diff --git a/packages/coding-agent/src/modes/setup-wizard/lazy.ts b/packages/coding-agent/src/modes/setup-wizard/lazy.ts index 159b5cc33..dc4eabd2f 100644 --- a/packages/coding-agent/src/modes/setup-wizard/lazy.ts +++ b/packages/coding-agent/src/modes/setup-wizard/lazy.ts @@ -1,6 +1,8 @@ import type { InteractiveModeContext } from "../types"; export async function runProviderSetupWizard(ctx: InteractiveModeContext): Promise { + // Keep the full setup wizard behind the existing cold-start boundary; a static + // import here would load provider/OAuth/search/theme setup deps on every TUI startup. const { ALL_SCENES, runSetupWizard } = await import("./index"); const providersScene = ALL_SCENES.find(scene => scene.id === "providers"); if (!providersScene) { diff --git a/packages/coding-agent/src/slash-commands/builtin-registry.ts b/packages/coding-agent/src/slash-commands/builtin-registry.ts index 6c0223dce..91345c028 100644 --- a/packages/coding-agent/src/slash-commands/builtin-registry.ts +++ b/packages/coding-agent/src/slash-commands/builtin-registry.ts @@ -86,7 +86,6 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray = [ name: "setup", aliases: ["providers"], description: "Open provider setup", - inlineHint: "[providers]", allowArgs: true, subcommands: [{ name: "providers", description: "Configure sign-in and web search providers" }], handleTui: async (command, runtime) => { @@ -95,7 +94,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray = [ if (opensProviders) { await runtime.ctx.showProviderSetup(); } else { - runtime.ctx.showWarning("Usage: /setup [providers]"); + runtime.ctx.showWarning(`Usage: /${command.name} [providers]`); } runtime.ctx.editor.setText(""); }, diff --git a/packages/coding-agent/test/slash-commands/setup.test.ts b/packages/coding-agent/test/slash-commands/setup.test.ts index 9f236ca56..7f855235e 100644 --- a/packages/coding-agent/test/slash-commands/setup.test.ts +++ b/packages/coding-agent/test/slash-commands/setup.test.ts @@ -71,4 +71,15 @@ describe("/setup slash command", () => { expect(harness.showWarning).toHaveBeenCalledWith("Usage: /setup [providers]"); expect(harness.setText).toHaveBeenCalledWith(""); }); + + it("shows alias-specific usage for unsupported providers alias arguments", async () => { + const harness = createRuntime(); + + const handled = await executeBuiltinSlashCommand("/providers theme", harness.runtime); + + expect(handled).toBe(true); + expect(harness.showProviderSetup).not.toHaveBeenCalled(); + expect(harness.showWarning).toHaveBeenCalledWith("Usage: /providers [providers]"); + expect(harness.setText).toHaveBeenCalledWith(""); + }); }); diff --git a/packages/tui/src/autocomplete.ts b/packages/tui/src/autocomplete.ts index 08b28f9d0..247bbd7a5 100644 --- a/packages/tui/src/autocomplete.ts +++ b/packages/tui/src/autocomplete.ts @@ -259,16 +259,18 @@ function buildSlashCommandCompletions(commands: CommandEntry[], lowerPrefix: str }); } - for (const alias of getCommandAliases(cmd)) { - if (alias === name) continue; - const aliasScore = scoreCommandTextMatch(lowerPrefix, alias.toLowerCase()); - if (aliasScore === 0) continue; - candidates.push({ - value: alias, - label: alias, - score: aliasScore, - ...(fullDesc && { description: fullDesc }), - }); + if (lowerPrefix.length > 0) { + for (const alias of getCommandAliases(cmd)) { + if (alias === name) continue; + const aliasScore = scoreCommandTextMatch(lowerPrefix, alias.toLowerCase()); + if (aliasScore === 0) continue; + candidates.push({ + value: alias, + label: alias, + score: aliasScore, + ...(fullDesc && { description: fullDesc }), + }); + } } return candidates; diff --git a/packages/tui/test/autocomplete.test.ts b/packages/tui/test/autocomplete.test.ts index b3da026fe..b6818554f 100644 --- a/packages/tui/test/autocomplete.test.ts +++ b/packages/tui/test/autocomplete.test.ts @@ -292,6 +292,19 @@ describe("trySyncSlashCompletion", () => { expect(result!.items.map(i => i.value)).toEqual(["model"]); }); + it("does not list aliases as separate rows for bare slash suggestions", async () => { + const provider = new CombinedAutocompleteProvider( + [ + { name: "setup", aliases: ["providers"], description: "Open provider setup" }, + { name: "usage", description: "Show provider usage and limits" }, + ], + "/tmp", + ); + const result = await provider.getSuggestions(["/"], 0, 1); + expect(result).not.toBeNull(); + expect(result!.items.map(i => i.value)).toEqual(["setup", "usage"]); + }); + it("prefers exact command aliases over fuzzy description matches", () => { const provider = new CombinedAutocompleteProvider( [