@ia-ccun/code-agent-cli 0.0.57-beta.2 → 0.0.58-beta.1
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.
- package/config/agent/models.json +27 -1
- package/package.json +5 -5
- package/scripts/postinstall.js +230 -155
- package/scripts/regression/cases/01-version-and-deps.sh +4 -6
- package/scripts/regression/cases/03-rpc-protocol.sh +28 -11
- package/scripts/regression/cases/04-prompt-stream.sh +23 -12
- package/scripts/regression/cases/07-pi-new-features.sh +2 -2
- package/scripts/regression/results/.last_pid +1 -1
- package/scripts/regression/results/.last_workdir +1 -1
- package/scripts/regression/results/02-extension-loading.log +14 -16
- package/scripts/regression/results/03-prompt-stream.log +30 -12
- package/scripts/regression/results/03-rpc-protocol.log +59 -20
- package/scripts/regression/results/04-slash-commands-and-skills.log +11 -12
- package/scripts/regression/results/05-tool-execution.log +5 -5
- package/scripts/regression/results/06-pi-new-features.log +24 -19
- package/scripts/regression/run-all.sh +26 -32
- package/config/agent/extensions/aicode-llm-provider.ts +0 -149
package/scripts/postinstall.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// Post-install script for aicode-cli
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
import {
|
|
5
|
+
existsSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
copyFileSync,
|
|
10
|
+
readdirSync,
|
|
11
|
+
statSync,
|
|
12
|
+
createWriteStream,
|
|
13
|
+
} from "fs";
|
|
14
|
+
import { symlink as fsSymlink } from "fs/promises";
|
|
15
|
+
import { join, dirname, relative } from "path";
|
|
16
|
+
import { homedir } from "os";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
import { spawn } from "child_process";
|
|
10
19
|
|
|
11
20
|
// Get __dirname equivalent for ES modules
|
|
12
21
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -15,8 +24,8 @@ const __dirname = dirname(__filename);
|
|
|
15
24
|
// ============================================================================
|
|
16
25
|
// Security Logger (inline for postinstall script)
|
|
17
26
|
// ============================================================================
|
|
18
|
-
const LOG_DIR = join(homedir(),
|
|
19
|
-
const SECURITY_LOG = join(LOG_DIR,
|
|
27
|
+
const LOG_DIR = join(homedir(), ".aicode-cli", "logs");
|
|
28
|
+
const SECURITY_LOG = join(LOG_DIR, "security.log");
|
|
20
29
|
|
|
21
30
|
function ensureLogDir() {
|
|
22
31
|
if (!existsSync(LOG_DIR)) {
|
|
@@ -24,7 +33,7 @@ function ensureLogDir() {
|
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
35
|
|
|
27
|
-
function logSecurity(event, details, level =
|
|
36
|
+
function logSecurity(event, details, level = "info") {
|
|
28
37
|
ensureLogDir();
|
|
29
38
|
const entry = {
|
|
30
39
|
timestamp: new Date().toISOString(),
|
|
@@ -34,15 +43,15 @@ function logSecurity(event, details, level = 'info') {
|
|
|
34
43
|
details,
|
|
35
44
|
pid: process.pid,
|
|
36
45
|
};
|
|
37
|
-
|
|
46
|
+
|
|
38
47
|
try {
|
|
39
|
-
const stream = createWriteStream(SECURITY_LOG, { flags:
|
|
40
|
-
stream.write(JSON.stringify(entry) +
|
|
48
|
+
const stream = createWriteStream(SECURITY_LOG, { flags: "a", mode: 0o600 });
|
|
49
|
+
stream.write(JSON.stringify(entry) + "\n");
|
|
41
50
|
stream.end();
|
|
42
51
|
} catch (e) {
|
|
43
52
|
// Ignore logging errors
|
|
44
53
|
}
|
|
45
|
-
|
|
54
|
+
|
|
46
55
|
if (process.env.DEBUG) {
|
|
47
56
|
console.error(`[🔒 安全] ${event}:`, details);
|
|
48
57
|
}
|
|
@@ -52,64 +61,86 @@ function logSecurity(event, details, level = 'info') {
|
|
|
52
61
|
// Main Installation Logic
|
|
53
62
|
// ============================================================================
|
|
54
63
|
|
|
55
|
-
console.log(
|
|
64
|
+
console.log("\n🚀 Setting up aicode-cli...");
|
|
56
65
|
|
|
57
66
|
// Record installation start
|
|
58
|
-
logSecurity(
|
|
59
|
-
version:
|
|
67
|
+
logSecurity("install_start", {
|
|
68
|
+
version: "0.0.51-beta.1",
|
|
60
69
|
homeDir: homedir(),
|
|
61
70
|
timestamp: new Date().toISOString(),
|
|
62
71
|
});
|
|
63
72
|
|
|
64
73
|
// Get the current user's home directory
|
|
65
74
|
const homeDir = homedir();
|
|
66
|
-
const aicodeCliDir = join(homeDir,
|
|
67
|
-
const piDir = join(homeDir,
|
|
75
|
+
const aicodeCliDir = join(homeDir, ".aicode-cli");
|
|
76
|
+
const piDir = join(homeDir, ".pi");
|
|
68
77
|
|
|
69
78
|
// ============================================================================
|
|
70
79
|
// Fix pi-coding-agent APP_NAME
|
|
71
80
|
// ============================================================================
|
|
72
|
-
const piAgentPackageJson = join(
|
|
81
|
+
const piAgentPackageJson = join(
|
|
82
|
+
__dirname,
|
|
83
|
+
"..",
|
|
84
|
+
"node_modules",
|
|
85
|
+
"@earendil-works",
|
|
86
|
+
"pi-coding-agent",
|
|
87
|
+
"package.json",
|
|
88
|
+
);
|
|
73
89
|
if (existsSync(piAgentPackageJson)) {
|
|
74
90
|
try {
|
|
75
|
-
const piPkg = JSON.parse(readFileSync(piAgentPackageJson,
|
|
91
|
+
const piPkg = JSON.parse(readFileSync(piAgentPackageJson, "utf-8"));
|
|
76
92
|
if (!piPkg.piConfig) {
|
|
77
93
|
piPkg.piConfig = {};
|
|
78
94
|
}
|
|
79
|
-
const oldName = piPkg.piConfig.name ||
|
|
80
|
-
piPkg.piConfig.name =
|
|
81
|
-
piPkg.piConfig.configDir =
|
|
82
|
-
writeFileSync(piAgentPackageJson, JSON.stringify(piPkg, null, 2) +
|
|
95
|
+
const oldName = piPkg.piConfig.name || "pi";
|
|
96
|
+
piPkg.piConfig.name = "aicode-cli";
|
|
97
|
+
piPkg.piConfig.configDir = ".aicode-cli";
|
|
98
|
+
writeFileSync(piAgentPackageJson, JSON.stringify(piPkg, null, 2) + "\n");
|
|
83
99
|
console.log(`✓ Updated pi-coding-agent app name: ${oldName} -> aicode-cli`);
|
|
84
|
-
|
|
85
|
-
logSecurity(
|
|
100
|
+
|
|
101
|
+
logSecurity("file_modified", {
|
|
86
102
|
file: piAgentPackageJson,
|
|
87
|
-
action:
|
|
88
|
-
changes: [
|
|
103
|
+
action: "Updated piConfig",
|
|
104
|
+
changes: ["name", "configDir"],
|
|
89
105
|
});
|
|
90
106
|
} catch (e) {
|
|
91
107
|
console.log(`⚠ Could not update pi-coding-agent config: ${e.message}`);
|
|
92
|
-
logSecurity(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
108
|
+
logSecurity(
|
|
109
|
+
"file_modified",
|
|
110
|
+
{
|
|
111
|
+
file: piAgentPackageJson,
|
|
112
|
+
action: "Update failed",
|
|
113
|
+
error: e.message,
|
|
114
|
+
},
|
|
115
|
+
"warn",
|
|
116
|
+
);
|
|
97
117
|
}
|
|
98
118
|
}
|
|
99
119
|
|
|
100
120
|
// Fix pi-coding-agent cli.js process.title
|
|
101
|
-
const piAgentCliJs = join(
|
|
121
|
+
const piAgentCliJs = join(
|
|
122
|
+
__dirname,
|
|
123
|
+
"..",
|
|
124
|
+
"node_modules",
|
|
125
|
+
"@earendil-works",
|
|
126
|
+
"pi-coding-agent",
|
|
127
|
+
"dist",
|
|
128
|
+
"cli.js",
|
|
129
|
+
);
|
|
102
130
|
if (existsSync(piAgentCliJs)) {
|
|
103
131
|
try {
|
|
104
|
-
let cliContent = readFileSync(piAgentCliJs,
|
|
132
|
+
let cliContent = readFileSync(piAgentCliJs, "utf-8");
|
|
105
133
|
if (cliContent.includes('process.title = "pi"')) {
|
|
106
|
-
cliContent = cliContent.replace(
|
|
134
|
+
cliContent = cliContent.replace(
|
|
135
|
+
/process\.title = "pi"/g,
|
|
136
|
+
'process.title = "aicode-cli"',
|
|
137
|
+
);
|
|
107
138
|
writeFileSync(piAgentCliJs, cliContent);
|
|
108
139
|
console.log(`✓ Updated pi-coding-agent process.title`);
|
|
109
|
-
|
|
110
|
-
logSecurity(
|
|
140
|
+
|
|
141
|
+
logSecurity("file_modified", {
|
|
111
142
|
file: piAgentCliJs,
|
|
112
|
-
action:
|
|
143
|
+
action: "Updated process.title",
|
|
113
144
|
});
|
|
114
145
|
}
|
|
115
146
|
} catch (e) {
|
|
@@ -118,18 +149,29 @@ if (existsSync(piAgentCliJs)) {
|
|
|
118
149
|
}
|
|
119
150
|
|
|
120
151
|
// Fix pi-coding-agent config.js APP_NAME default
|
|
121
|
-
const piAgentConfigJs = join(
|
|
152
|
+
const piAgentConfigJs = join(
|
|
153
|
+
__dirname,
|
|
154
|
+
"..",
|
|
155
|
+
"node_modules",
|
|
156
|
+
"@earendil-works",
|
|
157
|
+
"pi-coding-agent",
|
|
158
|
+
"dist",
|
|
159
|
+
"config.js",
|
|
160
|
+
);
|
|
122
161
|
if (existsSync(piAgentConfigJs)) {
|
|
123
162
|
try {
|
|
124
|
-
let configContent = readFileSync(piAgentConfigJs,
|
|
163
|
+
let configContent = readFileSync(piAgentConfigJs, "utf-8");
|
|
125
164
|
if (configContent.includes('pkg.piConfig?.name || "pi"')) {
|
|
126
|
-
configContent = configContent.replace(
|
|
165
|
+
configContent = configContent.replace(
|
|
166
|
+
/pkg\.piConfig\?\.name \|\| "pi"/g,
|
|
167
|
+
'pkg.piConfig?.name || "aicode-cli"',
|
|
168
|
+
);
|
|
127
169
|
writeFileSync(piAgentConfigJs, configContent);
|
|
128
170
|
console.log(`✓ Updated pi-coding-agent config.js APP_NAME`);
|
|
129
|
-
|
|
130
|
-
logSecurity(
|
|
171
|
+
|
|
172
|
+
logSecurity("file_modified", {
|
|
131
173
|
file: piAgentConfigJs,
|
|
132
|
-
action:
|
|
174
|
+
action: "Updated APP_NAME",
|
|
133
175
|
});
|
|
134
176
|
}
|
|
135
177
|
} catch (e) {
|
|
@@ -138,18 +180,27 @@ if (existsSync(piAgentConfigJs)) {
|
|
|
138
180
|
}
|
|
139
181
|
|
|
140
182
|
// Fix pi-coding-agent slash commands - change "Quit pi" to "Quit aicode-cli"
|
|
141
|
-
const slashCommandsJs = join(
|
|
183
|
+
const slashCommandsJs = join(
|
|
184
|
+
__dirname,
|
|
185
|
+
"..",
|
|
186
|
+
"node_modules",
|
|
187
|
+
"@earendil-works",
|
|
188
|
+
"pi-coding-agent",
|
|
189
|
+
"dist",
|
|
190
|
+
"core",
|
|
191
|
+
"slash-commands.js",
|
|
192
|
+
);
|
|
142
193
|
if (existsSync(slashCommandsJs)) {
|
|
143
194
|
try {
|
|
144
|
-
let content = readFileSync(slashCommandsJs,
|
|
145
|
-
if (content.includes(
|
|
146
|
-
content = content.replace(/Quit pi/g,
|
|
195
|
+
let content = readFileSync(slashCommandsJs, "utf-8");
|
|
196
|
+
if (content.includes("Quit pi")) {
|
|
197
|
+
content = content.replace(/Quit pi/g, "Quit aicode-cli");
|
|
147
198
|
writeFileSync(slashCommandsJs, content);
|
|
148
199
|
console.log(`✓ Updated slash command description`);
|
|
149
|
-
|
|
150
|
-
logSecurity(
|
|
200
|
+
|
|
201
|
+
logSecurity("file_modified", {
|
|
151
202
|
file: slashCommandsJs,
|
|
152
|
-
action:
|
|
203
|
+
action: "Updated slash commands",
|
|
153
204
|
});
|
|
154
205
|
}
|
|
155
206
|
} catch (e) {
|
|
@@ -164,7 +215,7 @@ if (!existsSync(aicodeCliDir)) {
|
|
|
164
215
|
}
|
|
165
216
|
|
|
166
217
|
// Create agent subdirectory
|
|
167
|
-
const agentDir = join(aicodeCliDir,
|
|
218
|
+
const agentDir = join(aicodeCliDir, "agent");
|
|
168
219
|
if (!existsSync(agentDir)) {
|
|
169
220
|
mkdirSync(agentDir, { recursive: true });
|
|
170
221
|
console.log(`✓ Created directory: ${agentDir}`);
|
|
@@ -182,7 +233,7 @@ function copyDirRecursive(src, dest) {
|
|
|
182
233
|
}
|
|
183
234
|
|
|
184
235
|
const files = readdirSync(src);
|
|
185
|
-
files.forEach(function(file) {
|
|
236
|
+
files.forEach(function (file) {
|
|
186
237
|
const srcPath = join(src, file);
|
|
187
238
|
const destPath = join(dest, file);
|
|
188
239
|
copyDirRecursive(srcPath, destPath);
|
|
@@ -203,13 +254,13 @@ function copyDirRecursive(src, dest) {
|
|
|
203
254
|
// Force copy directory recursively (always overwrite destination)
|
|
204
255
|
function forceCopyDirRecursive(src, dest) {
|
|
205
256
|
if (!existsSync(src)) return;
|
|
206
|
-
|
|
257
|
+
|
|
207
258
|
const stats = statSync(src);
|
|
208
259
|
if (stats.isDirectory()) {
|
|
209
260
|
if (!existsSync(dest)) {
|
|
210
261
|
mkdirSync(dest, { recursive: true });
|
|
211
262
|
}
|
|
212
|
-
readdirSync(src).forEach(file => {
|
|
263
|
+
readdirSync(src).forEach((file) => {
|
|
213
264
|
forceCopyDirRecursive(join(src, file), join(dest, file));
|
|
214
265
|
});
|
|
215
266
|
} else {
|
|
@@ -222,53 +273,54 @@ function forceCopyDirRecursive(src, dest) {
|
|
|
222
273
|
}
|
|
223
274
|
|
|
224
275
|
// Copy config.json if it doesn't exist
|
|
225
|
-
const packageConfigFile = join(__dirname,
|
|
226
|
-
const userConfigFile = join(aicodeCliDir,
|
|
276
|
+
const packageConfigFile = join(__dirname, "..", "config.json");
|
|
277
|
+
const userConfigFile = join(aicodeCliDir, "config.json");
|
|
227
278
|
if (existsSync(packageConfigFile) && !existsSync(userConfigFile)) {
|
|
228
|
-
console.log(
|
|
279
|
+
console.log(
|
|
280
|
+
`📁 Copying config.json from ${packageConfigFile} to ${userConfigFile}`,
|
|
281
|
+
);
|
|
229
282
|
copyFileSync(packageConfigFile, userConfigFile);
|
|
230
|
-
console.log(
|
|
283
|
+
console.log("✓ config.json copied successfully");
|
|
231
284
|
} else if (!existsSync(packageConfigFile)) {
|
|
232
|
-
console.log(
|
|
285
|
+
console.log("⚠ config.json not found in package");
|
|
233
286
|
}
|
|
234
287
|
|
|
235
288
|
// ============================================================================
|
|
236
289
|
// Files/folders that must be force-overwritten on every install
|
|
237
290
|
// ============================================================================
|
|
238
|
-
const packageConfigDir = join(__dirname,
|
|
291
|
+
const packageConfigDir = join(__dirname, "..", "config", "agent");
|
|
239
292
|
|
|
240
293
|
const FORCE_OVERWRITE_LIST = [
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
'skills/*/*/SKILL.md',
|
|
294
|
+
"APPEND_SYSTEM.md",
|
|
295
|
+
"SYSTEM.md",
|
|
296
|
+
"help.md",
|
|
297
|
+
"extensions/*.ts",
|
|
298
|
+
"prompts/*.md",
|
|
299
|
+
"skills/*/SKILL.md",
|
|
300
|
+
"skills/*/*/SKILL.md",
|
|
249
301
|
];
|
|
250
302
|
|
|
251
303
|
// Function to expand glob patterns
|
|
252
304
|
function expandGlob(pattern) {
|
|
253
305
|
const results = [];
|
|
254
|
-
|
|
255
|
-
if (pattern.includes(
|
|
256
|
-
const parts = pattern.split(
|
|
306
|
+
|
|
307
|
+
if (pattern.includes("*")) {
|
|
308
|
+
const parts = pattern.split("/");
|
|
257
309
|
let currentPaths = [packageConfigDir];
|
|
258
|
-
|
|
310
|
+
|
|
259
311
|
for (let i = 0; i < parts.length; i++) {
|
|
260
312
|
const part = parts[i];
|
|
261
313
|
const nextPaths = [];
|
|
262
314
|
const isLastPart = i === parts.length - 1;
|
|
263
|
-
const hasWildcard = part.includes(
|
|
264
|
-
|
|
315
|
+
const hasWildcard = part.includes("*");
|
|
316
|
+
|
|
265
317
|
for (const cp of currentPaths) {
|
|
266
318
|
if (!existsSync(cp)) continue;
|
|
267
|
-
|
|
319
|
+
|
|
268
320
|
if (hasWildcard) {
|
|
269
321
|
const entries = readdirSync(cp);
|
|
270
|
-
const regex = new RegExp(
|
|
271
|
-
|
|
322
|
+
const regex = new RegExp("^" + part.replace(/\*/g, ".*") + "$");
|
|
323
|
+
|
|
272
324
|
for (const entry of entries) {
|
|
273
325
|
if (regex.test(entry)) {
|
|
274
326
|
const fullPath = join(cp, entry);
|
|
@@ -289,7 +341,7 @@ function expandGlob(pattern) {
|
|
|
289
341
|
}
|
|
290
342
|
currentPaths = nextPaths;
|
|
291
343
|
}
|
|
292
|
-
|
|
344
|
+
|
|
293
345
|
for (const p of currentPaths) {
|
|
294
346
|
if (existsSync(p)) {
|
|
295
347
|
results.push(relative(packageConfigDir, p));
|
|
@@ -298,7 +350,7 @@ function expandGlob(pattern) {
|
|
|
298
350
|
} else {
|
|
299
351
|
results.push(pattern);
|
|
300
352
|
}
|
|
301
|
-
|
|
353
|
+
|
|
302
354
|
return results;
|
|
303
355
|
}
|
|
304
356
|
|
|
@@ -308,11 +360,11 @@ function forceOverwriteList(relativePaths) {
|
|
|
308
360
|
for (const relativePath of relativePaths) {
|
|
309
361
|
expandedPaths.push(...expandGlob(relativePath));
|
|
310
362
|
}
|
|
311
|
-
|
|
312
|
-
expandedPaths.forEach(relativePath => {
|
|
363
|
+
|
|
364
|
+
expandedPaths.forEach((relativePath) => {
|
|
313
365
|
const srcPath = join(packageConfigDir, relativePath);
|
|
314
366
|
const destPath = join(agentDir, relativePath);
|
|
315
|
-
|
|
367
|
+
|
|
316
368
|
if (existsSync(srcPath)) {
|
|
317
369
|
try {
|
|
318
370
|
const stats = statSync(srcPath);
|
|
@@ -331,7 +383,9 @@ function forceOverwriteList(relativePaths) {
|
|
|
331
383
|
console.log(`✓ Force overwritten: ${relativePath}`);
|
|
332
384
|
}
|
|
333
385
|
} catch (e) {
|
|
334
|
-
console.log(
|
|
386
|
+
console.log(
|
|
387
|
+
`⚠ Could not force overwrite ${relativePath}: ${e.message}`,
|
|
388
|
+
);
|
|
335
389
|
}
|
|
336
390
|
} else {
|
|
337
391
|
console.log(`⚠ Source path does not exist: ${relativePath}`);
|
|
@@ -341,66 +395,67 @@ function forceOverwriteList(relativePaths) {
|
|
|
341
395
|
|
|
342
396
|
// Copy config/agent contents to ~/.aicode-cli/agent
|
|
343
397
|
if (existsSync(packageConfigDir)) {
|
|
344
|
-
console.log(
|
|
398
|
+
console.log(
|
|
399
|
+
`📁 Syncing default config files to ${agentDir} (preserving user customizations)`,
|
|
400
|
+
);
|
|
345
401
|
|
|
346
402
|
copyDirRecursive(packageConfigDir, agentDir);
|
|
347
|
-
console.log(
|
|
403
|
+
console.log("✓ Default config files synced successfully");
|
|
348
404
|
|
|
349
405
|
if (FORCE_OVERWRITE_LIST.length > 0) {
|
|
350
406
|
forceOverwriteList(FORCE_OVERWRITE_LIST);
|
|
351
407
|
}
|
|
352
408
|
|
|
353
|
-
const extensionsDir = join(agentDir,
|
|
409
|
+
const extensionsDir = join(agentDir, "extensions");
|
|
354
410
|
if (existsSync(extensionsDir)) {
|
|
355
411
|
try {
|
|
356
|
-
const extFiles = readdirSync(extensionsDir).filter(f =>
|
|
412
|
+
const extFiles = readdirSync(extensionsDir).filter((f) =>
|
|
413
|
+
f.endsWith(".ts"),
|
|
414
|
+
);
|
|
357
415
|
if (extFiles.length > 0) {
|
|
358
|
-
console.log(
|
|
416
|
+
console.log(
|
|
417
|
+
`✓ Found ${extFiles.length} extension(s): ${extFiles.join(", ")}`,
|
|
418
|
+
);
|
|
359
419
|
}
|
|
360
420
|
} catch (e) {
|
|
361
421
|
// ignore
|
|
362
422
|
}
|
|
363
423
|
}
|
|
364
424
|
} else {
|
|
365
|
-
console.log(
|
|
425
|
+
console.log("⚠ Configuration directory not found in package");
|
|
366
426
|
}
|
|
367
427
|
|
|
368
428
|
// ============================================================================
|
|
369
429
|
// Reset User-Agent placeholder in models.json
|
|
370
430
|
// ============================================================================
|
|
371
|
-
const modelsPath = join(agentDir,
|
|
431
|
+
const modelsPath = join(agentDir, "models.json");
|
|
372
432
|
if (existsSync(modelsPath)) {
|
|
373
433
|
try {
|
|
374
|
-
let content = readFileSync(modelsPath,
|
|
434
|
+
let content = readFileSync(modelsPath, "utf-8");
|
|
375
435
|
try {
|
|
376
436
|
const config = JSON.parse(content);
|
|
377
437
|
for (const provider of Object.values(config.providers || {})) {
|
|
378
|
-
if (provider.headers && provider.headers[
|
|
379
|
-
const ua = provider.headers[
|
|
380
|
-
if (ua && ua.startsWith(
|
|
381
|
-
provider.headers[
|
|
438
|
+
if (provider.headers && provider.headers["User-Agent"]) {
|
|
439
|
+
const ua = provider.headers["User-Agent"];
|
|
440
|
+
if (ua && ua.startsWith("aicode-cli/")) {
|
|
441
|
+
provider.headers["User-Agent"] = "${VERSION}";
|
|
382
442
|
}
|
|
383
443
|
}
|
|
384
444
|
}
|
|
385
445
|
const newContent = JSON.stringify(config, null, 2);
|
|
386
|
-
|
|
446
|
+
|
|
387
447
|
if (newContent !== content) {
|
|
388
|
-
writeFileSync(modelsPath, newContent,
|
|
389
|
-
console.log(
|
|
390
|
-
|
|
391
|
-
logSecurity(
|
|
448
|
+
writeFileSync(modelsPath, newContent, "utf-8");
|
|
449
|
+
console.log("✓ Reset User-Agent placeholder in models.json");
|
|
450
|
+
|
|
451
|
+
logSecurity("file_modified", {
|
|
392
452
|
file: modelsPath,
|
|
393
|
-
action:
|
|
453
|
+
action: "Reset User-Agent placeholder",
|
|
394
454
|
});
|
|
395
455
|
}
|
|
396
456
|
} catch (e) {
|
|
397
457
|
console.log(`⚠ Could not reset User-Agent placeholder: ${e.message}`);
|
|
398
458
|
}
|
|
399
|
-
|
|
400
|
-
if (newContent !== content) {
|
|
401
|
-
writeFileSync(modelsPath, newContent, 'utf-8');
|
|
402
|
-
console.log('✓ Reset User-Agent placeholder in models.json');
|
|
403
|
-
}
|
|
404
459
|
} catch (e) {
|
|
405
460
|
console.log(`⚠ Could not reset User-Agent placeholder: ${e.message}`);
|
|
406
461
|
}
|
|
@@ -410,10 +465,10 @@ if (existsSync(modelsPath)) {
|
|
|
410
465
|
(async () => {
|
|
411
466
|
try {
|
|
412
467
|
if (!existsSync(piDir)) {
|
|
413
|
-
await fsSymlink(aicodeCliDir, piDir,
|
|
468
|
+
await fsSymlink(aicodeCliDir, piDir, "dir");
|
|
414
469
|
console.log(`✓ Created symbolic link: ${piDir} -> ${aicodeCliDir}`);
|
|
415
|
-
|
|
416
|
-
logSecurity(
|
|
470
|
+
|
|
471
|
+
logSecurity("symlink_create", {
|
|
417
472
|
target: piDir,
|
|
418
473
|
source: aicodeCliDir,
|
|
419
474
|
success: true,
|
|
@@ -422,20 +477,26 @@ if (existsSync(modelsPath)) {
|
|
|
422
477
|
console.log(`✓ ${piDir} already exists`);
|
|
423
478
|
}
|
|
424
479
|
} catch (e) {
|
|
425
|
-
if (e.code ===
|
|
480
|
+
if (e.code === "EEXIST") {
|
|
426
481
|
console.log(`✓ Symbolic link already exists: ${piDir}`);
|
|
427
482
|
} else {
|
|
428
483
|
console.log(`⚠ Could not create symbolic link: ${e.message}`);
|
|
429
|
-
console.log(
|
|
430
|
-
console.log(
|
|
431
|
-
console.log(
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
484
|
+
console.log("\n📌 To fix this, please run manually:");
|
|
485
|
+
console.log(" ln -s ~/.aicode-cli ~/.pi");
|
|
486
|
+
console.log(
|
|
487
|
+
"\n (If ~/.pi exists, run: rm -rf ~/.pi && ln -s ~/.aicode-cli ~/.pi)",
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
logSecurity(
|
|
491
|
+
"symlink_create",
|
|
492
|
+
{
|
|
493
|
+
target: piDir,
|
|
494
|
+
source: aicodeCliDir,
|
|
495
|
+
success: false,
|
|
496
|
+
error: e.message,
|
|
497
|
+
},
|
|
498
|
+
"warn",
|
|
499
|
+
);
|
|
439
500
|
}
|
|
440
501
|
}
|
|
441
502
|
})();
|
|
@@ -443,7 +504,7 @@ if (existsSync(modelsPath)) {
|
|
|
443
504
|
// Check and display models config
|
|
444
505
|
if (existsSync(modelsPath)) {
|
|
445
506
|
try {
|
|
446
|
-
const models = JSON.parse(readFileSync(modelsPath,
|
|
507
|
+
const models = JSON.parse(readFileSync(modelsPath, "utf-8"));
|
|
447
508
|
if (models.providers) {
|
|
448
509
|
const providerCount = Object.keys(models.providers).length;
|
|
449
510
|
console.log(`✓ Found ${providerCount} configured provider(s)`);
|
|
@@ -456,7 +517,7 @@ if (existsSync(modelsPath)) {
|
|
|
456
517
|
}
|
|
457
518
|
|
|
458
519
|
// Record installation complete
|
|
459
|
-
logSecurity(
|
|
520
|
+
logSecurity("install_complete", {
|
|
460
521
|
success: true,
|
|
461
522
|
aicodeCliDir,
|
|
462
523
|
agentDir,
|
|
@@ -467,51 +528,61 @@ logSecurity('install_complete', {
|
|
|
467
528
|
// Auto-install codegraph (optional dependency)
|
|
468
529
|
// ============================================================================
|
|
469
530
|
|
|
470
|
-
const CODEGRAPH_PKG =
|
|
531
|
+
const CODEGRAPH_PKG = "@colbymchenry/codegraph@0.9.7";
|
|
471
532
|
|
|
472
533
|
async function installCodegraph() {
|
|
473
534
|
return new Promise((resolve) => {
|
|
474
|
-
const child = spawn(
|
|
475
|
-
stdio:
|
|
476
|
-
shell: process.platform ===
|
|
535
|
+
const child = spawn("npm", ["i", "-g", CODEGRAPH_PKG], {
|
|
536
|
+
stdio: "pipe",
|
|
537
|
+
shell: process.platform === "win32",
|
|
477
538
|
});
|
|
478
|
-
|
|
479
|
-
let stderr =
|
|
480
|
-
|
|
481
|
-
child.stderr.on(
|
|
539
|
+
|
|
540
|
+
let stderr = "";
|
|
541
|
+
|
|
542
|
+
child.stderr.on("data", (data) => {
|
|
482
543
|
stderr += data.toString();
|
|
483
544
|
});
|
|
484
|
-
|
|
485
|
-
child.on(
|
|
545
|
+
|
|
546
|
+
child.on("close", (code) => {
|
|
486
547
|
if (code === 0) {
|
|
487
|
-
console.log(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
548
|
+
console.log(
|
|
549
|
+
"✓ Installed codegraph globally,See UniDoc《2026.5 aicode+codegraph 安装与使用》",
|
|
550
|
+
);
|
|
551
|
+
logSecurity("codegraph_install", {
|
|
552
|
+
package: CODEGRAPH_PKG,
|
|
553
|
+
success: true,
|
|
491
554
|
});
|
|
492
555
|
} else {
|
|
493
556
|
// 静默失败,不中断主流程
|
|
494
557
|
if (process.env.DEBUG) {
|
|
495
558
|
console.log(`⚠ Could not install codegraph: ${stderr.slice(0, 100)}`);
|
|
496
559
|
}
|
|
497
|
-
logSecurity(
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
560
|
+
logSecurity(
|
|
561
|
+
"codegraph_install",
|
|
562
|
+
{
|
|
563
|
+
package: CODEGRAPH_PKG,
|
|
564
|
+
success: false,
|
|
565
|
+
error: stderr.slice(0, 200),
|
|
566
|
+
},
|
|
567
|
+
"warn",
|
|
568
|
+
);
|
|
502
569
|
}
|
|
503
570
|
resolve();
|
|
504
571
|
});
|
|
505
|
-
|
|
506
|
-
child.on(
|
|
572
|
+
|
|
573
|
+
child.on("error", (err) => {
|
|
507
574
|
if (process.env.DEBUG) {
|
|
508
575
|
console.log(`⚠ Could not install codegraph: ${err.message}`);
|
|
509
576
|
}
|
|
510
|
-
logSecurity(
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
577
|
+
logSecurity(
|
|
578
|
+
"codegraph_install",
|
|
579
|
+
{
|
|
580
|
+
package: CODEGRAPH_PKG,
|
|
581
|
+
success: false,
|
|
582
|
+
error: err.message,
|
|
583
|
+
},
|
|
584
|
+
"warn",
|
|
585
|
+
);
|
|
515
586
|
resolve();
|
|
516
587
|
});
|
|
517
588
|
});
|
|
@@ -520,8 +591,12 @@ async function installCodegraph() {
|
|
|
520
591
|
// Execute codegraph installation
|
|
521
592
|
await installCodegraph();
|
|
522
593
|
|
|
523
|
-
console.log(
|
|
524
|
-
console.log(
|
|
525
|
-
console.log(
|
|
526
|
-
|
|
527
|
-
|
|
594
|
+
console.log("\n✨ Setup complete!");
|
|
595
|
+
console.log("📝 Configuration files are in ~/.aicode-cli/");
|
|
596
|
+
console.log(
|
|
597
|
+
"🔗 ~/.pi is linked to ~/.aicode-cli (ensuring model configs work)",
|
|
598
|
+
);
|
|
599
|
+
console.log("🚀 Run with: aicode-cli");
|
|
600
|
+
console.log(
|
|
601
|
+
"\n📖 For more information, see: https://www.npmjs.com/package/@ia-ccun/code-agent-cli",
|
|
602
|
+
);
|