@odla-ai/harness 0.9.0 → 0.9.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/dist/{chunk-CR6RE3A2.js → chunk-5LRYJKUI.js} +3 -3
- package/dist/chunk-FAN2R3GW.js +166 -0
- package/dist/chunk-FAN2R3GW.js.map +1 -0
- package/dist/{chunk-NWNBSX56.js → chunk-OZBJNTML.js} +4 -4
- package/dist/{chunk-NG7AYYH3.js → chunk-Q4NL5XO3.js} +204 -217
- package/dist/chunk-Q4NL5XO3.js.map +1 -0
- package/dist/{chunk-RXNHCGWE.js → chunk-U324RQ4N.js} +1 -1
- package/dist/{chunk-RXNHCGWE.js.map → chunk-U324RQ4N.js.map} +1 -1
- package/dist/{chunk-Q7CKOT7T.js → chunk-VDY5V7ZG.js} +2 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/code-runtime-cli.cjs +311 -164
- package/dist/code-runtime-cli.cjs.map +1 -1
- package/dist/code-runtime-cli.js +12 -6
- package/dist/code-runtime-cli.js.map +1 -1
- package/dist/index.cjs +172 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -3
- package/dist/index.d.ts +24 -3
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +308 -162
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +44 -7
- package/dist/node.d.ts +44 -7
- package/dist/node.js +10 -5
- package/dist/node.js.map +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/{types-BNJikP5h.d.ts → types-_8y8vBDI.d.cts} +19 -1
- package/dist/{types-BNJikP5h.d.cts → types-_8y8vBDI.d.ts} +19 -1
- package/package.json +1 -1
- package/dist/chunk-NG7AYYH3.js.map +0 -1
- /package/dist/{chunk-CR6RE3A2.js.map → chunk-5LRYJKUI.js.map} +0 -0
- /package/dist/{chunk-NWNBSX56.js.map → chunk-OZBJNTML.js.map} +0 -0
- /package/dist/{chunk-Q7CKOT7T.js.map → chunk-VDY5V7ZG.js.map} +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
observedBroker
|
|
3
|
+
} from "./chunk-FAN2R3GW.js";
|
|
1
4
|
import {
|
|
2
5
|
SKIP_WORKSPACE_DIRS,
|
|
3
6
|
assertPinnedImage,
|
|
4
7
|
stageWorkspace,
|
|
5
8
|
stageWorkspacePair,
|
|
6
9
|
verifyContainerEngineBoundary
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5LRYJKUI.js";
|
|
8
11
|
import {
|
|
9
12
|
HARNESS_PROTOCOL_VERSION
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-U324RQ4N.js";
|
|
11
14
|
|
|
12
15
|
// src/workspace-digest.ts
|
|
13
16
|
import { createHash } from "crypto";
|
|
@@ -186,12 +189,14 @@ async function runCodeRuntimeHeartbeatLoop(options) {
|
|
|
186
189
|
} while (!options.signal?.aborted);
|
|
187
190
|
}
|
|
188
191
|
var CodeRuntimeReconciler = class {
|
|
189
|
-
constructor(control, engine) {
|
|
192
|
+
constructor(control, engine, onDiagnostic) {
|
|
190
193
|
this.control = control;
|
|
191
194
|
this.engine = engine;
|
|
195
|
+
this.onDiagnostic = onDiagnostic;
|
|
192
196
|
}
|
|
193
197
|
control;
|
|
194
198
|
engine;
|
|
199
|
+
onDiagnostic;
|
|
195
200
|
results = /* @__PURE__ */ new Map();
|
|
196
201
|
async reconcile(snapshot) {
|
|
197
202
|
for (const command of snapshot.commands) {
|
|
@@ -209,7 +214,13 @@ var CodeRuntimeReconciler = class {
|
|
|
209
214
|
}
|
|
210
215
|
await this.control.acknowledge(command.commandId, completed.result);
|
|
211
216
|
if (!completed.notified) {
|
|
212
|
-
|
|
217
|
+
try {
|
|
218
|
+
await this.engine.acknowledged?.(command, completed.result);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
this.onDiagnostic?.(
|
|
221
|
+
`command ${command.commandId} acknowledged handling failed \xB7 ${error instanceof Error ? error.message : String(error)}`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
213
224
|
completed.notified = true;
|
|
214
225
|
}
|
|
215
226
|
}
|
|
@@ -336,7 +347,7 @@ async function parseSource(value) {
|
|
|
336
347
|
}
|
|
337
348
|
function parseReview(value) {
|
|
338
349
|
const review = record(record(value)?.review);
|
|
339
|
-
if (!review || !["approved", "rejected"].includes(String(review.verdict)) || typeof review.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(review.reviewDigest) || typeof review.provider !== "string" || !review.provider || typeof review.model !== "string" || !review.model || !Number.isSafeInteger(review.policyVersion) || Number(review.policyVersion) < 1) throw invalid("review");
|
|
350
|
+
if (!review || !["approved", "rejected"].includes(String(review.verdict)) || typeof review.reviewDigest !== "string" || !/^sha256:[0-9a-f]{64}$/.test(review.reviewDigest) || typeof review.provider !== "string" || !review.provider || typeof review.model !== "string" || !review.model || !Number.isSafeInteger(review.policyVersion) || Number(review.policyVersion) < 1 || !Number.isSafeInteger(review.score) || Number(review.score) < 0 || Number(review.score) > 100 || typeof review.summary !== "string" || !Array.isArray(review.findings) || review.findings.length > 12) throw invalid("review");
|
|
340
351
|
return review;
|
|
341
352
|
}
|
|
342
353
|
function parseCandidate(value) {
|
|
@@ -443,10 +454,41 @@ var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-toke
|
|
|
443
454
|
var PATH = /^[A-Za-z0-9_@+.,-]+(?:\/[A-Za-z0-9_@+.,-]+)*$/;
|
|
444
455
|
var FORBIDDEN = /^(?:GIT binary patch|Binary files |rename (?:from|to) |copy (?:from|to) |similarity index |old mode |new mode |deleted file mode 160000|new file mode 160000)/m;
|
|
445
456
|
function stripPatchEnvelope(patch2) {
|
|
446
|
-
if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return patch2;
|
|
457
|
+
if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return applyPatchDialectToDiff(patch2);
|
|
447
458
|
const kept = patch2.split("\n").filter((line) => !/^\*\*\* (?:Begin|End) Patch\s*$/.test(line));
|
|
448
459
|
const stripped = kept.join("\n");
|
|
449
|
-
|
|
460
|
+
if (/^diff --git /m.test(stripped)) return stripped;
|
|
461
|
+
const translated = applyPatchDialectToDiff(stripped);
|
|
462
|
+
return translated === stripped ? patch2 : translated;
|
|
463
|
+
}
|
|
464
|
+
function applyPatchDialectToDiff(patch2) {
|
|
465
|
+
if (!/^\*\*\* (?:Update|Add|Delete) File: /m.test(patch2)) return patch2;
|
|
466
|
+
const out = [];
|
|
467
|
+
let open = false;
|
|
468
|
+
for (const line of patch2.split("\n")) {
|
|
469
|
+
const file = /^\*\*\* (Update|Add|Delete) File: (.+?)\s*$/.exec(line);
|
|
470
|
+
if (file) {
|
|
471
|
+
const [, verb, raw] = file;
|
|
472
|
+
const path = raw.trim();
|
|
473
|
+
if (!PATH.test(path)) return patch2;
|
|
474
|
+
out.push(`diff --git a/${path} b/${path}`);
|
|
475
|
+
if (verb === "Add") out.push("new file mode 100644", "--- /dev/null", `+++ b/${path}`);
|
|
476
|
+
else if (verb === "Delete") out.push(`--- a/${path}`, "+++ /dev/null");
|
|
477
|
+
else out.push(`--- a/${path}`, `+++ b/${path}`);
|
|
478
|
+
open = true;
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (/^\*\*\* /.test(line)) continue;
|
|
482
|
+
if (!open) continue;
|
|
483
|
+
if (/^@@/.test(line)) {
|
|
484
|
+
out.push("@@ -1 +1 @@");
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
out.push(line);
|
|
488
|
+
}
|
|
489
|
+
if (!open) return patch2;
|
|
490
|
+
return `${out.join("\n").replace(/\n+$/, "")}
|
|
491
|
+
`;
|
|
450
492
|
}
|
|
451
493
|
function validateCodePatch(rawPatch, maxBytes) {
|
|
452
494
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
@@ -462,7 +504,7 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
462
504
|
if (FORBIDDEN.test(patch2) || /(?:old|new)(?: file)? mode 120000/.test(patch2)) {
|
|
463
505
|
throw new TypeError("patch uses a forbidden binary, link, mode, rename, or copy operation");
|
|
464
506
|
}
|
|
465
|
-
const
|
|
507
|
+
const paths = [];
|
|
466
508
|
const lines = patch2.split("\n");
|
|
467
509
|
for (let index = 0; index < lines.length; index += 1) {
|
|
468
510
|
const line = lines[index];
|
|
@@ -478,10 +520,10 @@ function validateCodePatch(rawPatch, maxBytes) {
|
|
|
478
520
|
if (!validHeaderPath(oldPath, path, "a") || !validHeaderPath(newPath, path, "b")) {
|
|
479
521
|
throw new TypeError("patch file headers do not match the declared path");
|
|
480
522
|
}
|
|
481
|
-
|
|
523
|
+
paths.push(path);
|
|
482
524
|
}
|
|
483
|
-
if (!
|
|
484
|
-
return
|
|
525
|
+
if (!paths.length || new Set(paths).size !== paths.length) throw new TypeError("patch has no diffs or repeats a path");
|
|
526
|
+
return paths;
|
|
485
527
|
}
|
|
486
528
|
function validHeaderPath(value, path, prefix) {
|
|
487
529
|
return value === "/dev/null" || value === `${prefix}/${path}`;
|
|
@@ -499,18 +541,21 @@ function resolveCodePath(workspaceDir, path) {
|
|
|
499
541
|
if (target !== root && !target.startsWith(`${root}${sep}`)) throw new TypeError("path escapes the staged workspace");
|
|
500
542
|
return target;
|
|
501
543
|
}
|
|
544
|
+
function hasContextFreeHunk(patch2) {
|
|
545
|
+
const bodies = patch2.split(/^@@.*$/m).slice(1);
|
|
546
|
+
return bodies.some((body) => !body.split("\n").some((line) => line.startsWith(" ") && line.trim().length > 0));
|
|
547
|
+
}
|
|
502
548
|
function describePatchFailure(patch2, detail) {
|
|
503
549
|
const hunks = patch2.split("\n").filter((line) => line.startsWith("@@"));
|
|
504
|
-
const
|
|
505
|
-
const contextless = bodies.some((body) => !body.split("\n").some((line) => line.startsWith(" ") && line.trim().length > 0));
|
|
506
|
-
const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
550
|
+
const hint = hunks.length > 0 && hasContextFreeHunk(patch2) ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
|
|
507
551
|
return `patch did not apply: ${detail}${hint}`;
|
|
508
552
|
}
|
|
509
|
-
async function applyCodePatch(workspaceDir, rawPatch,
|
|
553
|
+
async function applyCodePatch(workspaceDir, rawPatch, paths) {
|
|
510
554
|
const patch2 = stripPatchEnvelope(rawPatch);
|
|
511
|
-
|
|
512
|
-
await gitApply(workspaceDir, patch2,
|
|
513
|
-
|
|
555
|
+
const zero = hasContextFreeHunk(patch2);
|
|
556
|
+
await gitApply(workspaceDir, patch2, true, zero);
|
|
557
|
+
await gitApply(workspaceDir, patch2, false, zero);
|
|
558
|
+
for (const path of paths) {
|
|
514
559
|
try {
|
|
515
560
|
const info = await lstat(resolveCodePath(workspaceDir, path));
|
|
516
561
|
if (info.isSymbolicLink() || !info.isFile() && !info.isDirectory()) {
|
|
@@ -521,9 +566,16 @@ async function applyCodePatch(workspaceDir, rawPatch, paths2) {
|
|
|
521
566
|
}
|
|
522
567
|
}
|
|
523
568
|
}
|
|
524
|
-
function gitApply(cwd, patch2, check) {
|
|
569
|
+
function gitApply(cwd, patch2, check, unidiffZero = false) {
|
|
525
570
|
return new Promise((accept, reject) => {
|
|
526
|
-
const args = [
|
|
571
|
+
const args = [
|
|
572
|
+
"apply",
|
|
573
|
+
"--recount",
|
|
574
|
+
...unidiffZero ? ["--unidiff-zero"] : [],
|
|
575
|
+
"--whitespace=nowarn",
|
|
576
|
+
...check ? ["--check"] : [],
|
|
577
|
+
"-"
|
|
578
|
+
];
|
|
527
579
|
const child = spawn("git", args, {
|
|
528
580
|
cwd,
|
|
529
581
|
shell: false,
|
|
@@ -532,8 +584,8 @@ function gitApply(cwd, patch2, check) {
|
|
|
532
584
|
});
|
|
533
585
|
let stderr = "";
|
|
534
586
|
child.stderr.setEncoding("utf8");
|
|
535
|
-
child.stderr.on("data", (
|
|
536
|
-
if (stderr.length < 4e3) stderr +=
|
|
587
|
+
child.stderr.on("data", (text) => {
|
|
588
|
+
if (stderr.length < 4e3) stderr += text.slice(0, 4e3);
|
|
537
589
|
});
|
|
538
590
|
child.once("error", reject);
|
|
539
591
|
child.once("exit", (code) => code === 0 ? accept() : reject(new TypeError(describePatchFailure(patch2, stderr.trim().slice(0, 500)))));
|
|
@@ -563,8 +615,8 @@ async function restoreCodeWorkspaceCheckpoint(input) {
|
|
|
563
615
|
const workspace = await stageWorkspace(input.trustedBaseDir, input.stage);
|
|
564
616
|
try {
|
|
565
617
|
if (checkpoint.patch) {
|
|
566
|
-
const
|
|
567
|
-
await applyCodePatch(workspace.workspaceDir, checkpoint.patch,
|
|
618
|
+
const paths = validateCodePatch(checkpoint.patch, 256 * 1024);
|
|
619
|
+
await applyCodePatch(workspace.workspaceDir, checkpoint.patch, paths);
|
|
568
620
|
}
|
|
569
621
|
return { workspace, checkpoint };
|
|
570
622
|
} catch (error) {
|
|
@@ -733,8 +785,8 @@ async function verifyCodeCandidate(input) {
|
|
|
733
785
|
try {
|
|
734
786
|
const baseDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
735
787
|
if (baseDigest !== input.trustedBaseDigest) throw new TypeError("trusted base does not match its registered digest");
|
|
736
|
-
const
|
|
737
|
-
await applyCodePatch(staged.workspaceDir, input.candidatePatch,
|
|
788
|
+
const paths = validateCodePatch(input.candidatePatch, policy.maximumPatchBytes);
|
|
789
|
+
await applyCodePatch(staged.workspaceDir, input.candidatePatch, paths);
|
|
738
790
|
const sourceDigest = await digestStagedWorkspace(staged.workspaceDir, limits);
|
|
739
791
|
const policyDigest = digestPolicy(policy);
|
|
740
792
|
const patchDigest = digestBytes(input.candidatePatch);
|
|
@@ -743,7 +795,7 @@ async function verifyCodeCandidate(input) {
|
|
|
743
795
|
trustedBaseDigest: input.trustedBaseDigest,
|
|
744
796
|
patchDigest
|
|
745
797
|
});
|
|
746
|
-
const changedTests = changedTestPaths(
|
|
798
|
+
const changedTests = changedTestPaths(paths, policy);
|
|
747
799
|
if (changedTests.length > policy.maximumChangedTests) throw new TypeError("candidate changes too many test files");
|
|
748
800
|
const recipes = [];
|
|
749
801
|
const logs = [];
|
|
@@ -810,8 +862,8 @@ function validate(input) {
|
|
|
810
862
|
}
|
|
811
863
|
return result;
|
|
812
864
|
}
|
|
813
|
-
function changedTestPaths(
|
|
814
|
-
return
|
|
865
|
+
function changedTestPaths(paths, policy) {
|
|
866
|
+
return paths.filter((path) => policy.testPathSuffixes.some((suffix) => path.endsWith(suffix)) || policy.testPathPrefixes.some((prefix) => path.startsWith(prefix) || path.includes(`/${prefix}`))).sort();
|
|
815
867
|
}
|
|
816
868
|
function recipeReceipt(recipe2, result, artifacts) {
|
|
817
869
|
const status = result.timedOut ? "timed_out" : result.outputLimitExceeded ? "output_limited" : result.exitCode === 0 && artifacts.every((item) => item.status === "verified") ? "passed" : "failed";
|
|
@@ -935,9 +987,9 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
935
987
|
if (evidence.receipt.outcome === "passed") {
|
|
936
988
|
verification = evidence.receipt;
|
|
937
989
|
review = await input.review(patch2, verification);
|
|
938
|
-
note = review
|
|
990
|
+
note = describeReview(review);
|
|
939
991
|
} else {
|
|
940
|
-
note =
|
|
992
|
+
note = describeGateFailure(evidence);
|
|
941
993
|
}
|
|
942
994
|
} catch (cause) {
|
|
943
995
|
note = `Candidate verification or review failed closed: ${message(cause)}`;
|
|
@@ -962,6 +1014,23 @@ async function prepareRuntimeCheckpoint(input) {
|
|
|
962
1014
|
});
|
|
963
1015
|
return { checkpoint, verification, review, note };
|
|
964
1016
|
}
|
|
1017
|
+
function describeReview(review) {
|
|
1018
|
+
const findings = review.findings.map((finding) => ` - [${finding.severity}] ${finding.detail}`).join("\n");
|
|
1019
|
+
const head = review.verdict === "approved" ? `Clean verification and independent review passed (score ${review.score}/100).` : `Clean verification passed; independent review REJECTED this candidate (score ${review.score}/100). Address the findings and checkpoint again.`;
|
|
1020
|
+
return [head, review.summary, findings].filter(Boolean).join("\n").slice(0, 4e3);
|
|
1021
|
+
}
|
|
1022
|
+
function describeGateFailure(evidence) {
|
|
1023
|
+
const failed = evidence.receipt.recipes.filter((recipe2) => recipe2.status !== "passed");
|
|
1024
|
+
const detail = failed.map((recipe2) => {
|
|
1025
|
+
const log = evidence.logs.find((entry) => entry.recipeId === recipe2.recipeId);
|
|
1026
|
+
const output = `${log?.stdout ?? ""}
|
|
1027
|
+
${log?.stderr ?? ""}`.trim();
|
|
1028
|
+
return `${recipe2.recipeId}=${recipe2.status}${output ? `
|
|
1029
|
+
${output.slice(0, 1500)}` : ""}`;
|
|
1030
|
+
}).join("\n\n");
|
|
1031
|
+
return `Clean verification failed. Fix this and checkpoint again:
|
|
1032
|
+
${detail}`.slice(0, 4e3);
|
|
1033
|
+
}
|
|
965
1034
|
var message = (value) => (value instanceof Error ? value.message : String(value)).slice(0, 500);
|
|
966
1035
|
|
|
967
1036
|
// src/code-runtime-checkpoint-manager.ts
|
|
@@ -1618,7 +1687,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
1618
1687
|
files(root) {
|
|
1619
1688
|
const existing = cache2.get(root);
|
|
1620
1689
|
if (existing) return existing;
|
|
1621
|
-
const pending = enumerate(root, limit).then((
|
|
1690
|
+
const pending = enumerate(root, limit).then((paths) => Object.freeze(paths));
|
|
1622
1691
|
cache2.set(root, pending);
|
|
1623
1692
|
void pending.catch(() => {
|
|
1624
1693
|
if (cache2.get(root) === pending) cache2.delete(root);
|
|
@@ -1631,7 +1700,7 @@ function createWorkspaceFileRegistry(limit = DEFAULT_MAX_FILES, enumerate = regi
|
|
|
1631
1700
|
};
|
|
1632
1701
|
}
|
|
1633
1702
|
async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
1634
|
-
const
|
|
1703
|
+
const paths = [];
|
|
1635
1704
|
const walk = async (directory) => {
|
|
1636
1705
|
for (const entry of await readdir2(directory, { withFileTypes: true })) {
|
|
1637
1706
|
if (SKIP_WORKSPACE_DIRS.has(entry.name)) continue;
|
|
@@ -1645,26 +1714,26 @@ async function registeredFiles(root, limit = DEFAULT_MAX_FILES) {
|
|
|
1645
1714
|
} catch {
|
|
1646
1715
|
continue;
|
|
1647
1716
|
}
|
|
1648
|
-
|
|
1649
|
-
if (
|
|
1717
|
+
paths.push(path);
|
|
1718
|
+
if (paths.length > limit) throw new TypeError("workspace file registry exceeds its bound");
|
|
1650
1719
|
}
|
|
1651
1720
|
}
|
|
1652
1721
|
};
|
|
1653
1722
|
await walk(resolve4(root));
|
|
1654
|
-
return
|
|
1723
|
+
return paths.sort();
|
|
1655
1724
|
}
|
|
1656
|
-
function listWorkspace(
|
|
1725
|
+
function listWorkspace(paths, options = {}) {
|
|
1657
1726
|
const max = options.maxEntries ?? 1e3;
|
|
1658
1727
|
const prefix = options.prefix?.replace(/\/+$/, "");
|
|
1659
|
-
const scoped = prefix ?
|
|
1728
|
+
const scoped = prefix ? paths.filter((path) => path === prefix || path.startsWith(`${prefix}/`)) : [...paths];
|
|
1660
1729
|
return scoped.slice(0, max);
|
|
1661
1730
|
}
|
|
1662
|
-
async function searchWorkspace(root,
|
|
1731
|
+
async function searchWorkspace(root, paths, options) {
|
|
1663
1732
|
options.signal?.throwIfAborted();
|
|
1664
1733
|
if (!options.query) throw new TypeError("search query must be a non-empty string");
|
|
1665
1734
|
const maxResults = options.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
1666
1735
|
const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
1667
|
-
const scoped = listWorkspace(
|
|
1736
|
+
const scoped = listWorkspace(paths, { ...options.prefix ? { prefix: options.prefix } : {}, maxEntries: paths.length });
|
|
1668
1737
|
if (scoped.length === 0) return [];
|
|
1669
1738
|
try {
|
|
1670
1739
|
return await nativeSearch(root, scoped, { ...options, maxResults, maxFileBytes });
|
|
@@ -1674,11 +1743,11 @@ async function searchWorkspace(root, paths2, options) {
|
|
|
1674
1743
|
}
|
|
1675
1744
|
}
|
|
1676
1745
|
var MAX_NATIVE_ARG_BYTES = 96 * 1024;
|
|
1677
|
-
async function nativeSearch(root,
|
|
1746
|
+
async function nativeSearch(root, paths, options) {
|
|
1678
1747
|
const batches = [];
|
|
1679
1748
|
let batch = [];
|
|
1680
1749
|
let bytes = 0;
|
|
1681
|
-
for (const path of
|
|
1750
|
+
for (const path of paths) {
|
|
1682
1751
|
const size = Buffer.byteLength(path) + 1;
|
|
1683
1752
|
if (batch.length > 0 && bytes + size > MAX_NATIVE_ARG_BYTES) {
|
|
1684
1753
|
batches.push(batch);
|
|
@@ -1697,7 +1766,7 @@ async function nativeSearch(root, paths2, options) {
|
|
|
1697
1766
|
}
|
|
1698
1767
|
return matches;
|
|
1699
1768
|
}
|
|
1700
|
-
function nativeSearchBatch(root,
|
|
1769
|
+
function nativeSearchBatch(root, paths, options, remaining) {
|
|
1701
1770
|
return new Promise((resolveMatches, reject) => {
|
|
1702
1771
|
const args = [
|
|
1703
1772
|
"--fixed-strings",
|
|
@@ -1710,7 +1779,7 @@ function nativeSearchBatch(root, paths2, options, remaining) {
|
|
|
1710
1779
|
options.caseSensitive === false ? "--ignore-case" : "--case-sensitive",
|
|
1711
1780
|
"--",
|
|
1712
1781
|
options.query,
|
|
1713
|
-
...
|
|
1782
|
+
...paths
|
|
1714
1783
|
];
|
|
1715
1784
|
const child = spawn3("rg", args, {
|
|
1716
1785
|
cwd: root,
|
|
@@ -1908,16 +1977,16 @@ function createCodePolicyGate(options) {
|
|
|
1908
1977
|
}
|
|
1909
1978
|
};
|
|
1910
1979
|
}
|
|
1911
|
-
function directoryPrefixes(
|
|
1980
|
+
function directoryPrefixes(paths) {
|
|
1912
1981
|
const prefixes = /* @__PURE__ */ new Set(["."]);
|
|
1913
|
-
for (const path of
|
|
1982
|
+
for (const path of paths) {
|
|
1914
1983
|
const parts = path.split("/");
|
|
1915
1984
|
for (let index = 1; index < parts.length; index += 1) prefixes.add(parts.slice(0, index).join("/"));
|
|
1916
1985
|
}
|
|
1917
1986
|
return [...prefixes].sort();
|
|
1918
1987
|
}
|
|
1919
|
-
async function safePrefix(base,
|
|
1920
|
-
const prefixes = directoryPrefixes(
|
|
1988
|
+
async function safePrefix(base, paths, prefix) {
|
|
1989
|
+
const prefixes = directoryPrefixes(paths);
|
|
1921
1990
|
const conversions = await conversionRegistry(
|
|
1922
1991
|
[await registeredPolicy("code.prefix.v1", "code.prefixes.v1", prefixes)],
|
|
1923
1992
|
{ "code.prefixes.v1": prefixes }
|
|
@@ -2027,8 +2096,14 @@ function optionalInteger(value) {
|
|
|
2027
2096
|
if (!Number.isSafeInteger(value) || value < 1) throw new TypeError("line bounds must be positive integers");
|
|
2028
2097
|
return value;
|
|
2029
2098
|
}
|
|
2099
|
+
var DEFAULT_FAILURE_REASON = {
|
|
2100
|
+
"tool denied by CaMeL policy": "tool denied by CaMeL policy",
|
|
2101
|
+
"review sessions are read-only": "review session is read-only; workspace changes are not permitted"
|
|
2102
|
+
};
|
|
2030
2103
|
function response(request, ok, content, details) {
|
|
2031
|
-
return { requestId: request.requestId, ok, content, ...details ? { details } : {} };
|
|
2104
|
+
if (ok) return { requestId: request.requestId, ok, content, ...details ? { details } : {} };
|
|
2105
|
+
const failureReason = typeof details?.failureReason === "string" && details.failureReason || DEFAULT_FAILURE_REASON[content] || content || "tool request failed; inspect the tool input and workspace state";
|
|
2106
|
+
return { requestId: request.requestId, ok, content, details: { ...details, failureReason } };
|
|
2032
2107
|
}
|
|
2033
2108
|
|
|
2034
2109
|
// src/code-tool-reads.ts
|
|
@@ -2047,7 +2122,7 @@ import {
|
|
|
2047
2122
|
} from "@odla-ai/graph";
|
|
2048
2123
|
import { buildCodeGraph, FILE, IMPORTS, PACKAGE, READS, SYMBOL, WRITES } from "@odla-ai/graph/code";
|
|
2049
2124
|
var cache = /* @__PURE__ */ new Map();
|
|
2050
|
-
function workspaceGraphs(workspaceDir,
|
|
2125
|
+
function workspaceGraphs(workspaceDir, paths) {
|
|
2051
2126
|
const existing = cache.get(workspaceDir);
|
|
2052
2127
|
if (existing) return existing;
|
|
2053
2128
|
const read2 = (path) => readFile3(join3(workspaceDir, path), "utf8");
|
|
@@ -2055,7 +2130,7 @@ function workspaceGraphs(workspaceDir, paths2) {
|
|
|
2055
2130
|
// No knownTables: a staged workspace may not carry migrations, and a filter
|
|
2056
2131
|
// that silently drops every table is worse than an unfiltered one. Callers
|
|
2057
2132
|
// with ground truth should build the graph themselves.
|
|
2058
|
-
graph: await buildCodeGraph({ paths
|
|
2133
|
+
graph: await buildCodeGraph({ paths, read: read2, data: { ignore: (path) => path.includes(".generated.") } })
|
|
2059
2134
|
}))();
|
|
2060
2135
|
cache.set(workspaceDir, built);
|
|
2061
2136
|
return built;
|
|
@@ -2117,11 +2192,11 @@ async function read(context, request, options, policy, registry) {
|
|
|
2117
2192
|
if (endLine < startLine || endLine - startLine + 1 > (options.maxReadLines ?? 2e3)) {
|
|
2118
2193
|
throw new TypeError("requested line range exceeds its bound");
|
|
2119
2194
|
}
|
|
2120
|
-
const
|
|
2121
|
-
if (!
|
|
2195
|
+
const paths = await registry.files(context.workspaceDir);
|
|
2196
|
+
if (!paths.includes(path)) {
|
|
2122
2197
|
throw new TypeError(`no such file in the staged workspace: "${path}". Use sandbox.overview, sandbox.where_is or sandbox.search to find the correct path.`);
|
|
2123
2198
|
}
|
|
2124
|
-
const allowed = await policy.read(policyContext(context, request, options, { paths
|
|
2199
|
+
const allowed = await policy.read(policyContext(context, request, options, { paths, path, startLine, endLine }));
|
|
2125
2200
|
if (!allowed) return response(request, false, "tool denied by CaMeL policy");
|
|
2126
2201
|
const target = resolveCodePath(context.workspaceDir, path);
|
|
2127
2202
|
const info = await stat(target);
|
|
@@ -2143,16 +2218,16 @@ async function list(context, request, options, policy, registry) {
|
|
|
2143
2218
|
const prefix = typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
2144
2219
|
const maxEntries = optionalInteger(request.input.maxEntries) ?? 1e3;
|
|
2145
2220
|
if (maxEntries > 5e3) throw new TypeError("maxEntries exceeds its bound");
|
|
2146
|
-
const
|
|
2147
|
-
const allowed = await policy.list(policyContext(context, request, options, { paths
|
|
2221
|
+
const paths = await registry.files(context.workspaceDir);
|
|
2222
|
+
const allowed = await policy.list(policyContext(context, request, options, { paths, ...prefix ? { prefix } : {} }));
|
|
2148
2223
|
if (!allowed) return response(request, false, "tool denied by CaMeL policy");
|
|
2149
|
-
const entries = listWorkspace(
|
|
2224
|
+
const entries = listWorkspace(paths, { ...prefix ? { prefix } : {}, maxEntries });
|
|
2150
2225
|
if (!entries.length) {
|
|
2151
2226
|
return response(request, true, prefix ? `No files under "${prefix}".` : "Workspace is empty.", { count: 0 });
|
|
2152
2227
|
}
|
|
2153
|
-
const truncated = entries.length <
|
|
2154
|
-
const hint = !prefix &&
|
|
2155
|
-
\u2026 ${
|
|
2228
|
+
const truncated = entries.length < paths.length && entries.length === maxEntries;
|
|
2229
|
+
const hint = !prefix && paths.length > 500 ? `
|
|
2230
|
+
\u2026 ${paths.length} files total. sandbox.overview is far cheaper for orientation; use a prefix here once you know the area.` : "";
|
|
2156
2231
|
return response(
|
|
2157
2232
|
request,
|
|
2158
2233
|
true,
|
|
@@ -2170,10 +2245,10 @@ async function search(context, request, options, policy, registry) {
|
|
|
2170
2245
|
const maxResults = optionalInteger(request.input.maxResults) ?? 100;
|
|
2171
2246
|
if (maxResults > 500) throw new TypeError("maxResults exceeds its bound");
|
|
2172
2247
|
const caseSensitive = request.input.caseSensitive === void 0 ? true : request.input.caseSensitive === true;
|
|
2173
|
-
const
|
|
2174
|
-
const allowed = await policy.search(policyContext(context, request, options, { paths
|
|
2248
|
+
const paths = await registry.files(context.workspaceDir);
|
|
2249
|
+
const allowed = await policy.search(policyContext(context, request, options, { paths, query, ...prefix ? { prefix } : {} }));
|
|
2175
2250
|
if (!allowed) return response(request, false, "tool denied by CaMeL policy");
|
|
2176
|
-
const matches = await searchWorkspace(context.workspaceDir,
|
|
2251
|
+
const matches = await searchWorkspace(context.workspaceDir, paths, {
|
|
2177
2252
|
query,
|
|
2178
2253
|
maxResults,
|
|
2179
2254
|
caseSensitive,
|
|
@@ -2195,8 +2270,8 @@ async function graphQuery(context, request, options, policy, registry) {
|
|
|
2195
2270
|
selector: query
|
|
2196
2271
|
}));
|
|
2197
2272
|
if (!allowed) return response(request, false, "tool denied by CaMeL policy");
|
|
2198
|
-
const
|
|
2199
|
-
const graphs = await workspaceGraphs(context.workspaceDir,
|
|
2273
|
+
const paths = await registry.files(context.workspaceDir);
|
|
2274
|
+
const graphs = await workspaceGraphs(context.workspaceDir, paths);
|
|
2200
2275
|
if (request.tool === "sandbox.overview") {
|
|
2201
2276
|
return response(request, true, renderOverview(graphs, query || void 0));
|
|
2202
2277
|
}
|
|
@@ -2260,16 +2335,16 @@ function toolFailureMessage(reason) {
|
|
|
2260
2335
|
async function patch(context, request, options, policy, registry) {
|
|
2261
2336
|
exactKeys(request.input, ["patch"]);
|
|
2262
2337
|
const value = stringField(request.input, "patch");
|
|
2263
|
-
const
|
|
2264
|
-
if (
|
|
2338
|
+
const paths = validateCodePatch(value, options.maxPatchBytes ?? 256 * 1024);
|
|
2339
|
+
if (paths.some((path) => options.readOnlyPrefixes?.some((prefix) => path === prefix || path.startsWith(`${prefix}/`)))) {
|
|
2265
2340
|
throw new TypeError("patch targets a read-only reference source");
|
|
2266
2341
|
}
|
|
2267
2342
|
const allowed = await policy.patch(policyContext(context, request, options, { patch: value }));
|
|
2268
2343
|
if (!allowed) return response(request, false, "tool denied by CaMeL policy");
|
|
2269
|
-
await applyCodePatch(context.workspaceDir, value,
|
|
2344
|
+
await applyCodePatch(context.workspaceDir, value, paths);
|
|
2270
2345
|
registry.invalidate(context.workspaceDir);
|
|
2271
2346
|
forgetWorkspaceGraphs(context.workspaceDir);
|
|
2272
|
-
return response(request, true, `Applied patch to ${
|
|
2347
|
+
return response(request, true, `Applied patch to ${paths.length} file(s).`, { paths });
|
|
2273
2348
|
}
|
|
2274
2349
|
async function recipe(context, request, options, recipes, policy) {
|
|
2275
2350
|
exactKeys(request.input, ["recipeId"]);
|
|
@@ -2660,122 +2735,6 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
2660
2735
|
var digestRuntimeValue = (value) => `sha256:${createHash3("sha256").update(value).digest("hex")}`;
|
|
2661
2736
|
var runtimeErrorMessage = (value) => value instanceof Error ? value.message : String(value);
|
|
2662
2737
|
|
|
2663
|
-
// src/code-tool-presentation.ts
|
|
2664
|
-
var text = (value, maximum) => {
|
|
2665
|
-
if (typeof value !== "string") return void 0;
|
|
2666
|
-
const bounded = value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
|
|
2667
|
-
return bounded ? bounded.slice(0, maximum) : void 0;
|
|
2668
|
-
};
|
|
2669
|
-
var integer2 = (value) => Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : void 0;
|
|
2670
|
-
var record3 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2671
|
-
var excerpt = (value, tail = false) => {
|
|
2672
|
-
if (typeof value !== "string") return void 0;
|
|
2673
|
-
const safe = value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
|
|
2674
|
-
const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
|
|
2675
|
-
if (!source) return void 0;
|
|
2676
|
-
const lines = source.split("\n").filter((line) => line.trim()).map((line) => line.slice(0, 240));
|
|
2677
|
-
const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
|
|
2678
|
-
return text(selected.join("\n"), 2400);
|
|
2679
|
-
};
|
|
2680
|
-
var paths = (value) => {
|
|
2681
|
-
if (!Array.isArray(value)) return void 0;
|
|
2682
|
-
const items = value.flatMap((item) => {
|
|
2683
|
-
const path = text(item, 1024);
|
|
2684
|
-
return path ? [path] : [];
|
|
2685
|
-
}).slice(0, 12);
|
|
2686
|
-
return items.length ? items : void 0;
|
|
2687
|
-
};
|
|
2688
|
-
function patchStats(value) {
|
|
2689
|
-
if (typeof value !== "string") return {};
|
|
2690
|
-
let additions = 0;
|
|
2691
|
-
let deletions = 0;
|
|
2692
|
-
for (const line of value.slice(0, 262144).split("\n")) {
|
|
2693
|
-
if (line.startsWith("+++") || line.startsWith("---")) continue;
|
|
2694
|
-
if (line.startsWith("+")) additions += 1;
|
|
2695
|
-
else if (line.startsWith("-")) deletions += 1;
|
|
2696
|
-
}
|
|
2697
|
-
return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
|
|
2698
|
-
}
|
|
2699
|
-
function searchResults(value) {
|
|
2700
|
-
if (typeof value !== "string") return void 0;
|
|
2701
|
-
const results = value.split("\n").flatMap((line) => {
|
|
2702
|
-
const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line);
|
|
2703
|
-
if (!match) return [];
|
|
2704
|
-
const lineNumber = Number(match[2]);
|
|
2705
|
-
const itemText = text(match[3], 240);
|
|
2706
|
-
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
|
|
2707
|
-
return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
|
|
2708
|
-
}).slice(0, 5);
|
|
2709
|
-
return results.length ? results : void 0;
|
|
2710
|
-
}
|
|
2711
|
-
function codeToolRequestPresentation(request) {
|
|
2712
|
-
const input = request.input;
|
|
2713
|
-
if (request.tool === "sandbox.read") {
|
|
2714
|
-
const path = text(input.path, 1024);
|
|
2715
|
-
if (!path) return void 0;
|
|
2716
|
-
const startLine = integer2(input.startLine);
|
|
2717
|
-
const endLine = integer2(input.endLine);
|
|
2718
|
-
return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
|
|
2719
|
-
}
|
|
2720
|
-
if (request.tool === "sandbox.list") {
|
|
2721
|
-
const scope = text(input.prefix, 1024);
|
|
2722
|
-
return { kind: "list", ...scope ? { scope } : {} };
|
|
2723
|
-
}
|
|
2724
|
-
if (request.tool === "sandbox.search" || request.tool === "sandbox.overview" || request.tool === "sandbox.where_is" || request.tool === "sandbox.who_imports" || request.tool === "sandbox.who_touches") {
|
|
2725
|
-
const query = text(input.query, 512);
|
|
2726
|
-
const scope = request.tool === "sandbox.search" ? text(input.prefix, 1024) : void 0;
|
|
2727
|
-
if (request.tool === "sandbox.search" && !query) return void 0;
|
|
2728
|
-
return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
|
|
2729
|
-
}
|
|
2730
|
-
if (request.tool === "sandbox.apply_patch") {
|
|
2731
|
-
return { kind: "patch", ...patchStats(input.patch) };
|
|
2732
|
-
}
|
|
2733
|
-
const recipeId = text(input.recipeId, 120);
|
|
2734
|
-
return recipeId ? { kind: "recipe", recipeId } : void 0;
|
|
2735
|
-
}
|
|
2736
|
-
function codeToolResultPresentation(request, response2) {
|
|
2737
|
-
const started = codeToolRequestPresentation(request);
|
|
2738
|
-
if (!started || !response2.ok) return started;
|
|
2739
|
-
const details = record3(response2.details);
|
|
2740
|
-
if (started.kind === "read") {
|
|
2741
|
-
return {
|
|
2742
|
-
...started,
|
|
2743
|
-
...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
|
|
2744
|
-
...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
|
|
2745
|
-
...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
|
|
2746
|
-
};
|
|
2747
|
-
}
|
|
2748
|
-
if (started.kind === "list") {
|
|
2749
|
-
const listed = response2.content.split("\n").filter((line) => line && !line.startsWith("\u2026") && !line.startsWith("Workspace ")).map((line) => text(line, 1024)).filter((line) => Boolean(line)).slice(0, 8);
|
|
2750
|
-
return {
|
|
2751
|
-
...started,
|
|
2752
|
-
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
2753
|
-
...listed.length ? { paths: listed } : {}
|
|
2754
|
-
};
|
|
2755
|
-
}
|
|
2756
|
-
if (started.kind === "query") {
|
|
2757
|
-
const results = request.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
|
|
2758
|
-
const resultExcerpt = request.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
|
|
2759
|
-
return {
|
|
2760
|
-
...started,
|
|
2761
|
-
...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
|
|
2762
|
-
...results ? { results } : {},
|
|
2763
|
-
...resultExcerpt ? { excerpt: resultExcerpt } : {}
|
|
2764
|
-
};
|
|
2765
|
-
}
|
|
2766
|
-
if (started.kind === "patch") {
|
|
2767
|
-
return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
|
|
2768
|
-
}
|
|
2769
|
-
const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
|
|
2770
|
-
return {
|
|
2771
|
-
...started,
|
|
2772
|
-
...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
|
|
2773
|
-
...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
|
|
2774
|
-
...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
|
|
2775
|
-
...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
|
|
2776
|
-
};
|
|
2777
|
-
}
|
|
2778
|
-
|
|
2779
2738
|
// src/code-runtime-acknowledgement-gate.ts
|
|
2780
2739
|
function codeRuntimeAcknowledgementGate(signal) {
|
|
2781
2740
|
let settle;
|
|
@@ -2795,6 +2754,57 @@ function codeRuntimeAcknowledgementGate(signal) {
|
|
|
2795
2754
|
return { ready, release };
|
|
2796
2755
|
}
|
|
2797
2756
|
|
|
2757
|
+
// src/code-runtime-session-activity.ts
|
|
2758
|
+
function observeCodeRuntimeSessionSkills(command, skills, emit) {
|
|
2759
|
+
return skills.map((skill) => ({
|
|
2760
|
+
...skill,
|
|
2761
|
+
tools: skill.tools.map((tool) => {
|
|
2762
|
+
if (!tool.handler) return tool;
|
|
2763
|
+
const handler = tool.handler;
|
|
2764
|
+
return {
|
|
2765
|
+
...tool,
|
|
2766
|
+
handler: async (input, context) => {
|
|
2767
|
+
const startedAt = Date.now();
|
|
2768
|
+
const operationId = digestRuntimeValue(
|
|
2769
|
+
`${command.commandId}:${skill.name}:${tool.name}:${context.toolCallId ?? "missing"}`
|
|
2770
|
+
);
|
|
2771
|
+
await emit({
|
|
2772
|
+
type: "collaboration",
|
|
2773
|
+
phase: "started",
|
|
2774
|
+
skill: skill.name,
|
|
2775
|
+
tool: tool.name,
|
|
2776
|
+
operationId
|
|
2777
|
+
}).catch(() => void 0);
|
|
2778
|
+
try {
|
|
2779
|
+
const output = await handler(input, context);
|
|
2780
|
+
await emit({
|
|
2781
|
+
type: "collaboration",
|
|
2782
|
+
phase: "completed",
|
|
2783
|
+
skill: skill.name,
|
|
2784
|
+
tool: tool.name,
|
|
2785
|
+
operationId,
|
|
2786
|
+
ok: output.isError !== true,
|
|
2787
|
+
durationMs: Date.now() - startedAt
|
|
2788
|
+
}).catch(() => void 0);
|
|
2789
|
+
return output;
|
|
2790
|
+
} catch (cause) {
|
|
2791
|
+
await emit({
|
|
2792
|
+
type: "collaboration",
|
|
2793
|
+
phase: "completed",
|
|
2794
|
+
skill: skill.name,
|
|
2795
|
+
tool: tool.name,
|
|
2796
|
+
operationId,
|
|
2797
|
+
ok: false,
|
|
2798
|
+
durationMs: Date.now() - startedAt
|
|
2799
|
+
}).catch(() => void 0);
|
|
2800
|
+
throw cause;
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
};
|
|
2804
|
+
})
|
|
2805
|
+
}));
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2798
2808
|
// src/code-runtime-engine.ts
|
|
2799
2809
|
var TheseusRuntimeEngine = class {
|
|
2800
2810
|
constructor(options) {
|
|
@@ -2992,7 +3002,7 @@ var TheseusRuntimeEngine = class {
|
|
|
2992
3002
|
event: (event) => this.#event(command, event, active.conversationRefs)
|
|
2993
3003
|
});
|
|
2994
3004
|
await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
|
|
2995
|
-
const extraSkills = await sessionSkillsFor(this.options, command);
|
|
3005
|
+
const extraSkills = observeCodeRuntimeSessionSkills(command, await sessionSkillsFor(this.options, command), (event) => this.#event(command, event, active.conversationRefs));
|
|
2996
3006
|
const result = await this.#attempt({
|
|
2997
3007
|
inference,
|
|
2998
3008
|
broker,
|
|
@@ -3031,36 +3041,11 @@ var TheseusRuntimeEngine = class {
|
|
|
3031
3041
|
}
|
|
3032
3042
|
/** Report every brokered effect as it starts and finishes. */
|
|
3033
3043
|
#observed(command, active, broker) {
|
|
3034
|
-
return {
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
await this.#event(
|
|
3040
|
-
command,
|
|
3041
|
-
{
|
|
3042
|
-
type: "tool",
|
|
3043
|
-
phase: "started",
|
|
3044
|
-
tool: request.tool,
|
|
3045
|
-
operationId,
|
|
3046
|
-
...startedPresentation ? { presentation: startedPresentation } : {}
|
|
3047
|
-
},
|
|
3048
|
-
active.conversationRefs
|
|
3049
|
-
).catch(() => void 0);
|
|
3050
|
-
const response2 = await broker.execute(context, request);
|
|
3051
|
-
const completedPresentation = codeToolResultPresentation(request, response2);
|
|
3052
|
-
await this.#event(command, {
|
|
3053
|
-
type: "tool",
|
|
3054
|
-
phase: "completed",
|
|
3055
|
-
tool: request.tool,
|
|
3056
|
-
ok: response2.ok,
|
|
3057
|
-
durationMs: Date.now() - startedAt,
|
|
3058
|
-
operationId,
|
|
3059
|
-
...completedPresentation ? { presentation: completedPresentation } : {}
|
|
3060
|
-
}, active.conversationRefs).catch(() => void 0);
|
|
3061
|
-
return response2;
|
|
3062
|
-
}
|
|
3063
|
-
};
|
|
3044
|
+
return observedBroker({
|
|
3045
|
+
broker,
|
|
3046
|
+
operationIdFor: (requestId) => digestRuntimeValue(`${command.commandId}:${requestId}`),
|
|
3047
|
+
emit: (event) => this.#event(command, event, active.conversationRefs).catch(() => void 0)
|
|
3048
|
+
});
|
|
3064
3049
|
}
|
|
3065
3050
|
async #checkpoint(command) {
|
|
3066
3051
|
const active = this.#active.get(command.sessionId);
|
|
@@ -3097,9 +3082,11 @@ export {
|
|
|
3097
3082
|
runCodeRuntimeHeartbeatLoop,
|
|
3098
3083
|
CodeRuntimeReconciler,
|
|
3099
3084
|
stripPatchEnvelope,
|
|
3085
|
+
applyPatchDialectToDiff,
|
|
3100
3086
|
validateCodePatch,
|
|
3101
3087
|
validateRelativePath,
|
|
3102
3088
|
resolveCodePath,
|
|
3089
|
+
hasContextFreeHunk,
|
|
3103
3090
|
describePatchFailure,
|
|
3104
3091
|
applyCodePatch,
|
|
3105
3092
|
createCodeWorkspaceCheckpoint,
|
|
@@ -3134,4 +3121,4 @@ export {
|
|
|
3134
3121
|
runGoal,
|
|
3135
3122
|
TheseusRuntimeEngine
|
|
3136
3123
|
};
|
|
3137
|
-
//# sourceMappingURL=chunk-
|
|
3124
|
+
//# sourceMappingURL=chunk-Q4NL5XO3.js.map
|