@szc-ft/mcp-szcd-client 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,15 @@
1
1
  ---
2
2
  name: local-api-tool
3
- description: 本地网络 API 工具,专门处理 10.x.x.x 网段的 Swagger/YApi 文档拉取和联调测试。内置 scripts/extract_swagger.py 一步完成"下载→解析→按 tag 过滤→关联 DTO definitions→输出",与服务端 parseApiDocs 一比一对齐(递归深度 5、两层 definitions、传递闭包裁剪),避免 curl 管道截断和手写花括号平衡脚本的弯路。仅当脚本不可用时回退到服务端 parse_swagger_json 兜底。**仅限 10.x.x.x 网段**,172.16-31.x.x 和 192.168.x.x 服务端可直连,不要使用本技能。
3
+ description: 本地网络 API 工具,专门处理 10.x.x.x 网段的 Swagger/YApi 文档拉取和联调测试。内置 scripts/extract-swagger.mjs(Node.js,跨平台零安装;同目录 extract_swagger.py 为等价兜底)一步完成"下载→解析→按 tag 过滤→关联 DTO definitions→输出",与服务端 parseApiDocs 一比一对齐(递归深度 5、两层 definitions、传递闭包裁剪),自动修复非标 JSON(八进制字面量)、自带 /tmp 缓存(TTL 10 分钟),避免 curl 管道截断和手写花括号平衡脚本的弯路。仅当脚本不可用时回退到服务端 parse_swagger_json 兜底。**仅限 10.x.x.x 网段**,172.16-31.x.x 和 192.168.x.x 服务端可直连,不要使用本技能。
4
4
  compatibility:
5
5
  tools:
6
6
  - run_command
7
7
  - web_search
8
8
  - web_fetch
9
9
  runtime:
10
- - python3 >= 3.7
11
- - curl
10
+ - node >= 18(首选,跨平台无需额外依赖;内置 fetch + crypto + fs)
11
+ - python3 >= 3.7(兜底,仅当本地无 Node 时使用)
12
+ - curl(仅 Node < 18 或 fetch 不可用时降级使用)
12
13
  ---
13
14
 
14
15
  # 本地网络 API 工具(local-api-tool)
@@ -38,10 +39,47 @@ compatibility:
38
39
 
39
40
  ## 工作流
40
41
 
42
+ ### 🔍 第 0 步:环境探测(必做,决定后续路径)
43
+
44
+ 在执行任何拉取/解析操作**之前**,AI **必须**先用 `run_command` 探测一次本机运行时,按结果选择执行路径。**不要凭直觉默认 Node**,也不要省略探测——历史反馈中有 Windows/Trae 用户撞 python3 不存在、有精简容器没装 curl。
45
+
46
+ ```bash
47
+ # 一行三探(exit 0 = 可用;任意一项不可用不影响其他探测)
48
+ node --version 2>/dev/null && echo "NODE_OK"; \
49
+ python3 --version 2>/dev/null || python --version 2>/dev/null && echo "PY_OK"; \
50
+ curl --version 2>/dev/null | head -1 && echo "CURL_OK"
51
+ ```
52
+
53
+ **决策表(按优先级从高到低,命中第一个匹配项即停):**
54
+
55
+ | 输出包含 | 走的路径 | 命令头 |
56
+ |---------|---------|--------|
57
+ | `NODE_OK` | **Node 路径**(首选)| `node $SKILL_DIR/scripts/extract-swagger.mjs ...` |
58
+ | `PY_OK`(含 curl)| **Python 路径**(次选)| `python3 $SKILL_DIR/scripts/extract_swagger.py ...`(Windows 上用 `python`)|
59
+ | 仅 `CURL_OK`(无 Node 也无 Python)| **裸 curl + AI 直接推理**(兜底,见下方 A3)| `curl -o /tmp/swagger-raw.json ...` → `read_file('/tmp/swagger-raw.json')` → AI 在上下文里挑接口/字段 |
60
+ | swagger 文件 > 200KB 且裸 curl 兜底装不下上下文 | **MCP parse_swagger_json**(最终兜底)| `api_tool(action="parse_swagger_json", swaggerJson=...)` |
61
+ | 都没有 | **失败**,告知用户至少装一个 | 不要尝试用 `web_fetch` 等绕——会撞内网不可达 |
62
+
63
+ **为什么这么排(含三档兜底的实测对比):**
64
+ - Node 在 mcp 客户端用户中**已装率 100%**(用户必须装 Node 才能跑 szcd-mcp-client 本身),Windows 上单命令 `node` 跨平台无差异;脚本内置 fetch 不强依赖 curl
65
+ - Python 在 macOS ≥ 12.3 / Linux 主流发行版自带,但 **Windows 原生默认没装**——所以排第二
66
+ - **兜底选「裸 curl + read_file + AI 推理」而非「MCP parse_swagger_json」**:实测 100 接口 / 150 DTO / 77KB 的中等规模 swagger,前者只占 ~19K tokens(read_file 一次),后者要 ~38K tokens(read_file + 整段 JSON 作为 swaggerJson 参数再传一次),**MCP 路径反而更费上下文**
67
+ - **绝对禁止"AI 临时写 awk/sed/jq 脚本去切 swagger"**——历史反馈 #2026-06-11-catalog-tag 这条路踩了 3-5 分钟坑,`$ref`/`originalRef` 嵌套不是手写正则能搞定的
68
+ - MCP `parse_swagger_json` 仅作为"裸 curl 也撑不住(swagger 太大、read_file 一次进不来)"的最终兜底保留
69
+
70
+ **简化版(如果你只想一行判断):**
71
+ ```bash
72
+ command -v node >/dev/null && echo NODE || (command -v python3 >/dev/null && echo PY || (command -v python >/dev/null && echo PY || echo CURL_ONLY))
73
+ ```
74
+ 直接根据 stdout 第一个 token 选路径,无需 grep 解析。
75
+
76
+ ---
77
+
41
78
  ### 流程 A:拉取 Swagger API 文档(fetch)
42
79
 
43
- > **优先使用内置脚本 `scripts/extract_swagger.py`**,一步完成"下载 → 解析 → 过滤 → 关联 DTO → 输出",避免 curl 管道截断、临时脚本花括号平衡等弯路。脚本与服务端 `parseApiDocs` 一比一对齐(递归深度 5、两层 definitions、传递闭包裁剪)。
44
- > 仅当脚本不可用(无 python3 / 文件权限缺失)时才回退到「手工 curl + 服务端 parse_swagger_json」兜底流程。
80
+ > **优先使用内置脚本 `scripts/extract-swagger.mjs`(Node.js)**,一步完成"下载 → 解析 → 过滤 → 关联 DTO → 输出",避免 curl 管道截断、临时脚本花括号平衡等弯路。脚本与服务端 `parseApiDocs` 一比一对齐(递归深度 5、两层 definitions、传递闭包裁剪)。
81
+ > 同目录 `extract_swagger.py` 为等价 Python 兜底(行为一致),仅当本地无 Node 18 时使用。
82
+ > 仅当两个脚本都不可用时才回退到「手工 curl + 服务端 parse_swagger_json」兜底流程(见下方 A2)。
45
83
 
46
84
  #### A1. 内置脚本路径(首选)
47
85
 
@@ -52,12 +90,12 @@ compatibility:
52
90
  AI 识别 10.x.x.x 网段(或服务端返回 LOCAL_NETWORK_UNREACHABLE)
53
91
 
54
92
 
55
- 通过 run_command 在本地执行:
56
- bash $SKILL_DIR/scripts/extract_swagger.py \
93
+ 通过 run_command 在本地执行(Node 版,跨平台同一条命令):
94
+ node $SKILL_DIR/scripts/extract-swagger.mjs \
57
95
  --url <apiDocsUrl> [--cookie '...'] [--filter <关键词>] [--out /tmp/parsed.json]
58
96
 
59
97
 
60
- 脚本内部:curl 下载 解析 → 过滤 paths 自动展开被引用 DTO → 输出 JSON
98
+ 脚本内部:fetch 下载(Node 18+ 内置;不可用时降级 curl)→ 解析 → 过滤 → 自动展开 DTO → 输出 JSON
61
99
 
62
100
 
63
101
  AI 读取脚本输出(或 --out 指定的文件),结构与 api_tool(parse_swagger_json) 完全一致:
@@ -65,10 +103,13 @@ AI 读取脚本输出(或 --out 指定的文件),结构与 api_tool(parse_
65
103
  ```
66
104
 
67
105
  **$SKILL_DIR 是本 skill 的绝对目录**。在 qwen/qoder 中 skill 加载时通常通过环境变量或上下文提供,若不确定可用:
68
- - qwen-extension: `~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract_swagger.py`
69
- - opencode-extension: `~/.config/opencode/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract_swagger.py`
106
+ - qwen-extension: `~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract-swagger.mjs`
107
+ - opencode-extension: `~/.config/opencode/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract-swagger.mjs`
108
+ - claude-code: `~/.claude/skills/local-api-tool/scripts/extract-swagger.mjs`
109
+
110
+ **无 Node 环境时**:把命令头 `node .../extract-swagger.mjs` 换成 `python3 .../extract_swagger.py`(或 Windows 上 `python ...`),参数完全一致。
70
111
 
71
- #### A2. 服务端兜底(脚本不可用时)
112
+ #### A2. 裸 curl + AI 直接推理(无 Node 也无 Python 时的兜底)
72
113
 
73
114
  ```
74
115
  调用 api_tool(action="fetch", url=...)
@@ -79,16 +120,43 @@ AI 读取脚本输出(或 --out 指定的文件),结构与 api_tool(parse_
79
120
 
80
121
  AI 通过 run_command 在本地 curl 写到临时文件(禁止管道截断!):
81
122
  步骤1: 鉴权获取 Cookie(如 authInfo.hasPassword 为 true)
82
- 步骤2: curl -o /tmp/swagger.json <apiDocsUrl> ← 必须写文件
123
+ 步骤2: curl -o /tmp/swagger-raw.json <apiDocsUrl> ← 必须写文件
124
+
125
+
126
+ AI 用 read_file('/tmp/swagger-raw.json') 把整段 JSON 读进上下文
127
+
128
+
129
+ AI **直接在对话上下文里**阅读 JSON:按 tag 找 apis、按 $ref/originalRef 跳到 definitions 展开 DTO/VO、组织响应
130
+ (典型规模 100 接口 / 150 DTO / 77KB ≈ 19K tokens,单次 read_file 足够)
131
+ ```
132
+
133
+ > **🚫 绝对禁止"AI 临时写 awk/sed/jq/python 脚本去切 swagger"**
134
+ >
135
+ > 历史反馈 #2026-06-11-catalog-tag 在这条路上踩了 3-5 分钟坑——`$ref`/`originalRef` 双字段嵌套不是手写正则能搞定的,
136
+ > allOf/oneOf/数组 items 几层嵌套下来,临时脚本不是漏字段就是花括号失衡。
137
+ > **直接 read_file 进上下文人脑挑反而最快**。
138
+ > 如果 JSON 大到 read_file 装不下(一般 > 200KB),才升级到 A3 走服务端解析。
139
+
140
+ #### A3. 服务端兜底(仅当 swagger 大到 read_file 装不下,约 > 200KB)
141
+
142
+ ```
143
+ (接 A2 步骤 2:已经 curl -o /tmp/swagger-raw.json 写好文件)
144
+
145
+
146
+ 预判文件大小:ls -l /tmp/swagger-raw.json
147
+ ├─ ≤ 200KB → 回到 A2,read_file 直读即可
148
+ └─ > 200KB → 进入本路径
83
149
 
84
150
 
85
151
  AI 读取整个文件传给服务端:
86
- api_tool(action="parse_swagger_json", swaggerJson=<完整 JSON 字符串>, apiFilter=<可选>)
152
+ api_tool(action="parse_swagger_json", swaggerJson=<完整 JSON 字符串>, apiFilter=<必填,过滤接口避免输出爆炸>)
87
153
 
88
154
 
89
- 返回解析后的 API 文档给用户
155
+ 返回解析后(按 apiFilter 裁剪过)的 API 文档给用户
90
156
  ```
91
157
 
158
+ > 注意:此路径上下文成本翻倍(read_file 一次 + 字符串参数再传一次),**仅在 A2 装不下时启用**,且 `apiFilter` 必填以裁剪输出。
159
+
92
160
  ### 流程 B:联调测试(test)
93
161
 
94
162
  ```
@@ -112,26 +180,27 @@ AI 通过 run_command 在本地执行对应 curl 命令
112
180
 
113
181
  ## 详细执行步骤
114
182
 
115
- ### 一、拉取 Swagger 文档(推荐路径:extract_swagger.py
183
+ ### 一、拉取 Swagger 文档(推荐路径:extract-swagger.mjs
116
184
 
117
- **前提**:本地有 python3(≥ 3.7)和 curl。脚本只依赖标准库,无第三方依赖。
185
+ **前提**:本地有 Node.js ≥ 18(内置 fetch;mcp 客户端用户基本都装了)。脚本只用 Node 内置模块(fs/crypto/child_process),无第三方依赖。
186
+ **无 Node 时回退**:用同目录 `extract_swagger.py`(Python ≥ 3.7 + curl),参数完全一致。
118
187
 
119
188
  #### 1.1 直接通过 URL 下载并解析(推荐)
120
189
 
121
190
  ```bash
122
191
  # 无鉴权
123
- python3 ~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract_swagger.py \
192
+ node ~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract-swagger.mjs \
124
193
  --url 'http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs' \
125
194
  --out /tmp/parsed.json
126
195
 
127
196
  # 有鉴权(先单独 curl 拿 Cookie,参考下方 1.3)
128
- python3 .../extract_swagger.py \
197
+ node .../extract-swagger.mjs \
129
198
  --url 'http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs' \
130
199
  --cookie 'JSESSIONID=xxx' \
131
200
  --out /tmp/parsed.json
132
201
 
133
202
  # 按关键词过滤 + 自动裁剪 definitionsDetail(仅保留被引用的 VO 及传递闭包)
134
- python3 .../extract_swagger.py \
203
+ node .../extract-swagger.mjs \
135
204
  --url '<apiDocsUrl>' \
136
205
  --filter tag --filter user \
137
206
  --out /tmp/parsed.json
@@ -148,7 +217,7 @@ curl -sS --connect-timeout 10 --max-time 30 \
148
217
  'http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs'
149
218
 
150
219
  # 第二步:交给脚本解析
151
- python3 .../extract_swagger.py --file /tmp/swagger-raw.json --filter tag --out /tmp/parsed.json
220
+ node .../extract-swagger.mjs --file /tmp/swagger-raw.json --filter tag --out /tmp/parsed.json
152
221
  ```
153
222
 
154
223
  #### 1.3 鉴权(如需 Cookie)
@@ -169,7 +238,7 @@ curl -sS -D - -X GET 'http://10.2.7.60:30194/ikmp-knowledge/swagger-resources/co
169
238
  如果脚本已经解析过、但 AI 后续发现某个 `definitionsDetail` 之外的 VO 也需要展开,用:
170
239
 
171
240
  ```bash
172
- python3 .../extract_swagger.py --file /tmp/swagger-raw.json --definition KnowledgeOperLogVO
241
+ node .../extract-swagger.mjs --file /tmp/swagger-raw.json --definition KnowledgeOperLogVO
173
242
  ```
174
243
 
175
244
  找不到时会自动给出模糊匹配建议(最多 10 个)。
@@ -202,7 +271,11 @@ python3 .../extract_swagger.py --file /tmp/swagger-raw.json --definition Knowled
202
271
  }
203
272
  ```
204
273
 
205
- ### 二、服务端兜底路径(脚本不可用时)
274
+ ### 二、本地兜底路径(脚本不可用时)
275
+
276
+ 无 Node 也无 Python 时按 **2.A → 2.B** 顺序处理:默认走 2.A(裸 curl + read_file + AI 推理),只有 swagger 超过 ~200KB read_file 装不下时才升级到 2.B(MCP parse_swagger_json)。
277
+
278
+ #### 2.A 裸 curl + AI 直接推理(默认兜底)
206
279
 
207
280
  **步骤 1:调用服务端 api_tool**
208
281
 
@@ -243,20 +316,50 @@ curl -sS --connect-timeout 10 --max-time 30 \
243
316
  -H 'Cookie: <步骤上一步的 Cookie>' \
244
317
  -o /tmp/swagger-raw.json \
245
318
  '<apiDocsUrl>'
319
+
320
+ # 检查大小:> 200KB 跳到 2.B;否则继续步骤 4
321
+ ls -l /tmp/swagger-raw.json
322
+ ```
323
+
324
+ **步骤 4:read_file 进上下文,AI 直接阅读 JSON**
325
+
326
+ ```
327
+ read_file('/tmp/swagger-raw.json')
246
328
  ```
247
329
 
248
- **步骤 4:调用服务端解析**
330
+ 随后 AI 在对话上下文里**直接阅读** JSON,按以下路径检索:
331
+
332
+ 1. 找到目标 tag(`tags[]` 或 `paths.*.tags`),列出该 tag 下所有 `paths`
333
+ 2. 对感兴趣的接口,看 `parameters[].schema.$ref` / `responses.200.schema.$ref`(或 `originalRef`)
334
+ 3. 跳到 `definitions.<VOName>`,沿 `properties.*.$ref` 递归展开(一般 2-3 层够用)
335
+ 4. 注意 `allOf`/`oneOf`/`items` 嵌套和 `required` 数组
336
+
337
+ > **🚫 禁止在此步骤写任何临时脚本(awk/sed/jq/python 一次性脚本)切 JSON**。
338
+ > 历史反馈 #2026-06-11-catalog-tag 已经验证:`$ref` 双字段嵌套 + allOf 让正则方案漏字段或花括号失衡,
339
+ > 调试 3-5 分钟 ≫ 直接 read_file 进上下文人脑挑(19K tokens 中等规模 < 30 秒)。
340
+ > 真正的结构化解析交给脚本(A1)或 MCP(2.B),不要中间态。
341
+
342
+ **步骤 5:把整理好的 API 信息呈现给用户**
343
+
344
+ #### 2.B MCP 服务端解析(仅当 swagger > 200KB read_file 装不下时升级)
345
+
346
+ **触发条件**:步骤 3 的 `ls -l` 显示 swagger 超过 ~200KB,或 read_file 后明显超出上下文预算。
347
+
348
+ **步骤 1:调用服务端解析**
249
349
 
250
350
  ```
251
351
  api_tool(
252
352
  action="parse_swagger_json",
253
353
  swaggerJson=<读取 /tmp/swagger-raw.json 的完整内容>,
254
354
  swaggerSourceUrl="http://10.2.7.60:30194/ikmp-knowledge/swagger-ui/index.html",
255
- apiFilter=["tag"] // 可选,强烈推荐:按关键词过滤 + 自动裁剪 definitionsDetail
355
+ apiFilter=["tag"] // 必填,避免输出爆炸 + 触发 definitionsDetail 传递闭包裁剪
256
356
  )
257
357
  ```
258
358
 
259
- **步骤 5:返回解析结果**
359
+ > 此路径上下文成本翻倍(read_file 一次 + 整段 JSON 作为字符串参数再传一次),所以 `apiFilter` 必填。
360
+ > 若不知道按什么过滤,先回到 2.A 步骤 4 用 read_file 看一眼 `tags[]`/`paths.*.tags` 选 1-3 个关键词再调。
361
+
362
+ **步骤 2:返回解析结果**
260
363
 
261
364
  将返回结果直接呈现给用户。
262
365
 
@@ -314,16 +417,45 @@ curl -s -X POST 'http://10.2.7.60:30194/ikmp-knowledge/api/xxx' \
314
417
  ## ⚠️ 避坑指南(来自历史反馈)
315
418
 
316
419
  1. **禁止用 `curl | head/tail/jq/python` 对完整 Swagger JSON 做管道切片** —— curl 管道经常因下游 SIGPIPE 截断,导致 JSON 不闭合 / Python 解析失败 / 临时写花括号平衡脚本,是历史踩坑率最高的反模式。**必须用 `-o /tmp/xxx.json` 写文件**,再用脚本或 `parse_swagger_json` 处理。
317
- 2. **不要在本地手写 Python 切 Swagger** —— `extract_swagger.py` 已经做了和服务端 `parseApiDocs` 完全对齐的递归展开、传递闭包、required 标注、过滤裁剪。本地手写一个 mini 版只会丢字段或踩 `$ref`/`originalRef` 双字段陷阱。
420
+ 2. **不要在本地手写脚本切 Swagger** —— `extract-swagger.mjs`/`extract_swagger.py` 已经做了和服务端 `parseApiDocs` 完全对齐的递归展开、传递闭包、required 标注、过滤裁剪。本地手写一个 mini 版只会丢字段或踩 `$ref`/`originalRef` 双字段陷阱。
318
421
  3. **过滤优先用 `--filter`(脚本)或 `apiFilter`(服务端)** —— 不要先拿全量再让 AI 自己挑接口看,过滤后 `definitionsDetail` 会自动按传递闭包裁剪,输出量减少 70%+。
319
422
  4. **单 VO 查询用 `--definition`(脚本)或 `get_definition`(服务端)** —— 不要回头再拉一次全量。
423
+ 5. **JSON 解析报错先看脚本输出,再考虑手工修复** —— 两个脚本都内置八进制字面量自动修复(如 `[011,015]` → `[11,15]`,Java/旧网关常见)和错误诊断(HTML 跳转/截断/编码)。**不要再手写正则修 JSON**,浪费 30s 起步;如果脚本仍然报错,按提示原因(HTML/截断/真八进制以外的非法字符)针对性处理。
424
+ 6. **首选 Node 版(.mjs),无 Node 才用 Python 版(.py)** —— `extract-swagger.mjs` 跨平台单命令 `node ...`,绕开 Python 在 Windows 上 `python3` 不存在、`python` 版本不一的麻烦;扩展名 `.mjs` 强制 ESM,也不会撞上宿主 `package.json "type":"module"` 的 .cjs 强制要求。两脚本输出结构完全等价(仅 `definitionsDetail` 数组顺序可能不同,因 Python `set` vs JS `Set` 迭代规则差异——业务无感)。
425
+ 7. **重复拉同一份 Swagger 走缓存** —— 同 URL+cookie+auth 默认 10 分钟内命中 `<tmpdir>/swagger-cache/`,无需手动判断。如需强制最新数据用 `--no-cache`;如需调整 TTL 用 `--cache-ttl <秒>`(设为 0 关闭缓存)。两个脚本共用同一目录、同一 sha256 key 算法,Node 版写的缓存 Python 版也能读,反之亦然。
426
+
427
+ ## 内置容错与性能优化
428
+
429
+ `extract-swagger.mjs` / `extract_swagger.py` 内置以下能力,**无需 AI 在外层重复实现**:
430
+
431
+ | 能力 | 触发条件 | 行为 |
432
+ |------|----------|------|
433
+ | 八进制修复 | JSON 含 `[011,015]` 这类非标字面量 | 首次 `JSON.parse`/`json.loads` 失败后自动正则修复重试,stderr 打印 `[INFO] 自动修复八进制字面量后解析成功` |
434
+ | 错误诊断 | 任何 JSON 解析失败 | stderr 输出"错误行列 + 上下文 ±80 字符 + `^` 指向 + 常见原因"(HTML 跳转/截断/八进制) |
435
+ | TTL 缓存 | `--url` 模式默认开启 | `<tmpdir>/swagger-cache/<sha256(url+cookie+auth)截16位>.json`,meta 文件记录 cached_at + ttl + size;Node 版与 Python 版共用缓存目录 |
436
+ | 缓存绕过 | 命令行 `--no-cache` 或 `--cache-ttl 0` | 强制重新拉取 |
437
+
438
+ **典型场景**(以 Node 版为例,Python 版只需把命令头换成 `python3 .../extract_swagger.py`):
439
+ ```bash
440
+ # 首次拉取 → fetch + 写缓存
441
+ node .../extract-swagger.mjs --url '...' --out /tmp/r1.json
442
+ # stderr: [CACHE] 已写入 c57b1f88a49f0f7d (530 bytes)
443
+
444
+ # 5 分钟内二次拉取 → 命中
445
+ node .../extract-swagger.mjs --url '...' --out /tmp/r2.json
446
+ # stderr: [CACHE] 命中 c57b1f88a49f0f7d (age=287s, ttl=600s)
447
+
448
+ # Cookie 变了(如重新登录)→ key 自动变化,不会串
449
+ node .../extract-swagger.mjs --url '...' --cookie 'JSESSIONID=NEW' --out /tmp/r3.json
450
+ # stderr: [CACHE] 已写入 a93f...(新 key)
451
+ ```
320
452
 
321
453
  ## 快捷方式:AI 直接识别 10 段地址
322
454
 
323
455
  如果 AI 能识别出用户请求的 URL 中包含 `10.x.x.x` 主机地址,可以**直接跳过首次 api_tool 调用**,在本地执行脚本,减少一次无用的服务端请求:
324
456
 
325
457
  ```bash
326
- python3 ~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract_swagger.py \
458
+ node ~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract-swagger.mjs \
327
459
  --url 'http://10.x.x.x/<service>/v2/api-docs' \
328
460
  [--cookie '<JSESSIONID=...>'] \
329
461
  [--filter '<关键词>'] \
@@ -344,7 +476,7 @@ python3 ~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/e
344
476
 
345
477
  1. **Cookie 传递**:鉴权步骤获取的 Cookie 通过 `--cookie` 传给脚本,或通过 `-H 'Cookie: xxx'` 传给 curl
346
478
  2. **无密码场景**:如果用户未提供密码,跳过鉴权步骤,直接获取文档
347
- 3. **JSON 格式**:脚本/curl 获取的 API 文档必须是有效的 Swagger JSON,否则 `extract_swagger.py` / `parse_swagger_json` 会报错(脚本会打印预览前 200 字符方便排查)
479
+ 3. **JSON 格式**:脚本/curl 获取的 API 文档必须是有效的 Swagger JSON。八进制字面量(`[011,015]` 类)会被自动修复;其他非法格式(HTML 跳转/截断)脚本会输出错误位置 ±80 字符上下文 + 常见原因提示,按提示排查即可
348
480
  4. **超时处理**:脚本和 curl 都已内置 `--connect-timeout 10 --max-time 30`,可通过 `--timeout` 调整
349
481
  5. **错误处理**:脚本退出码 1=参数错误 / 2=网络IO / 3=解析;如果某步骤失败,将错误信息返回给用户,不要继续后续步骤
350
482
  6. **自动执行**:AI 识别 10.x.x.x 或 `reason: "LOCAL_NETWORK_UNREACHABLE"` 后应**自动**通过 `run_command` 执行脚本,无需让用户手动复制粘贴命令