2026-10-11 01:46:54 +00:00
package ckprompt
import (
2026-10-12 02:17:54 +00:00
"context"
2026-10-11 01:46:54 +00:00
"errors"
"fmt"
"strings"
2026-11-04 03:55:17 +00:00
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
2026-11-06 00:57:50 +00:00
promptkit "go.maximumdirect.net/promptkit"
2026-10-11 01:46:54 +00:00
)
type definitionInput [ I any ] struct {
2026-11-07 04:23:39 +00:00
namespaces namespaceInput
selection ckconfig . Selection
id string
captured commandkit . FlagValues [ I ]
selected I
2026-10-11 01:46:54 +00:00
}
2026-10-12 02:17:54 +00:00
type catalogInput [ I any ] struct {
2026-10-17 18:45:39 +00:00
selection ckconfig . Selection
namespace commandkit . Supplied [ string ]
allNamespaces commandkit . Supplied [ bool ]
kinds [ ] promptkit . ResourceKind
filter promptkit . NamespaceFilter
captured commandkit . FlagValues [ I ]
selected I
2026-10-12 02:17:54 +00:00
}
2026-10-12 17:05:33 +00:00
type requirementsInput [ I any ] struct {
2026-11-07 04:23:39 +00:00
namespaces namespaceInput
2026-10-12 17:05:33 +00:00
selection ckconfig . Selection
inspection promptkit . RequirementInspectionRequest
2026-11-07 04:16:09 +00:00
resources ResourceInput
inputs PromptInputs
2026-10-12 17:05:33 +00:00
captured commandkit . FlagValues [ I ]
selected I
}
type variableAssignment struct {
key string
value string
}
2026-10-12 22:16:44 +00:00
type inputAssignment struct {
2026-11-07 04:19:58 +00:00
name string
value string
2026-10-12 22:16:44 +00:00
}
2026-10-17 18:45:39 +00:00
// Command captures the optional PromptKit catalogs, named inspection,
2026-11-07 04:19:58 +00:00
// requirements discovery, concrete request validation and preparation, and smoke-test
2026-10-17 18:55:41 +00:00
// callbacks and adds only supplied operations. Discovery and validation share the
2026-10-12 22:25:43 +00:00
// `requirements` group and remain independently optional. An absent suite
// claims no namespace; attached construction issues remain reportable. It adds
// no configuration family; callers compose ConfigScope independently.
// Construction, installation, help, and version do not run suite factories or
// providers. Command captures suite callbacks and selector metadata;
// callback-referenced objects and effects remain caller-owned. Suite documents
// invocation input and state initialization, zero values, and caller ownership
// of returned objects.
2026-11-07 04:05:51 +00:00
// Named resource inspections return native reports through shared formatting.
// Catalog commands accept config/overlay selection and suite selectors.
2026-10-11 01:46:54 +00:00
func Command [ I , S any ] ( suite Suite [ I , S ] ) commandkit . Command {
2026-11-07 04:19:58 +00:00
if suite . InspectPrompt == nil && suite . InspectProfile == nil && suite . InspectBackend == nil && suite . InspectRequirements == nil && suite . ValidateRequest == nil && suite . PrepareRequest == nil && suite . SmokeTest == nil && suite . ListPrompts == nil && suite . ListProfiles == nil && suite . ListBackends == nil && suite . ListNamespaces == nil && suite . ListCollections == nil {
2026-10-11 01:46:54 +00:00
command := commandkit . NoCommand ( )
for _ , issue := range suite . issues {
command = commandkit . WithError ( command , issue )
}
return command
}
2026-10-11 13:02:54 +00:00
suite . Selectors = append ( [ ] commandkit . Flag [ I ] ( nil ) , suite . Selectors ... )
2026-10-12 17:05:33 +00:00
rootCommands := make ( [ ] commandkit . Command , 0 , 3 )
2026-10-11 01:46:54 +00:00
showCommands := make ( [ ] commandkit . Command , 0 , 2 )
if suite . InspectPrompt != nil {
2026-11-07 04:05:51 +00:00
showCommands = append ( showCommands , newDefinitionCommand ( suite , "prompt" ) )
2026-10-11 01:46:54 +00:00
}
if suite . InspectProfile != nil {
2026-11-07 04:05:51 +00:00
showCommands = append ( showCommands , newDefinitionCommand ( suite , "profile" ) )
}
if suite . InspectBackend != nil {
showCommands = append ( showCommands , newDefinitionCommand ( suite , "backend" ) )
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:19:58 +00:00
if suite . PrepareRequest != nil {
showCommands = append ( showCommands , newPreparationCommand ( suite ) )
}
2026-10-12 02:17:54 +00:00
if len ( showCommands ) != 0 {
rootCommands = append ( rootCommands , commandkit . Group ( "show" , "Show a named PromptKit definition." , showCommands ... ) )
}
2026-10-17 18:45:39 +00:00
listCommands := make ( [ ] commandkit . Command , 0 , 5 )
2026-10-12 02:17:54 +00:00
if suite . ListPrompts != nil {
2026-10-17 18:45:39 +00:00
listCommands = append ( listCommands , newCatalogListCommand ( suite , "prompts" ) )
2026-10-12 02:17:54 +00:00
}
if suite . ListProfiles != nil {
2026-10-17 18:45:39 +00:00
listCommands = append ( listCommands , newCatalogListCommand ( suite , "profiles" ) )
}
if suite . ListBackends != nil {
listCommands = append ( listCommands , newCatalogListCommand ( suite , "backends" ) )
}
if suite . ListNamespaces != nil {
listCommands = append ( listCommands , newCatalogListCommand ( suite , "namespaces" ) )
}
if suite . ListCollections != nil {
listCommands = append ( listCommands , newCatalogListCommand ( suite , "collections" ) )
2026-10-12 02:17:54 +00:00
}
if len ( listCommands ) != 0 {
rootCommands = append ( rootCommands , commandkit . Group ( "list" , "List PromptKit catalogs." , listCommands ... ) )
}
2026-10-12 22:16:44 +00:00
requirementsCommands := make ( [ ] commandkit . Command , 0 , 2 )
2026-10-12 17:05:33 +00:00
if suite . InspectRequirements != nil {
2026-10-12 22:16:44 +00:00
requirementsCommands = append ( requirementsCommands , newRequirementsCommand ( suite ) )
2026-10-12 17:05:33 +00:00
}
2026-10-12 22:16:44 +00:00
if suite . ValidateRequest != nil {
requirementsCommands = append ( requirementsCommands , newValidationCommand ( suite ) )
}
if len ( requirementsCommands ) != 0 {
rootCommands = append ( rootCommands , commandkit . Group ( "requirements" , "Inspect and validate prompt requirements." , requirementsCommands ... ) )
}
2026-10-17 18:55:41 +00:00
if suite . SmokeTest != nil {
rootCommands = append ( rootCommands , newSmokeTestCommand ( suite ) )
}
command := commandkit . RootGroup ( "promptkit" , "Inspect, list, validate requests, and run PromptKit smoke tests." , rootCommands ... )
2026-10-11 01:46:54 +00:00
for _ , issue := range suite . issues {
command = commandkit . WithError ( command , issue )
}
return command
}
2026-10-17 18:45:39 +00:00
func newCatalogListCommand [ I , S any ] ( suite Suite [ I , S ] , name string ) commandkit . Command {
2026-10-12 02:17:54 +00:00
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 ,
2026-11-03 04:09:27 +00:00
commandkit . ValueFlag ( commandkit . FlagMeta { Name : "config" , Usage : "Configuration input path." , Completion : commandkit . CompleteFiles ( ) } , ( * string ) ( nil ) , parseDefinitionString ,
2026-10-12 02:17:54 +00:00
func ( input * * catalogInput [ I ] , value commandkit . Supplied [ string ] ) { ( * input ) . selection . Config = value } ) ,
2026-11-03 04:09:27 +00:00
commandkit . ValueFlag ( commandkit . FlagMeta { Name : "overlay" , Usage : "Configuration overlay path." , Completion : commandkit . CompleteFiles ( ) } , ( * string ) ( nil ) , parseDefinitionString ,
2026-10-12 02:17:54 +00:00
func ( input * * catalogInput [ I ] , value commandkit . Supplied [ string ] ) { ( * input ) . selection . Overlay = value } ) ,
)
2026-10-17 18:45:39 +00:00
if name == "prompts" || name == "profiles" || name == "backends" {
flags = append ( flags ,
commandkit . ValueFlag ( commandkit . FlagMeta { Name : "namespace" , Usage : "Select one native namespace." } , ( * string ) ( nil ) , parseDefinitionString ,
func ( input * * catalogInput [ I ] , value commandkit . Supplied [ string ] ) { ( * input ) . namespace = value } ) ,
commandkit . BoolFlag ( commandkit . FlagMeta { Name : "all-namespaces" , Usage : "Select identities from every namespace." } , false ,
func ( input * * catalogInput [ I ] , value commandkit . Supplied [ bool ] ) { ( * input ) . allNamespaces = value } ) ,
)
}
if name == "namespaces" {
flags = append ( flags ,
commandkit . RepeatFlag ( commandkit . FlagMeta { Name : "kind" , Usage : "Resource kind to include." } , [ ] promptkit . ResourceKind ( nil ) ,
func ( value string ) ( promptkit . ResourceKind , error ) { return promptkit . ResourceKind ( value ) , nil } ,
func ( input * * catalogInput [ I ] , value commandkit . Supplied [ [ ] promptkit . ResourceKind ] ) {
( * input ) . kinds = value . Value
} ) ,
)
}
2026-10-12 02:17:54 +00:00
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" )
}
2026-10-17 18:45:39 +00:00
if err := prepareCatalogFilter ( input , name ) ; err != nil {
return err
}
2026-10-12 02:17:54 +00:00
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 {
2026-10-17 18:45:39 +00:00
switch name {
case "prompts" :
2026-11-07 04:10:47 +00:00
return runCatalogList ( invocation , suite , input , name , suite . ListPrompts , promptCatalogReport )
2026-10-17 18:45:39 +00:00
case "profiles" :
2026-11-07 04:10:47 +00:00
return runCatalogList ( invocation , suite , input , name , suite . ListProfiles , stringCatalogReport )
2026-10-17 18:45:39 +00:00
case "backends" :
2026-11-07 04:10:47 +00:00
return runCatalogList ( invocation , suite , input , name , suite . ListBackends , stringCatalogReport )
2026-10-17 18:45:39 +00:00
case "namespaces" :
list := func ( ctx context . Context , request CatalogRequest , value I , state S ) ( commandkit . Acquired [ [ ] string ] , error ) {
return suite . ListNamespaces ( ctx , NamespaceRequest { Selection : request . Selection , Kinds : input . kinds } , value , state )
}
2026-11-07 04:10:47 +00:00
return runCatalogList ( invocation , suite , input , name , list , stringCatalogReport )
2026-10-17 18:45:39 +00:00
case "collections" :
list := func ( ctx context . Context , request CatalogRequest , value I , state S ) ( commandkit . Acquired [ [ ] promptkit . CollectionInfo ] , error ) {
return suite . ListCollections ( ctx , request . Selection , value , state )
}
2026-11-07 04:10:47 +00:00
return runCatalogList ( invocation , suite , input , name , list , collectionCatalogReport )
2026-10-17 18:45:39 +00:00
default :
2026-10-26 03:30:19 +00:00
return definitionFailure ( "Unable to list the selected PromptKit catalog." , commandkit . Explanation { } , fmt . Errorf ( "unknown PromptKit catalog %q" , name ) )
2026-10-12 02:17:54 +00:00
}
} ,
} )
}
2026-10-17 18:45:39 +00:00
func prepareCatalogFilter [ I any ] ( input * catalogInput [ I ] , name string ) error {
input . filter = promptkit . NamespaceFilter { Mode : promptkit . NamespaceDefault }
if name != "prompts" && name != "profiles" && name != "backends" {
return nil
}
if input . allNamespaces . Set && input . allNamespaces . Value && input . namespace . Set {
return errors . New ( "--namespace cannot be combined with --all-namespaces" )
}
if input . allNamespaces . Set && input . allNamespaces . Value {
input . filter . Mode = promptkit . NamespaceAll
return nil
}
if input . namespace . Set {
if input . namespace . Value == "" {
input . filter . Mode = promptkit . NamespaceUnqualified
} else {
input . filter . Mode = promptkit . NamespaceNamed
input . filter . Name = input . namespace . Value
}
}
return nil
}
2026-10-12 02:17:54 +00:00
func prepareCatalogInput [ I , S any ] ( suite Suite [ I , S ] , input * catalogInput [ I ] ) ( I , error ) {
return prepareSuiteInput ( suite , input . selection , input . captured )
}
2026-11-07 04:05:51 +00:00
func newDefinitionCommand [ I , S any ] ( suite Suite [ I , S ] , name string ) commandkit . Command {
2026-10-11 01:46:54 +00:00
flags := commandkit . CaptureFlags ( suite . Selectors , func ( input * * definitionInput [ I ] ) * commandkit . FlagValues [ I ] {
if input == nil || * input == nil {
return nil
}
return & ( * input ) . captured
} )
flags = append ( flags ,
2026-11-03 04:09:27 +00:00
commandkit . ValueFlag ( commandkit . FlagMeta { Name : "config" , Usage : "Configuration input path." , Completion : commandkit . CompleteFiles ( ) } , ( * string ) ( nil ) , parseDefinitionString ,
2026-10-11 01:46:54 +00:00
func ( input * * definitionInput [ I ] , value commandkit . Supplied [ string ] ) { ( * input ) . selection . Config = value } ) ,
2026-11-03 04:09:27 +00:00
commandkit . ValueFlag ( commandkit . FlagMeta { Name : "overlay" , Usage : "Configuration overlay path." , Completion : commandkit . CompleteFiles ( ) } , ( * string ) ( nil ) , parseDefinitionString ,
2026-10-11 01:46:54 +00:00
func ( input * * definitionInput [ I ] , value commandkit . Supplied [ string ] ) {
( * input ) . selection . Overlay = value
} ) ,
)
2026-11-07 04:23:39 +00:00
if suite . namespaces != nil {
flags = append ( flags , namespaceFlags ( func ( input * * definitionInput [ I ] ) * namespaceInput { return & ( * input ) . namespaces } , name ) ... )
}
2026-10-11 01:46:54 +00:00
spec := commandkit . CommandSpec [ * definitionInput [ I ] ] {
Name : name ,
Summary : "Inspect a named PromptKit " + name + "." ,
NewInput : func ( ) * definitionInput [ I ] {
return & definitionInput [ I ] { }
} ,
Flags : flags ,
Arguments : [ ] commandkit . Argument [ * definitionInput [ I ] ] {
2026-11-07 04:05:51 +00:00
commandkit . ValueArgument ( commandkit . ArgumentMeta { Name : strings . ToUpper ( name ) + "_ID" , Usage : "Resource ID." } , true , parseDefinitionString ,
2026-10-11 01:46:54 +00:00
func ( input * * definitionInput [ I ] , value commandkit . Supplied [ string ] ) { ( * input ) . id = value . Value } ) ,
} ,
CheckInput : func ( input * definitionInput [ I ] ) error {
selected , err := prepareDefinitionInput ( suite , input )
if err != nil {
return err
}
input . selected = selected
return nil
} ,
Run : func ( invocation commandkit . Invocation , input * definitionInput [ I ] ) commandkit . Outcome {
2026-11-07 04:05:51 +00:00
return runDefinitionInspection ( invocation , suite , input , name )
2026-10-11 01:46:54 +00:00
} ,
}
return commandkit . NewCommand ( spec )
}
2026-10-12 17:05:33 +00:00
func newRequirementsCommand [ I , S any ] ( suite Suite [ I , S ] ) commandkit . Command {
flags := commandkit . CaptureFlags ( suite . Selectors , func ( input * * requirementsInput [ I ] ) * commandkit . FlagValues [ I ] {
if input == nil || * input == nil {
return nil
}
return & ( * input ) . captured
} )
flags = append ( flags ,
2026-11-03 04:09:27 +00:00
commandkit . ValueFlag ( commandkit . FlagMeta { Name : "config" , Usage : "Configuration input path." , Completion : commandkit . CompleteFiles ( ) } , ( * string ) ( nil ) , parseDefinitionString ,
2026-10-12 17:05:33 +00:00
func ( input * * requirementsInput [ I ] , value commandkit . Supplied [ string ] ) {
( * input ) . selection . Config = value
} ) ,
2026-11-03 04:09:27 +00:00
commandkit . ValueFlag ( commandkit . FlagMeta { Name : "overlay" , Usage : "Configuration overlay path." , Completion : commandkit . CompleteFiles ( ) } , ( * string ) ( nil ) , parseDefinitionString ,
2026-10-12 17:05:33 +00:00
func ( input * * requirementsInput [ I ] , value commandkit . Supplied [ string ] ) {
( * input ) . selection . Overlay = value
} ) ,
)
2026-11-07 04:16:09 +00:00
resources := NewResourceFlags ( func ( input * * requirementsInput [ I ] ) * ResourceInput { return & ( * input ) . resources } )
inputs := NewPromptInputFlags ( func ( input * * requirementsInput [ I ] ) * PromptInputs { return & ( * input ) . inputs } )
flags = append ( flags , resources . Profile , resources . SessionID , inputs . Variable )
2026-11-07 04:23:39 +00:00
if suite . namespaces != nil {
flags = append ( flags , namespaceFlags ( func ( input * * requirementsInput [ I ] ) * namespaceInput { return & ( * input ) . namespaces } , "prompt" , "profile" ) ... )
}
2026-10-12 17:05:33 +00:00
spec := commandkit . CommandSpec [ * requirementsInput [ I ] ] {
2026-11-07 04:23:39 +00:00
Name : "show" ,
Summary : "Inspect requirements for a named PromptKit prompt." ,
Description : "Profile selection establishes the reported profile identity, not a different set of requirements. A profile namespace qualifies an explicitly supplied short profile ID, not the prompt’ s stored default reference." ,
2026-10-12 17:05:33 +00:00
NewInput : func ( ) * requirementsInput [ I ] {
return & requirementsInput [ I ] { }
} ,
Flags : flags ,
Arguments : [ ] commandkit . Argument [ * requirementsInput [ I ] ] {
commandkit . ValueArgument ( commandkit . ArgumentMeta { Name : "id" , Usage : "Prompt ID." } , true , parseDefinitionString ,
func ( input * * requirementsInput [ I ] , value commandkit . Supplied [ string ] ) {
( * input ) . inspection . PromptID = value . Value
} ) ,
} ,
CheckInput : func ( input * requirementsInput [ I ] ) error {
2026-11-07 04:16:09 +00:00
input . inspection . ProfileID = input . resources . Profile . Value
input . inspection . SessionID = input . resources . SessionID . Value
input . inspection . Vars = input . inputs . Vars
2026-10-12 17:05:33 +00:00
selected , err := prepareSuiteInput ( suite , input . selection , input . captured )
if err != nil {
return err
}
input . selected = selected
return nil
} ,
Run : func ( invocation commandkit . Invocation , input * requirementsInput [ I ] ) commandkit . Outcome {
return runRequirementsInspection ( invocation , suite , input )
} ,
}
return commandkit . NewCommand ( spec )
}
2026-10-11 01:46:54 +00:00
func prepareDefinitionInput [ I , S any ] ( suite Suite [ I , S ] , input * definitionInput [ I ] ) ( I , error ) {
2026-10-12 02:17:54 +00:00
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 ) {
2026-10-11 01:46:54 +00:00
var selected I
if suite . NewInput != nil {
selected = suite . NewInput ( )
}
2026-10-12 02:17:54 +00:00
if err := captured . ApplyTo ( & selected , suite . Selectors ... ) ; err != nil {
2026-10-11 01:46:54 +00:00
return selected , err
}
if suite . CheckInput != nil {
2026-10-12 02:17:54 +00:00
if err := suite . CheckInput ( selection , selected ) ; err != nil {
2026-10-11 01:46:54 +00:00
return selected , err
}
}
return selected , nil
}
2026-10-12 02:17:54 +00:00
func runCatalogList [ T any , I , S any ] (
invocation commandkit . Invocation ,
suite Suite [ I , S ] ,
input * catalogInput [ I ] ,
2026-10-26 03:30:19 +00:00
catalog string ,
2026-10-17 18:44:10 +00:00
list func ( context . Context , CatalogRequest , I , S ) ( commandkit . Acquired [ T ] , error ) ,
2026-11-07 04:10:47 +00:00
project func ( T ) any ,
2026-10-12 02:17:54 +00:00
) commandkit . Outcome {
if invocation . Context != nil {
if err := invocation . Context . Err ( ) ; err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( "PromptKit catalog listing was canceled." , commandkit . Explanation { } , err )
2026-10-12 02:17:54 +00:00
}
}
var state S
if suite . NewState != nil {
state = suite . NewState ( )
}
if invocation . Context != nil {
if err := invocation . Context . Err ( ) ; err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( "PromptKit catalog listing was canceled." , commandkit . Explanation { } , err )
2026-10-12 02:17:54 +00:00
}
}
2026-10-17 18:45:39 +00:00
acquired , err := list ( invocation . Context , CatalogRequest { Selection : input . selection , Filter : input . filter } , input . selected , state )
2026-10-26 03:30:19 +00:00
queuePromptDiagnostics ( invocation . Reporter ( ) , acquired . Diagnostics )
2026-10-12 02:17:54 +00:00
if err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( fmt . Sprintf ( "Unable to list PromptKit %s." , catalog ) , acquired . Explanation , err )
2026-10-12 02:17:54 +00:00
}
if invocation . Context != nil {
if err := invocation . Context . Err ( ) ; err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( "PromptKit catalog listing was canceled." , acquired . Explanation , err )
2026-10-12 02:17:54 +00:00
}
}
2026-11-07 04:10:47 +00:00
_ = invocation . Reporter ( ) . Report ( commandkit . Report { Value : project ( acquired . Value ) } )
return commandkit . Success ( )
2026-10-12 02:17:54 +00:00
}
2026-11-07 04:05:51 +00:00
func runDefinitionInspection [ I , S any ] ( invocation commandkit . Invocation , suite Suite [ I , S ] , input * definitionInput [ I ] , kind string ) commandkit . Outcome {
if err := promptKitContextError ( invocation . Context ) ; err != nil {
return definitionFailure ( "PromptKit inspection was canceled." , commandkit . Explanation { } , err )
2026-10-11 01:46:54 +00:00
}
var state S
if suite . NewState != nil {
state = suite . NewState ( )
}
2026-11-07 04:05:51 +00:00
if err := promptKitContextError ( invocation . Context ) ; err != nil {
return definitionFailure ( "PromptKit inspection was canceled." , commandkit . Explanation { } , err )
}
var value any
var diagnostics [ ] commandkit . Diagnostic
var explanation commandkit . Explanation
var err error
switch kind {
case "prompt" :
var result commandkit . Acquired [ * promptkit . PromptInspection ]
2026-11-07 04:23:39 +00:00
result , err = suite . InspectPrompt ( invocation . Context , PromptRequest { Selection : input . selection , ID : input . id , Namespaces : selectedNamespaces ( suite . namespaces , input . namespaces ) } , input . selected , state )
2026-11-07 04:05:51 +00:00
if result . Value != nil {
value = result . Value
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:05:51 +00:00
diagnostics , explanation = result . Diagnostics , result . Explanation
case "profile" :
var result commandkit . Acquired [ * promptkit . ProfileInspection ]
2026-11-07 04:23:39 +00:00
result , err = suite . InspectProfile ( invocation . Context , ProfileRequest { Selection : input . selection , ID : input . id , Namespaces : selectedNamespaces ( suite . namespaces , input . namespaces ) } , input . selected , state )
2026-11-07 04:05:51 +00:00
if result . Value != nil {
value = result . Value
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:05:51 +00:00
diagnostics , explanation = result . Diagnostics , result . Explanation
case "backend" :
var result commandkit . Acquired [ * promptkit . BackendInspection ]
2026-11-07 04:23:39 +00:00
result , err = suite . InspectBackend ( invocation . Context , BackendRequest { Selection : input . selection , ID : input . id , Namespaces : selectedNamespaces ( suite . namespaces , input . namespaces ) } , input . selected , state )
2026-11-07 04:05:51 +00:00
if result . Value != nil {
value = result . Value
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:05:51 +00:00
diagnostics , explanation = result . Diagnostics , result . Explanation
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:05:51 +00:00
queuePromptDiagnostics ( invocation . Reporter ( ) , diagnostics )
2026-10-11 01:46:54 +00:00
if err != nil {
2026-11-07 04:05:51 +00:00
return definitionFailure ( fmt . Sprintf ( "Unable to inspect PromptKit %s %q." , kind , input . id ) , explanation , err )
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:05:51 +00:00
if value == nil {
return definitionFailure ( fmt . Sprintf ( "PromptKit %s inspection returned no result." , kind ) , explanation , nil )
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:05:51 +00:00
if err := promptKitContextError ( invocation . Context ) ; err != nil {
return definitionFailure ( fmt . Sprintf ( "Inspection of PromptKit %s %q was canceled." , kind , input . id ) , explanation , err )
2026-10-11 01:46:54 +00:00
}
2026-11-07 04:05:51 +00:00
_ = invocation . Reporter ( ) . Report ( commandkit . Report { Value : value } )
return commandkit . Success ( )
2026-10-11 01:46:54 +00:00
}
2026-10-12 16:57:23 +00:00
type requirementsInspectionReport struct {
2026-11-07 04:10:47 +00:00
PromptID string ` json:"prompt_id" `
ProfileID string ` json:"profile_id" `
Complete bool ` json:"complete" `
Inputs [ ] requirementInputReport ` json:"inputs" `
Variables [ ] requirementVariableReport ` json:"variables" `
Issues [ ] requirementIssueReport ` json:"issues" `
2026-10-12 16:57:23 +00:00
}
type requirementInputReport struct {
2026-11-07 04:10:47 +00:00
Name string ` json:"name" `
Kind string ` json:"kind" `
Declared bool ` json:"declared" `
ContentType * string ` json:"content_type" `
Description * string ` json:"description" `
Explanation string ` json:"explanation" `
2026-10-12 16:57:23 +00:00
}
type requirementVariableReport struct {
2026-11-07 04:10:47 +00:00
Name string ` json:"name" `
Kind string ` json:"kind" `
Supplied bool ` json:"supplied" `
Explanation string ` json:"explanation" `
2026-10-12 16:57:23 +00:00
}
type requirementIssueReport struct {
2026-11-07 04:10:47 +00:00
Code string ` json:"code" `
InputName string ` json:"input_name" `
VariableName string ` json:"variable_name" `
Description string ` json:"description" `
2026-10-12 16:57:23 +00:00
}
func requirementsReportFromInspection ( inspection * promptkit . RequirementInspection ) requirementsInspectionReport {
report := requirementsInspectionReport {
2026-11-06 00:57:50 +00:00
PromptID : inspection . PromptID ,
ProfileID : inspection . ProfileID ,
Complete : inspection . Complete ,
Inputs : make ( [ ] requirementInputReport , 0 , len ( inspection . Inputs ) ) ,
Variables : make ( [ ] requirementVariableReport , 0 , len ( inspection . Variables ) ) ,
Issues : make ( [ ] requirementIssueReport , 0 , len ( inspection . Issues ) ) ,
2026-10-12 16:57:23 +00:00
}
for _ , input := range inspection . Inputs {
report . Inputs = append ( report . Inputs , requirementInputReport {
Name : input . Name ,
Kind : string ( input . Kind ) ,
Declared : input . Declared ,
ContentType : input . ContentType ,
Description : input . Description ,
Explanation : input . Explanation ,
} )
}
for _ , variable := range inspection . Variables {
report . Variables = append ( report . Variables , requirementVariableReport {
Name : variable . Name ,
Kind : string ( variable . Kind ) ,
Supplied : variable . Supplied ,
Explanation : variable . Explanation ,
} )
}
for _ , issue := range inspection . Issues {
report . Issues = append ( report . Issues , requirementIssueReport {
Code : string ( issue . Code ) ,
InputName : issue . InputName ,
VariableName : issue . VariableName ,
Description : issue . Description ,
} )
}
return report
}
2026-10-12 17:05:33 +00:00
func runRequirementsInspection [ I , S any ] ( invocation commandkit . Invocation , suite Suite [ I , S ] , input * requirementsInput [ I ] ) commandkit . Outcome {
if invocation . Context != nil {
if err := invocation . Context . Err ( ) ; err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( "PromptKit requirements inspection was canceled." , commandkit . Explanation { } , err )
2026-10-12 17:05:33 +00:00
}
}
var state S
if suite . NewState != nil {
state = suite . NewState ( )
}
if invocation . Context != nil {
if err := invocation . Context . Err ( ) ; err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( "PromptKit requirements inspection was canceled." , commandkit . Explanation { } , err )
2026-10-12 17:05:33 +00:00
}
}
2026-11-07 04:23:39 +00:00
request := RequirementsRequest { Selection : input . selection , Inspection : input . inspection , Namespaces : selectedNamespaces ( suite . namespaces , input . namespaces ) }
2026-10-12 17:05:33 +00:00
acquired , err := suite . InspectRequirements ( invocation . Context , request , input . selected , state )
2026-10-26 03:30:19 +00:00
queuePromptDiagnostics ( invocation . Reporter ( ) , acquired . Diagnostics )
2026-10-12 17:05:33 +00:00
if err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( fmt . Sprintf ( "Unable to inspect requirements for PromptKit prompt %q." , input . inspection . PromptID ) , acquired . Explanation , err )
2026-10-12 17:05:33 +00:00
}
if acquired . Value == nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( "PromptKit requirements inspection returned no result." , acquired . Explanation , nil )
2026-10-12 17:05:33 +00:00
}
if invocation . Context != nil {
if err := invocation . Context . Err ( ) ; err != nil {
2026-10-26 03:30:19 +00:00
return definitionFailure ( fmt . Sprintf ( "Requirements inspection for PromptKit prompt %q was canceled." , input . inspection . PromptID ) , acquired . Explanation , err )
2026-10-12 17:05:33 +00:00
}
}
2026-11-07 04:10:47 +00:00
_ = invocation . Reporter ( ) . Report ( commandkit . Report { Value : requirementsReportFromInspection ( acquired . Value ) } )
2026-10-26 03:30:19 +00:00
return commandkit . Success ( )
2026-10-11 01:46:54 +00:00
}
2026-10-12 02:12:47 +00:00
type promptCatalogEntry struct {
2026-11-07 04:10:47 +00:00
ID string ` json:"id" `
2026-10-12 02:12:47 +00:00
}
2026-11-07 04:10:47 +00:00
func promptCatalogReport ( prompts [ ] promptkit . PromptIdentity ) any {
2026-10-12 02:12:47 +00:00
entries := make ( [ ] promptCatalogEntry , len ( prompts ) )
for index , prompt := range prompts {
2026-11-06 00:57:50 +00:00
entries [ index ] = promptCatalogEntry { ID : prompt . ID }
2026-10-12 02:12:47 +00:00
}
2026-11-07 04:10:47 +00:00
return entries
2026-10-12 02:12:47 +00:00
}
2026-11-07 04:10:47 +00:00
func stringCatalogReport ( values [ ] string ) any {
if values == nil {
return [ ] string { }
2026-10-12 02:12:47 +00:00
}
2026-11-07 04:10:47 +00:00
return values
2026-10-12 02:12:47 +00:00
}
2026-10-17 18:45:39 +00:00
type collectionCatalogEntry struct {
2026-11-07 04:10:47 +00:00
Namespace string ` json:"namespace" `
Version * string ` json:"version,omitempty" `
2026-10-17 18:45:39 +00:00
}
2026-11-07 04:10:47 +00:00
func collectionCatalogReport ( collections [ ] promptkit . CollectionInfo ) any {
2026-10-17 18:45:39 +00:00
entries := make ( [ ] collectionCatalogEntry , len ( collections ) )
for index , collection := range collections {
entries [ index ] = collectionCatalogEntry { Namespace : collection . Namespace , Version : collection . ReleaseVersion }
}
2026-11-07 04:10:47 +00:00
return entries
2026-10-12 02:12:47 +00:00
}
2026-10-26 03:30:19 +00:00
func queuePromptDiagnostics ( reporter * commandkit . Reporter , diagnostics [ ] commandkit . Diagnostic ) {
deferred := reporter . AtEnd ( )
for _ , diagnostic := range diagnostics {
if diagnostic . Write == nil {
continue
}
switch diagnostic . Severity {
case commandkit . SeverityInfo :
_ = deferred . Info ( "" , diagnostic . Write )
case commandkit . SeverityDebug :
_ = deferred . Debug ( "" , diagnostic . Write )
case commandkit . SeverityProgress :
_ = reporter . Progress ( "" , diagnostic . Write )
default :
_ = deferred . Warn ( "" , diagnostic . Write )
2026-10-11 01:46:54 +00:00
}
}
}
2026-10-26 03:30:19 +00:00
func definitionFailure ( message string , explanation commandkit . Explanation , cause error ) commandkit . Outcome {
outcome := commandkit . Failure ( message )
if explanation . Message != "" || len ( explanation . Details ) > 0 {
outcome = outcome . WithExplanation ( explanation . Message , explanation . Details ... )
}
if cause != nil {
outcome = outcome . WithCause ( cause )
}
2026-10-11 01:46:54 +00:00
return outcome
}
func parseDefinitionString ( value string ) ( string , error ) { return value , nil }
2026-10-12 17:05:33 +00:00
func parseVariableAssignment ( raw string ) ( variableAssignment , error ) {
key , value , found := strings . Cut ( raw , "=" )
if ! found {
return variableAssignment { } , fmt . Errorf ( "variable assignment %q must contain =" , raw )
}
return variableAssignment { key : key , value : value } , nil
}
2026-10-12 22:16:44 +00:00
func parseInputAssignment ( raw string ) ( inputAssignment , error ) {
2026-11-07 04:19:58 +00:00
name , value , found := strings . Cut ( raw , "=" )
2026-10-12 22:16:44 +00:00
if ! found {
return inputAssignment { } , fmt . Errorf ( "input assignment %q must contain =" , raw )
}
2026-11-07 04:19:58 +00:00
return inputAssignment { name : name , value : value } , nil
2026-10-12 22:16:44 +00:00
}