diff --git a/.opencode/tools/tjwater_cli.ts b/.opencode/tools/tjwater_cli.ts index e72a0f6..462d0eb 100644 --- a/.opencode/tools/tjwater_cli.ts +++ b/.opencode/tools/tjwater_cli.ts @@ -14,7 +14,7 @@ export default tool({ command: tool.schema .string() .describe( - "tjwater-cli 子命令,不含二进制路径。示例:'project list'、'data timeseries realtime links --start-time 2025-01-01T00:00:00+08:00 --end-time 2025-01-01T01:00:00+08:00'", + "tjwater-cli 子命令,不含二进制路径。示例:'data scheme list'、'data timeseries realtime links --start-time 2025-01-01T00:00:00+08:00 --end-time 2025-01-01T01:00:00+08:00'", ), timeout: tool.schema .number() diff --git a/cli/src/commands/data.ts b/cli/src/commands/data.ts index 5cf56f9..bca471e 100644 --- a/cli/src/commands/data.ts +++ b/cli/src/commands/data.ts @@ -6,6 +6,10 @@ import { resolveScheme } from "../core/runtime.js"; import { parseTime } from "../core/time.js"; import type { HandlerMap, RuntimeContext } from "../core/types.js"; +function backendElementType(type: ElementType): "link" | "node" { + return type === "pipe" ? "link" : "node"; +} + function rangeGet(ctx: RuntimeContext, argv: string[], summary: string, path: string): Promise { const { values } = parseOptions(argv); return emitApi(ctx, summary, { @@ -18,10 +22,11 @@ function rangeGet(ctx: RuntimeContext, argv: string[], summary: string, path: st function realtimeByIdTime(ctx: RuntimeContext, argv: string[]): Promise { const { values } = parseOptions(argv); + const type = validateChoice(requiredString(values, "type"), ["pipe", "junction"] as const, "--type"); return emitApi(ctx, "读取实时模拟数据成功", { method: "GET", path: "/timeseries/realtime/simulation-results", - params: { id: requiredString(values, "id"), type: validateChoice(requiredString(values, "type"), ["pipe", "junction"] as const, "--type"), query_time: parseTime(requiredString(values, "time"), "--time") }, + params: { id: requiredString(values, "id"), type: backendElementType(type), query_time: parseTime(requiredString(values, "time"), "--time") }, requireProject: true, }); } @@ -32,7 +37,7 @@ function realtimeByTimeProperty(ctx: RuntimeContext, argv: string[]): Promise { scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true), scheme_type: optionalString(values, "scheme-type") || "simulation", query_time: parseTime(requiredString(values, "time"), "--time"), - type, + type: backendElementType(type), }; if (query === "by-id-time") { params.id = requiredString(values, "id"); diff --git a/node-tests/cli/tjwaterCli.node.mjs b/node-tests/cli/tjwaterCli.node.mjs index 5b48bc4..e04470e 100644 --- a/node-tests/cli/tjwaterCli.node.mjs +++ b/node-tests/cli/tjwaterCli.node.mjs @@ -262,6 +262,26 @@ test("uses project scoped headers for realtime data commands", async () => { } }); +test("maps CLI pipe and junction types to backend link and node types", async () => { + const server = await startJsonServer({ accepted: true }); + const auth = { server: server.url, access_token: "token-3", project_id: "project-1" }; + const at = "2025-01-02T03:30:00+08:00"; + try { + for (const args of [ + ["data", "timeseries", "realtime", "simulation-by-id-time", "--id", "J1", "--type", "junction", "--time", at], + ["data", "timeseries", "realtime", "simulation-by-time-property", "--type", "pipe", "--time", at, "--property", "flow"], + ["data", "timeseries", "scheme", "simulation", "--query", "by-id-time", "--id", "P1", "--type", "pipe", "--time", at, "--scheme", "scheme_case"], + ]) { + const result = await runCli(["--auth-stdin", ...args], auth); + assert.equal(result.exitCode, 0, result.stderr); + } + const queries = server.seen.map(normalizeSeenRequest).map((request) => request.query.type); + assert.deepEqual(queries, ["node", "link", "link"]); + } finally { + await server.close(); + } +}); + test("matches Python CLI backend request shape for every command and key variants", async () => { const tempDir = await mkdtemp(join(tmpdir(), "tjwater-cli-parity-")); try {