Add PromptKit catalog commands
This commit is contained in:
@@ -2,6 +2,7 @@ package ckprompt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -23,13 +24,20 @@ type definitionInput[I any] struct {
|
||||
selected I
|
||||
}
|
||||
|
||||
// Command captures the optional named PromptKit inspection tree and adds only
|
||||
// the inspection capabilities present in suite. It adds no configuration
|
||||
type catalogInput[I any] struct {
|
||||
selection ckconfig.Selection
|
||||
format string
|
||||
captured commandkit.FlagValues[I]
|
||||
selected I
|
||||
}
|
||||
|
||||
// Command captures the optional PromptKit catalog and named inspection trees
|
||||
// and adds only the operations present in suite. It adds no configuration
|
||||
// family; callers compose ConfigScope independently. Construction and
|
||||
// installation do not run suite callbacks. Suite documents invocation input
|
||||
// and state initialization, zero values, and caller ownership of returned objects.
|
||||
func Command[I, S any](suite Suite[I, S]) commandkit.Command {
|
||||
if suite.InspectPrompt == nil && suite.InspectProfile == nil {
|
||||
if suite.InspectPrompt == nil && suite.InspectProfile == nil && suite.ListPrompts == nil && suite.ListProfiles == nil {
|
||||
command := commandkit.NoCommand()
|
||||
for _, issue := range suite.issues {
|
||||
command = commandkit.WithError(command, issue)
|
||||
@@ -38,6 +46,7 @@ func Command[I, S any](suite Suite[I, S]) commandkit.Command {
|
||||
}
|
||||
|
||||
suite.Selectors = append([]commandkit.Flag[I](nil), suite.Selectors...)
|
||||
rootCommands := make([]commandkit.Command, 0, 2)
|
||||
showCommands := make([]commandkit.Command, 0, 2)
|
||||
if suite.InspectPrompt != nil {
|
||||
showCommands = append(showCommands, newDefinitionCommand(suite, "prompt", true))
|
||||
@@ -45,15 +54,82 @@ func Command[I, S any](suite Suite[I, S]) commandkit.Command {
|
||||
if suite.InspectProfile != nil {
|
||||
showCommands = append(showCommands, newDefinitionCommand(suite, "profile", false))
|
||||
}
|
||||
command := commandkit.RootGroup("promptkit", "Inspect named PromptKit definitions.",
|
||||
commandkit.Group("show", "Show a named PromptKit definition.", showCommands...),
|
||||
)
|
||||
if len(showCommands) != 0 {
|
||||
rootCommands = append(rootCommands, commandkit.Group("show", "Show a named PromptKit definition.", showCommands...))
|
||||
}
|
||||
listCommands := make([]commandkit.Command, 0, 2)
|
||||
if suite.ListPrompts != nil {
|
||||
listCommands = append(listCommands, newCatalogListCommand(suite, "prompts", true))
|
||||
}
|
||||
if suite.ListProfiles != nil {
|
||||
listCommands = append(listCommands, newCatalogListCommand(suite, "profiles", false))
|
||||
}
|
||||
if len(listCommands) != 0 {
|
||||
rootCommands = append(rootCommands, commandkit.Group("list", "List PromptKit catalogs.", listCommands...))
|
||||
}
|
||||
command := commandkit.RootGroup("promptkit", "Inspect and list PromptKit definitions.", rootCommands...)
|
||||
for _, issue := range suite.issues {
|
||||
command = commandkit.WithError(command, issue)
|
||||
}
|
||||
return command
|
||||
}
|
||||
|
||||
func newCatalogListCommand[I, S any](suite Suite[I, S], name string, prompts bool) commandkit.Command {
|
||||
flags := commandkit.CaptureFlags(suite.Selectors, func(input **catalogInput[I]) *commandkit.FlagValues[I] {
|
||||
if input == nil || *input == nil {
|
||||
return nil
|
||||
}
|
||||
return &(*input).captured
|
||||
})
|
||||
flags = append(flags,
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path."}, (*string)(nil), parseDefinitionString,
|
||||
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }),
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path."}, (*string)(nil), parseDefinitionString,
|
||||
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Overlay = value }),
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "format", Usage: "Catalog format: yaml."}, stringDefault("yaml"), parseDefinitionString,
|
||||
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).format = value.Value }),
|
||||
)
|
||||
return commandkit.NewCommand(commandkit.CommandSpec[*catalogInput[I]]{
|
||||
Name: name,
|
||||
Summary: "List PromptKit " + name + ".",
|
||||
NewInput: func() *catalogInput[I] {
|
||||
return &catalogInput[I]{}
|
||||
},
|
||||
Flags: flags,
|
||||
CheckInput: func(input *catalogInput[I]) error {
|
||||
if input == nil {
|
||||
return errors.New("PromptKit catalog input must not be nil")
|
||||
}
|
||||
if err := checkCatalogFormat(input.format); err != nil {
|
||||
return err
|
||||
}
|
||||
selected, err := prepareCatalogInput(suite, input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
input.selected = selected
|
||||
return nil
|
||||
},
|
||||
Run: func(invocation commandkit.Invocation, input *catalogInput[I]) commandkit.Outcome {
|
||||
if prompts {
|
||||
return runCatalogList(invocation, suite, input, suite.ListPrompts, encodePromptCatalog)
|
||||
}
|
||||
return runCatalogList(invocation, suite, input, suite.ListProfiles, encodeProfileCatalog)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func checkCatalogFormat(format string) error {
|
||||
if format != "yaml" {
|
||||
return fmt.Errorf("unsupported catalog format %q", format)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func prepareCatalogInput[I, S any](suite Suite[I, S], input *catalogInput[I]) (I, error) {
|
||||
return prepareSuiteInput(suite, input.selection, input.captured)
|
||||
}
|
||||
|
||||
func newDefinitionCommand[I, S any](suite Suite[I, S], name string, prompt bool) commandkit.Command {
|
||||
flags := commandkit.CaptureFlags(suite.Selectors, func(input **definitionInput[I]) *commandkit.FlagValues[I] {
|
||||
if input == nil || *input == nil {
|
||||
@@ -106,21 +182,63 @@ func newDefinitionCommand[I, S any](suite Suite[I, S], name string, prompt bool)
|
||||
}
|
||||
|
||||
func prepareDefinitionInput[I, S any](suite Suite[I, S], input *definitionInput[I]) (I, error) {
|
||||
return prepareSuiteInput(suite, input.selection, input.captured)
|
||||
}
|
||||
|
||||
func prepareSuiteInput[I, S any](suite Suite[I, S], selection ckconfig.Selection, captured commandkit.FlagValues[I]) (I, error) {
|
||||
var selected I
|
||||
if suite.NewInput != nil {
|
||||
selected = suite.NewInput()
|
||||
}
|
||||
if err := input.captured.ApplyTo(&selected, suite.Selectors...); err != nil {
|
||||
if err := captured.ApplyTo(&selected, suite.Selectors...); err != nil {
|
||||
return selected, err
|
||||
}
|
||||
if suite.CheckInput != nil {
|
||||
if err := suite.CheckInput(input.selection, selected); err != nil {
|
||||
if err := suite.CheckInput(selection, selected); err != nil {
|
||||
return selected, err
|
||||
}
|
||||
}
|
||||
return selected, nil
|
||||
}
|
||||
|
||||
func runCatalogList[T any, I, S any](
|
||||
invocation commandkit.Invocation,
|
||||
suite Suite[I, S],
|
||||
input *catalogInput[I],
|
||||
list func(context.Context, ckconfig.Selection, I, S) (commandkit.Acquired[T], error),
|
||||
encode func(T) ([]byte, error),
|
||||
) commandkit.Outcome {
|
||||
if invocation.Context != nil {
|
||||
if err := invocation.Context.Err(); err != nil {
|
||||
return definitionFailure(err, nil)
|
||||
}
|
||||
}
|
||||
var state S
|
||||
if suite.NewState != nil {
|
||||
state = suite.NewState()
|
||||
}
|
||||
if invocation.Context != nil {
|
||||
if err := invocation.Context.Err(); err != nil {
|
||||
return definitionFailure(err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
acquired, err := list(invocation.Context, input.selection, input.selected, state)
|
||||
if err != nil {
|
||||
return definitionFailure(err, acquired.Diagnostics)
|
||||
}
|
||||
if invocation.Context != nil {
|
||||
if err := invocation.Context.Err(); err != nil {
|
||||
return definitionFailure(err, acquired.Diagnostics)
|
||||
}
|
||||
}
|
||||
output, err := encode(acquired.Value)
|
||||
if err != nil {
|
||||
return definitionFailure(err, acquired.Diagnostics)
|
||||
}
|
||||
return writePromptReport(invocation, output, acquired.Diagnostics)
|
||||
}
|
||||
|
||||
func runDefinitionInspection[I, S any](invocation commandkit.Invocation, suite Suite[I, S], input *definitionInput[I], prompt bool) commandkit.Outcome {
|
||||
if invocation.Context != nil {
|
||||
if err := invocation.Context.Err(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user