51 lines
2.2 KiB
TypeScript
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;
|
|
}
|