omnius 1.0.375 → 1.0.377

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
@@ -4806,6 +4806,9 @@ var init_shell = __esm({
4806
4806
  const lines = [
4807
4807
  "[SHELL TRANSCRIPT]",
4808
4808
  `command: ${args.command}`,
4809
+ args.cwdBefore ? `cwd_before: ${args.cwdBefore}` : null,
4810
+ args.cwdAfter ? `cwd_after: ${args.cwdAfter}` : null,
4811
+ args.cwdBefore && args.cwdAfter && args.nextCwd && args.cwdAfter !== args.nextCwd ? `cwd_note: cd changes are command-local; next shell call starts at ${args.nextCwd}` : null,
4809
4812
  args.timedOut ? "status: timeout" : args.exitCode === 0 ? "status: success" : "status: failure",
4810
4813
  args.exitCode === void 0 || args.exitCode === null ? null : `exit_code: ${args.exitCode}`,
4811
4814
  args.error ? `error: ${args.error}` : null,
@@ -4919,6 +4922,8 @@ ${elevatedResult.stderr}` : ""),
4919
4922
  runCommand(command, timeout2, stdinInput, onOutput) {
4920
4923
  const start2 = performance.now();
4921
4924
  const isWin2 = process.platform === "win32";
4925
+ const cwdBefore = this.currentCwd;
4926
+ let cwdAfter = cwdBefore;
4922
4927
  let pwdDir = mkdtempSync(join6(tmpdir(), "omnius-shell-"));
4923
4928
  let pwdFile = join6(pwdDir, `cwd-${randomUUID3()}`);
4924
4929
  let wrappedCommand;
@@ -4987,13 +4992,13 @@ exit $__omnius_exit
4987
4992
  heartbeatTimer.unref?.();
4988
4993
  const captureFinalCwd = () => {
4989
4994
  if (!pwdFile)
4990
- return;
4995
+ return cwdAfter;
4991
4996
  try {
4992
4997
  const raw = readFileSync7(pwdFile, "utf8").trim();
4993
- if (raw && raw !== this.currentCwd) {
4998
+ if (raw) {
4994
4999
  try {
4995
5000
  if (statSync5(raw).isDirectory()) {
4996
- this.currentCwd = raw;
5001
+ cwdAfter = raw;
4997
5002
  }
4998
5003
  } catch {
4999
5004
  }
@@ -5008,6 +5013,7 @@ exit $__omnius_exit
5008
5013
  }
5009
5014
  pwdFile = null;
5010
5015
  pwdDir = null;
5016
+ return cwdAfter;
5011
5017
  };
5012
5018
  const doResolve = (result) => {
5013
5019
  if (resolved)
@@ -5017,7 +5023,6 @@ exit $__omnius_exit
5017
5023
  clearInterval(heartbeatTimer);
5018
5024
  if (exitFlushTimer)
5019
5025
  clearTimeout(exitFlushTimer);
5020
- captureFinalCwd();
5021
5026
  releaseProcessLease(leaseId, killed ? "killed" : result.success ? "completed" : "released", killed ? "shell command timed out" : "shell command exited");
5022
5027
  resolve73(result);
5023
5028
  };
@@ -5056,6 +5061,7 @@ exit $__omnius_exit
5056
5061
  exitFlushTimer = setTimeout(() => {
5057
5062
  const durationMs = performance.now() - start2;
5058
5063
  if (killed) {
5064
+ const finalCwd2 = captureFinalCwd();
5059
5065
  const combined = stdout + stderr;
5060
5066
  const looksInteractive = /\? .+[›>]|y\/n|yes\/no|\(Y\/n\)|\[y\/N\]/i.test(combined);
5061
5067
  const hint = looksInteractive ? " The command appears to be waiting for interactive input. Use non-interactive flags (e.g., --yes, --no-input) or provide input via the stdin parameter." : ` To run longer, retry with a higher timeout parameter (e.g. timeout: ${Math.min(timeout2 * 10, 6e5)} for ${Math.min(timeout2 * 10, 6e5) / 1e3}s). Or use background_run to run in the background and check with task_output later.`;
@@ -5065,6 +5071,9 @@ exit $__omnius_exit
5065
5071
  error: `Command timed out after ${timeout2}ms.${hint}`,
5066
5072
  llmContent: this.formatShellTranscript({
5067
5073
  command,
5074
+ cwdBefore,
5075
+ cwdAfter: finalCwd2,
5076
+ nextCwd: this.currentCwd,
5068
5077
  timedOut: true,
5069
5078
  stdout,
5070
5079
  stderr,
@@ -5075,6 +5084,7 @@ exit $__omnius_exit
5075
5084
  return;
5076
5085
  }
5077
5086
  const success = code8 === 0;
5087
+ const finalCwd = captureFinalCwd();
5078
5088
  doResolve({
5079
5089
  success,
5080
5090
  output: stdout + (stderr && success ? `
@@ -5083,6 +5093,9 @@ ${stderr}` : ""),
5083
5093
  error: success ? void 0 : stderr || `Exit code ${code8}`,
5084
5094
  llmContent: this.formatShellTranscript({
5085
5095
  command,
5096
+ cwdBefore,
5097
+ cwdAfter: finalCwd,
5098
+ nextCwd: this.currentCwd,
5086
5099
  exitCode: code8,
5087
5100
  stdout,
5088
5101
  stderr,
@@ -5095,6 +5108,7 @@ ${stderr}` : ""),
5095
5108
  child.on("close", (code8) => {
5096
5109
  const durationMs = performance.now() - start2;
5097
5110
  if (killed) {
5111
+ const finalCwd2 = captureFinalCwd();
5098
5112
  const combined = stdout + stderr;
5099
5113
  const looksInteractive = /\? .+[›>]|y\/n|yes\/no|\(Y\/n\)|\[y\/N\]/i.test(combined);
5100
5114
  const hint = looksInteractive ? " The command appears to be waiting for interactive input. Use non-interactive flags (e.g., --yes, --no-input) or provide input via the stdin parameter." : ` To run longer, retry with a higher timeout parameter (e.g. timeout: ${Math.min(timeout2 * 10, 6e5)} for ${Math.min(timeout2 * 10, 6e5) / 1e3}s). Or use background_run to run in the background and check with task_output later.`;
@@ -5104,6 +5118,9 @@ ${stderr}` : ""),
5104
5118
  error: `Command timed out after ${timeout2}ms.${hint}`,
5105
5119
  llmContent: this.formatShellTranscript({
5106
5120
  command,
5121
+ cwdBefore,
5122
+ cwdAfter: finalCwd2,
5123
+ nextCwd: this.currentCwd,
5107
5124
  timedOut: true,
5108
5125
  stdout,
5109
5126
  stderr,
@@ -5114,6 +5131,7 @@ ${stderr}` : ""),
5114
5131
  return;
5115
5132
  }
5116
5133
  const success = code8 === 0;
5134
+ const finalCwd = captureFinalCwd();
5117
5135
  doResolve({
5118
5136
  success,
5119
5137
  output: stdout + (stderr && success ? `
@@ -5122,6 +5140,9 @@ ${stderr}` : ""),
5122
5140
  error: success ? void 0 : stderr || `Exit code ${code8}`,
5123
5141
  llmContent: this.formatShellTranscript({
5124
5142
  command,
5143
+ cwdBefore,
5144
+ cwdAfter: finalCwd,
5145
+ nextCwd: this.currentCwd,
5125
5146
  exitCode: code8,
5126
5147
  stdout,
5127
5148
  stderr,
@@ -5131,12 +5152,16 @@ ${stderr}` : ""),
5131
5152
  });
5132
5153
  });
5133
5154
  child.on("error", (err) => {
5155
+ const finalCwd = captureFinalCwd();
5134
5156
  doResolve({
5135
5157
  success: false,
5136
5158
  output: stdout,
5137
5159
  error: err.message,
5138
5160
  llmContent: this.formatShellTranscript({
5139
5161
  command,
5162
+ cwdBefore,
5163
+ cwdAfter: finalCwd,
5164
+ nextCwd: this.currentCwd,
5140
5165
  stdout,
5141
5166
  stderr,
5142
5167
  error: err.message
@@ -16742,6 +16767,20 @@ function clamp01Local(x) {
16742
16767
  return 1;
16743
16768
  return x;
16744
16769
  }
16770
+ function stableJson2(value2) {
16771
+ if (value2 === null || typeof value2 !== "object") {
16772
+ return JSON.stringify(value2);
16773
+ }
16774
+ if (Array.isArray(value2)) {
16775
+ return `[${value2.map((item) => stableJson2(item)).join(",")}]`;
16776
+ }
16777
+ const entries = Object.entries(value2).filter(([, v]) => v !== void 0).sort(([a2], [b]) => a2.localeCompare(b));
16778
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${stableJson2(v)}`).join(",")}}`;
16779
+ }
16780
+ function episodeIdentityHash(ep) {
16781
+ const identity3 = ep.metadata ? `${ep.content}\0metadata:${stableJson2(ep.metadata)}` : ep.content;
16782
+ return createHash8("sha256").update(identity3).digest("hex").slice(0, 16);
16783
+ }
16745
16784
  function sanitizeImportance(raw, fallback = 5) {
16746
16785
  if (typeof raw !== "number" || !Number.isFinite(raw))
16747
16786
  return fallback;
@@ -16926,7 +16965,7 @@ var init_episodeStore = __esm({
16926
16965
  insert(ep) {
16927
16966
  const id = randomUUID10();
16928
16967
  const now2 = Date.now();
16929
- const contentHash2 = createHash8("sha256").update(ep.content).digest("hex").slice(0, 16);
16968
+ const contentHash2 = episodeIdentityHash(ep);
16930
16969
  const modality = ep.modality ?? "text";
16931
16970
  const rawImportance = ep.importance ?? autoImportance(ep.toolName ?? null, modality, ep.content);
16932
16971
  const modulated = ep.emotionalState ? modulateImportance(sanitizeImportance(rawImportance), ep.emotionalState) : sanitizeImportance(rawImportance);
@@ -16935,7 +16974,11 @@ var init_episodeStore = __esm({
16935
16974
  return "";
16936
16975
  }
16937
16976
  const decayClass = ep.decayClass ?? autoDecayClass(ep.toolName ?? null, modality, ep.content);
16938
- const existing = this.db.prepare("SELECT id FROM episodes WHERE content_hash = ? AND session_id = ? LIMIT 1").get(contentHash2, ep.sessionId ?? null);
16977
+ const existing = this.db.prepare(`SELECT id FROM episodes
16978
+ WHERE content_hash = ?
16979
+ AND COALESCE(session_id, '') = COALESCE(?, '')
16980
+ AND COALESCE(tool_name, '') = COALESCE(?, '')
16981
+ LIMIT 1`).get(contentHash2, ep.sessionId ?? null, ep.toolName ?? null);
16939
16982
  if (existing)
16940
16983
  return existing.id;
16941
16984
  this.db.prepare(`
@@ -37611,12 +37654,12 @@ function catalogAdaptersDir() {
37611
37654
  function nowIso() {
37612
37655
  return (/* @__PURE__ */ new Date()).toISOString();
37613
37656
  }
37614
- function stableJson2(value2) {
37657
+ function stableJson3(value2) {
37615
37658
  if (Array.isArray(value2))
37616
- return `[${value2.map(stableJson2).join(",")}]`;
37659
+ return `[${value2.map(stableJson3).join(",")}]`;
37617
37660
  if (value2 && typeof value2 === "object") {
37618
37661
  const obj = value2;
37619
- return `{${Object.keys(obj).sort().map((key) => `${JSON.stringify(key)}:${stableJson2(obj[key])}`).join(",")}}`;
37662
+ return `{${Object.keys(obj).sort().map((key) => `${JSON.stringify(key)}:${stableJson3(obj[key])}`).join(",")}}`;
37620
37663
  }
37621
37664
  return JSON.stringify(value2);
37622
37665
  }
@@ -37996,7 +38039,7 @@ function builtInMediaModelSpec(seed) {
37996
38039
  evidence: seed.evidence
37997
38040
  }
37998
38041
  };
37999
- spec.provenance.contentHash = sha256(stableJson2({ ...spec, provenance: { ...spec.provenance, contentHash: void 0 } }));
38042
+ spec.provenance.contentHash = sha256(stableJson3({ ...spec, provenance: { ...spec.provenance, contentHash: void 0 } }));
38000
38043
  return spec;
38001
38044
  }
38002
38045
  function builtInMediaModelCatalog() {
@@ -38148,7 +38191,7 @@ function draftMediaModelAdapter(args) {
38148
38191
  dependencies: ["torch", "transformers", "diffusers", "accelerate", "safetensors"]
38149
38192
  };
38150
38193
  }
38151
- spec.provenance.contentHash = sha256(stableJson2({ ...spec, provenance: { ...spec.provenance, contentHash: void 0 } }));
38194
+ spec.provenance.contentHash = sha256(stableJson3({ ...spec, provenance: { ...spec.provenance, contentHash: void 0 } }));
38152
38195
  return spec;
38153
38196
  }
38154
38197
  function validateMediaModelAdapter(spec) {
@@ -38312,7 +38355,7 @@ function saveMediaModelAdapter(spec) {
38312
38355
  contentHash: void 0
38313
38356
  }
38314
38357
  };
38315
- updated.provenance.contentHash = sha256(stableJson2(updated));
38358
+ updated.provenance.contentHash = sha256(stableJson3(updated));
38316
38359
  const json = `${JSON.stringify(updated, null, 2)}
38317
38360
  `;
38318
38361
  const path12 = specPathFor(updated.id);
@@ -41699,7 +41742,39 @@ function bwrapAvailable() {
41699
41742
  if (_bwrapAvailable !== null)
41700
41743
  return _bwrapAvailable;
41701
41744
  try {
41702
- const r2 = spawnSync5("bwrap", ["--version"], { timeout: 4e3 });
41745
+ const r2 = spawnSync5("bwrap", [
41746
+ "--unshare-all",
41747
+ "--die-with-parent",
41748
+ "--new-session",
41749
+ "--ro-bind-try",
41750
+ "/usr",
41751
+ "/usr",
41752
+ "--ro-bind-try",
41753
+ "/bin",
41754
+ "/bin",
41755
+ "--ro-bind-try",
41756
+ "/lib",
41757
+ "/lib",
41758
+ "--ro-bind-try",
41759
+ "/lib64",
41760
+ "/lib64",
41761
+ "--proc",
41762
+ "/proc",
41763
+ "--tmpfs",
41764
+ "/tmp",
41765
+ "--chdir",
41766
+ "/tmp",
41767
+ "--clearenv",
41768
+ "--setenv",
41769
+ "PATH",
41770
+ "/usr/bin:/bin",
41771
+ "--",
41772
+ "python3",
41773
+ "-I",
41774
+ "-S",
41775
+ "-c",
41776
+ "print(1)"
41777
+ ], { timeout: 4e3 });
41703
41778
  _bwrapAvailable = r2.status === 0;
41704
41779
  } catch {
41705
41780
  _bwrapAvailable = false;
@@ -289916,7 +289991,8 @@ async function saveStore(workingDir, store2) {
289916
289991
  await writeFile22(join62(dir, "tasks.json"), JSON.stringify(store2, null, 2), "utf-8");
289917
289992
  }
289918
289993
  function globalStoreDir() {
289919
- return join62(homedir14(), ".omnius", "scheduled");
289994
+ const home = process.env["OMNIUS_HOME"]?.trim() || join62(homedir14(), ".omnius");
289995
+ return join62(home, "scheduled");
289920
289996
  }
289921
289997
  async function loadGlobalStore() {
289922
289998
  try {
@@ -295009,6 +295085,9 @@ import { existsSync as existsSync56, readFileSync as readFileSync40, writeFileSy
295009
295085
  import { join as join69 } from "node:path";
295010
295086
  import { homedir as homedir16 } from "node:os";
295011
295087
  import { randomBytes as randomBytes17 } from "node:crypto";
295088
+ function canonicalTodoContent(content) {
295089
+ return content.trim().replace(/\s+/g, " ").toLowerCase();
295090
+ }
295012
295091
  function setTodoEventPublisher(pub) {
295013
295092
  _eventPublisher = pub;
295014
295093
  }
@@ -295042,19 +295121,48 @@ function writeTodos(sessionId, incoming) {
295042
295121
  mkdirSync31(todoDir(), { recursive: true });
295043
295122
  const old = readTodos(sessionId);
295044
295123
  const oldById = new Map(old.map((t2) => [t2.id, t2]));
295124
+ const oldByContent = /* @__PURE__ */ new Map();
295125
+ for (const todo of old) {
295126
+ const key = canonicalTodoContent(todo.content);
295127
+ const bucket = oldByContent.get(key) ?? [];
295128
+ bucket.push(todo);
295129
+ oldByContent.set(key, bucket);
295130
+ }
295131
+ const usedOldIds = /* @__PURE__ */ new Set();
295132
+ const idAliases = /* @__PURE__ */ new Map();
295133
+ const indexAliases = /* @__PURE__ */ new Map();
295134
+ for (const [index, incomingTodo] of incoming.entries()) {
295135
+ const requestedId = incomingTodo.id;
295136
+ if (requestedId && oldById.has(requestedId)) {
295137
+ usedOldIds.add(requestedId);
295138
+ continue;
295139
+ }
295140
+ const matches = oldByContent.get(canonicalTodoContent(incomingTodo.content)) ?? [];
295141
+ const match = matches.find((todo) => !usedOldIds.has(todo.id));
295142
+ if (!match)
295143
+ continue;
295144
+ usedOldIds.add(match.id);
295145
+ indexAliases.set(index, match.id);
295146
+ if (requestedId && requestedId !== match.id)
295147
+ idAliases.set(requestedId, match.id);
295148
+ }
295045
295149
  const now2 = Date.now();
295046
- const newTodos = incoming.map((t2) => {
295047
- const id = t2.id || `todo-${randomBytes17(4).toString("hex")}`;
295150
+ const newTodos = incoming.map((t2, index) => {
295151
+ const requestedId = t2.id || `todo-${randomBytes17(4).toString("hex")}`;
295152
+ const id = indexAliases.get(index) ?? idAliases.get(requestedId) ?? requestedId;
295048
295153
  const existing = oldById.get(id);
295154
+ const requestedParentId = t2.parentId ? idAliases.get(t2.parentId) ?? t2.parentId : void 0;
295155
+ const requestedStatus = t2.status;
295156
+ const status = existing?.status === "completed" && (requestedStatus === "pending" || requestedStatus === "in_progress") && !t2.blocker ? "completed" : requestedStatus;
295049
295157
  const next = {
295050
295158
  id,
295051
295159
  content: t2.content,
295052
- status: t2.status,
295053
- parentId: t2.parentId ?? existing?.parentId,
295054
- blocker: t2.blocker ?? (t2.status === "blocked" ? existing?.blocker : void 0),
295160
+ status,
295161
+ parentId: requestedParentId ?? existing?.parentId,
295162
+ blocker: t2.blocker ?? (status === "blocked" ? existing?.blocker : void 0),
295055
295163
  createdAt: existing?.createdAt ?? now2,
295056
295164
  updatedAt: now2,
295057
- completedAt: t2.status === "completed" ? existing?.completedAt ?? now2 : void 0,
295165
+ completedAt: status === "completed" ? existing?.completedAt ?? now2 : void 0,
295058
295166
  verifyCommand: t2.verifyCommand ?? existing?.verifyCommand,
295059
295167
  // REG-37
295060
295168
  declaredArtifacts: t2.declaredArtifacts ?? existing?.declaredArtifacts
@@ -549192,7 +549300,7 @@ var init_agent_tool = __esm({
549192
549300
  });
549193
549301
  return {
549194
549302
  success: true,
549195
- output: `Agent spawned (subprocess, worktree): ${agentId}
549303
+ output: `Agent spawned (background subprocess, worktree): ${agentId}
549196
549304
  Type: ${subagentType}
549197
549305
  PID: ${spawn35.pid}
549198
549306
  Task: ${prompt.slice(0, 100)}
@@ -552173,6 +552281,22 @@ function deduplicateFrames(frames) {
552173
552281
  }
552174
552282
  return frames;
552175
552283
  }
552284
+ function normalizeFrameDescriptionForVideo(raw) {
552285
+ let text2 = raw.replace(/\s+/g, " ").trim();
552286
+ const answerMatch = text2.match(/\bA:\s*([\s\S]*?)(?:\s+Image:|$)/);
552287
+ if (answerMatch?.[1])
552288
+ text2 = answerMatch[1].replace(/\s+/g, " ").trim();
552289
+ if (!text2)
552290
+ return null;
552291
+ if (/\[IMAGE_BASE64:|data:image\/|base64/i.test(text2))
552292
+ return null;
552293
+ if (/^\s*(?:ids?|coords?|points?)\s*=\s*\[[\d\s,.[\]-]+\]\s*$/i.test(text2))
552294
+ return null;
552295
+ const letters = text2.match(/[A-Za-z]/g)?.length ?? 0;
552296
+ if (text2.length < 12 || letters < 4)
552297
+ return null;
552298
+ return text2.slice(0, 700);
552299
+ }
552176
552300
  function formatTime2(seconds) {
552177
552301
  const m2 = Math.floor(seconds / 60);
552178
552302
  const s2 = Math.floor(seconds % 60);
@@ -552221,9 +552345,9 @@ var init_video_understand = __esm({
552221
552345
  prompt: "Describe only the visible scene in this video frame. Note subject identity/type, pose, motion cues, contacts with the ground, and visible text if present. Do not mention file metadata, base64, data URIs, or this prompt.",
552222
552346
  length: "normal"
552223
552347
  });
552224
- const output = String(result.llmContent || result.output || "").replace(/\s+/g, " ").trim();
552225
- if (result.success && output.length > 0)
552226
- frame.description = output.slice(0, 700);
552348
+ const output = normalizeFrameDescriptionForVideo(String(result.llmContent || result.output || ""));
552349
+ if (result.success && output)
552350
+ frame.description = output;
552227
552351
  } catch {
552228
552352
  }
552229
552353
  }
@@ -555078,26 +555202,34 @@ var init_VllmBackend = __esm({
555078
555202
  const url = `${this.baseUrl}/health`;
555079
555203
  const controller = new AbortController();
555080
555204
  const timer = setTimeout(() => controller.abort(), 5e3);
555081
- const maxRetries = 3;
555082
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
555083
- if (attempt > 0) {
555084
- const backoff = Math.min(1e3 * Math.pow(2, attempt - 1), 4e3);
555085
- await new Promise((r2) => setTimeout(r2, backoff));
555086
- }
555087
- try {
555088
- const response = await fetch(url, {
555089
- method: "GET",
555090
- signal: controller.signal,
555091
- headers: this.authHeaders()
555092
- });
555093
- if (response.ok) {
555094
- this.consecutiveFailures = 0;
555095
- return true;
555205
+ let healthy = false;
555206
+ try {
555207
+ const maxRetries = Math.max(0, this.maxRetries);
555208
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
555209
+ if (attempt > 0) {
555210
+ const backoff = Math.min(1e3 * Math.pow(2, attempt - 1), 4e3);
555211
+ await new Promise((r2) => setTimeout(r2, backoff));
555212
+ }
555213
+ try {
555214
+ const response = await fetch(url, {
555215
+ method: "GET",
555216
+ signal: controller.signal,
555217
+ headers: this.authHeaders()
555218
+ });
555219
+ if (response.ok) {
555220
+ healthy = true;
555221
+ break;
555222
+ }
555223
+ } catch {
555096
555224
  }
555097
- } catch {
555098
555225
  }
555226
+ } finally {
555227
+ clearTimeout(timer);
555228
+ }
555229
+ if (healthy) {
555230
+ this.consecutiveFailures = 0;
555231
+ return true;
555099
555232
  }
555100
- clearTimeout(timer);
555101
555233
  this.consecutiveFailures++;
555102
555234
  if (this.consecutiveFailures >= 3) {
555103
555235
  this.degradedUntil = Date.now() + 3e4;
@@ -555291,25 +555423,33 @@ var init_OllamaBackend = __esm({
555291
555423
  const url = `${this.baseUrl}/api/tags`;
555292
555424
  const controller = new AbortController();
555293
555425
  const timer = setTimeout(() => controller.abort(), 5e3);
555294
- const maxRetries = 3;
555295
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
555296
- if (attempt > 0) {
555297
- const backoff = Math.min(1e3 * Math.pow(2, attempt - 1), 4e3);
555298
- await new Promise((r2) => setTimeout(r2, backoff));
555299
- }
555300
- try {
555301
- const response = await fetch(url, {
555302
- method: "GET",
555303
- signal: controller.signal
555304
- });
555305
- if (response.ok) {
555306
- this.consecutiveFailures = 0;
555307
- return true;
555426
+ let healthy = false;
555427
+ try {
555428
+ const maxRetries = Math.max(0, this.maxRetries);
555429
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
555430
+ if (attempt > 0) {
555431
+ const backoff = Math.min(1e3 * Math.pow(2, attempt - 1), 4e3);
555432
+ await new Promise((r2) => setTimeout(r2, backoff));
555433
+ }
555434
+ try {
555435
+ const response = await fetch(url, {
555436
+ method: "GET",
555437
+ signal: controller.signal
555438
+ });
555439
+ if (response.ok) {
555440
+ healthy = true;
555441
+ break;
555442
+ }
555443
+ } catch {
555308
555444
  }
555309
- } catch {
555310
555445
  }
555446
+ } finally {
555447
+ clearTimeout(timer);
555448
+ }
555449
+ if (healthy) {
555450
+ this.consecutiveFailures = 0;
555451
+ return true;
555311
555452
  }
555312
- clearTimeout(timer);
555313
555453
  this.consecutiveFailures++;
555314
555454
  if (this.consecutiveFailures >= 3) {
555315
555455
  this.degradedUntil = Date.now() + 3e4;
@@ -559114,7 +559254,7 @@ function recordToolEvidence(ledger, input) {
559114
559254
  input.name,
559115
559255
  input.success === true ? "succeeded" : input.success === false ? "failed" : "observed",
559116
559256
  input.argsKey ? `args=${cleanText(input.argsKey, 180)}` : "",
559117
- input.outputPreview ? `output=${cleanText(input.outputPreview, 700)}` : ""
559257
+ input.outputPreview ? `output=${cleanText(input.outputPreview, 1200)}` : ""
559118
559258
  ].filter(Boolean).join(" ");
559119
559259
  return recordCompletionEvidence(ledger, {
559120
559260
  kind: "tool_result",
@@ -559571,13 +559711,6 @@ var init_completionLedger = __esm({
559571
559711
  // packages/orchestrator/dist/completionAutoFinalize.js
559572
559712
  function buildTruthBasedCompletion(input) {
559573
559713
  const maxAge = input.maxValidationAgeTurns ?? 8;
559574
- if (input.todos.length === 0) {
559575
- return { ready: false, reason: "no active todo tree" };
559576
- }
559577
- const open2 = input.todos.filter((todo) => todo.status !== "completed");
559578
- if (open2.length > 0) {
559579
- return { ready: false, reason: `${open2.length} open todo(s)` };
559580
- }
559581
559714
  if (input.verifyFailureCount > 0) {
559582
559715
  return {
559583
559716
  ready: false,
@@ -559595,6 +559728,33 @@ function buildTruthBasedCompletion(input) {
559595
559728
  };
559596
559729
  }
559597
559730
  const files = (input.filesEdited ?? []).filter((file) => file.path.trim().length > 0).slice(0, 12);
559731
+ if (input.todos.length === 0) {
559732
+ if (files.length === 0) {
559733
+ return { ready: false, reason: "no active todo tree or changed files" };
559734
+ }
559735
+ if (typeof input.lastMutationTurn === "number" && input.lastMutationTurn >= 0 && input.lastValidationTurn < input.lastMutationTurn) {
559736
+ return {
559737
+ ready: false,
559738
+ reason: "validation happened before the last mutation"
559739
+ };
559740
+ }
559741
+ const fileLines2 = files.map((file) => `- ${file.action ? `${file.action} ` : ""}${file.path}`).join("\n");
559742
+ const summary2 = [
559743
+ "Completed with direct task evidence.",
559744
+ fileLines2 ? `Files changed:
559745
+ ${fileLines2}` : null,
559746
+ `Validation passed after the last mutation: ${input.lastValidationCommand}`
559747
+ ].filter((line) => Boolean(line)).join("\n\n");
559748
+ return {
559749
+ ready: true,
559750
+ reason: `changed files validated ${age} turn(s) ago`,
559751
+ summary: summary2
559752
+ };
559753
+ }
559754
+ const open2 = input.todos.filter((todo) => todo.status !== "completed");
559755
+ if (open2.length > 0) {
559756
+ return { ready: false, reason: `${open2.length} open todo(s)` };
559757
+ }
559598
559758
  const todoLines = input.todos.slice(0, 12).map((todo) => {
559599
559759
  const id = todo.id ? `${todo.id}: ` : "";
559600
559760
  return `- ${id}${todo.content}`;
@@ -559623,7 +559783,13 @@ var init_completionAutoFinalize = __esm({
559623
559783
 
559624
559784
  // packages/orchestrator/dist/verificationCommand.js
559625
559785
  function normalizeShellCommand(command) {
559626
- return command.replace(/\s+/g, " ").trim();
559786
+ let normalized = command.replace(/\s+/g, " ").trim();
559787
+ let previous = "";
559788
+ while (previous !== normalized) {
559789
+ previous = normalized;
559790
+ normalized = normalized.replace(/\s+(?:[12]?>&[12]|[12]?>\s*['"]?\/dev\/null['"]?)$/i, "").trim();
559791
+ }
559792
+ return normalized;
559627
559793
  }
559628
559794
  function splitConjunctiveVerifyCommand(command) {
559629
559795
  return normalizeShellCommand(command).split(/\s+&&\s+/).map((part) => part.trim()).filter(Boolean);
@@ -569421,7 +569587,7 @@ var init_resolution_memory = __esm({
569421
569587
  /** Load prior fixes (cross-session). */
569422
569588
  loadFixes(fixes) {
569423
569589
  for (const f2 of fixes) {
569424
- if (Array.isArray(f2.from) && Array.isArray(f2.to) && f2.from.length > 0) {
569590
+ if (Array.isArray(f2.from) && Array.isArray(f2.to) && f2.from.length > 0 && !isPathSensitiveFix(f2)) {
569425
569591
  this.fixes.push(f2);
569426
569592
  }
569427
569593
  }
@@ -569470,6 +569636,10 @@ var init_resolution_memory = __esm({
569470
569636
  const delta = computeDelta(fail3.tokens, workedTokens);
569471
569637
  if (!delta)
569472
569638
  continue;
569639
+ if (isPathSensitiveFix(delta)) {
569640
+ this.recentFailures.splice(i2, 1);
569641
+ return null;
569642
+ }
569473
569643
  const existing = this.fixes.find((f2) => sameFix(f2, delta.from, delta.to, fail3.errorKey));
569474
569644
  if (existing) {
569475
569645
  existing.count++;
@@ -569506,6 +569676,8 @@ var init_resolution_memory = __esm({
569506
569676
  const tokens = new Set(tokenize6(command));
569507
569677
  let best = null;
569508
569678
  for (const f2 of this.fixes) {
569679
+ if (isPathSensitiveFix(f2))
569680
+ continue;
569509
569681
  if (f2.from.every((t2) => tokens.has(t2))) {
569510
569682
  if (!best || f2.count > best.count)
569511
569683
  best = f2;
@@ -572051,7 +572223,7 @@ ${parts.join("\n")}
572051
572223
  /** State root for runner-owned memory/artifacts. Defaults to cwd/.omnius. */
572052
572224
  omniusStateDir() {
572053
572225
  const configured = (this.options.stateDir || "").trim();
572054
- return configured ? _pathResolve(configured) : _pathJoin(process.cwd(), ".omnius");
572226
+ return configured ? _pathResolve(configured) : _pathJoin(this.authoritativeWorkingDirectory(), ".omnius");
572055
572227
  }
572056
572228
  writesUserTaskArtifacts() {
572057
572229
  return this.options.artifactMode === "user-task" && !this.options.subAgent;
@@ -572178,7 +572350,7 @@ ${parts.join("\n")}
572178
572350
  }
572179
572351
  } catch {
572180
572352
  }
572181
- if (selected.size === 0) {
572353
+ if (selected.size === 0 && process.env["OMNIUS_FAILURE_PATTERN_INFERENCE"] === "1") {
572182
572354
  const relevant = await this._inferRelevantFailurePatternSignatures(taskGoal, candidates, maxPatterns);
572183
572355
  for (const signature of relevant) {
572184
572356
  const raw = this._errorPatterns.get(signature);
@@ -573098,7 +573270,7 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
573098
573270
  if (process.env["OMNIUS_DISABLE_REG66"] === "1")
573099
573271
  return { detected: false };
573100
573272
  const WINDOW = 20;
573101
- const SHELL_REPEAT_THRESHOLD = 5;
573273
+ const SHELL_REPEAT_THRESHOLD = 3;
573102
573274
  const READ_REPEAT_THRESHOLD = 4;
573103
573275
  const window2 = toolCallLog.slice(-WINDOW);
573104
573276
  if (window2.length < SHELL_REPEAT_THRESHOLD)
@@ -573225,13 +573397,85 @@ Pick the SMALLEST concrete deliverable from the spec — typically the project e
573225
573397
  return false;
573226
573398
  return true;
573227
573399
  }
573228
- _toolEvidencePreview(result, displayOutput, max = 500) {
573400
+ _toolEvidencePreview(result, displayOutput, max = 500, toolName) {
573229
573401
  const modelVisible = result.llmContent ?? result.output ?? displayOutput ?? "";
573230
573402
  const failurePrefix = result.success === false && result.error ? `Error: ${result.error}` : "";
573231
573403
  const combined = failurePrefix && modelVisible && !String(modelVisible).startsWith(failurePrefix) ? `${failurePrefix}
573232
573404
  ${modelVisible}` : modelVisible || result.error || displayOutput || "";
573405
+ const structured = this._structuredMediaEvidencePreview(toolName, String(combined));
573406
+ if (structured)
573407
+ return structured.slice(0, Math.max(max, 1200));
573233
573408
  return String(combined).slice(0, max);
573234
573409
  }
573410
+ _structuredMediaEvidencePreview(toolName, text2) {
573411
+ if (!toolName || !text2)
573412
+ return null;
573413
+ if (toolName !== "audio_analyze" && toolName !== "video_understand") {
573414
+ return null;
573415
+ }
573416
+ const lines = text2.replace(/\r/g, "").split("\n").map((line) => line.trim()).filter(Boolean);
573417
+ if (lines.length === 0)
573418
+ return null;
573419
+ if (toolName === "audio_analyze") {
573420
+ const kept2 = [];
573421
+ const answer = [];
573422
+ let inAnswer = false;
573423
+ for (const line of lines) {
573424
+ if (line.startsWith("# Audio comprehension:") || line.startsWith("duration ") || line.startsWith("roles:") || line.startsWith("quality:") || /^- (?:mean volume|max volume|silence|active audio windows):/i.test(line)) {
573425
+ kept2.push(line);
573426
+ continue;
573427
+ }
573428
+ if (line === "## Grounded Answer") {
573429
+ inAnswer = true;
573430
+ continue;
573431
+ }
573432
+ if (inAnswer && line.startsWith("## ")) {
573433
+ inAnswer = false;
573434
+ } else if (inAnswer && answer.length < 3) {
573435
+ answer.push(line);
573436
+ }
573437
+ }
573438
+ if (answer.length > 0)
573439
+ kept2.push(`grounded_answer=${answer.join(" ")}`);
573440
+ return kept2.length > 0 ? kept2.join(" | ") : null;
573441
+ }
573442
+ const kept = [];
573443
+ let inAudio = false;
573444
+ let audioLines = 0;
573445
+ let frameLines = 0;
573446
+ for (const line of lines) {
573447
+ if (line.startsWith("# Video Analysis") || line.startsWith("Source:") || line.startsWith("Duration:")) {
573448
+ kept.push(line);
573449
+ continue;
573450
+ }
573451
+ if (line === "## Audio Comprehension") {
573452
+ kept.push("Audio Comprehension: present");
573453
+ inAudio = true;
573454
+ audioLines = 0;
573455
+ continue;
573456
+ }
573457
+ if (line.startsWith("## Frames")) {
573458
+ kept.push(line);
573459
+ inAudio = false;
573460
+ frameLines = 0;
573461
+ continue;
573462
+ }
573463
+ if (line.startsWith("## ")) {
573464
+ inAudio = false;
573465
+ continue;
573466
+ }
573467
+ if (inAudio && audioLines < 8 && (line.startsWith("# Audio comprehension:") || line.startsWith("duration ") || line.startsWith("roles:") || line.startsWith("quality:") || /^- (?:mean volume|max volume|silence|active audio windows):/i.test(line))) {
573468
+ kept.push(line);
573469
+ audioLines++;
573470
+ continue;
573471
+ }
573472
+ if (/^\[[0-9:.]+\]\s+/.test(line) && frameLines < 3) {
573473
+ kept.push(line);
573474
+ frameLines++;
573475
+ }
573476
+ }
573477
+ return kept.length > 0 ? kept.join(" | ") : null;
573478
+ }
573235
573479
  _recordCompletionToolEvidenceFromResult(input) {
573236
573480
  if (!this._completionLedger || input.toolName === "task_complete")
573237
573481
  return;
@@ -573241,7 +573485,7 @@ ${modelVisible}` : modelVisible || result.error || displayOutput || "";
573241
573485
  this._completionLedger = recordToolEvidence(this._completionLedger, {
573242
573486
  name: input.toolName,
573243
573487
  success: input.result.success,
573244
- outputPreview: (input.outputPreview ?? this._toolEvidencePreview(input.result)).toString().slice(0, 500),
573488
+ outputPreview: (input.outputPreview ?? this._toolEvidencePreview(input.result, void 0, 1200, input.toolName)).toString().slice(0, input.toolName === "audio_analyze" || input.toolName === "video_understand" ? 1200 : 500),
573245
573489
  argsKey: input.argsKey.slice(0, 300),
573246
573490
  targetPaths: attemptedTargetPaths
573247
573491
  });
@@ -573784,6 +574028,18 @@ ${shellLines.join("\n")}` : "Commands run: none"
573784
574028
  const failCount = toolCallLog.filter((e2) => e2.success === false).length;
573785
574029
  evidenceParts.push(`Failed tool calls this run: ${failCount}`);
573786
574030
  const evidenceDigest = evidenceParts.join("\n");
574031
+ const hasFileAction = toolCallLog.some((e2) => e2.mutated || e2.name === "file_write" || e2.name === "file_edit" || e2.name === "batch_edit" || e2.name === "file_patch");
574032
+ if (!hasFileAction && failCount === 0) {
574033
+ const summaryNorm = proposedSummary.replace(/\s+/g, " ");
574034
+ const supportedByShellOutput = toolCallLog.filter((e2) => e2.name === "shell" && e2.success === true).some((e2) => {
574035
+ const output = String(e2.outputPreview ?? "").trim().replace(/\s+/g, " ");
574036
+ if (output.length < 8)
574037
+ return false;
574038
+ return summaryNorm.includes(output.slice(0, Math.min(output.length, 120)));
574039
+ });
574040
+ if (supportedByShellOutput)
574041
+ return { proceed: true };
574042
+ }
573787
574043
  const degraded = failCount > 0 ? await this._inferExplicitDegradedCompletion({
573788
574044
  turn,
573789
574045
  originalGoal,
@@ -578049,6 +578305,7 @@ TASK: ${scrubbedTask}` : scrubbedTask;
578049
578305
  currentTurn: turn,
578050
578306
  lastValidationTurn: this._lastBuildSuccessTurn,
578051
578307
  lastValidationCommand: this._lastBuildSuccessCommand,
578308
+ lastMutationTurn: this._lastFileWriteTurn,
578052
578309
  verifyFailureCount: this._verifyFailures.size,
578053
578310
  filesEdited: [...this._taskState.modifiedFiles.entries()].map(([path12, action]) => ({ path: path12, action }))
578054
578311
  });
@@ -580173,7 +580430,10 @@ Corrective action: try a different approach first: read relevant files, adjust a
580173
580430
  "background_run"
580174
580431
  ]);
580175
580432
  if (this._reg61PerpetualGateActive && !REG61_BYPASS_TOOLS.has(tc.name) && process.env["OMNIUS_DISABLE_REG61_COERCE"] !== "1") {
580176
- const _dbgLoop = this._detectDebugLoop(toolCallLog);
580433
+ const _dbgLoop = this._detectDebugLoop([
580434
+ ...toolCallLog,
580435
+ { name: tc.name, argsKey }
580436
+ ]);
580177
580437
  const _debugLoopSampleSafe = (_dbgLoop.repeatedSample ?? "").slice(0, 120);
580178
580438
  const _localFailureNudge = this._renderLocalFailureNudge(turn);
580179
580439
  const reg61SteerMsg = _dbgLoop.detected ? [
@@ -580329,6 +580589,43 @@ Use the saved fact to continue the promised synthesis or next concrete step, or
580329
580589
  systemGuidance: staleEditBlock
580330
580590
  };
580331
580591
  }
580592
+ const staleRewriteBlock = this.staleEditOverwritePreflightBlock(tc.name, tc.arguments ?? {});
580593
+ if (staleRewriteBlock) {
580594
+ this.emit({
580595
+ type: "tool_call",
580596
+ toolName: tc.name,
580597
+ toolArgs: tc.arguments,
580598
+ turn,
580599
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
580600
+ });
580601
+ this.emit({
580602
+ type: "tool_result",
580603
+ toolName: tc.name,
580604
+ success: false,
580605
+ content: staleRewriteBlock.slice(0, 120),
580606
+ turn,
580607
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
580608
+ });
580609
+ this._tagSyntheticFailure({
580610
+ mode: "step_repetition",
580611
+ rationale: "full-file overwrite attempted while a stale narrow-edit repair lock is active"
580612
+ });
580613
+ if (this._completionLedger) {
580614
+ this._completionLedger = recordToolEvidence(this._completionLedger, {
580615
+ name: tc.name,
580616
+ success: false,
580617
+ outputPreview: staleRewriteBlock.slice(0, 500),
580618
+ argsKey: tc.arguments ? JSON.stringify(tc.arguments).slice(0, 300) : ""
580619
+ });
580620
+ this._saveCompletionLedgerSafe();
580621
+ }
580622
+ return {
580623
+ tc,
580624
+ output: staleRewriteBlock,
580625
+ success: false,
580626
+ systemGuidance: staleRewriteBlock
580627
+ };
580628
+ }
580332
580629
  const baseIsReadLike = ![
580333
580630
  "file_write",
580334
580631
  "file_edit",
@@ -580463,11 +580760,12 @@ Use the saved fact to continue the promised synthesis or next concrete step, or
580463
580760
  if (repeatGateEligible && _existingFp !== void 0 && _repeatGateMax > 0) {
580464
580761
  if (criticDecision.hitNumber >= _repeatGateMax) {
580465
580762
  if (isReadLike) {
580763
+ const cachedResult = this.sanitizeCachedToolResult(tc.name, _existingFp.result);
580466
580764
  repeatShortCircuit = {
580467
580765
  success: true,
580468
580766
  output: `[STOP RE-READING — you have requested this exact read ${criticDecision.hitNumber}× and you ALREADY HAVE its full content, shown again below. Do NOT read it again. Act on it: edit the file, run a verification, or call task_complete. If a previous edit failed with "old_string not found", your old_string did not match the file — copy it EXACTLY (including indentation) from the content below.]
580469
580767
 
580470
- ` + _existingFp.result
580768
+ ` + cachedResult
580471
580769
  };
580472
580770
  } else {
580473
580771
  repeatShortCircuit = {
@@ -580477,9 +580775,10 @@ Use the saved fact to continue the promised synthesis or next concrete step, or
580477
580775
  };
580478
580776
  }
580479
580777
  } else {
580778
+ const cachedResult = this.sanitizeCachedToolResult(tc.name, _existingFp.result);
580480
580779
  repeatShortCircuit = {
580481
580780
  success: true,
580482
- output: _existingFp.result
580781
+ output: cachedResult
580483
580782
  };
580484
580783
  }
580485
580784
  }
@@ -581276,8 +581575,10 @@ Respond with EXACTLY this structure before your next tool call:
581276
581575
  if (tc.name === "shell") {
581277
581576
  const _shellCmd2 = String(tc.arguments?.["command"] ?? tc.arguments?.["cmd"] ?? "");
581278
581577
  const _declaredVerify = this._matchedDeclaredVerifyCommand(_shellCmd2);
581578
+ const _lastVerifier = this._lastVerifierResult;
581579
+ const _noTodoDirectValidation = !_declaredVerify && (this.readSessionTodos() || []).length === 0 && this._taskState.modifiedFiles.size > 0 && _lastVerifier?.outcomeClass === "verified";
581279
581580
  const _legacyGenericValidation = process.env["OMNIUS_ENABLE_GENERIC_COMPLETION_COMMAND_HEURISTIC"] === "1" && /\b(build|test|run\b|start\b|serve\b|verify|check)\b/i.test(_shellCmd2);
581280
- if (_declaredVerify || _legacyGenericValidation) {
581581
+ if (_declaredVerify || _noTodoDirectValidation || _legacyGenericValidation) {
581281
581582
  this._lastBuildSuccessTurn = turn;
581282
581583
  this._lastBuildSuccessCommand = (_declaredVerify || _shellCmd2).slice(0, 200);
581283
581584
  this._truthAutoCompleteBlockedValidationTurn = -1;
@@ -581458,7 +581759,7 @@ Respond with EXACTLY this structure before your next tool call:
581458
581759
  // source files (the "old_string not found" cascade). Large
581459
581760
  // files are handled by branch-extract upstream, so 16KB
581460
581761
  // here covers ordinary files without bloating the cache.
581461
- isReadLike ? (result.output ?? "").slice(0, 16e3) : (result.output ?? "").slice(0, 2e3)
581762
+ isReadLike ? this.sanitizeCachedToolResult(tc.name, result.output ?? "").slice(0, 16e3) : (result.output ?? "").slice(0, 2e3)
581462
581763
  ),
581463
581764
  compacted: false
581464
581765
  });
@@ -581750,12 +582051,12 @@ ${bookkeepingGuidance}` : bookkeepingGuidance;
581750
582051
  currentLogEntry.success = result.success;
581751
582052
  currentLogEntry.mutated = realFileMutation;
581752
582053
  currentLogEntry.mutatedFiles = realMutationPaths;
581753
- currentLogEntry.outputPreview = this._toolEvidencePreview(result, output);
582054
+ currentLogEntry.outputPreview = this._toolEvidencePreview(result, output, 1200, tc.name);
581754
582055
  }
581755
582056
  this._toolEvents.push({
581756
582057
  name: tc.name,
581757
582058
  success: result.success,
581758
- outputPreview: (result.output ?? result.error ?? output ?? "").toString().slice(0, 300),
582059
+ outputPreview: this._toolEvidencePreview(result, output, 1200, tc.name),
581759
582060
  turn
581760
582061
  });
581761
582062
  if (this._toolEvents.length > 200)
@@ -582096,7 +582397,7 @@ Then use file_read on individual FILES inside it.`);
582096
582397
  argsKey: tc.arguments ? JSON.stringify(tc.arguments) : "",
582097
582398
  args: tc.arguments,
582098
582399
  result,
582099
- outputPreview: this._toolEvidencePreview(result, output),
582400
+ outputPreview: this._toolEvidencePreview(result, output, 1200, tc.name),
582100
582401
  realFileMutation,
582101
582402
  realMutationPaths
582102
582403
  });
@@ -583202,7 +583503,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
583202
583503
  bfLogEntry.success = result.success;
583203
583504
  bfLogEntry.mutated = bfRealFileMutation;
583204
583505
  bfLogEntry.mutatedFiles = bfRealMutationPaths;
583205
- bfLogEntry.outputPreview = this._toolEvidencePreview(result, output);
583506
+ bfLogEntry.outputPreview = this._toolEvidencePreview(result, output, 1200, tc.name);
583206
583507
  }
583207
583508
  this.emit({
583208
583509
  type: "tool_result",
@@ -583218,7 +583519,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
583218
583519
  argsKey: bfArgsKey,
583219
583520
  args: tc.arguments,
583220
583521
  result,
583221
- outputPreview: this._toolEvidencePreview(result, output),
583522
+ outputPreview: this._toolEvidencePreview(result, output, 1200, tc.name),
583222
583523
  realFileMutation: bfRealFileMutation,
583223
583524
  realMutationPaths: bfRealMutationPaths
583224
583525
  });
@@ -584303,15 +584604,32 @@ ${marker}` : marker);
584303
584604
  return "stale_old_string";
584304
584605
  return null;
584305
584606
  }
584306
- staleEditFamilyKey(toolName, path12, errorKind, targetHash) {
584307
- return toolName + ":" + path12 + ":" + errorKind + ":" + targetHash;
584607
+ staleEditPathKey(path12) {
584608
+ const trimmed = path12.trim();
584609
+ if (!trimmed)
584610
+ return "";
584611
+ try {
584612
+ return _pathResolve(this._workingDirectory || process.cwd(), trimmed).replace(/\\/g, "/");
584613
+ } catch {
584614
+ return trimmed.replace(/\\/g, "/").replace(/^\.\/+/, "");
584615
+ }
584616
+ }
584617
+ staleEditFamilyKey(toolName, pathKey, errorKind, targetHash, latestFileHash) {
584618
+ return [
584619
+ toolName,
584620
+ pathKey || "(unknown)",
584621
+ errorKind,
584622
+ targetHash,
584623
+ latestFileHash || "unknown-file-hash"
584624
+ ].join(":");
584308
584625
  }
584309
584626
  staleEditPreflightBlock(toolName, args) {
584310
584627
  const target = this.staleEditTarget(toolName, args);
584311
584628
  if (!target)
584312
584629
  return null;
584630
+ const pathKey = this.staleEditPathKey(target.path);
584313
584631
  for (const entry of this._staleEditFamilies.values()) {
584314
- if (entry.tool !== toolName || entry.path !== target.path || entry.targetHash !== target.targetHash)
584632
+ if (entry.tool !== toolName || entry.pathKey !== pathKey || entry.targetHash !== target.targetHash)
584315
584633
  continue;
584316
584634
  const hasFreshRead = entry.lastReadTurn > entry.lastFailureTurn;
584317
584635
  const hasFreshMutation = entry.lastMutationTurn > entry.lastFailureTurn;
@@ -584328,23 +584646,65 @@ ${marker}` : marker);
584328
584646
  }
584329
584647
  return null;
584330
584648
  }
584649
+ staleEditOverwritePreflightBlock(toolName, args) {
584650
+ if (toolName !== "file_write")
584651
+ return null;
584652
+ if (process.env["OMNIUS_ALLOW_STALE_REPAIR_OVERWRITE"] === "1")
584653
+ return null;
584654
+ if (this.options.modelTier !== "small" && this.options.modelTier !== "medium")
584655
+ return null;
584656
+ if (args?.["dry_run"] === true || args?.["dryRun"] === true)
584657
+ return null;
584658
+ const path12 = this.extractPrimaryToolPath(args);
584659
+ if (!path12)
584660
+ return null;
584661
+ const pathKey = this.staleEditPathKey(path12);
584662
+ const active = [...this._staleEditFamilies.values()].filter((entry) => entry.pathKey === pathKey).sort((a2, b) => b.lastFailureTurn - a2.lastFailureTurn).find((entry) => {
584663
+ const hasFreshRead = entry.lastReadTurn > entry.lastFailureTurn;
584664
+ const hasFreshMutation = entry.lastMutationTurn > entry.lastFailureTurn;
584665
+ return !hasFreshMutation && (entry.count >= 2 || !hasFreshRead);
584666
+ });
584667
+ if (!active)
584668
+ return null;
584669
+ return [
584670
+ `[EDIT REPAIR LOCK] A recent narrow edit to ${active.path} failed because the model-visible target diverged from disk (${active.errorKind}; latest_file_hash=${active.latestFileHash || "unknown"}).`,
584671
+ `This full-file overwrite was NOT executed. A stale narrow edit must not be repaired by broad file regeneration on ${this.options.modelTier ?? "unknown"} tier models.`,
584672
+ ``,
584673
+ `Allowed next actions:`,
584674
+ `1. file_read ${active.path} once and construct file_edit from exact current text.`,
584675
+ `2. file_patch/file_edit against the latest file hash or a different target.`,
584676
+ `3. file_write with dry_run=true only to validate a full rewrite proposal without changing disk.`,
584677
+ `4. run verification if the desired change is already present, or report the explicit blocker instead of completing.`,
584678
+ ``,
584679
+ `Stale target preview: ${active.preview}`
584680
+ ].join("\n");
584681
+ }
584331
584682
  noteStaleEditGuardOutcome(toolName, args, result, turn) {
584332
584683
  const path12 = this.extractPrimaryToolPath(args);
584684
+ const pathKey = path12 ? this.staleEditPathKey(path12) : "";
584333
584685
  if (toolName === "file_read" && path12 && result.success) {
584334
584686
  for (const entry of this._staleEditFamilies.values()) {
584335
- if (entry.path === path12)
584687
+ if (entry.pathKey === pathKey)
584336
584688
  entry.lastReadTurn = turn;
584337
584689
  }
584338
584690
  return;
584339
584691
  }
584692
+ if (toolName === "file_write" && path12 && result.success && result.mutated !== false) {
584693
+ for (const [key2, entry] of this._staleEditFamilies) {
584694
+ if (entry.pathKey === pathKey)
584695
+ this._staleEditFamilies.delete(key2);
584696
+ }
584697
+ return;
584698
+ }
584340
584699
  if (!this.isEditToolName(toolName))
584341
584700
  return;
584342
584701
  const target = this.staleEditTarget(toolName, args);
584343
584702
  if (!target)
584344
584703
  return;
584704
+ const targetPathKey = this.staleEditPathKey(target.path);
584345
584705
  if (result.success && result.mutated !== false) {
584346
584706
  for (const [key2, entry] of this._staleEditFamilies) {
584347
- if (entry.path === target.path)
584707
+ if (entry.pathKey === targetPathKey)
584348
584708
  this._staleEditFamilies.delete(key2);
584349
584709
  }
584350
584710
  return;
@@ -584352,14 +584712,17 @@ ${marker}` : marker);
584352
584712
  const errorKind = this.classifyStaleEditFailure(toolName, result);
584353
584713
  if (!errorKind)
584354
584714
  return;
584355
- const key = this.staleEditFamilyKey(toolName, target.path, errorKind, target.targetHash);
584715
+ const latestFileHash = typeof result.beforeHash === "string" && result.beforeHash.trim() ? result.beforeHash.trim() : typeof result.afterHash === "string" && result.afterHash.trim() ? result.afterHash.trim() : "unknown-file-hash";
584716
+ const key = this.staleEditFamilyKey(toolName, targetPathKey, errorKind, target.targetHash, latestFileHash);
584356
584717
  const existing = this._staleEditFamilies.get(key);
584357
584718
  this._staleEditFamilies.set(key, {
584358
584719
  count: (existing?.count ?? 0) + 1,
584359
584720
  path: target.path,
584721
+ pathKey: targetPathKey,
584360
584722
  tool: toolName,
584361
584723
  errorKind,
584362
584724
  targetHash: target.targetHash,
584725
+ latestFileHash,
584363
584726
  lastFailureTurn: turn,
584364
584727
  lastReadTurn: existing?.lastReadTurn ?? -1,
584365
584728
  lastMutationTurn: existing?.lastMutationTurn ?? -1,
@@ -584378,6 +584741,16 @@ ${marker}` : marker);
584378
584741
  }
584379
584742
  return hash.toString(16).padStart(8, "0");
584380
584743
  }
584744
+ sanitizeCachedToolResult(toolName, output) {
584745
+ let text2 = output;
584746
+ if (text2.includes("[IMAGE_BASE64:")) {
584747
+ text2 = text2.replace(/\[IMAGE_BASE64:[^\]]+\]/g, "[image binary omitted from repeat cache; use the OCR/image analysis text in this result]");
584748
+ }
584749
+ if (toolName === "image_read" && text2.length > 8e3) {
584750
+ text2 = this.foldOutput(text2, 8e3);
584751
+ }
584752
+ return text2;
584753
+ }
584381
584754
  /**
584382
584755
  * WO-NORMALIZE: Normalize tool output at source.
584383
584756
  * Caps output length, persists large results to .omnius/tool-results/ with preview,
@@ -601304,6 +601677,10 @@ var init_command_registry = __esm({
601304
601677
  ["/memory episodes", "Show recent episodes view"],
601305
601678
  ["/memory concepts", "Show concept clusters view"],
601306
601679
  ["/memory timeline", "Show temporal timeline view"],
601680
+ [
601681
+ "/metabolize [--dry-run] [--verbose] [--min-score <n>]",
601682
+ "Run memory metabolism: score and compact stale episode entries"
601683
+ ],
601307
601684
  ["/verbose", "Toggle verbose mode"],
601308
601685
  ["/clear", "Clear the screen"],
601309
601686
  ["/help", "Show this help"],
@@ -601407,6 +601784,7 @@ var init_command_registry = __esm({
601407
601784
  skillify: "tools",
601408
601785
  memory: "memory",
601409
601786
  mem: "memory",
601787
+ metabolize: "memory",
601410
601788
  mouse: "ui",
601411
601789
  color: "ui",
601412
601790
  colors: "ui",
@@ -601453,6 +601831,7 @@ var init_command_registry = __esm({
601453
601831
  "task-type": ["tasktype", "tt"],
601454
601832
  stats: ["dashboard"],
601455
601833
  memory: ["mem"],
601834
+ metabolize: ["metab"],
601456
601835
  files: ["workspace"],
601457
601836
  skills: ["skill"],
601458
601837
  commands: ["cmds"],
@@ -602166,8 +602545,8 @@ function formatTokenCount(t2) {
602166
602545
  }
602167
602546
  function buildMetricsChip(data) {
602168
602547
  const parts = [];
602169
- parts.push(`${data.turns}t`);
602170
- parts.push(`${data.toolCalls}c`);
602548
+ parts.push(`${data.turns} ${data.turns === 1 ? "turn" : "turns"}`);
602549
+ parts.push(`${data.toolCalls} ${data.toolCalls === 1 ? "call" : "calls"}`);
602171
602550
  if (data.tokens && data.durationMs > 0) {
602172
602551
  const total = data.tokens.total > 0 ? data.tokens.total : data.tokens.estimated;
602173
602552
  if (total > 0) {
@@ -604960,7 +605339,7 @@ function renderInfo(message2) {
604960
605339
  breakTelegramCoalesce();
604961
605340
  const redir = _contentWriteHook?.redirect?.();
604962
605341
  const dim = dimFg();
604963
- const icon = `${dim}∙\x1B[0m`;
605342
+ const icon = `${dim}🛈\x1B[0m`;
604964
605343
  const prefix = `${icon} ${dim}`;
604965
605344
  const lines = wrapLinesWithPrefix(message2, prefix, getTermWidth());
604966
605345
  const text2 = `${lines.map((l2) => l2 + "\x1B[0m").join("\n")}
@@ -611306,6 +611685,27 @@ function watchForOmniusGitignore(repoRoot) {
611306
611685
  }
611307
611686
  if (watchers.length > 0) gitignoreWatchers.set(key, watchers);
611308
611687
  }
611688
+ function scheduleOmniusGitignoreRescans(repoRoot) {
611689
+ const key = resolve54(repoRoot);
611690
+ if (gitignoreRetryTimers.has(key)) return;
611691
+ const timers = [25, 100, 250, 500, 1e3].map((delay3) => {
611692
+ const timer = setTimeout(() => {
611693
+ try {
611694
+ ensureOmniusIgnored(repoRoot);
611695
+ } catch {
611696
+ }
611697
+ const list = gitignoreRetryTimers.get(key);
611698
+ if (list) {
611699
+ const idx = list.indexOf(timer);
611700
+ if (idx >= 0) list.splice(idx, 1);
611701
+ if (list.length === 0) gitignoreRetryTimers.delete(key);
611702
+ }
611703
+ }, delay3);
611704
+ timer.unref?.();
611705
+ return timer;
611706
+ });
611707
+ gitignoreRetryTimers.set(key, timers);
611708
+ }
611309
611709
  function stopOmniusGitignoreWatcher(repoRoot) {
611310
611710
  const keys = repoRoot ? [resolve54(repoRoot)] : Array.from(gitignoreWatchers.keys());
611311
611711
  for (const key of keys) {
@@ -611317,6 +611717,9 @@ function stopOmniusGitignoreWatcher(repoRoot) {
611317
611717
  }
611318
611718
  }
611319
611719
  gitignoreWatchers.delete(key);
611720
+ const timers = gitignoreRetryTimers.get(key) ?? [];
611721
+ for (const timer of timers) clearTimeout(timer);
611722
+ gitignoreRetryTimers.delete(key);
611320
611723
  }
611321
611724
  }
611322
611725
  function migrateLegacyDirectories(repoRoot, omniusPath) {
@@ -611348,6 +611751,10 @@ function initOmniusDirectory(repoRoot) {
611348
611751
  watchForOmniusGitignore(repoRoot);
611349
611752
  } catch {
611350
611753
  }
611754
+ try {
611755
+ scheduleOmniusGitignoreRescans(repoRoot);
611756
+ } catch {
611757
+ }
611351
611758
  return omniusPath;
611352
611759
  }
611353
611760
  function hasOmniusDirectory(repoRoot) {
@@ -612375,7 +612782,7 @@ function deleteUsageRecord(kind, value2, repoRoot) {
612375
612782
  remove(join126(repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE));
612376
612783
  }
612377
612784
  }
612378
- var OMNIUS_DIR, LEGACY_DIRS, SUBDIRS, gitignoreWatchers, CONTEXT_FILES, PENDING_TASK_FILE, HANDOFF_FILE, CONTEXT_SAVE_FILE, CONTEXT_LEDGER_FILE, MAX_CONTEXT_ENTRIES, MAX_SESSION_DIARY_ENTRIES, MAX_SESSION_DIARY_DETAILED_ENTRIES, MAX_CONTEXT_LEDGER_LINES, MAX_CONTEXT_LEDGER_BYTES, SAME_TASK_REPLACE_WINDOW_MS, LOCK_TIMEOUT_MS, LOCK_RETRY_MS, LOCK_RETRY_MAX, SESSIONS_DIR, SESSIONS_INDEX, SKIP_DIRS3, HOME_SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
612785
+ var OMNIUS_DIR, LEGACY_DIRS, SUBDIRS, gitignoreWatchers, gitignoreRetryTimers, CONTEXT_FILES, PENDING_TASK_FILE, HANDOFF_FILE, CONTEXT_SAVE_FILE, CONTEXT_LEDGER_FILE, MAX_CONTEXT_ENTRIES, MAX_SESSION_DIARY_ENTRIES, MAX_SESSION_DIARY_DETAILED_ENTRIES, MAX_CONTEXT_LEDGER_LINES, MAX_CONTEXT_LEDGER_BYTES, SAME_TASK_REPLACE_WINDOW_MS, LOCK_TIMEOUT_MS, LOCK_RETRY_MS, LOCK_RETRY_MAX, SESSIONS_DIR, SESSIONS_INDEX, SKIP_DIRS3, HOME_SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
612379
612786
  var init_omnius_directory = __esm({
612380
612787
  "packages/cli/src/tui/omnius-directory.ts"() {
612381
612788
  "use strict";
@@ -612384,6 +612791,7 @@ var init_omnius_directory = __esm({
612384
612791
  LEGACY_DIRS = [".oa", ".open-agents"];
612385
612792
  SUBDIRS = ["memory", "index", "context", "history", "notes", "embedded", "provenance", "tools", "dreams"];
612386
612793
  gitignoreWatchers = /* @__PURE__ */ new Map();
612794
+ gitignoreRetryTimers = /* @__PURE__ */ new Map();
612387
612795
  CONTEXT_FILES = [
612388
612796
  "AGENTS.md",
612389
612797
  "Omnius.md",
@@ -614844,7 +615252,7 @@ var init_status_bar = __esm({
614844
615252
  BOX_FG = tuiBoxFg();
614845
615253
  TEXT_PRIMARY = tuiTextPrimary() < 0 ? 252 : tuiTextPrimary();
614846
615254
  TEXT_DIM = tuiTextDim();
614847
- NO_SUB_AGENTS_HEADER_LABEL = " no agents ";
615255
+ NO_SUB_AGENTS_HEADER_LABEL = " no sub-agents ";
614848
615256
  HEADER_BUTTON_GLYPH_FG = headerButtonGlyphFg();
614849
615257
  HEADER_BUTTON_BG = headerButtonBg();
614850
615258
  HEADER_BUTTON_FG = headerButtonFg();
@@ -615253,11 +615661,11 @@ var init_status_bar = __esm({
615253
615661
  return "p2p";
615254
615662
  if (backendType === "fake") return "fake";
615255
615663
  if (!backendUrl2) return "";
615256
- if (backendType) return backendType;
615257
615664
  if (backendUrl2.includes("127.0.0.1") || backendUrl2.includes("localhost") || backendUrl2.includes("0.0.0.0")) {
615258
615665
  return "local";
615259
615666
  }
615260
- return "remote";
615667
+ if (/^https?:\/\//i.test(backendUrl2)) return "remote";
615668
+ return backendType || "remote";
615261
615669
  }
615262
615670
  buildHeaderIdentitySegments() {
615263
615671
  const sponsorLabel = (this._sponsorHeader?.message || this._sponsorHeader?.linkText || "").trim();
@@ -615277,6 +615685,16 @@ var init_status_bar = __esm({
615277
615685
  last2.width += 2;
615278
615686
  }
615279
615687
  }
615688
+ const modelSummary2 = this.summarizeHeaderModelName();
615689
+ if (modelSummary2) {
615690
+ const text2 = ` ${modelSummary2} `;
615691
+ parts.push({ text: text2, width: stripAnsi(text2).length });
615692
+ }
615693
+ const transportSummary = this.summarizeHeaderTransport();
615694
+ if (transportSummary) {
615695
+ const text2 = ` ${transportSummary} `;
615696
+ parts.push({ text: text2, width: stripAnsi(text2).length });
615697
+ }
615280
615698
  if (this._processing) {
615281
615699
  const glyph = _StatusBar.HEADER_SPINNER_FRAMES[this._headerSpinnerFrame] ?? "";
615282
615700
  const last2 = parts[parts.length - 1];
@@ -615592,20 +616010,23 @@ var init_status_bar = __esm({
615592
616010
  return [];
615593
616011
  }
615594
616012
  getHeaderChromeLayout(termWidth) {
616013
+ const showPrev = this._headerPanelIndex > 0;
616014
+ const showNext = this._headerPanelIndex < this._headerPanels.length - 1;
616015
+ const contentStartCol = showPrev ? 4 : 2;
616016
+ const rightChrome = showNext ? 1 : 0;
615595
616017
  return {
615596
- showPrev: false,
615597
- showNext: true,
615598
- prevLabel: this._headerExpanded ? "▲" : "▼",
615599
- //
615600
- contentStartCol: 2,
615601
- innerWidth: Math.max(1, termWidth - 4)
616018
+ showPrev,
616019
+ showNext,
616020
+ contentStartCol,
616021
+ innerWidth: Math.max(1, termWidth - contentStartCol - rightChrome)
615602
616022
  };
615603
616023
  }
615604
616024
  hitTestCurrentHeaderAction(row, col, termWidth) {
615605
616025
  const hdrRow = layout().headerContent;
615606
616026
  if (row !== hdrRow) return null;
615607
616027
  const chrome = this.getHeaderChromeLayout(termWidth);
615608
- if (chrome.showNext && col === termWidth - 2) return "header-toggle";
616028
+ if (chrome.showPrev && col === 2) return "header-prev";
616029
+ if (chrome.showNext && col === termWidth - 1) return "header-next";
615609
616030
  const hit = this._headerCommandZones.find(
615610
616031
  (zone) => col >= zone.start && col <= zone.end
615611
616032
  );
@@ -615698,9 +616119,14 @@ var init_status_bar = __esm({
615698
616119
  let buf = "\x1B7";
615699
616120
  buf += `\x1B[${hdrRow};1H${PANEL_BG_SEQ}\x1B[2K`;
615700
616121
  buf += `${BOX_FG}│${RESET4}${PANEL_BG_SEQ}`;
616122
+ if (chromeLayout.showPrev) {
616123
+ buf += `${HEADER_BUTTON_FG}◀${RESET4}${PANEL_BG_SEQ} `;
616124
+ }
615701
616125
  buf += `\x1B[38;5;${TEXT_PRIMARY}m${PANEL_BG_SEQ}`;
615702
616126
  buf += content;
615703
- buf += `\x1B[${hdrRow};${w - 2}H${chromeLayout.prevLabel}${RESET4}${PANEL_BG_SEQ}`;
616127
+ if (chromeLayout.showNext) {
616128
+ buf += `\x1B[${hdrRow};${w - 1}H${HEADER_BUTTON_FG}▶${RESET4}${PANEL_BG_SEQ}`;
616129
+ }
615704
616130
  buf += `\x1B[${hdrRow};${w}H${BOX_FG}│${RESET4}${PANEL_BG_SEQ}`;
615705
616131
  const scrollPct = this._contentScrollOffset > 0 ? `${Math.round(this._contentScrollOffset / this._contentMaxLines * 100)}%` : "live";
615706
616132
  if (this._headerExpanded) {
@@ -618027,6 +618453,10 @@ ${CONTENT_BG_SEQ}`);
618027
618453
  const digits = String(n2).split("");
618028
618454
  return digits.map((d2) => this.DIGIT_EMOJI[parseInt(d2)] ?? d2).join("");
618029
618455
  }
618456
+ static formatInteger(n2) {
618457
+ if (!Number.isFinite(n2) || n2 < 0) return "0";
618458
+ return Math.round(n2).toLocaleString();
618459
+ }
618030
618460
  /** Render a digit bar with a given fg color, wrapped in panel bg */
618031
618461
  static digitBarAnsi(n2, fgCode) {
618032
618462
  const bar = this.digitBar(n2);
@@ -618073,10 +618503,10 @@ ${CONTENT_BG_SEQ}`);
618073
618503
  const tpsStr = _StatusBar.formatTokensPerSecond(this._tokensPerSecond);
618074
618504
  const tpsExpanded = " " + pastel2(222, "t/s") + " " + c3.bold(tpsStr);
618075
618505
  const tpsW = 1 + 3 + 1 + tpsStr.length;
618076
- const tokExpanded = pastel2(117, "↑") + _StatusBar.digitBarAnsi(tokInRaw, 117) + " " + pastel2(151, "↓") + _StatusBar.digitBarAnsi(tokOutVal, 151) + " " + pastel2(222, "t/s") + " " + c3.bold(tpsStr);
618077
- const tokCompact = pastel2(117, "↑") + _StatusBar.digitBarAnsi(tokInRaw, 117) + " " + pastel2(151, "↓") + _StatusBar.digitBarAnsi(tokOutVal, 151) + " " + pastel2(222, "t/s") + " " + c3.bold(tpsStr);
618078
- const tokExpW = 1 + _StatusBar.digitBar(tokInRaw).length + 1 + 1 + _StatusBar.digitBar(tokOutVal).length + tpsW;
618079
- const tokCompW = 1 + _StatusBar.digitBar(tokInRaw).length + 1 + 1 + _StatusBar.digitBar(tokOutVal).length + tpsW;
618506
+ const tokExpanded = pastel2(117, "↑") + pastel2(117, _StatusBar.formatInteger(tokInRaw)) + " " + pastel2(151, "↓") + pastel2(151, _StatusBar.formatInteger(tokOutVal)) + " " + pastel2(222, "t/s") + " " + c3.bold(tpsStr);
618507
+ const tokCompact = pastel2(117, "↑") + pastel2(117, _StatusBar.formatInteger(tokInRaw)) + " " + pastel2(151, "↓") + pastel2(151, _StatusBar.formatInteger(tokOutVal)) + " " + pastel2(222, "t/s") + " " + c3.bold(tpsStr);
618508
+ const tokExpW = 1 + _StatusBar.formatInteger(tokInRaw).length + 1 + 1 + _StatusBar.formatInteger(tokOutVal).length + tpsW;
618509
+ const tokCompW = 1 + _StatusBar.formatInteger(tokInRaw).length + 1 + 1 + _StatusBar.formatInteger(tokOutVal).length + tpsW;
618080
618510
  sections.push({
618081
618511
  expanded: tokExpanded,
618082
618512
  compact: tokCompact,
@@ -618264,24 +618694,24 @@ ${CONTENT_BG_SEQ}`);
618264
618694
  if (rm4.cpuUtil >= 0) {
618265
618695
  const cpuColor = rm4.cpuUtil > 80 ? c3.red : rm4.cpuUtil > 50 ? c3.yellow : c3.green;
618266
618696
  const cpuCoresInfo = rm4.cpuCores > 0 ? ` (${_StatusBar.digitBar(rm4.cpuCores)}c` + (rm4.cpuModel ? " " + rm4.cpuModel.replace(/\s+/g, " ").slice(0, 30) : "") + ")" : "";
618267
- hwExpStr += `CPU${cpuColor(_StatusBar.digitBar(rm4.cpuUtil) + "%")}${c3.dim(cpuCoresInfo)}`;
618268
- hwCompStr += `CPU${cpuColor(_StatusBar.digitBar(rm4.cpuUtil) + "%")}`;
618269
- hwExpW += 4 + `${rm4.cpuUtil}%`.length + cpuCoresInfo.length;
618270
- hwCompW += 4 + `${rm4.cpuUtil}%`.length;
618697
+ hwExpStr += `CPU ${cpuColor(_StatusBar.digitBar(rm4.cpuUtil) + "%")}${c3.dim(cpuCoresInfo)}`;
618698
+ hwCompStr += `CPU ${cpuColor(_StatusBar.digitBar(rm4.cpuUtil) + "%")}`;
618699
+ hwExpW += 5 + `${rm4.cpuUtil}%`.length + cpuCoresInfo.length;
618700
+ hwCompW += 5 + `${rm4.cpuUtil}%`.length;
618271
618701
  }
618272
618702
  if (rm4.memUtil >= 0) {
618273
618703
  const memColor = rm4.memUtil > 80 ? c3.red : rm4.memUtil > 50 ? c3.yellow : c3.green;
618274
618704
  const memDetail = rm4.memTotalGB > 0 ? ` (${rm4.memUsedGB}/${rm4.memTotalGB}GB)` : "";
618275
- hwExpStr += ` RAM${memColor(_StatusBar.digitBar(rm4.memUtil) + "%")}${c3.dim(memDetail)}`;
618276
- hwCompStr += ` RAM${memColor(_StatusBar.digitBar(rm4.memUtil) + "%")}`;
618705
+ hwExpStr += ` RAM ${memColor(_StatusBar.digitBar(rm4.memUtil) + "%")}${c3.dim(memDetail)}`;
618706
+ hwCompStr += ` RAM ${memColor(_StatusBar.digitBar(rm4.memUtil) + "%")}`;
618277
618707
  hwExpW += 5 + `${rm4.memUtil}%`.length + memDetail.length;
618278
618708
  hwCompW += 5 + `${rm4.memUtil}%`.length;
618279
618709
  }
618280
618710
  if (rm4.diskUtil >= 0) {
618281
618711
  const diskColor = rm4.diskUtil > 90 ? c3.red : rm4.diskUtil > 75 ? c3.yellow : c3.green;
618282
618712
  const diskDetail = rm4.diskTotalGB > 0 ? ` (${rm4.diskFreeGB.toFixed(rm4.diskFreeGB < 10 ? 1 : 0)}GB free)` : "";
618283
- hwExpStr += ` DISK${diskColor(_StatusBar.digitBar(rm4.diskUtil) + "%")}${c3.dim(diskDetail)}`;
618284
- hwCompStr += ` DISK${diskColor(_StatusBar.digitBar(rm4.diskUtil) + "%")}`;
618713
+ hwExpStr += ` DISK ${diskColor(_StatusBar.digitBar(rm4.diskUtil) + "%")}${c3.dim(diskDetail)}`;
618714
+ hwCompStr += ` DISK ${diskColor(_StatusBar.digitBar(rm4.diskUtil) + "%")}`;
618285
618715
  hwExpW += 6 + `${rm4.diskUtil}%`.length + diskDetail.length;
618286
618716
  hwCompW += 6 + `${rm4.diskUtil}%`.length;
618287
618717
  }
@@ -640282,6 +640712,22 @@ The session corrections MUST become hard rules in the SKILL.md Rules section.`;
640282
640712
  await showCohereStatus(ctx3);
640283
640713
  return "handled";
640284
640714
  }
640715
+ if (arg === "models") {
640716
+ const nexus = new NexusTool(ctx3.repoRoot);
640717
+ const result = await nexus.execute({
640718
+ action: "cohere_list_models",
640719
+ format: "json"
640720
+ });
640721
+ if (result.success) {
640722
+ renderInfo(`COHERE all endpoint models:
640723
+ ${result.output}`);
640724
+ } else {
640725
+ renderError(
640726
+ result.error || result.output || "COHERE model listing failed."
640727
+ );
640728
+ }
640729
+ return "handled";
640730
+ }
640285
640731
  await showCohereDashboard(ctx3);
640286
640732
  return "handled";
640287
640733
  }
@@ -650566,6 +651012,7 @@ async function handleUpdate(subcommand, ctx3) {
650566
651012
  installOverlay.stop("Requesting permissions...");
650567
651013
  await new Promise((r2) => setTimeout(r2, 300));
650568
651014
  installOverlay.dismiss();
651015
+ renderInfo("Global npm directory requires elevated permissions.");
650569
651016
  const sudoReady = await acquireSudoCredentials(
650570
651017
  ctx3,
650571
651018
  "The global npm directory requires elevated permissions for this update."
@@ -651825,7 +652272,7 @@ function getModelTier(modelName) {
651825
652272
  if (sizeMatch) {
651826
652273
  const size = parseInt(sizeMatch[1], 10);
651827
652274
  if (size >= 30) return "large";
651828
- if (size >= 8) return "medium";
652275
+ if (size >= 14) return "medium";
651829
652276
  return "small";
651830
652277
  }
651831
652278
  if (/\b(small|mini|nano|tiny)\b/.test(m2)) return "small";
@@ -655593,12 +656040,12 @@ var init_stream_renderer = __esm({
655593
656040
  this.thinkingBoxOpen = true;
655594
656041
  this.thinkingBoxRowCount = 2;
655595
656042
  this.writeRaw(thinkingBoxTop(w) + "\n");
655596
- this.writeRaw(thinkingBoxRow(dimItalic("processing..."), w) + "\n");
656043
+ this.writeRaw(thinkingBoxRow(dimItalic("thinking..."), w) + "\n");
655597
656044
  this.lineStarted = false;
655598
656045
  }
655599
656046
  if (this.thinkingTokenCount % 500 === 0) {
655600
656047
  this.updateThinkingBox(
655601
- `processing... (${this.thinkingTokenCount} tokens)`,
656048
+ `thinking... (${this.thinkingTokenCount} tokens)`,
655602
656049
  w
655603
656050
  );
655604
656051
  }
@@ -660661,12 +661108,6 @@ function buildToolDetailText(tool) {
660661
661108
  lines.push("🔙 <i>Tap Back to return to the tool list.</i>");
660662
661109
  return lines.join("\n");
660663
661110
  }
660664
- function renderHelpMenu(scope) {
660665
- const tools = buildScopedToolList(scope);
660666
- const text2 = buildToolListText(tools, 0, scope);
660667
- const inline_keyboard = buildToolListKeyboard(tools, 0, scope);
660668
- return { text: text2, replyMarkup: { inline_keyboard } };
660669
- }
660670
661111
  function renderHelpMenuPage(scope, page2) {
660671
661112
  const tools = buildScopedToolList(scope);
660672
661113
  const totalPages = Math.max(1, Math.ceil(tools.length / TOOLS_PER_PAGE));
@@ -660675,14 +661116,6 @@ function renderHelpMenuPage(scope, page2) {
660675
661116
  const inline_keyboard = buildToolListKeyboard(tools, page2, scope);
660676
661117
  return { text: text2, replyMarkup: { inline_keyboard } };
660677
661118
  }
660678
- function renderHelpMenuPageWithCountdown(scope, page2, countdown) {
660679
- const tools = buildScopedToolList(scope);
660680
- const totalPages = Math.max(1, Math.ceil(tools.length / TOOLS_PER_PAGE));
660681
- page2 = Math.max(0, Math.min(page2, totalPages - 1));
660682
- const text2 = buildToolListText(tools, page2, scope);
660683
- const inline_keyboard = buildToolListKeyboard(tools, page2, scope, countdown);
660684
- return { text: text2, replyMarkup: { inline_keyboard } };
660685
- }
660686
661119
  function renderHelpToolDetail(scope, toolName, returnPage) {
660687
661120
  const tools = buildScopedToolList(scope);
660688
661121
  const tool = tools.find((t2) => t2.name === toolName);
@@ -660727,7 +661160,7 @@ function handleHelpCallback(callbackData, currentState) {
660727
661160
  }
660728
661161
  return { render: render2, newState };
660729
661162
  }
660730
- var TOOLS_PER_PAGE, GRID_COLS, CALLBACK_PREFIX, MAX_CALLBACK_DATA, INACTIVITY_TIMEOUT_MS, COUNTDOWN_SECONDS, TELEGRAM_PUBLIC_HELP_COMMANDS, HelpMenuStateStore, HelpMenuTimerManager;
661163
+ var TOOLS_PER_PAGE, GRID_COLS, CALLBACK_PREFIX, MAX_CALLBACK_DATA, TELEGRAM_PUBLIC_HELP_COMMANDS, HelpMenuStateStore;
660731
661164
  var init_telegram_help_menu = __esm({
660732
661165
  "packages/cli/src/tui/telegram-help-menu.ts"() {
660733
661166
  "use strict";
@@ -660736,8 +661169,6 @@ var init_telegram_help_menu = __esm({
660736
661169
  GRID_COLS = 5;
660737
661170
  CALLBACK_PREFIX = "help";
660738
661171
  MAX_CALLBACK_DATA = 64;
660739
- INACTIVITY_TIMEOUT_MS = 6e4;
660740
- COUNTDOWN_SECONDS = 10;
660741
661172
  TELEGRAM_PUBLIC_HELP_COMMANDS = /* @__PURE__ */ new Set(["help", "start", "auth", "call"]);
660742
661173
  HelpMenuStateStore = class {
660743
661174
  states = /* @__PURE__ */ new Map();
@@ -660763,124 +661194,6 @@ var init_telegram_help_menu = __esm({
660763
661194
  }
660764
661195
  }
660765
661196
  };
660766
- HelpMenuTimerManager = class {
660767
- inactivityTimers = /* @__PURE__ */ new Map();
660768
- countdownIntervals = /* @__PURE__ */ new Map();
660769
- stateStore;
660770
- callbacks;
660771
- constructor(stateStore, callbacks) {
660772
- this.stateStore = stateStore;
660773
- this.callbacks = callbacks;
660774
- }
660775
- key(chatId, messageId) {
660776
- return `${chatId}:${messageId}`;
660777
- }
660778
- /** Start the inactivity timer for a newly created menu */
660779
- startTimer(state) {
660780
- this.clearTimer(state.chatId, state.messageId);
660781
- const k = this.key(state.chatId, state.messageId);
660782
- const timer = setTimeout(() => {
660783
- this.inactivityTimers.delete(k);
660784
- this.startCountdown(state);
660785
- }, INACTIVITY_TIMEOUT_MS);
660786
- this.inactivityTimers.set(k, timer);
660787
- }
660788
- /** Reset the inactivity timer after user interaction */
660789
- resetTimer(chatId, messageId) {
660790
- const state = this.stateStore.get(chatId, messageId);
660791
- if (!state) return;
660792
- this.cancelCountdown(chatId, messageId);
660793
- const updated = { ...state, lastInteractionAt: Date.now(), countdownValue: null };
660794
- this.stateStore.set(updated);
660795
- this.startTimer(updated);
660796
- }
660797
- /** Clear all timers for a menu (used when menu is closed or deleted) */
660798
- clearTimer(chatId, messageId) {
660799
- const k = this.key(chatId, messageId);
660800
- const timer = this.inactivityTimers.get(k);
660801
- if (timer) {
660802
- clearTimeout(timer);
660803
- this.inactivityTimers.delete(k);
660804
- }
660805
- this.cancelCountdown(chatId, messageId);
660806
- }
660807
- /** Start the 10-second countdown, updating the close button each second */
660808
- startCountdown(state) {
660809
- const k = this.key(state.chatId, state.messageId);
660810
- let countdown = COUNTDOWN_SECONDS;
660811
- const updatedState = { ...state, countdownValue: countdown, lastInteractionAt: Date.now() };
660812
- this.stateStore.set(updatedState);
660813
- this.updateCountdownButton(updatedState);
660814
- const interval = setInterval(() => {
660815
- countdown--;
660816
- if (countdown <= 0) {
660817
- clearInterval(interval);
660818
- this.countdownIntervals.delete(k);
660819
- this.deleteMenu(state.chatId, state.messageId);
660820
- } else {
660821
- const s2 = { ...state, countdownValue: countdown, lastInteractionAt: Date.now() };
660822
- this.stateStore.set(s2);
660823
- this.updateCountdownButton(s2);
660824
- }
660825
- }, 1e3);
660826
- this.countdownIntervals.set(k, interval);
660827
- }
660828
- cancelCountdown(chatId, messageId) {
660829
- const k = this.key(chatId, messageId);
660830
- const interval = this.countdownIntervals.get(k);
660831
- if (interval) {
660832
- clearInterval(interval);
660833
- this.countdownIntervals.delete(k);
660834
- }
660835
- }
660836
- /** Update the close button to show countdown value */
660837
- async updateCountdownButton(state) {
660838
- try {
660839
- let render2;
660840
- if (state.view === "list") {
660841
- render2 = renderHelpMenuPageWithCountdown(state.scope, state.page, state.countdownValue);
660842
- } else {
660843
- render2 = renderHelpToolDetail(state.scope, state.detailToolName, state.page);
660844
- }
660845
- if (!render2) return;
660846
- await this.callbacks.editMessageText(
660847
- state.chatId,
660848
- state.messageId,
660849
- render2.text,
660850
- render2.replyMarkup
660851
- );
660852
- } catch {
660853
- }
660854
- }
660855
- /** Delete the menu message, the invoking user message, and clean up state */
660856
- async deleteMenu(chatId, messageId) {
660857
- const state = this.stateStore.get(chatId, messageId);
660858
- const invokerMsgId = state?.invokerMessageId;
660859
- this.clearTimer(chatId, messageId);
660860
- this.stateStore.delete(chatId, messageId);
660861
- try {
660862
- await this.callbacks.deleteMessage(chatId, messageId);
660863
- } catch {
660864
- }
660865
- if (invokerMsgId) {
660866
- try {
660867
- await this.callbacks.deleteMessage(chatId, invokerMsgId);
660868
- } catch {
660869
- }
660870
- }
660871
- }
660872
- /** Clean up all timers (for shutdown) */
660873
- destroyAll() {
660874
- for (const [k, timer] of this.inactivityTimers) {
660875
- clearTimeout(timer);
660876
- }
660877
- this.inactivityTimers.clear();
660878
- for (const [k, interval] of this.countdownIntervals) {
660879
- clearInterval(interval);
660880
- }
660881
- this.countdownIntervals.clear();
660882
- }
660883
- };
660884
661197
  }
660885
661198
  });
660886
661199
 
@@ -661140,7 +661453,7 @@ function handleStatsCallback(data, currentState, snapshot) {
661140
661453
  return null;
661141
661454
  }
661142
661455
  }
661143
- var PAGE_SIZE, StatsMenuStateStore, CB_PREFIX, CATEGORY_LABELS2, INACTIVITY_TIMEOUT_MS2, COUNTDOWN_SECONDS2, StatsMenuTimerManager;
661456
+ var PAGE_SIZE, StatsMenuStateStore, CB_PREFIX, CATEGORY_LABELS2, INACTIVITY_TIMEOUT_MS, COUNTDOWN_SECONDS, StatsMenuTimerManager;
661144
661457
  var init_telegram_stats_menu = __esm({
661145
661458
  "packages/cli/src/tui/telegram-stats-menu.ts"() {
661146
661459
  "use strict";
@@ -661174,8 +661487,8 @@ var init_telegram_stats_menu = __esm({
661174
661487
  session: "Session",
661175
661488
  system: "System"
661176
661489
  };
661177
- INACTIVITY_TIMEOUT_MS2 = 6e4;
661178
- COUNTDOWN_SECONDS2 = 10;
661490
+ INACTIVITY_TIMEOUT_MS = 6e4;
661491
+ COUNTDOWN_SECONDS = 10;
661179
661492
  StatsMenuTimerManager = class {
661180
661493
  constructor(states2, callbacks, getSnapshot) {
661181
661494
  this.states = states2;
@@ -661211,12 +661524,12 @@ var init_telegram_stats_menu = __esm({
661211
661524
  lastInteractionAt: Date.now()
661212
661525
  }
661213
661526
  );
661214
- }, INACTIVITY_TIMEOUT_MS2)
661527
+ }, INACTIVITY_TIMEOUT_MS)
661215
661528
  );
661216
661529
  }
661217
661530
  startCountdown(state) {
661218
661531
  const k = this.key(state.chatId, state.messageId);
661219
- this.countdownValues.set(k, COUNTDOWN_SECONDS2);
661532
+ this.countdownValues.set(k, COUNTDOWN_SECONDS);
661220
661533
  this.renderCountdown(state).catch(() => {
661221
661534
  });
661222
661535
  this.countdownTimers.set(
@@ -668572,6 +668885,7 @@ Telegram link integrity contract:
668572
668885
  telegramActiveWorkStartedAtMs = /* @__PURE__ */ new Map();
668573
668886
  /** Queued Telegram sessions waiting for a global work slot. */
668574
668887
  telegramQueuedSessionWork = /* @__PURE__ */ new Map();
668888
+ telegramQueuedSessionCompletions = /* @__PURE__ */ new Map();
668575
668889
  telegramDispatchQueuedTimer = null;
668576
668890
  telegramDispatchQueuedAtMs = 0;
668577
668891
  telegramQueueDiagnosticLastAtMs = 0;
@@ -669474,22 +669788,41 @@ No scoped reflection artifact exists yet for this chat. Use <code>/reflect</code
669474
669788
  messageCount: (existing?.messageCount ?? 0) + 1
669475
669789
  };
669476
669790
  }
669791
+ getTelegramQueuedSessionCompletion(sessionKey) {
669792
+ const existing = this.telegramQueuedSessionCompletions.get(sessionKey);
669793
+ if (existing) return existing;
669794
+ let resolve73;
669795
+ let reject;
669796
+ const promise = new Promise((res, rej) => {
669797
+ resolve73 = res;
669798
+ reject = rej;
669799
+ });
669800
+ promise.catch(() => {
669801
+ });
669802
+ const completion = { promise, resolve: resolve73, reject };
669803
+ this.telegramQueuedSessionCompletions.set(sessionKey, completion);
669804
+ return completion;
669805
+ }
669806
+ shouldAwaitTelegramQueuedWorkForTests() {
669807
+ return process.env["OMNIUS_TG_AWAIT_QUEUED_WORK"] === "1" || process.env["VITEST"] === "true";
669808
+ }
669477
669809
  scheduleTelegramSessionWork(msg, toolContext) {
669478
669810
  const sessionKey = this.sessionKeyForMessage(msg);
669479
669811
  const now2 = Date.now();
669480
669812
  const existing = this.subAgents.get(sessionKey);
669481
669813
  if (existing && !existing.aborted) {
669482
- void this.enqueueTelegramMessageForExistingSubAgent(msg, existing).catch(
669483
- (err) => {
669484
- this.tuiWrite(
669485
- () => renderWarning(
669486
- `Telegram context merge error: ${err instanceof Error ? err.message : String(err)}`
669487
- )
669488
- );
669489
- }
669490
- );
669491
- return;
669814
+ return this.enqueueTelegramMessageForExistingSubAgent(
669815
+ msg,
669816
+ existing
669817
+ ).catch((err) => {
669818
+ this.tuiWrite(
669819
+ () => renderWarning(
669820
+ `Telegram context merge error: ${err instanceof Error ? err.message : String(err)}`
669821
+ )
669822
+ );
669823
+ });
669492
669824
  }
669825
+ const completion = this.getTelegramQueuedSessionCompletion(sessionKey);
669493
669826
  const queued = this.buildTelegramQueuedSessionWork(
669494
669827
  sessionKey,
669495
669828
  msg,
@@ -669507,6 +669840,7 @@ No scoped reflection artifact exists yet for this chat. Use <code>/reflect</code
669507
669840
  `queued Telegram work for ${msg.chatTitle || msg.chatType}; active ${this.activeTelegramInteractionCount()}/${this.getSubAgentLimit()}, queued ${this.telegramQueuedSessionWork.size}, bundled ${queued.messageCount}`
669508
669841
  )
669509
669842
  );
669843
+ return completion.promise;
669510
669844
  }
669511
669845
  startTelegramSessionWork(work) {
669512
669846
  if (this.telegramSessionIsLive(work.sessionKey)) {
@@ -669521,13 +669855,20 @@ No scoped reflection artifact exists yet for this chat. Use <code>/reflect</code
669521
669855
  this.telegramActiveWorkStartedAtMs.set(work.sessionKey, Date.now());
669522
669856
  const generation = this.nextTelegramWorkGeneration(work.sessionKey);
669523
669857
  this.refreshActiveTelegramInteractionCount();
669524
- void this.processTelegramMessageWork(work, generation).catch((err) => {
669858
+ const completion = this.telegramQueuedSessionCompletions.get(
669859
+ work.sessionKey
669860
+ );
669861
+ void this.processTelegramMessageWork(work, generation).then(() => {
669862
+ completion?.resolve();
669863
+ }).catch((err) => {
669525
669864
  this.tuiWrite(
669526
669865
  () => renderWarning(
669527
669866
  `Telegram sub-agent error: ${err instanceof Error ? err.message : String(err)}`
669528
669867
  )
669529
669868
  );
669869
+ completion?.reject(err);
669530
669870
  }).finally(() => {
669871
+ this.telegramQueuedSessionCompletions.delete(work.sessionKey);
669531
669872
  if (this.telegramWorkGenerationIsCurrent(work.sessionKey, generation)) {
669532
669873
  this.telegramActiveWorkSessions.delete(work.sessionKey);
669533
669874
  this.telegramActiveWorkStartedAtMs.delete(work.sessionKey);
@@ -669738,58 +670079,21 @@ ${message2}`)
669738
670079
  }
669739
670080
  async replyWithTelegramHelp(msg, isAdmin) {
669740
670081
  const scope = isAdmin ? "admin" : "public";
669741
- const menu = renderHelpMenu(scope);
670082
+ const helpText = buildTelegramHelpHTML(scope);
669742
670083
  if (msg.guestQueryId) {
669743
- const chunks = splitTelegramHTMLMessage(
669744
- buildTelegramHelpHTML(isAdmin ? "admin" : "public")
669745
- );
670084
+ const chunks = splitTelegramHTMLMessage(helpText);
669746
670085
  await this.answerGuestQuery(msg.guestQueryId, chunks[0] ?? "", {
669747
670086
  parseMode: "HTML"
669748
670087
  });
669749
670088
  return;
669750
670089
  }
669751
- const sent = await this.apiCall("sendMessage", {
669752
- chat_id: msg.chatId,
669753
- text: menu.text,
669754
- parse_mode: "HTML",
669755
- reply_markup: JSON.stringify(menu.replyMarkup),
669756
- ...msg.chatType !== "private" ? { reply_to_message_id: msg.messageId } : {}
669757
- });
669758
- if (sent.ok && sent.result?.message_id) {
669759
- const state = {
669760
- chatId: msg.chatId,
669761
- messageId: sent.result.message_id,
669762
- invokerMessageId: msg.messageId,
669763
- scope,
669764
- page: 0,
669765
- view: "list",
669766
- detailToolName: null,
669767
- fromUserId: msg.fromUserId ?? 0,
669768
- createdAt: Date.now(),
669769
- lastInteractionAt: Date.now(),
669770
- countdownValue: null
669771
- };
669772
- this.helpMenuStates.set(state);
669773
- if (!this.helpMenuTimers) {
669774
- this.helpMenuTimers = new HelpMenuTimerManager(this.helpMenuStates, {
669775
- editMessageText: async (chatId, messageId, text2, replyMarkup) => {
669776
- await this.apiCall("editMessageText", {
669777
- chat_id: chatId,
669778
- message_id: messageId,
669779
- text: text2,
669780
- parse_mode: "HTML",
669781
- reply_markup: JSON.stringify(replyMarkup)
669782
- });
669783
- },
669784
- deleteMessage: async (chatId, messageId) => {
669785
- await this.apiCall("deleteMessage", {
669786
- chat_id: chatId,
669787
- message_id: messageId
669788
- });
669789
- }
669790
- });
669791
- }
669792
- this.helpMenuTimers.startTimer(state);
670090
+ for (const chunk of splitTelegramHTMLMessage(helpText)) {
670091
+ await this.apiCall("sendMessage", {
670092
+ chat_id: msg.chatId,
670093
+ text: chunk,
670094
+ parse_mode: "HTML",
670095
+ ...msg.chatType !== "private" ? { reply_to_message_id: msg.messageId } : {}
670096
+ });
669793
670097
  }
669794
670098
  }
669795
670099
  async replyWithTelegramCommandMenu(msg, isAdmin, kind, commandName) {
@@ -673854,6 +674158,10 @@ ${lines.join("\n")}`;
673854
674158
  const factCount = memory?.facts.length ?? 0;
673855
674159
  const userMemoryCount = memory ? Object.keys(memory.users).length : 0;
673856
674160
  const historyCount = (this.chatHistory.get(sessionKey) ?? []).length;
674161
+ const sqliteHistoryCount = this.telegramSqliteHistoryForSession(
674162
+ sessionKey,
674163
+ 5e3
674164
+ ).length;
673857
674165
  const chatId = msg.chatId;
673858
674166
  let topicCount = 0;
673859
674167
  if (this.repoRoot && chatId !== void 0) {
@@ -673868,11 +674176,37 @@ ${lines.join("\n")}`;
673868
674176
  } catch {
673869
674177
  }
673870
674178
  }
673871
- const hasMemory = cardCount + factCount + userMemoryCount + topicCount > 0 || historyCount > 0;
674179
+ const hasMemory = cardCount + factCount + userMemoryCount + topicCount > 0 || historyCount > 0 || sqliteHistoryCount > 0;
673872
674180
  if (!hasMemory) return "";
674181
+ const sqliteLines = [];
674182
+ if (sqliteHistoryCount > 0) {
674183
+ const addressableRows = this.telegramMergedHistoryForSession(
674184
+ sessionKey,
674185
+ 5e3
674186
+ ).length;
674187
+ const anchors = this.telegramHistoryAnchorsForSession(sessionKey, 1);
674188
+ sqliteLines.push(`SQLite mirror rows: ${sqliteHistoryCount}`);
674189
+ sqliteLines.push(
674190
+ `Addressable conversation history rows: ${addressableRows}`
674191
+ );
674192
+ const earliest = anchors.earliest[0];
674193
+ if (earliest?.ts) {
674194
+ sqliteLines.push(
674195
+ `Earliest turn: ${new Date(earliest.ts).toISOString()} ${telegramHistorySpeaker(earliest)}`
674196
+ );
674197
+ }
674198
+ for (const stat8 of this.telegramParticipantActivityStats(sessionKey, {
674199
+ limit: 5
674200
+ })) {
674201
+ sqliteLines.push(
674202
+ `${stat8.speaker}: ${stat8.count} message${stat8.count === 1 ? "" : "s"}`
674203
+ );
674204
+ }
674205
+ }
673873
674206
  return [
673874
674207
  "### Memory Substrate (this chat)",
673875
674208
  `Available: ${cardCount} cards, ${factCount} facts, ${userMemoryCount} per-user memories, ${historyCount} rolling-history msgs, ${topicCount} memory_read topics.`,
674209
+ ...sqliteLines,
673876
674210
  "Recall via memory_search (semantic similarity / graph traversal / episodes). For exact reads: memory_read(topic, key). The substrate is associative — recall is by cue, not by date."
673877
674211
  ].join("\n");
673878
674212
  }
@@ -673933,6 +674267,11 @@ ${lines.join("\n")}`;
673933
674267
  if (socialStateContext) {
673934
674268
  sections.push(socialStateContext);
673935
674269
  }
674270
+ try {
674271
+ const daydreamContext = this.formatLatestTelegramChannelDaydreamContext(sessionKey);
674272
+ if (daydreamContext) sections.push(daydreamContext);
674273
+ } catch {
674274
+ }
673936
674275
  if (participants.length > 0) {
673937
674276
  const fullCount = Math.min(12, participants.length);
673938
674277
  const tier1Count = Math.max(1, Math.round(fullCount * tier1Ratio));
@@ -674336,13 +674675,8 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`,
674336
674675
  const suppressed = telegramThinkSuppressedRequest(request);
674337
674676
  const requestTimeoutMs = Number.isFinite(suppressed.timeoutMs) && (suppressed.timeoutMs ?? 0) > 0 ? suppressed.timeoutMs : void 0;
674338
674677
  const jsonStartMs = Date.now();
674339
- const nativeOllamaRouter = diagnostics?.backendType === "ollama" && typeof backend.nativeOllamaChatCompletion === "function";
674340
674678
  try {
674341
- jsonModeResult = nativeOllamaRouter ? await backend.nativeOllamaChatCompletion({
674342
- ...suppressed,
674343
- responseFormat: TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT,
674344
- disableEmptyContentRecovery: true
674345
- }) : await this.telegramObservableInference(
674679
+ jsonModeResult = await this.telegramObservableInference(
674346
674680
  backend,
674347
674681
  {
674348
674682
  ...suppressed,
@@ -674406,7 +674740,7 @@ ${this.quoteTelegramContextBlock(msg.text, 1200)}`,
674406
674740
  }
674407
674741
  const plainStartMs = Date.now();
674408
674742
  try {
674409
- const plainResult = nativeOllamaRouter ? await backend.nativeOllamaChatCompletion(suppressed) : await this.telegramObservableInference(
674743
+ const plainResult = await this.telegramObservableInference(
674410
674744
  backend,
674411
674745
  suppressed,
674412
674746
  inferenceKind,
@@ -676480,6 +676814,10 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
676480
676814
  this.telegramDispatchQueuedAtMs = 0;
676481
676815
  }
676482
676816
  this.telegramQueuedSessionWork.clear();
676817
+ for (const completion of this.telegramQueuedSessionCompletions.values()) {
676818
+ completion.reject(new Error("Telegram bridge stopped before queued work completed"));
676819
+ }
676820
+ this.telegramQueuedSessionCompletions.clear();
676483
676821
  this.telegramActiveWorkSessions.clear();
676484
676822
  this.telegramActiveWorkGenerations.clear();
676485
676823
  this.telegramActiveWorkStartedAtMs.clear();
@@ -677625,7 +677963,8 @@ Join: ${newUrl}`
677625
677963
  await this.enqueueTelegramMessageForExistingSubAgent(msg, existing);
677626
677964
  return;
677627
677965
  }
677628
- this.scheduleTelegramSessionWork(msg, toolContext);
677966
+ const queuedWork = this.scheduleTelegramSessionWork(msg, toolContext);
677967
+ if (this.shouldAwaitTelegramQueuedWorkForTests()) await queuedWork;
677629
677968
  }
677630
677969
  async processTelegramMessageWork(work, workGeneration) {
677631
677970
  const msg = work.msg;
@@ -687348,11 +687687,14 @@ var init_routes_media = __esm({
687348
687687
  async function buildDirectToolRegistry(workingDir) {
687349
687688
  const mod3 = await Promise.resolve().then(() => (init_dist5(), dist_exports2)).catch(() => null);
687350
687689
  if (!mod3) {
687351
- return { entries: [], byName: /* @__PURE__ */ new Map(), executionModule: {} };
687690
+ return { entries: [], byName: /* @__PURE__ */ new Map(), callableByName: /* @__PURE__ */ new Map(), executionModule: {} };
687352
687691
  }
687353
687692
  const buildManifest = mod3.buildToolManifestFromModule;
687354
687693
  const baseEntries = buildManifest ? buildManifest(mod3, { cwd: workingDir }) : [];
687355
- const entries = baseEntries.filter((entry) => typeof entry.name === "string" && typeof entry.className === "string").map((entry) => ({ ...entry, directCallable: true }));
687694
+ const entries = baseEntries.filter((entry) => typeof entry.name === "string" && typeof entry.className === "string").map((entry) => ({
687695
+ ...entry,
687696
+ directCallable: DIRECT_BOOKKEEPING_TOOL_NAMES.has(entry.name)
687697
+ }));
687356
687698
  if (!entries.some((entry) => entry.name === TASK_COMPLETE_ENTRY.name)) {
687357
687699
  entries.push({
687358
687700
  ...TASK_COMPLETE_ENTRY,
@@ -687360,14 +687702,16 @@ async function buildDirectToolRegistry(workingDir) {
687360
687702
  });
687361
687703
  }
687362
687704
  entries.sort((a2, b) => a2.name.localeCompare(b.name));
687705
+ const callableEntries = entries.filter((entry) => entry.directCallable);
687363
687706
  return {
687364
687707
  entries,
687365
687708
  byName: new Map(entries.map((entry) => [entry.name, entry])),
687709
+ callableByName: new Map(callableEntries.map((entry) => [entry.name, entry])),
687366
687710
  executionModule: mod3
687367
687711
  };
687368
687712
  }
687369
687713
  function instantiateDirectTool(registry4, name10, workingDir) {
687370
- const entry = registry4.byName.get(name10);
687714
+ const entry = registry4.callableByName.get(name10);
687371
687715
  if (!entry) return null;
687372
687716
  if (entry.virtual && entry.name === "task_complete") {
687373
687717
  return createTaskCompleteDirectTool();
@@ -687415,7 +687759,7 @@ function createTaskCompleteDirectTool() {
687415
687759
  }
687416
687760
  };
687417
687761
  }
687418
- var TASK_COMPLETE_ENTRY;
687762
+ var TASK_COMPLETE_ENTRY, DIRECT_BOOKKEEPING_TOOL_NAMES;
687419
687763
  var init_direct_tool_registry = __esm({
687420
687764
  "packages/cli/src/api/direct-tool-registry.ts"() {
687421
687765
  "use strict";
@@ -687446,6 +687790,11 @@ var init_direct_tool_registry = __esm({
687446
687790
  directCallable: true,
687447
687791
  virtual: true
687448
687792
  };
687793
+ DIRECT_BOOKKEEPING_TOOL_NAMES = /* @__PURE__ */ new Set([
687794
+ "todo_write",
687795
+ "todo_read",
687796
+ "working_notes"
687797
+ ]);
687449
687798
  }
687450
687799
  });
687451
687800
 
@@ -691741,17 +692090,18 @@ async function handleCallTool(ctx3, name10) {
691741
692090
  workingDir = pathResolve3(body.working_dir);
691742
692091
  }
691743
692092
  const registry4 = await buildDirectToolRegistry(workingDir);
691744
- const entry = registry4.byName.get(name10);
692093
+ const entry = registry4.callableByName.get(name10);
691745
692094
  if (!entry) {
691746
692095
  const ext = getExternalTool(workingDir, name10);
691747
692096
  if (ext) {
691748
692097
  return callExternalTool(ctx3, ext, args, workingDir, origin, scope, body);
691749
692098
  }
692099
+ const builtin = registry4.byName.get(name10);
691750
692100
  sendProblem(res, problemDetails({
691751
692101
  type: P2.notFound,
691752
692102
  status: 404,
691753
- title: `Tool '${name10}' not found`,
691754
- detail: "This endpoint exposes the same direct-callable tool registry returned by GET /v1/tools. Use GET /v1/tools for schemas or POST /v1/run for full agent execution.",
692103
+ title: builtin ? `Tool '${name10}' is not direct-callable` : `Tool '${name10}' not found`,
692104
+ detail: builtin ? "This built-in tool is discoverable through GET /v1/tools but is not executable through direct REST calls. Use POST /v1/run for agent-bound workflows." : "No direct-callable built-in or registered external tool with that name. Use GET /v1/tools for schemas or POST /v1/run for full agent execution.",
691755
692105
  instance: requestId
691756
692106
  }));
691757
692107
  return true;
@@ -725556,6 +725906,7 @@ async function runCommand2(opts, config) {
725556
725906
  await runJson(opts.task, mergedConfig, opts.repoPath);
725557
725907
  } else {
725558
725908
  await runWithTUI(opts.task, mergedConfig, opts.repoPath);
725909
+ if (shouldForceSingleRunExit()) process.exit(0);
725559
725910
  }
725560
725911
  } else {
725561
725912
  await startInteractive(mergedConfig, opts.repoPath);
@@ -725655,6 +726006,12 @@ function shouldForceJsonExit() {
725655
726006
  return false;
725656
726007
  return true;
725657
726008
  }
726009
+ function shouldForceSingleRunExit() {
726010
+ if (process.env["OMNIUS_SINGLE_RUN_NO_FORCE_EXIT"] === "1") return false;
726011
+ if (process.env["VITEST"] === "true" || process.env["NODE_ENV"] === "test")
726012
+ return false;
726013
+ return true;
726014
+ }
725658
726015
  function extractSummary(captured) {
725659
726016
  const all2 = captured.join("");
725660
726017
  const match = all2.match(/task_complete.*?summary[:\s]*["']?([^"'\n]+)/i);