fix(cli): an unknown command like search says which command does that (#6710)

* fix(cli): an unknown command like search says which command does that

* fix(cli): the synonym hint is checked before the spelling match, so list, find and browse reach it
This commit is contained in:
Miguel Ángel
2026-10-29 05:03:43 +00:00
committed by GitHub
parent 2f8c4b1daf
commit bb4deb8014
3 changed files with 25 additions and 2 deletions
+6
View File
@@ -286,6 +286,12 @@ describe("agent-mode contract", () => {
["cloud rendr", "Did you mean 'hyperframes cloud render'?"],
["help rendr", "Did you mean 'hyperframes render'?"],
["help cloud rendr", "Did you mean 'hyperframes cloud render'?"],
["search crossfade", "Did you mean 'hyperframes catalog'?"],
["install crossfade", "Did you mean 'hyperframes add'?"],
["find crossfade", "Did you mean 'hyperframes catalog'?"],
["list", "Did you mean 'hyperframes catalog'?"],
["browse", "Did you mean 'hyperframes catalog'?"],
["registry", "Did you mean 'hyperframes catalog'?"],
])(
"unknown command `%s` suggests the closest one, usage on stderr, exit 2",
async (args, hint) => {
+5 -2
View File
@@ -98,7 +98,7 @@ import {
markCommandDelivered,
} from "./utils/render-success-state.js";
import { resolveCommandUsage, type ResolvedCommandUsage } from "./utils/commandUsageResolution.js";
import { closestMatch } from "./utils/didYouMean.js";
import { closestMatch, synonymMatch } from "./utils/didYouMean.js";
import { jsonErrorBody, watchOutput, writeJsonFailure } from "./utils/jsonError.js";
import { isDevMode } from "./utils/env.js";
import {
@@ -542,7 +542,10 @@ async function unknownCommandError(requested: ResolvedCommandUsage): Promise<Cli
const group = ["hyperframes", ...requested.path].join(" ");
const declared = requested.command.subCommands;
const subCommands = typeof declared === "function" ? await declared() : await declared;
const match = closestMatch(word, Object.keys(subCommands ?? {}));
const names = Object.keys(subCommands ?? {});
const match =
(requested.path.length === 0 ? synonymMatch(word, names) : undefined) ??
closestMatch(word, names);
console.error(`Unknown command: ${word}`);
if (match) console.error(`Did you mean '${group} ${match}'?`);
console.error("");
+14
View File
@@ -28,3 +28,17 @@ export function closestMatch(input: string, candidates: Iterable<string>): strin
}
return best;
}
const COMMAND_SYNONYMS: Record<string, string> = {
search: "catalog",
find: "catalog",
browse: "catalog",
registry: "catalog",
list: "catalog",
install: "add",
};
export function synonymMatch(input: string, candidates: Iterable<string>): string | undefined {
const target = COMMAND_SYNONYMS[input];
return target !== undefined && [...candidates].includes(target) ? target : undefined;
}