726 lines
42 KiB
Markdown
726 lines
42 KiB
Markdown
# Application-owned aliases implementation plan
|
|
|
|
Status: ready for implementation; no stages completed.
|
|
|
|
## Authority, baseline, and scope
|
|
|
|
Implement [Application-owned aliases](aliases.md), governed by
|
|
[ADR 0013](../adr/0013-application-alias-routing.md),
|
|
[ADR 0011](../adr/0011-captured-declarations-and-installation.md), and the
|
|
[architecture policy](../policy/architecture.md). The feature roadmap owns the
|
|
selected behavior; this document owns the work sequence and implementation
|
|
choices. Follow the [agent](../policy/agents.md),
|
|
[testing](../policy/testing.md), and [documentation](../policy/documentation.md)
|
|
policies. Read [the developer guide](../development.md) first.
|
|
|
|
The inspected baseline is commit `f3b8a129d99d04230f998d0327ffad05f6002d7a`.
|
|
Core v0.2.0, ckconfig v0.1.0, and ckprompt v0.1.0 have been published.
|
|
`New` and `Register` currently accept `...Command`; there are no routing-rule
|
|
declarations. `Invocation` currently contains context and streams only.
|
|
The Cobra adapter selects canonical commands, parses their flags, and renders
|
|
help. Core owns typed conversion, input construction, dispatch, and outcomes.
|
|
|
|
This sprint delivers command and flag alias declarations, joint installation,
|
|
resolution, invocation identity, help, diagnostics, examples, and documentation.
|
|
It includes the selected canonical short-option empty-value correction.
|
|
It does not implement operand synonyms, preset arguments, shell completion,
|
|
new upstream operations, a replacement backend, or release publication.
|
|
|
|
## How to execute the plan
|
|
|
|
- Perform Stage 1 through Stage 17 in order. Each stage is sized as a separate
|
|
Luna implementation prompt. Add its completion evidence here and commit each
|
|
completed nonempty unit under the agent policy.
|
|
- Inspect the current tree before editing; preserve unrelated work. Prefer the
|
|
code knowledge graph for code discovery, falling back when it is insufficient.
|
|
- Reuse current behavior and tests where they express accepted contracts.
|
|
Replace mechanics when needed; do not add compatibility wrappers around the
|
|
old installation signatures or a second application parsing lifecycle.
|
|
- Stages include the focused tests needed for their work. Run those during
|
|
implementation, not during this planning pass. Do not make later stages
|
|
depend on unverified termination or token-interpretation assumptions.
|
|
- Keep tests about CommandKit adaptation, presentation, and lifetimes. Upstream
|
|
libraries own their domain tests. Use local callbacks and fixtures; no live
|
|
providers or credentials are needed.
|
|
- Preserve eager declaration capture, reusable declarations, namespace ownership,
|
|
binding identity, presence, wrapped causes, and existing outcome delivery.
|
|
Do not add concurrent-dispatch, arbitrary deep-copy, performance, or public
|
|
ordering guarantees.
|
|
- New private records and helpers described below are implementation choices.
|
|
Their names and exact organization can change without altering public behavior.
|
|
Do not expose them through the facade or add backend selection APIs.
|
|
- Keep published release records unchanged. Local source verification does not
|
|
authorize creating tags, pushing, or publishing another release.
|
|
|
|
## Implementation decisions used by the stages
|
|
|
|
### Owners and data flow
|
|
|
|
| Owner | Work |
|
|
| --- | --- |
|
|
| Root `commandkit` package | Public declarations, retained errors, candidate installation, alias records, routing coordination, invocation identity, typed conversion, and outcome presentation. |
|
|
| New `internal/commandpath` package | Shared path representation and token/path operations used by core, neutral metadata, and the adapter. It has no backend or optional-library imports. |
|
|
| New `internal/alias` package | Private command-prefix lookup and termination analysis over paths; no handlers, application factories, or backend types. Keep its model limited to the selected routing rules. |
|
|
| `internal/commandmeta` | Neutral canonical metadata and the routing, spelling-provenance, and help-view records actually needed across the adapter boundary. |
|
|
| `internal/cobra` | Canonical backend sessions, alias-aware flag interpretation, and rendering selected help views without installing alias command nodes. |
|
|
| Optional integrations | Continue returning canonical `Command` declarations and owning their providers. Only source migrations, focused composition evidence, and maintained consumer changes are needed here. |
|
|
|
|
Core retains canonical commands and routing rules separately. A candidate
|
|
installation compiles relationships against the complete prospective registry,
|
|
then publishes them together. Derived lookup metadata is reusable within an App;
|
|
parse state and entered-route provenance remain invocation-local.
|
|
|
|
Use the same private route lookup for execution, explicit help-target lookup,
|
|
and discovery-help views. It returns a canonical command identity or a distinct
|
|
alias-prefix discovery context, plus entered/canonical paths and remaining
|
|
arguments. Keep lookup independent of execution and rendering. This is current
|
|
routing/help machinery, not a completion API.
|
|
|
|
### Public declarations and invalid values
|
|
|
|
Implement the roadmap's signatures:
|
|
|
|
```go
|
|
type Declaration interface { commandkitDeclaration() }
|
|
|
|
func New(identity Identity, declarations ...Declaration) (*App, error)
|
|
func (a *App) Register(declarations ...Declaration) error
|
|
|
|
func Alias(path, target string) RoutingRule
|
|
func FlagAlias(spelling, target string) RoutingRule
|
|
func FlagAliasFor(commandPath, spelling, target string) RoutingRule
|
|
|
|
func (inv Invocation) EnteredPath() string
|
|
func (inv Invocation) CanonicalPath() string
|
|
```
|
|
|
|
`Command` and opaque `RoutingRule` implement the private marker. Their factories
|
|
capture values and retain errors; alias factories do not return errors or run
|
|
callbacks. Keep `Group`, `RootGroup`, and `CommandSpec.Children` command-only.
|
|
`WithError` and `NoCommand` keep their current command contracts; do not add an
|
|
absence rule or a general extension/plugin declaration kind.
|
|
|
|
A nil declaration, invalid zero `Command`, and zero `RoutingRule` are
|
|
installation errors, not no-ops. Handle nil pointers without panics; normalize
|
|
non-nil pointers to the supplied opaque declaration types to their values.
|
|
Dispatch only the supported CommandKit declaration kinds, without reflection or
|
|
calling application-defined assembly callbacks. `NoCommand` remains the explicit
|
|
absence case, with retained errors checked before it is skipped.
|
|
|
|
An identical normalized routing rule can be contributed repeatedly. It is
|
|
idempotent, including across calls to `Register`. Do not extend that exception
|
|
to duplicate canonical command declarations. Identity uses declared kind,
|
|
source, target, and scope, not merely the final resolved endpoint: different
|
|
declared targets remain competing mappings even if they reach the same command
|
|
or binding. Invalid later registration leaves both registries and derived
|
|
metadata intact.
|
|
|
|
Store invocation paths privately as normalized strings, populated by dispatch.
|
|
Accessors on an otherwise caller-created zero invocation return empty strings.
|
|
The original context and stream fields remain usable in keyed literals.
|
|
|
|
### Paths and provenance
|
|
|
|
Parse declaration paths on whitespace once at capture. Reuse canonical
|
|
one-token name validation; do not introduce a stricter name alphabet. Path
|
|
rendering, prefix comparison, normalized keys, and exact backend lookup use
|
|
shared helpers. Never split or trim already-tokenized argv elements.
|
|
|
|
Route tokens retain their association with the original argv prefix as aliases
|
|
replace command-path components. This is needed to identify the entered path
|
|
without guessing from the length of the final canonical path. For
|
|
`smoke all` with `smoke → promptkit test`, the entered command path is `smoke`,
|
|
the canonical path is `promptkit test`, and `all` is still an operand.
|
|
For `pk list bundles`, both original `list` and `bundles` belong to the entered
|
|
path when its resolved command is `promptkit list collections`.
|
|
|
|
Only the leading command portion participates in command rewriting. A flag or
|
|
`--` stops command-path lookup. Canonical command structure and operand metadata
|
|
establish where trailing non-option tokens become operands. Longest explicit
|
|
rules beneath an alternate spelling still take precedence as selected in the
|
|
roadmap; do not reserve all operand space beneath an alternate spelling.
|
|
|
|
### Exact termination analysis
|
|
|
|
Use a finite pushdown analysis of the deterministic longest-prefix rewriter.
|
|
This is private installation machinery. It avoids rejecting valid consuming
|
|
repetitions or accepting a growing loop that never repeats an entire path.
|
|
Keep it isolated so its correctness can be established before dispatch uses it.
|
|
|
|
The implementation has two parts, split across Stages 2 and 3:
|
|
|
|
1. Compile a prefix trie into a finite-state stack machine. The top of the
|
|
stack is the beginning of the unresolved path. Lookup remembers the deepest
|
|
matching rule, inspects only the finite source-prefix length, and restores
|
|
any inspected suffix when replacing that source with its target. A failed
|
|
longer match selects the saved shorter match; it does not invent a route.
|
|
No match halts rewriting. End-of-path and the boundary before flags are
|
|
terminal markers, never command components that a rule can consume.
|
|
2. The finite stack alphabet contains literal tokens used by rules, an `OTHER`
|
|
equivalence class for tokens not used by any rule, and an end marker.
|
|
Preserve original arbitrary tokens in the runtime resolver; this quotient
|
|
is only for proving termination. All alias sources are nonempty.
|
|
3. Normalize transitions to `(p,A) → (q,w)` with `w` of length zero, one, or two,
|
|
using finite helper states for longer pushes. Remember which original rules
|
|
participate so an error can identify mappings. The compiler's lookup and
|
|
restoration phases must be acyclic; only completing a rule can return to
|
|
the lookup start. The bottom/end marker is never popped or duplicated.
|
|
4. Compute the finite least fixed point `Pop(p,A,q)`: starting in control `p`
|
|
with top `A`, the machine can remove that symbol and finish in `q` without
|
|
inspecting the stack below it. Seed pop transitions. A one-symbol push uses
|
|
one existing pop summary; a two-symbol push composes two summaries in
|
|
left-to-right order. Retain witness information, not copies of arbitrary
|
|
stack contents.
|
|
5. Build a graph of heads `(control, top-symbol)`. A transition pushing `B`
|
|
gives an edge to `(q,B)`. One pushing `BC` gives an edge to `(q,B)` and,
|
|
for every `Pop(q,B,r)`, to `(r,C)`. A pop transition alone gives no edge.
|
|
These edges summarize nonempty paths that never pop below their starting
|
|
stack level. A directed cycle, including a self-edge, witnesses a repeatable
|
|
computation and hence nontermination.
|
|
6. Check the model's scope explicitly: installation is checking all finite
|
|
command-token suffixes, not just each bare source or target. For this
|
|
compiler, helper phases cannot run forever without returning to the lookup
|
|
start, and every finite token stack at that start is a possible input.
|
|
Therefore a repeatable computation must correspond to a possible alias
|
|
invocation; do not reject an abstract cycle introduced only by an invalid
|
|
end-marker configuration. Restrict marker transitions accordingly and
|
|
record this reasoning with the implementation tests.
|
|
|
|
For the fixed-point step, a rule `(p,A) → (r,BC)` adds `Pop(p,A,q)` only when
|
|
both `Pop(r,B,s)` and `Pop(s,C,q)` hold for some `s`. This distinction matters:
|
|
the head-graph edge to `(s,C)` requires only the first summary and represents
|
|
continuing at `C`, rather than having removed it.
|
|
|
|
Do not substitute an ordinary graph of alias declarations, a decreasing-length
|
|
rule, a maximum chain length, a fixed suffix-enumeration depth, or a timeout
|
|
for this analysis. Use a straightforward finite fixed point and cycle detector;
|
|
no external model-checker dependency or public automaton abstraction is needed.
|
|
Bounded examples are regression evidence, not the proof of universal termination.
|
|
If implementation exposes a flaw in the compiler or analysis, correct that
|
|
isolated stage before proceeding; do not weaken the selected alias contract.
|
|
|
|
After termination succeeds, resolve each declared target through the same
|
|
longest-prefix semantics and require an exact canonical command/group endpoint,
|
|
with no injected operand tokens. Validate literal canonical reachability using
|
|
the complete candidate command tree and its argument bounds, without invoking
|
|
value parsers or application checks. Follow canonical child selection before
|
|
treating unmatched tokens as operands. Do not reject a route solely because a
|
|
runnable ancestor exists: it must actually intercept that command's declared
|
|
operand space or a canonical route.
|
|
|
|
### Flag resolution and parsing
|
|
|
|
Normalize a flag declaration into a long or individual one-byte short spelling,
|
|
without a value. Reuse the existing canonical spelling rules, allowing built-in
|
|
help as a destination. Do not interpret clusters or attached values in a rule
|
|
declaration. A command-scoped path must be an exact canonical path, not an alias
|
|
or an operand-bearing invocation.
|
|
|
|
For each canonical command/group and the application root, form effective
|
|
mappings from application-wide rules plus command-local overrides. Include
|
|
canonical `--help` and `-h`. Resolve chains with canonical spellings as endpoints,
|
|
apply availability to the final endpoint, and validate active source collisions
|
|
separately. Application-wide missing destinations stay inactive; explicit scoped
|
|
missing destinations are errors. Detect mapping cycles, including in reusable
|
|
global chains, and recompute relationships when registration changes the context.
|
|
Discovery-help contexts have core help flags and global rules only.
|
|
|
|
Keep the flag-name/value interpretation in the internal adapter. Use one
|
|
metadata-driven token pass for canonical and alias spellings, including mixed
|
|
short clusters. Normalize reached spellings to canonical backend flags, retain
|
|
their original occurrence spellings, and pass values/operands unchanged.
|
|
Cobra/pflag remain the backend; this pass adapts the selected token grammar and
|
|
does not convert typed application values. Do not independently scan or rewrite
|
|
tokens in core as a second flag parser.
|
|
|
|
Once a value-taking flag consumes an attached suffix or the next token, neither
|
|
that value nor anything following `--` is searched for aliases. Explicit
|
|
boolean values require `=`; a bare boolean contributes `true`. Normalize
|
|
`-c=` as an explicitly empty value, and `-v=` as an empty value for boolean
|
|
conversion, including when these are canonical short spellings. Keep occurrence
|
|
order within each canonical binding and raw values available for the existing
|
|
typed converter; do not add a cross-binding converter-order guarantee.
|
|
|
|
Retain private per-occurrence spelling provenance through conversion. An
|
|
internal conversion error can carry a canonical binding/occurrence index and
|
|
wrap the original cause so presentation can identify the entered spelling.
|
|
Do not rerun converters or stringify and replace their errors. Preserve
|
|
`CaptureFlags`/`FlagValues` binding identity and application-input semantics.
|
|
|
|
## Stage 1: Introduce shared command-path primitives
|
|
|
|
**Work**
|
|
|
|
1. Add `internal/commandpath` with capture parsing, component validation,
|
|
equality/prefix operations, normalized keys, formatting, and owned token copies
|
|
at capture boundaries. Distinguish a root lookup path from a declaration
|
|
path: root lookup is valid; an empty alias declaration path is invalid.
|
|
2. Move or delegate the existing command-name check to the shared validator.
|
|
Migrate canonical bridge paths, exact help lookup, and core path formatting
|
|
where they currently join/split the same paths repeatedly.
|
|
3. Keep argv as tokens throughout. Do not change canonical routing, public API,
|
|
command names, or name restrictions in this refactor.
|
|
|
|
**Evidence:** focused path tests for whitespace-normalized declarations,
|
|
literal quotes/backslashes, invalid option components, empty declarations,
|
|
root lookup, and a single argv token containing whitespace. Existing routing
|
|
and help tests remain green.
|
|
|
|
**Completed:** Added shared command-path parsing, validation, relations, keys,
|
|
formatting, and token-copy helpers. Core command validation and path diagnostics,
|
|
plus adapter route comparison and exact help lookup, now use the shared package.
|
|
Verified with `go test ./internal/commandpath ./internal/cobra .`.
|
|
|
|
## Stage 2: Model deterministic prefix rewriting
|
|
|
|
**Work**
|
|
|
|
1. Add private normalized command-rule records and longest-prefix lookup under
|
|
`internal/alias`, using Stage 1 paths. A simple trie is sufficient.
|
|
2. Implement the finite stack-machine compiler described above, including saved
|
|
shorter matches, mismatch restoration, token equivalence classes, end-marker
|
|
handling, and normalized short push transitions.
|
|
3. Add a small test interpreter for the compiled machine and compare finite
|
|
cases with the direct longest-prefix resolver. Do not expose this interpreter
|
|
or use a test step bound as the production validity decision.
|
|
4. Keep compiler phase transitions explicit so lookup/restoration cannot create
|
|
an internal loop unrelated to completing alias rewrites.
|
|
|
|
**Evidence:** chains; overlap chosen by token count rather than character
|
|
count; target expansion; group suffix preservation; shorter fallback after
|
|
a failed longer token match; unknown tokens; empty suffixes. The compiler
|
|
and direct resolver agree on these terminating cases.
|
|
|
|
**Completed:** Added the independent longest-prefix resolver and compiled its
|
|
trie into a finite stack machine with literal and `OTHER` symbols, end and
|
|
flag-boundary markers, shorter-match fallback, restoration, and normalized
|
|
pushes. A test-only interpreter matches direct resolution for the recorded
|
|
finite cases. Verified with `go test ./internal/alias`.
|
|
|
|
## Stage 3: Prove and test termination validation
|
|
|
|
**Work**
|
|
|
|
1. Implement pop-summary saturation, head-graph construction, and cycle
|
|
detection from the implementation decisions. Return useful participating
|
|
rule context for a rejection. Document why the abstraction neither misses
|
|
growing loops nor invents invalid marker loops.
|
|
2. Cover direct cycles and `a → b extra`, `b → a`, whose paths grow without
|
|
repeating. Cover a suffix-dependent cycle using `a → b`, `b → group`,
|
|
`b x → a x`: bare `a` terminates but `a x` does not.
|
|
3. Accept consuming repetitions: with canonical group `group`, `a → group`
|
|
and `group again → a` must accept `a again again` and consume both suffix
|
|
tokens before ending at `group`.
|
|
4. Cover longest-match suppression of a potential shorter-rule loop: with
|
|
`a → b x`, `b → a`, `b x → group`, actual resolution terminates. A naive
|
|
rule-dependency cycle detector would incorrectly reject it.
|
|
5. Include a valid chain longer than any tempting small fixed hop limit and
|
|
vary rule registration order. Keep no artificial public alias-count limit.
|
|
|
|
**Complete when:** the exact finite analysis is justified and the focused
|
|
cases distinguish it from conservative declaration-cycle or bounded simulation
|
|
checks. Do not integrate an approximate validator and defer correctness.
|
|
|
|
**Completed:** Added worklist saturation for finite pop summaries, head-graph
|
|
construction, cycle detection, and errors naming participating mappings.
|
|
Terminal-marker transitions preserve the unique bottom marker, and tests verify
|
|
markers cannot be popped. Direct, growing, and suffix-dependent loops are
|
|
rejected; consuming repetition, longest-match suppression, and 80-rule chains
|
|
in either registration order are accepted. Verified with
|
|
`go test ./internal/alias -count=1`.
|
|
|
|
## Stage 4: Add captured declaration types and factories
|
|
|
|
**Work**
|
|
|
|
1. Add `Declaration`, opaque `RoutingRule`, the three alias factories, and
|
|
private captured rule records with retained construction errors.
|
|
2. Capture and normalize command paths and flag spellings immediately. Preserve
|
|
the existing `Command` capture, `WithError`, and absence behavior.
|
|
3. Change `New`/`Register` to `...Declaration`, normalizing supported values and
|
|
pointers at the installation boundary. Keep group children command-only.
|
|
4. Convert internal `[]Command` expansions used for installation into explicit
|
|
declaration slices where necessary, including built-in assembly and affected
|
|
consumers/tests. Do not add a bundle API or generalize `Group`.
|
|
|
|
**Evidence:** a core-only public consumer can capture mixed declarations;
|
|
invalid paths/spellings are reported at installation; nil and zero declarations
|
|
are handled as selected; canonical command-only calls continue to work. No
|
|
factories, loaders, or handlers run during capture.
|
|
|
|
## Stage 5: Install canonical commands and command aliases atomically
|
|
|
|
**Work**
|
|
|
|
1. Replace the current root-command-only pending map with a candidate containing
|
|
existing/new canonical commands and separate normalized routing records.
|
|
Reuse existing canonical placement and namespace checks.
|
|
2. Validate retained errors, exact canonical-source collisions, competing rule
|
|
mappings, prefix termination, exact resolved targets, and canonical operand
|
|
interception before publishing the candidate. Same-batch target order is
|
|
irrelevant. Missing targets and operand-bearing destinations are errors.
|
|
3. Accept identical normalized mappings, including repeated contributions across
|
|
registration calls. Revalidate existing aliases when a new canonical batch
|
|
changes reachability. Invalidate derived snapshots only on accepted changes.
|
|
4. Preserve old registry/help behavior after every failed batch. Aliases inside
|
|
an installed standard-family spelling remain routing records and never
|
|
bypass canonical root-only placement or merge command trees.
|
|
|
|
**Evidence:** both registration orders; retained wrapped errors; duplicates;
|
|
missing/forward targets; existing and same-batch collisions; canonical children
|
|
versus runnable operand space; valid longer aliases beneath `r → run`; failed
|
|
registration after a snapshot was used. Explicitly reject
|
|
`promptkit test full → promptkit test all` under a `test KIND` fixture.
|
|
|
|
## Stage 6: Compile effective flag aliases during installation
|
|
|
|
**Work**
|
|
|
|
1. Extend the candidate with global and canonical-command-scoped flag rules.
|
|
Build effective mappings from neutral canonical flag metadata and core help
|
|
spellings, without preparing application inputs.
|
|
2. Resolve chains, apply scoped precedence, check final availability and active
|
|
canonical-source collisions, and reject cycles. Handle long-to-short,
|
|
short-to-long, and canonical short endpoints consistently.
|
|
3. Accept globals whose destinations are currently absent. Recompute all
|
|
affected contexts when later commands arrive; reject the whole batch if a
|
|
newly active global now overloads a canonical spelling.
|
|
4. Add the root and group contexts; support the restricted help context for
|
|
alias-only prefixes. Keep command-scoped aliases local to their canonical
|
|
command rather than implicitly inheriting through descendants.
|
|
|
|
**Evidence:** different-target duplicates versus identical duplicates; explicit
|
|
unknown scopes; inactive globals; scoped overrides inside a chain; cycles;
|
|
`--colour → --color` terminating at canonical `--color` even with an inactive
|
|
global `--color → --missing`; collision after `--missing` becomes available;
|
|
root/group help targets and failed-batch preservation.
|
|
|
|
## Stage 7: Resolve entered routes to canonical commands
|
|
|
|
**Work**
|
|
|
|
1. Add alias lookup records to the App snapshot without adding alias nodes or
|
|
runners to the canonical command tree. Reuse the validated longest-prefix
|
|
semantics and Stage 1 paths.
|
|
2. Implement command/group rewriting with token provenance, remaining argv,
|
|
canonical selection, and a distinct discovery-prefix result. Stop path
|
|
matching at flag/terminator boundaries and canonical operands.
|
|
3. Retain the original entered endpoint and final canonical endpoint, not
|
|
intermediate chain names. Do not use the final path length to slice original
|
|
argv. Unknown paths retain the entered route without a fabricated target.
|
|
4. Ensure a failed longer explicit mapping never retries a shorter mapping.
|
|
Centralize this lookup for execution and help consumers in later stages.
|
|
|
|
**Evidence:** `collections → list collections → promptkit list collections`;
|
|
`pk → promptkit` composed with `promptkit list bundles`; longest explicit
|
|
`pk list bundles` override; `smoke all` retaining its operand; `r full` choosing
|
|
an explicit longer route while canonical `run full` remains unchanged;
|
|
flags/values/space-containing argv tokens never becoming command components.
|
|
|
|
## Stage 8: Integrate parser-aware flag aliasing and short grammar
|
|
|
|
**Work**
|
|
|
|
1. Pass the selected canonical/discovery context's effective spellings to the
|
|
internal adapter through neutral records. Keep Cobra/pflag imports internal.
|
|
2. Implement the single alias-aware token interpretation pass described above.
|
|
Canonical and aliased short flags use the same cluster logic. Preserve raw
|
|
values, explicit empties, `--`, and interspersed operands.
|
|
3. Feed canonical backend flags without invoking a typed parser twice. Collect
|
|
original spelling provenance per occurrence alongside canonical raw values.
|
|
4. Correct canonical `-c=` and boolean `-v=` at this same boundary; do not patch
|
|
aliases alone or pre-rewrite every token beginning with a dash in core.
|
|
|
|
**Evidence:** every token example in the roadmap's flag sections; mixed
|
|
canonical/alias clusters; `-cvq` consuming `vq`; `-qv=false`; explicit empty
|
|
values for long, short, and aliased spellings; missing values; unknown cluster
|
|
members; `--message --hlep` as a value; `--message=--hlep`; post-`--` operands.
|
|
|
|
## Stage 9: Wire execution and invocation identity
|
|
|
|
**Work**
|
|
|
|
1. Use the route result to select the existing canonical payload and its input
|
|
preparation. Populate both Invocation accessors for ordinary and alias
|
|
invocations, including callbacks reached by private built-in plumbing.
|
|
2. Replace the current directly constructed Invocation in the typed runner with
|
|
the coordinated context so metadata reaches handlers without changing their
|
|
signature. Retain caller context and streams.
|
|
3. Keep canonical parsing/conversion, required checks, input/state lifetimes,
|
|
`CaptureFlags`, provider acquisition, and domain outcome classification on
|
|
their existing paths. No handler delegates to another alias handler.
|
|
4. Keep failed routing, invalid flags, and help from constructing application
|
|
input or running acquisition. Preserve the existing distinction that help
|
|
still converts supplied values but skips execution-required checks.
|
|
|
|
**Evidence:** a canonical handler observes equal endpoints directly and distinct
|
|
endpoints through aliases; operands are absent from both path strings; alias
|
|
and canonical forms reach the same binding/callback once; repeated calls and
|
|
declaration reuse do not leak invocation values; zero Invocation accessors
|
|
are empty. Existing cancellation and domain outcome checks remain green.
|
|
|
|
## Stage 10: Add alias-aware help and discovery views
|
|
|
|
**Work**
|
|
|
|
1. Route `help COMMAND...` targets through the shared metadata lookup, despite
|
|
those tokens being operands of the built-in help command. Do not globally
|
|
rewrite arbitrary operands to obtain this special help-target behavior.
|
|
Keep the help command's invocation identity separate from its requested
|
|
view: `help list collections` invokes canonical `help`, while rendering the
|
|
entered target `list collections` and its resolved canonical command.
|
|
2. Coordinate `ALIAS --help`, bare canonical groups, and aliases to groups with
|
|
the same help selection. Render canonical inputs with entered usage paths
|
|
and a canonical-target annotation when the paths differ.
|
|
3. List explicit root aliases separately from canonical commands. Group views
|
|
include relevant aliases separately from children, accounting for more-specific
|
|
overrides. Do not enumerate every possible composed shortcut or chain hop.
|
|
4. Implement help for alias-only prefixes without canonical nodes or namespaces.
|
|
Bare incomplete prefixes are usage failures pointing to help. Global help
|
|
flag aliases work on these views; descendant flags do not become available.
|
|
5. Add only effective flag aliases to each canonical input's help, resolving
|
|
chains to endpoints and describing the canonical input once. Keep lookup
|
|
records independent of rendering and provider callbacks.
|
|
|
|
**Evidence:** root/group/alias/discovery help; `help list collections` and
|
|
`list collections --hlep`; `help promptkit list` showing `bundles`; group
|
|
shortcut help with a more-specific destination override; inactive/scoped flag
|
|
visibility; no input/state factories or providers called. Preserve existing
|
|
help output-delivery handling.
|
|
|
|
## Stage 11: Preserve entered spellings in errors and delivery outcomes
|
|
|
|
**Work**
|
|
|
|
1. Thread flag occurrence provenance into private conversion-error context.
|
|
Identify the actual failing occurrence, including an earlier invalid value
|
|
followed by a valid overwrite. Wrap rather than replace application causes.
|
|
2. Update usage presentation to use entered command paths, identify a resolved
|
|
canonical target, and preserve the target's diagnostic content. An unresolved
|
|
route does not acquire an invented canonical label.
|
|
3. Use existing usage/operational/domain classifications and diagnostic-delivery
|
|
ownership. Route aliases must not duplicate already delivered diagnostics.
|
|
Preserve writer errors, short writes, cause identity, and incomplete reports.
|
|
4. Check alias-related help/usage presentation against failed and successful
|
|
registration so a stale snapshot does not mislabel the selected operation.
|
|
|
|
**Evidence:** malformed aliased scalar and repeatable occurrences; mixed
|
|
spellings; wrapped `errors.Is`/`errors.As`; usage paths with canonical annotation;
|
|
unknown routes and flags; cancellation; output and diagnostic failures. Assert
|
|
semantic fragments and identities, not entire backend wording snapshots.
|
|
|
|
## Stage 12: Verify registration and routing interactions end to end
|
|
|
|
**Work**
|
|
|
|
1. Extend public external-package tests with command-only and simulated
|
|
root-only family fixtures. Exercise construction, later registration,
|
|
retained declaration errors, reuse across Apps, and failed-batch recovery.
|
|
2. Verify canonical invocations retain their declared operand space in both
|
|
installation orders, while longer mappings beneath alternate spellings work.
|
|
Cover optional, required, and repeated operand metadata without calling
|
|
domain value converters at installation.
|
|
3. Verify same-batch alias chains and globals see the entire candidate, and
|
|
later command additions trigger full relationship validation. Check cached
|
|
lookup/help before and after successful and failed registration.
|
|
4. Include a core-only consumer proving alias infrastructure needs no optional
|
|
integration imports. Keep alias records out of the canonical handler tree.
|
|
|
|
**Evidence:** run the focused external registration, routing, and help suites.
|
|
Fill missing cross-boundary cases rather than duplicating the private algorithm
|
|
test inventory. No concurrent-dispatch contract is introduced.
|
|
|
|
## Stage 13: Verify typed bindings and integration composition
|
|
|
|
**Work**
|
|
|
|
1. Cover singleton last-occurrence behavior, conversion of every supplied
|
|
occurrence, repeatable ordering, explicit false/zero/empty presence, required
|
|
checks, and fresh invocation state with mixed flag spellings.
|
|
2. Verify captured selector bindings still reach selected typed integration
|
|
inputs. Test a command-scoped flag alias reached through a command shortcut,
|
|
and global help on standard families, without rechecking upstream semantics.
|
|
3. Add focused ckprompt composition cases for actual installed collection and
|
|
named-inspection commands, plus the valid `smoke → promptkit test` shortcut.
|
|
Use local callbacks; smoke tests should assert forwarded kind and returned
|
|
report/outcome, not perform network requests.
|
|
4. Reject the invalid smoke operand-synonym mapping against the actual
|
|
`promptkit test KIND` declaration. Preserve ordinary canonical calls in the
|
|
same application. Use a small ckconfig alias case for selector forwarding.
|
|
|
|
**Evidence:** root binding suites and affected integration suites under the
|
|
local workspace. Do not claim nested modules' pinned core v0.2.0 graph validates
|
|
new alias APIs. See Stage 17 for independent local-source graph verification.
|
|
|
|
## Stage 14: Update maintained consumer examples
|
|
|
|
**Work**
|
|
|
|
1. Extend `examples/core` with application command shortcuts, a group shortcut,
|
|
a global help typo alias, and a scoped flag alias. Demonstrate a mixed
|
|
`[]Declaration` collection and the two Invocation path accessors with small
|
|
application-owned behavior.
|
|
2. Extend the composed ckprompt consumer with
|
|
`list collections → promptkit list collections`,
|
|
`promptkit list bundles → promptkit list collections`, and `pk → promptkit`.
|
|
Add scoped `--fmt → --format` for named prompt inspection and
|
|
`--hlep → --help` globally. Keep canonical suite loading and domain commands
|
|
unchanged; install aliases alongside the complete canonical declarations.
|
|
3. Add the valid smoke command-path shortcut if useful for the existing local
|
|
smoke fixture. Do not represent `all` as a child command or alias target.
|
|
4. Update example tests to show aliases reaching canonical operations, help
|
|
without acquisition, and ordinary canonical commands still working. Keep
|
|
outputs local and deterministic.
|
|
|
|
**Evidence:** root and composed-example tests pass against the new local core;
|
|
the examples remain complete, copyable artifacts. Explain local source testing
|
|
and forthcoming core dependency adoption in their developer-facing guidance;
|
|
do not claim published core v0.2.0 has alias support.
|
|
|
|
## Stage 15: Reconcile public and internal documentation
|
|
|
|
**Work**
|
|
|
|
1. Add GoDoc for `Declaration`, `RoutingRule`, factories, installation changes,
|
|
and Invocation accessors. Explain eager capture, factory errors retained for
|
|
installation, nil/zero handling, duplicate rules, and canonical scope paths.
|
|
2. Update `docs/cli.md` with implemented alias routing, command/operand
|
|
boundaries, flag scope/availability, short grammar and empty-value correction,
|
|
entered-path diagnostics, and help/discovery behavior. Preserve canonical
|
|
upstream command and report contracts.
|
|
3. Update the consumer guide and example READMEs for `[]Declaration`, direct
|
|
`Command` calls, slice conversion, and explicit root installation of rules.
|
|
Include a minimal real integration composition example and links to the
|
|
maintained complete consumers.
|
|
4. Update the internal overview and applicable architecture provisions for the
|
|
separate canonical/routing layers and joint installation. ADR 0013 already
|
|
authorizes this architecture; do not rewrite accepted decisions or add an ADR
|
|
for incidental algorithm or presentation details.
|
|
5. Update developer navigation to the roadmap/plan while work is active and
|
|
preserve `deferred.md`. Keep shell completion as future direction only.
|
|
|
|
**Evidence:** local links and fragments resolve; volatile behavior has its
|
|
canonical owner; no future alias APIs are described as existing before their
|
|
implementation is present. Prose checks and relevant examples agree.
|
|
|
|
## Stage 16: Record compatibility impact for the next core release
|
|
|
|
**Work**
|
|
|
|
1. Prepare the next core minor release note, `docs/releases/v0.3.0.md`, with
|
|
the product title, short summary, migration guidance, and required immutable
|
|
licensing footer under the release procedure. Do not edit published notes.
|
|
2. Explain the `...Command` to `...Declaration` change, especially `[]Command`
|
|
expansion and function-value signature changes; command/group factories
|
|
still return `Command`. Note private Invocation path storage's impact on
|
|
positional struct literals and recommend keyed construction when needed.
|
|
3. Explain command/flag aliases and the explicit short-option empty-value
|
|
correction. Go 1.26.0 and the current upstream/backend selections need not
|
|
change for this feature.
|
|
4. Keep publication and real integration dependency bumps separate. The next
|
|
core must be published before dependent module release preparation downloads
|
|
that version and records actual sums, as required by `docs/release.md`.
|
|
Do not invent core v0.3.0 sums, commit local replacements, or rewrite the
|
|
integrations' existing v0.1.0 release notes. Report this release-preparation
|
|
dependency in the final implementation handoff.
|
|
|
|
**Evidence:** note explains consumer action and candidate-local link paths and
|
|
footer are correct. No release launcher, remote push, or tag operation occurs
|
|
as part of implementing this plan.
|
|
|
|
## Stage 17: Verify the complete target and finish
|
|
|
|
**Work**
|
|
|
|
1. Format changed Go sources and run the complete deterministic root suite and
|
|
both integration suites using the local three-module workspace described by
|
|
the developer guide. Use the documented Go 1.26.8 maintainer toolchain; this
|
|
feature does not raise the consumer minimum.
|
|
2. Root independent validation uses `GOWORK=off` and its actual module graph.
|
|
For nested modules needing unpublished local core APIs in tests/examples,
|
|
use disposable copies of each `go.mod`/`go.sum` through `-modfile`, with a
|
|
local core replacement; replace ckconfig with its local source for composed
|
|
verification where needed. Run `GOWORK=off` module suites against those
|
|
copies. Permit only disposable metadata to change and inspect it separately.
|
|
This verifies local source composition, not published-version availability.
|
|
3. Leave committed dependency constraints and genuine sums intact until their
|
|
separately authorized release preparation. Do not run nested suites against
|
|
old published core and count failures as feature failures or count old code's
|
|
success as evidence for new aliases. Do not publish dependencies to make
|
|
this implementation sprint's checks pass.
|
|
4. Confirm core still has no optional-library dependency, backend imports stay
|
|
internal, integration factories remain canonical `Command` factories, and
|
|
alias lookup requires no application/provider initialization.
|
|
5. Audit every roadmap behavior against the evidence index below. Verify
|
|
metadata paths, help views, errors, and failed-registration recovery, not
|
|
only successful alias execution. Reuse existing focused evidence rather
|
|
than creating an additional redundant test framework or release gate.
|
|
6. Run prose whitespace and local-link checks; inspect all diffs and intended
|
|
files. Mark stages complete with actual evidence, update the feature
|
|
roadmap's status, commit remaining intended work, and report validation plus
|
|
any release-preparation steps still required. Preserve completed planning
|
|
records until cleanup is requested.
|
|
|
|
After selecting the documented toolchain and preparing the existing dependency
|
|
cache, the independent graph checks can be performed from the repository root
|
|
as follows. The workspace checks above are still needed; these commands exercise
|
|
each module's own metadata with only the indicated local source substitutions.
|
|
The temporary-file updates accommodate unpublished source without changing
|
|
tracked version requirements or synthesizing published checksums.
|
|
|
|
```sh
|
|
(
|
|
set -eu
|
|
commandkit_alias_repo=$(pwd)
|
|
commandkit_alias_verify=$(mktemp -d /tmp/commandkit-alias-verify.XXXXXX)
|
|
trap 'rm -rf "$commandkit_alias_verify"' EXIT
|
|
export GOTOOLCHAIN=local GOWORK=off
|
|
export GOPROXY=off GONOPROXY=none GOSUMDB=off
|
|
|
|
go test -mod=readonly ./...
|
|
|
|
cp integrations/ckconfig/go.mod "$commandkit_alias_verify/ckconfig.mod"
|
|
cp integrations/ckconfig/go.sum "$commandkit_alias_verify/ckconfig.sum"
|
|
go mod edit -modfile="$commandkit_alias_verify/ckconfig.mod" \
|
|
-replace="gitea.maximumdirect.net/eric/CommandKit=$commandkit_alias_repo"
|
|
(cd integrations/ckconfig &&
|
|
go test -mod=mod -modfile="$commandkit_alias_verify/ckconfig.mod" ./...)
|
|
|
|
cp integrations/ckprompt/go.mod "$commandkit_alias_verify/ckprompt.mod"
|
|
cp integrations/ckprompt/go.sum "$commandkit_alias_verify/ckprompt.sum"
|
|
go mod edit -modfile="$commandkit_alias_verify/ckprompt.mod" \
|
|
-replace="gitea.maximumdirect.net/eric/CommandKit=$commandkit_alias_repo"
|
|
go mod edit -modfile="$commandkit_alias_verify/ckprompt.mod" \
|
|
-replace="gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig=$commandkit_alias_repo/integrations/ckconfig"
|
|
(cd integrations/ckprompt &&
|
|
go test -mod=mod -modfile="$commandkit_alias_verify/ckprompt.mod" ./...)
|
|
)
|
|
```
|
|
|
|
If an offline command reports an absent dependency, prepare that dependency
|
|
separately and rerun the affected check. Do not turn an offline suite into a
|
|
network-enabled test run or silently substitute older published implementation.
|
|
These local-source graph checks do not add a permanent release gate.
|
|
|
|
**Complete when:** the accepted feature works through the public consumer
|
|
boundary, the selected checks pass against local source, documentation matches
|
|
the implementation, and no unresolved feature decisions or implementation work
|
|
remain. Publishing and dependent-version availability are separate operations.
|
|
|
|
## Target evidence index
|
|
|
|
| Accepted behavior | Primary stages |
|
|
| --- | --- |
|
|
| Public factories, capture, absence/zero/nil handling, slices | 1, 4, 5, 12, 15, 16 |
|
|
| Exact chains, longest matches, group composition, universal termination | 2, 3, 5, 7, 12 |
|
|
| Canonical ownership, operand boundaries, no preset operands | 5, 7, 12, 13 |
|
|
| Same-batch and later installation, duplicates, rollback | 5, 6, 12 |
|
|
| Global/scoped flag aliases, chains, endpoints, availability, collisions | 6, 8, 12, 13 |
|
|
| Values, operands, clusters, empty values, presence, repeat order | 8, 9, 11, 13 |
|
|
| Entered/canonical identity and ordinary lifecycle | 7, 9, 11, 13 |
|
|
| Root/group/alias-prefix help, effective flag help, target-aware usage | 7, 10, 11, 12 |
|
|
| Error identity, cancellation, report/diagnostic delivery | 9, 11, 13 |
|
|
| Real consumer composition and module boundaries | 12, 13, 14, 17 |
|
|
| Future-completion lookup separation without completion delivery | 7, 10, 15 |
|
|
| Migration, current references, release-note preparation | 14, 15, 16, 17 |
|