@buildaharness/aielia 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +31 -8
  2. package/dist/agent-loop.d.ts +8 -8
  3. package/dist/ask-clarification-service.d.ts +1 -1
  4. package/dist/ask-mode-flag.d.ts +1 -1
  5. package/dist/assistant-session.d.ts +1 -1
  6. package/dist/assistant-types.d.ts +3 -3
  7. package/dist/assistant.d.ts +12 -12
  8. package/dist/batch-research-fixtures.d.ts +1 -1
  9. package/dist/benchmark-injected-failure.d.ts +1 -1
  10. package/dist/bin-Btzhiyzi.js +2108 -0
  11. package/dist/bin-Btzhiyzi.js.map +1 -0
  12. package/dist/bin-sea-bootstrap.d.ts +1 -0
  13. package/dist/bin.d.ts +1 -0
  14. package/dist/claude-cli-llm-client.d.ts +2 -2
  15. package/dist/cli-args.d.ts +20 -0
  16. package/dist/cli-icons.d.ts +28 -0
  17. package/dist/{cli-session-D0uLdT2A.js → cli-session-DnSc6Hhx.js} +607 -127
  18. package/dist/cli-session-DnSc6Hhx.js.map +1 -0
  19. package/dist/cli.d.ts +31 -1
  20. package/dist/cli.js +1 -1691
  21. package/dist/cli.js.map +1 -1
  22. package/dist/config.d.ts +14 -6
  23. package/dist/contradiction-checker.d.ts +1 -1
  24. package/dist/diff-format.d.ts +16 -0
  25. package/dist/execution-mode.d.ts +1 -1
  26. package/dist/fact-extraction.d.ts +4 -4
  27. package/dist/failure-mode-matcher.d.ts +1 -1
  28. package/dist/file-tools-mcp-server.mjs +2 -2
  29. package/dist/file-tools.d.ts +10 -2
  30. package/dist/harness-bridge.d.ts +21 -4
  31. package/dist/index.js +68 -68
  32. package/dist/index.js.map +1 -1
  33. package/dist/ink-select-prompt.d.ts +21 -0
  34. package/dist/markdown-line.d.ts +42 -0
  35. package/dist/mcp-server-asset.d.ts +24 -0
  36. package/dist/memory-service.d.ts +12 -2
  37. package/dist/network-containment.d.ts +1 -1
  38. package/dist/node-display-names.d.ts +1 -1
  39. package/dist/one-loop-flag.d.ts +1 -1
  40. package/dist/plan-drafting-service.d.ts +1 -1
  41. package/dist/plan-drafting.d.ts +4 -4
  42. package/dist/plan-mode-flag.d.ts +1 -1
  43. package/dist/plan-sketch-service.d.ts +1 -1
  44. package/dist/plan-sketch.d.ts +1 -1
  45. package/dist/plan-store.d.ts +2 -2
  46. package/dist/plan-templates/index.d.ts +1 -1
  47. package/dist/plan-verification.d.ts +1 -1
  48. package/dist/review-checker.d.ts +10 -0
  49. package/dist/scripted-llm-client.d.ts +1 -1
  50. package/dist/sea-cache.d.ts +9 -0
  51. package/dist/self-update.d.ts +101 -0
  52. package/dist/semantic-criterion-coverage.d.ts +10 -0
  53. package/dist/shell-tools.d.ts +1 -1
  54. package/dist/spike.js.map +1 -1
  55. package/dist/tool-control-plane.d.ts +1 -1
  56. package/dist/tool-policy.d.ts +1 -1
  57. package/dist/tool-step.d.ts +10 -0
  58. package/dist/trace-events.d.ts +5 -5
  59. package/dist/trust-tagging.d.ts +1 -1
  60. package/dist/{tui-app-DxLPSGh2.js → tui-app-CFfOP2DC.js} +176 -20
  61. package/dist/tui-app-CFfOP2DC.js.map +1 -0
  62. package/dist/tui-app.d.ts +34 -9
  63. package/dist/tui-mode-flag.d.ts +1 -1
  64. package/dist/turn-intent-classifier.d.ts +5 -5
  65. package/dist/turn-interpreter.d.ts +12 -0
  66. package/dist/turn-policy.d.ts +1 -1
  67. package/dist/update-check-flag.d.ts +11 -0
  68. package/dist/version.d.ts +6 -0
  69. package/package.json +7 -3
  70. package/dist/cli-session-D0uLdT2A.js.map +0 -1
  71. package/dist/tui-app-DxLPSGh2.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { loadHarnessCheckpoint, deleteHarnessCheckpoint, ControlState, FailureDiagnostics, Diagnostics, WorldModel, EvidenceStore, gatherEvidence, applyToolReliability, updateWorldModel, normalise, DimensionType, resolveControlState, containsCJK, Budget, validateInvestigationTools, tokenize, validateAskQuestion, validateAskResponse, makeQuestionsBatch, HarnessRuntime, saveHarnessCheckpoint, supervisorEnabled, EscalationHalt, riskSummary, InMemoryExperienceStore, resolveAskMode as resolveAskMode$1 } from "@buildaharness/harness";
4
+ import { loadHarnessCheckpoint, deleteHarnessCheckpoint, ControlState, FailureDiagnostics, Diagnostics, WorldModel, EvidenceStore, gatherEvidence, applyToolReliability, updateWorldModel, normalise, DimensionType, resolveControlState, containsCJK, Budget, validateInvestigationTools, tokenize as tokenize$1, validateAskQuestion, validateAskResponse, makeQuestionsBatch, HarnessRuntime, saveHarnessCheckpoint, supervisorEnabled, EscalationHalt, riskSummary, InMemoryExperienceStore, resolveAskMode as resolveAskMode$1 } from "@buildaharness/harness";
5
5
  import { ANTHROPIC_DEFAULT_MODEL, InMemoryAdapter, InMemoryReminderStore, IndexedDBAdapter, DexieExperienceStore } from "@buildaharness/runtime";
6
6
  const en$9 = {
7
7
  factMarkers: "\\b(my(?:\\s+\\w+(?:'s)?){0,3}\\s+name is|i(?:\\s+\\w+){0,4}\\s+live(?:\\s+\\w+){0,2}\\s+in|i(?:\\s+\\w+){0,4}\\s+work(?:\\s+\\w+){0,4}\\s+(at|as|for)|i am(?:\\s+(?!\\w*ing\\b)\\w+){0,4}\\s+an?\\b|i'm(?:\\s+(?!\\w*ing\\b)\\w+){0,4}\\s+an?\\b|i prefer|remember that|note that|for future reference|call me|i go by|i have (?:a|an|\\d+)(?:\\s+\\w+){0,4}\\s+named)\\b",
@@ -625,7 +625,7 @@ function compileRiskPatternsAcrossLanguages(data) {
625
625
  mediumRiskPatterns: languages.flatMap((lang) => lang.mediumRiskPatterns.map(compileRiskPattern)),
626
626
  // Reason text stays whichever language declared it first (today: "en") — the assistant's own
627
627
  // output isn't translated by this change, only its ability to understand non-English input;
628
- // see plans/personal_assistant_chinese_lexical_checks_plan.html's Phase 4 for that separate,
628
+ // see the internal plan's Phase 4 for that separate,
629
629
  // later concern.
630
630
  reminderPattern: { pattern: new RegExp(languages.map((lang) => lang.reminderPattern.source).join("|"), "i"), reason: first.reminderPattern.reason },
631
631
  reminderRecallQuestion: languages.map((lang) => new RegExp(lang.reminderRecallQuestion, "i")),
@@ -877,7 +877,7 @@ function migrateFact(fact) {
877
877
  const TIER_RULES = {
878
878
  episodic: { allowedSources: ["user_asserted", "model_inferred", "observed", "externally_verified"], retention: "session", contradictionChecked: false },
879
879
  // model_inferred added to semantic/identity/preference in Phase 4 of
880
- // plans/personal_assistant_fact_extraction_llm_confidence_plan.html: tierForFact() now routes a
880
+ // the internal plan: tierForFact() now routes a
881
881
  // model_inferred fact here too, but only once it's durable AND high-confidence — see that
882
882
  // function's doc comment.
883
883
  semantic: { allowedSources: ["user_asserted", "model_inferred", "externally_verified"], retention: "durable", contradictionChecked: true },
@@ -934,13 +934,19 @@ function isNearDuplicateText(a, b) {
934
934
  const lb = b.toLowerCase();
935
935
  return la.includes(lb) || lb.includes(la);
936
936
  }
937
+ function modelInferredFactsEnabled(env) {
938
+ const source = typeof process !== "undefined" ? process.env : {};
939
+ const raw = String(source.AUDIT_MODEL_INFERRED_FACTS ?? "").trim().toLowerCase();
940
+ if (raw === "") return true;
941
+ return !["0", "false", "off", "no", "disabled"].includes(raw);
942
+ }
937
943
  function mergeTurnFacts(lexicalFacts, llmFacts) {
938
944
  const novelLlmFacts = llmFacts.filter((llmFact) => !lexicalFacts.some((lexFact) => isNearDuplicateText(lexFact.text, llmFact.text)));
939
945
  return [...lexicalFacts, ...novelLlmFacts];
940
946
  }
941
947
  function buildTurnFacts(sessionId, userMessage, statedFacts) {
942
948
  const lexicalFacts = extractFactsFromTurn(userMessage, `turn:${sessionId}`);
943
- const llmFacts = statedFacts.map((fact) => ({
949
+ const llmFacts = modelInferredFactsEnabled() ? statedFacts.map((fact) => ({
944
950
  text: fact.text,
945
951
  extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
946
952
  sourceTurn: `turn:${sessionId}`,
@@ -948,7 +954,7 @@ function buildTurnFacts(sessionId, userMessage, statedFacts) {
948
954
  durable: fact.durable,
949
955
  confidence: fact.confidence,
950
956
  category: fact.category
951
- }));
957
+ })) : [];
952
958
  return mergeTurnFacts(lexicalFacts, llmFacts);
953
959
  }
954
960
  function shouldAutoPromote(fact) {
@@ -1570,6 +1576,11 @@ async function resolveAndVerify(ctx, requestedPath) {
1570
1576
  await assertRealPathInWorkspace(ctx.backend, ctx.workspaceRoot, resolved);
1571
1577
  return resolved;
1572
1578
  }
1579
+ async function readCurrentFileContent(backend, workspaceRoot, requestedPath) {
1580
+ const resolved = resolveInWorkspace(workspaceRoot, requestedPath);
1581
+ await assertRealPathInWorkspace(backend, workspaceRoot, resolved);
1582
+ return backend.readTextFile(resolved);
1583
+ }
1573
1584
  const READ_FILE_TOOL = {
1574
1585
  name: "read_file",
1575
1586
  description: "Read a text file inside the sandboxed workspace directory. `path` is relative to the workspace root (or an absolute path that is still inside it) — any path outside the workspace is rejected.",
@@ -1681,7 +1692,10 @@ async function applyPendingAction(backend, workspaceRoot, id, options = {}) {
1681
1692
  await backend.writeTextFile(resolved, record.content);
1682
1693
  await recordUndoLogEntry(backend, workspaceRoot, undoEntry2);
1683
1694
  await backend.removeFile(pendingActionPath(workspaceRoot, id));
1684
- return record;
1695
+ return {
1696
+ ...record,
1697
+ previousContent: snapshot.undoable ? snapshot.previousContent ?? void 0 : void 0
1698
+ };
1685
1699
  }
1686
1700
  if (record.kind === "email") {
1687
1701
  if (!options.sendEmail) {
@@ -2289,6 +2303,407 @@ function classifyToolYield(toolName, resultText) {
2289
2303
  if (testAny(DEAD_END_MARKERS, resultText)) return "dead_end";
2290
2304
  return "productive";
2291
2305
  }
2306
+ class Diff {
2307
+ diff(oldStr, newStr, options = {}) {
2308
+ let callback;
2309
+ if (typeof options === "function") {
2310
+ callback = options;
2311
+ options = {};
2312
+ } else if ("callback" in options) {
2313
+ callback = options.callback;
2314
+ }
2315
+ const oldString = this.castInput(oldStr, options);
2316
+ const newString = this.castInput(newStr, options);
2317
+ const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
2318
+ const newTokens = this.removeEmpty(this.tokenize(newString, options));
2319
+ return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
2320
+ }
2321
+ diffWithOptionsObj(oldTokens, newTokens, options, callback) {
2322
+ var _a;
2323
+ const done = (value) => {
2324
+ value = this.postProcess(value, options);
2325
+ if (callback) {
2326
+ setTimeout(function() {
2327
+ callback(value);
2328
+ }, 0);
2329
+ return void 0;
2330
+ } else {
2331
+ return value;
2332
+ }
2333
+ };
2334
+ const newLen = newTokens.length, oldLen = oldTokens.length;
2335
+ let editLength = 1;
2336
+ let maxEditLength = newLen + oldLen;
2337
+ if (options.maxEditLength != null) {
2338
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
2339
+ }
2340
+ const maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity;
2341
+ const abortAfterTimestamp = Date.now() + maxExecutionTime;
2342
+ const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
2343
+ let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
2344
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
2345
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
2346
+ }
2347
+ let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
2348
+ const execEditLength = () => {
2349
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
2350
+ let basePath;
2351
+ const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
2352
+ if (removePath) {
2353
+ bestPath[diagonalPath - 1] = void 0;
2354
+ }
2355
+ let canAdd = false;
2356
+ if (addPath) {
2357
+ const addPathNewPos = addPath.oldPos - diagonalPath;
2358
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
2359
+ }
2360
+ const canRemove = removePath && removePath.oldPos + 1 < oldLen;
2361
+ if (!canAdd && !canRemove) {
2362
+ bestPath[diagonalPath] = void 0;
2363
+ continue;
2364
+ }
2365
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
2366
+ basePath = this.addToPath(addPath, true, false, 0, options);
2367
+ } else {
2368
+ basePath = this.addToPath(removePath, false, true, 1, options);
2369
+ }
2370
+ newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
2371
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
2372
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
2373
+ } else {
2374
+ bestPath[diagonalPath] = basePath;
2375
+ if (basePath.oldPos + 1 >= oldLen) {
2376
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
2377
+ }
2378
+ if (newPos + 1 >= newLen) {
2379
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
2380
+ }
2381
+ }
2382
+ }
2383
+ editLength++;
2384
+ };
2385
+ if (callback) {
2386
+ (function exec() {
2387
+ setTimeout(function() {
2388
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
2389
+ return callback(void 0);
2390
+ }
2391
+ if (!execEditLength()) {
2392
+ exec();
2393
+ }
2394
+ }, 0);
2395
+ })();
2396
+ } else {
2397
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
2398
+ const ret = execEditLength();
2399
+ if (ret) {
2400
+ return ret;
2401
+ }
2402
+ }
2403
+ }
2404
+ }
2405
+ addToPath(path, added, removed, oldPosInc, options) {
2406
+ const last = path.lastComponent;
2407
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
2408
+ return {
2409
+ oldPos: path.oldPos + oldPosInc,
2410
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
2411
+ };
2412
+ } else {
2413
+ return {
2414
+ oldPos: path.oldPos + oldPosInc,
2415
+ lastComponent: { count: 1, added, removed, previousComponent: last }
2416
+ };
2417
+ }
2418
+ }
2419
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
2420
+ const newLen = newTokens.length, oldLen = oldTokens.length;
2421
+ let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
2422
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
2423
+ newPos++;
2424
+ oldPos++;
2425
+ commonCount++;
2426
+ if (options.oneChangePerToken) {
2427
+ basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
2428
+ }
2429
+ }
2430
+ if (commonCount && !options.oneChangePerToken) {
2431
+ basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
2432
+ }
2433
+ basePath.oldPos = oldPos;
2434
+ return newPos;
2435
+ }
2436
+ equals(left, right, options) {
2437
+ if (options.comparator) {
2438
+ return options.comparator(left, right);
2439
+ } else {
2440
+ return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
2441
+ }
2442
+ }
2443
+ removeEmpty(array) {
2444
+ const ret = [];
2445
+ for (let i = 0; i < array.length; i++) {
2446
+ if (array[i]) {
2447
+ ret.push(array[i]);
2448
+ }
2449
+ }
2450
+ return ret;
2451
+ }
2452
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2453
+ castInput(value, options) {
2454
+ return value;
2455
+ }
2456
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2457
+ tokenize(value, options) {
2458
+ return Array.from(value);
2459
+ }
2460
+ join(chars) {
2461
+ return chars.join("");
2462
+ }
2463
+ postProcess(changeObjects, options) {
2464
+ return changeObjects;
2465
+ }
2466
+ get useLongestToken() {
2467
+ return false;
2468
+ }
2469
+ buildValues(lastComponent, newTokens, oldTokens) {
2470
+ const components = [];
2471
+ let nextComponent;
2472
+ while (lastComponent) {
2473
+ components.push(lastComponent);
2474
+ nextComponent = lastComponent.previousComponent;
2475
+ delete lastComponent.previousComponent;
2476
+ lastComponent = nextComponent;
2477
+ }
2478
+ components.reverse();
2479
+ const componentLen = components.length;
2480
+ let componentPos = 0, newPos = 0, oldPos = 0;
2481
+ for (; componentPos < componentLen; componentPos++) {
2482
+ const component = components[componentPos];
2483
+ if (!component.removed) {
2484
+ if (!component.added && this.useLongestToken) {
2485
+ let value = newTokens.slice(newPos, newPos + component.count);
2486
+ value = value.map(function(value2, i) {
2487
+ const oldValue = oldTokens[oldPos + i];
2488
+ return oldValue.length > value2.length ? oldValue : value2;
2489
+ });
2490
+ component.value = this.join(value);
2491
+ } else {
2492
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
2493
+ }
2494
+ newPos += component.count;
2495
+ if (!component.added) {
2496
+ oldPos += component.count;
2497
+ }
2498
+ } else {
2499
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
2500
+ oldPos += component.count;
2501
+ }
2502
+ }
2503
+ return components;
2504
+ }
2505
+ }
2506
+ class LineDiff extends Diff {
2507
+ constructor() {
2508
+ super(...arguments);
2509
+ this.tokenize = tokenize;
2510
+ }
2511
+ equals(left, right, options) {
2512
+ if (options.ignoreWhitespace) {
2513
+ if (!options.newlineIsToken || !left.includes("\n")) {
2514
+ left = left.trim();
2515
+ }
2516
+ if (!options.newlineIsToken || !right.includes("\n")) {
2517
+ right = right.trim();
2518
+ }
2519
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
2520
+ if (left.endsWith("\n")) {
2521
+ left = left.slice(0, -1);
2522
+ }
2523
+ if (right.endsWith("\n")) {
2524
+ right = right.slice(0, -1);
2525
+ }
2526
+ }
2527
+ return super.equals(left, right, options);
2528
+ }
2529
+ }
2530
+ const lineDiff = new LineDiff();
2531
+ function diffLines(oldStr, newStr, options) {
2532
+ return lineDiff.diff(oldStr, newStr, options);
2533
+ }
2534
+ function tokenize(value, options) {
2535
+ if (options.stripTrailingCr) {
2536
+ value = value.replace(/\r\n/g, "\n");
2537
+ }
2538
+ const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
2539
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
2540
+ linesAndNewlines.pop();
2541
+ }
2542
+ for (let i = 0; i < linesAndNewlines.length; i++) {
2543
+ const line = linesAndNewlines[i];
2544
+ if (i % 2 && !options.newlineIsToken) {
2545
+ retLines[retLines.length - 1] += line;
2546
+ } else {
2547
+ retLines.push(line);
2548
+ }
2549
+ }
2550
+ return retLines;
2551
+ }
2552
+ function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
2553
+ let optionsObj;
2554
+ if (!options) {
2555
+ optionsObj = {};
2556
+ } else if (typeof options === "function") {
2557
+ optionsObj = { callback: options };
2558
+ } else {
2559
+ optionsObj = options;
2560
+ }
2561
+ if (typeof optionsObj.context === "undefined") {
2562
+ optionsObj.context = 4;
2563
+ }
2564
+ const context = optionsObj.context;
2565
+ if (optionsObj.newlineIsToken) {
2566
+ throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
2567
+ }
2568
+ if (!optionsObj.callback) {
2569
+ return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
2570
+ } else {
2571
+ const { callback } = optionsObj;
2572
+ diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
2573
+ const patch = diffLinesResultToPatch(diff);
2574
+ callback(patch);
2575
+ } }));
2576
+ }
2577
+ function diffLinesResultToPatch(diff) {
2578
+ if (!diff) {
2579
+ return;
2580
+ }
2581
+ diff.push({ value: "", lines: [] });
2582
+ function contextLines(lines) {
2583
+ return lines.map(function(entry) {
2584
+ return " " + entry;
2585
+ });
2586
+ }
2587
+ const hunks = [];
2588
+ let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
2589
+ for (let i = 0; i < diff.length; i++) {
2590
+ const current = diff[i], lines = current.lines || splitLines(current.value);
2591
+ current.lines = lines;
2592
+ if (current.added || current.removed) {
2593
+ if (!oldRangeStart) {
2594
+ const prev = diff[i - 1];
2595
+ oldRangeStart = oldLine;
2596
+ newRangeStart = newLine;
2597
+ if (prev) {
2598
+ curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
2599
+ oldRangeStart -= curRange.length;
2600
+ newRangeStart -= curRange.length;
2601
+ }
2602
+ }
2603
+ for (const line of lines) {
2604
+ curRange.push((current.added ? "+" : "-") + line);
2605
+ }
2606
+ if (current.added) {
2607
+ newLine += lines.length;
2608
+ } else {
2609
+ oldLine += lines.length;
2610
+ }
2611
+ } else {
2612
+ if (oldRangeStart) {
2613
+ if (lines.length <= context * 2 && i < diff.length - 2) {
2614
+ for (const line of contextLines(lines)) {
2615
+ curRange.push(line);
2616
+ }
2617
+ } else {
2618
+ const contextSize = Math.min(lines.length, context);
2619
+ for (const line of contextLines(lines.slice(0, contextSize))) {
2620
+ curRange.push(line);
2621
+ }
2622
+ const hunk = {
2623
+ oldStart: oldRangeStart,
2624
+ oldLines: oldLine - oldRangeStart + contextSize,
2625
+ newStart: newRangeStart,
2626
+ newLines: newLine - newRangeStart + contextSize,
2627
+ lines: curRange
2628
+ };
2629
+ hunks.push(hunk);
2630
+ oldRangeStart = 0;
2631
+ newRangeStart = 0;
2632
+ curRange = [];
2633
+ }
2634
+ }
2635
+ oldLine += lines.length;
2636
+ newLine += lines.length;
2637
+ }
2638
+ }
2639
+ for (const hunk of hunks) {
2640
+ for (let i = 0; i < hunk.lines.length; i++) {
2641
+ if (hunk.lines[i].endsWith("\n")) {
2642
+ hunk.lines[i] = hunk.lines[i].slice(0, -1);
2643
+ } else {
2644
+ hunk.lines.splice(i + 1, 0, "\");
2645
+ i++;
2646
+ }
2647
+ }
2648
+ }
2649
+ return {
2650
+ oldFileName,
2651
+ newFileName,
2652
+ oldHeader,
2653
+ newHeader,
2654
+ hunks
2655
+ };
2656
+ }
2657
+ }
2658
+ function splitLines(text) {
2659
+ const hasTrailingNl = text.endsWith("\n");
2660
+ const result = text.split("\n").map((line) => line + "\n");
2661
+ if (hasTrailingNl) {
2662
+ result.pop();
2663
+ } else {
2664
+ result.push(result.pop().slice(0, -1));
2665
+ }
2666
+ return result;
2667
+ }
2668
+ const DEFAULT_MAX_LINES = 20;
2669
+ const DIFF_INDENT = " ";
2670
+ function formatWriteDiff(oldContent, newContent, maxLines = DEFAULT_MAX_LINES) {
2671
+ if (oldContent === void 0) return previewContent(newContent, maxLines);
2672
+ const hunks = structuredPatch("before", "after", oldContent, newContent, "", "", { context: 3 }).hunks;
2673
+ const entries = [];
2674
+ for (const hunk of hunks) {
2675
+ let oldLine = hunk.oldStart;
2676
+ let newLine = hunk.newStart;
2677
+ for (const rawLine of hunk.lines) {
2678
+ if (rawLine.startsWith("\\")) continue;
2679
+ const sign = rawLine[0];
2680
+ const content = rawLine.slice(1);
2681
+ if (sign === "-") {
2682
+ entries.push({ lineNumber: oldLine, sign, content });
2683
+ oldLine++;
2684
+ } else if (sign === "+") {
2685
+ entries.push({ lineNumber: newLine, sign, content });
2686
+ newLine++;
2687
+ } else {
2688
+ entries.push({ lineNumber: newLine, sign, content });
2689
+ oldLine++;
2690
+ newLine++;
2691
+ }
2692
+ }
2693
+ }
2694
+ if (entries.length === 0) return "(no changes)";
2695
+ const gutterWidth = Math.max(...entries.map((e) => String(e.lineNumber).length));
2696
+ const diffLines2 = entries.map((e) => `${DIFF_INDENT}${String(e.lineNumber).padStart(gutterWidth, " ")} ${e.sign}${e.content}`);
2697
+ return previewLines(diffLines2, maxLines);
2698
+ }
2699
+ function previewContent(content, maxLines = DEFAULT_MAX_LINES) {
2700
+ return previewLines(content.split("\n"), maxLines);
2701
+ }
2702
+ function previewLines(lines, maxLines) {
2703
+ if (lines.length <= maxLines) return lines.join("\n");
2704
+ return `${lines.slice(0, maxLines).join("\n")}
2705
+ … (truncated)`;
2706
+ }
2292
2707
  class PrivateNetworkTargetError extends Error {
2293
2708
  constructor(requestedUrl, detail) {
2294
2709
  super(`Refusing to fetch "${requestedUrl}": ${detail}`);
@@ -2863,12 +3278,6 @@ const UNPARSED_TOOL_CALL_PATTERN = /<tool_call>|<\/?|[^|<>]{1,32}|(?:tool_
2863
3278
  function looksLikeUnparsedToolCall(content) {
2864
3279
  return UNPARSED_TOOL_CALL_PATTERN.test(content);
2865
3280
  }
2866
- function previewContent$1(content, maxLines = 20) {
2867
- const lines = content.split("\n");
2868
- if (lines.length <= maxLines) return content;
2869
- return `${lines.slice(0, maxLines).join("\n")}
2870
- … (truncated)`;
2871
- }
2872
3281
  function shellApprovalReason(command, cwd) {
2873
3282
  const base = `Proposes running: ${command}
2874
3283
  (cwd: ${cwd})`;
@@ -2910,7 +3319,7 @@ class AgentLoop {
2910
3319
  return createTurnControlPlaneState(toolNames);
2911
3320
  }
2912
3321
  /**
2913
- * R2 of plans/harness_d2_one_loop_rewire_plan.html: builds the real toolExecutors['default']
3322
+ * R2 of the internal plan: builds the real toolExecutors['default']
2914
3323
  * entry HarnessBridge.run() swaps in when the one-loop flag is enabled — a proposer that calls
2915
3324
  * runToolIterationStep once per driveMainLoop iteration and translates its discriminated result
2916
3325
  * into the primitives D0/D1 already built: a plain return (status 'continue', no output yet) for
@@ -2981,7 +3390,7 @@ ${freshFindings.map((o) => o.content).join("\n\n")}`
2981
3390
  };
2982
3391
  }
2983
3392
  /**
2984
- * R3 of plans/harness_d2_one_loop_rewire_plan.html: the wiring-level counterpart to
3393
+ * R3 of the internal plan: the wiring-level counterpart to
2985
3394
  * `createHarnessProposer` above — builds the same `messages`/`tools` shape `runToolLoop` builds
2986
3395
  * (system prompt + transcript + user message; whichever of FILE_TOOLS/WEB_TOOLS/SHELL_TOOLS/
2987
3396
  * ACTION_TOOLS/REMINDER_TOOLS are configured) so `assistant.ts`'s `runTurn` doesn't need to
@@ -3020,7 +3429,7 @@ ${freshFindings.map((o) => o.content).join("\n\n")}`
3020
3429
  return { proposer, sources };
3021
3430
  }
3022
3431
  /**
3023
- * R4 of plans/harness_d2_one_loop_rewire_plan.html: the batch-research counterpart to
3432
+ * R4 of the internal plan: the batch-research counterpart to
3024
3433
  * `createOneLoopProposer` above — routes `runBatchToolLoop`'s probe → calibrate → confirm-gate
3025
3434
  * → resolve-remaining → synthesize sequence through the same harness-driven proposer mechanism,
3026
3435
  * instead of batch research remaining a second code path that (per R3) never reached the
@@ -3199,7 +3608,7 @@ ${freshFindings.map((o) => o.content).join("\n\n")}`
3199
3608
  }
3200
3609
  /**
3201
3610
  * One iteration's worth of `runToolIterations`' ReAct loop, extracted (R1 of the D2
3202
- * one-loop-rewire follow-up plan, `plans/harness_d2_one_loop_rewire_plan.html`) so a
3611
+ * one-loop-rewire follow-up plan, the internal plan) so a
3203
3612
  * harness-driven proposer (R2) can call this directly, once per `driveMainLoop` iteration,
3204
3613
  * instead of only ever being driven by `runToolIterations`' own `for` loop. Preserves every
3205
3614
  * early-return branch of the original loop body exactly — the unparsed-tool-call retry,
@@ -3217,6 +3626,9 @@ ${freshFindings.map((o) => o.content).join("\n\n")}`
3217
3626
  const reportStep = (tool, input) => {
3218
3627
  onToolStep == null ? void 0 : onToolStep({ tool, input, summary: summarizeToolStep(tool, input) });
3219
3628
  };
3629
+ const reportDenied = (tool, input, reason) => {
3630
+ onToolStep == null ? void 0 : onToolStep({ tool, input, summary: summarizeToolStep(tool, input), deniedReason: reason });
3631
+ };
3220
3632
  {
3221
3633
  const response = await this.llmClient.callChatStructured(messages, tools, {
3222
3634
  model: this.model(),
@@ -3229,9 +3641,10 @@ ${freshFindings.map((o) => o.content).join("\n\n")}`
3229
3641
  // makes directly, now also covering the calls this backend used to resolve invisibly.
3230
3642
  // A backend without such an internal loop (the proxy client) never calls this — its
3231
3643
  // calls come back as response.toolCalls and are gated inline below instead.
3232
- onToolProposal: async (tool) => {
3644
+ onToolProposal: async (tool, input) => {
3233
3645
  const policy = this.checkToolPolicy(tool, riskHint, controlPlaneState == null ? void 0 : controlPlaneState.controlState);
3234
3646
  if (policy.decision === "ALLOW") return { decision: "allow" };
3647
+ reportDenied(tool, input, policy.reason);
3235
3648
  return { decision: "deny", reason: policy.reason };
3236
3649
  }
3237
3650
  });
@@ -3261,12 +3674,13 @@ ${freshFindings.map((o) => o.content).join("\n\n")}`
3261
3674
  const { id, kind, ...payload } = alreadyStagedCall.input;
3262
3675
  if (kind === "write") {
3263
3676
  const { path, content } = payload;
3677
+ const previousContent = this.fileTools ? await readCurrentFileContent(this.fileTools.backend, this.fileTools.workspaceRoot, path) : void 0;
3264
3678
  return {
3265
3679
  done: true,
3266
3680
  result: {
3267
3681
  kind: "needs_approval",
3268
3682
  reason: `Proposes writing to "${path}":
3269
- ${previewContent$1(content)}`,
3683
+ ${formatWriteDiff(previousContent, content)}`,
3270
3684
  pendingActionId: id,
3271
3685
  pendingActionKind: "write"
3272
3686
  }
@@ -3303,12 +3717,13 @@ ${previewContent$1(content)}`,
3303
3717
  if (result.kind !== "staged_write") {
3304
3718
  throw new Error("write_file executor returned an unexpected result kind");
3305
3719
  }
3720
+ const previousContent = await readCurrentFileContent(this.fileTools.backend, this.fileTools.workspaceRoot, result.path);
3306
3721
  return {
3307
3722
  done: true,
3308
3723
  result: {
3309
3724
  kind: "needs_approval",
3310
3725
  reason: `Proposes writing to "${result.path}":
3311
- ${previewContent$1(result.content)}`,
3726
+ ${formatWriteDiff(previousContent, result.content)}`,
3312
3727
  pendingActionId: result.id,
3313
3728
  pendingActionKind: "write"
3314
3729
  }
@@ -3350,6 +3765,7 @@ ${previewContent$1(result.content)}`,
3350
3765
  const policy = this.checkToolPolicy(call.name, riskHint, controlPlaneState == null ? void 0 : controlPlaneState.controlState);
3351
3766
  if (policy.decision === "DENY") {
3352
3767
  const resultText2 = `Denied by tool policy: ${policy.reason}`;
3768
+ reportDenied(call.name, call.input, policy.reason);
3353
3769
  messages.push({ role: "tool", content: resultText2, toolCallId: call.id });
3354
3770
  (_a = this.onTrace) == null ? void 0 : _a.call(this, { kind: "tool_call", tool: call.name, ok: false });
3355
3771
  continue;
@@ -3614,7 +4030,7 @@ ${text}` : text;
3614
4030
  }
3615
4031
  /**
3616
4032
  * Trajectory Supervisor GATHER_EVIDENCE host (S5 of
3617
- * plans/harness_trajectory_supervisor_plan.html). A bounded, strictly read-only tool
4033
+ * the internal plan). A bounded, strictly read-only tool
3618
4034
  * loop the harness calls (via HarnessRunOptions.runInvestigation) when the supervisor
3619
4035
  * decides the run is stuck for lack of a fact.
3620
4036
  *
@@ -3692,12 +4108,6 @@ ${content}`.slice(0, 800), tool: "read_file", reliability: "MEDIUM" });
3692
4108
  return findings;
3693
4109
  }
3694
4110
  }
3695
- function previewContent(content, maxLines = 20) {
3696
- const lines = content.split("\n");
3697
- if (lines.length <= maxLines) return content;
3698
- return `${lines.slice(0, maxLines).join("\n")}
3699
- … (truncated)`;
3700
- }
3701
4111
  class ActionApprovalService {
3702
4112
  constructor(memory, llmClient, model, fileTools, shellTools, actionTools, session, agentLoop, onTrace, onDebugLog) {
3703
4113
  this.memory = memory;
@@ -3829,19 +4239,27 @@ ${reply.slice(0, 4e3)}${reply.length > 4e3 ? `
3829
4239
  async loadChainedApproval(backend, workspaceRoot, nextPendingActionId, previousOutcome) {
3830
4240
  const next = await loadPendingAction(backend, workspaceRoot, nextPendingActionId);
3831
4241
  if (!next) return void 0;
3832
- const reason = next.kind === "write" ? `${previousOutcome}
4242
+ let reason;
4243
+ if (next.kind === "write") {
4244
+ const previousContent = await readCurrentFileContent(backend, workspaceRoot, next.path);
4245
+ reason = `${previousOutcome}
3833
4246
 
3834
4247
  Next, it also proposes writing to "${next.path}":
3835
- ${previewContent(next.content)}` : next.kind === "shell" ? `${previousOutcome}
4248
+ ${formatWriteDiff(previousContent, next.content)}`;
4249
+ } else if (next.kind === "shell") {
4250
+ reason = `${previousOutcome}
3836
4251
 
3837
4252
  Next, it also proposes running: ${next.command}
3838
- (cwd: ${next.cwd})` : next.kind === "email" ? `${previousOutcome}
4253
+ (cwd: ${next.cwd})`;
4254
+ } else if (next.kind === "email") {
4255
+ reason = `${previousOutcome}
3839
4256
 
3840
4257
  Next, it also proposes sending an email:
3841
4258
  To: ${next.to}
3842
4259
  Subject: ${next.subject}
3843
4260
 
3844
- ${previewContent(next.body)}` : void 0;
4261
+ ${previewContent(next.body)}`;
4262
+ }
3845
4263
  if (!reason) return void 0;
3846
4264
  return {
3847
4265
  status: "needs_approval",
@@ -4060,7 +4478,7 @@ function matchTaskCancelAttempt(message, plan) {
4060
4478
  const lower = message.toLowerCase();
4061
4479
  for (const task of plan.tasks) {
4062
4480
  if (task.status === "COMPLETE" || task.cancelled) continue;
4063
- const words = tokenize(`${task.id} ${task.description}`.toLowerCase()).filter(
4481
+ const words = tokenize$1(`${task.id} ${task.description}`.toLowerCase()).filter(
4064
4482
  (w) => !CANCEL_MATCH_STOPWORDS.has(w) && (containsCJK(w) || w.length >= 4)
4065
4483
  );
4066
4484
  if (words.some((w) => lower.includes(w))) {
@@ -5725,6 +6143,12 @@ function toTaskRiskLevel(riskLevel) {
5725
6143
  function planTaskRiskLevel(description) {
5726
6144
  return classifyRisk(description).riskLevel;
5727
6145
  }
6146
+ function decompositionEnabled(env) {
6147
+ const source = typeof process !== "undefined" ? process.env : {};
6148
+ const raw = String(source.AUDIT_DECOMPOSITION ?? "").trim().toLowerCase();
6149
+ if (raw === "") return true;
6150
+ return !["0", "false", "off", "no", "disabled"].includes(raw);
6151
+ }
5728
6152
  class TurnInterpreter {
5729
6153
  constructor(llmClient, model, planService, reminderStore) {
5730
6154
  this.llmClient = llmClient;
@@ -5786,8 +6210,9 @@ class TurnInterpreter {
5786
6210
  */
5787
6211
  async resolveTasks(params) {
5788
6212
  const { userMessage, sessionId, classification, planForCancelCheck, onUsage } = params;
6213
+ const decompose = decompositionEnabled();
5789
6214
  let initialTasks = toHarnessTasks([{ id: "respond", description: userMessage, depends_on: [] }], toTaskRiskLevel(classification.riskLevel));
5790
- const decomposed = classification.decomposedTasks;
6215
+ const decomposed = decompose ? classification.decomposedTasks : null;
5791
6216
  if (decomposed) {
5792
6217
  initialTasks = toHarnessTasks(decomposed, toTaskRiskLevel(classification.riskLevel));
5793
6218
  }
@@ -5802,7 +6227,7 @@ class TurnInterpreter {
5802
6227
  } else {
5803
6228
  planClassifiedTrace = { isCandidate: classification.matchedPlanTemplate !== null, matchedTemplate: classification.matchedPlanTemplate };
5804
6229
  }
5805
- if (initialTasks.length === 1 && initialTasks[0].id === "respond" && classification.riskLevel !== "LOW" && looksLikeCodingFact(userMessage)) {
6230
+ if (decompose && initialTasks.length === 1 && initialTasks[0].id === "respond" && classification.riskLevel !== "LOW" && looksLikeCodingFact(userMessage)) {
5806
6231
  const reframed = await reframeTaskDescriptionWithLLM(userMessage, this.llmClient, this.model(), onUsage);
5807
6232
  if (reframed) {
5808
6233
  initialTasks = toHarnessTasks([{ id: "respond", description: reframed, depends_on: [] }], toTaskRiskLevel(classification.riskLevel));
@@ -5873,6 +6298,12 @@ const REVIEW_SCHEMA = {
5873
6298
  },
5874
6299
  required: ["conflict"]
5875
6300
  };
6301
+ function semanticChangeReviewEnabled(env) {
6302
+ const source = typeof process !== "undefined" ? process.env : {};
6303
+ const raw = String(source.AUDIT_SEMANTIC_CHANGE_REVIEW ?? "").trim().toLowerCase();
6304
+ if (raw === "") return true;
6305
+ return !["0", "false", "off", "no", "disabled"].includes(raw);
6306
+ }
5876
6307
  const SYSTEM_PROMPT$2 = `You check whether a proposed action genuinely conflicts with something already known to be true (a high-confidence belief) or predicted (an active hypothesis's predicted observation) — a real logical conflict, not just a superficially related topic (e.g. proposing to remove something a belief says is required, or an action that presumes the opposite of what's predicted). You are given "changeDescription", "highConfidenceBeliefs", and "hypothesisPredictions" as JSON. Respond with JSON only: {"conflict": boolean, "reason": string}. reason only needs to be set when conflict is true.`;
5877
6308
  async function checkSemanticReviewConflict(changeDescription, highConfidenceBeliefs, hypothesisPredictions, llmClient, model, onUsage) {
5878
6309
  if (looksLikeCodingFact(changeDescription)) return { conflict: false };
@@ -5930,6 +6361,12 @@ async function checkSemanticFailureMatch(symptoms, libraryEntries, llmClient, mo
5930
6361
  }
5931
6362
  }
5932
6363
  const NON_CHECKABLE_DEFAULT_CRITERION = "Respond helpfully, accurately, and safely to the user request.";
6364
+ function semanticCriterionCoverageEnabled(env) {
6365
+ const source = typeof process !== "undefined" ? process.env : {};
6366
+ const raw = String(source.AUDIT_SEMANTIC_CRITERION_COVERAGE ?? "").trim().toLowerCase();
6367
+ if (raw === "") return true;
6368
+ return !["0", "false", "off", "no", "disabled"].includes(raw);
6369
+ }
5933
6370
  const COVERAGE_SCHEMA = {
5934
6371
  type: "object",
5935
6372
  properties: {
@@ -5955,6 +6392,18 @@ async function checkSemanticCriterionCoverage(criterion, beliefs, llmClient, mod
5955
6392
  return false;
5956
6393
  }
5957
6394
  }
6395
+ function verificationEnabled(env) {
6396
+ const source = typeof process !== "undefined" ? process.env : {};
6397
+ const raw = String(source.AUDIT_VERIFICATION ?? "").trim().toLowerCase();
6398
+ if (raw === "") return true;
6399
+ return !["0", "false", "off", "no", "disabled"].includes(raw);
6400
+ }
6401
+ function reviewerPassEnabled(env) {
6402
+ const source = typeof process !== "undefined" ? process.env : {};
6403
+ const raw = String(source.AUDIT_REVIEWER_PASS ?? "").trim().toLowerCase();
6404
+ if (raw === "") return true;
6405
+ return !["0", "false", "off", "no", "disabled"].includes(raw);
6406
+ }
5958
6407
  const PLAN_AUTO_ADVANCE_TASK_CEILING = 10;
5959
6408
  class HarnessBridge {
5960
6409
  constructor(memory, experienceStore, checkpointStore, llmClient, model, maxSteps, planService, assistantSession, onTrace, oneLoopMode = DEFAULT_ONE_LOOP_MODE) {
@@ -6006,7 +6455,7 @@ class HarnessBridge {
6006
6455
  // task-graph *shape* (visible in stepsUsed/nodeExecutionOrder), not the number of
6007
6456
  // distinct replies produced.
6008
6457
  //
6009
- // R2 of plans/harness_d2_one_loop_rewire_plan.html: flag-OFF (the default) and flag-ON
6458
+ // R2 of the internal plan: flag-OFF (the default) and flag-ON
6010
6459
  // with no caller-supplied proposer are byte-identical to the line above — `() =>
6011
6460
  // draftReply` — satisfying INV-19. Flag-ON with a real oneLoopProposer swaps it in as the
6012
6461
  // 'default' toolExecutor instead, read once per turn right here.
@@ -6036,6 +6485,13 @@ class HarnessBridge {
6036
6485
  onVerification: (result) => {
6037
6486
  lastVerification = result;
6038
6487
  },
6488
+ // AUDIT_VERIFICATION (feature-value audit, Phase C5, eval-only) → skip verify() entirely.
6489
+ // Default ON — unchanged shipped behaviour; skipVerification stays undefined.
6490
+ skipVerification: verificationEnabled() ? void 0 : true,
6491
+ // AUDIT_REVIEWER_PASS (feature-value audit, Phase C6, eval-only) → skip reviewerPass()
6492
+ // (and any reviewer_pass_2 re-run) entirely, including its C1/C2 sub-mechanisms. Default
6493
+ // ON — unchanged shipped behaviour; skipReviewerPass stays undefined.
6494
+ skipReviewerPass: reviewerPassEnabled() ? void 0 : true,
6039
6495
  // Trajectory Supervisor GATHER_EVIDENCE host (S5). Inert unless a supervisorDecider is
6040
6496
  // also wired and returns a GATHER_EVIDENCE directive at a stall edge; absent → the
6041
6497
  // harness degrades GATHER_EVIDENCE to CONTINUE.
@@ -6043,7 +6499,7 @@ class HarnessBridge {
6043
6499
  // Trajectory Supervisor decider (S5) — the single stall-edge LLM call. Flag-gated on
6044
6500
  // HARNESS_TRAJECTORY_SUPERVISOR (default OFF); when off, the harness never consults it
6045
6501
  // and the whole supervisor path stays inert (INV-22). The harness itself only calls this
6046
- // inside its own cannotMakeProgress() branch. Twin of planner_api.py's _run_planner gate.
6502
+ // inside its own cannotMakeProgress() branch. Twin of the planner driver's _run_planner gate.
6047
6503
  supervisorDecider: supervisorEnabled() ? (digest) => decideSupervisorDirective(digest, this.llmClient, this.model(), onUsage) : void 0,
6048
6504
  onSupervisorDirective: (directive) => {
6049
6505
  var _a2;
@@ -6082,7 +6538,11 @@ class HarnessBridge {
6082
6538
  // Layered on top of review-proposed-change.ts's lexical isNegation check — same "skip
6083
6539
  // when it reads like a coding fact" gate contradictionChecker uses, since that's the
6084
6540
  // domain the fixed-phrase check already covers reasonably well.
6085
- semanticChangeReviewer: (input) => checkSemanticReviewConflict(input.changeDescription, input.highConfidenceBeliefs, input.hypothesisPredictions, this.llmClient, this.model(), onUsage),
6541
+ // AUDIT_SEMANTIC_CHANGE_REVIEW (feature-value audit, Phase C2) gates the whole hook: OFF →
6542
+ // no host semanticChangeReviewer is wired at all, so the harness's mechanical
6543
+ // reviewProposedChange (lexical isNegation) is the only conflict check. Default ON —
6544
+ // unchanged shipped behaviour.
6545
+ semanticChangeReviewer: semanticChangeReviewEnabled() ? (input) => checkSemanticReviewConflict(input.changeDescription, input.highConfidenceBeliefs, input.hypothesisPredictions, this.llmClient, this.model(), onUsage) : void 0,
6086
6546
  // Layered on top of FailureModeLibrary's own exact-string-overlap match() — see
6087
6547
  // failure-mode-matcher.ts's doc comment for why exact equality against a curated symptom
6088
6548
  // list almost never happens for free-text observations in practice.
@@ -6093,7 +6553,10 @@ class HarnessBridge {
6093
6553
  // Layered on top of reviewerPass's implementerLens's own `.includes()` substring check —
6094
6554
  // called only for a success criterion that substring check found no coverage for. See
6095
6555
  // semantic-criterion-coverage.ts's doc comment.
6096
- semanticCriterionCoverage: (criterion, beliefs) => checkSemanticCriterionCoverage(criterion, beliefs, this.llmClient, this.model(), onUsage),
6556
+ // AUDIT_SEMANTIC_CRITERION_COVERAGE (feature-value audit, Phase C1) gates the whole hook:
6557
+ // OFF → no host semanticCriterionCoverage is wired at all, so the reviewer's implementer
6558
+ // lens runs its `.includes()` substring check alone. Default ON — unchanged shipped behaviour.
6559
+ semanticCriterionCoverage: semanticCriterionCoverageEnabled() ? (criterion, beliefs) => checkSemanticCriterionCoverage(criterion, beliefs, this.llmClient, this.model(), onUsage) : void 0,
6097
6560
  // Stop right after a MEDIUM/HIGH-risk plan step resolves (COMPLETE or FAILED), before
6098
6561
  // the loop would go pick the next one — undefined for a non-plan turn, so shouldPause is
6099
6562
  // simply never checked and behavior is unchanged.
@@ -6328,7 +6791,7 @@ class AskClarificationService {
6328
6791
  sessionId,
6329
6792
  userMessage: answerText,
6330
6793
  facts: staged.facts,
6331
- // Phase 4 of plans/personal_assistant_fact_extraction_llm_confidence_plan.html — same
6794
+ // Phase 4 of the internal plan — same
6332
6795
  // reasoning as assistant.ts's own call site: buildSuccessResult below runs recordFacts()
6333
6796
  // with this same (sessionId, answerText, staged.classification.statesDurableFacts) triple,
6334
6797
  // so this stays consistent with what actually gets written to the fact stores this turn.
@@ -6539,7 +7002,7 @@ class PersonalAssistant {
6539
7002
  __publicField(this, "dangerouslySkipPermissions");
6540
7003
  /** Whenever any of fileTools/webTools/shellTools is configured, `turn()` routes through AgentLoop instead of a single plain chat call — computed once here since it never changes for the lifetime of an instance. */
6541
7004
  __publicField(this, "toolLoopWillRun");
6542
- /** R3 of plans/harness_d2_one_loop_rewire_plan.html — mirrors the same flag HarnessBridge was given at construction, kept here too so runTurn can decide whether to defer the tool loop into a harness-driven proposer instead of precomputing draftReply. See PersonalAssistantOptions.oneLoopMode's doc comment. */
7005
+ /** R3 of the internal plan — mirrors the same flag HarnessBridge was given at construction, kept here too so runTurn can decide whether to defer the tool loop into a harness-driven proposer instead of precomputing draftReply. See PersonalAssistantOptions.oneLoopMode's doc comment. */
6543
7006
  __publicField(this, "oneLoopMode");
6544
7007
  /** Q2 — global-flag tier of the ask-question mechanism's three-tier INV-29 resolution. See PersonalAssistantOptions.askMode's doc comment. */
6545
7008
  __publicField(this, "askMode");
@@ -6550,7 +7013,7 @@ class PersonalAssistant {
6550
7013
  * AssistantTurnResult.proposerKind, and emitted as a 'proposer_selected' trace event from
6551
7014
  * runTurn itself. A single mutable field is safe because `turn()` is awaited end to end (turns
6552
7015
  * never overlap within one instance). See AssistantTurnResult.proposerKind and
6553
- * plans/chat_ui_browser_e2e_plan.html phase B1.
7016
+ * the internal plan phase B1.
6554
7017
  */
6555
7018
  __publicField(this, "lastProposerKind", "posthoc");
6556
7019
  __publicField(this, "memoryService");
@@ -6708,7 +7171,7 @@ class PersonalAssistant {
6708
7171
  return this.session.clearSession(sessionId);
6709
7172
  }
6710
7173
  /**
6711
- * P1 of plans/ask_question_and_plan_mode_plan.html — explicit entry point into plan mode's
7174
+ * P1 of the internal plan — explicit entry point into plan mode's
6712
7175
  * exclusive drafting state. No production caller yet: P3 will later set this automatically from
6713
7176
  * a judgment-based trigger ahead of TurnInterpreter's classification. Until then this is reached
6714
7177
  * only by a caller (a future `/plan` CLI command, or a test) that wants to exercise the drafting
@@ -6720,7 +7183,7 @@ class PersonalAssistant {
6720
7183
  return this.session.enterPlanMode(sessionId);
6721
7184
  }
6722
7185
  /**
6723
- * P7 of plans/ask_question_and_plan_mode_plan.html — the raw current `PlanRecord` for this
7186
+ * P7 of the internal plan — the raw current `PlanRecord` for this
6724
7187
  * session, regardless of `mode`, so a caller (chat-ui's persistent banner, the CLI's `/plan
6725
7188
  * show`) can display live drafting/awaiting-approval state independent of any single turn's
6726
7189
  * own result (a `needs_plan_approval` result only carries a snapshot at the moment it's
@@ -6731,7 +7194,7 @@ class PersonalAssistant {
6731
7194
  return this.planService.loadPlanRecord(sessionId);
6732
7195
  }
6733
7196
  /**
6734
- * P9 of plans/ask_question_and_plan_mode_plan.html — the lightweight plan-sketch delegate: a
7197
+ * P9 of the internal plan — the lightweight plan-sketch delegate: a
6735
7198
  * cheaper "just go research and draft an approach" path than plan mode's durable task-graph
6736
7199
  * machinery (P0-P8), explicitly invoked (a CLI `/plan sketch <request>` command, a chat-ui
6737
7200
  * "Sketch a plan" action) rather than auto-triggered. Returns advice in the reply text — it
@@ -6785,7 +7248,7 @@ class PersonalAssistant {
6785
7248
  /**
6786
7249
  * `/memory confirm <n|category>` — `selector` is either a 1-based index into `/memory`'s
6787
7250
  * flat, display-order "Pending confirmation" listing, or one of FactCategory's names for a
6788
- * bulk confirm. Phase 3 of plans/personal_assistant_fact_extraction_llm_confidence_plan.html.
7251
+ * bulk confirm. Phase 3 of the internal plan.
6789
7252
  * `conflictNotices` (if any) are advisory only — every confirmed fact is promoted regardless,
6790
7253
  * matching how every other contradiction check in this codebase never gates belief admission.
6791
7254
  */
@@ -7009,7 +7472,7 @@ class PersonalAssistant {
7009
7472
  sessionId,
7010
7473
  userMessage,
7011
7474
  facts,
7012
- // Phase 4 of plans/personal_assistant_fact_extraction_llm_confidence_plan.html: the same
7475
+ // Phase 4 of the internal plan: the same
7013
7476
  // merged lexical+LLM list recordFacts() (called later, in responseService's build*Result)
7014
7477
  // derives its writes from — computed independently here (both calls are pure given the
7015
7478
  // same sessionId/userMessage/statedFacts) so the harness's World Model sees a same-turn
@@ -7088,7 +7551,7 @@ class PersonalAssistant {
7088
7551
  /**
7089
7552
  * Shared by the flag-OFF flat/batch tool loop's own needs_approval/escalated ToolLoopResult and
7090
7553
  * the flag-ON harness-driven proposer's equivalent OneLoopPause (R3 of
7091
- * plans/harness_d2_one_loop_rewire_plan.html, see runTurn's two call sites) — "the model wants
7554
+ * the internal plan, see runTurn's two call sites) — "the model wants
7092
7555
  * to write/run/send something" or "the tool loop gave up" means the same thing to the caller
7093
7556
  * regardless of which loop discovered it.
7094
7557
  */
@@ -7363,6 +7826,7 @@ const CONFIG_KEYS = [
7363
7826
  "askMode",
7364
7827
  "planMode",
7365
7828
  "tuiMode",
7829
+ "updateCheck",
7366
7830
  "activeProject"
7367
7831
  ];
7368
7832
  const DEFAULT_CONFIG = {
@@ -7430,6 +7894,16 @@ function resolveTuiMode(env) {
7430
7894
  function shouldLaunchTuiApp(tuiMode, stdoutIsTty, stdinIsTty) {
7431
7895
  return tuiMode === "enabled" && stdoutIsTty && stdinIsTty;
7432
7896
  }
7897
+ const DEFAULT_UPDATE_CHECK_MODE = "enabled";
7898
+ function normalizeUpdateCheckMode(raw, varName = "ASSISTANT_UPDATE_CHECK") {
7899
+ if (raw === void 0 || raw === "") return DEFAULT_UPDATE_CHECK_MODE;
7900
+ if (raw === "enabled" || raw === "disabled") return raw;
7901
+ console.error(`[warning] ${varName}="${raw}" is not "enabled" or "disabled" — using the default (${DEFAULT_UPDATE_CHECK_MODE}).`);
7902
+ return DEFAULT_UPDATE_CHECK_MODE;
7903
+ }
7904
+ function resolveUpdateCheckMode(env) {
7905
+ return normalizeUpdateCheckMode(env.ASSISTANT_UPDATE_CHECK);
7906
+ }
7433
7907
  const SECRET_CONFIG_KEYS = /* @__PURE__ */ new Set(["authToken", "apiKey", "braveApiKey"]);
7434
7908
  const ENV_VAR_FOR_CONFIG_KEY = {
7435
7909
  llmBackend: "ASSISTANT_LLM_BACKEND",
@@ -7458,6 +7932,7 @@ const ENV_VAR_FOR_CONFIG_KEY = {
7458
7932
  askMode: "ASSISTANT_ASK_MODE",
7459
7933
  planMode: "ASSISTANT_PLAN_MODE",
7460
7934
  tuiMode: "ASSISTANT_TUI",
7935
+ updateCheck: "ASSISTANT_UPDATE_CHECK",
7461
7936
  activeProject: "ASSISTANT_ACTIVE_PROJECT"
7462
7937
  };
7463
7938
  function isConfigKey(key) {
@@ -7505,6 +7980,7 @@ function envOverridesFromProcessEnv(env) {
7505
7980
  if (env.ASSISTANT_ASK_MODE !== void 0) overrides.askMode = resolveAskMode(env);
7506
7981
  if (env.ASSISTANT_PLAN_MODE !== void 0) overrides.planMode = resolvePlanMode(env);
7507
7982
  if (env.ASSISTANT_TUI !== void 0) overrides.tuiMode = resolveTuiMode(env);
7983
+ if (env.ASSISTANT_UPDATE_CHECK !== void 0) overrides.updateCheck = resolveUpdateCheckMode(env);
7508
7984
  if (env.ASSISTANT_ACTIVE_PROJECT !== void 0) overrides.activeProject = env.ASSISTANT_ACTIVE_PROJECT;
7509
7985
  return overrides;
7510
7986
  }
@@ -7560,6 +8036,9 @@ function parseConfigValue(key, raw) {
7560
8036
  case "tuiMode":
7561
8037
  if (raw !== "enabled" && raw !== "disabled") throw new ConfigValueParseError('tuiMode must be "enabled" or "disabled"');
7562
8038
  return raw;
8039
+ case "updateCheck":
8040
+ if (raw !== "enabled" && raw !== "disabled") throw new ConfigValueParseError('updateCheck must be "enabled" or "disabled"');
8041
+ return raw;
7563
8042
  default:
7564
8043
  return raw;
7565
8044
  }
@@ -7761,103 +8240,104 @@ function formatDoctorReport(checks) {
7761
8240
  return checks.map((c) => ` ${c.ok ? "✓" : "✗"} ${c.label}${!c.ok && c.detail ? ` — ${c.detail}` : ""}`).join("\n");
7762
8241
  }
7763
8242
  export {
7764
- formatConfigListing as $,
8243
+ executeWebTool as $,
7765
8244
  ACTION_TOOLS as A,
7766
- classifyToolYield as B,
8245
+ classifyRisk as B,
7767
8246
  CONFIG_KEYS as C,
7768
8247
  DEFAULT_ASK_MODE as D,
7769
8248
  ENV_VAR_FOR_CONFIG_KEY as E,
7770
8249
  FETCH_URL_TOOL as F,
7771
- classifyTurnIntent as G,
7772
- computePlanPosition as H,
8250
+ classifyToolYield as G,
8251
+ classifyTurnIntent as H,
7773
8252
  InvalidEmailArgsError as I,
7774
- createPlanRecord as J,
7775
- createResendSender as K,
8253
+ computePlanPosition as J,
8254
+ createPlanRecord as K,
7776
8255
  LAYER_DISPLAY_NAME as L,
7777
- createSmtpSender as M,
7778
- defaultExportFilename as N,
7779
- defaultMemoryExportFilename as O,
8256
+ createResendSender as M,
8257
+ createSmtpSender as N,
8258
+ defaultExportFilename as O,
7780
8259
  PathOutsideWorkspaceError as P,
7781
- detectHomogeneousBatchList as Q,
8260
+ defaultMemoryExportFilename as Q,
7782
8261
  READ_FILE_TOOL as R,
7783
8262
  SEND_EMAIL_TOOL as S,
7784
- discardPendingAction as T,
7785
- envOverridesFromProcessEnv as U,
7786
- estimateCostUsd as V,
8263
+ detectHomogeneousBatchList as T,
8264
+ discardPendingAction as U,
8265
+ envOverridesFromProcessEnv as V,
7787
8266
  WEB_SEARCH_TOOL as W,
7788
- executeActionTool as X,
7789
- executeFileTool as Y,
7790
- executeShellTool as Z,
7791
- executeWebTool as _,
8267
+ estimateCostUsd as X,
8268
+ executeActionTool as Y,
8269
+ executeFileTool as Z,
8270
+ executeShellTool as _,
7792
8271
  ALREADY_STAGED_ACTION_TOOL as a,
7793
- formatCostSummary as a0,
7794
- formatDoctorReport as a1,
7795
- formatEmailApprovalReason as a2,
7796
- formatHelp as a3,
7797
- formatMemoryExport as a4,
7798
- formatMemoryPendingOutcome as a5,
7799
- formatMemorySummary as a6,
7800
- formatPlanProgress as a7,
7801
- formatSearchResults as a8,
7802
- formatSpendCapStatus as a9,
7803
- shouldLaunchTuiApp as aA,
7804
- stagePendingAction as aB,
7805
- stagedActionInput as aC,
7806
- stripJsonCodeFence as aD,
7807
- stripMcpToolPrefix as aE,
7808
- summarizeToolStep as aF,
7809
- updatePlanFromRun as aG,
7810
- validateConfig as aH,
7811
- formatStatus as aa,
7812
- formatTranscriptMarkdown as ab,
7813
- formatUndoLogListing as ac,
7814
- isConfigKey as ad,
7815
- isLikelyEmailAddress as ae,
7816
- listTemplateNames as af,
7817
- loadActivePlan as ag,
7818
- loadPendingAction as ah,
7819
- loadTemplate as ai,
7820
- matchTemplateIfConfident as aj,
7821
- nextPendingTask as ak,
7822
- nodeDisplayName as al,
7823
- nodeToLayer as am,
7824
- normalizeAskMode as an,
7825
- normalizeOneLoopMode as ao,
7826
- normalizePlanMode as ap,
7827
- parseClaudeCliOutput as aq,
7828
- parseConfigValue as ar,
7829
- pickTemplateForTask as as,
7830
- planCompletionPct as at,
7831
- resolveAskMode as au,
7832
- resolveConfig as av,
7833
- resolveInWorkspace as aw,
7834
- resolveOneLoopMode as ax,
7835
- resolvePlanMode as ay,
7836
- savePlan as az,
8272
+ formatConfigListing as a0,
8273
+ formatCostSummary as a1,
8274
+ formatDoctorReport as a2,
8275
+ formatEmailApprovalReason as a3,
8276
+ formatHelp as a4,
8277
+ formatMemoryExport as a5,
8278
+ formatMemoryPendingOutcome as a6,
8279
+ formatMemorySummary as a7,
8280
+ formatPlanProgress as a8,
8281
+ formatSearchResults as a9,
8282
+ savePlan as aA,
8283
+ shouldLaunchTuiApp as aB,
8284
+ stagePendingAction as aC,
8285
+ stagedActionInput as aD,
8286
+ stripJsonCodeFence as aE,
8287
+ stripMcpToolPrefix as aF,
8288
+ summarizeToolStep as aG,
8289
+ updatePlanFromRun as aH,
8290
+ validateConfig as aI,
8291
+ formatSpendCapStatus as aa,
8292
+ formatStatus as ab,
8293
+ formatTranscriptMarkdown as ac,
8294
+ formatUndoLogListing as ad,
8295
+ isConfigKey as ae,
8296
+ isLikelyEmailAddress as af,
8297
+ listTemplateNames as ag,
8298
+ loadActivePlan as ah,
8299
+ loadPendingAction as ai,
8300
+ loadTemplate as aj,
8301
+ matchTemplateIfConfident as ak,
8302
+ nextPendingTask as al,
8303
+ nodeDisplayName as am,
8304
+ nodeToLayer as an,
8305
+ normalizeAskMode as ao,
8306
+ normalizeOneLoopMode as ap,
8307
+ normalizePlanMode as aq,
8308
+ parseClaudeCliOutput as ar,
8309
+ parseConfigValue as as,
8310
+ pickTemplateForTask as at,
8311
+ planCompletionPct as au,
8312
+ resolveAskMode as av,
8313
+ resolveConfig as aw,
8314
+ resolveInWorkspace as ax,
8315
+ resolveOneLoopMode as ay,
8316
+ resolvePlanMode as az,
7837
8317
  AskClarificationService as b,
7838
8318
  ConfigValidationError as c,
7839
8319
  ConfigValueParseError as d,
7840
8320
  DEFAULT_CONFIG as e,
7841
8321
  DEFAULT_ONE_LOOP_MODE as f,
7842
8322
  DEFAULT_PLAN_MODE as g,
7843
- EmailDeliveryError as h,
7844
- FILE_TOOLS as i,
7845
- LAYER_ORDER as j,
7846
- LAYER_SHORT_CODE as k,
7847
- LIST_DIRECTORY_TOOL as l,
7848
- PersonalAssistant as m,
7849
- PrivateNetworkTargetError as n,
7850
- RUN_SHELL_COMMAND_TOOL as o,
7851
- SHELL_TOOLS as p,
7852
- WEB_TOOLS as q,
7853
- WRITE_FILE_TOOL as r,
7854
- abandonPlan as s,
7855
- applyPendingAction as t,
7856
- assertPublicHttpUrl as u,
7857
- braveSearch as v,
7858
- buildClaudePrompt as w,
7859
- buildWhyChain as x,
7860
- classifyError as y,
7861
- classifyRisk as z
8323
+ DIFF_INDENT as h,
8324
+ EmailDeliveryError as i,
8325
+ FILE_TOOLS as j,
8326
+ LAYER_ORDER as k,
8327
+ LAYER_SHORT_CODE as l,
8328
+ LIST_DIRECTORY_TOOL as m,
8329
+ PersonalAssistant as n,
8330
+ PrivateNetworkTargetError as o,
8331
+ RUN_SHELL_COMMAND_TOOL as p,
8332
+ SHELL_TOOLS as q,
8333
+ WEB_TOOLS as r,
8334
+ WRITE_FILE_TOOL as s,
8335
+ abandonPlan as t,
8336
+ applyPendingAction as u,
8337
+ assertPublicHttpUrl as v,
8338
+ braveSearch as w,
8339
+ buildClaudePrompt as x,
8340
+ buildWhyChain as y,
8341
+ classifyError as z
7862
8342
  };
7863
- //# sourceMappingURL=cli-session-D0uLdT2A.js.map
8343
+ //# sourceMappingURL=cli-session-DnSc6Hhx.js.map