chore(cli): rebrand CLI from Claude to CoStrict with restructured help output

This commit is contained in:
yhangf 2026-04-28 14:28:21 +08:00
parent fc78a84ccf
commit 6fe647c10d

View File

@ -1243,9 +1243,11 @@ async function getInputPrompt(
async function run(): Promise<CommanderCommand> { async function run(): Promise<CommanderCommand> {
profileCheckpoint("run_function_start"); profileCheckpoint("run_function_start");
// Create help config that sorts options by long option name. // Create help config that sorts options by long option name and puts
// Commander supports compareOptions at runtime but @commander-js/extra-typings // Commands section before Options section in the root command's help output.
// doesn't include it in the type definitions, so we use Object.assign to add it. // Commander supports compareOptions/formatHelp at runtime but
// @commander-js/extra-typings doesn't include them in the type definitions,
// so we use Object.assign to add them.
function createSortedHelpConfig(): { function createSortedHelpConfig(): {
sortSubcommands: true; sortSubcommands: true;
sortOptions: true; sortOptions: true;
@ -1257,10 +1259,72 @@ async function run(): Promise<CommanderCommand> {
{ {
compareOptions: (a: Option, b: Option) => compareOptions: (a: Option, b: Option) =>
getOptionSortKey(a).localeCompare(getOptionSortKey(b)), getOptionSortKey(a).localeCompare(getOptionSortKey(b)),
// Reorder help sections: Usage → Description → Arguments →
// Commands → Options (matching cs/opencode style).
// Uses duck-typed access because @commander-js/extra-typings
// doesn't expose the full Help class API.
formatHelp: (cmd: CommanderCommand, helper: unknown) => {
const h = helper as {
padWidth: (cmd: CommanderCommand, helper: unknown) => number;
helpWidth: number;
commandUsage: (cmd: CommanderCommand) => string;
commandDescription: (cmd: CommanderCommand) => string;
visibleArguments: (cmd: CommanderCommand) => unknown[];
visibleCommands: (cmd: CommanderCommand) => unknown[];
visibleOptions: (cmd: CommanderCommand) => unknown[];
argumentTerm: (arg: unknown) => string;
argumentDescription: (arg: unknown) => string;
subcommandTerm: (cmd: unknown) => string;
subcommandDescription: (cmd: unknown) => string;
optionTerm: (opt: unknown) => string;
optionDescription: (opt: unknown) => string;
formatItem: (term: string, termWidth: number, description: string, helper: unknown) => string;
styleTitle: (s: string) => string;
styleUsage: (s: string) => string;
styleCommandDescription: (s: string) => string;
styleArgumentTerm: (s: string) => string;
styleArgumentDescription: (s: string) => string;
styleSubcommandTerm: (s: string) => string;
styleSubcommandDescription: (s: string) => string;
styleOptionTerm: (s: string) => string;
styleOptionDescription: (s: string) => string;
boxWrap: (s: string, width: number) => string;
};
const termWidth = h.padWidth(cmd, helper);
const helpWidth = h.helpWidth ?? 80;
const fmt = (term: string, desc: string) =>
h.formatItem(term, termWidth, desc, helper);
let output = [
`${h.styleTitle('Usage:')} ${h.styleUsage(h.commandUsage(cmd))}`,
'',
];
const desc = h.commandDescription(cmd);
if (desc.length > 0) {
output = output.concat([h.boxWrap(h.styleCommandDescription(desc), helpWidth), '']);
}
// Order: Commands → Options → Arguments (matches usage line: [options] [command] [prompt])
const cmdList = h.visibleCommands(cmd).map(c =>
fmt(h.styleSubcommandTerm(h.subcommandTerm(c)), h.styleSubcommandDescription(h.subcommandDescription(c))));
if (cmdList.length > 0) output = output.concat([h.styleTitle('Commands:'), ...cmdList, '']);
const optList = h.visibleOptions(cmd).map(o =>
fmt(h.styleOptionTerm(h.optionTerm(o)), h.styleOptionDescription(h.optionDescription(o))));
if (optList.length > 0) output = output.concat([h.styleTitle('Options:'), ...optList, '']);
const argList = h.visibleArguments(cmd).map(a =>
fmt(h.styleArgumentTerm(h.argumentTerm(a)), h.styleArgumentDescription(h.argumentDescription(a))));
if (argList.length > 0) output = output.concat([h.styleTitle('Arguments:'), ...argList, '']);
return output.join('\n');
},
}, },
); );
} }
const program = new CommanderCommand() const program = new CommanderCommand()
.addHelpCommand(false)
.configureHelp(createSortedHelpConfig()) .configureHelp(createSortedHelpConfig())
.enablePositionalOptions(); .enablePositionalOptions();
profileCheckpoint("run_commander_initialized"); profileCheckpoint("run_commander_initialized");
@ -1340,10 +1404,9 @@ async function run(): Promise<CommanderCommand> {
}); });
program program
.name("claude") .name("csc")
.description( .description(`CoStrict AI coding assistant`)
`CoStrict - starts an interactive session by default, use -p/--print for non-interactive output`, .usage("[command] [options] [prompt]")
)
.argument("[prompt]", "Your prompt", String) .argument("[prompt]", "Your prompt", String)
// Subcommands inherit helpOption via commander's copyInheritedSettings — // Subcommands inherit helpOption via commander's copyInheritedSettings —
// setting it once here covers mcp, plugin, auth, and all other subcommands. // setting it once here covers mcp, plugin, auth, and all other subcommands.
@ -1363,25 +1426,28 @@ async function run(): Promise<CommanderCommand> {
.argParser(Boolean) .argParser(Boolean)
.hideHelp(), .hideHelp(),
) )
.option( .addOption(
"--debug-file <path>", new Option("--debug-file <path>", "Write debug logs to a specific file path (implicitly enables debug mode)")
"Write debug logs to a specific file path (implicitly enables debug mode)", .argParser(() => true)
() => true, .hideHelp(),
) )
.option( .addOption(
"--verbose", new Option("--verbose", "Override verbose mode setting from config")
"Override verbose mode setting from config", .argParser(() => true)
() => true, .hideHelp(),
) )
.option( .option(
"-p, --print", "-p, --print",
"Print response and exit (useful for pipes). Note: The workspace trust dialog is skipped when Claude is run with the -p mode. Only use this flag in directories you trust.", "Print response and exit (useful for pipes). Note: The workspace trust dialog is skipped when CSC is run with the -p mode. Only use this flag in directories you trust.",
() => true, () => true,
) )
.option( .addOption(
"--bare", new Option(
"Minimal mode: skip hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery. Sets CLAUDE_CODE_SIMPLE=1. Anthropic auth is strictly ANTHROPIC_API_KEY or apiKeyHelper via --settings (OAuth and keychain are never read). 3P providers (Bedrock/Vertex/Foundry) use their own credentials. Skills still resolve via /skill-name. Explicitly provide context via: --system-prompt[-file], --append-system-prompt[-file], --add-dir (CLAUDE.md dirs), --mcp-config, --settings, --agents, --plugin-dir.", "--bare",
() => true, "Minimal mode: skip hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery. Sets CLAUDE_CODE_SIMPLE=1. Anthropic auth is strictly ANTHROPIC_API_KEY or apiKeyHelper via --settings (OAuth and keychain are never read). 3P providers (Bedrock/Vertex/Foundry) use their own credentials. Skills still resolve via /skill-name. Explicitly provide context via: --system-prompt[-file], --append-system-prompt[-file], --add-dir (CLAUDE.md dirs), --mcp-config, --settings, --agents, --plugin-dir.",
)
.argParser(() => true)
.hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
@ -1412,33 +1478,39 @@ async function run(): Promise<CommanderCommand> {
"--json-schema <schema>", "--json-schema <schema>",
"JSON Schema for structured output validation. " + "JSON Schema for structured output validation. " +
'Example: {"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}', 'Example: {"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}',
).argParser(String), )
.argParser(String)
.hideHelp(),
) )
.option( .addOption(
"--include-hook-events", new Option("--include-hook-events", "Include all hook lifecycle events in the output stream (only works with --output-format=stream-json)")
"Include all hook lifecycle events in the output stream (only works with --output-format=stream-json)", .argParser(() => true)
() => true, .hideHelp(),
) )
.option( .addOption(
"--include-partial-messages", new Option("--include-partial-messages", "Include partial message chunks as they arrive (only works with --print and --output-format=stream-json)")
"Include partial message chunks as they arrive (only works with --print and --output-format=stream-json)", .argParser(() => true)
() => true, .hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
"--input-format <format>", "--input-format <format>",
'Input format (only works with --print): "text" (default), or "stream-json" (realtime streaming input)', 'Input format (only works with --print): "text" (default), or "stream-json" (realtime streaming input)',
).choices(["text", "stream-json"]), )
.choices(["text", "stream-json"])
.hideHelp(),
) )
.option( .addOption(
"--mcp-debug", new Option(
"[DEPRECATED. Use --debug instead] Enable MCP debug mode (shows MCP server errors)", "--mcp-debug",
() => true, "[DEPRECATED. Use --debug instead] Enable MCP debug mode (shows MCP server errors)",
)
.argParser(() => true)
.hideHelp(),
) )
.option( .addOption(
"--dangerously-skip-permissions", new Option("--dangerously-skip-permissions", "Bypass all permission checks. Recommended only for sandboxes with no internet access.")
"Bypass all permission checks. Recommended only for sandboxes with no internet access.", .argParser(() => true),
() => true,
) )
// .option( // .option(
// "--allow-dangerously-skip-permissions", // "--allow-dangerously-skip-permissions",
@ -1473,15 +1545,17 @@ async function run(): Promise<CommanderCommand> {
new Option( new Option(
"--max-budget-usd <amount>", "--max-budget-usd <amount>",
"Maximum dollar amount to spend on API calls (only works with --print)", "Maximum dollar amount to spend on API calls (only works with --print)",
).argParser((value) => { )
const amount = Number(value); .argParser((value) => {
if (isNaN(amount) || amount <= 0) { const amount = Number(value);
throw new Error( if (isNaN(amount) || amount <= 0) {
"--max-budget-usd must be a positive number greater than 0", throw new Error(
); "--max-budget-usd must be a positive number greater than 0",
} );
return amount; }
}), return amount;
})
.hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
@ -1503,10 +1577,10 @@ async function run(): Promise<CommanderCommand> {
}) })
.hideHelp(), .hideHelp(),
) )
.option( .addOption(
"--replay-user-messages", new Option("--replay-user-messages", "Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json)")
"Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json)", .argParser(() => true)
() => true, .hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
@ -1516,21 +1590,35 @@ async function run(): Promise<CommanderCommand> {
.default(false) .default(false)
.hideHelp(), .hideHelp(),
) )
.option( .addOption(
"--allowedTools, --allowed-tools <tools...>", new Option(
'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")', "--allowed-tools <tools...>",
'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")',
).hideHelp(),
) )
.option( .addOption(
"--tools <tools...>", new Option(
'Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read").', "--allowedTools <tools...>",
'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")',
).hideHelp(),
) )
.option( .addOption(
"--disallowedTools, --disallowed-tools <tools...>", new Option("--tools <tools...>", 'Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read").').hideHelp(),
'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")',
) )
.option( .addOption(
"--mcp-config <configs...>", new Option(
"Load MCP servers from JSON files or strings (space-separated)", "--disallowed-tools <tools...>",
'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")',
).hideHelp(),
)
.addOption(
new Option(
"--disallowedTools <tools...>",
'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")',
).hideHelp(),
)
.addOption(
new Option("--mcp-config <configs...>", "Load MCP servers from JSON files or strings (space-separated)").hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
@ -1558,7 +1646,9 @@ async function run(): Promise<CommanderCommand> {
new Option( new Option(
"--append-system-prompt <prompt>", "--append-system-prompt <prompt>",
"Append a system prompt to the default system prompt", "Append a system prompt to the default system prompt",
).argParser(String), )
.argParser(String)
.hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
@ -1586,10 +1676,10 @@ async function run(): Promise<CommanderCommand> {
"Resume a conversation by session ID, or open interactive picker with optional search term", "Resume a conversation by session ID, or open interactive picker with optional search term",
(value) => value || true, (value) => value || true,
) )
.option( .addOption(
"--fork-session", new Option("--fork-session", "When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)")
"When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)", .argParser(() => true)
() => true, .hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
@ -1620,14 +1710,14 @@ async function run(): Promise<CommanderCommand> {
}) })
.hideHelp(), .hideHelp(),
) )
.option( .addOption(
"--from-pr [value]", new Option("--from-pr [value]", "Resume a session linked to a PR by PR number/URL, or open interactive picker with optional search term")
"Resume a session linked to a PR by PR number/URL, or open interactive picker with optional search term", .argParser((value) => value || true)
(value) => value || true, .hideHelp(),
) )
.option( .addOption(
"--no-session-persistence", new Option("--no-session-persistence", "Disable session persistence - sessions will not be saved to disk and cannot be resumed (only works with --print)")
"Disable session persistence - sessions will not be saved to disk and cannot be resumed (only works with --print)", .hideHelp(),
) )
.addOption( .addOption(
new Option( new Option(
@ -1646,34 +1736,34 @@ async function run(): Promise<CommanderCommand> {
// @[MODEL LAUNCH]: Update the example model ID in the --model help text. // @[MODEL LAUNCH]: Update the example model ID in the --model help text.
.option( .option(
"--model <model>", "--model <model>",
`Model for the current session. Provide an alias for the latest model (e.g. 'sonnet' or 'opus') or a model's full name (e.g. 'claude-sonnet-4-6').`, `Model for the current session. Provide a model's full name (e.g. 'GLM-5.1').`,
) )
.addOption( .addOption(
new Option( new Option(
"--effort <level>", "--effort <level>",
`Effort level for the current session (low, medium, high, max)`, `Effort level for the current session (low, medium, high, max)`,
).argParser((rawValue: string) => { )
const value = rawValue.toLowerCase(); .argParser((rawValue: string) => {
const allowed = ["low", "medium", "high", "max"]; const value = rawValue.toLowerCase();
if (!allowed.includes(value)) { const allowed = ["low", "medium", "high", "max"];
throw new InvalidArgumentError( if (!allowed.includes(value)) {
`It must be one of: ${allowed.join(", ")}`, throw new InvalidArgumentError(
); `It must be one of: ${allowed.join(", ")}`,
} );
return value; }
}), return value;
})
.hideHelp(),
) )
.option( .option(
"--agent <agent>", "--agent <agent>",
`Agent for the current session. Overrides the 'agent' setting.`, `Agent for the current session. Overrides the 'agent' setting.`,
) )
.option( .addOption(
"--betas <betas...>", new Option("--betas <betas...>", "Beta headers to include in API requests (API key users only)").hideHelp(),
"Beta headers to include in API requests (API key users only)",
) )
.option( .addOption(
"--fallback-model <model>", new Option("--fallback-model <model>", "Enable automatic fallback to specified model when default model is overloaded (only works with --print)").hideHelp(),
"Enable automatic fallback to specified model when default model is overloaded (only works with --print)",
) )
.addOption( .addOption(
new Option( new Option(
@ -1689,49 +1779,46 @@ async function run(): Promise<CommanderCommand> {
"--add-dir <directories...>", "--add-dir <directories...>",
"Additional directories to allow tool access to", "Additional directories to allow tool access to",
) )
.option( .addOption(
"--ide", new Option("--ide", "Automatically connect to IDE on startup if exactly one valid IDE is available")
"Automatically connect to IDE on startup if exactly one valid IDE is available", .argParser(() => true)
() => true, .hideHelp(),
) )
.option( .addOption(
"--strict-mcp-config", new Option("--strict-mcp-config", "Only use MCP servers from --mcp-config, ignoring all other MCP configurations")
"Only use MCP servers from --mcp-config, ignoring all other MCP configurations", .argParser(() => true)
() => true, .hideHelp(),
) )
.option( .addOption(
"--session-id <uuid>", new Option("--session-id <uuid>", "Use a specific session ID for the conversation (must be a valid UUID)").hideHelp(),
"Use a specific session ID for the conversation (must be a valid UUID)",
) )
.option( .addOption(
"-n, --name <name>", new Option("-n, --name <name>", "Set a display name for this session (shown in /resume and terminal title)").hideHelp(),
"Set a display name for this session (shown in /resume and terminal title)",
) )
.option( .addOption(
"--agents <json>", new Option("--agents <json>", 'JSON object defining custom agents (e.g. \'{"reviewer": {"description": "Reviews code", "prompt": "You are a code reviewer"}}\')').hideHelp(),
'JSON object defining custom agents (e.g. \'{"reviewer": {"description": "Reviews code", "prompt": "You are a code reviewer"}}\')',
) )
.option( .addOption(
"--setting-sources <sources>", new Option("--setting-sources <sources>", "Comma-separated list of setting sources to load (user, project, local).").hideHelp(),
"Comma-separated list of setting sources to load (user, project, local).",
) )
// gh-33508: <paths...> (variadic) consumed everything until the next // gh-33508: <paths...> (variadic) consumed everything until the next
// --flag. `claude --plugin-dir /path mcp add --transport http` swallowed // --flag. `claude --plugin-dir /path mcp add --transport http` swallowed
// `mcp` and `add` as paths, then choked on --transport as an unknown // `mcp` and `add` as paths, then choked on --transport as an unknown
// top-level option. Single-value + collect accumulator means each // top-level option. Single-value + collect accumulator means each
// --plugin-dir takes exactly one arg; repeat the flag for multiple dirs. // --plugin-dir takes exactly one arg; repeat the flag for multiple dirs.
.option( .addOption(
"--plugin-dir <path>", new Option("--plugin-dir <path>", "Load plugins from a directory for this session only (repeatable: --plugin-dir A --plugin-dir B)")
"Load plugins from a directory for this session only (repeatable: --plugin-dir A --plugin-dir B)", .argParser((val: string, prev: string[]) => [...prev, val])
(val: string, prev: string[]) => [...prev, val], .default([] as string[])
[] as string[], .hideHelp(),
) )
.option("--disable-slash-commands", "Disable all skills", () => true) .addOption(
.option("--chrome", "Enable Claude in Chrome integration") new Option("--disable-slash-commands", "Disable all skills").argParser(() => true).hideHelp(),
.option("--no-chrome", "Disable Claude in Chrome integration") )
.option( .addOption(new Option("--chrome", "Enable Claude in Chrome integration").hideHelp())
"--file <specs...>", .addOption(new Option("--no-chrome", "Disable Claude in Chrome integration").hideHelp())
"File resources to download at startup. Format: file_id:relative_path (e.g., --file file_abc:doc.txt file_def:img.png)", .addOption(
new Option("--file <specs...>", "File resources to download at startup. Format: file_id:relative_path (e.g., --file file_abc:doc.txt file_def:img.png)").hideHelp(),
) )
.action(async (prompt, options) => { .action(async (prompt, options) => {
profileCheckpoint("action_handler_start"); profileCheckpoint("action_handler_start");
@ -5532,13 +5619,11 @@ async function run(): Promise<CommanderCommand> {
); );
// Worktree flags // Worktree flags
program.option( program.addOption(
"-w, --worktree [name]", new Option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)").hideHelp(),
"Create a new git worktree for this session (optionally specify a name)",
); );
program.option( program.addOption(
"--tmux", new Option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.").hideHelp(),
"Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.",
); );
if (canUserConfigureAdvisor()) { if (canUserConfigureAdvisor()) {
@ -5598,7 +5683,7 @@ async function run(): Promise<CommanderCommand> {
if (feature("PROACTIVE") || feature("KAIROS")) { if (feature("PROACTIVE") || feature("KAIROS")) {
program.addOption( program.addOption(
new Option("--proactive", "Start in proactive autonomous mode"), new Option("--proactive", "Start in proactive autonomous mode").hideHelp(),
); );
} }
@ -5607,7 +5692,7 @@ async function run(): Promise<CommanderCommand> {
new Option( new Option(
"--messaging-socket-path <path>", "--messaging-socket-path <path>",
"Unix domain socket path for the UDS messaging server (defaults to a tmp path)", "Unix domain socket path for the UDS messaging server (defaults to a tmp path)",
), ).hideHelp(),
); );
} }
@ -5616,7 +5701,7 @@ async function run(): Promise<CommanderCommand> {
new Option( new Option(
"--brief", "--brief",
"Enable SendUserMessage tool for agent-to-user communication", "Enable SendUserMessage tool for agent-to-user communication",
), ).hideHelp(),
); );
} }
if (feature("KAIROS")) { if (feature("KAIROS")) {
@ -5759,6 +5844,7 @@ async function run(): Promise<CommanderCommand> {
const mcp = program const mcp = program
.command("mcp") .command("mcp")
.description("Configure and manage MCP servers") .description("Configure and manage MCP servers")
.addHelpCommand(false)
.configureHelp(createSortedHelpConfig()) .configureHelp(createSortedHelpConfig())
.enablePositionalOptions(); .enablePositionalOptions();
@ -5792,6 +5878,7 @@ async function run(): Promise<CommanderCommand> {
} }
mcp.command("remove <name>") mcp.command("remove <name>")
.alias("rm")
.description("Remove an MCP server") .description("Remove an MCP server")
.option( .option(
"-s, --scope <scope>", "-s, --scope <scope>",
@ -5803,18 +5890,15 @@ async function run(): Promise<CommanderCommand> {
}); });
mcp.command("list") mcp.command("list")
.description( .alias("ls")
"List configured MCP servers. Note: The workspace trust dialog is skipped and stdio servers from .mcp.json are spawned for health checks. Only use this command in directories you trust.", .description("List configured MCP servers")
)
.action(async () => { .action(async () => {
const { mcpListHandler } = await import("./cli/handlers/mcp.js"); const { mcpListHandler } = await import("./cli/handlers/mcp.js");
await mcpListHandler(); await mcpListHandler();
}); });
mcp.command("get <name>") mcp.command("get <name>")
.description( .description("Get details about an MCP server")
"Get details about an MCP server. Note: The workspace trust dialog is skipped and stdio servers from .mcp.json are spawned for health checks. Only use this command in directories you trust.",
)
.action(async (name: string) => { .action(async (name: string) => {
const { mcpGetHandler } = await import("./cli/handlers/mcp.js"); const { mcpGetHandler } = await import("./cli/handlers/mcp.js");
await mcpGetHandler(name); await mcpGetHandler(name);
@ -6088,6 +6172,7 @@ async function run(): Promise<CommanderCommand> {
const auth = program const auth = program
.command("auth") .command("auth")
.description("Manage authentication") .description("Manage authentication")
.addHelpCommand(false)
.configureHelp(createSortedHelpConfig()); .configureHelp(createSortedHelpConfig());
auth.command("login") auth.command("login")
@ -6149,7 +6234,9 @@ async function run(): Promise<CommanderCommand> {
const pluginCmd = program const pluginCmd = program
.command("plugin") .command("plugin")
.alias("plugins") .alias("plugins")
.alias("plug")
.description("Manage CoStrict plugins") .description("Manage CoStrict plugins")
.addHelpCommand(false)
.configureHelp(createSortedHelpConfig()); .configureHelp(createSortedHelpConfig());
pluginCmd pluginCmd
@ -6165,6 +6252,7 @@ async function run(): Promise<CommanderCommand> {
// Plugin list command // Plugin list command
pluginCmd pluginCmd
.command("list") .command("list")
.alias("ls")
.description("List installed plugins") .description("List installed plugins")
.option("--json", "Output as JSON") .option("--json", "Output as JSON")
.option( .option(
@ -6406,7 +6494,7 @@ async function run(): Promise<CommanderCommand> {
// Reads from disk cache — GrowthBook isn't initialized at registration time. // Reads from disk cache — GrowthBook isn't initialized at registration time.
if (getAutoModeEnabledStateIfCached() !== "disabled") { if (getAutoModeEnabledStateIfCached() !== "disabled") {
const autoModeCmd = program const autoModeCmd = program
.command("auto-mode") .command("auto-mode", { hidden: true })
.description("Inspect auto mode classifier configuration"); .description("Inspect auto mode classifier configuration");
autoModeCmd autoModeCmd
@ -6471,7 +6559,7 @@ async function run(): Promise<CommanderCommand> {
if (feature("KAIROS")) { if (feature("KAIROS")) {
program program
.command("assistant [sessionId]") .command("assistant [sessionId]", { hidden: true })
.description( .description(
"Attach the REPL as a client to a running bridge session. Discovers sessions via API if no sessionId given.", "Attach the REPL as a client to a running bridge session. Discovers sessions via API if no sessionId given.",
) )
@ -6503,7 +6591,7 @@ async function run(): Promise<CommanderCommand> {
program program
.command('doctor') .command('doctor')
.description( .description(
'Check the health of your CoStrict auto-updater. Note: The workspace trust dialog is skipped and stdio servers from .mcp.json are spawned for health checks. Only use this command in directories you trust.', 'Check the health of your CoStrict auto-updater',
) )
.action(async () => { .action(async () => {
const [{ doctorHandler }, { createRoot }] = await Promise.all([ const [{ doctorHandler }, { createRoot }] = await Promise.all([