@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/builtin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn, execFileSync, spawnSync } from 'node:child_process';
|
|
2
2
|
import * as Core from '@wrongstack/core';
|
|
3
|
-
import { buildChildEnv, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, isPrivateIPv4, isPrivateIPv6, compileGlob, expectDefined, recordPackageAction, detectPackageEcosystem, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, mutateTasks, formatTaskList, formatPlan, computeTaskItemProgress, loadPlan, savePlan, loadTasks, saveTasks, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
3
|
+
import { buildChildEnv, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, isPrivateIPv4, isPrivateIPv6, assessCommitSafety, compileGlob, expectDefined, recordPackageAction, detectPackageEcosystem, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, mutateTasks, formatTaskList, formatPlan, computeTaskItemProgress, loadPlan, savePlan, loadTasks, saveTasks, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import { statSync, mkdirSync, createWriteStream, writeFileSync } from 'node:fs';
|
|
6
6
|
import * as fs14 from 'node:fs/promises';
|
|
@@ -763,8 +763,8 @@ async function* spawnStream(opts) {
|
|
|
763
763
|
try {
|
|
764
764
|
for (; ; ) {
|
|
765
765
|
while (queue.length === 0) {
|
|
766
|
-
await new Promise((
|
|
767
|
-
waiter =
|
|
766
|
+
await new Promise((resolve6) => {
|
|
767
|
+
waiter = resolve6;
|
|
768
768
|
});
|
|
769
769
|
}
|
|
770
770
|
const chunk = queue.shift();
|
|
@@ -1319,10 +1319,10 @@ var bashTool = {
|
|
|
1319
1319
|
queue.push(c);
|
|
1320
1320
|
}
|
|
1321
1321
|
};
|
|
1322
|
-
const next = () => new Promise((
|
|
1322
|
+
const next = () => new Promise((resolve6) => {
|
|
1323
1323
|
const c = queue.shift();
|
|
1324
|
-
if (c)
|
|
1325
|
-
else resolveNext =
|
|
1324
|
+
if (c) resolve6(c);
|
|
1325
|
+
else resolveNext = resolve6;
|
|
1326
1326
|
});
|
|
1327
1327
|
let lastFlush = Date.now();
|
|
1328
1328
|
const flush = () => {
|
|
@@ -3530,8 +3530,9 @@ async function loadGitignoreMatcher(projectRoot) {
|
|
|
3530
3530
|
|
|
3531
3531
|
// src/codebase-index/indexer.ts
|
|
3532
3532
|
var YIELD_EVERY_N = 50;
|
|
3533
|
+
var PARALLEL_BATCH = 20;
|
|
3533
3534
|
function yieldEventLoop() {
|
|
3534
|
-
return new Promise((
|
|
3535
|
+
return new Promise((resolve6) => setImmediate(resolve6));
|
|
3535
3536
|
}
|
|
3536
3537
|
function throwIfAborted(signal) {
|
|
3537
3538
|
if (!signal?.aborted) return;
|
|
@@ -3663,97 +3664,108 @@ async function runIndexerWithStore(store, opts) {
|
|
|
3663
3664
|
if (!force) {
|
|
3664
3665
|
for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
|
|
3665
3666
|
}
|
|
3666
|
-
for (let
|
|
3667
|
-
const
|
|
3668
|
-
|
|
3669
|
-
|
|
3667
|
+
for (let batchStart = 0; batchStart < files.length; batchStart += PARALLEL_BATCH) {
|
|
3668
|
+
const batchEnd = Math.min(batchStart + PARALLEL_BATCH, files.length);
|
|
3669
|
+
const batchFiles = files.slice(batchStart, batchEnd);
|
|
3670
|
+
opts.onProgress?.(batchEnd, files.length);
|
|
3671
|
+
if (batchStart > 0 && batchStart % YIELD_EVERY_N === 0) {
|
|
3670
3672
|
await yieldEventLoop();
|
|
3671
3673
|
throwIfAborted(signal);
|
|
3672
3674
|
}
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
if (!stat11.isFile()) continue;
|
|
3683
|
-
const lang = detectLang(file);
|
|
3684
|
-
if (!lang) continue;
|
|
3685
|
-
const meta = existingMeta.get(file);
|
|
3686
|
-
if (!force && meta && meta.mtimeMs === Math.floor(stat11.mtimeMs)) {
|
|
3687
|
-
langStats[lang] = (langStats[lang] ?? 0) + meta.symbolCount;
|
|
3688
|
-
symbolsIndexed += meta.symbolCount;
|
|
3689
|
-
filesIndexed++;
|
|
3690
|
-
continue;
|
|
3691
|
-
}
|
|
3692
|
-
store.deleteRefsForFile(file);
|
|
3693
|
-
store.deleteSymbolsForFile(file);
|
|
3694
|
-
let content;
|
|
3695
|
-
try {
|
|
3696
|
-
content = await fs14.readFile(file, { encoding: "utf8", signal });
|
|
3697
|
-
} catch (e) {
|
|
3698
|
-
if (isAbortError(e)) throw e;
|
|
3699
|
-
errors.push(`read error: ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
3700
|
-
continue;
|
|
3701
|
-
}
|
|
3702
|
-
let parsed;
|
|
3703
|
-
try {
|
|
3704
|
-
parsed = await parseFile(file, content, lang);
|
|
3705
|
-
} catch (e) {
|
|
3706
|
-
errors.push(`parse error: ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
3707
|
-
continue;
|
|
3708
|
-
}
|
|
3709
|
-
if (parsed.symbols.length === 0) {
|
|
3710
|
-
store.upsertFile({
|
|
3711
|
-
file,
|
|
3712
|
-
lang,
|
|
3713
|
-
mtimeMs: Math.floor(stat11.mtimeMs),
|
|
3714
|
-
symbolCount: 0,
|
|
3715
|
-
lastIndexed: Date.now()
|
|
3716
|
-
});
|
|
3717
|
-
filesIndexed++;
|
|
3718
|
-
continue;
|
|
3719
|
-
}
|
|
3720
|
-
const nextId = store.getMaxSymbolId() + 1;
|
|
3721
|
-
const symbolsWithIds = parsed.symbols.map((s, i) => ({ ...s, id: nextId + i }));
|
|
3722
|
-
store.insertSymbols(symbolsWithIds, nextId);
|
|
3723
|
-
const count = symbolsWithIds.length;
|
|
3724
|
-
symbolsIndexed += count;
|
|
3725
|
-
langStats[lang] = (langStats[lang] ?? 0) + count;
|
|
3726
|
-
if (parsed.refs && parsed.refs.length > 0) {
|
|
3727
|
-
const refsByLine = /* @__PURE__ */ new Map();
|
|
3728
|
-
for (const r of parsed.refs) {
|
|
3729
|
-
let arr = refsByLine.get(r.line);
|
|
3730
|
-
if (!arr) {
|
|
3731
|
-
arr = [];
|
|
3732
|
-
refsByLine.set(r.line, arr);
|
|
3675
|
+
const statOpts = signal ? { signal } : {};
|
|
3676
|
+
const statReadParse = await Promise.allSettled(
|
|
3677
|
+
batchFiles.map(async (file) => {
|
|
3678
|
+
let stat11;
|
|
3679
|
+
try {
|
|
3680
|
+
stat11 = await fs14.stat(file, statOpts);
|
|
3681
|
+
} catch (e) {
|
|
3682
|
+
if (isAbortError(e)) throw e;
|
|
3683
|
+
return { file, stat: null, lang: "", parsed: null, error: `stat error: ${e instanceof Error ? e.message : String(e)}` };
|
|
3733
3684
|
}
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
}
|
|
3685
|
+
if (!stat11.isFile()) return { file, stat: stat11, lang: "", parsed: null };
|
|
3686
|
+
const lang = detectLang(file);
|
|
3687
|
+
if (!lang) return { file, stat: stat11, lang: "", parsed: null };
|
|
3688
|
+
let content;
|
|
3689
|
+
try {
|
|
3690
|
+
content = await fs14.readFile(file, { encoding: "utf8", signal });
|
|
3691
|
+
} catch (e) {
|
|
3692
|
+
if (isAbortError(e)) throw e;
|
|
3693
|
+
return { file, stat: stat11, lang, parsed: null, error: `read error: ${e instanceof Error ? e.message : String(e)}` };
|
|
3694
|
+
}
|
|
3695
|
+
let parsed;
|
|
3696
|
+
try {
|
|
3697
|
+
parsed = await parseFile(file, content, lang);
|
|
3698
|
+
} catch (e) {
|
|
3699
|
+
return { file, stat: stat11, lang, parsed: null, error: `parse error: ${e instanceof Error ? e.message : String(e)}` };
|
|
3743
3700
|
}
|
|
3701
|
+
return { file, stat: stat11, lang, parsed, content };
|
|
3702
|
+
})
|
|
3703
|
+
);
|
|
3704
|
+
for (let fi = 0; fi < statReadParse.length; fi++) {
|
|
3705
|
+
const settled = statReadParse[fi];
|
|
3706
|
+
const file = expectDefined(batchFiles[fi]);
|
|
3707
|
+
if (settled.status === "rejected") {
|
|
3708
|
+
const err = settled.reason;
|
|
3709
|
+
if (err instanceof Error && isAbortError(err)) throw err;
|
|
3710
|
+
errors.push(`batch error: ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3711
|
+
continue;
|
|
3712
|
+
}
|
|
3713
|
+
const result = settled.value;
|
|
3714
|
+
if (result.error) {
|
|
3715
|
+
if (result.stat) store.deleteFile(file);
|
|
3716
|
+
if (result.error.includes("error:")) errors.push(result.error);
|
|
3717
|
+
continue;
|
|
3744
3718
|
}
|
|
3745
|
-
|
|
3746
|
-
|
|
3719
|
+
const { stat: stat11, lang, parsed } = result;
|
|
3720
|
+
if (!lang || !parsed) {
|
|
3721
|
+
if (lang) {
|
|
3722
|
+
store.upsertFile({ file, lang, mtimeMs: Math.floor(stat11.mtimeMs), symbolCount: 0, lastIndexed: Date.now() });
|
|
3723
|
+
filesIndexed++;
|
|
3724
|
+
}
|
|
3725
|
+
continue;
|
|
3747
3726
|
}
|
|
3727
|
+
const meta = existingMeta.get(file);
|
|
3728
|
+
if (!force && meta && meta.mtimeMs === Math.floor(stat11.mtimeMs)) {
|
|
3729
|
+
langStats[lang] = (langStats[lang] ?? 0) + meta.symbolCount;
|
|
3730
|
+
symbolsIndexed += meta.symbolCount;
|
|
3731
|
+
filesIndexed++;
|
|
3732
|
+
continue;
|
|
3733
|
+
}
|
|
3734
|
+
store.deleteRefsForFile(file);
|
|
3735
|
+
store.deleteSymbolsForFile(file);
|
|
3736
|
+
if (parsed.symbols.length === 0) {
|
|
3737
|
+
store.upsertFile({ file, lang, mtimeMs: Math.floor(stat11.mtimeMs), symbolCount: 0, lastIndexed: Date.now() });
|
|
3738
|
+
filesIndexed++;
|
|
3739
|
+
continue;
|
|
3740
|
+
}
|
|
3741
|
+
const nextId = store.getMaxSymbolId() + 1;
|
|
3742
|
+
const symbolsWithIds = parsed.symbols.map((s, i) => ({ ...s, id: nextId + i }));
|
|
3743
|
+
store.insertSymbols(symbolsWithIds, nextId);
|
|
3744
|
+
const count = symbolsWithIds.length;
|
|
3745
|
+
symbolsIndexed += count;
|
|
3746
|
+
langStats[lang] = (langStats[lang] ?? 0) + count;
|
|
3747
|
+
if (parsed.refs && parsed.refs.length > 0) {
|
|
3748
|
+
const refsByLine = /* @__PURE__ */ new Map();
|
|
3749
|
+
for (const r of parsed.refs) {
|
|
3750
|
+
let arr = refsByLine.get(r.line);
|
|
3751
|
+
if (!arr) {
|
|
3752
|
+
arr = [];
|
|
3753
|
+
refsByLine.set(r.line, arr);
|
|
3754
|
+
}
|
|
3755
|
+
arr.push(r);
|
|
3756
|
+
}
|
|
3757
|
+
const batch = [];
|
|
3758
|
+
for (const sym of symbolsWithIds) {
|
|
3759
|
+
const symRefs = refsByLine.get(sym.line);
|
|
3760
|
+
if (symRefs) {
|
|
3761
|
+
for (const r of symRefs) batch.push({ ...r, fromId: sym.id });
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
if (batch.length > 0) store.insertRefsBatch(batch);
|
|
3765
|
+
}
|
|
3766
|
+
store.upsertFile({ file, lang, mtimeMs: Math.floor(stat11.mtimeMs), symbolCount: count, lastIndexed: Date.now() });
|
|
3767
|
+
filesIndexed++;
|
|
3748
3768
|
}
|
|
3749
|
-
store.upsertFile({
|
|
3750
|
-
file,
|
|
3751
|
-
lang,
|
|
3752
|
-
mtimeMs: Math.floor(stat11.mtimeMs),
|
|
3753
|
-
symbolCount: count,
|
|
3754
|
-
lastIndexed: Date.now()
|
|
3755
|
-
});
|
|
3756
|
-
filesIndexed++;
|
|
3757
3769
|
}
|
|
3758
3770
|
for (const [file_] of existingMeta) {
|
|
3759
3771
|
try {
|
|
@@ -3920,7 +3932,7 @@ function terminateWorker(reason) {
|
|
|
3920
3932
|
function callIndexOp(op, args, opts) {
|
|
3921
3933
|
const w = ensureWorker();
|
|
3922
3934
|
if (!w) return callInline(op, args, opts);
|
|
3923
|
-
return new Promise((
|
|
3935
|
+
return new Promise((resolve6, reject) => {
|
|
3924
3936
|
const id = nextRpcId++;
|
|
3925
3937
|
const timer = setTimeout(() => {
|
|
3926
3938
|
pending.delete(id);
|
|
@@ -3943,7 +3955,7 @@ function callIndexOp(op, args, opts) {
|
|
|
3943
3955
|
pending.set(id, {
|
|
3944
3956
|
resolve: (v) => {
|
|
3945
3957
|
cleanup();
|
|
3946
|
-
|
|
3958
|
+
resolve6(v);
|
|
3947
3959
|
},
|
|
3948
3960
|
reject: (e) => {
|
|
3949
3961
|
cleanup();
|
|
@@ -4369,7 +4381,7 @@ function findGitDir(cwd) {
|
|
|
4369
4381
|
return null;
|
|
4370
4382
|
}
|
|
4371
4383
|
function runGit(args, cwd, signal) {
|
|
4372
|
-
return new Promise((
|
|
4384
|
+
return new Promise((resolve6) => {
|
|
4373
4385
|
let stdout = "";
|
|
4374
4386
|
let stderr = "";
|
|
4375
4387
|
const child = spawn("git", args, {
|
|
@@ -4385,8 +4397,8 @@ function runGit(args, cwd, signal) {
|
|
|
4385
4397
|
child.stderr?.on("data", (c) => {
|
|
4386
4398
|
stderr += c.toString();
|
|
4387
4399
|
});
|
|
4388
|
-
child.on("close", (code) =>
|
|
4389
|
-
child.on("error", (e) =>
|
|
4400
|
+
child.on("close", (code) => resolve6({ stdout, stderr, exitCode: code ?? 0 }));
|
|
4401
|
+
child.on("error", (e) => resolve6({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
4390
4402
|
});
|
|
4391
4403
|
}
|
|
4392
4404
|
async function fileDiff(input, ctx, _signal) {
|
|
@@ -4571,8 +4583,8 @@ function processFile(content, absPath, _style, _overwrite, target) {
|
|
|
4571
4583
|
var editTool = {
|
|
4572
4584
|
name: "edit",
|
|
4573
4585
|
category: "Filesystem",
|
|
4574
|
-
description: "Perform a precise, surgical text replacement in a file. This is the preferred tool for modifying existing code. It
|
|
4575
|
-
usageHint: "
|
|
4586
|
+
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.",
|
|
4587
|
+
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.",
|
|
4576
4588
|
permission: "confirm",
|
|
4577
4589
|
mutating: true,
|
|
4578
4590
|
capabilities: ["fs.write"],
|
|
@@ -4601,9 +4613,7 @@ var editTool = {
|
|
|
4601
4613
|
throw err;
|
|
4602
4614
|
});
|
|
4603
4615
|
if (!stat11.isFile()) throw new Error(`edit: "${input.path}" is not a regular file`);
|
|
4604
|
-
|
|
4605
|
-
throw new Error(`edit: file "${input.path}" was not read in this session. Read it first.`);
|
|
4606
|
-
}
|
|
4616
|
+
const autoRead = !ctx.hasRead(absPath);
|
|
4607
4617
|
const original = await fs14.readFile(absPath, "utf8");
|
|
4608
4618
|
const updated = await fs14.stat(absPath);
|
|
4609
4619
|
const mtimeTolerance = process.platform === "win32" ? 2e3 : 1;
|
|
@@ -4611,15 +4621,21 @@ var editTool = {
|
|
|
4611
4621
|
if (lastReadMtime !== void 0 && updated.mtimeMs > lastReadMtime + mtimeTolerance) {
|
|
4612
4622
|
throw new Error(`edit: file "${input.path}" was modified externally. Re-read it first.`);
|
|
4613
4623
|
}
|
|
4624
|
+
if (autoRead && updated.mtimeMs > stat11.mtimeMs + mtimeTolerance) {
|
|
4625
|
+
throw new Error(`edit: file "${input.path}" changed while being auto-read. Retry the edit.`);
|
|
4626
|
+
}
|
|
4627
|
+
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;
|
|
4614
4628
|
const style = detectNewlineStyle(original);
|
|
4615
4629
|
const fileLf = normalizeToLf(original);
|
|
4616
4630
|
const oldLf = normalizeToLf(input.old_string);
|
|
4617
4631
|
const newLf = normalizeToLf(input.new_string);
|
|
4618
4632
|
if (oldLf === newLf) {
|
|
4633
|
+
if (autoRead) ctx.recordRead(absPath, updated.mtimeMs);
|
|
4619
4634
|
return {
|
|
4620
4635
|
path: absPath,
|
|
4621
4636
|
replacements: 0,
|
|
4622
|
-
diff: "(no-op: old and new are identical)"
|
|
4637
|
+
diff: "(no-op: old and new are identical)",
|
|
4638
|
+
note: autoReadNote
|
|
4623
4639
|
};
|
|
4624
4640
|
}
|
|
4625
4641
|
let count = 0;
|
|
@@ -4660,7 +4676,8 @@ var editTool = {
|
|
|
4660
4676
|
return {
|
|
4661
4677
|
path: absPath,
|
|
4662
4678
|
replacements: input.replace_all ? count : 1,
|
|
4663
|
-
diff
|
|
4679
|
+
diff,
|
|
4680
|
+
note: autoReadNote
|
|
4664
4681
|
};
|
|
4665
4682
|
}
|
|
4666
4683
|
};
|
|
@@ -4872,26 +4889,26 @@ var execTool = {
|
|
|
4872
4889
|
allowed: false
|
|
4873
4890
|
};
|
|
4874
4891
|
}
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4892
|
+
let cwd;
|
|
4893
|
+
try {
|
|
4894
|
+
cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : await safeResolveReal(ctx.cwd, ctx);
|
|
4895
|
+
} catch {
|
|
4878
4896
|
return {
|
|
4879
4897
|
command: cmd,
|
|
4880
4898
|
args,
|
|
4881
4899
|
stdout: "",
|
|
4882
|
-
stderr: `cwd "${input.cwd}" resolves outside project root`,
|
|
4900
|
+
stderr: `cwd "${input.cwd ?? ctx.cwd}" resolves outside project root`,
|
|
4883
4901
|
exitCode: 1,
|
|
4884
4902
|
truncated: false,
|
|
4885
4903
|
allowed: false
|
|
4886
4904
|
};
|
|
4887
4905
|
}
|
|
4888
|
-
const cwd = requestedCwd;
|
|
4889
4906
|
const signal = opts.signal;
|
|
4890
4907
|
return runCommand(cmd, args, cwd, timeout, signal, ctx.session?.id);
|
|
4891
4908
|
}
|
|
4892
4909
|
};
|
|
4893
4910
|
function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
4894
|
-
return new Promise((
|
|
4911
|
+
return new Promise((resolve6) => {
|
|
4895
4912
|
let stdout = "";
|
|
4896
4913
|
let stderr = "";
|
|
4897
4914
|
let killed = false;
|
|
@@ -4946,7 +4963,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
4946
4963
|
const exitCode = killed ? 124 : code ?? 1;
|
|
4947
4964
|
registry.afterCall(durationMs, exitCode !== 0);
|
|
4948
4965
|
const spooled = spool.finalize();
|
|
4949
|
-
|
|
4966
|
+
resolve6({
|
|
4950
4967
|
command: cmd,
|
|
4951
4968
|
args,
|
|
4952
4969
|
stdout: normalizeCommandOutput(stdout) + (spooled ? spoolNote(spooled) : ""),
|
|
@@ -4962,7 +4979,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
4962
4979
|
if (typeof pid === "number") registry.unregister(pid);
|
|
4963
4980
|
registry.afterCall(Date.now() - startedAt, true);
|
|
4964
4981
|
spool.finalize();
|
|
4965
|
-
|
|
4982
|
+
resolve6({
|
|
4966
4983
|
command: cmd,
|
|
4967
4984
|
args,
|
|
4968
4985
|
stdout: normalizeCommandOutput(stdout),
|
|
@@ -5336,7 +5353,7 @@ var gitTool = {
|
|
|
5336
5353
|
name: "git",
|
|
5337
5354
|
category: "Git",
|
|
5338
5355
|
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.",
|
|
5339
|
-
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.",
|
|
5356
|
+
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.",
|
|
5340
5357
|
permission: "confirm",
|
|
5341
5358
|
icon: "git",
|
|
5342
5359
|
// Conservative: any of these may mutate. The non-mutating commands
|
|
@@ -5425,6 +5442,22 @@ var gitTool = {
|
|
|
5425
5442
|
};
|
|
5426
5443
|
}
|
|
5427
5444
|
const args = buildArgs(input);
|
|
5445
|
+
let safetyWarning;
|
|
5446
|
+
if (input.command === "commit") {
|
|
5447
|
+
try {
|
|
5448
|
+
const report = await assessCommitSafety({
|
|
5449
|
+
cwd: ctx.cwd,
|
|
5450
|
+
projectRoot: ctx.projectRoot,
|
|
5451
|
+
sessionId: ctx.session?.id,
|
|
5452
|
+
signal: opts.signal
|
|
5453
|
+
});
|
|
5454
|
+
if (report.warning) {
|
|
5455
|
+
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.";
|
|
5456
|
+
safetyWarning = report.warning + scopeNote;
|
|
5457
|
+
}
|
|
5458
|
+
} catch {
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5428
5461
|
let stagedDiff;
|
|
5429
5462
|
if (input.command === "commit" && !input.dry_run) {
|
|
5430
5463
|
try {
|
|
@@ -5438,6 +5471,7 @@ var gitTool = {
|
|
|
5438
5471
|
}
|
|
5439
5472
|
const result = await runGit2(args, gitDir, opts.signal);
|
|
5440
5473
|
if (stagedDiff !== void 0) result.diff = stagedDiff;
|
|
5474
|
+
if (safetyWarning !== void 0) result.warning = safetyWarning;
|
|
5441
5475
|
return result;
|
|
5442
5476
|
}
|
|
5443
5477
|
};
|
|
@@ -5549,7 +5583,7 @@ function buildArgs(input) {
|
|
|
5549
5583
|
}
|
|
5550
5584
|
}
|
|
5551
5585
|
function runGit2(args, cwd, signal) {
|
|
5552
|
-
return new Promise((
|
|
5586
|
+
return new Promise((resolve6) => {
|
|
5553
5587
|
let stdout = "";
|
|
5554
5588
|
let stderr = "";
|
|
5555
5589
|
const child = spawn("git", args, {
|
|
@@ -5570,7 +5604,7 @@ function runGit2(args, cwd, signal) {
|
|
|
5570
5604
|
}
|
|
5571
5605
|
});
|
|
5572
5606
|
child.on("error", (err) => {
|
|
5573
|
-
|
|
5607
|
+
resolve6({
|
|
5574
5608
|
command: args[0],
|
|
5575
5609
|
stdout: normalizeCommandOutput(stdout),
|
|
5576
5610
|
stderr: err.message,
|
|
@@ -5579,7 +5613,7 @@ function runGit2(args, cwd, signal) {
|
|
|
5579
5613
|
});
|
|
5580
5614
|
});
|
|
5581
5615
|
child.on("close", (code) => {
|
|
5582
|
-
|
|
5616
|
+
resolve6({
|
|
5583
5617
|
command: args[0],
|
|
5584
5618
|
stdout: normalizeCommandOutput(stdout),
|
|
5585
5619
|
stderr: normalizeCommandOutput(stderr),
|
|
@@ -5802,13 +5836,13 @@ var grepTool = {
|
|
|
5802
5836
|
}
|
|
5803
5837
|
};
|
|
5804
5838
|
async function detectRg(signal) {
|
|
5805
|
-
return new Promise((
|
|
5839
|
+
return new Promise((resolve6) => {
|
|
5806
5840
|
try {
|
|
5807
5841
|
const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore", signal, windowsHide: true });
|
|
5808
|
-
p.on("error", () =>
|
|
5809
|
-
p.on("close", (code) =>
|
|
5842
|
+
p.on("error", () => resolve6(false));
|
|
5843
|
+
p.on("close", (code) => resolve6(code === 0));
|
|
5810
5844
|
} catch {
|
|
5811
|
-
|
|
5845
|
+
resolve6(false);
|
|
5812
5846
|
}
|
|
5813
5847
|
});
|
|
5814
5848
|
}
|
|
@@ -6223,8 +6257,8 @@ var jsonTool = {
|
|
|
6223
6257
|
};
|
|
6224
6258
|
}
|
|
6225
6259
|
};
|
|
6226
|
-
function query(data,
|
|
6227
|
-
const parts =
|
|
6260
|
+
function query(data, path20) {
|
|
6261
|
+
const parts = path20.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
6228
6262
|
let current = data;
|
|
6229
6263
|
for (const part of parts) {
|
|
6230
6264
|
if (current === null || current === void 0) return void 0;
|
|
@@ -6450,7 +6484,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
6450
6484
|
};
|
|
6451
6485
|
}
|
|
6452
6486
|
args.push("--timestamps", service);
|
|
6453
|
-
return new Promise((
|
|
6487
|
+
return new Promise((resolve6) => {
|
|
6454
6488
|
let stdout = "";
|
|
6455
6489
|
let stderr = "";
|
|
6456
6490
|
const MAX = 2e5;
|
|
@@ -6466,7 +6500,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
6466
6500
|
if (settled) return;
|
|
6467
6501
|
settled = true;
|
|
6468
6502
|
clearTimeout(timer);
|
|
6469
|
-
|
|
6503
|
+
resolve6(result);
|
|
6470
6504
|
};
|
|
6471
6505
|
const child = spawn("docker", args, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
|
|
6472
6506
|
const timer = setTimeout(() => {
|
|
@@ -6501,7 +6535,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
6501
6535
|
}
|
|
6502
6536
|
var DOCKER_LOGS_TIMEOUT_MS = 3e3;
|
|
6503
6537
|
var MAX_TAIL_LINES = 1e5;
|
|
6504
|
-
async function fileLogs(
|
|
6538
|
+
async function fileLogs(path20, lines, filterRe, stream) {
|
|
6505
6539
|
const { createInterface } = await import('node:readline');
|
|
6506
6540
|
const { createReadStream } = await import('node:fs');
|
|
6507
6541
|
const entries = [];
|
|
@@ -6510,7 +6544,7 @@ async function fileLogs(path21, lines, filterRe, stream) {
|
|
|
6510
6544
|
let writeIdx = 0;
|
|
6511
6545
|
let totalLines = 0;
|
|
6512
6546
|
const rl = createInterface({
|
|
6513
|
-
input: createReadStream(
|
|
6547
|
+
input: createReadStream(path20),
|
|
6514
6548
|
crlfDelay: Number.POSITIVE_INFINITY
|
|
6515
6549
|
});
|
|
6516
6550
|
for await (const line of rl) {
|
|
@@ -6531,7 +6565,7 @@ async function fileLogs(path21, lines, filterRe, stream) {
|
|
|
6531
6565
|
if (parsed) entries.push(parsed);
|
|
6532
6566
|
}
|
|
6533
6567
|
return {
|
|
6534
|
-
source:
|
|
6568
|
+
source: path20,
|
|
6535
6569
|
entries,
|
|
6536
6570
|
total: entries.length,
|
|
6537
6571
|
truncated: totalLines > effLines,
|
|
@@ -6589,12 +6623,15 @@ var outdatedTool = {
|
|
|
6589
6623
|
// fixed four sibling tools (mcp_control, shellcheck, shellcheck_scan,
|
|
6590
6624
|
// web_search) but missed this one; applying the same contract here.
|
|
6591
6625
|
mutating: true,
|
|
6592
|
-
// Capability is
|
|
6626
|
+
// Capability is outbound network — the tool only hits the package
|
|
6593
6627
|
// registry over HTTP, never touches the filesystem or runs shell.
|
|
6628
|
+
// Use the canonical `net.outbound` capability (not the non-existent
|
|
6629
|
+
// `network` string) so the subagent allowlist recognises it and
|
|
6630
|
+
// permits read-only registry lookups under a director.
|
|
6594
6631
|
// The H7 invariant test requires this array to be non-empty for
|
|
6595
6632
|
// any mutating:true tool (meta-tools whitelisted). See
|
|
6596
6633
|
// tests/permission-mutating-invariant.test.ts:92.
|
|
6597
|
-
capabilities: ["
|
|
6634
|
+
capabilities: ["net.outbound"],
|
|
6598
6635
|
timeoutMs: 6e4,
|
|
6599
6636
|
inputSchema: {
|
|
6600
6637
|
type: "object",
|
|
@@ -6625,7 +6662,7 @@ var outdatedTool = {
|
|
|
6625
6662
|
}
|
|
6626
6663
|
};
|
|
6627
6664
|
function runOutdated(manager, args, cwd, signal) {
|
|
6628
|
-
return new Promise((
|
|
6665
|
+
return new Promise((resolve6) => {
|
|
6629
6666
|
let stdout = "";
|
|
6630
6667
|
let stderr = "";
|
|
6631
6668
|
const MAX = 1e5;
|
|
@@ -6641,10 +6678,10 @@ function runOutdated(manager, args, cwd, signal) {
|
|
|
6641
6678
|
});
|
|
6642
6679
|
child.on("close", (code) => {
|
|
6643
6680
|
const result = parseOutdatedOutput(stdout, code ?? 0);
|
|
6644
|
-
|
|
6681
|
+
resolve6(result);
|
|
6645
6682
|
});
|
|
6646
6683
|
child.on("error", (e) => {
|
|
6647
|
-
|
|
6684
|
+
resolve6({
|
|
6648
6685
|
exit_code: 1,
|
|
6649
6686
|
packages: [],
|
|
6650
6687
|
total: 0,
|
|
@@ -6778,7 +6815,7 @@ function stripPathComponents(p, strip) {
|
|
|
6778
6815
|
return parts.slice(strip).join("/");
|
|
6779
6816
|
}
|
|
6780
6817
|
function runPatch(args, cwd, signal) {
|
|
6781
|
-
return new Promise((
|
|
6818
|
+
return new Promise((resolve6) => {
|
|
6782
6819
|
let stdout = "";
|
|
6783
6820
|
let stderr = "";
|
|
6784
6821
|
const env = { ...buildChildEnv(), LANG: "C", LC_ALL: "C" };
|
|
@@ -6789,8 +6826,8 @@ function runPatch(args, cwd, signal) {
|
|
|
6789
6826
|
child.stderr?.on("data", (c) => {
|
|
6790
6827
|
stderr += c.toString();
|
|
6791
6828
|
});
|
|
6792
|
-
child.on("close", (code) =>
|
|
6793
|
-
child.on("error", (e) =>
|
|
6829
|
+
child.on("close", (code) => resolve6({ exitCode: code ?? 1, stdout, stderr }));
|
|
6830
|
+
child.on("error", (e) => resolve6({ exitCode: 1, stdout: "", stderr: e.message }));
|
|
6794
6831
|
});
|
|
6795
6832
|
}
|
|
6796
6833
|
function extractPatchedFiles(output) {
|
|
@@ -7087,6 +7124,11 @@ var readTool = {
|
|
|
7087
7124
|
limit: {
|
|
7088
7125
|
type: "integer",
|
|
7089
7126
|
description: "Maximum number of lines to return (default is 2000)."
|
|
7127
|
+
},
|
|
7128
|
+
mode: {
|
|
7129
|
+
type: "string",
|
|
7130
|
+
enum: ["content", "summary"],
|
|
7131
|
+
description: "Return full line-numbered content (default) or a compact file summary with imports/exports/symbols."
|
|
7090
7132
|
}
|
|
7091
7133
|
},
|
|
7092
7134
|
required: ["path"]
|
|
@@ -7100,14 +7142,27 @@ var readTool = {
|
|
|
7100
7142
|
} catch (err) {
|
|
7101
7143
|
const code = err.code;
|
|
7102
7144
|
if (code === "ENOENT") throw new Error(`read: file not found "${input.path}"`);
|
|
7103
|
-
throw new Error(
|
|
7104
|
-
`read: failed to stat "${input.path}": ${toErrorMessage(err)}`
|
|
7105
|
-
);
|
|
7145
|
+
throw new Error(`read: failed to stat "${input.path}": ${toErrorMessage(err)}`);
|
|
7106
7146
|
}
|
|
7107
7147
|
if (!stat11.isFile()) throw new Error(`read: "${input.path}" is not a regular file`);
|
|
7108
7148
|
if (stat11.size > MAX_BYTES2) {
|
|
7109
7149
|
throw new Error(`read: file too large (${stat11.size} bytes, limit ${MAX_BYTES2})`);
|
|
7110
7150
|
}
|
|
7151
|
+
const offset = Math.max(1, input.offset ?? 1);
|
|
7152
|
+
const limit = Math.max(0, Math.min(input.limit ?? 2e3, 5e3));
|
|
7153
|
+
const prior = getReadRangeRecord(ctx, absPath);
|
|
7154
|
+
const requestedEnd = prior ? Math.min(offset + limit - 1, prior.totalLines) : offset + limit - 1;
|
|
7155
|
+
if (input.mode !== "summary" && limit > 0 && prior && coversRange(prior, stat11.mtimeMs, offset, requestedEnd)) {
|
|
7156
|
+
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
7157
|
+
return {
|
|
7158
|
+
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.]`,
|
|
7159
|
+
total_lines: prior.totalLines,
|
|
7160
|
+
encoding: "utf8",
|
|
7161
|
+
truncated: requestedEnd < prior.totalLines,
|
|
7162
|
+
cached: true,
|
|
7163
|
+
note: "Repeated read suppressed to save tokens."
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7111
7166
|
const buf = await fs14.readFile(absPath);
|
|
7112
7167
|
if (isBinaryBuffer(buf)) {
|
|
7113
7168
|
throw new Error(`read: "${input.path}" appears to be binary`);
|
|
@@ -7115,17 +7170,38 @@ var readTool = {
|
|
|
7115
7170
|
const text = buf.toString("utf8");
|
|
7116
7171
|
const allLines = text.split(/\r\n|\r|\n/);
|
|
7117
7172
|
const total = allLines.length;
|
|
7118
|
-
|
|
7119
|
-
|
|
7173
|
+
if (input.mode === "summary") {
|
|
7174
|
+
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
7175
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, 1, Math.min(total, 200));
|
|
7176
|
+
return {
|
|
7177
|
+
text: summarizeFile(input.path, stat11.size, allLines),
|
|
7178
|
+
total_lines: total,
|
|
7179
|
+
encoding: "utf8",
|
|
7180
|
+
truncated: total > 200,
|
|
7181
|
+
note: "Summary mode returned compact structure instead of full file content."
|
|
7182
|
+
};
|
|
7183
|
+
}
|
|
7120
7184
|
if (limit === 0) {
|
|
7121
7185
|
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
7186
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, 1, 0);
|
|
7122
7187
|
return { text: "", total_lines: total, encoding: "utf8", truncated: total > 0 };
|
|
7123
7188
|
}
|
|
7189
|
+
if (offset > total) {
|
|
7190
|
+
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
7191
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, total + 1, total + 1);
|
|
7192
|
+
return {
|
|
7193
|
+
text: `[offset ${offset} is past end of file "${input.path}" \u2014 file has ${total} line(s). Do not retry this offset.]`,
|
|
7194
|
+
total_lines: total,
|
|
7195
|
+
encoding: "utf8",
|
|
7196
|
+
truncated: false
|
|
7197
|
+
};
|
|
7198
|
+
}
|
|
7124
7199
|
const slice = allLines.slice(offset - 1, offset - 1 + limit);
|
|
7125
7200
|
const truncated = offset - 1 + slice.length < total;
|
|
7126
7201
|
const width = String(offset + slice.length - 1).length;
|
|
7127
7202
|
const numbered = slice.map((line, i) => `${String(offset + i).padStart(width, " ")}\u2192${line}`).join("\n");
|
|
7128
7203
|
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
7204
|
+
rememberReadRange(ctx, absPath, stat11.mtimeMs, total, offset, offset + slice.length - 1);
|
|
7129
7205
|
return {
|
|
7130
7206
|
text: numbered,
|
|
7131
7207
|
total_lines: total,
|
|
@@ -7134,6 +7210,62 @@ var readTool = {
|
|
|
7134
7210
|
};
|
|
7135
7211
|
}
|
|
7136
7212
|
};
|
|
7213
|
+
var READ_RANGES_META_KEY = "tools.read.ranges.v1";
|
|
7214
|
+
function getReadRanges(ctx) {
|
|
7215
|
+
const existing = ctx.meta[READ_RANGES_META_KEY];
|
|
7216
|
+
if (existing && typeof existing === "object" && !Array.isArray(existing)) {
|
|
7217
|
+
return existing;
|
|
7218
|
+
}
|
|
7219
|
+
const next = {};
|
|
7220
|
+
ctx.meta[READ_RANGES_META_KEY] = next;
|
|
7221
|
+
return next;
|
|
7222
|
+
}
|
|
7223
|
+
function getReadRangeRecord(ctx, absPath) {
|
|
7224
|
+
return getReadRanges(ctx)[absPath];
|
|
7225
|
+
}
|
|
7226
|
+
function rememberReadRange(ctx, absPath, mtimeMs, totalLines, start, end) {
|
|
7227
|
+
if (end < start) return;
|
|
7228
|
+
const ranges = getReadRanges(ctx);
|
|
7229
|
+
const prior = ranges[absPath];
|
|
7230
|
+
const nextRanges = prior && Math.abs(prior.mtimeMs - mtimeMs) <= 1 ? prior.ranges.slice() : [];
|
|
7231
|
+
nextRanges.push({ start, end });
|
|
7232
|
+
ranges[absPath] = {
|
|
7233
|
+
mtimeMs,
|
|
7234
|
+
totalLines,
|
|
7235
|
+
ranges: mergeRanges(nextRanges)
|
|
7236
|
+
};
|
|
7237
|
+
}
|
|
7238
|
+
function coversRange(record, mtimeMs, start, end) {
|
|
7239
|
+
if (Math.abs(record.mtimeMs - mtimeMs) > 1) return false;
|
|
7240
|
+
return record.ranges.some((range) => range.start <= start && range.end >= end);
|
|
7241
|
+
}
|
|
7242
|
+
function mergeRanges(ranges) {
|
|
7243
|
+
const sorted = ranges.slice().sort((a, b) => a.start - b.start);
|
|
7244
|
+
const merged = [];
|
|
7245
|
+
for (const range of sorted) {
|
|
7246
|
+
const last = merged[merged.length - 1];
|
|
7247
|
+
if (!last || range.start > last.end + 1) {
|
|
7248
|
+
merged.push({ ...range });
|
|
7249
|
+
continue;
|
|
7250
|
+
}
|
|
7251
|
+
last.end = Math.max(last.end, range.end);
|
|
7252
|
+
}
|
|
7253
|
+
return merged;
|
|
7254
|
+
}
|
|
7255
|
+
function summarizeFile(filePath, bytes, lines) {
|
|
7256
|
+
const interesting = lines.map((line, index) => ({ line: line.trim(), number: index + 1 })).filter(
|
|
7257
|
+
({ 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(
|
|
7258
|
+
line
|
|
7259
|
+
)
|
|
7260
|
+
).slice(0, 80).map(({ line, number }) => `${number}: ${line}`);
|
|
7261
|
+
return [
|
|
7262
|
+
`summary: ${filePath}`,
|
|
7263
|
+
`bytes=${bytes}`,
|
|
7264
|
+
`total_lines=${lines.length}`,
|
|
7265
|
+
interesting.length > 0 ? `symbols/imports:
|
|
7266
|
+
${interesting.join("\n")}` : "symbols/imports: (none detected)"
|
|
7267
|
+
].join("\n");
|
|
7268
|
+
}
|
|
7137
7269
|
var DEFAULT_IGNORE4 = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
|
|
7138
7270
|
var replaceTool = {
|
|
7139
7271
|
name: "replace",
|
|
@@ -7270,13 +7402,13 @@ async function globFiles(pattern, base, extraGlob) {
|
|
|
7270
7402
|
return await globNative(pattern, base, extraGlob);
|
|
7271
7403
|
}
|
|
7272
7404
|
function checkRg() {
|
|
7273
|
-
return new Promise((
|
|
7405
|
+
return new Promise((resolve6) => {
|
|
7274
7406
|
try {
|
|
7275
7407
|
const p = spawn("rg", ["--version"], { env: buildChildEnv(), stdio: "ignore", windowsHide: true });
|
|
7276
|
-
p.on("error", () =>
|
|
7277
|
-
p.on("close", (code) =>
|
|
7408
|
+
p.on("error", () => resolve6(false));
|
|
7409
|
+
p.on("close", (code) => resolve6(code === 0));
|
|
7278
7410
|
} catch {
|
|
7279
|
-
|
|
7411
|
+
resolve6(false);
|
|
7280
7412
|
}
|
|
7281
7413
|
});
|
|
7282
7414
|
}
|
|
@@ -7293,10 +7425,10 @@ function spawnRgFind(pattern, base) {
|
|
|
7293
7425
|
buf += chunk.toString();
|
|
7294
7426
|
});
|
|
7295
7427
|
return {
|
|
7296
|
-
promise: new Promise((
|
|
7428
|
+
promise: new Promise((resolve6, reject) => {
|
|
7297
7429
|
child.on("error", reject);
|
|
7298
7430
|
child.on("close", () => {
|
|
7299
|
-
|
|
7431
|
+
resolve6(buf.split("\n").filter(Boolean));
|
|
7300
7432
|
});
|
|
7301
7433
|
})
|
|
7302
7434
|
};
|