@ia-ccun/code-agent-cli 0.0.54-beta.1 → 0.0.54-beta.4

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 (144) hide show
  1. package/bin/cli.js +116 -74
  2. package/config/agent/extensions/aicode-advisor.ts +187 -64
  3. package/config/agent/extensions/aicode-banner.ts +101 -0
  4. package/config/agent/extensions/aicode-btw.ts +619 -182
  5. package/config/agent/extensions/aicode-cd.ts +246 -63
  6. package/config/agent/extensions/aicode-pets.ts +0 -11
  7. package/config/agent/extensions/aicode-plan.ts +2 -0
  8. package/config/agent/extensions/aicode-safety-guard.ts +3 -0
  9. package/config/agent/extensions/aicode-tips.ts +1 -16
  10. package/config/agent/extensions/context-monitor.ts +30 -15
  11. package/config/agent/extensions/context.ts +132 -60
  12. package/config/agent/extensions/custom-footer.ts +42 -24
  13. package/config/agent/extensions/custom.ts +41 -29
  14. package/config/agent/extensions/error-monitor.ts +37 -33
  15. package/config/agent/extensions/goal.ts +8 -6
  16. package/config/agent/extensions/msg-debug.ts +103 -112
  17. package/config/agent/extensions/review.ts +365 -164
  18. package/config/agent/extensions/working-msg.ts +2 -4
  19. package/config/agent/settings.json +15 -14
  20. package/config/agent/skills/hello/SKILL.md +1 -1
  21. package/config/agent/skills/refactor/SKILL.md +40 -0
  22. package/dist/banner.d.ts.map +1 -1
  23. package/dist/banner.js +8 -1
  24. package/dist/banner.js.map +1 -1
  25. package/dist/config-loader.d.ts.map +1 -1
  26. package/dist/config-loader.js +9 -2
  27. package/dist/config-loader.js.map +1 -1
  28. package/package.json +6 -7
  29. package/scripts/regression/README.md +224 -0
  30. package/scripts/regression/cases/01-version-and-deps.sh +94 -0
  31. package/scripts/regression/cases/02-extension-loading.sh +130 -0
  32. package/scripts/regression/cases/03-rpc-protocol.sh +259 -0
  33. package/scripts/regression/cases/04-prompt-stream.sh +130 -0
  34. package/scripts/regression/cases/05-slash-commands-and-skills.sh +119 -0
  35. package/scripts/regression/cases/06-tool-execution.sh +115 -0
  36. package/scripts/regression/cases/07-pi-new-features.sh +141 -0
  37. package/scripts/regression/cases/08-cwd-resilience.sh +84 -0
  38. package/scripts/regression/lib/common.sh +287 -0
  39. package/scripts/regression/results/.last_pid +1 -0
  40. package/scripts/regression/results/.last_workdir +1 -0
  41. package/scripts/regression/results/02-extension-loading.log +19 -0
  42. package/scripts/regression/results/03-prompt-stream.log +16 -0
  43. package/scripts/regression/results/03-rpc-protocol.log +28 -0
  44. package/scripts/regression/results/04-slash-commands-and-skills.log +11 -0
  45. package/scripts/regression/results/05-tool-execution.log +8 -0
  46. package/scripts/regression/results/06-pi-new-features.log +27 -0
  47. package/scripts/regression/results/08-cwd-resilience.log +1 -0
  48. package/scripts/regression/run-all.sh +187 -0
  49. package/config/agent/bin/fd.exe +0 -0
  50. package/config/agent/bin/rg.exe +0 -0
  51. package/config/agent/extensions/aicode-filter-outputs.ts +0 -131
  52. package/config/agent/extensions/aicode-snake.ts +0 -354
  53. /package/config/agent/{skills_bak → skills}/csv-data-summarizer/SKILL.md +0 -0
  54. /package/config/agent/{skills_bak → skills}/csv-data-summarizer/analyze.py +0 -0
  55. /package/config/agent/{skills_bak → skills}/csv-data-summarizer/examples/showcase_financial_pl_data.csv +0 -0
  56. /package/config/agent/{skills_bak → skills}/csv-data-summarizer/requirements.txt +0 -0
  57. /package/config/agent/{skills_bak → skills}/csv-data-summarizer/resources/sample.csv +0 -0
  58. /package/config/agent/{skills_bak → skills}/dispatching-parallel-agents/SKILL.md +0 -0
  59. /package/config/agent/{skills_bak → skills}/find-skills/SKILL.md +0 -0
  60. /package/config/agent/{skills_bak → skills}/finishing-a-development-branch/SKILL.md +0 -0
  61. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/LICENSE +0 -0
  62. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/README.md +0 -0
  63. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/README.zh.md +0 -0
  64. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/SKILL.md +0 -0
  65. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/agentloop-core.svg +0 -0
  66. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/agents/openai.yaml +0 -0
  67. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/assets/samples/sample-style1-flat.png +0 -0
  68. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/assets/samples/sample-style2-dark.png +0 -0
  69. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/assets/samples/sample-style3-blueprint.png +0 -0
  70. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/assets/samples/sample-style4-notion.png +0 -0
  71. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/assets/samples/sample-style5-glass.png +0 -0
  72. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/assets/samples/sample-style6-claude.png +0 -0
  73. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/assets/samples/sample-style7-openai.png +0 -0
  74. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/fixtures/agent-memory-types-style4.json +0 -0
  75. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/fixtures/api-flow-style7.json +0 -0
  76. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/fixtures/mem0-style1.json +0 -0
  77. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/fixtures/microservices-style3.json +0 -0
  78. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/fixtures/multi-agent-style5.json +0 -0
  79. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/fixtures/system-architecture-style6.json +0 -0
  80. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/fixtures/tool-call-style2.json +0 -0
  81. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/package.json +0 -0
  82. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/icons.md +0 -0
  83. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-1-flat-icon.md +0 -0
  84. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-2-dark-terminal.md +0 -0
  85. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-3-blueprint.md +0 -0
  86. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-4-notion-clean.md +0 -0
  87. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-5-glassmorphism.md +0 -0
  88. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-6-claude-official.md +0 -0
  89. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-7-openai.md +0 -0
  90. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/style-diagram-matrix.md +0 -0
  91. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/references/svg-layout-best-practices.md +0 -0
  92. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/scripts/README.md +0 -0
  93. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/scripts/generate-diagram.sh +0 -0
  94. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/scripts/generate-from-template.py +0 -0
  95. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/scripts/test-all-styles.sh +0 -0
  96. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/scripts/validate-svg.sh +0 -0
  97. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/agent-architecture.svg +0 -0
  98. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/architecture.svg +0 -0
  99. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/comparison-matrix.svg +0 -0
  100. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/data-flow.svg +0 -0
  101. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/er-diagram.svg +0 -0
  102. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/flowchart.svg +0 -0
  103. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/sequence.svg +0 -0
  104. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/state-machine.svg +0 -0
  105. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/timeline.svg +0 -0
  106. /package/config/agent/{skills_bak → skills}/fireworks-tech-graph/templates/use-case.svg +0 -0
  107. /package/config/agent/{skills_bak → skills}/librarian/SKILL.md +0 -0
  108. /package/config/agent/{skills_bak → skills}/markdown-to-html/SKILL.md +0 -0
  109. /package/config/agent/{skills_bak → skills}/milvus-skill/LICENSE +0 -0
  110. /package/config/agent/{skills_bak → skills}/milvus-skill/README.md +0 -0
  111. /package/config/agent/{skills_bak → skills}/milvus-skill/SKILL.md +0 -0
  112. /package/config/agent/{skills_bak → skills}/milvus-skill/references/collection.md +0 -0
  113. /package/config/agent/{skills_bak → skills}/milvus-skill/references/database.md +0 -0
  114. /package/config/agent/{skills_bak → skills}/milvus-skill/references/index.md +0 -0
  115. /package/config/agent/{skills_bak → skills}/milvus-skill/references/partition.md +0 -0
  116. /package/config/agent/{skills_bak → skills}/milvus-skill/references/patterns.md +0 -0
  117. /package/config/agent/{skills_bak → skills}/milvus-skill/references/user-role.md +0 -0
  118. /package/config/agent/{skills_bak → skills}/milvus-skill/references/vector.md +0 -0
  119. /package/config/agent/{skills_bak → skills}/pr/SKILL.md +0 -0
  120. /package/config/agent/{skills_bak → skills}/receiving-code-review/SKILL.md +0 -0
  121. /package/config/agent/{skills_bak → skills}/requesting-code-review/SKILL.md +0 -0
  122. /package/config/agent/{skills_bak → skills}/requesting-code-review/code-reviewer.md +0 -0
  123. /package/config/agent/{skills_bak → skills}/subagent-driven-development/SKILL.md +0 -0
  124. /package/config/agent/{skills_bak → skills}/subagent-driven-development/code-quality-reviewer-prompt.md +0 -0
  125. /package/config/agent/{skills_bak → skills}/subagent-driven-development/implementer-prompt.md +0 -0
  126. /package/config/agent/{skills_bak → skills}/subagent-driven-development/spec-reviewer-prompt.md +0 -0
  127. /package/config/agent/{skills_bak → skills}/systematic-debugging/CREATION-LOG.md +0 -0
  128. /package/config/agent/{skills_bak → skills}/systematic-debugging/SKILL.md +0 -0
  129. /package/config/agent/{skills_bak → skills}/systematic-debugging/condition-based-waiting-example.ts +0 -0
  130. /package/config/agent/{skills_bak → skills}/systematic-debugging/condition-based-waiting.md +0 -0
  131. /package/config/agent/{skills_bak → skills}/systematic-debugging/defense-in-depth.md +0 -0
  132. /package/config/agent/{skills_bak → skills}/systematic-debugging/find-polluter.sh +0 -0
  133. /package/config/agent/{skills_bak → skills}/systematic-debugging/root-cause-tracing.md +0 -0
  134. /package/config/agent/{skills_bak → skills}/systematic-debugging/test-academic.md +0 -0
  135. /package/config/agent/{skills_bak → skills}/systematic-debugging/test-pressure-1.md +0 -0
  136. /package/config/agent/{skills_bak → skills}/systematic-debugging/test-pressure-2.md +0 -0
  137. /package/config/agent/{skills_bak → skills}/systematic-debugging/test-pressure-3.md +0 -0
  138. /package/config/agent/{skills_bak → skills}/test-driven-development/SKILL.md +0 -0
  139. /package/config/agent/{skills_bak → skills}/test-driven-development/testing-anti-patterns.md +0 -0
  140. /package/config/agent/{skills_bak → skills}/unit-test/SKILL.md +0 -0
  141. /package/config/agent/{skills_bak → skills}/using-git-worktrees/SKILL.md +0 -0
  142. /package/config/agent/{skills_bak → skills}/zread/README.md +0 -0
  143. /package/config/agent/{skills_bak → skills}/zread/SKILL.md +0 -0
  144. /package/config/agent/{skills_bak → skills}/zread/references/stdio-protocol.md +0 -0
package/bin/cli.js CHANGED
@@ -6,15 +6,30 @@
6
6
  */
7
7
 
8
8
  // 设置终端标题
9
- process.title = 'aicode-cli';
9
+ process.title = "aicode-cli";
10
10
 
11
- import { spawn } from 'child_process';
12
- import { fileURLToPath } from 'url';
13
- import { dirname, join } from 'path';
14
- import { existsSync, readFileSync, writeFileSync } from 'fs';
15
- import { getConfig, getConfigDir, loadConfig } from '../dist/config-loader.js';
16
- import { generateBanner } from '../dist/banner.js';
11
+ // 防御 CWD 被删: 在所有 import 之前 chdir (node ESM 解析 import 时会读 cwd)
12
+ // 不 import os.homedir() 因为那需要模块解析, 此时 cwd 还没改
13
+ // 用 process.env.PWD 优先 (用户启动目录) → HOME fallback (防 PWD 缺失 ENOENT)
14
+ // 先 PWD 试 (用户启动目录), 失败 fallback HOME (cwd 被删时 PWD 也指向已删目录, chdir 会抛 ENOENT)
15
+ // catch 后再退一步: HOME 也失败则 chdir 到 / (绝对保证不会 ENOENT)
16
+ try {
17
+ process.chdir(process.env.PWD);
18
+ } catch {
19
+ try {
20
+ process.chdir(process.env.HOME || "/");
21
+ } catch {
22
+ try {
23
+ process.chdir("/");
24
+ } catch {}
25
+ }
26
+ }
17
27
 
28
+ import { spawn } from "child_process";
29
+ import { fileURLToPath } from "url";
30
+ import { dirname, join } from "path";
31
+ import { existsSync, readFileSync, writeFileSync } from "fs";
32
+ import { getConfig, loadConfig } from "../dist/config-loader.js";
18
33
  const __filename = fileURLToPath(import.meta.url);
19
34
  const __dirname = dirname(__filename);
20
35
 
@@ -22,9 +37,13 @@ const __dirname = dirname(__filename);
22
37
  function getLocalVersion() {
23
38
  let rootDir = __dirname;
24
39
  while (rootDir !== dirname(rootDir)) {
25
- const pkgPath = join(rootDir, 'package.json');
40
+ const pkgPath = join(rootDir, "package.json");
26
41
  if (existsSync(pkgPath)) {
27
- return JSON.parse(readFileSync(pkgPath, 'utf-8')).version;
42
+ try {
43
+ return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
44
+ } catch {
45
+ return null;
46
+ }
28
47
  }
29
48
  rootDir = dirname(rootDir);
30
49
  }
@@ -33,33 +52,38 @@ function getLocalVersion() {
33
52
 
34
53
  // 获取版本缓存文件路径
35
54
  function getVersionCachePath() {
36
- return join(process.env.HOME || process.env.USERPROFILE, '.aicode-cli', '.version-cache.json');
55
+ return join(
56
+ process.env.HOME || process.env.USERPROFILE,
57
+ ".aicode-cli",
58
+ ".version-cache.json",
59
+ );
37
60
  }
38
61
 
39
62
  // 解析命令行参数
40
63
  function parseArgs() {
41
64
  const args = process.argv.slice(2);
42
65
  let configDir;
43
-
66
+
44
67
  // 处理 --version 参数,显示 CLI 自己的版本
45
- if (args.includes('--version') || args.includes('-v')) {
46
- const pkgPath = join(__dirname, '..', 'package.json');
68
+ if (args.includes("--version") || args.includes("-v")) {
69
+ const pkgPath = join(__dirname, "..", "package.json");
47
70
  if (existsSync(pkgPath)) {
48
- const { version } = JSON.parse(readFileSync(pkgPath, 'utf-8'));
49
- console.log(version);
50
- }
71
+ try {
72
+ const { version } = JSON.parse(readFileSync(pkgPath, "utf-8"));
73
+ console.log(version);
74
+ } catch (_e) {
51
75
  process.exit(0);
52
76
  }
53
-
77
+
54
78
  for (let i = 0; i < args.length; i++) {
55
79
  const arg = args[i];
56
- if (arg === '--config' || arg === '-c') {
80
+ if (arg === "--config" || arg === "-c") {
57
81
  configDir = args[i + 1];
58
82
  args.splice(i, 2);
59
83
  break;
60
84
  }
61
85
  }
62
-
86
+
63
87
  return { remainingArgs: args, configDir };
64
88
  }
65
89
 
@@ -86,41 +110,41 @@ function replaceCLIVersionPlaceholder() {
86
110
  // 找到项目根目录的 package.json
87
111
  let rootDir = __dirname;
88
112
  while (rootDir !== dirname(rootDir)) {
89
- const pkgPath = join(rootDir, 'package.json');
113
+ const pkgPath = join(rootDir, "package.json");
90
114
  if (existsSync(pkgPath)) {
91
- const { version } = JSON.parse(readFileSync(pkgPath, 'utf-8'));
115
+ const { version } = JSON.parse(readFileSync(pkgPath, "utf-8"));
92
116
  const versionString = `aicode-cli/${version}`;
93
-
117
+
94
118
  // 查找配置目录下的 models.json
95
119
  const homeDir = process.env.HOME || process.env.USERPROFILE;
96
120
  const configDirs = [
97
- join(homeDir, '.aicode-cli', 'agent'),
98
- join(homeDir, '.pi', 'agent'),
121
+ join(homeDir, ".aicode-cli", "agent"),
122
+ join(homeDir, ".pi", "agent"),
99
123
  ];
100
-
124
+
101
125
  for (const dir of configDirs) {
102
- const modelsPath = join(dir, 'models.json');
126
+ const modelsPath = join(dir, "models.json");
103
127
  if (!existsSync(modelsPath)) continue;
104
-
128
+
105
129
  try {
106
- let content = readFileSync(modelsPath, 'utf-8');
130
+ let content = readFileSync(modelsPath, "utf-8");
107
131
  const config = JSON.parse(content);
108
-
132
+
109
133
  // 遍历所有 provider,替换 headers.User-Agent 中的占位符
110
134
  for (const provider of Object.values(config.providers || {})) {
111
- if (provider.headers && provider.headers['User-Agent']) {
112
- const ua = provider.headers['User-Agent'];
113
- if (ua && ua.startsWith('${') && ua.endsWith('}')) {
114
- provider.headers['User-Agent'] = versionString;
135
+ if (provider.headers && provider.headers["User-Agent"]) {
136
+ const ua = provider.headers["User-Agent"];
137
+ if (ua && ua.startsWith("${") && ua.endsWith("}")) {
138
+ provider.headers["User-Agent"] = versionString;
115
139
  }
116
140
  }
117
141
  }
118
-
142
+
119
143
  const newContent = JSON.stringify(config, null, 2);
120
144
  if (newContent !== content) {
121
- writeFileSync(modelsPath, newContent, 'utf-8');
145
+ writeFileSync(modelsPath, newContent, "utf-8");
122
146
  }
123
- } catch (e) {
147
+ } catch {
124
148
  // 忽略错误
125
149
  }
126
150
  }
@@ -128,7 +152,7 @@ function replaceCLIVersionPlaceholder() {
128
152
  }
129
153
  rootDir = dirname(rootDir);
130
154
  }
131
- } catch (e) {
155
+ } catch {
132
156
  // 忽略错误
133
157
  }
134
158
  }
@@ -138,24 +162,21 @@ replaceCLIVersionPlaceholder();
138
162
 
139
163
  // 提前获取版本号(用于 banner 显示)
140
164
  const localVersion = getLocalVersion();
141
- process.env.AICODE_CLI_VERSION = localVersion || '';
165
+ process.env.AICODE_CLI_VERSION = localVersion || "";
142
166
 
143
- // 显示 Banner
144
- if (config.banner === '__default__' || config.banner !== '') {
145
- console.log(generateBanner(config.themeColor));
146
- }
167
+ // banner 启动后打印已移交给 config/agent/extensions/aicode-banner.ts
168
+ // 理由: 1) 避免 RPC 父进程的 stdout JSON-RPC 污染; 2) chdir 到 homedir 后再触发更稳
147
169
 
148
- // 检查新版本
149
170
  async function checkForUpdates() {
150
171
  try {
151
- const { execFileSync } = await import('child_process');
172
+ const { execFileSync } = await import("child_process");
152
173
  // 读取本地版本 - 向上查找 package.json
153
174
  let rootDir = __dirname;
154
175
  let localVersion = null;
155
176
  while (rootDir !== dirname(rootDir)) {
156
- const pkgPath = join(rootDir, 'package.json');
177
+ const pkgPath = join(rootDir, "package.json");
157
178
  if (existsSync(pkgPath)) {
158
- localVersion = JSON.parse(readFileSync(pkgPath, 'utf-8')).version;
179
+ localVersion = JSON.parse(readFileSync(pkgPath, "utf-8")).version;
159
180
  break;
160
181
  }
161
182
  rootDir = dirname(rootDir);
@@ -163,42 +184,56 @@ async function checkForUpdates() {
163
184
  if (!localVersion) return;
164
185
 
165
186
  // 🔒 Security: Use execFileSync instead of execSync to prevent command injection
166
- const registry = execFileSync('npm', ['config', 'get', 'registry'], { encoding: 'utf8', stdio: 'pipe' }).trim();
167
- const latestVersion = execFileSync('npm', ['view', '@ia-ccun/code-agent-cli', 'version', '--registry=' + registry], { encoding: 'utf8', stdio: 'pipe' }).trim();
187
+ const registry = execFileSync("npm", ["config", "get", "registry"], {
188
+ encoding: "utf8",
189
+ stdio: "pipe",
190
+ }).trim();
191
+ const latestVersion = execFileSync(
192
+ "npm",
193
+ ["view", "@ia-ccun/code-agent-cli", "version", "--registry=" + registry],
194
+ { encoding: "utf8", stdio: "pipe" },
195
+ ).trim();
168
196
 
169
197
  // 比较版本号
170
- const localParts = localVersion.split('.').map(Number);
171
- const latestParts = latestVersion.split('.').map(Number);
172
- const needsUpdate = latestParts[0] > localParts[0] ||
173
- (latestParts[0] === localParts[0] && latestParts[1] > localParts[1]) ||
174
- (latestParts[0] === localParts[0] && latestParts[1] === localParts[1] && latestParts[2] > localParts[2]);
175
-
176
-
198
+ const localParts = localVersion.split(".").map(Number);
199
+ const latestParts = latestVersion.split(".").map(Number);
200
+ const needsUpdate =
201
+ latestParts[0] > localParts[0] ||
202
+ (latestParts[0] === localParts[0] && latestParts[1] > localParts[1]) ||
203
+ (latestParts[0] === localParts[0] &&
204
+ latestParts[1] === localParts[1] &&
205
+ latestParts[2] > localParts[2]);
177
206
 
178
207
  // 写入版本缓存
179
208
  try {
180
- const cacheDir = join(process.env.HOME || process.env.USERPROFILE, '.aicode-cli');
209
+ const cacheDir = join(
210
+ process.env.HOME || process.env.USERPROFILE,
211
+ ".aicode-cli",
212
+ );
181
213
  if (!existsSync(cacheDir)) {
182
214
  // 🔒 Security: Use execFileSync for mkdir instead of execSync
183
- execFileSync('mkdir', ['-p', cacheDir], { stdio: 'pipe' });
215
+ execFileSync("mkdir", ["-p", cacheDir], { stdio: "pipe" });
184
216
  }
185
217
  const cacheData = {
186
218
  localVersion,
187
219
  latestVersion,
188
220
  needsUpdate,
189
- timestamp: Date.now()
221
+ timestamp: Date.now(),
190
222
  };
191
223
  writeFileSync(versionCachePath, JSON.stringify(cacheData, null, 2));
192
- } catch (e) {
224
+ } catch {
193
225
  // 忽略缓存写入失败
194
226
  }
195
- } catch (e) {
227
+ } catch {
196
228
  // 忽略检查失败
197
229
  }
198
230
  }
199
231
  checkForUpdates();
200
232
 
201
- const piAgentPathUrl = new URL('../node_modules/@earendil-works/pi-coding-agent/dist/cli.js', import.meta.url);
233
+ const piAgentPathUrl = new URL(
234
+ "../node_modules/@earendil-works/pi-coding-agent/dist/cli.js",
235
+ import.meta.url,
236
+ );
202
237
  const piAgentPath = fileURLToPath(piAgentPathUrl); // 解码中文路径
203
238
 
204
239
  // 获取版本缓存文件路径
@@ -209,30 +244,37 @@ const env = {
209
244
  ...process.env,
210
245
  AICODE_CLI_CONFIG_DIR: config.configDir,
211
246
  AICODE_CLI_NAME: config.name,
212
- AICODE_CLI_VERSION: localVersion || '',
247
+ AICODE_CLI_VERSION: localVersion || "",
213
248
  AICODE_CLI_VERSION_CACHE: versionCachePath,
214
- PI_SKIP_VERSION_CHECK: '1',
215
- PI_OFFLINE: '1' // 禁用包更新检查
249
+ PI_SKIP_VERSION_CHECK: "1",
250
+ PI_OFFLINE: "1", // 禁用包更新检查
216
251
  };
217
252
 
218
253
  // 传递配置目录给 pi
219
- // pi 使用 AICODE_CLI_CODING_AGENT_DIR 环境变量 (基于 piConfig.name)
220
- // 确保使用完整的绝对路径
221
- const fullPath = join(process.env.HOME || process.env.USERPROFILE, config.configDir);
222
- const agentDir = join(fullPath, 'agent');
254
+ // pi 使用 ${APP_NAME.toUpperCase()}_CODING_AGENT_DIR 环境变量识别 agent 目录
255
+ // 注意 "aicode-cli".toUpperCase() = "AICODE-CLI"(连字符,不是下划线)
256
+ // 所以 pi 0.85+ 读的是 AICODE-CLI_CODING_AGENT_DIR(连字符),不是 AICODE_CLI_CODING_AGENT_DIR(下划线)
257
+ // 下划线版本保留向后兼容 0.80~0.84
258
+ const fullPath = join(
259
+ process.env.HOME || process.env.USERPROFILE,
260
+ config.configDir,
261
+ );
262
+ const agentDir = join(fullPath, "agent");
263
+ env["AICODE-CLI_CODING_AGENT_DIR"] = agentDir;
223
264
  env.AICODE_CLI_CODING_AGENT_DIR = agentDir;
265
+ env.PI_CODING_AGENT_DIR = agentDir;
224
266
 
225
267
  // 启动 pi-coding-agent
226
- const child = spawn('node', [piAgentPath, ...remainingArgs], {
227
- stdio: 'inherit',
228
- env
268
+ const child = spawn("node", [piAgentPath, ...remainingArgs], {
269
+ stdio: "inherit",
270
+ env,
229
271
  });
230
272
 
231
- child.on('exit', (code) => {
273
+ child.on("exit", (code) => {
232
274
  process.exit(code ?? 0);
233
275
  });
234
276
 
235
- child.on('error', (err) => {
236
- console.error('Failed to start agent:', err);
277
+ child.on("error", (err) => {
278
+ console.error("Failed to start agent:", err);
237
279
  process.exit(1);
238
280
  });