@ia-ccun/code-agent-cli 0.0.52 → 0.0.53-beta.2

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 (89) hide show
  1. package/bin/cli.js +97 -69
  2. package/config/agent/bin/README.md +102 -0
  3. package/config/agent/extensions/aicode-advisor.ts +197 -61
  4. package/config/agent/extensions/aicode-banner.ts +101 -0
  5. package/config/agent/extensions/aicode-btw.ts +677 -183
  6. package/config/agent/extensions/aicode-cd.ts +1017 -0
  7. package/config/agent/extensions/aicode-grillMe.ts +198 -0
  8. package/config/agent/extensions/aicode-pets.ts +351 -0
  9. package/config/agent/extensions/aicode-plan.ts +2 -0
  10. package/config/agent/extensions/aicode-safety-guard.ts +555 -0
  11. package/config/agent/extensions/aicode-tips.ts +69 -30
  12. package/config/agent/extensions/aicode-todo-progress.ts +547 -0
  13. package/config/agent/extensions/context-monitor.ts +30 -15
  14. package/config/agent/extensions/context.ts +132 -60
  15. package/config/agent/extensions/custom-footer.ts +0 -5
  16. package/config/agent/extensions/custom.ts +119 -109
  17. package/config/agent/extensions/error-monitor.ts +38 -51
  18. package/config/agent/extensions/goal.ts +8 -6
  19. package/config/agent/extensions/msg-debug.ts +103 -112
  20. package/config/agent/extensions/ponytail.ts +441 -0
  21. package/config/agent/extensions/review.ts +365 -164
  22. package/config/agent/extensions/tps.ts +87 -0
  23. package/config/agent/extensions/working-msg.ts +164 -51
  24. package/config/agent/help.md +0 -7
  25. package/config/agent/models.json +7 -7
  26. package/config/agent/settings.json +2 -1
  27. package/config/agent/skills/chroma/LICENSE +21 -0
  28. package/config/agent/skills/chroma/chroma-local/SKILL.md +165 -0
  29. package/config/agent/skills/chroma/chroma-local/cli.md +48 -0
  30. package/config/agent/skills/chroma/chroma-local/data-model.md +103 -0
  31. package/config/agent/skills/chroma/chroma-local/error-handling/python.md +166 -0
  32. package/config/agent/skills/chroma/chroma-local/error-handling/typescript.md +231 -0
  33. package/config/agent/skills/chroma/chroma-local/local-chroma/python.md +95 -0
  34. package/config/agent/skills/chroma/chroma-local/local-chroma/typescript.md +101 -0
  35. package/config/agent/skills/chroma/chroma-local/metadata/python.md +154 -0
  36. package/config/agent/skills/chroma/chroma-local/metadata/typescript.md +153 -0
  37. package/config/agent/skills/chroma/chroma-local/querying/python.md +147 -0
  38. package/config/agent/skills/chroma/chroma-local/querying/typescript.md +157 -0
  39. package/config/agent/skills/chroma/chroma-local/regex/python.md +69 -0
  40. package/config/agent/skills/chroma/chroma-local/regex/typescript.md +71 -0
  41. package/config/agent/skills/chroma/chroma-local/understanding-a-codebase.md +80 -0
  42. package/config/agent/skills/chroma/chroma-local/updating-deleting/python.md +159 -0
  43. package/config/agent/skills/chroma/chroma-local/updating-deleting/typescript.md +228 -0
  44. package/config/agent/skills/milvus-skill/LICENSE +202 -0
  45. package/config/agent/skills/milvus-skill/README.md +37 -0
  46. package/config/agent/skills/milvus-skill/SKILL.md +259 -0
  47. package/config/agent/skills/milvus-skill/references/collection.md +86 -0
  48. package/config/agent/skills/milvus-skill/references/database.md +24 -0
  49. package/config/agent/skills/milvus-skill/references/index.md +69 -0
  50. package/config/agent/skills/milvus-skill/references/partition.md +29 -0
  51. package/config/agent/skills/milvus-skill/references/patterns.md +150 -0
  52. package/config/agent/skills/milvus-skill/references/user-role.md +90 -0
  53. package/config/agent/skills/milvus-skill/references/vector.md +247 -0
  54. package/config/agent/skills/ponytail/SKILL.md +100 -0
  55. package/config/agent/skills/ponytail-audit/SKILL.md +40 -0
  56. package/config/agent/skills/ponytail-debt/SKILL.md +44 -0
  57. package/config/agent/skills/ponytail-help/SKILL.md +68 -0
  58. package/config/agent/skills/ponytail-review/SKILL.md +56 -0
  59. package/config/agent/skills/zread/README.md +115 -0
  60. package/config/agent/skills/zread/SKILL.md +103 -0
  61. package/config/agent/skills/zread/references/stdio-protocol.md +312 -0
  62. package/dist/banner.d.ts.map +1 -1
  63. package/dist/banner.js +8 -1
  64. package/dist/banner.js.map +1 -1
  65. package/dist/config-loader.d.ts.map +1 -1
  66. package/dist/config-loader.js +9 -2
  67. package/dist/config-loader.js.map +1 -1
  68. package/package.json +7 -7
  69. package/scripts/postinstall.js +58 -1
  70. package/scripts/regression/README.md +224 -0
  71. package/scripts/regression/cases/01-version-and-deps.sh +94 -0
  72. package/scripts/regression/cases/02-extension-loading.sh +130 -0
  73. package/scripts/regression/cases/03-rpc-protocol.sh +259 -0
  74. package/scripts/regression/cases/04-prompt-stream.sh +130 -0
  75. package/scripts/regression/cases/05-slash-commands-and-skills.sh +119 -0
  76. package/scripts/regression/cases/06-tool-execution.sh +115 -0
  77. package/scripts/regression/cases/07-pi-new-features.sh +141 -0
  78. package/scripts/regression/lib/common.sh +287 -0
  79. package/scripts/regression/results/.last_pid +1 -0
  80. package/scripts/regression/results/.last_workdir +1 -0
  81. package/scripts/regression/results/02-extension-loading.log +18 -0
  82. package/scripts/regression/results/03-prompt-stream.log +16 -0
  83. package/scripts/regression/results/03-rpc-protocol.log +27 -0
  84. package/scripts/regression/results/04-slash-commands-and-skills.log +11 -0
  85. package/scripts/regression/results/05-tool-execution.log +8 -0
  86. package/scripts/regression/results/06-pi-new-features.log +29 -0
  87. package/scripts/regression/run-all.sh +187 -0
  88. package/config/agent/dangerous-patterns.json +0 -106
  89. package/config/agent/extensions/bash-check.ts +0 -227
@@ -0,0 +1,224 @@
1
+ # aicode-cli 回归测试套件
2
+
3
+ > 用于验证每次升级 pi 底层依赖后,aicode-cli 的功能完整性不受影响。
4
+ > 也可用于新 aicode 版本发布前的本地预检。
5
+
6
+ ## 设计目标
7
+
8
+ | 维度 | 验证内容 |
9
+ |---|---|
10
+ | **版本对齐** | aicode 二进制版本 + 4 个 pi 依赖包主版本一致 |
11
+ | **aicode 特色功能** | 20 个自定义 TS 扩展全部加载,无冲突 / 无语法错误 |
12
+ | **RPC 协议兼容** ⭐ | AicodeRpcClient.kt 实际用到的 17 个 RPC 命令 + 7 个事件类型 + 字段 schema |
13
+ | **预置资产** | 5 个 Prompt + 21+ 个 Skill 全部通过 `get_commands` 注册 |
14
+ | **核心能力** | prompt → message_update 完整事件流、tool_execution 配对 |
15
+ | **pi 0.85 新功能** | `clear_queue` RPC、GPT-6 Astra、thinking 持久化、`usage.cacheWrite1h` |
16
+
17
+ > ⭐ **RPC 协议兼容** 是本套件的核心重点 — 任何 RPC 命令的字段格式变化都会在 case 03 失败。
18
+
19
+ ## 快速开始
20
+
21
+ ### 前置依赖
22
+
23
+ ```bash
24
+ brew install jq
25
+ ```
26
+
27
+ ### 运行全部测试
28
+
29
+ ```bash
30
+ # 默认(使用 PATH 中的 aicode,配置目录 ~/.aicode-cli)
31
+ ./run-all.sh
32
+
33
+ # 指定 aicode 二进制(测试本地包)
34
+ AICODE_BIN=$(pwd)/bin/cli.js ./run-all.sh
35
+ ```
36
+
37
+ ### 只跑部分 case
38
+
39
+ ```bash
40
+ # 只跑 RPC 兼容性(升级后必跑)
41
+ ./run-all.sh --only 03
42
+
43
+ # 跑 RPC + 新功能验证(最小升级预检)
44
+ ./run-all.sh --only 03,07
45
+
46
+ # 跑核心 4 个
47
+ ./run-all.sh --only 01,02,03,07
48
+ ```
49
+
50
+ ### 单个 case 直接跑
51
+
52
+ ```bash
53
+ ./cases/01-version-and-deps.sh
54
+ ./cases/02-extension-loading.sh
55
+ ./cases/03-rpc-protocol.sh
56
+ ./cases/04-prompt-stream.sh
57
+ ./cases/05-slash-commands-and-skills.sh
58
+ ./cases/06-tool-execution.sh
59
+ ./cases/07-pi-new-features.sh
60
+ ```
61
+
62
+ ## Case 清单
63
+
64
+ | Case | 文件 | 主题 | 关键断言 |
65
+ |---|---|---|---|
66
+ | **01** | `01-version-and-deps.sh` | 版本与依赖 | `aicode -v` 格式合规 + 4 个 pi 包主版本匹配 |
67
+ | **02** | `02-extension-loading.sh` | aicode 扩展加载 | 启动无 `Failed to load`/`conflict`/`SyntaxError`;aicode-* 命令注册 |
68
+ | **03** ⭐ | `03-rpc-protocol.sh` | **RPC 协议兼容性矩阵** | 17 个 RPC 命令 + 7 个事件类型 + 字段 schema + stopReason 枚举值 |
69
+ | **04** | `04-prompt-stream.sh` | prompt 事件流 | `agent_start`/`turn_start`/`message_update`(thinking_delta/text_delta)/`turn_end`/`agent_end` 序列 |
70
+ | **05** | `05-slash-commands-and-skills.sh` | Prompts + Skills | `/git-commit` `/workflow` 等 5 个 prompt + `/skill:code-review` 等核心 skill |
71
+ | **06** | `06-tool-execution.sh` | 工具调用 | `tool_execution_start` 必带 `toolCallId`+`toolName`(0.84.3 修复点) |
72
+ | **07** | `07-pi-new-features.sh` | pi 0.85 新功能 | `clear_queue` RPC、GPT-6、thinking 持久化、`cacheWrite1h` |
73
+
74
+ ## RPC 协议覆盖矩阵(case 03)
75
+
76
+ ### RPC 命令(17 个)
77
+
78
+ | 命令 | 来源 | 用途 |
79
+ |---|---|---|
80
+ | `prompt` / `steer` / `follow_up` / `abort` | AicodeRpcClient.streamPrompt/Steer/FollowUp/abort | 消息流 |
81
+ | `compact` | AicodeRpcClient.compact | 上下文压缩 |
82
+ | `extension_ui_response` | AicodeRpcClient.respondExtensionUi | 扩展 UI 回调 |
83
+ | `get_state` / `get_session_stats` / `get_commands` | fetchState/fetchSessionStats/getCommands | 状态查询 |
84
+ | `get_available_models` / `get_available_thinking_levels` | AicodeRpcClient | 模型/thinking 选择 |
85
+ | `get_messages` / `get_entries` / `get_tree` | AicodeRpcClient | 会话历史 |
86
+ | `set_thinking_level` / `cycle_thinking_level` / `set_model_provider` | AicodeRpcClient | 模型控制 |
87
+ | `set_tools` | AicodeRpcClient.setTools | 工具开关 |
88
+ | `new_session` / `clear_queue` | AicodeRpcClient.newSession/clearQueue | 会话管理 + 队列 |
89
+
90
+ ### 事件类型(11 个)
91
+
92
+ | 事件 | AicodeStreamItem 映射 |
93
+ |---|---|
94
+ | `agent_start` / `turn_start` | lifecycle |
95
+ | `message_start` / `message_end` | lifecycle |
96
+ | `message_update` | Text / Thinking |
97
+ | `turn_end` / `agent_end` | TurnEnd / lifecycle |
98
+ | `tool_execution_start` / `_update` / `_end` | ToolStart / ToolUpdate / ToolEnd |
99
+ | `queue_update` | QueueUpdate |
100
+ | `auto_retry_end` | Error |
101
+
102
+ ### 字段 schema(关键)
103
+
104
+ - `message_start.message.role` ∈ {user, assistant, toolResult}
105
+ - `message_update.assistantMessageEvent.{type, delta, contentIndex}`
106
+ - `turn_end.message.usage.{input, output, cost, ...}`
107
+ - `tool_execution_start.{toolCallId, toolName, args}` (0.84.3 修复点)
108
+ - `tool_execution_end.{isError: "true"|"false"}`
109
+ - `message_end.message.stopReason` ∈ {end_turn, tool_use, error, max_tokens, aborted}
110
+ - `agent_end.willRetry` ∈ {"true", "false"}
111
+
112
+ ## 升级后必跑
113
+
114
+ ```bash
115
+ # 1. 改完 package.json,npm install
116
+ # 2. 编译
117
+ npm run build
118
+
119
+ # 3. RPC 兼容性是首要重点
120
+ ./scripts/regression/run-all.sh --only 03
121
+
122
+ # 4. 全量回归
123
+ ./scripts/regression/run-all.sh
124
+
125
+ # 5. 看 results/*.log
126
+ ls scripts/regression/results/
127
+ ```
128
+
129
+ ## 验收标准
130
+
131
+ 升级可发布的最低条件:
132
+
133
+ | Case | 最低要求 |
134
+ |---|---|
135
+ | 01 version-and-deps | 全部 pass |
136
+ | 02 extension-loading | fail_count = 0 |
137
+ | **03 rpc-protocol** | **全部 pass 或 skip(已知不支持)** |
138
+ | 04 prompt-stream | 全部 pass |
139
+ | 05 slash-commands-and-skills | 注册率 ≥ 80% |
140
+ | 06 tool-execution | 至少 1 个 tool 事件配对成功 |
141
+ | 07 pi-new-features | skip 都标 "pi < 0.85.0 不支持" |
142
+
143
+ ## 输出位置
144
+
145
+ | 文件 | 内容 |
146
+ |---|---|
147
+ | `results/<case-name>.log` | 每个 case 的 stdout(pass/fail 行 + RPC 事件 log) |
148
+ | `results/.last_pid` | 最近一次 spawn 的 RPC 进程 PID(调试用) |
149
+
150
+ ## 隔离机制
151
+
152
+ 每个 case 独立 spawn 一个 `aicode --mode rpc --no-session` 子进程,使用临时目录(`mktemp -d`)作为 configDir,**不污染**用户 `~/.aicode-cli/`。结束后自动清理。
153
+
154
+ 但 `02-extension-loading.sh` 需要真实加载扩展(不能用 `-ne`),所以它会用临时目录作为 configDir 跑全量加载,验证 20 个扩展都能正常启动。
155
+
156
+ ## 依赖扩展的 case
157
+
158
+ - **02、05** 都需要正常启动扩展 → 不传 `-ne`
159
+ - **03、04、06、07** 主要测 RPC 协议 → 用 `-ne` 跳过扩展避免冲突
160
+
161
+ ## 调试
162
+
163
+ ### 单独看 RPC 事件流
164
+
165
+ ```bash
166
+ # 看 03 的 RPC 命令响应
167
+ jq -c 'select(.type=="response")' scripts/regression/results/03-rpc-protocol.log | head -20
168
+
169
+ # 看 message_update delta 流
170
+ grep message_update scripts/regression/results/04-prompt-stream.log | \
171
+ jq -c '{event: .assistantMessageEvent.type, delta: .assistantMessageEvent.delta}'
172
+ ```
173
+
174
+ ### 验证 RPC schema 漂移
175
+
176
+ ```bash
177
+ # 列出所有 turn_end 的 usage keys
178
+ jq -c 'select(.type=="turn_end") | .message.usage | keys | sort' \
179
+ scripts/regression/results/03-rpc-protocol.log | sort -u
180
+
181
+ # 对比不同 pi 版本
182
+ diff <(jq -c '...' results-v0.80.log) <(jq -c '...' results-v0.85.log)
183
+ ```
184
+
185
+ ## 与 aicode-plugin-swing 的关系
186
+
187
+ | 层 | 测试位置 |
188
+ |---|---|
189
+ | aicode CLI 功能(命令/扩展/skills) | 本套件(scripts/regression/) |
190
+ | RPC 协议兼容性 | 本套件 case 03 ⭐ |
191
+ | Kotlin 客户端逻辑 | `~/icode/aicode-idea-plugin-swing/src/test/kotlin/com/nu/aicode/rpc/` |
192
+ | 升级兼容性评估 | `~/icode/aicode-idea-plugin-swing/docs/spec/upgrade-code-agent-cli-to-pi-085.md` |
193
+ | 端到端 IDE 集成 | aicode-plugin-swing 实际 IDE 测试 |
194
+
195
+ **本套件(CLI 侧)+ Kotlin 单元测试 + 实际 IDE 集成 = 完整回归链路。**
196
+
197
+ ## 添加新 case
198
+
199
+ 1. 复制 `cases/06-tool-execution.sh` → `cases/08-my-feature.sh`
200
+ 2. 修改 `CURRENT_CASE`
201
+ 3. 调用 `source "$SCRIPT_DIR/../lib/common.sh"`
202
+ 4. 用 `pass` / `fail` / `skip` 报告结果
203
+ 5. 最后 `summary; exit $?`
204
+
205
+ ## 添加新的 RPC 命令到 case 03
206
+
207
+ 编辑 `03-rpc-protocol.sh` 的 `RPC_COMMANDS` 数组:
208
+
209
+ ```bash
210
+ RPC_COMMANDS=(
211
+ ...
212
+ "my_new_command|{\"foo\":\"bar\"}"
213
+ )
214
+ ```
215
+
216
+ 格式:`type|payload`,payload 会拼到 `{...,"id":"rpcN"}` 中。
217
+
218
+ ## 修订记录
219
+
220
+ | 日期 | 修订 |
221
+ |---|---|
222
+ | 2026-09-12 | 初版:6 个 case |
223
+ | 2026-09-12 v2 | 新增 case 03 RPC 协议兼容性矩阵(17 命令 + 11 事件 + schema)|
224
+ | 2026-09-12 v2 | 重新编号:03 RPC / 04 prompt / 05 slash / 06 tool / 07 pi-new |
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env bash
2
+ # 01-version-and-deps.sh
3
+ # 验证:aicode 二进制版本 + 内嵌 pi 包版本
4
+ # 这是回归测试的入口,确认我们用的版本符合预期
5
+
6
+ set -uo pipefail
7
+ CURRENT_CASE="01-version-and-deps"
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ source "$SCRIPT_DIR/../lib/common.sh"
10
+
11
+ header "$CURRENT_CASE" "version & pi dependencies"
12
+
13
+ # ----- Test 1: aicode -v 输出 -----
14
+ header "$CURRENT_CASE" "aicode binary"
15
+ if ! command -v "$AICODE_BIN" >/dev/null 2>&1; then
16
+ fail "aicode 二进制存在" "未找到 $AICODE_BIN,设 AICODE_BIN 环境变量"
17
+ summary
18
+ exit 1
19
+ fi
20
+ pass "aicode 二进制存在 ($AICODE_BIN)"
21
+
22
+ VERSION=$("$AICODE_BIN" -v 2>&1 | head -1)
23
+ echo " version: $VERSION"
24
+
25
+ if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9.]+)?$ ]]; then
26
+ pass "版本号格式合规 ($VERSION)"
27
+ else
28
+ fail "版本号格式合规" "got: $VERSION"
29
+ fi
30
+
31
+ # ----- Test 2: 内嵌 pi 包版本 -----
32
+ header "$CURRENT_CASE" "pi package dependencies"
33
+
34
+ # 找到 aicode 安装路径里的 package.json
35
+ AICODE_PATH=$(command -v "$AICODE_BIN")
36
+ # 解析 symlink
37
+ if [[ -L "$AICODE_PATH" ]]; then
38
+ AICODE_PATH=$(readlink "$AICODE_PATH")
39
+ fi
40
+
41
+ # 找 package.json
42
+ RESOLVED_PATH=$(node -e "
43
+ const path = require('path');
44
+ const fs = require('fs');
45
+ let p = '$AICODE_PATH';
46
+ // aicode -> ../lib/node_modules/@ia-ccun/code-agent-cli/bin/cli.js
47
+ if (p.includes('/lib/node_modules/')) {
48
+ p = p.split('/lib/node_modules/')[0] + '/lib/node_modules/@ia-ccun/code-agent-cli';
49
+ } else if (p.includes('/.bin/')) {
50
+ p = path.join(path.dirname(p), '..', 'lib', 'node_modules', '@ia-ccun', 'code-agent-cli');
51
+ }
52
+ try {
53
+ const pkg = JSON.parse(fs.readFileSync(path.join(p, 'package.json'), 'utf8'));
54
+ console.log(p);
55
+ console.log(JSON.stringify(pkg.dependencies || {}));
56
+ } catch (e) { console.error(e.message); process.exit(1); }
57
+ " 2>&1) || {
58
+ fail "解析 aicode 安装路径" "node 解析失败"
59
+ summary
60
+ exit 1
61
+ }
62
+
63
+ AICODE_ROOT=$(echo "$RESOLVED_PATH" | head -1)
64
+ DEPS_JSON=$(echo "$RESOLVED_PATH" | tail -1)
65
+ echo " install path: $AICODE_ROOT"
66
+ echo " declared deps: $DEPS_JSON"
67
+
68
+ # 检查 4 个核心 pi 包
69
+ for pkg in @earendil-works/pi-agent-core @earendil-works/pi-ai @earendil-works/pi-coding-agent @earendil-works/pi-tui; do
70
+ declared=$(echo "$DEPS_JSON" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('$pkg','MISSING'))" 2>/dev/null)
71
+ if [[ "$declared" == "MISSING" || -z "$declared" ]]; then
72
+ fail "$pkg 已在 dependencies 声明" "declared: $declared"
73
+ continue
74
+ fi
75
+ pass "$pkg declared as $declared"
76
+
77
+ # 检查实际安装版本
78
+ actual=$("$AICODE_ROOT/node_modules/$pkg/package.json" -e "console.log(require('$AICODE_ROOT/node_modules/$pkg/package.json').version)" 2>/dev/null)
79
+ if [[ -n "$actual" ]]; then
80
+ # 解析 semver 主要版本
81
+ declared_major=$(echo "$declared" | sed -E 's/^[^0-9]*([0-9]+).*/\1/')
82
+ actual_major=$(echo "$actual" | sed -E 's/^[^0-9]*([0-9]+).*/\1/')
83
+ if [[ "$declared_major" == "$actual_major" ]]; then
84
+ pass "$pkg 安装版本 $actual 满足 ^$declared_major"
85
+ else
86
+ fail "$pkg 主版本一致" "declared major=$declared_major | actual=$actual"
87
+ fi
88
+ else
89
+ fail "$pkg 实际安装版本" "无法读取 $AICODE_ROOT/node_modules/$pkg/package.json"
90
+ fi
91
+ done
92
+
93
+ summary
94
+ exit $?
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env bash
2
+ # 02-extension-loading.sh
3
+ # 验证:aicode-cli 自带的 20 个 TypeScript 扩展在 RPC 启动时全部成功加载
4
+ #
5
+ # 这是 aicode-cli 的核心差异化能力:
6
+ # - aicode-btw / aicode-plan / aicode-advisor / aicode-cd / aicode-grillMe
7
+ # - aicode-safety-guard / aicode-todo-progress / aicode-tips / aicode-pets
8
+ # - context-monitor / context / error-monitor / working-msg / tps
9
+ # - goal / review / ponytail / custom / custom-footer / msg-debug
10
+ #
11
+ # 升级 pi 后扩展 API 可能微调,必须验证:
12
+ # 1. 启动时没有任何 "Failed to load extension" 错误
13
+ # 2. 没有任何工具名冲突(conflict error)
14
+ # 3. 至少 N 个 aicode-* 扩展在 .agents.md 或 get_commands 中可见
15
+
16
+ set -uo pipefail
17
+ CURRENT_CASE="02-extension-loading"
18
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ source "$SCRIPT_DIR/../lib/common.sh"
20
+
21
+ header "$CURRENT_CASE" "aicode custom extensions"
22
+
23
+ if ! spawn_rpc; then
24
+ fail "spawn aicode RPC(带扩展)" "进程启动失败"
25
+ summary
26
+ exit 1
27
+ fi
28
+ pass "spawn aicode RPC (pid=$REGRESSION_PID)"
29
+
30
+ # ----- Test 1: 启动日志中无扩展加载失败 -----
31
+ header "$CURRENT_CASE" "extension load errors"
32
+
33
+ # 把 stderr/stdout 全捕获到 log(-ne 关闭扩展 → 我们用普通模式)
34
+ cleanup_rpc
35
+
36
+ # 重启:不用 -ne,让所有扩展都加载
37
+ WORKDIR=$(mktemp -d -t aicode-ext.XXXXXX)
38
+ cat >"$WORKDIR/config.json" <<EOF
39
+ {"name":"aicode-test","banner":"","themeColor":"#49bccf","configDir":"$(basename "$WORKDIR")"}
40
+ EOF
41
+
42
+ LOG="$RESULTS_DIR/${CURRENT_CASE}.log"
43
+ : >"$LOG"
44
+
45
+ "$AICODE_BIN" --config "$WORKDIR" --mode rpc --no-session \
46
+ < /dev/null >"$LOG" 2>&1 &
47
+ EXT_PID=$!
48
+
49
+ # 等启动完成(5s 应该够)
50
+ sleep 5
51
+ kill "$EXT_PID" 2>/dev/null
52
+ wait "$EXT_PID" 2>/dev/null
53
+
54
+ # 错误关键字扫描
55
+ echo " scanning log for extension errors..."
56
+
57
+ fail_count=0
58
+ for pattern in "Failed to load extension" "Tool.*conflicts with" "Cannot find module" "SyntaxError" "TypeError.*Extension"; do
59
+ matches=$(grep -cE "$pattern" "$LOG" 2>/dev/null || echo 0)
60
+ if [[ "$matches" -gt 0 ]]; then
61
+ fail "无 $pattern 错误" "found $matches matches"
62
+ grep -E "$pattern" "$LOG" | head -3 | sed 's/^/ /'
63
+ fail_count=$((fail_count + matches))
64
+ else
65
+ pass "无 '$pattern' 错误"
66
+ fi
67
+ done
68
+
69
+ # ----- Test 2: get_commands 包含 aicode- 自定义命令 -----
70
+ # 不带 -ne 启动,确认扩展注册的 slash commands 也可见
71
+ header "$CURRENT_CASE" "aicode custom slash commands"
72
+
73
+ spawn_rpc 2>/dev/null || {
74
+ fail "second spawn" "进程启动失败"
75
+ summary; exit 1
76
+ }
77
+
78
+ send '{"type":"get_commands","id":"e1"}'
79
+ sleep 1
80
+
81
+ cmds_json=$(jq -c 'select(.id=="e1" and .type=="response") | .data.commands' "$REGRESSION_LOG" 2>/dev/null | head -1)
82
+ cmd_count=$(echo "$cmds_json" | jq -c 'length' 2>/dev/null)
83
+ echo " registered commands: $cmd_count"
84
+
85
+ if [[ -z "$cmd_count" || "$cmd_count" == "null" || "$cmd_count" -lt 5 ]]; then
86
+ fail "至少注册 5 个命令" "got: $cmd_count"
87
+ else
88
+ pass "注册 $cmd_count 个 slash commands"
89
+ fi
90
+
91
+ # 关键 aicode 自定义命令(在 /llama /model /settings 等内置之外的 aicode-*)
92
+ AICODE_CMDS=("/aicode-cd" "/grill-me" "/bugs" "/goal" "/plan" "/workflow" "/git-commit" "/feat" "/init-project" "/code-simplifier")
93
+ for cmd in "${AICODE_CMDS[@]}"; do
94
+ if echo "$cmds_json" | jq -e --arg c "$cmd" '.[] | select(.name == $c)' >/dev/null 2>&1; then
95
+ pass "扩展命令 $cmd 已注册"
96
+ else
97
+ # 可能该命令需要其他条件才注册,标记 skip
98
+ skip "扩展命令 $cmd 已注册" "未在 get_commands 中找到"
99
+ fi
100
+ done
101
+
102
+ # ----- Test 3: get_state 反映扩展注册的工具 -----
103
+ header "$CURRENT_CASE" "tools registered by extensions"
104
+
105
+ send '{"type":"get_state","id":"e2"}'
106
+ sleep 1
107
+
108
+ # 通过发 prompt 让模型思考,看 tool_execution_start 是否包含 aicode 扩展工具
109
+ # (aicode-safety-guard 注册的 safety_check / aicode-plan 注册的 todo_update 等)
110
+
111
+ send '{"type":"prompt","message":"just say hi","id":"e3"}'
112
+ sleep 8
113
+
114
+ # 收集所有出现过的 tool_name
115
+ all_tools=$(jq -r 'select(.type=="tool_execution_start") | .toolName // empty' "$REGRESSION_LOG" 2>/dev/null | sort -u)
116
+ echo " observed tools: $(echo "$all_tools" | tr '\n' ' ')"
117
+
118
+ # 内置工具一定在
119
+ for tool in read bash write edit; do
120
+ if echo "$all_tools" | grep -qx "$tool"; then
121
+ pass "内置工具 $tool 可调用"
122
+ else
123
+ # 单次 prompt 可能不调用
124
+ skip "内置工具 $tool 可调用" "本次 prompt 未触发"
125
+ fi
126
+ done
127
+
128
+ cleanup_rpc
129
+ summary
130
+ exit $?