@wrongstack/tools 0.265.1 → 0.268.0
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/builtin.js +276 -144
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.js +94 -82
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/codebase-index/worker.js +94 -82
- package/dist/codebase-index/worker.js.map +1 -1
- package/dist/edit.d.ts +1 -0
- package/dist/edit.js +12 -7
- package/dist/edit.js.map +1 -1
- package/dist/exec.js +63 -12
- package/dist/exec.js.map +1 -1
- package/dist/git.d.ts +7 -0
- package/dist/git.js +19 -2
- package/dist/git.js.map +1 -1
- package/dist/index.js +281 -147
- package/dist/index.js.map +1 -1
- package/dist/outdated.js +5 -2
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +276 -144
- package/dist/pack.js.map +1 -1
- package/dist/read.d.ts +3 -0
- package/dist/read.js +103 -6
- package/dist/read.js.map +1 -1
- package/dist/tool-icons.js +2 -2
- package/dist/tool-icons.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as fs4 from 'node:fs/promises';
|
|
2
|
+
import { toErrorMessage } from '@wrongstack/core/utils';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
import { resolve, sep, dirname, join } from 'node:path';
|
|
4
5
|
import * as Core from '@wrongstack/core';
|
|
5
|
-
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, expectDefined, buildChildEnv, isPrivateIPv4, isPrivateIPv6, loadPlan, setPlanItemStatus, savePlan, loadTasks, saveTasks, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, mutateTasks, formatTaskList, formatPlan, recordPackageAction, detectPackageEcosystem, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
6
|
-
import { toErrorMessage } from '@wrongstack/core/utils';
|
|
6
|
+
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, expectDefined, buildChildEnv, isPrivateIPv4, isPrivateIPv6, loadPlan, setPlanItemStatus, savePlan, loadTasks, saveTasks, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, mutateTasks, formatTaskList, formatPlan, assessCommitSafety, recordPackageAction, detectPackageEcosystem, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
7
7
|
import { spawn, execFileSync, spawnSync } from 'node:child_process';
|
|
8
8
|
import * as os from 'node:os';
|
|
9
9
|
import * as fs7 from 'node:fs';
|
|
@@ -168,6 +168,8 @@ function normalizeCommandOutput(raw, opts = {}) {
|
|
|
168
168
|
text = text.replace(/\n{3,}/g, "\n\n");
|
|
169
169
|
return truncateHeadTail(text, opts.maxBytes ?? COMMAND_OUTPUT_MAX_BYTES);
|
|
170
170
|
}
|
|
171
|
+
|
|
172
|
+
// src/read.ts
|
|
171
173
|
var MAX_BYTES = 5 * 1024 * 1024;
|
|
172
174
|
var readTool = {
|
|
173
175
|
name: "read",
|
|
@@ -194,6 +196,11 @@ var readTool = {
|
|
|
194
196
|
limit: {
|
|
195
197
|
type: "integer",
|
|
196
198
|
description: "Maximum number of lines to return (default is 2000)."
|
|
199
|
+
},
|
|
200
|
+
mode: {
|
|
201
|
+
type: "string",
|
|
202
|
+
enum: ["content", "summary"],
|
|
203
|
+
description: "Return full line-numbered content (default) or a compact file summary with imports/exports/symbols."
|
|
197
204
|
}
|
|
198
205
|
},
|
|
199
206
|
required: ["path"]
|
|
@@ -207,14 +214,27 @@ var readTool = {
|
|
|
207
214
|
} catch (err) {
|
|
208
215
|
const code = err.code;
|
|
209
216
|
if (code === "ENOENT") throw new Error(`read: file not found "${input.path}"`);
|
|
210
|
-
throw new Error(
|
|
211
|
-
`read: failed to stat "${input.path}": ${toErrorMessage(err)}`
|
|
212
|
-
);
|
|
217
|
+
throw new Error(`read: failed to stat "${input.path}": ${toErrorMessage(err)}`);
|
|
213
218
|
}
|
|
214
219
|
if (!stat11.isFile()) throw new Error(`read: "${input.path}" is not a regular file`);
|
|
215
220
|
if (stat11.size > MAX_BYTES) {
|
|
216
221
|
throw new Error(`read: file too large (${stat11.size} bytes, limit ${MAX_BYTES})`);
|
|
217
222
|
}
|
|
223
|
+
const offset = Math.max(1, input.offset ?? 1);
|
|
224
|
+
const limit = Math.max(0, Math.min(input.limit ?? 2e3, 5e3));
|
|
225
|
+
const prior = getReadRangeRecord(ctx, absPath);
|
|
226
|
+
const requestedEnd = prior ? Math.min(offset + limit - 1, prior.totalLines) : offset + limit - 1;
|
|
227
|
+
if (input.mode !== "summary" && limit > 0 && prior && coversRange(prior, stat11.mtimeMs, offset, requestedEnd)) {
|
|
228
|
+
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
229
|
+
return {
|
|
230
|
+
text: `[unchanged since previous read: "${input.path}" mtime=${Math.round(stat11.mtimeMs)}; requested lines ${offset}-${requestedEnd} were already shown. Use offset/limit for a new range if needed.]`,
|
|
231
|
+
total_lines: prior.totalLines,
|
|
232
|
+
encoding: "utf8",
|
|
233
|
+
truncated: requestedEnd < prior.totalLines,
|
|
234
|
+
cached: true,
|
|
235
|
+
note: "Repeated read suppressed to save tokens."
|
|
236
|
+
};
|
|
237
|
+
}
|
|
218
238
|
const buf = await fs4.readFile(absPath);
|
|
219
239
|
if (isBinaryBuffer(buf)) {
|
|
220
240
|
throw new Error(`read: "${input.path}" appears to be binary`);
|
|
@@ -222,17 +242,38 @@ var readTool = {
|
|
|
222
242
|
const text = buf.toString("utf8");
|
|
223
243
|
const allLines = text.split(/\r\n|\r|\n/);
|
|
224
244
|
const total = allLines.length;
|
|
225
|
-
|
|
226
|
-
|
|
245
|
+
if (input.mode === "summary") {
|
|
246
|
+
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
247
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, 1, Math.min(total, 200));
|
|
248
|
+
return {
|
|
249
|
+
text: summarizeFile(input.path, stat11.size, allLines),
|
|
250
|
+
total_lines: total,
|
|
251
|
+
encoding: "utf8",
|
|
252
|
+
truncated: total > 200,
|
|
253
|
+
note: "Summary mode returned compact structure instead of full file content."
|
|
254
|
+
};
|
|
255
|
+
}
|
|
227
256
|
if (limit === 0) {
|
|
228
257
|
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
258
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, 1, 0);
|
|
229
259
|
return { text: "", total_lines: total, encoding: "utf8", truncated: total > 0 };
|
|
230
260
|
}
|
|
261
|
+
if (offset > total) {
|
|
262
|
+
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
263
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, total + 1, total + 1);
|
|
264
|
+
return {
|
|
265
|
+
text: `[offset ${offset} is past end of file "${input.path}" \u2014 file has ${total} line(s). Do not retry this offset.]`,
|
|
266
|
+
total_lines: total,
|
|
267
|
+
encoding: "utf8",
|
|
268
|
+
truncated: false
|
|
269
|
+
};
|
|
270
|
+
}
|
|
231
271
|
const slice = allLines.slice(offset - 1, offset - 1 + limit);
|
|
232
272
|
const truncated = offset - 1 + slice.length < total;
|
|
233
273
|
const width = String(offset + slice.length - 1).length;
|
|
234
274
|
const numbered = slice.map((line, i) => `${String(offset + i).padStart(width, " ")}\u2192${line}`).join("\n");
|
|
235
275
|
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
276
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, offset, offset + slice.length - 1);
|
|
236
277
|
return {
|
|
237
278
|
text: numbered,
|
|
238
279
|
total_lines: total,
|
|
@@ -241,6 +282,62 @@ var readTool = {
|
|
|
241
282
|
};
|
|
242
283
|
}
|
|
243
284
|
};
|
|
285
|
+
var READ_RANGES_META_KEY = "tools.read.ranges.v1";
|
|
286
|
+
function getReadRanges(ctx) {
|
|
287
|
+
const existing = ctx.meta[READ_RANGES_META_KEY];
|
|
288
|
+
if (existing && typeof existing === "object" && !Array.isArray(existing)) {
|
|
289
|
+
return existing;
|
|
290
|
+
}
|
|
291
|
+
const next = {};
|
|
292
|
+
ctx.meta[READ_RANGES_META_KEY] = next;
|
|
293
|
+
return next;
|
|
294
|
+
}
|
|
295
|
+
function getReadRangeRecord(ctx, absPath) {
|
|
296
|
+
return getReadRanges(ctx)[absPath];
|
|
297
|
+
}
|
|
298
|
+
function rememberReadRange(ctx, absPath, mtimeMs, totalLines, start, end) {
|
|
299
|
+
if (end < start) return;
|
|
300
|
+
const ranges = getReadRanges(ctx);
|
|
301
|
+
const prior = ranges[absPath];
|
|
302
|
+
const nextRanges = prior && Math.abs(prior.mtimeMs - mtimeMs) <= 1 ? prior.ranges.slice() : [];
|
|
303
|
+
nextRanges.push({ start, end });
|
|
304
|
+
ranges[absPath] = {
|
|
305
|
+
mtimeMs,
|
|
306
|
+
totalLines,
|
|
307
|
+
ranges: mergeRanges(nextRanges)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function coversRange(record, mtimeMs, start, end) {
|
|
311
|
+
if (Math.abs(record.mtimeMs - mtimeMs) > 1) return false;
|
|
312
|
+
return record.ranges.some((range) => range.start <= start && range.end >= end);
|
|
313
|
+
}
|
|
314
|
+
function mergeRanges(ranges) {
|
|
315
|
+
const sorted = ranges.slice().sort((a, b) => a.start - b.start);
|
|
316
|
+
const merged = [];
|
|
317
|
+
for (const range of sorted) {
|
|
318
|
+
const last = merged[merged.length - 1];
|
|
319
|
+
if (!last || range.start > last.end + 1) {
|
|
320
|
+
merged.push({ ...range });
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
last.end = Math.max(last.end, range.end);
|
|
324
|
+
}
|
|
325
|
+
return merged;
|
|
326
|
+
}
|
|
327
|
+
function summarizeFile(filePath, bytes, lines) {
|
|
328
|
+
const interesting = lines.map((line, index) => ({ line: line.trim(), number: index + 1 })).filter(
|
|
329
|
+
({ line }) => /^(import\s|export\s|class\s|interface\s|type\s|function\s|const\s+\w+\s*=|let\s+\w+\s*=|var\s+\w+\s*=|def\s+|async\s+function\s)/.test(
|
|
330
|
+
line
|
|
331
|
+
)
|
|
332
|
+
).slice(0, 80).map(({ line, number }) => `${number}: ${line}`);
|
|
333
|
+
return [
|
|
334
|
+
`summary: ${filePath}`,
|
|
335
|
+
`bytes=${bytes}`,
|
|
336
|
+
`total_lines=${lines.length}`,
|
|
337
|
+
interesting.length > 0 ? `symbols/imports:
|
|
338
|
+
${interesting.join("\n")}` : "symbols/imports: (none detected)"
|
|
339
|
+
].join("\n");
|
|
340
|
+
}
|
|
244
341
|
var writeTool = {
|
|
245
342
|
name: "write",
|
|
246
343
|
category: "Filesystem",
|
|
@@ -309,8 +406,8 @@ var writeTool = {
|
|
|
309
406
|
var editTool = {
|
|
310
407
|
name: "edit",
|
|
311
408
|
category: "Filesystem",
|
|
312
|
-
description: "Perform a precise, surgical text replacement in a file. This is the preferred tool for modifying existing code. It
|
|
313
|
-
usageHint: "
|
|
409
|
+
description: "Perform a precise, surgical text replacement in a file. This is the preferred tool for modifying existing code. It works best after a prior `read`, but can auto-read the current file when the replacement is still unambiguous. Fails safely if the `old_string` appears more than once unless `replace_all` is set.",
|
|
410
|
+
usageHint: "RECOMMENDED WORKFLOW:\n1. Prefer calling `read` on the target file first when planning an edit.\n2. Use a sufficiently unique `old_string` (include surrounding lines/context if needed).\n3. If the string appears multiple times and you want to change all of them, set `replace_all: true`.\n4. `new_string` must be the exact replacement text.\n\nIf no prior read is recorded, the tool auto-reads the current file and only applies the edit after the same ambiguity checks pass.",
|
|
314
411
|
permission: "confirm",
|
|
315
412
|
mutating: true,
|
|
316
413
|
capabilities: ["fs.write"],
|
|
@@ -339,9 +436,7 @@ var editTool = {
|
|
|
339
436
|
throw err;
|
|
340
437
|
});
|
|
341
438
|
if (!stat11.isFile()) throw new Error(`edit: "${input.path}" is not a regular file`);
|
|
342
|
-
|
|
343
|
-
throw new Error(`edit: file "${input.path}" was not read in this session. Read it first.`);
|
|
344
|
-
}
|
|
439
|
+
const autoRead = !ctx.hasRead(absPath);
|
|
345
440
|
const original = await fs4.readFile(absPath, "utf8");
|
|
346
441
|
const updated = await fs4.stat(absPath);
|
|
347
442
|
const mtimeTolerance = process.platform === "win32" ? 2e3 : 1;
|
|
@@ -349,15 +444,21 @@ var editTool = {
|
|
|
349
444
|
if (lastReadMtime !== void 0 && updated.mtimeMs > lastReadMtime + mtimeTolerance) {
|
|
350
445
|
throw new Error(`edit: file "${input.path}" was modified externally. Re-read it first.`);
|
|
351
446
|
}
|
|
447
|
+
if (autoRead && updated.mtimeMs > stat11.mtimeMs + mtimeTolerance) {
|
|
448
|
+
throw new Error(`edit: file "${input.path}" changed while being auto-read. Retry the edit.`);
|
|
449
|
+
}
|
|
450
|
+
const autoReadNote = autoRead ? `No prior read was recorded for "${input.path}"; edit auto-read the current file and applied the replacement only after the ambiguity checks passed.` : void 0;
|
|
352
451
|
const style = detectNewlineStyle(original);
|
|
353
452
|
const fileLf = normalizeToLf(original);
|
|
354
453
|
const oldLf = normalizeToLf(input.old_string);
|
|
355
454
|
const newLf = normalizeToLf(input.new_string);
|
|
356
455
|
if (oldLf === newLf) {
|
|
456
|
+
if (autoRead) ctx.recordRead(absPath, updated.mtimeMs);
|
|
357
457
|
return {
|
|
358
458
|
path: absPath,
|
|
359
459
|
replacements: 0,
|
|
360
|
-
diff: "(no-op: old and new are identical)"
|
|
460
|
+
diff: "(no-op: old and new are identical)",
|
|
461
|
+
note: autoReadNote
|
|
361
462
|
};
|
|
362
463
|
}
|
|
363
464
|
let count = 0;
|
|
@@ -398,7 +499,8 @@ var editTool = {
|
|
|
398
499
|
return {
|
|
399
500
|
path: absPath,
|
|
400
501
|
replacements: input.replace_all ? count : 1,
|
|
401
|
-
diff
|
|
502
|
+
diff,
|
|
503
|
+
note: autoReadNote
|
|
402
504
|
};
|
|
403
505
|
}
|
|
404
506
|
};
|
|
@@ -609,13 +711,13 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
609
711
|
return await globNative(pattern, base, extraGlob);
|
|
610
712
|
}
|
|
611
713
|
function checkRg() {
|
|
612
|
-
return new Promise((
|
|
714
|
+
return new Promise((resolve6) => {
|
|
613
715
|
try {
|
|
614
716
|
const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore", windowsHide: true });
|
|
615
|
-
p.on("error", () =>
|
|
616
|
-
p.on("close", (code) =>
|
|
717
|
+
p.on("error", () => resolve6(false));
|
|
718
|
+
p.on("close", (code) => resolve6(code === 0));
|
|
617
719
|
} catch {
|
|
618
|
-
|
|
720
|
+
resolve6(false);
|
|
619
721
|
}
|
|
620
722
|
});
|
|
621
723
|
}
|
|
@@ -632,10 +734,10 @@ function spawnRgFind(pattern, base) {
|
|
|
632
734
|
buf += chunk.toString();
|
|
633
735
|
});
|
|
634
736
|
return {
|
|
635
|
-
promise: new Promise((
|
|
737
|
+
promise: new Promise((resolve6, reject) => {
|
|
636
738
|
child.on("error", reject);
|
|
637
739
|
child.on("close", () => {
|
|
638
|
-
|
|
740
|
+
resolve6(buf.split("\n").filter(Boolean));
|
|
639
741
|
});
|
|
640
742
|
})
|
|
641
743
|
};
|
|
@@ -841,13 +943,13 @@ var grepTool = {
|
|
|
841
943
|
}
|
|
842
944
|
};
|
|
843
945
|
async function detectRg(signal) {
|
|
844
|
-
return new Promise((
|
|
946
|
+
return new Promise((resolve6) => {
|
|
845
947
|
try {
|
|
846
948
|
const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore", signal, windowsHide: true });
|
|
847
|
-
p.on("error", () =>
|
|
848
|
-
p.on("close", (code) =>
|
|
949
|
+
p.on("error", () => resolve6(false));
|
|
950
|
+
p.on("close", (code) => resolve6(code === 0));
|
|
849
951
|
} catch {
|
|
850
|
-
|
|
952
|
+
resolve6(false);
|
|
851
953
|
}
|
|
852
954
|
});
|
|
853
955
|
}
|
|
@@ -1922,10 +2024,10 @@ var bashTool = {
|
|
|
1922
2024
|
queue.push(c);
|
|
1923
2025
|
}
|
|
1924
2026
|
};
|
|
1925
|
-
const next = () => new Promise((
|
|
2027
|
+
const next = () => new Promise((resolve6) => {
|
|
1926
2028
|
const c = queue.shift();
|
|
1927
|
-
if (c)
|
|
1928
|
-
else resolveNext =
|
|
2029
|
+
if (c) resolve6(c);
|
|
2030
|
+
else resolveNext = resolve6;
|
|
1929
2031
|
});
|
|
1930
2032
|
let lastFlush = Date.now();
|
|
1931
2033
|
const flush = () => {
|
|
@@ -2221,26 +2323,26 @@ var execTool = {
|
|
|
2221
2323
|
allowed: false
|
|
2222
2324
|
};
|
|
2223
2325
|
}
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2326
|
+
let cwd;
|
|
2327
|
+
try {
|
|
2328
|
+
cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : await safeResolveReal(ctx.cwd, ctx);
|
|
2329
|
+
} catch {
|
|
2227
2330
|
return {
|
|
2228
2331
|
command: cmd,
|
|
2229
2332
|
args,
|
|
2230
2333
|
stdout: "",
|
|
2231
|
-
stderr: `cwd "${input.cwd}" resolves outside project root`,
|
|
2334
|
+
stderr: `cwd "${input.cwd ?? ctx.cwd}" resolves outside project root`,
|
|
2232
2335
|
exitCode: 1,
|
|
2233
2336
|
truncated: false,
|
|
2234
2337
|
allowed: false
|
|
2235
2338
|
};
|
|
2236
2339
|
}
|
|
2237
|
-
const cwd = requestedCwd;
|
|
2238
2340
|
const signal = opts.signal;
|
|
2239
2341
|
return runCommand(cmd, args, cwd, timeout, signal, ctx.session?.id);
|
|
2240
2342
|
}
|
|
2241
2343
|
};
|
|
2242
2344
|
function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
2243
|
-
return new Promise((
|
|
2345
|
+
return new Promise((resolve6) => {
|
|
2244
2346
|
let stdout = "";
|
|
2245
2347
|
let stderr = "";
|
|
2246
2348
|
let killed = false;
|
|
@@ -2295,7 +2397,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
2295
2397
|
const exitCode = killed ? 124 : code ?? 1;
|
|
2296
2398
|
registry.afterCall(durationMs, exitCode !== 0);
|
|
2297
2399
|
const spooled = spool.finalize();
|
|
2298
|
-
|
|
2400
|
+
resolve6({
|
|
2299
2401
|
command: cmd,
|
|
2300
2402
|
args,
|
|
2301
2403
|
stdout: normalizeCommandOutput(stdout) + (spooled ? spoolNote(spooled) : ""),
|
|
@@ -2311,7 +2413,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
2311
2413
|
if (typeof pid === "number") registry.unregister(pid);
|
|
2312
2414
|
registry.afterCall(Date.now() - startedAt, true);
|
|
2313
2415
|
spool.finalize();
|
|
2314
|
-
|
|
2416
|
+
resolve6({
|
|
2315
2417
|
command: cmd,
|
|
2316
2418
|
args,
|
|
2317
2419
|
stdout: normalizeCommandOutput(stdout),
|
|
@@ -3167,7 +3269,7 @@ var gitTool = {
|
|
|
3167
3269
|
name: "git",
|
|
3168
3270
|
category: "Git",
|
|
3169
3271
|
description: "Safe wrapper around common git operations. Supports status, log, diff, commit, branch, checkout, stash, push, pull, fetch, reset, worktree, etc. This is the preferred way to interact with git instead of using the raw `bash` or `exec` tools.",
|
|
3170
|
-
usageHint: "ALWAYS prefer this tool over raw shell git commands.\n\nKey fields:\n- `command`: one of the supported subcommands (status, log, diff, commit, etc.)\n- Use `message` only for commit operations.\n- Use `files` array for operations that take paths (status, diff, add, etc.).\n- Non-mutating commands (status, log, diff, branch, fetch) are still permission:confirm for safety.\nNever pass raw git flags through `args` for dangerous operations \u2014 use the structured fields.",
|
|
3272
|
+
usageHint: "ALWAYS prefer this tool over raw shell git commands.\n\nKey fields:\n- `command`: one of the supported subcommands (status, log, diff, commit, etc.)\n- Use `message` only for commit operations.\n- Use `files` array for operations that take paths (status, diff, add, etc.).\n- Non-mutating commands (status, log, diff, branch, fetch) are still permission:confirm for safety.\n- For `commit` in a possibly-shared working tree, pass an explicit `files` list scoped to what YOU changed. A bare commit (no `files`) includes ALL staged changes and may capture another agent's half-done work. Heed the `warning` field on the result.\nNever pass raw git flags through `args` for dangerous operations \u2014 use the structured fields.",
|
|
3171
3273
|
permission: "confirm",
|
|
3172
3274
|
icon: "git",
|
|
3173
3275
|
// Conservative: any of these may mutate. The non-mutating commands
|
|
@@ -3256,6 +3358,22 @@ var gitTool = {
|
|
|
3256
3358
|
};
|
|
3257
3359
|
}
|
|
3258
3360
|
const args = buildArgs(input);
|
|
3361
|
+
let safetyWarning;
|
|
3362
|
+
if (input.command === "commit") {
|
|
3363
|
+
try {
|
|
3364
|
+
const report = await assessCommitSafety({
|
|
3365
|
+
cwd: ctx.cwd,
|
|
3366
|
+
projectRoot: ctx.projectRoot,
|
|
3367
|
+
sessionId: ctx.session?.id,
|
|
3368
|
+
signal: opts.signal
|
|
3369
|
+
});
|
|
3370
|
+
if (report.warning) {
|
|
3371
|
+
const scopeNote = input.files ? "" : "\nNote: this commit has no explicit `files` list, so it will include ALL staged changes. Pass `files` to scope the commit to only what you changed.";
|
|
3372
|
+
safetyWarning = report.warning + scopeNote;
|
|
3373
|
+
}
|
|
3374
|
+
} catch {
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3259
3377
|
let stagedDiff;
|
|
3260
3378
|
if (input.command === "commit" && !input.dry_run) {
|
|
3261
3379
|
try {
|
|
@@ -3269,6 +3387,7 @@ var gitTool = {
|
|
|
3269
3387
|
}
|
|
3270
3388
|
const result = await runGit(args, gitDir, opts.signal);
|
|
3271
3389
|
if (stagedDiff !== void 0) result.diff = stagedDiff;
|
|
3390
|
+
if (safetyWarning !== void 0) result.warning = safetyWarning;
|
|
3272
3391
|
return result;
|
|
3273
3392
|
}
|
|
3274
3393
|
};
|
|
@@ -3380,7 +3499,7 @@ function buildArgs(input) {
|
|
|
3380
3499
|
}
|
|
3381
3500
|
}
|
|
3382
3501
|
function runGit(args, cwd, signal) {
|
|
3383
|
-
return new Promise((
|
|
3502
|
+
return new Promise((resolve6) => {
|
|
3384
3503
|
let stdout = "";
|
|
3385
3504
|
let stderr = "";
|
|
3386
3505
|
const child = spawn("git", args, {
|
|
@@ -3401,7 +3520,7 @@ function runGit(args, cwd, signal) {
|
|
|
3401
3520
|
}
|
|
3402
3521
|
});
|
|
3403
3522
|
child.on("error", (err) => {
|
|
3404
|
-
|
|
3523
|
+
resolve6({
|
|
3405
3524
|
command: args[0],
|
|
3406
3525
|
stdout: normalizeCommandOutput(stdout),
|
|
3407
3526
|
stderr: err.message,
|
|
@@ -3410,7 +3529,7 @@ function runGit(args, cwd, signal) {
|
|
|
3410
3529
|
});
|
|
3411
3530
|
});
|
|
3412
3531
|
child.on("close", (code) => {
|
|
3413
|
-
|
|
3532
|
+
resolve6({
|
|
3414
3533
|
command: args[0],
|
|
3415
3534
|
stdout: normalizeCommandOutput(stdout),
|
|
3416
3535
|
stderr: normalizeCommandOutput(stderr),
|
|
@@ -3510,7 +3629,7 @@ function stripPathComponents(p, strip) {
|
|
|
3510
3629
|
return parts.slice(strip).join("/");
|
|
3511
3630
|
}
|
|
3512
3631
|
function runPatch(args, cwd, signal) {
|
|
3513
|
-
return new Promise((
|
|
3632
|
+
return new Promise((resolve6) => {
|
|
3514
3633
|
let stdout = "";
|
|
3515
3634
|
let stderr = "";
|
|
3516
3635
|
const env = { ...buildChildEnv(), LANG: "C", LC_ALL: "C" };
|
|
@@ -3521,8 +3640,8 @@ function runPatch(args, cwd, signal) {
|
|
|
3521
3640
|
child.stderr?.on("data", (c) => {
|
|
3522
3641
|
stderr += c.toString();
|
|
3523
3642
|
});
|
|
3524
|
-
child.on("close", (code) =>
|
|
3525
|
-
child.on("error", (e) =>
|
|
3643
|
+
child.on("close", (code) => resolve6({ exitCode: code ?? 1, stdout, stderr }));
|
|
3644
|
+
child.on("error", (e) => resolve6({ exitCode: 1, stdout: "", stderr: e.message }));
|
|
3526
3645
|
});
|
|
3527
3646
|
}
|
|
3528
3647
|
function extractPatchedFiles(output) {
|
|
@@ -3608,8 +3727,8 @@ var jsonTool = {
|
|
|
3608
3727
|
};
|
|
3609
3728
|
}
|
|
3610
3729
|
};
|
|
3611
|
-
function query(data,
|
|
3612
|
-
const parts =
|
|
3730
|
+
function query(data, path20) {
|
|
3731
|
+
const parts = path20.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
3613
3732
|
let current = data;
|
|
3614
3733
|
for (const part of parts) {
|
|
3615
3734
|
if (current === null || current === void 0) return void 0;
|
|
@@ -3750,7 +3869,7 @@ function findGitDir2(cwd) {
|
|
|
3750
3869
|
return null;
|
|
3751
3870
|
}
|
|
3752
3871
|
function runGit2(args, cwd, signal) {
|
|
3753
|
-
return new Promise((
|
|
3872
|
+
return new Promise((resolve6) => {
|
|
3754
3873
|
let stdout = "";
|
|
3755
3874
|
let stderr = "";
|
|
3756
3875
|
const child = spawn("git", args, {
|
|
@@ -3766,8 +3885,8 @@ function runGit2(args, cwd, signal) {
|
|
|
3766
3885
|
child.stderr?.on("data", (c) => {
|
|
3767
3886
|
stderr += c.toString();
|
|
3768
3887
|
});
|
|
3769
|
-
child.on("close", (code) =>
|
|
3770
|
-
child.on("error", (e) =>
|
|
3888
|
+
child.on("close", (code) => resolve6({ stdout, stderr, exitCode: code ?? 0 }));
|
|
3889
|
+
child.on("error", (e) => resolve6({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
3771
3890
|
});
|
|
3772
3891
|
}
|
|
3773
3892
|
async function fileDiff(input, ctx, _signal) {
|
|
@@ -4085,8 +4204,8 @@ async function* spawnStream(opts) {
|
|
|
4085
4204
|
try {
|
|
4086
4205
|
for (; ; ) {
|
|
4087
4206
|
while (queue.length === 0) {
|
|
4088
|
-
await new Promise((
|
|
4089
|
-
waiter =
|
|
4207
|
+
await new Promise((resolve6) => {
|
|
4208
|
+
waiter = resolve6;
|
|
4090
4209
|
});
|
|
4091
4210
|
}
|
|
4092
4211
|
const chunk = queue.shift();
|
|
@@ -4839,12 +4958,15 @@ var outdatedTool = {
|
|
|
4839
4958
|
// fixed four sibling tools (mcp_control, shellcheck, shellcheck_scan,
|
|
4840
4959
|
// web_search) but missed this one; applying the same contract here.
|
|
4841
4960
|
mutating: true,
|
|
4842
|
-
// Capability is
|
|
4961
|
+
// Capability is outbound network — the tool only hits the package
|
|
4843
4962
|
// registry over HTTP, never touches the filesystem or runs shell.
|
|
4963
|
+
// Use the canonical `net.outbound` capability (not the non-existent
|
|
4964
|
+
// `network` string) so the subagent allowlist recognises it and
|
|
4965
|
+
// permits read-only registry lookups under a director.
|
|
4844
4966
|
// The H7 invariant test requires this array to be non-empty for
|
|
4845
4967
|
// any mutating:true tool (meta-tools whitelisted). See
|
|
4846
4968
|
// tests/permission-mutating-invariant.test.ts:92.
|
|
4847
|
-
capabilities: ["
|
|
4969
|
+
capabilities: ["net.outbound"],
|
|
4848
4970
|
timeoutMs: 6e4,
|
|
4849
4971
|
inputSchema: {
|
|
4850
4972
|
type: "object",
|
|
@@ -4875,7 +4997,7 @@ var outdatedTool = {
|
|
|
4875
4997
|
}
|
|
4876
4998
|
};
|
|
4877
4999
|
function runOutdated(manager, args, cwd, signal) {
|
|
4878
|
-
return new Promise((
|
|
5000
|
+
return new Promise((resolve6) => {
|
|
4879
5001
|
let stdout = "";
|
|
4880
5002
|
let stderr = "";
|
|
4881
5003
|
const MAX = 1e5;
|
|
@@ -4891,10 +5013,10 @@ function runOutdated(manager, args, cwd, signal) {
|
|
|
4891
5013
|
});
|
|
4892
5014
|
child.on("close", (code) => {
|
|
4893
5015
|
const result = parseOutdatedOutput(stdout, code ?? 0);
|
|
4894
|
-
|
|
5016
|
+
resolve6(result);
|
|
4895
5017
|
});
|
|
4896
5018
|
child.on("error", (e) => {
|
|
4897
|
-
|
|
5019
|
+
resolve6({
|
|
4898
5020
|
exit_code: 1,
|
|
4899
5021
|
packages: [],
|
|
4900
5022
|
total: 0,
|
|
@@ -5020,7 +5142,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
5020
5142
|
};
|
|
5021
5143
|
}
|
|
5022
5144
|
args.push("--timestamps", service);
|
|
5023
|
-
return new Promise((
|
|
5145
|
+
return new Promise((resolve6) => {
|
|
5024
5146
|
let stdout = "";
|
|
5025
5147
|
let stderr = "";
|
|
5026
5148
|
const MAX = 2e5;
|
|
@@ -5036,7 +5158,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
5036
5158
|
if (settled) return;
|
|
5037
5159
|
settled = true;
|
|
5038
5160
|
clearTimeout(timer);
|
|
5039
|
-
|
|
5161
|
+
resolve6(result);
|
|
5040
5162
|
};
|
|
5041
5163
|
const child = spawn("docker", args, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
|
|
5042
5164
|
const timer = setTimeout(() => {
|
|
@@ -5071,7 +5193,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
5071
5193
|
}
|
|
5072
5194
|
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
5073
5195
|
var MAX_TAIL_LINES = 1e5;
|
|
5074
|
-
async function fileLogs(
|
|
5196
|
+
async function fileLogs(path20, lines, filterRe, stream) {
|
|
5075
5197
|
const { createInterface } = await import('node:readline');
|
|
5076
5198
|
const { createReadStream } = await import('node:fs');
|
|
5077
5199
|
const entries = [];
|
|
@@ -5080,7 +5202,7 @@ async function fileLogs(path21, lines, filterRe, stream) {
|
|
|
5080
5202
|
let writeIdx = 0;
|
|
5081
5203
|
let totalLines = 0;
|
|
5082
5204
|
const rl = createInterface({
|
|
5083
|
-
input: createReadStream(
|
|
5205
|
+
input: createReadStream(path20),
|
|
5084
5206
|
crlfDelay: Number.POSITIVE_INFINITY
|
|
5085
5207
|
});
|
|
5086
5208
|
for await (const line of rl) {
|
|
@@ -5101,7 +5223,7 @@ async function fileLogs(path21, lines, filterRe, stream) {
|
|
|
5101
5223
|
if (parsed) entries.push(parsed);
|
|
5102
5224
|
}
|
|
5103
5225
|
return {
|
|
5104
|
-
source:
|
|
5226
|
+
source: path20,
|
|
5105
5227
|
entries,
|
|
5106
5228
|
total: entries.length,
|
|
5107
5229
|
truncated: totalLines > effLines,
|
|
@@ -8129,8 +8251,9 @@ async function loadGitignoreMatcher(projectRoot) {
|
|
|
8129
8251
|
|
|
8130
8252
|
// src/codebase-index/indexer.ts
|
|
8131
8253
|
var YIELD_EVERY_N = 50;
|
|
8254
|
+
var PARALLEL_BATCH = 20;
|
|
8132
8255
|
function yieldEventLoop() {
|
|
8133
|
-
return new Promise((
|
|
8256
|
+
return new Promise((resolve6) => setImmediate(resolve6));
|
|
8134
8257
|
}
|
|
8135
8258
|
function throwIfAborted(signal) {
|
|
8136
8259
|
if (!signal?.aborted) return;
|
|
@@ -8262,97 +8385,108 @@ async function runIndexerWithStore(store, opts) {
|
|
|
8262
8385
|
if (!force) {
|
|
8263
8386
|
for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
|
|
8264
8387
|
}
|
|
8265
|
-
for (let
|
|
8266
|
-
const
|
|
8267
|
-
|
|
8268
|
-
|
|
8388
|
+
for (let batchStart = 0; batchStart < files.length; batchStart += PARALLEL_BATCH) {
|
|
8389
|
+
const batchEnd = Math.min(batchStart + PARALLEL_BATCH, files.length);
|
|
8390
|
+
const batchFiles = files.slice(batchStart, batchEnd);
|
|
8391
|
+
opts.onProgress?.(batchEnd, files.length);
|
|
8392
|
+
if (batchStart > 0 && batchStart % YIELD_EVERY_N === 0) {
|
|
8269
8393
|
await yieldEventLoop();
|
|
8270
8394
|
throwIfAborted(signal);
|
|
8271
8395
|
}
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
if (!stat11.isFile()) continue;
|
|
8282
|
-
const lang = detectLang(file);
|
|
8283
|
-
if (!lang) continue;
|
|
8284
|
-
const meta = existingMeta.get(file);
|
|
8285
|
-
if (!force && meta && meta.mtimeMs === Math.floor(stat11.mtimeMs)) {
|
|
8286
|
-
langStats[lang] = (langStats[lang] ?? 0) + meta.symbolCount;
|
|
8287
|
-
symbolsIndexed += meta.symbolCount;
|
|
8288
|
-
filesIndexed++;
|
|
8289
|
-
continue;
|
|
8290
|
-
}
|
|
8291
|
-
store.deleteRefsForFile(file);
|
|
8292
|
-
store.deleteSymbolsForFile(file);
|
|
8293
|
-
let content;
|
|
8294
|
-
try {
|
|
8295
|
-
content = await fs4.readFile(file, { encoding: "utf8", signal });
|
|
8296
|
-
} catch (e) {
|
|
8297
|
-
if (isAbortError(e)) throw e;
|
|
8298
|
-
errors.push(`read error: ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
8299
|
-
continue;
|
|
8300
|
-
}
|
|
8301
|
-
let parsed;
|
|
8302
|
-
try {
|
|
8303
|
-
parsed = await parseFile(file, content, lang);
|
|
8304
|
-
} catch (e) {
|
|
8305
|
-
errors.push(`parse error: ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
8306
|
-
continue;
|
|
8307
|
-
}
|
|
8308
|
-
if (parsed.symbols.length === 0) {
|
|
8309
|
-
store.upsertFile({
|
|
8310
|
-
file,
|
|
8311
|
-
lang,
|
|
8312
|
-
mtimeMs: Math.floor(stat11.mtimeMs),
|
|
8313
|
-
symbolCount: 0,
|
|
8314
|
-
lastIndexed: Date.now()
|
|
8315
|
-
});
|
|
8316
|
-
filesIndexed++;
|
|
8317
|
-
continue;
|
|
8318
|
-
}
|
|
8319
|
-
const nextId = store.getMaxSymbolId() + 1;
|
|
8320
|
-
const symbolsWithIds = parsed.symbols.map((s, i) => ({ ...s, id: nextId + i }));
|
|
8321
|
-
store.insertSymbols(symbolsWithIds, nextId);
|
|
8322
|
-
const count = symbolsWithIds.length;
|
|
8323
|
-
symbolsIndexed += count;
|
|
8324
|
-
langStats[lang] = (langStats[lang] ?? 0) + count;
|
|
8325
|
-
if (parsed.refs && parsed.refs.length > 0) {
|
|
8326
|
-
const refsByLine = /* @__PURE__ */ new Map();
|
|
8327
|
-
for (const r of parsed.refs) {
|
|
8328
|
-
let arr = refsByLine.get(r.line);
|
|
8329
|
-
if (!arr) {
|
|
8330
|
-
arr = [];
|
|
8331
|
-
refsByLine.set(r.line, arr);
|
|
8396
|
+
const statOpts = signal ? { signal } : {};
|
|
8397
|
+
const statReadParse = await Promise.allSettled(
|
|
8398
|
+
batchFiles.map(async (file) => {
|
|
8399
|
+
let stat11;
|
|
8400
|
+
try {
|
|
8401
|
+
stat11 = await fs4.stat(file, statOpts);
|
|
8402
|
+
} catch (e) {
|
|
8403
|
+
if (isAbortError(e)) throw e;
|
|
8404
|
+
return { file, stat: null, lang: "", parsed: null, error: `stat error: ${e instanceof Error ? e.message : String(e)}` };
|
|
8332
8405
|
}
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
}
|
|
8406
|
+
if (!stat11.isFile()) return { file, stat: stat11, lang: "", parsed: null };
|
|
8407
|
+
const lang = detectLang(file);
|
|
8408
|
+
if (!lang) return { file, stat: stat11, lang: "", parsed: null };
|
|
8409
|
+
let content;
|
|
8410
|
+
try {
|
|
8411
|
+
content = await fs4.readFile(file, { encoding: "utf8", signal });
|
|
8412
|
+
} catch (e) {
|
|
8413
|
+
if (isAbortError(e)) throw e;
|
|
8414
|
+
return { file, stat: stat11, lang, parsed: null, error: `read error: ${e instanceof Error ? e.message : String(e)}` };
|
|
8415
|
+
}
|
|
8416
|
+
let parsed;
|
|
8417
|
+
try {
|
|
8418
|
+
parsed = await parseFile(file, content, lang);
|
|
8419
|
+
} catch (e) {
|
|
8420
|
+
return { file, stat: stat11, lang, parsed: null, error: `parse error: ${e instanceof Error ? e.message : String(e)}` };
|
|
8421
|
+
}
|
|
8422
|
+
return { file, stat: stat11, lang, parsed, content };
|
|
8423
|
+
})
|
|
8424
|
+
);
|
|
8425
|
+
for (let fi = 0; fi < statReadParse.length; fi++) {
|
|
8426
|
+
const settled = statReadParse[fi];
|
|
8427
|
+
const file = expectDefined(batchFiles[fi]);
|
|
8428
|
+
if (settled.status === "rejected") {
|
|
8429
|
+
const err = settled.reason;
|
|
8430
|
+
if (err instanceof Error && isAbortError(err)) throw err;
|
|
8431
|
+
errors.push(`batch error: ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
8432
|
+
continue;
|
|
8433
|
+
}
|
|
8434
|
+
const result = settled.value;
|
|
8435
|
+
if (result.error) {
|
|
8436
|
+
if (result.stat) store.deleteFile(file);
|
|
8437
|
+
if (result.error.includes("error:")) errors.push(result.error);
|
|
8438
|
+
continue;
|
|
8439
|
+
}
|
|
8440
|
+
const { stat: stat11, lang, parsed } = result;
|
|
8441
|
+
if (!lang || !parsed) {
|
|
8442
|
+
if (lang) {
|
|
8443
|
+
store.upsertFile({ file, lang, mtimeMs: Math.floor(stat11.mtimeMs), symbolCount: 0, lastIndexed: Date.now() });
|
|
8444
|
+
filesIndexed++;
|
|
8342
8445
|
}
|
|
8446
|
+
continue;
|
|
8343
8447
|
}
|
|
8344
|
-
|
|
8345
|
-
|
|
8448
|
+
const meta = existingMeta.get(file);
|
|
8449
|
+
if (!force && meta && meta.mtimeMs === Math.floor(stat11.mtimeMs)) {
|
|
8450
|
+
langStats[lang] = (langStats[lang] ?? 0) + meta.symbolCount;
|
|
8451
|
+
symbolsIndexed += meta.symbolCount;
|
|
8452
|
+
filesIndexed++;
|
|
8453
|
+
continue;
|
|
8454
|
+
}
|
|
8455
|
+
store.deleteRefsForFile(file);
|
|
8456
|
+
store.deleteSymbolsForFile(file);
|
|
8457
|
+
if (parsed.symbols.length === 0) {
|
|
8458
|
+
store.upsertFile({ file, lang, mtimeMs: Math.floor(stat11.mtimeMs), symbolCount: 0, lastIndexed: Date.now() });
|
|
8459
|
+
filesIndexed++;
|
|
8460
|
+
continue;
|
|
8461
|
+
}
|
|
8462
|
+
const nextId = store.getMaxSymbolId() + 1;
|
|
8463
|
+
const symbolsWithIds = parsed.symbols.map((s, i) => ({ ...s, id: nextId + i }));
|
|
8464
|
+
store.insertSymbols(symbolsWithIds, nextId);
|
|
8465
|
+
const count = symbolsWithIds.length;
|
|
8466
|
+
symbolsIndexed += count;
|
|
8467
|
+
langStats[lang] = (langStats[lang] ?? 0) + count;
|
|
8468
|
+
if (parsed.refs && parsed.refs.length > 0) {
|
|
8469
|
+
const refsByLine = /* @__PURE__ */ new Map();
|
|
8470
|
+
for (const r of parsed.refs) {
|
|
8471
|
+
let arr = refsByLine.get(r.line);
|
|
8472
|
+
if (!arr) {
|
|
8473
|
+
arr = [];
|
|
8474
|
+
refsByLine.set(r.line, arr);
|
|
8475
|
+
}
|
|
8476
|
+
arr.push(r);
|
|
8477
|
+
}
|
|
8478
|
+
const batch = [];
|
|
8479
|
+
for (const sym of symbolsWithIds) {
|
|
8480
|
+
const symRefs = refsByLine.get(sym.line);
|
|
8481
|
+
if (symRefs) {
|
|
8482
|
+
for (const r of symRefs) batch.push({ ...r, fromId: sym.id });
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
8485
|
+
if (batch.length > 0) store.insertRefsBatch(batch);
|
|
8346
8486
|
}
|
|
8487
|
+
store.upsertFile({ file, lang, mtimeMs: Math.floor(stat11.mtimeMs), symbolCount: count, lastIndexed: Date.now() });
|
|
8488
|
+
filesIndexed++;
|
|
8347
8489
|
}
|
|
8348
|
-
store.upsertFile({
|
|
8349
|
-
file,
|
|
8350
|
-
lang,
|
|
8351
|
-
mtimeMs: Math.floor(stat11.mtimeMs),
|
|
8352
|
-
symbolCount: count,
|
|
8353
|
-
lastIndexed: Date.now()
|
|
8354
|
-
});
|
|
8355
|
-
filesIndexed++;
|
|
8356
8490
|
}
|
|
8357
8491
|
for (const [file_] of existingMeta) {
|
|
8358
8492
|
try {
|
|
@@ -8534,7 +8668,7 @@ function shutdownCodebaseIndexHost() {
|
|
|
8534
8668
|
function callIndexOp(op, args, opts) {
|
|
8535
8669
|
const w = ensureWorker();
|
|
8536
8670
|
if (!w) return callInline(op, args, opts);
|
|
8537
|
-
return new Promise((
|
|
8671
|
+
return new Promise((resolve6, reject) => {
|
|
8538
8672
|
const id = nextRpcId++;
|
|
8539
8673
|
const timer = setTimeout(() => {
|
|
8540
8674
|
pending.delete(id);
|
|
@@ -8557,7 +8691,7 @@ function callIndexOp(op, args, opts) {
|
|
|
8557
8691
|
pending.set(id, {
|
|
8558
8692
|
resolve: (v) => {
|
|
8559
8693
|
cleanup();
|
|
8560
|
-
|
|
8694
|
+
resolve6(v);
|
|
8561
8695
|
},
|
|
8562
8696
|
reject: (e) => {
|
|
8563
8697
|
cleanup();
|
|
@@ -9566,8 +9700,8 @@ var TOOL_ICON_CONFIG = {
|
|
|
9566
9700
|
// emerald
|
|
9567
9701
|
folder: { icon: "folder", color: "#8b5cf6" },
|
|
9568
9702
|
// violet
|
|
9569
|
-
terminal: { icon: "terminal", color: "#
|
|
9570
|
-
//
|
|
9703
|
+
terminal: { icon: "terminal", color: "#fb923c" },
|
|
9704
|
+
// orange
|
|
9571
9705
|
web: { icon: "web", color: "#06b6d4" },
|
|
9572
9706
|
// cyan
|
|
9573
9707
|
git: { icon: "git", color: "#f97316" },
|