omnius 1.0.545 → 1.0.547

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/index.js CHANGED
@@ -5195,6 +5195,18 @@ ${result.llmContent ?? ""}`);
5195
5195
  llmContent: this.markTranscriptFailure(result.llmContent ?? result.output ?? "", reportedExitCode, error)
5196
5196
  };
5197
5197
  }
5198
+ if (result.success && process.env["OMNIUS_DISABLE_SOFT_FAILURE_DETECT"] !== "1") {
5199
+ const declared = this.terminalErrorDeclarationFromOutput(command, result.output ?? "");
5200
+ if (declared) {
5201
+ const error = `Command exited 0 but its final output declares an error: "${declared.slice(0, 160)}". The probe did NOT achieve its goal — treat this as a failure, not a success. Do not re-run the same command unchanged; change the approach or the arguments.`;
5202
+ result = {
5203
+ ...result,
5204
+ success: false,
5205
+ error,
5206
+ llmContent: this.markSoftFailureTranscript(result.llmContent ?? result.output ?? "", error)
5207
+ };
5208
+ }
5209
+ }
5198
5210
  if (this.isBenignPipePreviewSigpipe(command, result)) {
5199
5211
  const note = "[NOTE — preview pipe closed after producing output]\nA downstream preview command such as `head`/`tail`/`sed -n` closed the pipe early, producing SIGPIPE exit 141 upstream. Captured output is usable as a preview; rerun without the preview pipe if the full output is needed.";
5200
5212
  const output = result.output ? `${result.output}
@@ -5286,6 +5298,55 @@ ${elevatedResult.stderr}` : ""),
5286
5298
  }
5287
5299
  return found;
5288
5300
  }
5301
+ /**
5302
+ * Detect an unambiguous error declaration on the FINAL line(s) of a
5303
+ * command's output despite exit 0 (false-success probe). Conservative:
5304
+ * anchored patterns, last two non-empty lines only, and skipped entirely
5305
+ * for pure search/read commands (grep/rg/cat/…) whose output legitimately
5306
+ * QUOTES error text. Returns the declaring line, or null.
5307
+ */
5308
+ terminalErrorDeclarationFromOutput(command, output) {
5309
+ if (/^\s*(?:grep|rg|ag|cat|head|tail|less|awk|sed|find|ls|wc|sort|uniq|diff|strings|hexdump|xxd|jq|yq)\b/.test(command)) {
5310
+ return null;
5311
+ }
5312
+ const lines = output.split("\n").map((l2) => l2.trim()).filter((l2) => l2.length > 0 && !l2.startsWith("["));
5313
+ if (lines.length === 0)
5314
+ return null;
5315
+ const tail = lines.slice(-2);
5316
+ const TERMINAL_ERROR = [
5317
+ /^ERROR\b[:\s]/,
5318
+ // conventional script error prefix (screenshot case: "ERROR: timed out")
5319
+ /^FAILED\b/,
5320
+ /^FAILURE\b[:\s]/,
5321
+ /^FATAL\b[:\s]/i,
5322
+ /^[A-Za-z_][A-Za-z0-9_.]*(?:Error|Exception)\b:/,
5323
+ // Python traceback terminal line
5324
+ /^panic:/,
5325
+ // Go
5326
+ /^Segmentation fault\b/
5327
+ ];
5328
+ for (let i2 = tail.length - 1; i2 >= 0; i2--) {
5329
+ const line = tail[i2];
5330
+ if (TERMINAL_ERROR.some((re) => re.test(line)))
5331
+ return line;
5332
+ }
5333
+ return null;
5334
+ }
5335
+ /**
5336
+ * Rewrite a transcript for a false-success probe: status becomes failure
5337
+ * while the true wrapper exit code (0) stays visible, so the model sees
5338
+ * BOTH facts — the process exited cleanly AND the operation failed.
5339
+ */
5340
+ markSoftFailureTranscript(text2, error) {
5341
+ if (!text2)
5342
+ return error;
5343
+ let next = text2.replace(/status: success/g, "status: failure (error declared in output despite exit 0)");
5344
+ if (!next.includes(error)) {
5345
+ next = `${next}
5346
+ error: ${error}`;
5347
+ }
5348
+ return next;
5349
+ }
5289
5350
  markTranscriptFailure(text2, exitCode, error) {
5290
5351
  if (!text2)
5291
5352
  return error;
@@ -6498,11 +6559,29 @@ import { resolve as resolve4 } from "node:path";
6498
6559
  function computeMaxUngatedLines(contextWindow) {
6499
6560
  if (contextWindow <= 0)
6500
6561
  return 200;
6501
- const budget = Math.floor(contextWindow * 0.15);
6562
+ const budget = Math.floor(contextWindow * 0.2);
6502
6563
  const maxLines = Math.floor(budget / 10);
6503
6564
  return Math.max(80, Math.min(500, maxLines));
6504
6565
  }
6505
- function buildStructuralPreview(lines, filePath, maxLines) {
6566
+ function exceedsInlineCharacterBudget(lines, contextWindow) {
6567
+ const sourceBytes = Buffer.byteLength(lines.join("\n"), "utf8");
6568
+ const projectedTokens = Math.ceil((sourceBytes + lines.length * 10 + 512) / 4);
6569
+ const tokenBudget = contextWindow > 0 ? Math.floor(contextWindow * 0.2) : 2e3;
6570
+ return projectedTokens > tokenBudget;
6571
+ }
6572
+ function boundedBranchPreview(prefix, preview, contextWindow) {
6573
+ const tokenBudget = contextWindow > 0 ? Math.floor(contextWindow * 0.2) : 2e3;
6574
+ const maxChars = Math.max(192, Math.max(0, tokenBudget - 128) * 4);
6575
+ const combined = `${prefix}
6576
+ ${preview}`;
6577
+ if (combined.length <= maxChars)
6578
+ return combined;
6579
+ const suffix = "\n[preview truncated to the 20% context budget; use AgenticRunner branch extraction]";
6580
+ if (suffix.length >= maxChars)
6581
+ return suffix.slice(0, maxChars);
6582
+ return `${combined.slice(0, maxChars - suffix.length).trimEnd()}${suffix}`;
6583
+ }
6584
+ function buildStructuralPreview(lines, filePath, maxLines, lineOffset = 0) {
6506
6585
  const total = lines.length;
6507
6586
  const HEAD = Math.min(30, Math.floor(maxLines * 0.35));
6508
6587
  const TAIL = Math.min(15, Math.floor(maxLines * 0.15));
@@ -6511,13 +6590,14 @@ function buildStructuralPreview(lines, filePath, maxLines) {
6511
6590
  `);
6512
6591
  parts.push(`## Lines 1-${HEAD}:`);
6513
6592
  for (let i2 = 0; i2 < HEAD; i2++) {
6514
- parts.push(`${String(i2 + 1).padStart(6)} | ${lines[i2]}`);
6593
+ const line = lines[i2] ?? "";
6594
+ parts.push(`${String(lineOffset + i2 + 1).padStart(6)} | ${line.slice(0, 400)}${line.length > 400 ? "…" : ""}`);
6515
6595
  }
6516
6596
  const sigs = [];
6517
6597
  for (let i2 = HEAD; i2 < total - TAIL; i2++) {
6518
6598
  const line = lines[i2];
6519
6599
  if (SIG_PATTERNS.some((p2) => p2.test(line))) {
6520
- sigs.push(`${String(i2 + 1).padStart(6)} | ${line}`);
6600
+ sigs.push(`${String(lineOffset + i2 + 1).padStart(6)} | ${line.slice(0, 400)}${line.length > 400 ? "…" : ""}`);
6521
6601
  }
6522
6602
  }
6523
6603
  if (sigs.length > 0) {
@@ -6539,7 +6619,8 @@ function buildStructuralPreview(lines, filePath, maxLines) {
6539
6619
  parts.push(`
6540
6620
  ## Lines ${tailStart + 1}-${total}:`);
6541
6621
  for (let i2 = tailStart; i2 < total; i2++) {
6542
- parts.push(`${String(i2 + 1).padStart(6)} | ${lines[i2]}`);
6622
+ const line = lines[i2] ?? "";
6623
+ parts.push(`${String(lineOffset + i2 + 1).padStart(6)} | ${line.slice(0, 400)}${line.length > 400 ? "…" : ""}`);
6543
6624
  }
6544
6625
  }
6545
6626
  parts.push(``);
@@ -6595,7 +6676,7 @@ var init_file_read = __esm({
6595
6676
  FileReadTool = class {
6596
6677
  name = "file_read";
6597
6678
  aliases = ["read_file", "read", "cat"];
6598
- description = "Read the contents of a file. For large files (200+ lines), returns a structural preview with signatures — use offset/limit to read specific sections.";
6679
+ description = "Read file contents. Payloads projected above 20% of context are branch-extracted by the agent runner; direct use returns a bounded structural preview. offset/limit does not bypass the budget.";
6599
6680
  parameters = {
6600
6681
  type: "object",
6601
6682
  properties: {
@@ -6640,7 +6721,21 @@ var init_file_read = __esm({
6640
6721
  const totalLines = lines.length;
6641
6722
  if (offset !== void 0 || limit !== void 0) {
6642
6723
  const startIdx = Math.max(0, (offset ?? 1) - 1);
6643
- lines = lines.slice(startIdx, limit ? startIdx + limit : void 0);
6724
+ lines = lines.slice(startIdx, limit !== void 0 ? startIdx + Math.max(0, limit) : void 0);
6725
+ if (exceedsInlineCharacterBudget(lines, this._contextWindowSize)) {
6726
+ const maxLines2 = computeMaxUngatedLines(this._contextWindowSize);
6727
+ return {
6728
+ success: true,
6729
+ output: boundedBranchPreview([
6730
+ fileContextHeader(filePath, content, { offset, limit }),
6731
+ `[BRANCH_REQUIRED] The selected range exceeds 20% of the context window and was not inlined. An AgenticRunner must route this request through branch extraction; direct callers receive only this bounded structural preview.`
6732
+ ].join("\n"), buildStructuralPreview(lines, filePath, maxLines2, startIdx), this._contextWindowSize),
6733
+ durationMs: performance.now() - start2,
6734
+ mutated: false,
6735
+ mutatedFiles: [],
6736
+ beforeHash: contentHash(content)
6737
+ };
6738
+ }
6644
6739
  const numbered2 = lines.map((line, i2) => `${String(startIdx + i2 + 1).padStart(6)} | ${line}`).join("\n");
6645
6740
  const hash = contentHash(content);
6646
6741
  return {
@@ -6655,12 +6750,14 @@ ${numbered2}`,
6655
6750
  }
6656
6751
  touchFile(this.workingDir, filePath);
6657
6752
  const maxLines = computeMaxUngatedLines(this._contextWindowSize);
6658
- if (totalLines > maxLines) {
6753
+ if (exceedsInlineCharacterBudget(lines, this._contextWindowSize)) {
6659
6754
  const notes = getFileNotes(this.workingDir, filePath);
6660
6755
  return {
6661
6756
  success: true,
6662
- output: `${fileContextHeader(filePath, content)}
6663
- ${buildStructuralPreview(lines, filePath, maxLines)}${notes ? "\n\n" + notes : ""}`,
6757
+ output: boundedBranchPreview([
6758
+ fileContextHeader(filePath, content),
6759
+ `[BRANCH_REQUIRED] This file exceeds 20% of the context window and was not inlined. An AgenticRunner must route it through branch extraction.`
6760
+ ].join("\n"), `${buildStructuralPreview(lines, filePath, maxLines)}${notes ? "\n\n" + notes : ""}`, this._contextWindowSize),
6664
6761
  durationMs: performance.now() - start2,
6665
6762
  mutated: false,
6666
6763
  mutatedFiles: [],
@@ -119389,7 +119486,7 @@ var require_auto = __commonJS({
119389
119486
  // ../node_modules/acme-client/src/client.js
119390
119487
  var require_client = __commonJS({
119391
119488
  "../node_modules/acme-client/src/client.js"(exports, module) {
119392
- var { createHash: createHash53 } = __require("crypto");
119489
+ var { createHash: createHash54 } = __require("crypto");
119393
119490
  var { getPemBodyAsB64u } = require_crypto();
119394
119491
  var { log: log22 } = require_logger();
119395
119492
  var HttpClient = require_http();
@@ -119700,14 +119797,14 @@ var require_client = __commonJS({
119700
119797
  */
119701
119798
  async getChallengeKeyAuthorization(challenge) {
119702
119799
  const jwk = this.http.getJwk();
119703
- const keysum = createHash53("sha256").update(JSON.stringify(jwk));
119800
+ const keysum = createHash54("sha256").update(JSON.stringify(jwk));
119704
119801
  const thumbprint = keysum.digest("base64url");
119705
119802
  const result = `${challenge.token}.${thumbprint}`;
119706
119803
  if (challenge.type === "http-01") {
119707
119804
  return result;
119708
119805
  }
119709
119806
  if (challenge.type === "dns-01") {
119710
- return createHash53("sha256").update(result).digest("base64url");
119807
+ return createHash54("sha256").update(result).digest("base64url");
119711
119808
  }
119712
119809
  if (challenge.type === "tls-alpn-01") {
119713
119810
  return result;
@@ -124334,9 +124431,9 @@ var require_sha256 = __commonJS({
124334
124431
  var forge = require_forge();
124335
124432
  require_md();
124336
124433
  require_util2();
124337
- var sha2565 = module.exports = forge.sha256 = forge.sha256 || {};
124338
- forge.md.sha256 = forge.md.algorithms.sha256 = sha2565;
124339
- sha2565.create = function() {
124434
+ var sha2566 = module.exports = forge.sha256 = forge.sha256 || {};
124435
+ forge.md.sha256 = forge.md.algorithms.sha256 = sha2566;
124436
+ sha2566.create = function() {
124340
124437
  if (!_initialized) {
124341
124438
  _init();
124342
124439
  }
@@ -262387,7 +262484,7 @@ var require_websocket2 = __commonJS({
262387
262484
  var http6 = __require("http");
262388
262485
  var net5 = __require("net");
262389
262486
  var tls2 = __require("tls");
262390
- var { randomBytes: randomBytes31, createHash: createHash53 } = __require("crypto");
262487
+ var { randomBytes: randomBytes31, createHash: createHash54 } = __require("crypto");
262391
262488
  var { Duplex: Duplex3, Readable } = __require("stream");
262392
262489
  var { URL: URL3 } = __require("url");
262393
262490
  var PerMessageDeflate3 = require_permessage_deflate2();
@@ -263047,7 +263144,7 @@ var require_websocket2 = __commonJS({
263047
263144
  abortHandshake(websocket, socket, "Invalid Upgrade header");
263048
263145
  return;
263049
263146
  }
263050
- const digest3 = createHash53("sha1").update(key + GUID).digest("base64");
263147
+ const digest3 = createHash54("sha1").update(key + GUID).digest("base64");
263051
263148
  if (res.headers["sec-websocket-accept"] !== digest3) {
263052
263149
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
263053
263150
  return;
@@ -263414,7 +263511,7 @@ var require_websocket_server = __commonJS({
263414
263511
  var EventEmitter15 = __require("events");
263415
263512
  var http6 = __require("http");
263416
263513
  var { Duplex: Duplex3 } = __require("stream");
263417
- var { createHash: createHash53 } = __require("crypto");
263514
+ var { createHash: createHash54 } = __require("crypto");
263418
263515
  var extension3 = require_extension2();
263419
263516
  var PerMessageDeflate3 = require_permessage_deflate2();
263420
263517
  var subprotocol3 = require_subprotocol();
@@ -263715,7 +263812,7 @@ var require_websocket_server = __commonJS({
263715
263812
  );
263716
263813
  }
263717
263814
  if (this._state > RUNNING) return abortHandshake(socket, 503);
263718
- const digest3 = createHash53("sha1").update(key + GUID).digest("base64");
263815
+ const digest3 = createHash54("sha1").update(key + GUID).digest("base64");
263719
263816
  const headers = [
263720
263817
  "HTTP/1.1 101 Switching Protocols",
263721
263818
  "Upgrade: websocket",
@@ -276522,13 +276619,13 @@ Justification: ${justification || "(none provided)"}`,
276522
276619
  }
276523
276620
  const snapshot = JSON.stringify(this.selfState, null, 2);
276524
276621
  try {
276525
- const { createHash: createHash53 } = await import("node:crypto");
276622
+ const { createHash: createHash54 } = await import("node:crypto");
276526
276623
  const snapshotDir = join44(this.cwd, ".omnius", "identity", "snapshots");
276527
276624
  await mkdir7(snapshotDir, { recursive: true });
276528
276625
  const version5 = this.selfState.version;
276529
276626
  const snapshotPath = join44(snapshotDir, `v${version5}.json`);
276530
276627
  await writeFile12(snapshotPath, snapshot, "utf8");
276531
- const hash = createHash53("sha256").update(snapshot).digest("hex");
276628
+ const hash = createHash54("sha256").update(snapshot).digest("hex");
276532
276629
  await writeFile12(join44(this.cwd, ".omnius", "identity", "latest-hash.txt"), hash, "utf8");
276533
276630
  let ipfsCid = "";
276534
276631
  try {
@@ -276661,8 +276758,8 @@ New: ${newNarrative.slice(0, 200)}...`,
276661
276758
  }
276662
276759
  // ── Helpers ──────────────────────────────────────────────────────────────
276663
276760
  createDefaultState() {
276664
- const { createHash: createHash53 } = __require("node:crypto");
276665
- const machineId = createHash53("sha256").update(this.cwd).digest("hex").slice(0, 12);
276761
+ const { createHash: createHash54 } = __require("node:crypto");
276762
+ const machineId = createHash54("sha256").update(this.cwd).digest("hex").slice(0, 12);
276666
276763
  return {
276667
276764
  self_id: `omnius-${machineId}`,
276668
276765
  version: 1,
@@ -276744,9 +276841,9 @@ New: ${newNarrative.slice(0, 200)}...`,
276744
276841
  let cid;
276745
276842
  if (this.selfState.version > prevVersion) {
276746
276843
  try {
276747
- const { createHash: createHash53 } = await import("node:crypto");
276844
+ const { createHash: createHash54 } = await import("node:crypto");
276748
276845
  const stateJson = JSON.stringify(this.selfState);
276749
- const hash = createHash53("sha256").update(stateJson).digest("hex").slice(0, 32);
276846
+ const hash = createHash54("sha256").update(stateJson).digest("hex").slice(0, 32);
276750
276847
  const cidsPath = join44(this.cwd, ".omnius", "identity", "cids.json");
276751
276848
  const cidsData = { latest: "", hash, version: this.selfState.version };
276752
276849
  try {
@@ -566130,6 +566227,165 @@ var init_textSanitize = __esm({
566130
566227
  }
566131
566228
  });
566132
566229
 
566230
+ // packages/orchestrator/dist/text-echo-guard.js
566231
+ function normalizeForEcho(text2) {
566232
+ return text2.replace(/<think>[\s\S]*?<\/think>/gi, "").replace(/<reasoning>[\s\S]*?<\/reasoning>/gi, "").replace(/```[\s\S]*?```/g, " ").replace(/[*_`#>|-]+/g, " ").toLowerCase().replace(/\s+/g, " ").trim();
566233
+ }
566234
+ function echoSimilarity(a2, b) {
566235
+ const sa = shingles(a2);
566236
+ const sb = shingles(b);
566237
+ if (sa.size === 0 || sb.size === 0) {
566238
+ return a2 === b && a2.length > 0 ? 1 : 0;
566239
+ }
566240
+ let inter = 0;
566241
+ for (const s2 of sa)
566242
+ if (sb.has(s2))
566243
+ inter++;
566244
+ const union = sa.size + sb.size - inter;
566245
+ return union === 0 ? 0 : inter / union;
566246
+ }
566247
+ function shingles(normalized, k = 3) {
566248
+ const words = normalized.split(" ").filter(Boolean);
566249
+ const out = /* @__PURE__ */ new Set();
566250
+ for (let i2 = 0; i2 + k <= words.length; i2++) {
566251
+ out.add(words.slice(i2, i2 + k).join(" "));
566252
+ }
566253
+ return out;
566254
+ }
566255
+ function contentAsText(m2) {
566256
+ if (typeof m2.content === "string")
566257
+ return m2.content;
566258
+ return null;
566259
+ }
566260
+ function isEligible(m2, minLength) {
566261
+ if (m2.role !== "assistant")
566262
+ return false;
566263
+ if (Array.isArray(m2.tool_calls) && m2.tool_calls.length > 0)
566264
+ return false;
566265
+ const text2 = contentAsText(m2);
566266
+ if (!text2)
566267
+ return false;
566268
+ if (text2.startsWith(COLLAPSE_MARKER))
566269
+ return false;
566270
+ return normalizeForEcho(text2).length >= minLength;
566271
+ }
566272
+ var COLLAPSE_MARKER, DEFAULTS, TextEchoGuard;
566273
+ var init_text_echo_guard = __esm({
566274
+ "packages/orchestrator/dist/text-echo-guard.js"() {
566275
+ "use strict";
566276
+ COLLAPSE_MARKER = "[Superseded near-duplicate plan removed";
566277
+ DEFAULTS = {
566278
+ similarityThreshold: 0.6,
566279
+ minLength: 80,
566280
+ window: 6
566281
+ };
566282
+ TextEchoGuard = class {
566283
+ threshold;
566284
+ minLength;
566285
+ window;
566286
+ /** Recent normalized text-only assistant messages (raw preview kept for messaging). */
566287
+ recent = [];
566288
+ streak = 0;
566289
+ constructor(options2 = {}) {
566290
+ this.threshold = options2.similarityThreshold ?? DEFAULTS.similarityThreshold;
566291
+ this.minLength = options2.minLength ?? DEFAULTS.minLength;
566292
+ this.window = options2.window ?? DEFAULTS.window;
566293
+ }
566294
+ /**
566295
+ * Observe a new text-only assistant message. Records it and reports whether
566296
+ * it echoes a recent one. Call ONLY for text-only turns (no tool_calls).
566297
+ */
566298
+ observe(text2) {
566299
+ const normalized = normalizeForEcho(text2);
566300
+ if (normalized.length < this.minLength) {
566301
+ return { isEcho: false, echoCount: this.streak, similarity: 0, matchedPreview: "" };
566302
+ }
566303
+ let best = 0;
566304
+ let matchedPreview = "";
566305
+ for (const prev of this.recent) {
566306
+ const sim = echoSimilarity(normalized, prev.normalized);
566307
+ if (sim > best) {
566308
+ best = sim;
566309
+ matchedPreview = prev.preview;
566310
+ }
566311
+ }
566312
+ const isEcho = best >= this.threshold;
566313
+ this.streak = isEcho ? this.streak + 1 : 0;
566314
+ this.recent.push({ normalized, preview: text2.slice(0, 160) });
566315
+ if (this.recent.length > this.window)
566316
+ this.recent.shift();
566317
+ return {
566318
+ isEcho,
566319
+ echoCount: this.streak,
566320
+ similarity: best,
566321
+ matchedPreview
566322
+ };
566323
+ }
566324
+ /** A real tool call happened — the loop is broken; reset escalation. */
566325
+ noteToolProgress() {
566326
+ this.streak = 0;
566327
+ }
566328
+ /**
566329
+ * Remove the attractor from the live prompt: for every pair of text-only
566330
+ * assistant messages where an EARLIER one is a near-duplicate of a LATER
566331
+ * one, replace the earlier one's content with a one-line stub. The latest
566332
+ * copy always survives. Safe to call repeatedly (stubs are skipped).
566333
+ *
566334
+ * Returns the number of messages collapsed.
566335
+ */
566336
+ collapseEchoes(messages2) {
566337
+ const eligible = [];
566338
+ for (let i2 = 0; i2 < messages2.length; i2++) {
566339
+ const m2 = messages2[i2];
566340
+ if (isEligible(m2, this.minLength)) {
566341
+ eligible.push({ idx: i2, normalized: normalizeForEcho(m2.content) });
566342
+ }
566343
+ }
566344
+ if (eligible.length < 2)
566345
+ return 0;
566346
+ let collapsed = 0;
566347
+ const survivors = [];
566348
+ for (let j = eligible.length - 1; j >= 0; j--) {
566349
+ const cur = eligible[j];
566350
+ const echoesSurvivor = survivors.some((s2) => echoSimilarity(cur.normalized, s2) >= this.threshold);
566351
+ if (echoesSurvivor) {
566352
+ const msg = messages2[cur.idx];
566353
+ const preview = (contentAsText(msg) ?? "").slice(0, 100).replace(/\s+/g, " ");
566354
+ msg.content = `${COLLAPSE_MARKER} — an almost identical statement appears later in this conversation ("${preview}…"). No tool call followed it. Do NOT restate this plan; execute its next step with a tool call.]`;
566355
+ collapsed++;
566356
+ } else {
566357
+ survivors.push(cur.normalized);
566358
+ }
566359
+ }
566360
+ return collapsed;
566361
+ }
566362
+ /**
566363
+ * Escalating pattern-breaker to inject INSTEAD of the generic
566364
+ * "Continue working…" nudge (which, being verbatim-identical each turn, is
566365
+ * itself part of the repetition attractor).
566366
+ */
566367
+ buildIntervention(obs) {
566368
+ const pct2 = Math.round(obs.similarity * 100);
566369
+ const quoted = obs.matchedPreview.replace(/\s+/g, " ").slice(0, 120);
566370
+ if (obs.echoCount <= 1) {
566371
+ return `[ECHO BREAK] Your last message is ${pct2}% identical to a previous message of yours ("${quoted}…") and neither included a tool call. The plan is already recorded — writing it again does nothing. Your next output MUST be a tool call executing the FIRST concrete step of that plan (e.g. file_write, shell, list_directory). Do not produce any text-only response.`;
566372
+ }
566373
+ if (obs.echoCount === 2) {
566374
+ return `[ECHO BREAK — SECOND WARNING] You have now restated the same plan ${obs.echoCount + 1} times with zero tool calls. Text-only planning is FORBIDDEN for the rest of this task. Choose exactly one:
566375
+ 1. Call a tool that mutates or inspects the workspace (file_write / shell / file_read).
566376
+ 2. If genuinely blocked, call task_complete with a summary that names the exact blocker.
566377
+ Any further text-only response will be discarded.`;
566378
+ }
566379
+ return `[ECHO BREAK — FINAL] ${obs.echoCount + 1} near-identical text-only responses detected. This trajectory is dead. Abandon the current phrasing entirely: do not describe, do not plan. Emit ONLY a tool call. If no tool call is possible, call task_complete and report the blocker.`;
566380
+ }
566381
+ /** Test/telemetry helper. */
566382
+ snapshot() {
566383
+ return { streak: this.streak, windowSize: this.recent.length };
566384
+ }
566385
+ };
566386
+ }
566387
+ });
566388
+
566133
566389
  // packages/orchestrator/dist/permissionRuleset.js
566134
566390
  function checkDoomLoop(context2) {
566135
566391
  const history = context2.toolCallHistory;
@@ -567254,7 +567510,109 @@ function reconcileCompletedTodosWithEvidence(input) {
567254
567510
  downgrades
567255
567511
  };
567256
567512
  }
567257
- var NON_WORK_TOOLS, VISUAL_EVIDENCE_TOOLS, AUDIO_EVIDENCE_TOOLS;
567513
+ function extractPathTokens(content) {
567514
+ const withSeparator = [];
567515
+ const bareFilenames = [];
567516
+ const stripped = content.replace(/https?:\/\/\S+/g, " ").replace(/`/g, " ");
567517
+ for (const raw of stripped.match(PATH_TOKEN_RE) ?? []) {
567518
+ const hadSeparator = raw.includes("/");
567519
+ const token = raw.replace(/[.,;:!?)]+$/, "").replace(/\/+$/, "");
567520
+ if (!token || token.length < 3)
567521
+ continue;
567522
+ if (/^v?\d+(\.\d+)*$/i.test(token))
567523
+ continue;
567524
+ if (NON_FILE_SUFFIXES.has(token.toLowerCase()))
567525
+ continue;
567526
+ if (hadSeparator)
567527
+ withSeparator.push(token);
567528
+ else
567529
+ bareFilenames.push(token);
567530
+ }
567531
+ return { withSeparator, bareFilenames };
567532
+ }
567533
+ function looksLikeDirectory(pathToken) {
567534
+ const last2 = pathToken.split("/").pop() ?? "";
567535
+ return !last2.includes(".");
567536
+ }
567537
+ function reconcileRestoredTodosWithDisk(input) {
567538
+ const cleaned = [];
567539
+ let droppedCorrupt = 0;
567540
+ for (const todo of input.todos) {
567541
+ const valid = todo && typeof todo.content === "string" && todo.content.trim().length > 0 && typeof todo.status === "string" && ["pending", "in_progress", "completed", "blocked"].includes(todo.status);
567542
+ if (valid)
567543
+ cleaned.push({ ...todo });
567544
+ else
567545
+ droppedCorrupt++;
567546
+ }
567547
+ const index = buildTodoTruthIndex(cleaned);
567548
+ const downgrades = [];
567549
+ const contextDirsFor = (todo) => {
567550
+ const dirs = [];
567551
+ let cur = todo;
567552
+ const seen = /* @__PURE__ */ new Set();
567553
+ while (cur) {
567554
+ if (cur.id && seen.has(cur.id))
567555
+ break;
567556
+ if (cur.id)
567557
+ seen.add(cur.id);
567558
+ const { withSeparator } = extractPathTokens(cur.content);
567559
+ for (const p2 of withSeparator) {
567560
+ if (looksLikeDirectory(p2))
567561
+ dirs.push(p2);
567562
+ }
567563
+ cur = cur.parentId ? index.byId.get(cur.parentId) : void 0;
567564
+ }
567565
+ return dirs;
567566
+ };
567567
+ for (const todo of cleaned) {
567568
+ if (todo.status !== "completed")
567569
+ continue;
567570
+ const declared = (todo.declaredArtifacts ?? []).filter((a2) => typeof a2 === "string" && a2.trim().length > 0);
567571
+ const { withSeparator, bareFilenames } = extractPathTokens(todo.content);
567572
+ const contextDirs = contextDirsFor(todo);
567573
+ const candidates = /* @__PURE__ */ new Set();
567574
+ for (const a2 of declared)
567575
+ candidates.add(input.resolvePath(input.workingDir, a2));
567576
+ for (const p2 of withSeparator)
567577
+ candidates.add(input.resolvePath(input.workingDir, p2));
567578
+ for (const f2 of bareFilenames) {
567579
+ candidates.add(input.resolvePath(input.workingDir, f2));
567580
+ for (const dir of contextDirs) {
567581
+ candidates.add(input.resolvePath(input.workingDir, dir, f2));
567582
+ }
567583
+ }
567584
+ if (candidates.size === 0)
567585
+ continue;
567586
+ let anyExists = false;
567587
+ for (const abs of candidates) {
567588
+ if (input.exists(abs)) {
567589
+ anyExists = true;
567590
+ break;
567591
+ }
567592
+ }
567593
+ if (anyExists)
567594
+ continue;
567595
+ const shown = [...candidates].slice(0, 4).join(", ");
567596
+ const blocker = `Restored completion claim contradicts the local disk: none of the referenced artifacts exist (checked: ${shown}). The prior session's work is not present in this workspace. Do NOT search for these artifacts — CREATE them (file_write/shell mkdir) as the next step.`;
567597
+ downgrades.push({
567598
+ id: todo.id,
567599
+ content: todo.content,
567600
+ from: "completed",
567601
+ to: "pending",
567602
+ blocker,
567603
+ evidence: `disk verification at restore: 0/${candidates.size} candidate path(s) exist`
567604
+ });
567605
+ todo.status = "pending";
567606
+ todo.blocker = blocker;
567607
+ }
567608
+ return {
567609
+ todos: cleaned,
567610
+ changed: downgrades.length > 0 || droppedCorrupt > 0,
567611
+ downgrades,
567612
+ droppedCorrupt
567613
+ };
567614
+ }
567615
+ var NON_WORK_TOOLS, VISUAL_EVIDENCE_TOOLS, AUDIO_EVIDENCE_TOOLS, PATH_TOKEN_RE, NON_FILE_SUFFIXES;
567258
567616
  var init_todoTruth = __esm({
567259
567617
  "packages/orchestrator/dist/todoTruth.js"() {
567260
567618
  "use strict";
@@ -567278,6 +567636,13 @@ var init_todoTruth = __esm({
567278
567636
  "transcribe_url",
567279
567637
  "video_understand"
567280
567638
  ]);
567639
+ PATH_TOKEN_RE = /[A-Za-z0-9_.~-]*\/[A-Za-z0-9_.\/~-]*|[A-Za-z0-9_-]+\.[A-Za-z0-9]{1,8}\b/g;
567640
+ NON_FILE_SUFFIXES = /* @__PURE__ */ new Set([
567641
+ // common sentence-token false positives ("e.g.", version numbers, hosts)
567642
+ "e.g",
567643
+ "i.e",
567644
+ "vs"
567645
+ ]);
567281
567646
  }
567282
567647
  });
567283
567648
 
@@ -576742,6 +577107,7 @@ var init_streaming_executor = __esm({
576742
577107
  reset() {
576743
577108
  this.tools.clear();
576744
577109
  this.insertionOrder = [];
577110
+ this.executeFn = null;
576745
577111
  }
576746
577112
  // ─────────────────────────────────────────────────────────
576747
577113
  // Internal — Hannover-aligned concurrency control
@@ -578614,9 +578980,11 @@ var init_evidenceLedger = __esm({
578614
578980
  if (!path16 || !content)
578615
578981
  return;
578616
578982
  const built = buildExtract(content);
578983
+ if (input.fidelity)
578984
+ built.fidelity = input.fidelity;
578617
578985
  const existing = this.entries.get(path16);
578618
578986
  if (existing && existing.readVersion === fileVersion && !existing.stale) {
578619
- const keepNew = built.text.length >= existing.content.length;
578987
+ const keepNew = input.fidelity === "extract" || built.text.length >= existing.content.length;
578620
578988
  this.entries.set(path16, {
578621
578989
  ...existing,
578622
578990
  content: keepNew ? built.text : existing.content,
@@ -578759,6 +579127,175 @@ var init_evidenceLedger = __esm({
578759
579127
  }
578760
579128
  });
578761
579129
 
579130
+ // packages/orchestrator/dist/observationLedger.js
579131
+ function hashText(text2) {
579132
+ let h = 2166136261;
579133
+ for (let i2 = 0; i2 < text2.length; i2++) {
579134
+ h ^= text2.charCodeAt(i2);
579135
+ h = Math.imul(h, 16777619);
579136
+ }
579137
+ return (h >>> 0).toString(16);
579138
+ }
579139
+ function boundOutput(output) {
579140
+ if (output.length <= ENTRY_FULL_CHARS)
579141
+ return output;
579142
+ const head = output.slice(0, ENTRY_HEAD_CHARS);
579143
+ const tail = output.slice(-ENTRY_TAIL_CHARS);
579144
+ return `${head}
579145
+ … (${output.length - ENTRY_HEAD_CHARS - ENTRY_TAIL_CHARS} chars elided — full output was in the turn it ran) …
579146
+ ${tail}`;
579147
+ }
579148
+ function labelFor(tool, args) {
579149
+ const a2 = args ?? {};
579150
+ const pick = (...keys) => {
579151
+ for (const k of keys) {
579152
+ const v = a2[k];
579153
+ if (typeof v === "string" && v.trim())
579154
+ return v.trim();
579155
+ }
579156
+ return "";
579157
+ };
579158
+ let detail = "";
579159
+ switch (tool) {
579160
+ case "shell":
579161
+ case "shell_async":
579162
+ detail = pick("command", "cmd");
579163
+ break;
579164
+ case "web_fetch":
579165
+ detail = pick("url", "target");
579166
+ break;
579167
+ case "web_search":
579168
+ detail = pick("query", "q");
579169
+ break;
579170
+ case "list_directory":
579171
+ case "file_explore":
579172
+ detail = pick("path") || ".";
579173
+ break;
579174
+ case "grep_search":
579175
+ case "find_files":
579176
+ detail = [pick("pattern", "query"), pick("path")].filter(Boolean).join(" in ");
579177
+ break;
579178
+ default:
579179
+ detail = pick("path", "url", "query", "command", "target");
579180
+ }
579181
+ const flat = detail.replace(/\s+/g, " ").slice(0, 120);
579182
+ return flat ? `${tool}: ${flat}` : tool;
579183
+ }
579184
+ var SKIP_TOOLS, ENTRY_FULL_CHARS, ENTRY_HEAD_CHARS, ENTRY_TAIL_CHARS, MAX_ENTRIES2, ObservationLedger;
579185
+ var init_observationLedger = __esm({
579186
+ "packages/orchestrator/dist/observationLedger.js"() {
579187
+ "use strict";
579188
+ SKIP_TOOLS = /* @__PURE__ */ new Set([
579189
+ "file_read",
579190
+ // EvidenceLedger's domain
579191
+ "todo_write",
579192
+ "todo_read",
579193
+ "task_complete",
579194
+ "memory_read",
579195
+ "memory_write",
579196
+ "working_notes"
579197
+ ]);
579198
+ ENTRY_FULL_CHARS = 1200;
579199
+ ENTRY_HEAD_CHARS = 700;
579200
+ ENTRY_TAIL_CHARS = 300;
579201
+ MAX_ENTRIES2 = 24;
579202
+ ObservationLedger = class {
579203
+ entries = /* @__PURE__ */ new Map();
579204
+ record(input) {
579205
+ const { tool, fingerprint, output, success, turn } = input;
579206
+ if (!fingerprint || SKIP_TOOLS.has(tool))
579207
+ return;
579208
+ const trimmed = (output ?? "").trim();
579209
+ if (!trimmed)
579210
+ return;
579211
+ const outputHash = hashText(trimmed);
579212
+ const existing = this.entries.get(fingerprint);
579213
+ if (existing) {
579214
+ const identical = existing.outputHash === outputHash;
579215
+ this.entries.delete(fingerprint);
579216
+ this.entries.set(fingerprint, {
579217
+ ...existing,
579218
+ output: boundOutput(trimmed),
579219
+ fullChars: trimmed.length,
579220
+ success,
579221
+ lastTurn: turn,
579222
+ runs: existing.runs + 1,
579223
+ identicalRuns: identical ? existing.identicalRuns + 1 : 1,
579224
+ outputHash
579225
+ });
579226
+ return;
579227
+ }
579228
+ this.entries.set(fingerprint, {
579229
+ fingerprint,
579230
+ tool,
579231
+ label: labelFor(tool, input.args),
579232
+ output: boundOutput(trimmed),
579233
+ fullChars: trimmed.length,
579234
+ success,
579235
+ lastTurn: turn,
579236
+ runs: 1,
579237
+ identicalRuns: 1,
579238
+ outputHash
579239
+ });
579240
+ while (this.entries.size > MAX_ENTRIES2) {
579241
+ const oldest = this.entries.keys().next().value;
579242
+ if (oldest === void 0)
579243
+ break;
579244
+ this.entries.delete(oldest);
579245
+ }
579246
+ }
579247
+ /** Consecutive identical-output executions for a fingerprint (0 if unseen). */
579248
+ identicalRunsFor(fingerprint) {
579249
+ return this.entries.get(fingerprint)?.identicalRuns ?? 0;
579250
+ }
579251
+ size() {
579252
+ return this.entries.size;
579253
+ }
579254
+ clear() {
579255
+ this.entries.clear();
579256
+ }
579257
+ /**
579258
+ * Render the CURRENT OBSERVED STATE block for the frame. Newest first,
579259
+ * bounded to maxChars. Every entry shows outcome, repeat counts, and the
579260
+ * actual output — the ground truth the model must reason from.
579261
+ */
579262
+ renderBlock(maxChars = 5e3) {
579263
+ if (this.entries.size === 0)
579264
+ return null;
579265
+ const newestFirst = [...this.entries.values()].reverse();
579266
+ const lines = [
579267
+ "[CURRENT OBSERVED STATE — latest output of each distinct tool call this run]",
579268
+ "This is the ground truth your tools actually returned (regenerated every turn; survives compaction).",
579269
+ "Reason from these outputs — NOT from your earlier prose about them. If an entry says the output was identical across repeats, re-running that exact call will return the same thing again.",
579270
+ ""
579271
+ ];
579272
+ let used = lines.join("\n").length;
579273
+ for (const e2 of newestFirst) {
579274
+ const outcome = e2.success ? "ok" : "FAILED";
579275
+ const repeat = e2.runs > 1 ? e2.identicalRuns >= 2 ? ` (run ${e2.runs}×; output IDENTICAL ${e2.identicalRuns}× in a row — no new information)` : ` (run ${e2.runs}×; output changed on the last run)` : "";
579276
+ const header = `▸ [${outcome}] ${e2.label} — turn ${e2.lastTurn}${repeat}`;
579277
+ const body = e2.output.split("\n").map((l2) => ` ${l2}`).join("\n");
579278
+ const chunk = `${header}
579279
+ ${body}
579280
+ `;
579281
+ if (used + chunk.length > maxChars) {
579282
+ const stub = `▸ [${outcome}] ${e2.label} — turn ${e2.lastTurn}${repeat} (output elided for budget)
579283
+ `;
579284
+ if (used + stub.length <= maxChars) {
579285
+ lines.push(stub);
579286
+ used += stub.length;
579287
+ }
579288
+ continue;
579289
+ }
579290
+ lines.push(chunk);
579291
+ used += chunk.length;
579292
+ }
579293
+ return lines.join("\n");
579294
+ }
579295
+ };
579296
+ }
579297
+ });
579298
+
578762
579299
  // packages/orchestrator/dist/contextWindowDump.js
578763
579300
  import { existsSync as existsSync102, mkdirSync as mkdirSync58, readdirSync as readdirSync32, readFileSync as readFileSync78, statSync as statSync39, unlinkSync as unlinkSync17, writeFileSync as writeFileSync48, appendFileSync as appendFileSync9 } from "node:fs";
578764
579301
  import { homedir as homedir35 } from "node:os";
@@ -581254,7 +581791,7 @@ var init_focusSupervisor = __esm({
581254
581791
  });
581255
581792
 
581256
581793
  // packages/orchestrator/dist/convergence-breaker.js
581257
- var InMemoryConvergenceStore, DEFAULTS, ConvergenceBreaker;
581794
+ var InMemoryConvergenceStore, DEFAULTS2, ConvergenceBreaker;
581258
581795
  var init_convergence_breaker = __esm({
581259
581796
  "packages/orchestrator/dist/convergence-breaker.js"() {
581260
581797
  "use strict";
@@ -581271,7 +581808,7 @@ var init_convergence_breaker = __esm({
581271
581808
  return [...this.map.values()];
581272
581809
  }
581273
581810
  };
581274
- DEFAULTS = { warnRound: 2, stallRound: 3, abandonRound: 5 };
581811
+ DEFAULTS2 = { warnRound: 2, stallRound: 3, abandonRound: 5 };
581275
581812
  ConvergenceBreaker = class {
581276
581813
  warnRound;
581277
581814
  stallRound;
@@ -581290,9 +581827,9 @@ var init_convergence_breaker = __esm({
581290
581827
  /** Last verification signal (error count) seen per family, for delta-based progress. */
581291
581828
  lastSignal = /* @__PURE__ */ new Map();
581292
581829
  constructor(options2 = {}) {
581293
- this.warnRound = Math.max(1, options2.warnRound ?? DEFAULTS.warnRound);
581294
- this.stallRound = Math.max(this.warnRound + 1, options2.stallRound ?? DEFAULTS.stallRound);
581295
- this.abandonRound = Math.max(this.stallRound + 1, options2.abandonRound ?? DEFAULTS.abandonRound);
581830
+ this.warnRound = Math.max(1, options2.warnRound ?? DEFAULTS2.warnRound);
581831
+ this.stallRound = Math.max(this.warnRound + 1, options2.stallRound ?? DEFAULTS2.stallRound);
581832
+ this.abandonRound = Math.max(this.stallRound + 1, options2.abandonRound ?? DEFAULTS2.abandonRound);
581296
581833
  this.store = options2.store ?? new InMemoryConvergenceStore();
581297
581834
  }
581298
581835
  /**
@@ -583584,6 +584121,7 @@ var init_completion_resolution_verifier = __esm({
583584
584121
  });
583585
584122
 
583586
584123
  // packages/orchestrator/dist/evidenceBranch.js
584124
+ import { createHash as createHash33 } from "node:crypto";
583587
584125
  function buildBranchExtractionBrief(input) {
583588
584126
  const path16 = cleanBriefText(input.path, 320) || "the requested file";
583589
584127
  const intent = firstBriefText([
@@ -583593,37 +584131,75 @@ function buildBranchExtractionBrief(input) {
583593
584131
  ]);
583594
584132
  const openQuestion = cleanBriefText(input.trajectoryOpenQuestion, 280);
583595
584133
  const focus = openQuestion || intent;
584134
+ const goalAnchor = cleanBriefText(input.goalAnchor || input.currentStep || input.trajectoryAssessment || intent, 320);
583596
584135
  const request = openQuestion ? `Determine the exact file-local facts in ${path16} that answer this unresolved agent question: ${openQuestion}` : intent ? `Identify the exact file-local facts in ${path16} that the active agent needs before it can ${asActionClause(intent)}.` : `Identify the exact declarations, behavior, and configuration in ${path16} needed to choose the next narrow action.`;
584136
+ const rangeLabel2 = input.requestedRange ? `requested range offset=${input.requestedRange.offset ?? 1}, limit=${input.requestedRange.limit ?? "EOF"}` : "whole-file read";
584137
+ const budgetLabel = input.projectedReadTokens && input.contextWindowTokens ? ` The projected payload is ~${Math.max(0, input.projectedReadTokens)} tokens of a ${Math.max(0, input.contextWindowTokens)}-token context.` : "";
583597
584138
  const triggerEvidence = uniqueBriefLines([
583598
- `The active action is a whole-file read of ${path16}; disk inspection found ${Math.max(0, input.lineCount)} lines / ${Math.max(0, input.byteCount)} bytes, so the parent context would otherwise receive only a preview.`,
584139
+ `The active action is a ${rangeLabel2} of ${path16}; disk inspection found ${Math.max(0, input.lineCount)} lines selected / ${Math.max(0, input.byteCount)} bytes selected.${budgetLabel}`,
584140
+ input.routingReason ? `Branch routing reason: ${cleanBriefText(input.routingReason, 300)}` : "",
583599
584141
  input.trajectoryAssessment ? `Current trajectory assessment: ${cleanBriefText(input.trajectoryAssessment, 360)}` : "No current file-level evidence has been returned to the parent yet.",
583600
584142
  input.currentStep ? `Current task step: ${cleanBriefText(input.currentStep, 260)}` : "",
583601
584143
  input.recentFailure ? `Recent unresolved evidence: ${cleanBriefText(input.recentFailure, 320)}` : ""
583602
584144
  ]);
583603
584145
  const returnContract = focus ? `Return only the exact declarations, values, behavior, and line spans that resolve: ${focus}` : "Return only the exact declarations, values, behavior, and line spans needed for the next safe action.";
583604
- const retrievalQuery = uniqueBriefLines([
583605
- path16,
583606
- focus,
584146
+ const requirementQuestions = uniqueBriefLines([
583607
584147
  openQuestion,
583608
- "relevant declarations behavior configuration line spans"
584148
+ intent,
584149
+ input.currentStep && input.currentStep !== intent ? input.currentStep : "",
584150
+ input.recentFailure ? `Which file-local declaration, value, or behavior explains this unresolved failure: ${cleanBriefText(input.recentFailure, 260)}` : ""
584151
+ ]).slice(0, 3);
584152
+ if (requirementQuestions.length === 0) {
584153
+ requirementQuestions.push(`Which declarations, values, and behavior in this file are required for the next narrow action?`);
584154
+ }
584155
+ const requirements = requirementQuestions.map((question, index) => ({
584156
+ id: `R${index + 1}`,
584157
+ question,
584158
+ required: index === 0 || requirementQuestions.length === 1,
584159
+ expectedEvidence: "Exact source declarations, literal values, control/configuration behavior, and their line anchors.",
584160
+ searchTerms: queryTerms(question).slice(0, 16)
584161
+ }));
584162
+ const retrievalQuery = uniqueBriefLines([
584163
+ ...requirements.map((requirement) => requirement.question),
584164
+ input.recentFailure
583609
584165
  ]).join(" ");
584166
+ const discoveryContract = {
584167
+ version: 1,
584168
+ path: path16,
584169
+ goalAnchor: goalAnchor || "Choose the next narrow evidence-backed action.",
584170
+ query: cleanBriefText(retrievalQuery, 700),
584171
+ requirements,
584172
+ completionCriteria: [
584173
+ "Every required requirement is either supported by an exact anchored segment or explicitly marked unresolved.",
584174
+ "Every returned factual claim names its source line span; discontiguous evidence remains separate.",
584175
+ "Stop when the contract is satisfied, no new query/range is available, or the bounded search budget is exhausted."
584176
+ ],
584177
+ budget: {
584178
+ maxRounds: 3,
584179
+ maxWindowsPerRound: 3,
584180
+ maxTotalWindows: MAX_WINDOWS,
584181
+ maxPresentedLines: MAX_SNIPPET_LINES,
584182
+ maxInjectedChars: 2400
584183
+ }
584184
+ };
583610
584185
  return {
583611
584186
  request: cleanBriefText(request, 520),
583612
- triggerEvidence: triggerEvidence.slice(0, 4),
584187
+ triggerEvidence: triggerEvidence.slice(0, 5),
583613
584188
  returnContract: cleanBriefText(returnContract, 520),
583614
- retrievalQuery: cleanBriefText(retrievalQuery, 700)
584189
+ retrievalQuery: cleanBriefText(retrievalQuery, 700),
584190
+ discoveryContract
583615
584191
  };
583616
584192
  }
583617
- function buildStructuralPreview2(lines, path16, query) {
584193
+ function buildStructuralPreview2(lines, path16, query, sourceLineOffset = 0) {
583618
584194
  const n2 = lines.length;
583619
584195
  const clip3 = (l2) => l2.length > 180 ? l2.slice(0, 180) + "…" : l2;
583620
- const head = lines.slice(0, HEAD_LINES2).map((l2, i2) => `${i2 + 1}: ${clip3(l2)}`);
584196
+ const head = lines.slice(0, HEAD_LINES2).map((l2, i2) => `${sourceLineOffset + i2 + 1}: ${clip3(l2)}`);
583621
584197
  const isStructural = (l2) => /^\s*(<[A-Za-z!]|#{1,6}\s|def |class |function |export |interface |type |async |public |private |\[[^\]]+\]|[A-Za-z_][\w.]*\s*=)/.test(l2) && l2.trim().length > 0 && l2.trim().length <= 180;
583622
584198
  const markers = [];
583623
584199
  for (let i2 = HEAD_LINES2; i2 < n2; i2++) {
583624
584200
  const l2 = lines[i2];
583625
584201
  if (isStructural(l2))
583626
- markers.push(`${i2 + 1}: ${clip3(l2.trim())}`);
584202
+ markers.push(`${sourceLineOffset + i2 + 1}: ${clip3(l2.trim())}`);
583627
584203
  }
583628
584204
  const MAX_MARKERS = 30;
583629
584205
  const sampled = markers.length > MAX_MARKERS ? Array.from({ length: MAX_MARKERS }, (_, k) => markers[Math.floor(k * markers.length / MAX_MARKERS)]) : markers;
@@ -583709,7 +584285,9 @@ function selectWindows(lines, terms2) {
583709
584285
  return chosen.sort((a2, b) => a2.start - b.start).map((m2) => ({
583710
584286
  start: m2.start + 1,
583711
584287
  end: m2.end + 1,
583712
- text: lines.slice(m2.start, m2.end + 1).join("\n"),
584288
+ // A one-line minified artifact can be hundreds of KB. The branch prompt
584289
+ // is bounded independently of line count; exact source remains local.
584290
+ text: lines.slice(m2.start, m2.end + 1).map((line) => line.length > 400 ? `${line.slice(0, 400)}…` : line).join("\n"),
583713
584291
  score: m2.score
583714
584292
  }));
583715
584293
  }
@@ -583724,6 +584302,8 @@ ${w.text}`).join("\n\n");
583724
584302
  ...brief.triggerEvidence.map((evidence) => `- ${evidence}`),
583725
584303
  `Return contract: ${brief.returnContract}`,
583726
584304
  `Retrieval focus: ${brief.retrievalQuery}`,
584305
+ brief.discoveryContract ? `Discovery contract: ${JSON.stringify(brief.discoveryContract)}` : "",
584306
+ `Search-loop contract: resolve required facts from the supplied windows; if unresolved, return NEW narrow search terms. Never request or summarize the whole file.`,
583727
584307
  ``,
583728
584308
  `File excerpts:`,
583729
584309
  blocks,
@@ -583733,8 +584313,10 @@ ${w.text}`).join("\n\n");
583733
584313
  ` "source_start":<1-based line where the answer is, or null>,`,
583734
584314
  ` "source_end":<1-based end line, or null>,`,
583735
584315
  ` "confidence":0.0-1.0, // how sure the excerpts actually contain the answer`,
584316
+ ` "satisfied_requirement_ids":["R1"],`,
584317
+ ` "refined_search_terms":["new exact symbol or phrase"],`,
583736
584318
  ` "found":true|false}`
583737
- ].join("\n");
584319
+ ].filter(Boolean).join("\n");
583738
584320
  }
583739
584321
  function parseExtraction(raw) {
583740
584322
  if (!raw)
@@ -583758,127 +584340,442 @@ function parseExtraction(raw) {
583758
584340
  sourceStart: num3(o2["source_start"]),
583759
584341
  sourceEnd: num3(o2["source_end"]),
583760
584342
  confidence: Math.min(1, Math.max(0, conf)),
583761
- found: o2["found"] !== false
584343
+ found: o2["found"] !== false,
584344
+ satisfiedRequirementIds: Array.isArray(o2["satisfied_requirement_ids"]) ? o2["satisfied_requirement_ids"].map((value2) => cleanBriefText(value2, 40)).filter(Boolean).slice(0, 8) : [],
584345
+ refinedSearchTerms: Array.isArray(o2["refined_search_terms"]) ? o2["refined_search_terms"].map((value2) => cleanBriefText(value2, 80)).filter(Boolean).slice(0, 8) : []
583762
584346
  };
583763
584347
  }
584348
+ function sha2564(text2) {
584349
+ return createHash33("sha256").update(text2).digest("hex");
584350
+ }
584351
+ function lineNumberedExcerpt(lines, startIndex, endIndex, sourceLineOffset, maxLineChars = 240) {
584352
+ return lines.slice(startIndex, endIndex + 1).map((line, index) => {
584353
+ const clipped = line.length > maxLineChars ? `${line.slice(0, maxLineChars)}…` : line;
584354
+ return `${sourceLineOffset + startIndex + index + 1}: ${clipped}`;
584355
+ }).join("\n");
584356
+ }
584357
+ function rangesOverlap(a2, b) {
584358
+ return a2.startLine <= b.endLine + 1 && b.startLine <= a2.endLine + 1;
584359
+ }
584360
+ function makeSegment(input) {
584361
+ const segmentHash = sha2564(input.excerpt);
584362
+ return {
584363
+ id: `E${input.index + 1}-${segmentHash.slice(0, 10)}`,
584364
+ requirementIds: [...new Set(input.requirementIds)],
584365
+ summary: cleanBriefText(input.summary, 280),
584366
+ excerpt: input.excerpt,
584367
+ confidence: Math.min(1, Math.max(0, input.confidence)),
584368
+ anchor: {
584369
+ path: input.path,
584370
+ startLine: input.startLine,
584371
+ endLine: input.endLine,
584372
+ contentHash: input.contentHash,
584373
+ segmentHash
584374
+ }
584375
+ };
584376
+ }
584377
+ function renderSegments(segments, maxChars) {
584378
+ const blocks = [];
584379
+ let used = 0;
584380
+ for (const segment of segments) {
584381
+ const block = [
584382
+ `[${segment.id} ${segment.anchor.path}:L${segment.anchor.startLine}-L${segment.anchor.endLine} requirements=${segment.requirementIds.join(",") || "supporting"}]`,
584383
+ segment.excerpt
584384
+ ].join("\n");
584385
+ if (used + block.length > maxChars && blocks.length > 0)
584386
+ break;
584387
+ const clipped = block.slice(0, Math.max(0, maxChars - used));
584388
+ blocks.push(clipped);
584389
+ used += clipped.length + 1;
584390
+ }
584391
+ return blocks.join("\n");
584392
+ }
584393
+ function legacyContiguousSpan(segments) {
584394
+ if (segments.length === 0)
584395
+ return { start: null, end: null };
584396
+ const sorted = [...segments].sort((a2, b) => a2.anchor.startLine - b.anchor.startLine);
584397
+ for (let index = 1; index < sorted.length; index++) {
584398
+ if (sorted[index].anchor.startLine > sorted[index - 1].anchor.endLine + 1) {
584399
+ return { start: null, end: null };
584400
+ }
584401
+ }
584402
+ return {
584403
+ start: sorted[0].anchor.startLine,
584404
+ end: sorted.at(-1).anchor.endLine
584405
+ };
584406
+ }
584407
+ function requirementSearchPasses(brief) {
584408
+ const requirements = brief.discoveryContract?.requirements ?? [];
584409
+ const passes = requirements.map((requirement) => ({
584410
+ id: requirement.id,
584411
+ query: requirement.question,
584412
+ strategy: "literal"
584413
+ }));
584414
+ if (passes.length === 0 && brief.retrievalQuery) {
584415
+ passes.push({ id: "R1", query: brief.retrievalQuery, strategy: "literal" });
584416
+ }
584417
+ return passes.slice(0, brief.discoveryContract?.budget.maxRounds ?? 3);
584418
+ }
584419
+ function deterministicSegments(input) {
584420
+ const { lines, path: path16, contentHash: contentHash2, sourceLineOffset, brief } = input;
584421
+ const segments = [];
584422
+ const satisfied = /* @__PURE__ */ new Set();
584423
+ const rounds = [];
584424
+ const lowers = lines.map((line) => line.toLowerCase());
584425
+ const lineCount = Math.max(1, lines.length);
584426
+ const passes = requirementSearchPasses(brief);
584427
+ let totalMatches = 0;
584428
+ for (const pass of passes) {
584429
+ const terms2 = queryTerms(pass.query);
584430
+ const weights = /* @__PURE__ */ new Map();
584431
+ for (const term of terms2) {
584432
+ let documentFrequency = 0;
584433
+ for (const line of lowers)
584434
+ if (line.includes(term))
584435
+ documentFrequency++;
584436
+ weights.set(term, documentFrequency === 0 ? 0 : Math.log(lineCount / documentFrequency) + 0.1);
584437
+ }
584438
+ const hits = [];
584439
+ for (let index = 0; index < lines.length; index++) {
584440
+ const matched = terms2.filter((term) => lowers[index].includes(term));
584441
+ const score = matched.reduce((sum2, term) => sum2 + (weights.get(term) ?? 0), 0);
584442
+ if (score > 0)
584443
+ hits.push({ index, score, matched });
584444
+ }
584445
+ totalMatches += hits.length;
584446
+ const ranked = hits.sort((a2, b) => b.score - a2.score).slice(0, 4);
584447
+ for (const hit of ranked) {
584448
+ if (segments.length >= input.maxSegments)
584449
+ break;
584450
+ const startIndex = Math.max(0, hit.index - 2);
584451
+ const endIndex = Math.min(lines.length - 1, hit.index + 2);
584452
+ const absolute = {
584453
+ startLine: sourceLineOffset + startIndex + 1,
584454
+ endLine: sourceLineOffset + endIndex + 1
584455
+ };
584456
+ if (segments.some((segment) => rangesOverlap(segment.anchor, absolute))) {
584457
+ continue;
584458
+ }
584459
+ const discriminatingTerms = terms2.filter((term) => (weights.get(term) ?? 0) > 0);
584460
+ const coverage = discriminatingTerms.length > 0 ? hit.matched.length / discriminatingTerms.length : 0;
584461
+ const confidence2 = Math.min(1, Math.max(0.2, coverage));
584462
+ if (confidence2 < EXTRACT_CONFIDENCE_FLOOR)
584463
+ continue;
584464
+ const excerpt = lineNumberedExcerpt(lines, startIndex, endIndex, sourceLineOffset);
584465
+ segments.push(makeSegment({
584466
+ path: path16,
584467
+ contentHash: contentHash2,
584468
+ requirementIds: [pass.id],
584469
+ summary: `Literal/identifier evidence for ${pass.query}`,
584470
+ excerpt,
584471
+ startLine: absolute.startLine,
584472
+ endLine: absolute.endLine,
584473
+ confidence: confidence2,
584474
+ index: segments.length
584475
+ }));
584476
+ satisfied.add(pass.id);
584477
+ }
584478
+ }
584479
+ rounds.push({
584480
+ round: 1,
584481
+ strategy: "literal",
584482
+ query: cleanBriefText(passes.map((pass) => pass.query).join(" | "), 180),
584483
+ matches: totalMatches
584484
+ });
584485
+ return { segments, satisfied: [...satisfied], rounds };
584486
+ }
583764
584487
  async function extractEvidence(opts) {
583765
584488
  const { path: path16, content, fileVersion, backend } = opts;
584489
+ const sourceLineOffset = Math.max(0, Math.floor(opts.sourceLineOffset ?? 0));
583766
584490
  const brief = opts.brief ?? buildBranchExtractionBrief({
583767
584491
  path: path16,
583768
584492
  lineCount: content.split("\n").length,
583769
- byteCount: content.length,
584493
+ byteCount: Buffer.byteLength(content, "utf8"),
583770
584494
  assistantIntent: opts.query
583771
584495
  });
583772
584496
  const query = brief.retrievalQuery || opts.query;
583773
584497
  const lines = content.split("\n");
583774
- const terms2 = queryTerms(query);
583775
- if (terms2.length > 0) {
583776
- const lowers = lines.map((l2) => l2.toLowerCase());
583777
- const N = Math.max(1, lines.length);
583778
- const weight = /* @__PURE__ */ new Map();
583779
- for (const t2 of terms2) {
583780
- let df = 0;
583781
- for (const l2 of lowers)
583782
- if (l2.includes(t2))
583783
- df++;
583784
- weight.set(t2, df === 0 ? 0 : Math.log(N / df) + 0.1);
584498
+ const contentHash2 = opts.contentHash || sha2564(content);
584499
+ const byteCount = Buffer.byteLength(content, "utf8");
584500
+ const requirements = brief.discoveryContract?.requirements ?? [
584501
+ {
584502
+ id: "R1",
584503
+ question: query,
584504
+ required: true,
584505
+ expectedEvidence: "Anchored source evidence",
584506
+ searchTerms: queryTerms(query)
583785
584507
  }
583786
- const hits = [];
583787
- for (let i2 = 0; i2 < lines.length; i2++) {
583788
- const lower = lowers[i2];
583789
- let score = 0;
583790
- for (const t2 of terms2)
583791
- if (lower.includes(t2))
583792
- score += weight.get(t2) ?? 0;
583793
- if (score > 0)
583794
- hits.push({ idx: i2, score });
583795
- }
583796
- if (hits.length > 0) {
583797
- const CHAR_BUDGET = 900;
583798
- const ranked = [...hits].sort((a2, b) => b.score - a2.score).slice(0, 8);
583799
- const MAX_LINE = 200;
583800
- const snippets = ranked.map((h) => {
583801
- const lo = Math.max(0, h.idx - 2);
583802
- const hi = Math.min(lines.length - 1, h.idx + 2);
583803
- const text2 = lines.slice(lo, hi + 1).map((l2, k) => {
583804
- const v = l2.length > MAX_LINE ? l2.slice(0, MAX_LINE) + "…" : l2;
583805
- return `${lo + k + 1}: ${v}`;
583806
- }).join("\n");
583807
- return { score: h.score, start: lo + 1, end: hi + 1, text: text2 };
583808
- });
583809
- const kept = [];
583810
- let used = 0;
583811
- for (const s2 of snippets) {
583812
- if (used + s2.text.length + 1 > CHAR_BUDGET && kept.length > 0)
584508
+ ];
584509
+ const maxSegments = Math.max(1, Math.min(brief.discoveryContract?.budget.maxTotalWindows ?? MAX_WINDOWS, MAX_WINDOWS));
584510
+ const maxInjectedChars = Math.max(600, Math.min(brief.discoveryContract?.budget.maxInjectedChars ?? 2400, 4e3));
584511
+ const deterministic = deterministicSegments({
584512
+ lines,
584513
+ path: path16,
584514
+ contentHash: contentHash2,
584515
+ sourceLineOffset,
584516
+ brief,
584517
+ maxSegments
584518
+ });
584519
+ const requiredIds = requirements.filter((requirement) => requirement.required).map((requirement) => requirement.id);
584520
+ const deterministicSatisfied = new Set(deterministic.satisfied);
584521
+ if (deterministic.segments.length > 0 && requiredIds.every((id2) => deterministicSatisfied.has(id2))) {
584522
+ const claim = renderSegments(deterministic.segments, maxInjectedChars);
584523
+ const legacySpan = legacyContiguousSpan(deterministic.segments);
584524
+ return {
584525
+ path: path16,
584526
+ query,
584527
+ claim,
584528
+ sourceStart: legacySpan.start,
584529
+ sourceEnd: legacySpan.end,
584530
+ fileVersion,
584531
+ confidence: Math.max(...deterministic.segments.map((segment) => segment.confidence)),
584532
+ exploredLines: lines.length,
584533
+ injectedChars: claim.length,
584534
+ segments: deterministic.segments,
584535
+ satisfiedRequirementIds: [...deterministicSatisfied],
584536
+ unresolvedRequirementIds: requirements.map((requirement) => requirement.id).filter((id2) => !deterministicSatisfied.has(id2)),
584537
+ provenance: {
584538
+ contentHash: contentHash2,
584539
+ byteCount,
584540
+ lineCount: lines.length,
584541
+ fileVersion,
584542
+ exploredRanges: deterministic.segments.map((segment) => ({
584543
+ startLine: segment.anchor.startLine,
584544
+ endLine: segment.anchor.endLine
584545
+ })),
584546
+ searchRounds: deterministic.rounds,
584547
+ truncated: deterministic.segments.length >= maxSegments
584548
+ }
584549
+ };
584550
+ }
584551
+ const seenQueries = /* @__PURE__ */ new Set();
584552
+ let activeQuery = query;
584553
+ let parsed = null;
584554
+ let parsedWindows = [];
584555
+ const searchRounds = [...deterministic.rounds];
584556
+ let remainingWindows = Math.min(MAX_WINDOWS, brief.discoveryContract?.budget.maxTotalWindows ?? MAX_WINDOWS);
584557
+ let remainingPresentedLines = Math.min(MAX_SNIPPET_LINES, brief.discoveryContract?.budget.maxPresentedLines ?? MAX_SNIPPET_LINES);
584558
+ if (backend) {
584559
+ const maxSemanticRounds = Math.max(0, (brief.discoveryContract?.budget.maxRounds ?? 3) - searchRounds.length);
584560
+ for (let attempt = 0; attempt < Math.min(2, maxSemanticRounds); attempt++) {
584561
+ const queryKey = cleanBriefText(activeQuery, 700).toLowerCase();
584562
+ if (!queryKey || seenQueries.has(queryKey))
584563
+ break;
584564
+ seenQueries.add(queryKey);
584565
+ const activeTerms = queryTerms(activeQuery);
584566
+ const perRound = Math.min(remainingWindows, brief.discoveryContract?.budget.maxWindowsPerRound ?? 3);
584567
+ const selectedWindows = [];
584568
+ for (const window2 of selectWindows(lines, activeTerms)) {
584569
+ if (selectedWindows.length >= perRound)
584570
+ break;
584571
+ const windowLines = window2.end - window2.start + 1;
584572
+ if (windowLines > remainingPresentedLines)
583813
584573
  continue;
583814
- kept.push(s2);
583815
- used += s2.text.length + 1;
583816
- }
583817
- kept.sort((a2, b) => a2.start - b.start);
583818
- const claim2 = kept.map((s2) => s2.text).join("\n …\n");
583819
- const starts = kept.map((s2) => s2.start);
583820
- const ends = kept.map((s2) => s2.end);
583821
- const snippetLower = claim2.toLowerCase();
583822
- const covered = terms2.filter((t2) => snippetLower.includes(t2)).length;
583823
- const grepConfidence = Math.min(1, covered / Math.max(1, terms2.length));
583824
- if (grepConfidence >= EXTRACT_CONFIDENCE_FLOOR) {
583825
- return {
583826
- path: path16,
583827
- query,
583828
- claim: claim2,
583829
- sourceStart: starts.length ? Math.min(...starts) : null,
583830
- sourceEnd: ends.length ? Math.max(...ends) : null,
583831
- fileVersion,
583832
- confidence: grepConfidence,
583833
- exploredLines: lines.length,
583834
- injectedChars: claim2.length
583835
- };
584574
+ selectedWindows.push(window2);
584575
+ remainingPresentedLines -= windowLines;
584576
+ }
584577
+ remainingWindows -= selectedWindows.length;
584578
+ const relativeWindows = selectedWindows.map((window2) => ({
584579
+ start: window2.start + sourceLineOffset,
584580
+ end: window2.end + sourceLineOffset,
584581
+ text: window2.text
584582
+ }));
584583
+ if (relativeWindows.length === 0)
584584
+ break;
584585
+ parsedWindows = relativeWindows;
584586
+ searchRounds.push({
584587
+ round: searchRounds.length + 1,
584588
+ strategy: attempt === 0 ? "semantic" : "refined",
584589
+ query: cleanBriefText(activeQuery, 180),
584590
+ matches: relativeWindows.length
584591
+ });
584592
+ try {
584593
+ const resp = await backend.chatCompletion({
584594
+ messages: [
584595
+ {
584596
+ role: "system",
584597
+ content: "You extract precise facts from bounded file excerpts. Output ONLY a JSON object and never invent source text or line spans."
584598
+ },
584599
+ { role: "user", content: extractionPrompt(brief, path16, relativeWindows) }
584600
+ ],
584601
+ tools: [],
584602
+ temperature: 0,
584603
+ maxTokens: 900,
584604
+ timeoutMs: opts.timeoutMs ?? 3e4
584605
+ });
584606
+ parsed = parseExtraction(resp.choices?.[0]?.message?.content ?? "");
584607
+ } catch {
584608
+ parsed = null;
583836
584609
  }
584610
+ if (parsed?.found)
584611
+ break;
584612
+ const refined = uniqueBriefLines(parsed?.refinedSearchTerms ?? []).join(" ");
584613
+ if (!refined || seenQueries.has(refined.toLowerCase()))
584614
+ break;
584615
+ activeQuery = refined;
583837
584616
  }
583838
584617
  }
583839
- const windows = lines.length <= WINDOW_LINES * 2 ? [{ start: 1, end: lines.length, text: content, score: 1 }] : selectWindows(lines, terms2);
583840
- const exploredLines = windows.reduce((n2, w) => n2 + (w.end - w.start + 1), 0);
583841
- let parsed = null;
583842
- for (let attempt = 0; attempt < 2 && !parsed; attempt++) {
583843
- try {
583844
- const resp = await backend.chatCompletion({
583845
- messages: [
583846
- { role: "system", content: "You extract precise facts from file excerpts. Output ONLY a JSON object." },
583847
- { role: "user", content: extractionPrompt(brief, path16, windows) }
583848
- ],
583849
- tools: [],
583850
- temperature: 0,
583851
- maxTokens: 900,
583852
- timeoutMs: opts.timeoutMs ?? 3e4
584618
+ let semanticSegment = null;
584619
+ if (parsed?.found && parsed.claim && Number.isInteger(parsed.sourceStart) && Number.isInteger(parsed.sourceEnd) && parsed.sourceStart <= parsed.sourceEnd && parsedWindows.some((window2) => parsed.sourceStart >= window2.start && parsed.sourceEnd <= window2.end)) {
584620
+ const startIndex = parsed.sourceStart - sourceLineOffset - 1;
584621
+ const endIndex = parsed.sourceEnd - sourceLineOffset - 1;
584622
+ if (startIndex >= 0 && endIndex < lines.length) {
584623
+ semanticSegment = makeSegment({
584624
+ path: path16,
584625
+ contentHash: contentHash2,
584626
+ requirementIds: parsed.satisfiedRequirementIds.length > 0 ? parsed.satisfiedRequirementIds : [requirements[0].id],
584627
+ summary: parsed.claim,
584628
+ excerpt: lineNumberedExcerpt(lines, startIndex, endIndex, sourceLineOffset),
584629
+ startLine: parsed.sourceStart,
584630
+ endLine: parsed.sourceEnd,
584631
+ confidence: parsed.confidence,
584632
+ index: deterministic.segments.length
583853
584633
  });
583854
- parsed = parseExtraction(resp.choices?.[0]?.message?.content ?? "");
583855
- } catch {
583856
- parsed = null;
583857
584634
  }
583858
584635
  }
583859
- const claim = parsed && parsed.found && parsed.claim ? parsed.claim : buildStructuralPreview2(lines, path16, query);
584636
+ const segments = [...deterministic.segments];
584637
+ if (semanticSegment && !segments.some((segment) => rangesOverlap(segment.anchor, semanticSegment.anchor))) {
584638
+ segments.push(semanticSegment);
584639
+ }
584640
+ const satisfied = new Set(deterministic.satisfied);
584641
+ for (const segment of segments) {
584642
+ for (const id2 of segment.requirementIds)
584643
+ satisfied.add(id2);
584644
+ }
584645
+ if (segments.length > 0) {
584646
+ const claim = renderSegments(segments, maxInjectedChars);
584647
+ const legacySpan = legacyContiguousSpan(segments);
584648
+ return {
584649
+ path: path16,
584650
+ query,
584651
+ claim,
584652
+ sourceStart: legacySpan.start,
584653
+ sourceEnd: legacySpan.end,
584654
+ fileVersion,
584655
+ confidence: Math.max(...segments.map((segment) => segment.confidence)),
584656
+ exploredLines: Math.min(lines.length, parsedWindows.reduce((sum2, window2) => sum2 + (window2.end - window2.start + 1), 0) || lines.length),
584657
+ injectedChars: claim.length,
584658
+ segments,
584659
+ satisfiedRequirementIds: [...satisfied],
584660
+ unresolvedRequirementIds: requirements.map((requirement) => requirement.id).filter((id2) => !satisfied.has(id2)),
584661
+ provenance: {
584662
+ contentHash: contentHash2,
584663
+ byteCount,
584664
+ lineCount: lines.length,
584665
+ fileVersion,
584666
+ exploredRanges: segments.map((segment) => ({
584667
+ startLine: segment.anchor.startLine,
584668
+ endLine: segment.anchor.endLine
584669
+ })),
584670
+ searchRounds,
584671
+ truncated: segments.length >= maxSegments
584672
+ }
584673
+ };
584674
+ }
584675
+ const structuralClaim = buildStructuralPreview2(lines, path16, query, sourceLineOffset);
584676
+ const headEndIndex = Math.max(0, Math.min(lines.length - 1, HEAD_LINES2 - 1));
584677
+ const structuralSegment = makeSegment({
584678
+ path: path16,
584679
+ contentHash: contentHash2,
584680
+ requirementIds: [],
584681
+ summary: "Structural navigation anchor; required facts remain unresolved.",
584682
+ excerpt: lineNumberedExcerpt(lines, 0, headEndIndex, sourceLineOffset),
584683
+ startLine: sourceLineOffset + 1,
584684
+ endLine: sourceLineOffset + headEndIndex + 1,
584685
+ confidence: 0.2,
584686
+ index: 0
584687
+ });
584688
+ const maxRounds = brief.discoveryContract?.budget.maxRounds ?? 3;
584689
+ if (searchRounds.length < maxRounds) {
584690
+ searchRounds.push({
584691
+ round: searchRounds.length + 1,
584692
+ strategy: "structural",
584693
+ query: cleanBriefText(query, 180),
584694
+ matches: 1
584695
+ });
584696
+ }
583860
584697
  return {
583861
584698
  path: path16,
583862
584699
  query,
583863
- claim,
583864
- sourceStart: parsed?.sourceStart ?? null,
583865
- sourceEnd: parsed?.sourceEnd ?? null,
584700
+ claim: structuralClaim.slice(0, maxInjectedChars),
584701
+ sourceStart: structuralSegment.anchor.startLine,
584702
+ sourceEnd: structuralSegment.anchor.endLine,
583866
584703
  fileVersion,
583867
- confidence: parsed?.found ? parsed.confidence : 0.2,
583868
- exploredLines,
583869
- injectedChars: claim.length
584704
+ confidence: 0.2,
584705
+ exploredLines: Math.min(lines.length, HEAD_LINES2),
584706
+ injectedChars: Math.min(structuralClaim.length, maxInjectedChars),
584707
+ segments: [structuralSegment],
584708
+ satisfiedRequirementIds: [],
584709
+ unresolvedRequirementIds: requirements.map((requirement) => requirement.id),
584710
+ provenance: {
584711
+ contentHash: contentHash2,
584712
+ byteCount,
584713
+ lineCount: lines.length,
584714
+ fileVersion,
584715
+ exploredRanges: [
584716
+ {
584717
+ startLine: structuralSegment.anchor.startLine,
584718
+ endLine: structuralSegment.anchor.endLine
584719
+ }
584720
+ ],
584721
+ searchRounds,
584722
+ truncated: true
584723
+ }
583870
584724
  };
583871
584725
  }
583872
- function shouldBranchRead(contentLength, lineCount, hasExplicitSmallRange, thresholdChars = 8e3) {
583873
- if (hasExplicitSmallRange)
583874
- return false;
584726
+ function shouldBranchRead(contentLength, lineCount, _hasExplicitSmallRange, thresholdChars = 8e3) {
583875
584727
  return contentLength > thresholdChars || lineCount > 200;
583876
584728
  }
583877
- var WINDOW_LINES, SNIPPET_CONTEXT, HEAD_LINES2, MAX_SNIPPET_LINES, EXTRACT_CONFIDENCE_FLOOR, STOPWORDS2;
584729
+ function estimateFileReadInjectionTokens(sourceBytes, sourceLines) {
584730
+ const bytes = Math.max(0, Math.floor(sourceBytes));
584731
+ const lines = Math.max(0, Math.floor(sourceLines));
584732
+ return Math.ceil((bytes + lines * 10 + 512) / 4);
584733
+ }
584734
+ function assessBranchRead(input) {
584735
+ const projectedReadTokens = Math.max(0, Math.ceil(input.projectedReadTokens ?? estimateFileReadInjectionTokens(input.sourceBytes, input.sourceLines)));
584736
+ const contextWindowTokens = Math.max(0, Math.floor(input.contextWindowTokens));
584737
+ if (contextWindowTokens <= 0) {
584738
+ const legacy = shouldBranchRead(input.sourceBytes, input.sourceLines, false);
584739
+ return {
584740
+ branch: legacy,
584741
+ reasons: legacy ? ["legacy_size"] : [],
584742
+ projectedReadTokens,
584743
+ fractionLimitTokens: 0,
584744
+ availableHeadroomTokens: Number.POSITIVE_INFINITY,
584745
+ projectedFraction: 0,
584746
+ ...input.requestedRange ? { requestedRange: input.requestedRange } : {}
584747
+ };
584748
+ }
584749
+ const fraction = Math.min(0.9, Math.max(0.01, input.maxInlineFraction ?? DEFAULT_BRANCH_READ_CONTEXT_FRACTION));
584750
+ const fractionLimitTokens = Math.floor(contextWindowTokens * fraction);
584751
+ const resident = Math.max(0, Math.ceil(input.residentContextTokens ?? 0));
584752
+ const reserved = Math.max(0, Math.ceil(input.reservedTokens ?? 0));
584753
+ const pending2 = Math.max(0, Math.ceil(input.pendingInlineReadTokens ?? 0));
584754
+ const safeCeiling = Math.max(0, Math.min(contextWindowTokens, Math.floor(input.safeContextTokens ?? contextWindowTokens)));
584755
+ const availableHeadroomTokens = Math.max(0, safeCeiling - resident - reserved - pending2);
584756
+ const reasons = [];
584757
+ if (projectedReadTokens > fractionLimitTokens)
584758
+ reasons.push("read_fraction");
584759
+ if (projectedReadTokens > availableHeadroomTokens)
584760
+ reasons.push("headroom");
584761
+ if (pending2 > 0 && pending2 + projectedReadTokens > fractionLimitTokens) {
584762
+ reasons.push("batch_budget");
584763
+ }
584764
+ return {
584765
+ branch: reasons.length > 0,
584766
+ reasons: [...new Set(reasons)],
584767
+ projectedReadTokens,
584768
+ fractionLimitTokens,
584769
+ availableHeadroomTokens,
584770
+ projectedFraction: projectedReadTokens / contextWindowTokens,
584771
+ ...input.requestedRange ? { requestedRange: input.requestedRange } : {}
584772
+ };
584773
+ }
584774
+ var MAX_WINDOWS, SNIPPET_CONTEXT, HEAD_LINES2, MAX_SNIPPET_LINES, EXTRACT_CONFIDENCE_FLOOR, STOPWORDS2, DEFAULT_BRANCH_READ_CONTEXT_FRACTION;
583878
584775
  var init_evidenceBranch = __esm({
583879
584776
  "packages/orchestrator/dist/evidenceBranch.js"() {
583880
584777
  "use strict";
583881
- WINDOW_LINES = 40;
584778
+ MAX_WINDOWS = 6;
583882
584779
  SNIPPET_CONTEXT = 4;
583883
584780
  HEAD_LINES2 = 10;
583884
584781
  MAX_SNIPPET_LINES = 220;
@@ -583916,6 +584813,7 @@ var init_evidenceBranch = __esm({
583916
584813
  "report",
583917
584814
  "tell"
583918
584815
  ]);
584816
+ DEFAULT_BRANCH_READ_CONTEXT_FRACTION = 0.2;
583919
584817
  }
583920
584818
  });
583921
584819
 
@@ -584338,7 +585236,7 @@ var init_prompt_cache = __esm({
584338
585236
 
584339
585237
  // packages/orchestrator/dist/git-progress.js
584340
585238
  import { existsSync as existsSync104, readFileSync as readFileSync80, statSync as statSync41 } from "node:fs";
584341
- import { createHash as createHash33 } from "node:crypto";
585239
+ import { createHash as createHash34 } from "node:crypto";
584342
585240
  import { relative as relative13, resolve as resolve56, sep as sep4 } from "node:path";
584343
585241
  function isRunnerOwnedGitPath(path16) {
584344
585242
  const normalized = normalizeGitPath(path16);
@@ -584365,7 +585263,7 @@ function pathHash(repoRoot, relPath) {
584365
585263
  const st = statSync41(absolute);
584366
585264
  if (!st.isFile())
584367
585265
  return `non-file:${st.size}:${Math.floor(st.mtimeMs)}`;
584368
- return createHash33("sha256").update(readFileSync80(absolute)).digest("hex");
585266
+ return createHash34("sha256").update(readFileSync80(absolute)).digest("hex");
584369
585267
  } catch {
584370
585268
  return void 0;
584371
585269
  }
@@ -585265,7 +586163,7 @@ __export(preflightSnapshot_exports, {
585265
586163
  import { existsSync as existsSync105, readFileSync as readFileSync81, statSync as statSync42, statfsSync as statfsSync6 } from "node:fs";
585266
586164
  import { homedir as homedir36, platform as platform4, arch as arch2, totalmem as totalmem4, freemem as freemem3, hostname as hostname3 } from "node:os";
585267
586165
  import { join as join113 } from "node:path";
585268
- import { createHash as createHash34 } from "node:crypto";
586166
+ import { createHash as createHash35 } from "node:crypto";
585269
586167
  function capturePreflightSnapshot(workingDir) {
585270
586168
  const warnings = [];
585271
586169
  const configFingerprints = {};
@@ -585279,7 +586177,7 @@ function capturePreflightSnapshot(workingDir) {
585279
586177
  } catch {
585280
586178
  continue;
585281
586179
  }
585282
- configFingerprints[det.path] = sha2564(raw);
586180
+ configFingerprints[det.path] = sha2565(raw);
585283
586181
  for (const w of det.check(raw)) {
585284
586182
  warnings.push({ ...w, source: expanded });
585285
586183
  }
@@ -585297,7 +586195,7 @@ function capturePreflightSnapshot(workingDir) {
585297
586195
  } catch {
585298
586196
  continue;
585299
586197
  }
585300
- configFingerprints[`<cwd>/${localName}`] = sha2564(raw);
586198
+ configFingerprints[`<cwd>/${localName}`] = sha2565(raw);
585301
586199
  for (const w of det.check(raw)) {
585302
586200
  warnings.push({ ...w, source: projectPath });
585303
586201
  }
@@ -585433,8 +586331,8 @@ function expandPath(p2) {
585433
586331
  return join113(homedir36(), p2.slice(2));
585434
586332
  return p2;
585435
586333
  }
585436
- function sha2564(s2) {
585437
- return createHash34("sha256").update(s2).digest("hex").slice(0, 16);
586334
+ function sha2565(s2) {
586335
+ return createHash35("sha256").update(s2).digest("hex").slice(0, 16);
585438
586336
  }
585439
586337
  function freeDiskBytes(path16 = "/tmp") {
585440
586338
  try {
@@ -586048,7 +586946,7 @@ function formatStagnantLine(c9, critical) {
586048
586946
  const tag = critical ? "STAGNANT-CRIT" : "STAGNANT";
586049
586947
  return `${tag}: ${shortFile(c9.key.file)} ${c9.count}${codeLabel} unchanged across ${c9.attemptsSinceCountChange} attempts — per-line edits aren't converging; consider reverting the affected region or rewriting it as a unit`;
586050
586948
  }
586051
- var ERROR_PATTERNS, DEFAULTS2, ErrorClusterTracker;
586949
+ var ERROR_PATTERNS, DEFAULTS3, ErrorClusterTracker;
586052
586950
  var init_errorClusterTracker = __esm({
586053
586951
  "packages/orchestrator/dist/errorClusterTracker.js"() {
586054
586952
  "use strict";
@@ -586161,7 +587059,7 @@ RECOVERY: cd to the directory containing '${file}', run a plain install with no
586161
587059
  }
586162
587060
  }
586163
587061
  ];
586164
- DEFAULTS2 = {
587062
+ DEFAULTS3 = {
586165
587063
  warnAttempts: 3,
586166
587064
  criticalAttempts: 5,
586167
587065
  cooldownAttempts: 2,
@@ -586175,7 +587073,7 @@ RECOVERY: cd to the directory containing '${file}', run a plain install with no
586175
587073
  // key → observations counter at last emit
586176
587074
  observationCounter = 0;
586177
587075
  constructor(options2 = {}) {
586178
- this.opts = { ...DEFAULTS2, ...options2 };
587076
+ this.opts = { ...DEFAULTS3, ...options2 };
586179
587077
  this.now = options2.now ?? Date.now;
586180
587078
  }
586181
587079
  /**
@@ -587104,6 +588002,7 @@ var init_agenticRunner = __esm({
587104
588002
  "use strict";
587105
588003
  init_contextBudget();
587106
588004
  init_textSanitize();
588005
+ init_text_echo_guard();
587107
588006
  init_permissionRuleset();
587108
588007
  init_steeringIntake();
587109
588008
  init_completionLedger();
@@ -587157,6 +588056,7 @@ var init_agenticRunner = __esm({
587157
588056
  init_context_fabric();
587158
588057
  init_context_compiler();
587159
588058
  init_evidenceLedger();
588059
+ init_observationLedger();
587160
588060
  init_trajectory_checkpoint();
587161
588061
  init_adversaryStream();
587162
588062
  init_contextWindowDump();
@@ -587480,6 +588380,23 @@ var init_agenticRunner = __esm({
587480
588380
  // Loop Intervention escalation path. Reset when repetition score
587481
588381
  // drops below the recovery threshold (0.2).
587482
588382
  _smaFiredThisLoop = false;
588383
+ // ROOT CAUSE FIX: one-shot system note describing restored-todo claims that
588384
+ // were contradicted by the disk at session start. Injected into the initial
588385
+ // context so the model starts from a truthful world model instead of
588386
+ // discovering the contradiction through failed discovery loops.
588387
+ _restoredTodoVerificationNote = null;
588388
+ // ECHO-1: assistant text-echo guard (mode-collapse breaker). Every other
588389
+ // loop defense keys off the tool-call log; this one detects the tool-free
588390
+ // failure mode where the model restates the same text-only plan turn after
588391
+ // turn (personaplex post-mortem: consecutive assistant messages at
588392
+ // 0.77–1.00 similarity, zero tool calls). Detects echoes, collapses the
588393
+ // earlier duplicates out of the live context (removing the attractor), and
588394
+ // requests a one-shot sampling perturbation for the next completion.
588395
+ _textEchoGuard = new TextEchoGuard();
588396
+ // Turns remaining with a temperature floor applied to knock a greedy
588397
+ // decoder off a repetition attractor. Set on echo detection; decremented
588398
+ // when a request is built.
588399
+ _echoTempBoostTurns = 0;
587483
588400
  // REG-50: same-file write-thrash detector cooldown. Once fired, give
587484
588401
  // the agent 8 turns to break out before re-firing. Distinct from REG-44
587485
588402
  // because the failure shape is different (writes >> reads, but stuck
@@ -587729,6 +588646,18 @@ var init_agenticRunner = __esm({
587729
588646
  // sees the evidence it already has instead of re-deriving it. See
587730
588647
  // evidenceLedger.ts.
587731
588648
  _evidenceLedger = new EvidenceLedger();
588649
+ /**
588650
+ * Curated branch nodes keyed by source hash + discovery contract. Raw source
588651
+ * is deliberately absent so retries/compaction cannot rehydrate it.
588652
+ */
588653
+ _branchEvidenceCache = /* @__PURE__ */ new Map();
588654
+ /** Latest curated node per canonical path for safe post-compaction recovery. */
588655
+ _branchEvidenceByPath = /* @__PURE__ */ new Map();
588656
+ // OBS-1: durable "current observed state" for non-file_read tool outputs
588657
+ // (shell/web_fetch/list_directory/…). EvidenceLedger's counterpart for the
588658
+ // observation channels that were previously invisible after compaction —
588659
+ // the model must see the raw outputs it is reasoning about, every turn.
588660
+ _observationLedger = new ObservationLedger();
587732
588661
  // Generative, inference-driven adversary running as an async memory stream
587733
588662
  // adjacent to the main loop. Initialized per run when the step critic is
587734
588663
  // enabled and a backend is available. See adversaryStream.ts.
@@ -594276,6 +595205,7 @@ ${String(concreteGoal).replace(/\s+/g, " ").trim().slice(0, 1200)}` : null
594276
595205
  ].filter((block) => Boolean(block)));
594277
595206
  const trajectoryBlock = this.options.trajectoryCheckpoint === "shadow" ? null : trajectoryCheckpoint ? renderTrajectoryCheckpoint(trajectoryCheckpoint) : null;
594278
595207
  const toolCacheBlock = recentToolResults ? this._renderKnowledgeBlock(recentToolResults) : null;
595208
+ const observationBlock = process.env["OMNIUS_DISABLE_OBSERVATION_FRAME"] === "1" ? null : this._observationLedger.renderBlock(5e3);
594279
595209
  const anchorsBlock = this.surfaceAnchors(messages2);
594280
595210
  const pprMemoryBlock = this._lastPprMemoryLines.length > 0 ? `[Associative Memory - related prior experience]
594281
595211
  ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
@@ -594400,6 +595330,19 @@ ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
594400
595330
  createdTurn: turn,
594401
595331
  ttlTurns: 1
594402
595332
  }),
595333
+ // OBS-1: current observed state — the actual latest OUTPUT of each
595334
+ // distinct non-file_read tool call. Higher priority than the names-only
595335
+ // tool cache: the substance of what tools returned is more decision-
595336
+ // relevant than the list of what ran. Survives compaction because it is
595337
+ // regenerated from the ledger every turn.
595338
+ signalFromBlock("tool_cache", "turn.observed-state", observationBlock, {
595339
+ id: "observed-state",
595340
+ dedupeKey: "turn.observed-state",
595341
+ semanticKey: "context.observed-state",
595342
+ priority: 94,
595343
+ createdTurn: turn,
595344
+ ttlTurns: 1
595345
+ }),
594403
595346
  signalFromBlock("memory", "turn.ppr-memory", pprMemoryBlock, {
594404
595347
  id: "ppr-memory",
594405
595348
  dedupeKey: "turn.ppr-memory",
@@ -595563,7 +596506,31 @@ Rewrite it now for ${ctx3.model}.`;
595563
596506
  };
595564
596507
  }
595565
596508
  try {
595566
- const result = await tool.execute(args);
596509
+ const callId = `runTool:${resolved.name}:${Date.now()}:${Math.random()}`;
596510
+ const batchBudget = {
596511
+ inlineTokens: 0,
596512
+ reservations: /* @__PURE__ */ new Map()
596513
+ };
596514
+ const preempted = await this._preemptFileReadWithBranch({
596515
+ callId,
596516
+ toolName: resolved.name,
596517
+ args,
596518
+ messages: [],
596519
+ turn: this._taskState.toolCallCount,
596520
+ batchBudget
596521
+ });
596522
+ if (preempted)
596523
+ return preempted;
596524
+ let result = await tool.execute(args);
596525
+ result = await this._guardMaterializedFileReadResult({
596526
+ callId,
596527
+ toolName: resolved.name,
596528
+ args,
596529
+ result,
596530
+ messages: [],
596531
+ turn: this._taskState.toolCallCount,
596532
+ batchBudget
596533
+ });
595567
596534
  return this.applyRegisteredToolResultTriage(result, resolved.name, tool);
595568
596535
  } catch (e2) {
595569
596536
  return { success: false, output: "", error: e2?.message || String(e2) };
@@ -595788,8 +596755,309 @@ ${notice}`;
595788
596755
  trajectoryNextAction: trajectory?.nextAction || this._taskState.nextAction,
595789
596756
  trajectoryOpenQuestion: trajectory?.openQuestions[0],
595790
596757
  currentStep: this._taskState.currentStep,
595791
- recentFailure
596758
+ recentFailure,
596759
+ goalAnchor: trajectory?.currentStep || this._taskState.currentStep || this._taskState.nextAction,
596760
+ requestedRange: input.requestedRange,
596761
+ projectedReadTokens: input.routingDecision?.projectedReadTokens,
596762
+ contextWindowTokens: this._branchRoutingContextWindow(),
596763
+ routingReason: input.routingDecision?.reasons.join(", ")
596764
+ });
596765
+ }
596766
+ /** The usable total window for mandatory read routing. */
596767
+ _branchRoutingContextWindow() {
596768
+ const declared = Math.max(0, this.options.contextWindowSize ?? 0);
596769
+ const effective = Math.max(0, this.effectiveContextWindow());
596770
+ if (declared > 0 && effective > 0)
596771
+ return Math.min(declared, effective);
596772
+ return declared || effective;
596773
+ }
596774
+ _branchReadReservedTokens(contextWindow) {
596775
+ if (contextWindow <= 0)
596776
+ return 0;
596777
+ const generation = Math.min(this.contextLimits().maxOutputTokens, Math.max(1024, Math.floor(contextWindow * 0.15)));
596778
+ return generation + Math.max(512, Math.floor(contextWindow * 0.05));
596779
+ }
596780
+ _branchReadPath(args) {
596781
+ for (const key of ["path", "file", "file_path", "filename", "filepath"]) {
596782
+ const value2 = args[key];
596783
+ if (typeof value2 === "string" && value2.trim())
596784
+ return value2.trim();
596785
+ }
596786
+ return "";
596787
+ }
596788
+ /** Content identity used to prove an exact local read is still unchanged. */
596789
+ _fileReadDiskIdentity(args) {
596790
+ const path16 = this._branchReadPath(args);
596791
+ if (!path16)
596792
+ return null;
596793
+ try {
596794
+ const absolutePath = this._absoluteToolPath(path16);
596795
+ const stat9 = _fsStatSync(absolutePath);
596796
+ if (!stat9.isFile())
596797
+ return null;
596798
+ const content = _fsReadFileSync(absolutePath, "utf8");
596799
+ return {
596800
+ path: path16,
596801
+ canonicalPath: this._normalizeEvidencePath(path16),
596802
+ contentHash: _createHash("sha256").update(content).digest("hex"),
596803
+ byteCount: stat9.size,
596804
+ mtimeMs: stat9.mtimeMs
596805
+ };
596806
+ } catch {
596807
+ return null;
596808
+ }
596809
+ }
596810
+ /**
596811
+ * Mandatory pre-dispatch router for local file reads. It resolves exactly
596812
+ * once against the authoritative run directory, computes the actual selected
596813
+ * range, and intercepts unsafe reads before registered tool code or any
596814
+ * transcript/evidence consumer can observe raw content.
596815
+ */
596816
+ async _preemptFileReadWithBranch(input) {
596817
+ if (this.lookupRegisteredTool(input.toolName)?.name !== "file_read") {
596818
+ return null;
596819
+ }
596820
+ const rawPath = this._branchReadPath(input.args);
596821
+ if (!rawPath)
596822
+ return null;
596823
+ let fullContent;
596824
+ let stat9;
596825
+ let absolutePath;
596826
+ try {
596827
+ absolutePath = this._absoluteToolPath(rawPath);
596828
+ stat9 = _fsStatSync(absolutePath);
596829
+ if (!stat9.isFile())
596830
+ return null;
596831
+ fullContent = _fsReadFileSync(absolutePath, "utf8");
596832
+ } catch {
596833
+ return null;
596834
+ }
596835
+ const allLines = fullContent.split("\n");
596836
+ const rawOffset = input.args["offset"];
596837
+ const rawLimit = input.args["limit"];
596838
+ const hasRange = typeof rawOffset === "number" || typeof rawLimit === "number";
596839
+ const offset = typeof rawOffset === "number" && Number.isFinite(rawOffset) ? Math.max(1, Math.floor(rawOffset)) : void 0;
596840
+ const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.max(0, Math.floor(rawLimit)) : void 0;
596841
+ const startIndex = hasRange ? Math.max(0, (offset ?? 1) - 1) : 0;
596842
+ const selectedLines = hasRange ? allLines.slice(startIndex, limit === void 0 ? void 0 : startIndex + limit) : allLines;
596843
+ const selectedContent = selectedLines.join("\n");
596844
+ const selectedBytes = Buffer.byteLength(selectedContent, "utf8");
596845
+ const contextWindow = this._branchRoutingContextWindow();
596846
+ const residentTokens = estimateMessagesTokens2(input.messages);
596847
+ const reservedTokens = this._branchReadReservedTokens(contextWindow);
596848
+ const decision2 = assessBranchRead({
596849
+ sourceBytes: selectedBytes,
596850
+ sourceLines: selectedLines.length,
596851
+ contextWindowTokens: contextWindow,
596852
+ residentContextTokens: residentTokens,
596853
+ reservedTokens,
596854
+ pendingInlineReadTokens: input.batchBudget.inlineTokens,
596855
+ safeContextTokens: this.contextLimits().compactionThreshold,
596856
+ ...hasRange ? { requestedRange: { offset, limit } } : {}
596857
+ });
596858
+ if (!decision2.branch) {
596859
+ input.batchBudget.inlineTokens += decision2.projectedReadTokens;
596860
+ input.batchBudget.reservations.set(input.callId, decision2.projectedReadTokens);
596861
+ return null;
596862
+ }
596863
+ const fullHash = _createHash("sha256").update(fullContent).digest("hex");
596864
+ const branchBrief = this._buildBranchExtractionBrief({
596865
+ path: rawPath,
596866
+ lineCount: selectedLines.length,
596867
+ byteCount: selectedBytes,
596868
+ messages: input.messages,
596869
+ ...hasRange ? { requestedRange: { offset, limit } } : {},
596870
+ routingDecision: decision2
596871
+ });
596872
+ const contractFingerprint = _createHash("sha256").update(JSON.stringify(branchBrief.discoveryContract ?? branchBrief)).digest("hex").slice(0, 20);
596873
+ const canonicalPath = this._normalizeEvidencePath(rawPath);
596874
+ const cacheKey = `${canonicalPath}|${fullHash}|${offset ?? 0}:${limit ?? "EOF"}|${contractFingerprint}`;
596875
+ const cached = this._branchEvidenceCache.get(cacheKey);
596876
+ if (cached) {
596877
+ const duplicateBlocked = [
596878
+ `[BRANCH-DUPLICATE-BLOCKED] path=${rawPath} sha256=${fullHash} contract=${contractFingerprint}`,
596879
+ `The unchanged source was already branch-extracted into the current evidence ledger; the registered file_read was not executed and raw content was not re-injected.`,
596880
+ `Use the existing curated anchors. If a required discovery is unresolved, issue one narrower grep_search or a range whose projected payload stays below the 20% limit; otherwise take the next task action.`
596881
+ ].join("\n");
596882
+ this.emit({
596883
+ type: "status",
596884
+ toolName: input.toolName,
596885
+ content: `Branch-extract cache hit: ${rawPath} sha256=${fullHash.slice(0, 12)} contract=${contractFingerprint}`,
596886
+ turn: input.turn,
596887
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
596888
+ });
596889
+ return {
596890
+ success: true,
596891
+ output: duplicateBlocked,
596892
+ llmContent: duplicateBlocked,
596893
+ beforeHash: fullHash,
596894
+ runtimeAuthored: true,
596895
+ noop: true,
596896
+ completionEvidenceMetrics: {
596897
+ branchSourceBytes: cached.sourceBytes,
596898
+ branchCacheHit: true
596899
+ }
596900
+ };
596901
+ }
596902
+ const extractionBackend = process.env["OMNIUS_DISABLE_BRANCH_EXTRACT"] === "1" ? void 0 : this._auxInferenceBackend();
596903
+ const ev = await extractEvidence({
596904
+ path: rawPath,
596905
+ query: branchBrief.retrievalQuery,
596906
+ brief: branchBrief,
596907
+ content: selectedContent,
596908
+ contentHash: fullHash,
596909
+ sourceLineOffset: startIndex,
596910
+ fileVersion: this._worldFacts.files.get(rawPath)?.writeCount ?? 0,
596911
+ backend: extractionBackend,
596912
+ timeoutMs: 3e4
596913
+ });
596914
+ const verboseOutput = [
596915
+ `[BRANCH-EXTRACT v2] path=${rawPath}`,
596916
+ `routing=mandatory reasons=${decision2.reasons.join(",")} projected_read_tokens=${decision2.projectedReadTokens} fraction_limit_tokens=${decision2.fractionLimitTokens} available_headroom_tokens=${decision2.availableHeadroomTokens}`,
596917
+ `source=sha256:${fullHash} selected_lines=${selectedLines.length} selected_bytes=${selectedBytes}${hasRange ? ` range=${offset ?? 1}:${limit ?? "EOF"}` : " range=whole"}`,
596918
+ `[DISCOVERY CONTRACT]`,
596919
+ `Goal anchor: ${branchBrief.discoveryContract?.goalAnchor ?? this._taskState.currentStep}`,
596920
+ `Request: ${branchBrief.request}`,
596921
+ `Required discoveries:`,
596922
+ ...(branchBrief.discoveryContract?.requirements ?? []).map((requirement) => `- ${requirement.id}${requirement.required ? " [required]" : ""}: ${requirement.question}`),
596923
+ `Stop conditions: ${(branchBrief.discoveryContract?.completionCriteria ?? []).join(" | ")}`,
596924
+ `[CURATED SEGMENTS]`,
596925
+ ev.claim,
596926
+ `satisfied=${ev.satisfiedRequirementIds.join(",") || "none"}`,
596927
+ `unresolved=${ev.unresolvedRequirementIds.join(",") || "none"}`,
596928
+ `provenance=content:${ev.provenance.contentHash} searches:${ev.provenance.searchRounds.length} ranges:${ev.provenance.exploredRanges.map((range) => `L${range.startLine}-L${range.endLine}`).join(",")}`,
596929
+ `Contract: use these anchors as evidence. If a required item remains unresolved, issue one narrow grep_search or bounded file_read for that item; never re-read the whole file or expand a range past the 20% budget.`
596930
+ ].join("\n");
596931
+ const outputBudgetChars = Math.max(800, decision2.fractionLimitTokens * 4);
596932
+ let output = verboseOutput;
596933
+ if (verboseOutput.length > outputBudgetChars) {
596934
+ const required = (branchBrief.discoveryContract?.requirements ?? []).filter((requirement) => requirement.required).map((requirement) => `${requirement.id}:${requirement.question.slice(0, 180)}`).join(" | ");
596935
+ const prefix = [
596936
+ `[BRANCH-EXTRACT v2] path=${rawPath} sha256=${fullHash}`,
596937
+ `routing=${decision2.reasons.join(",")} projected=${decision2.projectedReadTokens}/${contextWindow}t limit=${decision2.fractionLimitTokens}t`,
596938
+ `[DISCOVERY CONTRACT] required=${required || "next narrow file-local fact"}`,
596939
+ `[CURATED SEGMENTS]`
596940
+ ].join("\n");
596941
+ const suffix = [
596942
+ `unresolved=${ev.unresolvedRequirementIds.join(",") || "none"}`,
596943
+ `anchors=${ev.provenance.exploredRanges.map((range) => `L${range.startLine}-L${range.endLine}`).join(",")}`,
596944
+ `Do not whole-read again; act on these anchors or issue one narrower search.`
596945
+ ].join("\n");
596946
+ const claimBudget = Math.max(120, outputBudgetChars - prefix.length - suffix.length - 2);
596947
+ output = `${prefix}
596948
+ ${ev.claim.slice(0, claimBudget)}
596949
+ ${suffix}`.slice(0, outputBudgetChars);
596950
+ }
596951
+ this._branchEvidenceCache.set(cacheKey, {
596952
+ output,
596953
+ path: canonicalPath,
596954
+ contentHash: fullHash,
596955
+ sourceBytes: stat9.size,
596956
+ createdAt: Date.now()
596957
+ });
596958
+ this._branchEvidenceByPath.set(canonicalPath, {
596959
+ output,
596960
+ contentHash: fullHash,
596961
+ mtimeMs: stat9.mtimeMs
595792
596962
  });
596963
+ this.emit({
596964
+ type: "status",
596965
+ toolName: input.toolName,
596966
+ content: `Branch-extract preempted ${rawPath}: ${decision2.projectedReadTokens}/${contextWindow} projected tokens (${(decision2.projectedFraction * 100).toFixed(1)}%); resident=${residentTokens}t reserve=${reservedTokens}t pending_reads=${input.batchBudget.inlineTokens}t; ${selectedBytes}B → ${output.length} curated chars; reasons=${decision2.reasons.join(",")}`,
596967
+ turn: input.turn,
596968
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
596969
+ });
596970
+ return {
596971
+ success: true,
596972
+ output,
596973
+ llmContent: output,
596974
+ beforeHash: fullHash,
596975
+ runtimeAuthored: true,
596976
+ mutated: false,
596977
+ mutatedFiles: [],
596978
+ completionEvidenceMetrics: {
596979
+ branchSourceBytes: stat9.size,
596980
+ branchSelectedBytes: selectedBytes,
596981
+ branchProjectedTokens: decision2.projectedReadTokens
596982
+ }
596983
+ };
596984
+ }
596985
+ /** Fail-safe for virtual/custom file_read tools that cannot be statted locally. */
596986
+ async _guardMaterializedFileReadResult(input) {
596987
+ if (this.lookupRegisteredTool(input.toolName)?.name !== "file_read") {
596988
+ return input.result;
596989
+ }
596990
+ const reservedForThisCall = input.batchBudget.reservations.get(input.callId) ?? 0;
596991
+ if (!input.result.success) {
596992
+ if (reservedForThisCall > 0) {
596993
+ input.batchBudget.inlineTokens = Math.max(0, input.batchBudget.inlineTokens - reservedForThisCall);
596994
+ input.batchBudget.reservations.delete(input.callId);
596995
+ }
596996
+ return input.result;
596997
+ }
596998
+ if (!input.result.output)
596999
+ return input.result;
597000
+ const lines = input.result.output.split("\n");
597001
+ const contextWindow = this._branchRoutingContextWindow();
597002
+ const decision2 = assessBranchRead({
597003
+ sourceBytes: Buffer.byteLength(input.result.output, "utf8"),
597004
+ sourceLines: lines.length,
597005
+ contextWindowTokens: contextWindow,
597006
+ residentContextTokens: estimateMessagesTokens2(input.messages),
597007
+ reservedTokens: this._branchReadReservedTokens(contextWindow),
597008
+ pendingInlineReadTokens: Math.max(0, input.batchBudget.inlineTokens - reservedForThisCall),
597009
+ safeContextTokens: this.contextLimits().compactionThreshold
597010
+ });
597011
+ if (!decision2.branch) {
597012
+ if (reservedForThisCall === 0) {
597013
+ input.batchBudget.inlineTokens += decision2.projectedReadTokens;
597014
+ input.batchBudget.reservations.set(input.callId, decision2.projectedReadTokens);
597015
+ }
597016
+ return input.result;
597017
+ }
597018
+ if (reservedForThisCall > 0) {
597019
+ input.batchBudget.inlineTokens = Math.max(0, input.batchBudget.inlineTokens - reservedForThisCall);
597020
+ input.batchBudget.reservations.delete(input.callId);
597021
+ }
597022
+ const path16 = this._branchReadPath(input.args) || "virtual:file_read";
597023
+ const brief = this._buildBranchExtractionBrief({
597024
+ path: path16,
597025
+ lineCount: lines.length,
597026
+ byteCount: Buffer.byteLength(input.result.output, "utf8"),
597027
+ messages: input.messages,
597028
+ routingDecision: decision2
597029
+ });
597030
+ const ev = await extractEvidence({
597031
+ path: path16,
597032
+ query: brief.retrievalQuery,
597033
+ brief,
597034
+ content: input.result.output,
597035
+ fileVersion: 0,
597036
+ backend: process.env["OMNIUS_DISABLE_BRANCH_EXTRACT"] === "1" ? void 0 : this._auxInferenceBackend(),
597037
+ timeoutMs: 3e4
597038
+ });
597039
+ const output = [
597040
+ `[BRANCH-EXTRACT v2] path=${path16}`,
597041
+ `routing=post-execution-failsafe reasons=${decision2.reasons.join(",")} projected_read_tokens=${decision2.projectedReadTokens}`,
597042
+ `[DISCOVERY CONTRACT] ${brief.request}`,
597043
+ `[CURATED SEGMENTS]`,
597044
+ ev.claim,
597045
+ `unresolved=${ev.unresolvedRequirementIds.join(",") || "none"}`,
597046
+ `provenance=content:${ev.provenance.contentHash} ranges:${ev.provenance.exploredRanges.map((range) => `L${range.startLine}-L${range.endLine}`).join(",")}`
597047
+ ].join("\n").slice(0, Math.max(800, decision2.fractionLimitTokens * 4));
597048
+ return {
597049
+ ...input.result,
597050
+ output,
597051
+ llmContent: output,
597052
+ beforeHash: input.result.beforeHash ?? ev.provenance.contentHash,
597053
+ runtimeAuthored: true,
597054
+ completionEvidenceMetrics: {
597055
+ ...input.result.completionEvidenceMetrics,
597056
+ branchSourceBytes: Buffer.byteLength(input.result.output, "utf8"),
597057
+ branchSelectedBytes: Buffer.byteLength(input.result.output, "utf8"),
597058
+ branchProjectedTokens: decision2.projectedReadTokens
597059
+ }
597060
+ };
595793
597061
  }
595794
597062
  /**
595795
597063
  * Build a child-task request from the live parent state. This is the common
@@ -596448,6 +597716,7 @@ Respond with the assessment and take the selected evidence-backed action.`;
596448
597716
  this._lastSurfacedAnchorIds.clear();
596449
597717
  this._contextLedger = new ContextLedger();
596450
597718
  this._evidenceLedger = new EvidenceLedger();
597719
+ this._observationLedger = new ObservationLedger();
596451
597720
  this._lastContextFrameDiagnostics = null;
596452
597721
  this._lastContextPressureSnapshot = null;
596453
597722
  this._lastFocusContextSnapshot = null;
@@ -596613,6 +597882,45 @@ Respond with the assessment and take the selected evidence-backed action.`;
596613
597882
  verbose: false
596614
597883
  });
596615
597884
  await this._initializeGitProgressBaseline();
597885
+ this._restoredTodoVerificationNote = null;
597886
+ try {
597887
+ const restored = process.env["OMNIUS_DISABLE_RESTORED_TODO_VERIFY"] === "1" ? null : this.readSessionTodos();
597888
+ if (restored && restored.length > 0) {
597889
+ const verification = reconcileRestoredTodosWithDisk({
597890
+ todos: restored,
597891
+ workingDir: this.authoritativeWorkingDirectory(),
597892
+ exists: (p2) => _fsExistsSync(p2),
597893
+ resolvePath: (...segments) => _pathResolve(...segments)
597894
+ });
597895
+ if (verification.changed) {
597896
+ writeTodos(this._sessionId, verification.todos.map((t2) => ({
597897
+ id: t2.id,
597898
+ content: t2.content,
597899
+ status: t2.status,
597900
+ parentId: t2.parentId,
597901
+ blocker: t2.blocker,
597902
+ verifyCommand: t2.verifyCommand,
597903
+ declaredArtifacts: t2.declaredArtifacts
597904
+ })));
597905
+ const lines = verification.downgrades.slice(0, 6).map((d2) => `- "${d2.content.slice(0, 90)}": ${d2.from} -> ${d2.to} (${d2.evidence})`);
597906
+ if (verification.downgrades.length > 0) {
597907
+ this._restoredTodoVerificationNote = [
597908
+ `[RESTORED TODO VERIFICATION]`,
597909
+ `This session restored a todo list from a prior run. ${verification.downgrades.length} completed claim(s) were contradicted by the local disk and downgraded:`,
597910
+ ...lines,
597911
+ ``,
597912
+ `The referenced artifacts do NOT exist in this workspace. Do not search for them — the correct next action is to CREATE them (file_write / shell mkdir) or re-plan from the actual disk state.`
597913
+ ].join("\n");
597914
+ }
597915
+ this.emit({
597916
+ type: "status",
597917
+ content: `Restored-todo disk verification: ${verification.downgrades.length} claim(s) downgraded, ${verification.droppedCorrupt} corrupt entr${verification.droppedCorrupt === 1 ? "y" : "ies"} dropped`,
597918
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
597919
+ });
597920
+ }
597921
+ }
597922
+ } catch {
597923
+ }
596616
597924
  this._emitModelResolutionTelemetry("main");
596617
597925
  void this._hookManager.runSessionHook("session_start", this._sessionId).catch(() => {
596618
597926
  });
@@ -596848,6 +598156,12 @@ TASK: ${scrubbedTask}` : scrubbedTask;
596848
598156
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
596849
598157
  });
596850
598158
  }
598159
+ if (this._restoredTodoVerificationNote) {
598160
+ messages2.splice(messages2.length - 1, 0, {
598161
+ role: "system",
598162
+ content: this._restoredTodoVerificationNote
598163
+ });
598164
+ }
596851
598165
  this._phaseMessageStartIdx = messages2.length;
596852
598166
  if (process.env["OMNIUS_DISABLE_DECOMP1"] !== "1") {
596853
598167
  try {
@@ -597028,6 +598342,8 @@ TASK: ${scrubbedTask}` : scrubbedTask;
597028
598342
  let completionTokens = 0;
597029
598343
  let estimatedTokens = 0;
597030
598344
  let toolCallCount = 0;
598345
+ let substantiveProgressCount = 0;
598346
+ const substantiveProgressFingerprints = /* @__PURE__ */ new Set();
597031
598347
  let completed = false;
597032
598348
  let summary = "";
597033
598349
  let bruteForceCycle = 0;
@@ -597096,6 +598412,7 @@ TASK: ${scrubbedTask}` : scrubbedTask;
597096
598412
  let lastCommitGateTurn = -1;
597097
598413
  let lastShellPivotTurn = -1;
597098
598414
  const recentToolResults = /* @__PURE__ */ new Map();
598415
+ const exactFileReadObservations = /* @__PURE__ */ new Map();
597099
598416
  let fileMutationEpoch = 0;
597100
598417
  const dedupHitCount = /* @__PURE__ */ new Map();
597101
598418
  const noopedMemoryWriteFingerprints = /* @__PURE__ */ new Set();
@@ -597500,6 +598817,16 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
597500
598817
  });
597501
598818
  }
597502
598819
  }
598820
+ if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
598821
+ const restoredCollapsed = this._textEchoGuard.collapseEchoes(messages2);
598822
+ if (restoredCollapsed > 0) {
598823
+ this.emit({
598824
+ type: "status",
598825
+ content: `ECHO-1: collapsed ${restoredCollapsed} near-duplicate assistant plan(s) from restored transcript before first turn`,
598826
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
598827
+ });
598828
+ }
598829
+ }
597503
598830
  for (let turn = 0; turn < turnCap; turn++) {
597504
598831
  clearTurnState(this._appState);
597505
598832
  this._maybeApplyThinkGuard();
@@ -598931,8 +600258,8 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
598931
600258
  if (process.env["OMNIUS_DISABLE_ADAPTIVE_RETRIEVAL"] !== "1") {
598932
600259
  const goalForSig = (this._taskState.goal || "").slice(0, 200);
598933
600260
  const recentTools = this._toolSequence.slice(-5).join("|");
598934
- const { createHash: createHash53 } = await import("node:crypto");
598935
- const sig = createHash53("sha256").update(`${goalForSig}::${recentTools}`).digest("hex").slice(0, 16);
600261
+ const { createHash: createHash54 } = await import("node:crypto");
600262
+ const sig = createHash54("sha256").update(`${goalForSig}::${recentTools}`).digest("hex").slice(0, 16);
598936
600263
  if (this._lastPprSig === sig && this._lastPprMemoryLines.length > 0) {
598937
600264
  compacted.push({
598938
600265
  role: "system",
@@ -599070,10 +600397,13 @@ ${memoryLines.join("\n")}`
599070
600397
  const { maxOutputTokens: effectiveMaxTokens } = this.contextLimits();
599071
600398
  this.gcSystemMessages(requestMessages);
599072
600399
  requestMessages = this._prepareModelFacingMessages(requestMessages, turn);
600400
+ const echoBoostedTemp = this._echoTempBoostTurns > 0 ? Math.max(this.options.temperature ?? 0, 0.7) : this.options.temperature;
600401
+ if (this._echoTempBoostTurns > 0)
600402
+ this._echoTempBoostTurns--;
599073
600403
  const chatRequest = {
599074
600404
  messages: requestMessages,
599075
600405
  tools: toolDefs,
599076
- temperature: this.options.temperature,
600406
+ temperature: echoBoostedTemp,
599077
600407
  maxTokens: effectiveMaxTokens,
599078
600408
  timeoutMs: boundedRequestTimeoutMs()
599079
600409
  };
@@ -599268,9 +600598,7 @@ ${memoryLines.join("\n")}`
599268
600598
  const parsed = JSON.parse(jsonMatch[1]);
599269
600599
  const resolvedParsedTool = parsed.tool ? this.lookupRegisteredTool(parsed.tool) : null;
599270
600600
  if (parsed.tool && resolvedParsedTool) {
599271
- const tool = resolvedParsedTool.tool;
599272
- const rawResult = await tool.execute(parsed.args ?? {});
599273
- const result = this.applyRegisteredToolResultTriage(rawResult, resolvedParsedTool.name, tool);
600601
+ const result = await this.runToolByName(resolvedParsedTool.name, parsed.args ?? {});
599274
600602
  messages2.push({ role: "assistant", content });
599275
600603
  messages2.push({
599276
600604
  role: "system",
@@ -599479,6 +600807,7 @@ ${memoryLines.join("\n")}`
599479
600807
  if (msg.toolCalls && msg.toolCalls.length > 0) {
599480
600808
  consecutiveTextOnly = 0;
599481
600809
  consecutiveThinkOnly = 0;
600810
+ this._textEchoGuard.noteToolProgress();
599482
600811
  msg.toolCalls = this._dedupeToolCallsForResponse(msg.toolCalls, turn);
599483
600812
  if (msg.toolCalls.length === 0) {
599484
600813
  messages2.push({
@@ -599544,6 +600873,10 @@ ${memoryLines.join("\n")}`
599544
600873
  });
599545
600874
  }
599546
600875
  let editFeedbackRequiredBeforeMoreEdits = null;
600876
+ const branchReadBatchBudget = {
600877
+ inlineTokens: 0,
600878
+ reservations: /* @__PURE__ */ new Map()
600879
+ };
599547
600880
  executeSingle = async (tc) => {
599548
600881
  if (this.aborted)
599549
600882
  return null;
@@ -600402,6 +601735,7 @@ ${cachedResult}`,
600402
601735
  const resolvedTool = this.lookupRegisteredTool(tc.name);
600403
601736
  const tool = resolvedTool?.tool;
600404
601737
  let result;
601738
+ let fileReadSafetyChecked = false;
600405
601739
  let runtimeSystemGuidance = null;
600406
601740
  if (repeatShortCircuit) {
600407
601741
  result = repeatShortCircuit;
@@ -600551,22 +601885,86 @@ ${cachedResult}`,
600551
601885
  }
600552
601886
  }
600553
601887
  try {
600554
- if (typeof tool.executeStream === "function") {
600555
- const gen = tool.executeStream(finalArgs);
600556
- let iterResult = await gen.next();
600557
- while (!iterResult.done) {
600558
- const progress = String(iterResult.value);
600559
- this.emit({
600560
- type: "status",
600561
- toolName: tc.name,
600562
- content: progress,
600563
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
600564
- });
600565
- iterResult = await gen.next();
601888
+ tc.arguments = finalArgs;
601889
+ const normalizedDispatchName = resolvedTool?.name ?? tc.name;
601890
+ let branchPreempted = null;
601891
+ if (normalizedDispatchName === "file_read") {
601892
+ const exactReadKey = this._buildToolFingerprint("file_read", tc.arguments);
601893
+ const priorRead = exactFileReadObservations.get(exactReadKey);
601894
+ if (priorRead) {
601895
+ const currentRead = this._fileReadDiskIdentity(tc.arguments);
601896
+ if (currentRead && currentRead.contentHash === priorRead.contentHash) {
601897
+ exactFileReadObservations.set(exactReadKey, currentRead);
601898
+ const duplicateOutput = [
601899
+ `[DUPLICATE_READ_BLOCKED] path=${currentRead.path} sha256=${currentRead.contentHash}`,
601900
+ `The exact file_read arguments already produced evidence from this unchanged source during the current run. The tool was not re-executed and the raw body was not re-injected.`,
601901
+ `Use the existing evidence/anchors now. To discover something different, issue one narrower offset/limit or grep_search with a new symbol; otherwise take the next mutation, verification, or completion action.`
601902
+ ].join("\n");
601903
+ branchPreempted = {
601904
+ success: true,
601905
+ output: duplicateOutput,
601906
+ llmContent: duplicateOutput,
601907
+ beforeHash: currentRead.contentHash,
601908
+ runtimeAuthored: true,
601909
+ noop: true,
601910
+ completionEvidenceMetrics: {
601911
+ duplicateReadBlocked: true,
601912
+ duplicateReadSourceBytes: currentRead.byteCount
601913
+ }
601914
+ };
601915
+ this.emit({
601916
+ type: "status",
601917
+ toolName: normalizedDispatchName,
601918
+ content: `Exact unchanged file_read blocked before dispatch: ${currentRead.path} sha256=${currentRead.contentHash.slice(0, 12)}`,
601919
+ turn,
601920
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
601921
+ });
601922
+ } else {
601923
+ exactFileReadObservations.delete(exactReadKey);
601924
+ }
600566
601925
  }
600567
- result = iterResult.value;
601926
+ }
601927
+ if (!branchPreempted) {
601928
+ branchPreempted = await this._preemptFileReadWithBranch({
601929
+ callId: tc.id,
601930
+ toolName: normalizedDispatchName,
601931
+ args: tc.arguments,
601932
+ messages: messages2,
601933
+ turn,
601934
+ batchBudget: branchReadBatchBudget
601935
+ });
601936
+ }
601937
+ if (branchPreempted) {
601938
+ result = branchPreempted;
601939
+ fileReadSafetyChecked = true;
600568
601940
  } else {
600569
- result = await tool.execute(finalArgs);
601941
+ if (typeof tool.executeStream === "function") {
601942
+ const gen = tool.executeStream(finalArgs);
601943
+ let iterResult = await gen.next();
601944
+ while (!iterResult.done) {
601945
+ const progress = String(iterResult.value);
601946
+ this.emit({
601947
+ type: "status",
601948
+ toolName: tc.name,
601949
+ content: progress,
601950
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
601951
+ });
601952
+ iterResult = await gen.next();
601953
+ }
601954
+ result = iterResult.value;
601955
+ } else {
601956
+ result = await tool.execute(finalArgs);
601957
+ }
601958
+ result = await this._guardMaterializedFileReadResult({
601959
+ callId: tc.id,
601960
+ toolName: resolvedTool?.name ?? tc.name,
601961
+ args: tc.arguments,
601962
+ result,
601963
+ messages: messages2,
601964
+ turn,
601965
+ batchBudget: branchReadBatchBudget
601966
+ });
601967
+ fileReadSafetyChecked = true;
600570
601968
  }
600571
601969
  result = this.applyRegisteredToolResultTriage(result, resolvedTool?.name ?? tc.name, tool);
600572
601970
  if (tc.name === "shell" && result.success === true) {
@@ -600666,6 +602064,23 @@ Respond with EXACTLY this structure before your next tool call:
600666
602064
  }
600667
602065
  }
600668
602066
  }
602067
+ if (!fileReadSafetyChecked) {
602068
+ result = await this._guardMaterializedFileReadResult({
602069
+ callId: tc.id,
602070
+ toolName: resolvedTool?.name ?? tc.name,
602071
+ args: tc.arguments,
602072
+ result,
602073
+ messages: messages2,
602074
+ turn,
602075
+ batchBudget: branchReadBatchBudget
602076
+ });
602077
+ }
602078
+ if ((resolvedTool?.name ?? tc.name) === "file_read" && result.success === true && result.noop !== true) {
602079
+ const observedIdentity = this._fileReadDiskIdentity(tc.arguments);
602080
+ if (observedIdentity && (!result.beforeHash || result.beforeHash === observedIdentity.contentHash)) {
602081
+ exactFileReadObservations.set(this._buildToolFingerprint("file_read", tc.arguments), observedIdentity);
602082
+ }
602083
+ }
600669
602084
  const shellFilesystemMutation = tc.name === "shell" && result.success === true && this._shellCommandLikelyMutatesFilesystem(String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? ""));
600670
602085
  this._releaseMutationWorkerLeaseForArgs(resolvedTool?.name ?? tc.name, tc.arguments, result, turn);
600671
602086
  const shellMutationPaths = shellFilesystemMutation ? extractShellMutationPaths(String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? ""), { workingDir: this.authoritativeWorkingDirectory() }).paths : [];
@@ -600716,6 +602131,13 @@ Respond with EXACTLY this structure before your next tool call:
600716
602131
  writeCount: nextWriteCount
600717
602132
  });
600718
602133
  this._evidenceLedger.markMutated(this._normalizeEvidencePath(p2), nextWriteCount, turn);
602134
+ const branchPath = this._normalizeEvidencePath(p2);
602135
+ this._branchEvidenceByPath.delete(branchPath);
602136
+ for (const [cacheKey, cached] of this._branchEvidenceCache) {
602137
+ if (cached.path === branchPath) {
602138
+ this._branchEvidenceCache.delete(cacheKey);
602139
+ }
602140
+ }
600719
602141
  {
600720
602142
  const _normMut = this._normalizeEvidencePath(p2);
600721
602143
  for (const _covKey of this._readCoverage.keys()) {
@@ -600755,7 +602177,7 @@ Respond with EXACTLY this structure before your next tool call:
600755
602177
  const prev = this._worldFacts.files.get(p2);
600756
602178
  this._worldFacts.files.set(p2, {
600757
602179
  exists: result.success,
600758
- size: (result.output || "").length,
602180
+ size: typeof result.completionEvidenceMetrics?.["branchSourceBytes"] === "number" ? result.completionEvidenceMetrics["branchSourceBytes"] : (result.output || "").length,
600759
602181
  hashSample: (result.output || "").slice(0, 32),
600760
602182
  lastSeenTurn: turn,
600761
602183
  lastWriteTurn: prev?.lastWriteTurn,
@@ -600774,7 +602196,8 @@ Respond with EXACTLY this structure before your next tool call:
600774
602196
  range: { start: start3, end },
600775
602197
  fileVersion: this._worldFacts.files.get(p2)?.writeCount ?? 0,
600776
602198
  mtimeMs: this._statMtimeMsForToolPath(p2),
600777
- turn
602199
+ turn,
602200
+ fidelity: result.runtimeAuthored === true && result.output.startsWith("[BRANCH-EXTRACT") ? "extract" : void 0
600778
602201
  });
600779
602202
  }
600780
602203
  if (this._fileSummaryStore && result.success && result.output && result.output.length > 100) {
@@ -601679,74 +603102,6 @@ Respond with EXACTLY this structure before your next tool call:
601679
603102
  result = await this.offloadEmbeddedImageResult(result, tc.name, turn);
601680
603103
  }
601681
603104
  let output = this.normalizeToolOutput(result, tc.name, tc.arguments, turn);
601682
- if (process.env["OMNIUS_DISABLE_BRANCH_EXTRACT"] !== "1" && this.lookupRegisteredTool(tc.name)?.name === "file_read" && result.success && this.backend && typeof this.backend.chatCompletion === "function") {
601683
- const a2 = tc.arguments ?? {};
601684
- const hasExplicitRange = typeof a2["offset"] === "number" || typeof a2["limit"] === "number";
601685
- const pRaw = String(a2["path"] ?? a2["file"] ?? a2["file_path"] ?? "");
601686
- if (!hasExplicitRange && pRaw) {
601687
- let fullContent = null;
601688
- let trueLines = 0;
601689
- let trueBytes = 0;
601690
- for (const cand of [
601691
- pRaw,
601692
- _pathResolve(this._workingDirectory || process.cwd(), pRaw)
601693
- ]) {
601694
- try {
601695
- const st = _fsStatSync(cand);
601696
- if (st.isFile()) {
601697
- trueBytes = st.size;
601698
- if (trueBytes > 8e3) {
601699
- fullContent = _fsReadFileSync(cand, "utf-8");
601700
- trueLines = fullContent.split("\n").length;
601701
- }
601702
- break;
601703
- }
601704
- } catch {
601705
- }
601706
- }
601707
- if (fullContent && shouldBranchRead(trueBytes, trueLines, false)) {
601708
- const branchBrief = this._buildBranchExtractionBrief({
601709
- path: pRaw,
601710
- lineCount: trueLines,
601711
- byteCount: trueBytes,
601712
- messages: messages2
601713
- });
601714
- try {
601715
- const ev = await extractEvidence({
601716
- path: pRaw,
601717
- query: branchBrief.retrievalQuery,
601718
- brief: branchBrief,
601719
- content: fullContent,
601720
- // the REAL body, not the preview
601721
- fileVersion: this._worldFacts.files.get(pRaw)?.writeCount ?? 0,
601722
- // Native /api/chat so the extractor LLM fallback isn't
601723
- // silently empty on qwen3-family models.
601724
- backend: this._auxInferenceBackend(),
601725
- timeoutMs: 3e4
601726
- });
601727
- output = [
601728
- `[BRANCH-EXTRACT] ${pRaw} is large (${trueLines} lines, ${trueBytes} bytes); a whole-file read only returns a preview, so it was read in an isolated branch and distilled.`,
601729
- `[AGENTIC EXTRACTION REQUEST] ${branchBrief.request}`,
601730
- `Evidence driving this request:`,
601731
- ...branchBrief.triggerEvidence.map((evidence) => `- ${evidence}`),
601732
- `Looking for: ${branchBrief.returnContract}`,
601733
- `Retrieval focus: "${branchBrief.retrievalQuery.slice(0, 240)}"`,
601734
- `Relevant evidence (lines ${ev.sourceStart ?? "?"}-${ev.sourceEnd ?? "?"}, confidence ${ev.confidence.toFixed(2)}):`,
601735
- ev.claim,
601736
- `If you need a different region, call file_read with a specific offset+limit. Do NOT re-read the whole file — you already have the relevant content above.`
601737
- ].join("\n");
601738
- this.emit({
601739
- type: "status",
601740
- toolName: tc.name,
601741
- content: `Branch-extract: ${pRaw} (${trueLines} lines / ${trueBytes}B) → ${ev.injectedChars} chars to context (${(trueBytes / Math.max(1, ev.injectedChars)).toFixed(0)}× smaller)`,
601742
- turn,
601743
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
601744
- });
601745
- } catch {
601746
- }
601747
- }
601748
- }
601749
- }
601750
603105
  if (criticGuidance && !repeatShortCircuit) {
601751
603106
  output += `
601752
603107
 
@@ -601830,6 +603185,22 @@ Evidence: ${evidencePreview}`.slice(0, 500);
601830
603185
  turn,
601831
603186
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
601832
603187
  });
603188
+ const branchCacheHit = result.completionEvidenceMetrics?.["branchCacheHit"] === true;
603189
+ const nonSubstantiveResult = result.noop === true || branchCacheHit || repeatShortCircuit !== null && result.runtimeAuthored === true;
603190
+ if (!nonSubstantiveResult) {
603191
+ const observationFingerprint = [
603192
+ this._buildToolFingerprint(tc.name, tc.arguments ?? {}),
603193
+ result.success ? "ok" : "error",
603194
+ result.beforeHash ?? "",
603195
+ result.afterHash ?? "",
603196
+ realMutationPaths.join(","),
603197
+ this.quickHash(String(result.output ?? result.error ?? result.llmContent ?? ""))
603198
+ ].join("|");
603199
+ if (!substantiveProgressFingerprints.has(observationFingerprint)) {
603200
+ substantiveProgressFingerprints.add(observationFingerprint);
603201
+ substantiveProgressCount++;
603202
+ }
603203
+ }
601833
603204
  this._taskState.toolCallCount++;
601834
603205
  if (realFileMutation) {
601835
603206
  this._lastFileWriteTurn = turn;
@@ -602959,6 +604330,30 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
602959
604330
  });
602960
604331
  break;
602961
604332
  }
604333
+ if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
604334
+ const echoObs = this._textEchoGuard.observe(content);
604335
+ if (echoObs.isEcho) {
604336
+ const collapsedCount = this._textEchoGuard.collapseEchoes(messages2);
604337
+ this._echoTempBoostTurns = 2;
604338
+ this.emit({
604339
+ type: "status",
604340
+ content: `ECHO-1: text-only echo #${echoObs.echoCount} (${Math.round(echoObs.similarity * 100)}% similar to earlier message) — collapsed ${collapsedCount} duplicate(s), injecting pattern breaker`,
604341
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
604342
+ });
604343
+ messages2.push({
604344
+ role: "system",
604345
+ content: this._textEchoGuard.buildIntervention(echoObs)
604346
+ });
604347
+ if (adversaryAddedGuidance) {
604348
+ this.drainPendingRuntimeGuidance(turn);
604349
+ while (this.pendingUserMessages.length > 0) {
604350
+ const userMsg = this.pendingUserMessages.shift();
604351
+ await this.appendInjectedUserMessage(userMsg, messages2, turn);
604352
+ }
604353
+ }
604354
+ continue;
604355
+ }
604356
+ }
602962
604357
  const codeBlockMatch = content.match(/```(?:bash|sh|shell|zsh)\s*\n([\s\S]*?)```/);
602963
604358
  const codeBlockLines = codeBlockMatch?.[1] ? codeBlockMatch[1].trim().split("\n").filter((l2) => l2.trim() && !l2.trim().startsWith("#")) : [];
602964
604359
  const everyLineLooksExecutable = codeBlockLines.length > 0 && codeBlockLines.every((l2) => {
@@ -603096,24 +604491,24 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
603096
604491
  } catch {
603097
604492
  }
603098
604493
  }
603099
- let prevCycleToolCalls = toolCallCount;
604494
+ let prevCycleSubstantiveProgress = substantiveProgressCount;
603100
604495
  while (!completed && !this.aborted && !this._completionIncompleteVerification && this.options.bruteForce && bruteForceCycle < this.options.bruteForceMaxCycles) {
603101
604496
  bruteForceCycle++;
603102
604497
  const totalTurns = messages2.filter((m2) => m2.role === "assistant").length;
603103
- if (bruteForceCycle > 1 && toolCallCount === prevCycleToolCalls) {
604498
+ if (bruteForceCycle > 1 && substantiveProgressCount === prevCycleSubstantiveProgress) {
603104
604499
  this.emit({
603105
604500
  type: "status",
603106
- content: `Stopping re-engagement — no tool call progress in cycle ${bruteForceCycle - 1}. Model may not support tool calling for this task.`,
604501
+ content: `Stopping re-engagement — cycle ${bruteForceCycle - 1} produced no new executed fingerprint, mutation, todo transition, or verifier evidence (${toolCallCount} attempted tool calls; ${substantiveProgressCount} substantive observations).`,
603107
604502
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
603108
604503
  });
603109
604504
  break;
603110
604505
  }
603111
- prevCycleToolCalls = toolCallCount;
604506
+ prevCycleSubstantiveProgress = substantiveProgressCount;
603112
604507
  consecutiveTextOnly = 0;
603113
604508
  consecutiveThinkOnly = 0;
603114
604509
  this.emit({
603115
604510
  type: "status",
603116
- content: `Re-engaging — cycle ${bruteForceCycle} (${totalTurns} turns, ${toolCallCount} tool calls so far)`,
604511
+ content: `Re-engaging — cycle ${bruteForceCycle} (${totalTurns} turns, ${toolCallCount} attempted calls / ${substantiveProgressCount} substantive observations)`,
603117
604512
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
603118
604513
  });
603119
604514
  this._reg61CooldownUntilTurn = -1;
@@ -603243,10 +604638,13 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
603243
604638
  this._insertContextFrame(compactedMsgs, await this._buildTurnContextFrame(turn, compactedMsgs, void 0, bfEnvironmentBlock));
603244
604639
  this.gcSystemMessages(compactedMsgs);
603245
604640
  const modelFacingMessages = this._prepareModelFacingMessages(compactedMsgs, turn);
604641
+ const bfEchoBoostedTemp = this._echoTempBoostTurns > 0 ? Math.max(this.options.temperature ?? 0, 0.7) : this.options.temperature;
604642
+ if (this._echoTempBoostTurns > 0)
604643
+ this._echoTempBoostTurns--;
603246
604644
  const chatRequest = {
603247
604645
  messages: modelFacingMessages,
603248
604646
  tools: toolDefs,
603249
- temperature: this.options.temperature,
604647
+ temperature: bfEchoBoostedTemp,
603250
604648
  maxTokens: this.options.maxTokens,
603251
604649
  timeoutMs: boundedRequestTimeoutMs(),
603252
604650
  numCtx: this.options.contextWindowSize || void 0
@@ -603371,6 +604769,7 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
603371
604769
  if (msg.toolCalls && msg.toolCalls.length > 0) {
603372
604770
  consecutiveTextOnly = 0;
603373
604771
  consecutiveThinkOnly = 0;
604772
+ this._textEchoGuard.noteToolProgress();
603374
604773
  msg.toolCalls = this._dedupeRepeatedToolCallIdsForResponse(msg.toolCalls, turn);
603375
604774
  if (msg.toolCalls.length === 0) {
603376
604775
  messages2.push({
@@ -603547,6 +604946,23 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
603547
604946
  });
603548
604947
  break;
603549
604948
  }
604949
+ if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
604950
+ const echoObsBF = this._textEchoGuard.observe(content);
604951
+ if (echoObsBF.isEcho) {
604952
+ const collapsedBF = this._textEchoGuard.collapseEchoes(messages2);
604953
+ this._echoTempBoostTurns = 2;
604954
+ this.emit({
604955
+ type: "status",
604956
+ content: `ECHO-1: text-only echo #${echoObsBF.echoCount} in bf-cycle ${bruteForceCycle} (${Math.round(echoObsBF.similarity * 100)}% similar) — collapsed ${collapsedBF} duplicate(s), injecting pattern breaker`,
604957
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
604958
+ });
604959
+ messages2.push({
604960
+ role: "system",
604961
+ content: this._textEchoGuard.buildIntervention(echoObsBF)
604962
+ });
604963
+ continue;
604964
+ }
604965
+ }
603550
604966
  messages2.push({
603551
604967
  role: "system",
603552
604968
  content: "Continue working. Use tools to read files, make changes, and run validation. Call task_complete when done."
@@ -604510,6 +605926,19 @@ ${marker}` : marker);
604510
605926
  return { role: "tool", content: messageContent, tool_call_id: toolCallId };
604511
605927
  }
604512
605928
  buildModelFacingToolMessage(output, toolCallId, toolName, args, success) {
605929
+ if (process.env["OMNIUS_DISABLE_OBSERVATION_FRAME"] !== "1") {
605930
+ try {
605931
+ this._observationLedger.record({
605932
+ tool: toolName,
605933
+ args,
605934
+ fingerprint: this._buildToolFingerprint(toolName, args ?? {}),
605935
+ output,
605936
+ success: success !== false,
605937
+ turn: this._taskState?.toolCallCount ?? 0
605938
+ });
605939
+ } catch {
605940
+ }
605941
+ }
604513
605942
  return this.buildToolMessage(this.compactDiscoveryOutputForModel(toolName, args, output, success), toolCallId, toolName);
604514
605943
  }
604515
605944
  compactDiscoveryOutputForModel(toolName, args, output, success) {
@@ -606899,7 +608328,7 @@ ${telegramPersonaHead}` : stripped
606899
608328
  ...stickyToKeep,
606900
608329
  ...filteredRecent
606901
608330
  ];
606902
- const fileRecoveryBudget = Math.floor((this.options.contextWindowSize || 32768) * 0.15);
608331
+ const fileRecoveryBudget = Math.floor((this._branchRoutingContextWindow() || 32768) * 0.15);
606903
608332
  const maxRecoverFiles = tier === "small" ? 3 : tier === "medium" ? 4 : 5;
606904
608333
  const recoveredFiles = [];
606905
608334
  if (this._fileRegistry.size > 0) {
@@ -606914,8 +608343,45 @@ ${telegramPersonaHead}` : stripped
606914
608343
  for (const [filePath, entry] of entries) {
606915
608344
  try {
606916
608345
  const { readFileSync: readFileSync144 } = await import("node:fs");
606917
- const content = readFileSync144(filePath, "utf8");
608346
+ const absolutePath = this._absoluteToolPath(filePath);
608347
+ const content = readFileSync144(absolutePath, "utf8");
606918
608348
  const tokenEst = Math.ceil(content.length / 4);
608349
+ const canonicalPath = this._normalizeEvidencePath(filePath);
608350
+ const branchNode = this._branchEvidenceByPath.get(canonicalPath);
608351
+ const currentMtime = this._statMtimeMsForToolPath(filePath) ?? 0;
608352
+ if (branchNode && branchNode.mtimeMs === currentMtime) {
608353
+ const nodeTokens = Math.ceil(branchNode.output.length / 4);
608354
+ if (recoveredTokens + nodeTokens > fileRecoveryBudget)
608355
+ continue;
608356
+ result.push({
608357
+ role: "system",
608358
+ content: `<recovered-branch-evidence path="${filePath}" sha256="${branchNode.contentHash}">
608359
+ ${branchNode.output}
608360
+ </recovered-branch-evidence>`
608361
+ });
608362
+ recoveredFiles.push(filePath);
608363
+ recoveredTokens += nodeTokens;
608364
+ continue;
608365
+ }
608366
+ const recoveryDecision = assessBranchRead({
608367
+ sourceBytes: Buffer.byteLength(content, "utf8"),
608368
+ sourceLines: content.split("\n").length,
608369
+ contextWindowTokens: this._branchRoutingContextWindow(),
608370
+ residentContextTokens: estimateMessagesTokens2(result),
608371
+ reservedTokens: this._branchReadReservedTokens(this._branchRoutingContextWindow()),
608372
+ pendingInlineReadTokens: recoveredTokens,
608373
+ safeContextTokens: this.contextLimits().compactionThreshold
608374
+ });
608375
+ if (recoveryDecision.branch) {
608376
+ const reference = `<recovered-file-reference path="${filePath}" status="${entry.modified ? "modified" : "read"}" routing="branch-required" projected_tokens="${recoveryDecision.projectedReadTokens}">Raw recovery suppressed by the 20% context contract; use the existing evidence ledger or issue one goal-scoped file_read.</recovered-file-reference>`;
608377
+ const referenceTokens = Math.ceil(reference.length / 4);
608378
+ if (recoveredTokens + referenceTokens <= fileRecoveryBudget) {
608379
+ result.push({ role: "system", content: reference });
608380
+ recoveredFiles.push(filePath);
608381
+ recoveredTokens += referenceTokens;
608382
+ }
608383
+ continue;
608384
+ }
606919
608385
  if (recoveredTokens + tokenEst > fileRecoveryBudget)
606920
608386
  break;
606921
608387
  const truncated = content.length > 8e3;
@@ -606985,6 +608451,7 @@ ${content.slice(0, 8e3)}${truncated ? "\n[truncated recovery; use a narrow live
606985
608451
  } catch {
606986
608452
  }
606987
608453
  }
608454
+ const protectedRecoveryMessages = result.filter((message2) => message2.role === "system" && typeof message2.content === "string" && /^<recovered-(?:branch-evidence|file-reference|file)\b/.test(message2.content));
606988
608455
  const ctxWindow = this.options.contextWindowSize;
606989
608456
  if (ctxWindow > 0) {
606990
608457
  const _safetyImgPat = /\[IMAGE_BASE64:[^\]]+\]/g;
@@ -607022,6 +608489,7 @@ ${content.slice(0, 8e3)}${truncated ? "\n[truncated recovery; use a narrow live
607022
608489
  ...narrowedHead,
607023
608490
  compactionMsg,
607024
608491
  ...stickyToKeep,
608492
+ ...protectedRecoveryMessages,
607025
608493
  ...trimmedRecent
607026
608494
  ];
607027
608495
  }
@@ -612036,7 +613504,7 @@ var init_composite_scorer = __esm({
612036
613504
  });
612037
613505
 
612038
613506
  // packages/orchestrator/dist/memory/materialization-policy.js
612039
- import { createHash as createHash35 } from "node:crypto";
613507
+ import { createHash as createHash36 } from "node:crypto";
612040
613508
  function materializeMemoryItems(items, options2 = {}) {
612041
613509
  const config = options2.config ?? DEFAULT_WEIGHTING_CONFIG;
612042
613510
  const sorted = [...items].sort((a2, b) => b.weight - a2.weight || a2.id.localeCompare(b.id));
@@ -612173,7 +613641,7 @@ function renderPlan(decisions, includeHeader) {
612173
613641
  footerBlock,
612174
613642
  renderedText,
612175
613643
  memoryPrefix,
612176
- prefixHash: hashText(memoryPrefix),
613644
+ prefixHash: hashText2(memoryPrefix),
612177
613645
  tierDistribution,
612178
613646
  tokensEmitted,
612179
613647
  tokensBaselineNoWeighting,
@@ -612273,8 +613741,8 @@ function estimateTokens4(text2) {
612273
613741
  return 0;
612274
613742
  return Math.max(1, Math.ceil(text2.length / 4));
612275
613743
  }
612276
- function hashText(text2) {
612277
- return createHash35("sha256").update(text2).digest("hex");
613744
+ function hashText2(text2) {
613745
+ return createHash36("sha256").update(text2).digest("hex");
612278
613746
  }
612279
613747
  var init_materialization_policy = __esm({
612280
613748
  "packages/orchestrator/dist/memory/materialization-policy.js"() {
@@ -612438,7 +613906,7 @@ var init_config_loader = __esm({
612438
613906
  });
612439
613907
 
612440
613908
  // packages/orchestrator/dist/memory/stability-tracker.js
612441
- import { createHash as createHash36 } from "node:crypto";
613909
+ import { createHash as createHash37 } from "node:crypto";
612442
613910
  import { existsSync as existsSync109, mkdirSync as mkdirSync60, readFileSync as readFileSync84, writeFileSync as writeFileSync51 } from "node:fs";
612443
613911
  import { dirname as dirname36, join as join117 } from "node:path";
612444
613912
  function stabilityFilePath(repoRoot) {
@@ -612502,7 +613970,7 @@ function computeStabilityHash(item) {
612502
613970
  item.scope.name,
612503
613971
  item.topicKey
612504
613972
  ].join("|");
612505
- return createHash36("sha256").update(normalized).digest("hex");
613973
+ return createHash37("sha256").update(normalized).digest("hex");
612506
613974
  }
612507
613975
  function normalizeContent2(content) {
612508
613976
  return content.replace(/\s+/g, " ").trim();
@@ -616522,10 +617990,10 @@ var init_project_arc = __esm({
616522
617990
  });
616523
617991
 
616524
617992
  // packages/orchestrator/dist/dedup-gate.js
616525
- import { createHash as createHash37 } from "node:crypto";
617993
+ import { createHash as createHash38 } from "node:crypto";
616526
617994
  function fingerprintCall(name10, args) {
616527
617995
  const canon = canonicalize(args);
616528
- return createHash37("sha1").update(`${name10}\0${canon}`).digest("hex").slice(0, 16);
617996
+ return createHash38("sha1").update(`${name10}\0${canon}`).digest("hex").slice(0, 16);
616529
617997
  }
616530
617998
  function canonicalize(value2) {
616531
617999
  if (value2 === null || typeof value2 !== "object")
@@ -627457,7 +628925,7 @@ var require_websocket3 = __commonJS({
627457
628925
  var http6 = __require("http");
627458
628926
  var net5 = __require("net");
627459
628927
  var tls2 = __require("tls");
627460
- var { randomBytes: randomBytes31, createHash: createHash53 } = __require("crypto");
628928
+ var { randomBytes: randomBytes31, createHash: createHash54 } = __require("crypto");
627461
628929
  var { Duplex: Duplex3, Readable } = __require("stream");
627462
628930
  var { URL: URL3 } = __require("url");
627463
628931
  var PerMessageDeflate3 = require_permessage_deflate3();
@@ -628117,7 +629585,7 @@ var require_websocket3 = __commonJS({
628117
629585
  abortHandshake(websocket, socket, "Invalid Upgrade header");
628118
629586
  return;
628119
629587
  }
628120
- const digest3 = createHash53("sha1").update(key + GUID).digest("base64");
629588
+ const digest3 = createHash54("sha1").update(key + GUID).digest("base64");
628121
629589
  if (res.headers["sec-websocket-accept"] !== digest3) {
628122
629590
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
628123
629591
  return;
@@ -628484,7 +629952,7 @@ var require_websocket_server2 = __commonJS({
628484
629952
  var EventEmitter15 = __require("events");
628485
629953
  var http6 = __require("http");
628486
629954
  var { Duplex: Duplex3 } = __require("stream");
628487
- var { createHash: createHash53 } = __require("crypto");
629955
+ var { createHash: createHash54 } = __require("crypto");
628488
629956
  var extension3 = require_extension3();
628489
629957
  var PerMessageDeflate3 = require_permessage_deflate3();
628490
629958
  var subprotocol3 = require_subprotocol2();
@@ -628785,7 +630253,7 @@ var require_websocket_server2 = __commonJS({
628785
630253
  );
628786
630254
  }
628787
630255
  if (this._state > RUNNING) return abortHandshake(socket, 503);
628788
- const digest3 = createHash53("sha1").update(key + GUID).digest("base64");
630256
+ const digest3 = createHash54("sha1").update(key + GUID).digest("base64");
628789
630257
  const headers = [
628790
630258
  "HTTP/1.1 101 Switching Protocols",
628791
630259
  "Upgrade: websocket",
@@ -635566,14 +637034,14 @@ var init_voice_session = __esm({
635566
637034
  });
635567
637035
 
635568
637036
  // packages/cli/src/tui/scoped-personality.ts
635569
- import { createHash as createHash38 } from "node:crypto";
637037
+ import { createHash as createHash39 } from "node:crypto";
635570
637038
  import { appendFileSync as appendFileSync13, existsSync as existsSync120, mkdirSync as mkdirSync72, readFileSync as readFileSync97, writeFileSync as writeFileSync60 } from "node:fs";
635571
637039
  import { join as join131, resolve as resolve60 } from "node:path";
635572
637040
  function safeName(input) {
635573
637041
  return input.replace(/[^A-Za-z0-9_.-]/g, "-").slice(0, 80) || "default";
635574
637042
  }
635575
637043
  function scopeHash(scope) {
635576
- return createHash38("sha1").update(`${scope.kind}:${scope.id}`).digest("hex").slice(0, 16);
637044
+ return createHash39("sha1").update(`${scope.kind}:${scope.id}`).digest("hex").slice(0, 16);
635577
637045
  }
635578
637046
  function scopedPersonalityDir(repoRoot, kind) {
635579
637047
  return resolve60(repoRoot, ".omnius", "scoped-personality", kind);
@@ -635944,7 +637412,7 @@ var init_scoped_personality = __esm({
635944
637412
  });
635945
637413
 
635946
637414
  // packages/cli/src/tui/voice-soul.ts
635947
- import { createHash as createHash39 } from "node:crypto";
637415
+ import { createHash as createHash40 } from "node:crypto";
635948
637416
  import { existsSync as existsSync121, readdirSync as readdirSync38, readFileSync as readFileSync98 } from "node:fs";
635949
637417
  import { basename as basename26, join as join132, resolve as resolve61 } from "node:path";
635950
637418
  function compactText(text2, limit) {
@@ -635959,7 +637427,7 @@ function blockText(text2, limit) {
635959
637427
  ... [truncated]`;
635960
637428
  }
635961
637429
  function scopeStateKey(scope, surface) {
635962
- return createHash39("sha1").update(`${surface}:${scope.kind}:${scope.id}`).digest("hex").slice(0, 16);
637430
+ return createHash40("sha1").update(`${surface}:${scope.kind}:${scope.id}`).digest("hex").slice(0, 16);
635963
637431
  }
635964
637432
  function safeName2(input) {
635965
637433
  return input.replace(/[^A-Za-z0-9_.-]/g, "-").slice(0, 80) || "default";
@@ -638599,7 +640067,7 @@ var init_types3 = __esm({
638599
640067
  });
638600
640068
 
638601
640069
  // packages/cli/src/tui/p2p/secret-vault.ts
638602
- import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes23, scryptSync as scryptSync2, createHash as createHash40 } from "node:crypto";
640070
+ import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes23, scryptSync as scryptSync2, createHash as createHash41 } from "node:crypto";
638603
640071
  import { readFileSync as readFileSync100, writeFileSync as writeFileSync62, existsSync as existsSync123, mkdirSync as mkdirSync74 } from "node:fs";
638604
640072
  import { dirname as dirname39 } from "node:path";
638605
640073
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
@@ -638843,7 +640311,7 @@ var init_secret_vault = __esm({
638843
640311
  /** Generate a deterministic fingerprint of vault contents (for sync verification) */
638844
640312
  fingerprint() {
638845
640313
  const names = Array.from(this.secrets.keys()).sort();
638846
- const hash = createHash40("sha256");
640314
+ const hash = createHash41("sha256");
638847
640315
  for (const name10 of names) {
638848
640316
  hash.update(name10 + ":");
638849
640317
  hash.update(this.secrets.get(name10).value);
@@ -638858,7 +640326,7 @@ var init_secret_vault = __esm({
638858
640326
  // packages/cli/src/tui/p2p/peer-mesh.ts
638859
640327
  import { EventEmitter as EventEmitter9 } from "node:events";
638860
640328
  import { createServer as createServer6 } from "node:http";
638861
- import { randomBytes as randomBytes24, createHash as createHash41, generateKeyPairSync } from "node:crypto";
640329
+ import { randomBytes as randomBytes24, createHash as createHash42, generateKeyPairSync } from "node:crypto";
638862
640330
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
638863
640331
  var init_peer_mesh = __esm({
638864
640332
  "packages/cli/src/tui/p2p/peer-mesh.ts"() {
@@ -638874,7 +640342,7 @@ var init_peer_mesh = __esm({
638874
640342
  const { publicKey: publicKey2, privateKey } = generateKeyPairSync("ed25519");
638875
640343
  this.publicKey = publicKey2.export({ type: "spki", format: "der" });
638876
640344
  this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
638877
- this.peerId = createHash41("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
640345
+ this.peerId = createHash42("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
638878
640346
  this.capabilities = options2.capabilities;
638879
640347
  this.displayName = options2.displayName;
638880
640348
  this._authKey = options2.authKey ?? randomBytes24(24).toString("base64url");
@@ -640240,7 +641708,7 @@ __export(omnius_directory_exports, {
640240
641708
  import { appendFileSync as appendFileSync14, cpSync as cpSync2, existsSync as existsSync125, mkdirSync as mkdirSync76, readFileSync as readFileSync102, writeFileSync as writeFileSync64, readdirSync as readdirSync41, statSync as statSync51, unlinkSync as unlinkSync23, openSync as openSync2, closeSync as closeSync2, renameSync as renameSync11, watch as fsWatch2 } from "node:fs";
640241
641709
  import { join as join136, relative as relative17, basename as basename27, dirname as dirname40, resolve as resolve62 } from "node:path";
640242
641710
  import { homedir as homedir42 } from "node:os";
640243
- import { createHash as createHash43 } from "node:crypto";
641711
+ import { createHash as createHash44 } from "node:crypto";
640244
641712
  function isGitRoot(dir) {
640245
641713
  const gitPath = join136(dir, ".git");
640246
641714
  if (!existsSync125(gitPath)) return false;
@@ -640738,7 +642206,7 @@ function buildHandoffPrompt(repoRoot) {
640738
642206
  return lines.join("\n");
640739
642207
  }
640740
642208
  function computeDedupeHash(task, savedAt) {
640741
- return createHash43("sha256").update(`${task}|${savedAt}`).digest("hex").slice(0, 16);
642209
+ return createHash44("sha256").update(`${task}|${savedAt}`).digest("hex").slice(0, 16);
640742
642210
  }
640743
642211
  function generateSessionId() {
640744
642212
  const timestamp = Date.now().toString(36);
@@ -647365,7 +648833,7 @@ var init_status_bar = __esm({
647365
648833
  this.advanceStagePhase();
647366
648834
  this.renderFooterPreserveCursor();
647367
648835
  refreshTuiTasksAnimationFrame();
647368
- if ((this._trajectoryLiveBlockAppended || this._subAgentLiveBlockAppended) && this._activeViewId === "main" && this.stageBorderActive()) {
648836
+ if ((this._trajectoryLiveBlockAppended || this._subAgentLiveBlockAppended) && this._activeViewId === "main" && supportsTruecolor() && (this.stageBorderActive() || this.hasRunningChildAgentView())) {
647369
648837
  this.refreshDynamicBlocks();
647370
648838
  }
647371
648839
  if (this._agentViews.size > 1 && (String(this.currentHeaderPanel).startsWith("sys-") || this._headerExpanded)) {
@@ -647382,6 +648850,15 @@ var init_status_bar = __esm({
647382
648850
  advanceStagePhase() {
647383
648851
  this._stagePhase = (this._stagePhase + 6) % 360;
647384
648852
  }
648853
+ /** True while any non-main agent view (sub / full / telegram) is running.
648854
+ * Child-agent work does not sweep the MAIN stage, so the live-block
648855
+ * animation gate needs this signal in addition to stageBorderActive(). */
648856
+ hasRunningChildAgentView() {
648857
+ for (const view of this._agentViews.values()) {
648858
+ if (view.id !== "main" && view.status === "running") return true;
648859
+ }
648860
+ return false;
648861
+ }
647385
648862
  /**
647386
648863
  * Ensure the monitoring timer is running when the registry has entries
647387
648864
  * and the braille spinner is not active. Refreshes the buffer line
@@ -668323,7 +669800,7 @@ __export(commands_exports, {
668323
669800
  });
668324
669801
  import * as nodeOs from "node:os";
668325
669802
  import { spawn as nodeSpawn2 } from "node:child_process";
668326
- import { createHash as createHash44 } from "node:crypto";
669803
+ import { createHash as createHash45 } from "node:crypto";
668327
669804
  import {
668328
669805
  existsSync as existsSync147,
668329
669806
  readFileSync as readFileSync119,
@@ -681683,7 +683160,7 @@ async function collectSponsorMediaStream(args) {
681683
683160
  };
681684
683161
  }
681685
683162
  if (artifact.sha256) {
681686
- const sha = createHash44("sha256").update(bytes).digest("hex");
683163
+ const sha = createHash45("sha256").update(bytes).digest("hex");
681687
683164
  if (sha !== artifact.sha256)
681688
683165
  return { ok: false, error: `Artifact hash mismatch for ${artifactId}` };
681689
683166
  }
@@ -688309,6 +689786,18 @@ var init_stream_renderer = __esm({
688309
689786
  * runs. Tracked in VISIBLE chars (ANSI escapes stripped).
688310
689787
  */
688311
689788
  _cursorCol = 0;
689789
+ /**
689790
+ * RESIZE-REWRAP: raw (un-highlighted) text of the CURRENT in-progress
689791
+ * logical content line — everything streamed since the last "\n",
689792
+ * including already-flushed partials. Streaming hard-breaks rows at the
689793
+ * width current at flush time, so without this raw copy a SIGWINCH left
689794
+ * the in-progress line "locked" at the old width (the reported artifact).
689795
+ * onResize() erases the line's visual rows and re-emits from this buffer
689796
+ * wrapped at the new width.
689797
+ */
689798
+ _currentLineRaw = "";
689799
+ /** Visual rows (newlines) already emitted for the current logical line. */
689800
+ _wrapRowsEmitted = 0;
688312
689801
  /** Called when a new model response starts streaming */
688313
689802
  onStreamStart() {
688314
689803
  this.lineBuffer = "";
@@ -688320,6 +689809,8 @@ var init_stream_renderer = __esm({
688320
689809
  this.jsonBlobSize = 0;
688321
689810
  this.jsonBlobSuppressed = false;
688322
689811
  this._cursorCol = 0;
689812
+ this._currentLineRaw = "";
689813
+ this._wrapRowsEmitted = 0;
688323
689814
  this.enabled = true;
688324
689815
  this.tokenCount = 0;
688325
689816
  this.startTime = Date.now();
@@ -688408,6 +689899,34 @@ var init_stream_renderer = __esm({
688408
689899
  process.stdout.write("\n");
688409
689900
  this.lineStarted = false;
688410
689901
  }
689902
+ this._currentLineRaw = "";
689903
+ this._wrapRowsEmitted = 0;
689904
+ this._cursorCol = 0;
689905
+ }
689906
+ /**
689907
+ * RESIZE-REWRAP: re-render the in-progress logical content line at the new
689908
+ * terminal width. Streaming hard-breaks rows at flush-time width, so after
689909
+ * a SIGWINCH the current line was left "locked" at the old width — wrapped
689910
+ * rows missing the pipe gutter or overflowing. Erases the rows this line
689911
+ * occupies (tracked in _wrapRowsEmitted) and re-emits from the raw buffer.
689912
+ * Completed lines live in terminal scrollback and are not repainted.
689913
+ * Call AFTER setTermSize() so termCols() reflects the new width.
689914
+ */
689915
+ onResize() {
689916
+ if (!this.enabled) return;
689917
+ const raw = this._currentLineRaw;
689918
+ if (!raw) return;
689919
+ if (isTTY8) {
689920
+ const rowsUp = Math.min(this._wrapRowsEmitted, 40);
689921
+ let seq = "\r\x1B[2K";
689922
+ for (let i2 = 0; i2 < rowsUp; i2++) seq += "\x1B[A\x1B[2K";
689923
+ process.stdout.write(`\x1B[?25l\x1B[?7l${seq}\x1B[?7h`);
689924
+ }
689925
+ this._cursorCol = 0;
689926
+ this.lineStarted = false;
689927
+ this._currentLineRaw = "";
689928
+ this._wrapRowsEmitted = 0;
689929
+ this.writeHighlighted(raw, "content");
688411
689930
  }
688412
689931
  /** Called when streaming ends for this response */
688413
689932
  onStreamEnd() {
@@ -688448,6 +689967,9 @@ var init_stream_renderer = __esm({
688448
689967
  if (this.lineStarted) {
688449
689968
  process.stdout.write("\n");
688450
689969
  this.lineStarted = false;
689970
+ this._currentLineRaw = "";
689971
+ this._wrapRowsEmitted = 0;
689972
+ this._cursorCol = 0;
688451
689973
  }
688452
689974
  return;
688453
689975
  }
@@ -688517,6 +690039,14 @@ var init_stream_renderer = __esm({
688517
690039
  this.jsonBlobSuppressed = false;
688518
690040
  }
688519
690041
  }
690042
+ const trackedContent = kind === "content" && !this.inCodeBlock && !this.looksLikeJson(raw);
690043
+ if (trackedContent) this._currentLineRaw += raw;
690044
+ const endTrackedLine = () => {
690045
+ if (trackedContent && hasNewline) {
690046
+ this._currentLineRaw = "";
690047
+ this._wrapRowsEmitted = 0;
690048
+ }
690049
+ };
688520
690050
  const prefix = this.lineStarted ? "" : " │ ";
688521
690051
  const maxW = Math.max(10, termCols() - 6);
688522
690052
  let rendered;
@@ -688527,6 +690057,7 @@ var init_stream_renderer = __esm({
688527
690057
  const firstChunkLen = Math.min(text3.length, Math.max(1, remaining));
688528
690058
  if (remaining < 8 && text3.length > remaining) {
688529
690059
  this.writeRaw("\n");
690060
+ if (trackedContent) this._wrapRowsEmitted++;
688530
690061
  this.lineStarted = false;
688531
690062
  } else if (text3.length > remaining) {
688532
690063
  const window2 = text3.slice(0, firstChunkLen);
@@ -688535,12 +690066,13 @@ var init_stream_renderer = __esm({
688535
690066
  const head = text3.slice(0, wb).replace(/\s+$/, "");
688536
690067
  const tail = text3.slice(wb).replace(/^\s+/, "");
688537
690068
  this.writeRaw(highlight(head) + "\n");
690069
+ if (trackedContent) this._wrapRowsEmitted++;
688538
690070
  this.lineStarted = false;
688539
690071
  text3 = tail;
688540
690072
  if (!text3) return;
688541
690073
  }
688542
690074
  }
688543
- const usePrefix = this.lineStarted && this._cursorCol > 0 ? "" : prefix;
690075
+ const usePrefix = this.lineStarted && this._cursorCol > 0 ? "" : " │ ";
688544
690076
  const usableW = this.lineStarted ? maxW : Math.max(1, maxW - usePrefix.length);
688545
690077
  const lines = text3.length > usableW ? this.wordWrap(text3, usableW) : [text3];
688546
690078
  const isBlockquote = kind === "content" && /^>\s/.test(text3);
@@ -688553,12 +690085,14 @@ var init_stream_renderer = __esm({
688553
690085
  this.writeRaw(
688554
690086
  dimText(lp) + highlight(chunk) + (needsNewline ? "\n" : "")
688555
690087
  );
690088
+ if (trackedContent && needsNewline) this._wrapRowsEmitted++;
688556
690089
  }
688557
690090
  this.lineStarted = !trailingNewline;
688558
690091
  };
688559
690092
  switch (kind) {
688560
690093
  case "thinking":
688561
690094
  emitWrapped(raw, dimItalic, hasNewline);
690095
+ endTrackedLine();
688562
690096
  return;
688563
690097
  case "tool_args":
688564
690098
  rendered = this.highlightJson(raw, true);
@@ -688582,6 +690116,7 @@ var init_stream_renderer = __esm({
688582
690116
  } else {
688583
690117
  if (visibleLength(raw) > maxW || this.lineStarted && this._cursorCol + visibleLength(raw) > maxW) {
688584
690118
  emitWrapped(raw, (s2) => this.highlightMarkdown(s2), hasNewline);
690119
+ endTrackedLine();
688585
690120
  return;
688586
690121
  }
688587
690122
  rendered = this.highlightMarkdown(raw);
@@ -688591,10 +690126,12 @@ var init_stream_renderer = __esm({
688591
690126
  }
688592
690127
  if (kind === "content" && this.lineStarted && this._cursorCol + visibleLength(raw) > maxW) {
688593
690128
  emitWrapped(raw, (s2) => this.highlightMarkdown(s2), hasNewline);
690129
+ endTrackedLine();
688594
690130
  return;
688595
690131
  }
688596
690132
  this.writeRaw(dimText(prefix) + rendered + (hasNewline ? "\n" : ""));
688597
690133
  this.lineStarted = !hasNewline;
690134
+ endTrackedLine();
688598
690135
  }
688599
690136
  /** In-place update of the compact thinking box content row (cursor-up + rewrite) */
688600
690137
  updateThinkingBox(text2, width) {
@@ -696151,7 +697688,7 @@ import {
696151
697688
  unlinkSync as unlinkSync34
696152
697689
  } from "node:fs";
696153
697690
  import { join as join168 } from "node:path";
696154
- import { createHash as createHash45 } from "node:crypto";
697691
+ import { createHash as createHash46 } from "node:crypto";
696155
697692
  function safeFilePart(value2) {
696156
697693
  return value2.replace(/[^A-Za-z0-9_.-]+/g, "_").slice(0, 80) || "telegram";
696157
697694
  }
@@ -696159,7 +697696,7 @@ function daydreamRoot(repoRoot) {
696159
697696
  return join168(repoRoot, ".omnius", "telegram-daydreams");
696160
697697
  }
696161
697698
  function sessionDir(repoRoot, sessionKey) {
696162
- const hash = createHash45("sha1").update(sessionKey).digest("hex").slice(0, 20);
697699
+ const hash = createHash46("sha1").update(sessionKey).digest("hex").slice(0, 20);
696163
697700
  return join168(daydreamRoot(repoRoot), safeFilePart(hash));
696164
697701
  }
696165
697702
  function compactLine2(value2, max = 220) {
@@ -696270,7 +697807,7 @@ function buildReplyOpportunities(input, openQuestions) {
696270
697807
  return opportunities;
696271
697808
  }
696272
697809
  function daydreamOpportunityId(input, trigger) {
696273
- return createHash45("sha1").update(`${input.sessionKey}:${input.generatedAtMs}:${trigger}`).digest("hex").slice(0, 16);
697810
+ return createHash46("sha1").update(`${input.sessionKey}:${input.generatedAtMs}:${trigger}`).digest("hex").slice(0, 16);
696274
697811
  }
696275
697812
  function clamp0115(value2) {
696276
697813
  if (!Number.isFinite(value2)) return 0;
@@ -696675,7 +698212,7 @@ function buildTelegramChannelDaydream(input, corpus, extraction, extractionCommi
696675
698212
  const seed = `${input.sessionKey}:${input.generatedAtMs}:${input.history.length}`;
696676
698213
  return {
696677
698214
  version: 3,
696678
- id: createHash45("sha1").update(seed).digest("hex").slice(0, 16),
698215
+ id: createHash46("sha1").update(seed).digest("hex").slice(0, 16),
696679
698216
  sessionKey: input.sessionKey,
696680
698217
  chatId: input.chatId,
696681
698218
  chatTitle: input.chatTitle,
@@ -696987,12 +698524,12 @@ var init_telegram_channel_dmn = __esm({
696987
698524
  });
696988
698525
 
696989
698526
  // packages/cli/src/tui/telegram-reflection-corpus.ts
696990
- import { createHash as createHash46 } from "node:crypto";
698527
+ import { createHash as createHash47 } from "node:crypto";
696991
698528
  function telegramReflectionMemoryDbPaths(repoRoot) {
696992
698529
  return omniusMemoryDbPaths(repoRoot);
696993
698530
  }
696994
698531
  function stableHash2(value2, length4 = 16) {
696995
- return createHash46("sha1").update(value2).digest("hex").slice(0, length4);
698532
+ return createHash47("sha1").update(value2).digest("hex").slice(0, length4);
696996
698533
  }
696997
698534
  function clean3(value2) {
696998
698535
  return String(value2 ?? "").replace(/\s+/g, " ").trim();
@@ -697805,7 +699342,7 @@ var init_telegram_reflection_extraction = __esm({
697805
699342
  });
697806
699343
 
697807
699344
  // packages/cli/src/tui/telegram-social-state-types.ts
697808
- import { createHash as createHash47 } from "node:crypto";
699345
+ import { createHash as createHash48 } from "node:crypto";
697809
699346
  function telegramSocialActorKey(actor) {
697810
699347
  if (!actor) return "unknown";
697811
699348
  if (typeof actor.userId === "number") return `user:${actor.userId}`;
@@ -697838,7 +699375,7 @@ function appendUnique(items, value2, max) {
697838
699375
  return next.slice(-max);
697839
699376
  }
697840
699377
  function hashTelegramSocialId(parts) {
697841
- return createHash47("sha1").update(parts.map((part) => String(part ?? "")).join(":")).digest("hex").slice(0, 16);
699378
+ return createHash48("sha1").update(parts.map((part) => String(part ?? "")).join(":")).digest("hex").slice(0, 16);
697842
699379
  }
697843
699380
  function cleanUsername(value2) {
697844
699381
  if (typeof value2 !== "string") return void 0;
@@ -698898,7 +700435,7 @@ import {
698898
700435
  } from "node:path";
698899
700436
  import { homedir as homedir56 } from "node:os";
698900
700437
  import { writeFile as writeFileAsync } from "node:fs/promises";
698901
- import { createHash as createHash48, randomBytes as randomBytes28, randomInt } from "node:crypto";
700438
+ import { createHash as createHash49, randomBytes as randomBytes28, randomInt } from "node:crypto";
698902
700439
  function formatModelBytes(bytes) {
698903
700440
  if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
698904
700441
  const units = ["B", "KB", "MB", "GB", "TB"];
@@ -700143,7 +701680,7 @@ function buildTelegramRuntimeContext(now2 = /* @__PURE__ */ new Date(), repoRoot
700143
701680
  return buildConversationRuntimeContext(now2, repoRoot);
700144
701681
  }
700145
701682
  function telegramSessionIdFromKey(sessionKey) {
700146
- return `telegram-${createHash48("sha1").update(sessionKey).digest("hex").slice(0, 16)}`;
701683
+ return `telegram-${createHash49("sha1").update(sessionKey).digest("hex").slice(0, 16)}`;
700147
701684
  }
700148
701685
  function normalizeTelegramSubAgentLimit(value2) {
700149
701686
  const parsed = typeof value2 === "number" ? value2 : typeof value2 === "string" && value2.trim() ? Number(value2.trim()) : TELEGRAM_SUB_AGENT_DEFAULT_LIMIT;
@@ -702307,7 +703844,7 @@ Telegram link integrity contract:
702307
703844
  return !!this.adminAuthChallenge && this.adminAuthChallenge.expiresAtMs > Date.now();
702308
703845
  }
702309
703846
  hashAdminAuthCode(code8) {
702310
- return createHash48("sha256").update(`omnius-telegram-admin:${code8.trim()}`).digest("hex");
703847
+ return createHash49("sha256").update(`omnius-telegram-admin:${code8.trim()}`).digest("hex");
702311
703848
  }
702312
703849
  viewIdForMessage(msg) {
702313
703850
  return `telegram-${this.sessionKeyForMessage(msg).replace(/[^A-Za-z0-9_-]/g, "-")}`;
@@ -704379,11 +705916,11 @@ ${mediaContext}` : ""
704379
705916
  return payload;
704380
705917
  }
704381
705918
  telegramConversationPath(sessionKey) {
704382
- const safe = createHash48("sha1").update(sessionKey).digest("hex").slice(0, 20);
705919
+ const safe = createHash49("sha1").update(sessionKey).digest("hex").slice(0, 20);
704383
705920
  return join170(this.telegramConversationDir, `${safe}.json`);
704384
705921
  }
704385
705922
  telegramConversationLedgerPath(sessionKey) {
704386
- const safe = createHash48("sha1").update(sessionKey).digest("hex").slice(0, 20);
705923
+ const safe = createHash49("sha1").update(sessionKey).digest("hex").slice(0, 20);
704387
705924
  return join170(this.telegramConversationDir, `${safe}.events.jsonl`);
704388
705925
  }
704389
705926
  telegramDb() {
@@ -704616,7 +706153,7 @@ ${mediaContext}` : ""
704616
706153
  relationships: Array.isArray(raw.relationships) ? raw.relationships.slice(0, TELEGRAM_ASSOCIATIVE_RELATION_LIMIT).map((fact) => this.normalizeTelegramAssociativeFact(fact)) : [],
704617
706154
  actions: Array.isArray(raw.actions) ? raw.actions.slice(-TELEGRAM_ASSOCIATIVE_ACTION_LIMIT).map((action) => ({
704618
706155
  id: String(
704619
- action.id || createHash48("sha1").update(JSON.stringify(action)).digest("hex").slice(0, 12)
706156
+ action.id || createHash49("sha1").update(JSON.stringify(action)).digest("hex").slice(0, 12)
704620
706157
  ),
704621
706158
  ts: typeof action.ts === "number" ? action.ts : Date.now(),
704622
706159
  role: action.role === "assistant" ? "assistant" : "user",
@@ -704635,7 +706172,7 @@ ${mediaContext}` : ""
704635
706172
  const now2 = Date.now();
704636
706173
  return {
704637
706174
  id: String(
704638
- raw.id || createHash48("sha1").update(text2 || String(now2)).digest("hex").slice(0, 12)
706175
+ raw.id || createHash49("sha1").update(text2 || String(now2)).digest("hex").slice(0, 12)
704639
706176
  ),
704640
706177
  text: text2,
704641
706178
  tags: Array.isArray(raw.tags) ? raw.tags.map(String).slice(0, 16) : [],
@@ -705092,7 +706629,7 @@ ${mediaContext}` : ""
705092
706629
  telegramHistoryBackfillMessageId(sessionKey, entry, index) {
705093
706630
  if (typeof entry.messageId === "number" && Number.isFinite(entry.messageId))
705094
706631
  return entry.messageId;
705095
- const digest3 = createHash48("sha1").update(
706632
+ const digest3 = createHash49("sha1").update(
705096
706633
  `${sessionKey}:${index}:${entry.role}:${entry.ts ?? ""}:${entry.text}`
705097
706634
  ).digest("hex").slice(0, 8);
705098
706635
  return -Number.parseInt(digest3, 16);
@@ -706282,7 +707819,7 @@ ${mediaContext}` : ""
706282
707819
  const now2 = entry.ts ?? Date.now();
706283
707820
  memory.updatedAt = now2;
706284
707821
  const speaker = telegramHistorySpeaker(entry);
706285
- const actionId = createHash48("sha1").update(
707822
+ const actionId = createHash49("sha1").update(
706286
707823
  `${sessionKey}:${entry.role}:${entry.messageId ?? ""}:${now2}:${entry.text}`
706287
707824
  ).digest("hex").slice(0, 16);
706288
707825
  if (!memory.actions.some((action) => action.id === actionId)) {
@@ -706445,7 +707982,7 @@ ${mediaContext}` : ""
706445
707982
  let fact = facts.find((item) => item.text.toLowerCase() === key);
706446
707983
  if (!fact) {
706447
707984
  fact = {
706448
- id: createHash48("sha1").update(`${entry.chatId ?? ""}:${key}`).digest("hex").slice(0, 12),
707985
+ id: createHash49("sha1").update(`${entry.chatId ?? ""}:${key}`).digest("hex").slice(0, 12),
706449
707986
  text: clean5,
706450
707987
  tags: telegramMemoryTags(clean5, entry.mediaSummary),
706451
707988
  speakers: [],
@@ -706530,7 +708067,7 @@ ${mediaContext}` : ""
706530
708067
  const titleTags = tags.slice(0, 4);
706531
708068
  const title = titleTags.length > 0 ? `${speaker} / ${titleTags.join(" ")}` : `${speaker} / conversation`;
706532
708069
  const card = {
706533
- id: createHash48("sha1").update(`${sessionKey}:${now2}:${speaker}:${text2}`).digest("hex").slice(0, 12),
708070
+ id: createHash49("sha1").update(`${sessionKey}:${now2}:${speaker}:${text2}`).digest("hex").slice(0, 12),
706534
708071
  title,
706535
708072
  notes: [],
706536
708073
  tags: [],
@@ -709294,7 +710831,7 @@ ${list}` : "No shared group target is currently known for this sender. Ask in th
709294
710831
  }
709295
710832
  telegramRunnerStateDir(sessionKey) {
709296
710833
  if (!this.repoRoot) return void 0;
709297
- const safe = createHash48("sha1").update(sessionKey).digest("hex").slice(0, 20);
710834
+ const safe = createHash49("sha1").update(sessionKey).digest("hex").slice(0, 20);
709298
710835
  return join170(this.repoRoot, ".omnius", "telegram-runner-state", safe);
709299
710836
  }
709300
710837
  buildTelegramAdminOverviewContext(currentSessionKey) {
@@ -717693,13 +719230,13 @@ function isLikelyAgentSpeechEcho({
717693
719230
  if (!agentTokens.length) return { likelyEcho: false, echoSimilarity: 0, reason: "no_agent_speech" };
717694
719231
  const agentComparable = agentTokens.join(" ");
717695
719232
  const heardComparable = heardTokens.join(" ");
717696
- const echoSimilarity = jaccardSimilarity(heardTokens, agentTokens);
719233
+ const echoSimilarity2 = jaccardSimilarity(heardTokens, agentTokens);
717697
719234
  const exactEcho = Boolean(heardComparable && agentComparable && (agentComparable.includes(heardComparable) || heardComparable.includes(agentComparable)));
717698
719235
  const orderedEcho = heardTokens.length >= 3 && isMostlyContainedInOrder(heardTokens, agentTokens);
717699
- const likelyEcho = echoSimilarity >= AGENT_ECHO_SIMILARITY || exactEcho || orderedEcho;
719236
+ const likelyEcho = echoSimilarity2 >= AGENT_ECHO_SIMILARITY || exactEcho || orderedEcho;
717700
719237
  return {
717701
719238
  likelyEcho,
717702
- echoSimilarity,
719239
+ echoSimilarity: echoSimilarity2,
717703
719240
  reason: likelyEcho ? "speaker_echo" : "pass"
717704
719241
  };
717705
719242
  }
@@ -719989,14 +721526,14 @@ var init_access_policy = __esm({
719989
721526
  });
719990
721527
 
719991
721528
  // packages/cli/src/api/project-preferences.ts
719992
- import { createHash as createHash49 } from "node:crypto";
721529
+ import { createHash as createHash50 } from "node:crypto";
719993
721530
  import { existsSync as existsSync162, mkdirSync as mkdirSync100, readFileSync as readFileSync133, renameSync as renameSync16, writeFileSync as writeFileSync87, unlinkSync as unlinkSync37 } from "node:fs";
719994
721531
  import { homedir as homedir58 } from "node:os";
719995
721532
  import { join as join172, resolve as resolve75 } from "node:path";
719996
721533
  import { randomUUID as randomUUID20 } from "node:crypto";
719997
721534
  function projectKey(root) {
719998
721535
  const canonical = resolve75(root);
719999
- return createHash49("sha256").update(canonical).digest("hex").slice(0, 16);
721536
+ return createHash50("sha256").update(canonical).digest("hex").slice(0, 16);
720000
721537
  }
720001
721538
  function projectDir(root) {
720002
721539
  return join172(PROJECTS_DIR, projectKey(root));
@@ -720287,7 +721824,7 @@ var init_disk_task_output = __esm({
720287
721824
  });
720288
721825
 
720289
721826
  // packages/cli/src/api/http.ts
720290
- import { createHash as createHash50 } from "node:crypto";
721827
+ import { createHash as createHash51 } from "node:crypto";
720291
721828
  function problemDetails(opts) {
720292
721829
  const p2 = {
720293
721830
  type: opts.type ?? "about:blank",
@@ -720350,7 +721887,7 @@ function paginated(items, page2, total) {
720350
721887
  }
720351
721888
  function computeEtag(payload) {
720352
721889
  const json = typeof payload === "string" ? payload : JSON.stringify(payload);
720353
- const hash = createHash50("sha1").update(json).digest("hex").slice(0, 16);
721890
+ const hash = createHash51("sha1").update(json).digest("hex").slice(0, 16);
720354
721891
  return `W/"${hash}"`;
720355
721892
  }
720356
721893
  function checkNotModified(req3, res, etag) {
@@ -739761,7 +741298,7 @@ import {
739761
741298
  closeSync as closeSync6
739762
741299
  } from "node:fs";
739763
741300
  import { randomBytes as randomBytes29, randomUUID as randomUUID21, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
739764
- import { createHash as createHash51 } from "node:crypto";
741301
+ import { createHash as createHash52 } from "node:crypto";
739765
741302
  function memoryDbPaths3(baseDir = process.cwd()) {
739766
741303
  const dir = join183(baseDir, ".omnius");
739767
741304
  return {
@@ -747930,7 +749467,7 @@ function listScheduledTasks() {
747930
749467
  );
747931
749468
  const enabled2 = typeof t2?.enabled === "boolean" ? t2.enabled : true;
747932
749469
  const realId = typeof t2?.id === "string" && t2.id ? t2.id : null;
747933
- const fallbackId = createHash51("sha1").update(`${file}#${i2}`).digest("hex").slice(0, 16);
749470
+ const fallbackId = createHash52("sha1").update(`${file}#${i2}`).digest("hex").slice(0, 16);
747934
749471
  const uid = realId || fallbackId;
747935
749472
  const key = `${uid}`;
747936
749473
  if (seen.has(key)) return;
@@ -748068,8 +749605,8 @@ function deleteScheduledById(id2) {
748068
749605
  if (typeof entry?.id === "string" && entry.id && !candidates.includes(entry.id))
748069
749606
  candidates.push(entry.id);
748070
749607
  try {
748071
- const { createHash: createHash53 } = require4("node:crypto");
748072
- const fallback = createHash53("sha1").update(`${target.file}#${target.index}`).digest("hex").slice(0, 16);
749608
+ const { createHash: createHash54 } = require4("node:crypto");
749609
+ const fallback = createHash54("sha1").update(`${target.file}#${target.index}`).digest("hex").slice(0, 16);
748073
749610
  if (!candidates.includes(fallback)) candidates.push(fallback);
748074
749611
  } catch {
748075
749612
  }
@@ -750306,7 +751843,7 @@ import { cwd } from "node:process";
750306
751843
  import { resolve as resolve78, join as join185, dirname as dirname56, extname as extname22, relative as relative22, sep as sep7 } from "node:path";
750307
751844
  import { createRequire as createRequire9 } from "node:module";
750308
751845
  import { fileURLToPath as fileURLToPath24 } from "node:url";
750309
- import { createHash as createHash52 } from "node:crypto";
751846
+ import { createHash as createHash53 } from "node:crypto";
750310
751847
  import {
750311
751848
  readFileSync as readFileSync142,
750312
751849
  writeFileSync as writeFileSync94,
@@ -751240,7 +752777,7 @@ function truncateSubAgentViewText(s2, n2) {
751240
752777
  return s2.length > n2 ? `${s2.slice(0, n2)}…` : s2;
751241
752778
  }
751242
752779
  function childAgentTaskHash(task) {
751243
- return createHash52("sha256").update(task).digest("hex").slice(0, 12);
752780
+ return createHash53("sha256").update(task).digest("hex").slice(0, 12);
751244
752781
  }
751245
752782
  function stripAnsiForParentContext(value2) {
751246
752783
  return value2.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
@@ -756345,6 +757882,12 @@ This is an independent background session started from /background.`
756345
757882
  process.stdout.on("resize", () => {
756346
757883
  statusBar.handleResize();
756347
757884
  setTermSize(process.stdout.rows ?? 24, process.stdout.columns ?? 80);
757885
+ if (!isNeovimActive()) {
757886
+ try {
757887
+ streamRenderer.onResize();
757888
+ } catch {
757889
+ }
757890
+ }
756348
757891
  if (isNeovimActive()) {
756349
757892
  const contentRows = statusBar.isActive ? statusBar.availableContentRows : Math.max(5, termRows() - 6);
756350
757893
  resizeNeovim(termCols(), contentRows);
@@ -760561,13 +762104,13 @@ ${taskInput}`;
760561
762104
  writeContent(() => renderError(errMsg));
760562
762105
  if (failureStore) {
760563
762106
  try {
760564
- const { createHash: createHash53 } = await import("node:crypto");
762107
+ const { createHash: createHash54 } = await import("node:crypto");
760565
762108
  failureStore.insert({
760566
762109
  taskId: "",
760567
762110
  sessionId: `${Date.now()}`,
760568
762111
  repoRoot,
760569
762112
  failureType: "runtime-error",
760570
- fingerprint: createHash53("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
762113
+ fingerprint: createHash54("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
760571
762114
  filePath: null,
760572
762115
  errorMessage: errMsg.slice(0, 500),
760573
762116
  context: null,