jinzd-ai-cli 0.4.223 → 0.4.225
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/dist/{batch-PJIRZJCT.js → batch-OWM7PN4L.js} +2 -2
- package/dist/{chat-index-FDSGKWQV.js → chat-index-O56HDGFI.js} +2 -2
- package/dist/{chat-index-PS274XM7.js → chat-index-WSI7ULRQ.js} +1 -1
- package/dist/{chunk-WDUKU5HH.js → chunk-6ISALPIH.js} +1 -1
- package/dist/{chunk-SLSWPBK3.js → chunk-B5TYJO7V.js} +4 -1
- package/dist/{chunk-OPAOQZDC.js → chunk-BWCZYPEU.js} +2 -2
- package/dist/{chunk-OJXYL2W2.js → chunk-DEHVRQWW.js} +1 -1
- package/dist/{chunk-GXAGBILB.js → chunk-DUKZBAI4.js} +1 -1
- package/dist/{chunk-5ZPO47YE.js → chunk-IZ4VM2P5.js} +281 -41
- package/dist/{chunk-VHY6NVMQ.js → chunk-LF3OUJHK.js} +4 -1
- package/dist/{chunk-GH37CLOE.js → chunk-M4QZYFPN.js} +1 -1
- package/dist/{chunk-35AVZVXZ.js → chunk-MFFMRTP6.js} +3 -3
- package/dist/{chunk-TB4W4Y4T.js → chunk-NVUCDUXE.js} +1 -1
- package/dist/{chunk-PNFOWBKL.js → chunk-Q3XNGXNR.js} +3 -3
- package/dist/{chunk-5GTWZ4QF.js → chunk-QYQCCIBT.js} +1 -1
- package/dist/{chunk-ZILWADNL.js → chunk-RC7FBLFT.js} +1 -1
- package/dist/{chunk-OABKF7MR.js → chunk-YENINV7F.js} +1 -1
- package/dist/{chunk-RGL2KKCO.js → chunk-YUGXAALR.js} +1 -1
- package/dist/{ci-ESZOGOGZ.js → ci-RTGUV5C3.js} +4 -4
- package/dist/{ci-format-TIDA4V7T.js → ci-format-QDBP5WBU.js} +2 -2
- package/dist/{constants-VFBSBHFO.js → constants-P4NBXYN5.js} +1 -1
- package/dist/{doctor-cli-W3I33E4Q.js → doctor-cli-SEX44HGI.js} +4 -4
- package/dist/electron-server.js +285 -55
- package/dist/{hub-7BLT2JUU.js → hub-FAKZZQGX.js} +2 -2
- package/dist/index.js +45 -26
- package/dist/{persist-GJ2JGZFR.js → persist-XUXIPYUU.js} +3 -3
- package/dist/{pr-7YET7ODT.js → pr-DK6ENTZN.js} +4 -4
- package/dist/{run-tests-HGBTHWNT.js → run-tests-COCXP4B6.js} +2 -2
- package/dist/{run-tests-4PNOUHC3.js → run-tests-P6F27SWN.js} +1 -1
- package/dist/{server-AN7HZVNG.js → server-BG3J7GFG.js} +22 -16
- package/dist/{server-APQHU4TR.js → server-J4W6UZXJ.js} +6 -6
- package/dist/{task-orchestrator-L7LBMQUQ.js → task-orchestrator-6LKQAS74.js} +6 -6
- package/dist/{usage-BTP5SSGC.js → usage-IPFSL5WT.js} +2 -2
- package/dist/web/client/app.js +3 -2
- package/dist/web/client/util.js +42 -0
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6ISALPIH.js";
|
|
5
5
|
import "./chunk-5ULLIOVC.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-DUKZBAI4.js";
|
|
7
7
|
import {
|
|
8
8
|
atomicWriteFileSync
|
|
9
9
|
} from "./chunk-IW3Q7AE5.js";
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
getChatIndexStatus,
|
|
7
7
|
loadChatIndex,
|
|
8
8
|
searchChatMemory
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-NVUCDUXE.js";
|
|
10
10
|
import "./chunk-KHYD3WXE.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-B5TYJO7V.js";
|
|
12
12
|
import "./chunk-IW3Q7AE5.js";
|
|
13
13
|
export {
|
|
14
14
|
buildChatIndex,
|
|
@@ -38,16 +38,19 @@ var DEFAULT_PATTERNS = [
|
|
|
38
38
|
// Bearer <token> in Authorization headers
|
|
39
39
|
{ kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
|
|
40
40
|
// Private key PEM blocks — catch the header+footer together
|
|
41
|
-
|
|
41
|
+
// P2-PERF-02: PEM bodies use strict Base64 + =\n — narrowed char class avoids backtracking
|
|
42
|
+
{ kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[ \t\n\r]*[A-Za-z0-9+/=\n\r-]*[ \t\n\r]*-----END [A-Z ]*PRIVATE KEY-----/g }
|
|
42
43
|
];
|
|
43
44
|
var MAX_CUSTOM = 32;
|
|
44
45
|
var MAX_PATTERN_LEN = 500;
|
|
45
46
|
var SUSPICIOUS_REDOS = /\([^)]*[+*][^)]*\)\s*[+*{]/;
|
|
47
|
+
var MAX_REDACT_INPUT = 512e3;
|
|
46
48
|
function render(placeholder, kind) {
|
|
47
49
|
return placeholder.replace("{kind}", kind);
|
|
48
50
|
}
|
|
49
51
|
function redactString(input, options) {
|
|
50
52
|
if (!options.enabled || !input) return { redacted: input, hits: [] };
|
|
53
|
+
if (input.length > MAX_REDACT_INPUT) return { redacted: input, hits: [] };
|
|
51
54
|
const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
|
|
52
55
|
const customSrcs = (options.customRegexes ?? []).slice(0, MAX_CUSTOM);
|
|
53
56
|
const patterns = [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
truncateForPersist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IZ4VM2P5.js";
|
|
5
5
|
import {
|
|
6
6
|
APP_NAME,
|
|
7
7
|
CONFIG_DIR_NAME,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MCP_PROTOCOL_VERSION,
|
|
12
12
|
MCP_TOOL_PREFIX,
|
|
13
13
|
VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-DUKZBAI4.js";
|
|
15
15
|
import {
|
|
16
16
|
atomicWriteFileSync
|
|
17
17
|
} from "./chunk-IW3Q7AE5.js";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
runHook,
|
|
15
15
|
runLifecycleHooks,
|
|
16
16
|
runTool
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YUGXAALR.js";
|
|
18
18
|
import {
|
|
19
19
|
getDangerLevel,
|
|
20
20
|
isFileWriteTool,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
} from "./chunk-4BKXL7SM.js";
|
|
34
34
|
import {
|
|
35
35
|
runTestsTool
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-RC7FBLFT.js";
|
|
37
37
|
import {
|
|
38
38
|
CONFIG_DIR_NAME,
|
|
39
39
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -43,23 +43,219 @@ import {
|
|
|
43
43
|
SUBAGENT_ALLOWED_TOOLS,
|
|
44
44
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
45
45
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-DUKZBAI4.js";
|
|
47
47
|
import {
|
|
48
48
|
loadChatIndex,
|
|
49
49
|
searchChatMemory
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-NVUCDUXE.js";
|
|
51
51
|
import {
|
|
52
52
|
DEFAULT_PATTERNS,
|
|
53
53
|
redactString
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-B5TYJO7V.js";
|
|
55
55
|
import {
|
|
56
56
|
atomicWriteFileSync
|
|
57
57
|
} from "./chunk-IW3Q7AE5.js";
|
|
58
58
|
|
|
59
|
-
// src/tools/
|
|
59
|
+
// src/tools/shell-pool.ts
|
|
60
60
|
import { spawn } from "child_process";
|
|
61
|
+
import { platform } from "os";
|
|
62
|
+
var IS_WINDOWS = platform() === "win32";
|
|
63
|
+
var SHELL = IS_WINDOWS ? "powershell.exe" : process.env["SHELL"] ?? "/bin/bash";
|
|
64
|
+
var pool = /* @__PURE__ */ new Map();
|
|
65
|
+
var IDLE_EVICT_MS = 5 * 6e4;
|
|
66
|
+
var evictionTimer = null;
|
|
67
|
+
function spawnShell(cwd) {
|
|
68
|
+
const shellArgs = IS_WINDOWS ? ["-NoProfile", "-NonInteractive", "-Command", "-"] : ["-s"];
|
|
69
|
+
const proc = spawn(SHELL, shellArgs, {
|
|
70
|
+
cwd,
|
|
71
|
+
windowsHide: true,
|
|
72
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
73
|
+
});
|
|
74
|
+
proc.on("exit", () => {
|
|
75
|
+
for (const [key, entry] of pool) {
|
|
76
|
+
if (entry.proc === proc) {
|
|
77
|
+
pool.delete(key);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return proc;
|
|
83
|
+
}
|
|
84
|
+
function startEvictionTimer() {
|
|
85
|
+
if (evictionTimer) return;
|
|
86
|
+
evictionTimer = setInterval(() => {
|
|
87
|
+
const now = Date.now();
|
|
88
|
+
for (const [key, entry] of pool) {
|
|
89
|
+
if (now - entry.lastUsed > IDLE_EVICT_MS) {
|
|
90
|
+
try {
|
|
91
|
+
entry.proc.kill();
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
pool.delete(key);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}, 6e4).unref();
|
|
98
|
+
}
|
|
99
|
+
async function execInPool(sessionKey, command, timeout, cwd, abortSignal) {
|
|
100
|
+
let entry = pool.get(sessionKey);
|
|
101
|
+
if (!entry || entry.proc.exitCode !== null || entry.cwd !== cwd) {
|
|
102
|
+
if (entry) {
|
|
103
|
+
try {
|
|
104
|
+
entry.proc.kill();
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const proc = spawnShell(cwd);
|
|
109
|
+
entry = { proc, cwd, lastUsed: Date.now() };
|
|
110
|
+
pool.set(sessionKey, entry);
|
|
111
|
+
}
|
|
112
|
+
entry.lastUsed = Date.now();
|
|
113
|
+
startEvictionTimer();
|
|
114
|
+
const id = `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
115
|
+
const markerStart = `AICLI_MARKER_START:${id}`;
|
|
116
|
+
const markerEnd = `AICLI_MARKER_END:${id}`;
|
|
117
|
+
const wrappedCmd = IS_WINDOWS ? `echo "${markerStart}"; ${command}; echo "${markerEnd}:0"` : `echo "${markerStart}"; ${command}; echo "${markerEnd}:$?"`;
|
|
118
|
+
return new Promise((resolve8) => {
|
|
119
|
+
let stdout = "";
|
|
120
|
+
let stderr = "";
|
|
121
|
+
let timedOut = false;
|
|
122
|
+
let aborted = false;
|
|
123
|
+
let resolved = false;
|
|
124
|
+
const markerStartPattern = `AICLI_MARKER_START:${id}`;
|
|
125
|
+
const markerEndPattern = `AICLI_MARKER_END:${id}`;
|
|
126
|
+
const onData = (chunk) => {
|
|
127
|
+
stdout += chunk.toString("utf-8");
|
|
128
|
+
if (!resolved && stdout.includes(markerEndPattern)) {
|
|
129
|
+
const endLine = stdout.split("\n").find((l) => l.includes(markerEndPattern));
|
|
130
|
+
const exitCode = endLine ? parseEndMarker(endLine, markerEndPattern) : null;
|
|
131
|
+
stdout = stripMarkerOutput(stdout, markerStartPattern, markerEndPattern);
|
|
132
|
+
resolved = true;
|
|
133
|
+
cleanup();
|
|
134
|
+
resolve8({ stdout, stderr, exitCode, timedOut, aborted });
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const onErr = (chunk) => {
|
|
138
|
+
stderr += chunk.toString("utf-8");
|
|
139
|
+
};
|
|
140
|
+
const proc = entry.proc;
|
|
141
|
+
proc.stdout?.on("data", onData);
|
|
142
|
+
proc.stderr?.on("data", onErr);
|
|
143
|
+
const timeoutTimer = setTimeout(() => {
|
|
144
|
+
if (resolved) return;
|
|
145
|
+
timedOut = true;
|
|
146
|
+
resolved = true;
|
|
147
|
+
stdout = stripMarkerOutput(stdout, markerStartPattern, markerEndPattern);
|
|
148
|
+
cleanup();
|
|
149
|
+
resolve8({ stdout, stderr, exitCode: null, timedOut, aborted });
|
|
150
|
+
try {
|
|
151
|
+
proc.kill();
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
pool.delete(sessionKey);
|
|
155
|
+
}, timeout);
|
|
156
|
+
const onAbort = () => {
|
|
157
|
+
if (resolved) return;
|
|
158
|
+
aborted = true;
|
|
159
|
+
resolved = true;
|
|
160
|
+
cleanup();
|
|
161
|
+
stdout = stripMarkerOutput(stdout, markerStartPattern, markerEndPattern);
|
|
162
|
+
resolve8({ stdout, stderr, exitCode: null, timedOut, aborted });
|
|
163
|
+
try {
|
|
164
|
+
proc.kill();
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
pool.delete(sessionKey);
|
|
168
|
+
};
|
|
169
|
+
if (abortSignal?.aborted) {
|
|
170
|
+
onAbort();
|
|
171
|
+
} else {
|
|
172
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
173
|
+
}
|
|
174
|
+
const onError = (err) => {
|
|
175
|
+
if (resolved) return;
|
|
176
|
+
resolved = true;
|
|
177
|
+
stderr += `
|
|
178
|
+
[pool error] ${err.message}`;
|
|
179
|
+
cleanup();
|
|
180
|
+
resolve8({ stdout, stderr, exitCode: null, timedOut, aborted });
|
|
181
|
+
pool.delete(sessionKey);
|
|
182
|
+
};
|
|
183
|
+
proc.on("error", onError);
|
|
184
|
+
function cleanup() {
|
|
185
|
+
clearTimeout(timeoutTimer);
|
|
186
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
187
|
+
proc.stdout?.removeListener("data", onData);
|
|
188
|
+
proc.stderr?.removeListener("data", onErr);
|
|
189
|
+
proc.removeListener("error", onError);
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
proc.stdin?.write(wrappedCmd + "\n");
|
|
193
|
+
} catch (err) {
|
|
194
|
+
if (!resolved) {
|
|
195
|
+
cleanup();
|
|
196
|
+
pool.delete(sessionKey);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
function parseEndMarker(line, markerEndPattern) {
|
|
202
|
+
const idx = line.lastIndexOf(":");
|
|
203
|
+
if (idx < 0) return null;
|
|
204
|
+
const code = line.slice(idx + 1).trim();
|
|
205
|
+
return /^\d+$/.test(code) ? Number(code) : null;
|
|
206
|
+
}
|
|
207
|
+
function stripMarkerOutput(stdout, startMarker, endMarker) {
|
|
208
|
+
const lines = stdout.split("\n");
|
|
209
|
+
let capturing = false;
|
|
210
|
+
const out = [];
|
|
211
|
+
for (const line of lines) {
|
|
212
|
+
if (line.includes(startMarker)) {
|
|
213
|
+
capturing = true;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (line.includes(endMarker)) {
|
|
217
|
+
capturing = false;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (capturing) {
|
|
221
|
+
out.push(line);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (!stdout.includes(endMarker) && out.length === 0) {
|
|
225
|
+
const startIdx = stdout.indexOf(startMarker);
|
|
226
|
+
if (startIdx >= 0) {
|
|
227
|
+
return stdout.slice(startIdx + startMarker.length).trimStart();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return out.join("\n").trim();
|
|
231
|
+
}
|
|
232
|
+
function cleanupPoolSession(sessionKey) {
|
|
233
|
+
const entry = pool.get(sessionKey);
|
|
234
|
+
if (!entry) return;
|
|
235
|
+
try {
|
|
236
|
+
entry.proc.kill();
|
|
237
|
+
} catch {
|
|
238
|
+
}
|
|
239
|
+
pool.delete(sessionKey);
|
|
240
|
+
}
|
|
241
|
+
function cleanupAllSessions() {
|
|
242
|
+
for (const [key, entry] of pool) {
|
|
243
|
+
try {
|
|
244
|
+
entry.proc.kill();
|
|
245
|
+
} catch {
|
|
246
|
+
}
|
|
247
|
+
pool.delete(key);
|
|
248
|
+
}
|
|
249
|
+
if (evictionTimer) {
|
|
250
|
+
clearInterval(evictionTimer);
|
|
251
|
+
evictionTimer = null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/tools/builtin/bash.ts
|
|
256
|
+
import { spawn as spawn2 } from "child_process";
|
|
61
257
|
import { existsSync as existsSync2, readdirSync, statSync } from "fs";
|
|
62
|
-
import { platform as
|
|
258
|
+
import { platform as platform3 } from "os";
|
|
63
259
|
import { resolve } from "path";
|
|
64
260
|
|
|
65
261
|
// src/tools/undo-stack.ts
|
|
@@ -212,11 +408,11 @@ function runWithSessionKey(sessionKey, fn) {
|
|
|
212
408
|
}
|
|
213
409
|
|
|
214
410
|
// src/tools/win-shell.ts
|
|
215
|
-
import { platform } from "os";
|
|
216
|
-
var
|
|
411
|
+
import { platform as platform2 } from "os";
|
|
412
|
+
var IS_WINDOWS2 = platform2() === "win32";
|
|
217
413
|
var WIN_UTF8_PREAMBLE = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; $OutputEncoding = [System.Text.Encoding]::UTF8; ";
|
|
218
414
|
function shellInvocation(command) {
|
|
219
|
-
if (
|
|
415
|
+
if (IS_WINDOWS2) {
|
|
220
416
|
return {
|
|
221
417
|
shell: "powershell.exe",
|
|
222
418
|
args: ["-NoProfile", "-NonInteractive", "-Command", WIN_UTF8_PREAMBLE + command]
|
|
@@ -235,8 +431,8 @@ function decodeWindowsBuffer(buf) {
|
|
|
235
431
|
}
|
|
236
432
|
|
|
237
433
|
// src/tools/builtin/bash.ts
|
|
238
|
-
var
|
|
239
|
-
var
|
|
434
|
+
var IS_WINDOWS3 = platform3() === "win32";
|
|
435
|
+
var SHELL2 = IS_WINDOWS3 ? "powershell.exe" : process.env["SHELL"] ?? "/bin/bash";
|
|
240
436
|
var cwdBySession = /* @__PURE__ */ new Map();
|
|
241
437
|
function getCwd() {
|
|
242
438
|
const key = getCurrentSessionKey();
|
|
@@ -250,17 +446,21 @@ function getCwd() {
|
|
|
250
446
|
function setCwd(next) {
|
|
251
447
|
cwdBySession.set(getCurrentSessionKey(), next);
|
|
252
448
|
}
|
|
449
|
+
function clearBashSession(sessionKey) {
|
|
450
|
+
cwdBySession.delete(sessionKey);
|
|
451
|
+
cleanupPoolSession(sessionKey);
|
|
452
|
+
}
|
|
253
453
|
var bashTool = {
|
|
254
454
|
definition: {
|
|
255
455
|
name: "bash",
|
|
256
|
-
description:
|
|
456
|
+
description: IS_WINDOWS3 ? `Execute commands in PowerShell. Supports mkdir, ls, cat, python, etc.
|
|
257
457
|
Important rules:
|
|
258
458
|
1. Each bash call runs in an independent subprocess; cd commands do not persist. To run in a specific directory, use the cwd parameter, or combine commands: e.g. "cd mydir; ls" or "mkdir mydir; cd mydir; New-Item file.txt".
|
|
259
459
|
2. If a command fails (returns an error or non-zero exit code), stop immediately, report the error to the user, and do not retry the same or similar commands.
|
|
260
460
|
3. Multiple commands can be combined with semicolons in a single call to reduce rounds.
|
|
261
461
|
4. To delete directories, use Remove-Item -Recurse (the system will automatically optimize to a more reliable method).
|
|
262
462
|
5. IMPORTANT: On Windows, "curl" is an alias for Invoke-WebRequest and does NOT support curl flags like -s, -X, -H. Use Invoke-RestMethod instead for HTTP requests. Example: Invoke-RestMethod -Uri "http://localhost:3000/api/health" -Method Get
|
|
263
|
-
6. NEVER run long-running / never-exiting commands through bash \u2014 they block until timeout. This includes starting an Android emulator (emulator -avd X), streaming logs (adb logcat), and dev servers (node server.js, npm run dev, metro / react-native start). Use the 'task_create' tool to run these in the background, then poll status with short bash calls (e.g. adb shell getprop sys.boot_completed).` : `Execute commands in ${
|
|
463
|
+
6. NEVER run long-running / never-exiting commands through bash \u2014 they block until timeout. This includes starting an Android emulator (emulator -avd X), streaming logs (adb logcat), and dev servers (node server.js, npm run dev, metro / react-native start). Use the 'task_create' tool to run these in the background, then poll status with short bash calls (e.g. adb shell getprop sys.boot_completed).` : `Execute commands in ${SHELL2}.
|
|
264
464
|
Important rules:
|
|
265
465
|
1. Each bash call runs in an independent subprocess; cd commands do not persist. To run in a specific directory, use the cwd parameter, or combine commands: e.g. "cd mydir && ls" or "mkdir -p mydir && touch mydir/file.txt".
|
|
266
466
|
2. If a command fails (returns an error or non-zero exit code), stop immediately, report the error to the user, and do not retry the same or similar commands.
|
|
@@ -269,7 +469,7 @@ Important rules:
|
|
|
269
469
|
parameters: {
|
|
270
470
|
command: {
|
|
271
471
|
type: "string",
|
|
272
|
-
description:
|
|
472
|
+
description: IS_WINDOWS3 ? `PowerShell command to execute. Combine multiple commands with semicolons, e.g.: "mkdir mydir; Set-Content mydir/file.txt 'content'"` : `${SHELL2} command to execute. Combine multiple commands with &&, e.g.: "mkdir -p mydir && echo 'content' > mydir/file.txt"`,
|
|
273
473
|
required: true
|
|
274
474
|
},
|
|
275
475
|
cwd: {
|
|
@@ -321,7 +521,7 @@ Important rules:
|
|
|
321
521
|
setCwd(resolved);
|
|
322
522
|
}
|
|
323
523
|
let actualCommand;
|
|
324
|
-
if (
|
|
524
|
+
if (IS_WINDOWS3) {
|
|
325
525
|
const fixedCommand = fixWindowsDeleteCommand(command);
|
|
326
526
|
actualCommand = WIN_UTF8_PREAMBLE + fixedCommand;
|
|
327
527
|
} else {
|
|
@@ -333,6 +533,44 @@ Important rules:
|
|
|
333
533
|
for (const t of parsedTargets) {
|
|
334
534
|
parsedTargetsBefore.set(t, existsSync2(t));
|
|
335
535
|
}
|
|
536
|
+
let poolResult = null;
|
|
537
|
+
try {
|
|
538
|
+
poolResult = await execInPool(
|
|
539
|
+
getCurrentSessionKey(),
|
|
540
|
+
actualCommand,
|
|
541
|
+
timeout,
|
|
542
|
+
effectiveCwd,
|
|
543
|
+
currentAbortSignal()
|
|
544
|
+
);
|
|
545
|
+
} catch {
|
|
546
|
+
poolResult = null;
|
|
547
|
+
}
|
|
548
|
+
if (poolResult) {
|
|
549
|
+
const { stdout, stderr, exitCode, timedOut, aborted } = poolResult;
|
|
550
|
+
const status = exitCode;
|
|
551
|
+
if (aborted) {
|
|
552
|
+
pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, effectiveCwd);
|
|
553
|
+
throw new ToolError(
|
|
554
|
+
"bash",
|
|
555
|
+
`Command interrupted by user (Ctrl+C).
|
|
556
|
+
|
|
557
|
+
[The user pressed Ctrl+C while this command was running. Stop the current task, summarize what was done so far, and wait for the user's next instruction. Do NOT retry this command or continue with further tool calls unless explicitly asked.]`
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
if (status !== 0 || timedOut) {
|
|
561
|
+
throw {
|
|
562
|
+
status,
|
|
563
|
+
signal: null,
|
|
564
|
+
code: timedOut ? "ETIMEDOUT" : void 0,
|
|
565
|
+
stdout: Buffer.from(stdout, "utf-8"),
|
|
566
|
+
stderr: Buffer.from(stderr, "utf-8"),
|
|
567
|
+
message: timedOut ? "ETIMEDOUT" : `exit ${status}`
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, effectiveCwd);
|
|
571
|
+
updateCwdFromCommand(command, effectiveCwd);
|
|
572
|
+
return stdout || "(command completed with no output)";
|
|
573
|
+
}
|
|
336
574
|
try {
|
|
337
575
|
const { stdout, stderr, status, signal, timedOut, aborted } = await runShell(
|
|
338
576
|
actualCommand,
|
|
@@ -367,7 +605,7 @@ Important rules:
|
|
|
367
605
|
}
|
|
368
606
|
updateCwdFromCommand(command, effectiveCwd);
|
|
369
607
|
pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, effectiveCwd);
|
|
370
|
-
const result = Buffer.isBuffer(stdout) ?
|
|
608
|
+
const result = Buffer.isBuffer(stdout) ? IS_WINDOWS3 ? decodeWindowsBuffer(stdout) : stdout.toString("utf-8") : String(stdout ?? "");
|
|
371
609
|
return result || "(command completed with no output)";
|
|
372
610
|
} catch (err) {
|
|
373
611
|
pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, effectiveCwd);
|
|
@@ -392,8 +630,8 @@ How to recover (pick ONE \u2014 do NOT retry the same command):
|
|
|
392
630
|
);
|
|
393
631
|
}
|
|
394
632
|
if ("status" in execErr && execErr.status !== void 0) {
|
|
395
|
-
const stderr =
|
|
396
|
-
const stdout =
|
|
633
|
+
const stderr = IS_WINDOWS3 && Buffer.isBuffer(execErr.stderr) ? decodeWindowsBuffer(execErr.stderr).trim() : execErr.stderr?.toString().trim() ?? "";
|
|
634
|
+
const stdout = IS_WINDOWS3 && Buffer.isBuffer(execErr.stdout) ? decodeWindowsBuffer(execErr.stdout).trim() : execErr.stdout?.toString().trim() ?? "";
|
|
397
635
|
const combined = [stdout, stderr].filter(Boolean).join("\n");
|
|
398
636
|
const hint = buildErrorHint(command, combined);
|
|
399
637
|
throw new ToolError(
|
|
@@ -429,12 +667,12 @@ function fixWindowsDeleteCommand(command) {
|
|
|
429
667
|
}
|
|
430
668
|
function buildErrorHint(command, stderr) {
|
|
431
669
|
const hints = [];
|
|
432
|
-
if (
|
|
670
|
+
if (IS_WINDOWS3 && /\|\|/.test(command) && /(\|\||is not a valid argument|不是此版本中的有效|ParserError|Unexpected token)/i.test(stderr)) {
|
|
433
671
|
hints.push(
|
|
434
672
|
`Hint: PowerShell parses '||' as a pipeline operator (PS 5.x) or logical-or (PS 7+), it CANNOT be passed inline as SQL string concatenation. Workaround: write the SQL to a local .sql file with write_file, then 'scp' it to the remote host and run 'psql -f /tmp/x.sql'. Do NOT try to escape || or wrap the command differently \u2014 it will not work.`
|
|
435
673
|
);
|
|
436
674
|
}
|
|
437
|
-
if (
|
|
675
|
+
if (IS_WINDOWS3 && /\bpython3\b/.test(command)) {
|
|
438
676
|
const trivialStderr = stderr.trim().length === 0 || /^[·\s]*exit 1\b/i.test(stderr.trim());
|
|
439
677
|
if (/(not recognized|is not recognized|无法将.*识别)/i.test(stderr) || trivialStderr) {
|
|
440
678
|
hints.push(
|
|
@@ -442,27 +680,27 @@ function buildErrorHint(command, stderr) {
|
|
|
442
680
|
);
|
|
443
681
|
}
|
|
444
682
|
}
|
|
445
|
-
if (
|
|
683
|
+
if (IS_WINDOWS3 && /^\s*ssh\b/.test(command) && /\\"/.test(command) && /(syntax error|ERROR:|ParserError|unexpected|parser|意外的|语法|不是此版本|所在位置\s+行)/i.test(stderr)) {
|
|
446
684
|
hints.push(
|
|
447
685
|
`Hint: SSH + nested quotes ("...\\"...\\"") is fragile across PS \u2192 ssh \u2192 remote-shell \u2192 psql layers. Use the file-based flow: (1) write_file locally to a .sql file, (2) 'scp x.sql root@host:/tmp/', (3) 'ssh root@host "sudo -u postgres psql -d <db> -f /tmp/x.sql"'. Or for remote-only SQL: 'ssh host "cat > /tmp/x.sql << \\'SQLEOF\\'\\n...\\nSQLEOF"' then run psql -f. Avoid inline psql -c with embedded quotes.`
|
|
448
686
|
);
|
|
449
687
|
}
|
|
450
|
-
if (
|
|
688
|
+
if (IS_WINDOWS3 && /\bmkdir\b/.test(command) && /\s-p\b/.test(command) && /(已存在|already exists|ItemExistsUnauthorizedAccessError|exists)/i.test(stderr)) {
|
|
451
689
|
hints.push(
|
|
452
690
|
`Hint: PowerShell's mkdir does not support the '-p' flag. When the directory already exists it exits with code 1. Use instead: New-Item -ItemType Directory -Force -Path <dir> ('-Force' silently succeeds even if the directory already exists, mimicking 'mkdir -p').`
|
|
453
691
|
);
|
|
454
692
|
}
|
|
455
|
-
if (
|
|
693
|
+
if (IS_WINDOWS3 && /Remove-Item/i.test(command) && /cannot find path|no such file|exit 1/i.test(stderr || command)) {
|
|
456
694
|
hints.push(
|
|
457
695
|
`Hint: On Windows, "Remove-Item ... -ErrorAction SilentlyContinue" still makes the powershell process exit 1 when no files match (even though the error is silenced). Use Test-Path as a guard: @('tmp_a.sql','tmp_b.sql','tmp_c.csv') | Where-Object { Test-Path $_ } | Remove-Item -Force \u2014 Test-Path returns a bool without raising, so missing paths are filtered out and exit code is 0.`
|
|
458
696
|
);
|
|
459
697
|
}
|
|
460
|
-
if (
|
|
698
|
+
if (IS_WINDOWS3 && /-(?:EA|ErrorAction)\s+(?:SilentlyContinue|Ignore)\b/i.test(command) && /\b(Get-ChildItem|Get-Item|Get-Content|gci|gi|gc|dir|ls)\b/i.test(command) && !/Remove-Item/i.test(command) && !/Test-Path/i.test(command) && /cannot find path|no such file|does not exist|exit 1|不存在|找不到/i.test(stderr || command)) {
|
|
461
699
|
hints.push(
|
|
462
700
|
`Hint: On Windows, "-ErrorAction SilentlyContinue" silences the error MESSAGE but does NOT change the exit code \u2014 the process still exits 1 when the path doesn't exist (because powershell.exe -NonInteractive flips the exit code on any non-terminating error, silenced or not). If you're just probing for existence, use Test-Path instead \u2014 it returns $true/$false without raising: \`if (Test-Path ./mydir) { Get-ChildItem ./mydir }\` or unconditionally use \`New-Item -ItemType Directory -Force -Path ./mydir\` which is idempotent. Don't retry the same -ErrorAction SilentlyContinue probe expecting a different result.`
|
|
463
701
|
);
|
|
464
702
|
}
|
|
465
|
-
if (
|
|
703
|
+
if (IS_WINDOWS3 && /\bWrite-(?:Content|File)\b/i.test(command) && /(not recognized|无法将.*识别|不是.*cmdlet|CommandNotFoundException)/i.test(stderr)) {
|
|
466
704
|
hints.push(
|
|
467
705
|
`Hint: 'Write-Content' / 'Write-File' are NOT PowerShell cmdlets (common LLM hallucination). To write a file, prefer the built-in 'write_file' tool \u2014 it handles encoding/escaping cleanly and supports diff preview. If you must stay in bash: use 'Set-Content -Path <file> -Value <string> -Encoding utf8' (overwrites) or 'Add-Content' (appends) or 'Out-File -FilePath <file> -Encoding utf8'.`
|
|
468
706
|
);
|
|
@@ -574,8 +812,8 @@ function pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, cwd) {
|
|
|
574
812
|
}
|
|
575
813
|
function runShell(command, opts) {
|
|
576
814
|
return new Promise((resolvePromise) => {
|
|
577
|
-
const shellArgs =
|
|
578
|
-
const child =
|
|
815
|
+
const shellArgs = IS_WINDOWS3 ? ["-NoProfile", "-NonInteractive", "-Command", command] : ["-c", command];
|
|
816
|
+
const child = spawn2(SHELL2, shellArgs, {
|
|
579
817
|
cwd: opts.cwd,
|
|
580
818
|
env: opts.env,
|
|
581
819
|
windowsHide: true,
|
|
@@ -637,9 +875,9 @@ function runShell(command, opts) {
|
|
|
637
875
|
}
|
|
638
876
|
function killChild(child) {
|
|
639
877
|
if (child.killed || child.exitCode !== null) return;
|
|
640
|
-
if (
|
|
878
|
+
if (IS_WINDOWS3 && child.pid) {
|
|
641
879
|
try {
|
|
642
|
-
|
|
880
|
+
spawn2("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
|
|
643
881
|
windowsHide: true,
|
|
644
882
|
stdio: "ignore"
|
|
645
883
|
});
|
|
@@ -3626,9 +3864,9 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
3626
3864
|
}
|
|
3627
3865
|
|
|
3628
3866
|
// src/tools/builtin/run-interactive.ts
|
|
3629
|
-
import { spawn as
|
|
3630
|
-
import { platform as
|
|
3631
|
-
var
|
|
3867
|
+
import { spawn as spawn3 } from "child_process";
|
|
3868
|
+
import { platform as platform4 } from "os";
|
|
3869
|
+
var IS_WINDOWS4 = platform4() === "win32";
|
|
3632
3870
|
var runInteractiveTool = {
|
|
3633
3871
|
definition: {
|
|
3634
3872
|
name: "run_interactive",
|
|
@@ -3690,7 +3928,7 @@ var runInteractiveTool = {
|
|
|
3690
3928
|
};
|
|
3691
3929
|
const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
|
|
3692
3930
|
return new Promise((resolve8) => {
|
|
3693
|
-
const child =
|
|
3931
|
+
const child = spawn3(executable, cmdArgs.map(String), {
|
|
3694
3932
|
cwd: process.cwd(),
|
|
3695
3933
|
env,
|
|
3696
3934
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -3708,7 +3946,7 @@ var runInteractiveTool = {
|
|
|
3708
3946
|
let lineIdx = 0;
|
|
3709
3947
|
const writeNextLine = () => {
|
|
3710
3948
|
if (lineIdx < stdinLines.length && !child.stdin.destroyed) {
|
|
3711
|
-
const line = stdinLines[lineIdx++] + (
|
|
3949
|
+
const line = stdinLines[lineIdx++] + (IS_WINDOWS4 ? "\r\n" : "\n");
|
|
3712
3950
|
const canContinue = child.stdin.write(line);
|
|
3713
3951
|
if (canContinue) {
|
|
3714
3952
|
setTimeout(writeNextLine, 150);
|
|
@@ -5549,9 +5787,9 @@ var spawnAgentTool = {
|
|
|
5549
5787
|
};
|
|
5550
5788
|
|
|
5551
5789
|
// src/tools/builtin/task-manager.ts
|
|
5552
|
-
import { spawn as
|
|
5790
|
+
import { spawn as spawn4 } from "child_process";
|
|
5553
5791
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5554
|
-
import { platform as
|
|
5792
|
+
import { platform as platform5 } from "os";
|
|
5555
5793
|
var MAX_OUTPUT_CHARS = 1e4;
|
|
5556
5794
|
var MAX_OUTPUT_BYTES = 64 * 1024;
|
|
5557
5795
|
var MAX_TASKS = 20;
|
|
@@ -5565,7 +5803,7 @@ function capChunks(chunks) {
|
|
|
5565
5803
|
}
|
|
5566
5804
|
function decodeField(chunks) {
|
|
5567
5805
|
const buf = Buffer.concat(chunks);
|
|
5568
|
-
const text =
|
|
5806
|
+
const text = IS_WINDOWS2 ? decodeWindowsBuffer(buf) : buf.toString("utf-8");
|
|
5569
5807
|
return text.length > MAX_OUTPUT_CHARS ? "... [truncated] ...\n" + text.slice(-MAX_OUTPUT_CHARS) : text;
|
|
5570
5808
|
}
|
|
5571
5809
|
function appendOutput(task, field, chunk) {
|
|
@@ -5585,7 +5823,7 @@ function createTask(command, description) {
|
|
|
5585
5823
|
}
|
|
5586
5824
|
const id = randomUUID2().slice(0, 8);
|
|
5587
5825
|
const { shell, args } = shellInvocation(command);
|
|
5588
|
-
const proc =
|
|
5826
|
+
const proc = spawn4(shell, args, {
|
|
5589
5827
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5590
5828
|
detached: false,
|
|
5591
5829
|
env: { ...process.env, PYTHONUTF8: "1", PYTHONIOENCODING: "utf-8" }
|
|
@@ -5635,9 +5873,9 @@ function stopTask(id) {
|
|
|
5635
5873
|
if (!task || task.status !== "running") return false;
|
|
5636
5874
|
try {
|
|
5637
5875
|
const proc = task.process;
|
|
5638
|
-
if (
|
|
5876
|
+
if (platform5() === "win32" && proc.pid) {
|
|
5639
5877
|
try {
|
|
5640
|
-
|
|
5878
|
+
spawn4("taskkill", ["/PID", String(proc.pid), "/T", "/F"], {
|
|
5641
5879
|
windowsHide: true,
|
|
5642
5880
|
stdio: "ignore"
|
|
5643
5881
|
});
|
|
@@ -6733,6 +6971,7 @@ var ToolRegistry = class {
|
|
|
6733
6971
|
};
|
|
6734
6972
|
|
|
6735
6973
|
export {
|
|
6974
|
+
cleanupAllSessions,
|
|
6736
6975
|
initTheme,
|
|
6737
6976
|
theme,
|
|
6738
6977
|
undoStack,
|
|
@@ -6755,6 +6994,7 @@ export {
|
|
|
6755
6994
|
requestInterrupt,
|
|
6756
6995
|
resetInterrupt,
|
|
6757
6996
|
runWithSessionKey,
|
|
6997
|
+
clearBashSession,
|
|
6758
6998
|
rlInternal,
|
|
6759
6999
|
groupCallsByPhase,
|
|
6760
7000
|
runSafePhases,
|
|
@@ -51,16 +51,19 @@ var DEFAULT_PATTERNS = [
|
|
|
51
51
|
// Bearer <token> in Authorization headers
|
|
52
52
|
{ kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
|
|
53
53
|
// Private key PEM blocks — catch the header+footer together
|
|
54
|
-
|
|
54
|
+
// P2-PERF-02: PEM bodies use strict Base64 + =\n — narrowed char class avoids backtracking
|
|
55
|
+
{ kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[ \t\n\r]*[A-Za-z0-9+/=\n\r-]*[ \t\n\r]*-----END [A-Z ]*PRIVATE KEY-----/g }
|
|
55
56
|
];
|
|
56
57
|
var MAX_CUSTOM = 32;
|
|
57
58
|
var MAX_PATTERN_LEN = 500;
|
|
58
59
|
var SUSPICIOUS_REDOS = /\([^)]*[+*][^)]*\)\s*[+*{]/;
|
|
60
|
+
var MAX_REDACT_INPUT = 512e3;
|
|
59
61
|
function render(placeholder, kind) {
|
|
60
62
|
return placeholder.replace("{kind}", kind);
|
|
61
63
|
}
|
|
62
64
|
function redactString(input, options) {
|
|
63
65
|
if (!options.enabled || !input) return { redacted: input, hits: [] };
|
|
66
|
+
if (input.length > MAX_REDACT_INPUT) return { redacted: input, hits: [] };
|
|
64
67
|
const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
|
|
65
68
|
const customSrcs = (options.customRegexes ?? []).slice(0, MAX_CUSTOM);
|
|
66
69
|
const patterns = [
|