omnius 1.0.463 → 1.0.464

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
@@ -578528,7 +578528,7 @@ function classifyThinkOutcome(raw) {
578528
578528
  }
578529
578529
  return null;
578530
578530
  }
578531
- var TOOL_SUBSETS, TOOL_AUTO_DEMOTE_TURNS, TOOL_ACTION_REASON_KEYS, TOOL_ACTION_REASON_SCOPES, TOOL_ACTION_REASON_SCHEMA, SYSTEM_PROMPT, SYSTEM_PROMPT_MEDIUM, SYSTEM_PROMPT_SMALL, VISUAL_TOOLS, AUDIO_TOOLS, SOCIAL_TOOLS, SPATIAL_TOOLS, CODE_TOOLS, AgenticRunner, OllamaAgenticBackend;
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;
578532
578532
  var init_agenticRunner = __esm({
578533
578533
  "packages/orchestrator/dist/agenticRunner.js"() {
578534
578534
  "use strict";
@@ -578633,6 +578633,25 @@ var init_agenticRunner = __esm({
578633
578633
  "completion",
578634
578634
  "other"
578635
578635
  ]);
578636
+ READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS = /* @__PURE__ */ new Set([
578637
+ "file_read",
578638
+ "file_explore",
578639
+ "list_directory",
578640
+ "grep_search",
578641
+ "grep",
578642
+ "glob_find",
578643
+ "find_files",
578644
+ "todo_read",
578645
+ "memory_read",
578646
+ "memory_search",
578647
+ "semantic_map",
578648
+ "code_graph",
578649
+ "graph_query",
578650
+ "graph_traverse",
578651
+ "web_search",
578652
+ "web_fetch",
578653
+ "tool_search"
578654
+ ]);
578636
578655
  TOOL_ACTION_REASON_SCHEMA = {
578637
578656
  type: "object",
578638
578657
  description: "Compact public action contract for this exact tool call. Do not include hidden chain-of-thought; use concise task-state facts.",
@@ -579573,7 +579592,7 @@ ${parts.join("\n")}
579573
579592
  if (ts.failedApproaches.length > 0) {
579574
579593
  lines.push(`recent_failed_approaches=${ts.failedApproaches.slice(-3).join(" | ").replace(/\s+/g, " ").slice(0, 420)}`);
579575
579594
  }
579576
- lines.push("tool_call_contract=Each tool call must include action_reason {task_anchor,intent,evidence,expected_result,scope}; compact public facts only, no hidden chain-of-thought.");
579595
+ lines.push("tool_call_contract=Mutating/side-effectful tool calls require action_reason {task_anchor,intent,evidence,expected_result,scope}; read-only evidence tools may include it but must never be blocked only for missing metadata. Compact public facts only, no hidden chain-of-thought.");
579577
579596
  lines.push(`scope_contract=${Array.from(TOOL_ACTION_REASON_SCOPES).join("|")}; use targeted_patch for constrained code edits and full_file_rewrite only for deliberate whole-file replacement.`);
579578
579597
  const focus = this._focusSupervisor?.snapshot().directive ?? null;
579579
579598
  if (focus) {
@@ -584785,7 +584804,7 @@ ${blob}
584785
584804
  * size. The hash is computed over the full canonical value.
584786
584805
  */
584787
584806
  _buildExactArgsKey(args) {
584788
- return Object.entries(args ?? {}).sort(([a2], [b]) => a2.localeCompare(b)).map(([k, v]) => `${k}=${this._formatExactArgValue(v)}`).join(",");
584807
+ return Object.entries(args ?? {}).filter(([key]) => !TOOL_ACTION_REASON_KEYS.has(key)).sort(([a2], [b]) => a2.localeCompare(b)).map(([k, v]) => `${k}=${this._formatExactArgValue(v)}`).join(",");
584789
584808
  }
584790
584809
  _buildToolFingerprint(name10, args) {
584791
584810
  const canonical = this.lookupRegisteredTool(name10)?.name ?? name10;
@@ -585260,7 +585279,8 @@ Rewrite it now for ${ctx3.model}.`;
585260
585279
  const unknownKeys = providedKeys.filter((key) => !props.has(key));
585261
585280
  const aliases = this.suggestArgumentAliases(missingRequired, providedKeys, args, props);
585262
585281
  const corrected = this.buildCorrectedArgsPreview(args, props, aliases);
585263
- const siblingMatches = this.findSiblingToolSchemaMatches(toolName, providedKeys);
585282
+ const actionReasonOnlyFailure = validationError.includes("[TOOL ACTION REASON CONTRACT]");
585283
+ const siblingMatches = actionReasonOnlyFailure ? [] : this.findSiblingToolSchemaMatches(toolName, providedKeys);
585264
585284
  const lines = [
585265
585285
  `[RUNTIME TOOL ARGUMENT REPAIR]`,
585266
585286
  `Tool call failed before execution: ${toolName}`,
@@ -588680,7 +588700,7 @@ ${memoryLines.join("\n")}`
588680
588700
  const executeSingle = async (tc) => {
588681
588701
  if (this.aborted)
588682
588702
  return null;
588683
- const actionReasonForAdvisory = this._extractToolActionReason(tc.arguments ?? {});
588703
+ const actionReasonForAdvisory = this._toolActionReasonForCall(tc.name, tc.arguments ?? {});
588684
588704
  const cohortKey = this.buildArgCohortKey(tc.name, tc.arguments);
588685
588705
  const cohort = this._argCohorts.get(cohortKey);
588686
588706
  if (cohort && cohort.failure >= 3 && cohort.success === 0) {
@@ -593831,21 +593851,40 @@ ${marker}` : marker);
593831
593851
  }
593832
593852
  return matchesFresh(args);
593833
593853
  }
593834
- _requiresToolActionReason(toolName) {
593854
+ _toolActionReasonPolicy(toolName, args) {
593835
593855
  if (process.env["OMNIUS_DISABLE_TOOL_ACTION_REASON"] === "1") {
593836
- return false;
593856
+ return "disabled";
593837
593857
  }
593838
593858
  if ((process.env["VITEST"] || process.env["NODE_ENV"] === "test") && process.env["OMNIUS_REQUIRE_TOOL_ACTION_REASON"] !== "1") {
593839
- return false;
593859
+ return "disabled";
593840
593860
  }
593841
593861
  if (this.options.artifactMode === "internal")
593842
- return false;
593862
+ return "disabled";
593843
593863
  if (toolName.startsWith("__"))
593844
- return false;
593845
- return true;
593864
+ return "disabled";
593865
+ return this._toolActionReasonIsOptional(toolName, args) ? "optional" : "required";
593866
+ }
593867
+ _requiresToolActionReason(toolName, args) {
593868
+ return this._toolActionReasonPolicy(toolName, args) === "required";
593869
+ }
593870
+ _toolActionReasonIsOptional(toolName, args) {
593871
+ const resolved = this.lookupRegisteredTool(toolName);
593872
+ const canonical = resolved?.name ?? toolName;
593873
+ if (READ_ONLY_ACTION_REASON_OPTIONAL_TOOLS.has(canonical))
593874
+ return true;
593875
+ const tool = resolved?.tool;
593876
+ if (typeof tool?.isReadOnly === "function") {
593877
+ try {
593878
+ if (tool.isReadOnly(args ?? {}))
593879
+ return true;
593880
+ } catch {
593881
+ }
593882
+ }
593883
+ return false;
593846
593884
  }
593847
593885
  _withToolActionReasonSchema(toolName, parameters) {
593848
- if (!this._requiresToolActionReason(toolName)) {
593886
+ const policy = this._toolActionReasonPolicy(toolName);
593887
+ if (policy === "disabled") {
593849
593888
  return parameters ?? { type: "object", properties: {} };
593850
593889
  }
593851
593890
  const base3 = parameters && typeof parameters === "object" && !Array.isArray(parameters) ? { ...parameters } : { type: "object" };
@@ -593856,7 +593895,7 @@ ${marker}` : marker);
593856
593895
  ...base3,
593857
593896
  type: "object",
593858
593897
  properties,
593859
- required: [.../* @__PURE__ */ new Set([...required, "action_reason"])]
593898
+ required: policy === "required" ? [.../* @__PURE__ */ new Set([...required, "action_reason"])] : required
593860
593899
  };
593861
593900
  }
593862
593901
  _extractToolActionReason(args) {
@@ -593883,20 +593922,46 @@ ${marker}` : marker);
593883
593922
  };
593884
593923
  return reason;
593885
593924
  }
593925
+ _toolActionReasonForCall(toolName, args) {
593926
+ const explicit = this._extractToolActionReason(args);
593927
+ if (explicit)
593928
+ return explicit;
593929
+ if (this._toolActionReasonPolicy(toolName, args) !== "optional")
593930
+ return null;
593931
+ return this._synthesizeReadOnlyToolActionReason(toolName, args);
593932
+ }
593933
+ _synthesizeReadOnlyToolActionReason(toolName, args) {
593934
+ const canonical = this.lookupRegisteredTool(toolName)?.name ?? toolName;
593935
+ const goal = this._taskState.currentStep || this._taskState.nextAction || this._taskState.goal || this._taskState.originalGoal || "current task";
593936
+ const targets = this._extractToolTargetPaths(canonical, args).slice(0, 3);
593937
+ const targetText = targets.length > 0 ? ` for ${targets.join(", ")}` : "";
593938
+ return {
593939
+ task_anchor: String(goal).replace(/\s+/g, " ").trim().slice(0, 160),
593940
+ intent: `Run read-only ${canonical}${targetText} to gather current evidence.`,
593941
+ evidence: "Read-only metadata fallback; no project mutation is authorized by this action.",
593942
+ expected_result: `Current ${canonical} evidence for the next decision.`,
593943
+ scope: "discovery"
593944
+ };
593945
+ }
593886
593946
  _validateToolActionReason(toolName, args) {
593887
- if (!this._requiresToolActionReason(toolName))
593947
+ const policy = this._toolActionReasonPolicy(toolName, args);
593948
+ if (policy === "disabled")
593888
593949
  return null;
593889
593950
  const raw = args["action_reason"] ?? args["actionReason"] ?? args["justification"];
593890
593951
  if (!raw || typeof raw === "string" && !raw.trim()) {
593952
+ if (policy === "optional")
593953
+ return null;
593891
593954
  return [
593892
593955
  "[TOOL ACTION REASON CONTRACT]",
593893
- `Every tool call must include action_reason: { task_anchor, intent, evidence, expected_result, scope }.`,
593956
+ `This side-effectful tool call must include action_reason: { task_anchor, intent, evidence, expected_result, scope }.`,
593894
593957
  `Use compact public facts only; do not include hidden chain-of-thought.`,
593895
593958
  `scope must be one of: ${Array.from(TOOL_ACTION_REASON_SCOPES).join(", ")}.`
593896
593959
  ].join("\n");
593897
593960
  }
593898
593961
  const reason = this._extractToolActionReason(args);
593899
593962
  if (!reason) {
593963
+ if (policy === "optional")
593964
+ return null;
593900
593965
  return "[TOOL ACTION REASON CONTRACT] action_reason must be an object with compact public task-state fields.";
593901
593966
  }
593902
593967
  const missing = [
@@ -593907,9 +593972,13 @@ ${marker}` : marker);
593907
593972
  "scope"
593908
593973
  ].filter((key) => reason[key].length < 3);
593909
593974
  if (missing.length > 0) {
593975
+ if (policy === "optional")
593976
+ return null;
593910
593977
  return `[TOOL ACTION REASON CONTRACT] action_reason missing non-empty field(s): ${missing.join(", ")}.`;
593911
593978
  }
593912
593979
  if (!TOOL_ACTION_REASON_SCOPES.has(reason.scope)) {
593980
+ if (policy === "optional")
593981
+ return null;
593913
593982
  return `[TOOL ACTION REASON CONTRACT] action_reason.scope="${reason.scope}" is invalid. Use one of: ${Array.from(TOOL_ACTION_REASON_SCOPES).join(", ")}.`;
593914
593983
  }
593915
593984
  return null;
@@ -595967,7 +596036,7 @@ ${trimmedNew}`;
595967
596036
  args = JSON.parse(tc.function.arguments);
595968
596037
  } catch {
595969
596038
  }
595970
- const actionReason = this._extractToolActionReason(args);
596039
+ const actionReason = this._toolActionReasonForCall(name10, args);
595971
596040
  const argsKey = this._buildExactArgsKey(args);
595972
596041
  const fingerprint = this._buildToolFingerprint(name10, args);
595973
596042
  const prior = this._adversaryToolOutcomes.find((o2) => o2.succeeded && o2.tool === name10 && o2.fingerprint === fingerprint && o2.stateVersion === this._adversaryStateVersion && o2.turn < turn);
@@ -627926,6 +627995,7 @@ var omnius_directory_exports = {};
627926
627995
  __export(omnius_directory_exports, {
627927
627996
  OMNIUS_DIR: () => OMNIUS_DIR,
627928
627997
  buildContextRestorePrompt: () => buildContextRestorePrompt,
627998
+ buildContextRestoreSnapshot: () => buildContextRestoreSnapshot,
627929
627999
  buildHandoffPrompt: () => buildHandoffPrompt,
627930
628000
  cleanPromptForDiary: () => cleanPromptForDiary,
627931
628001
  clearTaskHandoff: () => clearTaskHandoff,
@@ -628869,9 +628939,7 @@ function selectActiveTaskAnchor(repoRoot) {
628869
628939
  return null;
628870
628940
  }
628871
628941
  }
628872
- function buildActiveTaskAnchor(repoRoot) {
628873
- const selected = selectActiveTaskAnchor(repoRoot);
628874
- if (!selected) return null;
628942
+ function formatActiveTaskAnchor(selected) {
628875
628943
  const ledger = selected.ledger;
628876
628944
  const evidence = ledger.evidence ?? [];
628877
628945
  const selectedEvidence = [...evidence.slice(0, 2), ...evidence.slice(-4)];
@@ -628905,6 +628973,131 @@ ${boardCards.join("\n")}
628905
628973
  ` : "") + `Continuation rule: when the user asks to continue, resume this active task unless the new prompt names a different target.
628906
628974
  </active-task-anchor>`;
628907
628975
  }
628976
+ function uniqueSessionIds(ids) {
628977
+ const seen = /* @__PURE__ */ new Set();
628978
+ const out = [];
628979
+ for (const raw of ids) {
628980
+ const id2 = String(raw || "").trim();
628981
+ if (!id2 || seen.has(id2)) continue;
628982
+ seen.add(id2);
628983
+ out.push(id2);
628984
+ }
628985
+ return out;
628986
+ }
628987
+ function collectRestoreSessionIds(ctx3, activeTask, historySessionId) {
628988
+ const entries = ctx3?.entries ?? [];
628989
+ const usefulEntries = entries.filter((entry) => !isManualSessionEntry(entry));
628990
+ const chronological = usefulEntries.length > 0 ? usefulEntries : entries;
628991
+ return uniqueSessionIds([
628992
+ activeTask?.ledger.runId,
628993
+ ...[...chronological].reverse().map((entry) => entry.sessionId),
628994
+ ...[...entries].reverse().map((entry) => entry.sessionId),
628995
+ historySessionId
628996
+ ]);
628997
+ }
628998
+ function childMapForTodos(todos) {
628999
+ const byId = new Set(todos.map((todo) => todo.id));
629000
+ const byParent = /* @__PURE__ */ new Map();
629001
+ for (const todo of todos) {
629002
+ if (!todo.parentId || !byId.has(todo.parentId)) continue;
629003
+ const bucket = byParent.get(todo.parentId) ?? [];
629004
+ bucket.push(todo);
629005
+ byParent.set(todo.parentId, bucket);
629006
+ }
629007
+ for (const bucket of byParent.values()) {
629008
+ bucket.sort((a2, b) => a2.createdAt - b.createdAt || a2.id.localeCompare(b.id));
629009
+ }
629010
+ return byParent;
629011
+ }
629012
+ function statusRank2(status) {
629013
+ switch (status) {
629014
+ case "in_progress":
629015
+ return 0;
629016
+ case "blocked":
629017
+ return 1;
629018
+ case "pending":
629019
+ return 2;
629020
+ case "completed":
629021
+ return 3;
629022
+ default:
629023
+ return 4;
629024
+ }
629025
+ }
629026
+ function orderedTodoTree(todos) {
629027
+ const byId = new Set(todos.map((todo) => todo.id));
629028
+ const byParent = childMapForTodos(todos);
629029
+ const roots = todos.filter((todo) => !todo.parentId || !byId.has(todo.parentId)).sort((a2, b) => statusRank2(a2.status) - statusRank2(b.status) || a2.createdAt - b.createdAt || a2.id.localeCompare(b.id));
629030
+ const out = [];
629031
+ const seen = /* @__PURE__ */ new Set();
629032
+ const visit = (todo, depth) => {
629033
+ if (seen.has(todo.id)) return;
629034
+ seen.add(todo.id);
629035
+ out.push({ todo, depth });
629036
+ for (const child of byParent.get(todo.id) ?? []) visit(child, depth + 1);
629037
+ };
629038
+ for (const root of roots) visit(root, 0);
629039
+ for (const todo of todos) visit(todo, 0);
629040
+ return out;
629041
+ }
629042
+ function formatTodoLine(todo, depth) {
629043
+ const indent2 = " ".repeat(Math.min(depth, 6));
629044
+ const blocker = todo.blocker ? ` blocker="${normalizeSessionText(todo.blocker, 120)}"` : "";
629045
+ const verify2 = todo.verifyCommand ? ` verify="${normalizeSessionText(todo.verifyCommand, 120)}"` : "";
629046
+ const artifacts = todo.declaredArtifacts && todo.declaredArtifacts.length > 0 ? ` artifacts=${todo.declaredArtifacts.slice(0, 4).map((item) => normalizeSessionText(item, 80)).join(",")}` : "";
629047
+ return `${indent2}- [${todo.status}] ${normalizeSessionText(todo.content, 180)} (id=${todo.id}${todo.parentId ? ` parent=${todo.parentId}` : ""}${blocker}${verify2}${artifacts})`;
629048
+ }
629049
+ function buildRestoredTodoBlock(sessionId, todos) {
629050
+ const byParent = childMapForTodos(todos);
629051
+ const leafTodos = todos.filter((todo) => (byParent.get(todo.id)?.length ?? 0) === 0);
629052
+ const completedLeaves = leafTodos.filter((todo) => todo.status === "completed").length;
629053
+ const activeTodos = todos.filter((todo) => todo.status === "in_progress" || todo.status === "blocked").sort((a2, b) => statusRank2(a2.status) - statusRank2(b.status) || b.updatedAt - a2.updatedAt).slice(0, 8);
629054
+ const ordered = orderedTodoTree(todos);
629055
+ const visible = ordered.slice(0, 48);
629056
+ const omitted = Math.max(0, ordered.length - visible.length);
629057
+ const activeLines = activeTodos.map((todo) => `- [${todo.status}] ${normalizeSessionText(todo.content, 180)} (id=${todo.id})`);
629058
+ const treeLines = visible.map(({ todo, depth }) => formatTodoLine(todo, depth));
629059
+ return `<restored-todo-state>
629060
+ todo_session_id=${sessionId}
629061
+ total=${todos.length}; leaf_progress=${completedLeaves}/${leafTodos.length || todos.length}
629062
+ ` + (activeLines.length > 0 ? `Active/blocked items:
629063
+ ${activeLines.join("\n")}
629064
+ ` : "") + `Todo tree:
629065
+ ${treeLines.join("\n")}${omitted > 0 ? `
629066
+ - ... ${omitted} more todo(s) in restored session` : ""}
629067
+ Continuation contract: this is the live checklist from the restored run. Continue it and update it with todo_write; do not recreate a parallel plan unless the new user request explicitly changes direction.
629068
+ </restored-todo-state>`;
629069
+ }
629070
+ function findRestoredTodoState(sessionIds) {
629071
+ for (const sessionId of sessionIds) {
629072
+ const todos = readTodos(sessionId).filter((todo) => todo && todo.id && todo.content);
629073
+ if (todos.length === 0) continue;
629074
+ return {
629075
+ sessionId,
629076
+ todos,
629077
+ block: buildRestoredTodoBlock(sessionId, todos)
629078
+ };
629079
+ }
629080
+ return null;
629081
+ }
629082
+ function buildRestoreHistoryAnchor(repoRoot) {
629083
+ const [latest] = listSessions(repoRoot);
629084
+ if (!latest?.id) return null;
629085
+ const lines = loadSessionHistory(repoRoot, latest.id) ?? [];
629086
+ const meaningfulTail = lines.map((line) => cleanSessionHistoryDisplayLine(line)).filter((line) => line && !isNoisySessionHistoryLine(line)).slice(-18).map((line) => `- ${normalizeSessionText(line, 220)}`);
629087
+ const path12 = join136(OMNIUS_DIR, SESSIONS_DIR, `${latest.id}.jsonl`);
629088
+ const block = `<restored-interface-history>
629089
+ latest_visual_session_id=${latest.id}
629090
+ full_transcript_path=${path12}
629091
+ recorded_lines=${lines.length}
629092
+ ` + (meaningfulTail.length > 0 ? `Recent visible transcript tail:
629093
+ ${meaningfulTail.join("\n")}
629094
+ ` : "") + `Recall contract: the full transcript artifact above is restored into the TUI scrollback and is the authoritative previous interface state. Read it only when exact prior UI/tool output is needed; otherwise use this restored state to avoid rediscovery.
629095
+ </restored-interface-history>`;
629096
+ return { sessionId: latest.id, path: path12, lineCount: lines.length, block };
629097
+ }
629098
+ function appendRestoreBlocks(base3, blocks) {
629099
+ return [base3, ...blocks].filter((part) => part && part.trim()).join("\n\n");
629100
+ }
628908
629101
  function formatSessionHistoryDisplay(ctx3) {
628909
629102
  return buildSessionHistoryBoxLines(
628910
629103
  sessionContextToHistoryBoxData(ctx3),
@@ -628930,10 +629123,15 @@ function sessionContextToHistoryBoxData(ctx3, title = "Session History") {
628930
629123
  updatedAt: ctx3?.updatedAt ?? null
628931
629124
  };
628932
629125
  }
628933
- function buildContextRestorePrompt(repoRoot) {
629126
+ function buildContextRestoreSnapshot(repoRoot) {
628934
629127
  const ctx3 = loadSessionContext(repoRoot);
628935
629128
  const handoffPrompt = buildHandoffPrompt(repoRoot);
628936
- const activeTaskAnchor = buildActiveTaskAnchor(repoRoot);
629129
+ const activeTask = selectActiveTaskAnchor(repoRoot);
629130
+ const activeTaskAnchor = activeTask ? formatActiveTaskAnchor(activeTask) : null;
629131
+ const historyAnchor = buildRestoreHistoryAnchor(repoRoot);
629132
+ const restoreSessionIds = collectRestoreSessionIds(ctx3, activeTask, historyAnchor?.sessionId);
629133
+ const restoredTodos = findRestoredTodoState(restoreSessionIds);
629134
+ const sourceSessionId = restoredTodos?.sessionId ?? restoreSessionIds[0];
628937
629135
  if (handoffPrompt) {
628938
629136
  const usefulEntries2 = (ctx3?.entries ?? []).filter((entry) => !isManualSessionEntry(entry));
628939
629137
  const baseCtx = ctx3 && ctx3.entries.length > 0 ? `
@@ -628943,13 +629141,37 @@ Recent tasks: ${(usefulEntries2.length > 0 ? usefulEntries2 : ctx3.entries).slic
628943
629141
  (e2) => `[${e2.completed ? "done" : "partial"}] ${normalizeSessionText(e2.summary || e2.task, 80)}`
628944
629142
  ).join(", ")}
628945
629143
  </session-recap>` : "";
628946
- return handoffPrompt + (activeTaskAnchor ? `
629144
+ const prompt2 = appendRestoreBlocks(
629145
+ handoffPrompt + (activeTaskAnchor ? `
628947
629146
 
628948
- ${activeTaskAnchor}` : "") + baseCtx;
629147
+ ${activeTaskAnchor}` : "") + baseCtx,
629148
+ [restoredTodos?.block, historyAnchor?.block]
629149
+ );
629150
+ return {
629151
+ prompt: prompt2,
629152
+ sourceSessionId,
629153
+ todoSessionId: restoredTodos?.sessionId,
629154
+ todoCount: restoredTodos?.todos.length ?? 0,
629155
+ historySessionId: historyAnchor?.sessionId,
629156
+ historyPath: historyAnchor?.path,
629157
+ historyLineCount: historyAnchor?.lineCount
629158
+ };
629159
+ }
629160
+ if (!ctx3 || ctx3.entries.length === 0) {
629161
+ const prompt2 = appendRestoreBlocks(activeTaskAnchor ?? "", [restoredTodos?.block, historyAnchor?.block]);
629162
+ if (!prompt2.trim()) return null;
629163
+ return {
629164
+ prompt: prompt2,
629165
+ sourceSessionId,
629166
+ todoSessionId: restoredTodos?.sessionId,
629167
+ todoCount: restoredTodos?.todos.length ?? 0,
629168
+ historySessionId: historyAnchor?.sessionId,
629169
+ historyPath: historyAnchor?.path,
629170
+ historyLineCount: historyAnchor?.lineCount
629171
+ };
628949
629172
  }
628950
- if (!ctx3 || ctx3.entries.length === 0) return activeTaskAnchor;
628951
629173
  const usefulEntries = ctx3.entries.filter((entry) => !isManualSessionEntry(entry));
628952
- const recent = (usefulEntries.length > 0 ? usefulEntries : ctx3.entries).slice(-5);
629174
+ const recent = (usefulEntries.length > 0 ? usefulEntries : ctx3.entries).slice(-20);
628953
629175
  const chronology = recent.map((e2) => {
628954
629176
  const status = e2.completed ? "done" : "partial";
628955
629177
  const summary = normalizeSessionText(e2.assistantResponse || e2.summary || e2.task, 140);
@@ -628960,7 +629182,7 @@ ${activeTaskAnchor}` : "") + baseCtx;
628960
629182
  const last2 = recent[recent.length - 1] ?? ctx3.entries[ctx3.entries.length - 1];
628961
629183
  const lastCompleted = [...usefulEntries].reverse().find((entry) => entry.completed);
628962
629184
  const latestCompleted = lastCompleted ? `Latest completed task: ${normalizeSessionText(lastCompleted.assistantResponse || lastCompleted.summary || lastCompleted.task, 180)}` : "";
628963
- const recentDialogue = recent.slice(-3).map((entry) => {
629185
+ const recentDialogue = recent.slice(-8).map((entry) => {
628964
629186
  const assistant = normalizeSessionText(entry.assistantResponse || entry.summary, 320) || "(no assistant reply captured)";
628965
629187
  const user = cleanPromptForDiary(entry.task).slice(0, 220);
628966
629188
  return `User: ${user}
@@ -628970,10 +629192,12 @@ Assistant: ${assistant}`;
628970
629192
  Provenance: ${last2.provenance} (file_read to expand)` : "";
628971
629193
  const kg = `
628972
629194
  KG summary: .omnius/context/kg-summary/latest.md (file_read to expand; legacy pointer: .omnius/context/kg-summary-latest.md)`;
628973
- return `<session-recap>
629195
+ const prompt = appendRestoreBlocks(
629196
+ `<session-recap>
628974
629197
  ` + (activeTaskAnchor ? `${activeTaskAnchor}
628975
629198
 
628976
629199
  ` : "") + `Project chronology (older to newer):
629200
+ Scope: full retained rolling window (${recent.length} entr${recent.length === 1 ? "y" : "ies"}).
628977
629201
  ${chronology.join("\n")}
628978
629202
  ` + (latestCompleted ? `
628979
629203
  ${latestCompleted}
@@ -628982,7 +629206,21 @@ Most recent exchanges (older to newer):
628982
629206
  ${recentDialogue}
628983
629207
  ` + (activeTaskAnchor ? `For continuation prompts, resume the active task anchor above; use chronology only to avoid repeating completed work.${prov}${kg}
628984
629208
  ` : `Continue from the latest exchange and do not repeat completed work.${prov}${kg}
628985
- `) + `</session-recap>`;
629209
+ `) + `</session-recap>`,
629210
+ [restoredTodos?.block, historyAnchor?.block]
629211
+ );
629212
+ return {
629213
+ prompt,
629214
+ sourceSessionId,
629215
+ todoSessionId: restoredTodos?.sessionId,
629216
+ todoCount: restoredTodos?.todos.length ?? 0,
629217
+ historySessionId: historyAnchor?.sessionId,
629218
+ historyPath: historyAnchor?.path,
629219
+ historyLineCount: historyAnchor?.lineCount
629220
+ };
629221
+ }
629222
+ function buildContextRestorePrompt(repoRoot) {
629223
+ return buildContextRestoreSnapshot(repoRoot)?.prompt ?? null;
628986
629224
  }
628987
629225
  function getLastTaskSummary(repoRoot) {
628988
629226
  const ctx3 = loadSessionContext(repoRoot);
@@ -629309,6 +629547,7 @@ var OMNIUS_DIR, LEGACY_DIRS, SUBDIRS, gitignoreWatchers, gitignoreRetryTimers, C
629309
629547
  var init_omnius_directory = __esm({
629310
629548
  "packages/cli/src/tui/omnius-directory.ts"() {
629311
629549
  "use strict";
629550
+ init_dist5();
629312
629551
  init_task_complete_box();
629313
629552
  OMNIUS_DIR = ".omnius";
629314
629553
  LEGACY_DIRS = [".oa", ".open-agents"];
@@ -632239,6 +632478,12 @@ var init_status_bar = __esm({
632239
632478
  }
632240
632479
  return out;
632241
632480
  }
632481
+ /** Capture the main session scrollback for persistence, independent of active tab. */
632482
+ capturePersistedSessionLines(width = 100) {
632483
+ const mainView = this._agentViews.get("main");
632484
+ const lines = mainView?.contentLines ?? this._contentLines;
632485
+ return this.expandDynamicBlockSentinels(lines, width);
632486
+ }
632242
632487
  /**
632243
632488
  * Append a previously-registered dynamic block's sentinel to scrollback
632244
632489
  * and trigger a repaint. The block's renderer fires immediately at the
@@ -633605,6 +633850,40 @@ var init_status_bar = __esm({
633605
633850
  this.fillContentArea();
633606
633851
  this.renderFooterAndPositionInput();
633607
633852
  }
633853
+ /**
633854
+ * Restore persisted scrollback into the main TUI view after process restart.
633855
+ *
633856
+ * Session transcripts are persisted with dynamic blocks already expanded, so
633857
+ * this intentionally restores plain rendered lines rather than stale sentinel
633858
+ * callbacks from a prior process.
633859
+ */
633860
+ restoreMainContentLines(lines) {
633861
+ const mainView = this._agentViews.get("main");
633862
+ const restored = lines.filter((line) => typeof line === "string").slice(-this._contentMaxLines);
633863
+ if (mainView) {
633864
+ mainView.contentLines.splice(0, mainView.contentLines.length, ...restored);
633865
+ mainView.scrollOffset = 0;
633866
+ this._activeViewId = "main";
633867
+ this._contentLines = mainView.contentLines;
633868
+ } else {
633869
+ this._contentLines.splice(0, this._contentLines.length, ...restored);
633870
+ }
633871
+ this._contentScrollOffset = 0;
633872
+ this._pendingTrailingBlanks = 0;
633873
+ this._inProgressLine = "";
633874
+ this.clearStreamingRepaintTimer();
633875
+ this._lastBufferedFingerprint = "";
633876
+ this._lastBufferedAt = 0;
633877
+ this._autoScroll = true;
633878
+ this.markContentMutated();
633879
+ this.clampContentScrollOffset();
633880
+ if (this.active) {
633881
+ this.fillContentArea();
633882
+ this.repaintContent();
633883
+ this.renderFooterAndPositionInput();
633884
+ this.refreshHeaderContent();
633885
+ }
633886
+ }
633608
633887
  /** Set callback for header focus changes (wired by interactive.ts to banner) */
633609
633888
  setHeaderFocusHandler(handler) {
633610
633889
  this._headerFocusHandler = handler;
@@ -659388,11 +659667,12 @@ sleep 1
659388
659667
  const prompt = ctx3.contextRestore?.();
659389
659668
  if (prompt) {
659390
659669
  const info = ctx3.contextShow?.();
659670
+ const snapshot = typeof prompt === "string" ? null : prompt;
659671
+ ctx3.setRestoredContext?.(prompt);
659391
659672
  renderInfo(
659392
- `Context restored from ${info?.entries ?? 0} saved session(s). Will be injected into your next task.`
659673
+ `Context restored from ${info?.entries ?? 0} saved session(s)${snapshot?.historyLineCount ? `; replayed ${snapshot.historyLineCount} transcript line(s)` : ""}${snapshot?.todoCount ? `; restored ${snapshot.todoCount} todo(s)` : ""}. Will be injected into your next task.`
659393
659674
  );
659394
- renderContextHistory(ctx3, "Session History");
659395
- ctx3.setRestoredContext?.(prompt);
659675
+ if (!snapshot?.historyLineCount) renderContextHistory(ctx3, "Session History");
659396
659676
  } else {
659397
659677
  renderWarning(
659398
659678
  "No saved session context found. Complete a task first, or use /context save."
@@ -738694,7 +738974,7 @@ async function runSelfImprovementCycle(repoRoot) {
738694
738974
  } catch {
738695
738975
  }
738696
738976
  }
738697
- function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType, contextWindowSize, modelCaps, personality, deepContext, onCompaction, emotionEngine, flowEnabled, slashCommandHandler, thinkingEnabled, askUserCallback, selfModifyEnabled, sessionMetrics, realtimeEnabled) {
738977
+ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType, contextWindowSize, modelCaps, personality, deepContext, onCompaction, emotionEngine, flowEnabled, slashCommandHandler, thinkingEnabled, askUserCallback, selfModifyEnabled, sessionMetrics, realtimeEnabled, restoredRunSessionId) {
738698
738978
  const voiceStyleMap = {
738699
738979
  concise: 1,
738700
738980
  balanced: 3,
@@ -738715,7 +738995,7 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
738715
738995
  if (emotionEngine) emotionEngine.autistMode = true;
738716
738996
  }
738717
738997
  const modelTier2 = getModelTier(config.model);
738718
- const sessionId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
738998
+ const sessionId = typeof restoredRunSessionId === "string" && restoredRunSessionId.trim() ? restoredRunSessionId.trim() : `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
738719
738999
  const taskMetricDescription = cleanForStorage(task).replace(/\s+/g, " ").slice(0, 160) || "task";
738720
739000
  costTracker?.startTask(taskMetricDescription);
738721
739001
  sessionMetrics?.startTask(taskMetricDescription);
@@ -740719,7 +740999,8 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
740719
740999
  toolCalls: result.toolCalls,
740720
741000
  completed: result.completed,
740721
741001
  model: config.model,
740722
- source: "task_complete"
741002
+ source: "task_complete",
741003
+ sessionId
740723
741004
  });
740724
741005
  } catch {
740725
741006
  }
@@ -740756,7 +741037,8 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
740756
741037
  toolCalls: result.toolCalls,
740757
741038
  completed: result.completed,
740758
741039
  model: config.model,
740759
- source: "task_complete"
741040
+ source: "task_complete",
741041
+ sessionId
740760
741042
  },
740761
741043
  accomplishments: extractedAccomplishments.length > 0 ? extractedAccomplishments : [
740762
741044
  `Completed task in ${result.turns} turns with ${result.toolCalls} tool calls`
@@ -740780,11 +741062,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
740780
741062
  }
740781
741063
  try {
740782
741064
  const historySessionId = process.env["OMNIUS_SESSION_ID"] || `session-${Date.now().toString(36)}`;
740783
- const rawContentLines = statusBar?._contentLines ?? [];
740784
- const contentLines = typeof statusBar?.expandDynamicBlockSentinels === "function" ? statusBar.expandDynamicBlockSentinels(
740785
- rawContentLines,
740786
- 100
740787
- ) : rawContentLines;
741065
+ const contentLines = typeof statusBar?.capturePersistedSessionLines === "function" ? statusBar.capturePersistedSessionLines(100) : statusBar?._contentLines ?? [];
740788
741066
  if (contentLines.length > 0) {
740789
741067
  const description = cleanPromptForDiary(task).slice(0, 240);
740790
741068
  const historyTitle = description.slice(0, 80) || void 0;
@@ -741025,6 +741303,8 @@ async function startInteractive(config, repoPath2) {
741025
741303
  }
741026
741304
  await bootstrapMcpAndPlugins(repoRoot);
741027
741305
  let restoredSessionContext = null;
741306
+ let restoredTaskSessionId = null;
741307
+ let saveVisualSessionSnapshotRef = null;
741028
741308
  let terminalRestoredForExit = false;
741029
741309
  let interactiveExiting = false;
741030
741310
  let idleMemoryMaintenance = null;
@@ -741053,6 +741333,10 @@ async function startInteractive(config, repoPath2) {
741053
741333
  );
741054
741334
  const cleanupAndExit = (code8) => {
741055
741335
  interactiveExiting = true;
741336
+ try {
741337
+ saveVisualSessionSnapshotRef?.("process exit");
741338
+ } catch {
741339
+ }
741056
741340
  if (_shellToolRef) _shellToolRef.killAll();
741057
741341
  idleMemoryMaintenance?.stop();
741058
741342
  killAllFullSubAgents();
@@ -741569,14 +741853,14 @@ ${result.summary}`
741569
741853
  const { getLastTaskSummary: getLastTaskSummary2 } = (init_omnius_directory(), __toCommonJS(omnius_directory_exports));
741570
741854
  const taskSummary = hasTaskToResume ? getLastTaskSummary2(repoRoot) : null;
741571
741855
  const resumeMsg = taskSummary ? `v${version5} — picking up: ${taskSummary}` : `Updated to v${version5}.`;
741856
+ const restoreSnapshot = buildContextRestoreSnapshot(repoRoot);
741857
+ const replayedVisual = restoreSnapshot ? applyRestoreSnapshot(restoreSnapshot, { replayVisual: true }) : false;
741572
741858
  writeContent(() => {
741573
741859
  renderInfo(resumeMsg);
741574
- const resumePrompt = buildContextRestorePrompt(repoRoot);
741575
- if (resumePrompt) {
741576
- restoredSessionContext = resumePrompt;
741860
+ if (restoreSnapshot) {
741577
741861
  const info = loadSessionContext(repoRoot);
741578
741862
  renderInfo(
741579
- `Context restored from ${info?.entries.length ?? 0} session(s).`
741863
+ `Context restored from ${info?.entries.length ?? 0} session(s)${replayedVisual ? `; replayed ${restoreSnapshot.historyLineCount ?? 0} transcript line(s).` : "."}`
741580
741864
  );
741581
741865
  }
741582
741866
  });
@@ -742560,6 +742844,69 @@ This is an independent background session started from /background.`
742560
742844
  }
742561
742845
  }
742562
742846
  setDreamWriteContent(writeContent);
742847
+ function saveVisualSessionSnapshot(reason) {
742848
+ try {
742849
+ const historySessionId = process.env["OMNIUS_SESSION_ID"] || process.env["OMNIUS_TUI_SESSION_ID"] || `session-${Date.now().toString(36)}`;
742850
+ const contentLines = statusBar.capturePersistedSessionLines(100);
742851
+ if (contentLines.length === 0) return;
742852
+ const description = cleanPromptForDiary(lastSubmittedPrompt || lastCompletedSummary || reason).slice(0, 240) || reason;
742853
+ const historyTitle = description.slice(0, 80) || void 0;
742854
+ saveSessionHistory(repoRoot, historySessionId, contentLines, {
742855
+ name: historyTitle,
742856
+ description,
742857
+ taskCount: 1,
742858
+ model: currentConfig.model
742859
+ });
742860
+ importTranscriptSession({
742861
+ id: `tui:${historySessionId}`,
742862
+ projectRoot: repoRoot,
742863
+ model: currentConfig.model,
742864
+ title: historyTitle,
742865
+ description,
742866
+ transcriptLines: contentLines,
742867
+ updatedAt: Date.now()
742868
+ });
742869
+ } catch {
742870
+ }
742871
+ }
742872
+ saveVisualSessionSnapshotRef = saveVisualSessionSnapshot;
742873
+ function replayRestoredVisualSession(snapshot) {
742874
+ if (!snapshot.historySessionId) return false;
742875
+ const lines = loadSessionHistory(repoRoot, snapshot.historySessionId);
742876
+ if (!lines || lines.length === 0) return false;
742877
+ try {
742878
+ statusBar.restoreMainContentLines(lines);
742879
+ return true;
742880
+ } catch {
742881
+ return false;
742882
+ }
742883
+ }
742884
+ function applyRestoreSnapshot(snapshot, options2 = {}) {
742885
+ if (options2.injectNextTask !== false) {
742886
+ restoredSessionContext = snapshot.prompt;
742887
+ }
742888
+ const restoredId = snapshot.todoSessionId || snapshot.sourceSessionId || null;
742889
+ restoredTaskSessionId = restoredId;
742890
+ if (restoredId) {
742891
+ try {
742892
+ process.env["OMNIUS_SESSION_ID"] = restoredId;
742893
+ } catch {
742894
+ }
742895
+ try {
742896
+ setTodoSessionId(restoredId);
742897
+ } catch {
742898
+ }
742899
+ try {
742900
+ setTuiTasksSession(restoredId);
742901
+ } catch {
742902
+ }
742903
+ try {
742904
+ refreshTuiTasks();
742905
+ } catch {
742906
+ }
742907
+ }
742908
+ return options2.replayVisual ? replayRestoredVisualSession(snapshot) : false;
742909
+ }
742563
742910
  async function writeContentAsync(fn) {
742564
742911
  if (!statusBar.isActive) return fn();
742565
742912
  if (isNeovimActive()) {
@@ -743335,6 +743682,7 @@ Log: ${nexusLogPath}`
743335
743682
  clearInterval(reminderDispatchTimer);
743336
743683
  reminderDispatchTimer = null;
743337
743684
  }
743685
+ saveVisualSessionSnapshot("command exit");
743338
743686
  statusBar.deactivate();
743339
743687
  if (carousel.isRunning) carousel.stop();
743340
743688
  banner.stop();
@@ -745551,7 +745899,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
745551
745899
  toolCalls: sessionToolCallCount,
745552
745900
  source: "manual",
745553
745901
  completed: false,
745554
- model: currentConfig.model
745902
+ model: currentConfig.model,
745903
+ sessionId: getTodoSessionId() || process.env["OMNIUS_SESSION_ID"]
745555
745904
  };
745556
745905
  saveSessionContext(repoRoot, entry);
745557
745906
  return true;
@@ -745560,10 +745909,14 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
745560
745909
  }
745561
745910
  },
745562
745911
  contextRestore() {
745563
- return buildContextRestorePrompt(repoRoot);
745912
+ return buildContextRestoreSnapshot(repoRoot);
745564
745913
  },
745565
745914
  setRestoredContext(ctx3) {
745566
- restoredSessionContext = ctx3;
745915
+ if (typeof ctx3 === "string") {
745916
+ restoredSessionContext = ctx3;
745917
+ } else {
745918
+ applyRestoreSnapshot(ctx3, { replayVisual: true });
745919
+ }
745567
745920
  },
745568
745921
  contextShow() {
745569
745922
  const ctx3 = loadSessionContext(repoRoot);
@@ -745706,28 +746059,30 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
745706
746059
  const auto = countdown <= 0;
745707
746060
  const doRestore = selectResult.confirmed && selectResult.key === "restore";
745708
746061
  if (doRestore) {
745709
- const prompt = buildContextRestorePrompt(repoRoot);
745710
- if (prompt) {
745711
- restoredSessionContext = prompt;
746062
+ const snapshot = buildContextRestoreSnapshot(repoRoot);
746063
+ if (snapshot) {
746064
+ const replayedVisual = applyRestoreSnapshot(snapshot, { replayVisual: true });
745712
746065
  const info = loadSessionContext(repoRoot);
745713
746066
  writeContent(() => {
745714
746067
  renderInfo(
745715
- auto ? `Context auto-restored from ${info?.entries.length ?? 0} session(s).` : `Context restored from ${info?.entries.length ?? 0} session(s).`
746068
+ auto ? `Context auto-restored from ${info?.entries.length ?? 0} session(s)${replayedVisual ? `; replayed ${snapshot.historyLineCount ?? 0} transcript line(s)` : ""}${snapshot.todoCount ? `; restored ${snapshot.todoCount} todo(s)` : ""}.` : `Context restored from ${info?.entries.length ?? 0} session(s)${replayedVisual ? `; replayed ${snapshot.historyLineCount ?? 0} transcript line(s)` : ""}${snapshot.todoCount ? `; restored ${snapshot.todoCount} todo(s)` : ""}.`
745716
746069
  );
745717
- if (statusBar.isActive && !isNeovimActive() && !isOverlayActive()) {
745718
- renderSessionHistoryBox(
745719
- {
745720
- registerDynamicBlock: (id2, render2) => statusBar.registerDynamicBlock(id2, render2),
745721
- appendDynamicBlock: (id2) => statusBar.appendDynamicBlock(id2)
745722
- },
745723
- sessionContextToHistoryBoxData(info, "Session History")
745724
- );
745725
- } else {
745726
- const historyDisplay = formatSessionHistoryDisplay(info);
745727
- process.stdout.write(
745728
- historyDisplay.endsWith("\n") ? historyDisplay : `${historyDisplay}
746070
+ if (!replayedVisual) {
746071
+ if (statusBar.isActive && !isNeovimActive() && !isOverlayActive()) {
746072
+ renderSessionHistoryBox(
746073
+ {
746074
+ registerDynamicBlock: (id2, render2) => statusBar.registerDynamicBlock(id2, render2),
746075
+ appendDynamicBlock: (id2) => statusBar.appendDynamicBlock(id2)
746076
+ },
746077
+ sessionContextToHistoryBoxData(info, "Session History")
746078
+ );
746079
+ } else {
746080
+ const historyDisplay = formatSessionHistoryDisplay(info);
746081
+ process.stdout.write(
746082
+ historyDisplay.endsWith("\n") ? historyDisplay : `${historyDisplay}
745729
746083
  `
745730
- );
746084
+ );
746085
+ }
745731
746086
  }
745732
746087
  });
745733
746088
  } else {
@@ -745787,7 +746142,14 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
745787
746142
  const pendingTask = loadPendingTask(repoRoot);
745788
746143
  if (pendingTask) {
745789
746144
  setTimeout(() => {
745790
- const sessionCtx = buildContextRestorePrompt(repoRoot);
746145
+ const restoreSnapshot = buildContextRestoreSnapshot(repoRoot);
746146
+ if (restoreSnapshot) {
746147
+ applyRestoreSnapshot(restoreSnapshot, {
746148
+ replayVisual: true,
746149
+ injectNextTask: false
746150
+ });
746151
+ }
746152
+ const sessionCtx = restoreSnapshot?.prompt ?? buildContextRestorePrompt(repoRoot);
745791
746153
  const resumeContext = [
745792
746154
  sessionCtx || "",
745793
746155
  `Continuing task after update: ${pendingTask.prompt}`,
@@ -745958,6 +746320,7 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
745958
746320
  const quitMatch = input.trim().replace(/^\//, "").toLowerCase();
745959
746321
  if (quitMatch === "quit" || quitMatch === "exit" || quitMatch === "q") {
745960
746322
  interactiveExiting = true;
746323
+ saveVisualSessionSnapshot("quit");
745961
746324
  if (activeTask) activeTask.runner.abort();
745962
746325
  idleMemoryMaintenance?.stop();
745963
746326
  taskManager.stopAll();
@@ -745975,6 +746338,7 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
745975
746338
  );
745976
746339
  if (cmdResult === "exit") {
745977
746340
  interactiveExiting = true;
746341
+ saveVisualSessionSnapshot("command exit");
745978
746342
  if (activeTask) activeTask.runner.abort();
745979
746343
  idleMemoryMaintenance?.stop();
745980
746344
  taskManager.stopAll();
@@ -746539,6 +746903,7 @@ ${formatTaskCompletionMeta(previousMetaForIntake)}`
746539
746903
  } catch {
746540
746904
  }
746541
746905
  let taskInput = fullInput;
746906
+ let taskSessionId = restoredTaskSessionId;
746542
746907
  if (restoredSessionContext) {
746543
746908
  taskInput = `${restoredSessionContext}
746544
746909
 
@@ -746547,6 +746912,7 @@ ${formatTaskCompletionMeta(previousMetaForIntake)}`
746547
746912
  NEW TASK: ${fullInput}`;
746548
746913
  restoredSessionContext = null;
746549
746914
  }
746915
+ restoredTaskSessionId = null;
746550
746916
  if (taskIntakePacket) {
746551
746917
  taskInput = `${taskIntakePacket}
746552
746918
 
@@ -746595,7 +746961,8 @@ ${taskInput}`;
746595
746961
  handleAskUser,
746596
746962
  selfModifyEnabled,
746597
746963
  sessionMetrics,
746598
- realtimeEnabled
746964
+ realtimeEnabled,
746965
+ taskSessionId
746599
746966
  );
746600
746967
  activeTask = task;
746601
746968
  _recallText = null;
@@ -746834,6 +747201,7 @@ Rationale: ${proposal.rationale}${provenanceNote}${dmnDevDiscipline(proposal.cat
746834
747201
  rl.on("close", () => {
746835
747202
  if (interactiveExiting) return;
746836
747203
  interactiveExiting = true;
747204
+ saveVisualSessionSnapshot("readline close");
746837
747205
  if (peerMesh) {
746838
747206
  peerMesh.stop().catch(() => {
746839
747207
  });
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.463",
3
+ "version": "1.0.464",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.463",
9
+ "version": "1.0.464",
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.463",
3
+ "version": "1.0.464",
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",