@ordewell/core 0.11.1 → 0.11.2
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/AUTHORS.md +4 -0
- package/dist/{IRunner-B5l9PCTv.d.ts → IRunner-DOMtDTVt.d.ts} +50 -14
- package/dist/{IRunner-DBgDx_Mr.d.mts → IRunner-ihalYfTo.d.mts} +50 -14
- package/dist/{chunk-4QXOWEGC.mjs → chunk-7WNLN63J.mjs} +11 -4
- package/dist/chunk-7WNLN63J.mjs.map +1 -0
- package/dist/index.d.mts +44 -12
- package/dist/index.d.ts +44 -12
- package/dist/index.js +901 -497
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +878 -480
- package/dist/index.mjs.map +1 -1
- package/dist/plan-utils.d.mts +2 -2
- package/dist/plan-utils.d.ts +2 -2
- package/dist/plan-utils.js +7 -0
- package/dist/plan-utils.js.map +1 -1
- package/dist/plan-utils.mjs +3 -1
- package/dist/{runSettingsText-CAXiTpsj.d.ts → runSettingsText-CYMhTWfw.d.ts} +110 -67
- package/dist/{runSettingsText-BKwWs052.d.mts → runSettingsText-tnmvdSfS.d.mts} +110 -67
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-4QXOWEGC.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -210,6 +210,7 @@ __export(index_exports, {
|
|
|
210
210
|
assignedRunnerOf: () => assignedRunnerOf,
|
|
211
211
|
assignmentIssue: () => assignmentIssue,
|
|
212
212
|
assignmentIssueText: () => assignmentIssueText,
|
|
213
|
+
attachingLabel: () => attachingLabel,
|
|
213
214
|
augmentedPath: () => augmentedPath,
|
|
214
215
|
automergeSummary: () => automergeSummary,
|
|
215
216
|
autonomyLevelLabel: () => autonomyLevelLabel,
|
|
@@ -661,18 +662,18 @@ function dependencyTargetErrors(tasks, taskId, dependencies) {
|
|
|
661
662
|
}
|
|
662
663
|
function findDependencyCycle(tasks) {
|
|
663
664
|
const byId = new Map([...walkPlan(tasks)].map(({ task: task2 }) => [task2.id, task2]));
|
|
664
|
-
const
|
|
665
|
+
const path48 = [];
|
|
665
666
|
const done = /* @__PURE__ */ new Set();
|
|
666
667
|
const visit = (id2) => {
|
|
667
668
|
if (done.has(id2)) return null;
|
|
668
|
-
const at =
|
|
669
|
-
if (at >= 0) return
|
|
670
|
-
|
|
669
|
+
const at = path48.indexOf(id2);
|
|
670
|
+
if (at >= 0) return path48.slice(at);
|
|
671
|
+
path48.push(id2);
|
|
671
672
|
for (const dep of byId.get(id2)?.dependencies ?? []) {
|
|
672
673
|
const hit = visit(dep);
|
|
673
674
|
if (hit) return hit;
|
|
674
675
|
}
|
|
675
|
-
|
|
676
|
+
path48.pop();
|
|
676
677
|
done.add(id2);
|
|
677
678
|
return null;
|
|
678
679
|
};
|
|
@@ -1737,7 +1738,7 @@ function lastServedModel(events) {
|
|
|
1737
1738
|
return void 0;
|
|
1738
1739
|
}
|
|
1739
1740
|
function taskLogForSurface(events) {
|
|
1740
|
-
return events.map((event) => event.type === "task_skills" ? { type: "task_skills", skills: event.skills.map(({ name, source, path:
|
|
1741
|
+
return events.map((event) => event.type === "task_skills" ? { type: "task_skills", skills: event.skills.map(({ name, source, path: path48 }) => ({ name, source, path: path48 })) } : event);
|
|
1741
1742
|
}
|
|
1742
1743
|
function coalesceTaskLog(events) {
|
|
1743
1744
|
const out = [];
|
|
@@ -2780,9 +2781,9 @@ function literalCdTarget(seg) {
|
|
|
2780
2781
|
return target === "" || target.startsWith("-") || target.startsWith("~") || /[*?[]/.test(target) ? void 0 : target;
|
|
2781
2782
|
}
|
|
2782
2783
|
function followCd(segments) {
|
|
2783
|
-
if (segments.some((s) => s.joinedBy === "other" ||
|
|
2784
|
+
if (segments.some((s) => s.joinedBy === "other" || movesShell(s))) return;
|
|
2784
2785
|
const inPipeline = (i) => segments[i].joinedBy === "pipe" || segments[i + 1]?.joinedBy === "pipe";
|
|
2785
|
-
if (segments.some((s, i) => s.binary === "cd" && !inPipeline(i) && literalCdTarget(s) === void 0)) return;
|
|
2786
|
+
if (segments.some((s, i) => s.binary.toLowerCase() === "cd" && !inPipeline(i) && literalCdTarget(s) === void 0)) return;
|
|
2786
2787
|
let chain = [];
|
|
2787
2788
|
segments.forEach((seg, i) => {
|
|
2788
2789
|
seg.cwd = chain;
|
|
@@ -2791,7 +2792,7 @@ function followCd(segments) {
|
|
|
2791
2792
|
});
|
|
2792
2793
|
}
|
|
2793
2794
|
function markShellState(segments, bareSegment) {
|
|
2794
|
-
if (!bareSegment && !segments.some(
|
|
2795
|
+
if (!bareSegment && !segments.some(movesShell)) return;
|
|
2795
2796
|
for (const seg of segments) if (seg.binary === "cd") seg.cdSteered = true;
|
|
2796
2797
|
}
|
|
2797
2798
|
var SHELL_STATE_COMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -2810,6 +2811,7 @@ var SHELL_STATE_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
2810
2811
|
"exec",
|
|
2811
2812
|
"pushd",
|
|
2812
2813
|
"popd",
|
|
2814
|
+
"chdir",
|
|
2813
2815
|
"alias",
|
|
2814
2816
|
"unalias",
|
|
2815
2817
|
"builtin",
|
|
@@ -2818,6 +2820,9 @@ var SHELL_STATE_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
2818
2820
|
"hash",
|
|
2819
2821
|
"trap"
|
|
2820
2822
|
]);
|
|
2823
|
+
function movesShell(seg) {
|
|
2824
|
+
return SHELL_STATE_COMMANDS.has(seg.binary.toLowerCase());
|
|
2825
|
+
}
|
|
2821
2826
|
|
|
2822
2827
|
// src/services/commandRunners.ts
|
|
2823
2828
|
var HELP_FLAGS = ["--help", "--version"];
|
|
@@ -3673,8 +3678,9 @@ var FLAG_POLICY = {
|
|
|
3673
3678
|
sort: {
|
|
3674
3679
|
cluster: true,
|
|
3675
3680
|
// Absent on purpose: `-o`/`--output` writes a file with no redirect for the
|
|
3676
|
-
// redirect check to see,
|
|
3677
|
-
//
|
|
3681
|
+
// redirect check to see, `-T`/`--temporary-directory` names where sort writes
|
|
3682
|
+
// its run files, and `--compress-program` names a program that sort runs
|
|
3683
|
+
// over its own temporary files — a permitted binary as an interpreter.
|
|
3678
3684
|
booleans: [
|
|
3679
3685
|
"-b",
|
|
3680
3686
|
"-c",
|
|
@@ -3713,11 +3719,9 @@ var FLAG_POLICY = {
|
|
|
3713
3719
|
"-k",
|
|
3714
3720
|
"-t",
|
|
3715
3721
|
"-S",
|
|
3716
|
-
"-T",
|
|
3717
3722
|
"--key",
|
|
3718
3723
|
"--field-separator",
|
|
3719
3724
|
"--buffer-size",
|
|
3720
|
-
"--temporary-directory",
|
|
3721
3725
|
"--random-source",
|
|
3722
3726
|
"--batch-size",
|
|
3723
3727
|
"--parallel",
|
|
@@ -4344,23 +4348,28 @@ function scanFlags(seg) {
|
|
|
4344
4348
|
const booleans = /* @__PURE__ */ new Set([...spec.booleans ?? [], ...UNIVERSAL_FLAGS]);
|
|
4345
4349
|
const values = new Set(spec.values ?? []);
|
|
4346
4350
|
const operands = [];
|
|
4351
|
+
const operandAt = [];
|
|
4352
|
+
const operand = (at) => {
|
|
4353
|
+
operands.push(seg.args[at]);
|
|
4354
|
+
operandAt.push(at);
|
|
4355
|
+
};
|
|
4347
4356
|
let i = 0;
|
|
4348
4357
|
while (i < seg.args.length) {
|
|
4349
4358
|
const token = seg.args[i];
|
|
4350
4359
|
if (token === "--" && !spec.expressionArgs) {
|
|
4351
|
-
|
|
4360
|
+
for (let j = i + 1; j < seg.args.length; j++) operand(j);
|
|
4352
4361
|
break;
|
|
4353
4362
|
}
|
|
4354
4363
|
if (!/^-./.test(token)) {
|
|
4355
|
-
|
|
4364
|
+
operand(i);
|
|
4356
4365
|
i++;
|
|
4357
4366
|
continue;
|
|
4358
4367
|
}
|
|
4359
4368
|
const shape = matchFlag(spec, booleans, values, token);
|
|
4360
|
-
if (shape === void 0) return { unknown: flagLabel(token), operands };
|
|
4369
|
+
if (shape === void 0) return { unknown: flagLabel(token), operands, operandAt };
|
|
4361
4370
|
i += shape === "value" && takesNextToken(seg.args[i + 1]) ? 2 : 1;
|
|
4362
4371
|
}
|
|
4363
|
-
return { operands };
|
|
4372
|
+
return { operands, operandAt };
|
|
4364
4373
|
}
|
|
4365
4374
|
function subcommandOf(seg) {
|
|
4366
4375
|
const scan = scanFlags(seg);
|
|
@@ -4513,6 +4522,8 @@ function sedRefusalFor(binary, scripts) {
|
|
|
4513
4522
|
return `The "${binary}" script runs a shell command (the "e" command or the "e" flag of "s"), which this classifier cannot inspect. ${INSPECT_OR_TASK}`;
|
|
4514
4523
|
case "write":
|
|
4515
4524
|
return `The "${binary}" script writes a file (the "w"/"W" command or the "w" flag of "s"). You are a read-only planner \u2014 print the output instead, or describe the write as a task.`;
|
|
4525
|
+
case "read":
|
|
4526
|
+
return `The "${binary}" script reads a file it names itself (the "r"/"R" command), which path confinement cannot see. Read that file directly instead.`;
|
|
4516
4527
|
default:
|
|
4517
4528
|
return `This classifier could not read the "${binary}" script well enough to rule out a shell command or a file write in it. Rewrite it with plain print, delete and substitute commands, or describe the work as a task.`;
|
|
4518
4529
|
}
|
|
@@ -4633,6 +4644,7 @@ function sedScriptHazard(script) {
|
|
|
4633
4644
|
if (cmd === void 0) return "unreadable";
|
|
4634
4645
|
if (cmd === "e") return "exec";
|
|
4635
4646
|
if (cmd === "w" || cmd === "W") return "write";
|
|
4647
|
+
if (cmd === "r" || cmd === "R") return "read";
|
|
4636
4648
|
if (cmd === "{" || cmd === "}") continue;
|
|
4637
4649
|
if (cmd === "#") {
|
|
4638
4650
|
while (i < n && script[i] !== "\n") i++;
|
|
@@ -4654,7 +4666,7 @@ function sedScriptHazard(script) {
|
|
|
4654
4666
|
if (!commandEnds()) return "unreadable";
|
|
4655
4667
|
continue;
|
|
4656
4668
|
}
|
|
4657
|
-
if ("
|
|
4669
|
+
if ("aic".includes(cmd)) {
|
|
4658
4670
|
while (i < n && script[i] !== "\n") i += script[i] === "\\" ? 2 : 1;
|
|
4659
4671
|
continue;
|
|
4660
4672
|
}
|
|
@@ -4754,6 +4766,12 @@ function awkRefusalFor(binary, programs) {
|
|
|
4754
4766
|
return `The "${binary}" program pipes to or from a command ("|"), which runs it through a shell this classifier cannot inspect. ${INSPECT_OR_TASK}`;
|
|
4755
4767
|
case "write":
|
|
4756
4768
|
return `The "${binary}" program redirects its output to a file (">"). You are a read-only planner \u2014 print to standard output instead, or describe the write as a task.`;
|
|
4769
|
+
case "read":
|
|
4770
|
+
return `The "${binary}" program reads a file it names itself ("getline <" or an "ARGV" entry), which path confinement cannot see. Name the file as an operand instead.`;
|
|
4771
|
+
case "environment":
|
|
4772
|
+
return `The "${binary}" program reads the environment ("ENVIRON"), which holds credentials. Run printenv for the one variable you need, which asks first.`;
|
|
4773
|
+
case "symbol-table":
|
|
4774
|
+
return `The "${binary}" program uses "SYMTAB", which gawk reads as every global by name, "ENVIRON" and "ARGV" included. Name the variable you need directly.`;
|
|
4757
4775
|
case "extension":
|
|
4758
4776
|
return `The "${binary}" program uses an "@" form, which loads an extension, includes a source file or calls a function by name \u2014 none of which this classifier can inspect. ${INSPECT_OR_TASK}`;
|
|
4759
4777
|
default:
|
|
@@ -4795,6 +4813,7 @@ function awkProgramHazard(program) {
|
|
|
4795
4813
|
let slash = "regex";
|
|
4796
4814
|
let depth = 0;
|
|
4797
4815
|
let printDepth;
|
|
4816
|
+
let getlineDepth;
|
|
4798
4817
|
let continues = false;
|
|
4799
4818
|
const readRegex = () => {
|
|
4800
4819
|
i++;
|
|
@@ -4861,7 +4880,10 @@ function awkProgramHazard(program) {
|
|
|
4861
4880
|
continue;
|
|
4862
4881
|
}
|
|
4863
4882
|
if (c === "\n" || c === ";") {
|
|
4864
|
-
if (c === ";" || !continues)
|
|
4883
|
+
if (c === ";" || !continues) {
|
|
4884
|
+
printDepth = void 0;
|
|
4885
|
+
getlineDepth = void 0;
|
|
4886
|
+
}
|
|
4865
4887
|
slash = "regex";
|
|
4866
4888
|
i++;
|
|
4867
4889
|
continue;
|
|
@@ -4912,6 +4934,12 @@ function awkProgramHazard(program) {
|
|
|
4912
4934
|
slash = "unclear";
|
|
4913
4935
|
continue;
|
|
4914
4936
|
}
|
|
4937
|
+
if (c === "<") {
|
|
4938
|
+
if (getlineDepth !== void 0 && depth >= getlineDepth) return "read";
|
|
4939
|
+
i++;
|
|
4940
|
+
slash = "unclear";
|
|
4941
|
+
continue;
|
|
4942
|
+
}
|
|
4915
4943
|
if (c === "(" || c === "[") {
|
|
4916
4944
|
depth++;
|
|
4917
4945
|
i++;
|
|
@@ -4920,12 +4948,16 @@ function awkProgramHazard(program) {
|
|
|
4920
4948
|
}
|
|
4921
4949
|
if (c === ")" || c === "]") {
|
|
4922
4950
|
depth--;
|
|
4951
|
+
if (getlineDepth !== void 0 && depth < getlineDepth) getlineDepth = void 0;
|
|
4923
4952
|
i++;
|
|
4924
4953
|
slash = "divide";
|
|
4925
4954
|
continue;
|
|
4926
4955
|
}
|
|
4927
4956
|
if (c === "{" || c === "}") {
|
|
4928
|
-
if (c === "}")
|
|
4957
|
+
if (c === "}") {
|
|
4958
|
+
printDepth = void 0;
|
|
4959
|
+
getlineDepth = void 0;
|
|
4960
|
+
}
|
|
4929
4961
|
i++;
|
|
4930
4962
|
slash = "regex";
|
|
4931
4963
|
continue;
|
|
@@ -4946,6 +4978,10 @@ function awkProgramHazard(program) {
|
|
|
4946
4978
|
while (i < n && /[A-Za-z0-9_.]/.test(program[i])) i++;
|
|
4947
4979
|
const word = program.slice(start, i);
|
|
4948
4980
|
if (word === "system") return "exec";
|
|
4981
|
+
if (word === "ENVIRON") return "environment";
|
|
4982
|
+
if (word === "ARGV") return "read";
|
|
4983
|
+
if (word === "SYMTAB") return "symbol-table";
|
|
4984
|
+
if (word === "getline") getlineDepth = depth;
|
|
4949
4985
|
if (word === "print" || word === "printf") printDepth = depth;
|
|
4950
4986
|
slash = AWK_KEYWORDS.includes(word) ? "unclear" : "divide";
|
|
4951
4987
|
continue;
|
|
@@ -5832,6 +5868,36 @@ var GIT_READONLY_SUBCOMMANDS = [
|
|
|
5832
5868
|
"whatchanged",
|
|
5833
5869
|
"cat-file"
|
|
5834
5870
|
];
|
|
5871
|
+
var onlyAction = (...reads) => (after) => after[0] === void 0 || reads.includes(after[0]);
|
|
5872
|
+
var GIT_PROMPTABLE = {
|
|
5873
|
+
"ls-remote": () => true,
|
|
5874
|
+
"for-each-ref": () => true,
|
|
5875
|
+
"show-ref": () => true,
|
|
5876
|
+
"name-rev": () => true,
|
|
5877
|
+
"merge-base": () => true,
|
|
5878
|
+
"count-objects": () => true,
|
|
5879
|
+
"cherry": () => true,
|
|
5880
|
+
"range-diff": () => true,
|
|
5881
|
+
"diff-tree": () => true,
|
|
5882
|
+
"diff-files": () => true,
|
|
5883
|
+
"diff-index": () => true,
|
|
5884
|
+
"show-branch": () => true,
|
|
5885
|
+
"annotate": () => true,
|
|
5886
|
+
"check-ignore": () => true,
|
|
5887
|
+
"check-attr": () => true,
|
|
5888
|
+
"check-ref-format": () => true,
|
|
5889
|
+
"check-mailmap": () => true,
|
|
5890
|
+
"var": () => true,
|
|
5891
|
+
"version": () => true,
|
|
5892
|
+
"worktree": onlyAction("list"),
|
|
5893
|
+
"notes": onlyAction("list", "show"),
|
|
5894
|
+
"bisect": onlyAction("log"),
|
|
5895
|
+
"sparse-checkout": onlyAction("list"),
|
|
5896
|
+
"reflog": onlyAction("show", "exists"),
|
|
5897
|
+
"symbolic-ref": (after) => after.filter((a) => !a.startsWith("-")).length <= 1,
|
|
5898
|
+
// `-w` writes the object; git's shared flag set keeps it for `git diff -w`.
|
|
5899
|
+
"hash-object": (after) => !after.some((a) => /^-[^-]*w/.test(a))
|
|
5900
|
+
};
|
|
5835
5901
|
var REFUSED_COMMANDS = [
|
|
5836
5902
|
"rm",
|
|
5837
5903
|
"rmdir",
|
|
@@ -5923,7 +5989,28 @@ var REFUSED_SUBCOMMANDS = {
|
|
|
5923
5989
|
"clone",
|
|
5924
5990
|
"fetch",
|
|
5925
5991
|
"pull",
|
|
5926
|
-
"submodule"
|
|
5992
|
+
"submodule",
|
|
5993
|
+
"add",
|
|
5994
|
+
"rm",
|
|
5995
|
+
"mv",
|
|
5996
|
+
"format-patch",
|
|
5997
|
+
"replace",
|
|
5998
|
+
"mergetool",
|
|
5999
|
+
"repack",
|
|
6000
|
+
"update-index",
|
|
6001
|
+
"read-tree",
|
|
6002
|
+
"checkout-index",
|
|
6003
|
+
"merge-file",
|
|
6004
|
+
"bundle",
|
|
6005
|
+
"commit-tree",
|
|
6006
|
+
"write-tree",
|
|
6007
|
+
"mktree",
|
|
6008
|
+
"mktag",
|
|
6009
|
+
"unpack-objects",
|
|
6010
|
+
"fast-import",
|
|
6011
|
+
"pack-refs",
|
|
6012
|
+
"prune-packed",
|
|
6013
|
+
"maintenance"
|
|
5927
6014
|
],
|
|
5928
6015
|
npm: ["publish", "unpublish", "deprecate", "owner", "access", "token", "login", "logout"],
|
|
5929
6016
|
yarn: ["publish", "npm"],
|
|
@@ -6133,7 +6220,7 @@ function pathRefs(command, opts = {}) {
|
|
|
6133
6220
|
return lexAll(command.trim(), dialect, opts.cdpathSet).segments.flatMap((seg) => {
|
|
6134
6221
|
const patterns = patternArgs(seg);
|
|
6135
6222
|
const cwd = seg.cwd ?? [];
|
|
6136
|
-
return [...seg.args.filter((_, i) => !patterns.has(i)), ...seg.inputs].flatMap(pathIn).map((
|
|
6223
|
+
return [...seg.args.filter((_, i) => !patterns.has(i)), ...seg.inputs].flatMap(pathIn).map((path48) => ({ path: path48, cwd }));
|
|
6137
6224
|
});
|
|
6138
6225
|
}
|
|
6139
6226
|
function excludedBy(command, allow, opts = {}) {
|
|
@@ -6240,7 +6327,9 @@ function patternArgs(seg) {
|
|
|
6240
6327
|
var SCOPE_LEAD_ARGS = 2;
|
|
6241
6328
|
function scopeFor(seg) {
|
|
6242
6329
|
const name = seg.binaryPath ?? seg.binary;
|
|
6243
|
-
|
|
6330
|
+
const program = programName(seg.binary);
|
|
6331
|
+
if (!MULTIPLEXERS.includes(program)) return name;
|
|
6332
|
+
if (program === "git") return gitScope(seg, name);
|
|
6244
6333
|
const lead = [];
|
|
6245
6334
|
for (const arg of seg.args) {
|
|
6246
6335
|
if (arg.startsWith("-")) break;
|
|
@@ -6249,6 +6338,14 @@ function scopeFor(seg) {
|
|
|
6249
6338
|
}
|
|
6250
6339
|
return [name, ...lead].join(" ");
|
|
6251
6340
|
}
|
|
6341
|
+
function gitScope(seg, name) {
|
|
6342
|
+
const scan = scanFlags({ ...seg, binary: "git" });
|
|
6343
|
+
if (!scan || scan.unknown || scan.operands[0] === "ls-remote") return [name, ...seg.args].map(scopeWord).join(" ");
|
|
6344
|
+
return [name, ...scan.operands.slice(0, SCOPE_LEAD_ARGS)].join(" ");
|
|
6345
|
+
}
|
|
6346
|
+
function scopeWord(word) {
|
|
6347
|
+
return word === "" || /[\s"'\\]/.test(word) ? JSON.stringify(word) : word;
|
|
6348
|
+
}
|
|
6252
6349
|
function climbsByGlob(seg) {
|
|
6253
6350
|
if (!seg.globbed) return false;
|
|
6254
6351
|
const patterns = patternArgs(seg);
|
|
@@ -6270,6 +6367,27 @@ function swallowsRefName(arg) {
|
|
|
6270
6367
|
const values = FLAG_POLICY.git.values ?? [];
|
|
6271
6368
|
return [...arg.slice(1)].some((c) => c !== "n" && values.includes(`-${c}`));
|
|
6272
6369
|
}
|
|
6370
|
+
function gitArgsAfterSubcommand(seg) {
|
|
6371
|
+
const at = scanFlags(seg)?.operandAt[0];
|
|
6372
|
+
return at === void 0 ? [] : seg.args.slice(at + 1);
|
|
6373
|
+
}
|
|
6374
|
+
var REMOTE_NAME = /^[A-Za-z0-9_][A-Za-z0-9_.-]*$/;
|
|
6375
|
+
function namesConfiguredRemote(seg, after) {
|
|
6376
|
+
const destination2 = scanFlags({ ...seg, args: after })?.operands[0];
|
|
6377
|
+
return destination2 === void 0 || REMOTE_NAME.test(destination2);
|
|
6378
|
+
}
|
|
6379
|
+
function programName(binary) {
|
|
6380
|
+
return binary.toLowerCase().replace(/\.exe$/, "");
|
|
6381
|
+
}
|
|
6382
|
+
function isRemoteListing(seg) {
|
|
6383
|
+
const git2 = { ...seg, binary: programName(seg.binary) };
|
|
6384
|
+
return git2.binary === "git" && subcommandOf(git2) === "ls-remote";
|
|
6385
|
+
}
|
|
6386
|
+
function remoteListingTexts(seg) {
|
|
6387
|
+
if (!isRemoteListing(seg)) return [];
|
|
6388
|
+
const git2 = { ...seg, binary: "git" };
|
|
6389
|
+
return scanFlags({ ...git2, args: gitArgsAfterSubcommand(git2) })?.operands ?? [];
|
|
6390
|
+
}
|
|
6273
6391
|
function refusalFor(seg, trustedResolves) {
|
|
6274
6392
|
const web = webCommand(seg, trustedResolves);
|
|
6275
6393
|
if (web?.reason) return web.reason;
|
|
@@ -6307,8 +6425,24 @@ function refusalFor(seg, trustedResolves) {
|
|
|
6307
6425
|
}
|
|
6308
6426
|
if (seg.binary === "git") {
|
|
6309
6427
|
const sub = subcommandOf(seg);
|
|
6428
|
+
const after = gitArgsAfterSubcommand(seg);
|
|
6429
|
+
if (sub !== void 0 && !GIT_READONLY_SUBCOMMANDS.includes(sub)) {
|
|
6430
|
+
const reads = GIT_PROMPTABLE[sub];
|
|
6431
|
+
if (!reads) {
|
|
6432
|
+
return `"git ${sub}" is not a git subcommand known only to read, so it may write the repository. You are a read-only planner: ${EFFECT_ROUTE}`;
|
|
6433
|
+
}
|
|
6434
|
+
if (!reads(after)) {
|
|
6435
|
+
return `"git ${[sub, ...after].join(" ")}" is not a read-only form of "git ${sub}". You are a read-only planner: ${EFFECT_ROUTE}`;
|
|
6436
|
+
}
|
|
6437
|
+
}
|
|
6438
|
+
if (sub === "ls-remote" && !namesConfiguredRemote(seg, after)) {
|
|
6439
|
+
return `"git ls-remote" given a URL, an address or a path reaches it through git's own transport, which resolves the host itself and follows a redirect, so the origin approval, address guard and pinned connection a web read gets (ADR-0027) cannot hold for it. Name a remote the repository configures, such as "git ls-remote origin", or fetch the page with your web fetch tool.`;
|
|
6440
|
+
}
|
|
6441
|
+
if (sub === "ls-remote" && (seg.expandable || seg.globbed || after.some((a) => a.includes("~")))) {
|
|
6442
|
+
return `The shell rewrites part of this "git ls-remote" before git sees it (a variable, substitution, glob or "~"), so what it sends the remote, and which repository it lists, cannot be checked for a secret or approved. Write the remote and patterns literally, in single quotes where they hold a "*", and re-run.`;
|
|
6443
|
+
}
|
|
6310
6444
|
if (sub === "branch" || sub === "tag") {
|
|
6311
|
-
const flag2 = seg.args.find((a) => ["-D", "-d", "-m", "-M", "--delete", "--move"].includes(a)) ??
|
|
6445
|
+
const flag2 = seg.args.find((a) => ["-D", "-d", "-m", "-M", "--delete", "--move"].includes(a)) ?? after.find(swallowsRefName);
|
|
6312
6446
|
if (flag2) {
|
|
6313
6447
|
return `"git ${sub} ${flag2}" mutates refs. You are a read-only planner: ${EFFECT_ROUTE}`;
|
|
6314
6448
|
}
|
|
@@ -6447,10 +6581,10 @@ function classifyCommand(command, opts = {}) {
|
|
|
6447
6581
|
return { tier: "refuse", scope: "", reason: `curl and wget are refused in Full and allowlist mode. ${web.effect ? EFFECT_REFUSAL_HINT : READ_REFUSAL_HINT}` };
|
|
6448
6582
|
}
|
|
6449
6583
|
const allow = opts.allow;
|
|
6450
|
-
if (web && allow && web.urls.some((url) => scopeExcluded(allow, `${seg.binary
|
|
6584
|
+
if (web && allow && web.urls.some((url) => scopeExcluded(allow, `${programName(seg.binary)} ${url.origin}/*`))) {
|
|
6451
6585
|
return { tier: "refuse", scope: "", reason: `The web origin is excluded by the planner allowlist. ${READ_REFUSAL_HINT}` };
|
|
6452
6586
|
}
|
|
6453
|
-
const reason = refusalFor({ ...seg, binary: seg.binary
|
|
6587
|
+
const reason = refusalFor({ ...seg, binary: programName(seg.binary) }, opts.trustedWebResolves);
|
|
6454
6588
|
if (reason) return { tier: "refuse", scope: "", reason: withWrapperNote(reason, wrappers) };
|
|
6455
6589
|
if (runner && !XARGS_TARGETS.includes(seg.binary)) {
|
|
6456
6590
|
return {
|
|
@@ -6460,23 +6594,24 @@ function classifyCommand(command, opts = {}) {
|
|
|
6460
6594
|
};
|
|
6461
6595
|
}
|
|
6462
6596
|
}
|
|
6463
|
-
if (unwrapped.some(({ seg }) => seg.binary
|
|
6597
|
+
if (unwrapped.some(({ seg }) => programName(seg.binary) === "wget") && wgetVersionCommands(command, opts.dialect).includes(void 0)) {
|
|
6464
6598
|
return { tier: "refuse", scope: "", reason: `The wget executable cannot be checked safely in this working directory. ${READ_REFUSAL_HINT}` };
|
|
6465
6599
|
}
|
|
6466
6600
|
const nonAuto = unwrapped.filter((u) => u.runner !== void 0 || u.wrappers.some((w) => w !== w.toLowerCase()) || !isAuto(u.seg, opts));
|
|
6467
6601
|
if (nonAuto.length === 0) return { tier: "auto", scope: "" };
|
|
6602
|
+
const changesDirectory = unwrapped.some(({ seg }) => seg.binary.toLowerCase() === "cd");
|
|
6468
6603
|
const lineScoped = nonAuto.some((u) => {
|
|
6469
6604
|
const name = u.seg.binary.toLowerCase();
|
|
6470
|
-
return name === "cd" || name !== "command" && SHELL_STATE_COMMANDS.has(name) || climbsByGlob(u.seg);
|
|
6605
|
+
return name === "cd" || name !== "command" && SHELL_STATE_COMMANDS.has(name) || climbsByGlob(u.seg) || isRemoteListing(u.seg) && (changesDirectory || u.wrappers.length > 0 || nonAuto.length > 1);
|
|
6471
6606
|
});
|
|
6472
6607
|
const webUrls = nonAuto.flatMap((u) => webCommand(u.seg, opts.trustedWebResolves)?.urls ?? []);
|
|
6473
|
-
const
|
|
6608
|
+
const outboundTexts = nonAuto.flatMap((u) => webCommand(u.seg, opts.trustedWebResolves)?.outboundTexts ?? remoteListingTexts(u.seg));
|
|
6474
6609
|
if (lineScoped && webUrls.length === 0) {
|
|
6475
|
-
return { tier: "ask", scope: trimmed2 };
|
|
6610
|
+
return { tier: "ask", scope: trimmed2, ...outboundTexts.length ? { outboundTexts } : {} };
|
|
6476
6611
|
}
|
|
6477
6612
|
const scopes = [...new Set(nonAuto.flatMap((u) => {
|
|
6478
6613
|
const web = webCommand(u.seg, opts.trustedWebResolves);
|
|
6479
|
-
return web ? web.urls.map((url) => `${u.seg.binary
|
|
6614
|
+
return web ? web.urls.map((url) => `${programName(u.seg.binary)} ${url.origin}/*`) : [lineScoped ? trimmed2 : u.runner ? `${u.runner} ${scopeFor(u.seg)}` : scopeFor(u.seg)];
|
|
6480
6615
|
}))].sort();
|
|
6481
6616
|
const scope = scopes.join(" + ");
|
|
6482
6617
|
const perInvocation = nonAuto.some((u) => webCommand(u.seg, opts.trustedWebResolves)?.perInvocation);
|
|
@@ -6484,7 +6619,8 @@ function classifyCommand(command, opts = {}) {
|
|
|
6484
6619
|
return {
|
|
6485
6620
|
tier: "ask",
|
|
6486
6621
|
scope,
|
|
6487
|
-
...webUrls.length ? { webUrls
|
|
6622
|
+
...webUrls.length ? { webUrls } : {},
|
|
6623
|
+
...outboundTexts.length ? { outboundTexts } : {},
|
|
6488
6624
|
...scopes.length > 1 && webUrls.length ? { scopes } : {},
|
|
6489
6625
|
...perInvocation ? { perInvocation } : {},
|
|
6490
6626
|
...allowedBy ? { allowedBy } : {}
|
|
@@ -6628,9 +6764,9 @@ function summarizeToolCall(tool2, argsJson, toolLabel) {
|
|
|
6628
6764
|
const scope = args.include ? ` in ${args.include}` : "";
|
|
6629
6765
|
return `grep ${ellipsize(String(args.pattern), 40)}${scope}${mode}`;
|
|
6630
6766
|
}
|
|
6631
|
-
const
|
|
6632
|
-
if (
|
|
6633
|
-
const basename6 = String(
|
|
6767
|
+
const path48 = args.filePath || args.file_path || args.path;
|
|
6768
|
+
if (path48) {
|
|
6769
|
+
const basename6 = String(path48).split("/").pop() || String(path48);
|
|
6634
6770
|
return `${display} ${basename6}`;
|
|
6635
6771
|
}
|
|
6636
6772
|
if (args.pattern) {
|
|
@@ -8116,7 +8252,7 @@ ${TASK_CONTINUE}`);
|
|
|
8116
8252
|
command = disableWebCommandStartup(command, this.researchShell.dialect);
|
|
8117
8253
|
const { approval, root } = site;
|
|
8118
8254
|
const allow = approval.allowlist?.();
|
|
8119
|
-
const { tier, scope, reason, allowedBy, perInvocation, scopes: commandScopes, webUrls,
|
|
8255
|
+
const { tier, scope, reason, allowedBy, perInvocation, scopes: commandScopes, webUrls, outboundTexts } = classifyCommand(command, {
|
|
8120
8256
|
...this.policyOptions(),
|
|
8121
8257
|
...approval.commandPolicy?.(),
|
|
8122
8258
|
...allow ? { allow } : {}
|
|
@@ -8141,8 +8277,9 @@ ${TASK_CONTINUE}`);
|
|
|
8141
8277
|
if (site.task?.sealed) return this.runSealed(site, command, request, "after", signal);
|
|
8142
8278
|
if (tier === "refuse") return this.sealedInstead(site, command, request, refusal(`Command refused: ${reason}${site.task ? `
|
|
8143
8279
|
${TASK_UNSEALED} ${TASK_CONTINUE}` : ""}`), signal);
|
|
8144
|
-
|
|
8145
|
-
|
|
8280
|
+
const outbound = [...outboundTexts ?? [], ...(webUrls ?? []).map((url) => url.href)];
|
|
8281
|
+
if (outbound.length && carriesSecret(outbound, [...this.outboundSecrets(), ...sensitiveEnvValues(process.env)])) {
|
|
8282
|
+
return refusal(webUrls?.length ? "Command refused: a web command contains what looks like a secret. Fetch the page with your web fetch tool, without credentials." : "Command refused: what this command sends over the network contains what looks like a secret. Run it without the value.");
|
|
8146
8283
|
}
|
|
8147
8284
|
const vettedAddresses = /* @__PURE__ */ new Map();
|
|
8148
8285
|
for (const url of webUrls ?? []) {
|
|
@@ -8245,7 +8382,7 @@ ${outcome.output}${outcome.success ? "" : `
|
|
|
8245
8382
|
}
|
|
8246
8383
|
let shell;
|
|
8247
8384
|
try {
|
|
8248
|
-
const sealed2 = site.task?.gitBefore ? { ...site.sealed, gitEntries: site.task.gitBefore.entries.map(({ path:
|
|
8385
|
+
const sealed2 = site.task?.gitBefore ? { ...site.sealed, gitEntries: site.task.gitBefore.entries.map(({ path: path48, directory }) => ({ path: path48, directory })) } : site.sealed;
|
|
8249
8386
|
shell = await site.sandbox.launchSealed(this.researchShell, sealed2);
|
|
8250
8387
|
} catch (err) {
|
|
8251
8388
|
return { refused: refusal(`Command not run: its sealed sandbox could not be prepared (${err instanceof Error ? err.message : String(err)}).`) };
|
|
@@ -9794,8 +9931,8 @@ function firstLineOf(command) {
|
|
|
9794
9931
|
function text(value) {
|
|
9795
9932
|
return typeof value === "string" ? value : "";
|
|
9796
9933
|
}
|
|
9797
|
-
function searchArg(pattern,
|
|
9798
|
-
return `${pattern}${
|
|
9934
|
+
function searchArg(pattern, path48, include = "") {
|
|
9935
|
+
return `${pattern}${path48 ? ` in ${path48}` : ""}${include ? ` (${include})` : ""}`;
|
|
9799
9936
|
}
|
|
9800
9937
|
function hintArg(args) {
|
|
9801
9938
|
for (const field of HINT_FIELDS) {
|
|
@@ -9900,8 +10037,8 @@ function userMessage(id2, text6, skills, { turnId, forced } = {}) {
|
|
|
9900
10037
|
...forced ? { forced: true } : {}
|
|
9901
10038
|
};
|
|
9902
10039
|
}
|
|
9903
|
-
function skillLoadNotice({ invokedBy, name, source, path:
|
|
9904
|
-
return { invokedBy, name, source, path:
|
|
10040
|
+
function skillLoadNotice({ invokedBy, name, source, path: path48, attaches }) {
|
|
10041
|
+
return { invokedBy, name, source, path: path48, ...attaches ? { attaches } : {} };
|
|
9905
10042
|
}
|
|
9906
10043
|
var LOAD_SKILL_TOOL = /(?:^|_)load_skill$/;
|
|
9907
10044
|
function surfaceStep(step) {
|
|
@@ -9918,8 +10055,8 @@ function loadedSkillName(args) {
|
|
|
9918
10055
|
return void 0;
|
|
9919
10056
|
}
|
|
9920
10057
|
}
|
|
9921
|
-
function skillLoadBlock(id2, { invokedBy, name, source, path:
|
|
9922
|
-
return { type: "skill_load", id: id2, invokedBy, name, source, path:
|
|
10058
|
+
function skillLoadBlock(id2, { invokedBy, name, source, path: path48, attaches }, turnId) {
|
|
10059
|
+
return { type: "skill_load", id: id2, invokedBy, name, source, path: path48, ...attaches ? { attaches } : {}, ...turnId ? { turnId } : {} };
|
|
9923
10060
|
}
|
|
9924
10061
|
function subagentBlock(id2, { toolCallId, model, usage, turnId, ...fields }) {
|
|
9925
10062
|
return {
|
|
@@ -10693,6 +10830,7 @@ function enabledRunners(cfg) {
|
|
|
10693
10830
|
}
|
|
10694
10831
|
|
|
10695
10832
|
// src/plugins/builtin/claudeModels.ts
|
|
10833
|
+
var path13 = __toESM(require("path"));
|
|
10696
10834
|
var ANTHROPIC_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
10697
10835
|
var ANTHROPIC_VARIANT_LABELS = {
|
|
10698
10836
|
adaptive: "Adaptive",
|
|
@@ -10786,6 +10924,53 @@ function parseClaudeHelp(stdout) {
|
|
|
10786
10924
|
}
|
|
10787
10925
|
return models;
|
|
10788
10926
|
}
|
|
10927
|
+
function claudeConfigDir(env) {
|
|
10928
|
+
return env.CLAUDE_CONFIG_DIR?.trim() || "~/.claude";
|
|
10929
|
+
}
|
|
10930
|
+
function claudeManagedSettingsDir(platform = process.platform) {
|
|
10931
|
+
if (platform === "darwin") return "/Library/Application Support/ClaudeCode";
|
|
10932
|
+
if (platform === "win32") return "C:\\Program Files\\ClaudeCode";
|
|
10933
|
+
return "/etc/claude-code";
|
|
10934
|
+
}
|
|
10935
|
+
function readClaudeSettingsModels(files, platform = process.platform) {
|
|
10936
|
+
const managed = claudeManagedSettingsDir(platform);
|
|
10937
|
+
const join44 = platform === "win32" ? path13.win32.join : path13.posix.join;
|
|
10938
|
+
const dropIns = files.list(join44(managed, "managed-settings.d")).filter((name) => name.endsWith(".json") && !name.startsWith(".")).sort().map((name) => join44(managed, "managed-settings.d", name));
|
|
10939
|
+
const ranked = [...dropIns.reverse(), join44(managed, "managed-settings.json"), join44(claudeConfigDir(files.env), "settings.json")];
|
|
10940
|
+
for (const file of ranked) {
|
|
10941
|
+
const content = files.read(file);
|
|
10942
|
+
const lineup = content === null ? null : parseClaudeSettingsModels(content);
|
|
10943
|
+
if (lineup) return lineup;
|
|
10944
|
+
}
|
|
10945
|
+
return [];
|
|
10946
|
+
}
|
|
10947
|
+
function parseClaudeSettingsModels(content) {
|
|
10948
|
+
let parsed;
|
|
10949
|
+
try {
|
|
10950
|
+
parsed = JSON.parse(content);
|
|
10951
|
+
} catch {
|
|
10952
|
+
return null;
|
|
10953
|
+
}
|
|
10954
|
+
const picker = parsed && typeof parsed === "object" ? parsed.modelPicker : void 0;
|
|
10955
|
+
const options = picker && typeof picker === "object" ? picker.options : void 0;
|
|
10956
|
+
if (!Array.isArray(options)) return null;
|
|
10957
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10958
|
+
const models = [];
|
|
10959
|
+
for (const row of options) {
|
|
10960
|
+
if (!row || typeof row !== "object") continue;
|
|
10961
|
+
const { model: raw, label } = row;
|
|
10962
|
+
const model = typeof raw === "string" ? raw.trim() : "";
|
|
10963
|
+
if (!model || seen.has(model)) continue;
|
|
10964
|
+
seen.add(model);
|
|
10965
|
+
models.push({
|
|
10966
|
+
modelId: model,
|
|
10967
|
+
modelLabel: typeof label === "string" && label.trim() ? label.trim() : model,
|
|
10968
|
+
runnerProvider: model.includes("/") ? model.split("/")[0] : void 0,
|
|
10969
|
+
variants: []
|
|
10970
|
+
});
|
|
10971
|
+
}
|
|
10972
|
+
return models;
|
|
10973
|
+
}
|
|
10789
10974
|
|
|
10790
10975
|
// src/plugins/builtin/claude-code.manifest.ts
|
|
10791
10976
|
var TURN_NOT_LOGGED_IN = /not logged in\s*·\s*please run \/login/i;
|
|
@@ -10824,18 +11009,24 @@ var CLAUDE_CODE_MANIFEST = {
|
|
|
10824
11009
|
// 3. canonicalAliases — stable --model contracts (opus/sonnet/haiku/fable)
|
|
10825
11010
|
// merged into any successful result to fill gaps, and used as the full
|
|
10826
11011
|
// last-resort list when both API and CLI are unavailable.
|
|
11012
|
+
//
|
|
11013
|
+
// Whichever source answers, the models the user added to Claude's own
|
|
11014
|
+
// picker (`modelPicker.options` in its managed or user settings, usually
|
|
11015
|
+
// gateway IDs) are appended (settingsModels): the CLI accepts them as
|
|
11016
|
+
// `--model` values though no catalog above lists them.
|
|
10827
11017
|
apiDiscovery: {
|
|
10828
11018
|
url: "https://api.anthropic.com/v1/models?limit=100",
|
|
10829
11019
|
headers: { "anthropic-version": "2023-06-01" },
|
|
10830
11020
|
auth: [
|
|
10831
11021
|
{ type: "env", varName: "ANTHROPIC_API_KEY", header: "X-Api-Key" },
|
|
10832
|
-
{ type: "file", path:
|
|
11022
|
+
{ type: "file", path: (env) => `${claudeConfigDir(env)}/.credentials.json`, jsonPath: "claudeAiOauth.accessToken", header: "Authorization", prefix: "Bearer " }
|
|
10833
11023
|
],
|
|
10834
11024
|
parser: parseAnthropicModels
|
|
10835
11025
|
},
|
|
10836
11026
|
discoveryCommands: [
|
|
10837
11027
|
{ command: "claude", args: ["--help"], parser: parseClaudeHelp }
|
|
10838
11028
|
],
|
|
11029
|
+
settingsModels: (files) => readClaudeSettingsModels(files),
|
|
10839
11030
|
canonicalAliases: [
|
|
10840
11031
|
{ modelId: "opus", modelLabel: "Opus" },
|
|
10841
11032
|
{ modelId: "sonnet", modelLabel: "Sonnet" },
|
|
@@ -10893,7 +11084,7 @@ var import_path5 = require("path");
|
|
|
10893
11084
|
|
|
10894
11085
|
// src/services/harness/repoConfig.ts
|
|
10895
11086
|
var import_fs6 = require("fs");
|
|
10896
|
-
var
|
|
11087
|
+
var path14 = __toESM(require("path"));
|
|
10897
11088
|
|
|
10898
11089
|
// src/services/mcp/OrdewellMcpServer.ts
|
|
10899
11090
|
var import_http = require("http");
|
|
@@ -11857,12 +12048,12 @@ function checkpointReply(answer2) {
|
|
|
11857
12048
|
return { text: `The checkpoint was withdrawn: ${answer2.why}`, isError: true };
|
|
11858
12049
|
}
|
|
11859
12050
|
}
|
|
11860
|
-
function fieldPath(
|
|
11861
|
-
return
|
|
12051
|
+
function fieldPath(path48) {
|
|
12052
|
+
return path48.reduce((text6, part) => typeof part === "number" ? `${text6}[${part}]` : text6 ? `${text6}.${String(part)}` : String(part), "");
|
|
11862
12053
|
}
|
|
11863
|
-
function valueAt(value,
|
|
12054
|
+
function valueAt(value, path48) {
|
|
11864
12055
|
let current = value;
|
|
11865
|
-
for (const part of
|
|
12056
|
+
for (const part of path48) {
|
|
11866
12057
|
if (typeof part === "number") {
|
|
11867
12058
|
if (!Array.isArray(current)) return void 0;
|
|
11868
12059
|
current = current[part];
|
|
@@ -11884,7 +12075,7 @@ function boundedRefusal(issue, args) {
|
|
|
11884
12075
|
var LEAKED_PARAMETER = /<\/parameter>|<parameter\s+name\s*=\s*"([^"]*)">/g;
|
|
11885
12076
|
function leakedMarkupIn(value) {
|
|
11886
12077
|
const found = [];
|
|
11887
|
-
const walk = (node,
|
|
12078
|
+
const walk = (node, path48) => {
|
|
11888
12079
|
if (typeof node === "string") {
|
|
11889
12080
|
const names = [];
|
|
11890
12081
|
let closing = false;
|
|
@@ -11892,25 +12083,25 @@ function leakedMarkupIn(value) {
|
|
|
11892
12083
|
if (match[1] !== void 0) names.push(match[1]);
|
|
11893
12084
|
else closing = true;
|
|
11894
12085
|
}
|
|
11895
|
-
if (names.length > 0 || closing) found.push({ path:
|
|
12086
|
+
if (names.length > 0 || closing) found.push({ path: path48, names: [...new Set(names)], closing });
|
|
11896
12087
|
return;
|
|
11897
12088
|
}
|
|
11898
12089
|
if (Array.isArray(node)) {
|
|
11899
|
-
node.forEach((item, i) => walk(item, `${
|
|
12090
|
+
node.forEach((item, i) => walk(item, `${path48}[${i}]`));
|
|
11900
12091
|
return;
|
|
11901
12092
|
}
|
|
11902
12093
|
if (node !== null && typeof node === "object") {
|
|
11903
|
-
for (const [key, item] of Object.entries(node)) walk(item,
|
|
12094
|
+
for (const [key, item] of Object.entries(node)) walk(item, path48 ? `${path48}.${key}` : key);
|
|
11904
12095
|
}
|
|
11905
12096
|
};
|
|
11906
12097
|
walk(value, "");
|
|
11907
12098
|
return found;
|
|
11908
12099
|
}
|
|
11909
12100
|
function markupRefusal(leaks) {
|
|
11910
|
-
return leaks.map(({ path:
|
|
12101
|
+
return leaks.map(({ path: path48, names, closing }) => {
|
|
11911
12102
|
const tags = [...names.map((n) => `<parameter name="${n}">`), ...closing ? ["</parameter>"] : []];
|
|
11912
|
-
const guide = names.length > 0 ? ` The parameters ${names.map((n) => JSON.stringify(n)).join(", ")} are inside it; pass them as separate arguments, not inside ${
|
|
11913
|
-
return `${
|
|
12103
|
+
const guide = names.length > 0 ? ` The parameters ${names.map((n) => JSON.stringify(n)).join(", ")} are inside it; pass them as separate arguments, not inside ${path48}.` : " Pass each argument separately, not inside one string.";
|
|
12104
|
+
return `${path48} contains leaked tool-call markup: ${tags.join(", ")}.${guide}`;
|
|
11914
12105
|
}).join("\n");
|
|
11915
12106
|
}
|
|
11916
12107
|
function invalidArguments(name, error, args) {
|
|
@@ -12375,9 +12566,9 @@ function mcpClientConfig(credential) {
|
|
|
12375
12566
|
}
|
|
12376
12567
|
function ownerOnlyConfigFile(fileName, contents) {
|
|
12377
12568
|
const dir = (0, import_fs5.mkdtempSync)((0, import_path4.join)((0, import_os.tmpdir)(), "ordewell-mcp-"));
|
|
12378
|
-
const
|
|
12379
|
-
(0, import_fs5.writeFileSync)(
|
|
12380
|
-
return { path:
|
|
12569
|
+
const path48 = (0, import_path4.join)(dir, fileName);
|
|
12570
|
+
(0, import_fs5.writeFileSync)(path48, contents, { mode: 384 });
|
|
12571
|
+
return { path: path48, remove: () => (0, import_fs5.rmSync)(dir, { recursive: true, force: true }) };
|
|
12381
12572
|
}
|
|
12382
12573
|
|
|
12383
12574
|
// src/services/harness/repoConfig.ts
|
|
@@ -12400,19 +12591,19 @@ function onDisk(target) {
|
|
|
12400
12591
|
try {
|
|
12401
12592
|
return import_fs6.realpathSync.native(target);
|
|
12402
12593
|
} catch {
|
|
12403
|
-
return
|
|
12594
|
+
return path14.resolve(target);
|
|
12404
12595
|
}
|
|
12405
12596
|
}
|
|
12406
12597
|
function insideOnDisk(root, target) {
|
|
12407
|
-
const rel =
|
|
12408
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
12598
|
+
const rel = path14.relative(onDisk(root), onDisk(target));
|
|
12599
|
+
return rel === "" || !rel.startsWith("..") && !path14.isAbsolute(rel);
|
|
12409
12600
|
}
|
|
12410
12601
|
function repoLevels(workspace) {
|
|
12411
12602
|
const levels = [];
|
|
12412
|
-
for (let dir =
|
|
12603
|
+
for (let dir = path14.resolve(workspace); ; dir = path14.dirname(dir)) {
|
|
12413
12604
|
levels.unshift(dir);
|
|
12414
|
-
if ((0, import_fs6.existsSync)(
|
|
12415
|
-
if (
|
|
12605
|
+
if ((0, import_fs6.existsSync)(path14.join(dir, ".git"))) return levels;
|
|
12606
|
+
if (path14.dirname(dir) === dir) return [path14.resolve(workspace)];
|
|
12416
12607
|
}
|
|
12417
12608
|
}
|
|
12418
12609
|
function repoRoot(workspace) {
|
|
@@ -12506,33 +12697,33 @@ var TomlReader = class {
|
|
|
12506
12697
|
if (this.i >= this.src.length) return root;
|
|
12507
12698
|
if (this.src.startsWith("[[", this.i)) {
|
|
12508
12699
|
this.i += 2;
|
|
12509
|
-
const
|
|
12700
|
+
const path48 = this.key();
|
|
12510
12701
|
this.expect("]]");
|
|
12511
|
-
const parent = this.tableAt(root,
|
|
12512
|
-
const last =
|
|
12702
|
+
const parent = this.tableAt(root, path48.slice(0, -1));
|
|
12703
|
+
const last = path48[path48.length - 1];
|
|
12513
12704
|
const list = Object.hasOwn(parent, last) ? parent[last] : parent[last] = [];
|
|
12514
|
-
if (!Array.isArray(list)) throw this.fail(`${
|
|
12705
|
+
if (!Array.isArray(list)) throw this.fail(`${path48.join(".")} is not an array of tables`);
|
|
12515
12706
|
table = newTable();
|
|
12516
12707
|
list.push(table);
|
|
12517
12708
|
} else if (this.src[this.i] === "[") {
|
|
12518
12709
|
this.i += 1;
|
|
12519
|
-
const
|
|
12710
|
+
const path48 = this.key();
|
|
12520
12711
|
this.expect("]");
|
|
12521
|
-
table = this.tableAt(root,
|
|
12712
|
+
table = this.tableAt(root, path48);
|
|
12522
12713
|
} else {
|
|
12523
|
-
const
|
|
12714
|
+
const path48 = this.key();
|
|
12524
12715
|
this.skipBlank(false);
|
|
12525
12716
|
this.expect("=");
|
|
12526
12717
|
this.skipBlank(false);
|
|
12527
|
-
const owner = this.tableAt(table,
|
|
12528
|
-
owner[
|
|
12718
|
+
const owner = this.tableAt(table, path48.slice(0, -1));
|
|
12719
|
+
owner[path48[path48.length - 1]] = this.value();
|
|
12529
12720
|
}
|
|
12530
12721
|
this.endOfLine();
|
|
12531
12722
|
}
|
|
12532
12723
|
}
|
|
12533
|
-
tableAt(from,
|
|
12724
|
+
tableAt(from, path48) {
|
|
12534
12725
|
let table = from;
|
|
12535
|
-
for (const part of
|
|
12726
|
+
for (const part of path48) {
|
|
12536
12727
|
const next = Object.hasOwn(table, part) ? table[part] : void 0;
|
|
12537
12728
|
if (next === void 0) table = table[part] = newTable();
|
|
12538
12729
|
else if (isRecord2(next)) table = next;
|
|
@@ -12601,10 +12792,10 @@ var TomlReader = class {
|
|
|
12601
12792
|
this.i++;
|
|
12602
12793
|
return table;
|
|
12603
12794
|
}
|
|
12604
|
-
const
|
|
12795
|
+
const path48 = this.key();
|
|
12605
12796
|
this.expect("=");
|
|
12606
12797
|
this.skipBlank(false);
|
|
12607
|
-
this.tableAt(table,
|
|
12798
|
+
this.tableAt(table, path48.slice(0, -1))[path48[path48.length - 1]] = this.value();
|
|
12608
12799
|
this.skipBlank(true);
|
|
12609
12800
|
if (this.src[this.i] === ",") this.i++;
|
|
12610
12801
|
else if (this.src[this.i] !== "}") throw this.fail("expected , or } in an inline table");
|
|
@@ -12749,7 +12940,8 @@ var CODEX_MANIFEST = {
|
|
|
12749
12940
|
appServer: {
|
|
12750
12941
|
command: "codex",
|
|
12751
12942
|
args: ["app-server"],
|
|
12752
|
-
|
|
12943
|
+
// CODEX_HOME moves all of Codex's own files from `~/.codex`.
|
|
12944
|
+
cacheFile: (env) => `${env.CODEX_HOME?.trim() || "~/.codex"}/models_cache.json`
|
|
12753
12945
|
},
|
|
12754
12946
|
canonicalAliases: [
|
|
12755
12947
|
{ modelId: "gpt-5.6-sol", modelLabel: "GPT-5.6-Sol" },
|
|
@@ -12978,8 +13170,7 @@ var LineBuffer = class {
|
|
|
12978
13170
|
// src/services/harness/ClaudeCodeAdapter.ts
|
|
12979
13171
|
var import_crypto6 = require("crypto");
|
|
12980
13172
|
var import_fs11 = require("fs");
|
|
12981
|
-
var
|
|
12982
|
-
var path21 = __toESM(require("path"));
|
|
13173
|
+
var path22 = __toESM(require("path"));
|
|
12983
13174
|
|
|
12984
13175
|
// src/plugins/resolveArgs.ts
|
|
12985
13176
|
function claudeThinkingArgs(effort) {
|
|
@@ -13017,14 +13208,29 @@ function resolveTaskRunnerFlags(manifest, ctx) {
|
|
|
13017
13208
|
return flags;
|
|
13018
13209
|
}
|
|
13019
13210
|
|
|
13211
|
+
// src/utils/runnerHome.ts
|
|
13212
|
+
var os5 = __toESM(require("os"));
|
|
13213
|
+
function runnerHomeDir(env, platform = process.platform) {
|
|
13214
|
+
const name = platform === "win32" ? "USERPROFILE" : "HOME";
|
|
13215
|
+
const key = platform === "win32" ? Object.keys(env).filter((k) => k.toUpperCase() === name).pop() : name;
|
|
13216
|
+
const home = key === void 0 ? void 0 : env[key];
|
|
13217
|
+
return home ?? os5.homedir();
|
|
13218
|
+
}
|
|
13219
|
+
function expandRunnerHome(filePath, env = process.env) {
|
|
13220
|
+
if (!filePath.startsWith("~")) return filePath;
|
|
13221
|
+
const home = runnerHomeDir(env);
|
|
13222
|
+
return home ? home + filePath.slice(1) : null;
|
|
13223
|
+
}
|
|
13224
|
+
|
|
13020
13225
|
// src/services/harness/runnerProcess.ts
|
|
13226
|
+
var import_net = require("net");
|
|
13021
13227
|
var import_string_decoder = require("string_decoder");
|
|
13022
13228
|
|
|
13023
13229
|
// src/utils/shellPath.ts
|
|
13024
13230
|
var import_child_process3 = require("child_process");
|
|
13025
13231
|
var import_util = require("util");
|
|
13026
|
-
var
|
|
13027
|
-
var
|
|
13232
|
+
var os6 = __toESM(require("os"));
|
|
13233
|
+
var path15 = __toESM(require("path"));
|
|
13028
13234
|
var execAsync = (0, import_util.promisify)(import_child_process3.exec);
|
|
13029
13235
|
var LOGIN_SHELL_TIMEOUT_MS = 5e3;
|
|
13030
13236
|
var PATH_MARKER = "__ORDEWELL_PATH__";
|
|
@@ -13033,21 +13239,21 @@ var defaultExec = async (command, options) => {
|
|
|
13033
13239
|
return { stdout: String(stdout) };
|
|
13034
13240
|
};
|
|
13035
13241
|
function posixBinDirs() {
|
|
13036
|
-
const home =
|
|
13242
|
+
const home = os6.homedir();
|
|
13037
13243
|
return [
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13244
|
+
path15.join(home, ".local", "bin"),
|
|
13245
|
+
path15.join(home, ".opencode", "bin"),
|
|
13246
|
+
path15.join(home, ".claude", "bin"),
|
|
13247
|
+
path15.join(home, ".bun", "bin"),
|
|
13248
|
+
path15.join(home, ".volta", "bin"),
|
|
13249
|
+
path15.join(home, ".npm-global", "bin"),
|
|
13250
|
+
path15.join(home, "bin"),
|
|
13045
13251
|
"/usr/local/bin",
|
|
13046
13252
|
"/opt/homebrew/bin"
|
|
13047
13253
|
];
|
|
13048
13254
|
}
|
|
13049
13255
|
function windowsBinDirs(env, home) {
|
|
13050
|
-
const join44 = (...parts) =>
|
|
13256
|
+
const join44 = (...parts) => path15.win32.join(...parts);
|
|
13051
13257
|
const under = (base, ...parts) => base ? [join44(base, ...parts)] : [];
|
|
13052
13258
|
const appData = env.APPDATA;
|
|
13053
13259
|
const localAppData = env.LOCALAPPDATA;
|
|
@@ -13084,7 +13290,7 @@ function windowsBinDirs(env, home) {
|
|
|
13084
13290
|
function wellKnownBinDirs(deps = {}) {
|
|
13085
13291
|
const platform = deps.platform ?? process.platform;
|
|
13086
13292
|
if (platform !== "win32") return posixBinDirs();
|
|
13087
|
-
return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ??
|
|
13293
|
+
return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os6.homedir()))];
|
|
13088
13294
|
}
|
|
13089
13295
|
async function loginShellPath(execImpl) {
|
|
13090
13296
|
if (process.platform === "win32") return null;
|
|
@@ -13107,14 +13313,14 @@ function augmentedPath(execImpl = defaultExec) {
|
|
|
13107
13313
|
const segments = [];
|
|
13108
13314
|
const push = (p) => {
|
|
13109
13315
|
if (!p) return;
|
|
13110
|
-
for (const seg of p.split(
|
|
13316
|
+
for (const seg of p.split(path15.delimiter)) {
|
|
13111
13317
|
if (seg && !segments.includes(seg)) segments.push(seg);
|
|
13112
13318
|
}
|
|
13113
13319
|
};
|
|
13114
13320
|
push(process.env.PATH);
|
|
13115
13321
|
push(await loginShellPath(execImpl));
|
|
13116
13322
|
for (const dir of wellKnownBinDirs()) push(dir);
|
|
13117
|
-
return segments.join(
|
|
13323
|
+
return segments.join(path15.delimiter);
|
|
13118
13324
|
})();
|
|
13119
13325
|
}
|
|
13120
13326
|
return cachedPath;
|
|
@@ -13136,7 +13342,7 @@ function withPath(base, resolvedPath, overrides = {}) {
|
|
|
13136
13342
|
|
|
13137
13343
|
// src/utils/launch.ts
|
|
13138
13344
|
var fsSync4 = __toESM(require("fs"));
|
|
13139
|
-
var
|
|
13345
|
+
var path16 = __toESM(require("path"));
|
|
13140
13346
|
var DIRECT_EXTENSIONS = [".exe", ".com"];
|
|
13141
13347
|
var BATCH_EXTENSIONS = [".cmd", ".bat"];
|
|
13142
13348
|
var POWERSHELL_EXTENSIONS = [".ps1"];
|
|
@@ -13144,7 +13350,7 @@ var CMD_EXE_MAX_COMMAND_LINE = 8191;
|
|
|
13144
13350
|
var WINDOWS_MAX_COMMAND_LINE = 32767;
|
|
13145
13351
|
function defaultPowerShell() {
|
|
13146
13352
|
const root = process.env.SystemRoot || process.env.windir;
|
|
13147
|
-
return root ?
|
|
13353
|
+
return root ? path16.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "powershell.exe";
|
|
13148
13354
|
}
|
|
13149
13355
|
var POWERSHELL_FLAGS = ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File"];
|
|
13150
13356
|
var CommandLineTooLongError = class extends Error {
|
|
@@ -13210,7 +13416,7 @@ Searched: ${searchedPath || "(empty PATH)"}`);
|
|
|
13210
13416
|
};
|
|
13211
13417
|
function isResolvableOnPosixPath(command, PATH, exists) {
|
|
13212
13418
|
if (command.includes("/")) return exists(command);
|
|
13213
|
-
return PATH.split(
|
|
13419
|
+
return PATH.split(path16.delimiter).map((d) => d.trim()).filter(Boolean).some((dir) => exists(path16.join(dir, command)));
|
|
13214
13420
|
}
|
|
13215
13421
|
function isExecutableResolved(command, plan, PATH, deps = {}) {
|
|
13216
13422
|
if ((deps.platform ?? process.platform) === "win32") return plan.file !== command;
|
|
@@ -13250,9 +13456,9 @@ function cmdArgs(line) {
|
|
|
13250
13456
|
return ["/d", "/s", "/c", `"${line}"`];
|
|
13251
13457
|
}
|
|
13252
13458
|
function candidateExtensions(command, pathExt) {
|
|
13253
|
-
const declared = pathExt.split(
|
|
13459
|
+
const declared = pathExt.split(path16.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);
|
|
13254
13460
|
const known = /* @__PURE__ */ new Set([...DIRECT_EXTENSIONS, ...BATCH_EXTENSIONS, ...POWERSHELL_EXTENSIONS, ...declared]);
|
|
13255
|
-
const ext =
|
|
13461
|
+
const ext = path16.win32.extname(command).toLowerCase();
|
|
13256
13462
|
if (ext && known.has(ext)) {
|
|
13257
13463
|
const route = BATCH_EXTENSIONS.includes(ext) ? "cmd" : POWERSHELL_EXTENSIONS.includes(ext) ? "powershell" : "direct";
|
|
13258
13464
|
return { direct: [], cmd: [], powershell: [], [route]: [""] };
|
|
@@ -13273,13 +13479,13 @@ async function findWindowsExecutables(command, deps) {
|
|
|
13273
13479
|
const exists = deps.exists ?? defaultExists3;
|
|
13274
13480
|
const pathExt = (deps.pathExt ?? (() => process.env.PATHEXT ?? ""))();
|
|
13275
13481
|
const byRoute = candidateExtensions(command, pathExt);
|
|
13276
|
-
const dirs =
|
|
13277
|
-
const base =
|
|
13482
|
+
const dirs = path16.win32.basename(command) !== command ? [path16.win32.dirname(path16.win32.resolve(command))] : (await (deps.resolvePath ?? augmentedPath)() || "").split(path16.win32.delimiter).map((d) => d.trim().replace(/^"|"$/g, "")).filter(Boolean);
|
|
13483
|
+
const base = path16.win32.basename(command);
|
|
13278
13484
|
const found = [];
|
|
13279
13485
|
for (const route of ROUTES) {
|
|
13280
13486
|
outer: for (const ext of byRoute[route]) {
|
|
13281
13487
|
for (const dir of dirs) {
|
|
13282
|
-
const candidate =
|
|
13488
|
+
const candidate = path16.win32.join(dir, `${base}${ext}`);
|
|
13283
13489
|
if (exists(candidate)) {
|
|
13284
13490
|
found.push({ file: candidate, route });
|
|
13285
13491
|
break outer;
|
|
@@ -13327,7 +13533,7 @@ async function planDirectLaunch(command, args, deps = {}) {
|
|
|
13327
13533
|
|
|
13328
13534
|
// src/utils/workspace.ts
|
|
13329
13535
|
var fs3 = __toESM(require("fs"));
|
|
13330
|
-
var
|
|
13536
|
+
var path17 = __toESM(require("path"));
|
|
13331
13537
|
var WorkspaceNotFoundError = class extends Error {
|
|
13332
13538
|
constructor(workspace) {
|
|
13333
13539
|
super(`Workspace "${workspace}" does not exist.`);
|
|
@@ -13383,7 +13589,7 @@ function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
|
13383
13589
|
throw new WorkspaceNotAProjectError(workspace);
|
|
13384
13590
|
}
|
|
13385
13591
|
const hasMarker = [...PROJECT_MARKER_DIRS, ...PROJECT_MARKER_FILES].some(
|
|
13386
|
-
(marker2) => exists(
|
|
13592
|
+
(marker2) => exists(path17.join(resolved, marker2))
|
|
13387
13593
|
);
|
|
13388
13594
|
if (!hasMarker) throw new WorkspaceNotAProjectError(workspace);
|
|
13389
13595
|
}
|
|
@@ -13391,12 +13597,12 @@ function assertWorkspaceIsProject(workspace, deps = {}) {
|
|
|
13391
13597
|
// src/services/workspaceEnv.ts
|
|
13392
13598
|
var import_child_process4 = require("child_process");
|
|
13393
13599
|
var fs5 = __toESM(require("fs"));
|
|
13394
|
-
var
|
|
13395
|
-
var
|
|
13600
|
+
var os7 = __toESM(require("os"));
|
|
13601
|
+
var path19 = __toESM(require("path"));
|
|
13396
13602
|
|
|
13397
13603
|
// src/utils/fsHelpers.ts
|
|
13398
13604
|
var fs4 = __toESM(require("fs"));
|
|
13399
|
-
var
|
|
13605
|
+
var path18 = __toESM(require("path"));
|
|
13400
13606
|
var import_crypto5 = require("crypto");
|
|
13401
13607
|
var STATE_DIR = ".ordewell";
|
|
13402
13608
|
function ensureDir(dir) {
|
|
@@ -13405,9 +13611,9 @@ function ensureDir(dir) {
|
|
|
13405
13611
|
}
|
|
13406
13612
|
}
|
|
13407
13613
|
function writeFileAtomic(filePath, content) {
|
|
13408
|
-
const dir =
|
|
13614
|
+
const dir = path18.dirname(filePath);
|
|
13409
13615
|
ensureDir(dir);
|
|
13410
|
-
const tempPath =
|
|
13616
|
+
const tempPath = path18.join(dir, `.${path18.basename(filePath)}.${(0, import_crypto5.randomUUID)()}.tmp`);
|
|
13411
13617
|
fs4.writeFileSync(tempPath, content, { flag: "wx" });
|
|
13412
13618
|
try {
|
|
13413
13619
|
fs4.renameSync(tempPath, filePath);
|
|
@@ -13420,7 +13626,7 @@ function writeFileAtomic(filePath, content) {
|
|
|
13420
13626
|
}
|
|
13421
13627
|
}
|
|
13422
13628
|
function getStateDir(baseDir) {
|
|
13423
|
-
return
|
|
13629
|
+
return path18.join(baseDir ?? process.cwd(), STATE_DIR);
|
|
13424
13630
|
}
|
|
13425
13631
|
var IGNORE_FILE = ".gitignore";
|
|
13426
13632
|
var STATE_DIR_IGNORE = "*\n!.gitignore\n!skills/\n!skills/**\n";
|
|
@@ -13428,7 +13634,7 @@ var LEGACY_IGNORES = /* @__PURE__ */ new Set(["*", "*\n"]);
|
|
|
13428
13634
|
function ensureStateDirIgnored(baseDir) {
|
|
13429
13635
|
const dir = getStateDir(baseDir);
|
|
13430
13636
|
ensureDir(dir);
|
|
13431
|
-
const file =
|
|
13637
|
+
const file = path18.join(dir, IGNORE_FILE);
|
|
13432
13638
|
try {
|
|
13433
13639
|
fs4.writeFileSync(file, STATE_DIR_IGNORE, { flag: "wx" });
|
|
13434
13640
|
return;
|
|
@@ -13963,7 +14169,7 @@ function defaultDeps() {
|
|
|
13963
14169
|
}
|
|
13964
14170
|
},
|
|
13965
14171
|
baseEnv: process.env,
|
|
13966
|
-
home:
|
|
14172
|
+
home: os7.homedir()
|
|
13967
14173
|
};
|
|
13968
14174
|
}
|
|
13969
14175
|
var REFUSED2 = new Set(SETTINGS_ENV_REFUSED);
|
|
@@ -13975,7 +14181,7 @@ async function resolveWorkspaceEnv(cwd, overrides = {}) {
|
|
|
13975
14181
|
const direnv = await fromDirenv(checkoutDirOf(cwd, deps), deps);
|
|
13976
14182
|
result.blockedEnvrc = direnv.blocked;
|
|
13977
14183
|
Object.assign(collected, direnv.env);
|
|
13978
|
-
const file = findUp(cwd,
|
|
14184
|
+
const file = findUp(cwd, path19.join(STATE_DIR, WORKSPACE_ENV_FILE), deps);
|
|
13979
14185
|
if (file) {
|
|
13980
14186
|
const content = deps.readFile(file);
|
|
13981
14187
|
if (content !== null) {
|
|
@@ -13992,7 +14198,7 @@ async function resolveWorkspaceEnv(cwd, overrides = {}) {
|
|
|
13992
14198
|
}
|
|
13993
14199
|
var evaluating = /* @__PURE__ */ new Map();
|
|
13994
14200
|
async function workspaceEnvOf(cwd) {
|
|
13995
|
-
const key =
|
|
14201
|
+
const key = path19.resolve(cwd);
|
|
13996
14202
|
let running2 = evaluating.get(key);
|
|
13997
14203
|
if (!running2) {
|
|
13998
14204
|
running2 = resolveWorkspaceEnv(cwd).then((result) => result.env).finally(() => evaluating.delete(key));
|
|
@@ -14001,11 +14207,11 @@ async function workspaceEnvOf(cwd) {
|
|
|
14001
14207
|
return { ...await running2 };
|
|
14002
14208
|
}
|
|
14003
14209
|
function checkoutDirOf(cwd, deps) {
|
|
14004
|
-
const parts =
|
|
14210
|
+
const parts = path19.resolve(cwd).split(path19.sep);
|
|
14005
14211
|
const at = parts.findIndex((part, i) => part === STATE_DIR && parts[i + 1] === "worktrees");
|
|
14006
14212
|
if (at < 0 || parts.length < at + 4) return cwd;
|
|
14007
|
-
const root = parts.slice(0, at).join(
|
|
14008
|
-
const mapped =
|
|
14213
|
+
const root = parts.slice(0, at).join(path19.sep) || path19.sep;
|
|
14214
|
+
const mapped = path19.join(root, ...parts.slice(at + 4));
|
|
14009
14215
|
return deps.isDirectory(mapped) ? mapped : root;
|
|
14010
14216
|
}
|
|
14011
14217
|
async function fromDirenv(cwd, deps) {
|
|
@@ -14035,18 +14241,18 @@ async function fromDirenv(cwd, deps) {
|
|
|
14035
14241
|
return { env, blocked: null };
|
|
14036
14242
|
}
|
|
14037
14243
|
function findUp(start, relative17, deps) {
|
|
14038
|
-
let dir =
|
|
14244
|
+
let dir = path19.resolve(start);
|
|
14039
14245
|
for (; ; ) {
|
|
14040
|
-
const candidate =
|
|
14246
|
+
const candidate = path19.join(dir, relative17);
|
|
14041
14247
|
if (deps.readFile(candidate) !== null) return candidate;
|
|
14042
|
-
const parent =
|
|
14248
|
+
const parent = path19.dirname(dir);
|
|
14043
14249
|
if (parent === dir) return null;
|
|
14044
14250
|
dir = parent;
|
|
14045
14251
|
}
|
|
14046
14252
|
}
|
|
14047
14253
|
async function isTracked(file, deps) {
|
|
14048
14254
|
try {
|
|
14049
|
-
const out = await deps.run("git", ["ls-files", "--error-unmatch",
|
|
14255
|
+
const out = await deps.run("git", ["ls-files", "--error-unmatch", path19.basename(file)], { cwd: path19.dirname(file), env: deps.baseEnv });
|
|
14050
14256
|
return out.code === 0;
|
|
14051
14257
|
} catch {
|
|
14052
14258
|
return false;
|
|
@@ -14056,7 +14262,7 @@ function parseEnvFile(content, context, home) {
|
|
|
14056
14262
|
const env = {};
|
|
14057
14263
|
const lookup2 = (name) => env[name] ?? context[name] ?? "";
|
|
14058
14264
|
const expand = (value) => {
|
|
14059
|
-
const tilde = value.startsWith("~/") ?
|
|
14265
|
+
const tilde = value.startsWith("~/") ? path19.join(home, value.slice(2)) : value;
|
|
14060
14266
|
return tilde.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g, (_, braced, bare) => lookup2(braced ?? bare));
|
|
14061
14267
|
};
|
|
14062
14268
|
for (const raw of content.split(/\r?\n/)) {
|
|
@@ -14326,7 +14532,7 @@ function readOnlySessionRules(site) {
|
|
|
14326
14532
|
real = import_fs8.realpathSync.native(root);
|
|
14327
14533
|
} catch {
|
|
14328
14534
|
}
|
|
14329
|
-
for (const
|
|
14535
|
+
for (const path48 of /* @__PURE__ */ new Set([root, real])) rules.push({ action: "external_directory", resource: `${path48.replace(/[\\/]$/, "")}/*`, effect: "allow" });
|
|
14330
14536
|
}
|
|
14331
14537
|
return rules;
|
|
14332
14538
|
}
|
|
@@ -14452,6 +14658,14 @@ function runnerEnv(resolvedPath, workspace = {}, launch = {}, drop) {
|
|
|
14452
14658
|
// src/services/harness/runnerProcess.ts
|
|
14453
14659
|
var STDERR_TAIL_CHARS = 4e3;
|
|
14454
14660
|
var CLOSE_GRACE_MS = 2e3;
|
|
14661
|
+
function releasePipes(child) {
|
|
14662
|
+
for (const stream of [child.stdin, child.stdout, child.stderr]) {
|
|
14663
|
+
if (stream instanceof import_net.Socket) stream.unref();
|
|
14664
|
+
}
|
|
14665
|
+
for (const stream of [child.stdout, child.stderr]) {
|
|
14666
|
+
if (stream instanceof import_net.Socket) stream.resume();
|
|
14667
|
+
}
|
|
14668
|
+
}
|
|
14455
14669
|
var RunnerProcess = class {
|
|
14456
14670
|
constructor(deps) {
|
|
14457
14671
|
this.deps = deps;
|
|
@@ -14524,6 +14738,7 @@ var RunnerProcess = class {
|
|
|
14524
14738
|
const grace = setTimeout(() => {
|
|
14525
14739
|
for (const flush of [...this.stdoutEnds]) flush();
|
|
14526
14740
|
this.end({ code, signal });
|
|
14741
|
+
releasePipes(child);
|
|
14527
14742
|
}, CLOSE_GRACE_MS);
|
|
14528
14743
|
grace.unref?.();
|
|
14529
14744
|
void this.ended.then(() => clearTimeout(grace));
|
|
@@ -14622,11 +14837,11 @@ ${tail}` : ""}`;
|
|
|
14622
14837
|
|
|
14623
14838
|
// src/services/sandbox/nativeShellLauncher.ts
|
|
14624
14839
|
var import_fs9 = require("fs");
|
|
14625
|
-
var
|
|
14626
|
-
var
|
|
14840
|
+
var os8 = __toESM(require("os"));
|
|
14841
|
+
var path20 = __toESM(require("path"));
|
|
14627
14842
|
function nativeShellInvocation(platform, env = process.env) {
|
|
14628
14843
|
const shell = platform === "darwin" ? "/bin/zsh" : env.SHELL;
|
|
14629
|
-
return { shell: shell &&
|
|
14844
|
+
return { shell: shell && path20.posix.isAbsolute(shell) ? shell : "/bin/sh", args: ["-c"] };
|
|
14630
14845
|
}
|
|
14631
14846
|
var live = /* @__PURE__ */ new Set();
|
|
14632
14847
|
var exitHook = false;
|
|
@@ -14658,10 +14873,10 @@ function launcherScript(launch) {
|
|
|
14658
14873
|
}
|
|
14659
14874
|
async function createNativeShellLauncher(opts) {
|
|
14660
14875
|
const invocation = nativeShellInvocation(opts.platform ?? process.platform, opts.env);
|
|
14661
|
-
const root = (0, import_fs9.realpathSync)((0, import_fs9.mkdtempSync)(
|
|
14876
|
+
const root = (0, import_fs9.realpathSync)((0, import_fs9.mkdtempSync)(path20.join(os8.tmpdir(), "ordewell-native-shell-")));
|
|
14662
14877
|
let shortTmp = null;
|
|
14663
14878
|
try {
|
|
14664
|
-
shortTmp = (0, import_fs9.realpathSync)((0, import_fs9.mkdtempSync)(
|
|
14879
|
+
shortTmp = (0, import_fs9.realpathSync)((0, import_fs9.mkdtempSync)(path20.join("/tmp", "ow-")));
|
|
14665
14880
|
const tmpdir7 = shortTmp;
|
|
14666
14881
|
const launch = await opts.sandbox.launchNativeShell({
|
|
14667
14882
|
workspace: opts.workspace,
|
|
@@ -14670,7 +14885,7 @@ async function createNativeShellLauncher(opts) {
|
|
|
14670
14885
|
shellArgs: invocation.args,
|
|
14671
14886
|
...opts.env ? { env: opts.env } : {}
|
|
14672
14887
|
});
|
|
14673
|
-
const prefix =
|
|
14888
|
+
const prefix = path20.join(root, "run");
|
|
14674
14889
|
(0, import_fs9.writeFileSync)(prefix, launcherScript(launch), { mode: 448 });
|
|
14675
14890
|
(0, import_fs9.chmodSync)(prefix, 448);
|
|
14676
14891
|
keep(root);
|
|
@@ -15186,9 +15401,8 @@ var ReplyRuns = class {
|
|
|
15186
15401
|
};
|
|
15187
15402
|
|
|
15188
15403
|
// src/services/harness/claudeRepoConfig.ts
|
|
15189
|
-
var
|
|
15190
|
-
var
|
|
15191
|
-
var MEMORY_FILES = ["CLAUDE.md", path20.join(".claude", "CLAUDE.md"), "CLAUDE.local.md"];
|
|
15404
|
+
var path21 = __toESM(require("path"));
|
|
15405
|
+
var MEMORY_FILES = ["CLAUDE.md", path21.join(".claude", "CLAUDE.md"), "CLAUDE.local.md"];
|
|
15192
15406
|
var MAX_IMPORT_DEPTH = 5;
|
|
15193
15407
|
function importsOf(text6) {
|
|
15194
15408
|
const prose = text6.replace(/```[\s\S]*?```/g, "").replace(/`[^`\n]*`/g, "");
|
|
@@ -15199,11 +15413,11 @@ function withImports(workspace, file, depth, seen, into) {
|
|
|
15199
15413
|
seen.add(file);
|
|
15200
15414
|
const text6 = readText(file);
|
|
15201
15415
|
if (text6 === void 0) return;
|
|
15202
|
-
into.push({ path:
|
|
15416
|
+
into.push({ path: path21.relative(workspace, file), text: text6 });
|
|
15203
15417
|
if (depth >= MAX_IMPORT_DEPTH) return;
|
|
15204
15418
|
for (const target of importsOf(text6)) {
|
|
15205
15419
|
if (target.startsWith("~")) continue;
|
|
15206
|
-
const abs =
|
|
15420
|
+
const abs = path21.resolve(path21.dirname(file), target);
|
|
15207
15421
|
if (insideOnDisk(workspace, abs)) withImports(workspace, abs, depth + 1, seen, into);
|
|
15208
15422
|
}
|
|
15209
15423
|
}
|
|
@@ -15224,12 +15438,12 @@ var CLAUDE_REPO_CONFIG = {
|
|
|
15224
15438
|
instructions(workspace) {
|
|
15225
15439
|
const files = [];
|
|
15226
15440
|
const seen = /* @__PURE__ */ new Set();
|
|
15227
|
-
for (const name of MEMORY_FILES) withImports(workspace,
|
|
15441
|
+
for (const name of MEMORY_FILES) withImports(workspace, path21.join(workspace, name), 0, seen, files);
|
|
15228
15442
|
return files;
|
|
15229
15443
|
},
|
|
15230
15444
|
projectServers(workspace) {
|
|
15231
15445
|
const source = ".mcp.json";
|
|
15232
|
-
const text6 = readText(
|
|
15446
|
+
const text6 = readText(path21.join(workspace, source));
|
|
15233
15447
|
if (text6 === void 0) return NO_SERVERS;
|
|
15234
15448
|
let parsed;
|
|
15235
15449
|
try {
|
|
@@ -15247,13 +15461,14 @@ var CLAUDE_REPO_CONFIG = {
|
|
|
15247
15461
|
return found;
|
|
15248
15462
|
}
|
|
15249
15463
|
};
|
|
15250
|
-
function claudeLocalServers(
|
|
15251
|
-
const
|
|
15252
|
-
const
|
|
15464
|
+
function claudeLocalServers(env, workspace) {
|
|
15465
|
+
const configDir2 = env.CLAUDE_CONFIG_DIR?.trim();
|
|
15466
|
+
const file = expandRunnerHome(configDir2 ? path21.join(configDir2, ".claude.json") : "~/.claude.json", env);
|
|
15467
|
+
const text6 = file === null ? void 0 : readText(file);
|
|
15253
15468
|
if (text6 === void 0) return {};
|
|
15254
15469
|
try {
|
|
15255
15470
|
const parsed = JSON.parse(text6);
|
|
15256
|
-
const project = isRecord2(parsed) && isRecord2(parsed.projects) ? parsed.projects[
|
|
15471
|
+
const project = isRecord2(parsed) && isRecord2(parsed.projects) ? parsed.projects[path21.resolve(workspace)] : void 0;
|
|
15257
15472
|
return isRecord2(project) && isRecord2(project.mcpServers) ? project.mcpServers : {};
|
|
15258
15473
|
} catch {
|
|
15259
15474
|
return {};
|
|
@@ -15508,13 +15723,13 @@ var NO_AUTO_MEMORY = { CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1" };
|
|
|
15508
15723
|
function inSavedOutput(abs, configDir2, sessionId) {
|
|
15509
15724
|
let projects;
|
|
15510
15725
|
try {
|
|
15511
|
-
projects = import_fs11.realpathSync.native(
|
|
15726
|
+
projects = import_fs11.realpathSync.native(path22.join(configDir2, "projects"));
|
|
15512
15727
|
} catch {
|
|
15513
15728
|
return false;
|
|
15514
15729
|
}
|
|
15515
|
-
const rel =
|
|
15516
|
-
if (rel.startsWith("..") ||
|
|
15517
|
-
const [project, session, folder] = rel.split(
|
|
15730
|
+
const rel = path22.relative(projects, abs);
|
|
15731
|
+
if (rel.startsWith("..") || path22.isAbsolute(rel)) return false;
|
|
15732
|
+
const [project, session, folder] = rel.split(path22.sep);
|
|
15518
15733
|
return Boolean(project) && session === sessionId && folder === "tool-results";
|
|
15519
15734
|
}
|
|
15520
15735
|
var PATH_TOOLS = {
|
|
@@ -15752,7 +15967,7 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
15752
15967
|
"--append-system-prompt",
|
|
15753
15968
|
opts.systemPrompt
|
|
15754
15969
|
];
|
|
15755
|
-
if (opts.mcp) args.push(...this.ordewellServerArgs(opts.mcp, "planner", this.plannerServers(opts, workspace)));
|
|
15970
|
+
if (opts.mcp) args.push(...this.ordewellServerArgs(opts.mcp, "planner", this.plannerServers(opts, { ...process.env, ...workspace })));
|
|
15756
15971
|
if (opts.model) args.push("--model", opts.model);
|
|
15757
15972
|
if (opts.effort && opts.effort !== "adaptive") args.push("--effort", opts.effort);
|
|
15758
15973
|
if (opts.resumeSessionId) {
|
|
@@ -15760,7 +15975,8 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
15760
15975
|
this.countFrom(opts.resumeSessionId, opts.resumeCost);
|
|
15761
15976
|
this.pendingResume = opts.resumeSessionId;
|
|
15762
15977
|
}
|
|
15763
|
-
|
|
15978
|
+
const env = { ...process.env, ...workspace };
|
|
15979
|
+
this.configDir = expandRunnerHome(claudeConfigDir(env), env);
|
|
15764
15980
|
return {
|
|
15765
15981
|
command: "claude",
|
|
15766
15982
|
args,
|
|
@@ -15830,13 +16046,12 @@ var ClaudeCodeAdapter = class extends StdioAgentAdapter {
|
|
|
15830
16046
|
/**
|
|
15831
16047
|
* What user-only settings stop the CLI loading that is not the
|
|
15832
16048
|
* repository's to choose (ADR-0028): the user's own local-scope servers,
|
|
15833
|
-
*
|
|
15834
|
-
* servers approved for it.
|
|
16049
|
+
* from the account in the environment the planner runs with, and the
|
|
16050
|
+
* project servers approved for it.
|
|
15835
16051
|
*/
|
|
15836
|
-
plannerServers(opts,
|
|
15837
|
-
const configDir2 = workspace.CLAUDE_CONFIG_DIR ?? process.env.CLAUDE_CONFIG_DIR;
|
|
16052
|
+
plannerServers(opts, env) {
|
|
15838
16053
|
return {
|
|
15839
|
-
...claudeLocalServers(
|
|
16054
|
+
...claudeLocalServers(env, opts.cwd),
|
|
15840
16055
|
...Object.fromEntries((opts.projectServers ?? []).map((server4) => [server4.name, server4.definition]))
|
|
15841
16056
|
};
|
|
15842
16057
|
}
|
|
@@ -16600,8 +16815,8 @@ function runProbe(deps, cwd, env, flags) {
|
|
|
16600
16815
|
}
|
|
16601
16816
|
|
|
16602
16817
|
// src/services/harness/codexRepoConfig.ts
|
|
16603
|
-
var
|
|
16604
|
-
var CONFIG_FILE =
|
|
16818
|
+
var path23 = __toESM(require("path"));
|
|
16819
|
+
var CONFIG_FILE = path23.join(".codex", "config.toml");
|
|
16605
16820
|
function stringsOf(value) {
|
|
16606
16821
|
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
16607
16822
|
}
|
|
@@ -16627,9 +16842,9 @@ var CODEX_REPO_CONFIG = {
|
|
|
16627
16842
|
const files = [];
|
|
16628
16843
|
for (const dir of repoLevels(workspace)) {
|
|
16629
16844
|
for (const name of ["AGENTS.override.md", "AGENTS.md"]) {
|
|
16630
|
-
const text6 = readText(
|
|
16845
|
+
const text6 = readText(path23.join(dir, name));
|
|
16631
16846
|
if (text6 === void 0) continue;
|
|
16632
|
-
files.push({ path:
|
|
16847
|
+
files.push({ path: path23.relative(workspace, path23.join(dir, name)) || name, text: text6 });
|
|
16633
16848
|
break;
|
|
16634
16849
|
}
|
|
16635
16850
|
}
|
|
@@ -16640,10 +16855,10 @@ var CODEX_REPO_CONFIG = {
|
|
|
16640
16855
|
const byName = /* @__PURE__ */ new Map();
|
|
16641
16856
|
const unreadable = [];
|
|
16642
16857
|
for (const dir of repoLevels(workspace)) {
|
|
16643
|
-
const file =
|
|
16858
|
+
const file = path23.join(dir, CONFIG_FILE);
|
|
16644
16859
|
const text6 = readText(file);
|
|
16645
16860
|
if (text6 === void 0) continue;
|
|
16646
|
-
const source =
|
|
16861
|
+
const source = path23.relative(workspace, file);
|
|
16647
16862
|
let parsed;
|
|
16648
16863
|
try {
|
|
16649
16864
|
parsed = parseToml(text6);
|
|
@@ -16663,9 +16878,9 @@ var CODEX_REPO_CONFIG = {
|
|
|
16663
16878
|
};
|
|
16664
16879
|
function untrustedProjects(workspace) {
|
|
16665
16880
|
const projects = {};
|
|
16666
|
-
for (let dir =
|
|
16881
|
+
for (let dir = path23.resolve(workspace); ; dir = path23.dirname(dir)) {
|
|
16667
16882
|
projects[dir] = { trust_level: "untrusted" };
|
|
16668
|
-
if (
|
|
16883
|
+
if (path23.dirname(dir) === dir) return projects;
|
|
16669
16884
|
}
|
|
16670
16885
|
}
|
|
16671
16886
|
|
|
@@ -17786,7 +18001,7 @@ ${this.exitMessage()}`);
|
|
|
17786
18001
|
case "webSearch":
|
|
17787
18002
|
return;
|
|
17788
18003
|
case "fileChange": {
|
|
17789
|
-
const paths = (item.changes ?? []).map((change) => change.path).filter((
|
|
18004
|
+
const paths = (item.changes ?? []).map((change) => change.path).filter((path48) => !!path48);
|
|
17790
18005
|
this.fileChangePaths.set(item.id, paths);
|
|
17791
18006
|
if (this.startOpts?.kind === "task") {
|
|
17792
18007
|
for (const change of item.changes ?? []) this.announceFileChange(item.id, change, emit, subagentId);
|
|
@@ -17889,20 +18104,20 @@ ${this.exitMessage()}`);
|
|
|
17889
18104
|
announceFileChange(itemId, change, emit, subagentId) {
|
|
17890
18105
|
const rows = this.fileChangeRows.get(itemId) ?? /* @__PURE__ */ new Map();
|
|
17891
18106
|
this.fileChangeRows.set(itemId, rows);
|
|
17892
|
-
const
|
|
17893
|
-
const known = rows.get(
|
|
18107
|
+
const path48 = this.shownChangePath(change);
|
|
18108
|
+
const known = rows.get(path48);
|
|
17894
18109
|
if (known) return known;
|
|
17895
|
-
const row = rows.size === 0 ? itemId : `${itemId}:${
|
|
17896
|
-
rows.set(
|
|
17897
|
-
emit({ type: "tool_call", id: row, name: changeName(change), args: { path:
|
|
18110
|
+
const row = rows.size === 0 ? itemId : `${itemId}:${path48}`;
|
|
18111
|
+
rows.set(path48, row);
|
|
18112
|
+
emit({ type: "tool_call", id: row, name: changeName(change), args: { path: path48 }, ...subagentId ? { subagentId } : {} });
|
|
17898
18113
|
return row;
|
|
17899
18114
|
}
|
|
17900
18115
|
/** Relative to the task's worktree, where every path but a stray one lies; a move names both ends. */
|
|
17901
18116
|
shownChangePath(change) {
|
|
17902
|
-
const shown = (
|
|
18117
|
+
const shown = (path48) => {
|
|
17903
18118
|
const cwd = this.startOpts?.cwd;
|
|
17904
|
-
const rel = cwd ? (0, import_path6.relative)(cwd,
|
|
17905
|
-
return rel && rel !== ".." && !rel.startsWith(`..${import_path6.sep}`) && !(0, import_path6.isAbsolute)(rel) ? rel :
|
|
18119
|
+
const rel = cwd ? (0, import_path6.relative)(cwd, path48) : path48;
|
|
18120
|
+
return rel && rel !== ".." && !rel.startsWith(`..${import_path6.sep}`) && !(0, import_path6.isAbsolute)(rel) ? rel : path48;
|
|
17906
18121
|
};
|
|
17907
18122
|
const from = shown(change.path ?? "");
|
|
17908
18123
|
return change.kind?.move_path ? `${from} \u2192 ${shown(change.kind.move_path)}` : from;
|
|
@@ -17953,7 +18168,7 @@ var import_fs12 = require("fs");
|
|
|
17953
18168
|
|
|
17954
18169
|
// src/services/harness/projectServers.ts
|
|
17955
18170
|
var import_crypto8 = require("crypto");
|
|
17956
|
-
var
|
|
18171
|
+
var path24 = __toESM(require("path"));
|
|
17957
18172
|
function canonical2(value) {
|
|
17958
18173
|
if (Array.isArray(value)) return value.map(canonical2);
|
|
17959
18174
|
if (!isRecord2(value)) return value;
|
|
@@ -17964,7 +18179,7 @@ function projectServerScope(server4) {
|
|
|
17964
18179
|
return `mcp-server:${server4.name}@${hash}`;
|
|
17965
18180
|
}
|
|
17966
18181
|
var scopeName = (scope) => scope.slice(0, scope.lastIndexOf("@"));
|
|
17967
|
-
function fileProjectServerApprovals(file =
|
|
18182
|
+
function fileProjectServerApprovals(file = path24.join(globalDataDir(), "project-mcp-servers.json")) {
|
|
17968
18183
|
const load = () => {
|
|
17969
18184
|
const text6 = readText(file);
|
|
17970
18185
|
if (text6 === void 0) return {};
|
|
@@ -19127,8 +19342,8 @@ var OpenCodeAdapter = class extends ProcessLifecycle {
|
|
|
19127
19342
|
this.v2 = new OpenCodeV2({
|
|
19128
19343
|
version,
|
|
19129
19344
|
nativeShell: this.nativeShell?.prefix ?? null,
|
|
19130
|
-
request: (method,
|
|
19131
|
-
json: (method,
|
|
19345
|
+
request: (method, path48, body, signal, timeoutMs) => this.request(method, path48, body, signal, timeoutMs),
|
|
19346
|
+
json: (method, path48, body, signal, timeoutMs) => this.json(method, path48, body, signal, timeoutMs),
|
|
19132
19347
|
openEvents: (signal) => this.deps.fetch(`${this.baseUrl}/api/event`, { signal, headers: this.headers() }),
|
|
19133
19348
|
processEnded: this.processEnded,
|
|
19134
19349
|
isExited: () => this.exited,
|
|
@@ -19765,15 +19980,15 @@ var OpenCodeAdapter = class extends ProcessLifecycle {
|
|
|
19765
19980
|
onActivity
|
|
19766
19981
|
);
|
|
19767
19982
|
}
|
|
19768
|
-
async json(method,
|
|
19769
|
-
const response = await this.request(method,
|
|
19770
|
-
if (!response.ok) throw new OpenCodeHttpError(`${method} ${
|
|
19983
|
+
async json(method, path48, body, signal, timeoutMs) {
|
|
19984
|
+
const response = await this.request(method, path48, body, signal, timeoutMs);
|
|
19985
|
+
if (!response.ok) throw new OpenCodeHttpError(`${method} ${path48} failed: ${response.status} ${response.statusText}`);
|
|
19771
19986
|
return await response.json().catch(() => null);
|
|
19772
19987
|
}
|
|
19773
19988
|
/** `timeoutMs` null is for a turn's own POST, which the server answers when the turn is done. */
|
|
19774
|
-
request(method,
|
|
19989
|
+
request(method, path48, body, signal, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
19775
19990
|
const deadline = withDeadline(signal, timeoutMs);
|
|
19776
|
-
return this.deps.fetch(`${this.baseUrl}${
|
|
19991
|
+
return this.deps.fetch(`${this.baseUrl}${path48}`, {
|
|
19777
19992
|
method,
|
|
19778
19993
|
headers: this.headers({ "content-type": "application/json" }),
|
|
19779
19994
|
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
@@ -19834,8 +20049,8 @@ var OpenCodeAdapter = class extends ProcessLifecycle {
|
|
|
19834
20049
|
};
|
|
19835
20050
|
|
|
19836
20051
|
// src/services/harness/openCodeRepoConfig.ts
|
|
19837
|
-
var
|
|
19838
|
-
var CONFIG_FILES = ["opencode.json", "opencode.jsonc",
|
|
20052
|
+
var path25 = __toESM(require("path"));
|
|
20053
|
+
var CONFIG_FILES = ["opencode.json", "opencode.jsonc", path25.join(".opencode", "opencode.json"), path25.join(".opencode", "opencode.jsonc")];
|
|
19839
20054
|
var INSTRUCTION_NAMES = ["AGENTS.md", "CLAUDE.md", "CONTEXT.md"];
|
|
19840
20055
|
function server3(name, entry, source) {
|
|
19841
20056
|
if (!isRecord2(entry)) return "not an object";
|
|
@@ -19854,8 +20069,8 @@ var OPENCODE_REPO_CONFIG = {
|
|
|
19854
20069
|
const levels = repoLevels(workspace);
|
|
19855
20070
|
for (const name of INSTRUCTION_NAMES) {
|
|
19856
20071
|
const files = levels.flatMap((dir) => {
|
|
19857
|
-
const text6 = readText(
|
|
19858
|
-
return text6 === void 0 ? [] : [{ path:
|
|
20072
|
+
const text6 = readText(path25.join(dir, name));
|
|
20073
|
+
return text6 === void 0 ? [] : [{ path: path25.relative(workspace, path25.join(dir, name)) || name, text: text6 }];
|
|
19859
20074
|
});
|
|
19860
20075
|
if (files.length > 0) return files;
|
|
19861
20076
|
}
|
|
@@ -19867,10 +20082,10 @@ var OPENCODE_REPO_CONFIG = {
|
|
|
19867
20082
|
const unreadable = [];
|
|
19868
20083
|
for (const dir of repoLevels(workspace)) {
|
|
19869
20084
|
for (const name of CONFIG_FILES) {
|
|
19870
|
-
const file =
|
|
20085
|
+
const file = path25.join(dir, name);
|
|
19871
20086
|
const text6 = readText(file);
|
|
19872
20087
|
if (text6 === void 0) continue;
|
|
19873
|
-
const source =
|
|
20088
|
+
const source = path25.relative(workspace, file);
|
|
19874
20089
|
let parsed;
|
|
19875
20090
|
try {
|
|
19876
20091
|
parsed = parseJsonc(text6);
|
|
@@ -20059,7 +20274,7 @@ function knownModelId(value, optionIds, shortcuts) {
|
|
|
20059
20274
|
|
|
20060
20275
|
// src/services/ModelCatalog.ts
|
|
20061
20276
|
var fs6 = __toESM(require("fs"));
|
|
20062
|
-
var
|
|
20277
|
+
var path26 = __toESM(require("path"));
|
|
20063
20278
|
var CACHE_KEY = "model-catalog";
|
|
20064
20279
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
20065
20280
|
function storageKey(baseUrl) {
|
|
@@ -20112,7 +20327,7 @@ var ModelCatalog = class {
|
|
|
20112
20327
|
const url = (baseUrl || "https://openrouter.ai/api/v1").replace(/\/+$/, "");
|
|
20113
20328
|
const key = storageKey(url);
|
|
20114
20329
|
const cacheDir = globalCacheDir();
|
|
20115
|
-
const cacheFile =
|
|
20330
|
+
const cacheFile = path26.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
20116
20331
|
if (fs6.existsSync(cacheFile)) fs6.rmSync(cacheFile);
|
|
20117
20332
|
} catch {
|
|
20118
20333
|
}
|
|
@@ -20120,7 +20335,7 @@ var ModelCatalog = class {
|
|
|
20120
20335
|
static readCache(key) {
|
|
20121
20336
|
try {
|
|
20122
20337
|
const cacheDir = globalCacheDir();
|
|
20123
|
-
const cacheFile =
|
|
20338
|
+
const cacheFile = path26.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
20124
20339
|
if (!fs6.existsSync(cacheFile)) return null;
|
|
20125
20340
|
const raw = fs6.readFileSync(cacheFile, "utf8");
|
|
20126
20341
|
const data = JSON.parse(raw);
|
|
@@ -20134,7 +20349,7 @@ var ModelCatalog = class {
|
|
|
20134
20349
|
try {
|
|
20135
20350
|
const cacheDir = globalCacheDir();
|
|
20136
20351
|
fs6.mkdirSync(cacheDir, { recursive: true });
|
|
20137
|
-
const cacheFile =
|
|
20352
|
+
const cacheFile = path26.join(cacheDir, `${key.replace(/[:/]/g, "_")}.json`);
|
|
20138
20353
|
fs6.writeFileSync(
|
|
20139
20354
|
cacheFile,
|
|
20140
20355
|
JSON.stringify({ models, cachedAt: Date.now() }, null, 2)
|
|
@@ -20145,15 +20360,17 @@ var ModelCatalog = class {
|
|
|
20145
20360
|
};
|
|
20146
20361
|
|
|
20147
20362
|
// src/services/ModelDiscovery.ts
|
|
20148
|
-
var
|
|
20363
|
+
var path27 = __toESM(require("path"));
|
|
20149
20364
|
var import_child_process6 = require("child_process");
|
|
20150
20365
|
var import_util2 = require("util");
|
|
20151
20366
|
var fsSync5 = __toESM(require("fs"));
|
|
20152
|
-
var osMod = __toESM(require("os"));
|
|
20153
20367
|
|
|
20154
20368
|
// src/services/harness/appServerModels.ts
|
|
20155
20369
|
var import_child_process5 = require("child_process");
|
|
20156
20370
|
var DEFAULT_TIMEOUT_MS3 = 2e4;
|
|
20371
|
+
function definedOnly(env) {
|
|
20372
|
+
return Object.fromEntries(Object.entries(env).filter((entry) => entry[1] !== void 0));
|
|
20373
|
+
}
|
|
20157
20374
|
function parseRpcLine(line) {
|
|
20158
20375
|
try {
|
|
20159
20376
|
const value = JSON.parse(line);
|
|
@@ -20166,10 +20383,9 @@ async function openAppServer(command, args, launch) {
|
|
|
20166
20383
|
const runner = new RunnerProcess({
|
|
20167
20384
|
spawn: import_child_process5.spawn,
|
|
20168
20385
|
fetch: globalThis.fetch,
|
|
20169
|
-
// The cwd is no workspace
|
|
20170
|
-
//
|
|
20171
|
-
//
|
|
20172
|
-
// that can choose whose account is read.
|
|
20386
|
+
// The cwd is no workspace, so it pays no direnv round trip before a spawn
|
|
20387
|
+
// with a deadline. Discovery and the account monitor pass the workspace's
|
|
20388
|
+
// environment themselves, since that can choose whose account is read.
|
|
20173
20389
|
workspaceEnv: async () => ({}),
|
|
20174
20390
|
...launch.deps
|
|
20175
20391
|
});
|
|
@@ -20222,7 +20438,11 @@ async function openAppServer(command, args, launch) {
|
|
|
20222
20438
|
}
|
|
20223
20439
|
var APP_SERVER_CLIENT_INFO = { name: "ordewell", title: "Ordewell", version: "0.1.0" };
|
|
20224
20440
|
async function discoverAppServerModels(command, args, options = {}) {
|
|
20225
|
-
const
|
|
20441
|
+
const env = options.env;
|
|
20442
|
+
const server4 = await openAppServer(command, args, {
|
|
20443
|
+
cwd: process.cwd(),
|
|
20444
|
+
deps: { ...env ? { workspaceEnv: async () => definedOnly(env) } : {}, ...options.deps }
|
|
20445
|
+
});
|
|
20226
20446
|
if (!server4) return null;
|
|
20227
20447
|
const { rpc } = server4;
|
|
20228
20448
|
const asked = (async () => {
|
|
@@ -20249,10 +20469,10 @@ async function discoverAppServerModels(command, args, options = {}) {
|
|
|
20249
20469
|
var execAsync2 = (0, import_util2.promisify)(import_child_process6.exec);
|
|
20250
20470
|
var defaultExec2 = async (command, options) => {
|
|
20251
20471
|
const PATH = await augmentedPath();
|
|
20252
|
-
const { stdout } = await execAsync2(command, {
|
|
20472
|
+
const { stdout } = await execAsync2(command, { timeout: options?.timeout, maxBuffer: 32 * 1024 * 1024, env: withPath(options?.env ?? process.env, PATH) });
|
|
20253
20473
|
return { stdout: String(stdout) };
|
|
20254
20474
|
};
|
|
20255
|
-
var defaultAppServerClient = (command, args, options) => discoverAppServerModels(command, args, { timeout: options?.timeout });
|
|
20475
|
+
var defaultAppServerClient = (command, args, options) => discoverAppServerModels(command, args, { timeout: options?.timeout, env: options?.env });
|
|
20256
20476
|
function effortVariant(effort) {
|
|
20257
20477
|
return { id: effort, label: effort.charAt(0).toUpperCase() + effort.slice(1) };
|
|
20258
20478
|
}
|
|
@@ -20286,7 +20506,7 @@ function geminiDiscoveryCacheKey(apiKey) {
|
|
|
20286
20506
|
return {
|
|
20287
20507
|
key: `gemini-models:${hash}`,
|
|
20288
20508
|
dir,
|
|
20289
|
-
file:
|
|
20509
|
+
file: path27.join(dir, `gemini_models_${hash}.json`)
|
|
20290
20510
|
};
|
|
20291
20511
|
}
|
|
20292
20512
|
function readGeminiCache(apiKey) {
|
|
@@ -20373,15 +20593,22 @@ function applyVariants(models, manifest) {
|
|
|
20373
20593
|
if (!variants || variants.length === 0) return models;
|
|
20374
20594
|
return models.map((m) => m.variants.length > 0 ? m : { ...m, variants });
|
|
20375
20595
|
}
|
|
20376
|
-
function
|
|
20596
|
+
function listDir(dir) {
|
|
20597
|
+
try {
|
|
20598
|
+
return fsSync5.readdirSync(dir);
|
|
20599
|
+
} catch {
|
|
20600
|
+
return [];
|
|
20601
|
+
}
|
|
20602
|
+
}
|
|
20603
|
+
function resolveApiAuth(authMethods, env) {
|
|
20377
20604
|
for (const method of authMethods) {
|
|
20378
20605
|
try {
|
|
20379
20606
|
let token;
|
|
20380
20607
|
if (method.type === "env") {
|
|
20381
|
-
token =
|
|
20608
|
+
token = env[method.varName];
|
|
20382
20609
|
} else {
|
|
20383
|
-
const filePath = method.path.
|
|
20384
|
-
if (!fsSync5.existsSync(filePath)) continue;
|
|
20610
|
+
const filePath = expandRunnerHome(typeof method.path === "function" ? method.path(env) : method.path, env);
|
|
20611
|
+
if (!filePath || !fsSync5.existsSync(filePath)) continue;
|
|
20385
20612
|
const data = JSON.parse(fsSync5.readFileSync(filePath, "utf8"));
|
|
20386
20613
|
token = method.jsonPath.split(".").reduce((obj, key) => {
|
|
20387
20614
|
if (obj && typeof obj === "object") return obj[key];
|
|
@@ -20397,8 +20624,8 @@ function resolveApiAuth(authMethods) {
|
|
|
20397
20624
|
}
|
|
20398
20625
|
return null;
|
|
20399
20626
|
}
|
|
20400
|
-
async function discoverFromApi(manifest, config, fetchImpl) {
|
|
20401
|
-
const auth = resolveApiAuth(config.auth);
|
|
20627
|
+
async function discoverFromApi(manifest, config, env, fetchImpl) {
|
|
20628
|
+
const auth = resolveApiAuth(config.auth, env);
|
|
20402
20629
|
if (!auth) return null;
|
|
20403
20630
|
try {
|
|
20404
20631
|
const headers = { ...config.headers, [auth.header]: auth.value };
|
|
@@ -20414,7 +20641,7 @@ async function discoverFromApi(manifest, config, fetchImpl) {
|
|
|
20414
20641
|
function wasKilled(err) {
|
|
20415
20642
|
return !!err && typeof err === "object" && err.killed === true;
|
|
20416
20643
|
}
|
|
20417
|
-
async function discoverFromCommand(manifest, execImpl) {
|
|
20644
|
+
async function discoverFromCommand(manifest, execImpl, env) {
|
|
20418
20645
|
const discovery = manifest.modelDiscovery;
|
|
20419
20646
|
const commands = discovery.discoveryCommands ?? [
|
|
20420
20647
|
{ command: discovery.command, args: discovery.args || [], parser: discovery.parser }
|
|
@@ -20423,7 +20650,7 @@ async function discoverFromCommand(manifest, execImpl) {
|
|
|
20423
20650
|
let timedOut2 = false;
|
|
20424
20651
|
for (const cmd of commands) {
|
|
20425
20652
|
try {
|
|
20426
|
-
const { stdout } = await execImpl(`${cmd.command} ${cmd.args.join(" ")}`, { timeout: 45e3 });
|
|
20653
|
+
const { stdout } = await execImpl(`${cmd.command} ${cmd.args.join(" ")}`, { timeout: 45e3, env });
|
|
20427
20654
|
const models = parseModelOutput(stdout, cmd.parser, manifest);
|
|
20428
20655
|
if (models.length > 0) return { models: applyVariants(mergeCanonicalAliases(models, manifest), manifest), timedOut: timedOut2 };
|
|
20429
20656
|
} catch (err) {
|
|
@@ -20489,21 +20716,26 @@ var ModelDiscovery = class {
|
|
|
20489
20716
|
* same background service.
|
|
20490
20717
|
*/
|
|
20491
20718
|
inflight = /* @__PURE__ */ new Map();
|
|
20719
|
+
/** Bumped by every `clear()`: a discovery begun before one answers its own lookups but fills no cache. */
|
|
20720
|
+
generation = 0;
|
|
20492
20721
|
registry;
|
|
20493
20722
|
execImpl;
|
|
20494
20723
|
fetchImpl;
|
|
20495
20724
|
appServerClient;
|
|
20496
20725
|
readFileImpl;
|
|
20497
20726
|
now;
|
|
20498
|
-
|
|
20727
|
+
env;
|
|
20728
|
+
constructor(registry, execImpl = defaultExec2, fetchImpl, appServerClient = defaultAppServerClient, readFileImpl, now = Date.now, env = async () => process.env) {
|
|
20499
20729
|
this.registry = registry;
|
|
20500
20730
|
this.execImpl = execImpl;
|
|
20501
20731
|
this.fetchImpl = fetchImpl;
|
|
20502
20732
|
this.appServerClient = appServerClient;
|
|
20503
20733
|
this.now = now;
|
|
20734
|
+
this.env = env;
|
|
20504
20735
|
this.readFileImpl = readFileImpl ?? ((filePath) => {
|
|
20505
20736
|
try {
|
|
20506
|
-
|
|
20737
|
+
const file = expandRunnerHome(filePath);
|
|
20738
|
+
return file ? fsSync5.readFileSync(file, "utf8") : null;
|
|
20507
20739
|
} catch {
|
|
20508
20740
|
return null;
|
|
20509
20741
|
}
|
|
@@ -20515,16 +20747,17 @@ var ModelDiscovery = class {
|
|
|
20515
20747
|
* null when both fail so `discover()` falls through to the remaining
|
|
20516
20748
|
* methods.
|
|
20517
20749
|
*/
|
|
20518
|
-
async discoverFromAppServer(manifest) {
|
|
20750
|
+
async discoverFromAppServer(manifest, env) {
|
|
20519
20751
|
const config = manifest.modelDiscovery.appServer;
|
|
20520
20752
|
if (!config) return null;
|
|
20521
|
-
const raw = await this.appServerClient(config.command, config.args);
|
|
20753
|
+
const raw = await this.appServerClient(config.command, config.args, { env });
|
|
20522
20754
|
if (raw) {
|
|
20523
20755
|
const models = parseAppServerModels(raw);
|
|
20524
20756
|
if (models.length > 0) return models;
|
|
20525
20757
|
}
|
|
20526
|
-
|
|
20527
|
-
|
|
20758
|
+
const cacheFile = config.cacheFile && expandRunnerHome(typeof config.cacheFile === "function" ? config.cacheFile(env) : config.cacheFile, env);
|
|
20759
|
+
if (cacheFile) {
|
|
20760
|
+
const content = this.readFileImpl(cacheFile);
|
|
20528
20761
|
if (content) {
|
|
20529
20762
|
const models = parseCodexModelsCache(content);
|
|
20530
20763
|
if (models.length > 0) return models;
|
|
@@ -20562,37 +20795,60 @@ var ModelDiscovery = class {
|
|
|
20562
20795
|
if (!manifest) {
|
|
20563
20796
|
return [];
|
|
20564
20797
|
}
|
|
20565
|
-
|
|
20798
|
+
const generation2 = this.generation;
|
|
20799
|
+
const env = await this.env().catch(() => process.env);
|
|
20800
|
+
const found = await this.discoverFromSources(manifest, env);
|
|
20801
|
+
const models = this.withSettingsModels(found.models, manifest, env);
|
|
20802
|
+
if (generation2 !== this.generation) return models;
|
|
20803
|
+
if (found.cacheable && models.length > 0) this.cache.set(runner, models);
|
|
20804
|
+
else this.misses.set(runner, { models, at: this.now() });
|
|
20805
|
+
return models;
|
|
20806
|
+
}
|
|
20807
|
+
async discoverFromSources(manifest, env) {
|
|
20566
20808
|
let cacheable = true;
|
|
20567
20809
|
const discovery = manifest.modelDiscovery;
|
|
20568
20810
|
if (discovery.appServer) {
|
|
20569
|
-
const appServerModels = await this.discoverFromAppServer(manifest);
|
|
20570
|
-
if (appServerModels && appServerModels.length > 0) {
|
|
20571
|
-
this.cache.set(runner, appServerModels);
|
|
20572
|
-
return appServerModels;
|
|
20573
|
-
}
|
|
20811
|
+
const appServerModels = await this.discoverFromAppServer(manifest, env);
|
|
20812
|
+
if (appServerModels && appServerModels.length > 0) return { models: appServerModels, cacheable: true };
|
|
20574
20813
|
cacheable = false;
|
|
20575
20814
|
}
|
|
20576
20815
|
if (discovery.apiDiscovery) {
|
|
20577
|
-
const apiModels = await discoverFromApi(manifest, discovery.apiDiscovery, this.fetchImpl);
|
|
20816
|
+
const apiModels = await discoverFromApi(manifest, discovery.apiDiscovery, env, this.fetchImpl);
|
|
20578
20817
|
if (apiModels && apiModels.length > 0) {
|
|
20579
|
-
models
|
|
20580
|
-
if (cacheable && models.length > 0) this.cache.set(runner, models);
|
|
20581
|
-
return models;
|
|
20818
|
+
return { models: applyVariants(mergeCanonicalAliases(apiModels, manifest), manifest), cacheable };
|
|
20582
20819
|
}
|
|
20583
20820
|
}
|
|
20584
20821
|
if (discovery.method === "command" && (discovery.command || discovery.discoveryCommands?.length)) {
|
|
20585
|
-
const result = await discoverFromCommand(manifest, this.execImpl);
|
|
20586
|
-
models
|
|
20587
|
-
cacheable = !result.fromFallback;
|
|
20588
|
-
} else {
|
|
20589
|
-
models = buildFallbackModels(manifest);
|
|
20822
|
+
const result = await discoverFromCommand(manifest, this.execImpl, env);
|
|
20823
|
+
return { models: result.models, cacheable: !result.fromFallback };
|
|
20590
20824
|
}
|
|
20591
|
-
|
|
20592
|
-
|
|
20593
|
-
|
|
20825
|
+
return { models: buildFallbackModels(manifest), cacheable };
|
|
20826
|
+
}
|
|
20827
|
+
/**
|
|
20828
|
+
* Append the models registered in the runner's own settings. Read on every
|
|
20829
|
+
* discovery rather than cached apart, so a refresh picks up an edit;
|
|
20830
|
+
* whatever the sources already offer keeps its entry and metadata.
|
|
20831
|
+
*/
|
|
20832
|
+
withSettingsModels(models, manifest, env) {
|
|
20833
|
+
const read2 = manifest.modelDiscovery.settingsModels;
|
|
20834
|
+
if (!read2) return models;
|
|
20835
|
+
const files = {
|
|
20836
|
+
read: (filePath) => {
|
|
20837
|
+
const file = expandRunnerHome(filePath, env);
|
|
20838
|
+
return file ? this.readFileImpl(file) : null;
|
|
20839
|
+
},
|
|
20840
|
+
list: (dir) => {
|
|
20841
|
+
const expanded = expandRunnerHome(dir, env);
|
|
20842
|
+
return expanded ? listDir(expanded) : [];
|
|
20843
|
+
},
|
|
20844
|
+
env
|
|
20845
|
+
};
|
|
20846
|
+
const seen = new Set(models.map((m) => m.modelId));
|
|
20847
|
+
const added = read2(files).filter((m) => !seen.has(m.modelId));
|
|
20848
|
+
return added.length > 0 ? [...models, ...applyVariants(added, manifest)] : models;
|
|
20594
20849
|
}
|
|
20595
20850
|
clear() {
|
|
20851
|
+
this.generation++;
|
|
20596
20852
|
this.cache.clear();
|
|
20597
20853
|
this.misses.clear();
|
|
20598
20854
|
this.inflight.clear();
|
|
@@ -20758,7 +21014,7 @@ function parseMaxParallel(value) {
|
|
|
20758
21014
|
|
|
20759
21015
|
// src/services/SettingsService.ts
|
|
20760
21016
|
var fs12 = __toESM(require("fs"));
|
|
20761
|
-
var
|
|
21017
|
+
var path34 = __toESM(require("path"));
|
|
20762
21018
|
|
|
20763
21019
|
// src/utils/fileLock.ts
|
|
20764
21020
|
var fs7 = __toESM(require("fs"));
|
|
@@ -20890,6 +21146,10 @@ var RECEIPT_LABELS = {
|
|
|
20890
21146
|
function receiptLabel(task2) {
|
|
20891
21147
|
return isTaskRunning(task2) && task2.completionReceived ? RECEIPT_LABELS[task2.completionReceived] : null;
|
|
20892
21148
|
}
|
|
21149
|
+
function attachingLabel(task2) {
|
|
21150
|
+
if (!isTaskRunning(task2) || !task2.attaching) return null;
|
|
21151
|
+
return task2.attaching === 2 ? "Connecting Ordewell's tools, retry" : "Connecting Ordewell's tools";
|
|
21152
|
+
}
|
|
20893
21153
|
function approvalLabel(count) {
|
|
20894
21154
|
if (!count) return null;
|
|
20895
21155
|
return count > 1 ? `Waiting for approval (${count})` : "Waiting for approval";
|
|
@@ -22359,7 +22619,7 @@ function createWakePolicy(options) {
|
|
|
22359
22619
|
}
|
|
22360
22620
|
|
|
22361
22621
|
// src/services/runnerExit.ts
|
|
22362
|
-
var USAGE_LIMIT_RE = /\b(?:usage|session|weekly|daily|monthly) limit\b|\brate limit (?:exceeded|reached)\b|\brate[- ]limited\b|\blimit (?:will )?reset\b|\bquota (?:exceeded|reached)\b|\btoo many requests\b/i;
|
|
22622
|
+
var USAGE_LIMIT_RE = /\b(?:usage|session|weekly|daily|monthly) limit\b|\byou['’]ve hit your (?:[\w'’-]+ ){0,3}?limit\b|\brate limit (?:exceeded|reached)\b|\brate[- ]limited\b|\blimit (?:will )?reset\b|\bquota (?:exceeded|reached)\b|\btoo many requests\b/i;
|
|
22363
22623
|
var USAGE_LIMIT_TAIL = 4096;
|
|
22364
22624
|
function classifyRunnerStop(said2) {
|
|
22365
22625
|
if (typeof said2 !== "string" && said2.usageLimit !== void 0) return said2.usageLimit ? "usage-limit" : "stopped";
|
|
@@ -22720,8 +22980,8 @@ function compactionCut(transcript) {
|
|
|
22720
22980
|
}
|
|
22721
22981
|
|
|
22722
22982
|
// src/services/skillInvocation.ts
|
|
22723
|
-
var
|
|
22724
|
-
function abbreviateHome(file, home =
|
|
22983
|
+
var os9 = __toESM(require("os"));
|
|
22984
|
+
function abbreviateHome(file, home = os9.homedir(), platform = process.platform) {
|
|
22725
22985
|
const win = platform === "win32";
|
|
22726
22986
|
const normal = (p) => win ? p.replace(/\\/g, "/") : p;
|
|
22727
22987
|
const shown = normal(file);
|
|
@@ -22736,13 +22996,13 @@ function modelInvocablePlannerSkills(skills) {
|
|
|
22736
22996
|
function modelInvocableTaskSkills(skills) {
|
|
22737
22997
|
return skills.filter((skill) => skill.appliesTo === "task" && skill.modelInvocable);
|
|
22738
22998
|
}
|
|
22739
|
-
function snapshotSkill(skill, invokedBy, home =
|
|
22999
|
+
function snapshotSkill(skill, invokedBy, home = os9.homedir()) {
|
|
22740
23000
|
return { invokedBy, name: skill.name, source: skill.source, path: abbreviateHome(skill.path, home), content: skill.content };
|
|
22741
23001
|
}
|
|
22742
23002
|
function attachSkill(skill, home) {
|
|
22743
23003
|
return { ...snapshotSkill(skill, "user", home), content: "", attaches: { description: skill.description } };
|
|
22744
23004
|
}
|
|
22745
|
-
function resolveSkillInvocation(text6, skillsService, home =
|
|
23005
|
+
function resolveSkillInvocation(text6, skillsService, home = os9.homedir()) {
|
|
22746
23006
|
const skills = skillTokens(text6).flatMap(({ name }) => {
|
|
22747
23007
|
const skill = skillsService.findSkill(name);
|
|
22748
23008
|
if (!skill?.userInvocable) return [];
|
|
@@ -22806,33 +23066,33 @@ ${skillBlock(entry.skill)}`, timestamp: entry.timestamp });
|
|
|
22806
23066
|
}
|
|
22807
23067
|
|
|
22808
23068
|
// src/services/taskSkills.ts
|
|
22809
|
-
var
|
|
23069
|
+
var path33 = __toESM(require("path"));
|
|
22810
23070
|
|
|
22811
23071
|
// src/services/SkillsService.ts
|
|
22812
23072
|
var import_crypto12 = require("crypto");
|
|
22813
23073
|
var fs11 = __toESM(require("fs"));
|
|
22814
|
-
var
|
|
23074
|
+
var path32 = __toESM(require("path"));
|
|
22815
23075
|
|
|
22816
23076
|
// src/services/builtinSkills.ts
|
|
22817
|
-
var
|
|
23077
|
+
var path28 = __toESM(require("path"));
|
|
22818
23078
|
var import_url = require("url");
|
|
22819
23079
|
function builtinSkillsDir() {
|
|
22820
|
-
const dir = typeof __dirname !== "undefined" && __dirname ? __dirname :
|
|
23080
|
+
const dir = typeof __dirname !== "undefined" && __dirname ? __dirname : path28.dirname((0, import_url.fileURLToPath)(
|
|
22821
23081
|
// @ts-expect-error - import.meta is only valid under an ESM module setting
|
|
22822
23082
|
__filename
|
|
22823
23083
|
));
|
|
22824
|
-
return
|
|
23084
|
+
return path28.join(dir, "..", "skills");
|
|
22825
23085
|
}
|
|
22826
23086
|
|
|
22827
23087
|
// src/services/repoGroup.ts
|
|
22828
23088
|
var fs10 = __toESM(require("fs"));
|
|
22829
|
-
var
|
|
23089
|
+
var path31 = __toESM(require("path"));
|
|
22830
23090
|
|
|
22831
23091
|
// src/services/worktreeBootstrap.ts
|
|
22832
23092
|
var import_child_process8 = require("child_process");
|
|
22833
23093
|
var import_util4 = require("util");
|
|
22834
23094
|
var fs9 = __toESM(require("fs"));
|
|
22835
|
-
var
|
|
23095
|
+
var path30 = __toESM(require("path"));
|
|
22836
23096
|
|
|
22837
23097
|
// src/services/gitExec.ts
|
|
22838
23098
|
var import_child_process7 = require("child_process");
|
|
@@ -22914,7 +23174,7 @@ function subcommandOf2(args) {
|
|
|
22914
23174
|
|
|
22915
23175
|
// src/services/worktreeLink.ts
|
|
22916
23176
|
var fs8 = __toESM(require("fs"));
|
|
22917
|
-
var
|
|
23177
|
+
var path29 = __toESM(require("path"));
|
|
22918
23178
|
function linkPath(source, target, platform, hardLink = fs8.linkSync) {
|
|
22919
23179
|
const isDir = fs8.statSync(source).isDirectory();
|
|
22920
23180
|
if (platform !== "win32") {
|
|
@@ -22939,8 +23199,8 @@ function mirrorDir(source, target, opts) {
|
|
|
22939
23199
|
const mirror = (from, to, prefix, top) => {
|
|
22940
23200
|
fs8.mkdirSync(to, { recursive: true });
|
|
22941
23201
|
for (const entry of fs8.readdirSync(from, { withFileTypes: true })) {
|
|
22942
|
-
const name =
|
|
22943
|
-
const at = { from:
|
|
23202
|
+
const name = path29.join(prefix, entry.name);
|
|
23203
|
+
const at = { from: path29.join(from, entry.name), to: path29.join(to, entry.name), name };
|
|
22944
23204
|
if (entry.isSymbolicLink()) links.push(at);
|
|
22945
23205
|
else if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin")) mirror(at.from, at.to, name, false);
|
|
22946
23206
|
else if (linkPath(at.from, at.to, opts.platform, opts.hardLink) === "copy") copied.push(name);
|
|
@@ -22960,16 +23220,16 @@ function mirrorDir(source, target, opts) {
|
|
|
22960
23220
|
}
|
|
22961
23221
|
function relink(from, to, opts) {
|
|
22962
23222
|
const text6 = fs8.readlinkSync(from);
|
|
22963
|
-
const pointee =
|
|
23223
|
+
const pointee = path29.isAbsolute(text6) ? rebased(text6, opts) : text6;
|
|
22964
23224
|
if (opts.platform !== "win32") {
|
|
22965
|
-
if (!fs8.existsSync(
|
|
22966
|
-
fs8.symlinkSync(rebased(
|
|
23225
|
+
if (!fs8.existsSync(path29.resolve(path29.dirname(to), pointee)) && fs8.existsSync(path29.resolve(path29.dirname(from), pointee))) {
|
|
23226
|
+
fs8.symlinkSync(rebased(path29.resolve(path29.dirname(from), pointee), opts), to);
|
|
22967
23227
|
return "symlink";
|
|
22968
23228
|
}
|
|
22969
23229
|
fs8.symlinkSync(pointee, to);
|
|
22970
23230
|
return "symlink";
|
|
22971
23231
|
}
|
|
22972
|
-
const resolved = fs8.existsSync(
|
|
23232
|
+
const resolved = fs8.existsSync(path29.resolve(path29.dirname(to), pointee)) ? path29.resolve(path29.dirname(to), pointee) : rebased(path29.resolve(path29.dirname(from), pointee), opts);
|
|
22973
23233
|
try {
|
|
22974
23234
|
fs8.statSync(resolved);
|
|
22975
23235
|
} catch {
|
|
@@ -22978,9 +23238,9 @@ function relink(from, to, opts) {
|
|
|
22978
23238
|
return linkPath(resolved, to, opts.platform, opts.hardLink);
|
|
22979
23239
|
}
|
|
22980
23240
|
function rebased(pointee, opts) {
|
|
22981
|
-
const rel =
|
|
22982
|
-
const inside2 = rel !== "" && !rel.startsWith("..") && !
|
|
22983
|
-
return inside2 && !rel.split(/[\\/]/).includes("node_modules") ?
|
|
23241
|
+
const rel = path29.relative(opts.from, pointee);
|
|
23242
|
+
const inside2 = rel !== "" && !rel.startsWith("..") && !path29.isAbsolute(rel);
|
|
23243
|
+
return inside2 && !rel.split(/[\\/]/).includes("node_modules") ? path29.join(opts.to, rel) : pointee;
|
|
22984
23244
|
}
|
|
22985
23245
|
|
|
22986
23246
|
// src/services/worktreeBootstrap.ts
|
|
@@ -22997,7 +23257,7 @@ function lexists(target) {
|
|
|
22997
23257
|
return false;
|
|
22998
23258
|
}
|
|
22999
23259
|
}
|
|
23000
|
-
function
|
|
23260
|
+
function listDir2(dir) {
|
|
23001
23261
|
try {
|
|
23002
23262
|
return fs9.readdirSync(dir).sort();
|
|
23003
23263
|
} catch {
|
|
@@ -23017,18 +23277,18 @@ function matchLinks(root, patterns) {
|
|
|
23017
23277
|
}
|
|
23018
23278
|
function segmentMatches(root, base, segment) {
|
|
23019
23279
|
const under = (name) => base ? `${base}/${name}` : name;
|
|
23020
|
-
if (!/[*?]/.test(segment)) return lexists(
|
|
23280
|
+
if (!/[*?]/.test(segment)) return lexists(path30.join(root, base, segment)) ? [under(segment)] : [];
|
|
23021
23281
|
const pattern = new RegExp(`^${segment.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
23022
|
-
return
|
|
23282
|
+
return listDir2(path30.join(root, base)).filter((name) => !NEVER_SCANNED.has(name) && pattern.test(name)).map(under);
|
|
23023
23283
|
}
|
|
23024
23284
|
function installDirs(root) {
|
|
23025
23285
|
const packages = matchLinks(root, workspaceGlobs(root)).map((pkg) => `${pkg}/node_modules`);
|
|
23026
|
-
return ["node_modules", ...packages].filter((dir) => lexists(
|
|
23286
|
+
return ["node_modules", ...packages].filter((dir) => lexists(path30.join(root, dir)));
|
|
23027
23287
|
}
|
|
23028
23288
|
function workspaceGlobs(root) {
|
|
23029
23289
|
let manifest;
|
|
23030
23290
|
try {
|
|
23031
|
-
manifest = JSON.parse(fs9.readFileSync(
|
|
23291
|
+
manifest = JSON.parse(fs9.readFileSync(path30.join(root, "package.json"), "utf8"));
|
|
23032
23292
|
} catch {
|
|
23033
23293
|
return [];
|
|
23034
23294
|
}
|
|
@@ -23043,19 +23303,19 @@ async function bootstrap(repo, cwd, opts) {
|
|
|
23043
23303
|
const linked = [];
|
|
23044
23304
|
const copied = [];
|
|
23045
23305
|
const link = (name) => {
|
|
23046
|
-
const target =
|
|
23306
|
+
const target = path30.join(cwd, name);
|
|
23047
23307
|
if (lexists(target)) return;
|
|
23048
|
-
fs9.mkdirSync(
|
|
23049
|
-
if (linkPath(
|
|
23308
|
+
fs9.mkdirSync(path30.dirname(target), { recursive: true });
|
|
23309
|
+
if (linkPath(path30.join(repo.root, name), target, opts.platform) === "copy") copied.push(name);
|
|
23050
23310
|
linked.push(name);
|
|
23051
23311
|
};
|
|
23052
23312
|
const mirror = (name) => {
|
|
23053
|
-
const target =
|
|
23054
|
-
if (lexists(target) || !fs9.existsSync(
|
|
23055
|
-
const source =
|
|
23313
|
+
const target = path30.join(cwd, name);
|
|
23314
|
+
if (lexists(target) || !fs9.existsSync(path30.dirname(target))) return;
|
|
23315
|
+
const source = path30.join(repo.root, name);
|
|
23056
23316
|
if (!fs9.lstatSync(source).isDirectory()) return link(name);
|
|
23057
23317
|
const mirrored = mirrorDir(source, target, { platform: opts.platform, from: repo.root, to: cwd });
|
|
23058
|
-
copied.push(...mirrored.map((entry) =>
|
|
23318
|
+
copied.push(...mirrored.map((entry) => path30.join(name, entry)));
|
|
23059
23319
|
linked.push(name);
|
|
23060
23320
|
};
|
|
23061
23321
|
if (!setup) {
|
|
@@ -23090,12 +23350,12 @@ async function runSetup(command, repo, cwd, resolvePath) {
|
|
|
23090
23350
|
|
|
23091
23351
|
// src/services/repoGroup.ts
|
|
23092
23352
|
function hasGitEntry(dir) {
|
|
23093
|
-
return fs10.existsSync(
|
|
23353
|
+
return fs10.existsSync(path31.join(dir, ".git"));
|
|
23094
23354
|
}
|
|
23095
23355
|
function groupPathOf(listed3) {
|
|
23096
23356
|
const slashed = listed3.trim().replace(/\\/g, "/");
|
|
23097
|
-
if (
|
|
23098
|
-
const rel =
|
|
23357
|
+
if (path31.posix.isAbsolute(slashed) || path31.win32.isAbsolute(slashed)) return null;
|
|
23358
|
+
const rel = path31.posix.normalize(slashed).replace(/\/+$/, "");
|
|
23099
23359
|
return rel === "" || rel === "." || rel === ".." || rel.startsWith("../") ? null : rel;
|
|
23100
23360
|
}
|
|
23101
23361
|
function childDirs(dir) {
|
|
@@ -23106,14 +23366,14 @@ function childDirs(dir) {
|
|
|
23106
23366
|
}
|
|
23107
23367
|
}
|
|
23108
23368
|
function groupPaths(workspaceRoot, listed3) {
|
|
23109
|
-
if (listed3.length === 0) return childDirs(workspaceRoot).filter((name) => hasGitEntry(
|
|
23110
|
-
const paths = listed3.map(groupPathOf).filter((rel) => rel !== null && hasGitEntry(
|
|
23369
|
+
if (listed3.length === 0) return childDirs(workspaceRoot).filter((name) => hasGitEntry(path31.join(workspaceRoot, name)));
|
|
23370
|
+
const paths = listed3.map(groupPathOf).filter((rel) => rel !== null && hasGitEntry(path31.join(workspaceRoot, rel)));
|
|
23111
23371
|
return [...new Set(paths)].sort();
|
|
23112
23372
|
}
|
|
23113
23373
|
function workspaceRepoGroup(workspaceRoot, listed3) {
|
|
23114
|
-
for (let dir =
|
|
23374
|
+
for (let dir = path31.resolve(workspaceRoot); ; dir = path31.dirname(dir)) {
|
|
23115
23375
|
if (hasGitEntry(dir)) return [SELF_REPO];
|
|
23116
|
-
if (
|
|
23376
|
+
if (path31.dirname(dir) === dir) break;
|
|
23117
23377
|
}
|
|
23118
23378
|
return groupPaths(workspaceRoot, listed3);
|
|
23119
23379
|
}
|
|
@@ -23194,8 +23454,8 @@ function copyDirSync(src, dest) {
|
|
|
23194
23454
|
fs11.mkdirSync(dest, { recursive: true });
|
|
23195
23455
|
const entries = fs11.readdirSync(src, { withFileTypes: true });
|
|
23196
23456
|
for (const entry of entries) {
|
|
23197
|
-
const srcPath =
|
|
23198
|
-
const destPath =
|
|
23457
|
+
const srcPath = path32.join(src, entry.name);
|
|
23458
|
+
const destPath = path32.join(dest, entry.name);
|
|
23199
23459
|
if (entry.isDirectory()) copyDirSync(srcPath, destPath);
|
|
23200
23460
|
else fs11.copyFileSync(srcPath, destPath);
|
|
23201
23461
|
}
|
|
@@ -23219,7 +23479,7 @@ function readDir(dir, source) {
|
|
|
23219
23479
|
if (!fs11.existsSync(dir)) return { skills, invalid };
|
|
23220
23480
|
for (const entry of fs11.readdirSync(dir, { withFileTypes: true })) {
|
|
23221
23481
|
if (!entry.isDirectory()) continue;
|
|
23222
|
-
const skillFile =
|
|
23482
|
+
const skillFile = path32.join(dir, entry.name, "SKILL.md");
|
|
23223
23483
|
if (!fs11.existsSync(skillFile)) continue;
|
|
23224
23484
|
if (!isSkillName(entry.name)) {
|
|
23225
23485
|
invalid.push({ name: entry.name, path: skillFile, source, reason: INVALID_SKILL_NAME_REASON });
|
|
@@ -23238,15 +23498,15 @@ function skillFileIn(dir, name) {
|
|
|
23238
23498
|
return void 0;
|
|
23239
23499
|
}
|
|
23240
23500
|
if (!entries.some((entry) => entry.isDirectory() && entry.name === name)) return void 0;
|
|
23241
|
-
const skillFile =
|
|
23501
|
+
const skillFile = path32.join(dir, name, "SKILL.md");
|
|
23242
23502
|
return fs11.existsSync(skillFile) ? skillFile : void 0;
|
|
23243
23503
|
}
|
|
23244
23504
|
function skillsDirOf(root) {
|
|
23245
|
-
return
|
|
23505
|
+
return path32.join(root, STATE_DIR, "skills");
|
|
23246
23506
|
}
|
|
23247
23507
|
function workspaceSkillRoots(workspaceRoot, repos, checkout = workspaceRoot) {
|
|
23248
23508
|
if (repos.length === 0 || repos.includes(SELF_REPO)) return [checkout];
|
|
23249
|
-
return [workspaceRoot, ...repos.map((repo) =>
|
|
23509
|
+
return [workspaceRoot, ...repos.map((repo) => path32.join(checkout, repo))];
|
|
23250
23510
|
}
|
|
23251
23511
|
var SkillsService = class _SkillsService {
|
|
23252
23512
|
workspaceRoots;
|
|
@@ -23269,11 +23529,11 @@ var SkillsService = class _SkillsService {
|
|
|
23269
23529
|
return this.workspaceRoots.map(skillsDirOf);
|
|
23270
23530
|
}
|
|
23271
23531
|
globalDir() {
|
|
23272
|
-
return
|
|
23532
|
+
return path32.join(globalDataDir(), "skills");
|
|
23273
23533
|
}
|
|
23274
23534
|
readSeedManifest() {
|
|
23275
23535
|
try {
|
|
23276
|
-
const parsed = JSON.parse(fs11.readFileSync(
|
|
23536
|
+
const parsed = JSON.parse(fs11.readFileSync(path32.join(this.globalDir(), SEED_MANIFEST), "utf8"));
|
|
23277
23537
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
23278
23538
|
return Object.fromEntries(
|
|
23279
23539
|
Object.entries(parsed).filter((entry) => typeof entry[1] === "string")
|
|
@@ -23289,7 +23549,7 @@ var SkillsService = class _SkillsService {
|
|
|
23289
23549
|
manifest[name] = hash;
|
|
23290
23550
|
try {
|
|
23291
23551
|
fs11.mkdirSync(this.globalDir(), { recursive: true });
|
|
23292
|
-
fs11.writeFileSync(
|
|
23552
|
+
fs11.writeFileSync(path32.join(this.globalDir(), SEED_MANIFEST), JSON.stringify(manifest, null, 2));
|
|
23293
23553
|
} catch (err) {
|
|
23294
23554
|
console.warn(`Could not record seeded skill ${name}: ${String(err)}`);
|
|
23295
23555
|
}
|
|
@@ -23300,11 +23560,11 @@ var SkillsService = class _SkillsService {
|
|
|
23300
23560
|
return this.readSeedManifest()[name] === currentHash || (PRIOR_BUILTIN_HASHES[name] ?? []).includes(currentHash);
|
|
23301
23561
|
}
|
|
23302
23562
|
seed(name) {
|
|
23303
|
-
const dest =
|
|
23563
|
+
const dest = path32.join(this.globalDir(), name);
|
|
23304
23564
|
const exists = fs11.existsSync(dest);
|
|
23305
23565
|
let srcDir;
|
|
23306
23566
|
try {
|
|
23307
|
-
srcDir =
|
|
23567
|
+
srcDir = path32.join(builtinSkillsDir(), name);
|
|
23308
23568
|
} catch (err) {
|
|
23309
23569
|
if (!exists) console.warn(`Could not locate built-in skills dir: ${String(err)}`);
|
|
23310
23570
|
return false;
|
|
@@ -23313,9 +23573,9 @@ var SkillsService = class _SkillsService {
|
|
|
23313
23573
|
if (!exists) console.warn(`Built-in skill not found in package: ${name}`);
|
|
23314
23574
|
return false;
|
|
23315
23575
|
}
|
|
23316
|
-
const srcHash = fileHash(
|
|
23576
|
+
const srcHash = fileHash(path32.join(srcDir, "SKILL.md"));
|
|
23317
23577
|
if (exists) {
|
|
23318
|
-
const currentHash = fileHash(
|
|
23578
|
+
const currentHash = fileHash(path32.join(dest, "SKILL.md"));
|
|
23319
23579
|
if (currentHash !== void 0 && currentHash === srcHash) {
|
|
23320
23580
|
this.recordSeed(name, currentHash);
|
|
23321
23581
|
return false;
|
|
@@ -23359,7 +23619,7 @@ var SkillsService = class _SkillsService {
|
|
|
23359
23619
|
if (entries.length !== 1 || entries[0].name !== "SKILL.md" || !entries[0].isFile()) return false;
|
|
23360
23620
|
let raw;
|
|
23361
23621
|
try {
|
|
23362
|
-
raw = readSkillText(
|
|
23622
|
+
raw = readSkillText(path32.join(dir, "SKILL.md"));
|
|
23363
23623
|
} catch {
|
|
23364
23624
|
return false;
|
|
23365
23625
|
}
|
|
@@ -23367,7 +23627,7 @@ var SkillsService = class _SkillsService {
|
|
|
23367
23627
|
}
|
|
23368
23628
|
pruneRetired() {
|
|
23369
23629
|
for (const name of RETIRED_BUILTIN_SKILL_NAMES) {
|
|
23370
|
-
const dest =
|
|
23630
|
+
const dest = path32.join(this.globalDir(), name);
|
|
23371
23631
|
if (!fs11.existsSync(dest)) continue;
|
|
23372
23632
|
if (!this.isUnmodifiedRetiredSeed(dest, name)) continue;
|
|
23373
23633
|
try {
|
|
@@ -23505,12 +23765,12 @@ var runGit = execFileWithTimeout(1e4);
|
|
|
23505
23765
|
async function committedInHead(files) {
|
|
23506
23766
|
const byDir = /* @__PURE__ */ new Map();
|
|
23507
23767
|
for (const file of new Set(files)) {
|
|
23508
|
-
const dir =
|
|
23768
|
+
const dir = path33.dirname(path33.dirname(file));
|
|
23509
23769
|
byDir.set(dir, [...byDir.get(dir) ?? [], file]);
|
|
23510
23770
|
}
|
|
23511
23771
|
const result = /* @__PURE__ */ new Map();
|
|
23512
23772
|
await Promise.all([...byDir].map(async ([dir, inDir]) => {
|
|
23513
|
-
const relative17 = (file) =>
|
|
23773
|
+
const relative17 = (file) => path33.relative(dir, file).split(path33.sep).join("/");
|
|
23514
23774
|
try {
|
|
23515
23775
|
const { stdout } = await runGit("git", ["ls-tree", "--name-only", "HEAD", "--", ...inDir.map(relative17)], { cwd: dir, env: cleanEnv() });
|
|
23516
23776
|
const listed3 = new Set(stdout.split("\n").map((line) => line.trim()).filter(Boolean));
|
|
@@ -23530,9 +23790,9 @@ function plannedSkillLookup(skillsAt, workspaceRoot, layout) {
|
|
|
23530
23790
|
searchedDirs: () => lookup2.searchedDirs(),
|
|
23531
23791
|
listSkills: () => lookup2.listSkills(),
|
|
23532
23792
|
uncommitted: async (skills) => {
|
|
23533
|
-
const checked = skills.filter((skill) => skill.source === "workspace" && !(readInPlace &&
|
|
23793
|
+
const checked = skills.filter((skill) => skill.source === "workspace" && !(readInPlace && path33.dirname(path33.dirname(skill.path)) === readInPlace));
|
|
23534
23794
|
const committed = await committedInHead(checked.map((skill) => skill.path));
|
|
23535
|
-
return new Map(checked.filter((skill) => committed.get(skill.path) === false).map((skill) => [skill.path,
|
|
23795
|
+
return new Map(checked.filter((skill) => committed.get(skill.path) === false).map((skill) => [skill.path, path33.relative(workspaceRoot, path33.dirname(skill.path)).split(path33.sep).join("/")]));
|
|
23536
23796
|
}
|
|
23537
23797
|
};
|
|
23538
23798
|
}
|
|
@@ -23545,13 +23805,13 @@ function checkPlanSkills(tasks, lookup2) {
|
|
|
23545
23805
|
function checkTaskSkillsEdit(task2, skills, lookup2) {
|
|
23546
23806
|
return check([{ taskId: task2.id, owner: `Task "${task2.title}"`, ...attached(skills) }], lookup2);
|
|
23547
23807
|
}
|
|
23548
|
-
function subtaskEntries(op, spec,
|
|
23808
|
+
function subtaskEntries(op, spec, path48 = []) {
|
|
23549
23809
|
const subtasks = spec?.subtasks;
|
|
23550
23810
|
if (!Array.isArray(subtasks)) return [];
|
|
23551
23811
|
return subtasks.flatMap((sub, i) => {
|
|
23552
23812
|
if (typeof sub !== "object" || sub === null) return [];
|
|
23553
23813
|
const child = sub;
|
|
23554
|
-
const at = [...
|
|
23814
|
+
const at = [...path48, typeof child.title === "string" && child.title.trim() ? `"${child.title}"` : `#${i + 1}`];
|
|
23555
23815
|
return [{ op, owner: `subtask ${at.join(" > ")}`, ...attached(child.skills) }, ...subtaskEntries(op, child, at)];
|
|
23556
23816
|
});
|
|
23557
23817
|
}
|
|
@@ -27421,7 +27681,7 @@ var RUN_SETTING_KEYS = Object.keys(RUN_SETTING_CHECKS);
|
|
|
27421
27681
|
function getSettingsPath() {
|
|
27422
27682
|
const override = process.env.ORDEWELL_SETTINGS_PATH;
|
|
27423
27683
|
if (override && override.trim()) return override.trim();
|
|
27424
|
-
return
|
|
27684
|
+
return path34.join(globalDataDir(), "settings.json");
|
|
27425
27685
|
}
|
|
27426
27686
|
function readPlannerModels(raw) {
|
|
27427
27687
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
@@ -27501,8 +27761,8 @@ var SettingsService = class {
|
|
|
27501
27761
|
* a watch on the old one pointing at nothing.
|
|
27502
27762
|
*/
|
|
27503
27763
|
watch(listener) {
|
|
27504
|
-
const dir =
|
|
27505
|
-
const name =
|
|
27764
|
+
const dir = path34.dirname(this.filePath);
|
|
27765
|
+
const name = path34.basename(this.filePath);
|
|
27506
27766
|
let seen = this.fileStamp();
|
|
27507
27767
|
let timer;
|
|
27508
27768
|
let dead = false;
|
|
@@ -27511,7 +27771,7 @@ var SettingsService = class {
|
|
|
27511
27771
|
fs12.mkdirSync(dir, { recursive: true });
|
|
27512
27772
|
watcher = fs12.watch(dir, (_event, changed) => {
|
|
27513
27773
|
if (dead) return;
|
|
27514
|
-
if (changed && changed !== name && changed !==
|
|
27774
|
+
if (changed && changed !== name && changed !== path34.basename(dir)) return;
|
|
27515
27775
|
clearTimeout(timer);
|
|
27516
27776
|
timer = setTimeout(() => {
|
|
27517
27777
|
const stamp2 = this.fileStamp();
|
|
@@ -27744,7 +28004,7 @@ var SettingsService = class {
|
|
|
27744
28004
|
if (this.unreadable) {
|
|
27745
28005
|
throw new Error(`Cannot save settings: ${this.filePath} could not be read, so it will not be overwritten. Fix or remove it and try again.`);
|
|
27746
28006
|
}
|
|
27747
|
-
const dir =
|
|
28007
|
+
const dir = path34.dirname(this.filePath);
|
|
27748
28008
|
if (!fs12.existsSync(dir)) {
|
|
27749
28009
|
fs12.mkdirSync(dir, { recursive: true });
|
|
27750
28010
|
}
|
|
@@ -28188,7 +28448,7 @@ var BaseConfig = class {
|
|
|
28188
28448
|
const { model, effort, override = "" } = configured;
|
|
28189
28449
|
const named3 = isPlannerBackend(configured.setting ?? "") || isPlannerBackend(process.env.AI_PROVIDER ?? "");
|
|
28190
28450
|
const pickedElsewhere = configured.pickedFor !== void 0 && configured.pickedFor !== provider;
|
|
28191
|
-
const kept = configured.pickedFor === provider || !pickedElsewhere && (isApiProvider(provider) || named3 && !isForeignModel(provider, model, this.agentCatalog(provider)));
|
|
28451
|
+
const kept = configured.pickedFor === provider || !pickedElsewhere && (isApiProvider(provider) || named3 && !isForeignModel(provider, model, () => this.agentCatalog(provider)));
|
|
28192
28452
|
if (kept) return { model: override || model, effort, source: override ? "request" : "configured" };
|
|
28193
28453
|
const own = pickedElsewhere || named3 ? rememberedOrDefault(provider) : detectedAgentChoice(provider, configured);
|
|
28194
28454
|
return !override || override === own.model ? own : { model: override, effort: "", source: "request" };
|
|
@@ -28197,7 +28457,8 @@ var BaseConfig = class {
|
|
|
28197
28457
|
* The model ids a coding agent was last discovered serving, empty while
|
|
28198
28458
|
* discovery is cold. A host that holds a runner catalog supplies it: it is
|
|
28199
28459
|
* the only evidence that tells OpenCode's `provider/model` ids from an
|
|
28200
|
-
* OpenRouter slug.
|
|
28460
|
+
* OpenRouter slug. Asked only when a named agent's configured model is
|
|
28461
|
+
* neither its alias nor its remembered pick.
|
|
28201
28462
|
*/
|
|
28202
28463
|
agentCatalog(_provider) {
|
|
28203
28464
|
return [];
|
|
@@ -28222,8 +28483,10 @@ function isVendorModelFor(agent, model) {
|
|
|
28222
28483
|
return !discoveryOf(agent)?.providerQualifiedIds && SLUG_SHAPE.test(model);
|
|
28223
28484
|
}
|
|
28224
28485
|
function isForeignModel(agent, model, catalog) {
|
|
28225
|
-
if (!model || isStableAlias(agent, model) ||
|
|
28226
|
-
|
|
28486
|
+
if (!model || isStableAlias(agent, model) || rememberedChoice(agent)?.model === model) return false;
|
|
28487
|
+
const listed3 = catalog();
|
|
28488
|
+
if (listed3.includes(model)) return false;
|
|
28489
|
+
return isVendorModelFor(agent, model) || listed3.length > 0 && SLUG_SHAPE.test(model);
|
|
28227
28490
|
}
|
|
28228
28491
|
function rememberedChoice(provider) {
|
|
28229
28492
|
const entry = new SettingsService().getPlannerModel(provider);
|
|
@@ -28343,11 +28606,11 @@ function mergeOutcome(result, branch, group, repaired = []) {
|
|
|
28343
28606
|
// src/services/taskDiffRead.ts
|
|
28344
28607
|
var import_crypto13 = require("crypto");
|
|
28345
28608
|
var fs13 = __toESM(require("fs"));
|
|
28346
|
-
var
|
|
28609
|
+
var path35 = __toESM(require("path"));
|
|
28347
28610
|
var import_os3 = require("os");
|
|
28348
28611
|
var TASK_DIFF_UNAVAILABLE = "Task diff is not available for this run: no task-specific changes were recorded (shared runs cannot attribute workspace changes to one task).";
|
|
28349
28612
|
function allowedPath(file) {
|
|
28350
|
-
return file.length > 0 && !
|
|
28613
|
+
return file.length > 0 && !path35.isAbsolute(file) && !/^[A-Za-z]:/.test(file) && !file.split(/[\\/]/).some((part) => part === ".." || part === ".git" || part === ".ordewell");
|
|
28351
28614
|
}
|
|
28352
28615
|
function stats(raw) {
|
|
28353
28616
|
return raw.split("\0").flatMap((row) => {
|
|
@@ -28356,8 +28619,8 @@ function stats(raw) {
|
|
|
28356
28619
|
});
|
|
28357
28620
|
}
|
|
28358
28621
|
function inside(root, target) {
|
|
28359
|
-
const rel =
|
|
28360
|
-
return rel === "" || !rel.startsWith(`..${
|
|
28622
|
+
const rel = path35.relative(root, target);
|
|
28623
|
+
return rel === "" || !rel.startsWith(`..${path35.sep}`) && rel !== ".." && !path35.isAbsolute(rel);
|
|
28361
28624
|
}
|
|
28362
28625
|
function unquoted(quoted4) {
|
|
28363
28626
|
const bytes = [];
|
|
@@ -28405,10 +28668,10 @@ function patchFiles(patch) {
|
|
|
28405
28668
|
const sections = patch.toString("utf8").split(/(?<![^\n])(?=diff --git )/).filter((section) => section.startsWith("diff --git "));
|
|
28406
28669
|
const files = /* @__PURE__ */ new Map();
|
|
28407
28670
|
for (const section of sections) {
|
|
28408
|
-
const
|
|
28671
|
+
const path48 = sectionPath(section);
|
|
28409
28672
|
const counts = sectionStats(section);
|
|
28410
|
-
const earlier = files.get(
|
|
28411
|
-
files.set(
|
|
28673
|
+
const earlier = files.get(path48);
|
|
28674
|
+
files.set(path48, earlier ? { path: path48, section: earlier.section + section, added: summed(earlier.added, counts.added), removed: summed(earlier.removed, counts.removed) } : { path: path48, section, ...counts });
|
|
28412
28675
|
}
|
|
28413
28676
|
return [...files.values()];
|
|
28414
28677
|
}
|
|
@@ -28478,11 +28741,11 @@ async function readTaskDiff(invoker, run, taskId, options) {
|
|
|
28478
28741
|
files.push({ ...file, repo: repo.path, patch: () => git(reader, cwd, [...diffArgs, "--", `:(top,literal)${prefix}${file.path}`]) });
|
|
28479
28742
|
}
|
|
28480
28743
|
if (live3) {
|
|
28481
|
-
const workspace =
|
|
28744
|
+
const workspace = path35.join(entry.worktree, prefix);
|
|
28482
28745
|
const others = await git(reader, workspace, [...common, "ls-files", "--others", "--exclude-standard", "-z", "--", "."]);
|
|
28483
28746
|
for (const file of others.split("\0").filter((f) => allowed(f))) {
|
|
28484
|
-
const full =
|
|
28485
|
-
if (!inside(fs13.realpathSync(workspace), fs13.realpathSync(
|
|
28747
|
+
const full = path35.join(workspace, file);
|
|
28748
|
+
if (!inside(fs13.realpathSync(workspace), fs13.realpathSync(path35.dirname(full)))) continue;
|
|
28486
28749
|
const untracked = async (numstat) => {
|
|
28487
28750
|
const result = await tryGit(reader, workspace, [...common, "diff", "--no-index", "--no-renames", "--no-ext-diff", "--no-textconv", ...numstat ? ["--numstat", "-z"] : [], "--", import_os3.devNull, file]);
|
|
28488
28751
|
if (!result.ok && result.code !== 1) throw new Error(result.stderr.trim() || "Could not read an untracked file diff.");
|
|
@@ -28512,11 +28775,11 @@ ${await file.patch()}`);
|
|
|
28512
28775
|
var import_crypto14 = require("crypto");
|
|
28513
28776
|
var import_child_process9 = require("child_process");
|
|
28514
28777
|
var fs15 = __toESM(require("fs"));
|
|
28515
|
-
var
|
|
28778
|
+
var path37 = __toESM(require("path"));
|
|
28516
28779
|
|
|
28517
28780
|
// src/utils/prdStore.ts
|
|
28518
28781
|
var fs14 = __toESM(require("fs"));
|
|
28519
|
-
var
|
|
28782
|
+
var path36 = __toESM(require("path"));
|
|
28520
28783
|
var PRD_BLOCK_RE = /<!--\s*ORDEWELL_PRD_START\s+slug="([^"]+)"\s*-->\s*([\s\S]*?)\s*<!--\s*ORDEWELL_PRD_END\s*-->/;
|
|
28521
28784
|
function extractPrdBlock(text6) {
|
|
28522
28785
|
const match = PRD_BLOCK_RE.exec(text6);
|
|
@@ -28530,9 +28793,9 @@ function sanitizeSlug(raw) {
|
|
|
28530
28793
|
return raw.toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
28531
28794
|
}
|
|
28532
28795
|
function savePrdMarkdown(workspace, slug, markdown) {
|
|
28533
|
-
const dir =
|
|
28796
|
+
const dir = path36.join(workspace, ".scratch", sanitizeSlug(slug));
|
|
28534
28797
|
fs14.mkdirSync(dir, { recursive: true });
|
|
28535
|
-
const file =
|
|
28798
|
+
const file = path36.join(dir, "PRD.md");
|
|
28536
28799
|
fs14.writeFileSync(file, markdown.endsWith("\n") ? markdown : markdown + "\n", "utf8");
|
|
28537
28800
|
return file;
|
|
28538
28801
|
}
|
|
@@ -28564,12 +28827,12 @@ var NESTED_REPO_DEPTH = 2;
|
|
|
28564
28827
|
var GITLINK_MODE = "160000";
|
|
28565
28828
|
var READ_ONLY = ["--no-optional-locks", "-c", "core.fsmonitor=false"];
|
|
28566
28829
|
function isInside(parent, child) {
|
|
28567
|
-
const rel =
|
|
28568
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
28830
|
+
const rel = path37.relative(parent, child);
|
|
28831
|
+
return rel !== "" && !rel.startsWith("..") && !path37.isAbsolute(rel);
|
|
28569
28832
|
}
|
|
28570
28833
|
function resolvesAsNamed(base, p) {
|
|
28571
28834
|
try {
|
|
28572
|
-
return fs15.realpathSync(p) ===
|
|
28835
|
+
return fs15.realpathSync(p) === path37.join(fs15.realpathSync(base), path37.relative(base, p));
|
|
28573
28836
|
} catch {
|
|
28574
28837
|
return false;
|
|
28575
28838
|
}
|
|
@@ -28624,7 +28887,7 @@ function sameDir(a, b) {
|
|
|
28624
28887
|
try {
|
|
28625
28888
|
return fs15.realpathSync.native(p);
|
|
28626
28889
|
} catch {
|
|
28627
|
-
return
|
|
28890
|
+
return path37.resolve(p);
|
|
28628
28891
|
}
|
|
28629
28892
|
};
|
|
28630
28893
|
return real(a) === real(b);
|
|
@@ -28646,7 +28909,7 @@ function clearImmutableFlags(platform, dir) {
|
|
|
28646
28909
|
(0, import_child_process9.spawnSync)("/usr/bin/chflags", ["-R", "nouchg", dir], { stdio: "ignore" });
|
|
28647
28910
|
}
|
|
28648
28911
|
function leftoverLinks(dir) {
|
|
28649
|
-
const named3 =
|
|
28912
|
+
const named3 = listDir2(dir).filter((name) => LINKED_ARTIFACTS.has(name) || isEnvFile(name) || isLink(path37.join(dir, name)));
|
|
28650
28913
|
return [.../* @__PURE__ */ new Set([...named3, ...installDirs(dir)])];
|
|
28651
28914
|
}
|
|
28652
28915
|
function isLink(target) {
|
|
@@ -28719,7 +28982,7 @@ var GitWorktreeIsolation = class {
|
|
|
28719
28982
|
const head = await this.headOf(root);
|
|
28720
28983
|
const repo = { path: repoPath, head };
|
|
28721
28984
|
if (scan.toplevel !== void 0) {
|
|
28722
|
-
const top =
|
|
28985
|
+
const top = path37.relative(workspaceRoot, scan.toplevel).split(path37.sep).join("/");
|
|
28723
28986
|
if (top !== "") repo.top = top;
|
|
28724
28987
|
}
|
|
28725
28988
|
if (enabled && (head.kind === "branch" || head.kind === "detached")) {
|
|
@@ -28776,9 +29039,9 @@ var GitWorktreeIsolation = class {
|
|
|
28776
29039
|
async nestedRepos(workspaceRoot, toplevel) {
|
|
28777
29040
|
const found = [];
|
|
28778
29041
|
const walk = (rel, depth) => {
|
|
28779
|
-
for (const name of childDirs(
|
|
29042
|
+
for (const name of childDirs(path37.join(workspaceRoot, rel))) {
|
|
28780
29043
|
const child = rel ? `${rel}/${name}` : name;
|
|
28781
|
-
if (hasGitEntry(
|
|
29044
|
+
if (hasGitEntry(path37.join(workspaceRoot, child))) found.push(child);
|
|
28782
29045
|
else if (depth < NESTED_REPO_DEPTH) walk(child, depth + 1);
|
|
28783
29046
|
}
|
|
28784
29047
|
};
|
|
@@ -28796,7 +29059,7 @@ var GitWorktreeIsolation = class {
|
|
|
28796
29059
|
const [meta, file] = entry.split(" ");
|
|
28797
29060
|
if (file !== void 0 && meta.startsWith(`${GITLINK_MODE} `)) paths.add(file);
|
|
28798
29061
|
}
|
|
28799
|
-
const declared = await this.tryGit(workspaceRoot, ["config", "-z", "-f",
|
|
29062
|
+
const declared = await this.tryGit(workspaceRoot, ["config", "-z", "-f", path37.join(toplevel, ".gitmodules"), "--get-regexp", "^submodule\\..*\\.path$"]);
|
|
28800
29063
|
for (const entry of declared.stdout.split("\0")) {
|
|
28801
29064
|
const value = entry.split("\n")[1];
|
|
28802
29065
|
if (value) paths.add(value.replace(/\/+$/, ""));
|
|
@@ -28854,7 +29117,7 @@ var GitWorktreeIsolation = class {
|
|
|
28854
29117
|
async acceptsWorktree(run, repo) {
|
|
28855
29118
|
const dir = this.integrationDir(run, repo);
|
|
28856
29119
|
ensureStateDirIgnored(run.workspaceRoot);
|
|
28857
|
-
fs15.mkdirSync(
|
|
29120
|
+
fs15.mkdirSync(path37.dirname(dir), { recursive: true });
|
|
28858
29121
|
const added = await this.tryGit(repo.root, ["worktree", "add", "-q", "--no-checkout", dir, repo.integrationBranch]);
|
|
28859
29122
|
await this.removeWorktreeDir(run, repo, dir, []);
|
|
28860
29123
|
return added.ok;
|
|
@@ -28869,12 +29132,12 @@ var GitWorktreeIsolation = class {
|
|
|
28869
29132
|
if (isolated.includes(SELF_REPO)) return [];
|
|
28870
29133
|
const shared2 = [];
|
|
28871
29134
|
const walk = (rel) => {
|
|
28872
|
-
for (const name of
|
|
29135
|
+
for (const name of listDir2(path37.join(workspaceRoot, rel))) {
|
|
28873
29136
|
if (!rel && (name === STATE_DIR || name === ".git")) continue;
|
|
28874
29137
|
const child = rel ? `${rel}/${name}` : name;
|
|
28875
29138
|
if (isolated.includes(child)) continue;
|
|
28876
29139
|
if (isolated.some((p) => p.startsWith(`${child}/`))) walk(child);
|
|
28877
|
-
else if (resolves(
|
|
29140
|
+
else if (resolves(path37.join(workspaceRoot, child))) shared2.push(child);
|
|
28878
29141
|
}
|
|
28879
29142
|
};
|
|
28880
29143
|
walk("");
|
|
@@ -28914,9 +29177,9 @@ var GitWorktreeIsolation = class {
|
|
|
28914
29177
|
try {
|
|
28915
29178
|
ensureStateDirIgnored(run.workspaceRoot);
|
|
28916
29179
|
for (const repo of run.repos) {
|
|
28917
|
-
const worktree =
|
|
29180
|
+
const worktree = path37.join(dir, repo.path);
|
|
28918
29181
|
const tip = (await this.git(repo.root, ["rev-parse", repo.integrationBranch])).trim();
|
|
28919
|
-
fs15.mkdirSync(
|
|
29182
|
+
fs15.mkdirSync(path37.dirname(worktree), { recursive: true });
|
|
28920
29183
|
await this.git(repo.root, ["worktree", "add", "-q", "-B", branch, worktree, tip]);
|
|
28921
29184
|
record.repos[repo.path] = { worktree, linked: [], baseRef: tip };
|
|
28922
29185
|
}
|
|
@@ -28941,13 +29204,13 @@ var GitWorktreeIsolation = class {
|
|
|
28941
29204
|
setupFailed.push({ repo: repo.path, detail: err.detail });
|
|
28942
29205
|
}
|
|
28943
29206
|
entry.linked = boot.linked;
|
|
28944
|
-
copied.push(...boot.copied.map((name) =>
|
|
29207
|
+
copied.push(...boot.copied.map((name) => path37.posix.join(repo.path, name)));
|
|
28945
29208
|
}
|
|
28946
29209
|
for (const rel of run.shared) {
|
|
28947
|
-
const source =
|
|
28948
|
-
const target =
|
|
29210
|
+
const source = path37.join(run.workspaceRoot, rel);
|
|
29211
|
+
const target = path37.join(cwd, rel);
|
|
28949
29212
|
if (!resolves(source) || lexists(target)) continue;
|
|
28950
|
-
fs15.mkdirSync(
|
|
29213
|
+
fs15.mkdirSync(path37.dirname(target), { recursive: true });
|
|
28951
29214
|
if (linkPath(source, target, this.platform) === "copy") copied.push(rel);
|
|
28952
29215
|
const entry = self ? record.repos[SELF_REPO] : void 0;
|
|
28953
29216
|
if (entry) entry.linked.push(rel);
|
|
@@ -28979,7 +29242,7 @@ var GitWorktreeIsolation = class {
|
|
|
28979
29242
|
*/
|
|
28980
29243
|
async clearLeftovers(run, task2, names) {
|
|
28981
29244
|
const removal = noRemoval();
|
|
28982
|
-
const holder = Object.values(run.tasks).find((r) => r.taskId !== task2.id && (r.branch === names.branch ||
|
|
29245
|
+
const holder = Object.values(run.tasks).find((r) => r.taskId !== task2.id && (r.branch === names.branch || path37.resolve(r.workspace) === path37.resolve(names.dir) || isInside(r.workspace, names.dir)));
|
|
28983
29246
|
if (holder) throw new Error(`Its worktree path or branch is held by the record of task ${holder.order} (${holder.title}); Ordewell will not remove it`);
|
|
28984
29247
|
const found = [];
|
|
28985
29248
|
for (const repo of run.repos) {
|
|
@@ -28989,14 +29252,14 @@ var GitWorktreeIsolation = class {
|
|
|
28989
29252
|
worktree: /^worktree (.+)$/m.exec(block)?.[1],
|
|
28990
29253
|
branch: /^branch refs\/heads\/(.+)$/m.exec(block)?.[1]
|
|
28991
29254
|
}));
|
|
28992
|
-
const at = /* @__PURE__ */ new Set([
|
|
29255
|
+
const at = /* @__PURE__ */ new Set([path37.join(names.dir, repo.path)]);
|
|
28993
29256
|
for (const entry of registered) {
|
|
28994
|
-
if (entry.worktree && entry.branch === names.branch && isInside(this.runRoot(run),
|
|
29257
|
+
if (entry.worktree && entry.branch === names.branch && isInside(this.runRoot(run), path37.resolve(entry.worktree))) at.add(entry.worktree);
|
|
28995
29258
|
}
|
|
28996
|
-
const base = { branch: names.branch, name:
|
|
29259
|
+
const base = { branch: names.branch, name: path37.basename(names.dir), title: task2.title };
|
|
28997
29260
|
for (const worktree of at) {
|
|
28998
29261
|
if (!fs15.existsSync(worktree)) continue;
|
|
28999
|
-
const linked = leftoverLinks(
|
|
29262
|
+
const linked = leftoverLinks(path37.join(worktree, await this.prefixOf(repo)));
|
|
29000
29263
|
found.push({ repo, worktree, target: { ...base, worktree, linked } });
|
|
29001
29264
|
}
|
|
29002
29265
|
found.push({ repo, worktree: names.dir, target: { ...base, linked: [] } });
|
|
@@ -29089,7 +29352,7 @@ var GitWorktreeIsolation = class {
|
|
|
29089
29352
|
*/
|
|
29090
29353
|
async inWorkspacePlace(repo, worktree) {
|
|
29091
29354
|
const prefix = await this.prefixOf(repo);
|
|
29092
|
-
return prefix ?
|
|
29355
|
+
return prefix ? path37.join(worktree, prefix) : worktree;
|
|
29093
29356
|
}
|
|
29094
29357
|
async prefixOf(repo) {
|
|
29095
29358
|
return (await this.git(repo.root, ["rev-parse", "--show-prefix"])).trim();
|
|
@@ -29619,15 +29882,15 @@ var GitWorktreeIsolation = class {
|
|
|
29619
29882
|
return landingMessage(kind, from, this.deps.plannedWith?.() ?? false);
|
|
29620
29883
|
}
|
|
29621
29884
|
integrationDir(run, repo) {
|
|
29622
|
-
return
|
|
29885
|
+
return path37.join(this.runRoot(run), INTEGRATION_DIR, repo.path);
|
|
29623
29886
|
}
|
|
29624
29887
|
async ensureIntegrationWorktree(run, repo) {
|
|
29625
29888
|
return this.admin(run.workspaceRoot, async () => {
|
|
29626
29889
|
const dir = this.integrationDir(run, repo);
|
|
29627
|
-
if (fs15.existsSync(
|
|
29890
|
+
if (fs15.existsSync(path37.join(dir, ".git"))) return dir;
|
|
29628
29891
|
await this.tryGit(repo.root, ["worktree", "prune"]);
|
|
29629
29892
|
ensureStateDirIgnored(run.workspaceRoot);
|
|
29630
|
-
fs15.mkdirSync(
|
|
29893
|
+
fs15.mkdirSync(path37.dirname(dir), { recursive: true });
|
|
29631
29894
|
await this.git(repo.root, ["worktree", "add", "-q", dir, repo.integrationBranch]);
|
|
29632
29895
|
return dir;
|
|
29633
29896
|
});
|
|
@@ -29650,7 +29913,7 @@ var GitWorktreeIsolation = class {
|
|
|
29650
29913
|
const removal = noRemoval();
|
|
29651
29914
|
for (const repo of opts.preserve === false || record.readOnly ? [] : run.repos) {
|
|
29652
29915
|
const entry = record.repos[repo.path];
|
|
29653
|
-
const target = { worktree: entry?.worktree, linked: entry?.linked ?? [], branch: record.branch, name:
|
|
29916
|
+
const target = { worktree: entry?.worktree, linked: entry?.linked ?? [], branch: record.branch, name: path37.basename(record.workspace), title: record.title, commit: record.commit };
|
|
29654
29917
|
try {
|
|
29655
29918
|
const kept = await this.preserve(run, repo, target, opts.intent);
|
|
29656
29919
|
if (kept) removal.preserved.push({ task: task2, ...kept });
|
|
@@ -29731,7 +29994,7 @@ var GitWorktreeIsolation = class {
|
|
|
29731
29994
|
return;
|
|
29732
29995
|
}
|
|
29733
29996
|
for (const entry of entries) {
|
|
29734
|
-
const target =
|
|
29997
|
+
const target = path37.join(dir, entry.name);
|
|
29735
29998
|
if (entry.isSymbolicLink()) this.unlinkIfLink(target);
|
|
29736
29999
|
else if (entry.isDirectory()) this.unlinkLinksUnder(target);
|
|
29737
30000
|
}
|
|
@@ -29753,20 +30016,20 @@ var GitWorktreeIsolation = class {
|
|
|
29753
30016
|
return false;
|
|
29754
30017
|
}
|
|
29755
30018
|
};
|
|
29756
|
-
const owned = new Set(Object.values(run.tasks).map((r) =>
|
|
30019
|
+
const owned = new Set(Object.values(run.tasks).map((r) => path37.resolve(r.workspace)));
|
|
29757
30020
|
const root = this.runRoot(run);
|
|
29758
30021
|
if (fs15.existsSync(root)) {
|
|
29759
30022
|
for (const entry of fs15.readdirSync(root)) {
|
|
29760
|
-
const dir =
|
|
29761
|
-
if (entry === INTEGRATION_DIR || owned.has(
|
|
30023
|
+
const dir = path37.join(root, entry);
|
|
30024
|
+
if (entry === INTEGRATION_DIR || owned.has(path37.resolve(dir))) continue;
|
|
29762
30025
|
let kept = true;
|
|
29763
30026
|
for (const repo of run.repos) {
|
|
29764
|
-
const worktree =
|
|
29765
|
-
const linked = leftoverLinks(
|
|
30027
|
+
const worktree = path37.join(dir, repo.path);
|
|
30028
|
+
const linked = leftoverLinks(path37.join(worktree, await this.prefixOf(repo)));
|
|
29766
30029
|
if (!await keep2(repo, { worktree, linked, branch: null, name: entry, title: entry }, worktree)) kept = false;
|
|
29767
30030
|
}
|
|
29768
30031
|
if (!kept) continue;
|
|
29769
|
-
for (const repo of run.repos) await this.removeWorktreeDir(run, repo,
|
|
30032
|
+
for (const repo of run.repos) await this.removeWorktreeDir(run, repo, path37.join(dir, repo.path), []);
|
|
29770
30033
|
this.removeTaskWorkspace(run, dir);
|
|
29771
30034
|
}
|
|
29772
30035
|
}
|
|
@@ -29784,13 +30047,13 @@ var GitWorktreeIsolation = class {
|
|
|
29784
30047
|
}
|
|
29785
30048
|
async removeWorktreeDir(run, repo, dir, linked) {
|
|
29786
30049
|
for (const name of /* @__PURE__ */ new Set([...linked, ...installDirs(dir)])) {
|
|
29787
|
-
const target =
|
|
29788
|
-
if (!resolvesAsNamed(this.runRoot(run),
|
|
30050
|
+
const target = path37.join(dir, name);
|
|
30051
|
+
if (!resolvesAsNamed(this.runRoot(run), path37.dirname(target))) continue;
|
|
29789
30052
|
this.unlinkIfLink(target);
|
|
29790
30053
|
this.unlinkLinksUnder(target);
|
|
29791
30054
|
}
|
|
29792
30055
|
for (const name of resolvesAsNamed(this.runRoot(run), dir) ? fs15.readdirSync(dir) : []) {
|
|
29793
|
-
if (LINKED_ARTIFACTS.has(name) || isEnvFile(name)) this.unlinkIfLink(
|
|
30056
|
+
if (LINKED_ARTIFACTS.has(name) || isEnvFile(name)) this.unlinkIfLink(path37.join(dir, name));
|
|
29794
30057
|
}
|
|
29795
30058
|
await this.tryGit(repo.root, ["worktree", "remove", "--force", dir]);
|
|
29796
30059
|
if (fs15.existsSync(dir) && isInside(this.runRoot(run), dir)) {
|
|
@@ -29798,7 +30061,7 @@ var GitWorktreeIsolation = class {
|
|
|
29798
30061
|
fs15.rmSync(dir, { recursive: true, force: true });
|
|
29799
30062
|
}
|
|
29800
30063
|
await this.tryGit(repo.root, ["worktree", "prune"]);
|
|
29801
|
-
for (let parent =
|
|
30064
|
+
for (let parent = path37.dirname(dir); isInside(this.runRoot(run), parent); parent = path37.dirname(parent)) this.removeIfEmpty(parent);
|
|
29802
30065
|
}
|
|
29803
30066
|
unlinkIfLink(target) {
|
|
29804
30067
|
try {
|
|
@@ -29813,14 +30076,14 @@ var GitWorktreeIsolation = class {
|
|
|
29813
30076
|
}
|
|
29814
30077
|
}
|
|
29815
30078
|
runRoot(run) {
|
|
29816
|
-
return
|
|
30079
|
+
return path37.join(run.workspaceRoot, STATE_DIR, "worktrees", run.id);
|
|
29817
30080
|
}
|
|
29818
30081
|
namesFor(run, task2) {
|
|
29819
30082
|
const slug = sanitizeSlug(task2.title).slice(0, 40).replace(/-+$/, "") || "task";
|
|
29820
30083
|
let name = `${task2.order}-${slug}`;
|
|
29821
30084
|
const clash = Object.values(run.tasks).some((r) => r.taskId !== task2.id && r.branch === `ordewell/${run.id}/${name}`);
|
|
29822
30085
|
if (clash) name = `${name}-${sanitizeSlug(task2.id) || "x"}`;
|
|
29823
|
-
return { branch: `ordewell/${run.id}/${name}`, dir:
|
|
30086
|
+
return { branch: `ordewell/${run.id}/${name}`, dir: path37.join(this.runRoot(run), name) };
|
|
29824
30087
|
}
|
|
29825
30088
|
async unmergedPaths(cwd) {
|
|
29826
30089
|
const listed3 = await this.tryGit(cwd, ["diff", "--name-only", "-z", "--diff-filter=U"]);
|
|
@@ -29834,7 +30097,7 @@ var GitWorktreeIsolation = class {
|
|
|
29834
30097
|
async rebaseInProgress(cwd) {
|
|
29835
30098
|
for (const dir of ["rebase-merge", "rebase-apply"]) {
|
|
29836
30099
|
const found = await this.tryGit(cwd, ["rev-parse", "--git-path", dir]);
|
|
29837
|
-
if (found.ok && fs15.existsSync(
|
|
30100
|
+
if (found.ok && fs15.existsSync(path37.resolve(cwd, found.stdout.trim()))) return true;
|
|
29838
30101
|
}
|
|
29839
30102
|
return false;
|
|
29840
30103
|
}
|
|
@@ -29942,7 +30205,7 @@ function handoffBaseLine(handoff, length) {
|
|
|
29942
30205
|
return handoff.repos.map((repo) => `${group ? `${repo.path}: ` : ""}${repoBaseLine(repo, length)}`).join(", ");
|
|
29943
30206
|
}
|
|
29944
30207
|
function repoResultLines(handoff) {
|
|
29945
|
-
return handoff.repos.map(({ path:
|
|
30208
|
+
return handoff.repos.map(({ path: path48, landed: landed2 }) => `${path48}: ${landed2.length === 0 ? "nothing to merge" : `${landed2.length} task${landed2.length === 1 ? "" : "s"} landed`}`);
|
|
29946
30209
|
}
|
|
29947
30210
|
|
|
29948
30211
|
// src/interfaces/ILogger.ts
|
|
@@ -33769,15 +34032,21 @@ var Landing = class {
|
|
|
33769
34032
|
* has landed. Its branch is on the integration branch by then, so it merges
|
|
33770
34033
|
* clean — and one the resolver did not really bring along conflicts again
|
|
33771
34034
|
* instead of being taken at its word. Null when there is nothing to land.
|
|
34035
|
+
* The task is named before its landing settles, so the caller can hold
|
|
34036
|
+
* its worktree for as long as the merge is in it; one the caller says is
|
|
34037
|
+
* `leaving` the plan is not landed at all.
|
|
33772
34038
|
*/
|
|
33773
|
-
|
|
34039
|
+
landResolved(resolverId, leaving = () => false) {
|
|
33774
34040
|
const conflictedId = this.runs.takeResolver(resolverId);
|
|
33775
|
-
if (!conflictedId) return null;
|
|
34041
|
+
if (!conflictedId || leaving(conflictedId)) return null;
|
|
33776
34042
|
const task2 = this.tasks.get(conflictedId);
|
|
33777
34043
|
if (!task2 || this.runs.current?.tasks[conflictedId]?.status !== "conflict") return null;
|
|
34044
|
+
return { task: task2, outcome: this.landConflicted(task2) };
|
|
34045
|
+
}
|
|
34046
|
+
async landConflicted(task2) {
|
|
33778
34047
|
const landing2 = await this.runs.integrate(task2);
|
|
33779
|
-
if (landing2 !== "merged") return
|
|
33780
|
-
return {
|
|
34048
|
+
if (landing2 !== "merged") return this.unmerged(task2, landing2);
|
|
34049
|
+
return { kind: "landed", messages: [{ level: "info", text: `Task "${task2.title}" landed through its conflict resolution.` }] };
|
|
33781
34050
|
}
|
|
33782
34051
|
/** The repair a conflicted task is owed next; null when repair is off, used up, or there is no isolated run to repair it in. */
|
|
33783
34052
|
nextRepair(taskId) {
|
|
@@ -34122,7 +34391,7 @@ function heldFrom(state) {
|
|
|
34122
34391
|
}
|
|
34123
34392
|
|
|
34124
34393
|
// src/services/Attempts.ts
|
|
34125
|
-
var
|
|
34394
|
+
var path40 = __toESM(require("path"));
|
|
34126
34395
|
|
|
34127
34396
|
// src/services/VerdictEngine.ts
|
|
34128
34397
|
var IDLE_TIMEOUT_MS = 10 * 6e4;
|
|
@@ -34230,6 +34499,18 @@ var VerdictEngine = class {
|
|
|
34230
34499
|
this.resumeIdle(taskId);
|
|
34231
34500
|
this.toolCheckpoints.get(taskId)?.({ kind: "rejected", reason });
|
|
34232
34501
|
}
|
|
34502
|
+
/**
|
|
34503
|
+
* An attempt's runner is being started, with no session to watch yet. Its
|
|
34504
|
+
* silence counts from here, so one whose start never resolves — stuck
|
|
34505
|
+
* launching, or waiting for its tools to attach — is flagged quiet as well.
|
|
34506
|
+
* {@link watch} starts the count again once the runner is up.
|
|
34507
|
+
*/
|
|
34508
|
+
starting(taskId) {
|
|
34509
|
+
const gen = this.bumpGeneration(taskId);
|
|
34510
|
+
this.idlePaused.delete(taskId);
|
|
34511
|
+
this.openApprovals.delete(taskId);
|
|
34512
|
+
this.touchIdle(taskId, gen);
|
|
34513
|
+
}
|
|
34233
34514
|
/**
|
|
34234
34515
|
* Attach to a spawned session. The runner's `task_complete` call on the
|
|
34235
34516
|
* attempt's token is the only completion evidence (ADR-0022, V2); a session
|
|
@@ -34240,6 +34521,9 @@ var VerdictEngine = class {
|
|
|
34240
34521
|
*/
|
|
34241
34522
|
watch(task2, session) {
|
|
34242
34523
|
const gen = this.bumpGeneration(task2.id);
|
|
34524
|
+
this.idlePaused.delete(task2.id);
|
|
34525
|
+
this.openApprovals.delete(task2.id);
|
|
34526
|
+
this.touchIdle(task2.id, gen);
|
|
34243
34527
|
session.onOutput(() => {
|
|
34244
34528
|
if (this.generations.get(task2.id) === gen) this.touchIdle(task2.id, gen);
|
|
34245
34529
|
});
|
|
@@ -34498,7 +34782,7 @@ function reportedVerdict(report) {
|
|
|
34498
34782
|
// src/services/ScriptRunner.ts
|
|
34499
34783
|
var import_child_process11 = require("child_process");
|
|
34500
34784
|
var fs16 = __toESM(require("fs"));
|
|
34501
|
-
var
|
|
34785
|
+
var path38 = __toESM(require("path"));
|
|
34502
34786
|
var import_events2 = require("events");
|
|
34503
34787
|
var import_string_decoder2 = require("string_decoder");
|
|
34504
34788
|
|
|
@@ -34639,7 +34923,7 @@ var ScriptSession = class extends AbstractRunnerSession {
|
|
|
34639
34923
|
async launchOf(step) {
|
|
34640
34924
|
if ("argv" in step) {
|
|
34641
34925
|
const [named3, ...args] = step.argv;
|
|
34642
|
-
const program = this.setup.platform === "win32" &&
|
|
34926
|
+
const program = this.setup.platform === "win32" && path38.win32.basename(named3) !== named3 && !path38.win32.isAbsolute(named3) ? path38.win32.resolve(this.setup.cwd, named3) : named3;
|
|
34643
34927
|
const plan = await planDirectLaunch(program, args, this.setup.launch);
|
|
34644
34928
|
return { file: plan.file, args: plan.args, shell: false, ...plan.verbatim ? { verbatim: true } : {} };
|
|
34645
34929
|
}
|
|
@@ -34874,8 +35158,8 @@ function passed(status) {
|
|
|
34874
35158
|
// src/services/PatchCapture.ts
|
|
34875
35159
|
var import_crypto15 = require("crypto");
|
|
34876
35160
|
var fs17 = __toESM(require("fs"));
|
|
34877
|
-
var
|
|
34878
|
-
var
|
|
35161
|
+
var os10 = __toESM(require("os"));
|
|
35162
|
+
var path39 = __toESM(require("path"));
|
|
34879
35163
|
|
|
34880
35164
|
// src/services/readTask.ts
|
|
34881
35165
|
function readTask2(args, readerId, plan, log) {
|
|
@@ -35142,7 +35426,7 @@ function linkInPatch(patch) {
|
|
|
35142
35426
|
function readOwn(scratch, name, max) {
|
|
35143
35427
|
let fd;
|
|
35144
35428
|
try {
|
|
35145
|
-
fd = fs17.openSync(
|
|
35429
|
+
fd = fs17.openSync(path39.join(scratch, name), fs17.constants.O_RDONLY | (fs17.constants.O_NOFOLLOW ?? 0));
|
|
35146
35430
|
} catch (err) {
|
|
35147
35431
|
throw new Refusal(`the capture left no ${name.split(".").pop()} Ordewell could read (${err.code ?? String(err)})`);
|
|
35148
35432
|
}
|
|
@@ -35180,7 +35464,7 @@ async function captureHeld(runs, opts, signal) {
|
|
|
35180
35464
|
const [worktree] = runs.worktrees;
|
|
35181
35465
|
const scratch = runs.scratch;
|
|
35182
35466
|
const tag = `ordewell-patch-${(0, import_crypto15.randomBytes)(8).toString("hex")}`;
|
|
35183
|
-
const stem =
|
|
35467
|
+
const stem = path39.join(scratch, tag);
|
|
35184
35468
|
const own = (suffix, max = LISTING_BYTES) => readOwn(scratch, `${tag}.${suffix}`, max);
|
|
35185
35469
|
try {
|
|
35186
35470
|
const stage = await runs.run(stageScript(stem, opts.linked ?? []), worktree);
|
|
@@ -35272,8 +35556,8 @@ async function indexEntries(invoker, worktree) {
|
|
|
35272
35556
|
return entries;
|
|
35273
35557
|
}
|
|
35274
35558
|
async function trialApply(invoker, worktree, patchFile, scratch) {
|
|
35275
|
-
const index =
|
|
35276
|
-
const copy =
|
|
35559
|
+
const index = path39.resolve(worktree, (await git(invoker, worktree, [...APPLY_GIT, "rev-parse", "--git-path", "index"])).trim());
|
|
35560
|
+
const copy = path39.join(scratch, "index");
|
|
35277
35561
|
fs17.copyFileSync(index, copy);
|
|
35278
35562
|
const trial = { ...invoker, exec: (file, args, opts) => invoker.exec(file, args, { ...opts, env: { ...opts.env, GIT_INDEX_FILE: copy } }) };
|
|
35279
35563
|
const tried = await tryGit(trial, worktree, [...APPLY_GIT, "apply", "--cached", "--3way", "--whitespace=nowarn", patchFile]);
|
|
@@ -35293,7 +35577,7 @@ function gitRefused(lead, stderr) {
|
|
|
35293
35577
|
function onDisk3(worktree, names) {
|
|
35294
35578
|
return names.map((name) => {
|
|
35295
35579
|
try {
|
|
35296
|
-
const stat = fs17.lstatSync(
|
|
35580
|
+
const stat = fs17.lstatSync(path39.join(worktree, name), { bigint: true, throwIfNoEntry: false });
|
|
35297
35581
|
return stat ? `${stat.mode} ${stat.ino} ${stat.size} ${stat.mtimeNs} ${stat.ctimeNs}` : "none";
|
|
35298
35582
|
} catch (err) {
|
|
35299
35583
|
return err.code ?? "unreadable";
|
|
@@ -35333,7 +35617,7 @@ function leavesWorktree(worktree, names, linked, held2, left) {
|
|
|
35333
35617
|
if (i < parts.length && held2.get(at)?.some((entry) => entry.mode === SUBMODULE)) {
|
|
35334
35618
|
return `the patch writes ${name}, under ${at}, a submodule, whose files are another repository's.`;
|
|
35335
35619
|
}
|
|
35336
|
-
const full =
|
|
35620
|
+
const full = path39.join(worktree, ...parts.slice(0, i));
|
|
35337
35621
|
const stat = fs17.lstatSync(full, { throwIfNoEntry: false });
|
|
35338
35622
|
if (!stat) break;
|
|
35339
35623
|
const last = i === parts.length;
|
|
@@ -35361,7 +35645,7 @@ async function applyPatch(invoker, worktree, patch, saved, opts = {}) {
|
|
|
35361
35645
|
if (link !== void 0) {
|
|
35362
35646
|
return refused4(`the patch holds a link or a submodule (${JSON.stringify(link.slice(0, 80))}), which a saved patch never does, so it is not one that was saved.`);
|
|
35363
35647
|
}
|
|
35364
|
-
const dir = fs17.mkdtempSync(
|
|
35648
|
+
const dir = fs17.mkdtempSync(path39.join(os10.tmpdir(), "ordewell-apply-"));
|
|
35365
35649
|
try {
|
|
35366
35650
|
const toplevel = (await git(invoker, worktree, [...APPLY_GIT, "rev-parse", "--show-toplevel"])).trim();
|
|
35367
35651
|
if (fs17.realpathSync(toplevel) !== fs17.realpathSync(worktree)) return refused4(`${worktree} is not the root of a worktree of its own.`);
|
|
@@ -35371,7 +35655,7 @@ async function applyPatch(invoker, worktree, patch, saved, opts = {}) {
|
|
|
35371
35655
|
}
|
|
35372
35656
|
const before = await unmergedPaths(invoker, worktree);
|
|
35373
35657
|
if (before.length > 0) return refused4(`your worktree still has unresolved conflicts (${listed(before.slice(0, 10))}${before.length > 10 ? `, +${before.length - 10} more` : ""}). Resolve them and git add them, or undo them, then apply the patch.`);
|
|
35374
|
-
const file =
|
|
35658
|
+
const file = path39.join(dir, "saved.patch");
|
|
35375
35659
|
fs17.writeFileSync(file, patch, { flag: "wx", mode: 384 });
|
|
35376
35660
|
const held2 = await indexEntries(invoker, worktree);
|
|
35377
35661
|
const named3 = await pathsNamed(invoker, worktree, file);
|
|
@@ -35607,6 +35891,10 @@ var Attempts = class {
|
|
|
35607
35891
|
receipt(taskId) {
|
|
35608
35892
|
return this.live.get(taskId)?.receipt ?? null;
|
|
35609
35893
|
}
|
|
35894
|
+
/** Which spawn of the live attempt's runner waits for Ordewell's tools to connect; null when none does. */
|
|
35895
|
+
attaching(taskId) {
|
|
35896
|
+
return this.live.get(taskId)?.attaching ?? null;
|
|
35897
|
+
}
|
|
35610
35898
|
/** The kind a task's next attempt starts as, short of a repair or a continue: what is weighed before one exists. */
|
|
35611
35899
|
nextKind(taskId) {
|
|
35612
35900
|
const task2 = this.deps.store.get(taskId);
|
|
@@ -35647,7 +35935,9 @@ var Attempts = class {
|
|
|
35647
35935
|
shell: null,
|
|
35648
35936
|
web: null,
|
|
35649
35937
|
patch: null,
|
|
35650
|
-
receipt: null
|
|
35938
|
+
receipt: null,
|
|
35939
|
+
attaching: null,
|
|
35940
|
+
spawning: new AbortController()
|
|
35651
35941
|
};
|
|
35652
35942
|
this.spawnCounts.set(task2.id, attempt.attempt);
|
|
35653
35943
|
this.live.set(task2.id, attempt);
|
|
@@ -35662,7 +35952,8 @@ var Attempts = class {
|
|
|
35662
35952
|
/**
|
|
35663
35953
|
* The one way an attempt ends. Dropping the record is itself what
|
|
35664
35954
|
* invalidates a spawn still in flight ({@link run} kills the session it
|
|
35665
|
-
* receives for an attempt that is no longer current)
|
|
35955
|
+
* receives for an attempt that is no longer current), and its cancel takes
|
|
35956
|
+
* back a runner still starting meanwhile.
|
|
35666
35957
|
*
|
|
35667
35958
|
* A user interruption also bumps the verifier's generation *before* stopping
|
|
35668
35959
|
* the runner: a runner may fire onExit synchronously from
|
|
@@ -35678,6 +35969,7 @@ var Attempts = class {
|
|
|
35678
35969
|
const session = attempt?.session ?? null;
|
|
35679
35970
|
const nativeSessionId = session?.nativeSessionId() ?? null;
|
|
35680
35971
|
if (attempt) {
|
|
35972
|
+
attempt.spawning.abort();
|
|
35681
35973
|
store.endAttemptUsage(taskId, attempt.attempt, (/* @__PURE__ */ new Date()).toISOString(), session?.sessionCost?.() ?? void 0, nativeSessionId ?? void 0);
|
|
35682
35974
|
this.deps.output.detach(taskId);
|
|
35683
35975
|
attempt.shell?.end();
|
|
@@ -35854,12 +36146,14 @@ var Attempts = class {
|
|
|
35854
36146
|
this.abandonSpawn(task2, attempt);
|
|
35855
36147
|
return false;
|
|
35856
36148
|
}
|
|
36149
|
+
this.verifier.starting(task2.id);
|
|
35857
36150
|
const session = attempt.script ? await this.spawnScript(task2, attempt, cwd) : await this.spawnRunner(task2, attempt, cwd, worktree ? workspace : void 0, previousWork);
|
|
35858
36151
|
if (this.live.get(task2.id) !== attempt) {
|
|
35859
36152
|
this.abandonSpawn(task2, attempt, session);
|
|
35860
36153
|
return false;
|
|
35861
36154
|
}
|
|
35862
36155
|
attempt.phase = "running";
|
|
36156
|
+
attempt.attaching = null;
|
|
35863
36157
|
attempt.session = session;
|
|
35864
36158
|
store.setTaskRunnerSessionId(task2.id, void 0);
|
|
35865
36159
|
store.clearCarriedFrom(task2.id);
|
|
@@ -36005,7 +36299,13 @@ var Attempts = class {
|
|
|
36005
36299
|
...web ? { webReads: web } : {},
|
|
36006
36300
|
applyPatch: (args) => this.applyPatch(task2, attempt, args),
|
|
36007
36301
|
workspaceRoot: this.deps.workspaceRoot(),
|
|
36008
|
-
onNotice: (message) => this.host.tell("warn", `Task "${task2.title}": ${message}`)
|
|
36302
|
+
onNotice: (message) => this.host.tell("warn", `Task "${task2.title}": ${message}`),
|
|
36303
|
+
cancelled: attempt.spawning.signal,
|
|
36304
|
+
onAttaching: (spawn) => {
|
|
36305
|
+
if (this.live.get(task2.id) !== attempt) return;
|
|
36306
|
+
attempt.attaching = spawn;
|
|
36307
|
+
this.host.emit("onTaskChanged");
|
|
36308
|
+
}
|
|
36009
36309
|
});
|
|
36010
36310
|
}
|
|
36011
36311
|
/**
|
|
@@ -36058,9 +36358,9 @@ var Attempts = class {
|
|
|
36058
36358
|
const repos = Object.values(this.deps.runs.openRecord(taskId)?.repos ?? {});
|
|
36059
36359
|
if (repos.length !== 1 || cwd === null) return [];
|
|
36060
36360
|
const [{ worktree, linked }] = repos;
|
|
36061
|
-
const prefix =
|
|
36062
|
-
if (prefix.startsWith("..") ||
|
|
36063
|
-
return linked.map((name) => (prefix ? `${prefix}/${name}` : name).split(
|
|
36361
|
+
const prefix = path40.relative(worktree, cwd).split(path40.sep).join("/");
|
|
36362
|
+
if (prefix.startsWith("..") || path40.isAbsolute(prefix)) return [];
|
|
36363
|
+
return linked.map((name) => (prefix ? `${prefix}/${name}` : name).split(path40.sep).join("/"));
|
|
36064
36364
|
}
|
|
36065
36365
|
/**
|
|
36066
36366
|
* A script task's start (ADR-0035): its body as the plan holds it now, run
|
|
@@ -36098,7 +36398,7 @@ var Attempts = class {
|
|
|
36098
36398
|
this.deps.notifications.warn(message);
|
|
36099
36399
|
};
|
|
36100
36400
|
if (resolved.blockedEnvrc) {
|
|
36101
|
-
warn(`blocked:${resolved.blockedEnvrc}`, `direnv has blocked ${resolved.blockedEnvrc}, so tasks start without its variables. Run \`direnv allow\` in ${
|
|
36401
|
+
warn(`blocked:${resolved.blockedEnvrc}`, `direnv has blocked ${resolved.blockedEnvrc}, so tasks start without its variables. Run \`direnv allow\` in ${path40.dirname(resolved.blockedEnvrc)} to use them.`);
|
|
36102
36402
|
}
|
|
36103
36403
|
if (resolved.trackedEnvFile) {
|
|
36104
36404
|
warn(`tracked:${resolved.trackedEnvFile}`, `Ignored ${resolved.trackedEnvFile}: git tracks it, and a committed file must not choose the environment agents run in. Untrack it to use it.`);
|
|
@@ -36124,7 +36424,7 @@ var Attempts = class {
|
|
|
36124
36424
|
uncommittedSkillFolder(name) {
|
|
36125
36425
|
const root = this.deps.workspaceRoot();
|
|
36126
36426
|
const skill = this.deps.skillsAt(this.skillRoots(root)).findSkill(name);
|
|
36127
|
-
return skill?.source === "workspace" ?
|
|
36427
|
+
return skill?.source === "workspace" ? path40.relative(root, path40.dirname(skill.path)).split(path40.sep).join("/") : void 0;
|
|
36128
36428
|
}
|
|
36129
36429
|
/**
|
|
36130
36430
|
* The roots whose `.ordewell/skills/` an attempt at `cwd` reads: in a repo
|
|
@@ -36554,12 +36854,12 @@ function ancestors(task2, store) {
|
|
|
36554
36854
|
|
|
36555
36855
|
// src/services/sessionLease.ts
|
|
36556
36856
|
var fs19 = __toESM(require("fs"));
|
|
36557
|
-
var
|
|
36857
|
+
var path42 = __toESM(require("path"));
|
|
36558
36858
|
var import_crypto17 = require("crypto");
|
|
36559
36859
|
|
|
36560
36860
|
// src/utils/sessionStore.ts
|
|
36561
36861
|
var fs18 = __toESM(require("fs"));
|
|
36562
|
-
var
|
|
36862
|
+
var path41 = __toESM(require("path"));
|
|
36563
36863
|
|
|
36564
36864
|
// src/utils/sessionId.ts
|
|
36565
36865
|
var import_crypto16 = require("crypto");
|
|
@@ -36570,13 +36870,13 @@ function mintSessionId() {
|
|
|
36570
36870
|
// src/utils/sessionStore.ts
|
|
36571
36871
|
var SESSIONS_SUBDIR = "sessions";
|
|
36572
36872
|
function getSessionsDir(baseDir) {
|
|
36573
|
-
return
|
|
36873
|
+
return path41.join(getStateDir(baseDir), SESSIONS_SUBDIR);
|
|
36574
36874
|
}
|
|
36575
36875
|
function idSegment(id2) {
|
|
36576
36876
|
return /^[A-Za-z0-9_-][A-Za-z0-9._-]{0,127}$/.test(id2) ? id2 : `~${Buffer.from(id2, "utf-8").toString("hex")}`;
|
|
36577
36877
|
}
|
|
36578
36878
|
function sessionDataDir(sessionId, baseDir) {
|
|
36579
|
-
return
|
|
36879
|
+
return path41.join(getSessionsDir(baseDir), idSegment(sessionId));
|
|
36580
36880
|
}
|
|
36581
36881
|
var REJECTION_MESSAGE = "This session was created with an older version of Ordewell. Please re-plan.";
|
|
36582
36882
|
function isSessionMeta(value) {
|
|
@@ -36603,8 +36903,8 @@ function legacySessionFilename(session) {
|
|
|
36603
36903
|
return `${filenameStem(session)}_${session.id.slice(0, 8)}.json`;
|
|
36604
36904
|
}
|
|
36605
36905
|
function dropLegacyFile(sessionsDir, meta) {
|
|
36606
|
-
const legacy =
|
|
36607
|
-
if (legacy ===
|
|
36906
|
+
const legacy = path41.join(sessionsDir, legacySessionFilename(meta));
|
|
36907
|
+
if (legacy === path41.join(sessionsDir, sessionFilename(meta)) || !fs18.existsSync(legacy)) return;
|
|
36608
36908
|
try {
|
|
36609
36909
|
const held2 = JSON.parse(fs18.readFileSync(legacy, "utf-8")).meta?.id;
|
|
36610
36910
|
if (held2 === meta.id) fs18.unlinkSync(legacy);
|
|
@@ -36631,7 +36931,7 @@ function saveSession(plan, goal, baseDir, id2) {
|
|
|
36631
36931
|
};
|
|
36632
36932
|
dropRetiredPlanFields(session.plan);
|
|
36633
36933
|
const filename = sessionFilename(meta);
|
|
36634
|
-
const filePath =
|
|
36934
|
+
const filePath = path41.join(sessionsDir, filename);
|
|
36635
36935
|
writeFileAtomic(filePath, JSON.stringify(session, null, 2));
|
|
36636
36936
|
dropLegacyFile(sessionsDir, meta);
|
|
36637
36937
|
return meta;
|
|
@@ -36643,7 +36943,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
36643
36943
|
return files.map((f) => {
|
|
36644
36944
|
let parsed;
|
|
36645
36945
|
try {
|
|
36646
|
-
parsed = JSON.parse(fs18.readFileSync(
|
|
36946
|
+
parsed = JSON.parse(fs18.readFileSync(path41.join(sessionsDir, f), "utf-8"));
|
|
36647
36947
|
} catch (err) {
|
|
36648
36948
|
if (err instanceof SyntaxError) return moveAside(sessionsDir, f, "is not valid JSON", logger);
|
|
36649
36949
|
logger.warn("sessionStore", `failed to read session file ${f}; skipping`, err);
|
|
@@ -36664,7 +36964,7 @@ function listSessions(baseDir, logger = defaultLogger) {
|
|
|
36664
36964
|
function moveAside(sessionsDir, file, reason, logger) {
|
|
36665
36965
|
const aside = `${file}.${Date.now()}.corrupt`;
|
|
36666
36966
|
try {
|
|
36667
|
-
fs18.renameSync(
|
|
36967
|
+
fs18.renameSync(path41.join(sessionsDir, file), path41.join(sessionsDir, aside));
|
|
36668
36968
|
logger.warn("sessionStore", `session file ${file} ${reason}; moved aside to ${aside} rather than overwritten`);
|
|
36669
36969
|
} catch {
|
|
36670
36970
|
logger.warn("sessionStore", `failed to read session file ${file}; skipping`);
|
|
@@ -36675,7 +36975,7 @@ function findSessionFile(sessionsDir, sessionId, logger) {
|
|
|
36675
36975
|
const files = fs18.readdirSync(sessionsDir).filter((f) => f.endsWith(".json"));
|
|
36676
36976
|
for (const f of files) {
|
|
36677
36977
|
try {
|
|
36678
|
-
const raw = fs18.readFileSync(
|
|
36978
|
+
const raw = fs18.readFileSync(path41.join(sessionsDir, f), "utf-8");
|
|
36679
36979
|
const session = JSON.parse(raw);
|
|
36680
36980
|
if (session.meta.id === sessionId) return f;
|
|
36681
36981
|
} catch (err) {
|
|
@@ -36690,7 +36990,7 @@ function loadSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
36690
36990
|
try {
|
|
36691
36991
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
36692
36992
|
if (file) {
|
|
36693
|
-
const raw = fs18.readFileSync(
|
|
36993
|
+
const raw = fs18.readFileSync(path41.join(sessionsDir, file), "utf-8");
|
|
36694
36994
|
const parsed = JSON.parse(raw);
|
|
36695
36995
|
if (hasScalarRunner(parsed)) {
|
|
36696
36996
|
logger.warn("sessionStore", `session file ${file}: ${REJECTION_MESSAGE}`);
|
|
@@ -36732,7 +37032,7 @@ function deleteSession(sessionId, baseDir, logger = defaultLogger) {
|
|
|
36732
37032
|
try {
|
|
36733
37033
|
const file = findSessionFile(sessionsDir, sessionId, logger);
|
|
36734
37034
|
if (file) {
|
|
36735
|
-
fs18.unlinkSync(
|
|
37035
|
+
fs18.unlinkSync(path41.join(sessionsDir, file));
|
|
36736
37036
|
return true;
|
|
36737
37037
|
}
|
|
36738
37038
|
} catch (err) {
|
|
@@ -36785,7 +37085,7 @@ var UNLEASED = {
|
|
|
36785
37085
|
};
|
|
36786
37086
|
var hostsHere = /* @__PURE__ */ new Set();
|
|
36787
37087
|
function leaseFile(sessionId, workspace) {
|
|
36788
|
-
return
|
|
37088
|
+
return path42.join(sessionDataDir(sessionId, workspace), LEASE_FILE);
|
|
36789
37089
|
}
|
|
36790
37090
|
function isRecord9(value) {
|
|
36791
37091
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -36874,7 +37174,7 @@ var LeaseHost = class {
|
|
|
36874
37174
|
*/
|
|
36875
37175
|
acquire(file, workspace, holder) {
|
|
36876
37176
|
ensureStateDirIgnored(workspace);
|
|
36877
|
-
ensurePrivateDir(
|
|
37177
|
+
ensurePrivateDir(path42.dirname(file));
|
|
36878
37178
|
const outcome = withFileLock(file, () => {
|
|
36879
37179
|
const current = readRecord(file);
|
|
36880
37180
|
const taken = current !== null && current.hostId !== this.id ? current : null;
|
|
@@ -36929,7 +37229,7 @@ var LeaseHost = class {
|
|
|
36929
37229
|
withFileLock(file, () => {
|
|
36930
37230
|
if (readRecord(file)?.hostId === this.id) fs19.rmSync(file, { force: true });
|
|
36931
37231
|
}, "release a session lease");
|
|
36932
|
-
fs19.rmdirSync(
|
|
37232
|
+
fs19.rmdirSync(path42.dirname(file));
|
|
36933
37233
|
} catch {
|
|
36934
37234
|
}
|
|
36935
37235
|
}
|
|
@@ -37122,10 +37422,14 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
37122
37422
|
/** Conflict repairs owed with every slot taken and no scheduler to claim them: a freed slot starts them. */
|
|
37123
37423
|
owedRepairs = /* @__PURE__ */ new Set();
|
|
37124
37424
|
/**
|
|
37125
|
-
* Tasks Mark complete is landing after it ended their attempt
|
|
37126
|
-
*
|
|
37425
|
+
* Tasks Mark complete is landing after it ended their attempt, or that
|
|
37426
|
+
* their conflict resolver is landing, and that landing: in progress with
|
|
37427
|
+
* no attempt for as long as it takes, and not orphans for it. Both can be
|
|
37428
|
+
* landing one task at once, so each holds it for itself (see {@link holdWhileLanding}).
|
|
37127
37429
|
*/
|
|
37128
|
-
completing = /* @__PURE__ */ new
|
|
37430
|
+
completing = /* @__PURE__ */ new Map();
|
|
37431
|
+
/** Tasks {@link releaseTask} is tearing down once their landings have settled: none may begin another. */
|
|
37432
|
+
releasing = /* @__PURE__ */ new Set();
|
|
37129
37433
|
/** Tasks paused on a usage limit, the run's hold on them, and each runner's wait for its reset (ADR-0018, U1). */
|
|
37130
37434
|
limitPauses;
|
|
37131
37435
|
/**
|
|
@@ -37261,6 +37565,10 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
37261
37565
|
getCompletionReceipt(taskId) {
|
|
37262
37566
|
return this.attempts.receipt(taskId);
|
|
37263
37567
|
}
|
|
37568
|
+
/** Which spawn of a live attempt's runner waits for Ordewell's tools to connect (ADR-0025); null when none does. */
|
|
37569
|
+
getToolsAttaching(taskId) {
|
|
37570
|
+
return this.attempts.attaching(taskId);
|
|
37571
|
+
}
|
|
37264
37572
|
/** Recent clean output of a task's latest attempt, running or ended; null if it never ran. */
|
|
37265
37573
|
getLiveOutput(taskId, opts) {
|
|
37266
37574
|
return this.attempts.liveTail(taskId, opts);
|
|
@@ -37425,12 +37733,13 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
37425
37733
|
/**
|
|
37426
37734
|
* Something can still start that nobody has to ask for again: a start
|
|
37427
37735
|
* admitted and not yet claimed, a force start queued behind its
|
|
37428
|
-
* dependencies, a
|
|
37429
|
-
*
|
|
37430
|
-
* replay. A Stop is owed to
|
|
37736
|
+
* dependencies, a conflict repair owed a slot or the end of a start hold,
|
|
37737
|
+
* a task that resumes on its own at its usage limit's reset, or a start a
|
|
37738
|
+
* dirty checkout parked for Stash and continue to replay. A Stop is owed to
|
|
37739
|
+
* it, whether or not anything runs.
|
|
37431
37740
|
*/
|
|
37432
37741
|
get startsPending() {
|
|
37433
|
-
return this.admissions > 0 || this.queuedStarts.size > 0 || this.runs.blocked || this.store.allTasks.some(waitsForReset);
|
|
37742
|
+
return this.admissions > 0 || this.queuedStarts.size > 0 || this.owedRepairs.size > 0 || this.runs.blocked || this.store.allTasks.some(waitsForReset);
|
|
37434
37743
|
}
|
|
37435
37744
|
/**
|
|
37436
37745
|
* The plan's activity as one word for every surface: a start on its way,
|
|
@@ -37931,6 +38240,7 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
37931
38240
|
* Work that did not land waits on the user — it never fails the task or
|
|
37932
38241
|
* blocks its dependents — unless its conflict is owed a repair, which takes
|
|
37933
38242
|
* the slot the ending attempt freed and never one more than the run allows.
|
|
38243
|
+
* A planner turn's start hold holds it as it holds any new spawn (ADR-0029).
|
|
37934
38244
|
* The repair follows on from the start whose work it repairs: a Stop since
|
|
37935
38245
|
* that was admitted withdraws it.
|
|
37936
38246
|
*/
|
|
@@ -37938,20 +38248,22 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
37938
38248
|
this.store.markAwaitingUser(task2.id, "conflict");
|
|
37939
38249
|
this.say(outcome.messages);
|
|
37940
38250
|
if (outcome.kind !== "repair-needed") return;
|
|
37941
|
-
|
|
38251
|
+
const waitsFor = this.startHolds > 0 ? "the planner's turn ends" : this.slotsFull() ? "a slot is free" : null;
|
|
38252
|
+
if (!waitsFor) {
|
|
37942
38253
|
const claimed = this.claim(task2.id, admission);
|
|
37943
38254
|
if ("refused" in claimed) this.tell("warn", `The conflict of task "${task2.title}" is not repaired: ${claimed.refused}`);
|
|
37944
38255
|
else this.unawaited(claimed.spawned, `Could not start the repair of task "${task2.title}"`);
|
|
37945
38256
|
} else {
|
|
37946
38257
|
this.store.markPending(task2.id);
|
|
37947
38258
|
if (!this.isScheduling) this.owedRepairs.add(task2.id);
|
|
37948
|
-
this.tell("info", `Task "${task2.title}" is repaired once
|
|
38259
|
+
this.tell("info", `Task "${task2.title}" is repaired once ${waitsFor}.`);
|
|
37949
38260
|
}
|
|
37950
38261
|
}
|
|
37951
|
-
/** Start the repairs {@link settleUnlanded} left owed, as slots allow. */
|
|
38262
|
+
/** Start the repairs {@link settleUnlanded} left owed, as slots and any start hold allow. */
|
|
37952
38263
|
startOwedRepairs(admission) {
|
|
38264
|
+
if (this.startHolds > 0) return;
|
|
37953
38265
|
for (const id2 of [...this.owedRepairs]) {
|
|
37954
|
-
if (this.
|
|
38266
|
+
if (this.slotsFull()) return;
|
|
37955
38267
|
this.owedRepairs.delete(id2);
|
|
37956
38268
|
const task2 = this.store.get(id2);
|
|
37957
38269
|
if (!task2 || task2.status !== "pending" || this.attempts.has(id2) || !this.landing.nextRepair(id2)) continue;
|
|
@@ -37961,13 +38273,31 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
37961
38273
|
}
|
|
37962
38274
|
}
|
|
37963
38275
|
async landResolved(resolverId, admission) {
|
|
37964
|
-
const resolved =
|
|
38276
|
+
const resolved = this.landing.landResolved(resolverId, (id2) => this.releasing.has(id2));
|
|
37965
38277
|
if (!resolved) return;
|
|
37966
|
-
const { task: task2
|
|
38278
|
+
const { task: task2 } = resolved;
|
|
38279
|
+
const outcome = await this.holdWhileLanding(task2.id, resolved.outcome);
|
|
38280
|
+
if (this.store.get(task2.id)?.status === "completed") return;
|
|
37967
38281
|
await this.applyLanding(task2, outcome, admission, () => {
|
|
37968
38282
|
if (task2.verdict) this.logAndArchive(task2, task2.verdict);
|
|
37969
38283
|
});
|
|
37970
38284
|
}
|
|
38285
|
+
/**
|
|
38286
|
+
* Hold a task for as long as `landing` is merging its worktree. Its end lets
|
|
38287
|
+
* go of its own hold only: another landing of the task begun meanwhile
|
|
38288
|
+
* still holds it.
|
|
38289
|
+
*/
|
|
38290
|
+
async holdWhileLanding(taskId, landing2) {
|
|
38291
|
+
const holds2 = this.completing.get(taskId) ?? /* @__PURE__ */ new Set();
|
|
38292
|
+
holds2.add(landing2);
|
|
38293
|
+
this.completing.set(taskId, holds2);
|
|
38294
|
+
try {
|
|
38295
|
+
return await landing2;
|
|
38296
|
+
} finally {
|
|
38297
|
+
holds2.delete(landing2);
|
|
38298
|
+
if (holds2.size === 0 && this.completing.get(taskId) === holds2) this.completing.delete(taskId);
|
|
38299
|
+
}
|
|
38300
|
+
}
|
|
37971
38301
|
getReadyTasks() {
|
|
37972
38302
|
return this.readiness().ready;
|
|
37973
38303
|
}
|
|
@@ -38075,17 +38405,27 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
38075
38405
|
* as {@link cancelTask} does, but its worktree goes: no task is left to land
|
|
38076
38406
|
* it into. A spawn still in flight just loses its attempt,
|
|
38077
38407
|
* which is what makes {@link Attempts} kill the session it is about to
|
|
38078
|
-
* receive.
|
|
38079
|
-
*
|
|
38408
|
+
* receive. Every landing of it in flight — Mark complete's, its resolver's —
|
|
38409
|
+
* settles first, so its worktree is not torn down under a merge, and none
|
|
38410
|
+
* begins while it goes; a repair a landing claims is cancelled as any
|
|
38411
|
+
* running attempt is. The id's cross-attempt bookkeeping
|
|
38412
|
+
* goes too — a hold or retry count kept for a task that no longer exists
|
|
38413
|
+
* would be inherited by nothing.
|
|
38080
38414
|
*/
|
|
38081
38415
|
async releaseTask(taskId) {
|
|
38082
38416
|
this.limitPauses.cancel(taskId);
|
|
38083
|
-
|
|
38084
|
-
|
|
38085
|
-
|
|
38086
|
-
this.attempts.
|
|
38087
|
-
if (
|
|
38088
|
-
|
|
38417
|
+
for (let holds2 = this.completing.get(taskId); holds2; holds2 = this.completing.get(taskId)) await Promise.allSettled(holds2);
|
|
38418
|
+
this.releasing.add(taskId);
|
|
38419
|
+
try {
|
|
38420
|
+
const phase = this.attempts.phaseOf(taskId);
|
|
38421
|
+
if (phase === "running" || phase === "integrating") await this.cancelAttempt(taskId, { keep: false });
|
|
38422
|
+
else {
|
|
38423
|
+
this.attempts.end(taskId, "release");
|
|
38424
|
+
if (this.store.get(taskId)?.status === "in_progress") this.store.markPending(taskId);
|
|
38425
|
+
await this.runs.release(taskId, { keep: false });
|
|
38426
|
+
}
|
|
38427
|
+
} finally {
|
|
38428
|
+
this.releasing.delete(taskId);
|
|
38089
38429
|
}
|
|
38090
38430
|
this.onHold.delete(taskId);
|
|
38091
38431
|
this.retryCounts.delete(taskId);
|
|
@@ -38094,17 +38434,12 @@ var TaskOrchestrator = class _TaskOrchestrator {
|
|
|
38094
38434
|
async markTaskComplete(taskId) {
|
|
38095
38435
|
const task2 = this.store.get(taskId);
|
|
38096
38436
|
if (!task2 || task2.status === "completed") return;
|
|
38097
|
-
if (this.completing.has(taskId)) return;
|
|
38437
|
+
if (this.completing.has(taskId) || this.releasing.has(taskId)) return;
|
|
38098
38438
|
const admission = this.admittedNow();
|
|
38099
38439
|
const ended = this.attempts.end(taskId, "complete");
|
|
38100
38440
|
const verdict = this.attempts.markComplete(task2);
|
|
38101
|
-
this.
|
|
38102
|
-
|
|
38103
|
-
try {
|
|
38104
|
-
landing2 = await (ended?.integration ?? this.landing.landVouched(task2));
|
|
38105
|
-
} finally {
|
|
38106
|
-
this.completing.delete(taskId);
|
|
38107
|
-
}
|
|
38441
|
+
const landed2 = ended?.integration ?? this.landing.landVouched(task2);
|
|
38442
|
+
const landing2 = await this.holdWhileLanding(taskId, landed2);
|
|
38108
38443
|
this.store.setTaskVerdict(taskId, verdict);
|
|
38109
38444
|
const handoff = task2.type === "user" ? userTaskHandoff(task2.userSteps) : void 0;
|
|
38110
38445
|
this.attempts.handOver(taskId, summarizeOutput(verdict.reason, ""), handoff);
|
|
@@ -38393,7 +38728,7 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
38393
38728
|
if (!await this.openForAdmitted(taskId, origin, resume, admission)) return;
|
|
38394
38729
|
if (this.attempts.has(taskId)) return;
|
|
38395
38730
|
this.refuseOpsDuringMerge(taskId, forced);
|
|
38396
|
-
if (forced.queued && this.holdsQueued(taskId, forced)) {
|
|
38731
|
+
if (forced.queued && (this.holdsQueued(taskId, forced) || this.slotsFull())) {
|
|
38397
38732
|
this.queuedStarts.set(taskId, { pastGate: forced.pastGate });
|
|
38398
38733
|
return;
|
|
38399
38734
|
}
|
|
@@ -38452,8 +38787,9 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
38452
38787
|
this.queuedStarts.delete(id2);
|
|
38453
38788
|
continue;
|
|
38454
38789
|
}
|
|
38790
|
+
if (this.slotsFull()) continue;
|
|
38455
38791
|
const waits = this.startWaits(task2, task2.research ? void 0 : { queued: true, pastGate: queued.pastGate });
|
|
38456
|
-
if (task2.research &&
|
|
38792
|
+
if (task2.research && waits.length > 0) continue;
|
|
38457
38793
|
if (waits.some((w) => QUEUED_WAITS.has(w.kind))) continue;
|
|
38458
38794
|
if (this.leftToScheduler(task2) && queued.pastGate.length === 0) {
|
|
38459
38795
|
this.queuedStarts.delete(id2);
|
|
@@ -38482,6 +38818,9 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
38482
38818
|
const task2 = this.store.get(taskId);
|
|
38483
38819
|
return !!task2 && this.startWaits(task2, forced).some((w) => QUEUED_WAITS.has(w.kind) || w.kind === "dependencies" || w.kind === "merge-gate");
|
|
38484
38820
|
}
|
|
38821
|
+
slotsFull() {
|
|
38822
|
+
return this.attempts.size >= this.config.maxParallelSessions;
|
|
38823
|
+
}
|
|
38485
38824
|
sayQueuedAtGate(task2, queued, unmerged) {
|
|
38486
38825
|
const titles = unmerged.map((id2) => `"${this.store.get(id2)?.title ?? id2}"`).join(", ");
|
|
38487
38826
|
const notice = `Task "${task2.title}" waits for Merge all: the work of ${titles} is not merged into your branch yet. Merge all to start it, or force start it again to start it without that work.`;
|
|
@@ -38582,7 +38921,7 @@ ${now.message}` : LIMIT_RESET_MESSAGE;
|
|
|
38582
38921
|
*/
|
|
38583
38922
|
async settleRun(after) {
|
|
38584
38923
|
if (!this.store.isFinished()) this.transition({ type: "reopen" });
|
|
38585
|
-
if (this.attempts.size > 0) return;
|
|
38924
|
+
if (this.attempts.size > 0 || this.owedRepairs.size > 0) return;
|
|
38586
38925
|
if (this.runState.kind === "held") return;
|
|
38587
38926
|
if (this.runState.kind !== "scheduling") {
|
|
38588
38927
|
if (after === "tick") {
|
|
@@ -38876,21 +39215,45 @@ var Planner = class {
|
|
|
38876
39215
|
};
|
|
38877
39216
|
|
|
38878
39217
|
// src/services/ModelResolver.ts
|
|
38879
|
-
var ModelResolver = class {
|
|
39218
|
+
var ModelResolver = class _ModelResolver {
|
|
38880
39219
|
constructor(registry, config, deps = {}) {
|
|
38881
39220
|
this.registry = registry;
|
|
38882
39221
|
this.config = config;
|
|
38883
|
-
this.discovery = new ModelDiscovery(registry, deps.execImpl, deps.fetchImpl);
|
|
39222
|
+
this.discovery = new ModelDiscovery(registry, deps.execImpl, deps.fetchImpl, void 0, void 0, void 0, deps.env);
|
|
38884
39223
|
this.fetchImpl = deps.fetchImpl;
|
|
39224
|
+
this.execImpl = deps.execImpl;
|
|
39225
|
+
this.shared = { vendor: { options: null, load: null, errors: {}, generation: 0 }, root: this, views: /* @__PURE__ */ new Map() };
|
|
38885
39226
|
}
|
|
38886
39227
|
registry;
|
|
38887
39228
|
config;
|
|
38888
39229
|
discovery;
|
|
38889
39230
|
fetchImpl;
|
|
38890
|
-
|
|
38891
|
-
|
|
38892
|
-
|
|
38893
|
-
|
|
39231
|
+
execImpl;
|
|
39232
|
+
shared;
|
|
39233
|
+
get vendor() {
|
|
39234
|
+
return this.shared.vendor;
|
|
39235
|
+
}
|
|
39236
|
+
/**
|
|
39237
|
+
* This resolver for runners launched with another environment, a
|
|
39238
|
+
* workspace's own: their catalogs are discovered and cached under `env`, as
|
|
39239
|
+
* `CLAUDE_CONFIG_DIR` there can name another account, while the vendor
|
|
39240
|
+
* catalogs stay this resolver's, fetched once. One view per `key`, made on
|
|
39241
|
+
* its first ask: a later ask with the same key gets that view, whatever
|
|
39242
|
+
* `env` it passes.
|
|
39243
|
+
*/
|
|
39244
|
+
withRunnerEnv(key, env) {
|
|
39245
|
+
let view = this.shared.views.get(key);
|
|
39246
|
+
if (!view) {
|
|
39247
|
+
view = new _ModelResolver(this.registry, this.config, { fetchImpl: this.fetchImpl, execImpl: this.execImpl, env });
|
|
39248
|
+
view.shared = this.shared;
|
|
39249
|
+
this.shared.views.set(key, view);
|
|
39250
|
+
}
|
|
39251
|
+
return view;
|
|
39252
|
+
}
|
|
39253
|
+
/** Every runner-environment catalog this resolver's family holds: its root's and each view's. */
|
|
39254
|
+
runnerCatalogs() {
|
|
39255
|
+
return [this.shared.root, ...this.shared.views.values()].map((resolver) => resolver.discovery);
|
|
39256
|
+
}
|
|
38894
39257
|
static builtinOptions() {
|
|
38895
39258
|
return toOrchestratorOptions({}, ORCHESTRATOR_SHORTCUTS);
|
|
38896
39259
|
}
|
|
@@ -38906,16 +39269,16 @@ var ModelResolver = class {
|
|
|
38906
39269
|
return Object.fromEntries(discovered);
|
|
38907
39270
|
}
|
|
38908
39271
|
async pickerOptions() {
|
|
38909
|
-
if (this.
|
|
38910
|
-
if (!this.
|
|
39272
|
+
if (this.vendor.options) return this.vendor.options;
|
|
39273
|
+
if (!this.vendor.load) {
|
|
38911
39274
|
const load = this.loadPickerOptions();
|
|
38912
|
-
this.
|
|
39275
|
+
this.vendor.load = load;
|
|
38913
39276
|
void load.finally(() => {
|
|
38914
|
-
if (this.
|
|
39277
|
+
if (this.vendor.load === load) this.vendor.load = null;
|
|
38915
39278
|
}).catch(() => {
|
|
38916
39279
|
});
|
|
38917
39280
|
}
|
|
38918
|
-
return this.
|
|
39281
|
+
return this.vendor.load;
|
|
38919
39282
|
}
|
|
38920
39283
|
/**
|
|
38921
39284
|
* Start loading the vendor catalogs without waiting for them, unless they
|
|
@@ -38923,20 +39286,25 @@ var ModelResolver = class {
|
|
|
38923
39286
|
* known yet reads it from them on a later call, never waiting on the fetch.
|
|
38924
39287
|
*/
|
|
38925
39288
|
warmPickerOptions() {
|
|
38926
|
-
if (this.
|
|
39289
|
+
if (this.vendor.options || this.vendor.load) return;
|
|
38927
39290
|
this.pickerOptions().catch(() => {
|
|
38928
39291
|
});
|
|
38929
39292
|
}
|
|
38930
39293
|
async loadPickerOptions() {
|
|
39294
|
+
const vendor = this.vendor;
|
|
39295
|
+
const generation2 = vendor.generation;
|
|
38931
39296
|
const { apiKeys, baseUrls } = collectProviderCredentials(this.config);
|
|
38932
39297
|
const { models, errors } = await fetchAllProviderModels({
|
|
38933
39298
|
apiKeys,
|
|
38934
39299
|
baseUrls,
|
|
38935
39300
|
fetchImpl: this.fetchImpl
|
|
38936
39301
|
});
|
|
38937
|
-
|
|
38938
|
-
|
|
38939
|
-
|
|
39302
|
+
const options = toOrchestratorOptions(models, ORCHESTRATOR_SHORTCUTS);
|
|
39303
|
+
if (vendor.generation === generation2) {
|
|
39304
|
+
vendor.errors = errors;
|
|
39305
|
+
vendor.options = options;
|
|
39306
|
+
}
|
|
39307
|
+
return options;
|
|
38940
39308
|
}
|
|
38941
39309
|
/**
|
|
38942
39310
|
* Per-provider failures from the most recent `pickerOptions()` fetch, keyed
|
|
@@ -38945,7 +39313,7 @@ var ModelResolver = class {
|
|
|
38945
39313
|
* key/endpoint is set but whose catalog could not be reached.
|
|
38946
39314
|
*/
|
|
38947
39315
|
getDiscoveryErrors() {
|
|
38948
|
-
return this.
|
|
39316
|
+
return this.vendor.errors;
|
|
38949
39317
|
}
|
|
38950
39318
|
async refresh() {
|
|
38951
39319
|
const options = await this.pickerOptions();
|
|
@@ -38956,8 +39324,25 @@ var ModelResolver = class {
|
|
|
38956
39324
|
this.config.setProviderModelLists(lists);
|
|
38957
39325
|
return lists;
|
|
38958
39326
|
}
|
|
39327
|
+
/** Forget every runner catalog, each workspace's included; the vendor catalogs stay. */
|
|
38959
39328
|
refreshRunnerModels() {
|
|
38960
|
-
this.discovery.clear();
|
|
39329
|
+
for (const discovery of this.runnerCatalogs()) discovery.clear();
|
|
39330
|
+
}
|
|
39331
|
+
/**
|
|
39332
|
+
* The models a pick for `provider` is judged against: a harness planner's
|
|
39333
|
+
* own runner catalog, or the vendor picker catalog (ADR-0009). Discovered
|
|
39334
|
+
* if not held. Never throws: a catalog that cannot be had is empty.
|
|
39335
|
+
*/
|
|
39336
|
+
async plannerCatalog(provider) {
|
|
39337
|
+
const runner = runnerForProvider(provider);
|
|
39338
|
+
if (runner) return candidatesOf((await this.modelsForRunners([runner]))[runner] ?? []);
|
|
39339
|
+
return (await this.pickerOptions().catch(() => [])).map((o) => ({ id: o.id }));
|
|
39340
|
+
}
|
|
39341
|
+
/** {@link plannerCatalog} from what is already held, so a cold catalog is empty; never discovers. */
|
|
39342
|
+
cachedPlannerCatalog(provider) {
|
|
39343
|
+
const runner = runnerForProvider(provider);
|
|
39344
|
+
if (runner) return candidatesOf(this.getCachedRunnerModels(runner));
|
|
39345
|
+
return this.getCachedPickerOptions().map((o) => ({ id: o.id }));
|
|
38961
39346
|
}
|
|
38962
39347
|
/**
|
|
38963
39348
|
* Synchronous reads of whatever the last `modelsForRunners`/`pickerOptions`
|
|
@@ -38968,7 +39353,7 @@ var ModelResolver = class {
|
|
|
38968
39353
|
return this.discovery.getCached(runner) ?? [];
|
|
38969
39354
|
}
|
|
38970
39355
|
getCachedPickerOptions() {
|
|
38971
|
-
return this.
|
|
39356
|
+
return this.vendor.options ?? [];
|
|
38972
39357
|
}
|
|
38973
39358
|
/**
|
|
38974
39359
|
* A model's context window from whatever catalog is already cached (#49),
|
|
@@ -38981,7 +39366,7 @@ var ModelResolver = class {
|
|
|
38981
39366
|
*/
|
|
38982
39367
|
contextWindowFor(source, model) {
|
|
38983
39368
|
if (!model) return void 0;
|
|
38984
|
-
const window2 = isApiProvider(source) ? this.
|
|
39369
|
+
const window2 = isApiProvider(source) ? this.vendor.options?.find((o) => o.apiProvider === source && o.id === prefixModelId(source, stripModelPrefix(model, source)))?.contextWindow : this.discovery.getCached(source)?.find((m) => m.modelId === model)?.contextWindow;
|
|
38985
39370
|
return window2 && window2 > 0 ? window2 : void 0;
|
|
38986
39371
|
}
|
|
38987
39372
|
/**
|
|
@@ -38991,14 +39376,16 @@ var ModelResolver = class {
|
|
|
38991
39376
|
*/
|
|
38992
39377
|
maxOutputTokensFor(source, model) {
|
|
38993
39378
|
if (!model || !isApiProvider(source)) return void 0;
|
|
38994
|
-
const cap = this.
|
|
39379
|
+
const cap = this.vendor.options?.find((o) => o.apiProvider === source && o.id === prefixModelId(source, stripModelPrefix(model, source)))?.maxOutputTokens;
|
|
38995
39380
|
return cap && cap > 0 ? cap : void 0;
|
|
38996
39381
|
}
|
|
39382
|
+
/** Forget every catalog: the vendor ones, and each runner environment's. */
|
|
38997
39383
|
invalidate() {
|
|
38998
|
-
this.
|
|
38999
|
-
this.
|
|
39000
|
-
this.
|
|
39001
|
-
this.
|
|
39384
|
+
this.refreshRunnerModels();
|
|
39385
|
+
this.vendor.generation++;
|
|
39386
|
+
this.vendor.options = null;
|
|
39387
|
+
this.vendor.load = null;
|
|
39388
|
+
this.vendor.errors = {};
|
|
39002
39389
|
if (!this.fetchImpl) {
|
|
39003
39390
|
for (const provider of PROVIDER_PRIORITY) {
|
|
39004
39391
|
const baseUrl = this.config.getProviderBaseUrl(provider);
|
|
@@ -39008,6 +39395,9 @@ var ModelResolver = class {
|
|
|
39008
39395
|
}
|
|
39009
39396
|
}
|
|
39010
39397
|
};
|
|
39398
|
+
function candidatesOf(models) {
|
|
39399
|
+
return models.map((m) => ({ id: m.modelId, variants: m.variants }));
|
|
39400
|
+
}
|
|
39011
39401
|
|
|
39012
39402
|
// src/services/RunnerInstallation.ts
|
|
39013
39403
|
var import_child_process12 = require("child_process");
|
|
@@ -39785,12 +40175,12 @@ function openCodeStorePaths(env, home) {
|
|
|
39785
40175
|
return { db: file === ":memory:" ? null : (0, import_path9.resolve)(data, file), auth: (0, import_path9.join)(data, "auth.json") };
|
|
39786
40176
|
}
|
|
39787
40177
|
function openCodeGoLoginReader(deps = {}) {
|
|
39788
|
-
const
|
|
40178
|
+
const homedir10 = deps.homedir ?? import_os6.homedir;
|
|
39789
40179
|
let last;
|
|
39790
40180
|
return {
|
|
39791
40181
|
async read(env, signal) {
|
|
39792
40182
|
if (signal.aborted) return { kind: "unreadable" };
|
|
39793
|
-
const paths = openCodeStorePaths(env,
|
|
40183
|
+
const paths = openCodeStorePaths(env, homedir10());
|
|
39794
40184
|
const [db, wal, auth] = await Promise.all([
|
|
39795
40185
|
paths.db ? stamp(paths.db) : null,
|
|
39796
40186
|
paths.db ? stamp(`${paths.db}-wal`) : null,
|
|
@@ -39844,8 +40234,8 @@ function v2Login(db, row) {
|
|
|
39844
40234
|
login: { route: "console", owner: digest("console", db, row.id, account, orgID ?? ""), access: value.access, ...orgID ? { orgID } : {}, expires: value.expires }
|
|
39845
40235
|
};
|
|
39846
40236
|
}
|
|
39847
|
-
async function legacyLogin(
|
|
39848
|
-
const content = env.OPENCODE_AUTH_CONTENT ?? await readSmall(
|
|
40237
|
+
async function legacyLogin(path48, env) {
|
|
40238
|
+
const content = env.OPENCODE_AUTH_CONTENT ?? await readSmall(path48);
|
|
39849
40239
|
if (content === void 0) return env[ENV_KEY] ? { kind: "unsupported" } : { kind: "none" };
|
|
39850
40240
|
if (content === null) return { kind: "unreadable" };
|
|
39851
40241
|
const auth = parseJson(content);
|
|
@@ -39854,15 +40244,15 @@ async function legacyLogin(path47, env) {
|
|
|
39854
40244
|
if (entry === void 0) return env[ENV_KEY] ? { kind: "unsupported" } : { kind: "none" };
|
|
39855
40245
|
if (!isRecord12(entry) || entry.type !== "api") return { kind: "unsupported" };
|
|
39856
40246
|
if (typeof entry.key !== "string" || entry.key.length === 0) return { kind: "unreadable" };
|
|
39857
|
-
return { kind: "login", login: { route: "key", owner: digest("v1",
|
|
40247
|
+
return { kind: "login", login: { route: "key", owner: digest("v1", path48, entry.key), key: entry.key } };
|
|
39858
40248
|
}
|
|
39859
|
-
function queryStore(
|
|
40249
|
+
function queryStore(path48, signal, deps) {
|
|
39860
40250
|
return new Promise((settle) => {
|
|
39861
40251
|
let worker;
|
|
39862
40252
|
try {
|
|
39863
40253
|
worker = (deps.spawnWorker ?? ((source, options) => new import_worker_threads.Worker(source, options)))(WORKER_SOURCE, {
|
|
39864
40254
|
eval: true,
|
|
39865
|
-
workerData: { path:
|
|
40255
|
+
workerData: { path: path48, integrations: GO_INTEGRATIONS, busyMs: BUSY_MS, maxValueBytes: MAX_VALUE_BYTES },
|
|
39866
40256
|
execArgv: deps.workerExecArgv ?? [],
|
|
39867
40257
|
resourceLimits: { maxOldGenerationSizeMb: 64 }
|
|
39868
40258
|
});
|
|
@@ -39889,19 +40279,19 @@ function queryStore(path47, signal, deps) {
|
|
|
39889
40279
|
worker.once("exit", aborted);
|
|
39890
40280
|
});
|
|
39891
40281
|
}
|
|
39892
|
-
async function stamp(
|
|
40282
|
+
async function stamp(path48) {
|
|
39893
40283
|
try {
|
|
39894
|
-
const stat = await import_fs14.promises.stat(
|
|
40284
|
+
const stat = await import_fs14.promises.stat(path48);
|
|
39895
40285
|
return [stat.ino, stat.size, stat.mtimeMs];
|
|
39896
40286
|
} catch {
|
|
39897
40287
|
return null;
|
|
39898
40288
|
}
|
|
39899
40289
|
}
|
|
39900
|
-
async function readSmall(
|
|
40290
|
+
async function readSmall(path48) {
|
|
39901
40291
|
try {
|
|
39902
|
-
const stat = await import_fs14.promises.stat(
|
|
40292
|
+
const stat = await import_fs14.promises.stat(path48);
|
|
39903
40293
|
if (!stat.isFile() || stat.size > MAX_AUTH_FILE_BYTES) return null;
|
|
39904
|
-
return await import_fs14.promises.readFile(
|
|
40294
|
+
return await import_fs14.promises.readFile(path48, "utf8");
|
|
39905
40295
|
} catch (err) {
|
|
39906
40296
|
return err.code === "ENOENT" ? void 0 : null;
|
|
39907
40297
|
}
|
|
@@ -41030,20 +41420,20 @@ function createAiService(config, deps) {
|
|
|
41030
41420
|
}
|
|
41031
41421
|
|
|
41032
41422
|
// src/services/createSession.ts
|
|
41033
|
-
var
|
|
41423
|
+
var path45 = __toESM(require("path"));
|
|
41034
41424
|
|
|
41035
41425
|
// src/services/handoffReferences.ts
|
|
41036
41426
|
var fs21 = __toESM(require("fs"));
|
|
41037
|
-
var
|
|
41427
|
+
var path43 = __toESM(require("path"));
|
|
41038
41428
|
var import_child_process15 = require("child_process");
|
|
41039
41429
|
function resolveHandoffReferences(handoff, workspace) {
|
|
41040
41430
|
const checked = /* @__PURE__ */ new Map();
|
|
41041
41431
|
const contained = (candidate) => {
|
|
41042
41432
|
try {
|
|
41043
41433
|
const root = fs21.realpathSync(workspace);
|
|
41044
|
-
const resolved = fs21.realpathSync(
|
|
41045
|
-
const relative17 =
|
|
41046
|
-
return relative17 !== ".." && !relative17.startsWith(`..${
|
|
41434
|
+
const resolved = fs21.realpathSync(path43.resolve(root, candidate));
|
|
41435
|
+
const relative17 = path43.relative(root, resolved);
|
|
41436
|
+
return relative17 !== ".." && !relative17.startsWith(`..${path43.sep}`) && !path43.isAbsolute(relative17) ? resolved : void 0;
|
|
41047
41437
|
} catch {
|
|
41048
41438
|
return void 0;
|
|
41049
41439
|
}
|
|
@@ -41064,7 +41454,7 @@ function resolveHandoffReferences(handoff, workspace) {
|
|
|
41064
41454
|
}
|
|
41065
41455
|
} else if (/^[0-9a-fA-F]{4,64}$/.test(ref.sha)) {
|
|
41066
41456
|
const repo = contained(ref.repo ?? ".");
|
|
41067
|
-
if (repo && fs21.existsSync(
|
|
41457
|
+
if (repo && fs21.existsSync(path43.join(repo, ".git"))) {
|
|
41068
41458
|
const result2 = (0, import_child_process15.spawnSync)("git", ["--no-optional-locks", "--no-replace-objects", "cat-file", "-t", ref.sha], {
|
|
41069
41459
|
cwd: repo,
|
|
41070
41460
|
encoding: "utf8",
|
|
@@ -42022,7 +42412,7 @@ function serializeTask(t) {
|
|
|
42022
42412
|
...t.loop && t.loopRound !== void 0 ? { loopRound: t.loopRound } : {}
|
|
42023
42413
|
};
|
|
42024
42414
|
}
|
|
42025
|
-
function serializeTaskStatus(t, idleSince = null, isolation = null, queued = [], awaitingApproval = 0, mergeGate2 = [], checkpoint = "", waitsForApproval2 = false, holdReason = null, completionReceived = null) {
|
|
42415
|
+
function serializeTaskStatus(t, idleSince = null, isolation = null, queued = [], awaitingApproval = 0, mergeGate2 = [], checkpoint = "", waitsForApproval2 = false, holdReason = null, completionReceived = null, attaching = null) {
|
|
42026
42416
|
return {
|
|
42027
42417
|
id: t.id,
|
|
42028
42418
|
type: t.type,
|
|
@@ -42030,6 +42420,7 @@ function serializeTaskStatus(t, idleSince = null, isolation = null, queued = [],
|
|
|
42030
42420
|
verdict: t.verdict ? { outcome: t.verdict.outcome, reason: t.verdict.reason, checks: t.verdict.checks || [], ...t.verdict.reported ? { reported: t.verdict.reported } : {} } : null,
|
|
42031
42421
|
idleSince,
|
|
42032
42422
|
...completionReceived ? { completionReceived } : {},
|
|
42423
|
+
...attaching ? { attaching } : {},
|
|
42033
42424
|
...t.attempted ? { attempted: true } : {},
|
|
42034
42425
|
...t.attemptUsage ? { attemptUsage: structuredClone(t.attemptUsage) } : {},
|
|
42035
42426
|
...isolation ? { isolation } : {},
|
|
@@ -42059,7 +42450,7 @@ function surfacePendingTurns(pending) {
|
|
|
42059
42450
|
function surfaceTask({ attemptSkills, subtasks, runnerSessionId: _runnerSessionId, ...task2 }) {
|
|
42060
42451
|
return {
|
|
42061
42452
|
...task2,
|
|
42062
|
-
...attemptSkills ? { attemptSkills: attemptSkills.map(({ name, source, path:
|
|
42453
|
+
...attemptSkills ? { attemptSkills: attemptSkills.map(({ name, source, path: path48 }) => ({ name, source, path: path48 })) } : {},
|
|
42063
42454
|
subtasks: (subtasks ?? []).map(surfaceTask)
|
|
42064
42455
|
};
|
|
42065
42456
|
}
|
|
@@ -42479,8 +42870,8 @@ var RunSupervision = class {
|
|
|
42479
42870
|
|
|
42480
42871
|
// src/services/runView.ts
|
|
42481
42872
|
var EMPTY_RUN = { tasks: [], runMerge: null, handoff: null, mergeResult: null, activity: IDLE_ACTIVITY };
|
|
42482
|
-
function split({ verdict, idleSince, completionReceived, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate: mergeGate2, forcedPastGate, waitsForApproval: waitsForApproval2, holdReason, handoff, attempted, ...plan }) {
|
|
42483
|
-
return { plan, status: { verdict, idleSince, completionReceived, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate: mergeGate2, forcedPastGate, waitsForApproval: waitsForApproval2, holdReason, handoff, attempted } };
|
|
42873
|
+
function split({ verdict, idleSince, completionReceived, attaching, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate: mergeGate2, forcedPastGate, waitsForApproval: waitsForApproval2, holdReason, handoff, attempted, ...plan }) {
|
|
42874
|
+
return { plan, status: { verdict, idleSince, completionReceived, attaching, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate: mergeGate2, forcedPastGate, waitsForApproval: waitsForApproval2, holdReason, handoff, attempted } };
|
|
42484
42875
|
}
|
|
42485
42876
|
function refresh(previous, tasks) {
|
|
42486
42877
|
const held2 = new Map([...walkPlan(previous)].map(({ task: task2 }) => [task2.id, task2]));
|
|
@@ -42716,7 +43107,8 @@ var SessionEventRelay = class {
|
|
|
42716
43107
|
this.checkpointQuestion(t.id),
|
|
42717
43108
|
this.waitsForApproval(t.id),
|
|
42718
43109
|
this.orchestrator.holdReason(t.id),
|
|
42719
|
-
this.orchestrator.getCompletionReceipt(t.id)
|
|
43110
|
+
this.orchestrator.getCompletionReceipt(t.id),
|
|
43111
|
+
this.orchestrator.getToolsAttaching(t.id)
|
|
42720
43112
|
)),
|
|
42721
43113
|
...runMerge ? { runMerge } : {},
|
|
42722
43114
|
activity: this.orchestrator.activity
|
|
@@ -42838,10 +43230,10 @@ var SessionEventRelay = class {
|
|
|
42838
43230
|
|
|
42839
43231
|
// src/utils/taskLogStore.ts
|
|
42840
43232
|
var fs22 = __toESM(require("fs"));
|
|
42841
|
-
var
|
|
43233
|
+
var path44 = __toESM(require("path"));
|
|
42842
43234
|
var EXTENSION = ".jsonl";
|
|
42843
43235
|
function taskDir({ baseDir, sessionId }, taskId) {
|
|
42844
|
-
return
|
|
43236
|
+
return path44.join(sessionDataDir(sessionId, baseDir), "tasks", idSegment(taskId));
|
|
42845
43237
|
}
|
|
42846
43238
|
function listTaskLogAttempts(location, taskId) {
|
|
42847
43239
|
let names;
|
|
@@ -42859,7 +43251,7 @@ function openTaskLog(location, taskId, attempt) {
|
|
|
42859
43251
|
const next = (listTaskLogAttempts(location, taskId).pop() ?? 0) + 1;
|
|
42860
43252
|
let number = attempt !== void 0 && Number.isInteger(attempt) && attempt >= 1 ? attempt : next;
|
|
42861
43253
|
for (; ; ) {
|
|
42862
|
-
const file =
|
|
43254
|
+
const file = path44.join(dir, `${number}${EXTENSION}`);
|
|
42863
43255
|
try {
|
|
42864
43256
|
fs22.writeFileSync(file, "", { flag: "wx" });
|
|
42865
43257
|
} catch (err) {
|
|
@@ -42883,15 +43275,15 @@ function prepareTaskOutputFile(location, taskId, attempt) {
|
|
|
42883
43275
|
ensureStateDirIgnored(location.baseDir);
|
|
42884
43276
|
const dir = taskDir(location, taskId);
|
|
42885
43277
|
fs22.mkdirSync(dir, { recursive: true });
|
|
42886
|
-
return
|
|
43278
|
+
return path44.join(dir, `${attempt}.output.txt`);
|
|
42887
43279
|
}
|
|
42888
43280
|
function taskPatchFile(location, taskId, attempt) {
|
|
42889
|
-
return
|
|
43281
|
+
return path44.join(taskDir(location, taskId), `${attempt}.patch`);
|
|
42890
43282
|
}
|
|
42891
43283
|
function saveTaskPatch(location, taskId, attempt, patch) {
|
|
42892
43284
|
ensureStateDirIgnored(location.baseDir);
|
|
42893
43285
|
const file = taskPatchFile(location, taskId, attempt);
|
|
42894
|
-
fs22.mkdirSync(
|
|
43286
|
+
fs22.mkdirSync(path44.dirname(file), { recursive: true });
|
|
42895
43287
|
const partial = `${file}.${process.pid}-${Date.now()}.partial`;
|
|
42896
43288
|
fs22.writeFileSync(partial, patch, { flag: "wx" });
|
|
42897
43289
|
fs22.renameSync(partial, file);
|
|
@@ -42912,7 +43304,7 @@ function readTaskLog(location, taskId, attempt) {
|
|
|
42912
43304
|
if (!Number.isInteger(attempt) || attempt < 1) return [];
|
|
42913
43305
|
let raw;
|
|
42914
43306
|
try {
|
|
42915
|
-
raw = fs22.readFileSync(
|
|
43307
|
+
raw = fs22.readFileSync(path44.join(taskDir(location, taskId), `${attempt}${EXTENSION}`), "utf-8");
|
|
42916
43308
|
} catch {
|
|
42917
43309
|
return [];
|
|
42918
43310
|
}
|
|
@@ -44974,7 +45366,7 @@ function createSession(deps) {
|
|
|
44974
45366
|
...deps.openTaskLog ? {} : {
|
|
44975
45367
|
keepPatch: (taskId, attempt, patch) => {
|
|
44976
45368
|
const location = session.taskLogLocation;
|
|
44977
|
-
return
|
|
45369
|
+
return path45.relative(location.baseDir, saveTaskPatch(location, taskId, attempt, patch)).split(path45.sep).join("/");
|
|
44978
45370
|
}
|
|
44979
45371
|
},
|
|
44980
45372
|
recordHandoff: (sessionId, taskId, handoff) => taskLogs.note(sessionId, taskId, { type: "handoff", handoff }),
|
|
@@ -47842,6 +48234,7 @@ function taskRowView(task2, context = {}) {
|
|
|
47842
48234
|
resumes: resumeLabel(task2, context.now),
|
|
47843
48235
|
approvals: approvalLabel(task2.awaitingApproval),
|
|
47844
48236
|
receipt: receiptLabel(task2),
|
|
48237
|
+
attaching: attachingLabel(task2),
|
|
47845
48238
|
waitsForApproval: task2.waitsForApproval && NOT_STARTED.has(task2.status) ? WAITS_FOR_APPROVAL_LABEL : null,
|
|
47846
48239
|
holdReason: task2.holdReason?.trim() || null,
|
|
47847
48240
|
research: task2.type === "ai" && task2.research === true,
|
|
@@ -48155,6 +48548,7 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
48155
48548
|
*/
|
|
48156
48549
|
async startAttached(opts) {
|
|
48157
48550
|
const { server: server4, scope, shell, savePatch, webReads } = this.launch.tools;
|
|
48551
|
+
this.launch.onAttaching?.(1);
|
|
48158
48552
|
const spawned = await spawnAttached({
|
|
48159
48553
|
runner: this.launch.runner,
|
|
48160
48554
|
create: () => this.launch.createAdapter(this.launch.runner, this.launch.deps),
|
|
@@ -48191,7 +48585,10 @@ var StructuredSession = class extends AbstractRunnerSession {
|
|
|
48191
48585
|
},
|
|
48192
48586
|
cancelled: this.ended.signal,
|
|
48193
48587
|
startupExit: () => this.startupExit,
|
|
48194
|
-
onRespawn: (failure2) =>
|
|
48588
|
+
onRespawn: (failure2) => {
|
|
48589
|
+
this.launch.onNotice?.(`${this.launch.runner} started without Ordewell's tools (${failure2}); respawning once.`);
|
|
48590
|
+
this.launch.onAttaching?.(2);
|
|
48591
|
+
},
|
|
48195
48592
|
failed: (first, second) => `Could not start ${this.launch.runner} with Ordewell's tools, so the task was not sent to it. First spawn: ${first}. Respawn: ${second}.`
|
|
48196
48593
|
});
|
|
48197
48594
|
if (!spawned) return;
|
|
@@ -48774,16 +49171,22 @@ var StructuredRunner = class extends AbstractRunner {
|
|
|
48774
49171
|
checkHandoff: opts.checkHandoff ?? ((completion) => checkHandoff(completion, opts.taskId, [])),
|
|
48775
49172
|
...opts.readTask ? { readTask: opts.readTask } : {},
|
|
48776
49173
|
...opts.applyPatch ? { applyPatch: opts.applyPatch } : {},
|
|
48777
|
-
onNotice: opts.onNotice
|
|
49174
|
+
onNotice: opts.onNotice,
|
|
49175
|
+
onAttaching: opts.onAttaching
|
|
48778
49176
|
});
|
|
48779
49177
|
console.error(`[structured] Starting ${opts.runner} [${opts.mode ?? "default"}] (${opts.modelId || "default"}) for task ${opts.taskId.slice(0, 8)}`);
|
|
48780
49178
|
this.registerSession(id2, session);
|
|
49179
|
+
const cancel = () => void session.stop();
|
|
49180
|
+
opts.cancelled?.addEventListener("abort", cancel, { once: true });
|
|
48781
49181
|
try {
|
|
49182
|
+
if (opts.cancelled?.aborted) cancel();
|
|
48782
49183
|
await session.start(opts.prompt);
|
|
48783
49184
|
} catch (err) {
|
|
48784
49185
|
session.kill();
|
|
48785
49186
|
this.sessions.delete(id2);
|
|
48786
49187
|
throw err;
|
|
49188
|
+
} finally {
|
|
49189
|
+
opts.cancelled?.removeEventListener("abort", cancel);
|
|
48787
49190
|
}
|
|
48788
49191
|
return session;
|
|
48789
49192
|
}
|
|
@@ -48857,7 +49260,7 @@ var RunnerRegistry = class {
|
|
|
48857
49260
|
|
|
48858
49261
|
// src/plugins/removedPluginNotice.ts
|
|
48859
49262
|
var fs23 = __toESM(require("fs"));
|
|
48860
|
-
var
|
|
49263
|
+
var path46 = __toESM(require("path"));
|
|
48861
49264
|
function isManifestFile(file) {
|
|
48862
49265
|
try {
|
|
48863
49266
|
return fs23.statSync(file).isFile();
|
|
@@ -48866,10 +49269,10 @@ function isManifestFile(file) {
|
|
|
48866
49269
|
}
|
|
48867
49270
|
}
|
|
48868
49271
|
function removedPluginNotice(dataDir = globalDataDir()) {
|
|
48869
|
-
const directory =
|
|
49272
|
+
const directory = path46.join(dataDir, "plugins");
|
|
48870
49273
|
try {
|
|
48871
|
-
const hasManifest = isManifestFile(
|
|
48872
|
-
(entry) => (entry.isDirectory() || entry.isSymbolicLink()) && isManifestFile(
|
|
49274
|
+
const hasManifest = isManifestFile(path46.join(directory, "manifest.json")) || fs23.readdirSync(directory, { withFileTypes: true }).some(
|
|
49275
|
+
(entry) => (entry.isDirectory() || entry.isSymbolicLink()) && isManifestFile(path46.join(directory, entry.name, "manifest.json"))
|
|
48873
49276
|
);
|
|
48874
49277
|
if (hasManifest) return "Plugin runners were removed; manifests in ~/.ordewell/plugins/ are ignored. See the CHANGELOG.";
|
|
48875
49278
|
} catch {
|
|
@@ -48880,15 +49283,15 @@ function removedPluginNotice(dataDir = globalDataDir()) {
|
|
|
48880
49283
|
|
|
48881
49284
|
// src/utils/stateStore.ts
|
|
48882
49285
|
var fs24 = __toESM(require("fs"));
|
|
48883
|
-
var
|
|
49286
|
+
var path47 = __toESM(require("path"));
|
|
48884
49287
|
var STATE_FILE2 = "state.json";
|
|
48885
49288
|
function getStatePath(baseDir) {
|
|
48886
|
-
return
|
|
49289
|
+
return path47.join(getStateDir(baseDir), STATE_FILE2);
|
|
48887
49290
|
}
|
|
48888
49291
|
var SESSION_ID_KEY = "sessionId";
|
|
48889
49292
|
function saveState(plan, baseDir, sessionId) {
|
|
48890
49293
|
const statePath = getStatePath(baseDir ?? process.cwd());
|
|
48891
|
-
ensureDir(
|
|
49294
|
+
ensureDir(path47.dirname(statePath));
|
|
48892
49295
|
plan.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
48893
49296
|
const file = sessionId ? { ...plan, [SESSION_ID_KEY]: sessionId } : plan;
|
|
48894
49297
|
dropRetiredPlanFields(file);
|
|
@@ -49175,6 +49578,7 @@ var PlannerModelMemory = class {
|
|
|
49175
49578
|
assignedRunnerOf,
|
|
49176
49579
|
assignmentIssue,
|
|
49177
49580
|
assignmentIssueText,
|
|
49581
|
+
attachingLabel,
|
|
49178
49582
|
augmentedPath,
|
|
49179
49583
|
automergeSummary,
|
|
49180
49584
|
autonomyLevelLabel,
|