reasonix 0.24.1 → 0.25.1
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/cli/index.js +9186 -6440
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{prompt-VZQ2CPID.js → prompt-YUL7CYKY.js} +1 -2
- package/dist/index.d.ts +1 -16
- package/dist/index.js +481 -84
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/banner-demo-C3FJP4R6.js +0 -77
- package/dist/cli/banner-demo-C3FJP4R6.js.map +0 -1
- package/dist/cli/card-demo-OEFBRAJP.js +0 -944
- package/dist/cli/card-demo-OEFBRAJP.js.map +0 -1
- package/dist/cli/chunk-2H7UOFLK.js +0 -11
- package/dist/cli/chunk-2K5D5J3I.js +0 -197
- package/dist/cli/chunk-2K5D5J3I.js.map +0 -1
- package/dist/cli/chunk-V3DLUJY6.js +0 -2066
- package/dist/cli/chunk-V3DLUJY6.js.map +0 -1
- package/dist/cli/flicker-demo-YCYC5AR7.js +0 -165
- package/dist/cli/flicker-demo-YCYC5AR7.js.map +0 -1
- package/dist/cli/preview-7BGTDC65.js +0 -224
- package/dist/cli/preview-7BGTDC65.js.map +0 -1
- package/dist/cli/prompt-VZQ2CPID.js.map +0 -1
- package/dist/cli/renderer-demo-262TD7PU.js +0 -95
- package/dist/cli/renderer-demo-262TD7PU.js.map +0 -1
- package/dist/cli/select-demo-3QMFXV5D.js +0 -107
- package/dist/cli/select-demo-3QMFXV5D.js.map +0 -1
- package/dist/cli/stress-demo-W3AU6PUZ.js +0 -211
- package/dist/cli/stress-demo-W3AU6PUZ.js.map +0 -1
- /package/dist/cli/{chunk-2H7UOFLK.js.map → prompt-YUL7CYKY.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -47,8 +47,8 @@ function computeWait(attempt, initial, cap, retryAfter) {
|
|
|
47
47
|
}
|
|
48
48
|
function sleep(ms, signal) {
|
|
49
49
|
if (ms <= 0) return Promise.resolve();
|
|
50
|
-
return new Promise((
|
|
51
|
-
const timer = setTimeout(
|
|
50
|
+
return new Promise((resolve10, reject) => {
|
|
51
|
+
const timer = setTimeout(resolve10, ms);
|
|
52
52
|
if (signal) {
|
|
53
53
|
const onAbort = () => {
|
|
54
54
|
clearTimeout(timer);
|
|
@@ -523,7 +523,7 @@ function matchesTool(hook, toolName) {
|
|
|
523
523
|
}
|
|
524
524
|
var HOOK_OUTPUT_CAP_BYTES = 256 * 1024;
|
|
525
525
|
function defaultSpawner(input) {
|
|
526
|
-
return new Promise((
|
|
526
|
+
return new Promise((resolve10) => {
|
|
527
527
|
const child = spawn(input.command, {
|
|
528
528
|
cwd: input.cwd,
|
|
529
529
|
shell: true,
|
|
@@ -568,7 +568,7 @@ function defaultSpawner(input) {
|
|
|
568
568
|
child.stderr.on("data", (chunk) => onChunk("stderr", chunk));
|
|
569
569
|
child.once("error", (err) => {
|
|
570
570
|
clearTimeout(timer);
|
|
571
|
-
|
|
571
|
+
resolve10({
|
|
572
572
|
exitCode: null,
|
|
573
573
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
574
574
|
stderr: Buffer.concat(stderrChunks).toString("utf8"),
|
|
@@ -579,7 +579,7 @@ function defaultSpawner(input) {
|
|
|
579
579
|
});
|
|
580
580
|
child.once("close", (code) => {
|
|
581
581
|
clearTimeout(timer);
|
|
582
|
-
|
|
582
|
+
resolve10({
|
|
583
583
|
exitCode: code,
|
|
584
584
|
stdout: Buffer.concat(stdoutChunks).toString("utf8").trim(),
|
|
585
585
|
stderr: Buffer.concat(stderrChunks).toString("utf8").trim(),
|
|
@@ -2310,8 +2310,8 @@ var CacheFirstLoop = class {
|
|
|
2310
2310
|
}
|
|
2311
2311
|
);
|
|
2312
2312
|
for (let k = 0; k < budget; k++) {
|
|
2313
|
-
const sample = queue.shift() ?? await new Promise((
|
|
2314
|
-
waiter =
|
|
2313
|
+
const sample = queue.shift() ?? await new Promise((resolve10) => {
|
|
2314
|
+
waiter = resolve10;
|
|
2315
2315
|
});
|
|
2316
2316
|
yield {
|
|
2317
2317
|
turn: this._turn,
|
|
@@ -4926,33 +4926,6 @@ var PlanProposedError = class extends Error {
|
|
|
4926
4926
|
return payload;
|
|
4927
4927
|
}
|
|
4928
4928
|
};
|
|
4929
|
-
var PlanCheckpointError = class extends Error {
|
|
4930
|
-
stepId;
|
|
4931
|
-
title;
|
|
4932
|
-
result;
|
|
4933
|
-
notes;
|
|
4934
|
-
constructor(update) {
|
|
4935
|
-
super(
|
|
4936
|
-
"PlanCheckpointError: step complete \u2014 STOP calling tools. The TUI has paused the plan for user review. Wait for the next user message; it will either say continue (proceed to the next step), request a revision (adjust the remaining plan), or stop (summarize and end)."
|
|
4937
|
-
);
|
|
4938
|
-
this.name = "PlanCheckpointError";
|
|
4939
|
-
this.stepId = update.stepId;
|
|
4940
|
-
this.title = update.title;
|
|
4941
|
-
this.result = update.result;
|
|
4942
|
-
this.notes = update.notes;
|
|
4943
|
-
}
|
|
4944
|
-
toToolResult() {
|
|
4945
|
-
const payload = {
|
|
4946
|
-
error: `${this.name}: ${this.message}`,
|
|
4947
|
-
kind: "step_completed",
|
|
4948
|
-
stepId: this.stepId,
|
|
4949
|
-
result: this.result
|
|
4950
|
-
};
|
|
4951
|
-
if (this.title) payload.title = this.title;
|
|
4952
|
-
if (this.notes) payload.notes = this.notes;
|
|
4953
|
-
return payload;
|
|
4954
|
-
}
|
|
4955
|
-
};
|
|
4956
4929
|
var PlanRevisionProposedError = class extends Error {
|
|
4957
4930
|
reason;
|
|
4958
4931
|
remainingSteps;
|
|
@@ -4979,7 +4952,7 @@ var PlanRevisionProposedError = class extends Error {
|
|
|
4979
4952
|
|
|
4980
4953
|
// src/tools/plan-core.ts
|
|
4981
4954
|
var SUBMIT_PLAN_DESCRIPTION = "Submit ONE concrete plan you've already decided on. Use this for tasks that warrant a review gate \u2014 multi-file refactors, architecture changes, anything that would be expensive or confusing to undo. Skip it for small fixes (one-line typo, obvious bug with a clear fix) \u2014 just make the change. The user will either approve (you then implement it), ask for refinement, or cancel. If the user has already enabled /plan mode, writes are blocked at dispatch and you MUST use this. CRITICAL: do NOT use submit_plan to present alternative routes (A/B/C, option 1/2/3) for the user to pick from \u2014 the picker only exposes approve/refine/cancel, so a menu plan strands the user with no way to choose. For branching decisions, call `ask_choice` instead; only call submit_plan once the user has picked a direction and you have a single actionable plan. Write the plan as markdown with a one-line summary, a bulleted list of files to touch and what will change, and any risks or open questions. STRONGLY PREFERRED: pass `steps` \u2014 an array of {id, title, action, risk?} \u2014 so the UI renders a structured step list above the approval picker and tracks per-step progress. Use risk='high' for steps that touch prod data / break public APIs / are hard to undo; 'med' for non-trivial but reversible (multi-file edits, schema tweaks); 'low' for safe local work. After each step, call `mark_step_complete` so the user sees progress ticks.";
|
|
4982
|
-
var MARK_STEP_COMPLETE_DESCRIPTION = "Mark one step of the approved plan as done
|
|
4955
|
+
var MARK_STEP_COMPLETE_DESCRIPTION = "Mark one step of the approved plan as done. Call this after finishing each step, then immediately continue with the NEXT step \u2014 do not stop or wait for the user. The TUI updates the plan card's progress in place. After the FINAL step, write a brief reply summarizing what was done and end the turn. Pass the `stepId` from the plan's steps array, a short `result` (what you did), and optional `notes` for anything surprising (errors, scope changes, follow-ups). This tool doesn't change any files. Don't call it if the plan didn't include structured steps, and don't invent ids that weren't in the original plan.";
|
|
4983
4956
|
var REVISE_PLAN_DESCRIPTION = "Surgically replace the REMAINING steps of an in-flight plan. Call this when the user has given feedback at a checkpoint that warrants a structured plan change \u2014 skip a step, swap two steps, add a new step, change risk, etc. Pass: `reason` (one sentence why), `remainingSteps` (the new tail of the plan, replacing whatever steps haven't been done yet), and optional `summary` (updated one-line plan summary). Done steps are NEVER touched \u2014 keep them out of `remainingSteps`. The TUI shows a diff (removed in red, kept in gray, added in green) and the user accepts or rejects. Don't call this for trivial mid-step adjustments \u2014 just keep executing. Don't call submit_plan for revisions either \u2014 that resets the whole plan including completed steps. Use submit_plan only when the entire approach has changed; use revise_plan when the tail needs editing.";
|
|
4984
4957
|
var STEP_ITEM_SCHEMA = {
|
|
4985
4958
|
type: "object",
|
|
@@ -5096,7 +5069,7 @@ function registerMarkStepComplete(registry, opts) {
|
|
|
5096
5069
|
if (title) update.title = title;
|
|
5097
5070
|
if (notes) update.notes = notes;
|
|
5098
5071
|
opts.onStepCompleted?.(update);
|
|
5099
|
-
|
|
5072
|
+
return update;
|
|
5100
5073
|
}
|
|
5101
5074
|
});
|
|
5102
5075
|
}
|
|
@@ -5394,9 +5367,9 @@ function forkRegistryExcluding(parent, exclude) {
|
|
|
5394
5367
|
}
|
|
5395
5368
|
|
|
5396
5369
|
// src/tools/shell.ts
|
|
5397
|
-
import { spawn as
|
|
5370
|
+
import { spawn as spawn4, spawnSync } from "child_process";
|
|
5398
5371
|
import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
5399
|
-
import * as
|
|
5372
|
+
import * as pathMod4 from "path";
|
|
5400
5373
|
|
|
5401
5374
|
// src/tools/jobs.ts
|
|
5402
5375
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -5686,6 +5659,417 @@ function snapshot(job) {
|
|
|
5686
5659
|
};
|
|
5687
5660
|
}
|
|
5688
5661
|
|
|
5662
|
+
// src/tools/shell-chain.ts
|
|
5663
|
+
import { spawn as spawn3 } from "child_process";
|
|
5664
|
+
import { closeSync, openSync } from "fs";
|
|
5665
|
+
import * as pathMod3 from "path";
|
|
5666
|
+
var UnsupportedSyntaxError = class extends Error {
|
|
5667
|
+
constructor(detail) {
|
|
5668
|
+
super(`run_command: ${detail}`);
|
|
5669
|
+
this.name = "UnsupportedSyntaxError";
|
|
5670
|
+
}
|
|
5671
|
+
};
|
|
5672
|
+
function splitOnChainOps(cmd) {
|
|
5673
|
+
const segs = [];
|
|
5674
|
+
const ops = [];
|
|
5675
|
+
let segStart = 0;
|
|
5676
|
+
let i = 0;
|
|
5677
|
+
let quote = null;
|
|
5678
|
+
let atTokenStart = true;
|
|
5679
|
+
while (i < cmd.length) {
|
|
5680
|
+
const ch = cmd[i];
|
|
5681
|
+
if (quote) {
|
|
5682
|
+
if (ch === quote) quote = null;
|
|
5683
|
+
else if (ch === "\\" && quote === '"' && i + 1 < cmd.length) i++;
|
|
5684
|
+
i++;
|
|
5685
|
+
atTokenStart = false;
|
|
5686
|
+
continue;
|
|
5687
|
+
}
|
|
5688
|
+
if (ch === '"' || ch === "'") {
|
|
5689
|
+
quote = ch;
|
|
5690
|
+
i++;
|
|
5691
|
+
atTokenStart = false;
|
|
5692
|
+
continue;
|
|
5693
|
+
}
|
|
5694
|
+
if (ch === " " || ch === " ") {
|
|
5695
|
+
i++;
|
|
5696
|
+
atTokenStart = true;
|
|
5697
|
+
continue;
|
|
5698
|
+
}
|
|
5699
|
+
if (atTokenStart) {
|
|
5700
|
+
let op = null;
|
|
5701
|
+
let opLen = 0;
|
|
5702
|
+
const next = cmd[i + 1];
|
|
5703
|
+
if (ch === "|" && next === "|") {
|
|
5704
|
+
op = "||";
|
|
5705
|
+
opLen = 2;
|
|
5706
|
+
} else if (ch === "&" && next === "&") {
|
|
5707
|
+
op = "&&";
|
|
5708
|
+
opLen = 2;
|
|
5709
|
+
} else if (ch === "|") {
|
|
5710
|
+
op = "|";
|
|
5711
|
+
opLen = 1;
|
|
5712
|
+
} else if (ch === ";") {
|
|
5713
|
+
op = ";";
|
|
5714
|
+
opLen = 1;
|
|
5715
|
+
}
|
|
5716
|
+
if (op !== null) {
|
|
5717
|
+
segs.push(cmd.slice(segStart, i));
|
|
5718
|
+
ops.push(op);
|
|
5719
|
+
i += opLen;
|
|
5720
|
+
segStart = i;
|
|
5721
|
+
atTokenStart = true;
|
|
5722
|
+
continue;
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
i++;
|
|
5726
|
+
atTokenStart = false;
|
|
5727
|
+
}
|
|
5728
|
+
segs.push(cmd.slice(segStart));
|
|
5729
|
+
return { segs, ops };
|
|
5730
|
+
}
|
|
5731
|
+
function parseSegment(segStr) {
|
|
5732
|
+
const argv = [];
|
|
5733
|
+
const redirects = [];
|
|
5734
|
+
let cur = "";
|
|
5735
|
+
let curHasContent = false;
|
|
5736
|
+
let pending = null;
|
|
5737
|
+
let quote = null;
|
|
5738
|
+
const flush = () => {
|
|
5739
|
+
if (!curHasContent && cur.length === 0) return;
|
|
5740
|
+
if (pending) {
|
|
5741
|
+
redirects.push({ kind: pending, target: cur });
|
|
5742
|
+
pending = null;
|
|
5743
|
+
} else {
|
|
5744
|
+
argv.push(cur);
|
|
5745
|
+
}
|
|
5746
|
+
cur = "";
|
|
5747
|
+
curHasContent = false;
|
|
5748
|
+
};
|
|
5749
|
+
let i = 0;
|
|
5750
|
+
while (i < segStr.length) {
|
|
5751
|
+
const ch = segStr[i];
|
|
5752
|
+
if (quote) {
|
|
5753
|
+
if (ch === quote) {
|
|
5754
|
+
quote = null;
|
|
5755
|
+
} else if (ch === "\\" && quote === '"' && i + 1 < segStr.length) {
|
|
5756
|
+
cur += segStr[++i] ?? "";
|
|
5757
|
+
curHasContent = true;
|
|
5758
|
+
} else {
|
|
5759
|
+
cur += ch;
|
|
5760
|
+
curHasContent = true;
|
|
5761
|
+
}
|
|
5762
|
+
i++;
|
|
5763
|
+
continue;
|
|
5764
|
+
}
|
|
5765
|
+
if (ch === '"' || ch === "'") {
|
|
5766
|
+
quote = ch;
|
|
5767
|
+
curHasContent = true;
|
|
5768
|
+
i++;
|
|
5769
|
+
continue;
|
|
5770
|
+
}
|
|
5771
|
+
if (ch === " " || ch === " ") {
|
|
5772
|
+
flush();
|
|
5773
|
+
i++;
|
|
5774
|
+
continue;
|
|
5775
|
+
}
|
|
5776
|
+
if (cur.length === 0 && !curHasContent) {
|
|
5777
|
+
const remaining = segStr.slice(i);
|
|
5778
|
+
let matched = null;
|
|
5779
|
+
if (remaining.startsWith("2>&1")) matched = { op: "2>&1", len: 4 };
|
|
5780
|
+
else if (remaining.startsWith("&>")) matched = { op: "&>", len: 2 };
|
|
5781
|
+
else if (remaining.startsWith("2>>")) matched = { op: "2>>", len: 3 };
|
|
5782
|
+
else if (remaining.startsWith("2>")) matched = { op: "2>", len: 2 };
|
|
5783
|
+
else if (remaining.startsWith(">>")) matched = { op: ">>", len: 2 };
|
|
5784
|
+
else if (remaining.startsWith(">")) matched = { op: ">", len: 1 };
|
|
5785
|
+
else if (remaining.startsWith("<<")) {
|
|
5786
|
+
throw new UnsupportedSyntaxError(
|
|
5787
|
+
`shell operator "<<" is not supported \u2014 heredoc / here-string is not implemented; pass input via a "<" file or the binary's --input flag`
|
|
5788
|
+
);
|
|
5789
|
+
} else if (remaining.startsWith("<")) matched = { op: "<", len: 1 };
|
|
5790
|
+
if (matched) {
|
|
5791
|
+
if (pending !== null) {
|
|
5792
|
+
throw new UnsupportedSyntaxError(
|
|
5793
|
+
`redirect "${pending}" is missing a target file before "${matched.op}"`
|
|
5794
|
+
);
|
|
5795
|
+
}
|
|
5796
|
+
if (matched.op === "2>&1") {
|
|
5797
|
+
redirects.push({ kind: "2>&1", target: "" });
|
|
5798
|
+
} else {
|
|
5799
|
+
pending = matched.op;
|
|
5800
|
+
}
|
|
5801
|
+
i += matched.len;
|
|
5802
|
+
continue;
|
|
5803
|
+
}
|
|
5804
|
+
if (ch === "&") {
|
|
5805
|
+
throw new UnsupportedSyntaxError(
|
|
5806
|
+
'shell operator "&" is not supported \u2014 background runs need run_background, not run_command. Wrap a literal `&` arg in quotes.'
|
|
5807
|
+
);
|
|
5808
|
+
}
|
|
5809
|
+
}
|
|
5810
|
+
cur += ch;
|
|
5811
|
+
curHasContent = true;
|
|
5812
|
+
i++;
|
|
5813
|
+
}
|
|
5814
|
+
if (quote) throw new Error(`unclosed ${quote} in command`);
|
|
5815
|
+
flush();
|
|
5816
|
+
if (pending) throw new UnsupportedSyntaxError(`redirect "${pending}" is missing a target file`);
|
|
5817
|
+
if (argv.length === 0 && redirects.length > 0) {
|
|
5818
|
+
throw new UnsupportedSyntaxError(
|
|
5819
|
+
"redirect without a command \u2014 segment must have at least one program argument"
|
|
5820
|
+
);
|
|
5821
|
+
}
|
|
5822
|
+
validateRedirectFds(redirects);
|
|
5823
|
+
return { argv, redirects };
|
|
5824
|
+
}
|
|
5825
|
+
function validateRedirectFds(redirects) {
|
|
5826
|
+
let stdin = 0;
|
|
5827
|
+
let stdout = 0;
|
|
5828
|
+
let stderr = 0;
|
|
5829
|
+
for (const r of redirects) {
|
|
5830
|
+
if (r.kind === "<") stdin++;
|
|
5831
|
+
else if (r.kind === ">" || r.kind === ">>") stdout++;
|
|
5832
|
+
else if (r.kind === "2>" || r.kind === "2>>" || r.kind === "2>&1") stderr++;
|
|
5833
|
+
else if (r.kind === "&>") {
|
|
5834
|
+
stdout++;
|
|
5835
|
+
stderr++;
|
|
5836
|
+
}
|
|
5837
|
+
}
|
|
5838
|
+
if (stdin > 1) throw new UnsupportedSyntaxError("multiple `<` stdin redirects in one segment");
|
|
5839
|
+
if (stdout > 1)
|
|
5840
|
+
throw new UnsupportedSyntaxError(
|
|
5841
|
+
"multiple stdout redirects in one segment (`>` / `>>` / `&>` conflict)"
|
|
5842
|
+
);
|
|
5843
|
+
if (stderr > 1)
|
|
5844
|
+
throw new UnsupportedSyntaxError(
|
|
5845
|
+
"multiple stderr redirects in one segment (`2>` / `2>>` / `&>` / `2>&1` conflict)"
|
|
5846
|
+
);
|
|
5847
|
+
}
|
|
5848
|
+
function parseCommandChain(cmd) {
|
|
5849
|
+
const { segs, ops } = splitOnChainOps(cmd);
|
|
5850
|
+
const segments = [];
|
|
5851
|
+
for (let i = 0; i < segs.length; i++) {
|
|
5852
|
+
const trimmed = segs[i].trim();
|
|
5853
|
+
if (trimmed.length === 0) {
|
|
5854
|
+
const op = i === 0 ? ops[0] : ops[i - 1];
|
|
5855
|
+
throw new UnsupportedSyntaxError(
|
|
5856
|
+
i === 0 ? `empty segment before "${op}"` : i === segs.length - 1 ? `chain ends with "${op}"` : `empty segment between "${ops[i - 1]}" and "${ops[i]}"`
|
|
5857
|
+
);
|
|
5858
|
+
}
|
|
5859
|
+
segments.push(parseSegment(trimmed));
|
|
5860
|
+
}
|
|
5861
|
+
if (ops.length === 0 && segments[0].redirects.length === 0) return null;
|
|
5862
|
+
return { segments, ops };
|
|
5863
|
+
}
|
|
5864
|
+
function chainAllowed(chain, isAllowed2) {
|
|
5865
|
+
for (const seg of chain.segments) {
|
|
5866
|
+
if (!isAllowed2(seg.argv.join(" "))) return false;
|
|
5867
|
+
}
|
|
5868
|
+
return true;
|
|
5869
|
+
}
|
|
5870
|
+
function groupChain(chain) {
|
|
5871
|
+
const groups = [{ segments: [chain.segments[0]], opBefore: null }];
|
|
5872
|
+
for (let i = 0; i < chain.ops.length; i++) {
|
|
5873
|
+
const op = chain.ops[i];
|
|
5874
|
+
const next = chain.segments[i + 1];
|
|
5875
|
+
if (op === "|") {
|
|
5876
|
+
groups[groups.length - 1].segments.push(next);
|
|
5877
|
+
} else {
|
|
5878
|
+
groups.push({ segments: [next], opBefore: op });
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
return groups;
|
|
5882
|
+
}
|
|
5883
|
+
async function runChain(chain, opts) {
|
|
5884
|
+
const groups = groupChain(chain);
|
|
5885
|
+
const buf = new OutputBuffer(opts.maxOutputChars * 2 * 4);
|
|
5886
|
+
const deadline = Date.now() + opts.timeoutSec * 1e3;
|
|
5887
|
+
let lastExit = 0;
|
|
5888
|
+
let timedOut = false;
|
|
5889
|
+
for (const group of groups) {
|
|
5890
|
+
if (group.opBefore === "&&" && lastExit !== 0) continue;
|
|
5891
|
+
if (group.opBefore === "||" && lastExit === 0) continue;
|
|
5892
|
+
const remainingMs = deadline - Date.now();
|
|
5893
|
+
if (remainingMs <= 0) {
|
|
5894
|
+
timedOut = true;
|
|
5895
|
+
break;
|
|
5896
|
+
}
|
|
5897
|
+
const result = await runPipeGroup(group.segments, {
|
|
5898
|
+
cwd: opts.cwd,
|
|
5899
|
+
timeoutMs: remainingMs,
|
|
5900
|
+
buf,
|
|
5901
|
+
signal: opts.signal
|
|
5902
|
+
});
|
|
5903
|
+
lastExit = result.exitCode;
|
|
5904
|
+
if (result.timedOut) {
|
|
5905
|
+
timedOut = true;
|
|
5906
|
+
break;
|
|
5907
|
+
}
|
|
5908
|
+
if (opts.signal?.aborted) break;
|
|
5909
|
+
}
|
|
5910
|
+
const output = buf.toString();
|
|
5911
|
+
const truncated = output.length > opts.maxOutputChars ? `${output.slice(0, opts.maxOutputChars)}
|
|
5912
|
+
|
|
5913
|
+
[\u2026 truncated ${output.length - opts.maxOutputChars} chars \u2026]` : output;
|
|
5914
|
+
return { exitCode: lastExit, output: truncated, timedOut };
|
|
5915
|
+
}
|
|
5916
|
+
function openRedirects(redirects, cwd) {
|
|
5917
|
+
let stdinFd = null;
|
|
5918
|
+
let stdoutFd = null;
|
|
5919
|
+
let stderrFd = null;
|
|
5920
|
+
let mergeStderrToStdout = false;
|
|
5921
|
+
let bothFd = null;
|
|
5922
|
+
const toClose = [];
|
|
5923
|
+
const open = (target, flags) => {
|
|
5924
|
+
const resolved = pathMod3.resolve(cwd, target);
|
|
5925
|
+
const fd = openSync(resolved, flags);
|
|
5926
|
+
toClose.push(fd);
|
|
5927
|
+
return fd;
|
|
5928
|
+
};
|
|
5929
|
+
for (const r of redirects) {
|
|
5930
|
+
if (r.kind === "<") stdinFd = open(r.target, "r");
|
|
5931
|
+
else if (r.kind === ">") stdoutFd = open(r.target, "w");
|
|
5932
|
+
else if (r.kind === ">>") stdoutFd = open(r.target, "a");
|
|
5933
|
+
else if (r.kind === "2>") stderrFd = open(r.target, "w");
|
|
5934
|
+
else if (r.kind === "2>>") stderrFd = open(r.target, "a");
|
|
5935
|
+
else if (r.kind === "&>") {
|
|
5936
|
+
bothFd = open(r.target, "w");
|
|
5937
|
+
stdoutFd = bothFd;
|
|
5938
|
+
stderrFd = bothFd;
|
|
5939
|
+
} else if (r.kind === "2>&1") {
|
|
5940
|
+
mergeStderrToStdout = true;
|
|
5941
|
+
}
|
|
5942
|
+
}
|
|
5943
|
+
return { stdinFd, stdoutFd, stderrFd, mergeStderrToStdout, toClose };
|
|
5944
|
+
}
|
|
5945
|
+
async function runPipeGroup(segments, opts) {
|
|
5946
|
+
const env = { ...process.env, PYTHONIOENCODING: "utf-8", PYTHONUTF8: "1" };
|
|
5947
|
+
const children = [];
|
|
5948
|
+
const allFds = [];
|
|
5949
|
+
let timedOut = false;
|
|
5950
|
+
const killAll = () => {
|
|
5951
|
+
for (const c of children) killProcessTree2(c);
|
|
5952
|
+
};
|
|
5953
|
+
const killTimer = setTimeout(() => {
|
|
5954
|
+
timedOut = true;
|
|
5955
|
+
killAll();
|
|
5956
|
+
}, opts.timeoutMs);
|
|
5957
|
+
const onAbort = () => killAll();
|
|
5958
|
+
if (opts.signal?.aborted) {
|
|
5959
|
+
onAbort();
|
|
5960
|
+
} else {
|
|
5961
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
5962
|
+
}
|
|
5963
|
+
try {
|
|
5964
|
+
for (let i = 0; i < segments.length; i++) {
|
|
5965
|
+
const isFirst = i === 0;
|
|
5966
|
+
const isLast = i === segments.length - 1;
|
|
5967
|
+
const seg = segments[i];
|
|
5968
|
+
const io = openRedirects(seg.redirects, opts.cwd);
|
|
5969
|
+
allFds.push(...io.toClose);
|
|
5970
|
+
const { bin, args, spawnOverrides } = prepareSpawn(seg.argv);
|
|
5971
|
+
const stdoutSpec = io.stdoutFd !== null ? io.stdoutFd : "pipe";
|
|
5972
|
+
const stderrSpec = io.stderrFd !== null ? io.stderrFd : io.mergeStderrToStdout ? stdoutSpec : "pipe";
|
|
5973
|
+
const stdinSpec = io.stdinFd !== null ? io.stdinFd : isFirst ? "ignore" : "pipe";
|
|
5974
|
+
const spawnOpts = {
|
|
5975
|
+
cwd: opts.cwd,
|
|
5976
|
+
shell: false,
|
|
5977
|
+
windowsHide: true,
|
|
5978
|
+
env,
|
|
5979
|
+
stdio: [stdinSpec, stdoutSpec, stderrSpec],
|
|
5980
|
+
...spawnOverrides
|
|
5981
|
+
};
|
|
5982
|
+
let child;
|
|
5983
|
+
try {
|
|
5984
|
+
child = spawn3(bin, args, spawnOpts);
|
|
5985
|
+
} catch (err) {
|
|
5986
|
+
for (const fd of allFds) tryClose(fd);
|
|
5987
|
+
killAll();
|
|
5988
|
+
clearTimeout(killTimer);
|
|
5989
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
5990
|
+
throw err;
|
|
5991
|
+
}
|
|
5992
|
+
children.push(child);
|
|
5993
|
+
if (!isFirst && io.stdinFd === null) {
|
|
5994
|
+
const prev = children[i - 1];
|
|
5995
|
+
prev.stdout?.on("error", () => {
|
|
5996
|
+
});
|
|
5997
|
+
child.stdin?.on("error", () => {
|
|
5998
|
+
});
|
|
5999
|
+
const prevMergesStderr = segments[i - 1].redirects.some((r) => r.kind === "2>&1") && !!prev.stderr;
|
|
6000
|
+
if (prevMergesStderr && prev.stderr) {
|
|
6001
|
+
prev.stderr.on("error", () => {
|
|
6002
|
+
});
|
|
6003
|
+
let openSources = 2;
|
|
6004
|
+
const closeIfDone = () => {
|
|
6005
|
+
if (--openSources === 0) child.stdin?.end();
|
|
6006
|
+
};
|
|
6007
|
+
prev.stdout?.pipe(child.stdin, { end: false });
|
|
6008
|
+
prev.stderr.pipe(child.stdin, { end: false });
|
|
6009
|
+
prev.stdout?.once("end", closeIfDone);
|
|
6010
|
+
prev.stderr.once("end", closeIfDone);
|
|
6011
|
+
} else {
|
|
6012
|
+
prev.stdout?.pipe(child.stdin);
|
|
6013
|
+
}
|
|
6014
|
+
}
|
|
6015
|
+
if (child.stderr && io.stderrFd === null && !(io.mergeStderrToStdout && !isLast)) {
|
|
6016
|
+
child.stderr.on("data", (chunk) => opts.buf.push(toBuf(chunk)));
|
|
6017
|
+
}
|
|
6018
|
+
if (isLast && child.stdout && io.stdoutFd === null) {
|
|
6019
|
+
child.stdout.on("data", (chunk) => opts.buf.push(toBuf(chunk)));
|
|
6020
|
+
if (io.mergeStderrToStdout && child.stderr && io.stderrFd === null) {
|
|
6021
|
+
child.stderr.removeAllListeners("data");
|
|
6022
|
+
child.stderr.on("data", (chunk) => opts.buf.push(toBuf(chunk)));
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
const exits = await Promise.all(
|
|
6027
|
+
children.map(
|
|
6028
|
+
(c) => new Promise((resolve10) => {
|
|
6029
|
+
c.once("error", () => resolve10(null));
|
|
6030
|
+
c.once("close", (code) => resolve10(code));
|
|
6031
|
+
})
|
|
6032
|
+
)
|
|
6033
|
+
);
|
|
6034
|
+
return { exitCode: exits[exits.length - 1] ?? null, timedOut };
|
|
6035
|
+
} finally {
|
|
6036
|
+
for (const fd of allFds) tryClose(fd);
|
|
6037
|
+
clearTimeout(killTimer);
|
|
6038
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
function tryClose(fd) {
|
|
6042
|
+
try {
|
|
6043
|
+
closeSync(fd);
|
|
6044
|
+
} catch {
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
function toBuf(chunk) {
|
|
6048
|
+
return typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
6049
|
+
}
|
|
6050
|
+
var OutputBuffer = class {
|
|
6051
|
+
constructor(cap) {
|
|
6052
|
+
this.cap = cap;
|
|
6053
|
+
}
|
|
6054
|
+
cap;
|
|
6055
|
+
chunks = [];
|
|
6056
|
+
bytes = 0;
|
|
6057
|
+
push(b) {
|
|
6058
|
+
if (this.bytes >= this.cap) return;
|
|
6059
|
+
const remaining = this.cap - this.bytes;
|
|
6060
|
+
if (b.length > remaining) {
|
|
6061
|
+
this.chunks.push(b.subarray(0, remaining));
|
|
6062
|
+
this.bytes = this.cap;
|
|
6063
|
+
} else {
|
|
6064
|
+
this.chunks.push(b);
|
|
6065
|
+
this.bytes += b.length;
|
|
6066
|
+
}
|
|
6067
|
+
}
|
|
6068
|
+
toString() {
|
|
6069
|
+
return smartDecodeOutput(Buffer.concat(this.chunks));
|
|
6070
|
+
}
|
|
6071
|
+
};
|
|
6072
|
+
|
|
5689
6073
|
// src/tools/shell.ts
|
|
5690
6074
|
function killProcessTree2(child) {
|
|
5691
6075
|
if (!child.pid || child.killed) return;
|
|
@@ -5857,17 +6241,31 @@ function isAllowed(cmd, extra = []) {
|
|
|
5857
6241
|
}
|
|
5858
6242
|
return false;
|
|
5859
6243
|
}
|
|
6244
|
+
function isCommandAllowed(cmd, extra = []) {
|
|
6245
|
+
let chain;
|
|
6246
|
+
try {
|
|
6247
|
+
chain = parseCommandChain(cmd);
|
|
6248
|
+
} catch {
|
|
6249
|
+
return false;
|
|
6250
|
+
}
|
|
6251
|
+
if (chain === null) return isAllowed(cmd, extra);
|
|
6252
|
+
return chainAllowed(chain, (seg) => isAllowed(seg, extra));
|
|
6253
|
+
}
|
|
5860
6254
|
async function runCommand(cmd, opts) {
|
|
6255
|
+
const timeoutSec = opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC;
|
|
6256
|
+
const maxChars = opts.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
5861
6257
|
const argv = tokenizeCommand(cmd);
|
|
5862
6258
|
if (argv.length === 0) throw new Error("run_command: empty command");
|
|
5863
|
-
const
|
|
5864
|
-
if (
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
6259
|
+
const chain = parseCommandChain(cmd);
|
|
6260
|
+
if (chain !== null) {
|
|
6261
|
+
return await runChain(chain, {
|
|
6262
|
+
cwd: opts.cwd,
|
|
6263
|
+
timeoutSec,
|
|
6264
|
+
maxOutputChars: maxChars,
|
|
6265
|
+
signal: opts.signal
|
|
6266
|
+
});
|
|
5868
6267
|
}
|
|
5869
|
-
const timeoutMs =
|
|
5870
|
-
const maxChars = opts.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
6268
|
+
const timeoutMs = timeoutSec * 1e3;
|
|
5871
6269
|
const spawnOpts = {
|
|
5872
6270
|
cwd: opts.cwd,
|
|
5873
6271
|
shell: false,
|
|
@@ -5885,10 +6283,10 @@ async function runCommand(cmd, opts) {
|
|
|
5885
6283
|
};
|
|
5886
6284
|
const { bin, args, spawnOverrides } = prepareSpawn(argv);
|
|
5887
6285
|
const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };
|
|
5888
|
-
return await new Promise((
|
|
6286
|
+
return await new Promise((resolve10, reject) => {
|
|
5889
6287
|
let child;
|
|
5890
6288
|
try {
|
|
5891
|
-
child =
|
|
6289
|
+
child = spawn4(bin, args, effectiveSpawnOpts);
|
|
5892
6290
|
} catch (err) {
|
|
5893
6291
|
reject(err);
|
|
5894
6292
|
return;
|
|
@@ -5939,7 +6337,7 @@ async function runCommand(cmd, opts) {
|
|
|
5939
6337
|
const output = buf.length > maxChars ? `${buf.slice(0, maxChars)}
|
|
5940
6338
|
|
|
5941
6339
|
[\u2026 truncated ${buf.length - maxChars} chars \u2026]` : buf;
|
|
5942
|
-
|
|
6340
|
+
resolve10({ exitCode: code, output, timedOut });
|
|
5943
6341
|
});
|
|
5944
6342
|
});
|
|
5945
6343
|
}
|
|
@@ -5961,16 +6359,16 @@ function resolveExecutable(cmd, opts = {}) {
|
|
|
5961
6359
|
const platform = opts.platform ?? process.platform;
|
|
5962
6360
|
if (platform !== "win32") return cmd;
|
|
5963
6361
|
if (!cmd) return cmd;
|
|
5964
|
-
if (cmd.includes("/") || cmd.includes("\\") ||
|
|
5965
|
-
if (
|
|
6362
|
+
if (cmd.includes("/") || cmd.includes("\\") || pathMod4.isAbsolute(cmd)) return cmd;
|
|
6363
|
+
if (pathMod4.extname(cmd)) return cmd;
|
|
5966
6364
|
const env = opts.env ?? process.env;
|
|
5967
6365
|
const pathExt = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
|
|
5968
|
-
const delimiter2 = opts.pathDelimiter ?? (platform === "win32" ? ";" :
|
|
6366
|
+
const delimiter2 = opts.pathDelimiter ?? (platform === "win32" ? ";" : pathMod4.delimiter);
|
|
5969
6367
|
const pathDirs = (env.PATH ?? "").split(delimiter2).filter(Boolean);
|
|
5970
6368
|
const isFile = opts.isFile ?? defaultIsFile;
|
|
5971
6369
|
for (const dir of pathDirs) {
|
|
5972
6370
|
for (const ext of pathExt) {
|
|
5973
|
-
const full =
|
|
6371
|
+
const full = pathMod4.win32.join(dir, cmd + ext);
|
|
5974
6372
|
if (isFile(full)) return full;
|
|
5975
6373
|
}
|
|
5976
6374
|
}
|
|
@@ -6040,8 +6438,8 @@ function withUtf8Codepage(cmdline) {
|
|
|
6040
6438
|
function isBareWindowsName(s) {
|
|
6041
6439
|
if (!s) return false;
|
|
6042
6440
|
if (s.includes("/") || s.includes("\\")) return false;
|
|
6043
|
-
if (
|
|
6044
|
-
if (
|
|
6441
|
+
if (pathMod4.isAbsolute(s)) return false;
|
|
6442
|
+
if (pathMod4.extname(s)) return false;
|
|
6045
6443
|
return true;
|
|
6046
6444
|
}
|
|
6047
6445
|
function quoteForCmdExe(arg) {
|
|
@@ -6060,7 +6458,7 @@ var NeedsConfirmationError = class extends Error {
|
|
|
6060
6458
|
}
|
|
6061
6459
|
};
|
|
6062
6460
|
function registerShellTools(registry, opts) {
|
|
6063
|
-
const rootDir =
|
|
6461
|
+
const rootDir = pathMod4.resolve(opts.rootDir);
|
|
6064
6462
|
const timeoutSec = opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC;
|
|
6065
6463
|
const maxOutputChars = opts.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
6066
6464
|
const jobs = opts.jobs ?? new JobRegistry();
|
|
@@ -6071,7 +6469,7 @@ function registerShellTools(registry, opts) {
|
|
|
6071
6469
|
const isAllowAll = typeof opts.allowAll === "function" ? opts.allowAll : () => opts.allowAll === true;
|
|
6072
6470
|
registry.register({
|
|
6073
6471
|
name: "run_command",
|
|
6074
|
-
description: "Run a shell command in the project root and return its combined stdout+stderr.\n\nConstraints (read these before the first call):\n\u2022
|
|
6472
|
+
description: "Run a shell command in the project root and return its combined stdout+stderr.\n\nConstraints (read these before the first call):\n\u2022 Chain operators `|`, `||`, `&&`, `;` ARE supported \u2014 parsed natively, no shell invoked, so semantics are identical on Windows / macOS / Linux. Each chain segment is allowlist-checked individually: `git status | grep main` runs if both halves are allowed.\n\u2022 File redirects ARE supported: `>` truncate, `>>` append, `<` stdin from file, `2>` / `2>>` stderr to file, `2>&1` merge stderr\u2192stdout, `&>` both to file. Targets resolve relative to the project root. At most one redirect per fd per segment.\n\u2022 Background `&`, heredoc `<<`, command substitution `$(\u2026)`, subshells `(\u2026)`, and process substitution `<(\u2026)` are NOT supported. Wrap a literal `&` arg in quotes; for input use a `<` file or the binary's own --input flag.\n\u2022 Env-var expansion `$VAR` is NOT performed \u2014 `$VAR` is passed as a literal string. Use the binary's own --env flag or substitute the value yourself.\n\u2022 `cd` DOES NOT PERSIST between calls \u2014 each call spawns a fresh process rooted at the project. If a tool needs a subdirectory, pass it via the tool's own flag (`npm --prefix`, `cargo -C`, `git -C`, `pytest tests/\u2026`), NOT via a preceding `cd`.\n\u2022 Glob patterns (`*.ts`) are passed through as literal arguments \u2014 no shell expansion. Use `grep -r`, `rg`, `find -name`, etc.\n\u2022 Avoid commands with unbounded output (`netstat -ano`, `find /`, etc.) \u2014 they waste tokens. Filter at source: `netstat -ano -p TCP`, `find src -name '*.ts'`, `grep -c`, `wc -l`.\n\nCommon read-only inspection and test/lint/typecheck commands run immediately; anything that could mutate state, install dependencies, or touch the network is refused until the user confirms it in the TUI. Prefer this over asking the user to run a command manually \u2014 after edits, run the project's tests to verify.",
|
|
6075
6473
|
// Plan-mode gate: allow allowlisted commands through (git status,
|
|
6076
6474
|
// cargo check, ls, grep …) so the model can actually investigate
|
|
6077
6475
|
// during planning. Anything that would otherwise trigger a
|
|
@@ -6080,14 +6478,14 @@ function registerShellTools(registry, opts) {
|
|
|
6080
6478
|
if (isAllowAll()) return true;
|
|
6081
6479
|
const cmd = typeof args?.command === "string" ? args.command.trim() : "";
|
|
6082
6480
|
if (!cmd) return false;
|
|
6083
|
-
return
|
|
6481
|
+
return isCommandAllowed(cmd, getExtraAllowed());
|
|
6084
6482
|
},
|
|
6085
6483
|
parameters: {
|
|
6086
6484
|
type: "object",
|
|
6087
6485
|
properties: {
|
|
6088
6486
|
command: {
|
|
6089
6487
|
type: "string",
|
|
6090
|
-
description: 'Full command line.
|
|
6488
|
+
description: 'Full command line. POSIX-ish quoting. Chain operators `|`, `||`, `&&`, `;` and file redirects `>` / `>>` / `<` / `2>` / `2>>` / `2>&1` / `&>` work natively (no shell). Background `&`, heredoc `<<`, env-var expansion `$VAR`, and command substitution `$(\u2026)` are rejected (or passed through as literal in the case of `$VAR`). To pass an operator character as a literal argument (e.g. a regex), wrap it in quotes: `grep "a|b" file.txt`.'
|
|
6091
6489
|
},
|
|
6092
6490
|
timeoutSec: {
|
|
6093
6491
|
type: "integer",
|
|
@@ -6099,7 +6497,7 @@ function registerShellTools(registry, opts) {
|
|
|
6099
6497
|
fn: async (args, ctx) => {
|
|
6100
6498
|
const cmd = args.command.trim();
|
|
6101
6499
|
if (!cmd) throw new Error("run_command: empty command");
|
|
6102
|
-
if (!isAllowAll() && !
|
|
6500
|
+
if (!isAllowAll() && !isCommandAllowed(cmd, getExtraAllowed())) {
|
|
6103
6501
|
throw new NeedsConfirmationError(cmd);
|
|
6104
6502
|
}
|
|
6105
6503
|
const effectiveTimeout = Math.max(1, Math.min(600, args.timeoutSec ?? timeoutSec));
|
|
@@ -6463,11 +6861,11 @@ ${i + 1}. ${r.title}`);
|
|
|
6463
6861
|
|
|
6464
6862
|
// src/env.ts
|
|
6465
6863
|
import { readFileSync as readFileSync9 } from "fs";
|
|
6466
|
-
import { resolve as
|
|
6864
|
+
import { resolve as resolve8 } from "path";
|
|
6467
6865
|
function loadDotenv(path2 = ".env") {
|
|
6468
6866
|
let raw;
|
|
6469
6867
|
try {
|
|
6470
|
-
raw = readFileSync9(
|
|
6868
|
+
raw = readFileSync9(resolve8(process.cwd(), path2), "utf8");
|
|
6471
6869
|
} catch {
|
|
6472
6870
|
return;
|
|
6473
6871
|
}
|
|
@@ -7221,7 +7619,7 @@ var McpClient = class {
|
|
|
7221
7619
|
const id = this.nextId++;
|
|
7222
7620
|
const frame = { jsonrpc: "2.0", id, method, params };
|
|
7223
7621
|
let abortHandler = null;
|
|
7224
|
-
const promise = new Promise((
|
|
7622
|
+
const promise = new Promise((resolve10, reject) => {
|
|
7225
7623
|
const timeout = setTimeout(() => {
|
|
7226
7624
|
this.pending.delete(id);
|
|
7227
7625
|
if (abortHandler && signal) signal.removeEventListener("abort", abortHandler);
|
|
@@ -7230,7 +7628,7 @@ var McpClient = class {
|
|
|
7230
7628
|
);
|
|
7231
7629
|
}, this.requestTimeoutMs);
|
|
7232
7630
|
this.pending.set(id, {
|
|
7233
|
-
resolve:
|
|
7631
|
+
resolve: resolve10,
|
|
7234
7632
|
reject,
|
|
7235
7633
|
timeout
|
|
7236
7634
|
});
|
|
@@ -7312,7 +7710,7 @@ var McpClient = class {
|
|
|
7312
7710
|
};
|
|
7313
7711
|
|
|
7314
7712
|
// src/mcp/stdio.ts
|
|
7315
|
-
import { spawn as
|
|
7713
|
+
import { spawn as spawn5 } from "child_process";
|
|
7316
7714
|
var StdioTransport = class {
|
|
7317
7715
|
child;
|
|
7318
7716
|
queue = [];
|
|
@@ -7327,14 +7725,14 @@ var StdioTransport = class {
|
|
|
7327
7725
|
opts.command,
|
|
7328
7726
|
...(opts.args ?? []).map((a) => quoteArg(a, process.platform === "win32"))
|
|
7329
7727
|
].join(" ");
|
|
7330
|
-
this.child =
|
|
7728
|
+
this.child = spawn5(line, [], {
|
|
7331
7729
|
env,
|
|
7332
7730
|
cwd: opts.cwd,
|
|
7333
7731
|
stdio: ["pipe", "pipe", "inherit"],
|
|
7334
7732
|
shell: true
|
|
7335
7733
|
});
|
|
7336
7734
|
} else {
|
|
7337
|
-
this.child =
|
|
7735
|
+
this.child = spawn5(opts.command, opts.args ?? [], {
|
|
7338
7736
|
env,
|
|
7339
7737
|
cwd: opts.cwd,
|
|
7340
7738
|
stdio: ["pipe", "pipe", "inherit"]
|
|
@@ -7353,12 +7751,12 @@ var StdioTransport = class {
|
|
|
7353
7751
|
}
|
|
7354
7752
|
async send(message) {
|
|
7355
7753
|
if (this.closed) throw new Error("MCP transport is closed");
|
|
7356
|
-
return new Promise((
|
|
7754
|
+
return new Promise((resolve10, reject) => {
|
|
7357
7755
|
const line = `${JSON.stringify(message)}
|
|
7358
7756
|
`;
|
|
7359
7757
|
this.child.stdin.write(line, "utf8", (err) => {
|
|
7360
7758
|
if (err) reject(err);
|
|
7361
|
-
else
|
|
7759
|
+
else resolve10();
|
|
7362
7760
|
});
|
|
7363
7761
|
});
|
|
7364
7762
|
}
|
|
@@ -7369,8 +7767,8 @@ var StdioTransport = class {
|
|
|
7369
7767
|
continue;
|
|
7370
7768
|
}
|
|
7371
7769
|
if (this.closed) return;
|
|
7372
|
-
const next = await new Promise((
|
|
7373
|
-
this.waiters.push(
|
|
7770
|
+
const next = await new Promise((resolve10) => {
|
|
7771
|
+
this.waiters.push(resolve10);
|
|
7374
7772
|
});
|
|
7375
7773
|
if (next === null) return;
|
|
7376
7774
|
yield next;
|
|
@@ -7439,8 +7837,8 @@ var SseTransport = class {
|
|
|
7439
7837
|
constructor(opts) {
|
|
7440
7838
|
this.url = opts.url;
|
|
7441
7839
|
this.headers = opts.headers ?? {};
|
|
7442
|
-
this.endpointReady = new Promise((
|
|
7443
|
-
this.resolveEndpoint =
|
|
7840
|
+
this.endpointReady = new Promise((resolve10, reject) => {
|
|
7841
|
+
this.resolveEndpoint = resolve10;
|
|
7444
7842
|
this.rejectEndpoint = reject;
|
|
7445
7843
|
});
|
|
7446
7844
|
this.endpointReady.catch(() => void 0);
|
|
@@ -7467,8 +7865,8 @@ var SseTransport = class {
|
|
|
7467
7865
|
continue;
|
|
7468
7866
|
}
|
|
7469
7867
|
if (this.closed) return;
|
|
7470
|
-
const next = await new Promise((
|
|
7471
|
-
this.waiters.push(
|
|
7868
|
+
const next = await new Promise((resolve10) => {
|
|
7869
|
+
this.waiters.push(resolve10);
|
|
7472
7870
|
});
|
|
7473
7871
|
if (next === null) return;
|
|
7474
7872
|
yield next;
|
|
@@ -7654,8 +8052,8 @@ var StreamableHttpTransport = class {
|
|
|
7654
8052
|
continue;
|
|
7655
8053
|
}
|
|
7656
8054
|
if (this.closed) return;
|
|
7657
|
-
const next = await new Promise((
|
|
7658
|
-
this.waiters.push(
|
|
8055
|
+
const next = await new Promise((resolve10) => {
|
|
8056
|
+
this.waiters.push(resolve10);
|
|
7659
8057
|
});
|
|
7660
8058
|
if (next === null) return;
|
|
7661
8059
|
yield next;
|
|
@@ -7826,7 +8224,7 @@ async function trySection(load) {
|
|
|
7826
8224
|
|
|
7827
8225
|
// src/code/edit-blocks.ts
|
|
7828
8226
|
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync12, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
7829
|
-
import { dirname as dirname5, resolve as
|
|
8227
|
+
import { dirname as dirname5, resolve as resolve9 } from "path";
|
|
7830
8228
|
var BLOCK_RE = /^(\S[^\n]*)\n<{7} SEARCH\n([\s\S]*?)\n?={7}\n([\s\S]*?)\n?>{7} REPLACE/gm;
|
|
7831
8229
|
function parseEditBlocks(text) {
|
|
7832
8230
|
const out = [];
|
|
@@ -7844,8 +8242,8 @@ function parseEditBlocks(text) {
|
|
|
7844
8242
|
return out;
|
|
7845
8243
|
}
|
|
7846
8244
|
function applyEditBlock(block, rootDir) {
|
|
7847
|
-
const absRoot =
|
|
7848
|
-
const absTarget =
|
|
8245
|
+
const absRoot = resolve9(rootDir);
|
|
8246
|
+
const absTarget = resolve9(absRoot, block.path);
|
|
7849
8247
|
if (absTarget !== absRoot && !absTarget.startsWith(`${absRoot}${sep()}`)) {
|
|
7850
8248
|
return {
|
|
7851
8249
|
path: block.path,
|
|
@@ -7898,13 +8296,13 @@ function applyEditBlocks(blocks, rootDir) {
|
|
|
7898
8296
|
return blocks.map((b) => applyEditBlock(b, rootDir));
|
|
7899
8297
|
}
|
|
7900
8298
|
function snapshotBeforeEdits(blocks, rootDir) {
|
|
7901
|
-
const absRoot =
|
|
8299
|
+
const absRoot = resolve9(rootDir);
|
|
7902
8300
|
const seen = /* @__PURE__ */ new Set();
|
|
7903
8301
|
const snapshots = [];
|
|
7904
8302
|
for (const b of blocks) {
|
|
7905
8303
|
if (seen.has(b.path)) continue;
|
|
7906
8304
|
seen.add(b.path);
|
|
7907
|
-
const abs =
|
|
8305
|
+
const abs = resolve9(absRoot, b.path);
|
|
7908
8306
|
if (!existsSync10(abs)) {
|
|
7909
8307
|
snapshots.push({ path: b.path, prevContent: null });
|
|
7910
8308
|
continue;
|
|
@@ -7918,9 +8316,9 @@ function snapshotBeforeEdits(blocks, rootDir) {
|
|
|
7918
8316
|
return snapshots;
|
|
7919
8317
|
}
|
|
7920
8318
|
function restoreSnapshots(snapshots, rootDir) {
|
|
7921
|
-
const absRoot =
|
|
8319
|
+
const absRoot = resolve9(rootDir);
|
|
7922
8320
|
return snapshots.map((snap) => {
|
|
7923
|
-
const abs =
|
|
8321
|
+
const abs = resolve9(absRoot, snap.path);
|
|
7924
8322
|
if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep()}`)) {
|
|
7925
8323
|
return {
|
|
7926
8324
|
path: snap.path,
|
|
@@ -8457,7 +8855,6 @@ export {
|
|
|
8457
8855
|
NeedsConfirmationError,
|
|
8458
8856
|
PROJECT_MEMORY_FILE,
|
|
8459
8857
|
PROJECT_MEMORY_MAX_CHARS,
|
|
8460
|
-
PlanCheckpointError,
|
|
8461
8858
|
PlanProposedError,
|
|
8462
8859
|
PlanRevisionProposedError,
|
|
8463
8860
|
SessionStats,
|