465 lines
23 KiB
Markdown
465 lines
23 KiB
Markdown
# Application-owned aliases
|
|
|
|
Status: command- and flag-alias directions accepted; implementation has not
|
|
started. Consumer registration conventions are selected; the installer declaration
|
|
type and remaining routing details are open. This roadmap records
|
|
the target and work needed before implementation.
|
|
|
|
## Purpose and ownership
|
|
|
|
Make alternate command paths and flag spellings simple for consuming
|
|
applications to declare. CommandKit core owns alias registration, resolution,
|
|
and integration with routing and help. Applications choose their aliases.
|
|
Integrated libraries continue to own their canonical command behavior.
|
|
|
|
Aliases occupy a separate application routing layer above installed canonical
|
|
commands:
|
|
|
|
```text
|
|
CLI argument tokens
|
|
→ command-path alias resolution
|
|
→ canonical command selection
|
|
→ applicable flag-alias resolution using canonical flag metadata
|
|
→ canonical parsing
|
|
→ ordinary invocation lifecycle
|
|
```
|
|
|
|
Alias declarations do not install new handlers or modify the canonical command
|
|
tree. An alias spelled inside `promptkit` therefore does not add an
|
|
application-owned operation to the integration's namespace. The ownership and
|
|
placement rules in [ADR 0011](../adr/0011-captured-declarations-and-installation.md)
|
|
and the [architecture policy](../policy/architecture.md) continue to govern
|
|
canonical command installation.
|
|
|
|
Flag aliases likewise leave canonical flag definitions and typed bindings
|
|
unchanged. This is one conceptual routing layer; its internal implementation
|
|
cooperates with the existing parser to preserve token interpretation.
|
|
|
|
## Current baseline
|
|
|
|
Core captures reusable `Command` declarations and installs them through `New`
|
|
and `App.Register`. Installation validates a batch before registry mutation.
|
|
Optional standard families own their installed root namespaces. Core routing
|
|
and the internal backend coordinate parsing, help, and execution through one
|
|
invocation lifecycle.
|
|
|
|
The current public model has no application alias layer. PromptKit already
|
|
exposes the collection catalog and smoke-test commands used in the examples
|
|
below. These examples illustrate alternate routes to existing capabilities;
|
|
they do not introduce new PromptKit operations.
|
|
|
|
The [CLI reference](../cli.md) owns current grammar. Options follow the complete
|
|
command path, can be interspersed with operands, and use `--` to terminate
|
|
option parsing. Aliasing preserves the target's grammar and typed binding
|
|
contracts.
|
|
|
|
## Selected declaration and registration conventions
|
|
|
|
Commands and aliases use the same installation boundary through `New` and
|
|
`App.Register`. Core validates the complete batch together while retaining
|
|
aliases as separate routing records internally. No separate alias-registration
|
|
API is needed.
|
|
|
|
Use space-separated strings for command paths, interpreted as sequences of
|
|
command names without shell quoting or expansion. Application-wide flag aliases
|
|
use `FlagAlias`; command-scoped aliases use `FlagAliasFor` with an explicit
|
|
canonical command path. The selected consumer-facing shape is:
|
|
|
|
```go
|
|
app, err := commandkit.New(
|
|
identity,
|
|
ckprompt.Command(suite),
|
|
commandkit.Alias("list collections", "promptkit list collections"),
|
|
commandkit.FlagAlias("--hlep", "--help"),
|
|
commandkit.FlagAliasFor("promptkit show prompt", "--ver", "--version"),
|
|
)
|
|
```
|
|
|
|
This illustrates planned APIs. The declaration type accepted by the installer
|
|
still needs design; aliases remain routing records rather than fabricated
|
|
canonical command nodes. Later registration uses the same model and validation.
|
|
|
|
Accept identical duplicate alias mappings as harmless, including when reusable
|
|
helpers contribute them. Identity includes the alias kind, source, target, and
|
|
scope where applicable. Different-target command mappings for the same source
|
|
remain errors; overlap between flag scopes is addressed under OD-6.
|
|
|
|
Alias support lives entirely in core and works with built-in commands,
|
|
application commands, optional integrations, or any combination. Validation
|
|
uses the commands and flags installed in that application. No integration
|
|
dependency is required for alias support. Core continues to supply help and
|
|
version automatically, including for applications whose other commands are
|
|
entirely application-defined.
|
|
|
|
## Selected command-alias behavior
|
|
|
|
### Paths and resolution
|
|
|
|
Declare mappings between command paths relative to the application root. The
|
|
executable name is not part of either path:
|
|
|
|
| Alias path | Target path |
|
|
| --- | --- |
|
|
| `list collections` | `promptkit list collections` |
|
|
| `promptkit test full` | `promptkit test all` |
|
|
| `list` | `promptkit list` |
|
|
|
|
Aliases can target individual commands or groups. A group alias preserves
|
|
remaining subcommand tokens. For example, `list collections` can reach
|
|
`promptkit list collections` through the `list` group alias.
|
|
|
|
Match exact, complete argument tokens at the beginning of the command path;
|
|
`list` does not match `listing`. Resolve overlapping alias paths using the
|
|
longest matching path, measured by the number of command-path tokens, not
|
|
character count. This rule applies at each command-alias lookup and is
|
|
independent of registration order. Sorting by descending token count and taking
|
|
the first matching prefix is one possible implementation; the algorithm remains
|
|
an implementation choice.
|
|
|
|
For example, with `list → promptkit list` and
|
|
`list collections → application collections`, the more specific mapping wins
|
|
for `list collections`, while `list prompts` uses the `list` mapping.
|
|
|
|
Once a matching alias is selected, resolve that route and apply canonical
|
|
validation. A validation failure reports an error; it does not retry a shorter
|
|
alias that could invoke a different command.
|
|
|
|
Preserve trailing arguments,
|
|
including flags, operands, explicit empty values, and `--`, for canonical
|
|
parsing. Values and operands are not searched for alias text.
|
|
|
|
The initial command-alias feature maps command paths. Preset flags, operand
|
|
transformation, and arbitrary argument rewriting are outside this delivery.
|
|
|
|
### Chains and group composition
|
|
|
|
Support alias chains and resolve them to their canonical target. At each lookup,
|
|
select the longest matching command-path prefix, replace it with its target,
|
|
and preserve the remaining tokens. Repeat command-path resolution until the
|
|
canonical route is reached, then parse its inputs normally. Flags, flag values,
|
|
and operands remain outside command-alias matching under the command/operand
|
|
boundary rules below.
|
|
|
|
A group shortcut provides access to routes beneath its target, including aliases:
|
|
|
|
```text
|
|
pk → promptkit
|
|
promptkit test full → promptkit test all
|
|
```
|
|
|
|
Here, `pk test full` resolves through `promptkit test full` to
|
|
`promptkit test all`. An explicitly declared `pk test full` alias would take
|
|
precedence over `pk` at the initial lookup. Ordinary chains follow the same
|
|
rules, for example `collections → list collections → promptkit list collections`.
|
|
|
|
Validate composition during installation and reject cycles and nonterminating
|
|
prefix expansion with diagnostics identifying the participating mappings.
|
|
Checking only for repeated complete paths is insufficient: `a → b extra` and
|
|
`b → a` continually expand the path without repeating it. Analyze prefix
|
|
composition so these configuration errors are caught before invocation. An
|
|
arbitrary runtime hop limit is not a substitute for installation validation
|
|
and must not reject an otherwise valid long chain.
|
|
|
|
### Installation and collisions
|
|
|
|
Use the shared declaration and installation conventions above for aliases,
|
|
application commands, and integration commands.
|
|
|
|
An alias target may already be installed or be supplied in the same installation
|
|
batch. Declaration order within that batch does not affect resolution. Missing
|
|
targets, collisions, and cycles produce installation errors with useful path
|
|
context. Failed installation preserves the existing application registry and
|
|
alias mappings under the existing batch-atomicity model.
|
|
|
|
An alias cannot conflict with or overload a canonical command path. Reject such
|
|
a declaration during installation as invalid application configuration. Apply
|
|
the same protection when later registration adds a canonical command conflicting
|
|
with an existing alias. Reject competing mappings from the same source path to
|
|
different targets; registration order must not select a winner. Identical
|
|
duplicate mappings are accepted under the shared registration conventions.
|
|
|
|
Aliases do not create canonical parent groups, merge integration trees, or
|
|
replace handlers.
|
|
|
|
### Prefix interactions and canonical reachability
|
|
|
|
Alias paths may share prefixes with canonical paths when they introduce a
|
|
distinct route. Preserve existing canonical invocations, including the declared
|
|
operand space of runnable commands.
|
|
|
|
| Canonical declaration | Proposed alias | Result |
|
|
| --- | --- | --- |
|
|
| `promptkit test all` | `promptkit test full` → `promptkit test all` | Allow the distinct route beneath the shared prefix. |
|
|
| `list projects` | `list collections` → `promptkit list collections` | Allow the distinct route beneath the shared prefix. |
|
|
| `list` group | `list` → `promptkit list` | Reject replacement of the canonical group path. |
|
|
| `run` accepts an operand | `run full` → another command | Reject interception of `full` in the canonical command's operand space. |
|
|
|
|
Determine command and operand boundaries from declared command structure and
|
|
argument metadata, without executing handlers or application validation.
|
|
Longest-path matching chooses among valid aliases; it does not authorize
|
|
consumption of canonical operands. Sharing a runnable ancestor alone does not
|
|
establish a conflict: check whether the proposed route intercepts that
|
|
ancestor's operands or an existing canonical child route.
|
|
|
|
Check these conflicts against the complete candidate registry when adding
|
|
either aliases or canonical commands, including later registration. Report the
|
|
conflicting paths and preserve batch atomicity. Apply the chain and group
|
|
composition rules above when validating resolved routes.
|
|
|
|
### Execution and help
|
|
|
|
An invocation through an alias uses the canonical target's flags, operands,
|
|
defaults, typed bindings, input preparation, providers, diagnostics, and
|
|
outcomes. Execute the ordinary lifecycle once. Alias registration, resolution,
|
|
and help do not invoke application input/state factories or acquisition callbacks.
|
|
|
|
Expose the original entered command path and final resolved canonical command
|
|
path as read-only invocation metadata. Both paths exclude the executable name,
|
|
flags, and operands. For a direct canonical invocation the paths are equal;
|
|
for `app pk test full`, they can be `pk test full` and `promptkit test all`.
|
|
Retain the endpoints through a chain; intermediate rewrites are not part of
|
|
the selected public metadata.
|
|
|
|
Consumers can use the canonical path to identify the operation consistently
|
|
and the entered path for logging and diagnostics. CommandKit dispatch and
|
|
bindings continue to use the canonical target. Exact accessor names and path
|
|
representation remain API design details under OD-1.
|
|
|
|
Support both help forms:
|
|
|
|
```text
|
|
scriptorium help list collections
|
|
scriptorium list collections --help
|
|
```
|
|
|
|
Alias help describes the canonical target's inputs using the alias invocation
|
|
path and identifies the canonical command. Root help lists explicitly declared
|
|
command aliases separately from canonical commands, showing their resolved
|
|
canonical targets. Ordinary help need not show intermediate chain mappings or
|
|
enumerate every route reachable through group shortcuts.
|
|
|
|
Group help includes relevant aliases separately from canonical children. For
|
|
example, `help promptkit test` shows `full → promptkit test all`. Help reached
|
|
through a group alias uses that spelling in usage examples and presents the
|
|
routes available through it, including applicable aliases beneath the target.
|
|
Account for more-specific mappings so displayed destinations match routing.
|
|
|
|
Provide discovery help for alias-only prefixes. If `list collections` and
|
|
`list prompts` are declared without a canonical `list` group, both `help list`
|
|
and `list --help` display the available routes. This help view is derived from
|
|
alias declarations and creates no canonical group or namespace ownership.
|
|
Bare `list` reports an incomplete command and points to that help.
|
|
|
|
Usage errors use the entered path and identify the canonical target when one
|
|
has been resolved, while preserving the canonical command's diagnostic content:
|
|
|
|
```text
|
|
Usage: scriptorium list collections [flags]
|
|
Alias for: scriptorium promptkit list collections
|
|
```
|
|
|
|
If resolution fails before identifying a target, report the entered route
|
|
without assigning a canonical identity.
|
|
|
|
## Selected flag-alias behavior
|
|
|
|
### Spellings and scopes
|
|
|
|
Applications can declare alternate spellings for canonical flags, including
|
|
`--hlep` mapping to `--help`. Declaring a flag alias should be as simple as
|
|
declaring a command alias, using the shared registration conventions above.
|
|
|
|
Support application-wide mappings and mappings scoped to a canonical command.
|
|
The selected canonical command determines the applicable flag aliases, so a
|
|
command-scoped mapping works through every command alias that reaches that
|
|
target. A command-scoped mapping takes precedence over an application-wide
|
|
mapping for the same alias spelling. Reject different-target mappings within
|
|
the same scope; identical duplicates are harmless. Registration order does not
|
|
choose a winner, and neither scope may overload an applicable canonical flag.
|
|
|
|
An application-wide mapping is available wherever its target flag exists and
|
|
contributes nothing elsewhere. For example, `--colour → --color` need not require
|
|
every command to define `--color`. On a command without that target, `--colour`
|
|
receives the ordinary unknown-flag error. Reusable application-wide declarations
|
|
are valid even when no currently installed command has their target flag.
|
|
|
|
A command-scoped mapping requires its named canonical command and target flag
|
|
to exist in the complete candidate installation batch. An unavailable explicit
|
|
destination is invalid configuration.
|
|
|
|
Application-wide mappings also apply to built-in flags at the application root
|
|
and on groups. In particular, `--hlep → --help` works wherever canonical
|
|
`--help` works, including help for alias-only prefixes.
|
|
|
|
Later registration repeats validation against the candidate registry. Newly
|
|
installed commands gain applicable application-wide aliases automatically;
|
|
canonical spelling collisions reject the batch under the collision rules below.
|
|
|
|
### Token interpretation
|
|
|
|
Resolve command aliases and identify the canonical command before applying its
|
|
flag aliases. Use canonical flag metadata to distinguish flag names from values.
|
|
Preserve the existing grammar, including flags interspersed with operands.
|
|
|
|
| Input | Effect |
|
|
| --- | --- |
|
|
| `list collections --hlep` | Resolve the command path and route `--hlep` to canonical help. |
|
|
| `foo --colour=blue` | With `--colour` mapped to `--color`, preserve `blue` as the value. |
|
|
| `foo --message=--hlep` | Preserve the value `--hlep`. |
|
|
| `foo --message --hlep` | When `--message` consumes a value, preserve `--hlep` as that value. |
|
|
| `foo -- --hlep` | Preserve the operand `--hlep` after the option terminator. |
|
|
|
|
Only tokens interpreted as flag names participate in flag aliasing. Preserve
|
|
values, explicit empty strings, and operands. The routing layer cooperates with
|
|
the existing parser rather than maintaining a separate interpretation of flag
|
|
arity, boolean syntax, or option termination.
|
|
|
|
Match the complete flag name. Length precedence does not apply: `--out` and
|
|
`--output` are different names, and only `--out` participates in alias lookup in
|
|
`--out=value`. Use the scope precedence selected above. Resolution must
|
|
be deterministic and must not depend on registration order.
|
|
|
|
### Canonical flag collisions
|
|
|
|
An alias cannot conflict with or overload an applicable canonical flag spelling.
|
|
Reject conflicts during installation as invalid application configuration.
|
|
Check a command-scoped alias against that command's canonical flags, and an
|
|
application-wide alias across the commands where it applies. Apply the same
|
|
checks when later registration adds canonical declarations. Failed batches
|
|
preserve existing commands and alias mappings.
|
|
|
|
### Canonical binding behavior
|
|
|
|
An alias feeds the same typed binding as its canonical flag. The target retains
|
|
its value conversion, defaults, required-value checks, presence tracking,
|
|
repetition rules, and behavior. Mixed spellings retain invocation order:
|
|
|
|
```text
|
|
foo --color red --colour blue
|
|
```
|
|
|
|
With `--colour` mapped to singleton `--color`, the normal last-occurrence rule
|
|
selects `blue`. Earlier invalid occurrences remain errors under the existing
|
|
conversion contract. For a repeatable target, occurrences through either
|
|
spelling accumulate in order. Alias resolution adds no second conversion or
|
|
input-preparation lifecycle.
|
|
|
|
Flag aliases do not change canonical flag ownership or add new provider
|
|
capabilities.
|
|
|
|
### Chains and short spellings
|
|
|
|
Support flag-alias chains, such as `--colour → --hue → --color`. At each step,
|
|
use the selected command's effective mappings, with command-scoped mappings
|
|
taking precedence over application-wide mappings. Resolve to the final
|
|
canonical flag and use its binding.
|
|
|
|
Apply target-availability rules to the final destination. An application-wide
|
|
chain contributes nothing where its final canonical flag is unavailable. A
|
|
command-scoped declaration must resolve to an available canonical flag. Reject
|
|
cycles during installation, identify the participating spellings in diagnostics,
|
|
and revalidate composition after later registration.
|
|
|
|
Support individual short alias spellings, such as `-c → --color`, alongside
|
|
long aliases. Canonical short spellings and aliases use the same cluster and
|
|
attached-value grammar and may mix freely within a cluster. Resolve each alias
|
|
to its final canonical flag before determining whether it consumes a value.
|
|
|
|
Process short spellings left to right. Boolean flags use presence as true;
|
|
explicit boolean values require `=`. The first value-taking flag consumes the
|
|
remaining suffix, removing a separating `=` when present, or consumes the next
|
|
argument if there is no suffix. Consumed values are never searched for aliases.
|
|
Unknown spellings within a cluster produce a usage error. Preserve occurrence
|
|
order for repeatable bindings and singleton last-occurrence behavior.
|
|
|
|
With boolean aliases `-v → --verbose` and `-q → --quiet`, and value-taking
|
|
`-c → --color`:
|
|
|
|
| Input | Interpretation |
|
|
| --- | --- |
|
|
| `-vq` | `--verbose --quiet` |
|
|
| `-c blue`, `-c=blue`, or `-cblue` | `--color=blue` |
|
|
| `-vqcblue` or `-vqc blue` | `--verbose --quiet --color=blue` |
|
|
| `-cvq` | `--color=vq` |
|
|
| `-v=false` | `--verbose=false` |
|
|
| `-qv=false` | `--quiet --verbose=false` |
|
|
|
|
`-vfalse` is a cluster beginning with `-v`, not an explicit false value.
|
|
A spelling such as `-color` follows short-option parsing; long aliases use
|
|
the `--` prefix. Options still follow the complete command path, and `--`
|
|
ends option parsing.
|
|
|
|
Correct explicit empty-value handling for both canonical short spellings and
|
|
aliases: `-c=` supplies an empty string, consistently with `--color=` and
|
|
`-c ""`. The current backend instead passes the literal string `"="` for `-c=`;
|
|
this delivery corrects that behavior. Likewise, `-v=` supplies an empty value
|
|
to boolean conversion and fails conversion. This correction preserves the
|
|
distinction between an omitted value and an explicitly supplied empty value.
|
|
|
|
### Flag help and diagnostics
|
|
|
|
Present aliases alongside their canonical flags in help. Show only mappings
|
|
effective in the current scope, resolve chains to their final targets, and
|
|
document each canonical input once. For example:
|
|
|
|
```text
|
|
--color VALUE
|
|
Output color.
|
|
Aliases: --colour, -c
|
|
```
|
|
|
|
When identifying an invalid occurrence in diagnostics, retain the spelling
|
|
the operator supplied and identify the canonical flag where helpful. Conversion,
|
|
required-value checks, and repetition behavior continue to come from the
|
|
canonical binding.
|
|
|
|
## Work needed from the baseline
|
|
|
|
1. Finalize the installer declaration type and open routing details with consumer examples
|
|
covering a command shortcut, a synonym inside an integration namespace, and
|
|
a group shortcut, an application-wide help flag alias, and a command-scoped
|
|
flag alias reached through a command shortcut.
|
|
2. Capture the durable separation between application alias routing and canonical
|
|
command and flag ownership in an ADR. Keep exact API, matching, and presentation
|
|
details in their appropriate contracts. No relaxation of canonical namespace
|
|
ownership is selected.
|
|
3. Extend installation to validate aliases and commands against the complete
|
|
candidate batch, preserving retained errors and atomicity. Keep aliases
|
|
independent of optional-library dependencies and backend-specific exports.
|
|
4. Integrate command and flag alias resolution with canonical routing, help, and
|
|
invocation identity. Use canonical flag metadata and the existing parser to
|
|
preserve values and operands, and reuse typed execution machinery. Apply the
|
|
selected short-option grammar and correct explicit empty values for canonical
|
|
short spellings and aliases together.
|
|
5. Add focused behavioral evidence for both example mappings, group aliases,
|
|
longest matches, chains, group composition, cycles and nonterminating prefix
|
|
expansion, collisions, missing targets, same-batch
|
|
resolution, later registration, argument preservation, help without
|
|
acquisition, and a single execution lifecycle. Cover application-wide and
|
|
command-scoped flag mappings, attached and separate values, option termination,
|
|
mixed canonical/alias repetitions, flag chains and scope overrides, short
|
|
aliases, mixed clusters, attached values, explicit empty-value correction,
|
|
flag help and diagnostics, and unchanged typed binding semantics.
|
|
6. Add maintained consumer examples and update GoDoc, the CLI reference, consumer
|
|
guidance, and internal documentation when implementation lands. Validate the
|
|
affected modules under the [developer guide](../development.md).
|
|
|
|
Completion means consumers can declare alternate command paths and flag
|
|
spellings with minimal wiring and invoke canonical behavior and help through
|
|
them while canonical ownership and binding semantics stay intact. Installation
|
|
rejects conflicts with canonical commands and applicable flags in either
|
|
registration order. Remaining public API details are listed below.
|
|
|
|
## Open Decisions
|
|
|
|
### OD-1: Installer declaration type and composition details
|
|
|
|
The shared installation API, path strings, explicit flag scopes, identical
|
|
duplicate handling, and core-only availability are selected above. What public
|
|
declaration type lets `New` and `App.Register` accept commands and aliases
|
|
together? How do collections of reusable declarations and group composition
|
|
interact with application-root alias paths? What exact whitespace parsing and
|
|
path validation rules accompany the selected string representation? What
|
|
accessor names and representation expose the selected read-only entered and
|
|
canonical invocation paths?
|