omnius 1.0.545 → 1.0.546

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;
@@ -566130,6 +566191,165 @@ var init_textSanitize = __esm({
566130
566191
  }
566131
566192
  });
566132
566193
 
566194
+ // packages/orchestrator/dist/text-echo-guard.js
566195
+ function normalizeForEcho(text2) {
566196
+ 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();
566197
+ }
566198
+ function echoSimilarity(a2, b) {
566199
+ const sa = shingles(a2);
566200
+ const sb = shingles(b);
566201
+ if (sa.size === 0 || sb.size === 0) {
566202
+ return a2 === b && a2.length > 0 ? 1 : 0;
566203
+ }
566204
+ let inter = 0;
566205
+ for (const s2 of sa)
566206
+ if (sb.has(s2))
566207
+ inter++;
566208
+ const union = sa.size + sb.size - inter;
566209
+ return union === 0 ? 0 : inter / union;
566210
+ }
566211
+ function shingles(normalized, k = 3) {
566212
+ const words = normalized.split(" ").filter(Boolean);
566213
+ const out = /* @__PURE__ */ new Set();
566214
+ for (let i2 = 0; i2 + k <= words.length; i2++) {
566215
+ out.add(words.slice(i2, i2 + k).join(" "));
566216
+ }
566217
+ return out;
566218
+ }
566219
+ function contentAsText(m2) {
566220
+ if (typeof m2.content === "string")
566221
+ return m2.content;
566222
+ return null;
566223
+ }
566224
+ function isEligible(m2, minLength) {
566225
+ if (m2.role !== "assistant")
566226
+ return false;
566227
+ if (Array.isArray(m2.tool_calls) && m2.tool_calls.length > 0)
566228
+ return false;
566229
+ const text2 = contentAsText(m2);
566230
+ if (!text2)
566231
+ return false;
566232
+ if (text2.startsWith(COLLAPSE_MARKER))
566233
+ return false;
566234
+ return normalizeForEcho(text2).length >= minLength;
566235
+ }
566236
+ var COLLAPSE_MARKER, DEFAULTS, TextEchoGuard;
566237
+ var init_text_echo_guard = __esm({
566238
+ "packages/orchestrator/dist/text-echo-guard.js"() {
566239
+ "use strict";
566240
+ COLLAPSE_MARKER = "[Superseded near-duplicate plan removed";
566241
+ DEFAULTS = {
566242
+ similarityThreshold: 0.6,
566243
+ minLength: 80,
566244
+ window: 6
566245
+ };
566246
+ TextEchoGuard = class {
566247
+ threshold;
566248
+ minLength;
566249
+ window;
566250
+ /** Recent normalized text-only assistant messages (raw preview kept for messaging). */
566251
+ recent = [];
566252
+ streak = 0;
566253
+ constructor(options2 = {}) {
566254
+ this.threshold = options2.similarityThreshold ?? DEFAULTS.similarityThreshold;
566255
+ this.minLength = options2.minLength ?? DEFAULTS.minLength;
566256
+ this.window = options2.window ?? DEFAULTS.window;
566257
+ }
566258
+ /**
566259
+ * Observe a new text-only assistant message. Records it and reports whether
566260
+ * it echoes a recent one. Call ONLY for text-only turns (no tool_calls).
566261
+ */
566262
+ observe(text2) {
566263
+ const normalized = normalizeForEcho(text2);
566264
+ if (normalized.length < this.minLength) {
566265
+ return { isEcho: false, echoCount: this.streak, similarity: 0, matchedPreview: "" };
566266
+ }
566267
+ let best = 0;
566268
+ let matchedPreview = "";
566269
+ for (const prev of this.recent) {
566270
+ const sim = echoSimilarity(normalized, prev.normalized);
566271
+ if (sim > best) {
566272
+ best = sim;
566273
+ matchedPreview = prev.preview;
566274
+ }
566275
+ }
566276
+ const isEcho = best >= this.threshold;
566277
+ this.streak = isEcho ? this.streak + 1 : 0;
566278
+ this.recent.push({ normalized, preview: text2.slice(0, 160) });
566279
+ if (this.recent.length > this.window)
566280
+ this.recent.shift();
566281
+ return {
566282
+ isEcho,
566283
+ echoCount: this.streak,
566284
+ similarity: best,
566285
+ matchedPreview
566286
+ };
566287
+ }
566288
+ /** A real tool call happened — the loop is broken; reset escalation. */
566289
+ noteToolProgress() {
566290
+ this.streak = 0;
566291
+ }
566292
+ /**
566293
+ * Remove the attractor from the live prompt: for every pair of text-only
566294
+ * assistant messages where an EARLIER one is a near-duplicate of a LATER
566295
+ * one, replace the earlier one's content with a one-line stub. The latest
566296
+ * copy always survives. Safe to call repeatedly (stubs are skipped).
566297
+ *
566298
+ * Returns the number of messages collapsed.
566299
+ */
566300
+ collapseEchoes(messages2) {
566301
+ const eligible = [];
566302
+ for (let i2 = 0; i2 < messages2.length; i2++) {
566303
+ const m2 = messages2[i2];
566304
+ if (isEligible(m2, this.minLength)) {
566305
+ eligible.push({ idx: i2, normalized: normalizeForEcho(m2.content) });
566306
+ }
566307
+ }
566308
+ if (eligible.length < 2)
566309
+ return 0;
566310
+ let collapsed = 0;
566311
+ const survivors = [];
566312
+ for (let j = eligible.length - 1; j >= 0; j--) {
566313
+ const cur = eligible[j];
566314
+ const echoesSurvivor = survivors.some((s2) => echoSimilarity(cur.normalized, s2) >= this.threshold);
566315
+ if (echoesSurvivor) {
566316
+ const msg = messages2[cur.idx];
566317
+ const preview = (contentAsText(msg) ?? "").slice(0, 100).replace(/\s+/g, " ");
566318
+ 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.]`;
566319
+ collapsed++;
566320
+ } else {
566321
+ survivors.push(cur.normalized);
566322
+ }
566323
+ }
566324
+ return collapsed;
566325
+ }
566326
+ /**
566327
+ * Escalating pattern-breaker to inject INSTEAD of the generic
566328
+ * "Continue working…" nudge (which, being verbatim-identical each turn, is
566329
+ * itself part of the repetition attractor).
566330
+ */
566331
+ buildIntervention(obs) {
566332
+ const pct2 = Math.round(obs.similarity * 100);
566333
+ const quoted = obs.matchedPreview.replace(/\s+/g, " ").slice(0, 120);
566334
+ if (obs.echoCount <= 1) {
566335
+ 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.`;
566336
+ }
566337
+ if (obs.echoCount === 2) {
566338
+ 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:
566339
+ 1. Call a tool that mutates or inspects the workspace (file_write / shell / file_read).
566340
+ 2. If genuinely blocked, call task_complete with a summary that names the exact blocker.
566341
+ Any further text-only response will be discarded.`;
566342
+ }
566343
+ 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.`;
566344
+ }
566345
+ /** Test/telemetry helper. */
566346
+ snapshot() {
566347
+ return { streak: this.streak, windowSize: this.recent.length };
566348
+ }
566349
+ };
566350
+ }
566351
+ });
566352
+
566133
566353
  // packages/orchestrator/dist/permissionRuleset.js
566134
566354
  function checkDoomLoop(context2) {
566135
566355
  const history = context2.toolCallHistory;
@@ -567254,7 +567474,109 @@ function reconcileCompletedTodosWithEvidence(input) {
567254
567474
  downgrades
567255
567475
  };
567256
567476
  }
567257
- var NON_WORK_TOOLS, VISUAL_EVIDENCE_TOOLS, AUDIO_EVIDENCE_TOOLS;
567477
+ function extractPathTokens(content) {
567478
+ const withSeparator = [];
567479
+ const bareFilenames = [];
567480
+ const stripped = content.replace(/https?:\/\/\S+/g, " ").replace(/`/g, " ");
567481
+ for (const raw of stripped.match(PATH_TOKEN_RE) ?? []) {
567482
+ const hadSeparator = raw.includes("/");
567483
+ const token = raw.replace(/[.,;:!?)]+$/, "").replace(/\/+$/, "");
567484
+ if (!token || token.length < 3)
567485
+ continue;
567486
+ if (/^v?\d+(\.\d+)*$/i.test(token))
567487
+ continue;
567488
+ if (NON_FILE_SUFFIXES.has(token.toLowerCase()))
567489
+ continue;
567490
+ if (hadSeparator)
567491
+ withSeparator.push(token);
567492
+ else
567493
+ bareFilenames.push(token);
567494
+ }
567495
+ return { withSeparator, bareFilenames };
567496
+ }
567497
+ function looksLikeDirectory(pathToken) {
567498
+ const last2 = pathToken.split("/").pop() ?? "";
567499
+ return !last2.includes(".");
567500
+ }
567501
+ function reconcileRestoredTodosWithDisk(input) {
567502
+ const cleaned = [];
567503
+ let droppedCorrupt = 0;
567504
+ for (const todo of input.todos) {
567505
+ const valid = todo && typeof todo.content === "string" && todo.content.trim().length > 0 && typeof todo.status === "string" && ["pending", "in_progress", "completed", "blocked"].includes(todo.status);
567506
+ if (valid)
567507
+ cleaned.push({ ...todo });
567508
+ else
567509
+ droppedCorrupt++;
567510
+ }
567511
+ const index = buildTodoTruthIndex(cleaned);
567512
+ const downgrades = [];
567513
+ const contextDirsFor = (todo) => {
567514
+ const dirs = [];
567515
+ let cur = todo;
567516
+ const seen = /* @__PURE__ */ new Set();
567517
+ while (cur) {
567518
+ if (cur.id && seen.has(cur.id))
567519
+ break;
567520
+ if (cur.id)
567521
+ seen.add(cur.id);
567522
+ const { withSeparator } = extractPathTokens(cur.content);
567523
+ for (const p2 of withSeparator) {
567524
+ if (looksLikeDirectory(p2))
567525
+ dirs.push(p2);
567526
+ }
567527
+ cur = cur.parentId ? index.byId.get(cur.parentId) : void 0;
567528
+ }
567529
+ return dirs;
567530
+ };
567531
+ for (const todo of cleaned) {
567532
+ if (todo.status !== "completed")
567533
+ continue;
567534
+ const declared = (todo.declaredArtifacts ?? []).filter((a2) => typeof a2 === "string" && a2.trim().length > 0);
567535
+ const { withSeparator, bareFilenames } = extractPathTokens(todo.content);
567536
+ const contextDirs = contextDirsFor(todo);
567537
+ const candidates = /* @__PURE__ */ new Set();
567538
+ for (const a2 of declared)
567539
+ candidates.add(input.resolvePath(input.workingDir, a2));
567540
+ for (const p2 of withSeparator)
567541
+ candidates.add(input.resolvePath(input.workingDir, p2));
567542
+ for (const f2 of bareFilenames) {
567543
+ candidates.add(input.resolvePath(input.workingDir, f2));
567544
+ for (const dir of contextDirs) {
567545
+ candidates.add(input.resolvePath(input.workingDir, dir, f2));
567546
+ }
567547
+ }
567548
+ if (candidates.size === 0)
567549
+ continue;
567550
+ let anyExists = false;
567551
+ for (const abs of candidates) {
567552
+ if (input.exists(abs)) {
567553
+ anyExists = true;
567554
+ break;
567555
+ }
567556
+ }
567557
+ if (anyExists)
567558
+ continue;
567559
+ const shown = [...candidates].slice(0, 4).join(", ");
567560
+ 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.`;
567561
+ downgrades.push({
567562
+ id: todo.id,
567563
+ content: todo.content,
567564
+ from: "completed",
567565
+ to: "pending",
567566
+ blocker,
567567
+ evidence: `disk verification at restore: 0/${candidates.size} candidate path(s) exist`
567568
+ });
567569
+ todo.status = "pending";
567570
+ todo.blocker = blocker;
567571
+ }
567572
+ return {
567573
+ todos: cleaned,
567574
+ changed: downgrades.length > 0 || droppedCorrupt > 0,
567575
+ downgrades,
567576
+ droppedCorrupt
567577
+ };
567578
+ }
567579
+ var NON_WORK_TOOLS, VISUAL_EVIDENCE_TOOLS, AUDIO_EVIDENCE_TOOLS, PATH_TOKEN_RE, NON_FILE_SUFFIXES;
567258
567580
  var init_todoTruth = __esm({
567259
567581
  "packages/orchestrator/dist/todoTruth.js"() {
567260
567582
  "use strict";
@@ -567278,6 +567600,13 @@ var init_todoTruth = __esm({
567278
567600
  "transcribe_url",
567279
567601
  "video_understand"
567280
567602
  ]);
567603
+ PATH_TOKEN_RE = /[A-Za-z0-9_.~-]*\/[A-Za-z0-9_.\/~-]*|[A-Za-z0-9_-]+\.[A-Za-z0-9]{1,8}\b/g;
567604
+ NON_FILE_SUFFIXES = /* @__PURE__ */ new Set([
567605
+ // common sentence-token false positives ("e.g.", version numbers, hosts)
567606
+ "e.g",
567607
+ "i.e",
567608
+ "vs"
567609
+ ]);
567281
567610
  }
567282
567611
  });
567283
567612
 
@@ -578759,6 +579088,175 @@ var init_evidenceLedger = __esm({
578759
579088
  }
578760
579089
  });
578761
579090
 
579091
+ // packages/orchestrator/dist/observationLedger.js
579092
+ function hashText(text2) {
579093
+ let h = 2166136261;
579094
+ for (let i2 = 0; i2 < text2.length; i2++) {
579095
+ h ^= text2.charCodeAt(i2);
579096
+ h = Math.imul(h, 16777619);
579097
+ }
579098
+ return (h >>> 0).toString(16);
579099
+ }
579100
+ function boundOutput(output) {
579101
+ if (output.length <= ENTRY_FULL_CHARS)
579102
+ return output;
579103
+ const head = output.slice(0, ENTRY_HEAD_CHARS);
579104
+ const tail = output.slice(-ENTRY_TAIL_CHARS);
579105
+ return `${head}
579106
+ … (${output.length - ENTRY_HEAD_CHARS - ENTRY_TAIL_CHARS} chars elided — full output was in the turn it ran) …
579107
+ ${tail}`;
579108
+ }
579109
+ function labelFor(tool, args) {
579110
+ const a2 = args ?? {};
579111
+ const pick = (...keys) => {
579112
+ for (const k of keys) {
579113
+ const v = a2[k];
579114
+ if (typeof v === "string" && v.trim())
579115
+ return v.trim();
579116
+ }
579117
+ return "";
579118
+ };
579119
+ let detail = "";
579120
+ switch (tool) {
579121
+ case "shell":
579122
+ case "shell_async":
579123
+ detail = pick("command", "cmd");
579124
+ break;
579125
+ case "web_fetch":
579126
+ detail = pick("url", "target");
579127
+ break;
579128
+ case "web_search":
579129
+ detail = pick("query", "q");
579130
+ break;
579131
+ case "list_directory":
579132
+ case "file_explore":
579133
+ detail = pick("path") || ".";
579134
+ break;
579135
+ case "grep_search":
579136
+ case "find_files":
579137
+ detail = [pick("pattern", "query"), pick("path")].filter(Boolean).join(" in ");
579138
+ break;
579139
+ default:
579140
+ detail = pick("path", "url", "query", "command", "target");
579141
+ }
579142
+ const flat = detail.replace(/\s+/g, " ").slice(0, 120);
579143
+ return flat ? `${tool}: ${flat}` : tool;
579144
+ }
579145
+ var SKIP_TOOLS, ENTRY_FULL_CHARS, ENTRY_HEAD_CHARS, ENTRY_TAIL_CHARS, MAX_ENTRIES2, ObservationLedger;
579146
+ var init_observationLedger = __esm({
579147
+ "packages/orchestrator/dist/observationLedger.js"() {
579148
+ "use strict";
579149
+ SKIP_TOOLS = /* @__PURE__ */ new Set([
579150
+ "file_read",
579151
+ // EvidenceLedger's domain
579152
+ "todo_write",
579153
+ "todo_read",
579154
+ "task_complete",
579155
+ "memory_read",
579156
+ "memory_write",
579157
+ "working_notes"
579158
+ ]);
579159
+ ENTRY_FULL_CHARS = 1200;
579160
+ ENTRY_HEAD_CHARS = 700;
579161
+ ENTRY_TAIL_CHARS = 300;
579162
+ MAX_ENTRIES2 = 24;
579163
+ ObservationLedger = class {
579164
+ entries = /* @__PURE__ */ new Map();
579165
+ record(input) {
579166
+ const { tool, fingerprint, output, success, turn } = input;
579167
+ if (!fingerprint || SKIP_TOOLS.has(tool))
579168
+ return;
579169
+ const trimmed = (output ?? "").trim();
579170
+ if (!trimmed)
579171
+ return;
579172
+ const outputHash = hashText(trimmed);
579173
+ const existing = this.entries.get(fingerprint);
579174
+ if (existing) {
579175
+ const identical = existing.outputHash === outputHash;
579176
+ this.entries.delete(fingerprint);
579177
+ this.entries.set(fingerprint, {
579178
+ ...existing,
579179
+ output: boundOutput(trimmed),
579180
+ fullChars: trimmed.length,
579181
+ success,
579182
+ lastTurn: turn,
579183
+ runs: existing.runs + 1,
579184
+ identicalRuns: identical ? existing.identicalRuns + 1 : 1,
579185
+ outputHash
579186
+ });
579187
+ return;
579188
+ }
579189
+ this.entries.set(fingerprint, {
579190
+ fingerprint,
579191
+ tool,
579192
+ label: labelFor(tool, input.args),
579193
+ output: boundOutput(trimmed),
579194
+ fullChars: trimmed.length,
579195
+ success,
579196
+ lastTurn: turn,
579197
+ runs: 1,
579198
+ identicalRuns: 1,
579199
+ outputHash
579200
+ });
579201
+ while (this.entries.size > MAX_ENTRIES2) {
579202
+ const oldest = this.entries.keys().next().value;
579203
+ if (oldest === void 0)
579204
+ break;
579205
+ this.entries.delete(oldest);
579206
+ }
579207
+ }
579208
+ /** Consecutive identical-output executions for a fingerprint (0 if unseen). */
579209
+ identicalRunsFor(fingerprint) {
579210
+ return this.entries.get(fingerprint)?.identicalRuns ?? 0;
579211
+ }
579212
+ size() {
579213
+ return this.entries.size;
579214
+ }
579215
+ clear() {
579216
+ this.entries.clear();
579217
+ }
579218
+ /**
579219
+ * Render the CURRENT OBSERVED STATE block for the frame. Newest first,
579220
+ * bounded to maxChars. Every entry shows outcome, repeat counts, and the
579221
+ * actual output — the ground truth the model must reason from.
579222
+ */
579223
+ renderBlock(maxChars = 5e3) {
579224
+ if (this.entries.size === 0)
579225
+ return null;
579226
+ const newestFirst = [...this.entries.values()].reverse();
579227
+ const lines = [
579228
+ "[CURRENT OBSERVED STATE — latest output of each distinct tool call this run]",
579229
+ "This is the ground truth your tools actually returned (regenerated every turn; survives compaction).",
579230
+ "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.",
579231
+ ""
579232
+ ];
579233
+ let used = lines.join("\n").length;
579234
+ for (const e2 of newestFirst) {
579235
+ const outcome = e2.success ? "ok" : "FAILED";
579236
+ 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)` : "";
579237
+ const header = `▸ [${outcome}] ${e2.label} — turn ${e2.lastTurn}${repeat}`;
579238
+ const body = e2.output.split("\n").map((l2) => ` ${l2}`).join("\n");
579239
+ const chunk = `${header}
579240
+ ${body}
579241
+ `;
579242
+ if (used + chunk.length > maxChars) {
579243
+ const stub = `▸ [${outcome}] ${e2.label} — turn ${e2.lastTurn}${repeat} (output elided for budget)
579244
+ `;
579245
+ if (used + stub.length <= maxChars) {
579246
+ lines.push(stub);
579247
+ used += stub.length;
579248
+ }
579249
+ continue;
579250
+ }
579251
+ lines.push(chunk);
579252
+ used += chunk.length;
579253
+ }
579254
+ return lines.join("\n");
579255
+ }
579256
+ };
579257
+ }
579258
+ });
579259
+
578762
579260
  // packages/orchestrator/dist/contextWindowDump.js
578763
579261
  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
579262
  import { homedir as homedir35 } from "node:os";
@@ -581254,7 +581752,7 @@ var init_focusSupervisor = __esm({
581254
581752
  });
581255
581753
 
581256
581754
  // packages/orchestrator/dist/convergence-breaker.js
581257
- var InMemoryConvergenceStore, DEFAULTS, ConvergenceBreaker;
581755
+ var InMemoryConvergenceStore, DEFAULTS2, ConvergenceBreaker;
581258
581756
  var init_convergence_breaker = __esm({
581259
581757
  "packages/orchestrator/dist/convergence-breaker.js"() {
581260
581758
  "use strict";
@@ -581271,7 +581769,7 @@ var init_convergence_breaker = __esm({
581271
581769
  return [...this.map.values()];
581272
581770
  }
581273
581771
  };
581274
- DEFAULTS = { warnRound: 2, stallRound: 3, abandonRound: 5 };
581772
+ DEFAULTS2 = { warnRound: 2, stallRound: 3, abandonRound: 5 };
581275
581773
  ConvergenceBreaker = class {
581276
581774
  warnRound;
581277
581775
  stallRound;
@@ -581290,9 +581788,9 @@ var init_convergence_breaker = __esm({
581290
581788
  /** Last verification signal (error count) seen per family, for delta-based progress. */
581291
581789
  lastSignal = /* @__PURE__ */ new Map();
581292
581790
  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);
581791
+ this.warnRound = Math.max(1, options2.warnRound ?? DEFAULTS2.warnRound);
581792
+ this.stallRound = Math.max(this.warnRound + 1, options2.stallRound ?? DEFAULTS2.stallRound);
581793
+ this.abandonRound = Math.max(this.stallRound + 1, options2.abandonRound ?? DEFAULTS2.abandonRound);
581296
581794
  this.store = options2.store ?? new InMemoryConvergenceStore();
581297
581795
  }
581298
581796
  /**
@@ -586048,7 +586546,7 @@ function formatStagnantLine(c9, critical) {
586048
586546
  const tag = critical ? "STAGNANT-CRIT" : "STAGNANT";
586049
586547
  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
586548
  }
586051
- var ERROR_PATTERNS, DEFAULTS2, ErrorClusterTracker;
586549
+ var ERROR_PATTERNS, DEFAULTS3, ErrorClusterTracker;
586052
586550
  var init_errorClusterTracker = __esm({
586053
586551
  "packages/orchestrator/dist/errorClusterTracker.js"() {
586054
586552
  "use strict";
@@ -586161,7 +586659,7 @@ RECOVERY: cd to the directory containing '${file}', run a plain install with no
586161
586659
  }
586162
586660
  }
586163
586661
  ];
586164
- DEFAULTS2 = {
586662
+ DEFAULTS3 = {
586165
586663
  warnAttempts: 3,
586166
586664
  criticalAttempts: 5,
586167
586665
  cooldownAttempts: 2,
@@ -586175,7 +586673,7 @@ RECOVERY: cd to the directory containing '${file}', run a plain install with no
586175
586673
  // key → observations counter at last emit
586176
586674
  observationCounter = 0;
586177
586675
  constructor(options2 = {}) {
586178
- this.opts = { ...DEFAULTS2, ...options2 };
586676
+ this.opts = { ...DEFAULTS3, ...options2 };
586179
586677
  this.now = options2.now ?? Date.now;
586180
586678
  }
586181
586679
  /**
@@ -587104,6 +587602,7 @@ var init_agenticRunner = __esm({
587104
587602
  "use strict";
587105
587603
  init_contextBudget();
587106
587604
  init_textSanitize();
587605
+ init_text_echo_guard();
587107
587606
  init_permissionRuleset();
587108
587607
  init_steeringIntake();
587109
587608
  init_completionLedger();
@@ -587157,6 +587656,7 @@ var init_agenticRunner = __esm({
587157
587656
  init_context_fabric();
587158
587657
  init_context_compiler();
587159
587658
  init_evidenceLedger();
587659
+ init_observationLedger();
587160
587660
  init_trajectory_checkpoint();
587161
587661
  init_adversaryStream();
587162
587662
  init_contextWindowDump();
@@ -587480,6 +587980,23 @@ var init_agenticRunner = __esm({
587480
587980
  // Loop Intervention escalation path. Reset when repetition score
587481
587981
  // drops below the recovery threshold (0.2).
587482
587982
  _smaFiredThisLoop = false;
587983
+ // ROOT CAUSE FIX: one-shot system note describing restored-todo claims that
587984
+ // were contradicted by the disk at session start. Injected into the initial
587985
+ // context so the model starts from a truthful world model instead of
587986
+ // discovering the contradiction through failed discovery loops.
587987
+ _restoredTodoVerificationNote = null;
587988
+ // ECHO-1: assistant text-echo guard (mode-collapse breaker). Every other
587989
+ // loop defense keys off the tool-call log; this one detects the tool-free
587990
+ // failure mode where the model restates the same text-only plan turn after
587991
+ // turn (personaplex post-mortem: consecutive assistant messages at
587992
+ // 0.77–1.00 similarity, zero tool calls). Detects echoes, collapses the
587993
+ // earlier duplicates out of the live context (removing the attractor), and
587994
+ // requests a one-shot sampling perturbation for the next completion.
587995
+ _textEchoGuard = new TextEchoGuard();
587996
+ // Turns remaining with a temperature floor applied to knock a greedy
587997
+ // decoder off a repetition attractor. Set on echo detection; decremented
587998
+ // when a request is built.
587999
+ _echoTempBoostTurns = 0;
587483
588000
  // REG-50: same-file write-thrash detector cooldown. Once fired, give
587484
588001
  // the agent 8 turns to break out before re-firing. Distinct from REG-44
587485
588002
  // because the failure shape is different (writes >> reads, but stuck
@@ -587729,6 +588246,11 @@ var init_agenticRunner = __esm({
587729
588246
  // sees the evidence it already has instead of re-deriving it. See
587730
588247
  // evidenceLedger.ts.
587731
588248
  _evidenceLedger = new EvidenceLedger();
588249
+ // OBS-1: durable "current observed state" for non-file_read tool outputs
588250
+ // (shell/web_fetch/list_directory/…). EvidenceLedger's counterpart for the
588251
+ // observation channels that were previously invisible after compaction —
588252
+ // the model must see the raw outputs it is reasoning about, every turn.
588253
+ _observationLedger = new ObservationLedger();
587732
588254
  // Generative, inference-driven adversary running as an async memory stream
587733
588255
  // adjacent to the main loop. Initialized per run when the step critic is
587734
588256
  // enabled and a backend is available. See adversaryStream.ts.
@@ -594276,6 +594798,7 @@ ${String(concreteGoal).replace(/\s+/g, " ").trim().slice(0, 1200)}` : null
594276
594798
  ].filter((block) => Boolean(block)));
594277
594799
  const trajectoryBlock = this.options.trajectoryCheckpoint === "shadow" ? null : trajectoryCheckpoint ? renderTrajectoryCheckpoint(trajectoryCheckpoint) : null;
594278
594800
  const toolCacheBlock = recentToolResults ? this._renderKnowledgeBlock(recentToolResults) : null;
594801
+ const observationBlock = process.env["OMNIUS_DISABLE_OBSERVATION_FRAME"] === "1" ? null : this._observationLedger.renderBlock(5e3);
594279
594802
  const anchorsBlock = this.surfaceAnchors(messages2);
594280
594803
  const pprMemoryBlock = this._lastPprMemoryLines.length > 0 ? `[Associative Memory - related prior experience]
594281
594804
  ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
@@ -594400,6 +594923,19 @@ ${this._lastPprMemoryLines.slice(0, 5).join("\n")}` : null;
594400
594923
  createdTurn: turn,
594401
594924
  ttlTurns: 1
594402
594925
  }),
594926
+ // OBS-1: current observed state — the actual latest OUTPUT of each
594927
+ // distinct non-file_read tool call. Higher priority than the names-only
594928
+ // tool cache: the substance of what tools returned is more decision-
594929
+ // relevant than the list of what ran. Survives compaction because it is
594930
+ // regenerated from the ledger every turn.
594931
+ signalFromBlock("tool_cache", "turn.observed-state", observationBlock, {
594932
+ id: "observed-state",
594933
+ dedupeKey: "turn.observed-state",
594934
+ semanticKey: "context.observed-state",
594935
+ priority: 94,
594936
+ createdTurn: turn,
594937
+ ttlTurns: 1
594938
+ }),
594403
594939
  signalFromBlock("memory", "turn.ppr-memory", pprMemoryBlock, {
594404
594940
  id: "ppr-memory",
594405
594941
  dedupeKey: "turn.ppr-memory",
@@ -596448,6 +596984,7 @@ Respond with the assessment and take the selected evidence-backed action.`;
596448
596984
  this._lastSurfacedAnchorIds.clear();
596449
596985
  this._contextLedger = new ContextLedger();
596450
596986
  this._evidenceLedger = new EvidenceLedger();
596987
+ this._observationLedger = new ObservationLedger();
596451
596988
  this._lastContextFrameDiagnostics = null;
596452
596989
  this._lastContextPressureSnapshot = null;
596453
596990
  this._lastFocusContextSnapshot = null;
@@ -596613,6 +597150,45 @@ Respond with the assessment and take the selected evidence-backed action.`;
596613
597150
  verbose: false
596614
597151
  });
596615
597152
  await this._initializeGitProgressBaseline();
597153
+ this._restoredTodoVerificationNote = null;
597154
+ try {
597155
+ const restored = process.env["OMNIUS_DISABLE_RESTORED_TODO_VERIFY"] === "1" ? null : this.readSessionTodos();
597156
+ if (restored && restored.length > 0) {
597157
+ const verification = reconcileRestoredTodosWithDisk({
597158
+ todos: restored,
597159
+ workingDir: this.authoritativeWorkingDirectory(),
597160
+ exists: (p2) => _fsExistsSync(p2),
597161
+ resolvePath: (...segments) => _pathResolve(...segments)
597162
+ });
597163
+ if (verification.changed) {
597164
+ writeTodos(this._sessionId, verification.todos.map((t2) => ({
597165
+ id: t2.id,
597166
+ content: t2.content,
597167
+ status: t2.status,
597168
+ parentId: t2.parentId,
597169
+ blocker: t2.blocker,
597170
+ verifyCommand: t2.verifyCommand,
597171
+ declaredArtifacts: t2.declaredArtifacts
597172
+ })));
597173
+ const lines = verification.downgrades.slice(0, 6).map((d2) => `- "${d2.content.slice(0, 90)}": ${d2.from} -> ${d2.to} (${d2.evidence})`);
597174
+ if (verification.downgrades.length > 0) {
597175
+ this._restoredTodoVerificationNote = [
597176
+ `[RESTORED TODO VERIFICATION]`,
597177
+ `This session restored a todo list from a prior run. ${verification.downgrades.length} completed claim(s) were contradicted by the local disk and downgraded:`,
597178
+ ...lines,
597179
+ ``,
597180
+ `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.`
597181
+ ].join("\n");
597182
+ }
597183
+ this.emit({
597184
+ type: "status",
597185
+ content: `Restored-todo disk verification: ${verification.downgrades.length} claim(s) downgraded, ${verification.droppedCorrupt} corrupt entr${verification.droppedCorrupt === 1 ? "y" : "ies"} dropped`,
597186
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
597187
+ });
597188
+ }
597189
+ }
597190
+ } catch {
597191
+ }
596616
597192
  this._emitModelResolutionTelemetry("main");
596617
597193
  void this._hookManager.runSessionHook("session_start", this._sessionId).catch(() => {
596618
597194
  });
@@ -596848,6 +597424,12 @@ TASK: ${scrubbedTask}` : scrubbedTask;
596848
597424
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
596849
597425
  });
596850
597426
  }
597427
+ if (this._restoredTodoVerificationNote) {
597428
+ messages2.splice(messages2.length - 1, 0, {
597429
+ role: "system",
597430
+ content: this._restoredTodoVerificationNote
597431
+ });
597432
+ }
596851
597433
  this._phaseMessageStartIdx = messages2.length;
596852
597434
  if (process.env["OMNIUS_DISABLE_DECOMP1"] !== "1") {
596853
597435
  try {
@@ -597500,6 +598082,16 @@ ${lastCompletionGateFeedback.trim().slice(0, 4e3)}` : ""
597500
598082
  });
597501
598083
  }
597502
598084
  }
598085
+ if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
598086
+ const restoredCollapsed = this._textEchoGuard.collapseEchoes(messages2);
598087
+ if (restoredCollapsed > 0) {
598088
+ this.emit({
598089
+ type: "status",
598090
+ content: `ECHO-1: collapsed ${restoredCollapsed} near-duplicate assistant plan(s) from restored transcript before first turn`,
598091
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
598092
+ });
598093
+ }
598094
+ }
597503
598095
  for (let turn = 0; turn < turnCap; turn++) {
597504
598096
  clearTurnState(this._appState);
597505
598097
  this._maybeApplyThinkGuard();
@@ -599070,10 +599662,13 @@ ${memoryLines.join("\n")}`
599070
599662
  const { maxOutputTokens: effectiveMaxTokens } = this.contextLimits();
599071
599663
  this.gcSystemMessages(requestMessages);
599072
599664
  requestMessages = this._prepareModelFacingMessages(requestMessages, turn);
599665
+ const echoBoostedTemp = this._echoTempBoostTurns > 0 ? Math.max(this.options.temperature ?? 0, 0.7) : this.options.temperature;
599666
+ if (this._echoTempBoostTurns > 0)
599667
+ this._echoTempBoostTurns--;
599073
599668
  const chatRequest = {
599074
599669
  messages: requestMessages,
599075
599670
  tools: toolDefs,
599076
- temperature: this.options.temperature,
599671
+ temperature: echoBoostedTemp,
599077
599672
  maxTokens: effectiveMaxTokens,
599078
599673
  timeoutMs: boundedRequestTimeoutMs()
599079
599674
  };
@@ -599479,6 +600074,7 @@ ${memoryLines.join("\n")}`
599479
600074
  if (msg.toolCalls && msg.toolCalls.length > 0) {
599480
600075
  consecutiveTextOnly = 0;
599481
600076
  consecutiveThinkOnly = 0;
600077
+ this._textEchoGuard.noteToolProgress();
599482
600078
  msg.toolCalls = this._dedupeToolCallsForResponse(msg.toolCalls, turn);
599483
600079
  if (msg.toolCalls.length === 0) {
599484
600080
  messages2.push({
@@ -602959,6 +603555,30 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
602959
603555
  });
602960
603556
  break;
602961
603557
  }
603558
+ if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
603559
+ const echoObs = this._textEchoGuard.observe(content);
603560
+ if (echoObs.isEcho) {
603561
+ const collapsedCount = this._textEchoGuard.collapseEchoes(messages2);
603562
+ this._echoTempBoostTurns = 2;
603563
+ this.emit({
603564
+ type: "status",
603565
+ content: `ECHO-1: text-only echo #${echoObs.echoCount} (${Math.round(echoObs.similarity * 100)}% similar to earlier message) — collapsed ${collapsedCount} duplicate(s), injecting pattern breaker`,
603566
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
603567
+ });
603568
+ messages2.push({
603569
+ role: "system",
603570
+ content: this._textEchoGuard.buildIntervention(echoObs)
603571
+ });
603572
+ if (adversaryAddedGuidance) {
603573
+ this.drainPendingRuntimeGuidance(turn);
603574
+ while (this.pendingUserMessages.length > 0) {
603575
+ const userMsg = this.pendingUserMessages.shift();
603576
+ await this.appendInjectedUserMessage(userMsg, messages2, turn);
603577
+ }
603578
+ }
603579
+ continue;
603580
+ }
603581
+ }
602962
603582
  const codeBlockMatch = content.match(/```(?:bash|sh|shell|zsh)\s*\n([\s\S]*?)```/);
602963
603583
  const codeBlockLines = codeBlockMatch?.[1] ? codeBlockMatch[1].trim().split("\n").filter((l2) => l2.trim() && !l2.trim().startsWith("#")) : [];
602964
603584
  const everyLineLooksExecutable = codeBlockLines.length > 0 && codeBlockLines.every((l2) => {
@@ -603243,10 +603863,13 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
603243
603863
  this._insertContextFrame(compactedMsgs, await this._buildTurnContextFrame(turn, compactedMsgs, void 0, bfEnvironmentBlock));
603244
603864
  this.gcSystemMessages(compactedMsgs);
603245
603865
  const modelFacingMessages = this._prepareModelFacingMessages(compactedMsgs, turn);
603866
+ const bfEchoBoostedTemp = this._echoTempBoostTurns > 0 ? Math.max(this.options.temperature ?? 0, 0.7) : this.options.temperature;
603867
+ if (this._echoTempBoostTurns > 0)
603868
+ this._echoTempBoostTurns--;
603246
603869
  const chatRequest = {
603247
603870
  messages: modelFacingMessages,
603248
603871
  tools: toolDefs,
603249
- temperature: this.options.temperature,
603872
+ temperature: bfEchoBoostedTemp,
603250
603873
  maxTokens: this.options.maxTokens,
603251
603874
  timeoutMs: boundedRequestTimeoutMs(),
603252
603875
  numCtx: this.options.contextWindowSize || void 0
@@ -603371,6 +603994,7 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
603371
603994
  if (msg.toolCalls && msg.toolCalls.length > 0) {
603372
603995
  consecutiveTextOnly = 0;
603373
603996
  consecutiveThinkOnly = 0;
603997
+ this._textEchoGuard.noteToolProgress();
603374
603998
  msg.toolCalls = this._dedupeRepeatedToolCallIdsForResponse(msg.toolCalls, turn);
603375
603999
  if (msg.toolCalls.length === 0) {
603376
604000
  messages2.push({
@@ -603547,6 +604171,23 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
603547
604171
  });
603548
604172
  break;
603549
604173
  }
604174
+ if (process.env["OMNIUS_DISABLE_TEXT_ECHO_GUARD"] !== "1") {
604175
+ const echoObsBF = this._textEchoGuard.observe(content);
604176
+ if (echoObsBF.isEcho) {
604177
+ const collapsedBF = this._textEchoGuard.collapseEchoes(messages2);
604178
+ this._echoTempBoostTurns = 2;
604179
+ this.emit({
604180
+ type: "status",
604181
+ 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`,
604182
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
604183
+ });
604184
+ messages2.push({
604185
+ role: "system",
604186
+ content: this._textEchoGuard.buildIntervention(echoObsBF)
604187
+ });
604188
+ continue;
604189
+ }
604190
+ }
603550
604191
  messages2.push({
603551
604192
  role: "system",
603552
604193
  content: "Continue working. Use tools to read files, make changes, and run validation. Call task_complete when done."
@@ -604510,6 +605151,19 @@ ${marker}` : marker);
604510
605151
  return { role: "tool", content: messageContent, tool_call_id: toolCallId };
604511
605152
  }
604512
605153
  buildModelFacingToolMessage(output, toolCallId, toolName, args, success) {
605154
+ if (process.env["OMNIUS_DISABLE_OBSERVATION_FRAME"] !== "1") {
605155
+ try {
605156
+ this._observationLedger.record({
605157
+ tool: toolName,
605158
+ args,
605159
+ fingerprint: this._buildToolFingerprint(toolName, args ?? {}),
605160
+ output,
605161
+ success: success !== false,
605162
+ turn: this._taskState?.toolCallCount ?? 0
605163
+ });
605164
+ } catch {
605165
+ }
605166
+ }
604513
605167
  return this.buildToolMessage(this.compactDiscoveryOutputForModel(toolName, args, output, success), toolCallId, toolName);
604514
605168
  }
604515
605169
  compactDiscoveryOutputForModel(toolName, args, output, success) {
@@ -612173,7 +612827,7 @@ function renderPlan(decisions, includeHeader) {
612173
612827
  footerBlock,
612174
612828
  renderedText,
612175
612829
  memoryPrefix,
612176
- prefixHash: hashText(memoryPrefix),
612830
+ prefixHash: hashText2(memoryPrefix),
612177
612831
  tierDistribution,
612178
612832
  tokensEmitted,
612179
612833
  tokensBaselineNoWeighting,
@@ -612273,7 +612927,7 @@ function estimateTokens4(text2) {
612273
612927
  return 0;
612274
612928
  return Math.max(1, Math.ceil(text2.length / 4));
612275
612929
  }
612276
- function hashText(text2) {
612930
+ function hashText2(text2) {
612277
612931
  return createHash35("sha256").update(text2).digest("hex");
612278
612932
  }
612279
612933
  var init_materialization_policy = __esm({
@@ -647365,7 +648019,7 @@ var init_status_bar = __esm({
647365
648019
  this.advanceStagePhase();
647366
648020
  this.renderFooterPreserveCursor();
647367
648021
  refreshTuiTasksAnimationFrame();
647368
- if ((this._trajectoryLiveBlockAppended || this._subAgentLiveBlockAppended) && this._activeViewId === "main" && this.stageBorderActive()) {
648022
+ if ((this._trajectoryLiveBlockAppended || this._subAgentLiveBlockAppended) && this._activeViewId === "main" && supportsTruecolor() && (this.stageBorderActive() || this.hasRunningChildAgentView())) {
647369
648023
  this.refreshDynamicBlocks();
647370
648024
  }
647371
648025
  if (this._agentViews.size > 1 && (String(this.currentHeaderPanel).startsWith("sys-") || this._headerExpanded)) {
@@ -647382,6 +648036,15 @@ var init_status_bar = __esm({
647382
648036
  advanceStagePhase() {
647383
648037
  this._stagePhase = (this._stagePhase + 6) % 360;
647384
648038
  }
648039
+ /** True while any non-main agent view (sub / full / telegram) is running.
648040
+ * Child-agent work does not sweep the MAIN stage, so the live-block
648041
+ * animation gate needs this signal in addition to stageBorderActive(). */
648042
+ hasRunningChildAgentView() {
648043
+ for (const view of this._agentViews.values()) {
648044
+ if (view.id !== "main" && view.status === "running") return true;
648045
+ }
648046
+ return false;
648047
+ }
647385
648048
  /**
647386
648049
  * Ensure the monitoring timer is running when the registry has entries
647387
648050
  * and the braille spinner is not active. Refreshes the buffer line
@@ -717693,13 +718356,13 @@ function isLikelyAgentSpeechEcho({
717693
718356
  if (!agentTokens.length) return { likelyEcho: false, echoSimilarity: 0, reason: "no_agent_speech" };
717694
718357
  const agentComparable = agentTokens.join(" ");
717695
718358
  const heardComparable = heardTokens.join(" ");
717696
- const echoSimilarity = jaccardSimilarity(heardTokens, agentTokens);
718359
+ const echoSimilarity2 = jaccardSimilarity(heardTokens, agentTokens);
717697
718360
  const exactEcho = Boolean(heardComparable && agentComparable && (agentComparable.includes(heardComparable) || heardComparable.includes(agentComparable)));
717698
718361
  const orderedEcho = heardTokens.length >= 3 && isMostlyContainedInOrder(heardTokens, agentTokens);
717699
- const likelyEcho = echoSimilarity >= AGENT_ECHO_SIMILARITY || exactEcho || orderedEcho;
718362
+ const likelyEcho = echoSimilarity2 >= AGENT_ECHO_SIMILARITY || exactEcho || orderedEcho;
717700
718363
  return {
717701
718364
  likelyEcho,
717702
- echoSimilarity,
718365
+ echoSimilarity: echoSimilarity2,
717703
718366
  reason: likelyEcho ? "speaker_echo" : "pass"
717704
718367
  };
717705
718368
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.545",
3
+ "version": "1.0.546",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.545",
9
+ "version": "1.0.546",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.545",
3
+ "version": "1.0.546",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",