From a4384330689e326db6ba4419fcb5f2bb2a3777c4 Mon Sep 17 00:00:00 2001 From: Huarch Date: Wed, 26 Aug 2026 17:28:41 +0800 Subject: [PATCH] refactor(cli)!: align commands with analysis run APIs Replace legacy scheme commands with run-id based analysis and timeseries queries. Update sensor placement and SCADA routes, and refresh CLI help, tests, and usage guidance. BREAKING CHANGE: legacy scheme, risk, and valve-close CLI command paths are removed. --- .opencode/skills/tjwater-cli/SKILL.md | 31 +++--- .opencode/tools/tjwater_cli.ts | 2 +- cli/src/commands/analysis.ts | 93 +++++++--------- cli/src/commands/data.ts | 93 +++++++--------- cli/src/help/docs.ts | 52 ++++----- node-tests/cli/tjwaterCli.node.mjs | 150 +++++++++++++++++--------- 6 files changed, 215 insertions(+), 206 deletions(-) diff --git a/.opencode/skills/tjwater-cli/SKILL.md b/.opencode/skills/tjwater-cli/SKILL.md index 865c431..ce1d963 100644 --- a/.opencode/skills/tjwater-cli/SKILL.md +++ b/.opencode/skills/tjwater-cli/SKILL.md @@ -35,15 +35,18 @@ description: tjwater-cli 命令行工具使用说明,涵盖命令发现、输 Agent 通过 `help` 动态发现可用命令,而非依赖硬编码清单。 -**重要:命令分为两类——触发动作与数据获取。** +**重要:命令分为三类——触发动作、运行/结果查询与时序数据获取。** -- **触发动作**(`simulation`、`analysis`):向服务端发起计算请求,返回任务状态/ID,**不直接返回分析结果**。 -- **数据获取**(`data timeseries`):所有计算结果(仿真压力、分析指标等)的唯一数据出口,需在触发动作完成后调用。 +- **触发动作**(`simulation`、各类 `analysis`):向服务端发起计算请求。 +- **运行/结果查询**(`analysis runs`):按 `run_id` 查询运行元数据和非时序结果。 +- **时序数据获取**(`data timeseries`):实时结果或按 `run_id` 查询节点、管道时序。 ``` -simulation/analysis → 触发计算 → 返回状态/任务ID - ↓ - data timeseries → 获取计算结果 +analysis → 触发计算 → analysis runs list/get/results + ↓ run_id + data timeseries analysis → 获取元素时序 + +simulation → 触发实时模拟 → data timeseries realtime → 获取实时结果 ``` 通过 `help` 发现命令: @@ -63,11 +66,11 @@ tjwater-cli help COMMAND → 子命令与参数详情 | 命令族 | 典型子命令 | 用途 | |------|-----------|------| -| `project` | `list`, `db-health` | 项目管理、数据库健康检查 | -| `data` | `timeseries realtime links / nodes`, `timeseries scada query` | **时序数据查询**(实时/SCADA),所有分析结果的唯一获取渠道 | +| `network` | `get-pipe-properties`, `get-all-pipes-properties` | 管网元素查询 | +| `component` | `option get`, `option schema` | 模型选项和结构查询 | +| `data` | `timeseries realtime`, `timeseries analysis`, `timeseries scada`, `scada` | 实时、分析时序和 SCADA 查询 | | `simulation` | 通过 `help simulation` 发现 | **触发水力仿真计算**(执行成功返回状态,实际结果需走 `data timeseries` 获取) | -| `analysis` | 通过 `help analysis` 发现 | **触发分析计算**(执行成功返回状态,实际结果需走 `data timeseries` 获取) | -| `net` | `list-pipes` | 管网拓扑查询 | +| `analysis` | `runs`, `sensor-placement` 及各类分析命令 | 触发分析,并按运行 ID 查询元数据与结果 | | `help` | (无子命令) | 命令发现入口 | > 完整命令清单始终以 `tjwater-cli help` 实时输出为准。 @@ -128,11 +131,11 @@ tjwater-cli help COMMAND → 子命令与参数详情 1. **禁止猜测命令** — 执行任何命令前必须先 `tjwater_cli(command="help ...")` 确认命令存在及参数签名,参数均已写在 help 中,禁止凭经验拼写 2. **reason 必填** — 每次调用必须说明具体理由 -3. **触发后取数据** — `simulation`/`analysis` 仅触发计算,结果必须从 `data timeseries` 获取,勿将触发返回的状态信息当作分析结果 +3. **按运行 ID 取结果** — 分析完成后先用 `analysis runs list/get/results` 获取 `run_id` 和非时序结果;元素时序再用 `data timeseries analysis` 查询 4. **文件分析** — workflow 脚本需要文件时使用 `store_result=true`,不得从 Bash 直接联网调用 CLI 5. **结果验证** — 始终检查 `ok` 字段,失败时先处理错误码再重试 6. **大结果集** — 优先过滤/采样,不要一次性拉取全部数据 -7. **模拟时长控制** — 模拟(`simulation`)或方案模拟的 `--duration` 不宜过长,建议每次仿真时间跨度控制在一小时以内,避免计算耗时过长或结果数据量过大 +7. **模拟时长控制** — 实时模拟或分析运行的 `--duration` 不宜过长,建议每次仿真时间跨度控制在一小时以内,避免计算耗时过长或结果数据量过大 ## 示例 @@ -145,11 +148,11 @@ tjwater-cli help COMMAND → 子命令与参数详情 ``` > `data timeseries realtime nodes` 仅接受 `--start-time` / `--end-time`,返回全量节点数据。 -### 按节点查询方案时序字段 +### 按节点查询分析运行时序字段 ```json { "reason": "查询节点 J-001 最近1小时的压力数据", - "command": "data timeseries scheme node-field --node J-001 --field pressure --start-time 2026-06-03T08:00:00+08:00 --end-time 2026-06-03T09:00:00+08:00" + "command": "data timeseries analysis node-field --run-id 00000000-0000-0000-0000-000000000001 --node J-001 --field pressure --start-time 2026-06-03T08:00:00+08:00 --end-time 2026-06-03T09:00:00+08:00" } ``` diff --git a/.opencode/tools/tjwater_cli.ts b/.opencode/tools/tjwater_cli.ts index d85c02e..e05a8b8 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 子命令,不含二进制路径。示例:'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'", + "tjwater-cli 子命令,不含二进制路径。示例:'analysis runs 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/analysis.ts b/cli/src/commands/analysis.ts index 6463301..68ba11c 100644 --- a/cli/src/commands/analysis.ts +++ b/cli/src/commands/analysis.ts @@ -1,10 +1,9 @@ import { CliError } from "../core/errors.js"; -import { emitApi, requestJson } from "../core/http.js"; +import { emitApi } from "../core/http.js"; import { assignDatasetKeys, parseBurstFile, parseValveSettingFile } from "../core/files.js"; import { optionalNumber, optionalString, optionalStringArray, parseOptions, requiredNumber, requiredString, validateChoice } from "../core/options.js"; import { resolveScheme } from "../core/runtime.js"; import { parseTime } from "../core/time.js"; -import { success } from "../core/output.js"; import type { HandlerMap, RuntimeContext } from "../core/types.js"; function analysisBurst(ctx: RuntimeContext, argv: string[]): Promise { @@ -22,30 +21,13 @@ function analysisBurst(ctx: RuntimeContext, argv: string[]): Promise { scheme_name: schemeName, }, requireProject: true, - }, [`tjwater-cli data scheme get --name ${schemeName}`, "tjwater-cli data scheme list"]); + }, ["tjwater-cli analysis runs list"]); } -function analysisValve(ctx: RuntimeContext, argv: string[]): Promise { - const { values } = parseOptions(argv, { valve: "repeat", element: "repeat", "disabled-valve": "repeat", duration: "integer" }); - const mode = validateChoice(requiredString(values, "mode"), ["close", "isolation"] as const, "--mode"); - if (mode === "close") { - const valves = optionalStringArray(values, "valve"); - const startTime = optionalString(values, "start-time"); - if (!startTime || !valves) throw new CliError("CLI 参数错误", "INVALID_VALVE_CLOSE_ARGS", "close mode requires --start-time and at least one --valve", 2); - return emitApi(ctx, "阀门关闭分析执行成功", { - method: "POST", - path: "/valve-isolation-analyses", - params: { - start_time: parseTime(startTime, "--start-time"), - valves, - duration: optionalNumber(values, "duration") || 900, - scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true), - }, - requireProject: true, - }); - } +function analysisValveIsolation(ctx: RuntimeContext, argv: string[]): Promise { + const { values } = parseOptions(argv, { element: "repeat", "disabled-valve": "repeat" }); const elements = optionalStringArray(values, "element"); - if (!elements) throw new CliError("CLI 参数错误", "INVALID_VALVE_ISOLATION_ARGS", "isolation mode requires at least one --element", 2); + if (!elements) throw new CliError("CLI 参数错误", "INVALID_VALVE_ISOLATION_ARGS", "at least one --element is required", 2); return emitApi(ctx, "阀门隔离分析执行成功", { method: "POST", path: "/valve-isolation-analyses", @@ -97,14 +79,16 @@ function analysisContaminant(ctx: RuntimeContext, argv: string[]): Promise return emitApi(ctx, "污染物模拟执行成功", { method: "POST", path: "/contaminant-simulations", params, requireProject: true }); } -function sensorKmeans(ctx: RuntimeContext, argv: string[]): Promise { +function sensorPlacementRun(ctx: RuntimeContext, argv: string[]): Promise { const { values } = parseOptions(argv, { count: "integer", "min-diameter": "integer" }); return emitApi(ctx, "传感器选址执行成功", { method: "POST", - path: "/pressure-sensor-placement-kmeans", + path: "/sensor-placement-runs", body: { - scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true), - sensor_number: requiredNumber(values, "count"), + run_name: requiredString(values, "run-name"), + sensor_type: "pressure", + method: validateChoice(requiredString(values, "method"), ["sensitivity", "kmeans"] as const, "--method"), + sensor_count: requiredNumber(values, "count"), min_diameter: optionalNumber(values, "min-diameter") || 0, }, requireProject: true, @@ -125,14 +109,25 @@ function schemeAnalysis(ctx: RuntimeContext, argv: string[], summary: string, pa }); } -function schemeList(ctx: RuntimeContext, summary: string, schemeType: string): Promise { - return emitApi(ctx, summary, { method: "GET", path: "/schemes", params: { scheme_type: schemeType }, requireProject: true }); +function analysisRunGet(ctx: RuntimeContext, argv: string[]): Promise { + const { values } = parseOptions(argv); + const runId = requiredString(values, "run-id"); + return emitApi(ctx, "读取分析运行成功", { + method: "GET", + path: `/analysis/runs/${encodeURIComponent(runId)}`, + requireProject: true, + }); } -function schemeGet(ctx: RuntimeContext, argv: string[], summary: string, schemeType: string): Promise { - const { positionals } = parseOptions(argv); - if (!positionals[0]) throw new CliError("CLI 参数错误", "MISSING_ARGUMENT", "Missing argument 'SCHEME_NAME'", 2); - return emitApi(ctx, summary, { method: "GET", path: `/schemes/${positionals[0]}`, params: { scheme_type: schemeType }, requireProject: true }); +function analysisRunResults(ctx: RuntimeContext, argv: string[]): Promise { + const { values } = parseOptions(argv); + const runId = requiredString(values, "run-id"); + return emitApi(ctx, "读取分析结果成功", { + method: "GET", + path: `/analysis/runs/${encodeURIComponent(runId)}/results`, + params: { result_type: optionalString(values, "result-type") }, + requireProject: true, + }); } function burstLocation(ctx: RuntimeContext, argv: string[]): Promise { @@ -156,34 +151,22 @@ function burstLocation(ctx: RuntimeContext, argv: string[]): Promise { return emitApi(ctx, "爆管定位执行成功", { method: "POST", path: "/burst-locations", body, requireProject: true }); } -function riskPipe(ctx: RuntimeContext, argv: string[], summary: string, path: string): Promise { - const { values } = parseOptions(argv); - return emitApi(ctx, summary, { method: "GET", path, params: { pipe_id: requiredString(values, "pipe") }, requireProject: true }); -} - -async function riskNetwork(ctx: RuntimeContext): Promise { - const [probabilities, a] = await requestJson(ctx, { method: "GET", path: "/network-pipe-risk-probability-nows", requireProject: true }); - const [geometries, b] = await requestJson(ctx, { method: "GET", path: "/pipes/risk-probability-geometries", requireProject: true }); - success("读取全网风险成功", { probabilities, geometries }, ctx, a + b); -} - export const analysisHandlers: HandlerMap = { "analysis burst": analysisBurst, - "analysis valve": analysisValve, + "analysis valve isolation": analysisValveIsolation, "analysis flushing": analysisFlushing, "analysis age": analysisAge, "analysis contaminant": analysisContaminant, - "analysis sensor-placement kmeans": sensorKmeans, + "analysis sensor-placement run": sensorPlacementRun, + "analysis sensor-placement list": (ctx) => emitApi(ctx, "读取传感器选址运行列表成功", { method: "GET", path: "/sensor-placement-runs", requireProject: true }), + "analysis sensor-placement get": (ctx, argv) => { + const { values } = parseOptions(argv); + return emitApi(ctx, "读取传感器选址运行成功", { method: "GET", path: `/sensor-placement-runs/${encodeURIComponent(requiredString(values, "run-id"))}`, requireProject: true }); + }, + "analysis runs list": (ctx) => emitApi(ctx, "读取分析运行列表成功", { method: "GET", path: "/analysis/runs", requireProject: true }), + "analysis runs get": analysisRunGet, + "analysis runs results": analysisRunResults, "analysis leakage identify": (ctx, argv) => schemeAnalysis(ctx, argv, "漏损识别执行成功", "/leakage-identifications", "scada_start", "scada_end"), - "analysis leakage schemes list": (ctx) => schemeList(ctx, "读取漏损方案列表成功", "dma_leak_identification"), - "analysis leakage schemes get": (ctx, argv) => schemeGet(ctx, argv, "读取漏损方案详情成功", "dma_leak_identification"), "analysis burst-detection detect": (ctx, argv) => schemeAnalysis(ctx, argv, "爆管检测执行成功", "/burst-detections", "scada_start", "scada_end"), - "analysis burst-detection schemes list": (ctx) => schemeList(ctx, "读取爆管检测方案列表成功", "burst_detection"), - "analysis burst-detection schemes get": (ctx, argv) => schemeGet(ctx, argv, "读取爆管检测方案详情成功", "burst_detection"), "analysis burst-location locate": burstLocation, - "analysis burst-location schemes list": (ctx) => schemeList(ctx, "读取爆管定位方案列表成功", "burst_location"), - "analysis burst-location schemes get": (ctx, argv) => schemeGet(ctx, argv, "读取爆管定位方案详情成功", "burst_location"), - "analysis risk pipe-now": (ctx, argv) => riskPipe(ctx, argv, "读取当前管道风险成功", "/pipes/risk-probability-now"), - "analysis risk pipe-history": (ctx, argv) => riskPipe(ctx, argv, "读取历史管道风险成功", "/pipes/risk-probability"), - "analysis risk network": riskNetwork, }; diff --git a/cli/src/commands/data.ts b/cli/src/commands/data.ts index bca471e..58c69e5 100644 --- a/cli/src/commands/data.ts +++ b/cli/src/commands/data.ts @@ -1,8 +1,8 @@ import { SCADA_FIELDS, type ElementType } from "../core/constants.js"; import { CliError } from "../core/errors.js"; -import { emitApi } from "../core/http.js"; -import { fieldsFor, optionalString, parseOptions, requiredString, requiredStringArray, validateChoice } from "../core/options.js"; -import { resolveScheme } from "../core/runtime.js"; +import { emitApi, requestAllPages } from "../core/http.js"; +import { fieldsFor, optionalNumber, optionalString, parseOptions, requiredString, requiredStringArray, validateChoice } from "../core/options.js"; +import { success } from "../core/output.js"; import { parseTime } from "../core/time.js"; import type { HandlerMap, RuntimeContext } from "../core/types.js"; @@ -42,14 +42,17 @@ function realtimeByTimeProperty(ctx: RuntimeContext, argv: string[]): Promise { +function analysisSeries(ctx: RuntimeContext, argv: string[], type: ElementType): Promise { const { values } = parseOptions(argv); - return emitApi(ctx, "读取方案管道数据成功", { + const runId = requiredString(values, "run-id"); + const idOption = type === "pipe" ? "link" : "node"; + const elementId = requiredString(values, idOption); + const elementPath = type === "pipe" ? "links" : "nodes"; + return emitApi(ctx, type === "pipe" ? "读取分析管道字段成功" : "读取分析节点字段成功", { method: "GET", - path: "/timeseries/schemes/links", + path: `/timeseries/analysis/runs/${encodeURIComponent(runId)}/${elementPath}/${encodeURIComponent(elementId)}`, params: { - scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true), - scheme_type: optionalString(values, "scheme-type") || "simulation", + field: validateChoice(requiredString(values, "field"), fieldsFor(type), "--field"), start_time: parseTime(requiredString(values, "start-time"), "--start-time"), end_time: parseTime(requiredString(values, "end-time"), "--end-time"), }, @@ -57,40 +60,21 @@ function schemeLinks(ctx: RuntimeContext, argv: string[]): Promise { }); } -function schemeNodeField(ctx: RuntimeContext, argv: string[]): Promise { +function analysisValues(ctx: RuntimeContext, argv: string[]): Promise { const { values } = parseOptions(argv); - return emitApi(ctx, "读取方案节点字段成功", { + const type = validateChoice(requiredString(values, "type"), ["pipe", "junction"] as const, "--type"); + return emitApi(ctx, "读取分析运行指定时刻结果成功", { method: "GET", - path: `/timeseries/schemes/nodes/${requiredString(values, "node")}/field`, + path: `/timeseries/analysis/runs/${encodeURIComponent(requiredString(values, "run-id"))}/values`, params: { - field: validateChoice(requiredString(values, "field"), fieldsFor("junction"), "--field"), - scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true), - scheme_type: optionalString(values, "scheme-type") || "simulation", - start_time: parseTime(requiredString(values, "start-time"), "--start-time"), - end_time: parseTime(requiredString(values, "end-time"), "--end-time"), + result_time: parseTime(requiredString(values, "time"), "--time"), + element_type: backendElementType(type), + field: validateChoice(requiredString(values, "field"), fieldsFor(type), "--field"), }, requireProject: true, }); } -function schemeSimulation(ctx: RuntimeContext, argv: string[]): Promise { - const { values } = parseOptions(argv); - const query = validateChoice(requiredString(values, "query"), ["by-id-time", "by-scheme-time-property"] as const, "--query"); - const type = validateChoice(optionalString(values, "type") || "pipe", ["pipe", "junction"] as const, "--type") as ElementType; - const params: Record = { - scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true), - scheme_type: optionalString(values, "scheme-type") || "simulation", - query_time: parseTime(requiredString(values, "time"), "--time"), - type: backendElementType(type), - }; - if (query === "by-id-time") { - params.id = requiredString(values, "id"); - return emitApi(ctx, "读取方案单点模拟数据成功", { method: "GET", path: "/timeseries/schemes/simulation-results", params, requireProject: true }); - } - params.property = validateChoice(requiredString(values, "property"), fieldsFor(type), "--property"); - return emitApi(ctx, "读取方案属性聚合数据成功", { method: "GET", path: "/timeseries/schemes/records", params, requireProject: true }); -} - function scadaQuery(ctx: RuntimeContext, argv: string[]): Promise { const { values } = parseOptions(argv, { "device-id": "repeat" }); const params: Record = { @@ -110,8 +94,8 @@ function composite(ctx: RuntimeContext, argv: string[]): Promise { start_time: parseTime(requiredString(values, "start-time"), "--start-time"), end_time: parseTime(requiredString(values, "end-time"), "--end-time"), }; - const schemeName = resolveScheme(ctx, optionalString(values, "scheme")); - if (schemeName) Object.assign(params, { scheme_name: schemeName, scheme_type: optionalString(values, "scheme-type") || "simulation" }); + const runId = optionalString(values, "run-id"); + if (runId && kind !== "element-scada") params.run_id = runId; if (kind === "scada-simulation") params.device_ids = requiredStringArray(values, "feature").join(","); else if (kind === "element-simulation") params.feature_infos = requiredStringArray(values, "feature").join(","); else { @@ -130,31 +114,28 @@ function composite(ctx: RuntimeContext, argv: string[]): Promise { function pipelineHealth(ctx: RuntimeContext, argv: string[]): Promise { const { values } = parseOptions(argv); - requiredString(values, "pipe"); - requiredString(values, "start-time"); return emitApi(ctx, "读取管道健康预测成功", { method: "GET", path: "/pipeline-health-predictions", - params: { query_time: parseTime(requiredString(values, "end-time"), "--end-time") }, + params: { query_time: parseTime(requiredString(values, "time"), "--time") }, requireProject: true, }); } function dataScadaGet(ctx: RuntimeContext, argv: string[]): Promise { const { values } = parseOptions(argv); - validateChoice(requiredString(values, "kind"), ["info"] as const, "--kind"); - return emitApi(ctx, "读取 SCADA 数据成功", { method: "GET", path: "/scada-info/detail", params: { id: requiredString(values, "id") }, requireProject: true }); + return emitApi(ctx, "读取 SCADA 设备成功", { method: "GET", path: "/scada-devices/detail", params: { device_id: requiredString(values, "device-id") }, requireProject: true }); } -function dataScadaList(ctx: RuntimeContext, argv: string[]): Promise { - const { values } = parseOptions(argv); - validateChoice(requiredString(values, "kind"), ["info"] as const, "--kind"); - return emitApi(ctx, "读取 SCADA 列表成功", { method: "GET", path: "/scada-info", requireProject: true }); -} - -function dataSchemeGet(ctx: RuntimeContext, argv: string[]): Promise { - const { values } = parseOptions(argv); - return emitApi(ctx, "读取方案成功", { method: "GET", path: "/schemes/detail", params: { schema_name: requiredString(values, "name") }, requireProject: true }); +async function dataScadaList(ctx: RuntimeContext, argv: string[]): Promise { + const { values } = parseOptions(argv, { "page-size": "integer" }); + const pageSize = Math.min(1000, Math.max(1, optionalNumber(values, "page-size") ?? 1000)); + const [data, durationMs] = await requestAllPages( + ctx, + { method: "GET", path: "/scada-devices", requireProject: true }, + pageSize, + ); + success("读取 SCADA 设备列表成功", data, ctx, durationMs); } export const dataHandlers: HandlerMap = { @@ -162,15 +143,13 @@ export const dataHandlers: HandlerMap = { "data timeseries realtime nodes": (ctx, argv) => rangeGet(ctx, argv, "读取实时节点数据成功", "/timeseries/realtime/nodes"), "data timeseries realtime simulation-by-id-time": realtimeByIdTime, "data timeseries realtime simulation-by-time-property": realtimeByTimeProperty, - "data timeseries scheme links": schemeLinks, - "data timeseries scheme node-field": schemeNodeField, - "data timeseries scheme simulation": schemeSimulation, + "data timeseries analysis link-field": (ctx, argv) => analysisSeries(ctx, argv, "pipe"), + "data timeseries analysis node-field": (ctx, argv) => analysisSeries(ctx, argv, "junction"), + "data timeseries analysis values": analysisValues, "data timeseries scada query": scadaQuery, "data timeseries composite": composite, - "data timeseries composite pipeline-health": pipelineHealth, + "data pipeline-health": pipelineHealth, "data scada get": dataScadaGet, "data scada list": dataScadaList, - "data scheme schema": (ctx) => emitApi(ctx, "读取方案 schema 成功", { method: "GET", path: "/network-schemas/scheme", requireProject: true }), - "data scheme get": dataSchemeGet, - "data scheme list": (ctx) => emitApi(ctx, "读取方案列表成功", { method: "GET", path: "/schemes", requireProject: true }), + "data scada schema": (ctx) => emitApi(ctx, "读取 SCADA 设备 schema 成功", { method: "GET", path: "/network-schemas/scada-device", requireProject: true }), }; diff --git a/cli/src/help/docs.ts b/cli/src/help/docs.ts index 9fb759a..7f19629 100644 --- a/cli/src/help/docs.ts +++ b/cli/src/help/docs.ts @@ -7,25 +7,21 @@ export const GROUP_SUMMARIES: Record = { "component option": "组件选项查询命令。", simulation: "模拟运行与调度相关命令。", analysis: "分析计算与诊断相关命令。", + "analysis runs": "分析运行及结果查询命令。", "analysis leakage": "漏损分析相关命令。", - "analysis leakage schemes": "漏损方案查询命令。", "analysis burst-detection": "爆管检测相关命令。", - "analysis burst-detection schemes": "爆管检测方案查询命令。", "analysis burst-location": "爆管定位相关命令。", - "analysis burst-location schemes": "爆管定位方案查询命令。", - "analysis risk": "风险分析相关命令。", "analysis sensor-placement": "传感器选址相关命令。", - data: "时序、SCADA 和方案数据查询命令。", + data: "时序、SCADA 和分析数据查询命令。", "data timeseries": "时序数据查询命令。", "data timeseries realtime": "实时模拟时序查询命令。", - "data timeseries scheme": "方案时序查询命令。", + "data timeseries analysis": "按分析运行 ID 查询历史时序命令。", "data timeseries scada": "SCADA 时序查询命令。", "data timeseries composite": "复合时序查询命令。", "data scada": "SCADA 元数据查询命令。", - "data scheme": "方案数据查询命令。", }; -export const HIDDEN_PATH_PREFIXES = ["analysis burst-location", "analysis risk"]; +export const HIDDEN_PATH_PREFIXES: string[] = []; type CommandSpec = readonly [path: string, summary: string, options: readonly string[], examples: readonly string[], nextCommands?: readonly string[]]; @@ -44,39 +40,33 @@ const commandSpecs: readonly CommandSpec[] = [ ["component option schema", "读取选项 schema", ["--kind ", "[--pump ]"], ["tjwater-cli component option schema --kind time", "tjwater-cli component option schema --kind energy", "tjwater-cli component option schema --kind pump-energy --pump PUMP1", "tjwater-cli component option schema --kind network"]], ["component option get", "读取选项属性", ["--kind ", "[--pump ]"], ["tjwater-cli component option get --kind time", "tjwater-cli component option get --kind energy", "tjwater-cli component option get --kind pump-energy --pump PUMP1", "tjwater-cli component option get --kind network"]], ["simulation run", "触发指定绝对时间的模拟运行", ["--start-time ", "--duration "], ["tjwater-cli simulation run --start-time 2025-01-02T03:04:05+08:00 --duration 30"], ["tjwater-cli data timeseries realtime links --start-time 2025-01-02T03:04:05+08:00 --end-time 2025-01-02T03:34:05+08:00", "tjwater-cli data timeseries realtime nodes --start-time 2025-01-02T03:04:05+08:00 --end-time 2025-01-02T03:34:05+08:00"]], - ["analysis burst", "执行爆管分析", ["--start-time ", "--duration ", "--burst-file ", "[--scheme ]"], ["tjwater-cli analysis burst --start-time 2025-01-02T03:04:05+08:00 --duration 900 --burst-file ./burst.json --scheme burst_case_01", "tjwater-cli data scheme get --name burst_case_01", "tjwater-cli data scheme list"]], - ["analysis valve", "阀门工况分析。", ["--mode ", "[--start-time ]", "[--valve ]", "[--element ]", "[--disabled-valve ]", "[--duration ]", "[--scheme ]"], ["tjwater-cli analysis valve --mode close --start-time 2025-01-02T03:04:05+08:00 --valve V1 --valve V2 --duration 900 --scheme valve_case_01", "tjwater-cli analysis valve --mode isolation --element E1 --element E2", "tjwater-cli analysis valve --mode isolation --element E1 --disabled-valve V3"]], + ["analysis burst", "执行爆管分析", ["--start-time ", "--duration ", "--burst-file ", "[--scheme ]"], ["tjwater-cli analysis burst --start-time 2025-01-02T03:04:05+08:00 --duration 900 --burst-file ./burst.json --scheme burst_case_01", "tjwater-cli analysis runs list"]], + ["analysis valve isolation", "执行阀门隔离分析", ["--element ", "[--disabled-valve ]"], ["tjwater-cli analysis valve isolation --element E1 --element E2", "tjwater-cli analysis valve isolation --element E1 --disabled-valve V3"]], ["analysis flushing", "执行冲洗分析", ["--start-time ", "--valve-setting-file ", "--drainage-node ", "--flow ", "[--duration ]", "[--scheme ]"], ["tjwater-cli analysis flushing --start-time 2025-01-02T03:04:05+08:00 --valve-setting-file ./valve.json --drainage-node N1 --flow 100.0 --duration 900 --scheme flush_case_01"]], ["analysis age", "执行水龄分析", ["--start-time ", "--duration "], ["tjwater-cli analysis age --start-time 2025-01-02T03:04:05+08:00 --duration 900"]], ["analysis contaminant", "执行污染物模拟", ["--start-time ", "--duration ", "--source-node ", "--concentration ", "[--pattern ]", "[--scheme ]"], ["tjwater-cli analysis contaminant --start-time 2025-01-02T03:04:05+08:00 --duration 900 --source-node N1 --concentration 10.0 --scheme contam_case_01"]], - ["analysis sensor-placement kmeans", "执行 KMeans 传感器选址", ["--count ", "[--min-diameter ]", "[--scheme ]"], ["tjwater-cli analysis sensor-placement kmeans --count 5 --min-diameter 100 --scheme placement_case_01"]], + ["analysis sensor-placement run", "执行传感器选址", ["--run-name ", "--method ", "--count ", "[--min-diameter ]"], ["tjwater-cli analysis sensor-placement run --run-name placement_case_01 --method kmeans --count 5 --min-diameter 100", "tjwater-cli analysis sensor-placement run --run-name placement_case_02 --method sensitivity --count 5"]], + ["analysis sensor-placement list", "列出传感器选址运行", [], ["tjwater-cli analysis sensor-placement list"]], + ["analysis sensor-placement get", "读取传感器选址运行", ["--run-id "], ["tjwater-cli analysis sensor-placement get --run-id 00000000-0000-0000-0000-000000000001"]], + ["analysis runs list", "列出分析运行", [], ["tjwater-cli analysis runs list"]], + ["analysis runs get", "读取分析运行", ["--run-id "], ["tjwater-cli analysis runs get --run-id 00000000-0000-0000-0000-000000000001"]], + ["analysis runs results", "读取分析运行结果", ["--run-id ", "[--result-type ]"], ["tjwater-cli analysis runs results --run-id 00000000-0000-0000-0000-000000000001", "tjwater-cli analysis runs results --run-id 00000000-0000-0000-0000-000000000001 --result-type leakage_identification"]], ["analysis leakage identify", "执行漏损识别", ["--start-time ", "--end-time ", "[--scheme ]"], ["tjwater-cli analysis leakage identify --start-time 2025-01-02T03:00:00+08:00 --end-time 2025-01-02T04:00:00+08:00 --scheme leak_case_01"]], - ["analysis leakage schemes list", "列出漏损方案", [], ["tjwater-cli analysis leakage schemes list"]], - ["analysis leakage schemes get", "读取漏损方案详情", [""], ["tjwater-cli analysis leakage schemes get my_scheme"]], ["analysis burst-detection detect", "执行爆管检测", ["--start-time ", "--end-time ", "[--scheme ]"], ["tjwater-cli analysis burst-detection detect --start-time 2025-01-02T03:00:00+08:00 --end-time 2025-01-02T04:00:00+08:00 --scheme detect_case_01"]], - ["analysis burst-detection schemes list", "列出爆管检测方案", [], ["tjwater-cli analysis burst-detection schemes list"]], - ["analysis burst-detection schemes get", "读取爆管检测方案详情", [""], ["tjwater-cli analysis burst-detection schemes get my_scheme"]], ["analysis burst-location locate", "执行爆管定位", ["--start-time ", "--end-time ", "--burst-leakage ", "[--scheme ]"], ["tjwater-cli analysis burst-location locate --start-time 2025-01-02T03:00:00+08:00 --end-time 2025-01-02T04:00:00+08:00 --burst-leakage 100.0 --scheme locate_case_01"]], - ["analysis burst-location schemes list", "列出爆管定位方案", [], ["tjwater-cli analysis burst-location schemes list"]], - ["analysis burst-location schemes get", "读取爆管定位方案详情", [""], ["tjwater-cli analysis burst-location schemes get my_scheme"]], - ["analysis risk pipe-now", "读取单条管道当前风险", ["--pipe "], ["tjwater-cli analysis risk pipe-now --pipe P1"]], - ["analysis risk pipe-history", "读取单条管道历史风险", ["--pipe "], ["tjwater-cli analysis risk pipe-history --pipe P1"]], - ["analysis risk network", "读取全网风险", [], ["tjwater-cli analysis risk network"]], ["data timeseries realtime links", "查询实时管道时序", ["--start-time ", "--end-time "], ["tjwater-cli data timeseries realtime links --start-time 2025-01-02T03:00:00+08:00 --end-time 2025-01-02T04:00:00+08:00"]], ["data timeseries realtime nodes", "查询实时节点时序", ["--start-time ", "--end-time "], ["tjwater-cli data timeseries realtime nodes --start-time 2025-01-02T03:00:00+08:00 --end-time 2025-01-02T04:00:00+08:00"]], ["data timeseries realtime simulation-by-id-time", "按元素和时间查询实时模拟结果", ["--id ", "--type ", "--time