@szc-ft/mcp-szcd-client 0.24.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.
Files changed (34) hide show
  1. package/agents/build.js +22 -12
  2. package/agents/opencode-extension/agents/szcd-component-expert.md +235 -49
  3. package/agents/qwen-extension/agents/szcd-component-expert.md +235 -49
  4. package/agents/src/szcd-component-expert.md +262 -49
  5. package/agents/src/tools.json +1 -1
  6. package/agents/szcd-component-expert.md +235 -49
  7. package/agents/szcd-component-expert.qoder.md +261 -50
  8. package/agents/szcd-component-expert.trae.md +260 -49
  9. package/opencode-extension/agents/szcd-component-expert.md +235 -49
  10. package/opencode-extension/skills/local-api-tool/SKILL.md +296 -60
  11. package/opencode-extension/skills/local-api-tool/scripts/extract-swagger.mjs +625 -0
  12. package/opencode-extension/skills/local-api-tool/scripts/extract_swagger.py +593 -0
  13. package/opencode-extension/skills/szcd-component-helper/SKILL.md +7 -4
  14. package/opencode-extension/skills/szcd-design-to-code/SKILL.md +267 -25
  15. package/package.json +1 -1
  16. package/qwen-extension/agents/szcd-component-expert.md +235 -49
  17. package/qwen-extension/qwen-extension.json +1 -1
  18. package/qwen-extension/skills/local-api-tool/SKILL.md +296 -60
  19. package/qwen-extension/skills/local-api-tool/scripts/extract-swagger.mjs +625 -0
  20. package/qwen-extension/skills/local-api-tool/scripts/extract_swagger.py +593 -0
  21. package/qwen-extension/skills/szcd-component-helper/SKILL.md +7 -4
  22. package/qwen-extension/skills/szcd-design-to-code/SKILL.md +267 -25
  23. package/scripts/lib/claude-code.js +1 -1
  24. package/scripts/lib/common.js +44 -0
  25. package/scripts/lib/opencode.js +1 -1
  26. package/scripts/lib/qoder.js +1 -1
  27. package/scripts/lib/trae-cli.js +1 -1
  28. package/scripts/lib/trae-ide.js +1 -1
  29. package/scripts/postinstall.js +1 -0
  30. package/standard-skill/local-api-tool/SKILL.md +296 -60
  31. package/standard-skill/local-api-tool/scripts/extract-swagger.mjs +625 -0
  32. package/standard-skill/local-api-tool/scripts/extract_swagger.py +593 -0
  33. package/standard-skill/szcd-component-helper/SKILL.md +7 -4
  34. package/standard-skill/szcd-design-to-code/SKILL.md +267 -25
@@ -1,11 +1,15 @@
1
1
  ---
2
2
  name: local-api-tool
3
- description: 本地网络 API 工具,专门处理 10.x.x.x 网段的 Swagger/YApi 文档拉取和联调测试。当服务端 api_tool LOCAL_NETWORK_UNREACHABLE 无法访问时,此技能在用户本地环境执行 curl,再将结果交给服务端解析。适用于内网开发环境、VPN 场景。**仅限 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
+ runtime:
10
+ - node >= 18(首选,跨平台无需额外依赖;内置 fetch + crypto + fs)
11
+ - python3 >= 3.7(兜底,仅当本地无 Node 时使用)
12
+ - curl(仅 Node < 18 或 fetch 不可用时降级使用)
9
13
  ---
10
14
 
11
15
  # 本地网络 API 工具(local-api-tool)
@@ -35,32 +39,124 @@ compatibility:
35
39
 
36
40
  ## 工作流
37
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
+
38
78
  ### 流程 A:拉取 Swagger API 文档(fetch)
39
79
 
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)。
83
+
84
+ #### A1. 内置脚本路径(首选)
85
+
40
86
  ```
41
87
  用户请求 fetch Swagger URL (10.x.x.x)
42
88
 
43
89
 
44
- 调用 api_tool(action="fetch", url=...)
90
+ AI 识别 10.x.x.x 网段(或服务端返回 LOCAL_NETWORK_UNREACHABLE)
91
+
92
+
93
+ 通过 run_command 在本地执行(Node 版,跨平台同一条命令):
94
+ node $SKILL_DIR/scripts/extract-swagger.mjs \
95
+ --url <apiDocsUrl> [--cookie '...'] [--filter <关键词>] [--out /tmp/parsed.json]
45
96
 
46
97
 
47
- 服务端返回 { reason: "LOCAL_NETWORK_UNREACHABLE", action: "请使用 local-api-tool ...", swaggerEndpoints: {...} }
98
+ 脚本内部:fetch 下载(Node 18+ 内置;不可用时降级 curl)→ 解析 过滤 自动展开 DTO → 输出 JSON
99
+
100
+
101
+ AI 读取脚本输出(或 --out 指定的文件),结构与 api_tool(parse_swagger_json) 完全一致:
102
+ { info, basePath, tags, apis, definitions, definitionsDetail, _filter? }
103
+ ```
104
+
105
+ **$SKILL_DIR 是本 skill 的绝对目录**。在 qwen/qoder 中 skill 加载时通常通过环境变量或上下文提供,若不确定可用:
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 ...`),参数完全一致。
111
+
112
+ #### A2. 裸 curl + AI 直接推理(无 Node 也无 Python 时的兜底)
113
+
114
+ ```
115
+ 调用 api_tool(action="fetch", url=...)
48
116
 
49
117
 
50
- AI 识别 LOCAL_NETWORK_UNREACHABLE,读取 swaggerEndpoints authInfo
118
+ 服务端返回 { reason: "LOCAL_NETWORK_UNREACHABLE", swaggerEndpoints, authInfo }
51
119
 
52
120
 
53
- AI 通过 run_command 在本地执行 curl
121
+ AI 通过 run_command 在本地 curl 写到临时文件(禁止管道截断!):
54
122
  步骤1: 鉴权获取 Cookie(如 authInfo.hasPassword 为 true)
55
- 步骤2: 获取完整 API 文档 JSON
123
+ 步骤2: curl -o /tmp/swagger-raw.json <apiDocsUrl> ← 必须写文件
56
124
 
57
125
 
58
- AI 调用 api_tool(action="parse_swagger_json", swaggerJson=..., swaggerSourceUrl=...)
126
+ AI read_file('/tmp/swagger-raw.json') 把整段 JSON 读进上下文
59
127
 
60
128
 
61
- 返回解析后的 API 文档给用户
129
+ AI **直接在对话上下文里**阅读 JSON:按 tag 找 apis、按 $ref/originalRef 跳到 definitions 展开 DTO/VO、组织响应
130
+ (典型规模 100 接口 / 150 DTO / 77KB ≈ 19K tokens,单次 read_file 足够)
62
131
  ```
63
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 → 进入本路径
149
+
150
+
151
+ AI 读取整个文件传给服务端:
152
+ api_tool(action="parse_swagger_json", swaggerJson=<完整 JSON 字符串>, apiFilter=<必填,过滤接口避免输出爆炸>)
153
+
154
+
155
+ 返回解析后(按 apiFilter 裁剪过)的 API 文档给用户
156
+ ```
157
+
158
+ > 注意:此路径上下文成本翻倍(read_file 一次 + 字符串参数再传一次),**仅在 A2 装不下时启用**,且 `apiFilter` 必填以裁剪输出。
159
+
64
160
  ### 流程 B:联调测试(test)
65
161
 
66
162
  ```
@@ -84,7 +180,102 @@ AI 通过 run_command 在本地执行对应 curl 命令
84
180
 
85
181
  ## 详细执行步骤
86
182
 
87
- ### 一、拉取 Swagger 文档(action=fetch
183
+ ### 一、拉取 Swagger 文档(推荐路径:extract-swagger.mjs
184
+
185
+ **前提**:本地有 Node.js ≥ 18(内置 fetch;mcp 客户端用户基本都装了)。脚本只用 Node 内置模块(fs/crypto/child_process),无第三方依赖。
186
+ **无 Node 时回退**:用同目录 `extract_swagger.py`(Python ≥ 3.7 + curl),参数完全一致。
187
+
188
+ #### 1.1 直接通过 URL 下载并解析(推荐)
189
+
190
+ ```bash
191
+ # 无鉴权
192
+ node ~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract-swagger.mjs \
193
+ --url 'http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs' \
194
+ --out /tmp/parsed.json
195
+
196
+ # 有鉴权(先单独 curl 拿 Cookie,参考下方 1.3)
197
+ node .../extract-swagger.mjs \
198
+ --url 'http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs' \
199
+ --cookie 'JSESSIONID=xxx' \
200
+ --out /tmp/parsed.json
201
+
202
+ # 按关键词过滤 + 自动裁剪 definitionsDetail(仅保留被引用的 VO 及传递闭包)
203
+ node .../extract-swagger.mjs \
204
+ --url '<apiDocsUrl>' \
205
+ --filter tag --filter user \
206
+ --out /tmp/parsed.json
207
+ ```
208
+
209
+ #### 1.2 读取已下载的本地 JSON 文件
210
+
211
+ ```bash
212
+ # 第一步:curl 写文件(务必用 -o 写文件,不要用管道,避免大 JSON 被截断)
213
+ curl -sS --connect-timeout 10 --max-time 30 \
214
+ -H 'Accept: application/json' \
215
+ -H 'Cookie: <Cookie>' \
216
+ -o /tmp/swagger-raw.json \
217
+ 'http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs'
218
+
219
+ # 第二步:交给脚本解析
220
+ node .../extract-swagger.mjs --file /tmp/swagger-raw.json --filter tag --out /tmp/parsed.json
221
+ ```
222
+
223
+ #### 1.3 鉴权(如需 Cookie)
224
+
225
+ ```bash
226
+ # 取 Cookie(注意 -D - 把响应头打到 stdout)
227
+ curl -sS -D - -X GET 'http://10.2.7.60:30194/ikmp-knowledge/swagger-resources/configuration/ui' \
228
+ -H 'Authorization: Basic <base64(username:password)>' \
229
+ -H 'Accept: application/json' \
230
+ -o /dev/null \
231
+ | grep -i '^set-cookie:' | head -1 | sed 's/.*: //; s/;.*//'
232
+ ```
233
+
234
+ 将得到的 `JSESSIONID=xxx` 传给 `--cookie` 参数。
235
+
236
+ #### 1.4 单独查询某个 VO/DTO 完整定义(兜底)
237
+
238
+ 如果脚本已经解析过、但 AI 后续发现某个 `definitionsDetail` 之外的 VO 也需要展开,用:
239
+
240
+ ```bash
241
+ node .../extract-swagger.mjs --file /tmp/swagger-raw.json --definition KnowledgeOperLogVO
242
+ ```
243
+
244
+ 找不到时会自动给出模糊匹配建议(最多 10 个)。
245
+
246
+ #### 1.5 输出结构(与服务端 `parse_swagger_json` 一致)
247
+
248
+ ```json
249
+ {
250
+ "info": { "title": "...", "version": "...", "description": "..." },
251
+ "basePath": "/svc",
252
+ "tags": [{ "name": "tag", "description": "..." }],
253
+ "apis": [
254
+ {
255
+ "url": "/tag/pageList",
256
+ "method": "POST",
257
+ "tag": "tag",
258
+ "summary": "标签分页查询",
259
+ "operationId": "tagPageList",
260
+ "parameters": [
261
+ { "name": "body", "in": "body", "required": true,
262
+ "dtoRef": "TagQueryDTO",
263
+ "dtoProperties": [ /* 递归展开,required 字段已标注 */ ] }
264
+ ],
265
+ "response": { "voName": "ResponseTagPage", "properties": [ /* 递归展开 */ ] }
266
+ }
267
+ ],
268
+ "definitions": [ /* 摘要:所有 VO/DTO 的 name + type + description */ ],
269
+ "definitionsDetail": [ /* 详情:被 apis 引用的 VO/DTO 及传递闭包,深度5 */ ],
270
+ "_filter": { "keywords": ["tag"], "total": 50, "matched": 12 } // 仅 --filter 生效时出现
271
+ }
272
+ ```
273
+
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 直接推理(默认兜底)
88
279
 
89
280
  **步骤 1:调用服务端 api_tool**
90
281
 
@@ -111,41 +302,68 @@ api_tool(action="fetch", url="http://10.2.7.60:30194/ikmp-knowledge/swagger-ui/i
111
302
  }
112
303
  ```
113
304
 
114
- **步骤 3:AI 通过 run_command 在本地执行 curl**
305
+ **步骤 3:本地 curl 写入临时文件(禁止管道截断!)**
115
306
 
116
- 根据返回数据中的 `authInfo` 和 `swaggerEndpoints`,AI 自行构造 curl 命令并通过 `run_command` 在本地执行:
307
+ ```bash
308
+ # 鉴权(如需要)
309
+ curl -sS -D - -X GET '<authUrl>' \
310
+ -H 'Authorization: Basic <base64(user:pass)>' \
311
+ -o /dev/null | grep -i '^set-cookie:' | head -1 | sed 's/.*: //; s/;.*//'
117
312
 
118
- 3a. **鉴权(如 authInfo.hasPassword true)**:
313
+ # 下载 API 文档(务必 -o 写文件,不要 | head / | python)
314
+ curl -sS --connect-timeout 10 --max-time 30 \
315
+ -H 'Accept: application/json' \
316
+ -H 'Cookie: <步骤上一步的 Cookie>' \
317
+ -o /tmp/swagger-raw.json \
318
+ '<apiDocsUrl>'
119
319
 
120
- ```bash
121
- curl -s -D - -X GET 'http://10.2.7.60:30194/ikmp-knowledge/swagger-resources/configuration/ui' \
122
- -H 'Authorization: Basic <base64(username:password)>' \
123
- -H 'Accept: application/json'
320
+ # 检查大小:> 200KB 跳到 2.B;否则继续步骤 4
321
+ ls -l /tmp/swagger-raw.json
124
322
  ```
125
323
 
126
- 从输出的 `Set-Cookie:` 行提取 Cookie 值(分号前的部分)。
127
-
128
- 3b. **获取 API 文档 JSON**:直接使用 `swaggerEndpoints.apiDocsUrl`:
324
+ **步骤 4:read_file 进上下文,AI 直接阅读 JSON**
129
325
 
130
- ```bash
131
- curl -s -X GET 'http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs' \
132
- -H 'Accept: application/json' \
133
- -H 'Cookie: <步骤3a获取的Cookie>'
134
326
  ```
327
+ read_file('/tmp/swagger-raw.json')
328
+ ```
329
+
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 信息呈现给用户**
135
343
 
136
- 如果 authInfo.hasPassword false,省略 Cookie 头。
344
+ #### 2.B MCP 服务端解析(仅当 swagger > 200KB read_file 装不下时升级)
137
345
 
138
- **步骤 4:调用服务端解析**
346
+ **触发条件**:步骤 3 的 `ls -l` 显示 swagger 超过 ~200KB,或 read_file 后明显超出上下文预算。
347
+
348
+ **步骤 1:调用服务端解析**
139
349
 
140
350
  ```
141
- api_tool(action="parse_swagger_json", swaggerJson="<步骤3b获取的JSON字符串>", swaggerSourceUrl="http://10.2.7.60:30194/ikmp-knowledge/swagger-ui/index.html")
351
+ api_tool(
352
+ action="parse_swagger_json",
353
+ swaggerJson=<读取 /tmp/swagger-raw.json 的完整内容>,
354
+ swaggerSourceUrl="http://10.2.7.60:30194/ikmp-knowledge/swagger-ui/index.html",
355
+ apiFilter=["tag"] // 必填,避免输出爆炸 + 触发 definitionsDetail 传递闭包裁剪
356
+ )
142
357
  ```
143
358
 
144
- **步骤 5:返回解析结果**
359
+ > 此路径上下文成本翻倍(read_file 一次 + 整段 JSON 作为字符串参数再传一次),所以 `apiFilter` 必填。
360
+ > 若不知道按什么过滤,先回到 2.A 步骤 4 用 read_file 看一眼 `tags[]`/`paths.*.tags` 选 1-3 个关键词再调。
361
+
362
+ **步骤 2:返回解析结果**
145
363
 
146
- 将 `parse_swagger_json` 返回的解析结果直接返回给用户,格式与正常 fetch 完全一致。
364
+ 将返回结果直接呈现给用户。
147
365
 
148
- ### 二、联调测试(action=test)
366
+ ### 三、联调测试(action=test)
149
367
 
150
368
  **步骤 1:调用服务端 api_tool**
151
369
 
@@ -196,13 +414,53 @@ curl -s -X POST 'http://10.2.7.60:30194/ikmp-knowledge/api/xxx' \
196
414
 
197
415
  将 curl 的响应内容返回给用户。如果是 JSON 格式,尽量格式化输出。
198
416
 
417
+ ## ⚠️ 避坑指南(来自历史反馈)
418
+
419
+ 1. **禁止用 `curl | head/tail/jq/python` 对完整 Swagger JSON 做管道切片** —— curl 管道经常因下游 SIGPIPE 截断,导致 JSON 不闭合 / Python 解析失败 / 临时写花括号平衡脚本,是历史踩坑率最高的反模式。**必须用 `-o /tmp/xxx.json` 写文件**,再用脚本或 `parse_swagger_json` 处理。
420
+ 2. **不要在本地手写脚本切 Swagger** —— `extract-swagger.mjs`/`extract_swagger.py` 已经做了和服务端 `parseApiDocs` 完全对齐的递归展开、传递闭包、required 标注、过滤裁剪。本地手写一个 mini 版只会丢字段或踩 `$ref`/`originalRef` 双字段陷阱。
421
+ 3. **过滤优先用 `--filter`(脚本)或 `apiFilter`(服务端)** —— 不要先拿全量再让 AI 自己挑接口看,过滤后 `definitionsDetail` 会自动按传递闭包裁剪,输出量减少 70%+。
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
+ ```
452
+
199
453
  ## 快捷方式:AI 直接识别 10 段地址
200
454
 
201
- 如果 AI 能识别出用户请求的 URL 中包含 `10.x.x.x` 主机地址,可以**直接跳过首次 api_tool 调用**,在本地执行 curl,再调用 `parse_swagger_json`,减少一次无用的服务端请求:
455
+ 如果 AI 能识别出用户请求的 URL 中包含 `10.x.x.x` 主机地址,可以**直接跳过首次 api_tool 调用**,在本地执行脚本,减少一次无用的服务端请求:
202
456
 
203
- 1. 从 Swagger URL 推导鉴权地址、文档地址
204
- 2. 通过 `run_command` 在本地依次 curl
205
- 3. 调用 `api_tool(action="parse_swagger_json")` 解析
457
+ ```bash
458
+ node ~/.qwen/extensions/szcd-component-helper/skills/local-api-tool/scripts/extract-swagger.mjs \
459
+ --url 'http://10.x.x.x/<service>/v2/api-docs' \
460
+ [--cookie '<JSESSIONID=...>'] \
461
+ [--filter '<关键词>'] \
462
+ --out /tmp/parsed.json
463
+ ```
206
464
 
207
465
  ### URL 推导规则
208
466
 
@@ -214,33 +472,11 @@ curl -s -X POST 'http://10.2.7.60:30194/ikmp-knowledge/api/xxx' \
214
472
  | authUrl | `basePath + /swagger-resources/configuration/ui` | `http://10.2.7.60:30194/ikmp-knowledge/swagger-resources/configuration/ui` |
215
473
  | apiDocsUrl | `basePath + /v2/api-docs` | `http://10.2.7.60:30194/ikmp-knowledge/v2/api-docs` |
216
474
 
217
- ### curl 执行模板
218
-
219
- **鉴权(带密码时):**
220
- ```bash
221
- curl -s -D - -X GET '<authUrl>' \
222
- -H 'Authorization: Basic <base64(username:password)>' \
223
- -H 'Accept: application/json'
224
- ```
225
-
226
- **获取文档(带 Cookie 时):**
227
- ```bash
228
- curl -s -X GET '<apiDocsUrl>' \
229
- -H 'Accept: application/json' \
230
- -H 'Cookie: <鉴权获取的Cookie>'
231
- ```
232
-
233
- **获取文档(无密码时):**
234
- ```bash
235
- curl -s -X GET '<apiDocsUrl>' \
236
- -H 'Accept: application/json'
237
- ```
238
-
239
475
  ## 注意事项
240
476
 
241
- 1. **Cookie 传递**:鉴权步骤获取的 Cookie 需要在后续步骤中通过 `-H 'Cookie: xxx'` 传递
477
+ 1. **Cookie 传递**:鉴权步骤获取的 Cookie 通过 `--cookie` 传给脚本,或通过 `-H 'Cookie: xxx'` 传给 curl
242
478
  2. **无密码场景**:如果用户未提供密码,跳过鉴权步骤,直接获取文档
243
- 3. **JSON 格式**:curl 获取的 API 文档必须是有效的 Swagger JSON,否则 `parse_swagger_json` 会报错
244
- 4. **超时处理**:本地 curl 可能因网络原因超时,建议添加 `--connect-timeout 10 --max-time 30` 参数
245
- 5. **错误处理**:如果某步骤 curl 失败,将错误信息返回给用户,不要继续后续步骤
246
- 6. **自动执行**:AI 识别 `reason: "LOCAL_NETWORK_UNREACHABLE"` 后应**自动**通过 `run_command` 执行 curl,无需让用户手动复制粘贴命令
479
+ 3. **JSON 格式**:脚本/curl 获取的 API 文档必须是有效的 Swagger JSON。八进制字面量(`[011,015]` 类)会被自动修复;其他非法格式(HTML 跳转/截断)脚本会输出错误位置 ±80 字符上下文 + 常见原因提示,按提示排查即可
480
+ 4. **超时处理**:脚本和 curl 都已内置 `--connect-timeout 10 --max-time 30`,可通过 `--timeout` 调整
481
+ 5. **错误处理**:脚本退出码 1=参数错误 / 2=网络IO / 3=解析;如果某步骤失败,将错误信息返回给用户,不要继续后续步骤
482
+ 6. **自动执行**:AI 识别 10.x.x.x 或 `reason: "LOCAL_NETWORK_UNREACHABLE"` 后应**自动**通过 `run_command` 执行脚本,无需让用户手动复制粘贴命令