@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.
Files changed (38) hide show
  1. package/dist/{chunk-CR6RE3A2.js → chunk-5LRYJKUI.js} +3 -3
  2. package/dist/chunk-FAN2R3GW.js +166 -0
  3. package/dist/chunk-FAN2R3GW.js.map +1 -0
  4. package/dist/{chunk-NWNBSX56.js → chunk-OZBJNTML.js} +4 -4
  5. package/dist/{chunk-NG7AYYH3.js → chunk-Q4NL5XO3.js} +204 -217
  6. package/dist/chunk-Q4NL5XO3.js.map +1 -0
  7. package/dist/{chunk-RXNHCGWE.js → chunk-U324RQ4N.js} +1 -1
  8. package/dist/{chunk-RXNHCGWE.js.map → chunk-U324RQ4N.js.map} +1 -1
  9. package/dist/{chunk-Q7CKOT7T.js → chunk-VDY5V7ZG.js} +2 -2
  10. package/dist/cli.cjs.map +1 -1
  11. package/dist/cli.js +4 -4
  12. package/dist/code-runtime-cli.cjs +311 -164
  13. package/dist/code-runtime-cli.cjs.map +1 -1
  14. package/dist/code-runtime-cli.js +12 -6
  15. package/dist/code-runtime-cli.js.map +1 -1
  16. package/dist/index.cjs +172 -6
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +24 -3
  19. package/dist/index.d.ts +24 -3
  20. package/dist/index.js +11 -3
  21. package/dist/index.js.map +1 -1
  22. package/dist/node.cjs +308 -162
  23. package/dist/node.cjs.map +1 -1
  24. package/dist/node.d.cts +44 -7
  25. package/dist/node.d.ts +44 -7
  26. package/dist/node.js +10 -5
  27. package/dist/node.js.map +1 -1
  28. package/dist/testing.cjs.map +1 -1
  29. package/dist/testing.d.cts +1 -1
  30. package/dist/testing.d.ts +1 -1
  31. package/dist/testing.js +1 -1
  32. package/dist/{types-BNJikP5h.d.ts → types-_8y8vBDI.d.cts} +19 -1
  33. package/dist/{types-BNJikP5h.d.cts → types-_8y8vBDI.d.ts} +19 -1
  34. package/package.json +1 -1
  35. package/dist/chunk-NG7AYYH3.js.map +0 -1
  36. /package/dist/{chunk-CR6RE3A2.js.map → chunk-5LRYJKUI.js.map} +0 -0
  37. /package/dist/{chunk-NWNBSX56.js.map → chunk-OZBJNTML.js.map} +0 -0
  38. /package/dist/{chunk-Q7CKOT7T.js.map → chunk-VDY5V7ZG.js.map} +0 -0
package/dist/node.cjs CHANGED
@@ -33,6 +33,7 @@ __export(node_exports, {
33
33
  V2_SYSTEM_PROMPT: () => V2_SYSTEM_PROMPT,
34
34
  V3_SYSTEM_PROMPT: () => V3_SYSTEM_PROMPT,
35
35
  applyCodePatch: () => applyCodePatch,
36
+ applyPatchDialectToDiff: () => applyPatchDialectToDiff,
36
37
  assertCodeBuildRecipe: () => assertCodeBuildRecipe,
37
38
  assertDisjointPlan: () => assertDisjointPlan,
38
39
  assertPinnedImage: () => assertPinnedImage,
@@ -50,6 +51,7 @@ __export(node_exports, {
50
51
  describePatchFailure: () => describePatchFailure,
51
52
  digestStagedWorkspace: () => digestStagedWorkspace,
52
53
  feedbackIsActionable: () => feedbackIsActionable,
54
+ hasContextFreeHunk: () => hasContextFreeHunk,
53
55
  hazardFromAttempt: () => hazardFromAttempt,
54
56
  installedDependencies: () => installedDependencies,
55
57
  integrateSubGoals: () => integrateSubGoals,
@@ -999,7 +1001,7 @@ async function parseSource(value) {
999
1001
  }
1000
1002
  function parseReview(value) {
1001
1003
  const review = record2(record2(value)?.review);
1002
- 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");
1004
+ 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");
1003
1005
  return review;
1004
1006
  }
1005
1007
  function parseCandidate(value) {
@@ -1240,12 +1242,14 @@ async function runCodeRuntimeHeartbeatLoop(options) {
1240
1242
  } while (!options.signal?.aborted);
1241
1243
  }
1242
1244
  var CodeRuntimeReconciler = class {
1243
- constructor(control, engine) {
1245
+ constructor(control, engine, onDiagnostic) {
1244
1246
  this.control = control;
1245
1247
  this.engine = engine;
1248
+ this.onDiagnostic = onDiagnostic;
1246
1249
  }
1247
1250
  control;
1248
1251
  engine;
1252
+ onDiagnostic;
1249
1253
  results = /* @__PURE__ */ new Map();
1250
1254
  async reconcile(snapshot) {
1251
1255
  for (const command of snapshot.commands) {
@@ -1263,7 +1267,13 @@ var CodeRuntimeReconciler = class {
1263
1267
  }
1264
1268
  await this.control.acknowledge(command.commandId, completed.result);
1265
1269
  if (!completed.notified) {
1266
- await this.engine.acknowledged?.(command, completed.result);
1270
+ try {
1271
+ await this.engine.acknowledged?.(command, completed.result);
1272
+ } catch (error) {
1273
+ this.onDiagnostic?.(
1274
+ `command ${command.commandId} acknowledged handling failed \xB7 ${error instanceof Error ? error.message : String(error)}`
1275
+ );
1276
+ }
1267
1277
  completed.notified = true;
1268
1278
  }
1269
1279
  }
@@ -1298,10 +1308,41 @@ var SECRET = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-toke
1298
1308
  var PATH = /^[A-Za-z0-9_@+.,-]+(?:\/[A-Za-z0-9_@+.,-]+)*$/;
1299
1309
  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;
1300
1310
  function stripPatchEnvelope(patch2) {
1301
- if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return patch2;
1311
+ if (!/^\*\*\* (?:Begin|End) Patch\s*$/m.test(patch2)) return applyPatchDialectToDiff(patch2);
1302
1312
  const kept = patch2.split("\n").filter((line) => !/^\*\*\* (?:Begin|End) Patch\s*$/.test(line));
1303
1313
  const stripped = kept.join("\n");
1304
- return /^diff --git /m.test(stripped) ? stripped : patch2;
1314
+ if (/^diff --git /m.test(stripped)) return stripped;
1315
+ const translated = applyPatchDialectToDiff(stripped);
1316
+ return translated === stripped ? patch2 : translated;
1317
+ }
1318
+ function applyPatchDialectToDiff(patch2) {
1319
+ if (!/^\*\*\* (?:Update|Add|Delete) File: /m.test(patch2)) return patch2;
1320
+ const out = [];
1321
+ let open = false;
1322
+ for (const line of patch2.split("\n")) {
1323
+ const file = /^\*\*\* (Update|Add|Delete) File: (.+?)\s*$/.exec(line);
1324
+ if (file) {
1325
+ const [, verb, raw] = file;
1326
+ const path = raw.trim();
1327
+ if (!PATH.test(path)) return patch2;
1328
+ out.push(`diff --git a/${path} b/${path}`);
1329
+ if (verb === "Add") out.push("new file mode 100644", "--- /dev/null", `+++ b/${path}`);
1330
+ else if (verb === "Delete") out.push(`--- a/${path}`, "+++ /dev/null");
1331
+ else out.push(`--- a/${path}`, `+++ b/${path}`);
1332
+ open = true;
1333
+ continue;
1334
+ }
1335
+ if (/^\*\*\* /.test(line)) continue;
1336
+ if (!open) continue;
1337
+ if (/^@@/.test(line)) {
1338
+ out.push("@@ -1 +1 @@");
1339
+ continue;
1340
+ }
1341
+ out.push(line);
1342
+ }
1343
+ if (!open) return patch2;
1344
+ return `${out.join("\n").replace(/\n+$/, "")}
1345
+ `;
1305
1346
  }
1306
1347
  function validateCodePatch(rawPatch, maxBytes) {
1307
1348
  const patch2 = stripPatchEnvelope(rawPatch);
@@ -1354,17 +1395,20 @@ function resolveCodePath(workspaceDir, path) {
1354
1395
  if (target !== root && !target.startsWith(`${root}${import_node_path6.sep}`)) throw new TypeError("path escapes the staged workspace");
1355
1396
  return target;
1356
1397
  }
1398
+ function hasContextFreeHunk(patch2) {
1399
+ const bodies = patch2.split(/^@@.*$/m).slice(1);
1400
+ return bodies.some((body) => !body.split("\n").some((line) => line.startsWith(" ") && line.trim().length > 0));
1401
+ }
1357
1402
  function describePatchFailure(patch2, detail) {
1358
1403
  const hunks = patch2.split("\n").filter((line) => line.startsWith("@@"));
1359
- const bodies = patch2.split(/^@@.*$/m).slice(1);
1360
- const contextless = bodies.some((body) => !body.split("\n").some((line) => line.startsWith(" ") && line.trim().length > 0));
1361
- const hint = hunks.length > 0 && contextless ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
1404
+ const hint = hunks.length > 0 && hasContextFreeHunk(patch2) ? " A hunk has no context lines; include at least one unchanged line above or below each change." : "";
1362
1405
  return `patch did not apply: ${detail}${hint}`;
1363
1406
  }
1364
1407
  async function applyCodePatch(workspaceDir, rawPatch, paths2) {
1365
1408
  const patch2 = stripPatchEnvelope(rawPatch);
1366
- await gitApply(workspaceDir, patch2, true);
1367
- await gitApply(workspaceDir, patch2, false);
1409
+ const zero = hasContextFreeHunk(patch2);
1410
+ await gitApply(workspaceDir, patch2, true, zero);
1411
+ await gitApply(workspaceDir, patch2, false, zero);
1368
1412
  for (const path of paths2) {
1369
1413
  try {
1370
1414
  const info = await (0, import_promises6.lstat)(resolveCodePath(workspaceDir, path));
@@ -1376,9 +1420,16 @@ async function applyCodePatch(workspaceDir, rawPatch, paths2) {
1376
1420
  }
1377
1421
  }
1378
1422
  }
1379
- function gitApply(cwd, patch2, check) {
1423
+ function gitApply(cwd, patch2, check, unidiffZero = false) {
1380
1424
  return new Promise((accept, reject) => {
1381
- const args = ["apply", "--recount", "--whitespace=nowarn", ...check ? ["--check"] : [], "-"];
1425
+ const args = [
1426
+ "apply",
1427
+ "--recount",
1428
+ ...unidiffZero ? ["--unidiff-zero"] : [],
1429
+ "--whitespace=nowarn",
1430
+ ...check ? ["--check"] : [],
1431
+ "-"
1432
+ ];
1382
1433
  const child = (0, import_node_child_process4.spawn)("git", args, {
1383
1434
  cwd,
1384
1435
  shell: false,
@@ -1786,9 +1837,9 @@ async function prepareRuntimeCheckpoint(input) {
1786
1837
  if (evidence.receipt.outcome === "passed") {
1787
1838
  verification = evidence.receipt;
1788
1839
  review = await input.review(patch2, verification);
1789
- note = review.verdict === "approved" ? "Clean verification and independent review passed" : "Clean verification passed; independent review rejected the candidate";
1840
+ note = describeReview(review);
1790
1841
  } else {
1791
- note = `Clean verification failed: ${evidence.receipt.recipes.filter((recipe2) => recipe2.status !== "passed").map((recipe2) => `${recipe2.recipeId}=${recipe2.status}`).join(", ")}`;
1842
+ note = describeGateFailure(evidence);
1792
1843
  }
1793
1844
  } catch (cause) {
1794
1845
  note = `Candidate verification or review failed closed: ${message(cause)}`;
@@ -1813,6 +1864,23 @@ async function prepareRuntimeCheckpoint(input) {
1813
1864
  });
1814
1865
  return { checkpoint, verification, review, note };
1815
1866
  }
1867
+ function describeReview(review) {
1868
+ const findings = review.findings.map((finding) => ` - [${finding.severity}] ${finding.detail}`).join("\n");
1869
+ 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.`;
1870
+ return [head, review.summary, findings].filter(Boolean).join("\n").slice(0, 4e3);
1871
+ }
1872
+ function describeGateFailure(evidence) {
1873
+ const failed = evidence.receipt.recipes.filter((recipe2) => recipe2.status !== "passed");
1874
+ const detail = failed.map((recipe2) => {
1875
+ const log = evidence.logs.find((entry) => entry.recipeId === recipe2.recipeId);
1876
+ const output = `${log?.stdout ?? ""}
1877
+ ${log?.stderr ?? ""}`.trim();
1878
+ return `${recipe2.recipeId}=${recipe2.status}${output ? `
1879
+ ${output.slice(0, 1500)}` : ""}`;
1880
+ }).join("\n\n");
1881
+ return `Clean verification failed. Fix this and checkpoint again:
1882
+ ${detail}`.slice(0, 4e3);
1883
+ }
1816
1884
  var message = (value) => (value instanceof Error ? value.message : String(value)).slice(0, 500);
1817
1885
 
1818
1886
  // src/code-runtime-checkpoint-manager.ts
@@ -2457,6 +2525,166 @@ function createCodeRuntimeInference(options) {
2457
2525
  };
2458
2526
  }
2459
2527
 
2528
+ // src/code-tool-presentation.ts
2529
+ var text = (value, maximum) => {
2530
+ if (typeof value !== "string") return void 0;
2531
+ const bounded = value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
2532
+ return bounded ? bounded.slice(0, maximum) : void 0;
2533
+ };
2534
+ var integer2 = (value) => Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : void 0;
2535
+ var record4 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2536
+ var excerpt = (value, tail = false) => {
2537
+ if (typeof value !== "string") return void 0;
2538
+ const safe = value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
2539
+ const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
2540
+ if (!source) return void 0;
2541
+ const lines = source.split("\n").filter((line) => line.trim()).map((line) => line.slice(0, 240));
2542
+ const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
2543
+ return text(selected.join("\n"), 2400);
2544
+ };
2545
+ var paths = (value) => {
2546
+ if (!Array.isArray(value)) return void 0;
2547
+ const items = value.flatMap((item) => {
2548
+ const path = text(item, 1024);
2549
+ return path ? [path] : [];
2550
+ }).slice(0, 12);
2551
+ return items.length ? items : void 0;
2552
+ };
2553
+ function patchStats(value) {
2554
+ if (typeof value !== "string") return {};
2555
+ let additions = 0;
2556
+ let deletions = 0;
2557
+ for (const line of value.slice(0, 262144).split("\n")) {
2558
+ if (line.startsWith("+++") || line.startsWith("---")) continue;
2559
+ if (line.startsWith("+")) additions += 1;
2560
+ else if (line.startsWith("-")) deletions += 1;
2561
+ }
2562
+ return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
2563
+ }
2564
+ function searchResults(value) {
2565
+ if (typeof value !== "string") return void 0;
2566
+ const results = value.split("\n").flatMap((line) => {
2567
+ const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line);
2568
+ if (!match) return [];
2569
+ const lineNumber = Number(match[2]);
2570
+ const itemText = text(match[3], 240);
2571
+ if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
2572
+ return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
2573
+ }).slice(0, 5);
2574
+ return results.length ? results : void 0;
2575
+ }
2576
+ function codeToolRequestPresentation(request) {
2577
+ const input = request.input;
2578
+ if (request.tool === "sandbox.read") {
2579
+ const path = text(input.path, 1024);
2580
+ if (!path) return void 0;
2581
+ const startLine = integer2(input.startLine);
2582
+ const endLine = integer2(input.endLine);
2583
+ return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
2584
+ }
2585
+ if (request.tool === "sandbox.list") {
2586
+ const scope = text(input.prefix, 1024);
2587
+ return { kind: "list", ...scope ? { scope } : {} };
2588
+ }
2589
+ if (request.tool === "sandbox.search" || request.tool === "sandbox.overview" || request.tool === "sandbox.where_is" || request.tool === "sandbox.who_imports" || request.tool === "sandbox.who_touches") {
2590
+ const query = text(input.query, 512);
2591
+ const scope = request.tool === "sandbox.search" ? text(input.prefix, 1024) : void 0;
2592
+ if (request.tool === "sandbox.search" && !query) return void 0;
2593
+ return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
2594
+ }
2595
+ if (request.tool === "sandbox.apply_patch") {
2596
+ return { kind: "patch", ...patchStats(input.patch) };
2597
+ }
2598
+ const recipeId = text(input.recipeId, 120);
2599
+ return recipeId ? { kind: "recipe", recipeId } : void 0;
2600
+ }
2601
+ function codeToolResultPresentation(request, response2) {
2602
+ const started = codeToolRequestPresentation(request);
2603
+ if (!started || !response2.ok) return started;
2604
+ const details = record4(response2.details);
2605
+ if (started.kind === "read") {
2606
+ return {
2607
+ ...started,
2608
+ ...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
2609
+ ...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
2610
+ ...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
2611
+ };
2612
+ }
2613
+ if (started.kind === "list") {
2614
+ 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);
2615
+ return {
2616
+ ...started,
2617
+ ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
2618
+ ...listed.length ? { paths: listed } : {}
2619
+ };
2620
+ }
2621
+ if (started.kind === "query") {
2622
+ const results = request.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
2623
+ const resultExcerpt = request.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
2624
+ return {
2625
+ ...started,
2626
+ ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
2627
+ ...results ? { results } : {},
2628
+ ...resultExcerpt ? { excerpt: resultExcerpt } : {}
2629
+ };
2630
+ }
2631
+ if (started.kind === "patch") {
2632
+ return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
2633
+ }
2634
+ const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
2635
+ return {
2636
+ ...started,
2637
+ ...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
2638
+ ...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
2639
+ ...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
2640
+ ...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
2641
+ };
2642
+ }
2643
+
2644
+ // src/code-runtime-observer.ts
2645
+ var MAX_FAILURE_REASON = 240;
2646
+ function toolFailureReason(response2) {
2647
+ if (response2.ok) return void 0;
2648
+ const supplied = response2.details?.failureReason;
2649
+ const reason = typeof supplied === "string" && supplied || DEFAULT_FAILURE_REASON[response2.content] || response2.content || "tool request failed; inspect the tool input and workspace state";
2650
+ return reason.slice(0, MAX_FAILURE_REASON);
2651
+ }
2652
+ var DEFAULT_FAILURE_REASON = {
2653
+ "tool denied by CaMeL policy": "tool denied by CaMeL policy",
2654
+ "review sessions are read-only": "review session is read-only; workspace changes are not permitted"
2655
+ };
2656
+ function observedBroker(input) {
2657
+ const now = input.now ?? Date.now;
2658
+ return {
2659
+ execute: async (context, request) => {
2660
+ const startedAt = now();
2661
+ const operationId = input.operationIdFor(request.requestId);
2662
+ const startedPresentation = codeToolRequestPresentation(request);
2663
+ await input.emit({
2664
+ type: "tool",
2665
+ phase: "started",
2666
+ tool: request.tool,
2667
+ operationId,
2668
+ ...startedPresentation ? { presentation: startedPresentation } : {}
2669
+ });
2670
+ const response2 = await input.broker.execute(context, request);
2671
+ const completedPresentation = codeToolResultPresentation(request, response2);
2672
+ const failureReason = toolFailureReason(response2);
2673
+ await input.emit({
2674
+ type: "tool",
2675
+ phase: "completed",
2676
+ tool: request.tool,
2677
+ ok: response2.ok,
2678
+ durationMs: now() - startedAt,
2679
+ operationId,
2680
+ ...failureReason ? { failureReason } : {},
2681
+ ...completedPresentation ? { presentation: completedPresentation } : {}
2682
+ });
2683
+ return response2;
2684
+ }
2685
+ };
2686
+ }
2687
+
2460
2688
  // src/code-tool-policy.ts
2461
2689
  var import_camel = require("@odla-ai/camel");
2462
2690
  var import_policy = require("@odla-ai/camel/policy");
@@ -2695,8 +2923,14 @@ function optionalInteger(value) {
2695
2923
  if (!Number.isSafeInteger(value) || value < 1) throw new TypeError("line bounds must be positive integers");
2696
2924
  return value;
2697
2925
  }
2926
+ var DEFAULT_FAILURE_REASON2 = {
2927
+ "tool denied by CaMeL policy": "tool denied by CaMeL policy",
2928
+ "review sessions are read-only": "review session is read-only; workspace changes are not permitted"
2929
+ };
2698
2930
  function response(request, ok, content, details) {
2699
- return { requestId: request.requestId, ok, content, ...details ? { details } : {} };
2931
+ if (ok) return { requestId: request.requestId, ok, content, ...details ? { details } : {} };
2932
+ const failureReason = typeof details?.failureReason === "string" && details.failureReason || DEFAULT_FAILURE_REASON2[content] || content || "tool request failed; inspect the tool input and workspace state";
2933
+ return { requestId: request.requestId, ok, content, details: { ...details, failureReason } };
2700
2934
  }
2701
2935
 
2702
2936
  // src/code-tool-reads.ts
@@ -3497,122 +3731,6 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
3497
3731
  var digestRuntimeValue = (value) => `sha256:${(0, import_node_crypto4.createHash)("sha256").update(value).digest("hex")}`;
3498
3732
  var runtimeErrorMessage = (value) => value instanceof Error ? value.message : String(value);
3499
3733
 
3500
- // src/code-tool-presentation.ts
3501
- var text = (value, maximum) => {
3502
- if (typeof value !== "string") return void 0;
3503
- const bounded = value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ").trim();
3504
- return bounded ? bounded.slice(0, maximum) : void 0;
3505
- };
3506
- var integer2 = (value) => Number.isSafeInteger(value) && Number(value) >= 0 ? Number(value) : void 0;
3507
- var record4 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3508
- var excerpt = (value, tail = false) => {
3509
- if (typeof value !== "string") return void 0;
3510
- const safe = value.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, " ");
3511
- const source = (tail ? safe.slice(-1e4) : safe.slice(0, 1e4)).trim();
3512
- if (!source) return void 0;
3513
- const lines = source.split("\n").filter((line) => line.trim()).map((line) => line.slice(0, 240));
3514
- const selected = tail ? lines.slice(-10) : lines.slice(0, 10);
3515
- return text(selected.join("\n"), 2400);
3516
- };
3517
- var paths = (value) => {
3518
- if (!Array.isArray(value)) return void 0;
3519
- const items = value.flatMap((item) => {
3520
- const path = text(item, 1024);
3521
- return path ? [path] : [];
3522
- }).slice(0, 12);
3523
- return items.length ? items : void 0;
3524
- };
3525
- function patchStats(value) {
3526
- if (typeof value !== "string") return {};
3527
- let additions = 0;
3528
- let deletions = 0;
3529
- for (const line of value.slice(0, 262144).split("\n")) {
3530
- if (line.startsWith("+++") || line.startsWith("---")) continue;
3531
- if (line.startsWith("+")) additions += 1;
3532
- else if (line.startsWith("-")) deletions += 1;
3533
- }
3534
- return { ...additions ? { additions } : {}, ...deletions ? { deletions } : {} };
3535
- }
3536
- function searchResults(value) {
3537
- if (typeof value !== "string") return void 0;
3538
- const results = value.split("\n").flatMap((line) => {
3539
- const match = /^([^:\n]{1,1024}):(\d+):\s?(.*)$/.exec(line);
3540
- if (!match) return [];
3541
- const lineNumber = Number(match[2]);
3542
- const itemText = text(match[3], 240);
3543
- if (!Number.isSafeInteger(lineNumber) || lineNumber < 1) return [];
3544
- return [{ path: match[1], line: lineNumber, ...itemText ? { text: itemText } : {} }];
3545
- }).slice(0, 5);
3546
- return results.length ? results : void 0;
3547
- }
3548
- function codeToolRequestPresentation(request) {
3549
- const input = request.input;
3550
- if (request.tool === "sandbox.read") {
3551
- const path = text(input.path, 1024);
3552
- if (!path) return void 0;
3553
- const startLine = integer2(input.startLine);
3554
- const endLine = integer2(input.endLine);
3555
- return { kind: "read", path, ...startLine ? { startLine } : {}, ...endLine ? { endLine } : {} };
3556
- }
3557
- if (request.tool === "sandbox.list") {
3558
- const scope = text(input.prefix, 1024);
3559
- return { kind: "list", ...scope ? { scope } : {} };
3560
- }
3561
- if (request.tool === "sandbox.search" || request.tool === "sandbox.overview" || request.tool === "sandbox.where_is" || request.tool === "sandbox.who_imports" || request.tool === "sandbox.who_touches") {
3562
- const query = text(input.query, 512);
3563
- const scope = request.tool === "sandbox.search" ? text(input.prefix, 1024) : void 0;
3564
- if (request.tool === "sandbox.search" && !query) return void 0;
3565
- return { kind: "query", ...query ? { query } : {}, ...scope ? { scope } : {} };
3566
- }
3567
- if (request.tool === "sandbox.apply_patch") {
3568
- return { kind: "patch", ...patchStats(input.patch) };
3569
- }
3570
- const recipeId = text(input.recipeId, 120);
3571
- return recipeId ? { kind: "recipe", recipeId } : void 0;
3572
- }
3573
- function codeToolResultPresentation(request, response2) {
3574
- const started = codeToolRequestPresentation(request);
3575
- if (!started || !response2.ok) return started;
3576
- const details = record4(response2.details);
3577
- if (started.kind === "read") {
3578
- return {
3579
- ...started,
3580
- ...integer2(details?.startLine) ? { startLine: integer2(details?.startLine) } : {},
3581
- ...integer2(details?.endLine) ? { endLine: integer2(details?.endLine) } : {},
3582
- ...excerpt(response2.content) ? { excerpt: excerpt(response2.content) } : {}
3583
- };
3584
- }
3585
- if (started.kind === "list") {
3586
- 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);
3587
- return {
3588
- ...started,
3589
- ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
3590
- ...listed.length ? { paths: listed } : {}
3591
- };
3592
- }
3593
- if (started.kind === "query") {
3594
- const results = request.tool === "sandbox.search" ? searchResults(response2.content) : void 0;
3595
- const resultExcerpt = request.tool === "sandbox.search" ? void 0 : excerpt(response2.content);
3596
- return {
3597
- ...started,
3598
- ...integer2(details?.count) !== void 0 ? { count: integer2(details?.count) } : {},
3599
- ...results ? { results } : {},
3600
- ...resultExcerpt ? { excerpt: resultExcerpt } : {}
3601
- };
3602
- }
3603
- if (started.kind === "patch") {
3604
- return { ...started, ...paths(details?.paths) ? { paths: paths(details?.paths) } : {} };
3605
- }
3606
- const output = response2.content.replace(/^Recipe [^\n]*\.?\s*/u, "");
3607
- return {
3608
- ...started,
3609
- ...integer2(details?.exitCode) !== void 0 ? { exitCode: integer2(details?.exitCode) } : {},
3610
- ...typeof details?.timedOut === "boolean" ? { timedOut: details.timedOut } : {},
3611
- ...typeof details?.outputLimitExceeded === "boolean" ? { outputLimitExceeded: details.outputLimitExceeded } : {},
3612
- ...excerpt(output, true) ? { excerpt: excerpt(output, true) } : {}
3613
- };
3614
- }
3615
-
3616
3734
  // src/code-runtime-acknowledgement-gate.ts
3617
3735
  function codeRuntimeAcknowledgementGate(signal) {
3618
3736
  let settle;
@@ -3632,6 +3750,57 @@ function codeRuntimeAcknowledgementGate(signal) {
3632
3750
  return { ready, release };
3633
3751
  }
3634
3752
 
3753
+ // src/code-runtime-session-activity.ts
3754
+ function observeCodeRuntimeSessionSkills(command, skills, emit) {
3755
+ return skills.map((skill) => ({
3756
+ ...skill,
3757
+ tools: skill.tools.map((tool) => {
3758
+ if (!tool.handler) return tool;
3759
+ const handler = tool.handler;
3760
+ return {
3761
+ ...tool,
3762
+ handler: async (input, context) => {
3763
+ const startedAt = Date.now();
3764
+ const operationId = digestRuntimeValue(
3765
+ `${command.commandId}:${skill.name}:${tool.name}:${context.toolCallId ?? "missing"}`
3766
+ );
3767
+ await emit({
3768
+ type: "collaboration",
3769
+ phase: "started",
3770
+ skill: skill.name,
3771
+ tool: tool.name,
3772
+ operationId
3773
+ }).catch(() => void 0);
3774
+ try {
3775
+ const output = await handler(input, context);
3776
+ await emit({
3777
+ type: "collaboration",
3778
+ phase: "completed",
3779
+ skill: skill.name,
3780
+ tool: tool.name,
3781
+ operationId,
3782
+ ok: output.isError !== true,
3783
+ durationMs: Date.now() - startedAt
3784
+ }).catch(() => void 0);
3785
+ return output;
3786
+ } catch (cause) {
3787
+ await emit({
3788
+ type: "collaboration",
3789
+ phase: "completed",
3790
+ skill: skill.name,
3791
+ tool: tool.name,
3792
+ operationId,
3793
+ ok: false,
3794
+ durationMs: Date.now() - startedAt
3795
+ }).catch(() => void 0);
3796
+ throw cause;
3797
+ }
3798
+ }
3799
+ };
3800
+ })
3801
+ }));
3802
+ }
3803
+
3635
3804
  // src/code-runtime-engine.ts
3636
3805
  var TheseusRuntimeEngine = class {
3637
3806
  constructor(options) {
@@ -3829,7 +3998,7 @@ var TheseusRuntimeEngine = class {
3829
3998
  event: (event) => this.#event(command, event, active.conversationRefs)
3830
3999
  });
3831
4000
  await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
3832
- const extraSkills = await sessionSkillsFor(this.options, command);
4001
+ const extraSkills = observeCodeRuntimeSessionSkills(command, await sessionSkillsFor(this.options, command), (event) => this.#event(command, event, active.conversationRefs));
3833
4002
  const result = await this.#attempt({
3834
4003
  inference,
3835
4004
  broker,
@@ -3868,36 +4037,11 @@ var TheseusRuntimeEngine = class {
3868
4037
  }
3869
4038
  /** Report every brokered effect as it starts and finishes. */
3870
4039
  #observed(command, active, broker) {
3871
- return {
3872
- execute: async (context, request) => {
3873
- const startedAt = Date.now();
3874
- const operationId = digestRuntimeValue(`${command.commandId}:${request.requestId}`);
3875
- const startedPresentation = codeToolRequestPresentation(request);
3876
- await this.#event(
3877
- command,
3878
- {
3879
- type: "tool",
3880
- phase: "started",
3881
- tool: request.tool,
3882
- operationId,
3883
- ...startedPresentation ? { presentation: startedPresentation } : {}
3884
- },
3885
- active.conversationRefs
3886
- ).catch(() => void 0);
3887
- const response2 = await broker.execute(context, request);
3888
- const completedPresentation = codeToolResultPresentation(request, response2);
3889
- await this.#event(command, {
3890
- type: "tool",
3891
- phase: "completed",
3892
- tool: request.tool,
3893
- ok: response2.ok,
3894
- durationMs: Date.now() - startedAt,
3895
- operationId,
3896
- ...completedPresentation ? { presentation: completedPresentation } : {}
3897
- }, active.conversationRefs).catch(() => void 0);
3898
- return response2;
3899
- }
3900
- };
4040
+ return observedBroker({
4041
+ broker,
4042
+ operationIdFor: (requestId) => digestRuntimeValue(`${command.commandId}:${requestId}`),
4043
+ emit: (event) => this.#event(command, event, active.conversationRefs).catch(() => void 0)
4044
+ });
3901
4045
  }
3902
4046
  async #checkpoint(command) {
3903
4047
  const active = this.#active.get(command.sessionId);
@@ -4241,6 +4385,7 @@ async function installedDependencies(repoRoot) {
4241
4385
  V2_SYSTEM_PROMPT,
4242
4386
  V3_SYSTEM_PROMPT,
4243
4387
  applyCodePatch,
4388
+ applyPatchDialectToDiff,
4244
4389
  assertCodeBuildRecipe,
4245
4390
  assertDisjointPlan,
4246
4391
  assertPinnedImage,
@@ -4258,6 +4403,7 @@ async function installedDependencies(repoRoot) {
4258
4403
  describePatchFailure,
4259
4404
  digestStagedWorkspace,
4260
4405
  feedbackIsActionable,
4406
+ hasContextFreeHunk,
4261
4407
  hazardFromAttempt,
4262
4408
  installedDependencies,
4263
4409
  integrateSubGoals,