@ponythewhite/base-context 1.0.10 → 1.0.12
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/CHANGELOG.md +22 -0
- package/dist/base-context-runtime/pyproject.toml +1 -1
- package/dist/base-context-runtime/uv.lock +1 -1
- package/dist/build-info.json +1 -1
- package/dist/bundle/amazon-bedrock.js +3 -3
- package/dist/bundle/{anthropic-5PSCZEER.js → anthropic-BJVPUMPB.js} +2 -2
- package/dist/bundle/{azure-openai-responses-AYTLJR33.js → azure-openai-responses-ERRMAXK6.js} +4 -5
- package/dist/bundle/{bundled-modules-MX6YNAM2.js → bundled-modules-WCGPZI2H.js} +5 -5
- package/dist/bundle/{chunk-D3KOF57W.js → chunk-25VYRAC6.js} +14 -1
- package/dist/bundle/{chunk-2IPDSTDR.js → chunk-AEMRBMI2.js} +9 -9
- package/dist/bundle/{chunk-Q3MBSBEB.js → chunk-FOGKLC7V.js} +1 -1
- package/dist/bundle/{chunk-UHLGPYMI.js → chunk-IAKHCQA2.js} +185 -39
- package/dist/bundle/{chunk-KT2BNEPE.js → chunk-MUFZODP5.js} +1 -1
- package/dist/bundle/{chunk-QKIFBA7N.js → chunk-Q6UAHLII.js} +2 -2
- package/dist/bundle/{chunk-CDXQNS5P.js → chunk-YGV3Y4AD.js} +1009 -185
- package/dist/bundle/{cli-main-D7W3WWCV.js → cli-main-CTYDQHFE.js} +4 -4
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/{google-HTMCUJ7X.js → google-4GA4YMUX.js} +2 -2
- package/dist/bundle/{google-vertex-ZQO65AXF.js → google-vertex-7AMALD7D.js} +2 -2
- package/dist/bundle/{main-5J3QBZ5Y.js → main-GVGK354K.js} +5 -5
- package/dist/bundle/{mistral-SB7LU56G.js → mistral-74BXMNRM.js} +1 -1
- package/dist/bundle/{openai-codex-responses-5CEW4VN3.js → openai-codex-responses-COXNC4IH.js} +2 -2
- package/dist/bundle/{openai-completions-BAZJQSS2.js → openai-completions-BCSA5Q6S.js} +2 -2
- package/dist/bundle/{openai-responses-VHOE427P.js → openai-responses-ONCIZSJS.js} +3 -3
- package/dist/core/agent-session.d.ts +6 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +445 -146
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/canonical-context.d.ts +19 -3
- package/dist/core/canonical-context.d.ts.map +1 -1
- package/dist/core/canonical-context.js +130 -9
- package/dist/core/canonical-context.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +9 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +29 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context-epoch-copy.d.ts +1 -1
- package/dist/core/context-epoch-copy.d.ts.map +1 -1
- package/dist/core/context-epoch-copy.js +18 -7
- package/dist/core/context-epoch-copy.js.map +1 -1
- package/dist/core/context-epoch.d.ts +4 -0
- package/dist/core/context-epoch.d.ts.map +1 -1
- package/dist/core/context-epoch.js +8 -1
- package/dist/core/context-epoch.js.map +1 -1
- package/dist/core/context-tree.d.ts +14 -11
- package/dist/core/context-tree.d.ts.map +1 -1
- package/dist/core/context-tree.js +145 -9
- package/dist/core/context-tree.js.map +1 -1
- package/dist/core/history-index-worker.d.ts.map +1 -1
- package/dist/core/history-index-worker.js +59 -6
- package/dist/core/history-index-worker.js.map +1 -1
- package/dist/core/history-index.d.ts +17 -0
- package/dist/core/history-index.d.ts.map +1 -1
- package/dist/core/history-index.js +22 -0
- package/dist/core/history-index.js.map +1 -1
- package/dist/core/inference-coordinator.d.ts +1 -1
- package/dist/core/inference-coordinator.d.ts.map +1 -1
- package/dist/core/inference-coordinator.js +23 -6
- package/dist/core/inference-coordinator.js.map +1 -1
- package/dist/core/messages.d.ts +2 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +2 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/refinement/refinement.d.ts +2 -0
- package/dist/core/refinement/refinement.d.ts.map +1 -1
- package/dist/core/refinement/refinement.js +10 -1
- package/dist/core/refinement/refinement.js.map +1 -1
- package/dist/core/request-usage.d.ts +34 -0
- package/dist/core/request-usage.d.ts.map +1 -0
- package/dist/core/request-usage.js +111 -0
- package/dist/core/request-usage.js.map +1 -0
- package/dist/core/request-view-selection.d.ts +2 -1
- package/dist/core/request-view-selection.d.ts.map +1 -1
- package/dist/core/request-view-selection.js +29 -2
- package/dist/core/request-view-selection.js.map +1 -1
- package/dist/core/session-fork-messages.d.ts +5 -0
- package/dist/core/session-fork-messages.d.ts.map +1 -1
- package/dist/core/session-fork-messages.js +44 -0
- package/dist/core/session-fork-messages.js.map +1 -1
- package/dist/core/session-history-index.d.ts +5 -0
- package/dist/core/session-history-index.d.ts.map +1 -1
- package/dist/core/session-history-index.js +7 -0
- package/dist/core/session-history-index.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +155 -13
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-tree.d.ts +9 -0
- package/dist/core/session-tree.d.ts.map +1 -1
- package/dist/core/session-tree.js +71 -11
- package/dist/core/session-tree.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +7 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts +2 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js +8 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
- package/dist/modes/agent-connection/in-process-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/in-process-agent-connection.js +4 -4
- package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
- package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-mode.js +4 -4
- package/dist/modes/daemon/daemon-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-protocol.d.ts +13 -3
- package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-protocol.js +10 -2
- package/dist/modes/daemon/daemon-protocol.js.map +1 -1
- package/dist/modes/daemon/daemon-session-summarizer.d.ts +3 -0
- package/dist/modes/daemon/daemon-session-summarizer.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-session-summarizer.js +71 -32
- package/dist/modes/daemon/daemon-session-summarizer.js.map +1 -1
- package/dist/modes/interactive/components/context-tree-format.d.ts.map +1 -1
- package/dist/modes/interactive/components/context-tree-format.js +49 -0
- package/dist/modes/interactive/components/context-tree-format.js.map +1 -1
- package/docs/compaction.md +27 -3
- package/docs/context-management.md +17 -1
- package/docs/rlm.md +1 -1
- package/docs/settings.md +12 -0
- package/docs/usage.md +24 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport type { AgentMessage, FinalizedToolExchange, ToolInvocation } from \"@ponythewhite/base-context-agent\";\nimport type {\n\tAssistantMessage,\n\tImageContent,\n\tMessage,\n\tServiceTier,\n\tTextContent,\n\tUsage,\n} from \"@ponythewhite/base-context-ai\";\nimport { randomUUID } from \"crypto\";\nimport { type Dir, existsSync, readdirSync, readFileSync, realpathSync, type Stats, statSync } from \"fs\";\nimport { opendir, open as openFile, stat } from \"fs/promises\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport { getAgentDir as getDefaultAgentDir, getSessionsDir } from \"../config.js\";\nimport { assertProductStatePath } from \"../runtime-paths.js\";\nimport { captureGitContext, type GitContext, gitContextsEqual } from \"../utils/git.js\";\nimport { AGENT_RESULT_CUSTOM_TYPE, type AgentResultData } from \"./agent-results.js\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport type { CanonicalPayloadFragment } from \"./canonical-payload-parts.js\";\nimport { takeCompactionRequestOutputs } from \"./compaction/compaction.js\";\nimport {\n\tappendContextEpoch,\n\tCONTEXT_EPOCH_DETAIL,\n\ttype ContextEpochCheckpoint,\n\ttype ContextEpochSummary,\n} from \"./context-epoch.js\";\nimport {\n\ttype CapturedEpochCopy,\n\ttype CopiedEpochEntry,\n\tcaptureEpochCopyEntry,\n\treadCopiedEpochSource,\n\trebuildCopiedContextEpoch,\n} from \"./context-epoch-copy.js\";\nimport { GOAL_STATE_CUSTOM_TYPE } from \"./goals.js\";\nimport type {\n\tContextManifestOptions,\n\tContextManifestPage,\n\tHistoryIndexPage,\n\tHistoryPayloadReadOptions,\n\tIndexedSourceEvent,\n\tTaskEvidenceOptions,\n\tTaskEvidencePage,\n} from \"./history-index.js\";\nimport { HistoryIndex, HistoryIndexUnsupportedError } from \"./history-index.js\";\nimport {\n\tdecodeJournalFrame,\n\tencodeJournalFrame,\n\tINITIAL_JOURNAL_CURSOR,\n\ttype JournalFrameRetention,\n\ttype NativeEntryQualification,\n} from \"./journal-frame.js\";\nimport {\n\ttype BashExecutionMessage,\n\tCOMPACTION_OUTCOME_CUSTOM_TYPE,\n\ttype CustomMessage,\n\tcreateCompactionSummaryMessage,\n} from \"./messages.js\";\nimport type {\n\tContextEpochEntryRef,\n\tNativeBranchRequestOutputSource,\n\tNativeCompactionRequestOutputAssociation,\n\tNativePlannerRequestOutputSource,\n\tNativeRequestEvent,\n\tNativeRequestOutputAssociation,\n\tNativeRequestOutputSource,\n\tSourceSnapshotRef,\n} from \"./request-events.js\";\nimport {\n\tSELECTED_SKILL_CUSTOM_TYPE,\n\tSELECTED_SKILL_DETAIL,\n\tselectedSkillBlock,\n\tselectedSkillCapture,\n} from \"./selected-skills.js\";\nimport { DEFAULT_NATIVE_RECOVERY_LIMITS } from \"./selective-recovery.js\";\nimport { orderContextToolResults, sessionEntryMessage } from \"./session-context-messages.js\";\nimport {\n\tIPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY,\n\ttype PersistedIpythonSentAgentMessage,\n\tparsePersistedIpythonSentAgentMessage,\n} from \"./session-context-updates.js\";\nimport { bindNativeEntryWriter, type NativeEntryOrigin, type NativeEntryWriter } from \"./session-entry-origin.js\";\nimport {\n\ttype BoundHistoryReadSink,\n\ttype BoundSessionRequestSink,\n\tcreateBranchHistoryReadView,\n\tcreateSessionHistoryReadScope,\n\ttype HistoryReadQuery,\n\ttype HydratedSessionHistoryEntry,\n\thydrateCapturedHistoryEntry,\n\ttype MaterializedSessionHistory,\n\tSessionHistoryIndex,\n\ttype SessionHistoryReadLimits,\n\ttype SessionHistoryReadScope,\n\ttype SessionHistoryReadView,\n} from \"./session-history-index.js\";\nimport {\n\tappendCappedSearchText,\n\textractOversizedMessageSummary,\n\textractTextContent,\n\tgetSessionModifiedDateFromLastActivity,\n\tisMessageWithContent,\n\tlooksLikeMessageEntry,\n\tnormalizeSessionStateStatus,\n\tSESSION_LIST_PARSE_MAX_LINE_CHARS,\n\tupdateLastActivityTime,\n} from \"./session-info-projection.js\";\nimport {\n\tAPPEND_NATIVE_ADMISSION,\n\tAPPEND_NATIVE_CONTEXT_EPOCH,\n\tAPPEND_NATIVE_RECOVERY,\n\tAPPEND_NATIVE_TOOL_EXECUTION,\n\tSESSION_JOURNAL_MAX_RECORD_BYTES as MAX_SESSION_RECORD_BYTES,\n\tSESSION_JOURNAL_MAX_FRAME_BYTES,\n\tSessionJournalOwner,\n\ttype SessionJournalState,\n} from \"./session-journal-owner.js\";\nimport {\n\treadCapturedSessionJournal,\n\treadSessionCatalogHeader,\n\treadSessionJournal,\n\treadSessionJournalHeader,\n\tSessionJournalDecoder,\n} from \"./session-journal-reader.js\";\nimport { readTaskStateFromHistory, type TaskStateView } from \"./task-state-reader.js\";\nimport { type TaskStateReadLimits, taskStateReadLimits } from \"./task-state-reducer.js\";\nimport {\n\taddAssistantUsage,\n\tcloneUsage,\n\temptyUsage,\n\ttype SessionUsageSummary,\n\tsessionUsageSummaryFrom,\n\tsubtractAssistantUsage,\n} from \"./usage.js\";\n\nexport const CURRENT_SESSION_VERSION = 3;\nconst SESSION_ASYNC_PARSE_YIELD_BYTES = 4 * 1024 * 1024;\n\n// These records advance the journal leaf without changing the captured compaction input.\nconst COMPACTION_BOOKKEEPING_ENTRY_TYPES = new Set<SessionEntry[\"type\"]>([\n\t\"session_state\",\n\t\"agent_status\",\n\t\"git_state\",\n\t\"child_usage_attributed\",\n]);\n\nfunction isCompactionBookkeeping(entry: SessionEntry): boolean {\n\treturn (\n\t\tCOMPACTION_BOOKKEEPING_ENTRY_TYPES.has(entry.type) ||\n\t\t(entry.type === \"custom_message\" && entry.customType === COMPACTION_OUTCOME_CUSTOM_TYPE)\n\t);\n}\n\n// Entry types that can represent user intent (vs. daemon bookkeeping like\n// session_state/agent_status/git_state/child_usage_attributed). Used by\n// hasUserContent to decide whether a message-less draft is safe to discard.\nconst CONTENT_ENTRY_TYPES = new Set([\n\t\"message\",\n\t\"custom_message\",\n\t\"custom\",\n\t\"model_change\",\n\t\"thinking_level_change\",\n\t\"service_tier_change\",\n\t\"session_info\",\n\t\"label\",\n\t\"compaction\",\n\t\"branch_summary\",\n\t// Effect/accounting facts must not disappear with a message-less draft.\n\t\"tool_intent\",\n\t\"request\",\n]);\n\nfunction realpathIfPresent(path: string): string {\n\ttry {\n\t\treturn realpathSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return path;\n\t\tthrow error;\n\t}\n}\n\n// Only actual manager-created source objects enter this private binding. Payloads and callbacks cannot brand a sink.\ntype NativeOutputCapture = (association: NativeRequestOutputAssociation) => NativeRequestOutputAssociation | undefined;\ninterface NativeOutputSource {\n\tcapture: NativeOutputCapture;\n\tmain: NativeRequestOutputSource;\n\tbranch: NativeBranchRequestOutputSource;\n\tplanner: NativePlannerRequestOutputSource;\n\tcompaction?: true;\n}\nconst nativeRequestOutputSources = new WeakMap<object, NativeOutputSource>();\n\n/** Internal main-stream capture; the factory closes over its original manager/writer before any waits. */\nexport function captureNativeRequestOutputSource(sink: object): NativeRequestOutputSource | undefined {\n\treturn nativeRequestOutputSources.get(sink)?.main;\n}\n\n/** Only the actual bound compaction wrapper, not a described or generic request sink. */\nexport function captureNativeCompactionOutputSource(sink: object): NativeOutputCapture | undefined {\n\tconst source = nativeRequestOutputSources.get(sink);\n\treturn source?.compaction ? source.capture : undefined;\n}\n\n/** Genuine writer ownership only; native branch invocation eligibility belongs to its captured coordinator. */\nexport function captureNativeBranchOutputSource(sink: object): NativeBranchRequestOutputSource | undefined {\n\treturn nativeRequestOutputSources.get(sink)?.branch;\n}\n\n/** Original writer ownership; native planner invocation eligibility is held by its captured coordinator. */\nexport function captureNativePlannerOutputSource(sink: object): NativePlannerRequestOutputSource | undefined {\n\treturn nativeRequestOutputSources.get(sink)?.planner;\n}\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tversion?: number; // v1 sessions don't have this\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n\trlmDepth?: number;\n\tgit?: GitContext;\n}\n\n/** One captured branch for summary input, physical requests, and the queued compaction commit. */\nexport interface BoundCompactionSink extends BoundSessionRequestSink {\n\t/** Original ownership and compaction input, including this sink's own acknowledged checkpoint. */\n\tisCurrent(): boolean;\n\t/** Internal explicit-copy read on this same held source, never a provider-view capability. */\n\t[readCopiedEpochSource]<T>(read: (history: SessionHistoryReadScope) => Promise<T>): Promise<T>;\n\treadBranch(): Promise<SessionEntry[]>;\n\t[appendContextEpoch](\n\t\tcheckpoint: ContextEpochCheckpoint,\n\t\ttokensBefore: number | null,\n\t\tsummary?: ContextEpochSummary,\n\t\trequestOutputSource?: object,\n\t): Promise<string>;\n\tappendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number | null,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t\tcustomInstructions?: string,\n\t\tusage?: Usage,\n\t\trequestOutputSource?: object,\n\t): Promise<string>;\n}\n\nexport interface NewSessionOptions {\n\tid?: string;\n\tparentSession?: string;\n\trlmDepth?: number;\n}\n\n/** Source preparation only. No destination is allocated and no activation result is predicted. */\nexport interface SessionImportPreview {\n\tsourcePath: string;\n\tsourceFormat: \"legacy-jsonl\" | \"native-framed\";\n\tinputVersion: number;\n\t/** Decoded records after the initial header. */\n\tentriesRead: number;\n\t/** Decoded JSON bytes including the header, not physical file bytes. */\n\tsourceJsonBytes: number;\n\t/** Prepared source entries, excluding the new header and any rebuilt epoch. */\n\tpreparedEntryCount: number;\n\ttargetCwd: string;\n\ttargetDirectory: string;\n\tretention: \"retained-import\";\n\tsourceHeader: \"replace\";\n\tgitState: \"omit-and-relink-parents\";\n\tcapture: \"bounded-prefix-not-live-snapshot\";\n\tdestinationCreated: false;\n\tdestinationCreationAndIndexing: \"not-assessed\";\n\tcanonicalEpochActivation: \"not-assessed\";\n\treferenceReplayCoverage: \"not-assessed\";\n\tlaterImport: \"rereads-source-and-can-fail\";\n}\n\nexport type SessionPersistListener = (sessionFile: string) => void;\n\nexport interface SessionEntryBase {\n\ttype: string;\n\tid: string;\n\tparentId: string | null;\n\ttimestamp: string;\n\t/** Native admission/control metadata, never read from the entry's arbitrary data payload. */\n\tnativeOrigin?: NativeEntryOrigin;\n}\n\nexport type SessionExecutionEvidence = Omit<FinalizedToolExchange, \"result\" | \"originalInput\" | \"executedInput\"> &\n\t({ invocationId: string } | { originalInput: unknown; executedInput?: unknown });\n\nexport interface SessionMessageEntry extends SessionEntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n\t/** Metadata from the original main-request owner; does not grant native input/task authority. */\n\trequestOutput?: NativeRequestOutputAssociation;\n\t/** Native execution evidence belongs to this result, not a second transcript. */\n\texecution?: SessionExecutionEvidence;\n}\n\nexport interface ToolIntentEntry extends SessionEntryBase {\n\ttype: \"tool_intent\";\n\tinvocation: ToolInvocation;\n\t/** Only the qualified original execution owner supplies this acknowledged source. */\n\tassistant?: ContextEpochEntryRef & { sessionFile: string | undefined };\n}\n\nexport interface RequestJournalEntry extends SessionEntryBase {\n\ttype: \"request\";\n\trequest: NativeRequestEvent;\n}\n\ntype PrivateSessionEntry = ToolIntentEntry | RequestJournalEntry;\n\ntype AssistantSessionMessageEntry = SessionMessageEntry & { message: AssistantMessage };\n\nexport interface ThinkingLevelChangeEntry extends SessionEntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ServiceTierChangeEntry extends SessionEntryBase {\n\ttype: \"service_tier_change\";\n\tserviceTier: ServiceTier;\n}\n\nexport interface ModelChangeEntry extends SessionEntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\t/** Descriptive native projected-output links; not checkpoint/task authority or append ACK. */\n\trequestOutputs?: readonly NativeCompactionRequestOutputAssociation[];\n\tfirstKeptEntryId: string;\n\t/** Prior-context estimate; null when the original context is not measurable. */\n\ttokensBefore: number | null;\n\tdetails?: T;\n\tfromHook?: boolean;\n\tcustomInstructions?: string;\n\tusage?: Usage;\n}\n\nexport interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"branch_summary\";\n\t/** Descriptive built-in projected-output link, not native task authority, append ACK or caller delivery. */\n\trequestOutput?: NativeRequestOutputAssociation;\n\tfromId: string;\n\tsummary: string;\n\tdetails?: T;\n\tfromHook?: boolean;\n\tusage?: Usage;\n}\n\nexport interface CustomEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom\";\n\t/** Native planner contribution on prime-agent.refinement only; not whole-output, effect or ACK authority. */\n\tplannerRequest?: NativeRequestOutputAssociation;\n\tcustomType: string;\n\tdata?: T;\n}\n\n/**\n * Records usage folded into a parent assistant message after an RLM child run.\n * The child usage is kept separately so audit/UI code can explain why the\n * parent turn's aggregate usage exceeds the parent model response itself.\n */\nexport interface ChildUsageAttributionEntry extends SessionEntryBase {\n\ttype: \"child_usage_attributed\";\n\ttargetId: string;\n\tchildUsage: Usage;\n\taggregateUsage: Usage;\n\torigin?: \"spawn_task\" | \"agent_message\" | \"direct_user\";\n}\n\ninterface CapturedForkInput {\n\tsource?: SourceSnapshotRef;\n\tepochCopy?: CapturedEpochCopy;\n\tleafId?: string | null;\n\tselectedEntry?: SessionEntry;\n\tpath: SessionEntry[];\n\tlabels: {\n\t\ttargetId: string;\n\t\tlabel: string;\n\t\ttimestamp: string;\n\t\tretention?: JournalFrameRetention;\n\t\tqualification?: NativeEntryQualification;\n\t}[];\n\tsourceFile?: string;\n\tcwd: string;\n\tsessionDir: string;\n\tpersist: boolean;\n\trlmDepth: number | undefined;\n\tlimits: SessionHistoryReadLimits;\n}\n\nexport interface PreparedSessionFork {\n\t/** Present only for an owned canonical capture. */\n\tsource?: SourceSnapshotRef;\n\tselectedEntry: SessionEntry;\n\tcreate(): Promise<SessionManager>;\n}\n\nexport interface ChildUsageAttributionAcknowledgement {\n\tentryId: string;\n\taggregateUsage: Usage;\n}\n\nexport interface LabelEntry extends SessionEntryBase {\n\ttype: \"label\";\n\ttargetId: string;\n\tlabel: string | undefined;\n}\n\nexport interface SessionInfoEntry extends SessionEntryBase {\n\ttype: \"session_info\";\n\tname?: string;\n}\n\nexport type SessionStateStatus = \"active\" | \"archived\" | \"crash\";\n\nexport interface SessionState {\n\tstatus: SessionStateStatus;\n}\n\nexport interface SessionStateEntry extends SessionEntryBase {\n\ttype: \"session_state\";\n\tstate: SessionState;\n}\n\nexport type AgentTaskState = \"needs_input\" | \"completed\";\n\nexport interface AgentStatus {\n\tsummary: string;\n\ttaskState?: AgentTaskState;\n\tbasedOnMessageCount: number;\n}\n\nexport interface AgentStatusEntry extends SessionEntryBase {\n\ttype: \"agent_status\";\n\tstatus: AgentStatus;\n}\n\nexport interface GitStateEntry extends SessionEntryBase {\n\ttype: \"git_state\";\n\tgit: GitContext;\n}\n\nexport interface CustomMessageEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom_message\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdetails?: T;\n\tdisplay: boolean;\n}\n\nexport type SessionEntry =\n\t| SessionMessageEntry\n\t| ToolIntentEntry\n\t| RequestJournalEntry\n\t| ThinkingLevelChangeEntry\n\t| ServiceTierChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry\n\t| ChildUsageAttributionEntry\n\t| CustomMessageEntry\n\t| LabelEntry\n\t| SessionInfoEntry\n\t| SessionStateEntry\n\t| AgentStatusEntry\n\t| GitStateEntry;\n\nexport type FileEntry = SessionHeader | SessionEntry;\n\nexport interface SessionTreeFlatNode {\n\tentry: Exclude<SessionEntry, PrivateSessionEntry>;\n\tlabel?: string;\n\tlabelTimestamp?: string;\n}\n\nexport interface SessionTreeNode extends SessionTreeFlatNode {\n\tchildren: SessionTreeNode[];\n}\n\nexport interface ResidentSessionHistory {\n\theader: SessionHeader | null;\n\tentries: SessionEntry[];\n\t/** Per-row source controls, outside the unchanged entry payloads. */\n\tretentions: (JournalFrameRetention | null)[];\n\tqualifications: (NativeEntryQualification | null)[];\n\tleafId: string | null;\n\t/** Serialized header/entry JSON bytes, not physical frame bytes or heap size. */\n\tsourceBytes: number;\n}\n\nexport interface SessionContext {\n\tmessages: AgentMessage[];\n\tthinkingLevel: string;\n\tserviceTier: ServiceTier;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport interface SessionInfo {\n\tpath: string;\n\tid: string;\n\tcwd: string;\n\tname?: string;\n\tstate?: SessionState;\n\tparentSessionPath?: string;\n\trlmDepth: number;\n\tcreated: Date;\n\tmodified: Date;\n\tmessageCount: number;\n\tfirstMessage: string;\n\tallMessagesText: string;\n\tagentStatus?: AgentStatus;\n\tusage?: SessionUsageSummary;\n}\n\nexport type ReadonlySessionManager = Pick<\n\tSessionManager,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionFile\"\n\t| \"getLeafId\"\n\t| \"readEntry\"\n\t| \"readLeafEntry\"\n\t| \"readEntryRetention\"\n\t| \"readLabel\"\n\t| \"readBranch\"\n\t| \"readBranches\"\n\t| \"readEntries\"\n\t| \"readFlatTree\"\n\t| \"readTree\"\n\t| \"readToolExchange\"\n\t| \"supportsCapturedHistoryReads\"\n\t| \"materializeResidentHistory\"\n\t| \"readBranchHistory\"\n\t| \"readSourceHistory\"\n\t| \"materializeParentPathHistory\"\n\t| \"materializeBranchHistory\"\n\t| \"materializeSourceHistory\"\n\t| \"getHeader\"\n\t| \"getCompactionCount\"\n\t| \"getSessionName\"\n>;\n\nfunction createSessionId(): string {\n\treturn uuidv7();\n}\n\nfunction getSessionFilePath(sessionDir: string, sessionId: string): string {\n\treturn join(sessionDir, `${sessionId}.jsonl`);\n}\n\nfunction createUniqueSessionFileTarget(sessionDir: string): { sessionId: string; sessionFile: string } {\n\tfor (let i = 0; i < 100; i++) {\n\t\tconst sessionId = createSessionId();\n\t\tconst sessionFile = getSessionFilePath(sessionDir, sessionId);\n\t\tif (!existsSync(sessionFile)) {\n\t\t\treturn { sessionId, sessionFile };\n\t\t}\n\t}\n\tthrow new Error(\"Unable to create a unique session file\");\n}\n\nexport function getSessionArtifactsRoot(sessionDir: string): string {\n\treturn join(dirname(sessionDir), \"session-artifacts\");\n}\n\nexport function getSessionArtifactPath(sessionDir: string, sessionId: string): string {\n\treturn join(getSessionArtifactsRoot(sessionDir), sessionId);\n}\n\nexport function getSessionArtifactPathForFile(sessionFile: string, sessionId?: string): string {\n\treturn getSessionArtifactPath(dirname(sessionFile), sessionId ?? basename(sessionFile).replace(/\\.jsonl$/, \"\"));\n}\n\nfunction generateId(byId: { has(id: string): boolean }): string {\n\tfor (let i = 0; i < 100; i++) {\n\t\tconst id = randomUUID().slice(0, 8);\n\t\tif (!byId.has(id)) return id;\n\t}\n\treturn randomUUID();\n}\n\nfunction migrateV1ToV2(entries: FileEntry[]): void {\n\tconst ids = new Set<string>();\n\tlet prevId: string | null = null;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tentry.version = 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\tentry.id = generateId(ids);\n\t\tentry.parentId = prevId;\n\t\tprevId = entry.id;\n\n\t\tif (entry.type === \"compaction\") {\n\t\t\tconst comp = entry as CompactionEntry & { firstKeptEntryIndex?: number };\n\t\t\tif (typeof comp.firstKeptEntryIndex === \"number\") {\n\t\t\t\tconst targetEntry = entries[comp.firstKeptEntryIndex];\n\t\t\t\tif (targetEntry && targetEntry.type !== \"session\") {\n\t\t\t\t\tcomp.firstKeptEntryId = targetEntry.id;\n\t\t\t\t}\n\t\t\t\tdelete comp.firstKeptEntryIndex;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction migrateV2ToV3(entries: FileEntry[]): void {\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tentry.version = 3;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (entry.type === \"message\") {\n\t\t\tconst msgEntry = entry as SessionMessageEntry;\n\t\t\tif (msgEntry.message && (msgEntry.message as { role: string }).role === \"hookMessage\") {\n\t\t\t\t(msgEntry.message as { role: string }).role = \"custom\";\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction migrateToCurrentVersion(entries: FileEntry[]): boolean {\n\tconst header = entries.find((e) => e.type === \"session\") as SessionHeader | undefined;\n\tconst version = header?.version ?? 1;\n\n\tif (version >= CURRENT_SESSION_VERSION) return false;\n\n\tif (version < 2) migrateV1ToV2(entries);\n\tif (version < 3) migrateV2ToV3(entries);\n\n\treturn true;\n}\n\nexport function migrateSessionEntries(entries: FileEntry[]): void {\n\tmigrateToCurrentVersion(entries);\n}\n\nexport function parseSessionEntries(content: string): FileEntry[] {\n\treturn finalizeLoadedEntries(parseEntriesFromBuffer(Buffer.from(content)));\n}\n\nexport function applyChildUsageAttributions(entries: FileEntry[]): void {\n\tconst assistantEntriesById = new Map<string, AssistantSessionMessageEntry>();\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tassistantEntriesById.set(entry.id, entry as AssistantSessionMessageEntry);\n\t\t}\n\t}\n\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"child_usage_attributed\") continue;\n\t\tconst target = assistantEntriesById.get(entry.targetId);\n\t\tif (!target) continue;\n\t\ttarget.message.usage = cloneUsage(entry.aggregateUsage);\n\t}\n}\n\nexport function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\treturn entries[i] as CompactionEntry;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function buildSessionContext(\n\tentries: SessionEntry[],\n\tleafId?: string | null,\n\tbyId?: Map<string, SessionEntry>,\n): SessionContext {\n\tif (!byId) {\n\t\tbyId = new Map<string, SessionEntry>();\n\t\tfor (const entry of entries) {\n\t\t\tbyId.set(entry.id, entry);\n\t\t}\n\t}\n\n\tlet leaf: SessionEntry | undefined;\n\tif (leafId === null) {\n\t\treturn { messages: [], thinkingLevel: \"off\", serviceTier: \"default\", model: null };\n\t}\n\tif (leafId) {\n\t\tleaf = byId.get(leafId);\n\t}\n\tif (!leaf) {\n\t\tleaf = entries[entries.length - 1];\n\t}\n\n\tif (!leaf) {\n\t\treturn { messages: [], thinkingLevel: \"off\", serviceTier: \"default\", model: null };\n\t}\n\n\t// push+reverse, not unshift-per-entry: unshift is O(n), making this O(n^2) on long sessions.\n\tconst path: SessionEntry[] = [];\n\tlet current: SessionEntry | undefined = leaf;\n\twhile (current) {\n\t\tpath.push(current);\n\t\tcurrent = current.parentId ? byId.get(current.parentId) : undefined;\n\t}\n\tpath.reverse();\n\n\tlet thinkingLevel = \"off\";\n\tlet serviceTier: ServiceTier = \"default\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\tlet compaction: CompactionEntry | null = null;\n\n\tfor (const entry of path) {\n\t\tif (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"service_tier_change\") {\n\t\t\tserviceTier = entry.serviceTier;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tmodel = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t} else if (entry.type === \"compaction\") {\n\t\t\tcompaction = entry;\n\t\t}\n\t}\n\n\t// Build messages and collect corresponding entries\n\t// When there's a compaction, model context remains summary-first while the\n\t// summary records where clients should present it among retained messages.\n\tconst messages: AgentMessage[] = [];\n\n\tconst appendMessage = (entry: SessionEntry, target = messages) => {\n\t\tconst message = sessionEntryMessage(entry);\n\t\tif (message) target.push(message);\n\t};\n\n\tif (compaction) {\n\t\tconst compactionIdx = path.findIndex((e) => e.type === \"compaction\" && e.id === compaction.id);\n\n\t\t// Collect kept messages (before compaction, starting from firstKeptEntryId).\n\t\t// The context remains summary-first for the model; retainedMessageCount records\n\t\t// the exact chronological presentation boundary for clients.\n\t\tconst retainedMessages: AgentMessage[] = [];\n\t\tlet foundFirstKept = false;\n\t\tfor (let i = 0; i < compactionIdx; i++) {\n\t\t\tconst entry = path[i];\n\t\t\tif (entry.id === compaction.firstKeptEntryId) {\n\t\t\t\tfoundFirstKept = true;\n\t\t\t}\n\t\t\tif (foundFirstKept) {\n\t\t\t\tappendMessage(entry, retainedMessages);\n\t\t\t}\n\t\t}\n\n\t\tmessages.push(\n\t\t\tcreateCompactionSummaryMessage(\n\t\t\t\tcompaction.summary,\n\t\t\t\tcompaction.tokensBefore,\n\t\t\t\tcompaction.timestamp,\n\t\t\t\tcompaction.customInstructions,\n\t\t\t\tretainedMessages.length,\n\t\t\t),\n\t\t\t...retainedMessages,\n\t\t);\n\n\t\tfor (let i = compactionIdx + 1; i < path.length; i++) {\n\t\t\tconst entry = path[i];\n\t\t\tappendMessage(entry);\n\t\t}\n\t} else {\n\t\tfor (const entry of path) {\n\t\t\tappendMessage(entry);\n\t\t}\n\t}\n\n\torderContextToolResults(messages);\n\treturn { messages, thinkingLevel, serviceTier, model };\n}\n\nexport function getDefaultSessionDir(_cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\treturn getSessionsDir(agentDir);\n}\n\n// Actual reader/import control metadata, never a field in the entry payload.\nconst entryRetentions = new WeakMap<FileEntry, JournalFrameRetention>();\nconst entryQualifications = new WeakMap<FileEntry, NativeEntryQualification>();\n\nfunction withEntryRetention<T extends FileEntry>(\n\tentry: T,\n\tretention?: JournalFrameRetention,\n\tqualification?: NativeEntryQualification,\n): T {\n\tif (retention !== undefined) entryRetentions.set(entry, retention);\n\tif (qualification !== undefined) entryQualifications.set(entry, qualification);\n\treturn entry;\n}\n\nfunction sessionFileEntry(\n\tvalue: unknown,\n\tretention?: JournalFrameRetention,\n\tqualification?: NativeEntryQualification,\n): FileEntry {\n\tif (!value || typeof value !== \"object\" || !(\"type\" in value) || typeof value.type !== \"string\")\n\t\tthrow new Error(\"Invalid session journal entry\");\n\treturn withEntryRetention(value as FileEntry, retention, qualification);\n}\n\nfunction appendSourceEntry(owner: SessionJournalOwner, json: string, entry: FileEntry): Promise<{ sequence: number }> {\n\tconst qualification = entryQualifications.get(entry);\n\tif (qualification === \"native-admission\") return owner[APPEND_NATIVE_ADMISSION](json, entryRetentions.get(entry));\n\tif (qualification === \"native-recovery\") return owner[APPEND_NATIVE_RECOVERY](json, entryRetentions.get(entry));\n\tif (qualification === \"native-context-epoch\")\n\t\treturn owner[APPEND_NATIVE_CONTEXT_EPOCH](json, entryRetentions.get(entry));\n\tif (qualification === \"native-tool-execution\")\n\t\treturn owner[APPEND_NATIVE_TOOL_EXECUTION](json, entryRetentions.get(entry));\n\treturn owner.appendJson(json, entryRetentions.get(entry));\n}\n\nfunction parseEntriesFromBuffer(buffer: Buffer): FileEntry[] {\n\tconst decoder = new SessionJournalDecoder();\n\tconst entries: FileEntry[] = [];\n\tlet start = 0;\n\twhile (start < buffer.length) {\n\t\tconst end = buffer.indexOf(0x0a, start);\n\t\tif (end === -1) break; // Only exclusive recovery may change an incomplete tail.\n\t\tconst record = decoder.decode(buffer.subarray(start, end + 1));\n\t\tif (record) entries.push(sessionFileEntry(record.entry, record.retention, record.qualification));\n\t\tstart = end + 1;\n\t}\n\treturn entries;\n}\n\nfunction finalizeLoadedEntries(entries: FileEntry[]): FileEntry[] {\n\tif (entries.length === 0) return entries;\n\tconst header = entries[0];\n\tif (header.type !== \"session\" || typeof header.id !== \"string\")\n\t\tthrow new Error(\"Session source has no valid header\");\n\tapplyChildUsageAttributions(entries);\n\treturn entries;\n}\n\nexport function loadEntriesFromFile(filePath: string): FileEntry[] {\n\tif (!existsSync(filePath)) return [];\n\treturn finalizeLoadedEntries(parseEntriesFromBuffer(readFileSync(filePath)));\n}\n\nexport async function loadEntriesFromFileAsync(\n\tfilePath: string,\n\t_options: { streamThresholdBytes?: number } = {},\n): Promise<FileEntry[]> {\n\tif (!existsSync(filePath)) return [];\n\tconst entries: FileEntry[] = [];\n\tlet bytesSinceYield = 0;\n\tfor await (const record of readSessionJournal(filePath)) {\n\t\tentries.push(sessionFileEntry(record.entry, record.retention, record.qualification));\n\t\tbytesSinceYield += Buffer.byteLength(record.json);\n\t\tif (bytesSinceYield >= SESSION_ASYNC_PARSE_YIELD_BYTES) {\n\t\t\tbytesSinceYield = 0;\n\t\t\tawait new Promise<void>((resolve) => setImmediate(resolve));\n\t\t}\n\t}\n\treturn finalizeLoadedEntries(entries);\n}\n\nfunction readSessionHeader(filePath: string): Partial<SessionHeader> | undefined {\n\treturn readSessionJournalHeader(filePath) as Partial<SessionHeader> | undefined;\n}\n\nfunction isValidRlmDepth(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nexport function resolveSessionRlmDepth(\n\theader: { rlmDepth?: number; parentSession?: string },\n\tsessionPath: string,\n): number {\n\treturn resolveLegacySessionRlmDepth(header, sessionPath, new Set()) ?? legacyChildDepthFromPath(sessionPath);\n}\n\nfunction resolveLegacySessionRlmDepth(\n\theader: { rlmDepth?: number; parentSession?: string },\n\tsessionPath: string,\n\tvisitedPaths: Set<string>,\n): number | undefined {\n\tif (isValidRlmDepth(header.rlmDepth)) {\n\t\treturn header.rlmDepth;\n\t}\n\tif (!header.parentSession) {\n\t\treturn 0;\n\t}\n\n\tconst resolvedSessionPath = resolve(sessionPath);\n\tif (visitedPaths.has(resolvedSessionPath)) {\n\t\treturn undefined;\n\t}\n\tvisitedPaths.add(resolvedSessionPath);\n\n\tconst pathDepth = legacyChildDepthFromPath(sessionPath);\n\tconst parentSessionPath = resolve(dirname(sessionPath), header.parentSession);\n\ttry {\n\t\tconst parentHeader = readSessionHeader(parentSessionPath);\n\t\tif (parentHeader) {\n\t\t\tconst parentDepth = resolveLegacySessionRlmDepth(parentHeader, parentSessionPath, visitedPaths);\n\t\t\tif (parentDepth !== undefined) {\n\t\t\t\treturn pathDepth > 0 ? parentDepth + 1 : parentDepth;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fall back to artifact ancestry for unavailable or invalid legacy parents.\n\t} finally {\n\t\tvisitedPaths.delete(resolvedSessionPath);\n\t}\n\treturn pathDepth;\n}\n\nfunction legacyChildDepthFromPath(sessionPath: string): number {\n\tlet depth = 0;\n\tfor (const segment of dirname(sessionPath)\n\t\t.split(/[\\\\/]+/)\n\t\t.reverse()) {\n\t\tif (!/^sub-[0-9a-f]{8}$/.test(segment)) {\n\t\t\tbreak;\n\t\t}\n\t\tdepth += 1;\n\t}\n\treturn depth;\n}\n\nfunction deriveChildRlmDepth(parentHeader: Partial<SessionHeader> | undefined): number | undefined {\n\tconst depth = parentHeader?.rlmDepth;\n\treturn isValidRlmDepth(depth) && depth < Number.MAX_SAFE_INTEGER ? depth + 1 : undefined;\n}\n\nfunction rootRlmDepthFromEnv(): number {\n\tconst value = process.env.BASE_CONTEXT_RLM_DEPTH;\n\tif (value === undefined || value === \"\") {\n\t\treturn 0;\n\t}\n\tconst parsed = Number(value);\n\tif (!/^\\d+$/.test(value) || !isValidRlmDepth(parsed)) {\n\t\tthrow new Error(\"BASE_CONTEXT_RLM_DEPTH must be a non-negative integer\");\n\t}\n\treturn parsed;\n}\n\nfunction isValidSessionFile(filePath: string): boolean {\n\ttry {\n\t\tconst header = readSessionHeader(filePath);\n\t\treturn header?.type === \"session\" && typeof header.id === \"string\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction sessionCatalogDirectories(sessionDir: string): string[] {\n\tconst directories = [sessionDir];\n\tif (existsSync(sessionDir)) {\n\t\tfor (const entry of readdirSync(sessionDir, { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory() && /^--.+--$/.test(entry.name)) directories.push(join(sessionDir, entry.name));\n\t\t}\n\t}\n\t// Older default installations also stored direct JSONLs beside the sessions directory.\n\tif (resolve(sessionDir) === resolve(getSessionsDir())) directories.push(getDefaultAgentDir());\n\treturn directories;\n}\n\nfunction sessionCatalogFiles(sessionDir: string): string[] {\n\tconst paths: string[] = [];\n\tfor (const directory of sessionCatalogDirectories(sessionDir)) {\n\t\tif (!existsSync(directory)) continue;\n\t\tfor (const entry of readdirSync(directory)) if (entry.endsWith(\".jsonl\")) paths.push(join(directory, entry));\n\t}\n\treturn paths;\n}\n\n/** Native catalog pages visit the existing directories without an all-paths array. */\nexport async function* iterateSessionCatalogFiles(sessionDir: string): AsyncGenerator<string> {\n\tconst entries = async function* (directory: string) {\n\t\tlet handle: Dir;\n\t\ttry {\n\t\t\thandle = await opendir(directory);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\t\tthrow error;\n\t\t}\n\t\tfor await (const entry of handle) yield entry;\n\t};\n\tfor await (const entry of entries(sessionDir)) if (entry.name.endsWith(\".jsonl\")) yield join(sessionDir, entry.name);\n\t// Match the existing catalog's root-files, project-directories, legacy-files order.\n\tfor await (const entry of entries(sessionDir)) {\n\t\tif (entry.isDirectory() && /^--.+--$/.test(entry.name)) {\n\t\t\tconst directory = join(sessionDir, entry.name);\n\t\t\tfor await (const child of entries(directory))\n\t\t\t\tif (child.name.endsWith(\".jsonl\")) yield join(directory, child.name);\n\t\t}\n\t}\n\tif (resolve(sessionDir) === resolve(getSessionsDir())) {\n\t\tfor await (const entry of entries(getDefaultAgentDir()))\n\t\t\tif (entry.name.endsWith(\".jsonl\")) yield join(getDefaultAgentDir(), entry.name);\n\t}\n}\n\n/** Directory membership only; the existing source reader still decides readability. */\nexport function isSessionCatalogFile(path: string, sessionDir: string): boolean {\n\tconst directory = dirname(resolve(path));\n\tconst root = resolve(sessionDir);\n\treturn (\n\t\tpath.endsWith(\".jsonl\") &&\n\t\t(directory === root ||\n\t\t\t(dirname(directory) === root && /^--.+--$/.test(basename(directory))) ||\n\t\t\t(root === resolve(getSessionsDir()) && directory === resolve(getDefaultAgentDir())))\n\t);\n}\n\nexport function findMostRecentSession(sessionDir: string): string | null {\n\ttry {\n\t\tconst files = sessionCatalogFiles(sessionDir)\n\t\t\t.filter(isValidSessionFile)\n\t\t\t.map((path) => ({ path, mtime: statSync(path).mtime }))\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction normalizeCwd(cwd: string): string {\n\treturn resolve(cwd);\n}\n\nfunction sessionInfoMatchesCwd(session: SessionInfo, cwd: string): boolean {\n\treturn !!session.cwd && normalizeCwd(session.cwd) === normalizeCwd(cwd);\n}\n\nfunction sessionHeaderMatchesCwd(header: Partial<SessionHeader> | undefined, cwd: string): boolean {\n\treturn (\n\t\theader?.type === \"session\" &&\n\t\ttypeof header.id === \"string\" &&\n\t\ttypeof header.cwd === \"string\" &&\n\t\tnormalizeCwd(header.cwd) === normalizeCwd(cwd)\n\t);\n}\n\nexport function findMostRecentSessionForCwd(sessionDir: string, cwd: string): string | null {\n\ttry {\n\t\tconst files = sessionCatalogFiles(sessionDir)\n\t\t\t.map((path) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst header = readSessionHeader(path);\n\t\t\t\t\tif (!sessionHeaderMatchesCwd(header, cwd)) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn { path, mtime: statSync(path).mtime };\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.filter((entry): entry is { path: string; mtime: Date } => entry !== undefined)\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nconst SESSION_INFO_CACHE_MAX_ENTRIES = 256;\nconst SESSION_INFO_CACHE_MAX_BYTES = 4 * 1024 * 1024;\n\ninterface SessionInfoCacheEntry {\n\tdev: number;\n\tino: number;\n\tnativeRevision?: string;\n\tsize: number;\n\tmtimeMs: number;\n\tinfo: SessionInfo | null;\n\tencodedBytes: number;\n}\n\n// Optional derived metadata. Native hits also require current indexed coverage.\n// The byte limit covers encoded key/stat/capture/info data, not process heap.\nconst sessionInfoCache = new Map<string, SessionInfoCacheEntry>();\n\nexport class SessionCatalogReadError extends Error {\n\tconstructor(\n\t\treadonly reason: \"unavailable\" | \"stale\" | \"unsupported\" | \"error\",\n\t\tmessage: string,\n\t\toptions?: ErrorOptions,\n\t) {\n\t\tsuper(`Native session catalog ${reason}: ${message}`, options);\n\t\tthis.name = \"SessionCatalogReadError\";\n\t}\n}\n\nasync function readIndexedSessionInfo(\n\tfilePath: string,\n\tstats: Stats,\n\theader: SessionHeader,\n\theaderChecksum: string,\n\tcached?: SessionInfoCacheEntry,\n): Promise<{ info: SessionInfo; revision: string; cached: boolean }> {\n\tconst source = {\n\t\tjournalPath: realpathIfPresent(resolve(filePath)),\n\t\tdev: stats.dev,\n\t\tino: stats.ino,\n\t\tbyteLength: stats.size,\n\t\theaderChecksum,\n\t};\n\tconst indexPath = join(getSessionArtifactPathForFile(source.journalPath, header.id), \"history.sqlite\");\n\tlet index: HistoryIndex | undefined;\n\tconst outcome = await (async () => {\n\t\ttry {\n\t\t\tawait stat(indexPath);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\")\n\t\t\t\tthrow new SessionCatalogReadError(\"unavailable\", \"The existing history index is missing\");\n\t\t\tthrow error;\n\t\t}\n\t\tindex = await HistoryIndex.open(indexPath, { readOnly: true });\n\t\tconst capturedIndex = index;\n\t\tconst view = await index.readSessionCatalog(header.id, source);\n\t\tif (view.selection !== \"covered\") throw new SessionCatalogReadError(view.selection, view.reason);\n\t\tconst revision = view.frontier.checksum!;\n\t\tconst hit =\n\t\t\t!!cached?.info &&\n\t\t\tcached.nativeRevision === revision &&\n\t\t\tcached.dev === stats.dev &&\n\t\t\tcached.ino === stats.ino &&\n\t\t\tcached.size === stats.size &&\n\t\t\tcached.mtimeMs === stats.mtimeMs;\n\t\tlet info: SessionInfo;\n\t\tif (hit && cached?.info) {\n\t\t\ttry {\n\t\t\t\tinfo = structuredClone(cached.info);\n\t\t\t} catch {\n\t\t\t\tsessionInfoCache.delete(filePath);\n\t\t\t\tinfo = cached.info;\n\t\t\t}\n\t\t\tif (sessionInfoCache.has(filePath)) {\n\t\t\t\tsessionInfoCache.delete(filePath);\n\t\t\t\tsessionInfoCache.set(filePath, cached);\n\t\t\t}\n\t\t} else {\n\t\t\tconst read = async (ref: IndexedSourceEvent | null) =>\n\t\t\t\tref\n\t\t\t\t\t? (\n\t\t\t\t\t\t\tawait hydrateCapturedHistoryEntry(ref, MAX_SESSION_RECORD_BYTES, (id, options) =>\n\t\t\t\t\t\t\t\tcapturedIndex.readSourcePayload(header.id, id, view.frontier.indexedThrough, options),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t).entry\n\t\t\t\t\t: undefined;\n\t\t\tlet firstMessage = \"(no messages)\";\n\t\t\tif (view.projection.firstMessage && \"preview\" in view.projection.firstMessage)\n\t\t\t\tfirstMessage = view.projection.firstMessage.preview;\n\t\t\telse if (view.refs.firstMessage) {\n\t\t\t\tconst entry = await read(view.refs.firstMessage);\n\t\t\t\tif (entry?.type !== \"message\" || entry.message.role !== \"user\" || !isMessageWithContent(entry.message))\n\t\t\t\t\tthrow new Error(\"Indexed catalog first-message reference is invalid\");\n\t\t\t\tfirstMessage = extractTextContent(entry.message) || \"(no messages)\";\n\t\t\t}\n\t\t\tconst named = await read(view.refs.name);\n\t\t\tif (named && named.type !== \"session_info\") throw new Error(\"Indexed catalog name reference is invalid\");\n\t\t\tconst status = await read(view.refs.agentStatus);\n\t\t\tif (status && status.type !== \"agent_status\") throw new Error(\"Indexed catalog status reference is invalid\");\n\t\t\tinfo = {\n\t\t\t\tpath: filePath,\n\t\t\t\tid: header.id,\n\t\t\t\tcwd: typeof header.cwd === \"string\" ? header.cwd : \"\",\n\t\t\t\tname: named?.type === \"session_info\" ? named.name?.trim() || undefined : undefined,\n\t\t\t\tstate: view.projection.state,\n\t\t\t\tparentSessionPath: header.parentSession,\n\t\t\t\trlmDepth: resolveSessionRlmDepth(header, filePath),\n\t\t\t\tcreated: new Date(header.timestamp),\n\t\t\t\tmodified: getSessionModifiedDateFromLastActivity(view.projection.lastActivityTime, header, stats.mtime),\n\t\t\t\tmessageCount: view.projection.messageCount,\n\t\t\t\tfirstMessage,\n\t\t\t\tallMessagesText: view.projection.allMessagesText,\n\t\t\t\tagentStatus: status?.type === \"agent_status\" ? status.status : undefined,\n\t\t\t\tusage: view.projection.usage,\n\t\t\t};\n\t\t}\n\t\t// The same read transaction and descriptor/frontier contract must still be current\n\t\t// after bounded source-part hydration, not merely when the query began.\n\t\tconst final = await index.readSessionCatalog(header.id, source);\n\t\tif (final.selection !== \"covered\") throw new SessionCatalogReadError(final.selection, final.reason);\n\t\treturn { info, revision, cached: hit };\n\t})().then(\n\t\t(value) => ({ ok: true as const, value }),\n\t\t(error: unknown) => ({\n\t\t\tok: false as const,\n\t\t\terror:\n\t\t\t\terror instanceof SessionCatalogReadError\n\t\t\t\t\t? error\n\t\t\t\t\t: error instanceof HistoryIndexUnsupportedError\n\t\t\t\t\t\t? new SessionCatalogReadError(\"unsupported\", error.message, { cause: error })\n\t\t\t\t\t\t: new SessionCatalogReadError(\"error\", `Indexed metadata read failed: ${String(error)}`, {\n\t\t\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\t\t}),\n\t\t}),\n\t);\n\ttry {\n\t\tawait index?.close();\n\t} catch (error) {\n\t\tthrow new SessionCatalogReadError(\n\t\t\t\"error\",\n\t\t\toutcome.ok\n\t\t\t\t? `Index reader close failed: ${String(error)}`\n\t\t\t\t: `Catalog read and close failed: ${String(outcome.error)}; ${String(error)}`,\n\t\t\t{ cause: outcome.ok ? error : new AggregateError([outcome.error, error], \"Catalog read and close failed\") },\n\t\t);\n\t}\n\tif (!outcome.ok) throw outcome.error;\n\treturn outcome.value;\n}\n\nexport async function readSessionInfo(filePath: string): Promise<SessionInfo | null> {\n\tlet stats: Awaited<ReturnType<typeof stat>>;\n\ttry {\n\t\tstats = await stat(filePath);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\" || (error as NodeJS.ErrnoException).code === \"ENOTDIR\")\n\t\t\treturn null;\n\t\tthrow new SessionCatalogReadError(\"error\", `Source metadata stat failed: ${String(error)}`, { cause: error });\n\t}\n\tconst cached = sessionInfoCache.get(filePath);\n\tif (\n\t\tcached &&\n\t\tcached.nativeRevision === undefined &&\n\t\tcached.dev === stats.dev &&\n\t\tcached.ino === stats.ino &&\n\t\tcached.size === stats.size &&\n\t\tcached.mtimeMs === stats.mtimeMs\n\t) {\n\t\ttry {\n\t\t\tconst info = structuredClone(cached.info);\n\t\t\tsessionInfoCache.delete(filePath);\n\t\t\tsessionInfoCache.set(filePath, cached);\n\t\t\treturn info;\n\t\t} catch {\n\t\t\t// Give up cache ownership rather than lose a complete successful result.\n\t\t\tsessionInfoCache.delete(filePath);\n\t\t\treturn cached.info;\n\t\t}\n\t}\n\tlet nativeRevision: string | undefined;\n\tlet info: SessionInfo | null;\n\ttry {\n\t\tconst first = readSessionCatalogHeader(filePath);\n\t\tif (first?.source) {\n\t\t\tconst header = first.entry as SessionHeader;\n\t\t\tif (header?.type !== \"session\" || typeof header.id !== \"string\")\n\t\t\t\tthrow new SessionCatalogReadError(\"unsupported\", \"Native source has no supported session header\");\n\t\t\tconst result = await readIndexedSessionInfo(filePath, stats, header, first.source.revision, cached);\n\t\t\tif (result.cached) return result.info;\n\t\t\tinfo = result.info;\n\t\t\tnativeRevision = result.revision;\n\t\t} else info = first ? await scanSessionInfo(filePath, stats) : null; // Explicitly legacy/invalid-header only.\n\t} catch (error) {\n\t\tif (error instanceof SessionCatalogReadError) throw error;\n\t\tthrow new SessionCatalogReadError(\"error\", `Source header read failed: ${String(error)}`, { cause: error });\n\t}\n\tsessionInfoCache.delete(filePath);\n\ttry {\n\t\tconst encoded = stringifyBoundedJson(\n\t\t\t{\n\t\t\t\tfilePath,\n\t\t\t\tsize: stats.size,\n\t\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\t\tdev: stats.dev,\n\t\t\t\tino: stats.ino,\n\t\t\t\tnativeRevision,\n\t\t\t\tinfo:\n\t\t\t\t\tinfo === null\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\t\tcreated: info.created.toISOString(),\n\t\t\t\t\t\t\t\tmodified: info.modified.toISOString(),\n\t\t\t\t\t\t\t},\n\t\t\t},\n\t\t\tSESSION_INFO_CACHE_MAX_BYTES,\n\t\t);\n\t\tconst entry: SessionInfoCacheEntry = {\n\t\t\tsize: stats.size,\n\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\tdev: stats.dev,\n\t\t\tino: stats.ino,\n\t\t\tnativeRevision,\n\t\t\tinfo: structuredClone(info),\n\t\t\tencodedBytes: Buffer.byteLength(encoded),\n\t\t};\n\t\tlet retainedBytes = 0;\n\t\tfor (const retained of sessionInfoCache.values()) retainedBytes += retained.encodedBytes;\n\t\twhile (\n\t\t\tsessionInfoCache.size >= SESSION_INFO_CACHE_MAX_ENTRIES ||\n\t\t\tretainedBytes + entry.encodedBytes > SESSION_INFO_CACHE_MAX_BYTES\n\t\t) {\n\t\t\tconst oldest = sessionInfoCache.entries().next().value;\n\t\t\tif (!oldest) return info;\n\t\t\tsessionInfoCache.delete(oldest[0]);\n\t\t\tretainedBytes -= oldest[1].encodedBytes;\n\t\t}\n\t\tsessionInfoCache.set(filePath, entry);\n\t} catch {\n\t\t// Cache admission is optional. Return the complete successful result unchanged.\n\t}\n\treturn info;\n}\n\nasync function scanSessionInfo(filePath: string, stats: Awaited<ReturnType<typeof stat>>): Promise<SessionInfo | null> {\n\ttry {\n\t\tlet header: SessionHeader | undefined;\n\t\tlet messageCount = 0;\n\t\tlet firstMessage = \"\";\n\t\tlet allMessagesText = \"\";\n\t\tlet name: string | undefined;\n\t\tlet state: SessionState | undefined;\n\t\tlet agentStatus: AgentStatus | undefined;\n\t\tlet lastActivityTime: number | undefined;\n\t\t// Fold attribution aggregates like the loader: either disk representation cancels to the same own spend.\n\t\tconst assistantUsageById = new Map<string, Usage>();\n\t\tconst attributedChildUsages: Usage[] = [];\n\t\tconst summarizationUsages: Usage[] = [];\n\n\t\tfor await (const record of readSessionJournal(filePath)) {\n\t\t\tconst line = record.json;\n\n\t\t\t// Large tool-result entries can be many MB. They do not carry the\n\t\t\t// session-list metadata we need, and parsing them during every refresh\n\t\t\t// can exhaust the daemon heap.\n\t\t\tif (line.length > SESSION_LIST_PARSE_MAX_LINE_CHARS) {\n\t\t\t\tif (looksLikeMessageEntry(line)) {\n\t\t\t\t\tmessageCount++;\n\t\t\t\t\tconst summary = extractOversizedMessageSummary(line);\n\t\t\t\t\tif (typeof summary.timestamp === \"number\" && (summary.role === \"user\" || summary.role === \"assistant\")) {\n\t\t\t\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, summary.timestamp);\n\t\t\t\t\t}\n\t\t\t\t\tif (summary.role === \"user\" && !firstMessage) {\n\t\t\t\t\t\tfirstMessage = summary.textPreview || \"(large message)\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst entry = sessionFileEntry(record.entry, record.retention, record.qualification);\n\n\t\t\tif (entry.type === \"session_info\") {\n\t\t\t\tconst infoEntry = entry as SessionInfoEntry;\n\t\t\t\tname = infoEntry.name?.trim() || undefined;\n\t\t\t}\n\t\t\tif (entry.type === \"session_state\") {\n\t\t\t\tconst stateEntry = entry as SessionStateEntry;\n\t\t\t\tconst status = normalizeSessionStateStatus(stateEntry.state?.status);\n\t\t\t\tif (status) {\n\t\t\t\t\tstate = { status };\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Keep the latest recap/verdict so off-daemon sessions don't all show as\n\t\t\t// unjudged in the agents view. Append-only, so last seen wins.\n\t\t\tif (entry.type === \"agent_status\") {\n\t\t\t\tagentStatus = (entry as AgentStatusEntry).status;\n\t\t\t}\n\t\t\tif (entry.type === \"child_usage_attributed\") {\n\t\t\t\tconst attribution = entry as ChildUsageAttributionEntry;\n\t\t\t\tif (assistantUsageById.has(attribution.targetId)) {\n\t\t\t\t\tassistantUsageById.set(attribution.targetId, attribution.aggregateUsage);\n\t\t\t\t\tattributedChildUsages.push(attribution.childUsage);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n\t\t\t\tconst summarizationUsage = (entry as CompactionEntry | BranchSummaryEntry).usage;\n\t\t\t\tif (summarizationUsage) summarizationUsages.push(summarizationUsage);\n\t\t\t}\n\t\t\tif (!header) {\n\t\t\t\tif (entry.type !== \"session\") {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\theader = entry as SessionHeader;\n\t\t\t}\n\n\t\t\tlastActivityTime = updateLastActivityTime(lastActivityTime, entry);\n\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tmessageCount++;\n\n\t\t\tconst message = (entry as SessionMessageEntry).message;\n\t\t\tif (message.role === \"assistant\" && (message as { usage?: Usage }).usage) {\n\t\t\t\tassistantUsageById.set(entry.id, (message as { usage: Usage }).usage);\n\t\t\t}\n\t\t\tif (!isMessageWithContent(message)) continue;\n\t\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\t\tconst textContent = extractTextContent(message);\n\t\t\tif (!textContent) continue;\n\n\t\t\tallMessagesText = appendCappedSearchText(allMessagesText, textContent);\n\t\t\tif (!firstMessage && message.role === \"user\") {\n\t\t\t\tfirstMessage = textContent;\n\t\t\t}\n\t\t}\n\n\t\tif (!header) return null;\n\t\tconst usageTotal = emptyUsage();\n\t\tfor (const usage of assistantUsageById.values()) {\n\t\t\taddAssistantUsage(usageTotal, usage);\n\t\t}\n\t\tfor (const usage of summarizationUsages) {\n\t\t\taddAssistantUsage(usageTotal, usage);\n\t\t}\n\t\tfor (const childUsage of attributedChildUsages) {\n\t\t\tsubtractAssistantUsage(usageTotal, childUsage);\n\t\t}\n\t\tconst cwd = typeof header.cwd === \"string\" ? header.cwd : \"\";\n\t\tconst parentSessionPath = header.parentSession;\n\t\tconst rlmDepth = resolveSessionRlmDepth(header, filePath);\n\t\tconst modified = getSessionModifiedDateFromLastActivity(lastActivityTime, header, stats.mtime);\n\n\t\treturn {\n\t\t\tpath: filePath,\n\t\t\tid: header.id,\n\t\t\tcwd,\n\t\t\tname,\n\t\t\tstate,\n\t\t\tparentSessionPath,\n\t\t\trlmDepth,\n\t\t\tcreated: new Date(header.timestamp),\n\t\t\tmodified,\n\t\t\tmessageCount,\n\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\tallMessagesText,\n\t\t\tagentStatus,\n\t\t\tusage: sessionUsageSummaryFrom(usageTotal),\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport type SessionListProgress = (loaded: number, total: number) => void;\nexport type SessionListItem = (session: SessionInfo) => void;\n\nexport interface SessionListCallbacks {\n\tonProgress?: SessionListProgress;\n\tonSession?: SessionListItem;\n}\n\nasync function listSessionsFromDir(\n\tdir: string,\n\tcallbacks?: SessionListCallbacks,\n\tprogressOffset = 0,\n\tprogressTotal?: number,\n): Promise<SessionInfo[]> {\n\tconst sessions: SessionInfo[] = [];\n\ttry {\n\t\tconst files = sessionCatalogFiles(dir);\n\t\tconst total = progressTotal ?? files.length;\n\n\t\tconst present = new Set(files);\n\t\tfor (const key of sessionInfoCache.keys()) {\n\t\t\tconst directory = dirname(key);\n\t\t\tconst inScope =\n\t\t\t\tdirectory === dir ||\n\t\t\t\t(dirname(directory) === dir && /^--.+--$/.test(basename(directory))) ||\n\t\t\t\t(resolve(dir) === resolve(getSessionsDir()) && directory === getDefaultAgentDir());\n\t\t\tif (inScope && !present.has(key)) {\n\t\t\t\tsessionInfoCache.delete(key);\n\t\t\t}\n\t\t}\n\n\t\tlet loaded = 0;\n\t\tfor (const file of files) {\n\t\t\tconst info = await readSessionInfo(file);\n\t\t\tloaded++;\n\t\t\tcallbacks?.onProgress?.(progressOffset + loaded, total);\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t\tcallbacks?.onSession?.(info);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof SessionCatalogReadError) throw error;\n\t\t// Return no sessions when the directory cannot be read.\n\t}\n\n\treturn sessions;\n}\n\nconst DEFAULT_MANAGER_HISTORY_LIMITS: SessionHistoryReadLimits = {\n\tmaxEntries: 16_384,\n\tmaxSourceBytes: 64 * 1024 * 1024,\n};\n\nasync function readOwnedSessionHeader(snapshot: SessionJournalState): Promise<SessionHeader> {\n\tconst handle = await openFile(snapshot.journalPath, \"r\");\n\tlet capturedHeader: SessionHeader | undefined;\n\ttry {\n\t\tconst checkIdentity = async () => {\n\t\t\tconst identity = await handle.stat();\n\t\t\tif (identity.dev !== snapshot.dev || identity.ino !== snapshot.ino || identity.size < snapshot.byteLength)\n\t\t\t\tthrow new Error(\"Owned session header source identity changed\");\n\t\t};\n\t\tawait checkIdentity();\n\t\tconst maximum = Math.min(snapshot.byteLength, SESSION_JOURNAL_MAX_FRAME_BYTES);\n\t\tconst parts: Buffer[] = [];\n\t\tlet offset = 0;\n\t\twhile (offset < maximum) {\n\t\t\tconst buffer = Buffer.allocUnsafe(Math.min(64 * 1024, maximum - offset));\n\t\t\tconst { bytesRead } = await handle.read(buffer, 0, buffer.length, offset);\n\t\t\tif (bytesRead === 0) break;\n\t\t\tconst chunk = buffer.subarray(0, bytesRead);\n\t\t\tconst end = chunk.indexOf(0x0a);\n\t\t\tparts.push(end < 0 ? chunk : chunk.subarray(0, end + 1));\n\t\t\toffset += bytesRead;\n\t\t\tif (end < 0) continue;\n\t\t\tconst frame = decodeJournalFrame(\n\t\t\t\tBuffer.concat(parts),\n\t\t\t\tINITIAL_JOURNAL_CURSOR,\n\t\t\t\tSESSION_JOURNAL_MAX_FRAME_BYTES,\n\t\t\t);\n\t\t\tconst header = frame.payload as SessionHeader;\n\t\t\tif (!header || header.type !== \"session\" || typeof header.id !== \"string\")\n\t\t\t\tthrow new Error(`Session source has no valid header: ${snapshot.journalPath}`);\n\t\t\tawait checkIdentity();\n\t\t\tcapturedHeader = header;\n\t\t\tbreak;\n\t\t}\n\t\tif (!capturedHeader) throw new Error(\"Owned session header is incomplete or exceeds the frame byte limit\");\n\t} catch (error) {\n\t\ttry {\n\t\t\tawait handle.close();\n\t\t} catch (closeError) {\n\t\t\tthrow new AggregateError([error, closeError], \"Owned session header read and close failed\", { cause: error });\n\t\t}\n\t\tthrow error;\n\t}\n\tawait handle.close();\n\treturn capturedHeader;\n}\n\ninterface SessionWriteState {\n\towner?: SessionJournalOwner;\n\thistory?: SessionHistoryIndex;\n\ttail: Promise<void>;\n\tpending: number;\n\tbytes: number;\n\treservedLeaf: string | null;\n\tleafId: string | null;\n\tbranchSelectionRevision: number;\n\tcompactionRevision: number;\n\tpins: number;\n\tretired: boolean;\n\tclosed: boolean;\n\tsequence: number;\n\tcompactionCount: number;\n\tsessionName?: string;\n\tsourceVersion: number;\n\theader?: SessionHeader;\n\tsessionState?: SessionState;\n\thasUserContent?: boolean;\n\tcontentPrefix?: number;\n\tgit?: GitContext;\n\tagentStatus?: AgentStatus;\n\tmetadataRefs?: { name?: string; state?: string; git?: string; status?: string };\n\tpendingIds: Set<string>;\n\tfailure?: Error;\n\tclosing?: Promise<void>;\n\tunpinned?: Promise<void>;\n\tonUnpinned?: () => void;\n}\n\nfunction newSessionWriteState(): SessionWriteState {\n\treturn {\n\t\ttail: Promise.resolve(),\n\t\tpending: 0,\n\t\tbytes: 0,\n\t\treservedLeaf: null,\n\t\tleafId: null,\n\t\tbranchSelectionRevision: 0,\n\t\tcompactionRevision: 0,\n\t\tpins: 0,\n\t\tretired: false,\n\t\tclosed: false,\n\t\tsequence: -1,\n\t\tcompactionCount: 0,\n\t\tsourceVersion: CURRENT_SESSION_VERSION,\n\t\tpendingIds: new Set(),\n\t};\n}\n\nconst MAX_SESSION_PENDING_OPERATIONS = 32;\nconst MAX_SESSION_PENDING_BYTES = 64 * 1024 * 1024;\n\nexport class SessionManager {\n\tprivate sessionId: string = \"\";\n\tprivate sessionFile: string | undefined;\n\tprivate sessionDir: string;\n\tprivate cwd: string;\n\tprivate persist: boolean;\n\tprivate fileEntries: FileEntry[] = [];\n\tprivate byId: Map<string, SessionEntry> = new Map();\n\tprivate labelsById: Map<string, string> = new Map();\n\tprivate labelTimestampsById: Map<string, string> = new Map();\n\tprivate leafId: string | null = null;\n\tprivate persistListeners = new Set<SessionPersistListener>();\n\tprivate finalizedToolMessages = new WeakMap<AgentMessage, string>();\n\tprivate pendingToolExchanges = new Map<string, Promise<string>>();\n\tprivate writeState = newSessionWriteState();\n\tprivate retiredSources = new Set<SessionWriteState>();\n\tprivate switching = false;\n\tprivate closing?: Promise<void>;\n\n\tprivate readOnly = false;\n\tprivate freshContextPolicySource = true;\n\tprivate indexed = false;\n\tprivate header: SessionHeader | null = null;\n\n\tprivate constructor(cwd: string, sessionDir: string, persist: boolean, options?: NewSessionOptions) {\n\t\tthis.cwd = cwd;\n\t\tthis.sessionDir = sessionDir;\n\t\tthis.persist = persist;\n\t\tif (persist) assertProductStatePath(sessionDir);\n\t\tthis._stageNewSession(options);\n\t}\n\n\tprivate _stageNewSession(options?: NewSessionOptions): void {\n\t\tthis.finalizedToolMessages = new WeakMap();\n\t\tlet sessionId = options?.id ?? createSessionId();\n\t\tlet sessionFile: string | undefined;\n\t\tconst hasExplicitRlmDepth = options !== undefined && Object.hasOwn(options, \"rlmDepth\");\n\t\tlet parentHeader: Partial<SessionHeader> | undefined;\n\t\tif (options?.parentSession && !hasExplicitRlmDepth) {\n\t\t\ttry {\n\t\t\t\tparentHeader = readSessionHeader(options.parentSession);\n\t\t\t} catch {\n\t\t\t\t// Unavailable parent metadata leaves the child depth unknown.\n\t\t\t}\n\t\t}\n\t\tif (this.persist) {\n\t\t\tif (options?.id) {\n\t\t\t\tsessionFile = getSessionFilePath(this.getSessionDir(), sessionId);\n\t\t\t\tif (existsSync(sessionFile)) {\n\t\t\t\t\tthrow new Error(`Session file already exists for id \"${sessionId}\": ${sessionFile}`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst target = createUniqueSessionFileTarget(this.getSessionDir());\n\t\t\t\tsessionId = target.sessionId;\n\t\t\t\tsessionFile = target.sessionFile;\n\t\t\t}\n\t\t}\n\n\t\tthis.sessionId = sessionId;\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst git = this.persist ? (captureGitContext(this.cwd) ?? undefined) : undefined;\n\t\tconst rlmDepth = hasExplicitRlmDepth\n\t\t\t? options?.rlmDepth\n\t\t\t: options?.parentSession\n\t\t\t\t? deriveChildRlmDepth(parentHeader)\n\t\t\t\t: rootRlmDepthFromEnv();\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp,\n\t\t\tcwd: this.cwd,\n\t\t\tparentSession: options?.parentSession,\n\t\t\trlmDepth,\n\t\t\tgit,\n\t\t};\n\t\tthis.fileEntries = [header];\n\t\tthis.byId = new Map();\n\t\tthis.labelsById = new Map();\n\t\tthis.labelTimestampsById = new Map();\n\t\tthis.leafId = null;\n\n\t\tif (this.persist) {\n\t\t\tthis.sessionFile = sessionFile ? assertProductStatePath(sessionFile) : undefined;\n\t\t}\n\t\tthis.writeState.sequence = this.persist ? -1 : 0;\n\t\tthis.writeState.compactionCount = 0;\n\t}\n\n\tprivate async _openNew(): Promise<void> {\n\t\tif (!this.persist || !this.sessionFile) return;\n\t\tconst state = this.writeState;\n\t\tconst owner = await SessionJournalOwner.open({\n\t\t\tjournalPath: assertProductStatePath(this.sessionFile),\n\t\t\tcreate: true,\n\t\t});\n\t\tstate.owner = owner;\n\t\tthis.sessionFile = owner.journalPath;\n\t\ttry {\n\t\t\tfor (const entry of this.fileEntries) {\n\t\t\t\tconst ack = await appendSourceEntry(owner, stringifyBoundedJson(entry, MAX_SESSION_RECORD_BYTES), entry);\n\t\t\t\tstate.sequence = ack.sequence;\n\t\t\t}\n\t\t\tawait this._activateIndexedSource(this.fileEntries[0] as SessionHeader);\n\t\t} catch (error) {\n\t\t\tstate.closed = true;\n\t\t\ttry {\n\t\t\t\tawait this._closeSourceActors(state);\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Session creation and cleanup failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate async _adopt(next: SessionManager): Promise<void> {\n\t\tconst previous = this.writeState;\n\t\ttry {\n\t\t\tawait this._retire(previous);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait next.close();\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Session adoption and destination close failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tthis.sessionId = next.sessionId;\n\t\tthis.sessionFile = next.sessionFile;\n\t\tthis.sessionDir = next.sessionDir;\n\t\tthis.persist = next.persist;\n\t\tthis.freshContextPolicySource = next.freshContextPolicySource;\n\t\tthis.indexed = next.indexed;\n\t\tthis.header = next.header;\n\t\tthis.fileEntries = next.fileEntries;\n\t\tthis.byId = next.byId;\n\t\tthis.labelsById = next.labelsById;\n\t\tthis.labelTimestampsById = next.labelTimestampsById;\n\t\tthis.leafId = next.leafId;\n\t\tthis.finalizedToolMessages = next.finalizedToolMessages;\n\t\tthis.writeState = next.writeState;\n\t}\n\n\tprivate _assertResident(): void {\n\t\tif (this.indexed)\n\t\t\tthrow new Error(\n\t\t\t\t\"Synchronous history access requires a resident session view; use captured async history reads\",\n\t\t\t);\n\t}\n\n\tprivate async _acknowledgedHistory(\n\t\tstate: SessionWriteState,\n\t\tsnapshot = state.owner!.getSnapshot(),\n\t): Promise<SessionHistoryReadScope> {\n\t\tconst owner = state.owner;\n\t\tconst header = state.header;\n\t\tif (!owner || !header || owner.format !== \"framed\" || state.sourceVersion !== CURRENT_SESSION_VERSION)\n\t\t\tthrow new Error(\"An owned canonical session source is required\");\n\t\tstate.history ??= new SessionHistoryIndex(\n\t\t\theader.id,\n\t\t\tjoin(assertProductStatePath(getSessionArtifactPathForFile(owner.journalPath, header.id)), \"history.sqlite\"),\n\t\t);\n\t\tconst index = await state.history.synchronize(snapshot);\n\t\treturn createSessionHistoryReadScope(\n\t\t\tindex,\n\t\t\tObject.freeze({\n\t\t\t\tsessionId: header.id,\n\t\t\t\tsessionFile: owner.journalPath,\n\t\t\t\tleafId: state.leafId,\n\t\t\t\tsourceSequence: snapshot.nextSequence - 1,\n\t\t\t\tpersistent: true,\n\t\t\t}),\n\t\t\t(operation) => operation(),\n\t\t\t\"source\",\n\t\t);\n\t}\n\n\tprivate async _storedEntry(\n\t\thistory: SessionHistoryReadScope,\n\t\tid: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<HydratedSessionHistoryEntry | undefined> {\n\t\tconst value = await history.hydrateEntry(id, maxSourceBytes);\n\t\tif (!value || value.entry.type !== \"message\" || value.entry.message.role !== \"assistant\") return value;\n\t\tconst update = await history.sourceAssistantUsage(id);\n\t\tif (!update) return value;\n\t\tif (value.source.locator.length + update.locator.length > maxSourceBytes)\n\t\t\tthrow new Error(\"Stored assistant source byte budget exceeded\");\n\t\tconst related = await history.hydrateEntry(update.id, maxSourceBytes - value.source.locator.length);\n\t\tif (!related || related.entry.type !== \"child_usage_attributed\")\n\t\t\tthrow new Error(\"Stored assistant aggregate source is unavailable\");\n\t\tvalue.entry.message.usage = cloneUsage(related.entry.aggregateUsage);\n\t\treturn value;\n\t}\n\n\tprivate async _refreshOwnedMetadata(state: SessionWriteState, startup = false): Promise<void> {\n\t\tconst owner = state.owner!;\n\t\tconst snapshot = owner.getSnapshot();\n\t\tconst history = await this._acknowledgedHistory(state, snapshot);\n\t\tconst bootstrap = await state.history!.currentSourceBootstrap(snapshot);\n\t\tconst leafId = startup ? (bootstrap.leaf?.id ?? null) : state.leafId;\n\t\tconst index = await state.history!.synchronize(snapshot);\n\t\tconst branch = await index.branchBootstrap(state.header!.id, {\n\t\t\tleafId,\n\t\t\tthrough: history.source.sourceSequence,\n\t\t});\n\t\tconst refs = [bootstrap.sessionInfo, bootstrap.sessionState, branch.gitState, branch.agentStatus];\n\t\tif (\n\t\t\trefs.reduce((bytes, ref) => bytes + (ref?.locator.length ?? 0), 0) >\n\t\t\tDEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes\n\t\t)\n\t\t\tthrow new Error(\"Owned session metadata source byte budget exceeded\");\n\t\tconst previous = state.metadataRefs ?? {};\n\t\tconst read = async (ref: IndexedSourceEvent | null) => {\n\t\t\tif (!ref) return undefined;\n\t\t\tconst value = await history.hydrateEntry(ref.id, DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes);\n\t\t\tif (!value) throw new Error(\"Owned session metadata source is unavailable\");\n\t\t\treturn value.entry;\n\t\t};\n\t\tif (!state.metadataRefs || previous.name !== bootstrap.sessionInfo?.revision) {\n\t\t\tconst entry = await read(bootstrap.sessionInfo);\n\t\t\tstate.sessionName = entry?.type === \"session_info\" ? entry.name : undefined;\n\t\t}\n\t\tif (!state.metadataRefs || previous.state !== bootstrap.sessionState?.revision) {\n\t\t\tconst entry = await read(bootstrap.sessionState);\n\t\t\tconst status = entry?.type === \"session_state\" ? normalizeSessionStateStatus(entry.state.status) : undefined;\n\t\t\tstate.sessionState = status ? { status } : undefined;\n\t\t}\n\t\tif (!state.metadataRefs || previous.git !== branch.gitState?.revision) {\n\t\t\tconst entry = await read(branch.gitState);\n\t\t\tstate.git = entry?.type === \"git_state\" ? entry.git : state.header?.git;\n\t\t}\n\t\tif (!state.metadataRefs || previous.status !== branch.agentStatus?.revision) {\n\t\t\tconst entry = await read(branch.agentStatus);\n\t\t\tstate.agentStatus = entry?.type === \"agent_status\" ? { ...entry.status } : undefined;\n\t\t}\n\t\tstate.metadataRefs = {\n\t\t\tname: bootstrap.sessionInfo?.revision,\n\t\t\tstate: bootstrap.sessionState?.revision,\n\t\t\tgit: branch.gitState?.revision,\n\t\t\tstatus: branch.agentStatus?.revision,\n\t\t};\n\t\tstate.compactionCount = bootstrap.compactionCount;\n\t\tstate.hasUserContent = bootstrap.hasUserContent;\n\t\tstate.contentPrefix = bootstrap.contentPrefix;\n\t\tstate.leafId = leafId;\n\t\tstate.reservedLeaf = leafId;\n\t\tif (this.writeState === state) this.leafId = leafId;\n\t}\n\n\tprivate async _prepareOwnedMetadata(\n\t\tstate: SessionWriteState,\n\t\tentry: SessionEntry,\n\t\thistory: SessionHistoryReadScope,\n\t\tadvanceLeaf: boolean,\n\t): Promise<\n\t\tPick<\n\t\t\tSessionWriteState,\n\t\t\t\"compactionCount\" | \"sessionName\" | \"sessionState\" | \"hasUserContent\" | \"contentPrefix\" | \"git\" | \"agentStatus\"\n\t\t>\n\t> {\n\t\tif (state.hasUserContent === undefined || state.contentPrefix === undefined)\n\t\t\tthrow new Error(\"Owned session metadata is unavailable\");\n\t\tconst metadata = {\n\t\t\tcompactionCount: state.compactionCount + (entry.type === \"compaction\" ? 1 : 0),\n\t\t\tsessionName: entry.type === \"session_info\" ? entry.name : state.sessionName,\n\t\t\tsessionState: state.sessionState,\n\t\t\thasUserContent: state.hasUserContent,\n\t\t\tcontentPrefix: state.contentPrefix,\n\t\t\tgit: state.git,\n\t\t\tagentStatus: state.agentStatus,\n\t\t};\n\t\tif (entry.type === \"session_state\") {\n\t\t\tconst status = normalizeSessionStateStatus(entry.state?.status);\n\t\t\tif (status) metadata.sessionState = { status };\n\t\t}\n\t\tif (!metadata.hasUserContent && CONTENT_ENTRY_TYPES.has(entry.type)) {\n\t\t\tconst prefix = [\"model_change\", \"thinking_level_change\", \"service_tier_change\"];\n\t\t\twhile (metadata.contentPrefix < prefix.length && entry.type !== prefix[metadata.contentPrefix])\n\t\t\t\tmetadata.contentPrefix++;\n\t\t\tif (metadata.contentPrefix < prefix.length) metadata.contentPrefix++;\n\t\t\telse metadata.hasUserContent = true;\n\t\t}\n\t\tif (advanceLeaf) {\n\t\t\tif (entry.parentId !== state.leafId) {\n\t\t\t\tconst index = await state.history!.synchronize(state.owner!.getSnapshot());\n\t\t\t\tconst branch = await index.branchBootstrap(state.header!.id, {\n\t\t\t\t\tleafId: entry.parentId,\n\t\t\t\t\tthrough: history.source.sourceSequence,\n\t\t\t\t});\n\t\t\t\tlet remaining = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes;\n\t\t\t\tconst read = async (reference: IndexedSourceEvent | null) => {\n\t\t\t\t\tif (!reference) return undefined;\n\t\t\t\t\tconst budget = remaining;\n\t\t\t\t\tremaining -= reference.locator.length;\n\t\t\t\t\tif (remaining < 0) throw new Error(\"Owned session metadata source byte budget exceeded\");\n\t\t\t\t\tconst hydrated = await history.hydrateEntry(reference.id, budget);\n\t\t\t\t\tif (!hydrated) throw new Error(\"Owned session metadata source is unavailable\");\n\t\t\t\t\treturn hydrated.entry;\n\t\t\t\t};\n\t\t\t\tconst git = await read(branch.gitState);\n\t\t\t\tconst status = await read(branch.agentStatus);\n\t\t\t\tmetadata.git = git?.type === \"git_state\" ? git.git : state.header?.git;\n\t\t\t\tmetadata.agentStatus = status?.type === \"agent_status\" ? { ...status.status } : undefined;\n\t\t\t}\n\t\t\tif (entry.type === \"git_state\") metadata.git = entry.git;\n\t\t\tif (entry.type === \"agent_status\") metadata.agentStatus = { ...entry.status };\n\t\t}\n\t\treturn metadata;\n\t}\n\n\tprivate async _activateIndexedSource(header: SessionHeader, state = this.writeState): Promise<void> {\n\t\tstate.header = header;\n\t\tawait this._refreshOwnedMetadata(state, true);\n\t\tthis.writeState = state;\n\t\tthis.header = header;\n\t\tthis.leafId = state.leafId;\n\t\tthis.fileEntries = [];\n\t\tthis.byId.clear();\n\t\tthis.labelsById.clear();\n\t\tthis.labelTimestampsById.clear();\n\t\tthis.indexed = true;\n\t}\n\n\tprivate _assertMutable(): void {\n\t\tif (this.readOnly) throw new Error(\"Session view is read-only\");\n\t\tif (this.persist && this.sessionFile) {\n\t\t\tassertProductStatePath(this.sessionFile);\n\t\t\tif (this.writeState.owner && realpathIfPresent(this.sessionFile) !== this.writeState.owner.journalPath)\n\t\t\t\tthrow new Error(\"Session source target changed outside its owner\");\n\t\t}\n\t\tif (this.switching || this.closing) throw new Error(\"Session source is switching or closing\");\n\t}\n\n\tasync setSessionFile(sessionFile: string): Promise<void> {\n\t\tthis._assertMutable();\n\t\tconst target = assertProductStatePath(sessionFile);\n\t\tif (realpathIfPresent(target) === this.sessionFile) {\n\t\t\tawait this.flushNow();\n\t\t\treturn;\n\t\t}\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this.flushNow();\n\t\t\tconst next = await SessionManager.open(target, this.sessionDir, this.cwd);\n\t\t\tawait this._adopt(next);\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tasync newSession(options?: NewSessionOptions): Promise<string | undefined> {\n\t\tthis._assertMutable();\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this.flushNow();\n\t\t\tconst next = new SessionManager(this.cwd, this.sessionDir, this.persist, options);\n\t\t\tawait next._openNew();\n\t\t\tawait this._adopt(next);\n\t\t\treturn this.sessionFile;\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tprivate _buildIndex(): void {\n\t\tthis.byId = new Map();\n\t\tthis.labelsById = new Map();\n\t\tthis.labelTimestampsById = new Map();\n\t\tthis.leafId = null;\n\t\tthis.writeState.compactionCount = 0;\n\t\tthis.writeState.sessionName = undefined;\n\t\tfor (const entry of this.fileEntries) {\n\t\t\tif (entry.type === \"session\") continue;\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tif (entry.type === \"compaction\") this.writeState.compactionCount++;\n\t\t\tif (entry.type === \"session_info\") this.writeState.sessionName = entry.name;\n\t\t\tif (entry.type !== \"request\") this.leafId = entry.id;\n\t\t\tif (entry.type === \"label\") {\n\t\t\t\tif (entry.label) {\n\t\t\t\t\tthis.labelsById.set(entry.targetId, entry.label);\n\t\t\t\t\tthis.labelTimestampsById.set(entry.targetId, entry.timestamp);\n\t\t\t\t} else {\n\t\t\t\t\tthis.labelsById.delete(entry.targetId);\n\t\t\t\t\tthis.labelTimestampsById.delete(entry.targetId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.writeState.leafId = this.leafId;\n\t\tthis.writeState.reservedLeaf = this.leafId;\n\t}\n\n\tprivate _notifyPersistListeners(): void {\n\t\tif (!this.sessionFile) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const listener of this.persistListeners) {\n\t\t\ttry {\n\t\t\t\tlistener(this.sessionFile);\n\t\t\t} catch {\n\t\t\t\t// Persistence observers must not break session writes.\n\t\t\t}\n\t\t}\n\t}\n\n\tonPersist(listener: SessionPersistListener): () => void {\n\t\tthis.persistListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.persistListeners.delete(listener);\n\t\t};\n\t}\n\n\tisPersisted(): boolean {\n\t\treturn this.persist;\n\t}\n\n\t/** Actual new-owner creation plus the existing canonical bootstrap-content boundary. */\n\tcanSeedContextModeContract(): boolean {\n\t\treturn this.freshContextPolicySource && !this.readOnly && !this.hasUserContent();\n\t}\n\n\t/** Captured indexed reads require this manager's owned, framed source. */\n\tsupportsCapturedHistoryReads(): boolean {\n\t\treturn this.persist && !this.readOnly && this.writeState.owner?.format === \"framed\";\n\t}\n\n\tgetCwd(): string {\n\t\treturn this.cwd;\n\t}\n\n\tgetSessionDir(): string {\n\t\treturn this.sessionDir;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string | undefined {\n\t\treturn this.sessionFile;\n\t}\n\n\tasync materializeSessionFile(sessionDir?: string): Promise<string> {\n\t\tthis._assertMutable();\n\t\tif (this.sessionFile) return this.sessionFile;\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this.flushNow();\n\t\t\tconst dir = sessionDir ?? (this.sessionDir || getDefaultSessionDir(this.cwd));\n\t\t\tconst header = this.getHeader();\n\t\t\tconst next = new SessionManager(this.cwd, dir, true, {\n\t\t\t\tparentSession: header?.parentSession,\n\t\t\t\trlmDepth: resolveSessionRlmDepth(header ?? {}, dir),\n\t\t\t});\n\t\t\tconst captured = this.materializeResidentHistory(DEFAULT_MANAGER_HISTORY_LIMITS);\n\t\t\tnext.fileEntries.push(\n\t\t\t\t...captured.entries.map((entry, index) =>\n\t\t\t\t\twithEntryRetention(\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tcaptured.retentions[index] ?? undefined,\n\t\t\t\t\t\tcaptured.qualifications[index] ?? undefined,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t\tnext._buildIndex();\n\t\t\tawait next._openNew();\n\t\t\tawait this._adopt(next);\n\t\t\treturn this.sessionFile!;\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tgetSessionArtifactDir(): string | undefined {\n\t\treturn this.persist && this.sessionFile\n\t\t\t? assertProductStatePath(getSessionArtifactPathForFile(this.sessionFile, this.sessionId))\n\t\t\t: undefined;\n\t}\n\n\t/** Exact source metadata within the captured current branch, not a scan of message arrays. */\n\tgetHistoryEntry(id: string): Promise<IndexedSourceEvent | undefined> {\n\t\treturn this._readHistory((view) => view.get(id));\n\t}\n\n\t/** Exact canonical JSON bytes as bounded UTF8 fragments, within the captured branch. */\n\treadHistoryPayload(\n\t\tid: string,\n\t\toptions: HistoryPayloadReadOptions = {},\n\t): Promise<CanonicalPayloadFragment | undefined> {\n\t\tconst captured = { ...options, ...(options.cursor ? { cursor: { ...options.cursor } } : {}) };\n\t\treturn this._readHistory((view) => view.readPayload(id, captured));\n\t}\n\n\tpageHistory(after = 0, limit = 64): Promise<HistoryIndexPage> {\n\t\treturn this._readHistory((view) => view.page(after, limit));\n\t}\n\n\tsearchHistory(query: string, limit = 16): Promise<HistoryIndexPage> {\n\t\treturn this._readHistory((view) => view.search(query, limit));\n\t}\n\n\t/** Source-order active-context references, not a last-N transcript. */\n\tcontextManifest(options: ContextManifestOptions = {}): Promise<ContextManifestPage> {\n\t\tconst captured = { ...options, ...(options.cursor ? { cursor: { ...options.cursor } } : {}) };\n\t\treturn this._readHistory((view) => view.contextManifest(captured));\n\t}\n\n\t/** Structured descriptive evidence; selective output is not an exhaustive requirements list. */\n\ttaskEvidence(options: TaskEvidenceOptions = {}): Promise<TaskEvidencePage> {\n\t\tconst captured = { ...options, ...(options.after ? { after: { ...options.after } } : {}) };\n\t\treturn this._readHistory((view) => view.taskEvidence(captured));\n\t}\n\n\tprivate async _readHistory<T>(read: (view: SessionHistoryReadView) => Promise<T>): Promise<T> {\n\t\treturn this._runHistoryRead(this.bindRequestSink(), read);\n\t}\n\n\t/** Explicit branch read at one pinned canonical frontier. */\n\treadBranchHistory<T>(read: (view: SessionHistoryReadScope) => Promise<T>): Promise<T> {\n\t\treturn this._runHistoryRead(\n\t\t\tthis._bindHistorySource((index, source, query) =>\n\t\t\t\tcreateSessionHistoryReadScope(index, source, query, \"branch\"),\n\t\t\t),\n\t\t\tread,\n\t\t);\n\t}\n\n\t/** Explicit whole-source read, including branches outside the current leaf. */\n\treadSourceHistory<T>(read: (view: SessionHistoryReadScope) => Promise<T>): Promise<T> {\n\t\treturn this._runHistoryRead(\n\t\t\tthis._bindHistorySource((index, source, query) =>\n\t\t\t\tcreateSessionHistoryReadScope(index, source, query, \"source\"),\n\t\t\t),\n\t\t\tread,\n\t\t);\n\t}\n\n\t/** Complete bounded structured task reduction on one captured native branch. */\n\tasync readTaskState(limits: Partial<TaskStateReadLimits> = {}): Promise<TaskStateView> {\n\t\tconst captured = taskStateReadLimits(limits);\n\t\tif (!this.supportsCapturedHistoryReads())\n\t\t\tthrow new Error(\"Task-state reduction requires captured native history\");\n\t\treturn this.readSourceHistory((history) => readTaskStateFromHistory(history, captured));\n\t}\n\n\t/** Complete actual parent chain, excluding merely attached request evidence. */\n\tprivate async _materializeParentPath(\n\t\tview: SessionHistoryReadScope,\n\t\tleafId: string | null,\n\t\tlimits: SessionHistoryReadLimits,\n\t): Promise<Omit<MaterializedSessionHistory, \"scope\">> {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tconst entries: MaterializedSessionHistory[\"entries\"] = [];\n\t\tlet sourceBytes = 0;\n\t\tlet page = await view.parentPathFrom(leafId);\n\t\tfor (;;) {\n\t\t\tif (page.totalEntries > maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\tfor (const ref of page.events) {\n\t\t\t\tif (entries.length >= maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\t\tconst remaining = maxSourceBytes - sourceBytes;\n\t\t\t\tsourceBytes += ref.locator.length;\n\t\t\t\tif (sourceBytes > maxSourceBytes) throw new Error(\"Parent-path source byte budget exceeded\");\n\t\t\t\tconst hydrated = await view.hydrateEntry(ref.id, remaining);\n\t\t\t\tif (!hydrated) throw new Error(\"Parent-path entry source is unavailable\");\n\t\t\t\tentries.push(hydrated);\n\t\t\t}\n\t\t\tif (!page.nextCursor) return { source: view.source, entries, sourceBytes };\n\t\t\tpage = await view.parentPathFrom(leafId, { cursor: page.nextCursor });\n\t\t}\n\t}\n\n\tasync materializeParentPathHistory(\n\t\tlimits: SessionHistoryReadLimits,\n\t): Promise<Omit<MaterializedSessionHistory, \"scope\">> {\n\t\tconst capturedLimits = { ...limits };\n\t\treturn this.readSourceHistory((history) =>\n\t\t\tthis._materializeParentPath(history, history.source.leafId, capturedLimits),\n\t\t);\n\t}\n\n\tmaterializeBranchHistory(limits: SessionHistoryReadLimits): Promise<MaterializedSessionHistory> {\n\t\tconst captured = { ...limits };\n\t\treturn this.readBranchHistory((view) => view.materialize(captured));\n\t}\n\n\tmaterializeSourceHistory(limits: SessionHistoryReadLimits): Promise<MaterializedSessionHistory> {\n\t\tconst captured = { ...limits };\n\t\treturn this.readSourceHistory((view) => view.materialize(captured));\n\t}\n\n\tprivate async _runHistoryRead<View, T>(\n\t\tsink: BoundHistoryReadSink<View>,\n\t\tread: (view: View) => Promise<T>,\n\t): Promise<T> {\n\t\tconst outcome = await sink.readHistory(read).then(\n\t\t\t(value) => ({ ok: true, value }) as const,\n\t\t\t(error: unknown) => ({ ok: false, error }) as const,\n\t\t);\n\t\ttry {\n\t\t\tawait sink.release();\n\t\t} catch (error) {\n\t\t\tif (!outcome.ok) throw new AggregateError([outcome.error, error], \"History read and source release failed\");\n\t\t\tthrow error;\n\t\t}\n\t\tif (!outcome.ok) throw outcome.error;\n\t\treturn outcome.value;\n\t}\n\n\tprivate _publishHistory(state: SessionWriteState): void {\n\t\tif (state.history && state.owner) state.history.publish(state.owner.getSnapshot());\n\t}\n\n\tprivate async _releaseSourcePin(state: SessionWriteState): Promise<void> {\n\t\tstate.pins--;\n\t\tif (state.pins === 0) {\n\t\t\tstate.onUnpinned?.();\n\t\t\tstate.onUnpinned = undefined;\n\t\t\tstate.unpinned = undefined;\n\t\t}\n\t\tawait this._closeRetired(state);\n\t}\n\n\tprivate async _closeSourceActors(state: SessionWriteState): Promise<void> {\n\t\tconst errors: unknown[] = [];\n\t\ttry {\n\t\t\tawait state.history?.close();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\t// Keep the canonical fence until the derived reader has exited, including failed shutdown.\n\t\ttry {\n\t\t\tawait state.owner?.close();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tif (errors.length === 1) throw errors[0];\n\t\tif (errors.length > 1) throw new AggregateError(errors, \"Session source actors failed to close\");\n\t}\n\n\t/** Wait for all previously admitted writes and the writer's durability barrier. */\n\tasync flushNow(): Promise<void> {\n\t\tconst state = this.writeState;\n\t\tawait this._enqueue(state, 0, async () => {\n\t\t\tawait state.owner?.flush();\n\t\t});\n\t}\n\n\tasync migrateLegacy(): Promise<void> {\n\t\tthis._assertMutable();\n\t\tconst state = this.writeState;\n\t\tif (state.pins > 0) throw new Error(\"Drain captured requests before migrating session history\");\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this._enqueue(state, 0, async () => {\n\t\t\t\tif (!state.owner) throw new Error(\"An owned persistent source is required for migration\");\n\t\t\t\tif (state.sourceVersion !== CURRENT_SESSION_VERSION)\n\t\t\t\t\tthrow new Error(\"Legacy session payload requires an explicit retained import before writing\");\n\t\t\t\ttry {\n\t\t\t\t\tawait state.owner.migrateLegacy();\n\t\t\t\t\tstate.sequence = state.owner.nextSequence - 1;\n\t\t\t\t\tawait this._activateIndexedSource(this.getHeader()!, state);\n\t\t\t\t\tthis._publishHistory(state);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.failure = new Error(\"Session source migration failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\t/** Re-open and replay after explicit exclusive repair; never re-execute an effect. */\n\tasync recover(): Promise<void> {\n\t\tthis._assertMutable();\n\t\tconst previous = this.writeState;\n\t\tif (!this.persist || !this.sessionFile || this.readOnly)\n\t\t\tthrow new Error(\"An owned persistent source is required for recovery\");\n\t\tif (previous.pins > 0 || previous.pending > 0)\n\t\t\tthrow new Error(\"Drain captured requests and source writes before recovery\");\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait previous.tail;\n\t\t\tawait this._closeSourceActors(previous);\n\t\t\tprevious.closed = true;\n\t\t\tconst owner = await SessionJournalOwner.open({ journalPath: this.sessionFile });\n\t\t\tconst state = newSessionWriteState();\n\t\t\tstate.owner = owner;\n\t\t\ttry {\n\t\t\t\tawait owner.recover();\n\t\t\t\tlet residentEntries: FileEntry[] | undefined;\n\t\t\t\tlet header: SessionHeader;\n\t\t\t\tif (owner.format === \"framed\") header = await readOwnedSessionHeader(owner.getSnapshot());\n\t\t\t\telse {\n\t\t\t\t\tresidentEntries = await loadEntriesFromFileAsync(owner.journalPath);\n\t\t\t\t\tconst first = residentEntries[0];\n\t\t\t\t\tif (!first || first.type !== \"session\") throw new Error(\"Recovered source has no valid header\");\n\t\t\t\t\theader = first;\n\t\t\t\t}\n\t\t\t\tif (header.id !== this.sessionId) throw new Error(\"Recovered source identity does not match this session\");\n\t\t\t\tstate.sequence = owner.nextSequence - 1;\n\t\t\t\tstate.sourceVersion = header.version ?? 1;\n\t\t\t\tif (owner.format === \"framed\" && state.sourceVersion === CURRENT_SESSION_VERSION)\n\t\t\t\t\tawait this._activateIndexedSource(header, state);\n\t\t\t\telse {\n\t\t\t\t\tconst entries = residentEntries ?? (await loadEntriesFromFileAsync(owner.journalPath));\n\t\t\t\t\tmigrateToCurrentVersion(entries);\n\t\t\t\t\tthis.indexed = false;\n\t\t\t\t\tthis.fileEntries = entries;\n\t\t\t\t\tthis.writeState = state;\n\t\t\t\t\tthis._buildIndex();\n\t\t\t\t}\n\t\t\t\tthis.finalizedToolMessages = new WeakMap();\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this._closeSourceActors(state);\n\t\t\t\t} catch (cleanup) {\n\t\t\t\t\tthrow new AggregateError([error, cleanup], \"Session recovery and cleanup failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tprivate _enqueue<T>(state: SessionWriteState, bytes: number, action: () => Promise<T>): Promise<T> {\n\t\tif (state.closed) return Promise.reject(new Error(\"Session source owner is closed\"));\n\t\tif (state.failure) return Promise.reject(state.failure);\n\t\tif (state.pending >= MAX_SESSION_PENDING_OPERATIONS || state.bytes + bytes > MAX_SESSION_PENDING_BYTES)\n\t\t\treturn Promise.reject(new Error(\"Session source queue limit exceeded\"));\n\t\tstate.pending++;\n\t\tstate.bytes += bytes;\n\t\tconst result = state.tail.then(async () => {\n\t\t\tif (state.failure) throw state.failure;\n\t\t\treturn action();\n\t\t});\n\t\tstate.tail = result\n\t\t\t.then(\n\t\t\t\t() => undefined,\n\t\t\t\t() => undefined,\n\t\t\t)\n\t\t\t.finally(() => {\n\t\t\t\tstate.pending--;\n\t\t\t\tstate.bytes -= bytes;\n\t\t\t});\n\t\treturn result;\n\t}\n\n\tprivate async _appendIndexedEntry(\n\t\tstate: SessionWriteState,\n\t\tentry: SessionEntry,\n\t\texplicitParent = false,\n\t\tprepare?: (snapshot: SessionEntry) => void | Promise<void>,\n\t\tonDuplicate?: (entry: SessionEntry) => SessionEntry,\n\t\tadvanceLeaf = true,\n\t\tdeduplicate?: (history: SessionHistoryReadScope) => Promise<SessionEntry | undefined>,\n\t\tassertCurrent?: () => void,\n\t): Promise<SessionEntry> {\n\t\tif (state.failure) throw state.failure;\n\t\tconst generated = entry.id === \"\";\n\t\tconst initial = { ...entry, parentId: explicitParent ? entry.parentId : null };\n\t\tconst snapshot = withEntryRetention(\n\t\t\tJSON.parse(stringifyBoundedJson(initial, MAX_SESSION_RECORD_BYTES)) as SessionEntry,\n\t\t\tentryRetentions.get(entry),\n\t\t\tentryQualifications.get(entry),\n\t\t);\n\t\tconst ownsPendingId = !generated && !state.pendingIds.has(snapshot.id);\n\t\tif (!generated && !ownsPendingId && !onDuplicate) throw new Error(`Duplicate session entry: ${snapshot.id}`);\n\t\tconst idBytes = (id: string) => Buffer.byteLength(JSON.stringify(id));\n\t\tconst parentBytes = explicitParent\n\t\t\t? 0\n\t\t\t: Math.max(38, idBytes(state.leafId ?? \"\"), ...Array.from(state.pendingIds, idBytes));\n\t\tconst admittedBytes =\n\t\t\tBuffer.byteLength(stringifyBoundedJson(snapshot, MAX_SESSION_RECORD_BYTES)) +\n\t\t\tparentBytes +\n\t\t\t(generated ? 36 : 0) +\n\t\t\t(prepare ? 16 * 1024 : 0);\n\t\tif (state.pending >= MAX_SESSION_PENDING_OPERATIONS || state.bytes + admittedBytes > MAX_SESSION_PENDING_BYTES)\n\t\t\tthrow new Error(\"Session source queue limit exceeded\");\n\t\tif (ownsPendingId) state.pendingIds.add(snapshot.id);\n\t\ttry {\n\t\t\treturn await this._enqueue(state, admittedBytes, async () => {\n\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\tconst duplicate = await deduplicate?.(history);\n\t\t\t\tif (duplicate) return duplicate;\n\t\t\t\tif (generated) {\n\t\t\t\t\tfor (let attempt = 0; ; attempt++) {\n\t\t\t\t\t\tconst id = attempt < 100 ? randomUUID().slice(0, 8) : randomUUID();\n\t\t\t\t\t\tif (state.pendingIds.has(id) || (await history.get(id))) {\n\t\t\t\t\t\t\tif (attempt >= 100) throw new Error(`Duplicate session entry: ${id}`);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsnapshot.id = id;\n\t\t\t\t\t\tstate.pendingIds.add(id);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst reference = await history.get(snapshot.id);\n\t\t\t\t\tif (reference) {\n\t\t\t\t\t\tif (!onDuplicate) throw new Error(`Duplicate session entry: ${snapshot.id}`);\n\t\t\t\t\t\tconst existing = await history.hydrateEntry(reference.id, MAX_SESSION_RECORD_BYTES);\n\t\t\t\t\t\tif (!existing) throw new Error(\"Duplicate entry source is unavailable\");\n\t\t\t\t\t\treturn onDuplicate(existing.entry);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!explicitParent) snapshot.parentId = state.leafId;\n\t\t\t\tif (prepare) await prepare(snapshot);\n\t\t\t\tconst metadata = await this._prepareOwnedMetadata(state, snapshot, history, advanceLeaf);\n\t\t\t\tconst json = stringifyBoundedJson(snapshot, Math.min(admittedBytes, MAX_SESSION_RECORD_BYTES));\n\t\t\t\tassertCurrent?.();\n\t\t\t\ttry {\n\t\t\t\t\tconst ack = await appendSourceEntry(state.owner!, json, snapshot);\n\t\t\t\t\tstate.sequence = ack.sequence;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.failure = new Error(\"Session source append failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tObject.assign(state, metadata);\n\t\t\t\tstate.metadataRefs = undefined;\n\t\t\t\tif (advanceLeaf) {\n\t\t\t\t\tstate.leafId = snapshot.id;\n\t\t\t\t\tif (!isCompactionBookkeeping(snapshot)) state.compactionRevision++;\n\t\t\t\t}\n\t\t\t\tstate.reservedLeaf = state.leafId;\n\t\t\t\tif (this.writeState === state) this.leafId = state.leafId;\n\t\t\t\tthis._publishHistory(state);\n\t\t\t\tentry.id = snapshot.id;\n\t\t\t\tif (this.writeState === state) this._notifyPersistListeners();\n\t\t\t\treturn snapshot;\n\t\t\t});\n\t\t} finally {\n\t\t\tif (generated || ownsPendingId) state.pendingIds.delete(snapshot.id);\n\t\t}\n\t}\n\n\tprivate async _appendEntry(\n\t\tentry: SessionEntry,\n\t\texplicitParent = false,\n\t\tprepare?: (snapshot: SessionEntry) => void | Promise<void>,\n\t\tonDuplicate?: (entry: SessionEntry) => SessionEntry,\n\t\tassertCurrent?: () => void,\n\t): Promise<SessionEntry> {\n\t\tthis._assertMutable();\n\t\tif (this.indexed)\n\t\t\treturn this._appendIndexedEntry(\n\t\t\t\tthis.writeState,\n\t\t\t\tentry,\n\t\t\t\texplicitParent,\n\t\t\t\tprepare,\n\t\t\t\tonDuplicate,\n\t\t\t\ttrue,\n\t\t\t\tundefined,\n\t\t\t\tassertCurrent,\n\t\t\t);\n\t\tconst state = this.writeState;\n\t\tif (state.failure) throw state.failure;\n\t\tif (state.owner?.format === \"legacy\") throw new Error(\"Session journal requires explicit legacy migration\");\n\t\tif (this.byId.has(entry.id) || state.pendingIds.has(entry.id))\n\t\t\tthrow new Error(`Duplicate session entry: ${entry.id}`);\n\t\tif (!explicitParent) entry.parentId = state.pending ? state.reservedLeaf : this.leafId;\n\t\tlet json = stringifyBoundedJson(entry, MAX_SESSION_RECORD_BYTES);\n\t\tconst retention = entryRetentions.get(entry);\n\t\tconst snapshot = withEntryRetention(JSON.parse(json) as SessionEntry, retention, entryQualifications.get(entry));\n\t\t// Queued usage projection only changes a fixed set of numeric fields.\n\t\tlet parentBytes = 0;\n\t\tif (!explicitParent) {\n\t\t\tparentBytes = Math.max(38, Buffer.byteLength(JSON.stringify(state.leafId)));\n\t\t\tfor (const id of state.pendingIds) parentBytes = Math.max(parentBytes, Buffer.byteLength(JSON.stringify(id)));\n\t\t}\n\t\tconst admittedBytes = Buffer.byteLength(json) + parentBytes + (prepare ? 16 * 1024 : 0);\n\t\tconst entries = this.fileEntries;\n\t\tconst byId = this.byId;\n\t\tconst labels = this.labelsById;\n\t\tconst labelTimes = this.labelTimestampsById;\n\t\tif (state.pending >= MAX_SESSION_PENDING_OPERATIONS || state.bytes + admittedBytes > MAX_SESSION_PENDING_BYTES)\n\t\t\tthrow new Error(\"Session source queue limit exceeded\");\n\t\tstate.reservedLeaf = snapshot.id;\n\t\tstate.pendingIds.add(snapshot.id);\n\t\ttry {\n\t\t\tawait this._enqueue(state, admittedBytes, async () => {\n\t\t\t\tif (!explicitParent) snapshot.parentId = state.leafId;\n\t\t\t\tif (prepare) await prepare(snapshot);\n\t\t\t\tjson = stringifyBoundedJson(snapshot, admittedBytes);\n\t\t\t\tassertCurrent?.();\n\t\t\t\ttry {\n\t\t\t\t\tif (state.owner) {\n\t\t\t\t\t\tconst ack = await appendSourceEntry(state.owner, json, snapshot);\n\t\t\t\t\t\tstate.sequence = ack.sequence;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstate.sequence++;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.failure = new Error(\"Session source append failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tthis._publishHistory(state);\n\t\t\t\tentries.push(snapshot);\n\t\t\t\tbyId.set(snapshot.id, snapshot);\n\t\t\t\tif (snapshot.type === \"compaction\") state.compactionCount++;\n\t\t\t\tif (snapshot.type === \"session_info\") state.sessionName = snapshot.name;\n\t\t\t\tif (snapshot.type === \"label\") {\n\t\t\t\t\tif (snapshot.label) {\n\t\t\t\t\t\tlabels.set(snapshot.targetId, snapshot.label);\n\t\t\t\t\t\tlabelTimes.set(snapshot.targetId, snapshot.timestamp);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlabels.delete(snapshot.targetId);\n\t\t\t\t\t\tlabelTimes.delete(snapshot.targetId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (snapshot.type === \"child_usage_attributed\") {\n\t\t\t\t\tconst target = byId.get(snapshot.targetId);\n\t\t\t\t\tif (target?.type === \"message\" && target.message.role === \"assistant\")\n\t\t\t\t\t\ttarget.message.usage = cloneUsage(snapshot.aggregateUsage);\n\t\t\t\t}\n\t\t\t\tstate.leafId = snapshot.id;\n\t\t\t\tif (!isCompactionBookkeeping(snapshot)) state.compactionRevision++;\n\t\t\t\tif (this.writeState === state) {\n\t\t\t\t\tthis.leafId = snapshot.id;\n\t\t\t\t\tthis._notifyPersistListeners();\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tstate.pendingIds.delete(snapshot.id);\n\t\t}\n\t\treturn snapshot;\n\t}\n\n\tprivate async _closeRetired(state: SessionWriteState): Promise<void> {\n\t\tif (!state.retired || state.pins > 0) return;\n\t\tstate.closing ??= (async () => {\n\t\t\tawait state.tail;\n\t\t\tawait this._closeSourceActors(state);\n\t\t\tstate.closed = true;\n\t\t\tthis.retiredSources.delete(state);\n\t\t})();\n\t\tawait state.closing;\n\t}\n\n\tprivate async _retire(state: SessionWriteState): Promise<void> {\n\t\tstate.retired = true;\n\t\tthis.retiredSources.add(state);\n\t\tawait this._closeRetired(state);\n\t}\n\n\tclose(): Promise<void> {\n\t\tthis.closing ??= (async () => {\n\t\t\tawait this._retire(this.writeState);\n\t\t\tfor (const state of [...this.retiredSources]) {\n\t\t\t\tif (state.pins > 0) {\n\t\t\t\t\tstate.unpinned ??= new Promise<void>((resolve) => {\n\t\t\t\t\t\tstate.onUnpinned = resolve;\n\t\t\t\t\t});\n\t\t\t\t\tawait state.unpinned;\n\t\t\t\t}\n\t\t\t\tawait this._closeRetired(state);\n\t\t\t}\n\t\t})();\n\t\treturn this.closing;\n\t}\n\n\t/** Capture before waits; the barrier resolves only after this source's prior ACKs. */\n\tbindRequestSink(): BoundSessionRequestSink {\n\t\treturn this._bindHistorySource(createBranchHistoryReadView);\n\t}\n\n\t/** Capture ownership, not a history frontier: ordinary appends may finish before the checkpoint capture. */\n\tcaptureCompactionSourceOwner(): () => boolean {\n\t\tconst state = this.writeState;\n\t\tconst owner = state.owner;\n\t\tconst sessionId = this.sessionId;\n\t\tconst sessionFile = this.sessionFile;\n\t\tconst selectionRevision = state.branchSelectionRevision;\n\t\treturn () =>\n\t\t\tthis.writeState === state &&\n\t\t\tstate.owner === owner &&\n\t\t\t!state.retired &&\n\t\t\t!state.closed &&\n\t\t\tthis.sessionId === sessionId &&\n\t\t\tthis.sessionFile === sessionFile &&\n\t\t\tstate.branchSelectionRevision === selectionRevision;\n\t}\n\n\tbindCompactionSink(limits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS): BoundCompactionSink {\n\t\tconst state = this.writeState;\n\t\tconst owner = state.owner;\n\t\tconst sessionId = this.sessionId;\n\t\tconst sessionFile = this.sessionFile;\n\t\tconst indexed = this.indexed;\n\t\tconst byId = this.byId;\n\t\tconst capturedLimits = { ...limits };\n\t\tlet residentBranch: SessionEntry[] | undefined;\n\t\tlet capturedSource: SourceSnapshotRef | undefined;\n\t\tlet captureFailure: unknown;\n\t\tlet selectionRevision: number;\n\t\tlet compactionRevision: number;\n\t\tlet currentRevision: number;\n\t\tconst isCurrent = (revision: number) =>\n\t\t\tcapturedSource !== undefined &&\n\t\t\tthis.writeState === state &&\n\t\t\tstate.owner === owner &&\n\t\t\t!state.retired &&\n\t\t\t!state.closed &&\n\t\t\tthis.sessionId === sessionId &&\n\t\t\tthis.sessionFile === sessionFile &&\n\t\t\tstate.branchSelectionRevision === selectionRevision &&\n\t\t\tstate.compactionRevision === revision;\n\t\tconst sink = this._bindHistorySource(\n\t\t\t(index, source, query) => createSessionHistoryReadScope(index, source, query, \"source\"),\n\t\t\t(source) => {\n\t\t\t\tselectionRevision = state.branchSelectionRevision;\n\t\t\t\tcompactionRevision = state.compactionRevision;\n\t\t\t\tcurrentRevision = compactionRevision;\n\t\t\t\tif (!indexed)\n\t\t\t\t\tresidentBranch = this._readResidentBranches([source.leafId], capturedLimits, byId).branches[0];\n\t\t\t\tcapturedSource = source;\n\t\t\t},\n\t\t);\n\t\tvoid sink.source.catch((error: unknown) => {\n\t\t\tcaptureFailure = error;\n\t\t});\n\t\tconst appendCaptured = async (\n\t\t\tsummary: string,\n\t\t\tfirstKeptEntryId: string,\n\t\t\ttokensBefore: number | null,\n\t\t\tdetails?: unknown,\n\t\t\tfromHook?: boolean,\n\t\t\tinstructions?: string,\n\t\t\tusage?: Usage,\n\t\t\tqualification?: NativeEntryQualification,\n\t\t\trequestOutputSource?: object,\n\t\t): Promise<string> => {\n\t\t\tsink.assertRetained();\n\t\t\tconst values = {\n\t\t\t\tsummary,\n\t\t\t\tfirstKeptEntryId,\n\t\t\t\ttokensBefore,\n\t\t\t\tdetails,\n\t\t\t\tfromHook,\n\t\t\t\tinstructions,\n\t\t\t\tusage: usage ? cloneUsage(usage) : undefined,\n\t\t\t\trequestOutputs:\n\t\t\t\t\tfromHook === false ? takeCompactionRequestOutputs(requestOutputSource, bound, summary) : undefined,\n\t\t\t};\n\t\t\tconst snapshot = JSON.parse(stringifyBoundedJson(values, MAX_SESSION_RECORD_BYTES)) as typeof values;\n\t\t\tconst assertCurrent = () => {\n\t\t\t\tif (captureFailure !== undefined) throw captureFailure;\n\t\t\t\tif (qualification === \"native-context-epoch\") {\n\t\t\t\t\tconst epoch = (snapshot.details as { [CONTEXT_EPOCH_DETAIL]: ContextEpochCheckpoint })[\n\t\t\t\t\t\tCONTEXT_EPOCH_DETAIL\n\t\t\t\t\t];\n\t\t\t\t\tif (JSON.stringify(epoch.source) !== JSON.stringify(capturedSource))\n\t\t\t\t\t\tthrow new Error(\"Context epoch does not match the bound source capture\");\n\t\t\t\t}\n\t\t\t\tif (!isCurrent(compactionRevision)) throw new Error(\"Compaction source or branch changed\");\n\t\t\t};\n\t\t\t// Admission is synchronous; this append queues behind the capture before release can drain it.\n\t\t\tconst args = [\n\t\t\t\tsnapshot.summary,\n\t\t\t\tsnapshot.firstKeptEntryId,\n\t\t\t\tsnapshot.tokensBefore,\n\t\t\t\tsnapshot.details,\n\t\t\t\tsnapshot.fromHook,\n\t\t\t\tsnapshot.instructions,\n\t\t\t\tsnapshot.usage,\n\t\t\t\tassertCurrent,\n\t\t\t] as const;\n\t\t\tconst entryId = await (qualification || snapshot.requestOutputs\n\t\t\t\t? this._appendCompaction(...args, qualification, snapshot.requestOutputs)\n\t\t\t\t: this.appendCompaction(...args));\n\t\t\tcurrentRevision = compactionRevision + 1;\n\t\t\treturn entryId;\n\t\t};\n\t\tconst bound: BoundCompactionSink = {\n\t\t\t...sink,\n\t\t\tisCurrent: () => isCurrent(currentRevision),\n\t\t\treadHistory: (read) => sink.readHistory((history) => read(history.branchContext)),\n\t\t\t[readCopiedEpochSource]: (read) => sink.readHistory(read),\n\t\t\treadBranch: async () => {\n\t\t\t\tif (indexed)\n\t\t\t\t\treturn sink.readHistory(\n\t\t\t\t\t\tasync (history) =>\n\t\t\t\t\t\t\t(await this._readBranchesAt(history, [history.source.leafId], capturedLimits)).branches[0],\n\t\t\t\t\t);\n\t\t\t\tsink.assertRetained();\n\t\t\t\tawait sink.source;\n\t\t\t\treturn residentBranch!.map((entry) =>\n\t\t\t\t\twithEntryRetention(\n\t\t\t\t\t\tJSON.parse(stringifyBoundedJson(entry, capturedLimits.maxSourceBytes)) as SessionEntry,\n\t\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t},\n\t\t\tappendCompaction: (\n\t\t\t\tsummary,\n\t\t\t\tfirstKeptEntryId,\n\t\t\t\ttokensBefore,\n\t\t\t\tdetails,\n\t\t\t\tfromHook,\n\t\t\t\tinstructions,\n\t\t\t\tusage,\n\t\t\t\toutputSource,\n\t\t\t) =>\n\t\t\t\tappendCaptured(\n\t\t\t\t\tsummary,\n\t\t\t\t\tfirstKeptEntryId,\n\t\t\t\t\ttokensBefore,\n\t\t\t\t\tdetails,\n\t\t\t\t\tfromHook,\n\t\t\t\t\tinstructions,\n\t\t\t\t\tusage,\n\t\t\t\t\tundefined,\n\t\t\t\t\toutputSource,\n\t\t\t\t),\n\t\t\t[appendContextEpoch]: (checkpoint, tokensBefore, summary, outputSource) => {\n\t\t\t\tif (checkpoint.policyOnly && (tokensBefore !== null || summary !== undefined))\n\t\t\t\t\tthrow new Error(\"Context mode policy ACK is not a measured request or summary\");\n\t\t\t\tif (Boolean(summary) !== Boolean(checkpoint.includeSummary))\n\t\t\t\t\tthrow new Error(\"Context epoch summary does not match its rendering plan\");\n\t\t\t\treturn appendCaptured(\n\t\t\t\t\tsummary?.summary ?? \"\",\n\t\t\t\t\tcheckpoint.literalTailId,\n\t\t\t\t\ttokensBefore,\n\t\t\t\t\t{ ...summary?.details, [CONTEXT_EPOCH_DETAIL]: checkpoint },\n\t\t\t\t\tsummary?.fromHook ?? false,\n\t\t\t\t\tsummary?.customInstructions,\n\t\t\t\t\tsummary?.usage,\n\t\t\t\t\t\"native-context-epoch\",\n\t\t\t\t\toutputSource,\n\t\t\t\t);\n\t\t\t},\n\t\t};\n\t\tconst outputSource = nativeRequestOutputSources.get(sink);\n\t\tif (outputSource) nativeRequestOutputSources.set(bound, { ...outputSource, compaction: true });\n\t\treturn bound;\n\t}\n\n\tprivate _bindHistorySource<View>(\n\t\tcreateView: (index: HistoryIndex, source: SourceSnapshotRef, query: HistoryReadQuery) => View,\n\t\tonCapture?: (source: SourceSnapshotRef) => void,\n\t): BoundHistoryReadSink<View> & { assertRetained(): void } {\n\t\tthis._assertMutable();\n\t\tconst state = this.writeState;\n\t\tconst sourceFile =\n\t\t\tstate.owner?.journalPath ?? (this.sessionFile ? realpathIfPresent(resolve(this.sessionFile)) : undefined);\n\t\tconst sessionId = this.sessionId;\n\t\tconst persistent = this.persist;\n\t\tconst indexed = this.indexed;\n\t\tconst entries = this.fileEntries;\n\t\tconst byId = this.byId;\n\t\tconst writer = state.owner;\n\t\tconst ownsOutputSource = SessionManager.prototype.captureCompactionSourceOwner.call(this);\n\t\tlet outputSource: SourceSnapshotRef | undefined;\n\t\tlet held = false;\n\t\tconst retain = () => {\n\t\t\tif (held) return;\n\t\t\tif (state.closed || state.closing) throw new Error(\"Captured session source owner is closed\");\n\t\t\theld = true;\n\t\t\tstate.pins++;\n\t\t};\n\t\tconst assertRetained = () => {\n\t\t\tif (!held) throw new Error(\"Captured request sink is not retained\");\n\t\t};\n\t\tretain();\n\t\tconst captured = this._enqueue(state, 0, async () => {\n\t\t\tawait state.owner?.flush();\n\t\t\tconst source: SourceSnapshotRef = Object.freeze({\n\t\t\t\tsessionId,\n\t\t\t\t...(sourceFile ? { sessionFile: sourceFile } : {}),\n\t\t\t\tleafId: state.leafId,\n\t\t\t\tsourceSequence: state.sequence,\n\t\t\t\tpersistent,\n\t\t\t});\n\t\t\tconst snapshot = state.owner?.getSnapshot();\n\t\t\toutputSource = source;\n\t\t\tonCapture?.(source);\n\t\t\treturn { source, snapshot };\n\t\t});\n\t\tconst source = captured.then((value) => value.source);\n\t\t// A captured auxiliary operation can await UI work before consuming its barrier.\n\t\tvoid source.catch(() => undefined);\n\t\tconst sink: BoundHistoryReadSink<View> & { assertRetained(): void } = {\n\t\t\tsource,\n\t\t\tassertRetained,\n\t\t\treadHistory: async <T>(read: (view: View) => Promise<T>): Promise<T> => {\n\t\t\t\tassertRetained();\n\t\t\t\t// A running read holds its own pin if request disposal happens concurrently.\n\t\t\t\tstate.pins++;\n\t\t\t\ttry {\n\t\t\t\t\tconst { source: boundSource, snapshot } = await captured;\n\t\t\t\t\tif (!snapshot || snapshot.format !== \"framed\" || state.sourceVersion !== CURRENT_SESSION_VERSION)\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Indexed history requires an owned canonical session; import or migrate legacy history explicitly\",\n\t\t\t\t\t\t);\n\t\t\t\t\tstate.history ??= new SessionHistoryIndex(\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tjoin(\n\t\t\t\t\t\t\tassertProductStatePath(getSessionArtifactPathForFile(snapshot.journalPath, sessionId)),\n\t\t\t\t\t\t\t\"history.sqlite\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tconst index = await state.history.synchronize(snapshot);\n\t\t\t\t\tlet active = true;\n\t\t\t\t\tconst query: HistoryReadQuery = (operation) => {\n\t\t\t\t\t\tif (!active) return Promise.reject(new Error(\"Captured history read has ended\"));\n\t\t\t\t\t\treturn operation();\n\t\t\t\t\t};\n\t\t\t\t\tconst view = createView(index, boundSource, query);\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn await read(view);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tactive = false;\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tawait this._releaseSourcePin(state);\n\t\t\t\t}\n\t\t\t},\n\t\t\tretain,\n\t\t\trelease: async () => {\n\t\t\t\tif (!held) return;\n\t\t\t\theld = false;\n\t\t\t\tawait this._releaseSourcePin(state);\n\t\t\t},\n\t\t\tpersist: async (event: NativeRequestEvent) => {\n\t\t\t\tassertRetained();\n\t\t\t\tif (state.owner) assertProductStatePath(state.owner.journalPath);\n\t\t\t\tif (state.owner?.format === \"legacy\") throw new Error(\"Session journal requires explicit legacy migration\");\n\t\t\t\tconst snapshot = await source;\n\t\t\t\tconst request = JSON.parse(stringifyBoundedJson(event, 1024 * 1024)) as NativeRequestEvent;\n\t\t\t\tif (!isDeepStrictEqual(request.source, snapshot))\n\t\t\t\t\tthrow new Error(\"Request event does not match its bound source\");\n\t\t\t\tconst id = `${request.attemptId}:${request.type}`;\n\t\t\t\tconst entry: RequestJournalEntry = {\n\t\t\t\t\ttype: \"request\",\n\t\t\t\t\tid,\n\t\t\t\t\tparentId: snapshot.leafId,\n\t\t\t\t\ttimestamp: new Date(request.timestamp).toISOString(),\n\t\t\t\t\trequest,\n\t\t\t\t};\n\t\t\t\tconst json = stringifyBoundedJson(entry, 1024 * 1024 - 1);\n\t\t\t\tif (indexed) {\n\t\t\t\t\tawait this._appendIndexedEntry(\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t(existing) => {\n\t\t\t\t\t\t\tif (existing.type !== \"request\" || !isDeepStrictEqual(existing.request, request))\n\t\t\t\t\t\t\t\tthrow new Error(`Conflicting request event: ${id}`);\n\t\t\t\t\t\t\treturn existing;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait this._enqueue(state, Buffer.byteLength(json), async () => {\n\t\t\t\t\tconst existing = byId.get(id);\n\t\t\t\t\tif (existing) {\n\t\t\t\t\t\tif (existing.type !== \"request\" || !isDeepStrictEqual(existing.request, request))\n\t\t\t\t\t\t\tthrow new Error(`Conflicting request event: ${id}`);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (state.owner) state.sequence = (await state.owner.appendJson(json)).sequence;\n\t\t\t\t\t\telse state.sequence++;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tstate.failure = new Error(\"Session request append failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\tthis._publishHistory(state);\n\t\t\t\t\tentries.push(entry);\n\t\t\t\t\tbyId.set(id, entry);\n\t\t\t\t\tif (this.writeState === state) this._notifyPersistListeners();\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t\tif (persistent && indexed && writer?.format === \"framed\") {\n\t\t\tconst capture: NativeOutputCapture = (association) => {\n\t\t\t\tif (!outputSource || !ownsOutputSource() || !isDeepStrictEqual(association.source, outputSource))\n\t\t\t\t\treturn undefined;\n\t\t\t\treturn structuredClone(association);\n\t\t\t};\n\t\t\tnativeRequestOutputSources.set(sink, {\n\t\t\t\tcapture,\n\t\t\t\tplanner: (association) => {\n\t\t\t\t\tconst request = capture(association);\n\t\t\t\t\tif (!request) return undefined;\n\t\t\t\t\treturn (manager, result) => {\n\t\t\t\t\t\tif (manager !== this || !ownsOutputSource()) return undefined;\n\t\t\t\t\t\tconst stale = new Error(\"Native planner source changed before result append\");\n\t\t\t\t\t\tconst assertCurrent = () => {\n\t\t\t\t\t\t\tif (!ownsOutputSource()) throw stale;\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn (async () => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\treturn await this._appendCustomEntry(\n\t\t\t\t\t\t\t\t\t\"prime-agent.refinement\",\n\t\t\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\t\t\tassertCurrent,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t// Only this final pre-write stale signal permits the ordinary unassociated append.\n\t\t\t\t\t\t\t\tif (error === stale) return undefined;\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})();\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tbranch: (association) => {\n\t\t\t\t\tconst requestOutput = capture(association);\n\t\t\t\t\tif (!requestOutput) return undefined;\n\t\t\t\t\treturn (manager, branchFromId, summary, details, usage) => {\n\t\t\t\t\t\tif (manager !== this || !ownsOutputSource()) return undefined;\n\t\t\t\t\t\tconst stale = new Error(\"Native branch summary source changed before append\");\n\t\t\t\t\t\tconst assertCurrent = () => {\n\t\t\t\t\t\t\tif (!ownsOutputSource()) throw stale;\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn (async () => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\treturn await this._branchWithSummary(branchFromId, summary, details, false, usage, {\n\t\t\t\t\t\t\t\t\trequestOutput,\n\t\t\t\t\t\t\t\t\tassertCurrent,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t// Only our final pre-write stale signal permits the ordinary unassociated append.\n\t\t\t\t\t\t\t\tif (error === stale) return undefined;\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})();\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tmain: (association) => {\n\t\t\t\t\tconst requestOutput = capture(association);\n\t\t\t\t\tif (!requestOutput) return undefined;\n\t\t\t\t\treturn async (manager, message) => {\n\t\t\t\t\t\tif (manager !== this || !ownsOutputSource()) return undefined;\n\t\t\t\t\t\tconst stale = new Error(\"Native request output source changed before append\");\n\t\t\t\t\t\tconst assertCurrent = () => {\n\t\t\t\t\t\t\tif (!ownsOutputSource()) throw stale;\n\t\t\t\t\t\t};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// No new qualification: this is request metadata, not input/task authority.\n\t\t\t\t\t\t\treturn await this._appendMessage(message, undefined, undefined, { requestOutput, assertCurrent });\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t// Only this pre-append stale signal permits the ordinary unassociated append.\n\t\t\t\t\t\t\tif (error === stale) return undefined;\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\treturn sink;\n\t}\n\n\tappendToolInvocation(invocation: ToolInvocation): Promise<string> {\n\t\treturn this._appendToolInvocation(invocation);\n\t}\n\n\tprivate async _appendToolInvocation(\n\t\tinvocation: ToolInvocation,\n\t\tassistant?: ContextEpochEntryRef & { sessionFile: string | undefined },\n\t): Promise<string> {\n\t\tconst id = `${invocation.executionId}:intent`;\n\t\tif (!this.indexed && this.byId.has(id))\n\t\t\tthrow new Error(`Tool invocation already admitted: ${invocation.executionId}`);\n\t\tconst entry: ToolIntentEntry = {\n\t\t\ttype: \"tool_intent\",\n\t\t\tid,\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tinvocation: structuredClone(invocation),\n\t\t\t...(assistant ? { assistant: { ...assistant } } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, assistant ? \"native-tool-execution\" : undefined),\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\t() => {\n\t\t\t\tthrow new Error(`Tool invocation already admitted: ${invocation.executionId}`);\n\t\t\t},\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tappendToolExchange(exchange: FinalizedToolExchange): Promise<string> {\n\t\treturn this._appendToolExchangeOnce(exchange);\n\t}\n\n\tprivate _appendToolExchangeOnce(\n\t\texchange: FinalizedToolExchange,\n\t\tqualification?: \"native-recovery\" | \"native-tool-execution\",\n\t): Promise<string> {\n\t\tconst executionId = exchange.executionId;\n\t\tconst pending = this.pendingToolExchanges.get(executionId);\n\t\tif (pending) return pending;\n\t\tconst result = this._appendToolExchange(exchange, qualification).finally(() => {\n\t\t\tthis.pendingToolExchanges.delete(executionId);\n\t\t});\n\t\tthis.pendingToolExchanges.set(executionId, result);\n\t\treturn result;\n\t}\n\n\tprivate async _appendToolExchange(\n\t\texchange: FinalizedToolExchange,\n\t\tqualification?: \"native-recovery\" | \"native-tool-execution\",\n\t): Promise<string> {\n\t\tif (this.indexed) {\n\t\t\tconst state = this.writeState;\n\t\t\tconst executionId = exchange.executionId;\n\t\t\tconst { result, originalInput, executedInput, ...rest } = exchange;\n\t\t\tconst outcome = structuredClone(rest);\n\t\t\tconst entry: SessionMessageEntry = {\n\t\t\t\ttype: \"message\",\n\t\t\t\tid: executionId,\n\t\t\t\tparentId: this.leafId,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tmessage: structuredClone(result),\n\t\t\t\texecution: structuredClone({\n\t\t\t\t\t...outcome,\n\t\t\t\t\toriginalInput,\n\t\t\t\t\t...(exchange.executionOutcome === \"not_started\" ? {} : { executedInput }),\n\t\t\t\t}),\n\t\t\t};\n\t\t\tconst acknowledged = await this._appendEntry(\n\t\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\t\tfalse,\n\t\t\t\tasync (snapshot) => {\n\t\t\t\t\tconst invocationId = `${executionId}:intent`;\n\t\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\t\tif (await history.get(invocationId))\n\t\t\t\t\t\t(snapshot as SessionMessageEntry).execution = { ...outcome, invocationId };\n\t\t\t\t},\n\t\t\t\t(existing) => {\n\t\t\t\t\tif (existing.type !== \"message\" || existing.execution?.executionId !== executionId)\n\t\t\t\t\t\tthrow new Error(`Conflicting tool execution ID: ${executionId}`);\n\t\t\t\t\treturn existing;\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.finalizedToolMessages.set(result, acknowledged.id);\n\t\t\treturn acknowledged.id;\n\t\t}\n\n\t\tconst existing = this.byId.get(exchange.executionId);\n\t\tif (existing?.type === \"message\" && existing.execution?.executionId === exchange.executionId) {\n\t\t\tthis.finalizedToolMessages.set(exchange.result, existing.id);\n\t\t\treturn existing.id;\n\t\t}\n\t\tif (existing) throw new Error(`Conflicting tool execution ID: ${exchange.executionId}`);\n\t\tconst { result, originalInput, executedInput, ...outcome } = exchange;\n\t\tconst invocationId = `${exchange.executionId}:intent`;\n\t\tconst execution: SessionExecutionEvidence = this.byId.has(invocationId)\n\t\t\t? { ...outcome, invocationId }\n\t\t\t: { ...outcome, originalInput, ...(exchange.executionOutcome === \"not_started\" ? {} : { executedInput }) };\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: exchange.executionId,\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage: structuredClone(result),\n\t\t\texecution: structuredClone(execution),\n\t\t};\n\t\tconst finalized = this.finalizedToolMessages;\n\t\tawait this._appendEntry(withEntryRetention(entry, undefined, qualification));\n\t\tfinalized.set(result, entry.id);\n\t\treturn entry.id;\n\t}\n\n\tgetToolExchange(executionId: string): FinalizedToolExchange | undefined {\n\t\tthis._assertResident();\n\t\tconst entry = this.byId.get(executionId);\n\t\tif (entry?.type !== \"message\" || entry.message.role !== \"toolResult\" || !entry.execution) return undefined;\n\t\tif (\"invocationId\" in entry.execution) {\n\t\t\tconst intent = this.byId.get(entry.execution.invocationId);\n\t\t\tif (intent?.type !== \"tool_intent\") throw new Error(`Missing invocation for tool execution ${executionId}`);\n\t\t\tconst { invocationId: _invocationId, ...outcome } = entry.execution;\n\t\t\tconst { executedInput, ...invocation } = intent.invocation;\n\t\t\treturn {\n\t\t\t\t...invocation,\n\t\t\t\t...outcome,\n\t\t\t\t...(outcome.executionOutcome === \"not_started\" ? {} : { executedInput }),\n\t\t\t\tresult: entry.message,\n\t\t\t};\n\t\t}\n\t\treturn { ...entry.execution, result: entry.message };\n\t}\n\n\t/** Internal native admission. Ordinary append arguments remain descriptive JSON. */\n\t[bindNativeEntryWriter](): NativeEntryWriter {\n\t\tthis._assertMutable();\n\t\tconst state = this.writeState;\n\t\tconst assertWriter = () => {\n\t\t\tthis._assertMutable();\n\t\t\tif (this.writeState !== state || state.retired || state.closed)\n\t\t\t\tthrow new Error(\"Session source changed after native admission capture\");\n\t\t};\n\t\treturn {\n\t\t\tcaptureAgentResult: () => async (data) => {\n\t\t\t\tassertWriter();\n\t\t\t\tif (!this.isPersisted() || !this.getSessionFile() || !this.supportsCapturedHistoryReads())\n\t\t\t\t\tthrow new Error(\"Agent results require an owned persistent session source\");\n\t\t\t\tconst entry: CustomEntry<AgentResultData> = {\n\t\t\t\t\ttype: \"custom\",\n\t\t\t\t\tcustomType: AGENT_RESULT_CUSTOM_TYPE,\n\t\t\t\t\tdata,\n\t\t\t\t\tid: \"\",\n\t\t\t\t\tparentId: this.leafId,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t};\n\t\t\t\tawait this._appendEntry(\n\t\t\t\t\twithEntryRetention(entry, undefined, \"native-recovery\"),\n\t\t\t\t\tfalse,\n\t\t\t\t\t(snapshot) => {\n\t\t\t\t\t\tconst cursor = state.owner!.getSnapshot();\n\t\t\t\t\t\t// Recovery charges the entire encoded frame, including its native qualifier.\n\t\t\t\t\t\tencodeJournalFrame(\n\t\t\t\t\t\t\tsnapshot,\n\t\t\t\t\t\t\t{ sequence: cursor.nextSequence, checksum: cursor.checksum },\n\t\t\t\t\t\t\tDEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\"native-recovery\",\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\tundefined,\n\t\t\t\t\tassertWriter,\n\t\t\t\t);\n\t\t\t\treturn entry.id;\n\t\t\t},\n\t\t\tcaptureSkillSelection: () => ({\n\t\t\t\tassertCurrent: assertWriter,\n\t\t\t\tappend: (capture, producer) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\tif (producer === \"command\")\n\t\t\t\t\t\treturn this._appendCustomEntry(\n\t\t\t\t\t\t\tSELECTED_SKILL_CUSTOM_TYPE,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontent: capture.content,\n\t\t\t\t\t\t\t\t[SELECTED_SKILL_DETAIL]: {\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\tproducer,\n\t\t\t\t\t\t\t\t\tdescriptor: structuredClone(capture.descriptor),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\"native-recovery\",\n\t\t\t\t\t\t\t{ maxSourceBytes: DEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes, assertCurrent: assertWriter },\n\t\t\t\t\t\t);\n\t\t\t\t\treturn this._appendCustomMessageEntry(\n\t\t\t\t\t\tSELECTED_SKILL_CUSTOM_TYPE,\n\t\t\t\t\t\tcapture.content,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t[SELECTED_SKILL_DETAIL]: { version: 1, producer, descriptor: structuredClone(capture.descriptor) },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\"native-recovery\",\n\t\t\t\t\t\t{ maxSourceBytes: DEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes, assertCurrent: assertWriter },\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t}),\n\t\t\tcaptureToolInvocation: (assistant) => {\n\t\t\t\tconst captured = assistant ? { ...assistant } : undefined;\n\t\t\t\tif (\n\t\t\t\t\tcaptured &&\n\t\t\t\t\t(captured.sessionId !== this.getSessionId() ||\n\t\t\t\t\t\ttypeof captured.sessionFile !== \"string\" ||\n\t\t\t\t\t\tcaptured.sessionFile !== this.getSessionFile())\n\t\t\t\t)\n\t\t\t\t\tthrow new Error(\"Tool intent belongs to another assistant owner\");\n\t\t\t\treturn (invocation) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\treturn this._appendToolInvocation(invocation, captured);\n\t\t\t\t};\n\t\t\t},\n\t\t\tcaptureToolExchange: (executionId) => (exchange) => {\n\t\t\t\tassertWriter();\n\t\t\t\tif (exchange.executionId !== executionId) throw new Error(\"Tool execution identity changed\");\n\t\t\t\treturn this._appendToolExchangeOnce(exchange, \"native-tool-execution\");\n\t\t\t},\n\t\t\tcaptureRecoveryExchange: (executionId) => (exchange) => {\n\t\t\t\tassertWriter();\n\t\t\t\tif (exchange.executionId !== executionId) throw new Error(\"Recovery execution identity changed\");\n\t\t\t\treturn this._appendToolExchangeOnce(exchange, \"native-recovery\");\n\t\t\t},\n\t\t\tcaptureMessage: (origin) => {\n\t\t\t\tconst captured = JSON.parse(stringifyBoundedJson(origin, MAX_SESSION_RECORD_BYTES)) as typeof origin;\n\t\t\t\treturn async (message) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\tlet applied = captured;\n\t\t\t\t\tconst selectedSkillRef = captured.selectedSkillRef;\n\t\t\t\t\tif (selectedSkillRef) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tselectedSkillRef.sessionId !== this.getSessionId() ||\n\t\t\t\t\t\t\tselectedSkillRef.sessionFile !== this.getSessionFile()\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tthrow new Error(\"Native input skill capture belongs to another source\");\n\t\t\t\t\t\tconst source = await this.readBranchHistory((history) =>\n\t\t\t\t\t\t\thistory.hydrateEntry(selectedSkillRef.entryId, DEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tassertWriter();\n\t\t\t\t\t\tconst skill =\n\t\t\t\t\t\t\tsource?.source.qualification === \"native-recovery\"\n\t\t\t\t\t\t\t\t? selectedSkillCapture(source.entry)\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tif (!skill) throw new Error(\"Native input selected skill source is unavailable\");\n\t\t\t\t\t\tconst texts =\n\t\t\t\t\t\t\ttypeof message.content === \"string\"\n\t\t\t\t\t\t\t\t? [message.content]\n\t\t\t\t\t\t\t\t: message.content.flatMap((part) => (part.type === \"text\" ? [part.text] : []));\n\t\t\t\t\t\t// This only drops a real producer binding after a body replacement; copied text cannot add one.\n\t\t\t\t\t\tif (!texts.some((text) => text.includes(selectedSkillBlock(skill, selectedSkillRef.entryId))))\n\t\t\t\t\t\t\tapplied = { ...captured, selectedSkillRef: undefined };\n\t\t\t\t\t}\n\t\t\t\t\t// Hooks may replace the body. Input/task admission stays on the original action/record.\n\t\t\t\t\treturn message.role === \"custom\"\n\t\t\t\t\t\t? this._appendCustomMessageEntry(\n\t\t\t\t\t\t\t\tmessage.customType,\n\t\t\t\t\t\t\t\tmessage.content,\n\t\t\t\t\t\t\t\tmessage.display,\n\t\t\t\t\t\t\t\tmessage.details,\n\t\t\t\t\t\t\t\tapplied,\n\t\t\t\t\t\t\t\t\"native-admission\",\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: this._appendMessage(message, applied, \"native-admission\");\n\t\t\t\t};\n\t\t\t},\n\t\t\tcaptureGoalOperation: (origin) => {\n\t\t\t\tconst captured = JSON.parse(stringifyBoundedJson(origin, MAX_SESSION_RECORD_BYTES)) as typeof origin;\n\t\t\t\treturn (goal) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\treturn this._appendCustomEntry(GOAL_STATE_CUSTOM_TYPE, goal, captured, \"native-admission\");\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t}\n\n\tappendMessage(\n\t\tmessage: Message | CustomMessage | BashExecutionMessage,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t): Promise<string> {\n\t\treturn this._appendMessage(message, nativeOrigin);\n\t}\n\n\tprivate async _appendMessage(\n\t\tmessage: Message | CustomMessage | BashExecutionMessage,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t\tqualification?: NativeEntryQualification,\n\t\toutput?: { requestOutput: NativeRequestOutputAssociation; assertCurrent(): void },\n\t): Promise<string> {\n\t\tconst finalized = this.finalizedToolMessages.get(message);\n\t\tif (finalized) return finalized;\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t\t...(nativeOrigin ? { nativeOrigin } : {}),\n\t\t\t...(output ? { requestOutput: output.requestOutput } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\toutput?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tasync appendThinkingLevelChange(thinkingLevel: string): Promise<string> {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendServiceTierChange(serviceTier: ServiceTier): Promise<string> {\n\t\tconst entry: ServiceTierChangeEntry = {\n\t\t\ttype: \"service_tier_change\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tserviceTier,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendModelChange(provider: string, modelId: string): Promise<string> {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number | null,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t\tcustomInstructions?: string,\n\t\tusage?: Usage,\n\t\tassertCurrent?: () => void,\n\t): Promise<string> {\n\t\treturn this._appendCompaction(\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t\tcustomInstructions,\n\t\t\tusage,\n\t\t\tassertCurrent,\n\t\t);\n\t}\n\n\tprivate async _appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number | null,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t\tcustomInstructions?: string,\n\t\tusage?: Usage,\n\t\tassertCurrent?: () => void,\n\t\tqualification?: NativeEntryQualification,\n\t\trequestOutputs?: readonly NativeCompactionRequestOutputAssociation[],\n\t): Promise<string> {\n\t\tconst entry: CompactionEntry<T> = {\n\t\t\ttype: \"compaction\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t\tcustomInstructions,\n\t\t\tusage,\n\t\t\t...(requestOutputs?.length ? { requestOutputs } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tassertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tappendCustomEntry(customType: string, data?: unknown, nativeOrigin?: NativeEntryOrigin): Promise<string> {\n\t\treturn this._appendCustomEntry(customType, data, nativeOrigin);\n\t}\n\n\tprivate async _appendCustomEntry(\n\t\tcustomType: string,\n\t\tdata?: unknown,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t\tqualification?: NativeEntryQualification,\n\t\tselection?: { maxSourceBytes: number; assertCurrent: () => void },\n\t\tplannerOutput?: { request: NativeRequestOutputAssociation; assertCurrent: () => void },\n\t): Promise<string> {\n\t\tconst entry: CustomEntry = {\n\t\t\ttype: \"custom\",\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t\t...(customType === \"prime-agent.refinement\" && plannerOutput ? { plannerRequest: plannerOutput.request } : {}),\n\t\t\t...(nativeOrigin ? { nativeOrigin } : {}),\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tselection\n\t\t\t\t? (snapshot) => {\n\t\t\t\t\t\tstringifyBoundedJson(snapshot, selection.maxSourceBytes);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tundefined,\n\t\t\tplannerOutput?.assertCurrent ?? selection?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tasync appendIpythonSentAgentMessage(\n\t\tdata: PersistedIpythonSentAgentMessage,\n\t): Promise<{ entryId: string; appended: boolean }> {\n\t\tthis._assertMutable();\n\t\tif (!this.indexed) throw new Error(\"Atomic IPython message append requires an indexed owned source\");\n\t\tconst captured = parsePersistedIpythonSentAgentMessage(structuredClone(data));\n\t\tif (!captured) throw new Error(\"Invalid persisted IPython sent message\");\n\t\tconst state = this.writeState;\n\t\tconst entry: CustomEntry<PersistedIpythonSentAgentMessage> = {\n\t\t\ttype: \"custom\",\n\t\t\tid: \"\",\n\t\t\tparentId: state.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType: IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY,\n\t\t\tdata: captured,\n\t\t};\n\t\tlet appended = true;\n\t\tconst acknowledged = await this._appendIndexedEntry(\n\t\t\tstate,\n\t\t\tentry,\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t\tasync (history) => {\n\t\t\t\tlet page = await history.ipythonSentMessages(captured.toolCallId, { messageId: captured.message.id });\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst reference = page.refs[0];\n\t\t\t\t\tif (reference) {\n\t\t\t\t\t\tconst value = await history.hydrateEntry(reference.entryId, MAX_SESSION_RECORD_BYTES);\n\t\t\t\t\t\tif (!value) throw new Error(\"IPython sent message source is unavailable\");\n\t\t\t\t\t\tappended = false;\n\t\t\t\t\t\treturn value.entry;\n\t\t\t\t\t}\n\t\t\t\t\tif (!page.nextCursor) return undefined;\n\t\t\t\t\tpage = await history.ipythonSentMessages(captured.toolCallId, {\n\t\t\t\t\t\tmessageId: captured.message.id,\n\t\t\t\t\t\tcursor: page.nextCursor,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t\treturn { entryId: acknowledged.id, appended };\n\t}\n\n\tasync appendCustomEntryWithRollback(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendCustomEntry(customType, data);\n\t}\n\n\tasync appendChildUsageAttribution(\n\t\ttargetId: string,\n\t\tchildUsage: Usage,\n\t\taggregateUsage?: Usage,\n\t\torigin?: ChildUsageAttributionEntry[\"origin\"],\n\t): Promise<string> {\n\t\treturn (await this.appendChildUsageAttributionWithAggregate(targetId, childUsage, aggregateUsage, origin))\n\t\t\t.entryId;\n\t}\n\n\tasync appendChildUsageAttributionWithAggregate(\n\t\ttargetId: string,\n\t\tchildUsage: Usage,\n\t\taggregateUsage?: Usage,\n\t\torigin?: ChildUsageAttributionEntry[\"origin\"],\n\t): Promise<ChildUsageAttributionAcknowledgement> {\n\t\tconst state = this.writeState;\n\t\tconst indexed = this.indexed;\n\t\tconst residentTarget = indexed ? undefined : this.byId.get(targetId);\n\t\tif (!indexed && (residentTarget?.type !== \"message\" || residentTarget.message.role !== \"assistant\"))\n\t\t\tthrow new Error(`Assistant message entry ${targetId} not found`);\n\t\tconst entry: ChildUsageAttributionEntry = {\n\t\t\ttype: \"child_usage_attributed\",\n\t\t\tid: indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tchildUsage: cloneUsage(childUsage),\n\t\t\taggregateUsage: cloneUsage(aggregateUsage ?? emptyUsage()),\n\t\t\t...(origin ? { origin } : {}),\n\t\t};\n\t\tconst acknowledged = await this._appendEntry(entry, false, async (snapshot) => {\n\t\t\tif (snapshot.type !== \"child_usage_attributed\") throw new Error(\"Expected child usage projection\");\n\t\t\tlet target = residentTarget;\n\t\t\tlet history: SessionHistoryReadScope | undefined;\n\t\t\tif (indexed) {\n\t\t\t\thistory = await this._acknowledgedHistory(state);\n\t\t\t\ttarget = (await history.hydrateEntry(targetId, MAX_SESSION_RECORD_BYTES))?.entry;\n\t\t\t}\n\t\t\tif (target?.type !== \"message\" || target.message.role !== \"assistant\")\n\t\t\t\tthrow new Error(`Assistant message entry ${targetId} not found`);\n\t\t\tif (aggregateUsage === undefined) {\n\t\t\t\tlet usage = target.message.usage;\n\t\t\t\tif (history) {\n\t\t\t\t\tconst reference = await history.sourceAssistantUsage(targetId);\n\t\t\t\t\tif (reference) {\n\t\t\t\t\t\tconst aggregate = await history.hydrateEntry(reference.id, MAX_SESSION_RECORD_BYTES);\n\t\t\t\t\t\tif (!aggregate || aggregate.entry.type !== \"child_usage_attributed\")\n\t\t\t\t\t\t\tthrow new Error(\"Stored assistant aggregate source is unavailable\");\n\t\t\t\t\t\tusage = cloneUsage(aggregate.entry.aggregateUsage);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst total = cloneUsage(usage);\n\t\t\t\tconst contextTokens = total.totalTokens || total.input + total.output + total.cacheRead + total.cacheWrite;\n\t\t\t\taddAssistantUsage(total, snapshot.childUsage);\n\t\t\t\ttotal.totalTokens = contextTokens;\n\t\t\t\tsnapshot.aggregateUsage = total;\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tentryId: acknowledged.id,\n\t\t\taggregateUsage: cloneUsage((acknowledged as ChildUsageAttributionEntry).aggregateUsage),\n\t\t};\n\t}\n\n\tasync appendSessionInfo(name: string): Promise<string> {\n\t\tconst entry: SessionInfoEntry = {\n\t\t\ttype: \"session_info\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: name.trim(),\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendSessionState(state: SessionState): Promise<string> {\n\t\tconst entry: SessionStateEntry = {\n\t\t\ttype: \"session_state\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tstate: { status: state.status },\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tgetSessionName(): string | undefined {\n\t\treturn this.writeState.sessionName?.trim() || undefined;\n\t}\n\n\tgetSessionState(): SessionState | undefined {\n\t\tif (this.indexed) {\n\t\t\tconst state = this.writeState.sessionState;\n\t\t\treturn state ? { ...state } : undefined;\n\t\t}\n\t\tconst entries = this.getEntries();\n\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\tconst entry = entries[i];\n\t\t\tif (entry.type === \"session_state\") {\n\t\t\t\tconst status = normalizeSessionStateStatus(entry.state.status);\n\t\t\t\tif (status) {\n\t\t\t\t\treturn { status };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * True when the session holds user-meaningful persisted content, as opposed to\n\t * only daemon-written bookkeeping (session_state, agent_status, git_state) or\n\t * the default model/thinking entries every new session is created with. Used by\n\t * the daemon discard guard to decide whether a message-less draft is safe to\n\t * delete (that guard always also requires zero messages).\n\t *\n\t * createAgentSession opens a new session with an optional leading `model_change`\n\t * followed by `thinking_level_change` and `service_tier_change`. That creation\n\t * prefix is skipped; anything beyond it is user content.\n\t */\n\thasUserContent(): boolean {\n\t\tif (this.indexed) {\n\t\t\tif (this.writeState.hasUserContent === undefined) throw new Error(\"Owned session metadata is unavailable\");\n\t\t\treturn this.writeState.hasUserContent;\n\t\t}\n\t\tconst contentEntries = this.getEntries().filter((entry) => CONTENT_ENTRY_TYPES.has(entry.type));\n\t\tlet start = 0;\n\t\tif (contentEntries[start]?.type === \"model_change\") {\n\t\t\tstart++;\n\t\t}\n\t\tif (contentEntries[start]?.type === \"thinking_level_change\") {\n\t\t\tstart++;\n\t\t}\n\t\tif (contentEntries[start]?.type === \"service_tier_change\") {\n\t\t\tstart++;\n\t\t}\n\t\treturn contentEntries.length > start;\n\t}\n\n\tasync appendAgentStatus(status: AgentStatus): Promise<string> {\n\t\tconst entry: AgentStatusEntry = {\n\t\t\ttype: \"agent_status\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tstatus: {\n\t\t\t\tsummary: status.summary,\n\t\t\t\ttaskState: status.taskState,\n\t\t\t\tbasedOnMessageCount: status.basedOnMessageCount,\n\t\t\t},\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendGitState(git: GitContext): Promise<string> {\n\t\tconst entry: GitStateEntry = {\n\t\t\ttype: \"git_state\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tgit,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync recordGitStateIfChanged(): Promise<string | undefined> {\n\t\tif (!this.persist) return undefined;\n\t\tconst git = captureGitContext(this.cwd);\n\t\tif (!git) return undefined;\n\t\tconst last = this.getActiveGitContext();\n\t\tif (last && gitContextsEqual(last, git)) return undefined;\n\t\treturn this.appendGitState(git);\n\t}\n\n\tprivate getActiveGitContext(): GitContext | undefined {\n\t\tif (this.indexed) return this.writeState.git;\n\t\tlet current = this.leafId ? this.byId.get(this.leafId) : undefined;\n\t\twhile (current) {\n\t\t\tif (current.type === \"git_state\") return current.git;\n\t\t\tcurrent = current.parentId ? this.byId.get(current.parentId) : undefined;\n\t\t}\n\t\tconst header = this.fileEntries[0];\n\t\treturn header?.type === \"session\" ? header.git : undefined;\n\t}\n\n\tgetLatestAgentStatus(): AgentStatus | undefined {\n\t\tif (this.indexed) return this.writeState.agentStatus ? { ...this.writeState.agentStatus } : undefined;\n\t\t// Walk the current leaf to root so we only read status on the active branch,\n\t\t// not a sibling branch's status that happens to sit later in the file.\n\t\tlet current = this.leafId ? this.byId.get(this.leafId) : undefined;\n\t\twhile (current) {\n\t\t\tif (current.type === \"agent_status\") {\n\t\t\t\treturn { ...current.status };\n\t\t\t}\n\t\t\tcurrent = current.parentId ? this.byId.get(current.parentId) : undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tappendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t): Promise<string> {\n\t\treturn this._appendCustomMessageEntry(customType, content, display, details, nativeOrigin);\n\t}\n\n\tprivate async _appendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t\tqualification?: NativeEntryQualification,\n\t\tselection?: { maxSourceBytes: number; assertCurrent: () => void },\n\t): Promise<string> {\n\t\tconst entry: CustomMessageEntry<T> = {\n\t\t\ttype: \"custom_message\",\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t\t...(nativeOrigin ? { nativeOrigin } : {}),\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tselection\n\t\t\t\t? (snapshot) => {\n\t\t\t\t\t\tstringifyBoundedJson(snapshot, selection.maxSourceBytes);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tundefined,\n\t\t\tselection?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Append a custom message, undoing the append if persistence fails so a\n\t * best-effort record never leaves an unsaved leaf for later entries.\n\t */\n\tasync appendCustomMessageEntryWithRollback<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): Promise<string> {\n\t\treturn this.appendCustomMessageEntry(customType, content, display, details);\n\t}\n\n\tasync readEntry(\n\t\tid: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<SessionEntry | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) {\n\t\t\tconst entry = this.getEntry(id);\n\t\t\treturn entry\n\t\t\t\t? withEntryRetention(\n\t\t\t\t\t\tJSON.parse(stringifyBoundedJson(entry, maxSourceBytes)) as SessionEntry,\n\t\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst value = await this._storedEntry(history, id, maxSourceBytes);\n\t\t\treturn value ? withEntryRetention(value.entry, value.source.retention, value.source.qualification) : undefined;\n\t\t});\n\t}\n\n\tasync readLeafEntry(\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<SessionEntry | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) return this.leafId ? this.readEntry(this.leafId, maxSourceBytes) : undefined;\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tif (history.source.leafId === null) return undefined;\n\t\t\tconst value = await this._storedEntry(history, history.source.leafId, maxSourceBytes);\n\t\t\treturn value ? withEntryRetention(value.entry, value.source.retention, value.source.qualification) : undefined;\n\t\t});\n\t}\n\n\tasync readEntryRetention(id: string): Promise<JournalFrameRetention | undefined> {\n\t\tif (!this.indexed) return this.getEntryRetention(id);\n\t\treturn this.readSourceHistory(async (history) => (await history.get(id))?.retention);\n\t}\n\n\tasync readLabel(\n\t\tid: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<string | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) {\n\t\t\tconst label = this.getLabel(id);\n\t\t\treturn label === undefined ? undefined : (JSON.parse(stringifyBoundedJson(label, maxSourceBytes)) as string);\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst reference = await history.sourceLabel(id);\n\t\t\tif (!reference) return undefined;\n\t\t\tconst value = await history.hydrateEntry(reference.id, maxSourceBytes);\n\t\t\tif (!value || value.entry.type !== \"label\") throw new Error(\"Label source is unavailable\");\n\t\t\treturn value.entry.label || undefined;\n\t\t});\n\t}\n\n\tasync readEntries(limits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS): Promise<SessionEntry[]> {\n\t\tconst capturedLimits = { ...limits };\n\t\tif (!this.indexed) {\n\t\t\tconst resident = this.materializeResidentHistory(capturedLimits);\n\t\t\treturn resident.entries.map((entry, index) =>\n\t\t\t\twithEntryRetention(\n\t\t\t\t\tentry,\n\t\t\t\t\tresident.retentions[index] ?? undefined,\n\t\t\t\t\tresident.qualifications[index] ?? undefined,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst result = await history.materialize(capturedLimits);\n\t\t\tconst entries = result.entries.map(({ entry, source }) =>\n\t\t\t\twithEntryRetention(entry, source.retention, source.qualification),\n\t\t\t);\n\t\t\tapplyChildUsageAttributions(entries);\n\t\t\treturn entries;\n\t\t});\n\t}\n\n\tprivate async _readBranchesAt(\n\t\thistory: SessionHistoryReadScope,\n\t\tleafIds: readonly (string | null)[],\n\t\tlimits: SessionHistoryReadLimits,\n\t): Promise<{ source: SourceSnapshotRef; branches: SessionEntry[][]; sourceBytes: number }> {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tconst loaded = new Map<string, SessionEntry>();\n\t\tlet sourceBytes = 0;\n\t\tconst load = async (reference: IndexedSourceEvent) => {\n\t\t\tconst existing = loaded.get(reference.id);\n\t\t\tif (existing) return existing;\n\t\t\tif (loaded.size >= maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\tconst remaining = maxSourceBytes - sourceBytes;\n\t\t\tsourceBytes += reference.locator.length;\n\t\t\tif (sourceBytes > maxSourceBytes) throw new Error(\"Parent-path source byte budget exceeded\");\n\t\t\tconst value = await history.hydrateEntry(reference.id, remaining);\n\t\t\tif (!value) throw new Error(\"Parent-path entry source is unavailable\");\n\t\t\tconst entry = withEntryRetention(value.entry, value.source.retention, value.source.qualification);\n\t\t\tloaded.set(entry.id, entry);\n\t\t\treturn entry;\n\t\t};\n\t\tconst branches: SessionEntry[][] = [];\n\t\tfor (const leafId of leafIds) {\n\t\t\tconst branch: SessionEntry[] = [];\n\t\t\tlet page = await history.parentPathFrom(leafId);\n\t\t\tfor (;;) {\n\t\t\t\tif (page.totalEntries > maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\t\tfor (const reference of page.events) branch.push(await load(reference));\n\t\t\t\tif (!page.nextCursor) break;\n\t\t\t\tpage = await history.parentPathFrom(leafId, { cursor: page.nextCursor });\n\t\t\t}\n\t\t\tbranches.push(branch);\n\t\t}\n\t\tfor (const entry of loaded.values()) {\n\t\t\tif (entry.type !== \"message\" || entry.message.role !== \"assistant\") continue;\n\t\t\tconst reference = await history.sourceAssistantUsage(entry.id);\n\t\t\tif (!reference) continue;\n\t\t\tconst aggregate = await load(reference);\n\t\t\tif (aggregate.type !== \"child_usage_attributed\")\n\t\t\t\tthrow new Error(\"Stored assistant aggregate source is unavailable\");\n\t\t\tentry.message.usage = cloneUsage(aggregate.aggregateUsage);\n\t\t}\n\t\treturn { source: history.source, branches, sourceBytes };\n\t}\n\n\tprivate _residentParentPath(id: string | null, byId = this.byId): SessionEntry[] {\n\t\tconst entries: SessionEntry[] = [];\n\t\tconst seen = new Set<string>();\n\t\tlet current = id;\n\t\twhile (current !== null) {\n\t\t\tif (seen.has(current)) throw new Error(\"Parent path lineage is unresolved\");\n\t\t\tseen.add(current);\n\t\t\tconst entry = byId.get(current);\n\t\t\tif (!entry) throw new Error(\"Parent path lineage is unresolved\");\n\t\t\tentries.push(entry);\n\t\t\tcurrent = entry.parentId;\n\t\t}\n\t\treturn entries.reverse();\n\t}\n\n\tasync readBranches(\n\t\tleafIds: readonly (string | null)[],\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<{ source?: SourceSnapshotRef; branches: SessionEntry[][]; sourceBytes: number }> {\n\t\tconst ids = [...leafIds];\n\t\tconst capturedLimits = { ...limits };\n\t\tif (this.indexed) return this.readSourceHistory((history) => this._readBranchesAt(history, ids, capturedLimits));\n\t\treturn this._readResidentBranches(ids, capturedLimits, this.byId);\n\t}\n\n\tprivate _readResidentBranches(\n\t\tids: readonly (string | null)[],\n\t\tlimits: SessionHistoryReadLimits,\n\t\tbyId: Map<string, SessionEntry>,\n\t): { branches: SessionEntry[][]; sourceBytes: number } {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tconst cloned = new Map<string, SessionEntry>();\n\t\tlet sourceBytes = 0;\n\t\tconst branches = ids.map((id) =>\n\t\t\tthis._residentParentPath(id, byId).map((entry) => {\n\t\t\t\tconst existing = cloned.get(entry.id);\n\t\t\t\tif (existing) return existing;\n\t\t\t\tif (cloned.size >= maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\t\tconst json = stringifyBoundedJson(entry, maxSourceBytes - sourceBytes);\n\t\t\t\tsourceBytes += Buffer.byteLength(json);\n\t\t\t\tconst copy = withEntryRetention(\n\t\t\t\t\tJSON.parse(json) as SessionEntry,\n\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t);\n\t\t\t\tcloned.set(copy.id, copy);\n\t\t\t\treturn copy;\n\t\t\t}),\n\t\t);\n\t\treturn { branches, sourceBytes };\n\t}\n\n\tasync readBranch(\n\t\tfromId?: string | null,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionEntry[]> {\n\t\tconst capturedLimits = { ...limits };\n\t\tif (!this.indexed)\n\t\t\treturn (await this.readBranches([fromId === undefined ? this.leafId : fromId], capturedLimits)).branches[0];\n\t\treturn this.readSourceHistory(\n\t\t\tasync (history) =>\n\t\t\t\t(\n\t\t\t\t\tawait this._readBranchesAt(\n\t\t\t\t\t\thistory,\n\t\t\t\t\t\t[fromId === undefined ? history.source.leafId : fromId],\n\t\t\t\t\t\tcapturedLimits,\n\t\t\t\t\t)\n\t\t\t\t).branches[0],\n\t\t);\n\t}\n\n\tasync branchTo(id: string | null): Promise<void> {\n\t\tthis._assertMutable();\n\t\tif (!this.indexed) {\n\t\t\tif (id === null) this.resetLeaf();\n\t\t\telse this.branch(id);\n\t\t\treturn;\n\t\t}\n\t\tconst state = this.writeState;\n\t\tif (state.pending > 0) throw new Error(\"Drain session writes before changing the branch\");\n\t\tawait this._enqueue(state, 0, async () => {\n\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\tif (id !== null && !(await history.get(id))) throw new Error(`Entry ${id} not found`);\n\t\t\tconst previous = state.leafId;\n\t\t\tstate.leafId = id;\n\t\t\ttry {\n\t\t\t\tawait this._refreshOwnedMetadata(state);\n\t\t\t\tif (id !== previous) state.branchSelectionRevision++;\n\t\t\t} catch (error) {\n\t\t\t\tstate.leafId = previous;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t});\n\t}\n\n\tgetLeafId(): string | null {\n\t\treturn this.leafId;\n\t}\n\n\tgetLeafEntry(): SessionEntry | undefined {\n\t\tthis._assertResident();\n\t\treturn this.leafId ? this.byId.get(this.leafId) : undefined;\n\t}\n\n\tgetEntry(id: string): SessionEntry | undefined {\n\t\tthis._assertResident();\n\t\treturn this.byId.get(id);\n\t}\n\n\tgetChildren(parentId: string): SessionEntry[] {\n\t\tthis._assertResident();\n\t\tconst children: SessionEntry[] = [];\n\t\tfor (const entry of this.byId.values()) {\n\t\t\tif (entry.parentId === parentId) {\n\t\t\t\tchildren.push(entry);\n\t\t\t}\n\t\t}\n\t\treturn children;\n\t}\n\n\tgetLabel(id: string): string | undefined {\n\t\tthis._assertResident();\n\t\treturn this.labelsById.get(id);\n\t}\n\n\tasync appendLabelChange(targetId: string, label: string | undefined): Promise<string> {\n\t\tconst state = this.writeState;\n\t\tif (!this.indexed && !this.byId.has(targetId)) {\n\t\t\tthrow new Error(`Entry ${targetId} not found`);\n\t\t}\n\t\tconst entry: LabelEntry = {\n\t\t\ttype: \"label\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\tentry,\n\t\t\tfalse,\n\t\t\tthis.indexed\n\t\t\t\t? async () => {\n\t\t\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\t\t\tif (!(await history.get(targetId))) throw new Error(`Entry ${targetId} not found`);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t);\n\n\t\treturn entry.id;\n\t}\n\n\tgetBranch(fromId?: string): SessionEntry[] {\n\t\tthis._assertResident();\n\t\t// push+reverse, not unshift-per-entry: unshift is O(n), which makes this O(n^2) on long sessions.\n\t\tconst path: SessionEntry[] = [];\n\t\tconst startId = fromId ?? this.leafId;\n\t\tlet current = startId ? this.byId.get(startId) : undefined;\n\t\twhile (current) {\n\t\t\tpath.push(current);\n\t\t\tcurrent = current.parentId ? this.byId.get(current.parentId) : undefined;\n\t\t}\n\t\tpath.reverse();\n\t\treturn path;\n\t}\n\n\tbuildSessionContext(): SessionContext {\n\t\tthis._assertResident();\n\t\t// Pass fileEntries directly rather than getEntries(): the resolved context\n\t\t// is computed from the leaf-to-root walk over byId (which already excludes\n\t\t// the header), so the entries argument is only a fallback for an undefined\n\t\t// leaf — never hit here since leafId is always set or null. Avoids an O(n)\n\t\t// array copy on every call (attach, get_session_context, agent init, ...).\n\t\treturn buildSessionContext(this.fileEntries as SessionEntry[], this.leafId, this.byId);\n\t}\n\n\tgetHeader(): SessionHeader | null {\n\t\tif (this.indexed) return this.header;\n\t\tconst header = this.fileEntries.find((entry) => entry.type === \"session\");\n\t\treturn header ? (header as SessionHeader) : null;\n\t}\n\n\t/** A lowering-only source qualification; absence does not establish native authorship. */\n\tgetEntryRetention(entryId: string): JournalFrameRetention | undefined {\n\t\tthis._assertResident();\n\t\tconst entry = this.byId.get(entryId);\n\t\treturn entry ? entryRetentions.get(entry) : undefined;\n\t}\n\n\t/** Whole-source count published with acknowledged entries, independent of the current branch. */\n\tgetCompactionCount(): number {\n\t\treturn this.writeState.compactionCount;\n\t}\n\n\t/** Complete detached snapshot of this resident view, including readonly and in-memory views. */\n\tmaterializeResidentHistory(limits: SessionHistoryReadLimits): ResidentSessionHistory {\n\t\tthis._assertResident();\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid resident history materialization limits\");\n\t\tconst leafId = this.leafId;\n\t\tlet sourceBytes = 0;\n\t\tconst clone = <T extends FileEntry>(entry: T): T => {\n\t\t\tconst json = stringifyBoundedJson(entry, maxSourceBytes - sourceBytes);\n\t\t\tsourceBytes += Buffer.byteLength(json);\n\t\t\treturn JSON.parse(json) as T;\n\t\t};\n\t\tconst originalHeader = this.getHeader();\n\t\tconst header = originalHeader ? clone(originalHeader) : null;\n\t\tconst entries: SessionEntry[] = [];\n\t\tconst retentions: (JournalFrameRetention | null)[] = [];\n\t\tconst qualifications: (NativeEntryQualification | null)[] = [];\n\t\tfor (const entry of this.fileEntries) {\n\t\t\tif (entry.type === \"session\") continue;\n\t\t\tif (entries.length >= maxEntries) throw new Error(\"Resident history entry budget exceeded\");\n\t\t\tentries.push(clone(entry));\n\t\t\tretentions.push(entryRetentions.get(entry) ?? null);\n\t\t\tqualifications.push(entryQualifications.get(entry) ?? null);\n\t\t}\n\t\treturn { header, entries, retentions, qualifications, leafId, sourceBytes };\n\t}\n\n\tgetEntries(): SessionEntry[] {\n\t\tthis._assertResident();\n\t\treturn this.fileEntries.filter((e): e is SessionEntry => e.type !== \"session\");\n\t}\n\n\tasync readFlatTree(\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionTreeFlatNode[]> {\n\t\tconst entries = await this.readEntries({ ...limits });\n\t\tconst byId = new Map(entries.map((entry) => [entry.id, entry]));\n\t\tconst labels = new Map<string, { value: string; timestamp: string }>();\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type !== \"label\") continue;\n\t\t\tif (entry.label) labels.set(entry.targetId, { value: entry.label, timestamp: entry.timestamp });\n\t\t\telse labels.delete(entry.targetId);\n\t\t}\n\t\treturn entries\n\t\t\t.filter(\n\t\t\t\t(entry): entry is Exclude<SessionEntry, PrivateSessionEntry> =>\n\t\t\t\t\tentry.type !== \"tool_intent\" && entry.type !== \"request\",\n\t\t\t)\n\t\t\t.map((entry) => {\n\t\t\t\tlet parentId = entry.parentId;\n\t\t\t\tlet parent = parentId ? byId.get(parentId) : undefined;\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\twhile (parent?.type === \"tool_intent\" || parent?.type === \"request\") {\n\t\t\t\t\tif (seen.has(parent.id)) throw new Error(\"Session tree private ancestry is unresolved\");\n\t\t\t\t\tseen.add(parent.id);\n\t\t\t\t\tparentId = parent.parentId;\n\t\t\t\t\tparent = parentId ? byId.get(parentId) : undefined;\n\t\t\t\t}\n\t\t\t\tconst label = labels.get(entry.id);\n\t\t\t\treturn {\n\t\t\t\t\tentry:\n\t\t\t\t\t\tparentId === entry.parentId\n\t\t\t\t\t\t\t? entry\n\t\t\t\t\t\t\t: withEntryRetention(\n\t\t\t\t\t\t\t\t\t{ ...entry, parentId },\n\t\t\t\t\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\tlabel: label?.value,\n\t\t\t\t\tlabelTimestamp: label?.timestamp,\n\t\t\t\t};\n\t\t\t});\n\t}\n\n\tasync readTree(limits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS): Promise<SessionTreeNode[]> {\n\t\tconst entries = await this.readFlatTree({ ...limits });\n\t\tconst nodes = new Map<string, SessionTreeNode>();\n\t\tconst roots: SessionTreeNode[] = [];\n\t\tfor (const entry of entries) nodes.set(entry.entry.id, { ...entry, children: [] });\n\t\tfor (const flat of entries) {\n\t\t\tconst node = nodes.get(flat.entry.id)!;\n\t\t\tconst parent =\n\t\t\t\tflat.entry.parentId === null || flat.entry.parentId === flat.entry.id\n\t\t\t\t\t? undefined\n\t\t\t\t\t: nodes.get(flat.entry.parentId);\n\t\t\tif (parent) parent.children.push(node);\n\t\t\telse roots.push(node);\n\t\t}\n\t\tconst stack = [...roots];\n\t\twhile (stack.length) {\n\t\t\tconst node = stack.pop()!;\n\t\t\tnode.children.sort(\n\t\t\t\t(left, right) => new Date(left.entry.timestamp).getTime() - new Date(right.entry.timestamp).getTime(),\n\t\t\t);\n\t\t\tstack.push(...node.children);\n\t\t}\n\t\treturn roots;\n\t}\n\n\tasync readToolExchange(\n\t\texecutionId: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<FinalizedToolExchange | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) {\n\t\t\tconst exchange = this.getToolExchange(executionId);\n\t\t\treturn exchange\n\t\t\t\t? (JSON.parse(stringifyBoundedJson(exchange, maxSourceBytes)) as FinalizedToolExchange)\n\t\t\t\t: undefined;\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst value = await history.hydrateEntry(executionId, maxSourceBytes);\n\t\t\tconst entry = value?.entry;\n\t\t\tif (entry?.type !== \"message\" || entry.message.role !== \"toolResult\" || !entry.execution) return undefined;\n\t\t\tif (!(\"invocationId\" in entry.execution)) return { ...entry.execution, result: entry.message };\n\t\t\tconst intentValue = await history.hydrateEntry(\n\t\t\t\tentry.execution.invocationId,\n\t\t\t\tmaxSourceBytes - value!.source.locator.length,\n\t\t\t);\n\t\t\tif (intentValue?.entry.type !== \"tool_intent\")\n\t\t\t\tthrow new Error(`Missing invocation for tool execution ${executionId}`);\n\t\t\tconst { invocationId: _invocationId, ...outcome } = entry.execution;\n\t\t\tconst { executedInput, ...invocation } = intentValue.entry.invocation;\n\t\t\treturn {\n\t\t\t\t...invocation,\n\t\t\t\t...outcome,\n\t\t\t\t...(outcome.executionOutcome === \"not_started\" ? {} : { executedInput }),\n\t\t\t\tresult: entry.message,\n\t\t\t};\n\t\t});\n\t}\n\n\tgetFlatTree(): SessionTreeFlatNode[] {\n\t\tthis._assertResident();\n\t\treturn this.getEntries()\n\t\t\t.filter(\n\t\t\t\t(entry): entry is Exclude<SessionEntry, PrivateSessionEntry> =>\n\t\t\t\t\tentry.type !== \"tool_intent\" && entry.type !== \"request\",\n\t\t\t)\n\t\t\t.map((entry) => {\n\t\t\t\t// Internal intent records remain in source history, not the conversation tree.\n\t\t\t\tlet parentId = entry.parentId;\n\t\t\t\tlet parent = parentId ? this.byId.get(parentId) : undefined;\n\t\t\t\twhile (parent?.type === \"tool_intent\" || parent?.type === \"request\") {\n\t\t\t\t\tparentId = parent.parentId;\n\t\t\t\t\tparent = parentId ? this.byId.get(parentId) : undefined;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tentry: parentId === entry.parentId ? entry : { ...entry, parentId },\n\t\t\t\t\tlabel: this.labelsById.get(entry.id),\n\t\t\t\t\tlabelTimestamp: this.labelTimestampsById.get(entry.id),\n\t\t\t\t};\n\t\t\t});\n\t}\n\n\tgetTree(): SessionTreeNode[] {\n\t\tconst entries = this.getFlatTree();\n\t\tconst nodeMap = new Map<string, SessionTreeNode>();\n\t\tconst roots: SessionTreeNode[] = [];\n\n\t\tfor (const flatNode of entries) {\n\t\t\tnodeMap.set(flatNode.entry.id, { ...flatNode, children: [] });\n\t\t}\n\n\t\tfor (const flatNode of entries) {\n\t\t\tconst entry = flatNode.entry;\n\t\t\tconst node = nodeMap.get(entry.id)!;\n\t\t\tif (entry.parentId === null || entry.parentId === entry.id) {\n\t\t\t\troots.push(node);\n\t\t\t} else {\n\t\t\t\tconst parent = nodeMap.get(entry.parentId);\n\t\t\t\tif (parent) {\n\t\t\t\t\tparent.children.push(node);\n\t\t\t\t} else {\n\t\t\t\t\troots.push(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sort children by timestamp (oldest first, newest at bottom)\n\t\t// Use iterative approach to avoid stack overflow on deep trees\n\t\tconst stack: SessionTreeNode[] = [...roots];\n\t\twhile (stack.length > 0) {\n\t\t\tconst node = stack.pop()!;\n\t\t\tnode.children.sort((a, b) => new Date(a.entry.timestamp).getTime() - new Date(b.entry.timestamp).getTime());\n\t\t\tstack.push(...node.children);\n\t\t}\n\n\t\treturn roots;\n\t}\n\n\tbranch(branchFromId: string): void {\n\t\tthis._assertResident();\n\t\tif (!this.byId.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tif (this.writeState.pending > 0) throw new Error(\"Drain session writes before changing the branch\");\n\t\tif (this.writeState.leafId !== branchFromId) this.writeState.branchSelectionRevision++;\n\t\tthis.leafId = branchFromId;\n\t\tthis.writeState.leafId = branchFromId;\n\t\tthis.writeState.reservedLeaf = branchFromId;\n\t}\n\n\tresetLeaf(): void {\n\t\tthis._assertResident();\n\t\tif (this.writeState.pending > 0) throw new Error(\"Drain session writes before changing the branch\");\n\t\tif (this.writeState.leafId !== null) this.writeState.branchSelectionRevision++;\n\t\tthis.leafId = null;\n\t\tthis.writeState.leafId = null;\n\t\tthis.writeState.reservedLeaf = null;\n\t}\n\n\tbranchWithSummary(\n\t\tbranchFromId: string | null,\n\t\tsummary: string,\n\t\tdetails?: unknown,\n\t\tfromHook?: boolean,\n\t\tusage?: Usage,\n\t): Promise<string> {\n\t\treturn this._branchWithSummary(branchFromId, summary, details, fromHook, usage);\n\t}\n\n\tprivate async _branchWithSummary(\n\t\tbranchFromId: string | null,\n\t\tsummary: string,\n\t\tdetails?: unknown,\n\t\tfromHook?: boolean,\n\t\tusage?: Usage,\n\t\toutput?: { requestOutput: NativeRequestOutputAssociation; assertCurrent(): void },\n\t): Promise<string> {\n\t\tconst state = this.writeState;\n\t\tif (!this.indexed && branchFromId !== null && !this.byId.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tconst entry: BranchSummaryEntry = {\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: branchFromId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: branchFromId ?? \"root\",\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t\tusage,\n\t\t\t...(output ? { requestOutput: output.requestOutput } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\tentry,\n\t\t\ttrue,\n\t\t\tthis.indexed\n\t\t\t\t? async () => {\n\t\t\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\t\t\tif (branchFromId !== null) {\n\t\t\t\t\t\t\tif (!(await history.get(branchFromId))) throw new Error(`Entry ${branchFromId} not found`);\n\t\t\t\t\t\t\tawait history.parentPathFrom(branchFromId, { limit: 1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tundefined,\n\t\t\toutput?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tprivate async _captureForkInput(\n\t\ttarget: { leafId: string | null } | { entryId: string; position: \"before\" | \"at\" },\n\t\toptions: { persist?: boolean; sessionDir?: string; rlmDepth?: number; limits?: SessionHistoryReadLimits },\n\t): Promise<CapturedForkInput> {\n\t\tconst limits = { ...(options.limits ?? DEFAULT_MANAGER_HISTORY_LIMITS) };\n\t\tconst sourceFile = this.sessionFile;\n\t\tconst header = JSON.parse(stringifyBoundedJson(this.getHeader(), limits.maxSourceBytes)) as SessionHeader | null;\n\t\tconst settings = {\n\t\t\tsourceFile,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionDir: options.sessionDir ?? this.sessionDir,\n\t\t\tpersist: options.persist ?? this.persist,\n\t\t\trlmDepth: options.rlmDepth ?? resolveSessionRlmDepth(header ?? {}, sourceFile ?? \"\"),\n\t\t\tlimits,\n\t\t};\n\t\tconst finish = async (\n\t\t\tentries: SessionEntry[],\n\t\t\thistory?: SessionHistoryReadScope,\n\t\t\tepochCopy?: CapturedEpochCopy,\n\t\t): Promise<CapturedForkInput> => {\n\t\t\tconst byId = new Map<string, SessionEntry>();\n\t\t\tfor (const entry of entries) if (!byId.has(entry.id)) byId.set(entry.id, entry);\n\t\t\tconst selectedEntry = \"entryId\" in target ? byId.get(target.entryId) : undefined;\n\t\t\tlet leafId: string | null;\n\t\t\tif (\"entryId\" in target) {\n\t\t\t\tif (!selectedEntry) throw new Error(\"Invalid entry ID for forking\");\n\t\t\t\tif (\n\t\t\t\t\ttarget.position === \"before\" &&\n\t\t\t\t\t(selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\")\n\t\t\t\t)\n\t\t\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t\t\tleafId = target.position === \"at\" ? selectedEntry.id : selectedEntry.parentId;\n\t\t\t} else leafId = target.leafId;\n\t\t\tconst path: SessionEntry[] = [];\n\t\t\tif (history) {\n\t\t\t\tlet page = await history.parentPathFrom(leafId);\n\t\t\t\tfor (;;) {\n\t\t\t\t\tfor (const reference of page.events) {\n\t\t\t\t\t\tconst entry = byId.get(reference.id);\n\t\t\t\t\t\tif (!entry) throw new Error(\"Fork path source is unavailable\");\n\t\t\t\t\t\tpath.push(entry);\n\t\t\t\t\t}\n\t\t\t\t\tif (!page.nextCursor) break;\n\t\t\t\t\tpage = await history.parentPathFrom(leafId, { cursor: page.nextCursor });\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tlet id = leafId;\n\t\t\t\twhile (id !== null) {\n\t\t\t\t\tconst entry = byId.get(id);\n\t\t\t\t\tif (!entry || seen.has(id)) throw new Error(\"Parent path lineage is unresolved\");\n\t\t\t\t\tseen.add(id);\n\t\t\t\t\tpath.push(entry);\n\t\t\t\t\tid = entry.parentId;\n\t\t\t\t}\n\t\t\t\tpath.reverse();\n\t\t\t}\n\t\t\tlet copied: SessionEntry[] = path.filter((entry) => entry.type !== \"label\");\n\t\t\tconst ids = new Set(copied.map((entry) => entry.id));\n\t\t\tif (epochCopy) {\n\t\t\t\t// Preserve source-backed display updates and original invocation relations, not baked replacement bodies.\n\t\t\t\tconst toolCalls = new Set(\n\t\t\t\t\tcopied.flatMap((entry) =>\n\t\t\t\t\t\tentry.type === \"message\" && entry.message.role === \"toolResult\" ? [entry.message.toolCallId] : [],\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tfor (const entry of copied) {\n\t\t\t\t\tif (entry.type === \"message\" && entry.execution && \"invocationId\" in entry.execution)\n\t\t\t\t\t\tids.add(entry.execution.invocationId);\n\t\t\t\t}\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tif (entry.type === \"child_usage_attributed\" && ids.has(entry.targetId)) ids.add(entry.id);\n\t\t\t\t\tif (entry.type === \"custom\" && entry.customType === IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY) {\n\t\t\t\t\t\tconst sent = parsePersistedIpythonSentAgentMessage(entry.data);\n\t\t\t\t\t\tif (sent && toolCalls.has(sent.toolCallId)) ids.add(entry.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Related records keep their actual parent relations, including necessary off-branch ancestors.\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tconst entry = byId.get(id);\n\t\t\t\t\tif (!entry) throw new Error(\"Fork related source is unavailable\");\n\t\t\t\t\tif (entry.parentId !== null) ids.add(entry.parentId);\n\t\t\t\t}\n\t\t\t\tconst order = new Map(epochCopy.entries.map((entry) => [entry.id, entry.sequence]));\n\t\t\t\tcopied = [...ids].map((id) => byId.get(id)!).sort((a, b) => order.get(a.id)! - order.get(b.id)!);\n\t\t\t}\n\t\t\tconst activeLabels = new Map<string, CapturedForkInput[\"labels\"][number]>();\n\t\t\tfor (const entry of entries) {\n\t\t\t\tif (entry.type !== \"label\") continue;\n\t\t\t\tif (entry.label)\n\t\t\t\t\tactiveLabels.set(entry.targetId, {\n\t\t\t\t\t\ttargetId: entry.targetId,\n\t\t\t\t\t\tlabel: entry.label,\n\t\t\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\t\t\tretention: entryRetentions.get(entry),\n\t\t\t\t\t\tqualification: entryQualifications.get(entry),\n\t\t\t\t\t});\n\t\t\t\telse activeLabels.delete(entry.targetId);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...settings,\n\t\t\t\tsource: history?.source,\n\t\t\t\t...(epochCopy ? { epochCopy, leafId } : {}),\n\t\t\t\tselectedEntry: selectedEntry\n\t\t\t\t\t? withEntryRetention(\n\t\t\t\t\t\t\tJSON.parse(stringifyBoundedJson(selectedEntry, limits.maxSourceBytes)) as SessionEntry,\n\t\t\t\t\t\t\tentryRetentions.get(selectedEntry),\n\t\t\t\t\t\t\tentryQualifications.get(selectedEntry),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tpath: copied,\n\t\t\t\tlabels: [...activeLabels.values()].filter((label) => ids.has(label.targetId)),\n\t\t\t};\n\t\t};\n\t\tif (!this.indexed) {\n\t\t\tconst resident = this.materializeResidentHistory(limits);\n\t\t\treturn finish(\n\t\t\t\tresident.entries.map((entry, index) =>\n\t\t\t\t\twithEntryRetention(\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tresident.retentions[index] ?? undefined,\n\t\t\t\t\t\tresident.qualifications[index] ?? undefined,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tconst headerBytes = Buffer.byteLength(stringifyBoundedJson(header, limits.maxSourceBytes));\n\t\tif (headerBytes >= limits.maxSourceBytes) throw new Error(\"Fork source byte budget exceeded\");\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst materialized = await history.materialize({\n\t\t\t\t...limits,\n\t\t\t\tmaxSourceBytes: limits.maxSourceBytes - headerBytes,\n\t\t\t});\n\t\t\tconst entries = materialized.entries.map(({ entry, source }) =>\n\t\t\t\twithEntryRetention(entry, source.retention, source.qualification),\n\t\t\t);\n\t\t\tconst sourceEntries = materialized.entries.map(({ entry, source }) => captureEpochCopyEntry(entry, source));\n\t\t\tconst hasEpoch = sourceEntries.some(\n\t\t\t\t(entry) => entry.kind === \"compaction\" && entry.qualification === \"native-context-epoch\",\n\t\t\t);\n\t\t\tif (!hasEpoch) applyChildUsageAttributions(entries);\n\t\t\treturn finish(\n\t\t\t\tentries,\n\t\t\t\thistory,\n\t\t\t\thasEpoch\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tsessionId: history.source.sessionId,\n\t\t\t\t\t\t\tsessionFile: history.source.sessionFile,\n\t\t\t\t\t\t\tthrough: history.source.sourceSequence,\n\t\t\t\t\t\t\tentries: sourceEntries,\n\t\t\t\t\t\t\tretained: false,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t});\n\t}\n\n\tprivate async _rebuildCopiedEpoch(copied: CapturedEpochCopy, limits: SessionHistoryReadLimits): Promise<void> {\n\t\tif (\n\t\t\t!copied.entries.some((entry) => entry.kind === \"compaction\" && entry.qualification === \"native-context-epoch\")\n\t\t)\n\t\t\treturn;\n\t\tif (!this.supportsCapturedHistoryReads())\n\t\t\tthrow new Error(\"Copied context epochs require an owned persistent source\");\n\t\tconst sink = this.bindCompactionSink(limits);\n\t\tawait this._runHistoryRead(\n\t\t\t{ ...sink, readHistory: (read) => sink[readCopiedEpochSource](read) },\n\t\t\tasync (history: SessionHistoryReadScope) => {\n\t\t\t\tconst rebuilt = await rebuildCopiedContextEpoch(history, copied, limits);\n\t\t\t\tif (rebuilt) await sink[appendContextEpoch](rebuilt.checkpoint, rebuilt.tokensBefore, rebuilt.summary);\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate static async _createCapturedFork(input: CapturedForkInput): Promise<SessionManager> {\n\t\tconst next = new SessionManager(input.cwd, input.sessionDir, input.persist, {\n\t\t\tparentSession: input.sourceFile,\n\t\t\trlmDepth: input.rlmDepth,\n\t\t});\n\t\tnext.freshContextPolicySource = false;\n\t\tlet bytes = Buffer.byteLength(stringifyBoundedJson(next.fileEntries[0], input.limits.maxSourceBytes));\n\t\tconst append = (\n\t\t\tentry: SessionEntry,\n\t\t\tretention?: JournalFrameRetention,\n\t\t\tqualification = entryQualifications.get(entry),\n\t\t) => {\n\t\t\tif (next.fileEntries.length - 1 >= input.limits.maxEntries) throw new Error(\"Fork entry budget exceeded\");\n\t\t\tconst json = stringifyBoundedJson(entry, input.limits.maxSourceBytes - bytes);\n\t\t\tbytes += Buffer.byteLength(json);\n\t\t\tnext.fileEntries.push(withEntryRetention(JSON.parse(json) as SessionEntry, retention, qualification));\n\t\t};\n\t\tfor (const entry of input.path) append(entry, entryRetentions.get(entry));\n\t\tconst ids = new Set(input.path.map((entry) => entry.id));\n\t\tlet parentId = input.path.at(-1)?.id ?? null;\n\t\tfor (const label of input.labels) {\n\t\t\tconst id = generateId(ids);\n\t\t\tids.add(id);\n\t\t\tappend(\n\t\t\t\t{ type: \"label\", id, parentId, timestamp: label.timestamp, targetId: label.targetId, label: label.label },\n\t\t\t\tlabel.retention,\n\t\t\t\tlabel.qualification,\n\t\t\t);\n\t\t\tparentId = id;\n\t\t}\n\t\tnext._buildIndex();\n\t\tif (input.persist) await next._openNew();\n\t\telse next.writeState.sequence = next.fileEntries.length - 1;\n\t\tif (input.epochCopy) {\n\t\t\ttry {\n\t\t\t\tawait next.branchTo(input.leafId ?? null);\n\t\t\t\tawait next._rebuildCopiedEpoch(input.epochCopy, input.limits);\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait next.close();\n\t\t\t\t} catch (cleanup) {\n\t\t\t\t\tthrow new AggregateError([error, cleanup], \"Fork activation and destination close failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn next;\n\t}\n\n\tasync prepareFork(\n\t\tentryId: string,\n\t\toptions: {\n\t\t\tposition?: \"before\" | \"at\";\n\t\t\tpersist?: boolean;\n\t\t\tsessionDir?: string;\n\t\t\trlmDepth?: number;\n\t\t\tlimits?: SessionHistoryReadLimits;\n\t\t} = {},\n\t): Promise<PreparedSessionFork> {\n\t\tconst captured = await this._captureForkInput(\n\t\t\t{ entryId, position: options.position ?? \"before\" },\n\t\t\t{ ...options },\n\t\t);\n\t\treturn {\n\t\t\tsource: captured.source,\n\t\t\tselectedEntry: captured.selectedEntry!,\n\t\t\tcreate: () => SessionManager._createCapturedFork(captured),\n\t\t};\n\t}\n\n\tasync forkBranch(\n\t\tleafId: string | null,\n\t\toptions: { persist?: boolean; sessionDir?: string; rlmDepth?: number; limits?: SessionHistoryReadLimits } = {},\n\t): Promise<SessionManager> {\n\t\treturn SessionManager._createCapturedFork(await this._captureForkInput({ leafId }, { ...options }));\n\t}\n\n\tasync createBranchedSession(leafId: string): Promise<string | undefined> {\n\t\tthis._assertMutable();\n\t\tconst next = await this.forkBranch(leafId);\n\t\tthis._assertMutable();\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tawait this.flushNow();\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait next.close();\n\t\t\t\t} catch (cleanup) {\n\t\t\t\t\tthrow new AggregateError([error, cleanup], \"Branch adoption preparation and destination close failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tawait this._adopt(next);\n\t\t\treturn this.sessionFile;\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tstatic async create(cwd: string, sessionDir?: string, options?: NewSessionOptions): Promise<SessionManager> {\n\t\tconst manager = new SessionManager(cwd, sessionDir ?? getDefaultSessionDir(cwd), true, options);\n\t\tawait manager._openNew();\n\t\treturn manager;\n\t}\n\n\tstatic async open(path: string, sessionDir?: string, cwdOverride?: string): Promise<SessionManager> {\n\t\tconst target = assertProductStatePath(path);\n\t\tif (!existsSync(target)) {\n\t\t\tconst manager = new SessionManager(cwdOverride ?? process.cwd(), sessionDir ?? dirname(target), true);\n\t\t\tmanager.sessionFile = target;\n\t\t\tawait manager._openNew();\n\t\t\treturn manager;\n\t\t}\n\t\tconst owner = await SessionJournalOwner.open({ journalPath: target });\n\t\tlet manager: SessionManager | undefined;\n\t\ttry {\n\t\t\tlet entries: FileEntry[] | undefined;\n\t\t\tlet header: SessionHeader;\n\t\t\tif (owner.format === \"framed\") header = await readOwnedSessionHeader(owner.getSnapshot());\n\t\t\telse {\n\t\t\t\tentries = await loadEntriesFromFileAsync(owner.journalPath);\n\t\t\t\tconst first = entries[0];\n\t\t\t\tif (!first || first.type !== \"session\" || typeof first.id !== \"string\")\n\t\t\t\t\tthrow new Error(`Session source has no valid header: ${target}`);\n\t\t\t\theader = first;\n\t\t\t}\n\t\t\tconst sourceVersion = header.version ?? 1;\n\t\t\tif (sourceVersion > CURRENT_SESSION_VERSION) throw new Error(`Unsupported session version: ${sourceVersion}`);\n\t\t\tif (header.parentSession && !isValidRlmDepth(header.rlmDepth))\n\t\t\t\theader.rlmDepth = resolveSessionRlmDepth(header, owner.journalPath);\n\t\t\tmanager = new SessionManager(\n\t\t\t\tcwdOverride ?? header.cwd ?? process.cwd(),\n\t\t\t\tsessionDir ?? dirname(owner.journalPath),\n\t\t\t\tfalse,\n\t\t\t);\n\t\t\tmanager.persist = true;\n\t\t\tmanager.freshContextPolicySource = false;\n\t\t\tmanager.sessionId = header.id;\n\t\t\tmanager.sessionFile = owner.journalPath;\n\t\t\tmanager.writeState.owner = owner;\n\t\t\tmanager.writeState.sequence = owner.nextSequence - 1;\n\t\t\tmanager.writeState.sourceVersion = sourceVersion;\n\t\t\tif (owner.format === \"framed\" && sourceVersion === CURRENT_SESSION_VERSION) {\n\t\t\t\tawait manager._activateIndexedSource(header);\n\t\t\t} else {\n\t\t\t\tentries ??= await loadEntriesFromFileAsync(owner.journalPath);\n\t\t\t\tmigrateToCurrentVersion(entries);\n\t\t\t\tmanager.fileEntries = entries;\n\t\t\t\tmanager._buildIndex();\n\t\t\t}\n\t\t\treturn manager;\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tif (manager) await manager._closeSourceActors(manager.writeState);\n\t\t\t\telse await owner.close();\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Session open and cleanup failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tstatic async openAsync(path: string, sessionDir?: string, cwdOverride?: string): Promise<SessionManager> {\n\t\treturn SessionManager.open(path, sessionDir, cwdOverride);\n\t}\n\n\tstatic async openReadOnly(path: string, sessionDir?: string, cwdOverride?: string): Promise<SessionManager> {\n\t\tconst target = realpathIfPresent(resolve(path));\n\t\tconst entries = await loadEntriesFromFileAsync(target);\n\t\tconst header = entries[0];\n\t\tif (!header || header.type !== \"session\" || typeof header.id !== \"string\")\n\t\t\tthrow new Error(`Session source has no valid header: ${target}`);\n\t\tconst sourceVersion = header.version ?? 1;\n\t\tif (sourceVersion > CURRENT_SESSION_VERSION) throw new Error(`Unsupported session version: ${sourceVersion}`);\n\t\tmigrateToCurrentVersion(entries);\n\t\tif (header.parentSession && !isValidRlmDepth(header.rlmDepth))\n\t\t\theader.rlmDepth = resolveSessionRlmDepth(header, target);\n\t\tconst manager = new SessionManager(\n\t\t\tcwdOverride ?? header.cwd ?? process.cwd(),\n\t\t\tsessionDir ?? dirname(target),\n\t\t\tfalse,\n\t\t);\n\t\tmanager.writeState.sourceVersion = sourceVersion;\n\t\tmanager.persist = true;\n\t\tmanager.readOnly = true;\n\t\tmanager.sessionId = header.id;\n\t\tmanager.sessionFile = target;\n\t\tmanager.fileEntries = entries;\n\t\tmanager.writeState.sequence = entries.length - 1;\n\t\tmanager._buildIndex();\n\t\treturn manager;\n\t}\n\n\tstatic async continueRecent(cwd: string, sessionDir?: string): Promise<SessionManager> {\n\t\tconst dir = sessionDir ?? getDefaultSessionDir(cwd);\n\t\tconst mostRecent = findMostRecentSessionForCwd(dir, cwd);\n\t\treturn mostRecent ? SessionManager.open(mostRecent, dir, cwd) : SessionManager.create(cwd, dir);\n\t}\n\n\tstatic inMemory(cwd: string = process.cwd(), sessionDir = \"\", options?: NewSessionOptions): SessionManager {\n\t\treturn new SessionManager(cwd, sessionDir, false, options);\n\t}\n\n\tstatic async forkFrom(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionManager> {\n\t\treturn SessionManager._copyFrom(sourcePath, targetCwd, sessionDir, undefined, { ...limits });\n\t}\n\n\t/** Explicit external import: supported payload versions and complete captured records, with copied authority lowered. */\n\tstatic async importRetainedFrom(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t\trequiredSourceFormat?: \"legacy-jsonl\",\n\t): Promise<SessionManager> {\n\t\treturn SessionManager._copyFrom(\n\t\t\tsourcePath,\n\t\t\ttargetCwd,\n\t\t\tsessionDir,\n\t\t\t\"retained-import\",\n\t\t\t{ ...limits },\n\t\t\trequiredSourceFormat,\n\t\t);\n\t}\n\n\t/** Prepare one retained source without allocating a destination or assessing its activation. */\n\tstatic async previewRetainedImport(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionImportPreview> {\n\t\tconst targetDirectory = assertProductStatePath(sessionDir ?? getDefaultSessionDir(targetCwd));\n\t\tconst prepared = await SessionManager._prepareCopy(sourcePath, \"retained-import\", { ...limits });\n\t\treturn {\n\t\t\tsourcePath: prepared.sourcePath,\n\t\t\tsourceFormat: prepared.sourceFormat,\n\t\t\tinputVersion: prepared.inputVersion,\n\t\t\tentriesRead: prepared.entriesRead,\n\t\t\tsourceJsonBytes: prepared.sourceJsonBytes,\n\t\t\tpreparedEntryCount: prepared.targetEntries.length,\n\t\t\ttargetCwd,\n\t\t\ttargetDirectory,\n\t\t\tretention: \"retained-import\",\n\t\t\tsourceHeader: \"replace\",\n\t\t\tgitState: \"omit-and-relink-parents\",\n\t\t\tcapture: \"bounded-prefix-not-live-snapshot\",\n\t\t\tdestinationCreated: false,\n\t\t\tdestinationCreationAndIndexing: \"not-assessed\",\n\t\t\tcanonicalEpochActivation: \"not-assessed\",\n\t\t\treferenceReplayCoverage: \"not-assessed\",\n\t\t\tlaterImport: \"rereads-source-and-can-fail\",\n\t\t};\n\t}\n\n\tprivate static async _copyFrom(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tretention?: JournalFrameRetention,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t\trequiredSourceFormat?: \"legacy-jsonl\",\n\t): Promise<SessionManager> {\n\t\tconst targetDirectory = resolve(sessionDir ?? getDefaultSessionDir(targetCwd));\n\t\tconst prepared = await SessionManager._prepareCopy(sourcePath, retention, limits, requiredSourceFormat);\n\t\tconst manager = new SessionManager(targetCwd, targetDirectory, true, {\n\t\t\tparentSession: sourcePath,\n\t\t\trlmDepth: resolveSessionRlmDepth(prepared.sourceHeader, sourcePath),\n\t\t});\n\t\tprepared.targetEntries.unshift(manager.fileEntries[0]);\n\t\tmanager.fileEntries = prepared.targetEntries;\n\t\tmanager._buildIndex();\n\t\tawait manager._openNew();\n\t\ttry {\n\t\t\tawait manager._rebuildCopiedEpoch(prepared.epochCopy, limits);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait manager.close();\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Copied context activation and destination close failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\treturn manager;\n\t}\n\n\t/** The same held source preparation feeds preview and the real destination writer. */\n\tprivate static async _prepareCopy(\n\t\tsourcePath: string,\n\t\tretention: JournalFrameRetention | undefined,\n\t\tlimits: SessionHistoryReadLimits,\n\t\trequiredSourceFormat?: \"legacy-jsonl\",\n\t) {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tconst explicitImport = retention === \"retained-import\";\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid copied history limits\");\n\t\tlet entriesRead = 0;\n\t\tlet sourceBytes = 0;\n\t\tlet sourceHeader:\n\t\t\t| {\n\t\t\t\t\tentry: SessionHeader;\n\t\t\t\t\tformat: SessionImportPreview[\"sourceFormat\"];\n\t\t\t\t\tinputVersion: number;\n\t\t\t }\n\t\t\t| undefined;\n\t\tconst capturedPath = realpathIfPresent(resolve(sourcePath));\n\t\tconst capturedEntries: CopiedEpochEntry[] = [];\n\t\tlet through = 0;\n\t\tlet legacyEntries: FileEntry[] | undefined;\n\t\t// This becomes the target's resident array; current-version copies do not retain a second source array.\n\t\tconst targetEntries: FileEntry[] = [];\n\t\tconst dropped = new Map<string, string | null>();\n\t\tconst keep = (entry: FileEntry) => {\n\t\t\tif (entry.type === \"session\") return;\n\t\t\tif (entry.type === \"git_state\") dropped.set(entry.id, entry.parentId);\n\t\t\telse\n\t\t\t\ttargetEntries.push(\n\t\t\t\t\twithEntryRetention(entry, retention ?? entryRetentions.get(entry), entryQualifications.get(entry)),\n\t\t\t\t);\n\t\t};\n\t\tif (existsSync(sourcePath)) {\n\t\t\tawait readCapturedSessionJournal(\n\t\t\t\tcapturedPath,\n\t\t\t\t(record) => {\n\t\t\t\t\tsourceBytes += Buffer.byteLength(record.json);\n\t\t\t\t\tif (sourceBytes > maxSourceBytes) throw new Error(\"Copied history JSON byte budget exceeded\");\n\t\t\t\t\tconst entry = sessionFileEntry(record.entry, record.retention, record.qualification);\n\t\t\t\t\tif (record.source) through = record.source.sequence;\n\t\t\t\t\tif (!sourceHeader) {\n\t\t\t\t\t\tif (entry.type !== \"session\" || typeof entry.id !== \"string\")\n\t\t\t\t\t\t\tthrow new Error(\"Session source has no valid header\");\n\t\t\t\t\t\tconst version = entry.version === undefined ? 1 : entry.version;\n\t\t\t\t\t\tif (explicitImport && ![1, 2, CURRENT_SESSION_VERSION].includes(version))\n\t\t\t\t\t\t\tthrow new Error(`Unsupported session version for retained import: ${String(entry.version)}`);\n\t\t\t\t\t\tif (requiredSourceFormat === \"legacy-jsonl\" && record.source)\n\t\t\t\t\t\t\tthrow new Error(\"This import requires legacy-jsonl; native-framed input is unsupported\");\n\t\t\t\t\t\tsourceHeader = {\n\t\t\t\t\t\t\tentry,\n\t\t\t\t\t\t\tformat: record.source ? \"native-framed\" : \"legacy-jsonl\",\n\t\t\t\t\t\t\tinputVersion: version,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (entry.version !== CURRENT_SESSION_VERSION) legacyEntries = [entry];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (++entriesRead > maxEntries) throw new Error(\"Copied history entry budget exceeded\");\n\t\t\t\t\t\tif (entry.type !== \"session\" && record.source)\n\t\t\t\t\t\t\tcapturedEntries.push(\n\t\t\t\t\t\t\t\tcaptureEpochCopyEntry(entry, {\n\t\t\t\t\t\t\t\t\t...record.source,\n\t\t\t\t\t\t\t\t\tid: entry.id,\n\t\t\t\t\t\t\t\t\tparentId: entry.parentId,\n\t\t\t\t\t\t\t\t\tkind: entry.type,\n\t\t\t\t\t\t\t\t\tretention: record.retention,\n\t\t\t\t\t\t\t\t\tqualification: record.qualification,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\tif (legacyEntries) legacyEntries.push(entry);\n\t\t\t\t\t\telse keep(entry);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ requireCompleteTail: explicitImport },\n\t\t\t);\n\t\t}\n\t\tif (!sourceHeader)\n\t\t\tthrow new Error(`Cannot ${explicitImport ? \"import\" : \"fork\"}: source session has no header: ${sourcePath}`);\n\t\tif (legacyEntries) {\n\t\t\tfinalizeLoadedEntries(legacyEntries);\n\t\t\tmigrateToCurrentVersion(legacyEntries);\n\t\t\tfor (const entry of legacyEntries) keep(entry);\n\t\t} else if (\n\t\t\t!capturedEntries.some((entry) => entry.kind === \"compaction\" && entry.qualification === \"native-context-epoch\")\n\t\t) {\n\t\t\tapplyChildUsageAttributions(targetEntries);\n\t\t}\n\t\t// Relink after reading so even forward references through dropped git facts keep their old meaning.\n\t\tfor (let index = 0; index < targetEntries.length; index++) {\n\t\t\tconst entry = targetEntries[index] as SessionEntry;\n\t\t\tlet parentId = entry.parentId;\n\t\t\tconst seen = new Set<string>();\n\t\t\twhile (parentId !== null && dropped.has(parentId)) {\n\t\t\t\tif (seen.has(parentId)) throw new Error(\"Copied session git ancestry is unresolved\");\n\t\t\t\tseen.add(parentId);\n\t\t\t\tparentId = dropped.get(parentId) ?? null;\n\t\t\t}\n\t\t\tif (parentId !== entry.parentId)\n\t\t\t\ttargetEntries[index] = withEntryRetention(\n\t\t\t\t\t{ ...entry, parentId },\n\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tsourcePath: capturedPath,\n\t\t\tsourceFormat: sourceHeader.format,\n\t\t\tinputVersion: sourceHeader.inputVersion,\n\t\t\tentriesRead,\n\t\t\tsourceJsonBytes: sourceBytes,\n\t\t\tsourceHeader: sourceHeader.entry,\n\t\t\ttargetEntries,\n\t\t\tepochCopy: {\n\t\t\t\tsessionId: sourceHeader.entry.id,\n\t\t\t\tsessionFile: capturedPath,\n\t\t\t\tthrough,\n\t\t\t\tentries: capturedEntries,\n\t\t\t\tretained: retention === \"retained-import\",\n\t\t\t},\n\t\t};\n\t}\n\n\tstatic async list(cwd: string, sessionDir?: string, callbacks?: SessionListCallbacks): Promise<SessionInfo[]> {\n\t\tconst dir = sessionDir ?? getDefaultSessionDir(cwd);\n\t\tconst matchesCwd = (session: SessionInfo) => sessionInfoMatchesCwd(session, cwd);\n\t\tconst sessions = (\n\t\t\tawait listSessionsFromDir(dir, {\n\t\t\t\tonProgress: callbacks?.onProgress,\n\t\t\t\tonSession: callbacks?.onSession\n\t\t\t\t\t? (session) => {\n\t\t\t\t\t\t\tif (matchesCwd(session)) {\n\t\t\t\t\t\t\t\tcallbacks.onSession?.(session);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t})\n\t\t).filter(matchesCwd);\n\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\treturn sessions;\n\t}\n\n\tstatic async listAll(callbacks?: SessionListCallbacks, sessionDir?: string): Promise<SessionInfo[]> {\n\t\tconst sessionsDir = sessionDir ?? getSessionsDir();\n\t\tconst sessions = await listSessionsFromDir(sessionsDir, callbacks);\n\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\treturn sessions;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport type { AgentMessage, FinalizedToolExchange, ToolInvocation } from \"@ponythewhite/base-context-agent\";\nimport type {\n\tAssistantMessage,\n\tImageContent,\n\tMessage,\n\tServiceTier,\n\tTextContent,\n\tUsage,\n} from \"@ponythewhite/base-context-ai\";\nimport { randomUUID } from \"crypto\";\nimport { type Dir, existsSync, readdirSync, readFileSync, realpathSync, type Stats, statSync } from \"fs\";\nimport { opendir, open as openFile, stat } from \"fs/promises\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport { getAgentDir as getDefaultAgentDir, getSessionsDir } from \"../config.js\";\nimport { assertProductStatePath } from \"../runtime-paths.js\";\nimport { captureGitContext, type GitContext, gitContextsEqual } from \"../utils/git.js\";\nimport { AGENT_RESULT_CUSTOM_TYPE, type AgentResultData } from \"./agent-results.js\";\nimport { stringifyBoundedJson } from \"./bounded-json.js\";\nimport type { CanonicalPayloadFragment } from \"./canonical-payload-parts.js\";\nimport { takeCompactionRequestOutputs } from \"./compaction/compaction.js\";\nimport {\n\tappendContextEpoch,\n\tCONTEXT_EPOCH_DETAIL,\n\ttype ContextEpochCheckpoint,\n\ttype ContextEpochSummary,\n} from \"./context-epoch.js\";\nimport {\n\ttype CapturedEpochCopy,\n\ttype CopiedEpochEntry,\n\tcaptureEpochCopyEntry,\n\treadCopiedEpochSource,\n\trebuildCopiedContextEpoch,\n} from \"./context-epoch-copy.js\";\nimport { GOAL_STATE_CUSTOM_TYPE } from \"./goals.js\";\nimport type {\n\tContextManifestOptions,\n\tContextManifestPage,\n\tHistoryIndexPage,\n\tHistoryPayloadReadOptions,\n\tIndexedSourceEvent,\n\tTaskEvidenceOptions,\n\tTaskEvidencePage,\n} from \"./history-index.js\";\nimport { HistoryIndex, HistoryIndexUnsupportedError } from \"./history-index.js\";\nimport {\n\tdecodeJournalFrame,\n\tencodeJournalFrame,\n\tINITIAL_JOURNAL_CURSOR,\n\ttype JournalFrameRetention,\n\ttype NativeEntryQualification,\n} from \"./journal-frame.js\";\nimport {\n\ttype BashExecutionMessage,\n\tCOMPACTION_OUTCOME_CUSTOM_TYPE,\n\ttype CustomMessage,\n\tcreateCompactionSummaryMessage,\n} from \"./messages.js\";\nimport type {\n\tContextEpochEntryRef,\n\tNativeBranchRequestOutputSource,\n\tNativeCompactionRequestOutputAssociation,\n\tNativePlannerRequestOutputSource,\n\tNativeRequestEvent,\n\tNativeRequestOutputAssociation,\n\tNativeRequestOutputSource,\n\tSourceSnapshotRef,\n} from \"./request-events.js\";\nimport {\n\tSELECTED_SKILL_CUSTOM_TYPE,\n\tSELECTED_SKILL_DETAIL,\n\tselectedSkillBlock,\n\tselectedSkillCapture,\n} from \"./selected-skills.js\";\nimport { DEFAULT_NATIVE_RECOVERY_LIMITS } from \"./selective-recovery.js\";\nimport { orderContextToolResults, sessionEntryMessage } from \"./session-context-messages.js\";\nimport {\n\tIPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY,\n\ttype PersistedIpythonSentAgentMessage,\n\tparsePersistedIpythonSentAgentMessage,\n} from \"./session-context-updates.js\";\nimport { bindNativeEntryWriter, type NativeEntryOrigin, type NativeEntryWriter } from \"./session-entry-origin.js\";\nimport {\n\ttype BoundHistoryReadSink,\n\ttype BoundSessionRequestSink,\n\tcreateBranchHistoryReadView,\n\tcreateSessionHistoryReadScope,\n\ttype HistoryReadQuery,\n\ttype HydratedSessionHistoryEntry,\n\thydrateCapturedHistoryEntry,\n\ttype MaterializedSessionHistory,\n\tSessionHistoryIndex,\n\ttype SessionHistoryReadLimits,\n\ttype SessionHistoryReadScope,\n\ttype SessionHistoryReadView,\n} from \"./session-history-index.js\";\nimport {\n\tappendCappedSearchText,\n\textractOversizedMessageSummary,\n\textractTextContent,\n\tgetSessionModifiedDateFromLastActivity,\n\tisMessageWithContent,\n\tlooksLikeMessageEntry,\n\tnormalizeSessionStateStatus,\n\tSESSION_LIST_PARSE_MAX_LINE_CHARS,\n\tupdateLastActivityTime,\n} from \"./session-info-projection.js\";\nimport {\n\tAPPEND_NATIVE_ADMISSION,\n\tAPPEND_NATIVE_CONTEXT_EPOCH,\n\tAPPEND_NATIVE_RECOVERY,\n\tAPPEND_NATIVE_TOOL_EXECUTION,\n\tSESSION_JOURNAL_MAX_RECORD_BYTES as MAX_SESSION_RECORD_BYTES,\n\tSESSION_JOURNAL_MAX_FRAME_BYTES,\n\tSessionJournalOwner,\n\ttype SessionJournalState,\n} from \"./session-journal-owner.js\";\nimport {\n\treadCapturedSessionJournal,\n\treadSessionCatalogHeader,\n\treadSessionJournal,\n\treadSessionJournalHeader,\n\tSessionJournalDecoder,\n} from \"./session-journal-reader.js\";\nimport { readTaskStateFromHistory, type TaskStateView } from \"./task-state-reader.js\";\nimport { type TaskStateReadLimits, taskStateReadLimits } from \"./task-state-reducer.js\";\nimport {\n\taddAssistantUsage,\n\tcloneUsage,\n\temptyUsage,\n\ttype SessionUsageSummary,\n\tsessionUsageSummaryFrom,\n\tsubtractAssistantUsage,\n} from \"./usage.js\";\n\nexport const CURRENT_SESSION_VERSION = 3;\nconst SESSION_ASYNC_PARSE_YIELD_BYTES = 4 * 1024 * 1024;\n\n// These records advance the journal leaf without changing the captured compaction input.\nconst COMPACTION_BOOKKEEPING_ENTRY_TYPES = new Set<SessionEntry[\"type\"]>([\n\t\"session_state\",\n\t\"agent_status\",\n\t\"git_state\",\n\t\"child_usage_attributed\",\n]);\n\nfunction isCompactionBookkeeping(entry: SessionEntry): boolean {\n\treturn (\n\t\tCOMPACTION_BOOKKEEPING_ENTRY_TYPES.has(entry.type) ||\n\t\t(entry.type === \"custom_message\" && entry.customType === COMPACTION_OUTCOME_CUSTOM_TYPE)\n\t);\n}\n\n// Entry types that can represent user intent (vs. daemon bookkeeping like\n// session_state/agent_status/git_state/child_usage_attributed). Used by\n// hasUserContent to decide whether a message-less draft is safe to discard.\nconst CONTENT_ENTRY_TYPES = new Set([\n\t\"message\",\n\t\"custom_message\",\n\t\"custom\",\n\t\"model_change\",\n\t\"thinking_level_change\",\n\t\"service_tier_change\",\n\t\"session_info\",\n\t\"label\",\n\t\"compaction\",\n\t\"branch_summary\",\n\t// Effect/accounting facts must not disappear with a message-less draft.\n\t\"tool_intent\",\n\t\"request\",\n]);\n\nfunction realpathIfPresent(path: string): string {\n\ttry {\n\t\treturn realpathSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return path;\n\t\tthrow error;\n\t}\n}\n\n// Only actual manager-created source objects enter this private binding. Payloads and callbacks cannot brand a sink.\ntype NativeOutputCapture = (association: NativeRequestOutputAssociation) => NativeRequestOutputAssociation | undefined;\ninterface NativeOutputSource {\n\tcapture: NativeOutputCapture;\n\tmain: NativeRequestOutputSource;\n\tbranch: NativeBranchRequestOutputSource;\n\tplanner: NativePlannerRequestOutputSource;\n\tcompaction?: true;\n}\nconst nativeRequestOutputSources = new WeakMap<object, NativeOutputSource>();\n\n/** Internal main-stream capture; the factory closes over its original manager/writer before any waits. */\nexport function captureNativeRequestOutputSource(sink: object): NativeRequestOutputSource | undefined {\n\treturn nativeRequestOutputSources.get(sink)?.main;\n}\n\n/** Only the actual bound compaction wrapper, not a described or generic request sink. */\nexport function captureNativeCompactionOutputSource(sink: object): NativeOutputCapture | undefined {\n\tconst source = nativeRequestOutputSources.get(sink);\n\treturn source?.compaction ? source.capture : undefined;\n}\n\n/** Genuine writer ownership only; native branch invocation eligibility belongs to its captured coordinator. */\nexport function captureNativeBranchOutputSource(sink: object): NativeBranchRequestOutputSource | undefined {\n\treturn nativeRequestOutputSources.get(sink)?.branch;\n}\n\n/** Original writer ownership; native planner invocation eligibility is held by its captured coordinator. */\nexport function captureNativePlannerOutputSource(sink: object): NativePlannerRequestOutputSource | undefined {\n\treturn nativeRequestOutputSources.get(sink)?.planner;\n}\n\nexport interface SessionHeader {\n\ttype: \"session\";\n\tversion?: number; // v1 sessions don't have this\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n\trlmDepth?: number;\n\tgit?: GitContext;\n}\n\n/** One captured branch for summary input, physical requests, and the queued compaction commit. */\nexport interface BoundCompactionSink extends BoundSessionRequestSink {\n\t/** Original ownership and compaction input, including this sink's own acknowledged checkpoint. */\n\tisCurrent(): boolean;\n\t/** Internal explicit-copy read on this same held source, never a provider-view capability. */\n\t[readCopiedEpochSource]<T>(read: (history: SessionHistoryReadScope) => Promise<T>): Promise<T>;\n\treadBranch(): Promise<SessionEntry[]>;\n\t[appendContextEpoch](\n\t\tcheckpoint: ContextEpochCheckpoint,\n\t\ttokensBefore: number | null,\n\t\tsummary?: ContextEpochSummary,\n\t\trequestOutputSource?: object,\n\t): Promise<string>;\n\tappendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number | null,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t\tcustomInstructions?: string,\n\t\tusage?: Usage,\n\t\trequestOutputSource?: object,\n\t): Promise<string>;\n}\n\nexport interface NewSessionOptions {\n\tid?: string;\n\tparentSession?: string;\n\trlmDepth?: number;\n}\n\n/** Source preparation only. No destination is allocated and no activation result is predicted. */\nexport interface SessionImportPreview {\n\tsourcePath: string;\n\tsourceFormat: \"legacy-jsonl\" | \"native-framed\";\n\tinputVersion: number;\n\t/** Decoded records after the initial header. */\n\tentriesRead: number;\n\t/** Decoded JSON bytes including the header, not physical file bytes. */\n\tsourceJsonBytes: number;\n\t/** Prepared source entries, excluding the new header and any rebuilt epoch. */\n\tpreparedEntryCount: number;\n\ttargetCwd: string;\n\ttargetDirectory: string;\n\tretention: \"retained-import\";\n\tsourceHeader: \"replace\";\n\tgitState: \"omit-and-relink-parents\";\n\tcapture: \"bounded-prefix-not-live-snapshot\";\n\tdestinationCreated: false;\n\tdestinationCreationAndIndexing: \"not-assessed\";\n\tcanonicalEpochActivation: \"not-assessed\";\n\treferenceReplayCoverage: \"not-assessed\";\n\tlaterImport: \"rereads-source-and-can-fail\";\n}\n\nexport type SessionPersistListener = (sessionFile: string) => void;\n\nexport interface SessionEntryBase {\n\ttype: string;\n\tid: string;\n\tparentId: string | null;\n\ttimestamp: string;\n\t/** Native admission/control metadata, never read from the entry's arbitrary data payload. */\n\tnativeOrigin?: NativeEntryOrigin;\n}\n\nexport type SessionExecutionEvidence = Omit<FinalizedToolExchange, \"result\" | \"originalInput\" | \"executedInput\"> &\n\t({ invocationId: string } | { originalInput: unknown; executedInput?: unknown });\n\nexport interface SessionMessageEntry extends SessionEntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n\t/** Metadata from the original main-request owner; does not grant native input/task authority. */\n\trequestOutput?: NativeRequestOutputAssociation;\n\t/** Native execution evidence belongs to this result, not a second transcript. */\n\texecution?: SessionExecutionEvidence;\n}\n\nexport interface ToolIntentEntry extends SessionEntryBase {\n\ttype: \"tool_intent\";\n\tinvocation: ToolInvocation;\n\t/** Only the qualified original execution owner supplies this acknowledged source. */\n\tassistant?: ContextEpochEntryRef & { sessionFile: string | undefined };\n}\n\nexport interface RequestJournalEntry extends SessionEntryBase {\n\ttype: \"request\";\n\trequest: NativeRequestEvent;\n}\n\ntype PrivateSessionEntry = ToolIntentEntry | RequestJournalEntry;\n\ntype AssistantSessionMessageEntry = SessionMessageEntry & { message: AssistantMessage };\n\nexport interface ThinkingLevelChangeEntry extends SessionEntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ServiceTierChangeEntry extends SessionEntryBase {\n\ttype: \"service_tier_change\";\n\tserviceTier: ServiceTier;\n}\n\nexport interface ModelChangeEntry extends SessionEntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface CompactionEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\t/** Descriptive native projected-output links; not checkpoint/task authority or append ACK. */\n\trequestOutputs?: readonly NativeCompactionRequestOutputAssociation[];\n\tfirstKeptEntryId: string;\n\t/** Prior-context estimate; null when the original context is not measurable. */\n\ttokensBefore: number | null;\n\tdetails?: T;\n\tfromHook?: boolean;\n\tcustomInstructions?: string;\n\tusage?: Usage;\n}\n\nexport interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"branch_summary\";\n\t/** Descriptive built-in projected-output link, not native task authority, append ACK or caller delivery. */\n\trequestOutput?: NativeRequestOutputAssociation;\n\tfromId: string;\n\tsummary: string;\n\tdetails?: T;\n\tfromHook?: boolean;\n\tusage?: Usage;\n}\n\nexport interface CustomEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom\";\n\t/** Native planner contribution on prime-agent.refinement only; not whole-output, effect or ACK authority. */\n\tplannerRequest?: NativeRequestOutputAssociation;\n\tcustomType: string;\n\tdata?: T;\n}\n\n/**\n * Records usage folded into a parent assistant message after an RLM child run.\n * The child usage is kept separately so audit/UI code can explain why the\n * parent turn's aggregate usage exceeds the parent model response itself.\n */\nexport interface ChildUsageAttributionEntry extends SessionEntryBase {\n\ttype: \"child_usage_attributed\";\n\ttargetId: string;\n\tchildUsage: Usage;\n\taggregateUsage: Usage;\n\torigin?: \"spawn_task\" | \"agent_message\" | \"direct_user\";\n}\n\ninterface CapturedForkInput {\n\tsource?: SourceSnapshotRef;\n\tepochCopy?: CapturedEpochCopy;\n\tleafId?: string | null;\n\tselectedEntry?: SessionEntry;\n\tpath: SessionEntry[];\n\tlabels: {\n\t\ttargetId: string;\n\t\tlabel: string;\n\t\ttimestamp: string;\n\t\tretention?: JournalFrameRetention;\n\t\tqualification?: NativeEntryQualification;\n\t}[];\n\tsourceFile?: string;\n\tcwd: string;\n\tsessionDir: string;\n\tpersist: boolean;\n\trlmDepth: number | undefined;\n\tlimits: SessionHistoryReadLimits;\n}\n\nexport interface PreparedSessionFork {\n\t/** Present only for an owned canonical capture. */\n\tsource?: SourceSnapshotRef;\n\tselectedEntry: SessionEntry;\n\tcreate(): Promise<SessionManager>;\n}\n\nexport interface ChildUsageAttributionAcknowledgement {\n\tentryId: string;\n\taggregateUsage: Usage;\n}\n\nexport interface LabelEntry extends SessionEntryBase {\n\ttype: \"label\";\n\ttargetId: string;\n\tlabel: string | undefined;\n}\n\nexport interface SessionInfoEntry extends SessionEntryBase {\n\ttype: \"session_info\";\n\tname?: string;\n}\n\nexport type SessionStateStatus = \"active\" | \"archived\" | \"crash\";\n\nexport interface SessionState {\n\tstatus: SessionStateStatus;\n}\n\nexport interface SessionStateEntry extends SessionEntryBase {\n\ttype: \"session_state\";\n\tstate: SessionState;\n}\n\nexport type AgentTaskState = \"needs_input\" | \"completed\";\n\nexport interface AgentStatus {\n\tsummary: string;\n\ttaskState?: AgentTaskState;\n\tbasedOnMessageCount: number;\n}\n\nexport interface AgentStatusEntry extends SessionEntryBase {\n\ttype: \"agent_status\";\n\tstatus: AgentStatus;\n}\n\nexport interface GitStateEntry extends SessionEntryBase {\n\ttype: \"git_state\";\n\tgit: GitContext;\n}\n\nexport interface CustomMessageEntry<T = unknown> extends SessionEntryBase {\n\ttype: \"custom_message\";\n\tcustomType: string;\n\tcontent: string | (TextContent | ImageContent)[];\n\tdetails?: T;\n\tdisplay: boolean;\n}\n\nexport type SessionEntry =\n\t| SessionMessageEntry\n\t| ToolIntentEntry\n\t| RequestJournalEntry\n\t| ThinkingLevelChangeEntry\n\t| ServiceTierChangeEntry\n\t| ModelChangeEntry\n\t| CompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry\n\t| ChildUsageAttributionEntry\n\t| CustomMessageEntry\n\t| LabelEntry\n\t| SessionInfoEntry\n\t| SessionStateEntry\n\t| AgentStatusEntry\n\t| GitStateEntry;\n\nexport type FileEntry = SessionHeader | SessionEntry;\n\nexport interface SessionTreeFlatNode {\n\tentry: Exclude<SessionEntry, PrivateSessionEntry>;\n\tlabel?: string;\n\tlabelTimestamp?: string;\n}\n\nexport interface SessionTreeNode extends SessionTreeFlatNode {\n\tchildren: SessionTreeNode[];\n}\n\nexport interface ResidentSessionHistory {\n\theader: SessionHeader | null;\n\tentries: SessionEntry[];\n\t/** Per-row source controls, outside the unchanged entry payloads. */\n\tretentions: (JournalFrameRetention | null)[];\n\tqualifications: (NativeEntryQualification | null)[];\n\tleafId: string | null;\n\t/** Serialized header/entry JSON bytes, not physical frame bytes or heap size. */\n\tsourceBytes: number;\n}\n\nexport interface SessionContext {\n\tmessages: AgentMessage[];\n\tthinkingLevel: string;\n\tserviceTier: ServiceTier;\n\tmodel: { provider: string; modelId: string } | null;\n}\n\nexport interface SessionInfo {\n\tpath: string;\n\tid: string;\n\tcwd: string;\n\tname?: string;\n\tstate?: SessionState;\n\tparentSessionPath?: string;\n\trlmDepth: number;\n\tcreated: Date;\n\tmodified: Date;\n\tmessageCount: number;\n\tfirstMessage: string;\n\tallMessagesText: string;\n\tagentStatus?: AgentStatus;\n\tusage?: SessionUsageSummary;\n}\n\nexport type ReadonlySessionManager = Pick<\n\tSessionManager,\n\t| \"getCwd\"\n\t| \"getSessionDir\"\n\t| \"getSessionId\"\n\t| \"getSessionFile\"\n\t| \"getLeafId\"\n\t| \"readEntry\"\n\t| \"readLeafEntry\"\n\t| \"readEntryRetention\"\n\t| \"readLabel\"\n\t| \"readBranch\"\n\t| \"readBranches\"\n\t| \"readEntries\"\n\t| \"readFlatTree\"\n\t| \"readTree\"\n\t| \"readToolExchange\"\n\t| \"supportsCapturedHistoryReads\"\n\t| \"materializeResidentHistory\"\n\t| \"readBranchHistory\"\n\t| \"readSourceHistory\"\n\t| \"materializeParentPathHistory\"\n\t| \"materializeBranchHistory\"\n\t| \"materializeSourceHistory\"\n\t| \"getHeader\"\n\t| \"getCompactionCount\"\n\t| \"getSessionName\"\n>;\n\nfunction createSessionId(): string {\n\treturn uuidv7();\n}\n\nfunction getSessionFilePath(sessionDir: string, sessionId: string): string {\n\treturn join(sessionDir, `${sessionId}.jsonl`);\n}\n\nfunction createUniqueSessionFileTarget(sessionDir: string): { sessionId: string; sessionFile: string } {\n\tfor (let i = 0; i < 100; i++) {\n\t\tconst sessionId = createSessionId();\n\t\tconst sessionFile = getSessionFilePath(sessionDir, sessionId);\n\t\tif (!existsSync(sessionFile)) {\n\t\t\treturn { sessionId, sessionFile };\n\t\t}\n\t}\n\tthrow new Error(\"Unable to create a unique session file\");\n}\n\nexport function getSessionArtifactsRoot(sessionDir: string): string {\n\treturn join(dirname(sessionDir), \"session-artifacts\");\n}\n\nexport function getSessionArtifactPath(sessionDir: string, sessionId: string): string {\n\treturn join(getSessionArtifactsRoot(sessionDir), sessionId);\n}\n\nexport function getSessionArtifactPathForFile(sessionFile: string, sessionId?: string): string {\n\treturn getSessionArtifactPath(dirname(sessionFile), sessionId ?? basename(sessionFile).replace(/\\.jsonl$/, \"\"));\n}\n\nfunction generateId(byId: { has(id: string): boolean }): string {\n\tfor (let i = 0; i < 100; i++) {\n\t\tconst id = randomUUID().slice(0, 8);\n\t\tif (!byId.has(id)) return id;\n\t}\n\treturn randomUUID();\n}\n\nfunction migrateV1ToV2(entries: FileEntry[]): void {\n\tconst ids = new Set<string>();\n\tlet prevId: string | null = null;\n\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tentry.version = 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\tentry.id = generateId(ids);\n\t\tentry.parentId = prevId;\n\t\tprevId = entry.id;\n\n\t\tif (entry.type === \"compaction\") {\n\t\t\tconst comp = entry as CompactionEntry & { firstKeptEntryIndex?: number };\n\t\t\tif (typeof comp.firstKeptEntryIndex === \"number\") {\n\t\t\t\tconst targetEntry = entries[comp.firstKeptEntryIndex];\n\t\t\t\tif (targetEntry && targetEntry.type !== \"session\") {\n\t\t\t\t\tcomp.firstKeptEntryId = targetEntry.id;\n\t\t\t\t}\n\t\t\t\tdelete comp.firstKeptEntryIndex;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction migrateV2ToV3(entries: FileEntry[]): void {\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"session\") {\n\t\t\tentry.version = 3;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (entry.type === \"message\") {\n\t\t\tconst msgEntry = entry as SessionMessageEntry;\n\t\t\tif (msgEntry.message && (msgEntry.message as { role: string }).role === \"hookMessage\") {\n\t\t\t\t(msgEntry.message as { role: string }).role = \"custom\";\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction migrateToCurrentVersion(entries: FileEntry[]): boolean {\n\tconst header = entries.find((e) => e.type === \"session\") as SessionHeader | undefined;\n\tconst version = header?.version ?? 1;\n\n\tif (version >= CURRENT_SESSION_VERSION) return false;\n\n\tif (version < 2) migrateV1ToV2(entries);\n\tif (version < 3) migrateV2ToV3(entries);\n\n\treturn true;\n}\n\nexport function migrateSessionEntries(entries: FileEntry[]): void {\n\tmigrateToCurrentVersion(entries);\n}\n\nexport function parseSessionEntries(content: string): FileEntry[] {\n\treturn finalizeLoadedEntries(parseEntriesFromBuffer(Buffer.from(content)));\n}\n\nexport function applyChildUsageAttributions(entries: FileEntry[]): void {\n\tconst assistantEntriesById = new Map<string, AssistantSessionMessageEntry>();\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tassistantEntriesById.set(entry.id, entry as AssistantSessionMessageEntry);\n\t\t}\n\t}\n\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"child_usage_attributed\") continue;\n\t\tconst target = assistantEntriesById.get(entry.targetId);\n\t\tif (!target) continue;\n\t\ttarget.message.usage = cloneUsage(entry.aggregateUsage);\n\t}\n}\n\nexport function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null {\n\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\tif (entries[i].type === \"compaction\") {\n\t\t\treturn entries[i] as CompactionEntry;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function buildSessionContext(\n\tentries: SessionEntry[],\n\tleafId?: string | null,\n\tbyId?: Map<string, SessionEntry>,\n): SessionContext {\n\tif (!byId) {\n\t\tbyId = new Map<string, SessionEntry>();\n\t\tfor (const entry of entries) {\n\t\t\tbyId.set(entry.id, entry);\n\t\t}\n\t}\n\n\tlet leaf: SessionEntry | undefined;\n\tif (leafId === null) {\n\t\treturn { messages: [], thinkingLevel: \"off\", serviceTier: \"default\", model: null };\n\t}\n\tif (leafId) {\n\t\tleaf = byId.get(leafId);\n\t}\n\tif (!leaf) {\n\t\tleaf = entries[entries.length - 1];\n\t}\n\n\tif (!leaf) {\n\t\treturn { messages: [], thinkingLevel: \"off\", serviceTier: \"default\", model: null };\n\t}\n\n\t// push+reverse, not unshift-per-entry: unshift is O(n), making this O(n^2) on long sessions.\n\tconst path: SessionEntry[] = [];\n\tlet current: SessionEntry | undefined = leaf;\n\twhile (current) {\n\t\tpath.push(current);\n\t\tcurrent = current.parentId ? byId.get(current.parentId) : undefined;\n\t}\n\tpath.reverse();\n\n\tlet thinkingLevel = \"off\";\n\tlet serviceTier: ServiceTier = \"default\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\tlet compaction: CompactionEntry | null = null;\n\n\tfor (const entry of path) {\n\t\tif (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"service_tier_change\") {\n\t\t\tserviceTier = entry.serviceTier;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tmodel = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t} else if (entry.type === \"compaction\") {\n\t\t\tcompaction = entry;\n\t\t}\n\t}\n\n\t// Build messages and collect corresponding entries\n\t// When there's a compaction, model context remains summary-first while the\n\t// summary records where clients should present it among retained messages.\n\tconst messages: AgentMessage[] = [];\n\n\tconst appendMessage = (entry: SessionEntry, target = messages) => {\n\t\tconst message = sessionEntryMessage(entry);\n\t\tif (message) target.push(message);\n\t};\n\n\tif (compaction) {\n\t\tconst compactionIdx = path.findIndex((e) => e.type === \"compaction\" && e.id === compaction.id);\n\n\t\t// Collect kept messages (before compaction, starting from firstKeptEntryId).\n\t\t// The context remains summary-first for the model; retainedMessageCount records\n\t\t// the exact chronological presentation boundary for clients.\n\t\tconst retainedMessages: AgentMessage[] = [];\n\t\tlet foundFirstKept = false;\n\t\tfor (let i = 0; i < compactionIdx; i++) {\n\t\t\tconst entry = path[i];\n\t\t\tif (entry.id === compaction.firstKeptEntryId) {\n\t\t\t\tfoundFirstKept = true;\n\t\t\t}\n\t\t\tif (foundFirstKept) {\n\t\t\t\tappendMessage(entry, retainedMessages);\n\t\t\t}\n\t\t}\n\n\t\tmessages.push(\n\t\t\tcreateCompactionSummaryMessage(\n\t\t\t\tcompaction.summary,\n\t\t\t\tcompaction.tokensBefore,\n\t\t\t\tcompaction.timestamp,\n\t\t\t\tcompaction.customInstructions,\n\t\t\t\tretainedMessages.length,\n\t\t\t),\n\t\t\t...retainedMessages,\n\t\t);\n\n\t\tfor (let i = compactionIdx + 1; i < path.length; i++) {\n\t\t\tconst entry = path[i];\n\t\t\tappendMessage(entry);\n\t\t}\n\t} else {\n\t\tfor (const entry of path) {\n\t\t\tappendMessage(entry);\n\t\t}\n\t}\n\n\torderContextToolResults(messages);\n\treturn { messages, thinkingLevel, serviceTier, model };\n}\n\nexport function getDefaultSessionDir(_cwd: string, agentDir: string = getDefaultAgentDir()): string {\n\treturn getSessionsDir(agentDir);\n}\n\n// Actual reader/import control metadata, never a field in the entry payload.\nconst entryRetentions = new WeakMap<FileEntry, JournalFrameRetention>();\nconst entryQualifications = new WeakMap<FileEntry, NativeEntryQualification>();\n\nfunction withEntryRetention<T extends FileEntry>(\n\tentry: T,\n\tretention?: JournalFrameRetention,\n\tqualification?: NativeEntryQualification,\n): T {\n\tif (retention !== undefined) entryRetentions.set(entry, retention);\n\tif (qualification !== undefined) entryQualifications.set(entry, qualification);\n\treturn entry;\n}\n\nfunction sessionFileEntry(\n\tvalue: unknown,\n\tretention?: JournalFrameRetention,\n\tqualification?: NativeEntryQualification,\n): FileEntry {\n\tif (!value || typeof value !== \"object\" || !(\"type\" in value) || typeof value.type !== \"string\")\n\t\tthrow new Error(\"Invalid session journal entry\");\n\treturn withEntryRetention(value as FileEntry, retention, qualification);\n}\n\nfunction appendSourceEntry(owner: SessionJournalOwner, json: string, entry: FileEntry): Promise<{ sequence: number }> {\n\tconst qualification = entryQualifications.get(entry);\n\tif (qualification === \"native-admission\") return owner[APPEND_NATIVE_ADMISSION](json, entryRetentions.get(entry));\n\tif (qualification === \"native-recovery\") return owner[APPEND_NATIVE_RECOVERY](json, entryRetentions.get(entry));\n\tif (qualification === \"native-context-epoch\")\n\t\treturn owner[APPEND_NATIVE_CONTEXT_EPOCH](json, entryRetentions.get(entry));\n\tif (qualification === \"native-tool-execution\")\n\t\treturn owner[APPEND_NATIVE_TOOL_EXECUTION](json, entryRetentions.get(entry));\n\treturn owner.appendJson(json, entryRetentions.get(entry));\n}\n\nfunction parseEntriesFromBuffer(buffer: Buffer): FileEntry[] {\n\tconst decoder = new SessionJournalDecoder();\n\tconst entries: FileEntry[] = [];\n\tlet start = 0;\n\twhile (start < buffer.length) {\n\t\tconst end = buffer.indexOf(0x0a, start);\n\t\tif (end === -1) break; // Only exclusive recovery may change an incomplete tail.\n\t\tconst record = decoder.decode(buffer.subarray(start, end + 1));\n\t\tif (record) entries.push(sessionFileEntry(record.entry, record.retention, record.qualification));\n\t\tstart = end + 1;\n\t}\n\treturn entries;\n}\n\nfunction finalizeLoadedEntries(entries: FileEntry[]): FileEntry[] {\n\tif (entries.length === 0) return entries;\n\tconst header = entries[0];\n\tif (header.type !== \"session\" || typeof header.id !== \"string\")\n\t\tthrow new Error(\"Session source has no valid header\");\n\tapplyChildUsageAttributions(entries);\n\treturn entries;\n}\n\nexport function loadEntriesFromFile(filePath: string): FileEntry[] {\n\tif (!existsSync(filePath)) return [];\n\treturn finalizeLoadedEntries(parseEntriesFromBuffer(readFileSync(filePath)));\n}\n\nexport async function loadEntriesFromFileAsync(\n\tfilePath: string,\n\t_options: { streamThresholdBytes?: number } = {},\n): Promise<FileEntry[]> {\n\tif (!existsSync(filePath)) return [];\n\tconst entries: FileEntry[] = [];\n\tlet bytesSinceYield = 0;\n\tfor await (const record of readSessionJournal(filePath)) {\n\t\tentries.push(sessionFileEntry(record.entry, record.retention, record.qualification));\n\t\tbytesSinceYield += Buffer.byteLength(record.json);\n\t\tif (bytesSinceYield >= SESSION_ASYNC_PARSE_YIELD_BYTES) {\n\t\t\tbytesSinceYield = 0;\n\t\t\tawait new Promise<void>((resolve) => setImmediate(resolve));\n\t\t}\n\t}\n\treturn finalizeLoadedEntries(entries);\n}\n\nfunction readSessionHeader(filePath: string): Partial<SessionHeader> | undefined {\n\treturn readSessionJournalHeader(filePath) as Partial<SessionHeader> | undefined;\n}\n\nfunction isValidRlmDepth(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nexport function resolveSessionRlmDepth(\n\theader: { rlmDepth?: number; parentSession?: string },\n\tsessionPath: string,\n): number {\n\treturn resolveLegacySessionRlmDepth(header, sessionPath, new Set()) ?? legacyChildDepthFromPath(sessionPath);\n}\n\nfunction resolveLegacySessionRlmDepth(\n\theader: { rlmDepth?: number; parentSession?: string },\n\tsessionPath: string,\n\tvisitedPaths: Set<string>,\n): number | undefined {\n\tif (isValidRlmDepth(header.rlmDepth)) {\n\t\treturn header.rlmDepth;\n\t}\n\tif (!header.parentSession) {\n\t\treturn 0;\n\t}\n\n\tconst resolvedSessionPath = resolve(sessionPath);\n\tif (visitedPaths.has(resolvedSessionPath)) {\n\t\treturn undefined;\n\t}\n\tvisitedPaths.add(resolvedSessionPath);\n\n\tconst pathDepth = legacyChildDepthFromPath(sessionPath);\n\tconst parentSessionPath = resolve(dirname(sessionPath), header.parentSession);\n\ttry {\n\t\tconst parentHeader = readSessionHeader(parentSessionPath);\n\t\tif (parentHeader) {\n\t\t\tconst parentDepth = resolveLegacySessionRlmDepth(parentHeader, parentSessionPath, visitedPaths);\n\t\t\tif (parentDepth !== undefined) {\n\t\t\t\treturn pathDepth > 0 ? parentDepth + 1 : parentDepth;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fall back to artifact ancestry for unavailable or invalid legacy parents.\n\t} finally {\n\t\tvisitedPaths.delete(resolvedSessionPath);\n\t}\n\treturn pathDepth;\n}\n\nfunction legacyChildDepthFromPath(sessionPath: string): number {\n\tlet depth = 0;\n\tfor (const segment of dirname(sessionPath)\n\t\t.split(/[\\\\/]+/)\n\t\t.reverse()) {\n\t\tif (!/^sub-[0-9a-f]{8}$/.test(segment)) {\n\t\t\tbreak;\n\t\t}\n\t\tdepth += 1;\n\t}\n\treturn depth;\n}\n\nfunction deriveChildRlmDepth(parentHeader: Partial<SessionHeader> | undefined): number | undefined {\n\tconst depth = parentHeader?.rlmDepth;\n\treturn isValidRlmDepth(depth) && depth < Number.MAX_SAFE_INTEGER ? depth + 1 : undefined;\n}\n\nfunction rootRlmDepthFromEnv(): number {\n\tconst value = process.env.BASE_CONTEXT_RLM_DEPTH;\n\tif (value === undefined || value === \"\") {\n\t\treturn 0;\n\t}\n\tconst parsed = Number(value);\n\tif (!/^\\d+$/.test(value) || !isValidRlmDepth(parsed)) {\n\t\tthrow new Error(\"BASE_CONTEXT_RLM_DEPTH must be a non-negative integer\");\n\t}\n\treturn parsed;\n}\n\nfunction isValidSessionFile(filePath: string): boolean {\n\ttry {\n\t\tconst header = readSessionHeader(filePath);\n\t\treturn header?.type === \"session\" && typeof header.id === \"string\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction sessionCatalogDirectories(sessionDir: string): string[] {\n\tconst directories = [sessionDir];\n\tif (existsSync(sessionDir)) {\n\t\tfor (const entry of readdirSync(sessionDir, { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory() && /^--.+--$/.test(entry.name)) directories.push(join(sessionDir, entry.name));\n\t\t}\n\t}\n\t// Older default installations also stored direct JSONLs beside the sessions directory.\n\tif (resolve(sessionDir) === resolve(getSessionsDir())) directories.push(getDefaultAgentDir());\n\treturn directories;\n}\n\nfunction sessionCatalogFiles(sessionDir: string): string[] {\n\tconst paths: string[] = [];\n\tfor (const directory of sessionCatalogDirectories(sessionDir)) {\n\t\tif (!existsSync(directory)) continue;\n\t\tfor (const entry of readdirSync(directory)) if (entry.endsWith(\".jsonl\")) paths.push(join(directory, entry));\n\t}\n\treturn paths;\n}\n\n/** Native catalog pages visit the existing directories without an all-paths array. */\nexport async function* iterateSessionCatalogFiles(sessionDir: string): AsyncGenerator<string> {\n\tconst entries = async function* (directory: string) {\n\t\tlet handle: Dir;\n\t\ttry {\n\t\t\thandle = await opendir(directory);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n\t\t\tthrow error;\n\t\t}\n\t\tfor await (const entry of handle) yield entry;\n\t};\n\tfor await (const entry of entries(sessionDir)) if (entry.name.endsWith(\".jsonl\")) yield join(sessionDir, entry.name);\n\t// Match the existing catalog's root-files, project-directories, legacy-files order.\n\tfor await (const entry of entries(sessionDir)) {\n\t\tif (entry.isDirectory() && /^--.+--$/.test(entry.name)) {\n\t\t\tconst directory = join(sessionDir, entry.name);\n\t\t\tfor await (const child of entries(directory))\n\t\t\t\tif (child.name.endsWith(\".jsonl\")) yield join(directory, child.name);\n\t\t}\n\t}\n\tif (resolve(sessionDir) === resolve(getSessionsDir())) {\n\t\tfor await (const entry of entries(getDefaultAgentDir()))\n\t\t\tif (entry.name.endsWith(\".jsonl\")) yield join(getDefaultAgentDir(), entry.name);\n\t}\n}\n\n/** Directory membership only; the existing source reader still decides readability. */\nexport function isSessionCatalogFile(path: string, sessionDir: string): boolean {\n\tconst directory = dirname(resolve(path));\n\tconst root = resolve(sessionDir);\n\treturn (\n\t\tpath.endsWith(\".jsonl\") &&\n\t\t(directory === root ||\n\t\t\t(dirname(directory) === root && /^--.+--$/.test(basename(directory))) ||\n\t\t\t(root === resolve(getSessionsDir()) && directory === resolve(getDefaultAgentDir())))\n\t);\n}\n\nexport function findMostRecentSession(sessionDir: string): string | null {\n\ttry {\n\t\tconst files = sessionCatalogFiles(sessionDir)\n\t\t\t.filter(isValidSessionFile)\n\t\t\t.map((path) => ({ path, mtime: statSync(path).mtime }))\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction normalizeCwd(cwd: string): string {\n\treturn resolve(cwd);\n}\n\nfunction sessionInfoMatchesCwd(session: SessionInfo, cwd: string): boolean {\n\treturn !!session.cwd && normalizeCwd(session.cwd) === normalizeCwd(cwd);\n}\n\nfunction sessionHeaderMatchesCwd(header: Partial<SessionHeader> | undefined, cwd: string): boolean {\n\treturn (\n\t\theader?.type === \"session\" &&\n\t\ttypeof header.id === \"string\" &&\n\t\ttypeof header.cwd === \"string\" &&\n\t\tnormalizeCwd(header.cwd) === normalizeCwd(cwd)\n\t);\n}\n\nexport function findMostRecentSessionForCwd(sessionDir: string, cwd: string): string | null {\n\ttry {\n\t\tconst files = sessionCatalogFiles(sessionDir)\n\t\t\t.map((path) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst header = readSessionHeader(path);\n\t\t\t\t\tif (!sessionHeaderMatchesCwd(header, cwd)) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn { path, mtime: statSync(path).mtime };\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.filter((entry): entry is { path: string; mtime: Date } => entry !== undefined)\n\t\t\t.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());\n\n\t\treturn files[0]?.path || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nconst SESSION_INFO_CACHE_MAX_ENTRIES = 256;\nconst SESSION_INFO_CACHE_MAX_BYTES = 4 * 1024 * 1024;\n\ninterface SessionInfoCacheEntry {\n\tdev: number;\n\tino: number;\n\tnativeRevision?: string;\n\tsize: number;\n\tmtimeMs: number;\n\tinfo: SessionInfo | null;\n\tencodedBytes: number;\n}\n\n// Optional derived metadata. Native hits also require current indexed coverage.\n// The byte limit covers encoded key/stat/capture/info data, not process heap.\nconst sessionInfoCache = new Map<string, SessionInfoCacheEntry>();\n\nexport class SessionCatalogReadError extends Error {\n\tconstructor(\n\t\treadonly reason: \"unavailable\" | \"stale\" | \"unsupported\" | \"error\",\n\t\tmessage: string,\n\t\toptions?: ErrorOptions,\n\t) {\n\t\tsuper(`Native session catalog ${reason}: ${message}`, options);\n\t\tthis.name = \"SessionCatalogReadError\";\n\t}\n}\n\nasync function readIndexedSessionInfo(\n\tfilePath: string,\n\tstats: Stats,\n\theader: SessionHeader,\n\theaderChecksum: string,\n\tcached?: SessionInfoCacheEntry,\n): Promise<{ info: SessionInfo; revision: string; cached: boolean }> {\n\tconst source = {\n\t\tjournalPath: realpathIfPresent(resolve(filePath)),\n\t\tdev: stats.dev,\n\t\tino: stats.ino,\n\t\tbyteLength: stats.size,\n\t\theaderChecksum,\n\t};\n\tconst indexPath = join(getSessionArtifactPathForFile(source.journalPath, header.id), \"history.sqlite\");\n\tlet index: HistoryIndex | undefined;\n\tconst outcome = await (async () => {\n\t\ttry {\n\t\t\tawait stat(indexPath);\n\t\t} catch (error) {\n\t\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\")\n\t\t\t\tthrow new SessionCatalogReadError(\"unavailable\", \"The existing history index is missing\");\n\t\t\tthrow error;\n\t\t}\n\t\tindex = await HistoryIndex.open(indexPath, { readOnly: true });\n\t\tconst capturedIndex = index;\n\t\tconst view = await index.readSessionCatalog(header.id, source);\n\t\tif (view.selection !== \"covered\") throw new SessionCatalogReadError(view.selection, view.reason);\n\t\tconst revision = view.frontier.checksum!;\n\t\tconst hit =\n\t\t\t!!cached?.info &&\n\t\t\tcached.nativeRevision === revision &&\n\t\t\tcached.dev === stats.dev &&\n\t\t\tcached.ino === stats.ino &&\n\t\t\tcached.size === stats.size &&\n\t\t\tcached.mtimeMs === stats.mtimeMs;\n\t\tlet info: SessionInfo;\n\t\tif (hit && cached?.info) {\n\t\t\ttry {\n\t\t\t\tinfo = structuredClone(cached.info);\n\t\t\t} catch {\n\t\t\t\tsessionInfoCache.delete(filePath);\n\t\t\t\tinfo = cached.info;\n\t\t\t}\n\t\t\tif (sessionInfoCache.has(filePath)) {\n\t\t\t\tsessionInfoCache.delete(filePath);\n\t\t\t\tsessionInfoCache.set(filePath, cached);\n\t\t\t}\n\t\t} else {\n\t\t\tconst read = async (ref: IndexedSourceEvent | null) =>\n\t\t\t\tref\n\t\t\t\t\t? (\n\t\t\t\t\t\t\tawait hydrateCapturedHistoryEntry(ref, MAX_SESSION_RECORD_BYTES, (id, options) =>\n\t\t\t\t\t\t\t\tcapturedIndex.readSourcePayload(header.id, id, view.frontier.indexedThrough, options),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t).entry\n\t\t\t\t\t: undefined;\n\t\t\tlet firstMessage = \"(no messages)\";\n\t\t\tif (view.projection.firstMessage && \"preview\" in view.projection.firstMessage)\n\t\t\t\tfirstMessage = view.projection.firstMessage.preview;\n\t\t\telse if (view.refs.firstMessage) {\n\t\t\t\tconst entry = await read(view.refs.firstMessage);\n\t\t\t\tif (entry?.type !== \"message\" || entry.message.role !== \"user\" || !isMessageWithContent(entry.message))\n\t\t\t\t\tthrow new Error(\"Indexed catalog first-message reference is invalid\");\n\t\t\t\tfirstMessage = extractTextContent(entry.message) || \"(no messages)\";\n\t\t\t}\n\t\t\tconst named = await read(view.refs.name);\n\t\t\tif (named && named.type !== \"session_info\") throw new Error(\"Indexed catalog name reference is invalid\");\n\t\t\tconst status = await read(view.refs.agentStatus);\n\t\t\tif (status && status.type !== \"agent_status\") throw new Error(\"Indexed catalog status reference is invalid\");\n\t\t\tinfo = {\n\t\t\t\tpath: filePath,\n\t\t\t\tid: header.id,\n\t\t\t\tcwd: typeof header.cwd === \"string\" ? header.cwd : \"\",\n\t\t\t\tname: named?.type === \"session_info\" ? named.name?.trim() || undefined : undefined,\n\t\t\t\tstate: view.projection.state,\n\t\t\t\tparentSessionPath: header.parentSession,\n\t\t\t\trlmDepth: resolveSessionRlmDepth(header, filePath),\n\t\t\t\tcreated: new Date(header.timestamp),\n\t\t\t\tmodified: getSessionModifiedDateFromLastActivity(view.projection.lastActivityTime, header, stats.mtime),\n\t\t\t\tmessageCount: view.projection.messageCount,\n\t\t\t\tfirstMessage,\n\t\t\t\tallMessagesText: view.projection.allMessagesText,\n\t\t\t\tagentStatus: status?.type === \"agent_status\" ? status.status : undefined,\n\t\t\t\tusage: view.projection.usage,\n\t\t\t};\n\t\t}\n\t\t// The same read transaction and descriptor/frontier contract must still be current\n\t\t// after bounded source-part hydration, not merely when the query began.\n\t\tconst final = await index.readSessionCatalog(header.id, source);\n\t\tif (final.selection !== \"covered\") throw new SessionCatalogReadError(final.selection, final.reason);\n\t\treturn { info, revision, cached: hit };\n\t})().then(\n\t\t(value) => ({ ok: true as const, value }),\n\t\t(error: unknown) => ({\n\t\t\tok: false as const,\n\t\t\terror:\n\t\t\t\terror instanceof SessionCatalogReadError\n\t\t\t\t\t? error\n\t\t\t\t\t: error instanceof HistoryIndexUnsupportedError\n\t\t\t\t\t\t? new SessionCatalogReadError(\"unsupported\", error.message, { cause: error })\n\t\t\t\t\t\t: new SessionCatalogReadError(\"error\", `Indexed metadata read failed: ${String(error)}`, {\n\t\t\t\t\t\t\t\tcause: error,\n\t\t\t\t\t\t\t}),\n\t\t}),\n\t);\n\ttry {\n\t\tawait index?.close();\n\t} catch (error) {\n\t\tthrow new SessionCatalogReadError(\n\t\t\t\"error\",\n\t\t\toutcome.ok\n\t\t\t\t? `Index reader close failed: ${String(error)}`\n\t\t\t\t: `Catalog read and close failed: ${String(outcome.error)}; ${String(error)}`,\n\t\t\t{ cause: outcome.ok ? error : new AggregateError([outcome.error, error], \"Catalog read and close failed\") },\n\t\t);\n\t}\n\tif (!outcome.ok) throw outcome.error;\n\treturn outcome.value;\n}\n\nexport async function readSessionInfo(filePath: string): Promise<SessionInfo | null> {\n\tlet stats: Awaited<ReturnType<typeof stat>>;\n\ttry {\n\t\tstats = await stat(filePath);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\" || (error as NodeJS.ErrnoException).code === \"ENOTDIR\")\n\t\t\treturn null;\n\t\tthrow new SessionCatalogReadError(\"error\", `Source metadata stat failed: ${String(error)}`, { cause: error });\n\t}\n\tconst cached = sessionInfoCache.get(filePath);\n\tif (\n\t\tcached &&\n\t\tcached.nativeRevision === undefined &&\n\t\tcached.dev === stats.dev &&\n\t\tcached.ino === stats.ino &&\n\t\tcached.size === stats.size &&\n\t\tcached.mtimeMs === stats.mtimeMs\n\t) {\n\t\ttry {\n\t\t\tconst info = structuredClone(cached.info);\n\t\t\tsessionInfoCache.delete(filePath);\n\t\t\tsessionInfoCache.set(filePath, cached);\n\t\t\treturn info;\n\t\t} catch {\n\t\t\t// Give up cache ownership rather than lose a complete successful result.\n\t\t\tsessionInfoCache.delete(filePath);\n\t\t\treturn cached.info;\n\t\t}\n\t}\n\tlet nativeRevision: string | undefined;\n\tlet info: SessionInfo | null;\n\ttry {\n\t\tconst first = readSessionCatalogHeader(filePath);\n\t\tif (first?.source) {\n\t\t\tconst header = first.entry as SessionHeader;\n\t\t\tif (header?.type !== \"session\" || typeof header.id !== \"string\")\n\t\t\t\tthrow new SessionCatalogReadError(\"unsupported\", \"Native source has no supported session header\");\n\t\t\tconst result = await readIndexedSessionInfo(filePath, stats, header, first.source.revision, cached);\n\t\t\tif (result.cached) return result.info;\n\t\t\tinfo = result.info;\n\t\t\tnativeRevision = result.revision;\n\t\t} else info = first ? await scanSessionInfo(filePath, stats) : null; // Explicitly legacy/invalid-header only.\n\t} catch (error) {\n\t\tif (error instanceof SessionCatalogReadError) throw error;\n\t\tthrow new SessionCatalogReadError(\"error\", `Source header read failed: ${String(error)}`, { cause: error });\n\t}\n\tsessionInfoCache.delete(filePath);\n\ttry {\n\t\tconst encoded = stringifyBoundedJson(\n\t\t\t{\n\t\t\t\tfilePath,\n\t\t\t\tsize: stats.size,\n\t\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\t\tdev: stats.dev,\n\t\t\t\tino: stats.ino,\n\t\t\t\tnativeRevision,\n\t\t\t\tinfo:\n\t\t\t\t\tinfo === null\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\t\tcreated: info.created.toISOString(),\n\t\t\t\t\t\t\t\tmodified: info.modified.toISOString(),\n\t\t\t\t\t\t\t},\n\t\t\t},\n\t\t\tSESSION_INFO_CACHE_MAX_BYTES,\n\t\t);\n\t\tconst entry: SessionInfoCacheEntry = {\n\t\t\tsize: stats.size,\n\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\tdev: stats.dev,\n\t\t\tino: stats.ino,\n\t\t\tnativeRevision,\n\t\t\tinfo: structuredClone(info),\n\t\t\tencodedBytes: Buffer.byteLength(encoded),\n\t\t};\n\t\tlet retainedBytes = 0;\n\t\tfor (const retained of sessionInfoCache.values()) retainedBytes += retained.encodedBytes;\n\t\twhile (\n\t\t\tsessionInfoCache.size >= SESSION_INFO_CACHE_MAX_ENTRIES ||\n\t\t\tretainedBytes + entry.encodedBytes > SESSION_INFO_CACHE_MAX_BYTES\n\t\t) {\n\t\t\tconst oldest = sessionInfoCache.entries().next().value;\n\t\t\tif (!oldest) return info;\n\t\t\tsessionInfoCache.delete(oldest[0]);\n\t\t\tretainedBytes -= oldest[1].encodedBytes;\n\t\t}\n\t\tsessionInfoCache.set(filePath, entry);\n\t} catch {\n\t\t// Cache admission is optional. Return the complete successful result unchanged.\n\t}\n\treturn info;\n}\n\nasync function scanSessionInfo(filePath: string, stats: Awaited<ReturnType<typeof stat>>): Promise<SessionInfo | null> {\n\ttry {\n\t\tlet header: SessionHeader | undefined;\n\t\tlet messageCount = 0;\n\t\tlet firstMessage = \"\";\n\t\tlet allMessagesText = \"\";\n\t\tlet name: string | undefined;\n\t\tlet state: SessionState | undefined;\n\t\tlet agentStatus: AgentStatus | undefined;\n\t\tlet lastActivityTime: number | undefined;\n\t\t// Fold attribution aggregates like the loader: either disk representation cancels to the same own spend.\n\t\tconst assistantUsageById = new Map<string, Usage>();\n\t\tconst attributedChildUsages: Usage[] = [];\n\t\tconst summarizationUsages: Usage[] = [];\n\n\t\tfor await (const record of readSessionJournal(filePath)) {\n\t\t\tconst line = record.json;\n\n\t\t\t// Large tool-result entries can be many MB. They do not carry the\n\t\t\t// session-list metadata we need, and parsing them during every refresh\n\t\t\t// can exhaust the daemon heap.\n\t\t\tif (line.length > SESSION_LIST_PARSE_MAX_LINE_CHARS) {\n\t\t\t\tif (looksLikeMessageEntry(line)) {\n\t\t\t\t\tmessageCount++;\n\t\t\t\t\tconst summary = extractOversizedMessageSummary(line);\n\t\t\t\t\tif (typeof summary.timestamp === \"number\" && (summary.role === \"user\" || summary.role === \"assistant\")) {\n\t\t\t\t\t\tlastActivityTime = Math.max(lastActivityTime ?? 0, summary.timestamp);\n\t\t\t\t\t}\n\t\t\t\t\tif (summary.role === \"user\" && !firstMessage) {\n\t\t\t\t\t\tfirstMessage = summary.textPreview || \"(large message)\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst entry = sessionFileEntry(record.entry, record.retention, record.qualification);\n\n\t\t\tif (entry.type === \"session_info\") {\n\t\t\t\tconst infoEntry = entry as SessionInfoEntry;\n\t\t\t\tname = infoEntry.name?.trim() || undefined;\n\t\t\t}\n\t\t\tif (entry.type === \"session_state\") {\n\t\t\t\tconst stateEntry = entry as SessionStateEntry;\n\t\t\t\tconst status = normalizeSessionStateStatus(stateEntry.state?.status);\n\t\t\t\tif (status) {\n\t\t\t\t\tstate = { status };\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Keep the latest recap/verdict so off-daemon sessions don't all show as\n\t\t\t// unjudged in the agents view. Append-only, so last seen wins.\n\t\t\tif (entry.type === \"agent_status\") {\n\t\t\t\tagentStatus = (entry as AgentStatusEntry).status;\n\t\t\t}\n\t\t\tif (entry.type === \"child_usage_attributed\") {\n\t\t\t\tconst attribution = entry as ChildUsageAttributionEntry;\n\t\t\t\tif (assistantUsageById.has(attribution.targetId)) {\n\t\t\t\t\tassistantUsageById.set(attribution.targetId, attribution.aggregateUsage);\n\t\t\t\t\tattributedChildUsages.push(attribution.childUsage);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n\t\t\t\tconst summarizationUsage = (entry as CompactionEntry | BranchSummaryEntry).usage;\n\t\t\t\tif (summarizationUsage) summarizationUsages.push(summarizationUsage);\n\t\t\t}\n\t\t\tif (!header) {\n\t\t\t\tif (entry.type !== \"session\") {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\theader = entry as SessionHeader;\n\t\t\t}\n\n\t\t\tlastActivityTime = updateLastActivityTime(lastActivityTime, entry);\n\n\t\t\tif (entry.type !== \"message\") continue;\n\t\t\tmessageCount++;\n\n\t\t\tconst message = (entry as SessionMessageEntry).message;\n\t\t\tif (message.role === \"assistant\" && (message as { usage?: Usage }).usage) {\n\t\t\t\tassistantUsageById.set(entry.id, (message as { usage: Usage }).usage);\n\t\t\t}\n\t\t\tif (!isMessageWithContent(message)) continue;\n\t\t\tif (message.role !== \"user\" && message.role !== \"assistant\") continue;\n\n\t\t\tconst textContent = extractTextContent(message);\n\t\t\tif (!textContent) continue;\n\n\t\t\tallMessagesText = appendCappedSearchText(allMessagesText, textContent);\n\t\t\tif (!firstMessage && message.role === \"user\") {\n\t\t\t\tfirstMessage = textContent;\n\t\t\t}\n\t\t}\n\n\t\tif (!header) return null;\n\t\tconst usageTotal = emptyUsage();\n\t\tfor (const usage of assistantUsageById.values()) {\n\t\t\taddAssistantUsage(usageTotal, usage);\n\t\t}\n\t\tfor (const usage of summarizationUsages) {\n\t\t\taddAssistantUsage(usageTotal, usage);\n\t\t}\n\t\tfor (const childUsage of attributedChildUsages) {\n\t\t\tsubtractAssistantUsage(usageTotal, childUsage);\n\t\t}\n\t\tconst cwd = typeof header.cwd === \"string\" ? header.cwd : \"\";\n\t\tconst parentSessionPath = header.parentSession;\n\t\tconst rlmDepth = resolveSessionRlmDepth(header, filePath);\n\t\tconst modified = getSessionModifiedDateFromLastActivity(lastActivityTime, header, stats.mtime);\n\n\t\treturn {\n\t\t\tpath: filePath,\n\t\t\tid: header.id,\n\t\t\tcwd,\n\t\t\tname,\n\t\t\tstate,\n\t\t\tparentSessionPath,\n\t\t\trlmDepth,\n\t\t\tcreated: new Date(header.timestamp),\n\t\t\tmodified,\n\t\t\tmessageCount,\n\t\t\tfirstMessage: firstMessage || \"(no messages)\",\n\t\t\tallMessagesText,\n\t\t\tagentStatus,\n\t\t\tusage: sessionUsageSummaryFrom(usageTotal),\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport type SessionListProgress = (loaded: number, total: number) => void;\nexport type SessionListItem = (session: SessionInfo) => void;\n\nexport interface SessionListCallbacks {\n\tonProgress?: SessionListProgress;\n\tonSession?: SessionListItem;\n}\n\nasync function listSessionsFromDir(\n\tdir: string,\n\tcallbacks?: SessionListCallbacks,\n\tprogressOffset = 0,\n\tprogressTotal?: number,\n): Promise<SessionInfo[]> {\n\tconst sessions: SessionInfo[] = [];\n\ttry {\n\t\tconst files = sessionCatalogFiles(dir);\n\t\tconst total = progressTotal ?? files.length;\n\n\t\tconst present = new Set(files);\n\t\tfor (const key of sessionInfoCache.keys()) {\n\t\t\tconst directory = dirname(key);\n\t\t\tconst inScope =\n\t\t\t\tdirectory === dir ||\n\t\t\t\t(dirname(directory) === dir && /^--.+--$/.test(basename(directory))) ||\n\t\t\t\t(resolve(dir) === resolve(getSessionsDir()) && directory === getDefaultAgentDir());\n\t\t\tif (inScope && !present.has(key)) {\n\t\t\t\tsessionInfoCache.delete(key);\n\t\t\t}\n\t\t}\n\n\t\tlet loaded = 0;\n\t\tfor (const file of files) {\n\t\t\tconst info = await readSessionInfo(file);\n\t\t\tloaded++;\n\t\t\tcallbacks?.onProgress?.(progressOffset + loaded, total);\n\t\t\tif (info) {\n\t\t\t\tsessions.push(info);\n\t\t\t\tcallbacks?.onSession?.(info);\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof SessionCatalogReadError) throw error;\n\t\t// Return no sessions when the directory cannot be read.\n\t}\n\n\treturn sessions;\n}\n\nconst DEFAULT_MANAGER_HISTORY_LIMITS: SessionHistoryReadLimits = {\n\tmaxEntries: 16_384,\n\tmaxSourceBytes: 64 * 1024 * 1024,\n};\n// Selected forks bound compact original-reference metadata separately from selected payload/output limits.\nconst FORK_SOURCE_METADATA_MAX_BYTES = 64 * 1024 * 1024;\n\nasync function readOwnedSessionHeader(snapshot: SessionJournalState): Promise<SessionHeader> {\n\tconst handle = await openFile(snapshot.journalPath, \"r\");\n\tlet capturedHeader: SessionHeader | undefined;\n\ttry {\n\t\tconst checkIdentity = async () => {\n\t\t\tconst identity = await handle.stat();\n\t\t\tif (identity.dev !== snapshot.dev || identity.ino !== snapshot.ino || identity.size < snapshot.byteLength)\n\t\t\t\tthrow new Error(\"Owned session header source identity changed\");\n\t\t};\n\t\tawait checkIdentity();\n\t\tconst maximum = Math.min(snapshot.byteLength, SESSION_JOURNAL_MAX_FRAME_BYTES);\n\t\tconst parts: Buffer[] = [];\n\t\tlet offset = 0;\n\t\twhile (offset < maximum) {\n\t\t\tconst buffer = Buffer.allocUnsafe(Math.min(64 * 1024, maximum - offset));\n\t\t\tconst { bytesRead } = await handle.read(buffer, 0, buffer.length, offset);\n\t\t\tif (bytesRead === 0) break;\n\t\t\tconst chunk = buffer.subarray(0, bytesRead);\n\t\t\tconst end = chunk.indexOf(0x0a);\n\t\t\tparts.push(end < 0 ? chunk : chunk.subarray(0, end + 1));\n\t\t\toffset += bytesRead;\n\t\t\tif (end < 0) continue;\n\t\t\tconst frame = decodeJournalFrame(\n\t\t\t\tBuffer.concat(parts),\n\t\t\t\tINITIAL_JOURNAL_CURSOR,\n\t\t\t\tSESSION_JOURNAL_MAX_FRAME_BYTES,\n\t\t\t);\n\t\t\tconst header = frame.payload as SessionHeader;\n\t\t\tif (!header || header.type !== \"session\" || typeof header.id !== \"string\")\n\t\t\t\tthrow new Error(`Session source has no valid header: ${snapshot.journalPath}`);\n\t\t\tawait checkIdentity();\n\t\t\tcapturedHeader = header;\n\t\t\tbreak;\n\t\t}\n\t\tif (!capturedHeader) throw new Error(\"Owned session header is incomplete or exceeds the frame byte limit\");\n\t} catch (error) {\n\t\ttry {\n\t\t\tawait handle.close();\n\t\t} catch (closeError) {\n\t\t\tthrow new AggregateError([error, closeError], \"Owned session header read and close failed\", { cause: error });\n\t\t}\n\t\tthrow error;\n\t}\n\tawait handle.close();\n\treturn capturedHeader;\n}\n\ninterface SessionWriteState {\n\towner?: SessionJournalOwner;\n\thistory?: SessionHistoryIndex;\n\ttail: Promise<void>;\n\tpending: number;\n\tbytes: number;\n\treservedLeaf: string | null;\n\tleafId: string | null;\n\tbranchSelectionRevision: number;\n\tcompactionRevision: number;\n\tpins: number;\n\tretired: boolean;\n\tclosed: boolean;\n\tsequence: number;\n\tcompactionCount: number;\n\tsessionName?: string;\n\tsourceVersion: number;\n\theader?: SessionHeader;\n\tsessionState?: SessionState;\n\thasUserContent?: boolean;\n\tcontentPrefix?: number;\n\tgit?: GitContext;\n\tagentStatus?: AgentStatus;\n\tmetadataRefs?: { name?: string; state?: string; git?: string; status?: string };\n\tpendingIds: Set<string>;\n\tfailure?: Error;\n\tclosing?: Promise<void>;\n\tunpinned?: Promise<void>;\n\tonUnpinned?: () => void;\n}\n\nfunction newSessionWriteState(): SessionWriteState {\n\treturn {\n\t\ttail: Promise.resolve(),\n\t\tpending: 0,\n\t\tbytes: 0,\n\t\treservedLeaf: null,\n\t\tleafId: null,\n\t\tbranchSelectionRevision: 0,\n\t\tcompactionRevision: 0,\n\t\tpins: 0,\n\t\tretired: false,\n\t\tclosed: false,\n\t\tsequence: -1,\n\t\tcompactionCount: 0,\n\t\tsourceVersion: CURRENT_SESSION_VERSION,\n\t\tpendingIds: new Set(),\n\t};\n}\n\nconst MAX_SESSION_PENDING_OPERATIONS = 32;\nconst MAX_SESSION_PENDING_BYTES = 64 * 1024 * 1024;\n\nexport class SessionManager {\n\tprivate sessionId: string = \"\";\n\tprivate sessionFile: string | undefined;\n\tprivate sessionDir: string;\n\tprivate cwd: string;\n\tprivate persist: boolean;\n\tprivate fileEntries: FileEntry[] = [];\n\tprivate byId: Map<string, SessionEntry> = new Map();\n\tprivate labelsById: Map<string, string> = new Map();\n\tprivate labelTimestampsById: Map<string, string> = new Map();\n\tprivate leafId: string | null = null;\n\tprivate persistListeners = new Set<SessionPersistListener>();\n\tprivate finalizedToolMessages = new WeakMap<AgentMessage, string>();\n\tprivate pendingToolExchanges = new Map<string, Promise<string>>();\n\tprivate writeState = newSessionWriteState();\n\tprivate retiredSources = new Set<SessionWriteState>();\n\tprivate switching = false;\n\tprivate closing?: Promise<void>;\n\n\tprivate readOnly = false;\n\tprivate freshContextPolicySource = true;\n\tprivate indexed = false;\n\tprivate header: SessionHeader | null = null;\n\n\tprivate constructor(cwd: string, sessionDir: string, persist: boolean, options?: NewSessionOptions) {\n\t\tthis.cwd = cwd;\n\t\tthis.sessionDir = sessionDir;\n\t\tthis.persist = persist;\n\t\tif (persist) assertProductStatePath(sessionDir);\n\t\tthis._stageNewSession(options);\n\t}\n\n\tprivate _stageNewSession(options?: NewSessionOptions): void {\n\t\tthis.finalizedToolMessages = new WeakMap();\n\t\tlet sessionId = options?.id ?? createSessionId();\n\t\tlet sessionFile: string | undefined;\n\t\tconst hasExplicitRlmDepth = options !== undefined && Object.hasOwn(options, \"rlmDepth\");\n\t\tlet parentHeader: Partial<SessionHeader> | undefined;\n\t\tif (options?.parentSession && !hasExplicitRlmDepth) {\n\t\t\ttry {\n\t\t\t\tparentHeader = readSessionHeader(options.parentSession);\n\t\t\t} catch {\n\t\t\t\t// Unavailable parent metadata leaves the child depth unknown.\n\t\t\t}\n\t\t}\n\t\tif (this.persist) {\n\t\t\tif (options?.id) {\n\t\t\t\tsessionFile = getSessionFilePath(this.getSessionDir(), sessionId);\n\t\t\t\tif (existsSync(sessionFile)) {\n\t\t\t\t\tthrow new Error(`Session file already exists for id \"${sessionId}\": ${sessionFile}`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst target = createUniqueSessionFileTarget(this.getSessionDir());\n\t\t\t\tsessionId = target.sessionId;\n\t\t\t\tsessionFile = target.sessionFile;\n\t\t\t}\n\t\t}\n\n\t\tthis.sessionId = sessionId;\n\t\tconst timestamp = new Date().toISOString();\n\t\tconst git = this.persist ? (captureGitContext(this.cwd) ?? undefined) : undefined;\n\t\tconst rlmDepth = hasExplicitRlmDepth\n\t\t\t? options?.rlmDepth\n\t\t\t: options?.parentSession\n\t\t\t\t? deriveChildRlmDepth(parentHeader)\n\t\t\t\t: rootRlmDepthFromEnv();\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: CURRENT_SESSION_VERSION,\n\t\t\tid: this.sessionId,\n\t\t\ttimestamp,\n\t\t\tcwd: this.cwd,\n\t\t\tparentSession: options?.parentSession,\n\t\t\trlmDepth,\n\t\t\tgit,\n\t\t};\n\t\tthis.fileEntries = [header];\n\t\tthis.byId = new Map();\n\t\tthis.labelsById = new Map();\n\t\tthis.labelTimestampsById = new Map();\n\t\tthis.leafId = null;\n\n\t\tif (this.persist) {\n\t\t\tthis.sessionFile = sessionFile ? assertProductStatePath(sessionFile) : undefined;\n\t\t}\n\t\tthis.writeState.sequence = this.persist ? -1 : 0;\n\t\tthis.writeState.compactionCount = 0;\n\t}\n\n\tprivate async _openNew(): Promise<void> {\n\t\tif (!this.persist || !this.sessionFile) return;\n\t\tconst state = this.writeState;\n\t\tconst owner = await SessionJournalOwner.open({\n\t\t\tjournalPath: assertProductStatePath(this.sessionFile),\n\t\t\tcreate: true,\n\t\t});\n\t\tstate.owner = owner;\n\t\tthis.sessionFile = owner.journalPath;\n\t\ttry {\n\t\t\tfor (const entry of this.fileEntries) {\n\t\t\t\tconst ack = await appendSourceEntry(owner, stringifyBoundedJson(entry, MAX_SESSION_RECORD_BYTES), entry);\n\t\t\t\tstate.sequence = ack.sequence;\n\t\t\t}\n\t\t\tawait this._activateIndexedSource(this.fileEntries[0] as SessionHeader);\n\t\t} catch (error) {\n\t\t\tstate.closed = true;\n\t\t\ttry {\n\t\t\t\tawait this._closeSourceActors(state);\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Session creation and cleanup failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate async _adopt(next: SessionManager): Promise<void> {\n\t\tconst previous = this.writeState;\n\t\ttry {\n\t\t\tawait this._retire(previous);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait next.close();\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Session adoption and destination close failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tthis.sessionId = next.sessionId;\n\t\tthis.sessionFile = next.sessionFile;\n\t\tthis.sessionDir = next.sessionDir;\n\t\tthis.persist = next.persist;\n\t\tthis.freshContextPolicySource = next.freshContextPolicySource;\n\t\tthis.indexed = next.indexed;\n\t\tthis.header = next.header;\n\t\tthis.fileEntries = next.fileEntries;\n\t\tthis.byId = next.byId;\n\t\tthis.labelsById = next.labelsById;\n\t\tthis.labelTimestampsById = next.labelTimestampsById;\n\t\tthis.leafId = next.leafId;\n\t\tthis.finalizedToolMessages = next.finalizedToolMessages;\n\t\tthis.writeState = next.writeState;\n\t}\n\n\tprivate _assertResident(): void {\n\t\tif (this.indexed)\n\t\t\tthrow new Error(\n\t\t\t\t\"Synchronous history access requires a resident session view; use captured async history reads\",\n\t\t\t);\n\t}\n\n\tprivate async _acknowledgedHistory(\n\t\tstate: SessionWriteState,\n\t\tsnapshot = state.owner!.getSnapshot(),\n\t): Promise<SessionHistoryReadScope> {\n\t\tconst owner = state.owner;\n\t\tconst header = state.header;\n\t\tif (!owner || !header || owner.format !== \"framed\" || state.sourceVersion !== CURRENT_SESSION_VERSION)\n\t\t\tthrow new Error(\"An owned canonical session source is required\");\n\t\tstate.history ??= new SessionHistoryIndex(\n\t\t\theader.id,\n\t\t\tjoin(assertProductStatePath(getSessionArtifactPathForFile(owner.journalPath, header.id)), \"history.sqlite\"),\n\t\t);\n\t\tconst index = await state.history.synchronize(snapshot);\n\t\treturn createSessionHistoryReadScope(\n\t\t\tindex,\n\t\t\tObject.freeze({\n\t\t\t\tsessionId: header.id,\n\t\t\t\tsessionFile: owner.journalPath,\n\t\t\t\tleafId: state.leafId,\n\t\t\t\tsourceSequence: snapshot.nextSequence - 1,\n\t\t\t\tpersistent: true,\n\t\t\t}),\n\t\t\t(operation) => operation(),\n\t\t\t\"source\",\n\t\t);\n\t}\n\n\tprivate async _storedEntry(\n\t\thistory: SessionHistoryReadScope,\n\t\tid: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<HydratedSessionHistoryEntry | undefined> {\n\t\tconst value = await history.hydrateEntry(id, maxSourceBytes);\n\t\tif (!value || value.entry.type !== \"message\" || value.entry.message.role !== \"assistant\") return value;\n\t\tconst update = await history.sourceAssistantUsage(id);\n\t\tif (!update) return value;\n\t\tif (value.source.locator.length + update.locator.length > maxSourceBytes)\n\t\t\tthrow new Error(\"Stored assistant source byte budget exceeded\");\n\t\tconst related = await history.hydrateEntry(update.id, maxSourceBytes - value.source.locator.length);\n\t\tif (!related || related.entry.type !== \"child_usage_attributed\")\n\t\t\tthrow new Error(\"Stored assistant aggregate source is unavailable\");\n\t\tvalue.entry.message.usage = cloneUsage(related.entry.aggregateUsage);\n\t\treturn value;\n\t}\n\n\tprivate async _refreshOwnedMetadata(state: SessionWriteState, startup = false): Promise<void> {\n\t\tconst owner = state.owner!;\n\t\tconst snapshot = owner.getSnapshot();\n\t\tconst history = await this._acknowledgedHistory(state, snapshot);\n\t\tconst bootstrap = await state.history!.currentSourceBootstrap(snapshot);\n\t\tconst leafId = startup ? (bootstrap.leaf?.id ?? null) : state.leafId;\n\t\tconst index = await state.history!.synchronize(snapshot);\n\t\tconst branch = await index.branchBootstrap(state.header!.id, {\n\t\t\tleafId,\n\t\t\tthrough: history.source.sourceSequence,\n\t\t});\n\t\tconst refs = [bootstrap.sessionInfo, bootstrap.sessionState, branch.gitState, branch.agentStatus];\n\t\tif (\n\t\t\trefs.reduce((bytes, ref) => bytes + (ref?.locator.length ?? 0), 0) >\n\t\t\tDEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes\n\t\t)\n\t\t\tthrow new Error(\"Owned session metadata source byte budget exceeded\");\n\t\tconst previous = state.metadataRefs ?? {};\n\t\tconst read = async (ref: IndexedSourceEvent | null) => {\n\t\t\tif (!ref) return undefined;\n\t\t\tconst value = await history.hydrateEntry(ref.id, DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes);\n\t\t\tif (!value) throw new Error(\"Owned session metadata source is unavailable\");\n\t\t\treturn value.entry;\n\t\t};\n\t\tif (!state.metadataRefs || previous.name !== bootstrap.sessionInfo?.revision) {\n\t\t\tconst entry = await read(bootstrap.sessionInfo);\n\t\t\tstate.sessionName = entry?.type === \"session_info\" ? entry.name : undefined;\n\t\t}\n\t\tif (!state.metadataRefs || previous.state !== bootstrap.sessionState?.revision) {\n\t\t\tconst entry = await read(bootstrap.sessionState);\n\t\t\tconst status = entry?.type === \"session_state\" ? normalizeSessionStateStatus(entry.state.status) : undefined;\n\t\t\tstate.sessionState = status ? { status } : undefined;\n\t\t}\n\t\tif (!state.metadataRefs || previous.git !== branch.gitState?.revision) {\n\t\t\tconst entry = await read(branch.gitState);\n\t\t\tstate.git = entry?.type === \"git_state\" ? entry.git : state.header?.git;\n\t\t}\n\t\tif (!state.metadataRefs || previous.status !== branch.agentStatus?.revision) {\n\t\t\tconst entry = await read(branch.agentStatus);\n\t\t\tstate.agentStatus = entry?.type === \"agent_status\" ? { ...entry.status } : undefined;\n\t\t}\n\t\tstate.metadataRefs = {\n\t\t\tname: bootstrap.sessionInfo?.revision,\n\t\t\tstate: bootstrap.sessionState?.revision,\n\t\t\tgit: branch.gitState?.revision,\n\t\t\tstatus: branch.agentStatus?.revision,\n\t\t};\n\t\tstate.compactionCount = bootstrap.compactionCount;\n\t\tstate.hasUserContent = bootstrap.hasUserContent;\n\t\tstate.contentPrefix = bootstrap.contentPrefix;\n\t\tstate.leafId = leafId;\n\t\tstate.reservedLeaf = leafId;\n\t\tif (this.writeState === state) this.leafId = leafId;\n\t}\n\n\tprivate async _prepareOwnedMetadata(\n\t\tstate: SessionWriteState,\n\t\tentry: SessionEntry,\n\t\thistory: SessionHistoryReadScope,\n\t\tadvanceLeaf: boolean,\n\t): Promise<\n\t\tPick<\n\t\t\tSessionWriteState,\n\t\t\t\"compactionCount\" | \"sessionName\" | \"sessionState\" | \"hasUserContent\" | \"contentPrefix\" | \"git\" | \"agentStatus\"\n\t\t>\n\t> {\n\t\tif (state.hasUserContent === undefined || state.contentPrefix === undefined)\n\t\t\tthrow new Error(\"Owned session metadata is unavailable\");\n\t\tconst metadata = {\n\t\t\tcompactionCount: state.compactionCount + (entry.type === \"compaction\" ? 1 : 0),\n\t\t\tsessionName: entry.type === \"session_info\" ? entry.name : state.sessionName,\n\t\t\tsessionState: state.sessionState,\n\t\t\thasUserContent: state.hasUserContent,\n\t\t\tcontentPrefix: state.contentPrefix,\n\t\t\tgit: state.git,\n\t\t\tagentStatus: state.agentStatus,\n\t\t};\n\t\tif (entry.type === \"session_state\") {\n\t\t\tconst status = normalizeSessionStateStatus(entry.state?.status);\n\t\t\tif (status) metadata.sessionState = { status };\n\t\t}\n\t\tif (!metadata.hasUserContent && CONTENT_ENTRY_TYPES.has(entry.type)) {\n\t\t\tconst prefix = [\"model_change\", \"thinking_level_change\", \"service_tier_change\"];\n\t\t\twhile (metadata.contentPrefix < prefix.length && entry.type !== prefix[metadata.contentPrefix])\n\t\t\t\tmetadata.contentPrefix++;\n\t\t\tif (metadata.contentPrefix < prefix.length) metadata.contentPrefix++;\n\t\t\telse metadata.hasUserContent = true;\n\t\t}\n\t\tif (advanceLeaf) {\n\t\t\tif (entry.parentId !== state.leafId) {\n\t\t\t\tconst index = await state.history!.synchronize(state.owner!.getSnapshot());\n\t\t\t\tconst branch = await index.branchBootstrap(state.header!.id, {\n\t\t\t\t\tleafId: entry.parentId,\n\t\t\t\t\tthrough: history.source.sourceSequence,\n\t\t\t\t});\n\t\t\t\tlet remaining = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes;\n\t\t\t\tconst read = async (reference: IndexedSourceEvent | null) => {\n\t\t\t\t\tif (!reference) return undefined;\n\t\t\t\t\tconst budget = remaining;\n\t\t\t\t\tremaining -= reference.locator.length;\n\t\t\t\t\tif (remaining < 0) throw new Error(\"Owned session metadata source byte budget exceeded\");\n\t\t\t\t\tconst hydrated = await history.hydrateEntry(reference.id, budget);\n\t\t\t\t\tif (!hydrated) throw new Error(\"Owned session metadata source is unavailable\");\n\t\t\t\t\treturn hydrated.entry;\n\t\t\t\t};\n\t\t\t\tconst git = await read(branch.gitState);\n\t\t\t\tconst status = await read(branch.agentStatus);\n\t\t\t\tmetadata.git = git?.type === \"git_state\" ? git.git : state.header?.git;\n\t\t\t\tmetadata.agentStatus = status?.type === \"agent_status\" ? { ...status.status } : undefined;\n\t\t\t}\n\t\t\tif (entry.type === \"git_state\") metadata.git = entry.git;\n\t\t\tif (entry.type === \"agent_status\") metadata.agentStatus = { ...entry.status };\n\t\t}\n\t\treturn metadata;\n\t}\n\n\tprivate async _activateIndexedSource(header: SessionHeader, state = this.writeState): Promise<void> {\n\t\tstate.header = header;\n\t\tawait this._refreshOwnedMetadata(state, true);\n\t\tthis.writeState = state;\n\t\tthis.header = header;\n\t\tthis.leafId = state.leafId;\n\t\tthis.fileEntries = [];\n\t\tthis.byId.clear();\n\t\tthis.labelsById.clear();\n\t\tthis.labelTimestampsById.clear();\n\t\tthis.indexed = true;\n\t}\n\n\tprivate _assertMutable(): void {\n\t\tif (this.readOnly) throw new Error(\"Session view is read-only\");\n\t\tif (this.persist && this.sessionFile) {\n\t\t\tassertProductStatePath(this.sessionFile);\n\t\t\tif (this.writeState.owner && realpathIfPresent(this.sessionFile) !== this.writeState.owner.journalPath)\n\t\t\t\tthrow new Error(\"Session source target changed outside its owner\");\n\t\t}\n\t\tif (this.switching || this.closing) throw new Error(\"Session source is switching or closing\");\n\t}\n\n\tasync setSessionFile(sessionFile: string): Promise<void> {\n\t\tthis._assertMutable();\n\t\tconst target = assertProductStatePath(sessionFile);\n\t\tif (realpathIfPresent(target) === this.sessionFile) {\n\t\t\tawait this.flushNow();\n\t\t\treturn;\n\t\t}\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this.flushNow();\n\t\t\tconst next = await SessionManager.open(target, this.sessionDir, this.cwd);\n\t\t\tawait this._adopt(next);\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tasync newSession(options?: NewSessionOptions): Promise<string | undefined> {\n\t\tthis._assertMutable();\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this.flushNow();\n\t\t\tconst next = new SessionManager(this.cwd, this.sessionDir, this.persist, options);\n\t\t\tawait next._openNew();\n\t\t\tawait this._adopt(next);\n\t\t\treturn this.sessionFile;\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tprivate _buildIndex(): void {\n\t\tthis.byId = new Map();\n\t\tthis.labelsById = new Map();\n\t\tthis.labelTimestampsById = new Map();\n\t\tthis.leafId = null;\n\t\tthis.writeState.compactionCount = 0;\n\t\tthis.writeState.sessionName = undefined;\n\t\tfor (const entry of this.fileEntries) {\n\t\t\tif (entry.type === \"session\") continue;\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tif (entry.type === \"compaction\") this.writeState.compactionCount++;\n\t\t\tif (entry.type === \"session_info\") this.writeState.sessionName = entry.name;\n\t\t\tif (entry.type !== \"request\") this.leafId = entry.id;\n\t\t\tif (entry.type === \"label\") {\n\t\t\t\tif (entry.label) {\n\t\t\t\t\tthis.labelsById.set(entry.targetId, entry.label);\n\t\t\t\t\tthis.labelTimestampsById.set(entry.targetId, entry.timestamp);\n\t\t\t\t} else {\n\t\t\t\t\tthis.labelsById.delete(entry.targetId);\n\t\t\t\t\tthis.labelTimestampsById.delete(entry.targetId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.writeState.leafId = this.leafId;\n\t\tthis.writeState.reservedLeaf = this.leafId;\n\t}\n\n\tprivate _notifyPersistListeners(): void {\n\t\tif (!this.sessionFile) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const listener of this.persistListeners) {\n\t\t\ttry {\n\t\t\t\tlistener(this.sessionFile);\n\t\t\t} catch {\n\t\t\t\t// Persistence observers must not break session writes.\n\t\t\t}\n\t\t}\n\t}\n\n\tonPersist(listener: SessionPersistListener): () => void {\n\t\tthis.persistListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.persistListeners.delete(listener);\n\t\t};\n\t}\n\n\tisPersisted(): boolean {\n\t\treturn this.persist;\n\t}\n\n\t/** Actual new-owner creation plus the existing canonical bootstrap-content boundary. */\n\tcanSeedContextModeContract(): boolean {\n\t\treturn this.freshContextPolicySource && !this.readOnly && !this.hasUserContent();\n\t}\n\n\t/** Captured indexed reads require this manager's owned, framed source. */\n\tsupportsCapturedHistoryReads(): boolean {\n\t\treturn this.persist && !this.readOnly && this.writeState.owner?.format === \"framed\";\n\t}\n\n\tgetCwd(): string {\n\t\treturn this.cwd;\n\t}\n\n\tgetSessionDir(): string {\n\t\treturn this.sessionDir;\n\t}\n\n\tgetSessionId(): string {\n\t\treturn this.sessionId;\n\t}\n\n\tgetSessionFile(): string | undefined {\n\t\treturn this.sessionFile;\n\t}\n\n\tasync materializeSessionFile(sessionDir?: string): Promise<string> {\n\t\tthis._assertMutable();\n\t\tif (this.sessionFile) return this.sessionFile;\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this.flushNow();\n\t\t\tconst dir = sessionDir ?? (this.sessionDir || getDefaultSessionDir(this.cwd));\n\t\t\tconst header = this.getHeader();\n\t\t\tconst next = new SessionManager(this.cwd, dir, true, {\n\t\t\t\tparentSession: header?.parentSession,\n\t\t\t\trlmDepth: resolveSessionRlmDepth(header ?? {}, dir),\n\t\t\t});\n\t\t\tconst captured = this.materializeResidentHistory(DEFAULT_MANAGER_HISTORY_LIMITS);\n\t\t\tnext.fileEntries.push(\n\t\t\t\t...captured.entries.map((entry, index) =>\n\t\t\t\t\twithEntryRetention(\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tcaptured.retentions[index] ?? undefined,\n\t\t\t\t\t\tcaptured.qualifications[index] ?? undefined,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t\tnext._buildIndex();\n\t\t\tawait next._openNew();\n\t\t\tawait this._adopt(next);\n\t\t\treturn this.sessionFile!;\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tgetSessionArtifactDir(): string | undefined {\n\t\treturn this.persist && this.sessionFile\n\t\t\t? assertProductStatePath(getSessionArtifactPathForFile(this.sessionFile, this.sessionId))\n\t\t\t: undefined;\n\t}\n\n\t/** Exact source metadata within the captured current branch, not a scan of message arrays. */\n\tgetHistoryEntry(id: string): Promise<IndexedSourceEvent | undefined> {\n\t\treturn this._readHistory((view) => view.get(id));\n\t}\n\n\t/** Exact canonical JSON bytes as bounded UTF8 fragments, within the captured branch. */\n\treadHistoryPayload(\n\t\tid: string,\n\t\toptions: HistoryPayloadReadOptions = {},\n\t): Promise<CanonicalPayloadFragment | undefined> {\n\t\tconst captured = { ...options, ...(options.cursor ? { cursor: { ...options.cursor } } : {}) };\n\t\treturn this._readHistory((view) => view.readPayload(id, captured));\n\t}\n\n\tpageHistory(after = 0, limit = 64): Promise<HistoryIndexPage> {\n\t\treturn this._readHistory((view) => view.page(after, limit));\n\t}\n\n\tsearchHistory(query: string, limit = 16): Promise<HistoryIndexPage> {\n\t\treturn this._readHistory((view) => view.search(query, limit));\n\t}\n\n\t/** Source-order active-context references, not a last-N transcript. */\n\tcontextManifest(options: ContextManifestOptions = {}): Promise<ContextManifestPage> {\n\t\tconst captured = { ...options, ...(options.cursor ? { cursor: { ...options.cursor } } : {}) };\n\t\treturn this._readHistory((view) => view.contextManifest(captured));\n\t}\n\n\t/** Structured descriptive evidence; selective output is not an exhaustive requirements list. */\n\ttaskEvidence(options: TaskEvidenceOptions = {}): Promise<TaskEvidencePage> {\n\t\tconst captured = { ...options, ...(options.after ? { after: { ...options.after } } : {}) };\n\t\treturn this._readHistory((view) => view.taskEvidence(captured));\n\t}\n\n\tprivate async _readHistory<T>(read: (view: SessionHistoryReadView) => Promise<T>): Promise<T> {\n\t\treturn this._runHistoryRead(this.bindRequestSink(), read);\n\t}\n\n\t/** Explicit branch read at one pinned canonical frontier. */\n\treadBranchHistory<T>(read: (view: SessionHistoryReadScope) => Promise<T>): Promise<T> {\n\t\treturn this._runHistoryRead(\n\t\t\tthis._bindHistorySource((index, source, query) =>\n\t\t\t\tcreateSessionHistoryReadScope(index, source, query, \"branch\"),\n\t\t\t),\n\t\t\tread,\n\t\t);\n\t}\n\n\t/** Explicit whole-source read, including branches outside the current leaf. */\n\treadSourceHistory<T>(read: (view: SessionHistoryReadScope) => Promise<T>): Promise<T> {\n\t\treturn this._runHistoryRead(\n\t\t\tthis._bindHistorySource((index, source, query) =>\n\t\t\t\tcreateSessionHistoryReadScope(index, source, query, \"source\"),\n\t\t\t),\n\t\t\tread,\n\t\t);\n\t}\n\n\t/** Read the owner-maintained own-spend projection without hydrating the source. */\n\tasync readOwnUsageSummary(): Promise<SessionUsageSummary | undefined> {\n\t\tthis._assertMutable();\n\t\tif (!this.supportsCapturedHistoryReads()) throw new Error(\"Own usage projection requires an owned native source\");\n\t\tconst state = this.writeState;\n\t\treturn this._enqueue(state, 0, async () => {\n\t\t\tawait state.owner!.flush();\n\t\t\tconst snapshot = state.owner!.getSnapshot();\n\t\t\tawait this._acknowledgedHistory(state, snapshot);\n\t\t\t// Keep later appends queued: the catalog holds current totals, not historical versions.\n\t\t\treturn state.history!.currentSourceUsage(snapshot);\n\t\t});\n\t}\n\n\t/** Complete bounded structured task reduction on one captured native branch. */\n\tasync readTaskState(limits: Partial<TaskStateReadLimits> = {}): Promise<TaskStateView> {\n\t\tconst captured = taskStateReadLimits(limits);\n\t\tif (!this.supportsCapturedHistoryReads())\n\t\t\tthrow new Error(\"Task-state reduction requires captured native history\");\n\t\treturn this.readSourceHistory((history) => readTaskStateFromHistory(history, captured));\n\t}\n\n\t/** Complete actual parent chain, excluding merely attached request evidence. */\n\tprivate async _materializeParentPath(\n\t\tview: SessionHistoryReadScope,\n\t\tleafId: string | null,\n\t\tlimits: SessionHistoryReadLimits,\n\t): Promise<Omit<MaterializedSessionHistory, \"scope\">> {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tconst entries: MaterializedSessionHistory[\"entries\"] = [];\n\t\tlet sourceBytes = 0;\n\t\tlet page = await view.parentPathFrom(leafId);\n\t\tfor (;;) {\n\t\t\tif (page.totalEntries > maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\tfor (const ref of page.events) {\n\t\t\t\tif (entries.length >= maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\t\tconst remaining = maxSourceBytes - sourceBytes;\n\t\t\t\tsourceBytes += ref.locator.length;\n\t\t\t\tif (sourceBytes > maxSourceBytes) throw new Error(\"Parent-path source byte budget exceeded\");\n\t\t\t\tconst hydrated = await view.hydrateEntry(ref.id, remaining);\n\t\t\t\tif (!hydrated) throw new Error(\"Parent-path entry source is unavailable\");\n\t\t\t\tentries.push(hydrated);\n\t\t\t}\n\t\t\tif (!page.nextCursor) return { source: view.source, entries, sourceBytes };\n\t\t\tpage = await view.parentPathFrom(leafId, { cursor: page.nextCursor });\n\t\t}\n\t}\n\n\tasync materializeParentPathHistory(\n\t\tlimits: SessionHistoryReadLimits,\n\t): Promise<Omit<MaterializedSessionHistory, \"scope\">> {\n\t\tconst capturedLimits = { ...limits };\n\t\treturn this.readSourceHistory((history) =>\n\t\t\tthis._materializeParentPath(history, history.source.leafId, capturedLimits),\n\t\t);\n\t}\n\n\tmaterializeBranchHistory(limits: SessionHistoryReadLimits): Promise<MaterializedSessionHistory> {\n\t\tconst captured = { ...limits };\n\t\treturn this.readBranchHistory((view) => view.materialize(captured));\n\t}\n\n\tmaterializeSourceHistory(limits: SessionHistoryReadLimits): Promise<MaterializedSessionHistory> {\n\t\tconst captured = { ...limits };\n\t\treturn this.readSourceHistory((view) => view.materialize(captured));\n\t}\n\n\tprivate async _runHistoryRead<View, T>(\n\t\tsink: BoundHistoryReadSink<View>,\n\t\tread: (view: View) => Promise<T>,\n\t): Promise<T> {\n\t\tconst outcome = await sink.readHistory(read).then(\n\t\t\t(value) => ({ ok: true, value }) as const,\n\t\t\t(error: unknown) => ({ ok: false, error }) as const,\n\t\t);\n\t\ttry {\n\t\t\tawait sink.release();\n\t\t} catch (error) {\n\t\t\tif (!outcome.ok) throw new AggregateError([outcome.error, error], \"History read and source release failed\");\n\t\t\tthrow error;\n\t\t}\n\t\tif (!outcome.ok) throw outcome.error;\n\t\treturn outcome.value;\n\t}\n\n\tprivate _publishHistory(state: SessionWriteState): void {\n\t\tif (state.history && state.owner) state.history.publish(state.owner.getSnapshot());\n\t}\n\n\tprivate async _releaseSourcePin(state: SessionWriteState): Promise<void> {\n\t\tstate.pins--;\n\t\tif (state.pins === 0) {\n\t\t\tstate.onUnpinned?.();\n\t\t\tstate.onUnpinned = undefined;\n\t\t\tstate.unpinned = undefined;\n\t\t}\n\t\tawait this._closeRetired(state);\n\t}\n\n\tprivate async _closeSourceActors(state: SessionWriteState): Promise<void> {\n\t\tconst errors: unknown[] = [];\n\t\ttry {\n\t\t\tawait state.history?.close();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\t// Keep the canonical fence until the derived reader has exited, including failed shutdown.\n\t\ttry {\n\t\t\tawait state.owner?.close();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tif (errors.length === 1) throw errors[0];\n\t\tif (errors.length > 1) throw new AggregateError(errors, \"Session source actors failed to close\");\n\t}\n\n\t/** Wait for all previously admitted writes and the writer's durability barrier. */\n\tasync flushNow(): Promise<void> {\n\t\tconst state = this.writeState;\n\t\tawait this._enqueue(state, 0, async () => {\n\t\t\tawait state.owner?.flush();\n\t\t});\n\t}\n\n\tasync migrateLegacy(): Promise<void> {\n\t\tthis._assertMutable();\n\t\tconst state = this.writeState;\n\t\tif (state.pins > 0) throw new Error(\"Drain captured requests before migrating session history\");\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait this._enqueue(state, 0, async () => {\n\t\t\t\tif (!state.owner) throw new Error(\"An owned persistent source is required for migration\");\n\t\t\t\tif (state.sourceVersion !== CURRENT_SESSION_VERSION)\n\t\t\t\t\tthrow new Error(\"Legacy session payload requires an explicit retained import before writing\");\n\t\t\t\ttry {\n\t\t\t\t\tawait state.owner.migrateLegacy();\n\t\t\t\t\tstate.sequence = state.owner.nextSequence - 1;\n\t\t\t\t\tawait this._activateIndexedSource(this.getHeader()!, state);\n\t\t\t\t\tthis._publishHistory(state);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.failure = new Error(\"Session source migration failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\t/** Re-open and replay after explicit exclusive repair; never re-execute an effect. */\n\tasync recover(): Promise<void> {\n\t\tthis._assertMutable();\n\t\tconst previous = this.writeState;\n\t\tif (!this.persist || !this.sessionFile || this.readOnly)\n\t\t\tthrow new Error(\"An owned persistent source is required for recovery\");\n\t\tif (previous.pins > 0 || previous.pending > 0)\n\t\t\tthrow new Error(\"Drain captured requests and source writes before recovery\");\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\tawait previous.tail;\n\t\t\tawait this._closeSourceActors(previous);\n\t\t\tprevious.closed = true;\n\t\t\tconst owner = await SessionJournalOwner.open({ journalPath: this.sessionFile });\n\t\t\tconst state = newSessionWriteState();\n\t\t\tstate.owner = owner;\n\t\t\ttry {\n\t\t\t\tawait owner.recover();\n\t\t\t\tlet residentEntries: FileEntry[] | undefined;\n\t\t\t\tlet header: SessionHeader;\n\t\t\t\tif (owner.format === \"framed\") header = await readOwnedSessionHeader(owner.getSnapshot());\n\t\t\t\telse {\n\t\t\t\t\tresidentEntries = await loadEntriesFromFileAsync(owner.journalPath);\n\t\t\t\t\tconst first = residentEntries[0];\n\t\t\t\t\tif (!first || first.type !== \"session\") throw new Error(\"Recovered source has no valid header\");\n\t\t\t\t\theader = first;\n\t\t\t\t}\n\t\t\t\tif (header.id !== this.sessionId) throw new Error(\"Recovered source identity does not match this session\");\n\t\t\t\tstate.sequence = owner.nextSequence - 1;\n\t\t\t\tstate.sourceVersion = header.version ?? 1;\n\t\t\t\tif (owner.format === \"framed\" && state.sourceVersion === CURRENT_SESSION_VERSION)\n\t\t\t\t\tawait this._activateIndexedSource(header, state);\n\t\t\t\telse {\n\t\t\t\t\tconst entries = residentEntries ?? (await loadEntriesFromFileAsync(owner.journalPath));\n\t\t\t\t\tmigrateToCurrentVersion(entries);\n\t\t\t\t\tthis.indexed = false;\n\t\t\t\t\tthis.fileEntries = entries;\n\t\t\t\t\tthis.writeState = state;\n\t\t\t\t\tthis._buildIndex();\n\t\t\t\t}\n\t\t\t\tthis.finalizedToolMessages = new WeakMap();\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this._closeSourceActors(state);\n\t\t\t\t} catch (cleanup) {\n\t\t\t\t\tthrow new AggregateError([error, cleanup], \"Session recovery and cleanup failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tprivate _enqueue<T>(state: SessionWriteState, bytes: number, action: () => Promise<T>): Promise<T> {\n\t\tif (state.closed) return Promise.reject(new Error(\"Session source owner is closed\"));\n\t\tif (state.failure) return Promise.reject(state.failure);\n\t\tif (state.pending >= MAX_SESSION_PENDING_OPERATIONS || state.bytes + bytes > MAX_SESSION_PENDING_BYTES)\n\t\t\treturn Promise.reject(new Error(\"Session source queue limit exceeded\"));\n\t\tstate.pending++;\n\t\tstate.bytes += bytes;\n\t\tconst result = state.tail.then(async () => {\n\t\t\tif (state.failure) throw state.failure;\n\t\t\treturn action();\n\t\t});\n\t\tstate.tail = result\n\t\t\t.then(\n\t\t\t\t() => undefined,\n\t\t\t\t() => undefined,\n\t\t\t)\n\t\t\t.finally(() => {\n\t\t\t\tstate.pending--;\n\t\t\t\tstate.bytes -= bytes;\n\t\t\t});\n\t\treturn result;\n\t}\n\n\tprivate async _appendIndexedEntry(\n\t\tstate: SessionWriteState,\n\t\tentry: SessionEntry,\n\t\texplicitParent = false,\n\t\tprepare?: (snapshot: SessionEntry) => void | Promise<void>,\n\t\tonDuplicate?: (entry: SessionEntry) => SessionEntry,\n\t\tadvanceLeaf = true,\n\t\tdeduplicate?: (history: SessionHistoryReadScope) => Promise<SessionEntry | undefined>,\n\t\tassertCurrent?: () => void,\n\t): Promise<SessionEntry> {\n\t\tif (state.failure) throw state.failure;\n\t\tconst generated = entry.id === \"\";\n\t\tconst initial = { ...entry, parentId: explicitParent ? entry.parentId : null };\n\t\tconst snapshot = withEntryRetention(\n\t\t\tJSON.parse(stringifyBoundedJson(initial, MAX_SESSION_RECORD_BYTES)) as SessionEntry,\n\t\t\tentryRetentions.get(entry),\n\t\t\tentryQualifications.get(entry),\n\t\t);\n\t\tconst ownsPendingId = !generated && !state.pendingIds.has(snapshot.id);\n\t\tif (!generated && !ownsPendingId && !onDuplicate) throw new Error(`Duplicate session entry: ${snapshot.id}`);\n\t\tconst idBytes = (id: string) => Buffer.byteLength(JSON.stringify(id));\n\t\tconst parentBytes = explicitParent\n\t\t\t? 0\n\t\t\t: Math.max(38, idBytes(state.leafId ?? \"\"), ...Array.from(state.pendingIds, idBytes));\n\t\tconst admittedBytes =\n\t\t\tBuffer.byteLength(stringifyBoundedJson(snapshot, MAX_SESSION_RECORD_BYTES)) +\n\t\t\tparentBytes +\n\t\t\t(generated ? 36 : 0) +\n\t\t\t(prepare ? 16 * 1024 : 0);\n\t\tif (state.pending >= MAX_SESSION_PENDING_OPERATIONS || state.bytes + admittedBytes > MAX_SESSION_PENDING_BYTES)\n\t\t\tthrow new Error(\"Session source queue limit exceeded\");\n\t\tif (ownsPendingId) state.pendingIds.add(snapshot.id);\n\t\ttry {\n\t\t\treturn await this._enqueue(state, admittedBytes, async () => {\n\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\tconst duplicate = await deduplicate?.(history);\n\t\t\t\tif (duplicate) return duplicate;\n\t\t\t\tif (generated) {\n\t\t\t\t\tfor (let attempt = 0; ; attempt++) {\n\t\t\t\t\t\tconst id = attempt < 100 ? randomUUID().slice(0, 8) : randomUUID();\n\t\t\t\t\t\tif (state.pendingIds.has(id) || (await history.get(id))) {\n\t\t\t\t\t\t\tif (attempt >= 100) throw new Error(`Duplicate session entry: ${id}`);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsnapshot.id = id;\n\t\t\t\t\t\tstate.pendingIds.add(id);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst reference = await history.get(snapshot.id);\n\t\t\t\t\tif (reference) {\n\t\t\t\t\t\tif (!onDuplicate) throw new Error(`Duplicate session entry: ${snapshot.id}`);\n\t\t\t\t\t\tconst existing = await history.hydrateEntry(reference.id, MAX_SESSION_RECORD_BYTES);\n\t\t\t\t\t\tif (!existing) throw new Error(\"Duplicate entry source is unavailable\");\n\t\t\t\t\t\treturn onDuplicate(existing.entry);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!explicitParent) snapshot.parentId = state.leafId;\n\t\t\t\tif (prepare) await prepare(snapshot);\n\t\t\t\tconst metadata = await this._prepareOwnedMetadata(state, snapshot, history, advanceLeaf);\n\t\t\t\tconst json = stringifyBoundedJson(snapshot, Math.min(admittedBytes, MAX_SESSION_RECORD_BYTES));\n\t\t\t\tassertCurrent?.();\n\t\t\t\ttry {\n\t\t\t\t\tconst ack = await appendSourceEntry(state.owner!, json, snapshot);\n\t\t\t\t\tstate.sequence = ack.sequence;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.failure = new Error(\"Session source append failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tObject.assign(state, metadata);\n\t\t\t\tstate.metadataRefs = undefined;\n\t\t\t\tif (advanceLeaf) {\n\t\t\t\t\tstate.leafId = snapshot.id;\n\t\t\t\t\tif (!isCompactionBookkeeping(snapshot)) state.compactionRevision++;\n\t\t\t\t}\n\t\t\t\tstate.reservedLeaf = state.leafId;\n\t\t\t\tif (this.writeState === state) this.leafId = state.leafId;\n\t\t\t\tthis._publishHistory(state);\n\t\t\t\tentry.id = snapshot.id;\n\t\t\t\tif (this.writeState === state) this._notifyPersistListeners();\n\t\t\t\treturn snapshot;\n\t\t\t});\n\t\t} finally {\n\t\t\tif (generated || ownsPendingId) state.pendingIds.delete(snapshot.id);\n\t\t}\n\t}\n\n\tprivate async _appendEntry(\n\t\tentry: SessionEntry,\n\t\texplicitParent = false,\n\t\tprepare?: (snapshot: SessionEntry) => void | Promise<void>,\n\t\tonDuplicate?: (entry: SessionEntry) => SessionEntry,\n\t\tassertCurrent?: () => void,\n\t): Promise<SessionEntry> {\n\t\tthis._assertMutable();\n\t\tif (this.indexed)\n\t\t\treturn this._appendIndexedEntry(\n\t\t\t\tthis.writeState,\n\t\t\t\tentry,\n\t\t\t\texplicitParent,\n\t\t\t\tprepare,\n\t\t\t\tonDuplicate,\n\t\t\t\ttrue,\n\t\t\t\tundefined,\n\t\t\t\tassertCurrent,\n\t\t\t);\n\t\tconst state = this.writeState;\n\t\tif (state.failure) throw state.failure;\n\t\tif (state.owner?.format === \"legacy\") throw new Error(\"Session journal requires explicit legacy migration\");\n\t\tif (this.byId.has(entry.id) || state.pendingIds.has(entry.id))\n\t\t\tthrow new Error(`Duplicate session entry: ${entry.id}`);\n\t\tif (!explicitParent) entry.parentId = state.pending ? state.reservedLeaf : this.leafId;\n\t\tlet json = stringifyBoundedJson(entry, MAX_SESSION_RECORD_BYTES);\n\t\tconst retention = entryRetentions.get(entry);\n\t\tconst snapshot = withEntryRetention(JSON.parse(json) as SessionEntry, retention, entryQualifications.get(entry));\n\t\t// Queued usage projection only changes a fixed set of numeric fields.\n\t\tlet parentBytes = 0;\n\t\tif (!explicitParent) {\n\t\t\tparentBytes = Math.max(38, Buffer.byteLength(JSON.stringify(state.leafId)));\n\t\t\tfor (const id of state.pendingIds) parentBytes = Math.max(parentBytes, Buffer.byteLength(JSON.stringify(id)));\n\t\t}\n\t\tconst admittedBytes = Buffer.byteLength(json) + parentBytes + (prepare ? 16 * 1024 : 0);\n\t\tconst entries = this.fileEntries;\n\t\tconst byId = this.byId;\n\t\tconst labels = this.labelsById;\n\t\tconst labelTimes = this.labelTimestampsById;\n\t\tif (state.pending >= MAX_SESSION_PENDING_OPERATIONS || state.bytes + admittedBytes > MAX_SESSION_PENDING_BYTES)\n\t\t\tthrow new Error(\"Session source queue limit exceeded\");\n\t\tstate.reservedLeaf = snapshot.id;\n\t\tstate.pendingIds.add(snapshot.id);\n\t\ttry {\n\t\t\tawait this._enqueue(state, admittedBytes, async () => {\n\t\t\t\tif (!explicitParent) snapshot.parentId = state.leafId;\n\t\t\t\tif (prepare) await prepare(snapshot);\n\t\t\t\tjson = stringifyBoundedJson(snapshot, admittedBytes);\n\t\t\t\tassertCurrent?.();\n\t\t\t\ttry {\n\t\t\t\t\tif (state.owner) {\n\t\t\t\t\t\tconst ack = await appendSourceEntry(state.owner, json, snapshot);\n\t\t\t\t\t\tstate.sequence = ack.sequence;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstate.sequence++;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.failure = new Error(\"Session source append failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tthis._publishHistory(state);\n\t\t\t\tentries.push(snapshot);\n\t\t\t\tbyId.set(snapshot.id, snapshot);\n\t\t\t\tif (snapshot.type === \"compaction\") state.compactionCount++;\n\t\t\t\tif (snapshot.type === \"session_info\") state.sessionName = snapshot.name;\n\t\t\t\tif (snapshot.type === \"label\") {\n\t\t\t\t\tif (snapshot.label) {\n\t\t\t\t\t\tlabels.set(snapshot.targetId, snapshot.label);\n\t\t\t\t\t\tlabelTimes.set(snapshot.targetId, snapshot.timestamp);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlabels.delete(snapshot.targetId);\n\t\t\t\t\t\tlabelTimes.delete(snapshot.targetId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (snapshot.type === \"child_usage_attributed\") {\n\t\t\t\t\tconst target = byId.get(snapshot.targetId);\n\t\t\t\t\tif (target?.type === \"message\" && target.message.role === \"assistant\")\n\t\t\t\t\t\ttarget.message.usage = cloneUsage(snapshot.aggregateUsage);\n\t\t\t\t}\n\t\t\t\tstate.leafId = snapshot.id;\n\t\t\t\tif (!isCompactionBookkeeping(snapshot)) state.compactionRevision++;\n\t\t\t\tif (this.writeState === state) {\n\t\t\t\t\tthis.leafId = snapshot.id;\n\t\t\t\t\tthis._notifyPersistListeners();\n\t\t\t\t}\n\t\t\t});\n\t\t} finally {\n\t\t\tstate.pendingIds.delete(snapshot.id);\n\t\t}\n\t\treturn snapshot;\n\t}\n\n\tprivate async _closeRetired(state: SessionWriteState): Promise<void> {\n\t\tif (!state.retired || state.pins > 0) return;\n\t\tstate.closing ??= (async () => {\n\t\t\tawait state.tail;\n\t\t\tawait this._closeSourceActors(state);\n\t\t\tstate.closed = true;\n\t\t\tthis.retiredSources.delete(state);\n\t\t})();\n\t\tawait state.closing;\n\t}\n\n\tprivate async _retire(state: SessionWriteState): Promise<void> {\n\t\tstate.retired = true;\n\t\tthis.retiredSources.add(state);\n\t\tawait this._closeRetired(state);\n\t}\n\n\tclose(): Promise<void> {\n\t\tthis.closing ??= (async () => {\n\t\t\tawait this._retire(this.writeState);\n\t\t\tfor (const state of [...this.retiredSources]) {\n\t\t\t\tif (state.pins > 0) {\n\t\t\t\t\tstate.unpinned ??= new Promise<void>((resolve) => {\n\t\t\t\t\t\tstate.onUnpinned = resolve;\n\t\t\t\t\t});\n\t\t\t\t\tawait state.unpinned;\n\t\t\t\t}\n\t\t\t\tawait this._closeRetired(state);\n\t\t\t}\n\t\t})();\n\t\treturn this.closing;\n\t}\n\n\t/** Capture before waits; the barrier resolves only after this source's prior ACKs. */\n\tbindRequestSink(): BoundSessionRequestSink {\n\t\treturn this._bindHistorySource(createBranchHistoryReadView);\n\t}\n\n\t/** Capture ownership, not a history frontier: ordinary appends may finish before the checkpoint capture. */\n\tcaptureCompactionSourceOwner(): () => boolean {\n\t\tconst state = this.writeState;\n\t\tconst owner = state.owner;\n\t\tconst sessionId = this.sessionId;\n\t\tconst sessionFile = this.sessionFile;\n\t\tconst selectionRevision = state.branchSelectionRevision;\n\t\treturn () =>\n\t\t\tthis.writeState === state &&\n\t\t\tstate.owner === owner &&\n\t\t\t!state.retired &&\n\t\t\t!state.closed &&\n\t\t\tthis.sessionId === sessionId &&\n\t\t\tthis.sessionFile === sessionFile &&\n\t\t\tstate.branchSelectionRevision === selectionRevision;\n\t}\n\n\tbindCompactionSink(limits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS): BoundCompactionSink {\n\t\tconst state = this.writeState;\n\t\tconst owner = state.owner;\n\t\tconst sessionId = this.sessionId;\n\t\tconst sessionFile = this.sessionFile;\n\t\tconst indexed = this.indexed;\n\t\tconst byId = this.byId;\n\t\tconst capturedLimits = { ...limits };\n\t\tlet residentBranch: SessionEntry[] | undefined;\n\t\tlet capturedSource: SourceSnapshotRef | undefined;\n\t\tlet captureFailure: unknown;\n\t\tlet selectionRevision: number;\n\t\tlet compactionRevision: number;\n\t\tlet currentRevision: number;\n\t\tconst isCurrent = (revision: number) =>\n\t\t\tcapturedSource !== undefined &&\n\t\t\tthis.writeState === state &&\n\t\t\tstate.owner === owner &&\n\t\t\t!state.retired &&\n\t\t\t!state.closed &&\n\t\t\tthis.sessionId === sessionId &&\n\t\t\tthis.sessionFile === sessionFile &&\n\t\t\tstate.branchSelectionRevision === selectionRevision &&\n\t\t\tstate.compactionRevision === revision;\n\t\tconst sink = this._bindHistorySource(\n\t\t\t(index, source, query) => createSessionHistoryReadScope(index, source, query, \"source\"),\n\t\t\t(source) => {\n\t\t\t\tselectionRevision = state.branchSelectionRevision;\n\t\t\t\tcompactionRevision = state.compactionRevision;\n\t\t\t\tcurrentRevision = compactionRevision;\n\t\t\t\tif (!indexed)\n\t\t\t\t\tresidentBranch = this._readResidentBranches([source.leafId], capturedLimits, byId).branches[0];\n\t\t\t\tcapturedSource = source;\n\t\t\t},\n\t\t);\n\t\tvoid sink.source.catch((error: unknown) => {\n\t\t\tcaptureFailure = error;\n\t\t});\n\t\tconst appendCaptured = async (\n\t\t\tsummary: string,\n\t\t\tfirstKeptEntryId: string,\n\t\t\ttokensBefore: number | null,\n\t\t\tdetails?: unknown,\n\t\t\tfromHook?: boolean,\n\t\t\tinstructions?: string,\n\t\t\tusage?: Usage,\n\t\t\tqualification?: NativeEntryQualification,\n\t\t\trequestOutputSource?: object,\n\t\t): Promise<string> => {\n\t\t\tsink.assertRetained();\n\t\t\tconst values = {\n\t\t\t\tsummary,\n\t\t\t\tfirstKeptEntryId,\n\t\t\t\ttokensBefore,\n\t\t\t\tdetails,\n\t\t\t\tfromHook,\n\t\t\t\tinstructions,\n\t\t\t\tusage: usage ? cloneUsage(usage) : undefined,\n\t\t\t\trequestOutputs:\n\t\t\t\t\tfromHook === false ? takeCompactionRequestOutputs(requestOutputSource, bound, summary) : undefined,\n\t\t\t};\n\t\t\tconst snapshot = JSON.parse(stringifyBoundedJson(values, MAX_SESSION_RECORD_BYTES)) as typeof values;\n\t\t\tconst assertCurrent = () => {\n\t\t\t\tif (captureFailure !== undefined) throw captureFailure;\n\t\t\t\tif (qualification === \"native-context-epoch\") {\n\t\t\t\t\tconst epoch = (snapshot.details as { [CONTEXT_EPOCH_DETAIL]: ContextEpochCheckpoint })[\n\t\t\t\t\t\tCONTEXT_EPOCH_DETAIL\n\t\t\t\t\t];\n\t\t\t\t\tif (JSON.stringify(epoch.source) !== JSON.stringify(capturedSource))\n\t\t\t\t\t\tthrow new Error(\"Context epoch does not match the bound source capture\");\n\t\t\t\t}\n\t\t\t\tif (!isCurrent(compactionRevision)) throw new Error(\"Compaction source or branch changed\");\n\t\t\t};\n\t\t\t// Admission is synchronous; this append queues behind the capture before release can drain it.\n\t\t\tconst args = [\n\t\t\t\tsnapshot.summary,\n\t\t\t\tsnapshot.firstKeptEntryId,\n\t\t\t\tsnapshot.tokensBefore,\n\t\t\t\tsnapshot.details,\n\t\t\t\tsnapshot.fromHook,\n\t\t\t\tsnapshot.instructions,\n\t\t\t\tsnapshot.usage,\n\t\t\t\tassertCurrent,\n\t\t\t] as const;\n\t\t\tconst entryId = await (qualification || snapshot.requestOutputs\n\t\t\t\t? this._appendCompaction(...args, qualification, snapshot.requestOutputs)\n\t\t\t\t: this.appendCompaction(...args));\n\t\t\tcurrentRevision = compactionRevision + 1;\n\t\t\treturn entryId;\n\t\t};\n\t\tconst bound: BoundCompactionSink = {\n\t\t\t...sink,\n\t\t\tisCurrent: () => isCurrent(currentRevision),\n\t\t\treadHistory: (read) => sink.readHistory((history) => read(history.branchContext)),\n\t\t\t[readCopiedEpochSource]: (read) => sink.readHistory(read),\n\t\t\treadBranch: async () => {\n\t\t\t\tif (indexed)\n\t\t\t\t\treturn sink.readHistory(\n\t\t\t\t\t\tasync (history) =>\n\t\t\t\t\t\t\t(await this._readBranchesAt(history, [history.source.leafId], capturedLimits)).branches[0],\n\t\t\t\t\t);\n\t\t\t\tsink.assertRetained();\n\t\t\t\tawait sink.source;\n\t\t\t\treturn residentBranch!.map((entry) =>\n\t\t\t\t\twithEntryRetention(\n\t\t\t\t\t\tJSON.parse(stringifyBoundedJson(entry, capturedLimits.maxSourceBytes)) as SessionEntry,\n\t\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t},\n\t\t\tappendCompaction: (\n\t\t\t\tsummary,\n\t\t\t\tfirstKeptEntryId,\n\t\t\t\ttokensBefore,\n\t\t\t\tdetails,\n\t\t\t\tfromHook,\n\t\t\t\tinstructions,\n\t\t\t\tusage,\n\t\t\t\toutputSource,\n\t\t\t) =>\n\t\t\t\tappendCaptured(\n\t\t\t\t\tsummary,\n\t\t\t\t\tfirstKeptEntryId,\n\t\t\t\t\ttokensBefore,\n\t\t\t\t\tdetails,\n\t\t\t\t\tfromHook,\n\t\t\t\t\tinstructions,\n\t\t\t\t\tusage,\n\t\t\t\t\tundefined,\n\t\t\t\t\toutputSource,\n\t\t\t\t),\n\t\t\t[appendContextEpoch]: (checkpoint, tokensBefore, summary, outputSource) => {\n\t\t\t\tif (checkpoint.policyOnly && (tokensBefore !== null || summary !== undefined))\n\t\t\t\t\tthrow new Error(\"Context mode policy ACK is not a measured request or summary\");\n\t\t\t\tif (Boolean(summary) !== Boolean(checkpoint.includeSummary))\n\t\t\t\t\tthrow new Error(\"Context epoch summary does not match its rendering plan\");\n\t\t\t\treturn appendCaptured(\n\t\t\t\t\tsummary?.summary ?? \"\",\n\t\t\t\t\tcheckpoint.literalTailId,\n\t\t\t\t\ttokensBefore,\n\t\t\t\t\t{ ...summary?.details, [CONTEXT_EPOCH_DETAIL]: checkpoint },\n\t\t\t\t\tsummary?.fromHook ?? false,\n\t\t\t\t\tsummary?.customInstructions,\n\t\t\t\t\tsummary?.usage,\n\t\t\t\t\t\"native-context-epoch\",\n\t\t\t\t\toutputSource,\n\t\t\t\t);\n\t\t\t},\n\t\t};\n\t\tconst outputSource = nativeRequestOutputSources.get(sink);\n\t\tif (outputSource) nativeRequestOutputSources.set(bound, { ...outputSource, compaction: true });\n\t\treturn bound;\n\t}\n\n\tprivate _bindHistorySource<View>(\n\t\tcreateView: (index: HistoryIndex, source: SourceSnapshotRef, query: HistoryReadQuery) => View,\n\t\tonCapture?: (source: SourceSnapshotRef) => void,\n\t): BoundHistoryReadSink<View> & { assertRetained(): void } {\n\t\tthis._assertMutable();\n\t\tconst state = this.writeState;\n\t\tconst sourceFile =\n\t\t\tstate.owner?.journalPath ?? (this.sessionFile ? realpathIfPresent(resolve(this.sessionFile)) : undefined);\n\t\tconst sessionId = this.sessionId;\n\t\tconst persistent = this.persist;\n\t\tconst indexed = this.indexed;\n\t\tconst entries = this.fileEntries;\n\t\tconst byId = this.byId;\n\t\tconst writer = state.owner;\n\t\tconst ownsOutputSource = SessionManager.prototype.captureCompactionSourceOwner.call(this);\n\t\tlet outputSource: SourceSnapshotRef | undefined;\n\t\tlet held = false;\n\t\tconst retain = () => {\n\t\t\tif (held) return;\n\t\t\tif (state.closed || state.closing) throw new Error(\"Captured session source owner is closed\");\n\t\t\theld = true;\n\t\t\tstate.pins++;\n\t\t};\n\t\tconst assertRetained = () => {\n\t\t\tif (!held) throw new Error(\"Captured request sink is not retained\");\n\t\t};\n\t\tretain();\n\t\tconst captured = this._enqueue(state, 0, async () => {\n\t\t\tawait state.owner?.flush();\n\t\t\tconst source: SourceSnapshotRef = Object.freeze({\n\t\t\t\tsessionId,\n\t\t\t\t...(sourceFile ? { sessionFile: sourceFile } : {}),\n\t\t\t\tleafId: state.leafId,\n\t\t\t\tsourceSequence: state.sequence,\n\t\t\t\tpersistent,\n\t\t\t});\n\t\t\tconst snapshot = state.owner?.getSnapshot();\n\t\t\toutputSource = source;\n\t\t\tonCapture?.(source);\n\t\t\treturn { source, snapshot };\n\t\t});\n\t\tconst source = captured.then((value) => value.source);\n\t\t// A captured auxiliary operation can await UI work before consuming its barrier.\n\t\tvoid source.catch(() => undefined);\n\t\tconst sink: BoundHistoryReadSink<View> & { assertRetained(): void } = {\n\t\t\tsource,\n\t\t\tassertRetained,\n\t\t\treadHistory: async <T>(read: (view: View) => Promise<T>): Promise<T> => {\n\t\t\t\tassertRetained();\n\t\t\t\t// A running read holds its own pin if request disposal happens concurrently.\n\t\t\t\tstate.pins++;\n\t\t\t\ttry {\n\t\t\t\t\tconst { source: boundSource, snapshot } = await captured;\n\t\t\t\t\tif (!snapshot || snapshot.format !== \"framed\" || state.sourceVersion !== CURRENT_SESSION_VERSION)\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\"Indexed history requires an owned canonical session; import or migrate legacy history explicitly\",\n\t\t\t\t\t\t);\n\t\t\t\t\tstate.history ??= new SessionHistoryIndex(\n\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\tjoin(\n\t\t\t\t\t\t\tassertProductStatePath(getSessionArtifactPathForFile(snapshot.journalPath, sessionId)),\n\t\t\t\t\t\t\t\"history.sqlite\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tconst index = await state.history.synchronize(snapshot);\n\t\t\t\t\tlet active = true;\n\t\t\t\t\tconst query: HistoryReadQuery = (operation) => {\n\t\t\t\t\t\tif (!active) return Promise.reject(new Error(\"Captured history read has ended\"));\n\t\t\t\t\t\treturn operation();\n\t\t\t\t\t};\n\t\t\t\t\tconst view = createView(index, boundSource, query);\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn await read(view);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tactive = false;\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tawait this._releaseSourcePin(state);\n\t\t\t\t}\n\t\t\t},\n\t\t\tretain,\n\t\t\trelease: async () => {\n\t\t\t\tif (!held) return;\n\t\t\t\theld = false;\n\t\t\t\tawait this._releaseSourcePin(state);\n\t\t\t},\n\t\t\tpersist: async (event: NativeRequestEvent) => {\n\t\t\t\tassertRetained();\n\t\t\t\tif (state.owner) assertProductStatePath(state.owner.journalPath);\n\t\t\t\tif (state.owner?.format === \"legacy\") throw new Error(\"Session journal requires explicit legacy migration\");\n\t\t\t\tconst snapshot = await source;\n\t\t\t\tconst request = JSON.parse(stringifyBoundedJson(event, 1024 * 1024)) as NativeRequestEvent;\n\t\t\t\tif (!isDeepStrictEqual(request.source, snapshot))\n\t\t\t\t\tthrow new Error(\"Request event does not match its bound source\");\n\t\t\t\tconst id = `${request.attemptId}:${request.type}`;\n\t\t\t\tconst entry: RequestJournalEntry = {\n\t\t\t\t\ttype: \"request\",\n\t\t\t\t\tid,\n\t\t\t\t\tparentId: snapshot.leafId,\n\t\t\t\t\ttimestamp: new Date(request.timestamp).toISOString(),\n\t\t\t\t\trequest,\n\t\t\t\t};\n\t\t\t\tconst json = stringifyBoundedJson(entry, 1024 * 1024 - 1);\n\t\t\t\tif (indexed) {\n\t\t\t\t\tawait this._appendIndexedEntry(\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t(existing) => {\n\t\t\t\t\t\t\tif (existing.type !== \"request\" || !isDeepStrictEqual(existing.request, request))\n\t\t\t\t\t\t\t\tthrow new Error(`Conflicting request event: ${id}`);\n\t\t\t\t\t\t\treturn existing;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait this._enqueue(state, Buffer.byteLength(json), async () => {\n\t\t\t\t\tconst existing = byId.get(id);\n\t\t\t\t\tif (existing) {\n\t\t\t\t\t\tif (existing.type !== \"request\" || !isDeepStrictEqual(existing.request, request))\n\t\t\t\t\t\t\tthrow new Error(`Conflicting request event: ${id}`);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (state.owner) state.sequence = (await state.owner.appendJson(json)).sequence;\n\t\t\t\t\t\telse state.sequence++;\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tstate.failure = new Error(\"Session request append failed; outcome may be unknown\", { cause: error });\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\tthis._publishHistory(state);\n\t\t\t\t\tentries.push(entry);\n\t\t\t\t\tbyId.set(id, entry);\n\t\t\t\t\tif (this.writeState === state) this._notifyPersistListeners();\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t\tif (persistent && indexed && writer?.format === \"framed\") {\n\t\t\tconst capture: NativeOutputCapture = (association) => {\n\t\t\t\tif (!outputSource || !ownsOutputSource() || !isDeepStrictEqual(association.source, outputSource))\n\t\t\t\t\treturn undefined;\n\t\t\t\treturn structuredClone(association);\n\t\t\t};\n\t\t\tnativeRequestOutputSources.set(sink, {\n\t\t\t\tcapture,\n\t\t\t\tplanner: (association) => {\n\t\t\t\t\tconst request = capture(association);\n\t\t\t\t\tif (!request) return undefined;\n\t\t\t\t\treturn (manager, result) => {\n\t\t\t\t\t\tif (manager !== this || !ownsOutputSource()) return undefined;\n\t\t\t\t\t\tconst stale = new Error(\"Native planner source changed before result append\");\n\t\t\t\t\t\tconst assertCurrent = () => {\n\t\t\t\t\t\t\tif (!ownsOutputSource()) throw stale;\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn (async () => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\treturn await this._appendCustomEntry(\n\t\t\t\t\t\t\t\t\t\"prime-agent.refinement\",\n\t\t\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\t\t\tassertCurrent,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t// Only this final pre-write stale signal permits the ordinary unassociated append.\n\t\t\t\t\t\t\t\tif (error === stale) return undefined;\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})();\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tbranch: (association) => {\n\t\t\t\t\tconst requestOutput = capture(association);\n\t\t\t\t\tif (!requestOutput) return undefined;\n\t\t\t\t\treturn (manager, branchFromId, summary, details, usage) => {\n\t\t\t\t\t\tif (manager !== this || !ownsOutputSource()) return undefined;\n\t\t\t\t\t\tconst stale = new Error(\"Native branch summary source changed before append\");\n\t\t\t\t\t\tconst assertCurrent = () => {\n\t\t\t\t\t\t\tif (!ownsOutputSource()) throw stale;\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn (async () => {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\treturn await this._branchWithSummary(branchFromId, summary, details, false, usage, {\n\t\t\t\t\t\t\t\t\trequestOutput,\n\t\t\t\t\t\t\t\t\tassertCurrent,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t// Only our final pre-write stale signal permits the ordinary unassociated append.\n\t\t\t\t\t\t\t\tif (error === stale) return undefined;\n\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})();\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tmain: (association) => {\n\t\t\t\t\tconst requestOutput = capture(association);\n\t\t\t\t\tif (!requestOutput) return undefined;\n\t\t\t\t\treturn async (manager, message) => {\n\t\t\t\t\t\tif (manager !== this || !ownsOutputSource()) return undefined;\n\t\t\t\t\t\tconst stale = new Error(\"Native request output source changed before append\");\n\t\t\t\t\t\tconst assertCurrent = () => {\n\t\t\t\t\t\t\tif (!ownsOutputSource()) throw stale;\n\t\t\t\t\t\t};\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// No new qualification: this is request metadata, not input/task authority.\n\t\t\t\t\t\t\treturn await this._appendMessage(message, undefined, undefined, { requestOutput, assertCurrent });\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t// Only this pre-append stale signal permits the ordinary unassociated append.\n\t\t\t\t\t\t\tif (error === stale) return undefined;\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\treturn sink;\n\t}\n\n\tappendToolInvocation(invocation: ToolInvocation): Promise<string> {\n\t\treturn this._appendToolInvocation(invocation);\n\t}\n\n\tprivate async _appendToolInvocation(\n\t\tinvocation: ToolInvocation,\n\t\tassistant?: ContextEpochEntryRef & { sessionFile: string | undefined },\n\t): Promise<string> {\n\t\tconst id = `${invocation.executionId}:intent`;\n\t\tif (!this.indexed && this.byId.has(id))\n\t\t\tthrow new Error(`Tool invocation already admitted: ${invocation.executionId}`);\n\t\tconst entry: ToolIntentEntry = {\n\t\t\ttype: \"tool_intent\",\n\t\t\tid,\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tinvocation: structuredClone(invocation),\n\t\t\t...(assistant ? { assistant: { ...assistant } } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, assistant ? \"native-tool-execution\" : undefined),\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\t() => {\n\t\t\t\tthrow new Error(`Tool invocation already admitted: ${invocation.executionId}`);\n\t\t\t},\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tappendToolExchange(exchange: FinalizedToolExchange): Promise<string> {\n\t\treturn this._appendToolExchangeOnce(exchange);\n\t}\n\n\tprivate _appendToolExchangeOnce(\n\t\texchange: FinalizedToolExchange,\n\t\tqualification?: \"native-recovery\" | \"native-tool-execution\",\n\t): Promise<string> {\n\t\tconst executionId = exchange.executionId;\n\t\tconst pending = this.pendingToolExchanges.get(executionId);\n\t\tif (pending) return pending;\n\t\tconst result = this._appendToolExchange(exchange, qualification).finally(() => {\n\t\t\tthis.pendingToolExchanges.delete(executionId);\n\t\t});\n\t\tthis.pendingToolExchanges.set(executionId, result);\n\t\treturn result;\n\t}\n\n\tprivate async _appendToolExchange(\n\t\texchange: FinalizedToolExchange,\n\t\tqualification?: \"native-recovery\" | \"native-tool-execution\",\n\t): Promise<string> {\n\t\tif (this.indexed) {\n\t\t\tconst state = this.writeState;\n\t\t\tconst executionId = exchange.executionId;\n\t\t\tconst { result, originalInput, executedInput, ...rest } = exchange;\n\t\t\tconst outcome = structuredClone(rest);\n\t\t\tconst entry: SessionMessageEntry = {\n\t\t\t\ttype: \"message\",\n\t\t\t\tid: executionId,\n\t\t\t\tparentId: this.leafId,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tmessage: structuredClone(result),\n\t\t\t\texecution: structuredClone({\n\t\t\t\t\t...outcome,\n\t\t\t\t\toriginalInput,\n\t\t\t\t\t...(exchange.executionOutcome === \"not_started\" ? {} : { executedInput }),\n\t\t\t\t}),\n\t\t\t};\n\t\t\tconst acknowledged = await this._appendEntry(\n\t\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\t\tfalse,\n\t\t\t\tasync (snapshot) => {\n\t\t\t\t\tconst invocationId = `${executionId}:intent`;\n\t\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\t\tif (await history.get(invocationId))\n\t\t\t\t\t\t(snapshot as SessionMessageEntry).execution = { ...outcome, invocationId };\n\t\t\t\t},\n\t\t\t\t(existing) => {\n\t\t\t\t\tif (existing.type !== \"message\" || existing.execution?.executionId !== executionId)\n\t\t\t\t\t\tthrow new Error(`Conflicting tool execution ID: ${executionId}`);\n\t\t\t\t\treturn existing;\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.finalizedToolMessages.set(result, acknowledged.id);\n\t\t\treturn acknowledged.id;\n\t\t}\n\n\t\tconst existing = this.byId.get(exchange.executionId);\n\t\tif (existing?.type === \"message\" && existing.execution?.executionId === exchange.executionId) {\n\t\t\tthis.finalizedToolMessages.set(exchange.result, existing.id);\n\t\t\treturn existing.id;\n\t\t}\n\t\tif (existing) throw new Error(`Conflicting tool execution ID: ${exchange.executionId}`);\n\t\tconst { result, originalInput, executedInput, ...outcome } = exchange;\n\t\tconst invocationId = `${exchange.executionId}:intent`;\n\t\tconst execution: SessionExecutionEvidence = this.byId.has(invocationId)\n\t\t\t? { ...outcome, invocationId }\n\t\t\t: { ...outcome, originalInput, ...(exchange.executionOutcome === \"not_started\" ? {} : { executedInput }) };\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: exchange.executionId,\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage: structuredClone(result),\n\t\t\texecution: structuredClone(execution),\n\t\t};\n\t\tconst finalized = this.finalizedToolMessages;\n\t\tawait this._appendEntry(withEntryRetention(entry, undefined, qualification));\n\t\tfinalized.set(result, entry.id);\n\t\treturn entry.id;\n\t}\n\n\tgetToolExchange(executionId: string): FinalizedToolExchange | undefined {\n\t\tthis._assertResident();\n\t\tconst entry = this.byId.get(executionId);\n\t\tif (entry?.type !== \"message\" || entry.message.role !== \"toolResult\" || !entry.execution) return undefined;\n\t\tif (\"invocationId\" in entry.execution) {\n\t\t\tconst intent = this.byId.get(entry.execution.invocationId);\n\t\t\tif (intent?.type !== \"tool_intent\") throw new Error(`Missing invocation for tool execution ${executionId}`);\n\t\t\tconst { invocationId: _invocationId, ...outcome } = entry.execution;\n\t\t\tconst { executedInput, ...invocation } = intent.invocation;\n\t\t\treturn {\n\t\t\t\t...invocation,\n\t\t\t\t...outcome,\n\t\t\t\t...(outcome.executionOutcome === \"not_started\" ? {} : { executedInput }),\n\t\t\t\tresult: entry.message,\n\t\t\t};\n\t\t}\n\t\treturn { ...entry.execution, result: entry.message };\n\t}\n\n\t/** Internal native admission. Ordinary append arguments remain descriptive JSON. */\n\t[bindNativeEntryWriter](): NativeEntryWriter {\n\t\tthis._assertMutable();\n\t\tconst state = this.writeState;\n\t\tconst assertWriter = () => {\n\t\t\tthis._assertMutable();\n\t\t\tif (this.writeState !== state || state.retired || state.closed)\n\t\t\t\tthrow new Error(\"Session source changed after native admission capture\");\n\t\t};\n\t\treturn {\n\t\t\tcaptureAgentResult: () => async (data) => {\n\t\t\t\tassertWriter();\n\t\t\t\tif (!this.isPersisted() || !this.getSessionFile() || !this.supportsCapturedHistoryReads())\n\t\t\t\t\tthrow new Error(\"Agent results require an owned persistent session source\");\n\t\t\t\tconst entry: CustomEntry<AgentResultData> = {\n\t\t\t\t\ttype: \"custom\",\n\t\t\t\t\tcustomType: AGENT_RESULT_CUSTOM_TYPE,\n\t\t\t\t\tdata,\n\t\t\t\t\tid: \"\",\n\t\t\t\t\tparentId: this.leafId,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t};\n\t\t\t\tawait this._appendEntry(\n\t\t\t\t\twithEntryRetention(entry, undefined, \"native-recovery\"),\n\t\t\t\t\tfalse,\n\t\t\t\t\t(snapshot) => {\n\t\t\t\t\t\tconst cursor = state.owner!.getSnapshot();\n\t\t\t\t\t\t// Recovery charges the entire encoded frame, including its native qualifier.\n\t\t\t\t\t\tencodeJournalFrame(\n\t\t\t\t\t\t\tsnapshot,\n\t\t\t\t\t\t\t{ sequence: cursor.nextSequence, checksum: cursor.checksum },\n\t\t\t\t\t\t\tDEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\"native-recovery\",\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\tundefined,\n\t\t\t\t\tassertWriter,\n\t\t\t\t);\n\t\t\t\treturn entry.id;\n\t\t\t},\n\t\t\tcaptureSkillSelection: () => ({\n\t\t\t\tassertCurrent: assertWriter,\n\t\t\t\tappend: (capture, producer) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\tif (producer === \"command\")\n\t\t\t\t\t\treturn this._appendCustomEntry(\n\t\t\t\t\t\t\tSELECTED_SKILL_CUSTOM_TYPE,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcontent: capture.content,\n\t\t\t\t\t\t\t\t[SELECTED_SKILL_DETAIL]: {\n\t\t\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\t\t\tproducer,\n\t\t\t\t\t\t\t\t\tdescriptor: structuredClone(capture.descriptor),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t\"native-recovery\",\n\t\t\t\t\t\t\t{ maxSourceBytes: DEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes, assertCurrent: assertWriter },\n\t\t\t\t\t\t);\n\t\t\t\t\treturn this._appendCustomMessageEntry(\n\t\t\t\t\t\tSELECTED_SKILL_CUSTOM_TYPE,\n\t\t\t\t\t\tcapture.content,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t[SELECTED_SKILL_DETAIL]: { version: 1, producer, descriptor: structuredClone(capture.descriptor) },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\"native-recovery\",\n\t\t\t\t\t\t{ maxSourceBytes: DEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes, assertCurrent: assertWriter },\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t}),\n\t\t\tcaptureToolInvocation: (assistant) => {\n\t\t\t\tconst captured = assistant ? { ...assistant } : undefined;\n\t\t\t\tif (\n\t\t\t\t\tcaptured &&\n\t\t\t\t\t(captured.sessionId !== this.getSessionId() ||\n\t\t\t\t\t\ttypeof captured.sessionFile !== \"string\" ||\n\t\t\t\t\t\tcaptured.sessionFile !== this.getSessionFile())\n\t\t\t\t)\n\t\t\t\t\tthrow new Error(\"Tool intent belongs to another assistant owner\");\n\t\t\t\treturn (invocation) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\treturn this._appendToolInvocation(invocation, captured);\n\t\t\t\t};\n\t\t\t},\n\t\t\tcaptureToolExchange: (executionId) => (exchange) => {\n\t\t\t\tassertWriter();\n\t\t\t\tif (exchange.executionId !== executionId) throw new Error(\"Tool execution identity changed\");\n\t\t\t\treturn this._appendToolExchangeOnce(exchange, \"native-tool-execution\");\n\t\t\t},\n\t\t\tcaptureRecoveryExchange: (executionId) => (exchange) => {\n\t\t\t\tassertWriter();\n\t\t\t\tif (exchange.executionId !== executionId) throw new Error(\"Recovery execution identity changed\");\n\t\t\t\treturn this._appendToolExchangeOnce(exchange, \"native-recovery\");\n\t\t\t},\n\t\t\tcaptureMessage: (origin) => {\n\t\t\t\tconst captured = JSON.parse(stringifyBoundedJson(origin, MAX_SESSION_RECORD_BYTES)) as typeof origin;\n\t\t\t\treturn async (message) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\tlet applied = captured;\n\t\t\t\t\tconst selectedSkillRef = captured.selectedSkillRef;\n\t\t\t\t\tif (selectedSkillRef) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tselectedSkillRef.sessionId !== this.getSessionId() ||\n\t\t\t\t\t\t\tselectedSkillRef.sessionFile !== this.getSessionFile()\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tthrow new Error(\"Native input skill capture belongs to another source\");\n\t\t\t\t\t\tconst source = await this.readBranchHistory((history) =>\n\t\t\t\t\t\t\thistory.hydrateEntry(selectedSkillRef.entryId, DEFAULT_NATIVE_RECOVERY_LIMITS.maxSourceBytes),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tassertWriter();\n\t\t\t\t\t\tconst skill =\n\t\t\t\t\t\t\tsource?.source.qualification === \"native-recovery\"\n\t\t\t\t\t\t\t\t? selectedSkillCapture(source.entry)\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tif (!skill) throw new Error(\"Native input selected skill source is unavailable\");\n\t\t\t\t\t\tconst texts =\n\t\t\t\t\t\t\ttypeof message.content === \"string\"\n\t\t\t\t\t\t\t\t? [message.content]\n\t\t\t\t\t\t\t\t: message.content.flatMap((part) => (part.type === \"text\" ? [part.text] : []));\n\t\t\t\t\t\t// This only drops a real producer binding after a body replacement; copied text cannot add one.\n\t\t\t\t\t\tif (!texts.some((text) => text.includes(selectedSkillBlock(skill, selectedSkillRef.entryId))))\n\t\t\t\t\t\t\tapplied = { ...captured, selectedSkillRef: undefined };\n\t\t\t\t\t}\n\t\t\t\t\t// Hooks may replace the body. Input/task admission stays on the original action/record.\n\t\t\t\t\treturn message.role === \"custom\"\n\t\t\t\t\t\t? this._appendCustomMessageEntry(\n\t\t\t\t\t\t\t\tmessage.customType,\n\t\t\t\t\t\t\t\tmessage.content,\n\t\t\t\t\t\t\t\tmessage.display,\n\t\t\t\t\t\t\t\tmessage.details,\n\t\t\t\t\t\t\t\tapplied,\n\t\t\t\t\t\t\t\t\"native-admission\",\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: this._appendMessage(message, applied, \"native-admission\");\n\t\t\t\t};\n\t\t\t},\n\t\t\tcaptureGoalOperation: (origin) => {\n\t\t\t\tconst captured = JSON.parse(stringifyBoundedJson(origin, MAX_SESSION_RECORD_BYTES)) as typeof origin;\n\t\t\t\treturn (goal) => {\n\t\t\t\t\tassertWriter();\n\t\t\t\t\treturn this._appendCustomEntry(GOAL_STATE_CUSTOM_TYPE, goal, captured, \"native-admission\");\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t}\n\n\tappendMessage(\n\t\tmessage: Message | CustomMessage | BashExecutionMessage,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t): Promise<string> {\n\t\treturn this._appendMessage(message, nativeOrigin);\n\t}\n\n\tprivate async _appendMessage(\n\t\tmessage: Message | CustomMessage | BashExecutionMessage,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t\tqualification?: NativeEntryQualification,\n\t\toutput?: { requestOutput: NativeRequestOutputAssociation; assertCurrent(): void },\n\t): Promise<string> {\n\t\tconst finalized = this.finalizedToolMessages.get(message);\n\t\tif (finalized) return finalized;\n\t\tconst entry: SessionMessageEntry = {\n\t\t\ttype: \"message\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tmessage,\n\t\t\t...(nativeOrigin ? { nativeOrigin } : {}),\n\t\t\t...(output ? { requestOutput: output.requestOutput } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\toutput?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tasync appendThinkingLevelChange(thinkingLevel: string): Promise<string> {\n\t\tconst entry: ThinkingLevelChangeEntry = {\n\t\t\ttype: \"thinking_level_change\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tthinkingLevel,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendServiceTierChange(serviceTier: ServiceTier): Promise<string> {\n\t\tconst entry: ServiceTierChangeEntry = {\n\t\t\ttype: \"service_tier_change\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tserviceTier,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendModelChange(provider: string, modelId: string): Promise<string> {\n\t\tconst entry: ModelChangeEntry = {\n\t\t\ttype: \"model_change\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number | null,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t\tcustomInstructions?: string,\n\t\tusage?: Usage,\n\t\tassertCurrent?: () => void,\n\t): Promise<string> {\n\t\treturn this._appendCompaction(\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t\tcustomInstructions,\n\t\t\tusage,\n\t\t\tassertCurrent,\n\t\t);\n\t}\n\n\tprivate async _appendCompaction<T = unknown>(\n\t\tsummary: string,\n\t\tfirstKeptEntryId: string,\n\t\ttokensBefore: number | null,\n\t\tdetails?: T,\n\t\tfromHook?: boolean,\n\t\tcustomInstructions?: string,\n\t\tusage?: Usage,\n\t\tassertCurrent?: () => void,\n\t\tqualification?: NativeEntryQualification,\n\t\trequestOutputs?: readonly NativeCompactionRequestOutputAssociation[],\n\t): Promise<string> {\n\t\tconst entry: CompactionEntry<T> = {\n\t\t\ttype: \"compaction\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tsummary,\n\t\t\tfirstKeptEntryId,\n\t\t\ttokensBefore,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t\tcustomInstructions,\n\t\t\tusage,\n\t\t\t...(requestOutputs?.length ? { requestOutputs } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tassertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tappendCustomEntry(customType: string, data?: unknown, nativeOrigin?: NativeEntryOrigin): Promise<string> {\n\t\treturn this._appendCustomEntry(customType, data, nativeOrigin);\n\t}\n\n\tprivate async _appendCustomEntry(\n\t\tcustomType: string,\n\t\tdata?: unknown,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t\tqualification?: NativeEntryQualification,\n\t\tselection?: { maxSourceBytes: number; assertCurrent: () => void },\n\t\tplannerOutput?: { request: NativeRequestOutputAssociation; assertCurrent: () => void },\n\t): Promise<string> {\n\t\tconst entry: CustomEntry = {\n\t\t\ttype: \"custom\",\n\t\t\tcustomType,\n\t\t\tdata,\n\t\t\t...(customType === \"prime-agent.refinement\" && plannerOutput ? { plannerRequest: plannerOutput.request } : {}),\n\t\t\t...(nativeOrigin ? { nativeOrigin } : {}),\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tselection\n\t\t\t\t? (snapshot) => {\n\t\t\t\t\t\tstringifyBoundedJson(snapshot, selection.maxSourceBytes);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tundefined,\n\t\t\tplannerOutput?.assertCurrent ?? selection?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tasync appendIpythonSentAgentMessage(\n\t\tdata: PersistedIpythonSentAgentMessage,\n\t): Promise<{ entryId: string; appended: boolean }> {\n\t\tthis._assertMutable();\n\t\tif (!this.indexed) throw new Error(\"Atomic IPython message append requires an indexed owned source\");\n\t\tconst captured = parsePersistedIpythonSentAgentMessage(structuredClone(data));\n\t\tif (!captured) throw new Error(\"Invalid persisted IPython sent message\");\n\t\tconst state = this.writeState;\n\t\tconst entry: CustomEntry<PersistedIpythonSentAgentMessage> = {\n\t\t\ttype: \"custom\",\n\t\t\tid: \"\",\n\t\t\tparentId: state.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcustomType: IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY,\n\t\t\tdata: captured,\n\t\t};\n\t\tlet appended = true;\n\t\tconst acknowledged = await this._appendIndexedEntry(\n\t\t\tstate,\n\t\t\tentry,\n\t\t\tfalse,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t\tasync (history) => {\n\t\t\t\tlet page = await history.ipythonSentMessages(captured.toolCallId, { messageId: captured.message.id });\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst reference = page.refs[0];\n\t\t\t\t\tif (reference) {\n\t\t\t\t\t\tconst value = await history.hydrateEntry(reference.entryId, MAX_SESSION_RECORD_BYTES);\n\t\t\t\t\t\tif (!value) throw new Error(\"IPython sent message source is unavailable\");\n\t\t\t\t\t\tappended = false;\n\t\t\t\t\t\treturn value.entry;\n\t\t\t\t\t}\n\t\t\t\t\tif (!page.nextCursor) return undefined;\n\t\t\t\t\tpage = await history.ipythonSentMessages(captured.toolCallId, {\n\t\t\t\t\t\tmessageId: captured.message.id,\n\t\t\t\t\t\tcursor: page.nextCursor,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\t\treturn { entryId: acknowledged.id, appended };\n\t}\n\n\tasync appendCustomEntryWithRollback(customType: string, data?: unknown): Promise<string> {\n\t\treturn this.appendCustomEntry(customType, data);\n\t}\n\n\tasync appendChildUsageAttribution(\n\t\ttargetId: string,\n\t\tchildUsage: Usage,\n\t\taggregateUsage?: Usage,\n\t\torigin?: ChildUsageAttributionEntry[\"origin\"],\n\t): Promise<string> {\n\t\treturn (await this.appendChildUsageAttributionWithAggregate(targetId, childUsage, aggregateUsage, origin))\n\t\t\t.entryId;\n\t}\n\n\tasync appendChildUsageAttributionWithAggregate(\n\t\ttargetId: string,\n\t\tchildUsage: Usage,\n\t\taggregateUsage?: Usage,\n\t\torigin?: ChildUsageAttributionEntry[\"origin\"],\n\t): Promise<ChildUsageAttributionAcknowledgement> {\n\t\tconst state = this.writeState;\n\t\tconst indexed = this.indexed;\n\t\tconst residentTarget = indexed ? undefined : this.byId.get(targetId);\n\t\tif (!indexed && (residentTarget?.type !== \"message\" || residentTarget.message.role !== \"assistant\"))\n\t\t\tthrow new Error(`Assistant message entry ${targetId} not found`);\n\t\tconst entry: ChildUsageAttributionEntry = {\n\t\t\ttype: \"child_usage_attributed\",\n\t\t\tid: indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tchildUsage: cloneUsage(childUsage),\n\t\t\taggregateUsage: cloneUsage(aggregateUsage ?? emptyUsage()),\n\t\t\t...(origin ? { origin } : {}),\n\t\t};\n\t\tconst acknowledged = await this._appendEntry(entry, false, async (snapshot) => {\n\t\t\tif (snapshot.type !== \"child_usage_attributed\") throw new Error(\"Expected child usage projection\");\n\t\t\tlet target = residentTarget;\n\t\t\tlet history: SessionHistoryReadScope | undefined;\n\t\t\tif (indexed) {\n\t\t\t\thistory = await this._acknowledgedHistory(state);\n\t\t\t\ttarget = (await history.hydrateEntry(targetId, MAX_SESSION_RECORD_BYTES))?.entry;\n\t\t\t}\n\t\t\tif (target?.type !== \"message\" || target.message.role !== \"assistant\")\n\t\t\t\tthrow new Error(`Assistant message entry ${targetId} not found`);\n\t\t\tif (aggregateUsage === undefined) {\n\t\t\t\tlet usage = target.message.usage;\n\t\t\t\tif (history) {\n\t\t\t\t\tconst reference = await history.sourceAssistantUsage(targetId);\n\t\t\t\t\tif (reference) {\n\t\t\t\t\t\tconst aggregate = await history.hydrateEntry(reference.id, MAX_SESSION_RECORD_BYTES);\n\t\t\t\t\t\tif (!aggregate || aggregate.entry.type !== \"child_usage_attributed\")\n\t\t\t\t\t\t\tthrow new Error(\"Stored assistant aggregate source is unavailable\");\n\t\t\t\t\t\tusage = cloneUsage(aggregate.entry.aggregateUsage);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst total = cloneUsage(usage);\n\t\t\t\tconst contextTokens = total.totalTokens || total.input + total.output + total.cacheRead + total.cacheWrite;\n\t\t\t\taddAssistantUsage(total, snapshot.childUsage);\n\t\t\t\ttotal.totalTokens = contextTokens;\n\t\t\t\tsnapshot.aggregateUsage = total;\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tentryId: acknowledged.id,\n\t\t\taggregateUsage: cloneUsage((acknowledged as ChildUsageAttributionEntry).aggregateUsage),\n\t\t};\n\t}\n\n\tasync appendSessionInfo(name: string): Promise<string> {\n\t\tconst entry: SessionInfoEntry = {\n\t\t\ttype: \"session_info\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tname: name.trim(),\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendSessionState(state: SessionState): Promise<string> {\n\t\tconst entry: SessionStateEntry = {\n\t\t\ttype: \"session_state\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tstate: { status: state.status },\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tgetSessionName(): string | undefined {\n\t\treturn this.writeState.sessionName?.trim() || undefined;\n\t}\n\n\tgetSessionState(): SessionState | undefined {\n\t\tif (this.indexed) {\n\t\t\tconst state = this.writeState.sessionState;\n\t\t\treturn state ? { ...state } : undefined;\n\t\t}\n\t\tconst entries = this.getEntries();\n\t\tfor (let i = entries.length - 1; i >= 0; i--) {\n\t\t\tconst entry = entries[i];\n\t\t\tif (entry.type === \"session_state\") {\n\t\t\t\tconst status = normalizeSessionStateStatus(entry.state.status);\n\t\t\t\tif (status) {\n\t\t\t\t\treturn { status };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * True when the session holds user-meaningful persisted content, as opposed to\n\t * only daemon-written bookkeeping (session_state, agent_status, git_state) or\n\t * the default model/thinking entries every new session is created with. Used by\n\t * the daemon discard guard to decide whether a message-less draft is safe to\n\t * delete (that guard always also requires zero messages).\n\t *\n\t * createAgentSession opens a new session with an optional leading `model_change`\n\t * followed by `thinking_level_change` and `service_tier_change`. That creation\n\t * prefix is skipped; anything beyond it is user content.\n\t */\n\thasUserContent(): boolean {\n\t\tif (this.indexed) {\n\t\t\tif (this.writeState.hasUserContent === undefined) throw new Error(\"Owned session metadata is unavailable\");\n\t\t\treturn this.writeState.hasUserContent;\n\t\t}\n\t\tconst contentEntries = this.getEntries().filter((entry) => CONTENT_ENTRY_TYPES.has(entry.type));\n\t\tlet start = 0;\n\t\tif (contentEntries[start]?.type === \"model_change\") {\n\t\t\tstart++;\n\t\t}\n\t\tif (contentEntries[start]?.type === \"thinking_level_change\") {\n\t\t\tstart++;\n\t\t}\n\t\tif (contentEntries[start]?.type === \"service_tier_change\") {\n\t\t\tstart++;\n\t\t}\n\t\treturn contentEntries.length > start;\n\t}\n\n\tasync appendAgentStatus(status: AgentStatus): Promise<string> {\n\t\tconst entry: AgentStatusEntry = {\n\t\t\ttype: \"agent_status\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tstatus: {\n\t\t\t\tsummary: status.summary,\n\t\t\t\ttaskState: status.taskState,\n\t\t\t\tbasedOnMessageCount: status.basedOnMessageCount,\n\t\t\t},\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync appendGitState(git: GitContext): Promise<string> {\n\t\tconst entry: GitStateEntry = {\n\t\t\ttype: \"git_state\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tgit,\n\t\t};\n\t\tawait this._appendEntry(entry);\n\t\treturn entry.id;\n\t}\n\n\tasync recordGitStateIfChanged(): Promise<string | undefined> {\n\t\tif (!this.persist) return undefined;\n\t\tconst git = captureGitContext(this.cwd);\n\t\tif (!git) return undefined;\n\t\tconst last = this.getActiveGitContext();\n\t\tif (last && gitContextsEqual(last, git)) return undefined;\n\t\treturn this.appendGitState(git);\n\t}\n\n\tprivate getActiveGitContext(): GitContext | undefined {\n\t\tif (this.indexed) return this.writeState.git;\n\t\tlet current = this.leafId ? this.byId.get(this.leafId) : undefined;\n\t\twhile (current) {\n\t\t\tif (current.type === \"git_state\") return current.git;\n\t\t\tcurrent = current.parentId ? this.byId.get(current.parentId) : undefined;\n\t\t}\n\t\tconst header = this.fileEntries[0];\n\t\treturn header?.type === \"session\" ? header.git : undefined;\n\t}\n\n\tgetLatestAgentStatus(): AgentStatus | undefined {\n\t\tif (this.indexed) return this.writeState.agentStatus ? { ...this.writeState.agentStatus } : undefined;\n\t\t// Walk the current leaf to root so we only read status on the active branch,\n\t\t// not a sibling branch's status that happens to sit later in the file.\n\t\tlet current = this.leafId ? this.byId.get(this.leafId) : undefined;\n\t\twhile (current) {\n\t\t\tif (current.type === \"agent_status\") {\n\t\t\t\treturn { ...current.status };\n\t\t\t}\n\t\t\tcurrent = current.parentId ? this.byId.get(current.parentId) : undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tappendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t): Promise<string> {\n\t\treturn this._appendCustomMessageEntry(customType, content, display, details, nativeOrigin);\n\t}\n\n\tprivate async _appendCustomMessageEntry<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t\tnativeOrigin?: NativeEntryOrigin,\n\t\tqualification?: NativeEntryQualification,\n\t\tselection?: { maxSourceBytes: number; assertCurrent: () => void },\n\t): Promise<string> {\n\t\tconst entry: CustomMessageEntry<T> = {\n\t\t\ttype: \"custom_message\",\n\t\t\tcustomType,\n\t\t\tcontent,\n\t\t\tdisplay,\n\t\t\tdetails,\n\t\t\t...(nativeOrigin ? { nativeOrigin } : {}),\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\twithEntryRetention(entry, undefined, qualification),\n\t\t\tfalse,\n\t\t\tselection\n\t\t\t\t? (snapshot) => {\n\t\t\t\t\t\tstringifyBoundedJson(snapshot, selection.maxSourceBytes);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tundefined,\n\t\t\tselection?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\t/**\n\t * Append a custom message, undoing the append if persistence fails so a\n\t * best-effort record never leaves an unsaved leaf for later entries.\n\t */\n\tasync appendCustomMessageEntryWithRollback<T = unknown>(\n\t\tcustomType: string,\n\t\tcontent: string | (TextContent | ImageContent)[],\n\t\tdisplay: boolean,\n\t\tdetails?: T,\n\t): Promise<string> {\n\t\treturn this.appendCustomMessageEntry(customType, content, display, details);\n\t}\n\n\tasync readEntry(\n\t\tid: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<SessionEntry | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) {\n\t\t\tconst entry = this.getEntry(id);\n\t\t\treturn entry\n\t\t\t\t? withEntryRetention(\n\t\t\t\t\t\tJSON.parse(stringifyBoundedJson(entry, maxSourceBytes)) as SessionEntry,\n\t\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst value = await this._storedEntry(history, id, maxSourceBytes);\n\t\t\treturn value ? withEntryRetention(value.entry, value.source.retention, value.source.qualification) : undefined;\n\t\t});\n\t}\n\n\tasync readLeafEntry(\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<SessionEntry | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) return this.leafId ? this.readEntry(this.leafId, maxSourceBytes) : undefined;\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tif (history.source.leafId === null) return undefined;\n\t\t\tconst value = await this._storedEntry(history, history.source.leafId, maxSourceBytes);\n\t\t\treturn value ? withEntryRetention(value.entry, value.source.retention, value.source.qualification) : undefined;\n\t\t});\n\t}\n\n\tasync readEntryRetention(id: string): Promise<JournalFrameRetention | undefined> {\n\t\tif (!this.indexed) return this.getEntryRetention(id);\n\t\treturn this.readSourceHistory(async (history) => (await history.get(id))?.retention);\n\t}\n\n\tasync readLabel(\n\t\tid: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<string | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) {\n\t\t\tconst label = this.getLabel(id);\n\t\t\treturn label === undefined ? undefined : (JSON.parse(stringifyBoundedJson(label, maxSourceBytes)) as string);\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst reference = await history.sourceLabel(id);\n\t\t\tif (!reference) return undefined;\n\t\t\tconst value = await history.hydrateEntry(reference.id, maxSourceBytes);\n\t\t\tif (!value || value.entry.type !== \"label\") throw new Error(\"Label source is unavailable\");\n\t\t\treturn value.entry.label || undefined;\n\t\t});\n\t}\n\n\tasync readEntries(limits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS): Promise<SessionEntry[]> {\n\t\tconst capturedLimits = { ...limits };\n\t\tif (!this.indexed) {\n\t\t\tconst resident = this.materializeResidentHistory(capturedLimits);\n\t\t\treturn resident.entries.map((entry, index) =>\n\t\t\t\twithEntryRetention(\n\t\t\t\t\tentry,\n\t\t\t\t\tresident.retentions[index] ?? undefined,\n\t\t\t\t\tresident.qualifications[index] ?? undefined,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst result = await history.materialize(capturedLimits);\n\t\t\tconst entries = result.entries.map(({ entry, source }) =>\n\t\t\t\twithEntryRetention(entry, source.retention, source.qualification),\n\t\t\t);\n\t\t\tapplyChildUsageAttributions(entries);\n\t\t\treturn entries;\n\t\t});\n\t}\n\n\tprivate async _readBranchesAt(\n\t\thistory: SessionHistoryReadScope,\n\t\tleafIds: readonly (string | null)[],\n\t\tlimits: SessionHistoryReadLimits,\n\t): Promise<{ source: SourceSnapshotRef; branches: SessionEntry[][]; sourceBytes: number }> {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tconst loaded = new Map<string, SessionEntry>();\n\t\tlet sourceBytes = 0;\n\t\tconst load = async (reference: IndexedSourceEvent) => {\n\t\t\tconst existing = loaded.get(reference.id);\n\t\t\tif (existing) return existing;\n\t\t\tif (loaded.size >= maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\tconst remaining = maxSourceBytes - sourceBytes;\n\t\t\tsourceBytes += reference.locator.length;\n\t\t\tif (sourceBytes > maxSourceBytes) throw new Error(\"Parent-path source byte budget exceeded\");\n\t\t\tconst value = await history.hydrateEntry(reference.id, remaining);\n\t\t\tif (!value) throw new Error(\"Parent-path entry source is unavailable\");\n\t\t\tconst entry = withEntryRetention(value.entry, value.source.retention, value.source.qualification);\n\t\t\tloaded.set(entry.id, entry);\n\t\t\treturn entry;\n\t\t};\n\t\tconst branches: SessionEntry[][] = [];\n\t\tfor (const leafId of leafIds) {\n\t\t\tconst branch: SessionEntry[] = [];\n\t\t\tlet page = await history.parentPathFrom(leafId);\n\t\t\tfor (;;) {\n\t\t\t\tif (page.totalEntries > maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\t\tfor (const reference of page.events) branch.push(await load(reference));\n\t\t\t\tif (!page.nextCursor) break;\n\t\t\t\tpage = await history.parentPathFrom(leafId, { cursor: page.nextCursor });\n\t\t\t}\n\t\t\tbranches.push(branch);\n\t\t}\n\t\tfor (const entry of loaded.values()) {\n\t\t\tif (entry.type !== \"message\" || entry.message.role !== \"assistant\") continue;\n\t\t\tconst reference = await history.sourceAssistantUsage(entry.id);\n\t\t\tif (!reference) continue;\n\t\t\tconst aggregate = await load(reference);\n\t\t\tif (aggregate.type !== \"child_usage_attributed\")\n\t\t\t\tthrow new Error(\"Stored assistant aggregate source is unavailable\");\n\t\t\tentry.message.usage = cloneUsage(aggregate.aggregateUsage);\n\t\t}\n\t\treturn { source: history.source, branches, sourceBytes };\n\t}\n\n\tprivate _residentParentPath(id: string | null, byId = this.byId): SessionEntry[] {\n\t\tconst entries: SessionEntry[] = [];\n\t\tconst seen = new Set<string>();\n\t\tlet current = id;\n\t\twhile (current !== null) {\n\t\t\tif (seen.has(current)) throw new Error(\"Parent path lineage is unresolved\");\n\t\t\tseen.add(current);\n\t\t\tconst entry = byId.get(current);\n\t\t\tif (!entry) throw new Error(\"Parent path lineage is unresolved\");\n\t\t\tentries.push(entry);\n\t\t\tcurrent = entry.parentId;\n\t\t}\n\t\treturn entries.reverse();\n\t}\n\n\tasync readBranches(\n\t\tleafIds: readonly (string | null)[],\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<{ source?: SourceSnapshotRef; branches: SessionEntry[][]; sourceBytes: number }> {\n\t\tconst ids = [...leafIds];\n\t\tconst capturedLimits = { ...limits };\n\t\tif (this.indexed) return this.readSourceHistory((history) => this._readBranchesAt(history, ids, capturedLimits));\n\t\treturn this._readResidentBranches(ids, capturedLimits, this.byId);\n\t}\n\n\tprivate _readResidentBranches(\n\t\tids: readonly (string | null)[],\n\t\tlimits: SessionHistoryReadLimits,\n\t\tbyId: Map<string, SessionEntry>,\n\t): { branches: SessionEntry[][]; sourceBytes: number } {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid parent-path materialization limits\");\n\t\tconst cloned = new Map<string, SessionEntry>();\n\t\tlet sourceBytes = 0;\n\t\tconst branches = ids.map((id) =>\n\t\t\tthis._residentParentPath(id, byId).map((entry) => {\n\t\t\t\tconst existing = cloned.get(entry.id);\n\t\t\t\tif (existing) return existing;\n\t\t\t\tif (cloned.size >= maxEntries) throw new Error(\"Parent-path entry budget exceeded\");\n\t\t\t\tconst json = stringifyBoundedJson(entry, maxSourceBytes - sourceBytes);\n\t\t\t\tsourceBytes += Buffer.byteLength(json);\n\t\t\t\tconst copy = withEntryRetention(\n\t\t\t\t\tJSON.parse(json) as SessionEntry,\n\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t);\n\t\t\t\tcloned.set(copy.id, copy);\n\t\t\t\treturn copy;\n\t\t\t}),\n\t\t);\n\t\treturn { branches, sourceBytes };\n\t}\n\n\tasync readBranch(\n\t\tfromId?: string | null,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionEntry[]> {\n\t\tconst capturedLimits = { ...limits };\n\t\tif (!this.indexed)\n\t\t\treturn (await this.readBranches([fromId === undefined ? this.leafId : fromId], capturedLimits)).branches[0];\n\t\treturn this.readSourceHistory(\n\t\t\tasync (history) =>\n\t\t\t\t(\n\t\t\t\t\tawait this._readBranchesAt(\n\t\t\t\t\t\thistory,\n\t\t\t\t\t\t[fromId === undefined ? history.source.leafId : fromId],\n\t\t\t\t\t\tcapturedLimits,\n\t\t\t\t\t)\n\t\t\t\t).branches[0],\n\t\t);\n\t}\n\n\tasync branchTo(id: string | null): Promise<void> {\n\t\tthis._assertMutable();\n\t\tif (!this.indexed) {\n\t\t\tif (id === null) this.resetLeaf();\n\t\t\telse this.branch(id);\n\t\t\treturn;\n\t\t}\n\t\tconst state = this.writeState;\n\t\tif (state.pending > 0) throw new Error(\"Drain session writes before changing the branch\");\n\t\tawait this._enqueue(state, 0, async () => {\n\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\tif (id !== null && !(await history.get(id))) throw new Error(`Entry ${id} not found`);\n\t\t\tconst previous = state.leafId;\n\t\t\tstate.leafId = id;\n\t\t\ttry {\n\t\t\t\tawait this._refreshOwnedMetadata(state);\n\t\t\t\tif (id !== previous) state.branchSelectionRevision++;\n\t\t\t} catch (error) {\n\t\t\t\tstate.leafId = previous;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t});\n\t}\n\n\tgetLeafId(): string | null {\n\t\treturn this.leafId;\n\t}\n\n\tgetLeafEntry(): SessionEntry | undefined {\n\t\tthis._assertResident();\n\t\treturn this.leafId ? this.byId.get(this.leafId) : undefined;\n\t}\n\n\tgetEntry(id: string): SessionEntry | undefined {\n\t\tthis._assertResident();\n\t\treturn this.byId.get(id);\n\t}\n\n\tgetChildren(parentId: string): SessionEntry[] {\n\t\tthis._assertResident();\n\t\tconst children: SessionEntry[] = [];\n\t\tfor (const entry of this.byId.values()) {\n\t\t\tif (entry.parentId === parentId) {\n\t\t\t\tchildren.push(entry);\n\t\t\t}\n\t\t}\n\t\treturn children;\n\t}\n\n\tgetLabel(id: string): string | undefined {\n\t\tthis._assertResident();\n\t\treturn this.labelsById.get(id);\n\t}\n\n\tasync appendLabelChange(targetId: string, label: string | undefined): Promise<string> {\n\t\tconst state = this.writeState;\n\t\tif (!this.indexed && !this.byId.has(targetId)) {\n\t\t\tthrow new Error(`Entry ${targetId} not found`);\n\t\t}\n\t\tconst entry: LabelEntry = {\n\t\t\ttype: \"label\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId,\n\t\t\tlabel,\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\tentry,\n\t\t\tfalse,\n\t\t\tthis.indexed\n\t\t\t\t? async () => {\n\t\t\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\t\t\tif (!(await history.get(targetId))) throw new Error(`Entry ${targetId} not found`);\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t);\n\n\t\treturn entry.id;\n\t}\n\n\tgetBranch(fromId?: string): SessionEntry[] {\n\t\tthis._assertResident();\n\t\t// push+reverse, not unshift-per-entry: unshift is O(n), which makes this O(n^2) on long sessions.\n\t\tconst path: SessionEntry[] = [];\n\t\tconst startId = fromId ?? this.leafId;\n\t\tlet current = startId ? this.byId.get(startId) : undefined;\n\t\twhile (current) {\n\t\t\tpath.push(current);\n\t\t\tcurrent = current.parentId ? this.byId.get(current.parentId) : undefined;\n\t\t}\n\t\tpath.reverse();\n\t\treturn path;\n\t}\n\n\tbuildSessionContext(): SessionContext {\n\t\tthis._assertResident();\n\t\t// Pass fileEntries directly rather than getEntries(): the resolved context\n\t\t// is computed from the leaf-to-root walk over byId (which already excludes\n\t\t// the header), so the entries argument is only a fallback for an undefined\n\t\t// leaf — never hit here since leafId is always set or null. Avoids an O(n)\n\t\t// array copy on every call (attach, get_session_context, agent init, ...).\n\t\treturn buildSessionContext(this.fileEntries as SessionEntry[], this.leafId, this.byId);\n\t}\n\n\tgetHeader(): SessionHeader | null {\n\t\tif (this.indexed) return this.header;\n\t\tconst header = this.fileEntries.find((entry) => entry.type === \"session\");\n\t\treturn header ? (header as SessionHeader) : null;\n\t}\n\n\t/** A lowering-only source qualification; absence does not establish native authorship. */\n\tgetEntryRetention(entryId: string): JournalFrameRetention | undefined {\n\t\tthis._assertResident();\n\t\tconst entry = this.byId.get(entryId);\n\t\treturn entry ? entryRetentions.get(entry) : undefined;\n\t}\n\n\t/** Whole-source count published with acknowledged entries, independent of the current branch. */\n\tgetCompactionCount(): number {\n\t\treturn this.writeState.compactionCount;\n\t}\n\n\t/** Complete detached snapshot of this resident view, including readonly and in-memory views. */\n\tmaterializeResidentHistory(limits: SessionHistoryReadLimits): ResidentSessionHistory {\n\t\tthis._assertResident();\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid resident history materialization limits\");\n\t\tconst leafId = this.leafId;\n\t\tlet sourceBytes = 0;\n\t\tconst clone = <T extends FileEntry>(entry: T): T => {\n\t\t\tconst json = stringifyBoundedJson(entry, maxSourceBytes - sourceBytes);\n\t\t\tsourceBytes += Buffer.byteLength(json);\n\t\t\treturn JSON.parse(json) as T;\n\t\t};\n\t\tconst originalHeader = this.getHeader();\n\t\tconst header = originalHeader ? clone(originalHeader) : null;\n\t\tconst entries: SessionEntry[] = [];\n\t\tconst retentions: (JournalFrameRetention | null)[] = [];\n\t\tconst qualifications: (NativeEntryQualification | null)[] = [];\n\t\tfor (const entry of this.fileEntries) {\n\t\t\tif (entry.type === \"session\") continue;\n\t\t\tif (entries.length >= maxEntries) throw new Error(\"Resident history entry budget exceeded\");\n\t\t\tentries.push(clone(entry));\n\t\t\tretentions.push(entryRetentions.get(entry) ?? null);\n\t\t\tqualifications.push(entryQualifications.get(entry) ?? null);\n\t\t}\n\t\treturn { header, entries, retentions, qualifications, leafId, sourceBytes };\n\t}\n\n\tgetEntries(): SessionEntry[] {\n\t\tthis._assertResident();\n\t\treturn this.fileEntries.filter((e): e is SessionEntry => e.type !== \"session\");\n\t}\n\n\tasync readFlatTree(\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionTreeFlatNode[]> {\n\t\tconst entries = await this.readEntries({ ...limits });\n\t\tconst byId = new Map(entries.map((entry) => [entry.id, entry]));\n\t\tconst labels = new Map<string, { value: string; timestamp: string }>();\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.type !== \"label\") continue;\n\t\t\tif (entry.label) labels.set(entry.targetId, { value: entry.label, timestamp: entry.timestamp });\n\t\t\telse labels.delete(entry.targetId);\n\t\t}\n\t\treturn entries\n\t\t\t.filter(\n\t\t\t\t(entry): entry is Exclude<SessionEntry, PrivateSessionEntry> =>\n\t\t\t\t\tentry.type !== \"tool_intent\" && entry.type !== \"request\",\n\t\t\t)\n\t\t\t.map((entry) => {\n\t\t\t\tlet parentId = entry.parentId;\n\t\t\t\tlet parent = parentId ? byId.get(parentId) : undefined;\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\twhile (parent?.type === \"tool_intent\" || parent?.type === \"request\") {\n\t\t\t\t\tif (seen.has(parent.id)) throw new Error(\"Session tree private ancestry is unresolved\");\n\t\t\t\t\tseen.add(parent.id);\n\t\t\t\t\tparentId = parent.parentId;\n\t\t\t\t\tparent = parentId ? byId.get(parentId) : undefined;\n\t\t\t\t}\n\t\t\t\tconst label = labels.get(entry.id);\n\t\t\t\treturn {\n\t\t\t\t\tentry:\n\t\t\t\t\t\tparentId === entry.parentId\n\t\t\t\t\t\t\t? entry\n\t\t\t\t\t\t\t: withEntryRetention(\n\t\t\t\t\t\t\t\t\t{ ...entry, parentId },\n\t\t\t\t\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\tlabel: label?.value,\n\t\t\t\t\tlabelTimestamp: label?.timestamp,\n\t\t\t\t};\n\t\t\t});\n\t}\n\n\tasync readTree(limits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS): Promise<SessionTreeNode[]> {\n\t\tconst entries = await this.readFlatTree({ ...limits });\n\t\tconst nodes = new Map<string, SessionTreeNode>();\n\t\tconst roots: SessionTreeNode[] = [];\n\t\tfor (const entry of entries) nodes.set(entry.entry.id, { ...entry, children: [] });\n\t\tfor (const flat of entries) {\n\t\t\tconst node = nodes.get(flat.entry.id)!;\n\t\t\tconst parent =\n\t\t\t\tflat.entry.parentId === null || flat.entry.parentId === flat.entry.id\n\t\t\t\t\t? undefined\n\t\t\t\t\t: nodes.get(flat.entry.parentId);\n\t\t\tif (parent) parent.children.push(node);\n\t\t\telse roots.push(node);\n\t\t}\n\t\tconst stack = [...roots];\n\t\twhile (stack.length) {\n\t\t\tconst node = stack.pop()!;\n\t\t\tnode.children.sort(\n\t\t\t\t(left, right) => new Date(left.entry.timestamp).getTime() - new Date(right.entry.timestamp).getTime(),\n\t\t\t);\n\t\t\tstack.push(...node.children);\n\t\t}\n\t\treturn roots;\n\t}\n\n\tasync readToolExchange(\n\t\texecutionId: string,\n\t\tmaxSourceBytes = DEFAULT_MANAGER_HISTORY_LIMITS.maxSourceBytes,\n\t): Promise<FinalizedToolExchange | undefined> {\n\t\tif (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)\n\t\t\tthrow new Error(\"Invalid history entry source byte budget\");\n\t\tif (!this.indexed) {\n\t\t\tconst exchange = this.getToolExchange(executionId);\n\t\t\treturn exchange\n\t\t\t\t? (JSON.parse(stringifyBoundedJson(exchange, maxSourceBytes)) as FinalizedToolExchange)\n\t\t\t\t: undefined;\n\t\t}\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst value = await history.hydrateEntry(executionId, maxSourceBytes);\n\t\t\tconst entry = value?.entry;\n\t\t\tif (entry?.type !== \"message\" || entry.message.role !== \"toolResult\" || !entry.execution) return undefined;\n\t\t\tif (!(\"invocationId\" in entry.execution)) return { ...entry.execution, result: entry.message };\n\t\t\tconst intentValue = await history.hydrateEntry(\n\t\t\t\tentry.execution.invocationId,\n\t\t\t\tmaxSourceBytes - value!.source.locator.length,\n\t\t\t);\n\t\t\tif (intentValue?.entry.type !== \"tool_intent\")\n\t\t\t\tthrow new Error(`Missing invocation for tool execution ${executionId}`);\n\t\t\tconst { invocationId: _invocationId, ...outcome } = entry.execution;\n\t\t\tconst { executedInput, ...invocation } = intentValue.entry.invocation;\n\t\t\treturn {\n\t\t\t\t...invocation,\n\t\t\t\t...outcome,\n\t\t\t\t...(outcome.executionOutcome === \"not_started\" ? {} : { executedInput }),\n\t\t\t\tresult: entry.message,\n\t\t\t};\n\t\t});\n\t}\n\n\tgetFlatTree(): SessionTreeFlatNode[] {\n\t\tthis._assertResident();\n\t\treturn this.getEntries()\n\t\t\t.filter(\n\t\t\t\t(entry): entry is Exclude<SessionEntry, PrivateSessionEntry> =>\n\t\t\t\t\tentry.type !== \"tool_intent\" && entry.type !== \"request\",\n\t\t\t)\n\t\t\t.map((entry) => {\n\t\t\t\t// Internal intent records remain in source history, not the conversation tree.\n\t\t\t\tlet parentId = entry.parentId;\n\t\t\t\tlet parent = parentId ? this.byId.get(parentId) : undefined;\n\t\t\t\twhile (parent?.type === \"tool_intent\" || parent?.type === \"request\") {\n\t\t\t\t\tparentId = parent.parentId;\n\t\t\t\t\tparent = parentId ? this.byId.get(parentId) : undefined;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tentry: parentId === entry.parentId ? entry : { ...entry, parentId },\n\t\t\t\t\tlabel: this.labelsById.get(entry.id),\n\t\t\t\t\tlabelTimestamp: this.labelTimestampsById.get(entry.id),\n\t\t\t\t};\n\t\t\t});\n\t}\n\n\tgetTree(): SessionTreeNode[] {\n\t\tconst entries = this.getFlatTree();\n\t\tconst nodeMap = new Map<string, SessionTreeNode>();\n\t\tconst roots: SessionTreeNode[] = [];\n\n\t\tfor (const flatNode of entries) {\n\t\t\tnodeMap.set(flatNode.entry.id, { ...flatNode, children: [] });\n\t\t}\n\n\t\tfor (const flatNode of entries) {\n\t\t\tconst entry = flatNode.entry;\n\t\t\tconst node = nodeMap.get(entry.id)!;\n\t\t\tif (entry.parentId === null || entry.parentId === entry.id) {\n\t\t\t\troots.push(node);\n\t\t\t} else {\n\t\t\t\tconst parent = nodeMap.get(entry.parentId);\n\t\t\t\tif (parent) {\n\t\t\t\t\tparent.children.push(node);\n\t\t\t\t} else {\n\t\t\t\t\troots.push(node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sort children by timestamp (oldest first, newest at bottom)\n\t\t// Use iterative approach to avoid stack overflow on deep trees\n\t\tconst stack: SessionTreeNode[] = [...roots];\n\t\twhile (stack.length > 0) {\n\t\t\tconst node = stack.pop()!;\n\t\t\tnode.children.sort((a, b) => new Date(a.entry.timestamp).getTime() - new Date(b.entry.timestamp).getTime());\n\t\t\tstack.push(...node.children);\n\t\t}\n\n\t\treturn roots;\n\t}\n\n\tbranch(branchFromId: string): void {\n\t\tthis._assertResident();\n\t\tif (!this.byId.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tif (this.writeState.pending > 0) throw new Error(\"Drain session writes before changing the branch\");\n\t\tif (this.writeState.leafId !== branchFromId) this.writeState.branchSelectionRevision++;\n\t\tthis.leafId = branchFromId;\n\t\tthis.writeState.leafId = branchFromId;\n\t\tthis.writeState.reservedLeaf = branchFromId;\n\t}\n\n\tresetLeaf(): void {\n\t\tthis._assertResident();\n\t\tif (this.writeState.pending > 0) throw new Error(\"Drain session writes before changing the branch\");\n\t\tif (this.writeState.leafId !== null) this.writeState.branchSelectionRevision++;\n\t\tthis.leafId = null;\n\t\tthis.writeState.leafId = null;\n\t\tthis.writeState.reservedLeaf = null;\n\t}\n\n\tbranchWithSummary(\n\t\tbranchFromId: string | null,\n\t\tsummary: string,\n\t\tdetails?: unknown,\n\t\tfromHook?: boolean,\n\t\tusage?: Usage,\n\t): Promise<string> {\n\t\treturn this._branchWithSummary(branchFromId, summary, details, fromHook, usage);\n\t}\n\n\tprivate async _branchWithSummary(\n\t\tbranchFromId: string | null,\n\t\tsummary: string,\n\t\tdetails?: unknown,\n\t\tfromHook?: boolean,\n\t\tusage?: Usage,\n\t\toutput?: { requestOutput: NativeRequestOutputAssociation; assertCurrent(): void },\n\t): Promise<string> {\n\t\tconst state = this.writeState;\n\t\tif (!this.indexed && branchFromId !== null && !this.byId.has(branchFromId)) {\n\t\t\tthrow new Error(`Entry ${branchFromId} not found`);\n\t\t}\n\t\tconst entry: BranchSummaryEntry = {\n\t\t\ttype: \"branch_summary\",\n\t\t\tid: this.indexed ? \"\" : generateId(this.byId),\n\t\t\tparentId: branchFromId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tfromId: branchFromId ?? \"root\",\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\tfromHook,\n\t\t\tusage,\n\t\t\t...(output ? { requestOutput: output.requestOutput } : {}),\n\t\t};\n\t\tawait this._appendEntry(\n\t\t\tentry,\n\t\t\ttrue,\n\t\t\tthis.indexed\n\t\t\t\t? async () => {\n\t\t\t\t\t\tconst history = await this._acknowledgedHistory(state);\n\t\t\t\t\t\tif (branchFromId !== null) {\n\t\t\t\t\t\t\tif (!(await history.get(branchFromId))) throw new Error(`Entry ${branchFromId} not found`);\n\t\t\t\t\t\t\tawait history.parentPathFrom(branchFromId, { limit: 1 });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tundefined,\n\t\t\toutput?.assertCurrent,\n\t\t);\n\t\treturn entry.id;\n\t}\n\n\tprivate async _captureForkInput(\n\t\ttarget: { leafId: string | null } | { entryId: string; position: \"before\" | \"at\" },\n\t\toptions: { persist?: boolean; sessionDir?: string; rlmDepth?: number; limits?: SessionHistoryReadLimits },\n\t): Promise<CapturedForkInput> {\n\t\tconst limits = { ...(options.limits ?? DEFAULT_MANAGER_HISTORY_LIMITS) };\n\t\tif (\n\t\t\t!Number.isSafeInteger(limits.maxEntries) ||\n\t\t\tlimits.maxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(limits.maxSourceBytes) ||\n\t\t\tlimits.maxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid fork source limits\");\n\t\tconst sourceFile = this.sessionFile;\n\t\tconst header = JSON.parse(stringifyBoundedJson(this.getHeader(), limits.maxSourceBytes)) as SessionHeader | null;\n\t\tconst settings = {\n\t\t\tsourceFile,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionDir: options.sessionDir ?? this.sessionDir,\n\t\t\tpersist: options.persist ?? this.persist,\n\t\t\trlmDepth: options.rlmDepth ?? resolveSessionRlmDepth(header ?? {}, sourceFile ?? \"\"),\n\t\t\tlimits,\n\t\t};\n\t\tconst finish = async (\n\t\t\tentries: SessionEntry[],\n\t\t\thistory?: SessionHistoryReadScope,\n\t\t\tepochCopy?: CapturedEpochCopy,\n\t\t): Promise<CapturedForkInput> => {\n\t\t\tconst byId = new Map<string, SessionEntry>();\n\t\t\tfor (const entry of entries) if (!byId.has(entry.id)) byId.set(entry.id, entry);\n\t\t\tconst selectedEntry = \"entryId\" in target ? byId.get(target.entryId) : undefined;\n\t\t\tlet leafId: string | null;\n\t\t\tif (\"entryId\" in target) {\n\t\t\t\tif (!selectedEntry) throw new Error(\"Invalid entry ID for forking\");\n\t\t\t\tif (\n\t\t\t\t\ttarget.position === \"before\" &&\n\t\t\t\t\t(selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\")\n\t\t\t\t)\n\t\t\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t\t\tleafId = target.position === \"at\" ? selectedEntry.id : selectedEntry.parentId;\n\t\t\t} else leafId = target.leafId;\n\t\t\tconst path: SessionEntry[] = [];\n\t\t\tif (history) {\n\t\t\t\tlet page = await history.parentPathFrom(leafId);\n\t\t\t\tfor (;;) {\n\t\t\t\t\tfor (const reference of page.events) {\n\t\t\t\t\t\tconst entry = byId.get(reference.id);\n\t\t\t\t\t\tif (!entry) throw new Error(\"Fork path source is unavailable\");\n\t\t\t\t\t\tpath.push(entry);\n\t\t\t\t\t}\n\t\t\t\t\tif (!page.nextCursor) break;\n\t\t\t\t\tpage = await history.parentPathFrom(leafId, { cursor: page.nextCursor });\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tlet id = leafId;\n\t\t\t\twhile (id !== null) {\n\t\t\t\t\tconst entry = byId.get(id);\n\t\t\t\t\tif (!entry || seen.has(id)) throw new Error(\"Parent path lineage is unresolved\");\n\t\t\t\t\tseen.add(id);\n\t\t\t\t\tpath.push(entry);\n\t\t\t\t\tid = entry.parentId;\n\t\t\t\t}\n\t\t\t\tpath.reverse();\n\t\t\t}\n\t\t\tlet copied: SessionEntry[] = path.filter((entry) => entry.type !== \"label\");\n\t\t\tconst ids = new Set(copied.map((entry) => entry.id));\n\t\t\tif (epochCopy) {\n\t\t\t\t// Preserve source-backed display updates and original invocation relations, not baked replacement bodies.\n\t\t\t\tconst toolCalls = new Set(\n\t\t\t\t\tcopied.flatMap((entry) =>\n\t\t\t\t\t\tentry.type === \"message\" && entry.message.role === \"toolResult\" ? [entry.message.toolCallId] : [],\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tfor (const entry of copied) {\n\t\t\t\t\tif (entry.type === \"message\" && entry.execution && \"invocationId\" in entry.execution)\n\t\t\t\t\t\tids.add(entry.execution.invocationId);\n\t\t\t\t}\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tif (entry.type === \"child_usage_attributed\" && ids.has(entry.targetId)) ids.add(entry.id);\n\t\t\t\t\tif (entry.type === \"custom\" && entry.customType === IPYTHON_SENT_AGENT_MESSAGE_CUSTOM_ENTRY) {\n\t\t\t\t\t\tconst sent = parsePersistedIpythonSentAgentMessage(entry.data);\n\t\t\t\t\t\tif (sent && toolCalls.has(sent.toolCallId)) ids.add(entry.id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Related records keep their actual parent relations, including necessary off-branch ancestors.\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tconst entry = byId.get(id);\n\t\t\t\t\tif (!entry) throw new Error(\"Fork related source is unavailable\");\n\t\t\t\t\tif (entry.parentId !== null) ids.add(entry.parentId);\n\t\t\t\t}\n\t\t\t\tconst order = new Map(epochCopy.entries.map((entry) => [entry.id, entry.sequence]));\n\t\t\t\tcopied = [...ids].map((id) => byId.get(id)!).sort((a, b) => order.get(a.id)! - order.get(b.id)!);\n\t\t\t}\n\t\t\tconst activeLabels = new Map<string, CapturedForkInput[\"labels\"][number]>();\n\t\t\tfor (const entry of entries) {\n\t\t\t\tif (entry.type !== \"label\") continue;\n\t\t\t\tif (entry.label)\n\t\t\t\t\tactiveLabels.set(entry.targetId, {\n\t\t\t\t\t\ttargetId: entry.targetId,\n\t\t\t\t\t\tlabel: entry.label,\n\t\t\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\t\t\tretention: entryRetentions.get(entry),\n\t\t\t\t\t\tqualification: entryQualifications.get(entry),\n\t\t\t\t\t});\n\t\t\t\telse activeLabels.delete(entry.targetId);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...settings,\n\t\t\t\tsource: history?.source,\n\t\t\t\t...(epochCopy ? { epochCopy, leafId } : {}),\n\t\t\t\tselectedEntry: selectedEntry\n\t\t\t\t\t? withEntryRetention(\n\t\t\t\t\t\t\tJSON.parse(stringifyBoundedJson(selectedEntry, limits.maxSourceBytes)) as SessionEntry,\n\t\t\t\t\t\t\tentryRetentions.get(selectedEntry),\n\t\t\t\t\t\t\tentryQualifications.get(selectedEntry),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tpath: copied,\n\t\t\t\tlabels: [...activeLabels.values()].filter((label) => ids.has(label.targetId)),\n\t\t\t};\n\t\t};\n\t\tif (!this.indexed) {\n\t\t\tconst resident = this.materializeResidentHistory(limits);\n\t\t\treturn finish(\n\t\t\t\tresident.entries.map((entry, index) =>\n\t\t\t\t\twithEntryRetention(\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tresident.retentions[index] ?? undefined,\n\t\t\t\t\t\tresident.qualifications[index] ?? undefined,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tconst headerBytes = Buffer.byteLength(stringifyBoundedJson(header, limits.maxSourceBytes));\n\t\tif (headerBytes >= limits.maxSourceBytes) throw new Error(\"Fork source byte budget exceeded\");\n\t\treturn this.readSourceHistory(async (history) => {\n\t\t\tconst metadata = new Map<string, CopiedEpochEntry>();\n\t\t\tlet metadataBytes = 0;\n\t\t\tlet after = 0;\n\t\t\tfor (;;) {\n\t\t\t\tconst page = await history.page(after, 128);\n\t\t\t\tif (page.indexedThrough < history.source.sourceSequence)\n\t\t\t\t\tthrow new Error(\"Captured fork history has incomplete index coverage\");\n\t\t\t\tfor (const reference of page.events) {\n\t\t\t\t\t// Prefix/revision remapping needs original refs, not text previews or unselected bodies.\n\t\t\t\t\tconst source: CopiedEpochEntry = {\n\t\t\t\t\t\tid: reference.id,\n\t\t\t\t\t\tparentId: reference.parentId,\n\t\t\t\t\t\tkind: reference.kind,\n\t\t\t\t\t\tsequence: reference.sequence,\n\t\t\t\t\t\trevision: reference.revision,\n\t\t\t\t\t\tlocator: { ...reference.locator },\n\t\t\t\t\t\tretention: reference.retention,\n\t\t\t\t\t\tqualification: reference.qualification,\n\t\t\t\t\t};\n\t\t\t\t\tmetadataBytes += Buffer.byteLength(JSON.stringify(source)) + 1;\n\t\t\t\t\tif (metadataBytes > FORK_SOURCE_METADATA_MAX_BYTES)\n\t\t\t\t\t\tthrow new Error(\"Fork source metadata byte budget exceeded\");\n\t\t\t\t\tmetadata.set(source.id, source);\n\t\t\t\t}\n\t\t\t\tif (page.nextAfter === null) break;\n\t\t\t\tafter = page.nextAfter;\n\t\t\t}\n\t\t\tconst hasEpoch = [...metadata.values()].some(\n\t\t\t\t(entry) => entry.kind === \"compaction\" && entry.qualification === \"native-context-epoch\",\n\t\t\t);\n\t\t\tconst loaded = new Map<string, SessionEntry>();\n\t\t\tlet sourceBytes = headerBytes;\n\t\t\tconst load = async (id: string): Promise<SessionEntry> => {\n\t\t\t\tconst existing = loaded.get(id);\n\t\t\t\tif (existing) return existing;\n\t\t\t\tconst reference = metadata.get(id);\n\t\t\t\tif (!reference) throw new Error(\"Fork selected source is unavailable\");\n\t\t\t\tif (loaded.size >= limits.maxEntries) throw new Error(\"Fork entry budget exceeded\");\n\t\t\t\tconst remaining = limits.maxSourceBytes - sourceBytes;\n\t\t\t\tif (reference.locator.length > remaining) throw new Error(\"Fork source byte budget exceeded\");\n\t\t\t\tconst hydrated = await history.hydrateEntry(id, remaining);\n\t\t\t\tif (!hydrated) throw new Error(\"Fork selected source is unavailable\");\n\t\t\t\tconst entry = withEntryRetention(hydrated.entry, hydrated.source.retention, hydrated.source.qualification);\n\t\t\t\tloaded.set(id, entry);\n\t\t\t\tmetadata.set(id, captureEpochCopyEntry(entry, hydrated.source));\n\t\t\t\tsourceBytes += reference.locator.length;\n\t\t\t\treturn entry;\n\t\t\t};\n\t\t\tif (\"entryId\" in target && !metadata.has(target.entryId)) throw new Error(\"Invalid entry ID for forking\");\n\t\t\tconst selected = \"entryId\" in target ? await load(target.entryId) : undefined;\n\t\t\tif (\n\t\t\t\t\"entryId\" in target &&\n\t\t\t\ttarget.position === \"before\" &&\n\t\t\t\t(selected?.type !== \"message\" || selected.message.role !== \"user\")\n\t\t\t)\n\t\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t\tconst leafId =\n\t\t\t\t\"entryId\" in target ? (target.position === \"at\" ? selected!.id : selected!.parentId) : target.leafId;\n\t\t\tconst path: SessionEntry[] = [];\n\t\t\tlet page = await history.parentPathFrom(leafId);\n\t\t\tfor (;;) {\n\t\t\t\tif (page.totalEntries > limits.maxEntries) throw new Error(\"Fork entry budget exceeded\");\n\t\t\t\tfor (const reference of page.events) path.push(await load(reference.id));\n\t\t\t\tif (!page.nextCursor) break;\n\t\t\t\tpage = await history.parentPathFrom(leafId, { cursor: page.nextCursor });\n\t\t\t}\n\t\t\tconst copied = path.filter((entry) => entry.type !== \"label\");\n\t\t\tconst ids = new Set(copied.map((entry) => entry.id));\n\t\t\tif (hasEpoch) {\n\t\t\t\tfor (const entry of copied) {\n\t\t\t\t\tif (entry.type !== \"message\") continue;\n\t\t\t\t\tif (entry.execution && \"invocationId\" in entry.execution) ids.add(entry.execution.invocationId);\n\t\t\t\t\tconst updateTarget =\n\t\t\t\t\t\tentry.message.role === \"assistant\"\n\t\t\t\t\t\t\t? { kind: \"assistant-usage\" as const, targetId: entry.id }\n\t\t\t\t\t\t\t: entry.message.role === \"toolResult\"\n\t\t\t\t\t\t\t\t? { kind: \"ipython-sent-message\" as const, toolCallId: entry.message.toolCallId }\n\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\tif (!updateTarget) continue;\n\t\t\t\t\tlet after = 0;\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tconst updates = await history.sourceContextUpdates(updateTarget, after);\n\t\t\t\t\t\tif (updates.indexedThrough < history.source.sourceSequence)\n\t\t\t\t\t\t\tthrow new Error(\"Captured fork updates have incomplete index coverage\");\n\t\t\t\t\t\tfor (const reference of updates.events) ids.add(reference.id);\n\t\t\t\t\t\tif (updates.nextAfter === null) break;\n\t\t\t\t\t\tafter = updates.nextAfter;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Keep every actual related ancestor, including private intent/request rows when necessary.\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tconst reference = metadata.get(id);\n\t\t\t\t\tif (!reference) throw new Error(\"Fork related source is unavailable\");\n\t\t\t\t\tif (reference.parentId !== null) ids.add(reference.parentId);\n\t\t\t\t}\n\t\t\t\tfor (const id of ids) await load(id);\n\t\t\t} else {\n\t\t\t\t// Preserve the existing non-epoch copy's resolved whole-source assistant usage overlay.\n\t\t\t\tfor (const entry of copied) {\n\t\t\t\t\tif (entry.type !== \"message\" || entry.message.role !== \"assistant\") continue;\n\t\t\t\t\tconst latest = await history.sourceAssistantUsage(entry.id);\n\t\t\t\t\tif (latest) await load(latest.id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const id of ids) {\n\t\t\t\tconst label = await history.sourceLabel(id);\n\t\t\t\tif (label) await load(label.id);\n\t\t\t}\n\t\t\tconst entries = [...loaded.values()].sort(\n\t\t\t\t(left, right) => metadata.get(left.id)!.sequence - metadata.get(right.id)!.sequence,\n\t\t\t);\n\t\t\tif (!hasEpoch) applyChildUsageAttributions(entries);\n\t\t\tconst epochCopy: CapturedEpochCopy | undefined = hasEpoch\n\t\t\t\t? {\n\t\t\t\t\t\tsessionId: history.source.sessionId,\n\t\t\t\t\t\tsessionFile: history.source.sessionFile,\n\t\t\t\t\t\tthrough: history.source.sourceSequence,\n\t\t\t\t\t\tentries: [...metadata.values()],\n\t\t\t\t\t\tretained: false,\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\t\t\tif (epochCopy) stringifyBoundedJson(epochCopy, FORK_SOURCE_METADATA_MAX_BYTES);\n\t\t\treturn finish(entries, history, epochCopy);\n\t\t});\n\t}\n\n\tprivate async _rebuildCopiedEpoch(\n\t\tcopied: CapturedEpochCopy,\n\t\tlimits: SessionHistoryReadLimits,\n\t\tmetadataMaxBytes = limits.maxSourceBytes,\n\t): Promise<void> {\n\t\tif (\n\t\t\t!copied.entries.some((entry) => entry.kind === \"compaction\" && entry.qualification === \"native-context-epoch\")\n\t\t)\n\t\t\treturn;\n\t\tif (!this.supportsCapturedHistoryReads())\n\t\t\tthrow new Error(\"Copied context epochs require an owned persistent source\");\n\t\tconst sink = this.bindCompactionSink(limits);\n\t\tawait this._runHistoryRead(\n\t\t\t{ ...sink, readHistory: (read) => sink[readCopiedEpochSource](read) },\n\t\t\tasync (history: SessionHistoryReadScope) => {\n\t\t\t\tconst rebuilt = await rebuildCopiedContextEpoch(history, copied, limits, metadataMaxBytes);\n\t\t\t\tif (rebuilt) await sink[appendContextEpoch](rebuilt.checkpoint, rebuilt.tokensBefore, rebuilt.summary);\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate static async _createCapturedFork(input: CapturedForkInput): Promise<SessionManager> {\n\t\tconst next = new SessionManager(input.cwd, input.sessionDir, input.persist, {\n\t\t\tparentSession: input.sourceFile,\n\t\t\trlmDepth: input.rlmDepth,\n\t\t});\n\t\tnext.freshContextPolicySource = false;\n\t\tlet bytes = Buffer.byteLength(stringifyBoundedJson(next.fileEntries[0], input.limits.maxSourceBytes));\n\t\tconst append = (\n\t\t\tentry: SessionEntry,\n\t\t\tretention?: JournalFrameRetention,\n\t\t\tqualification = entryQualifications.get(entry),\n\t\t) => {\n\t\t\tif (next.fileEntries.length - 1 >= input.limits.maxEntries) throw new Error(\"Fork entry budget exceeded\");\n\t\t\tconst json = stringifyBoundedJson(entry, input.limits.maxSourceBytes - bytes);\n\t\t\tbytes += Buffer.byteLength(json);\n\t\t\tnext.fileEntries.push(withEntryRetention(JSON.parse(json) as SessionEntry, retention, qualification));\n\t\t};\n\t\tfor (const entry of input.path) append(entry, entryRetentions.get(entry));\n\t\tconst ids = new Set(input.path.map((entry) => entry.id));\n\t\tlet parentId = input.path.at(-1)?.id ?? null;\n\t\tfor (const label of input.labels) {\n\t\t\tconst id = generateId(ids);\n\t\t\tids.add(id);\n\t\t\tappend(\n\t\t\t\t{ type: \"label\", id, parentId, timestamp: label.timestamp, targetId: label.targetId, label: label.label },\n\t\t\t\tlabel.retention,\n\t\t\t\tlabel.qualification,\n\t\t\t);\n\t\t\tparentId = id;\n\t\t}\n\t\tnext._buildIndex();\n\t\tif (input.persist) await next._openNew();\n\t\telse next.writeState.sequence = next.fileEntries.length - 1;\n\t\tif (input.epochCopy) {\n\t\t\ttry {\n\t\t\t\tawait next.branchTo(input.leafId ?? null);\n\t\t\t\tawait next._rebuildCopiedEpoch(input.epochCopy, input.limits, FORK_SOURCE_METADATA_MAX_BYTES);\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait next.close();\n\t\t\t\t} catch (cleanup) {\n\t\t\t\t\tthrow new AggregateError([error, cleanup], \"Fork activation and destination close failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn next;\n\t}\n\n\tasync prepareFork(\n\t\tentryId: string,\n\t\toptions: {\n\t\t\tposition?: \"before\" | \"at\";\n\t\t\tpersist?: boolean;\n\t\t\tsessionDir?: string;\n\t\t\trlmDepth?: number;\n\t\t\tlimits?: SessionHistoryReadLimits;\n\t\t} = {},\n\t): Promise<PreparedSessionFork> {\n\t\tconst captured = await this._captureForkInput(\n\t\t\t{ entryId, position: options.position ?? \"before\" },\n\t\t\t{ ...options },\n\t\t);\n\t\treturn {\n\t\t\tsource: captured.source,\n\t\t\tselectedEntry: captured.selectedEntry!,\n\t\t\tcreate: () => SessionManager._createCapturedFork(captured),\n\t\t};\n\t}\n\n\tasync forkBranch(\n\t\tleafId: string | null,\n\t\toptions: { persist?: boolean; sessionDir?: string; rlmDepth?: number; limits?: SessionHistoryReadLimits } = {},\n\t): Promise<SessionManager> {\n\t\treturn SessionManager._createCapturedFork(await this._captureForkInput({ leafId }, { ...options }));\n\t}\n\n\tasync createBranchedSession(leafId: string): Promise<string | undefined> {\n\t\tthis._assertMutable();\n\t\tconst next = await this.forkBranch(leafId);\n\t\tthis._assertMutable();\n\t\tthis.switching = true;\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tawait this.flushNow();\n\t\t\t} catch (error) {\n\t\t\t\ttry {\n\t\t\t\t\tawait next.close();\n\t\t\t\t} catch (cleanup) {\n\t\t\t\t\tthrow new AggregateError([error, cleanup], \"Branch adoption preparation and destination close failed\");\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tawait this._adopt(next);\n\t\t\treturn this.sessionFile;\n\t\t} finally {\n\t\t\tthis.switching = false;\n\t\t}\n\t}\n\n\tstatic async create(cwd: string, sessionDir?: string, options?: NewSessionOptions): Promise<SessionManager> {\n\t\tconst manager = new SessionManager(cwd, sessionDir ?? getDefaultSessionDir(cwd), true, options);\n\t\tawait manager._openNew();\n\t\treturn manager;\n\t}\n\n\tstatic async open(path: string, sessionDir?: string, cwdOverride?: string): Promise<SessionManager> {\n\t\tconst target = assertProductStatePath(path);\n\t\tif (!existsSync(target)) {\n\t\t\tconst manager = new SessionManager(cwdOverride ?? process.cwd(), sessionDir ?? dirname(target), true);\n\t\t\tmanager.sessionFile = target;\n\t\t\tawait manager._openNew();\n\t\t\treturn manager;\n\t\t}\n\t\tconst owner = await SessionJournalOwner.open({ journalPath: target });\n\t\tlet manager: SessionManager | undefined;\n\t\ttry {\n\t\t\tlet entries: FileEntry[] | undefined;\n\t\t\tlet header: SessionHeader;\n\t\t\tif (owner.format === \"framed\") header = await readOwnedSessionHeader(owner.getSnapshot());\n\t\t\telse {\n\t\t\t\tentries = await loadEntriesFromFileAsync(owner.journalPath);\n\t\t\t\tconst first = entries[0];\n\t\t\t\tif (!first || first.type !== \"session\" || typeof first.id !== \"string\")\n\t\t\t\t\tthrow new Error(`Session source has no valid header: ${target}`);\n\t\t\t\theader = first;\n\t\t\t}\n\t\t\tconst sourceVersion = header.version ?? 1;\n\t\t\tif (sourceVersion > CURRENT_SESSION_VERSION) throw new Error(`Unsupported session version: ${sourceVersion}`);\n\t\t\tif (header.parentSession && !isValidRlmDepth(header.rlmDepth))\n\t\t\t\theader.rlmDepth = resolveSessionRlmDepth(header, owner.journalPath);\n\t\t\tmanager = new SessionManager(\n\t\t\t\tcwdOverride ?? header.cwd ?? process.cwd(),\n\t\t\t\tsessionDir ?? dirname(owner.journalPath),\n\t\t\t\tfalse,\n\t\t\t);\n\t\t\tmanager.persist = true;\n\t\t\tmanager.freshContextPolicySource = false;\n\t\t\tmanager.sessionId = header.id;\n\t\t\tmanager.sessionFile = owner.journalPath;\n\t\t\tmanager.writeState.owner = owner;\n\t\t\tmanager.writeState.sequence = owner.nextSequence - 1;\n\t\t\tmanager.writeState.sourceVersion = sourceVersion;\n\t\t\tif (owner.format === \"framed\" && sourceVersion === CURRENT_SESSION_VERSION) {\n\t\t\t\tawait manager._activateIndexedSource(header);\n\t\t\t} else {\n\t\t\t\tentries ??= await loadEntriesFromFileAsync(owner.journalPath);\n\t\t\t\tmigrateToCurrentVersion(entries);\n\t\t\t\tmanager.fileEntries = entries;\n\t\t\t\tmanager._buildIndex();\n\t\t\t}\n\t\t\treturn manager;\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tif (manager) await manager._closeSourceActors(manager.writeState);\n\t\t\t\telse await owner.close();\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Session open and cleanup failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tstatic async openAsync(path: string, sessionDir?: string, cwdOverride?: string): Promise<SessionManager> {\n\t\treturn SessionManager.open(path, sessionDir, cwdOverride);\n\t}\n\n\tstatic async openReadOnly(path: string, sessionDir?: string, cwdOverride?: string): Promise<SessionManager> {\n\t\tconst target = realpathIfPresent(resolve(path));\n\t\tconst entries = await loadEntriesFromFileAsync(target);\n\t\tconst header = entries[0];\n\t\tif (!header || header.type !== \"session\" || typeof header.id !== \"string\")\n\t\t\tthrow new Error(`Session source has no valid header: ${target}`);\n\t\tconst sourceVersion = header.version ?? 1;\n\t\tif (sourceVersion > CURRENT_SESSION_VERSION) throw new Error(`Unsupported session version: ${sourceVersion}`);\n\t\tmigrateToCurrentVersion(entries);\n\t\tif (header.parentSession && !isValidRlmDepth(header.rlmDepth))\n\t\t\theader.rlmDepth = resolveSessionRlmDepth(header, target);\n\t\tconst manager = new SessionManager(\n\t\t\tcwdOverride ?? header.cwd ?? process.cwd(),\n\t\t\tsessionDir ?? dirname(target),\n\t\t\tfalse,\n\t\t);\n\t\tmanager.writeState.sourceVersion = sourceVersion;\n\t\tmanager.persist = true;\n\t\tmanager.readOnly = true;\n\t\tmanager.sessionId = header.id;\n\t\tmanager.sessionFile = target;\n\t\tmanager.fileEntries = entries;\n\t\tmanager.writeState.sequence = entries.length - 1;\n\t\tmanager._buildIndex();\n\t\treturn manager;\n\t}\n\n\tstatic async continueRecent(cwd: string, sessionDir?: string): Promise<SessionManager> {\n\t\tconst dir = sessionDir ?? getDefaultSessionDir(cwd);\n\t\tconst mostRecent = findMostRecentSessionForCwd(dir, cwd);\n\t\treturn mostRecent ? SessionManager.open(mostRecent, dir, cwd) : SessionManager.create(cwd, dir);\n\t}\n\n\tstatic inMemory(cwd: string = process.cwd(), sessionDir = \"\", options?: NewSessionOptions): SessionManager {\n\t\treturn new SessionManager(cwd, sessionDir, false, options);\n\t}\n\n\tstatic async forkFrom(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionManager> {\n\t\treturn SessionManager._copyFrom(sourcePath, targetCwd, sessionDir, undefined, { ...limits });\n\t}\n\n\t/** Explicit external import: supported payload versions and complete captured records, with copied authority lowered. */\n\tstatic async importRetainedFrom(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t\trequiredSourceFormat?: \"legacy-jsonl\",\n\t): Promise<SessionManager> {\n\t\treturn SessionManager._copyFrom(\n\t\t\tsourcePath,\n\t\t\ttargetCwd,\n\t\t\tsessionDir,\n\t\t\t\"retained-import\",\n\t\t\t{ ...limits },\n\t\t\trequiredSourceFormat,\n\t\t);\n\t}\n\n\t/** Prepare one retained source without allocating a destination or assessing its activation. */\n\tstatic async previewRetainedImport(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t): Promise<SessionImportPreview> {\n\t\tconst targetDirectory = assertProductStatePath(sessionDir ?? getDefaultSessionDir(targetCwd));\n\t\tconst prepared = await SessionManager._prepareCopy(sourcePath, \"retained-import\", { ...limits });\n\t\treturn {\n\t\t\tsourcePath: prepared.sourcePath,\n\t\t\tsourceFormat: prepared.sourceFormat,\n\t\t\tinputVersion: prepared.inputVersion,\n\t\t\tentriesRead: prepared.entriesRead,\n\t\t\tsourceJsonBytes: prepared.sourceJsonBytes,\n\t\t\tpreparedEntryCount: prepared.targetEntries.length,\n\t\t\ttargetCwd,\n\t\t\ttargetDirectory,\n\t\t\tretention: \"retained-import\",\n\t\t\tsourceHeader: \"replace\",\n\t\t\tgitState: \"omit-and-relink-parents\",\n\t\t\tcapture: \"bounded-prefix-not-live-snapshot\",\n\t\t\tdestinationCreated: false,\n\t\t\tdestinationCreationAndIndexing: \"not-assessed\",\n\t\t\tcanonicalEpochActivation: \"not-assessed\",\n\t\t\treferenceReplayCoverage: \"not-assessed\",\n\t\t\tlaterImport: \"rereads-source-and-can-fail\",\n\t\t};\n\t}\n\n\tprivate static async _copyFrom(\n\t\tsourcePath: string,\n\t\ttargetCwd: string,\n\t\tsessionDir?: string,\n\t\tretention?: JournalFrameRetention,\n\t\tlimits: SessionHistoryReadLimits = DEFAULT_MANAGER_HISTORY_LIMITS,\n\t\trequiredSourceFormat?: \"legacy-jsonl\",\n\t): Promise<SessionManager> {\n\t\tconst targetDirectory = resolve(sessionDir ?? getDefaultSessionDir(targetCwd));\n\t\tconst prepared = await SessionManager._prepareCopy(sourcePath, retention, limits, requiredSourceFormat);\n\t\tconst manager = new SessionManager(targetCwd, targetDirectory, true, {\n\t\t\tparentSession: sourcePath,\n\t\t\trlmDepth: resolveSessionRlmDepth(prepared.sourceHeader, sourcePath),\n\t\t});\n\t\tprepared.targetEntries.unshift(manager.fileEntries[0]);\n\t\tmanager.fileEntries = prepared.targetEntries;\n\t\tmanager._buildIndex();\n\t\tawait manager._openNew();\n\t\ttry {\n\t\t\tawait manager._rebuildCopiedEpoch(prepared.epochCopy, limits);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait manager.close();\n\t\t\t} catch (cleanup) {\n\t\t\t\tthrow new AggregateError([error, cleanup], \"Copied context activation and destination close failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\treturn manager;\n\t}\n\n\t/** The same held source preparation feeds preview and the real destination writer. */\n\tprivate static async _prepareCopy(\n\t\tsourcePath: string,\n\t\tretention: JournalFrameRetention | undefined,\n\t\tlimits: SessionHistoryReadLimits,\n\t\trequiredSourceFormat?: \"legacy-jsonl\",\n\t) {\n\t\tconst { maxEntries, maxSourceBytes } = limits;\n\t\tconst explicitImport = retention === \"retained-import\";\n\t\tif (\n\t\t\t!Number.isSafeInteger(maxEntries) ||\n\t\t\tmaxEntries <= 0 ||\n\t\t\t!Number.isSafeInteger(maxSourceBytes) ||\n\t\t\tmaxSourceBytes <= 0\n\t\t)\n\t\t\tthrow new Error(\"Invalid copied history limits\");\n\t\tlet entriesRead = 0;\n\t\tlet sourceBytes = 0;\n\t\tlet sourceHeader:\n\t\t\t| {\n\t\t\t\t\tentry: SessionHeader;\n\t\t\t\t\tformat: SessionImportPreview[\"sourceFormat\"];\n\t\t\t\t\tinputVersion: number;\n\t\t\t }\n\t\t\t| undefined;\n\t\tconst capturedPath = realpathIfPresent(resolve(sourcePath));\n\t\tconst capturedEntries: CopiedEpochEntry[] = [];\n\t\tlet through = 0;\n\t\tlet legacyEntries: FileEntry[] | undefined;\n\t\t// This becomes the target's resident array; current-version copies do not retain a second source array.\n\t\tconst targetEntries: FileEntry[] = [];\n\t\tconst dropped = new Map<string, string | null>();\n\t\tconst keep = (entry: FileEntry) => {\n\t\t\tif (entry.type === \"session\") return;\n\t\t\tif (entry.type === \"git_state\") dropped.set(entry.id, entry.parentId);\n\t\t\telse\n\t\t\t\ttargetEntries.push(\n\t\t\t\t\twithEntryRetention(entry, retention ?? entryRetentions.get(entry), entryQualifications.get(entry)),\n\t\t\t\t);\n\t\t};\n\t\tif (existsSync(sourcePath)) {\n\t\t\tawait readCapturedSessionJournal(\n\t\t\t\tcapturedPath,\n\t\t\t\t(record) => {\n\t\t\t\t\tsourceBytes += Buffer.byteLength(record.json);\n\t\t\t\t\tif (sourceBytes > maxSourceBytes) throw new Error(\"Copied history JSON byte budget exceeded\");\n\t\t\t\t\tconst entry = sessionFileEntry(record.entry, record.retention, record.qualification);\n\t\t\t\t\tif (record.source) through = record.source.sequence;\n\t\t\t\t\tif (!sourceHeader) {\n\t\t\t\t\t\tif (entry.type !== \"session\" || typeof entry.id !== \"string\")\n\t\t\t\t\t\t\tthrow new Error(\"Session source has no valid header\");\n\t\t\t\t\t\tconst version = entry.version === undefined ? 1 : entry.version;\n\t\t\t\t\t\tif (explicitImport && ![1, 2, CURRENT_SESSION_VERSION].includes(version))\n\t\t\t\t\t\t\tthrow new Error(`Unsupported session version for retained import: ${String(entry.version)}`);\n\t\t\t\t\t\tif (requiredSourceFormat === \"legacy-jsonl\" && record.source)\n\t\t\t\t\t\t\tthrow new Error(\"This import requires legacy-jsonl; native-framed input is unsupported\");\n\t\t\t\t\t\tsourceHeader = {\n\t\t\t\t\t\t\tentry,\n\t\t\t\t\t\t\tformat: record.source ? \"native-framed\" : \"legacy-jsonl\",\n\t\t\t\t\t\t\tinputVersion: version,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (entry.version !== CURRENT_SESSION_VERSION) legacyEntries = [entry];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (++entriesRead > maxEntries) throw new Error(\"Copied history entry budget exceeded\");\n\t\t\t\t\t\tif (entry.type !== \"session\" && record.source)\n\t\t\t\t\t\t\tcapturedEntries.push(\n\t\t\t\t\t\t\t\tcaptureEpochCopyEntry(entry, {\n\t\t\t\t\t\t\t\t\t...record.source,\n\t\t\t\t\t\t\t\t\tid: entry.id,\n\t\t\t\t\t\t\t\t\tparentId: entry.parentId,\n\t\t\t\t\t\t\t\t\tkind: entry.type,\n\t\t\t\t\t\t\t\t\tretention: record.retention,\n\t\t\t\t\t\t\t\t\tqualification: record.qualification,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\tif (legacyEntries) legacyEntries.push(entry);\n\t\t\t\t\t\telse keep(entry);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ requireCompleteTail: explicitImport },\n\t\t\t);\n\t\t}\n\t\tif (!sourceHeader)\n\t\t\tthrow new Error(`Cannot ${explicitImport ? \"import\" : \"fork\"}: source session has no header: ${sourcePath}`);\n\t\tif (legacyEntries) {\n\t\t\tfinalizeLoadedEntries(legacyEntries);\n\t\t\tmigrateToCurrentVersion(legacyEntries);\n\t\t\tfor (const entry of legacyEntries) keep(entry);\n\t\t} else if (\n\t\t\t!capturedEntries.some((entry) => entry.kind === \"compaction\" && entry.qualification === \"native-context-epoch\")\n\t\t) {\n\t\t\tapplyChildUsageAttributions(targetEntries);\n\t\t}\n\t\t// Relink after reading so even forward references through dropped git facts keep their old meaning.\n\t\tfor (let index = 0; index < targetEntries.length; index++) {\n\t\t\tconst entry = targetEntries[index] as SessionEntry;\n\t\t\tlet parentId = entry.parentId;\n\t\t\tconst seen = new Set<string>();\n\t\t\twhile (parentId !== null && dropped.has(parentId)) {\n\t\t\t\tif (seen.has(parentId)) throw new Error(\"Copied session git ancestry is unresolved\");\n\t\t\t\tseen.add(parentId);\n\t\t\t\tparentId = dropped.get(parentId) ?? null;\n\t\t\t}\n\t\t\tif (parentId !== entry.parentId)\n\t\t\t\ttargetEntries[index] = withEntryRetention(\n\t\t\t\t\t{ ...entry, parentId },\n\t\t\t\t\tentryRetentions.get(entry),\n\t\t\t\t\tentryQualifications.get(entry),\n\t\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tsourcePath: capturedPath,\n\t\t\tsourceFormat: sourceHeader.format,\n\t\t\tinputVersion: sourceHeader.inputVersion,\n\t\t\tentriesRead,\n\t\t\tsourceJsonBytes: sourceBytes,\n\t\t\tsourceHeader: sourceHeader.entry,\n\t\t\ttargetEntries,\n\t\t\tepochCopy: {\n\t\t\t\tsessionId: sourceHeader.entry.id,\n\t\t\t\tsessionFile: capturedPath,\n\t\t\t\tthrough,\n\t\t\t\tentries: capturedEntries,\n\t\t\t\tretained: retention === \"retained-import\",\n\t\t\t},\n\t\t};\n\t}\n\n\tstatic async list(cwd: string, sessionDir?: string, callbacks?: SessionListCallbacks): Promise<SessionInfo[]> {\n\t\tconst dir = sessionDir ?? getDefaultSessionDir(cwd);\n\t\tconst matchesCwd = (session: SessionInfo) => sessionInfoMatchesCwd(session, cwd);\n\t\tconst sessions = (\n\t\t\tawait listSessionsFromDir(dir, {\n\t\t\t\tonProgress: callbacks?.onProgress,\n\t\t\t\tonSession: callbacks?.onSession\n\t\t\t\t\t? (session) => {\n\t\t\t\t\t\t\tif (matchesCwd(session)) {\n\t\t\t\t\t\t\t\tcallbacks.onSession?.(session);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t})\n\t\t).filter(matchesCwd);\n\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\treturn sessions;\n\t}\n\n\tstatic async listAll(callbacks?: SessionListCallbacks, sessionDir?: string): Promise<SessionInfo[]> {\n\t\tconst sessionsDir = sessionDir ?? getSessionsDir();\n\t\tconst sessions = await listSessionsFromDir(sessionsDir, callbacks);\n\t\tsessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\treturn sessions;\n\t}\n}\n"]}
|