What
When Cobra rejects an unknown command, the error names the bad token and, when the edit distance is small enough, a "Did you mean this?" suggestion. It never lists the commands the caller could actually run. I would like an opt-in that appends the available command set to that error.
Current behaviour
legacyArgs produces:
Error: unknown command "lst" for "app"
findSuggestions adds a "Did you mean this?" block only when SuggestionsFor finds a near match (Levenshtein distance <= SuggestionsMinimumDistance, default 2, or a name prefix). A token with no near match gets nothing beyond Run 'app --help' for usage.
So app lst (a typo of list) may get a suggestion, but app frobnicate gets none. In neither case does the caller see the full menu without a second --help round-trip.
Why this helps
Two audiences benefit:
- Humans see the valid options inline, without re-running with
--help.
- LLM agents driving the CLI recover in one step. A fuzzy "did you mean" only rescues a near-miss typo. An agent that guesses a plausible but wrong verb hits a dead end today. The available-command list gives it the menu to pick the right call on the next turn. That is the difference between a one-shot recovery and a stalled retry loop.
Proposed change
An opt-in that appends the available commands to the unknown-command error. It would use IsAvailableCommand, so hidden and deprecated commands stay out:
Error: unknown command "frobnicate" for "app"; available commands: list, get, add, edit, delete
A cap (say, the first 10) keeps the line readable for large trees. The exact shape is open: a Command field, a setting on the suggestion machinery, or a hook. It composes with, rather than replaces, the "did you mean" block.
Reference implementation
I ship this in a CLI today by building the error by hand:
func unknownSubcommandError(cmd *cobra.Command, name string) error {
msg := fmt.Sprintf("unknown command %q for %q", name, cmd.CommandPath())
if s := cmd.SuggestionsFor(name); len(s) > 0 {
msg += fmt.Sprintf(" (did you mean %q?)", s[0])
}
var avail []string
for _, sub := range cmd.Commands() {
if sub.IsAvailableCommand() {
avail = append(avail, sub.Name())
}
}
if len(avail) > 0 {
msg += fmt.Sprintf("; available commands: %s", strings.Join(avail, ", "))
}
return fmt.Errorf("%s", msg)
}
It works, but every user who wants this re-implements it, and wiring it onto a command group also means giving the group its own RunE to dodge a separate problem (a non-runnable parent swallows an unknown subcommand and exits 0, tracked in #2130 / #2167). Built-in support would cover the common case without the boilerplate.
Related
What
When Cobra rejects an unknown command, the error names the bad token and, when the edit distance is small enough, a "Did you mean this?" suggestion. It never lists the commands the caller could actually run. I would like an opt-in that appends the available command set to that error.
Current behaviour
legacyArgsproduces:findSuggestionsadds a "Did you mean this?" block only whenSuggestionsForfinds a near match (Levenshtein distance<= SuggestionsMinimumDistance, default 2, or a name prefix). A token with no near match gets nothing beyondRun 'app --help' for usage.So
app lst(a typo oflist) may get a suggestion, butapp frobnicategets none. In neither case does the caller see the full menu without a second--helpround-trip.Why this helps
Two audiences benefit:
--help.Proposed change
An opt-in that appends the available commands to the unknown-command error. It would use
IsAvailableCommand, so hidden and deprecated commands stay out:A cap (say, the first 10) keeps the line readable for large trees. The exact shape is open: a
Commandfield, a setting on the suggestion machinery, or a hook. It composes with, rather than replaces, the "did you mean" block.Reference implementation
I ship this in a CLI today by building the error by hand:
It works, but every user who wants this re-implements it, and wiring it onto a command group also means giving the group its own
RunEto dodge a separate problem (a non-runnable parent swallows an unknown subcommand and exits 0, tracked in #2130 / #2167). Built-in support would cover the common case without the boilerplate.Related
SetSuggestFunc). That mechanism could host this, but the requests are distinct: this one is about which information the error carries, not about restyling the existing "did you mean" text.findSuggestions.