Files
commandkit/docs/roadmap/completion.md

188 lines
10 KiB
Markdown

# Shell completion
Status: the selected initial scope is implemented; final sprint validation
remains. Canonical suggestions and alias-aware interpretation are available for
Bash, Zsh, and Fish through explicitly installed completion support.
## Purpose
Provide useful shell completion for core-only applications and applications with
optional integrations. Reuse installed command declarations and CommandKit's
routing rules so consumers need little completion-specific wiring.
Completion helps an operator construct an invocation. It does not execute the
selected application command. Preserve application ownership of runtime behavior
and upstream ownership of configuration and prompt semantics.
## Planning baseline
Reviewed baseline: `2301872` (`Stop flag interpretation at unknown flags`).
- Core captures declarations and builds a routing snapshot containing canonical
commands and separate application aliases.
- [Neutral metadata](../../internal/commandmeta/metadata.go) describes command
names, descriptions, flags, boolean/value distinctions, repetition, required
flags, and operand cardinality. It has no completion choices or path hints.
- The [Cobra adapter](../../internal/cobra/parse.go) constructs a backend tree
for parsing and help. CommandKit owns execution and presentation outside that
tree; enabling Cobra's default completion command alone is insufficient.
- [Alias routing](../../route.go) resolves complete command paths and coordinates
canonical parsing with entered spellings. Completion must also handle partial
words and an empty current word.
- Invocation reporting controls ordinary output and diagnostics. Shell completion
queries need machine-readable replies independent of flags in the unfinished
command line.
- The core module uses Cobra v1.10.1 and pflag v1.0.9. Cobra supplies script
generators and completion callbacks for Bash, Zsh, Fish, and PowerShell.
See its [versioned completion documentation](https://github.com/spf13/cobra/blob/v1.10.1/site/content/completions/_index.md).
[ADR 0013](../adr/0013-application-alias-routing.md) owns the separation between
alias routes and canonical commands. [ADR 0014](../adr/0014-invocation-reporting.md)
owns invocation reporting. This roadmap defines completion within those
boundaries; it does not establish a replacement command model.
## Target experience
An operator generates and loads a shell integration script, then receives
suggestions for installed commands, applicable canonical flags, and declared
value choices or paths. The selected script-generation grammar is:
```text
app completion bash
app completion zsh
app completion fish
```
Consumers explicitly install a core completion declaration through the existing
installation API. The completion namespace is reserved only when installed.
Keep the machine query hidden from ordinary help, with collision validation for
its selected path. Installation must not replace an application-owned command.
Script generation writes to the caller-selected result stream. Shell setup
instructions explain loading the script; automatic modification of shell startup
files is outside the initial implementation.
The initial MVP suggests canonical command names and flag spellings. Completed aliases
already entered by the operator are interpreted to identify the canonical target.
For example, with `jobs` routing to `workspace jobs`, completing after
`app jobs ` can suggest the canonical children of `workspace jobs`.
Completion should preserve the text the operator has already entered.
Matching partial canonical names, resolving completed aliases, and interpreting
an alias-only discovery prefix are distinct cases. Initially, an alias-only
prefix with no canonical target offers no command continuations. For example,
if `legacy inspect` is an alias but `legacy` has no canonical target,
`app legacy <TAB>` offers no command continuations. After the complete alias is
entered, completion uses its canonical target. Applicable flag suggestions can
still follow the existing discovery context.
Suggested continuations must form a valid next step when inserted into the
entered route. Do not append canonical words that would create an invalid route.
Alias discovery may be omitted from the initial MVP; this is a scope choice,
not a permanent limitation of CommandKit. Suggesting alias names or alias-path
continuations remains [potential future work](deferred.md#alias-completion-and-discovery).
### Flag suggestions
Initially suppress already supplied singleton flags from flag-name suggestions.
Canonical and aliased occurrences count as the same flag. Keep repeatable flags
available. Keep all four reporting flags (`--quiet`, `--verbose`, `--debug`, and
`--progress`) available because later occurrences can intentionally change or
reset their settings.
Suggestion filtering leaves accepted syntax unchanged. Operators can still type
singleton flags again under the existing repetition rules. If an operator has
already entered a repeated flag, continue completing its value according to its
hint even when its name would have been omitted from suggestions.
## Selected initial scope
Provide canonical command and flag suggestions, descriptions where supported by
the selected shells, alias-aware interpretation, static value choices, and
file/directory hints. Apply the same declaration facilities to application-owned
commands and optional integrations.
Support Bash, Zsh, and Fish using the existing backend generators, with validation
in each shell. PowerShell is outside the initial supported shell set because
there is no current consumer need; this does not preclude future support.
Static suggestions should come from captured metadata. Completion should not
invoke ordinary handlers, input/state factories, or acquisition callbacks to
obtain it. Application startup and declaration-factory effects remain owned by
the consumer, just as they do for help.
Dynamic discovery of configured prompt names, remote resources, or other live
values is a possible later extension. Deferring it avoids selecting provider
lifetimes and latency behavior before a concrete consumer need; it is not a
permanent prohibition on dynamic completion.
## Ownership and implementation approach
Core owns completion context, alias interpretation, and neutral suggestions.
The internal backend adapter owns Cobra-specific types, directives, script
emission, and protocol details. Prefer the existing backend facilities where
compatible with CommandKit's grammar. Verify the adapter approach with a small
end-to-end prototype before fixing private interfaces.
A completion request identifies completed words and the current partial word,
including an empty word after a space. Interpret only what is needed to locate
suggestions. Ordinary required-value validation and input conversion must not
reject a partially constructed invocation before completion can help fill it.
Reuse token and flag interpretation helpers where practical without changing
normal execution grammar or treating incomplete input as an executable command.
Account for command-local flags, aliases, consumed values, `--`, attached values,
boolean assignments, short clusters, repeatable flags, and operand positions.
Keep provenance sufficient to return a replacement for the word being edited.
Completion candidates are suggestions, not an additional input validator.
When both an operand and a flag are valid, use the operand's hint for an
empty current word after a space. Offer flag names when the operator starts
the word with `-` in a context where flags are accepted.
Value choices and path hints belong in CommandKit-owned public metadata. Carry
them through declaration capture and neutral metadata to the adapter. Arbitrary
converter functions cannot reliably reveal their accepted values. Adding a list
of suggestions must not silently restrict the values a converter accepts.
Provide declarative static choices with optional descriptions, file/directory
hints, and an explicit way to request no value suggestions. Unannotated values
default to no value suggestions; applicable commands and flags still complete.
Filename completion requires a path hint. This keeps unrelated filenames out of
identifier and numeric completions. The implementation plan specifies how hints
fit into existing binding declarations.
Initially use one hint strategy per value position: static choices, files,
directories, or no value suggestions. Optional choice descriptions belong to the
static-choice strategy. Combined choices and filesystem suggestions can be
considered later if consumers need them; the initial API need not define their
merging or deduplication behavior.
Verify the same strategy works for separated and attached flag values, such as
`app serve --config ./par<TAB>` and `app serve --config=./par<TAB>`. For the
attached form, preserve `--config=` and complete its value correctly. Validate
the resulting command line in each supported shell.
Keep ordinary script generation under the existing reporting policy. A hidden
shell query is a protocol exchange: flags in the command being completed are
request data, so `--quiet` must not erase its reply and `--debug` must not append
ordinary diagnostics to it. When an unrecognized or incomplete command line
leaves no inferable completion context, return a valid empty reply that disables filename fallback. Reserve
protocol errors for failures in the query itself. Specify their wire behavior
and output ownership in the implementation plan. A completion request must not
accidentally run the target command.
Hidden protocol names are implementation details unless deliberately published.
## Delivery plan
The [implementation plan](implementation.md) owns the sprint sequence, API and
protocol design, and validation steps. The target includes behavioral coverage
and shell-level validation through the public consumer path in Bash, Zsh, and
Fish.
## Deferred scope
Alias discovery remains a potential extension beyond the MVP. Dynamic discovery
remains deferred until a concrete consumer need justifies its callback,
cancellation, error-handling, and provider-lifetime design.