jinzd-ai-cli 0.4.307 → 0.4.308
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 -0
- package/THIRD_PARTY_NOTICES.md +3 -0
- package/dist/{agent-client-6GX6QQDU.js → agent-client-TIEAYZXV.js} +4 -1
- package/dist/{auth-PE3Z5OHS.js → auth-QTQNZ6IX.js} +2 -2
- package/dist/{batch-HMADXNOD.js → batch-S7XLEEOH.js} +3 -3
- package/dist/{chat-index-2D5GK2DB.js → chat-index-7CLR4CBG.js} +4 -3
- package/dist/{chat-index-DGUOUUQW.js → chat-index-RLVLQRRC.js} +3 -2
- package/dist/{chunk-SJFZPS65.js → chunk-2DYQDLLF.js} +1 -1
- package/dist/{chunk-VAV2IJ3R.js → chunk-2MNUMLN4.js} +1 -1
- package/dist/chunk-2XMUCC42.js +67 -0
- package/dist/{chunk-5GQL4TSZ.js → chunk-3537CQ5M.js} +2 -2
- package/dist/{chunk-OAXLMF3U.js → chunk-3YVNDYOY.js} +1 -1
- package/dist/{chunk-RYQBBEMM.js → chunk-4PR5AVJ5.js} +115 -19
- package/dist/{chunk-GHWZVPUV.js → chunk-6JHACXB3.js} +7 -5
- package/dist/{chunk-CIM2PV2F.js → chunk-7OHXFTZO.js} +2 -2
- package/dist/{chunk-IUVDZVZ4.js → chunk-AXTLYOA7.js} +24 -17
- package/dist/{chunk-XJOK5353.js → chunk-B3MPYI4E.js} +2 -2
- package/dist/{chunk-3CKJOTVM.js → chunk-BGZN4K7Q.js} +4 -4
- package/dist/chunk-BMLQPSHP.js +69 -0
- package/dist/{chunk-NRSYBKWA.js → chunk-C7CKDFJS.js} +1 -1
- package/dist/{chunk-NQJSPMY2.js → chunk-E2PNXNKI.js} +4 -4
- package/dist/chunk-FVXNEZEW.js +161 -0
- package/dist/{chunk-YKJO3SI4.js → chunk-G6DVGQ4I.js} +1 -1
- package/dist/{chunk-YFDQIUQ3.js → chunk-HC33C4U3.js} +18 -18
- package/dist/chunk-JJFJWD35.js +162 -0
- package/dist/{chunk-KRCYR46A.js → chunk-JJNUASMJ.js} +264 -55
- package/dist/{chunk-NYNSYLFY.js → chunk-JL44HGZC.js} +1 -1
- package/dist/{chunk-NUJTNH76.js → chunk-LBWKMTT3.js} +1 -1
- package/dist/{chunk-AHL6KOGM.js → chunk-LR3TGZWQ.js} +2 -2
- package/dist/{chunk-WQ3OMEC4.js → chunk-M6HLYG33.js} +1 -1
- package/dist/{chunk-I4GQRMFV.js → chunk-M6YV5KSS.js} +6 -4
- package/dist/{chunk-3TBXHLSC.js → chunk-NLK45GUS.js} +1 -1
- package/dist/{chunk-KBDKKHXB.js → chunk-O6CGOVD4.js} +2 -2
- package/dist/chunk-QMFMST2T.js +39 -0
- package/dist/{chunk-MI4SFZGX.js → chunk-RMEJR3AW.js} +5 -2
- package/dist/{chunk-UFW4S3RU.js → chunk-RVMCY6DP.js} +1 -1
- package/dist/{chunk-LF67HWWR.js → chunk-RWRZVQCB.js} +1 -1
- package/dist/chunk-SXIJLSVF.js +41 -0
- package/dist/chunk-TDQW2YHK.js +65 -0
- package/dist/{chunk-L2RJPVHV.js → chunk-TPTFV3Y6.js} +266 -512
- package/dist/{chunk-45UVJXFQ.js → chunk-W2UOVGRC.js} +1 -1
- package/dist/{chunk-VXEF2SWG.js → chunk-WT252ZDV.js} +2 -2
- package/dist/{chunk-4W6VDVQU.js → chunk-WVEIUSXE.js} +246 -56
- package/dist/{chunk-AQF6IXSR.js → chunk-YBZM7PHI.js} +4 -4
- package/dist/{ci-QD2Q7NWY.js → ci-5HONSUAS.js} +7 -7
- package/dist/{ci-format-42XIZO5P.js → ci-format-URUH3ZZ5.js} +2 -2
- package/dist/{constants-NMASHFDL.js → constants-BLDBI7IG.js} +1 -1
- package/dist/{constants-5CMEFZQB.js → constants-FG27DQMS.js} +1 -1
- package/dist/doctor-cli-QQLMNJN7.js +18 -0
- package/dist/electron-server.js +886 -828
- package/dist/file-checkpoint-64A2AXHE.js +7 -0
- package/dist/{file-checkpoint-NKBHGC7L.js → file-checkpoint-VVPUJNCI.js} +2 -1
- package/dist/{hub-ZLF6GMQD.js → hub-GGFW3DCC.js} +3 -3
- package/dist/{hub-server-CBKCP5VD.js → hub-server-JLC7CNP7.js} +55 -17
- package/dist/index.js +42 -40
- package/dist/{indexer-P3FPRTPJ.js → indexer-GKIWSSRP.js} +3 -3
- package/dist/indexer-VRXDZ74A.js +10 -0
- package/dist/{persist-S77WRVLD.js → persist-ZZXRWFBX.js} +4 -4
- package/dist/{persistent-memory-GJE7HKVK.js → persistent-memory-UNLCXUWH.js} +3 -3
- package/dist/{persistent-memory-MBSBTBGY.js → persistent-memory-YYWIN6BG.js} +3 -3
- package/dist/{pr-SXRW24JG.js → pr-YCFGPFI7.js} +7 -7
- package/dist/{project-trust-MUG325AW.js → project-trust-6CJB5ZMX.js} +1 -1
- package/dist/{project-trust-NKYHL3VZ.js → project-trust-KGG2BWKC.js} +1 -1
- package/dist/run-tests-GHY4BYDE.js +13 -0
- package/dist/run-tests-KRNMFXAN.js +12 -0
- package/dist/{semantic-7GM5M4MU.js → semantic-N227CLSC.js} +4 -4
- package/dist/{semantic-QOBAXEQ4.js → semantic-TRQAZSRY.js} +4 -4
- package/dist/{server-MO3EU2XD.js → server-73UBHSFV.js} +16 -14
- package/dist/{server-GGEO7SA2.js → server-QRAWSG4Z.js} +231 -103
- package/dist/{store-SIKHCUYJ.js → store-2N6PPPBP.js} +2 -2
- package/dist/{store-CMSSWZF7.js → store-76VVFDXM.js} +2 -2
- package/dist/{task-orchestrator-JGEEQ2OE.js → task-orchestrator-GI3RGLZI.js} +15 -14
- package/dist/{usage-B7RIAPPT.js → usage-GWTIGZF5.js} +4 -4
- package/dist/{vector-store-JAXWDZYW.js → vector-store-T2DVUMY4.js} +2 -2
- package/dist/{vector-store-PWIOQFTP.js → vector-store-V6UGEYWK.js} +2 -2
- package/dist/web/client/app.js +7 -0
- package/dist/web/client/app.js.br +0 -0
- package/dist/web/client/app.js.gz +0 -0
- package/dist/web/client/util.js +14 -23
- package/dist/web/client/util.js.br +0 -0
- package/dist/web/client/util.js.gz +0 -0
- package/dist/web/client/vendor/DOMPurify-LICENSE.txt +202 -0
- package/dist/web/client/vendor/purify.es.mjs +2722 -0
- package/dist/web/client/vendor/purify.es.mjs.br +0 -0
- package/dist/web/client/vendor/purify.es.mjs.gz +0 -0
- package/package.json +4 -2
- package/dist/chunk-4BKXL7SM.js +0 -98
- package/dist/chunk-6BUTA5VW.js +0 -38
- package/dist/chunk-IW3Q7AE5.js +0 -40
- package/dist/chunk-SKET65WZ.js +0 -96
- package/dist/doctor-cli-IOVSHBDI.js +0 -18
- package/dist/file-checkpoint-CGH6OJVI.js +0 -6
- package/dist/indexer-FPKY7LCT.js +0 -10
- package/dist/run-tests-EQCAMFQE.js +0 -10
- package/dist/run-tests-V3N7YV3P.js +0 -9
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
loadChatIndex,
|
|
4
4
|
searchChatMemory
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-6JHACXB3.js";
|
|
6
6
|
import {
|
|
7
7
|
addMemoryEntry,
|
|
8
8
|
findSimilarMemory,
|
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
searchPersistentMemories,
|
|
12
12
|
touchMemoryReferences,
|
|
13
13
|
updateMemoryEntry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-LR3TGZWQ.js";
|
|
15
15
|
import {
|
|
16
16
|
indexProject
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-RWRZVQCB.js";
|
|
18
18
|
import {
|
|
19
19
|
hasSemanticIndex,
|
|
20
20
|
semanticSearch
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-B3MPYI4E.js";
|
|
22
22
|
import {
|
|
23
23
|
loadIndex
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-M6HLYG33.js";
|
|
25
25
|
import {
|
|
26
26
|
theme
|
|
27
27
|
} from "./chunk-5C76XDDF.js";
|
|
@@ -30,13 +30,13 @@ import {
|
|
|
30
30
|
runHook,
|
|
31
31
|
runLifecycleHooks,
|
|
32
32
|
runTool
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-3537CQ5M.js";
|
|
34
34
|
import {
|
|
35
35
|
buildTruncatedArgumentsError,
|
|
36
36
|
getDangerLevel,
|
|
37
37
|
isFileWriteTool,
|
|
38
38
|
runLeanAgentLoop
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-RMEJR3AW.js";
|
|
40
40
|
import {
|
|
41
41
|
EnvLoader,
|
|
42
42
|
NetworkError,
|
|
@@ -44,13 +44,26 @@ import {
|
|
|
44
44
|
} from "./chunk-TU3L3PW7.js";
|
|
45
45
|
import {
|
|
46
46
|
atomicWriteFileSync
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-BMLQPSHP.js";
|
|
48
48
|
import {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
MAX_SNAPSHOT_TOTAL_BYTES,
|
|
50
|
+
assertReadablePath,
|
|
51
|
+
canonicalPath,
|
|
52
|
+
fileCheckpoints,
|
|
53
|
+
isCredentialVault,
|
|
54
|
+
readSnapshot
|
|
55
|
+
} from "./chunk-JJFJWD35.js";
|
|
51
56
|
import {
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
IS_WINDOWS,
|
|
58
|
+
WIN_UTF8_PREAMBLE,
|
|
59
|
+
currentAbortSignal,
|
|
60
|
+
decodeWindowsBuffer,
|
|
61
|
+
killProcessTree,
|
|
62
|
+
looksLikeGbkMojibake,
|
|
63
|
+
recoverGbkMojibake,
|
|
64
|
+
runTestsTool,
|
|
65
|
+
shellInvocation
|
|
66
|
+
} from "./chunk-JJNUASMJ.js";
|
|
54
67
|
import {
|
|
55
68
|
CONFIG_DIR_NAME,
|
|
56
69
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -59,170 +72,25 @@ import {
|
|
|
59
72
|
SUBAGENT_ALLOWED_TOOLS,
|
|
60
73
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
61
74
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
62
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-2MNUMLN4.js";
|
|
76
|
+
import {
|
|
77
|
+
getCurrentSessionKey,
|
|
78
|
+
getExecutionConfigDir,
|
|
79
|
+
runWithSessionKey,
|
|
80
|
+
scopedState
|
|
81
|
+
} from "./chunk-SXIJLSVF.js";
|
|
63
82
|
|
|
64
83
|
// src/tools/shell-pool.ts
|
|
65
|
-
import { spawn as spawn2 } from "child_process";
|
|
66
|
-
import { platform as platform2 } from "os";
|
|
67
|
-
|
|
68
|
-
// src/tools/win-shell.ts
|
|
69
|
-
import { platform } from "os";
|
|
70
84
|
import { spawn } from "child_process";
|
|
71
|
-
|
|
72
|
-
var
|
|
73
|
-
function shellInvocation(command) {
|
|
74
|
-
if (IS_WINDOWS) {
|
|
75
|
-
return {
|
|
76
|
-
shell: "powershell.exe",
|
|
77
|
-
args: ["-NoProfile", "-NonInteractive", "-Command", WIN_UTF8_PREAMBLE + command]
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
return { shell: process.env["SHELL"] ?? "/bin/bash", args: ["-c", command] };
|
|
81
|
-
}
|
|
82
|
-
function decodeWindowsBuffer(buf) {
|
|
83
|
-
const utf8 = buf.toString("utf-8");
|
|
84
|
-
if (!utf8.includes("\uFFFD")) return utf8;
|
|
85
|
-
try {
|
|
86
|
-
return new TextDecoder("gbk").decode(buf);
|
|
87
|
-
} catch {
|
|
88
|
-
return utf8;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
var GBK_MOJIBAKE_FINGERPRINTS = [
|
|
92
|
-
"\uFFFD",
|
|
93
|
-
"\u9215",
|
|
94
|
-
"\u951B",
|
|
95
|
-
"\u9983",
|
|
96
|
-
"\u9241",
|
|
97
|
-
"\u6D93",
|
|
98
|
-
"\u935B",
|
|
99
|
-
"\u9428",
|
|
100
|
-
"\u7EFE",
|
|
101
|
-
"\u95AB",
|
|
102
|
-
"\u9593",
|
|
103
|
-
"\u95BF",
|
|
104
|
-
"\u68E3",
|
|
105
|
-
"\u95B4",
|
|
106
|
-
"\u5A11",
|
|
107
|
-
"\u95B8",
|
|
108
|
-
"\u95BB",
|
|
109
|
-
"\u7F01",
|
|
110
|
-
"\u95C1"
|
|
111
|
-
];
|
|
112
|
-
var gbkReverse = null;
|
|
113
|
-
function gbkReverseMap() {
|
|
114
|
-
if (gbkReverse) return gbkReverse;
|
|
115
|
-
const map = /* @__PURE__ */ new Map();
|
|
116
|
-
try {
|
|
117
|
-
const dec = new TextDecoder("gbk");
|
|
118
|
-
for (let hi = 129; hi <= 254; hi++) {
|
|
119
|
-
for (let lo = 64; lo <= 254; lo++) {
|
|
120
|
-
if (lo === 127) continue;
|
|
121
|
-
const ch = dec.decode(new Uint8Array([hi, lo]));
|
|
122
|
-
if (ch.length === 1 && ch !== "\uFFFD" && !map.has(ch)) map.set(ch, [hi, lo]);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
} catch {
|
|
126
|
-
}
|
|
127
|
-
gbkReverse = map;
|
|
128
|
-
return map;
|
|
129
|
-
}
|
|
130
|
-
function decodeRunAsChinese(bytes) {
|
|
131
|
-
for (let start = 0; start <= 2 && start < bytes.length; start++) {
|
|
132
|
-
for (let end = 0; end <= 2 && bytes.length - end > start; end++) {
|
|
133
|
-
const slice = bytes.slice(start, bytes.length - end);
|
|
134
|
-
if (slice.length < 6) continue;
|
|
135
|
-
try {
|
|
136
|
-
const out = new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array(slice));
|
|
137
|
-
if (/[一-鿿]/.test(out)) return out;
|
|
138
|
-
} catch {
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
function recoverGbkMojibake(text) {
|
|
145
|
-
if (!text) return null;
|
|
146
|
-
const map = gbkReverseMap();
|
|
147
|
-
if (map.size === 0) return null;
|
|
148
|
-
let run = [];
|
|
149
|
-
let best = null;
|
|
150
|
-
const flush = () => {
|
|
151
|
-
if (run.length >= 4) {
|
|
152
|
-
const bytes = [];
|
|
153
|
-
for (const p of run) bytes.push(p[0], p[1]);
|
|
154
|
-
const out = decodeRunAsChinese(bytes);
|
|
155
|
-
if (out && (!best || out.length > best.length)) best = out;
|
|
156
|
-
}
|
|
157
|
-
run = [];
|
|
158
|
-
};
|
|
159
|
-
for (const ch of text) {
|
|
160
|
-
const pair = ch.codePointAt(0) < 128 ? void 0 : map.get(ch);
|
|
161
|
-
if (pair) run.push(pair);
|
|
162
|
-
else flush();
|
|
163
|
-
}
|
|
164
|
-
flush();
|
|
165
|
-
return best;
|
|
166
|
-
}
|
|
167
|
-
function looksLikeGbkMojibake(text) {
|
|
168
|
-
if (recoverGbkMojibake(text) !== null) return true;
|
|
169
|
-
let hits = 0;
|
|
170
|
-
for (const ch of GBK_MOJIBAKE_FINGERPRINTS) {
|
|
171
|
-
if (text.includes(ch) && ++hits >= 2) return true;
|
|
172
|
-
}
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
function killProcessTree(proc) {
|
|
176
|
-
if (proc.killed || proc.exitCode !== null) return;
|
|
177
|
-
if (IS_WINDOWS && proc.pid) {
|
|
178
|
-
try {
|
|
179
|
-
const tk = spawn("taskkill", ["/PID", String(proc.pid), "/T", "/F"], {
|
|
180
|
-
windowsHide: true,
|
|
181
|
-
stdio: "ignore"
|
|
182
|
-
});
|
|
183
|
-
tk.on("exit", () => {
|
|
184
|
-
try {
|
|
185
|
-
proc.kill();
|
|
186
|
-
} catch {
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
tk.on("error", () => {
|
|
190
|
-
try {
|
|
191
|
-
proc.kill();
|
|
192
|
-
} catch {
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
} catch {
|
|
196
|
-
try {
|
|
197
|
-
proc.kill();
|
|
198
|
-
} catch {
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
try {
|
|
204
|
-
proc.kill("SIGTERM");
|
|
205
|
-
} catch {
|
|
206
|
-
}
|
|
207
|
-
setTimeout(() => {
|
|
208
|
-
if (!proc.killed && proc.exitCode === null) {
|
|
209
|
-
try {
|
|
210
|
-
proc.kill("SIGKILL");
|
|
211
|
-
} catch {
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}, 500).unref();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// src/tools/shell-pool.ts
|
|
218
|
-
var IS_WINDOWS2 = platform2() === "win32";
|
|
85
|
+
import { platform } from "os";
|
|
86
|
+
var IS_WINDOWS2 = platform() === "win32";
|
|
219
87
|
var SHELL = IS_WINDOWS2 ? "powershell.exe" : process.env["SHELL"] ?? "/bin/bash";
|
|
220
88
|
var pool = /* @__PURE__ */ new Map();
|
|
221
89
|
var IDLE_EVICT_MS = 5 * 6e4;
|
|
222
90
|
var evictionTimer = null;
|
|
223
91
|
function spawnShell(cwd) {
|
|
224
92
|
const shellArgs = IS_WINDOWS2 ? ["-NoProfile", "-NonInteractive", "-Command", "-"] : ["-s"];
|
|
225
|
-
const proc =
|
|
93
|
+
const proc = spawn(SHELL, shellArgs, {
|
|
226
94
|
cwd,
|
|
227
95
|
windowsHide: true,
|
|
228
96
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -433,16 +301,22 @@ function isToolCapableProvider(provider) {
|
|
|
433
301
|
}
|
|
434
302
|
|
|
435
303
|
// src/tools/builtin/bash.ts
|
|
436
|
-
import { spawn as
|
|
304
|
+
import { spawn as spawn2 } from "child_process";
|
|
437
305
|
import { existsSync as existsSync2, readdirSync, statSync } from "fs";
|
|
438
|
-
import { platform as
|
|
306
|
+
import { platform as platform2 } from "os";
|
|
439
307
|
import { resolve } from "path";
|
|
440
308
|
|
|
441
309
|
// src/tools/undo-stack.ts
|
|
442
|
-
import {
|
|
310
|
+
import { writeFileSync, unlinkSync, rmdirSync, existsSync } from "fs";
|
|
443
311
|
var MAX_UNDO_DEPTH = 20;
|
|
444
312
|
var UndoStack = class {
|
|
445
|
-
|
|
313
|
+
stateKey = /* @__PURE__ */ Symbol("stack");
|
|
314
|
+
get stack() {
|
|
315
|
+
return scopedState(this.stateKey, () => ({ items: [] })).items;
|
|
316
|
+
}
|
|
317
|
+
set stack(items) {
|
|
318
|
+
scopedState(this.stateKey, () => ({ items: [] })).items = items;
|
|
319
|
+
}
|
|
446
320
|
/**
|
|
447
321
|
* 在执行文件写入操作之前调用,保存当前状态。
|
|
448
322
|
* @param filePath 将要被写入的文件路径
|
|
@@ -451,11 +325,7 @@ var UndoStack = class {
|
|
|
451
325
|
push(filePath, description) {
|
|
452
326
|
let previousContent = null;
|
|
453
327
|
if (existsSync(filePath)) {
|
|
454
|
-
|
|
455
|
-
previousContent = readFileSync(filePath, "utf-8");
|
|
456
|
-
} catch {
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
328
|
+
previousContent = readSnapshot(filePath);
|
|
459
329
|
}
|
|
460
330
|
this.pushEntry({
|
|
461
331
|
filePath,
|
|
@@ -492,7 +362,7 @@ var UndoStack = class {
|
|
|
492
362
|
/** 内部统一入栈方法,含溢出裁剪 */
|
|
493
363
|
pushEntry(entry) {
|
|
494
364
|
this.stack.push(entry);
|
|
495
|
-
|
|
365
|
+
while (this.stack.length > MAX_UNDO_DEPTH || this.stack.reduce((n, e) => n + Buffer.byteLength(e.previousContent ?? ""), 0) > MAX_SNAPSHOT_TOTAL_BYTES) {
|
|
496
366
|
this.stack.shift();
|
|
497
367
|
}
|
|
498
368
|
}
|
|
@@ -553,42 +423,8 @@ var UndoStack = class {
|
|
|
553
423
|
};
|
|
554
424
|
var undoStack = new UndoStack();
|
|
555
425
|
|
|
556
|
-
// src/core/interrupt.ts
|
|
557
|
-
var controller = new AbortController();
|
|
558
|
-
var interrupted = false;
|
|
559
|
-
function currentAbortSignal() {
|
|
560
|
-
return controller.signal;
|
|
561
|
-
}
|
|
562
|
-
function isInterrupted() {
|
|
563
|
-
return interrupted;
|
|
564
|
-
}
|
|
565
|
-
function requestInterrupt() {
|
|
566
|
-
interrupted = true;
|
|
567
|
-
if (!controller.signal.aborted) {
|
|
568
|
-
controller.abort(new DOMException("User interrupted (Ctrl+C)", "AbortError"));
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
function resetInterrupt() {
|
|
572
|
-
controller = new AbortController();
|
|
573
|
-
interrupted = false;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// src/tools/session-context.ts
|
|
577
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
578
|
-
var als = new AsyncLocalStorage();
|
|
579
|
-
var DEFAULT_SESSION_KEY = "__default__";
|
|
580
|
-
function getCurrentSessionKey() {
|
|
581
|
-
const ctx = als.getStore();
|
|
582
|
-
if (!ctx || !ctx.sessionKey) return DEFAULT_SESSION_KEY;
|
|
583
|
-
return ctx.sessionKey;
|
|
584
|
-
}
|
|
585
|
-
function runWithSessionKey(sessionKey, fn) {
|
|
586
|
-
const key = sessionKey && sessionKey.length > 0 ? sessionKey : DEFAULT_SESSION_KEY;
|
|
587
|
-
return als.run({ sessionKey: key }, fn);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
426
|
// src/tools/builtin/bash.ts
|
|
591
|
-
var IS_WINDOWS3 =
|
|
427
|
+
var IS_WINDOWS3 = platform2() === "win32";
|
|
592
428
|
var SHELL2 = IS_WINDOWS3 ? "powershell.exe" : process.env["SHELL"] ?? "/bin/bash";
|
|
593
429
|
var cwdBySession = /* @__PURE__ */ new Map();
|
|
594
430
|
function getCwd() {
|
|
@@ -1171,7 +1007,7 @@ function pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, cwd) {
|
|
|
1171
1007
|
function runShell(command, opts) {
|
|
1172
1008
|
return new Promise((resolvePromise) => {
|
|
1173
1009
|
const shellArgs = IS_WINDOWS3 ? ["-NoProfile", "-NonInteractive", "-Command", WIN_UTF8_PREAMBLE + command] : ["-c", command];
|
|
1174
|
-
const child =
|
|
1010
|
+
const child = spawn2(SHELL2, shellArgs, {
|
|
1175
1011
|
cwd: opts.cwd,
|
|
1176
1012
|
env: opts.env,
|
|
1177
1013
|
windowsHide: true,
|
|
@@ -1250,16 +1086,16 @@ function updateCwdFromCommand(command, baseCwd) {
|
|
|
1250
1086
|
}
|
|
1251
1087
|
|
|
1252
1088
|
// src/tools/builtin/read-file.ts
|
|
1253
|
-
import { readFileSync
|
|
1089
|
+
import { readFileSync, existsSync as existsSync3, statSync as statSync2, readdirSync as readdirSync2 } from "fs";
|
|
1254
1090
|
import { execFileSync } from "child_process";
|
|
1255
1091
|
import { extname, resolve as resolve2, basename, sep, dirname } from "path";
|
|
1256
1092
|
import { homedir } from "os";
|
|
1257
1093
|
|
|
1258
1094
|
// src/tools/builtin/notebook-utils.ts
|
|
1259
|
-
function cellSourceToString(
|
|
1260
|
-
if (!
|
|
1261
|
-
if (Array.isArray(
|
|
1262
|
-
return
|
|
1095
|
+
function cellSourceToString(source2) {
|
|
1096
|
+
if (!source2) return "";
|
|
1097
|
+
if (Array.isArray(source2)) return source2.join("");
|
|
1098
|
+
return source2;
|
|
1263
1099
|
}
|
|
1264
1100
|
function stringToCellSource(content) {
|
|
1265
1101
|
if (content.length === 0) return [];
|
|
@@ -1314,16 +1150,16 @@ function renderNotebookAsText(nb, filePath) {
|
|
|
1314
1150
|
nb.cells.forEach((cell, idx) => {
|
|
1315
1151
|
const cellNum = idx + 1;
|
|
1316
1152
|
const type = cell.cell_type;
|
|
1317
|
-
const
|
|
1153
|
+
const source2 = cellSourceToString(cell.source);
|
|
1318
1154
|
if (type === "markdown") {
|
|
1319
1155
|
lines.push(`## Cell ${cellNum} [markdown]`);
|
|
1320
|
-
lines.push(
|
|
1156
|
+
lines.push(source2);
|
|
1321
1157
|
lines.push("");
|
|
1322
1158
|
} else if (type === "code") {
|
|
1323
1159
|
const execLabel = cell.execution_count != null ? ` (execution #${cell.execution_count})` : "";
|
|
1324
1160
|
lines.push(`## Cell ${cellNum} [code${execLabel}]`);
|
|
1325
1161
|
lines.push("```" + language);
|
|
1326
|
-
lines.push(
|
|
1162
|
+
lines.push(source2);
|
|
1327
1163
|
lines.push("```");
|
|
1328
1164
|
const outputText = extractOutputText(cell.outputs);
|
|
1329
1165
|
if (outputText) {
|
|
@@ -1335,7 +1171,7 @@ function renderNotebookAsText(nb, filePath) {
|
|
|
1335
1171
|
lines.push("");
|
|
1336
1172
|
} else if (type === "raw") {
|
|
1337
1173
|
lines.push(`## Cell ${cellNum} [raw]`);
|
|
1338
|
-
lines.push(
|
|
1174
|
+
lines.push(source2);
|
|
1339
1175
|
lines.push("");
|
|
1340
1176
|
}
|
|
1341
1177
|
});
|
|
@@ -1360,6 +1196,7 @@ function createCell(cellType, content) {
|
|
|
1360
1196
|
// src/tools/builtin/read-file.ts
|
|
1361
1197
|
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
1362
1198
|
function getHardRefusal(normalizedPath) {
|
|
1199
|
+
if (isCredentialVault(normalizedPath)) return "[Refused] Credential vault files cannot be read by tools.";
|
|
1363
1200
|
const home2 = homedir();
|
|
1364
1201
|
const p = normalizedPath.toLowerCase();
|
|
1365
1202
|
const base = basename(normalizedPath).toLowerCase();
|
|
@@ -1534,7 +1371,7 @@ var readFileTool = {
|
|
|
1534
1371
|
const offsetLine = typeof rawOffset === "number" && Number.isFinite(rawOffset) && rawOffset > 0 ? Math.floor(rawOffset) : void 0;
|
|
1535
1372
|
const limitLines = typeof rawLimit === "number" && Number.isFinite(rawLimit) && rawLimit > 0 ? Math.floor(rawLimit) : void 0;
|
|
1536
1373
|
if (!filePath) throw new ToolError("read_file", "path is required");
|
|
1537
|
-
const normalizedPath =
|
|
1374
|
+
const normalizedPath = canonicalPath(filePath);
|
|
1538
1375
|
const refusal = getHardRefusal(normalizedPath);
|
|
1539
1376
|
if (refusal) return refusal;
|
|
1540
1377
|
if (!existsSync3(normalizedPath)) {
|
|
@@ -1601,7 +1438,7 @@ Suggestion: read existing text versions (.md / .txt) in the project, or install
|
|
|
1601
1438
|
}
|
|
1602
1439
|
if (ext === ".ipynb") {
|
|
1603
1440
|
try {
|
|
1604
|
-
const raw =
|
|
1441
|
+
const raw = readFileSync(normalizedPath, "utf-8");
|
|
1605
1442
|
const nb = parseNotebook(raw);
|
|
1606
1443
|
return renderNotebookAsText(nb, filePath);
|
|
1607
1444
|
} catch (err) {
|
|
@@ -1619,8 +1456,8 @@ Do NOT claim you inspected this image \u2014 you have not seen it.`;
|
|
|
1619
1456
|
return `[Binary file: ${filePath} (${ext})]
|
|
1620
1457
|
This is a binary file and cannot be read as text. If there is a text version (.md / .txt) in the project, please read that instead.`;
|
|
1621
1458
|
}
|
|
1622
|
-
const { readFile
|
|
1623
|
-
const buf = size > 1048576 ? await
|
|
1459
|
+
const { readFile } = await import("fs/promises");
|
|
1460
|
+
const buf = size > 1048576 ? await readFile(normalizedPath) : readFileSync(normalizedPath);
|
|
1624
1461
|
if (encoding === "base64") {
|
|
1625
1462
|
return `[File: ${filePath} | base64]
|
|
1626
1463
|
|
|
@@ -1658,12 +1495,12 @@ ${content}`;
|
|
|
1658
1495
|
};
|
|
1659
1496
|
|
|
1660
1497
|
// src/tools/builtin/write-file.ts
|
|
1661
|
-
import { appendFileSync, mkdirSync, readFileSync as
|
|
1498
|
+
import { appendFileSync, mkdirSync, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
1662
1499
|
import { dirname as dirname3 } from "path";
|
|
1663
1500
|
|
|
1664
1501
|
// src/tools/executor.ts
|
|
1665
1502
|
import chalk2 from "chalk";
|
|
1666
|
-
import { existsSync as
|
|
1503
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
1667
1504
|
import { tmpdir } from "os";
|
|
1668
1505
|
|
|
1669
1506
|
// src/core/readline-internal.ts
|
|
@@ -2006,7 +1843,8 @@ var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
2006
1843
|
"recall_memory"
|
|
2007
1844
|
]);
|
|
2008
1845
|
function normalizePathForPermission(value) {
|
|
2009
|
-
|
|
1846
|
+
const normalized = value.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1847
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
2010
1848
|
}
|
|
2011
1849
|
function canonicalizeWithNearestParent(value) {
|
|
2012
1850
|
const missing = [];
|
|
@@ -2094,7 +1932,7 @@ function profileHardDecision(profileName, toolName, args, dangerLevel, ctx) {
|
|
|
2094
1932
|
return { action: "deny", reason: "file write target is outside workspace/temp roots", profileName, hardBoundary: true };
|
|
2095
1933
|
}
|
|
2096
1934
|
}
|
|
2097
|
-
if (toolName === "bash" || toolName === "run_interactive" || toolName === "task_create") {
|
|
1935
|
+
if (toolName === "bash" || toolName === "run_interactive" || toolName === "task_create" || toolName === "run_tests") {
|
|
2098
1936
|
return {
|
|
2099
1937
|
action: "confirm",
|
|
2100
1938
|
reason: "shell/process writes cannot be proven to stay inside workspace/temp roots",
|
|
@@ -2196,9 +2034,9 @@ function checkNetworkPolicy(toolName, args, policy) {
|
|
|
2196
2034
|
if (!policy?.enabled) return null;
|
|
2197
2035
|
let action = networkToolAction(toolName, policy);
|
|
2198
2036
|
let reason = "network access requires confirmation";
|
|
2199
|
-
if (
|
|
2037
|
+
if (["bash", "run_tests", "run_interactive", "task_create"].includes(toolName)) {
|
|
2200
2038
|
const command = String(args["command"] ?? "");
|
|
2201
|
-
if (!isShellNetworkCommand(command)) return null;
|
|
2039
|
+
if (toolName === "bash" && !isShellNetworkCommand(command) && dangerIsReadOnly(command)) return null;
|
|
2202
2040
|
action = policy.tools?.shell ?? policy.defaultAction ?? "confirm";
|
|
2203
2041
|
reason = "shell command may access the network";
|
|
2204
2042
|
}
|
|
@@ -2234,6 +2072,9 @@ function checkNetworkPolicy(toolName, args, policy) {
|
|
|
2234
2072
|
if (!permissionAction) return null;
|
|
2235
2073
|
return { action: permissionAction, reason, profileName: "networkPolicy" };
|
|
2236
2074
|
}
|
|
2075
|
+
function dangerIsReadOnly(command) {
|
|
2076
|
+
return /^(?:pwd|echo [\w .-]+|git status(?: --short)?)$/.test(command.trim());
|
|
2077
|
+
}
|
|
2237
2078
|
|
|
2238
2079
|
// src/tools/truncate.ts
|
|
2239
2080
|
var DEFAULT_MAX_TOOL_OUTPUT_CHARS = 12e3;
|
|
@@ -2343,8 +2184,7 @@ function truncateOutput(content, toolName, maxChars) {
|
|
|
2343
2184
|
}
|
|
2344
2185
|
|
|
2345
2186
|
// src/tools/action-classifier.ts
|
|
2346
|
-
import {
|
|
2347
|
-
import { isAbsolute as isAbsolute2, join, resolve as resolve4 } from "path";
|
|
2187
|
+
import { isAbsolute as isAbsolute2, resolve as resolve4 } from "path";
|
|
2348
2188
|
var RECENT_DENIED_LIMIT = 50;
|
|
2349
2189
|
var recentlyDenied = [];
|
|
2350
2190
|
function recordRecentlyDeniedAutoAction(call, classification) {
|
|
@@ -2364,7 +2204,8 @@ function clearRecentlyDeniedAutoActions() {
|
|
|
2364
2204
|
recentlyDenied.splice(0, recentlyDenied.length);
|
|
2365
2205
|
}
|
|
2366
2206
|
function normalizePath(value) {
|
|
2367
|
-
|
|
2207
|
+
const normalized = canonicalPath(value).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
2208
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
2368
2209
|
}
|
|
2369
2210
|
function isInside(root, target) {
|
|
2370
2211
|
const absoluteRoot = resolve4(root);
|
|
@@ -2377,56 +2218,6 @@ function getPathArg(call) {
|
|
|
2377
2218
|
const raw = call.arguments.path ?? call.arguments.filePath ?? call.arguments.outputPath ?? call.arguments.file;
|
|
2378
2219
|
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
2379
2220
|
}
|
|
2380
|
-
function splitShellWords(command) {
|
|
2381
|
-
const out = [];
|
|
2382
|
-
const re = /"([^"]*)"|'([^']*)'|([^\s]+)/g;
|
|
2383
|
-
let m;
|
|
2384
|
-
while (m = re.exec(command)) out.push(m[1] ?? m[2] ?? m[3] ?? "");
|
|
2385
|
-
return out.filter(Boolean);
|
|
2386
|
-
}
|
|
2387
|
-
function readPackageManifest(root) {
|
|
2388
|
-
const p = join(root, "package.json");
|
|
2389
|
-
if (!existsSync5(p)) return null;
|
|
2390
|
-
try {
|
|
2391
|
-
return JSON.parse(readFileSync3(p, "utf-8"));
|
|
2392
|
-
} catch {
|
|
2393
|
-
return null;
|
|
2394
|
-
}
|
|
2395
|
-
}
|
|
2396
|
-
function manifestHasDependency(root, name) {
|
|
2397
|
-
const manifest = readPackageManifest(root);
|
|
2398
|
-
if (!manifest) return false;
|
|
2399
|
-
for (const key of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
|
|
2400
|
-
const deps = manifest[key];
|
|
2401
|
-
if (deps && typeof deps === "object" && Object.prototype.hasOwnProperty.call(deps, name)) return true;
|
|
2402
|
-
}
|
|
2403
|
-
return false;
|
|
2404
|
-
}
|
|
2405
|
-
function lockfileMentions(root, name) {
|
|
2406
|
-
for (const file of ["package-lock.json", "pnpm-lock.yaml", "yarn.lock"]) {
|
|
2407
|
-
const p = join(root, file);
|
|
2408
|
-
if (!existsSync5(p)) continue;
|
|
2409
|
-
try {
|
|
2410
|
-
if (readFileSync3(p, "utf-8").includes(name)) return true;
|
|
2411
|
-
} catch {
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
return false;
|
|
2415
|
-
}
|
|
2416
|
-
function getInstallPackages(command) {
|
|
2417
|
-
const words = splitShellWords(command);
|
|
2418
|
-
const cmd = words[0]?.toLowerCase();
|
|
2419
|
-
const sub = words[1]?.toLowerCase();
|
|
2420
|
-
if (!cmd || !sub) return [];
|
|
2421
|
-
const isInstall = cmd === "npm" && (sub === "install" || sub === "i" || sub === "add") || (cmd === "pnpm" || cmd === "yarn") && (sub === "add" || sub === "install");
|
|
2422
|
-
if (!isInstall) return [];
|
|
2423
|
-
return words.slice(2).filter((w) => !w.startsWith("-")).filter((w) => w !== "." && w !== "./").map((w) => w.replace(/^@([^/]+)\/([^@]+)(?:@.+)?$/, "@$1/$2").replace(/^([^@]+)@.+$/, "$1"));
|
|
2424
|
-
}
|
|
2425
|
-
function isPlainGitPush(command) {
|
|
2426
|
-
if (!/^\s*git\s+push\b/i.test(command)) return false;
|
|
2427
|
-
if (/--force|-f\b|\+[^\s]+/i.test(command)) return false;
|
|
2428
|
-
return !/[;&|`$<>\n\r]/.test(command);
|
|
2429
|
-
}
|
|
2430
2221
|
function hasSecretExfiltrationShape(command) {
|
|
2431
2222
|
return /(?:\.env|config\.json|id_rsa|id_ed25519|AWS_SECRET|AICLI_API_KEY|OPENAI_API_KEY|ANTHROPIC_API_KEY)/i.test(command) && /\b(curl|wget|scp|rsync|nc|netcat|Invoke-WebRequest|Invoke-RestMethod)\b/i.test(command);
|
|
2432
2223
|
}
|
|
@@ -2448,7 +2239,7 @@ var RuleBasedActionClassifier = class {
|
|
|
2448
2239
|
}
|
|
2449
2240
|
return { decision: "confirm", reason: "destructive actions require confirmation", ruleId: "auto.destructive-confirm", confidence: "high" };
|
|
2450
2241
|
}
|
|
2451
|
-
classifyShell(call, dangerLevel,
|
|
2242
|
+
classifyShell(call, dangerLevel, _ctx) {
|
|
2452
2243
|
const command = String(call.arguments.command ?? "");
|
|
2453
2244
|
if (/\bcurl\b[^\n|;&]*\|\s*(?:sudo\s+)?(?:bash|sh|zsh)\b/i.test(command)) {
|
|
2454
2245
|
return { decision: "deny", reason: "curl pipe shell execution is blocked in auto mode", ruleId: "deny.curl-pipe-shell", confidence: "high" };
|
|
@@ -2474,18 +2265,7 @@ var RuleBasedActionClassifier = class {
|
|
|
2474
2265
|
if (/\b(npx|pnpm\s+dlx|yarn\s+dlx)\s+(claude|codex|aider|cursor-agent|gemini)\b/i.test(command)) {
|
|
2475
2266
|
return { decision: "confirm", reason: "third-party agent loop requires confirmation", ruleId: "confirm.third-party-agent", confidence: "high" };
|
|
2476
2267
|
}
|
|
2477
|
-
if (
|
|
2478
|
-
return { decision: "auto-approve", reason: "plain git push without force", ruleId: "auto.git-push", confidence: "high" };
|
|
2479
|
-
}
|
|
2480
|
-
const pkgs = getInstallPackages(command);
|
|
2481
|
-
if (pkgs.length > 0) {
|
|
2482
|
-
const allDeclared = pkgs.every((p) => manifestHasDependency(ctx.workspaceRoot, p) || lockfileMentions(ctx.workspaceRoot, p));
|
|
2483
|
-
return allDeclared ? { decision: "auto-approve", reason: "installing dependencies already declared in manifest/lockfile", ruleId: "auto.declared-dependency-install", confidence: "medium" } : { decision: "confirm", reason: "dependency install includes undeclared packages", ruleId: "confirm.undeclared-dependency-install", confidence: "medium" };
|
|
2484
|
-
}
|
|
2485
|
-
if (/\b(curl|wget|Invoke-WebRequest|Invoke-RestMethod)\b/i.test(command) && !/[>|;&`$]/.test(command)) {
|
|
2486
|
-
return { decision: "auto-approve", reason: "read-only HTTP shell command", ruleId: "auto.readonly-http-shell", confidence: "medium" };
|
|
2487
|
-
}
|
|
2488
|
-
if (dangerLevel === "safe") {
|
|
2268
|
+
if (dangerLevel === "safe" && getDangerLevel(call.name, call.arguments) === "safe") {
|
|
2489
2269
|
return { decision: "auto-approve", reason: "safe shell action", ruleId: "auto.safe-shell", confidence: "medium" };
|
|
2490
2270
|
}
|
|
2491
2271
|
return { decision: "confirm", reason: "shell action is not proven low-risk", ruleId: "confirm.shell-default", confidence: "medium" };
|
|
@@ -2954,10 +2734,10 @@ var ToolExecutor = class {
|
|
|
2954
2734
|
if (call.name === "write_file") {
|
|
2955
2735
|
const { path: filePath, content: chunk, append } = resolveWriteFileArgs(call.arguments);
|
|
2956
2736
|
if (!filePath) return;
|
|
2957
|
-
if (
|
|
2737
|
+
if (existsSync5(filePath)) {
|
|
2958
2738
|
let oldContent;
|
|
2959
2739
|
try {
|
|
2960
|
-
oldContent =
|
|
2740
|
+
oldContent = readFileSync2(filePath, "utf-8");
|
|
2961
2741
|
} catch {
|
|
2962
2742
|
return;
|
|
2963
2743
|
}
|
|
@@ -2981,7 +2761,7 @@ var ToolExecutor = class {
|
|
|
2981
2761
|
}
|
|
2982
2762
|
} else if (call.name === "edit_file") {
|
|
2983
2763
|
const filePath = String(call.arguments["path"] ?? "");
|
|
2984
|
-
if (!filePath || !
|
|
2764
|
+
if (!filePath || !existsSync5(filePath)) return;
|
|
2985
2765
|
const oldStr = call.arguments["old_str"];
|
|
2986
2766
|
const newStr = call.arguments["new_str"];
|
|
2987
2767
|
if (oldStr !== void 0) {
|
|
@@ -3008,7 +2788,7 @@ var ToolExecutor = class {
|
|
|
3008
2788
|
const to = Number(call.arguments["delete_to_line"] ?? from);
|
|
3009
2789
|
let fileContent;
|
|
3010
2790
|
try {
|
|
3011
|
-
fileContent =
|
|
2791
|
+
fileContent = readFileSync2(filePath, "utf-8");
|
|
3012
2792
|
} catch {
|
|
3013
2793
|
return;
|
|
3014
2794
|
}
|
|
@@ -3104,7 +2884,12 @@ import { resolve as resolve5, sep as sep2, basename as basename3 } from "path";
|
|
|
3104
2884
|
import { homedir as homedir2 } from "os";
|
|
3105
2885
|
var home = homedir2();
|
|
3106
2886
|
function norm(p) {
|
|
3107
|
-
|
|
2887
|
+
let abs;
|
|
2888
|
+
try {
|
|
2889
|
+
abs = canonicalPath(p);
|
|
2890
|
+
} catch {
|
|
2891
|
+
abs = resolve5(p);
|
|
2892
|
+
}
|
|
3108
2893
|
return process.platform === "win32" ? abs.toLowerCase() : abs;
|
|
3109
2894
|
}
|
|
3110
2895
|
function homeRel(p) {
|
|
@@ -3118,6 +2903,7 @@ function homeRel(p) {
|
|
|
3118
2903
|
}
|
|
3119
2904
|
function classifyWritePath(path3) {
|
|
3120
2905
|
if (!path3) return { sensitive: false };
|
|
2906
|
+
if (isCredentialVault(path3)) return { sensitive: true, reason: "credential vault" };
|
|
3121
2907
|
const abs = norm(path3);
|
|
3122
2908
|
const base = basename3(abs);
|
|
3123
2909
|
const rel = homeRel(path3);
|
|
@@ -3200,7 +2986,7 @@ function countTextLines(text) {
|
|
|
3200
2986
|
|
|
3201
2987
|
// src/tools/builtin/write-file.ts
|
|
3202
2988
|
function countFileLines(filePath) {
|
|
3203
|
-
return countTextLines(
|
|
2989
|
+
return countTextLines(readFileSync3(filePath, "utf-8"));
|
|
3204
2990
|
}
|
|
3205
2991
|
var writeFileTool = {
|
|
3206
2992
|
definition: {
|
|
@@ -3264,7 +3050,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
3264
3050
|
const mode = appendMode ? "appended" : "written";
|
|
3265
3051
|
void (async () => {
|
|
3266
3052
|
try {
|
|
3267
|
-
const { updateFile } = await import("./indexer-
|
|
3053
|
+
const { updateFile } = await import("./indexer-GKIWSSRP.js");
|
|
3268
3054
|
await updateFile(process.cwd(), filePath);
|
|
3269
3055
|
} catch {
|
|
3270
3056
|
}
|
|
@@ -3283,7 +3069,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
3283
3069
|
};
|
|
3284
3070
|
|
|
3285
3071
|
// src/tools/builtin/edit-file.ts
|
|
3286
|
-
import { readFileSync as
|
|
3072
|
+
import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
|
|
3287
3073
|
|
|
3288
3074
|
// src/tools/builtin/patch-apply.ts
|
|
3289
3075
|
function parseUnifiedDiff(patch) {
|
|
@@ -3651,7 +3437,7 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
3651
3437
|
const filePath = String(args["path"] ?? args["file"] ?? "");
|
|
3652
3438
|
const encoding = args["encoding"] ?? "utf-8";
|
|
3653
3439
|
if (!filePath) throw new ToolError("edit_file", "path is required");
|
|
3654
|
-
if (!
|
|
3440
|
+
if (!existsSync6(filePath)) throw new ToolError("edit_file", `File not found: ${filePath}`);
|
|
3655
3441
|
const verdict = classifyWritePath(filePath);
|
|
3656
3442
|
if (verdict.sensitive && subAgentGuard.active) {
|
|
3657
3443
|
throw new ToolError(
|
|
@@ -3659,7 +3445,7 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
3659
3445
|
`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.`
|
|
3660
3446
|
);
|
|
3661
3447
|
}
|
|
3662
|
-
const original =
|
|
3448
|
+
const original = readFileSync4(filePath, encoding);
|
|
3663
3449
|
if (args["patch"] !== void 0) {
|
|
3664
3450
|
const patchText = String(args["patch"] ?? "");
|
|
3665
3451
|
const stopOnError = args["stop_on_error"] !== false;
|
|
@@ -3836,8 +3622,8 @@ function truncatePreview(str, maxLen = 80) {
|
|
|
3836
3622
|
}
|
|
3837
3623
|
|
|
3838
3624
|
// src/tools/builtin/list-dir.ts
|
|
3839
|
-
import { readdirSync as readdirSync3, statSync as statSync4, existsSync as
|
|
3840
|
-
import { join
|
|
3625
|
+
import { readdirSync as readdirSync3, statSync as statSync4, existsSync as existsSync7 } from "fs";
|
|
3626
|
+
import { join, basename as basename4 } from "path";
|
|
3841
3627
|
var listDirTool = {
|
|
3842
3628
|
definition: {
|
|
3843
3629
|
name: "list_dir",
|
|
@@ -3859,7 +3645,7 @@ var listDirTool = {
|
|
|
3859
3645
|
async execute(args) {
|
|
3860
3646
|
const dirPath = String(args["path"] ?? process.cwd());
|
|
3861
3647
|
const recursive = Boolean(args["recursive"] ?? false);
|
|
3862
|
-
if (!
|
|
3648
|
+
if (!existsSync7(dirPath)) {
|
|
3863
3649
|
const targetName = basename4(dirPath).toLowerCase();
|
|
3864
3650
|
const cwd = process.cwd();
|
|
3865
3651
|
const suggestions = [];
|
|
@@ -3917,11 +3703,11 @@ function listRecursive(basePath, indent, recursive, lines) {
|
|
|
3917
3703
|
if (entry.isDirectory()) {
|
|
3918
3704
|
lines.push(`${indent}\u{1F4C1} ${entry.name}/`);
|
|
3919
3705
|
if (recursive) {
|
|
3920
|
-
listRecursive(
|
|
3706
|
+
listRecursive(join(basePath, entry.name), indent + " ", true, lines);
|
|
3921
3707
|
}
|
|
3922
3708
|
} else {
|
|
3923
3709
|
try {
|
|
3924
|
-
const stat = statSync4(
|
|
3710
|
+
const stat = statSync4(join(basePath, entry.name));
|
|
3925
3711
|
const size = formatSize(stat.size);
|
|
3926
3712
|
lines.push(`${indent}\u{1F4C4} ${entry.name} (${size})`);
|
|
3927
3713
|
} catch {
|
|
@@ -3936,10 +3722,77 @@ function formatSize(bytes) {
|
|
|
3936
3722
|
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
3937
3723
|
}
|
|
3938
3724
|
|
|
3725
|
+
// src/tools/regex-search.ts
|
|
3726
|
+
import { Worker } from "worker_threads";
|
|
3727
|
+
var source = String.raw`
|
|
3728
|
+
const { parentPort, workerData: d } = require('node:worker_threads');
|
|
3729
|
+
const fs = require('node:fs');
|
|
3730
|
+
let re;
|
|
3731
|
+
try { re = new RegExp(d.pattern, d.ignoreCase ? 'i' : ''); }
|
|
3732
|
+
catch { re = new RegExp(d.pattern.replace(/[.*+?^$()|[\]\\]/g, '\\$&'), d.ignoreCase ? 'i' : ''); }
|
|
3733
|
+
const results = [];
|
|
3734
|
+
for (const f of d.files) {
|
|
3735
|
+
if (results.length >= d.maxResults) break;
|
|
3736
|
+
let fd;
|
|
3737
|
+
try {
|
|
3738
|
+
fd = fs.openSync(f.fullPath, 'r');
|
|
3739
|
+
const buf = Buffer.alloc(1000001);
|
|
3740
|
+
let size = 0;
|
|
3741
|
+
while (size < buf.length) { const n = fs.readSync(fd, buf, size, buf.length - size, null); if (!n) break; size += n; }
|
|
3742
|
+
if (size > 1000000 || buf.subarray(0, Math.min(size,512)).includes(0)) continue;
|
|
3743
|
+
const lines = buf.subarray(0,size).toString('utf8').split('\n');
|
|
3744
|
+
for (let i=0; i<lines.length && results.length<d.maxResults; i++) {
|
|
3745
|
+
if (!re.test(lines[i])) continue;
|
|
3746
|
+
const match = { file:f.relPath.replace(/\\/g,'/'), lineNumber:i+1, lineText:lines[i].slice(0,10000) };
|
|
3747
|
+
if (d.context) {
|
|
3748
|
+
match.contextBefore=[]; match.contextAfter=[];
|
|
3749
|
+
for(let j=Math.max(0,i-d.context);j<i;j++) match.contextBefore.push([j+1,lines[j].slice(0,10000)]);
|
|
3750
|
+
for(let j=i+1;j<=Math.min(lines.length-1,i+d.context);j++) match.contextAfter.push([j+1,lines[j].slice(0,10000)]);
|
|
3751
|
+
}
|
|
3752
|
+
results.push(match);
|
|
3753
|
+
}
|
|
3754
|
+
} catch {} finally { if (fd !== undefined) fs.closeSync(fd); }
|
|
3755
|
+
}
|
|
3756
|
+
parentPort.postMessage(results);
|
|
3757
|
+
`;
|
|
3758
|
+
var active = 0;
|
|
3759
|
+
async function searchInWorker(files, pattern, ignoreCase, context, maxResults) {
|
|
3760
|
+
const signal = currentAbortSignal();
|
|
3761
|
+
if (signal.aborted) throw new Error("Search cancelled");
|
|
3762
|
+
if (active >= 4) throw new Error("Search capacity reached; wait for another search to finish");
|
|
3763
|
+
active++;
|
|
3764
|
+
let worker;
|
|
3765
|
+
try {
|
|
3766
|
+
return await new Promise((resolve7, reject) => {
|
|
3767
|
+
worker = new Worker(source, { eval: true, workerData: { files, pattern, ignoreCase, context, maxResults }, resourceLimits: { maxOldGenerationSizeMb: 64 } });
|
|
3768
|
+
let settled = false;
|
|
3769
|
+
const finish = (error, results) => {
|
|
3770
|
+
if (settled) return;
|
|
3771
|
+
settled = true;
|
|
3772
|
+
clearTimeout(timer);
|
|
3773
|
+
signal.removeEventListener("abort", abort);
|
|
3774
|
+
if (error) reject(error);
|
|
3775
|
+
else resolve7(results ?? []);
|
|
3776
|
+
};
|
|
3777
|
+
const timer = setTimeout(() => finish(new Error("Search exceeded 2 second CPU/time budget; simplify the pattern or narrow the path")), 2e3);
|
|
3778
|
+
const abort = () => finish(new Error("Search cancelled"));
|
|
3779
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
3780
|
+
if (signal.aborted) abort();
|
|
3781
|
+
worker.once("message", (results) => finish(void 0, results));
|
|
3782
|
+
worker.once("error", (error) => finish(error));
|
|
3783
|
+
worker.once("exit", (code) => {
|
|
3784
|
+
if (!settled) finish(new Error(`Search worker exited (${code})`));
|
|
3785
|
+
});
|
|
3786
|
+
});
|
|
3787
|
+
} finally {
|
|
3788
|
+
if (worker) await worker.terminate();
|
|
3789
|
+
active--;
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3939
3793
|
// src/tools/builtin/grep-files.ts
|
|
3940
|
-
import { readdirSync as readdirSync4,
|
|
3941
|
-
import {
|
|
3942
|
-
import { join as join3, relative } from "path";
|
|
3794
|
+
import { readdirSync as readdirSync4, statSync as statSync5, existsSync as existsSync8 } from "fs";
|
|
3795
|
+
import { join as join2, relative } from "path";
|
|
3943
3796
|
var grepFilesTool = {
|
|
3944
3797
|
definition: {
|
|
3945
3798
|
name: "grep_files",
|
|
@@ -3987,43 +3840,24 @@ Supports regex. Automatically skips node_modules, dist, .git directories.`,
|
|
|
3987
3840
|
const rootPath = String(args["path"] ?? process.cwd());
|
|
3988
3841
|
const filePattern = args["file_pattern"] ? String(args["file_pattern"]) : void 0;
|
|
3989
3842
|
const ignoreCase = Boolean(args["ignore_case"] ?? false);
|
|
3990
|
-
const contextLines = Math.max(0, Number(args["context_lines"]
|
|
3991
|
-
const maxResults = Math.max(1, Number(args["max_results"]
|
|
3843
|
+
const contextLines = Math.min(10, Math.max(0, Number(args["context_lines"]) || 0));
|
|
3844
|
+
const maxResults = Math.min(200, Math.max(1, Number(args["max_results"]) || 50));
|
|
3992
3845
|
if (!pattern) throw new ToolError("grep_files", "pattern is required");
|
|
3993
|
-
if (!
|
|
3846
|
+
if (!existsSync8(rootPath)) throw new ToolError("grep_files", `Path not found: ${rootPath}`);
|
|
3994
3847
|
const MAX_PATTERN_LENGTH = 1e3;
|
|
3995
|
-
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
3848
|
+
if (pattern.length > MAX_PATTERN_LENGTH || (filePattern?.length ?? 0) > MAX_PATTERN_LENGTH) {
|
|
3996
3849
|
throw new ToolError("grep_files", `Pattern too long (${pattern.length} chars, max ${MAX_PATTERN_LENGTH}). Use a shorter pattern.`);
|
|
3997
3850
|
}
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
const results = [];
|
|
4006
|
-
const stat = statSync5(rootPath);
|
|
4007
|
-
if (stat.isFile()) {
|
|
4008
|
-
searchInFile(rootPath, rootPath, regex, contextLines, maxResults, results);
|
|
4009
|
-
} else {
|
|
4010
|
-
const filePaths = collectFilePaths(rootPath, filePattern, maxResults);
|
|
4011
|
-
const BATCH_SIZE = 16;
|
|
4012
|
-
for (let i = 0; i < filePaths.length && results.length < maxResults; i += BATCH_SIZE) {
|
|
4013
|
-
const batch = filePaths.slice(i, i + BATCH_SIZE);
|
|
4014
|
-
const batchResults = await Promise.all(
|
|
4015
|
-
batch.map(
|
|
4016
|
-
({ fullPath, relPath }) => searchInFileAsync(fullPath, relPath, regex, contextLines, maxResults - results.length)
|
|
4017
|
-
)
|
|
4018
|
-
);
|
|
4019
|
-
for (const br of batchResults) {
|
|
4020
|
-
for (const r of br) {
|
|
4021
|
-
if (results.length >= maxResults) break;
|
|
4022
|
-
results.push(r);
|
|
4023
|
-
}
|
|
4024
|
-
}
|
|
3851
|
+
assertReadablePath(rootPath);
|
|
3852
|
+
const paths = statSync5(rootPath).isFile() ? [{ fullPath: rootPath, relPath: rootPath }] : collectFilePaths(rootPath, filePattern, maxResults);
|
|
3853
|
+
const files = paths.filter((f) => {
|
|
3854
|
+
try {
|
|
3855
|
+
return !isCredentialVault(f.fullPath);
|
|
3856
|
+
} catch {
|
|
3857
|
+
return false;
|
|
4025
3858
|
}
|
|
4026
|
-
}
|
|
3859
|
+
});
|
|
3860
|
+
const results = await searchInWorker(files, pattern, ignoreCase, contextLines, maxResults);
|
|
4027
3861
|
if (results.length === 0) {
|
|
4028
3862
|
return `No matches found for pattern: ${pattern}
|
|
4029
3863
|
Searched in: ${rootPath}${filePattern ? `
|
|
@@ -4063,8 +3897,23 @@ File filter: ${filePattern}` : ""}`;
|
|
|
4063
3897
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "dist-cjs", "release", ".next", "__pycache__", ".cache", "coverage", ".nyc_output"]);
|
|
4064
3898
|
var BINARY_EXTS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".ico", ".woff", ".woff2", ".ttf", ".eot", ".otf", ".mp3", ".mp4", ".wav", ".zip", ".tar", ".gz", ".rar", ".7z", ".exe", ".dll", ".so", ".dylib", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx"]);
|
|
4065
3899
|
function matchesFilePattern(filename, pattern) {
|
|
4066
|
-
|
|
4067
|
-
|
|
3900
|
+
filename = filename.toLowerCase();
|
|
3901
|
+
pattern = pattern.toLowerCase();
|
|
3902
|
+
let i = 0, j = 0, star = -1, restart = 0;
|
|
3903
|
+
while (i < filename.length) {
|
|
3904
|
+
if (pattern[j] === filename[i]) {
|
|
3905
|
+
i++;
|
|
3906
|
+
j++;
|
|
3907
|
+
} else if (pattern[j] === "*") {
|
|
3908
|
+
star = j++;
|
|
3909
|
+
restart = i;
|
|
3910
|
+
} else if (star >= 0) {
|
|
3911
|
+
j = star + 1;
|
|
3912
|
+
i = ++restart;
|
|
3913
|
+
} else return false;
|
|
3914
|
+
}
|
|
3915
|
+
while (pattern[j] === "*") j++;
|
|
3916
|
+
return j === pattern.length;
|
|
4068
3917
|
}
|
|
4069
3918
|
function isBinary(filename) {
|
|
4070
3919
|
const ext = filename.slice(filename.lastIndexOf(".")).toLowerCase();
|
|
@@ -4072,8 +3921,9 @@ function isBinary(filename) {
|
|
|
4072
3921
|
}
|
|
4073
3922
|
function collectFilePaths(rootPath, filePattern, maxFiles) {
|
|
4074
3923
|
const paths = [];
|
|
4075
|
-
|
|
4076
|
-
|
|
3924
|
+
let visited = 0;
|
|
3925
|
+
function walk(dirPath, depth = 0) {
|
|
3926
|
+
if (paths.length >= maxFiles || depth > 20 || visited >= 2e4) return;
|
|
4077
3927
|
let entries;
|
|
4078
3928
|
try {
|
|
4079
3929
|
entries = readdirSync4(dirPath, { withFileTypes: true });
|
|
@@ -4081,14 +3931,14 @@ function collectFilePaths(rootPath, filePattern, maxFiles) {
|
|
|
4081
3931
|
return;
|
|
4082
3932
|
}
|
|
4083
3933
|
for (const entry of entries) {
|
|
4084
|
-
if (paths.length >= maxFiles) return;
|
|
3934
|
+
if (paths.length >= maxFiles || ++visited > 2e4) return;
|
|
4085
3935
|
if (entry.isDirectory()) {
|
|
4086
3936
|
if (SKIP_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
4087
|
-
walk(
|
|
3937
|
+
walk(join2(dirPath, entry.name), depth + 1);
|
|
4088
3938
|
} else if (entry.isFile()) {
|
|
4089
3939
|
if (isBinary(entry.name)) continue;
|
|
4090
3940
|
if (filePattern && !matchesFilePattern(entry.name, filePattern)) continue;
|
|
4091
|
-
const fullPath =
|
|
3941
|
+
const fullPath = join2(dirPath, entry.name);
|
|
4092
3942
|
try {
|
|
4093
3943
|
if (statSync5(fullPath).size > 1e6) continue;
|
|
4094
3944
|
} catch {
|
|
@@ -4101,81 +3951,10 @@ function collectFilePaths(rootPath, filePattern, maxFiles) {
|
|
|
4101
3951
|
walk(rootPath);
|
|
4102
3952
|
return paths;
|
|
4103
3953
|
}
|
|
4104
|
-
async function searchInFileAsync(fullPath, displayPath, regex, contextLines, maxResults) {
|
|
4105
|
-
let content;
|
|
4106
|
-
try {
|
|
4107
|
-
content = await readFile(fullPath, "utf-8");
|
|
4108
|
-
} catch {
|
|
4109
|
-
return [];
|
|
4110
|
-
}
|
|
4111
|
-
const results = [];
|
|
4112
|
-
const lines = content.split("\n");
|
|
4113
|
-
regex.lastIndex = 0;
|
|
4114
|
-
for (let i = 0; i < lines.length && results.length < maxResults; i++) {
|
|
4115
|
-
regex.lastIndex = 0;
|
|
4116
|
-
if (regex.test(lines[i])) {
|
|
4117
|
-
const match = {
|
|
4118
|
-
file: displayPath.replace(/\\/g, "/"),
|
|
4119
|
-
lineNumber: i + 1,
|
|
4120
|
-
lineText: lines[i]
|
|
4121
|
-
};
|
|
4122
|
-
if (contextLines > 0) {
|
|
4123
|
-
match.contextBefore = [];
|
|
4124
|
-
for (let j = Math.max(0, i - contextLines); j < i; j++) {
|
|
4125
|
-
match.contextBefore.push([j + 1, lines[j]]);
|
|
4126
|
-
}
|
|
4127
|
-
match.contextAfter = [];
|
|
4128
|
-
for (let j = i + 1; j <= Math.min(lines.length - 1, i + contextLines); j++) {
|
|
4129
|
-
match.contextAfter.push([j + 1, lines[j]]);
|
|
4130
|
-
}
|
|
4131
|
-
}
|
|
4132
|
-
results.push(match);
|
|
4133
|
-
}
|
|
4134
|
-
}
|
|
4135
|
-
return results;
|
|
4136
|
-
}
|
|
4137
|
-
function searchInFile(fullPath, displayPath, regex, contextLines, maxResults, results) {
|
|
4138
|
-
try {
|
|
4139
|
-
const stat = statSync5(fullPath);
|
|
4140
|
-
if (stat.size > 1e6) return;
|
|
4141
|
-
} catch {
|
|
4142
|
-
return;
|
|
4143
|
-
}
|
|
4144
|
-
let content;
|
|
4145
|
-
try {
|
|
4146
|
-
content = readFileSync7(fullPath, "utf-8");
|
|
4147
|
-
} catch {
|
|
4148
|
-
return;
|
|
4149
|
-
}
|
|
4150
|
-
const lines = content.split("\n");
|
|
4151
|
-
regex.lastIndex = 0;
|
|
4152
|
-
for (let i = 0; i < lines.length; i++) {
|
|
4153
|
-
if (results.length >= maxResults) return;
|
|
4154
|
-
regex.lastIndex = 0;
|
|
4155
|
-
if (regex.test(lines[i])) {
|
|
4156
|
-
const result = {
|
|
4157
|
-
file: displayPath,
|
|
4158
|
-
lineNumber: i + 1,
|
|
4159
|
-
lineText: lines[i].trimEnd()
|
|
4160
|
-
};
|
|
4161
|
-
if (contextLines > 0) {
|
|
4162
|
-
result.contextBefore = [];
|
|
4163
|
-
result.contextAfter = [];
|
|
4164
|
-
for (let c = Math.max(0, i - contextLines); c < i; c++) {
|
|
4165
|
-
result.contextBefore.push([c + 1, lines[c].trimEnd()]);
|
|
4166
|
-
}
|
|
4167
|
-
for (let c = i + 1; c <= Math.min(lines.length - 1, i + contextLines); c++) {
|
|
4168
|
-
result.contextAfter.push([c + 1, lines[c].trimEnd()]);
|
|
4169
|
-
}
|
|
4170
|
-
}
|
|
4171
|
-
results.push(result);
|
|
4172
|
-
}
|
|
4173
|
-
}
|
|
4174
|
-
}
|
|
4175
3954
|
|
|
4176
3955
|
// src/tools/builtin/glob-files.ts
|
|
4177
|
-
import { readdirSync as readdirSync5, statSync as statSync6, existsSync as
|
|
4178
|
-
import { join as
|
|
3956
|
+
import { readdirSync as readdirSync5, statSync as statSync6, existsSync as existsSync9 } from "fs";
|
|
3957
|
+
import { join as join3, relative as relative2, basename as basename5 } from "path";
|
|
4179
3958
|
var globFilesTool = {
|
|
4180
3959
|
definition: {
|
|
4181
3960
|
name: "glob_files",
|
|
@@ -4208,7 +3987,7 @@ Results sorted by most recent modification time. Automatically skips node_module
|
|
|
4208
3987
|
const rootPath = String(args["path"] ?? process.cwd());
|
|
4209
3988
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 100));
|
|
4210
3989
|
if (!pattern) throw new ToolError("glob_files", "pattern is required");
|
|
4211
|
-
if (!
|
|
3990
|
+
if (!existsSync9(rootPath)) throw new ToolError("glob_files", `Path not found: ${rootPath}`);
|
|
4212
3991
|
const regex = globToRegex(pattern);
|
|
4213
3992
|
const matches = [];
|
|
4214
3993
|
collectMatchingFiles(rootPath, rootPath, regex, matches, maxResults);
|
|
@@ -4285,7 +4064,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
4285
4064
|
}
|
|
4286
4065
|
for (const entry of entries) {
|
|
4287
4066
|
if (results.length >= maxResults) break;
|
|
4288
|
-
const fullPath =
|
|
4067
|
+
const fullPath = join3(dirPath, entry.name);
|
|
4289
4068
|
if (entry.isDirectory()) {
|
|
4290
4069
|
if (SKIP_DIRS2.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
4291
4070
|
collectMatchingFiles(fullPath, rootPath, regex, results, maxResults);
|
|
@@ -4304,9 +4083,9 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
4304
4083
|
}
|
|
4305
4084
|
|
|
4306
4085
|
// src/tools/builtin/run-interactive.ts
|
|
4307
|
-
import { spawn as
|
|
4308
|
-
import { platform as
|
|
4309
|
-
var IS_WINDOWS4 =
|
|
4086
|
+
import { spawn as spawn3 } from "child_process";
|
|
4087
|
+
import { platform as platform3 } from "os";
|
|
4088
|
+
var IS_WINDOWS4 = platform3() === "win32";
|
|
4310
4089
|
var runInteractiveTool = {
|
|
4311
4090
|
definition: {
|
|
4312
4091
|
name: "run_interactive",
|
|
@@ -4368,7 +4147,7 @@ var runInteractiveTool = {
|
|
|
4368
4147
|
};
|
|
4369
4148
|
const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
|
|
4370
4149
|
return new Promise((resolve7) => {
|
|
4371
|
-
const child =
|
|
4150
|
+
const child = spawn3(executable, cmdArgs.map(String), {
|
|
4372
4151
|
cwd: process.cwd(),
|
|
4373
4152
|
env,
|
|
4374
4153
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -4638,8 +4417,8 @@ var webFetchTool = {
|
|
|
4638
4417
|
if (e.message.startsWith("Blocked:")) throw e;
|
|
4639
4418
|
throw new NetworkError(`Invalid URL: "${url}"`);
|
|
4640
4419
|
}
|
|
4641
|
-
const
|
|
4642
|
-
const timeoutId = setTimeout(() =>
|
|
4420
|
+
const controller = new AbortController();
|
|
4421
|
+
const timeoutId = setTimeout(() => controller.abort(), 2e4);
|
|
4643
4422
|
let rawHtml;
|
|
4644
4423
|
let finalUrl;
|
|
4645
4424
|
let contentType;
|
|
@@ -4660,7 +4439,7 @@ var webFetchTool = {
|
|
|
4660
4439
|
}
|
|
4661
4440
|
await resolveAndCheck(parsedHop.hostname);
|
|
4662
4441
|
const r = await fetch(currentUrl, {
|
|
4663
|
-
signal:
|
|
4442
|
+
signal: controller.signal,
|
|
4664
4443
|
headers: FETCH_HEADERS,
|
|
4665
4444
|
redirect: "manual",
|
|
4666
4445
|
// 手动控制重定向
|
|
@@ -5023,8 +4802,8 @@ function parseGoogleResults(html, maxResults) {
|
|
|
5023
4802
|
return results;
|
|
5024
4803
|
}
|
|
5025
4804
|
async function fetchHtml(url) {
|
|
5026
|
-
const
|
|
5027
|
-
const timer = setTimeout(() =>
|
|
4805
|
+
const controller = new AbortController();
|
|
4806
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
5028
4807
|
try {
|
|
5029
4808
|
const res = await fetch(url, {
|
|
5030
4809
|
method: "GET",
|
|
@@ -5033,7 +4812,7 @@ async function fetchHtml(url) {
|
|
|
5033
4812
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9",
|
|
5034
4813
|
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8"
|
|
5035
4814
|
},
|
|
5036
|
-
signal:
|
|
4815
|
+
signal: controller.signal
|
|
5037
4816
|
});
|
|
5038
4817
|
if (!res.ok) {
|
|
5039
4818
|
throw new NetworkError(`HTTP ${res.status} ${res.statusText}`, res.status);
|
|
@@ -5127,10 +4906,8 @@ Any of these triggers means use save_last_response, NOT write_file:
|
|
|
5127
4906
|
};
|
|
5128
4907
|
|
|
5129
4908
|
// src/tools/builtin/save-memory.ts
|
|
5130
|
-
import { join as join5 } from "path";
|
|
5131
|
-
import { homedir as homedir3 } from "os";
|
|
5132
4909
|
function getConfigDir() {
|
|
5133
|
-
return
|
|
4910
|
+
return getExecutionConfigDir();
|
|
5134
4911
|
}
|
|
5135
4912
|
function parseSensitivity(value) {
|
|
5136
4913
|
return value === "low" || value === "medium" || value === "high" ? value : void 0;
|
|
@@ -5394,15 +5171,15 @@ var googleSearchTool = {
|
|
|
5394
5171
|
url.searchParams.set("cx", cx);
|
|
5395
5172
|
url.searchParams.set("q", query);
|
|
5396
5173
|
url.searchParams.set("num", String(numResults));
|
|
5397
|
-
const
|
|
5398
|
-
const timeout = setTimeout(() =>
|
|
5174
|
+
const controller = new AbortController();
|
|
5175
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
5399
5176
|
try {
|
|
5400
5177
|
const response = await fetch(url.toString(), {
|
|
5401
5178
|
method: "GET",
|
|
5402
5179
|
headers: {
|
|
5403
5180
|
"Accept": "application/json"
|
|
5404
5181
|
},
|
|
5405
|
-
signal:
|
|
5182
|
+
signal: controller.signal
|
|
5406
5183
|
});
|
|
5407
5184
|
if (!response.ok) {
|
|
5408
5185
|
const errorBody = await response.text().catch(() => "");
|
|
@@ -5479,9 +5256,9 @@ function formatResults2(query, data, _requested) {
|
|
|
5479
5256
|
}
|
|
5480
5257
|
|
|
5481
5258
|
// src/agents/agent-config.ts
|
|
5482
|
-
import { existsSync as
|
|
5483
|
-
import { join as
|
|
5484
|
-
import { homedir as
|
|
5259
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync5 } from "fs";
|
|
5260
|
+
import { join as join4 } from "path";
|
|
5261
|
+
import { homedir as homedir3 } from "os";
|
|
5485
5262
|
var READ_ONLY_TOOLS2 = /* @__PURE__ */ new Set([
|
|
5486
5263
|
"read_file",
|
|
5487
5264
|
"list_dir",
|
|
@@ -5552,13 +5329,13 @@ function normalizeName(name) {
|
|
|
5552
5329
|
function isStringArray(value) {
|
|
5553
5330
|
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
5554
5331
|
}
|
|
5555
|
-
function parseAgentConfig(raw,
|
|
5332
|
+
function parseAgentConfig(raw, source2, path3) {
|
|
5556
5333
|
if (!raw || typeof raw !== "object") return null;
|
|
5557
5334
|
const obj = raw;
|
|
5558
5335
|
if (typeof obj.name !== "string" || obj.name.trim() === "") return null;
|
|
5559
5336
|
const cfg = {
|
|
5560
5337
|
name: obj.name.trim(),
|
|
5561
|
-
source,
|
|
5338
|
+
source: source2,
|
|
5562
5339
|
path: path3
|
|
5563
5340
|
};
|
|
5564
5341
|
if (typeof obj.description === "string") cfg.description = obj.description;
|
|
@@ -5574,15 +5351,15 @@ function parseAgentConfig(raw, source, path3) {
|
|
|
5574
5351
|
if (typeof obj.contextPolicy === "string") cfg.contextPolicy = obj.contextPolicy;
|
|
5575
5352
|
return cfg;
|
|
5576
5353
|
}
|
|
5577
|
-
function loadAgentDir(dir,
|
|
5578
|
-
if (!
|
|
5354
|
+
function loadAgentDir(dir, source2) {
|
|
5355
|
+
if (!existsSync10(dir)) return [];
|
|
5579
5356
|
const out = [];
|
|
5580
5357
|
for (const file of readdirSync6(dir)) {
|
|
5581
5358
|
if (!file.endsWith(".json")) continue;
|
|
5582
|
-
const path3 =
|
|
5359
|
+
const path3 = join4(dir, file);
|
|
5583
5360
|
try {
|
|
5584
|
-
const parsed = JSON.parse(
|
|
5585
|
-
const cfg = parseAgentConfig(parsed,
|
|
5361
|
+
const parsed = JSON.parse(readFileSync5(path3, "utf-8"));
|
|
5362
|
+
const cfg = parseAgentConfig(parsed, source2, path3);
|
|
5586
5363
|
if (cfg) out.push(cfg);
|
|
5587
5364
|
} catch {
|
|
5588
5365
|
}
|
|
@@ -5591,8 +5368,8 @@ function loadAgentDir(dir, source) {
|
|
|
5591
5368
|
}
|
|
5592
5369
|
function getAgentDirs(configDir, cwd = process.cwd()) {
|
|
5593
5370
|
return {
|
|
5594
|
-
user:
|
|
5595
|
-
project:
|
|
5371
|
+
user: join4(configDir ?? join4(homedir3(), CONFIG_DIR_NAME), "agents"),
|
|
5372
|
+
project: join4(cwd, CONFIG_DIR_NAME, "agents")
|
|
5596
5373
|
};
|
|
5597
5374
|
}
|
|
5598
5375
|
function listAgentConfigs(configDir, cwd = process.cwd()) {
|
|
@@ -6095,9 +5872,8 @@ var spawnAgentTool = {
|
|
|
6095
5872
|
};
|
|
6096
5873
|
|
|
6097
5874
|
// src/tools/builtin/task-manager.ts
|
|
6098
|
-
import { spawn as
|
|
5875
|
+
import { spawn as spawn4 } from "child_process";
|
|
6099
5876
|
import { randomUUID } from "crypto";
|
|
6100
|
-
import { platform as platform5 } from "os";
|
|
6101
5877
|
var MAX_OUTPUT_CHARS = 1e4;
|
|
6102
5878
|
var MAX_OUTPUT_BYTES = 64 * 1024;
|
|
6103
5879
|
var MAX_TASKS = 20;
|
|
@@ -6116,14 +5892,16 @@ function decodeField(chunks) {
|
|
|
6116
5892
|
}
|
|
6117
5893
|
function appendOutput(task, field, chunk) {
|
|
6118
5894
|
const chunks = field === "stdout" ? task._stdoutChunks : task._stderrChunks;
|
|
6119
|
-
chunks.push(chunk);
|
|
5895
|
+
chunks.push(chunk.length > MAX_OUTPUT_BYTES ? chunk.subarray(-MAX_OUTPUT_BYTES) : chunk);
|
|
6120
5896
|
capChunks(chunks);
|
|
6121
5897
|
task[field] = decodeField(chunks);
|
|
6122
5898
|
}
|
|
6123
5899
|
function createTask(command, description) {
|
|
5900
|
+
if ([...tasks.values()].filter((t) => t._active && t.owner === getExecutionConfigDir()).length >= 10) throw new Error("Background task limit reached (10 running per user).");
|
|
5901
|
+
if ([...tasks.values()].filter((t) => t._active).length >= MAX_TASKS) throw new Error("Background task limit reached (20 running). Stop a task before creating another.");
|
|
6124
5902
|
if (tasks.size >= MAX_TASKS) {
|
|
6125
5903
|
for (const [id2, t] of tasks) {
|
|
6126
|
-
if (t.
|
|
5904
|
+
if (!t._active) {
|
|
6127
5905
|
tasks.delete(id2);
|
|
6128
5906
|
break;
|
|
6129
5907
|
}
|
|
@@ -6131,16 +5909,19 @@ function createTask(command, description) {
|
|
|
6131
5909
|
}
|
|
6132
5910
|
const id = randomUUID().slice(0, 8);
|
|
6133
5911
|
const { shell, args } = shellInvocation(command);
|
|
6134
|
-
const proc =
|
|
5912
|
+
const proc = spawn4(shell, args, {
|
|
6135
5913
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6136
|
-
detached:
|
|
5914
|
+
detached: process.platform !== "win32",
|
|
5915
|
+
windowsHide: true,
|
|
6137
5916
|
env: { ...process.env, PYTHONUTF8: "1", PYTHONIOENCODING: "utf-8" }
|
|
6138
5917
|
});
|
|
6139
5918
|
const task = {
|
|
6140
5919
|
id,
|
|
5920
|
+
owner: getExecutionConfigDir(),
|
|
6141
5921
|
command,
|
|
6142
5922
|
description,
|
|
6143
5923
|
process: proc,
|
|
5924
|
+
_active: true,
|
|
6144
5925
|
startTime: Date.now(),
|
|
6145
5926
|
endTime: null,
|
|
6146
5927
|
status: "running",
|
|
@@ -6153,11 +5934,13 @@ function createTask(command, description) {
|
|
|
6153
5934
|
proc.stdout?.on("data", (chunk) => appendOutput(task, "stdout", chunk));
|
|
6154
5935
|
proc.stderr?.on("data", (chunk) => appendOutput(task, "stderr", chunk));
|
|
6155
5936
|
proc.on("close", (code) => {
|
|
5937
|
+
task._active = false;
|
|
6156
5938
|
task.endTime = Date.now();
|
|
6157
5939
|
task.exitCode = code;
|
|
6158
|
-
task.status = code === 0 ? "completed" : "failed";
|
|
5940
|
+
if (task.status !== "stopped") task.status = code === 0 ? "completed" : "failed";
|
|
6159
5941
|
});
|
|
6160
5942
|
proc.on("error", (err) => {
|
|
5943
|
+
task._active = false;
|
|
6161
5944
|
task.endTime = Date.now();
|
|
6162
5945
|
task.status = "failed";
|
|
6163
5946
|
task.stderr += `
|
|
@@ -6167,43 +5950,20 @@ Process error: ${err.message}`;
|
|
|
6167
5950
|
return task;
|
|
6168
5951
|
}
|
|
6169
5952
|
function listTasks() {
|
|
6170
|
-
return [...tasks.values()].map(
|
|
6171
|
-
({ process: _p, _stdoutChunks: _o, _stderrChunks: _e, ...rest }) => rest
|
|
5953
|
+
return [...tasks.values()].filter((t) => t.owner === getExecutionConfigDir()).map(
|
|
5954
|
+
({ process: _p, _stdoutChunks: _o, _stderrChunks: _e, _active: _a, ...rest }) => rest
|
|
6172
5955
|
);
|
|
6173
5956
|
}
|
|
6174
5957
|
function getTaskOutput(id) {
|
|
6175
5958
|
const task = tasks.get(id);
|
|
6176
|
-
if (!task) return null;
|
|
5959
|
+
if (!task || task.owner !== getExecutionConfigDir()) return null;
|
|
6177
5960
|
return { stdout: task.stdout, stderr: task.stderr, status: task.status };
|
|
6178
5961
|
}
|
|
6179
5962
|
function stopTask(id) {
|
|
6180
5963
|
const task = tasks.get(id);
|
|
6181
|
-
if (!task || task.status !== "running") return false;
|
|
5964
|
+
if (!task || task.owner !== getExecutionConfigDir() || task.status !== "running") return false;
|
|
6182
5965
|
try {
|
|
6183
|
-
|
|
6184
|
-
if (platform5() === "win32" && proc.pid) {
|
|
6185
|
-
try {
|
|
6186
|
-
spawn5("taskkill", ["/PID", String(proc.pid), "/T", "/F"], {
|
|
6187
|
-
windowsHide: true,
|
|
6188
|
-
stdio: "ignore"
|
|
6189
|
-
});
|
|
6190
|
-
} catch {
|
|
6191
|
-
}
|
|
6192
|
-
try {
|
|
6193
|
-
proc.kill();
|
|
6194
|
-
} catch {
|
|
6195
|
-
}
|
|
6196
|
-
} else {
|
|
6197
|
-
proc.kill("SIGTERM");
|
|
6198
|
-
setTimeout(() => {
|
|
6199
|
-
if (proc.exitCode === null && proc.signalCode === null) {
|
|
6200
|
-
try {
|
|
6201
|
-
proc.kill("SIGKILL");
|
|
6202
|
-
} catch {
|
|
6203
|
-
}
|
|
6204
|
-
}
|
|
6205
|
-
}, 3e3).unref();
|
|
6206
|
-
}
|
|
5966
|
+
killProcessTree(task.process, true);
|
|
6207
5967
|
task.status = "stopped";
|
|
6208
5968
|
task.endTime = Date.now();
|
|
6209
5969
|
return true;
|
|
@@ -6311,14 +6071,14 @@ var taskStopTool = {
|
|
|
6311
6071
|
|
|
6312
6072
|
// src/tools/builtin/git-tools.ts
|
|
6313
6073
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
6314
|
-
import { existsSync as
|
|
6315
|
-
import { join as
|
|
6074
|
+
import { existsSync as existsSync11 } from "fs";
|
|
6075
|
+
import { join as join5 } from "path";
|
|
6316
6076
|
function assertGitRepo(cwd) {
|
|
6317
6077
|
let dir = cwd;
|
|
6318
6078
|
const root = dir.split(/[\\/]/)[0] + (dir.includes("\\") ? "\\" : "/");
|
|
6319
6079
|
while (dir && dir !== root) {
|
|
6320
|
-
if (
|
|
6321
|
-
const parent =
|
|
6080
|
+
if (existsSync11(join5(dir, ".git"))) return;
|
|
6081
|
+
const parent = join5(dir, "..");
|
|
6322
6082
|
if (parent === dir) break;
|
|
6323
6083
|
dir = parent;
|
|
6324
6084
|
}
|
|
@@ -6583,7 +6343,7 @@ ${commitOutput.trim()}`;
|
|
|
6583
6343
|
};
|
|
6584
6344
|
|
|
6585
6345
|
// src/tools/builtin/notebook-edit.ts
|
|
6586
|
-
import { readFileSync as
|
|
6346
|
+
import { readFileSync as readFileSync6, existsSync as existsSync12 } from "fs";
|
|
6587
6347
|
import { writeFile } from "fs/promises";
|
|
6588
6348
|
import { resolve as resolve6, extname as extname2 } from "path";
|
|
6589
6349
|
var notebookEditTool = {
|
|
@@ -6638,10 +6398,10 @@ var notebookEditTool = {
|
|
|
6638
6398
|
if (extname2(absPath).toLowerCase() !== ".ipynb") {
|
|
6639
6399
|
throw new ToolError("notebook_edit", "path must point to a .ipynb file");
|
|
6640
6400
|
}
|
|
6641
|
-
if (!
|
|
6401
|
+
if (!existsSync12(absPath)) {
|
|
6642
6402
|
throw new ToolError("notebook_edit", `Notebook not found: ${filePath}`);
|
|
6643
6403
|
}
|
|
6644
|
-
const raw =
|
|
6404
|
+
const raw = readFileSync6(absPath, "utf-8");
|
|
6645
6405
|
const nb = parseNotebook(raw);
|
|
6646
6406
|
const cellIdx0 = cellIndexRaw - 1;
|
|
6647
6407
|
undoStack.push(absPath, `notebook_edit (${action}): ${filePath}`);
|
|
@@ -6967,8 +6727,6 @@ ${lines.join("\n")}`;
|
|
|
6967
6727
|
};
|
|
6968
6728
|
|
|
6969
6729
|
// src/tools/builtin/recall-memory.ts
|
|
6970
|
-
import { join as join8 } from "path";
|
|
6971
|
-
import { homedir as homedir5 } from "os";
|
|
6972
6730
|
function formatHit(h, i) {
|
|
6973
6731
|
const ts = h.chunk.timestamp.slice(0, 16).replace("T", " ");
|
|
6974
6732
|
const title = h.chunk.sessionTitle ? ` \xB7 ${h.chunk.sessionTitle}` : "";
|
|
@@ -7018,7 +6776,7 @@ var recallMemoryTool = {
|
|
|
7018
6776
|
const excludeCurrent = Boolean(args["excludeCurrentSession"]);
|
|
7019
6777
|
const currentId = args["currentSessionId"] ? String(args["currentSessionId"]) : void 0;
|
|
7020
6778
|
const minScore = args["minScore"] !== void 0 ? Number(args["minScore"]) : 0.25;
|
|
7021
|
-
const configDir =
|
|
6779
|
+
const configDir = getExecutionConfigDir();
|
|
7022
6780
|
let persistentSection = "";
|
|
7023
6781
|
try {
|
|
7024
6782
|
const persistentHits = searchPersistentMemories(configDir, query, process.cwd(), 3);
|
|
@@ -7072,8 +6830,8 @@ function estimateToolDefinitionTokens(def) {
|
|
|
7072
6830
|
|
|
7073
6831
|
// src/tools/registry.ts
|
|
7074
6832
|
import { pathToFileURL } from "url";
|
|
7075
|
-
import { existsSync as
|
|
7076
|
-
import { join as
|
|
6833
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync3, readdirSync as readdirSync7 } from "fs";
|
|
6834
|
+
import { join as join6 } from "path";
|
|
7077
6835
|
var ToolRegistry = class {
|
|
7078
6836
|
tools = /* @__PURE__ */ new Map();
|
|
7079
6837
|
pluginToolNames = /* @__PURE__ */ new Set();
|
|
@@ -7234,7 +6992,7 @@ var ToolRegistry = class {
|
|
|
7234
6992
|
* Returns the number of successfully loaded plugins.
|
|
7235
6993
|
*/
|
|
7236
6994
|
async loadPlugins(pluginsDir, allowPlugins = false) {
|
|
7237
|
-
if (!
|
|
6995
|
+
if (!existsSync13(pluginsDir)) {
|
|
7238
6996
|
try {
|
|
7239
6997
|
mkdirSync3(pluginsDir, { recursive: true });
|
|
7240
6998
|
} catch {
|
|
@@ -7260,12 +7018,12 @@ var ToolRegistry = class {
|
|
|
7260
7018
|
process.stderr.write(
|
|
7261
7019
|
`
|
|
7262
7020
|
[plugins] \u26A0 Loading ${files.length} plugin(s) with FULL system privileges:
|
|
7263
|
-
` + files.map((f) => ` + ${
|
|
7021
|
+
` + files.map((f) => ` + ${join6(pluginsDir, f)}`).join("\n") + "\n\n"
|
|
7264
7022
|
);
|
|
7265
7023
|
let loaded = 0;
|
|
7266
7024
|
for (const file of files) {
|
|
7267
7025
|
try {
|
|
7268
|
-
const fileUrl = pathToFileURL(
|
|
7026
|
+
const fileUrl = pathToFileURL(join6(pluginsDir, file)).href;
|
|
7269
7027
|
const mod = await import(fileUrl);
|
|
7270
7028
|
const tool = mod.tool ?? mod.default?.tool ?? mod.default;
|
|
7271
7029
|
if (!tool || typeof tool.execute !== "function" || !tool.definition?.name) {
|
|
@@ -7306,10 +7064,6 @@ export {
|
|
|
7306
7064
|
requestAgentStop,
|
|
7307
7065
|
setPreferredAgentName,
|
|
7308
7066
|
getPreferredAgentName,
|
|
7309
|
-
isInterrupted,
|
|
7310
|
-
requestInterrupt,
|
|
7311
|
-
resetInterrupt,
|
|
7312
|
-
runWithSessionKey,
|
|
7313
7067
|
clearBashSession,
|
|
7314
7068
|
rlInternal,
|
|
7315
7069
|
groupCallsByPhase,
|