/** 命令定義:名稱、說明、參數與執行。供 help 與分發使用。 */ export interface ParsedArgs { /** 位置參數(子命令後的非選項值)。 */ positionals: string[]; /** 選項旗標(--key value 或 --flag)。 */ flags: Record; } export interface CommandContext { args: ParsedArgs; /** 輸出 JSON 到 stdout(唯一 stdout 內容)。 */ print: (value: unknown) => void; } export interface Command { /** 子命令路徑,例如 ["tokens", "verify"]。 */ path: string[]; summary: string; usage: string; /** 位置參數說明,例如 [""]。與 usage 一致即可。 */ run: (ctx: CommandContext) => Promise | void; } /** 解析 argv:--key value、--key=value、--flag(布林)、-- 結束選項。 */ export function parseArgs(argv: string[]): ParsedArgs { const positionals: string[] = []; const flags: Record = {}; let i = 0; let noMoreFlags = false; while (i < argv.length) { const arg = argv[i++]!; if (!noMoreFlags && arg === "--") { noMoreFlags = true; continue; } if (!noMoreFlags && arg.startsWith("--")) { const eq = arg.indexOf("="); if (eq !== -1) { const key = arg.slice(2, eq); const value = arg.slice(eq + 1); flags[key] = value; } else { const key = arg.slice(2); const next = argv[i]; if (next !== undefined && !next.startsWith("--")) { flags[key] = next; i += 1; } else { flags[key] = true; } } continue; } positionals.push(arg); } return { positionals, flags }; } export function flagString(flags: Record, key: string): string | undefined { const v = flags[key]; return typeof v === "string" ? v : undefined; } /** 註冊表:以完整路徑字串("tokens verify")索引。 */ export class Registry { private readonly commands = new Map(); add(command: Command): void { this.commands.set(command.path.join(" "), command); } /** 找出命令;prefix 可指向群組(回傳其子命令列表供 help)。 */ find(prefix: string[]): Command | undefined { return this.commands.get(prefix.join(" ")); } /** 列出 prefix 下的下一層子命令(供群組 help)。 */ children(prefix: string[]): Command[] { return Array.from(this.commands.values()).filter((c) => { if (c.path.length !== prefix.length + 1) return false; return prefix.every((p, idx) => c.path[idx] === p); }); } all(): Command[] { return Array.from(this.commands.values()); } }