omnius 1.0.464 → 1.0.466

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
@@ -566840,7 +566840,9 @@ function loadIgnoreFile(path12) {
566840
566840
  return [];
566841
566841
  }
566842
566842
  }
566843
- function shouldIgnore(relPath, base3, patterns) {
566843
+ function shouldIgnore(relPath, base3, absPath, patterns) {
566844
+ if (existsSync92(join103(absPath, "pyvenv.cfg")))
566845
+ return true;
566844
566846
  for (const p2 of patterns) {
566845
566847
  if (!p2)
566846
566848
  continue;
@@ -566873,16 +566875,32 @@ function scanWorkspace(opts) {
566873
566875
  let dirsVisited = 0;
566874
566876
  const stack = [root];
566875
566877
  const visited = /* @__PURE__ */ new Set();
566876
- while (stack.length > 0) {
566877
- if (files.length >= maxFiles) {
566878
- truncated = true;
566879
- break;
566878
+ const considerFile = (file) => {
566879
+ totalBytes += file.bytes;
566880
+ if (files.length < maxFiles) {
566881
+ files.push(file);
566882
+ return;
566880
566883
  }
566884
+ truncated = true;
566885
+ let oldestIndex = 0;
566886
+ for (let i2 = 1; i2 < files.length; i2++) {
566887
+ if (files[i2].mtimeMs < files[oldestIndex].mtimeMs)
566888
+ oldestIndex = i2;
566889
+ }
566890
+ if (file.mtimeMs > files[oldestIndex].mtimeMs) {
566891
+ files[oldestIndex] = file;
566892
+ }
566893
+ };
566894
+ while (stack.length > 0) {
566881
566895
  const dir = stack.pop();
566882
566896
  if (visited.has(dir))
566883
566897
  continue;
566884
566898
  visited.add(dir);
566885
566899
  dirsVisited++;
566900
+ if (dirsVisited > maxDirs) {
566901
+ truncated = true;
566902
+ break;
566903
+ }
566886
566904
  if (dirs.length < maxDirs) {
566887
566905
  try {
566888
566906
  const st = statSync32(dir);
@@ -566901,15 +566919,12 @@ function scanWorkspace(opts) {
566901
566919
  continue;
566902
566920
  }
566903
566921
  entries.sort();
566922
+ const dirsToVisit = [];
566904
566923
  for (const entry of entries) {
566905
- if (files.length >= maxFiles) {
566906
- truncated = true;
566907
- break;
566908
- }
566909
566924
  const abs = join103(dir, entry);
566910
566925
  const rel = relative8(root, abs);
566911
566926
  const base3 = basename22(abs);
566912
- if (shouldIgnore(rel, base3, patterns))
566927
+ if (shouldIgnore(rel, base3, abs, patterns))
566913
566928
  continue;
566914
566929
  let st;
566915
566930
  try {
@@ -566918,13 +566933,15 @@ function scanWorkspace(opts) {
566918
566933
  continue;
566919
566934
  }
566920
566935
  if (st.isDirectory()) {
566921
- stack.push(abs);
566936
+ dirsToVisit.push(abs);
566922
566937
  continue;
566923
566938
  }
566924
566939
  if (!st.isFile())
566925
566940
  continue;
566926
- files.push({ abs, rel, bytes: st.size, mtimeMs: st.mtimeMs });
566927
- totalBytes += st.size;
566941
+ considerFile({ abs, rel, bytes: st.size, mtimeMs: st.mtimeMs });
566942
+ }
566943
+ for (let i2 = dirsToVisit.length - 1; i2 >= 0; i2--) {
566944
+ stack.push(dirsToVisit[i2]);
566928
566945
  }
566929
566946
  }
566930
566947
  files.sort((a2, b) => a2.rel.localeCompare(b.rel));
@@ -566955,6 +566972,7 @@ function ensureTreeNode(root, rel) {
566955
566972
  function renderWorkspaceTree(scan, opts = {}) {
566956
566973
  const maxLines = Math.max(10, Math.min(2e3, opts.maxLines ?? 120));
566957
566974
  const includeFileSizes = opts.includeFileSizes !== false;
566975
+ const sortBy = opts.sortBy ?? "path";
566958
566976
  const root = {
566959
566977
  name: ".",
566960
566978
  children: /* @__PURE__ */ new Map(),
@@ -566975,10 +566993,38 @@ function renderWorkspaceTree(scan, opts = {}) {
566975
566993
  directory: false
566976
566994
  });
566977
566995
  }
566996
+ const annotate = (node) => {
566997
+ if (!node.directory && node.file) {
566998
+ node.latestMtimeMs = node.file.mtimeMs;
566999
+ node.selectedFileCount = 1;
567000
+ return { latest: node.file.mtimeMs, files: 1 };
567001
+ }
567002
+ let latest = 0;
567003
+ let files = 0;
567004
+ for (const child of node.children.values()) {
567005
+ const stats = annotate(child);
567006
+ latest = Math.max(latest, stats.latest);
567007
+ files += stats.files;
567008
+ }
567009
+ node.latestMtimeMs = latest;
567010
+ node.selectedFileCount = files;
567011
+ return { latest, files };
567012
+ };
567013
+ annotate(root);
566978
567014
  const lines = ["./"];
566979
567015
  let truncated = false;
566980
567016
  const walk2 = (node, depth) => {
566981
567017
  const children2 = [...node.children.values()].sort((a2, b) => {
567018
+ if (sortBy === "recent") {
567019
+ const aFiles = a2.selectedFileCount ?? 0;
567020
+ const bFiles = b.selectedFileCount ?? 0;
567021
+ if (aFiles > 0 !== bFiles > 0)
567022
+ return aFiles > 0 ? -1 : 1;
567023
+ const aMtime = a2.latestMtimeMs ?? 0;
567024
+ const bMtime = b.latestMtimeMs ?? 0;
567025
+ if (aMtime !== bMtime)
567026
+ return bMtime - aMtime;
567027
+ }
566982
567028
  if (a2.directory !== b.directory)
566983
567029
  return a2.directory ? -1 : 1;
566984
567030
  return a2.name.localeCompare(b.name);
@@ -567057,12 +567103,23 @@ var init_world_state_disk_scan = __esm({
567057
567103
  ".venv",
567058
567104
  "venv",
567059
567105
  "env",
567106
+ "site-packages",
567107
+ ".eggs",
567108
+ "__pypackages__",
567109
+ // Embedded/device and package-manager dependency/build caches
567110
+ ".pio",
567111
+ ".platformio",
567112
+ "libdeps",
567060
567113
  // Rust / Go test / build outputs are caught by "target"/"build"
567061
567114
  // Editor swap / lock-only files — case-by-case skip, see file filter below
567062
567115
  // Omnius's own state dirs
567063
567116
  ".omnius",
567064
567117
  ".aiwg",
567065
567118
  ".ralph",
567119
+ ".claude",
567120
+ ".codex",
567121
+ ".factory",
567122
+ ".warp",
567066
567123
  // Next/Vite/etc. caches (broadly cross-framework — every JS bundler has one)
567067
567124
  ".next",
567068
567125
  ".nuxt",
@@ -575515,7 +575572,7 @@ var init_focusSupervisor = __esm({
575515
575572
  prior.ignoredCount++;
575516
575573
  this.ignoredDirectiveStreak++;
575517
575574
  this.lastIgnoredDirectiveTurn = input.turn;
575518
- if ((prior.requiredNextAction === "read_authoritative_target" || prior.requiredNextAction === "use_cached_evidence") && input.cachedResult && (input.duplicateHitCount ?? 0) >= Math.max(1, this.repeatGateMax - 1)) {
575575
+ if (prior.requiredNextAction === "read_authoritative_target" && input.cachedResult && (input.duplicateHitCount ?? 0) >= Math.max(1, this.repeatGateMax - 1)) {
575519
575576
  const deadlockDirective = this.setDirective({
575520
575577
  turn: input.turn,
575521
575578
  state: "terminal_incomplete",
@@ -578528,7 +578585,7 @@ function classifyThinkOutcome(raw) {
578528
578585
  }
578529
578586
  return null;
578530
578587
  }
578531
- var TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, TOOL_ACTION_REASON_KEYS, TOOL_ACTION_REASON_SCOPES, READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS, TOOL_ACTION_REASON_SCHEMA, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
578588
+ var TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, TOOL_ACTION_REASON_KEYS, TOOL_ACTION_REASON_SCOPES, READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS, STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS, TOOL_ACTION_REASON_SCHEMA, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
578532
578589
  var init_agenticRunner = __esm({
578533
578590
  "packages/orchestrator/dist/agenticRunner.js"() {
578534
578591
  "use strict";
@@ -578652,6 +578709,9 @@ var init_agenticRunner = __esm({
578652
578709
  "web_fetch",
578653
578710
  "tool_search"
578654
578711
  ]);
578712
+ STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS = /* @__PURE__ */ new Set([
578713
+ "todo_write"
578714
+ ]);
578655
578715
  TOOL_ACTION_REASON_SCHEMA = {
578656
578716
  type: "object",
578657
578717
  description: "Compact public action contract for this exact tool call. Do not include hidden chain-of-thought; use concise task-state facts.",
@@ -580012,10 +580072,13 @@ ${parts.join("\n")}
580012
580072
  }
580013
580073
  _maybeMarkFocusTerminalIncomplete(input) {
580014
580074
  if (input.decision.kind === "pass")
580015
- return;
580075
+ return null;
580016
580076
  const directive = input.decision.directive;
580017
580077
  if (directive.state !== "terminal_incomplete" || directive.requiredNextAction !== "report_incomplete") {
580018
- return;
580078
+ return null;
580079
+ }
580080
+ if (this._completionIncompleteVerification) {
580081
+ return this._completionIncompleteVerification.summary;
580019
580082
  }
580020
580083
  const reason = directive.reason;
580021
580084
  const blocked = input.blockedTool ? `Blocked tool: ${input.blockedTool}.` : "";
@@ -580033,6 +580096,10 @@ ${parts.join("\n")}
580033
580096
  "Next action:",
580034
580097
  'Call task_complete with status="incomplete" or status="blocked", or provide the missing evidence if a valid recovery action remains.'
580035
580098
  ].filter((line) => line.length > 0).join("\n");
580099
+ this._completionIncompleteVerification = {
580100
+ reason: "focus_supervisor_terminal",
580101
+ summary: focusTerminalSummary
580102
+ };
580036
580103
  this.emit({
580037
580104
  type: "status",
580038
580105
  content: `Focus supervisor terminal directive: ${reason.slice(0, 220)}`,
@@ -580051,6 +580118,7 @@ ${parts.join("\n")}
580051
580118
  this._saveCompletionLedgerSafe();
580052
580119
  this._focusTerminalLedgerRecorded = true;
580053
580120
  }
580121
+ return focusTerminalSummary;
580054
580122
  }
580055
580123
  _buildFocusContextSnapshot() {
580056
580124
  const last2 = this._lastFocusContextSnapshot;
@@ -583722,22 +583790,24 @@ ${latest.output || ""}`.trim();
583722
583790
  const artifactLines = intEnv("OMNIUS_CONTEXT_TREE_ARTIFACT_LINES", 1800, 100, 4e3);
583723
583791
  try {
583724
583792
  const scan = scanWorkspace({ root, maxFiles, maxDirs });
583725
- const compactTree = renderWorkspaceTree(scan, { maxLines: contextLines });
583726
- const fullTree = renderWorkspaceTree(scan, { maxLines: artifactLines });
583793
+ const compactTree = renderWorkspaceTree(scan, { maxLines: contextLines, sortBy: "recent" });
583794
+ const fullTree = renderWorkspaceTree(scan, { maxLines: artifactLines, sortBy: "recent" });
583727
583795
  const totalBytes = scan.files.reduce((sum, file) => sum + file.bytes, 0);
583728
583796
  const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
583729
583797
  const focusSnapshot = this._focusSupervisor?.snapshot();
583730
- const recentActions = this._adversaryToolOutcomes.slice(-12).map((item) => ({
583798
+ const recentActions = this._recentToolActionsForWorldState().slice(-12).map((item) => ({
583731
583799
  turn: item.turn,
583732
583800
  tool: item.tool,
583733
583801
  success: item.succeeded,
583734
583802
  path: item.path,
583735
583803
  stateVersion: item.stateVersion,
583736
- preview: item.preview.slice(0, 240)
583804
+ preview: item.preview.slice(0, 240),
583805
+ actionReason: item.actionReason ?? void 0
583737
583806
  }));
583738
583807
  const recentActionLines = recentActions.slice(-6).map((item) => {
583739
583808
  const path12 = item.path ? ` path=${item.path}` : "";
583740
- return `- turn=${item.turn} ${item.tool} ${item.success ? "ok" : "err"}${path12}: ${item.preview.replace(/\s+/g, " ").slice(0, 160)}`;
583809
+ const reason = item.actionReason ? ` reason=${[item.actionReason.scope, item.actionReason.intent].filter(Boolean).join(":").replace(/\s+/g, " ").slice(0, 120)}` : "";
583810
+ return `- turn=${item.turn} ${item.tool} ${item.success ? "ok" : "err"}${path12}${reason}: ${item.preview.replace(/\s+/g, " ").slice(0, 160)}`;
583741
583811
  });
583742
583812
  const treeDir = _pathJoin(this.omniusStateDir(), "world-state", "tree");
583743
583813
  const turnName = `turn-${String(turn).padStart(4, "0")}`;
@@ -589780,6 +589850,14 @@ Respond with EXACTLY this structure before your next tool call:
589780
589850
  const realFileMutation = this._isRealProjectMutation(tc.name, result);
589781
589851
  const observedStateMutation = realFileMutation || shellFilesystemMutation || result.success === true && result.mutated === true;
589782
589852
  const realMutationPaths = realFileMutation ? this._extractToolTargetPaths(tc.name, tc.arguments, result) : [];
589853
+ this._recordRecentToolOutcomeForWorldState({
589854
+ turn,
589855
+ toolName: resolvedTool?.name ?? tc.name,
589856
+ toolCallId: tc.id,
589857
+ args: tc.arguments,
589858
+ result,
589859
+ actionReason: toolActionReason
589860
+ });
589783
589861
  if (observedStateMutation) {
589784
589862
  this._markAdversaryObservedStateMutation();
589785
589863
  }
@@ -591549,6 +591627,8 @@ ${sr.result.output}`;
591549
591627
  }
591550
591628
  }
591551
591629
  const results = await executeBatch(batch2, async (call) => {
591630
+ if (this._completionIncompleteVerification)
591631
+ return null;
591552
591632
  const originalTc = rawToolCalls.find((tc) => tc.id === call.id);
591553
591633
  const fp = buildBatchFp(call);
591554
591634
  const firstId = batchFingerprintFirstId.get(fp);
@@ -593926,10 +594006,32 @@ ${marker}` : marker);
593926
594006
  const explicit = this._extractToolActionReason(args);
593927
594007
  if (explicit)
593928
594008
  return explicit;
594009
+ if (this._shouldSynthesizeMissingToolActionReason(toolName, args)) {
594010
+ return this._synthesizeStateUpdateToolActionReason(toolName, args);
594011
+ }
593929
594012
  if (this._toolActionReasonPolicy(toolName, args) !== "optional")
593930
594013
  return null;
593931
594014
  return this._synthesizeReadOnlyToolActionReason(toolName, args);
593932
594015
  }
594016
+ _shouldSynthesizeMissingToolActionReason(toolName, _args) {
594017
+ if (this._toolActionReasonPolicy(toolName, _args) === "disabled") {
594018
+ return false;
594019
+ }
594020
+ const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
594021
+ return STATE_UPDATE_ACTION_REASON_SYNTHESIS_TOOLS.has(canonical);
594022
+ }
594023
+ _synthesizeStateUpdateToolActionReason(toolName, args) {
594024
+ const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
594025
+ const goal = this._taskState.currentStep || this._taskState.nextAction || this._taskState.goal || this._taskState.originalGoal || "current task";
594026
+ const todoCount = Array.isArray(args["todos"]) ? args["todos"].length : null;
594027
+ return {
594028
+ task_anchor: String(goal).replace(/\s+/g, " ").trim().slice(0, 160),
594029
+ intent: `Update visible task state with ${canonical}.`,
594030
+ evidence: todoCount === null ? "Model omitted public action_reason; runtime synthesized bookkeeping metadata without authorizing project mutation." : `Model supplied ${todoCount} todo item(s); runtime synthesized bookkeeping metadata without authorizing project mutation.`,
594031
+ expected_result: "Session checklist reflects the current task state.",
594032
+ scope: "state_update"
594033
+ };
594034
+ }
593933
594035
  _synthesizeReadOnlyToolActionReason(toolName, args) {
593934
594036
  const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
593935
594037
  const goal = this._taskState.currentStep || this._taskState.nextAction || this._taskState.goal || this._taskState.originalGoal || "current task";
@@ -593951,6 +594053,9 @@ ${marker}` : marker);
593951
594053
  if (!raw || typeof raw === "string" && !raw.trim()) {
593952
594054
  if (policy === "optional")
593953
594055
  return null;
594056
+ if (this._shouldSynthesizeMissingToolActionReason(toolName, args)) {
594057
+ return null;
594058
+ }
593954
594059
  return [
593955
594060
  "[TOOL ACTION REASON CONTRACT]",
593956
594061
  `This side-effectful tool call must include action_reason: { task_anchor, intent, evidence, expected_result, scope }.`,
@@ -595798,6 +595903,10 @@ ${trimmedNew}`;
595798
595903
  // we add a second analysis path that catches mismatches in real-time.
595799
595904
  /** Track recent tool outcomes for the adversary */
595800
595905
  _adversaryToolOutcomes = [];
595906
+ /** Execution-time action ledger used by world-state artifacts. Unlike the
595907
+ * adversary buffer, this is populated directly after tool execution and does
595908
+ * not depend on raw tool messages surviving compaction. */
595909
+ _recentToolOutcomes = [];
595801
595910
  /** Monotonic counter for observed local state changes.
595802
595911
  * Redundant-action classification is only valid within the same state
595803
595912
  * version; a repeated verifier after an edit is fresh evidence. */
@@ -595902,6 +596011,38 @@ ${trimmedNew}`;
595902
596011
  }
595903
596012
  return { preview: snippet || content.slice(0, 160) };
595904
596013
  }
596014
+ _recordRecentToolOutcomeForWorldState(input) {
596015
+ const content = input.result.success === true ? String(input.result.output ?? "") : String(input.result.error ?? input.result.output ?? "");
596016
+ const outcomeEvidence = this.buildAdversaryToolOutcomeEvidence(input.toolName, input.args, content, input.result.success === true);
596017
+ const fingerprint = input.args ? this._buildToolFingerprint(input.toolName, input.args) : void 0;
596018
+ const alreadySeen = this._recentToolOutcomes.some((outcome) => {
596019
+ if (input.toolCallId && outcome.toolCallId === input.toolCallId) {
596020
+ return true;
596021
+ }
596022
+ return outcome.turn === input.turn && outcome.tool === input.toolName && outcome.fingerprint === fingerprint;
596023
+ });
596024
+ if (alreadySeen)
596025
+ return;
596026
+ this._recentToolOutcomes.push({
596027
+ turn: input.turn,
596028
+ tool: input.toolName,
596029
+ toolCallId: input.toolCallId,
596030
+ argsKey: input.args ? this._buildExactArgsKey(input.args) : void 0,
596031
+ fingerprint,
596032
+ stateVersion: this._adversaryStateVersion,
596033
+ succeeded: input.result.success === true,
596034
+ actionReason: input.actionReason,
596035
+ ...outcomeEvidence
596036
+ });
596037
+ while (this._recentToolOutcomes.length > 40) {
596038
+ this._recentToolOutcomes.shift();
596039
+ }
596040
+ }
596041
+ _recentToolActionsForWorldState() {
596042
+ if (this._recentToolOutcomes.length > 0)
596043
+ return this._recentToolOutcomes;
596044
+ return this._adversaryToolOutcomes;
596045
+ }
595905
596046
  /**
595906
596047
  * Adversary: post-turn meta-analysis.
595907
596048
  *
@@ -619139,7 +619280,10 @@ function renderTaskCompleteBox(host, data) {
619139
619280
  testsRun: data.testsRun ? [...data.testsRun] : [],
619140
619281
  provenanceAnchors: data.provenanceAnchors ? [...data.provenanceAnchors] : []
619141
619282
  };
619142
- host.registerDynamicBlock(blockId, (width) => buildBoxLines(frozen, width));
619283
+ host.registerDynamicBlock(blockId, (width) => buildBoxLines(frozen, width), {
619284
+ renderer: "task-complete",
619285
+ data: frozen
619286
+ });
619143
619287
  host.appendDynamicBlock(blockId);
619144
619288
  return blockId;
619145
619289
  }
@@ -619163,7 +619307,11 @@ function renderSessionHistoryBox(host, data) {
619163
619307
  };
619164
619308
  host.registerDynamicBlock(
619165
619309
  blockId,
619166
- (width) => buildSessionHistoryBoxLines(frozen, width)
619310
+ (width) => buildSessionHistoryBoxLines(frozen, width),
619311
+ {
619312
+ renderer: "session-history",
619313
+ data: frozen
619314
+ }
619167
619315
  );
619168
619316
  host.appendDynamicBlock(blockId);
619169
619317
  return blockId;
@@ -620206,6 +620354,7 @@ __export(render_exports, {
620206
620354
  getColorsEnabled: () => getColorsEnabled,
620207
620355
  getEmojisEnabled: () => getEmojisEnabled,
620208
620356
  getTermWidth: () => getTermWidth,
620357
+ isPersistedDynamicBlockSpec: () => isPersistedDynamicBlockSpec,
620209
620358
  pastel: () => pastel,
620210
620359
  renderAssistantText: () => renderAssistantText,
620211
620360
  renderBoxedBlock: () => renderBoxedBlock,
@@ -620219,6 +620368,7 @@ __export(render_exports, {
620219
620368
  renderInfo: () => renderInfo,
620220
620369
  renderModelList: () => renderModelList,
620221
620370
  renderModelSwitch: () => renderModelSwitch,
620371
+ renderPersistedDynamicBlockSpec: () => renderPersistedDynamicBlockSpec,
620222
620372
  renderRichHeader: () => renderRichHeader,
620223
620373
  renderSlashHelp: () => renderSlashHelp,
620224
620374
  renderSteeringIntake: () => renderSteeringIntake,
@@ -620668,6 +620818,68 @@ function applyCollapseToBox(fullLines, opts) {
620668
620818
  );
620669
620819
  return [...head, ...body, lessRow, bottom];
620670
620820
  }
620821
+ function isPersistedDynamicBlockSpec(value2) {
620822
+ if (!value2 || typeof value2 !== "object") return false;
620823
+ const renderer = value2.renderer;
620824
+ return renderer === "tool-combined" || renderer === "tool-result" || renderer === "tool-box" || renderer === "task-complete" || renderer === "session-history";
620825
+ }
620826
+ function renderPersistedDynamicBlockSpec(spec, width, id2) {
620827
+ switch (spec.renderer) {
620828
+ case "tool-combined": {
620829
+ let lines = buildCombinedToolBoxLines(
620830
+ spec.toolName,
620831
+ spec.callArgs ?? {},
620832
+ Boolean(spec.success),
620833
+ String(spec.output ?? ""),
620834
+ spec.opts ?? {},
620835
+ width
620836
+ );
620837
+ if (spec.collapse && id2) {
620838
+ ensureCollapsible(id2);
620839
+ lines = applyCollapseToBox(lines, {
620840
+ state: getCollapseState(id2),
620841
+ desc: spec.collapse,
620842
+ width
620843
+ });
620844
+ }
620845
+ return lines;
620846
+ }
620847
+ case "tool-result": {
620848
+ let lines = buildToolResultBoxLines(
620849
+ spec.toolName,
620850
+ Boolean(spec.success),
620851
+ String(spec.output ?? ""),
620852
+ spec.opts ?? {},
620853
+ width
620854
+ );
620855
+ if (spec.collapse && id2) {
620856
+ ensureCollapsible(id2);
620857
+ lines = applyCollapseToBox(lines, {
620858
+ state: getCollapseState(id2),
620859
+ desc: spec.collapse,
620860
+ width
620861
+ });
620862
+ }
620863
+ return lines;
620864
+ }
620865
+ case "tool-box": {
620866
+ let lines = buildToolBoxLines(spec.data, width);
620867
+ if (spec.collapse && id2) {
620868
+ ensureCollapsible(id2);
620869
+ lines = applyCollapseToBox(lines, {
620870
+ state: getCollapseState(id2),
620871
+ desc: spec.collapse,
620872
+ width
620873
+ });
620874
+ }
620875
+ return lines;
620876
+ }
620877
+ case "task-complete":
620878
+ return buildBoxLines(spec.data, width);
620879
+ case "session-history":
620880
+ return buildSessionHistoryBoxLines(spec.data, width);
620881
+ }
620882
+ }
620671
620883
  function buildToolContentRow(content, width, colorCode) {
620672
620884
  const border = toolColorSeq(colorCode);
620673
620885
  const reset = toolResetSeq();
@@ -620910,11 +621122,12 @@ function buildToolBoxLines(data, width) {
620910
621122
  lines.push(buildToolBottom(w, data.colorCode));
620911
621123
  return lines;
620912
621124
  }
620913
- function renderToolDynamicBlock(kind, render2, opts, collapse) {
621125
+ function renderToolDynamicBlock(kind, render2, opts, collapse, persistedSpec) {
620914
621126
  const redir = _contentWriteHook?.redirect?.();
620915
621127
  const host = opts.host !== void 0 ? opts.host : _contentWriteHook?.dynamicBlockHost?.();
620916
621128
  if (!redir && host) {
620917
621129
  const id2 = `${kind}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
621130
+ const specForPersistence = persistedSpec && collapse ? { ...persistedSpec, collapse } : persistedSpec;
620918
621131
  if (collapse) {
620919
621132
  ensureCollapsible(id2);
620920
621133
  host.registerDynamicBlock(
@@ -620923,10 +621136,11 @@ function renderToolDynamicBlock(kind, render2, opts, collapse) {
620923
621136
  state: getCollapseState(id2),
620924
621137
  desc: collapse,
620925
621138
  width
620926
- })
621139
+ }),
621140
+ specForPersistence
620927
621141
  );
620928
621142
  } else {
620929
- host.registerDynamicBlock(id2, render2);
621143
+ host.registerDynamicBlock(id2, render2, specForPersistence);
620930
621144
  }
620931
621145
  host.appendDynamicBlock(id2);
620932
621146
  return;
@@ -621495,7 +621709,16 @@ function renderToolResult(toolName, success, output, verboseOrOpts) {
621495
621709
  width
621496
621710
  ),
621497
621711
  opts,
621498
- collapseDesc
621712
+ collapseDesc,
621713
+ {
621714
+ renderer: "tool-combined",
621715
+ toolName,
621716
+ callArgs: { ...pending2.args ?? {} },
621717
+ success,
621718
+ output: frozenOutput,
621719
+ opts: { ...opts, verbose: pending2.verbose ?? opts.verbose },
621720
+ collapse: collapseDesc
621721
+ }
621499
621722
  );
621500
621723
  return;
621501
621724
  }
@@ -621504,7 +621727,15 @@ function renderToolResult(toolName, success, output, verboseOrOpts) {
621504
621727
  "tool-result",
621505
621728
  (width) => buildToolResultBoxLines(toolName, success, frozenOutput, opts, width),
621506
621729
  opts,
621507
- collapseDesc
621730
+ collapseDesc,
621731
+ {
621732
+ renderer: "tool-result",
621733
+ toolName,
621734
+ success,
621735
+ output: frozenOutput,
621736
+ opts: { ...opts },
621737
+ collapse: collapseDesc
621738
+ }
621508
621739
  );
621509
621740
  }
621510
621741
  function renderBoxedBlock(opts) {
@@ -621528,7 +621759,18 @@ function renderBoxedBlock(opts) {
621528
621759
  },
621529
621760
  width
621530
621761
  ),
621531
- opts.host === void 0 ? {} : { host: opts.host }
621762
+ opts.host === void 0 ? {} : { host: opts.host },
621763
+ void 0,
621764
+ {
621765
+ renderer: "tool-box",
621766
+ data: {
621767
+ title: opts.title,
621768
+ metrics: opts.metrics ?? "",
621769
+ body,
621770
+ colorCode: opts.colorCode ?? tuiTextDim(),
621771
+ metricsColorCode: opts.metricsColorCode
621772
+ }
621773
+ }
621532
621774
  );
621533
621775
  }
621534
621776
  function renderImageAsciiPreview(title, imagePath, ascii2, renderer) {
@@ -628014,6 +628256,7 @@ __export(omnius_directory_exports, {
628014
628256
  loadRecentSessions: () => loadRecentSessions,
628015
628257
  loadSessionContext: () => loadSessionContext,
628016
628258
  loadSessionHistory: () => loadSessionHistory,
628259
+ loadTuiSessionState: () => loadTuiSessionState,
628017
628260
  loadUsageHistory: () => loadUsageHistory,
628018
628261
  readIndexData: () => readIndexData,
628019
628262
  readIndexMeta: () => readIndexMeta,
@@ -628027,6 +628270,7 @@ __export(omnius_directory_exports, {
628027
628270
  saveSession: () => saveSession,
628028
628271
  saveSessionContext: () => saveSessionContext,
628029
628272
  saveSessionHistory: () => saveSessionHistory,
628273
+ saveTuiSessionState: () => saveTuiSessionState,
628030
628274
  sessionContextToHistoryBoxData: () => sessionContextToHistoryBoxData,
628031
628275
  stopOmniusGitignoreWatcher: () => stopOmniusGitignoreWatcher,
628032
628276
  updateSessionEntry: () => updateSessionEntry,
@@ -629085,9 +629329,12 @@ function buildRestoreHistoryAnchor(repoRoot) {
629085
629329
  const lines = loadSessionHistory(repoRoot, latest.id) ?? [];
629086
629330
  const meaningfulTail = lines.map((line) => cleanSessionHistoryDisplayLine(line)).filter((line) => line && !isNoisySessionHistoryLine(line)).slice(-18).map((line) => `- ${normalizeSessionText(line, 220)}`);
629087
629331
  const path12 = join136(OMNIUS_DIR, SESSIONS_DIR, `${latest.id}.jsonl`);
629332
+ const statePath = join136(OMNIUS_DIR, SESSIONS_DIR, `${latest.id}${TUI_STATE_SUFFIX}`);
629333
+ const hasTuiState = existsSync122(join136(repoRoot, statePath));
629088
629334
  const block = `<restored-interface-history>
629089
629335
  latest_visual_session_id=${latest.id}
629090
- full_transcript_path=${path12}
629336
+ ` + (hasTuiState ? `full_tui_state_path=${statePath}
629337
+ ` : "") + `full_transcript_path=${path12}
629091
629338
  recorded_lines=${lines.length}
629092
629339
  ` + (meaningfulTail.length > 0 ? `Recent visible transcript tail:
629093
629340
  ${meaningfulTail.join("\n")}
@@ -629311,6 +629558,34 @@ function saveSessionHistory(repoRoot, sessionId, contentLines, meta) {
629311
629558
  }
629312
629559
  writeFileSync64(indexPath, JSON.stringify(index, null, 2), "utf-8");
629313
629560
  }
629561
+ function saveTuiSessionState(repoRoot, sessionId, state) {
629562
+ const sessDir = join136(repoRoot, OMNIUS_DIR, SESSIONS_DIR);
629563
+ mkdirSync76(sessDir, { recursive: true });
629564
+ const statePath = join136(sessDir, `${sessionId}${TUI_STATE_SUFFIX}`);
629565
+ const payload = {
629566
+ version: 2,
629567
+ savedAt: state.savedAt || (/* @__PURE__ */ new Date()).toISOString(),
629568
+ contentLines: Array.isArray(state.contentLines) ? state.contentLines : [],
629569
+ dynamicBlocks: state.dynamicBlocks && typeof state.dynamicBlocks === "object" ? state.dynamicBlocks : {}
629570
+ };
629571
+ writeFileSync64(statePath, JSON.stringify(payload, null, 2), "utf-8");
629572
+ }
629573
+ function loadTuiSessionState(repoRoot, sessionId) {
629574
+ const statePath = join136(repoRoot, OMNIUS_DIR, SESSIONS_DIR, `${sessionId}${TUI_STATE_SUFFIX}`);
629575
+ try {
629576
+ if (!existsSync122(statePath)) return null;
629577
+ const parsed = JSON.parse(readFileSync101(statePath, "utf-8"));
629578
+ if (parsed.version !== 2 || !Array.isArray(parsed.contentLines)) return null;
629579
+ return {
629580
+ version: 2,
629581
+ savedAt: typeof parsed.savedAt === "string" ? parsed.savedAt : (/* @__PURE__ */ new Date()).toISOString(),
629582
+ contentLines: parsed.contentLines.filter((line) => typeof line === "string"),
629583
+ dynamicBlocks: parsed.dynamicBlocks && typeof parsed.dynamicBlocks === "object" ? parsed.dynamicBlocks : {}
629584
+ };
629585
+ } catch {
629586
+ return null;
629587
+ }
629588
+ }
629314
629589
  function listSessions(repoRoot) {
629315
629590
  const indexPath = join136(repoRoot, OMNIUS_DIR, SESSIONS_DIR, SESSIONS_INDEX);
629316
629591
  try {
@@ -629336,6 +629611,8 @@ function deleteSession(repoRoot, sessionId) {
629336
629611
  try {
629337
629612
  const contentPath = join136(sessDir, `${sessionId}.jsonl`);
629338
629613
  if (existsSync122(contentPath)) unlinkSync23(contentPath);
629614
+ const statePath = join136(sessDir, `${sessionId}${TUI_STATE_SUFFIX}`);
629615
+ if (existsSync122(statePath)) unlinkSync23(statePath);
629339
629616
  if (existsSync122(indexPath)) {
629340
629617
  let index = JSON.parse(readFileSync101(indexPath, "utf-8"));
629341
629618
  index = index.filter((s2) => s2.id !== sessionId);
@@ -629543,7 +629820,7 @@ function deleteUsageRecord(kind, value2, repoRoot) {
629543
629820
  remove(join136(repoRoot, OMNIUS_DIR, USAGE_HISTORY_FILE));
629544
629821
  }
629545
629822
  }
629546
- 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, DEICTIC_CONTINUATION_TERMS, SESSIONS_DIR, SESSIONS_INDEX, SKIP_DIRS3, HOME_SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
629823
+ 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, DEICTIC_CONTINUATION_TERMS, SESSIONS_DIR, SESSIONS_INDEX, TUI_STATE_SUFFIX, SKIP_DIRS3, HOME_SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
629547
629824
  var init_omnius_directory = __esm({
629548
629825
  "packages/cli/src/tui/omnius-directory.ts"() {
629549
629826
  "use strict";
@@ -629607,6 +629884,7 @@ var init_omnius_directory = __esm({
629607
629884
  ]);
629608
629885
  SESSIONS_DIR = "sessions";
629609
629886
  SESSIONS_INDEX = "sessions-index.json";
629887
+ TUI_STATE_SUFFIX = ".tui-state.json";
629610
629888
  SKIP_DIRS3 = /* @__PURE__ */ new Set([
629611
629889
  "node_modules",
629612
629890
  ".git",
@@ -632289,6 +632567,7 @@ var init_status_bar = __esm({
632289
632567
  * repaint, including selection updates and scroll events.
632290
632568
  */
632291
632569
  _dynamicBlocks = /* @__PURE__ */ new Map();
632570
+ _dynamicBlockSpecs = /* @__PURE__ */ new Map();
632292
632571
  _dynamicBlockClickHandlers = /* @__PURE__ */ new Map();
632293
632572
  /** Sentinel marker — used both for scrollback storage and reflow detection. */
632294
632573
  DYNAMIC_BLOCK_MARK_PREFIX = "DYNBLOCK:";
@@ -632434,8 +632713,13 @@ var init_status_bar = __esm({
632434
632713
  * through `appendDynamicBlock` which also triggers a repaint so the
632435
632714
  * block becomes visible immediately.
632436
632715
  */
632437
- registerDynamicBlock(id2, render2) {
632716
+ registerDynamicBlock(id2, render2, persistedSpec) {
632438
632717
  this._dynamicBlocks.set(id2, render2);
632718
+ if (isPersistedDynamicBlockSpec(persistedSpec)) {
632719
+ this._dynamicBlockSpecs.set(id2, persistedSpec);
632720
+ } else {
632721
+ this._dynamicBlockSpecs.delete(id2);
632722
+ }
632439
632723
  this._dynamicBlockVersion++;
632440
632724
  this.invalidateRowCountCache();
632441
632725
  return `${this.DYNAMIC_BLOCK_MARK_PREFIX}${id2}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`;
@@ -632446,6 +632730,7 @@ var init_status_bar = __esm({
632446
632730
  /** Unregister a dynamic block. Existing sentinels in scrollback become inert (rendered as empty). */
632447
632731
  unregisterDynamicBlock(id2) {
632448
632732
  this._dynamicBlocks.delete(id2);
632733
+ this._dynamicBlockSpecs.delete(id2);
632449
632734
  this._dynamicBlockClickHandlers.delete(id2);
632450
632735
  this._dynamicBlockVersion++;
632451
632736
  this.invalidateRowCountCache();
@@ -632484,6 +632769,45 @@ var init_status_bar = __esm({
632484
632769
  const lines = mainView?.contentLines ?? this._contentLines;
632485
632770
  return this.expandDynamicBlockSentinels(lines, width);
632486
632771
  }
632772
+ dynamicBlockIdFromSentinel(line) {
632773
+ if (typeof line !== "string" || !line.startsWith(this.DYNAMIC_BLOCK_MARK_PREFIX) || !line.endsWith(this.DYNAMIC_BLOCK_MARK_SUFFIX) || line.length <= this.DYNAMIC_BLOCK_MARK_PREFIX.length + this.DYNAMIC_BLOCK_MARK_SUFFIX.length) {
632774
+ return null;
632775
+ }
632776
+ return line.slice(
632777
+ this.DYNAMIC_BLOCK_MARK_PREFIX.length,
632778
+ line.length - this.DYNAMIC_BLOCK_MARK_SUFFIX.length
632779
+ );
632780
+ }
632781
+ /** Capture raw render sources for exact restart restore. */
632782
+ capturePersistedSessionState() {
632783
+ const mainView = this._agentViews.get("main");
632784
+ const contentLines = [...mainView?.contentLines ?? this._contentLines].slice(-this._contentMaxLines);
632785
+ const dynamicBlocks = {};
632786
+ for (const line of contentLines) {
632787
+ const id2 = this.dynamicBlockIdFromSentinel(line);
632788
+ if (!id2) continue;
632789
+ const spec = this._dynamicBlockSpecs.get(id2);
632790
+ if (spec) dynamicBlocks[id2] = spec;
632791
+ }
632792
+ return {
632793
+ version: 2,
632794
+ savedAt: (/* @__PURE__ */ new Date()).toISOString(),
632795
+ contentLines,
632796
+ dynamicBlocks
632797
+ };
632798
+ }
632799
+ /** Restore raw render sources and re-register their live dynamic renderers. */
632800
+ restoreMainSessionState(state) {
632801
+ for (const [id2, spec] of Object.entries(state.dynamicBlocks ?? {})) {
632802
+ if (!isPersistedDynamicBlockSpec(spec)) continue;
632803
+ this.registerDynamicBlock(
632804
+ id2,
632805
+ (width) => renderPersistedDynamicBlockSpec(spec, width, id2),
632806
+ spec
632807
+ );
632808
+ }
632809
+ this.restoreMainContentLines(Array.isArray(state.contentLines) ? state.contentLines : []);
632810
+ }
632487
632811
  /**
632488
632812
  * Append a previously-registered dynamic block's sentinel to scrollback
632489
632813
  * and trigger a repaint. The block's renderer fires immediately at the
@@ -741062,6 +741386,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
741062
741386
  }
741063
741387
  try {
741064
741388
  const historySessionId = process.env["OMNIUS_SESSION_ID"] || `session-${Date.now().toString(36)}`;
741389
+ const tuiState = typeof statusBar?.capturePersistedSessionState === "function" ? statusBar.capturePersistedSessionState() : null;
741065
741390
  const contentLines = typeof statusBar?.capturePersistedSessionLines === "function" ? statusBar.capturePersistedSessionLines(100) : statusBar?._contentLines ?? [];
741066
741391
  if (contentLines.length > 0) {
741067
741392
  const description = cleanPromptForDiary(task).slice(0, 240);
@@ -741072,6 +741397,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
741072
741397
  taskCount: 1,
741073
741398
  model: config.model
741074
741399
  });
741400
+ if (tuiState) {
741401
+ saveTuiSessionState(repoRoot, historySessionId, tuiState);
741402
+ }
741075
741403
  importTranscriptSession({
741076
741404
  id: `tui:${historySessionId}`,
741077
741405
  projectRoot: repoRoot,
@@ -742847,6 +743175,7 @@ This is an independent background session started from /background.`
742847
743175
  function saveVisualSessionSnapshot(reason) {
742848
743176
  try {
742849
743177
  const historySessionId = process.env["OMNIUS_SESSION_ID"] || process.env["OMNIUS_TUI_SESSION_ID"] || `session-${Date.now().toString(36)}`;
743178
+ const tuiState = statusBar.capturePersistedSessionState();
742850
743179
  const contentLines = statusBar.capturePersistedSessionLines(100);
742851
743180
  if (contentLines.length === 0) return;
742852
743181
  const description = cleanPromptForDiary(lastSubmittedPrompt || lastCompletedSummary || reason).slice(0, 240) || reason;
@@ -742857,6 +743186,7 @@ This is an independent background session started from /background.`
742857
743186
  taskCount: 1,
742858
743187
  model: currentConfig.model
742859
743188
  });
743189
+ saveTuiSessionState(repoRoot, historySessionId, tuiState);
742860
743190
  importTranscriptSession({
742861
743191
  id: `tui:${historySessionId}`,
742862
743192
  projectRoot: repoRoot,
@@ -742872,6 +743202,14 @@ This is an independent background session started from /background.`
742872
743202
  saveVisualSessionSnapshotRef = saveVisualSessionSnapshot;
742873
743203
  function replayRestoredVisualSession(snapshot) {
742874
743204
  if (!snapshot.historySessionId) return false;
743205
+ const tuiState = loadTuiSessionState(repoRoot, snapshot.historySessionId);
743206
+ if (tuiState) {
743207
+ try {
743208
+ statusBar.restoreMainSessionState(tuiState);
743209
+ return true;
743210
+ } catch {
743211
+ }
743212
+ }
742875
743213
  const lines = loadSessionHistory(repoRoot, snapshot.historySessionId);
742876
743214
  if (!lines || lines.length === 0) return false;
742877
743215
  try {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.464",
3
+ "version": "1.0.466",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.464",
9
+ "version": "1.0.466",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.464",
3
+ "version": "1.0.466",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",