@ordewell/core 0.6.2 → 0.6.3
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/{IFileSystem-DuEiG_kA.d.ts → IFileSystem-DQEKyC6H.d.ts} +1 -1
- package/dist/{IFileSystem-d_SV7jAH.d.mts → IFileSystem-Qj2MWHn_.d.mts} +1 -1
- package/dist/{ModeResolver-DXxV4n_V.d.ts → ModeResolver-ByNpC0EP.d.ts} +1 -1
- package/dist/{ModeResolver-DIReYAOq.d.mts → ModeResolver-rqaY_4Ex.d.mts} +1 -1
- package/dist/{Task-ib_U0YP7.d.mts → Task-xqdxugt2.d.mts} +31 -1
- package/dist/{Task-ib_U0YP7.d.ts → Task-xqdxugt2.d.ts} +31 -1
- package/dist/index.d.mts +86 -81
- package/dist/index.d.ts +86 -81
- package/dist/index.js +184 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +175 -28
- package/dist/index.mjs.map +1 -1
- package/dist/order-labels.d.mts +1 -1
- package/dist/order-labels.d.ts +1 -1
- package/dist/{parsing-C8Z22twN.d.ts → parsing-COPG8-Ep.d.ts} +2 -2
- package/dist/{parsing-DjRJJX-y.d.mts → parsing-DDZ1rUYa.d.mts} +2 -2
- package/dist/parsing.d.mts +3 -3
- package/dist/parsing.d.ts +3 -3
- package/dist/{plan-utils-2K_N5ZJe.d.ts → plan-utils-Br8UAoiu.d.ts} +2 -2
- package/dist/{plan-utils-D94CJ7CA.d.mts → plan-utils-DMgajMvd.d.mts} +2 -2
- package/dist/plan-utils.d.mts +3 -3
- package/dist/plan-utils.d.ts +3 -3
- package/dist/testing.d.mts +2 -2
- package/dist/testing.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3119,6 +3119,8 @@ function lex(command, nested, dialect) {
|
|
|
3119
3119
|
let unbalanced = false;
|
|
3120
3120
|
let grouped = false;
|
|
3121
3121
|
let joinedBy;
|
|
3122
|
+
let followable = true;
|
|
3123
|
+
let bareSegment = false;
|
|
3122
3124
|
let tokens = [];
|
|
3123
3125
|
let expandable = false;
|
|
3124
3126
|
let current = "";
|
|
@@ -3148,9 +3150,20 @@ function lex(command, nested, dialect) {
|
|
|
3148
3150
|
current = "";
|
|
3149
3151
|
started = false;
|
|
3150
3152
|
};
|
|
3151
|
-
const endSegment = (nextPiped, next = "other") => {
|
|
3153
|
+
const endSegment = (nextPiped, next = "other", last = false) => {
|
|
3152
3154
|
endToken();
|
|
3153
|
-
if (
|
|
3155
|
+
if (!last && next === "other") followable = false;
|
|
3156
|
+
if (tokens.length > 0) {
|
|
3157
|
+
const seg = toSegment(tokens, piped, dialect);
|
|
3158
|
+
if (!seg.binary) {
|
|
3159
|
+
followable = false;
|
|
3160
|
+
bareSegment = true;
|
|
3161
|
+
}
|
|
3162
|
+
segments.push({ ...seg, expandable, inputs, joinedBy });
|
|
3163
|
+
} else if (!last || segments.length > 0 || joinedBy !== void 0) {
|
|
3164
|
+
followable = false;
|
|
3165
|
+
bareSegment = true;
|
|
3166
|
+
}
|
|
3154
3167
|
tokens = [];
|
|
3155
3168
|
inputs = [];
|
|
3156
3169
|
expandable = false;
|
|
@@ -3305,8 +3318,8 @@ function lex(command, nested, dialect) {
|
|
|
3305
3318
|
i++;
|
|
3306
3319
|
}
|
|
3307
3320
|
if (quote !== "") unbalanced = true;
|
|
3308
|
-
endSegment(false);
|
|
3309
|
-
return { segments, unsafeRedirect, processSubstitution, unbalanced, grouped };
|
|
3321
|
+
endSegment(false, "other", true);
|
|
3322
|
+
return { segments, unsafeRedirect, processSubstitution, unbalanced, grouped, followable, bareSegment };
|
|
3310
3323
|
}
|
|
3311
3324
|
function binaryName(token, dialect) {
|
|
3312
3325
|
const base = token.split(/[/\\]/).pop() ?? "";
|
|
@@ -3450,7 +3463,8 @@ function lexAll(command, dialect, cdpathSet = false) {
|
|
|
3450
3463
|
const queue = [];
|
|
3451
3464
|
const top = lex(command, queue, dialect);
|
|
3452
3465
|
const all = { ...top, segments: top.segments.filter((s) => s.binary) };
|
|
3453
|
-
|
|
3466
|
+
markShellState(all.segments, top.bareSegment);
|
|
3467
|
+
if (top.followable && !top.grouped && queue.length === 0 && !cdpathSet) followCd(all.segments);
|
|
3454
3468
|
for (let depth = 0; depth < 32 && queue.length > 0; depth++) {
|
|
3455
3469
|
const inner = lex(queue.shift(), queue, dialect);
|
|
3456
3470
|
all.segments.push(...inner.segments.filter((s) => s.binary));
|
|
@@ -3467,22 +3481,51 @@ function literalCdTarget(seg) {
|
|
|
3467
3481
|
return target === "" || target.startsWith("-") || target.startsWith("~") || /[*?[]/.test(target) ? void 0 : target;
|
|
3468
3482
|
}
|
|
3469
3483
|
function followCd(segments) {
|
|
3470
|
-
if (segments.some((s) => s.joinedBy === "other")) return;
|
|
3484
|
+
if (segments.some((s) => s.joinedBy === "other" || SHELL_STATE_COMMANDS.has(s.binary))) return;
|
|
3485
|
+
const inPipeline = (i) => segments[i].joinedBy === "pipe" || segments[i + 1]?.joinedBy === "pipe";
|
|
3486
|
+
if (segments.some((s, i) => s.binary === "cd" && !inPipeline(i) && literalCdTarget(s) === void 0)) return;
|
|
3471
3487
|
let chain = [];
|
|
3472
3488
|
segments.forEach((seg, i) => {
|
|
3473
3489
|
seg.cwd = chain;
|
|
3474
|
-
const
|
|
3475
|
-
const target = inPipeline ? void 0 : literalCdTarget(seg);
|
|
3490
|
+
const target = inPipeline(i) ? void 0 : literalCdTarget(seg);
|
|
3476
3491
|
if (target !== void 0) chain = [...chain, target];
|
|
3477
3492
|
});
|
|
3478
3493
|
}
|
|
3494
|
+
function markShellState(segments, bareSegment) {
|
|
3495
|
+
if (!bareSegment && !segments.some((s) => SHELL_STATE_COMMANDS.has(s.binary))) return;
|
|
3496
|
+
for (const seg of segments) if (seg.binary === "cd") seg.cdSteered = true;
|
|
3497
|
+
}
|
|
3498
|
+
var SHELL_STATE_COMMANDS = /* @__PURE__ */ new Set([
|
|
3499
|
+
"export",
|
|
3500
|
+
"set",
|
|
3501
|
+
"shopt",
|
|
3502
|
+
"declare",
|
|
3503
|
+
"typeset",
|
|
3504
|
+
"readonly",
|
|
3505
|
+
"local",
|
|
3506
|
+
"unset",
|
|
3507
|
+
"let",
|
|
3508
|
+
"source",
|
|
3509
|
+
".",
|
|
3510
|
+
"eval",
|
|
3511
|
+
"exec",
|
|
3512
|
+
"pushd",
|
|
3513
|
+
"popd",
|
|
3514
|
+
"alias",
|
|
3515
|
+
"unalias",
|
|
3516
|
+
"builtin",
|
|
3517
|
+
"command",
|
|
3518
|
+
"enable",
|
|
3519
|
+
"hash",
|
|
3520
|
+
"trap"
|
|
3521
|
+
]);
|
|
3479
3522
|
function looksLikePath(arg) {
|
|
3480
3523
|
if (arg.startsWith("--") && arg.includes("=")) return looksLikePath(arg.slice(arg.indexOf("=") + 1));
|
|
3481
3524
|
return arg.startsWith("/") || arg.startsWith("~") || arg.startsWith("../") || arg === ".." || arg.startsWith("./") || /^[A-Za-z]:/.test(arg) || arg.startsWith("\\") || arg.startsWith("..\\") || arg.startsWith(".\\") || /(^|[\\/])\.\.([\\/]|$)/.test(arg);
|
|
3482
3525
|
}
|
|
3483
3526
|
function pathRefs(command, opts = {}) {
|
|
3484
3527
|
const dialect = dialectFor(opts.dialect);
|
|
3485
|
-
return lexAll(command, dialect, opts.cdpathSet).segments.flatMap((seg) => {
|
|
3528
|
+
return lexAll(command.trim(), dialect, opts.cdpathSet).segments.flatMap((seg) => {
|
|
3486
3529
|
const patterns = patternArgs(seg);
|
|
3487
3530
|
const cwd = seg.cwd ?? [];
|
|
3488
3531
|
return [...seg.args.filter((_, i) => !patterns.has(i)), ...seg.inputs].flatMap(pathIn).map((path27) => ({ path: path27, cwd }));
|
|
@@ -3650,7 +3693,7 @@ function scopeFor(seg) {
|
|
|
3650
3693
|
return [seg.binary, ...lead].join(" ");
|
|
3651
3694
|
}
|
|
3652
3695
|
function isAuto(seg, opts) {
|
|
3653
|
-
if (seg.binary === "cd") return !opts.cdpathSet && literalCdTarget(seg) !== void 0;
|
|
3696
|
+
if (seg.binary === "cd") return !opts.cdpathSet && !seg.cdSteered && literalCdTarget(seg) !== void 0;
|
|
3654
3697
|
if (!AUTO_COMMANDS.includes(seg.binary)) return false;
|
|
3655
3698
|
if (seg.expandable) return false;
|
|
3656
3699
|
if (seg.binary !== "git") return true;
|
|
@@ -3852,6 +3895,9 @@ function researchShellWarning(shell) {
|
|
|
3852
3895
|
if (shell.dialect !== "cmd") return null;
|
|
3853
3896
|
return "No POSIX shell was found on this machine, so research commands run through cmd.exe, where most read-only tools (ls, cat, wc, head, grep, find) do not exist. Installing Git for Windows provides one and restores the full research toolset.";
|
|
3854
3897
|
}
|
|
3898
|
+
function researchPolicyOptions(shell) {
|
|
3899
|
+
return { dialect: shell.dialect, cdpathSet: !!process.env.CDPATH };
|
|
3900
|
+
}
|
|
3855
3901
|
|
|
3856
3902
|
// src/services/pathScope.ts
|
|
3857
3903
|
var os = __toESM(require("os"));
|
|
@@ -4085,7 +4131,7 @@ ${refs.output.trim()}`);
|
|
|
4085
4131
|
return [...found].map(([scope, abs]) => ({ abs, scope }));
|
|
4086
4132
|
}
|
|
4087
4133
|
policyOptions() {
|
|
4088
|
-
return
|
|
4134
|
+
return researchPolicyOptions(this.researchShell);
|
|
4089
4135
|
}
|
|
4090
4136
|
/**
|
|
4091
4137
|
* Three tiers (see `commandPolicy.ts`): read-only inspection runs silently,
|
|
@@ -10532,16 +10578,15 @@ function nonPromptingFs(fs16) {
|
|
|
10532
10578
|
findSymbol: (symbol, opts) => withinWorkspace(opts?.path) ? fs16.findSymbol(symbol, opts) : Promise.resolve(outsideRefusal(opts.path)),
|
|
10533
10579
|
listDir: (p, depth) => withinWorkspace(p) ? fs16.listDir(p, depth) : Promise.resolve(outsideRefusal(p)),
|
|
10534
10580
|
bash: async (command, signal) => {
|
|
10535
|
-
const
|
|
10536
|
-
const policy = { dialect, cdpathSet: !!process.env.CDPATH };
|
|
10581
|
+
const policy = researchPolicyOptions(resolveResearchShell());
|
|
10537
10582
|
const { tier, reason } = classifyCommand(command, policy);
|
|
10538
10583
|
if (tier !== "auto") {
|
|
10539
10584
|
return refused2(
|
|
10540
10585
|
tier === "refuse" ? `Command refused: ${reason}` : `"${command}" needs user approval, and research agents run in the background where nothing can be approved. Use the read-only research tools, and note in your digest that this command would answer the question.`
|
|
10541
10586
|
);
|
|
10542
10587
|
}
|
|
10543
|
-
const escaping = pathRefs(command, policy).
|
|
10544
|
-
if (escaping) return outsideRefusal(escaping.
|
|
10588
|
+
const escaping = pathRefs(command, policy).map((ref) => resolveRef(fs16.getWorkspaceRoot(), ref)).find((r) => !r.inside);
|
|
10589
|
+
if (escaping) return outsideRefusal(escaping.abs);
|
|
10545
10590
|
return fs16.bash(command, signal);
|
|
10546
10591
|
}
|
|
10547
10592
|
};
|
|
@@ -13578,11 +13623,17 @@ function buildShellInvocation(command, args) {
|
|
|
13578
13623
|
const inner = [command, ...args].map(posixShellQuote).join(" ");
|
|
13579
13624
|
return { shellPath: "/bin/bash", shellArgs: ["-lc", inner] };
|
|
13580
13625
|
}
|
|
13626
|
+
var BSD_SCRIPT_PLATFORMS = /* @__PURE__ */ new Set(["darwin", "freebsd", "openbsd", "netbsd"]);
|
|
13627
|
+
var BSD_SCRIPT_FEED = 'exec 5<&0; p=$(mktemp) || exit 1; { cat <&5 & echo $! >"$p"; wait; } 2>/dev/null | { script -q -e -F /dev/null /bin/sh -c "$0"; s=$?; kill "$(cat "$p")" 2>/dev/null; rm -f "$p"; exit $s; }';
|
|
13581
13628
|
function wrapWithPty(command, args, opts = {}) {
|
|
13582
13629
|
const inner = [command, ...args].map(posixShellQuote).join(" ");
|
|
13583
13630
|
const watcher = opts.controlChannel ? 'exec 4<&0; ( while read -r C R <&3; do stty cols "$C" rows "$R" <&4; done ) & ' : "";
|
|
13584
13631
|
const setup = opts.size ? `stty cols ${opts.size.cols} rows ${opts.size.rows}; ` : "";
|
|
13585
|
-
|
|
13632
|
+
const line = `${watcher}${setup}${inner}`;
|
|
13633
|
+
if (BSD_SCRIPT_PLATFORMS.has(opts.platform ?? process.platform)) {
|
|
13634
|
+
return { command: "/bin/sh", args: ["-c", BSD_SCRIPT_FEED, line] };
|
|
13635
|
+
}
|
|
13636
|
+
return { command: "script", args: ["-q", "-e", "-f", "-c", line, "/dev/null"] };
|
|
13586
13637
|
}
|
|
13587
13638
|
|
|
13588
13639
|
// src/services/blockingPrompts.ts
|
|
@@ -13777,24 +13828,37 @@ var Block = /* @__PURE__ */ ((Block2) => {
|
|
|
13777
13828
|
Block2[Block2["IfHeadlessSession"] = 8] = "IfHeadlessSession";
|
|
13778
13829
|
Block2[Block2["IfInteractiveVariant"] = 9] = "IfInteractiveVariant";
|
|
13779
13830
|
Block2[Block2["IfProjectTrust"] = 10] = "IfProjectTrust";
|
|
13831
|
+
Block2[Block2["IfHeadlessModel"] = 11] = "IfHeadlessModel";
|
|
13780
13832
|
return Block2;
|
|
13781
13833
|
})(Block || {});
|
|
13782
13834
|
function isInteractive(ctx) {
|
|
13783
13835
|
return ctx.interactive ?? !ctx.headless;
|
|
13784
13836
|
}
|
|
13837
|
+
function majorVersion(version) {
|
|
13838
|
+
const match = version?.match(/(\d+)\.\d+/);
|
|
13839
|
+
return match ? Number(match[1]) : void 0;
|
|
13840
|
+
}
|
|
13841
|
+
function versionedInvocation(manifest, ctx) {
|
|
13842
|
+
const major = majorVersion(ctx.runnerVersion);
|
|
13843
|
+
if (major === void 0) return void 0;
|
|
13844
|
+
return (manifest.runner.versioned ?? []).filter((v) => major >= v.minMajor).sort((a, b) => b.minMajor - a.minMajor)[0];
|
|
13845
|
+
}
|
|
13785
13846
|
function resolveArgs(manifest, ctx) {
|
|
13786
13847
|
const args = [];
|
|
13787
13848
|
const env = {};
|
|
13788
|
-
|
|
13789
|
-
|
|
13849
|
+
const versioned = versionedInvocation(manifest, ctx);
|
|
13850
|
+
const argsTemplate = versioned?.argsTemplate ?? manifest.runner.argsTemplate;
|
|
13851
|
+
const envTemplate = versioned ? versioned.env : manifest.runner.env;
|
|
13852
|
+
if (envTemplate) {
|
|
13853
|
+
for (const [key, value] of Object.entries(envTemplate)) {
|
|
13790
13854
|
const resolved = substituteSimple(value, ctx);
|
|
13791
13855
|
if (resolved.length > 0) env[key] = resolved;
|
|
13792
13856
|
}
|
|
13793
13857
|
}
|
|
13794
13858
|
let block = 0 /* None */;
|
|
13795
13859
|
let include = true;
|
|
13796
|
-
for (let i = 0; i <
|
|
13797
|
-
const raw =
|
|
13860
|
+
for (let i = 0; i < argsTemplate.length; i++) {
|
|
13861
|
+
const raw = argsTemplate[i];
|
|
13798
13862
|
const blockOpen = parseBlockOpen(raw);
|
|
13799
13863
|
if (blockOpen !== null) {
|
|
13800
13864
|
if (block !== 0 /* None */) throw new ResolveError(`Nested conditional block at position ${i}: "${raw}"`);
|
|
@@ -13853,6 +13917,8 @@ function parseBlockOpen(raw) {
|
|
|
13853
13917
|
return 9 /* IfInteractiveVariant */;
|
|
13854
13918
|
case "{{if projectTrust}}":
|
|
13855
13919
|
return 10 /* IfProjectTrust */;
|
|
13920
|
+
case "{{if headlessModel}}":
|
|
13921
|
+
return 11 /* IfHeadlessModel */;
|
|
13856
13922
|
default:
|
|
13857
13923
|
return null;
|
|
13858
13924
|
}
|
|
@@ -13892,6 +13958,9 @@ function shouldIncludeBlock(block, ctx) {
|
|
|
13892
13958
|
// there is no cwd to name.
|
|
13893
13959
|
case 10 /* IfProjectTrust */:
|
|
13894
13960
|
return isInteractive(ctx) && !!ctx.cwd;
|
|
13961
|
+
// A model flag that only the non-interactive subcommand takes.
|
|
13962
|
+
case 11 /* IfHeadlessModel */:
|
|
13963
|
+
return !!ctx.model && !isInteractive(ctx);
|
|
13895
13964
|
default:
|
|
13896
13965
|
return true;
|
|
13897
13966
|
}
|
|
@@ -13937,6 +14006,10 @@ function resolveToken(token, manifest, ctx) {
|
|
|
13937
14006
|
if (token === "{{model}}") return ctx.model || "";
|
|
13938
14007
|
if (token === "{{thinkingEffort}}") return ctx.thinkingEffort || "";
|
|
13939
14008
|
if (token === "{{mode}}") return ctx.mode || "build";
|
|
14009
|
+
if (token === "{{modelWithVariant}}") {
|
|
14010
|
+
if (!ctx.model) return "";
|
|
14011
|
+
return ctx.thinkingEffort ? `${ctx.model}#${ctx.thinkingEffort}` : ctx.model;
|
|
14012
|
+
}
|
|
13940
14013
|
if (token === "{{projectTrust}}") {
|
|
13941
14014
|
if (!ctx.cwd) return "";
|
|
13942
14015
|
return `projects.${JSON.stringify(ctx.cwd)}.trust_level="trusted"`;
|
|
@@ -14011,13 +14084,21 @@ function resolveOpencodeVariantConfig(ctx) {
|
|
|
14011
14084
|
}
|
|
14012
14085
|
return JSON.stringify(config);
|
|
14013
14086
|
}
|
|
14087
|
+
function resolveOpencodeSessionConfig(ctx) {
|
|
14088
|
+
const mode = ctx.mode || "build";
|
|
14089
|
+
const pinned = resolveOpencodeVariantConfig(ctx);
|
|
14090
|
+
const config = pinned ? JSON.parse(pinned) : {};
|
|
14091
|
+
config.default_agent = mode;
|
|
14092
|
+
if (ctx.model && !pinned) config.agent = { [mode]: { model: ctx.model } };
|
|
14093
|
+
return JSON.stringify(config);
|
|
14094
|
+
}
|
|
14014
14095
|
function substituteSimple(value, ctx) {
|
|
14015
14096
|
const conditioned = value.replace(/\{\{if (\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (match, name, body) => {
|
|
14016
14097
|
const block = parseBlockOpen(`{{if ${name}}}`);
|
|
14017
14098
|
if (block === null) return match;
|
|
14018
14099
|
return shouldIncludeBlock(block, ctx) ? body : "";
|
|
14019
14100
|
});
|
|
14020
|
-
return conditioned.replace(/\{\{opencodeVariantConfig\}\}/g, () => resolveOpencodeVariantConfig(ctx)).replace(/\{\{prompt\}\}/g, ctx.prompt).replace(/\{\{model\}\}/g, ctx.model || "").replace(/\{\{thinkingEffort\}\}/g, ctx.thinkingEffort || "").replace(/\{\{mode\}\}/g, ctx.mode || "build");
|
|
14101
|
+
return conditioned.replace(/\{\{opencodeVariantConfig\}\}/g, () => resolveOpencodeVariantConfig(ctx)).replace(/\{\{opencodeSessionConfig\}\}/g, () => resolveOpencodeSessionConfig(ctx)).replace(/\{\{prompt\}\}/g, ctx.prompt).replace(/\{\{model\}\}/g, ctx.model || "").replace(/\{\{thinkingEffort\}\}/g, ctx.thinkingEffort || "").replace(/\{\{mode\}\}/g, ctx.mode || "build");
|
|
14021
14102
|
}
|
|
14022
14103
|
|
|
14023
14104
|
// src/utils/launch.ts
|
|
@@ -23445,12 +23526,32 @@ function buildRunnerInvocation(opts) {
|
|
|
23445
23526
|
mode: opts.mode ?? "build",
|
|
23446
23527
|
headless: opts.headless,
|
|
23447
23528
|
interactive: opts.interactive,
|
|
23448
|
-
cwd: opts.cwd
|
|
23529
|
+
cwd: opts.cwd,
|
|
23530
|
+
runnerVersion: opts.runnerVersion
|
|
23449
23531
|
});
|
|
23450
23532
|
}
|
|
23451
23533
|
|
|
23452
23534
|
// src/services/HeadlessRunner.ts
|
|
23535
|
+
var import_child_process9 = require("child_process");
|
|
23536
|
+
|
|
23537
|
+
// src/services/runnerVersion.ts
|
|
23453
23538
|
var import_child_process8 = require("child_process");
|
|
23539
|
+
var VERSION_TIMEOUT_MS = 5e3;
|
|
23540
|
+
var cache = /* @__PURE__ */ new Map();
|
|
23541
|
+
var probeRunnerVersion = (command, PATH) => {
|
|
23542
|
+
const key = `${command}\0${PATH}`;
|
|
23543
|
+
let pending = cache.get(key);
|
|
23544
|
+
if (!pending) {
|
|
23545
|
+
pending = new Promise((resolve7) => {
|
|
23546
|
+
(0, import_child_process8.execFile)(command, ["--version"], { env: { ...process.env, PATH }, timeout: VERSION_TIMEOUT_MS }, (err, stdout) => {
|
|
23547
|
+
const line = String(stdout ?? "").trim();
|
|
23548
|
+
resolve7(err || !line ? void 0 : line);
|
|
23549
|
+
});
|
|
23550
|
+
});
|
|
23551
|
+
cache.set(key, pending);
|
|
23552
|
+
}
|
|
23553
|
+
return pending;
|
|
23554
|
+
};
|
|
23454
23555
|
|
|
23455
23556
|
// src/services/AbstractRunner.ts
|
|
23456
23557
|
var import_events = require("events");
|
|
@@ -23505,7 +23606,7 @@ var AbstractRunner = class {
|
|
|
23505
23606
|
function defaultHasScriptCmd() {
|
|
23506
23607
|
if (process.platform === "win32") return false;
|
|
23507
23608
|
try {
|
|
23508
|
-
(0,
|
|
23609
|
+
(0, import_child_process9.execSync)("which script", { stdio: "ignore" });
|
|
23509
23610
|
return true;
|
|
23510
23611
|
} catch {
|
|
23511
23612
|
return false;
|
|
@@ -23572,6 +23673,10 @@ Process error: ${err.message}
|
|
|
23572
23673
|
this.process.stdin.write(text2);
|
|
23573
23674
|
}
|
|
23574
23675
|
}
|
|
23676
|
+
/** Closes the runner's stdin: what it has read so far is all it will get. */
|
|
23677
|
+
endInput() {
|
|
23678
|
+
this.process?.stdin?.end();
|
|
23679
|
+
}
|
|
23575
23680
|
/** PTY resize requests from a surface that owns the terminal rendering the wrapper. */
|
|
23576
23681
|
writeControl(text2) {
|
|
23577
23682
|
if (this.controlStream && !this.controlStream.destroyed) {
|
|
@@ -23584,6 +23689,7 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
23584
23689
|
hasScriptCmd;
|
|
23585
23690
|
resolvePath;
|
|
23586
23691
|
launchDeps;
|
|
23692
|
+
runnerVersion;
|
|
23587
23693
|
spawnCount = 0;
|
|
23588
23694
|
/**
|
|
23589
23695
|
* Session shape: a piped subprocess is not a terminal, so runners get their
|
|
@@ -23595,10 +23701,11 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
23595
23701
|
defaultInteractive = false;
|
|
23596
23702
|
constructor(deps = {}) {
|
|
23597
23703
|
super();
|
|
23598
|
-
this.spawnImpl = deps.spawnImpl ??
|
|
23704
|
+
this.spawnImpl = deps.spawnImpl ?? import_child_process9.spawn;
|
|
23599
23705
|
this.hasScriptCmd = deps.hasScriptCmd ?? defaultHasScriptCmd;
|
|
23600
23706
|
this.resolvePath = deps.resolvePath ?? augmentedPath;
|
|
23601
23707
|
this.launchDeps = { resolvePath: this.resolvePath, ...deps.launchDeps };
|
|
23708
|
+
this.runnerVersion = deps.runnerVersion ?? probeRunnerVersion;
|
|
23602
23709
|
}
|
|
23603
23710
|
/**
|
|
23604
23711
|
* Unique per spawn, not per task: a retry reuses its task id and ids often
|
|
@@ -23616,6 +23723,9 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
23616
23723
|
/** Everything up to, but not including, spawning — so a surface that owns its own child reaches the same decisions. */
|
|
23617
23724
|
async prepareLaunch(opts, ptyOptions) {
|
|
23618
23725
|
const interactive = this.defaultInteractive;
|
|
23726
|
+
const resolvedPath = await this.resolvePath();
|
|
23727
|
+
const manifest = opts.registry?.get(opts.runner)?.manifest;
|
|
23728
|
+
const runnerVersion = manifest?.runner.versioned?.length ? await this.runnerVersion(manifest.runner.command, resolvedPath) : void 0;
|
|
23619
23729
|
const invocation = buildRunnerInvocation({
|
|
23620
23730
|
runner: opts.runner,
|
|
23621
23731
|
prompt: opts.prompt,
|
|
@@ -23626,18 +23736,18 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
23626
23736
|
headless: opts.headless ?? true,
|
|
23627
23737
|
interactive,
|
|
23628
23738
|
cwd: opts.cwd,
|
|
23739
|
+
runnerVersion,
|
|
23629
23740
|
registry: opts.registry
|
|
23630
23741
|
});
|
|
23631
|
-
const manifest = opts.registry?.get(opts.runner)?.manifest;
|
|
23632
23742
|
const pty = (manifest?.runner.requiresTty === true || interactive) && this.hasScriptCmd();
|
|
23633
|
-
const
|
|
23634
|
-
const { command, args } = pty ? wrapWithPty(invocation.command, invocation.args, ptyOptions) : { command: invocation.command, args: invocation.args };
|
|
23743
|
+
const { command, args } = pty ? wrapWithPty(invocation.command, invocation.args, { platform: this.launchDeps.platform, ...ptyOptions }) : { command: invocation.command, args: invocation.args };
|
|
23635
23744
|
return {
|
|
23636
23745
|
launch: await planDirectLaunch(command, args, this.launchDeps),
|
|
23637
23746
|
resolvedPath,
|
|
23638
23747
|
env: { ...opts.env, ...invocation.env },
|
|
23639
23748
|
pty,
|
|
23640
|
-
submitPromptKey: invocation.submitPromptKey
|
|
23749
|
+
submitPromptKey: invocation.submitPromptKey,
|
|
23750
|
+
closeStdin: !pty && !interactive && invocation.promptInArgs
|
|
23641
23751
|
};
|
|
23642
23752
|
}
|
|
23643
23753
|
async spawn(opts) {
|
|
@@ -23648,20 +23758,21 @@ var HeadlessRunner = class extends AbstractRunner {
|
|
|
23648
23758
|
console.error(`[headless] Starting ${opts.runner} [${modeStr}] (${opts.modelId || "default"}) for task ${opts.taskId.slice(0, 8)}${prepared.pty ? " (PTY)" : ""}`);
|
|
23649
23759
|
session.start(prepared.launch, opts.cwd, prepared.resolvedPath, prepared.env);
|
|
23650
23760
|
if (prepared.submitPromptKey) session.write("\r");
|
|
23761
|
+
if (prepared.closeStdin) session.endInput();
|
|
23651
23762
|
this.registerSession(id, session);
|
|
23652
23763
|
return session;
|
|
23653
23764
|
}
|
|
23654
23765
|
};
|
|
23655
23766
|
|
|
23656
23767
|
// src/services/TmuxRunner.ts
|
|
23657
|
-
var
|
|
23768
|
+
var import_child_process11 = require("child_process");
|
|
23658
23769
|
var import_util5 = require("util");
|
|
23659
23770
|
var import_os = require("os");
|
|
23660
23771
|
var import_path2 = require("path");
|
|
23661
23772
|
var import_fs3 = require("fs");
|
|
23662
23773
|
|
|
23663
23774
|
// src/utils/tmux.ts
|
|
23664
|
-
var
|
|
23775
|
+
var import_child_process10 = require("child_process");
|
|
23665
23776
|
function tmuxSessionName(port) {
|
|
23666
23777
|
return `ordewell-${port}`;
|
|
23667
23778
|
}
|
|
@@ -23674,7 +23785,7 @@ function tmuxWindowName(taskId, planSessionId) {
|
|
|
23674
23785
|
return `t-${scope}${slug(taskId).slice(0, 16)}`;
|
|
23675
23786
|
}
|
|
23676
23787
|
var defaultProbe = () => {
|
|
23677
|
-
(0,
|
|
23788
|
+
(0, import_child_process10.execSync)(process.platform === "win32" ? "where tmux" : "which tmux", { stdio: "ignore" });
|
|
23678
23789
|
};
|
|
23679
23790
|
function hasTmux(probe = defaultProbe) {
|
|
23680
23791
|
try {
|
|
@@ -23686,7 +23797,7 @@ function hasTmux(probe = defaultProbe) {
|
|
|
23686
23797
|
}
|
|
23687
23798
|
var defaultHasBin = (bin) => {
|
|
23688
23799
|
try {
|
|
23689
|
-
(0,
|
|
23800
|
+
(0, import_child_process10.execSync)(`${process.platform === "win32" ? "where" : "which"} ${bin}`, { stdio: "ignore" });
|
|
23690
23801
|
return true;
|
|
23691
23802
|
} catch {
|
|
23692
23803
|
return false;
|
|
@@ -23711,7 +23822,7 @@ function clipboardCopyCommand(hasBin = defaultHasBin, platform = process.platfor
|
|
|
23711
23822
|
var EXIT_RE = /<<<ORDEWELL_TMUX_EXIT:(\d+)>>>/;
|
|
23712
23823
|
var LIVENESS_INTERVAL_MS = 5e3;
|
|
23713
23824
|
var LIVENESS_MISSES = 2;
|
|
23714
|
-
var execFileAsync2 = (0, import_util5.promisify)(
|
|
23825
|
+
var execFileAsync2 = (0, import_util5.promisify)(import_child_process11.execFile);
|
|
23715
23826
|
var defaultExecFile3 = async (command, args) => {
|
|
23716
23827
|
const { stdout, stderr } = await execFileAsync2(command, args);
|
|
23717
23828
|
return { stdout: String(stdout), stderr: String(stderr) };
|
|
@@ -23861,6 +23972,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
23861
23972
|
pollIntervalMs;
|
|
23862
23973
|
logDir;
|
|
23863
23974
|
clipboardCommand;
|
|
23975
|
+
runnerVersion;
|
|
23864
23976
|
/** Retries get a freshly named window so a failed attempt's output stays inspectable. */
|
|
23865
23977
|
attempts = /* @__PURE__ */ new Map();
|
|
23866
23978
|
ready = null;
|
|
@@ -23873,6 +23985,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
23873
23985
|
this.pollIntervalMs = deps.pollIntervalMs ?? 500;
|
|
23874
23986
|
this.logDir = deps.logDir ?? (0, import_os.tmpdir)();
|
|
23875
23987
|
this.clipboardCommand = deps.clipboardCommand ?? (() => clipboardCopyCommand());
|
|
23988
|
+
this.runnerVersion = deps.runnerVersion ?? probeRunnerVersion;
|
|
23876
23989
|
}
|
|
23877
23990
|
/**
|
|
23878
23991
|
* Reaps a session orphaned by a crashed prior daemon on the same port, then
|
|
@@ -23956,6 +24069,8 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
23956
24069
|
}
|
|
23957
24070
|
}
|
|
23958
24071
|
async spawn(opts) {
|
|
24072
|
+
const manifest = opts.registry?.get(opts.runner)?.manifest;
|
|
24073
|
+
const runnerVersion = manifest?.runner.versioned?.length ? await this.runnerVersion(manifest.runner.command, await this.resolvePath()) : void 0;
|
|
23959
24074
|
const invocation = buildRunnerInvocation({
|
|
23960
24075
|
runner: opts.runner,
|
|
23961
24076
|
prompt: opts.prompt,
|
|
@@ -23971,6 +24086,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
23971
24086
|
headless: opts.headless ?? true,
|
|
23972
24087
|
interactive: true,
|
|
23973
24088
|
cwd: opts.cwd,
|
|
24089
|
+
runnerVersion,
|
|
23974
24090
|
registry: opts.registry
|
|
23975
24091
|
});
|
|
23976
24092
|
await this.ensureSession();
|
|
@@ -24000,7 +24116,7 @@ var TmuxRunner = class extends AbstractRunner {
|
|
|
24000
24116
|
|
|
24001
24117
|
// src/services/StructuredRunner.ts
|
|
24002
24118
|
var import_events2 = require("events");
|
|
24003
|
-
var
|
|
24119
|
+
var import_child_process12 = require("child_process");
|
|
24004
24120
|
var DEFAULT_INTERRUPT_GRACE_MS = 5e3;
|
|
24005
24121
|
var TOOL_ARG_MAX_CHARS = 120;
|
|
24006
24122
|
var TURN_OPENING_EVENTS = /* @__PURE__ */ new Set(["assistant_text", "assistant_text_delta", "thinking", "thinking_delta", "tool_call"]);
|
|
@@ -24374,7 +24490,7 @@ var StructuredRunner = class extends AbstractRunner {
|
|
|
24374
24490
|
const session = new StructuredSession(id, opts.taskId, {
|
|
24375
24491
|
runner: opts.runner,
|
|
24376
24492
|
deps: {
|
|
24377
|
-
spawn:
|
|
24493
|
+
spawn: import_child_process12.spawn,
|
|
24378
24494
|
fetch: globalThis.fetch,
|
|
24379
24495
|
...this.processDeps,
|
|
24380
24496
|
// Already resolved by the caller (ADR-0016); resolving it again here
|
|
@@ -24469,7 +24585,7 @@ function tokensMatch(presented, expected) {
|
|
|
24469
24585
|
var fs13 = __toESM(require("fs"));
|
|
24470
24586
|
var path24 = __toESM(require("path"));
|
|
24471
24587
|
var os6 = __toESM(require("os"));
|
|
24472
|
-
var
|
|
24588
|
+
var import_child_process13 = require("child_process");
|
|
24473
24589
|
var import_crypto6 = require("crypto");
|
|
24474
24590
|
|
|
24475
24591
|
// src/plugins/FsPluginStore.ts
|
|
@@ -24887,6 +25003,37 @@ var OPENCODE_MANIFEST = {
|
|
|
24887
25003
|
env: {
|
|
24888
25004
|
OPENCODE_CONFIG_CONTENT: "{{if interactiveVariant}}{{opencodeVariantConfig}}{{/if}}"
|
|
24889
25005
|
},
|
|
25006
|
+
// OpenCode 2.x changed both shapes. Its TUI takes no `--model`/`--agent`,
|
|
25007
|
+
// so they ride on OPENCODE_CONFIG_CONTENT instead, and its `run` has no
|
|
25008
|
+
// `--variant` — the variant is a `#suffix` on the model id. Both run
|
|
25009
|
+
// `--standalone`: without it the TUI and `run` attach to the user's
|
|
25010
|
+
// background service, which neither reads this process's config nor
|
|
25011
|
+
// starts in the task's directory and environment.
|
|
25012
|
+
versioned: [{
|
|
25013
|
+
minMajor: 2,
|
|
25014
|
+
argsTemplate: [
|
|
25015
|
+
"{{if headlessSession}}",
|
|
25016
|
+
"run",
|
|
25017
|
+
"--agent",
|
|
25018
|
+
"{{mode}}",
|
|
25019
|
+
"{{/if}}",
|
|
25020
|
+
"{{if headlessModel}}",
|
|
25021
|
+
"--model",
|
|
25022
|
+
"{{modelWithVariant}}",
|
|
25023
|
+
"{{/if}}",
|
|
25024
|
+
"--standalone",
|
|
25025
|
+
"{{if buildMode}}",
|
|
25026
|
+
"--auto",
|
|
25027
|
+
"{{/if}}",
|
|
25028
|
+
"{{if interactive}}",
|
|
25029
|
+
"--prompt",
|
|
25030
|
+
"{{/if}}",
|
|
25031
|
+
"{{prompt}}"
|
|
25032
|
+
],
|
|
25033
|
+
env: {
|
|
25034
|
+
OPENCODE_CONFIG_CONTENT: "{{if interactive}}{{opencodeSessionConfig}}{{/if}}"
|
|
25035
|
+
}
|
|
25036
|
+
}],
|
|
24890
25037
|
promptInArgs: true,
|
|
24891
25038
|
requiresTty: true,
|
|
24892
25039
|
// `--prompt` only pre-fills the TUI's composer; it does not submit it.
|
|
@@ -25005,7 +25152,7 @@ function isReservedRunnerName(name) {
|
|
|
25005
25152
|
return RESERVED_RUNNER_NAMES.has(name.toLowerCase());
|
|
25006
25153
|
}
|
|
25007
25154
|
function gitClone(url, destDir) {
|
|
25008
|
-
(0,
|
|
25155
|
+
(0, import_child_process13.execFileSync)("git", ["clone", "--depth", "1", "--", url, destDir], {
|
|
25009
25156
|
stdio: "pipe",
|
|
25010
25157
|
timeout: 3e4,
|
|
25011
25158
|
// A repository that demands credentials should fail, not hang on a prompt.
|