import { CliError } from "./core/errors.js"; import { handlers } from "./handlers.js"; import { helpPayload } from "./help/index.js"; import { failure, json } from "./core/output.js"; import type { RuntimeContext } from "./core/types.js"; export async function dispatch(ctx: RuntimeContext | null, argv: string[]): Promise { if (argv.length === 0 || argv.includes("--help")) { process.stdout.write("Usage: tjwater-cli [OPTIONS] COMMAND [ARGS]...\n\nStructured JSON:\n tjwater-cli help\n"); return; } if (argv[0] === "help") { const payload = helpPayload(argv.slice(1)); if (!payload) { failure({ summary: "未找到命令", code: "COMMAND_NOT_FOUND", message: `unknown command path: ${argv.slice(1).join(" ")}`, retryable: false, data: { usage: "tjwater-cli help ", examples: ["tjwater-cli help simulation run", "tjwater-cli simulation help"] }, nextCommands: ["tjwater-cli help", "tjwater-cli help simulation"], }); return; } json(payload); return; } const matched = matchCommand(argv); if (!matched) throw new CliError("未找到命令", "COMMAND_NOT_FOUND", `No such command: ${argv.join(" ")}`, 2, false, { usage: "tjwater-cli help" }, ["tjwater-cli help"]); const handler = handlers[matched.path]; if (!handler) throw new CliError("未找到命令", "COMMAND_NOT_FOUND", `No such command: ${argv.join(" ")}`, 2, false, { usage: "tjwater-cli help" }, ["tjwater-cli help"]); if (!ctx && matched.path !== "__noop") throw new CliError("CLI 参数错误", "RUNTIME_REQUIRED", "runtime context is required for command execution", 2); await handler(ctx!, matched.args); } function matchCommand(argv: string[]): { path: string; args: string[] } | null { const paths = Object.keys(handlers).sort((a, b) => b.split(" ").length - a.split(" ").length); for (const path of paths) { const parts = path.split(" "); if (parts.every((part, index) => argv[index] === part)) return { path, args: argv.slice(parts.length) }; } if (argv.at(-1) === "help") { const payload = helpPayload(argv.slice(0, -1)); if (payload) { json(payload); return { path: "__noop", args: [] }; } } return null; }