jinzd-ai-cli 0.4.103 → 0.4.105
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/{agent-client-6GX6QQDU.js → agent-client-25TIQ6AP.js} +1 -0
- package/dist/{auth-MSUWO6SE.js → auth-SC6KHHI3.js} +1 -0
- package/dist/{batch-LNTG2IRQ.js → batch-NPK4USGH.js} +3 -2
- package/dist/{chat-index-W2UZ34ZI.js → chat-index-7OHUKJY5.js} +1 -0
- package/dist/{chat-index-QKFH7ZP6.js → chat-index-ADG2GPCC.js} +1 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/{chunk-SN56X6RE.js → chunk-B6NUQVYK.js} +1 -1
- package/dist/{chunk-VOWVIR2U.js → chunk-F7XJ67XB.js} +30 -112
- package/dist/chunk-HOSJZMQS.js +97 -0
- package/dist/{chunk-OVYOYUP7.js → chunk-LVX667WL.js} +89 -36
- package/dist/{chunk-JHPSWYO3.js → chunk-LX5FXZVP.js} +7 -4
- package/dist/chunk-PDX44BCA.js +11 -0
- package/dist/{chunk-RZWWODW7.js → chunk-RFKT3T5S.js} +199 -74
- package/dist/{chunk-DGXUO7D4.js → chunk-VOF6OTZB.js} +89 -39
- package/dist/constants-HK5BB5EZ.js +78 -0
- package/dist/electron-server.js +289 -129
- package/dist/{file-checkpoint-CGH6OJVI.js → file-checkpoint-UHSMHCRU.js} +1 -0
- package/dist/{file-checkpoint-NKBHGC7L.js → file-checkpoint-ZN7KE3TN.js} +1 -0
- package/dist/git-context-7KIP4X2V.js +12 -0
- package/dist/{hub-4YGZ4XHN.js → hub-5VFGLTHY.js} +3 -2
- package/dist/{hub-server-BYXNQGDY.js → hub-server-AUMVPNU6.js} +1 -0
- package/dist/index.js +98 -47
- package/dist/{indexer-C7QYYHSZ.js → indexer-XGY7XGJM.js} +1 -0
- package/dist/{indexer-O5FCGFBJ.js → indexer-Z6AQTGBK.js} +1 -0
- package/dist/project-trust-EBGHD7LE.js +67 -0
- package/dist/project-trust-IFM7FXEV.js +68 -0
- package/dist/{run-tests-SN74WT4Z.js → run-tests-IMVI43CZ.js} +2 -1
- package/dist/{run-tests-3YOJEN2Q.js → run-tests-VQ3YZB75.js} +3 -2
- package/dist/{semantic-3KJPAUW6.js → semantic-FR2ZSQLY.js} +1 -0
- package/dist/{semantic-YDRPPVWK.js → semantic-UFKVYKFE.js} +3 -2
- package/dist/{server-BG4WR6RF.js → server-XDBIWNRW.js} +9 -8
- package/dist/{server-TNPDHGQT.js → server-ZVY3CKTJ.js} +65 -28
- package/dist/{store-S24SPPDZ.js → store-JDEW743P.js} +1 -0
- package/dist/{store-247B3TAU.js → store-Q7NMUCPP.js} +1 -0
- package/dist/{task-orchestrator-MUIH3XBY.js → task-orchestrator-UEZOFXQX.js} +9 -8
- package/dist/{vector-store-NDUFLNGN.js → vector-store-AK6J3RIA.js} +1 -0
- package/dist/{vector-store-QARQ2P6D.js → vector-store-MCQ77OOJ.js} +1 -0
- package/package.json +1 -1
- package/dist/{chunk-KJLJPUY2.js → chunk-3BICTI5M.js} +3 -3
package/dist/electron-server.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-VOF6OTZB.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -51,12 +51,13 @@ import {
|
|
|
51
51
|
searchChatMemory
|
|
52
52
|
} from "./chunk-5S3PIG5O.js";
|
|
53
53
|
import "./chunk-JV5N65KN.js";
|
|
54
|
+
import "./chunk-3RG5ZIWI.js";
|
|
54
55
|
|
|
55
56
|
// src/web/server.ts
|
|
56
57
|
import express from "express";
|
|
57
58
|
import { createServer } from "http";
|
|
58
59
|
import { WebSocketServer } from "ws";
|
|
59
|
-
import { join as join15, dirname as dirname5, resolve as
|
|
60
|
+
import { join as join15, dirname as dirname5, resolve as resolve6, relative as relative3, sep as sep3 } from "path";
|
|
60
61
|
import { existsSync as existsSync22, readFileSync as readFileSync15, readdirSync as readdirSync11, statSync as statSync9, realpathSync } from "fs";
|
|
61
62
|
import { networkInterfaces } from "os";
|
|
62
63
|
|
|
@@ -512,11 +513,17 @@ function getDangerLevel(toolName, args) {
|
|
|
512
513
|
const cmd = String(args["command"] ?? "");
|
|
513
514
|
if (/\brm\s+[^\n]*(?:-\w*[rRfF]\w*|--recursive|--force)\b/.test(cmd)) return "destructive";
|
|
514
515
|
if (/\brm\s+\S/.test(cmd)) return "destructive";
|
|
515
|
-
if (/\brmdir\b|\bformat\b|\bmkfs\b/.test(cmd)) return "destructive";
|
|
516
|
-
if (/\
|
|
516
|
+
if (/\brmdir\b|\bformat\b|\bmkfs\b|\bdd\s+if=|\bshred\b|\bfdisk\b|\bparted\b/.test(cmd)) return "destructive";
|
|
517
|
+
if (/\bshutdown\b|\breboot\b|\bhalt\b|\bpoweroff\b/.test(cmd)) return "destructive";
|
|
518
|
+
if (/\bkill\s+-9\b|\bkillall\b/.test(cmd)) return "destructive";
|
|
519
|
+
if (/\bRemove-Item\b|\bri\s+\S/i.test(cmd)) return "destructive";
|
|
520
|
+
if (/\brd\s+\/s\b|\brmdir\s+\/s\b/i.test(cmd)) return "destructive";
|
|
517
521
|
if (/\bdel\s+\S/.test(cmd)) return "destructive";
|
|
518
|
-
if (/\
|
|
519
|
-
if (
|
|
522
|
+
if (/\bShutdown(-Computer)?\b|\bRestart-Computer\b/i.test(cmd)) return "destructive";
|
|
523
|
+
if (/(?:^|[\s|;&])>>?\s*\S/.test(cmd)) return "write";
|
|
524
|
+
if (/\btee\b|\bcp\b|\bmv\b|\bln\s+-s/.test(cmd)) return "write";
|
|
525
|
+
if (/\bchmod\b|\bchown\b/.test(cmd)) return "write";
|
|
526
|
+
if (/\bSet-Content\b|\bOut-File\b|\bAdd-Content\b|\bCopy-Item\b|\bMove-Item\b|\bSet-ItemProperty\b|\bNew-ItemProperty\b/i.test(cmd)) return "write";
|
|
520
527
|
return "safe";
|
|
521
528
|
}
|
|
522
529
|
if (toolName === "write_file") return "write";
|
|
@@ -4053,10 +4060,10 @@ function createCell(cellType, content) {
|
|
|
4053
4060
|
// src/tools/builtin/read-file.ts
|
|
4054
4061
|
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
4055
4062
|
function getSensitiveWarning(normalizedPath) {
|
|
4056
|
-
const
|
|
4063
|
+
const home2 = homedir2();
|
|
4057
4064
|
const p = normalizedPath.toLowerCase();
|
|
4058
4065
|
const base = basename(normalizedPath).toLowerCase();
|
|
4059
|
-
if (normalizedPath.startsWith(
|
|
4066
|
+
if (normalizedPath.startsWith(home2) && p.includes(".aicli") && base === "config.json") {
|
|
4060
4067
|
return "[\u26A0 Security Warning: This file contains API keys. Be careful not to share this content.]\n\n";
|
|
4061
4068
|
}
|
|
4062
4069
|
if (base === ".env" || base.startsWith(".env.") || base.endsWith(".env")) {
|
|
@@ -4550,8 +4557,14 @@ function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "co
|
|
|
4550
4557
|
if (rule.when) {
|
|
4551
4558
|
if (rule.when.dangerLevel && rule.when.dangerLevel !== dangerLevel) continue;
|
|
4552
4559
|
if (rule.when.pathPattern) {
|
|
4553
|
-
|
|
4554
|
-
|
|
4560
|
+
if (toolName === "bash" && rule.action === "auto-approve") {
|
|
4561
|
+
const cmd = String(args["command"] ?? "").trim();
|
|
4562
|
+
if (/[;&|`$<>]/.test(cmd) || /\$\(/.test(cmd)) continue;
|
|
4563
|
+
if (!cmd.startsWith(rule.when.pathPattern)) continue;
|
|
4564
|
+
} else {
|
|
4565
|
+
const path3 = String(args["path"] ?? args["command"] ?? "");
|
|
4566
|
+
if (!path3.includes(rule.when.pathPattern)) continue;
|
|
4567
|
+
}
|
|
4555
4568
|
}
|
|
4556
4569
|
}
|
|
4557
4570
|
return rule.action;
|
|
@@ -4958,7 +4971,7 @@ var ToolExecutor = class {
|
|
|
4958
4971
|
rl.resume();
|
|
4959
4972
|
process.stdout.write(prompt);
|
|
4960
4973
|
this.confirming = true;
|
|
4961
|
-
return new Promise((
|
|
4974
|
+
return new Promise((resolve7) => {
|
|
4962
4975
|
let completed = false;
|
|
4963
4976
|
const cleanup = (result) => {
|
|
4964
4977
|
if (completed) return;
|
|
@@ -4968,7 +4981,7 @@ var ToolExecutor = class {
|
|
|
4968
4981
|
rl.pause();
|
|
4969
4982
|
rlAny.output = savedOutput;
|
|
4970
4983
|
this.confirming = false;
|
|
4971
|
-
|
|
4984
|
+
resolve7(result);
|
|
4972
4985
|
};
|
|
4973
4986
|
const onLine = (line) => {
|
|
4974
4987
|
const trimmed = line.trim();
|
|
@@ -5138,7 +5151,7 @@ var ToolExecutor = class {
|
|
|
5138
5151
|
rl.resume();
|
|
5139
5152
|
process.stdout.write(color("Proceed? [y/N] (type y + Enter to confirm) "));
|
|
5140
5153
|
this.confirming = true;
|
|
5141
|
-
return new Promise((
|
|
5154
|
+
return new Promise((resolve7) => {
|
|
5142
5155
|
let completed = false;
|
|
5143
5156
|
const cleanup = (answer) => {
|
|
5144
5157
|
if (completed) return;
|
|
@@ -5148,7 +5161,7 @@ var ToolExecutor = class {
|
|
|
5148
5161
|
rl.pause();
|
|
5149
5162
|
rlAny.output = savedOutput;
|
|
5150
5163
|
this.confirming = false;
|
|
5151
|
-
|
|
5164
|
+
resolve7(answer === "y");
|
|
5152
5165
|
};
|
|
5153
5166
|
const onLine = (line) => {
|
|
5154
5167
|
const trimmed = line.trim();
|
|
@@ -5175,6 +5188,99 @@ var ToolExecutor = class {
|
|
|
5175
5188
|
}
|
|
5176
5189
|
};
|
|
5177
5190
|
|
|
5191
|
+
// src/tools/sensitive-paths.ts
|
|
5192
|
+
import { resolve as resolve3, sep as sep2, basename as basename2 } from "path";
|
|
5193
|
+
import { homedir as homedir3 } from "os";
|
|
5194
|
+
var home = homedir3();
|
|
5195
|
+
function norm(p) {
|
|
5196
|
+
const abs = resolve3(p);
|
|
5197
|
+
return process.platform === "win32" ? abs.toLowerCase() : abs;
|
|
5198
|
+
}
|
|
5199
|
+
function homeRel(p) {
|
|
5200
|
+
const abs = norm(p);
|
|
5201
|
+
const h = norm(home);
|
|
5202
|
+
if (abs === h) return ".";
|
|
5203
|
+
if (abs.startsWith(h + (process.platform === "win32" ? "\\" : "/"))) {
|
|
5204
|
+
return abs.slice(h.length + 1);
|
|
5205
|
+
}
|
|
5206
|
+
return null;
|
|
5207
|
+
}
|
|
5208
|
+
function classifyWritePath(path3) {
|
|
5209
|
+
if (!path3) return { sensitive: false };
|
|
5210
|
+
const abs = norm(path3);
|
|
5211
|
+
const base = basename2(abs);
|
|
5212
|
+
const rel = homeRel(path3);
|
|
5213
|
+
if (rel) {
|
|
5214
|
+
const shellRc = /* @__PURE__ */ new Set([
|
|
5215
|
+
".bashrc",
|
|
5216
|
+
".bash_profile",
|
|
5217
|
+
".bash_login",
|
|
5218
|
+
".profile",
|
|
5219
|
+
".zshrc",
|
|
5220
|
+
".zprofile",
|
|
5221
|
+
".zshenv",
|
|
5222
|
+
".zlogin",
|
|
5223
|
+
".kshrc",
|
|
5224
|
+
".cshrc",
|
|
5225
|
+
".tcshrc",
|
|
5226
|
+
".fish_config"
|
|
5227
|
+
]);
|
|
5228
|
+
if (shellRc.has(base)) {
|
|
5229
|
+
return { sensitive: true, reason: `shell startup file (${rel})` };
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
const sshDir = `${sep2}.ssh${sep2}`;
|
|
5233
|
+
if (abs.includes(sshDir.toLowerCase()) || abs.includes(sshDir)) {
|
|
5234
|
+
return { sensitive: true, reason: `SSH directory (${rel ?? abs})` };
|
|
5235
|
+
}
|
|
5236
|
+
const credPaths = [
|
|
5237
|
+
`${sep2}.aws${sep2}credentials`,
|
|
5238
|
+
`${sep2}.aws${sep2}config`,
|
|
5239
|
+
`${sep2}.gcp${sep2}`,
|
|
5240
|
+
`${sep2}.azure${sep2}`,
|
|
5241
|
+
`${sep2}.config${sep2}gcloud${sep2}`,
|
|
5242
|
+
`${sep2}.kube${sep2}config`,
|
|
5243
|
+
`${sep2}.docker${sep2}config.json`,
|
|
5244
|
+
`${sep2}.netrc`
|
|
5245
|
+
];
|
|
5246
|
+
for (const c of credPaths) {
|
|
5247
|
+
const lc = process.platform === "win32" ? c.toLowerCase() : c;
|
|
5248
|
+
if (abs.includes(lc)) return { sensitive: true, reason: `cloud/auth credential file (${rel ?? abs})` };
|
|
5249
|
+
}
|
|
5250
|
+
if (rel && (rel === ".aicli" || rel.startsWith(".aicli" + (process.platform === "win32" ? "\\" : "/")))) {
|
|
5251
|
+
if (base === "config.json" || base === "users.json") {
|
|
5252
|
+
return { sensitive: true, reason: `ai-cli internal config (${rel})` };
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
if (abs.includes(`${sep2}.git${sep2}hooks${sep2}`) || abs.includes(`${sep2}.git${sep2}hooks${sep2}`.toLowerCase())) {
|
|
5256
|
+
return { sensitive: true, reason: ".git/hooks/* \u2014 runs on next git operation" };
|
|
5257
|
+
}
|
|
5258
|
+
if (abs.includes(`${sep2}.git${sep2}config`) || abs.includes(`${sep2}.git${sep2}config`.toLowerCase())) {
|
|
5259
|
+
return { sensitive: true, reason: ".git/config \u2014 repository identity" };
|
|
5260
|
+
}
|
|
5261
|
+
if (process.platform !== "win32") {
|
|
5262
|
+
const sysPrefixes = ["/etc/", "/usr/bin/", "/usr/sbin/", "/bin/", "/sbin/", "/boot/"];
|
|
5263
|
+
for (const pre of sysPrefixes) {
|
|
5264
|
+
if (abs.startsWith(pre)) return { sensitive: true, reason: `system path (${pre})` };
|
|
5265
|
+
}
|
|
5266
|
+
} else {
|
|
5267
|
+
const winSys = ["c:\\windows\\system32\\", "c:\\windows\\syswow64\\", "c:\\program files\\", "c:\\program files (x86)\\"];
|
|
5268
|
+
for (const pre of winSys) {
|
|
5269
|
+
if (abs.startsWith(pre)) return { sensitive: true, reason: `system path (${pre})` };
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
if (abs.includes(`${sep2}cron.d${sep2}`) || abs.startsWith("/etc/cron") || abs.startsWith("/var/spool/cron/")) {
|
|
5273
|
+
return { sensitive: true, reason: "cron scheduling" };
|
|
5274
|
+
}
|
|
5275
|
+
if (rel && (rel.startsWith("Library/LaunchAgents/") || rel.startsWith("Library/LaunchDaemons/"))) {
|
|
5276
|
+
return { sensitive: true, reason: "macOS launch agent" };
|
|
5277
|
+
}
|
|
5278
|
+
return { sensitive: false };
|
|
5279
|
+
}
|
|
5280
|
+
var subAgentGuard = {
|
|
5281
|
+
active: false
|
|
5282
|
+
};
|
|
5283
|
+
|
|
5178
5284
|
// src/tools/builtin/write-file.ts
|
|
5179
5285
|
var writeFileTool = {
|
|
5180
5286
|
definition: {
|
|
@@ -5217,6 +5323,13 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
5217
5323
|
const encoding = args["encoding"] ?? "utf-8";
|
|
5218
5324
|
const appendMode = String(args["append"] ?? "false").toLowerCase() === "true";
|
|
5219
5325
|
if (!filePath) throw new ToolError("write_file", "path is required");
|
|
5326
|
+
const verdict = classifyWritePath(filePath);
|
|
5327
|
+
if (verdict.sensitive && subAgentGuard.active) {
|
|
5328
|
+
throw new ToolError(
|
|
5329
|
+
"write_file",
|
|
5330
|
+
`Refused: sub-agents cannot write to sensitive paths \u2014 ${verdict.reason}. If this is genuinely needed, ask the parent agent to perform the write so the user can approve it.`
|
|
5331
|
+
);
|
|
5332
|
+
}
|
|
5220
5333
|
undoStack.push(filePath, `write_file${appendMode ? " (append)" : ""}: ${filePath}`);
|
|
5221
5334
|
fileCheckpoints.snapshot(filePath, ToolExecutor.currentMessageIndex);
|
|
5222
5335
|
mkdirSync3(dirname2(filePath), { recursive: true });
|
|
@@ -5229,7 +5342,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
5229
5342
|
const mode = appendMode ? "appended" : "written";
|
|
5230
5343
|
void (async () => {
|
|
5231
5344
|
try {
|
|
5232
|
-
const { updateFile } = await import("./indexer-
|
|
5345
|
+
const { updateFile } = await import("./indexer-Z6AQTGBK.js");
|
|
5233
5346
|
await updateFile(process.cwd(), filePath);
|
|
5234
5347
|
} catch {
|
|
5235
5348
|
}
|
|
@@ -5601,6 +5714,13 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
5601
5714
|
const encoding = args["encoding"] ?? "utf-8";
|
|
5602
5715
|
if (!filePath) throw new ToolError("edit_file", "path is required");
|
|
5603
5716
|
if (!existsSync7(filePath)) throw new ToolError("edit_file", `File not found: ${filePath}`);
|
|
5717
|
+
const verdict = classifyWritePath(filePath);
|
|
5718
|
+
if (verdict.sensitive && subAgentGuard.active) {
|
|
5719
|
+
throw new ToolError(
|
|
5720
|
+
"edit_file",
|
|
5721
|
+
`Refused: sub-agents cannot edit sensitive paths \u2014 ${verdict.reason}. If this is genuinely needed, ask the parent agent to perform the edit so the user can approve it.`
|
|
5722
|
+
);
|
|
5723
|
+
}
|
|
5604
5724
|
const original = readFileSync6(filePath, encoding);
|
|
5605
5725
|
if (args["patch"] !== void 0) {
|
|
5606
5726
|
const patchText = String(args["patch"] ?? "");
|
|
@@ -5760,7 +5880,7 @@ function truncatePreview(str, maxLen = 80) {
|
|
|
5760
5880
|
|
|
5761
5881
|
// src/tools/builtin/list-dir.ts
|
|
5762
5882
|
import { readdirSync as readdirSync4, statSync as statSync3, existsSync as existsSync8 } from "fs";
|
|
5763
|
-
import { join as join3, basename as
|
|
5883
|
+
import { join as join3, basename as basename3 } from "path";
|
|
5764
5884
|
var listDirTool = {
|
|
5765
5885
|
definition: {
|
|
5766
5886
|
name: "list_dir",
|
|
@@ -5783,7 +5903,7 @@ var listDirTool = {
|
|
|
5783
5903
|
const dirPath = String(args["path"] ?? process.cwd());
|
|
5784
5904
|
const recursive = Boolean(args["recursive"] ?? false);
|
|
5785
5905
|
if (!existsSync8(dirPath)) {
|
|
5786
|
-
const targetName =
|
|
5906
|
+
const targetName = basename3(dirPath).toLowerCase();
|
|
5787
5907
|
const cwd = process.cwd();
|
|
5788
5908
|
const suggestions = [];
|
|
5789
5909
|
try {
|
|
@@ -6098,7 +6218,7 @@ function searchInFile(fullPath, displayPath, regex, contextLines, maxResults, re
|
|
|
6098
6218
|
|
|
6099
6219
|
// src/tools/builtin/glob-files.ts
|
|
6100
6220
|
import { readdirSync as readdirSync6, statSync as statSync5, existsSync as existsSync10 } from "fs";
|
|
6101
|
-
import { join as join5, relative as relative2, basename as
|
|
6221
|
+
import { join as join5, relative as relative2, basename as basename4 } from "path";
|
|
6102
6222
|
var globFilesTool = {
|
|
6103
6223
|
definition: {
|
|
6104
6224
|
name: "glob_files",
|
|
@@ -6214,7 +6334,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
6214
6334
|
collectMatchingFiles(fullPath, rootPath, regex, results, maxResults);
|
|
6215
6335
|
} else if (entry.isFile()) {
|
|
6216
6336
|
const relPath = relative2(rootPath, fullPath).replace(/\\/g, "/");
|
|
6217
|
-
if (regex.test(relPath) || regex.test(
|
|
6337
|
+
if (regex.test(relPath) || regex.test(basename4(relPath))) {
|
|
6218
6338
|
try {
|
|
6219
6339
|
const stat = statSync5(fullPath);
|
|
6220
6340
|
results.push({ relPath, absPath: fullPath, mtime: stat.mtimeMs });
|
|
@@ -6290,7 +6410,7 @@ var runInteractiveTool = {
|
|
|
6290
6410
|
PYTHONDONTWRITEBYTECODE: "1"
|
|
6291
6411
|
};
|
|
6292
6412
|
const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
|
|
6293
|
-
return new Promise((
|
|
6413
|
+
return new Promise((resolve7) => {
|
|
6294
6414
|
const child = spawn2(executable, cmdArgs.map(String), {
|
|
6295
6415
|
cwd: process.cwd(),
|
|
6296
6416
|
env,
|
|
@@ -6323,22 +6443,22 @@ var runInteractiveTool = {
|
|
|
6323
6443
|
setTimeout(writeNextLine, 400);
|
|
6324
6444
|
const timer = setTimeout(() => {
|
|
6325
6445
|
child.kill();
|
|
6326
|
-
|
|
6446
|
+
resolve7(`${prefixWarnings}[Timeout after ${timeout}ms]
|
|
6327
6447
|
${buildOutput(stdout, stderr)}`);
|
|
6328
6448
|
}, timeout);
|
|
6329
6449
|
child.on("close", (code) => {
|
|
6330
6450
|
clearTimeout(timer);
|
|
6331
6451
|
const output = buildOutput(stdout, stderr);
|
|
6332
6452
|
if (code !== 0 && code !== null) {
|
|
6333
|
-
|
|
6453
|
+
resolve7(`${prefixWarnings}Exit code ${code}:
|
|
6334
6454
|
${output}`);
|
|
6335
6455
|
} else {
|
|
6336
|
-
|
|
6456
|
+
resolve7(`${prefixWarnings}${output || "(no output)"}`);
|
|
6337
6457
|
}
|
|
6338
6458
|
});
|
|
6339
6459
|
child.on("error", (err) => {
|
|
6340
6460
|
clearTimeout(timer);
|
|
6341
|
-
|
|
6461
|
+
resolve7(
|
|
6342
6462
|
`${prefixWarnings}Failed to start process "${executable}": ${err.message}
|
|
6343
6463
|
Hint: On Windows, use the full path to the executable, e.g.:
|
|
6344
6464
|
C:\\Users\\Jinzd\\anaconda3\\envs\\python312\\python.exe`
|
|
@@ -6608,9 +6728,9 @@ Any of these triggers means use save_last_response, NOT write_file:
|
|
|
6608
6728
|
// src/tools/builtin/save-memory.ts
|
|
6609
6729
|
import { existsSync as existsSync11, statSync as statSync6, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5 } from "fs";
|
|
6610
6730
|
import { join as join6 } from "path";
|
|
6611
|
-
import { homedir as
|
|
6731
|
+
import { homedir as homedir4 } from "os";
|
|
6612
6732
|
function getMemoryFilePath() {
|
|
6613
|
-
return join6(
|
|
6733
|
+
return join6(homedir4(), CONFIG_DIR_NAME, MEMORY_FILE_NAME);
|
|
6614
6734
|
}
|
|
6615
6735
|
function formatTimestamp() {
|
|
6616
6736
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -6634,7 +6754,7 @@ var saveMemoryTool = {
|
|
|
6634
6754
|
const content = String(args["content"] ?? "").trim();
|
|
6635
6755
|
if (!content) throw new ToolError("save_memory", "content is required");
|
|
6636
6756
|
const memoryPath = getMemoryFilePath();
|
|
6637
|
-
const configDir = join6(
|
|
6757
|
+
const configDir = join6(homedir4(), CONFIG_DIR_NAME);
|
|
6638
6758
|
if (!existsSync11(configDir)) {
|
|
6639
6759
|
mkdirSync5(configDir, { recursive: true });
|
|
6640
6760
|
}
|
|
@@ -6689,7 +6809,7 @@ function promptUser(rl, question) {
|
|
|
6689
6809
|
console.log();
|
|
6690
6810
|
console.log(chalk4.cyan("\u2753 ") + chalk4.bold(question));
|
|
6691
6811
|
process.stdout.write(chalk4.cyan("> "));
|
|
6692
|
-
return new Promise((
|
|
6812
|
+
return new Promise((resolve7) => {
|
|
6693
6813
|
let completed = false;
|
|
6694
6814
|
const cleanup = (answer) => {
|
|
6695
6815
|
if (completed) return;
|
|
@@ -6699,7 +6819,7 @@ function promptUser(rl, question) {
|
|
|
6699
6819
|
rl.pause();
|
|
6700
6820
|
rlAny.output = savedOutput;
|
|
6701
6821
|
askUserContext.prompting = false;
|
|
6702
|
-
|
|
6822
|
+
resolve7(answer);
|
|
6703
6823
|
};
|
|
6704
6824
|
const onLine = (line) => {
|
|
6705
6825
|
cleanup(line);
|
|
@@ -7196,37 +7316,43 @@ var spawnAgentTool = {
|
|
|
7196
7316
|
if (!ctx.provider) {
|
|
7197
7317
|
throw new ToolError("spawn_agent", "provider not initialized (context not injected)");
|
|
7198
7318
|
}
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7319
|
+
const guardWasActive = subAgentGuard.active;
|
|
7320
|
+
subAgentGuard.active = true;
|
|
7321
|
+
try {
|
|
7322
|
+
if (singleTask) {
|
|
7323
|
+
const { content, usage } = await runSubAgent(singleTask, maxRounds, null, ctx);
|
|
7324
|
+
return [
|
|
7325
|
+
"## Sub-Agent Result",
|
|
7326
|
+
"",
|
|
7327
|
+
content,
|
|
7328
|
+
"",
|
|
7329
|
+
"---",
|
|
7330
|
+
`Token usage: ${usage.inputTokens} input, ${usage.outputTokens} output`
|
|
7331
|
+
].join("\n");
|
|
7332
|
+
}
|
|
7333
|
+
console.log();
|
|
7334
|
+
console.log(theme.toolCall(`\u{1F916} Spawning ${tasksArr.length} sub-agents in parallel...`));
|
|
7335
|
+
const results = await Promise.all(
|
|
7336
|
+
tasksArr.map((t, i) => runSubAgent(t, maxRounds, i + 1, ctx))
|
|
7337
|
+
);
|
|
7338
|
+
const totalIn = results.reduce((s, r) => s + r.usage.inputTokens, 0);
|
|
7339
|
+
const totalOut = results.reduce((s, r) => s + r.usage.outputTokens, 0);
|
|
7340
|
+
const lines = [`## Parallel Sub-Agent Results (${results.length} agents)`, ""];
|
|
7341
|
+
results.forEach((r, i) => {
|
|
7342
|
+
lines.push(`### Sub-Agent #${i + 1}`);
|
|
7343
|
+
lines.push(`**Task**: ${tasksArr[i].slice(0, 200)}${tasksArr[i].length > 200 ? "..." : ""}`);
|
|
7344
|
+
lines.push("");
|
|
7345
|
+
lines.push(r.content);
|
|
7346
|
+
lines.push("");
|
|
7347
|
+
lines.push(`*Tokens: ${r.usage.inputTokens} in / ${r.usage.outputTokens} out*`);
|
|
7348
|
+
lines.push("");
|
|
7349
|
+
});
|
|
7350
|
+
lines.push("---");
|
|
7351
|
+
lines.push(`Total token usage: ${totalIn} input, ${totalOut} output`);
|
|
7352
|
+
return lines.join("\n");
|
|
7353
|
+
} finally {
|
|
7354
|
+
subAgentGuard.active = guardWasActive;
|
|
7209
7355
|
}
|
|
7210
|
-
console.log();
|
|
7211
|
-
console.log(theme.toolCall(`\u{1F916} Spawning ${tasksArr.length} sub-agents in parallel...`));
|
|
7212
|
-
const results = await Promise.all(
|
|
7213
|
-
tasksArr.map((t, i) => runSubAgent(t, maxRounds, i + 1, ctx))
|
|
7214
|
-
);
|
|
7215
|
-
const totalIn = results.reduce((s, r) => s + r.usage.inputTokens, 0);
|
|
7216
|
-
const totalOut = results.reduce((s, r) => s + r.usage.outputTokens, 0);
|
|
7217
|
-
const lines = [`## Parallel Sub-Agent Results (${results.length} agents)`, ""];
|
|
7218
|
-
results.forEach((r, i) => {
|
|
7219
|
-
lines.push(`### Sub-Agent #${i + 1}`);
|
|
7220
|
-
lines.push(`**Task**: ${tasksArr[i].slice(0, 200)}${tasksArr[i].length > 200 ? "..." : ""}`);
|
|
7221
|
-
lines.push("");
|
|
7222
|
-
lines.push(r.content);
|
|
7223
|
-
lines.push("");
|
|
7224
|
-
lines.push(`*Tokens: ${r.usage.inputTokens} in / ${r.usage.outputTokens} out*`);
|
|
7225
|
-
lines.push("");
|
|
7226
|
-
});
|
|
7227
|
-
lines.push("---");
|
|
7228
|
-
lines.push(`Total token usage: ${totalIn} input, ${totalOut} output`);
|
|
7229
|
-
return lines.join("\n");
|
|
7230
7356
|
}
|
|
7231
7357
|
};
|
|
7232
7358
|
|
|
@@ -7691,7 +7817,7 @@ ${commitOutput.trim()}`;
|
|
|
7691
7817
|
// src/tools/builtin/notebook-edit.ts
|
|
7692
7818
|
import { readFileSync as readFileSync8, existsSync as existsSync13 } from "fs";
|
|
7693
7819
|
import { writeFile } from "fs/promises";
|
|
7694
|
-
import { resolve as
|
|
7820
|
+
import { resolve as resolve4, extname as extname2 } from "path";
|
|
7695
7821
|
var notebookEditTool = {
|
|
7696
7822
|
definition: {
|
|
7697
7823
|
name: "notebook_edit",
|
|
@@ -7740,7 +7866,7 @@ var notebookEditTool = {
|
|
|
7740
7866
|
if (!Number.isInteger(cellIndexRaw) || cellIndexRaw < 1) {
|
|
7741
7867
|
throw new ToolError("notebook_edit", "cell_index must be a positive integer (1-based)");
|
|
7742
7868
|
}
|
|
7743
|
-
const absPath =
|
|
7869
|
+
const absPath = resolve4(filePath);
|
|
7744
7870
|
if (extname2(absPath).toLowerCase() !== ".ipynb") {
|
|
7745
7871
|
throw new ToolError("notebook_edit", "path must point to a .ipynb file");
|
|
7746
7872
|
}
|
|
@@ -8512,7 +8638,7 @@ var McpClient = class {
|
|
|
8512
8638
|
// 内部方法:JSON-RPC 通信
|
|
8513
8639
|
// ══════════════════════════════════════════════════════════════════
|
|
8514
8640
|
sendRequest(method, params) {
|
|
8515
|
-
return new Promise((
|
|
8641
|
+
return new Promise((resolve7, reject) => {
|
|
8516
8642
|
if (!this.process?.stdin?.writable) {
|
|
8517
8643
|
return reject(new Error(`MCP server [${this.serverId}] stdin not writable`));
|
|
8518
8644
|
}
|
|
@@ -8536,7 +8662,7 @@ var McpClient = class {
|
|
|
8536
8662
|
this.pendingRequests.set(id, {
|
|
8537
8663
|
resolve: (result) => {
|
|
8538
8664
|
cleanup();
|
|
8539
|
-
|
|
8665
|
+
resolve7(result);
|
|
8540
8666
|
},
|
|
8541
8667
|
reject: (error) => {
|
|
8542
8668
|
cleanup();
|
|
@@ -8613,13 +8739,13 @@ var McpClient = class {
|
|
|
8613
8739
|
}
|
|
8614
8740
|
/** Promise 超时包装 */
|
|
8615
8741
|
withTimeout(promise, ms, label) {
|
|
8616
|
-
return new Promise((
|
|
8742
|
+
return new Promise((resolve7, reject) => {
|
|
8617
8743
|
const timer = setTimeout(() => {
|
|
8618
8744
|
reject(new Error(`MCP [${this.serverId}] ${label} timed out after ${ms}ms`));
|
|
8619
8745
|
}, ms);
|
|
8620
8746
|
promise.then((val) => {
|
|
8621
8747
|
clearTimeout(timer);
|
|
8622
|
-
|
|
8748
|
+
resolve7(val);
|
|
8623
8749
|
}).catch((err) => {
|
|
8624
8750
|
clearTimeout(timer);
|
|
8625
8751
|
reject(err);
|
|
@@ -8892,7 +9018,7 @@ import { join as join9 } from "path";
|
|
|
8892
9018
|
|
|
8893
9019
|
// src/skills/types.ts
|
|
8894
9020
|
import { readFileSync as readFileSync9 } from "fs";
|
|
8895
|
-
import { basename as
|
|
9021
|
+
import { basename as basename5 } from "path";
|
|
8896
9022
|
function parseSimpleYaml(yaml) {
|
|
8897
9023
|
const result = {};
|
|
8898
9024
|
for (const line of yaml.split("\n")) {
|
|
@@ -8921,7 +9047,7 @@ function parseSkillFile(filePath) {
|
|
|
8921
9047
|
if (!frontmatterMatch) {
|
|
8922
9048
|
return {
|
|
8923
9049
|
meta: {
|
|
8924
|
-
name:
|
|
9050
|
+
name: basename5(filePath, ".md"),
|
|
8925
9051
|
description: ""
|
|
8926
9052
|
},
|
|
8927
9053
|
content: raw.trim(),
|
|
@@ -8932,7 +9058,7 @@ function parseSkillFile(filePath) {
|
|
|
8932
9058
|
const parsed = parseSimpleYaml(yaml);
|
|
8933
9059
|
return {
|
|
8934
9060
|
meta: {
|
|
8935
|
-
name: parsed["name"] ??
|
|
9061
|
+
name: parsed["name"] ?? basename5(filePath, ".md"),
|
|
8936
9062
|
description: parsed["description"] ?? "",
|
|
8937
9063
|
tools: parsed["tools"] ? parseYamlArray(parsed["tools"]) : void 0
|
|
8938
9064
|
},
|
|
@@ -9086,33 +9212,33 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
9086
9212
|
}
|
|
9087
9213
|
/** Resolve a pending confirm from client response */
|
|
9088
9214
|
resolveConfirm(requestId, approved) {
|
|
9089
|
-
const
|
|
9090
|
-
if (
|
|
9215
|
+
const resolve7 = this.pendingConfirms.get(requestId);
|
|
9216
|
+
if (resolve7) {
|
|
9091
9217
|
this.clearPendingTimer(requestId);
|
|
9092
9218
|
this.pendingConfirms.delete(requestId);
|
|
9093
9219
|
this.confirming = false;
|
|
9094
|
-
|
|
9220
|
+
resolve7(approved);
|
|
9095
9221
|
}
|
|
9096
9222
|
}
|
|
9097
9223
|
/** Resolve a pending batch confirm from client response */
|
|
9098
9224
|
resolveBatchConfirm(requestId, decision) {
|
|
9099
|
-
const
|
|
9100
|
-
if (
|
|
9225
|
+
const resolve7 = this.pendingBatchConfirms.get(requestId);
|
|
9226
|
+
if (resolve7) {
|
|
9101
9227
|
this.clearPendingTimer(requestId);
|
|
9102
9228
|
this.pendingBatchConfirms.delete(requestId);
|
|
9103
9229
|
this.confirming = false;
|
|
9104
9230
|
if (decision === "all" || decision === "none") {
|
|
9105
|
-
|
|
9231
|
+
resolve7(decision);
|
|
9106
9232
|
} else {
|
|
9107
|
-
|
|
9233
|
+
resolve7(new Set(decision));
|
|
9108
9234
|
}
|
|
9109
9235
|
}
|
|
9110
9236
|
}
|
|
9111
9237
|
/** Cancel all pending confirms (e.g., on disconnect) */
|
|
9112
9238
|
cancelAll() {
|
|
9113
|
-
for (const
|
|
9239
|
+
for (const resolve7 of this.pendingConfirms.values()) resolve7(false);
|
|
9114
9240
|
this.pendingConfirms.clear();
|
|
9115
|
-
for (const
|
|
9241
|
+
for (const resolve7 of this.pendingBatchConfirms.values()) resolve7("none");
|
|
9116
9242
|
this.pendingBatchConfirms.clear();
|
|
9117
9243
|
this.confirming = false;
|
|
9118
9244
|
}
|
|
@@ -9188,8 +9314,8 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
9188
9314
|
diff: this.getDiffPreview(call)
|
|
9189
9315
|
};
|
|
9190
9316
|
this.send(msg);
|
|
9191
|
-
return new Promise((
|
|
9192
|
-
this.pendingConfirms.set(requestId,
|
|
9317
|
+
return new Promise((resolve7) => {
|
|
9318
|
+
this.pendingConfirms.set(requestId, resolve7);
|
|
9193
9319
|
this.pendingTimers.set(requestId, setTimeout(() => {
|
|
9194
9320
|
if (this.pendingConfirms.has(requestId)) {
|
|
9195
9321
|
this.resolveConfirm(requestId, false);
|
|
@@ -9213,8 +9339,8 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
9213
9339
|
files
|
|
9214
9340
|
};
|
|
9215
9341
|
this.send(msg);
|
|
9216
|
-
return new Promise((
|
|
9217
|
-
this.pendingBatchConfirms.set(requestId,
|
|
9342
|
+
return new Promise((resolve7) => {
|
|
9343
|
+
this.pendingBatchConfirms.set(requestId, resolve7);
|
|
9218
9344
|
this.pendingTimers.set(requestId, setTimeout(() => {
|
|
9219
9345
|
if (this.pendingBatchConfirms.has(requestId)) {
|
|
9220
9346
|
this.resolveBatchConfirm(requestId, "none");
|
|
@@ -9365,9 +9491,9 @@ import { join as join11 } from "path";
|
|
|
9365
9491
|
// src/repl/dev-state.ts
|
|
9366
9492
|
import { existsSync as existsSync17, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync as unlinkSync3, mkdirSync as mkdirSync8 } from "fs";
|
|
9367
9493
|
import { join as join10 } from "path";
|
|
9368
|
-
import { homedir as
|
|
9494
|
+
import { homedir as homedir5 } from "os";
|
|
9369
9495
|
function getDevStatePath() {
|
|
9370
|
-
return join10(
|
|
9496
|
+
return join10(homedir5(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
|
|
9371
9497
|
}
|
|
9372
9498
|
function loadDevState() {
|
|
9373
9499
|
const path3 = getDevStatePath();
|
|
@@ -9627,7 +9753,7 @@ function autoTrimSessionIfNeeded(session, sizeLimit = SESSION_SIZE_LIMIT) {
|
|
|
9627
9753
|
|
|
9628
9754
|
// src/web/session-handler.ts
|
|
9629
9755
|
import { existsSync as existsSync20, readFileSync as readFileSync13, appendFileSync as appendFileSync3, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, readdirSync as readdirSync9, statSync as statSync8, createWriteStream } from "fs";
|
|
9630
|
-
import { join as join13, resolve as
|
|
9756
|
+
import { join as join13, resolve as resolve5, dirname as dirname4 } from "path";
|
|
9631
9757
|
import { execSync as execSync3 } from "child_process";
|
|
9632
9758
|
|
|
9633
9759
|
// src/tools/git-context.ts
|
|
@@ -9861,10 +9987,10 @@ var SessionHandler = class _SessionHandler {
|
|
|
9861
9987
|
return;
|
|
9862
9988
|
}
|
|
9863
9989
|
case "ask_user_response": {
|
|
9864
|
-
const
|
|
9865
|
-
if (
|
|
9990
|
+
const resolve7 = this.pendingAskUser.get(msg.requestId);
|
|
9991
|
+
if (resolve7) {
|
|
9866
9992
|
this.pendingAskUser.delete(msg.requestId);
|
|
9867
|
-
|
|
9993
|
+
resolve7(msg.answer);
|
|
9868
9994
|
}
|
|
9869
9995
|
return;
|
|
9870
9996
|
}
|
|
@@ -9875,10 +10001,10 @@ var SessionHandler = class _SessionHandler {
|
|
|
9875
10001
|
case "memory_rebuild":
|
|
9876
10002
|
return this.handleMemoryRebuild(Boolean(msg.full));
|
|
9877
10003
|
case "auto_pause_response": {
|
|
9878
|
-
const
|
|
9879
|
-
if (
|
|
10004
|
+
const resolve7 = this.pendingAutoPause.get(msg.requestId);
|
|
10005
|
+
if (resolve7) {
|
|
9880
10006
|
this.pendingAutoPause.delete(msg.requestId);
|
|
9881
|
-
|
|
10007
|
+
resolve7({ action: msg.action, message: msg.message });
|
|
9882
10008
|
}
|
|
9883
10009
|
return;
|
|
9884
10010
|
}
|
|
@@ -9895,9 +10021,9 @@ var SessionHandler = class _SessionHandler {
|
|
|
9895
10021
|
onDisconnect() {
|
|
9896
10022
|
this.toolExecutor.cancelAll();
|
|
9897
10023
|
if (this.abortController) this.abortController.abort();
|
|
9898
|
-
for (const
|
|
10024
|
+
for (const resolve7 of this.pendingAskUser.values()) resolve7(null);
|
|
9899
10025
|
this.pendingAskUser.clear();
|
|
9900
|
-
for (const
|
|
10026
|
+
for (const resolve7 of this.pendingAutoPause.values()) resolve7({ action: "stop" });
|
|
9901
10027
|
this.pendingAutoPause.clear();
|
|
9902
10028
|
this.saveIfNeeded();
|
|
9903
10029
|
}
|
|
@@ -10281,8 +10407,9 @@ Details: ${errMsg.split("\n")[0]}
|
|
|
10281
10407
|
const alreadyWrote = hadPreviousWriteToolCalls(extraMessages);
|
|
10282
10408
|
if (hasWriteTools && !alreadyWrote && detectsHallucinatedFileOp(result.content) && round < maxToolRounds - 1) {
|
|
10283
10409
|
this.send({ type: "info", message: "\u26A0 Hallucinated completion detected, forcing retry..." });
|
|
10410
|
+
const reasoningField = result.reasoningContent ? { reasoning_content: result.reasoningContent } : this.currentProvider === "deepseek" ? { reasoning_content: "" } : {};
|
|
10284
10411
|
extraMessages.push(
|
|
10285
|
-
{ role: "assistant", content: result.content },
|
|
10412
|
+
{ role: "assistant", content: result.content, ...reasoningField },
|
|
10286
10413
|
{ role: "user", content: HALLUCINATION_CORRECTION_MESSAGE }
|
|
10287
10414
|
);
|
|
10288
10415
|
continue;
|
|
@@ -10390,8 +10517,8 @@ ${systemPromptVolatile}` : systemPrompt;
|
|
|
10390
10517
|
}
|
|
10391
10518
|
const toolSummary = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).map(([name, count]) => count > 1 ? `${name}\xD7${count}` : name).join(", ");
|
|
10392
10519
|
const requestId = `pause_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
10393
|
-
const pauseResp = await new Promise((
|
|
10394
|
-
this.pendingAutoPause.set(requestId,
|
|
10520
|
+
const pauseResp = await new Promise((resolve7) => {
|
|
10521
|
+
this.pendingAutoPause.set(requestId, resolve7);
|
|
10395
10522
|
this.send({
|
|
10396
10523
|
type: "auto_pause_request",
|
|
10397
10524
|
requestId,
|
|
@@ -10526,8 +10653,8 @@ ${summaryResult.content}`,
|
|
|
10526
10653
|
}
|
|
10527
10654
|
if (chunk.done) break;
|
|
10528
10655
|
}
|
|
10529
|
-
await new Promise((
|
|
10530
|
-
fileStream.end((err) => err ? reject(err) :
|
|
10656
|
+
await new Promise((resolve7, reject) => {
|
|
10657
|
+
fileStream.end((err) => err ? reject(err) : resolve7());
|
|
10531
10658
|
});
|
|
10532
10659
|
const lines = fullContent.split("\n").length;
|
|
10533
10660
|
const bytes = Buffer.byteLength(fullContent, "utf-8");
|
|
@@ -10542,7 +10669,7 @@ ${summaryResult.content}`,
|
|
|
10542
10669
|
} catch (err) {
|
|
10543
10670
|
if (fileStream) {
|
|
10544
10671
|
try {
|
|
10545
|
-
await new Promise((
|
|
10672
|
+
await new Promise((resolve7) => fileStream.end(() => resolve7()));
|
|
10546
10673
|
} catch {
|
|
10547
10674
|
}
|
|
10548
10675
|
}
|
|
@@ -11210,7 +11337,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11210
11337
|
break;
|
|
11211
11338
|
}
|
|
11212
11339
|
const sub = args[0]?.toLowerCase();
|
|
11213
|
-
const
|
|
11340
|
+
const resolve7 = (ref) => {
|
|
11214
11341
|
const r = session.resolveBranchRef(ref);
|
|
11215
11342
|
if (r.ok) return r.id;
|
|
11216
11343
|
if (r.reason === "ambiguous") {
|
|
@@ -11264,7 +11391,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11264
11391
|
this.send({ type: "error", message: "Usage: /branch switch <id|title>" });
|
|
11265
11392
|
break;
|
|
11266
11393
|
}
|
|
11267
|
-
const id =
|
|
11394
|
+
const id = resolve7(ref);
|
|
11268
11395
|
if (!id) break;
|
|
11269
11396
|
const ok = session.switchBranch(id);
|
|
11270
11397
|
if (ok) {
|
|
@@ -11284,7 +11411,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11284
11411
|
this.send({ type: "error", message: "Usage: /branch delete <id|title>" });
|
|
11285
11412
|
break;
|
|
11286
11413
|
}
|
|
11287
|
-
const id =
|
|
11414
|
+
const id = resolve7(ref);
|
|
11288
11415
|
if (!id) break;
|
|
11289
11416
|
const ok = session.deleteBranch(id);
|
|
11290
11417
|
if (ok) {
|
|
@@ -11303,7 +11430,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11303
11430
|
this.send({ type: "error", message: "Usage: /branch rename <id|title> <new title>" });
|
|
11304
11431
|
break;
|
|
11305
11432
|
}
|
|
11306
|
-
const id =
|
|
11433
|
+
const id = resolve7(ref);
|
|
11307
11434
|
if (!id) break;
|
|
11308
11435
|
const ok = session.renameBranch(id, title);
|
|
11309
11436
|
if (ok) {
|
|
@@ -11321,7 +11448,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11321
11448
|
this.send({ type: "error", message: "Usage: /branch diff <id|title>" });
|
|
11322
11449
|
break;
|
|
11323
11450
|
}
|
|
11324
|
-
const id =
|
|
11451
|
+
const id = resolve7(ref);
|
|
11325
11452
|
if (!id) break;
|
|
11326
11453
|
const d = session.diffBranches(id);
|
|
11327
11454
|
if (!d) {
|
|
@@ -11363,7 +11490,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11363
11490
|
this.send({ type: "error", message: "Usage: /branch cherry-pick <source-id|title> <msg-index>" });
|
|
11364
11491
|
break;
|
|
11365
11492
|
}
|
|
11366
|
-
const id =
|
|
11493
|
+
const id = resolve7(ref);
|
|
11367
11494
|
if (!id) break;
|
|
11368
11495
|
const idx = parseInt(idxStr, 10);
|
|
11369
11496
|
if (Number.isNaN(idx)) {
|
|
@@ -11389,9 +11516,9 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11389
11516
|
case "index": {
|
|
11390
11517
|
const sub = (args[0] ?? "status").toLowerCase();
|
|
11391
11518
|
const root = process.cwd();
|
|
11392
|
-
const { loadIndex: loadIndex2, clearIndex } = await import("./store-
|
|
11393
|
-
const { indexProject: indexProject2 } = await import("./indexer-
|
|
11394
|
-
const { loadVectorStore, clearVectorStore } = await import("./vector-store-
|
|
11519
|
+
const { loadIndex: loadIndex2, clearIndex } = await import("./store-Q7NMUCPP.js");
|
|
11520
|
+
const { indexProject: indexProject2 } = await import("./indexer-Z6AQTGBK.js");
|
|
11521
|
+
const { loadVectorStore, clearVectorStore } = await import("./vector-store-AK6J3RIA.js");
|
|
11395
11522
|
if (sub === "status") {
|
|
11396
11523
|
const idx = loadIndex2(root);
|
|
11397
11524
|
const vec = loadVectorStore(root);
|
|
@@ -11440,7 +11567,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11440
11567
|
message: `Building semantic index for ${idx.symbolCount} symbols\u2026 (first run downloads ~117 MB model)`
|
|
11441
11568
|
});
|
|
11442
11569
|
try {
|
|
11443
|
-
const { rebuildSemanticIndex } = await import("./semantic-
|
|
11570
|
+
const { rebuildSemanticIndex } = await import("./semantic-FR2ZSQLY.js");
|
|
11444
11571
|
const stats = await rebuildSemanticIndex(root);
|
|
11445
11572
|
const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
|
|
11446
11573
|
this.send({
|
|
@@ -11588,7 +11715,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11588
11715
|
if (rewindSub === "list" || !rewindSub) {
|
|
11589
11716
|
const lines = [`Conversation messages (${session.messages.length} total):
|
|
11590
11717
|
`];
|
|
11591
|
-
const cpIndices = (await import("./file-checkpoint-
|
|
11718
|
+
const cpIndices = (await import("./file-checkpoint-UHSMHCRU.js")).fileCheckpoints.getMessageIndices();
|
|
11592
11719
|
for (let i = 0; i < session.messages.length; i++) {
|
|
11593
11720
|
const m = session.messages[i];
|
|
11594
11721
|
const text = getContentText(m.content).replace(/\n/g, " ").slice(0, 60);
|
|
@@ -11604,7 +11731,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11604
11731
|
this.send({ type: "error", message: `Invalid message number: ${rewindSub}. Range: 1-${session.messages.length}` });
|
|
11605
11732
|
break;
|
|
11606
11733
|
}
|
|
11607
|
-
const { fileCheckpoints: fc } = await import("./file-checkpoint-
|
|
11734
|
+
const { fileCheckpoints: fc } = await import("./file-checkpoint-UHSMHCRU.js");
|
|
11608
11735
|
const rewindRemoved = session.messages.length - rewindN;
|
|
11609
11736
|
const rewindResult = fc.restoreToMessageIndex(rewindN);
|
|
11610
11737
|
session.messages = session.messages.slice(0, rewindN);
|
|
@@ -11627,7 +11754,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
11627
11754
|
case "test": {
|
|
11628
11755
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
11629
11756
|
try {
|
|
11630
|
-
const { executeTests } = await import("./run-tests-
|
|
11757
|
+
const { executeTests } = await import("./run-tests-IMVI43CZ.js");
|
|
11631
11758
|
const argStr = args.join(" ").trim();
|
|
11632
11759
|
let testArgs = {};
|
|
11633
11760
|
if (argStr) {
|
|
@@ -11812,7 +11939,7 @@ ${this.config.toFormattedJSON()}
|
|
|
11812
11939
|
};
|
|
11813
11940
|
checkLayer("Global", configDir);
|
|
11814
11941
|
checkLayer("Project", projectRoot);
|
|
11815
|
-
if (
|
|
11942
|
+
if (resolve5(cwd) !== resolve5(projectRoot)) {
|
|
11816
11943
|
checkLayer("Subdir", cwd);
|
|
11817
11944
|
}
|
|
11818
11945
|
layers.push("");
|
|
@@ -11883,7 +12010,7 @@ Use /add-dir remove to clear.` : "No directories added.\nUsage: /add-dir <path>
|
|
|
11883
12010
|
this.send({ type: "info", message: "\u2713 All added directories removed from context." });
|
|
11884
12011
|
break;
|
|
11885
12012
|
}
|
|
11886
|
-
const dirPath =
|
|
12013
|
+
const dirPath = resolve5(sub);
|
|
11887
12014
|
if (!existsSync20(dirPath)) {
|
|
11888
12015
|
this.send({ type: "error", message: `Directory not found: ${dirPath}` });
|
|
11889
12016
|
break;
|
|
@@ -12151,7 +12278,7 @@ Add .md files to create commands.` });
|
|
|
12151
12278
|
return;
|
|
12152
12279
|
}
|
|
12153
12280
|
try {
|
|
12154
|
-
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-
|
|
12281
|
+
const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-ADG2GPCC.js");
|
|
12155
12282
|
const loaded = loadChatIndex2();
|
|
12156
12283
|
if (!loaded || loaded.idx.chunks.length === 0) {
|
|
12157
12284
|
this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
|
|
@@ -12187,7 +12314,7 @@ Add .md files to create commands.` });
|
|
|
12187
12314
|
}
|
|
12188
12315
|
async handleMemoryStatus() {
|
|
12189
12316
|
try {
|
|
12190
|
-
const { getChatIndexStatus } = await import("./chat-index-
|
|
12317
|
+
const { getChatIndexStatus } = await import("./chat-index-ADG2GPCC.js");
|
|
12191
12318
|
const s = getChatIndexStatus();
|
|
12192
12319
|
this.send({
|
|
12193
12320
|
type: "memory_status",
|
|
@@ -12212,7 +12339,7 @@ Add .md files to create commands.` });
|
|
|
12212
12339
|
type: "info",
|
|
12213
12340
|
message: full ? "\u{1F9E0} Rebuilding chat memory index (this may take a while on first run \u2014 ~117 MB embedder)." : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
|
|
12214
12341
|
});
|
|
12215
|
-
const { buildChatIndex } = await import("./chat-index-
|
|
12342
|
+
const { buildChatIndex } = await import("./chat-index-ADG2GPCC.js");
|
|
12216
12343
|
const stats = await buildChatIndex({
|
|
12217
12344
|
full,
|
|
12218
12345
|
onProgress: (p) => {
|
|
@@ -12591,7 +12718,7 @@ If none found: "\u2705 No security vulnerabilities detected"`;
|
|
|
12591
12718
|
const projectRoot = gitRoot ?? cwd;
|
|
12592
12719
|
const projectCtx = this.findContextFile(projectRoot);
|
|
12593
12720
|
if (projectCtx) parts.push(projectCtx);
|
|
12594
|
-
if (
|
|
12721
|
+
if (resolve5(cwd) !== resolve5(projectRoot)) {
|
|
12595
12722
|
const localCtx = this.findContextFile(cwd);
|
|
12596
12723
|
if (localCtx) parts.push(localCtx);
|
|
12597
12724
|
}
|
|
@@ -12831,7 +12958,7 @@ function getModuleDir() {
|
|
|
12831
12958
|
}
|
|
12832
12959
|
} catch {
|
|
12833
12960
|
}
|
|
12834
|
-
return
|
|
12961
|
+
return resolve6(".");
|
|
12835
12962
|
}
|
|
12836
12963
|
async function startWebServer(options = {}) {
|
|
12837
12964
|
const port = options.port ?? 3e3;
|
|
@@ -12860,7 +12987,18 @@ async function startWebServer(options = {}) {
|
|
|
12860
12987
|
console.log(` Providers: ${availableProviders.map((p) => p.info.id).join(", ")}`);
|
|
12861
12988
|
let mcpManager = null;
|
|
12862
12989
|
const globalMcpServers = config.get("mcpServers") ?? {};
|
|
12863
|
-
const
|
|
12990
|
+
const projectMcpResolved = resolveProjectMcpPath();
|
|
12991
|
+
let projectMcpServers = {};
|
|
12992
|
+
if (projectMcpResolved) {
|
|
12993
|
+
const { checkTrust } = await import("./project-trust-EBGHD7LE.js");
|
|
12994
|
+
const verdict = checkTrust(config.getConfigDir(), projectMcpResolved);
|
|
12995
|
+
if (verdict.trusted) {
|
|
12996
|
+
projectMcpServers = loadProjectMcpConfig() ?? {};
|
|
12997
|
+
} else {
|
|
12998
|
+
console.log(` \u26A0 Project .mcp.json found at ${projectMcpResolved} but not trusted (${verdict.reason}).`);
|
|
12999
|
+
console.log(` Skipped to prevent unintended RCE. Run "aicli" then "/mcp trust-project" to approve.`);
|
|
13000
|
+
}
|
|
13001
|
+
}
|
|
12864
13002
|
const mergedMcpServers = { ...globalMcpServers, ...projectMcpServers };
|
|
12865
13003
|
if (Object.keys(mergedMcpServers).length > 0) {
|
|
12866
13004
|
mcpManager = new McpManager();
|
|
@@ -12955,6 +13093,17 @@ async function startWebServer(options = {}) {
|
|
|
12955
13093
|
});
|
|
12956
13094
|
app.use(express.json());
|
|
12957
13095
|
app.post("/api/auth/register", (req, res) => {
|
|
13096
|
+
const firstRun = !authManager.hasUsers();
|
|
13097
|
+
if (!firstRun) {
|
|
13098
|
+
const authHeader = req.headers.authorization;
|
|
13099
|
+
const token2 = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
13100
|
+
const cookieToken = parseCookie(req.headers.cookie ?? "")["aicli_token"];
|
|
13101
|
+
const effectiveToken = token2 ?? cookieToken;
|
|
13102
|
+
if (!effectiveToken || !authManager.verifyToken(effectiveToken)) {
|
|
13103
|
+
res.status(403).json({ error: "Registration is closed. Use `aicli user create` on the host to add users." });
|
|
13104
|
+
return;
|
|
13105
|
+
}
|
|
13106
|
+
}
|
|
12958
13107
|
const { username, password } = req.body ?? {};
|
|
12959
13108
|
if (!username || !password) {
|
|
12960
13109
|
res.status(400).json({ error: "Username and password required" });
|
|
@@ -12966,7 +13115,7 @@ async function startWebServer(options = {}) {
|
|
|
12966
13115
|
return;
|
|
12967
13116
|
}
|
|
12968
13117
|
const token = authManager.login(username, password);
|
|
12969
|
-
console.log(` \u2713 User registered via API: ${username}`);
|
|
13118
|
+
console.log(` \u2713 User registered via API: ${username}${firstRun ? " (first-run)" : ""}`);
|
|
12970
13119
|
res.cookie("aicli_token", token, { httpOnly: true, sameSite: "strict", maxAge: 7 * 24 * 3600 * 1e3 });
|
|
12971
13120
|
res.json({ success: true, token, username });
|
|
12972
13121
|
});
|
|
@@ -12975,9 +13124,9 @@ async function startWebServer(options = {}) {
|
|
|
12975
13124
|
const prefix = req.query.prefix || "";
|
|
12976
13125
|
const targetDir = join15(cwd, prefix);
|
|
12977
13126
|
try {
|
|
12978
|
-
const canonicalTarget = realpathSync(
|
|
12979
|
-
const canonicalCwd = realpathSync(
|
|
12980
|
-
if (!canonicalTarget.startsWith(canonicalCwd +
|
|
13127
|
+
const canonicalTarget = realpathSync(resolve6(targetDir));
|
|
13128
|
+
const canonicalCwd = realpathSync(resolve6(cwd));
|
|
13129
|
+
if (!canonicalTarget.startsWith(canonicalCwd + sep3) && canonicalTarget !== canonicalCwd) {
|
|
12981
13130
|
res.json({ files: [] });
|
|
12982
13131
|
return;
|
|
12983
13132
|
}
|
|
@@ -13034,7 +13183,7 @@ async function startWebServer(options = {}) {
|
|
|
13034
13183
|
try {
|
|
13035
13184
|
const canonicalFile = realpathSync(filePath);
|
|
13036
13185
|
const canonicalDir = realpathSync(histDir);
|
|
13037
|
-
if (!canonicalFile.startsWith(canonicalDir +
|
|
13186
|
+
if (!canonicalFile.startsWith(canonicalDir + sep3)) {
|
|
13038
13187
|
res.status(404).json({ error: "Session not found" });
|
|
13039
13188
|
return;
|
|
13040
13189
|
}
|
|
@@ -13055,11 +13204,11 @@ async function startWebServer(options = {}) {
|
|
|
13055
13204
|
return;
|
|
13056
13205
|
}
|
|
13057
13206
|
const cwd = process.cwd();
|
|
13058
|
-
const fullPath =
|
|
13207
|
+
const fullPath = resolve6(join15(cwd, filePath));
|
|
13059
13208
|
try {
|
|
13060
13209
|
const canonicalFull = realpathSync(fullPath);
|
|
13061
|
-
const canonicalCwd = realpathSync(
|
|
13062
|
-
if (!canonicalFull.startsWith(canonicalCwd +
|
|
13210
|
+
const canonicalCwd = realpathSync(resolve6(cwd));
|
|
13211
|
+
if (!canonicalFull.startsWith(canonicalCwd + sep3) && canonicalFull !== canonicalCwd) {
|
|
13063
13212
|
res.json({ error: "Access denied" });
|
|
13064
13213
|
return;
|
|
13065
13214
|
}
|
|
@@ -13193,6 +13342,10 @@ async function startWebServer(options = {}) {
|
|
|
13193
13342
|
if (parsed.type === "auth") {
|
|
13194
13343
|
const { action, username, password } = parsed;
|
|
13195
13344
|
if (action === "register") {
|
|
13345
|
+
if (authManager.hasUsers() && !authenticatedUser) {
|
|
13346
|
+
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Registration is closed. Use `aicli user create` on the host to add users." }));
|
|
13347
|
+
return;
|
|
13348
|
+
}
|
|
13196
13349
|
const err = authManager.register(username, password);
|
|
13197
13350
|
if (err) {
|
|
13198
13351
|
ws.send(JSON.stringify({ type: "auth_result", success: false, error: err }));
|
|
@@ -13272,7 +13425,7 @@ async function startWebServer(options = {}) {
|
|
|
13272
13425
|
});
|
|
13273
13426
|
const MAX_PORT_ATTEMPTS = 10;
|
|
13274
13427
|
let actualPort = port;
|
|
13275
|
-
const result = await new Promise((
|
|
13428
|
+
const result = await new Promise((resolve7, reject) => {
|
|
13276
13429
|
const tryListen = (attempt) => {
|
|
13277
13430
|
server.once("error", (err) => {
|
|
13278
13431
|
if (err.code === "EADDRINUSE" && attempt < MAX_PORT_ATTEMPTS) {
|
|
@@ -13303,7 +13456,7 @@ async function startWebServer(options = {}) {
|
|
|
13303
13456
|
}
|
|
13304
13457
|
console.log(` Press Ctrl+C to stop
|
|
13305
13458
|
`);
|
|
13306
|
-
|
|
13459
|
+
resolve7({ port: actualPort, host, url });
|
|
13307
13460
|
});
|
|
13308
13461
|
};
|
|
13309
13462
|
tryListen(1);
|
|
@@ -13319,6 +13472,13 @@ async function startWebServer(options = {}) {
|
|
|
13319
13472
|
});
|
|
13320
13473
|
return result;
|
|
13321
13474
|
}
|
|
13475
|
+
function resolveProjectMcpPath() {
|
|
13476
|
+
const cwd = process.cwd();
|
|
13477
|
+
const gitRoot = getGitRoot(cwd);
|
|
13478
|
+
const projectRoot = gitRoot ?? cwd;
|
|
13479
|
+
const configPath = join15(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
13480
|
+
return existsSync22(configPath) ? configPath : null;
|
|
13481
|
+
}
|
|
13322
13482
|
function loadProjectMcpConfig() {
|
|
13323
13483
|
const cwd = process.cwd();
|
|
13324
13484
|
const gitRoot = getGitRoot(cwd);
|