Compare commits
15 Commits
integratio
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bc1d1d5844 | |||
| 260256d722 | |||
| 5a79b56e3c | |||
| 5ccdcb91c9 | |||
| 42176a7ac4 | |||
| 72099958d1 | |||
| 2904eadf4f | |||
| 1c778d7ad3 | |||
| 16584084b1 | |||
| ce8ab3be38 | |||
| 7a9e3a1f7c | |||
| 60841227b7 | |||
| 3699c6c5e6 | |||
| 3f1ed2f107 | |||
| 4a8f73f289 |
11
README.md
11
README.md
@@ -20,11 +20,12 @@ defines the shared visibility policy.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `go.maximumdirect.net/commandkit` | `commandkit` | Typed commands, bindings, execution reporting and outcomes, help, and version. |
|
| `go.maximumdirect.net/commandkit` | `commandkit` | Typed commands, bindings, execution reporting and outcomes, help, and version. |
|
||||||
| `go.maximumdirect.net/ckconfig` | `ckconfig` | ConfigKit-backed `config` scopes, including configuration source evidence. |
|
| `go.maximumdirect.net/ckconfig` | `ckconfig` | ConfigKit-backed `config` scopes, including configuration source evidence. |
|
||||||
| `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | `ckprompt` | PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, concrete request validation, and native smoke tests. |
|
| `go.maximumdirect.net/ckprompt` | `ckprompt` | PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, concrete request validation, and native smoke tests. |
|
||||||
|
|
||||||
Importing an integration does not install commands. The ckconfig v0.2.0
|
Importing an integration does not install commands. The published ckconfig and
|
||||||
candidate uses core v0.3.0; ckprompt still uses the old core identity and cannot
|
ckprompt v0.2.0 modules use core v0.3.0. The local
|
||||||
be composed with the new core path until its planned v0.2.0 release. See the
|
ckconfig v0.3.0 candidate uses ConfigKit v1.1.0 and does not compose with
|
||||||
|
ckprompt v0.2.0; the published v0.2.0 pair remains matched. See the
|
||||||
[consumer guide](docs/consumers/guide.md#module-selection) for migration details.
|
[consumer guide](docs/consumers/guide.md#module-selection) for migration details.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
@@ -42,7 +43,7 @@ be composed with the new core path until its planned v0.2.0 release. See the
|
|||||||
- [Maintainer release procedure](docs/release.md)
|
- [Maintainer release procedure](docs/release.md)
|
||||||
- [Architecture policy](docs/policy/architecture.md)
|
- [Architecture policy](docs/policy/architecture.md)
|
||||||
- [Policy provenance](docs/policy/meta.md)
|
- [Policy provenance](docs/policy/meta.md)
|
||||||
- [Deferred capabilities and proposals](docs/roadmap/deferred.md)
|
- [Future work and proposals](docs/roadmap/future.md)
|
||||||
|
|
||||||
CommandKit is licensed under the [LGPL v3.0 or later](COPYRIGHT).
|
CommandKit is licensed under the [LGPL v3.0 or later](COPYRIGHT).
|
||||||
|
|
||||||
|
|||||||
26
docs/cli.md
26
docs/cli.md
@@ -363,14 +363,14 @@ sources:
|
|||||||
- id: source-1
|
- id: source-1
|
||||||
label: "application config"
|
label: "application config"
|
||||||
path: /etc/example/config.yml
|
path: /etc/example/config.yml
|
||||||
layer: base
|
layer: main
|
||||||
kind: file
|
kind: file
|
||||||
underlay_index: 0
|
underlay_index: 0
|
||||||
imported_from: null
|
imported_from: null
|
||||||
destination: /server
|
destination: /server
|
||||||
placement: mapping
|
placement: mapping
|
||||||
destination_unresolved: false
|
destination_is_fallback: false
|
||||||
version_check:
|
version_evidence:
|
||||||
path: /version
|
path: /version
|
||||||
version:
|
version:
|
||||||
present: true
|
present: true
|
||||||
@@ -381,22 +381,28 @@ sources:
|
|||||||
line: 2
|
line: 2
|
||||||
column: 1
|
column: 1
|
||||||
redacted: false
|
redacted: false
|
||||||
|
empty_import_selections: []
|
||||||
```
|
```
|
||||||
|
|
||||||
Each source includes `id`, `label`, `path`, `layer`, `kind`, `underlay_index`,
|
Each source includes `id`, `label`, `path`, `layer`, `kind`, `underlay_index`,
|
||||||
and `imported_from`, plus the native destination pointer, placement, unresolved
|
and `imported_from`, plus the native destination pointer, placement,
|
||||||
destination flag, and nullable `version_check`. Placement is `mapping` or
|
`destination_is_fallback`, nullable `version_evidence`, and
|
||||||
`sequence_item`. The import location is null when absent; otherwise it has
|
`empty_import_selections`. Placement is `mapping` or `sequence_item`. The
|
||||||
|
import location is null when absent; otherwise it has
|
||||||
`source_id`, `line`, and `column`. Version evidence preserves `path`, `present`,
|
`source_id`, `line`, and `column`. Version evidence preserves `path`, `present`,
|
||||||
`null`, `text`, optional source `location`, and `redacted` as returned by
|
`null`, `text`, optional source `location`, and `redacted` as returned by
|
||||||
ConfigKit. Owning values and source order are preserved, including empty fields,
|
ConfigKit. Owning values and source order are preserved, including empty fields,
|
||||||
zero coordinates, false and null observations, and synthetic sources without
|
zero coordinates, false and null observations, and synthetic sources without
|
||||||
paths. An absent version check is null. An empty inventory is `sources: []`.
|
paths. Absent version evidence is null. Each empty-import record has a source-local
|
||||||
|
`path`, a `location` mapping (`source_id`, `line`, `column`), and a `selector`;
|
||||||
|
records preserve their returned order. No records are `empty_import_selections: []`.
|
||||||
|
An empty inventory is `sources: []`.
|
||||||
Text output begins with the scope heading and prints the same source fields,
|
Text output begins with the scope heading and prints the same source fields,
|
||||||
quoting labels and paths. These fields project the selected ConfigKit source
|
quoting labels and paths. These fields project the selected ConfigKit source
|
||||||
records; CommandKit does not reload files or rerun version checks. See the
|
records; CommandKit does not reload files or rerun version checks. See the
|
||||||
[ConfigKit v0.8.0 inspection API](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go)
|
[ConfigKit v1.1.0 source records](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/records.go)
|
||||||
for native evidence definitions.
|
for native evidence definitions. Ckprompt v0.2.0 uses
|
||||||
|
[ConfigKit v0.8.0](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go).
|
||||||
|
|
||||||
### Explain a configuration path
|
### Explain a configuration path
|
||||||
|
|
||||||
@@ -427,7 +433,7 @@ effective:
|
|||||||
redacted: false
|
redacted: false
|
||||||
yaml: "localhost:8080\n"
|
yaml: "localhost:8080\n"
|
||||||
origin:
|
origin:
|
||||||
layer: base
|
layer: main
|
||||||
locations:
|
locations:
|
||||||
- source_id: source-1
|
- source_id: source-1
|
||||||
line: 4
|
line: 4
|
||||||
|
|||||||
@@ -13,14 +13,16 @@ installed at the application root, not as group children.
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `go.maximumdirect.net/commandkit` | The application needs typed command declarations and common CLI behavior. |
|
| `go.maximumdirect.net/commandkit` | The application needs typed command declarations and common CLI behavior. |
|
||||||
| `go.maximumdirect.net/ckconfig` | The application wants ConfigKit-backed configuration scopes and reports. |
|
| `go.maximumdirect.net/ckconfig` | The application wants ConfigKit-backed configuration scopes and reports. |
|
||||||
| `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | The application wants PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, request validation, or native smoke testing. |
|
| `go.maximumdirect.net/ckprompt` | The application wants PromptKit engine configuration/comparison, five catalogs, named inspection, requirements discovery, request validation, or native smoke testing. |
|
||||||
|
|
||||||
The ckconfig v0.2.0 candidate uses core v0.3.0. The ckprompt source still uses
|
The published matched releases are core v0.3.0, ckconfig v0.2.0, and ckprompt v0.2.0.
|
||||||
the old core and ckconfig identities; its planned matched v0.2.0 release will
|
The local ckconfig v0.3.0 candidate uses ConfigKit v1.1.0 and does not compose
|
||||||
use the new paths. Update application imports and dependency versions together.
|
with ckprompt v0.2.0, which retains ckconfig v0.2.0 and ConfigKit v0.8.0.
|
||||||
Old and new core paths have distinct Go type identities. Install core with
|
Update application imports and dependency versions together; old and new core
|
||||||
`go get go.maximumdirect.net/commandkit@v0.3.0` and the matching integration
|
paths have distinct Go type identities. Install core with
|
||||||
with `go get go.maximumdirect.net/ckconfig@v0.2.0` once it is published.
|
`go get go.maximumdirect.net/commandkit@v0.3.0` and either integration with
|
||||||
|
`go get go.maximumdirect.net/ckconfig@v0.2.0` or
|
||||||
|
`go get go.maximumdirect.net/ckprompt@v0.2.0`.
|
||||||
|
|
||||||
The two integrations are independent optional imports. `ckprompt` uses the
|
The two integrations are independent optional imports. `ckprompt` uses the
|
||||||
public scope and error contracts from `ckconfig`; importing it does not add the
|
public scope and error contracts from `ckconfig`; importing it does not add the
|
||||||
@@ -30,12 +32,13 @@ core-only, ConfigKit-only, and composed applications.
|
|||||||
|
|
||||||
## Go compatibility
|
## Go compatibility
|
||||||
|
|
||||||
All three modules declare a consumer minimum of Go 1.26.0. The root module also
|
Core and ckprompt declare a consumer minimum of Go 1.26.0; the ckconfig
|
||||||
|
v0.3.0 candidate requires Go 1.27.0. The root module also
|
||||||
selects ReleaseKit v0.9.0 (`go.maximumdirect.net/releasekit`) as a Go tool, which
|
selects ReleaseKit v0.9.0 (`go.maximumdirect.net/releasekit`) as a Go tool, which
|
||||||
makes that tool's module graph part of the root consumer module requirements
|
makes that tool's module graph part of the root consumer module requirements
|
||||||
even though production packages do not import ReleaseKit. The
|
even though production packages do not import ReleaseKit. The
|
||||||
[release policy](../policy/release.md#consumer-minimum-and-release-toolchain)
|
[release policy](../policy/release.md#consumer-minimum-and-release-toolchain)
|
||||||
defines the support assumption. Maintainers use Go 1.26.8 for validation and
|
defines the support assumption. Maintainers use Go 1.27.0 for validation and
|
||||||
publication; see the [release procedure](../release.md#release-toolchain).
|
publication; see the [release procedure](../release.md#release-toolchain).
|
||||||
|
|
||||||
## Core commands
|
## Core commands
|
||||||
@@ -347,8 +350,24 @@ signal handling, and exit mapping; `Execute` never exits the process.
|
|||||||
Go declarations and GoDoc own exact exported contracts. ConfigKit owns
|
Go declarations and GoDoc own exact exported contracts. ConfigKit owns
|
||||||
configuration decoding, validation, and provenance. PromptKit owns prompt
|
configuration decoding, validation, and provenance. PromptKit owns prompt
|
||||||
formats, profile resolution, and inspection details. See the
|
formats, profile resolution, and inspection details. See the
|
||||||
[ConfigKit v0.8.0 inspection API](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go),
|
[ConfigKit v0.8.0 inspection API for ckprompt v0.2.0](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/inspection.go),
|
||||||
[PromptKit engine methods](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/engine.go),
|
[PromptKit engine methods](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/engine.go),
|
||||||
[configuration inspection](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/configuration_inspection.go),
|
[configuration inspection](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/configuration_inspection.go),
|
||||||
[smoke diagnostics](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/smoke_diagnostics.go),
|
[smoke diagnostics](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/smoke_diagnostics.go),
|
||||||
and [PromptKit v0.16.0 consumer guidance](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/docs/consumers/pkg-promptkit.md).
|
and [PromptKit v0.16.0 consumer guidance](https://gitea.maximumdirect.net/eric/promptkit/src/commit/9178f3eb91c2b2138caa78e22be93c048b4bc992/docs/consumers/pkg-promptkit.md).
|
||||||
|
|
||||||
|
## ConfigKit v1.1 migration
|
||||||
|
|
||||||
|
The ckconfig v0.3.0 candidate uses `go.maximumdirect.net/configkit v1.1.0`
|
||||||
|
and Go 1.27.0. Consumers must migrate ConfigKit imports and values passed to
|
||||||
|
ckconfig: the old and new package paths have distinct type identities. Source
|
||||||
|
reports rename `destination_unresolved` to `destination_is_fallback` and
|
||||||
|
`version_check` to `version_evidence`, and add `empty_import_selections`.
|
||||||
|
|
||||||
|
The upstream [v0.9 migration notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v0.9.0.md),
|
||||||
|
[v0.10 notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v0.10.0.md),
|
||||||
|
[v1.0 migration notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v1.0.0.md),
|
||||||
|
and [v1.1 notes](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/docs/releases/v1.1.0.md)
|
||||||
|
cover source-root `configkit` controls becoming `config`, import requiredness
|
||||||
|
and defaults, collection registration and operations, removed APIs, and CLI
|
||||||
|
assignment order.
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ canonical documentation owners.
|
|||||||
For application-owned aliases, use the
|
For application-owned aliases, use the
|
||||||
[CLI reference](cli.md#application-owned-aliases),
|
[CLI reference](cli.md#application-owned-aliases),
|
||||||
[Go declarations and GoDoc](../command.go), and
|
[Go declarations and GoDoc](../command.go), and
|
||||||
[ADR 0013](adr/0013-application-alias-routing.md). Keep deferred capabilities in
|
[ADR 0013](adr/0013-application-alias-routing.md). Keep unfinished work and
|
||||||
[deferred work](roadmap/deferred.md).
|
capability proposals in [future work](roadmap/future.md).
|
||||||
|
|
||||||
## Initial orientation
|
## Initial orientation
|
||||||
|
|
||||||
@@ -54,17 +54,17 @@ For application-owned aliases, use the
|
|||||||
| Task | Read |
|
| Task | Read |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Implemented CLI behavior | [CLI reference](cli.md) |
|
| Implemented CLI behavior | [CLI reference](cli.md) |
|
||||||
| Invocation reporting | [CLI reporting contract](cli.md#reporting), [consumer guide](consumers/guide.md#invocation-reporting), core GoDoc, [reporting roadmap](roadmap/reporting.md), and [ADR 0014](adr/0014-invocation-reporting.md) |
|
| Invocation reporting | [CLI reporting contract](cli.md#reporting), [consumer guide](consumers/guide.md#invocation-reporting), core GoDoc, and [ADR 0014](adr/0014-invocation-reporting.md) |
|
||||||
| Application-owned aliases | [CLI reference](cli.md#application-owned-aliases), [Go declarations and GoDoc](../command.go), [consumer guide](consumers/guide.md#application-owned-aliases), and [ADR 0013](adr/0013-application-alias-routing.md) |
|
| Application-owned aliases | [CLI reference](cli.md#application-owned-aliases), [Go declarations and GoDoc](../command.go), [consumer guide](consumers/guide.md#application-owned-aliases), and [ADR 0013](adr/0013-application-alias-routing.md) |
|
||||||
| Public API usage and standard-suite wiring | [Consumer guide](consumers/guide.md), [ckconfig package](../integrations/ckconfig/doc.go), [ckprompt package](../integrations/ckprompt/doc.go), and applicable ADRs |
|
| Public API usage and standard-suite wiring | [Consumer guide](consumers/guide.md), [ckconfig package](../integrations/ckconfig/doc.go), [ckprompt package](../integrations/ckprompt/doc.go), and applicable ADRs |
|
||||||
| Dispatcher, registration, or typed inputs | [Command declarations](../command.go), [bindings](../binding.go), [invocation](../execute.go), and [ADR 0001](adr/0001-command-dispatch-and-inputs.md), refined by [ADR 0011](adr/0011-captured-declarations-and-installation.md) |
|
| Dispatcher, registration, or typed inputs | [Command declarations](../command.go), [bindings](../binding.go), [invocation](../execute.go), and [ADR 0001](adr/0001-command-dispatch-and-inputs.md), refined by [ADR 0011](adr/0011-captured-declarations-and-installation.md) |
|
||||||
| Backend integration | [Internal overview](internal/overview.md), [adapter implementation](../internal/cobra/parse.go), and [ADR 0002](adr/0002-cobra-backend.md) |
|
| Backend integration | [Internal overview](internal/overview.md), [adapter implementation](../internal/cobra/parse.go), and [ADR 0002](adr/0002-cobra-backend.md) |
|
||||||
| Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0003](adr/0003-public-facade.md) as scoped by [ADR 0010](adr/0010-optional-integration-modules.md), and the architecture policy |
|
| Public facade or adapter boundaries | [Internal overview](internal/overview.md), [ADR 0003](adr/0003-public-facade.md) as scoped by [ADR 0010](adr/0010-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 |
|
||||||
| Deferred capabilities and proposals | [Deferred work](roadmap/deferred.md) |
|
| Unfinished work and capability proposals | [Future work](roadmap/future.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 [deferred efficiency work](roadmap/deferred.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) |
|
||||||
| Licensing or incorporated material | [Project grant](../COPYRIGHT), [license texts](../LICENSE), and [attribution](oss/attribution.md) |
|
| Licensing or incorporated material | [Project grant](../COPYRIGHT), [license texts](../LICENSE), and [attribution](oss/attribution.md) |
|
||||||
| Policy provenance | [Policy provenance](policy/meta.md) |
|
| Policy provenance | [Policy provenance](policy/meta.md) |
|
||||||
|
|
||||||
@@ -72,11 +72,12 @@ Read all applicable rows for cross-cutting work. Go declarations and GoDoc own
|
|||||||
current exported contracts; the CLI reference owns operator behavior. The
|
current exported contracts; the CLI reference owns operator behavior. The
|
||||||
[maintainer release procedure](release.md) owns current release operations.
|
[maintainer release procedure](release.md) owns current release operations.
|
||||||
Completed roadmaps and implementation evidence remain available in Git history,
|
Completed roadmaps and implementation evidence remain available in Git history,
|
||||||
including [application-owned alias planning, implementation, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/f42aefe02d84e154855ac922173e6f367180929f/docs/roadmap)
|
including [ConfigKit adoption, reporting, release-tooling, and remediation records](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/260256d722f52bc947103d078cb67a129f4cc9f1/docs/roadmap),
|
||||||
|
[application-owned alias planning, implementation, and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/f42aefe02d84e154855ac922173e6f367180929f/docs/roadmap)
|
||||||
and [PromptKit requirements implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/40499a43608bf60d1104cd8ee24caf18ac0e9e66/docs/roadmap).
|
and [PromptKit requirements implementation and remediation](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/40499a43608bf60d1104cd8ee24caf18ac0e9e66/docs/roadmap).
|
||||||
These records are not assignments to restart completed work. The
|
These records are not assignments to restart completed work. The
|
||||||
[deferred-work record](roadmap/deferred.md) preserves future capability targets
|
[future work record](roadmap/future.md) preserves unfinished work and unselected
|
||||||
and unselected proposals separately from current contracts.
|
proposals separately from current contracts.
|
||||||
|
|
||||||
## Documentation validation
|
## Documentation validation
|
||||||
|
|
||||||
@@ -99,28 +100,14 @@ 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. During the vanity-path
|
The root module does not traverse nested modules. Preserve the ignored `go.work`
|
||||||
migration, ckprompt still imports the old core and ckconfig identities and
|
and `go.work.sum`; use `GOWORK=off GOTOOLCHAIN=local` for dependency preparation,
|
||||||
cannot compose with the migrated modules until its own migration is complete. After
|
module suites, and examples during the ckconfig migration. Local ckprompt uses
|
||||||
the matched migrations, during development use a
|
the old ConfigKit identity and cannot compose with migrated local ckconfig. Its
|
||||||
local workspace for all three modules; it is ignored and must not be committed.
|
independent suite and composed example use published ckconfig v0.2.0; restore
|
||||||
If a local `go.work` already exists, preserve it and add these module directories:
|
full local workspace guidance after the coordinated ckprompt migration.
|
||||||
|
Run `go test ./...` separately from each module directory.
|
||||||
|
|
||||||
```sh
|
|
||||||
if [ -f go.work ]; then
|
|
||||||
go work use . ./integrations/ckconfig ./integrations/ckprompt
|
|
||||||
else
|
|
||||||
go work init . ./integrations/ckconfig ./integrations/ckprompt
|
|
||||||
fi
|
|
||||||
go test ./...
|
|
||||||
(cd integrations/ckconfig && go test ./...)
|
|
||||||
(cd integrations/ckprompt && go test ./...)
|
|
||||||
```
|
|
||||||
|
|
||||||
The workspace checks package behavior. Workspace-off checks with each module's
|
|
||||||
own dependency graph are separate evidence. For unpublished CommandKit dependency
|
|
||||||
versions, the [completed integration validation record](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/8a82620dfcd34c0ae56bbecb0d014eb49786bc92/docs/roadmap/implementation.md#stage-12-validate-the-complete-end-state-and-finish)
|
|
||||||
describes the disposable module-file procedure used during implementation.
|
|
||||||
Format changed Go files with `gofmt`. The
|
Format changed Go files with `gofmt`. The
|
||||||
[maintainer release procedure](release.md) owns candidate preparation and
|
[maintainer release procedure](release.md) owns candidate preparation and
|
||||||
publication commands.
|
publication commands.
|
||||||
@@ -144,25 +131,25 @@ external services. The PromptKit smoke examples use local fixtures and the
|
|||||||
example's configured client:
|
example's configured client:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go run ./examples/core workspace greet --count=0 --tag=first --tag second
|
GOWORK=off GOTOOLCHAIN=local go run ./examples/core workspace greet --count=0 --tag=first --tag second
|
||||||
(cd integrations/ckconfig/examples/simple && go run . config show)
|
(cd integrations/ckconfig/examples/simple && GOWORK=off GOTOOLCHAIN=local go run . config show)
|
||||||
(cd integrations/ckconfig/examples/simple && go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml)
|
(cd integrations/ckconfig/examples/simple && GOWORK=off GOTOOLCHAIN=local go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . config validate --scope all --campaign spring --limit=0)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . config validate --scope all --campaign spring --limit=0)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . config diff --scope app --config fixtures/before.yml --against-config fixtures/after.yml)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . config diff --scope promptkit --config fixtures/before.yml --against-config fixtures/after.yml --campaign spring)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit list prompts --config fixtures/before.yml --campaign spring)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list prompts --config fixtures/before.yml --campaign spring)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list profiles --config fixtures/after.yml --campaign autumn --format yaml)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit list backends --namespace team)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list backends --namespace team)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit list namespaces --kind prompt --kind profile)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list namespaces --kind prompt --kind profile)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit list collections)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit list collections)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit show prompt briefing --campaign spring --format yaml)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit show prompt briefing --campaign spring --format yaml)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements show briefing --campaign spring)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements show briefing --campaign spring)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt --var mode=full --input notes=fixtures/notes.txt --format yaml)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements validate briefing --campaign spring --input topic=fixtures/topic.txt --var mode=full --input notes=fixtures/notes.txt --format yaml)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit test reachability --campaign spring --prompt briefing --profile spring)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit test reachability --campaign spring --prompt briefing --profile spring)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . promptkit test all --campaign spring --prompt briefing --profile spring)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . promptkit test all --campaign spring --prompt briefing --profile spring)
|
||||||
(cd integrations/ckprompt/examples/composed && go run . session restore session-42 --campaign spring)
|
(cd integrations/ckprompt/examples/composed && GOWORK=off GOTOOLCHAIN=local go run . session restore session-42 --campaign spring)
|
||||||
```
|
```
|
||||||
|
|
||||||
The [consumer guide](consumers/guide.md) explains how their public API usage
|
The [consumer guide](consumers/guide.md) explains how their public API usage
|
||||||
|
|||||||
@@ -6,10 +6,9 @@ own the optional ConfigKit and PromptKit integrations. The
|
|||||||
[architecture policy](../policy/architecture.md) owns normative boundaries;
|
[architecture policy](../policy/architecture.md) owns normative boundaries;
|
||||||
this page inventories the implemented owners.
|
this page inventories the implemented owners.
|
||||||
|
|
||||||
The core and ckconfig modules declare `go.maximumdirect.net/commandkit` and
|
The core, ckconfig, and ckprompt modules declare
|
||||||
`go.maximumdirect.net/ckconfig`. Ckprompt retains the old module and import
|
`go.maximumdirect.net/commandkit`, `go.maximumdirect.net/ckconfig`, and
|
||||||
identities until its planned matched release; Go treats those identities as
|
`go.maximumdirect.net/ckprompt`, respectively.
|
||||||
distinct.
|
|
||||||
|
|
||||||
## Root `commandkit`
|
## Root `commandkit`
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ invariant, not from the convenience of the selected implementation. Explain the
|
|||||||
specific failure it prevents and why a less restrictive implementation cannot
|
specific failure it prevents and why a less restrictive implementation cannot
|
||||||
satisfy the contract.
|
satisfy the contract.
|
||||||
|
|
||||||
The [deferred-work record](../roadmap/deferred.md) distinguishes future proposals
|
The [future work record](../roadmap/future.md) distinguishes future proposals
|
||||||
from accepted contracts. Do not approve proposed commands, grammar, statuses, or
|
from accepted contracts. Do not approve proposed commands, grammar, statuses, or
|
||||||
illustrative API declarations
|
illustrative API declarations
|
||||||
merely by repeating them in implementation or tests. Cobra/pflag defaults do not
|
merely by repeating them in implementation or tests. Cobra/pflag defaults do not
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ recommended for application-owned commands; their names and domain behavior
|
|||||||
remain application choices.
|
remain application choices.
|
||||||
|
|
||||||
Accepted ADRs and current CLI/API owners define selected contracts; the
|
Accepted ADRs and current CLI/API owners define selected contracts; the
|
||||||
[deferred-work record](../roadmap/deferred.md) preserves remaining proposals.
|
[future work record](../roadmap/future.md) preserves remaining proposals.
|
||||||
Backend defaults and incidental consumer behavior do not establish new contracts.
|
Backend defaults and incidental consumer behavior do not establish new contracts.
|
||||||
A replacement backend must preserve published CLI behavior or follow deliberate compatibility
|
A replacement backend must preserve published CLI behavior or follow deliberate compatibility
|
||||||
changes under the release policy.
|
changes under the release policy.
|
||||||
|
|||||||
@@ -35,20 +35,21 @@ module metadata.
|
|||||||
|
|
||||||
## Release toolchain
|
## Release toolchain
|
||||||
|
|
||||||
The selected release toolchain is **Go 1.26.8**. Each module declares a consumer
|
The selected release toolchain is **Go 1.27.0**. Core and ckprompt declare a
|
||||||
minimum of **Go 1.26.0**. Maintainers use Go 1.26.8 for dependency preparation,
|
consumer minimum of **Go 1.26.0**; ckconfig requires **Go 1.27.0**. Maintainers
|
||||||
candidate validation, and ReleaseKit execution. The
|
use Go 1.27.0 for dependency preparation, candidate validation, and ReleaseKit
|
||||||
|
execution. The
|
||||||
[consumer guide](consumers/guide.md#go-compatibility) and
|
[consumer guide](consumers/guide.md#go-compatibility) and
|
||||||
[release policy](policy/release.md#consumer-minimum-and-release-toolchain)
|
[release policy](policy/release.md#consumer-minimum-and-release-toolchain)
|
||||||
describe these selections.
|
describe these selections.
|
||||||
|
|
||||||
Select Go 1.26.8 on `PATH`; the launcher uses `GOTOOLCHAIN=local`. If needed,
|
Select Go 1.27.0 on `PATH`; the launcher uses `GOTOOLCHAIN=local`. If needed,
|
||||||
install it with the standard Go tools:
|
install it with the standard Go tools:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
GOWORK=off GOTOOLCHAIN=local go install golang.org/dl/go1.26.8@latest
|
GOWORK=off GOTOOLCHAIN=local go install golang.org/dl/go1.27.0@latest
|
||||||
go1.26.8 download
|
go1.27.0 download
|
||||||
export PATH="$(go1.26.8 env GOROOT)/bin:$PATH"
|
export PATH="$(go1.27.0 env GOROOT)/bin:$PATH"
|
||||||
hash -r
|
hash -r
|
||||||
GOWORK=off GOTOOLCHAIN=local go version
|
GOWORK=off GOTOOLCHAIN=local go version
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
# Deferred work
|
|
||||||
|
|
||||||
Status: retained future work and unselected proposals; no implementation schedule.
|
|
||||||
|
|
||||||
## Purpose and authority
|
|
||||||
|
|
||||||
Completed initial delivery, performance, ReleaseKit upgrade, and remediation
|
|
||||||
records have been retired. This document preserves remaining deferred
|
|
||||||
capabilities and unselected ideas under the
|
|
||||||
[release policy](../policy/release.md#release-documentation-and-preparation).
|
|
||||||
The original records remain available in
|
|
||||||
[Git history](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap).
|
|
||||||
|
|
||||||
Accepted [ADRs](../adr/) and the [architecture policy](../policy/architecture.md)
|
|
||||||
govern any future implementation. The [CLI reference](../cli.md), public GoDoc,
|
|
||||||
and [consumer guide](../consumers/guide.md) own implemented behavior. Retaining
|
|
||||||
an idea here does not select its syntax, API, priority, or delivery date.
|
|
||||||
|
|
||||||
## Deferred capability targets
|
|
||||||
|
|
||||||
### Comparison extensions
|
|
||||||
|
|
||||||
Independent per-side domain selectors and an optional assertion mode remain
|
|
||||||
unselected extensions to the delivered ConfigKit comparison. Consider them only
|
|
||||||
for a concrete consumer need and a deliberate API/behavior decision under the
|
|
||||||
relevant ADRs.
|
|
||||||
|
|
||||||
### Alias completion and discovery
|
|
||||||
|
|
||||||
The delivered [shell completion feature](../cli.md#shell-completion) provides
|
|
||||||
canonical suggestions and alias-aware interpretation. Potential future work
|
|
||||||
includes suggesting command and flag alias spellings and valid continuations of
|
|
||||||
alias-only prefixes. For example, completion could suggest `inspect` after
|
|
||||||
`app legacy ` when `legacy inspect` is an installed alias.
|
|
||||||
|
|
||||||
Alias discovery is outside the initial scope. This deferral does not establish a
|
|
||||||
permanent canonical-only completion contract or prohibit future alias discovery.
|
|
||||||
A later design should determine how alias suggestions are presented alongside
|
|
||||||
canonical suggestions while ensuring inserted continuations form valid next
|
|
||||||
steps. No delivery date or final API is selected here.
|
|
||||||
|
|
||||||
## Other deferred proposals
|
|
||||||
|
|
||||||
These capabilities remain outside the delivered scope and require a concrete
|
|
||||||
operator or consumer need and an appropriate ownership/behavior decision:
|
|
||||||
|
|
||||||
- JSON reports and output-file management or reloadable export.
|
|
||||||
- Shell completion extensions, including alias discovery described above and
|
|
||||||
dynamic discovery of configured or remote values.
|
|
||||||
- Configuration mutation, generic value assignment, and exhaustive field-origin
|
|
||||||
inventories.
|
|
||||||
- Credential diagnostics beyond PromptKit's native smoke checks and additional
|
|
||||||
live provider probes.
|
|
||||||
- Additional component identity registration and domain artifact catalogs.
|
|
||||||
- Additional library families, including possible FeedKit integration; families
|
|
||||||
can define suitable verbs without requiring comparison or configuration scopes.
|
|
||||||
- Backend selection or replacement, a plugin framework, general dependency
|
|
||||||
injection, and concurrent-dispatch guarantees.
|
|
||||||
|
|
||||||
Execution, rendering, serving, and session operations remain application-owned.
|
|
||||||
Shared vocabulary is guidance under [ADR 0006](../adr/0006-command-grammar.md).
|
|
||||||
Backend replacement remains possible behind the accepted facade, subject to the
|
|
||||||
published API/CLI contracts and deliberate compatibility decisions.
|
|
||||||
|
|
||||||
## Possible further efficiency work
|
|
||||||
|
|
||||||
Selected-scope memoization and selector-membership indexes were deferred pending
|
|
||||||
measurements that justify their bookkeeping. Mutable backend reuse across
|
|
||||||
invocations, segmented aggregate YAML delivery, provider caching, consumer-loader
|
|
||||||
redesign, and a replacement backend were outside the completed performance
|
|
||||||
target. Reconsider them only with concrete motivation and review of ownership,
|
|
||||||
invocation state, native reports, and the affected contracts. Retained measurement
|
|
||||||
records are historical evidence, not performance guarantees or release gates.
|
|
||||||
|
|
||||||
## Consumer adoption
|
|
||||||
|
|
||||||
Consumer migrations remain separate from library delivery. Applications can
|
|
||||||
replace duplicated standard handlers and routing, then update their CLI docs
|
|
||||||
and subprocess consumers for intentional changes while retaining domain commands.
|
|
||||||
No migration order or claim about individual applications' adoption is recorded
|
|
||||||
here; the [consumer guide](../consumers/guide.md) and maintained examples provide
|
|
||||||
integration guidance.
|
|
||||||
183
docs/roadmap/future.md
Normal file
183
docs/roadmap/future.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Future work
|
||||||
|
|
||||||
|
Status: pending release and integration work, plus future capability proposals.
|
||||||
|
No delivery dates are selected here.
|
||||||
|
|
||||||
|
## Purpose and authority
|
||||||
|
|
||||||
|
Completed roadmaps, implementation plans, and review findings have been retired.
|
||||||
|
This document preserves unfinished work and unselected ideas under the
|
||||||
|
[release policy](../policy/release.md#release-documentation-and-preparation).
|
||||||
|
The completed ConfigKit adoption, reporting, dependency alignment, release-tooling,
|
||||||
|
and remediation records remain available at the
|
||||||
|
[retirement snapshot](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/260256d722f52bc947103d078cb67a129f4cc9f1/docs/roadmap).
|
||||||
|
[Earlier retired records](https://gitea.maximumdirect.net/eric/CommandKit/src/commit/6bc37e7ba64ca0920b4d0cc77039a18d4006b24e/docs/roadmap)
|
||||||
|
also remain in Git history. Completed records are not assignments to restart work.
|
||||||
|
|
||||||
|
Accepted [ADRs](../adr/) and the [architecture policy](../policy/architecture.md)
|
||||||
|
govern any future implementation. The [CLI reference](../cli.md), public GoDoc,
|
||||||
|
and [consumer guide](../consumers/guide.md) own implemented behavior. Retaining
|
||||||
|
an idea here does not select its syntax, API, priority, or delivery date.
|
||||||
|
|
||||||
|
## Pending release and integration work
|
||||||
|
|
||||||
|
### ckconfig release and hosted delivery
|
||||||
|
|
||||||
|
The ckconfig v0.3.0 candidate adopts ConfigKit v1.1.0 and Go 1.27.0; its
|
||||||
|
implementation and audits are complete. Its
|
||||||
|
[candidate release note](../../integrations/ckconfig/docs/releases/v0.3.0.md)
|
||||||
|
is prepared, but source publication and hosted delivery remain pending. Complete
|
||||||
|
those operations when requested through the [release procedure](../release.md),
|
||||||
|
using the existing fresh-version guards and reporting source publication and
|
||||||
|
hosted Gitea delivery separately. Publishing this roadmap cleanup does not
|
||||||
|
publish a module version tag or deliver a release page.
|
||||||
|
|
||||||
|
### ckprompt dependency migration and workspace alignment
|
||||||
|
|
||||||
|
Review the upstream PromptKit vanity release and select compatible ConfigKit
|
||||||
|
and PromptKit dependencies before migrating ckprompt's adapters and maintained
|
||||||
|
composed consumer. The new ckconfig uses vanity ConfigKit types; ckprompt v0.2.0
|
||||||
|
still uses published ckconfig v0.2.0 and old-path ConfigKit v0.8.0. Their local
|
||||||
|
sources do not currently compose in the three-module workspace. See the
|
||||||
|
[consumer guide](../consumers/guide.md#module-selection) for the current module
|
||||||
|
relationship.
|
||||||
|
|
||||||
|
The follow-up includes migrating affected imports and public type boundaries,
|
||||||
|
selecting real released dependency versions and the required Go minimum,
|
||||||
|
updating notices and migration guidance, and validating both ckprompt's
|
||||||
|
independent graph and the aligned composed consumer. Restore three-module
|
||||||
|
workspace guidance when those dependencies align, updating the ignored workspace
|
||||||
|
Go version as needed. Until then, preserve local workspace files and validate
|
||||||
|
with workspace discovery off as described in the [development guide](../development.md).
|
||||||
|
No unreviewed PromptKit version or new compatibility bridge is selected here.
|
||||||
|
|
||||||
|
## Future capability targets
|
||||||
|
|
||||||
|
### Comparison extensions
|
||||||
|
|
||||||
|
Independent per-side domain selectors and an optional assertion mode remain
|
||||||
|
unselected extensions to the delivered ConfigKit comparison. Consider them only
|
||||||
|
for a concrete consumer need and a deliberate API/behavior decision under the
|
||||||
|
relevant ADRs.
|
||||||
|
|
||||||
|
### Configuration inspection extensions
|
||||||
|
|
||||||
|
The [completed ConfigKit v1.1.0 adoption review](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/260256d722f52bc947103d078cb67a129f4cc9f1/docs/roadmap/configkit-v1.1.0.md#selected-scope-decisions)
|
||||||
|
retained the following work after dependency and source-report adoption.
|
||||||
|
Metadata inspection is the recommended next functional sprint; the other
|
||||||
|
features have no selected sequence or delivery date. These proposals do not
|
||||||
|
establish command grammar, report schemas, or new provider requirements.
|
||||||
|
ConfigKit's public APIs own the evidence and its semantics.
|
||||||
|
|
||||||
|
- **Optional field metadata, path discovery, and history (OD-3).** Expose native
|
||||||
|
`Metadata.Lookup`, `IsExplicit`, `HistoricalPaths`, and `History` through an
|
||||||
|
optional provider capability. Design field and history reports together,
|
||||||
|
keeping existing providers usable. Distinguish effective paths from removed
|
||||||
|
historical paths: a failed `Lookup` must not suppress available `History`.
|
||||||
|
Validate that distinction and faithful projection of returned field/change
|
||||||
|
records without recreating upstream provenance logic. Historical enumeration
|
||||||
|
is not an exhaustive inventory of possible schema fields. This gives the
|
||||||
|
earlier field-origin inventory proposal a concrete, upstream-backed scope;
|
||||||
|
command names, selectors, and report shapes remain to be designed.
|
||||||
|
- **Failed-load source inventory (OD-4).** Present acquired source evidence from
|
||||||
|
`LoadError.Sources()` while retaining the failed outcome and diagnostics.
|
||||||
|
Design how an adapter returns its source facet on error and how result output
|
||||||
|
precedes terminal failure presentation. Cover acquisition and report-delivery
|
||||||
|
failures together; current diagnostic context remains available meanwhile.
|
||||||
|
- **Detailed comparison (OD-5).** Consider an additional form projecting native
|
||||||
|
`Difference` paths, both snapshots, presence/redaction fields, and
|
||||||
|
`HiddenChanged`. The current comparison retains the reduced
|
||||||
|
additions/changes/deletions report. Decide later whether a detailed form
|
||||||
|
complements it or replaces it through a deliberate compatibility change.
|
||||||
|
- **Structured diagnostics (OD-6).** Consider machine-readable native codes,
|
||||||
|
paths, severities, and locations alongside CommandKit's shared reporting
|
||||||
|
design. Define result/diagnostic channels, warning and terminal-failure
|
||||||
|
interaction, and delivery outcomes. A ckconfig-specific report remains an
|
||||||
|
alternative, with its cross-family alignment considered explicitly.
|
||||||
|
- **Source-ID filtering.** Consider selecting a record already available in the
|
||||||
|
source inventory. Native `Source(id)` lookup is a convenience; this proposal
|
||||||
|
need not introduce another command or require a lookup method from every
|
||||||
|
custom source provider.
|
||||||
|
|
||||||
|
Discovery, import defaults, collection identities, and field-level resolution
|
||||||
|
recording remain available through application loaders. Standard inspection of
|
||||||
|
resource contexts or secrets-directory bootstrap has no immediate proposal;
|
||||||
|
those capabilities primarily serve application loading and startup.
|
||||||
|
|
||||||
|
### Alias completion and discovery
|
||||||
|
|
||||||
|
The delivered [shell completion feature](../cli.md#shell-completion) provides
|
||||||
|
canonical suggestions and alias-aware interpretation. Potential future work
|
||||||
|
includes suggesting command and flag alias spellings and valid continuations of
|
||||||
|
alias-only prefixes. For example, completion could suggest `inspect` after
|
||||||
|
`app legacy ` when `legacy inspect` is an installed alias.
|
||||||
|
|
||||||
|
Alias discovery is outside the initial scope. This deferral does not establish a
|
||||||
|
permanent canonical-only completion contract or prohibit future alias discovery.
|
||||||
|
A later design should determine how alias suggestions are presented alongside
|
||||||
|
canonical suggestions while ensuring inserted continuations form valid next
|
||||||
|
steps. No delivery date or final API is selected here.
|
||||||
|
|
||||||
|
### Reporting extensions
|
||||||
|
|
||||||
|
Error-conversion helpers such as `WarnError` remain deferred pending demonstrated
|
||||||
|
value; applications can already use `report.Warn(err.Error())`. Terminal redraw
|
||||||
|
and progress-bar presentation were outside the completed reporting scope and
|
||||||
|
remain unselected. Whole-run buffering to make failed runs show only errors
|
||||||
|
was also outside that scope. Any later extension needs a deliberate API and
|
||||||
|
presentation decision rather than assuming those behaviors are already provided.
|
||||||
|
|
||||||
|
### Release workflow extensions
|
||||||
|
|
||||||
|
Historical hosted-page backfilling and automated CI delivery remain separate
|
||||||
|
future choices. The current local page-only delivery workflow is implemented;
|
||||||
|
these extensions are not prerequisites for using it. The release procedure owns
|
||||||
|
delivery, immutable content, and recovery behavior.
|
||||||
|
|
||||||
|
Additional validation options, including race testing, full vet, compilation
|
||||||
|
matrices, size limits, and more forbidden-file paths, can be considered for
|
||||||
|
demonstrated needs. None is selected by retaining it here, and the existing
|
||||||
|
candidate checks do not become general prohibitions on development workspaces.
|
||||||
|
|
||||||
|
## Other future proposals
|
||||||
|
|
||||||
|
These capabilities remain outside the delivered scope and require a concrete
|
||||||
|
operator or consumer need and an appropriate ownership/behavior decision:
|
||||||
|
|
||||||
|
- JSON reports and output-file management or reloadable export.
|
||||||
|
- Shell completion extensions, including alias discovery described above and
|
||||||
|
dynamic discovery of configured or remote values.
|
||||||
|
- Configuration mutation and generic value assignment. Field metadata and
|
||||||
|
provenance inspection are scoped under
|
||||||
|
[configuration inspection extensions](#configuration-inspection-extensions).
|
||||||
|
- Credential diagnostics beyond PromptKit's native smoke checks and additional
|
||||||
|
live provider probes.
|
||||||
|
- Additional component identity registration and domain artifact catalogs.
|
||||||
|
- Additional library families, including possible FeedKit integration; families
|
||||||
|
can define suitable verbs without requiring comparison or configuration scopes.
|
||||||
|
- Backend selection or replacement, a plugin framework, general dependency
|
||||||
|
injection, and concurrent-dispatch guarantees.
|
||||||
|
|
||||||
|
Execution, rendering, serving, and session operations remain application-owned.
|
||||||
|
Shared vocabulary is guidance under [ADR 0006](../adr/0006-command-grammar.md).
|
||||||
|
Backend replacement remains possible behind the accepted facade, subject to the
|
||||||
|
published API/CLI contracts and deliberate compatibility decisions.
|
||||||
|
|
||||||
|
## Possible further efficiency work
|
||||||
|
|
||||||
|
Selected-scope memoization and selector-membership indexes were deferred pending
|
||||||
|
measurements that justify their bookkeeping. Mutable backend reuse across
|
||||||
|
invocations, segmented aggregate YAML delivery, provider caching, consumer-loader
|
||||||
|
redesign, and a replacement backend were outside the completed performance
|
||||||
|
target. Reconsider them only with concrete motivation and review of ownership,
|
||||||
|
invocation state, native reports, and the affected contracts. Retained measurement
|
||||||
|
records are historical evidence, not performance guarantees or release gates.
|
||||||
|
|
||||||
|
## Consumer adoption
|
||||||
|
|
||||||
|
Consumer migrations remain separate from library delivery. Applications can
|
||||||
|
replace duplicated standard handlers and routing, then update their CLI docs
|
||||||
|
and subprocess consumers for intentional changes while retaining domain commands.
|
||||||
|
No migration order or claim about individual applications' adoption is recorded
|
||||||
|
here; the [consumer guide](../consumers/guide.md) and maintained examples provide
|
||||||
|
integration guidance.
|
||||||
@@ -1,351 +0,0 @@
|
|||||||
# CommandKit vanity migration and dependency alignment plan
|
|
||||||
|
|
||||||
Status: Stages 1–3 complete; Stages 4–7 are not started.
|
|
||||||
|
|
||||||
This plan is for the Luna coding agent implementing the
|
|
||||||
[feature roadmap](integration-dependency-alignment.md). Follow the stages in
|
|
||||||
integer order during one end-to-end sprint. Unpublished editing states may be
|
|
||||||
temporarily inconsistent. Each published module must be a coherent, committed
|
|
||||||
candidate validated by its ordinary release workflow.
|
|
||||||
|
|
||||||
This planning pass changes documentation only. The target includes three real
|
|
||||||
source releases because later modules need downloadable predecessors. The
|
|
||||||
publication stages below describe that future work; this planning request does
|
|
||||||
not perform or authorize Git pushes. Honor the user's implementation/publication
|
|
||||||
scope when executing the plan, and report any unperformed release as pending.
|
|
||||||
|
|
||||||
Read [development guidance](../development.md), the
|
|
||||||
[agent policy](../policy/agents.md), [architecture policy](../policy/architecture.md),
|
|
||||||
[testing policy](../policy/testing.md),
|
|
||||||
[documentation policy](../policy/documentation.md),
|
|
||||||
[release policy](../policy/release.md), and [OSS policy](../policy/oss.md) for
|
|
||||||
the work they govern. Follow `AGENTS.md` codebase-memory discovery instructions.
|
|
||||||
The [release procedure](../release.md) remains the owner of operational commands.
|
|
||||||
|
|
||||||
The previous plan's [completed ReleaseKit v0.9.0 stages and evidence](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/c8d659dfe5ae3e834b3aeabdfd0fe29b736dc05a/docs/roadmap/implementation.md)
|
|
||||||
remain in Git history. R1/R2 in [remediation.md](remediation.md) and the ReleaseKit
|
|
||||||
adoption are complete; do not restart them or rewrite their historical evidence.
|
|
||||||
|
|
||||||
## Baseline and fixed decisions
|
|
||||||
|
|
||||||
Planning baseline: `c8d659dfe5ae3e834b3aeabdfd0fe29b736dc05a`.
|
|
||||||
|
|
||||||
| Module directory | Current module path | Target module path | Target version and full tag |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `.` | `gitea.maximumdirect.net/eric/CommandKit` | `go.maximumdirect.net/commandkit` | v0.3.0; `v0.3.0` |
|
|
||||||
| `integrations/ckconfig` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig` | `go.maximumdirect.net/ckconfig` | v0.2.0; `integrations/ckconfig/v0.2.0` |
|
|
||||||
| `integrations/ckprompt` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | `go.maximumdirect.net/ckprompt` | v0.2.0; `integrations/ckprompt/v0.2.0` |
|
|
||||||
|
|
||||||
- Both integrations currently require core v0.2.0; ckprompt also requires
|
|
||||||
ckconfig v0.1.0. Their source uses newer core APIs. Independent baseline suites
|
|
||||||
fail; temporary local-source selections pass only when ckprompt also uses
|
|
||||||
current ckconfig. The feature roadmap records those diagnostics.
|
|
||||||
- Target ckconfig requires `go.maximumdirect.net/commandkit v0.3.0`. Target
|
|
||||||
ckprompt requires that core and `go.maximumdirect.net/ckconfig v0.2.0`.
|
|
||||||
- Vanity discovery is verified. The integration metadata's fourth field maps
|
|
||||||
the short paths to the existing physical directories. Existing tags still
|
|
||||||
declare old identities. Discovery alone does not complete module migration.
|
|
||||||
- Preserve package names, exported declaration shapes, runtime behavior, Go
|
|
||||||
1.26.0 consumer minimums, and the Go 1.26.8 maintainer toolchain. Preserve root
|
|
||||||
ReleaseKit v0.9.0 selection, scripts, profiles, endpoints, and validators.
|
|
||||||
- Retain ConfigKit v0.8.0 and PromptKit v0.16.0; no upstream library upgrade is
|
|
||||||
selected. Inspect tidy's actual graph changes and update affected attribution.
|
|
||||||
- The three proposed tags were unused at planning time. Existing publication
|
|
||||||
guards recheck freshness; never move/reuse a published tag. A conflict needs
|
|
||||||
a deliberate new version selection and matching dependent metadata/notes.
|
|
||||||
- Retain ignored `go.work` and `go.work.sum`, and the supplied ignored
|
|
||||||
`.releasekit/gitea-token` without reading its contents. No credential or live
|
|
||||||
provider is needed for local validation. Source publication uses the existing
|
|
||||||
Git endpoint; hosted delivery remains a separate operation/outcome.
|
|
||||||
|
|
||||||
Do not rename physical module directories or flatten integration tag prefixes.
|
|
||||||
Do not add an old-path forwarding module, type-interoperability layer, API
|
|
||||||
rollback, permanent validation shim, or new recurring release gate. These are
|
|
||||||
outside the selected migration, not new restrictions on application behavior.
|
|
||||||
|
|
||||||
## Execution and validation conventions
|
|
||||||
|
|
||||||
Use Go 1.26.8 on `PATH` following the existing
|
|
||||||
[toolchain setup](../release.md#release-toolchain). The ignored workspace declares
|
|
||||||
Go 1.26.10 at baseline; preserve it. Use `GOWORK=off GOTOOLCHAIN=local` for module
|
|
||||||
preparation and independent validation. Use normal dependency retrieval during
|
|
||||||
preparation; ReleaseKit runs the final selected-module suite offline/read-only.
|
|
||||||
|
|
||||||
Migrate module-owned source, tests, and examples together. Apply integration
|
|
||||||
path mappings before the broader core prefix when a replacement tool is used;
|
|
||||||
`go.maximumdirect.net/commandkit/integrations/ckconfig` is not the selected
|
|
||||||
ckconfig identity. Preserve import aliases such as `commandkit`. Core `internal`
|
|
||||||
imports must use the new core prefix. Review identity-sensitive strings as well
|
|
||||||
as Go import declarations.
|
|
||||||
|
|
||||||
Update current prose and GoDoc for the module being migrated. Treat repository,
|
|
||||||
license, and immutable historical source links separately from Go import paths.
|
|
||||||
Keep published notes, accepted ADR history, and completed review evidence intact.
|
|
||||||
Do not globally replace every old URL or migrate unrelated upstream identities.
|
|
||||||
|
|
||||||
Publication steps use the existing protocol: prepare dependencies, review and
|
|
||||||
commit the final selected candidate on `main`, publish that candidate commit to
|
|
||||||
the authoritative branch, and invoke the module's release wrapper. The wrapper
|
|
||||||
runs the owning complete suite once, selected file checks, and publication
|
|
||||||
guards, then creates/pushes the intended tag. It does not push `main` for you.
|
|
||||||
Run validation-only `check` for diagnosis when useful; do not make it a required
|
|
||||||
duplicate suite before `publish`. Do not add CI/proxy polling or post-push
|
|
||||||
read-back as a successful-publication gate. Reuse evidence for unchanged content.
|
|
||||||
|
|
||||||
Each release has its own candidate commit, suite result, and publication outcome.
|
|
||||||
The next module's dependency download is preparation for that next release;
|
|
||||||
failure to download does not undo completion of the predecessor's source push.
|
|
||||||
Use a command-scoped direct download to diagnose proxy lag if necessary rather
|
|
||||||
than permanently changing proxy settings. Retain authentic downloaded sums.
|
|
||||||
|
|
||||||
## Stage 1: Migrate core identity and prepare its release candidate
|
|
||||||
|
|
||||||
**Completed.** The root module, owned imports, component build identity,
|
|
||||||
consumer guidance, and v0.3.0 release note use the new core identity. The
|
|
||||||
focused build-identity test passed offline with Go 1.26.8; affected links and
|
|
||||||
whitespace were checked. The complete candidate suite belongs to publication.
|
|
||||||
|
|
||||||
1. Change only the root module declaration to `go.maximumdirect.net/commandkit`.
|
|
||||||
Migrate root-owned imports in production files, root/external tests, internal
|
|
||||||
packages, and `examples/core`. Leave nested module migration to Stages 3/5.
|
|
||||||
Preserve the root tool declaration and other dependency versions; prepare
|
|
||||||
caches and tidy the root with workspace discovery off.
|
|
||||||
2. Update `commandKitModulePath` in `builtins.go` to the new core identity.
|
|
||||||
`version --scope commandkit` uses it to find build information. Retain its
|
|
||||||
existing application/component scopes, tag/replacement handling, and `dev`
|
|
||||||
fallback; do not add a legacy-identity fallback.
|
|
||||||
3. Adapt existing identity/import-path test expectations. In
|
|
||||||
`TestCommandKitBuildIdentityProjectsEffectiveModuleVersion`, make at least
|
|
||||||
one existing successful tagged case supply the literal new module path
|
|
||||||
independently of `commandKitModulePath`. Otherwise a stale constant and its
|
|
||||||
self-referencing fixtures could agree while real version lookup fails.
|
|
||||||
Preserve all existing replacement/development cases and boundary assertions.
|
|
||||||
4. Update the root row in README's module table, current core imports and
|
|
||||||
installation guidance in `docs/consumers/guide.md`, affected developer and
|
|
||||||
internal guidance, example documentation, and GoDoc. Describe integrations
|
|
||||||
according to their implemented identity until their migration stages land;
|
|
||||||
keep the matched future set in migration guidance explicit.
|
|
||||||
5. Refresh `docs/releases/v0.3.0.md` against the full v0.2.0-to-candidate change:
|
|
||||||
aliases, reporting migration, completion, ReleaseKit maintenance, and the new
|
|
||||||
core import path. Explain consumer updates and the forthcoming matched
|
|
||||||
integration versions. Use current procedure URLs with immutable `v0.3.0`
|
|
||||||
source/licensing links. Keep the declared toolchains unchanged.
|
|
||||||
6. Format changed Go files. Review root-owned imports/identity literals and
|
|
||||||
module metadata; check affected prose links and whitespace. Run the existing
|
|
||||||
focused identity test with prepared caches:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
GOWORK=off GOTOOLCHAIN=local GOPROXY=off GONOPROXY=none GOSUMDB=off \
|
|
||||||
go test -mod=readonly -count=1 -run '^TestCommandKitBuildIdentityProjectsEffectiveModuleVersion$' .
|
|
||||||
```
|
|
||||||
|
|
||||||
**Stage result:** a reviewed core v0.3.0 candidate with the new identity, correct
|
|
||||||
component version lookup, migrated root consumers, and current release notes.
|
|
||||||
The full root suite belongs to Stage 2's normal publication workflow.
|
|
||||||
|
|
||||||
## Stage 2: Validate and publish core v0.3.0
|
|
||||||
|
|
||||||
**Completed.** Core `go.maximumdirect.net/commandkit v0.3.0` was published as
|
|
||||||
tag `v0.3.0` at candidate `e256eb1cc02a0c72c4e23c4967ed1caeaef17008`.
|
|
||||||
The ordinary Go 1.26.8 release workflow passed the complete root suite and
|
|
||||||
selected file checks before the successful source-tag push.
|
|
||||||
|
|
||||||
1. Review and commit the complete core candidate under the local commit policy.
|
|
||||||
Confirm that unrelated/private files and ignored workspaces are excluded.
|
|
||||||
The independently released integration sources may still declare old paths;
|
|
||||||
that does not make their suites a prerequisite for this root release.
|
|
||||||
2. From the repository root, execute the existing publication sequence within
|
|
||||||
the authorized release scope:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git push origin HEAD:refs/heads/main
|
|
||||||
./scripts/release core v0.3.0
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Require the real selected-module suite and file checks to pass. Fix actual
|
|
||||||
failures in scope and commit the corrected candidate before retrying. On a
|
|
||||||
failed/ambiguous push, use the existing publication evidence and recovery
|
|
||||||
procedure. Do not force refs, bypass guards, or treat a local tag as publication.
|
|
||||||
4. Record the candidate commit, module path, full tag, validation outcome, and
|
|
||||||
confirmed source outcome here. A successful tag push completes this source
|
|
||||||
release; move to dependent preparation without waiting for hosted pages.
|
|
||||||
|
|
||||||
**Stage result:** core v0.3.0 is source-published with
|
|
||||||
`module go.maximumdirect.net/commandkit`. Actual download of this version and its
|
|
||||||
sums is part of Stage 3, not a new completion gate for core publication.
|
|
||||||
|
|
||||||
## Stage 3: Migrate ckconfig and prepare its independent candidate
|
|
||||||
|
|
||||||
**Completed.** Ckconfig declares `go.maximumdirect.net/ckconfig`, imports the
|
|
||||||
new core identity, and downloaded `go.maximumdirect.net/commandkit v0.3.0`
|
|
||||||
with authentic sums. The resolved graph retains ConfigKit v0.8.0 and selects
|
|
||||||
both the older ReleaseKit v0.4.1 and vanity ReleaseKit v0.9.0 tool modules;
|
|
||||||
module-local attribution and current guidance reflect those selections. The
|
|
||||||
v0.2.0 release note is prepared; independent suite validation follows.
|
|
||||||
|
|
||||||
1. In `integrations/ckconfig`, migrate the module declaration to
|
|
||||||
`go.maximumdirect.net/ckconfig`. Update all owned imports, tests, and the
|
|
||||||
maintained simple example to that self-path and the new core path. Keep
|
|
||||||
package names and existing adapter behavior.
|
|
||||||
2. Replace its old core dependency key with the published new-path version.
|
|
||||||
From the ckconfig module directory, use:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
GOWORK=off GOTOOLCHAIN=local go mod edit -module=go.maximumdirect.net/ckconfig -droprequire=gitea.maximumdirect.net/eric/CommandKit -require=go.maximumdirect.net/commandkit@v0.3.0
|
|
||||||
GOWORK=off GOTOOLCHAIN=local go mod download go.maximumdirect.net/commandkit@v0.3.0
|
|
||||||
GOWORK=off GOTOOLCHAIN=local go mod tidy
|
|
||||||
```
|
|
||||||
|
|
||||||
Perform source import migration before tidy to avoid resolving old imports.
|
|
||||||
Keep real downloaded sums. If retrieval is unavailable, resolve dependency
|
|
||||||
preparation before proceeding; do not fabricate metadata or substitute a
|
|
||||||
local replacement as final release evidence.
|
|
||||||
3. Inspect the actual direct and indirect graph, including tool requirements.
|
|
||||||
Preserve ConfigKit v0.8.0 and unrelated versions. Update affected notices in
|
|
||||||
`integrations/ckconfig/docs/oss/attribution.md` under the OSS policy using the
|
|
||||||
actual selected source revisions; add/retain applicable license texts. Do
|
|
||||||
not assume similarly named old/new upstream modules are interchangeable.
|
|
||||||
4. Prepare `integrations/ckconfig/docs/releases/v0.2.0.md` with product
|
|
||||||
`CommandKit ckconfig`, the new module/core paths, compatible dependency set,
|
|
||||||
and relevant reporting/completion migration. Immutable footer/source URLs
|
|
||||||
use the full tag `integrations/ckconfig/v0.2.0` and correct physical files.
|
|
||||||
5. Update README's ckconfig row, consumer module/import examples, the simple
|
|
||||||
example guidance, affected GoDoc, and relevant current release/development
|
|
||||||
references. Explain that applications moving to the new core identity also
|
|
||||||
use the matched new integration identity.
|
|
||||||
6. Format changed Go files. Review for stale owned imports/direct requirement
|
|
||||||
keys, accidental replacements/workspace files, and unexplained graph churn.
|
|
||||||
Check current links and whitespace. The owning complete suite runs in
|
|
||||||
Stage 4; a local workspace pass is not a substitute.
|
|
||||||
|
|
||||||
**Stage result:** a ckconfig v0.2.0 candidate whose actual dependency is
|
|
||||||
downloaded `go.maximumdirect.net/commandkit v0.3.0`, with authentic metadata and
|
|
||||||
aligned current documentation/attribution.
|
|
||||||
|
|
||||||
## Stage 4: Validate and publish ckconfig v0.2.0
|
|
||||||
|
|
||||||
**Status:** not started.
|
|
||||||
|
|
||||||
Review and commit the complete ckconfig candidate. From the repository root,
|
|
||||||
use the same authoritative-branch protocol as Stage 2:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git push origin HEAD:refs/heads/main
|
|
||||||
./scripts/release ckconfig v0.2.0
|
|
||||||
```
|
|
||||||
|
|
||||||
The normal release command must pass the independent ckconfig suite, including
|
|
||||||
its maintained example, with workspace discovery off and without dependency
|
|
||||||
redirection. It must also pass selected committed-file checks and publication
|
|
||||||
guards. Do not insert the earlier temporary Go shim or weaken a selected check.
|
|
||||||
Apply the existing failed/ambiguous-publication procedure if needed.
|
|
||||||
|
|
||||||
Record the candidate, path, version, full tag, validation, and source outcome.
|
|
||||||
The intended tag is `integrations/ckconfig/v0.2.0`; the physical directory remains
|
|
||||||
`integrations/ckconfig` despite the short vanity module path.
|
|
||||||
|
|
||||||
**Stage result:** compatible ckconfig v0.2.0 is source-published under its vanity
|
|
||||||
identity. Downloading it for ckprompt is the next module's preparation.
|
|
||||||
|
|
||||||
## Stage 5: Migrate ckprompt and prepare its independent candidate
|
|
||||||
|
|
||||||
**Status:** not started.
|
|
||||||
|
|
||||||
1. Migrate `integrations/ckprompt` to `go.maximumdirect.net/ckprompt`. Update its
|
|
||||||
owned source/tests and composed example to import the new core, ckconfig,
|
|
||||||
and ckprompt paths. Preserve PromptKit adaptation and reporting behavior.
|
|
||||||
2. From that module directory, replace both old CommandKit dependency keys:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
GOWORK=off GOTOOLCHAIN=local go mod edit -module=go.maximumdirect.net/ckprompt -droprequire=gitea.maximumdirect.net/eric/CommandKit -droprequire=gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig -require=go.maximumdirect.net/commandkit@v0.3.0 -require=go.maximumdirect.net/ckconfig@v0.2.0
|
|
||||||
GOWORK=off GOTOOLCHAIN=local go mod download go.maximumdirect.net/commandkit@v0.3.0 go.maximumdirect.net/ckconfig@v0.2.0
|
|
||||||
GOWORK=off GOTOOLCHAIN=local go mod tidy
|
|
||||||
```
|
|
||||||
|
|
||||||
Migrate imports before tidy. Retain actual downloaded sums; resolve fetch
|
|
||||||
failures as preparation rather than masking them with local source. A new
|
|
||||||
core with old ckconfig v0.1.0 is the known incompatible combination.
|
|
||||||
3. Review graph changes while retaining ConfigKit v0.8.0 and PromptKit v0.16.0.
|
|
||||||
Update affected module-local attribution and immutable notice links based on
|
|
||||||
the resolved graph, including transitive tools. Keep actual upstream module
|
|
||||||
identities distinct from the three CommandKit identities being migrated.
|
|
||||||
4. Prepare `integrations/ckprompt/docs/releases/v0.2.0.md` with product
|
|
||||||
`CommandKit ckprompt`, new imports/dependencies, and consumer migration.
|
|
||||||
Footer/source links use full tag `integrations/ckprompt/v0.2.0` and physical
|
|
||||||
module-local files. Preserve the published v0.1.0 record.
|
|
||||||
5. Update README's ckprompt row, consumer composition/import examples, composed
|
|
||||||
example guidance, affected GoDoc, and remaining current module descriptions.
|
|
||||||
Keep URLs to hosted repository files separate from Go package links.
|
|
||||||
6. Format changed Go files and review remaining owned old-path imports or direct
|
|
||||||
requirement keys, metadata, links, and whitespace. Keep the ordinary source
|
|
||||||
checks intact; the independent suite runs in Stage 6.
|
|
||||||
|
|
||||||
**Stage result:** ckprompt v0.2.0 composes the real new-path core and ckconfig
|
|
||||||
versions in its declared graph, with current guidance and authentic metadata.
|
|
||||||
|
|
||||||
## Stage 6: Validate and publish ckprompt v0.2.0
|
|
||||||
|
|
||||||
**Status:** not started.
|
|
||||||
|
|
||||||
Review and commit the complete ckprompt candidate. From the repository root:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git push origin HEAD:refs/heads/main
|
|
||||||
./scripts/release ckprompt v0.2.0
|
|
||||||
```
|
|
||||||
|
|
||||||
The normal publication workflow must pass the independent ckprompt suite and
|
|
||||||
composed consumer with actual downloaded predecessors, plus selected file and
|
|
||||||
publication checks. Preserve the offline/read-only suite environment and
|
|
||||||
ordinary recovery handling. No workspace or replacement shim supplies final
|
|
||||||
release evidence.
|
|
||||||
|
|
||||||
Record its candidate, module identity, full tag
|
|
||||||
`integrations/ckprompt/v0.2.0`, suite outcome, and source-publication outcome.
|
|
||||||
Report any separate hosted delivery under its own outcome; page publication
|
|
||||||
is not required to establish dependency alignment.
|
|
||||||
|
|
||||||
**Stage result:** all three matched source releases are published with vanity
|
|
||||||
module declarations and verified independent dependency graphs.
|
|
||||||
|
|
||||||
## Stage 7: Audit the completed migration and record evidence
|
|
||||||
|
|
||||||
**Status:** not started.
|
|
||||||
|
|
||||||
1. Review the cumulative diff against the feature roadmap. Confirm all three
|
|
||||||
module declarations, owned imports, examples, direct dependency keys, and
|
|
||||||
component build identity use the new paths. Preserve physical directories,
|
|
||||||
tag prefixes, root ReleaseKit selection, scripts/profiles, exported shapes,
|
|
||||||
Go minimums, and upstream versions apart from explained graph consequences.
|
|
||||||
2. Check that tests and current guidance use the new identities while historical
|
|
||||||
notes, accepted ADRs, and immutable source URLs retain their historical
|
|
||||||
meaning. Resolve current dependency-readiness claims that are now stale.
|
|
||||||
Do not mechanically rewrite every old-path reference in completed records.
|
|
||||||
3. Record each final candidate's exact commit, full tag, suite result, and
|
|
||||||
publication outcome. Identify diagnostic-only earlier evidence separately.
|
|
||||||
Reuse each successful publication suite for its unchanged candidate; do not
|
|
||||||
require another complete run just to finish this stage. Any later code or
|
|
||||||
metadata correction belongs in a new candidate/version under release policy.
|
|
||||||
4. Mark stages complete only with their stated evidence and update the feature
|
|
||||||
roadmap's status/link here. Preserve this record and prior immutable plans;
|
|
||||||
apply normal roadmap retirement only during later preparation. If publication
|
|
||||||
was outside the authorized implementation scope or could not finish, record
|
|
||||||
the actual prepared state and pending release stages rather than claiming
|
|
||||||
alignment is complete.
|
|
||||||
5. Review new evidence prose, links/fragments, intended staged files, and
|
|
||||||
`git diff --check` / `git diff --cached --check`. Commit any remaining
|
|
||||||
nonempty documentation unit with a short plain-English message, following
|
|
||||||
the local commit policy. Finish with a clean tracked worktree when only
|
|
||||||
planned work is present; preserve unrelated and ignored local files.
|
|
||||||
|
|
||||||
**Stage result:** the implemented and published matched version set has accurate
|
|
||||||
source/validation evidence, current migration guidance, and committed tracking.
|
|
||||||
Source release and hosted-delivery outcomes remain separate.
|
|
||||||
|
|
||||||
## Open Questions
|
|
||||||
|
|
||||||
None required to choose the implementation. Vanity paths, target versions,
|
|
||||||
physical layout, dependency order, validation ownership, and compatibility scope
|
|
||||||
are selected in the roadmap. Publication authorization is an execution-scope
|
|
||||||
constraint, not a reason to invent different versions, fabricated sums, or a
|
|
||||||
local-only substitute for the target end state.
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
# Integration dependency alignment and vanity-path migration
|
|
||||||
|
|
||||||
Status: proposed release-preparation roadmap. This pass adds documentation only;
|
|
||||||
dependency changes and publication remain future work. The
|
|
||||||
[implementation plan](implementation.md) owns execution stages, concrete tasks,
|
|
||||||
and validation tracking; this roadmap owns the target and selected scope.
|
|
||||||
|
|
||||||
## Purpose and authority
|
|
||||||
|
|
||||||
Align the independently released integrations with the core APIs their current
|
|
||||||
source already uses, and migrate all three CommandKit modules to the supplied
|
|
||||||
vanity paths. Publish compatible module versions in dependency order so each
|
|
||||||
integration builds and validates against its declared, downloaded dependencies
|
|
||||||
with workspace discovery off.
|
|
||||||
|
|
||||||
The [release procedure](../release.md) owns publication commands and release
|
|
||||||
order. The [release policy](../policy/release.md),
|
|
||||||
[agent policy](../policy/agents.md), [testing policy](../policy/testing.md),
|
|
||||||
[documentation policy](../policy/documentation.md), and
|
|
||||||
[OSS policy](../policy/oss.md) govern the work. This roadmap selects the target
|
|
||||||
and release-preparation scope; it does not change those policies.
|
|
||||||
|
|
||||||
## Baseline and investigation evidence
|
|
||||||
|
|
||||||
Reviewed baseline: `289a171e97699ad9aa57ee2cc40bdad1c0b680a9`.
|
|
||||||
Vanity-path review baseline: `d7cbaed3ed18bc2909c8144f308e2dfd58ade7ec`.
|
|
||||||
Module declarations and library source were unchanged between these revisions.
|
|
||||||
|
|
||||||
- Both integration module declarations require core v0.2.0. The
|
|
||||||
[ckprompt declaration](../../integrations/ckprompt/go.mod) also requires
|
|
||||||
ckconfig v0.1.0; the [ckconfig declaration](../../integrations/ckconfig/go.mod)
|
|
||||||
has no dependency on ckprompt.
|
|
||||||
- Current integration source uses newer core APIs including `CompletionHint`,
|
|
||||||
`Explanation`, and `Reporter`. Both independent Go 1.26.8 suites fail to
|
|
||||||
compile with `GOWORK=off` and their existing read-only module graphs.
|
|
||||||
- Updating core alone is insufficient for ckprompt: published ckconfig v0.1.0
|
|
||||||
still uses removed core APIs, including `Invocation.Streams`,
|
|
||||||
`Outcome.Diagnostics`, and `SeverityError`, plus the old `Failure(error)`
|
|
||||||
call shape.
|
|
||||||
- The authoritative `origin` tag listing contains core v0.1.0 and v0.2.0, and
|
|
||||||
the two integration v0.1.0 tags. The proposed next versions below were unused
|
|
||||||
at review. Remote `main` was `230187296fae5253cb1773f16c2f1d1a39499ed0`;
|
|
||||||
the reviewed local changes still need normal publication to the authoritative
|
|
||||||
branch as part of candidate preparation.
|
|
||||||
- A checked-in [core v0.3.0 draft](../releases/v0.3.0.md) already describes the
|
|
||||||
reporting and alias migration. It is an unpublished draft, not proof that
|
|
||||||
the module version can be downloaded.
|
|
||||||
|
|
||||||
The investigation used disposable alternate module files, Go 1.26.8,
|
|
||||||
`GOWORK=off`, and read-only offline tests. Only temporary dependency selections
|
|
||||||
changed; the real module declarations, sums, and source remained unchanged.
|
|
||||||
|
|
||||||
| Current source under test | Temporary dependency selection | Result |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| ckconfig | Current core source | Module suite and maintained example passed. |
|
|
||||||
| ckprompt | Current core source, published ckconfig v0.1.0 | Compilation failed in the old ckconfig implementation. |
|
|
||||||
| ckprompt | Current core and current ckconfig source | Module suite and maintained example passed. |
|
|
||||||
|
|
||||||
The successful cases retained ConfigKit v0.8.0 and PromptKit v0.16.0. These
|
|
||||||
results isolate the CommandKit dependency alignment needed here; they do not
|
|
||||||
prove that future published versions or their downloaded sums already exist.
|
|
||||||
|
|
||||||
### Verified vanity discovery
|
|
||||||
|
|
||||||
The core endpoint at `https://go.maximumdirect.net/commandkit?go-get=1` serves
|
|
||||||
the mapping to `https://forge.maximumdirect.net/base-layer/commandkit`. Go direct
|
|
||||||
discovery finds the existing core v0.1.0 and v0.2.0 tags. Fetching v0.2.0 through
|
|
||||||
the vanity path reaches its source but reports a module-path mismatch because
|
|
||||||
that release declares `gitea.maximumdirect.net/eric/CommandKit`.
|
|
||||||
|
|
||||||
Both integration endpoints now return HTTP 200 with these `go-import` contents:
|
|
||||||
|
|
||||||
| Vanity path | VCS | Repository URL | Subdirectory field |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `go.maximumdirect.net/ckconfig` | `git` | `https://forge.maximumdirect.net/base-layer/commandkit` | `integrations/ckconfig` |
|
|
||||||
| `go.maximumdirect.net/ckprompt` | `git` | `https://forge.maximumdirect.net/base-layer/commandkit` | `integrations/ckprompt` |
|
|
||||||
|
|
||||||
Go 1.26.8 direct discovery finds each integration's v0.1.0 tag. Disposable
|
|
||||||
consumer fetches reach the correct nested `go.mod` and report its old declared
|
|
||||||
module path, confirming subdirectory routing. Discovery is working; the
|
|
||||||
existing tags have not migrated. The optional fourth metadata field is
|
|
||||||
supported from Go 1.25, within the existing Go 1.26.0 consumer minimum; see the
|
|
||||||
[Go discovery reference](https://go.dev/ref/mod#vcs-find).
|
|
||||||
|
|
||||||
## Targeted end state
|
|
||||||
|
|
||||||
### Compatible independently released modules
|
|
||||||
|
|
||||||
Use the following proposed next versions, subject to the existing fresh-version
|
|
||||||
publication guards:
|
|
||||||
|
|
||||||
| Module path | Physical module directory | Next release | Required CommandKit dependencies | Full tag |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| `go.maximumdirect.net/commandkit` | `.` | v0.3.0 | None | `v0.3.0` |
|
|
||||||
| `go.maximumdirect.net/ckconfig` | `integrations/ckconfig` | v0.2.0 | `go.maximumdirect.net/commandkit v0.3.0` | `integrations/ckconfig/v0.2.0` |
|
|
||||||
| `go.maximumdirect.net/ckprompt` | `integrations/ckprompt` | v0.2.0 | `go.maximumdirect.net/commandkit v0.3.0` and `go.maximumdirect.net/ckconfig v0.2.0` | `integrations/ckprompt/v0.2.0` |
|
|
||||||
|
|
||||||
Minor integration releases fit the existing pre-1.0 compatibility policy: the
|
|
||||||
reporting migration changes consumer-facing behavior and adopts a core version
|
|
||||||
with incompatible API changes. The vanity migration also deliberately changes
|
|
||||||
Go module and import identities. Migration notes explain the new imports and
|
|
||||||
dependency set, provider results, invocation reporting, and application changes.
|
|
||||||
|
|
||||||
The three modules retain independent versions and source tags. Their candidates
|
|
||||||
may identify successive commits: core publication need not wait for integration
|
|
||||||
metadata that depends on that newly published core. Each selected module's
|
|
||||||
final release suite runs against its actual declared dependencies.
|
|
||||||
|
|
||||||
### Module and import identity
|
|
||||||
|
|
||||||
Change each module declaration and all CommandKit-owned imports to the matching
|
|
||||||
new path. Core self-imports, including its `internal` packages, use
|
|
||||||
`go.maximumdirect.net/commandkit/...`; integration self-imports use
|
|
||||||
`go.maximumdirect.net/ckconfig/...` or `go.maximumdirect.net/ckprompt/...`.
|
|
||||||
Cross-module imports and requirements use the complete new paths in the table,
|
|
||||||
including ckprompt's ckconfig dependency. Core component-version discovery uses
|
|
||||||
`go.maximumdirect.net/commandkit` as its build-info identity, retaining the
|
|
||||||
existing `version --scope commandkit` behavior with the new module path.
|
|
||||||
|
|
||||||
Update production files, tests, maintained examples, and any import-path-based
|
|
||||||
test expectations together. A declared vanity module that still imports the
|
|
||||||
old core path would select a different Go package identity and can violate
|
|
||||||
`internal` import rules. The matched new releases compose through one core
|
|
||||||
identity rather than mixing old-path and new-path CommandKit types.
|
|
||||||
|
|
||||||
Keep physical directories, repository URLs, and Git tag prefixes as shown. The
|
|
||||||
Go subdirectory metadata makes the short integration vanity paths resolve to
|
|
||||||
the existing layout. The existing release profiles select physical directories;
|
|
||||||
the migration does not rename those directories or flatten integration tags.
|
|
||||||
|
|
||||||
Published old-path versions remain immutable. This scope selects the new paths
|
|
||||||
for new releases and updates consumer guidance; it makes no new promise of
|
|
||||||
type interoperability between the two identities and adds no old-path forwarding
|
|
||||||
module or compatibility layer.
|
|
||||||
|
|
||||||
### Retained architecture and scope
|
|
||||||
|
|
||||||
Preserve exported declaration shapes and runtime behavior while deliberately
|
|
||||||
changing module/import identities. Retain the integration adapters, Go 1.26.0
|
|
||||||
consumer minimum, Go 1.26.8 maintainer toolchain, and root-selected ReleaseKit
|
|
||||||
v0.9.0. The earlier successful diagnostic suites establish the dependency fix
|
|
||||||
before renaming; the migrated source still needs its own validation. This work
|
|
||||||
selects no API rollback or shim for old reporting APIs.
|
|
||||||
|
|
||||||
Retain ConfigKit v0.8.0, PromptKit v0.16.0, and other dependency selections
|
|
||||||
unless ordinary tidy changes the resolved graph as a consequence of the
|
|
||||||
CommandKit updates. Inspect and explain the resulting graph rather than
|
|
||||||
bundling unrelated upgrades. In particular, transitive tools with different
|
|
||||||
module paths may coexist; attribution must reflect the actual selection.
|
|
||||||
|
|
||||||
Preserve the existing launchers, three release profiles, generic validators,
|
|
||||||
credential handling, and separate source-publication and hosted-delivery
|
|
||||||
outcomes. Development workspaces remain useful and ignored. Diagnostic local
|
|
||||||
replacements and the earlier temporary Go shim remain development evidence;
|
|
||||||
release validation uses normal downloaded dependencies without that redirection.
|
|
||||||
|
|
||||||
## Release-preparation deliverables
|
|
||||||
|
|
||||||
The core v0.3.0 draft describes the complete candidate, including completion,
|
|
||||||
reporting, aliases, tool maintenance, and the vanity-path migration. New
|
|
||||||
integration notes at `integrations/ckconfig/docs/releases/v0.2.0.md` and
|
|
||||||
`integrations/ckprompt/docs/releases/v0.2.0.md` explain the matched dependency set
|
|
||||||
and consumer migration. Their source and licensing links follow the current
|
|
||||||
release procedure; published notes and tags remain immutable.
|
|
||||||
|
|
||||||
Current installation examples, README module selections, consumer/developer
|
|
||||||
guidance, affected GoDoc, and maintained examples use the implemented new
|
|
||||||
identities. Import-path-aware tests retain their existing boundary assertions.
|
|
||||||
Source-hosting and license URLs remain repository links, distinct from Go
|
|
||||||
import paths. Module-local attribution describes each actual resolved graph.
|
|
||||||
|
|
||||||
The final record identifies module paths, versions, candidate revisions,
|
|
||||||
validation evidence, and independent source-publication outcomes. Current
|
|
||||||
readiness guidance reflects the aligned state; historical failures remain in
|
|
||||||
completed investigation records. The implementation plan owns the ordered
|
|
||||||
migration, dependency preparation, release, and evidence-recording steps.
|
|
||||||
|
|
||||||
## Validation and completion boundaries
|
|
||||||
|
|
||||||
Review current CommandKit-owned source and dependency selections for stale
|
|
||||||
self-imports or old direct dependency keys. Historical notes, source URLs, and
|
|
||||||
unrelated upstream module identities are outside that mechanical rename.
|
|
||||||
Confirm release identity still pairs each new module path with its existing
|
|
||||||
physical directory and tag prefix. The verified redirects are preparation
|
|
||||||
evidence; publishing the renamed modules is needed for real consumers to use
|
|
||||||
them through those paths.
|
|
||||||
|
|
||||||
Use the selected module's ordinary deterministic offline suite with
|
|
||||||
`GOWORK=off` and read-only metadata after dependency preparation. Its maintained
|
|
||||||
consumer compiles and runs with that suite. ReleaseKit's publication command
|
|
||||||
owns the final candidate suite and selected file checks; validation-only checks
|
|
||||||
remain optional diagnostics. Reuse successful evidence for unchanged candidates
|
|
||||||
instead of adding a required check-then-publish repetition.
|
|
||||||
|
|
||||||
Retrieving a newly published dependency is preparation for the next module's
|
|
||||||
release. It does not turn proxy availability or consumer installation into a
|
|
||||||
completion gate for the preceding source release. Continue to resolve failed
|
|
||||||
or ambiguous publication using the existing policy and upstream recovery flow.
|
|
||||||
Hosted Gitea delivery keeps its separate outcome; this roadmap adds no CI
|
|
||||||
polling, live provider calls, or additional publication gate.
|
|
||||||
|
|
||||||
Alignment is complete when the matched source versions are published under all
|
|
||||||
three vanity module paths, owned imports and examples use the new identities,
|
|
||||||
each integration declares the compatible vanity-path versions with authentic
|
|
||||||
downloaded sums, each final selected-module suite passes without workspace or
|
|
||||||
replacement redirection, and current documentation and attribution agree with
|
|
||||||
that graph. Temporary local-source success alone does not establish that end
|
|
||||||
state.
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
# Release tooling simplification
|
|
||||||
|
|
||||||
Status: the selected release-tooling design has been implemented. All four
|
|
||||||
generic file checks, registered-tool execution, page-only hosted delivery, and
|
|
||||||
protection of the supplied token path are selected.
|
|
||||||
The [completed implementation record](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/87eb84ccb462bf54e6250c8b287ac217efe90883/docs/roadmap/implementation.md)
|
|
||||||
contains stage order, tasks, validation, and completion evidence. Current release
|
|
||||||
behavior stays with its canonical owners.
|
|
||||||
|
|
||||||
## Purpose and authority
|
|
||||||
|
|
||||||
Reduce CommandKit's release infrastructure to declarative module profiles,
|
|
||||||
a small launcher, and focused tests of CommandKit-owned wiring. Delegate
|
|
||||||
reusable candidate validation and publication mechanics to ReleaseKit while
|
|
||||||
retaining CommandKit's domain-specific checks in their existing owners. Add
|
|
||||||
hosted Gitea release pages as a separate local delivery operation after source
|
|
||||||
publication.
|
|
||||||
|
|
||||||
The [agent policy](../policy/agents.md),
|
|
||||||
[release policy](../policy/release.md#candidate-validation), and
|
|
||||||
[testing policy](../policy/testing.md#upstream-integration-testing-ownership)
|
|
||||||
govern implementation. The [release procedure](../release.md) continues to own
|
|
||||||
the current workflow.
|
|
||||||
|
|
||||||
## Targeted end state
|
|
||||||
|
|
||||||
### Ownership
|
|
||||||
|
|
||||||
CommandKit retains module selectors, product identities, profile locations,
|
|
||||||
the authoritative endpoint selection, release order, release-note meaning,
|
|
||||||
compatibility decisions, and attribution accuracy. Its existing public API,
|
|
||||||
CLI, integration-adaptation, and consumer-example tests remain local and run
|
|
||||||
through the owning module's suite. No parallel release-only domain suite is
|
|
||||||
needed unless a concrete CommandKit requirement is otherwise unprotected.
|
|
||||||
|
|
||||||
ReleaseKit supplies the standard offline candidate suite, selected generic file
|
|
||||||
checks, candidate/note and publication guards, tag creation and publication,
|
|
||||||
hosted delivery, outcome reporting, and recovery. CommandKit's launcher delegates
|
|
||||||
those operations. Existing source-release completion and immutability rules
|
|
||||||
continue to apply. Hosted pages are the added delivery channel; binary
|
|
||||||
deliverables and platform support commitments remain unchanged.
|
|
||||||
|
|
||||||
### Profiles
|
|
||||||
|
|
||||||
Select these existing ReleaseKit options in each profile:
|
|
||||||
|
|
||||||
| Selection | Intended protection |
|
|
||||||
| --- | --- |
|
|
||||||
| `validation.go_format: true` | Detect unformatted committed Go source. |
|
|
||||||
| `validation.markdown: {}` | Detect broken local Markdown destinations and supported heading fragments. |
|
|
||||||
| `validation.module_distribution.workspace_files: true` | Detect committed development workspace files in selected inputs. |
|
|
||||||
| `validation.module_distribution.local_replacements: true` | Detect filesystem replacements in selected committed module declarations. |
|
|
||||||
|
|
||||||
Also select
|
|
||||||
`validation.forbidden_files: [".releasekit/gitea-token"]` in all three profiles.
|
|
||||||
This delegates protection of the supplied credential path to ReleaseKit's
|
|
||||||
existing check. The path is repository-relative and the check applies across
|
|
||||||
the captured repository even for an integration release. It does not read token
|
|
||||||
contents, scan other paths, or inspect Git history.
|
|
||||||
|
|
||||||
Retain the explicit shared-file lists and use ReleaseKit's existing input scope.
|
|
||||||
The root profile does not run every nested module's suite. File checks inspect
|
|
||||||
committed inputs and do not replace formatting worktree changes or reviewing
|
|
||||||
documentation meaning, attribution, and external links. Markdown keeps its
|
|
||||||
default treatment of outside-checkout destinations; no stricter boundary mode
|
|
||||||
is proposed.
|
|
||||||
|
|
||||||
The pinned [ReleaseKit configuration reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/23203f235cc414c4ffe0fd3941030eb0c9f9943f/docs/config.md)
|
|
||||||
owns exact scope and behavior, including nested-module boundaries and vendored
|
|
||||||
inputs. Do not expand an option's scope into a general repository prohibition.
|
|
||||||
Race testing, full vet, compilation matrices, size limits, and additional
|
|
||||||
forbidden-file paths are not selected by this roadmap. They can be considered
|
|
||||||
separately for demonstrated needs.
|
|
||||||
|
|
||||||
### Launcher and recovery
|
|
||||||
|
|
||||||
Use the root module's registered `go tool releasekit` through `exec`, keeping
|
|
||||||
the current selector interface and publication argument mapping.
|
|
||||||
Retain host normalization, workspace-off execution, the local toolchain, and
|
|
||||||
read-only module metadata. Preserve other effective Go settings while arranging
|
|
||||||
read-only selection.
|
|
||||||
The implementation plan specifies the wrapper interface and invocation details.
|
|
||||||
|
|
||||||
Go's cache supplies executable storage; the launcher creates no persistent
|
|
||||||
binary directory. `/.releasekit/` remains ignored for the credential file, with
|
|
||||||
an explanatory comment. Recovery instructions use the registered tool or the
|
|
||||||
entry point printed for the saved attempt, preserving ReleaseKit's distinction
|
|
||||||
between publication outcome and record-storage errors.
|
|
||||||
|
|
||||||
Share module selection and host-safe tool invocation between publication,
|
|
||||||
delivery, and recovery where applicable. Delivery selects the same module
|
|
||||||
profile as publication; recovery uses its recorded attempt rather than inferring
|
|
||||||
identity from a current profile. Keep the existing publication interface and
|
|
||||||
provide an explicit delivery invocation without automatically chaining the two
|
|
||||||
operations. Keep one selector mapping and shared invocation plumbing.
|
|
||||||
|
|
||||||
ReleaseKit v0.9.0 shipped host-safe consumer launcher examples and regression
|
|
||||||
coverage. The earlier simplification used v0.8.0, which already supported
|
|
||||||
registered tools. Keep host normalization locally because the reviewed
|
|
||||||
`go tool` invocation inherited foreign `GOOS`/`GOARCH` values and failed to run.
|
|
||||||
Do not switch tool-version selection from the root module to each integration
|
|
||||||
merely to match the upstream multi-module example.
|
|
||||||
|
|
||||||
### Hosted Gitea release pages
|
|
||||||
|
|
||||||
Configure this delivery selection in each module profile:
|
|
||||||
|
|
||||||
| Field | Selected value |
|
|
||||||
| --- | --- |
|
|
||||||
| `delivery.forge` | `gitea` |
|
|
||||||
| `delivery.base_url` | `https://forge.maximumdirect.net` |
|
|
||||||
| `delivery.owner` | `base-layer` |
|
|
||||||
| `delivery.repository` | `commandkit` |
|
|
||||||
| `delivery.token_file` | `.releasekit/gitea-token` |
|
|
||||||
|
|
||||||
Preserve the profiles' distinct product identities and physical module
|
|
||||||
directories. All pages belong to the same Gitea repository and are keyed by
|
|
||||||
the complete tag: `vX.Y.Z` for core, `integrations/ckconfig/vX.Y.Z` for ckconfig,
|
|
||||||
and `integrations/ckprompt/vX.Y.Z` for ckprompt. Pass the selected profile and
|
|
||||||
semantic version to `deliver`; ReleaseKit derives the complete module tag.
|
|
||||||
|
|
||||||
With no build targets, delivery is page-only. ReleaseKit uses the complete
|
|
||||||
checked-in module release note, including its licensing footer, as the hosted
|
|
||||||
body. No binary assets, receipts, or checksum manifests are added. Use current
|
|
||||||
forge URLs and the full module tag for future notes' immutable source and
|
|
||||||
licensing links. Existing published tags and notes remain unchanged.
|
|
||||||
|
|
||||||
After source publication succeeds, explicitly invoke delivery from a clean
|
|
||||||
checkout whose `HEAD` identifies that published tag's commit. For later retries,
|
|
||||||
use the original tagged source and its recorded module files. Report the source
|
|
||||||
publication outcome and hosted-delivery outcome separately, including the hosted
|
|
||||||
URL on success. A delivery failure leaves the source release complete; repair
|
|
||||||
delivery without republishing or moving its tag.
|
|
||||||
|
|
||||||
Delivery performs its own read-only credential preflight, without rerunning
|
|
||||||
candidate validation or publishing a tag. Hosted-service availability and the
|
|
||||||
Gitea token do not become source-publication gates. A nonblank
|
|
||||||
`RELEASEKIT_GITEA_TOKEN` environment value takes precedence over the configured
|
|
||||||
file. The file path resolves from the repository root for all three modules.
|
|
||||||
|
|
||||||
ReleaseKit accepts matching hosted content and reports conflicting content
|
|
||||||
without overwriting it. Resolve uncertain hosted writes before retrying the
|
|
||||||
same immutable version. The pinned
|
|
||||||
[delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/23203f235cc414c4ffe0fd3941030eb0c9f9943f/docs/consumers/delivery.md)
|
|
||||||
owns exact delivery behavior and recovery. Start with tags containing the new
|
|
||||||
delivery configuration; historical page backfilling remains a separate decision.
|
|
||||||
This local workflow needs no CI delivery job or additional secret distribution.
|
|
||||||
|
|
||||||
### Focused local tests
|
|
||||||
|
|
||||||
Replace the release-test scaffolding with a small controlled Go-command boundary
|
|
||||||
that invokes the actual launcher. Cover:
|
|
||||||
|
|
||||||
- Selector-to-profile/module routing for core, ckconfig, and ckprompt, including
|
|
||||||
consistency with the checked-in profiles' intended module and product.
|
|
||||||
- Invalid argument handling before tool invocation.
|
|
||||||
- Invocation from another directory and paths containing spaces.
|
|
||||||
- Host normalization and workspace/toolchain/read-only settings.
|
|
||||||
- Publication and delivery argument, output-stream, and child exit-status
|
|
||||||
forwarding, with the selected module profile reaching the delivery operation.
|
|
||||||
- Profile wiring for the shared Gitea destination, token path, and its selected
|
|
||||||
committed-path protection; assertions do not read the credential file.
|
|
||||||
|
|
||||||
Exercise module routing separately from exit statuses rather than multiplying
|
|
||||||
every combination. Assert behavior and meaningful selections, not helper
|
|
||||||
implementation details or exact usage prose.
|
|
||||||
|
|
||||||
The resulting local suite omits the disposable publication exercise, generic
|
|
||||||
tag inspection, assertion-helper self-tests, and custom build-call log/parser.
|
|
||||||
Upstream publication and delivery coverage owns those generic behaviors. No
|
|
||||||
replacement publication engine or exported test-helper API is needed. There is
|
|
||||||
no line-count target for the replacement tests.
|
|
||||||
|
|
||||||
## Selected choices and rationale
|
|
||||||
|
|
||||||
All four generic file checks are selected as release-time checks, in addition
|
|
||||||
to the agreed forbidden token path. Formatting and local-link validation automate
|
|
||||||
existing contributor review work. Workspace-file and filesystem-replacement
|
|
||||||
checks address accidental inclusion of development metadata that a successful
|
|
||||||
local test run can overlook. This adds specific release checks; it does not
|
|
||||||
make every optional ReleaseKit validator mandatory or prohibit development
|
|
||||||
workspaces and replacements outside the selected committed candidate inputs.
|
|
||||||
Selecting only formatting and Markdown would change less release behavior, but
|
|
||||||
would leave these distribution mistakes to manual review. The selected upstream
|
|
||||||
checks avoid a second local implementation.
|
|
||||||
|
|
||||||
Host-normalized registered-tool execution is selected because the root module
|
|
||||||
already registers ReleaseKit and Go caches the executable. Retaining a persistent
|
|
||||||
native executable would provide a recovery entry point independent of a later
|
|
||||||
Go-driver invocation, but would retain executable-storage and bootstrap test
|
|
||||||
maintenance. Recovery instead uses the registered tool or ReleaseKit's reported
|
|
||||||
entry point. The credential directory remains ignored under either approach.
|
|
||||||
|
|
||||||
The implementation plan records the existing integration dependency-version
|
|
||||||
mismatch separately from validation of the current source. This infrastructure
|
|
||||||
sprint does not publish releases or select new library dependency versions.
|
|
||||||
Historical hosted-page backfilling and CI delivery remain separate future
|
|
||||||
choices, not prerequisites for the selected local page-only workflow.
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
# ReleaseKit v0.9.0 adoption
|
|
||||||
|
|
||||||
Status: R1 and R2 remediation, ReleaseKit v0.9.0 adoption, and the completion
|
|
||||||
assertion repair are complete. The [completed implementation record](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/c8d659dfe5ae3e834b3aeabdfd0fe29b736dc05a/docs/roadmap/implementation.md)
|
|
||||||
records stage order, tasks, and validation evidence. This document owns the
|
|
||||||
target and selected choices; it does not authorize source or hosted publication.
|
|
||||||
|
|
||||||
## Purpose and authority
|
|
||||||
|
|
||||||
Adopt ReleaseKit v0.9.0's improved recovery behavior while preserving
|
|
||||||
CommandKit's existing release-tooling architecture. Update current dependency
|
|
||||||
and maintainer documentation together, and make the validation evidence clear
|
|
||||||
about existing local defects.
|
|
||||||
|
|
||||||
The [agent policy](../policy/agents.md),
|
|
||||||
[release policy](../policy/release.md#candidate-validation),
|
|
||||||
[testing policy](../policy/testing.md#upstream-integration-testing-ownership),
|
|
||||||
and [documentation policy](../policy/documentation.md) govern the work. Current
|
|
||||||
behavior remains owned by the [release procedure](../release.md), Go declarations,
|
|
||||||
and owning package tests until implementation updates them.
|
|
||||||
|
|
||||||
## Current baseline and review evidence
|
|
||||||
|
|
||||||
Reviewed CommandKit code baseline: `4d92ee4ee6a8403b22a4172e0f04face802b9499`.
|
|
||||||
The original upgrade review used `98e7e9933353cf43f2be4a96cb0436a0bce068d2`;
|
|
||||||
its findings and validation history are retained below.
|
|
||||||
|
|
||||||
- The root [module](../../go.mod) selects
|
|
||||||
`go.maximumdirect.net/releasekit v0.8.0` as a Go tool. Its selected version
|
|
||||||
serves core, ckconfig, and ckprompt operations.
|
|
||||||
- The [shared helper](../../scripts/releasekit) already normalizes the Go host,
|
|
||||||
disables workspace discovery, selects the local toolchain, retains read-only
|
|
||||||
metadata, and invokes the full executable package path. The
|
|
||||||
[legacy entry point](../../scripts/release) delegates publication to it.
|
|
||||||
- All three profiles already select the agreed generic file checks, forbidden
|
|
||||||
token path, and page-only Gitea destination. Source publication and hosted
|
|
||||||
delivery are separate operations. The local token directory remains ignored.
|
|
||||||
- [R1 and R2](remediation.md) are complete. Commit `7eac3fe` rejects invalid
|
|
||||||
legacy selectors before invoking Go; commit `4d92ee4` restores explicit,
|
|
||||||
optional POSIX-shell invocation in launcher tests. The remediation record owns
|
|
||||||
their acceptance evidence, including passing focused tests, shell syntax
|
|
||||||
checks, and profile assertions running when no shell is available.
|
|
||||||
- Both integrations still require older published CommandKit dependencies than
|
|
||||||
their current source needs. The completed [release-tooling implementation record](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/87eb84ccb462bf54e6250c8b287ac217efe90883/docs/roadmap/implementation.md#stage-5-verify-the-final-source-and-record-validation-boundaries)
|
|
||||||
distinguishes workspace-backed tests from independent release readiness.
|
|
||||||
|
|
||||||
The upstream v0.9.0 tag identifies commit
|
|
||||||
`2180aa868ec2caa95fc8279fd59d5f0ebac41bd4`. The tag and direct Go-module
|
|
||||||
resolution were verified. The default proxy initially returned v0.8.0 for
|
|
||||||
`@latest`; select v0.9.0 explicitly rather than changing repository-wide proxy
|
|
||||||
settings to work around that observation.
|
|
||||||
|
|
||||||
Upstream [release notes](https://forge.maximumdirect.net/base-layer/releasekit/src/tag/v0.9.0/docs/releases/v0.9.0.md)
|
|
||||||
describe host-safe launchers and generated recovery commands, full package-path
|
|
||||||
tool selection, preservation of wildcard and version-specific replacements in
|
|
||||||
API-only recovery, and safer manual hosted-page retries. Public Go APIs,
|
|
||||||
profiles, record formats, and the Go 1.26.0 consumer minimum remain unchanged.
|
|
||||||
The v0.8.0-to-v0.9.0 comparison also left upstream module requirements, checksums,
|
|
||||||
copyright, and license texts unchanged.
|
|
||||||
|
|
||||||
A disposable CommandKit upgrade changed only the selected ReleaseKit version in
|
|
||||||
`go.mod`. With Go 1.26.8, the root suite passed on a subsequent run, both
|
|
||||||
workspace-backed integration suites passed, and the real helper reported v0.9.0
|
|
||||||
under foreign target settings. No production publication or delivery was run.
|
|
||||||
|
|
||||||
A later disposable review at `7eac3fe` confirmed that downloading and tidying
|
|
||||||
v0.9.0 changed only the ReleaseKit requirement and its checksum entries. The
|
|
||||||
offline root suite and both workspace-backed integration suites passed with
|
|
||||||
Go 1.26.8, and the helper reported v0.9.0 under Windows/ARM64 target settings.
|
|
||||||
That snapshot excluded the then-uncommitted R2 change; it does not replace
|
|
||||||
validation of the eventual adoption commit.
|
|
||||||
|
|
||||||
The initial upgrade run failed in
|
|
||||||
[`TestCompletionCommandContext`](../../completion_context_test.go). The same
|
|
||||||
alias-order failure reproduced four times in 30 focused repetitions on the
|
|
||||||
unchanged v0.8.0 baseline. A single passing rerun therefore does not establish
|
|
||||||
stable validation. The test compares an internal alias slice in a fixed order;
|
|
||||||
commit `0acbbf4` deliberately changed completion to use unsorted lookup records
|
|
||||||
before this upgrade review.
|
|
||||||
|
|
||||||
## Targeted end state
|
|
||||||
|
|
||||||
### Tool adoption and retained architecture
|
|
||||||
|
|
||||||
The root module selects ReleaseKit v0.9.0 with authentic downloaded checksums.
|
|
||||||
Its existing tool declaration and root-owned selection remain. No integration
|
|
||||||
dependency version, library import path, Go minimum, or selected Go 1.26.8
|
|
||||||
maintainer toolchain changes as part of adoption.
|
|
||||||
|
|
||||||
Keep host normalization and full-package invocation in the existing helper:
|
|
||||||
upgrading a dependency does not update or replace local shell scripts. Keep one
|
|
||||||
module/profile mapping and the established wrapper forms. Retain the selected
|
|
||||||
profiles, token-file handling, credential-directory ignore rule, and separation
|
|
||||||
of source and hosted outcomes. No new validator, binary target, CI workflow,
|
|
||||||
publication channel, credential preflight gate, or runtime API is needed.
|
|
||||||
|
|
||||||
The new generated Go recovery commands complement the helper's existing host
|
|
||||||
handling. Recovery continues to use saved publication evidence and the upstream
|
|
||||||
record formats; CommandKit does not acquire a parallel recovery implementation.
|
|
||||||
|
|
||||||
### Release-code simplification review
|
|
||||||
|
|
||||||
The v0.9.0 review identified no additional local release implementation to remove.
|
|
||||||
The earlier simplification already delegated generic validation, publication,
|
|
||||||
delivery, and recovery to ReleaseKit. This release improves launcher examples
|
|
||||||
and generated recovery commands without adding validation options that replace
|
|
||||||
the remaining CommandKit code.
|
|
||||||
|
|
||||||
Retain the shared helper's module/profile selection and execution environment.
|
|
||||||
Host normalization must happen before Go compiles and runs ReleaseKit. Retain
|
|
||||||
the legacy publication wrapper to preserve the established maintainer interface.
|
|
||||||
The upstream multi-module launcher example adds a module map and temporary
|
|
||||||
metadata preparation for a different tool-selection model; replacing our
|
|
||||||
root-owned registered-tool helper with it would add machinery.
|
|
||||||
|
|
||||||
Retain the focused [wiring tests](../../scripts/release_test.go) for profile
|
|
||||||
selections, argument forwarding, environment, streams, status, and optional-shell
|
|
||||||
handling. ReleaseKit owns validation and recovery semantics; CommandKit's tests
|
|
||||||
continue to cover its own adapter. The adoption work therefore preserves the
|
|
||||||
release-code structure while updating the dependency and documentation, alongside
|
|
||||||
the separately planned completion assertion repair.
|
|
||||||
|
|
||||||
### Current documentation and history
|
|
||||||
|
|
||||||
Current release procedure, project-specific release policy, consumer Go-tool
|
|
||||||
selection summary, and root attribution describe v0.9.0. Upstream contract and
|
|
||||||
notice links use the corresponding immutable source revision. Record that the
|
|
||||||
host-safe launcher request has shipped upstream instead of describing it as
|
|
||||||
pending in the earlier feature roadmap.
|
|
||||||
|
|
||||||
Continue linking to upstream recovery and delivery contracts from the maintainer
|
|
||||||
procedure. Use ReleaseKit's generated recovery commands and keep local guidance
|
|
||||||
focused on CommandKit's entry points and selections.
|
|
||||||
|
|
||||||
Preserve the baseline and validation history in completed implementation and
|
|
||||||
review records. Do not mechanically replace every historical v0.8.0 reference.
|
|
||||||
Integration attribution describes its own selected published dependency graph;
|
|
||||||
update it only if that actual selection changes. No license-text replacement
|
|
||||||
is needed for the unchanged upstream texts.
|
|
||||||
|
|
||||||
### Completed remediation and remaining correctness work
|
|
||||||
|
|
||||||
R1 and R2 were delivered before the dependency upgrade, with their completion
|
|
||||||
markers and acceptance evidence in [remediation.md](remediation.md). Preserve
|
|
||||||
their selector rejection, legitimate raw helper forms, and optional-shell test
|
|
||||||
boundary during adoption; no further implementation of those findings remains.
|
|
||||||
|
|
||||||
The completion assertion compares the expected alias source/target records
|
|
||||||
without depending on their iteration order, while detecting missing, unexpected,
|
|
||||||
or duplicate records. Its routing and visible-completion assertions remain.
|
|
||||||
Production alias ordering and public contracts are unchanged. This correction
|
|
||||||
was completed as part of the maintenance scope, separate from R1/R2 remediation;
|
|
||||||
the implementation plan records the test changes and focused verification.
|
|
||||||
|
|
||||||
Ordinary releases retain their single selected-module publication suite and
|
|
||||||
separate hosted-delivery outcome. One-time upgrade diagnostics are maintenance
|
|
||||||
evidence, with no new recurring release gate. Credentials and live publication
|
|
||||||
are unnecessary for this adoption.
|
|
||||||
|
|
||||||
## Completion evidence
|
|
||||||
|
|
||||||
Adoption is demonstrated by authentic module metadata, the real helper reporting
|
|
||||||
v0.9.0 for the host, aligned current documentation and attribution, and recorded
|
|
||||||
validation of the final source. The reviewed upgrade introduced no other module
|
|
||||||
version change; verify rather than assume that result during implementation.
|
|
||||||
|
|
||||||
R1/R2 acceptance evidence is complete in the remediation record. Completion of
|
|
||||||
the remaining maintenance work also includes a stable, order-independent
|
|
||||||
completion assertion and validation that the adopted helper retains the
|
|
||||||
corrected launcher behavior. Independent integration dependency alignment
|
|
||||||
remains separate release-preparation work; this roadmap selects no future
|
|
||||||
versions or sums.
|
|
||||||
|
|
||||||
## Resolved choices
|
|
||||||
|
|
||||||
R1 and R2 were corrected in separate commits before adoption, resolving the
|
|
||||||
former OD-1 scheduling question. Their acceptance evidence remains in
|
|
||||||
[remediation.md](remediation.md).
|
|
||||||
|
|
||||||
The selected maintenance scope is the completion assertion repair, root tool
|
|
||||||
upgrade, aligned current documentation and attribution, and validation of the
|
|
||||||
resulting source. The older integration dependency-version mismatch remains
|
|
||||||
separate release-preparation work. The implementation plan defines execution
|
|
||||||
and commit sequencing.
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
# Release tooling review findings
|
|
||||||
|
|
||||||
Status: R1 and R2 complete; no open findings. Review baseline:
|
|
||||||
`124a9fa57fb3f815bedbafe2d4819f6aa265ee7d`, covering the implementation commits
|
|
||||||
after `cb40f1d`. The findings below preserve the review evidence; completion
|
|
||||||
markers record the subsequent corrections. No implementation was changed during
|
|
||||||
the original review.
|
|
||||||
|
|
||||||
The selected architecture is substantially present: three declarative profiles,
|
|
||||||
one host-normalized registered-tool helper, separate publication and page-only
|
|
||||||
delivery, retained credential-directory ignoring, and focused wiring tests.
|
|
||||||
Both issues identified by the review have been addressed.
|
|
||||||
|
|
||||||
## R1 — P2: Reject raw helper command names as legacy module selectors
|
|
||||||
|
|
||||||
**Completed.** The legacy entry point now checks its three module selectors
|
|
||||||
before delegating to the helper, retaining the single profile/module mapping
|
|
||||||
there. Regression cases cover all three raw-command collisions and require
|
|
||||||
usage status 2 with no Go invocation. The new regression failed before the fix;
|
|
||||||
the complete focused scripts suite and shell syntax checks passed afterward
|
|
||||||
with Go 1.26.8, including valid legacy and direct raw-command forwarding.
|
|
||||||
|
|
||||||
**Location:** [scripts/release](../../scripts/release), lines 9–10, delegating to
|
|
||||||
the first-argument dispatch in [scripts/releasekit](../../scripts/releasekit),
|
|
||||||
lines 10–15. The invalid-form cases in
|
|
||||||
[scripts/release_test.go](../../scripts/release_test.go), lines 186–200, miss
|
|
||||||
these collisions.
|
|
||||||
|
|
||||||
The legacy interface is `scripts/release MODULE VERSION`, with three module
|
|
||||||
selectors. It now delegates its first argument directly into a helper that also
|
|
||||||
accepts `version`, `publication-attempts`, and `reconcile` as raw commands. These
|
|
||||||
invalid module names consequently bypass selector rejection and invoke Go.
|
|
||||||
|
|
||||||
For example, `./scripts/release version v1.2.3` reaches the tool as
|
|
||||||
`version publish v1.2.3`. With the real pinned tool it returns upstream's
|
|
||||||
"version takes no arguments" diagnostic after tool resolution. In a disposable
|
|
||||||
copy with a controlled Go boundary returning status 73, each of the three raw
|
|
||||||
command names returned 73 and invoked Go; an ordinary unknown selector returned
|
|
||||||
2 without invoking Go. Thus invalid legacy input depends on tool availability
|
|
||||||
and behavior instead of being rejected at the wrapper boundary.
|
|
||||||
|
|
||||||
**Required correction:** Make legacy module selection unambiguous before raw
|
|
||||||
command dispatch. Keep one profile/module mapping and the supported raw helper
|
|
||||||
forms; a small selector check is preferable to another routing framework.
|
|
||||||
Preserve upstream ownership of version and flag validation.
|
|
||||||
|
|
||||||
**Verification:** Add all three raw command names as invalid legacy selectors.
|
|
||||||
Each must return usage status 2 before any Go command runs. Valid legacy
|
|
||||||
publication and the helper's direct raw forms must retain their forwarding and
|
|
||||||
exit-status behavior. This restores the requested malformed-wrapper handling;
|
|
||||||
it adds no new accepted-version restriction.
|
|
||||||
|
|
||||||
## R2 — P2: Restore the tests' optional POSIX-shell execution boundary
|
|
||||||
|
|
||||||
**Completed.** Launcher execution tests now discover `sh`, invoke it explicitly
|
|
||||||
with the script path, and skip when it is unavailable. Profile assertions remain
|
|
||||||
independent of shell availability. A regression case removes the fixture
|
|
||||||
script's executable permission to verify interpreter invocation; it failed
|
|
||||||
before the correction and passes afterward. The focused scripts suite and shell
|
|
||||||
syntax checks passed with Go 1.26.8 on the available POSIX host. Running the
|
|
||||||
compiled test binary with an empty `PATH` confirmed that every launcher
|
|
||||||
execution case skips while all three profile assertions pass. Native Windows
|
|
||||||
execution was not tested and no new platform guarantee is introduced.
|
|
||||||
|
|
||||||
**Location:** [scripts/release_test.go](../../scripts/release_test.go), especially
|
|
||||||
`fixture.run` at line 63 and the launcher test setup.
|
|
||||||
|
|
||||||
The rewritten tests execute extensionless POSIX shell scripts directly through
|
|
||||||
`exec.Command`. They neither discover a shell nor skip launcher execution when
|
|
||||||
it is unavailable. The previous suite resolved `sh`, skipped shell-dependent
|
|
||||||
tests when it was missing, and passed the script as an argument to that shell.
|
|
||||||
|
|
||||||
Direct execution works on this review's Linux host, but relies on Unix script
|
|
||||||
execution semantics. Native Windows process creation does not supply a POSIX
|
|
||||||
interpreter for these files. Go's
|
|
||||||
[os/exec documentation](https://pkg.go.dev/os/exec#hdr-Overview) explicitly notes
|
|
||||||
that it does not invoke a system shell. Consequently the default repository
|
|
||||||
suite now fails on hosts without compatible script execution rather than
|
|
||||||
preserving the previous optional-shell behavior. This portability finding is
|
|
||||||
based on the changed execution path and platform implementation; a native
|
|
||||||
Windows test run was not available during review.
|
|
||||||
|
|
||||||
**Required correction:** Discover a POSIX shell for launcher execution tests,
|
|
||||||
invoke it explicitly with the script path, and skip those tests when the shell
|
|
||||||
is unavailable. Keep profile-only JSON assertions runnable without requiring a
|
|
||||||
shell. Preserve the reduced test architecture and existing argv/status checks.
|
|
||||||
No native Windows release launcher or additional supported-platform guarantee
|
|
||||||
is requested.
|
|
||||||
|
|
||||||
**Verification:** Confirm that launcher tests use the discovered interpreter
|
|
||||||
and handle its absence explicitly, while profile assertions still run. Rerun
|
|
||||||
the focused suite on the available POSIX host. Broader platform matrices are
|
|
||||||
not a new release gate; this correction removes an incidental environment
|
|
||||||
restriction introduced by the test rewrite.
|
|
||||||
|
|
||||||
## Review evidence and limits
|
|
||||||
|
|
||||||
- Go 1.26.8 offline root tests and the temporary-workspace suites for both
|
|
||||||
integrations passed. Both production scripts passed shell syntax checks.
|
|
||||||
- The real helper reported ReleaseKit v0.8.0 under foreign target settings.
|
|
||||||
- ReleaseKit checks passed for a disposable committed source snapshot using
|
|
||||||
the actual profiles: ordinary root validation, then both integration checks
|
|
||||||
with the implementation plan's temporary workspace-backed test process.
|
|
||||||
Selected file checks continued to inspect the committed declarations.
|
|
||||||
- Local documentation destinations and applicable Markdown fragments passed
|
|
||||||
inspection. The credential file remained ignored and its contents were not
|
|
||||||
read. No real publication or hosted-delivery operation was invoked.
|
|
||||||
- Library code and dependency declarations were unchanged by the sprint. The
|
|
||||||
documented integration dependency-version mismatch remains a pre-existing
|
|
||||||
independent-release-readiness limitation; the workspace-backed results do
|
|
||||||
not establish that published dependencies are aligned.
|
|
||||||
|
|
||||||
No additional architecture gaps or unrequested runtime/public-API guarantees
|
|
||||||
were identified. The selected file checks and forbidden token path match the
|
|
||||||
finalized scope. R2 concerns the default tests' execution environment rather
|
|
||||||
than a new production validator or library contract.
|
|
||||||
@@ -1,890 +0,0 @@
|
|||||||
# Output policy and invocation reporting
|
|
||||||
|
|
||||||
Status: behavioral decisions selected through OD-4. Message categories, all four
|
|
||||||
output modes, uniform treatment of help and version, message prefixes, and
|
|
||||||
OD-1's flag grammar and scope (including independent Progress control) are selected.
|
|
||||||
OD-2's unified reporting direction, the terminal failure model, and application
|
|
||||||
ownership of domain-specific error decisions are selected.
|
|
||||||
OD-3's failure presentation and retention boundaries are selected.
|
|
||||||
OD-4's delivery lifecycle, write-failure handling, and quiet-mode rendering are
|
|
||||||
selected. The consumer API signatures, presentation-result model, provider
|
|
||||||
diagnostic boundary, fallback explanations, and rendering callback boundary
|
|
||||||
below are also selected. Architectural preparation is complete:
|
|
||||||
[ADR 0014](../adr/0014-invocation-reporting.md) is accepted, and the
|
|
||||||
[architecture policy](../policy/architecture.md) is aligned. Implementation and
|
|
||||||
final validation are complete; Stages 1–20 are complete. The [implementation
|
|
||||||
plan](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/230187296fae5253cb1773f16c2f1d1a39499ed0/docs/roadmap/implementation.md) records the stage order and validation evidence.
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Provide consistent handling of `--quiet`, `--verbose`, `--debug`, and
|
|
||||||
`--progress` across application commands and optional integrations. Reduce
|
|
||||||
repeated output classification, diagnostic presentation, and delivery bookkeeping
|
|
||||||
where CommandKit can provide a meaningful benefit.
|
|
||||||
|
|
||||||
Ordinary Go writers and formatting functions already make application output
|
|
||||||
straightforward. Design reporting conveniences around the shared output policy
|
|
||||||
and invocation lifecycle. Applications continue to own their report content,
|
|
||||||
domain behavior, and operation outcomes.
|
|
||||||
|
|
||||||
## CLI presentation and error-handling ownership
|
|
||||||
|
|
||||||
Applications decide how to respond to domain-specific errors: recover, retry,
|
|
||||||
continue silently, report a Warning, or end the invocation with a failure.
|
|
||||||
CommandKit may provide shared helpers for carrying, inspecting, and presenting
|
|
||||||
errors while leaving those decisions with the application. A Go `error` alone
|
|
||||||
does not determine a CLI message category. Warnings may describe issues with or
|
|
||||||
without an underlying Go error, and handling an error does not require emitting
|
|
||||||
a message.
|
|
||||||
|
|
||||||
CommandKit handles the presentation the application requests: message category,
|
|
||||||
visibility, formatting, timing, and delivery. For terminal application failures,
|
|
||||||
the application supplies a non-zero outcome and an operator-facing explanation.
|
|
||||||
It may also supply an optional Go error cause for the execution caller to inspect.
|
|
||||||
CommandKit preserves that cause and its existing `errors.Is`/`errors.As` behavior.
|
|
||||||
Supplying a cause alone does not select an outcome, generate an operator-facing
|
|
||||||
message, or change visibility.
|
|
||||||
|
|
||||||
Applications can explicitly present `err.Error()` as a Warning through the
|
|
||||||
ordinary message API, illustrated by `report.Warn(err.Error())`. Defer a separate
|
|
||||||
`WarnError` convenience helper pending demonstrated value; this conversion
|
|
||||||
already requires little code.
|
|
||||||
|
|
||||||
CommandKit retains responsibility for handling its own errors, including
|
|
||||||
routing, parsing, and reporting failures. Integration-owned commands similarly
|
|
||||||
adapt their upstream APIs into deliberate command outcomes and presentations.
|
|
||||||
Ordinary Go error returns from CommandKit APIs and writers remain available where
|
|
||||||
appropriate.
|
|
||||||
|
|
||||||
## Current baseline
|
|
||||||
|
|
||||||
[`Streams` and `Invocation`](../../identity.go) expose caller-selected output
|
|
||||||
and diagnostic writers. [`Outcome` and `Diagnostic`](../../outcome.go) carry
|
|
||||||
operation causes, diagnostic writers, and delivery state. Handlers can return
|
|
||||||
`Failure(err)` or attach diagnostics to an outcome for presentation after the
|
|
||||||
handler returns. `MessageDiagnostic` currently writes the supplied message with
|
|
||||||
a newline; severity does not add a label automatically.
|
|
||||||
|
|
||||||
CommandKit coordinates final diagnostic delivery and retains delivery failures
|
|
||||||
separately from the operation cause. Custom handlers can also write directly to
|
|
||||||
the supplied streams and retain responsibility for their output. The existing
|
|
||||||
outcome and channel ownership decisions are recorded in
|
|
||||||
[ADR 0005](../adr/0005-invocation-outcomes.md).
|
|
||||||
|
|
||||||
Integration adapters already translate upstream diagnostic records into
|
|
||||||
CommandKit diagnostics while preserving native rendering and source context.
|
|
||||||
Some adapters wrap multiple records in one diagnostic writer and classify the
|
|
||||||
batch by its highest severity. This matters when designing selective visibility.
|
|
||||||
|
|
||||||
There is currently no shared verbosity policy or invocation reporter API.
|
|
||||||
|
|
||||||
## Selected output policy
|
|
||||||
|
|
||||||
Distinguish substantive application output from diagnostic message categories:
|
|
||||||
|
|
||||||
- **Substantive output (Normal):** The requested report or command result.
|
|
||||||
- **Error:** Terminal presentation of an unrecoverable invocation failure,
|
|
||||||
resulting in a non-zero status code.
|
|
||||||
- **Warning:** Something went wrong or deserves attention, but the invocation
|
|
||||||
can still succeed. The application chooses whether to report such an issue.
|
|
||||||
- **Info:** Informational context and useful explanation, such as which profile
|
|
||||||
was selected or a final operation summary.
|
|
||||||
- **Progress:** Streaming updates about work underway, such as items processed.
|
|
||||||
- **Debug:** Troubleshooting detail, including intermediate decisions and
|
|
||||||
execution-path information.
|
|
||||||
|
|
||||||
Debug mode adds troubleshooting detail to verbose output:
|
|
||||||
|
|
||||||
| Output category | `--quiet` | No flag | `--verbose` | `--debug` |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| Substantive application output | Suppressed | Shown | Shown | Shown |
|
|
||||||
| Error | Shown | Shown | Shown | Shown |
|
|
||||||
| Warning | Suppressed | Suppressed | Shown | Shown |
|
|
||||||
| Info | Suppressed | Suppressed | Shown | Shown |
|
|
||||||
| Debug | Suppressed | Suppressed | Suppressed | Shown |
|
|
||||||
| Progress, without an explicit setting | Suppressed | Suppressed | Suppressed | Shown |
|
|
||||||
|
|
||||||
Info belongs in verbose mode; debug includes verbose messages. Normal output
|
|
||||||
remains a substantive result category, separate from diagnostic severity.
|
|
||||||
The category of a message determines its visibility; stream destination alone
|
|
||||||
cannot distinguish a warning from an error.
|
|
||||||
|
|
||||||
Progress is distinct from Info and is controlled separately as specified below.
|
|
||||||
Applications and integrations are not required to generate messages in any
|
|
||||||
category. Enabling a category adds no output when there are no messages in it;
|
|
||||||
other output remains subject to its own visibility rules.
|
|
||||||
|
|
||||||
Error presentation follows the terminal failure model below. An application
|
|
||||||
may report a recovered problem as a Warning or continue without a message.
|
|
||||||
|
|
||||||
Apply the same policy to help and version. There are no command-specific
|
|
||||||
exceptions for successful output:
|
|
||||||
|
|
||||||
```text
|
|
||||||
app help --quiet # succeeds silently
|
|
||||||
app version --quiet # succeeds silently
|
|
||||||
```
|
|
||||||
|
|
||||||
Usage and operational failures still report their errors in quiet mode.
|
|
||||||
The feature must distinguish successful output suppression from failure
|
|
||||||
diagnostic delivery.
|
|
||||||
|
|
||||||
### Message prefixes and channels
|
|
||||||
|
|
||||||
Substantive output uses the result destination, conventionally stdout. Warning,
|
|
||||||
Info, Progress, Debug, and terminal explanations use the diagnostic destination,
|
|
||||||
conventionally stderr. Callers supply both destinations.
|
|
||||||
|
|
||||||
Use `WARN:`, `DEBUG:`, and `ERROR:` prefixes for simple warning, debug, and error
|
|
||||||
messages respectively. Substantive output and Info messages have no prefix.
|
|
||||||
For multiline diagnostics, prefix the opening line and preserve the structured
|
|
||||||
detail. Integration adapters coordinate native diagnostic rendering to avoid
|
|
||||||
duplicate severity labels or loss of upstream formatting.
|
|
||||||
|
|
||||||
Usage guidance belongs to the terminal usage explanation and remains visible in
|
|
||||||
quiet mode. Successful help output follows the substantive-output policy.
|
|
||||||
|
|
||||||
Initially, Progress messages are unprefixed streamed lines. The diagnostic
|
|
||||||
destination keeps them separate from substantive output such as JSON or YAML.
|
|
||||||
Terminal redraw and progress-bar behavior are outside this implementation.
|
|
||||||
|
|
||||||
### Terminal failure model
|
|
||||||
|
|
||||||
During execution, applications can produce substantive output, Progress, Info,
|
|
||||||
Debug, and Warnings. An unrecoverable failure ends the handler by returning a
|
|
||||||
failed outcome. There is no standalone `report.Error(...)` method. Detailed
|
|
||||||
error explanations accompany the returned failure and are presented as part of
|
|
||||||
that terminal step.
|
|
||||||
|
|
||||||
CommandKit finalizes reporting, presents the terminal failure explanation, and
|
|
||||||
returns the non-zero outcome to the application entry point. It accepts no
|
|
||||||
further normal output for that invocation after terminal error presentation.
|
|
||||||
The same boundary applies to core routing and parsing failures that prevent
|
|
||||||
handler execution. The application entry point retains ownership of process
|
|
||||||
exit; CommandKit ends the invocation and returns its outcome.
|
|
||||||
|
|
||||||
For example, if an export operation fails and the application decides it cannot
|
|
||||||
continue, the handler returns a non-zero outcome with an explicit explanation
|
|
||||||
such as "Unable to export the requested report." The application can choose to
|
|
||||||
include detail from a Go error in that explanation. CommandKit presents the
|
|
||||||
supplied explanation without automatically deriving text from an application
|
|
||||||
error. The selected API below provides failure constructors for this purpose.
|
|
||||||
When a failed outcome supplies no explanation, CommandKit supplies the generic
|
|
||||||
fallback defined under terminal outcomes below.
|
|
||||||
|
|
||||||
Output streamed before the failure remains visible according to its selected
|
|
||||||
mode; terminal failure does not withdraw earlier bytes. Deferred messages,
|
|
||||||
cleanup writes, and delivery failures must respect the end of normal reporting.
|
|
||||||
Their finalization and late-write behavior follow OD-4 below. A terminal
|
|
||||||
failure may have multiple explanatory records, all belonging to that failure.
|
|
||||||
|
|
||||||
### Failure explanations and presentation ownership (OD-3)
|
|
||||||
|
|
||||||
Make a non-zero outcome with an explicit message the convenient failure path.
|
|
||||||
Support structured explanations, including multiple records, through the same
|
|
||||||
presentation facility for richer application and integration reports. Neither
|
|
||||||
form requires an underlying Go error.
|
|
||||||
|
|
||||||
The application or integration explicitly identifies the context belonging to
|
|
||||||
a terminal explanation. Present that context with the failure in every mode,
|
|
||||||
including quiet. Independent warnings and other messages retain their own
|
|
||||||
visibility rules. For mixed upstream batches, adapters preserve useful native
|
|
||||||
rendering while distinguishing terminal explanatory context from independent
|
|
||||||
messages. Core does not infer those relationships from error chains or text.
|
|
||||||
|
|
||||||
Assign each submitted message one presentation path. Returning a terminal
|
|
||||||
explanation schedules its presentation once; core does not append another
|
|
||||||
message derived from an application error cause. Native renderers can supply
|
|
||||||
already-labelled content without receiving duplicate prefixes. Avoid text-based
|
|
||||||
deduplication: separate events may legitimately produce identical messages.
|
|
||||||
|
|
||||||
Constructing a failure result attaches explanatory content without emitting or
|
|
||||||
independently scheduling an Error. Returning that result hands the explanation
|
|
||||||
to CommandKit for terminal delivery through the invocation's reporting facility.
|
|
||||||
The selected API expresses this distinction for both simple and structured
|
|
||||||
explanations. For example:
|
|
||||||
|
|
||||||
| Handler action | Presentation |
|
|
||||||
| --- | --- |
|
|
||||||
| Construct a non-zero result with "Unable to export the requested report," then return it. | Construction emits nothing. CommandKit presents the message once during terminal delivery. |
|
|
||||||
| Return a failure with native diagnostic records and their source context, submitting independent warnings separately. | CommandKit presents the structured terminal explanation in every mode. Independent warnings follow their own visibility policy. |
|
|
||||||
|
|
||||||
### Retention boundary (OD-3)
|
|
||||||
|
|
||||||
CommandKit provides invocation-scoped CLI presentation. Logging and message
|
|
||||||
history collection remain application concerns. Keep terminal explanations and
|
|
||||||
any supplied cause with the returned outcome, and keep the temporary state needed
|
|
||||||
for deferred delivery, parser events awaiting mode selection, and delivery
|
|
||||||
bookkeeping. The reporting facility does not collect a transcript or retain other
|
|
||||||
emitted or suppressed messages for later inspection. No optional message-history
|
|
||||||
facility is planned for this implementation.
|
|
||||||
|
|
||||||
## Selected flag grammar and scope
|
|
||||||
|
|
||||||
### Mode selection and resets
|
|
||||||
|
|
||||||
Model quiet, ordinary, verbose, and debug as mutually exclusive presentation
|
|
||||||
modes. Each invocation starts in ordinary mode. Process flag occurrences in
|
|
||||||
invocation order; the last enabled mode wins. Repetition does not increment
|
|
||||||
verbosity, and debug is selected explicitly.
|
|
||||||
|
|
||||||
Accept presence and the existing explicit boolean syntax, including
|
|
||||||
`--quiet=true` and `--quiet=false`. A false occurrence clears its mode only if
|
|
||||||
that mode is currently selected, returning to ordinary mode. It does not restore
|
|
||||||
an earlier selection or disable a different mode. Every occurrence is converted;
|
|
||||||
invalid boolean values remain usage errors even when a later flag would replace
|
|
||||||
the selection.
|
|
||||||
|
|
||||||
| Flag sequence | Final mode |
|
|
||||||
| --- | --- |
|
|
||||||
| `--quiet --verbose` | Verbose |
|
|
||||||
| `--debug --quiet` | Quiet |
|
|
||||||
| `--verbose --verbose` | Verbose |
|
|
||||||
| `--verbose --verbose=false` | Ordinary |
|
|
||||||
| `--quiet --verbose=false` | Quiet |
|
|
||||||
| `--verbose --quiet --quiet=false` | Ordinary |
|
|
||||||
| `--quiet=false --debug` | Debug |
|
|
||||||
|
|
||||||
Keep verbosity a presentation choice: quiet preserves the requested operation's
|
|
||||||
semantics and rendering failures. Delivery failures depend on the output actually
|
|
||||||
requested; suppressing a destination write can avoid a delivery failure. Apply
|
|
||||||
the policy through CommandKit-managed reporting and streams. Output written
|
|
||||||
directly to process streams or external destinations remains application-owned.
|
|
||||||
|
|
||||||
### Progress selection
|
|
||||||
|
|
||||||
`--progress` enables Progress without enabling Info, Warning, or Debug messages.
|
|
||||||
`--progress=false` explicitly disables it. Accept the existing boolean syntax;
|
|
||||||
repeated canonical or aliased progress settings use the last value. Retain
|
|
||||||
whether a setting was explicitly supplied, separately from its boolean value.
|
|
||||||
|
|
||||||
Determine effective Progress visibility from the final presentation mode and
|
|
||||||
explicit progress setting:
|
|
||||||
|
|
||||||
1. Quiet mode always suppresses Progress.
|
|
||||||
2. Otherwise, an explicit progress setting controls visibility.
|
|
||||||
3. Without an explicit setting, debug enables Progress; ordinary and verbose
|
|
||||||
modes leave it disabled.
|
|
||||||
|
|
||||||
An explicit progress setting overrides the mode's default regardless of its
|
|
||||||
position relative to mode flags. It does not select or reset the presentation
|
|
||||||
mode. Debug includes verbose detail and defaults Progress on; verbose alone
|
|
||||||
does not enable Progress.
|
|
||||||
|
|
||||||
| Flags | Result |
|
|
||||||
| --- | --- |
|
|
||||||
| `--verbose` | Warning and Info, without Progress. |
|
|
||||||
| `--verbose --progress` | Warning, Info, and Progress. |
|
|
||||||
| `--debug` | Warning, Info, Debug, and Progress. |
|
|
||||||
| `--debug --progress=false` or `--progress=false --debug` | Debug detail without Progress. |
|
|
||||||
| `--quiet --progress` or `--progress --quiet` | Only failure diagnostics. |
|
|
||||||
| `--debug --verbose` | Verbose detail without Progress, absent an explicit progress setting. |
|
|
||||||
|
|
||||||
Passing `--progress` to an application that emits no Progress messages adds no
|
|
||||||
visible output. It does not suppress that application's substantive results or
|
|
||||||
require a progress implementation.
|
|
||||||
|
|
||||||
### Placement, availability, and aliases
|
|
||||||
|
|
||||||
Core supplies `--quiet`, `--verbose`, `--debug`, and `--progress` for application
|
|
||||||
commands, integrations, the root, canonical groups, and alias-only discovery help.
|
|
||||||
Consumers do not register them individually. Preserve the existing placement
|
|
||||||
grammar: flags follow the complete command path and may be interspersed with
|
|
||||||
operands after that path. For example:
|
|
||||||
|
|
||||||
```text
|
|
||||||
app config show --quiet
|
|
||||||
app export destination --verbose
|
|
||||||
app help config show --quiet
|
|
||||||
app version --quiet
|
|
||||||
```
|
|
||||||
|
|
||||||
Options before or between command-path components are outside this grammar.
|
|
||||||
Tokens consumed as values and tokens following `--` retain their ordinary
|
|
||||||
meaning.
|
|
||||||
|
|
||||||
Reserve the four long spellings. Applications may add `-q`, `-v`, or `-d`
|
|
||||||
through the alias API; no built-in short spellings are selected. An application
|
|
||||||
flag declaration that defines a reserved long name fails installation with a
|
|
||||||
collision error. Aliases may target these flags but may not overload canonical
|
|
||||||
spellings. Apply the existing collision and atomic installation rules, including
|
|
||||||
later registration.
|
|
||||||
|
|
||||||
Aliased and canonical occurrences participate in the same ordering. With
|
|
||||||
`-q → --quiet`, `app export --verbose -q` selects quiet mode. Document the newly
|
|
||||||
reserved canonical names as a compatibility change.
|
|
||||||
|
|
||||||
### Routing and parsing failures
|
|
||||||
|
|
||||||
Determine the mode through the normal parser before execution or successful
|
|
||||||
help/report presentation. Do not add a separate verbosity scanner. This keeps
|
|
||||||
token interpretation consistent and avoids reinterpreting values or operands.
|
|
||||||
|
|
||||||
Routing and parsing failures report their errors regardless of verbosity. For
|
|
||||||
example, `app export --quiet --unknown` still reports the unknown flag. Error
|
|
||||||
visibility follows the selected output policy independently of how the mode is
|
|
||||||
determined; avoiding a separate scanner is an implementation simplification.
|
|
||||||
|
|
||||||
## CommandKit's own diagnostics
|
|
||||||
|
|
||||||
Use the shared reporting system for CommandKit's invocation diagnostics so
|
|
||||||
parser, integration, and application messages follow the same visibility and
|
|
||||||
delivery policy. Installation errors occur before an invocation exists and
|
|
||||||
continue to be returned to the application without automatic printing.
|
|
||||||
|
|
||||||
Supported repetition and last-occurrence overrides are routine decisions.
|
|
||||||
Repeated singleton flags, including `--verbose --verbose`, may produce debug
|
|
||||||
detail; repetition alone does not warrant a warning. Repeatable flags retain
|
|
||||||
their intended accumulation behavior. Add warnings for concrete concerns an
|
|
||||||
operator can act on, such as a deprecated spelling if deprecation is introduced.
|
|
||||||
Unknown flags, invalid values, and invalid command paths remain invocation
|
|
||||||
failures with error diagnostics.
|
|
||||||
|
|
||||||
Start debug instrumentation with routing, alias resolution, verbosity selection,
|
|
||||||
and handler completion. Other useful candidates can be added where they
|
|
||||||
explain a consequential decision:
|
|
||||||
|
|
||||||
| Event | Useful detail |
|
|
||||||
| --- | --- |
|
|
||||||
| Command-alias resolution | Entered path, intermediate redirects, and final canonical path. |
|
|
||||||
| Flag-alias resolution | Entered spelling and canonical flag name. |
|
|
||||||
| Scoped alias selection | A command-scoped mapping took precedence over an application-wide mapping. |
|
|
||||||
| Verbosity selection | A later occurrence selected a different mode; for `--verbose --debug`, debug wins because it appears last. |
|
|
||||||
| Help-route selection | A canonical command or alias-only discovery context was selected. |
|
|
||||||
| Repeated singleton flag | A later occurrence replaced an earlier occurrence, without printing their values. |
|
|
||||||
| Input preparation | Canonical input validation completed and the handler is starting. |
|
|
||||||
| Handler completion | Canonical command and the handler's returned classification and status, before final delivery. |
|
|
||||||
|
|
||||||
The handler-completion event describes the handler's result. The final returned
|
|
||||||
invocation outcome also includes delivery failures and remains authoritative.
|
|
||||||
Present this event before terminal failure presentation; do not emit a completion
|
|
||||||
message afterward.
|
|
||||||
|
|
||||||
Use the final selected mode to present earlier parser decisions. Collect the
|
|
||||||
relevant events during parsing and apply visibility after mode selection:
|
|
||||||
`--verbose --debug` shows the selection explanation, while `--debug --quiet`
|
|
||||||
suppresses it. This collection of parser events does not require whole-run
|
|
||||||
output buffering.
|
|
||||||
|
|
||||||
Debug messages should explain operator-relevant decisions independently of
|
|
||||||
incidental implementation steps. Use command paths, flag names, and decision
|
|
||||||
descriptions rather than raw argument or configuration-value dumps. Upstream
|
|
||||||
libraries retain ownership of their diagnostic detail and disclosure rules.
|
|
||||||
|
|
||||||
## Selected delivery lifecycle and quiet execution (OD-4)
|
|
||||||
|
|
||||||
### Ordering and finalization
|
|
||||||
|
|
||||||
Use synchronous delivery. Present immediate messages and substantive writes in
|
|
||||||
submission order. After the handler returns:
|
|
||||||
|
|
||||||
1. Deliver eligible deferred messages in queue order, without sorting by severity.
|
|
||||||
2. Finish ordinary reporting, including any handler-completion debug message and
|
|
||||||
flushing any CommandKit-owned buffers for ordinary output. Account for failures
|
|
||||||
discovered during this delivery before preparing the terminal explanation.
|
|
||||||
3. Present any terminal failure explanation and complete its delivery, including
|
|
||||||
any CommandKit-owned buffering of that explanation.
|
|
||||||
4. Close the invocation's reporting facility and return the final outcome.
|
|
||||||
|
|
||||||
Deferred messages remain eligible when the operation fails, subject to verbosity.
|
|
||||||
Deferral controls timing; applications queue success summaries only after the
|
|
||||||
relevant operation succeeds. Ordering governs CommandKit's writes; separate
|
|
||||||
stdout and stderr destinations may be buffered or displayed differently by the
|
|
||||||
caller.
|
|
||||||
|
|
||||||
CommandKit finalizes automatically. Consumers do not need a separate flush or
|
|
||||||
finish call. Handler cleanup, including Go `defer` functions, runs before the
|
|
||||||
handler returns and participates in normal reporting. Applications complete any
|
|
||||||
reporting goroutines before returning. After finalization, writes and message
|
|
||||||
submissions return a closed-reporter error and emit nothing.
|
|
||||||
|
|
||||||
Reporter operations within an invocation are safe to call concurrently.
|
|
||||||
Serialize access to reporting state and delivery so individual messages do not
|
|
||||||
interleave. Concurrent submissions have no predetermined order; deferred messages
|
|
||||||
follow the order in which they enter the queue. Multiple writes composing one
|
|
||||||
application report still require application coordination if they must remain
|
|
||||||
together. This contract covers operations through one invocation's reporter;
|
|
||||||
coordination with writes outside that reporter remains caller-owned.
|
|
||||||
|
|
||||||
Finalize any buffers owned by CommandKit. Caller-supplied writers remain
|
|
||||||
caller-owned; CommandKit does not automatically close them or invoke arbitrary
|
|
||||||
flushing interfaces.
|
|
||||||
|
|
||||||
Visibility applies when output is emitted. A verbose or debug run may show
|
|
||||||
informational detail before subsequently failing. Progress and substantive
|
|
||||||
output may likewise be partially delivered before a failure. Previously written
|
|
||||||
bytes cannot be withdrawn. Whole-run buffering solely to make failed runs
|
|
||||||
contain only error output is outside this implementation.
|
|
||||||
|
|
||||||
Keep errors understandable in every mode, including source locations and
|
|
||||||
related explanatory context. Unrelated warnings and informational messages
|
|
||||||
remain subject to the selected mode. Apply the selected retention boundary
|
|
||||||
without accumulating a message history.
|
|
||||||
|
|
||||||
### Rendering failures, write failures, and execution flow
|
|
||||||
|
|
||||||
Distinguish who invokes a renderer and whether its destination failed:
|
|
||||||
|
|
||||||
| Failure source | Responsibility and handling |
|
|
||||||
| --- | --- |
|
|
||||||
| An encoder or renderer called directly by the application | The application handles its returned error and chooses the outcome and explanation. |
|
|
||||||
| A rendering callback invoked by CommandKit | CommandKit handles its returned error as a presentation failure and reflects it in the invocation outcome. |
|
|
||||||
| A destination rejects a write | CommandKit records the delivery failure and stops further writes to that destination. |
|
|
||||||
|
|
||||||
A rendering failure may occur before any write or while the destination remains
|
|
||||||
healthy. It does not by itself establish a failed destination. CommandKit can
|
|
||||||
explain its rendering failure through a working diagnostic destination. These
|
|
||||||
responsibilities also apply when rendering into a discard destination under
|
|
||||||
quiet mode.
|
|
||||||
|
|
||||||
Failure to deliver requested output makes an otherwise successful invocation
|
|
||||||
unsuccessful. Apply this rule to substantive output, Warning, Info, Progress,
|
|
||||||
Debug, and terminal explanations. Intentional suppression requests no delivery
|
|
||||||
and is not a delivery failure.
|
|
||||||
|
|
||||||
Standard writer operations return write errors normally. Immediate reporting
|
|
||||||
methods also expose delivery errors. CommandKit records bounded delivery-failure
|
|
||||||
information so an ignored write error cannot yield a successful invocation.
|
|
||||||
Deferred delivery failures appear in the final outcome.
|
|
||||||
|
|
||||||
Apply ADR 0005's outcome rules when presentation fails. For standard outcomes,
|
|
||||||
return operational failure with status `1`, including when the original outcome
|
|
||||||
was a usage failure. Preserve the original explanation and any supplied cause;
|
|
||||||
record the presentation failure separately in `Presentation`.
|
|
||||||
|
|
||||||
Application-defined domain outcomes retain their domain classification. Preserve
|
|
||||||
an already non-zero domain status. If the domain status was `0`, change the
|
|
||||||
suggested status to `1` so presentation failure cannot yield a successful
|
|
||||||
invocation. The application entry point retains control of process exit.
|
|
||||||
|
|
||||||
| Outcome before presentation fails | Final outcome |
|
|
||||||
| --- | --- |
|
|
||||||
| Success, status `0` | Operational failure, status `1`. |
|
|
||||||
| Usage failure, status `2` | Operational failure, status `1`. |
|
|
||||||
| Operational failure, status `1` | Operational failure, status `1`. |
|
|
||||||
| Domain outcome, non-zero status | Same domain classification and status. |
|
|
||||||
| Domain outcome, status `0` | Same domain classification, status `1`. |
|
|
||||||
|
|
||||||
These rules apply to both destination-write failures and rendering failures from
|
|
||||||
callbacks invoked by CommandKit. Reporting failures remain CommandKit's own
|
|
||||||
error-handling responsibility.
|
|
||||||
|
|
||||||
Stop writing to a destination after it fails. A substantive-output failure can
|
|
||||||
receive a terminal explanation through the diagnostic destination if it still
|
|
||||||
works. If diagnostic delivery fails, return that information to the caller.
|
|
||||||
Do not redirect diagnostics into substantive output or recursively attempt to
|
|
||||||
report the reporting failure.
|
|
||||||
|
|
||||||
A failed write does not stop application code. The handler can inspect the error
|
|
||||||
and return immediately; otherwise, CommandKit records the failure and finalizes
|
|
||||||
when the handler returns. CommandKit does not use process exit or panic to
|
|
||||||
interrupt execution. Terminal failure presentation ends normal output.
|
|
||||||
|
|
||||||
### Quiet-mode rendering and suppression
|
|
||||||
|
|
||||||
Initially, run substantive report generation normally with its managed writer
|
|
||||||
discarding output in quiet mode. This preserves report generation, validation,
|
|
||||||
and serialization failures while changing presentation. For example, a report
|
|
||||||
encoder failure still fails the invocation under `--quiet`; the handler remains
|
|
||||||
responsible for handling errors returned by an encoder it calls.
|
|
||||||
|
|
||||||
Simple suppressed messages need no formatting or destination writes. For richer
|
|
||||||
report renderers, initially render into a discard destination. Rendering may be
|
|
||||||
skipped later where doing so preserves the command's operation and failure
|
|
||||||
semantics.
|
|
||||||
|
|
||||||
Treat suppression as intentional suppression, never as failed or incomplete
|
|
||||||
delivery. Do not retain suppressed content. Delivery needs only the deferred
|
|
||||||
queue, reporting lifecycle state, and bounded delivery-failure information,
|
|
||||||
alongside the temporary parser state and returned explanations described above.
|
|
||||||
|
|
||||||
## Selected consumer reporting API
|
|
||||||
|
|
||||||
Provide one reporting facility per invocation for substantive output, immediate
|
|
||||||
messages, and end-of-run diagnostics. The consumer API is chosen for its intended
|
|
||||||
long-term design; with no current consumers, preserving existing API shapes
|
|
||||||
carries no weight in this decision.
|
|
||||||
|
|
||||||
The following declarations specify the target API and are not yet implemented.
|
|
||||||
|
|
||||||
The reporter owns presentation: output visibility, progress settings, prefixes,
|
|
||||||
ordering, and delivery bookkeeping. Its views share invocation state, allowing
|
|
||||||
already-emitted messages, deferred messages, suppression, and write failures to
|
|
||||||
be coordinated in one place. Helpers may receive the reporter or a narrow
|
|
||||||
application-defined interface. Domain libraries can continue returning
|
|
||||||
diagnostic data for the handler to submit, independently of CommandKit.
|
|
||||||
|
|
||||||
Use the reporter as the common diagnostic submission path, replacing the earlier
|
|
||||||
proposal to split submission between a reporter and `Outcome.Diagnostics`.
|
|
||||||
Terminal explanations accompany returned outcomes and are delivered through the
|
|
||||||
same facility. Caller-selected destinations remain at `App.Execute`; handlers
|
|
||||||
use `Invocation.Reporter()` in place of raw invocation streams.
|
|
||||||
|
|
||||||
### Invocation reporter and structured detail
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (inv Invocation) Reporter() *Reporter
|
|
||||||
|
|
||||||
type Reporter struct {
|
|
||||||
// Private invocation state.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Reporter) Output() io.Writer
|
|
||||||
func (r *Reporter) RenderOutput(write func(io.Writer) error) error
|
|
||||||
|
|
||||||
func (r *Reporter) Info(message string, details ...Detail) error
|
|
||||||
func (r *Reporter) Warn(message string, details ...Detail) error
|
|
||||||
func (r *Reporter) Debug(message string, details ...Detail) error
|
|
||||||
func (r *Reporter) Progress(message string, details ...Detail) error
|
|
||||||
|
|
||||||
func (r *Reporter) AtEnd() DeferredReporter
|
|
||||||
|
|
||||||
type Detail func(io.Writer) error
|
|
||||||
```
|
|
||||||
|
|
||||||
`Output()` supports ordinary writers and encoders. `RenderOutput()` coordinates
|
|
||||||
an entire rendering operation, captures its rendering error, and prevents other
|
|
||||||
reporter operations from interleaving with it. Rendering callbacks write through
|
|
||||||
their supplied writer. Each complete categorized message, including its details,
|
|
||||||
is likewise coordinated as one reporter operation.
|
|
||||||
|
|
||||||
Rendering callbacks use their supplied writer only during the callback. They may
|
|
||||||
call rendering helpers that write through it. While a callback is running, it
|
|
||||||
must not recursively submit messages, queue deferred messages, start another
|
|
||||||
rendering operation, or write through a separate `Output()` handle belonging to
|
|
||||||
the same invocation's reporter. Make additional reporter submissions before or
|
|
||||||
after the callback. A callback must also avoid waiting for another goroutine to
|
|
||||||
submit through that reporter, since the submission may be waiting for the
|
|
||||||
callback to finish.
|
|
||||||
|
|
||||||
This boundary applies to `RenderOutput`, immediate and deferred message details,
|
|
||||||
and terminal explanation details. Ordinary concurrent reporter calls remain
|
|
||||||
supported and serialized. Keeping each rendering operation together motivates
|
|
||||||
the boundary; it does not prescribe a lock implementation or promise runtime
|
|
||||||
detection of recursive calls.
|
|
||||||
|
|
||||||
Message strings are literal; consumers use `fmt.Sprintf` when formatting is
|
|
||||||
needed. Initially omit parallel `Infof`, `Warnf`, and similar methods. CommandKit
|
|
||||||
formats the opening message with its category's prefix and a terminating newline.
|
|
||||||
Optional details follow in order with their formatting preserved. An empty
|
|
||||||
opening message produces no heading, prefix, or blank opening line, supporting
|
|
||||||
native renderers that supply a complete, labelled diagnostic:
|
|
||||||
|
|
||||||
```go
|
|
||||||
_ = report.Warn("Using the default profile")
|
|
||||||
_ = report.Warn("Some configuration settings need attention.", writeNativeWarnings)
|
|
||||||
_ = report.Warn("", writeNativeWarnings)
|
|
||||||
```
|
|
||||||
|
|
||||||
These are alternative calls; `writeNativeWarnings` represents an
|
|
||||||
application- or integration-supplied function with signature
|
|
||||||
`func(io.Writer) error`. No generic logging method or severity enumeration is
|
|
||||||
needed to submit messages. Applications need not check verbosity before reporting
|
|
||||||
or implement categories they do not use.
|
|
||||||
|
|
||||||
Immediate methods return rendering or delivery errors, and CommandKit records
|
|
||||||
the corresponding presentation failure even if the caller ignores the error.
|
|
||||||
A caller can inspect the returned error and end its handler immediately.
|
|
||||||
|
|
||||||
### Deferred messages
|
|
||||||
|
|
||||||
```go
|
|
||||||
type DeferredReporter struct {
|
|
||||||
// Private reference to the same invocation state.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r DeferredReporter) Info(message string, details ...Detail) error
|
|
||||||
func (r DeferredReporter) Warn(message string, details ...Detail) error
|
|
||||||
func (r DeferredReporter) Debug(message string, details ...Detail) error
|
|
||||||
```
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```go
|
|
||||||
_ = report.AtEnd().Warn("Three optional files were unavailable.")
|
|
||||||
```
|
|
||||||
|
|
||||||
Copies of the deferred view share invocation state. Its methods return submission
|
|
||||||
errors, such as attempting to use a closed reporter. Errors encountered during
|
|
||||||
deferred rendering appear in the final invocation outcome. Progress remains an
|
|
||||||
immediate streaming operation; substantive output uses the main reporter.
|
|
||||||
|
|
||||||
Copy callback lists when accepting a submission. Callers retain ownership of
|
|
||||||
data captured by rendering callbacks and keep that data valid until presentation.
|
|
||||||
|
|
||||||
### Terminal outcomes
|
|
||||||
|
|
||||||
Outcome construction requires no invocation state and emits nothing:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Explanation struct {
|
|
||||||
Message string
|
|
||||||
Details []Detail
|
|
||||||
}
|
|
||||||
|
|
||||||
type Outcome struct {
|
|
||||||
Kind OutcomeKind
|
|
||||||
Status int
|
|
||||||
Domain string
|
|
||||||
Cause error
|
|
||||||
Explanation Explanation
|
|
||||||
Presentation PresentationResult
|
|
||||||
}
|
|
||||||
|
|
||||||
func Success() Outcome
|
|
||||||
func Failure(message string, details ...Detail) Outcome
|
|
||||||
func Usage(message string, details ...Detail) Outcome
|
|
||||||
func Domain(name string, status int) Outcome
|
|
||||||
|
|
||||||
func (o Outcome) WithExplanation(message string, details ...Detail) Outcome
|
|
||||||
func (o Outcome) WithCause(cause error) Outcome
|
|
||||||
```
|
|
||||||
|
|
||||||
`Success` returns a successful outcome with status `0`. `Failure` produces an
|
|
||||||
operational failure with status `1`; `Usage` produces a usage failure with status
|
|
||||||
`2`. `Domain` constructs an outcome with the supplied application-defined
|
|
||||||
classification and status. Subsequent presentation failures follow OD-4's rules:
|
|
||||||
domain classification is preserved, and a zero status becomes `1` if presentation
|
|
||||||
fails.
|
|
||||||
`OutcomeKind` retains the success, usage, operational, and domain classifications.
|
|
||||||
|
|
||||||
`WithExplanation` returns a modified outcome value and replaces its terminal
|
|
||||||
explanation. Explanations belong to failed outcomes; successful summaries use
|
|
||||||
Info or substantive output. Ordinary application failure, native failure
|
|
||||||
rendering, and a custom domain failure respectively can be expressed as:
|
|
||||||
|
|
||||||
```go
|
|
||||||
return commandkit.Failure("Unable to export the requested report.")
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
|
||||||
return commandkit.Failure("", writeNativeFailure)
|
|
||||||
```
|
|
||||||
|
|
||||||
```go
|
|
||||||
return commandkit.Domain("validation", 3).
|
|
||||||
WithExplanation("The document failed validation.", writeFindings)
|
|
||||||
```
|
|
||||||
|
|
||||||
The named renderers above have signature `func(io.Writer) error` and preserve the
|
|
||||||
owning library's safe diagnostic formatting. They run during terminal delivery,
|
|
||||||
not when constructing the outcome.
|
|
||||||
|
|
||||||
Before terminal delivery, supply the explanation `Command failed.` when a
|
|
||||||
non-zero outcome has an empty `Explanation.Message` and no non-nil callback in
|
|
||||||
`Explanation.Details`. This produces `ERROR: Command failed.` in every mode,
|
|
||||||
including quiet, and becomes the explanation retained in the returned outcome.
|
|
||||||
Adding the fallback leaves classification, status, and cause unchanged;
|
|
||||||
presentation failures still follow OD-4's rules. The fallback is based on the
|
|
||||||
failed outcome and absent explanation, without deriving text from `Cause.Error()`.
|
|
||||||
|
|
||||||
An empty heading with a non-nil detail renderer is an explicitly supplied
|
|
||||||
explanation. Trust that renderer to provide its content. Do not buffer or replay
|
|
||||||
it to decide whether the explanation is sufficiently informative, and do not
|
|
||||||
add the fallback merely because it writes no bytes.
|
|
||||||
|
|
||||||
| Returned outcome | Terminal presentation |
|
|
||||||
| --- | --- |
|
|
||||||
| `Failure("")` | Generic fallback, operational classification and status `1`. |
|
|
||||||
| `Domain("validation", 3)` | Generic fallback, domain classification and status `3`. |
|
|
||||||
| `Failure("").WithCause(err)` | Generic fallback; the supplied cause remains available without automatic rendering. |
|
|
||||||
| `Failure("", writeNativeFailure)` | Native explanation without an added generic heading. |
|
|
||||||
|
|
||||||
`Cause` is optional. `WithCause` returns a modified outcome value, replacing the
|
|
||||||
cause without changing the classification, status, or explanation. For example:
|
|
||||||
|
|
||||||
```go
|
|
||||||
return commandkit.Failure("Unable to open the configuration file.").
|
|
||||||
WithCause(err)
|
|
||||||
```
|
|
||||||
|
|
||||||
CommandKit presents the supplied explanation and carries the original error
|
|
||||||
through to the execution caller, which can inspect it with expressions such as
|
|
||||||
`errors.Is(outcome.Cause, fs.ErrNotExist)`. It does not automatically present
|
|
||||||
`Cause.Error()` or use the cause to decide success, failure, or message category.
|
|
||||||
Providing a cause is independent of choosing the terminal explanation; neither
|
|
||||||
is inferred from the other. Warnings do not require supplying or retaining causes.
|
|
||||||
|
|
||||||
Outcome processing preserves supplied causes, including their existing Go error
|
|
||||||
identity, when a subsequent rendering or delivery failure occurs. Presentation
|
|
||||||
failures are recorded separately in `Presentation`. The returned outcome retains
|
|
||||||
its terminal explanation and optional cause, with other retention limited to the
|
|
||||||
presentation needs described above.
|
|
||||||
|
|
||||||
### Provider-returned diagnostic data
|
|
||||||
|
|
||||||
Providers return values and diagnostic data without needing a reporter parameter.
|
|
||||||
Retain `Acquired[T]` with separate fields for independent messages and failure
|
|
||||||
explanations:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Acquired[T any] struct {
|
|
||||||
Value T
|
|
||||||
Diagnostics []Diagnostic
|
|
||||||
Explanation Explanation
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`Diagnostics` carries independent, nonterminal messages. `Diagnostic` and
|
|
||||||
`Severity` remain passive data types for those messages, with each diagnostic
|
|
||||||
carrying its `Severity` and a `Write func(io.Writer) error` renderer. Adapt their
|
|
||||||
contracts to the nonterminal reporting categories. Integrations submit the
|
|
||||||
records through the corresponding reporter methods, including the deferred view
|
|
||||||
where appropriate. Removing `Outcome.Diagnostics` removes a submission path;
|
|
||||||
provider-returned records remain available for the integration to submit.
|
|
||||||
|
|
||||||
`Explanation` carries context to attach when the integration returns a failed
|
|
||||||
outcome. Terminal Error content uses this field rather than an independently
|
|
||||||
submitted diagnostic. An upstream warning that helps explain the failure may
|
|
||||||
belong in the explanation; unrelated warnings remain in `Diagnostics` and follow
|
|
||||||
their ordinary visibility rules. Adapters preserve this distinction and useful
|
|
||||||
native formatting when translating mixed upstream batches, instead of assigning
|
|
||||||
the whole batch its highest severity.
|
|
||||||
|
|
||||||
Providers may return acquired data alongside a Go error. The owning integration
|
|
||||||
chooses the command outcome, attaches any terminal explanation, and decides which
|
|
||||||
cause to preserve. Returning diagnostic data does not itself emit messages or
|
|
||||||
select the invocation outcome. Diagnostic renderers follow the same callback
|
|
||||||
boundary as other details when invoked through the reporter.
|
|
||||||
|
|
||||||
### Presentation observations and closed reporters
|
|
||||||
|
|
||||||
```go
|
|
||||||
type PresentationResult struct {
|
|
||||||
Output DeliveryResult
|
|
||||||
Diagnostics DeliveryResult
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeliveryResult struct {
|
|
||||||
State DeliveryState
|
|
||||||
RenderError error
|
|
||||||
WriteError error
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeliveryState uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
DeliveryNone DeliveryState = iota
|
|
||||||
DeliverySuppressed
|
|
||||||
DeliveryComplete
|
|
||||||
DeliveryIncomplete
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrReporterClosed = errors.New("reporter is closed")
|
|
||||||
```
|
|
||||||
|
|
||||||
| State | Meaning |
|
|
||||||
| --- | --- |
|
|
||||||
| `DeliveryNone` | No content was submitted for this destination. |
|
|
||||||
| `DeliverySuppressed` | All submitted content was intentionally suppressed, and rendering succeeded. |
|
|
||||||
| `DeliveryComplete` | All requested delivery completed; other content may have been suppressed. |
|
|
||||||
| `DeliveryIncomplete` | Rendering or destination writing failed. |
|
|
||||||
|
|
||||||
Retain the first rendering failure and first destination-write failure for each
|
|
||||||
destination. This provides bounded evidence without collecting an event history.
|
|
||||||
`Outcome.Presentation` is populated by CommandKit during execution and
|
|
||||||
finalization; it is observation data, not another submission API.
|
|
||||||
|
|
||||||
The invocation supplies the reporter. Consumers neither construct nor finalize
|
|
||||||
it. After closure, message submissions and writer operations return
|
|
||||||
`ErrReporterClosed`, including in quiet mode. The initial API needs no explicit
|
|
||||||
flush method, transcript accessor, or verbosity checks. Error-conversion helpers
|
|
||||||
are deferred pending demonstrated value.
|
|
||||||
|
|
||||||
### Application example
|
|
||||||
|
|
||||||
This target-API handler uses an application-owned `exportData` operation that
|
|
||||||
returns a JSON-encodable result with a `UsedDefaults` field:
|
|
||||||
|
|
||||||
```go
|
|
||||||
func runExport(inv commandkit.Invocation) commandkit.Outcome {
|
|
||||||
report := inv.Reporter()
|
|
||||||
|
|
||||||
result, err := exportData(inv.Context)
|
|
||||||
if err != nil {
|
|
||||||
return commandkit.Failure("Unable to export the requested data.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.UsedDefaults {
|
|
||||||
_ = report.Warn("Some optional settings used defaults.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := report.RenderOutput(func(w io.Writer) error {
|
|
||||||
return json.NewEncoder(w).Encode(result)
|
|
||||||
}); err != nil {
|
|
||||||
return commandkit.Failure("Unable to present the export result.")
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = report.AtEnd().Info("Export completed.")
|
|
||||||
return commandkit.Success()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Ignored immediate reporting errors are still recorded and can make the final
|
|
||||||
invocation unsuccessful. The renderer runs in quiet mode against the discard
|
|
||||||
destination, preserving serialization failures. The deferred summary follows
|
|
||||||
the selected verbosity policy and describes the completed export operation;
|
|
||||||
the final invocation outcome also accounts for presentation failures.
|
|
||||||
|
|
||||||
## Upstream diagnostic ownership
|
|
||||||
|
|
||||||
ConfigKit and PromptKit remain authoritative for their diagnostic semantics,
|
|
||||||
severity, source context, and disclosure rules. Integration adapters expose
|
|
||||||
those capabilities through the shared CommandKit presentation policy.
|
|
||||||
|
|
||||||
Support consistent reporting of ConfigKit errors and warnings as its adopted
|
|
||||||
public API evolves. This roadmap does not assume that a future warning API
|
|
||||||
already exists or prescribe its upstream shape. Integration-owned commands
|
|
||||||
select the outcome and submit useful native diagnostic detail for presentation.
|
|
||||||
Core presents those records under the shared policy. Applications using upstream
|
|
||||||
libraries directly choose how to respond to domain-specific errors and which
|
|
||||||
outcomes and messages to supply, as for their other operations.
|
|
||||||
|
|
||||||
An integration may receive both a useful substantive report and an operation
|
|
||||||
failure, as PromptKit smoke testing supports. Preserve the report under the
|
|
||||||
ordinary substantive-output policy, then present the terminal explanation.
|
|
||||||
Quiet mode suppresses the report while retaining the explanation. Having a
|
|
||||||
report does not imply a successful outcome, and returning a failure does not
|
|
||||||
discard substantive output already prepared for delivery before the terminal step.
|
|
||||||
|
|
||||||
Debug output follows the same upstream disclosure and safe-rendering contracts.
|
|
||||||
Enabling debug does not authorize secret disclosure or bypass owning-library
|
|
||||||
rules.
|
|
||||||
|
|
||||||
## Delivery scope
|
|
||||||
|
|
||||||
The completed feature includes the selected reporter and outcome API, ordered
|
|
||||||
mode/progress selection through normal parsing, shared core presentation, and
|
|
||||||
both optional integration migrations. Passive provider diagnostics distinguish
|
|
||||||
independent messages from terminal explanations while preserving native evidence
|
|
||||||
and rendering. Existing command behavior remains unchanged outside the selected
|
|
||||||
reporting policy.
|
|
||||||
|
|
||||||
Maintained consumers demonstrate ordinary output, immediate/deferred messages,
|
|
||||||
silent recovery, explicit warnings, failure after partial output, optional cause
|
|
||||||
transport, and structured terminal explanations. Integration consumers include
|
|
||||||
native diagnostic context and useful reports returned alongside failures.
|
|
||||||
|
|
||||||
Behavioral coverage establishes CommandKit-owned parsing, visibility, ordering,
|
|
||||||
concurrent reporter coordination, closure, presentation observations, and failure
|
|
||||||
handling. It preserves existing alias, input/state, discovery, native-report,
|
|
||||||
and upstream-adapter protections without testing upstream domain correctness.
|
|
||||||
GoDoc, CLI documentation, consumer guidance, internal documentation, and release
|
|
||||||
notes describe the implemented boundary under their canonical ownership.
|
|
||||||
|
|
||||||
The [implementation plan](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/230187296fae5253cb1773f16c2f1d1a39499ed0/docs/roadmap/implementation.md) defines the concrete migration
|
|
||||||
steps, focused validation, and completion criteria. This roadmap defines the
|
|
||||||
target behavior and selected policy choices.
|
|
||||||
|
|
||||||
## Architectural preparation completed
|
|
||||||
|
|
||||||
- [x] Review and accept [ADR 0014](../adr/0014-invocation-reporting.md) as an
|
|
||||||
extension for shared reporting, retaining ADR 0005's outcome and supplied-error
|
|
||||||
preservation decisions.
|
|
||||||
- [x] Align the [architecture policy](../policy/architecture.md) with the reporting
|
|
||||||
ownership model, including application ownership of domain-specific error
|
|
||||||
decisions and scope for useful shared error helpers.
|
|
||||||
|
|
||||||
OD-1 through OD-4 and the consumer API signatures are selected. The target end
|
|
||||||
state includes maintained, executable consumers using those APIs; the
|
|
||||||
[implementation plan](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/230187296fae5253cb1773f16c2f1d1a39499ed0/docs/roadmap/implementation.md) owns their delivery sequence.
|
|
||||||
@@ -26,8 +26,7 @@ and try completing `core-example report d` or `core-example ws gr`.
|
|||||||
|
|
||||||
Compatible integration factories also return `commandkit.Command` and can be
|
Compatible integration factories also return `commandkit.Command` and can be
|
||||||
passed directly to `New` beside `commandkit.Alias` or flag-alias declarations.
|
passed directly to `New` beside `commandkit.Alias` or flag-alias declarations.
|
||||||
The ckconfig candidate uses the new core identity; ckprompt will use it in its
|
The matched ckconfig and ckprompt releases use the new core identity. For a
|
||||||
planned matched release. For a
|
|
||||||
command-only `[]commandkit.Command`, convert its elements into a
|
command-only `[]commandkit.Command`, convert its elements into a
|
||||||
`[]commandkit.Declaration` before appending routing rules; Go cannot expand the
|
`[]commandkit.Declaration` before appending routing rules; Go cannot expand the
|
||||||
command slice as `...commandkit.Declaration`. The
|
command slice as `...commandkit.Declaration`. The
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ itself.
|
|||||||
|
|
||||||
## Module
|
## Module
|
||||||
|
|
||||||
The module path is `go.maximumdirect.net/ckconfig`. Version v0.2.0 uses
|
The module path is `go.maximumdirect.net/ckconfig`. The prepared v0.3.0
|
||||||
`go.maximumdirect.net/commandkit v0.3.0` and
|
candidate requires Go 1.27.0 and uses `go.maximumdirect.net/commandkit v0.3.0` and
|
||||||
ConfigKit; it does not import PromptKit. See the
|
`go.maximumdirect.net/configkit v1.1.0`; it does not import PromptKit. See the
|
||||||
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
|
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
|
||||||
for exact callback and lifetime contracts.
|
for exact callback and lifetime contracts.
|
||||||
|
|
||||||
@@ -26,9 +26,9 @@ scopes, selectors, input checks, and state shared by the selected acquisitions
|
|||||||
or comparison in a config invocation. `ckconfig.FromConfigKit` adapts a typed
|
or comparison in a config invocation. `ckconfig.FromConfigKit` adapts a typed
|
||||||
ConfigKit loader. The `config` command family exposes scope discovery and the
|
ConfigKit loader. The `config` command family exposes scope discovery and the
|
||||||
validate, show, sources, explain, and diff operations supported by the declared
|
validate, show, sources, explain, and diff operations supported by the declared
|
||||||
scopes. Source reports include native destination, placement, unresolved
|
scopes. Source reports include native destination, placement, destination
|
||||||
destination, and source version-check evidence. Comparison returns ConfigKit's
|
fallback, version evidence, and empty-import selections. Comparison returns
|
||||||
native records to the YAML report path; the
|
ConfigKit's native records to the YAML report path; the
|
||||||
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#compare-configuration-selections)
|
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#compare-configuration-selections)
|
||||||
owns its operator details.
|
owns its operator details.
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type adapterSettings struct {
|
type adapterSettings struct {
|
||||||
@@ -27,7 +27,7 @@ func adapterDefinition() configkit.Definition[adapterSettings] {
|
|||||||
validation.Warning(configkit.Keys("greeting"), "using the default greeting")
|
validation.Warning(configkit.Keys("greeting"), "using the default greeting")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Secret: func(path configkit.Path) bool { return path.String() == "/secret" },
|
Sensitive: func(path configkit.Path) bool { return path.String() == "/secret" },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ func TestFromConfigKitCompareIgnoresDefaultAndResolutionHistoryForEqualValues(t
|
|||||||
Resolve: func(value *resolvedSettings, resolution *configkit.Resolution) error {
|
Resolve: func(value *resolvedSettings, resolution *configkit.Resolution) error {
|
||||||
if value.Greeting != "resolved" {
|
if value.Greeting != "resolved" {
|
||||||
value.Greeting = "resolved"
|
value.Greeting = "resolved"
|
||||||
resolution.Record(configkit.Keys("greeting"), configkit.ChangeNormalization, "canonical greeting")
|
resolution.RecordNormalization(configkit.Keys("greeting"), "canonical greeting")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestComparisonCapabilitiesAreIndependentAndCaptured(t *testing.T) {
|
func TestComparisonCapabilitiesAreIndependentAndCaptured(t *testing.T) {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestComparisonSelectionInheritsFieldsIndependently(t *testing.T) {
|
func TestComparisonSelectionInheritsFieldsIndependently(t *testing.T) {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestComparisonPreparesEqualSelectionsWithSeparateTypedInputs(t *testing.T) {
|
func TestComparisonPreparesEqualSelectionsWithSeparateTypedInputs(t *testing.T) {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCompletionUsesInstalledScopeCapabilitiesWithoutAcquisition(t *testing.T) {
|
func TestCompletionUsesInstalledScopeCapabilitiesWithoutAcquisition(t *testing.T) {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FromConfigKit adapts a typed ConfigKit loader to all five native
|
// FromConfigKit adapts a typed ConfigKit loader to all five native
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Selection carries the configuration and overlay choices supplied for a
|
// Selection carries the configuration and overlay choices supplied for a
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWithScopeErrorCopiesAndRetainsCauses(t *testing.T) {
|
func TestWithScopeErrorCopiesAndRetainsCauses(t *testing.T) {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ func TestConfigDiffExecutesConcealedChangesAndEmptyResults(t *testing.T) {
|
|||||||
if selection.Config.Set && selection.Config.Value == "after" {
|
if selection.Config.Set && selection.Config.Value == "after" {
|
||||||
value = "changed-secret"
|
value = "changed-secret"
|
||||||
}
|
}
|
||||||
return configkit.Load(configkit.Mapping("selected", map[string]any{"secret": value}), configkit.Options[settings]{Definition: configkit.Definition[settings]{Secret: func(path configkit.Path) bool { return path.String() == "/secret" }}})
|
return configkit.Load(configkit.Mapping("selected", map[string]any{"secret": value}), configkit.Options[settings]{Definition: configkit.Definition[settings]{Sensitive: func(path configkit.Path) bool { return path.String() == "/secret" }}})
|
||||||
}))
|
}))
|
||||||
var output bytes.Buffer
|
var output bytes.Buffer
|
||||||
outcome := app.Execute(context.Background(), []string{"config", "diff", "--config", "before", "--against-config", "after"}, commandkit.Streams{Out: &output, Err: io.Discard})
|
outcome := app.Execute(context.Background(), []string{"config", "diff", "--config", "before", "--against-config", "after"}, commandkit.Streams{Out: &output, Err: io.Discard})
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "go.maximumdirect.net/configkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "go.maximumdirect.net/configkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ func TestRenderDiffReportPreservesNativeMasksAndMarkerLookingStrings(t *testing.
|
|||||||
Public string `yaml:"public"`
|
Public string `yaml:"public"`
|
||||||
Secret string `yaml:"secret"`
|
Secret string `yaml:"secret"`
|
||||||
}
|
}
|
||||||
definition := configkit.Definition[settings]{Secret: func(path configkit.Path) bool { return path.String() == "/secret" }}
|
definition := configkit.Definition[settings]{Sensitive: func(path configkit.Path) bool { return path.String() == "/secret" }}
|
||||||
load := func(public, secret string) *configkit.Result[settings] {
|
load := func(public, secret string) *configkit.Result[settings] {
|
||||||
result, err := configkit.Load(configkit.Mapping("configuration", map[string]any{"public": public, "secret": secret}), configkit.Options[settings]{Definition: definition})
|
result, err := configkit.Load(configkit.Mapping("configuration", map[string]any{"public": public, "secret": secret}), configkit.Options[settings]{Definition: definition})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Package ckconfig, provided by go.maximumdirect.net/ckconfig, provides
|
// Package ckconfig, provided by go.maximumdirect.net/ckconfig, provides
|
||||||
// CommandKit's optional ConfigKit integration. Its
|
// CommandKit's optional ConfigKit v1.1.0 integration, requiring Go 1.27.0. Its
|
||||||
// canonical Command declaration installs the standard config command family
|
// canonical Command declaration installs the standard config command family
|
||||||
// through the core commandkit package. Applications can install CommandKit
|
// through the core commandkit package. Applications can install CommandKit
|
||||||
// RoutingRule declarations alongside it through commandkit.New or
|
// RoutingRule declarations alongside it through commandkit.New or
|
||||||
// App.Register. Source reports preserve ConfigKit's destination, placement,
|
// App.Register. Source reports preserve ConfigKit's destination, placement,
|
||||||
// and version-check evidence. Invocation reporting applies CommandKit's shared
|
// version, and empty-import evidence. Invocation reporting applies CommandKit's shared
|
||||||
// visibility and delivery policy; provider warnings remain independent of
|
// visibility and delivery policy; provider warnings remain independent of
|
||||||
// failure explanations. Importing ckconfig alone installs no commands.
|
// failure explanations. Importing ckconfig alone installs no commands.
|
||||||
package ckconfig
|
package ckconfig
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
## ConfigKit
|
## ConfigKit
|
||||||
|
|
||||||
Selected module: `gitea.maximumdirect.net/eric/ConfigKit` at `v0.8.0`.
|
Selected module: `go.maximumdirect.net/configkit` at `v1.1.0`.
|
||||||
|
|
||||||
Copyright (C) 2026 Eric Rakestraw
|
Copyright (C) 2026 Eric Rakestraw
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-or-later
|
SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
License and notices: [LGPL v3.0](../../LICENSE) |
|
License and notices: [LGPL v3.0](../../LICENSE) |
|
||||||
[LICENSE](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5/LICENSE).
|
[LICENSE](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9/LICENSE).
|
||||||
|
|
||||||
[Source](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/137769f3f18a370c68444242fb5d88e620e307e5).
|
[Source](https://forge.maximumdirect.net/base-layer/configkit/src/commit/191015e289d7f2b91abb9fdd9c4f2f5cf75b4de9).
|
||||||
|
|
||||||
## go-yaml v4
|
## go-yaml v4
|
||||||
|
|
||||||
@@ -153,19 +153,6 @@ License and notices: [MIT](licenses/MIT.txt) |
|
|||||||
|
|
||||||
## ReleaseKit
|
## ReleaseKit
|
||||||
|
|
||||||
Selected module: `gitea.maximumdirect.net/eric/ReleaseKit` at `v0.4.1` (transitive Go tool requirement; not a runtime import).
|
|
||||||
|
|
||||||
Copyright (C) 2026 Eric Rakestraw
|
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
|
|
||||||
License and notices: [LGPL v3.0](../../LICENSE) |
|
|
||||||
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469/LICENSE).
|
|
||||||
|
|
||||||
[Source](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469).
|
|
||||||
|
|
||||||
## ReleaseKit (vanity module)
|
|
||||||
|
|
||||||
Selected module: `go.maximumdirect.net/releasekit` at `v0.9.0` (transitive Go tool requirement; not a runtime import).
|
Selected module: `go.maximumdirect.net/releasekit` at `v0.9.0` (transitive Go tool requirement; not a runtime import).
|
||||||
|
|
||||||
Copyright (C) 2026 Eric Rakestraw
|
Copyright (C) 2026 Eric Rakestraw
|
||||||
|
|||||||
25
integrations/ckconfig/docs/releases/v0.3.0.md
Normal file
25
integrations/ckconfig/docs/releases/v0.3.0.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# CommandKit ckconfig v0.3.0
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
This candidate adopts `go.maximumdirect.net/configkit v1.1.0` and requires Go
|
||||||
|
1.27.0, while retaining `go.maximumdirect.net/commandkit v0.3.0`. It updates
|
||||||
|
configuration source reports to expose ConfigKit's current evidence.
|
||||||
|
|
||||||
|
## Migration
|
||||||
|
|
||||||
|
Change ConfigKit imports from `gitea.maximumdirect.net/eric/ConfigKit` to
|
||||||
|
`go.maximumdirect.net/configkit`. Values from the two paths have distinct Go
|
||||||
|
type identities. Update application loaders and provider values together with
|
||||||
|
ckconfig. Published ckprompt v0.2.0 continues to use ckconfig v0.2.0 and the old
|
||||||
|
ConfigKit identity; it does not compose with this candidate.
|
||||||
|
|
||||||
|
Source reports rename `destination_unresolved` to `destination_is_fallback` and
|
||||||
|
`version_check` to `version_evidence`, use the native `main` layer name, and add
|
||||||
|
`empty_import_selections` records (or `[]` when empty). Update report consumers.
|
||||||
|
See the [consumer migration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/docs/consumers/guide.md#configkit-v11-migration)
|
||||||
|
for links to upstream configuration and API changes.
|
||||||
|
|
||||||
|
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/integrations/ckconfig/COPYRIGHT) |
|
||||||
|
[LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/integrations/ckconfig/LICENSE) |
|
||||||
|
[ATTRIBUTION](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckconfig/v0.3.0/integrations/ckconfig/docs/oss/attribution.md)
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
# Simple consumer
|
# Simple consumer
|
||||||
|
|
||||||
This example imports `go.maximumdirect.net/ckconfig` and
|
This example imports `go.maximumdirect.net/ckconfig` and
|
||||||
`go.maximumdirect.net/commandkit`; use ckconfig v0.2.0 with core v0.3.0.
|
`go.maximumdirect.net/commandkit`; use the ckconfig v0.3.0 candidate with core
|
||||||
|
v0.3.0, ConfigKit v1.1.0, and Go 1.27.0. Set `GOWORK=off GOTOOLCHAIN=local`
|
||||||
|
for the commands below.
|
||||||
|
|
||||||
Run the maintained example with:
|
Run the maintained example with:
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
"go.maximumdirect.net/ckconfig"
|
"go.maximumdirect.net/ckconfig"
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type appConfiguration struct {
|
type appConfiguration struct {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type explanationReport struct {
|
type explanationReport struct {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type scopeMetadata struct {
|
type scopeMetadata struct {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScopeDiscoveryIsOrderedAndDoesNotUseSuiteFactories(t *testing.T) {
|
func TestScopeDiscoveryIsOrderedAndDoesNotUseSuiteFactories(t *testing.T) {
|
||||||
@@ -441,6 +441,7 @@ func TestExplainParsesBeforeAcquisitionAndPreservesNativeSafeHistory(t *testing.
|
|||||||
value: configkit.Explanation{
|
value: configkit.Explanation{
|
||||||
Path: configkit.Path{},
|
Path: configkit.Path{},
|
||||||
Effective: configkit.ValueSnapshot{Present: true, Redacted: true},
|
Effective: configkit.ValueSnapshot{Present: true, Redacted: true},
|
||||||
|
Origin: configkit.Origin{Layer: configkit.LayerMain},
|
||||||
History: []configkit.ValueChange{{
|
History: []configkit.ValueChange{{
|
||||||
Before: configkit.ValueSnapshot{Present: true, Redacted: true},
|
Before: configkit.ValueSnapshot{Present: true, Redacted: true},
|
||||||
After: configkit.ValueSnapshot{Present: true, Redacted: true},
|
After: configkit.ValueSnapshot{Present: true, Redacted: true},
|
||||||
@@ -460,7 +461,7 @@ func TestExplainParsesBeforeAcquisitionAndPreservesNativeSafeHistory(t *testing.
|
|||||||
if outcome.Kind != commandkit.OutcomeSuccess || acquireCalls != 1 || reader.path.String() != "" {
|
if outcome.Kind != commandkit.OutcomeSuccess || acquireCalls != 1 || reader.path.String() != "" {
|
||||||
t.Fatalf("root explanation outcome=%#v calls=%d path=%q", outcome, acquireCalls, reader.path.String())
|
t.Fatalf("root explanation outcome=%#v calls=%d path=%q", outcome, acquireCalls, reader.path.String())
|
||||||
}
|
}
|
||||||
if strings.Contains(output.String(), "APP_TOKEN_VALUE") || !strings.Contains(output.String(), "redacted: true") || !strings.Contains(output.String(), "history:") || !strings.Contains(output.String(), "dependencies: []") || !strings.Contains(output.String(), "name: APP_TOKEN") {
|
if strings.Contains(output.String(), "APP_TOKEN_VALUE") || !strings.Contains(output.String(), "redacted: true") || !strings.Contains(output.String(), "layer: main") || !strings.Contains(output.String(), "history:") || !strings.Contains(output.String(), "dependencies: []") || !strings.Contains(output.String(), "name: APP_TOKEN") {
|
||||||
t.Fatalf("safe explanation report = %s", output.String())
|
t.Fatalf("safe explanation report = %s", output.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
module go.maximumdirect.net/ckconfig
|
module go.maximumdirect.net/ckconfig
|
||||||
|
|
||||||
go 1.26.0
|
go 1.27.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.maximumdirect.net/eric/ConfigKit v0.8.0
|
go.maximumdirect.net/commandkit v0.3.0
|
||||||
|
go.maximumdirect.net/configkit v1.1.0
|
||||||
go.yaml.in/yaml/v4 v4.0.0-rc.6
|
go.yaml.in/yaml/v4 v4.0.0-rc.6
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -11,5 +12,4 @@ require (
|
|||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/spf13/cobra v1.10.1 // indirect
|
github.com/spf13/cobra v1.10.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.9 // indirect
|
github.com/spf13/pflag v1.0.9 // indirect
|
||||||
go.maximumdirect.net/commandkit v0.3.0
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
gitea.maximumdirect.net/eric/ConfigKit v0.8.0 h1:xCIhYnOHjw7rFvB+vIremPKGeROOxKTomnUEUipuQno=
|
|
||||||
gitea.maximumdirect.net/eric/ConfigKit v0.8.0/go.mod h1:C82sbyKHYMV1OwaD2GJanFrwTfcZfjlW2JsGze5b0kA=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
@@ -10,6 +8,8 @@ github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
|||||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
go.maximumdirect.net/commandkit v0.3.0 h1:RCmg2GS8uzlLSJCIqarpn1uFDec0W3ylNNRRPT6kUFE=
|
go.maximumdirect.net/commandkit v0.3.0 h1:RCmg2GS8uzlLSJCIqarpn1uFDec0W3ylNNRRPT6kUFE=
|
||||||
go.maximumdirect.net/commandkit v0.3.0/go.mod h1:ZS98DewKNVBygKVDoh5MFD09CnPlP37dS9pVsID5Eoc=
|
go.maximumdirect.net/commandkit v0.3.0/go.mod h1:ZS98DewKNVBygKVDoh5MFD09CnPlP37dS9pVsID5Eoc=
|
||||||
|
go.maximumdirect.net/configkit v1.1.0 h1:UzXN2ZMnEkcL0O4YSLqD9qd9M1gb/NWCHQR/H8AaQzA=
|
||||||
|
go.maximumdirect.net/configkit v1.1.0/go.mod h1:s1zLJ9GGB/1Q4a+aOHMLISonJxWFgNWpA6SpPlOafeA=
|
||||||
go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4=
|
go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4=
|
||||||
go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type configCommandInput[I, S any] struct {
|
type configCommandInput[I, S any] struct {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,12 +22,19 @@ type sourceDTO struct {
|
|||||||
Path string `yaml:"path"`
|
Path string `yaml:"path"`
|
||||||
Destination string `yaml:"destination"`
|
Destination string `yaml:"destination"`
|
||||||
Placement string `yaml:"placement"`
|
Placement string `yaml:"placement"`
|
||||||
DestinationUnresolved bool `yaml:"destination_unresolved"`
|
DestinationIsFallback bool `yaml:"destination_is_fallback"`
|
||||||
Layer string `yaml:"layer"`
|
Layer string `yaml:"layer"`
|
||||||
Kind string `yaml:"kind"`
|
Kind string `yaml:"kind"`
|
||||||
UnderlayIndex int `yaml:"underlay_index"`
|
UnderlayIndex int `yaml:"underlay_index"`
|
||||||
ImportedFrom *locationDTO `yaml:"imported_from"`
|
ImportedFrom *locationDTO `yaml:"imported_from"`
|
||||||
VersionCheck *sourceVersionCheckDTO `yaml:"version_check"`
|
VersionEvidence *sourceVersionEvidenceDTO `yaml:"version_evidence"`
|
||||||
|
EmptyImportSelections []emptyImportSelectionDTO `yaml:"empty_import_selections"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type emptyImportSelectionDTO struct {
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
Location locationDTO `yaml:"location"`
|
||||||
|
Selector string `yaml:"selector"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type locationDTO struct {
|
type locationDTO struct {
|
||||||
@@ -36,7 +43,7 @@ type locationDTO struct {
|
|||||||
Column int `yaml:"column"`
|
Column int `yaml:"column"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type sourceVersionCheckDTO struct {
|
type sourceVersionEvidenceDTO struct {
|
||||||
Path string `yaml:"path"`
|
Path string `yaml:"path"`
|
||||||
Version versionDTO `yaml:"version"`
|
Version versionDTO `yaml:"version"`
|
||||||
Location *locationDTO `yaml:"location"`
|
Location *locationDTO `yaml:"location"`
|
||||||
@@ -89,17 +96,18 @@ func runConfigSources[I, S any](invocation commandkit.Invocation, plan *configOp
|
|||||||
Path: source.Path,
|
Path: source.Path,
|
||||||
Destination: source.Destination.String(),
|
Destination: source.Destination.String(),
|
||||||
Placement: placement,
|
Placement: placement,
|
||||||
DestinationUnresolved: source.DestinationUnresolved,
|
DestinationIsFallback: source.DestinationIsFallback,
|
||||||
Layer: string(source.Layer),
|
Layer: string(source.Layer),
|
||||||
Kind: string(source.Kind),
|
Kind: string(source.Kind),
|
||||||
UnderlayIndex: source.UnderlayIndex,
|
UnderlayIndex: source.UnderlayIndex,
|
||||||
|
EmptyImportSelections: make([]emptyImportSelectionDTO, 0, len(source.EmptyImportSelections)),
|
||||||
}
|
}
|
||||||
if source.ImportedFrom != nil {
|
if source.ImportedFrom != nil {
|
||||||
item.ImportedFrom = &locationDTO{SourceID: source.ImportedFrom.SourceID, Line: source.ImportedFrom.Line, Column: source.ImportedFrom.Column}
|
item.ImportedFrom = &locationDTO{SourceID: source.ImportedFrom.SourceID, Line: source.ImportedFrom.Line, Column: source.ImportedFrom.Column}
|
||||||
}
|
}
|
||||||
if source.VersionCheck != nil {
|
if source.VersionEvidence != nil {
|
||||||
check := source.VersionCheck
|
check := source.VersionEvidence
|
||||||
item.VersionCheck = &sourceVersionCheckDTO{
|
item.VersionEvidence = &sourceVersionEvidenceDTO{
|
||||||
Path: check.Path.String(),
|
Path: check.Path.String(),
|
||||||
Version: versionDTO{
|
Version: versionDTO{
|
||||||
Present: check.Version.Present,
|
Present: check.Version.Present,
|
||||||
@@ -109,9 +117,12 @@ func runConfigSources[I, S any](invocation commandkit.Invocation, plan *configOp
|
|||||||
Redacted: check.Redacted,
|
Redacted: check.Redacted,
|
||||||
}
|
}
|
||||||
if check.Location != nil {
|
if check.Location != nil {
|
||||||
item.VersionCheck.Location = &locationDTO{SourceID: check.Location.SourceID, Line: check.Location.Line, Column: check.Location.Column}
|
item.VersionEvidence.Location = &locationDTO{SourceID: check.Location.SourceID, Line: check.Location.Line, Column: check.Location.Column}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, selection := range source.EmptyImportSelections {
|
||||||
|
item.EmptyImportSelections = append(item.EmptyImportSelections, emptyImportSelectionDTO{Path: selection.Path.String(), Location: locationDTO{SourceID: selection.Location.SourceID, Line: selection.Location.Line, Column: selection.Location.Column}, Selector: string(selection.Selector)})
|
||||||
|
}
|
||||||
document.Sources = append(document.Sources, item)
|
document.Sources = append(document.Sources, item)
|
||||||
}
|
}
|
||||||
if err := invocation.Context.Err(); err != nil {
|
if err := invocation.Context.Err(); err != nil {
|
||||||
@@ -143,7 +154,7 @@ func writeSourceReportText(writer *bytes.Buffer, document sourceReport) {
|
|||||||
_, _ = fmt.Fprintf(writer, " path: %s\n", strconv.Quote(source.Path))
|
_, _ = fmt.Fprintf(writer, " path: %s\n", strconv.Quote(source.Path))
|
||||||
_, _ = fmt.Fprintf(writer, " destination: %s\n", strconv.Quote(source.Destination))
|
_, _ = fmt.Fprintf(writer, " destination: %s\n", strconv.Quote(source.Destination))
|
||||||
_, _ = fmt.Fprintf(writer, " placement: %s\n", strconv.Quote(source.Placement))
|
_, _ = fmt.Fprintf(writer, " placement: %s\n", strconv.Quote(source.Placement))
|
||||||
_, _ = fmt.Fprintf(writer, " destination_unresolved: %t\n", source.DestinationUnresolved)
|
_, _ = fmt.Fprintf(writer, " destination_is_fallback: %t\n", source.DestinationIsFallback)
|
||||||
_, _ = fmt.Fprintf(writer, " layer: %s\n", strconv.Quote(source.Layer))
|
_, _ = fmt.Fprintf(writer, " layer: %s\n", strconv.Quote(source.Layer))
|
||||||
_, _ = fmt.Fprintf(writer, " kind: %s\n", strconv.Quote(source.Kind))
|
_, _ = fmt.Fprintf(writer, " kind: %s\n", strconv.Quote(source.Kind))
|
||||||
_, _ = fmt.Fprintf(writer, " underlay_index: %d\n", source.UnderlayIndex)
|
_, _ = fmt.Fprintf(writer, " underlay_index: %d\n", source.UnderlayIndex)
|
||||||
@@ -153,12 +164,11 @@ func writeSourceReportText(writer *bytes.Buffer, document sourceReport) {
|
|||||||
_, _ = fmt.Fprintf(writer, " imported_from: {source_id: %s, line: %d, column: %d}\n",
|
_, _ = fmt.Fprintf(writer, " imported_from: {source_id: %s, line: %d, column: %d}\n",
|
||||||
strconv.Quote(source.ImportedFrom.SourceID), source.ImportedFrom.Line, source.ImportedFrom.Column)
|
strconv.Quote(source.ImportedFrom.SourceID), source.ImportedFrom.Line, source.ImportedFrom.Column)
|
||||||
}
|
}
|
||||||
if source.VersionCheck == nil {
|
if source.VersionEvidence == nil {
|
||||||
_, _ = writer.WriteString(" version_check: null\n")
|
_, _ = writer.WriteString(" version_evidence: null\n")
|
||||||
continue
|
} else {
|
||||||
}
|
check := source.VersionEvidence
|
||||||
check := source.VersionCheck
|
_, _ = fmt.Fprintf(writer, " version_evidence:\n path: %s\n", strconv.Quote(check.Path))
|
||||||
_, _ = fmt.Fprintf(writer, " version_check:\n path: %s\n", strconv.Quote(check.Path))
|
|
||||||
_, _ = fmt.Fprintf(writer, " version:\n present: %t\n null: %t\n text: %s\n",
|
_, _ = fmt.Fprintf(writer, " version:\n present: %t\n null: %t\n text: %s\n",
|
||||||
check.Version.Present, check.Version.Null, strconv.Quote(check.Version.Text))
|
check.Version.Present, check.Version.Null, strconv.Quote(check.Version.Text))
|
||||||
if check.Location == nil {
|
if check.Location == nil {
|
||||||
@@ -169,6 +179,15 @@ func writeSourceReportText(writer *bytes.Buffer, document sourceReport) {
|
|||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(writer, " redacted: %t\n", check.Redacted)
|
_, _ = fmt.Fprintf(writer, " redacted: %t\n", check.Redacted)
|
||||||
}
|
}
|
||||||
|
if len(source.EmptyImportSelections) == 0 {
|
||||||
|
_, _ = writer.WriteString(" empty_import_selections: []\n")
|
||||||
|
} else {
|
||||||
|
_, _ = writer.WriteString(" empty_import_selections:\n")
|
||||||
|
for _, selection := range source.EmptyImportSelections {
|
||||||
|
_, _ = fmt.Fprintf(writer, " - path: %s\n location: {source_id: %s, line: %d, column: %d}\n selector: %s\n", strconv.Quote(selection.Path), strconv.Quote(selection.Location.SourceID), selection.Location.Line, selection.Location.Column, strconv.Quote(selection.Selector))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeYAML(writer io.Writer, document any) error {
|
func encodeYAML(writer io.Writer, document any) error {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,13 +34,17 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
|
|||||||
reader := &sourceInventory{values: []configkit.SourceInfo{
|
reader := &sourceInventory{values: []configkit.SourceInfo{
|
||||||
{
|
{
|
||||||
ID: "root", Label: "root source", Path: "root.yml",
|
ID: "root", Label: "root source", Path: "root.yml",
|
||||||
PlacementMode: configkit.PlacementModeMapping,
|
PlacementMode: configkit.PlacementModeMapping, Layer: configkit.LayerMain,
|
||||||
|
EmptyImportSelections: []configkit.EmptyImportSelection{
|
||||||
|
{Path: configkit.Keys("imports", "first"), Location: configkit.Location{SourceID: "root.yml", Line: 3, Column: 4}, Selector: configkit.ImportSelectorGlob},
|
||||||
|
{Path: configkit.Keys("imports", "second"), Location: configkit.Location{}, Selector: configkit.ImportSelectorPath},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "item", Label: "sequence item", Path: "item.yml",
|
ID: "item", Label: "sequence item", Path: "item.yml",
|
||||||
Destination: servicePath, PlacementMode: configkit.PlacementModeSequenceItem,
|
Destination: servicePath, PlacementMode: configkit.PlacementModeSequenceItem,
|
||||||
DestinationUnresolved: true,
|
DestinationIsFallback: true,
|
||||||
VersionCheck: &configkit.SourceVersionCheck{
|
VersionEvidence: &configkit.SourceVersionEvidence{
|
||||||
Path: versionPath,
|
Path: versionPath,
|
||||||
Version: configkit.Version{Present: true, Text: "v2"},
|
Version: configkit.Version{Present: true, Text: "v2"},
|
||||||
Location: &configkit.Location{SourceID: "item.yml", Line: 4, Column: 2},
|
Location: &configkit.Location{SourceID: "item.yml", Line: 4, Column: 2},
|
||||||
@@ -49,7 +53,7 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ID: "null", Label: "null version", Path: "null.yml",
|
ID: "null", Label: "null version", Path: "null.yml",
|
||||||
Destination: otherPath, PlacementMode: configkit.PlacementModeMapping,
|
Destination: otherPath, PlacementMode: configkit.PlacementModeMapping,
|
||||||
VersionCheck: &configkit.SourceVersionCheck{
|
VersionEvidence: &configkit.SourceVersionEvidence{
|
||||||
Path: nullVersionPath,
|
Path: nullVersionPath,
|
||||||
Version: configkit.Version{Present: true, Null: true},
|
Version: configkit.Version{Present: true, Null: true},
|
||||||
Redacted: true,
|
Redacted: true,
|
||||||
@@ -73,8 +77,10 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
|
|||||||
ID string `yaml:"id"`
|
ID string `yaml:"id"`
|
||||||
Destination string `yaml:"destination"`
|
Destination string `yaml:"destination"`
|
||||||
Placement string `yaml:"placement"`
|
Placement string `yaml:"placement"`
|
||||||
DestinationUnresolved bool `yaml:"destination_unresolved"`
|
Layer string `yaml:"layer"`
|
||||||
VersionCheck *struct {
|
EmptyImportSelections []emptyImportSelectionDTO `yaml:"empty_import_selections"`
|
||||||
|
DestinationIsFallback bool `yaml:"destination_is_fallback"`
|
||||||
|
VersionEvidence *struct {
|
||||||
Path string `yaml:"path"`
|
Path string `yaml:"path"`
|
||||||
Version struct {
|
Version struct {
|
||||||
Present bool `yaml:"present"`
|
Present bool `yaml:"present"`
|
||||||
@@ -87,7 +93,7 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
|
|||||||
Column int `yaml:"column"`
|
Column int `yaml:"column"`
|
||||||
} `yaml:"location"`
|
} `yaml:"location"`
|
||||||
Redacted bool `yaml:"redacted"`
|
Redacted bool `yaml:"redacted"`
|
||||||
} `yaml:"version_check"`
|
} `yaml:"version_evidence"`
|
||||||
} `yaml:"sources"`
|
} `yaml:"sources"`
|
||||||
}
|
}
|
||||||
if err := yaml.Unmarshal(yamlOutput.Bytes(), &report); err != nil {
|
if err := yaml.Unmarshal(yamlOutput.Bytes(), &report); err != nil {
|
||||||
@@ -99,21 +105,31 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
|
|||||||
if got := []string{report.Sources[0].ID, report.Sources[1].ID, report.Sources[2].ID}; !reflect.DeepEqual(got, []string{"root", "item", "null"}) {
|
if got := []string{report.Sources[0].ID, report.Sources[1].ID, report.Sources[2].ID}; !reflect.DeepEqual(got, []string{"root", "item", "null"}) {
|
||||||
t.Fatalf("source order = %v", got)
|
t.Fatalf("source order = %v", got)
|
||||||
}
|
}
|
||||||
if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationUnresolved || root.VersionCheck != nil {
|
if root := report.Sources[0]; root.Destination != "" || root.Placement != "mapping" || root.DestinationIsFallback || root.VersionEvidence != nil || root.Layer != "main" {
|
||||||
t.Errorf("root source projection = %#v", root)
|
t.Errorf("root source projection = %#v", root)
|
||||||
}
|
}
|
||||||
|
wantSelections := []emptyImportSelectionDTO{
|
||||||
|
{Path: "/imports/first", Location: locationDTO{SourceID: "root.yml", Line: 3, Column: 4}, Selector: "glob"},
|
||||||
|
{Path: "/imports/second", Location: locationDTO{}, Selector: "path"},
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(report.Sources[0].EmptyImportSelections, wantSelections) || report.Sources[1].EmptyImportSelections == nil || len(report.Sources[1].EmptyImportSelections) != 0 {
|
||||||
|
t.Fatalf("import selections: %#v", report.Sources)
|
||||||
|
}
|
||||||
|
if strings.Contains(yamlOutput.String(), "destination_unresolved:") || strings.Contains(yamlOutput.String(), "version_check:") {
|
||||||
|
t.Fatal("legacy YAML keys present")
|
||||||
|
}
|
||||||
item := report.Sources[1]
|
item := report.Sources[1]
|
||||||
if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationUnresolved {
|
if item.Destination != "/services" || item.Placement != "sequence_item" || !item.DestinationIsFallback {
|
||||||
t.Errorf("sequence item projection = %#v", item)
|
t.Errorf("sequence item projection = %#v", item)
|
||||||
}
|
}
|
||||||
if check := item.VersionCheck; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted {
|
if check := item.VersionEvidence; check == nil || check.Path != "/version" || !check.Version.Present || check.Version.Null || check.Version.Text != "v2" || check.Location == nil || check.Location.SourceID != "item.yml" || check.Location.Line != 4 || check.Location.Column != 2 || check.Redacted {
|
||||||
t.Errorf("text version evidence projection = %#v", check)
|
t.Errorf("text version evidence projection = %#v", check)
|
||||||
}
|
}
|
||||||
nullSource := report.Sources[2]
|
nullSource := report.Sources[2]
|
||||||
if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationUnresolved {
|
if nullSource.Destination != "/other" || nullSource.Placement != "mapping" || nullSource.DestinationIsFallback {
|
||||||
t.Errorf("mapping projection = %#v", nullSource)
|
t.Errorf("mapping projection = %#v", nullSource)
|
||||||
}
|
}
|
||||||
if check := nullSource.VersionCheck; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted {
|
if check := nullSource.VersionEvidence; check == nil || check.Path != "/metadata/version" || !check.Version.Present || !check.Version.Null || check.Version.Text != "" || check.Location != nil || !check.Redacted {
|
||||||
t.Errorf("null/redacted version evidence projection = %#v", check)
|
t.Errorf("null/redacted version evidence projection = %#v", check)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,9 +138,15 @@ func TestSourcesProjectNativeEvidenceInTextAndYAML(t *testing.T) {
|
|||||||
if outcome.Kind != commandkit.OutcomeSuccess || reader.calls != 2 {
|
if outcome.Kind != commandkit.OutcomeSuccess || reader.calls != 2 {
|
||||||
t.Fatalf("text source report outcome=%#v calls=%d", outcome, reader.calls)
|
t.Fatalf("text source report outcome=%#v calls=%d", outcome, reader.calls)
|
||||||
}
|
}
|
||||||
|
if strings.Contains(textOutput.String(), "destination_unresolved:") || strings.Contains(textOutput.String(), "version_check:") {
|
||||||
|
t.Fatal("legacy text keys present")
|
||||||
|
}
|
||||||
|
if strings.Index(textOutput.String(), `path: "/imports/first"`) > strings.Index(textOutput.String(), `path: "/imports/second"`) {
|
||||||
|
t.Fatal("import selection order changed")
|
||||||
|
}
|
||||||
for _, fragment := range []string{
|
for _, fragment := range []string{
|
||||||
`id: "root"`, `destination: ""`, `placement: "mapping"`, "destination_unresolved: false", "version_check: null",
|
`id: "root"`, `destination: ""`, `placement: "mapping"`, `layer: "main"`, "destination_is_fallback: false", "version_evidence: null", `path: "/imports/first"`, `location: {source_id: "root.yml", line: 3, column: 4}`, `selector: "glob"`, `path: "/imports/second"`, `location: {source_id: "", line: 0, column: 0}`, `selector: "path"`, "empty_import_selections: []",
|
||||||
`destination: "/services"`, `placement: "sequence_item"`, "destination_unresolved: true", `path: "/version"`, `text: "v2"`,
|
`destination: "/services"`, `placement: "sequence_item"`, "destination_is_fallback: true", `path: "/version"`, `text: "v2"`,
|
||||||
`destination: "/other"`, `path: "/metadata/version"`, "null: true", `text: ""`, "location: null", "redacted: true",
|
`destination: "/other"`, `path: "/metadata/version"`, "null: true", `text: ""`, "location: null", "redacted: true",
|
||||||
} {
|
} {
|
||||||
if !strings.Contains(textOutput.String(), fragment) {
|
if !strings.Contains(textOutput.String(), fragment) {
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ Importing it does not install either command family.
|
|||||||
|
|
||||||
## Module
|
## Module
|
||||||
|
|
||||||
The module path is
|
The module path is `go.maximumdirect.net/ckprompt`. Version v0.2.0 uses
|
||||||
`gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt`. Its first
|
`go.maximumdirect.net/commandkit v0.3.0`, `go.maximumdirect.net/ckconfig v0.2.0`,
|
||||||
release is prepared as `v0.1.0`. It uses `commandkit`, `ckconfig`, and
|
and PromptKit v0.16.0. See the
|
||||||
PromptKit. See the
|
|
||||||
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-and-definitions)
|
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#promptkit-configuration-and-definitions)
|
||||||
for callback, input, state, and acquisition contracts.
|
for callback, input, state, and acquisition contracts.
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PromptRequest selects one named prompt for inspection.
|
// PromptRequest selects one named prompt for inspection.
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
const adapterPrompt = `prompts:
|
const adapterPrompt = `prompts:
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
"go.maximumdirect.net/ckprompt"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package ckprompt
|
package ckprompt
|
||||||
|
|
||||||
import commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
import commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
|
||||||
func completionChoices(values ...string) commandkit.CompletionHint {
|
func completionChoices(values ...string) commandkit.CompletionHint {
|
||||||
choices := make([]commandkit.CompletionChoice, len(values))
|
choices := make([]commandkit.CompletionChoice, len(values))
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
"go.maximumdirect.net/ckprompt"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type compositionInput struct{ Campaign commandkit.Supplied[string] }
|
type compositionInput struct{ Campaign commandkit.Supplied[string] }
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Package ckprompt provides optional PromptKit configuration comparison,
|
// Package ckprompt, provided by go.maximumdirect.net/ckprompt, provides optional
|
||||||
|
// PromptKit configuration comparison,
|
||||||
// prompt catalogs, named inspections, requirements discovery and validation,
|
// prompt catalogs, named inspections, requirements discovery and validation,
|
||||||
// and native smoke testing for CommandKit. Its command factories return
|
// and native smoke testing for CommandKit. Its command factories return
|
||||||
// canonical commandkit.Command declarations. Applications can install
|
// canonical commandkit.Command declarations. Applications can install
|
||||||
|
|||||||
@@ -28,16 +28,29 @@ License and notices: [LGPL v3.0](../../LICENSE) |
|
|||||||
|
|
||||||
## ReleaseKit
|
## ReleaseKit
|
||||||
|
|
||||||
Selected module: `gitea.maximumdirect.net/eric/ReleaseKit` at `v0.4.2` (transitive Go tool requirement; not a runtime import).
|
Selected module: `gitea.maximumdirect.net/eric/ReleaseKit` at `v0.4.1` (transitive Go tool requirement; not a runtime import).
|
||||||
|
|
||||||
Copyright (C) 2026 Eric Rakestraw
|
Copyright (C) 2026 Eric Rakestraw
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-or-later
|
SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
License and notices: [LGPL v3.0](../../LICENSE) |
|
License and notices: [LGPL v3.0](../../LICENSE) |
|
||||||
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/7d033c5ca1c95aec7db9690293638a0a1ac887b8/LICENSE).
|
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469/LICENSE).
|
||||||
|
|
||||||
[Source](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/7d033c5ca1c95aec7db9690293638a0a1ac887b8).
|
[Source](https://gitea.maximumdirect.net/eric/ReleaseKit/src/commit/2d5a8110c61e31daf8698766114ae305d0e0e469).
|
||||||
|
|
||||||
|
## ReleaseKit (vanity module)
|
||||||
|
|
||||||
|
Selected module: `go.maximumdirect.net/releasekit` at `v0.9.0` (transitive Go tool requirement; not a runtime import).
|
||||||
|
|
||||||
|
Copyright (C) 2026 Eric Rakestraw
|
||||||
|
|
||||||
|
SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
License and notices: [LGPL v3.0](../../LICENSE) |
|
||||||
|
[LICENSE](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4/LICENSE).
|
||||||
|
|
||||||
|
[Source](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/2180aa868ec2caa95fc8279fd59d5f0ebac41bd4).
|
||||||
|
|
||||||
## JSON Schema
|
## JSON Schema
|
||||||
|
|
||||||
|
|||||||
36
integrations/ckprompt/docs/releases/v0.2.0.md
Normal file
36
integrations/ckprompt/docs/releases/v0.2.0.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# CommandKit ckprompt v0.2.0
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
CommandKit ckprompt v0.2.0 moves the PromptKit integration to
|
||||||
|
`go.maximumdirect.net/ckprompt`. It uses core
|
||||||
|
`go.maximumdirect.net/commandkit v0.3.0`,
|
||||||
|
`go.maximumdirect.net/ckconfig v0.2.0`, PromptKit v0.16.0, and ConfigKit v0.8.0.
|
||||||
|
The integration adopts core's invocation reporting and completion contracts
|
||||||
|
while preserving PromptKit's inspection, validation, and smoke semantics.
|
||||||
|
|
||||||
|
## Migration
|
||||||
|
|
||||||
|
Replace imports of `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt`
|
||||||
|
with `go.maximumdirect.net/ckprompt`; update core and ckconfig imports to
|
||||||
|
`go.maximumdirect.net/commandkit` and `go.maximumdirect.net/ckconfig`. Select
|
||||||
|
core v0.3.0 and both integration modules at v0.2.0 as a matched set. Old and
|
||||||
|
new core paths identify different Go packages and their types cannot be mixed.
|
||||||
|
|
||||||
|
Handlers use `Invocation.Reporter()` for output and categorized messages;
|
||||||
|
terminal failures carry an explanation and optional cause. The integration
|
||||||
|
submits provider diagnostics through the reporter, respecting shared reporting
|
||||||
|
flags. Replace uses of `Invocation.Streams`, `Outcome.Diagnostics`, and the
|
||||||
|
old error-first failure API as described in the
|
||||||
|
[core migration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/v0.3.0/docs/consumers/guide.md#invocation-reporting).
|
||||||
|
PromptKit commands provide completion hints when the application installs the
|
||||||
|
core completion command. Command and flag aliases remain application owned.
|
||||||
|
|
||||||
|
Go 1.26.0 remains the consumer minimum. Importing ckprompt installs no commands;
|
||||||
|
compose configuration scopes and the PromptKit command family explicitly. See
|
||||||
|
the [module README](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/README.md)
|
||||||
|
and [consumer guide](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/docs/consumers/guide.md#promptkit-configuration-and-definitions).
|
||||||
|
|
||||||
|
[COPYRIGHT](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/COPYRIGHT) |
|
||||||
|
[LICENSE](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/LICENSE) |
|
||||||
|
[ATTRIBUTION](https://forge.maximumdirect.net/base-layer/commandkit/src/tag/integrations/ckprompt/v0.2.0/integrations/ckprompt/docs/oss/attribution.md)
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
# Composed consumer
|
# Composed consumer
|
||||||
|
|
||||||
|
This example uses `go.maximumdirect.net/commandkit v0.3.0`,
|
||||||
|
`go.maximumdirect.net/ckconfig v0.2.0`, and
|
||||||
|
`go.maximumdirect.net/ckprompt v0.2.0`.
|
||||||
|
|
||||||
This example composes application configuration, PromptKit configuration,
|
This example composes application configuration, PromptKit configuration,
|
||||||
PromptKit comparison and catalogs, definition and requirements inspection, and
|
PromptKit comparison and catalogs, definition and requirements inspection, and
|
||||||
one application-owned command:
|
one application-owned command:
|
||||||
@@ -121,11 +125,7 @@ the selected campaign but leaves artifact bindings to the operator. The
|
|||||||
`requirements show` commands remain discovery reports: partial discovery can
|
`requirements show` commands remain discovery reports: partial discovery can
|
||||||
succeed even when a concrete request would fail validation.
|
succeed even when a concrete request would fail validation.
|
||||||
|
|
||||||
The alias examples use the local CommandKit source because the composed
|
Run `GOWORK=off go test ./...` from this example directory to check it against
|
||||||
module's published core dependency, v0.2.0, predates alias declarations. From
|
the module's declared dependencies. A local workspace can instead select the
|
||||||
the repository root, add the three local modules to `go.work` as described in
|
three current sources, as described in the
|
||||||
the [developer guide](../../../../docs/development.md#documentation-validation),
|
[developer guide](../../../../docs/development.md#documentation-validation).
|
||||||
then run `go test ./...` from this example directory. This checks the example
|
|
||||||
against the current local core and integration sources; it does not claim that
|
|
||||||
published v0.2.0 supports aliases. The next core dependency adoption is handled
|
|
||||||
after the core release is prepared.
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
"go.maximumdirect.net/ckprompt"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type campaign struct {
|
type campaign struct {
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
"go.maximumdirect.net/ckprompt"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
module gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt
|
module go.maximumdirect.net/ckprompt
|
||||||
|
|
||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.maximumdirect.net/eric/CommandKit v0.2.0
|
|
||||||
gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig v0.1.0
|
|
||||||
gitea.maximumdirect.net/eric/ConfigKit v0.8.0
|
gitea.maximumdirect.net/eric/ConfigKit v0.8.0
|
||||||
gitea.maximumdirect.net/eric/promptkit v0.16.0
|
gitea.maximumdirect.net/eric/promptkit v0.16.0
|
||||||
go.yaml.in/yaml/v4 v4.0.0-rc.6
|
go.yaml.in/yaml/v4 v4.0.0-rc.6
|
||||||
@@ -15,5 +13,7 @@ require (
|
|||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
||||||
github.com/spf13/cobra v1.10.1 // indirect
|
github.com/spf13/cobra v1.10.1 // indirect
|
||||||
github.com/spf13/pflag v1.0.9 // indirect
|
github.com/spf13/pflag v1.0.9 // indirect
|
||||||
|
go.maximumdirect.net/ckconfig v0.2.0
|
||||||
|
go.maximumdirect.net/commandkit v0.3.0
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
gitea.maximumdirect.net/eric/CommandKit v0.2.0 h1:UNBjSq6XDZHdPqvZLOL3N5R1E1ol0jnfldgradU7eqw=
|
|
||||||
gitea.maximumdirect.net/eric/CommandKit v0.2.0/go.mod h1:47DQ6Mo/yZqUVn5PAFRmPck91Zhf1jfaHDMoEZvUzsQ=
|
|
||||||
gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig v0.1.0 h1:qqgaCKrraUL//1vcoU+KUlQ5PNX0EtRpqsUraSiUW/w=
|
|
||||||
gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig v0.1.0/go.mod h1:SFtsgbTVQd+BCGQVCFSAopl55pGYhP1sSF442KFpSYA=
|
|
||||||
gitea.maximumdirect.net/eric/ConfigKit v0.8.0 h1:xCIhYnOHjw7rFvB+vIremPKGeROOxKTomnUEUipuQno=
|
gitea.maximumdirect.net/eric/ConfigKit v0.8.0 h1:xCIhYnOHjw7rFvB+vIremPKGeROOxKTomnUEUipuQno=
|
||||||
gitea.maximumdirect.net/eric/ConfigKit v0.8.0/go.mod h1:C82sbyKHYMV1OwaD2GJanFrwTfcZfjlW2JsGze5b0kA=
|
gitea.maximumdirect.net/eric/ConfigKit v0.8.0/go.mod h1:C82sbyKHYMV1OwaD2GJanFrwTfcZfjlW2JsGze5b0kA=
|
||||||
gitea.maximumdirect.net/eric/promptkit v0.16.0 h1:g3dhN0QfzQriaVOBmGUZCw2iBM9Mli2AAU4CbMfzcuY=
|
gitea.maximumdirect.net/eric/promptkit v0.16.0 h1:g3dhN0QfzQriaVOBmGUZCw2iBM9Mli2AAU4CbMfzcuY=
|
||||||
@@ -18,6 +14,10 @@ github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
|
|||||||
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
||||||
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
||||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
go.maximumdirect.net/ckconfig v0.2.0 h1:gcv9Opp9RFgx1cupXq7Uf+P2UWh2FZGYwp+pFY7gmfg=
|
||||||
|
go.maximumdirect.net/ckconfig v0.2.0/go.mod h1:FR25dNBQCB3rPkmmrccct19SIlbW9mHra6DHx98h10c=
|
||||||
|
go.maximumdirect.net/commandkit v0.3.0 h1:RCmg2GS8uzlLSJCIqarpn1uFDec0W3ylNNRRPT6kUFE=
|
||||||
|
go.maximumdirect.net/commandkit v0.3.0/go.mod h1:ZS98DewKNVBygKVDoh5MFD09CnPlP37dS9pVsID5Eoc=
|
||||||
go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4=
|
go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4=
|
||||||
go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBundledNativeFailuresReachTerminalExplanation(t *testing.T) {
|
func TestBundledNativeFailuresReachTerminalExplanation(t *testing.T) {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cancelDuringYAML struct{ cancel context.CancelFunc }
|
type cancelDuringYAML struct{ cancel context.CancelFunc }
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SmokeRequest pairs the configuration selection with the seed request for one
|
// SmokeRequest pairs the configuration selection with the seed request for one
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type smokeCommandInput[I any] struct {
|
type smokeCommandInput[I any] struct {
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSmokeTestCommandRetainsSingletonValuesAndResetsInvocations(t *testing.T) {
|
func TestSmokeTestCommandRetainsSingletonValuesAndResetsInvocations(t *testing.T) {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package ckprompt
|
package ckprompt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidationRequest carries the configuration selection and seed PromptKit
|
// ValidationRequest carries the configuration selection and seed PromptKit
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type validationFailOnGenerate struct{ calls int }
|
type validationFailOnGenerate struct{ calls int }
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type validationCommandInput[I any] struct {
|
type validationCommandInput[I any] struct {
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
|
||||||
"gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig"
|
|
||||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
promptkit "gitea.maximumdirect.net/eric/promptkit"
|
||||||
|
"go.maximumdirect.net/ckconfig"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user