Add PromptKit catalog YAML encoders

This commit is contained in:
2026-10-12 02:12:47 +00:00
parent 330017fd75
commit c75d371ecd
3 changed files with 114 additions and 1 deletions

View File

@@ -322,6 +322,34 @@ func encodePromptYAML(writer io.Writer, value any) error {
return encoder.Encode(value)
}
type promptCatalogEntry struct {
ID string `yaml:"id"`
Version string `yaml:"version"`
}
func encodePromptCatalog(prompts []promptkit.PromptIdentity) ([]byte, error) {
entries := make([]promptCatalogEntry, len(prompts))
for index, prompt := range prompts {
entries[index] = promptCatalogEntry{ID: prompt.ID, Version: prompt.Version}
}
return encodePromptYAMLBytes(entries)
}
func encodeProfileCatalog(profiles []string) ([]byte, error) {
if profiles == nil {
profiles = []string{}
}
return encodePromptYAMLBytes(profiles)
}
func encodePromptYAMLBytes(value any) ([]byte, error) {
var output bytes.Buffer
if err := encodePromptYAML(&output, value); err != nil {
return nil, err
}
return output.Bytes(), nil
}
func writePromptReport(invocation commandkit.Invocation, output []byte, diagnostics []commandkit.Diagnostic) commandkit.Outcome {
if invocation.Context != nil {
if err := invocation.Context.Err(); err != nil {

View File

@@ -309,3 +309,75 @@ func TestProfileTextUsesCredentialNamesAndExplicitEmptyExtraParams(t *testing.T)
t.Fatalf("report contains a credential value: %q", text)
}
}
func TestPromptCatalogYAMLPreservesSchemaStringsAndOrder(t *testing.T) {
want := []promptkit.PromptIdentity{
{ID: " briefing ", Version: " 03 "},
{ID: "001", Version: "1.10"},
{ID: " briefing ", Version: " 03 "},
}
output, err := encodePromptCatalog(want)
if err != nil {
t.Fatal(err)
}
var decoded []map[string]any
if err := yaml.Unmarshal(output, &decoded); err != nil {
t.Fatalf("decode prompt catalog %q: %v", output, err)
}
if len(decoded) != len(want) {
t.Fatalf("catalog entry count = %d, want %d: %q", len(decoded), len(want), output)
}
for index, entry := range decoded {
if len(entry) != 2 {
t.Errorf("entry %d fields = %#v, want only id and version", index, entry)
}
id, idOK := entry["id"].(string)
version, versionOK := entry["version"].(string)
if !idOK || !versionOK || id != want[index].ID || version != want[index].Version {
t.Errorf("entry %d = %#v, want id/version %q/%q as strings", index, entry, want[index].ID, want[index].Version)
}
}
}
func TestCatalogYAMLEncodersRenderNilAndEmptyInventoriesAsSequences(t *testing.T) {
for _, test := range []struct {
name string
data func() ([]byte, error)
}{
{name: "nil prompts", data: func() ([]byte, error) { return encodePromptCatalog(nil) }},
{name: "empty prompts", data: func() ([]byte, error) { return encodePromptCatalog(make([]promptkit.PromptIdentity, 0)) }},
{name: "nil profiles", data: func() ([]byte, error) { return encodeProfileCatalog(nil) }},
{name: "empty profiles", data: func() ([]byte, error) { return encodeProfileCatalog(make([]string, 0)) }},
} {
t.Run(test.name, func(t *testing.T) {
output, err := test.data()
if err != nil {
t.Fatal(err)
}
if strings.TrimSpace(string(output)) != "[]" {
t.Fatalf("empty catalog YAML = %q, want empty sequence", output)
}
})
}
}
func TestProfileCatalogYAMLPreservesStringValuesAndOrder(t *testing.T) {
want := []string{" default ", "001", "same", "same"}
output, err := encodeProfileCatalog(want)
if err != nil {
t.Fatal(err)
}
var decoded []any
if err := yaml.Unmarshal(output, &decoded); err != nil {
t.Fatalf("decode profile catalog %q: %v", output, err)
}
if len(decoded) != len(want) {
t.Fatalf("catalog entry count = %d, want %d: %q", len(decoded), len(want), output)
}
for index, item := range decoded {
value, ok := item.(string)
if !ok || value != want[index] {
t.Errorf("profile %d = %#v, want string %q", index, item, want[index])
}
}
}