openclaw - ✅(Solved) Fix feat(cli): suggest closest command for unknown subcommands [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#83999Fetched 2026-05-20 03:45:26
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
1
Timeline (top)
labeled ×4commented ×1cross-referenced ×1

Suggest the closest known CLI command when openclaw receives an unknown root command.

Error Message

  • Do not auto-correct or auto-run. Only append a hint to the existing error output.
  • src/cli/program/error-output.ts formats Commander unknown-command parse errors.
  • src/cli/program/error-output.test.ts already covers unknown-command formatting.
  • src/cli/run-main.exit.test.ts has related CLI dispatch/error coverage.

Root Cause

Suggest the closest known CLI command when openclaw receives an unknown root command.

Fix Action

Fix / Workaround

  • src/cli/program/core-command-descriptors.ts exposes core command names via getCoreCliCommandNames().
  • src/cli/program/subcli-descriptors.ts exposes sub-CLI roots via getSubCliEntries() and includes update.
  • src/cli/run-main.ts has the early unknown-primary path: resolveUnownedCliPrimaryMessage().
  • src/cli/program/error-output.ts formats Commander unknown-command parse errors.
  • src/cli/program/error-output.test.ts already covers unknown-command formatting.
  • src/cli/run-main.exit.test.ts has related CLI dispatch/error coverage.

PR fix notes

PR #84036: feat(cli): suggest closest command for unknown subcommands (#83999)

Description (problem / solution / changelog)

Closes #83999.

Summary

`openclaw upate` and `openclaw upgrade` previously failed with a generic `OpenClaw does not know the command "upate".` and left the user to inspect `openclaw --help` manually. This change appends npm-style `Did you mean this?` suggestions, computed from Levenshtein distance against the registered root commands plus a tight explicit alias map for terminology that doesn't fall out of edit distance (`upgrade -> update`, `remove -> uninstall`, `rm -> uninstall`, `ls -> list`, `ping -> doctor`).

Output shapes:

``` $ openclaw upate OpenClaw does not know the command "upate". Did you mean this? openclaw update Try: openclaw --help Plugin command? openclaw plugins list Docs: https://docs.openclaw.ai/cli ```

``` $ openclaw upgrade OpenClaw does not know the command "upgrade". Did you mean this? openclaw update ... ```

``` $ openclaw zzqwerty # no suggestion when nothing is close OpenClaw does not know the command "zzqwerty". Try: openclaw --help ... ```

Design

  • `suggestClosestCommand` is exported from `src/cli/program/error-output.ts` and takes `(unknown, known[])`. Known commands are passed via the new `knownCommands` option on `formatCliParseErrorOptions`.
  • Explicit aliases win over edit distance — `upgrade -> update` is canonical even when other short roots score closer numerically.
  • Alias target must exist in `knownCommands` so the suggester can't invent a command that this build doesn't actually have.
  • npm-style threshold: distance must be `<= floor(input.length * 0.4)` (min 1). Keeps `zzqwerty` from misleadingly resolving to a 4-character root.
  • Two-row Levenshtein, `O(min(a,b))` memory, `O(a*b)` time. CLI roots are short, so this is fine.
  • No auto-correct, no auto-run: just an appended hint, same as the existing plugin hint.
  • Wired into the one caller (`src/cli/program/help.ts:108`) via `program.commands.map((cmd) => cmd.name())`, so the catalog stays in sync with whatever `openclaw --help` lists. When `knownCommands` is omitted (legacy callers / tests) the suggester is a no-op — behavior is unchanged.

Real behavior proof

Behavior addressed: unknown root commands now append `Did you mean this?` with the closest registered command (or alias target) when the distance is small enough.

Real environment tested: darwin / arm64 / Node 22.21.1, openclaw source tree at HEAD of branch above.

Exact steps or command run after this patch:

``` node scripts/run-vitest.mjs src/cli/program/error-output.test.ts ./node_modules/.bin/oxlint --type-aware src/cli/program/error-output.ts src/cli/program/error-output.test.ts src/cli/program/help.ts ```

Evidence after fix:

``` $ node scripts/run-vitest.mjs src/cli/program/error-output.test.ts RUN v4.1.6 /Users/harshkumarkaithwas/Desktop/openclaw

Test Files 1 passed (1) Tests 13 passed (13)

$ ./node_modules/.bin/oxlint --type-aware src/cli/program/error-output.ts src/cli/program/error-output.test.ts src/cli/program/help.ts Found 0 warnings and 0 errors. ```

Observed result after fix: `formatCliParseErrorOutput` now emits `Did you mean this?\n openclaw update\n` between the unknown-command error line and the `Try:` hint when (a) a typo is within edit-distance threshold OR (b) the input matches an entry in the explicit alias map AND the alias target is registered.

What was not tested: live binary spawn against a built `openclaw` CLI — covered transitively by the existing parse-error round-trip and `run-main.exit.test.ts` suite, which both call the same Commander `outputError` path.

Coverage

Unit tests in `src/cli/program/error-output.test.ts`:

CaseAsserts
typo `upate` with full `knownCommands`suggestion `openclaw update`
explicit alias `upgrade`suggestion `openclaw update` even though distance picks differently
off-vocabulary `zzqwerty`no `Did you mean this?` line
legacy caller without `knownCommands`output unchanged
`suggestClosestCommand` direct: typo / off-vocab / alias / empty / case-insensitivehelper-level coverage

Notes

  • No public API change; `knownCommands` is additive on an existing options bag.
  • Local lint+format wrappers (`node scripts/run-oxlint.mjs`, `pnpm format`) hit a pre-existing dts boundary failure on `@openclaw/proxyline` unrelated to this PR; ran `./node_modules/.bin/oxlint --type-aware` and `./node_modules/.bin/oxfmt --write` directly on the touched files.

Changed files

  • src/cli/program/error-output.test.ts (modified, +69/-1)
  • src/cli/program/error-output.ts (modified, +86/-0)
  • src/cli/program/help.ts (modified, +10/-1)

Code Example

OpenClaw does not know the command "upate".
Did you mean this?
  openclaw update
Try: openclaw --help
Plugin command? openclaw plugins list
Docs: https://docs.openclaw.ai/cli

---

OpenClaw does not know the command "upgrade".
Did you mean this?
  openclaw update
RAW_BUFFERClick to expand / collapse

This was generated by AI during triage.

Summary

Suggest the closest known CLI command when openclaw receives an unknown root command.

Problem to solve

Mistyped root commands currently fail with a generic unknown-command message and leave users to inspect openclaw --help manually. For near misses such as openclaw upate or common terminology such as openclaw upgrade, OpenClaw already has enough command metadata to point users at the intended command (openclaw update) without changing behavior or auto-running anything.

This is a small CLI UX improvement: reduce friction, avoid unnecessary docs/help lookup, and make mistakes recoverable in one terminal turn.

Proposed solution

Add npm-style suggestions for unknown root commands:

  • Keep a small explicit alias map for known/common terms where edit distance is not enough, e.g. upgrade -> update.
  • Compute simple Levenshtein distance from the unknown root command to known built-in root command names.
  • Consider both core commands and sub-CLI roots from the existing descriptor catalogs.
  • Only suggest when the best match is close enough, e.g. distance < input.length * 0.4, similar to npm's threshold.
  • Do not auto-correct or auto-run. Only append a hint to the existing error output.
  • Keep plugin-command policy behavior intact. If existing plugin allowlist/ownership diagnostics apply, preserve them and append suggestions only where appropriate.

Example desired output:

OpenClaw does not know the command "upate".
Did you mean this?
  openclaw update
Try: openclaw --help
Plugin command? openclaw plugins list
Docs: https://docs.openclaw.ai/cli

For explicit aliases:

OpenClaw does not know the command "upgrade".
Did you mean this?
  openclaw update

Alternatives considered

  • Only print openclaw --help: current behavior; correct but slower for common typos.
  • Auto-run the corrected command: risky and surprising, especially for commands that mutate state.
  • Rely only on Levenshtein: misses semantic/common aliases such as upgrade -> update.
  • Add Commander aliases for typo terms: would execute misspelled commands instead of teaching the canonical command, and risks preserving accidental API surface.

Impact

Affected users: CLI users who mistype root commands or use common adjacent terminology.

Severity: Low/medium UX friction; not blocking, but it causes extra manual help lookup.

Frequency: Intermittent but common for commands like update, doctor, config, plugins, channels, and models.

Consequence: Extra terminal turns and worse first-run CLI experience.

Evidence/examples

npm uses a similar approach:

  • explicit alias/typo mapping in its command list, e.g. upgrade -> update, udpate -> update
  • fastest-levenshtein for close matches
  • close threshold roughly distance(input, command) < input.length * 0.4
  • prints suggestions but does not auto-run unknown commands

Relevant OpenClaw implementation surfaces observed in the repo:

  • src/cli/program/core-command-descriptors.ts exposes core command names via getCoreCliCommandNames().
  • src/cli/program/subcli-descriptors.ts exposes sub-CLI roots via getSubCliEntries() and includes update.
  • src/cli/run-main.ts has the early unknown-primary path: resolveUnownedCliPrimaryMessage().
  • src/cli/program/error-output.ts formats Commander unknown-command parse errors.
  • src/cli/program/error-output.test.ts already covers unknown-command formatting.
  • src/cli/run-main.exit.test.ts has related CLI dispatch/error coverage.

Additional information

Suggested implementation shape:

  1. Add a small pure helper, e.g. src/cli/program/command-suggestions.ts:
    • CLI_COMMAND_ALIASES = { upgrade: "update" }
    • levenshteinDistance(a, b) implemented locally to avoid a new dependency
    • suggestCliCommands(input, candidates) returns up to 3 close command names
    • default candidates from getCoreCliCommandNames() plus getSubCliEntries().map(entry => entry.name)
  2. Use the helper in formatCliParseErrorOutput() for Commander parse errors.
  3. Use the helper in resolveUnownedCliPrimaryMessage() so the early plugin-aware unknown-primary path gets the same suggestion.
  4. Add tests for:
    • upate -> update
    • upgrade -> update
    • weak matches do not suggest
    • existing plugin-policy diagnostics remain unchanged except for optional appended suggestion when applicable

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix feat(cli): suggest closest command for unknown subcommands [1 pull requests, 1 comments, 2 participants]