Refresh operator documentation and CLI help
This commit is contained in:
26
README.md
26
README.md
@@ -1,26 +1,22 @@
|
|||||||
# CommandKit
|
# CommandKit
|
||||||
|
|
||||||
CommandKit is a Go library for typed command declarations, shared CLI behavior,
|
CommandKit helps Go applications build consistent command-line interfaces. It
|
||||||
and application-owned execution. The core `commandkit` module is usable by
|
provides typed flags and arguments, help, output formatting, and error reporting.
|
||||||
itself. ConfigKit and PromptKit support lives in separately versioned optional
|
Optional integrations add commands for inspecting configuration and working with
|
||||||
modules, so applications choose which upstream libraries they add.
|
PromptKit.
|
||||||
|
|
||||||
The core captures reusable command declarations, validates installation batches
|
CommandKit is in alpha. Start with the [consumer guide](docs/consumers/guide.md#core-commands)
|
||||||
before changing an application's registry, converts typed inputs before
|
to define a command, or run the [core example](examples/core/README.md).
|
||||||
constructing them, and returns outcomes without exiting the process. Its
|
Applications supply their own command handlers and decide when to exit;
|
||||||
[consumer guide](docs/consumers/guide.md) covers declaration, invocation
|
CommandKit returns the result of each invocation.
|
||||||
and reporting. Each handler receives one invocation reporter for
|
|
||||||
substantive output, categorized messages, and terminal explanations; `Execute`
|
|
||||||
returns delivery observations with the outcome. The [CLI reference](docs/cli.md)
|
|
||||||
defines the shared visibility policy.
|
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
| Module | Package | Provides |
|
| Module | Package | Provides |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `go.maximumdirect.net/commandkit` | `commandkit` | Typed commands, bindings, execution reporting and outcomes, help, and version. |
|
| `go.maximumdirect.net/commandkit` | `commandkit` | Commands, typed inputs, shared output and error reporting, help, and version. |
|
||||||
| `go.maximumdirect.net/ckconfig` | `ckconfig` | ConfigKit-backed `config` scopes, including configuration source evidence. |
|
| `go.maximumdirect.net/ckconfig` | `ckconfig` | Commands to view, validate, explain, and compare ConfigKit configuration. |
|
||||||
| `go.maximumdirect.net/ckprompt` | `ckprompt` | PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, concrete request validation, and native smoke tests. |
|
| `go.maximumdirect.net/ckprompt` | `ckprompt` | Commands to list and inspect PromptKit resources, discover required inputs, validate and preview requests, and run smoke tests. |
|
||||||
|
|
||||||
Importing an integration does not install commands. Core and the integrations
|
Importing an integration does not install commands. Core and the integrations
|
||||||
are versioned separately; see the [consumer guide](docs/consumers/guide.md#module-selection)
|
are versioned separately; see the [consumer guide](docs/consumers/guide.md#module-selection)
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ func (a *App) builtinCommands() []Declaration {
|
|||||||
help := captureCommand(CommandSpec[helpInput]{
|
help := captureCommand(CommandSpec[helpInput]{
|
||||||
Name: "help",
|
Name: "help",
|
||||||
Summary: "Show help for commands.",
|
Summary: "Show help for commands.",
|
||||||
Description: "Describe registered commands and their inputs.",
|
Description: "Show available commands, flags, and arguments.",
|
||||||
Arguments: []Argument[helpInput]{RepeatArgument(ArgumentMeta{Name: "COMMAND", Usage: "registered command path"}, 0, -1,
|
Arguments: []Argument[helpInput]{RepeatArgument(ArgumentMeta{Name: "COMMAND", Usage: "Command path to describe."}, 0, -1,
|
||||||
func(value string) (string, error) { return value, nil },
|
func(value string) (string, error) { return value, nil },
|
||||||
func(input *helpInput, value Supplied[[]string]) { input.Targets = value })},
|
func(input *helpInput, value Supplied[[]string]) { input.Targets = value })},
|
||||||
}, func(current commandExecution, input helpInput) Outcome {
|
}, func(current commandExecution, input helpInput) Outcome {
|
||||||
@@ -43,9 +43,9 @@ func (a *App) builtinCommands() []Declaration {
|
|||||||
version := NewCommand(CommandSpec[versionInput]{
|
version := NewCommand(CommandSpec[versionInput]{
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Summary: "Show application or CommandKit version.",
|
Summary: "Show application or CommandKit version.",
|
||||||
Description: "Report identity and build metadata without loading application configuration.",
|
Description: "Show the name, version, and revision without loading application configuration.",
|
||||||
Flags: []Flag[versionInput]{
|
Flags: []Flag[versionInput]{
|
||||||
ValueFlag(FlagMeta{Name: "scope", Usage: "version subject", Completion: CompleteChoices(CompletionChoice{Value: "app"}, CompletionChoice{Value: "commandkit"})}, &scopeDefault, parseVersionScope, func(input *versionInput, value Supplied[string]) { input.Scope = value.Value }),
|
ValueFlag(FlagMeta{Name: "scope", Usage: "Show the app or CommandKit version.", Completion: CompleteChoices(CompletionChoice{Value: "app"}, CompletionChoice{Value: "commandkit"})}, &scopeDefault, parseVersionScope, func(input *versionInput, value Supplied[string]) { input.Scope = value.Value }),
|
||||||
},
|
},
|
||||||
Run: func(invocation Invocation, input versionInput) Outcome {
|
Run: func(invocation Invocation, input versionInput) Outcome {
|
||||||
identity := a.identity
|
identity := a.identity
|
||||||
|
|||||||
16
doc.go
16
doc.go
@@ -1,8 +1,10 @@
|
|||||||
// Package commandkit provides the core instance-owned CLI dispatcher, typed
|
// Package commandkit helps Go applications build consistent command-line
|
||||||
// command declarations, application-owned command and flag aliases, input
|
// interfaces with typed flags and arguments, help, and shared output formatting.
|
||||||
// bindings, invocation-scoped reporting, and outcomes with separate operation
|
// Define commands with NewCommand and install them with New or App.Register.
|
||||||
// causes and presentation observations. New and App.Register accept canonical
|
// Commands and command or flag aliases can be installed together.
|
||||||
// Command declarations and RoutingRule declarations together. Optional
|
//
|
||||||
// integration modules provide ConfigKit and PromptKit-specific commands;
|
// App.Execute runs a command and returns an Outcome; the application decides
|
||||||
// importing those modules does not install their commands.
|
// when to exit. Handlers use Invocation.Reporter for output and messages.
|
||||||
|
// Optional ckconfig and ckprompt modules add inspection and testing commands;
|
||||||
|
// applications install those commands explicitly.
|
||||||
package commandkit
|
package commandkit
|
||||||
|
|||||||
870
docs/cli.md
870
docs/cli.md
File diff suppressed because it is too large
Load Diff
@@ -1,40 +1,46 @@
|
|||||||
# Consumer guide
|
# Consumer guide
|
||||||
|
|
||||||
CommandKit is distributed as three Go modules. Start with the core and add an
|
Start with core to build commands with typed inputs and shared output
|
||||||
integration module only when the application uses that library. Core and
|
formatting. Add an integration when your application uses ConfigKit or
|
||||||
compatible integration command factories return canonical `commandkit.Command` values.
|
PromptKit. The [core command example](#core-commands) below shows the basic
|
||||||
Applications may install those alongside application-owned `RoutingRule`
|
API; the [maintained examples](../../README.md#examples) show complete
|
||||||
declarations through `commandkit.New` or `App.Register`; routing rules are
|
applications.
|
||||||
installed at the application root, not as group children.
|
|
||||||
|
|
||||||
## Module selection
|
## Module selection
|
||||||
|
|
||||||
| Import | Use when |
|
| Import | Use when |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `go.maximumdirect.net/commandkit` | The application needs typed command declarations and common CLI behavior. |
|
| `go.maximumdirect.net/commandkit` | You need commands, typed inputs, help, and common output handling. |
|
||||||
| `go.maximumdirect.net/ckconfig` | The application wants ConfigKit-backed configuration scopes and reports. |
|
| `go.maximumdirect.net/ckconfig` | You want operators to view, validate, explain, and compare ConfigKit configuration. |
|
||||||
| `go.maximumdirect.net/ckprompt` | The application wants PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, request validation, or native smoke testing. |
|
| `go.maximumdirect.net/ckprompt` | You want operators to inspect PromptKit resources, check and preview requests, or run smoke tests. |
|
||||||
|
|
||||||
Core v0.4.0 is published. The previously published matched releases are core
|
The following distinguishes published combinations from the current checkout:
|
||||||
v0.3.0, ckconfig v0.2.0, and ckprompt v0.2.0.
|
|
||||||
The published ckconfig v0.3.0 uses ConfigKit v1.1.0 and does not compose
|
|
||||||
with ckprompt v0.2.0, which retains ckconfig v0.2.0 and ConfigKit v0.8.0.
|
|
||||||
Install the current core with `go get go.maximumdirect.net/commandkit@v0.4.0`.
|
|
||||||
For the older matched integration set, select core v0.3.0 and the corresponding
|
|
||||||
ckconfig or ckprompt v0.2.0 release together.
|
|
||||||
|
|
||||||
Published ckconfig v0.4.0 uses core v0.4.0 and ConfigKit v1.1.0. The ckprompt
|
| Selection | Core | ckconfig | ckprompt | Upstream libraries and status |
|
||||||
v0.3.0 candidate targets those releases and PromptKit v0.20.0. A Go 1.27.0
|
| --- | --- | --- | --- | --- |
|
||||||
workspace may compose the three local modules. Current ckprompt source uses a
|
| Published core | v0.4.0 | — | — | Usable independently. |
|
||||||
diagnostic helper introduced in local ckconfig source that is absent from
|
| Published ConfigKit integration | v0.4.0 | v0.4.0 | — | ConfigKit v1.1.0. |
|
||||||
released ckconfig v0.4.0; independent ckprompt builds require release and
|
| Earlier matched integration set | v0.3.0 | v0.2.0 | v0.2.0 | ConfigKit v0.8.0 and PromptKit v0.16.0, using their earlier import paths. |
|
||||||
dependency alignment described in [future work](../roadmap/future.md#pending-release-and-integration-work).
|
| Current source | Local | Local | Local | ConfigKit v1.1.0 and PromptKit v0.20.0; use an aligned workspace until release dependencies are updated. |
|
||||||
|
|
||||||
The two integrations are independent optional imports. `ckprompt` uses the
|
Install the published core with:
|
||||||
public scope and error contracts from `ckconfig`; importing it does not add the
|
|
||||||
`config` family. An application that wants both families passes both returned
|
```sh
|
||||||
declarations to core. The [maintained examples](../../README.md#examples) show
|
go get go.maximumdirect.net/commandkit@v0.4.0
|
||||||
core-only, ConfigKit-only, and composed applications.
|
```
|
||||||
|
|
||||||
|
Core v0.5.0 and ckprompt v0.3.0 have unpublished candidate notes. Current
|
||||||
|
ckprompt source calls `ckconfig.AdaptDiagnostics`, which is absent from its
|
||||||
|
selected released ckconfig v0.4.0 dependency. It therefore needs local
|
||||||
|
ckconfig source in the workspace until [release
|
||||||
|
alignment](../roadmap/future.md#pending-release-and-integration-work) is
|
||||||
|
complete. Published ckconfig v0.3.0 also uses ConfigKit v1.1.0 and does not
|
||||||
|
compose with ckprompt v0.2.0's earlier ConfigKit dependency.
|
||||||
|
|
||||||
|
Importing a module does not install its commands. Pass commands to
|
||||||
|
`commandkit.New` or `App.Register` explicitly. ckprompt depends on ckconfig's
|
||||||
|
public APIs, but you can install its `promptkit` commands without installing
|
||||||
|
the `config` family.
|
||||||
|
|
||||||
## Go compatibility
|
## Go compatibility
|
||||||
|
|
||||||
@@ -57,7 +63,6 @@ default from an explicitly supplied empty, false, or zero value.
|
|||||||
package example
|
package example
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
@@ -81,8 +86,12 @@ func Greeting() commandkit.Command {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome {
|
Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome {
|
||||||
if _, err := fmt.Fprintln(invocation.Reporter().Output(), input.Count.Value); err != nil {
|
greetings := []string{}
|
||||||
return commandkit.Failure("Could not write the greeting.").WithCause(err)
|
for i := 0; i < input.Count.Value; i++ {
|
||||||
|
greetings = append(greetings, "Hello!")
|
||||||
|
}
|
||||||
|
if err := invocation.Reporter().Report(commandkit.Report{Value: greetings}); err != nil {
|
||||||
|
return commandkit.Failure("Could not write the greetings.").WithCause(err)
|
||||||
}
|
}
|
||||||
return commandkit.Success()
|
return commandkit.Success()
|
||||||
},
|
},
|
||||||
@@ -90,6 +99,10 @@ func Greeting() commandkit.Command {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Install `Greeting()` with `commandkit.New(identity, Greeting())`. By default,
|
||||||
|
`greet` prints `Hello!`; `greet --count=2` prints it twice. Add `--format
|
||||||
|
json` to receive a JSON list. A count of zero produces an empty list.
|
||||||
|
|
||||||
The application supplies `context.Context`, argv without the executable name,
|
The application supplies `context.Context`, argv without the executable name,
|
||||||
and output streams to `App.Execute`; it decides how the returned status maps to
|
and output streams to `App.Execute`; it decides how the returned status maps to
|
||||||
process exit. `New` installs generated help/version and caller declarations as
|
process exit. `New` installs generated help/version and caller declarations as
|
||||||
@@ -134,15 +147,13 @@ installation alongside aliases and integration commands.
|
|||||||
|
|
||||||
## Invocation reporting
|
## Invocation reporting
|
||||||
|
|
||||||
`Invocation.Reporter()` supplies the reporter for the current handler. Use
|
Use `Invocation.Reporter().Report` to print a value in the selected output
|
||||||
`Report()` for formatted substantive values and optional text templates;
|
format. Pass ordinary Go values and, optionally, a `text/template` for text
|
||||||
use `Output()` or `RenderOutput()` for deliberate raw output. Use `Warn`, `Info`,
|
output. Use `Warn`, `Info`, `Progress`, and `Debug` for categorized messages.
|
||||||
`Progress`, and `Debug` for categorized messages. Queue a summary with
|
Queue a summary with `AtEnd().Info` when it belongs after the handler returns.
|
||||||
`AtEnd().Info` when it belongs after the handler returns. Deferred submissions
|
Deferred submissions are accepted until finalization begins; later submissions
|
||||||
are accepted until finalization begins; later submissions return
|
return `ErrReporterClosed`. The [CLI reference](../cli.md#reporting) owns flag
|
||||||
`ErrReporterClosed`. The
|
grammar, visibility, prefixes, and status behavior.
|
||||||
[CLI reference](../cli.md#reporting) owns flag grammar, visibility, prefixes,
|
|
||||||
and status behavior.
|
|
||||||
|
|
||||||
Reports use JSON serialization to establish the common value representation
|
Reports use JSON serialization to establish the common value representation
|
||||||
for YAML and JSON. A text template receives the original value; without one,
|
for YAML and JSON. A text template receives the original value; without one,
|
||||||
@@ -159,22 +170,29 @@ write to their supplied writer only while the callback runs; they must not
|
|||||||
submit another message or start another rendering operation through the same
|
submit another message or start another rendering operation through the same
|
||||||
reporter.
|
reporter.
|
||||||
|
|
||||||
|
For example, a handler can report a count as a small mapping:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
Run: func(invocation commandkit.Invocation, input GreetInput) commandkit.Outcome {
|
if err := invocation.Reporter().Report(commandkit.Report{
|
||||||
if _, err := fmt.Fprintln(invocation.Reporter().Output(), input.Count.Value); err != nil {
|
Value: map[string]int{"count": input.Count.Value},
|
||||||
return commandkit.Failure("Could not write the greeting.").WithCause(err)
|
}); err != nil {
|
||||||
|
return commandkit.Failure("Could not write the count.").WithCause(err)
|
||||||
}
|
}
|
||||||
return commandkit.Success()
|
return commandkit.Success()
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This uses YAML automatically and supports `--format json` without a separate
|
||||||
|
encoder. Use `Output()` or `RenderOutput()` instead when you deliberately need
|
||||||
|
raw output; `--format` does not reformat those bytes.
|
||||||
|
|
||||||
After `App.Execute`, inspect the returned `Outcome`. Its `Cause` retains the
|
After `App.Execute`, inspect the returned `Outcome`. Its `Cause` retains the
|
||||||
operation error; `Presentation.Output` and `Presentation.Diagnostics` report
|
operation error; `Presentation.Output` and `Presentation.Diagnostics` report
|
||||||
delivery state and the first rendering or write errors for their destinations.
|
delivery state and the first rendering or write errors for their destinations.
|
||||||
CommandKit does not retain a message transcript. Reporter operations for one
|
Joined operation errors support `errors.Is` and `errors.As` where the
|
||||||
invocation are safe concurrently, but concurrent submission order is not
|
underlying errors do. CommandKit does not retain a message transcript.
|
||||||
specified. The caller owns the writers passed to `Execute`; CommandKit does not
|
Reporter operations for one invocation are safe concurrently, but concurrent
|
||||||
close them.
|
submission order is not specified. The caller owns the writers passed to
|
||||||
|
`Execute`; CommandKit does not close them.
|
||||||
|
|
||||||
## Application-owned aliases
|
## Application-owned aliases
|
||||||
|
|
||||||
@@ -235,18 +253,22 @@ values.
|
|||||||
|
|
||||||
Use `ckconfig.Command(ckconfig.Suite[I, S]{...})` when the application needs
|
Use `ckconfig.Command(ckconfig.Suite[I, S]{...})` when the application needs
|
||||||
multiple named scopes, selector flags, scope-aware input checks, or shared
|
multiple named scopes, selector flags, scope-aware input checks, or shared
|
||||||
acquisition state or a custom comparison provider. A declared `Diff` capability
|
acquisition state or a custom comparison provider. A declared `Diff`
|
||||||
uses `Scope.Compare`; `ckconfig.FromConfigKit` and `AppCommand` provide the
|
capability uses `Scope.Compare`; `ckconfig.FromConfigKit` and `AppCommand`
|
||||||
ConfigKit-backed implementation. `Selector.AgainstName` opts a selector into an
|
provide the ConfigKit-backed implementation. `Selector.AgainstName` opts a
|
||||||
independent right-side flag. Each comparison side gets its own initialized and
|
selector into an independent right-side flag. Each comparison side gets its
|
||||||
checked input, with only its supplied selectors applied; state is shared by the
|
own initialized and checked input, with only its supplied selectors applied;
|
||||||
invocation. Factory results
|
state is shared by the invocation. Factory results remain caller-owned, so
|
||||||
remain caller-owned, so separate initialization calls do not guarantee distinct
|
separate initialization calls do not guarantee distinct objects. See
|
||||||
objects. See
|
|
||||||
[ckconfig.Suite's GoDoc](../../integrations/ckconfig/contracts.go) for factory
|
[ckconfig.Suite's GoDoc](../../integrations/ckconfig/contracts.go) for factory
|
||||||
timing, omitted-factory zero values (including nil pointers), and ownership.
|
timing, omitted-factory zero values (including nil pointers), and ownership.
|
||||||
The application owns the state type and what it caches. `ckconfig.FromConfigKit`
|
The application owns the state type and what it caches.
|
||||||
adapts a typed ConfigKit loader without calling it during construction.
|
`ckconfig.FromConfigKit` adapts a typed ConfigKit loader without calling it
|
||||||
|
during construction. The bundled comparison adapters call the loader for the
|
||||||
|
left side before the right, retain left diagnostics if right loading fails,
|
||||||
|
and collect diagnostics from both loads before native comparison. Custom
|
||||||
|
comparison callbacks own their loading and diagnostics; loader calls need not
|
||||||
|
reread sources if the application caches them.
|
||||||
|
|
||||||
The `config` family provides scope discovery, validation, safe effective configuration display,
|
The `config` family provides scope discovery, validation, safe effective configuration display,
|
||||||
source inventory, path explanation, and ConfigKit-backed comparison for the
|
source inventory, path explanation, and ConfigKit-backed comparison for the
|
||||||
@@ -274,6 +296,8 @@ it does not install PromptKit catalog, definition, or requirements commands.
|
|||||||
Its override feature is disabled because the released PromptKit configuration
|
Its override feature is disabled because the released PromptKit configuration
|
||||||
loader does not accept ConfigKit override records.
|
loader does not accept ConfigKit override records.
|
||||||
|
|
||||||
|
### Install resource commands and optional checks
|
||||||
|
|
||||||
`ckprompt.FromEngine(loadEngine)` supplies nine callbacks: prompt, profile,
|
`ckprompt.FromEngine(loadEngine)` supplies nine callbacks: prompt, profile,
|
||||||
backend, namespace, and collection catalogs; named prompt, profile, and backend
|
backend, namespace, and collection catalogs; named prompt, profile, and backend
|
||||||
inspection; and native requirements discovery. Concrete request validation,
|
inspection; and native requirements discovery. Concrete request validation,
|
||||||
@@ -308,6 +332,8 @@ suite := ckprompt.WithRequestValidation(
|
|||||||
validationCommand := ckprompt.Command(suite)
|
validationCommand := ckprompt.Command(suite)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Request builders and loading
|
||||||
|
|
||||||
If the loader is nil, the returned suite retains a wiring issue for installation
|
If the loader is nil, the returned suite retains a wiring issue for installation
|
||||||
to report, even if capabilities are narrowed later. A builder runs before the
|
to report, even if capabilities are narrowed later. A builder runs before the
|
||||||
engine loader and receives the seed request, selection, typed input, shared
|
engine loader and receives the seed request, selection, typed input, shared
|
||||||
@@ -357,6 +383,8 @@ same canonical request flags into their own input types. Each collection exposes
|
|||||||
individual handles and an `All` method, so a command can choose its applicable
|
individual handles and an `All` method, so a command can choose its applicable
|
||||||
subset. The application decides how to apply the resulting values to its request.
|
subset. The application decides how to apply the resulting values to its request.
|
||||||
|
|
||||||
|
### Enable namespace flags
|
||||||
|
|
||||||
`ckprompt.WithNamespaces` enables standard resource namespace selection from
|
`ckprompt.WithNamespaces` enables standard resource namespace selection from
|
||||||
application-supplied defaults. Loaders used with this option should leave view
|
application-supplied defaults. Loaders used with this option should leave view
|
||||||
selection to the adapter. Without it, a loader can supply its own engine view.
|
selection to the adapter. Without it, a loader can supply its own engine view.
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ capability proposals in [future work](roadmap/future.md).
|
|||||||
| Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0002](adr/0002-public-facade-and-cli-backend.md), [ADR 0004](adr/0004-optional-integration-modules.md), and the architecture policy |
|
| Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0002](adr/0002-public-facade-and-cli-backend.md), [ADR 0004](adr/0004-optional-integration-modules.md), and the architecture policy |
|
||||||
| Module ownership and public contracts | [Consumer guide](consumers/guide.md), [internal overview](internal/overview.md), [core GoDoc](../doc.go), [ckconfig GoDoc](../integrations/ckconfig/doc.go), [ckprompt GoDoc](../integrations/ckprompt/doc.go), and applicable ADRs |
|
| Module ownership and public contracts | [Consumer guide](consumers/guide.md), [internal overview](internal/overview.md), [core GoDoc](../doc.go), [ckconfig GoDoc](../integrations/ckconfig/doc.go), [ckprompt GoDoc](../integrations/ckprompt/doc.go), and applicable ADRs |
|
||||||
| Unfinished work and capability proposals | [Future work](roadmap/future.md) |
|
| Unfinished work and capability proposals | [Future work](roadmap/future.md) |
|
||||||
| Documentation refresh sprint | [Documentation roadmap](roadmap/documentation-refresh.md) |
|
| Documentation refresh record | [Documentation roadmap](roadmap/documentation-refresh.md) |
|
||||||
| Completed planning and implementation history | [Completed dependency upgrades, PromptKit validation, discovery, smoke testing, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/a6278a6d9f940948ec7745955d745523aaff0734/docs/roadmap), [earlier ConfigKit and PromptKit adoption and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap), [earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap), and [completed module implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/bb2528532b78d30e52f5082e491a5e1fd9b0fb99/docs/roadmap) in Git history |
|
| Completed planning and implementation history | [Completed dependency upgrades, PromptKit validation, discovery, smoke testing, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/a6278a6d9f940948ec7745955d745523aaff0734/docs/roadmap), [earlier ConfigKit and PromptKit adoption and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap), [earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap), and [completed module implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/bb2528532b78d30e52f5082e491a5e1fd9b0fb99/docs/roadmap) in Git history |
|
||||||
| Release tooling | [Maintainer release procedure](release.md) |
|
| Release tooling | [Maintainer release procedure](release.md) |
|
||||||
| Performance maintenance | [Internal overview](internal/overview.md), existing benchmarks, and [possible further efficiency work](roadmap/future.md#possible-further-efficiency-work) |
|
| Performance maintenance | [Internal overview](internal/overview.md), existing benchmarks, and [possible further efficiency work](roadmap/future.md#possible-further-efficiency-work) |
|
||||||
@@ -107,8 +107,16 @@ Sibling-checkout references in retired planning records are historical review
|
|||||||
evidence, not build dependencies. Implemented contracts belong in CommandKit
|
evidence, not build dependencies. Implemented contracts belong in CommandKit
|
||||||
under their canonical owners.
|
under their canonical owners.
|
||||||
|
|
||||||
The root module does not traverse nested modules. Preserve the ignored `go.work`
|
The root module does not traverse nested modules. With Go 1.27.0 on `PATH`,
|
||||||
and `go.work.sum`; use `GOWORK=off GOTOOLCHAIN=local` for dependency preparation
|
create the local workspace from the repository root if `go.work` is absent:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go work init . ./integrations/ckconfig ./integrations/ckprompt
|
||||||
|
```
|
||||||
|
|
||||||
|
If a workspace already exists, ensure it includes these three modules. Preserve
|
||||||
|
the ignored `go.work` and `go.work.sum`; do not commit them. Use
|
||||||
|
`GOWORK=off GOTOOLCHAIN=local` for dependency preparation
|
||||||
and independent module suites. The integrations select released core v0.4.0;
|
and independent module suites. The integrations select released core v0.4.0;
|
||||||
ckprompt also selects released ckconfig v0.4.0.
|
ckprompt also selects released ckconfig v0.4.0.
|
||||||
Current ckprompt source requires a ckconfig helper absent from that release, so
|
Current ckprompt source requires a ckconfig helper absent from that release, so
|
||||||
|
|||||||
@@ -1,32 +1,28 @@
|
|||||||
# CommandKit v0.5.0
|
# CommandKit v0.5.0
|
||||||
|
|
||||||
CommandKit v0.5.0 fixes defects in deferred reporting and YAML value preservation,
|
CommandKit v0.5.0 fixes lost deferred messages and preserves YAML value types
|
||||||
reduces repeated work in command installation and alias help, and simplifies
|
more accurately. It also reduces repeated work when installing commands and
|
||||||
typed input preparation and replay of captured flags.
|
showing alias help, and refreshes documentation and help text.
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
- Acceptance of deferred messages now closes atomically when invocation finalization
|
- Deferred messages accepted before finalization are retained for final reporting;
|
||||||
begins. Concurrent submissions are included in the final batch or rejected
|
they can no longer be silently lost when a handler finishes. Later submissions return
|
||||||
with `ErrReporterClosed`; accepted messages can no longer be silently lost
|
`ErrReporterClosed`.
|
||||||
between batch detachment and closure.
|
- Finished invocations release their direct references to output and diagnostic
|
||||||
- Finalized reporting state releases its direct references to borrowed output
|
writers while keeping delivery results available. Applications still own the
|
||||||
and diagnostic writers while retaining presentation results. Writers remain
|
writers.
|
||||||
caller-owned.
|
- `DecodeYAMLReport` preserves numeric-looking strings as strings. YAML report
|
||||||
- `DecodeYAMLReport` follows resolved YAML scalar tags, preserving numeric-looking
|
output also preserves explicitly tagged numbers beyond the YAML resolver's
|
||||||
strings as strings. YAML report rendering preserves explicit numeric meaning
|
ordinary numeric range.
|
||||||
for values beyond the resolver's ordinary numeric range.
|
- Command installation, alias help, and typed input handling avoid repeated
|
||||||
- Compilation of flag aliases reuses resolved chain suffixes. Alias discovery and
|
work. Parsing and completion share flag handling while retaining their
|
||||||
help reuse the existing source tree, and declaration validation reuses one
|
different treatment of errors and unfinished input.
|
||||||
scratch path across siblings, formatting paths only for diagnostics.
|
- The reporting example now works when its optional scenario is omitted, and
|
||||||
- Typed input preparation reconstructs occurrence order without general sorting;
|
the interactive completion fixture no longer conflicts with `--format`.
|
||||||
replay of captured flags merges already ordered streams. Parsing and completion
|
`FlagMeta` documents existing naming and reserved-spelling rules.
|
||||||
share flag-consumption mechanics while retaining their distinct handling of
|
- READMEs, CLI instructions, examples, and generated help use clearer language
|
||||||
errors and incomplete input.
|
and explain common tasks before implementation details.
|
||||||
- The core reporting example preserves its default scenario when the optional
|
|
||||||
operand is omitted. The interactive completion fixture no longer collides with
|
|
||||||
the reserved `--format` flag. `FlagMeta` documentation now states the existing
|
|
||||||
naming and reserved-spelling rules.
|
|
||||||
|
|
||||||
## Compatibility and upgrade
|
## Compatibility and upgrade
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Documentation refresh
|
# Documentation refresh
|
||||||
|
|
||||||
Status: agreed scope; ready for implementation planning. The refresh has not
|
Status: implemented and verified. Release/dependency alignment remains separate
|
||||||
been implemented.
|
work in [future.md](future.md#pending-release-and-integration-work).
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
@@ -197,18 +197,57 @@ Do not add wording snapshots, readability gates, or a new checker framework.
|
|||||||
Record workspace and independent-module results separately, including any
|
Record workspace and independent-module results separately, including any
|
||||||
dependency limitation. This work adds no release gates.
|
dependency limitation. This work adds no release gates.
|
||||||
|
|
||||||
- [ ] README openings explain purpose and give a clear starting path.
|
- [x] README openings explain purpose and give a clear starting path.
|
||||||
- [ ] CLI sections explain operator tasks before reference detail; necessary
|
- [x] CLI sections explain operator tasks before reference detail; necessary
|
||||||
behavior, report fields, status rules, and limitations remain discoverable.
|
behavior, report fields, status rules, and limitations remain discoverable.
|
||||||
- [ ] Example setup is explicit, commands have nearby explanations, and intended
|
- [x] Example setup is explicit, commands have nearby explanations, and intended
|
||||||
failures are labeled.
|
failures are labeled.
|
||||||
- [ ] Consumer guidance demonstrates formatted reporting, has a coherent initial
|
- [x] Consumer guidance demonstrates formatted reporting, has a coherent initial
|
||||||
example, and distinguishes published compatibility from current source needs.
|
example, and distinguishes published compatibility from current source needs.
|
||||||
- [ ] Package introductions and generated help use clear, accurate language;
|
- [x] Package introductions and generated help use clear, accurate language;
|
||||||
precise API contracts remain intact.
|
precise API contracts remain intact.
|
||||||
- [ ] Unpublished release notes explain benefits and consumer impact while
|
- [x] Unpublished release notes explain benefits and consumer impact while
|
||||||
historical records and required notices remain preserved.
|
historical records and required notices remain preserved.
|
||||||
- [ ] Changed commands, snippets, and help have appropriate verification; local
|
- [x] Changed commands, snippets, and help have appropriate verification; local
|
||||||
links and Markdown whitespace checks pass.
|
links and Markdown whitespace checks pass.
|
||||||
- [ ] Final review confirms consistent terminology, canonical ownership, and no
|
- [x] Final review confirms consistent terminology, canonical ownership, and no
|
||||||
unintended behavior or contract changes.
|
unintended behavior or contract changes.
|
||||||
|
|
||||||
|
## Implementation and verification
|
||||||
|
|
||||||
|
Completed the six work areas above. READMEs and package introductions now lead
|
||||||
|
with purpose and starting points; the CLI reference separates operator tasks
|
||||||
|
from report detail and developer wiring. Examples are grouped by task with
|
||||||
|
setup, expected results, and intentional failures explained nearby. The consumer
|
||||||
|
guide demonstrates shared report formatting and distinguishes published modules
|
||||||
|
from current source. Help strings and unpublished candidate notes use the same
|
||||||
|
plain language. Exact symbol contracts and runtime behavior were preserved.
|
||||||
|
|
||||||
|
Verification used Go 1.27.0 and existing cached dependencies:
|
||||||
|
|
||||||
|
- The aligned workspace suites passed for core, ckconfig, and ckprompt, including
|
||||||
|
their maintained examples.
|
||||||
|
- Independent core and ckconfig suites passed with `GOWORK=off`.
|
||||||
|
- Independent ckprompt compilation confirmed the existing dependency limitation:
|
||||||
|
released ckconfig v0.4.0 lacks `AdaptDiagnostics`. No module requirements,
|
||||||
|
checksums, or workspace files were changed to hide it. Its README, example,
|
||||||
|
consumer guidance, and candidate note identify the pending alignment.
|
||||||
|
- All 48 `go run` invocations in the three example READMEs were exercised with
|
||||||
|
binaries built from the aligned workspace, from the documented directories.
|
||||||
|
Results matched the walkthroughs, including two failed-load examples, missing
|
||||||
|
request input, and comparison status 3. Shared help and completion behavior
|
||||||
|
also passed the existing suites; representative rendered help was inspected.
|
||||||
|
- Both new consumer-guide report snippets compiled in a temporary consumer using
|
||||||
|
local core. Six checks confirmed greeting counts, empty-list output, and YAML
|
||||||
|
and JSON formatting.
|
||||||
|
- Local Markdown links, including incoming links to renamed sections, and
|
||||||
|
whitespace were checked. Go source changes are limited to help strings,
|
||||||
|
package comments, and formatting; no new tests or validation framework were
|
||||||
|
added.
|
||||||
|
- The authoritative remote had neither the core v0.5.0 nor ckprompt v0.3.0 tag
|
||||||
|
when their candidate notes were revised. Published notes, accepted ADRs,
|
||||||
|
policies, and license/attribution records were left intact.
|
||||||
|
|
||||||
|
The updated ckprompt candidate still requires dependency guidance to be finalized
|
||||||
|
when release alignment occurs. This is release preparation, not unfinished
|
||||||
|
editorial work or evidence of an independently buildable candidate.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Future work
|
# Future work
|
||||||
|
|
||||||
Status: documentation refresh, pending release/dependency alignment, optional
|
Status: pending release/dependency alignment, optional shell validation, and
|
||||||
shell validation, and future capability proposals.
|
future capability proposals.
|
||||||
No delivery dates are selected here.
|
No delivery dates are selected here.
|
||||||
|
|
||||||
## Purpose and authority
|
## Purpose and authority
|
||||||
@@ -30,13 +30,6 @@ an idea here does not select its syntax, API, priority, or delivery date.
|
|||||||
|
|
||||||
## Pending release and integration work
|
## Pending release and integration work
|
||||||
|
|
||||||
### Documentation refresh
|
|
||||||
|
|
||||||
The agreed [documentation roadmap](documentation-refresh.md) owns the upcoming
|
|
||||||
clarity refresh, its scope, sequence, and completion checklist. The work covers
|
|
||||||
operator instructions and public introductions while retaining necessary
|
|
||||||
technical detail in developer documentation.
|
|
||||||
|
|
||||||
### Audit remediation release alignment
|
### Audit remediation release alignment
|
||||||
|
|
||||||
The audit remediation is complete in source. The released ckconfig v0.4.0 does
|
The audit remediation is complete in source. The released ckconfig v0.4.0 does
|
||||||
|
|||||||
@@ -1,38 +1,70 @@
|
|||||||
# Core example
|
# Core example
|
||||||
|
|
||||||
Run the example from the repository root:
|
This example shows typed flags, command shortcuts, shared reporting, and shell
|
||||||
|
completion. It needs no external service. See the [consumer guide](../../docs/consumers/guide.md#go-compatibility)
|
||||||
|
for Go requirements; maintainers use the toolchain in the
|
||||||
|
[developer guide](../../docs/development.md#documentation-validation).
|
||||||
|
|
||||||
|
Run from the repository root, with that Go toolchain on `PATH`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
export GOWORK=off GOTOOLCHAIN=local
|
||||||
|
go run ./examples/core workspace greet --count=2
|
||||||
|
```
|
||||||
|
|
||||||
|
The result shows the selected count and whether it was supplied. It also shows
|
||||||
|
the entered command path and the original command path, which differ when you
|
||||||
|
use a shortcut.
|
||||||
|
|
||||||
|
## Try shortcuts and explicit values
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# The hello shortcut runs workspace greet; --times means --count.
|
||||||
go run ./examples/core hello --times=0 --tag=first
|
go run ./examples/core hello --times=0 --tag=first
|
||||||
|
# ws is a shortcut for the workspace group.
|
||||||
go run ./examples/core ws greet --count=2
|
go run ./examples/core ws greet --count=2
|
||||||
|
# Inspect the group or use the example's global help alias.
|
||||||
go run ./examples/core ws --help
|
go run ./examples/core ws --help
|
||||||
go run ./examples/core hello --hlep
|
go run ./examples/core hello --hlep
|
||||||
|
```
|
||||||
|
|
||||||
|
An explicit zero remains a supplied value. The handler prints both
|
||||||
|
`Invocation.EnteredPath()` and `Invocation.CanonicalPath()` so you can see how
|
||||||
|
shortcuts resolve.
|
||||||
|
|
||||||
|
## Try reporting
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run ./examples/core report
|
||||||
|
go run ./examples/core report --verbose
|
||||||
|
go run ./examples/core report --quiet
|
||||||
|
```
|
||||||
|
|
||||||
|
The default scenario succeeds and writes its result. Verbose mode also shows
|
||||||
|
warnings and information; quiet mode hides the result. The
|
||||||
|
[CLI reference](../../docs/cli.md#reporting) defines the shared visibility rules.
|
||||||
|
|
||||||
|
## Try shell completion
|
||||||
|
|
||||||
|
```sh
|
||||||
go build -o core-example ./examples/core
|
go build -o core-example ./examples/core
|
||||||
./core-example completion bash
|
./core-example completion bash
|
||||||
```
|
```
|
||||||
|
|
||||||
The example installs a canonical `workspace greet` command together with a
|
This prints the Bash completion script. Initialize `bash-completion`, then load
|
||||||
command shortcut, a group shortcut, a scoped flag alias, and a global help
|
the script as described in the [CLI reference](../../docs/cli.md#shell-completion).
|
||||||
alias. Its declaration slice mixes the canonical group and routing rules as
|
Use the executable basename `core-example` and try completing
|
||||||
`[]commandkit.Declaration`. The handler prints `Invocation.EnteredPath()` and
|
`core-example report d` or `core-example ws gr`. Other supported shells are
|
||||||
`Invocation.CanonicalPath()` so the alternate route and its canonical target
|
listed in the reference.
|
||||||
are visible in the output.
|
|
||||||
|
|
||||||
The example also installs `Completion("core-example")` and gives the `report`
|
## How it is wired
|
||||||
scenario argument static choices. Initialize `bash-completion` first if using
|
|
||||||
Bash. Build it with the basename shown above, load
|
|
||||||
the script for your shell using the [CLI reference](../../docs/cli.md#shell-completion),
|
|
||||||
and try completing `core-example report d` or `core-example ws gr`.
|
|
||||||
|
|
||||||
Compatible integration factories also return `commandkit.Command` and can be
|
The example installs `workspace greet` alongside command and flag aliases in a
|
||||||
passed directly to `New` beside `commandkit.Alias` or flag-alias declarations.
|
`[]commandkit.Declaration`. It also installs `Completion("core-example")` and
|
||||||
The matched ckconfig and ckprompt releases use the new core identity. For a
|
provides static choices for the reporting scenario argument. The
|
||||||
command-only `[]commandkit.Command`, convert its elements into a
|
|
||||||
`[]commandkit.Declaration` before appending routing rules; Go cannot expand the
|
|
||||||
command slice as `...commandkit.Declaration`. The
|
|
||||||
[consumer guide](../../docs/consumers/guide.md#application-owned-aliases)
|
[consumer guide](../../docs/consumers/guide.md#application-owned-aliases)
|
||||||
shows both forms, and the [composed consumer](../../integrations/ckprompt/examples/composed)
|
explains declaration composition; the [composed example](../../integrations/ckprompt/examples/composed)
|
||||||
is the maintained integration example.
|
adds integration commands.
|
||||||
|
|
||||||
These aliases require core v0.3.0. Repository contributors can run its test with
|
Run `GOWORK=off GOTOOLCHAIN=local go test ./examples/core` from the repository
|
||||||
`go test ./examples/core` from the root.
|
root to check this example.
|
||||||
|
|||||||
@@ -1,36 +1,30 @@
|
|||||||
# CommandKit ckconfig
|
# CommandKit ckconfig
|
||||||
|
|
||||||
`ckconfig` is the optional ConfigKit integration for CommandKit. It adapts
|
`ckconfig` adds configuration inspection commands to Go applications that use
|
||||||
ConfigKit loaders and scopes into reusable `commandkit.Command` declarations;
|
CommandKit and ConfigKit. Operators can view settings, validate configuration,
|
||||||
installing the integration is explicit and does not modify an application by
|
find where values came from, and compare two configurations.
|
||||||
itself.
|
|
||||||
|
The application chooses which commands to install. Importing the package alone
|
||||||
|
does not install commands.
|
||||||
|
|
||||||
## Module
|
## Module
|
||||||
|
|
||||||
The module path is `go.maximumdirect.net/ckconfig`. Version v0.4.0 requires Go
|
The module path is `go.maximumdirect.net/ckconfig`. It does not import PromptKit.
|
||||||
1.27.0 and uses `go.maximumdirect.net/commandkit v0.4.0` and
|
See the [consumer guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#module-selection)
|
||||||
`go.maximumdirect.net/configkit v1.1.0`; it does not import PromptKit. See the
|
for compatible releases and Go requirements.
|
||||||
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
|
|
||||||
for exact callback and lifetime contracts.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
For one application configuration scope, install the convenience declaration:
|
To inspect one application configuration, pass your loader to `AppCommand`:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
app, err := commandkit.New(identity, ckconfig.AppCommand(loadAppConfig))
|
app, err := commandkit.New(identity, ckconfig.AppCommand(loadAppConfig))
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `ckconfig.Command(ckconfig.Suite[Input, State]{...})` to define named
|
For multiple named configurations or application-specific flags, use
|
||||||
scopes, selectors, input checks, and state shared by the selected acquisitions
|
`ckconfig.Command` with a `ckconfig.Suite`. The
|
||||||
or comparison in a config invocation. `ckconfig.FromConfigKit` adapts a typed
|
[integration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
|
||||||
ConfigKit loader. The `config` command family exposes scope discovery and the
|
explains loader setup, inputs, and shared state.
|
||||||
validate, show, sources, explain, and diff operations supported by the declared
|
|
||||||
scopes. Source reports include native destination, placement, destination
|
|
||||||
fallback, version evidence, and empty-import selections. Comparison returns
|
|
||||||
ConfigKit's native records to shared report rendering; the
|
|
||||||
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#compare-configuration-selections)
|
|
||||||
owns its operator details.
|
|
||||||
|
|
||||||
The maintained [simple example](examples/simple) shows a complete consumer.
|
The maintained [simple example](examples/simple) shows a complete consumer.
|
||||||
The [CommandKit CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#configuration-scopes)
|
The [CommandKit CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#configuration-scopes)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// Package ckconfig, provided by go.maximumdirect.net/ckconfig, provides
|
// Package ckconfig adds commands to view, validate, explain, and compare
|
||||||
// CommandKit's optional ConfigKit v1.1.0 integration, requiring Go 1.27.0. Its
|
// ConfigKit configuration in CommandKit applications.
|
||||||
// canonical Command declaration installs the standard config command family
|
//
|
||||||
// through the core commandkit package. Applications can install CommandKit
|
// Use AppCommand for one application configuration loader, or Command with a
|
||||||
// RoutingRule declarations alongside it through commandkit.New or
|
// Suite for multiple named configurations and application-specific flags.
|
||||||
// App.Register. Source reports preserve ConfigKit's destination, placement,
|
// Install the returned command with commandkit.New or App.Register.
|
||||||
// version, and empty-import evidence. Invocation reporting applies CommandKit's shared
|
// Importing this package alone installs no commands.
|
||||||
// visibility and delivery policy; provider warnings remain independent of
|
//
|
||||||
// failure explanations. Importing ckconfig alone installs no commands.
|
// ConfigKit owns configuration loading and interpretation. CommandKit formats
|
||||||
|
// reports and messages using its shared reporting policy.
|
||||||
package ckconfig
|
package ckconfig
|
||||||
|
|||||||
@@ -1,37 +1,90 @@
|
|||||||
# Simple consumer
|
# ConfigKit example
|
||||||
|
|
||||||
This example imports `go.maximumdirect.net/ckconfig` and
|
This example adds configuration inspection and a custom `greet` command to a
|
||||||
`go.maximumdirect.net/commandkit`; ckconfig v0.4.0 uses core
|
small application. It uses local fixtures and in-memory defaults, with no
|
||||||
v0.4.0, ConfigKit v1.1.0, and Go 1.27.0. Set `GOWORK=off GOTOOLCHAIN=local`
|
external services. See [module selection](../../../../docs/consumers/guide.md#module-selection)
|
||||||
for the commands below.
|
for dependencies and Go requirements. Use Go 1.27.0 on `PATH` for this checkout.
|
||||||
|
|
||||||
Run the maintained example with:
|
From the repository root:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
cd integrations/ckconfig/examples/simple
|
||||||
|
export GOWORK=off GOTOOLCHAIN=local
|
||||||
go run . config show
|
go run . config show
|
||||||
go run . config show --config fixtures/before.yml --verbose
|
```
|
||||||
go run . config show --config fixtures/before.yml --quiet
|
|
||||||
|
The output includes the default greeting, `Hello`, and schema version 2.
|
||||||
|
This example can run against its declared released dependencies with the
|
||||||
|
workspace disabled.
|
||||||
|
|
||||||
|
## Inspect and override a value
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Discover configuration paths under schema.
|
||||||
go run . config explain --list --under /schema
|
go run . config explain --list --under /schema
|
||||||
|
# Change the greeting for this invocation and show just that value.
|
||||||
go run . config show --path /greeting --set '/greeting="Hi"'
|
go run . config show --path /greeting --set '/greeting="Hi"'
|
||||||
|
```
|
||||||
|
|
||||||
|
The second command prints `Hi`. It does not edit a file.
|
||||||
|
|
||||||
|
## Compare configurations
|
||||||
|
|
||||||
|
```sh
|
||||||
go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml
|
go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
The report includes `changes.greeting: Goodbye`.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Expected status 3: the overridden greeting differs from the ordinary default.
|
||||||
go run . config diff --set '/greeting="Hi"' --details --check
|
go run . config diff --set '/greeting="Hi"' --details --check
|
||||||
|
```
|
||||||
|
|
||||||
|
This compares the overridden left side with ordinary configuration on the
|
||||||
|
right. `go run` prints `exit status 3` and itself exits with status 1; a built
|
||||||
|
executable returns the application's status 3 directly.
|
||||||
|
|
||||||
|
## Inspect warnings and failed loads
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Schema version 1 produces a warning, visible in verbose mode.
|
||||||
|
go run . config show --config fixtures/before.yml --verbose
|
||||||
|
# Quiet mode hides the configuration report and warning.
|
||||||
|
go run . config show --config fixtures/before.yml --quiet
|
||||||
|
```
|
||||||
|
|
||||||
|
Ordinary mode hides the warning but still displays configuration.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Intentional failure: show detailed validation findings for the invalid fixture.
|
||||||
go run . config validate --config fixtures/invalid.yml --details --severity error
|
go run . config validate --config fixtures/invalid.yml --details --severity error
|
||||||
|
# Intentional failure: still show the source recorded before loading failed.
|
||||||
go run . config sources --config fixtures/invalid.yml --source-id source-1
|
go run . config sources --config fixtures/invalid.yml --source-id source-1
|
||||||
|
```
|
||||||
|
|
||||||
|
Both commands retain the load failure. `source-1` belongs to this fixture's
|
||||||
|
load; other configurations can have different source IDs. See the
|
||||||
|
[CLI reference](../../../../docs/cli.md#configuration-scopes) for report and status rules.
|
||||||
|
|
||||||
|
## Try a custom command
|
||||||
|
|
||||||
|
```sh
|
||||||
go run . greet
|
go run . greet
|
||||||
go run . greet --count=0 --tag=first --tag second
|
go run . greet --count=0 --tag=first --tag second
|
||||||
```
|
```
|
||||||
|
|
||||||
The `config` family comes from one typed ConfigKit scope. The custom `greet`
|
The handler reports its greeting, count, and tags. It distinguishes an omitted
|
||||||
command uses CommandKit's typed bindings and shows the difference between an
|
count from an explicitly supplied zero and preserves repeated tag order.
|
||||||
omitted `--count` and an explicitly supplied zero, plus ordered repeated tags.
|
|
||||||
With no `--config`, application settings use the in-memory default. A supplied
|
## How it is wired
|
||||||
configuration and overlay are passed to ConfigKit unchanged. The comparison
|
|
||||||
command loads the two local fixtures and reports `changes.greeting: Goodbye`.
|
One ConfigKit scope supplies the standard `config` commands. Without `--config`,
|
||||||
The before fixture uses schema version 1, which ConfigKit reports as a provider
|
its loader uses an in-memory default. Supplied configuration and overlay values
|
||||||
warning in verbose mode. Ordinary mode hides the warning while preserving the
|
are passed to ConfigKit unchanged. The scope enables temporary overrides and
|
||||||
effective YAML report; quiet mode suppresses that report.
|
passes them into its ordinary ConfigKit load. The
|
||||||
The invalid fixture demonstrates a failed-load report and captured source
|
[consumer guide](../../../../docs/consumers/guide.md#configkit-scopes) explains
|
||||||
inventory; `source-1` is the ID from that fixture's acquisition. The scope opts
|
loader and scope setup.
|
||||||
in to transient overrides and passes them into its normal ConfigKit load. The
|
|
||||||
diff example compares an overridden left side with ordinary configuration on
|
Run `GOWORK=off GOTOOLCHAIN=local go test ./...` from this example directory to
|
||||||
the right and returns status 3 because the values differ.
|
check it against its declared dependencies.
|
||||||
|
|||||||
@@ -73,13 +73,13 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
|||||||
scopeChoices = append(scopeChoices, commandkit.CompletionChoice{Value: "all"})
|
scopeChoices = append(scopeChoices, commandkit.CompletionChoice{Value: "all"})
|
||||||
}
|
}
|
||||||
flags := []commandkit.Flag[*configCommandInput[I, S]]{
|
flags := []commandkit.Flag[*configCommandInput[I, S]]{
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "scope", Usage: "Configuration scope name or all where supported.", Completion: commandkit.CompleteChoices(scopeChoices...)}, &defaultScope, parseConfigString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "scope", Usage: "Select a named configuration, or all where supported.", Completion: commandkit.CompleteChoices(scopeChoices...)}, &defaultScope, parseConfigString,
|
||||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).scope = value }),
|
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).scope = value }),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
||||||
(*input).selection.Config = value
|
(*input).selection.Config = value
|
||||||
}),
|
}),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Overlay source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
||||||
(*input).selection.Overlay = value
|
(*input).selection.Overlay = value
|
||||||
}),
|
}),
|
||||||
@@ -89,11 +89,11 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
|||||||
}
|
}
|
||||||
if operation == Validate {
|
if operation == Validate {
|
||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show native validation findings."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show detailed validation findings."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
||||||
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "severity", Usage: "Filter detailed findings by error or warning."}, []configkit.Severity(nil), parseValidationSeverity, func(input **configCommandInput[I, S], value commandkit.Supplied[[]configkit.Severity]) {
|
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "severity", Usage: "Filter detailed findings by error or warning."}, []configkit.Severity(nil), parseValidationSeverity, func(input **configCommandInput[I, S], value commandkit.Supplied[[]configkit.Severity]) {
|
||||||
(*input).severities = value.Value
|
(*input).severities = value.Value
|
||||||
}),
|
}),
|
||||||
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "code", Usage: "Filter detailed findings by exact native code."}, []string(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[[]string]) {
|
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "code", Usage: "Filter detailed findings by exact diagnostic code."}, []string(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[[]string]) {
|
||||||
(*input).codes = value.Value
|
(*input).codes = value.Value
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -114,16 +114,16 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
|||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer path to explain."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }),
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer path to explain."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }),
|
||||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "list", Usage: "List configuration paths."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).list = value }),
|
commandkit.BoolFlag(commandkit.FlagMeta{Name: "list", Usage: "List configuration paths."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).list = value }),
|
||||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "historical", Usage: "Include historical-only paths when listing."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).historical = value }),
|
commandkit.BoolFlag(commandkit.FlagMeta{Name: "historical", Usage: "Include paths that exist only in configuration history."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).historical = value }),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "under", Usage: "List paths under a JSON Pointer."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).under = value }),
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "under", Usage: "List paths under a JSON Pointer."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).under = value }),
|
||||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "explicit", Usage: "Filter listed current paths by explicitness."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).explicit = value }),
|
commandkit.BoolFlag(commandkit.FlagMeta{Name: "explicit", Usage: "Filter current paths by whether ConfigKit marks them explicit."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).explicit = value }),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if operation == Show {
|
if operation == Show {
|
||||||
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer to one effective value."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }))
|
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer to one effective value."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }))
|
||||||
}
|
}
|
||||||
if operation == Sources {
|
if operation == Sources {
|
||||||
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "source-id", Usage: "Select one source ID from this acquisition."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).sourceID = value }))
|
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "source-id", Usage: "Show one source ID from this configuration load."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).sourceID = value }))
|
||||||
}
|
}
|
||||||
flags = append(flags, commandkit.CaptureFlags(prepared.bindingsByOperation[operation], func(input **configCommandInput[I, S]) *commandkit.FlagValues[I] {
|
flags = append(flags, commandkit.CaptureFlags(prepared.bindingsByOperation[operation], func(input **configCommandInput[I, S]) *commandkit.FlagValues[I] {
|
||||||
if input == nil || *input == nil {
|
if input == nil || *input == nil {
|
||||||
@@ -160,7 +160,7 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
|||||||
|
|
||||||
func comparisonOperationFlags[I, S any]() []commandkit.Flag[*configCommandInput[I, S]] {
|
func comparisonOperationFlags[I, S any]() []commandkit.Flag[*configCommandInput[I, S]] {
|
||||||
return []commandkit.Flag[*configCommandInput[I, S]]{
|
return []commandkit.Flag[*configCommandInput[I, S]]{
|
||||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show native before and after difference evidence."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show before and after values with presence and redaction details."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
||||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "check", Usage: "Return status 3 when differences are found."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).check = value }),
|
commandkit.BoolFlag(commandkit.FlagMeta{Name: "check", Usage: "Return status 3 when differences are found."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).check = value }),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "against-config", Usage: "Configuration source for the right side.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "against-config", Usage: "Configuration source for the right side.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
||||||
@@ -191,7 +191,7 @@ func operationDeclaration(operation Operation) (string, string) {
|
|||||||
case Explain:
|
case Explain:
|
||||||
return "explain", "Explain a configuration path."
|
return "explain", "Explain a configuration path."
|
||||||
case Diff:
|
case Diff:
|
||||||
return "diff", "Compare two configuration selections."
|
return "diff", "Compare two configurations."
|
||||||
default:
|
default:
|
||||||
return string(operation), "Inspect configuration."
|
return string(operation), "Inspect configuration."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,40 @@
|
|||||||
# CommandKit ckprompt
|
# CommandKit ckprompt
|
||||||
|
|
||||||
`ckprompt` is the optional PromptKit integration for CommandKit. It adapts
|
`ckprompt` adds PromptKit inspection and testing commands to Go applications
|
||||||
PromptKit engine configuration, native comparison, five catalogs, named
|
that use CommandKit. Operators can list prompts, profiles, and backends, inspect
|
||||||
inspection, requirements discovery and validation, and native smoke tests.
|
their settings, discover required inputs, validate and preview requests, and
|
||||||
Importing it does not install either command family.
|
run smoke tests.
|
||||||
|
|
||||||
|
The application chooses which commands to install. Importing the package alone
|
||||||
|
does not install commands.
|
||||||
|
|
||||||
## Module
|
## Module
|
||||||
|
|
||||||
The module path is `go.maximumdirect.net/ckprompt`. This source uses Go 1.27.0,
|
The module path is `go.maximumdirect.net/ckprompt`. See the
|
||||||
`go.maximumdirect.net/commandkit v0.4.0`, `go.maximumdirect.net/ckconfig v0.4.0`,
|
[consumer guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#module-selection)
|
||||||
`go.maximumdirect.net/configkit v1.1.0`, and `go.maximumdirect.net/promptkit v0.20.0`. See the
|
for compatible releases, Go requirements, and the current source's dependency
|
||||||
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements)
|
alignment requirement.
|
||||||
for callback, input, state, and acquisition contracts.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Add `ckprompt.ConfigScope(loadEngine)` to the scopes passed to
|
Pass your engine loader to `FromEngine` to add resource listings, inspection,
|
||||||
`ckconfig.Command` when the application wants PromptKit engine configuration
|
and requirements discovery:
|
||||||
and native comparison in the `config` family. Install
|
|
||||||
`ckprompt.Command(ckprompt.FromEngine(loadEngine))` separately for catalogs,
|
```go
|
||||||
named inspections, and requirements discovery. `FromEngine` supplies nine
|
app, err := commandkit.New(identity, ckprompt.Command(ckprompt.FromEngine(loadEngine)))
|
||||||
PromptKit-backed callbacks: four inspections and five catalogs. Applications
|
```
|
||||||
may narrow, wrap, or replace them before capture or provide custom callbacks
|
|
||||||
with `ckprompt.Suite`. Add concrete request validation, prepared-request preview,
|
Add request validation, preview, and smoke tests with `WithRequestValidation`,
|
||||||
and smoke testing explicitly with `WithRequestValidation`,
|
`WithRequestPreparation`, and `WithSmokeTesting`. To expose engine configuration
|
||||||
`WithRequestPreparation`, and `WithSmokeTesting`. Inspection,
|
under `config`, add `ckprompt.ConfigScope(loadEngine)` to a `ckconfig.Suite`.
|
||||||
requirements, and catalog operations do not execute prompts or contact model
|
The [integration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements)
|
||||||
providers; application loaders and callbacks retain their own effects. Smoke
|
explains these choices; the [composed example](examples/composed) shows them together.
|
||||||
testing invokes the selected native PromptKit operation; the
|
|
||||||
application retains ownership of client and configuration choices. See the
|
Inspection commands do not call the model. Smoke tests can use the application's
|
||||||
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#promptkit-smoke-testing)
|
configured client or network probes. Applications own engine setup, credentials,
|
||||||
for operator commands and report semantics. The maintained
|
and any effects of their loaders and callbacks. See the
|
||||||
[composed example](examples/composed) shows complete application wiring.
|
[CLI reference](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/cli.md#promptkit-smoke-testing)
|
||||||
|
for commands and results.
|
||||||
|
|
||||||
## License and attribution
|
## License and attribution
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func buildCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration
|
|||||||
showCommands = append(showCommands, newPreparationCommand(suite, aliases))
|
showCommands = append(showCommands, newPreparationCommand(suite, aliases))
|
||||||
}
|
}
|
||||||
if len(showCommands) != 0 {
|
if len(showCommands) != 0 {
|
||||||
rootCommands = append(rootCommands, commandkit.Group("show", "Show a named PromptKit definition.", showCommands...))
|
rootCommands = append(rootCommands, commandkit.Group("show", "Show PromptKit definitions or preview a prepared request.", showCommands...))
|
||||||
}
|
}
|
||||||
listCommands := make([]commandkit.Command, 0, 5)
|
listCommands := make([]commandkit.Command, 0, 5)
|
||||||
if suite.ListPrompts != nil {
|
if suite.ListPrompts != nil {
|
||||||
@@ -110,7 +110,7 @@ func buildCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration
|
|||||||
listCommands = append(listCommands, newCatalogListCommand(suite, "collections"))
|
listCommands = append(listCommands, newCatalogListCommand(suite, "collections"))
|
||||||
}
|
}
|
||||||
if len(listCommands) != 0 {
|
if len(listCommands) != 0 {
|
||||||
rootCommands = append(rootCommands, commandkit.Group("list", "List PromptKit catalogs.", listCommands...))
|
rootCommands = append(rootCommands, commandkit.Group("list", "List available PromptKit resources.", listCommands...))
|
||||||
}
|
}
|
||||||
requirementsCommands := make([]commandkit.Command, 0, 2)
|
requirementsCommands := make([]commandkit.Command, 0, 2)
|
||||||
if suite.InspectRequirements != nil {
|
if suite.InspectRequirements != nil {
|
||||||
@@ -125,7 +125,7 @@ func buildCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration
|
|||||||
if suite.SmokeTest != nil {
|
if suite.SmokeTest != nil {
|
||||||
rootCommands = append(rootCommands, newSmokeTestCommand(suite, aliases))
|
rootCommands = append(rootCommands, newSmokeTestCommand(suite, aliases))
|
||||||
}
|
}
|
||||||
command := commandkit.RootGroup("promptkit", "Inspect, list, validate requests, and run PromptKit smoke tests.", rootCommands...)
|
command := commandkit.RootGroup("promptkit", "Inspect PromptKit resources, check requests, and run smoke tests.", rootCommands...)
|
||||||
for _, issue := range suite.issues {
|
for _, issue := range suite.issues {
|
||||||
command = commandkit.WithError(command, issue)
|
command = commandkit.WithError(command, issue)
|
||||||
}
|
}
|
||||||
@@ -140,16 +140,16 @@ func newCatalogListCommand[I, S any](suite Suite[I, S], name string) commandkit.
|
|||||||
return &(*input).captured
|
return &(*input).captured
|
||||||
})
|
})
|
||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }),
|
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Overlay = value }),
|
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).selection.Overlay = value }),
|
||||||
)
|
)
|
||||||
if name == "prompts" || name == "profiles" || name == "backends" {
|
if name == "prompts" || name == "profiles" || name == "backends" {
|
||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "namespace", Usage: "Select one native namespace."}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "namespace", Usage: "List resources in one namespace."}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **catalogInput[I], value commandkit.Supplied[string]) { (*input).namespace = value }),
|
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,
|
commandkit.BoolFlag(commandkit.FlagMeta{Name: "all-namespaces", Usage: "List resources from every namespace."}, false,
|
||||||
func(input **catalogInput[I], value commandkit.Supplied[bool]) { (*input).allNamespaces = value }),
|
func(input **catalogInput[I], value commandkit.Supplied[bool]) { (*input).allNamespaces = value }),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -243,9 +243,9 @@ func newDefinitionCommand[I, S any](suite Suite[I, S], name string, aliases *[]c
|
|||||||
return &(*input).captured
|
return &(*input).captured
|
||||||
})
|
})
|
||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **definitionInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }),
|
func(input **definitionInput[I], value commandkit.Supplied[string]) { (*input).selection.Config = value }),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **definitionInput[I], value commandkit.Supplied[string]) {
|
func(input **definitionInput[I], value commandkit.Supplied[string]) {
|
||||||
(*input).selection.Overlay = value
|
(*input).selection.Overlay = value
|
||||||
}),
|
}),
|
||||||
@@ -288,11 +288,11 @@ func newRequirementsCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.D
|
|||||||
return &(*input).captured
|
return &(*input).captured
|
||||||
})
|
})
|
||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **requirementsInput[I], value commandkit.Supplied[string]) {
|
func(input **requirementsInput[I], value commandkit.Supplied[string]) {
|
||||||
(*input).selection.Config = value
|
(*input).selection.Config = value
|
||||||
}),
|
}),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **requirementsInput[I], value commandkit.Supplied[string]) {
|
func(input **requirementsInput[I], value commandkit.Supplied[string]) {
|
||||||
(*input).selection.Overlay = value
|
(*input).selection.Overlay = value
|
||||||
}),
|
}),
|
||||||
@@ -308,8 +308,8 @@ func newRequirementsCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.D
|
|||||||
|
|
||||||
spec := commandkit.CommandSpec[*requirementsInput[I]]{
|
spec := commandkit.CommandSpec[*requirementsInput[I]]{
|
||||||
Name: "show",
|
Name: "show",
|
||||||
Summary: "Inspect requirements for a named PromptKit prompt.",
|
Summary: "Discover the inputs and variables a prompt needs.",
|
||||||
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.",
|
Description: "List required inputs without running the prompt. Choosing a profile changes the reported profile ID, not the requirements. A profile namespace applies to a short profile ID supplied here; it does not change the prompt’s stored default reference.",
|
||||||
NewInput: func() *requirementsInput[I] {
|
NewInput: func() *requirementsInput[I] {
|
||||||
return &requirementsInput[I]{}
|
return &requirementsInput[I]{}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
// Package ckprompt, provided by go.maximumdirect.net/ckprompt, provides optional
|
// Package ckprompt adds PromptKit inspection and testing commands to CommandKit
|
||||||
// PromptKit configuration comparison,
|
// applications. Operators can list resources, inspect definitions, discover
|
||||||
// prompt catalogs, named inspections, requirements discovery and validation,
|
// required inputs, validate and preview requests, and run smoke tests.
|
||||||
// prepared-request preview, and native smoke testing for CommandKit. Command
|
//
|
||||||
// returns a canonical declaration; Declarations adds scoped flag aliases.
|
// Start with FromEngine and add optional operations with WithRequestValidation,
|
||||||
// Applications can install those alongside other declarations through
|
// WithRequestPreparation, and WithSmokeTesting. Command returns the command
|
||||||
// commandkit.New or App.Register. Importing ckprompt installs neither family; callers compose its
|
// family; Declarations also includes its convenience flag aliases. Install
|
||||||
// declarations with core and ckconfig explicitly. Provider diagnostics remain
|
// these with commandkit.New or App.Register.
|
||||||
// passive until the owning command submits them through the invocation
|
//
|
||||||
// reporter, separately from any terminal explanation. This module uses
|
// ConfigScope separately exposes engine configuration through ckconfig.
|
||||||
// PromptKit v0.20.0 and its native engine inventory, including configured
|
// Importing this package installs neither command family. Applications own
|
||||||
// bundled resources.
|
// engine construction, credentials, and client configuration.
|
||||||
package ckprompt
|
package ckprompt
|
||||||
|
|||||||
@@ -1,27 +1,40 @@
|
|||||||
# CommandKit ckprompt v0.3.0
|
# CommandKit ckprompt v0.3.0
|
||||||
|
|
||||||
CommandKit ckprompt v0.3.0 adopts PromptKit v0.20.0 and ConfigKit v1.1.0,
|
This unpublished candidate adds PromptKit v0.20.0 support, including request
|
||||||
and requires CommandKit core v0.4.0, ckconfig v0.4.0, and Go 1.27.0.
|
preview, namespace selection, and shared text, YAML, and JSON output. It uses
|
||||||
The integration uses shared core reporting for text, YAML, and JSON output.
|
ConfigKit v1.1.0 and requires Go 1.27.0.
|
||||||
|
|
||||||
Prompt, profile, and backend commands report PromptKit's native resource
|
## Operator features
|
||||||
inspections. Applications may opt into prepared-request preview, concrete
|
|
||||||
request validation, smoke testing, and namespace selectors independently.
|
|
||||||
Reusable request flag collections support application-owned commands;
|
|
||||||
`ckprompt.Declarations` installs the standard family with scoped aliases.
|
|
||||||
Literal and file inputs retain their command-line order. Provider parameters
|
|
||||||
can be supplied for preparation and applicable diagnostics.
|
|
||||||
|
|
||||||
The PromptKit configuration scope exposes native metadata and load-failure
|
- Inspect prompts, profiles, and backends, and list available resources.
|
||||||
evidence through ckconfig, including independent comparison selections,
|
- Preview rendered requests without calling the model, or validate that a
|
||||||
detailed differences, and validation findings. Smoke reports retain native
|
request can be prepared with the supplied inputs.
|
||||||
evidence and operation failures separately from presentation failures.
|
- Choose namespaces and override request settings for supported commands.
|
||||||
|
- Run smoke tests and inspect their results, including incomplete or unsupported
|
||||||
|
checks and reports returned alongside errors.
|
||||||
|
- Inspect engine configuration through `config`, including detailed validation
|
||||||
|
findings, source information after failed loads, and configuration comparisons.
|
||||||
|
|
||||||
This pre-1.0 release changes resource report shapes, input flags, formatting,
|
Applications choose which commands to enable. Reusable flag collections also
|
||||||
and configuration comparison behavior. Applications should update declarations
|
let application commands offer the same request flags. `ckprompt.Declarations`
|
||||||
and report consumers to the current [CLI reference](../../../../docs/cli.md#promptkit-definition-inspection)
|
adds the standard commands with their shorter flag aliases. Literal and file
|
||||||
and [consumer guide](../../../../docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements).
|
inputs keep their command-line order.
|
||||||
Applications continue to own engine construction, credentials, and execution.
|
|
||||||
|
## Compatibility and preparation
|
||||||
|
|
||||||
|
This candidate changes resource report shapes, input flags, formatting, and
|
||||||
|
configuration comparison behavior. Review the current
|
||||||
|
[CLI reference](../../../../docs/cli.md#promptkit-definition-inspection) and
|
||||||
|
[consumer guide](../../../../docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements)
|
||||||
|
when updating declarations or code that reads reports. Applications continue to
|
||||||
|
own engine construction, credentials, and execution.
|
||||||
|
|
||||||
|
The current source requires `ckconfig.AdaptDiagnostics`, which is absent from
|
||||||
|
its selected ckconfig v0.4.0 dependency. Before publication, complete
|
||||||
|
[dependency alignment](../../../../docs/roadmap/future.md#pending-release-and-integration-work)
|
||||||
|
and update this candidate's dependency guidance to the selected releases.
|
||||||
|
The [module selection table](../../../../docs/consumers/guide.md#module-selection)
|
||||||
|
distinguishes published combinations from the current workspace.
|
||||||
|
|
||||||
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/COPYRIGHT) |
|
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/COPYRIGHT) |
|
||||||
[LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/LICENSE) |
|
[LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.3.0/integrations/ckprompt/LICENSE) |
|
||||||
|
|||||||
@@ -1,141 +1,172 @@
|
|||||||
# Composed consumer
|
# ConfigKit and PromptKit example
|
||||||
|
|
||||||
This example is part of the ckprompt module and uses core v0.4.0, ckconfig
|
This example combines application and PromptKit configuration, resource
|
||||||
v0.4.0, ConfigKit v1.1.0, and PromptKit v0.20.0. It requires Go 1.27.0.
|
inspection, request checks, and smoke tests. It uses local fixtures and an
|
||||||
|
in-memory model client. **No model service or credentials are required.**
|
||||||
|
|
||||||
This example composes application configuration, PromptKit configuration,
|
Use Go 1.27.0 on `PATH` and an aligned workspace containing all three local
|
||||||
PromptKit comparison and catalogs, definition and requirements inspection, and
|
modules. Follow the [workspace setup](../../../../docs/development.md#documentation-validation)
|
||||||
one application-owned command:
|
from the repository root first. Current ckprompt source needs a helper in local
|
||||||
|
ckconfig source that its released dependency does not yet contain; independent
|
||||||
|
builds remain pending [release alignment](../../../../docs/roadmap/future.md#pending-release-and-integration-work).
|
||||||
|
The [consumer guide](../../../../docs/consumers/guide.md#module-selection) owns
|
||||||
|
version and compatibility details.
|
||||||
|
|
||||||
|
From the repository root:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
cd integrations/ckprompt/examples/composed
|
||||||
|
export GOWORK=auto GOTOOLCHAIN=local
|
||||||
go run . config scopes
|
go run . config scopes
|
||||||
|
go run . promptkit list prompts --campaign spring
|
||||||
|
go run . promptkit show prompt briefing --campaign spring --format yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
The first command lists `app` and `promptkit` configurations and their available
|
||||||
|
operations. The next commands find and inspect the `briefing` prompt.
|
||||||
|
`--campaign` is a selector supplied by this example, not a standard PromptKit flag.
|
||||||
|
|
||||||
|
## Validate and compare configuration
|
||||||
|
|
||||||
|
```sh
|
||||||
go run . config validate --scope all --campaign spring --limit=0
|
go run . config validate --scope all --campaign spring --limit=0
|
||||||
go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml
|
go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml
|
||||||
go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring --limit=0
|
|
||||||
go run . config diff --scope app --campaign spring --limit=0 --against-campaign autumn --against-limit=0 --set '/campaigns/spring/model="left"' --against-set '/campaigns/spring/model="right"' --details
|
|
||||||
go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring --against-campaign spring
|
go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring --against-campaign spring
|
||||||
go run . promptkit list prompts --config fixtures/before.yml --campaign spring
|
```
|
||||||
|
|
||||||
|
The application scope requires `--limit=0` when `--campaign` is supplied.
|
||||||
|
The app comparison reports a changed default campaign and `campaigns.spring.model`.
|
||||||
|
The PromptKit comparison selects spring on both sides and reports the changed
|
||||||
|
profiles list as one value.
|
||||||
|
|
||||||
|
The two sides have independent selectors and overrides:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run . config diff --scope app --campaign spring --limit=0 --against-campaign autumn --against-limit=0 --set '/campaigns/spring/model="left"' --against-set '/campaigns/spring/model="right"' --details
|
||||||
|
```
|
||||||
|
|
||||||
|
Only the application scope supports `--set` here. The released PromptKit loader
|
||||||
|
has no override handoff, so its configuration scope does not enable the feature.
|
||||||
|
An aggregate operation that includes that scope rejects overrides.
|
||||||
|
|
||||||
|
## List resources and select namespaces
|
||||||
|
|
||||||
|
```sh
|
||||||
go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml
|
go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml
|
||||||
go run . promptkit list backends --campaign spring
|
go run . promptkit list backends --campaign spring
|
||||||
go run . promptkit list namespaces --campaign spring
|
go run . promptkit list namespaces --campaign spring
|
||||||
go run . promptkit list collections --campaign spring
|
go run . promptkit list collections --campaign spring
|
||||||
go run . list collections --campaign spring
|
|
||||||
go run . pk list bundles --campaign spring
|
|
||||||
go run . promptkit list prompts --namespace field-notes --campaign spring
|
go run . promptkit list prompts --namespace field-notes --campaign spring
|
||||||
go run . promptkit show prompt briefing --campaign spring --format yaml
|
|
||||||
go run . promptkit show prompt briefing --campaign spring --prompt-namespace field-notes
|
go run . promptkit show prompt briefing --campaign spring --prompt-namespace field-notes
|
||||||
go run . promptkit show prepared briefing --campaign spring --input topic=sprint --profile spring --extra-params '{"campaign":"preview"}'
|
|
||||||
go run . pk show prompt briefing --campaign spring --fmt yaml
|
|
||||||
go run . promptkit show profile spring --campaign spring
|
go run . promptkit show profile spring --campaign spring
|
||||||
|
```
|
||||||
|
|
||||||
|
The profile list includes the selected `autumn` profile. PromptKit's default
|
||||||
|
bundle contributes additional resources. The example also supplies a
|
||||||
|
`field-notes` collection containing a backend, profile, and prompt. Listing
|
||||||
|
filters and resource namespace flags let you inspect that collection.
|
||||||
|
|
||||||
|
## Discover inputs, then check a request
|
||||||
|
|
||||||
|
```sh
|
||||||
go run . promptkit requirements show briefing --campaign spring
|
go run . promptkit requirements show briefing --campaign spring
|
||||||
go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml
|
go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
The first report is incomplete: the `notes` input is conditional and `mode` is
|
||||||
|
missing. Supplying `mode=full` selects that branch and makes `notes` required.
|
||||||
|
Both commands succeed; discovery alone does not establish that a request can run.
|
||||||
|
|
||||||
|
```sh
|
||||||
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt
|
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt
|
||||||
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt --llm-var mode=full --llm-input-file notes=fixtures/notes.txt --format yaml
|
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt --llm-var mode=full --llm-input-file notes=fixtures/notes.txt --format yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Both commands check request preparation and report `prompt_id` and `valid: true`.
|
||||||
|
The builder provides campaign-specific variable defaults; the operator supplies
|
||||||
|
the input files. For comparison, this command intentionally fails because the
|
||||||
|
required `topic` input is missing:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Intentional failure: missing topic input.
|
||||||
go run . promptkit requirements validate briefing --campaign spring
|
go run . promptkit requirements validate briefing --campaign spring
|
||||||
|
```
|
||||||
|
|
||||||
|
Preview a request with literal input instead of a file:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run . promptkit show prepared briefing --campaign spring --input topic=sprint --profile spring --extra-params '{"campaign":"preview"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
The preview includes rendered messages and effective provider settings.
|
||||||
|
Validation and preview do not call the model or guarantee later execution.
|
||||||
|
|
||||||
|
## Run smoke tests
|
||||||
|
|
||||||
|
```sh
|
||||||
go run . promptkit test text_inference --campaign spring --prompt briefing --profile spring
|
go run . promptkit test text_inference --campaign spring --prompt briefing --profile spring
|
||||||
go run . smoke text_inference --campaign spring --llm-prompt briefing --llm-profile spring
|
# Some diagnostics can fail or be unsupported; inspect the retained report.
|
||||||
go run . promptkit test all --campaign spring --llm-prompt briefing --llm-profile spring
|
go run . promptkit test all --campaign spring --llm-prompt briefing --llm-profile spring
|
||||||
|
```
|
||||||
|
|
||||||
|
Inference uses the example's in-memory client. HTTP checks may be unsupported
|
||||||
|
or not applicable because the local backend has no network probe. The aggregate
|
||||||
|
can return a failure while still showing results. Read the facts in the report;
|
||||||
|
a successful command status does not mean every observation is positive.
|
||||||
|
|
||||||
|
For any command that returns nonzero, `go run` prints `exit status N` and itself
|
||||||
|
exits with status 1. A built executable returns the application's status directly.
|
||||||
|
The [CLI reference](../../../../docs/cli.md#promptkit-smoke-testing) explains the
|
||||||
|
standard test kinds, results, and statuses.
|
||||||
|
|
||||||
|
## Try aliases and application commands
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go run . list collections --campaign spring
|
||||||
|
go run . pk list bundles --campaign spring
|
||||||
|
go run . pk show prompt briefing --campaign spring --fmt yaml
|
||||||
|
go run . smoke text_inference --campaign spring --llm-prompt briefing --llm-profile spring
|
||||||
go run . pk --hlep
|
go run . pk --hlep
|
||||||
go run . session restore session-42 --campaign spring
|
go run . session restore session-42 --campaign spring
|
||||||
go run . request inspect --llm-prompt briefing --llm-profile= --llm-model example --llm-input-text topic=sprint --format json
|
go run . request inspect --llm-prompt briefing --llm-profile= --llm-model example --llm-input-text topic=sprint --format json
|
||||||
```
|
```
|
||||||
|
|
||||||
`newApp` installs application-owned command and flag aliases alongside the
|
The first two commands reach `promptkit list collections`. `pk` shortens the
|
||||||
complete `ckconfig` and `ckprompt` declarations. `list collections` and
|
PromptKit group; `--fmt` is an alias on prompt inspection and `--hlep` is a global
|
||||||
`promptkit list bundles` both reach the canonical collection command; `pk`
|
help alias. `smoke` shortens `promptkit test` while leaving the test kind as an
|
||||||
shortens the PromptKit group. `--fmt` is scoped to named prompt inspection and
|
argument. The session command uses an in-memory store. `request inspect` shows
|
||||||
`--hlep` is available globally. The `smoke` shortcut retains the canonical
|
how an application command can reuse canonical `--llm-*` flag collections without
|
||||||
`promptkit test KIND` operand, including the special `all` aggregate.
|
installing PromptKit's short aliases.
|
||||||
|
|
||||||
The example installs `Completion("composed-example")`. Build it as
|
## Try shell completion
|
||||||
`go build -o composed-example .`. Initialize `bash-completion` first if using
|
|
||||||
Bash, then load a shell script as described in the
|
|
||||||
[CLI reference](../../../../docs/cli.md#shell-completion). Try completion after
|
|
||||||
`composed-example pk show prompt briefing --fmt=` or after the filename prefix
|
|
||||||
in `composed-example config show --config=fixtures/`. The already-entered `pk`
|
|
||||||
alias selects the PromptKit command context without loading an engine.
|
|
||||||
|
|
||||||
The composition installs `ckconfig.Command(suite)` and the complete
|
```sh
|
||||||
`ckprompt.Declarations(definitions)` in a `[]commandkit.Declaration` with
|
go build -o composed-example .
|
||||||
root-installed routing rules. The PromptKit declarations include scoped aliases;
|
./composed-example completion bash
|
||||||
the application-owned `request inspect` command reuses the flag collections
|
|
||||||
with their canonical names and does not install those aliases.
|
|
||||||
Group children remain canonical `Command` values. For command-only slices,
|
|
||||||
convert each `Command` to `Declaration` before appending aliases. The
|
|
||||||
[consumer guide](../../../../docs/consumers/guide.md#application-owned-aliases)
|
|
||||||
includes minimal direct-call and slice-conversion examples; this README documents
|
|
||||||
the maintained complete consumer.
|
|
||||||
|
|
||||||
The sources and session store are small in-memory fixtures. `--campaign` is a
|
|
||||||
typed selector shared by the app and PromptKit configuration scopes. Their
|
|
||||||
`ckconfig.Suite[*inspectionInput, *runCache]` uses `NewInput` to initialize each
|
|
||||||
selected scope's input separately and `NewState` to create one cache shared by
|
|
||||||
that invocation's acquisitions. Prompt/profile inspection prepares its input and
|
|
||||||
cache independently for its invocation, using the same application and engine
|
|
||||||
loader functions. See the
|
|
||||||
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md)
|
|
||||||
and the suites' GoDoc for initialization timing and ownership.
|
|
||||||
|
|
||||||
The application-scope comparison reports the changed default campaign and the
|
|
||||||
updated `campaigns.spring.model`. The PromptKit-scope comparison selects spring
|
|
||||||
on both sides and reports the native engine change in the atomic profiles list.
|
|
||||||
The application input check requires `--limit=0` when `--campaign` is supplied.
|
|
||||||
Catalogs use the same selection-aware loader: the prompt catalog includes
|
|
||||||
`briefing`, and the profile catalog includes the selected `autumn` profile.
|
|
||||||
Prompt inspection uses an ID only. The default PromptKit bundle also contributes
|
|
||||||
profiles and a backend to the engine inventory and source reports. The synthetic `field-notes` collection
|
|
||||||
provides one backend, profile, and prompt for collection discovery and native
|
|
||||||
namespace filtering. The example's shared run cache keys successful results by
|
|
||||||
the complete supplied configuration/overlay selection, CLI overrides, and the
|
|
||||||
supplied campaign, including presence. The campaign override and application
|
|
||||||
scope's `--set` records are applied through ConfigKit before loading. The
|
|
||||||
PromptKit configuration scope does not enable `--set` because its released
|
|
||||||
configuration loader has no override handoff. An aggregate operation therefore
|
|
||||||
rejects overrides when that scope is selected. These are choices for this
|
|
||||||
example's loaders and do not define a CommandKit cache policy.
|
|
||||||
|
|
||||||
Smoke testing is explicitly wired with `ckprompt.WithSmokeTesting` and its
|
|
||||||
optional request builder is nil, so CommandKit forwards the selected native
|
|
||||||
request. Applications that need to adjust the request can provide a typed
|
|
||||||
builder that starts with the seed and returns the chosen native request:
|
|
||||||
|
|
||||||
```go
|
|
||||||
definitions = ckprompt.WithSmokeTesting(definitions, loadEngine,
|
|
||||||
func(ctx context.Context, seed ckprompt.SmokeRequest, input *inspectionInput, state *runCache) (promptkit.SmokeTestRequest, error) {
|
|
||||||
request := seed.Request
|
|
||||||
request.ProfileID = "spring"
|
|
||||||
return request, nil
|
|
||||||
})
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The example injects a small in-memory `promptkit.LLMClient` through its shared
|
Initialize `bash-completion` if using Bash, then load the generated script using
|
||||||
run state. Catalog, inspection, and requirements commands do not call it;
|
the [CLI reference](../../../../docs/cli.md#shell-completion). Try completing
|
||||||
inference smoke commands do. No model service or credentials are required.
|
`composed-example pk show prompt briefing --fmt=` or
|
||||||
Native HTTP checks may retain unsupported or not-applicable observations because
|
`composed-example config show --config=fixtures/`. The already-entered `pk` alias
|
||||||
the selected local backend does not configure a network probe. An aggregate smoke command can
|
selects the command context without loading an engine.
|
||||||
return an operational outcome for a native diagnostic while still delivering
|
|
||||||
the complete aggregate report.
|
|
||||||
|
|
||||||
The first requirements command reports incomplete discovery: PromptKit records
|
## How it is wired
|
||||||
the conditional `notes` input and a missing `mode` issue. Supplying `mode=full`
|
|
||||||
selects that branch, classifies the undeclared `notes` input as required, and
|
|
||||||
completes discovery. Both commands return successful reports; the result does
|
|
||||||
not execute the prompt or establish input, credential, or execution readiness.
|
|
||||||
See the [CLI reference](../../../../docs/cli.md#promptkit-requirements) for the
|
|
||||||
command and report contract.
|
|
||||||
|
|
||||||
The validation and preview commands exercise concrete PromptKit request preparation.
|
The example installs `ckconfig.Command(suite)` and
|
||||||
The first uses the builder's campaign-specific default topic variable and the
|
`ckprompt.Declarations(definitions)` with application-owned aliases in a
|
||||||
operator's topic file. The second also selects the notes branch and supplies its
|
`[]commandkit.Declaration`. `NewInput` initializes scope inputs; `NewState`
|
||||||
file. Validation reports only `prompt_id` and `valid: true`; preview returns the
|
creates a cache shared within an invocation. The loaders cache successful
|
||||||
prepared request, including rendered messages and effective provider settings.
|
configuration results by the complete configuration/overlay selection,
|
||||||
Neither executes the prompt. The validation command without inputs intentionally
|
overrides, and supplied campaign, including whether each value was supplied.
|
||||||
fails because the prompt's
|
These are example choices, not a CommandKit cache policy.
|
||||||
required `topic` artifact is not supplied. The builder defaults variables from
|
|
||||||
the selected campaign but leaves artifact bindings to the operator. The
|
|
||||||
`requirements show` commands remain discovery reports: partial discovery can
|
|
||||||
succeed even when a concrete request would fail validation.
|
|
||||||
|
|
||||||
Run `GOWORK=off go test ./...` from this example directory to check it against
|
Smoke testing uses `WithSmokeTesting` with a nil builder, forwarding the request
|
||||||
its declared dependencies. The [developer guide](../../../../docs/development.md#documentation-validation)
|
selected by flags. Applications can supply a builder to customize that request.
|
||||||
also describes aligned workspace tests.
|
See the [consumer guide](../../../../docs/consumers/guide.md#promptkit-configuration-definitions-and-requirements)
|
||||||
|
for suite composition, builders, and ownership, and the [source](main.go) for
|
||||||
|
the complete application.
|
||||||
|
|
||||||
|
Run `GOWORK=auto GOTOOLCHAIN=local go test ./...` from this example directory
|
||||||
|
for an aligned workspace check. Once dependency alignment is complete, also use
|
||||||
|
`GOWORK=off GOTOOLCHAIN=local go test ./...` to check the declared releases.
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ func namespaceFlags[I any](destination func(*I) *namespaceInput, kinds ...string
|
|||||||
}
|
}
|
||||||
|
|
||||||
var namespaceFlagDefinitions = struct{ prompt, profile, backend requestFlagDefinition }{
|
var namespaceFlagDefinitions = struct{ prompt, profile, backend requestFlagDefinition }{
|
||||||
prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt-namespace", Usage: "Prompt resource namespace."}, []string{"prompt-namespace"}},
|
prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt-namespace", Usage: "Use this namespace for unqualified prompt IDs."}, []string{"prompt-namespace"}},
|
||||||
profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile-namespace", Usage: "Profile resource namespace."}, []string{"profile-namespace"}},
|
profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile-namespace", Usage: "Use this namespace for unqualified profile IDs."}, []string{"profile-namespace"}},
|
||||||
backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend-namespace", Usage: "Backend resource namespace."}, []string{"backend-namespace"}},
|
backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend-namespace", Usage: "Use this namespace for unqualified backend IDs."}, []string{"backend-namespace"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectedNamespaces(defaults *promptkit.Namespaces, selected namespaceInput) *promptkit.Namespaces {
|
func selectedNamespaces(defaults *promptkit.Namespaces, selected namespaceInput) *promptkit.Namespaces {
|
||||||
|
|||||||
@@ -35,24 +35,24 @@ var requestFlags = struct {
|
|||||||
InputText requestFlagDefinition
|
InputText requestFlagDefinition
|
||||||
InputFile requestFlagDefinition
|
InputFile requestFlagDefinition
|
||||||
}{
|
}{
|
||||||
Endpoint: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-endpoint", Usage: "Execution endpoint override."}, []string{"endpoint"}},
|
Endpoint: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-endpoint", Usage: "Use this endpoint."}, []string{"endpoint"}},
|
||||||
Model: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-model", Usage: "Execution model override."}, []string{"model"}},
|
Model: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-model", Usage: "Use this model."}, []string{"model"}},
|
||||||
Temperature: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-temperature", Usage: "Execution temperature override."}, []string{"temperature"}},
|
Temperature: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-temperature", Usage: "Use this temperature."}, []string{"temperature"}},
|
||||||
MaxTokens: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-max-tokens", Usage: "Execution maximum tokens override."}, []string{"max-tokens"}},
|
MaxTokens: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-max-tokens", Usage: "Use this maximum token count."}, []string{"max-tokens"}},
|
||||||
TopP: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-top-p", Usage: "Execution top-p override."}, []string{"top-p"}},
|
TopP: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-top-p", Usage: "Use this top-p value."}, []string{"top-p"}},
|
||||||
TimeoutSeconds: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-timeout-seconds", Usage: "Execution timeout override in seconds."}, []string{"timeout-seconds"}},
|
TimeoutSeconds: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-timeout-seconds", Usage: "Set the request timeout in seconds."}, []string{"timeout-seconds"}},
|
||||||
ServiceTier: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-service-tier", Usage: "Execution service tier."}, []string{"service-tier"}},
|
ServiceTier: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-service-tier", Usage: "Use this service tier."}, []string{"service-tier"}},
|
||||||
ReasoningEffort: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-reasoning-effort", Usage: "Execution reasoning effort override."}, []string{"reasoning-effort"}},
|
ReasoningEffort: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-reasoning-effort", Usage: "Use this reasoning effort."}, []string{"reasoning-effort"}},
|
||||||
APIKeyEnv: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-api-key-env", Usage: "Execution API key environment variable."}, []string{"api-key-env"}},
|
APIKeyEnv: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-api-key-env", Usage: "Name the environment variable containing the API key."}, []string{"api-key-env"}},
|
||||||
TransientRetries: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-transient-retries", Usage: "Inference transient retry count."}, []string{"transient-retries"}},
|
TransientRetries: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-transient-retries", Usage: "Set the retry count for transient inference failures."}, []string{"transient-retries"}},
|
||||||
ExtraParams: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-extra-params", Usage: "Execution provider parameters as a JSON object."}, []string{"extra-params"}},
|
ExtraParams: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-extra-params", Usage: "Supply provider parameters as a JSON object."}, []string{"extra-params"}},
|
||||||
Prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt", Usage: "PromptKit prompt ID."}, []string{"prompt"}},
|
Prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt", Usage: "Select a prompt by ID."}, []string{"prompt"}},
|
||||||
Profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile", Usage: "PromptKit profile ID."}, []string{"profile"}},
|
Profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile", Usage: "Select a profile by ID."}, []string{"profile"}},
|
||||||
Backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend", Usage: "PromptKit backend ID."}, []string{"backend"}},
|
Backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend", Usage: "Select a backend by ID."}, []string{"backend"}},
|
||||||
SessionID: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-session-id", Usage: "PromptKit session ID."}, []string{"session-id"}},
|
SessionID: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-session-id", Usage: "Supply the session ID."}, []string{"session-id"}},
|
||||||
Var: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-var", Usage: "Caller variable assignment KEY=VALUE."}, []string{"var"}},
|
Var: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-var", Usage: "Supply a prompt variable as KEY=VALUE."}, []string{"var"}},
|
||||||
InputText: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-text", Usage: "Literal prompt input assignment NAME=TEXT."}, []string{"input-text", "llm-input", "input"}},
|
InputText: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-text", Usage: "Supply text for a prompt input as NAME=TEXT."}, []string{"input-text", "llm-input", "input"}},
|
||||||
InputFile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-file", Usage: "Prompt input file assignment NAME=PATH."}, []string{"input-file"}},
|
InputFile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-input-file", Usage: "Supply a file for a prompt input as NAME=PATH."}, []string{"input-file"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionInput contains request-scoped execution controls supplied on the CLI.
|
// ExecutionInput contains request-scoped execution controls supplied on the CLI.
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ func newSmokeTestCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Decl
|
|||||||
return &(*input).captured
|
return &(*input).captured
|
||||||
})
|
})
|
||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) {
|
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) {
|
||||||
(*input).selection.Config = value
|
(*input).selection.Config = value
|
||||||
}),
|
}),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) {
|
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) {
|
||||||
(*input).selection.Overlay = value
|
(*input).selection.Overlay = value
|
||||||
}),
|
}),
|
||||||
@@ -54,13 +54,14 @@ func newSmokeTestCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Decl
|
|||||||
|
|
||||||
return commandkit.NewCommand(commandkit.CommandSpec[*smokeCommandInput[I]]{
|
return commandkit.NewCommand(commandkit.CommandSpec[*smokeCommandInput[I]]{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Summary: "Run one PromptKit smoke test.",
|
Summary: "Run one or all PromptKit smoke tests.",
|
||||||
|
Description: "Tests use the configured client or probes and may contact a provider. The all option runs the four tests in order. Read the report: a successful command status does not mean every observation is positive.",
|
||||||
NewInput: func() *smokeCommandInput[I] {
|
NewInput: func() *smokeCommandInput[I] {
|
||||||
return &smokeCommandInput[I]{}
|
return &smokeCommandInput[I]{}
|
||||||
},
|
},
|
||||||
Flags: flags,
|
Flags: flags,
|
||||||
Arguments: []commandkit.Argument[*smokeCommandInput[I]]{
|
Arguments: []commandkit.Argument[*smokeCommandInput[I]]{
|
||||||
commandkit.ValueArgument(commandkit.ArgumentMeta{Name: "kind", Usage: "Native smoke-test kind.", Completion: smokeKindCompletion()}, true, parseDefinitionString,
|
commandkit.ValueArgument(commandkit.ArgumentMeta{Name: "kind", Usage: "Test kind: reachability, authentication, text_inference, structured_output, or all.", Completion: smokeKindCompletion()}, true, parseDefinitionString,
|
||||||
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) { (*input).kind = value.Value }),
|
func(input **smokeCommandInput[I], value commandkit.Supplied[string]) { (*input).kind = value.Value }),
|
||||||
},
|
},
|
||||||
CheckInput: func(input *smokeCommandInput[I]) error {
|
CheckInput: func(input *smokeCommandInput[I]) error {
|
||||||
|
|||||||
@@ -31,11 +31,11 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S], path string, aliases *[
|
|||||||
return &(*input).captured
|
return &(*input).captured
|
||||||
})
|
})
|
||||||
flags = append(flags,
|
flags = append(flags,
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **concreteRequestInput[I], value commandkit.Supplied[string]) {
|
func(input **concreteRequestInput[I], value commandkit.Supplied[string]) {
|
||||||
(*input).request.Selection.Config = value
|
(*input).request.Selection.Config = value
|
||||||
}),
|
}),
|
||||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString,
|
||||||
func(input **concreteRequestInput[I], value commandkit.Supplied[string]) {
|
func(input **concreteRequestInput[I], value commandkit.Supplied[string]) {
|
||||||
(*input).request.Selection.Overlay = value
|
(*input).request.Selection.Overlay = value
|
||||||
}),
|
}),
|
||||||
@@ -93,7 +93,7 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S], path string, aliases *[
|
|||||||
func newValidationCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
func newValidationCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
||||||
spec := newConcreteRequestSpec(suite, "promptkit requirements validate", aliases)
|
spec := newConcreteRequestSpec(suite, "promptkit requirements validate", aliases)
|
||||||
spec.Name = "validate"
|
spec.Name = "validate"
|
||||||
spec.Summary = "Validate a concrete PromptKit request without executing it."
|
spec.Summary = "Check whether a request can be prepared without calling the model."
|
||||||
spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome {
|
spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome {
|
||||||
return runRequestValidation(invocation, suite, input)
|
return runRequestValidation(invocation, suite, input)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ type CompletionResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var reportingFlags = [...]Flag{
|
var reportingFlags = [...]Flag{
|
||||||
{Name: "quiet", Usage: "suppress substantive output and optional messages; keep failures visible", Default: "false", Boolean: true},
|
{Name: "quiet", Usage: "hide command output and optional messages; keep failures visible", Default: "false", Boolean: true},
|
||||||
{Name: "verbose", Usage: "show warning and informational messages", Default: "false", Boolean: true},
|
{Name: "verbose", Usage: "show warning and informational messages", Default: "false", Boolean: true},
|
||||||
{Name: "debug", Usage: "show debugging messages", Default: "false", Boolean: true},
|
{Name: "debug", Usage: "show debugging messages", Default: "false", Boolean: true},
|
||||||
{Name: "progress", Usage: "show progress messages", Default: "false", Boolean: true},
|
{Name: "progress", Usage: "show progress messages", Default: "false", Boolean: true},
|
||||||
|
|||||||
Reference in New Issue
Block a user