codesesh 1.0.1 → 1.0.3
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/README.md +2 -1
- package/dist/{chunk-JHX5OLL4.js → chunk-PSHZZITB.js} +3280 -805
- package/dist/chunk-PSHZZITB.js.map +1 -0
- package/dist/chunk-RF3EEWPH.js +17 -0
- package/dist/chunk-RF3EEWPH.js.map +1 -0
- package/dist/{chunk-OFTTM3UD.js → chunk-WAKW5OPS.js} +2 -2
- package/dist/{dist-N2PQATP2.js → dist-RHDY2EZX.js} +18 -20
- package/dist/index.js +1291 -672
- package/dist/index.js.map +1 -1
- package/dist/project-identity-worker.js +27 -0
- package/dist/project-identity-worker.js.map +1 -0
- package/dist/scan-refresh-worker.js +15 -6
- package/dist/scan-refresh-worker.js.map +1 -1
- package/dist/search-index-worker.js +16 -6
- package/dist/search-index-worker.js.map +1 -1
- package/dist/smart-tag-worker.js +2 -2
- package/dist/web/assets/{ErrorBoundary-D11tWzfn.js → ErrorBoundary-DIwwrdlw.js} +1 -1
- package/dist/web/assets/InteractiveReceipt-DmNBDVms.js +1 -0
- package/dist/web/assets/{OverviewScreen-DriPmCam.js → OverviewScreen-B5JekBLC.js} +1 -1
- package/dist/web/assets/Projects-Bj6ma2k2.js +1 -0
- package/dist/web/assets/{SearchFilterBar-Bx73B5e9.js → SearchFilterBar-B9VrUbym.js} +1 -1
- package/dist/web/assets/{SearchResultsPanel-A6_3TPhW.js → SearchResultsPanel-C1cuuOKq.js} +1 -1
- package/dist/web/assets/SessionDetail-Dc2CQ3hH.js +54 -0
- package/dist/web/assets/contract-DXvltqJG.js +1 -0
- package/dist/web/assets/index-3UfOiTBO.css +1 -0
- package/dist/web/assets/index-DBMiEd61.js +1410 -0
- package/dist/web/assets/panel-CLnL4kMN.js +1 -0
- package/dist/web/assets/{session-indexes-0oT5HSS5.js → session-indexes-BPhf1X2P.js} +2 -2
- package/dist/web/assets/{utils-DgUgu15E.js → utils-BKqufGdv.js} +1 -1
- package/dist/web/icon/agent/dsh.svg +3 -0
- package/dist/web/index.html +8 -8
- package/package.json +1 -1
- package/dist/chunk-JHX5OLL4.js.map +0 -1
- package/dist/web/assets/InteractiveReceipt-DYGyHeZd.js +0 -1
- package/dist/web/assets/Projects-BPDIcUBK.js +0 -1
- package/dist/web/assets/SessionDetail-lQz99ARH.js +0 -54
- package/dist/web/assets/contract-V6QuD0UY.js +0 -1
- package/dist/web/assets/index-B2RqUgZ5.css +0 -1
- package/dist/web/assets/index-BgWoUD_4.js +0 -1410
- package/dist/web/assets/panel-C-gc79Gz.js +0 -1
- /package/dist/{chunk-OFTTM3UD.js.map → chunk-WAKW5OPS.js.map} +0 -0
- /package/dist/{dist-N2PQATP2.js.map → dist-RHDY2EZX.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/contract/session-reference.ts","../../core/src/contract/message-part.ts","../../core/src/agents/registry.ts","../../core/src/utils/diagnostics.ts","../../core/src/utils/private-storage.ts","../../core/src/pricing/fetcher.ts","../../core/src/pricing/data/snapshot.json","../../core/src/pricing/data/aliases.json","../../core/src/pricing/resolver.ts","../../core/src/pricing/cost.ts","../../core/src/agents/session-source-synchronization.ts","../../core/src/agents/base.ts","../../core/src/utils/perf.ts","../../core/src/agents/claudecode.ts","../../core/src/discovery/paths.ts","../../core/src/utils/jsonl.ts","../../core/src/utils/title-fallback.ts","../../core/src/utils/parse-cleanup.ts","../../core/src/utils/session-normalization.ts","../../core/src/utils/cost.ts","../../core/src/utils/timestamp.ts","../../core/src/utils/narrow.ts","../../core/src/agents/transcript-builder.ts","../../core/src/agents/opencode.ts","../../core/src/utils/sqlite.ts","../../core/src/agents/opencode-sqlite.ts","../../core/src/agents/kimi.ts","../../core/src/agents/tool-arguments.ts","../../core/src/agents/kimi-code.ts","../../core/src/agents/codex.ts","../../core/src/agents/codex-exec-decode.ts","../../core/src/agents/cursor.ts","../../core/src/agents/pi.ts","../../core/src/agents/zcode.ts","../../core/src/agents/grok.ts","../../core/src/agents/dsh.ts","../../core/src/agents/dsh-session-log.ts","../../core/src/agents/dsh-transcript.ts","../../core/src/agents/register.ts","../../core/src/discovery/cache/version.ts","../../core/src/contract/events.ts","../../core/src/contract/calendar-day.ts","../../core/src/contract/project-identity.ts","../../core/src/contract/session-index.ts","../../core/src/contract/session-tree.ts","../../core/src/discovery/scanner.ts","../../core/src/projects/display-name.ts","../../core/src/projects/fs.ts","../../core/src/projects/identity.ts","../../core/src/projects/groups.ts","../../core/src/projects/scope.ts","../../core/src/utils/smart-tags.ts","../../core/src/utils/worker-log.ts","../../core/src/utils/file-activity.ts","../../core/src/discovery/cache/sessions.ts","../../core/src/discovery/cache/db.ts","../../core/src/discovery/cache/messages.ts","../../core/src/discovery/cache/publication-staging.ts","../../core/src/discovery/cache/schema.ts","../../core/src/discovery/cache/analytics-revision.ts","../../core/src/discovery/cache/search-query-parser.ts","../../core/src/discovery/cache/message-cursor.ts","../../core/src/discovery/cache/detail-version.ts","../../core/src/discovery/cache/search-index-writer.ts","../../core/src/discovery/cache/search.ts","../../core/src/discovery/cache/file-activity.ts","../../core/src/discovery/orchestrate.ts","../../core/src/discovery/session-detail.ts","../../core/src/discovery/cache/project-groups.ts","../../core/src/discovery/cache/cost-facts.ts","../../core/src/discovery/cache/model-cost.ts","../../core/src/discovery/cache/publication.ts","../../core/src/state/database.ts","../../core/src/state/bookmarks.ts","../../core/src/state/session-aliases.ts","../../core/src/bookmarks/materialize.ts","../../core/src/analytics/cost-attribution.ts","../../core/src/analytics/dashboard.ts","../../core/src/analytics/projects.ts","../../core/src/search/session-search.ts"],"sourcesContent":["export interface SessionReference {\n agentName: string;\n sessionId: string;\n}\n\nexport const UNKNOWN_AGENT_NAME = \"unknown\";\n\nexport function normalizeSessionReference(reference: SessionReference): SessionReference {\n return {\n agentName: reference.agentName.trim().toLowerCase(),\n sessionId: reference.sessionId,\n };\n}\n\nexport function parseSessionReference(value: string): SessionReference | null {\n const separatorIndex = value.indexOf(\"/\");\n if (separatorIndex <= 0 || separatorIndex === value.length - 1) return null;\n\n const agentName = value.slice(0, separatorIndex).trim().toLowerCase();\n if (!agentName) return null;\n return {\n agentName,\n sessionId: value.slice(separatorIndex + 1),\n };\n}\n\nexport function formatSessionReference(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return `${normalized.agentName}/${normalized.sessionId}`;\n}\n\nexport function getSessionAgentKey(session: { slug?: string | null }): string {\n return parseSessionReference(session.slug ?? \"\")?.agentName ?? UNKNOWN_AGENT_NAME;\n}\n\n/**\n * Canonical URL path for an agent. Callers must never concatenate the name\n * themselves: both routers match on the raw path, so an unencoded segment can\n * split, truncate, or turn into a query or fragment.\n */\nexport function agentRoutePath(agentName: string): string {\n return `/${encodeURIComponent(agentName.trim().toLowerCase())}`;\n}\n\n/**\n * Canonical URL path for a session reference, shared by web routes and HTTP\n * endpoints. Each segment is encoded independently, so an opaque id keeps `/`,\n * `?`, `#` and `%` intact through React Router and Hono alike.\n */\nexport function sessionRoutePath(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return `${agentRoutePath(normalized.agentName)}/${encodeURIComponent(normalized.sessionId)}`;\n}\n\n/** Same as {@link sessionRoutePath}, for callers holding a session head. */\nexport function getSessionRoutePath(session: { slug: string; id: string }): string {\n return sessionRoutePath({ agentName: getSessionAgentKey(session), sessionId: session.id });\n}\n","import type {\n ImagePart,\n MessagePart,\n PlanPart,\n ToolPart,\n ToolPartState,\n ToolPartStatus,\n} from \"./session.js\";\n\nfunction toRecord(value: unknown): Record<string, unknown> | null {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return typeof value === \"string\" && value ? value : undefined;\n}\n\nfunction optionalTime(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction timeField(time_created: number | undefined) {\n return time_created === undefined ? {} : { time_created };\n}\n\nfunction firstDefined(...values: unknown[]): unknown {\n return values.find((value) => value !== undefined);\n}\n\nfunction normalizeStatus(\n state: Record<string, unknown>,\n output: unknown,\n error: unknown,\n): ToolPartStatus {\n const status = state.status;\n if (status === \"running\" || status === \"completed\" || status === \"error\") return status;\n if (status === \"success\") return \"completed\";\n if (error != null) return \"error\";\n if (output !== undefined) return \"completed\";\n return \"running\";\n}\n\nfunction normalizeMetadata(state: Record<string, unknown>): unknown {\n const rawMetadata = state.metadata ?? state.meta;\n const extras = Object.fromEntries(\n Object.entries(state).filter(\n ([key]) =>\n ![\"status\", \"input\", \"arguments\", \"output\", \"result\", \"error\", \"metadata\", \"meta\"].includes(\n key,\n ),\n ),\n );\n if (Object.keys(extras).length === 0) return rawMetadata;\n\n const metadata = toRecord(rawMetadata);\n return metadata ? { ...metadata, ...extras } : extras;\n}\n\nfunction normalizeToolState(value: unknown, legacyPart: Record<string, unknown>): ToolPartState {\n const state = toRecord(value) ?? {};\n const input = firstDefined(state.input, state.arguments, legacyPart.input);\n const output = firstDefined(state.output, state.result, legacyPart.output);\n const error = state.error;\n const metadata = normalizeMetadata(state);\n\n return {\n status: normalizeStatus(state, output, error),\n ...(input !== undefined ? { input } : {}),\n ...(output !== undefined ? { output } : {}),\n ...(error !== undefined ? { error } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\nfunction planText(value: unknown): string {\n if (typeof value === \"string\") return value;\n const record = toRecord(value);\n if (!record) return \"\";\n return planText(record.text ?? record.plan ?? record.content);\n}\n\nfunction normalizePlanPart(\n value: Record<string, unknown>,\n time_created: number | undefined,\n): PlanPart | null {\n const approval_status = value.approval_status === \"fail\" ? \"fail\" : \"success\";\n const text = planText(value.text ?? (approval_status === \"fail\" ? value.output : value.input));\n return text ? { type: \"plan\", text, approval_status, ...timeField(time_created) } : null;\n}\n\nfunction normalizeImagePart(\n value: Record<string, unknown>,\n time_created: number | undefined,\n): ImagePart | null {\n const data = optionalString(value.data);\n const url = optionalString(value.url);\n const mime_type = optionalString(value.mime_type);\n\n if (data && mime_type) {\n return {\n type: \"image\",\n data,\n mime_type,\n ...(url ? { url } : {}),\n ...timeField(time_created),\n };\n }\n if (url) {\n return {\n type: \"image\",\n url,\n ...(data ? { data } : {}),\n ...(mime_type ? { mime_type } : {}),\n ...timeField(time_created),\n };\n }\n return null;\n}\n\nfunction normalizeToolPart(\n value: Record<string, unknown>,\n time_created: number | undefined,\n): ToolPart | null {\n const title = optionalString(value.title);\n const callID = optionalString(value.callID);\n const tool = optionalString(value.tool)?.trim() || title?.replace(/^tool:\\s*/i, \"\").trim();\n if (!tool) return null;\n\n return {\n type: \"tool\",\n tool,\n ...(title ? { title } : {}),\n ...(callID ? { callID } : {}),\n state: normalizeToolState(value.state, value),\n ...timeField(time_created),\n };\n}\n\nfunction normalizeMessagePart(value: unknown): MessagePart | null {\n const part = toRecord(value);\n if (!part) return null;\n const time_created = optionalTime(part.time_created);\n\n if (part.type === \"text\" || part.type === \"reasoning\") {\n if (typeof part.text !== \"string\") return null;\n return { type: part.type, text: part.text, ...timeField(time_created) };\n }\n if (part.type === \"plan\") return normalizePlanPart(part, time_created);\n if (part.type === \"image\") return normalizeImagePart(part, time_created);\n if (part.type === \"tool\") return normalizeToolPart(part, time_created);\n return null;\n}\n\nexport function normalizeMessageParts(value: unknown): MessagePart[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((part) => {\n const normalized = normalizeMessagePart(part);\n return normalized ? [normalized] : [];\n });\n}\n","import type { BaseAgent } from \"./base.js\";\nimport type { AgentInfo } from \"../types/index.js\";\n\nexport type AgentToolStrategy = \"custom\" | \"default\";\n\nexport interface AgentRegistration {\n create: () => BaseAgent;\n icon: string;\n /** Icon uses brand colors that work on both themes; render it as-is instead of tinting with currentColor. */\n iconColored?: boolean;\n resolveDataRoot: () => string | null;\n resumeCommandPrefix: string | null;\n toolStrategy: AgentToolStrategy;\n}\n\nexport type AgentRoots = Readonly<Record<string, string | null>>;\n\nlet registrations: AgentRegistration[] = [];\n\nexport function registerAgent(reg: AgentRegistration): void {\n registrations.push(reg);\n}\n\nexport function createRegisteredAgents(): BaseAgent[] {\n return registrations.map((r) => r.create());\n}\n\nexport function getRegisteredAgents(): readonly AgentRegistration[] {\n return registrations;\n}\n\nexport function resolveAgentRoots(): AgentRoots {\n return Object.fromEntries(\n registrations.map((registration) => [\n registration.create().name,\n registration.resolveDataRoot(),\n ]),\n );\n}\n\nexport function getAgentInfoMap(sessionsByAgent: Record<string, number>): AgentInfo[] {\n return registrations.map((registration) => {\n const agent = registration.create();\n return {\n name: agent.name,\n displayName: agent.displayName,\n icon: registration.icon,\n iconColored: registration.iconColored,\n resumeCommandPrefix: registration.resumeCommandPrefix,\n count: sessionsByAgent[agent.name] ?? 0,\n };\n });\n}\n","/**\n * Injectable diagnostics sink for core's failure paths. core stays\n * framework-agnostic (no logger dependency); hosts opt in by calling\n * setCoreDiagnostics once at startup. Default is a silent no-op so core's\n * behavior is unchanged for consumers that never inject one.\n */\n\nexport interface CoreDiagnostics {\n info?(event: string, detail?: Record<string, unknown>): void;\n warn(event: string, detail?: Record<string, unknown>): void;\n}\n\nlet diagnostics: CoreDiagnostics | null = null;\n\n/**\n * A host-injected sink that throws must not escape into core's own control\n * flow — e.g. abort a `FileSystemSessionSource.scan` loop or turn a cache\n * write's `catch { return null }` into an uncaught throw. Wrap once here so\n * every `diagnostics?.warn(...)` call site stays exception-safe for free.\n */\nfunction toSafeSink(sink: CoreDiagnostics): CoreDiagnostics {\n return {\n info(event, detail) {\n try {\n sink.info?.(event, detail);\n } catch {}\n },\n warn(event, detail) {\n try {\n sink.warn(event, detail);\n } catch {}\n },\n };\n}\n\nexport function setCoreDiagnostics(next: CoreDiagnostics | null): void {\n diagnostics = next ? toSafeSink(next) : null;\n}\n\nexport function getCoreDiagnostics(): CoreDiagnostics | null {\n return diagnostics;\n}\n","/**\n * Owner-only permissions for the files CodeSesh writes.\n *\n * The session cache holds full transcripts; state holds bookmarks and aliases;\n * logs hold project paths and error detail. All of them were created under the\n * process umask, which is commonly 022 — so 0755 directories and 0644 files. On\n * a shared machine with a traversable home, another user could read them.\n *\n * POSIX modes do not apply on Windows, where `chmod` is a no-op; access there is\n * governed by the profile directory's ACL.\n */\nimport { chmodSync, existsSync, mkdirSync, readdirSync, statSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { getCoreDiagnostics } from \"./diagnostics.js\";\n\n/** Owner read/write/execute. */\nexport const PRIVATE_DIR_MODE = 0o700;\n/** Owner read/write. */\nexport const PRIVATE_FILE_MODE = 0o600;\n\n/** Sidecars SQLite creates next to a database, which carry the same data. */\nconst SQLITE_SIDECAR_SUFFIXES = [\"-wal\", \"-shm\", \"-journal\"];\n\nconst isPosix = process.platform !== \"win32\";\n\nfunction reportChmodFailure(path: string, error: unknown): void {\n getCoreDiagnostics()?.warn(\"storage.permissions_failed\", {\n path,\n message: error instanceof Error ? error.message : String(error),\n });\n}\n\n/** Narrows an existing path's permissions, reporting rather than throwing. */\nfunction restrict(path: string, mode: number): void {\n if (!isPosix || !existsSync(path)) return;\n try {\n // Skip the syscall when it would not change anything.\n if ((statSync(path).mode & 0o777) === mode) return;\n chmodSync(path, mode);\n } catch (error) {\n reportChmodFailure(path, error);\n }\n}\n\n/**\n * Creates a directory only its owner can enter, and tightens it if it existed.\n *\n * A failed mkdir propagates — the caller has nowhere to store anything. A failed\n * chmod does not: the directory is usable, just not as private as intended, and\n * that is reported instead.\n */\nexport function ensurePrivateDirectory(path: string): void {\n mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });\n // `recursive` skips the mode for a directory that already existed.\n restrict(path, PRIVATE_DIR_MODE);\n}\n\n/** Narrows a file CodeSesh owns to owner-only. */\nexport function restrictPrivateFile(path: string): void {\n restrict(path, PRIVATE_FILE_MODE);\n}\n\n/**\n * Tightens files already in a directory — those written before this policy\n * existed, or by an older version. The caller names exactly what it owns, so\n * the sweep never reaches beyond CodeSesh's own files.\n */\nexport function restrictExistingPrivateFiles(\n directory: string,\n owns: (name: string) => boolean,\n): void {\n try {\n for (const entry of readdirSync(directory)) {\n if (owns(entry)) restrictPrivateFile(join(directory, entry));\n }\n } catch (error) {\n reportChmodFailure(directory, error);\n }\n}\n\n/** Databases whose neighbouring backups have already been swept this process. */\nconst sweptBackupsFor = new Set<string>();\n\n/** A backup holds the same rows as the database it came from. */\nfunction restrictExistingBackups(dbPath: string): void {\n if (sweptBackupsFor.has(dbPath)) return;\n sweptBackupsFor.add(dbPath);\n\n const prefix = `${basename(dbPath)}.`;\n restrictExistingPrivateFiles(\n dirname(dbPath),\n (name) => name.startsWith(prefix) && name.endsWith(\".bak\"),\n );\n}\n\n/**\n * Narrows a database, any sidecar SQLite has created, and backups left beside\n * it. Call after opening: the sidecars do not exist until the connection is\n * established.\n */\nexport function restrictPrivateDatabase(dbPath: string): void {\n restrictPrivateFile(dbPath);\n for (const suffix of SQLITE_SIDECAR_SUFFIXES) restrictPrivateFile(`${dbPath}${suffix}`);\n restrictExistingBackups(dbPath);\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { ensurePrivateDirectory, restrictPrivateFile } from \"../utils/private-storage.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport snapshotData from \"./data/snapshot.json\";\n\nexport interface ModelPricing {\n inputCostPerToken: number;\n outputCostPerToken: number;\n cacheCreateCostPerToken: number;\n cacheReadCostPerToken: number;\n reasoningCostPerToken: number;\n webSearchCostPerRequest: number;\n}\n\ntype SnapshotEntry = [number, number, number | null, number | null, number?, number?];\n\ninterface LiteLLMEntry {\n input_cost_per_token?: number;\n output_cost_per_token?: number;\n cache_creation_input_token_cost?: number;\n cache_read_input_token_cost?: number;\n output_reasoning_cost_per_token?: number;\n web_search_cost_per_request?: unknown;\n search_context_cost_per_query?: unknown;\n}\n\nconst LITELLM_URL =\n \"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json\";\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst WEB_SEARCH_COST = 0.01;\nconst REFRESH_TIMEOUT_MS = 10_000;\n\n/**\n * A published set of prices. Estimates read one generation for as long as they\n * need it: a refresh landing mid-scan used to mean the first sessions of a scan\n * were priced differently from the last, with no record of which applied.\n */\nexport interface PricingGeneration {\n id: number;\n pricing: Map<string, ModelPricing>;\n}\n\nlet published = createPricingGeneration(loadSnapshot());\n/** A completed refresh waiting for a safe point to become current. */\nlet pending: Map<string, ModelPricing> | null = null;\npublished = readDiskCache() ?? published;\n\nexport function normalizeModelKey(key: string): string {\n return key.trim().toLowerCase().replaceAll(\"_\", \"-\");\n}\n\nfunction createPricingGeneration(pricing: Map<string, ModelPricing>): PricingGeneration {\n const hash = createHash(\"sha256\");\n const entries = [...pricing.entries()].sort(([left], [right]) =>\n left < right ? -1 : left > right ? 1 : 0,\n );\n for (const [name, modelPricing] of entries) {\n hash.update(name);\n hash.update(\"\\0\");\n hash.update(JSON.stringify(modelPricing));\n hash.update(\"\\n\");\n }\n\n return {\n id: Number.parseInt(hash.digest(\"hex\").slice(0, 13), 16) || 1,\n pricing,\n };\n}\n\nfunction costNumber(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}\n\nfunction getCacheDir() {\n return join(homedir(), \".cache\", \"codesesh\");\n}\n\nfunction getCachePath() {\n return join(getCacheDir(), \"litellm-pricing.json\");\n}\n\nfunction loadSnapshot(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n const snapshot = snapshotData as unknown as Record<string, SnapshotEntry>;\n for (const [name, entry] of Object.entries(snapshot)) {\n const [input, output, cacheCreate, cacheRead, reasoning, webSearch] = entry;\n indexPricing(map, name, {\n inputCostPerToken: input,\n outputCostPerToken: output,\n cacheCreateCostPerToken: cacheCreate ?? input * 1.25,\n cacheReadCostPerToken: cacheRead ?? input * 0.1,\n reasoningCostPerToken: reasoning ?? output,\n webSearchCostPerRequest: webSearch ?? WEB_SEARCH_COST,\n });\n }\n return map;\n}\n\nfunction parseLiteLLMEntry(entry: LiteLLMEntry): ModelPricing | null {\n const input = entry.input_cost_per_token;\n const output = entry.output_cost_per_token;\n if (typeof input !== \"number\" || typeof output !== \"number\") return null;\n\n return {\n inputCostPerToken: input,\n outputCostPerToken: output,\n cacheCreateCostPerToken: entry.cache_creation_input_token_cost ?? input * 1.25,\n cacheReadCostPerToken: entry.cache_read_input_token_cost ?? input * 0.1,\n reasoningCostPerToken: entry.output_reasoning_cost_per_token ?? output,\n webSearchCostPerRequest: costNumber(\n entry.web_search_cost_per_request ?? entry.search_context_cost_per_query,\n WEB_SEARCH_COST,\n ),\n };\n}\n\nfunction normalizeCachedPricing(raw: Record<string, unknown>): ModelPricing | null {\n const input = costNumber(raw[\"inputCostPerToken\"], 0);\n const output = costNumber(raw[\"outputCostPerToken\"], 0);\n if (input <= 0 || output <= 0) return null;\n\n return {\n inputCostPerToken: input,\n outputCostPerToken: output,\n cacheCreateCostPerToken: costNumber(raw[\"cacheCreateCostPerToken\"], input * 1.25),\n cacheReadCostPerToken: costNumber(raw[\"cacheReadCostPerToken\"], input * 0.1),\n reasoningCostPerToken: costNumber(raw[\"reasoningCostPerToken\"], output),\n webSearchCostPerRequest: costNumber(raw[\"webSearchCostPerRequest\"], WEB_SEARCH_COST),\n };\n}\n\nfunction indexPricing(map: Map<string, ModelPricing>, name: string, pricing: ModelPricing) {\n const normalized = normalizeModelKey(name);\n map.set(normalized, pricing);\n\n const slashIndex = normalized.indexOf(\"/\");\n if (slashIndex >= 0) {\n const stripped = normalized.slice(slashIndex + 1);\n if (!map.has(stripped)) map.set(stripped, pricing);\n }\n}\n\nfunction parseLiteLLMData(data: Record<string, LiteLLMEntry>): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const [name, entry] of Object.entries(data)) {\n const pricing = parseLiteLLMEntry(entry);\n if (pricing) indexPricing(map, name, pricing);\n }\n return map;\n}\n\ninterface PricingCache {\n timestamp: number;\n data: Record<string, Record<string, unknown>>;\n}\n\nfunction readDiskCache(): PricingGeneration | null {\n const path = getCachePath();\n if (!existsSync(path)) return null;\n\n try {\n const cached = JSON.parse(readFileSync(path, \"utf-8\")) as PricingCache;\n if (!Number.isFinite(cached.timestamp)) return null;\n if (cached.data == null || typeof cached.data !== \"object\" || Array.isArray(cached.data)) {\n return null;\n }\n\n const next = loadSnapshot();\n for (const [name, rawPricing] of Object.entries(cached.data)) {\n const pricing = normalizeCachedPricing(rawPricing);\n if (!pricing) continue;\n indexPricing(next, name, pricing);\n }\n return createPricingGeneration(next);\n } catch {\n return null;\n }\n}\n\nexport function getPricingRegistry(): Map<string, ModelPricing> {\n return published.pricing;\n}\n\n/** The generation estimates are currently reading. */\nexport function getPricingGeneration(): PricingGeneration {\n return published;\n}\n\n/** Aligns an isolated worker with the generation selected by its parent. */\nexport function synchronizePricingGeneration(expectedId: number): void {\n if (!Number.isSafeInteger(expectedId) || expectedId < 1) {\n throw new Error(`Invalid pricing generation: ${expectedId}`);\n }\n if (published.id === expectedId) return;\n\n const cached = readDiskCache();\n if (cached?.id !== expectedId) {\n throw new Error(\n `Pricing generation ${expectedId} is unavailable (current ${published.id}, cached ${cached?.id ?? \"none\"})`,\n );\n }\n\n published = cached;\n getCoreDiagnostics()?.info?.(\"pricing.generation.synchronized\", {\n generation: published.id,\n models: published.pricing.size,\n });\n}\n\n/**\n * Makes a completed refresh current. Owners call this between scans, never\n * during one, so a scan cannot span two generations.\n */\nexport function publishPendingPricing(): boolean {\n if (!pending) return false;\n\n const next = createPricingGeneration(pending);\n if (!writeDiskCacheAtomically(getCachePath(), next)) return false;\n\n published = next;\n pending = null;\n getCoreDiagnostics()?.info?.(\"pricing.generation.published\", {\n generation: published.id,\n models: published.pricing.size,\n });\n return true;\n}\n\n/** Whether a refresh is waiting to be published. */\nexport function hasPendingPricing(): boolean {\n return pending !== null;\n}\n\nexport function hasBillablePricing(pricing: ModelPricing): boolean {\n return (\n pricing.inputCostPerToken > 0 ||\n pricing.outputCostPerToken > 0 ||\n pricing.cacheReadCostPerToken > 0 ||\n pricing.cacheCreateCostPerToken > 0\n );\n}\n\n/** Replaces the cache in one step, so an interrupted write cannot truncate it. */\nfunction writeDiskCacheAtomically(path: string, generation: PricingGeneration): boolean {\n const temporaryPath = `${path}.${process.pid}.tmp`;\n const payload = JSON.stringify({\n timestamp: Date.now(),\n data: Object.fromEntries(generation.pricing),\n });\n try {\n ensurePrivateDirectory(getCacheDir());\n writeFileSync(temporaryPath, payload);\n restrictPrivateFile(temporaryPath);\n renameSync(temporaryPath, path);\n return true;\n } catch (error) {\n rmSync(temporaryPath, { force: true });\n getCoreDiagnostics()?.warn(\"pricing.cache_write_failed\", {\n message: error instanceof Error ? error.message : String(error),\n });\n return false;\n }\n}\n\nexport interface RefreshPricingOptions {\n /** Abort the request when it outlives a startup's patience. */\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\n/**\n * Fetches prices into a pending generation. It does not become current until\n * {@link publishPendingPricing}, so an in-flight scan keeps the prices it\n * started with.\n */\nexport async function refreshPricingCache(options: RefreshPricingOptions = {}): Promise<boolean> {\n const path = getCachePath();\n if (existsSync(path)) {\n try {\n const cached = JSON.parse(readFileSync(path, \"utf-8\")) as { timestamp?: number };\n if (typeof cached.timestamp === \"number\" && Date.now() - cached.timestamp <= CACHE_TTL_MS) {\n return false;\n }\n } catch {\n // refresh malformed cache\n }\n }\n\n const timeout = AbortSignal.timeout(options.timeoutMs ?? REFRESH_TIMEOUT_MS);\n const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;\n\n getCoreDiagnostics()?.info?.(\"pricing.refresh.started\", { generation: published.id });\n try {\n const response = await fetch(LITELLM_URL, { signal });\n if (!response.ok) return false;\n const data = (await response.json()) as Record<string, LiteLLMEntry>;\n const remote = parseLiteLLMData(data);\n if (remote.size === 0) return false;\n\n const next = loadSnapshot();\n for (const [name, pricing] of remote.entries()) {\n next.set(name, pricing);\n }\n\n pending = next;\n getCoreDiagnostics()?.info?.(\"pricing.refresh.completed\", {\n generation: published.id,\n models: next.size,\n });\n return true;\n } catch (error) {\n getCoreDiagnostics()?.warn(\"pricing.refresh.failed\", {\n generation: published.id,\n aborted: signal.aborted,\n message: error instanceof Error ? error.message : String(error),\n });\n return false;\n }\n}\n","{\n \"claude-3-5-haiku\": [8e-7, 0.000004, 0.000001, 8e-8],\n \"claude-3-5-sonnet\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-3-7-sonnet\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-haiku-4-5\": [0.000001, 0.000005, 0.00000125, 1e-7],\n \"claude-sonnet-4\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-sonnet-4-5\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-sonnet-4-6\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-opus-4\": [0.000015, 0.000075, 0.00001875, 0.0000015],\n \"claude-opus-4-1\": [0.000015, 0.000075, 0.00001875, 0.0000015],\n \"claude-opus-4-5\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"claude-opus-4-6\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"claude-opus-4-7\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"anthropic/claude-sonnet-4-5\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"anthropic/claude-sonnet-4-6\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"anthropic/claude-opus-4-6\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"gpt-4.1\": [0.000002, 0.000008, null, 5e-7],\n \"gpt-4.1-mini\": [4e-7, 0.0000016, null, 1e-7],\n \"gpt-4.1-nano\": [1e-7, 4e-7, null, 2.5e-8],\n \"gpt-4o\": [0.0000025, 0.00001, null, 0.00000125],\n \"gpt-4o-mini\": [1.5e-7, 6e-7, null, 7.5e-8],\n \"gpt-5\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gpt-5.1\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gpt-5.1-codex\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gpt-5.1-codex-mini\": [2.5e-7, 0.000002, null, 2.5e-8],\n \"gpt-5.2\": [0.00000175, 0.000014, null, 1.75e-7],\n \"gpt-5.2-codex\": [0.00000175, 0.000014, null, 1.75e-7],\n \"gpt-5.3-codex\": [0.00000175, 0.000014, null, 1.75e-7],\n \"gpt-5.4\": [0.0000025, 0.000015, null, 2.5e-7],\n \"gpt-5.4-mini\": [7.5e-7, 0.0000045, null, 7.5e-8],\n \"gpt-5.4-nano\": [2e-7, 0.00000125, null, 2e-8],\n \"gpt-5.5\": [0.000005, 0.00003, null, 5e-7],\n \"gpt-5-mini\": [2.5e-7, 0.000002, null, 2.5e-8],\n \"gpt-5-nano\": [5e-8, 4e-7, null, 5e-9],\n \"moonshotai/kimi-k2-0905\": [6e-7, 0.0000025, null, null],\n \"moonshotai/kimi-k2-instruct\": [5.7e-7, 0.0000023, null, null],\n \"moonshotai/kimi-k2-thinking\": [6e-7, 0.0000025, null, null],\n \"deepseek-chat\": [2.8e-7, 4.2e-7, null, 2.8e-8],\n \"deepseek-reasoner\": [2.8e-7, 4.2e-7, null, 2.8e-8],\n \"qwen3-coder-480b-a35b-instruct\": [3e-7, 0.0000013, null, null],\n \"gemini-2.5-pro\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gemini-2.5-flash\": [3e-7, 0.0000025, null, 3e-8]\n}\n","{\n \"anthropic--claude-4.6-opus\": \"claude-opus-4-6\",\n \"anthropic--claude-4.6-sonnet\": \"claude-sonnet-4-6\",\n \"claude-4.6-sonnet\": \"claude-sonnet-4-6\",\n \"anthropic--claude-4.5-opus\": \"claude-opus-4-5\",\n \"anthropic--claude-4.5-sonnet\": \"claude-sonnet-4-5\",\n \"anthropic--claude-4.5-haiku\": \"claude-haiku-4-5\",\n \"claude-4.5-sonnet-thinking\": \"claude-sonnet-4-5\",\n \"claude-4-sonnet-thinking\": \"claude-sonnet-4-5\",\n \"claude-4-opus\": \"claude-opus-4-5\",\n \"cursor-auto\": \"claude-sonnet-4-5\",\n \"cursor-agent-auto\": \"claude-sonnet-4-5\",\n \"copilot-auto\": \"claude-sonnet-4-5\",\n \"copilot-openai-auto\": \"gpt-5.3-codex\",\n \"copilot-anthropic-auto\": \"claude-sonnet-4-5\",\n \"kimi-for-coding\": \"moonshotai/kimi-k2-0905\",\n \"kimi-k2.5\": \"moonshotai/kimi-k2-0905\",\n \"moonshot-cn/kimi-k2.5\": \"moonshotai/kimi-k2-0905\",\n \"gpt-5-codex\": \"gpt-5\",\n \"gpt-5.1-codex-high\": \"gpt-5.3-codex\",\n \"gpt-5.2-low\": \"gpt-5.2\"\n}\n","import aliasesData from \"./data/aliases.json\";\nimport {\n getPricingRegistry,\n hasBillablePricing,\n normalizeModelKey,\n type ModelPricing,\n} from \"./fetcher.js\";\n\nconst BUILTIN_ALIASES = Object.fromEntries(\n Object.entries(aliasesData as Record<string, string>).map(([key, value]) => [\n normalizeModelKey(key),\n normalizeModelKey(value),\n ]),\n);\n\nfunction stripVersion(model: string): string {\n return model.replace(/@.*$/, \"\").replace(/-\\d{8}$/, \"\");\n}\n\nfunction stripProviderPrefix(model: string): string {\n const parts = model.split(\"/\");\n return parts[parts.length - 1] ?? model;\n}\n\nfunction resolveAlias(model: string): string {\n return BUILTIN_ALIASES[model] ?? model;\n}\n\nfunction getCandidates(rawModel: string): string[] {\n const withPrefix = stripVersion(normalizeModelKey(rawModel));\n const stripped = stripProviderPrefix(withPrefix);\n const aliased = resolveAlias(stripped);\n const candidates = [\n withPrefix,\n resolveAlias(withPrefix),\n stripped,\n aliased,\n `anthropic/${stripped}`,\n `openai/${stripped}`,\n `openrouter/openai/${stripped}`,\n `openrouter/anthropic/${stripped}`,\n `moonshotai/${stripped}`,\n `novita/moonshotai/${stripped}`,\n ];\n\n return [...new Set(candidates.filter(Boolean))];\n}\n\nfunction lookupCandidate(model: string, registry: Map<string, ModelPricing>) {\n const direct = registry.get(model);\n if (direct && hasBillablePricing(direct)) return direct;\n\n const alias = resolveAlias(model);\n if (alias !== model) {\n const aliased = registry.get(alias);\n if (aliased && hasBillablePricing(aliased)) return aliased;\n }\n\n return null;\n}\n\nfunction fuzzyLookup(model: string, registry: Map<string, ModelPricing>) {\n let best: [string, ModelPricing] | null = null;\n for (const [key, pricing] of registry.entries()) {\n if (!hasBillablePricing(pricing)) continue;\n if (model.startsWith(`${key}-`) || model.startsWith(`${key}@`) || model === key) {\n if (!best || key.length > best[0].length) best = [key, pricing];\n }\n }\n return best?.[1] ?? null;\n}\n\nexport interface PricingResolver {\n resolve(rawModelName: string): ModelPricing | null;\n}\n\nexport const pricingResolver: PricingResolver = {\n resolve(rawModelName: string): ModelPricing | null {\n const registry = getPricingRegistry();\n const candidates = getCandidates(rawModelName);\n\n for (const candidate of candidates) {\n const pricing = lookupCandidate(candidate, registry);\n if (pricing) return pricing;\n }\n\n for (const candidate of candidates) {\n const pricing = fuzzyLookup(candidate, registry);\n if (pricing) return pricing;\n }\n\n return null;\n },\n};\n","import type { CostSource, Message, MessageTokens, SessionStats } from \"../types/index.js\";\nimport { pricingResolver } from \"./resolver.js\";\n\nexport interface CostUsage extends MessageTokens {\n web_search_requests?: number;\n}\n\nexport interface CostEstimate {\n cost: number;\n source: CostSource;\n}\n\nfunction positive(value: number | undefined): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : 0;\n}\n\nlet pricingMissCapture: Set<string> | null = null;\n\nexport const PRICING_CAPTURE_EPOCH = \"pricing-capture-v1\";\n\n/** Whether a model that previously produced a zero estimate is now billable. */\nexport function pricingBecameAvailable(unpricedModels: unknown): boolean {\n if (!Array.isArray(unpricedModels)) return false;\n return unpricedModels.some(\n (model) => typeof model === \"string\" && pricingResolver.resolve(model) !== null,\n );\n}\n\n/**\n * Records which models {@link estimateCostForTokens} failed to price during\n * `run`. Cached session heads carry these misses so they can be re-parsed once\n * pricing for those models becomes available.\n */\nexport function capturePricingMisses<T>(run: () => T): { result: T; unpricedModels: string[] } {\n const previous = pricingMissCapture;\n const capture = new Set<string>();\n pricingMissCapture = capture;\n try {\n return { result: run(), unpricedModels: [...capture] };\n } finally {\n pricingMissCapture = previous;\n }\n}\n\nexport function estimateCostForTokens(\n model: string | null | undefined,\n usage: CostUsage | undefined,\n): CostEstimate | null {\n if (!model || !usage) return null;\n\n const pricing = pricingResolver.resolve(model);\n if (!pricing) {\n pricingMissCapture?.add(model);\n return null;\n }\n\n const cacheRead = positive(usage.cache_read);\n const cacheCreate = positive(usage.cache_create);\n const input = Math.max(0, positive(usage.input) - cacheRead - cacheCreate);\n const output = positive(usage.output);\n const reasoning = positive(usage.reasoning);\n const webSearchRequests = positive(usage.web_search_requests);\n\n const cost =\n input * pricing.inputCostPerToken +\n output * pricing.outputCostPerToken +\n reasoning * pricing.reasoningCostPerToken +\n cacheRead * pricing.cacheReadCostPerToken +\n cacheCreate * pricing.cacheCreateCostPerToken +\n webSearchRequests * pricing.webSearchCostPerRequest;\n\n return cost > 0 ? { cost: Number(cost.toFixed(8)), source: \"estimated\" } : null;\n}\n\nexport function applyMessageCost(message: Message): void {\n if ((message.cost ?? 0) > 0) {\n message.cost_source = \"recorded\";\n return;\n }\n\n const estimate = estimateCostForTokens(message.model, message.tokens);\n if (!estimate) return;\n\n message.cost = estimate.cost;\n message.cost_source = estimate.source;\n}\n\nexport function applyMessageCosts(messages: Message[]): { totalCost: number; source?: CostSource } {\n let totalCost = 0;\n let source: CostSource | undefined;\n\n for (const message of messages) {\n applyMessageCost(message);\n const cost = message.cost ?? 0;\n if (cost <= 0) continue;\n\n totalCost += cost;\n if (message.cost_source === \"estimated\") source = \"estimated\";\n else if (!source) source = \"recorded\";\n }\n\n return { totalCost: Number(totalCost.toFixed(8)), source };\n}\n\nexport function withEstimatedSessionCost<T extends SessionStats>(\n stats: T,\n model: string | null | undefined,\n): T {\n if (stats.total_cost > 0) {\n return { ...stats, cost_source: stats.cost_source ?? \"recorded\" };\n }\n\n const estimate = estimateCostForTokens(model, {\n input: stats.total_input_tokens,\n output: stats.total_output_tokens,\n cache_read: stats.total_cache_read_tokens,\n cache_create: stats.total_cache_create_tokens,\n });\n if (!estimate) return stats;\n\n return { ...stats, total_cost: estimate.cost, cost_source: estimate.source };\n}\n","import { statSync } from \"node:fs\";\nimport type { SessionSnapshotCompleteness } from \"../discovery/cache/sessions.js\";\nimport { PRICING_CAPTURE_EPOCH, pricingBecameAvailable } from \"../pricing/cost.js\";\nimport type { SessionHead } from \"../types/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport type {\n AgentScanOptions,\n CachedMetaLookup,\n SessionCacheMeta,\n SessionSourceAbsenceOutcome,\n SessionSourceDiff,\n SessionSourceFailure,\n SessionSourceOutcome,\n SessionSourceRef,\n} from \"./base.js\";\n\nexport interface SessionSourceSynchronizationAdapter {\n readonly name: string;\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[];\n scanSessionSourceOutcome(\n source: SessionSourceRef,\n options?: AgentScanOptions,\n ): SessionSourceOutcome;\n expandChangedSessionIds(changedIds: string[], refs?: SessionSourceRef[]): string[];\n filterCachedSessions(sessions: SessionHead[]): SessionHead[];\n getSessionMetaMap(): Map<string, SessionCacheMeta>;\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void;\n}\n\nexport interface SessionSourceSynchronizationBaseline {\n sessions: SessionHead[];\n meta: CachedMetaLookup;\n}\n\nexport type SessionSourceSynchronizationRequest =\n | { kind: \"inspect\"; scanOptions?: AgentScanOptions }\n | { kind: \"refresh\"; scanOptions?: AgentScanOptions }\n | { kind: \"reload\"; scanOptions?: AgentScanOptions }\n | {\n kind: \"known-changes\";\n changedIds: string[];\n refs?: SessionSourceRef[];\n scanOptions?: AgentScanOptions;\n };\n\nexport interface SessionSourceSynchronizationOutcome {\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n sources: SessionSourceRef[];\n sourceOutcomes: SessionSourceOutcome[];\n detectedSessionIds: string[];\n changedSessionIds: string[];\n explicitRemovedSessionIds: string[];\n finalizeSessionIds: string[];\n sourceFailures: SessionSourceFailure[];\n completeness: SessionSnapshotCompleteness;\n sourceCount: number;\n removedSourceCount: number;\n}\n\nfunction readCachedMeta(meta: CachedMetaLookup, sessionId: string): SessionCacheMeta | undefined {\n if (meta instanceof Map) return meta.get(sessionId);\n return (meta as Record<string, SessionCacheMeta>)[sessionId];\n}\n\n/** Parser/index revisions live inside the fingerprint, so comparison must be exact. */\nfunction fingerprintMatches(ref: SessionSourceRef, cached: SessionCacheMeta | undefined): boolean {\n return (\n typeof cached?.sourceFingerprint === \"string\" && cached.sourceFingerprint === ref.fingerprint\n );\n}\n\n/** Unknown or out-of-window mtime cannot prove deletion; retain last-known-good facts. */\nfunction wasEnumeratedThisPass(\n cached: SessionCacheMeta | undefined,\n options: AgentScanOptions | undefined,\n): boolean {\n if (options?.from == null && options?.to == null) return true;\n const mtimeMs = cached?.sourceMtimeMs;\n return typeof mtimeMs === \"number\" && matchesScanWindow(mtimeMs, options);\n}\n\nexport function matchesScanWindow(activityTime: number, options?: AgentScanOptions): boolean {\n if (options?.from != null && activityTime < options.from) return false;\n if (options?.to != null && activityTime > options.to) return false;\n return true;\n}\n\nexport function isMissingSessionSourceError(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null || !(\"code\" in error)) return false;\n const code = (error as { code?: unknown }).code;\n return code === \"ENOENT\" || code === \"ENOTDIR\";\n}\n\nconst FAILURE_MESSAGE_LIMIT = 500;\n\nfunction failureClass(error: unknown): string {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n const code = (error as { code?: unknown }).code;\n if (typeof code === \"string\" && code) return code;\n }\n if (error instanceof Error && error.name) return error.name;\n return typeof error;\n}\n\nfunction failureMessage(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n return message.slice(0, FAILURE_MESSAGE_LIMIT);\n}\n\nexport function describeFailure(error: unknown) {\n return {\n errorClass: failureClass(error),\n message: failureMessage(error),\n };\n}\n\nexport function createSessionSourceFailure(\n source: Pick<SessionSourceRef, \"sessionId\" | \"sourcePath\">,\n stage: SessionSourceFailure[\"stage\"],\n error: unknown,\n): SessionSourceFailure {\n return {\n sessionId: source.sessionId,\n sourcePath: source.sourcePath,\n stage,\n ...describeFailure(error),\n };\n}\n\nexport function reportSessionSourceOutcome(agentName: string, outcome: SessionSourceOutcome): void {\n if (outcome.status === \"parsed\") return;\n if (outcome.status === \"filtered\") {\n getCoreDiagnostics()?.info?.(\"agent.session_source_outcome\", {\n agent: agentName,\n session_id: outcome.source.sessionId,\n source_path: outcome.source.sourcePath,\n outcome: outcome.status,\n reason: outcome.reason,\n });\n return;\n }\n if (outcome.status === \"missing\") {\n getCoreDiagnostics()?.info?.(\"agent.session_source_outcome\", {\n agent: agentName,\n session_id: outcome.source.sessionId,\n source_path: outcome.source.sourcePath,\n outcome: outcome.status,\n });\n return;\n }\n getCoreDiagnostics()?.warn(\"agent.session_source_outcome\", {\n agent: agentName,\n session_id: outcome.failure.sessionId,\n source_path: outcome.failure.sourcePath,\n outcome: outcome.status,\n stage: outcome.failure.stage,\n error_class: outcome.failure.errorClass,\n message: outcome.failure.message,\n });\n}\n\nexport function diffSessionSources(\n refs: SessionSourceRef[],\n cachedSessions: SessionHead[],\n cachedMeta: CachedMetaLookup,\n options?: AgentScanOptions,\n): SessionSourceDiff {\n const cachedIds = new Set(cachedSessions.map((session) => session.id));\n const enumeratedIds = new Set<string>();\n const changedIds: string[] = [];\n\n for (const ref of refs) {\n enumeratedIds.add(ref.sessionId);\n const meta = readCachedMeta(cachedMeta, ref.sessionId);\n const unchanged =\n cachedIds.has(ref.sessionId) &&\n meta?.sourcePath === ref.sourcePath &&\n fingerprintMatches(ref, meta) &&\n meta.pricingCaptureEpoch === PRICING_CAPTURE_EPOCH &&\n !pricingBecameAvailable(meta.unpricedModels);\n if (!unchanged) changedIds.push(ref.sessionId);\n }\n\n const removedIds: string[] = [];\n const failedIds: string[] = [];\n const sourceOutcomes: SessionSourceAbsenceOutcome[] = [];\n for (const session of cachedSessions) {\n if (enumeratedIds.has(session.id)) continue;\n const meta = readCachedMeta(cachedMeta, session.id);\n if (!wasEnumeratedThisPass(meta, options)) continue;\n const source = {\n sessionId: session.id,\n sourcePath: typeof meta?.sourcePath === \"string\" ? meta.sourcePath : \"\",\n fingerprint: typeof meta?.sourceFingerprint === \"string\" ? meta.sourceFingerprint : \"\",\n };\n if (!source.sourcePath) {\n // No path can ever be re-checked, so keeping this entry would fail on\n // every future pass; a complete enumeration finding neither file nor\n // path proves the entry is unrecoverable.\n removedIds.push(session.id);\n sourceOutcomes.push({ status: \"missing\", source });\n continue;\n }\n try {\n statSync(source.sourcePath);\n failedIds.push(session.id);\n sourceOutcomes.push({\n status: \"failed\",\n failure: createSessionSourceFailure(\n source,\n \"enumeration\",\n new Error(\"cached source was not enumerated\"),\n ),\n });\n } catch (error) {\n if (!isMissingSessionSourceError(error)) {\n failedIds.push(session.id);\n sourceOutcomes.push({\n status: \"failed\",\n failure: createSessionSourceFailure(source, \"enumeration\", error),\n });\n continue;\n }\n removedIds.push(session.id);\n sourceOutcomes.push({ status: \"missing\", source });\n }\n }\n\n return { changedIds, removedIds, failedIds, sourceOutcomes };\n}\n\nfunction cloneMeta(meta: CachedMetaLookup): Map<string, SessionCacheMeta> {\n return meta instanceof Map ? new Map(meta) : new Map(Object.entries(meta));\n}\n\nfunction unique(values: Iterable<string>): string[] {\n return [...new Set(values)];\n}\n\nfunction sourceForMissingId(\n sessionId: string,\n meta: Map<string, SessionCacheMeta>,\n): SessionSourceRef {\n const cached = meta.get(sessionId);\n return {\n sessionId,\n sourcePath: typeof cached?.sourcePath === \"string\" ? cached.sourcePath : \"\",\n fingerprint: typeof cached?.sourceFingerprint === \"string\" ? cached.sourceFingerprint : \"\",\n };\n}\n\nfunction buildMeta(\n sessions: SessionHead[],\n metaMap: Map<string, SessionCacheMeta>,\n): Record<string, SessionCacheMeta> {\n const meta: Record<string, SessionCacheMeta> = {};\n for (const session of sessions) {\n const value = metaMap.get(session.id);\n if (value) meta[session.id] = value;\n }\n return meta;\n}\n\nfunction isWindowed(options: AgentScanOptions | undefined): boolean {\n return options?.from != null || options?.to != null;\n}\n\nexport function synchronizeSessionSources(\n adapter: SessionSourceSynchronizationAdapter,\n baseline: SessionSourceSynchronizationBaseline,\n request: SessionSourceSynchronizationRequest,\n): SessionSourceSynchronizationOutcome {\n adapter.setSessionMetaMap(cloneMeta(baseline.meta));\n const metaMap = adapter.getSessionMetaMap();\n const baselineMeta = new Map(metaMap);\n const baselineSessions = adapter.filterCachedSessions(baseline.sessions);\n const visibleBaselineIds = new Set(baselineSessions.map((session) => session.id));\n const filteredBaselineIds = baseline.sessions\n .map((session) => session.id)\n .filter((sessionId) => !visibleBaselineIds.has(sessionId));\n const filteredBaselineOutcomes: SessionSourceOutcome[] = filteredBaselineIds.map((sessionId) => ({\n status: \"filtered\",\n source: sourceForMissingId(sessionId, baselineMeta),\n reason: \"cached session rejected by adapter\",\n }));\n for (const sessionId of filteredBaselineIds) metaMap.delete(sessionId);\n const scanOptions = request.scanOptions;\n const sources =\n request.kind === \"known-changes\" && request.refs\n ? request.refs\n : adapter.listSessionSources(scanOptions);\n const sourceById = new Map(sources.map((source) => [source.sessionId, source]));\n const diff =\n request.kind === \"known-changes\"\n ? { changedIds: request.changedIds, removedIds: [], failedIds: [], sourceOutcomes: [] }\n : diffSessionSources(sources, baselineSessions, metaMap, scanOptions);\n const detectedSessionIds = unique([\n ...filteredBaselineIds,\n ...diff.changedIds,\n ...diff.removedIds,\n ]);\n const sourceOutcomes: SessionSourceOutcome[] = [\n ...filteredBaselineOutcomes,\n ...diff.sourceOutcomes,\n ];\n const sourceFailures = sourceOutcomes.flatMap((outcome) =>\n outcome.status === \"failed\" ? [outcome.failure] : [],\n );\n for (const outcome of sourceOutcomes) reportSessionSourceOutcome(adapter.name, outcome);\n\n if (request.kind === \"inspect\") {\n return {\n sessions: baselineSessions,\n meta: buildMeta(baselineSessions, metaMap),\n sources,\n sourceOutcomes,\n detectedSessionIds,\n changedSessionIds: [],\n explicitRemovedSessionIds: unique([...filteredBaselineIds, ...diff.removedIds]),\n finalizeSessionIds: [],\n sourceFailures,\n completeness: isWindowed(scanOptions) || sourceFailures.length > 0 ? \"partial\" : \"complete\",\n sourceCount: sources.length,\n removedSourceCount: diff.removedIds.length,\n };\n }\n\n const sessionsById = new Map(baselineSessions.map((session) => [session.id, session]));\n const changedSessionIds = new Set(filteredBaselineIds);\n const explicitRemovedSessionIds = new Set(filteredBaselineIds);\n for (const outcome of diff.sourceOutcomes) {\n if (outcome.status !== \"missing\") continue;\n sessionsById.delete(outcome.source.sessionId);\n metaMap.delete(outcome.source.sessionId);\n changedSessionIds.add(outcome.source.sessionId);\n explicitRemovedSessionIds.add(outcome.source.sessionId);\n }\n\n const requestedIds =\n request.kind === \"reload\"\n ? sources.map((source) => source.sessionId)\n : request.kind === \"known-changes\"\n ? request.changedIds\n : detectedSessionIds;\n const synchronizationIds = unique(adapter.expandChangedSessionIds(requestedIds, sources));\n if (synchronizationIds.length > 0 || request.kind === \"reload\") {\n scanOptions?.onProgress?.({\n total: synchronizationIds.length,\n processed: 0,\n sessions: sessionsById.size,\n });\n }\n\n synchronizationIds.forEach((sessionId, index) => {\n const source = sourceById.get(sessionId);\n if (!source) {\n if (!changedSessionIds.has(sessionId)) {\n const missing: SessionSourceOutcome = {\n status: \"missing\",\n source: sourceForMissingId(sessionId, metaMap),\n };\n sourceOutcomes.push(missing);\n reportSessionSourceOutcome(adapter.name, missing);\n sessionsById.delete(sessionId);\n metaMap.delete(sessionId);\n changedSessionIds.add(sessionId);\n explicitRemovedSessionIds.add(sessionId);\n }\n } else {\n const outcome = adapter.scanSessionSourceOutcome(source, scanOptions);\n sourceOutcomes.push(outcome);\n if (outcome.status === \"parsed\") {\n if (outcome.session.id !== source.sessionId) sessionsById.delete(source.sessionId);\n sessionsById.set(outcome.session.id, outcome.session);\n if (outcome.session.id !== source.sessionId) metaMap.delete(source.sessionId);\n if (outcome.session.id === source.sessionId)\n explicitRemovedSessionIds.delete(source.sessionId);\n changedSessionIds.add(source.sessionId);\n } else if (outcome.status === \"filtered\" || outcome.status === \"missing\") {\n sessionsById.delete(source.sessionId);\n metaMap.delete(source.sessionId);\n changedSessionIds.add(source.sessionId);\n explicitRemovedSessionIds.add(source.sessionId);\n reportSessionSourceOutcome(adapter.name, outcome);\n } else {\n // \"last-known-good data retained\" is only a failure when data exists;\n // a source that never produced a session (empty or malformed file) is\n // logged and skipped so it cannot poison every future pass.\n if (visibleBaselineIds.has(source.sessionId)) sourceFailures.push(outcome.failure);\n reportSessionSourceOutcome(adapter.name, outcome);\n }\n }\n scanOptions?.onProgress?.({\n total: synchronizationIds.length,\n processed: index + 1,\n sessions: sessionsById.size,\n });\n });\n\n const failedIds = new Set(sourceFailures.map((failure) => failure.sessionId));\n const finalizeSessionIds = (\n request.kind === \"reload\" || (request.kind === \"refresh\" && !isWindowed(scanOptions))\n ? sources.map((source) => source.sessionId)\n : [...changedSessionIds]\n ).filter((sessionId) => !failedIds.has(sessionId));\n const sessions = [...sessionsById.values()];\n\n return {\n sessions,\n meta: buildMeta(sessions, metaMap),\n sources,\n sourceOutcomes,\n detectedSessionIds,\n changedSessionIds: [...changedSessionIds],\n explicitRemovedSessionIds: [...explicitRemovedSessionIds],\n finalizeSessionIds,\n sourceFailures,\n completeness: isWindowed(scanOptions) || sourceFailures.length > 0 ? \"partial\" : \"complete\",\n sourceCount: sources.length,\n removedSourceCount: diff.removedIds.length,\n };\n}\n","import { readdirSync, statSync, type Dirent, type Stats } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { formatSessionReference } from \"../contract/session-reference.js\";\nimport type { SessionHead, SessionDetail, ParseSessionResult } from \"../types/index.js\";\nimport {\n capturePricingMisses,\n PRICING_CAPTURE_EPOCH,\n pricingBecameAvailable,\n} from \"../pricing/cost.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport {\n createSessionSourceFailure,\n describeFailure,\n isMissingSessionSourceError,\n matchesScanWindow,\n synchronizeSessionSources as runSessionSourceSynchronization,\n} from \"./session-source-synchronization.js\";\nimport type {\n SessionSourceSynchronizationBaseline,\n SessionSourceSynchronizationOutcome,\n SessionSourceSynchronizationRequest,\n} from \"./session-source-synchronization.js\";\n\nexport {\n createSessionSourceFailure,\n diffSessionSources,\n matchesScanWindow,\n reportSessionSourceOutcome,\n synchronizeSessionSources,\n} from \"./session-source-synchronization.js\";\nexport type {\n SessionSourceSynchronizationAdapter,\n SessionSourceSynchronizationBaseline,\n SessionSourceSynchronizationOutcome,\n SessionSourceSynchronizationRequest,\n} from \"./session-source-synchronization.js\";\n\nexport type { ParseSessionResult };\n\nexport function parsedSession<T>(session: T): ParseSessionResult<T> {\n return { status: \"parsed\", data: session };\n}\n\nexport function skippedSession<T>(reason: string): ParseSessionResult<T> {\n return { status: \"skipped\", reason };\n}\n\nexport function filteredSession<T>(reason: string): ParseSessionResult<T> {\n return { status: \"filtered\", reason };\n}\n\nexport function getParsedSession<T>(result: ParseSessionResult<T>): T | null {\n return result.status === \"parsed\" ? result.data : null;\n}\n\nexport interface SessionCacheMeta {\n id: string;\n sourcePath: string;\n /** Models the head parse could not price; their arrival invalidates the cache. */\n unpricedModels?: string[];\n /** Pricing-miss capture semantics used when this head was parsed. */\n pricingCaptureEpoch?: string;\n [key: string]: unknown;\n}\n\nexport interface AgentScanOptions {\n from?: number;\n to?: number;\n fast?: boolean;\n includeRelatedSessions?: boolean;\n onProgress?: (progress: AgentScanProgress) => void;\n}\n\nexport interface AgentScanProgress {\n phase?: \"scanning\" | \"finalizing\";\n total?: number;\n processed?: number;\n sessions?: number;\n}\n\nexport interface FileWalkOptions {\n recursive?: boolean;\n scanWindow?: Pick<AgentScanOptions, \"from\" | \"to\">;\n}\n\nexport interface ChangeCheckFailure {\n sourcePath: string;\n errorClass: string;\n message: string;\n}\n\ninterface SuccessfulChangeCheck {\n status?: \"checked\";\n /** 是否有变更 */\n hasChanges: boolean;\n /** 可精确定位时的变更会话 ID;省略表示只能确认数据源发生过变化 */\n changedIds?: string[];\n /** 检测时间戳 */\n timestamp: number;\n /** 检测过程中已枚举的会话源(可选),供 incrementalScan 复用以避免二次枚举 */\n refs?: SessionSourceRef[];\n sourceFailures?: SessionSourceFailure[];\n failure?: never;\n}\n\ninterface FailedChangeCheck {\n status: \"failed\";\n hasChanges: false;\n timestamp: number;\n failure: ChangeCheckFailure;\n changedIds?: never;\n refs?: never;\n sourceFailures?: never;\n}\n\n/** 变更检测结果 */\nexport type ChangeCheckResult = SuccessfulChangeCheck | FailedChangeCheck;\n\nexport interface SessionSourceRef {\n sessionId: string;\n sourcePath: string;\n fingerprint: string;\n}\n\nexport interface SessionSourceFailure {\n sessionId: string;\n sourcePath: string;\n stage: \"enumeration\" | \"parsing\";\n errorClass: string;\n message: string;\n}\n\nexport interface AgentScanFailure {\n agentName: string;\n stage: string;\n sourcePath?: string;\n errorClass: string;\n message: string;\n}\n\nexport type SessionSourceOutcome =\n | { status: \"parsed\"; session: SessionHead; source: SessionSourceRef }\n | { status: \"filtered\"; reason: string; source: SessionSourceRef }\n | { status: \"missing\"; source: SessionSourceRef }\n | { status: \"failed\"; failure: SessionSourceFailure };\n\nexport type SessionSourceAbsenceOutcome = Extract<\n SessionSourceOutcome,\n { status: \"missing\" | \"failed\" }\n>;\n\nexport interface SessionSourceScanBatch {\n sources: SessionSourceRef[];\n outcomes: SessionSourceOutcome[];\n sessions: SessionHead[];\n}\n\nexport interface SessionSourceFile {\n file: string;\n stat: Stats;\n}\n\nexport interface FileSessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n sourceFingerprint: string;\n sourceMtimeMs: number;\n directory: string;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface SessionWatchTarget {\n /** Session source path whose related changes should trigger a refresh. */\n path: string;\n /** Stable ancestor to watch when the source path can be created or replaced. */\n root?: string;\n}\n\n/** `supported` may have no targets when the provider has no location in the current environment. */\nexport type SessionWatchPlan =\n | { status: \"supported\"; targets: SessionWatchTarget[] }\n | { status: \"unsupported\"; reason: string }\n | { status: \"not-needed\"; reason: string };\n\n/** What a source enumeration says needs re-parsing and what disappeared. */\nexport interface SessionSourceDiff {\n changedIds: string[];\n removedIds: string[];\n failedIds: string[];\n sourceOutcomes: SessionSourceAbsenceOutcome[];\n}\n\n/**\n * Cached meta reaches this comparison as a live Map on the main thread and as a\n * plain object over the worker's structured-clone boundary.\n */\nexport type CachedMetaLookup =\n | ReadonlyMap<string, SessionCacheMeta>\n | Record<string, SessionCacheMeta>;\n\nexport function createAgentScanFailure(\n agentName: string,\n stage: string,\n error: unknown,\n sourcePath?: string,\n): AgentScanFailure {\n const scanError = error instanceof SessionScanError ? error : null;\n const cause = scanError?.cause ?? error;\n return {\n agentName: scanError?.agentName ?? agentName,\n stage: scanError?.stage ?? stage,\n ...((scanError?.sourcePath ?? sourcePath)\n ? { sourcePath: scanError?.sourcePath ?? sourcePath }\n : {}),\n ...describeFailure(cause),\n };\n}\n\nexport function reportAgentScanFailure(failure: AgentScanFailure, baselineRetained: boolean): void {\n getCoreDiagnostics()?.warn(\"agent.scan_failed\", {\n agent: failure.agentName,\n stage: failure.stage,\n source_path: failure.sourcePath,\n error_class: failure.errorClass,\n message: failure.message,\n baseline_retained: baselineRetained,\n });\n}\n\nexport abstract class BaseAgent {\n abstract readonly name: string;\n abstract readonly displayName: string;\n\n /** Check if this agent has data available on the local filesystem. */\n abstract isAvailable(): boolean;\n\n /** Scan for available sessions, returning lightweight metadata. */\n abstract scan(options?: AgentScanOptions): SessionHead[];\n\n /** Load full session data including all messages. */\n abstract getSessionData(sessionId: string): SessionDetail;\n\n /** Describe how changes to this agent's session sources can be observed. */\n abstract getSessionWatchPlan(): SessionWatchPlan;\n\n /**\n * 检查是否有变更(用于智能刷新)\n * @param sinceTimestamp 上次缓存时间戳\n * @param cachedSessions 缓存的会话列表\n * @returns 变更检测结果\n */\n abstract checkForChanges(\n sinceTimestamp: number,\n cachedSessions: SessionHead[],\n ): Promise<ChangeCheckResult> | ChangeCheckResult;\n\n /**\n * Commit the observation made by the latest checkForChanges. Called by the\n * scan orchestrator only after the scan consuming that check succeeded, so\n * a failed scan leaves the baseline behind and the next check re-detects\n * the same change instead of silently skipping it.\n */\n commitChangeCheck(): void {}\n\n /** Wrap an enumeration/database read so failures follow the error taxonomy. */\n protected scanStep<T>(stage: string, sourcePath: string, read: () => T): T {\n try {\n return read();\n } catch (error) {\n if (error instanceof SessionScanError) throw error;\n throw new SessionScanError(this.name, stage, { cause: error, sourcePath });\n }\n }\n\n /**\n * 增量扫描(仅扫描变更的会话)\n * @param cachedSessions 缓存的会话列表\n * @param changedIds 变更的会话 ID 列表\n * @param scanOptions 扫描窗口与解析选项\n * @returns 更新后的会话列表\n */\n abstract incrementalScan(\n cachedSessions: SessionHead[],\n changedIds: string[],\n refs?: SessionSourceRef[],\n scanOptions?: AgentScanOptions,\n ): Promise<SessionHead[]> | SessionHead[];\n\n filterCachedSessions(sessions: SessionHead[]): SessionHead[] {\n return sessions;\n }\n\n /** Get session metadata for caching. */\n abstract getSessionMetaMap(): Map<string, SessionCacheMeta>;\n\n /** Restore session metadata from cache. */\n abstract setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void;\n\n getUri(sessionId: string): string {\n return `${this.name}://${sessionId}`;\n }\n\n protected sessionSlug(sessionId: string): string {\n return formatSessionReference({ agentName: this.name, sessionId });\n }\n}\n\n/**\n * 文件型 Agent 基类:每个会话对应磁盘上一个独立文件/目录。\n *\n * 子类只需实现两个必需的文件级原语:\n * - listSessionSources(): 枚举所有源 + 计算指纹\n * - scanSessionSource(): 解析单个源(同时写入 metaMap)\n *\n * scanSessionSourceResult() 是可选的富结果扩展点:默认将 scanSessionSource()\n * 的会话或 null 转成 parsed/skipped 结果;需要保留 filtered 等结果时可覆写,\n * 例如 KimiAgent。\n *\n * 变更检测 / 增量扫描 / metaMap 管理由本基类统一提供:\n * checkForChanges 用 listSessionSources 的指纹与缓存 metaMap 比对,\n * incrementalScan 对变更集合调用 scanSessionSource 重解析。\n * 两原语在各子类中复用同一个 sourceFingerprint 计算,故指纹精确比对即等价于变更检测。\n */\nexport abstract class FileSystemSessionSource<\n TMeta extends SessionCacheMeta = SessionCacheMeta,\n> extends BaseAgent {\n protected sessionMetaMap = new Map<string, TMeta>();\n private sourceFileStats = new Map<string, Stats>();\n\n /** 枚举所有会话源及其指纹。传入 options 时按 mtime 限定扫描窗口。 */\n abstract listSessionSources(options?: AgentScanOptions): SessionSourceRef[];\n\n /** 解析单个源并写入 metaMap,返回会话 head(解析失败/不可见返回 null)。 */\n abstract scanSessionSource(sourcePath: string, options?: AgentScanOptions): SessionHead | null;\n\n protected scanSessionSourceResult(\n source: SessionSourceRef,\n options?: AgentScanOptions,\n ): ParseSessionResult<SessionHead> {\n const session = this.scanSessionSource(source.sourcePath, options);\n return session ? parsedSession(session) : skippedSession(\"source produced no session\");\n }\n\n scanSessionSourceOutcome(\n source: SessionSourceRef,\n options?: AgentScanOptions,\n ): SessionSourceOutcome {\n const previousMeta = this.sessionMetaMap.get(source.sessionId);\n let result: ParseSessionResult<SessionHead>;\n let unpricedModels: string[] = [];\n try {\n ({ result, unpricedModels } = capturePricingMisses(() =>\n this.scanSessionSourceResult(source, options),\n ));\n } catch (error) {\n if (previousMeta) this.sessionMetaMap.set(source.sessionId, previousMeta);\n else this.sessionMetaMap.delete(source.sessionId);\n if (isMissingSessionSourceError(error)) return { status: \"missing\", source };\n return {\n status: \"failed\",\n failure: createSessionSourceFailure(source, \"parsing\", error),\n };\n }\n if (result.status === \"parsed\") {\n const meta = this.sessionMetaMap.get(result.data.id);\n if (meta) {\n meta.pricingCaptureEpoch = PRICING_CAPTURE_EPOCH;\n if (unpricedModels.length > 0) meta.unpricedModels = unpricedModels;\n else delete meta.unpricedModels;\n }\n return { status: \"parsed\", source, session: result.data };\n }\n if (result.status === \"filtered\") {\n return { status: \"filtered\", source, reason: result.reason ?? \"filtered by agent\" };\n }\n if (previousMeta) this.sessionMetaMap.set(source.sessionId, previousMeta);\n else this.sessionMetaMap.delete(source.sessionId);\n return {\n status: \"failed\",\n failure: createSessionSourceFailure(\n source,\n \"parsing\",\n new Error(result.reason ?? \"source parse skipped\"),\n ),\n };\n }\n\n /**\n * 变更集合扩展:当某些会话变更会影响其他会话的派生数据时\n * (如 subagent 文件变更需要父会话重新聚合 token 统计),\n * 子类返回需要一并重解析的会话 ID 集合。默认无关联,原样返回。\n */\n expandChangedSessionIds(changedIds: string[], _refs?: SessionSourceRef[]): string[] {\n return changedIds;\n }\n\n synchronizeSessionSources(\n baseline: SessionSourceSynchronizationBaseline,\n request: SessionSourceSynchronizationRequest,\n ): SessionSourceSynchronizationOutcome {\n return runSessionSourceSynchronization(this, baseline, request);\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n return this.scanSessionSources(options).sessions;\n }\n\n scanSessionSources(options?: AgentScanOptions): SessionSourceScanBatch {\n const outcome = this.synchronizeSessionSources(\n { sessions: [], meta: this.sessionMetaMap },\n { kind: \"reload\", scanOptions: options },\n );\n return {\n sources: outcome.sources,\n outcomes: outcome.sourceOutcomes,\n sessions: outcome.sessions,\n };\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap as Map<string, SessionCacheMeta>;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta as Map<string, TMeta>;\n }\n\n protected walkFiles(\n roots: string | readonly string[],\n isSessionFile: (entry: Dirent) => boolean,\n options: FileWalkOptions = {},\n ): SessionSourceFile[] {\n const files: SessionSourceFile[] = [];\n this.sourceFileStats.clear();\n\n const walk = (directory: string): void => {\n const entries = this.readSessionSourceDirectory(directory);\n\n for (const entry of entries) {\n const filePath = join(directory, entry.name);\n if (entry.isDirectory()) {\n if (options.recursive !== false) walk(filePath);\n continue;\n }\n if (!entry.isFile() || !isSessionFile(entry)) continue;\n\n let stat: Stats;\n try {\n stat = statSync(filePath);\n } catch (error) {\n if (isMissingSessionSourceError(error)) continue;\n throw new SessionScanError(this.name, \"reading session source metadata\", {\n cause: error,\n sourcePath: filePath,\n });\n }\n if (!matchesScanWindow(stat.mtimeMs, options.scanWindow)) continue;\n\n files.push({ file: filePath, stat });\n this.sourceFileStats.set(filePath, stat);\n }\n };\n\n for (const root of typeof roots === \"string\" ? [roots] : roots) walk(root);\n return files;\n }\n\n protected readSessionSourceDirectory(directory: string): Dirent[] {\n try {\n return readdirSync(directory, { withFileTypes: true });\n } catch (error) {\n throw new SessionScanError(this.name, \"enumerating session sources\", {\n cause: error,\n sourcePath: directory,\n });\n }\n }\n\n protected sessionSourceFile(sourcePath: string): SessionSourceFile {\n return {\n file: sourcePath,\n stat: this.sourceFileStats.get(sourcePath) ?? statSync(sourcePath),\n };\n }\n\n protected readFileMtimeMs(filePath: string | null): number | null {\n if (!filePath) return null;\n try {\n return statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n }\n\n checkForChanges(_sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const outcome = this.synchronizeSessionSources(\n { sessions: cachedSessions, meta: this.sessionMetaMap },\n { kind: \"inspect\" },\n );\n\n return {\n hasChanges: outcome.detectedSessionIds.length > 0 || outcome.sourceFailures.length > 0,\n changedIds: outcome.detectedSessionIds,\n timestamp: Date.now(),\n refs: outcome.sources,\n sourceFailures: outcome.sourceFailures,\n };\n }\n\n incrementalScan(\n cachedSessions: SessionHead[],\n changedIds: string[],\n refs?: SessionSourceRef[],\n _scanOptions?: AgentScanOptions,\n ): SessionHead[] {\n return this.synchronizeSessionSources(\n { sessions: cachedSessions, meta: this.sessionMetaMap },\n { kind: \"known-changes\", changedIds, refs },\n ).sessions;\n }\n}\n\n/** Shared scan template for agents whose session source is a single stat-able file. */\nexport abstract class SingleFileSessionSource<\n TMeta extends FileSessionMeta = FileSessionMeta,\n> extends FileSystemSessionSource<TMeta> {\n private readonly pendingParseResults = new Map<\n string,\n ParseSessionResult<SessionHead> | undefined\n >();\n\n protected abstract parseFileSessionHead(\n sourcePath: string,\n options?: AgentScanOptions,\n ): SessionHead | null;\n\n protected parseFileSessionHeadResult(\n sourcePath: string,\n options?: AgentScanOptions,\n ): ParseSessionResult<SessionHead> {\n const head = this.parseFileSessionHead(sourcePath, options);\n return head ? parsedSession(head) : skippedSession(\"source produced no session\");\n }\n\n protected abstract createFileSessionMeta(head: SessionHead, source: SessionSourceFile): TMeta;\n\n scanSessionSource(sourcePath: string, options?: AgentScanOptions): SessionHead | null {\n const result = this.parseFileSessionHeadResult(sourcePath, options);\n if (this.pendingParseResults.has(sourcePath)) {\n this.pendingParseResults.set(sourcePath, result);\n }\n if (result.status === \"parsed\") {\n this.sessionMetaMap.set(\n result.data.id,\n this.createFileSessionMeta(result.data, this.sessionSourceFile(sourcePath)),\n );\n }\n return getParsedSession(result);\n }\n\n protected override scanSessionSourceResult(\n source: SessionSourceRef,\n options?: AgentScanOptions,\n ): ParseSessionResult<SessionHead> {\n this.pendingParseResults.set(source.sourcePath, undefined);\n try {\n const head = this.scanSessionSource(source.sourcePath, options);\n const result = this.pendingParseResults.get(source.sourcePath);\n if (head) return result?.status === \"parsed\" ? result : parsedSession(head);\n return result ?? skippedSession(\"source produced no session\");\n } finally {\n this.pendingParseResults.delete(source.sourcePath);\n }\n }\n\n protected buildFileSessionMeta<TExtra extends object>({\n head,\n source,\n fingerprint,\n extras,\n }: {\n head: SessionHead;\n source: SessionSourceFile;\n fingerprint: string;\n extras: TExtra;\n }): FileSessionMeta & TExtra {\n return {\n ...extras,\n id: head.id,\n title: head.title,\n sourcePath: source.file,\n sourceFingerprint: fingerprint,\n sourceMtimeMs: source.stat.mtimeMs,\n directory: head.directory,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n };\n }\n}\n\n/**\n * 数据库型 Agent 基类:所有会话聚合在单个 SQLite 数据库中,\n * 无法做 per-file 指纹,故变更检测退化为\"库文件 mtime 是否推进\",\n * 增量扫描退化为全量重扫。\n */\n/**\n * A scan that could not prove its result complete — the database would not\n * open, a table was missing, or a top-level query failed.\n *\n * This is not the same as an agent with no sessions. Callers must keep the last\n * successful snapshot: treating it as an empty result would diff every known\n * session into a removal and wipe the agent from cache, search and the UI.\n */\n/**\n * Error taxonomy for adapters — the same failure class must produce the same\n * user-visible outcome regardless of agent:\n *\n * 1. Malformed record inside an otherwise readable source → skip the record;\n * visibility comes from counted diagnostics (see readJsonlFile's\n * `agent.jsonl_lines_skipped`), never from a hard failure.\n * 2. One source fails to parse → the scan template converts the throw into a\n * `createSessionSourceFailure` (\"parsing\"), keeping the rest of the scan.\n * 3. Enumeration or database access fails → throw `SessionScanError` (wrap\n * reads in `scanStep`); the scanner surfaces it as an agent scan failure.\n *\n * What is never acceptable: catching an I/O or database error and returning\n * an empty/zero result — that makes a broken source indistinguishable from an\n * empty one.\n */\nexport class SessionScanError extends Error {\n constructor(\n readonly agentName: string,\n readonly stage: string,\n options?: { cause?: unknown; sourcePath?: string },\n ) {\n super(`${agentName} session scan failed while ${stage}`, options);\n this.name = \"SessionScanError\";\n this.sourcePath = options?.sourcePath;\n }\n\n readonly sourcePath?: string;\n}\n\n/**\n * Files that reflect committed data. `-shm` is deliberately absent: opening the\n * database read-only rewrites it, so including it would report a change after\n * every scan.\n */\nexport function sqliteSourceFiles(dbPath: string): string[] {\n return [dbPath, `${dbPath}-wal`];\n}\n\nfunction statOrNull(path: string): { size: number; mtimeMs: number } | null {\n try {\n return statSync(path);\n } catch (error) {\n if (isMissingSessionSourceError(error)) return null;\n throw error;\n }\n}\n\n/** Changes whenever committed data changes, and only then. */\nfunction sqliteSourceFingerprint(dbPath: string): string {\n return sqliteSourceFiles(dbPath)\n .map((path) => {\n const stats = statOrNull(path);\n return stats ? `${stats.size}:${Math.round(stats.mtimeMs)}` : \"-\";\n })\n .join(\"|\");\n}\n\nfunction latestSqliteSourceMtime(dbPath: string): number {\n return sqliteSourceFiles(dbPath).reduce((latest, path) => {\n const stats = statOrNull(path);\n return stats && stats.mtimeMs > latest ? stats.mtimeMs : latest;\n }, 0);\n}\n\nexport abstract class DatabaseSessionSource extends BaseAgent {\n protected sessionMetaMap = new Map<string, SessionCacheMeta>();\n private lastSourceFingerprint: string | null = null;\n private pendingSourceFingerprint: string | null = null;\n\n /** 返回数据库文件路径(供 mtime 检测)。 */\n protected abstract getDatabasePath(): string | null;\n\n /** 记录单个会话的缓存 meta(sourcePath = dbPath)。 */\n protected rememberSession(sessionId: string, additionalMeta: Record<string, unknown> = {}): void {\n const dbPath = this.getDatabasePath();\n if (!dbPath) return;\n this.sessionMetaMap.set(sessionId, {\n ...additionalMeta,\n id: sessionId,\n sourcePath: dbPath,\n pricingCaptureEpoch: PRICING_CAPTURE_EPOCH,\n });\n }\n\n protected captureSessionPricingMisses<T extends SessionHead | null>(scan: () => T): T {\n const { result, unpricedModels } = capturePricingMisses(scan);\n if (result) {\n this.rememberSession(result.id, unpricedModels.length > 0 ? { unpricedModels } : {});\n }\n return result;\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta;\n }\n\n override commitChangeCheck(): void {\n if (this.pendingSourceFingerprint == null) return;\n this.lastSourceFingerprint = this.pendingSourceFingerprint;\n this.pendingSourceFingerprint = null;\n }\n\n /**\n * 变更检测:数据库内部变更难以按行定位,按库文件集合的指纹判定。\n *\n * In WAL mode a commit appends to the sidecar and leaves the main file\n * untouched until checkpoint, so watching the database alone misses recent\n * writes entirely. Size is part of the fingerprint because an uncheckpointed\n * commit may land in the same millisecond as the previous one.\n */\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const dbPath = this.getDatabasePath();\n if (!dbPath) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n\n try {\n if (!statOrNull(dbPath)) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n const pricingChanged = cachedSessions.some((session) => {\n const meta = this.sessionMetaMap.get(session.id);\n return (\n meta?.pricingCaptureEpoch !== PRICING_CAPTURE_EPOCH ||\n pricingBecameAvailable(meta.unpricedModels)\n );\n });\n if (pricingChanged) return { hasChanges: true, timestamp: Date.now() };\n\n const fingerprint = sqliteSourceFingerprint(dbPath);\n const previous = this.lastSourceFingerprint;\n // Advancing the baseline here would make a failed scan look \"unchanged\"\n // on the next pass; stash it until the orchestrator commits the scan.\n this.pendingSourceFingerprint = fingerprint;\n // Nothing to compare against on the first pass — fall back to the caller's\n // baseline, which also covers a WAL written while the process was down.\n const hasChanges =\n previous == null\n ? latestSqliteSourceMtime(dbPath) > sinceTimestamp\n : fingerprint !== previous;\n return {\n hasChanges,\n timestamp: Date.now(),\n };\n } catch (error) {\n const failure = {\n sourcePath: dbPath,\n errorClass: error instanceof Error ? error.name : typeof error,\n message: error instanceof Error ? error.message : String(error),\n };\n getCoreDiagnostics()?.warn(\"agent.change_check_failed\", {\n agent: this.name,\n source_path: failure.sourcePath,\n error_class: failure.errorClass,\n message: failure.message,\n baseline_advanced: false,\n });\n return {\n status: \"failed\",\n hasChanges: false,\n timestamp: sinceTimestamp,\n failure,\n };\n }\n }\n\n /** 增量扫描:数据库型无法增量,直接全量重扫。 */\n incrementalScan(\n _cachedSessions: SessionHead[],\n _changedIds: string[],\n _refs?: SessionSourceRef[],\n scanOptions?: AgentScanOptions,\n ): SessionHead[] {\n return this.scan(scanOptions);\n }\n}\n","/**\n * 性能追踪工具 - 用于测量启动过程中的各个阶段耗时\n */\n\nexport interface PerfMarker {\n name: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n children: PerfMarker[];\n parent?: PerfMarker;\n}\n\nclass PerfTracer {\n private rootMarkers: PerfMarker[] = [];\n private activeStack: PerfMarker[] = [];\n private enabled = false;\n\n enable() {\n this.enabled = true;\n }\n\n start(name: string): PerfMarker {\n const marker: PerfMarker = {\n name,\n startTime: performance.now(),\n children: [],\n };\n\n if (!this.enabled) return marker;\n\n const parent = this.activeStack[this.activeStack.length - 1];\n if (parent) {\n marker.parent = parent;\n parent.children.push(marker);\n } else {\n this.rootMarkers.push(marker);\n }\n\n this.activeStack.push(marker);\n return marker;\n }\n\n end(marker?: PerfMarker): void {\n if (!this.enabled) return;\n\n const target = marker ?? this.activeStack[this.activeStack.length - 1];\n if (!target) return;\n\n target.endTime = performance.now();\n target.duration = target.endTime - target.startTime;\n\n // Pop until we remove the target\n while (this.activeStack.length > 0) {\n const popped = this.activeStack.pop();\n if (popped === target) break;\n }\n }\n\n measure<T>(name: string, fn: () => T): T {\n const marker = this.start(name);\n try {\n return fn();\n } finally {\n this.end(marker);\n }\n }\n\n async measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {\n const marker = this.start(name);\n try {\n return await fn();\n } finally {\n this.end(marker);\n }\n }\n\n getReport(): string {\n if (!this.enabled) return \"Performance tracing disabled\";\n\n const lines: string[] = [];\n lines.push(\"\\n=== Performance Report ===\\n\");\n\n for (const marker of this.rootMarkers) {\n this.formatMarker(marker, 0, lines);\n }\n\n return lines.join(\"\\n\");\n }\n\n private formatMarker(marker: PerfMarker, depth: number, lines: string[]): void {\n const indent = \" \".repeat(depth);\n const duration = marker.duration?.toFixed(2) ?? \"?\";\n lines.push(`${indent}${marker.name}: ${duration}ms`);\n\n for (const child of marker.children) {\n this.formatMarker(child, depth + 1, lines);\n }\n }\n\n reset(): void {\n this.rootMarkers = [];\n this.activeStack = [];\n }\n}\n\nexport const perf = new PerfTracer();\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport {\n SingleFileSessionSource,\n filteredSession,\n getParsedSession,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { ParseSessionResult } from \"./base.js\";\nimport type {\n SessionHead,\n SessionDetail,\n Message,\n MessagePart,\n ToolPart,\n ToolPartState,\n} from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile, readJsonlFileLines } from \"../utils/jsonl.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { parseAgentTimestamp } from \"../utils/timestamp.js\";\nimport { asArray, asNumber, asRecord, asString, reportFieldMismatch } from \"../utils/narrow.js\";\nimport {\n matchesScanWindow,\n type AgentScanOptions,\n type FileSessionMeta,\n type SessionCacheMeta,\n type SessionSourceFile,\n type SessionSourceRef,\n} from \"./base.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\n\n// v7: unified timestamp parsing changes head times for numeric timestamps.\nconst HEAD_INDEX_VERSION = \"claudecode-head-v7\";\n\nexport function resolveClaudeCodeDataRoot(): string {\n return resolveHomePath(\"CLAUDE_CONFIG_DIR\", \".claude\");\n}\n\ninterface ClaudeUsage {\n key: string;\n input: number;\n output: number;\n cacheRead: number;\n cacheCreate: number;\n}\n\ninterface SessionMeta extends FileSessionMeta {\n indexPath: string | null;\n indexMtimeMs: number | null;\n headIndexVersion: string;\n model: string | null | undefined;\n parentSessionId: string | null;\n toolUseId: string | null;\n}\n\ninterface ClaudeChildContext {\n sessionId: string;\n projectDir: string;\n parentSessionId: string | null;\n explicitTitle: string | null;\n metaMtimeMs: number | null;\n toolUseId: string | null;\n}\n\ninterface ClaudeChildContextCacheEntry {\n metaMtimeMs: number | null;\n context: ClaudeChildContext;\n}\n\nfunction parseTimestampMs(data: Record<string, unknown>): number {\n return parseAgentTimestamp(data[\"timestamp\"], \"claudecode\") ?? 0;\n}\n\n/** Reads a numeric usage field; a present-but-wrong-typed field is a schema drift signal. */\nfunction readUsageNumber(usage: Record<string, unknown>, field: string): number {\n const raw = usage[field];\n if (raw === undefined) return 0;\n const value = asNumber(raw);\n if (value === undefined) {\n reportFieldMismatch(\"claudecode\", `message.usage.${field}`);\n return 0;\n }\n return value;\n}\n\nfunction extractClaudeUsage(\n data: Record<string, unknown>,\n msg: Record<string, unknown>,\n): ClaudeUsage | null {\n const rawUsage = msg[\"usage\"];\n if (rawUsage === undefined || rawUsage === null) return null;\n\n const usage = asRecord(rawUsage);\n if (!usage) {\n reportFieldMismatch(\"claudecode\", \"message.usage\");\n return null;\n }\n\n const requestId = typeof data[\"requestId\"] === \"string\" ? data[\"requestId\"].trim() : \"\";\n const uuid = typeof data[\"uuid\"] === \"string\" ? data[\"uuid\"].trim() : \"\";\n const key = requestId || uuid;\n if (!key) return null;\n\n return {\n key,\n input: readUsageNumber(usage, \"input_tokens\"),\n output: readUsageNumber(usage, \"output_tokens\"),\n cacheRead: readUsageNumber(usage, \"cache_read_input_tokens\"),\n cacheCreate: readUsageNumber(usage, \"cache_creation_input_tokens\"),\n };\n}\n\nexport class ClaudeCodeAgent extends SingleFileSessionSource<SessionMeta> {\n readonly name = \"claudecode\";\n readonly displayName = \"Claude Code\";\n\n private basePath: string | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private sessionsIndexCache: Record<string, any> = {};\n private sessionsIndexMtime: Record<string, number | null> = {};\n private childContextsBySource = new Map<string, ClaudeChildContext>();\n private childContextCache = new Map<string, ClaudeChildContextCacheEntry>();\n private childSessionIdByToolUseId = new Map<string, string>();\n private childIndexReady = false;\n\n private findBasePath(): string | null {\n return firstExisting(join(resolveClaudeCodeDataRoot(), \"projects\"), \"data/claudecode\");\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveClaudeCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: [{ root: dataRoot, path: join(dataRoot, \"projects\") }, { path: \"data/claudecode\" }],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n for (const entry of this.readSessionSourceDirectory(this.basePath)) {\n if (!entry.isDirectory()) continue;\n const directory = join(this.basePath, entry.name);\n if (\n this.readSessionSourceDirectory(directory).some(\n (child) => child.isFile() && child.name.endsWith(\".jsonl\"),\n )\n ) {\n return true;\n }\n }\n return false;\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n const projectDirs = this.listProjectDirs();\n const indexMtimes = new Map<string, number | null>();\n for (const projectDir of projectDirs) {\n const indexPath = this.getSessionsIndexPath(projectDir);\n indexMtimes.set(projectDir, this.readFileMtimeMs(indexPath));\n }\n\n const projectDirSet = new Set(projectDirs);\n const allSources = this.walkFiles(projectDirs, (entry) => entry.name.endsWith(\".jsonl\"), {\n recursive: true,\n });\n this.indexChildContexts(allSources, projectDirs);\n const indexedSources = allSources.flatMap((source) => {\n const child = this.childContextsBySource.get(source.file);\n if (!child && !projectDirSet.has(dirname(source.file))) return [];\n return [\n {\n source,\n sessionId: child?.sessionId ?? basename(source.file, \".jsonl\"),\n child,\n },\n ];\n });\n let selectedSources = indexedSources.filter(({ source }) =>\n matchesScanWindow(source.stat.mtimeMs, options),\n );\n\n if (options?.from != null || options?.to != null) {\n type IndexedSource = (typeof indexedSources)[number];\n const childrenByParent = new Map<string, IndexedSource[]>();\n for (const indexed of indexedSources) {\n const parentId = indexed.child?.parentSessionId;\n if (!parentId) continue;\n const children = childrenByParent.get(parentId);\n if (children) children.push(indexed);\n else childrenByParent.set(parentId, [indexed]);\n }\n\n const windowSelectedById = new Map(\n selectedSources.map((indexed) => [indexed.sessionId, indexed]),\n );\n const connectedSelected = new Map<string, IndexedSource>();\n const acceptedIds = new Set<string>();\n const visitingIds = new Set<string>();\n const hasSelectedParent = (sessionId: string): boolean => {\n if (acceptedIds.has(sessionId)) return true;\n if (visitingIds.has(sessionId)) return false;\n\n const indexed = windowSelectedById.get(sessionId);\n if (!indexed) return false;\n const parentId = indexed.child?.parentSessionId;\n if (!parentId) {\n acceptedIds.add(sessionId);\n return true;\n }\n\n visitingIds.add(sessionId);\n const connected = hasSelectedParent(parentId);\n visitingIds.delete(sessionId);\n if (connected) acceptedIds.add(sessionId);\n return connected;\n };\n\n for (const indexed of selectedSources) {\n if (hasSelectedParent(indexed.sessionId)) {\n connectedSelected.set(indexed.sessionId, indexed);\n }\n }\n\n if (options?.includeRelatedSessions !== false) {\n const pending = [...connectedSelected.values()]\n .filter(({ child }) => !child?.parentSessionId)\n .map(({ sessionId }) => sessionId);\n while (pending.length > 0) {\n const parentId = pending.pop()!;\n for (const child of childrenByParent.get(parentId) ?? []) {\n if (connectedSelected.has(child.sessionId)) continue;\n connectedSelected.set(child.sessionId, child);\n pending.push(child.sessionId);\n }\n }\n }\n\n selectedSources = [...connectedSelected.values()];\n }\n\n return selectedSources.map(({ source: { file, stat }, sessionId, child }) => {\n const projectDir = child?.projectDir ?? dirname(file);\n return {\n sessionId,\n sourcePath: file,\n fingerprint: this.sourceFingerprint(\n stat,\n indexMtimes.get(projectDir) ?? null,\n child?.metaMtimeMs,\n ),\n };\n });\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n const childIndexInputsChanged = this.childIndexReady && this.didChildIndexInputsChange(meta);\n super.setSessionMetaMap(meta);\n if (!childIndexInputsChanged) return;\n this.childContextsBySource.clear();\n this.childSessionIdByToolUseId.clear();\n this.childIndexReady = false;\n }\n\n protected parseFileSessionHead(sourcePath: string): SessionHead | null {\n return getParsedSession(this.parseFileSessionHeadResult(sourcePath));\n }\n\n protected override parseFileSessionHeadResult(\n sourcePath: string,\n ): ParseSessionResult<SessionHead> {\n const child = this.getChildContext(sourcePath);\n const projectDir = child?.projectDir ?? dirname(sourcePath);\n return this.parseSessionHeadResult(sourcePath, projectDir, child);\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n if (!existsSync(meta.sourcePath)) {\n throw new Error(`Session file missing: ${meta.sourcePath}`);\n }\n\n this.ensureChildIndex();\n const builder = new TranscriptBuilder();\n const assistantUuidToToolCalls = new Map<string, string[]>();\n const countedUsageKeys = new Set<string>();\n for (const record of readJsonlFile(meta.sourcePath)) {\n try {\n this.convertRecord(\n record,\n builder,\n assistantUuidToToolCalls,\n countedUsageKeys,\n this.childSessionIdByToolUseId,\n );\n } catch {\n // skip malformed records\n }\n }\n\n const transcript = builder.finish();\n\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: this.sessionSlug(meta.id),\n directory: meta.directory,\n parent_reference:\n meta.parentSessionId == null\n ? undefined\n : { agentName: this.name, sessionId: meta.parentSessionId },\n version: undefined,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: transcript.stats,\n messages: transcript.messages,\n };\n }\n\n // --- Private helpers ---\n\n private listProjectDirs(): string[] {\n if (!this.basePath) return [];\n return this.readSessionSourceDirectory(this.basePath)\n .filter((entry) => entry.isDirectory())\n .map((entry) => join(this.basePath!, entry.name));\n }\n\n private didChildIndexInputsChange(meta: Map<string, SessionCacheMeta>): boolean {\n if (meta.size !== this.sessionMetaMap.size) return true;\n\n for (const [sessionId, next] of meta) {\n const current = this.sessionMetaMap.get(sessionId);\n if (!current || current.sourcePath !== next.sourcePath) return true;\n if (\n basename(dirname(next.sourcePath)) === \"subagents\" &&\n (current.title !== next[\"title\"] ||\n current.parentSessionId !== next[\"parentSessionId\"] ||\n this.readToolUseId(current) !== this.readToolUseId(next))\n ) {\n return true;\n }\n }\n\n return false;\n }\n\n private readToolUseId(meta: SessionCacheMeta): string | null {\n const value = meta[\"toolUseId\"];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n }\n\n private ensureChildIndex(): void {\n if (this.childIndexReady) return;\n this.basePath ??= this.findBasePath();\n if (!this.basePath) {\n this.childIndexReady = true;\n return;\n }\n\n const projectDirs = this.listProjectDirs();\n this.indexChildContexts(\n this.walkFiles(projectDirs, (entry) => entry.name.endsWith(\".jsonl\"), {\n recursive: true,\n }),\n projectDirs,\n );\n }\n\n private indexChildContexts(\n sources: readonly SessionSourceFile[],\n projectDirs: readonly string[],\n ): void {\n this.childContextsBySource.clear();\n this.childSessionIdByToolUseId.clear();\n const projectDirSet = new Set(projectDirs);\n const contexts = new Map<string, ClaudeChildContext>();\n const knownSessionIds = new Set<string>();\n\n for (const source of sources) {\n const child = this.readChildContext(source.file);\n if (!child) {\n if (projectDirSet.has(dirname(source.file))) {\n knownSessionIds.add(basename(source.file, \".jsonl\"));\n }\n continue;\n }\n contexts.set(source.file, child);\n knownSessionIds.add(child.sessionId);\n }\n\n for (const [sourcePath, child] of contexts) {\n const parentSessionId =\n child.parentSessionId && knownSessionIds.has(child.parentSessionId)\n ? child.parentSessionId\n : null;\n const normalized =\n parentSessionId === child.parentSessionId ? child : { ...child, parentSessionId };\n this.childContextsBySource.set(sourcePath, normalized);\n if (child.toolUseId) {\n this.childSessionIdByToolUseId.set(child.toolUseId, normalized.sessionId);\n }\n }\n\n this.childIndexReady = true;\n }\n\n private getChildContext(sourcePath: string): ClaudeChildContext | null {\n const cached = this.childContextsBySource.get(sourcePath);\n if (cached) return cached;\n\n const child = this.readChildContext(sourcePath);\n if (!child) return null;\n this.childContextsBySource.set(sourcePath, child);\n if (child.toolUseId) {\n this.childSessionIdByToolUseId.set(child.toolUseId, child.sessionId);\n }\n return child;\n }\n\n private readChildContext(sourcePath: string): ClaudeChildContext | null {\n const subagentsDir = dirname(sourcePath);\n if (basename(subagentsDir) !== \"subagents\") return null;\n\n const parentDir = dirname(subagentsDir);\n // Claude stores nested transcripts flat here; parentAgentId carries the nesting relation.\n const projectDir = dirname(parentDir);\n const fileStem = basename(sourcePath, \".jsonl\");\n const metaPath = join(subagentsDir, fileStem + \".meta.json\");\n const metaMtimeMs = this.readFileMtimeMs(metaPath);\n const cached = this.childContextCache.get(sourcePath);\n if (cached?.metaMtimeMs === metaMtimeMs) return cached.context;\n\n let metadata: Record<string, unknown> | null = null;\n if (metaMtimeMs !== null) {\n try {\n metadata = asRecord(JSON.parse(readFileSync(metaPath, \"utf-8\"))) ?? null;\n } catch {\n // Child transcripts can outlive their metadata during an interrupted spawn.\n }\n }\n\n const sessionId = asString(metadata?.[\"agentId\"])?.trim() || fileStem.replace(/^agent-/, \"\");\n if (!sessionId) return null;\n\n const parentAgentId = asString(metadata?.[\"parentAgentId\"])?.trim();\n const candidateParentId = parentAgentId || basename(parentDir) || null;\n const parentSessionId =\n candidateParentId && this.hasChildParent(sourcePath, projectDir, candidateParentId)\n ? candidateParentId\n : null;\n const name = asString(metadata?.[\"name\"])?.trim();\n const description = asString(metadata?.[\"description\"])?.trim();\n\n const context = {\n sessionId,\n projectDir,\n parentSessionId,\n explicitTitle: name || description || null,\n metaMtimeMs,\n toolUseId: asString(metadata?.[\"toolUseId\"])?.trim() || null,\n };\n this.childContextCache.set(sourcePath, { metaMtimeMs, context });\n return context;\n }\n\n private hasChildParent(sourcePath: string, projectDir: string, parentSessionId: string): boolean {\n const subagentsDir = dirname(sourcePath);\n return [\n join(projectDir, parentSessionId + \".jsonl\"),\n join(subagentsDir, \"agent-\" + parentSessionId + \".jsonl\"),\n join(subagentsDir, parentSessionId + \".jsonl\"),\n ].some((path) => existsSync(path));\n }\n\n protected createFileSessionMeta(head: SessionHead, source: SessionSourceFile): SessionMeta {\n const child = this.getChildContext(source.file);\n const projectDir = child?.projectDir ?? dirname(source.file);\n const indexPath = this.getSessionsIndexPath(projectDir);\n const indexMtime = this.readFileMtimeMs(indexPath);\n return this.buildFileSessionMeta({\n head,\n source,\n fingerprint: this.sourceFingerprint(source.stat, indexMtime, child?.metaMtimeMs),\n extras: {\n indexPath: indexMtime === null ? null : indexPath,\n indexMtimeMs: indexMtime,\n headIndexVersion: HEAD_INDEX_VERSION,\n model: head.stats.total_tokens ? \"unknown\" : undefined,\n parentSessionId: head.parent_reference?.sessionId ?? null,\n toolUseId: child?.toolUseId ?? null,\n },\n });\n }\n\n /** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */\n private sourceFingerprint(\n stat: { mtimeMs: number; size: number },\n indexMtime: number | null,\n metaMtime?: number | null,\n ): string {\n const fingerprint = [HEAD_INDEX_VERSION, stat.mtimeMs, stat.size, indexMtime];\n if (metaMtime !== undefined) fingerprint.push(metaMtime);\n return JSON.stringify(fingerprint);\n }\n\n private getSessionsIndexPath(projectDir: string): string {\n return join(projectDir, \"sessions-index.json\");\n }\n\n private loadSessionsIndex(projectDir: string): Map<string, Record<string, unknown>> {\n const cacheKey = basename(projectDir);\n const indexPath = this.getSessionsIndexPath(projectDir);\n const mtime = this.readFileMtimeMs(indexPath);\n\n // Invalidate when the index file mtime advances so long-running processes\n // pick up title changes without relying on callers to evict manually.\n if (cacheKey in this.sessionsIndexCache && this.sessionsIndexMtime[cacheKey] === mtime) {\n return this.sessionsIndexCache[cacheKey];\n }\n\n const map = new Map<string, Record<string, unknown>>();\n\n if (existsSync(indexPath)) {\n try {\n const data = JSON.parse(readFileSync(indexPath, \"utf-8\"));\n const entries: Record<string, unknown>[] = data?.entries ?? [];\n for (const entry of entries) {\n const sid = entry?.sessionId;\n if (typeof sid === \"string\") {\n map.set(sid, entry);\n }\n }\n } catch {\n // ignore\n }\n }\n\n this.sessionsIndexCache[cacheKey] = map;\n this.sessionsIndexMtime[cacheKey] = mtime;\n return map;\n }\n\n private parseSessionHeadResult(\n filePath: string,\n projectDir: string,\n child?: ClaudeChildContext | null,\n ): ParseSessionResult<SessionHead> {\n const sessionId = child?.sessionId ?? basename(filePath, \".jsonl\");\n\n // Try to get title from sessions-index.json\n const index = this.loadSessionsIndex(projectDir);\n const indexEntry = index.get(sessionId);\n const explicitTitle =\n child?.explicitTitle ?? (indexEntry?.summary ? String(indexEntry.summary) : null);\n\n // Extract lightweight metadata; cwd lives in user-type records, not the first line\n let createdAt = 0;\n let updatedAt = 0;\n let lineIndex = 0;\n let messageCount = 0;\n let model: string | null = null;\n let cwd: string | null = null;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCacheCreateTokens = 0;\n let totalCost = 0;\n const modelUsageMap: Record<string, number> = {};\n const countedUsageKeys = new Set<string>();\n let messageTitle: string | null = null;\n\n for (const line of readJsonlFileLines(filePath)) {\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(line) as Record<string, unknown>;\n } catch {\n // A malformed opening record means the file is not a session we can read;\n // later ones are individually skippable.\n if (lineIndex === 0) return skippedSession(\"malformed first record\");\n lineIndex += 1;\n continue;\n }\n\n if (lineIndex === 0) {\n createdAt = parseTimestampMs(data) || statSync(filePath).mtimeMs;\n updatedAt = createdAt;\n }\n const recordIndex = lineIndex;\n lineIndex += 1;\n\n try {\n if (isInternalEventType(data[\"type\"])) continue;\n if (data[\"isMeta\"] === true) continue;\n const ts = parseTimestampMs(data);\n if (ts > updatedAt) updatedAt = ts;\n\n if (!cwd && data[\"cwd\"] && typeof data[\"cwd\"] === \"string\") {\n cwd = data[\"cwd\"];\n }\n\n const msg = asRecord(data[\"message\"]);\n if (!msg && data[\"message\"] !== undefined && data[\"message\"] !== null) {\n reportFieldMismatch(\"claudecode\", \"message\");\n }\n if (msg) {\n const role = asString(msg[\"role\"]);\n if (msg[\"role\"] !== undefined && role === undefined) {\n reportFieldMismatch(\"claudecode\", \"message.role\");\n }\n const userTitle = role === \"user\" ? this.extractUserMessageTitle(msg[\"content\"]) : null;\n if (role?.trim() && (role !== \"user\" || userTitle !== null)) {\n messageCount++;\n }\n if (!model) {\n const m = asString(msg[\"model\"]);\n if (m?.trim()) model = m.trim();\n }\n // Title fallback mirrors the removed extractTitle(): first non-empty\n // visible user text within the first 20 lines.\n if (messageTitle === null && recordIndex < 20 && userTitle) {\n messageTitle = userTitle;\n }\n if (role === \"assistant\") {\n const usage = extractClaudeUsage(data, msg);\n if (usage && !countedUsageKeys.has(usage.key)) {\n countedUsageKeys.add(usage.key);\n const inputTokens = usage.input;\n const cacheRead = usage.cacheRead;\n const cacheCreate = usage.cacheCreate;\n const outputTokens = usage.output;\n\n totalInputTokens += inputTokens + cacheRead + cacheCreate;\n totalOutputTokens += outputTokens;\n totalCacheReadTokens += cacheRead;\n totalCacheCreateTokens += cacheCreate;\n\n const m = asString(msg[\"model\"]);\n if (m?.trim()) {\n const name = m.trim();\n const msgTotal = inputTokens + cacheRead + cacheCreate + outputTokens;\n modelUsageMap[name] = (modelUsageMap[name] ?? 0) + msgTotal;\n const cost = estimateTokenCost(name, {\n input: inputTokens + cacheRead + cacheCreate,\n output: outputTokens,\n cache_read: cacheRead,\n cache_create: cacheCreate,\n });\n if (cost !== null) totalCost += cost;\n }\n }\n }\n }\n } catch {\n // skip\n }\n }\n\n if (lineIndex === 0) return skippedSession(\"empty file\");\n\n const directory = cwd ?? projectDir;\n const directoryTitle = basenameTitle(directory) || basenameTitle(projectDir);\n\n const title = resolveSessionTitle(explicitTitle, messageTitle, directoryTitle);\n\n const hasModelUsage = Object.keys(modelUsageMap).length > 0;\n if (messageCount === 0) return filteredSession(\"no visible messages\");\n\n return parsedSession({\n id: sessionId,\n slug: this.sessionSlug(sessionId),\n title,\n directory,\n parent_reference:\n child?.parentSessionId == null\n ? undefined\n : { agentName: this.name, sessionId: child.parentSessionId },\n time_created: createdAt,\n time_updated: updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n total_cache_read_tokens: totalCacheReadTokens,\n total_cache_create_tokens: totalCacheCreateTokens,\n },\n model_usage: hasModelUsage ? modelUsageMap : undefined,\n });\n }\n\n /** Mirrors the title-candidate extraction previously done in a second JSON.parse pass. */\n private extractUserMessageTitle(content: unknown): string | null {\n if (!content) return null;\n\n if (typeof content === \"string\") {\n const title = normalizeTitleText(content);\n return title || null;\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter((item): item is Record<string, unknown> => {\n const record = asRecord(item);\n return record !== undefined && \"text\" in record;\n })\n .map((item) => String(item[\"text\"] ?? \"\"))\n .join(\" \");\n const title = normalizeTitleText(texts);\n return title || null;\n }\n return null;\n }\n\n // --- Record conversion ---\n\n private convertRecord(\n data: Record<string, unknown>,\n builder: TranscriptBuilder,\n assistantUuidToToolCalls: Map<string, string[]>,\n countedUsageKeys: Set<string>,\n childSessionIdByToolUseId: ReadonlyMap<string, string>,\n ): void {\n if (data[\"isMeta\"] === true) return;\n\n const msgType = String(data[\"type\"] ?? \"\");\n if (isInternalEventType(msgType)) return;\n\n if (msgType === \"assistant\") {\n this.convertAssistantRecord(\n data,\n builder,\n assistantUuidToToolCalls,\n countedUsageKeys,\n childSessionIdByToolUseId,\n );\n } else if (msgType === \"user\") {\n this.convertUserRecord(data, builder, assistantUuidToToolCalls);\n } else if (msgType === \"tool_result\") {\n this.convertToolResultRecord(data, builder);\n }\n }\n\n private convertAssistantRecord(\n data: Record<string, unknown>,\n builder: TranscriptBuilder,\n assistantUuidToToolCalls: Map<string, string[]>,\n countedUsageKeys: Set<string>,\n childSessionIdByToolUseId: ReadonlyMap<string, string>,\n ): void {\n const msg = asRecord(data[\"message\"]) ?? {};\n const timestampMs = parseTimestampMs(data);\n const rawContent = asArray(msg[\"content\"]) ?? [];\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n const toolCallIds: string[] = [];\n for (const item of rawContent) {\n const part = asRecord(item);\n if (!part) continue;\n const partType = String(part[\"type\"] ?? \"\");\n\n if (partType === \"thinking\") {\n const text = cleanInternalText(String(part[\"thinking\"] ?? \"\"));\n if (text) {\n const message = builder.appendAssistantPart(\n this.buildReasoningPart(text, timestampMs),\n { id: uuid, timestampMs, agent: \"claude\" },\n { deduplicateTail: true },\n );\n this.applyAssistantMetadata(message, data, msg, countedUsageKeys);\n }\n continue;\n }\n\n if (partType === \"text\") {\n const text = cleanInternalText(String(part[\"text\"] ?? \"\"));\n if (text) {\n const message = builder.appendAssistantPart(\n this.buildTextPart(text, timestampMs),\n {\n id: uuid,\n timestampMs,\n agent: \"claude\",\n },\n { deduplicateTail: true },\n );\n this.applyAssistantMetadata(message, data, msg, countedUsageKeys);\n }\n continue;\n }\n\n if (partType !== \"tool_use\") continue;\n\n const toolCallId = String(part[\"id\"] ?? \"\").trim();\n const subagentId = childSessionIdByToolUseId.get(toolCallId);\n\n const toolPart = this.buildToolPart(part, timestampMs);\n const message = builder.appendToolCall(\n toolPart,\n { id: uuid, timestampMs, agent: \"claude\", subagentId },\n { modeOnCreate: \"tool\" },\n );\n if (subagentId) message.subagent_id = subagentId;\n this.applyAssistantMetadata(message, data, msg, countedUsageKeys);\n if (toolCallId) {\n toolCallIds.push(toolCallId);\n }\n }\n\n if (toolCallIds.length > 0) {\n assistantUuidToToolCalls.set(uuid, toolCallIds);\n }\n }\n\n private convertUserRecord(\n data: Record<string, unknown>,\n builder: TranscriptBuilder,\n assistantUuidToToolCalls: Map<string, string[]>,\n ): void {\n const msg = asRecord(data[\"message\"]) ?? {};\n const timestampMs = parseTimestampMs(data);\n const content = msg[\"content\"] ?? \"\";\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n // String content — simple user message\n if (typeof content === \"string\") {\n const parts = this.normalizeUserTextParts(content, timestampMs);\n if (parts.length === 0) {\n builder.beginTurn();\n return;\n }\n builder.appendMessage({ id: uuid, role: \"user\", timestampMs, parts });\n return;\n }\n\n if (!Array.isArray(content)) {\n builder.beginTurn();\n return;\n }\n\n const visibleParts = this.normalizeUserTextParts(content, timestampMs);\n const toolStateUpdates = this.extractToolStateUpdates(data[\"toolUseResult\"]);\n\n for (const item of content) {\n const ci = asRecord(item);\n if (!ci || ci[\"type\"] !== \"tool_result\") continue;\n\n const toolCallId = this.resolveToolCallId(data, ci, assistantUuidToToolCalls);\n\n const outputParts = this.normalizeClaudeToolOutput(ci[\"content\"], timestampMs);\n if (this.backfillToolOutput(builder, toolCallId, outputParts, toolStateUpdates)) {\n continue;\n }\n\n const fallback = this.buildFallbackToolMessage({\n messageId: uuid,\n timestampMs,\n toolCallId,\n outputParts,\n });\n if (fallback) builder.appendMessage(fallback);\n }\n\n if (visibleParts.length > 0) {\n builder.appendMessage({ id: uuid, role: \"user\", timestampMs, parts: visibleParts });\n }\n\n builder.beginTurn();\n }\n\n private convertToolResultRecord(data: Record<string, unknown>, builder: TranscriptBuilder): void {\n const timestampMs = parseTimestampMs(data);\n const msg = asRecord(data[\"message\"]) ?? {};\n const outputParts = this.normalizeClaudeToolOutput(msg[\"content\"], timestampMs);\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n const fallback = this.buildFallbackToolMessage({\n messageId: uuid,\n timestampMs,\n toolCallId: null,\n outputParts,\n });\n if (fallback) builder.appendMessage(fallback);\n builder.beginTurn();\n }\n\n private buildTextPart(text: string, timestampMs: number): MessagePart {\n return { type: \"text\", text, time_created: timestampMs };\n }\n\n private buildReasoningPart(text: string, timestampMs: number): MessagePart {\n return { type: \"reasoning\", text, time_created: timestampMs };\n }\n\n private buildToolPart(part: Record<string, unknown>, timestampMs: number): ToolPart {\n const toolName = String(part[\"name\"] ?? \"\");\n return {\n type: \"tool\",\n tool: toolName,\n callID: String(part[\"id\"] ?? \"\"),\n title: `Tool: ${toolName}`,\n state: {\n status: \"running\",\n input: part[\"input\"] ?? {},\n output: null,\n },\n time_created: timestampMs,\n };\n }\n\n private applyAssistantMetadata(\n message: Message,\n data: Record<string, unknown>,\n msg: Record<string, unknown>,\n countedUsageKeys: Set<string>,\n ): void {\n const model = msg[\"model\"];\n if (model && typeof model === \"string\" && !message.model) {\n message.model = model;\n }\n const usage = extractClaudeUsage(data, msg);\n if (usage && !message.tokens && !countedUsageKeys.has(usage.key)) {\n countedUsageKeys.add(usage.key);\n message.tokens = {\n input: usage.input + usage.cacheCreate + usage.cacheRead,\n output: usage.output,\n cache_read: usage.cacheRead,\n cache_create: usage.cacheCreate,\n };\n const cost = estimateTokenCost(message.model, message.tokens);\n if (cost !== null) {\n message.cost = cost;\n message.cost_source = \"estimated\";\n }\n }\n }\n\n // --- User content normalization ---\n\n private normalizeUserTextParts(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n const text = cleanInternalText(content);\n return text ? [this.buildTextPart(text, timestampMs)] : [];\n }\n if (!Array.isArray(content)) return [];\n\n const parts: MessagePart[] = [];\n for (const item of content) {\n const ci = asRecord(item);\n if (ci) {\n if (ci[\"type\"] === \"tool_result\") continue;\n const text = cleanInternalText(String(ci[\"text\"] ?? \"\"));\n if (text) parts.push(this.buildTextPart(text, timestampMs));\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push(this.buildTextPart(text, timestampMs));\n }\n }\n return parts;\n }\n\n private normalizeClaudeToolOutput(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n const text = cleanInternalText(content);\n return text ? [this.buildTextPart(text, timestampMs)] : [];\n }\n if (content === null || content === undefined) return [];\n\n if (Array.isArray(content)) {\n const parts: MessagePart[] = [];\n for (const item of content) {\n const itemRecord = asRecord(item);\n if (itemRecord) {\n const rawSource = itemRecord[\"source\"];\n if (itemRecord[\"type\"] === \"image\" && rawSource) {\n const source = asRecord(rawSource);\n const data = asString(source?.[\"data\"]) ?? \"\";\n const mimeType = asString(source?.[\"media_type\"]) ?? \"\";\n if (data && mimeType.startsWith(\"image/\")) {\n parts.push({ type: \"image\", data, mime_type: mimeType, time_created: timestampMs });\n }\n continue;\n }\n const text = String(itemRecord[\"text\"] ?? itemRecord[\"content\"] ?? \"\");\n const cleaned = cleanInternalText(text);\n if (cleaned) parts.push(this.buildTextPart(cleaned, timestampMs));\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push(this.buildTextPart(text, timestampMs));\n }\n }\n return parts;\n }\n\n const text = cleanInternalText(String(content));\n return text ? [this.buildTextPart(text, timestampMs)] : [];\n }\n\n // --- Tool backfill ---\n\n private backfillToolOutput(\n builder: TranscriptBuilder,\n callId: string,\n outputParts: MessagePart[],\n stateUpdates?: Partial<Pick<ToolPartState, \"status\" | \"metadata\">>,\n ): boolean {\n if (!callId) return false;\n\n return builder.updateToolCall(callId, (part) => {\n const state = part.state;\n if (outputParts.length > 0) {\n const existing = state.output;\n if (Array.isArray(existing)) existing.push(...outputParts);\n else if (existing == null) state.output = [...outputParts];\n else state.output = [existing, ...outputParts];\n }\n if (stateUpdates?.status) state.status = stateUpdates.status;\n if (stateUpdates?.metadata !== undefined) state.metadata = stateUpdates.metadata;\n if (outputParts.length > 0 && state.status === \"running\") state.status = \"completed\";\n });\n }\n\n private resolveToolCallId(\n data: Record<string, unknown>,\n item: Record<string, unknown>,\n assistantUuidToToolCalls: Map<string, string[]>,\n ): string {\n const directId = String(item[\"tool_use_id\"] ?? \"\").trim();\n if (directId) return directId;\n\n const sourceUuid = String(data[\"sourceToolAssistantUUID\"] ?? \"\").trim();\n if (!sourceUuid) return \"\";\n\n const ids = assistantUuidToToolCalls.get(sourceUuid);\n if (ids && ids.length === 1) return ids[0]!;\n return \"\";\n }\n\n private extractToolStateUpdates(\n toolUseResult: unknown,\n ): Partial<Pick<ToolPartState, \"status\" | \"metadata\">> {\n const result = asRecord(toolUseResult);\n if (!result) return {};\n\n const updates: Partial<Pick<ToolPartState, \"status\" | \"metadata\">> = {};\n\n const success = result[\"success\"];\n if (typeof success === \"boolean\") {\n updates.status = success ? \"completed\" : \"error\";\n }\n\n const commandName = result[\"commandName\"];\n if (commandName) {\n updates.metadata = { commandName };\n }\n\n return updates;\n }\n\n // --- Fallback ---\n\n private buildFallbackToolMessage(opts: {\n messageId: string;\n timestampMs: number;\n toolCallId: string | null;\n outputParts: MessagePart[];\n }): TranscriptMessageInput | null {\n if (opts.outputParts.length === 0) return null;\n return {\n id: opts.messageId,\n role: \"tool\",\n timestampMs: opts.timestampMs,\n parts: opts.outputParts,\n };\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\n\n/** Expand the tilde prefixes shells accept for home-relative paths. */\nfunction expandHomePath(path: string): string {\n if (path === \"~\") return homedir();\n if (path.startsWith(\"~/\") || path.startsWith(\"~\\\\\")) return join(homedir(), path.slice(2));\n return path;\n}\n\n/**\n * Blank values count as unset, `~` expands, and relative paths resolve — so\n * CODEX_HOME=~/data points at the home directory instead of a literal\n * ./~/data that silently yields zero sessions.\n */\nexport function readEnvPath(name: string): string | null {\n const value = process.env[name];\n if (!value || !value.trim()) return null;\n const expanded = expandHomePath(value.trim());\n // resolve() would also prepend a drive letter to POSIX-absolute paths on\n // Windows; only relative inputs actually need anchoring.\n return isAbsolute(expanded) ? expanded : resolve(expanded);\n}\n\nfunction firstExisting(...paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nexport function resolveDataHome(): string {\n const xdg = readEnvPath(\"XDG_DATA_HOME\");\n if (xdg) return xdg;\n\n const p = platform();\n if (p === \"win32\") {\n return (\n readEnvPath(\"LOCALAPPDATA\") ?? readEnvPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Local\")\n );\n }\n\n // macOS / Linux\n return join(homedir(), \".local\", \"share\");\n}\n\nexport function resolveHomePath(environmentVariable: string, fallbackDirectory: string): string {\n return readEnvPath(environmentVariable) ?? join(homedir(), fallbackDirectory);\n}\n\nexport { firstExisting };\n","import { closeSync, openSync, readSync } from \"node:fs\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport { getCoreDiagnostics } from \"./diagnostics.js\";\n\nconst READ_CHUNK_BYTES = 1 << 20;\n\nexport function* parseJsonlLines(content: string): Generator<Record<string, unknown>> {\n let total = 0;\n let skipped = 0;\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n total += 1;\n try {\n yield JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n skipped += 1;\n }\n }\n // Reported after the generator is fully drained — a consumer that breaks\n // out of the loop early (e.g. to grab just the first line) never reaches\n // this point, so its skipped count goes unreported.\n if (skipped > 0) {\n getCoreDiagnostics()?.warn(\"agent.jsonl_lines_skipped\", { skipped, total });\n }\n}\n\n/**\n * Streams trimmed non-empty lines chunk by chunk so a session log is never\n * held in memory at once. Codex rollout files can exceed 400 MB; loading them\n * with readFileSync + split doubles that as UTF-16 strings and OOMs the\n * scan-refresh worker.\n */\nexport function* readJsonlFileLines(\n filePath: string,\n chunkBytes = READ_CHUNK_BYTES,\n): Generator<string> {\n const fd = openSync(filePath, \"r\");\n try {\n const buffer = Buffer.alloc(chunkBytes);\n // StringDecoder buffers multi-byte UTF-8 sequences split across chunks.\n const decoder = new StringDecoder(\"utf8\");\n // Chunks of the record currently being assembled, joined once when its line\n // break arrives. Concatenating onto a string instead would re-copy the whole\n // partial record on every chunk — quadratic on the multi-megabyte single-line\n // records agent logs routinely contain.\n let pending: string[] = [];\n let bytesRead = readSync(fd, buffer, 0, chunkBytes, -1);\n while (bytesRead > 0) {\n const decoded = decoder.write(buffer.subarray(0, bytesRead));\n const lastBreak = decoded.lastIndexOf(\"\\n\");\n if (lastBreak === -1) {\n if (decoded) pending.push(decoded);\n } else {\n pending.push(decoded.slice(0, lastBreak));\n const complete = pending.join(\"\");\n pending = [decoded.slice(lastBreak + 1)];\n for (const line of complete.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed) yield trimmed;\n }\n }\n bytesRead = readSync(fd, buffer, 0, chunkBytes, -1);\n }\n pending.push(decoder.end());\n const tail = pending.join(\"\").trim();\n if (tail) yield tail;\n } finally {\n closeSync(fd);\n }\n}\n\nexport function* readJsonlFile(filePath: string): Generator<Record<string, unknown>> {\n let total = 0;\n let skipped = 0;\n for (const line of readJsonlFileLines(filePath)) {\n total += 1;\n try {\n yield JSON.parse(line) as Record<string, unknown>;\n } catch {\n skipped += 1;\n }\n }\n // Same early-return caveat as parseJsonlLines above.\n if (skipped > 0) {\n getCoreDiagnostics()?.warn(\"agent.jsonl_lines_skipped\", { skipped, total, filePath });\n }\n}\n","import { basename } from \"node:path\";\nimport { cleanDisplayText } from \"./parse-cleanup.js\";\n\nconst TITLE_MAX_LENGTH = 100;\nconst UNTITLED_SESSION = \"Untitled Session\";\n\n/** Normalize extracted title text for display. */\nexport function normalizeTitleText(text: string): string | null {\n const visible =\n cleanDisplayText(text)\n ?.split(\"\\n\")\n .find((line) => line.trim())\n ?.trim() ?? null;\n if (!visible) return null;\n const cleaned = visible.replace(/\\s+/g, \" \").trim();\n if (!cleaned) return null;\n return cleaned.slice(0, TITLE_MAX_LENGTH);\n}\n\n/** Return a stable basename for fallback title. */\nexport function basenameTitle(path: string | null | undefined): string | null {\n if (!path) return null;\n const normalized = path.trim().replace(/[/\\\\]+$/, \"\");\n if (!normalized) return null;\n const name = basename(normalized).trim();\n return name || null;\n}\n\n/** Resolve final session title from explicit, message, and directory fallbacks. */\nexport function resolveSessionTitle(\n explicit: string | null | undefined,\n message: string | null | undefined,\n directory: string | null | undefined,\n): string {\n for (const candidate of [explicit, message, directory]) {\n if (candidate) {\n const normalized = normalizeTitleText(candidate);\n if (normalized) return normalized;\n }\n }\n return UNTITLED_SESSION;\n}\n","const INTERNAL_BLOCK_TAGS = [\n \"command-message\",\n \"command-name\",\n \"local-command-caveat\",\n \"local-command-stdout\",\n \"system-reminder\",\n];\n\nconst TRANSPARENT_TAGS = [\"command-args\"];\n\nconst INTERNAL_EVENT_TYPES = new Set([\n \"progress\",\n \"file history snapshot\",\n \"file-history snapshot\",\n \"file_history snapshot\",\n \"queue operation\",\n \"queue-operation\",\n \"queue_operation\",\n \"last prompt\",\n \"last-prompt\",\n \"last_prompt\",\n]);\n\nfunction blockTagPattern(tag: string): RegExp {\n return new RegExp(`<${tag}\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/${tag}>`, \"gi\");\n}\n\nfunction blockTagLinePattern(tag: string): RegExp {\n return new RegExp(\n `(^|\\\\r?\\\\n)[ \\\\t]*<${tag}\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/${tag}>[ \\\\t]*(?:\\\\r?\\\\n|$)`,\n \"gi\",\n );\n}\n\nfunction openBlockTagPattern(tag: string): RegExp {\n return new RegExp(`\\\\n*<${tag}\\\\b[^>]*>[\\\\s\\\\S]*$`, \"gi\");\n}\n\nfunction looseTagPattern(tag: string): RegExp {\n return new RegExp(`<\\\\/?${tag}\\\\b[^>]*>`, \"gi\");\n}\n\nexport function isInternalEventType(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n const normalized = value.trim().toLowerCase().replace(/[_-]+/g, \" \");\n return INTERNAL_EVENT_TYPES.has(normalized);\n}\n\nexport function cleanDisplayText(text: string): string | null {\n let cleaned = text;\n\n for (const tag of INTERNAL_BLOCK_TAGS) {\n cleaned = cleaned.replace(blockTagLinePattern(tag), \"$1\");\n cleaned = cleaned.replace(blockTagPattern(tag), \"\");\n cleaned = cleaned.replace(openBlockTagPattern(tag), \"\");\n }\n\n for (const tag of INTERNAL_BLOCK_TAGS) {\n cleaned = cleaned.replace(looseTagPattern(tag), \"\");\n }\n\n for (const tag of TRANSPARENT_TAGS) {\n cleaned = cleaned.replace(looseTagPattern(tag), \"\");\n }\n\n cleaned = cleaned.replace(/[ \\t]+(?=\\r?\\n|$)/g, \"\").replace(/(?:\\r?\\n)+$/g, \"\");\n\n return cleaned.trim() ? cleaned : null;\n}\n\nexport function firstVisibleLine(text: string): string | null {\n const cleaned = cleanDisplayText(text);\n if (!cleaned) return null;\n return (\n cleaned\n .split(\"\\n\")\n .find((line) => line.trim())\n ?.trim() ?? null\n );\n}\n","import type { Message, MessagePart } from \"../types/index.js\";\nimport {\n cleanDisplayText,\n isInternalEventType as isRawInternalEventType,\n} from \"./parse-cleanup.js\";\nimport { normalizeTitleText } from \"./title-fallback.js\";\n\nexport function isInternalEventType(value: unknown): boolean {\n return isRawInternalEventType(value);\n}\n\nexport function cleanInternalText(text: string): string {\n return cleanDisplayText(text) ?? \"\";\n}\n\nfunction cleanUnknown(value: unknown): unknown {\n if (typeof value === \"string\") return cleanInternalText(value);\n if (Array.isArray(value)) return value.map(cleanUnknown);\n if (!value || typeof value !== \"object\") return value;\n\n const cleaned: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n cleaned[key] = cleanUnknown(child);\n }\n return cleaned;\n}\n\nexport function cleanMessagePart(part: MessagePart): MessagePart | null {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"plan\") {\n const text = cleanInternalText(part.text);\n return text ? { ...part, text } : null;\n }\n if (part.type !== \"tool\") return part;\n\n const title = part.title ? cleanInternalText(part.title) : \"\";\n const state = {\n ...part.state,\n ...(part.state.input !== undefined ? { input: cleanUnknown(part.state.input) } : {}),\n ...(part.state.output !== undefined ? { output: cleanUnknown(part.state.output) } : {}),\n ...(part.state.error !== undefined ? { error: cleanUnknown(part.state.error) } : {}),\n ...(part.state.metadata !== undefined ? { metadata: cleanUnknown(part.state.metadata) } : {}),\n };\n const { title: _title, ...withoutTitle } = part;\n return {\n ...withoutTitle,\n ...(title ? { title } : {}),\n state,\n };\n}\n\nexport function cleanMessageParts(parts: MessagePart[]): MessagePart[] {\n return parts.flatMap((part) => {\n const cleaned = cleanMessagePart(part);\n return cleaned ? [cleaned] : [];\n });\n}\n\nexport function cleanParsedMessage(message: Message): Message | null {\n const parts = cleanMessageParts(message.parts);\n if (parts.length === 0) return null;\n return { ...message, parts };\n}\n\nexport function cleanParsedMessages(messages: Message[]): Message[] {\n return messages.flatMap((message) => {\n const cleaned = cleanParsedMessage(message);\n return cleaned ? [cleaned] : [];\n });\n}\n\nexport function firstUserMessageTitle(messages: Message[]): string | null {\n for (const message of messages) {\n if (message.role !== \"user\") continue;\n for (const part of message.parts) {\n if (part.type !== \"text\") continue;\n const title = normalizeTitleText(cleanInternalText(part.text));\n if (title) return title;\n }\n }\n return null;\n}\n","import type { MessageTokens } from \"../types/index.js\";\nimport { estimateCostForTokens } from \"../pricing/index.js\";\n\nexport function estimateTokenCost(\n model: string | null | undefined,\n tokens?: MessageTokens,\n): number | null {\n return estimateCostForTokens(model, tokens)?.cost ?? null;\n}\n","import { getCoreDiagnostics } from \"./diagnostics.js\";\n\nconst TIMEZONE_SUFFIX_PATTERN = /(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\nexport interface AgentTimestampOptions {\n /** Accept bare numeric strings as epoch milliseconds (Kimi wire format). */\n numericStrings?: boolean;\n}\n\n/**\n * The one timestamp parser for agent-supplied values of unknown shape.\n * Missing values are null without noise; present-but-unparseable values are\n * reported once and return null so callers pick their own fallback.\n */\nexport function parseAgentTimestamp(\n value: unknown,\n agentName: string,\n options: AgentTimestampOptions = {},\n): number | null {\n if (value == null) return null;\n if (typeof value === \"number\") {\n if (Number.isFinite(value)) return value;\n reportTimestampParseFailure(agentName, value);\n return null;\n }\n if (typeof value !== \"string\") {\n reportTimestampParseFailure(agentName, value);\n return null;\n }\n\n const timestamp = value.trim().replace(\" \", \"T\");\n if (!timestamp) return null;\n\n if (options.numericStrings) {\n const numeric = Number(timestamp);\n if (Number.isFinite(numeric)) return numeric;\n }\n\n const normalized = TIMEZONE_SUFFIX_PATTERN.test(timestamp) ? timestamp : `${timestamp}Z`;\n const timestampMs = Date.parse(normalized);\n if (Number.isFinite(timestampMs)) return timestampMs;\n\n reportTimestampParseFailure(agentName, value, normalized);\n return null;\n}\n\nfunction reportTimestampParseFailure(agentName: string, value: unknown, normalized?: string): void {\n getCoreDiagnostics()?.warn(\"agent.timestamp_parse_failed\", {\n agentName,\n value: typeof value === \"string\" || typeof value === \"number\" ? value : typeof value,\n normalized,\n });\n}\n","import { getCoreDiagnostics } from \"./diagnostics.js\";\n\n/** Narrow to a plain object (excludes arrays and null); undefined on mismatch. */\nexport function asRecord(value: unknown): Record<string, unknown> | undefined {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return undefined;\n}\n\n/** Narrow to a string; undefined on mismatch. */\nexport function asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\n/** Narrow to a finite number (rejects NaN/Infinity); undefined on mismatch. */\nexport function asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\n/** Narrow to an array; undefined on mismatch. */\nexport function asArray(value: unknown): unknown[] | undefined {\n return Array.isArray(value) ? value : undefined;\n}\n\n/**\n * Parses JSON text to a plain object; undefined on parse failure or a\n * non-object shape (e.g. array, string, null). Callers that need drift\n * reporting compose this with `narrowField`.\n */\nexport function safeParseJsonRecord(json: string): Record<string, unknown> | undefined {\n let raw: unknown;\n try {\n raw = JSON.parse(json);\n } catch {\n return undefined;\n }\n return asRecord(raw);\n}\n\nconst reportedFieldMismatches = new Set<string>();\n\n/**\n * Reports a field shape mismatch once per (agentName, field) for the life of\n * the process — an upstream format drift hits every line of a session file,\n * and warning per line would flood the diagnostics sink for no added signal.\n */\nexport function reportFieldMismatch(agentName: string, field: string): void {\n const key = `${agentName}\\0${field}`;\n if (reportedFieldMismatches.has(key)) return;\n reportedFieldMismatches.add(key);\n getCoreDiagnostics()?.warn(\"agent.field_shape_mismatch\", { agentName, field });\n}\n\n/**\n * Narrows a field's value with `narrow`, reporting once via\n * `reportFieldMismatch` when the field is present but narrowing fails.\n * `undefined`/`null` mean the field is absent (null-as-absent) and return\n * undefined silently — that's a normal shape, not drift.\n */\nexport function narrowField<T>(\n agent: string,\n field: string,\n value: unknown,\n narrow: (v: unknown) => T | undefined,\n): T | undefined {\n if (value === undefined || value === null) return undefined;\n const result = narrow(value);\n if (result === undefined) reportFieldMismatch(agent, field);\n return result;\n}\n","import type {\n Message,\n MessagePart,\n SessionStats,\n ToolPart,\n ToolPartStatus,\n} from \"../types/index.js\";\nimport { cleanParsedMessages } from \"../utils/session-normalization.js\";\n\nexport interface TranscriptMessageInput {\n id: string;\n role: Message[\"role\"];\n timestampMs: number;\n parts?: MessagePart[];\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n tokens?: Message[\"tokens\"];\n cost?: number;\n costSource?: Message[\"cost_source\"];\n subagentId?: string;\n nickname?: string;\n}\n\nexport type AssistantMessageInput = Omit<TranscriptMessageInput, \"role\" | \"parts\">;\n\nexport interface ToolResolution {\n output?: unknown;\n status?: ToolPartStatus;\n metadata?: unknown;\n consume?: boolean;\n}\n\nexport interface TranscriptResult {\n messages: Message[];\n stats: SessionStats;\n}\n\nfunction mergeTokens(base: Message[\"tokens\"], extra: Message[\"tokens\"]): Message[\"tokens\"] {\n if (!base) return extra;\n if (!extra) return base;\n const merged = { ...base };\n for (const key of Object.keys(extra) as (keyof NonNullable<Message[\"tokens\"]>)[]) {\n const value = extra[key];\n if (typeof value === \"number\") merged[key] = (merged[key] ?? 0) + value;\n }\n return merged;\n}\n\ninterface PartFlags {\n hasText: boolean;\n hasTool: boolean;\n}\n\nexport class TranscriptBuilder {\n private readonly messages: Message[] = [];\n private readonly pendingToolCalls = new Map<string, ToolPart>();\n // Tracks per-message part kinds so grouping checks are O(1) instead of\n // rescanning the growing parts array on every append (CS-283).\n private readonly partFlags = new WeakMap<Message, PartFlags>();\n private currentAssistant: Message | null = null;\n private latestTextAssistant: Message | null = null;\n\n constructor(private readonly options: { messageDefaults?: \"nullable\" | \"sparse\" } = {}) {}\n\n beginTurn(): void {\n this.currentAssistant = null;\n this.latestTextAssistant = null;\n }\n\n appendMessage(input: TranscriptMessageInput): Message {\n const message = this.createMessage(input);\n this.messages.push(message);\n for (const part of message.parts) {\n this.registerToolCall(part);\n this.notePart(message, part);\n }\n\n if (message.role === \"assistant\") {\n this.currentAssistant = message;\n if (this.flagsFor(message).hasText) {\n this.latestTextAssistant = message;\n }\n } else if (message.role === \"user\") {\n this.beginTurn();\n }\n\n return message;\n }\n\n appendAssistantPart(\n part: MessagePart,\n input: AssistantMessageInput,\n options: {\n grouping?: \"compatible\" | \"current\";\n resetLatestText?: boolean;\n deduplicateTail?: boolean;\n } = {},\n ): Message {\n const current = this.currentAssistant;\n const currentFlags = current === null ? null : this.flagsFor(current);\n const canReuse =\n current !== null &&\n (options.grouping === \"current\" ||\n (part.type === \"text\"\n ? !currentFlags!.hasTool\n : part.type === \"reasoning\"\n ? !currentFlags!.hasText && !currentFlags!.hasTool\n : false));\n\n const message = canReuse\n ? current\n : this.appendMessage({ ...input, role: \"assistant\", parts: [part] });\n\n if (canReuse) {\n if (options.deduplicateTail) this.appendPartIfNew(message, part);\n else this.pushPart(message, part);\n this.applyMissingMetadata(message, input);\n }\n if (part.type === \"text\") {\n this.latestTextAssistant = message;\n } else if (options.resetLatestText) {\n this.latestTextAssistant = null;\n }\n return message;\n }\n\n appendToolCall(\n part: ToolPart,\n input: AssistantMessageInput,\n options: {\n markModeAsTool?: boolean;\n modeOnCreate?: string;\n target?: \"latest-text\" | \"current\";\n } = {},\n ): Message {\n const target =\n options.target === \"current\"\n ? this.currentAssistant\n : (this.latestTextAssistant ?? this.currentAssistant);\n const message = target\n ? target\n : this.appendMessage({\n ...input,\n role: \"assistant\",\n mode: options.modeOnCreate ?? (options.markModeAsTool ? \"tool\" : input.mode),\n parts: [part],\n });\n\n if (target) {\n this.pushPart(message, part);\n this.applyMissingMetadata(message, input);\n if (options.markModeAsTool) message.mode = \"tool\";\n this.registerToolCall(part);\n }\n\n this.currentAssistant = message;\n return message;\n }\n\n appendToCurrentAssistant(part: MessagePart): boolean {\n if (!this.currentAssistant) return false;\n this.pushPart(this.currentAssistant, part);\n return true;\n }\n\n updateToolCall(callId: string, update: (part: ToolPart) => void): boolean {\n const part = this.pendingToolCalls.get(callId);\n if (!part) return false;\n update(part);\n return true;\n }\n\n resolveToolCall(callId: string, resolution: ToolResolution): boolean {\n return this.updateToolCall(callId, (part) => {\n const state = part.state;\n if (resolution.output !== undefined) state.output = resolution.output;\n if (resolution.status !== undefined) state.status = resolution.status;\n else if (resolution.output !== undefined && state.status === \"running\") {\n state.status = \"completed\";\n }\n if (resolution.metadata !== undefined) state.metadata = resolution.metadata;\n if (resolution.consume) this.pendingToolCalls.delete(callId);\n });\n }\n\n attachUsageToLatestAssistant(\n tokens: Message[\"tokens\"],\n options: { model?: string | null; cost?: number; costSource?: Message[\"cost_source\"] } = {},\n ): boolean {\n let mergeTarget: Message | null = null;\n for (let index = this.messages.length - 1; index >= 0; index -= 1) {\n const message = this.messages[index]!;\n if (message.role !== \"assistant\") continue;\n if (!message.tokens) {\n message.tokens = tokens;\n if (options.model !== undefined) message.model ??= options.model;\n if (options.cost !== undefined) message.cost = options.cost;\n if (options.costSource !== undefined) message.cost_source = options.costSource;\n return true;\n }\n if (!mergeTarget && (message.model ?? null) === (options.model ?? null)) {\n mergeTarget = message;\n }\n }\n // A turn can report usage more often than it produces assistant messages;\n // folding the surplus into the latest same-model message keeps its tokens\n // and cost attributed instead of silently dropping them.\n if (!mergeTarget) return false;\n mergeTarget.tokens = mergeTokens(mergeTarget.tokens, tokens);\n if (options.cost !== undefined) {\n mergeTarget.cost = (mergeTarget.cost ?? 0) + options.cost;\n if (options.costSource !== undefined) mergeTarget.cost_source ??= options.costSource;\n }\n return true;\n }\n\n finish(baseStats?: SessionStats): TranscriptResult {\n const messages = cleanParsedMessages(this.messages);\n const derived = this.deriveStats(messages);\n if (!baseStats) return { messages, stats: derived };\n\n return {\n messages,\n stats: {\n ...derived,\n ...baseStats,\n message_count: messages.length,\n cost_source: baseStats.cost_source,\n },\n };\n }\n\n private createMessage(input: TranscriptMessageInput): Message {\n const sparse = this.options.messageDefaults === \"sparse\";\n return {\n id: input.id,\n role: input.role,\n agent: sparse ? input.agent : (input.agent ?? null),\n time_created: input.timestampMs,\n mode: sparse ? input.mode : (input.mode ?? null),\n model: sparse ? input.model : (input.model ?? null),\n provider: sparse ? input.provider : (input.provider ?? null),\n tokens: input.tokens,\n cost: sparse ? input.cost : (input.cost ?? 0),\n cost_source: input.costSource,\n parts: input.parts ?? [],\n subagent_id: input.subagentId,\n nickname: input.nickname,\n };\n }\n\n private registerToolCall(part: MessagePart): void {\n if (part.type === \"tool\" && part.callID) {\n this.pendingToolCalls.set(part.callID, part);\n }\n }\n\n private appendPartIfNew(message: Message, part: MessagePart): void {\n const tail = message.parts.at(-1);\n if (\"text\" in part && tail?.type === part.type && \"text\" in tail && tail.text === part.text) {\n return;\n }\n this.pushPart(message, part);\n }\n\n private pushPart(message: Message, part: MessagePart): void {\n message.parts.push(part);\n this.notePart(message, part);\n }\n\n private notePart(message: Message, part: MessagePart): void {\n const flags = this.flagsFor(message);\n if (part.type === \"text\") flags.hasText = true;\n else if (part.type === \"tool\") flags.hasTool = true;\n }\n\n private flagsFor(message: Message): PartFlags {\n let flags = this.partFlags.get(message);\n if (!flags) {\n flags = { hasText: false, hasTool: false };\n this.partFlags.set(message, flags);\n }\n return flags;\n }\n\n private applyMissingMetadata(message: Message, input: AssistantMessageInput): void {\n if (!message.id && input.id) message.id = input.id;\n if (message.agent == null && input.agent !== undefined) message.agent = input.agent;\n if (message.mode == null && input.mode !== undefined) message.mode = input.mode;\n if (message.model == null && input.model !== undefined) message.model = input.model;\n if (message.provider == null && input.provider !== undefined) message.provider = input.provider;\n if (!message.tokens && input.tokens) message.tokens = input.tokens;\n if ((message.cost ?? 0) === 0 && input.cost !== undefined) message.cost = input.cost;\n if (!message.cost_source && input.costSource) message.cost_source = input.costSource;\n }\n\n private deriveStats(messages: Message[]): SessionStats {\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCacheCreateTokens = 0;\n let totalCost = 0;\n let hasEstimatedCost = false;\n\n for (const message of messages) {\n totalInputTokens += message.tokens?.input ?? 0;\n totalOutputTokens += message.tokens?.output ?? 0;\n totalCacheReadTokens += message.tokens?.cache_read ?? 0;\n totalCacheCreateTokens += message.tokens?.cache_create ?? 0;\n totalCost += message.cost ?? 0;\n if (message.cost_source === \"estimated\") hasEstimatedCost = true;\n }\n\n return {\n message_count: messages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cache_create_tokens: totalCacheCreateTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? (hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n };\n }\n}\n","import { join } from \"node:path\";\nimport { firstExisting, resolveDataHome } from \"../discovery/paths.js\";\nimport { isSqliteAvailable } from \"../utils/sqlite.js\";\nimport { OpenCodeSqliteAgent } from \"./opencode-sqlite.js\";\n\nexport function resolveOpenCodeDataRoot(): string {\n return join(resolveDataHome(), \"opencode\");\n}\n\nfunction findOpenCodeDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n return firstExisting(join(resolveOpenCodeDataRoot(), \"opencode.db\"), \"data/opencode/opencode.db\");\n}\n\nfunction getOpenCodeSessionWatchPlan() {\n const dataRoot = resolveOpenCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { root: dataRoot, path: join(dataRoot, \"opencode.db\") },\n { root: \"data/opencode\", path: \"data/opencode/opencode.db\" },\n ],\n };\n}\n\nexport class OpenCodeAgent extends OpenCodeSqliteAgent {\n constructor() {\n super({\n name: \"opencode\",\n displayName: \"OpenCode\",\n findDbPath: findOpenCodeDbPath,\n getSessionWatchPlan: getOpenCodeSessionWatchPlan,\n });\n }\n}\n","/**\n * SQLite helper — graceful degradation if better-sqlite3 is unavailable.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { getCoreDiagnostics } from \"./diagnostics.js\";\nimport {\n ensurePrivateDirectory,\n restrictPrivateDatabase,\n restrictPrivateFile,\n} from \"./private-storage.js\";\n\ninterface SQLiteStatement {\n all(...params: unknown[]): DatabaseRow[];\n get(...params: unknown[]): DatabaseRow | undefined;\n /** Streams rows so a large result set never has to be materialized at once. */\n iterate(...params: unknown[]): IterableIterator<DatabaseRow>;\n run(...params: unknown[]): unknown;\n}\n\ninterface SQLiteTransaction {\n (...params: unknown[]): unknown;\n}\n\nexport interface SQLiteTransactionRunner<T extends SQLiteTransaction> {\n (...params: Parameters<T>): ReturnType<T>;\n /**\n * BEGIN IMMEDIATE: takes the write lock up front so busy_timeout governs the\n * wait. A deferred write transaction that reads first can die instantly with\n * SQLITE_BUSY_SNAPSHOT when another connection commits in between.\n */\n immediate(...params: Parameters<T>): ReturnType<T>;\n}\n\ninterface SQLitePragmaCapable {\n pragma(sql: string): unknown;\n}\n\ntype SQLiteDatabaseConstructor = (\n path: string,\n options?: { readonly?: boolean },\n) => SQLiteDatabase & SQLitePragmaCapable;\n\nconst SQLITE_BUSY_TIMEOUT_MS = 5000;\n\nlet DatabaseConstructor: SQLiteDatabaseConstructor | null = null;\nlet loadErrorMessage: string | null = null;\n\ntry {\n const require = createRequire(import.meta.url);\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require(\"better-sqlite3\");\n DatabaseConstructor = (\n typeof mod === \"function\" ? mod : (mod as { default?: unknown }).default\n ) as SQLiteDatabaseConstructor;\n} catch (error) {\n // better-sqlite3 not installed — adapters that need SQLite will gracefully skip.\n // This module body evaluates before a host has a chance to call\n // setCoreDiagnostics, so reporting here would always be dropped — defer the\n // warn to reportUnavailableOnce(), called from the first actual open attempt.\n loadErrorMessage = error instanceof Error ? error.message : String(error);\n}\n\nlet unavailableReported = false;\n\nfunction reportUnavailableOnce(): void {\n if (unavailableReported) return;\n unavailableReported = true;\n getCoreDiagnostics()?.warn(\"sqlite.unavailable\", { message: loadErrorMessage });\n}\n\nexport interface DatabaseRow {\n [key: string]: unknown;\n}\n\nexport interface SQLiteDatabase {\n prepare(sql: string): SQLiteStatement;\n function(\n name: string,\n options: { deterministic?: boolean },\n callback: (...params: unknown[]) => unknown,\n ): void;\n exec(sql: string): void;\n transaction<T extends SQLiteTransaction>(fn: T): SQLiteTransactionRunner<T>;\n close(): void;\n}\n\nexport interface SchemaMigration {\n version: number;\n destructive?: boolean;\n migrate(db: SQLiteDatabase): void;\n}\n\nexport interface RunSchemaMigrationsOptions {\n dbPath: string;\n currentVersion: number;\n targetVersion: number;\n migrations: SchemaMigration[];\n backupTables: string[];\n backupLabel: string;\n}\n\nfunction quoteIdentifier(value: string): string {\n return `\"${value.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction quoteSqlString(value: string): string {\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nfunction isInMemoryPath(dbPath: string): boolean {\n return (\n dbPath === \":memory:\" || dbPath.startsWith(\"file::memory:\") || dbPath.includes(\"mode=memory\")\n );\n}\n\nexport function getUserVersion(db: SQLiteDatabase): number {\n const row = db.prepare(\"PRAGMA user_version\").get() as DatabaseRow | undefined;\n return Number(row?.user_version ?? 0);\n}\n\nexport function setUserVersion(db: SQLiteDatabase, version: number): void {\n db.exec(`PRAGMA user_version = ${Math.trunc(version)}`);\n}\n\nexport function tableExists(db: SQLiteDatabase, tableName: string): boolean {\n const row = db\n .prepare(\n `\n SELECT 1 AS value\n FROM sqlite_master\n WHERE name = ? AND type IN ('table', 'view')\n LIMIT 1\n `,\n )\n .get(tableName) as DatabaseRow | undefined;\n return row !== undefined;\n}\n\nexport function columnExists(db: SQLiteDatabase, tableName: string, columnName: string): boolean {\n if (!tableExists(db, tableName)) {\n return false;\n }\n\n const rows = db.prepare(`PRAGMA table_info(${quoteIdentifier(tableName)})`).all();\n return rows.some((row) => String(row.name) === columnName);\n}\n\nexport function tableHasRows(db: SQLiteDatabase, tableName: string): boolean {\n if (!tableExists(db, tableName)) {\n return false;\n }\n\n const row = db.prepare(`SELECT 1 AS value FROM ${quoteIdentifier(tableName)} LIMIT 1`).get() as\n | DatabaseRow\n | undefined;\n return row !== undefined;\n}\n\nexport function backupDatabase(db: SQLiteDatabase, dbPath: string, label: string): string | null {\n if (isInMemoryPath(dbPath)) {\n return null;\n }\n\n const timestamp = new Date(Date.now()).toISOString().replaceAll(\":\", \"\").replaceAll(\".\", \"-\");\n let backupPath = join(dirname(dbPath), `${basename(dbPath)}.${timestamp}.${label}.bak`);\n for (let counter = 1; existsSync(backupPath); counter += 1) {\n backupPath = join(dirname(dbPath), `${basename(dbPath)}.${timestamp}.${label}.${counter}.bak`);\n }\n db.exec(`VACUUM INTO ${quoteSqlString(backupPath)}`);\n // A fresh inode does not inherit the source database's mode.\n restrictPrivateFile(backupPath);\n return backupPath;\n}\n\nexport function backupDatabaseIfPopulated(\n db: SQLiteDatabase,\n dbPath: string,\n label: string,\n tables: string[],\n): string | null {\n if (!tables.some((table) => tableHasRows(db, table))) {\n return null;\n }\n\n return backupDatabase(db, dbPath, label);\n}\n\nexport function runSchemaMigrations(\n db: SQLiteDatabase,\n options: RunSchemaMigrationsOptions,\n): string[] {\n const backups: string[] = [];\n let currentVersion = options.currentVersion;\n\n for (const migration of options.migrations) {\n if (migration.version <= currentVersion) {\n continue;\n }\n if (migration.version > options.targetVersion) {\n break;\n }\n\n const fromVersion = currentVersion;\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.migration.started\", {\n label: options.backupLabel,\n from_version: fromVersion,\n to_version: migration.version,\n destructive: migration.destructive ?? false,\n });\n\n try {\n let backupCreated = false;\n if (migration.destructive) {\n const backupPath = backupDatabaseIfPopulated(\n db,\n options.dbPath,\n options.backupLabel,\n options.backupTables,\n );\n if (backupPath) {\n backups.push(backupPath);\n backupCreated = true;\n }\n }\n\n const apply = db.transaction(() => {\n migration.migrate(db);\n setUserVersion(db, migration.version);\n });\n apply.immediate();\n currentVersion = migration.version;\n getCoreDiagnostics()?.info?.(\"sqlite.migration.completed\", {\n label: options.backupLabel,\n from_version: fromVersion,\n to_version: migration.version,\n destructive: migration.destructive ?? false,\n backup_created: backupCreated,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.migration.failed\", {\n label: options.backupLabel,\n from_version: fromVersion,\n to_version: migration.version,\n destructive: migration.destructive ?? false,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n if (currentVersion < options.targetVersion) {\n setUserVersion(db, options.targetVersion);\n }\n\n return backups;\n}\n\n/**\n * Open a SQLite database in read-only mode.\n * Returns null if better-sqlite3 is unavailable or the file can't be opened.\n */\nexport function openDbReadOnly(dbPath: string): SQLiteDatabase | null {\n if (!DatabaseConstructor) {\n reportUnavailableOnce();\n return null;\n }\n try {\n const db = DatabaseConstructor(dbPath, { readonly: true });\n try {\n db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);\n } catch {\n // The handle remains usable when SQLite rejects connection-level tuning.\n }\n return db;\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.open_failed\", {\n dbPath,\n readonly: true,\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n}\n\nexport function openDb(dbPath: string): SQLiteDatabase | null {\n if (!DatabaseConstructor) {\n reportUnavailableOnce();\n return null;\n }\n try {\n ensurePrivateDirectory(dirname(dbPath));\n const db = DatabaseConstructor(dbPath);\n // The sidecars only exist once the connection is established.\n restrictPrivateDatabase(dbPath);\n try {\n // busy_timeout first: if a later pragma throws, writes must still wait for\n // concurrent writers instead of failing instantly with SQLITE_BUSY.\n db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"synchronous = NORMAL\");\n db.pragma(\"foreign_keys = ON\");\n } catch {\n // The database remains usable when SQLite rejects connection-level tuning.\n }\n return db;\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.open_failed\", {\n dbPath,\n readonly: false,\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n}\n\n/**\n * Check if SQLite support is available.\n */\nexport function isSqliteAvailable(): boolean {\n return DatabaseConstructor !== null;\n}\n","import {\n DatabaseSessionSource,\n SessionScanError,\n filteredSession,\n getParsedSession,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n ChangeCheckResult,\n ParseSessionResult,\n SessionWatchPlan,\n} from \"./base.js\";\nimport type { SessionHead, SessionDetail, Message, MessagePart } from \"../types/index.js\";\nimport { normalizeMessageParts } from \"../contract/message-part.js\";\nimport { capturePricingMisses } from \"../pricing/cost.js\";\nimport { columnExists, openDbReadOnly, type SQLiteDatabase } from \"../utils/sqlite.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { asRecord, asString, narrowField, reportFieldMismatch } from \"../utils/narrow.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport {\n cleanMessagePart,\n cleanParsedMessages,\n firstUserMessageTitle,\n} from \"../utils/session-normalization.js\";\n\ninterface OpenCodeMessageRow {\n id?: unknown;\n session_id?: unknown;\n data?: string;\n time_created?: unknown;\n}\n\ninterface OpenCodePartRow {\n message_id?: unknown;\n data?: string;\n time_created?: unknown;\n}\n\ninterface OpenCodeHeadContext {\n stats: SessionHead[\"stats\"];\n messageTitle: string | null;\n unpricedModels: Set<string>;\n}\n\ninterface OpenCodeSqliteAgentConfig {\n name: string;\n displayName: string;\n findDbPath: () => string | null;\n getSessionWatchPlan: () => SessionWatchPlan;\n}\n\nconst MESSAGE_ROLES = new Set<Message[\"role\"]>([\"user\", \"assistant\", \"tool\"]);\nconst SESSION_ID_QUERY_CHUNK_SIZE = 500;\nconst HEAD_PARSER_VERSION = \"opencode-sqlite-head-v1\";\n\nfunction compareSessionRowsByActivityDesc(\n left: Record<string, unknown>,\n right: Record<string, unknown>,\n): number {\n const leftUpdated = Number(left.time_updated ?? left.time_created ?? 0);\n const rightUpdated = Number(right.time_updated ?? right.time_created ?? 0);\n return (\n rightUpdated - leftUpdated ||\n Number(right.time_created ?? 0) - Number(left.time_created ?? 0) ||\n String(right.id ?? \"\").localeCompare(String(left.id ?? \"\"))\n );\n}\n\nfunction accumulateTokenStats(\n stats: SessionHead[\"stats\"],\n msgData: Record<string, unknown>,\n agentName: string,\n): void {\n const cost = Number(msgData.cost ?? 0);\n const tokens = parseTokens(msgData.tokens, agentName);\n const inputTokens = Number(tokens?.input ?? 0);\n const outputTokens = Number(tokens?.output ?? 0);\n const model = parseModel(msgData.modelID, agentName);\n const estimatedCost =\n cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });\n\n if (estimatedCost !== null) stats.cost_source = \"estimated\";\n stats.total_cost += cost || estimatedCost || 0;\n stats.total_input_tokens += inputTokens;\n stats.total_output_tokens += outputTokens;\n}\n\n/** Parses a SQLite `data` JSON column; non-object payloads fall back to `{}` (reported as drift). */\nfunction parseJsonRecord(raw: unknown, agentName: string, field: string): Record<string, unknown> {\n const parsed = asRecord(JSON.parse(String(raw ?? \"{}\")));\n if (parsed) return parsed;\n reportFieldMismatch(agentName, field);\n return {};\n}\n\nfunction narrowMessageRole(value: unknown): Message[\"role\"] | undefined {\n const role = asString(value);\n return role !== undefined && (MESSAGE_ROLES as Set<string>).has(role)\n ? (role as Message[\"role\"])\n : undefined;\n}\n\nfunction parseMessageRole(value: unknown, agentName: string): Message[\"role\"] {\n return narrowField(agentName, \"message.role\", value, narrowMessageRole) ?? \"assistant\";\n}\n\nfunction parseTokens(value: unknown, agentName: string): Record<string, unknown> | undefined {\n return narrowField(agentName, \"message.tokens\", value, asRecord);\n}\n\nfunction parseModel(value: unknown, agentName: string): string | null {\n return narrowField(agentName, \"message.modelID\", value, asString) ?? null;\n}\n\nexport class OpenCodeSqliteAgent extends DatabaseSessionSource {\n readonly name: string;\n readonly displayName: string;\n\n private dbPath: string | null = null;\n\n constructor(private readonly config: OpenCodeSqliteAgentConfig) {\n super();\n this.name = config.name;\n this.displayName = config.displayName;\n }\n\n protected getDatabasePath(): string | null {\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n return this.dbPath;\n }\n\n getSessionWatchPlan(): SessionWatchPlan {\n return this.config.getSessionWatchPlan();\n }\n\n private findDbPath(): string | null {\n return this.config.findDbPath();\n }\n\n isAvailable(): boolean {\n this.dbPath = this.findDbPath();\n return this.dbPath !== null;\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n if (!this.dbPath) return [];\n\n const db = openDbReadOnly(this.dbPath);\n if (!db) throw new SessionScanError(this.name, \"opening the database\");\n\n try {\n const cutoffTime = options?.from ?? Date.now() - 3650 * 24 * 60 * 60 * 1000;\n const activityPredicate =\n options?.to == null\n ? \"COALESCE(s.time_updated, s.time_created) >= ?\"\n : \"COALESCE(s.time_updated, s.time_created) >= ? AND COALESCE(s.time_updated, s.time_created) <= ?\";\n const activityBindings = options?.to == null ? [cutoffTime] : [cutoffTime, options.to];\n\n const hasMessageTable = Boolean(\n db\n .prepare(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'message'\")\n .get(),\n );\n\n const hasTaskType = columnExists(db, \"session\", \"task_type\");\n const hasParentId = columnExists(db, \"session\", \"parent_id\");\n const childPredicate = hasParentId\n ? \"AND s.parent_id IS NULL\"\n : hasTaskType\n ? \"AND (s.task_type IS NULL OR s.task_type != 'subagent_child')\"\n : \"\";\n\n let rows: Record<string, unknown>[];\n const parentIdSelect = hasParentId ? \", s.parent_id\" : \"\";\n if (hasMessageTable) {\n rows = db\n .prepare(`\n SELECT\n s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files${parentIdSelect}\n FROM session s\n WHERE ${activityPredicate}\n ${childPredicate}\n ORDER BY COALESCE(s.time_updated, s.time_created) DESC, s.time_created DESC, s.id DESC\n `)\n .all(...activityBindings);\n } else {\n rows = db\n .prepare(`\n SELECT s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files, 0 AS message_count, NULL AS model_message_data${parentIdSelect}\n FROM session s\n WHERE ${activityPredicate}\n ${childPredicate}\n ORDER BY COALESCE(s.time_updated, s.time_created) DESC, s.time_created DESC, s.id DESC\n `)\n .all(...activityBindings);\n }\n\n if (hasParentId && options?.includeRelatedSessions !== false) {\n const rootIds = rows.map((row) => String(row.id ?? \"\")).filter(Boolean);\n const relatedRows = this.readRelatedSessionRows(db, rootIds);\n const knownIds = new Set(rootIds);\n rows.push(...relatedRows.filter((row) => !knownIds.has(String(row.id ?? \"\"))));\n }\n\n rows.sort(compareSessionRowsByActivityDesc);\n\n const sessionIds = new Set(rows.map((row) => String(row.id ?? \"\")).filter(Boolean));\n\n const headContexts = hasMessageTable\n ? this.buildHeadContexts(\n this.readHeadMessageRows(db, cutoffTime, sessionIds.size > 0 ? sessionIds : undefined),\n this.readHeadPartRows(db, cutoffTime, sessionIds.size > 0 ? sessionIds : undefined),\n )\n : new Map<string, OpenCodeHeadContext>();\n const heads: SessionHead[] = [];\n options?.onProgress?.({ total: rows.length, processed: 0, sessions: 0 });\n let processed = 0;\n for (const row of rows) {\n const context = headContexts.get(String(row.id ?? \"\"));\n const head = getParsedSession(this.parseSessionHeadRow(row, hasMessageTable, context));\n if (head) {\n heads.push(head);\n this.rememberSession(head.id, {\n headParserVersion: HEAD_PARSER_VERSION,\n ...(context && context.unpricedModels.size > 0\n ? { unpricedModels: [...context.unpricedModels] }\n : {}),\n });\n }\n processed += 1;\n options?.onProgress?.({ total: rows.length, processed, sessions: heads.length });\n }\n\n return heads;\n } catch (error) {\n throw new SessionScanError(this.name, \"reading sessions\", { cause: error });\n } finally {\n db.close();\n }\n }\n\n private parseSessionHeadRow(\n row: Record<string, unknown>,\n hasMessageTable: boolean,\n context?: OpenCodeHeadContext,\n ): ParseSessionResult<SessionHead> {\n const id = String(row.id ?? \"\");\n if (!id) return skippedSession(\"missing session id\");\n\n const timeCreated = Number(row.time_created ?? 0);\n const timeUpdated = Number(row.time_updated ?? timeCreated);\n const stats = context?.stats ?? null;\n const messageCount = stats?.message_count ?? 0;\n if (hasMessageTable && messageCount === 0) return filteredSession(\"no visible messages\");\n const messageTitle = context?.messageTitle ?? null;\n\n return parsedSession({\n id,\n slug: this.sessionSlug(id),\n title: resolveSessionTitle(String(row.title ?? \"\"), messageTitle, null),\n directory: String(row.directory ?? \"\"),\n parent_reference:\n row.parent_id == null || String(row.parent_id) === \"\"\n ? undefined\n : { agentName: this.name, sessionId: String(row.parent_id) },\n time_created: timeCreated,\n time_updated: timeUpdated,\n stats: {\n message_count: messageCount,\n total_input_tokens: stats?.total_input_tokens ?? 0,\n total_output_tokens: stats?.total_output_tokens ?? 0,\n total_cost: stats?.total_cost ?? 0,\n cost_source: stats?.cost_source,\n },\n });\n }\n\n private readHeadMessageRows(\n db: SQLiteDatabase,\n cutoffTime: number,\n sessionIds?: Set<string>,\n ): OpenCodeMessageRow[] {\n const ids = sessionIds ? [...sessionIds] : [];\n if (ids.length === 0) {\n return db\n .prepare(\n `\n SELECT m.id, m.session_id, m.data, m.time_created\n FROM message m\n JOIN session s ON s.id = m.session_id\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ORDER BY m.session_id, m.time_created ASC\n `,\n )\n .all(cutoffTime) as OpenCodeMessageRow[];\n }\n\n const rows: OpenCodeMessageRow[] = [];\n for (let offset = 0; offset < ids.length; offset += SESSION_ID_QUERY_CHUNK_SIZE) {\n const chunk = ids.slice(offset, offset + SESSION_ID_QUERY_CHUNK_SIZE);\n rows.push(\n ...(db\n .prepare(\n `\n SELECT m.id, m.session_id, m.data, m.time_created\n FROM message m\n JOIN session s ON s.id = m.session_id\n WHERE s.id IN (${chunk.map(() => \"?\").join(\",\")})\n ORDER BY m.session_id, m.time_created ASC\n `,\n )\n .all(...chunk) as OpenCodeMessageRow[]),\n );\n }\n return rows;\n }\n\n private readHeadPartRows(\n db: SQLiteDatabase,\n cutoffTime: number,\n sessionIds?: Set<string>,\n ): OpenCodePartRow[] {\n const ids = sessionIds ? [...sessionIds] : [];\n if (ids.length === 0) {\n return db\n .prepare(\n `\n SELECT p.message_id, p.data, p.time_created\n FROM part p\n JOIN message m ON m.id = p.message_id\n JOIN session s ON s.id = m.session_id\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ORDER BY p.message_id, p.time_created ASC, p.id ASC\n `,\n )\n .all(cutoffTime) as OpenCodePartRow[];\n }\n\n const rows: OpenCodePartRow[] = [];\n for (let offset = 0; offset < ids.length; offset += SESSION_ID_QUERY_CHUNK_SIZE) {\n const chunk = ids.slice(offset, offset + SESSION_ID_QUERY_CHUNK_SIZE);\n rows.push(\n ...(db\n .prepare(\n `\n SELECT p.message_id, p.data, p.time_created\n FROM part p\n JOIN message m ON m.id = p.message_id\n JOIN session s ON s.id = m.session_id\n WHERE s.id IN (${chunk.map(() => \"?\").join(\",\")})\n ORDER BY p.message_id, p.time_created ASC, p.id ASC\n `,\n )\n .all(...chunk) as OpenCodePartRow[]),\n );\n }\n return rows;\n }\n\n private readRelatedSessionRows(db: SQLiteDatabase, rootIds: string[]): Record<string, unknown>[] {\n if (rootIds.length === 0) return [];\n\n const startedAt = performance.now();\n const relatedById = new Map<string, Record<string, unknown>>();\n let candidateRows = 0;\n let queryCount = 0;\n for (let offset = 0; offset < rootIds.length; offset += SESSION_ID_QUERY_CHUNK_SIZE) {\n const chunk = rootIds.slice(offset, offset + SESSION_ID_QUERY_CHUNK_SIZE);\n const rows = db\n .prepare(\n `\n WITH RECURSIVE related_sessions(\n id, title, time_created, time_updated, slug, directory,\n version, summary_files, parent_id\n ) AS (\n SELECT\n s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files, s.parent_id\n FROM session s\n WHERE s.parent_id IN (${chunk.map(() => \"?\").join(\",\")})\n\n UNION\n\n SELECT\n child.id, child.title, child.time_created, child.time_updated,\n child.slug, child.directory, child.version, child.summary_files, child.parent_id\n FROM session child\n JOIN related_sessions parent ON child.parent_id = parent.id\n )\n SELECT\n id, title, time_created, time_updated, slug, directory,\n version, summary_files, parent_id\n FROM related_sessions\n ORDER BY time_created ASC, id ASC\n `,\n )\n .all(...chunk) as Record<string, unknown>[];\n queryCount += 1;\n candidateRows += rows.length;\n for (const row of rows) {\n const id = String(row.id ?? \"\");\n if (id && !relatedById.has(id)) relatedById.set(id, row);\n }\n }\n const result = [...relatedById.values()];\n getCoreDiagnostics()?.info?.(\"agent.related_sessions.query\", {\n agent_name: this.name,\n root_count: rootIds.length,\n query_count: queryCount,\n candidate_rows: candidateRows,\n related_rows: result.length,\n duration_ms: Number((performance.now() - startedAt).toFixed(2)),\n });\n return result;\n }\n\n private parsePartRow(\n partRow: Pick<OpenCodePartRow, \"data\" | \"time_created\">,\n ): MessagePart | null {\n const partData = parseJsonRecord(partRow.data, this.name, \"part.data\");\n const partType = String(partData.type ?? \"\");\n if (isInternalEventType(partType)) return null;\n const [part] = normalizeMessageParts([\n { ...partData, time_created: Number(partRow.time_created ?? 0) },\n ]);\n return part ? cleanMessagePart(part) : null;\n }\n\n /**\n * Every part of one session in a single read. Fetching per message turned a\n * detail into M+2 queries, and without an index on part(message_id) each one\n * scanned the whole table.\n */\n private readSessionPartRows(db: SQLiteDatabase, sessionId: string): OpenCodePartRow[] {\n return db\n .prepare(\n `\n SELECT p.message_id, p.data, p.time_created\n FROM part p\n JOIN message m ON m.id = p.message_id\n WHERE m.session_id = ?\n ORDER BY p.message_id, p.time_created ASC, p.id ASC\n `,\n )\n .all(sessionId) as OpenCodePartRow[];\n }\n\n private buildPartsByMessage(partRows: OpenCodePartRow[]): Map<string, MessagePart[]> {\n const partsByMessage = new Map<string, MessagePart[]>();\n for (const row of partRows) {\n const messageId = String(row.message_id ?? \"\");\n if (!messageId) continue;\n const part = this.parsePartRow(row);\n if (!part) continue;\n const parts = partsByMessage.get(messageId);\n if (parts) {\n parts.push(part);\n } else {\n partsByMessage.set(messageId, [part]);\n }\n }\n return partsByMessage;\n }\n\n private buildHeadContexts(\n messageRows: OpenCodeMessageRow[],\n partRows: OpenCodePartRow[],\n ): Map<string, OpenCodeHeadContext> {\n const partsByMessage = this.buildPartsByMessage(partRows);\n const contexts = new Map<string, OpenCodeHeadContext>();\n\n const ensureContext = (sessionId: string): OpenCodeHeadContext => {\n let context = contexts.get(sessionId);\n if (!context) {\n context = {\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n messageTitle: null,\n unpricedModels: new Set(),\n };\n contexts.set(sessionId, context);\n }\n return context;\n };\n\n for (const row of messageRows) {\n const sessionId = String(row.session_id ?? \"\");\n if (!sessionId) continue;\n const msgData = parseJsonRecord(row.data, this.name, \"message.data\");\n if (isInternalEventType(msgData.type)) continue;\n\n const parts = partsByMessage.get(String(row.id ?? \"\")) ?? [];\n if (parts.length === 0) continue;\n\n const context = ensureContext(sessionId);\n const { unpricedModels } = capturePricingMisses(() =>\n accumulateTokenStats(context.stats, msgData, this.name),\n );\n for (const model of unpricedModels) context.unpricedModels.add(model);\n context.stats.message_count += 1;\n\n if (!context.messageTitle && String(msgData.role ?? \"\") === \"user\") {\n context.messageTitle = firstUserMessageTitle([\n {\n id: String(row.id ?? \"\"),\n role: \"user\",\n agent: null,\n time_created: Number(row.time_created ?? 0),\n parts,\n },\n ]);\n }\n }\n\n for (const context of contexts.values()) {\n if (context.stats.total_cost > 0 && context.stats.cost_source !== \"estimated\") {\n context.stats.cost_source = \"recorded\";\n }\n }\n\n return contexts;\n }\n\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const hasStaleHead = cachedSessions.some(\n (session) => this.sessionMetaMap.get(session.id)?.headParserVersion !== HEAD_PARSER_VERSION,\n );\n if (hasStaleHead) return { hasChanges: true, timestamp: Date.now() };\n return super.checkForChanges(sinceTimestamp, cachedSessions);\n }\n\n private sumChildTokenStats(db: SQLiteDatabase, parentSessionId: string): SessionHead[\"stats\"][] {\n if (!columnExists(db, \"session\", \"parent_id\")) return [];\n\n const childRows = this.readRelatedSessionRows(db, [parentSessionId]).filter(\n (row) => String(row.id ?? \"\") !== parentSessionId,\n );\n\n const results: SessionHead[\"stats\"][] = [];\n for (const child of childRows) {\n const childId = String(child.id ?? \"\");\n if (!childId) continue;\n const msgRows = db\n .prepare(\"SELECT data FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(childId) as OpenCodeMessageRow[];\n const stats: SessionHead[\"stats\"] = {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n };\n for (const row of msgRows) {\n const msgData = parseJsonRecord(row.data, this.name, \"message.data\");\n if (isInternalEventType(msgData.type)) continue;\n accumulateTokenStats(stats, msgData, this.name);\n }\n results.push(stats);\n }\n return results;\n }\n\n getSessionData(sessionId: string): SessionDetail {\n // Ensure dbPath is set\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath) {\n throw new Error(`${this.displayName} database is missing`);\n }\n\n const db = openDbReadOnly(this.dbPath);\n if (!db) {\n throw new Error(`${this.displayName} database is missing`);\n }\n\n try {\n // First get session metadata\n const sessionRow = db.prepare(\"SELECT * FROM session WHERE id = ?\").get(sessionId) as\n | Record<string, unknown>\n | undefined;\n if (!sessionRow) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const id = String(sessionRow.id ?? sessionId);\n const slug = `${this.name}/${id}`;\n const directory = String(sessionRow.directory ?? \"\");\n const timeCreated = Number(sessionRow.time_created ?? 0);\n const timeUpdated = Number(sessionRow.time_updated ?? timeCreated);\n\n const messages: Message[] = [];\n let hasEstimatedCost = false;\n\n // Get messages\n const msgRows = db\n .prepare(\"SELECT * FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(sessionId) as Record<string, unknown>[];\n const partsByMessage = this.buildPartsByMessage(this.readSessionPartRows(db, sessionId));\n\n for (const msgRow of msgRows) {\n const msgData = parseJsonRecord(msgRow.data, this.name, \"message.data\");\n if (isInternalEventType(msgData.type)) continue;\n\n const cost = Number(msgData.cost ?? 0);\n const tokens = parseTokens(msgData.tokens, this.name);\n const inputTokens = Number(tokens?.input ?? 0);\n const outputTokens = Number(tokens?.output ?? 0);\n const model = parseModel(msgData.modelID, this.name);\n const estimatedCost =\n cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });\n const resolvedCost = cost || estimatedCost || 0;\n\n const parts = partsByMessage.get(String(msgRow.id ?? \"\")) ?? [];\n if (parts.length === 0) continue;\n\n messages.push({\n id: String(msgRow.id ?? \"\"),\n role: parseMessageRole(msgData.role, this.name),\n agent: asString(msgData.agent) ?? null,\n mode: asString(msgData.mode) ?? null,\n model,\n provider: asString(msgData.providerID) ?? null,\n time_created: Number(msgRow.time_created ?? 0),\n tokens: tokens ? { input: inputTokens, output: outputTokens } : undefined,\n cost: resolvedCost,\n cost_source: resolvedCost > 0 ? (cost > 0 ? \"recorded\" : \"estimated\") : undefined,\n parts,\n });\n }\n\n const cleanedMessages = cleanParsedMessages(messages);\n const title = resolveSessionTitle(\n String(sessionRow.title ?? \"\"),\n firstUserMessageTitle(cleanedMessages),\n null,\n );\n const stats: SessionHead[\"stats\"] = {\n message_count: cleanedMessages.length,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n };\n for (const message of cleanedMessages) {\n stats.total_cost += message.cost ?? 0;\n stats.total_input_tokens += message.tokens?.input ?? 0;\n stats.total_output_tokens += message.tokens?.output ?? 0;\n if (message.cost_source === \"estimated\") hasEstimatedCost = true;\n }\n\n for (const childStats of this.sumChildTokenStats(db, sessionId)) {\n stats.total_cost += childStats.total_cost;\n stats.total_input_tokens += childStats.total_input_tokens;\n stats.total_output_tokens += childStats.total_output_tokens;\n if (childStats.cost_source === \"estimated\") hasEstimatedCost = true;\n }\n\n return {\n reference: { agentName: this.name, sessionId: id },\n id,\n title,\n slug,\n directory,\n parent_reference:\n sessionRow.parent_id == null || String(sessionRow.parent_id) === \"\"\n ? undefined\n : { agentName: this.name, sessionId: String(sessionRow.parent_id) },\n version: asString(sessionRow.version) ?? undefined,\n time_created: timeCreated,\n time_updated: timeUpdated,\n summary_files: sessionRow.summary_files ?? undefined,\n stats: {\n message_count: stats.message_count,\n total_input_tokens: stats.total_input_tokens,\n total_output_tokens: stats.total_output_tokens,\n total_cost: stats.total_cost,\n cost_source:\n stats.total_cost > 0 ? (hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n },\n messages: cleanedMessages,\n };\n } finally {\n db.close();\n }\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport {\n FileSystemSessionSource,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n ParseSessionResult,\n SessionCacheMeta,\n SessionSourceRef,\n} from \"./base.js\";\nimport type { SessionHead, SessionDetail, MessagePart } from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile } from \"../utils/jsonl.js\";\nimport { normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport {\n asArray,\n asNumber,\n asRecord,\n asString,\n narrowField,\n reportFieldMismatch,\n} from \"../utils/narrow.js\";\nimport { parseAgentTimestamp } from \"../utils/timestamp.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\nimport { normalizeToolArguments } from \"./tool-arguments.js\";\n\nconst KIMI_TOOL_TITLE_MAP: Record<string, string> = {\n ReadFile: \"read\",\n Glob: \"glob\",\n StrReplaceFile: \"edit\",\n Grep: \"grep\",\n WriteFile: \"write\",\n Shell: \"bash\",\n};\n\nconst KIMI_IGNORED_TOOLS = new Set([\"SetTodoList\"]);\nconst KIMI_PARSER_REVISION = \"kimi-parser-v2\";\n\nexport function resolveKimiDataRoot(): string {\n return resolveHomePath(\"KIMI_SHARE_DIR\", \".kimi\");\n}\n\nfunction mapToolTitle(toolName: string): string {\n return KIMI_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\n/**\n * 会话源的轻量视图:只需要目录遍历 + 小 JSON 文件(state/metadata)即可得出,\n * 不触碰 transcript。枚举路径(listSessionSources)每次刷新都会跑,只用这一层。\n */\ninterface SessionSource {\n id: string;\n sourcePath: string;\n cwd: string;\n contextFile: string | null;\n wireFile: string | null;\n createdAt: number;\n activityAt: number;\n metaFile: string;\n explicitTitle: string;\n}\n\ninterface SessionMeta extends SessionCacheMeta, SessionSource {\n title: string;\n sourceMtimeMs: number;\n}\n\n/** Reads state/metadata `wire_mtime`; reports drift when the field is present but not a number. */\nfunction readWireMtime(record: Record<string, unknown>): number | null {\n return narrowField(\"kimi\", \"session.wire_mtime\", record.wire_mtime, asNumber) ?? null;\n}\n\n/** Reads a wire record's `timestamp`; reports drift when the field is present but not a number. */\nfunction readWireTimestamp(record: Record<string, unknown>): number {\n return narrowField(\"kimi\", \"wire.timestamp\", record.timestamp, asNumber) ?? 0;\n}\n\nfunction parseTimestamp(raw: unknown): number | null {\n return parseAgentTimestamp(raw, \"kimi\", { numericStrings: true });\n}\n\n/** Reads a token count from a usage record; reports drift when the field is present but not a number. */\nfunction extractTokenField(usage: Record<string, unknown>, field: string): number {\n return narrowField(\"kimi\", `usage.${field}`, usage[field], asNumber) ?? 0;\n}\n\nclass KimiUsageAccumulator {\n readonly stats: SessionDetail[\"stats\"] = {\n total_cost: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_tokens: 0,\n message_count: 0,\n };\n\n private totalCost = 0;\n\n constructor(\n private readonly model: string | null,\n private readonly usesWireTotalFallback: boolean,\n ) {}\n\n applyContextRecord(record: Record<string, unknown>): void {\n if (record.role !== \"_usage\") return;\n const tokenCount = asNumber(record.token_count);\n if (tokenCount === undefined) {\n reportFieldMismatch(\"kimi\", \"usage.token_count\");\n return;\n }\n this.stats.total_tokens = tokenCount;\n }\n\n applyWireRecord(record: Record<string, unknown>) {\n if (this.usesWireTotalFallback) this.applyContextRecord(record);\n\n const tokenUsage = asRecord(asRecord(record.message)?.usage);\n if (!tokenUsage) return null;\n\n const inputTokens = extractTokenField(tokenUsage, \"input_tokens\");\n const outputTokens = extractTokenField(tokenUsage, \"output_tokens\");\n const cost = estimateTokenCost(this.model, { input: inputTokens, output: outputTokens });\n this.stats.total_input_tokens += inputTokens;\n this.stats.total_output_tokens += outputTokens;\n if (cost !== null) this.totalCost += cost;\n return { inputTokens, outputTokens, cost };\n }\n\n finish(): SessionDetail[\"stats\"] {\n const stats = { ...this.stats, total_cost: Number(this.totalCost.toFixed(8)) };\n if (stats.total_cost > 0) stats.cost_source = \"estimated\";\n return stats;\n }\n}\n\nfunction normalizeToolOutputParts(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n const text = cleanInternalText(content);\n return text ? [{ type: \"text\" as const, text, time_created: timestampMs }] : [];\n }\n if (Array.isArray(content)) {\n const parts: MessagePart[] = [];\n for (const item of content) {\n const record = asRecord(item);\n if (record && \"text\" in record) {\n const text = String(record.text ?? \"\");\n const cleaned = cleanInternalText(text);\n if (cleaned) parts.push({ type: \"text\", text: cleaned, time_created: timestampMs });\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n }\n return parts;\n }\n if (content == null) return [];\n const text = cleanInternalText(String(content));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction normalizeWireToolOutputParts(returnValue: unknown, timestampMs: number): MessagePart[] {\n if (returnValue == null) return [];\n if (typeof returnValue === \"string\") {\n const text = cleanInternalText(returnValue);\n return text ? [{ type: \"text\" as const, text, time_created: timestampMs }] : [];\n }\n if (typeof returnValue === \"object\") {\n const text = cleanInternalText(JSON.stringify(returnValue, null, 2));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n }\n const text = cleanInternalText(String(returnValue));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction kimiContentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n\n return content\n .map((item) => {\n if (typeof item === \"string\") return item;\n const record = asRecord(item);\n if (record) return String(record.text ?? record.content ?? \"\");\n return \"\";\n })\n .join(\" \");\n}\n\nfunction extractFirstUserTitle(contextFile: string | null, wireFile: string | null): string | null {\n if (contextFile && existsSync(contextFile)) {\n for (const record of readJsonlFile(contextFile)) {\n if (record.role !== \"user\") continue;\n const title = normalizeTitleText(kimiContentText(record.content));\n if (title) return title;\n }\n }\n\n if (wireFile && existsSync(wireFile)) {\n for (const record of readJsonlFile(wireFile)) {\n const message = asRecord(record.message) ?? {};\n if (message.type !== \"TurnBegin\") continue;\n const payload = asRecord(message.payload) ?? {};\n const userInput = payload.user_input;\n if (!Array.isArray(userInput)) continue;\n const title = normalizeTitleText(kimiContentText(userInput));\n if (title) return title;\n }\n }\n\n return null;\n}\n\nexport class KimiAgent extends FileSystemSessionSource<SessionMeta> {\n readonly name = \"kimi\";\n readonly displayName = \"Kimi-Cli\";\n\n private basePath: string | null = null;\n private projectMap = new Map<string, string>();\n private defaultModel: string | null = null;\n\n private findBasePath(): string | null {\n return firstExisting(join(resolveKimiDataRoot(), \"sessions\"), \"data/kimi\");\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveKimiDataRoot();\n return {\n status: \"supported\" as const,\n targets: [{ root: dataRoot, path: join(dataRoot, \"sessions\") }, { path: \"data/kimi\" }],\n };\n }\n\n /** Parse kimi.json and build md5(project_path) → cwd mapping */\n private loadKimiConfig(): void {\n const dataRoot = resolveKimiDataRoot();\n const configPath = join(dataRoot, \"kimi.json\");\n const tomlPath = join(dataRoot, \"config.toml\");\n if (existsSync(tomlPath)) {\n const configText = readFileSync(tomlPath, \"utf-8\");\n this.defaultModel = configText.match(/^default_model\\s*=\\s*\"([^\"]+)\"/m)?.[1] ?? null;\n }\n if (!existsSync(configPath)) return;\n try {\n const raw = asRecord(JSON.parse(readFileSync(configPath, \"utf-8\")));\n const workDirs = asArray(raw?.work_dirs);\n if (!workDirs) return;\n for (const wd of workDirs) {\n const path = asString(asRecord(wd)?.path);\n if (!path) continue;\n const hash = createHash(\"md5\").update(path).digest(\"hex\");\n this.projectMap.set(hash, path);\n }\n } catch {\n // ignore malformed config\n }\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n this.loadKimiConfig();\n return this.listSessionDirs().length > 0;\n }\n\n /** Walk sessions/{project_hash}/{session_id}/ and find valid session dirs */\n private listSessionDirs(): string[] {\n if (!this.basePath) return [];\n const dirs: string[] = [];\n for (const hashEntry of this.readSessionSourceDirectory(this.basePath)) {\n if (!hashEntry.isDirectory()) continue;\n const hashPath = join(this.basePath, hashEntry.name);\n for (const sessionEntry of this.readSessionSourceDirectory(hashPath)) {\n if (!sessionEntry.isDirectory()) continue;\n const sessionPath = join(hashPath, sessionEntry.name);\n if (\n existsSync(join(sessionPath, \"metadata.json\")) ||\n existsSync(join(sessionPath, \"state.json\"))\n ) {\n dirs.push(sessionPath);\n }\n }\n }\n return dirs;\n }\n\n /**\n * 解析会话源,优先 state.json 而非 metadata.json。\n * 只读小 JSON 文件与 statSync,不触碰 transcript——枚举路径依赖这一点。\n */\n private resolveSessionSourceResult(sessionDir: string): ParseSessionResult<SessionSource> {\n try {\n const sessionId = basename(sessionDir);\n const projectHash = basename(dirname(sessionDir));\n const contextFile = join(sessionDir, \"context.jsonl\");\n const wireFile = join(sessionDir, \"wire.jsonl\");\n\n const existingContextFile = existsSync(contextFile) ? contextFile : null;\n const existingWireFile = existsSync(wireFile) ? wireFile : null;\n if (!existingContextFile && !existingWireFile) {\n return skippedSession(\"missing transcript\");\n }\n\n const statePath = join(sessionDir, \"state.json\");\n const metaPath = join(sessionDir, \"metadata.json\");\n\n let explicitTitle = \"\";\n let wireMtime: number | null = null;\n let metaFile = \"\";\n let metadata: Record<string, unknown> = {};\n\n if (existsSync(statePath)) {\n metadata = asRecord(JSON.parse(readFileSync(statePath, \"utf-8\"))) ?? {};\n explicitTitle = String(metadata.custom_title ?? \"\");\n wireMtime = readWireMtime(metadata);\n metaFile = statePath;\n } else if (existsSync(metaPath)) {\n metadata = asRecord(JSON.parse(readFileSync(metaPath, \"utf-8\"))) ?? {};\n explicitTitle = String(metadata.title ?? \"\");\n wireMtime = readWireMtime(metadata);\n metaFile = metaPath;\n }\n\n const sessionStat = statSync(sessionDir);\n const createdAt =\n parseTimestamp(metadata.createdAt) ??\n parseTimestamp(metadata.created_at) ??\n (sessionStat.birthtimeMs > 0 ? sessionStat.birthtimeMs : sessionStat.ctimeMs);\n const activityAt = Math.max(\n createdAt,\n wireMtime === null ? 0 : wireMtime * 1000,\n existingContextFile ? statSync(existingContextFile).mtimeMs : 0,\n existingWireFile ? statSync(existingWireFile).mtimeMs : 0,\n );\n\n return parsedSession({\n id: sessionId,\n sourcePath: sessionDir,\n cwd: this.projectMap.get(projectHash) || \"\",\n contextFile: existingContextFile,\n wireFile: existingWireFile,\n createdAt,\n activityAt,\n metaFile,\n explicitTitle,\n });\n } catch {\n return skippedSession(\"malformed metadata\");\n }\n }\n\n /**\n * 在会话源之上补齐 title。仅当 state/metadata 里没有可用标题时才回退去读\n * transcript 找首条用户消息,所以标题解析的成本只在真正需要重解析时付出。\n */\n private parseSessionDirResult(sessionDir: string): ParseSessionResult<SessionMeta> {\n const result = this.resolveSessionSourceResult(sessionDir);\n if (result.status !== \"parsed\") return result;\n\n const source = result.data;\n const title =\n normalizeTitleText(source.explicitTitle) ??\n resolveSessionTitle(null, extractFirstUserTitle(source.contextFile, source.wireFile), null);\n\n return parsedSession({ ...source, title, sourceMtimeMs: source.activityAt });\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n const refs: SessionSourceRef[] = [];\n for (const dir of this.listSessionDirs()) {\n const source = getParsedSession(this.resolveSessionSourceResult(dir));\n if (!source || !matchesScanWindow(source.activityAt, options)) continue;\n refs.push({\n sessionId: source.id,\n sourcePath: source.sourcePath,\n fingerprint: this.sourceFingerprint(source),\n });\n }\n return refs;\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n return getParsedSession(this.parseSessionHeadResult(sourcePath));\n }\n\n protected override scanSessionSourceResult(\n source: SessionSourceRef,\n ): ParseSessionResult<SessionHead> {\n return this.parseSessionHeadResult(source.sourcePath);\n }\n\n private parseSessionHeadResult(sourcePath: string): ParseSessionResult<SessionHead> {\n const result = this.parseSessionDirResult(sourcePath);\n if (result.status !== \"parsed\") return result;\n const meta = result.data;\n meta.sourceFingerprint = this.sourceFingerprint(meta);\n this.sessionMetaMap.set(meta.id, meta);\n const stats = this.extractStats(meta.sourcePath);\n return parsedSession({\n id: meta.id,\n slug: this.sessionSlug(meta.id),\n title: meta.title,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.activityAt,\n stats,\n });\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n\n if (meta.contextFile) {\n return this.getSessionDataFromContext(meta);\n }\n return this.getSessionDataFromWire(meta);\n }\n\n private getSessionDataFromContext(meta: SessionMeta): SessionDetail {\n if (!meta.contextFile) throw new Error(\"context.jsonl is missing\");\n\n const builder = new TranscriptBuilder();\n const ignoredToolCallIds = new Set<string>();\n const accumulator = new KimiUsageAccumulator(this.defaultModel, false);\n\n let seq = 0;\n const fallbackTs = meta.createdAt;\n for (const record of readJsonlFile(meta.contextFile)) {\n seq++;\n accumulator.applyContextRecord(record);\n try {\n const role = String(record.role ?? \"\");\n if (role === \"_checkpoint\" || role === \"_usage\" || isInternalEventType(role)) continue;\n\n if (role === \"user\") {\n const text = cleanInternalText(kimiContentText(record.content));\n if (text) {\n builder.appendMessage({\n id: `context-${seq}`,\n role: \"user\",\n timestampMs: fallbackTs,\n parts: [{ type: \"text\", text, time_created: fallbackTs }],\n });\n }\n continue;\n }\n\n if (role === \"assistant\") {\n const message = this.buildContextAssistantMessage(\n record,\n seq,\n ignoredToolCallIds,\n fallbackTs,\n );\n if (!message) continue;\n builder.appendMessage(message);\n continue;\n }\n\n if (role === \"tool\") {\n const callId = String(record.tool_call_id ?? \"\").trim();\n if (callId && ignoredToolCallIds.has(callId)) continue;\n const outputParts = normalizeToolOutputParts(record.content, fallbackTs);\n if (callId && this.backfillToolOutput(builder, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `context-${seq}`,\n role: \"tool\",\n timestampMs: fallbackTs,\n parts: outputParts,\n });\n }\n }\n } catch {\n // skip\n }\n }\n\n this.collectWireUsage(meta.sourcePath, accumulator);\n return this.buildSessionData(meta, builder, accumulator.finish());\n }\n\n private getSessionDataFromWire(meta: SessionMeta): SessionDetail {\n const wirePath = meta.wireFile ?? join(meta.sourcePath, \"wire.jsonl\");\n if (!existsSync(wirePath)) throw new Error(\"wire.jsonl is missing\");\n\n const builder = new TranscriptBuilder();\n const ignoredToolCallIds = new Set<string>();\n const openToolArgumentBuffer = new Map<string, string>();\n const accumulator = new KimiUsageAccumulator(this.defaultModel, true);\n\n let openToolCallId: string | null = null;\n let seq = 0;\n\n for (const record of readJsonlFile(wirePath)) {\n seq++;\n try {\n const tokenUsage = accumulator.applyWireRecord(record);\n const message = asRecord(record.message) ?? {};\n const msgType = asString(message.type) ?? \"\";\n if (isInternalEventType(msgType)) continue;\n const payload = asRecord(message.payload) ?? {};\n const timestampMs = Math.floor(readWireTimestamp(record) * 1000);\n\n // Bind usage to the most recent assistant message without tokens\n if (tokenUsage && (tokenUsage.inputTokens || tokenUsage.outputTokens)) {\n const tokens = { input: tokenUsage.inputTokens, output: tokenUsage.outputTokens };\n builder.attachUsageToLatestAssistant(tokens, {\n model: this.defaultModel,\n cost: tokenUsage.cost ?? undefined,\n costSource: tokenUsage.cost === null ? undefined : \"estimated\",\n });\n }\n\n if (msgType === \"TurnBegin\") {\n const userInput = payload.user_input;\n if (Array.isArray(userInput) && userInput.length > 0) {\n const text = cleanInternalText(kimiContentText(userInput));\n if (text) {\n builder.appendMessage({\n id: `wire-${seq}`,\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text, time_created: timestampMs }],\n });\n }\n }\n builder.beginTurn();\n openToolCallId = null;\n continue;\n }\n\n if (msgType === \"ContentPart\") {\n const partType = String(payload.type ?? \"\");\n if (partType === \"think\") {\n const text = cleanInternalText(String(payload.think ?? \"\"));\n if (text) {\n builder.appendAssistantPart(\n { type: \"reasoning\", text, time_created: timestampMs },\n { id: `wire-${seq}`, timestampMs, agent: \"kimi\" },\n { grouping: \"current\" },\n );\n }\n } else if (partType === \"text\") {\n const text = cleanInternalText(String(payload.text ?? \"\"));\n if (text) {\n builder.appendAssistantPart(\n { type: \"text\", text, time_created: timestampMs },\n { id: `wire-${seq}`, timestampMs, agent: \"kimi\" },\n { grouping: \"current\" },\n );\n }\n }\n continue;\n }\n\n if (msgType === \"ToolCall\") {\n const function_ = asRecord(payload.function);\n const toolName = String(function_?.name ?? \"\").trim();\n const callId = String(payload.id ?? \"\").trim();\n\n if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n openToolCallId = callId;\n continue;\n }\n\n if (!function_ || !callId || !toolName) continue;\n\n const rawArgs = function_.arguments;\n const normalizedArgs = normalizeToolArguments(rawArgs);\n const buffer =\n typeof rawArgs === \"string\" && typeof normalizedArgs !== \"string\" ? rawArgs : null;\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: { status: \"running\", input: normalizedArgs, output: null },\n time_created: timestampMs,\n };\n\n builder.appendToolCall(\n toolPart,\n { id: `wire-${seq}`, timestampMs, agent: \"kimi\" },\n { markModeAsTool: true, target: \"current\" },\n );\n openToolCallId = callId;\n\n if (buffer !== null) {\n openToolArgumentBuffer.set(callId, buffer);\n }\n continue;\n }\n\n if (msgType === \"ToolCallPart\") {\n if (openToolCallId && ignoredToolCallIds.has(openToolCallId)) continue;\n const argumentsPart = String(payload.arguments_part ?? \"\");\n this.appendWireToolCallPart(\n argumentsPart,\n openToolCallId,\n openToolArgumentBuffer,\n builder,\n );\n continue;\n }\n\n if (msgType === \"ToolResult\") {\n const callId = String(payload.tool_call_id ?? \"\").trim();\n if (callId && ignoredToolCallIds.has(callId)) continue;\n const outputParts = normalizeWireToolOutputParts(payload.return_value, timestampMs);\n if (callId && this.backfillToolOutput(builder, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `wire-${seq}`,\n role: \"tool\",\n timestampMs,\n parts: outputParts,\n });\n }\n continue;\n }\n\n // Skip StepBegin, StatusUpdate, ApprovalRequest, ApprovalResponse, TurnEnd\n } catch {\n // skip\n }\n }\n\n return this.buildSessionData(meta, builder, accumulator.finish());\n }\n\n // --- Helpers ---\n\n private sourceFingerprint(meta: Pick<SessionSource, \"metaFile\" | \"contextFile\" | \"wireFile\">) {\n return JSON.stringify([\n KIMI_PARSER_REVISION,\n ...this.fileSnapshot(meta.metaFile),\n ...this.fileSnapshot(meta.contextFile),\n ...this.fileSnapshot(meta.wireFile),\n ]);\n }\n\n private fileSnapshot(filePath: string | null): [number | null, number | null] {\n if (!filePath) return [null, null];\n try {\n const stat = statSync(filePath);\n return [stat.mtimeMs, stat.size];\n } catch {\n return [null, null];\n }\n }\n\n private buildContextAssistantMessage(\n record: Record<string, unknown>,\n seq: number,\n ignoredToolCallIds: Set<string>,\n fallbackTs: number,\n ): TranscriptMessageInput | null {\n const parts: MessagePart[] = [];\n\n const content = record.content;\n if (Array.isArray(content)) {\n for (const item of content) {\n const ci = asRecord(item);\n if (!ci) continue;\n const partType = String(ci.type ?? \"\");\n\n if (partType === \"think\") {\n const text = cleanInternalText(String(ci.think ?? \"\"));\n if (text) parts.push({ type: \"reasoning\", text, time_created: fallbackTs });\n } else if (partType === \"text\") {\n const text = cleanInternalText(String(ci.text ?? \"\"));\n if (text) parts.push({ type: \"text\", text, time_created: fallbackTs });\n }\n }\n }\n\n const toolCalls = asArray(record.tool_calls);\n if (toolCalls) {\n for (const tc of toolCalls) {\n const tcRecord = asRecord(tc);\n const function_ = asRecord(tcRecord?.function);\n\n if (!function_) continue;\n const toolName = String(function_.name ?? \"\").trim();\n const callId = String(tcRecord?.id ?? \"\").trim();\n\n if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n continue;\n }\n\n if (!toolName || !callId) continue;\n\n const part: MessagePart = {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: {\n status: \"running\",\n input: normalizeToolArguments(function_.arguments),\n output: null,\n },\n time_created: fallbackTs,\n };\n parts.push(part);\n }\n }\n\n if (parts.length === 0) {\n return null;\n }\n\n const allTools = parts.every((p) => p.type === \"tool\");\n return {\n id: `context-${seq}`,\n role: \"assistant\",\n timestampMs: fallbackTs,\n parts,\n agent: \"kimi\",\n mode: allTools ? \"tool\" : undefined,\n };\n }\n\n private appendWireToolCallPart(\n argumentsPart: string,\n openCallId: string | null,\n buffer: Map<string, string>,\n builder: TranscriptBuilder,\n ): void {\n if (!openCallId) return;\n\n const existing = buffer.get(openCallId) ?? \"\";\n const combined = existing + argumentsPart;\n\n try {\n const parsed: unknown = JSON.parse(combined);\n if (\n builder.updateToolCall(openCallId, (part) => {\n part.state.input = parsed;\n })\n ) {\n buffer.delete(openCallId);\n }\n } catch {\n buffer.set(openCallId, combined);\n }\n }\n\n private backfillToolOutput(\n builder: TranscriptBuilder,\n callId: string,\n outputParts: MessagePart[],\n ): boolean {\n if (!outputParts.length || !callId) return false;\n\n return builder.resolveToolCall(callId, { output: [...outputParts] });\n }\n\n private extractStats(sessionDir: string): SessionDetail[\"stats\"] {\n const contextPath = join(sessionDir, \"context.jsonl\");\n const hasContext = existsSync(contextPath);\n const accumulator = new KimiUsageAccumulator(this.defaultModel, !hasContext);\n\n if (hasContext) {\n try {\n for (const record of readJsonlFile(contextPath)) accumulator.applyContextRecord(record);\n } catch {\n // skip unreadable context logs\n }\n }\n\n this.collectWireUsage(sessionDir, accumulator);\n return accumulator.finish();\n }\n\n private collectWireUsage(sessionDir: string, accumulator: KimiUsageAccumulator): void {\n const wirePath = join(sessionDir, \"wire.jsonl\");\n if (existsSync(wirePath)) {\n try {\n for (const record of readJsonlFile(wirePath)) accumulator.applyWireRecord(record);\n } catch {\n // skip unreadable wire logs\n }\n }\n }\n\n private buildSessionData(\n meta: SessionMeta,\n builder: TranscriptBuilder,\n stats: SessionDetail[\"stats\"],\n ): SessionDetail {\n const transcript = builder.finish(stats);\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: this.sessionSlug(meta.id),\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.activityAt,\n stats: transcript.stats,\n messages: transcript.messages,\n };\n }\n}\n","export function normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw;\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport {\n FileSystemSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n ChangeCheckResult,\n ParseSessionResult,\n SessionCacheMeta,\n SessionSourceRef,\n} from \"./base.js\";\nimport type {\n MessagePart,\n SessionDetail,\n SessionHead,\n SessionStats,\n ToolPart,\n} from \"../types/index.js\";\nimport { resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile } from \"../utils/jsonl.js\";\nimport { asArray, asNumber, asRecord, asString } from \"../utils/narrow.js\";\nimport { parseAgentTimestamp } from \"../utils/timestamp.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\nimport { normalizeToolArguments } from \"./tool-arguments.js\";\n\nconst KIMI_CODE_TOOL_TITLE_MAP: Record<string, string> = {\n Read: \"read\",\n Write: \"write\",\n Edit: \"edit\",\n Bash: \"bash\",\n TodoList: \"todo\",\n AskUserQuestion: \"ask\",\n EnterPlanMode: \"plan mode\",\n ExitPlanMode: \"plan approved\",\n ReadFile: \"read\",\n Glob: \"glob\",\n StrReplaceFile: \"edit\",\n Grep: \"grep\",\n WriteFile: \"write\",\n Shell: \"bash\",\n};\n\nconst KIMI_CODE_IGNORED_TOOLS = new Set([\"SetTodoList\"]);\nconst KIMI_CODE_PARSER_REVISION = \"kimi-code-parser-v2\";\n\nexport function resolveKimiCodeDataRoot(): string {\n return resolveHomePath(\"KIMI_CODE_HOME\", \".kimi-code\");\n}\n\ninterface SessionSource {\n id: string;\n sourcePath: string;\n stateFile: string;\n wireFile: string;\n workDir: string;\n createdAt: number;\n activityAt: number;\n stateMtimeMs: number;\n stateSize: number;\n wireMtimeMs: number;\n wireSize: number;\n explicitTitle: string;\n}\n\ninterface SessionMeta extends SessionCacheMeta {\n wireFile: string;\n workDir: string;\n createdAt: number;\n activityAt: number;\n title: string;\n sourceMtimeMs: number;\n}\n\ninterface UsageTotals {\n totalCost: number;\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCacheReadTokens: number;\n totalCacheCreateTokens: number;\n modelUsage: Record<string, number>;\n}\n\ninterface ParsedWire {\n builder: TranscriptBuilder;\n stats: SessionStats;\n firstUserTitle: string | null;\n modelUsage: Record<string, number>;\n}\n\nfunction mapToolTitle(toolName: string): string {\n return KIMI_CODE_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\nfunction parseTimestamp(raw: unknown): number | null {\n return parseAgentTimestamp(raw, \"kimi-code\", { numericStrings: true });\n}\n\nfunction timestampFromRecord(record: Record<string, unknown>): number {\n return parseTimestamp(record.time) ?? 0;\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) {\n const record = asRecord(content);\n return record ? String(record.text ?? \"\") : \"\";\n }\n\n return content\n .map((item) => {\n if (typeof item === \"string\") return item;\n const record = asRecord(item);\n return record ? String(record.text ?? \"\") : \"\";\n })\n .join(\" \");\n}\n\nfunction contentParts(content: unknown, timestampMs: number): MessagePart[] {\n const values = Array.isArray(content) ? content : [content];\n const parts: MessagePart[] = [];\n\n for (const value of values) {\n if (typeof value === \"string\") {\n const text = cleanInternalText(value);\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n continue;\n }\n\n const record = asRecord(value);\n if (!record) continue;\n const type = asString(record.type) ?? \"\";\n if (type === \"text\") {\n const text = cleanInternalText(asString(record.text) ?? \"\");\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n continue;\n }\n if (type === \"think\") {\n const text = cleanInternalText(asString(record.think) ?? \"\");\n if (text) parts.push({ type: \"reasoning\", text, time_created: timestampMs });\n continue;\n }\n if (type === \"plan\") {\n const text = cleanInternalText(asString(record.text) ?? \"\");\n if (text) {\n parts.push({\n type: \"plan\",\n text,\n approval_status: record.approved === false ? \"fail\" : \"success\",\n time_created: timestampMs,\n });\n }\n continue;\n }\n if (type === \"image\") {\n const source = asRecord(record.source);\n const imageUrl = asRecord(record.imageUrl);\n const url =\n asString(record.url) ??\n asString(imageUrl?.url) ??\n (source?.kind === \"url\" ? asString(source.url) : undefined);\n const data =\n asString(record.data) ?? (source?.kind === \"base64\" ? asString(source.data) : undefined);\n const mimeType =\n asString(record.mime_type) ??\n asString(record.media_type) ??\n (source?.kind === \"base64\" ? asString(source.media_type) : undefined) ??\n \"application/octet-stream\";\n if (url) parts.push({ type: \"image\", url, mime_type: mimeType, time_created: timestampMs });\n else if (data) {\n parts.push({\n type: \"image\",\n data,\n mime_type: mimeType,\n time_created: timestampMs,\n });\n }\n continue;\n }\n if (type === \"image_url\") {\n const imageUrl = asRecord(record.imageUrl);\n const url = asString(imageUrl?.url) ?? asString(record.url);\n if (url) parts.push({ type: \"image\", url, time_created: timestampMs });\n }\n }\n\n return parts;\n}\n\nfunction toolOutputParts(output: unknown, timestampMs: number): MessagePart[] {\n if (typeof output === \"string\") {\n const text = cleanInternalText(output);\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n }\n if (Array.isArray(output)) return contentParts(output, timestampMs);\n if (output == null) return [];\n\n const record = asRecord(output);\n if (record?.type === \"text\") return contentParts([record], timestampMs);\n\n const text = cleanInternalText(JSON.stringify(output, null, 2));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction toolPart(toolName: string, callId: string, input: unknown, timestampMs: number): ToolPart {\n return {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: {\n status: \"running\",\n ...(input === undefined ? {} : { input }),\n output: null,\n },\n time_created: timestampMs,\n };\n}\n\nfunction toolCallParts(\n message: Record<string, unknown>,\n timestampMs: number,\n ignoredToolCallIds: Set<string>,\n): MessagePart[] {\n const calls = asArray(message.toolCalls) ?? [];\n const parts: MessagePart[] = [];\n\n for (const call of calls) {\n const callRecord = asRecord(call);\n const functionRecord = asRecord(callRecord?.function) ?? callRecord;\n const toolName = asString(functionRecord?.name)?.trim() ?? \"\";\n const callId = asString(callRecord?.id)?.trim() ?? \"\";\n if (!toolName || !callId) continue;\n if (KIMI_CODE_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n continue;\n }\n\n const rawArguments = functionRecord?.arguments ?? callRecord?.arguments;\n parts.push(toolPart(toolName, callId, normalizeToolArguments(rawArguments), timestampMs));\n }\n\n return parts;\n}\n\nfunction addToolResolution(\n builder: TranscriptBuilder,\n callId: string,\n output: unknown,\n timestampMs: number,\n isError = false,\n note?: string,\n): boolean {\n const outputParts = toolOutputParts(output, timestampMs);\n return builder.resolveToolCall(callId, {\n output: outputParts,\n status: isError ? \"error\" : \"completed\",\n ...(note ? { metadata: { note: cleanInternalText(note) } } : {}),\n });\n}\n\nfunction usageNumber(usage: Record<string, unknown>, field: string): number {\n return asNumber(usage[field]) ?? 0;\n}\n\nfunction emptyStats(): SessionStats {\n return {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n };\n}\n\nfunction buildUsageTotals(): UsageTotals {\n return {\n totalCost: 0,\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalCacheReadTokens: 0,\n totalCacheCreateTokens: 0,\n modelUsage: {},\n };\n}\n\nfunction applyUsage(\n builder: TranscriptBuilder,\n record: Record<string, unknown>,\n activeModel: string | null,\n totals: UsageTotals,\n): void {\n const usage = asRecord(record.usage);\n if (!usage) return;\n\n const cacheRead = usageNumber(usage, \"inputCacheRead\");\n const cacheCreate = usageNumber(usage, \"inputCacheCreation\");\n const inputOther = usageNumber(usage, \"inputOther\");\n const output = usageNumber(usage, \"output\");\n const input = inputOther + cacheRead + cacheCreate;\n const model = asString(record.model) ?? activeModel;\n const tokens = {\n input,\n output,\n cache_read: cacheRead,\n cache_create: cacheCreate,\n };\n const cost = estimateTokenCost(model, tokens);\n\n totals.totalInputTokens += input;\n totals.totalOutputTokens += output;\n totals.totalCacheReadTokens += cacheRead;\n totals.totalCacheCreateTokens += cacheCreate;\n if (model) totals.modelUsage[model] = (totals.modelUsage[model] ?? 0) + input + output;\n if (cost !== null) totals.totalCost += cost;\n\n builder.attachUsageToLatestAssistant(tokens, {\n model,\n cost: cost ?? undefined,\n costSource: cost === null ? undefined : \"estimated\",\n });\n}\n\nfunction readState(stateFile: string): Record<string, unknown> | null {\n try {\n return asRecord(JSON.parse(readFileSync(stateFile, \"utf-8\"))) ?? null;\n } catch {\n return null;\n }\n}\n\nexport class KimiCodeAgent extends FileSystemSessionSource<SessionMeta> {\n readonly name = \"kimi-code\";\n readonly displayName = \"Kimi-Code\";\n\n private basePath: string | null = null;\n private workDirBySessionPath = new Map<string, string>();\n\n private findBasePath(): string | null {\n const sessionsPath = join(resolveKimiCodeDataRoot(), \"sessions\");\n return existsSync(sessionsPath) ? sessionsPath : null;\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveKimiCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { root: dataRoot, path: join(dataRoot, \"sessions\") },\n { root: dataRoot, path: join(dataRoot, \"session_index.jsonl\") },\n ],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n return this.listSessionDirs().length > 0;\n }\n\n private loadSessionIndex(): void {\n this.workDirBySessionPath.clear();\n if (!this.basePath) return;\n\n const indexPath = join(dirname(this.basePath), \"session_index.jsonl\");\n if (!existsSync(indexPath)) return;\n for (const record of readJsonlFile(indexPath)) {\n const sessionPath = asString(record.sessionDir);\n const workDir = asString(record.workDir);\n if (!sessionPath || !workDir) continue;\n this.workDirBySessionPath.set(resolve(sessionPath), workDir);\n }\n }\n\n private listSessionDirs(): string[] {\n if (!this.basePath) return [];\n const dirs: string[] = [];\n\n for (const bucket of this.readSessionSourceDirectory(this.basePath)) {\n if (!bucket.isDirectory()) continue;\n const bucketPath = join(this.basePath, bucket.name);\n for (const session of this.readSessionSourceDirectory(bucketPath)) {\n if (!session.isDirectory()) continue;\n const sessionPath = join(bucketPath, session.name);\n if (\n existsSync(join(sessionPath, \"state.json\")) &&\n existsSync(join(sessionPath, \"agents\", \"main\", \"wire.jsonl\"))\n ) {\n dirs.push(sessionPath);\n }\n }\n }\n\n return dirs;\n }\n\n private resolveSessionSourceResult(sessionDir: string): ParseSessionResult<SessionSource> {\n try {\n const stateFile = join(sessionDir, \"state.json\");\n const wireFile = join(sessionDir, \"agents\", \"main\", \"wire.jsonl\");\n if (!existsSync(stateFile) || !existsSync(wireFile)) return skippedSession(\"missing wire\");\n\n const state = readState(stateFile);\n if (!state) return skippedSession(\"malformed state\");\n\n const stateStat = statSync(stateFile);\n const wireStat = statSync(wireFile);\n const createdAt =\n parseTimestamp(state.createdAt) ?? parseTimestamp(state.created_at) ?? stateStat.mtimeMs;\n const activityAt = Math.max(\n parseTimestamp(state.updatedAt) ?? parseTimestamp(state.updated_at) ?? createdAt,\n wireStat.mtimeMs,\n );\n const custom = asRecord(state.custom);\n const workDir =\n asString(state.workDir) ??\n asString(custom?.cwd) ??\n this.workDirBySessionPath.get(resolve(sessionDir)) ??\n \"\";\n const explicitTitle = asString(state.title) ?? asString(state.customTitle) ?? \"\";\n\n return parsedSession({\n id: basename(sessionDir),\n sourcePath: sessionDir,\n stateFile,\n wireFile,\n workDir,\n createdAt,\n activityAt,\n stateMtimeMs: stateStat.mtimeMs,\n stateSize: stateStat.size,\n wireMtimeMs: wireStat.mtimeMs,\n wireSize: wireStat.size,\n explicitTitle,\n });\n } catch {\n return skippedSession(\"malformed session\");\n }\n }\n\n private sourceFingerprint(source: SessionSource): string {\n return JSON.stringify([\n KIMI_CODE_PARSER_REVISION,\n source.stateMtimeMs,\n source.stateSize,\n source.wireMtimeMs,\n source.wireSize,\n source.createdAt,\n source.activityAt,\n source.workDir,\n source.explicitTitle,\n ]);\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n this.loadSessionIndex();\n const refs: SessionSourceRef[] = [];\n\n for (const sessionDir of this.listSessionDirs()) {\n const source = getParsedSession(this.resolveSessionSourceResult(sessionDir));\n if (!source || !matchesScanWindow(source.activityAt, options)) continue;\n refs.push({\n sessionId: source.id,\n sourcePath: source.sourcePath,\n fingerprint: this.sourceFingerprint(source),\n });\n }\n\n return refs;\n }\n\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const result = super.checkForChanges(sinceTimestamp, cachedSessions);\n if (result.status === \"failed\") return result;\n const emptySessionIds = cachedSessions\n .filter((session) => !this.hasMessages(session))\n .map((session) => session.id);\n if (emptySessionIds.length === 0) return result;\n\n return {\n ...result,\n hasChanges: true,\n changedIds: [...new Set([...(result.changedIds ?? []), ...emptySessionIds])],\n };\n }\n\n filterCachedSessions(sessions: SessionHead[]): SessionHead[] {\n return this.removeEmptyCachedSessions(sessions);\n }\n\n incrementalScan(\n cachedSessions: SessionHead[],\n changedIds: string[],\n refs?: SessionSourceRef[],\n scanOptions?: AgentScanOptions,\n ): SessionHead[] {\n const visibleSessions = this.removeEmptyCachedSessions(cachedSessions);\n return super.incrementalScan(visibleSessions, changedIds, refs, scanOptions);\n }\n\n private hasMessages(session: SessionHead): boolean {\n return session.stats.message_count > 0;\n }\n\n private removeEmptyCachedSessions(sessions: SessionHead[]): SessionHead[] {\n return sessions.filter((session) => {\n if (this.hasMessages(session)) return true;\n this.sessionMetaMap.delete(session.id);\n return false;\n });\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n return getParsedSession(this.parseSessionHeadResult(sourcePath));\n }\n\n protected override scanSessionSourceResult(\n source: SessionSourceRef,\n ): ParseSessionResult<SessionHead> {\n return this.parseSessionHeadResult(source.sourcePath);\n }\n\n private parseSessionHeadResult(sourcePath: string): ParseSessionResult<SessionHead> {\n this.loadSessionIndex();\n const result = this.resolveSessionSourceResult(sourcePath);\n if (result.status !== \"parsed\") return result;\n const source = result.data;\n\n const parsed = this.parseWire(source);\n const transcript = parsed.builder.finish(parsed.stats);\n if (transcript.messages.length === 0) {\n this.sessionMetaMap.delete(source.id);\n return filteredSession(\"no visible messages\");\n }\n\n const title = resolveSessionTitle(source.explicitTitle, parsed.firstUserTitle, null);\n const meta: SessionMeta = {\n id: source.id,\n sourcePath: source.sourcePath,\n wireFile: source.wireFile,\n workDir: source.workDir,\n createdAt: source.createdAt,\n activityAt: source.activityAt,\n title,\n sourceMtimeMs: source.activityAt,\n sourceFingerprint: this.sourceFingerprint(source),\n };\n this.sessionMetaMap.set(meta.id, meta);\n return parsedSession({\n id: meta.id,\n slug: this.sessionSlug(meta.id),\n title: meta.title,\n directory: meta.workDir,\n time_created: meta.createdAt,\n time_updated: meta.activityAt,\n stats: transcript.stats,\n ...(Object.keys(parsed.modelUsage).length > 0 ? { model_usage: parsed.modelUsage } : {}),\n });\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n\n const parsed = this.parseWire(meta);\n const transcript = parsed.builder.finish(parsed.stats);\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: this.sessionSlug(meta.id),\n directory: meta.workDir,\n time_created: meta.createdAt,\n time_updated: meta.activityAt,\n stats: transcript.stats,\n messages: transcript.messages,\n };\n }\n\n private parseWire(source: Pick<SessionSource, \"wireFile\">): ParsedWire {\n const builder = new TranscriptBuilder();\n const totals = buildUsageTotals();\n const ignoredToolCallIds = new Set<string>();\n let activeModel: string | null = null;\n let activeProvider: string | null = null;\n let firstUserTitle: string | null = null;\n let sequence = 0;\n\n for (const record of readJsonlFile(source.wireFile)) {\n sequence += 1;\n try {\n const timestampMs = timestampFromRecord(record);\n const recordType = asString(record.type) ?? \"\";\n\n if (recordType === \"llm.request\") {\n activeModel = asString(record.model) ?? activeModel;\n activeProvider = asString(record.provider) ?? activeProvider;\n continue;\n }\n if (recordType === \"config.update\") {\n activeModel = asString(record.modelAlias) ?? activeModel;\n continue;\n }\n if (recordType === \"usage.record\") {\n applyUsage(builder, record, activeModel, totals);\n continue;\n }\n if (recordType === \"context.append_message\") {\n const message = asRecord(record.message);\n if (!message) continue;\n const role = asString(message.role) ?? \"\";\n const messageTimestamp = timestampMs;\n\n if (role === \"user\") {\n const text = normalizeTitleText(contentText(message.content));\n if (!firstUserTitle && text) firstUserTitle = text;\n }\n\n if (role === \"tool\") {\n const callId = asString(message.toolCallId)?.trim() ?? \"\";\n const output = message.content;\n if (callId && ignoredToolCallIds.has(callId)) continue;\n if (callId && addToolResolution(builder, callId, output, messageTimestamp)) continue;\n const outputParts = toolOutputParts(output, messageTimestamp);\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `wire-${sequence}`,\n role: \"tool\",\n timestampMs: messageTimestamp,\n parts: outputParts,\n });\n }\n continue;\n }\n\n if (role !== \"user\" && role !== \"assistant\") continue;\n const parts = [\n ...contentParts(message.content, messageTimestamp),\n ...(role === \"assistant\"\n ? toolCallParts(message, messageTimestamp, ignoredToolCallIds)\n : []),\n ];\n if (parts.length === 0) continue;\n const allTools = parts.every((part) => part.type === \"tool\");\n const input: TranscriptMessageInput = {\n id: `wire-${sequence}`,\n role,\n timestampMs: messageTimestamp,\n parts,\n ...(role === \"assistant\"\n ? {\n agent: this.name,\n mode: allTools ? \"tool\" : undefined,\n model: activeModel,\n provider: activeProvider,\n }\n : {}),\n };\n builder.appendMessage(input);\n continue;\n }\n if (recordType === \"context.append_loop_event\") {\n const event = asRecord(record.event);\n if (!event) continue;\n const eventType = asString(event.type) ?? \"\";\n const metadata = {\n id: `wire-${sequence}`,\n timestampMs,\n agent: this.name,\n model: activeModel,\n provider: activeProvider,\n };\n\n if (eventType === \"step.begin\") {\n builder.beginTurn();\n continue;\n }\n if (eventType === \"content.part\") {\n const part = asRecord(event.part);\n if (!part) continue;\n const parts = contentParts([part], timestampMs);\n for (const contentPart of parts) {\n if (contentPart.type === \"tool\") continue;\n if (contentPart.type === \"image\" && builder.appendToCurrentAssistant(contentPart)) {\n continue;\n }\n builder.appendAssistantPart(contentPart, metadata, { grouping: \"current\" });\n }\n continue;\n }\n if (eventType === \"tool.call\") {\n const toolName = asString(event.name)?.trim() ?? \"\";\n const callId = asString(event.toolCallId)?.trim() ?? \"\";\n if (!toolName || !callId) continue;\n if (KIMI_CODE_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n continue;\n }\n builder.appendToolCall(toolPart(toolName, callId, event.args, timestampMs), metadata, {\n markModeAsTool: true,\n target: \"current\",\n });\n continue;\n }\n if (eventType === \"tool.result\") {\n const callId = asString(event.toolCallId)?.trim() ?? \"\";\n const result = asRecord(event.result);\n if (!callId || ignoredToolCallIds.has(callId)) continue;\n const output = result?.output;\n const isError = result?.isError === true;\n const note = asString(result?.note);\n if (addToolResolution(builder, callId, output, timestampMs, isError, note)) continue;\n const outputParts = toolOutputParts(output, timestampMs);\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `wire-${sequence}`,\n role: \"tool\",\n timestampMs,\n parts: outputParts,\n });\n }\n }\n continue;\n }\n if (recordType === \"context.apply_compaction\") {\n const summary = cleanInternalText(asString(record.summary) ?? \"\");\n if (summary) {\n builder.appendMessage({\n id: `wire-${sequence}`,\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: summary, time_created: timestampMs }],\n });\n }\n }\n } catch {\n continue;\n }\n }\n\n const stats: SessionStats = {\n ...emptyStats(),\n total_input_tokens: totals.totalInputTokens,\n total_output_tokens: totals.totalOutputTokens,\n total_cost: Number(totals.totalCost.toFixed(8)),\n total_tokens: totals.totalInputTokens + totals.totalOutputTokens,\n ...(totals.totalCacheReadTokens > 0\n ? { total_cache_read_tokens: totals.totalCacheReadTokens }\n : {}),\n ...(totals.totalCacheCreateTokens > 0\n ? { total_cache_create_tokens: totals.totalCacheCreateTokens }\n : {}),\n ...(totals.totalCost > 0 ? { cost_source: \"estimated\" as const } : {}),\n };\n return { builder, stats, firstUserTitle, modelUsage: totals.modelUsage };\n }\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport {\n SingleFileSessionSource,\n filteredSession,\n getParsedSession,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { ParseSessionResult } from \"./base.js\";\nimport type { Message, SessionHead, SessionDetail, MessagePart } from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { parseJsonlLines, readJsonlFile, readJsonlFileLines } from \"../utils/jsonl.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { cleanInternalText, isInternalEventType } from \"../utils/session-normalization.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport { parseAgentTimestamp } from \"../utils/timestamp.js\";\nimport { asRecord, asString, narrowField } from \"../utils/narrow.js\";\nimport { TranscriptBuilder } from \"./transcript-builder.js\";\nimport { normalizeToolArguments } from \"./tool-arguments.js\";\nimport {\n type ExecInnerCall,\n decodeExecCalls,\n getExecPatchText,\n pickExecOutputTarget,\n splitExecToolName,\n stripExecOutputEnvelope,\n} from \"./codex-exec-decode.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst PROPOSED_PLAN_PATTERN = /<proposed_plan>\\s*([\\s\\S]*?)\\s*<\\/proposed_plan>/;\nconst PLAN_APPROVAL_PREFIX = \"PLEASE IMPLEMENT THIS PLAN\";\nconst SUBAGENT_NOTIFICATION_PATTERN =\n /<subagent_notification>\\s*([\\s\\S]*?)\\s*<\\/subagent_notification>/;\nconst HEAD_INDEX_VERSION = \"codex-head-v2\";\nconst PARSER_VERSION = \"codex-parser-v8\";\n\nexport function resolveCodexDataRoot(): string {\n return resolveHomePath(\"CODEX_HOME\", \".codex\");\n}\n\nconst DEVELOPER_LIKE_USER_MARKERS = [\n \"agents.md instructions for\",\n \"<instructions>\",\n \"<environment_context>\",\n \"<permissions instructions>\",\n \"<collaboration_mode>\",\n];\n\nfunction isDeveloperLikeUserMessage(text: string): boolean {\n const lower = text.toLowerCase();\n return DEVELOPER_LIKE_USER_MARKERS.some((m) => lower.includes(m));\n}\n\nconst CODEX_TOOL_TITLE_MAP: Record<string, string> = {\n exec_command: \"bash\",\n apply_patch: \"patch\",\n patch: \"patch\",\n spawn_agent: \"subagent\",\n subagent: \"subagent\",\n};\n\n// ---------------------------------------------------------------------------\n// Session ID extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Extract session UUID from Codex filename.\n * \"rollout-2026-02-03T10-04-47-019c213e-c251-73a3-af66-0ec9d7cb9e29.jsonl\"\n * → last 5 dash-delimited parts joined with \"-\"\n */\nfunction extractSessionId(filename: string): string {\n const stem = basename(filename, \".jsonl\");\n const parts = stem.split(\"-\");\n if (parts.length >= 5) {\n return parts.slice(-5).join(\"-\");\n }\n return stem;\n}\n\n// ---------------------------------------------------------------------------\n// Timestamp\n// ---------------------------------------------------------------------------\n\nfunction parseTimestampMs(data: Record<string, unknown>): number {\n return parseAgentTimestamp(data[\"timestamp\"], \"codex\") ?? 0;\n}\n\nfunction extractModelName(raw: unknown): string | null {\n return typeof raw === \"string\" && raw.trim() ? raw.trim() : null;\n}\n\nfunction extractCachedInputTokens(usage: Record<string, unknown> | undefined): number {\n if (!usage) return 0;\n return Number(usage[\"cached_input_tokens\"] ?? usage[\"cache_read_input_tokens\"] ?? 0);\n}\n\nfunction narrowRecordField(value: unknown, field: string): Record<string, unknown> | undefined {\n return narrowField(\"codex\", field, value, asRecord);\n}\n\nfunction extractPayload(data: Record<string, unknown>): Record<string, unknown> {\n return narrowRecordField(data[\"payload\"], \"payload\") ?? {};\n}\n\ninterface ThreadMeta {\n threadSource: string;\n parentThreadId: string | null;\n agentNickname: string | null;\n}\n\nfunction extractThreadMeta(firstRecord: Record<string, unknown>): ThreadMeta | null {\n if (firstRecord[\"type\"] !== \"session_meta\") return null;\n const payload = extractPayload(firstRecord);\n const threadSource = asString(payload[\"thread_source\"]) ?? \"\";\n const parentThreadId = asString(payload[\"parent_thread_id\"]) ?? null;\n const agentNickname = asString(payload[\"agent_nickname\"]) ?? null;\n return { threadSource, parentThreadId, agentNickname };\n}\n\n// Leading-line reads want a few KB, not the default 1 MiB streaming buffer;\n// readJsonlFileLines keeps accumulating chunks if a single line runs longer.\nconst LEADING_READ_CHUNK_BYTES = 64 * 1024;\n\nfunction readLeadingJsonlLines(filePath: string, limit: number): string[] {\n const lines: string[] = [];\n for (const line of readJsonlFileLines(filePath, LEADING_READ_CHUNK_BYTES)) {\n if (!line.trim()) continue;\n lines.push(line);\n if (lines.length === limit) break;\n }\n return lines;\n}\n\nfunction extractTokenUsage(payload: Record<string, unknown>): {\n totalUsage: Record<string, unknown> | undefined;\n lastUsage: Record<string, unknown> | undefined;\n} {\n const info = narrowRecordField(payload[\"info\"], \"token_count.info\");\n return {\n totalUsage: info\n ? narrowRecordField(info[\"total_token_usage\"], \"token_count.total_token_usage\")\n : undefined,\n lastUsage: info\n ? narrowRecordField(info[\"last_token_usage\"], \"token_count.last_token_usage\")\n : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tool helpers\n// ---------------------------------------------------------------------------\n\nfunction resolveToolIdentity(\n name: string,\n namespace: unknown,\n): { tool: string; metadata?: { name: string; namespace: string } } {\n const mappedName = CODEX_TOOL_TITLE_MAP[name];\n if (mappedName) return { tool: mappedName };\n\n const namespaceText = typeof namespace === \"string\" ? namespace.trim() : \"\";\n if (!namespaceText) return { tool: name };\n\n const namespaceName = namespaceText.split(\"__\").at(-1) ?? namespaceText;\n const toolName = name.replace(/^[_.]+/, \"\");\n if (!namespaceName) {\n return {\n tool: toolName || name,\n metadata: { name, namespace: namespaceText },\n };\n }\n\n return {\n tool: `${namespaceName}.${toolName || name}`,\n metadata: { name, namespace: namespaceText },\n };\n}\n\nfunction normalizeCustomToolArguments(toolName: string, input: unknown): unknown {\n if (toolName === \"apply_patch\") {\n return parseApplyPatchInput(input);\n }\n return input;\n}\n\n/**\n * Flatten tool-call output to text. Classic outputs are strings; code-mode\n * outputs are arrays of `{ type: \"input_text\", text }` segments.\n */\nfunction flattenOutputText(output: unknown): string {\n if (typeof output === \"string\") return output;\n if (Array.isArray(output)) {\n return output\n .map((item) => {\n if (typeof item === \"string\") return item;\n const record = asRecord(item);\n return record ? (asString(record[\"text\"]) ?? \"\") : \"\";\n })\n .join(\"\");\n }\n return \"\";\n}\n\nfunction extractAssistantOutputText(payload: Record<string, unknown>): string {\n const content = payload[\"content\"];\n if (Array.isArray(content)) {\n return content\n .map((item) => {\n const record = asRecord(item);\n return record && String(record[\"type\"] ?? \"\") === \"output_text\"\n ? String(record[\"text\"] ?? \"\")\n : \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n return \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Patch parsing\n// ---------------------------------------------------------------------------\n\ninterface PatchBlock {\n type: \"write_file\" | \"delete_file\" | \"move_file\" | \"edit_file\";\n path?: string;\n content?: string;\n targetPath?: string;\n}\n\nconst PATCH_BEGIN_RE = /\\*\\*\\* Begin Patch/;\nconst PATCH_END_RE = /\\*\\*\\* End Patch/;\nconst PATCH_HEADER_RE = /\\*\\*\\*\\s+(Add|Delete|Update|Move)\\s+File:\\s*(.+)/;\nconst PATCH_MOVE_TO_RE = /\\*\\*\\*\\s+Move to:\\s*(.+)/;\n\nfunction parseApplyPatchInput(input: unknown): PatchBlock[] {\n const text = typeof input === \"string\" ? input : \"\";\n if (!text) return [];\n\n const blocks: PatchBlock[] = [];\n const lines = text.split(\"\\n\");\n let inPatch = false;\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i]!;\n\n if (!inPatch && PATCH_BEGIN_RE.test(line)) {\n inPatch = true;\n i++;\n continue;\n }\n\n if (inPatch && PATCH_END_RE.test(line)) {\n inPatch = false;\n i++;\n continue;\n }\n\n if (inPatch) {\n const headerMatch = line.match(PATCH_HEADER_RE);\n if (headerMatch) {\n const action = headerMatch[1]!;\n const filePath = headerMatch[2]!.trim();\n i++;\n\n if (action === \"Add\") {\n const content = extractPatchContent(lines, i);\n i = content.nextLineIndex;\n blocks.push({ type: \"write_file\", path: filePath, content: content.text });\n } else if (action === \"Update\") {\n // Check for Move to on the next non-empty line\n let moveToTarget: string | null = null;\n let contentStart = i;\n for (let j = i; j < lines.length; j++) {\n const l = lines[j]!;\n if (!l.trim()) continue;\n const moveMatch = l.match(PATCH_MOVE_TO_RE);\n if (moveMatch) {\n moveToTarget = moveMatch[1]!.trim();\n contentStart = j + 1;\n break;\n }\n break;\n }\n if (moveToTarget) {\n const content = extractPatchContent(lines, contentStart);\n i = content.nextLineIndex;\n blocks.push({\n type: \"move_file\",\n path: filePath,\n targetPath: moveToTarget,\n content: content.text,\n });\n } else {\n const content = extractPatchContent(lines, i);\n i = content.nextLineIndex;\n blocks.push({ type: \"edit_file\", path: filePath, content: content.text });\n }\n } else if (action === \"Delete\") {\n blocks.push({ type: \"delete_file\", path: filePath });\n // No content to read for delete\n }\n continue;\n }\n }\n\n i++;\n }\n\n return blocks;\n}\n\nfunction extractPatchContent(\n lines: string[],\n startIndex: number,\n): { text: string; nextLineIndex: number } {\n const contentLines: string[] = [];\n let i = startIndex;\n while (i < lines.length) {\n const line = lines[i]!;\n // Stop at next patch header or end patch\n if (PATCH_HEADER_RE.test(line) || PATCH_END_RE.test(line)) break;\n contentLines.push(line);\n i++;\n }\n return { text: contentLines.join(\"\\n\"), nextLineIndex: i };\n}\n\n// ---------------------------------------------------------------------------\n// Session meta\n// ---------------------------------------------------------------------------\n\nimport type {\n AgentScanOptions,\n FileSessionMeta,\n SessionCacheMeta,\n SessionSourceFile,\n SessionSourceRef,\n} from \"./base.js\";\n\n/** 一次全量前缀扫构建的 subagent 关系索引;miss 即代表\"无子会话\"。 */\ninterface SubagentIndex {\n childFilesByParent: Map<string, string[]>;\n subagentFiles: Set<string>;\n}\n\ninterface SessionMeta extends FileSessionMeta {\n indexPath: string | null;\n indexMtimeMs: number | null;\n headIndexVersion: string;\n parserVersion: string;\n parentThreadId: string | null;\n}\n\ninterface ChildFinalMessageCacheEntry {\n sourceFingerprint: string;\n parserVersion: string;\n message: Message | null;\n}\n\nclass ChildMessageVisibilityIndex {\n private readonly visibleSubagentIds = new Set<string>();\n private readonly visibleNicknameTexts = new Map<string, Set<string>>();\n\n constructor(messages: Message[]) {\n for (const message of messages) this.add(message);\n }\n\n hasEquivalent(message: Message): boolean {\n if (message.subagent_id !== undefined && this.visibleSubagentIds.has(message.subagent_id)) {\n return true;\n }\n\n const nickname = message.nickname;\n const text = message.parts.find((part) => part.type === \"text\")?.text;\n return (\n nickname !== undefined &&\n text !== undefined &&\n this.visibleNicknameTexts.get(nickname)?.has(text) === true\n );\n }\n\n add(message: Message): void {\n if (message.subagent_id !== undefined) {\n this.visibleSubagentIds.add(message.subagent_id);\n return;\n }\n if (message.nickname === undefined) return;\n\n let texts = this.visibleNicknameTexts.get(message.nickname);\n if (!texts) {\n texts = new Set();\n this.visibleNicknameTexts.set(message.nickname, texts);\n }\n for (const part of message.parts) {\n if (part.type === \"text\") texts.add(part.text);\n }\n }\n}\n\nfunction compareSourceActivityDesc(left: SessionSourceFile, right: SessionSourceFile): number {\n const leftTimestamp = sourceTimestamp(left.file, left.stat.mtimeMs);\n const rightTimestamp = sourceTimestamp(right.file, right.stat.mtimeMs);\n return rightTimestamp - leftTimestamp || left.file.localeCompare(right.file);\n}\n\nfunction sourceTimestamp(filePath: string, fallback: number): number {\n // Sort before parsing heads; the rollout filename is the only cheap activity hint.\n const match = basename(filePath).match(/^rollout-(\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2})-/);\n if (!match) return fallback;\n const timestamp = match[1]!.replace(/-(\\d{2})-(\\d{2})$/, \":$1:$2\");\n const parsed = Date.parse(timestamp);\n return Number.isFinite(parsed) ? parsed : fallback;\n}\n\n// ---------------------------------------------------------------------------\n// CodexAgent\n// ---------------------------------------------------------------------------\n\nexport class CodexAgent extends SingleFileSessionSource<SessionMeta> {\n readonly name = \"codex\";\n readonly displayName = \"Codex\";\n\n private basePath: string | null = null;\n private sessionIndexCache = new Map<string, string>();\n private sessionIndexMtime: number | null | undefined;\n private sessionIndexPath: string | undefined;\n private subagentIndex: SubagentIndex | null = null;\n // Thread meta lives in a rollout's immutable first line; fingerprinting by\n // (mtime, size) lets index rebuilds stat files instead of re-reading them.\n private readonly threadMetaByPath = new Map<\n string,\n { fingerprint: string; meta: ThreadMeta | null }\n >();\n private subagentStatsByParent = new Map<string, SessionHead[\"stats\"][]>();\n private childFinalMessagesByParent = new Map<string, Map<string, ChildFinalMessageCacheEntry>>();\n\n // ---- BaseAgent implementation ----\n\n private findBasePath(): string | null {\n return firstExisting(join(resolveCodexDataRoot(), \"sessions\"));\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveCodexDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { path: join(dataRoot, \"sessions\") },\n { path: join(dataRoot, \"session_index.jsonl\") },\n ],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n return this.listRolloutFiles().length > 0;\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n this.loadSessionIndex();\n return this.listScanSources(options).map(({ file, stat }) => ({\n sessionId: extractSessionId(file),\n sourcePath: file,\n fingerprint: this.sourceFingerprint(file, stat),\n }));\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n super.setSessionMetaMap(meta);\n this.subagentIndex = null;\n this.subagentStatsByParent.clear();\n this.childFinalMessagesByParent.clear();\n }\n\n /**\n * A changed subagent file leaves its parent's aggregated token stats stale,\n * so the parent must re-parse alongside the child.\n */\n expandChangedSessionIds(changedIds: string[], refs?: SessionSourceRef[]): string[] {\n if (changedIds.length === 0) return changedIds;\n const pathById = new Map((refs ?? []).map((ref) => [ref.sessionId, ref.sourcePath]));\n const expanded = new Set(changedIds);\n for (const id of changedIds) {\n const sourcePath = pathById.get(id) ?? this.sessionMetaMap.get(id)?.sourcePath;\n const threadMeta = sourcePath ? this.readThreadMeta(sourcePath) : null;\n // A removed file cannot be read back; cached meta still knows its parent.\n const parentId = threadMeta\n ? threadMeta.threadSource === \"subagent\"\n ? threadMeta.parentThreadId\n : null\n : (this.sessionMetaMap.get(id)?.parentThreadId ?? null);\n if (!parentId) continue;\n expanded.add(parentId);\n this.subagentIndex = null;\n this.subagentStatsByParent.delete(parentId);\n this.childFinalMessagesByParent.delete(parentId);\n }\n return [...expanded];\n }\n\n private readThreadMeta(filePath: string): ThreadMeta | null {\n try {\n const { mtimeMs, size } = statSync(filePath);\n const fingerprint = `${mtimeMs}:${size}`;\n const cached = this.threadMetaByPath.get(filePath);\n if (cached && cached.fingerprint === fingerprint) return cached.meta;\n const firstLine = readLeadingJsonlLines(filePath, 1)[0];\n const meta = firstLine ? extractThreadMeta(JSON.parse(firstLine)) : null;\n this.threadMetaByPath.set(filePath, { fingerprint, meta });\n return meta;\n } catch (error) {\n getCoreDiagnostics()?.warn(\"codex.thread_meta_read_failed\", {\n filePath,\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n }\n\n private parseTokenStats(filePath: string): SessionHead[\"stats\"] {\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCost = 0;\n let activeModel: string | null = null;\n\n let prevCumulativeTotal = 0;\n let prevInput = 0;\n let prevOutput = 0;\n let prevReasoning = 0;\n let prevCachedInput = 0;\n\n for (const line of readJsonlFileLines(filePath)) {\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n const payload = extractPayload(data);\n\n if (recordType === \"session_meta\" || recordType === \"turn_context\") {\n const nextModel = extractModelName(payload[\"model\"]);\n if (nextModel) activeModel = nextModel;\n continue;\n }\n\n if (recordType === \"event_msg\" && String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const { totalUsage, lastUsage } = extractTokenUsage(payload);\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n if (cumulativeTotal <= 0 || cumulativeTotal === prevCumulativeTotal) continue;\n prevCumulativeTotal = cumulativeTotal;\n\n let inputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n let cacheReadTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n cacheReadTokens = extractCachedInputTokens(lastUsage);\n } else if (totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - prevInput;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - prevOutput;\n reasoningTokens = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - prevReasoning;\n cacheReadTokens = extractCachedInputTokens(totalUsage) - prevCachedInput;\n prevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n prevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n prevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n prevCachedInput = extractCachedInputTokens(totalUsage);\n }\n\n const totalInput = Math.max(0, inputTokens);\n const totalCacheRead = Math.max(0, cacheReadTokens);\n totalInputTokens += totalInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n totalCacheReadTokens += totalCacheRead;\n totalCost +=\n estimateTokenCost(activeModel, {\n input: totalInput,\n output: outputTokens,\n reasoning: reasoningTokens || undefined,\n cache_read: totalCacheRead || undefined,\n }) ?? 0;\n }\n } catch {\n // skip malformed records\n }\n }\n\n return {\n message_count: 0,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n };\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n if (!existsSync(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);\n this.basePath ??= this.findBasePath();\n\n const transcript = new TranscriptBuilder();\n\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCost = 0;\n\n let pendingPlan: MessagePart | null = null;\n let activeModel: string | null = null;\n\n // Token-count dedup state (matches codeburn strategy)\n let prevCumulativeTotal = 0;\n let prevInput = 0;\n let prevOutput = 0;\n let prevReasoning = 0;\n let prevCachedInput = 0;\n\n for (const record of readJsonlFile(meta.sourcePath)) {\n try {\n const recordType = String(record[\"type\"] ?? \"\");\n if (recordType === \"session_meta\" || recordType === \"turn_context\") {\n const payload = extractPayload(record);\n activeModel = extractModelName(payload[\"model\"]) ?? activeModel;\n }\n\n pendingPlan = this.convertRecord(record, transcript, pendingPlan, activeModel);\n\n // Process Codex token_count events\n if (recordType === \"event_msg\") {\n const payload = extractPayload(record);\n if (String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const { totalUsage, lastUsage } = extractTokenUsage(payload);\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n\n if (cumulativeTotal > 0 && cumulativeTotal === prevCumulativeTotal) {\n // duplicate event\n } else {\n prevCumulativeTotal = cumulativeTotal;\n\n let inputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n let cacheReadTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n cacheReadTokens = extractCachedInputTokens(lastUsage);\n } else if (cumulativeTotal > 0 && totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - prevInput;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - prevOutput;\n reasoningTokens =\n Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - prevReasoning;\n cacheReadTokens = extractCachedInputTokens(totalUsage) - prevCachedInput;\n\n prevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n prevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n prevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n prevCachedInput = extractCachedInputTokens(totalUsage);\n }\n\n const totalInput = Math.max(0, inputTokens);\n const totalCacheRead = Math.max(0, cacheReadTokens);\n if (totalInput || outputTokens || reasoningTokens) {\n totalInputTokens += totalInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n totalCacheReadTokens += totalCacheRead;\n\n const tokens = {\n input: totalInput,\n output: outputTokens,\n reasoning: reasoningTokens || undefined,\n cache_read: totalCacheRead || undefined,\n };\n const cost = estimateTokenCost(activeModel, tokens);\n transcript.attachUsageToLatestAssistant(tokens, {\n model: activeModel,\n cost: cost ?? undefined,\n costSource: cost === null ? undefined : \"estimated\",\n });\n totalCost += cost ?? 0;\n }\n }\n }\n }\n } catch {\n // skip malformed records\n }\n }\n\n if (pendingPlan) transcript.appendToCurrentAssistant(pendingPlan);\n const result = transcript.finish({\n message_count: 0,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n });\n\n this.applyChildStats(result.stats, meta.id);\n\n const childMessages = this.collectChildMessages(meta.id);\n this.mergeChildMessages(result.messages, childMessages);\n result.stats.message_count = result.messages.length;\n\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: this.sessionSlug(meta.id),\n directory: meta.directory,\n parent_reference:\n meta.parentThreadId == null\n ? undefined\n : { agentName: this.name, sessionId: meta.parentThreadId },\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: result.stats,\n messages: result.messages,\n };\n }\n\n /**\n * Builds the complete parent→children map in one prefix sweep. A cache miss\n * afterwards means \"no children\", so per-session directory rescans (the old\n * O(N²) finalization hotspot) never happen.\n */\n private ensureSubagentIndex(): SubagentIndex {\n if (this.subagentIndex) return this.subagentIndex;\n this.basePath ??= this.findBasePath();\n const index: SubagentIndex = { childFilesByParent: new Map(), subagentFiles: new Set() };\n const paths = this.listRolloutFilePaths();\n for (const file of paths) {\n const threadMeta = this.readThreadMeta(file);\n if (threadMeta?.threadSource !== \"subagent\") continue;\n index.subagentFiles.add(file);\n if (!threadMeta.parentThreadId) continue;\n const files = index.childFilesByParent.get(threadMeta.parentThreadId);\n if (files) files.push(file);\n else index.childFilesByParent.set(threadMeta.parentThreadId, [file]);\n }\n if (this.threadMetaByPath.size > paths.length) {\n const active = new Set(paths);\n for (const path of this.threadMetaByPath.keys()) {\n if (!active.has(path)) this.threadMetaByPath.delete(path);\n }\n }\n this.subagentIndex = index;\n return index;\n }\n\n private applyChildStats(target: SessionHead[\"stats\"], sessionId: string): void {\n for (const stats of this.collectChildStats(sessionId)) {\n target.total_input_tokens += stats.total_input_tokens ?? 0;\n target.total_output_tokens += stats.total_output_tokens ?? 0;\n target.total_cost += stats.total_cost ?? 0;\n if (stats.total_cache_read_tokens) {\n target.total_cache_read_tokens =\n (target.total_cache_read_tokens ?? 0) + stats.total_cache_read_tokens;\n }\n }\n }\n\n private collectChildStats(parentSessionId: string): SessionHead[\"stats\"][] {\n const files = this.collectChildFiles(parentSessionId);\n if (files.length === 0) return [];\n const cached = this.subagentStatsByParent.get(parentSessionId);\n if (cached) return cached;\n\n const stats = files.map((file) => this.parseTokenStats(file));\n this.subagentStatsByParent.set(parentSessionId, stats);\n return stats;\n }\n\n private collectChildFiles(parentSessionId: string): string[] {\n return this.ensureSubagentIndex().childFilesByParent.get(parentSessionId) ?? [];\n }\n\n private mergeChildMessages(visibleMessages: Message[], childMessages: Message[]): void {\n const visible = new ChildMessageVisibilityIndex(visibleMessages);\n for (const message of childMessages) {\n if (visible.hasEquivalent(message)) continue;\n visibleMessages.push(message);\n visible.add(message);\n }\n }\n\n private collectChildMessages(parentSessionId: string): Message[] {\n const childFiles = this.collectChildFiles(parentSessionId);\n this.reconcileChildFinalMessageCache(parentSessionId, childFiles);\n return childFiles\n .flatMap((file) => {\n const message = this.getChildFinalMessage(parentSessionId, file);\n return message ? [message] : [];\n })\n .sort((left, right) => left.time_created - right.time_created);\n }\n\n private getChildFinalMessage(parentSessionId: string, filePath: string): Message | null {\n const sourceFingerprint = this.childFinalMessageFingerprint(filePath);\n let cache = this.childFinalMessagesByParent.get(parentSessionId);\n if (!cache) {\n cache = new Map();\n this.childFinalMessagesByParent.set(parentSessionId, cache);\n }\n\n const cached = cache.get(filePath);\n if (\n cached?.sourceFingerprint === sourceFingerprint &&\n cached.parserVersion === PARSER_VERSION\n ) {\n return cached.message;\n }\n\n const message = this.readChildFinalMessage(filePath);\n cache.set(filePath, { sourceFingerprint, parserVersion: PARSER_VERSION, message });\n return message;\n }\n\n private reconcileChildFinalMessageCache(parentSessionId: string, childFiles: string[]): void {\n const cache = this.childFinalMessagesByParent.get(parentSessionId);\n if (!cache) return;\n\n const activeFiles = new Set(childFiles);\n for (const filePath of cache.keys()) {\n if (!activeFiles.has(filePath)) cache.delete(filePath);\n }\n if (cache.size === 0) this.childFinalMessagesByParent.delete(parentSessionId);\n }\n\n private childFinalMessageFingerprint(filePath: string): string {\n const { mtimeMs, size } = statSync(filePath);\n return JSON.stringify([mtimeMs, size]);\n }\n\n private readChildFinalMessage(filePath: string): Message | null {\n const sessionId = extractSessionId(filePath);\n const threadMeta = this.readThreadMeta(filePath);\n type ChildOutput = { id: string; text: string; timestampMs: number; isFinal: boolean };\n let latestOutput: ChildOutput | null = null;\n let finalOutput: ChildOutput | null = null;\n let fallbackMtimeMs: number | null = null;\n\n for (const record of readJsonlFile(filePath)) {\n try {\n const recordType = String(record[\"type\"] ?? \"\");\n if (recordType !== \"response_item\") continue;\n const payload = extractPayload(record);\n if (String(payload[\"type\"] ?? \"\") !== \"message\") continue;\n if (String(payload[\"role\"] ?? \"\") !== \"assistant\") continue;\n\n const text = cleanInternalText(extractAssistantOutputText(payload));\n if (!text) continue;\n\n const candidate: ChildOutput = {\n id: asString(payload[\"id\"]) ?? `codex-subagent-${sessionId}`,\n text,\n timestampMs:\n parseTimestampMs(record) ||\n parseTimestampMs(payload) ||\n (fallbackMtimeMs ??= statSync(filePath).mtimeMs),\n isFinal:\n String(record[\"phase\"] ?? \"\") === \"final_answer\" ||\n String(payload[\"phase\"] ?? \"\") === \"final_answer\",\n };\n latestOutput = candidate;\n if (candidate.isFinal) finalOutput = candidate;\n } catch {\n // skip malformed records\n }\n }\n\n const selected = finalOutput ?? latestOutput;\n if (!selected) return null;\n\n return {\n id: selected.id,\n role: \"assistant\",\n agent: \"codex\",\n time_created: selected.timestampMs,\n mode: null,\n model: null,\n provider: null,\n cost: 0,\n subagent_id: sessionId,\n nickname: threadMeta?.agentNickname ?? undefined,\n parts: [{ type: \"text\", text: selected.text, time_created: selected.timestampMs }],\n };\n }\n\n // ---- File listing ----\n\n private listRolloutFiles(options?: AgentScanOptions): SessionSourceFile[] {\n if (!this.basePath) return [];\n return this.walkFiles(\n this.basePath,\n (entry) => entry.name.endsWith(\".jsonl\") && entry.name.startsWith(\"rollout-\"),\n { scanWindow: options },\n );\n }\n\n /** Path-only listing for the subagent index: no per-file stat needed. */\n private listRolloutFilePaths(): string[] {\n if (!this.basePath) return [];\n const paths: string[] = [];\n const walk = (directory: string): void => {\n const entries = this.readSessionSourceDirectory(directory);\n for (const entry of entries) {\n const filePath = join(directory, entry.name);\n if (entry.isDirectory()) walk(filePath);\n else if (entry.name.startsWith(\"rollout-\") && entry.name.endsWith(\".jsonl\")) {\n paths.push(filePath);\n }\n }\n };\n walk(this.basePath);\n return paths;\n }\n\n private listScanSources(options?: AgentScanOptions): SessionSourceFile[] {\n const windowed = this.listRolloutFiles(options).sort(compareSourceActivityDesc);\n if (options?.from == null && options?.to == null) return windowed;\n\n const { childFilesByParent, subagentFiles } = this.ensureSubagentIndex();\n const rootFiles = windowed.filter((source) => !subagentFiles.has(source.file));\n const rootIds = new Set(rootFiles.map(({ file }) => extractSessionId(file)));\n if (rootIds.size === 0) return rootFiles;\n\n const selected = new Map(rootFiles.map((source) => [source.file, source]));\n const pending = [...rootIds];\n const seenParents = new Set<string>();\n while (pending.length > 0) {\n const parentId = pending.pop()!;\n if (seenParents.has(parentId)) continue;\n seenParents.add(parentId);\n for (const file of childFilesByParent.get(parentId) ?? []) {\n if (selected.has(file)) continue;\n try {\n selected.set(file, this.sessionSourceFile(file));\n } catch {\n continue;\n }\n pending.push(extractSessionId(file));\n }\n }\n return [...selected.values()].sort(compareSourceActivityDesc);\n }\n\n protected createFileSessionMeta(head: SessionHead, source: SessionSourceFile): SessionMeta {\n const indexPath = this.getSessionIndexPath();\n const indexMtime = this.sessionIndexMtime ?? null;\n return this.buildFileSessionMeta({\n head,\n source,\n fingerprint: this.sourceFingerprint(source.file, source.stat),\n extras: {\n indexPath: indexMtime === null ? null : indexPath,\n indexMtimeMs: indexMtime,\n headIndexVersion: HEAD_INDEX_VERSION,\n parserVersion: PARSER_VERSION,\n parentThreadId: head.parent_reference?.sessionId ?? null,\n },\n });\n }\n\n /** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */\n private sourceFingerprint(file: string, stat: { mtimeMs: number; size: number }): string {\n const sessionId = extractSessionId(file);\n return JSON.stringify([\n HEAD_INDEX_VERSION,\n PARSER_VERSION,\n stat.mtimeMs,\n stat.size,\n this.getTitleForSession(sessionId),\n ]);\n }\n\n private getSessionIndexPath(): string {\n this.sessionIndexPath ??= join(resolveCodexDataRoot(), \"session_index.jsonl\");\n return this.sessionIndexPath;\n }\n\n // ---- Session index ----\n\n private loadSessionIndex(): void {\n const indexPath = this.getSessionIndexPath();\n const mtime = this.readFileMtimeMs(indexPath);\n\n // Invalidate when the index file mtime advances so long-running processes\n // pick up title changes without relying on callers to evict manually.\n if (this.sessionIndexMtime !== undefined && this.sessionIndexMtime === mtime) return;\n\n if (mtime === null) {\n this.sessionIndexCache.clear();\n this.sessionIndexMtime = null;\n return;\n }\n\n try {\n const content = readFileSync(indexPath, \"utf-8\");\n const cache = new Map<string, string>();\n for (const record of parseJsonlLines(content)) {\n const sid = String(record[\"id\"] ?? \"\").trim();\n const threadName = String(record[\"thread_name\"] ?? \"\").trim();\n if (sid && threadName) {\n cache.set(sid, threadName);\n }\n }\n this.sessionIndexCache = cache;\n this.sessionIndexMtime = mtime;\n } catch (error) {\n // Titles silently falling back to filenames is a confusing failure\n // mode; keep the degradation but make it visible.\n getCoreDiagnostics()?.warn(\"codex.session_index_read_failed\", {\n path: indexPath,\n message: error instanceof Error ? error.message : String(error),\n });\n this.sessionIndexCache.clear();\n this.sessionIndexMtime = undefined;\n }\n }\n\n private getTitleForSession(sessionId: string): string | null {\n return this.sessionIndexCache.get(sessionId) ?? null;\n }\n\n // ---- Session head parsing ----\n\n protected parseFileSessionHead(filePath: string, options?: AgentScanOptions): SessionHead | null {\n return this.parseSessionHead(filePath, options);\n }\n\n private parseSessionHead(filePath: string, options?: AgentScanOptions): SessionHead | null {\n return getParsedSession(this.parseFileSessionHeadResult(filePath, options));\n }\n\n protected override parseFileSessionHeadResult(\n filePath: string,\n options?: AgentScanOptions,\n ): ParseSessionResult<SessionHead> {\n this.loadSessionIndex();\n if (options?.fast) {\n return this.parseFastSessionHeadResult(filePath);\n }\n\n const sessionId = extractSessionId(filePath);\n\n let firstPayload: Record<string, unknown> = {};\n let parentThreadId: string | null = null;\n let createdAt = 0;\n let lineCount = 0;\n let messageTitle: string | null = null;\n\n // Single streaming pass: read the first record, extract the title\n // candidate, count messages, extract models, and pre-accumulate tokens.\n let updatedAt = 0;\n let messageCount = 0;\n let activeModel: string | null = null;\n const modelUsageMap: Record<string, number> = {};\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCost = 0;\n\n let scanPrevCumulativeTotal = 0;\n let scanPrevInput = 0;\n let scanPrevOutput = 0;\n let scanPrevReasoning = 0;\n let scanPrevCachedInput = 0;\n\n const COUNTED_TYPES = new Set([\"message\", \"function_call\", \"function_call_output\"]);\n\n let hasNonInternalRecord = false;\n\n for (const line of readJsonlFileLines(filePath)) {\n lineCount += 1;\n if (lineCount === 1) {\n let firstRecord: Record<string, unknown>;\n try {\n firstRecord = JSON.parse(line);\n } catch {\n return skippedSession(\"malformed first record\");\n }\n firstPayload = extractPayload(firstRecord);\n const threadMeta = extractThreadMeta(firstRecord);\n parentThreadId = threadMeta?.threadSource === \"subagent\" ? threadMeta.parentThreadId : null;\n createdAt =\n parseTimestampMs(firstRecord) ||\n parseTimestampMs(firstPayload) ||\n statSync(filePath).mtimeMs;\n updatedAt = createdAt;\n }\n\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n const payload = extractPayload(data);\n const payloadType = String(payload[\"type\"] ?? \"\");\n if (isInternalEventType(recordType) || isInternalEventType(payloadType)) continue;\n hasNonInternalRecord = true;\n const recordTs = parseTimestampMs(data) || parseTimestampMs(payload);\n if (recordTs > updatedAt) updatedAt = recordTs;\n\n // Title fallback mirrors the removed extractTitleFromLines(): first\n // visible user message within the first 20 lines.\n if (messageTitle === null && lineCount <= 20) {\n const candidate = this.extractCodexRecordTitle(data);\n if (candidate) messageTitle = candidate;\n }\n\n if (recordType === \"session_meta\" || recordType === \"turn_context\") {\n const nextModel = extractModelName(payload[\"model\"]);\n if (nextModel) {\n activeModel = nextModel;\n }\n continue;\n }\n\n if (recordType === \"response_item\") {\n const p = payload;\n const pType = String(p[\"type\"] ?? \"\");\n if (COUNTED_TYPES.has(pType)) {\n messageCount++;\n }\n // Extract model from response_item\n const info = narrowRecordField(p[\"info\"], \"response_item.info\");\n const m = info?.[\"model\"] ?? p[\"model\"];\n if (typeof m === \"string\" && m.trim()) {\n activeModel = m.trim();\n }\n }\n\n if (recordType === \"event_msg\") {\n if (String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const { totalUsage, lastUsage } = extractTokenUsage(payload);\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n\n if (cumulativeTotal > 0 && cumulativeTotal !== scanPrevCumulativeTotal) {\n scanPrevCumulativeTotal = cumulativeTotal;\n\n let inputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n let cacheReadTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n cacheReadTokens = extractCachedInputTokens(lastUsage);\n } else if (cumulativeTotal > 0 && totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - scanPrevInput;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - scanPrevOutput;\n reasoningTokens =\n Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - scanPrevReasoning;\n cacheReadTokens = extractCachedInputTokens(totalUsage) - scanPrevCachedInput;\n\n scanPrevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n scanPrevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n scanPrevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n scanPrevCachedInput = extractCachedInputTokens(totalUsage);\n }\n\n const totalInput = Math.max(0, inputTokens);\n const totalCacheRead = Math.max(0, cacheReadTokens);\n totalInputTokens += totalInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n totalCacheReadTokens += totalCacheRead;\n const totalForModel = totalInput + outputTokens + reasoningTokens;\n if (activeModel && totalForModel > 0) {\n modelUsageMap[activeModel] = (modelUsageMap[activeModel] ?? 0) + totalForModel;\n }\n const cost = estimateTokenCost(activeModel, {\n input: totalInput,\n output: outputTokens,\n reasoning: reasoningTokens || undefined,\n cache_read: totalCacheRead || undefined,\n });\n if (cost !== null) totalCost += cost;\n }\n }\n }\n } catch {\n // skip\n }\n }\n\n if (lineCount === 0) return skippedSession(\"empty file\");\n if (!hasNonInternalRecord) return filteredSession(\"internal events only\");\n\n const indexTitle = this.getTitleForSession(sessionId);\n const directory = firstPayload[\"cwd\"] ? String(firstPayload[\"cwd\"]) : \"\";\n const title = resolveSessionTitle(indexTitle, messageTitle, basenameTitle(directory || null));\n\n return parsedSession({\n id: sessionId,\n slug: this.sessionSlug(sessionId),\n title,\n directory,\n parent_reference:\n parentThreadId == null ? undefined : { agentName: this.name, sessionId: parentThreadId },\n time_created: createdAt,\n time_updated: updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n model_usage: Object.keys(modelUsageMap).length > 0 ? modelUsageMap : undefined,\n });\n }\n\n private parseFastSessionHeadResult(filePath: string): ParseSessionResult<SessionHead> {\n const lines = readLeadingJsonlLines(filePath, 20);\n if (lines.length === 0) return skippedSession(\"empty file\");\n\n const sessionId = extractSessionId(filePath);\n\n let firstRecord: Record<string, unknown>;\n try {\n firstRecord = JSON.parse(lines[0]!);\n } catch (error) {\n getCoreDiagnostics()?.warn(\"codex.fast_head_first_record_failed\", {\n filePath,\n firstLineLength: lines[0]?.length ?? 0,\n message: error instanceof Error ? error.message : String(error),\n });\n return skippedSession(\"malformed first record\");\n }\n\n const threadMeta = extractThreadMeta(firstRecord);\n const parentThreadId =\n threadMeta?.threadSource === \"subagent\" ? threadMeta.parentThreadId : null;\n\n const payload = extractPayload(firstRecord);\n const stat = statSync(filePath);\n const createdAt = parseTimestampMs(firstRecord) || parseTimestampMs(payload) || stat.mtimeMs;\n const indexTitle = this.getTitleForSession(sessionId);\n const messageTitle = this.extractTitleFromLines(lines);\n const directory = payload[\"cwd\"] ? String(payload[\"cwd\"]) : \"\";\n const directoryTitle = basenameTitle(directory || null);\n const title = resolveSessionTitle(indexTitle, messageTitle, directoryTitle);\n\n return parsedSession({\n id: sessionId,\n slug: this.sessionSlug(sessionId),\n title,\n directory,\n parent_reference:\n parentThreadId == null ? undefined : { agentName: this.name, sessionId: parentThreadId },\n time_created: createdAt,\n time_updated: stat.mtimeMs,\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n });\n }\n\n /** Fast path only: parses each of the first 20 lines to find a title (no full stats pass available). */\n private extractTitleFromLines(lines: string[]): string | null {\n for (const line of lines.slice(0, 20)) {\n try {\n const title = this.extractCodexRecordTitle(JSON.parse(line));\n if (title) return title;\n } catch {\n // skip\n }\n }\n return null;\n }\n\n /**\n * Title candidate from a single already-parsed record, if it's a visible\n * user message. Shared by the main streaming pass (which parses every line\n * once) and the fast path's extractTitleFromLines().\n */\n private extractCodexRecordTitle(data: Record<string, unknown>): string | null {\n const recordType = String(data[\"type\"] ?? \"\");\n if (recordType !== \"response_item\" || isInternalEventType(recordType)) return null;\n\n const payload = extractPayload(data);\n const pType = String(payload[\"type\"] ?? \"\");\n if (pType !== \"message\" || isInternalEventType(pType)) return null;\n if (String(payload[\"role\"] ?? \"\") !== \"user\") return null;\n\n const content = payload[\"content\"];\n let text: string | null = null;\n if (Array.isArray(content)) {\n text = content\n .map((item) => {\n const record = asRecord(item);\n return record ? String(record[\"text\"] ?? \"\") : \"\";\n })\n .join(\" \");\n } else if (typeof content === \"string\") {\n text = content;\n }\n if (!text || isDeveloperLikeUserMessage(text)) return null;\n return normalizeTitleText(text) || null;\n }\n\n // ---- Record conversion ----\n\n private convertRecord(\n data: Record<string, unknown>,\n transcript: TranscriptBuilder,\n pendingPlan: MessagePart | null,\n activeModel: string | null,\n ): MessagePart | null {\n const recordType = String(data[\"type\"] ?? \"\");\n if (isInternalEventType(recordType)) return pendingPlan;\n\n if (recordType === \"session_meta\" || recordType === \"event_msg\") {\n return pendingPlan;\n }\n\n if (recordType !== \"response_item\") return pendingPlan;\n\n const payload = extractPayload(data);\n const payloadType = String(payload[\"type\"] ?? \"\");\n if (isInternalEventType(payloadType)) return pendingPlan;\n const timestampMs = parseTimestampMs(data) || parseTimestampMs(payload);\n\n switch (payloadType) {\n case \"message\": {\n const role = String(payload[\"role\"] ?? \"\");\n if (role === \"assistant\") {\n return this.convertAssistantMessage(\n payload,\n transcript,\n timestampMs,\n pendingPlan,\n activeModel,\n );\n }\n if (role === \"user\") {\n return this.convertUserMessage(payload, transcript, timestampMs, pendingPlan);\n }\n break;\n }\n\n case \"reasoning\":\n this.convertReasoning(payload, transcript, timestampMs, activeModel);\n return null;\n\n case \"function_call\":\n this.convertFunctionCall(payload, transcript, timestampMs, activeModel);\n return null;\n\n case \"function_call_output\":\n this.convertToolCallOutput(payload, transcript, timestampMs);\n return pendingPlan;\n\n case \"custom_tool_call\":\n this.convertCustomToolCall(payload, transcript, timestampMs, activeModel);\n return null;\n\n case \"custom_tool_call_output\":\n this.convertToolCallOutput(payload, transcript, timestampMs);\n return pendingPlan;\n }\n\n return pendingPlan;\n }\n\n // ---- Assistant message ----\n\n private convertAssistantMessage(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n pendingPlan: MessagePart | null,\n activeModel: string | null,\n ): MessagePart | null {\n const fullText = extractAssistantOutputText(payload);\n if (!fullText) return pendingPlan;\n\n const planMatch = fullText.match(PROPOSED_PLAN_PATTERN);\n if (planMatch) {\n const planText = planMatch[1]!.trim();\n const planPart: MessagePart = {\n type: \"plan\",\n text: planText,\n approval_status: \"success\",\n time_created: timestampMs,\n };\n pendingPlan = planPart;\n }\n\n const displayText = cleanInternalText(fullText.replace(PROPOSED_PLAN_PATTERN, \"\"));\n if (!displayText) return pendingPlan;\n\n const textPart: MessagePart = { type: \"text\", text: displayText, time_created: timestampMs };\n transcript.appendAssistantPart(textPart, {\n id: \"\",\n timestampMs,\n agent: \"codex\",\n model: activeModel,\n });\n return pendingPlan;\n }\n\n // ---- User message ----\n\n private convertUserMessage(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n pendingPlan: MessagePart | null,\n ): MessagePart | null {\n const content = payload[\"content\"];\n const text = Array.isArray(content)\n ? content\n .map((c) => {\n if (Array.isArray(c)) return \"\";\n const record = asRecord(c);\n return record ? String(record[\"text\"] ?? \"\") : String(c ?? \"\");\n })\n .join(\" \")\n : String(content ?? \"\");\n\n const visibleText = cleanInternalText(text);\n if (!visibleText) return pendingPlan;\n\n if (isDeveloperLikeUserMessage(visibleText)) return pendingPlan;\n\n if (visibleText.trimStart().startsWith(PLAN_APPROVAL_PREFIX)) {\n if (pendingPlan) transcript.appendToCurrentAssistant(pendingPlan);\n transcript.appendMessage({\n id: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: visibleText, time_created: timestampMs }],\n });\n return null;\n }\n\n const subagentMatch = visibleText.match(SUBAGENT_NOTIFICATION_PATTERN);\n if (subagentMatch) {\n // Malformed or non-object notification payloads fall through and are\n // treated as normal user messages below.\n let notifPayload: Record<string, unknown> | undefined;\n try {\n notifPayload = asRecord(JSON.parse(subagentMatch[1]!));\n } catch {\n notifPayload = undefined;\n }\n\n if (notifPayload) {\n const agentId = String(notifPayload[\"agent_id\"] ?? \"\");\n const nickname = String(notifPayload[\"nickname\"] ?? \"\");\n const completedText = String(notifPayload[\"completed\"] ?? \"\");\n\n const textPart: MessagePart = {\n type: \"text\",\n text: completedText || `Subagent ${nickname} completed`,\n time_created: timestampMs,\n };\n\n transcript.appendMessage({\n id: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [textPart],\n agent: \"codex\",\n subagentId: agentId || undefined,\n nickname: nickname || undefined,\n });\n transcript.beginTurn();\n return pendingPlan;\n }\n }\n\n transcript.appendMessage({\n id: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: visibleText, time_created: timestampMs }],\n });\n return pendingPlan;\n }\n\n // ---- Reasoning ----\n\n private convertReasoning(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const summary = payload[\"summary\"];\n if (!Array.isArray(summary)) return;\n\n const texts: string[] = [];\n for (const item of summary) {\n const ci = asRecord(item);\n if (!ci) continue;\n if (String(ci[\"type\"] ?? \"\") === \"summary_text\") {\n const text = String(ci[\"text\"] ?? \"\");\n if (text.trim()) texts.push(text);\n }\n }\n\n if (texts.length === 0) return;\n\n const reasoningText = texts.join(\"\\n\");\n const part: MessagePart = { type: \"reasoning\", text: reasoningText, time_created: timestampMs };\n transcript.appendAssistantPart(\n part,\n {\n id: \"\",\n timestampMs,\n agent: \"codex\",\n model: activeModel,\n },\n { resetLatestText: true },\n );\n }\n\n // ---- Function call ----\n\n private convertFunctionCall(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) return;\n\n const toolIdentity = resolveToolIdentity(name, payload[\"namespace\"]);\n const arguments_ = normalizeToolArguments(payload[\"arguments\"]);\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolIdentity.tool,\n callID: callId,\n title: `Tool: ${toolIdentity.tool}`,\n state: {\n status: \"running\",\n input: arguments_,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n transcript.appendToolCall(\n toolPart,\n { id: \"\", timestampMs, agent: \"codex\", model: activeModel },\n { markModeAsTool: true },\n );\n }\n\n // ---- Function call output ----\n\n private convertToolCallOutput(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n if (!callId) return;\n\n const outputText = cleanInternalText(\n stripExecOutputEnvelope(flattenOutputText(payload[\"output\"])),\n );\n const outputParts: MessagePart[] = outputText\n ? [{ type: \"text\", text: outputText, time_created: timestampMs }]\n : [];\n\n if (outputParts.length > 0) {\n transcript.resolveToolCall(callId, { output: outputParts, status: \"completed\" });\n }\n }\n\n // ---- Custom tool call ----\n\n private convertCustomToolCall(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) return;\n\n // Code-mode exec: the JS program wraps native tool calls. Decode each\n // inner call back to its classic tool part so existing displays apply.\n // Programs with no recognizable call fall through to the raw exec part.\n if (name === \"exec\") {\n const decoded = decodeExecCalls(payload[\"input\"]);\n if (decoded.length > 0) {\n this.appendDecodedExecCalls(decoded, callId, transcript, timestampMs, activeModel);\n return;\n }\n }\n\n const toolIdentity = resolveToolIdentity(name, payload[\"namespace\"]);\n const rawInput = payload[\"input\"];\n const normalizedInput = normalizeCustomToolArguments(name, rawInput);\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolIdentity.tool,\n callID: callId,\n title: `Tool: ${toolIdentity.tool}`,\n state: {\n status: \"running\",\n input: normalizedInput,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n transcript.appendToolCall(\n toolPart,\n { id: \"\", timestampMs, agent: \"codex\", model: activeModel },\n { markModeAsTool: true },\n );\n }\n\n // ---- Decoded code-mode exec calls ----\n\n private appendDecodedExecCalls(\n calls: ExecInnerCall[],\n callId: string,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n // Only one output record follows, keyed by the exec call id; route it to\n // the output-bearing part and give the rest unique ids so they still\n // register and render, just without a resolved output.\n const outputIndex = pickExecOutputTarget(calls);\n calls.forEach((call, index) => {\n const partCallId = index === outputIndex ? callId : `${callId}#${index}`;\n this.appendDecodedExecCall(call, partCallId, transcript, timestampMs, activeModel);\n });\n }\n\n private appendDecodedExecCall(\n call: ExecInnerCall,\n callId: string,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const { name, namespace } = splitExecToolName(call.name);\n const toolIdentity = resolveToolIdentity(name, namespace);\n const arguments_ =\n name === \"apply_patch\" ? parseApplyPatchInput(getExecPatchText(call.args)) : call.args;\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolIdentity.tool,\n callID: callId,\n title: `Tool: ${toolIdentity.tool}`,\n state: {\n status: \"running\",\n input: arguments_,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n transcript.appendToolCall(\n toolPart,\n { id: \"\", timestampMs, agent: \"codex\", model: activeModel },\n { markModeAsTool: true },\n );\n }\n}\n","/**\n * Codex \"code mode\" exec decoding.\n *\n * Since Codex 0.144.x the agent no longer calls tools directly. Every tool\n * invocation is now a `custom_tool_call` named \"exec\" whose `input` is a small\n * JS program that calls `tools.<name>({...})` (e.g. `tools.exec_command`,\n * `tools.apply_patch`). This module extracts those inner invocations so the\n * adapter can present each one as the native tool call it used to be.\n *\n * The inner argument objects are JS object literals, not JSON — unquoted keys,\n * single/double/template strings, and shorthand `{patch}` that references a\n * `const patch = \"...\"` declared earlier. A small tolerant reader handles that\n * subset and resolves string variables; anything it cannot parse degrades to an\n * empty result so the caller can fall back to the raw exec display.\n */\n\nexport interface ExecInnerCall {\n name: string;\n args: unknown;\n}\n\nconst PARSE_FAIL = Symbol(\"parse-fail\");\n\nconst EXEC_OUTPUT_ENVELOPE_RE = /^Script completed\\nWall time [^\\n]*\\nOutput:\\n?/;\n\n/** Strip the `Script completed / Wall time / Output:` wrapper code-mode adds. */\nexport function stripExecOutputEnvelope(text: string): string {\n return text.replace(EXEC_OUTPUT_ENVELOPE_RE, \"\");\n}\n\n/**\n * Split an inner tool name into `resolveToolIdentity(name, namespace)` inputs.\n * `mcp__node_repl__js` → { name: \"js\", namespace: \"mcp__node_repl__\" }.\n */\nexport function splitExecToolName(name: string): { name: string; namespace?: string } {\n if (name.startsWith(\"mcp__\")) {\n const separator = name.lastIndexOf(\"__\");\n if (separator > 0 && separator + 2 < name.length) {\n return { name: name.slice(separator + 2), namespace: name.slice(0, separator + 2) };\n }\n }\n return { name };\n}\n\n/**\n * Pick which decoded call receives the exec program's combined output. Patch\n * and plan calls do not emit stdout, so prefer the last output-bearing call;\n * otherwise fall back to the last call.\n */\nexport function pickExecOutputTarget(calls: ExecInnerCall[]): number {\n for (let index = calls.length - 1; index >= 0; index -= 1) {\n const { name } = splitExecToolName(calls[index]!.name);\n if (name !== \"apply_patch\" && name !== \"update_plan\") return index;\n }\n return calls.length - 1;\n}\n\n/** Extract the patch text from an `apply_patch` argument (`{patch}` or a string). */\nexport function getExecPatchText(args: unknown): string {\n if (typeof args === \"string\") return args;\n if (args && typeof args === \"object\") {\n const patch = (args as Record<string, unknown>)[\"patch\"];\n if (typeof patch === \"string\") return patch;\n }\n return \"\";\n}\n\n/** Decode the `tools.<name>({...})` invocations inside a code-mode exec program. */\nexport function decodeExecCalls(input: unknown): ExecInnerCall[] {\n if (typeof input !== \"string\" || !input.includes(\"tools.\")) return [];\n\n const scope = collectStringVars(input);\n const calls: ExecInnerCall[] = [];\n const callRe = /tools\\.([A-Za-z_$][\\w$]*)\\s*\\(/g;\n let match: RegExpExecArray | null;\n while ((match = callRe.exec(input)) !== null) {\n const reader = new JsValueReader(input, callRe.lastIndex, scope);\n const args = reader.parseValue();\n if (args !== PARSE_FAIL) {\n calls.push({ name: match[1]!, args });\n callRe.lastIndex = reader.pos;\n }\n }\n return calls;\n}\n\n/** Pre-scan `const/let/var NAME = \"...\"` so shorthand args can resolve them. */\nfunction collectStringVars(input: string): Map<string, unknown> {\n const scope = new Map<string, unknown>();\n const assignRe = /(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*/g;\n let match: RegExpExecArray | null;\n while ((match = assignRe.exec(input)) !== null) {\n const reader = new JsValueReader(input, assignRe.lastIndex, scope);\n const value = reader.parseValue();\n if (value !== PARSE_FAIL) {\n if (typeof value === \"string\") scope.set(match[1]!, value);\n assignRe.lastIndex = reader.pos;\n }\n }\n return scope;\n}\n\nconst IDENT_START_RE = /[A-Za-z_$]/;\nconst IDENT_PART_RE = /[\\w$]/;\n\n/** Recursive-descent reader for the JS-literal subset used in exec args. */\nclass JsValueReader {\n pos: number;\n private readonly src: string;\n private readonly scope: Map<string, unknown>;\n\n constructor(src: string, start: number, scope: Map<string, unknown>) {\n this.src = src;\n this.pos = start;\n this.scope = scope;\n }\n\n parseValue(): unknown | typeof PARSE_FAIL {\n this.skipTrivia();\n const char = this.src[this.pos];\n if (char === undefined) return PARSE_FAIL;\n if (char === \"{\") return this.parseObject();\n if (char === \"[\") return this.parseArray();\n if (char === '\"' || char === \"'\" || char === \"`\") return this.parseString(char);\n if (char === \"-\" || char === \"+\" || (char >= \"0\" && char <= \"9\")) return this.parseNumber();\n if (IDENT_START_RE.test(char)) return this.parseIdentifierValue();\n return PARSE_FAIL;\n }\n\n private parseObject(): unknown | typeof PARSE_FAIL {\n this.pos++; // {\n const result: Record<string, unknown> = {};\n this.skipTrivia();\n if (this.src[this.pos] === \"}\") {\n this.pos++;\n return result;\n }\n while (this.pos < this.src.length) {\n this.skipTrivia();\n const key = this.parseKey();\n if (key === PARSE_FAIL) return PARSE_FAIL;\n this.skipTrivia();\n if (this.src[this.pos] === \":\") {\n this.pos++;\n const value = this.parseValue();\n if (value === PARSE_FAIL) return PARSE_FAIL;\n result[key] = value;\n } else {\n result[key] = this.resolveIdentifier(key);\n }\n this.skipTrivia();\n const next = this.src[this.pos];\n if (next === \",\") {\n this.pos++;\n this.skipTrivia();\n if (this.src[this.pos] === \"}\") {\n this.pos++;\n return result;\n }\n continue;\n }\n if (next === \"}\") {\n this.pos++;\n return result;\n }\n return PARSE_FAIL;\n }\n return PARSE_FAIL;\n }\n\n private parseArray(): unknown | typeof PARSE_FAIL {\n this.pos++; // [\n const result: unknown[] = [];\n this.skipTrivia();\n if (this.src[this.pos] === \"]\") {\n this.pos++;\n return result;\n }\n while (this.pos < this.src.length) {\n const value = this.parseValue();\n if (value === PARSE_FAIL) return PARSE_FAIL;\n result.push(value);\n this.skipTrivia();\n const next = this.src[this.pos];\n if (next === \",\") {\n this.pos++;\n this.skipTrivia();\n if (this.src[this.pos] === \"]\") {\n this.pos++;\n return result;\n }\n continue;\n }\n if (next === \"]\") {\n this.pos++;\n return result;\n }\n return PARSE_FAIL;\n }\n return PARSE_FAIL;\n }\n\n private parseKey(): string | typeof PARSE_FAIL {\n const char = this.src[this.pos];\n if (char === '\"' || char === \"'\" || char === \"`\") {\n const value = this.parseString(char);\n return typeof value === \"string\" ? value : PARSE_FAIL;\n }\n if (char !== undefined && IDENT_START_RE.test(char)) return this.readIdentifier();\n return PARSE_FAIL;\n }\n\n private parseString(quote: string): string {\n this.pos++; // opening quote\n let out = \"\";\n while (this.pos < this.src.length) {\n const char = this.src[this.pos++]!;\n if (char === \"\\\\\") {\n out += this.readEscape();\n continue;\n }\n if (char === quote) break;\n out += char;\n }\n return out;\n }\n\n private readEscape(): string {\n const char = this.src[this.pos++];\n switch (char) {\n case \"n\":\n return \"\\n\";\n case \"t\":\n return \"\\t\";\n case \"r\":\n return \"\\r\";\n case \"b\":\n return \"\\b\";\n case \"f\":\n return \"\\f\";\n case \"v\":\n return \"\\v\";\n case \"0\":\n return \"\\0\";\n case \"u\": {\n const hex = this.src.slice(this.pos, this.pos + 4);\n if (/^[0-9a-fA-F]{4}$/.test(hex)) {\n this.pos += 4;\n return String.fromCharCode(parseInt(hex, 16));\n }\n return \"u\";\n }\n case \"x\": {\n const hex = this.src.slice(this.pos, this.pos + 2);\n if (/^[0-9a-fA-F]{2}$/.test(hex)) {\n this.pos += 2;\n return String.fromCharCode(parseInt(hex, 16));\n }\n return \"x\";\n }\n default:\n return char ?? \"\";\n }\n }\n\n private parseNumber(): number | typeof PARSE_FAIL {\n const numberRe = /[-+]?(?:0[xX][0-9a-fA-F]+|(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?)/y;\n numberRe.lastIndex = this.pos;\n const match = numberRe.exec(this.src);\n if (!match) return PARSE_FAIL;\n this.pos += match[0].length;\n return Number(match[0]);\n }\n\n private parseIdentifierValue(): unknown {\n const name = this.readIdentifier();\n if (name === \"true\") return true;\n if (name === \"false\") return false;\n if (name === \"null\") return null;\n if (name === \"undefined\") return undefined;\n return this.resolveIdentifier(name);\n }\n\n private resolveIdentifier(name: string): unknown {\n return this.scope.has(name) ? this.scope.get(name) : undefined;\n }\n\n private readIdentifier(): string {\n const start = this.pos;\n while (this.pos < this.src.length && IDENT_PART_RE.test(this.src[this.pos]!)) this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private skipTrivia(): void {\n while (this.pos < this.src.length) {\n const char = this.src[this.pos]!;\n if (char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\") {\n this.pos++;\n continue;\n }\n if (char === \"/\" && this.src[this.pos + 1] === \"/\") {\n const newline = this.src.indexOf(\"\\n\", this.pos + 2);\n this.pos = newline === -1 ? this.src.length : newline + 1;\n continue;\n }\n if (char === \"/\" && this.src[this.pos + 1] === \"*\") {\n const close = this.src.indexOf(\"*/\", this.pos + 2);\n this.pos = close === -1 ? this.src.length : close + 2;\n continue;\n }\n break;\n }\n }\n}\n","import { existsSync, lstatSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join, normalize } from \"node:path\";\nimport {\n DatabaseSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n SessionScanError,\n} from \"./base.js\";\nimport type { AgentScanOptions } from \"./base.js\";\nimport type {\n SessionHead,\n SessionDetail,\n Message,\n MessagePart,\n ToolPartState,\n} from \"../types/index.js\";\nimport { normalizeMessageParts } from \"../contract/message-part.js\";\nimport { firstExisting, readEnvPath } from \"../discovery/paths.js\";\nimport {\n openDbReadOnly,\n isSqliteAvailable,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../utils/sqlite.js\";\nimport { resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport {\n cleanInternalText,\n cleanParsedMessages,\n firstUserMessageTitle,\n} from \"../utils/session-normalization.js\";\nimport { perf } from \"../utils/perf.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport {\n asArray,\n asNumber,\n asRecord,\n asString,\n narrowField,\n safeParseJsonRecord,\n} from \"../utils/narrow.js\";\n\nexport function resolveCursorDataRoot(): string | null {\n const override = readEnvPath(\"CURSOR_DATA_PATH\");\n if (override) return override;\n\n const currentPlatform = platform();\n if (currentPlatform === \"darwin\") {\n return firstExisting(join(homedir(), \"Library\", \"Application Support\", \"Cursor\", \"User\"));\n }\n if (currentPlatform === \"linux\") {\n const configRoot = readEnvPath(\"XDG_CONFIG_HOME\") ?? join(homedir(), \".config\");\n return firstExisting(join(configRoot, \"Cursor\", \"User\"));\n }\n if (currentPlatform === \"win32\") {\n const appData = readEnvPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Roaming\");\n return firstExisting(join(appData, \"Cursor\", \"User\"));\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Cursor data model interfaces\n// ---------------------------------------------------------------------------\n\ninterface ComposerData {\n id?: string;\n composerId?: string;\n text?: string;\n name?: string;\n title?: string;\n createdAt?: number;\n updatedAt?: number;\n lastSendTime?: number;\n lastUpdatedAt?: number;\n model?: string;\n modelConfig?: { modelName?: string };\n inputTokenCount?: number;\n outputTokenCount?: number;\n subagentInfos?: SubagentInfo[];\n chatMessages?: ChatMessage[];\n usageData?: {\n contextTokensUsed?: number;\n contextTokenLimit?: number;\n contextUsagePercent?: number;\n };\n}\n\ninterface BubbleData {\n id?: string;\n composerId?: string;\n chatMessages?: ChatMessage[];\n type?: number; // 1 = user, 2 = assistant\n text?: string;\n requestId?: string;\n createdAt?: number;\n timestamp?: number;\n timingInfo?: {\n clientRpcSendTime?: number;\n clientSettleTime?: number;\n clientEndTime?: number;\n };\n tokenCount?: {\n inputTokens?: number;\n outputTokens?: number;\n };\n modelInfo?: {\n modelName?: string;\n };\n toolFormerData?: {\n name?: string;\n toolCallId?: string;\n status?: string;\n params?: unknown;\n result?: unknown;\n additionalData?: Record<string, unknown>;\n };\n [key: string]: unknown;\n}\n\ninterface SubagentInfo {\n id?: string;\n composerId?: string;\n title?: string;\n nickname?: string;\n}\n\ninterface ChatMessage {\n role: string;\n text?: string;\n createdAt?: number;\n timestamp?: number;\n actions?: ActionEntry[];\n isCompletion?: boolean;\n [key: string]: unknown;\n}\n\ninterface ActionEntry {\n type?: string;\n tool?: string;\n input?: Record<string, unknown>;\n output?: unknown;\n state?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Safe parsing of external rows — cursorDiskKV values and workspace.json are\n// untrusted (cross Cursor-version drift), so their fields are narrowed\n// individually instead of blindly cast. A field that's absent behaves like\n// today's optional-field fallback (?? 0 / skip); a field that's present but\n// wrong-typed additionally reports once via diagnostics.\n// ---------------------------------------------------------------------------\n\nfunction narrowString(field: string, value: unknown): string | undefined {\n return narrowField(\"cursor\", field, value, asString);\n}\n\nfunction narrowNumber(field: string, value: unknown): number | undefined {\n return narrowField(\"cursor\", field, value, asNumber);\n}\n\nfunction parseSubagentInfos(value: unknown): SubagentInfo[] | undefined {\n const arr = asArray(value);\n if (arr === undefined) return undefined;\n const infos: SubagentInfo[] = [];\n for (const item of arr) {\n const record = asRecord(item);\n if (!record) continue;\n infos.push({\n id: narrowString(\"subagentInfo.id\", record.id),\n composerId: narrowString(\"subagentInfo.composerId\", record.composerId),\n title: narrowString(\"subagentInfo.title\", record.title),\n nickname: narrowString(\"subagentInfo.nickname\", record.nickname),\n });\n }\n return infos;\n}\n\nfunction parseChatMessages(value: unknown): ChatMessage[] | undefined {\n const arr = asArray(value);\n if (arr === undefined) return undefined;\n const messages: ChatMessage[] = [];\n for (const item of arr) {\n const record = asRecord(item);\n if (!record) continue;\n const role = narrowString(\"chatMessage.role\", record.role);\n if (role === undefined) continue;\n messages.push({ ...record, role, text: narrowString(\"chatMessage.text\", record.text) });\n }\n return messages;\n}\n\n/** Parse a `composerData:*` row value into a field-validated ComposerData. */\nfunction parseComposerRow(value: string): ComposerData | null {\n const record = safeParseJsonRecord(value);\n if (!record) return null;\n\n const modelConfig = asRecord(record.modelConfig);\n\n return {\n id: narrowString(\"composer.id\", record.id),\n composerId: narrowString(\"composer.composerId\", record.composerId),\n text: narrowString(\"composer.text\", record.text),\n name: narrowString(\"composer.name\", record.name),\n title: narrowString(\"composer.title\", record.title),\n createdAt: narrowNumber(\"composer.createdAt\", record.createdAt),\n updatedAt: narrowNumber(\"composer.updatedAt\", record.updatedAt),\n lastSendTime: narrowNumber(\"composer.lastSendTime\", record.lastSendTime),\n lastUpdatedAt: narrowNumber(\"composer.lastUpdatedAt\", record.lastUpdatedAt),\n model: narrowString(\"composer.model\", record.model),\n modelConfig: modelConfig\n ? { modelName: narrowString(\"composer.modelConfig.modelName\", modelConfig.modelName) }\n : undefined,\n inputTokenCount: narrowNumber(\"composer.inputTokenCount\", record.inputTokenCount),\n outputTokenCount: narrowNumber(\"composer.outputTokenCount\", record.outputTokenCount),\n subagentInfos: parseSubagentInfos(record.subagentInfos),\n chatMessages: parseChatMessages(record.chatMessages),\n };\n}\n\ninterface BubbleRow extends DatabaseRow {\n row_id: number;\n key: string;\n value: string;\n}\n\ninterface BubbleEntry {\n rowId: number;\n key: string;\n bubble: BubbleData;\n}\n\n/**\n * One composer's bubbles, parsed once and offered in both orders the readers\n * need: request ids come from the key-ordered view, messages from insertion\n * order.\n */\ninterface ComposerBubbles {\n composerId: string;\n byKey: BubbleEntry[];\n byRowId: BubbleEntry[];\n}\n\n/** A composer waiting for its bubbles in the second phase of a scan. */\ninterface PendingComposer {\n composer: ComposerData;\n composerId: string;\n createdAt: number;\n updatedAt: number;\n hasSubagents: boolean;\n order: number;\n}\n\nfunction composerIdFromBubbleKey(key: string): string {\n const start = key.indexOf(\":\") + 1;\n const end = key.indexOf(\":\", start);\n return end === -1 ? key.slice(start) : key.slice(start, end);\n}\n\nfunction groupBubbleRows(rows: BubbleRow[]): ComposerBubbles {\n const byKey: BubbleEntry[] = [];\n for (const row of rows) {\n const bubble = parseBubbleRow(row.value);\n if (bubble) byKey.push({ rowId: row.row_id, key: row.key, bubble });\n }\n byKey.sort((left, right) => left.key.localeCompare(right.key));\n return {\n composerId: rows.length > 0 ? composerIdFromBubbleKey(rows[0]!.key) : \"\",\n byKey,\n byRowId: [...byKey].sort((left, right) => left.rowId - right.rowId),\n };\n}\n\n/** Parse a `bubbleId:*` / `bubble:*` row value into a field-validated BubbleData. */\nfunction parseBubbleRow(value: string): BubbleData | null {\n const record = safeParseJsonRecord(value);\n if (!record) return null;\n\n const timingInfo = asRecord(record.timingInfo);\n const tokenCount = asRecord(record.tokenCount);\n const modelInfo = asRecord(record.modelInfo);\n const toolFormerData = asRecord(record.toolFormerData);\n\n return {\n ...record,\n id: narrowString(\"bubble.id\", record.id),\n composerId: narrowString(\"bubble.composerId\", record.composerId),\n chatMessages: parseChatMessages(record.chatMessages),\n type: narrowNumber(\"bubble.type\", record.type),\n text: narrowString(\"bubble.text\", record.text),\n requestId: narrowString(\"bubble.requestId\", record.requestId),\n createdAt: narrowNumber(\"bubble.createdAt\", record.createdAt),\n timestamp: narrowNumber(\"bubble.timestamp\", record.timestamp),\n timingInfo: timingInfo\n ? {\n clientRpcSendTime: narrowNumber(\n \"bubble.timingInfo.clientRpcSendTime\",\n timingInfo.clientRpcSendTime,\n ),\n clientSettleTime: narrowNumber(\n \"bubble.timingInfo.clientSettleTime\",\n timingInfo.clientSettleTime,\n ),\n clientEndTime: narrowNumber(\"bubble.timingInfo.clientEndTime\", timingInfo.clientEndTime),\n }\n : undefined,\n tokenCount: tokenCount\n ? {\n inputTokens: narrowNumber(\"bubble.tokenCount.inputTokens\", tokenCount.inputTokens),\n outputTokens: narrowNumber(\"bubble.tokenCount.outputTokens\", tokenCount.outputTokens),\n }\n : undefined,\n modelInfo: modelInfo\n ? { modelName: narrowString(\"bubble.modelInfo.modelName\", modelInfo.modelName) }\n : undefined,\n toolFormerData: toolFormerData\n ? {\n name: narrowString(\"bubble.toolFormerData.name\", toolFormerData.name),\n toolCallId: narrowString(\"bubble.toolFormerData.toolCallId\", toolFormerData.toolCallId),\n status: narrowString(\"bubble.toolFormerData.status\", toolFormerData.status),\n params: toolFormerData.params,\n result: toolFormerData.result,\n additionalData: asRecord(toolFormerData.additionalData),\n }\n : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst CURSOR_TOOL_TITLE_MAP: Record<string, string> = {\n read_file_v2: \"read\",\n edit_file_v2: \"edit\",\n run_terminal_command_v2: \"bash\",\n ripgrep_raw_search: \"grep\",\n glob_file_search: \"glob\",\n};\n\nfunction mapToolTitle(toolName: string): string {\n return CURSOR_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\n/** Normalize tool output into MessagePart[] */\nfunction normalizeToolOutputParts(output: unknown, timestampMs: number): MessagePart[] {\n if (output == null) return [];\n\n if (typeof output === \"string\") {\n const text = cleanInternalText(output);\n return text ? [{ type: \"text\" as const, text, time_created: timestampMs }] : [];\n }\n\n if (Array.isArray(output)) {\n const parts: MessagePart[] = [];\n for (const item of output) {\n if (typeof item === \"object\" && item !== null) {\n const record = asRecord(item);\n const text = String(record?.text ?? record?.content ?? \"\");\n const cleaned = cleanInternalText(text);\n if (cleaned) parts.push({ type: \"text\", text: cleaned, time_created: timestampMs });\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n }\n return parts;\n }\n\n // For object output, stringify for readability\n const text = cleanInternalText(String(output));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\n/** Extract a timestamp (in ms) from a chat message */\nfunction extractTimestamp(msg: ChatMessage): number {\n if (msg.createdAt && typeof msg.createdAt === \"number\" && msg.createdAt > 0) {\n return msg.createdAt;\n }\n if (msg.timestamp && typeof msg.timestamp === \"number\" && msg.timestamp > 0) {\n return msg.timestamp;\n }\n return 0;\n}\n\nfunction isInternalBubble(bubble: BubbleData): boolean {\n return [\"eventType\", \"kind\", \"subtype\", \"name\"].some((key) => isInternalEventType(bubble[key]));\n}\n\nfunction composerUpdatedAt(composer: ComposerData): number {\n return (\n composer.updatedAt ?? composer.lastUpdatedAt ?? composer.lastSendTime ?? composer.createdAt ?? 0\n );\n}\n\nfunction cursorToolStatus(status: string | undefined): ToolPartState[\"status\"] {\n if (status === \"completed\") return \"completed\";\n if (status === \"error\" || status === \"failed\") return \"error\";\n return \"running\";\n}\n\n/** Build a normalized tool state object from an action entry */\nfunction buildToolState(action: ActionEntry): ToolPartState {\n let output = action.output;\n if (action.output != null) {\n const ts = 0; // we don't have a finer-grained timestamp for the output\n const outputParts = normalizeToolOutputParts(action.output, ts);\n output = outputParts.length > 0 ? outputParts : action.output;\n }\n\n const [part] = normalizeMessageParts([\n {\n type: \"tool\",\n tool: action.tool ?? \"unknown\",\n input: action.input,\n output,\n state: action.state,\n },\n ]);\n return part?.type === \"tool\" ? part.state : { status: \"running\" };\n}\n\n/** Build a MessagePart for a tool action */\nfunction buildToolPart(action: ActionEntry, timestampMs: number): MessagePart {\n const toolName = action.tool ?? \"unknown\";\n return {\n type: \"tool\",\n tool: mapToolTitle(toolName),\n callID: action.type ? `${action.type}:${String(action.input?.id ?? \"\")}` : \"\",\n title: `Tool: ${mapToolTitle(toolName)}`,\n state: buildToolState(action),\n time_created: timestampMs,\n };\n}\n\n/** Build a MessagePart for terminal command actions */\nfunction buildTerminalToolPart(action: ActionEntry, timestampMs: number): MessagePart {\n const command = String(action.input?.command ?? \"\");\n const description = cleanInternalText(String(action.input?.commandDescription ?? \"\"));\n\n const state = buildToolState(action);\n state.input = { command };\n state.output =\n typeof action.output === \"string\"\n ? [{ type: \"text\" as const, text: action.output, time_created: timestampMs }]\n : normalizeToolOutputParts(action.output, timestampMs);\n\n return {\n type: \"tool\",\n tool: \"bash\",\n callID: \"\",\n title: description || `bash: ${command.slice(0, 60)}`,\n state,\n time_created: timestampMs,\n };\n}\n\n/** Convert an ActionEntry into a MessagePart */\nfunction convertActionToPart(action: ActionEntry, timestampMs: number): MessagePart | null {\n const toolName = action.tool ?? \"\";\n\n // Terminal commands get special handling\n if (toolName === \"run_terminal_command_v2\") {\n return buildTerminalToolPart(action, timestampMs);\n }\n\n // Generic tool call\n if (toolName && action.type === \"tool\") {\n return buildToolPart(action, timestampMs);\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// CursorAgent\n// ---------------------------------------------------------------------------\n\nexport class CursorAgent extends DatabaseSessionSource {\n readonly name = \"cursor\";\n readonly displayName = \"Cursor\";\n\n private dbPath: string | null = null;\n\n private composerCache = new Map<string, ComposerData>();\n private directoryCache = new Map<string, string>();\n\n protected getDatabasePath(): string | null {\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n return this.dbPath;\n }\n\n private findDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n const dataPath = resolveCursorDataRoot();\n if (!dataPath) return null;\n return join(dataPath, \"globalStorage\", \"state.vscdb\");\n }\n\n getSessionWatchPlan() {\n const dataPath = resolveCursorDataRoot();\n return {\n status: \"supported\" as const,\n targets: dataPath\n ? [\n {\n root: dataPath,\n path: join(dataPath, \"globalStorage\", \"state.vscdb\"),\n },\n { root: dataPath, path: join(dataPath, \"workspaceStorage\") },\n ]\n : [],\n };\n }\n\n /**\n * Build a map of composerId → workspace folder path by reading\n * workspaceStorage/{id}/workspace.json and the corresponding state.vscdb.\n */\n private buildWorkspacePathMap(): Map<string, string> {\n const map = new Map<string, string>();\n const dataPath = resolveCursorDataRoot();\n if (!dataPath) return map;\n\n const wsStoragePath = join(dataPath, \"workspaceStorage\");\n if (!existsSync(wsStoragePath)) return map;\n\n let entryNames: string[];\n try {\n entryNames = readdirSync(wsStoragePath) as string[];\n } catch {\n return map;\n }\n\n for (const name of entryNames) {\n const wsDir = join(wsStoragePath, name);\n try {\n if (!lstatSync(wsDir).isDirectory()) continue;\n } catch {\n continue;\n }\n const wsJsonPath = join(wsDir, \"workspace.json\");\n if (!existsSync(wsJsonPath)) continue;\n\n // Parse workspace.json to get the project folder path\n let workspacePath: string;\n try {\n const data = asRecord(JSON.parse(readFileSync(wsJsonPath, \"utf-8\")));\n const uri =\n narrowString(\"workspaceJson.folder\", data?.folder) ??\n narrowString(\"workspaceJson.workspace\", data?.workspace) ??\n \"\";\n if (!uri) continue;\n workspacePath = normalize(decodeURIComponent(uri.replace(/^file:\\/\\//, \"\")));\n } catch {\n continue;\n }\n\n // Read composer IDs from this workspace's state.vscdb (ItemTable)\n const wsDbPath = join(wsDir, \"state.vscdb\");\n if (!existsSync(wsDbPath)) continue;\n\n const wsDb = openDbReadOnly(wsDbPath);\n if (!wsDb) continue;\n\n try {\n const row = wsDb\n .prepare(\"SELECT value FROM ItemTable WHERE key = 'composer.composerData'\")\n .get() as { value: string } | undefined;\n if (!row?.value) continue;\n\n const parsed: unknown = JSON.parse(row.value);\n const composers = asArray(asRecord(parsed)?.allComposers) ?? asArray(parsed) ?? [];\n\n for (const item of composers) {\n const composer = asRecord(item);\n if (!composer) continue;\n const id =\n narrowString(\"workspaceComposer.composerId\", composer.composerId) ??\n narrowString(\"workspaceComposer.id\", composer.id);\n if (id) map.set(id, workspacePath);\n }\n } catch {\n // skip unreadable workspace db\n } finally {\n wsDb.close();\n }\n }\n\n return map;\n }\n\n isAvailable(): boolean {\n this.dbPath = this.findDbPath();\n return this.dbPath !== null && existsSync(this.dbPath);\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n this.composerCache.clear();\n this.directoryCache.clear();\n if (!this.dbPath) return [];\n\n const scanMarker = perf.start(\"cursor:scan\");\n\n const dbMarker = perf.start(\"openDatabase\");\n const db = this.openDatabase();\n perf.end(dbMarker);\n\n if (!db) throw new SessionScanError(this.name, \"opening the database\");\n\n // Build composerId → workspace path map from workspaceStorage\n const wsMarker = perf.start(\"buildWorkspacePathMap\");\n const workspacePathMap = this.buildWorkspacePathMap();\n perf.end(wsMarker);\n\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'\")\n .all() as Array<{ key: string; value: string }>;\n\n // Heads are emitted by composer order regardless of which phase produced\n // them, so the scan output does not depend on how bubbles are read.\n const emitted = new Map<number, SessionHead>();\n const pending: PendingComposer[] = [];\n let order = 0;\n options?.onProgress?.({ total: rows.length, processed: 0, sessions: 0 });\n let processed = 0;\n\n for (const row of rows) {\n try {\n const composer = parseComposerRow(row.value);\n if (!composer || (!composer.id && !composer.composerId)) continue;\n\n const composerId = composer.id || composer.composerId || \"\";\n const createdAt = composer.createdAt ?? 0;\n const updatedAt = composerUpdatedAt(composer);\n if (!matchesScanWindow(updatedAt, options)) continue;\n\n const fastTitle = this.extractTitle(composer);\n const hasFastMessages = Array.isArray(composer.chatMessages);\n const fastMessageCount = composer.chatMessages?.length ?? 0;\n const hasSubagents =\n Array.isArray(composer.subagentInfos) && composer.subagentInfos.length > 0;\n if (options?.fast) {\n const directory = workspacePathMap.get(composerId) ?? \"\";\n const head = this.captureSessionPricingMisses(() => {\n const totalCost =\n estimateTokenCost(composer.modelConfig?.modelName ?? composer.model, {\n input: composer.inputTokenCount ?? 0,\n output: composer.outputTokenCount ?? 0,\n }) ?? 0;\n return getParsedSession(\n hasFastMessages && fastMessageCount === 0 && !hasSubagents\n ? filteredSession<SessionHead>(\"no visible messages\")\n : parsedSession<SessionHead>({\n id: composerId,\n slug: this.sessionSlug(composerId),\n title: fastTitle,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: fastMessageCount,\n total_input_tokens: composer.inputTokenCount ?? 0,\n total_output_tokens: composer.outputTokenCount ?? 0,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n }),\n );\n });\n if (!head) continue;\n emitted.set(order, head);\n order += 1;\n this.composerCache.set(composerId, composer);\n if (directory) this.directoryCache.set(composerId, directory);\n continue;\n }\n\n pending.push({ composer, composerId, createdAt, updatedAt, hasSubagents, order });\n order += 1;\n } catch {\n // skip malformed entries\n } finally {\n processed += 1;\n options?.onProgress?.({ total: rows.length, processed, sessions: emitted.size });\n }\n }\n\n // Second phase: one ordered pass over every bubble row. Keys share the\n // composer prefix, so each group arrives contiguously and only one group\n // is held at a time — replacing two full scans per composer.\n const bubbleMarker = perf.start(\"cursor:bubbles\");\n const wanted = new Map(pending.map((entry) => [entry.composerId, entry]));\n this.forEachComposerBubbles(db, wanted, (bubbles) => {\n const entry = wanted.get(bubbles.composerId);\n if (!entry) return;\n wanted.delete(bubbles.composerId);\n const head = this.captureSessionPricingMisses(() =>\n this.buildScanHead(entry, bubbles, workspacePathMap),\n );\n if (head) emitted.set(entry.order, head);\n });\n // Composers with no bubbles at all still go through the same builder.\n for (const entry of wanted.values()) {\n const head = this.captureSessionPricingMisses(() =>\n this.buildScanHead(\n entry,\n { composerId: entry.composerId, byKey: [], byRowId: [] },\n workspacePathMap,\n ),\n );\n if (head) emitted.set(entry.order, head);\n }\n perf.end(bubbleMarker);\n\n const heads = [...emitted.entries()]\n .sort(([left], [right]) => left - right)\n .map(([, head]) => head);\n options?.onProgress?.({ total: rows.length, processed, sessions: heads.length });\n\n perf.end(scanMarker);\n return heads;\n } catch (error) {\n throw new SessionScanError(this.name, \"reading composers\", { cause: error });\n } finally {\n db.close();\n }\n }\n\n getSessionData(sessionId: string): SessionDetail {\n // Ensure dbPath is set\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath) {\n throw new Error(\"Cursor database is missing\");\n }\n\n const db = this.openDatabase();\n if (!db) {\n throw new Error(\"Cursor database is missing\");\n }\n\n try {\n // Try cached composer data first\n let composer = this.composerCache.get(sessionId);\n\n if (!composer) {\n // Try loading directly by sessionId (might be composerId)\n composer = this.loadComposer(db, sessionId) ?? undefined;\n }\n\n if (!composer) {\n // sessionId might be a requestId - try to find the composer\n const composerId = this.findComposerIdByRequestId(db, sessionId);\n if (composerId) {\n composer = this.loadComposer(db, composerId) ?? undefined;\n }\n }\n\n if (!composer) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const composerId = composer.id || composer.composerId || \"\";\n const createdAt = composer.createdAt ?? 0;\n const updatedAt = composerUpdatedAt(composer);\n\n // Load messages from bubbles (like agent-dump does)\n const messages = this.loadMessagesFromBubbles(\n db,\n composerId,\n composer.modelConfig?.modelName ?? composer.model ?? null,\n );\n\n // Append subagent messages\n this.appendSubagentMessages(db, composer, messages);\n const cleanedMessages = cleanParsedMessages(messages);\n const title = this.extractTitle(composer, cleanedMessages);\n\n // Aggregate stats\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCost = 0;\n\n for (const msg of cleanedMessages) {\n totalInputTokens += msg.tokens?.input ?? 0;\n totalOutputTokens += msg.tokens?.output ?? 0;\n totalCost += msg.cost ?? 0;\n }\n\n // Use session-level token counts if per-message counts are zero\n if (totalInputTokens === 0) totalInputTokens = composer.inputTokenCount ?? 0;\n if (totalOutputTokens === 0) totalOutputTokens = composer.outputTokenCount ?? 0;\n if (totalCost === 0) {\n totalCost =\n estimateTokenCost(composer.modelConfig?.modelName ?? composer.model, {\n input: totalInputTokens,\n output: totalOutputTokens,\n }) ?? 0;\n }\n\n const directory =\n this.directoryCache.get(composerId) ?? this.buildWorkspacePathMap().get(composerId) ?? \"\";\n\n return {\n reference: { agentName: this.name, sessionId: composerId },\n id: composerId,\n title,\n slug: this.sessionSlug(composerId),\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: cleanedMessages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n messages: cleanedMessages,\n };\n } finally {\n db.close();\n }\n }\n\n // --- Private helpers ---\n\n private openDatabase(): SQLiteDatabase | null {\n if (!this.dbPath) return null;\n return openDbReadOnly(this.dbPath);\n }\n\n /**\n * Streams every bubble row once, in key order, handing each composer's group\n * to the caller. A key-ordered scan keeps a composer's bubbles contiguous, so\n * only one group is materialized at a time.\n */\n private forEachComposerBubbles(\n db: SQLiteDatabase,\n wanted: Map<string, PendingComposer>,\n onGroup: (bubbles: ComposerBubbles) => void,\n ): void {\n if (wanted.size === 0) return;\n\n let currentId: string | null = null;\n let group: BubbleRow[] = [];\n const flush = () => {\n if (currentId != null && group.length > 0) onGroup(groupBubbleRows(group));\n group = [];\n };\n\n const rows = db\n .prepare(\n \"SELECT rowid AS row_id, key, value FROM cursorDiskKV WHERE key LIKE 'bubbleId:%' ORDER BY key\",\n )\n .iterate() as Iterable<BubbleRow>;\n for (const row of rows) {\n const composerId = composerIdFromBubbleKey(row.key);\n if (composerId !== currentId) {\n flush();\n currentId = composerId;\n }\n if (wanted.has(composerId)) group.push(row);\n }\n flush();\n }\n\n /** Builds the head for one composer from bubbles that were parsed once. */\n private buildScanHead(\n entry: PendingComposer,\n bubbles: ComposerBubbles,\n workspacePathMap: Map<string, string>,\n ): SessionHead | null {\n const { composer, composerId, createdAt, updatedAt, hasSubagents } = entry;\n const legacySessionId = this.legacySessionIdFromBubbles(bubbles);\n\n const parsedMessages = cleanParsedMessages(\n this.messagesFromBubbles(bubbles, composer.modelConfig?.modelName ?? composer.model ?? null),\n );\n const messages = getParsedSession(\n parsedMessages.length === 0 && !hasSubagents\n ? filteredSession<Message[]>(\"no visible messages\")\n : parsedSession(parsedMessages),\n );\n if (!messages) return null;\n if (legacySessionId) this.migrateLegacySessionMeta(legacySessionId, composerId);\n\n const title = this.extractTitle(composer, messages);\n const directory = workspacePathMap.get(composerId) ?? \"\";\n\n const modelUsageMap: Record<string, number> = {};\n let totalCost = 0;\n for (const msg of messages) {\n totalCost += msg.cost ?? 0;\n if (msg.model) {\n const msgTokens = (msg.tokens?.input ?? 0) + (msg.tokens?.output ?? 0);\n if (msgTokens > 0) {\n modelUsageMap[msg.model] = (modelUsageMap[msg.model] ?? 0) + msgTokens;\n }\n }\n }\n const hasModelUsage = Object.keys(modelUsageMap).length > 0;\n\n this.composerCache.set(composerId, composer);\n if (directory) this.directoryCache.set(composerId, directory);\n return {\n id: composerId,\n slug: this.sessionSlug(composerId),\n title,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: messages.length,\n total_input_tokens: composer.inputTokenCount ?? 0,\n total_output_tokens: composer.outputTokenCount ?? 0,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n model_usage: hasModelUsage ? modelUsageMap : undefined,\n };\n }\n\n private legacySessionIdFromBubbles(bubbles: ComposerBubbles): string | null {\n for (const entry of bubbles.byKey) {\n const requestId = entry.bubble.requestId?.trim();\n if (requestId) return requestId;\n }\n return null;\n }\n\n private migrateLegacySessionMeta(legacySessionId: string, sessionId: string): void {\n if (legacySessionId === sessionId) return;\n const legacyMeta = this.sessionMetaMap.get(legacySessionId);\n if (!legacyMeta) return;\n\n this.sessionMetaMap.delete(legacySessionId);\n if (!this.sessionMetaMap.has(sessionId)) {\n this.sessionMetaMap.set(sessionId, { ...legacyMeta, id: sessionId });\n }\n getCoreDiagnostics()?.info?.(\"cursor.session_id_migrated\", {\n legacy_session_id: legacySessionId,\n session_id: sessionId,\n });\n }\n\n /** Find composerId by requestId (reverse lookup) */\n private findComposerIdByRequestId(db: SQLiteDatabase, requestId: string): string | null {\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE 'bubbleId:%' AND value LIKE ?\")\n .all(`%\"requestId\":\"${requestId}\"%`) as Array<{ key: string; value: string }>;\n\n for (const row of rows) {\n try {\n const bubble = parseBubbleRow(row.value);\n if (bubble?.requestId === requestId) {\n // Extract composerId from key (bubbleId:{composerId}:{bubbleId})\n const keyParts = row.key.split(\":\");\n if (keyParts.length >= 2 && keyParts[1]) {\n return keyParts[1];\n }\n }\n } catch {\n // skip malformed bubbles\n }\n }\n } catch {\n // ignore errors\n }\n return null;\n }\n\n /** Extract title from composer (like agent-dump) */\n private extractTitle(composer: ComposerData, messages: Message[] = []): string {\n const explicit = composer.name || composer.title;\n const messageTitle = firstUserMessageTitle(messages) ?? composer.text;\n return resolveSessionTitle(explicit, messageTitle, null);\n }\n\n /**\n * Load one composer's bubbles, for the detail path that only needs a\n * single session. A failing bubble query throws instead of returning [] —\n * a broken database must not read as an empty session.\n */\n private loadMessagesFromBubbles(\n db: SQLiteDatabase,\n composerId: string,\n initialModelName: string | null,\n ): Message[] {\n const rows = this.scanStep(\n \"reading composer bubbles\",\n this.getDatabasePath() ?? \"\",\n () =>\n db\n .prepare(\"SELECT rowid AS row_id, key, value FROM cursorDiskKV WHERE key LIKE ?\")\n .all(`bubbleId:${composerId}:%`) as BubbleRow[],\n );\n return this.messagesFromBubbles(groupBubbleRows(rows), initialModelName);\n }\n\n /** Build messages from bubbles already parsed once, in insertion order. */\n private messagesFromBubbles(\n bubbles: ComposerBubbles,\n initialModelName: string | null,\n ): Message[] {\n const messages: Message[] = [];\n\n {\n let activeModelName: string | null = initialModelName;\n let messageIndex = 0;\n\n for (const entry of bubbles.byRowId) {\n {\n const bubble = entry.bubble;\n if (isInternalBubble(bubble)) continue;\n const bubbleId = entry.key.split(\":\").pop() || String(messageIndex);\n\n // Determine role: type 2 = assistant, otherwise user\n const role = bubble.type === 2 ? \"assistant\" : \"user\";\n\n // Extract timestamp\n let timestampMs = 0;\n if (bubble.timingInfo?.clientRpcSendTime) {\n timestampMs = Math.floor(bubble.timingInfo.clientRpcSendTime);\n } else if (bubble.createdAt) {\n timestampMs = bubble.createdAt;\n } else if (bubble.timestamp) {\n timestampMs = bubble.timestamp;\n }\n\n // Track model from user turn\n if (bubble.modelInfo?.modelName) {\n activeModelName = bubble.modelInfo.modelName;\n }\n\n // Extract tokens\n const inputTokens = bubble.tokenCount?.inputTokens ?? 0;\n const outputTokens = bubble.tokenCount?.outputTokens ?? 0;\n\n // Build message parts\n const parts: MessagePart[] = [];\n\n // Text content\n const text = cleanInternalText(bubble.text ?? \"\");\n if (text) {\n parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n\n // Tool calls from toolFormerData\n if (bubble.toolFormerData) {\n const toolPart = this.convertToolFormerData(bubble.toolFormerData, timestampMs);\n if (toolPart) {\n parts.push(toolPart);\n }\n }\n\n // Skip empty messages\n if (parts.length === 0) continue;\n\n const modelName = bubble.modelInfo?.modelName ?? activeModelName;\n const tokens = { input: inputTokens, output: outputTokens };\n const cost = estimateTokenCost(modelName, tokens);\n\n messages.push({\n id: `cursor-${bubbles.composerId}-${bubbleId}`,\n role: role as Message[\"role\"],\n agent: \"cursor\",\n time_created: timestampMs,\n time_completed: null,\n mode: role === \"assistant\" && parts.some((p) => p.type === \"tool\") ? \"tool\" : null,\n model: modelName,\n provider: null,\n tokens,\n cost: cost ?? 0,\n cost_source: cost !== null ? \"estimated\" : undefined,\n parts,\n });\n\n messageIndex++;\n }\n }\n }\n\n return messages;\n }\n\n /** Convert toolFormerData to MessagePart */\n private convertToolFormerData(\n toolData: BubbleData[\"toolFormerData\"],\n timestampMs: number,\n ): MessagePart | null {\n if (!toolData || !toolData.name) return null;\n\n const toolName = toolData.name;\n const normalizedName = toolName === \"create_plan\" ? \"plan\" : mapToolTitle(toolName);\n\n // Build state\n const state: ToolPartState = {\n status: cursorToolStatus(toolData.status),\n };\n\n // Parse input params\n if (toolData.params) {\n if (typeof toolData.params === \"string\") {\n try {\n state.input = JSON.parse(toolData.params);\n } catch {\n state.input = { _raw: toolData.params };\n }\n } else {\n state.input = toolData.params;\n }\n }\n\n // Parse result/output\n if (toolData.result !== undefined) {\n let result = toolData.result;\n if (typeof toolData.result === \"string\") {\n try {\n result = JSON.parse(toolData.result);\n } catch {}\n }\n state.output = result;\n if (state.status === \"error\") {\n const resultRecord = asRecord(result);\n state.error =\n resultRecord?.error ?? resultRecord?.message ?? resultRecord?.stderr ?? result;\n }\n }\n\n // Handle plan tool specially\n if (toolName === \"create_plan\") {\n const planText = String(asRecord(state.input)?.plan ?? \"\").trim();\n if (planText) {\n return {\n type: \"plan\",\n text: planText,\n approval_status: state.status === \"completed\" ? \"success\" : \"fail\",\n time_created: timestampMs,\n };\n }\n }\n\n return {\n type: \"tool\",\n tool: normalizedName,\n callID: toolData.toolCallId || \"\",\n title: `Tool: ${normalizedName}`,\n state,\n time_created: timestampMs,\n };\n }\n\n private loadComposer(db: SQLiteDatabase, sessionId: string): ComposerData | null {\n const row = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key = ?\")\n .get(`composerData:${sessionId}`) as { value: string } | undefined;\n\n if (!row) return null;\n\n return parseComposerRow(row.value);\n }\n\n private loadBubble(db: SQLiteDatabase, sessionId: string): BubbleData | null {\n const row = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key = ?\")\n .get(`bubble:${sessionId}`) as { value: string } | undefined;\n\n if (!row) return null;\n\n return parseBubbleRow(row.value);\n }\n\n private appendSubagentMessages(\n db: SQLiteDatabase,\n composer: ComposerData,\n messages: Message[],\n ): void {\n const subagentInfos = composer.subagentInfos;\n if (!Array.isArray(subagentInfos) || subagentInfos.length === 0) return;\n\n for (const subInfo of subagentInfos) {\n if (!subInfo.id) continue;\n\n const bubble = this.loadBubble(db, subInfo.id);\n if (!bubble || !Array.isArray(bubble.chatMessages)) continue;\n\n for (const chatMsg of bubble.chatMessages) {\n const role = chatMsg.role?.trim().toLowerCase();\n if (role !== \"user\" && role !== \"assistant\") continue;\n\n const timestampMs = extractTimestamp(chatMsg);\n const parts: MessagePart[] = [];\n\n const text = cleanInternalText(chatMsg.text ?? \"\");\n if (text) {\n parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n\n if (role === \"assistant\" && Array.isArray(chatMsg.actions)) {\n for (const action of chatMsg.actions) {\n if (isInternalEventType(action.type) || isInternalEventType(action.tool)) continue;\n const part = convertActionToPart(action, timestampMs);\n if (part) parts.push(part);\n }\n }\n\n if (parts.length === 0) continue;\n\n messages.push({\n id: `cursor-sub-${subInfo.id}`,\n role: role as Message[\"role\"],\n agent: \"cursor\",\n time_created: timestampMs,\n time_completed: null,\n mode: null,\n model: null,\n provider: null,\n tokens: undefined,\n cost: 0,\n subagent_id: subInfo.id,\n nickname: subInfo.nickname ?? subInfo.title,\n parts,\n });\n }\n }\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport {\n SingleFileSessionSource,\n filteredSession,\n getParsedSession,\n parsedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n FileSessionMeta,\n ParseSessionResult,\n SessionSourceFile,\n SessionSourceRef,\n} from \"./base.js\";\nimport type { Message, MessagePart, SessionDetail, SessionHead } from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile } from \"../utils/jsonl.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { asNumber, asRecord, asString, narrowField } from \"../utils/narrow.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { parseAgentTimestamp } from \"../utils/timestamp.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\n\nconst HEAD_INDEX_VERSION = \"pi-head-v2\";\nconst PARSER_VERSION = \"pi-parser-v3\";\n\nexport function resolvePiDataRoot(): string {\n return resolveHomePath(\"PI_HOME\", \".pi\");\n}\n\ninterface SessionMeta extends FileSessionMeta {\n headIndexVersion: string;\n parserVersion: string;\n}\n\ninterface ParsedPiFile {\n sessionId: string;\n directory: string;\n createdAt: number;\n updatedAt: number;\n title: string;\n pathEntries: Record<string, unknown>[];\n}\n\nfunction narrowPiField<T>(\n field: string,\n value: unknown,\n narrow: (v: unknown) => T | undefined,\n): T | undefined {\n return narrowField(\"pi\", field, value, narrow);\n}\n\n/**\n * Reports drift only when the timestamp is present but neither a number nor\n * a string (e.g. an object); parsing goes through the shared agent parser\n * (numeric strings accepted, unparseable text reported and treated as 0).\n */\nfunction narrowTimestampMs(field: string, value: unknown): number {\n const shaped = narrowPiField(field, value, (v) =>\n typeof v === \"number\" || typeof v === \"string\" ? v : undefined,\n );\n return shaped === undefined\n ? 0\n : (parseAgentTimestamp(shaped, \"pi\", { numericStrings: true }) ?? 0);\n}\n\nfunction extractSessionIdFromFilename(filePath: string): string {\n const stem = basename(filePath, \".jsonl\");\n const underscore = stem.indexOf(\"_\");\n return underscore >= 0 ? stem.slice(underscore + 1) || stem : stem;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((item) => {\n if (!isObject(item)) return \"\";\n if (item[\"type\"] === \"text\") return String(item[\"text\"] ?? \"\");\n if (item[\"type\"] === \"image\") return \"[image]\";\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction normalizeTextParts(content: unknown, timestampMs: number): MessagePart[] {\n const text = cleanInternalText(contentToText(content));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction getEntryTimestamp(entry: Record<string, unknown>): number {\n return narrowTimestampMs(\"entry.timestamp\", entry[\"timestamp\"]);\n}\n\nfunction chooseLeafEntry(entries: Record<string, unknown>[]): Record<string, unknown> | null {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n if (typeof entries[index]?.[\"id\"] === \"string\") return entries[index]!;\n }\n return null;\n}\n\nfunction buildCurrentPathEntries(entries: Record<string, unknown>[]): Record<string, unknown>[] {\n const byId = new Map<string, Record<string, unknown>>();\n for (const entry of entries) {\n const id = entry[\"id\"];\n if (typeof id === \"string\" && id) byId.set(id, entry);\n }\n\n const leaf = chooseLeafEntry(entries);\n if (!leaf) return [];\n\n const path: Record<string, unknown>[] = [];\n const seen = new Set<string>();\n let current: Record<string, unknown> | undefined = leaf;\n while (current) {\n const id = String(current[\"id\"] ?? \"\");\n if (!id || seen.has(id)) break;\n seen.add(id);\n path.push(current);\n const parentId: unknown = current[\"parentId\"];\n current = typeof parentId === \"string\" ? byId.get(parentId) : undefined;\n }\n\n return path.reverse();\n}\n\nexport class PiAgent extends SingleFileSessionSource<SessionMeta> {\n readonly name = \"pi\";\n readonly displayName = \"Pi\";\n\n private basePath: string | null = null;\n\n private findBasePath(): string | null {\n return firstExisting(join(resolvePiDataRoot(), \"agent\", \"sessions\"), \"data/pi\");\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolvePiDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { root: dataRoot, path: join(dataRoot, \"agent\", \"sessions\") },\n { root: \"data/pi\", path: \"data/pi\" },\n ],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n return this.listSessionFiles().length > 0;\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n return this.listSessionFiles(options).map(({ file, stat }) => ({\n sessionId: extractSessionIdFromFilename(file),\n sourcePath: file,\n fingerprint: this.sourceFingerprint(stat),\n }));\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n if (!existsSync(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);\n\n const parsed = this.parsePiFile(meta.sourcePath);\n const state = this.convertEntries(parsed.pathEntries);\n\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: this.sessionSlug(meta.id),\n directory: meta.directory,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: {\n message_count: state.messages.length,\n total_input_tokens: state.totalInputTokens,\n total_output_tokens: state.totalOutputTokens,\n total_cache_read_tokens: state.totalCacheReadTokens || undefined,\n total_cache_create_tokens: state.totalCacheCreateTokens || undefined,\n total_cost: state.totalCost,\n cost_source: state.costSource,\n },\n messages: state.messages,\n };\n }\n\n private listSessionFiles(options?: AgentScanOptions): SessionSourceFile[] {\n if (!this.basePath) return [];\n return this.walkFiles(\n this.basePath,\n (entry) => entry.isFile() && entry.name.endsWith(\".jsonl\"),\n { scanWindow: options },\n );\n }\n\n protected createFileSessionMeta(head: SessionHead, source: SessionSourceFile): SessionMeta {\n return this.buildFileSessionMeta({\n head,\n source,\n fingerprint: this.sourceFingerprint(source.stat),\n extras: {\n headIndexVersion: HEAD_INDEX_VERSION,\n parserVersion: PARSER_VERSION,\n },\n });\n }\n\n /** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */\n private sourceFingerprint(stat: { mtimeMs: number; size: number }): string {\n return JSON.stringify([HEAD_INDEX_VERSION, PARSER_VERSION, stat.mtimeMs, stat.size]);\n }\n\n protected parseFileSessionHead(filePath: string): SessionHead | null {\n return getParsedSession(this.parseFileSessionHeadResult(filePath));\n }\n\n protected override parseFileSessionHeadResult(filePath: string): ParseSessionResult<SessionHead> {\n const parsed = this.parsePiFile(filePath);\n const state = this.convertEntries(parsed.pathEntries);\n const messageCount = state.messages.length;\n if (messageCount === 0) return filteredSession(\"no visible messages\");\n\n const modelUsage = Object.keys(state.modelUsage).length > 0 ? state.modelUsage : undefined;\n return parsedSession({\n id: parsed.sessionId,\n slug: this.sessionSlug(parsed.sessionId),\n title: parsed.title,\n directory: parsed.directory,\n time_created: parsed.createdAt,\n time_updated: parsed.updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: state.totalInputTokens,\n total_output_tokens: state.totalOutputTokens,\n total_cache_read_tokens: state.totalCacheReadTokens || undefined,\n total_cache_create_tokens: state.totalCacheCreateTokens || undefined,\n total_cost: state.totalCost,\n cost_source: state.costSource,\n },\n model_usage: modelUsage,\n });\n }\n\n private parsePiFile(filePath: string): ParsedPiFile {\n // Single streaming pass: the file is never held as a string, and header\n // selection happens inline instead of scanning a materialized record array.\n let header: Record<string, unknown> | null = null;\n let recordCount = 0;\n const entries: Record<string, unknown>[] = [];\n\n for (const record of readJsonlFile(filePath)) {\n recordCount += 1;\n if (record[\"type\"] === \"session\") {\n header ??= record;\n continue;\n }\n entries.push(record);\n }\n\n if (recordCount === 0) throw new Error(\"empty file\");\n if (!header) throw new Error(\"missing session header\");\n\n const pathEntries = buildCurrentPathEntries(entries);\n if (pathEntries.length === 0) throw new Error(\"empty session tree\");\n\n const sessionId = extractSessionIdFromFilename(filePath);\n if (!sessionId) throw new Error(\"missing session id\");\n\n const stat = this.sessionSourceFile(filePath).stat;\n const directory = String(header[\"cwd\"] ?? \"\").trim() || basename(filePath, \".jsonl\");\n const createdAt = narrowTimestampMs(\"session.timestamp\", header[\"timestamp\"]) || stat.mtimeMs;\n const updatedAt = pathEntries.reduce(\n (max, entry) => Math.max(max, getEntryTimestamp(entry)),\n createdAt,\n );\n const explicitTitle = this.extractSessionName(pathEntries);\n const messageTitle = this.extractTitle(pathEntries);\n const directoryTitle = basenameTitle(directory);\n\n return {\n sessionId,\n directory,\n createdAt,\n updatedAt,\n title: resolveSessionTitle(explicitTitle, messageTitle, directoryTitle),\n pathEntries,\n };\n }\n\n private extractSessionName(entries: Record<string, unknown>[]): string | null {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index]!;\n if (entry[\"type\"] !== \"session_info\") continue;\n const name = normalizeTitleText(String(entry[\"name\"] ?? \"\"));\n if (name) return name;\n }\n return null;\n }\n\n private extractTitle(entries: Record<string, unknown>[]): string | null {\n for (const entry of entries) {\n if (entry[\"type\"] !== \"message\") continue;\n const message = entry[\"message\"];\n if (!isObject(message) || message[\"role\"] !== \"user\") continue;\n const title = normalizeTitleText(contentToText(message[\"content\"]));\n if (title) return title;\n }\n return null;\n }\n\n private convertEntries(entries: Record<string, unknown>[]): {\n messages: Message[];\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCacheReadTokens: number;\n totalCacheCreateTokens: number;\n totalCost: number;\n costSource: Message[\"cost_source\"];\n modelUsage: Record<string, number>;\n } {\n const builder = new TranscriptBuilder({ messageDefaults: \"sparse\" });\n const modelUsage: Record<string, number> = {};\n\n for (const entry of entries) {\n const timestampMs = getEntryTimestamp(entry);\n const type = String(entry[\"type\"] ?? \"\");\n\n if (type === \"message\") {\n const message = narrowPiField(\"entry.message\", entry[\"message\"], asRecord);\n if (!message) continue;\n const result = this.convertAgentMessage(entry, message, timestampMs, builder);\n if (!result) continue;\n if (result.message) builder.appendMessage(result.message);\n if (result.model && result.totalTokens > 0) {\n modelUsage[result.model] = (modelUsage[result.model] ?? 0) + result.totalTokens;\n }\n continue;\n }\n\n const summary = this.convertSummaryEntry(entry, timestampMs);\n if (summary) builder.appendMessage(summary);\n }\n\n const result = builder.finish();\n\n return {\n messages: result.messages,\n totalInputTokens: result.stats.total_input_tokens,\n totalOutputTokens: result.stats.total_output_tokens,\n totalCacheReadTokens: result.stats.total_cache_read_tokens ?? 0,\n totalCacheCreateTokens: result.stats.total_cache_create_tokens ?? 0,\n totalCost: result.stats.total_cost,\n costSource: result.stats.cost_source,\n modelUsage,\n };\n }\n\n private convertAgentMessage(\n entry: Record<string, unknown>,\n message: Record<string, unknown>,\n timestampMs: number,\n builder: TranscriptBuilder,\n ): {\n message?: TranscriptMessageInput;\n totalTokens: number;\n model: string | null;\n } | null {\n const id = narrowPiField(\"message.id\", entry[\"id\"], asString) ?? \"\";\n const role = narrowPiField(\"message.role\", message[\"role\"], asString) ?? \"\";\n\n if (role === \"user\") {\n const parts = normalizeTextParts(message[\"content\"], timestampMs);\n if (parts.length === 0) return null;\n return this.emptyUsageResult({ id, role: \"user\", timestampMs, parts });\n }\n\n if (role === \"assistant\") {\n const parts = this.normalizeAssistantParts(message[\"content\"], timestampMs);\n if (parts.length === 0) return null;\n const usage = this.normalizeUsage(message[\"usage\"]);\n const model = typeof message[\"model\"] === \"string\" ? message[\"model\"].trim() : null;\n const estimatedCost = usage.cost === null ? estimateTokenCost(model, usage.tokens) : null;\n const cost = usage.cost ?? estimatedCost ?? 0;\n const costSource = cost > 0 ? (usage.cost === null ? \"estimated\" : \"recorded\") : undefined;\n return {\n message: {\n id,\n role: \"assistant\",\n agent: \"pi\",\n timestampMs,\n parts,\n provider: typeof message[\"provider\"] === \"string\" ? message[\"provider\"] : null,\n model,\n tokens: usage.tokens,\n cost: cost || undefined,\n costSource,\n },\n totalTokens: usage.totalTokens,\n model,\n };\n }\n\n if (role === \"toolResult\") {\n this.attachToolResult(message, timestampMs, builder);\n return this.emptyUsageResult();\n }\n\n if (role === \"bashExecution\") {\n return this.emptyUsageResult(this.convertBashExecution(id, message, timestampMs));\n }\n\n if (role === \"custom\" && message[\"display\"] === true) {\n const parts = normalizeTextParts(message[\"content\"], timestampMs);\n if (parts.length === 0) return null;\n return this.emptyUsageResult({ id, role: \"user\", timestampMs, parts });\n }\n\n if (role === \"branchSummary\" || role === \"compactionSummary\") {\n const summary = String(message[\"summary\"] ?? \"\").trim();\n if (!summary) return null;\n return this.emptyUsageResult({\n id,\n role: \"assistant\",\n agent: \"pi\",\n timestampMs,\n parts: [{ type: \"text\", text: summary, time_created: timestampMs }],\n });\n }\n\n return null;\n }\n\n private normalizeAssistantParts(content: unknown, timestampMs: number): MessagePart[] {\n if (!Array.isArray(content)) return [];\n\n const parts: MessagePart[] = [];\n for (const item of content) {\n if (!isObject(item)) continue;\n const type = item[\"type\"];\n\n if (type === \"text\") {\n const text = cleanInternalText(String(item[\"text\"] ?? \"\"));\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n continue;\n }\n\n if (type === \"thinking\") {\n const text = cleanInternalText(String(item[\"thinking\"] ?? \"\"));\n if (text) parts.push({ type: \"reasoning\", text, time_created: timestampMs });\n continue;\n }\n\n if (type === \"toolCall\") {\n const callId = String(item[\"id\"] ?? \"\").trim();\n const toolName = String(item[\"name\"] ?? \"\").trim() || \"tool\";\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolName,\n title: `Tool: ${toolName}`,\n callID: callId || undefined,\n time_created: timestampMs,\n state: {\n status: \"running\",\n input: item[\"arguments\"] ?? {},\n },\n };\n parts.push(toolPart);\n }\n }\n\n return parts;\n }\n\n private attachToolResult(\n message: Record<string, unknown>,\n timestampMs: number,\n builder: TranscriptBuilder,\n ): void {\n const callId = String(message[\"toolCallId\"] ?? \"\").trim();\n const output = normalizeTextParts(message[\"content\"], timestampMs);\n if (!callId) return;\n builder.resolveToolCall(callId, {\n output,\n status: message[\"isError\"] === true ? \"error\" : \"completed\",\n metadata: message[\"details\"],\n consume: true,\n });\n }\n\n private convertBashExecution(\n id: string,\n message: Record<string, unknown>,\n timestampMs: number,\n ): TranscriptMessageInput {\n const command = String(message[\"command\"] ?? \"\");\n const output = String(message[\"output\"] ?? \"\");\n const isError = Number(message[\"exitCode\"] ?? 0) !== 0 || message[\"cancelled\"] === true;\n return {\n id,\n role: \"tool\",\n timestampMs,\n parts: [\n {\n type: \"tool\",\n tool: \"bash\",\n title: \"Tool: bash\",\n time_created: timestampMs,\n state: {\n status: isError ? \"error\" : \"completed\",\n input: { command },\n output: output ? [{ type: \"text\", text: output, time_created: timestampMs }] : [],\n metadata: {\n exitCode: message[\"exitCode\"],\n cancelled: message[\"cancelled\"],\n truncated: message[\"truncated\"],\n fullOutputPath: message[\"fullOutputPath\"],\n },\n },\n },\n ],\n };\n }\n\n private convertSummaryEntry(\n entry: Record<string, unknown>,\n timestampMs: number,\n ): TranscriptMessageInput | null {\n const type = entry[\"type\"];\n if (type !== \"compaction\" && type !== \"branch_summary\" && type !== \"custom_message\") {\n return null;\n }\n\n if (type === \"custom_message\" && entry[\"display\"] !== true) return null;\n\n const rawText =\n type === \"custom_message\" ? contentToText(entry[\"content\"]) : String(entry[\"summary\"] ?? \"\");\n const text = cleanInternalText(rawText);\n if (!text) return null;\n\n return {\n id: narrowPiField(\"summary.id\", entry[\"id\"], asString) ?? \"\",\n role: type === \"custom_message\" ? \"user\" : \"assistant\",\n agent: type === \"custom_message\" ? undefined : \"pi\",\n timestampMs,\n parts: [{ type: \"text\", text, time_created: timestampMs }],\n };\n }\n\n private normalizeUsage(raw: unknown): {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreateTokens: number;\n totalTokens: number;\n cost: number | null;\n tokens: Message[\"tokens\"];\n } {\n const usage = narrowPiField(\"message.usage\", raw, asRecord) ?? {};\n const inputTokens = narrowPiField(\"message.usage.input\", usage[\"input\"], asNumber) ?? 0;\n const outputTokens = narrowPiField(\"message.usage.output\", usage[\"output\"], asNumber) ?? 0;\n const cacheReadTokens =\n narrowPiField(\"message.usage.cacheRead\", usage[\"cacheRead\"], asNumber) ?? 0;\n const cacheCreateTokens =\n narrowPiField(\"message.usage.cacheWrite\", usage[\"cacheWrite\"], asNumber) ?? 0;\n const totalTokens =\n narrowPiField(\"message.usage.totalTokens\", usage[\"totalTokens\"], asNumber) ??\n inputTokens + outputTokens + cacheReadTokens + cacheCreateTokens;\n const cost = isObject(usage[\"cost\"]) ? Number(usage[\"cost\"][\"total\"] ?? 0) : null;\n\n return {\n inputTokens: inputTokens + cacheReadTokens + cacheCreateTokens,\n outputTokens,\n cacheReadTokens,\n cacheCreateTokens,\n totalTokens,\n cost: cost && Number.isFinite(cost) ? cost : null,\n tokens: {\n input: inputTokens + cacheReadTokens + cacheCreateTokens,\n output: outputTokens,\n cache_read: cacheReadTokens || undefined,\n cache_create: cacheCreateTokens || undefined,\n },\n };\n }\n\n private emptyUsageResult(message?: TranscriptMessageInput): {\n message?: TranscriptMessageInput;\n totalTokens: number;\n model: string | null;\n } {\n return {\n message,\n totalTokens: 0,\n model: null,\n };\n }\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport { firstExisting } from \"../discovery/paths.js\";\nimport { isSqliteAvailable } from \"../utils/sqlite.js\";\nimport { OpenCodeSqliteAgent } from \"./opencode-sqlite.js\";\n\nexport function resolveZCodeDataRoot(): string | null {\n const currentPlatform = platform();\n if (currentPlatform !== \"darwin\" && currentPlatform !== \"win32\") return null;\n return join(homedir(), \".zcode\");\n}\n\nfunction findZCodeDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n const dataRoot = resolveZCodeDataRoot();\n if (!dataRoot) return null;\n return firstExisting(join(dataRoot, \"cli\", \"db\", \"db.sqlite\"));\n}\n\nfunction getZCodeSessionWatchPlan() {\n const dataRoot = resolveZCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: dataRoot ? [{ root: dataRoot, path: join(dataRoot, \"cli\", \"db\", \"db.sqlite\") }] : [],\n };\n}\n\nexport class ZCodeAgent extends OpenCodeSqliteAgent {\n constructor() {\n super({\n name: \"zcode\",\n displayName: \"ZCode\",\n findDbPath: findZCodeDbPath,\n getSessionWatchPlan: getZCodeSessionWatchPlan,\n });\n }\n}\n","import { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport {\n FileSystemSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n skippedSession,\n type AgentScanOptions,\n type FileSessionMeta,\n type ParseSessionResult,\n type SessionSourceFile,\n type SessionSourceRef,\n} from \"./base.js\";\nimport type {\n Message,\n MessagePart,\n MessageTokens,\n PlanPart,\n SessionDetail,\n SessionHead,\n SessionStats,\n ToolPart,\n ToolPartStatus,\n} from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile, readJsonlFileLines } from \"../utils/jsonl.js\";\nimport { asArray, asNumber, asRecord, asString } from \"../utils/narrow.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { basenameTitle, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { TranscriptBuilder, type TranscriptResult } from \"./transcript-builder.js\";\n\nconst HEAD_INDEX_VERSION = \"grok-head-v2\";\nconst PARSER_VERSION = \"grok-parser-v1\";\nconst SUMMARY_FILE = \"summary.json\";\nconst UPDATES_FILE = \"updates.jsonl\";\nconst ACP_UPDATE_METHOD = \"session/update\";\nconst XAI_UPDATE_METHOD = \"_x.ai/session/update\";\nconst USD_TICKS_PER_USD = 10_000_000_000;\n\nconst GROK_TOOL_TITLE_MAP: Record<string, string> = {\n get_command_or_subagent_output: \"task\",\n grep: \"grep\",\n list_dir: \"list\",\n read_file: \"read\",\n run_terminal_command: \"bash\",\n search_replace: \"edit\",\n todo_write: \"todo\",\n web_fetch: \"web fetch\",\n};\n\ninterface GrokSummary {\n id: string;\n cwd: string;\n title: string | null;\n createdAt: number;\n updatedAt: number;\n currentModel: string | null;\n parentSessionId: string | null;\n}\n\ninterface GrokSessionMeta extends FileSessionMeta {\n currentModel: string | null;\n parentSessionId: string | null;\n updatesPath: string | null;\n stats: SessionStats;\n}\n\ninterface GrokUpdate {\n method: string;\n params: Record<string, unknown>;\n update: Record<string, unknown>;\n timestampMs: number;\n}\n\ninterface GrokUsage {\n tokens: MessageTokens;\n totalTokens: number;\n cost: number | null;\n modelUsage: Record<string, number>;\n primaryModel: string | null;\n}\n\ninterface GrokHeadData {\n firstUserText: string | null;\n visibleMessageCount: number;\n stats: Omit<SessionStats, \"message_count\">;\n modelUsage: Record<string, number>;\n}\n\nexport function resolveGrokDataRoot(): string {\n return resolveHomePath(\"GROK_HOME\", \".grok\");\n}\n\nfunction safeCount(value: unknown): number {\n const number = asNumber(value);\n return number !== undefined && Number.isSafeInteger(number) && number >= 0 ? number : 0;\n}\n\nfunction addCount(total: number, value: number): number {\n return Math.min(Number.MAX_SAFE_INTEGER, total + value);\n}\n\nfunction timestampFromIso(value: unknown): number | null {\n const text = asString(value);\n if (!text) return null;\n const timestamp = Date.parse(text);\n return Number.isFinite(timestamp) ? timestamp : null;\n}\n\nfunction readJsonRecord(filePath: string): Record<string, unknown> | null {\n try {\n return asRecord(JSON.parse(readFileSync(filePath, \"utf8\"))) ?? null;\n } catch {\n return null;\n }\n}\n\nfunction parseSummary(source: SessionSourceFile): GrokSummary | null {\n const summary = readJsonRecord(source.file);\n const info = asRecord(summary?.info);\n const id = asString(info?.id)?.trim();\n const cwd = asString(info?.cwd)?.trim();\n if (!id || !cwd) return null;\n\n const createdAt = timestampFromIso(summary?.created_at) ?? source.stat.mtimeMs;\n const updatedAt =\n timestampFromIso(summary?.last_active_at) ?? timestampFromIso(summary?.updated_at) ?? createdAt;\n const generatedTitle = asString(summary?.generated_title)?.trim();\n const sessionSummary = asString(summary?.session_summary)?.trim();\n const parentSessionId = asString(summary?.parent_session_id)?.trim() || null;\n\n return {\n id,\n cwd,\n title: generatedTitle || sessionSummary || null,\n createdAt,\n updatedAt,\n currentModel: asString(summary?.current_model_id)?.trim() || null,\n parentSessionId: parentSessionId === id ? null : parentSessionId,\n };\n}\n\nfunction optionalFileFingerprint(filePath: string): [number, number] | null {\n try {\n const stat = statSync(filePath);\n return [stat.mtimeMs, stat.size];\n } catch {\n return null;\n }\n}\n\nfunction unpackUpdate(\n record: Record<string, unknown>,\n fallbackTimestampMs: number,\n): GrokUpdate | null {\n const method = asString(record.method) ?? ACP_UPDATE_METHOD;\n const params = asRecord(record.params) ?? record;\n const update = asRecord(params.update);\n if (!update) return null;\n\n const paramsMeta = asRecord(params._meta);\n const agentTimestampMs = asNumber(paramsMeta?.agentTimestampMs);\n const envelopeTimestamp = asNumber(record.timestamp);\n const timestampMs =\n agentTimestampMs !== undefined &&\n Number.isSafeInteger(agentTimestampMs) &&\n agentTimestampMs >= 0\n ? agentTimestampMs\n : envelopeTimestamp !== undefined &&\n Number.isSafeInteger(envelopeTimestamp) &&\n envelopeTimestamp >= 0 &&\n envelopeTimestamp <= Number.MAX_SAFE_INTEGER / 1000\n ? envelopeTimestamp * 1000\n : fallbackTimestampMs;\n\n return { method, params, update, timestampMs };\n}\n\nfunction isHostTurn(update: Record<string, unknown>): boolean {\n return asRecord(update._meta)?.hostTurn === true;\n}\n\nfunction updateType(update: GrokUpdate): string {\n return asString(update.update.sessionUpdate) ?? \"\";\n}\n\nfunction parseUsage(update: Record<string, unknown>): GrokUsage | null {\n const usage = asRecord(update.usage);\n if (!usage) return null;\n\n const input = safeCount(usage.inputTokens);\n const output = safeCount(usage.outputTokens);\n const reasoning = safeCount(usage.reasoningTokens);\n const cacheRead = safeCount(usage.cachedReadTokens);\n const cacheCreate = safeCount(usage.cacheCreationTokens);\n const totalTokens = safeCount(usage.totalTokens) || addCount(input, output);\n const isIncomplete = usage.usageIsIncomplete === true || usage.costIsPartial === true;\n const costTicks = safeCount(usage.costUsdTicks);\n const cost = !isIncomplete && costTicks > 0 ? costTicks / USD_TICKS_PER_USD : null;\n\n const modelUsage: Record<string, number> = {};\n const modelUsageRecord = asRecord(usage.modelUsage);\n if (modelUsageRecord) {\n for (const [model, rawUsage] of Object.entries(modelUsageRecord)) {\n const modelRecord = asRecord(rawUsage);\n if (!modelRecord) continue;\n const modelTotal =\n safeCount(modelRecord.totalTokens) ||\n addCount(safeCount(modelRecord.inputTokens), safeCount(modelRecord.outputTokens));\n if (modelTotal > 0) modelUsage[model] = modelTotal;\n }\n }\n\n const models = Object.keys(modelUsage);\n return {\n tokens: {\n input,\n output,\n reasoning: reasoning || undefined,\n cache_read: cacheRead || undefined,\n cache_create: cacheCreate || undefined,\n },\n totalTokens,\n cost,\n modelUsage,\n primaryModel: models.length === 1 ? models[0]! : null,\n };\n}\n\nfunction textFromContentBlock(value: unknown): string {\n const content = asRecord(value);\n if (!content) return \"\";\n if (content.type === \"text\") return asString(content.text) ?? \"\";\n const resource = asRecord(content.resource);\n return asString(resource?.text) ?? \"\";\n}\n\nfunction messagePartFromContentBlock(value: unknown, timestampMs: number): MessagePart | null {\n const content = asRecord(value);\n if (!content) return null;\n\n if (content.type === \"text\") {\n const text = asString(content.text) ?? \"\";\n return text ? { type: \"text\", text, time_created: timestampMs } : null;\n }\n\n if (content.type === \"image\") {\n const data = asString(content.data);\n const url = asString(content.uri) ?? asString(content.url);\n const mimeType = asString(content.mimeType) ?? asString(content.mime_type);\n if (data && mimeType) {\n return { type: \"image\", data, mime_type: mimeType, url, time_created: timestampMs };\n }\n if (url) return { type: \"image\", url, mime_type: mimeType, time_created: timestampMs };\n }\n\n const text = textFromContentBlock(content);\n return text ? { type: \"text\", text, time_created: timestampMs } : null;\n}\n\nclass GrokMessageCounter {\n firstUserText: string | null = null;\n messageCount = 0;\n private activeAssistant = false;\n private activeAssistantPromptId: string | null = null;\n private activeUser = false;\n private activeUserPromptIndex: number | null = null;\n\n process(envelope: GrokUpdate): void {\n if (envelope.method === XAI_UPDATE_METHOD) return;\n\n switch (updateType(envelope)) {\n case \"user_message_chunk\":\n this.appendUser(envelope);\n break;\n case \"agent_thought_chunk\":\n case \"agent_message_chunk\":\n if (cleanInternalText(textFromContentBlock(envelope.update.content))) {\n this.appendAssistant(envelope);\n }\n break;\n case \"tool_call\":\n if (asString(envelope.update.toolCallId)?.trim()) this.appendAssistant(envelope);\n break;\n case \"plan\":\n if (planPart(envelope.update, envelope.timestampMs)) this.appendAssistant(envelope);\n break;\n }\n }\n\n private appendUser(envelope: GrokUpdate): void {\n if (isHostTurn(envelope.update)) return;\n const part = messagePartFromContentBlock(envelope.update.content, envelope.timestampMs);\n if (!part) return;\n if (part.type === \"text\" && !cleanInternalText(part.text)) return;\n\n const promptIndexValue = asNumber(asRecord(envelope.update._meta)?.promptIndex);\n const promptIndex =\n promptIndexValue !== undefined && Number.isSafeInteger(promptIndexValue)\n ? promptIndexValue\n : null;\n const canReuse =\n this.activeUser &&\n (promptIndex === null ||\n this.activeUserPromptIndex === null ||\n promptIndex === this.activeUserPromptIndex);\n if (!canReuse) this.messageCount += 1;\n\n if (this.firstUserText === null && part.type === \"text\") {\n this.firstUserText = cleanInternalText(part.text) || null;\n }\n this.activeUser = true;\n this.activeUserPromptIndex = promptIndex;\n this.activeAssistant = false;\n this.activeAssistantPromptId = null;\n }\n\n private appendAssistant(envelope: GrokUpdate): void {\n const promptId = asString(asRecord(envelope.params._meta)?.promptId)?.trim() || null;\n if (promptId && this.activeAssistantPromptId && promptId !== this.activeAssistantPromptId) {\n this.activeAssistant = false;\n }\n if (promptId) this.activeAssistantPromptId = promptId;\n this.activeUser = false;\n this.activeUserPromptIndex = null;\n\n if (!this.activeAssistant) this.messageCount += 1;\n this.activeAssistant = true;\n }\n}\n\nfunction scanCanonicalMessages(updatesPath: string, fallbackTimestampMs: number) {\n const rewindIndex = new RewindIndex();\n let recordIndex = 0;\n for (const record of readJsonlFile(updatesPath)) {\n rewindIndex.process(record, recordIndex, fallbackTimestampMs);\n recordIndex += 1;\n }\n\n const survivingIndexes = new Set(rewindIndex.survivingRecordIndexes);\n const counter = new GrokMessageCounter();\n recordIndex = 0;\n for (const record of readJsonlFile(updatesPath)) {\n if (survivingIndexes.has(recordIndex)) {\n const envelope = unpackUpdate(record, fallbackTimestampMs);\n if (envelope) counter.process(envelope);\n }\n recordIndex += 1;\n }\n return counter;\n}\n\nfunction scanHeadData(updatesPath: string | null, fallbackTimestampMs: number): GrokHeadData {\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCacheCreateTokens = 0;\n let totalTokens = 0;\n let totalCost = 0;\n let hasUnknownCost = false;\n let hasRewinds = false;\n const modelUsage: Record<string, number> = {};\n let messageCounter = new GrokMessageCounter();\n\n if (updatesPath && existsSync(updatesPath)) {\n for (const line of readJsonlFileLines(updatesPath)) {\n const affectsMessages =\n line.includes('\"user_message_chunk\"') ||\n line.includes('\"agent_thought_chunk\"') ||\n line.includes('\"agent_message_chunk\"') ||\n line.includes('\"tool_call\"') ||\n line.includes('\"plan\"');\n const isTurnCompleted = line.includes('\"turn_completed\"');\n const isRewind = line.includes('\"rewind_marker\"');\n if (!affectsMessages && !isTurnCompleted && !isRewind) continue;\n\n let record: Record<string, unknown>;\n try {\n record = asRecord(JSON.parse(line)) ?? {};\n } catch {\n continue;\n }\n const envelope = unpackUpdate(record, fallbackTimestampMs);\n if (!envelope) continue;\n const type = updateType(envelope);\n if (affectsMessages) messageCounter.process(envelope);\n if (envelope.method === XAI_UPDATE_METHOD && type === \"rewind_marker\") {\n hasRewinds = true;\n }\n\n if (envelope.method !== XAI_UPDATE_METHOD || type !== \"turn_completed\") continue;\n const usage = parseUsage(envelope.update);\n if (!usage) continue;\n\n totalInputTokens = addCount(totalInputTokens, usage.tokens.input ?? 0);\n totalOutputTokens = addCount(totalOutputTokens, usage.tokens.output ?? 0);\n totalCacheReadTokens = addCount(totalCacheReadTokens, usage.tokens.cache_read ?? 0);\n totalCacheCreateTokens = addCount(totalCacheCreateTokens, usage.tokens.cache_create ?? 0);\n totalTokens = addCount(totalTokens, usage.totalTokens);\n if (usage.cost === null && usage.totalTokens > 0) hasUnknownCost = true;\n else totalCost += usage.cost ?? 0;\n\n for (const [model, tokens] of Object.entries(usage.modelUsage)) {\n modelUsage[model] = addCount(modelUsage[model] ?? 0, tokens);\n }\n }\n\n if (hasRewinds) messageCounter = scanCanonicalMessages(updatesPath, fallbackTimestampMs);\n }\n\n return {\n firstUserText: messageCounter.firstUserText,\n visibleMessageCount: messageCounter.messageCount,\n stats: {\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cache_create_tokens: totalCacheCreateTokens || undefined,\n total_tokens: totalTokens || addCount(totalInputTokens, totalOutputTokens),\n total_cost: totalCost,\n cost_source: totalCost > 0 && !hasUnknownCost ? \"recorded\" : undefined,\n },\n modelUsage,\n };\n}\n\nfunction toolTitle(toolName: string): string {\n return GROK_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\nfunction toolStatus(value: unknown): ToolPartStatus | null {\n switch (asString(value)?.toLowerCase()) {\n case \"completed\":\n return \"completed\";\n case \"failed\":\n return \"error\";\n case \"in_progress\":\n case \"pending\":\n return \"running\";\n default:\n return null;\n }\n}\n\nfunction toolOutput(update: Record<string, unknown>): unknown {\n if (update.rawOutput !== undefined && update.rawOutput !== null) return update.rawOutput;\n const content = asArray(update.content);\n if (!content) return undefined;\n\n const texts = content.flatMap((item) => {\n const wrapper = asRecord(item);\n const block = wrapper?.type === \"content\" ? wrapper.content : item;\n const text = textFromContentBlock(block);\n return text ? [text] : [];\n });\n if (texts.length === 0) return content;\n return texts.join(\"\\n\");\n}\n\nfunction planPart(update: Record<string, unknown>, timestampMs: number): PlanPart | null {\n const entries = asArray(update.entries)?.flatMap((value) => {\n const entry = asRecord(value);\n const content = cleanInternalText(asString(entry?.content) ?? \"\");\n if (!entry || !content) return [];\n return [{ content, status: asString(entry.status) ?? \"pending\" }];\n });\n if (!entries || entries.length === 0) return null;\n\n const text = entries\n .map(({ content, status }) => `- [${status === \"completed\" ? \"x\" : \" \"}] ${content}`)\n .join(\"\\n\");\n return {\n type: \"plan\",\n text,\n approval_status: entries.every(({ status }) => status === \"completed\") ? \"success\" : \"fail\",\n time_created: timestampMs,\n };\n}\n\nclass GrokTranscriptReducer {\n private readonly builder = new TranscriptBuilder();\n private activeAssistant: Message | null = null;\n private activeAssistantPromptId: string | null = null;\n private activeUser: Message | null = null;\n private activeUserPromptIndex: number | null = null;\n private latestPlan: PlanPart | null = null;\n private currentMode: string | null = null;\n private currentModel: string | null;\n\n constructor(\n private readonly sessionId: string,\n currentModel: string | null,\n private readonly fallbackTimestampMs: number,\n ) {\n this.currentModel = currentModel;\n }\n\n process(record: Record<string, unknown>): void {\n const envelope = unpackUpdate(record, this.fallbackTimestampMs);\n if (!envelope) return;\n if (envelope.method === XAI_UPDATE_METHOD) {\n this.processXaiUpdate(envelope);\n return;\n }\n this.processAcpUpdate(envelope);\n }\n\n finish(stats: SessionStats): TranscriptResult {\n return this.builder.finish(stats);\n }\n\n private processAcpUpdate(envelope: GrokUpdate): void {\n switch (updateType(envelope)) {\n case \"user_message_chunk\":\n this.appendUserChunk(envelope);\n break;\n case \"agent_thought_chunk\":\n this.appendAssistantText(envelope, \"reasoning\");\n break;\n case \"agent_message_chunk\":\n this.appendAssistantText(envelope, \"text\");\n break;\n case \"tool_call\":\n this.appendToolCall(envelope);\n break;\n case \"tool_call_update\":\n this.updateToolCall(envelope);\n break;\n case \"plan\":\n this.updatePlan(envelope);\n break;\n case \"current_mode_update\":\n this.currentMode = asString(envelope.update.currentModeId)?.trim() || null;\n break;\n }\n }\n\n private processXaiUpdate(envelope: GrokUpdate): void {\n switch (updateType(envelope)) {\n case \"turn_completed\": {\n const usage = parseUsage(envelope.update);\n if (!usage) return;\n this.builder.attachUsageToLatestAssistant(usage.tokens, {\n model: usage.primaryModel ?? this.currentModel,\n cost: usage.cost ?? undefined,\n costSource: usage.cost === null ? undefined : \"recorded\",\n });\n return;\n }\n case \"model_changed\":\n this.currentModel = asString(envelope.update.model_id)?.trim() || this.currentModel;\n return;\n case \"model_auto_switched\":\n this.currentModel = asString(envelope.update.new_model_id)?.trim() || this.currentModel;\n return;\n case \"subagent_spawned\": {\n const childSessionId = asString(envelope.update.child_session_id)?.trim();\n if (childSessionId && this.activeAssistant && !this.activeAssistant.subagent_id) {\n this.activeAssistant.subagent_id = childSessionId;\n }\n }\n }\n }\n\n private appendUserChunk(envelope: GrokUpdate): void {\n if (isHostTurn(envelope.update)) return;\n const part = messagePartFromContentBlock(envelope.update.content, envelope.timestampMs);\n if (!part) return;\n\n const promptIndexValue = asNumber(asRecord(envelope.update._meta)?.promptIndex);\n const promptIndex =\n promptIndexValue !== undefined && Number.isSafeInteger(promptIndexValue)\n ? promptIndexValue\n : null;\n const canReuse =\n this.activeUser !== null &&\n (promptIndex === null ||\n this.activeUserPromptIndex === null ||\n promptIndex === this.activeUserPromptIndex);\n\n if (canReuse) {\n const tail = this.activeUser!.parts.at(-1);\n if (tail?.type === \"text\" && part.type === \"text\") tail.text += part.text;\n else this.activeUser!.parts.push(part);\n } else {\n const eventId = asString(asRecord(envelope.params._meta)?.eventId);\n this.activeUser = this.builder.appendMessage({\n id: eventId || `${this.sessionId}-user-${envelope.timestampMs}`,\n role: \"user\",\n timestampMs: envelope.timestampMs,\n parts: [part],\n });\n }\n\n this.activeUserPromptIndex = promptIndex;\n this.activeAssistant = null;\n this.activeAssistantPromptId = null;\n this.latestPlan = null;\n }\n\n private prepareAssistant(envelope: GrokUpdate): void {\n const promptId = asString(asRecord(envelope.params._meta)?.promptId)?.trim() || null;\n if (promptId && this.activeAssistantPromptId && promptId !== this.activeAssistantPromptId) {\n this.builder.beginTurn();\n this.activeAssistant = null;\n this.latestPlan = null;\n }\n if (promptId) this.activeAssistantPromptId = promptId;\n this.activeUser = null;\n this.activeUserPromptIndex = null;\n }\n\n private assistantInput(envelope: GrokUpdate) {\n const paramsMeta = asRecord(envelope.params._meta);\n return {\n id:\n asString(paramsMeta?.promptId) ||\n asString(paramsMeta?.eventId) ||\n `${this.sessionId}-assistant-${envelope.timestampMs}`,\n timestampMs: envelope.timestampMs,\n agent: \"grok\",\n mode: this.currentMode,\n model: this.currentModel,\n provider: \"xai\",\n };\n }\n\n private appendAssistantText(envelope: GrokUpdate, type: \"text\" | \"reasoning\"): void {\n const text = textFromContentBlock(envelope.update.content);\n if (!text) return;\n this.prepareAssistant(envelope);\n\n const tail = this.activeAssistant?.parts.at(-1);\n if (tail?.type === type) {\n tail.text += text;\n return;\n }\n\n this.activeAssistant = this.builder.appendAssistantPart(\n { type, text, time_created: envelope.timestampMs },\n this.assistantInput(envelope),\n { grouping: \"current\" },\n );\n }\n\n private appendToolCall(envelope: GrokUpdate): void {\n const callId = asString(envelope.update.toolCallId)?.trim();\n const updateMeta = asRecord(envelope.update._meta);\n const nativeTool = asRecord(updateMeta?.[\"x.ai/tool\"]);\n const name =\n asString(nativeTool?.name)?.trim() || asString(envelope.update.title)?.trim() || \"tool\";\n if (!callId) return;\n\n this.prepareAssistant(envelope);\n const metadata = {\n kind: asString(nativeTool?.kind) ?? asString(envelope.update.kind),\n locations: envelope.update.locations,\n };\n const part: ToolPart = {\n type: \"tool\",\n tool: name,\n title: toolTitle(name),\n callID: callId,\n state: {\n status: toolStatus(envelope.update.status) ?? \"running\",\n input: envelope.update.rawInput,\n output: null,\n metadata,\n },\n time_created: envelope.timestampMs,\n };\n\n this.activeAssistant = this.builder.appendToolCall(part, this.assistantInput(envelope), {\n markModeAsTool: true,\n target: \"current\",\n });\n }\n\n private updateToolCall(envelope: GrokUpdate): void {\n const callId = asString(envelope.update.toolCallId)?.trim();\n if (!callId) return;\n this.builder.updateToolCall(callId, (part) => {\n const status = toolStatus(envelope.update.status);\n if (status) part.state.status = status;\n if (envelope.update.rawInput !== undefined) part.state.input = envelope.update.rawInput;\n\n const output = toolOutput(envelope.update);\n if (output !== undefined) {\n if (status === \"error\") part.state.error = output;\n else part.state.output = output;\n }\n\n const metadata = asRecord(part.state.metadata) ?? {};\n if (envelope.update.kind !== undefined) metadata.kind = envelope.update.kind;\n if (envelope.update.locations !== undefined) metadata.locations = envelope.update.locations;\n part.state.metadata = metadata;\n });\n }\n\n private updatePlan(envelope: GrokUpdate): void {\n const part = planPart(envelope.update, envelope.timestampMs);\n if (!part) return;\n this.prepareAssistant(envelope);\n\n if (this.latestPlan) {\n this.latestPlan.text = part.text;\n this.latestPlan.approval_status = part.approval_status;\n this.latestPlan.time_created = part.time_created;\n return;\n }\n\n this.latestPlan = part;\n this.activeAssistant = this.builder.appendAssistantPart(part, this.assistantInput(envelope), {\n grouping: \"current\",\n });\n }\n}\n\nclass UserRunTracker {\n private hasSeenPromptIndex = false;\n private isInUserRun = false;\n private currentPromptIndex: number | null = null;\n\n onUser(promptIndex: number | null): boolean {\n if (promptIndex !== null) this.hasSeenPromptIndex = true;\n const isCounted = this.hasSeenPromptIndex ? promptIndex !== null : true;\n const isNewRun =\n !this.isInUserRun ||\n ((this.hasSeenPromptIndex || promptIndex !== null) &&\n promptIndex !== this.currentPromptIndex);\n\n this.isInUserRun = true;\n if (!isNewRun) return false;\n this.currentPromptIndex = promptIndex;\n return isCounted;\n }\n\n onNonUser(): void {\n this.isInUserRun = false;\n this.currentPromptIndex = null;\n }\n}\n\nclass RewindIndex {\n readonly survivingRecordIndexes: number[] = [];\n hasRewinds = false;\n private readonly promptStarts: number[] = [];\n private readonly userRuns = new UserRunTracker();\n\n process(record: Record<string, unknown>, recordIndex: number, fallbackTimestampMs: number): void {\n const envelope = unpackUpdate(record, fallbackTimestampMs);\n if (!envelope) {\n this.userRuns.onNonUser();\n this.survivingRecordIndexes.push(recordIndex);\n return;\n }\n\n const type = updateType(envelope);\n if (envelope.method === XAI_UPDATE_METHOD && type === \"rewind_marker\") {\n const target = asNumber(envelope.update.target_prompt_index);\n if (target === undefined || !Number.isSafeInteger(target) || target < 0) {\n this.userRuns.onNonUser();\n this.survivingRecordIndexes.push(recordIndex);\n return;\n }\n const truncateAt = this.promptStarts[target] ?? this.survivingRecordIndexes.length;\n this.survivingRecordIndexes.length = truncateAt;\n this.promptStarts.length = Math.min(this.promptStarts.length, target);\n this.userRuns.onNonUser();\n this.hasRewinds = true;\n return;\n }\n\n if (\n envelope.method !== XAI_UPDATE_METHOD &&\n type === \"user_message_chunk\" &&\n !isHostTurn(envelope.update)\n ) {\n const rawPromptIndex = asNumber(asRecord(envelope.update._meta)?.promptIndex);\n const promptIndex =\n rawPromptIndex !== undefined && Number.isSafeInteger(rawPromptIndex) && rawPromptIndex >= 0\n ? rawPromptIndex\n : null;\n if (this.userRuns.onUser(promptIndex)) {\n this.promptStarts.push(this.survivingRecordIndexes.length);\n }\n } else {\n this.userRuns.onNonUser();\n }\n\n this.survivingRecordIndexes.push(recordIndex);\n }\n}\n\nfunction parseTranscript(meta: GrokSessionMeta): TranscriptResult {\n const reducer = new GrokTranscriptReducer(meta.id, meta.currentModel, meta.createdAt);\n if (!meta.updatesPath || !existsSync(meta.updatesPath)) return reducer.finish(meta.stats);\n\n const rewindIndex = new RewindIndex();\n let recordIndex = 0;\n for (const record of readJsonlFile(meta.updatesPath)) {\n rewindIndex.process(record, recordIndex, meta.createdAt);\n reducer.process(record);\n recordIndex += 1;\n }\n if (!rewindIndex.hasRewinds) return reducer.finish(meta.stats);\n\n const survivingIndexes = new Set(rewindIndex.survivingRecordIndexes);\n const replay = new GrokTranscriptReducer(meta.id, meta.currentModel, meta.createdAt);\n recordIndex = 0;\n for (const record of readJsonlFile(meta.updatesPath)) {\n if (survivingIndexes.has(recordIndex)) replay.process(record);\n recordIndex += 1;\n }\n return replay.finish(meta.stats);\n}\n\nexport class GrokAgent extends FileSystemSessionSource<GrokSessionMeta> {\n readonly name = \"grok\";\n readonly displayName = \"Grok\";\n\n private basePath: string | null = null;\n\n private findBasePath(): string | null {\n return firstExisting(join(resolveGrokDataRoot(), \"sessions\"), \"data/grok\");\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n return this.basePath !== null && this.listSessionSources().length > 0;\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveGrokDataRoot();\n return {\n status: \"supported\" as const,\n targets: [{ root: dataRoot, path: join(dataRoot, \"sessions\") }, { path: \"data/grok\" }],\n };\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n this.basePath ??= this.findBasePath();\n if (!this.basePath) return [];\n\n const sources = this.walkFiles(this.basePath, (entry) => entry.name === SUMMARY_FILE);\n return sources.flatMap((source) => {\n const summary = parseSummary(source);\n if (!summary || !matchesScanWindow(summary.updatedAt, options)) return [];\n return [\n {\n sessionId: summary.id,\n sourcePath: source.file,\n fingerprint: this.sourceFingerprint(source),\n },\n ];\n });\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n return getParsedSession(this.parseSessionHeadResult(sourcePath));\n }\n\n protected override scanSessionSourceResult(\n source: SessionSourceRef,\n ): ParseSessionResult<SessionHead> {\n return this.parseSessionHeadResult(source.sourcePath);\n }\n\n private parseSessionHeadResult(sourcePath: string): ParseSessionResult<SessionHead> {\n const source = this.sessionSourceFile(sourcePath);\n const summary = parseSummary(source);\n if (!summary) return skippedSession(\"malformed summary\");\n\n const sessionDir = dirname(source.file);\n const updatesPath = join(sessionDir, UPDATES_FILE);\n const existingUpdatesPath = existsSync(updatesPath) ? updatesPath : null;\n const headData = scanHeadData(existingUpdatesPath, summary.createdAt);\n const messageCount = headData.visibleMessageCount;\n if (messageCount === 0) return filteredSession(\"no visible messages\");\n\n const title = resolveSessionTitle(\n summary.title,\n headData.firstUserText,\n basenameTitle(summary.cwd),\n );\n const stats: SessionStats = { message_count: messageCount, ...headData.stats };\n const fingerprint = this.sourceFingerprint(source);\n const head: SessionHead = {\n id: summary.id,\n slug: this.sessionSlug(summary.id),\n title,\n directory: summary.cwd,\n parent_reference: summary.parentSessionId\n ? { agentName: this.name, sessionId: summary.parentSessionId }\n : undefined,\n time_created: summary.createdAt,\n time_updated: summary.updatedAt,\n stats,\n model_usage: Object.keys(headData.modelUsage).length > 0 ? headData.modelUsage : undefined,\n };\n\n this.sessionMetaMap.set(summary.id, {\n id: summary.id,\n title,\n sourcePath: source.file,\n sourceFingerprint: fingerprint,\n sourceMtimeMs: summary.updatedAt,\n directory: summary.cwd,\n messageCount,\n createdAt: summary.createdAt,\n updatedAt: summary.updatedAt,\n currentModel: summary.currentModel,\n parentSessionId: summary.parentSessionId,\n updatesPath: existingUpdatesPath,\n stats,\n });\n return parsedSession(head);\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n\n const transcript = parseTranscript(meta);\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: this.sessionSlug(meta.id),\n directory: meta.directory,\n parent_reference: meta.parentSessionId\n ? { agentName: this.name, sessionId: meta.parentSessionId }\n : undefined,\n version: undefined,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: transcript.stats,\n messages: transcript.messages,\n };\n }\n\n private sourceFingerprint(source: SessionSourceFile): string {\n const sessionDir = dirname(source.file);\n return JSON.stringify([\n HEAD_INDEX_VERSION,\n PARSER_VERSION,\n source.stat.mtimeMs,\n source.stat.size,\n optionalFileFingerprint(join(sessionDir, UPDATES_FILE)),\n ]);\n }\n}\n","/**\n * DeepSeek Harness (DSH) adapter.\n *\n * Enumeration walks the two-level `sessions/<project-key>/<session-id>/` layout\n * DSH writes. The project key is deliberately lossy — separators collapse and\n * long paths truncate — so it is used only to find candidates; the header's own\n * `id` and `cwd` are the identity, and every artifact must sit exactly where\n * those fields say it does.\n */\nimport { existsSync, readdirSync, realpathSync, statSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport {\n FileSystemSessionSource,\n SessionScanError,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n ParseSessionResult,\n SessionCacheMeta,\n SessionSourceRef,\n SessionWatchPlan,\n} from \"./base.js\";\nimport type { SessionDetail, SessionHead } from \"../types/index.js\";\nimport { basenameTitle, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport {\n DshSessionLogError,\n dshAttachmentsRoot,\n dshFileIdentity,\n dshLogFileName,\n dshLogPath,\n dshSessionsRoot,\n readDshSessionHeader,\n readDshSessionLog,\n resolveDshDataRoot,\n type DshEncoding,\n type DshSessionHeader,\n} from \"./dsh-session-log.js\";\nimport { projectDshSession, type DshProjection } from \"./dsh-transcript.js\";\n\nexport { resolveDshDataRoot } from \"./dsh-session-log.js\";\n\n/** Bump when event mapping, packed-row handling or token semantics change. */\nconst PARSER_REVISION = \"dsh-parser-v1\";\n\nconst ENCODINGS: readonly DshEncoding[] = [\"zstd\", \"none\"];\n\ninterface DshSessionMeta extends SessionCacheMeta {\n id: string;\n sourcePath: string;\n sourceFingerprint: string;\n sourceMtimeMs: number;\n encoding: DshEncoding;\n directory: string;\n title: string;\n createdAt: number;\n updatedAt: number;\n messageCount: number;\n parentSessionId: string | null;\n}\n\n/** One candidate artifact found by walking the session root. */\ninterface DshArtifact {\n sourcePath: string;\n encoding: DshEncoding;\n}\n\ninterface ParsedDshSession {\n header: DshSessionHeader;\n projection: DshProjection;\n}\n\nfunction encodingOfPath(sourcePath: string): DshEncoding {\n return basename(sourcePath) === dshLogFileName(\"zstd\") ? \"zstd\" : \"none\";\n}\n\n/** Two spellings of one physical file (a casing alias) are the same artifact. */\nfunction sameFile(left: string, right: string): boolean {\n if (left === right) return true;\n try {\n return realpathSync(left) === realpathSync(right);\n } catch {\n return false;\n }\n}\n\nexport class DshAgent extends FileSystemSessionSource<DshSessionMeta> {\n readonly name = \"dsh\";\n readonly displayName = \"DSH\";\n\n getSessionWatchPlan(): SessionWatchPlan {\n const dataRoot = resolveDshDataRoot();\n return {\n status: \"supported\",\n targets: [{ root: dataRoot, path: dshSessionsRoot(dataRoot) }],\n };\n }\n\n isAvailable(): boolean {\n try {\n return this.listArtifacts().length > 0;\n } catch {\n // A permission error, mixed encoding or legacy layout is a scan failure\n // to report, never proof that the agent has no data.\n return true;\n }\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n const sessionsRoot = dshSessionsRoot(resolveDshDataRoot());\n const refs: SessionSourceRef[] = [];\n const seenIds = new Map<string, string>();\n\n for (const artifact of this.listArtifacts()) {\n const stats = this.statArtifact(artifact.sourcePath);\n if (!stats) continue;\n if (!matchesScanWindow(Number(stats.mtimeMs), options)) continue;\n\n const header = this.scanStep(\"reading session headers\", artifact.sourcePath, () =>\n readDshSessionHeader(artifact.sourcePath, artifact.encoding),\n );\n this.assertStoredIdentity(sessionsRoot, artifact, header);\n\n const previous = seenIds.get(header.id);\n if (previous) {\n throw new SessionScanError(this.name, \"enumerating session sources\", {\n cause: new DshSessionLogError(\n `duplicate DSH session id ${JSON.stringify(header.id)} in ${JSON.stringify(previous)} and ${JSON.stringify(artifact.sourcePath)}`,\n ),\n sourcePath: artifact.sourcePath,\n });\n }\n seenIds.set(header.id, artifact.sourcePath);\n\n refs.push({\n sessionId: header.id,\n sourcePath: artifact.sourcePath,\n fingerprint: JSON.stringify([\n PARSER_REVISION,\n artifact.encoding,\n ...dshFileIdentity(stats),\n ]),\n });\n }\n\n return refs;\n }\n\n /** The scan window is applied during enumeration, so parsing needs no options. */\n scanSessionSource(sourcePath: string): SessionHead | null {\n return getParsedSession(\n this.scanSessionSourceResult({ sessionId: \"\", sourcePath, fingerprint: \"\" }),\n );\n }\n\n protected override scanSessionSourceResult(\n source: SessionSourceRef,\n ): ParseSessionResult<SessionHead> {\n const encoding = encodingOfPath(source.sourcePath);\n const { header, projection } = this.parseSession(source.sourcePath, encoding);\n if (projection.messages.length === 0) {\n return filteredSession(\"no visible messages\");\n }\n\n const head: SessionHead = {\n id: header.id,\n slug: this.sessionSlug(header.id),\n title: this.resolveTitle(header, projection),\n directory: header.cwd ?? \"\",\n ...(header.parentSession\n ? { parent_reference: { agentName: this.name, sessionId: header.parentSession } }\n : {}),\n time_created: header.createdAt,\n time_updated: projection.updatedAt,\n stats: projection.stats,\n ...(Object.keys(projection.modelUsage).length > 0\n ? { model_usage: projection.modelUsage }\n : {}),\n };\n\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n sourcePath: source.sourcePath,\n sourceFingerprint: JSON.stringify([\n PARSER_REVISION,\n encoding,\n ...dshFileIdentity(statSync(source.sourcePath, { bigint: true })),\n ]),\n sourceMtimeMs: statSync(source.sourcePath).mtimeMs,\n encoding,\n directory: head.directory,\n title: head.title,\n createdAt: head.time_created,\n updatedAt: projection.updatedAt,\n messageCount: projection.messages.length,\n parentSessionId: header.parentSession ?? null,\n });\n\n return parsedSession(head);\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n\n const { header, projection } = this.parseSession(meta.sourcePath, meta.encoding);\n return {\n reference: { agentName: this.name, sessionId: header.id },\n id: header.id,\n title: this.resolveTitle(header, projection),\n slug: this.sessionSlug(header.id),\n directory: header.cwd ?? \"\",\n ...(header.parentSession\n ? { parent_reference: { agentName: this.name, sessionId: header.parentSession } }\n : {}),\n version: \"0\",\n time_created: header.createdAt,\n time_updated: projection.updatedAt,\n stats: projection.stats,\n messages: projection.messages,\n };\n }\n\n /**\n * A cached head with no visible messages was materialized from context-only\n * events; dropping it keeps blank sessions out of the list after a restart.\n */\n override filterCachedSessions(sessions: SessionHead[]): SessionHead[] {\n return sessions.filter((session) => session.stats.message_count > 0);\n }\n\n private parseSession(sourcePath: string, encoding: DshEncoding): ParsedDshSession {\n const dataRoot = resolveDshDataRoot();\n const { header, events } = readDshSessionLog(sourcePath, encoding);\n return {\n header,\n projection: projectDshSession({\n header,\n events,\n sourcePath,\n attachmentsRoot: dshAttachmentsRoot(dataRoot),\n }),\n };\n }\n\n private resolveTitle(header: DshSessionHeader, projection: DshProjection): string {\n return resolveSessionTitle(projection.title, null, basenameTitle(header.cwd ?? null));\n }\n\n /**\n * Walk `sessions/<project>/<session>/` and reject the layouts DSH itself\n * refuses: a flat pre-directory artifact, and a root or session directory\n * holding both physical encodings (which one is current is unknowable).\n */\n private listArtifacts(): DshArtifact[] {\n const sessionsRoot = dshSessionsRoot(resolveDshDataRoot());\n const artifacts: DshArtifact[] = [];\n let rootEncoding: DshEncoding | null = null;\n\n for (const project of this.listDirectories(sessionsRoot, true)) {\n this.rejectLegacyLayout(project);\n for (const sessionDir of this.listDirectories(project, false)) {\n const present = ENCODINGS.filter((encoding) =>\n existsSync(join(sessionDir, dshLogFileName(encoding))),\n );\n if (present.length === 0) continue;\n if (present.length > 1) {\n this.rejectEnumeration(\n sessionDir,\n `session directory ${JSON.stringify(sessionDir)} holds both physical encodings`,\n );\n }\n const encoding = present[0] as DshEncoding;\n if (rootEncoding !== null && rootEncoding !== encoding) {\n this.rejectEnumeration(\n sessionDir,\n `session root ${JSON.stringify(sessionsRoot)} mixes ${rootEncoding} and ${encoding} artifacts`,\n );\n }\n rootEncoding = encoding;\n artifacts.push({ sourcePath: join(sessionDir, dshLogFileName(encoding)), encoding });\n }\n }\n\n return artifacts;\n }\n\n private listDirectories(directory: string, tolerateMissing: boolean): string[] {\n try {\n return readdirSync(directory, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => join(directory, entry.name));\n } catch (error) {\n // Only an absent session root means \"no DSH data\"; every other I/O\n // failure must surface so a readable baseline is not discarded.\n if (tolerateMissing && isMissingDirectory(error)) return [];\n throw new SessionScanError(this.name, \"enumerating session sources\", {\n cause: error,\n sourcePath: directory,\n });\n }\n }\n\n private rejectLegacyLayout(project: string): void {\n const legacy = readdirSync(project, { withFileTypes: true }).find(\n (entry) =>\n entry.isFile() && (entry.name.endsWith(\".jsonl\") || entry.name.endsWith(\".jsonl.zstd\")),\n );\n if (!legacy) return;\n this.rejectEnumeration(\n join(project, legacy.name),\n `session artifact ${JSON.stringify(join(project, legacy.name))} uses the unsupported flat-file layout`,\n );\n }\n\n /** The header's id and cwd must name exactly the artifact they were read from. */\n private assertStoredIdentity(\n sessionsRoot: string,\n artifact: DshArtifact,\n header: DshSessionHeader,\n ): void {\n let expected: string;\n try {\n expected = dshLogPath(sessionsRoot, header.cwd, header.id, artifact.encoding);\n } catch (error) {\n this.rejectEnumeration(\n artifact.sourcePath,\n `header id ${JSON.stringify(header.id)} cannot name a storage path`,\n error,\n );\n }\n if (!sameFile(artifact.sourcePath, expected)) {\n this.rejectEnumeration(\n artifact.sourcePath,\n `header identifies ${JSON.stringify(expected)}, not ${JSON.stringify(artifact.sourcePath)}`,\n );\n }\n }\n\n private statArtifact(sourcePath: string) {\n try {\n return statSync(sourcePath, { bigint: true });\n } catch (error) {\n if (isMissingDirectory(error)) return null;\n throw new SessionScanError(this.name, \"reading session source metadata\", {\n cause: error,\n sourcePath,\n });\n }\n }\n\n private rejectEnumeration(sourcePath: string, reason: string, cause?: unknown): never {\n throw new SessionScanError(this.name, \"enumerating session sources\", {\n cause: new DshSessionLogError(reason, cause ? { cause } : undefined),\n sourcePath,\n });\n }\n}\n\nfunction isMissingDirectory(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null || !(\"code\" in error)) return false;\n const code = (error as { code?: unknown }).code;\n return code === \"ENOENT\" || code === \"ENOTDIR\";\n}\n","/**\n * Read-only reader for DeepSeek Harness (DSH) v0 session artifacts.\n *\n * A DSH log is not one compressed blob: it is a concatenation of independently\n * checksummed Zstandard frames — the first holding the header line, each later\n * one holding a durable append batch. Decompressing the whole file at once\n * yields only the first frame, so this module scans frame ranges structurally\n * and decodes them one by one. It also expands the packed `*-chunks` storage\n * rows DSH writes for streaming deltas, so a physical JSONL line count is\n * never mistaken for an event count.\n *\n * CodeSesh is a strictly read-only consumer: nothing here writes, truncates or\n * repairs a DSH artifact, and a torn tail is reported as a warning over the\n * verified complete prefix.\n */\nimport { closeSync, openSync, readFileSync, readSync, statSync, type BigIntStats } from \"node:fs\";\nimport { join } from \"node:path\";\nimport * as zlib from \"node:zlib\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport { resolveHomePath } from \"../discovery/paths.js\";\n\n/** Physical encoding of a session artifact; DSH defaults to `zstd`. */\nexport type DshEncoding = \"zstd\" | \"none\";\n\n/** The on-disk session format version this reader understands. */\nconst DSH_FORMAT_VERSION = 0;\n\n/** DSH truncates a project-directory slug to this many characters. */\nconst PROJECT_SLUG_MAX_LENGTH = 251;\n\n/** Reads racing an active append retry this many times before failing. */\nconst STABLE_READ_ATTEMPTS = 3;\n\n/** Enough for any DSH header record; a longer one falls back to a whole-file read. */\nconst HEADER_PREFIX_BYTES = 64 * 1024;\n\nconst ZSTD_MAGIC = 0xfd2fb528;\n\n/**\n * DSH's `KNOWN_SESSION_EVENT_TYPES` for format version 0. An unrecognized type\n * without the envelope's `ignorable` marker means the log was written by a\n * newer harness whose semantics could change how the rest of it reads, so the\n * source is refused rather than silently reconstructed wrong.\n */\nconst KNOWN_DSH_EVENT_TYPES: ReadonlySet<string> = new Set([\n \"agent-preset/selected\",\n \"agent/inbox/spliced\",\n \"approval/asked\",\n \"approval/decided\",\n \"approval/policy\",\n \"assistant/chunk\",\n \"assistant/message\",\n \"command/done\",\n \"command/run\",\n \"compaction/end\",\n \"compaction/prune\",\n \"compaction/start\",\n \"compaction/summary\",\n \"feedback/record\",\n \"goal/change\",\n \"hook/invoked\",\n \"hook/result\",\n \"llm/retry\",\n \"llm/retry-started\",\n \"permission/preset\",\n \"plan/mode\",\n \"request/context\",\n \"request/header\",\n \"sandbox/mode\",\n \"schedule/change\",\n \"session/end-seed\",\n \"session/title\",\n \"session/title-llm-request\",\n \"step/end\",\n \"step/start\",\n \"subagent/descriptor\",\n \"todo/write\",\n \"tool-workflow/agent-end\",\n \"tool-workflow/agent-start\",\n \"tool-workflow/run-end\",\n \"tool-workflow/run-start\",\n \"tool/call\",\n \"tool/code-dispatch\",\n \"tool/code-dispatch-start\",\n \"tool/result\",\n \"turn/end\",\n \"turn/start\",\n \"user/message\",\n \"web/deepseek-search-llm-request\",\n]);\n\n/** Storage-row tags: a durable encoding vocabulary, never session events. */\nconst TEXT_CHUNK_ROWS: ReadonlySet<string> = new Set([\"text-chunks\", \"reasoning-chunks\"]);\nconst TOOL_CALL_CHUNK_ROW = \"tool-call-chunks\";\n\n/** Immutable storage metadata from a log's first record. */\nexport interface DshSessionHeader {\n id: string;\n createdAt: number;\n cwd: string | undefined;\n parentSession: string | undefined;\n seedLength: number | undefined;\n origin: \"subagent\" | undefined;\n delegationDepth: number;\n agentPreset: string | undefined;\n}\n\n/** One entry of the DSH append-only log, after storage rows are expanded. */\nexport interface DshEvent {\n type: string;\n seq: number;\n time: number;\n data: unknown;\n surfaceOp?: unknown;\n ignorable?: unknown;\n}\n\n/** A header plus the contiguous event prefix this reader could verify. */\nexport interface DshSessionLog {\n header: DshSessionHeader;\n events: DshEvent[];\n}\n\nexport class DshSessionLogError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"DshSessionLogError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Data root and path layout\n// ---------------------------------------------------------------------------\n\n/**\n * Reproduce DSH's `resolveDshHome`: a non-blank `DSH_HOME`, else `~/.dsh`.\n * DSH consults no XDG or Windows AppData location, so neither does this.\n * The blank/tilde/relative handling now lives in the shared resolveHomePath.\n */\nexport function resolveDshDataRoot(): string {\n return resolveHomePath(\"DSH_HOME\", \".dsh\");\n}\n\nexport function dshSessionsRoot(dataRoot: string): string {\n return join(dataRoot, \"sessions\");\n}\n\nexport function dshAttachmentsRoot(dataRoot: string): string {\n return join(dataRoot, \"attachments\", \"v1\");\n}\n\nexport function dshLogFileName(encoding: DshEncoding): string {\n return encoding === \"zstd\" ? \"session.jsonl.zstd\" : \"session.jsonl\";\n}\n\nfunction isSafeSegmentChar(ch: string): boolean {\n return /^[A-Za-z0-9._-]$/.test(ch);\n}\n\nfunction escapeCodeUnit(code: number): string {\n return `~${code.toString(16).toUpperCase().padStart(4, \"0\")}`;\n}\n\n/**\n * DSH's `encodeSegment`: injective over all UTF-16 strings, so a session id\n * can never escape its directory. Operates on code units to preserve lone\n * surrogates, and special-cases `.` / `..` which are safe per character yet\n * traversing as whole segments.\n */\nexport function dshEncodeSegment(raw: string): string {\n if (raw.length === 0) throw new DshSessionLogError(\"cannot encode an empty path segment\");\n if (raw === \".\") return \"~002E\";\n if (raw === \"..\") return \"~002E~002E\";\n let out = \"\";\n for (let index = 0; index < raw.length; index += 1) {\n const code = raw.charCodeAt(index);\n const ch = String.fromCharCode(code);\n out += ch !== \"~\" && isSafeSegmentChar(ch) ? ch : escapeCodeUnit(code);\n }\n return out;\n}\n\n/**\n * DSH's `projectKey`: a human-navigable, deliberately lossy directory name.\n * Separator runs collapse to one `-` and the slug is truncated, so the key\n * cannot recover a cwd — only the header can.\n */\nexport function dshProjectKey(cwd: string): string {\n if (cwd.length === 0) throw new DshSessionLogError(\"cannot encode an empty project path\");\n let readable = \"\";\n let separatorRun = false;\n for (let index = 0; index < cwd.length; index += 1) {\n const code = cwd.charCodeAt(index);\n const ch = String.fromCharCode(code);\n if (ch === \"/\" || ch === \"\\\\\" || ch === \":\") {\n if (!separatorRun) readable += \"-\";\n separatorRun = true;\n continue;\n }\n readable += ch !== \"~\" && isSafeSegmentChar(ch) ? ch : escapeCodeUnit(code);\n separatorRun = false;\n }\n const slug = readable.replace(/^-+/, \"\") || \"root\";\n return `--${slug.slice(0, PROJECT_SLUG_MAX_LENGTH)}--`;\n}\n\n/** The artifact path the header's own identity fields name. */\nexport function dshLogPath(\n sessionsRoot: string,\n cwd: string | undefined,\n id: string,\n encoding: DshEncoding,\n): string {\n const project = cwd === undefined ? \"_no-cwd\" : dshProjectKey(cwd);\n return join(sessionsRoot, project, dshEncodeSegment(id), dshLogFileName(encoding));\n}\n\n// ---------------------------------------------------------------------------\n// Stable snapshot\n// ---------------------------------------------------------------------------\n\n/** A file's bytes plus the identity proving nothing changed while reading. */\nexport interface DshFileSnapshot {\n buffer: Buffer;\n stats: BigIntStats;\n}\n\nfunction sameFileIdentity(before: BigIntStats, after: BigIntStats): boolean {\n return (\n before.dev === after.dev &&\n before.ino === after.ino &&\n before.size === after.size &&\n before.mtimeNs === after.mtimeNs &&\n before.ctimeNs === after.ctimeNs\n );\n}\n\n/**\n * Read a file whose writer may be appending concurrently. Bracketing the read\n * with two identical `stat`s proves the bytes belong to one point in time; a\n * file that keeps changing is a transient failure the watcher retries, never a\n * reason to publish a half-read session.\n */\nexport function readDshFileSnapshot(sourcePath: string): DshFileSnapshot {\n for (let attempt = 0; attempt < STABLE_READ_ATTEMPTS; attempt += 1) {\n const before = statSync(sourcePath, { bigint: true });\n const buffer = readFileSync(sourcePath);\n const after = statSync(sourcePath, { bigint: true });\n if (sameFileIdentity(before, after)) return { buffer, stats: after };\n }\n throw new DshSessionLogError(\n `DSH session log ${JSON.stringify(sourcePath)} changed during every read attempt`,\n );\n}\n\n/** Identity fields that must all change together for an append to go unnoticed. */\nexport function dshFileIdentity(stats: BigIntStats): string[] {\n return [stats.dev, stats.ino, stats.size, stats.mtimeNs, stats.ctimeNs].map(String);\n}\n\n/** Read at most `maxBytes` from the start of a file, without loading the rest. */\nfunction readFilePrefix(sourcePath: string, maxBytes: number): Buffer {\n const handle = openSync(sourcePath, \"r\");\n try {\n const buffer = Buffer.allocUnsafe(maxBytes);\n return buffer.subarray(0, readSync(handle, buffer, 0, maxBytes, 0));\n } finally {\n closeSync(handle);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Zstandard container\n// ---------------------------------------------------------------------------\n\ninterface ZstdFrameRange {\n start: number;\n end: number;\n}\n\ninterface ZstdFrameScan {\n frames: ZstdFrameRange[];\n /** Start of an incomplete final frame, when EOF interrupts one. */\n tornStart?: number;\n}\n\ntype ZstdDecompressSync = (input: Buffer) => Buffer;\n\n/**\n * Namespace import plus a runtime probe: a named import of a function absent\n * on older Node fails at ESM link time, taking every other agent down with it.\n */\nfunction resolveZstdDecoder(sourcePath: string): ZstdDecompressSync {\n const decoder = (zlib as { zstdDecompressSync?: ZstdDecompressSync }).zstdDecompressSync;\n if (typeof decoder !== \"function\") {\n throw new DshSessionLogError(\n `DSH session log ${JSON.stringify(sourcePath)} is Zstandard-compressed, but this Node ` +\n `runtime (${process.version}) has no native Zstandard decoder; DSH itself requires ` +\n \"Node ^22.19.0 || >=24.0.0\",\n );\n }\n return decoder;\n}\n\n/**\n * Locate structurally complete frames without decompressing any block. Only\n * the final frame may be cut short by EOF; anything else malformed is\n * corruption, because DSH publishes each batch as a whole frame.\n */\nfunction scanZstdFrames(\n buffer: Buffer,\n sourcePath: string,\n maxFrames = Number.POSITIVE_INFINITY,\n): ZstdFrameScan {\n const frames: ZstdFrameRange[] = [];\n let offset = 0;\n\n const corrupt = (reason: string): never => {\n throw new DshSessionLogError(\n `corrupt Zstandard session log ${JSON.stringify(sourcePath)}: ${reason}`,\n );\n };\n\n while (offset < buffer.length) {\n const start = offset;\n if (buffer.length - offset < 4) return { frames, tornStart: start };\n if (buffer.readUInt32LE(offset) !== ZSTD_MAGIC)\n corrupt(`invalid frame magic at byte ${offset}`);\n offset += 4;\n\n if (offset === buffer.length) return { frames, tornStart: start };\n const descriptor = buffer.readUInt8(offset);\n offset += 1;\n if ((descriptor & 0x18) !== 0) corrupt(`reserved frame-header bit at byte ${offset - 1}`);\n\n const contentSizeFlag = descriptor >>> 6;\n const singleSegment = (descriptor & 0x20) !== 0;\n const hasChecksum = (descriptor & 0x04) !== 0;\n const dictionaryFlag = descriptor & 0x03;\n const dictionaryBytes = dictionaryFlag === 3 ? 4 : dictionaryFlag;\n const contentSizeBytes = contentSizeFlag === 0 ? (singleSegment ? 1 : 0) : 1 << contentSizeFlag;\n const remainingHeaderBytes = (singleSegment ? 0 : 1) + dictionaryBytes + contentSizeBytes;\n if (buffer.length - offset < remainingHeaderBytes) return { frames, tornStart: start };\n offset += remainingHeaderBytes;\n\n for (;;) {\n if (buffer.length - offset < 3) return { frames, tornStart: start };\n const blockHeader = buffer.readUIntLE(offset, 3);\n offset += 3;\n const lastBlock = (blockHeader & 1) !== 0;\n const blockType = (blockHeader >>> 1) & 0x03;\n const blockSize = blockHeader >>> 3;\n if (blockType === 0x03) corrupt(`reserved block type at byte ${offset - 3}`);\n // An RLE block stores one repeated byte regardless of its declared size.\n const payloadBytes = blockType === 0x01 ? 1 : blockSize;\n if (buffer.length - offset < payloadBytes) return { frames, tornStart: start };\n offset += payloadBytes;\n if (lastBlock) break;\n }\n\n if (hasChecksum) {\n if (buffer.length - offset < 4) return { frames, tornStart: start };\n offset += 4;\n }\n frames.push({ start, end: offset });\n if (frames.length === maxFrames) return { frames };\n }\n\n return { frames };\n}\n\n/** Decode one complete frame; Node's decoder validates the frame checksum. */\nfunction decodeFrame(\n decoder: ZstdDecompressSync,\n buffer: Buffer,\n frame: ZstdFrameRange,\n sourcePath: string,\n): string {\n try {\n return decoder(buffer.subarray(frame.start, frame.end)).toString(\"utf8\");\n } catch (error) {\n throw new DshSessionLogError(\n `corrupt Zstandard session log ${JSON.stringify(sourcePath)}: frame at byte ${frame.start} failed validation`,\n { cause: error },\n );\n }\n}\n\n/**\n * Split one frame's plaintext into whole JSONL records. A complete frame that\n * ends mid-record is corruption, not a torn tail: DSH writes each batch as\n * newline-terminated lines inside a single frame.\n */\nfunction frameRecords(plaintext: string, sourcePath: string, frameStart: number): string[] {\n if (!plaintext.endsWith(\"\\n\")) {\n throw new DshSessionLogError(\n `corrupt Zstandard session log ${JSON.stringify(sourcePath)}: complete frame at byte ${frameStart} ends mid-record`,\n );\n }\n return plaintext.slice(0, -1).split(\"\\n\");\n}\n\nfunction warnTornTail(sourcePath: string, detail: Record<string, unknown>): void {\n getCoreDiagnostics()?.warn(\"dsh.torn_session_tail\", { source_path: sourcePath, ...detail });\n}\n\n/** Records of a compressed artifact, header line first. */\nfunction readCompressedRecords(buffer: Buffer, sourcePath: string, headerOnly: boolean): string[] {\n const decoder = resolveZstdDecoder(sourcePath);\n const scan = scanZstdFrames(buffer, sourcePath, headerOnly ? 1 : Number.POSITIVE_INFINITY);\n const first = scan.frames[0];\n if (!first) {\n throw new DshSessionLogError(\n `DSH session log ${JSON.stringify(sourcePath)} has no complete header frame`,\n );\n }\n\n const headerPlaintext = decodeFrame(decoder, buffer, first, sourcePath);\n if (headerPlaintext.indexOf(\"\\n\") !== headerPlaintext.length - 1) {\n throw new DshSessionLogError(\n `corrupt Zstandard session log ${JSON.stringify(sourcePath)}: header frame does not hold exactly one record`,\n );\n }\n const records = [headerPlaintext.slice(0, -1)];\n if (headerOnly) return records;\n\n for (const frame of scan.frames.slice(1)) {\n records.push(\n ...frameRecords(decodeFrame(decoder, buffer, frame, sourcePath), sourcePath, frame.start),\n );\n }\n if (scan.tornStart !== undefined) {\n warnTornTail(sourcePath, { encoding: \"zstd\", torn_start: scan.tornStart });\n }\n return records;\n}\n\n/** Records of a plaintext artifact; an unterminated final line is a torn tail. */\nfunction readPlaintextRecords(buffer: Buffer, sourcePath: string, headerOnly: boolean): string[] {\n const text = buffer.toString(\"utf8\");\n const newline = text.indexOf(\"\\n\");\n if (newline === -1) {\n throw new DshSessionLogError(\n `DSH session log ${JSON.stringify(sourcePath)} has no complete header record`,\n );\n }\n if (headerOnly) return [text.slice(0, newline)];\n\n const complete = text.endsWith(\"\\n\");\n const records = (complete ? text.slice(0, -1) : text).split(\"\\n\");\n if (!complete) {\n records.pop();\n warnTornTail(sourcePath, {\n encoding: \"none\",\n torn_bytes: text.length - text.lastIndexOf(\"\\n\") - 1,\n });\n }\n return records;\n}\n\nfunction readRecords(\n buffer: Buffer,\n sourcePath: string,\n encoding: DshEncoding,\n headerOnly: boolean,\n): string[] {\n return encoding === \"zstd\"\n ? readCompressedRecords(buffer, sourcePath, headerOnly)\n : readPlaintextRecords(buffer, sourcePath, headerOnly);\n}\n\n// ---------------------------------------------------------------------------\n// Header and event validation\n// ---------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isCount(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction optionalString(value: unknown, field: string, sourcePath: string): string | undefined {\n if (value === undefined) return undefined;\n if (typeof value !== \"string\") {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: header ${field} must be a string`,\n );\n }\n return value;\n}\n\nfunction parseJsonRecord(line: string, what: string, sourcePath: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (error) {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: ${what} is not valid JSON`,\n { cause: error },\n );\n }\n if (!isRecord(parsed)) {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: ${what} is not an object`,\n );\n }\n return parsed;\n}\n\n/**\n * Refuse a foreign format version before any structural check: a future format\n * need not satisfy today's shape at all, and its reader owes the user \"upgrade\n * CodeSesh\", never \"corrupt session log\".\n */\nfunction parseHeaderRecord(line: string, sourcePath: string): DshSessionHeader {\n const parsed = parseJsonRecord(line, \"header line\", sourcePath);\n const version = parsed[\"version\"];\n if (typeof version !== \"number\" || version !== DSH_FORMAT_VERSION) {\n throw new DshSessionLogError(\n `unsupported DSH session format version ${JSON.stringify(version)} in ${JSON.stringify(sourcePath)}; ` +\n `this build reads version ${DSH_FORMAT_VERSION}`,\n );\n }\n const invalid = (reason: string): never => {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: ${reason}`,\n );\n };\n\n if (parsed[\"type\"] !== \"session\") invalid(\"first record is not a session header\");\n const id = parsed[\"id\"];\n if (typeof id !== \"string\" || id.length === 0) invalid(\"header id must be a non-empty string\");\n const createdAt = parsed[\"createdAt\"];\n if (!isCount(createdAt)) invalid(\"header createdAt must be a non-negative safe integer\");\n const delegationDepth = parsed[\"delegationDepth\"];\n if (!isCount(delegationDepth)) {\n invalid(\"header delegationDepth must be a non-negative safe integer\");\n }\n const seedLength = parsed[\"seedLength\"];\n if (seedLength !== undefined && !isCount(seedLength)) {\n invalid(\"header seedLength must be a non-negative safe integer\");\n }\n const origin = parsed[\"origin\"];\n if (origin !== undefined && origin !== \"subagent\") invalid(\"header origin must be 'subagent'\");\n\n return {\n id: id as string,\n createdAt: createdAt as number,\n cwd: optionalString(parsed[\"cwd\"], \"cwd\", sourcePath),\n parentSession: optionalString(parsed[\"parentSession\"], \"parentSession\", sourcePath),\n seedLength: seedLength as number | undefined,\n origin: origin as \"subagent\" | undefined,\n delegationDepth: delegationDepth as number,\n agentPreset: optionalString(parsed[\"agentPreset\"], \"agentPreset\", sourcePath),\n };\n}\n\n/** Validate the run-shared fields of a packed chunk row and return its members. */\nfunction chunkRunMembers(\n data: Record<string, unknown>,\n payloadKey: \"texts\" | \"args\",\n tag: string,\n sourcePath: string,\n): { members: string[]; gaps: number[] } {\n const malformed = (reason: string): never => {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: malformed ${tag} storage row: ${reason}`,\n );\n };\n if (\n typeof data[\"turn\"] !== \"number\" ||\n typeof data[\"step\"] !== \"number\" ||\n typeof data[\"index\"] !== \"number\"\n ) {\n malformed(\"turn/step/index must be numbers\");\n }\n const payload = data[payloadKey];\n if (\n !Array.isArray(payload) ||\n payload.length === 0 ||\n payload.some((entry) => typeof entry !== \"string\")\n ) {\n malformed(`${payloadKey} must be a non-empty string array`);\n }\n const gaps = data[\"dt\"];\n if (!Array.isArray(gaps) || gaps.some((gap) => !Number.isSafeInteger(gap))) {\n malformed(\"dt must be an array of safe integers\");\n }\n const members = payload as string[];\n if ((gaps as number[]).length !== members.length - 1) {\n malformed(`dt length ${(gaps as number[]).length} does not match ${members.length} members`);\n }\n return { members, gaps: gaps as number[] };\n}\n\n/**\n * Expand one packed chunk row back into the exact `assistant/chunk` events it\n * stores. A malformed row throws: treating it as a single opaque event would\n * silently drop an entire streaming run.\n */\nfunction expandChunkRow(row: Record<string, unknown>, tag: string, sourcePath: string): DshEvent[] {\n const malformed = (reason: string): never => {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: malformed ${tag} storage row: ${reason}`,\n );\n };\n const seq0 = row[\"seq0\"];\n const time0 = row[\"time0\"];\n if (!isCount(seq0)) malformed(\"seq0 must be a non-negative safe integer\");\n if (!Number.isSafeInteger(time0)) malformed(\"time0 must be a safe integer\");\n const data = row[\"data\"];\n if (!isRecord(data)) malformed(\"data must be an object\");\n const payload = data as Record<string, unknown>;\n\n const isToolCall = tag === TOOL_CALL_CHUNK_ROW;\n const { members, gaps } = chunkRunMembers(\n payload,\n isToolCall ? \"args\" : \"texts\",\n tag,\n sourcePath,\n );\n const callId = payload[\"id\"];\n const callName = payload[\"name\"];\n if (isToolCall) {\n if (typeof callId !== \"string\") malformed(\"id must be a string\");\n if (callName !== undefined && typeof callName !== \"string\") malformed(\"name must be a string\");\n }\n if (!Number.isSafeInteger((seq0 as number) + members.length - 1)) {\n malformed(\"member seqs must stay safe integers\");\n }\n\n const turn = payload[\"turn\"] as number;\n const step = payload[\"step\"] as number;\n const index = payload[\"index\"] as number;\n const deltaType =\n tag === \"text-chunks\"\n ? \"text-delta\"\n : tag === \"reasoning-chunks\"\n ? \"reasoning-delta\"\n : \"tool-call-delta\";\n\n const events: DshEvent[] = [];\n let time = time0 as number;\n for (let member = 0; member < members.length; member += 1) {\n if (member > 0) {\n time += gaps[member - 1] as number;\n if (!Number.isSafeInteger(time)) malformed(\"member times must stay safe integers\");\n }\n const chunk = isToolCall\n ? {\n type: deltaType,\n index,\n id: callId,\n ...(callName !== undefined ? { name: callName } : {}),\n argumentsDelta: members[member],\n }\n : { type: deltaType, index, text: members[member] };\n events.push({\n type: \"assistant/chunk\",\n seq: (seq0 as number) + member,\n time,\n data: { turn, step, chunk },\n });\n }\n return events;\n}\n\n/** Decode one storage record into the event(s) it holds, in log order. */\nfunction decodeStorageRecord(line: string, sourcePath: string): DshEvent[] {\n const parsed = parseJsonRecord(line, \"event record\", sourcePath);\n const tag = parsed[\"type\"];\n if (typeof tag === \"string\" && (TEXT_CHUNK_ROWS.has(tag) || tag === TOOL_CALL_CHUNK_ROW)) {\n return expandChunkRow(parsed, tag, sourcePath);\n }\n if (typeof tag !== \"string\" || tag.length === 0) {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: event record has no type`,\n );\n }\n if (!KNOWN_DSH_EVENT_TYPES.has(tag) && parsed[\"ignorable\"] !== true) {\n throw new DshSessionLogError(\n `DSH session log ${JSON.stringify(sourcePath)} contains unsupported required event ` +\n `${JSON.stringify(tag)}; upgrade CodeSesh to read it`,\n );\n }\n if (!isCount(parsed[\"seq\"]) || !Number.isSafeInteger(parsed[\"time\"])) {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: event ${JSON.stringify(tag)} has an invalid seq/time`,\n );\n }\n return [parsed as unknown as DshEvent];\n}\n\n// ---------------------------------------------------------------------------\n// Public reads\n// ---------------------------------------------------------------------------\n\n/**\n * Read a log's authoritative identity without decoding its conversation, so\n * enumeration scales with the session count rather than total log size.\n *\n * The header is an immutable prefix that only a whole-file replacement can\n * change, and a replacement moves the fingerprint, so this read deliberately\n * skips the stable-snapshot handshake a full parse needs.\n */\nexport function readDshSessionHeader(sourcePath: string, encoding: DshEncoding): DshSessionHeader {\n const prefix = readFilePrefix(sourcePath, HEADER_PREFIX_BYTES);\n const line =\n firstRecordOf(prefix, sourcePath, encoding, prefix.length === HEADER_PREFIX_BYTES) ??\n firstRecordOf(readFileSync(sourcePath), sourcePath, encoding, false);\n return parseHeaderRecord(line as string, sourcePath);\n}\n\n/** The first record, or null when only a longer read could contain it. */\nfunction firstRecordOf(\n buffer: Buffer,\n sourcePath: string,\n encoding: DshEncoding,\n mayBeTruncated: boolean,\n): string | null {\n if (mayBeTruncated) {\n const complete =\n encoding === \"zstd\"\n ? scanZstdFrames(buffer, sourcePath, 1).frames.length > 0\n : buffer.includes(0x0a);\n if (!complete) return null;\n }\n return readRecords(buffer, sourcePath, encoding, true)[0] as string;\n}\n\n/**\n * Read the header and the contiguous event prefix a log can prove. Expanded\n * events must be densely numbered from zero: a gap, duplicate or rewind means\n * the source is corrupt, not merely incomplete.\n */\nexport function readDshSessionLog(sourcePath: string, encoding: DshEncoding): DshSessionLog {\n const { buffer } = readDshFileSnapshot(sourcePath);\n const records = readRecords(buffer, sourcePath, encoding, false);\n const header = parseHeaderRecord(records[0] as string, sourcePath);\n\n const events: DshEvent[] = [];\n for (let line = 1; line < records.length; line += 1) {\n for (const event of decodeStorageRecord(records[line] as string, sourcePath)) {\n if (event.seq !== events.length) {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: seq ${event.seq} at record ` +\n `${line} breaks the contiguous prefix (expected ${events.length})`,\n );\n }\n events.push(event);\n }\n }\n\n if (header.seedLength !== undefined && header.seedLength > events.length) {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(sourcePath)}: seedLength ${header.seedLength} ` +\n `exceeds ${events.length} events`,\n );\n }\n\n return { header, events };\n}\n","/**\n * Projection from a DSH v0 event log onto CodeSesh's session contract.\n *\n * Three DSH distinctions drive everything here and have no CodeSesh equivalent\n * yet, so they are resolved during projection rather than shown raw:\n *\n * - `user/message` covers direct human prompts AND injected context (agent\n * instructions, system-prompt snapshots, skill catalogs); only `source.kind\n * === 'user'` is a human turn.\n * - the model-visible surface deliberately shadows compacted ranges, so a\n * human transcript projects append-origin events only.\n * - a forked log carries its parent's history as an inherited seed prefix;\n * counting it in the child would bill the same tokens once per descendant.\n */\nimport { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n ImagePart,\n Message,\n MessagePart,\n MessageTokens,\n SessionStats,\n ToolPart,\n} from \"../types/index.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { normalizeTitleText } from \"../utils/title-fallback.js\";\nimport { DshSessionLogError, type DshEvent, type DshSessionHeader } from \"./dsh-session-log.js\";\nimport { TranscriptBuilder } from \"./transcript-builder.js\";\n\nconst AGENT_NAME = \"dsh\";\n\n/** DSH's version-one attachment path accepts exactly these raster formats. */\nconst IMAGE_MEDIA_TYPES: ReadonlySet<string> = new Set([\n \"image/png\",\n \"image/jpeg\",\n \"image/webp\",\n \"image/gif\",\n]);\n\nconst ATTACHMENT_ID_PATTERN = /^sha256:([a-f0-9]{64})$/;\n\nconst IMAGE_UNAVAILABLE_TEXT = \"Image attachment unavailable\";\n\nexport interface DshProjection {\n messages: Message[];\n stats: SessionStats;\n modelUsage: Record<string, number>;\n title: string | null;\n updatedAt: number;\n}\n\ninterface UsageTotals {\n input: number;\n /** Raw DSH output tokens; reasoning is already included in it. */\n output: number;\n cacheRead: number;\n cacheCreate: number;\n cost: number;\n}\n\n/** Streaming state for one `(turn, step)` that has no settled message yet. */\ninterface PendingStep {\n turn: number;\n step: number;\n firstTime: number;\n lastTime: number;\n blocks: Map<number, PendingBlock>;\n usage: DshTokenUsage | null;\n}\n\ntype PendingBlock =\n | { type: \"text\" | \"reasoning\"; text: string }\n | { type: \"tool-call\"; id: string; name: string; args: string };\n\ninterface DshTokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}\n\ninterface ProjectionContext {\n sessionId: string;\n sourcePath: string;\n attachmentsRoot: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction asText(value: unknown): string {\n return typeof value === \"string\" ? value : \"\";\n}\n\nfunction corrupt(context: ProjectionContext, reason: string): never {\n throw new DshSessionLogError(\n `corrupt DSH session log ${JSON.stringify(context.sourcePath)}: ${reason}`,\n );\n}\n\nfunction warn(context: ProjectionContext, event: string, detail: Record<string, unknown>): void {\n getCoreDiagnostics()?.warn(event, {\n agent: AGENT_NAME,\n session_id: context.sessionId,\n ...detail,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Surface placement\n// ---------------------------------------------------------------------------\n\nconst SURFACE_EVENT_TYPES: ReadonlySet<string> = new Set([\n \"user/message\",\n \"assistant/message\",\n \"tool/result\",\n]);\n\n/**\n * Classify how a surface-eligible event entered the model-visible surface.\n * Only `append` belongs in a human transcript: a replacement is a compaction\n * copy that shadows conversation the user already saw.\n */\nfunction isAppendOrigin(event: DshEvent, context: ProjectionContext): boolean {\n if (!SURFACE_EVENT_TYPES.has(event.type)) return false;\n const op = event.surfaceOp;\n if (op === \"append\") return true;\n if (op === undefined) {\n corrupt(\n context,\n `surface event ${JSON.stringify(event.type)} at seq ${event.seq} has no surfaceOp`,\n );\n }\n const replace = asRecord(op);\n if (\n replace[\"op\"] !== \"replace\" ||\n !Number.isSafeInteger(replace[\"start\"]) ||\n !Number.isSafeInteger(replace[\"end\"])\n ) {\n corrupt(\n context,\n `surface event ${JSON.stringify(event.type)} at seq ${event.seq} has an invalid surfaceOp`,\n );\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Content blocks\n// ---------------------------------------------------------------------------\n\n/**\n * Load a content-addressed image and prove the bytes still match the durable\n * reference. The attachment id is matched against a strict `sha256:<hex>`\n * pattern and used only to derive the object path — never joined as a path.\n */\nfunction readImageBlock(\n block: Record<string, unknown>,\n timeMs: number,\n context: ProjectionContext,\n): ImagePart | null {\n const attachment = asRecord(block[\"attachment\"]);\n const attachmentId = asText(attachment[\"attachmentId\"]);\n const mediaType = asText(attachment[\"mediaType\"]);\n const digest = ATTACHMENT_ID_PATTERN.exec(attachmentId)?.[1];\n\n const reject = (reason: string): null => {\n warn(context, \"dsh.attachment_unreadable\", { attachment_id: attachmentId, reason });\n return null;\n };\n\n if (!digest) return reject(\"invalid attachment reference\");\n if (!IMAGE_MEDIA_TYPES.has(mediaType)) return reject(\"unsupported media type\");\n\n let data: Buffer;\n try {\n data = readFileSync(join(context.attachmentsRoot, \"objects\", digest.slice(0, 2), digest));\n } catch {\n return reject(\"attachment object is missing\");\n }\n const declaredBytes = attachment[\"bytes\"];\n if (typeof declaredBytes === \"number\" && data.byteLength !== declaredBytes) {\n return reject(\"attachment byte length does not match its reference\");\n }\n if (createHash(\"sha256\").update(data).digest(\"hex\") !== digest) {\n return reject(\"attachment failed integrity verification\");\n }\n\n return {\n type: \"image\",\n data: data.toString(\"base64\"),\n mime_type: mediaType,\n time_created: timeMs,\n };\n}\n\n/**\n * Convert DSH content blocks into CodeSesh parts. `tool-call` blocks are\n * skipped when a canonical `tool/call` event carries the same call: the two\n * describe one invocation and rendering both would duplicate the tool card.\n */\nfunction convertContentBlocks(\n content: unknown,\n timeMs: number,\n context: ProjectionContext,\n canonicalCallIds: ReadonlySet<string>,\n): MessagePart[] {\n if (!Array.isArray(content)) return [];\n const parts: MessagePart[] = [];\n let droppedImages = 0;\n\n for (const raw of content) {\n const block = asRecord(raw);\n switch (block[\"type\"]) {\n case \"text\":\n case \"reasoning\": {\n const text = cleanInternalText(asText(block[\"text\"]));\n if (text) parts.push({ type: block[\"type\"], text, time_created: timeMs });\n break;\n }\n case \"image\": {\n const image = readImageBlock(block, timeMs, context);\n if (image) parts.push(image);\n else droppedImages += 1;\n break;\n }\n case \"tool-call\": {\n const callId = asText(block[\"id\"]);\n if (callId && canonicalCallIds.has(callId)) break;\n parts.push(buildToolPart(callId, asText(block[\"name\"]), block[\"arguments\"], timeMs));\n break;\n }\n default:\n break;\n }\n }\n\n // A message whose only content was an unreadable image must keep its place\n // in the timeline rather than vanish from the conversation.\n if (parts.length === 0 && droppedImages > 0) {\n parts.push({ type: \"text\", text: IMAGE_UNAVAILABLE_TEXT, time_created: timeMs });\n }\n return parts;\n}\n\n/** Raw arguments stay verbatim when unparsable so an interrupted call is still diagnosable. */\nfunction parseToolArguments(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw ?? {};\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\nfunction buildToolPart(\n callId: string,\n name: string,\n rawArguments: unknown,\n timeMs: number,\n): ToolPart {\n const tool = name.trim() || \"tool\";\n return {\n type: \"tool\",\n tool,\n title: tool.toLowerCase(),\n callID: callId || undefined,\n time_created: timeMs,\n state: { status: \"running\", input: parseToolArguments(rawArguments) },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Token accounting\n// ---------------------------------------------------------------------------\n\nfunction nonNegative(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : 0;\n}\n\nfunction readUsage(value: unknown): DshTokenUsage | null {\n if (!isRecord(value)) return null;\n return {\n inputTokens: nonNegative(value[\"inputTokens\"]),\n outputTokens: nonNegative(value[\"outputTokens\"]),\n cacheReadTokens: nonNegative(value[\"cacheReadTokens\"]),\n cacheWriteTokens: nonNegative(value[\"cacheWriteTokens\"]),\n reasoningTokens: nonNegative(value[\"reasoningTokens\"]),\n };\n}\n\n/**\n * DSH input buckets are disjoint (`inputTokens` is uncached input, cache reads\n * and writes are separate) and reasoning is already inside `outputTokens`.\n * CodeSesh prices a total input and a visible output separately, so the buckets\n * are folded in and reasoning is split out — counting either twice would\n * inflate both the token totals and the estimated cost.\n */\nfunction toMessageTokens(usage: DshTokenUsage): { tokens: MessageTokens; totals: UsageTotals } {\n const cacheRead = nonNegative(usage.cacheReadTokens);\n const cacheCreate = nonNegative(usage.cacheWriteTokens);\n const totalInput = nonNegative(usage.inputTokens) + cacheRead + cacheCreate;\n const output = nonNegative(usage.outputTokens);\n const reasoning = Math.min(nonNegative(usage.reasoningTokens), output);\n\n return {\n tokens: {\n input: totalInput,\n output: output - reasoning,\n reasoning: reasoning || undefined,\n cache_read: cacheRead || undefined,\n cache_create: cacheCreate || undefined,\n },\n totals: { input: totalInput, output, cacheRead, cacheCreate, cost: 0 },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Projection\n// ---------------------------------------------------------------------------\n\nclass DshProjector {\n private readonly builder = new TranscriptBuilder({ messageDefaults: \"sparse\" });\n private readonly totals: UsageTotals = {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheCreate: 0,\n cost: 0,\n };\n private readonly modelUsage: Record<string, number> = {};\n private readonly settledSteps = new Set<string>();\n private pending: PendingStep | null = null;\n private provider: string | null = null;\n private model: string | null = null;\n private ownTitle: string | null = null;\n private inheritedTitle: string | null = null;\n private subagentLabel: string | null = null;\n private firstHumanText: string | null = null;\n private updatedAt = 0;\n\n constructor(\n private readonly context: ProjectionContext,\n private readonly seedLength: number,\n private readonly canonicalCallIds: ReadonlySet<string>,\n ) {}\n\n project(events: readonly DshEvent[]): DshProjection {\n for (const event of events) {\n const own = event.seq >= this.seedLength;\n if (own) this.updatedAt = Math.max(this.updatedAt, event.time);\n this.consume(event, own);\n }\n this.flushPendingStep();\n\n const result = this.builder.finish({\n message_count: 0,\n total_input_tokens: this.totals.input,\n total_output_tokens: this.totals.output,\n total_cache_read_tokens: this.totals.cacheRead || undefined,\n total_cache_create_tokens: this.totals.cacheCreate || undefined,\n total_cost: this.totals.cost,\n cost_source: this.totals.cost > 0 ? \"estimated\" : undefined,\n });\n\n return {\n messages: result.messages,\n stats: result.stats,\n modelUsage: this.modelUsage,\n title: this.resolveTitle(),\n updatedAt: this.updatedAt,\n };\n }\n\n private consume(event: DshEvent, own: boolean): void {\n switch (event.type) {\n case \"user/message\":\n this.consumeUserMessage(event, own);\n return;\n case \"assistant/message\":\n this.consumeAssistantMessage(event, own);\n return;\n case \"tool/call\":\n if (own) this.consumeToolCall(event);\n return;\n case \"tool/result\":\n if (isAppendOrigin(event, this.context) && own) this.consumeToolResult(event);\n return;\n case \"assistant/chunk\":\n if (own) this.consumeChunk(event);\n return;\n case \"request/context\":\n this.consumeRequestContext(event);\n return;\n case \"session/title\":\n this.consumeTitle(event, own);\n return;\n case \"subagent/descriptor\":\n if (own) this.consumeSubagentDescriptor(event);\n return;\n default:\n return;\n }\n }\n\n private consumeUserMessage(event: DshEvent, own: boolean): void {\n // Every user/message is validated for surface placement, but injected\n // context and compaction replacements never become human turns.\n const appendOrigin = isAppendOrigin(event, this.context);\n const data = asRecord(event.data);\n if (!appendOrigin || !own || asRecord(data[\"source\"])[\"kind\"] !== \"user\") return;\n\n const parts = convertContentBlocks(\n data[\"content\"],\n event.time,\n this.context,\n this.canonicalCallIds,\n );\n if (parts.length === 0) return;\n this.builder.appendMessage({\n id: asText(data[\"id\"]) || `dsh-user-${event.seq}`,\n role: \"user\",\n timestampMs: event.time,\n parts,\n });\n // Read the title candidate from the source blocks, so an unreadable-image\n // placeholder never becomes the session's name.\n this.firstHumanText ??= firstTextBlock(data[\"content\"]);\n }\n\n private consumeAssistantMessage(event: DshEvent, own: boolean): void {\n const appendOrigin = isAppendOrigin(event, this.context);\n const data = asRecord(event.data);\n const turn = data[\"turn\"];\n const step = data[\"step\"];\n if (typeof turn === \"number\" && typeof step === \"number\") {\n this.settleStep(turn, step);\n }\n if (!appendOrigin || !own) return;\n\n const message = asRecord(data[\"message\"]);\n const source = asRecord(message[\"source\"]);\n const provider = asText(source[\"provider\"]) || null;\n const model = asText(source[\"model\"]) || null;\n if (provider) this.provider = provider;\n if (model) this.model = model;\n\n const parts = convertContentBlocks(\n message[\"content\"],\n event.time,\n this.context,\n this.canonicalCallIds,\n );\n const usage = readUsage(data[\"usage\"]);\n this.appendAssistant({\n id: asText(message[\"id\"]) || `dsh-assistant-${event.seq}`,\n timeMs: event.time,\n parts,\n provider,\n model,\n usage,\n });\n }\n\n private consumeToolCall(event: DshEvent): void {\n const data = asRecord(event.data);\n const callId = asText(data[\"callId\"]);\n const part = buildToolPart(callId, asText(data[\"name\"]), data[\"arguments\"], event.time);\n this.builder.appendToolCall(\n part,\n { id: callId, timestampMs: event.time, agent: AGENT_NAME },\n { target: \"current\" },\n );\n }\n\n private consumeToolResult(event: DshEvent): void {\n const data = asRecord(event.data);\n const message = asRecord(data[\"message\"]);\n const source = asRecord(message[\"source\"]);\n if (source[\"kind\"] !== \"tool\") {\n corrupt(this.context, `tool/result at seq ${event.seq} is not sourced from a tool call`);\n }\n const callId = asText(source[\"callId\"]);\n const content = Array.isArray(message[\"content\"]) ? message[\"content\"] : [];\n const block = asRecord(content[0]);\n if (content.length !== 1 || block[\"type\"] !== \"tool-result\") {\n corrupt(\n this.context,\n `tool/result at seq ${event.seq} must carry exactly one tool-result block`,\n );\n }\n if (asText(block[\"toolCallId\"]) !== callId) {\n corrupt(this.context, `tool/result at seq ${event.seq} disagrees with its call identity`);\n }\n\n const failed = block[\"isError\"] === true || isRecord(data[\"error\"]);\n const resolved = this.builder.resolveToolCall(callId, {\n output: convertContentBlocks(\n block[\"content\"],\n event.time,\n this.context,\n this.canonicalCallIds,\n ),\n status: failed ? \"error\" : \"completed\",\n metadata: data[\"meta\"],\n consume: true,\n });\n if (!resolved) {\n warn(this.context, \"dsh.orphan_tool_result\", { call_id: callId, seq: event.seq });\n }\n }\n\n private consumeChunk(event: DshEvent): void {\n const data = asRecord(event.data);\n const turn = data[\"turn\"];\n const step = data[\"step\"];\n if (typeof turn !== \"number\" || typeof step !== \"number\") return;\n if (this.settledSteps.has(stepKey(turn, step))) return;\n\n const pending = this.openStep(turn, step, event.time);\n pending.lastTime = event.time;\n applyChunk(pending, asRecord(data[\"chunk\"]));\n }\n\n private consumeRequestContext(event: DshEvent): void {\n const data = asRecord(event.data);\n const provider = asText(data[\"provider\"]);\n const model = asText(data[\"model\"]);\n if (provider) this.provider = provider;\n if (model) this.model = model;\n }\n\n private consumeTitle(event: DshEvent, own: boolean): void {\n const title = normalizeTitleText(asText(asRecord(event.data)[\"title\"]));\n if (!title) return;\n if (own) this.ownTitle = title;\n else this.inheritedTitle = title;\n }\n\n private consumeSubagentDescriptor(event: DshEvent): void {\n const label = normalizeTitleText(asText(asRecord(event.data)[\"label\"]));\n if (label) this.subagentLabel ??= label;\n }\n\n /** A settled message supersedes the streaming deltas of the same step. */\n private settleStep(turn: number, step: number): void {\n this.settledSteps.add(stepKey(turn, step));\n if (this.pending?.turn === turn && this.pending.step === step) this.pending = null;\n }\n\n private openStep(turn: number, step: number, timeMs: number): PendingStep {\n if (this.pending && (this.pending.turn !== turn || this.pending.step !== step)) {\n this.flushPendingStep();\n }\n this.pending ??= {\n turn,\n step,\n firstTime: timeMs,\n lastTime: timeMs,\n blocks: new Map(),\n usage: null,\n };\n return this.pending;\n }\n\n /** Rebuild the assistant message of a step the log was cut short in. */\n private flushPendingStep(): void {\n const pending = this.pending;\n this.pending = null;\n if (!pending) return;\n\n const parts: MessagePart[] = [];\n for (const index of [...pending.blocks.keys()].sort((a, b) => a - b)) {\n const block = pending.blocks.get(index) as PendingBlock;\n if (block.type === \"tool-call\") {\n if (this.canonicalCallIds.has(block.id)) continue;\n parts.push(buildToolPart(block.id, block.name, block.args, pending.lastTime));\n continue;\n }\n const text = cleanInternalText(block.text);\n if (text) parts.push({ type: block.type, text, time_created: pending.firstTime });\n }\n if (parts.length === 0) return;\n\n this.appendAssistant({\n id: `dsh-step-${pending.turn}-${pending.step}`,\n timeMs: pending.firstTime,\n parts,\n provider: this.provider,\n model: this.model,\n usage: pending.usage,\n });\n }\n\n private appendAssistant(input: {\n id: string;\n timeMs: number;\n parts: MessagePart[];\n provider: string | null;\n model: string | null;\n usage: DshTokenUsage | null;\n }): void {\n const mapped = input.usage ? toMessageTokens(input.usage) : null;\n const cost = mapped ? (estimateTokenCost(input.model, mapped.tokens) ?? 0) : 0;\n\n if (mapped) {\n this.totals.input += mapped.totals.input;\n this.totals.output += mapped.totals.output;\n this.totals.cacheRead += mapped.totals.cacheRead;\n this.totals.cacheCreate += mapped.totals.cacheCreate;\n this.totals.cost += cost;\n if (input.model) {\n const billed = mapped.totals.input + mapped.totals.output;\n this.modelUsage[input.model] = (this.modelUsage[input.model] ?? 0) + billed;\n }\n }\n\n // An empty-content assistant/message exists only to host a step's usage;\n // its tokens are real spend even though it shows nothing.\n if (input.parts.length === 0) return;\n\n this.builder.appendMessage({\n id: input.id,\n role: \"assistant\",\n agent: AGENT_NAME,\n timestampMs: input.timeMs,\n parts: input.parts,\n provider: input.provider,\n model: input.model,\n tokens: mapped?.tokens,\n cost: cost || undefined,\n costSource: cost > 0 ? \"estimated\" : undefined,\n });\n }\n\n private resolveTitle(): string | null {\n return this.ownTitle ?? this.subagentLabel ?? this.firstHumanText ?? this.inheritedTitle;\n }\n}\n\nfunction stepKey(turn: number, step: number): string {\n return `${turn}:${step}`;\n}\n\nfunction firstTextBlock(content: unknown): string | null {\n if (!Array.isArray(content)) return null;\n for (const raw of content) {\n const block = asRecord(raw);\n if (block[\"type\"] !== \"text\") continue;\n const text = cleanInternalText(asText(block[\"text\"]));\n if (text) return text;\n }\n return null;\n}\n\n/** Fold one stream chunk into the pending step's per-block accumulators. */\nfunction applyChunk(pending: PendingStep, chunk: Record<string, unknown>): void {\n const index = chunk[\"index\"];\n if (typeof index !== \"number\") {\n if (chunk[\"type\"] === \"usage\") pending.usage = readUsage(chunk[\"usage\"]);\n return;\n }\n\n switch (chunk[\"type\"]) {\n case \"text-delta\":\n case \"reasoning-delta\": {\n const type = chunk[\"type\"] === \"text-delta\" ? \"text\" : \"reasoning\";\n const current = pending.blocks.get(index);\n const text = current && current.type === type ? current.text : \"\";\n pending.blocks.set(index, { type, text: text + asText(chunk[\"text\"]) });\n return;\n }\n case \"tool-call-delta\": {\n const current = pending.blocks.get(index);\n const args = current && current.type === \"tool-call\" ? current.args : \"\";\n const name = current && current.type === \"tool-call\" ? current.name : \"\";\n pending.blocks.set(index, {\n type: \"tool-call\",\n id: asText(chunk[\"id\"]),\n name: asText(chunk[\"name\"]) || name,\n args: args + asText(chunk[\"argumentsDelta\"]),\n });\n return;\n }\n case \"block-end\": {\n // The assembled block is authoritative over the deltas that built it.\n const block = asRecord(chunk[\"block\"]);\n if (block[\"type\"] === \"text\" || block[\"type\"] === \"reasoning\") {\n pending.blocks.set(index, { type: block[\"type\"], text: asText(block[\"text\"]) });\n } else if (block[\"type\"] === \"tool-call\") {\n pending.blocks.set(index, {\n type: \"tool-call\",\n id: asText(block[\"id\"]),\n name: asText(block[\"name\"]),\n args: asText(block[\"arguments\"]),\n });\n }\n return;\n }\n default:\n return;\n }\n}\n\n/**\n * Collect the canonical call ids so an assistant message's `tool-call` blocks\n * can defer to them. A duplicate id is source corruption: two invocations\n * sharing an id make every result ambiguous.\n */\nfunction collectCanonicalCallIds(\n events: readonly DshEvent[],\n context: ProjectionContext,\n): ReadonlySet<string> {\n const ids = new Set<string>();\n for (const event of events) {\n if (event.type !== \"tool/call\") continue;\n const callId = asText(asRecord(event.data)[\"callId\"]);\n if (!callId) corrupt(context, `tool/call at seq ${event.seq} has no call id`);\n if (ids.has(callId)) corrupt(context, `duplicate tool call id ${JSON.stringify(callId)}`);\n ids.add(callId);\n }\n return ids;\n}\n\n/**\n * Project a DSH log onto CodeSesh messages, stats and title.\n *\n * `updatedAt` and every token total cover the session's own suffix only; the\n * inherited seed prefix still validates, but belongs to the parent.\n */\nexport function projectDshSession(options: {\n header: DshSessionHeader;\n events: readonly DshEvent[];\n sourcePath: string;\n attachmentsRoot: string;\n}): DshProjection {\n const context: ProjectionContext = {\n sessionId: options.header.id,\n sourcePath: options.sourcePath,\n attachmentsRoot: options.attachmentsRoot,\n };\n const projector = new DshProjector(\n context,\n options.header.seedLength ?? 0,\n collectCanonicalCallIds(options.events, context),\n );\n const projection = projector.project(options.events);\n return {\n ...projection,\n updatedAt: projection.updatedAt || options.header.createdAt,\n };\n}\n","import { registerAgent } from \"./registry.js\";\nimport { ClaudeCodeAgent, resolveClaudeCodeDataRoot } from \"./claudecode.js\";\nimport { OpenCodeAgent, resolveOpenCodeDataRoot } from \"./opencode.js\";\nimport { KimiAgent, resolveKimiDataRoot } from \"./kimi.js\";\nimport { KimiCodeAgent, resolveKimiCodeDataRoot } from \"./kimi-code.js\";\nimport { CodexAgent, resolveCodexDataRoot } from \"./codex.js\";\nimport { CursorAgent, resolveCursorDataRoot } from \"./cursor.js\";\nimport { PiAgent, resolvePiDataRoot } from \"./pi.js\";\nimport { ZCodeAgent, resolveZCodeDataRoot } from \"./zcode.js\";\nimport { GrokAgent, resolveGrokDataRoot } from \"./grok.js\";\nimport { DshAgent, resolveDshDataRoot } from \"./dsh.js\";\n\nregisterAgent({\n icon: \"/icon/agent/claudecode.svg\",\n iconColored: true,\n resolveDataRoot: resolveClaudeCodeDataRoot,\n resumeCommandPrefix: \"claude --resume\",\n toolStrategy: \"custom\",\n create: () => new ClaudeCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/opencode.svg\",\n resolveDataRoot: resolveOpenCodeDataRoot,\n resumeCommandPrefix: \"opencode -s\",\n toolStrategy: \"custom\",\n create: () => new OpenCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/zcode.svg\",\n resolveDataRoot: resolveZCodeDataRoot,\n resumeCommandPrefix: null,\n toolStrategy: \"custom\",\n create: () => new ZCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/kimi.svg\",\n resolveDataRoot: resolveKimiDataRoot,\n resumeCommandPrefix: \"kimi -r\",\n toolStrategy: \"custom\",\n create: () => new KimiAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/kimi.svg\",\n resolveDataRoot: resolveKimiCodeDataRoot,\n resumeCommandPrefix: \"kimi -r\",\n toolStrategy: \"custom\",\n create: () => new KimiCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/codex.svg\",\n resolveDataRoot: resolveCodexDataRoot,\n resumeCommandPrefix: \"codex resume\",\n toolStrategy: \"custom\",\n create: () => new CodexAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/grok.svg\",\n resolveDataRoot: resolveGrokDataRoot,\n resumeCommandPrefix: \"grok --resume\",\n toolStrategy: \"custom\",\n create: () => new GrokAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/pi.svg\",\n resolveDataRoot: resolvePiDataRoot,\n resumeCommandPrefix: \"pi --session\",\n toolStrategy: \"custom\",\n create: () => new PiAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/dsh.svg\",\n iconColored: true,\n resolveDataRoot: resolveDshDataRoot,\n // The DSH launcher hands inner arguments to a profile, so no single resume\n // command holds across installations.\n resumeCommandPrefix: null,\n toolStrategy: \"custom\",\n create: () => new DshAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/cursor.svg\",\n resolveDataRoot: resolveCursorDataRoot,\n resumeCommandPrefix: null,\n toolStrategy: \"custom\",\n create: () => new CursorAgent(),\n});\n","export const CACHE_SCHEMA_VERSION = 29;\n","import type { ReferencedSessionHead } from \"./session.js\";\nimport type { SessionReference } from \"./session-reference.js\";\n\nexport interface SessionsUpdatedEvent {\n type: \"sessions-updated\";\n changedAgents: string[];\n newSessions: number;\n /** Exact new-session subset for consumers that project the global event into a local view. */\n newSessionRefs?: SessionReference[];\n updatedSessions: number;\n removedSessions: number;\n totalSessions: number;\n timestamp: number;\n changedSessionHeads: ReferencedSessionHead[];\n /** Unchanged hierarchy context; it must not count as an update or invalidate session detail. */\n projectionRelatedSessionHeads?: ReferencedSessionHead[];\n /** Canonical global order for affected activity-time ties. */\n projectionSessionOrder?: SessionReference[];\n removedSessionRefs: SessionReference[];\n}\n\nexport function mergeSessionsUpdatedEvents(\n previous: SessionsUpdatedEvent,\n next: SessionsUpdatedEvent,\n): SessionsUpdatedEvent {\n const changedSessionHeads = new Map<string, ReferencedSessionHead>();\n const projectionRelatedSessionHeads = new Map<string, ReferencedSessionHead>();\n const projectionSessionOrder = new Map<string, SessionReference>();\n const newSessionRefs = new Map<string, SessionReference>();\n const removedSessionRefs = new Map<string, SessionReference>();\n const sessionKey = (agentName: string, sessionId: string) => `${agentName}\\0${sessionId}`;\n const addChanged = (item: ReferencedSessionHead) => {\n const key = sessionKey(item.reference.agentName, item.reference.sessionId);\n removedSessionRefs.delete(key);\n projectionRelatedSessionHeads.delete(key);\n changedSessionHeads.set(key, item);\n };\n const addProjectionRelated = (item: ReferencedSessionHead) => {\n const key = sessionKey(item.reference.agentName, item.reference.sessionId);\n if (changedSessionHeads.has(key) || removedSessionRefs.has(key)) return;\n projectionRelatedSessionHeads.set(key, item);\n };\n const addNew = (item: SessionReference) => {\n const key = sessionKey(item.agentName, item.sessionId);\n removedSessionRefs.delete(key);\n newSessionRefs.set(key, item);\n };\n const addProjectionOrder = (item: SessionReference) => {\n const key = sessionKey(item.agentName, item.sessionId);\n projectionSessionOrder.delete(key);\n projectionSessionOrder.set(key, item);\n };\n const addRemoved = (item: SessionReference) => {\n const key = sessionKey(item.agentName, item.sessionId);\n changedSessionHeads.delete(key);\n projectionRelatedSessionHeads.delete(key);\n projectionSessionOrder.delete(key);\n newSessionRefs.delete(key);\n removedSessionRefs.set(key, item);\n };\n\n for (const item of previous.newSessionRefs ?? []) addNew(item);\n for (const item of previous.projectionRelatedSessionHeads ?? []) addProjectionRelated(item);\n for (const item of previous.projectionSessionOrder ?? []) addProjectionOrder(item);\n for (const item of previous.changedSessionHeads) addChanged(item);\n for (const item of previous.removedSessionRefs) addRemoved(item);\n for (const item of next.newSessionRefs ?? []) addNew(item);\n for (const item of next.projectionRelatedSessionHeads ?? []) addProjectionRelated(item);\n for (const item of next.projectionSessionOrder ?? []) addProjectionOrder(item);\n for (const item of next.changedSessionHeads) addChanged(item);\n for (const item of next.removedSessionRefs) addRemoved(item);\n\n return {\n type: \"sessions-updated\",\n changedAgents: Array.from(new Set([...previous.changedAgents, ...next.changedAgents])),\n newSessions: previous.newSessions + next.newSessions,\n newSessionRefs: [...newSessionRefs.values()],\n updatedSessions: previous.updatedSessions + next.updatedSessions,\n removedSessions: previous.removedSessions + next.removedSessions,\n totalSessions: next.totalSessions,\n timestamp: next.timestamp,\n changedSessionHeads: [...changedSessionHeads.values()],\n projectionRelatedSessionHeads: [...projectionRelatedSessionHeads.values()],\n projectionSessionOrder: [...projectionSessionOrder.values()],\n removedSessionRefs: [...removedSessionRefs.values()],\n };\n}\n\nexport interface AgentScanStatus {\n agentName: string;\n status:\n | \"pending\"\n | \"scanning\"\n | \"finalizing\"\n | \"publish-queued\"\n | \"publishing\"\n | \"indexing\"\n | \"complete\"\n | \"failed\";\n completeness?: ScanCompletion[\"completeness\"];\n sourceFailureCount?: number;\n sourceFailureSummary?: string;\n error?: string;\n total?: number;\n processed?: number;\n sessions?: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n}\n\n/** Snapshot completeness is independent from whether the operation completed. */\nexport interface ScanCompletion {\n completeness: \"complete\" | \"partial\";\n sourceFailureCount?: number;\n sourceFailureSummary?: string;\n}\n\n/**\n * Full-history reconciliation runs independently of the main scan phase:\n * startup only syncs the display window, so a low-priority background pass\n * (capped at one agent at a time) periodically re-checks the rest of history.\n */\nexport interface BackfillProgress {\n phase?: \"scanning\" | \"finalizing\" | \"publish-queued\" | \"publishing\" | \"indexing\";\n total?: number;\n processed?: number;\n sessions?: number;\n}\n\nexport interface BackfillStatus {\n active: boolean;\n pendingAgents: string[];\n currentAgent?: string;\n progress?: BackfillProgress;\n completedAgents: string[];\n failedAgents: string[];\n partialAgents?: Record<string, ScanCompletion>;\n}\n\nexport interface SearchIndexMaintenanceStatus {\n active: boolean;\n pendingAgents: string[];\n currentAgent?: string;\n remaining?: number;\n completedAgents: string[];\n failedAgents: string[];\n}\n\nexport interface ScanStatusEvent {\n type: \"scan-status\";\n active: boolean;\n phase: \"idle\" | \"publishing\" | \"indexing\" | \"initializing\" | \"scanning\";\n pendingAgents: string[];\n scanningAgents: string[];\n completedAgents: string[];\n agentStatuses: Record<string, AgentScanStatus>;\n totalAgents: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n backfill: BackfillStatus;\n searchIndexMaintenance?: SearchIndexMaintenanceStatus;\n}\n","/**\n * Local calendar days, the unit the dashboard and its time windows are defined\n * in. A calendar day is not a fixed duration: across a DST transition adjacent\n * local midnights are 23 or 25 hours apart, so stepping by a constant number of\n * milliseconds skips or repeats a day. Every helper here advances date fields\n * instead.\n */\n\n/** Local midnight of the calendar day containing `timestamp`. */\nexport function startOfCalendarDay(timestamp: number): number {\n const date = new Date(timestamp);\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n}\n\n/** Local midnight `days` calendar days from the day containing `timestamp`. */\nexport function addCalendarDays(timestamp: number, days: number): number {\n const date = new Date(timestamp);\n return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days).getTime();\n}\n\n/** Days since the epoch for a local calendar date, counted on a fixed-length UTC grid. */\nfunction toCalendarDayNumber(timestamp: number): number {\n const date = new Date(timestamp);\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / 86_400_000;\n}\n\n/** Calendar days in the inclusive local range, at least 1. */\nexport function countCalendarDays(from: number, to: number): number {\n return Math.max(1, toCalendarDayNumber(to) - toCalendarDayNumber(from) + 1);\n}\n\n/** `YYYY-MM-DD` key for the local calendar day; the dashboard wire format. */\nexport function toCalendarDayKey(timestamp: number): string {\n const date = new Date(timestamp);\n return `${String(date.getFullYear()).padStart(4, \"0\")}-${String(date.getMonth() + 1).padStart(\n 2,\n \"0\",\n )}-${String(date.getDate()).padStart(2, \"0\")}`;\n}\n","/**\n * What a project identity is, independent of how it is discovered or displayed.\n *\n * The same facts used to be restated in five places: the kind union here, a kind\n * Set and `kind:key` encoding in the Node resolver, another `getProjectIdentityKey`\n * in the session index, a private group key in analytics, and a third copy in the\n * web adapter. Adding a kind meant editing all of them, and nothing failed if one\n * was missed.\n *\n * This module owns the closed set, the identity key, and identity comparison.\n * Discovering identities from the filesystem lives in `projects/identity.ts`;\n * encoding them into URLs lives in the web adapter. Both sit outside this one.\n */\n\n/**\n * Every kind of project identity, most specific first. The order is documentation,\n * not behavior. These values appear in SQLite rows and API responses, so they\n * cannot be renamed without a migration.\n */\nexport const PROJECT_IDENTITY_KINDS = [\n \"git_remote\",\n \"git_common_dir\",\n \"manifest_path\",\n \"synthetic\",\n \"path\",\n \"loose\",\n] as const;\n\nexport type ProjectIdentityKind = (typeof PROJECT_IDENTITY_KINDS)[number];\n\nexport interface ProjectIdentityRef {\n kind: ProjectIdentityKind;\n key: string;\n}\n\nconst KIND_LOOKUP = new Set<string>(PROJECT_IDENTITY_KINDS);\n\nexport function isProjectIdentityKind(value: string): value is ProjectIdentityKind {\n return KIND_LOOKUP.has(value);\n}\n\n/**\n * Stable key for grouping and lookup. This is not a URL: route encoding is a\n * separate adapter, and conflating the two would put an escaped key in storage.\n */\nexport function getProjectIdentityKey(identity: ProjectIdentityRef): string {\n return `${identity.kind}:${identity.key}`;\n}\n\nexport function matchesProjectIdentity(\n identity: ProjectIdentityRef | null | undefined,\n expected: ProjectIdentityRef,\n): boolean {\n return identity?.kind === expected.kind && identity.key === expected.key;\n}\n\n/** Key for one agent's slice of a project. */\nexport function getProjectAgentKey(projectIdentityKey: string, agentName: string): string {\n return `${projectIdentityKey}\\0${agentName.toLowerCase()}`;\n}\n","import type { ReferencedSessionHead, SessionHead } from \"./session.js\";\nimport { getProjectAgentKey, getProjectIdentityKey } from \"./project-identity.js\";\nimport {\n formatSessionReference,\n getSessionAgentKey,\n type SessionReference,\n} from \"./session-reference.js\";\n\nexport type SessionHeadChange = ReferencedSessionHead;\n\nexport type SessionHeadRemoval = SessionReference;\n\nexport interface CanonicalSessionIndex {\n sourceSessions: SessionHead[];\n sessionsByActivity: SessionHead[];\n byRouteKey: Map<string, SessionHead>;\n byAgent: Map<string, SessionHead[]>;\n byProjectIdentityKey: Map<string, SessionHead[]>;\n byProjectAgentKey: Map<string, SessionHead[]>;\n}\n\nexport function compareSessionActivityDesc(a: SessionHead, b: SessionHead): number {\n return (b.time_updated ?? b.time_created) - (a.time_updated ?? a.time_created);\n}\n\nexport function sortSessionsByActivity(sessions: SessionHead[]): SessionHead[] {\n for (let index = 1; index < sessions.length; index += 1) {\n if (compareSessionActivityDesc(sessions[index - 1]!, sessions[index]!) > 0) {\n return [...sessions].sort(compareSessionActivityDesc);\n }\n }\n return [...sessions];\n}\n\n/**\n * Merges shards that are each already sorted by activity, newest first.\n *\n * Callers must uphold that precondition — this does not re-sort. Ties resolve to\n * the earlier shard, which is what a stable `Array.sort` over the concatenation\n * would produce, so the result is element-for-element identical to\n * `sortSessionsByActivity(shards.flat())` at O(n·k) instead of O(n log n).\n */\nexport function mergeSortedSessions(shards: SessionHead[][]): SessionHead[] {\n const active = shards.filter((shard) => shard.length > 0);\n if (active.length === 0) return [];\n if (active.length === 1) return [...active[0]!];\n\n const total = active.reduce((sum, shard) => sum + shard.length, 0);\n const merged: SessionHead[] = [];\n const cursors = Array.from({ length: active.length }, () => 0);\n\n for (let position = 0; position < total; position += 1) {\n let pick = -1;\n for (let shard = 0; shard < active.length; shard += 1) {\n const cursor = cursors[shard]!;\n if (cursor >= active[shard]!.length) continue;\n if (\n pick === -1 ||\n compareSessionActivityDesc(active[shard]![cursor]!, active[pick]![cursors[pick]!]!) < 0\n ) {\n pick = shard;\n }\n }\n merged.push(active[pick]![cursors[pick]!]!);\n cursors[pick]! += 1;\n }\n\n return merged;\n}\n\nexport function getSessionRouteKey(agentName: string, sessionId: string): string {\n return formatSessionReference({ agentName, sessionId });\n}\n\nfunction pushMapValue<K, V>(map: Map<K, V[]>, key: K, value: V): void {\n const current = map.get(key);\n if (current) {\n current.push(value);\n } else {\n map.set(key, [value]);\n }\n}\n\nexport function createSessionIndex(sourceSessions: SessionHead[]): CanonicalSessionIndex {\n const byRouteKey = new Map<string, SessionHead>();\n const byAgent = new Map<string, SessionHead[]>();\n const byProjectIdentityKey = new Map<string, SessionHead[]>();\n const byProjectAgentKey = new Map<string, SessionHead[]>();\n\n for (const session of sourceSessions) {\n const agentName = getSessionAgentKey(session);\n const routeKey = getSessionRouteKey(agentName, session.id);\n if (!byRouteKey.has(routeKey)) byRouteKey.set(routeKey, session);\n }\n\n const sessionsByActivity = sortSessionsByActivity(sourceSessions);\n for (const session of sessionsByActivity) {\n const agentName = getSessionAgentKey(session);\n pushMapValue(byAgent, agentName, session);\n\n const identity = session.project_identity;\n if (!identity?.key) continue;\n\n const projectIdentityKey = getProjectIdentityKey(identity);\n pushMapValue(byProjectIdentityKey, projectIdentityKey, session);\n pushMapValue(byProjectAgentKey, getProjectAgentKey(projectIdentityKey, agentName), session);\n }\n\n return {\n sourceSessions,\n sessionsByActivity,\n byRouteKey,\n byAgent,\n byProjectIdentityKey,\n byProjectAgentKey,\n };\n}\n\nexport function applySessionChanges(\n sessions: SessionHead[],\n changes: SessionHeadChange[],\n removals: SessionHeadRemoval[],\n): SessionHead[] {\n const byRouteKey = new Map<string, SessionHead>();\n for (const session of sessions) {\n byRouteKey.set(getSessionRouteKey(getSessionAgentKey(session), session.id), session);\n }\n\n for (const removal of removals) {\n byRouteKey.delete(getSessionRouteKey(removal.agentName, removal.sessionId));\n }\n for (const change of changes) {\n byRouteKey.set(\n getSessionRouteKey(change.reference.agentName, change.reference.sessionId),\n change.session,\n );\n }\n\n return sortSessionsByActivity([...byRouteKey.values()]);\n}\n\nexport function updateSessionIndex(\n index: CanonicalSessionIndex,\n changes: SessionHeadChange[],\n removals: SessionHeadRemoval[],\n): CanonicalSessionIndex {\n return createSessionIndex(applySessionChanges(index.sourceSessions, changes, removals));\n}\n","/**\n * Parent/child structure over a session snapshot: mount classification,\n * inclusive stat rollups and calendar-day grouping. Everything here is a pure\n * derivation of `parent_reference` — the wire format carries no tree.\n */\nimport type { CostSource, ReferencedSessionHead, SessionHead } from \"./session.js\";\nimport { startOfCalendarDay, toCalendarDayKey } from \"./calendar-day.js\";\nimport {\n applySessionChanges,\n compareSessionActivityDesc,\n getSessionRouteKey,\n type SessionHeadChange,\n type SessionHeadRemoval,\n} from \"./session-index.js\";\nimport {\n formatSessionReference,\n getSessionAgentKey,\n type SessionReference,\n} from \"./session-reference.js\";\n\n/**\n * Where a session sits relative to its parent, with orphans distinguished\n * from mounted children.\n */\nexport type SessionMountState = \"root\" | \"mounted-child\" | \"orphan\";\n\nexport interface InclusiveSessionStats {\n messageCount: number;\n /** Raw `total_input_tokens`; cache reads/creates are part of it. */\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreateTokens: number;\n totalTokens: number;\n cost: number;\n /** Undefined while the subtree costs nothing; \"estimated\" wins over \"recorded\". */\n costSource?: CostSource;\n}\n\nexport interface SessionTreeNode {\n session: SessionHead;\n /** Direct children only, in the input array's order. */\n children: SessionTreeNode[];\n /** Total number of descendants at every depth. */\n descendantCount: number;\n /** stats rolled up over this node and every descendant. */\n inclusiveStats: InclusiveSessionStats;\n}\n\nexport interface SessionTree {\n /** Sessions with no parent_reference, in input order. */\n roots: SessionTreeNode[];\n /** Sessions whose parent is not present in the input (未挂载), in input order. */\n orphans: SessionTreeNode[];\n /** roots ∪ orphans, in input order — the set that owns the main axis. */\n entries: SessionTreeNode[];\n byRouteKey: Map<string, SessionTreeNode>;\n mountStateOf(session: SessionHead): SessionMountState;\n}\n\nexport interface SessionDayGroup {\n /** \"YYYY-MM-DD\" local calendar day. */\n dayKey: string;\n dayStart: number;\n nodes: SessionTreeNode[];\n mainCount: number;\n subCount: number;\n}\n\nfunction sessionKey(session: SessionHead): string {\n return getSessionRouteKey(getSessionAgentKey(session), session.id);\n}\n\nfunction parentKey(session: SessionHead): string | null {\n return session.parent_reference ? formatSessionReference(session.parent_reference) : null;\n}\n\nfunction activityTime(session: SessionHead): number {\n return session.time_updated ?? session.time_created;\n}\n\nfunction hasActivityInWindow(session: SessionHead, from?: number, to?: number): boolean {\n const activity = activityTime(session);\n return (from == null || activity >= from) && (to == null || activity <= to);\n}\n\nfunction ownStats(session: SessionHead): InclusiveSessionStats {\n const stats = session.stats;\n const cost = stats.total_cost ?? 0;\n return {\n messageCount: stats.message_count,\n inputTokens: stats.total_input_tokens,\n outputTokens: stats.total_output_tokens,\n cacheReadTokens: stats.total_cache_read_tokens ?? 0,\n cacheCreateTokens: stats.total_cache_create_tokens ?? 0,\n totalTokens: stats.total_tokens ?? stats.total_input_tokens + stats.total_output_tokens,\n cost,\n costSource: cost > 0 ? (stats.cost_source ?? \"recorded\") : undefined,\n };\n}\n\nfunction addStats(target: InclusiveSessionStats, source: InclusiveSessionStats): void {\n target.messageCount += source.messageCount;\n target.inputTokens += source.inputTokens;\n target.outputTokens += source.outputTokens;\n target.cacheReadTokens += source.cacheReadTokens;\n target.cacheCreateTokens += source.cacheCreateTokens;\n target.totalTokens += source.totalTokens;\n target.cost += source.cost;\n if (source.costSource === \"estimated\") target.costSource = \"estimated\";\n}\n\n/**\n * Post-order rollup of `descendantCount` and `inclusiveStats` over one entry.\n * Folds children into each node's own stats in place, which is sound because a\n * node hangs off exactly one entry and every entry is rolled up once.\n */\nfunction rollUpSubtree(entry: SessionTreeNode): void {\n const order: SessionTreeNode[] = [];\n const pending = [entry];\n while (pending.length > 0) {\n const node = pending.pop()!;\n order.push(node);\n for (const child of node.children) pending.push(child);\n }\n\n for (let index = order.length - 1; index >= 0; index -= 1) {\n const node = order[index]!;\n const stats = node.inclusiveStats;\n let descendants = 0;\n for (const child of node.children) {\n descendants += 1 + child.descendantCount;\n addStats(stats, child.inclusiveStats);\n }\n if (stats.cost > 0 && stats.costSource == null) stats.costSource = \"recorded\";\n node.descendantCount = descendants;\n }\n}\n\nexport function buildSessionTree(sessions: SessionHead[]): SessionTree {\n const byRouteKey = new Map<string, SessionTreeNode>();\n for (const session of sessions) {\n const key = sessionKey(session);\n if (byRouteKey.has(key)) continue;\n byRouteKey.set(key, {\n session,\n children: [],\n descendantCount: 0,\n inclusiveStats: ownStats(session),\n });\n }\n const nodes = [...byRouteKey.values()];\n\n // A session whose parent chain re-enters itself can never reach a root, so it\n // is mounted nowhere. Memoized so the walk stays linear over long chains.\n const chainTerminates = new Map<string, boolean>();\n function reachesRoot(startKey: string): boolean {\n const path: string[] = [];\n const onPath = new Set<string>();\n let key: string | null = startKey;\n let terminates = true;\n\n while (key != null) {\n const memo = chainTerminates.get(key);\n if (memo != null) {\n terminates = memo;\n break;\n }\n if (onPath.has(key)) {\n terminates = false;\n break;\n }\n onPath.add(key);\n path.push(key);\n const parent = parentKey(byRouteKey.get(key)!.session);\n key = parent != null && byRouteKey.has(parent) ? parent : null;\n }\n\n for (const visited of path) chainTerminates.set(visited, terminates);\n return terminates;\n }\n\n const mountStates = new Map<string, SessionMountState>();\n const roots: SessionTreeNode[] = [];\n const orphans: SessionTreeNode[] = [];\n const entries: SessionTreeNode[] = [];\n\n for (const node of nodes) {\n const key = sessionKey(node.session);\n const parent = parentKey(node.session);\n const state: SessionMountState =\n parent == null\n ? \"root\"\n : byRouteKey.has(parent) && reachesRoot(key)\n ? \"mounted-child\"\n : \"orphan\";\n\n mountStates.set(key, state);\n if (state === \"mounted-child\") {\n byRouteKey.get(parent!)!.children.push(node);\n continue;\n }\n (state === \"root\" ? roots : orphans).push(node);\n entries.push(node);\n }\n\n for (const entry of entries) rollUpSubtree(entry);\n\n return {\n roots,\n orphans,\n entries,\n byRouteKey,\n mountStateOf(session) {\n return mountStates.get(sessionKey(session)) ?? (session.parent_reference ? \"orphan\" : \"root\");\n },\n };\n}\n\n/**\n * Groups top-level nodes by the calendar day of their activity time,\n * newest day first, newest node first.\n */\nexport function groupSessionsByCalendarDay(nodes: SessionTreeNode[]): SessionDayGroup[] {\n const groups = new Map<string, SessionDayGroup>();\n\n for (const node of nodes) {\n const activity = activityTime(node.session);\n const dayKey = toCalendarDayKey(activity);\n let group = groups.get(dayKey);\n if (!group) {\n group = {\n dayKey,\n dayStart: startOfCalendarDay(activity),\n nodes: [],\n mainCount: 0,\n subCount: 0,\n };\n groups.set(dayKey, group);\n }\n group.nodes.push(node);\n }\n\n const days = [...groups.values()];\n for (const group of days) {\n group.nodes.sort((a, b) => compareSessionActivityDesc(a.session, b.session));\n group.mainCount = group.nodes.length;\n group.subCount = group.nodes.reduce((sum, node) => sum + node.descendantCount, 0);\n }\n return days.sort((a, b) => b.dayStart - a.dayStart);\n}\n\n/**\n * Filters main-axis sessions (roots and orphans) by activity and keeps every\n * mounted descendant of a match. The input order is preserved so callers keep\n * their existing sort behavior.\n */\nexport function filterSessionTreeByActivityWindow(\n sessions: SessionHead[],\n from?: number,\n to?: number,\n tree: SessionTree = buildSessionTree(sessions),\n): SessionHead[] {\n if (from == null && to == null) return sessions;\n\n const pending = filterSessionTreeEntriesByActivityWindow(tree, from, to);\n\n const visible = new Set<string>();\n while (pending.length > 0) {\n const node = pending.pop()!;\n const key = sessionKey(node.session);\n if (visible.has(key)) continue;\n visible.add(key);\n for (const child of node.children) pending.push(child);\n }\n\n return sessions.filter((session) => visible.has(sessionKey(session)));\n}\n\nexport function filterSessionTreeEntriesByActivityWindow(\n tree: SessionTree,\n from?: number,\n to?: number,\n): SessionTreeNode[] {\n if (from == null && to == null) return tree.entries;\n return tree.entries.filter((node) => hasActivityInWindow(node.session, from, to));\n}\n\ninterface SessionHierarchyGraph {\n sessionsByKey: Map<string, SessionHead>;\n parentByKey: Map<string, string>;\n childrenByKey: Map<string, string[]>;\n}\n\nfunction createSessionHierarchyGraph(sessions: SessionHead[]): SessionHierarchyGraph {\n const sessionsByKey = new Map<string, SessionHead>();\n for (const session of sessions) {\n const key = sessionKey(session);\n if (!sessionsByKey.has(key)) sessionsByKey.set(key, session);\n }\n\n const parentByKey = new Map<string, string>();\n const childrenByKey = new Map<string, string[]>();\n for (const [key, session] of sessionsByKey) {\n const parent = parentKey(session);\n if (!parent || !sessionsByKey.has(parent)) continue;\n parentByKey.set(key, parent);\n const children = childrenByKey.get(parent);\n if (children) children.push(key);\n else childrenByKey.set(parent, [key]);\n }\n return { sessionsByKey, parentByKey, childrenByKey };\n}\n\nfunction collectAffectedHierarchyKeys(\n graph: SessionHierarchyGraph,\n seedKeys: Iterable<string>,\n includeAncestors: boolean,\n collected: Set<string>,\n): void {\n const visited = new Set<string>();\n const pending = [...seedKeys].filter((key) => graph.sessionsByKey.has(key));\n while (pending.length > 0) {\n const key = pending.pop()!;\n if (visited.has(key)) continue;\n visited.add(key);\n collected.add(key);\n for (const child of graph.childrenByKey.get(key) ?? []) pending.push(child);\n }\n\n if (!includeAncestors) return;\n for (const seed of seedKeys) {\n let key = graph.sessionsByKey.has(seed) ? seed : undefined;\n const onPath = new Set<string>();\n while (key && !onPath.has(key)) {\n onPath.add(key);\n collected.add(key);\n key = graph.parentByKey.get(key);\n }\n }\n}\n\nexport interface SessionProjectionContext {\n relatedSessionHeads: ReferencedSessionHead[];\n sessionOrder: SessionReference[];\n}\n\nexport function createSessionProjectionContext(\n previousSessions: SessionHead[],\n nextSessions: SessionHead[],\n changedSessionHeads: ReferencedSessionHead[],\n removedSessionRefs: SessionReference[],\n): SessionProjectionContext {\n const changedKeys = new Set(\n changedSessionHeads.map(({ reference }) =>\n getSessionRouteKey(reference.agentName, reference.sessionId),\n ),\n );\n const removedKeys = removedSessionRefs.map(({ agentName, sessionId }) =>\n getSessionRouteKey(agentName, sessionId),\n );\n const affectedKeys = new Set<string>();\n const previousGraph = createSessionHierarchyGraph(previousSessions);\n const nextGraph = createSessionHierarchyGraph(nextSessions);\n collectAffectedHierarchyKeys(previousGraph, changedKeys, true, affectedKeys);\n collectAffectedHierarchyKeys(nextGraph, changedKeys, true, affectedKeys);\n collectAffectedHierarchyKeys(previousGraph, removedKeys, false, affectedKeys);\n\n const emitted = new Set<string>();\n const relatedSessionHeads = nextSessions.flatMap((session) => {\n const key = sessionKey(session);\n if (!affectedKeys.has(key) || changedKeys.has(key) || emitted.has(key)) return [];\n emitted.add(key);\n return [\n {\n reference: { agentName: getSessionAgentKey(session), sessionId: session.id },\n session,\n },\n ];\n });\n const affectedActivityTimes = new Set(\n [...changedSessionHeads, ...relatedSessionHeads].map(({ session }) => activityTime(session)),\n );\n const sessionOrder = nextSessions.flatMap((session) =>\n affectedActivityTimes.has(activityTime(session))\n ? [{ agentName: getSessionAgentKey(session), sessionId: session.id }]\n : [],\n );\n return { relatedSessionHeads, sessionOrder };\n}\n\nexport interface SessionWindowChanges {\n changedSessionHeads: SessionHeadChange[];\n projectionRelatedSessionHeads?: SessionHeadChange[];\n projectionSessionOrder?: SessionReference[];\n removedSessionRefs: SessionHeadRemoval[];\n from?: number;\n to?: number;\n}\n\nexport interface SessionWindowChangeResult {\n sessions: SessionHead[];\n visibleAddedSessions: number;\n visibleRemovedSessions: number;\n}\n\nexport function applySessionWindowChanges(\n sessions: SessionHead[],\n changes: SessionWindowChanges,\n): SessionWindowChangeResult {\n const previousKeys = new Set(sessions.map(sessionKey));\n const upserts = [\n ...(changes.projectionRelatedSessionHeads ?? []),\n ...changes.changedSessionHeads,\n ];\n const upsertsByKey = new Map(\n upserts.map((change) => [\n getSessionRouteKey(change.reference.agentName, change.reference.sessionId),\n change,\n ]),\n );\n const sessionsByKey = new Map(sessions.map((session) => [sessionKey(session), session]));\n const orderedUpserts: SessionHeadChange[] = [];\n const reorderedRefs: SessionReference[] = [];\n for (const reference of changes.projectionSessionOrder ?? []) {\n const key = getSessionRouteKey(reference.agentName, reference.sessionId);\n const change = upsertsByKey.get(key);\n const session = change?.session ?? sessionsByKey.get(key);\n if (!session) continue;\n orderedUpserts.push(change ?? { reference, session });\n reorderedRefs.push(reference);\n upsertsByKey.delete(key);\n }\n orderedUpserts.push(...upsertsByKey.values());\n const merged = applySessionChanges(sessions, orderedUpserts, [\n ...changes.removedSessionRefs,\n ...reorderedRefs,\n ]);\n const projected = filterSessionTreeByActivityWindow(merged, changes.from, changes.to);\n const nextKeys = new Set(projected.map(sessionKey));\n let visibleAddedSessions = 0;\n let visibleRemovedSessions = 0;\n for (const key of nextKeys) {\n if (!previousKeys.has(key)) visibleAddedSessions += 1;\n }\n for (const key of previousKeys) {\n if (!nextKeys.has(key)) visibleRemovedSessions += 1;\n }\n return { sessions: projected, visibleAddedSessions, visibleRemovedSessions };\n}\n","import { availableParallelism } from \"node:os\";\nimport { Worker } from \"node:worker_threads\";\nimport type { SessionDetail, SessionHead, SmartTag } from \"../types/index.js\";\nimport { filterSessionTreeByActivityWindow } from \"../contract/session-tree.js\";\nimport type {\n AgentScanFailure,\n AgentScanOptions,\n BaseAgent,\n SessionCacheMeta,\n SessionSourceFailure,\n} from \"../agents/index.js\";\nimport {\n createAgentScanFailure,\n createRegisteredAgents,\n FileSystemSessionSource,\n reportAgentScanFailure,\n SessionScanError,\n synchronizeSessionSources,\n} from \"../agents/index.js\";\nimport { filterSessionsByProjectScope } from \"../projects/index.js\";\nimport {\n classifySessionTags,\n getSmartTagSourceTimestamp,\n isWorkerLogMessage,\n perf,\n SMART_TAG_CLASSIFIER_REVISION,\n type WorkerLogMessage,\n} from \"../utils/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport { getPricingGeneration } from \"../pricing/index.js\";\nimport {\n loadCachedSessions,\n markAgentCacheInitialized,\n markAgentFullSyncCompleted,\n saveCachedSessionChanges,\n saveCachedSessions,\n type CachedResult,\n} from \"./cache/sessions.js\";\nimport {\n attachMissingProjectIdentities,\n buildAgentCacheMeta,\n computeSessionDiff,\n sessionSignature,\n} from \"./orchestrate.js\";\n\nexport interface ScanOptions {\n /** Filter to specific agent name(s) */\n agents?: string[];\n /** Filter to sessions from a specific project identity or directory scope */\n cwd?: string;\n /** Only include sessions active after this timestamp (ms) */\n from?: number;\n /** Only include sessions active before this timestamp (ms) */\n to?: number;\n /** Use cached scan results if available */\n useCache?: boolean;\n /** Enable smart refresh (fast cache + background incremental scan) */\n smartRefresh?: boolean;\n /** Return cached session heads without validating the filesystem */\n cacheOnly?: boolean;\n /** Persist scan results to the SQLite cache */\n writeCache?: boolean;\n /** Classify sessions by reading full conversation content */\n includeSmartTags?: boolean;\n /** Prefer lightweight metadata over complete statistics when the UI needs a fast first paint */\n fast?: boolean;\n /** URL to the compiled smart-tag worker file; omit to use synchronous fallback */\n smartTagWorkerUrl?: URL | string;\n}\n\nexport interface LiveSnapshot {\n sessions: SessionHead[];\n byAgent: Record<string, SessionHead[]>;\n agents: BaseAgent[];\n timings?: Record<string, AgentScanTiming>;\n cacheTimestamps?: Record<string, number>;\n cacheFailures?: Record<string, AgentCacheFailure>;\n scanFailures?: Record<string, AgentScanFailure>;\n}\n\nexport interface AgentCacheFailure {\n agentName: string;\n}\n\n/** 扫描状态更新回调 */\nexport interface ScanProgress {\n agent: string;\n phase: \"cache\" | \"checking\" | \"incremental\" | \"complete\";\n cachedCount?: number;\n newCount?: number;\n changedCount?: number;\n}\n\nexport function filterSessions(sessions: SessionHead[], options: ScanOptions): SessionHead[] {\n let result = sessions;\n\n if (options.cwd) {\n result = filterSessionsByProjectScope(result, options.cwd);\n }\n\n return filterSessionTreeByActivityWindow(result, options.from, options.to);\n}\n\nexport interface AgentScanTiming {\n cacheLoad?: number;\n checkChanges?: number;\n scan?: number;\n identity?: number;\n tags?: number;\n total: number;\n}\n\nexport interface SessionTagTiming {\n sessions: number;\n cacheHits: number;\n staleSessions: number;\n failedSessions: number;\n getSessionDataCalls: number;\n getSessionDataMs: number;\n classifySessionTagsCalls: number;\n classifySessionTagsMs: number;\n}\n\nfunction buildAgentScanOptions(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): AgentScanOptions {\n return {\n from: options.from,\n to: options.to,\n fast: options.fast,\n includeRelatedSessions: true,\n onProgress: (progress) => {\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n cachedCount: progress.total,\n newCount: progress.sessions,\n changedCount: progress.processed,\n });\n },\n };\n}\n\ntype CachePersistence = \"persisted\" | \"failed\" | \"not-requested\";\n\ninterface SuccessfulAgentScanResult {\n status: \"complete\" | \"partial\";\n agent: BaseAgent;\n heads: SessionHead[];\n cachePersistence: CachePersistence;\n fromCache?: boolean;\n refreshed?: boolean;\n timing?: AgentScanTiming;\n cacheTimestamp?: number;\n}\n\ninterface FailedAgentScanResult {\n status: \"failed\";\n agent: BaseAgent;\n failure: AgentScanFailure;\n retainedHeads?: SessionHead[];\n cacheTimestamp?: number;\n timing: AgentScanTiming;\n}\n\ntype AgentScanResult = SuccessfulAgentScanResult | FailedAgentScanResult;\n\ntype AgentScanFinalization =\n | { kind: \"cache-only\"; cached: CachedResult }\n | { kind: \"unchanged\"; cached: CachedResult }\n | {\n kind: \"incremental\";\n cached: CachedResult;\n changedIds: string[];\n explicitRemovedSessionIds?: string[];\n cacheTimestamp: number;\n };\n\ninterface FinalizeAgentScanContext {\n finalization: AgentScanFinalization;\n options: ScanOptions;\n timing: AgentScanTiming;\n agentStart: number;\n completeness: \"complete\" | \"partial\";\n onProgress?: (progress: ScanProgress) => void;\n}\n\ninterface SmartTagWorkerResult {\n id: string;\n tags?: SmartTag[];\n sourceUpdatedAt?: number;\n error?: string;\n}\n\nfunction restoreAgentCacheMeta(agent: BaseAgent, cached: CachedResult): void {\n agent.setSessionMetaMap(new Map(Object.entries(cached.meta)));\n}\n\nfunction saveCachedSessionDiff(\n agent: BaseAgent,\n cachedSessions: SessionHead[],\n updatedSessions: SessionHead[],\n changedIds: string[] = [],\n completeness: \"complete\" | \"partial\" = \"complete\",\n explicitRemovedSessionIds: readonly string[] = [],\n): boolean {\n const diff = computeSessionDiff(cachedSessions, updatedSessions, changedIds, sessionSignature);\n const explicitRemovals = new Set(explicitRemovedSessionIds);\n const removedSessionIds =\n completeness === \"complete\"\n ? diff.removedSessionIds\n : diff.removedSessionIds.filter((sessionId) => explicitRemovals.has(sessionId));\n const persisted = saveCachedSessionChanges(\n agent.name,\n diff.changes,\n removedSessionIds,\n buildAgentCacheMeta(agent),\n );\n if (persisted === false) {\n getCoreDiagnostics()?.warn(\"cache.save_failed\", {\n agent: agent.name,\n changed_sessions: diff.changes.length,\n removed_sessions: removedSessionIds.length,\n });\n }\n return persisted;\n}\n\nfunction getSmartTagWorkerCount(sessionCount: number): number {\n if (sessionCount < 50) return 1;\n return Math.min(sessionCount, Math.max(1, Math.min(4, availableParallelism() - 1)));\n}\n\nfunction chunkSessions<T>(items: T[], chunkCount: number): T[][] {\n const chunks = Array.from({ length: chunkCount }, () => [] as T[]);\n items.forEach((item, index) => {\n chunks[index % chunkCount]!.push(item);\n });\n return chunks.filter((chunk) => chunk.length > 0);\n}\n\nexport function ensureSessionTagsSync(\n agent: BaseAgent,\n sessions: SessionHead[],\n onProgress?: (processed: number, total: number) => void,\n classifierRevision = SMART_TAG_CLASSIFIER_REVISION,\n): { sessions: SessionHead[]; changed: boolean; timing: SessionTagTiming } {\n let changed = false;\n let processed = 0;\n const total = sessions.length;\n const timing: SessionTagTiming = {\n sessions: total,\n cacheHits: 0,\n staleSessions: 0,\n failedSessions: 0,\n getSessionDataCalls: 0,\n getSessionDataMs: 0,\n classifySessionTagsCalls: 0,\n classifySessionTagsMs: 0,\n };\n\n const tagged = sessions.map((session) => {\n const sourceUpdatedAt = session.time_updated ?? session.time_created;\n const currentTags = Array.isArray(session.smart_tags) ? session.smart_tags : null;\n if (\n currentTags &&\n session.smart_tags_source_updated_at === sourceUpdatedAt &&\n session.smart_tags_classifier_revision === classifierRevision\n ) {\n timing.cacheHits += 1;\n processed += 1;\n onProgress?.(processed, total);\n return session;\n }\n\n timing.staleSessions += 1;\n try {\n timing.getSessionDataCalls += 1;\n const getSessionDataStartedAt = performance.now();\n let data: SessionDetail;\n try {\n data = agent.getSessionData(session.id);\n } finally {\n timing.getSessionDataMs += performance.now() - getSessionDataStartedAt;\n }\n\n timing.classifySessionTagsCalls += 1;\n const classifySessionTagsStartedAt = performance.now();\n let tags: SmartTag[];\n try {\n tags = classifySessionTags(data);\n } finally {\n timing.classifySessionTagsMs += performance.now() - classifySessionTagsStartedAt;\n }\n\n changed = true;\n return {\n ...session,\n smart_tags: tags,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n smart_tags_classifier_revision: classifierRevision,\n };\n } catch {\n timing.failedSessions += 1;\n return session;\n } finally {\n processed += 1;\n onProgress?.(processed, total);\n }\n });\n\n return { sessions: tagged, changed, timing };\n}\n\nconst SMART_TAG_WORKER_TIMEOUT_MS = 300_000;\n\nasync function classifySessionTagsInWorker(\n workerUrl: URL | string,\n agentName: string,\n sessionIds: string[],\n meta: Record<string, SessionCacheMeta>,\n): Promise<SmartTagWorkerResult[]> {\n const worker = new Worker(workerUrl, {\n workerData: {\n pricingGenerationId: getPricingGeneration().id,\n agentName,\n sessionIds,\n meta,\n },\n });\n let timer: NodeJS.Timeout | undefined;\n try {\n return await new Promise<SmartTagWorkerResult[]>((resolveWorker, rejectWorker) => {\n timer = setTimeout(() => {\n rejectWorker(\n new Error(`Smart tag worker timed out after ${SMART_TAG_WORKER_TIMEOUT_MS}ms`),\n );\n }, SMART_TAG_WORKER_TIMEOUT_MS);\n worker.on(\"message\", (message: unknown) => {\n if (isWorkerLogMessage(message)) {\n relayWorkerLogMessage(message);\n return;\n }\n const results = message as SmartTagWorkerResult[];\n // An empty answer to a non-empty request means the worker could not\n // do the job at all (e.g. unresolvable agent) — fail over to the\n // synchronous path instead of silently shipping untagged sessions.\n if (results.length === 0 && sessionIds.length > 0) {\n rejectWorker(new Error(\"Smart tag worker returned no results\"));\n return;\n }\n resolveWorker(results);\n });\n worker.once(\"error\", rejectWorker);\n // Any exit before a result message — including a clean code 0 — must\n // reject; the old `code !== 0` guard left the promise pending forever\n // and hung server startup.\n worker.once(\"exit\", (code) => {\n rejectWorker(new Error(`Smart tag worker exited with code ${code} before responding`));\n });\n });\n } finally {\n if (timer) clearTimeout(timer);\n worker.terminate().catch(() => {});\n }\n}\n\nfunction relayWorkerLogMessage(message: WorkerLogMessage): void {\n const detail = {\n ...message.data,\n worker_ts: message.ts,\n worker_pid: message.pid,\n worker_thread_id: message.threadId,\n worker_level: message.level,\n };\n if (message.level === \"warn\" || message.level === \"error\") {\n getCoreDiagnostics()?.warn(message.event, detail);\n return;\n }\n getCoreDiagnostics()?.info?.(message.event, detail);\n}\n\nasync function ensureSessionTags(\n agent: BaseAgent,\n sessions: SessionHead[],\n workerUrl?: URL | string,\n): Promise<{ sessions: SessionHead[]; changed: boolean }> {\n const staleSessions = sessions.filter((session) => {\n const sourceUpdatedAt = session.time_updated ?? session.time_created;\n const currentTags = Array.isArray(session.smart_tags) ? session.smart_tags : null;\n return (\n !currentTags ||\n session.smart_tags_source_updated_at !== sourceUpdatedAt ||\n session.smart_tags_classifier_revision !== SMART_TAG_CLASSIFIER_REVISION\n );\n });\n\n if (staleSessions.length === 0) {\n return { sessions, changed: false };\n }\n\n const workerCount = workerUrl ? getSmartTagWorkerCount(staleSessions.length) : 1;\n if (workerCount <= 1) {\n return ensureSessionTagsSync(agent, sessions);\n }\n\n const meta = buildAgentCacheMeta(agent);\n try {\n const results = (\n await Promise.all(\n chunkSessions(\n staleSessions.map((session) => session.id),\n workerCount,\n ).map((sessionIds) =>\n classifySessionTagsInWorker(workerUrl!, agent.name, sessionIds, meta),\n ),\n )\n ).flat();\n const resultMap = new Map(results.filter((item) => item.tags).map((item) => [item.id, item]));\n\n return {\n changed: resultMap.size > 0,\n sessions: sessions.map((session) => {\n const result = resultMap.get(session.id);\n if (!result?.tags || result.sourceUpdatedAt == null) return session;\n return {\n ...session,\n smart_tags: result.tags,\n smart_tags_source_updated_at: result.sourceUpdatedAt,\n smart_tags_classifier_revision: SMART_TAG_CLASSIFIER_REVISION,\n };\n }),\n };\n } catch {\n return ensureSessionTagsSync(agent, sessions);\n }\n}\n\nexport async function finalizeAgentScan(\n agent: BaseAgent,\n sessions: SessionHead[],\n context: FinalizeAgentScanContext,\n): Promise<SuccessfulAgentScanResult> {\n const { finalization, options, timing, agentStart, onProgress } = context;\n const isIncremental = finalization.kind === \"incremental\";\n\n if (!isIncremental) {\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: sessions.length });\n }\n\n const identityStart = performance.now();\n const sessionsWithIdentity =\n finalization.kind === \"cache-only\" ? sessions : attachMissingProjectIdentities(sessions);\n const identityChanged = sessionsWithIdentity.some(\n (session, index) => session !== sessions[index],\n );\n timing.identity = performance.now() - identityStart;\n\n let tagged = { sessions: sessionsWithIdentity, changed: false };\n if (finalization.kind !== \"cache-only\") {\n const tagsStart = performance.now();\n tagged =\n options.includeSmartTags === false\n ? tagged\n : await ensureSessionTags(agent, sessionsWithIdentity, options.smartTagWorkerUrl);\n timing.tags = performance.now() - tagsStart;\n }\n\n let cachePersistence: CachePersistence = \"not-requested\";\n if (options.writeCache !== false) {\n if (finalization.kind === \"incremental\") {\n cachePersistence =\n saveCachedSessionDiff(\n agent,\n finalization.cached.sessions,\n tagged.sessions,\n finalization.changedIds,\n context.completeness,\n finalization.explicitRemovedSessionIds,\n ) === false\n ? \"failed\"\n : \"persisted\";\n } else if (finalization.kind === \"unchanged\" && (identityChanged || tagged.changed)) {\n cachePersistence =\n saveCachedSessionDiff(agent, finalization.cached.sessions, tagged.sessions) === false\n ? \"failed\"\n : \"persisted\";\n }\n }\n\n if (isIncremental) {\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: tagged.sessions.length });\n }\n\n const heads = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return {\n status: context.completeness,\n agent,\n heads,\n cachePersistence,\n fromCache: true,\n ...(isIncremental ? { refreshed: true } : {}),\n timing,\n cacheTimestamp:\n isIncremental && cachePersistence === \"persisted\"\n ? finalization.cacheTimestamp\n : finalization.cached.timestamp,\n };\n}\n\nasync function refreshCachedFileAgent(\n agent: FileSystemSessionSource,\n cached: CachedResult,\n options: ScanOptions,\n timing: AgentScanTiming,\n agentStart: number,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<SuccessfulAgentScanResult> {\n const scanStartedAt = performance.now();\n const synchronization = synchronizeSessionSources(\n agent,\n { sessions: cached.sessions, meta: cached.meta },\n {\n kind: \"refresh\",\n scanOptions: {\n onProgress: (progress) => {\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n cachedCount: progress.total,\n newCount: progress.sessions,\n changedCount: progress.processed,\n });\n },\n },\n },\n );\n timing.scan = performance.now() - scanStartedAt;\n const hasSourceChanges =\n synchronization.detectedSessionIds.length > 0 || synchronization.sourceFailures.length > 0;\n\n if (!hasSourceChanges) {\n return finalizeAgentScan(agent, synchronization.sessions, {\n finalization: { kind: \"unchanged\", cached },\n options,\n timing,\n agentStart,\n completeness: synchronization.completeness,\n onProgress,\n });\n }\n\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n changedCount: synchronization.detectedSessionIds.length,\n });\n return finalizeAgentScan(agent, synchronization.sessions, {\n finalization: {\n kind: \"incremental\",\n cached,\n changedIds: synchronization.changedSessionIds,\n explicitRemovedSessionIds: synchronization.explicitRemovedSessionIds,\n cacheTimestamp: Date.now(),\n },\n options,\n timing,\n agentStart,\n completeness: synchronization.completeness,\n onProgress,\n });\n}\n\n/**\n * 智能扫描单个 Agent\n * 1. 优先使用缓存立即返回\n * 2. 后台检测变更\n * 3. 增量刷新(仅更新变更的部分)\n */\nasync function scanAgentSmart(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<AgentScanResult | null> {\n const agentStart = performance.now();\n const timing: AgentScanTiming = { total: 0 };\n const useCache = options.useCache ?? true;\n\n // 1. 尝试加载缓存\n if (useCache) {\n const t0 = performance.now();\n const cached = loadCachedSessions(agent.name);\n timing.cacheLoad = performance.now() - t0;\n\n if (cached !== null) {\n // 恢复元数据\n restoreAgentCacheMeta(agent, cached);\n\n if (options.cacheOnly) {\n const visibleSessions = agent.filterCachedSessions(cached.sessions);\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: visibleSessions.length,\n });\n return finalizeAgentScan(agent, visibleSessions, {\n finalization: { kind: \"cache-only\", cached },\n options,\n timing,\n agentStart,\n completeness: \"partial\",\n onProgress,\n });\n }\n\n const isAvail = agent.isAvailable();\n if (!isAvail) {\n return null;\n }\n\n // 通知缓存已加载\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: cached.sessions.length,\n });\n\n onProgress?.({ agent: agent.name, phase: \"checking\" });\n\n if (agent instanceof FileSystemSessionSource) {\n return refreshCachedFileAgent(agent, cached, options, timing, agentStart, onProgress);\n }\n\n const t1 = performance.now();\n const checkResult = await Promise.resolve(\n agent.checkForChanges(cached.timestamp, cached.sessions),\n );\n timing.checkChanges = performance.now() - t1;\n\n if (checkResult.hasChanges) {\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n changedCount: checkResult.changedIds?.length,\n });\n\n const t2 = performance.now();\n const scanOptions = buildAgentScanOptions(agent, options, onProgress);\n const updatedSessions = await Promise.resolve(\n agent.incrementalScan(\n cached.sessions,\n checkResult.changedIds || [],\n checkResult.refs,\n scanOptions,\n ),\n );\n timing.scan = performance.now() - t2;\n agent.commitChangeCheck();\n\n return finalizeAgentScan(agent, updatedSessions, {\n finalization: {\n kind: \"incremental\",\n cached,\n changedIds: checkResult.changedIds ?? [],\n cacheTimestamp: checkResult.timestamp,\n },\n options,\n timing,\n agentStart,\n completeness:\n options.from == null &&\n options.to == null &&\n (checkResult.sourceFailures?.length ?? 0) === 0\n ? \"complete\"\n : \"partial\",\n onProgress,\n });\n }\n\n agent.commitChangeCheck();\n return finalizeAgentScan(agent, cached.sessions, {\n finalization: { kind: \"unchanged\", cached },\n options,\n timing,\n agentStart,\n completeness: \"complete\",\n onProgress,\n });\n }\n }\n\n if (options.cacheOnly) {\n timing.total = performance.now() - agentStart;\n return null;\n }\n\n // 无缓存或缓存失效,执行完整扫描\n return scanAgentFull(agent, options, onProgress, timing, agentStart);\n}\n\n/**\n * 完整扫描 Agent(无缓存时使用)\n */\nasync function scanAgentFull(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n timing: AgentScanTiming = { total: 0 },\n agentStart = performance.now(),\n): Promise<AgentScanResult | null> {\n const availMarker = perf.start(`agent:${agent.name}:isAvailable`);\n const isAvail = agent.isAvailable();\n perf.end(availMarker);\n\n if (!isAvail) {\n return null;\n }\n\n try {\n const scanMarker = perf.start(`agent:${agent.name}:scan`);\n const t0 = performance.now();\n const agentScanOptions = buildAgentScanOptions(agent, options, onProgress);\n let heads: SessionHead[];\n let sourceFailures: SessionSourceFailure[] = [];\n if (agent instanceof FileSystemSessionSource) {\n const cached = loadCachedSessions(agent.name);\n const synchronization = synchronizeSessionSources(\n agent,\n { sessions: cached?.sessions ?? [], meta: cached?.meta ?? new Map() },\n { kind: \"reload\", scanOptions: agentScanOptions },\n );\n heads = synchronization.sessions;\n sourceFailures = synchronization.sourceFailures;\n } else {\n heads = agent.scan(agentScanOptions);\n }\n perf.end(scanMarker);\n timing.scan = performance.now() - t0;\n\n const t1 = performance.now();\n const headsWithIdentity = attachMissingProjectIdentities(heads);\n timing.identity = performance.now() - t1;\n\n const t2 = performance.now();\n const tagged =\n options.includeSmartTags === false\n ? { sessions: headsWithIdentity, changed: false }\n : await ensureSessionTags(agent, headsWithIdentity, options.smartTagWorkerUrl);\n timing.tags = performance.now() - t2;\n\n // 收集元数据\n const meta = buildAgentCacheMeta(agent);\n\n let cachePersistence: CachePersistence = \"not-requested\";\n if (options.writeCache !== false) {\n const isFullWindow = options.from == null && options.to == null;\n const persisted = saveCachedSessions(agent.name, tagged.sessions, meta, {\n completeness: isFullWindow && sourceFailures.length === 0 ? \"complete\" : \"partial\",\n });\n if (persisted !== false) {\n cachePersistence = \"persisted\";\n markAgentCacheInitialized(agent.name);\n if (\n isFullWindow &&\n sourceFailures.length === 0 &&\n !markAgentFullSyncCompleted(agent.name)\n ) {\n getCoreDiagnostics()?.warn(\"cache.full_sync_marker_failed\", { agent: agent.name });\n }\n } else {\n cachePersistence = \"failed\";\n getCoreDiagnostics()?.warn(\"cache.save_failed\", {\n agent: agent.name,\n sessions: tagged.sessions.length,\n });\n }\n }\n\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: tagged.sessions.length });\n\n const filtered = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return {\n status:\n options.from == null && options.to == null && sourceFailures.length === 0\n ? \"complete\"\n : \"partial\",\n agent,\n heads: filtered,\n cachePersistence,\n fromCache: false,\n timing,\n };\n } catch (err) {\n if (err instanceof SessionScanError) throw err;\n throw new SessionScanError(agent.name, \"scanning sessions\", { cause: err });\n }\n}\n\nasync function scanAgentOutcome(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<AgentScanResult | null> {\n const startedAt = performance.now();\n try {\n return await scanAgentSmart(agent, options, onProgress);\n } catch (error) {\n const cached = (options.useCache ?? true) ? loadCachedSessions(agent.name) : null;\n if (cached) restoreAgentCacheMeta(agent, cached);\n const retainedHeads = cached\n ? filterSessions(agent.filterCachedSessions(cached.sessions), options)\n : undefined;\n const failure = createAgentScanFailure(agent.name, \"scanning sessions\", error);\n reportAgentScanFailure(failure, retainedHeads !== undefined);\n return {\n status: \"failed\",\n agent,\n failure,\n ...(retainedHeads !== undefined ? { retainedHeads } : {}),\n ...(cached ? { cacheTimestamp: cached.timestamp } : {}),\n timing: { total: performance.now() - startedAt },\n };\n }\n}\n\n/**\n * 主扫描函数 - 并行扫描所有 Agent\n */\nexport async function scanSessions(\n options: ScanOptions = {},\n onProgress?: (progress: ScanProgress) => void,\n): Promise<LiveSnapshot> {\n const scanMarker = perf.start(\"scanSessions\");\n const agents = createRegisteredAgents();\n const byAgent: Record<string, SessionHead[]> = {};\n const allSessions: SessionHead[] = [];\n const availableAgents: BaseAgent[] = [];\n const cacheTimestamps: Record<string, number> = {};\n const cacheFailures: Record<string, AgentCacheFailure> = {};\n const scanFailures: Record<string, AgentScanFailure> = {};\n\n const agentFilter = options.agents?.length\n ? new Set(options.agents.map((a) => a.toLowerCase()))\n : null;\n\n // 过滤需要扫描的 Agent\n const agentsToScan = agents.filter((agent) => {\n if (agentFilter && !agentFilter.has(agent.name.toLowerCase())) {\n return false;\n }\n return true;\n });\n\n // 并行扫描所有 Agent\n const scanPromises = agentsToScan.map((agent) => scanAgentOutcome(agent, options, onProgress));\n\n const results = await Promise.all(scanPromises);\n\n // 处理结果\n const timings: Record<string, AgentScanTiming> = {};\n for (const result of results) {\n if (result) {\n availableAgents.push(result.agent);\n if (result.status === \"failed\") {\n scanFailures[result.agent.name] = result.failure;\n if (result.retainedHeads !== undefined) {\n byAgent[result.agent.name] = result.retainedHeads;\n allSessions.push(...result.retainedHeads);\n }\n } else {\n byAgent[result.agent.name] = result.heads;\n allSessions.push(...result.heads);\n if (result.cachePersistence === \"failed\") {\n cacheFailures[result.agent.name] = { agentName: result.agent.name };\n }\n }\n if (result.timing) {\n timings[result.agent.name] = result.timing;\n }\n if (result.cacheTimestamp != null) {\n cacheTimestamps[result.agent.name] = result.cacheTimestamp;\n }\n }\n }\n\n perf.end(scanMarker);\n return {\n sessions: allSessions,\n byAgent,\n agents: availableAgents,\n timings,\n cacheTimestamps: Object.keys(cacheTimestamps).length > 0 ? cacheTimestamps : undefined,\n cacheFailures: Object.keys(cacheFailures).length > 0 ? cacheFailures : undefined,\n scanFailures: Object.keys(scanFailures).length > 0 ? scanFailures : undefined,\n };\n}\n","export function fallbackDisplayName(input: string): string {\n if (input === \"/\") return \"(root)\";\n const trimmed = input.replace(/[/\\\\]+$/, \"\");\n const parts = trimmed.split(/[/\\\\]+/).filter(Boolean);\n return parts.at(-1) ?? trimmed;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport type { IdentityFs } from \"./identity.js\";\n\nexport const realFs: IdentityFs = {\n exists(path) {\n return existsSync(path);\n },\n readText(path) {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n },\n spawn(cmd, args, opts) {\n const result = spawnSync(cmd, args, { cwd: opts.cwd, encoding: \"utf8\", timeout: 1000 });\n return {\n stdout: typeof result.stdout === \"string\" ? result.stdout : \"\",\n exitCode: result.status ?? 1,\n };\n },\n};\n","import * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport type { ProjectIdentity, ProjectIdentityKind } from \"../types/index.js\";\nimport { fallbackDisplayName } from \"./display-name.js\";\nimport { realFs } from \"./fs.js\";\n\nexport interface IdentityFs {\n exists(path: string): boolean;\n readText(path: string): string | null;\n spawn(cmd: string, args: string[], opts: { cwd: string }): { stdout: string; exitCode: number };\n}\n\nexport const PROJECT_IDENTITY_RESOLVER_REVISION = \"project-identity-v2\";\n\nexport interface ProjectIdentityProjection {\n identity: ProjectIdentity;\n resolverRevision: string;\n inputSignature: string;\n}\n\nconst MANIFESTS = [\n \"package.json\",\n \"Cargo.toml\",\n \"pyproject.toml\",\n \"go.mod\",\n \"Gemfile\",\n \"pom.xml\",\n \"build.gradle\",\n] as const;\n\nconst PARSEABLE_MANIFESTS = [\"package.json\", \"Cargo.toml\", \"pyproject.toml\"] as const;\n\nconst LOOSE_DIRS = new Set([\"/tmp\", \"/private/tmp\"]);\nconst LOOSE_HOME_DIRS = [\"Desktop\", \"Downloads\", \"Documents\"];\ntype PathOps = Pick<\n typeof path.posix,\n \"dirname\" | \"isAbsolute\" | \"join\" | \"relative\" | \"resolve\" | \"sep\"\n>;\n\n// Identity semantics live in the contract; this module only discovers them\n// from the filesystem and git.\nexport {\n getProjectIdentityKey,\n isProjectIdentityKind,\n matchesProjectIdentity,\n} from \"../contract/project-identity.js\";\n\nexport function normalizeGitRemote(url: string): string | null {\n if (!url) return null;\n let value = url.trim();\n if (/^[a-z][a-z\\d+.-]*:\\/\\//i.test(value)) {\n try {\n const parsed = new URL(value);\n value = `${parsed.hostname}${parsed.pathname}`;\n } catch {\n return null;\n }\n } else {\n const sshMatch = value.match(/^[^@]+@([^:]+):(.+)$/);\n if (sshMatch) value = `${sshMatch[1]}/${sshMatch[2]}`;\n }\n value = value.replace(/\\.git$/, \"\");\n if (!value.includes(\"/\")) return null;\n return value.toLowerCase();\n}\n\n// Process-lifetime identity cache, keyed by directory. Only used for the real\n// filesystem (fs === realFs); tests inject fake IdentityFs implementations and\n// must bypass the cache to stay isolated from each other. git remotes change\n// rarely, so a coarse TTL is enough — no file-watch invalidation needed.\nconst IDENTITY_CACHE_TTL_MS = 10 * 60 * 1000;\nexport const IDENTITY_CACHE_MAX_ENTRIES = 512;\n\ninterface IdentityCacheEntry {\n projection: ProjectIdentityProjection;\n resolvedAt: number;\n}\n\nconst identityCache = new Map<string, IdentityCacheEntry>();\n\n/** Clears the process-lifetime identity cache. For tests and explicit invalidation. */\nexport function clearIdentityCache(): void {\n identityCache.clear();\n}\n\nexport function computeIdentity(cwd: string | null | undefined, fs: IdentityFs): ProjectIdentity {\n return computeIdentityProjection(cwd, fs).identity;\n}\n\nexport function normalizeProjectDirectory(cwd: string | null | undefined): string {\n if (!cwd) return \"\";\n return getPathOps(cwd).resolve(cwd);\n}\n\nexport function computeIdentityProjection(\n cwd: string | null | undefined,\n fs: IdentityFs = realFs,\n resolverRevision = PROJECT_IDENTITY_RESOLVER_REVISION,\n): ProjectIdentityProjection {\n if (fs !== realFs) return resolveIdentityProjection(cwd, fs, resolverRevision);\n\n const key = normalizeProjectDirectory(cwd);\n const cached = identityCache.get(key);\n if (cached) {\n if (\n cached.projection.resolverRevision === resolverRevision &&\n Date.now() - cached.resolvedAt < IDENTITY_CACHE_TTL_MS\n ) {\n identityCache.delete(key);\n identityCache.set(key, cached);\n return cached.projection;\n }\n identityCache.delete(key);\n }\n const projection = resolveIdentityProjection(cwd, fs, resolverRevision);\n identityCache.set(key, { projection, resolvedAt: Date.now() });\n while (identityCache.size > IDENTITY_CACHE_MAX_ENTRIES) {\n const oldestKey = identityCache.keys().next().value;\n if (oldestKey == null) break;\n identityCache.delete(oldestKey);\n }\n return projection;\n}\n\nfunction resolveIdentityProjection(\n cwd: string | null | undefined,\n fs: IdentityFs,\n resolverRevision: string,\n): ProjectIdentityProjection {\n if (!cwd) return projectIdentityProjection(loose(), resolverRevision, [\"loose\", \"missing\"]);\n\n const pathOps = getPathOps(cwd);\n const absoluteCwd = pathOps.resolve(cwd);\n const homeDir = os.homedir();\n const homePathOps = getPathOps(homeDir);\n const home = homePathOps === pathOps ? pathOps.resolve(homeDir) : homeDir;\n if (absoluteCwd === home || LOOSE_DIRS.has(absoluteCwd)) {\n return projectIdentityProjection(loose(), resolverRevision, [\"loose\", absoluteCwd]);\n }\n if (\n homePathOps === pathOps &&\n LOOSE_HOME_DIRS.some((dir) => absoluteCwd === pathOps.join(home, dir))\n ) {\n return projectIdentityProjection(loose(), resolverRevision, [\"loose\", absoluteCwd]);\n }\n\n const gitRoot = findGitRoot(absoluteCwd, fs, pathOps);\n if (gitRoot) {\n const remote = fs.spawn(\"git\", [\"config\", \"--get\", \"remote.origin.url\"], { cwd: gitRoot });\n if (remote.exitCode === 0) {\n const normalized = normalizeGitRemote(remote.stdout.trim());\n if (normalized) {\n const identity: ProjectIdentity = {\n kind: \"git_remote\",\n key: normalized,\n displayName: deriveDisplayName({ kind: \"git_remote\", key: normalized, gitRoot, fs }),\n };\n return projectIdentityProjection(identity, resolverRevision, [\n \"git_remote\",\n gitRoot,\n normalized,\n identity.displayName,\n ]);\n }\n }\n\n const common = fs.spawn(\"git\", [\"rev-parse\", \"--git-common-dir\"], { cwd: gitRoot });\n if (common.exitCode === 0) {\n const raw = common.stdout.trim();\n if (raw) {\n const key = pathOps.isAbsolute(raw) ? raw : pathOps.resolve(gitRoot, raw);\n const identity: ProjectIdentity = {\n kind: \"git_common_dir\",\n key,\n displayName: deriveDisplayName({ kind: \"git_common_dir\", key, gitRoot, fs }),\n };\n return projectIdentityProjection(identity, resolverRevision, [\n \"git_common_dir\",\n gitRoot,\n key,\n identity.displayName,\n ]);\n }\n }\n }\n\n const manifestDir = findManifestDir(absoluteCwd, fs, pathOps);\n if (manifestDir) {\n const identity: ProjectIdentity = {\n kind: \"manifest_path\",\n key: manifestDir,\n displayName: deriveDisplayName({ kind: \"manifest_path\", key: manifestDir, fs }),\n };\n return projectIdentityProjection(identity, resolverRevision, [\n \"manifest_path\",\n manifestDir,\n identity.displayName,\n ]);\n }\n\n if (homePathOps === pathOps) {\n const synthetic = synthesizeCodexScratchIdentity(absoluteCwd, home, pathOps);\n if (synthetic) {\n return projectIdentityProjection(synthetic, resolverRevision, [\"synthetic\", synthetic.key]);\n }\n }\n\n const identity: ProjectIdentity = {\n kind: \"path\",\n key: absoluteCwd,\n displayName: fallbackDisplayName(absoluteCwd),\n };\n return projectIdentityProjection(identity, resolverRevision, [\"path\", absoluteCwd]);\n}\n\nfunction projectIdentityProjection(\n identity: ProjectIdentity,\n resolverRevision: string,\n inputs: readonly string[],\n): ProjectIdentityProjection {\n return {\n identity,\n resolverRevision,\n inputSignature: createHash(\"sha256\").update(JSON.stringify(inputs)).digest(\"hex\"),\n };\n}\n\nfunction loose(): ProjectIdentity {\n return { kind: \"loose\", key: \"loose\", displayName: \"Loose\" };\n}\n\nfunction synthesizeCodexScratchIdentity(\n absoluteCwd: string,\n home: string,\n pathOps: PathOps,\n): ProjectIdentity | null {\n const root = pathOps.resolve(pathOps.join(home, \"Documents\", \"Codex\"));\n const child = pathOps.relative(root, absoluteCwd);\n if (\n !child ||\n child === \"..\" ||\n child.startsWith(`..${pathOps.sep}`) ||\n pathOps.isAbsolute(child)\n ) {\n return null;\n }\n return { kind: \"synthetic\", key: \"codex:scratch\", displayName: \"Chats\" };\n}\n\nfunction getPathOps(input: string): PathOps {\n if (/^[a-zA-Z]:[\\\\/]/.test(input) || input.startsWith(\"\\\\\\\\\")) {\n return path.win32;\n }\n if (input.startsWith(\"/\")) return path.posix;\n return path;\n}\n\nfunction findGitRoot(start: string, fs: IdentityFs, pathOps: PathOps): string | null {\n let current = start;\n while (current) {\n if (fs.exists(pathOps.join(current, \".git\"))) return current;\n const parent = pathOps.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return null;\n}\n\nfunction findManifestDir(start: string, fs: IdentityFs, pathOps: PathOps): string | null {\n let current = start;\n while (current) {\n for (const manifest of MANIFESTS) {\n if (fs.exists(pathOps.join(current, manifest))) return current;\n }\n const parent = pathOps.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return null;\n}\n\ninterface DisplayNameInput {\n kind: ProjectIdentityKind;\n key: string;\n gitRoot?: string;\n fs: IdentityFs;\n}\n\nfunction deriveDisplayName(input: DisplayNameInput): string {\n const pathOps = getPathOps(input.gitRoot ?? input.key);\n const dir = input.gitRoot ?? (input.kind === \"manifest_path\" ? input.key : null);\n if (dir) {\n for (const manifest of PARSEABLE_MANIFESTS) {\n const manifestPath = pathOps.join(dir, manifest);\n if (input.fs.exists(manifestPath)) {\n const name = parseManifestName(manifest, input.fs.readText(manifestPath) ?? \"\");\n if (name) return name;\n }\n }\n }\n\n if (input.kind === \"git_remote\") {\n return input.key.split(\"/\").at(-1) || input.key;\n }\n if (input.gitRoot) return fallbackDisplayName(input.gitRoot);\n return fallbackDisplayName(input.key);\n}\n\nfunction parseManifestName(file: string, text: string): string | null {\n if (!text) return null;\n if (file === \"package.json\" || file === \"Cargo.toml\" || file === \"pyproject.toml\") {\n const match = text.match(/\"name\"\\s*:\\s*\"([^\"]+)\"/) || text.match(/^\\s*name\\s*=\\s*\"([^\"]+)\"/m);\n if (match?.[1]) return match[1];\n }\n return null;\n}\n","import type { ProjectGroup, ProjectIdentity, SessionHead } from \"../types/index.js\";\nimport { buildSessionTree, getSessionAgentKey } from \"../contract/index.js\";\nimport { getProjectIdentityKey } from \"./identity.js\";\n\nexport function buildProjectGroups(sessions: SessionHead[]): ProjectGroup[] {\n const groups = new Map<\n string,\n { identity: ProjectIdentity; sources: Set<string>; sessionCount: number; lastActivity: number }\n >();\n\n const tree = buildSessionTree(sessions);\n for (const session of sessions) {\n if (tree.mountStateOf(session) === \"mounted-child\") continue;\n const identity = session.project_identity;\n if (!identity) continue;\n const activity = session.time_updated ?? session.time_created;\n const groupKey = getProjectIdentityKey(identity);\n const current = groups.get(groupKey);\n if (current) {\n current.sources.add(getSessionAgentKey(session));\n current.sessionCount += 1;\n current.lastActivity = Math.max(current.lastActivity, activity);\n } else {\n groups.set(groupKey, {\n identity,\n sources: new Set([getSessionAgentKey(session)]),\n sessionCount: 1,\n lastActivity: activity,\n });\n }\n }\n\n return [...groups.values()]\n .map((group) => ({\n identityKind: group.identity.kind,\n identityKey: group.identity.key,\n displayName: group.identity.displayName,\n sources: [...group.sources].sort(),\n sessionCount: group.sessionCount,\n lastActivity: group.lastActivity || null,\n }))\n .sort((a, b) => {\n if (a.identityKind === \"loose\" && b.identityKind !== \"loose\") return 1;\n if (b.identityKind === \"loose\" && a.identityKind !== \"loose\") return -1;\n return (b.lastActivity ?? 0) - (a.lastActivity ?? 0);\n });\n}\n","import type { ProjectIdentityRef, SessionHead } from \"../types/index.js\";\nimport {\n computeIdentity,\n matchesProjectIdentity,\n normalizeProjectDirectory,\n type IdentityFs,\n} from \"./identity.js\";\nimport { realFs } from \"./fs.js\";\n\nexport interface ProjectScopeMatcher {\n identity: ProjectIdentityRef;\n path: string;\n}\n\nexport function createProjectScopeMatcher(\n queryPath: string,\n fs: IdentityFs = realFs,\n): ProjectScopeMatcher {\n const identity = computeIdentity(queryPath, fs);\n return createProjectScopeMatcherFromIdentity(queryPath, identity);\n}\n\nexport function createProjectScopeMatcherFromIdentity(\n queryPath: string,\n identity: ProjectIdentityRef,\n): ProjectScopeMatcher {\n return {\n identity: { kind: identity.kind, key: identity.key },\n path: normalizeProjectScopePath(queryPath),\n };\n}\n\nexport function matchesProjectScope(session: SessionHead, scope: ProjectScopeMatcher): boolean {\n if (matchesProjectIdentity(session.project_identity, scope.identity)) return true;\n return session.directory ? isPathScopeMatch(scope.path, session.directory) : false;\n}\n\nexport function filterSessionsByProjectScope(\n sessions: SessionHead[],\n queryPath: string,\n fs?: IdentityFs,\n): SessionHead[] {\n const scope = createProjectScopeMatcher(queryPath, fs);\n return sessions.filter((session) => matchesProjectScope(session, scope));\n}\n\nfunction isPathScopeMatch(queryPath: string, sessionPath: string): boolean {\n const session = normalizeProjectScopePath(sessionPath);\n return (\n session === queryPath ||\n session.startsWith(queryPath + \"/\") ||\n queryPath.startsWith(session + \"/\")\n );\n}\n\nexport function normalizeProjectScopePath(path: string): string {\n return normalizeProjectDirectory(path).replaceAll(\"\\\\\", \"/\");\n}\n","import type { MessagePart, SessionDetail, SmartTag, ToolPart } from \"../types/index.js\";\n\nexport const SMART_TAG_CLASSIFIER_REVISION = \"smart-tags-v1\";\n\nconst TAG_ORDER: SmartTag[] = [\n \"bugfix\",\n \"refactoring\",\n \"feature-dev\",\n \"testing\",\n \"docs\",\n \"git-ops\",\n \"build-deploy\",\n \"exploration\",\n \"planning\",\n];\n\nconst USER_RULES: Array<[SmartTag, RegExp]> = [\n [\"bugfix\", /\\b(fix|bug|error|crash|exception|fail(?:ed|ure)?)\\b|修复|错误|报错|崩溃|异常/i],\n [\"refactoring\", /\\b(refactor|rename|simplify|clean up|cleanup)\\b|重构|重命名|简化|清理/i],\n [\"feature-dev\", /\\b(add|create|implement|new|support|build)\\b|新增|创建|实现|增加|开发|支持/i],\n [\"docs\", /\\b(document|documentation|readme|docs?)\\b|文档|说明/i],\n];\n\nconst TESTING_COMMAND_RE = /\\b(pytest|vitest|jest|mocha|pnpm\\s+test|npm\\s+test|yarn\\s+test)\\b/i;\nconst GIT_COMMAND_RE = /\\bgit\\s+(push|commit|merge|branch|checkout|switch|rebase|tag)\\b/i;\nconst BUILD_DEPLOY_COMMAND_RE =\n /\\b((npm|pnpm|yarn|bun)\\s+(run\\s+)?build|docker|pm2|deploy|vercel|netlify)\\b/i;\nconst DOC_PATH_RE = /\\.(md|mdx|txt|rst|adoc)$/i;\nconst READ_TOOL_RE = /\\b(read|grep|glob|websearch|web_search|search|find|rg)\\b/i;\nconst EDIT_TOOL_RE = /\\b(edit|write|apply_patch|patch|multiedit|notebookedit)\\b/i;\nconst PLAN_TOOL_RE = /\\b(enterplanmode|taskcreate|update_plan|plan)\\b/i;\n\nexport function getSmartTagSourceTimestamp(\n session: Pick<SessionDetail, \"time_created\" | \"time_updated\">,\n): number {\n return session.time_updated ?? session.time_created;\n}\n\nexport function classifySessionTags(session: Pick<SessionDetail, \"messages\">): SmartTag[] {\n const tags = new Set<SmartTag>();\n let readToolCount = 0;\n let editToolCount = 0;\n\n for (const message of session.messages) {\n if (message.role === \"user\") {\n const text = message.parts.map(partText).join(\"\\n\");\n for (const [tag, pattern] of USER_RULES) {\n if (pattern.test(text)) tags.add(tag);\n }\n }\n\n for (const part of message.parts) {\n if (part.type === \"plan\") tags.add(\"planning\");\n if (part.type !== \"tool\") continue;\n\n const toolName = `${part.tool} ${part.title ?? \"\"}`;\n const toolPayload = stringifyToolPayload(part);\n\n if (PLAN_TOOL_RE.test(toolName)) tags.add(\"planning\");\n if (READ_TOOL_RE.test(toolName)) readToolCount += 1;\n if (EDIT_TOOL_RE.test(toolName)) editToolCount += 1;\n\n if (TESTING_COMMAND_RE.test(toolPayload)) tags.add(\"testing\");\n if (GIT_COMMAND_RE.test(toolPayload)) tags.add(\"git-ops\");\n if (BUILD_DEPLOY_COMMAND_RE.test(toolPayload)) tags.add(\"build-deploy\");\n if (hasEditedDocPath(part.state.input)) {\n tags.add(\"docs\");\n }\n }\n }\n\n if (readToolCount >= 3 && editToolCount <= 1) {\n tags.add(\"exploration\");\n }\n\n return TAG_ORDER.filter((tag) => tags.has(tag));\n}\n\nfunction partText(part: MessagePart): string {\n return part.type === \"text\" || part.type === \"reasoning\" || part.type === \"plan\" ? part.text : \"\";\n}\n\nfunction stringifyToolPayload(part: ToolPart): string {\n return [part.tool, part.title, valueToText(part.state)].filter(Boolean).join(\"\\n\");\n}\n\nfunction valueToText(value: unknown): string {\n if (value == null) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return \"\";\n }\n}\n\nfunction hasEditedDocPath(value: unknown): boolean {\n if (value == null) return false;\n if (typeof value === \"string\") return DOC_PATH_RE.test(value);\n if (Array.isArray(value)) return value.some(hasEditedDocPath);\n if (typeof value !== \"object\") return false;\n\n const record = value as Record<string, unknown>;\n for (const key of [\"path\", \"file\", \"filePath\", \"file_path\", \"targetPath\", \"target_path\"]) {\n const raw = record[key];\n if (typeof raw === \"string\" && DOC_PATH_RE.test(raw)) return true;\n }\n\n return Object.values(record).some(hasEditedDocPath);\n}\n","export const WORKER_LOG_MESSAGE_TYPE = \"codesesh.worker-log\";\n\nexport type WorkerLogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport interface WorkerLogMessage {\n type: typeof WORKER_LOG_MESSAGE_TYPE;\n ts: string;\n level: WorkerLogLevel;\n event: string;\n pid: number;\n threadId: number;\n data: Record<string, unknown>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function isWorkerLogMessage(value: unknown): value is WorkerLogMessage {\n if (!isRecord(value) || value.type !== WORKER_LOG_MESSAGE_TYPE) return false;\n return (\n typeof value.ts === \"string\" &&\n value.ts.length > 0 &&\n (value.level === \"debug\" ||\n value.level === \"info\" ||\n value.level === \"warn\" ||\n value.level === \"error\") &&\n typeof value.event === \"string\" &&\n value.event.length > 0 &&\n Number.isSafeInteger(value.pid) &&\n Number(value.pid) > 0 &&\n Number.isSafeInteger(value.threadId) &&\n Number(value.threadId) >= 0 &&\n isRecord(value.data)\n );\n}\n","import type {\n FileActivityKind,\n Message,\n SessionFileActivity,\n SessionFileActivityOccurrence,\n ToolPart,\n} from \"../types/index.js\";\n\ninterface CodexPatchEntry {\n type: string;\n path: string;\n oldPath: string;\n}\n\nconst CODEX_PATCH_TYPES = new Set([\n \"edit_file\",\n \"update_file\",\n \"write_file\",\n \"delete_file\",\n \"move_file\",\n]);\n\nfunction toRecord(value: unknown) {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction toStringValue(value: unknown) {\n return typeof value === \"string\" ? value : \"\";\n}\n\nfunction normalizeToolLabel(part: ToolPart) {\n if (part.title?.trim()) {\n return part.title.trim().replace(/^tool:\\s*/i, \"\");\n }\n if (part.tool.trim()) return part.tool.trim();\n return \"tool\";\n}\n\nfunction normalizeToolName(part: ToolPart) {\n return normalizeToolLabel(part).trim().toLowerCase();\n}\n\nfunction looksLikeFilePath(value: string) {\n const text = value.trim();\n if (!text || text.length > 300) return false;\n if (text.includes(\"\\n\")) return false;\n if (/^[a-z]+:\\/\\//i.test(text)) return false;\n if (/[<>{}]/.test(text)) return false;\n if (text.startsWith(\"/\")) return true;\n if (text.startsWith(\"./\") || text.startsWith(\"../\") || text.startsWith(\"~/\")) return true;\n if (text.includes(\"/\") || text.includes(\"\\\\\")) return true;\n return /^[A-Za-z0-9_.@-]+\\.[A-Za-z0-9_-]+$/.test(text);\n}\n\nfunction shouldTreatAsPathKey(key: string) {\n const normalized = key.trim().toLowerCase();\n if (!normalized) return false;\n if (\n normalized.includes(\"command\") ||\n normalized.includes(\"content\") ||\n normalized.includes(\"text\") ||\n normalized.includes(\"prompt\") ||\n normalized.includes(\"url\") ||\n normalized.includes(\"body\") ||\n normalized.includes(\"title\") ||\n normalized.includes(\"description\") ||\n normalized === \"cwd\" ||\n normalized === \"workdir\" ||\n normalized === \"directory\"\n ) {\n return false;\n }\n return (\n normalized === \"path\" ||\n normalized === \"paths\" ||\n normalized.includes(\"file\") ||\n normalized.includes(\"path\")\n );\n}\n\nfunction collectPathsFromValue(\n value: unknown,\n keyHint: string,\n paths: Set<string>,\n depth = 0,\n): void {\n if (value == null || depth > 4) return;\n\n if (typeof value === \"string\") {\n if (shouldTreatAsPathKey(keyHint) && looksLikeFilePath(value)) {\n paths.add(value.trim());\n }\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n collectPathsFromValue(item, keyHint, paths, depth + 1);\n }\n return;\n }\n\n if (typeof value === \"object\") {\n for (const [key, nested] of Object.entries(value as Record<string, unknown>)) {\n collectPathsFromValue(nested, key, paths, depth + 1);\n }\n }\n}\n\nfunction extractPathsFromToolInput(inputValue: unknown) {\n const paths = new Set<string>();\n collectPathsFromValue(inputValue, \"\", paths);\n return [...paths];\n}\n\nfunction getToolInputValue(part: ToolPart) {\n return part.state.input ?? null;\n}\n\nfunction classifyToolKind(part: ToolPart): FileActivityKind | null {\n const toolName = normalizeToolName(part);\n if (toolName === \"read\" || toolName === \"readfile\" || toolName === \"read_file\") return \"read\";\n if (\n toolName === \"edit\" ||\n toolName === \"multiedit\" ||\n toolName === \"apply_patch\" ||\n toolName === \"notebookedit\"\n ) {\n return \"edit\";\n }\n if (\n toolName === \"write\" ||\n toolName === \"writefile\" ||\n toolName === \"write_file\" ||\n toolName === \"create_file\"\n ) {\n return \"write\";\n }\n if (toolName === \"delete\" || toolName === \"delete_file\") {\n return \"delete\";\n }\n return null;\n}\n\nfunction normalizeCodexPatchEntry(entry: unknown): CodexPatchEntry | null {\n const record = toRecord(entry);\n const type = toStringValue(record.type);\n const path = toStringValue(record.path);\n const oldPath = toStringValue(record.old_path);\n if (!CODEX_PATCH_TYPES.has(type) || (!path && !oldPath)) return null;\n return {\n type,\n path,\n oldPath,\n };\n}\n\nfunction getCodexPatchEntries(inputValue: unknown): CodexPatchEntry[] {\n const input = toRecord(inputValue);\n const rawContent: unknown[] = Array.isArray(inputValue)\n ? inputValue\n : Array.isArray(input.content)\n ? (input.content as unknown[])\n : [];\n\n return rawContent\n .map((entry) => normalizeCodexPatchEntry(entry))\n .filter((entry): entry is CodexPatchEntry => entry != null);\n}\n\nfunction patchEntryKind(type: string): FileActivityKind {\n if (type === \"write_file\") return \"write\";\n if (type === \"delete_file\") return \"delete\";\n return \"edit\";\n}\n\nexport function extractFileActivityOccurrences(\n messages: Message[],\n): SessionFileActivityOccurrence[] {\n const occurrences: SessionFileActivityOccurrence[] = [];\n\n messages.forEach((message, messageIndex) => {\n let toolIndex = 0;\n\n for (const part of message.parts) {\n if (part.type !== \"tool\") continue;\n\n const inputValue = getToolInputValue(part);\n const toolLabel = normalizeToolLabel(part);\n const time = part.time_created ?? message.time_created;\n const currentToolIndex = toolIndex;\n toolIndex += 1;\n\n const kind = classifyToolKind(part);\n const patchEntries = getCodexPatchEntries(inputValue);\n if (patchEntries.length > 0) {\n for (const entry of patchEntries) {\n const path = (entry.path || entry.oldPath).trim();\n if (!path) continue;\n occurrences.push({\n path,\n kind: patchEntryKind(entry.type),\n time,\n tool_label: toolLabel,\n message_index: messageIndex,\n tool_index: currentToolIndex,\n });\n }\n continue;\n }\n\n if (!kind) continue;\n\n for (const path of extractPathsFromToolInput(inputValue)) {\n occurrences.push({\n path,\n kind,\n time,\n tool_label: toolLabel,\n message_index: messageIndex,\n tool_index: currentToolIndex,\n });\n }\n }\n });\n\n return occurrences;\n}\n\nexport function summarizeFileActivity(\n agentName: string,\n sessionId: string,\n projectIdentityKey: string,\n occurrences: SessionFileActivityOccurrence[],\n): SessionFileActivity[] {\n const grouped = new Map<string, SessionFileActivity>();\n\n for (const occurrence of occurrences) {\n const key = `${occurrence.kind}\\0${occurrence.path}`;\n const current = grouped.get(key);\n if (current) {\n current.count += 1;\n current.latestTime = Math.max(current.latestTime, occurrence.time);\n continue;\n }\n\n grouped.set(key, {\n reference: { agentName, sessionId },\n projectIdentityKey,\n path: occurrence.path,\n kind: occurrence.kind,\n count: 1,\n latestTime: occurrence.time,\n });\n }\n\n return [...grouped.values()].sort((a, b) => {\n if (b.latestTime !== a.latestTime) return b.latestTime - a.latestTime;\n return a.path.localeCompare(b.path);\n });\n}\n\nexport function extractSessionFileActivity(\n agentName: string,\n sessionId: string,\n projectIdentityKey: string,\n messages: Message[],\n): SessionFileActivity[] {\n return summarizeFileActivity(\n agentName,\n sessionId,\n projectIdentityKey,\n extractFileActivityOccurrences(messages),\n );\n}\n","/**\n * Cache persistence: load / save / clear / info / initialization tracking.\n */\nimport { existsSync, rmSync, unlinkSync } from \"node:fs\";\nimport type { SessionCacheMeta } from \"../../agents/base.js\";\nimport type { ReferencedSessionHead, SessionReference } from \"../../contract/index.js\";\nimport { formatSessionReference, normalizeSessionReference } from \"../../contract/index.js\";\nimport type { SessionDetail, SessionHead } from \"../../types/index.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport { tableExists, type SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport {\n closeCacheStorage,\n getCachePath,\n getLegacyCachePath,\n hasCacheStorage,\n type ScalarRow,\n type PersistedSessionHeadChange,\n} from \"./db.js\";\nimport { advanceAnalyticsRevision } from \"./analytics-revision.js\";\nimport {\n withCacheDb,\n withCacheDbOutcome,\n withCacheDbReadOnly,\n type CacheReadOutcome,\n} from \"./schema.js\";\nimport {\n assertSessionProjectIdentities,\n messageFromCachedRow,\n prepareUpsertSession,\n sessionFromRow,\n sourcePathFromMeta,\n upsertSessionRow,\n type CachedMessageRow,\n type SessionRow,\n} from \"./messages.js\";\nimport { fileActivityFromRow, type FileActivityRow } from \"./file-activity.js\";\n\nexport const CACHE_INITIALIZATION_VERSION = \"session-cache-v2\";\nconst FULL_SYNC_CURSOR_PREFIX = \"full_sync_cursor:\";\nconst SESSION_REFERENCE_QUERY_CHUNK_SIZE = 400;\nconst SESSION_HEAD_SELECT_COLUMNS = `\n s.agent_name,\n s.session_id,\n s.sort_index,\n s.slug,\n s.title,\n s.source_path,\n s.directory,\n s.parent_agent_name,\n s.parent_session_id,\n s.project_identity_kind,\n s.project_identity_key,\n s.project_display_name,\n s.project_identity_resolver_revision,\n s.project_identity_input_signature,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at,\n s.smart_tags_classifier_revision,\n s.meta_json\n`;\nexport interface CachedResult {\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n timestamp: number;\n}\n\nexport interface CachedSessionDataEntry {\n data: SessionDetail;\n meta: SessionCacheMeta | null;\n}\n\ninterface CachedSessionEntryBase {\n data: Omit<SessionDetail, \"messages\">;\n meta: SessionCacheMeta | null;\n detailVersion: string | null;\n pendingReindex: boolean;\n}\n\nexport interface CachedSessionRawEntry extends CachedSessionEntryBase {\n messageRows: CachedMessageRow[];\n}\n\nexport interface CachedSessionCursorEntry extends CachedSessionEntryBase {\n messageCount: number;\n messageDigest: string | null;\n}\n\nexport interface CachedSessionCursorReader {\n messageDigest(messageCount: number): string | null;\n messageRows(startIndex: number): CachedMessageRow[];\n}\n\nexport type SessionSnapshotCompleteness = \"complete\" | \"partial\";\n\nexport interface SaveCachedSessionsOptions {\n completeness?: SessionSnapshotCompleteness;\n removedSessionIds?: readonly string[];\n}\n\nfunction parseCachedSessionMeta(value: string | null | undefined): SessionCacheMeta | null {\n if (!value) return null;\n try {\n return JSON.parse(value) as SessionCacheMeta;\n } catch {\n return null;\n }\n}\n\nexport function deleteLegacyCacheFile(): void {\n const legacyPath = getLegacyCachePath();\n if (!existsSync(legacyPath)) {\n return;\n }\n\n try {\n unlinkSync(legacyPath);\n } catch {\n // Ignore legacy cleanup errors\n }\n}\n\n/**\n * Distinguishes \"no cache yet\" (success with null) from \"the database read\n * failed\" so callers can log the degradation instead of silently rescanning.\n */\nexport function readCachedSessions(agentName: string): CacheReadOutcome<CachedResult | null> {\n if (!hasCacheStorage()) {\n return { status: \"success\", value: null };\n }\n\n return withCacheDbOutcome((db) => {\n const timestampRow = db\n .prepare(\"SELECT timestamp AS value FROM agent_cache WHERE agent_name = ?\")\n .get(agentName) as ScalarRow | undefined;\n const timestamp = Number(timestampRow?.value ?? 0);\n\n if (!timestamp) {\n return null;\n }\n\n const rows = db\n .prepare(\n `\n SELECT ${SESSION_HEAD_SELECT_COLUMNS}\n FROM sessions s\n WHERE s.agent_name = ? AND s.publication_id IS NULL\n ORDER BY s.activity_time DESC, s.session_id\n `,\n )\n .all(agentName) as SessionRow[];\n\n const sessions: SessionHead[] = [];\n const meta: Record<string, SessionCacheMeta> = {};\n\n for (const row of rows) {\n const session = sessionFromRow(row);\n sessions.push(session);\n\n if (row.meta_json) {\n meta[session.id] = JSON.parse(row.meta_json) as SessionCacheMeta;\n }\n }\n\n return { sessions, meta, timestamp };\n });\n}\n\nexport function loadCachedSessions(agentName: string): CachedResult | null {\n const outcome = readCachedSessions(agentName);\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\nexport function loadCachedSessionHeads(\n references: readonly SessionReference[],\n): ReferencedSessionHead[] {\n if (references.length === 0 || !hasCacheStorage()) return [];\n\n const unique = new Map<string, SessionReference>();\n for (const reference of references) {\n const normalized = normalizeSessionReference(reference);\n const key = formatSessionReference(normalized);\n if (!unique.has(key)) unique.set(key, normalized);\n }\n\n const outcome = withCacheDbReadOnly((db) => {\n const resolved: ReferencedSessionHead[] = [];\n const normalized = [...unique.values()];\n for (let offset = 0; offset < normalized.length; offset += SESSION_REFERENCE_QUERY_CHUNK_SIZE) {\n const chunk = normalized.slice(offset, offset + SESSION_REFERENCE_QUERY_CHUNK_SIZE);\n const values = chunk.map(() => \"(?, ?)\").join(\", \");\n const params = chunk.flatMap((reference) => [reference.agentName, reference.sessionId]);\n const rows = db\n .prepare(\n `\n WITH requested(agent_name, session_id) AS (\n VALUES ${values}\n )\n SELECT ${SESSION_HEAD_SELECT_COLUMNS}\n FROM requested r\n JOIN sessions s\n ON s.agent_name = r.agent_name\n AND s.session_id = r.session_id\n AND s.publication_id IS NULL\n `,\n )\n .all(...params) as SessionRow[];\n\n for (const row of rows) {\n resolved.push({\n reference: normalizeSessionReference({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n }),\n session: sessionFromRow(row),\n });\n }\n }\n return resolved;\n });\n return outcome.status === \"success\" ? outcome.value : [];\n}\n\nexport function readAgentCacheInitialization(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): CacheReadOutcome<boolean> {\n if (!hasCacheStorage()) {\n return { status: \"success\", value: false };\n }\n\n return withCacheDbReadOnly((db) => {\n if (!tableExists(db, \"cache_initialization\")) return false;\n const row = db\n .prepare(\n `\n SELECT index_version\n FROM cache_initialization\n WHERE agent_name = ?\n `,\n )\n .get(agentName) as { index_version?: string } | undefined;\n return row?.index_version === indexVersion;\n });\n}\n\nexport function isAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): boolean {\n const outcome = readAgentCacheInitialization(agentName, indexVersion);\n return outcome.status === \"success\" && outcome.value;\n}\n\n/**\n * Marks the cache as warm/usable so refreshes can rely on incremental checks\n * instead of a raw full scan. This is deliberately independent of full-history\n * reconciliation: a first scan may be bounded to a display window, so\n * last_sync_at defaults to 0 (never synced) here and is only advanced by\n * markAgentFullSyncCompleted once a genuine unbounded pass completes.\n */\nexport function markAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): void {\n withCacheDb((db) => {\n db.prepare(\n `\n INSERT INTO cache_initialization(agent_name, initialized_at, index_version, last_sync_at)\n VALUES (?, ?, ?, 0)\n ON CONFLICT(agent_name) DO UPDATE SET\n index_version = excluded.index_version\n `,\n ).run(agentName, Date.now(), indexVersion);\n });\n}\n\n/**\n * Mark a full-history reconciliation as incomplete until it commits.\n * Returns whether the write reached disk, like saveCachedSessions.\n */\nexport function markAgentFullSyncStarted(agentName: string): boolean {\n const persisted = withCacheDb((db) => {\n db.prepare(\n `\n UPDATE cache_initialization\n SET last_sync_at = 0\n WHERE agent_name = ?\n `,\n ).run(agentName);\n return true;\n });\n return persisted ?? false;\n}\n\n/** Return the last durable source position reached by an incomplete full sync. */\nexport function getAgentFullSyncCursor(agentName: string): string | null {\n if (!hasCacheStorage()) return null;\n\n const outcome = withCacheDbReadOnly((db) => {\n const row = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(`${FULL_SYNC_CURSOR_PREFIX}${agentName}`) as { value?: string } | undefined;\n return row?.value || null;\n });\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\n/**\n * Persist a full-sync cursor only after the corresponding checkpoint is\n * durable. Returns whether the write reached disk — a dropped cursor means\n * every restart re-walks the whole history, so callers must not report the\n * checkpoint as durable on false.\n */\nexport function markAgentFullSyncProgress(agentName: string, cursor: string): boolean {\n if (!cursor) return true;\n\n const persisted = withCacheDb((db) => {\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(`${FULL_SYNC_CURSOR_PREFIX}${agentName}`, cursor);\n return true;\n });\n return persisted ?? false;\n}\n\nexport function readAgentLastFullSyncAt(agentName: string): CacheReadOutcome<number | null> {\n if (!hasCacheStorage()) {\n return { status: \"success\", value: null };\n }\n\n return withCacheDbReadOnly((db) => {\n if (!tableExists(db, \"cache_initialization\")) return null;\n const row = db\n .prepare(\n `\n SELECT last_sync_at\n FROM cache_initialization\n WHERE agent_name = ?\n `,\n )\n .get(agentName) as { last_sync_at?: number } | undefined;\n return row?.last_sync_at || null;\n });\n}\n\n/** Timestamp of the agent's last full (unbounded) history reconciliation, or null if none yet. */\nexport function getAgentLastFullSyncAt(agentName: string): number | null {\n const outcome = readAgentLastFullSyncAt(agentName);\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\n/**\n * Record that a full (unbounded) history reconciliation just completed for\n * this agent. Returns whether the write reached disk.\n */\nexport function markAgentFullSyncCompleted(agentName: string): boolean {\n const completedAt = Date.now();\n const persisted = withCacheDb((db) => {\n db.transaction(() => {\n // Upsert: on a fresh cache the initialization row may not exist yet,\n // and a bare UPDATE would silently record nothing (last_sync_at would\n // read back as \"never synced\" and re-trigger a full backfill).\n db.prepare(\n `\n INSERT INTO cache_initialization(agent_name, initialized_at, index_version, last_sync_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET\n last_sync_at = excluded.last_sync_at\n `,\n ).run(agentName, completedAt, CACHE_INITIALIZATION_VERSION, completedAt);\n db.prepare(\"DELETE FROM cache_meta WHERE key = ?\").run(\n `${FULL_SYNC_CURSOR_PREFIX}${agentName}`,\n );\n }).immediate();\n return true;\n });\n return persisted ?? false;\n}\n\nfunction loadCachedSessionEntryBase(\n db: SQLiteDatabase,\n agentName: string,\n sessionId: string,\n): CachedSessionEntryBase | null {\n const row = db\n .prepare(\n `\n SELECT\n sessions.*,\n documents.detail_version AS detail_version\n FROM sessions\n LEFT JOIN session_documents AS documents\n ON documents.agent_name = sessions.agent_name\n AND documents.session_id = sessions.session_id\n WHERE sessions.agent_name = ?\n AND sessions.session_id = ?\n AND sessions.publication_id IS NULL\n `,\n )\n .get(agentName, sessionId) as SessionRow | undefined;\n\n if (!row) return null;\n\n const pendingReindex =\n db\n .prepare(\"SELECT 1 FROM pending_reindex WHERE agent_name = ? AND session_id = ?\")\n .get(agentName, sessionId) != null;\n const fileActivityRows = db\n .prepare(\n `\n SELECT agent_name, session_id, project_identity_key, path, kind, count, latest_time\n FROM session_file_activity\n WHERE agent_name = ? AND session_id = ?\n ORDER BY latest_time DESC, count DESC, path\n LIMIT 500\n `,\n )\n .all(agentName, sessionId) as FileActivityRow[];\n\n return {\n data: {\n ...sessionFromRow(row),\n reference: { agentName, sessionId },\n file_activity: fileActivityRows.map((activityRow) => fileActivityFromRow(activityRow)),\n },\n meta: parseCachedSessionMeta(row.meta_json),\n detailVersion: typeof row.detail_version === \"string\" ? row.detail_version : null,\n pendingReindex,\n };\n}\n\nfunction readCachedSessionMessageRows(\n db: SQLiteDatabase,\n agentName: string,\n sessionId: string,\n startIndex: number,\n): CachedMessageRow[] {\n return db\n .prepare(\n `\n SELECT\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n tokens_json,\n cost,\n cost_source,\n parts_json,\n parts_format_version,\n content_chain_digest,\n subagent_id,\n nickname\n FROM messages\n WHERE agent_name = ? AND session_id = ? AND message_index >= ?\n ORDER BY message_index\n `,\n )\n .all(agentName, sessionId, startIndex) as CachedMessageRow[];\n}\n\nexport function loadCachedSessionRawEntry(\n agentName: string,\n sessionId: string,\n): CachedSessionRawEntry | null {\n if (!hasCacheStorage()) return null;\n\n const outcome = withCacheDbReadOnly((db) => {\n const entry = loadCachedSessionEntryBase(db, agentName, sessionId);\n return entry\n ? { ...entry, messageRows: readCachedSessionMessageRows(db, agentName, sessionId, 0) }\n : null;\n });\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\nfunction readCachedSessionMessageDigest(\n db: SQLiteDatabase,\n agentName: string,\n sessionId: string,\n messageCount: number,\n): string | null {\n if (!Number.isSafeInteger(messageCount) || messageCount <= 0) return null;\n const row = db\n .prepare(\n `\n SELECT content_chain_digest\n FROM messages\n WHERE agent_name = ? AND session_id = ? AND message_index = ?\n `,\n )\n .get(agentName, sessionId, messageCount - 1) as { content_chain_digest?: string | null };\n return typeof row?.content_chain_digest === \"string\" ? row.content_chain_digest : null;\n}\n\nexport function readCachedSessionCursor<T>(\n agentName: string,\n sessionId: string,\n read: (entry: CachedSessionCursorEntry, cursor: CachedSessionCursorReader) => T,\n): T | null {\n if (!hasCacheStorage()) return null;\n\n // A deferred transaction keeps cursor metadata and suffix rows in one snapshot.\n const outcome = withCacheDbReadOnly((db) =>\n db.transaction(() => {\n const entryBase = loadCachedSessionEntryBase(db, agentName, sessionId);\n if (!entryBase) return null;\n const messageState = db\n .prepare(\n `\n SELECT\n COUNT(*) AS message_count,\n (\n SELECT content_chain_digest\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n ORDER BY message_index DESC\n LIMIT 1\n ) AS content_chain_digest\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n `,\n )\n .get(agentName, sessionId, agentName, sessionId) as {\n message_count?: number;\n content_chain_digest?: string | null;\n };\n const entry: CachedSessionCursorEntry = {\n ...entryBase,\n messageCount: Number(messageState.message_count ?? 0),\n messageDigest:\n typeof messageState.content_chain_digest === \"string\"\n ? messageState.content_chain_digest\n : null,\n };\n return read(entry, {\n messageDigest: (messageCount) =>\n readCachedSessionMessageDigest(db, agentName, sessionId, messageCount),\n messageRows: (startIndex) =>\n Number.isSafeInteger(startIndex) && startIndex >= 0\n ? readCachedSessionMessageRows(db, agentName, sessionId, startIndex)\n : [],\n });\n })(),\n );\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\nexport function loadCachedSessionDataEntry(\n agentName: string,\n sessionId: string,\n): CachedSessionDataEntry | null {\n const entry = loadCachedSessionRawEntry(agentName, sessionId);\n if (!entry) return null;\n return {\n data: {\n ...entry.data,\n messages: entry.pendingReindex\n ? []\n : entry.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n },\n meta: entry.meta,\n };\n}\n\nexport function loadCachedSessionData(agentName: string, sessionId: string): SessionDetail | null {\n return loadCachedSessionDataEntry(agentName, sessionId)?.data ?? null;\n}\n\n/**\n * Returns whether the write reached disk; on `false`, callers must not mark the cache initialized\n * or a full sync complete.\n */\nexport function saveCachedSessions(\n agentName: string,\n sessions: SessionHead[],\n meta: Record<string, SessionCacheMeta> = {},\n options: SaveCachedSessionsOptions = {},\n): boolean {\n assertSessionProjectIdentities(agentName, sessions);\n const persisted = withCacheDb((db) => {\n db.transaction(() => {\n writeCachedSessionSnapshot(db, agentName, sessions, meta, options);\n advanceAnalyticsRevision(db);\n }).immediate();\n deleteLegacyCacheFile();\n return true;\n });\n\n return persisted ?? false;\n}\n\nexport function writeCachedSessionSnapshot(\n db: SQLiteDatabase,\n agentName: string,\n sessions: SessionHead[],\n meta: Record<string, SessionCacheMeta> = {},\n options: SaveCachedSessionsOptions = {},\n): void {\n const completeness = options.completeness ?? \"complete\";\n const deleteSession = db.prepare(\"DELETE FROM sessions WHERE agent_name = ? AND session_id = ?\");\n const deleteSearchDocument = db.prepare(\n \"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessages = db.prepare(\"DELETE FROM messages WHERE agent_name = ? AND session_id = ?\");\n const deleteModelCost = db.prepare(\n \"DELETE FROM session_model_cost WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteCostSummary = db.prepare(\n \"DELETE FROM session_cost_summary WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessageTools = db.prepare(\n \"DELETE FROM message_tools WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteFileActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const upsertAgent = db.prepare(`\n INSERT INTO agent_cache(agent_name, timestamp)\n VALUES (?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET timestamp = excluded.timestamp\n `);\n const upsertSession = prepareUpsertSession(db);\n const sessionIds = new Set(sessions.map((session) => session.id));\n const existingSessionIds = db\n .prepare(\"SELECT session_id FROM sessions WHERE agent_name = ?\")\n .all(agentName) as SessionRow[];\n\n upsertAgent.run(agentName, Date.now());\n\n const sessionIdsToDelete = new Set(options.removedSessionIds ?? []);\n if (completeness === \"complete\") {\n for (const row of existingSessionIds) {\n const sessionId = String(row.session_id);\n if (!sessionIds.has(sessionId)) sessionIdsToDelete.add(sessionId);\n }\n }\n for (const sessionId of sessionIdsToDelete) {\n deleteSearchDocument.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId);\n deleteMessages.run(agentName, sessionId);\n deleteModelCost.run(agentName, sessionId);\n deleteCostSummary.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteSession.run(agentName, sessionId);\n }\n\n sessions.forEach((session, index) => {\n const sessionMeta = meta[session.id];\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n index,\n sourcePathFromMeta(sessionMeta),\n );\n });\n}\n\n/**\n * Returns whether the write reached disk. On `false`, callers may serve the in-memory result\n * but must not advance the persistence timestamp, initialization marker, or durable baseline.\n */\nexport function saveCachedSessionChanges(\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n meta: Record<string, SessionCacheMeta> = {},\n): boolean {\n assertSessionProjectIdentities(\n agentName,\n changes.map(({ session }) => session),\n );\n const persisted = withCacheDb((db) => {\n db.transaction(() => {\n writeCachedSessionChanges(db, agentName, changes, removedSessionIds, meta);\n if (changes.length > 0 || removedSessionIds.length > 0) {\n advanceAnalyticsRevision(db);\n }\n }).immediate();\n deleteLegacyCacheFile();\n return true;\n });\n\n return persisted ?? false;\n}\n\nexport function writeCachedSessionChanges(\n db: SQLiteDatabase,\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n meta: Record<string, SessionCacheMeta> = {},\n): void {\n const deleteSession = db.prepare(\"DELETE FROM sessions WHERE agent_name = ? AND session_id = ?\");\n const deleteSearchDocument = db.prepare(\n \"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessages = db.prepare(\"DELETE FROM messages WHERE agent_name = ? AND session_id = ?\");\n const deleteModelCost = db.prepare(\n \"DELETE FROM session_model_cost WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteCostSummary = db.prepare(\n \"DELETE FROM session_cost_summary WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessageTools = db.prepare(\n \"DELETE FROM message_tools WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteFileActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const upsertAgent = db.prepare(`\n INSERT INTO agent_cache(agent_name, timestamp)\n VALUES (?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET timestamp = excluded.timestamp\n `);\n const upsertSession = prepareUpsertSession(db);\n\n upsertAgent.run(agentName, Date.now());\n\n for (const sessionId of new Set(removedSessionIds)) {\n deleteSearchDocument.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId);\n deleteMessages.run(agentName, sessionId);\n deleteModelCost.run(agentName, sessionId);\n deleteCostSummary.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteSession.run(agentName, sessionId);\n }\n\n for (const { session, sortIndex } of changes) {\n const sessionMeta = meta[session.id];\n if (!sessionMeta) {\n getCoreDiagnostics()?.warn(\"cache.session_meta_missing\", {\n agent: agentName,\n session_id: session.id,\n });\n }\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n sortIndex,\n sourcePathFromMeta(sessionMeta),\n );\n }\n}\n\nexport function clearCache(): void {\n closeCacheStorage();\n if (!hasCacheStorage()) {\n deleteLegacyCacheFile();\n return;\n }\n\n withCacheDb((db) => {\n db.transaction(() => {\n db.exec(`\n DELETE FROM agent_cache;\n DELETE FROM cache_initialization;\n DELETE FROM cached_sessions;\n DELETE FROM pending_reindex;\n DELETE FROM search_index_publication_entries;\n DELETE FROM session_documents;\n DELETE FROM session_file_activity;\n DELETE FROM message_tools;\n DELETE FROM messages;\n DELETE FROM session_model_cost;\n DELETE FROM session_cost_summary;\n DELETE FROM sessions;\n DELETE FROM project_sessions;\n -- analytics_revision is an invalidation counter, not cached data.\n DELETE FROM cache_meta WHERE key <> 'analytics_revision';\n `);\n advanceAnalyticsRevision(db);\n }).immediate();\n });\n closeCacheStorage();\n\n deleteLegacyCacheFile();\n\n const cachePath = getCachePath();\n const walPath = `${cachePath}-wal`;\n const shmPath = `${cachePath}-shm`;\n\n for (const filePath of [walPath, shmPath]) {\n if (!existsSync(filePath)) {\n continue;\n }\n try {\n rmSync(filePath, { force: true });\n } catch {\n // Ignore sidecar cleanup errors\n }\n }\n}\n\nexport function getCacheInfo(): { lastScanTime: number | null; size: number } {\n if (!hasCacheStorage()) {\n return { lastScanTime: null, size: 0 };\n }\n\n const info = withCacheDb((db) => {\n const timestampRow = db.prepare(\"SELECT MAX(timestamp) AS value FROM agent_cache\").get() as\n | ScalarRow\n | undefined;\n const sizeRow = db\n .prepare(\"SELECT COUNT(*) AS value FROM sessions WHERE publication_id IS NULL\")\n .get() as ScalarRow | undefined;\n\n const lastScanTime = Number(timestampRow?.value ?? 0) || null;\n const size = Number(sizeRow?.value ?? 0);\n\n return { lastScanTime, size };\n });\n\n return info ?? { lastScanTime: null, size: 0 };\n}\n","/** Cache paths, process-local connections, and shared query helpers. */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport { openDb, type DatabaseRow, type SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { SessionHead } from \"../../types/index.js\";\n\nconst CACHE_FILENAME = \"codesesh.db\";\nconst LEGACY_CACHE_FILENAME = \"scan-cache.json\";\nexport const SEARCH_INDEX_BULK_SYNC_THRESHOLD = 100;\n\nexport interface PersistedSessionHeadChange {\n session: SessionHead;\n sortIndex: number;\n}\n\nexport interface ScalarRow extends DatabaseRow {\n value?: number;\n}\n\nexport interface CacheRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n session_json?: string;\n meta_json?: string | null;\n sort_index?: number;\n}\n\nexport type SQLiteStatement = ReturnType<SQLiteDatabase[\"prepare\"]>;\n\nexport interface CacheConnection {\n db: SQLiteDatabase;\n ftsReady: boolean;\n publicationStagingCleaned: boolean;\n}\n\nconst cacheConnections = new Map<string, CacheConnection>();\nlet schemaEnsuredPath: string | null = null;\n\nexport function getCacheConnection(path: string): CacheConnection | null {\n const cached = cacheConnections.get(path);\n if (cached) return cached;\n\n const db = openDb(path);\n if (!db) return null;\n\n const connection = { db, ftsReady: false, publicationStagingCleaned: false };\n cacheConnections.set(path, connection);\n return connection;\n}\n\nexport function discardCacheConnection(path: string, connection: CacheConnection): void {\n if (cacheConnections.get(path) !== connection) return;\n cacheConnections.delete(path);\n closeConnection(path, connection);\n}\n\nfunction closeConnection(path: string, connection: CacheConnection): void {\n try {\n connection.db.close();\n } catch (error) {\n getCoreDiagnostics()?.warn(\"cache.close_failed\", {\n dbPath: path,\n message: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nexport function closeCacheStorage(): void {\n const connections = [...cacheConnections];\n cacheConnections.clear();\n schemaEnsuredPath = null;\n for (const [path, connection] of connections) closeConnection(path, connection);\n}\n\nexport function getSchemaEnsuredPath(): string | null {\n return schemaEnsuredPath;\n}\n\nexport function setSchemaEnsuredPath(path: string | null): void {\n if (path === null) {\n closeCacheStorage();\n return;\n }\n schemaEnsuredPath = path;\n}\n\nexport function getCacheDir(): string {\n return join(homedir(), \".cache\", \"codesesh\");\n}\n\nexport function getCachePath(): string {\n return join(getCacheDir(), CACHE_FILENAME);\n}\n\nexport function getLegacyCachePath(): string {\n return join(getCacheDir(), LEGACY_CACHE_FILENAME);\n}\n\nexport function hasCacheStorage(): boolean {\n return existsSync(getCachePath());\n}\n\nexport function likePattern(value: string): string {\n return `%${value\n .trim()\n .toLowerCase()\n .replace(/[\\\\%_]/g, \"\\\\$&\")}%`;\n}\n\nexport function filePathFtsQuery(value: string): string | null {\n const path = normalizeFilePathSearch(value);\n if (path.length < 3) return null;\n return `\"${path.replaceAll('\"', '\"\"')}\"`;\n}\n\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport function normalizeFilePathSearch(value: string): string {\n return value.trim().replace(/^\"|\"$/g, \"\");\n}\n","/**\n * Structured message storage: row ↔ domain mapping, prepared-statement\n * binders, and message-text builders shared by sessions/search/file-activity.\n */\nimport type { SessionCacheMeta } from \"../../agents/base.js\";\nimport type {\n Message,\n MessagePart,\n ProjectIdentity,\n ProjectIdentityKind,\n SessionDetail,\n SessionFileActivity,\n SessionHead,\n ToolPart,\n} from \"../../types/index.js\";\nimport { normalizeMessageParts } from \"../../contract/message-part.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { SQLiteStatement } from \"./db.js\";\nimport type { MessageCursorContent } from \"./message-cursor.js\";\n\nexport const MESSAGE_PARTS_FORMAT_VERSION = 1;\n\nexport interface SessionRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n sort_index?: number;\n slug?: string;\n title?: string;\n source_path?: string | null;\n directory?: string;\n parent_agent_name?: string | null;\n parent_session_id?: string | null;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n project_identity_resolver_revision?: string | null;\n project_identity_input_signature?: string | null;\n time_created?: number;\n time_updated?: number | null;\n activity_time?: number;\n message_count?: number;\n total_input_tokens?: number;\n total_output_tokens?: number;\n total_cache_read_tokens?: number | null;\n total_cache_create_tokens?: number | null;\n total_cost?: number;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"] | null;\n total_tokens?: number | null;\n model_usage_json?: string | null;\n smart_tags_json?: string | null;\n smart_tags_source_updated_at?: number | null;\n smart_tags_classifier_revision?: string | null;\n meta_json?: string | null;\n}\n\nexport interface MessageBackfillRow extends DatabaseRow {\n message_id?: string;\n role?: Message[\"role\"];\n time_created?: number;\n time_completed?: number | null;\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n parts_json?: string;\n subagent_id?: string | null;\n nickname?: string | null;\n}\n\nexport interface CachedMessageRow extends MessageBackfillRow {\n parts_format_version?: number | string;\n content_chain_digest?: string | null;\n tokens_json?: string | null;\n cost?: number | null;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"] | null;\n}\n\nexport interface StructuredMessageRecord {\n index: number;\n id: string;\n role: Message[\"role\"];\n timeCreated: number;\n timeCompleted?: number | null;\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n tokensJson?: string | null;\n cost?: number | null;\n costSource?: string | null;\n partsJson: string;\n subagentId?: string | null;\n nickname?: string | null;\n contentText: string;\n toolMetadataJson?: string | null;\n toolNames: string[];\n}\n\nexport function messageCursorContentFromCachedRow(row: CachedMessageRow): MessageCursorContent {\n return {\n messageId: String(row.message_id),\n role: String(row.role),\n timeCreated: Number(row.time_created),\n timeCompleted: row.time_completed,\n agent: row.agent,\n mode: row.mode,\n model: row.model,\n provider: row.provider,\n tokensJson: row.tokens_json,\n cost: row.cost,\n costSource: row.cost_source,\n partsJson: String(row.parts_json),\n partsFormatVersion: row.parts_format_version,\n subagentId: row.subagent_id,\n nickname: row.nickname,\n };\n}\n\nexport function messageCursorContentFromStructuredRecord(\n record: StructuredMessageRecord,\n): MessageCursorContent {\n return {\n messageId: record.id,\n role: record.role,\n timeCreated: record.timeCreated,\n timeCompleted: record.timeCompleted,\n agent: record.agent,\n mode: record.mode,\n model: record.model,\n provider: record.provider,\n tokensJson: record.tokensJson,\n cost: record.cost,\n costSource: record.costSource,\n partsJson: record.partsJson,\n partsFormatVersion: MESSAGE_PARTS_FORMAT_VERSION,\n subagentId: record.subagentId,\n nickname: record.nickname,\n };\n}\n\nexport function stringifyOptionalJson(value: unknown): string | null {\n return value == null ? null : JSON.stringify(value);\n}\n\nexport function parseOptionalJson<T>(value: unknown): T | undefined {\n return value == null ? undefined : (JSON.parse(String(value)) as T);\n}\n\nexport function sourcePathFromMeta(meta: SessionCacheMeta | undefined): string | null {\n return typeof meta?.sourcePath === \"string\" ? meta.sourcePath : null;\n}\n\nexport function sourcePathFromMetaJson(metaJson: string | null | undefined): string | null {\n if (!metaJson) return null;\n const meta = JSON.parse(metaJson) as SessionCacheMeta;\n return sourcePathFromMeta(meta);\n}\n\nexport function requireSessionProjectIdentity(\n agentName: string,\n session: SessionHead,\n): ProjectIdentity {\n if (session.project_identity) return session.project_identity;\n throw new Error(`Session ${agentName}/${session.id} is missing project_identity`);\n}\n\nexport function assertSessionProjectIdentities(\n agentName: string,\n sessions: Iterable<SessionHead>,\n): void {\n for (const session of sessions) requireSessionProjectIdentity(agentName, session);\n}\n\nexport function prepareUpsertSession(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT INTO sessions(\n agent_name,\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n parent_agent_name,\n parent_session_id,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n project_identity_resolver_revision,\n project_identity_input_signature,\n time_created,\n time_updated,\n activity_time,\n message_count,\n total_input_tokens,\n total_output_tokens,\n total_cache_read_tokens,\n total_cache_create_tokens,\n total_cost,\n cost_source,\n total_tokens,\n model_usage_json,\n smart_tags_json,\n smart_tags_source_updated_at,\n smart_tags_classifier_revision,\n meta_json,\n publication_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n sort_index = excluded.sort_index,\n slug = excluded.slug,\n title = excluded.title,\n source_path = CASE\n WHEN excluded.meta_json IS NULL THEN sessions.source_path\n ELSE excluded.source_path\n END,\n directory = excluded.directory,\n parent_agent_name = excluded.parent_agent_name,\n parent_session_id = excluded.parent_session_id,\n project_identity_kind = excluded.project_identity_kind,\n project_identity_key = excluded.project_identity_key,\n project_display_name = excluded.project_display_name,\n project_identity_resolver_revision = excluded.project_identity_resolver_revision,\n project_identity_input_signature = excluded.project_identity_input_signature,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n activity_time = excluded.activity_time,\n message_count = excluded.message_count,\n total_input_tokens = excluded.total_input_tokens,\n total_output_tokens = excluded.total_output_tokens,\n total_cache_read_tokens = excluded.total_cache_read_tokens,\n total_cache_create_tokens = excluded.total_cache_create_tokens,\n total_cost = excluded.total_cost,\n cost_source = excluded.cost_source,\n total_tokens = excluded.total_tokens,\n model_usage_json = excluded.model_usage_json,\n smart_tags_json = excluded.smart_tags_json,\n smart_tags_source_updated_at = excluded.smart_tags_source_updated_at,\n smart_tags_classifier_revision = excluded.smart_tags_classifier_revision,\n meta_json = COALESCE(excluded.meta_json, sessions.meta_json),\n publication_id = excluded.publication_id\n `);\n}\n\nfunction prepareIndexedSession(db: SQLiteDatabase): SQLiteStatement {\n const onConflict = `DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\n parent_agent_name = excluded.parent_agent_name,\n parent_session_id = excluded.parent_session_id,\n project_identity_kind = excluded.project_identity_kind,\n project_identity_key = excluded.project_identity_key,\n project_display_name = excluded.project_display_name,\n project_identity_resolver_revision = excluded.project_identity_resolver_revision,\n project_identity_input_signature = excluded.project_identity_input_signature,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n activity_time = excluded.activity_time,\n message_count = excluded.message_count,\n total_input_tokens = excluded.total_input_tokens,\n total_output_tokens = excluded.total_output_tokens,\n total_cache_read_tokens = excluded.total_cache_read_tokens,\n total_cache_create_tokens = excluded.total_cache_create_tokens,\n total_cost = excluded.total_cost,\n cost_source = excluded.cost_source,\n total_tokens = excluded.total_tokens,\n model_usage_json = excluded.model_usage_json,\n smart_tags_json = excluded.smart_tags_json,\n smart_tags_source_updated_at = excluded.smart_tags_source_updated_at,\n smart_tags_classifier_revision = excluded.smart_tags_classifier_revision,\n publication_id = excluded.publication_id`;\n return db.prepare(`\n INSERT INTO sessions(\n agent_name,\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n parent_agent_name,\n parent_session_id,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n project_identity_resolver_revision,\n project_identity_input_signature,\n time_created,\n time_updated,\n activity_time,\n message_count,\n total_input_tokens,\n total_output_tokens,\n total_cache_read_tokens,\n total_cache_create_tokens,\n total_cost,\n cost_source,\n total_tokens,\n model_usage_json,\n smart_tags_json,\n smart_tags_source_updated_at,\n smart_tags_classifier_revision,\n meta_json,\n publication_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) ${onConflict}\n `);\n}\n\nexport function prepareUpsertIndexedSession(db: SQLiteDatabase): SQLiteStatement {\n return prepareIndexedSession(db);\n}\n\nexport function upsertSessionRow(\n statement: SQLiteStatement,\n agentName: string,\n session: SessionHead,\n metaJson: string | null,\n sortIndex: number,\n sourcePath: string | null,\n): void {\n const identity = requireSessionProjectIdentity(agentName, session);\n const activityTime = session.time_updated ?? session.time_created;\n statement.run(\n agentName,\n session.id,\n sortIndex,\n session.slug,\n session.title,\n sourcePath,\n session.directory,\n session.parent_reference?.agentName ?? null,\n session.parent_reference?.sessionId ?? null,\n identity.kind,\n identity.key,\n identity.displayName,\n session.project_identity_resolver_revision ?? null,\n session.project_identity_input_signature ?? null,\n session.time_created,\n session.time_updated ?? null,\n activityTime,\n session.stats.message_count,\n session.stats.total_input_tokens,\n session.stats.total_output_tokens,\n session.stats.total_cache_read_tokens ?? null,\n session.stats.total_cache_create_tokens ?? null,\n session.stats.total_cost,\n session.stats.cost_source ?? null,\n session.stats.total_tokens ?? null,\n stringifyOptionalJson(session.model_usage),\n stringifyOptionalJson(session.smart_tags),\n session.smart_tags_source_updated_at ?? null,\n session.smart_tags_classifier_revision ?? null,\n metaJson,\n null,\n );\n}\n\nexport function prepareInsertFileActivity(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT INTO session_file_activity(\n agent_name,\n session_id,\n project_identity_key,\n path,\n kind,\n count,\n latest_time\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n}\n\nexport function prepareInsertMessageTool(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT OR IGNORE INTO message_tools(\n agent_name,\n session_id,\n message_index,\n tool_name\n ) VALUES (?, ?, ?, ?)\n `);\n}\n\nexport function writeFileActivityRows(\n statement: SQLiteStatement,\n activities: SessionFileActivity[],\n): void {\n for (const activity of activities) {\n statement.run(\n activity.reference.agentName,\n activity.reference.sessionId,\n activity.projectIdentityKey,\n activity.path,\n activity.kind,\n activity.count,\n activity.latestTime,\n );\n }\n}\n\nexport function sessionFromRow(row: SessionRow): SessionHead {\n const session: SessionHead = {\n id: String(row.session_id),\n slug: String(row.slug),\n title: String(row.title),\n directory: String(row.directory),\n time_created: Number(row.time_created),\n stats: {\n message_count: Number(row.message_count ?? 0),\n total_input_tokens: Number(row.total_input_tokens ?? 0),\n total_output_tokens: Number(row.total_output_tokens ?? 0),\n total_cost: Number(row.total_cost ?? 0),\n },\n };\n\n if (row.project_identity_key) {\n session.project_identity = {\n kind: row.project_identity_kind ?? \"path\",\n key: String(row.project_identity_key),\n displayName: String(row.project_display_name ?? \"\"),\n };\n }\n if (row.project_identity_resolver_revision) {\n session.project_identity_resolver_revision = String(row.project_identity_resolver_revision);\n }\n if (row.project_identity_input_signature) {\n session.project_identity_input_signature = String(row.project_identity_input_signature);\n }\n if (row.parent_agent_name && row.parent_session_id) {\n session.parent_reference = {\n agentName: String(row.parent_agent_name),\n sessionId: String(row.parent_session_id),\n };\n }\n if (row.time_updated != null) {\n session.time_updated = Number(row.time_updated);\n }\n if (row.total_cache_read_tokens != null) {\n session.stats.total_cache_read_tokens = Number(row.total_cache_read_tokens);\n }\n if (row.total_cache_create_tokens != null) {\n session.stats.total_cache_create_tokens = Number(row.total_cache_create_tokens);\n }\n if (row.cost_source) {\n session.stats.cost_source = row.cost_source;\n }\n if (row.total_tokens != null) {\n session.stats.total_tokens = Number(row.total_tokens);\n }\n\n const modelUsage = parseOptionalJson<Record<string, number>>(row.model_usage_json);\n if (modelUsage) {\n session.model_usage = modelUsage;\n }\n\n const smartTags = parseOptionalJson<SessionHead[\"smart_tags\"]>(row.smart_tags_json);\n if (smartTags) {\n session.smart_tags = smartTags;\n }\n if (row.smart_tags_source_updated_at != null) {\n session.smart_tags_source_updated_at = Number(row.smart_tags_source_updated_at);\n }\n if (row.smart_tags_classifier_revision) {\n session.smart_tags_classifier_revision = String(row.smart_tags_classifier_revision);\n }\n\n return session;\n}\n\nfunction messageMetadataFromBackfillRow(row: MessageBackfillRow): Omit<Message, \"parts\"> {\n const role = row.role === \"assistant\" || row.role === \"tool\" ? row.role : \"user\";\n return {\n id: String(row.message_id ?? \"\"),\n role,\n agent: row.agent ?? null,\n time_created: Number(row.time_created ?? 0),\n time_completed: row.time_completed == null ? null : Number(row.time_completed),\n mode: row.mode ?? null,\n model: row.model ?? null,\n provider: row.provider ?? null,\n subagent_id: row.subagent_id ?? undefined,\n nickname: row.nickname ?? undefined,\n };\n}\n\nfunction messageMetadataFromCachedRow(row: CachedMessageRow): Omit<Message, \"parts\"> {\n const message = messageMetadataFromBackfillRow(row);\n const tokens = parseOptionalJson<Message[\"tokens\"]>(row.tokens_json);\n if (tokens) {\n message.tokens = tokens;\n }\n if (row.cost != null) {\n message.cost = Number(row.cost);\n }\n if (row.cost_source) {\n message.cost_source = row.cost_source;\n }\n return message;\n}\n\nexport function messageFromBackfillRow(row: MessageBackfillRow): Message {\n return {\n ...messageMetadataFromBackfillRow(row),\n parts: messagePartsFromJson(row.parts_json),\n };\n}\n\nexport function messageFromCachedRow(row: CachedMessageRow): Message {\n return {\n ...messageMetadataFromCachedRow(row),\n parts: messagePartsFromJson(row.parts_json),\n };\n}\n\nfunction messagePartsFromJson(value: unknown): MessagePart[] {\n try {\n return normalizeMessageParts(JSON.parse(String(value ?? \"[]\")));\n } catch {\n return [];\n }\n}\n\nexport function normalizeMessagePartsJson(value: unknown): string {\n return JSON.stringify(messagePartsFromJson(value));\n}\n\nexport function messageJsonFromCachedRow(row: CachedMessageRow): string {\n const metadataJson = JSON.stringify(messageMetadataFromBackfillRow(row));\n const fields: string[] = [];\n if (row.tokens_json != null) {\n fields.push(`\"tokens\":${String(row.tokens_json)}`);\n }\n if (row.cost != null) {\n fields.push(`\"cost\":${JSON.stringify(Number(row.cost))}`);\n }\n if (row.cost_source) {\n fields.push(`\"cost_source\":${JSON.stringify(row.cost_source)}`);\n }\n const partsJson =\n Number(row.parts_format_version) >= MESSAGE_PARTS_FORMAT_VERSION\n ? String(row.parts_json ?? \"[]\")\n : normalizeMessagePartsJson(row.parts_json);\n fields.push(`\"parts\":${partsJson}`);\n return `${metadataJson.slice(0, -1)},${fields.join(\",\")}}`;\n}\n\nexport function appendPlainText(value: unknown, chunks: string[]): void {\n if (value == null) return;\n\n if (typeof value === \"string\") {\n const normalized = value.trim();\n if (normalized) {\n chunks.push(normalized);\n }\n return;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n chunks.push(String(value));\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n appendPlainText(item, chunks);\n }\n return;\n }\n\n if (typeof value === \"object\") {\n for (const nested of Object.values(value as Record<string, unknown>)) {\n appendPlainText(nested, chunks);\n }\n }\n}\n\nexport function compactRecord(record: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(record).filter(([, value]) => value != null));\n}\n\nexport function normalizeToolName(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const name = value.trim().toLowerCase();\n return name || null;\n}\n\nexport function toolNamesFromMetadataJson(value: unknown): string[] {\n if (!value) return [];\n\n try {\n const metadata = JSON.parse(String(value));\n if (!Array.isArray(metadata)) return [];\n const tools = new Set<string>();\n for (const item of metadata) {\n if (item == null || typeof item !== \"object\") continue;\n const toolName = normalizeToolName((item as Record<string, unknown>).tool);\n if (toolName) tools.add(toolName);\n }\n return [...tools];\n } catch {\n return [];\n }\n}\n\nexport function toolNamesFromMessage(message: Message): string[] {\n const tools = new Set<string>();\n for (const part of message.parts) {\n if (part.type !== \"tool\") continue;\n const toolName = normalizeToolName(part.tool);\n if (toolName) tools.add(toolName);\n }\n return [...tools];\n}\n\nexport function summarizeToolPart(part: ToolPart): Record<string, unknown> {\n const state = compactRecord({\n status: part.state.status,\n error: part.state.error,\n metadata: part.state.metadata,\n });\n return compactRecord({\n type: part.type,\n tool: part.tool,\n title: part.title,\n callID: part.callID,\n state,\n });\n}\n\nexport function buildMessageText(message: Message): string {\n const chunks: string[] = [];\n\n chunks.push(message.role);\n appendPlainText(message.agent, chunks);\n appendPlainText(message.model, chunks);\n\n for (const part of message.parts) {\n appendPlainText(part.type, chunks);\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"plan\") {\n appendPlainText(part.text, chunks);\n } else if (part.type === \"tool\") {\n appendPlainText(part.title, chunks);\n appendPlainText(part.tool, chunks);\n appendPlainText(part.state, chunks);\n }\n }\n\n return chunks.join(\"\\n\");\n}\n\nexport function normalizeMessages(session: SessionDetail): StructuredMessageRecord[] {\n return session.messages.map((message, index) => {\n const toolMetadata = message.parts\n .filter((part): part is ToolPart => part.type === \"tool\")\n .map((part) => summarizeToolPart(part));\n\n return {\n index,\n id: message.id || `${session.id}:${index}`,\n role: message.role,\n timeCreated: message.time_created,\n timeCompleted: message.time_completed ?? null,\n agent: message.agent ?? null,\n mode: message.mode ?? null,\n model: message.model ?? null,\n provider: message.provider ?? null,\n tokensJson: stringifyOptionalJson(message.tokens),\n cost: message.cost ?? null,\n costSource: message.cost_source ?? null,\n partsJson: JSON.stringify(message.parts),\n subagentId: message.subagent_id ?? null,\n nickname: message.nickname ?? null,\n contentText: buildMessageText(message),\n toolMetadataJson: toolMetadata.length > 0 ? JSON.stringify(toolMetadata) : null,\n toolNames: toolNamesFromMessage(message),\n };\n });\n}\n\nexport function buildSessionContentFromMessages(\n title: string | null | undefined,\n messages: StructuredMessageRecord[],\n): string {\n const chunks: string[] = [];\n appendPlainText(title, chunks);\n for (const message of messages) {\n appendPlainText(message.contentText, chunks);\n }\n return chunks.join(\"\\n\");\n}\n","import type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\n\ninterface StagedPublicationRow extends DatabaseRow {\n session_id?: string;\n payload_json?: string;\n}\n\nconst PUBLICATION_READ_BATCH_SIZE = 64;\n\nexport interface PublicationPayload {\n sessionId: string;\n json: string;\n}\n\nexport function createPublicationStagingTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS search_index_publication_entries (\n publication_id TEXT NOT NULL,\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n payload_json TEXT NOT NULL,\n PRIMARY KEY (publication_id, agent_name, session_id)\n );\n `);\n}\n\nexport function stagePublicationPayloads(\n db: SQLiteDatabase,\n publicationId: string,\n agentName: string,\n payloads: Iterable<PublicationPayload>,\n): number {\n const upsert = db.prepare(`\n INSERT INTO search_index_publication_entries(\n publication_id,\n agent_name,\n session_id,\n payload_json\n ) VALUES (?, ?, ?, ?)\n ON CONFLICT(publication_id, agent_name, session_id) DO UPDATE SET\n payload_json = excluded.payload_json\n `);\n let staged = 0;\n for (const payload of payloads) {\n upsert.run(publicationId, agentName, payload.sessionId, payload.json);\n staged += 1;\n }\n return staged;\n}\n\nexport function* readPublicationPayloads(\n db: SQLiteDatabase,\n publicationId: string,\n agentName: string,\n): Generator<string> {\n const readBatch = db.prepare(`\n SELECT session_id, payload_json\n FROM search_index_publication_entries\n WHERE publication_id = ? AND agent_name = ? AND session_id > ?\n ORDER BY session_id\n LIMIT ?\n `);\n let cursor = \"\";\n while (true) {\n const rows = readBatch.all(\n publicationId,\n agentName,\n cursor,\n PUBLICATION_READ_BATCH_SIZE,\n ) as StagedPublicationRow[];\n if (rows.length === 0) return;\n for (const row of rows) yield String(row.payload_json ?? \"\");\n cursor = String(rows.at(-1)?.session_id ?? \"\");\n }\n}\n\nexport function deletePublicationPayloads(db: SQLiteDatabase, publicationId: string): void {\n db.prepare(\"DELETE FROM search_index_publication_entries WHERE publication_id = ?\").run(\n publicationId,\n );\n}\n\nfunction hasLegacyPublicationRows(db: SQLiteDatabase, publicationId?: string): boolean {\n const predicate = publicationId ? \"publication_id = ?\" : \"publication_id IS NOT NULL\";\n const params = publicationId ? [publicationId] : [];\n return (\n db.prepare(`SELECT 1 FROM sessions WHERE ${predicate} LIMIT 1`).get(...params) !== undefined\n );\n}\n\nexport function hasPublicationStaging(db: SQLiteDatabase): boolean {\n const payload = db.prepare(\"SELECT 1 FROM search_index_publication_entries LIMIT 1\").get();\n return payload !== undefined || hasLegacyPublicationRows(db);\n}\n\nfunction deleteLegacyPublicationRows(db: SQLiteDatabase, publicationId?: string): void {\n // Schema v21 could leave staged heads and their live detail rows after an interruption.\n const predicate = publicationId\n ? \"staged.publication_id = ?\"\n : \"staged.publication_id IS NOT NULL\";\n const params = publicationId ? [publicationId] : [];\n for (const [table, alias] of [\n [\"message_tools\", \"target\"],\n [\"messages\", \"target\"],\n [\"session_file_activity\", \"target\"],\n [\"session_documents\", \"target\"],\n [\"pending_reindex\", \"target\"],\n ] as const) {\n db.prepare(`\n DELETE FROM ${table} AS ${alias}\n WHERE EXISTS (\n SELECT 1\n FROM sessions AS staged\n WHERE staged.agent_name = ${alias}.agent_name\n AND staged.session_id = ${alias}.session_id\n AND ${predicate}\n )\n `).run(...params);\n }\n db.prepare(\n publicationId\n ? \"DELETE FROM sessions WHERE publication_id = ?\"\n : \"DELETE FROM sessions WHERE publication_id IS NOT NULL\",\n ).run(...params);\n}\n\nexport function discardPublicationStaging(db: SQLiteDatabase, publicationId?: string): void {\n if (hasLegacyPublicationRows(db, publicationId)) {\n deleteLegacyPublicationRows(db, publicationId);\n }\n if (publicationId) {\n deletePublicationPayloads(db, publicationId);\n } else {\n db.prepare(\"DELETE FROM search_index_publication_entries\").run();\n }\n}\n","/**\n * Cache storage boundary. Callers request a ready database capability while\n * schema creation, migrations, and search-index maintenance stay internal.\n */\nimport type { ProjectIdentity, ProjectIdentityKind, SessionHead } from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport {\n columnExists,\n getUserVersion,\n runSchemaMigrations,\n setUserVersion,\n tableExists,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../../utils/sqlite.js\";\nimport {\n discardCacheConnection,\n getCacheConnection,\n getCachePath,\n getSchemaEnsuredPath,\n hasCacheStorage,\n setSchemaEnsuredPath,\n type CacheConnection,\n type CacheRow,\n} from \"./db.js\";\nimport {\n messageFromBackfillRow,\n prepareInsertFileActivity,\n prepareInsertMessageTool,\n prepareUpsertSession,\n sourcePathFromMetaJson,\n toolNamesFromMetadataJson,\n upsertSessionRow,\n writeFileActivityRows,\n type MessageBackfillRow,\n type SessionRow,\n} from \"./messages.js\";\nimport { CACHE_SCHEMA_VERSION } from \"./version.js\";\nimport {\n createPublicationStagingTable,\n discardPublicationStaging,\n hasPublicationStaging,\n} from \"./publication-staging.js\";\n\ninterface MessageToolBackfillRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_index?: number;\n tool_metadata_json?: string | null;\n}\n\ninterface ProjectBackfillSessionRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n session_json?: string;\n meta_json?: string | null;\n sort_index?: number;\n}\n\ninterface ProjectBackfillDocumentRow extends DatabaseRow {\n id?: number;\n agent_name?: string;\n session_id?: string;\n slug?: string;\n title?: string;\n directory?: string;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n time_created?: number;\n time_updated?: number | null;\n activity_time?: number;\n}\n\ninterface ProjectIdentityRefreshRow extends DatabaseRow {\n id?: number;\n agent_name?: string;\n session_id?: string;\n directory?: string;\n}\n\ntype LegacyProjectIdentityResolver = (directory: string) => ProjectIdentity;\n\n// Schema migrations hold an immediate SQLite transaction, so identity discovery\n// must complete before the migration runner starts one.\nfunction prepareLegacyProjectIdentityResolver(\n db: SQLiteDatabase,\n currentVersion: number,\n): LegacyProjectIdentityResolver {\n const directories = new Set<string>();\n\n if (currentVersion < 7 && tableExists(db, \"cached_sessions\")) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, session_json FROM cached_sessions\")\n .all() as ProjectBackfillSessionRow[];\n for (const row of rows) {\n if (!row.session_json) continue;\n try {\n const session = JSON.parse(row.session_json) as SessionHead;\n if (session.directory != null) {\n directories.add(String(session.directory));\n } else {\n getCoreDiagnostics()?.warn(\"sqlite.migration.identity_precompute.missing_directory\", {\n agent_name: row.agent_name,\n session_id: row.session_id,\n });\n }\n } catch {\n continue;\n }\n }\n }\n\n if (currentVersion < 12) {\n for (const table of [\"session_documents\", \"sessions\", \"project_sessions\"]) {\n if (!tableExists(db, table) || !columnExists(db, table, \"directory\")) continue;\n const rows = db.prepare(`SELECT directory FROM ${table}`).all() as Array<{\n directory?: unknown;\n }>;\n for (const row of rows) directories.add(String(row.directory ?? \"\"));\n }\n }\n\n const identities = new Map<string, ProjectIdentity | Error>();\n for (const directory of directories) {\n try {\n identities.set(directory, computeIdentity(directory, realFs));\n } catch (error) {\n identities.set(directory, error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n return (directory) => {\n const identity = identities.get(directory);\n if (identity instanceof Error) throw identity;\n if (identity) return identity;\n throw new Error(`Missing precomputed project identity for legacy directory: ${directory}`);\n };\n}\n\nfunction getLegacySessionDirectory(session: SessionHead): string | null {\n return typeof session.directory === \"string\" ? session.directory : null;\n}\n\nfunction withCacheConnection<T>(fn: (connection: CacheConnection) => T): T | null {\n const cachePath = getCachePath();\n const connection = getCacheConnection(cachePath);\n if (!connection) return null;\n\n try {\n if (getSchemaEnsuredPath() !== cachePath) {\n ensureSchema(connection.db, cachePath);\n setSchemaEnsuredPath(cachePath);\n }\n return fn(connection);\n } catch (error) {\n getCoreDiagnostics()?.warn(\"cache.write_failed\", {\n message: error instanceof Error ? error.message : String(error),\n code: (error as { code?: string })?.code,\n error_class: error instanceof Error ? error.name : typeof error,\n stack: error instanceof Error ? error.stack : undefined,\n });\n discardCacheConnection(cachePath, connection);\n return null;\n }\n}\n\nfunction cleanPublicationStaging(connection: CacheConnection): void {\n if (connection.publicationStagingCleaned) return;\n\n const startedAt = performance.now();\n const reclaimed = hasPublicationStaging(connection.db);\n if (reclaimed) {\n connection.db.transaction(() => discardPublicationStaging(connection.db)).immediate();\n }\n connection.publicationStagingCleaned = true;\n getCoreDiagnostics()?.info?.(\"sqlite.publication_staging_cleanup.completed\", {\n duration_ms: Math.round(performance.now() - startedAt),\n reclaimed,\n });\n}\n\nexport function withCacheDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheConnection(({ db }) => fn(db));\n}\n\nexport type CacheReadOutcome<T> = { status: \"success\"; value: T } | { status: \"failed\" };\n\n/**\n * Like withCacheDb (schema-ensuring, so it can be the first cache touch at\n * startup and still run migrations) but with an explicit failure outcome\n * instead of a null that shadows legitimate empty results.\n */\nexport function withCacheDbOutcome<T>(fn: (db: SQLiteDatabase) => T): CacheReadOutcome<T> {\n let result: CacheReadOutcome<T> = { status: \"failed\" };\n withCacheConnection(({ db }) => {\n result = { status: \"success\", value: fn(db) };\n });\n return result;\n}\n\nexport function withCacheDbReadOnly<T>(fn: (db: SQLiteDatabase) => T): CacheReadOutcome<T> {\n const cachePath = getCachePath();\n if (!hasCacheStorage()) return { status: \"failed\" };\n\n const connection = getCacheConnection(cachePath);\n if (!connection) return { status: \"failed\" };\n\n try {\n return { status: \"success\", value: fn(connection.db) };\n } catch (error) {\n getCoreDiagnostics()?.warn(\"cache.read_failed\", {\n message: error instanceof Error ? error.message : String(error),\n code: (error as { code?: string })?.code,\n error_class: error instanceof Error ? error.name : typeof error,\n });\n discardCacheConnection(cachePath, connection);\n return { status: \"failed\" };\n }\n}\n\nexport function withSearchDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheConnection((connection) => runWithFtsRecovery(connection, fn));\n}\n\nexport function withSearchIndexDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheConnection((connection) => {\n cleanPublicationStaging(connection);\n return runWithFtsRecovery(connection, fn);\n });\n}\n\ninterface SearchIndexWriteResult<T> {\n value: T;\n rebuildDurationMs?: number;\n}\n\nexport function runSearchIndexWrite<T>(\n db: SQLiteDatabase,\n rebuild: boolean,\n write: () => T,\n transaction: \"immediate\" | \"caller\" = \"immediate\",\n): SearchIndexWriteResult<T> {\n const execute = () => {\n if (rebuild) {\n dropSearchTriggers(db);\n }\n\n const value = write();\n let rebuildDurationMs: number | undefined;\n\n if (rebuild) {\n const rebuildStartedAt = performance.now();\n rebuildSearchIndex(db);\n rebuildDurationMs = performance.now() - rebuildStartedAt;\n createSearchTriggers(db);\n }\n\n return { value, rebuildDurationMs };\n };\n\n return transaction === \"caller\" ? execute() : db.transaction(execute).immediate();\n}\n\nfunction createCacheTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS cache_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS agent_cache (\n agent_name TEXT PRIMARY KEY,\n timestamp INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS cached_sessions (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n session_json TEXT NOT NULL,\n meta_json TEXT,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE TABLE IF NOT EXISTS cache_initialization (\n agent_name TEXT PRIMARY KEY,\n initialized_at INTEGER NOT NULL,\n index_version TEXT NOT NULL,\n last_sync_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS pending_reindex (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\n}\n\nfunction createSessionTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n sort_index INTEGER NOT NULL DEFAULT 0,\n slug TEXT NOT NULL,\n title TEXT NOT NULL,\n source_path TEXT,\n directory TEXT NOT NULL,\n parent_agent_name TEXT,\n parent_session_id TEXT,\n project_identity_kind TEXT NOT NULL,\n project_identity_key TEXT NOT NULL,\n project_display_name TEXT NOT NULL,\n project_identity_resolver_revision TEXT,\n project_identity_input_signature TEXT,\n time_created INTEGER NOT NULL,\n time_updated INTEGER,\n activity_time INTEGER NOT NULL,\n message_count INTEGER NOT NULL,\n total_input_tokens INTEGER NOT NULL,\n total_output_tokens INTEGER NOT NULL,\n total_cache_read_tokens INTEGER,\n total_cache_create_tokens INTEGER,\n total_cost REAL NOT NULL,\n cost_source TEXT,\n total_tokens INTEGER,\n model_usage_json TEXT,\n smart_tags_json TEXT,\n smart_tags_source_updated_at INTEGER,\n smart_tags_classifier_revision TEXT,\n meta_json TEXT,\n publication_id TEXT,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_sessions_agent_activity_order\n ON sessions(agent_name, activity_time DESC, session_id);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_activity\n ON sessions(activity_time DESC, agent_name, session_id);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_project\n ON sessions(project_identity_kind, project_identity_key, activity_time);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_parent\n ON sessions(parent_agent_name, parent_session_id);\n\n CREATE TABLE IF NOT EXISTS messages (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_index INTEGER NOT NULL,\n message_id TEXT NOT NULL,\n role TEXT NOT NULL,\n time_created INTEGER NOT NULL,\n time_completed INTEGER,\n agent TEXT,\n mode TEXT,\n model TEXT,\n provider TEXT,\n tokens_json TEXT,\n cost REAL,\n cost_source TEXT,\n parts_json TEXT NOT NULL,\n parts_format_version INTEGER NOT NULL DEFAULT 0,\n content_chain_digest TEXT,\n subagent_id TEXT,\n nickname TEXT,\n content_text TEXT NOT NULL,\n tool_metadata_json TEXT,\n PRIMARY KEY (agent_name, session_id, message_index),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_session\n ON messages(agent_name, session_id, message_index);\n\n CREATE INDEX IF NOT EXISTS idx_messages_usage_time\n ON messages(\n CASE\n WHEN time_completed > 0 THEN time_completed\n WHEN time_created > 0 THEN time_created\n END,\n agent_name,\n session_id\n );\n `);\n\n createSessionModelCostTable(db);\n createSessionCostSummaryTable(db);\n createMessageToolTables(db);\n}\n\n/**\n * Per-(session, model) cost rollup maintained in the same transaction that\n * writes message rows, so dashboard model-cost aggregation reads\n * sessions×models rows instead of scanning the full messages table (CS-270).\n */\nfunction createSessionModelCostTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_model_cost (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n model TEXT NOT NULL,\n cost REAL NOT NULL,\n cost_recorded REAL NOT NULL,\n PRIMARY KEY (agent_name, session_id, model),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n `);\n}\n\nfunction createSessionCostSummaryTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_cost_summary (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_count INTEGER NOT NULL DEFAULT 0,\n untimed_message_count INTEGER NOT NULL DEFAULT 0,\n input_tokens INTEGER NOT NULL DEFAULT 0,\n output_tokens INTEGER NOT NULL DEFAULT 0,\n reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n cache_read_tokens INTEGER NOT NULL DEFAULT 0,\n cache_create_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_input_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_output_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_cache_read_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_cache_create_tokens INTEGER NOT NULL DEFAULT 0,\n message_cost REAL NOT NULL,\n untimed_message_cost REAL NOT NULL,\n PRIMARY KEY (agent_name, session_id),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n `);\n}\n\nfunction createMessageToolTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS message_tools (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_index INTEGER NOT NULL,\n tool_name TEXT NOT NULL,\n PRIMARY KEY (agent_name, session_id, message_index, tool_name),\n FOREIGN KEY (agent_name, session_id, message_index)\n REFERENCES messages(agent_name, session_id, message_index)\n ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_message_tools_filter\n ON message_tools(tool_name, agent_name, session_id);\n `);\n}\n\nfunction dropLegacyMessageSearchIndex(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS messages_ai;\n DROP TRIGGER IF EXISTS messages_ad;\n DROP TRIGGER IF EXISTS messages_au;\n DROP TABLE IF EXISTS messages_fts;\n `);\n}\n\nfunction createFileActivityTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_file_activity (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n project_identity_key TEXT NOT NULL,\n path TEXT NOT NULL,\n kind TEXT NOT NULL,\n count INTEGER NOT NULL,\n latest_time INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id, project_identity_key, path, kind),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_project_latest\n ON session_file_activity(project_identity_key, latest_time);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_latest\n ON session_file_activity(latest_time DESC, count DESC, path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_agent_latest\n ON session_file_activity(agent_name, latest_time DESC, count DESC, path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_project_latest_ordered\n ON session_file_activity(project_identity_key, latest_time DESC, count DESC, path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_path\n ON session_file_activity(path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_kind\n ON session_file_activity(kind);\n `);\n\n createFileActivityPathSearchTables(db);\n}\n\nfunction createFileActivityPathSearchTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS session_file_activity_path_fts USING fts5(\n path,\n content='session_file_activity',\n content_rowid='rowid',\n tokenize='trigram'\n );\n `);\n\n createFileActivityPathSearchTriggers(db);\n}\n\nfunction createFileActivityPathSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_ai\n AFTER INSERT ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(rowid, path)\n VALUES (new.rowid, new.path);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_ad\n AFTER DELETE ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts, rowid, path)\n VALUES ('delete', old.rowid, old.path);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_au\n AFTER UPDATE ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts, rowid, path)\n VALUES ('delete', old.rowid, old.path);\n INSERT INTO session_file_activity_path_fts(rowid, path)\n VALUES (new.rowid, new.path);\n END;\n `);\n}\n\nfunction rebuildFileActivityPathIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_file_activity_path_fts\")) {\n return;\n }\n db.exec(\n \"INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts) VALUES ('rebuild')\",\n );\n}\n\nfunction createSearchTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n title TEXT NOT NULL,\n content_text TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n indexed_message_count INTEGER NOT NULL,\n detail_version TEXT NOT NULL DEFAULT '',\n indexed_at INTEGER NOT NULL,\n UNIQUE(agent_name, session_id)\n );\n\n CREATE VIRTUAL TABLE IF NOT EXISTS session_documents_fts USING fts5(\n title,\n content_text,\n content='session_documents',\n content_rowid='id'\n );\n `);\n\n createSearchTriggers(db);\n}\n\nfunction createSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS session_documents_ai AFTER INSERT ON session_documents BEGIN\n INSERT INTO session_documents_fts(rowid, title, content_text)\n VALUES (new.id, new.title, new.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_documents_ad AFTER DELETE ON session_documents BEGIN\n INSERT INTO session_documents_fts(session_documents_fts, rowid, title, content_text)\n VALUES ('delete', old.id, old.title, old.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_documents_au AFTER UPDATE ON session_documents BEGIN\n INSERT INTO session_documents_fts(session_documents_fts, rowid, title, content_text)\n VALUES ('delete', old.id, old.title, old.content_text);\n INSERT INTO session_documents_fts(rowid, title, content_text)\n VALUES (new.id, new.title, new.content_text);\n END;\n `);\n}\n\nfunction addIndexedMessageCount(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) return;\n\n if (!columnExists(db, \"session_documents\", \"indexed_message_count\")) {\n db.exec(\n \"ALTER TABLE session_documents ADD COLUMN indexed_message_count INTEGER NOT NULL DEFAULT 0\",\n );\n }\n if (!tableExists(db, \"messages\")) return;\n\n db.exec(`\n UPDATE session_documents\n SET indexed_message_count = (\n SELECT COUNT(*)\n FROM messages\n WHERE messages.agent_name = session_documents.agent_name\n AND messages.session_id = session_documents.session_id\n )\n `);\n}\n\nfunction addDetailVersion(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) return;\n createCacheTables(db);\n if (!columnExists(db, \"session_documents\", \"detail_version\")) {\n db.exec(\"ALTER TABLE session_documents ADD COLUMN detail_version TEXT NOT NULL DEFAULT ''\");\n }\n if (tableExists(db, \"sessions\") && tableExists(db, \"pending_reindex\")) {\n db.exec(`\n INSERT OR IGNORE INTO pending_reindex(agent_name, session_id)\n SELECT agent_name, session_id FROM sessions\n `);\n }\n}\n\nfunction addProjectIdentityProvenance(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n if (!columnExists(db, \"sessions\", \"project_identity_resolver_revision\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN project_identity_resolver_revision TEXT\");\n }\n if (!columnExists(db, \"sessions\", \"project_identity_input_signature\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN project_identity_input_signature TEXT\");\n }\n if (!columnExists(db, \"sessions\", \"smart_tags_classifier_revision\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN smart_tags_classifier_revision TEXT\");\n }\n}\n\nfunction addSessionPublicationId(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n if (!columnExists(db, \"sessions\", \"publication_id\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN publication_id TEXT\");\n }\n recreateProjectGroupsView(db);\n}\n\nfunction dropSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS session_documents_ai;\n DROP TRIGGER IF EXISTS session_documents_ad;\n DROP TRIGGER IF EXISTS session_documents_au;\n `);\n}\n\nconst LEGACY_SESSION_DOCUMENT_COLUMNS = [\n [\"slug\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"directory\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"time_created\", \"INTEGER NOT NULL DEFAULT 0\"],\n [\"time_updated\", \"INTEGER\"],\n [\"activity_time\", \"INTEGER NOT NULL DEFAULT 0\"],\n [\"project_identity_kind\", \"TEXT NOT NULL DEFAULT 'path'\"],\n [\"project_identity_key\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"project_display_name\", \"TEXT NOT NULL DEFAULT ''\"],\n] as const;\n\nfunction ensureLegacySessionDocumentColumns(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) {\n return;\n }\n\n for (const [name, definition] of LEGACY_SESSION_DOCUMENT_COLUMNS) {\n if (!columnExists(db, \"session_documents\", name)) {\n db.exec(`ALTER TABLE session_documents ADD COLUMN ${name} ${definition}`);\n }\n }\n}\n\nfunction createProjectTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS project_sessions (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n identity_kind TEXT NOT NULL,\n identity_key TEXT NOT NULL,\n display_name TEXT NOT NULL,\n directory TEXT NOT NULL,\n activity_time INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_project_sessions_identity\n ON project_sessions(identity_kind, identity_key);\n `);\n createProjectGroupsView(db);\n}\n\nfunction createProjectGroupsView(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) {\n db.exec(`\n CREATE VIEW IF NOT EXISTS project_groups_v AS\n SELECT\n identity_kind,\n identity_key,\n MIN(display_name) AS display_name,\n GROUP_CONCAT(DISTINCT agent_name) AS sources_csv,\n COUNT(*) AS session_count,\n MAX(activity_time) AS last_activity\n FROM project_sessions\n GROUP BY identity_kind, identity_key;\n `);\n return;\n }\n\n const hasParentReference =\n columnExists(db, \"sessions\", \"parent_agent_name\") &&\n columnExists(db, \"sessions\", \"parent_session_id\");\n const predicates = [\n ...(hasParentReference ? [\"parent_agent_name IS NULL OR parent_session_id IS NULL\"] : []),\n ...(columnExists(db, \"sessions\", \"publication_id\") ? [\"publication_id IS NULL\"] : []),\n ];\n db.exec(`\n CREATE VIEW IF NOT EXISTS project_groups_v AS\n SELECT\n project_identity_kind AS identity_kind,\n project_identity_key AS identity_key,\n MIN(project_display_name) AS display_name,\n GROUP_CONCAT(DISTINCT agent_name) AS sources_csv,\n COUNT(*) AS session_count,\n MAX(activity_time) AS last_activity\n FROM sessions\n ${predicates.length > 0 ? `WHERE ${predicates.map((predicate) => `(${predicate})`).join(\" AND \")}` : \"\"}\n GROUP BY project_identity_kind, project_identity_key;\n `);\n}\n\nfunction recreateProjectGroupsView(db: SQLiteDatabase): void {\n db.exec(\"DROP VIEW IF EXISTS project_groups_v\");\n createProjectGroupsView(db);\n}\n\nfunction createLatestCacheSchema(db: SQLiteDatabase): void {\n createCacheTables(db);\n createSessionTables(db);\n createFileActivityTables(db);\n createProjectTables(db);\n createPublicationStagingTable(db);\n ensureFtsReady(db);\n}\n\nfunction recreateSearchIndexSchema(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS session_documents_ai;\n DROP TRIGGER IF EXISTS session_documents_ad;\n DROP TRIGGER IF EXISTS session_documents_au;\n DROP TABLE IF EXISTS session_documents_fts;\n `);\n createSearchTables(db);\n rebuildSearchIndex(db);\n}\n\nfunction readLegacyCacheVersion(db: SQLiteDatabase): number {\n if (\n !tableExists(db, \"cache_meta\") ||\n !columnExists(db, \"cache_meta\", \"key\") ||\n !columnExists(db, \"cache_meta\", \"value\")\n ) {\n return 0;\n }\n\n const versionRow = db.prepare(\"SELECT value FROM cache_meta WHERE key = 'version'\").get() as\n | DatabaseRow\n | undefined;\n return Number(versionRow?.value ?? 0);\n}\n\nfunction inferCacheSchemaVersion(db: SQLiteDatabase): number {\n if (columnExists(db, \"session_documents\", \"indexed_message_count\")) {\n return columnExists(db, \"session_documents\", \"slug\") ? 14 : 15;\n }\n if (tableExists(db, \"message_tools\")) {\n return 11;\n }\n if (tableExists(db, \"session_file_activity_path_fts\")) {\n return 10;\n }\n if (tableExists(db, \"messages_fts\")) {\n return 9;\n }\n if (tableExists(db, \"session_file_activity\")) {\n return 8;\n }\n if (tableExists(db, \"sessions\") || tableExists(db, \"messages\")) {\n return 7;\n }\n if (\n tableExists(db, \"project_sessions\") ||\n columnExists(db, \"session_documents\", \"project_identity_key\")\n ) {\n return 5;\n }\n if (tableExists(db, \"session_documents\")) {\n return 4;\n }\n if (tableExists(db, \"cached_sessions\") || tableExists(db, \"agent_cache\")) {\n return 3;\n }\n return 0;\n}\n\nfunction getCurrentCacheSchemaVersion(db: SQLiteDatabase): number {\n const userVersion = getUserVersion(db);\n if (userVersion > 0) {\n return userVersion;\n }\n\n const legacyVersion = readLegacyCacheVersion(db);\n return Math.max(legacyVersion, inferCacheSchemaVersion(db));\n}\n\nfunction hasAnyCacheSchema(db: SQLiteDatabase): boolean {\n return [\n \"cache_meta\",\n \"agent_cache\",\n \"cached_sessions\",\n \"sessions\",\n \"messages\",\n \"message_tools\",\n \"session_file_activity\",\n \"session_file_activity_path_fts\",\n \"session_documents\",\n \"session_documents_fts\",\n \"project_sessions\",\n ].some((table) => tableExists(db, table));\n}\n\nfunction backfillProjectSessions(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n if (!tableExists(db, \"cached_sessions\") || !tableExists(db, \"project_sessions\")) {\n return;\n }\n\n const rows = db\n .prepare(\"SELECT agent_name, session_id, session_json FROM cached_sessions\")\n .all() as ProjectBackfillSessionRow[];\n const upsert = db.prepare(`\n INSERT INTO project_sessions(\n agent_name,\n session_id,\n identity_kind,\n identity_key,\n display_name,\n directory,\n activity_time\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n identity_kind = excluded.identity_kind,\n identity_key = excluded.identity_key,\n display_name = excluded.display_name,\n directory = excluded.directory,\n activity_time = excluded.activity_time\n `);\n\n for (const row of rows) {\n if (!row.session_json || !row.agent_name || !row.session_id) {\n continue;\n }\n\n try {\n const session = JSON.parse(row.session_json) as SessionHead;\n const directory = getLegacySessionDirectory(session);\n if (directory == null) continue;\n const identity = session.project_identity ?? resolveIdentity(directory);\n upsert.run(\n row.agent_name,\n row.session_id,\n identity.kind,\n identity.key,\n identity.displayName,\n directory,\n session.time_updated ?? session.time_created,\n );\n } catch {\n continue;\n }\n }\n}\n\nfunction backfillSessionDocumentProjects(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n if (\n !tableExists(db, \"session_documents\") ||\n !columnExists(db, \"session_documents\", \"project_identity_key\")\n ) {\n return;\n }\n\n const rows = db\n .prepare(\"SELECT id, directory FROM session_documents\")\n .all() as ProjectBackfillDocumentRow[];\n const update = db.prepare(`\n UPDATE session_documents\n SET\n project_identity_kind = ?,\n project_identity_key = ?,\n project_display_name = ?\n WHERE id = ?\n `);\n\n for (const row of rows) {\n const identity = resolveIdentity(String(row.directory ?? \"\"));\n update.run(identity.kind, identity.key, identity.displayName, Number(row.id));\n }\n}\n\nfunction migrateProjectIdentity(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n ensureLegacySessionDocumentColumns(db);\n createProjectTables(db);\n backfillProjectSessions(db, resolveIdentity);\n backfillSessionDocumentProjects(db, resolveIdentity);\n}\n\nfunction refreshProjectIdentities(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n if (\n tableExists(db, \"sessions\") &&\n columnExists(db, \"sessions\", \"project_identity_key\") &&\n columnExists(db, \"sessions\", \"directory\")\n ) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, directory FROM sessions\")\n .all() as ProjectIdentityRefreshRow[];\n const update = db.prepare(`\n UPDATE sessions\n SET\n project_identity_kind = ?,\n project_identity_key = ?,\n project_display_name = ?\n WHERE agent_name = ? AND session_id = ?\n `);\n const updateFileActivity =\n tableExists(db, \"session_file_activity\") &&\n columnExists(db, \"session_file_activity\", \"project_identity_key\")\n ? db.prepare(`\n UPDATE session_file_activity\n SET project_identity_key = ?\n WHERE agent_name = ? AND session_id = ?\n `)\n : null;\n\n for (const row of rows) {\n const identity = resolveIdentity(String(row.directory ?? \"\"));\n update.run(identity.kind, identity.key, identity.displayName, row.agent_name, row.session_id);\n updateFileActivity?.run(identity.key, row.agent_name, row.session_id);\n }\n }\n\n if (\n tableExists(db, \"project_sessions\") &&\n columnExists(db, \"project_sessions\", \"identity_key\") &&\n columnExists(db, \"project_sessions\", \"directory\")\n ) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, directory FROM project_sessions\")\n .all() as ProjectIdentityRefreshRow[];\n const update = db.prepare(`\n UPDATE project_sessions\n SET\n identity_kind = ?,\n identity_key = ?,\n display_name = ?\n WHERE agent_name = ? AND session_id = ?\n `);\n\n for (const row of rows) {\n const identity = resolveIdentity(String(row.directory ?? \"\"));\n update.run(identity.kind, identity.key, identity.displayName, row.agent_name, row.session_id);\n }\n }\n\n backfillSessionDocumentProjects(db, resolveIdentity);\n recreateProjectGroupsView(db);\n}\n\nfunction backfillStructuredSessions(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n createSessionTables(db);\n recreateProjectGroupsView(db);\n const upsertSession = prepareUpsertSession(db);\n\n if (tableExists(db, \"cached_sessions\")) {\n const rows = db\n .prepare(\n \"SELECT agent_name, session_id, session_json, meta_json, rowid AS sort_index FROM cached_sessions ORDER BY agent_name, rowid\",\n )\n .all() as CacheRow[];\n\n for (const row of rows) {\n if (!row.agent_name || !row.session_json) {\n continue;\n }\n\n try {\n const parsed = JSON.parse(row.session_json) as SessionHead;\n const directory = getLegacySessionDirectory(parsed);\n if (directory == null) continue;\n const session =\n parsed.project_identity == null\n ? { ...parsed, project_identity: resolveIdentity(directory) }\n : parsed;\n upsertSessionRow(\n upsertSession,\n String(row.agent_name),\n session,\n row.meta_json ?? null,\n Number(row.sort_index ?? 0),\n sourcePathFromMetaJson(row.meta_json),\n );\n } catch {\n continue;\n }\n }\n }\n\n if (!tableExists(db, \"session_documents\")) {\n return;\n }\n\n const documentRows = db\n .prepare(\n `\n SELECT\n d.agent_name,\n d.session_id,\n d.slug,\n d.title,\n d.directory,\n d.project_identity_kind,\n d.project_identity_key,\n d.project_display_name,\n d.time_created,\n d.time_updated,\n d.activity_time,\n d.id\n FROM session_documents d\n LEFT JOIN sessions s ON s.agent_name = d.agent_name AND s.session_id = d.session_id\n WHERE s.session_id IS NULL\n ORDER BY d.id\n `,\n )\n .all() as ProjectBackfillDocumentRow[];\n\n for (const row of documentRows) {\n const directory = String(row.directory ?? \"\");\n const identity =\n row.project_identity_key && row.project_identity_kind && row.project_display_name\n ? {\n kind: row.project_identity_kind,\n key: String(row.project_identity_key),\n displayName: String(row.project_display_name),\n }\n : resolveIdentity(directory);\n\n upsertSessionRow(\n upsertSession,\n String(row.agent_name),\n {\n id: String(row.session_id),\n slug: String(row.slug),\n title: String(row.title),\n directory,\n project_identity: identity,\n time_created: Number(row.time_created ?? row.activity_time ?? 0),\n time_updated: row.time_updated == null ? undefined : Number(row.time_updated),\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n },\n null,\n Number(row.id ?? 0),\n null,\n );\n }\n}\n\nfunction backfillMessageTools(db: SQLiteDatabase): void {\n createMessageToolTables(db);\n if (!tableExists(db, \"messages\")) {\n return;\n }\n\n db.exec(\"DELETE FROM message_tools\");\n const rows = db\n .prepare(\n `\n SELECT agent_name, session_id, message_index, tool_metadata_json\n FROM messages\n WHERE tool_metadata_json IS NOT NULL\n `,\n )\n .all() as MessageToolBackfillRow[];\n const insertTool = prepareInsertMessageTool(db);\n\n for (const row of rows) {\n if (!row.agent_name || !row.session_id || row.message_index == null) {\n continue;\n }\n\n for (const toolName of toolNamesFromMetadataJson(row.tool_metadata_json)) {\n insertTool.run(row.agent_name, row.session_id, row.message_index, toolName);\n }\n }\n}\n\nfunction backfillFileActivity(db: SQLiteDatabase): void {\n createFileActivityTables(db);\n if (!tableExists(db, \"sessions\") || !tableExists(db, \"messages\")) {\n return;\n }\n\n const sessions = db\n .prepare(\n `\n SELECT agent_name, session_id, project_identity_key\n FROM sessions\n ORDER BY agent_name, session_id\n `,\n )\n .all() as SessionRow[];\n const loadMessages = db.prepare(`\n SELECT\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n parts_json,\n subagent_id,\n nickname\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n ORDER BY message_index\n `);\n const deleteActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const insertActivity = prepareInsertFileActivity(db);\n\n for (const session of sessions) {\n if (!session.agent_name || !session.session_id || !session.project_identity_key) {\n continue;\n }\n\n try {\n const rows = loadMessages.all(session.agent_name, session.session_id) as MessageBackfillRow[];\n const messages = rows.map((row) => messageFromBackfillRow(row));\n const activities = extractSessionFileActivity(\n String(session.agent_name),\n String(session.session_id),\n String(session.project_identity_key),\n messages,\n );\n deleteActivity.run(session.agent_name, session.session_id);\n writeFileActivityRows(insertActivity, activities);\n } catch {\n continue;\n }\n }\n}\n\nfunction invalidateSearchContentHashes(db: SQLiteDatabase): void {\n if (\n tableExists(db, \"session_documents\") &&\n columnExists(db, \"session_documents\", \"content_hash\")\n ) {\n db.exec(\"UPDATE session_documents SET content_hash = ''\");\n }\n}\n\nfunction addAtomicPublicationStaging(db: SQLiteDatabase): void {\n createPublicationStagingTable(db);\n invalidateSearchContentHashes(db);\n if (tableExists(db, \"sessions\") && tableExists(db, \"pending_reindex\")) {\n db.exec(`\n INSERT OR IGNORE INTO pending_reindex(agent_name, session_id)\n SELECT agent_name, session_id\n FROM sessions\n WHERE publication_id IS NULL\n `);\n }\n}\n\nfunction replaceSessionActivityIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n db.exec(`\n DROP INDEX IF EXISTS idx_sessions_agent_activity;\n CREATE INDEX IF NOT EXISTS idx_sessions_agent_activity_order\n ON sessions(agent_name, activity_time DESC, session_id);\n `);\n}\n\n/**\n * The unfiltered \"recent sessions\" query orders by bare activity_time; every\n * existing index leads with agent_name, so the planner fell back to a full\n * scan plus a temp B-tree sort (verified via EXPLAIN QUERY PLAN, CS-271).\n */\nfunction addSessionActivityIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_sessions_activity\n ON sessions(activity_time DESC, agent_name, session_id)\n `);\n}\n\nfunction addSessionModelCostRollup(db: SQLiteDatabase): void {\n createSessionModelCostTable(db);\n if (!tableExists(db, \"messages\")) return;\n db.exec(`\n INSERT OR REPLACE INTO session_model_cost(agent_name, session_id, model, cost, cost_recorded)\n SELECT\n agent_name,\n session_id,\n model,\n SUM(COALESCE(cost, 0)),\n SUM(CASE WHEN cost_source = 'recorded' THEN COALESCE(cost, 0) ELSE 0 END)\n FROM messages\n WHERE model IS NOT NULL AND model <> ''\n GROUP BY agent_name, session_id, model\n `);\n}\n\nfunction addSessionCostSummary(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_cost_summary (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_cost REAL NOT NULL,\n untimed_message_cost REAL NOT NULL,\n PRIMARY KEY (agent_name, session_id),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n `);\n if (!tableExists(db, \"messages\")) return;\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_cost_time\n ON messages(\n CASE\n WHEN time_completed > 0 THEN time_completed\n WHEN time_created > 0 THEN time_created\n END,\n agent_name,\n session_id\n )\n WHERE cost > 0;\n `);\n\n if (columnExists(db, \"session_cost_summary\", \"message_count\")) return;\n db.exec(`\n\n INSERT OR REPLACE INTO session_cost_summary(\n agent_name,\n session_id,\n message_cost,\n untimed_message_cost\n )\n SELECT\n m.agent_name,\n m.session_id,\n SUM(CASE WHEN m.cost > 0 THEN m.cost ELSE 0 END),\n SUM(\n CASE\n WHEN m.cost > 0\n AND COALESCE(m.time_completed, 0) <= 0\n AND COALESCE(m.time_created, 0) <= 0\n THEN m.cost\n ELSE 0\n END\n )\n FROM messages m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n GROUP BY m.agent_name, m.session_id\n `);\n}\n\nfunction addSessionUsageSummary(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_cost_summary\")) addSessionCostSummary(db);\n const columns: Record<string, string> = {\n message_count: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_message_count: \"INTEGER NOT NULL DEFAULT 0\",\n input_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n output_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n reasoning_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n cache_read_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n cache_create_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_input_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_output_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_reasoning_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_cache_read_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_cache_create_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n };\n for (const [name, definition] of Object.entries(columns)) {\n if (!columnExists(db, \"session_cost_summary\", name)) {\n db.exec(`ALTER TABLE session_cost_summary ADD COLUMN ${name} ${definition}`);\n }\n }\n if (!tableExists(db, \"messages\")) return;\n\n db.exec(`\n DROP INDEX IF EXISTS idx_messages_cost_time;\n CREATE INDEX IF NOT EXISTS idx_messages_usage_time\n ON messages(\n CASE\n WHEN time_completed > 0 THEN time_completed\n WHEN time_created > 0 THEN time_created\n END,\n agent_name,\n session_id\n );\n\n DELETE FROM session_cost_summary;\n WITH normalized AS (\n SELECT\n m.agent_name,\n m.session_id,\n COALESCE(m.time_completed, 0) <= 0 AND COALESCE(m.time_created, 0) <= 0 AS untimed,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.input'), 0) AS INTEGER), 0) AS input_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.output'), 0) AS INTEGER), 0) AS output_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.reasoning'), 0) AS INTEGER), 0) AS reasoning_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.cache_read'), 0) AS INTEGER), 0) AS cache_read_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.cache_create'), 0) AS INTEGER), 0) AS cache_create_tokens,\n CASE WHEN m.cost > 0 THEN m.cost ELSE 0 END AS cost\n FROM messages m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n )\n INSERT INTO session_cost_summary(\n agent_name,\n session_id,\n message_count,\n untimed_message_count,\n input_tokens,\n output_tokens,\n reasoning_tokens,\n cache_read_tokens,\n cache_create_tokens,\n untimed_input_tokens,\n untimed_output_tokens,\n untimed_reasoning_tokens,\n untimed_cache_read_tokens,\n untimed_cache_create_tokens,\n message_cost,\n untimed_message_cost\n )\n SELECT\n agent_name,\n session_id,\n COUNT(*),\n SUM(CASE WHEN untimed THEN 1 ELSE 0 END),\n SUM(input_tokens),\n SUM(output_tokens),\n SUM(reasoning_tokens),\n SUM(cache_read_tokens),\n SUM(cache_create_tokens),\n SUM(CASE WHEN untimed THEN input_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN output_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN reasoning_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_read_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_create_tokens ELSE 0 END),\n SUM(cost),\n SUM(CASE WHEN untimed THEN cost ELSE 0 END)\n FROM normalized\n GROUP BY agent_name, session_id;\n `);\n}\n\nfunction compactSessionDocuments(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) {\n createSearchTables(db);\n return;\n }\n\n dropSearchTriggers(db);\n db.exec(`\n DROP TABLE IF EXISTS session_documents_fts;\n DROP TABLE IF EXISTS session_documents_legacy_v14;\n ALTER TABLE session_documents RENAME TO session_documents_legacy_v14;\n `);\n createSearchTables(db);\n db.exec(`\n INSERT INTO session_documents(\n id,\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n indexed_at\n )\n SELECT\n id,\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n indexed_at\n FROM session_documents_legacy_v14;\n\n DROP TABLE session_documents_legacy_v14;\n `);\n}\n\nfunction addMessagePartsFormatVersion(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages\") || columnExists(db, \"messages\", \"parts_format_version\")) {\n return;\n }\n db.exec(\"ALTER TABLE messages ADD COLUMN parts_format_version INTEGER NOT NULL DEFAULT 0\");\n}\n\nfunction addMessageContentChainDigest(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages\") || columnExists(db, \"messages\", \"content_chain_digest\")) {\n return;\n }\n db.exec(\"ALTER TABLE messages ADD COLUMN content_chain_digest TEXT\");\n}\n\nfunction addSessionParentReference(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n\n if (!columnExists(db, \"sessions\", \"parent_agent_name\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN parent_agent_name TEXT\");\n }\n if (!columnExists(db, \"sessions\", \"parent_session_id\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN parent_session_id TEXT\");\n }\n db.exec(\n \"CREATE INDEX IF NOT EXISTS idx_sessions_parent ON sessions(parent_agent_name, parent_session_id)\",\n );\n recreateProjectGroupsView(db);\n}\n\nconst CODEX_EXEC_DECODE_MIGRATION_KEY = \"codex_exec_decode_migrated_v3\";\n\n/**\n * One-time: mark every cached Codex detail as pending re-index so code-mode\n * exec decoding takes effect on upgrade. The search content hash derives only\n * from head-level fields, none of which the decoder touches, so nothing would\n * otherwise trigger a refresh. Session rows carry huge content_text, so\n * rewriting them (or clearing a hash) is slow; instead we record just the\n * session ids in the lightweight pending_reindex table. loadCachedSessionData\n * treats a marked session as pending and re-parses its detail fresh on view;\n * the search index clears the marker as it repopulates each one. Gated by a\n * cache_meta flag; a fresh cache just records it.\n */\nfunction migrateCodexExecDecode(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cache_meta\")) return;\n const done = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(CODEX_EXEC_DECODE_MIGRATION_KEY);\n if (done) return;\n\n if (tableExists(db, \"sessions\") && tableExists(db, \"pending_reindex\")) {\n db.exec(\n \"INSERT OR IGNORE INTO pending_reindex(agent_name, session_id) \" +\n \"SELECT agent_name, session_id FROM sessions WHERE agent_name = 'codex'\",\n );\n }\n db.prepare(\n \"INSERT INTO cache_meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'\",\n ).run(CODEX_EXEC_DECODE_MIGRATION_KEY);\n}\n\nconst OPENCODE_SUBAGENT_FOLD_KEY = \"opencode_subagent_fold_v1\";\nconst SUBAGENT_TREE_KEY = \"subagent_tree_v1\";\n\n/**\n * One-time: invalidate cached OpenCode-family (zcode/opencode) heads after the\n * subagent relation format changed. The next scan rebuilds parent references\n * and folded token totals from the source database.\n */\nfunction migrateOpenCodeSubagentFold(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cache_meta\")) return;\n const done = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(OPENCODE_SUBAGENT_FOLD_KEY);\n if (done) return;\n\n if (tableExists(db, \"agent_cache\")) {\n db.prepare(\"DELETE FROM agent_cache WHERE agent_name IN ('zcode', 'opencode')\").run();\n }\n db.prepare(\n \"INSERT INTO cache_meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'\",\n ).run(OPENCODE_SUBAGENT_FOLD_KEY);\n}\n\nfunction migrateSubagentTree(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cache_meta\")) return;\n const done = db.prepare(\"SELECT value FROM cache_meta WHERE key = ?\").get(SUBAGENT_TREE_KEY);\n if (done) return;\n\n if (tableExists(db, \"agent_cache\")) {\n db.prepare(\"DELETE FROM agent_cache WHERE agent_name IN ('codex', 'zcode', 'opencode')\").run();\n }\n db.prepare(\n \"INSERT INTO cache_meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'\",\n ).run(SUBAGENT_TREE_KEY);\n}\n\nfunction rebuildSearchIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents_fts\")) {\n return;\n }\n db.exec(\"INSERT INTO session_documents_fts(session_documents_fts) VALUES ('rebuild')\");\n}\n\nfunction triggerExists(db: SQLiteDatabase, triggerName: string): boolean {\n return (\n db\n .prepare(\"SELECT 1 AS value FROM sqlite_master WHERE name = ? AND type = 'trigger' LIMIT 1\")\n .get(triggerName) !== undefined\n );\n}\n\nfunction hasAllTriggers(db: SQLiteDatabase, triggerNames: string[]): boolean {\n return triggerNames.every((triggerName) => triggerExists(db, triggerName));\n}\n\nfunction rebuildSearchFtsIndex(db: SQLiteDatabase, reason: \"corruption\" | \"schema_missing\"): void {\n const indexes = [\"session_documents_fts\"];\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.fts_rebuild.started\", { indexes, reason });\n try {\n rebuildSearchIndex(db);\n getCoreDiagnostics()?.info?.(\"sqlite.fts_rebuild.completed\", {\n indexes,\n reason,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.fts_rebuild.failed\", {\n indexes,\n reason,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n\nfunction ensureFtsReady(db: SQLiteDatabase): void {\n const needsSearchRebuild =\n !tableExists(db, \"session_documents_fts\") ||\n !hasAllTriggers(db, [\"session_documents_ai\", \"session_documents_ad\", \"session_documents_au\"]);\n\n createSearchTables(db);\n if (needsSearchRebuild) rebuildSearchFtsIndex(db, \"schema_missing\");\n}\n\nfunction ensureFtsConsistency(db: SQLiteDatabase): void {\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.fts_integrity.started\", {\n indexes: 1,\n });\n try {\n db.exec(\n \"INSERT INTO session_documents_fts(session_documents_fts, rank) VALUES ('integrity-check', 1)\",\n );\n getCoreDiagnostics()?.info?.(\"sqlite.fts_integrity.completed\", {\n indexes: 1,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.fts_integrity.failed\", {\n indexes: 1,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n rebuildSearchFtsIndex(db, \"corruption\");\n }\n}\n\nfunction isFtsCorruptionError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"SQLITE_CORRUPT_VTAB\"\n );\n}\n\nfunction runWithFtsRecovery<T>(connection: CacheConnection, fn: (db: SQLiteDatabase) => T): T {\n const { db } = connection;\n if (!connection.ftsReady) {\n ensureFtsReady(db);\n connection.ftsReady = true;\n }\n try {\n return fn(db);\n } catch (error) {\n if (!isFtsCorruptionError(error)) throw error;\n getCoreDiagnostics()?.warn(\"sqlite.fts_corruption.detected\", {\n message: error instanceof Error ? error.message : String(error),\n });\n ensureFtsConsistency(db);\n return fn(db);\n }\n}\n\nfunction setCacheMetaVersion(db: SQLiteDatabase): void {\n createCacheTables(db);\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES ('version', ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(String(CACHE_SCHEMA_VERSION));\n}\n\nfunction setCacheSchemaVersion(db: SQLiteDatabase): void {\n setUserVersion(db, CACHE_SCHEMA_VERSION);\n setCacheMetaVersion(db);\n}\n\nfunction ensureSchema(db: SQLiteDatabase, dbPath: string): void {\n const currentVersion = getCurrentCacheSchemaVersion(db);\n if (currentVersion === 0 && !hasAnyCacheSchema(db)) {\n createLatestCacheSchema(db);\n setCacheSchemaVersion(db);\n migrateCodexExecDecode(db);\n migrateOpenCodeSubagentFold(db);\n migrateSubagentTree(db);\n return;\n }\n\n const resolveLegacyProjectIdentity = prepareLegacyProjectIdentityResolver(db, currentVersion);\n\n runSchemaMigrations(db, {\n dbPath,\n currentVersion,\n targetVersion: CACHE_SCHEMA_VERSION,\n backupLabel: \"cache-migration\",\n backupTables: [\n \"agent_cache\",\n \"cache_initialization\",\n \"cached_sessions\",\n \"sessions\",\n \"messages\",\n \"message_tools\",\n \"session_file_activity\",\n \"session_documents\",\n \"project_sessions\",\n ],\n migrations: [\n { version: 3, migrate: createCacheTables },\n { version: 4, migrate: createSearchTables },\n {\n version: 5,\n migrate: (migrationDb) => migrateProjectIdentity(migrationDb, resolveLegacyProjectIdentity),\n },\n {\n version: 6,\n destructive: true,\n migrate(db) {\n createLatestCacheSchema(db);\n recreateSearchIndexSchema(db);\n invalidateSearchContentHashes(db);\n },\n },\n {\n version: 7,\n migrate(db) {\n addSessionParentReference(db);\n backfillStructuredSessions(db, resolveLegacyProjectIdentity);\n },\n },\n { version: 8, migrate: backfillFileActivity },\n {\n version: 10,\n migrate(db) {\n createFileActivityPathSearchTables(db);\n rebuildFileActivityPathIndex(db);\n },\n },\n {\n version: 11,\n migrate(db) {\n backfillMessageTools(db);\n },\n },\n {\n version: 12,\n migrate(db) {\n refreshProjectIdentities(db, resolveLegacyProjectIdentity);\n },\n },\n { version: 13, migrate: createCacheTables },\n { version: 14, migrate: addIndexedMessageCount },\n { version: 15, destructive: true, migrate: compactSessionDocuments },\n { version: 17, migrate: addMessagePartsFormatVersion },\n { version: 18, migrate: addSessionParentReference },\n { version: 19, migrate: addDetailVersion },\n { version: 20, migrate: addProjectIdentityProvenance },\n { version: 21, migrate: addSessionPublicationId },\n { version: 22, migrate: addAtomicPublicationStaging },\n { version: 23, migrate: replaceSessionActivityIndex },\n { version: 24, migrate: dropLegacyMessageSearchIndex },\n { version: 25, migrate: addMessageContentChainDigest },\n { version: 26, migrate: addSessionActivityIndex },\n { version: 27, migrate: addSessionModelCostRollup },\n { version: 28, migrate: addSessionCostSummary },\n { version: 29, migrate: addSessionUsageSummary },\n ],\n });\n\n createLatestCacheSchema(db);\n\n // Only stamp when behind: every thread's first connection runs ensureSchema,\n // and an unconditional PRAGMA user_version write would contend for the write\n // lock against concurrent checkpoint/index writers on every startup.\n const userVersion = getUserVersion(db);\n if (userVersion < CACHE_SCHEMA_VERSION) {\n setCacheSchemaVersion(db);\n } else if (\n userVersion === CACHE_SCHEMA_VERSION &&\n readLegacyCacheVersion(db) !== CACHE_SCHEMA_VERSION\n ) {\n setCacheMetaVersion(db);\n }\n\n migrateCodexExecDecode(db);\n migrateOpenCodeSubagentFold(db);\n migrateSubagentTree(db);\n}\n","import type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDbReadOnly } from \"./schema.js\";\n\nconst ANALYTICS_REVISION_KEY = \"analytics_revision\";\n\ninterface AnalyticsRevisionRow {\n value?: string | number;\n}\n\nexport function readAnalyticsRevision(db: SQLiteDatabase): string {\n const row = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(ANALYTICS_REVISION_KEY) as AnalyticsRevisionRow | undefined;\n return String(row?.value ?? \"0\");\n}\n\nexport function advanceAnalyticsRevision(db: SQLiteDatabase): void {\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES (?, '1')\n ON CONFLICT(key) DO UPDATE SET value = CAST(value AS INTEGER) + 1\n `,\n ).run(ANALYTICS_REVISION_KEY);\n}\n\nexport function getAnalyticsRevision(): string | null {\n if (!hasCacheStorage()) return null;\n\n const read = withCacheDbReadOnly((db) => readAnalyticsRevision(db));\n return read.status === \"success\" ? read.value : null;\n}\n","import type { FileActivityKind, ProjectIdentityKind, SmartTag } from \"../../types/index.js\";\nimport { isProjectIdentityKind } from \"../../projects/index.js\";\n\nexport interface SearchQueryFilters {\n agent?: string;\n project?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n cwd?: string;\n tags?: SmartTag[];\n tools?: string[];\n file?: string;\n fileKind?: FileActivityKind;\n costMin?: number;\n costMax?: number;\n costMinExclusive?: boolean;\n costMaxExclusive?: boolean;\n}\n\nexport interface ParsedSearchQuery {\n text: string;\n filters: SearchQueryFilters;\n hasQualifiers: boolean;\n}\n\nfunction escapeFtsTerm(value: string): string {\n return value.replaceAll('\"', '\"\"');\n}\n\nexport function splitSearchTokens(input: string): string[] {\n const tokens: string[] = [];\n let token = \"\";\n let inQuote = false;\n\n for (const char of input) {\n if (char === '\"') {\n inQuote = !inQuote;\n token += char;\n continue;\n }\n if (/\\s/.test(char) && !inQuote) {\n if (token) {\n tokens.push(token);\n token = \"\";\n }\n continue;\n }\n token += char;\n }\n\n if (token) tokens.push(token);\n return tokens;\n}\n\nexport function unwrapSearchValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1).trim();\n }\n return trimmed;\n}\n\nfunction parseCostQualifier(value: string, filters: SearchQueryFilters): void {\n const raw = unwrapSearchValue(value);\n const range = raw.match(/^(\\d+(?:\\.\\d+)?)\\.\\.(\\d+(?:\\.\\d+)?)$/);\n if (range) {\n filters.costMin = Number(range[1]);\n filters.costMax = Number(range[2]);\n return;\n }\n\n const comparison = raw.match(/^(>=|>|<=|<)(\\d+(?:\\.\\d+)?)$/);\n if (comparison) {\n const amount = Number(comparison[2]);\n if (comparison[1]?.includes(\">\")) {\n filters.costMin = amount;\n filters.costMinExclusive = comparison[1] === \">\";\n } else {\n filters.costMax = amount;\n filters.costMaxExclusive = comparison[1] === \"<\";\n }\n return;\n }\n\n const amount = Number(raw);\n if (!Number.isNaN(amount)) {\n filters.costMin = amount;\n filters.costMax = amount;\n }\n}\n\nfunction appendUnique<T>(values: T[] | undefined, value: T): T[] {\n if (values?.includes(value)) return values;\n return [...(values ?? []), value];\n}\n\nfunction isSmartTag(value: string): value is SmartTag {\n return (\n value === \"bugfix\" ||\n value === \"refactoring\" ||\n value === \"feature-dev\" ||\n value === \"testing\" ||\n value === \"docs\" ||\n value === \"git-ops\" ||\n value === \"build-deploy\" ||\n value === \"exploration\" ||\n value === \"planning\"\n );\n}\n\nexport function parseSearchQuery(input: string): ParsedSearchQuery {\n const filters: SearchQueryFilters = {};\n const textTokens: string[] = [];\n let hasQualifiers = false;\n\n for (const token of splitSearchTokens(input)) {\n const match = token.match(/^([a-zA-Z][a-zA-Z_-]*):(.+)$/);\n if (!match) {\n textTokens.push(token);\n continue;\n }\n\n const key = match[1]!.toLowerCase();\n const value = unwrapSearchValue(match[2]!);\n if (!value) continue;\n\n let consumed = true;\n if (key === \"agent\") filters.agent = value.toLowerCase();\n else if (key === \"project\") filters.project = value;\n else if (key === \"projectkey\" || key === \"project-key\") filters.projectKey = value;\n else if (key === \"projectkind\" || key === \"project-kind\") {\n if (isProjectIdentityKind(value)) filters.projectKind = value;\n else consumed = false;\n } else if (key === \"cwd\") filters.cwd = value;\n else if (key === \"tool\") filters.tools = appendUnique(filters.tools, value.toLowerCase());\n else if (key === \"file\" || key === \"path\") filters.file = value;\n else if (key === \"kind\" || key === \"filekind\" || key === \"file-kind\") {\n if (value === \"read\" || value === \"edit\" || value === \"write\" || value === \"delete\") {\n filters.fileKind = value;\n } else {\n consumed = false;\n }\n } else if (key === \"tag\" || key === \"signal\") {\n const tag = value.toLowerCase();\n if (isSmartTag(tag)) filters.tags = appendUnique(filters.tags, tag);\n else consumed = false;\n } else if (key === \"cost\") {\n parseCostQualifier(value, filters);\n } else {\n consumed = false;\n }\n\n if (consumed) hasQualifiers = true;\n else textTokens.push(token);\n }\n\n return {\n text: textTokens.join(\" \").trim(),\n filters,\n hasQualifiers,\n };\n}\n\nexport function toFtsQuery(input: string): string {\n const tokens = splitSearchTokens(input);\n return tokens\n .map((token) => {\n if (/^OR$/i.test(token)) return \"OR\";\n if (token.startsWith('\"') && token.endsWith('\"')) {\n return `\"${escapeFtsTerm(token.slice(1, -1))}\"`;\n }\n return `\"${escapeFtsTerm(token)}\"`;\n })\n .filter(\n (token, index, values) =>\n token !== \"OR\" ||\n (index > 0 &&\n index < values.length - 1 &&\n values[index - 1] !== \"OR\" &&\n values[index + 1] !== \"OR\"),\n )\n .join(\" \");\n}\n","import { createHash, type Hash } from \"node:crypto\";\nimport type { SessionReference } from \"../../contract/index.js\";\n\nexport const MESSAGE_CURSOR_VERSION = 2;\n\nexport interface MessageCursorContent {\n messageId: string;\n role: string;\n timeCreated: number;\n timeCompleted: number | null | undefined;\n agent: string | null | undefined;\n mode: string | null | undefined;\n model: string | null | undefined;\n provider: string | null | undefined;\n tokensJson: string | null | undefined;\n cost: number | null | undefined;\n costSource: string | null | undefined;\n partsJson: string;\n partsFormatVersion: number | string | null | undefined;\n subagentId: string | null | undefined;\n nickname: string | null | undefined;\n}\n\nfunction updateField(hash: Hash, value: string | number | null | undefined): void {\n if (value == null) {\n hash.update(\"n;\");\n return;\n }\n const text = String(value);\n hash.update(`v${text.length}:`).update(text).update(\";\");\n}\n\nfunction updateMessageContent(hash: Hash, content: MessageCursorContent): void {\n updateField(hash, content.messageId);\n updateField(hash, content.role);\n updateField(hash, content.timeCreated);\n updateField(hash, content.timeCompleted);\n updateField(hash, content.agent);\n updateField(hash, content.mode);\n updateField(hash, content.model);\n updateField(hash, content.provider);\n updateField(hash, content.tokensJson);\n updateField(hash, content.cost);\n updateField(hash, content.costSource);\n updateField(hash, content.partsJson);\n updateField(hash, content.partsFormatVersion);\n updateField(hash, content.subagentId);\n updateField(hash, content.nickname);\n}\n\nexport function initialMessageCursorDigest(reference: SessionReference): string {\n const hash = createHash(\"sha256\");\n hash.update(\"codesesh-session-messages\\0\");\n updateField(hash, MESSAGE_CURSOR_VERSION);\n updateField(hash, reference.agentName);\n updateField(hash, reference.sessionId);\n return hash.digest(\"hex\");\n}\n\nexport function advanceMessageCursorDigest(\n previousDigest: string,\n content: MessageCursorContent,\n): string {\n const hash = createHash(\"sha256\");\n hash.update(\"codesesh-session-messages-chain\\0\");\n updateField(hash, previousDigest);\n updateMessageContent(hash, content);\n return hash.digest(\"hex\");\n}\n\nexport function computeMessageCursorDigest(\n reference: SessionReference,\n messages: Iterable<MessageCursorContent>,\n): string {\n let digest = initialMessageCursorDigest(reference);\n for (const message of messages) {\n digest = advanceMessageCursorDigest(digest, message);\n }\n return digest;\n}\n","import type { SessionCacheMeta } from \"../../agents/base.js\";\n\nconst DETAIL_PROJECTION_VERSION = \"session-detail-v1\";\n\nexport function sessionDetailVersion(meta: SessionCacheMeta | null | undefined): string {\n const parserVersions = Object.entries(meta ?? {})\n .filter(\n ([key, value]) => key.toLowerCase().endsWith(\"parserversion\") && typeof value === \"string\",\n )\n .sort(([left], [right]) => left.localeCompare(right));\n return JSON.stringify([\n DETAIL_PROJECTION_VERSION,\n typeof meta?.sourceFingerprint === \"string\" ? meta.sourceFingerprint : null,\n parserVersions,\n ]);\n}\n","import type { SessionCacheMeta } from \"../../agents/base.js\";\nimport type { SessionDetail, SessionFileActivity, SessionHead } from \"../../types/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { SEARCH_INDEX_BULK_SYNC_THRESHOLD, type PersistedSessionHeadChange } from \"./db.js\";\nimport { advanceAnalyticsRevision } from \"./analytics-revision.js\";\nimport {\n buildSessionContentFromMessages,\n messageCursorContentFromStructuredRecord,\n MESSAGE_PARTS_FORMAT_VERSION,\n normalizeMessages,\n prepareInsertFileActivity,\n prepareInsertMessageTool,\n prepareUpsertIndexedSession,\n assertSessionProjectIdentities,\n requireSessionProjectIdentity,\n upsertSessionRow,\n writeFileActivityRows,\n type StructuredMessageRecord,\n} from \"./messages.js\";\nimport { advanceMessageCursorDigest, initialMessageCursorDigest } from \"./message-cursor.js\";\nimport { runSearchIndexWrite, withCacheDbReadOnly, withSearchIndexDb } from \"./schema.js\";\nimport { sessionDetailVersion } from \"./detail-version.js\";\nimport type { SessionSnapshotCompleteness } from \"./sessions.js\";\nimport {\n deletePublicationPayloads,\n discardPublicationStaging,\n readPublicationPayloads,\n stagePublicationPayloads,\n} from \"./publication-staging.js\";\n\nexport interface SearchIndexSyncOptions {\n isBulk?: boolean;\n bulkThreshold?: number;\n includePendingReindex?: boolean;\n detailVersions?: Readonly<Record<string, string>>;\n completeness?: SessionSnapshotCompleteness;\n removedSessionIds?: readonly string[];\n publicationId?: string;\n}\n\nexport interface SearchIndexSyncFailure {\n sessionId: string;\n reason: \"parse-failed\" | \"superseded\";\n message?: string;\n}\n\nexport interface SearchIndexSyncResult {\n agentName: string;\n mode: \"bulk\" | \"incremental\";\n sessions: number;\n changed: number;\n deleted: number;\n indexed: number;\n skipped: number;\n failures?: SearchIndexSyncFailure[];\n durationMs: number;\n rebuildDurationMs?: number;\n}\n\nexport interface PendingSearchIndexMaintenance {\n sessionIds: string[];\n total: number;\n}\n\ninterface SearchIndexState {\n contentHashBySessionId: Map<string, string>;\n publishedContentHashBySessionId: Map<string, string>;\n indexedMessageCountBySessionId: Map<string, number>;\n messageCountBySessionId: Map<string, number>;\n detailVersionBySessionId: Map<string, string>;\n targetDetailVersionBySessionId: Map<string, string>;\n pendingReindexSessionIds: Set<string>;\n}\n\ninterface IndexedSearchRow {\n session_id?: string;\n content_hash?: string;\n indexed_message_count?: number;\n detail_version?: string;\n meta_json?: string | null;\n}\n\ninterface PublishedSessionRow {\n session_slug?: string | null;\n session_title?: string | null;\n session_directory?: string | null;\n session_time_created?: number | null;\n session_time_updated?: number | null;\n session_message_count?: number | null;\n session_total_input_tokens?: number | null;\n session_total_output_tokens?: number | null;\n session_total_cache_read_tokens?: number | null;\n session_total_cache_create_tokens?: number | null;\n session_total_cost?: number | null;\n session_cost_source?: string | null;\n session_total_tokens?: number | null;\n}\n\ninterface MessageCountRow {\n session_id?: string;\n value?: number;\n}\n\nfunction readPendingReindexIds(db: SQLiteDatabase, agentName: string): Set<string> {\n const rows = db\n .prepare(\"SELECT session_id FROM pending_reindex WHERE agent_name = ?\")\n .all(agentName) as Array<{ session_id?: string }>;\n return new Set(rows.map((row) => String(row.session_id)));\n}\n\ntype SearchIndexStateRow = IndexedSearchRow & MessageCountRow & PublishedSessionRow;\n\nconst SEARCH_INDEX_STATE_BATCH_SIZE = 900;\nconst SEARCH_INDEX_COMMIT_CHUNK_SIZE = 64;\n\ninterface LoadedSearchIndexEntry {\n session: SessionHead;\n messages: StructuredMessageRecord[];\n contentText: string;\n contentHash: string;\n fileActivity: SessionFileActivity[];\n sortIndex: number;\n detailVersion: string;\n}\n\ninterface SearchIndexRowWriteOptions {\n verifySupersession?: boolean;\n}\n\ntype SearchIndexPlanRequest =\n | { kind: \"snapshot\"; sessions: SessionHead[] }\n | {\n kind: \"changes\";\n changes: PersistedSessionHeadChange[];\n removedSessionIds: readonly string[];\n };\n\ninterface SearchIndexPlan {\n agentName: string;\n mode: \"bulk\" | \"incremental\";\n sessionCount: number;\n changes: PersistedSessionHeadChange[];\n removedSessionIds: string[];\n detailVersionBySessionId: Map<string, string>;\n needsRebuild: boolean;\n startedAt: number;\n}\n\ninterface SearchIndexPlanInput {\n agentName: string;\n sessionCount: number;\n candidates: PersistedSessionHeadChange[];\n removedSessionIds: string[];\n state: SearchIndexState;\n options: SearchIndexSyncOptions;\n startedAt: number;\n}\n\n/** Full snapshots bound memory with durable chunks; targeted changes retain one atomic write. */\ntype LargeBacklogWriteStrategy = \"atomic\" | \"chunked\";\n\ninterface PreparedSearchIndexPublication {\n agentName: string;\n mode: \"bulk\" | \"incremental\";\n sessions: number;\n changed: number;\n removedSessionIds: string[];\n entries: LoadedSearchIndexEntry[];\n publicationId?: string;\n /** Full entries stored outside the live tables until the atomic commit. */\n preStaged: number;\n failures: SearchIndexSyncFailure[];\n needsRebuild: boolean;\n startedAt: number;\n}\n\nfunction shouldBulkSyncSearchIndex(options: SearchIndexSyncOptions, changedCount: number): boolean {\n if (options.isBulk != null) {\n return options.isBulk;\n }\n\n const threshold = options.bulkThreshold ?? SEARCH_INDEX_BULK_SYNC_THRESHOLD;\n return threshold > 0 && changedCount >= threshold;\n}\n\nfunction sessionContentHash(session: SessionHead): string {\n return JSON.stringify([\n session.slug,\n session.title,\n session.directory,\n session.time_created,\n session.time_updated ?? session.time_created,\n session.stats.message_count,\n session.stats.total_input_tokens,\n session.stats.total_output_tokens,\n session.stats.total_cache_read_tokens ?? 0,\n session.stats.total_cache_create_tokens ?? 0,\n session.stats.total_cost,\n session.stats.cost_source ?? \"\",\n session.stats.total_tokens ?? 0,\n ]);\n}\n\nfunction publishedSessionContentHash(row: PublishedSessionRow): string | null {\n if (row.session_slug == null) return null;\n return JSON.stringify([\n row.session_slug,\n row.session_title ?? \"\",\n row.session_directory ?? \"\",\n Number(row.session_time_created ?? 0),\n Number(row.session_time_updated ?? row.session_time_created ?? 0),\n Number(row.session_message_count ?? 0),\n Number(row.session_total_input_tokens ?? 0),\n Number(row.session_total_output_tokens ?? 0),\n Number(row.session_total_cache_read_tokens ?? 0),\n Number(row.session_total_cache_create_tokens ?? 0),\n Number(row.session_total_cost ?? 0),\n row.session_cost_source ?? \"\",\n Number(row.session_total_tokens ?? 0),\n ]);\n}\n\nfunction detailVersionFromMetaJson(value: string | null | undefined): string {\n if (!value) return sessionDetailVersion(null);\n try {\n return sessionDetailVersion(JSON.parse(value) as SessionCacheMeta);\n } catch {\n return sessionDetailVersion(null);\n }\n}\n\nfunction searchIndexStateFromRows(\n indexedRows: SearchIndexStateRow[],\n messageCountRows: MessageCountRow[],\n pendingReindexSessionIds: Set<string> = new Set(),\n): SearchIndexState {\n return {\n contentHashBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), String(row.content_hash ?? \"\")]),\n ),\n publishedContentHashBySessionId: new Map(\n indexedRows.flatMap((row) => {\n const contentHash = publishedSessionContentHash(row);\n return contentHash == null ? [] : [[String(row.session_id), contentHash]];\n }),\n ),\n indexedMessageCountBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), Number(row.indexed_message_count ?? 0)]),\n ),\n messageCountBySessionId: new Map(\n messageCountRows.map((row) => [String(row.session_id), Number(row.value ?? 0)]),\n ),\n detailVersionBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), String(row.detail_version ?? \"\")]),\n ),\n targetDetailVersionBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), detailVersionFromMetaJson(row.meta_json)]),\n ),\n pendingReindexSessionIds,\n };\n}\n\nfunction readSearchIndexState(\n db: SQLiteDatabase,\n agentName: string,\n sessionIds: string[],\n): SearchIndexState {\n const rows: SearchIndexStateRow[] = [];\n const uniqueSessionIds = [...new Set(sessionIds)];\n\n for (let offset = 0; offset < uniqueSessionIds.length; offset += SEARCH_INDEX_STATE_BATCH_SIZE) {\n const batch = uniqueSessionIds.slice(offset, offset + SEARCH_INDEX_STATE_BATCH_SIZE);\n const requestedRows = batch.map(() => \"(?)\").join(\", \");\n const batchRows = db\n .prepare(\n `\n WITH requested_session_ids(session_id) AS (VALUES ${requestedRows})\n SELECT\n requested.session_id,\n documents.content_hash,\n documents.indexed_message_count,\n documents.detail_version,\n sessions.meta_json,\n sessions.slug AS session_slug,\n sessions.title AS session_title,\n sessions.directory AS session_directory,\n sessions.time_created AS session_time_created,\n sessions.time_updated AS session_time_updated,\n sessions.message_count AS session_message_count,\n sessions.total_input_tokens AS session_total_input_tokens,\n sessions.total_output_tokens AS session_total_output_tokens,\n sessions.total_cache_read_tokens AS session_total_cache_read_tokens,\n sessions.total_cache_create_tokens AS session_total_cache_create_tokens,\n sessions.total_cost AS session_total_cost,\n sessions.cost_source AS session_cost_source,\n sessions.total_tokens AS session_total_tokens,\n COUNT(messages.message_index) AS value\n FROM requested_session_ids AS requested\n LEFT JOIN session_documents AS documents\n ON documents.agent_name = ? AND documents.session_id = requested.session_id\n LEFT JOIN messages\n ON messages.agent_name = ? AND messages.session_id = requested.session_id\n LEFT JOIN sessions\n ON sessions.agent_name = ? AND sessions.session_id = requested.session_id\n GROUP BY\n requested.session_id,\n documents.content_hash,\n documents.indexed_message_count,\n documents.detail_version,\n sessions.meta_json,\n sessions.slug,\n sessions.title,\n sessions.directory,\n sessions.time_created,\n sessions.time_updated,\n sessions.message_count,\n sessions.total_input_tokens,\n sessions.total_output_tokens,\n sessions.total_cache_read_tokens,\n sessions.total_cache_create_tokens,\n sessions.total_cost,\n sessions.cost_source,\n sessions.total_tokens\n `,\n )\n .all(...batch, agentName, agentName, agentName) as SearchIndexStateRow[];\n rows.push(...batchRows);\n }\n\n return searchIndexStateFromRows(rows, rows, readPendingReindexIds(db, agentName));\n}\n\nfunction targetDetailVersion(\n state: SearchIndexState,\n sessionId: string,\n options: SearchIndexSyncOptions,\n): string {\n return (\n options.detailVersions?.[sessionId] ??\n state.targetDetailVersionBySessionId.get(sessionId) ??\n sessionDetailVersion(null)\n );\n}\n\nfunction searchIndexEntryNeedsUpdate(\n state: SearchIndexState,\n session: SessionHead,\n options: SearchIndexSyncOptions,\n): boolean {\n const sessionId = session.id;\n const pendingMaintenance = state.pendingReindexSessionIds.has(sessionId);\n const targetVersion = targetDetailVersion(state, sessionId, options);\n if (pendingMaintenance && options.includePendingReindex === false) {\n return (\n state.publishedContentHashBySessionId.get(sessionId) !== sessionContentHash(session) ||\n state.targetDetailVersionBySessionId.get(sessionId) !== targetVersion\n );\n }\n return (\n pendingMaintenance ||\n state.detailVersionBySessionId.get(sessionId) !== targetVersion ||\n state.contentHashBySessionId.get(sessionId) !== sessionContentHash(session) ||\n state.indexedMessageCountBySessionId.get(sessionId) !==\n (state.messageCountBySessionId.get(sessionId) ?? 0)\n );\n}\n\nexport function readPendingSearchIndexMaintenance(\n agentName: string,\n limit: number,\n): PendingSearchIndexMaintenance | null {\n const boundedLimit = Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 0;\n const outcome = withCacheDbReadOnly((db) => {\n const totalRow = db\n .prepare(\n `\n SELECT COUNT(*) AS value\n FROM pending_reindex AS pending\n INNER JOIN sessions\n ON sessions.agent_name = pending.agent_name\n AND sessions.session_id = pending.session_id\n WHERE pending.agent_name = ?\n AND sessions.publication_id IS NULL\n `,\n )\n .get(agentName) as { value?: number } | undefined;\n const rows = db\n .prepare(\n `\n SELECT pending.session_id\n FROM pending_reindex AS pending\n INNER JOIN sessions\n ON sessions.agent_name = pending.agent_name\n AND sessions.session_id = pending.session_id\n WHERE pending.agent_name = ?\n AND sessions.publication_id IS NULL\n ORDER BY sessions.sort_index, pending.session_id\n LIMIT ?\n `,\n )\n .all(agentName, boundedLimit) as Array<{ session_id?: string }>;\n return {\n sessionIds: rows.map((row) => String(row.session_id)),\n total: Number(totalRow?.value ?? 0),\n };\n });\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\nfunction loadSearchIndexEntry(\n agentName: string,\n change: PersistedSessionHeadChange,\n loadSessionData: (sessionId: string) => SessionDetail,\n detailVersion: string,\n failures: SearchIndexSyncFailure[],\n): LoadedSearchIndexEntry | null {\n try {\n const data = loadSessionData(change.session.id);\n const messages = normalizeMessages(data);\n const identity = requireSessionProjectIdentity(agentName, change.session);\n return {\n session: change.session,\n messages,\n contentText: buildSessionContentFromMessages(data.title ?? change.session.title, messages),\n contentHash: sessionContentHash(change.session),\n fileActivity: extractSessionFileActivity(\n agentName,\n change.session.id,\n identity.key,\n data.messages,\n ),\n sortIndex: change.sortIndex,\n detailVersion,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n failures.push({ sessionId: change.session.id, reason: \"parse-failed\", message });\n getCoreDiagnostics()?.warn(\"search_index.session_parse_failed\", {\n agent: agentName,\n session_id: change.session.id,\n message,\n });\n return null;\n }\n}\n\nfunction* loadSearchIndexEntries(\n agentName: string,\n changes: Iterable<PersistedSessionHeadChange>,\n loadSessionData: (sessionId: string) => SessionDetail,\n detailVersionFor: (sessionId: string) => string,\n failures: SearchIndexSyncFailure[],\n): Generator<LoadedSearchIndexEntry> {\n for (const change of changes) {\n const entry = loadSearchIndexEntry(\n agentName,\n change,\n loadSessionData,\n detailVersionFor(change.session.id),\n failures,\n );\n if (entry) yield entry;\n }\n}\n\nfunction writeSearchIndexRows(\n db: SQLiteDatabase,\n agentName: string,\n removedSessionIds: string[],\n entries: Iterable<LoadedSearchIndexEntry>,\n failures: SearchIndexSyncFailure[],\n options: SearchIndexRowWriteOptions = {},\n): number {\n const { verifySupersession = true } = options;\n const deleteRow = db.prepare(\n \"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessages = db.prepare(\n \"DELETE FROM messages WHERE agent_name = ? AND session_id = ? AND message_index >= ?\",\n );\n const deleteMessageTools = db.prepare(\n \"DELETE FROM message_tools WHERE agent_name = ? AND session_id = ? AND message_index >= ?\",\n );\n const deleteFileActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteModelCost = db.prepare(\n \"DELETE FROM session_model_cost WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteCostSummary = db.prepare(\n \"DELETE FROM session_cost_summary WHERE agent_name = ? AND session_id = ?\",\n );\n // Derived from the message rows just written, in the same transaction, so\n // the rollup can never drift from its source (CS-270).\n const rebuildModelCost = db.prepare(`\n INSERT INTO session_model_cost(agent_name, session_id, model, cost, cost_recorded)\n SELECT\n agent_name,\n session_id,\n model,\n SUM(COALESCE(cost, 0)),\n SUM(CASE WHEN cost_source = 'recorded' THEN COALESCE(cost, 0) ELSE 0 END)\n FROM messages\n WHERE agent_name = ? AND session_id = ? AND model IS NOT NULL AND model <> ''\n GROUP BY agent_name, session_id, model\n `);\n const rebuildCostSummary = db.prepare(`\n WITH normalized AS (\n SELECT\n agent_name,\n session_id,\n COALESCE(time_completed, 0) <= 0 AND COALESCE(time_created, 0) <= 0 AS untimed,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.input'), 0) AS INTEGER), 0) AS input_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.output'), 0) AS INTEGER), 0) AS output_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.reasoning'), 0) AS INTEGER), 0) AS reasoning_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.cache_read'), 0) AS INTEGER), 0) AS cache_read_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.cache_create'), 0) AS INTEGER), 0) AS cache_create_tokens,\n CASE WHEN cost > 0 THEN cost ELSE 0 END AS normalized_cost\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n )\n INSERT INTO session_cost_summary(\n agent_name,\n session_id,\n message_count,\n untimed_message_count,\n input_tokens,\n output_tokens,\n reasoning_tokens,\n cache_read_tokens,\n cache_create_tokens,\n untimed_input_tokens,\n untimed_output_tokens,\n untimed_reasoning_tokens,\n untimed_cache_read_tokens,\n untimed_cache_create_tokens,\n message_cost,\n untimed_message_cost\n )\n SELECT\n agent_name,\n session_id,\n COUNT(*),\n SUM(CASE WHEN untimed THEN 1 ELSE 0 END),\n SUM(input_tokens),\n SUM(output_tokens),\n SUM(reasoning_tokens),\n SUM(cache_read_tokens),\n SUM(cache_create_tokens),\n SUM(CASE WHEN untimed THEN input_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN output_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN reasoning_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_read_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_create_tokens ELSE 0 END),\n SUM(normalized_cost),\n SUM(CASE WHEN untimed THEN normalized_cost ELSE 0 END)\n FROM normalized\n GROUP BY agent_name, session_id\n `);\n const writeIndexedSession = prepareUpsertIndexedSession(db);\n const insertFileActivity = prepareInsertFileActivity(db);\n const insertMessageTool = prepareInsertMessageTool(db);\n const upsertMessage = db.prepare(`\n INSERT INTO messages(\n agent_name,\n session_id,\n message_index,\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n tokens_json,\n cost,\n cost_source,\n parts_json,\n parts_format_version,\n content_chain_digest,\n subagent_id,\n nickname,\n content_text,\n tool_metadata_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id, message_index) DO UPDATE SET\n message_id = excluded.message_id,\n role = excluded.role,\n time_created = excluded.time_created,\n time_completed = excluded.time_completed,\n agent = excluded.agent,\n mode = excluded.mode,\n model = excluded.model,\n provider = excluded.provider,\n tokens_json = excluded.tokens_json,\n cost = excluded.cost,\n cost_source = excluded.cost_source,\n parts_json = excluded.parts_json,\n parts_format_version = excluded.parts_format_version,\n content_chain_digest = excluded.content_chain_digest,\n subagent_id = excluded.subagent_id,\n nickname = excluded.nickname,\n content_text = excluded.content_text,\n tool_metadata_json = excluded.tool_metadata_json\n `);\n const upsertRow = db.prepare(`\n INSERT INTO session_documents(\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n detail_version,\n indexed_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n title = excluded.title,\n content_text = excluded.content_text,\n content_hash = excluded.content_hash,\n indexed_message_count = excluded.indexed_message_count,\n detail_version = excluded.detail_version,\n indexed_at = excluded.indexed_at\n `);\n\n const readCurrentMeta = db.prepare(\n \"SELECT meta_json FROM sessions WHERE agent_name = ? AND session_id = ?\",\n );\n\n const clearPendingReindex = db.prepare(\n \"DELETE FROM pending_reindex WHERE agent_name = ? AND session_id = ?\",\n );\n\n for (const sessionId of new Set(removedSessionIds)) {\n deleteRow.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId, 0);\n deleteMessages.run(agentName, sessionId, 0);\n deleteModelCost.run(agentName, sessionId);\n deleteCostSummary.run(agentName, sessionId);\n clearPendingReindex.run(agentName, sessionId);\n }\n\n let indexed = 0;\n for (const entry of entries) {\n if (verifySupersession) {\n const current = readCurrentMeta.get(agentName, entry.session.id) as\n | { meta_json?: string | null }\n | undefined;\n if (entry.detailVersion !== detailVersionFromMetaJson(current?.meta_json)) {\n failures.push({ sessionId: entry.session.id, reason: \"superseded\" });\n continue;\n }\n }\n upsertSessionRow(writeIndexedSession, agentName, entry.session, null, entry.sortIndex, null);\n deleteFileActivity.run(agentName, entry.session.id);\n deleteMessageTools.run(agentName, entry.session.id, 0);\n clearPendingReindex.run(agentName, entry.session.id);\n writeFileActivityRows(insertFileActivity, entry.fileActivity);\n let contentChainDigest = initialMessageCursorDigest({\n agentName,\n sessionId: entry.session.id,\n });\n for (const message of entry.messages) {\n contentChainDigest = advanceMessageCursorDigest(\n contentChainDigest,\n messageCursorContentFromStructuredRecord(message),\n );\n upsertMessage.run(\n agentName,\n entry.session.id,\n message.index,\n message.id,\n message.role,\n message.timeCreated,\n message.timeCompleted ?? null,\n message.agent ?? null,\n message.mode ?? null,\n message.model ?? null,\n message.provider ?? null,\n message.tokensJson ?? null,\n message.cost ?? null,\n message.costSource ?? null,\n message.partsJson,\n MESSAGE_PARTS_FORMAT_VERSION,\n contentChainDigest,\n message.subagentId ?? null,\n message.nickname ?? null,\n message.contentText,\n message.toolMetadataJson ?? null,\n );\n for (const toolName of message.toolNames) {\n insertMessageTool.run(agentName, entry.session.id, message.index, toolName);\n }\n }\n deleteMessages.run(agentName, entry.session.id, entry.messages.length);\n deleteModelCost.run(agentName, entry.session.id);\n deleteCostSummary.run(agentName, entry.session.id);\n rebuildModelCost.run(agentName, entry.session.id);\n rebuildCostSummary.run(agentName, entry.session.id);\n upsertRow.run(\n agentName,\n entry.session.id,\n entry.session.title,\n entry.contentText,\n entry.contentHash,\n entry.messages.length,\n entry.detailVersion,\n Date.now(),\n );\n indexed += 1;\n }\n return indexed;\n}\n\n/**\n * Loaded entries carry full message bodies, so a backlog larger than one commit\n * chunk cannot be held in memory at once — a first-time index of a large agent\n * (multi-GB codex rollouts) used to OOM the search-index worker. Larger\n * backlogs are serialized into a shadow table in chunks. The final transaction\n * streams those payloads into the live tables, keeping memory bounded without\n * publishing any detail facts ahead of their session heads.\n */\nfunction loadOrPreStageEntries(\n db: SQLiteDatabase,\n agentName: string,\n changes: PersistedSessionHeadChange[],\n loadSessionData: (sessionId: string) => SessionDetail,\n detailVersionFor: (sessionId: string) => string,\n failures: SearchIndexSyncFailure[],\n publicationId?: string,\n): { entries: LoadedSearchIndexEntry[]; preStaged: number } {\n if (changes.length <= SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n return {\n entries: [\n ...loadSearchIndexEntries(agentName, changes, loadSessionData, detailVersionFor, failures),\n ],\n preStaged: 0,\n };\n }\n\n if (!publicationId) {\n throw new Error(\"Large durable publications require a publication id\");\n }\n\n let preStaged = 0;\n for (let offset = 0; offset < changes.length; offset += SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n const chunk = changes.slice(offset, offset + SEARCH_INDEX_COMMIT_CHUNK_SIZE);\n runSearchIndexWrite(db, false, () => {\n const entries = loadSearchIndexEntries(\n agentName,\n chunk,\n loadSessionData,\n detailVersionFor,\n failures,\n );\n preStaged += stagePublicationPayloads(\n db,\n publicationId,\n agentName,\n (function* () {\n for (const entry of entries) {\n yield { sessionId: entry.session.id, json: JSON.stringify(entry) };\n }\n })(),\n );\n });\n }\n getCoreDiagnostics()?.info?.(\"search_index.pre_staged\", {\n agent: agentName,\n changed: changes.length,\n staged: preStaged,\n });\n return { entries: [], preStaged };\n}\n\nfunction readSearchIndexPlanInput(\n db: SQLiteDatabase,\n agentName: string,\n request: SearchIndexPlanRequest,\n options: SearchIndexSyncOptions,\n): SearchIndexPlanInput {\n const startedAt = performance.now();\n let candidates: PersistedSessionHeadChange[];\n let removedSessionIds: string[];\n let sessionCount: number;\n\n if (request.kind === \"snapshot\") {\n const existingRows = db\n .prepare(\"SELECT session_id FROM session_documents WHERE agent_name = ? ORDER BY id\")\n .all(agentName) as IndexedSearchRow[];\n const includedSessionIds = new Set(request.sessions.map((session) => session.id));\n const sortIndexBySessionId = new Map(\n request.sessions.map((session, sortIndex) => [session.id, sortIndex]),\n );\n const explicitRemovedSessionIds = new Set(options.removedSessionIds ?? []);\n const completeness = options.completeness ?? \"complete\";\n removedSessionIds = existingRows\n .map((row) => String(row.session_id))\n .filter(\n (sessionId) =>\n explicitRemovedSessionIds.has(sessionId) ||\n (completeness === \"complete\" && !includedSessionIds.has(sessionId)),\n );\n candidates = request.sessions.map((session) => ({\n session,\n sortIndex: sortIndexBySessionId.get(session.id) ?? 0,\n }));\n sessionCount = request.sessions.length;\n } else {\n candidates = request.changes;\n removedSessionIds = [...new Set(request.removedSessionIds)];\n sessionCount = request.changes.length;\n }\n\n const state = readSearchIndexState(\n db,\n agentName,\n candidates.map(({ session }) => session.id),\n );\n\n return {\n agentName,\n sessionCount,\n candidates,\n removedSessionIds,\n state,\n options,\n startedAt,\n };\n}\n\nfunction createSearchIndexPlan(input: SearchIndexPlanInput): SearchIndexPlan {\n const changes = input.candidates.filter(({ session }) =>\n searchIndexEntryNeedsUpdate(input.state, session, input.options),\n );\n const detailVersionBySessionId = new Map(\n changes.map(({ session }) => [\n session.id,\n targetDetailVersion(input.state, session.id, input.options),\n ]),\n );\n const changedCount = input.removedSessionIds.length + changes.length;\n const isBulk = shouldBulkSyncSearchIndex(input.options, changedCount);\n\n return {\n agentName: input.agentName,\n mode: isBulk ? \"bulk\" : \"incremental\",\n sessionCount: input.sessionCount,\n changes,\n removedSessionIds: input.removedSessionIds,\n detailVersionBySessionId,\n needsRebuild: isBulk && changedCount > 0,\n startedAt: input.startedAt,\n };\n}\n\nfunction planSearchIndexWrite(\n db: SQLiteDatabase,\n agentName: string,\n request: SearchIndexPlanRequest,\n options: SearchIndexSyncOptions,\n): SearchIndexPlan {\n return createSearchIndexPlan(readSearchIndexPlanInput(db, agentName, request, options));\n}\n\nfunction detailVersionForPlan(plan: SearchIndexPlan, sessionId: string): string {\n return plan.detailVersionBySessionId.get(sessionId) ?? sessionDetailVersion(null);\n}\n\nfunction prepareSearchIndexPublication(\n db: SQLiteDatabase,\n plan: SearchIndexPlan,\n loadSessionData: (sessionId: string) => SessionDetail,\n publicationId?: string,\n): PreparedSearchIndexPublication {\n getCoreDiagnostics()?.info?.(\"search_index.publication_plan\", {\n agent: plan.agentName,\n sessions: plan.sessionCount,\n changed: plan.changes.length,\n removed: plan.removedSessionIds.length,\n mode: plan.mode,\n planning_ms: Math.round(performance.now() - plan.startedAt),\n });\n const failures: SearchIndexSyncFailure[] = [];\n const { entries, preStaged } = loadOrPreStageEntries(\n db,\n plan.agentName,\n plan.changes,\n loadSessionData,\n (sessionId) => detailVersionForPlan(plan, sessionId),\n failures,\n publicationId,\n );\n\n return {\n agentName: plan.agentName,\n mode: plan.mode,\n sessions: plan.sessionCount,\n changed: plan.changes.length,\n removedSessionIds: plan.removedSessionIds,\n entries,\n publicationId,\n preStaged,\n failures,\n needsRebuild: plan.needsRebuild,\n startedAt: plan.startedAt,\n };\n}\n\nexport function prepareSessionSnapshotSearchIndex(\n db: SQLiteDatabase,\n agentName: string,\n sessions: SessionHead[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): PreparedSearchIndexPublication {\n return prepareSearchIndexPublication(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"snapshot\", sessions }, options),\n loadSessionData,\n options.publicationId,\n );\n}\n\nexport function prepareSessionChangesSearchIndex(\n db: SQLiteDatabase,\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): PreparedSearchIndexPublication {\n return prepareSearchIndexPublication(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"changes\", changes, removedSessionIds }, options),\n loadSessionData,\n options.publicationId,\n );\n}\n\nexport function writePreparedSessionSearchIndex(\n db: SQLiteDatabase,\n publication: PreparedSearchIndexPublication,\n): SearchIndexSyncResult {\n let indexed = 0;\n const { rebuildDurationMs } = runSearchIndexWrite(\n db,\n publication.needsRebuild,\n () => {\n const entries = (function* (): Generator<LoadedSearchIndexEntry> {\n yield* publication.entries;\n if (!publication.publicationId || publication.preStaged === 0) return;\n for (const payload of readPublicationPayloads(\n db,\n publication.publicationId,\n publication.agentName,\n )) {\n yield JSON.parse(payload) as LoadedSearchIndexEntry;\n }\n })();\n indexed += writeSearchIndexRows(\n db,\n publication.agentName,\n publication.removedSessionIds,\n entries,\n publication.failures,\n );\n if (publication.publicationId) {\n deletePublicationPayloads(db, publication.publicationId);\n }\n },\n \"caller\",\n );\n\n return {\n agentName: publication.agentName,\n mode: publication.mode,\n sessions: publication.sessions,\n changed: publication.changed,\n deleted: publication.removedSessionIds.length,\n indexed,\n skipped: publication.changed - indexed,\n failures: publication.failures.length > 0 ? publication.failures : undefined,\n durationMs: performance.now() - publication.startedAt,\n rebuildDurationMs,\n };\n}\n\nexport function discardPreparedSessionSearchIndex(publicationId: string): void {\n withSearchIndexDb((db) =>\n db.transaction(() => discardPublicationStaging(db, publicationId)).immediate(),\n );\n}\n\nfunction searchIndexSyncResult(\n plan: SearchIndexPlan,\n indexed: number,\n failures: SearchIndexSyncFailure[],\n rebuildDurationMs?: number,\n mode = plan.mode,\n): SearchIndexSyncResult {\n return {\n agentName: plan.agentName,\n mode,\n sessions: plan.sessionCount,\n changed: plan.changes.length,\n deleted: plan.removedSessionIds.length,\n indexed,\n skipped: plan.changes.length - indexed,\n failures: failures.length > 0 ? failures : undefined,\n durationMs: performance.now() - plan.startedAt,\n rebuildDurationMs,\n };\n}\n\nfunction executeSearchIndexPlan(\n db: SQLiteDatabase,\n plan: SearchIndexPlan,\n loadSessionData: (sessionId: string) => SessionDetail,\n largeBacklogStrategy: LargeBacklogWriteStrategy,\n): SearchIndexSyncResult {\n let indexed = 0;\n const failures: SearchIndexSyncFailure[] = [];\n const loadEntries = (changes: PersistedSessionHeadChange[]) =>\n loadSearchIndexEntries(\n plan.agentName,\n changes,\n loadSessionData,\n (sessionId) => detailVersionForPlan(plan, sessionId),\n failures,\n );\n\n if (largeBacklogStrategy === \"chunked\" && plan.changes.length > SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n runSearchIndexWrite(db, false, () => {\n indexed += writeSearchIndexRows(db, plan.agentName, plan.removedSessionIds, [], failures);\n if (plan.removedSessionIds.length > 0) advanceAnalyticsRevision(db);\n });\n for (let offset = 0; offset < plan.changes.length; offset += SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n const chunk = plan.changes.slice(offset, offset + SEARCH_INDEX_COMMIT_CHUNK_SIZE);\n runSearchIndexWrite(db, false, () => {\n const chunkIndexed = writeSearchIndexRows(\n db,\n plan.agentName,\n [],\n loadEntries(chunk),\n failures,\n );\n indexed += chunkIndexed;\n if (chunkIndexed > 0) advanceAnalyticsRevision(db);\n });\n }\n return searchIndexSyncResult(plan, indexed, failures, undefined, \"incremental\");\n }\n\n const { rebuildDurationMs } = runSearchIndexWrite(db, plan.needsRebuild, () => {\n indexed = writeSearchIndexRows(\n db,\n plan.agentName,\n plan.removedSessionIds,\n loadEntries(plan.changes),\n failures,\n );\n if (indexed > 0 || plan.removedSessionIds.length > 0) advanceAnalyticsRevision(db);\n });\n return searchIndexSyncResult(plan, indexed, failures, rebuildDurationMs);\n}\n\nexport function syncSessionSearchIndex(\n agentName: string,\n sessions: SessionHead[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): SearchIndexSyncResult | null {\n assertSessionProjectIdentities(agentName, sessions);\n return withSearchIndexDb((db) =>\n executeSearchIndexPlan(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"snapshot\", sessions }, options),\n loadSessionData,\n \"chunked\",\n ),\n );\n}\n\nexport function syncSessionSearchIndexChanges(\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): SearchIndexSyncResult | null {\n if (changes.length === 0 && removedSessionIds.length === 0) {\n return {\n agentName,\n mode: \"incremental\",\n sessions: 0,\n changed: 0,\n deleted: 0,\n indexed: 0,\n skipped: 0,\n durationMs: 0,\n };\n }\n\n assertSessionProjectIdentities(\n agentName,\n changes.map(({ session }) => session),\n );\n\n return withSearchIndexDb((db) =>\n executeSearchIndexPlan(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"changes\", changes, removedSessionIds }, options),\n loadSessionData,\n \"atomic\",\n ),\n );\n}\n","/**\n * Full-text query reader and the stable search cache export surface.\n */\nimport type {\n FileActivityKind,\n Message,\n ProjectIdentityKind,\n SessionHead,\n SmartTag,\n} from \"../../types/index.js\";\nimport type { SearchHighlightRange, SearchMatchType, SearchResult } from \"../../contract/index.js\";\nimport { normalizeProjectScopePath, type ProjectScopeMatcher } from \"../../projects/scope.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { escapeRegExp, filePathFtsQuery, hasCacheStorage, likePattern } from \"./db.js\";\nimport { normalizeToolName, sessionFromRow, type SessionRow } from \"./messages.js\";\nimport { withSearchDb } from \"./schema.js\";\nimport {\n parseSearchQuery,\n splitSearchTokens,\n toFtsQuery,\n unwrapSearchValue,\n type ParsedSearchQuery,\n type SearchQueryFilters,\n} from \"./search-query-parser.js\";\n\ninterface MessageSearchRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_index?: number;\n role?: Message[\"role\"];\n mode?: string | null;\n content_text?: string;\n tool_metadata_json?: string | null;\n}\n\nexport interface SearchResultRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n slug?: string;\n title?: string;\n directory?: string;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n time_created?: number;\n time_updated?: number | null;\n message_count?: number;\n total_input_tokens?: number;\n total_output_tokens?: number;\n total_cache_read_tokens?: number | null;\n total_cache_create_tokens?: number | null;\n total_cost?: number;\n cost_source?: string | null;\n total_tokens?: number | null;\n model_usage_json?: string | null;\n smart_tags_json?: string | null;\n smart_tags_source_updated_at?: number | null;\n snippet?: string | null;\n}\n\nexport type { SearchMatchType, SearchResult };\n\nexport { parseSearchQuery, type ParsedSearchQuery, type SearchQueryFilters };\n\nexport interface SearchOptions {\n agent?: string;\n project?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n projectScope?: ProjectScopeMatcher;\n tags?: SmartTag[];\n tools?: string[];\n file?: string;\n fileKind?: FileActivityKind;\n costMin?: number;\n costMax?: number;\n costMinExclusive?: boolean;\n costMaxExclusive?: boolean;\n from?: number;\n to?: number;\n limit?: number;\n}\n\nexport interface SearchRequestOptions extends SearchOptions {\n cwd?: string;\n}\n\nexport {\n readPendingSearchIndexMaintenance,\n syncSessionSearchIndex,\n syncSessionSearchIndexChanges,\n type PendingSearchIndexMaintenance,\n type SearchIndexSyncOptions,\n type SearchIndexSyncFailure,\n type SearchIndexSyncResult,\n} from \"./search-index-writer.js\";\nexport { sessionDetailVersion } from \"./detail-version.js\";\n\nexport function sessionHeadFromSearchRow(row: SearchResultRow): SessionHead {\n return sessionFromRow(row as SessionRow);\n}\n\nexport function mergeSearchLists<T>(\n left: T[] | undefined,\n right: T[] | undefined,\n): T[] | undefined {\n const values = [...(left ?? []), ...(right ?? [])];\n return values.length > 0 ? [...new Set(values)] : undefined;\n}\n\nexport function mergeSearchQueryOptions(query: string, options: SearchOptions) {\n const parsed = parseSearchQuery(query);\n return {\n text: parsed.text || (parsed.hasQualifiers ? \"\" : query.trim()),\n options: {\n ...options,\n agent: options.agent ?? parsed.filters.agent,\n project: options.project ?? parsed.filters.project,\n projectKind: options.projectKind ?? parsed.filters.projectKind,\n projectKey: options.projectKey ?? parsed.filters.projectKey,\n tags: mergeSearchLists(options.tags, parsed.filters.tags),\n tools: mergeSearchLists(options.tools, parsed.filters.tools),\n file: options.file ?? parsed.filters.file,\n fileKind: options.fileKind ?? parsed.filters.fileKind,\n costMin: options.costMin ?? parsed.filters.costMin,\n costMax: options.costMax ?? parsed.filters.costMax,\n costMinExclusive: options.costMinExclusive ?? parsed.filters.costMinExclusive,\n costMaxExclusive: options.costMaxExclusive ?? parsed.filters.costMaxExclusive,\n },\n parsed,\n };\n}\n\nexport function getSearchProjectDirectory(\n query: string,\n options: SearchRequestOptions,\n): string | undefined {\n return options.cwd ?? parseSearchQuery(query).filters.cwd;\n}\n\nexport function sessionMatchesSearchCost(\n session: SessionHead,\n options: SearchOptions,\n cost = session.stats.total_cost,\n): boolean {\n if (options.costMin != null) {\n if (options.costMinExclusive ? cost <= options.costMin : cost < options.costMin) {\n return false;\n }\n }\n if (options.costMax != null) {\n if (options.costMaxExclusive ? cost >= options.costMax : cost > options.costMax) {\n return false;\n }\n }\n return true;\n}\n\nexport function buildSessionSearchFilters(options: SearchOptions): {\n where: string;\n params: unknown[];\n} {\n const clauses: string[] = [];\n const params: unknown[] = [];\n\n if (options.agent) {\n clauses.push(\"s.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.projectKind || options.projectKey) {\n if (options.projectKind && options.projectKey) {\n clauses.push(\"s.project_identity_kind = ? AND s.project_identity_key = ?\");\n params.push(options.projectKind, options.projectKey);\n } else {\n clauses.push(\"0\");\n }\n }\n if (options.projectScope) {\n const scopePath = normalizeProjectScopePath(options.projectScope.path).toLowerCase();\n const normalizedDirectory = \"REPLACE(LOWER(s.directory), char(92), '/')\";\n clauses.push(\n `((s.project_identity_kind = ? AND s.project_identity_key = ?) OR ${normalizedDirectory} = ? OR instr(${normalizedDirectory}, ? || '/') = 1 OR instr(?, ${normalizedDirectory} || '/') = 1)`,\n );\n params.push(\n options.projectScope.identity.kind,\n options.projectScope.identity.key,\n scopePath,\n scopePath,\n scopePath,\n );\n }\n if (options.project) {\n clauses.push(\n \"(LOWER(s.project_identity_key) LIKE ? ESCAPE '\\\\' OR LOWER(s.project_display_name) LIKE ? ESCAPE '\\\\' OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n const pattern = likePattern(options.project);\n params.push(pattern, pattern, pattern);\n }\n for (const tag of options.tags ?? []) {\n clauses.push(\"s.smart_tags_json LIKE ?\");\n params.push(`%\"${tag}\"%`);\n }\n for (const tool of options.tools ?? []) {\n const toolName = normalizeToolName(tool);\n if (!toolName) continue;\n clauses.push(\n \"EXISTS (SELECT 1 FROM message_tools mt WHERE mt.tool_name = ? AND mt.agent_name = s.agent_name AND mt.session_id = s.session_id)\",\n );\n params.push(toolName);\n }\n if (options.file || options.fileKind) {\n const fileClauses = [\"fa.agent_name = s.agent_name\", \"fa.session_id = s.session_id\"];\n if (options.file) {\n const pathQuery = filePathFtsQuery(options.file);\n if (pathQuery) {\n fileClauses.push(\n \"fa.rowid IN (SELECT rowid FROM session_file_activity_path_fts WHERE path MATCH ?)\",\n );\n params.push(pathQuery);\n } else {\n fileClauses.push(\"LOWER(fa.path) LIKE ? ESCAPE '\\\\'\");\n params.push(likePattern(options.file));\n }\n }\n if (options.fileKind) {\n fileClauses.push(\"fa.kind = ?\");\n params.push(options.fileKind);\n }\n clauses.push(\n `EXISTS (SELECT 1 FROM session_file_activity fa WHERE ${fileClauses.join(\" AND \")})`,\n );\n }\n if (options.from != null) {\n clauses.push(\"s.activity_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"s.activity_time <= ?\");\n params.push(options.to);\n }\n appendInclusiveCostFilter(clauses, params, options);\n\n return {\n where: clauses.length > 0 ? ` AND ${clauses.join(\" AND \")}` : \"\",\n params,\n };\n}\n\nfunction appendInclusiveCostFilter(\n clauses: string[],\n params: unknown[],\n options: SearchOptions,\n): void {\n const predicates: string[] = [];\n if (options.costMin != null) {\n predicates.push(options.costMinExclusive ? \"SUM(own_cost) > ?\" : \"SUM(own_cost) >= ?\");\n params.push(options.costMin);\n }\n if (options.costMax != null) {\n predicates.push(options.costMaxExclusive ? \"SUM(own_cost) < ?\" : \"SUM(own_cost) <= ?\");\n params.push(options.costMax);\n }\n if (predicates.length === 0) return;\n\n // UNION makes malformed parent cycles converge while preserving one row per session.\n clauses.push(`EXISTS (\n WITH RECURSIVE session_subtree(agent_name, session_id, own_cost) AS (\n SELECT s.agent_name, s.session_id, s.total_cost\n UNION\n SELECT child.agent_name, child.session_id, child.total_cost\n FROM sessions child\n JOIN session_subtree parent\n ON child.parent_agent_name = parent.agent_name\n AND child.parent_session_id = parent.session_id\n WHERE child.publication_id IS NULL\n )\n SELECT SUM(own_cost)\n FROM session_subtree\n HAVING ${predicates.join(\" AND \")}\n )`);\n}\n\nexport interface SessionSearchReference {\n agentName: string;\n sessionId: string;\n}\n\nconst SQLITE_REFERENCE_BATCH_SIZE = 200;\n\nexport function filterIndexedSessionReferences(\n references: SessionSearchReference[],\n options: SearchOptions,\n): Set<string> {\n if (references.length === 0 || !hasCacheStorage()) return new Set();\n\n const matches = withSearchDb((db) => {\n const filters = buildSessionSearchFilters(options);\n const result = new Set<string>();\n\n for (let offset = 0; offset < references.length; offset += SQLITE_REFERENCE_BATCH_SIZE) {\n const batch = references.slice(offset, offset + SQLITE_REFERENCE_BATCH_SIZE);\n const referenceClauses = batch.map(() => \"(s.agent_name = ? AND s.session_id = ?)\");\n const referenceParams = batch.flatMap(({ agentName, sessionId }) => [agentName, sessionId]);\n const rows = db\n .prepare(\n `\n SELECT s.agent_name, s.session_id\n FROM sessions s\n WHERE (${referenceClauses.join(\" OR \")})\n AND s.publication_id IS NULL\n ${filters.where}\n `,\n )\n .all(...referenceParams, ...filters.params) as SearchResultRow[];\n\n for (const row of rows) {\n result.add(searchResultRowKey(row));\n }\n }\n\n return result;\n });\n\n return matches ?? new Set();\n}\n\nfunction searchSessionColumns(): string {\n return `\n s.agent_name,\n s.session_id,\n s.slug,\n s.title,\n s.directory,\n s.project_identity_kind,\n s.project_identity_key,\n s.project_display_name,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at\n `;\n}\n\nfunction parseTextTerms(input: string): { terms: string[]; mode: \"all\" | \"any\" } {\n const tokens = splitSearchTokens(input);\n return {\n terms: tokens\n .filter((token) => !/^OR$/i.test(token))\n .map((token) => unwrapSearchValue(token).toLowerCase())\n .filter(Boolean),\n mode: tokens.some((token) => /^OR$/i.test(token)) ? \"any\" : \"all\",\n };\n}\n\nfunction textMatchesTerms(text: string, terms: { terms: string[]; mode: \"all\" | \"any\" }) {\n const lower = text.toLowerCase();\n if (terms.terms.length === 0) return true;\n if (terms.mode === \"any\") return terms.terms.some((term) => lower.includes(term));\n return terms.terms.every((term) => lower.includes(term));\n}\n\ninterface SearchSnippet {\n snippet: string;\n snippetHighlights: SearchHighlightRange[];\n}\n\nfunction findHighlightRanges(text: string, terms: string[]): SearchHighlightRange[] {\n const ranges = terms.flatMap((term) =>\n Array.from(text.matchAll(new RegExp(escapeRegExp(term), \"giu\")), (match) => ({\n start: match.index,\n end: match.index + match[0].length,\n })),\n );\n ranges.sort((left, right) => left.start - right.start || right.end - left.end);\n\n return ranges.reduce<SearchHighlightRange[]>((merged, range) => {\n const previous = merged.at(-1);\n if (previous && range.start <= previous.end) {\n previous.end = Math.max(previous.end, range.end);\n } else {\n merged.push(range);\n }\n return merged;\n }, []);\n}\n\nfunction buildTermSnippet(\n text: string,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n): SearchSnippet {\n const lower = text.toLowerCase();\n const term = terms.terms.find((item) => lower.includes(item)) ?? terms.terms[0] ?? \"\";\n if (!term) {\n return { snippet: text.slice(0, 180), snippetHighlights: [] };\n }\n\n const index = lower.indexOf(term);\n const start = Math.max(0, index - 80);\n const end = Math.min(text.length, index + term.length + 80);\n const snippet = `${start > 0 ? \"… \" : \"\"}${text.slice(start, end)}${\n end < text.length ? \" …\" : \"\"\n }`;\n return {\n snippet,\n snippetHighlights: findHighlightRanges(snippet, terms.terms),\n };\n}\n\nfunction messageMatchType(row: MessageSearchRow): SearchMatchType {\n if (row.role === \"user\") return \"user_message\";\n if (row.role === \"tool\" || row.mode === \"tool\" || row.tool_metadata_json) return \"tool_output\";\n return \"assistant_reply\";\n}\n\nfunction searchResultRowKey(row: Pick<SearchResultRow, \"agent_name\" | \"session_id\">): string {\n return `${String(row.agent_name)}\\u0000${String(row.session_id)}`;\n}\n\nfunction fetchMessageSearchMatches(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n): Map<string, SearchSnippet & { matchType: SearchMatchType }> {\n const startedAt = performance.now();\n const candidates = rows.filter((row) => !textMatchesTerms(String(row.title ?? \"\"), terms));\n if (candidates.length === 0) {\n return new Map();\n }\n\n const candidateValues = candidates.map(() => \"(?, ?)\").join(\", \");\n const candidateParams = candidates.flatMap((row) => [\n String(row.agent_name),\n String(row.session_id),\n ]);\n let predicateEvaluations = 0;\n db.function(\"codesesh_message_matches_terms\", { deterministic: true }, (text) => {\n predicateEvaluations += 1;\n return textMatchesTerms(String(text ?? \"\"), terms) ? 1 : 0;\n });\n\n const messageRows = db\n .prepare(\n `\n WITH candidate_sessions(agent_name, session_id) AS (\n VALUES ${candidateValues}\n ),\n first_message_matches AS MATERIALIZED (\n SELECT\n c.agent_name,\n c.session_id,\n (\n SELECT m.rowid\n FROM messages m INDEXED BY idx_messages_session\n WHERE m.agent_name = c.agent_name\n AND m.session_id = c.session_id\n AND codesesh_message_matches_terms(m.content_text)\n ORDER BY m.message_index\n LIMIT 1\n ) AS message_rowid\n FROM candidate_sessions c\n )\n SELECT\n m.agent_name,\n m.session_id,\n m.message_index,\n m.role,\n m.mode,\n m.content_text,\n m.tool_metadata_json\n FROM first_message_matches f\n JOIN messages m ON m.rowid = f.message_rowid\n `,\n )\n .all(...candidateParams) as MessageSearchRow[];\n const matches = new Map<string, SearchSnippet & { matchType: SearchMatchType }>();\n\n for (const message of messageRows) {\n const key = searchResultRowKey(message);\n if (matches.has(key)) continue;\n\n const text = String(message.content_text ?? \"\");\n if (!textMatchesTerms(text, terms)) continue;\n\n matches.set(key, {\n ...buildTermSnippet(text, terms),\n matchType: messageMatchType(message),\n });\n }\n\n getCoreDiagnostics()?.info?.(\"search.message_match_projection\", {\n candidate_sessions: candidates.length,\n predicate_evaluations: predicateEvaluations,\n matched_sessions: matches.size,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n\n return matches;\n}\n\nfunction resolveSearchMatch(\n row: SearchResultRow,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n messageMatches: Map<string, SearchSnippet & { matchType: SearchMatchType }>,\n): SearchSnippet & { matchType: SearchMatchType } {\n const title = String(row.title ?? \"\");\n\n if (terms.terms.length === 0) {\n return {\n snippet: `Recent session · ${String(row.directory ?? \"\")}`,\n snippetHighlights: [],\n matchType: \"recent\",\n };\n }\n\n if (textMatchesTerms(title, terms)) {\n return { ...buildTermSnippet(title, terms), matchType: \"title\" };\n }\n\n const messageMatch = messageMatches.get(searchResultRowKey(row));\n if (messageMatch) {\n return messageMatch;\n }\n\n return {\n snippet: String(row.snippet ?? \"\"),\n snippetHighlights: findHighlightRanges(String(row.snippet ?? \"\"), terms.terms),\n matchType: \"assistant_reply\",\n };\n}\n\nfunction rowsToSearchResults(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n textQuery: string,\n): SearchResult[] {\n const terms = parseTextTerms(textQuery);\n const messageMatches =\n terms.terms.length > 0\n ? fetchMessageSearchMatches(db, rows, terms)\n : new Map<string, SearchSnippet & { matchType: SearchMatchType }>();\n\n return rows.map((row) => {\n const match = resolveSearchMatch(row, terms, messageMatches);\n return {\n reference: {\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n },\n session: sessionHeadFromSearchRow(row),\n snippet: match.snippet,\n snippetHighlights: match.snippetHighlights,\n matchType: match.matchType,\n };\n });\n}\n\nexport function searchSessions(query: string, options: SearchOptions = {}): SearchResult[] {\n const search = mergeSearchQueryOptions(query, options);\n const normalizedQuery = search.text.trim();\n if (!hasCacheStorage()) {\n return [];\n }\n\n const results = withSearchDb((db) => {\n const filters = buildSessionSearchFilters(search.options);\n\n if (!normalizedQuery) {\n const rows = db\n .prepare(\n `\n SELECT\n ${searchSessionColumns()},\n '' AS snippet\n FROM sessions s\n WHERE 1 = 1\n AND s.publication_id IS NULL\n ${filters.where}\n ORDER BY s.activity_time DESC\n LIMIT ?\n `,\n )\n .all(...filters.params, search.options.limit ?? 50) as SearchResultRow[];\n\n return rowsToSearchResults(db, rows, \"\");\n }\n\n const ftsQuery = toFtsQuery(normalizedQuery);\n if (!ftsQuery) return [];\n const rows = db\n .prepare(\n `\n SELECT\n ${searchSessionColumns()},\n COALESCE(\n NULLIF(snippet(session_documents_fts, 1, '', '', ' … ', 18), ''),\n highlight(session_documents_fts, 0, '', '')\n ) AS snippet\n FROM session_documents_fts\n JOIN session_documents d ON d.id = session_documents_fts.rowid\n JOIN sessions s ON s.agent_name = d.agent_name AND s.session_id = d.session_id\n WHERE session_documents_fts MATCH ?\n AND s.publication_id IS NULL\n ${filters.where}\n ORDER BY bm25(session_documents_fts, 8.0, 1.0), s.activity_time DESC\n LIMIT ?\n `,\n )\n .all(ftsQuery, ...filters.params, search.options.limit ?? 50) as SearchResultRow[];\n\n return rowsToSearchResults(db, rows, normalizedQuery);\n });\n\n return results ?? [];\n}\n","/**\n * File activity aggregation: per-session / cross-session file activity queries\n * and file-path search.\n */\nimport type {\n FileActivityKind,\n ProjectIdentityKind,\n SessionFileActivity,\n} from \"../../types/index.js\";\nimport type { FileActivityResult, SearchHighlightRange } from \"../../contract/index.js\";\nimport { normalizeProjectScopePath, type ProjectScopeMatcher } from \"../../projects/scope.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { filePathFtsQuery, hasCacheStorage, likePattern, normalizeFilePathSearch } from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./schema.js\";\nimport {\n buildSessionSearchFilters,\n mergeSearchQueryOptions,\n sessionHeadFromSearchRow,\n type SearchOptions,\n type SearchResult,\n type SearchResultRow,\n} from \"./search.js\";\n\nexport type { FileActivityResult };\n\nexport interface FileActivityRow extends SearchResultRow {\n project_identity_key?: string;\n path?: string;\n kind?: FileActivityKind;\n count?: number;\n latest_time?: number;\n}\n\nexport interface FileActivityOptions {\n agent?: string;\n sessionId?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n project?: string;\n projectScope?: ProjectScopeMatcher;\n path?: string;\n kind?: FileActivityKind;\n from?: number;\n to?: number;\n limit?: number;\n}\n\nexport function fileActivityFilters(options: FileActivityOptions): {\n projectKind: ProjectIdentityKind | null;\n projectKey: string | null;\n projectLike: string | null;\n scopeKind: ProjectIdentityKind | null;\n scopeKey: string | null;\n scopePath: string | null;\n path: string;\n pathLike: string | null;\n} {\n const path = options.path ? normalizeFilePathSearch(options.path) : \"\";\n const scope = options.projectScope;\n return {\n projectKind: options.projectKind ?? null,\n projectKey: options.projectKey ?? null,\n projectLike: options.project ? likePattern(options.project) : null,\n scopeKind: scope?.identity.kind ?? null,\n scopeKey: scope?.identity.key ?? null,\n scopePath: scope ? normalizeProjectScopePath(scope.path).toLowerCase() : null,\n path,\n pathLike: path ? likePattern(path) : null,\n };\n}\n\nexport function fileActivityFromRow(row: FileActivityRow): SessionFileActivity {\n return {\n reference: {\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n },\n projectIdentityKey: String(row.project_identity_key ?? \"\"),\n path: String(row.path ?? \"\"),\n kind: (row.kind ?? \"read\") as FileActivityKind,\n count: Number(row.count ?? 0),\n latestTime: Number(row.latest_time ?? 0),\n };\n}\n\nexport function buildFileActivityWhere(options: FileActivityOptions): {\n where: string;\n params: unknown[];\n} {\n const filters = fileActivityFilters(options);\n const clauses: string[] = [];\n const params: unknown[] = [];\n\n if (options.agent != null) {\n clauses.push(\"fa.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.sessionId != null) {\n clauses.push(\"fa.session_id = ?\");\n params.push(options.sessionId);\n }\n if (filters.projectKind != null || filters.projectKey != null) {\n if (filters.projectKind != null && filters.projectKey != null) {\n clauses.push(\"s.project_identity_kind = ? AND fa.project_identity_key = ?\");\n params.push(filters.projectKind, filters.projectKey);\n } else {\n clauses.push(\"0\");\n }\n }\n if (filters.projectLike != null) {\n clauses.push(\n \"(LOWER(fa.project_identity_key) LIKE ? ESCAPE '\\\\' OR LOWER(s.project_display_name) LIKE ? ESCAPE '\\\\' OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n params.push(filters.projectLike, filters.projectLike, filters.projectLike);\n }\n if (filters.scopeKey != null && filters.scopePath != null) {\n const normalizedDirectory = \"REPLACE(LOWER(s.directory), char(92), '/')\";\n clauses.push(\n `((s.project_identity_kind = ? AND s.project_identity_key = ?) OR ${normalizedDirectory} = ? OR instr(${normalizedDirectory}, ? || '/') = 1 OR instr(?, ${normalizedDirectory} || '/') = 1)`,\n );\n params.push(\n filters.scopeKind,\n filters.scopeKey,\n filters.scopePath,\n filters.scopePath,\n filters.scopePath,\n );\n }\n if (filters.pathLike != null) {\n const pathQuery = filePathFtsQuery(filters.path);\n if (pathQuery) {\n clauses.push(\n \"fa.rowid IN (SELECT rowid FROM session_file_activity_path_fts WHERE path MATCH ?)\",\n );\n params.push(pathQuery);\n } else {\n clauses.push(\"LOWER(fa.path) LIKE ? ESCAPE '\\\\'\");\n params.push(filters.pathLike);\n }\n }\n if (options.kind != null) {\n clauses.push(\"fa.kind = ?\");\n params.push(options.kind);\n }\n if (options.from != null) {\n clauses.push(\"fa.latest_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"fa.latest_time <= ?\");\n params.push(options.to);\n }\n\n return {\n where: clauses.length > 0 ? `WHERE ${clauses.join(\" AND \")}` : \"\",\n params,\n };\n}\n\nconst FILE_ACTIVITY_COLUMNS = `\n fa.agent_name,\n fa.session_id,\n fa.project_identity_key,\n fa.path,\n fa.kind,\n fa.count,\n fa.latest_time,\n s.slug,\n s.title,\n s.directory,\n s.project_identity_kind,\n s.project_display_name,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at\n`;\n\nconst FILE_ACTIVITY_JOIN = `\n FROM session_file_activity fa\n JOIN sessions s\n ON s.agent_name = fa.agent_name\n AND s.session_id = fa.session_id\n AND s.publication_id IS NULL\n`;\n\n/** Most recent first, then busiest, then path — the tie-break every caller relies on. */\nconst FILE_ACTIVITY_ORDER = \"fa.latest_time DESC, fa.count DESC, fa.path\";\n\nexport function listFileActivity(options: FileActivityOptions = {}): FileActivityResult[] {\n return queryFileActivity(options);\n}\n\ninterface FileActivityQuery {\n options: FileActivityOptions;\n sessionSearchOptions?: SearchOptions;\n /** Keep only each session's top-ranked row, so the limit counts sessions. */\n onePerSession?: boolean;\n}\n\nfunction fileActivityWhere(query: FileActivityQuery): { where: string; params: unknown[] } {\n const filters = buildFileActivityWhere(query.options);\n const sessionFilters = query.sessionSearchOptions\n ? buildSessionSearchFilters(query.sessionSearchOptions)\n : { where: \"\", params: [] };\n const clauses = [\n filters.where.replace(/^WHERE /, \"\"),\n sessionFilters.where.replace(/^ AND /, \"\"),\n ].filter(Boolean);\n return {\n where: clauses.length > 0 ? `WHERE ${clauses.join(\" AND \")}` : \"\",\n params: [...filters.params, ...sessionFilters.params],\n };\n}\n\nfunction fileActivitySql(query: FileActivityQuery, where: string): string {\n if (!query.onePerSession) {\n return `\n SELECT ${FILE_ACTIVITY_COLUMNS}\n ${FILE_ACTIVITY_JOIN}\n ${where}\n ORDER BY ${FILE_ACTIVITY_ORDER}\n LIMIT ?\n `;\n }\n\n return `\n SELECT ${FILE_ACTIVITY_COLUMNS}\n FROM (\n SELECT\n fa.rowid AS activity_rowid,\n ROW_NUMBER() OVER (\n PARTITION BY fa.agent_name, fa.session_id\n ORDER BY ${FILE_ACTIVITY_ORDER}\n ) AS session_rank\n ${FILE_ACTIVITY_JOIN}\n ${where}\n ) ranked\n JOIN session_file_activity fa ON fa.rowid = ranked.activity_rowid\n JOIN sessions s\n ON s.agent_name = fa.agent_name\n AND s.session_id = fa.session_id\n AND s.publication_id IS NULL\n WHERE ranked.session_rank = 1\n ORDER BY ${FILE_ACTIVITY_ORDER}\n LIMIT ?\n `;\n}\n\nfunction queryFileActivity(\n options: FileActivityOptions,\n sessionSearchOptions?: SearchOptions,\n onePerSession = false,\n): FileActivityResult[] {\n if (!hasCacheStorage()) {\n return [];\n }\n\n const query: FileActivityQuery = { options, sessionSearchOptions, onePerSession };\n const { where, params } = fileActivityWhere(query);\n const sql = fileActivitySql(query, where);\n const queryRows = (db: SQLiteDatabase) =>\n db.prepare(sql).all(...params, options.limit ?? 50) as FileActivityRow[];\n\n const read = withCacheDbReadOnly(queryRows);\n const rows =\n read.status === \"success\" ? read.value : options.path ? withCacheDb(queryRows) : null;\n\n return (rows ?? []).map((row) => ({\n ...fileActivityFromRow(row),\n session: sessionHeadFromSearchRow(row),\n }));\n}\n\nexport function listSessionFileActivity(\n agentName: string,\n sessionId: string,\n): SessionFileActivity[] {\n return listFileActivity({ agent: agentName, sessionId, limit: 500 }).map(\n ({ session: _session, ...activity }) => activity,\n );\n}\n\nexport function findFilePathHighlightRanges(path: string, query: string): SearchHighlightRange[] {\n const needle = normalizeFilePathSearch(query);\n if (!needle) return [];\n const lower = path.toLowerCase();\n const index = lower.indexOf(needle.toLowerCase());\n if (index < 0) return [];\n return [{ start: index, end: index + needle.length }];\n}\n\nexport function searchFileActivitySessions(\n query: string,\n options: SearchOptions = {},\n): SearchResult[] {\n const search = mergeSearchQueryOptions(query, options);\n const path = normalizeFilePathSearch(search.options.file ?? search.text);\n if (!path) return [];\n\n const rows = queryFileActivity(\n {\n path,\n kind: search.options.fileKind,\n limit: search.options.limit ?? 50,\n },\n search.options,\n true,\n );\n\n return rows.map((row) => {\n const prefix = `${row.kind} `;\n return {\n reference: row.reference,\n session: row.session,\n snippet: `${prefix}${row.path} · ${row.count} events`,\n snippetHighlights: findFilePathHighlightRanges(row.path, path).map((range) => ({\n start: prefix.length + range.start,\n end: prefix.length + range.end,\n })),\n matchType: \"file_path\",\n };\n });\n}\n","/**\n * Shared scan-orchestration helpers — pure functions reused by both the CLI\n * one-shot scanner (scanner.ts) and the live file-watch refresher (live-scan.ts).\n *\n * Nothing here touches SQLite, worker threads, or event emission. The two\n * orchestrators keep their own branch strategies (one-shot vs live refresh);\n * these helpers only collapse the duplicated identity / meta / signature / diff\n * plumbing that previously had to be kept in sync by hand.\n */\nimport type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport { sortSessionsByActivity } from \"../contract/session-index.js\";\nimport type {\n ProjectIdentity,\n SessionHead,\n SessionReference,\n SessionStats,\n} from \"../types/index.js\";\nimport type { PersistedSessionHeadChange } from \"./cache/db.js\";\nimport {\n computeIdentityProjection,\n normalizeProjectDirectory,\n realFs,\n type ProjectIdentityProjection,\n} from \"../projects/index.js\";\n\ntype ProjectIdentityResolver = (directory: string) => ProjectIdentityProjection;\n\n/** Attach or refresh project identities once per normalized directory. */\nexport function attachMissingProjectIdentities(\n sessions: SessionHead[],\n resolve: ProjectIdentityResolver = (directory) => computeIdentityProjection(directory, realFs),\n): SessionHead[] {\n const projections = new Map<string, ProjectIdentityProjection>();\n\n return sessions.map((session) => {\n const directory = normalizeProjectDirectory(session.directory);\n let projection = projections.get(directory);\n if (!projection) {\n projection = resolve(directory);\n projections.set(directory, projection);\n }\n\n const identity = session.project_identity;\n if (\n identity?.kind === projection.identity.kind &&\n identity.key === projection.identity.key &&\n identity.displayName === projection.identity.displayName &&\n session.project_identity_resolver_revision === projection.resolverRevision &&\n session.project_identity_input_signature === projection.inputSignature\n ) {\n return session;\n }\n\n return {\n ...session,\n project_identity: projection.identity,\n project_identity_resolver_revision: projection.resolverRevision,\n project_identity_input_signature: projection.inputSignature,\n };\n });\n}\n\n/** Serialize an agent's session meta map, optionally restricted to a set of ids. */\nexport function buildAgentCacheMeta(\n agent: BaseAgent,\n sessionIds?: Set<string>,\n): Record<string, SessionCacheMeta> {\n const metaMap = agent.getSessionMetaMap?.();\n const meta: Record<string, SessionCacheMeta> = {};\n if (!metaMap) return meta;\n\n for (const [id, data] of metaMap.entries()) {\n if (sessionIds && !sessionIds.has(id)) continue;\n meta[id] = { id, ...(data as Record<string, unknown>) } as SessionCacheMeta;\n }\n\n return meta;\n}\n\ntype SignatureValue = string | number | boolean | null | readonly SignatureValue[];\n\ntype SignatureSpec<Value extends object, Field extends keyof Value = keyof Value> = {\n [Key in Field]-?: (value: Value) => readonly SignatureValue[];\n};\n\ntype ObjectSignatureSpec<Value extends object> = {\n [Key in keyof Value]-?: (value: Value) => SignatureValue;\n};\n\nfunction signatureValues<Value extends object, Field extends keyof Value>(\n value: Value,\n spec: SignatureSpec<Value, Field>,\n): SignatureValue[] {\n const values: SignatureValue[] = [];\n for (const key of Object.keys(spec) as Array<Extract<Field, string>>) {\n values.push(...spec[key](value));\n }\n return values;\n}\n\nfunction objectSignatureValues<Value extends object>(\n value: Value | undefined,\n spec: ObjectSignatureSpec<Value>,\n): SignatureValue[] {\n const keys = Object.keys(spec) as Array<Extract<keyof Value, string>>;\n if (!value) return keys.map(() => null);\n return keys.map((key) => spec[key](value));\n}\n\nconst SESSION_REFERENCE_SIGNATURE_SPEC = {\n agentName: (reference) => reference.agentName,\n sessionId: (reference) => reference.sessionId,\n} satisfies ObjectSignatureSpec<SessionReference>;\n\nconst PROJECT_IDENTITY_SIGNATURE_SPEC = {\n kind: (identity) => identity.kind,\n key: (identity) => identity.key,\n displayName: (identity) => identity.displayName,\n} satisfies ObjectSignatureSpec<ProjectIdentity>;\n\nconst SESSION_STATS_SIGNATURE_SPEC = {\n message_count: (stats) => stats.message_count,\n total_input_tokens: (stats) => stats.total_input_tokens,\n total_output_tokens: (stats) => stats.total_output_tokens,\n total_cost: (stats) => stats.total_cost,\n cost_source: (stats) => stats.cost_source ?? null,\n total_tokens: (stats) => stats.total_tokens ?? 0,\n total_cache_read_tokens: (stats) => stats.total_cache_read_tokens ?? 0,\n total_cache_create_tokens: (stats) => stats.total_cache_create_tokens ?? 0,\n} satisfies ObjectSignatureSpec<SessionStats>;\n\n/** `id` is the diff key; `display_title` is an API alias decoration. */\ntype SessionHeadSignatureExcludedField = \"id\" | \"display_title\";\n\ntype SessionHeadSignatureField = Exclude<keyof SessionHead, SessionHeadSignatureExcludedField>;\n\nfunction modelUsageSignature(modelUsage: SessionHead[\"model_usage\"]): SignatureValue {\n if (!modelUsage) return null;\n return Object.entries(modelUsage)\n .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n .map(([model, tokens]) => [model, tokens]);\n}\n\nconst SESSION_HEAD_SIGNATURE_SPEC = {\n slug: (session) => [session.slug],\n title: (session) => [session.title],\n directory: (session) => [session.directory],\n parent_reference: (session) =>\n objectSignatureValues(session.parent_reference, SESSION_REFERENCE_SIGNATURE_SPEC),\n project_identity: (session) =>\n objectSignatureValues(session.project_identity, PROJECT_IDENTITY_SIGNATURE_SPEC),\n project_identity_resolver_revision: (session) => [\n session.project_identity_resolver_revision ?? null,\n ],\n project_identity_input_signature: (session) => [session.project_identity_input_signature ?? null],\n time_created: (session) => [session.time_created],\n time_updated: (session) => [session.time_updated ?? session.time_created],\n stats: (session) => objectSignatureValues(session.stats, SESSION_STATS_SIGNATURE_SPEC),\n model_usage: (session) => [modelUsageSignature(session.model_usage)],\n smart_tags: (session) => [session.smart_tags ? [...session.smart_tags].sort() : null],\n smart_tags_source_updated_at: (session) => [session.smart_tags_source_updated_at ?? null],\n smart_tags_classifier_revision: (session) => [session.smart_tags_classifier_revision ?? null],\n} satisfies SignatureSpec<SessionHead, SessionHeadSignatureField>;\n\n/** Stable signature for canonical session fields used by both scan orchestrators. */\nexport function sessionSignature(session: SessionHead): string {\n return JSON.stringify(signatureValues(session, SESSION_HEAD_SIGNATURE_SPEC));\n}\n\n/** Sort sessions by activity time, newest first. */\nexport function sortSessions(sessions: SessionHead[]): SessionHead[] {\n return sortSessionsByActivity(sessions);\n}\n\nexport interface SessionDiffResult {\n changes: PersistedSessionHeadChange[];\n removedSessionIds: string[];\n counts: { new: number; updated: number; removed: number };\n}\n\n/**\n * Compute the diff between a cached session set and an updated one.\n *\n * `signature` is injected so callers control the equality口径: a session counts\n * as \"changed\" if it is new, if its id is in `changedIds`, or if its signature\n * differs from the cached copy. The algorithm is pure — event assembly and\n * no-op short-circuiting stay with the caller.\n *\n * `signatureCache` is an optional id→signature memo the caller owns across\n * calls (e.g. across refresh cycles). On the cached side it's consulted before\n * falling back to `signature(cached)`; every updated session's signature is\n * written back into it, so the next call's cached-side lookups for unchanged\n * sessions can skip recomputation entirely. Mutating this caller-supplied map\n * is the only side effect — there's no module-level state. Callers must only\n * pass a cache whose lineage matches `cachedSessions`: if `cachedSessions` can\n * be a baseline the cache was never populated from (e.g. a DB snapshot instead\n * of the previous call's `updatedSessions`), a stale or mismatched hit will\n * silently suppress a real change.\n */\nexport function computeSessionDiff(\n cachedSessions: SessionHead[],\n updatedSessions: SessionHead[],\n changedIds: string[] = [],\n signature: (session: SessionHead) => string = sessionSignature,\n signatureCache?: Map<string, string>,\n): SessionDiffResult {\n const cachedMap = new Map(cachedSessions.map((session) => [session.id, session]));\n const updatedIds = new Set(updatedSessions.map((session) => session.id));\n const changedIdSet = new Set(changedIds);\n const changes: PersistedSessionHeadChange[] = [];\n const removedSessionIds: string[] = [];\n let newCount = 0;\n let updatedCount = 0;\n\n updatedSessions.forEach((session, sortIndex) => {\n const cached = cachedMap.get(session.id);\n if (!cached) {\n newCount += 1;\n changes.push({ session, sortIndex });\n signatureCache?.set(session.id, signature(session));\n return;\n }\n const cachedSignature = signatureCache?.get(cached.id) ?? signature(cached);\n const updatedSignature = signature(session);\n signatureCache?.set(session.id, updatedSignature);\n if (changedIdSet.has(session.id) || cachedSignature !== updatedSignature) {\n updatedCount += 1;\n changes.push({ session, sortIndex });\n }\n });\n\n for (const session of cachedSessions) {\n if (!updatedIds.has(session.id)) {\n removedSessionIds.push(session.id);\n }\n }\n\n return {\n changes,\n removedSessionIds,\n counts: { new: newCount, updated: updatedCount, removed: removedSessionIds.length },\n };\n}\n","import type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport type { SessionReference } from \"../contract/index.js\";\nimport type { ProjectIdentity, SessionDetail, SessionHead } from \"../types/index.js\";\nimport {\n classifySessionTags,\n extractSessionFileActivity,\n getSmartTagSourceTimestamp,\n SMART_TAG_CLASSIFIER_REVISION,\n} from \"../utils/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport { listSessionFileActivity } from \"./cache/file-activity.js\";\nimport { sessionDetailVersion } from \"./cache/detail-version.js\";\nimport {\n loadCachedSessionRawEntry,\n readCachedSessionCursor,\n type CachedSessionCursorEntry,\n type CachedSessionCursorReader,\n type CachedSessionRawEntry,\n} from \"./cache/sessions.js\";\nimport {\n messageCursorContentFromCachedRow,\n messageFromCachedRow,\n messageJsonFromCachedRow,\n type CachedMessageRow,\n} from \"./cache/messages.js\";\nimport {\n computeMessageCursorDigest,\n initialMessageCursorDigest,\n MESSAGE_CURSOR_VERSION,\n} from \"./cache/message-cursor.js\";\nimport type { LiveSnapshot } from \"./scanner.js\";\n\nexport type SessionDetailResult =\n | { status: \"found\"; data: SessionDetail }\n | { status: \"unknown-agent\" }\n | { status: \"not-ready\" }\n /**\n * The session has no identity on its head or cached detail. Resolving one\n * requires filesystem/git probing, which must not run on this synchronous\n * path — the caller resolves `directory` asynchronously and retries with\n * `projectIdentityFallback`.\n */\n | { status: \"needs-identity\"; directory: string };\n\nexport type SessionDetailResponseResult =\n | SessionDetailResult\n | {\n status: \"found-json\";\n data: Omit<SessionDetail, \"messages\">;\n messages: Iterable<string>;\n messageCount: number;\n sentMessageCount: number;\n };\n\nexport interface SessionDetailResponseOptions {\n messageCursor?: string;\n /** Pre-resolved identity used when neither the head nor the cache has one. */\n projectIdentityFallback?: ProjectIdentity;\n}\n\ninterface SessionDetailLookup {\n agentsByName: Map<string, BaseAgent>;\n headsByReference: Map<string, SessionHead>;\n}\n\ninterface SessionDetailContext {\n agent: BaseAgent;\n head: SessionHead | undefined;\n}\n\nconst sessionDetailLookups = new WeakMap<SessionHead[], SessionDetailLookup>();\nconst MAX_MESSAGE_CURSOR_LENGTH = 512;\n\ninterface MessageCursorPayload {\n version: typeof MESSAGE_CURSOR_VERSION;\n count: number;\n digest: string;\n}\n\nfunction parseMessageCursor(value: string | undefined): MessageCursorPayload | null {\n if (!value || value.length > MAX_MESSAGE_CURSOR_LENGTH) return null;\n try {\n const payload = JSON.parse(\n Buffer.from(value, \"base64url\").toString(\"utf8\"),\n ) as Partial<MessageCursorPayload>;\n if (\n payload.version !== MESSAGE_CURSOR_VERSION ||\n !Number.isSafeInteger(payload.count) ||\n payload.count == null ||\n payload.count < 0 ||\n typeof payload.digest !== \"string\" ||\n !/^[a-f0-9]{64}$/.test(payload.digest)\n ) {\n return null;\n }\n return payload as MessageCursorPayload;\n } catch {\n return null;\n }\n}\n\nfunction encodeMessageCursor(count: number, digest: string): string {\n return Buffer.from(JSON.stringify({ version: MESSAGE_CURSOR_VERSION, count, digest })).toString(\n \"base64url\",\n );\n}\n\ninterface CachedMessageStream {\n cursor: string;\n update: \"append\" | \"reset\";\n messageRows: CachedMessageRow[];\n messageCount: number;\n}\n\nfunction loadCachedMessageStream(\n reference: SessionReference,\n entry: CachedSessionCursorEntry,\n cursor: CachedSessionCursorReader,\n requestedCursor: string | undefined,\n): CachedMessageStream {\n const requested = parseMessageCursor(requestedCursor);\n const initialDigest = initialMessageCursorDigest(reference);\n const hasStoredChain = entry.messageCount === 0 || entry.messageDigest !== null;\n const canCheckAppend =\n hasStoredChain && requested !== null && requested.count <= entry.messageCount;\n const requestedDigest =\n canCheckAppend && requested\n ? requested.count === 0\n ? initialDigest\n : cursor.messageDigest(requested.count)\n : null;\n const canAppend = canCheckAppend && requested !== null && requestedDigest === requested.digest;\n let startIndex = canAppend ? requested.count : 0;\n let update: CachedMessageStream[\"update\"] = canAppend ? \"append\" : \"reset\";\n let messageRows = entry.messageCount === 0 ? [] : cursor.messageRows(startIndex);\n\n let messageCount = entry.messageCount;\n let digest = entry.messageCount === 0 ? initialDigest : entry.messageDigest;\n if (messageRows.length !== entry.messageCount - startIndex) {\n startIndex = 0;\n update = \"reset\";\n messageRows = cursor.messageRows(startIndex);\n messageCount = messageRows.length;\n digest = null;\n }\n\n if (!digest) {\n digest = computeMessageCursorDigest(\n reference,\n messageRows.map((row) => messageCursorContentFromCachedRow(row)),\n );\n }\n return {\n cursor: encodeMessageCursor(messageCount, digest),\n update,\n messageRows,\n messageCount,\n };\n}\n\nfunction sessionReferenceKey(agentName: string, sessionId: string): string {\n return `${agentName}\\0${sessionId}`;\n}\n\n/**\n * The canonical sessions array is replaced atomically with each scan snapshot,\n * so its identity also versions this lazily built lookup.\n */\nfunction getSessionDetailLookup(scanResult: LiveSnapshot): SessionDetailLookup {\n const cached = sessionDetailLookups.get(scanResult.sessions);\n if (cached) return cached;\n\n const agentsByName = new Map<string, BaseAgent>();\n for (const agent of scanResult.agents) {\n if (!agentsByName.has(agent.name)) agentsByName.set(agent.name, agent);\n }\n const headsByReference = new Map<string, SessionHead>();\n for (const [agentName, sessions] of Object.entries(scanResult.byAgent)) {\n for (const session of sessions) {\n const key = sessionReferenceKey(agentName, session.id);\n if (!headsByReference.has(key)) headsByReference.set(key, session);\n }\n }\n\n const lookup = { agentsByName, headsByReference };\n sessionDetailLookups.set(scanResult.sessions, lookup);\n return lookup;\n}\n\nfunction getSessionDetailContext(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n): SessionDetailContext | null {\n const lookup = getSessionDetailLookup(scanResult);\n const agent = lookup.agentsByName.get(reference.agentName);\n if (!agent) return null;\n return {\n agent,\n head: lookup.headsByReference.get(\n sessionReferenceKey(reference.agentName, reference.sessionId),\n ),\n };\n}\n\ntype CachedDetailState = \"fresh\" | \"stale\" | \"missing\";\ntype CachedSessionDetailEntry = Pick<\n CachedSessionRawEntry,\n \"data\" | \"detailVersion\" | \"pendingReindex\"\n>;\n\nfunction cachedDetailState(\n cachedEntry: CachedSessionDetailEntry | null,\n currentMeta: SessionCacheMeta | undefined,\n messageCount: number,\n): CachedDetailState {\n if (!cachedEntry || (messageCount === 0 && cachedEntry.data.stats.message_count > 0)) {\n return \"missing\";\n }\n return !cachedEntry.pendingReindex &&\n cachedEntry.detailVersion === sessionDetailVersion(currentMeta)\n ? \"fresh\"\n : \"stale\";\n}\n\nfunction getProjectIdentity(\n data: Pick<SessionDetail, \"directory\" | \"project_identity\">,\n head: SessionHead | undefined,\n fallback: ProjectIdentity | undefined,\n): ProjectIdentity | null {\n return head?.project_identity ?? data.project_identity ?? fallback ?? null;\n}\n\nfunction getSmartTags(data: SessionDetail) {\n if (\n Array.isArray(data.smart_tags) &&\n data.smart_tags_classifier_revision === SMART_TAG_CLASSIFIER_REVISION\n ) {\n return data.smart_tags;\n }\n return classifySessionTags(data);\n}\n\nfunction materializeStructuredSessionDetail(\n context: SessionDetailContext,\n reference: SessionReference,\n cachedEntry = loadCachedSessionRawEntry(reference.agentName, reference.sessionId),\n identityFallback?: ProjectIdentity,\n): SessionDetailResult {\n const { agent, head } = context;\n const currentMeta = head ? agent.getSessionMetaMap().get(reference.sessionId) : undefined;\n const cacheState = cachedDetailState(\n cachedEntry,\n currentMeta,\n cachedEntry?.messageRows.length ?? 0,\n );\n let useCache = cacheState === \"fresh\";\n let freshness: SessionDetail[\"detail_freshness\"] = useCache ? \"fresh\" : undefined;\n let data: SessionDetail | null = useCache\n ? {\n ...cachedEntry!.data,\n messages: cachedEntry!.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n }\n : null;\n let sourceError: unknown;\n if (!data && head) {\n try {\n data = agent.getSessionData(reference.sessionId);\n if (data) freshness = \"fresh\";\n } catch (error) {\n sourceError = error;\n }\n }\n if (!data && cacheState === \"stale\" && cachedEntry) {\n useCache = true;\n freshness = \"stale\";\n data = {\n ...cachedEntry.data,\n messages: cachedEntry.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n };\n getCoreDiagnostics()?.warn(\"session_detail.stale_fallback\", {\n agent: reference.agentName,\n session_id: reference.sessionId,\n stored_version: cachedEntry.detailVersion,\n target_version: sessionDetailVersion(currentMeta),\n error: sourceError instanceof Error ? sourceError.message : undefined,\n });\n }\n if (sourceError && !data) throw sourceError;\n\n if (!data) {\n return { status: \"not-ready\" };\n }\n\n const projectIdentity = getProjectIdentity(data, head, identityFallback);\n if (!projectIdentity) return { status: \"needs-identity\", directory: data.directory };\n const fileActivity =\n data.file_activity ??\n (useCache\n ? listSessionFileActivity(reference.agentName, reference.sessionId)\n : extractSessionFileActivity(\n reference.agentName,\n reference.sessionId,\n projectIdentity.key,\n data.messages,\n ));\n\n return {\n status: \"found\",\n data: {\n ...data,\n reference,\n detail_freshness: freshness,\n project_identity: projectIdentity,\n project_identity_resolver_revision:\n head?.project_identity_resolver_revision ?? data.project_identity_resolver_revision,\n project_identity_input_signature:\n head?.project_identity_input_signature ?? data.project_identity_input_signature,\n smart_tags: getSmartTags(data),\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n smart_tags_classifier_revision: SMART_TAG_CLASSIFIER_REVISION,\n file_activity: fileActivity,\n },\n };\n}\n\nfunction* serializeCachedMessages(messageRows: CachedMessageRow[]): IterableIterator<string> {\n for (const messageRow of messageRows) {\n yield messageJsonFromCachedRow(messageRow);\n }\n}\n\nexport function materializeSessionDetail(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n options: Pick<SessionDetailResponseOptions, \"projectIdentityFallback\"> = {},\n): SessionDetailResult {\n const context = getSessionDetailContext(scanResult, reference);\n if (!context) return { status: \"unknown-agent\" };\n return materializeStructuredSessionDetail(\n context,\n reference,\n undefined,\n options.projectIdentityFallback,\n );\n}\n\nexport function materializeSessionDetailResponse(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n options: SessionDetailResponseOptions = {},\n): SessionDetailResponseResult {\n const context = getSessionDetailContext(scanResult, reference);\n if (!context) return { status: \"unknown-agent\" };\n\n const currentMeta = context.head\n ? context.agent.getSessionMetaMap().get(reference.sessionId)\n : undefined;\n const startedAt = performance.now();\n const cursorRead = readCachedSessionCursor(\n reference.agentName,\n reference.sessionId,\n (entry, cursor) => {\n const cacheState = cachedDetailState(entry, currentMeta, entry.messageCount);\n const stream =\n cacheState === \"fresh\" &&\n entry.data.smart_tags != null &&\n entry.data.smart_tags_classifier_revision === SMART_TAG_CLASSIFIER_REVISION\n ? loadCachedMessageStream(reference, entry, cursor, options.messageCursor)\n : null;\n return { entry, cacheState, stream };\n },\n );\n const cachedEntry = cursorRead?.entry ?? null;\n const cacheState = cursorRead?.cacheState ?? \"missing\";\n if (\n !cachedEntry ||\n cacheState !== \"fresh\" ||\n cachedEntry.data.smart_tags == null ||\n cachedEntry.data.smart_tags_classifier_revision !== SMART_TAG_CLASSIFIER_REVISION\n ) {\n const result = materializeStructuredSessionDetail(\n context,\n reference,\n undefined,\n options.projectIdentityFallback,\n );\n return result.status === \"found\"\n ? { ...result, data: { ...result.data, message_update: \"reset\" } }\n : result;\n }\n\n const data = cachedEntry.data;\n const projectIdentity = getProjectIdentity(data, context.head, options.projectIdentityFallback);\n if (!projectIdentity) return { status: \"needs-identity\", directory: data.directory };\n const stream = cursorRead?.stream;\n if (!stream) {\n const result = materializeStructuredSessionDetail(\n context,\n reference,\n undefined,\n options.projectIdentityFallback,\n );\n return result.status === \"found\"\n ? { ...result, data: { ...result.data, message_update: \"reset\" } }\n : result;\n }\n const partsJsonBytes = stream.messageRows.reduce(\n (total, row) => total + Buffer.byteLength(String(row.parts_json)),\n 0,\n );\n getCoreDiagnostics()?.info?.(\"session_detail.cursor_stream\", {\n update: stream.update,\n message_count: stream.messageCount,\n sent_message_count: stream.messageRows.length,\n parts_json_bytes: partsJsonBytes,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return {\n status: \"found-json\",\n data: {\n ...data,\n reference,\n detail_freshness: \"fresh\",\n message_cursor: stream.cursor,\n message_update: stream.update,\n project_identity: projectIdentity,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n file_activity:\n data.file_activity ?? listSessionFileActivity(reference.agentName, reference.sessionId),\n },\n messages: serializeCachedMessages(stream.messageRows),\n messageCount: stream.messageCount,\n sentMessageCount: stream.messageRows.length,\n };\n}\n","/**\n * Project grouping: reads the project_groups_v view (or falls back to an\n * in-memory build) to list cached project groups.\n */\nimport type { ProjectGroup, ProjectIdentityKind, SessionHead } from \"../../types/index.js\";\nimport { buildProjectGroups } from \"../../projects/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./schema.js\";\n\nexport interface ProjectGroupRow extends DatabaseRow {\n identity_kind?: ProjectIdentityKind;\n identity_key?: string;\n display_name?: string;\n sources_csv?: string | null;\n session_count?: number;\n last_activity?: number | null;\n}\n\nexport function listCachedProjectGroups(sessions?: SessionHead[]): ProjectGroup[] {\n if (sessions) {\n return buildProjectGroups(sessions);\n }\n\n if (!hasCacheStorage()) {\n return [];\n }\n\n const queryRows = (db: SQLiteDatabase) =>\n db\n .prepare(\n `\n SELECT identity_kind, identity_key, display_name, sources_csv, session_count, last_activity\n FROM project_groups_v\n ORDER BY\n CASE identity_kind WHEN 'loose' THEN 1 ELSE 0 END,\n last_activity IS NULL,\n last_activity DESC\n `,\n )\n .all() as ProjectGroupRow[];\n\n const read = withCacheDbReadOnly(queryRows);\n const rows = read.status === \"success\" ? read.value : withCacheDb(queryRows);\n\n return (rows ?? []).map((row) => ({\n identityKind: row.identity_kind ?? \"path\",\n identityKey: String(row.identity_key ?? \"\"),\n displayName: String(row.display_name ?? \"\"),\n sources: String(row.sources_csv ?? \"\")\n .split(\",\")\n .filter(Boolean)\n .sort(),\n sessionCount: Number(row.session_count ?? 0),\n lastActivity: row.last_activity == null ? null : Number(row.last_activity),\n }));\n}\n","import type {\n DashboardCostFacts,\n MessageCostFact,\n SessionCostSummary,\n} from \"../../analytics/cost-facts.js\";\nimport type { CostSource } from \"../../contract/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDbReadOnly } from \"./schema.js\";\n\nexport interface CostFactOptions {\n from?: number;\n to?: number;\n includeModelCosts?: boolean;\n}\n\ninterface CostSummaryRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_count?: number;\n untimed_message_count?: number;\n input_tokens?: number;\n output_tokens?: number;\n reasoning_tokens?: number;\n cache_read_tokens?: number;\n cache_create_tokens?: number;\n untimed_input_tokens?: number;\n untimed_output_tokens?: number;\n untimed_reasoning_tokens?: number;\n untimed_cache_read_tokens?: number;\n untimed_cache_create_tokens?: number;\n message_cost?: number;\n untimed_message_cost?: number;\n}\n\ninterface MessageCostRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n cost_time?: number;\n model?: string | null;\n input_tokens?: number;\n output_tokens?: number;\n reasoning_tokens?: number;\n cache_read_tokens?: number;\n cache_create_tokens?: number;\n cost?: number;\n cost_source?: string | null;\n}\n\ninterface ModelCostRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n model?: string;\n cost?: number;\n cost_recorded?: number;\n}\n\nconst EFFECTIVE_COST_TIME = `CASE\n WHEN m.time_completed > 0 THEN m.time_completed\n WHEN m.time_created > 0 THEN m.time_created\nEND`;\n\nfunction sessionKey(agentName: string, sessionId: string): string {\n return `${agentName}\\u0000${sessionId}`;\n}\n\nfunction costSource(value: string | null | undefined): CostSource | undefined {\n return value === \"recorded\" || value === \"estimated\" ? value : undefined;\n}\n\nfunction nonNegative(value: number | undefined): number {\n return Math.max(0, Number(value ?? 0));\n}\n\nfunction readCostFacts(db: SQLiteDatabase, options: CostFactOptions): DashboardCostFacts {\n const summaries = db\n .prepare(\n `\n SELECT\n c.agent_name,\n c.session_id,\n c.message_count,\n c.untimed_message_count,\n c.input_tokens,\n c.output_tokens,\n c.reasoning_tokens,\n c.cache_read_tokens,\n c.cache_create_tokens,\n c.untimed_input_tokens,\n c.untimed_output_tokens,\n c.untimed_reasoning_tokens,\n c.untimed_cache_read_tokens,\n c.untimed_cache_create_tokens,\n c.message_cost,\n c.untimed_message_cost\n FROM session_cost_summary c\n JOIN sessions s\n ON s.agent_name = c.agent_name\n AND s.session_id = c.session_id\n AND s.publication_id IS NULL\n ORDER BY c.agent_name, c.session_id\n `,\n )\n .all() as CostSummaryRow[];\n\n const bySession = new Map<string, SessionCostSummary>();\n for (const row of summaries) {\n const agentName = String(row.agent_name ?? \"\");\n const sessionId = String(row.session_id ?? \"\");\n const summary: SessionCostSummary = {\n reference: { agentName, sessionId },\n messageCount: nonNegative(row.message_count),\n untimedMessageCount: nonNegative(row.untimed_message_count),\n inputTokens: nonNegative(row.input_tokens),\n outputTokens: nonNegative(row.output_tokens),\n reasoningTokens: nonNegative(row.reasoning_tokens),\n cacheReadTokens: nonNegative(row.cache_read_tokens),\n cacheCreateTokens: nonNegative(row.cache_create_tokens),\n untimedInputTokens: nonNegative(row.untimed_input_tokens),\n untimedOutputTokens: nonNegative(row.untimed_output_tokens),\n untimedReasoningTokens: nonNegative(row.untimed_reasoning_tokens),\n untimedCacheReadTokens: nonNegative(row.untimed_cache_read_tokens),\n untimedCacheCreateTokens: nonNegative(row.untimed_cache_create_tokens),\n messageCost: Number(row.message_cost ?? 0),\n untimedMessageCost: Number(row.untimed_message_cost ?? 0),\n modelCosts: [],\n };\n bySession.set(sessionKey(agentName, sessionId), summary);\n }\n\n const modelRows =\n options.includeModelCosts === false\n ? []\n : (db\n .prepare(\n `\n SELECT\n m.agent_name,\n m.session_id,\n m.model,\n m.cost,\n m.cost_recorded\n FROM session_model_cost m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n AND s.publication_id IS NULL\n ORDER BY m.agent_name, m.session_id, m.model\n `,\n )\n .all() as ModelCostRow[]);\n for (const row of modelRows) {\n const summary = bySession.get(\n sessionKey(String(row.agent_name ?? \"\"), String(row.session_id ?? \"\")),\n );\n if (!summary) continue;\n summary.modelCosts.push({\n model: String(row.model ?? \"\"),\n cost: Number(row.cost ?? 0),\n costRecorded: Number(row.cost_recorded ?? 0),\n });\n }\n\n const clauses = [`${EFFECTIVE_COST_TIME} IS NOT NULL`];\n const params: unknown[] = [];\n if (options.from != null) {\n clauses.push(`${EFFECTIVE_COST_TIME} >= ?`);\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(`${EFFECTIVE_COST_TIME} <= ?`);\n params.push(options.to);\n }\n\n const messageRows = db\n .prepare(\n `\n SELECT\n m.agent_name,\n m.session_id,\n ${EFFECTIVE_COST_TIME} AS cost_time,\n m.model,\n CAST(COALESCE(json_extract(m.tokens_json, '$.input'), 0) AS INTEGER) AS input_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.output'), 0) AS INTEGER) AS output_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.reasoning'), 0) AS INTEGER) AS reasoning_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.cache_read'), 0) AS INTEGER) AS cache_read_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.cache_create'), 0) AS INTEGER) AS cache_create_tokens,\n m.cost,\n m.cost_source\n FROM messages m INDEXED BY idx_messages_usage_time\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n AND s.publication_id IS NULL\n WHERE ${clauses.join(\" AND \")}\n ORDER BY cost_time, m.agent_name, m.session_id, m.message_index\n `,\n )\n .all(...params) as MessageCostRow[];\n\n const messages: MessageCostFact[] = messageRows.map((row) => {\n const model = typeof row.model === \"string\" && row.model.length > 0 ? row.model : undefined;\n return {\n reference: {\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n },\n time: Number(row.cost_time ?? 0),\n inputTokens: nonNegative(row.input_tokens),\n outputTokens: nonNegative(row.output_tokens),\n reasoningTokens: nonNegative(row.reasoning_tokens),\n cacheReadTokens: nonNegative(row.cache_read_tokens),\n cacheCreateTokens: nonNegative(row.cache_create_tokens),\n cost: Number(row.cost ?? 0),\n costSource: costSource(row.cost_source),\n ...(model ? { model } : {}),\n };\n });\n\n return { messages, sessions: [...bySession.values()] };\n}\n\nexport function listDashboardCostFacts(options: CostFactOptions = {}): DashboardCostFacts | null {\n if (!hasCacheStorage()) return null;\n\n const read = withCacheDbReadOnly((db: SQLiteDatabase) =>\n db.transaction(() => readCostFacts(db, options))(),\n );\n return read.status === \"success\" ? read.value : null;\n}\n","/**\n * Per-model cost aggregation. Session heads only carry per-model token totals,\n * so the cost split by model is only derivable from the cached message rows.\n */\nimport type { ModelCostEntry } from \"../../contract/index.js\";\nimport type { ProjectIdentityKind } from \"../../types/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDbReadOnly } from \"./schema.js\";\n\nexport type { ModelCostEntry };\n\nexport interface ModelCostOptions {\n agent?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n from?: number;\n to?: number;\n limit?: number;\n}\n\ninterface ModelCostRow extends DatabaseRow {\n model?: string;\n cost?: number;\n cost_recorded?: number;\n cost_estimated?: number;\n}\n\nconst DEFAULT_MODEL_COST_LIMIT = 20;\n\nfunction buildModelCostWhere(options: ModelCostOptions): {\n where: string;\n params: unknown[];\n} {\n const clauses = [\"m.model IS NOT NULL\", \"m.model <> ''\"];\n const params: unknown[] = [];\n\n if (options.agent != null) {\n clauses.push(\"s.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.projectKind != null || options.projectKey != null) {\n if (options.projectKind != null && options.projectKey != null) {\n clauses.push(\"s.project_identity_kind = ? AND s.project_identity_key = ?\");\n params.push(options.projectKind, options.projectKey);\n } else {\n // A half-specified identity can never match — mirrors listFileActivity.\n clauses.push(\"0\");\n }\n }\n if (options.from != null) {\n clauses.push(\"s.activity_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"s.activity_time <= ?\");\n params.push(options.to);\n }\n\n return { where: `WHERE ${clauses.join(\" AND \")}`, params };\n}\n\n/**\n * Sub-session messages are included on purpose: a parent's cost is defined to\n * cover its whole subtree. An unset `cost_source` counts as estimated, so\n * `costRecorded + costEstimated === cost` always holds.\n *\n * Reads the per-(session, model) rollup maintained alongside message writes\n * (CS-270) — sessions×models rows instead of a full messages-table scan.\n */\nconst MODEL_COST_SQL = `\n SELECT\n m.model AS model,\n SUM(m.cost) AS cost,\n SUM(m.cost_recorded) AS cost_recorded,\n SUM(m.cost - m.cost_recorded) AS cost_estimated\n FROM session_model_cost m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n AND s.publication_id IS NULL\n`;\n\n/**\n * Returns null when no cache database is available (--no-cache, or the\n * search-index worker has not created it yet). Callers MUST propagate the null\n * rather than substituting zeros.\n */\nexport function listModelCostDistribution(options: ModelCostOptions = {}): ModelCostEntry[] | null {\n if (!hasCacheStorage()) {\n return null;\n }\n\n const { where, params } = buildModelCostWhere(options);\n const sql = `\n ${MODEL_COST_SQL}\n ${where}\n GROUP BY m.model\n ORDER BY cost DESC, m.model\n LIMIT ?\n `;\n\n const read = withCacheDbReadOnly(\n (db: SQLiteDatabase) =>\n db.prepare(sql).all(...params, options.limit ?? DEFAULT_MODEL_COST_LIMIT) as ModelCostRow[],\n );\n if (read.status === \"failed\") {\n return null;\n }\n\n return read.value.map((row) => ({\n model: String(row.model ?? \"\"),\n cost: Number(row.cost ?? 0),\n costRecorded: Number(row.cost_recorded ?? 0),\n costEstimated: Number(row.cost_estimated ?? 0),\n }));\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { SessionCacheMeta } from \"../../agents/base.js\";\nimport type { SessionDetail, SessionHead } from \"../../types/index.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport type { PersistedSessionHeadChange } from \"./db.js\";\nimport { advanceAnalyticsRevision } from \"./analytics-revision.js\";\nimport { sessionDetailVersion } from \"./detail-version.js\";\nimport { assertSessionProjectIdentities } from \"./messages.js\";\nimport {\n prepareSessionChangesSearchIndex,\n prepareSessionSnapshotSearchIndex,\n discardPreparedSessionSearchIndex,\n writePreparedSessionSearchIndex,\n type SearchIndexSyncOptions,\n type SearchIndexSyncResult,\n} from \"./search-index-writer.js\";\nimport { withSearchIndexDb } from \"./schema.js\";\nimport {\n deleteLegacyCacheFile,\n writeCachedSessionChanges,\n writeCachedSessionSnapshot,\n type SessionSnapshotCompleteness,\n} from \"./sessions.js\";\n\nexport type DurableSessionPublication =\n | {\n kind: \"snapshot\";\n agentName: string;\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n completeness: SessionSnapshotCompleteness;\n removedSessionIds: string[];\n publicationId?: string;\n }\n | {\n kind: \"changes\";\n agentName: string;\n changes: PersistedSessionHeadChange[];\n removedSessionIds: string[];\n meta: Record<string, SessionCacheMeta>;\n publicationId?: string;\n };\n\nexport type DurableSessionPublicationFailureStage = \"prepare\" | \"cache\" | \"search_index\" | \"commit\";\n\nexport type DurableSessionPublicationCommitResult =\n | {\n status: \"committed\";\n publicationId: string;\n searchIndex: SearchIndexSyncResult;\n }\n | {\n status: \"rolled-back\";\n publicationId: string;\n stage: DurableSessionPublicationFailureStage;\n };\n\nfunction publicationSessionCount(publication: DurableSessionPublication): number {\n return publication.kind === \"snapshot\" ? publication.sessions.length : publication.changes.length;\n}\n\nfunction publicationSearchOptions(\n publication: DurableSessionPublication,\n options: SearchIndexSyncOptions,\n publicationId: string,\n): SearchIndexSyncOptions {\n return {\n ...options,\n includePendingReindex: false,\n publicationId,\n ...(publication.kind === \"snapshot\"\n ? {\n completeness: publication.completeness,\n removedSessionIds: publication.removedSessionIds,\n }\n : {}),\n detailVersions: Object.fromEntries(\n Object.entries(publication.meta).map(([sessionId, meta]) => [\n sessionId,\n sessionDetailVersion(meta),\n ]),\n ),\n };\n}\n\nexport function commitDurableSessionPublication(\n publication: DurableSessionPublication,\n loadSessionData: (sessionId: string) => SessionDetail,\n searchOptions: SearchIndexSyncOptions = {},\n): DurableSessionPublicationCommitResult {\n assertSessionProjectIdentities(\n publication.agentName,\n publication.kind === \"snapshot\"\n ? publication.sessions\n : publication.changes.map(({ session }) => session),\n );\n const publicationId = publication.publicationId ?? randomUUID();\n let failureStage: DurableSessionPublicationFailureStage = \"prepare\";\n const diagnostics = getCoreDiagnostics();\n const detail = {\n agent: publication.agentName,\n publication_id: publicationId,\n sessions: publicationSessionCount(publication),\n };\n diagnostics?.info?.(\"search_index.publication_stage\", { ...detail, stage: \"started\" });\n\n const searchIndex = withSearchIndexDb((db) => {\n const options = publicationSearchOptions(publication, searchOptions, publicationId);\n const prepared =\n publication.kind === \"snapshot\"\n ? prepareSessionSnapshotSearchIndex(\n db,\n publication.agentName,\n publication.sessions,\n loadSessionData,\n options,\n )\n : prepareSessionChangesSearchIndex(\n db,\n publication.agentName,\n publication.changes,\n publication.removedSessionIds,\n loadSessionData,\n options,\n );\n diagnostics?.info?.(\"search_index.publication_stage\", { ...detail, stage: \"prepared\" });\n\n return db\n .transaction(() => {\n failureStage = \"cache\";\n if (publication.kind === \"snapshot\") {\n writeCachedSessionSnapshot(\n db,\n publication.agentName,\n publication.sessions,\n publication.meta,\n {\n completeness: publication.completeness,\n removedSessionIds: publication.removedSessionIds,\n },\n );\n } else {\n writeCachedSessionChanges(\n db,\n publication.agentName,\n publication.changes,\n publication.removedSessionIds,\n publication.meta,\n );\n }\n diagnostics?.info?.(\"search_index.publication_stage\", {\n ...detail,\n stage: \"cache_staged\",\n });\n\n failureStage = \"search_index\";\n const result = writePreparedSessionSearchIndex(db, prepared);\n diagnostics?.info?.(\"search_index.publication_stage\", {\n ...detail,\n stage: \"search_staged\",\n });\n advanceAnalyticsRevision(db);\n failureStage = \"commit\";\n return result;\n })\n .immediate();\n });\n\n if (!searchIndex) {\n discardPreparedSessionSearchIndex(publicationId);\n diagnostics?.warn(\"search_index.publication_stage\", {\n ...detail,\n stage: \"rolled_back\",\n failure_stage: failureStage,\n });\n return { status: \"rolled-back\", publicationId, stage: failureStage };\n }\n\n deleteLegacyCacheFile();\n diagnostics?.info?.(\"search_index.publication_stage\", { ...detail, stage: \"committed\" });\n return { status: \"committed\", publicationId, searchIndex };\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n columnExists,\n getUserVersion,\n openDb,\n runSchemaMigrations,\n setUserVersion,\n tableExists,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../utils/sqlite.js\";\n\nconst STATE_DB_FILENAME = \"state.db\";\nconst STATE_SCHEMA_VERSION = 3;\nconst MEMORY_STATE_STORE = \"memory\";\n\n// One-shot per-process ensureSchema guard, mirroring the cache side's\n// schemaEnsuredPath (discovery/cache/db.ts). Keyed by dbPath so tests can\n// switch state directories; exported so tests can reset it between runs.\nlet stateSchemaEnsuredPath: string | null = null;\n\nexport function getStateSchemaEnsuredPath(): string | null {\n return stateSchemaEnsuredPath;\n}\n\nexport function setStateSchemaEnsuredPath(path: string | null): void {\n stateSchemaEnsuredPath = path;\n}\n\nexport class StateStorageUnavailableError extends Error {\n constructor() {\n super(\"SQLite state database is unavailable\");\n this.name = \"StateStorageUnavailableError\";\n }\n}\n\nfunction getStateDir(): string {\n if (process.env.CODESESH_STATE_DIR) return process.env.CODESESH_STATE_DIR;\n\n const currentPlatform = platform();\n if (currentPlatform === \"darwin\") {\n return join(homedir(), \"Library\", \"Application Support\", \"codesesh\");\n }\n if (currentPlatform === \"win32\") {\n const appData = process.env.APPDATA ?? process.env.LOCALAPPDATA;\n return join(appData ?? join(homedir(), \"AppData\", \"Roaming\"), \"codesesh\");\n }\n return join(process.env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\"), \"codesesh\");\n}\n\nfunction getStateDbPath(): string {\n return join(getStateDir(), STATE_DB_FILENAME);\n}\n\nexport function useMemoryStateStore(): boolean {\n return process.env.CODESESH_STATE_STORE === MEMORY_STATE_STORE;\n}\n\nfunction createBookmarksTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS bookmarks (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n bookmarked_at INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\n}\n\nfunction migrateBookmarkFacts(db: SQLiteDatabase): void {\n db.exec(\"ALTER TABLE bookmarks RENAME TO bookmarks_with_snapshots\");\n createBookmarksTable(db);\n db.exec(`\n INSERT INTO bookmarks(agent_name, session_id, bookmarked_at)\n SELECT agent_name, session_id, bookmarked_at\n FROM bookmarks_with_snapshots;\n\n DROP TABLE bookmarks_with_snapshots;\n `);\n}\n\nfunction createSessionAliasesTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_aliases (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n alias TEXT NOT NULL,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\n}\n\nfunction createStateSchema(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS state_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n createBookmarksTable(db);\n createSessionAliasesTable(db);\n}\n\nfunction readLegacyStateVersion(db: SQLiteDatabase): number {\n if (\n !tableExists(db, \"state_meta\") ||\n !columnExists(db, \"state_meta\", \"key\") ||\n !columnExists(db, \"state_meta\", \"value\")\n ) {\n return 0;\n }\n\n const row = db.prepare(\"SELECT value FROM state_meta WHERE key = 'version'\").get() as\n | DatabaseRow\n | undefined;\n return Number(row?.value ?? 0);\n}\n\nfunction getCurrentStateSchemaVersion(db: SQLiteDatabase): number {\n const userVersion = getUserVersion(db);\n if (userVersion > 0) return userVersion;\n\n const legacyVersion = readLegacyStateVersion(db);\n if (legacyVersion > 0) return legacyVersion;\n\n return tableExists(db, \"bookmarks\") ? 1 : 0;\n}\n\nfunction hasAnyStateSchema(db: SQLiteDatabase): boolean {\n return tableExists(db, \"state_meta\") || tableExists(db, \"bookmarks\");\n}\n\nfunction setStateSchemaVersion(db: SQLiteDatabase): void {\n createStateSchema(db);\n setUserVersion(db, STATE_SCHEMA_VERSION);\n db.prepare(\n `\n INSERT INTO state_meta(key, value)\n VALUES ('version', ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(String(STATE_SCHEMA_VERSION));\n}\n\nfunction ensureSchema(db: SQLiteDatabase, dbPath: string): void {\n const currentVersion = getCurrentStateSchemaVersion(db);\n if (currentVersion === 0 && !hasAnyStateSchema(db)) {\n setStateSchemaVersion(db);\n return;\n }\n\n runSchemaMigrations(db, {\n dbPath,\n currentVersion,\n targetVersion: STATE_SCHEMA_VERSION,\n backupLabel: \"state-migration\",\n backupTables: [\"bookmarks\", \"session_aliases\"],\n migrations: [\n { version: 1, migrate: createBookmarksTable },\n { version: 2, migrate: createSessionAliasesTable },\n { version: 3, destructive: true, migrate: migrateBookmarkFacts },\n ],\n });\n\n if (currentVersion < STATE_SCHEMA_VERSION) {\n setStateSchemaVersion(db);\n }\n}\n\nexport function withStateDb<T>(fn: (db: SQLiteDatabase) => T): T {\n const statePath = getStateDbPath();\n const db = openDb(statePath);\n if (!db) throw new StateStorageUnavailableError();\n\n try {\n if (getStateSchemaEnsuredPath() !== statePath) {\n ensureSchema(db, statePath);\n setStateSchemaEnsuredPath(statePath);\n }\n return fn(db);\n } finally {\n db.close();\n }\n}\n","import {\n normalizeSessionReference,\n type BookmarkRecord,\n type SessionReference,\n} from \"../contract/index.js\";\nimport { StateStorageUnavailableError, useMemoryStateStore, withStateDb } from \"./database.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../utils/sqlite.js\";\n\nconst memoryBookmarks = new Map<string, BookmarkRecord>();\n\nexport { StateStorageUnavailableError as BookmarkStorageUnavailableError };\n\nexport type { BookmarkRecord };\n\ninterface BookmarkRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n bookmarked_at?: number;\n}\n\nfunction getBookmarkKey(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return JSON.stringify([normalized.agentName, normalized.sessionId]);\n}\n\nfunction compareBookmarks(left: BookmarkRecord, right: BookmarkRecord): number {\n if (left.bookmarkedAt !== right.bookmarkedAt) {\n return left.bookmarkedAt > right.bookmarkedAt ? -1 : 1;\n }\n return getBookmarkKey(left.reference).localeCompare(getBookmarkKey(right.reference));\n}\n\nfunction normalizeBookmark(bookmark: BookmarkRecord): BookmarkRecord {\n return {\n reference: normalizeSessionReference(bookmark.reference),\n bookmarkedAt: bookmark.bookmarkedAt,\n };\n}\n\nfunction toBookmarkRecord(row: BookmarkRow): BookmarkRecord {\n return {\n reference: normalizeSessionReference({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n }),\n bookmarkedAt: Number(row.bookmarked_at ?? 0),\n };\n}\n\nfunction readBookmarks(db: SQLiteDatabase): BookmarkRecord[] {\n const rows = db\n .prepare(\n `\n SELECT agent_name, session_id, bookmarked_at\n FROM bookmarks\n ORDER BY bookmarked_at DESC, agent_name ASC, session_id ASC\n `,\n )\n .all() as BookmarkRow[];\n return rows.map(toBookmarkRecord);\n}\n\nfunction listMemoryBookmarks(): BookmarkRecord[] {\n return [...memoryBookmarks.values()].sort(compareBookmarks);\n}\n\nexport function listBookmarks(): BookmarkRecord[] {\n if (useMemoryStateStore()) return listMemoryBookmarks();\n return withStateDb(readBookmarks);\n}\n\nexport function upsertBookmark(reference: SessionReference): BookmarkRecord {\n const normalized = normalizeSessionReference(reference);\n const key = getBookmarkKey(normalized);\n if (useMemoryStateStore()) {\n const bookmark = memoryBookmarks.get(key) ?? {\n reference: normalized,\n bookmarkedAt: Date.now(),\n };\n memoryBookmarks.set(key, bookmark);\n return bookmark;\n }\n\n return withStateDb((db) => {\n const row = db\n .prepare(\n `\n INSERT INTO bookmarks(agent_name, session_id, bookmarked_at)\n VALUES (?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE\n SET bookmarked_at = bookmarks.bookmarked_at\n RETURNING agent_name, session_id, bookmarked_at\n `,\n )\n .get(normalized.agentName, normalized.sessionId, Date.now()) as BookmarkRow | undefined;\n if (!row) {\n throw new Error(\"Bookmark upsert returned no row\");\n }\n return toBookmarkRecord(row);\n });\n}\n\nexport function importBookmarks(bookmarks: readonly BookmarkRecord[]): BookmarkRecord[] {\n const unique = new Map<string, BookmarkRecord>();\n for (const bookmark of bookmarks) {\n const normalized = normalizeBookmark(bookmark);\n const key = getBookmarkKey(normalized.reference);\n if (!unique.has(key)) unique.set(key, normalized);\n }\n\n if (useMemoryStateStore()) {\n for (const [key, bookmark] of unique) {\n if (!memoryBookmarks.has(key)) memoryBookmarks.set(key, bookmark);\n }\n return listMemoryBookmarks();\n }\n\n return withStateDb((db) => {\n const insert = db.prepare(\n `\n INSERT INTO bookmarks(agent_name, session_id, bookmarked_at)\n VALUES (?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO NOTHING\n `,\n );\n const write = db.transaction(() => {\n for (const bookmark of unique.values()) {\n insert.run(\n bookmark.reference.agentName,\n bookmark.reference.sessionId,\n bookmark.bookmarkedAt,\n );\n }\n });\n write.immediate();\n return readBookmarks(db);\n });\n}\n\nexport function deleteBookmark(reference: SessionReference): void {\n const normalized = normalizeSessionReference(reference);\n if (useMemoryStateStore()) {\n memoryBookmarks.delete(getBookmarkKey(normalized));\n return;\n }\n\n withStateDb((db) => {\n db.prepare(\n `\n DELETE FROM bookmarks\n WHERE agent_name = ? AND session_id = ?\n `,\n ).run(normalized.agentName, normalized.sessionId);\n });\n}\n","import { StateStorageUnavailableError, useMemoryStateStore, withStateDb } from \"./database.js\";\nimport type { DatabaseRow } from \"../utils/sqlite.js\";\nimport { normalizeSessionReference, type SessionReference } from \"../contract/index.js\";\n\nexport const SESSION_ALIAS_MAX_LENGTH = 160;\n\nexport class SessionAliasValidationError extends Error {\n constructor() {\n super(\"Invalid session alias\");\n this.name = \"SessionAliasValidationError\";\n }\n}\n\nexport interface SessionAlias {\n reference: SessionReference;\n alias: string;\n updatedAt: number;\n}\n\ninterface SessionAliasRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n alias?: string;\n updated_at?: number;\n}\n\nconst memoryAliases = new Map<string, SessionAlias>();\n\nfunction getAliasKey(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return JSON.stringify([normalized.agentName, normalized.sessionId]);\n}\n\nfunction toSessionAlias(row: SessionAliasRow): SessionAlias {\n const reference = normalizeSessionReference({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n });\n return {\n reference,\n alias: String(row.alias ?? \"\"),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nexport function normalizeSessionAlias(value: string): string | null {\n const alias = value.trim();\n if (!alias || alias.length > SESSION_ALIAS_MAX_LENGTH) return null;\n return alias;\n}\n\nexport function listSessionAliases(): SessionAlias[] {\n if (useMemoryStateStore()) return [...memoryAliases.values()];\n\n return withStateDb((db) =>\n (\n db\n .prepare(\n `\n SELECT agent_name, session_id, alias, updated_at\n FROM session_aliases\n ORDER BY updated_at DESC\n `,\n )\n .all() as SessionAliasRow[]\n ).map(toSessionAlias),\n );\n}\n\nexport function upsertSessionAlias(reference: SessionReference, alias: string): SessionAlias {\n const normalizedAlias = normalizeSessionAlias(alias);\n if (!normalizedAlias) {\n throw new SessionAliasValidationError();\n }\n\n const normalizedReference = normalizeSessionReference(reference);\n const saved: SessionAlias = {\n reference: normalizedReference,\n alias: normalizedAlias,\n updatedAt: Date.now(),\n };\n if (useMemoryStateStore()) {\n memoryAliases.set(getAliasKey(normalizedReference), saved);\n return saved;\n }\n\n return withStateDb((db) => {\n db.prepare(\n `\n INSERT INTO session_aliases(agent_name, session_id, alias, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n alias = excluded.alias,\n updated_at = excluded.updated_at\n `,\n ).run(saved.reference.agentName, saved.reference.sessionId, saved.alias, saved.updatedAt);\n return saved;\n });\n}\n\nexport function deleteSessionAlias(reference: SessionReference): void {\n const normalizedReference = normalizeSessionReference(reference);\n if (useMemoryStateStore()) {\n memoryAliases.delete(getAliasKey(normalizedReference));\n return;\n }\n\n withStateDb((db) => {\n db.prepare(\n `\n DELETE FROM session_aliases\n WHERE agent_name = ? AND session_id = ?\n `,\n ).run(normalizedReference.agentName, normalizedReference.sessionId);\n });\n}\n\nexport { StateStorageUnavailableError };\n","import type {\n BookmarkRecord,\n BookmarkView,\n ReferencedSessionHead,\n SessionHead,\n SessionReference,\n} from \"../contract/index.js\";\nimport { formatSessionReference, normalizeSessionReference } from \"../contract/index.js\";\n\nexport interface BookmarkMaterializationOptions {\n liveSessionsByReference: ReadonlyMap<string, SessionHead>;\n knownAgentNames: ReadonlySet<string>;\n resolveCachedSessions?: (\n references: readonly SessionReference[],\n ) => readonly ReferencedSessionHead[];\n}\n\nfunction referenceKey(reference: SessionReference): string {\n return formatSessionReference(normalizeSessionReference(reference));\n}\n\nfunction canonicalSession(reference: SessionReference, session: SessionHead): SessionHead {\n return {\n ...session,\n id: reference.sessionId,\n slug: formatSessionReference(reference),\n };\n}\n\nfunction compareDescending(left: number, right: number): number {\n if (left === right) return 0;\n return left > right ? -1 : 1;\n}\n\nfunction getBookmarkViewTime(bookmark: BookmarkView): number {\n return bookmark.availability === \"available\"\n ? (bookmark.session.time_updated ?? bookmark.session.time_created)\n : bookmark.bookmarkedAt;\n}\n\nexport function compareBookmarkViews(left: BookmarkView, right: BookmarkView): number {\n return (\n compareDescending(getBookmarkViewTime(left), getBookmarkViewTime(right)) ||\n compareDescending(left.bookmarkedAt, right.bookmarkedAt) ||\n referenceKey(left.reference).localeCompare(referenceKey(right.reference))\n );\n}\n\nexport function materializeBookmarkViews(\n bookmarks: readonly BookmarkRecord[],\n options: BookmarkMaterializationOptions,\n): BookmarkView[] {\n const liveByKey = new Map<string, SessionHead>();\n const missingByKey = new Map<string, SessionReference>();\n const normalizedBookmarks = bookmarks.map((bookmark) => {\n const reference = normalizeSessionReference(bookmark.reference);\n return {\n bookmark: { reference, bookmarkedAt: bookmark.bookmarkedAt },\n key: referenceKey(reference),\n };\n });\n\n for (const { bookmark, key } of normalizedBookmarks) {\n const { reference } = bookmark;\n const live = options.liveSessionsByReference.get(key);\n if (live) liveByKey.set(key, canonicalSession(reference, live));\n else if (!missingByKey.has(key)) missingByKey.set(key, reference);\n }\n\n const cachedByKey = new Map<string, SessionHead>();\n if (missingByKey.size > 0 && options.resolveCachedSessions) {\n for (const cached of options.resolveCachedSessions([...missingByKey.values()])) {\n const reference = normalizeSessionReference(cached.reference);\n const key = referenceKey(reference);\n if (missingByKey.has(key) && !cachedByKey.has(key)) {\n cachedByKey.set(key, canonicalSession(reference, cached.session));\n }\n }\n }\n\n const views = normalizedBookmarks.map(({ bookmark, key }): BookmarkView => {\n const session = liveByKey.get(key) ?? cachedByKey.get(key);\n if (session) return { ...bookmark, availability: \"available\", session };\n\n return {\n ...bookmark,\n availability: options.knownAgentNames.has(bookmark.reference.agentName)\n ? \"session-unavailable\"\n : \"agent-unavailable\",\n };\n });\n\n return views.sort(compareBookmarkViews);\n}\n","import type { CostSource, SessionHead } from \"../types/session.js\";\nimport type { SessionTree, SessionTreeNode } from \"../contract/index.js\";\nimport { getSessionAgentKey, getSessionRouteKey } from \"../contract/index.js\";\nimport type {\n DashboardCostFacts,\n MessageCostFact,\n SessionCostSummary,\n SessionModelCostFact,\n} from \"./cost-facts.js\";\n\nconst COST_ABSOLUTE_TOLERANCE = 1e-8;\nconst COST_RELATIVE_TOLERANCE = 1e-6;\n\ninterface MetricFactIndex {\n messagesBySession: Map<string, MessageCostFact[]>;\n summariesBySession: Map<string, SessionCostSummary>;\n}\n\nexport interface AttributedCost {\n entry: SessionTreeNode;\n time: number;\n cost: number;\n source: CostSource;\n modelCosts: SessionModelCostFact[];\n}\n\nexport interface CostAttributionOptions {\n from?: number;\n to: number;\n facts?: DashboardCostFacts | null;\n matchesEntry?: (session: SessionHead) => boolean;\n}\n\nexport interface AttributedUsage {\n entry: SessionTreeNode;\n time: number;\n messages: number;\n totalTokens: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreateTokens: number;\n}\n\nexport type UsageAttributionOptions = CostAttributionOptions;\n\nfunction costFactKey(agentName: string, sessionId: string): string {\n return getSessionRouteKey(agentName, sessionId);\n}\n\nfunction indexFacts(facts: DashboardCostFacts | null | undefined): MetricFactIndex {\n const messagesBySession = new Map<string, MessageCostFact[]>();\n const summariesBySession = new Map<string, SessionCostSummary>();\n if (!facts) return { messagesBySession, summariesBySession };\n\n for (const summary of facts.sessions) {\n summariesBySession.set(\n costFactKey(summary.reference.agentName, summary.reference.sessionId),\n summary,\n );\n }\n for (const message of facts.messages) {\n const key = costFactKey(message.reference.agentName, message.reference.sessionId);\n const messages = messagesBySession.get(key);\n if (messages) messages.push(message);\n else messagesBySession.set(key, [message]);\n }\n return { messagesBySession, summariesBySession };\n}\n\nfunction nonNegative(value: number | undefined): number {\n return Math.max(0, Number(value ?? 0));\n}\n\nfunction costsReconcile(left: number, right: number): boolean {\n const tolerance = Math.max(\n COST_ABSOLUTE_TOLERANCE,\n Math.max(Math.abs(left), Math.abs(right)) * COST_RELATIVE_TOLERANCE,\n );\n return Math.abs(left - right) <= tolerance;\n}\n\nfunction hasDetailedCost(session: SessionHead, summary: SessionCostSummary | undefined): boolean {\n const totalCost = Math.max(0, session.stats.total_cost);\n return (\n totalCost > 0 &&\n summary != null &&\n summary.untimedMessageCost <= COST_ABSOLUTE_TOLERANCE &&\n costsReconcile(summary.messageCost, totalCost)\n );\n}\n\nfunction hasDetailedMessages(\n session: SessionHead,\n summary: SessionCostSummary | undefined,\n): boolean {\n return (\n summary != null &&\n summary.untimedMessageCount === 0 &&\n summary.messageCount === nonNegative(session.stats.message_count)\n );\n}\n\n// Provider payloads disagree on whether reasoning is already included in output.\nfunction detailedOutputIncludesReasoning(\n session: SessionHead,\n summary: SessionCostSummary | undefined,\n): boolean | null {\n if (!summary) return null;\n const stats = session.stats;\n const sessionInput = nonNegative(stats.total_input_tokens);\n const sessionOutput = nonNegative(stats.total_output_tokens);\n const sessionCacheRead = nonNegative(stats.total_cache_read_tokens);\n const sessionCacheCreate = nonNegative(stats.total_cache_create_tokens);\n const sessionTotal = nonNegative(stats.total_tokens ?? sessionInput + sessionOutput);\n const outputIncludesReasoning = summary.outputTokens + summary.reasoningTokens;\n const outputMatches = summary.outputTokens === sessionOutput;\n const outputWithReasoningMatches = outputIncludesReasoning === sessionOutput;\n const effectiveOutput = outputMatches\n ? summary.outputTokens\n : outputWithReasoningMatches\n ? outputIncludesReasoning\n : null;\n\n if (\n effectiveOutput == null ||\n summary.inputTokens !== sessionInput ||\n summary.cacheReadTokens !== sessionCacheRead ||\n summary.cacheCreateTokens !== sessionCacheCreate ||\n summary.inputTokens + effectiveOutput !== sessionTotal ||\n summary.untimedInputTokens > 0 ||\n summary.untimedOutputTokens > 0 ||\n summary.untimedReasoningTokens > 0 ||\n summary.untimedCacheReadTokens > 0 ||\n summary.untimedCacheCreateTokens > 0\n ) {\n return null;\n }\n return !outputMatches && outputWithReasoningMatches;\n}\n\nfunction isInWindow(time: number, from: number | undefined, to: number): boolean {\n return (from == null || time >= from) && time <= to;\n}\n\nfunction resolvedCostSource(session: SessionHead, source?: CostSource): CostSource {\n return source ?? session.stats.cost_source ?? \"recorded\";\n}\n\nfunction fallbackModelCosts(\n summary: SessionCostSummary | undefined,\n totalCost: number,\n): SessionModelCostFact[] {\n if (!summary) return [];\n const modelTotal = summary.modelCosts.reduce((sum, model) => sum + model.cost, 0);\n return modelTotal > totalCost && !costsReconcile(modelTotal, totalCost) ? [] : summary.modelCosts;\n}\n\nexport function visitAttributedCosts(\n tree: SessionTree,\n options: CostAttributionOptions,\n visit: (attributed: AttributedCost) => void,\n): void {\n const factIndex = indexFacts(options.facts);\n const factsAvailable = options.facts != null;\n\n for (const entry of tree.entries) {\n if (options.matchesEntry && !options.matchesEntry(entry.session)) continue;\n const fallbackTime = entry.session.time_updated ?? entry.session.time_created;\n const pending = [entry];\n\n while (pending.length > 0) {\n const node = pending.pop()!;\n for (const child of node.children) pending.push(child);\n\n const session = node.session;\n const totalCost = Math.max(0, session.stats.total_cost);\n if (totalCost <= 0) continue;\n const agentName = getSessionAgentKey(session);\n const key = costFactKey(agentName, session.id);\n const summary = factIndex.summariesBySession.get(key);\n\n if (factsAvailable && hasDetailedCost(session, summary)) {\n for (const message of factIndex.messagesBySession.get(key) ?? []) {\n if (!isInWindow(message.time, options.from, options.to) || message.cost <= 0) continue;\n const source = resolvedCostSource(session, message.costSource);\n visit({\n entry,\n time: message.time,\n cost: message.cost,\n source,\n modelCosts: message.model\n ? [\n {\n model: message.model,\n cost: message.cost,\n costRecorded: source === \"recorded\" ? message.cost : 0,\n },\n ]\n : [],\n });\n }\n continue;\n }\n\n if (!isInWindow(fallbackTime, options.from, options.to)) continue;\n visit({\n entry,\n time: fallbackTime,\n cost: totalCost,\n source: resolvedCostSource(session),\n modelCosts: factsAvailable ? fallbackModelCosts(summary, totalCost) : [],\n });\n }\n }\n}\n\nexport function visitAttributedUsage(\n tree: SessionTree,\n options: UsageAttributionOptions,\n visit: (attributed: AttributedUsage) => void,\n): void {\n const factIndex = indexFacts(options.facts);\n const factsAvailable = options.facts != null;\n\n for (const entry of tree.entries) {\n if (options.matchesEntry && !options.matchesEntry(entry.session)) continue;\n const fallbackTime = entry.session.time_updated ?? entry.session.time_created;\n const pending = [entry];\n\n while (pending.length > 0) {\n const node = pending.pop()!;\n for (const child of node.children) pending.push(child);\n\n const session = node.session;\n const key = costFactKey(getSessionAgentKey(session), session.id);\n const summary = factIndex.summariesBySession.get(key);\n const detailedMessages = factsAvailable && hasDetailedMessages(session, summary);\n const outputIncludesReasoning = factsAvailable\n ? detailedOutputIncludesReasoning(session, summary)\n : null;\n const detailedTokens = outputIncludesReasoning != null;\n\n if (detailedMessages || detailedTokens) {\n for (const message of factIndex.messagesBySession.get(key) ?? []) {\n if (!isInWindow(message.time, options.from, options.to)) continue;\n const outputTokens = detailedTokens\n ? message.outputTokens + (outputIncludesReasoning ? message.reasoningTokens : 0)\n : 0;\n visit({\n entry,\n time: message.time,\n messages: detailedMessages ? 1 : 0,\n totalTokens: detailedTokens ? message.inputTokens + outputTokens : 0,\n inputTokens: detailedTokens ? message.inputTokens : 0,\n outputTokens,\n cacheReadTokens: detailedTokens ? message.cacheReadTokens : 0,\n cacheCreateTokens: detailedTokens ? message.cacheCreateTokens : 0,\n });\n }\n }\n\n if (!isInWindow(fallbackTime, options.from, options.to)) continue;\n if (!detailedMessages) {\n visit({\n entry,\n time: fallbackTime,\n messages: nonNegative(session.stats.message_count),\n totalTokens: 0,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreateTokens: 0,\n });\n }\n if (!detailedTokens) {\n const inputTokens = nonNegative(session.stats.total_input_tokens);\n const outputTokens = nonNegative(session.stats.total_output_tokens);\n visit({\n entry,\n time: fallbackTime,\n messages: 0,\n totalTokens: nonNegative(session.stats.total_tokens ?? inputTokens + outputTokens),\n inputTokens,\n outputTokens,\n cacheReadTokens: nonNegative(session.stats.total_cache_read_tokens),\n cacheCreateTokens: nonNegative(session.stats.total_cache_create_tokens),\n });\n }\n }\n }\n}\n","/**\n * Dashboard analytics — pure aggregation over SessionHead[] with no HTTP or DB\n * coupling. The handler parses request params and supplies file-activity; this\n * module owns the domain math: per-agent metrics, daily buckets, model\n * distribution, project ranking and the recent-sessions window.\n *\n * Metrics are *inclusive*: the unit of work is a top-level node (root or\n * orphan) and every descendant's stats roll into it. See contract/session-tree.\n */\nimport type { AgentInfo } from \"../types/index.js\";\nimport type { CostSource, ProjectIdentityKind, SessionHead } from \"../types/session.js\";\nimport type {\n DashboardAgentStat,\n DashboardAggregate,\n DashboardDailyBucket,\n DashboardData,\n DashboardPreviousTotals,\n DashboardProjectRollup,\n DashboardProjectStat,\n DashboardRecentSession,\n DashboardTotals,\n ModelCostEntry,\n ModelDistributionEntry,\n SessionTree,\n SessionTreeNode,\n} from \"../contract/index.js\";\nimport {\n addCalendarDays,\n buildSessionTree,\n countCalendarDays,\n filterSessionTreeEntriesByActivityWindow,\n getProjectIdentityKey,\n getSessionAgentKey,\n toCalendarDayKey,\n} from \"../contract/index.js\";\nimport type { DashboardCostFacts } from \"./cost-facts.js\";\nimport { visitAttributedCosts, visitAttributedUsage } from \"./cost-attribution.js\";\n\nexport type {\n DashboardAgentStat,\n DashboardAggregate,\n DashboardDailyBucket,\n DashboardData,\n DashboardPreviousTotals,\n DashboardProjectRollup,\n DashboardProjectStat,\n DashboardRecentSession,\n DashboardTotals,\n ModelDistributionEntry,\n};\n\nexport const DASHBOARD_RECENT_LIMIT = 10;\nexport const DASHBOARD_PROJECT_LIMIT = 12;\nexport const PROJECT_SPARKLINE_DAYS = 14;\nconst MODEL_COST_LIMIT = 20;\n\nexport interface DashboardScope {\n agent?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n}\n\ninterface DashboardAgentAggregate {\n name: string;\n sessions: number;\n messages: number;\n tokens: number;\n cost: number;\n}\n\ninterface DashboardProjectAggregate {\n identityKind: ProjectIdentityKind;\n identityKey: string;\n displayName: string;\n sessions: number;\n messages: number;\n tokens: number;\n cost: number;\n hasEstimatedCost: boolean;\n agentSessions: Map<string, number>;\n sparkline: number[];\n}\n\ninterface DashboardRecentCandidate {\n session: SessionHead;\n activity: number;\n}\n\ninterface DashboardAccumulator {\n sessions: number;\n messages: number;\n tokens: number;\n cost: number;\n costRecorded: number;\n costEstimated: number;\n cacheReadTokens: number;\n hasEstimatedCost: boolean;\n agents: Map<string, DashboardAgentAggregate>;\n agentKeys: Set<string>;\n daily: Map<string, DashboardDailyBucket>;\n models: Map<string, { tokens: number; sessions: number }>;\n modelCosts: Map<string, ModelCostEntry>;\n projects: Map<string, DashboardProjectAggregate>;\n projectKeys: Set<string>;\n /** Calendar day key → sparkline slot; anchored at the window's `to`. */\n sparklineSlots: Map<string, number>;\n /** Activity-desc, capped at DASHBOARD_RECENT_LIMIT; index 0 is the latest entry. */\n recent: DashboardRecentCandidate[];\n}\n\nexport interface DashboardOptions {\n byAgentNames: string[];\n scope: DashboardScope;\n from?: number;\n to: number;\n agentInfoMap?: Map<string, AgentInfo>;\n /** Immediately preceding window of equal length; drives `totals.previous`. */\n compare?: { from: number; to: number };\n /** Message-level cost and usage facts; null/undefined keeps session-activity fallback behavior. */\n costFacts?: DashboardCostFacts | null;\n}\n\n// --- SessionHead domain helpers (shared with other handlers via re-export) ---\n\nexport function getTotalTokens(stats: SessionHead[\"stats\"]): number {\n return stats.total_tokens ?? stats.total_input_tokens + stats.total_output_tokens;\n}\n\nexport function getSessionAgentName(session: SessionHead): string {\n return getSessionAgentKey(session);\n}\n\nexport function getSessionActivityTime(session: SessionHead): number {\n return session.time_updated ?? session.time_created;\n}\n\nfunction matchesScope(session: SessionHead, scope: DashboardScope): boolean {\n if (scope.agent && getSessionAgentName(session) !== scope.agent) return false;\n if (scope.projectKind == null && scope.projectKey == null) return true;\n const identity = session.project_identity;\n // A half-specified scope matches nothing: identity fields are never undefined.\n return (\n identity != null && identity.kind === scope.projectKind && identity.key === scope.projectKey\n );\n}\n\n/** Top-level nodes (roots ∪ orphans) inside the window that match the scope. */\nfunction scopedEntries(\n tree: SessionTree,\n scope: DashboardScope,\n from: number | undefined,\n to: number,\n): SessionTreeNode[] {\n return filterSessionTreeEntriesByActivityWindow(tree, from, to).filter((node) =>\n matchesScope(node.session, scope),\n );\n}\n\nfunction emptyDailyBucket(date: string): DashboardDailyBucket {\n return {\n date,\n sessions: 0,\n messages: 0,\n cost: 0,\n input: 0,\n output: 0,\n cache_read: 0,\n cache_create: 0,\n };\n}\n\nfunction createAccumulator(\n byAgentNames: string[],\n scope: DashboardScope,\n to: number,\n): DashboardAccumulator {\n const agents = new Map<string, DashboardAgentAggregate>();\n for (const name of byAgentNames) {\n const key = name.toLowerCase();\n if (scope.agent && key !== scope.agent) continue;\n agents.set(key, { name, sessions: 0, messages: 0, tokens: 0, cost: 0 });\n }\n\n const sparklineSlots = new Map<string, number>();\n for (let slot = 0; slot < PROJECT_SPARKLINE_DAYS; slot += 1) {\n const day = addCalendarDays(to, slot - (PROJECT_SPARKLINE_DAYS - 1));\n sparklineSlots.set(toCalendarDayKey(day), slot);\n }\n\n return {\n sessions: 0,\n messages: 0,\n tokens: 0,\n cost: 0,\n costRecorded: 0,\n costEstimated: 0,\n cacheReadTokens: 0,\n hasEstimatedCost: false,\n agents,\n agentKeys: new Set(),\n daily: new Map(),\n models: new Map(),\n modelCosts: new Map(),\n projects: new Map(),\n projectKeys: new Set(),\n sparklineSlots,\n recent: [],\n };\n}\n\nfunction foldModelUsage(node: SessionTreeNode, into: Map<string, number>): void {\n if (node.session.model_usage) {\n for (const [model, tokens] of Object.entries(node.session.model_usage)) {\n into.set(model, (into.get(model) ?? 0) + tokens);\n }\n }\n for (const child of node.children) foldModelUsage(child, into);\n}\n\nfunction getOrCreateProject(\n session: SessionHead,\n acc: DashboardAccumulator,\n): DashboardProjectAggregate | undefined {\n const identity = session.project_identity;\n if (!identity) return undefined;\n\n const key = getProjectIdentityKey(identity);\n let project = acc.projects.get(key);\n if (!project) {\n project = {\n identityKind: identity.kind,\n identityKey: identity.key,\n displayName: identity.displayName,\n sessions: 0,\n messages: 0,\n tokens: 0,\n cost: 0,\n hasEstimatedCost: false,\n agentSessions: new Map(),\n sparkline: Array.from({ length: PROJECT_SPARKLINE_DAYS }, () => 0),\n };\n acc.projects.set(key, project);\n }\n return project;\n}\n\nfunction trackProjectActivity(\n node: SessionTreeNode,\n acc: DashboardAccumulator,\n agentKey: string,\n): void {\n const identity = node.session.project_identity;\n const project = getOrCreateProject(node.session, acc);\n if (!identity || !project) return;\n\n project.sessions += 1;\n project.agentSessions.set(agentKey, (project.agentSessions.get(agentKey) ?? 0) + 1);\n acc.projectKeys.add(getProjectIdentityKey(identity));\n}\n\n/** Fold activity metrics for one top-level node and its inclusive subtree. */\nfunction accumulateActivity(node: SessionTreeNode, acc: DashboardAccumulator): void {\n const session = node.session;\n const activity = getSessionActivityTime(session);\n const agentKey = getSessionAgentName(session);\n\n acc.sessions += 1;\n acc.agentKeys.add(agentKey);\n\n const metric = acc.agents.get(agentKey);\n if (metric) {\n metric.sessions += 1;\n }\n\n const dayKey = toCalendarDayKey(activity);\n let bucket = acc.daily.get(dayKey);\n if (!bucket) {\n bucket = emptyDailyBucket(dayKey);\n acc.daily.set(dayKey, bucket);\n }\n bucket.sessions += 1;\n\n const usage = new Map<string, number>();\n foldModelUsage(node, usage);\n for (const [model, tokens] of usage) {\n const entry = acc.models.get(model);\n if (entry) {\n entry.tokens += tokens;\n entry.sessions += 1;\n } else {\n acc.models.set(model, { tokens, sessions: 1 });\n }\n }\n\n trackProjectActivity(node, acc, agentKey);\n\n let recentIndex = acc.recent.length;\n for (let i = 0; i < acc.recent.length; i += 1) {\n if (activity > acc.recent[i]!.activity) {\n recentIndex = i;\n break;\n }\n }\n if (recentIndex < DASHBOARD_RECENT_LIMIT) {\n acc.recent.splice(recentIndex, 0, { session, activity });\n if (acc.recent.length > DASHBOARD_RECENT_LIMIT) acc.recent.pop();\n }\n}\n\nfunction addUsage(\n acc: DashboardAccumulator,\n entry: SessionTreeNode,\n time: number,\n usage: {\n messages: number;\n totalTokens: number;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreateTokens: number;\n },\n): void {\n const { messages, totalTokens, inputTokens, outputTokens, cacheReadTokens, cacheCreateTokens } =\n usage;\n if (\n messages <= 0 &&\n totalTokens <= 0 &&\n inputTokens <= 0 &&\n outputTokens <= 0 &&\n cacheReadTokens <= 0 &&\n cacheCreateTokens <= 0\n ) {\n return;\n }\n\n acc.messages += messages;\n acc.tokens += totalTokens;\n acc.cacheReadTokens += cacheReadTokens;\n\n const agentKey = getSessionAgentName(entry.session);\n let metric = acc.agents.get(agentKey);\n if (!metric) {\n metric = { name: agentKey, sessions: 0, messages: 0, tokens: 0, cost: 0 };\n acc.agents.set(agentKey, metric);\n }\n metric.messages += messages;\n metric.tokens += totalTokens;\n\n const dayKey = toCalendarDayKey(time);\n let bucket = acc.daily.get(dayKey);\n if (!bucket) {\n bucket = emptyDailyBucket(dayKey);\n acc.daily.set(dayKey, bucket);\n }\n bucket.messages += messages;\n bucket.input += Math.max(0, inputTokens - cacheReadTokens - cacheCreateTokens);\n bucket.output += outputTokens;\n bucket.cache_read += cacheReadTokens;\n bucket.cache_create += cacheCreateTokens;\n\n const project = getOrCreateProject(entry.session, acc);\n if (!project) return;\n project.messages += messages;\n project.tokens += totalTokens;\n}\n\nfunction accumulateUsage(\n tree: SessionTree,\n scope: DashboardScope,\n acc: DashboardAccumulator,\n from: number | undefined,\n to: number,\n costFacts: DashboardCostFacts | null | undefined,\n): void {\n visitAttributedUsage(\n tree,\n { from, to, facts: costFacts, matchesEntry: (session) => matchesScope(session, scope) },\n ({ entry, time, ...usage }) => addUsage(acc, entry, time, usage),\n );\n}\n\nfunction addModelCost(\n acc: DashboardAccumulator,\n model: string | undefined,\n cost: number,\n recordedCost: number,\n): void {\n if (!model || cost <= 0) return;\n const recorded = Math.max(0, Math.min(cost, recordedCost));\n const current = acc.modelCosts.get(model);\n if (current) {\n current.cost += cost;\n current.costRecorded += recorded;\n current.costEstimated += cost - recorded;\n return;\n }\n acc.modelCosts.set(model, {\n model,\n cost,\n costRecorded: recorded,\n costEstimated: cost - recorded,\n });\n}\n\nfunction addCost(\n acc: DashboardAccumulator,\n entry: SessionTreeNode,\n time: number,\n cost: number,\n source: CostSource,\n): void {\n if (cost <= 0) return;\n acc.cost += cost;\n if (source === \"recorded\") acc.costRecorded += cost;\n else {\n acc.costEstimated += cost;\n acc.hasEstimatedCost = true;\n }\n\n const agentKey = getSessionAgentName(entry.session);\n let metric = acc.agents.get(agentKey);\n if (!metric) {\n metric = { name: agentKey, sessions: 0, messages: 0, tokens: 0, cost: 0 };\n acc.agents.set(agentKey, metric);\n }\n metric.cost += cost;\n\n const dayKey = toCalendarDayKey(time);\n let bucket = acc.daily.get(dayKey);\n if (!bucket) {\n bucket = emptyDailyBucket(dayKey);\n acc.daily.set(dayKey, bucket);\n }\n bucket.cost += cost;\n\n const project = getOrCreateProject(entry.session, acc);\n if (!project) return;\n project.cost += cost;\n if (source === \"estimated\") project.hasEstimatedCost = true;\n const slot = acc.sparklineSlots.get(dayKey);\n if (slot != null) project.sparkline[slot]! += cost;\n}\n\nfunction accumulateCosts(\n tree: SessionTree,\n scope: DashboardScope,\n acc: DashboardAccumulator,\n from: number | undefined,\n to: number,\n costFacts: DashboardCostFacts | null | undefined,\n): void {\n visitAttributedCosts(\n tree,\n { from, to, facts: costFacts, matchesEntry: (session) => matchesScope(session, scope) },\n ({ entry, time, cost, source, modelCosts }) => {\n addCost(acc, entry, time, cost, source);\n for (const model of modelCosts) {\n addModelCost(acc, model.model, model.cost, model.costRecorded);\n }\n },\n );\n}\n\nfunction toPreviousTotals(acc: DashboardAccumulator): DashboardPreviousTotals {\n return { sessions: acc.sessions, messages: acc.messages, tokens: acc.tokens, cost: acc.cost };\n}\n\nfunction toProjectStat(project: DashboardProjectAggregate): DashboardProjectStat {\n return {\n identityKind: project.identityKind,\n identityKey: project.identityKey,\n displayName: project.displayName,\n sessions: project.sessions,\n messages: project.messages,\n tokens: project.tokens,\n cost: project.cost,\n cost_source:\n project.cost > 0 ? (project.hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n agents: [...project.agentSessions.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([agentKey]) => agentKey),\n sparkline: project.sparkline,\n };\n}\n\n/**\n * Aggregate sessions into dashboard metrics, daily buckets, model distribution,\n * project ranking and the recent-sessions window. Pure — no HTTP, no DB.\n */\nexport function buildDashboard(\n sessions: SessionHead[],\n options: DashboardOptions,\n): DashboardAggregate {\n const { byAgentNames, scope, from, to, agentInfoMap, compare, costFacts } = options;\n const tree = buildSessionTree(sessions);\n const costFactsAvailable = costFacts != null;\n\n const acc = createAccumulator(byAgentNames, scope, to);\n if (from != null) {\n const bucketDays = countCalendarDays(from, to);\n for (let i = 0; i < bucketDays; i += 1) {\n const key = toCalendarDayKey(addCalendarDays(from, i));\n acc.daily.set(key, emptyDailyBucket(key));\n }\n }\n for (const node of scopedEntries(tree, scope, from, to)) accumulateActivity(node, acc);\n accumulateUsage(tree, scope, acc, from, to, costFacts);\n accumulateCosts(tree, scope, acc, from, to, costFacts);\n\n let previous: DashboardPreviousTotals | undefined;\n if (compare) {\n const compareAcc = createAccumulator(byAgentNames, scope, compare.to);\n for (const node of scopedEntries(tree, scope, compare.from, compare.to)) {\n accumulateActivity(node, compareAcc);\n }\n accumulateUsage(tree, scope, compareAcc, compare.from, compare.to, costFacts);\n accumulateCosts(tree, scope, compareAcc, compare.from, compare.to, costFacts);\n previous = toPreviousTotals(compareAcc);\n }\n\n const perAgent: DashboardAgentStat[] = [...acc.agents.values()]\n .map((metrics) => {\n const info = agentInfoMap?.get(metrics.name);\n return {\n name: metrics.name,\n displayName: info?.displayName ?? metrics.name,\n icon: info?.icon ?? \"\",\n iconColored: info?.iconColored,\n sessions: metrics.sessions,\n messages: metrics.messages,\n tokens: metrics.tokens,\n cost: metrics.cost,\n };\n })\n .filter((item) => item.sessions > 0 || item.messages > 0 || item.tokens > 0 || item.cost > 0)\n .sort((a, b) => b.sessions - a.sessions || b.cost - a.cost);\n\n const dailyActivity = [...acc.daily.values()].sort((a, b) => a.date.localeCompare(b.date));\n const modelDistribution: ModelDistributionEntry[] = [...acc.models.entries()]\n .map(([model, { tokens, sessions: count }]) => ({ model, tokens, sessions: count }))\n .sort((a, b) => b.tokens - a.tokens);\n const modelCost = costFactsAvailable\n ? [...acc.modelCosts.values()].sort((a, b) => b.cost - a.cost).slice(0, MODEL_COST_LIMIT)\n : null;\n\n const rankedProjects = [...acc.projects.values()].sort((a, b) => b.cost - a.cost);\n const perProject = rankedProjects.slice(0, DASHBOARD_PROJECT_LIMIT).map(toProjectStat);\n const projectRollup = rankedProjects\n .slice(DASHBOARD_PROJECT_LIMIT)\n .reduce<DashboardProjectRollup>(\n (rollup, project) => ({\n projects: rollup.projects + 1,\n sessions: rollup.sessions + project.sessions,\n tokens: rollup.tokens + project.tokens,\n cost: rollup.cost + project.cost,\n }),\n { projects: 0, sessions: 0, tokens: 0, cost: 0 },\n );\n\n const recentSessions: DashboardRecentSession[] = acc.recent.map(({ session }) => ({\n reference: { agentName: getSessionAgentName(session), sessionId: session.id },\n session,\n }));\n\n const latest = acc.recent[0];\n return {\n totals: {\n sessions: acc.sessions,\n messages: acc.messages,\n tokens: acc.tokens,\n cost: acc.cost,\n costRecorded: acc.costRecorded,\n costEstimated: acc.costEstimated,\n cacheReadTokens: acc.cacheReadTokens,\n cost_source: acc.cost > 0 ? (acc.hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n latestActivity: latest?.activity || undefined,\n latestActivityProject: latest?.session.project_identity?.displayName,\n latestActivityAgent: latest ? getSessionAgentName(latest.session) : undefined,\n previous,\n },\n scopeCounts: { projects: acc.projectKeys.size, agents: acc.agentKeys.size },\n perAgent,\n dailyActivity,\n modelDistribution,\n modelCost,\n perProject,\n projectRollup,\n recentSessions,\n };\n}\n","/**\n * Project analytics — pure aggregation over SessionHead[], the project-level\n * counterpart to dashboard.ts. No HTTP, no DB: the caller supplies the groups\n * and the sessions, this module owns the arithmetic.\n *\n * Metrics are inclusive of sub-sessions and `sessionCount` is recomputed from\n * the sessions actually handed in, so a windowed caller gets windowed counts\n * instead of the cache-wide count carried by ProjectGroup.\n */\nimport type { ProjectGroup, SessionHead } from \"../types/index.js\";\nimport type {\n ApiProjectAgentStat,\n ApiProjectGroup,\n SessionTree,\n SessionTreeNode,\n} from \"../contract/index.js\";\nimport { getProjectIdentityKey } from \"../contract/project-identity.js\";\nimport {\n buildSessionTree,\n filterSessionTreeEntriesByActivityWindow,\n} from \"../contract/session-tree.js\";\nimport { getSessionAgentName } from \"./dashboard.js\";\nimport type { DashboardCostFacts } from \"./cost-facts.js\";\nimport { visitAttributedCosts, visitAttributedUsage } from \"./cost-attribution.js\";\n\ninterface ProjectMetrics {\n sessions: number;\n messages: number;\n tokens: number;\n cost: number;\n hasEstimatedCost: boolean;\n agentStats: Map<string, ApiProjectAgentStat>;\n}\n\nfunction emptyMetrics(): ProjectMetrics {\n return {\n sessions: 0,\n messages: 0,\n tokens: 0,\n cost: 0,\n hasEstimatedCost: false,\n agentStats: new Map(),\n };\n}\n\n/**\n * Fold per-session totals into the project groups they belong to. Sessions with\n * no resolved project identity contribute to nothing.\n */\nexport function attachProjectMetrics(\n projects: ProjectGroup[],\n sessions: SessionHead[],\n): ApiProjectGroup[] {\n const tree = buildSessionTree(sessions);\n return attachProjectMetricsToEntries(projects, tree, tree.entries);\n}\n\nexport function attachProjectMetricsFromTree(\n projects: ProjectGroup[],\n tree: SessionTree,\n from?: number,\n to?: number,\n costFacts?: DashboardCostFacts | null,\n): ApiProjectGroup[] {\n return attachProjectMetricsToEntries(\n projects,\n tree,\n filterSessionTreeEntriesByActivityWindow(tree, from, to),\n from,\n to,\n costFacts,\n );\n}\n\nfunction attachProjectMetricsToEntries(\n projects: ProjectGroup[],\n tree: SessionTree,\n entries: SessionTreeNode[],\n from?: number,\n to?: number,\n costFacts?: DashboardCostFacts | null,\n): ApiProjectGroup[] {\n const metrics = new Map<string, ProjectMetrics>();\n\n for (const node of entries) {\n const identity = node.session.project_identity;\n if (!identity) continue;\n\n const key = getProjectIdentityKey(identity);\n let current = metrics.get(key);\n if (!current) {\n current = emptyMetrics();\n metrics.set(key, current);\n }\n\n current.sessions += 1;\n\n const agentName = getSessionAgentName(node.session);\n const agent = current.agentStats.get(agentName);\n if (agent) {\n agent.sessions += 1;\n } else {\n current.agentStats.set(agentName, {\n name: agentName,\n sessions: 1,\n messages: 0,\n tokens: 0,\n cost: 0,\n });\n }\n }\n\n visitAttributedUsage(\n tree,\n { from, to: to ?? Number.POSITIVE_INFINITY, facts: costFacts },\n ({ entry, messages, totalTokens }) => {\n const identity = entry.session.project_identity;\n if (!identity) return;\n const key = getProjectIdentityKey(identity);\n let current = metrics.get(key);\n if (!current) {\n current = emptyMetrics();\n metrics.set(key, current);\n }\n current.messages += messages;\n current.tokens += totalTokens;\n\n const agentName = getSessionAgentName(entry.session);\n const agent = current.agentStats.get(agentName);\n if (agent) {\n agent.messages += messages;\n agent.tokens += totalTokens;\n } else {\n current.agentStats.set(agentName, {\n name: agentName,\n sessions: 0,\n messages,\n tokens: totalTokens,\n cost: 0,\n });\n }\n },\n );\n\n visitAttributedCosts(\n tree,\n { from, to: to ?? Number.POSITIVE_INFINITY, facts: costFacts },\n ({ entry, cost, source }) => {\n const identity = entry.session.project_identity;\n if (!identity) return;\n const key = getProjectIdentityKey(identity);\n let current = metrics.get(key);\n if (!current) {\n current = emptyMetrics();\n metrics.set(key, current);\n }\n current.cost += cost;\n if (source === \"estimated\") current.hasEstimatedCost = true;\n\n const agentName = getSessionAgentName(entry.session);\n const agent = current.agentStats.get(agentName);\n if (agent) agent.cost += cost;\n else {\n current.agentStats.set(agentName, {\n name: agentName,\n sessions: 0,\n messages: 0,\n tokens: 0,\n cost,\n });\n }\n },\n );\n\n return projects.map((project) => {\n const metric = metrics.get(\n getProjectIdentityKey({ kind: project.identityKind, key: project.identityKey }),\n );\n return {\n ...project,\n sessionCount: metric?.sessions ?? 0,\n messages: metric?.messages ?? 0,\n tokens: metric?.tokens ?? 0,\n cost: metric?.cost ?? 0,\n cost_source:\n metric && metric.cost > 0\n ? metric.hasEstimatedCost\n ? \"estimated\"\n : \"recorded\"\n : undefined,\n agentStats: [...(metric?.agentStats.values() ?? [])].sort((a, b) => b.sessions - a.sessions),\n };\n });\n}\n","/**\n * Deep session search: single owner for search-query interpretation\n * (qualifier parsing/merging), source selection between the live LiveSnapshot\n * snapshot (\"recent\" path) and the SQLite search index (FTS / file-activity\n * paths), and cross-source result merging.\n */\nimport type { SessionHead } from \"../types/index.js\";\nimport {\n buildSessionTree,\n getSessionAgentKey,\n getSessionRouteKey,\n type SearchResult,\n type SessionTree,\n} from \"../contract/index.js\";\nimport {\n filterIndexedSessionReferences,\n mergeSearchQueryOptions,\n searchSessions,\n sessionMatchesSearchCost,\n type ParsedSearchQuery,\n type SearchOptions,\n} from \"../discovery/cache/search.js\";\nimport { searchFileActivitySessions } from \"../discovery/cache/file-activity.js\";\nimport { matchesProjectScope, type ProjectScopeMatcher } from \"../projects/scope.js\";\nimport { matchesProjectIdentity } from \"../projects/identity.js\";\nimport { getSessionActivityTime } from \"../analytics/dashboard.js\";\n\nexport interface SessionSearchSnapshot {\n /** Globally sorted by activity descending; ties preserve the canonical live-index order. */\n sessions: SessionHead[];\n /** Each shard follows the same activity ordering as `sessions`. */\n byAgent: Record<string, SessionHead[]>;\n}\n\nexport interface SessionSearchContext {\n sessionTree?: SessionTree;\n}\n\nexport interface SessionSearchFilterContext extends SessionSearchContext {\n sessionSnapshot?: SessionHead[];\n}\n\nexport function executeSessionSearch(\n query: string,\n options: SearchOptions,\n snapshot: SessionSearchSnapshot,\n context: SessionSearchContext = {},\n): SearchResult[] {\n const merged = mergeSearchQueryOptions(query, options);\n\n if (!needsIndexedSearch(merged.text, merged.options)) {\n return searchRecentSessions(snapshot, merged.options, context);\n }\n\n return searchIndexedSessions(query, merged.text, merged.parsed, merged.options);\n}\n\n// Qualifiers alone (tag:/cost:/agent:/project:) do not force the indexed\n// path -- only text, file, fileKind, or tool do. A qualifier-only query is\n// treated identically to an empty query for source selection.\nfunction needsIndexedSearch(textQuery: string, options: SearchOptions): boolean {\n return Boolean(textQuery || options.file || options.fileKind || options.tools?.length);\n}\n\nfunction matchesRecentSearchFilters(\n session: SessionHead,\n options: SearchOptions,\n projectScope: ProjectScopeMatcher | null,\n inclusiveCost: number,\n): boolean {\n if (options.projectKind || options.projectKey) {\n if (\n !options.projectKind ||\n !options.projectKey ||\n !matchesProjectIdentity(session.project_identity, {\n kind: options.projectKind,\n key: options.projectKey,\n })\n ) {\n return false;\n }\n }\n if (projectScope && !matchesProjectScope(session, projectScope)) return false;\n if (options.project) {\n const projectNeedle = options.project.toLowerCase();\n const projectText = [\n session.project_identity?.key,\n session.project_identity?.displayName,\n session.directory,\n ]\n .filter(Boolean)\n .join(\"\\n\")\n .toLowerCase();\n if (!projectText.includes(projectNeedle)) return false;\n }\n if (options.tags?.length && !options.tags.every((tag) => session.smart_tags?.includes(tag))) {\n return false;\n }\n if (!sessionMatchesSearchCost(session, options, inclusiveCost)) return false;\n return true;\n}\n\n// Evaluates filters answerable from SessionHead. File and tool predicates\n// require the indexed batch seam in filterSessionSearchCandidates.\nexport function matchesSessionSearchFilters(\n agentName: string,\n session: SessionHead,\n options: SearchOptions,\n projectScope: ProjectScopeMatcher | null = null,\n inclusiveCost = session.stats.total_cost,\n): boolean {\n if (options.agent && agentName !== options.agent) return false;\n const activity = getSessionActivityTime(session);\n if (options.from != null && activity < options.from) return false;\n if (options.to != null && activity > options.to) return false;\n return matchesRecentSearchFilters(session, options, projectScope, inclusiveCost);\n}\n\nfunction sessionReferenceKey(agentName: string, sessionId: string): string {\n return `${agentName}\\u0000${sessionId}`;\n}\n\nexport function filterSessionSearchCandidates(\n candidates: SearchResult[],\n options: SearchOptions,\n context: SessionSearchFilterContext = {},\n): SearchResult[] {\n const projectScope = options.projectScope ?? null;\n const sessionSnapshot =\n context.sessionSnapshot ?? candidates.map((candidate) => candidate.session);\n const inclusiveCosts = buildInclusiveCostLookup(sessionSnapshot, options, context.sessionTree);\n const headMatches = candidates.filter((candidate) =>\n matchesSessionSearchFilters(\n candidate.reference.agentName,\n candidate.session,\n options,\n projectScope,\n inclusiveCostFor(candidate.reference.agentName, candidate.session, inclusiveCosts),\n ),\n );\n if (!options.file && !options.fileKind && !options.tools?.length) return headMatches;\n\n const indexedMatches = filterIndexedSessionReferences(\n headMatches.map((candidate) => ({\n agentName: candidate.reference.agentName,\n sessionId: candidate.reference.sessionId,\n })),\n {\n file: options.file,\n fileKind: options.fileKind,\n tools: options.tools,\n },\n );\n return headMatches.filter((candidate) =>\n indexedMatches.has(\n sessionReferenceKey(candidate.reference.agentName, candidate.reference.sessionId),\n ),\n );\n}\n\nfunction searchRecentSessions(\n snapshot: SessionSearchSnapshot,\n options: SearchOptions,\n context: SessionSearchContext,\n): SearchResult[] {\n const limit = Math.max(0, Math.trunc(options.limit ?? 50));\n if (limit === 0) return [];\n\n const projectScope = options.projectScope ?? null;\n const inclusiveCosts = buildInclusiveCostLookup(snapshot.sessions, options, context.sessionTree);\n const sessions = options.agent ? (snapshot.byAgent[options.agent] ?? []) : snapshot.sessions;\n const results: SearchResult[] = [];\n\n for (const session of sessions) {\n const agentName = options.agent ?? getSessionAgentKey(session);\n if (\n !matchesSessionSearchFilters(\n agentName,\n session,\n options,\n projectScope,\n inclusiveCostFor(agentName, session, inclusiveCosts),\n )\n ) {\n continue;\n }\n results.push({\n reference: { agentName, sessionId: session.id },\n session,\n snippet: `Recent session · ${session.directory}`,\n snippetHighlights: [],\n matchType: \"recent\",\n });\n if (results.length >= limit) break;\n }\n\n return results;\n}\n\nfunction buildInclusiveCostLookup(\n sessions: SessionHead[],\n options: SearchOptions,\n sessionTree?: SessionTree,\n): ReturnType<typeof buildSessionTree>[\"byRouteKey\"] | null {\n if (options.costMin == null && options.costMax == null) return null;\n return (sessionTree ?? buildSessionTree(sessions)).byRouteKey;\n}\n\nfunction inclusiveCostFor(\n agentName: string,\n session: SessionHead,\n lookup: ReturnType<typeof buildSessionTree>[\"byRouteKey\"] | null,\n): number {\n return (\n lookup?.get(getSessionRouteKey(agentName, session.id))?.inclusiveStats.cost ??\n session.stats.total_cost\n );\n}\n\n// `options.file` already carries the qualifier's `file:`/`path:` value once\n// merged (options.file ?? filters.file), so the middle branch only matters\n// when options.file was merged from something other than this parse. When\n// the query has no qualifiers at all, a bare text search is also attempted\n// as a file-path search (usually a no-op match, but it is why plain text\n// queries still touch the file-activity path).\nfunction deriveFileQuery(query: string, parsed: ParsedSearchQuery, options: SearchOptions): string {\n return (\n options.file ??\n (!parsed.text ? parsed.filters.file : undefined) ??\n (!parsed.hasQualifiers && query ? parsed.text || query : \"\")\n );\n}\n\nfunction mergeSearchResultSources(results: SearchResult[], limit: number): SearchResult[] {\n const seen = new Set<string>();\n const merged: SearchResult[] = [];\n\n for (const result of results) {\n const key = sessionReferenceKey(result.reference.agentName, result.reference.sessionId);\n if (seen.has(key)) continue;\n seen.add(key);\n merged.push(result);\n if (merged.length >= limit) break;\n }\n\n return merged;\n}\n\nfunction canSkipSessionsSearch(fileQuery: string, textQuery: string): boolean {\n return Boolean(fileQuery && !textQuery);\n}\n\nfunction searchIndexedSessions(\n query: string,\n textQuery: string,\n parsed: ParsedSearchQuery,\n options: SearchOptions,\n): SearchResult[] {\n const fileQuery = deriveFileQuery(query, parsed, options);\n const fileResults = fileQuery ? searchFileActivitySessions(fileQuery, options) : [];\n const sessionResults = canSkipSessionsSearch(fileQuery, textQuery)\n ? []\n : searchSessions(query, options);\n const textMatchReferences =\n textQuery && options.file\n ? new Set(\n sessionResults.map((result) =>\n sessionReferenceKey(result.reference.agentName, result.reference.sessionId),\n ),\n )\n : null;\n const matchingFileResults = textMatchReferences\n ? fileResults.filter((result) =>\n textMatchReferences.has(\n sessionReferenceKey(result.reference.agentName, result.reference.sessionId),\n ),\n )\n : fileResults;\n\n return mergeSearchResultSources([...matchingFileResults, ...sessionResults], options.limit ?? 50);\n}\n"],"mappings":"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","names":["existsSync","join","statSync","readdirSync","readFileSync","basename","dirname","homedir","createHash","resolve","platform","closeSync","openSync","readSync","path","activityTime","pending","isInternalEventType","message","toolPart","text","require","mapToolTitle","parseTimestamp","HEAD_INDEX_VERSION","parseTimestampMs","planText","planPart","normalizeToolOutputParts","composerId","PARSER_VERSION","result","costSource","corrupt","optionalString","parseJsonRecord","isRecord","asRecord","buildToolPart","encoding","sessionKey","pending","path","pending","existsSync","readFileSync","createHash","rmSync","join","homedir","platform","path","identity","isRecord","toRecord","getCacheDir","getCachePath","activityTime","normalizeToolName","db","amount","rows","unique","resolve","cacheState","stream","sessionKey","nonNegative","diagnostics","ensureSchema","pending","sessionReferenceKey"]}
|