Files
TJWaterAgent/cli/src/dispatch.ts
T
jiang 93d70da8be
Agent CI/CD / deploy-fallback-log (push) Has been cancelled
Agent CI/CD / docker-image (push) Has been cancelled
refactor(cli): split tjwater cli modules
2026-06-07 19:43:44 +08:00

51 lines
2.2 KiB
TypeScript

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<void> {
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 <command-path>", 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;
}