fix(autocomplete): repair /gsd skip, add widget/next completions, add discuss to hint (#1675)
* fix(autocomplete): repair /gsd skip, add widget/next --debug completions, add discuss to description - fix: bare `/gsd skip` (no args) fell through all handlers and hit the "Unknown command" warning — add a usage message handler matching `trimmed === "skip"` consistent with steer/knowledge/run-hook - fix: `next` handler supports `--debug` (enables debug logging) but it was absent from NESTED_COMPLETIONS; add alongside --verbose/--dry-run - fix: `widget` accepts full|small|min|off args but had no autocomplete entries; add widget to NESTED_COMPLETIONS with all four modes - fix: `discuss` was in TOP_LEVEL_SUBCOMMANDS and fully implemented but omitted from GSD_COMMAND_DESCRIPTION hint string; add it * test(gsd): add autocomplete regressions for skip/widget/next/discuss
This commit is contained in:
parent
9e21abfc19
commit
137a80b9bf
3 changed files with 95 additions and 1 deletions
|
|
@ -14,7 +14,7 @@ export interface GsdCommandDefinition {
|
|||
type CompletionMap = Record<string, readonly GsdCommandDefinition[]>;
|
||||
|
||||
export const GSD_COMMAND_DESCRIPTION =
|
||||
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|capture|triage|dispatch|history|undo|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update";
|
||||
"GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|widget|visualize|queue|quick|discuss|capture|triage|dispatch|history|undo|rate|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|logs|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|cmux|park|unpark|init|setup|inspect|extensions|update";
|
||||
|
||||
export const TOP_LEVEL_SUBCOMMANDS: readonly GsdCommandDefinition[] = [
|
||||
{ cmd: "help", desc: "Categorized command reference with descriptions" },
|
||||
|
|
@ -74,6 +74,13 @@ const NESTED_COMPLETIONS: CompletionMap = {
|
|||
next: [
|
||||
{ cmd: "--verbose", desc: "Show detailed step output" },
|
||||
{ cmd: "--dry-run", desc: "Preview next step without executing" },
|
||||
{ cmd: "--debug", desc: "Enable debug logging" },
|
||||
],
|
||||
widget: [
|
||||
{ cmd: "full", desc: "Full widget display" },
|
||||
{ cmd: "small", desc: "Compact widget display" },
|
||||
{ cmd: "min", desc: "Minimal widget display" },
|
||||
{ cmd: "off", desc: "Hide widget" },
|
||||
],
|
||||
mode: [
|
||||
{ cmd: "global", desc: "Edit global workflow mode" },
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ export async function handleOpsCommand(trimmed: string, ctx: ExtensionCommandCon
|
|||
await handleUndo(trimmed.replace(/^undo\s*/, "").trim(), ctx, pi, projectRoot());
|
||||
return true;
|
||||
}
|
||||
if (trimmed === "skip") {
|
||||
ctx.ui.notify("Usage: /gsd skip <unit-id> Example: /gsd skip M001/S01/T03", "warning");
|
||||
return true;
|
||||
}
|
||||
if (trimmed.startsWith("skip ")) {
|
||||
await handleSkip(trimmed.replace(/^skip\s*/, "").trim(), ctx, projectRoot());
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { registerGSDCommand } from "../commands.ts";
|
||||
import { handleGSDCommand } from "../commands/dispatcher.ts";
|
||||
|
||||
function createMockPi() {
|
||||
const commands = new Map<string, any>();
|
||||
return {
|
||||
registerCommand(name: string, options: any) {
|
||||
commands.set(name, options);
|
||||
},
|
||||
registerTool() {},
|
||||
registerShortcut() {},
|
||||
on() {},
|
||||
sendMessage() {},
|
||||
commands,
|
||||
};
|
||||
}
|
||||
|
||||
function createMockCtx() {
|
||||
const notifications: { message: string; level: string }[] = [];
|
||||
return {
|
||||
notifications,
|
||||
ui: {
|
||||
notify(message: string, level: string) {
|
||||
notifications.push({ message, level });
|
||||
},
|
||||
custom: async () => {},
|
||||
},
|
||||
shutdown: async () => {},
|
||||
};
|
||||
}
|
||||
|
||||
test("/gsd description includes discuss", () => {
|
||||
const pi = createMockPi();
|
||||
registerGSDCommand(pi as any);
|
||||
|
||||
const gsd = pi.commands.get("gsd");
|
||||
assert.ok(gsd, "registerGSDCommand should register /gsd");
|
||||
assert.ok(
|
||||
gsd.description.includes("discuss"),
|
||||
"description should include discuss",
|
||||
);
|
||||
});
|
||||
|
||||
test("/gsd next completions include --debug", () => {
|
||||
const pi = createMockPi();
|
||||
registerGSDCommand(pi as any);
|
||||
|
||||
const gsd = pi.commands.get("gsd");
|
||||
const completions = gsd.getArgumentCompletions("next ");
|
||||
const debug = completions.find((c: any) => c.value === "next --debug");
|
||||
assert.ok(debug, "next --debug should appear in completions");
|
||||
});
|
||||
|
||||
test("/gsd widget completions include full|small|min|off", () => {
|
||||
const pi = createMockPi();
|
||||
registerGSDCommand(pi as any);
|
||||
|
||||
const gsd = pi.commands.get("gsd");
|
||||
const completions = gsd.getArgumentCompletions("widget ");
|
||||
const values = completions.map((c: any) => c.value);
|
||||
for (const expected of ["widget full", "widget small", "widget min", "widget off"]) {
|
||||
assert.ok(values.includes(expected), `missing completion: ${expected}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("bare /gsd skip shows usage and does not fall through to unknown-command warning", async () => {
|
||||
const ctx = createMockCtx();
|
||||
|
||||
await handleGSDCommand("skip", ctx as any, {} as any);
|
||||
|
||||
assert.ok(
|
||||
ctx.notifications.some((n) => n.message.includes("Usage: /gsd skip <unit-id>")),
|
||||
"should show skip usage guidance",
|
||||
);
|
||||
assert.ok(
|
||||
!ctx.notifications.some((n) => n.message.startsWith("Unknown: /gsd skip")),
|
||||
"should not emit unknown-command warning for bare skip",
|
||||
);
|
||||
});
|
||||
|
||||
Loading…
Add table
Reference in a new issue