codesesh 0.10.0 → 0.12.0
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-ZQMIB7QO.js → chunk-GCOAE7KI.js} +131 -34
- package/dist/chunk-GCOAE7KI.js.map +1 -0
- package/dist/{dist-GZSUB4NY.js → dist-TZTL6VP4.js} +14 -2
- package/dist/index.js +226 -47
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +35 -9
- package/dist/scan-refresh-worker.js.map +1 -1
- package/dist/search-index-worker.js +6 -1
- package/dist/search-index-worker.js.map +1 -1
- package/dist/smart-tag-worker.js +1 -1
- package/dist/web/assets/index-D05hsCzb.css +2 -0
- package/dist/web/assets/index-DOy8q3la.js +113 -0
- package/dist/web/assets/markdown-CGVJZBE7.js +14 -0
- package/dist/web/assets/{react-CGUTVnhO.js → react-DkEeEGji.js} +1 -1
- package/dist/web/assets/{syntax-Cjw-OADI.js → syntax-CFQ-7fm6.js} +2 -2
- package/dist/web/assets/vendor-B2nLfkMs.js +80 -0
- package/dist/web/icon/agent/zcode.svg +1 -0
- package/dist/web/index.html +6 -6
- package/package.json +4 -3
- package/dist/chunk-ZQMIB7QO.js.map +0 -1
- package/dist/web/assets/index-BHmQBGNx.css +0 -2
- package/dist/web/assets/index-CxJTOv8L.js +0 -111
- package/dist/web/assets/markdown-Bm__FT1K.js +0 -14
- package/dist/web/assets/vendor-CQhWyNUf.js +0 -40
- /package/dist/{dist-GZSUB4NY.js.map → dist-TZTL6VP4.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../core/src/agents/registry.ts","../../core/src/agents/claudecode.ts","../../core/src/agents/base.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/perf.ts","../../core/src/pricing/data/aliases.json","../../core/src/pricing/fetcher.ts","../../core/src/pricing/data/snapshot.json","../../core/src/pricing/resolver.ts","../../core/src/pricing/cost.ts","../../core/src/utils/cost.ts","../../core/src/agents/opencode.ts","../../core/src/utils/sqlite.ts","../../core/src/agents/kimi.ts","../../core/src/agents/codex.ts","../../core/src/agents/cursor.ts","../../core/src/agents/pi.ts","../../core/src/agents/register.ts","../../core/src/discovery/scanner.ts","../../core/src/projects/display-name.ts","../../core/src/projects/fs.ts","../../core/src/projects/groups.ts","../../core/src/projects/identity.ts","../../core/src/projects/scope.ts","../../core/src/utils/smart-tags.ts","../../core/src/utils/file-activity.ts","../../core/src/discovery/cache/db.ts","../../core/src/discovery/cache/sessions.ts","../../core/src/discovery/cache/messages.ts","../../core/src/discovery/cache/schema.ts","../../core/src/discovery/cache/search.ts","../../core/src/discovery/cache/file-activity.ts","../../core/src/discovery/cache/project-groups.ts","../../core/src/discovery/orchestrate.ts","../../core/src/state/bookmarks.ts","../../core/src/analytics/dashboard.ts"],"sourcesContent":["import type { BaseAgent } from \"./base.js\";\nimport type { AgentInfo } from \"../types/index.js\";\n\nexport interface AgentRegistration {\n name: string;\n displayName: string;\n create: () => BaseAgent;\n icon: string;\n}\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 getAgentInfoMap(sessionsByAgent: Record<string, number>): AgentInfo[] {\n return registrations.map((r) => ({\n name: r.name,\n displayName: r.displayName,\n icon: r.icon,\n count: sessionsByAgent[r.name] ?? 0,\n }));\n}\n\nexport function getAgentByName(name: string): AgentRegistration | undefined {\n return registrations.find((r) => r.name === name);\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport {\n FileSystemSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { ParseSessionResult } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { parseJsonlLines } from \"../utils/jsonl.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { cleanInternalText, cleanParsedMessages } from \"../utils/session-normalization.js\";\nimport { perf } from \"../utils/perf.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport type { AgentScanOptions, SessionCacheMeta, SessionSourceRef } from \"./base.js\";\n\nconst HEAD_INDEX_VERSION = \"claudecode-head-v2\";\n\ninterface ClaudeUsage {\n key: string;\n input: number;\n output: number;\n cacheRead: number;\n cacheCreate: number;\n}\n\ninterface SessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n sourceMtimeMs: number;\n indexPath: string | null;\n indexMtimeMs: number | null;\n headIndexVersion: string;\n directory: string;\n model: string | null | undefined;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\nfunction parseTimestampMs(data: Record<string, unknown>): number {\n const raw = String(data[\"timestamp\"] ?? \"\").trim();\n if (!raw) return 0;\n try {\n return new Date(raw.includes(\"Z\") ? raw : raw + \"Z\").getTime();\n } catch {\n return 0;\n }\n}\n\nfunction numericUsage(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\nfunction extractClaudeUsage(\n data: Record<string, unknown>,\n msg: Record<string, unknown>,\n): ClaudeUsage | null {\n const usage = msg[\"usage\"];\n if (!usage || typeof usage !== \"object\") return null;\n\n const u = usage as Record<string, unknown>;\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: numericUsage(u[\"input_tokens\"]),\n output: numericUsage(u[\"output_tokens\"]),\n cacheRead: numericUsage(u[\"cache_read_input_tokens\"]),\n cacheCreate: numericUsage(u[\"cache_creation_input_tokens\"]),\n };\n}\n\nexport class ClaudeCodeAgent extends FileSystemSessionSource<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\n private findBasePath(): string | null {\n const roots = resolveProviderRoots();\n return firstExisting(join(roots.claudeRoot, \"projects\"), \"data/claudecode\");\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n try {\n for (const entry of readdirSync(this.basePath)) {\n const dir = join(this.basePath, entry);\n if (existsSync(dir) && readdirSync(dir).some((f) => f.endsWith(\".jsonl\"))) {\n return true;\n }\n }\n } catch {\n // ignore\n }\n return false;\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n if (!this.basePath) return [];\n\n const scanMarker = perf.start(\"claudecode:scan\");\n const heads: SessionHead[] = [];\n\n const listMarker = perf.start(\"listProjectDirs\");\n const projectDirs = this.listProjectDirs();\n perf.end(listMarker);\n\n const filesByProject = projectDirs.map((projectDir) => {\n const fileMarker = perf.start(`listJsonlFiles:${basename(projectDir)}`);\n const files = this.listJsonlFiles(projectDir).filter((file) => {\n try {\n return matchesScanWindow(statSync(file).mtimeMs, options);\n } catch {\n return false;\n }\n });\n perf.end(fileMarker);\n return { projectDir, files };\n });\n const totalFiles = filesByProject.reduce((total, item) => total + item.files.length, 0);\n options?.onProgress?.({ total: totalFiles, processed: 0, sessions: 0 });\n\n let processed = 0;\n for (const { projectDir, files } of filesByProject) {\n for (const file of files) {\n try {\n const parseMarker = perf.start(`parseSessionHead:${basename(file)}`);\n const head = getParsedSession(this.parseSessionHeadResult(file, projectDir));\n perf.end(parseMarker);\n\n if (head) {\n heads.push(head);\n this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, file, projectDir));\n }\n } catch {\n // skip malformed files\n } finally {\n processed += 1;\n options?.onProgress?.({ total: totalFiles, processed, sessions: heads.length });\n }\n }\n }\n\n perf.end(scanMarker);\n return heads;\n }\n\n listSessionSources(): SessionSourceRef[] {\n if (!this.basePath) return [];\n const refs: SessionSourceRef[] = [];\n for (const projectDir of this.listProjectDirs()) {\n for (const file of this.listJsonlFiles(projectDir)) {\n const sessionId = basename(file, \".jsonl\");\n refs.push({\n sessionId,\n sourcePath: file,\n fingerprint: this.sourceFingerprint(file, projectDir),\n });\n }\n }\n return refs;\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n const projectDir = dirname(sourcePath);\n const head = getParsedSession(this.parseSessionHeadResult(sourcePath, projectDir));\n if (head) {\n this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, sourcePath, projectDir));\n }\n return head;\n }\n\n getSessionData(sessionId: string): SessionData {\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 const content = readFileSync(meta.sourcePath, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n const ignoredToolCallIds = new Set<string>();\n const assistantUuidToToolCalls = new Map<string, string[]>();\n const countedUsageKeys = new Set<string>();\n const assistantState = {\n currentIndex: null as number | null,\n latestTextIndex: null as number | null,\n };\n\n let totalCost = 0;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheRead = 0;\n let totalCacheCreate = 0;\n\n for (const record of parseJsonlLines(content)) {\n try {\n this.convertRecord(\n record,\n messages,\n pendingToolCalls,\n ignoredToolCallIds,\n assistantUuidToToolCalls,\n countedUsageKeys,\n assistantState,\n );\n } catch {\n // skip malformed records\n }\n }\n\n const cleanedMessages = cleanParsedMessages(messages);\n\n for (const msg of cleanedMessages) {\n totalCost += msg.cost ?? 0;\n totalInputTokens += msg.tokens?.input ?? 0;\n totalOutputTokens += msg.tokens?.output ?? 0;\n totalCacheRead += msg.tokens?.cache_read ?? 0;\n totalCacheCreate += msg.tokens?.cache_create ?? 0;\n }\n\n return {\n id: meta.id,\n title: meta.title,\n slug: `claudecode/${meta.id}`,\n directory: meta.directory,\n version: undefined,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\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 total_cache_read_tokens: totalCacheRead,\n total_cache_create_tokens: totalCacheCreate,\n },\n messages: cleanedMessages,\n };\n }\n\n // --- Private helpers ---\n\n private listProjectDirs(): string[] {\n if (!this.basePath) return [];\n try {\n return readdirSync(this.basePath)\n .map((e) => join(this.basePath!, e))\n .filter((p) => existsSync(p));\n } catch {\n return [];\n }\n }\n\n private listJsonlFiles(dir: string): string[] {\n try {\n return readdirSync(dir)\n .filter((f) => f.endsWith(\".jsonl\") && f !== \"sessions-index.json\")\n .map((f) => join(dir, f));\n } catch {\n return [];\n }\n }\n\n private buildSessionMeta(head: SessionHead, file: string, projectDir: string): SessionMeta {\n const indexPath = this.getSessionsIndexPath(projectDir);\n return {\n id: head.id,\n title: head.title,\n sourcePath: file,\n sourceFingerprint: this.sourceFingerprint(file, projectDir),\n sourceMtimeMs: statSync(file).mtimeMs,\n indexPath: existsSync(indexPath) ? indexPath : null,\n indexMtimeMs: this.getFileMtimeMs(indexPath),\n headIndexVersion: HEAD_INDEX_VERSION,\n directory: head.directory,\n model: head.stats.total_tokens ? \"unknown\" : undefined,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n };\n }\n\n private sourceFingerprint(file: string, projectDir: string): string {\n const stat = statSync(file);\n const indexPath = this.getSessionsIndexPath(projectDir);\n return JSON.stringify([\n HEAD_INDEX_VERSION,\n stat.mtimeMs,\n stat.size,\n this.getFileMtimeMs(indexPath),\n ]);\n }\n\n private getSessionsIndexPath(projectDir: string): string {\n return join(projectDir, \"sessions-index.json\");\n }\n\n private getFileMtimeMs(filePath: string): number | null {\n try {\n return statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\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.getFileMtimeMs(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 parseSessionHead(filePath: string, projectDir: string): SessionHead | null {\n return getParsedSession(this.parseSessionHeadResult(filePath, projectDir));\n }\n\n private parseSessionHeadResult(\n filePath: string,\n projectDir: string,\n ): ParseSessionResult<SessionHead> {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\n\n if (lines.length === 0) return skippedSession(\"empty file\");\n\n const sessionId = basename(filePath, \".jsonl\");\n\n let firstRecord: Record<string, unknown>;\n try {\n firstRecord = JSON.parse(lines[0]!);\n } catch {\n return skippedSession(\"malformed first record\");\n }\n\n const createdAt = parseTimestampMs(firstRecord) || statSync(filePath).mtimeMs;\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 = indexEntry?.summary ? String(indexEntry.summary) : null;\n\n // Extract lightweight metadata; cwd lives in user-type records, not the first line\n let updatedAt = createdAt;\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\n for (const line of lines) {\n try {\n const data = JSON.parse(line);\n if (isInternalEventType(data[\"type\"])) 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 = data[\"message\"];\n if (msg && typeof msg === \"object\") {\n const role = (msg as Record<string, unknown>)[\"role\"];\n if (typeof role === \"string\" && role.trim()) {\n messageCount++;\n }\n if (!model) {\n const m = (msg as Record<string, unknown>)[\"model\"];\n if (typeof m === \"string\" && m.trim()) model = m.trim();\n }\n if (role === \"assistant\") {\n const usage = extractClaudeUsage(data, msg as Record<string, unknown>);\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 = (msg as Record<string, unknown>)[\"model\"];\n if (typeof m === \"string\" && 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 const directory = cwd ?? projectDir;\n\n // Extract first user message as fallback title\n const messageTitle = this.extractTitle(lines);\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: `claudecode/${sessionId}`,\n title,\n directory,\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 private extractTitle(lines: string[]): string | null {\n for (const line of lines.slice(0, 20)) {\n try {\n const data = JSON.parse(line);\n if (isInternalEventType(data[\"type\"])) continue;\n const msg = data[\"message\"];\n if (!msg || typeof msg !== \"object\") continue;\n if ((msg as Record<string, unknown>)[\"role\"] !== \"user\") continue;\n\n const content = (msg as Record<string, unknown>)[\"content\"];\n if (!content) continue;\n\n if (typeof content === \"string\") {\n const title = normalizeTitleText(content);\n if (title) return title;\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter((item) => typeof item === \"object\" && item !== null && \"text\" in item)\n .map((item) => String((item as Record<string, unknown>)[\"text\"] ?? \"\"))\n .join(\" \");\n const title = normalizeTitleText(texts);\n if (title) return title;\n }\n } catch {\n // skip\n }\n }\n return null;\n }\n\n // --- Record conversion ---\n\n private convertRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ignoredToolCallIds: Set<string>,\n assistantUuidToToolCalls: Map<string, string[]>,\n countedUsageKeys: Set<string>,\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\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 messages,\n pendingToolCalls,\n ignoredToolCallIds,\n assistantUuidToToolCalls,\n countedUsageKeys,\n assistantState,\n );\n } else if (msgType === \"user\") {\n this.convertUserRecord(\n data,\n messages,\n pendingToolCalls,\n ignoredToolCallIds,\n assistantUuidToToolCalls,\n assistantState,\n );\n } else if (msgType === \"tool_result\") {\n this.convertToolResultRecord(data, messages, assistantState);\n }\n }\n\n private convertAssistantRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ignoredToolCallIds: Set<string>,\n assistantUuidToToolCalls: Map<string, string[]>,\n countedUsageKeys: Set<string>,\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\n ): void {\n const msg = (data[\"message\"] ?? {}) as Record<string, unknown>;\n const timestampMs = parseTimestampMs(data);\n const rawContent = (msg[\"content\"] ?? []) as unknown[];\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n const toolCallIds: string[] = [];\n let currentAssistantIndex = assistantState.currentIndex;\n let latestAssistantTextIndex = assistantState.latestTextIndex;\n\n if (Array.isArray(rawContent)) {\n for (const item of rawContent) {\n if (!item || typeof item !== \"object\") continue;\n const part = item as Record<string, unknown>;\n const partType = String(part[\"type\"] ?? \"\");\n\n if (partType === \"thinking\") {\n const text = cleanInternalText(String(part[\"thinking\"] ?? \"\"));\n if (text) {\n currentAssistantIndex = this.appendAssistantReasoning(\n messages,\n { messageId: uuid, data, msg, timestampMs, text, countedUsageKeys },\n currentAssistantIndex,\n );\n }\n continue;\n }\n\n if (partType === \"text\") {\n const text = cleanInternalText(String(part[\"text\"] ?? \"\"));\n if (text) {\n currentAssistantIndex = this.appendAssistantText(\n messages,\n { messageId: uuid, data, msg, timestampMs, text, countedUsageKeys },\n currentAssistantIndex,\n );\n latestAssistantTextIndex = currentAssistantIndex;\n }\n continue;\n }\n\n if (partType !== \"tool_use\") continue;\n\n const toolName = String(part[\"name\"] ?? \"\").trim();\n const toolCallId = String(part[\"id\"] ?? \"\").trim();\n\n if (toolName && toolCallId && this.shouldIgnoreTool(toolName)) {\n ignoredToolCallIds.add(toolCallId);\n continue;\n }\n\n const toolPart = this.buildToolPart(part, timestampMs);\n const [msgIndex, partIndex] = this.attachToolCallToLatestAssistant(messages, {\n messageId: uuid,\n data,\n msg,\n timestampMs,\n toolPart,\n latestTextIndex: latestAssistantTextIndex,\n countedUsageKeys,\n });\n currentAssistantIndex = msgIndex;\n if (toolCallId) {\n pendingToolCalls.set(toolCallId, [msgIndex, partIndex]);\n toolCallIds.push(toolCallId);\n }\n }\n }\n\n if (toolCallIds.length > 0) {\n assistantUuidToToolCalls.set(uuid, toolCallIds);\n }\n\n assistantState.currentIndex = currentAssistantIndex;\n assistantState.latestTextIndex = latestAssistantTextIndex;\n }\n\n private convertUserRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ignoredToolCallIds: Set<string>,\n assistantUuidToToolCalls: Map<string, string[]>,\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\n ): void {\n const msg = (data[\"message\"] ?? {}) as Record<string, unknown>;\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 assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n return;\n }\n messages.push(this.buildMessage({ messageId: uuid, role: \"user\", timestampMs, parts }));\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n return;\n }\n\n if (!Array.isArray(content)) {\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\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 if (!item || typeof item !== \"object\") continue;\n const ci = item as Record<string, unknown>;\n if (ci[\"type\"] !== \"tool_result\") continue;\n\n const toolCallId = this.resolveToolCallId(data, ci, assistantUuidToToolCalls);\n if (toolCallId && ignoredToolCallIds.has(toolCallId)) continue;\n\n const outputParts = this.normalizeClaudeToolOutput(ci[\"content\"], timestampMs);\n if (\n this.backfillToolOutput(\n messages,\n pendingToolCalls,\n toolCallId,\n outputParts,\n toolStateUpdates,\n )\n ) {\n continue;\n }\n\n const fallback = this.buildFallbackToolMessage({\n messageId: uuid,\n timestampMs,\n toolCallId,\n outputParts,\n });\n if (fallback) messages.push(fallback);\n }\n\n if (visibleParts.length > 0) {\n messages.push(\n this.buildMessage({ messageId: uuid, role: \"user\", timestampMs, parts: visibleParts }),\n );\n }\n\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n }\n\n private convertToolResultRecord(\n data: Record<string, unknown>,\n messages: Message[],\n assistantState: { currentIndex: number | null; latestTextIndex: number | null },\n ): void {\n const timestampMs = parseTimestampMs(data);\n const msg = (data[\"message\"] ?? {}) as Record<string, unknown>;\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) messages.push(fallback);\n\n assistantState.currentIndex = null;\n assistantState.latestTextIndex = null;\n }\n\n // --- Message building ---\n\n private buildMessage(opts: {\n messageId: string;\n role: string;\n timestampMs: number;\n parts: MessagePart[];\n agent?: string;\n mode?: string;\n model?: string | null;\n provider?: string | null;\n tokens?: Record<string, unknown>;\n cost?: number;\n cost_source?: Message[\"cost_source\"];\n }): Message {\n return {\n id: opts.messageId,\n role: opts.role as Message[\"role\"],\n agent: opts.agent ?? null,\n time_created: opts.timestampMs,\n mode: opts.mode ?? null,\n model: opts.model ?? null,\n provider: opts.provider ?? null,\n tokens: opts.tokens ? (opts.tokens as Message[\"tokens\"]) : undefined,\n cost: opts.cost ?? 0,\n cost_source: opts.cost_source,\n parts: opts.parts,\n };\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): MessagePart {\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 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 // --- Assistant message grouping ---\n\n private appendAssistantReasoning(\n messages: Message[],\n opts: {\n messageId: string;\n data: Record<string, unknown>;\n msg: Record<string, unknown>;\n timestampMs: number;\n text: string;\n countedUsageKeys: Set<string>;\n },\n currentIndex: number | null,\n ): number {\n const part = this.buildReasoningPart(opts.text, opts.timestampMs);\n\n if (currentIndex !== null) {\n const message = messages[currentIndex]!;\n const hasText = message.parts.some((p) => p.type === \"text\");\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasText && !hasTool) {\n this.appendPartIfNew(message, part);\n this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);\n return currentIndex;\n }\n }\n\n const message = this.buildMessage({\n messageId: opts.messageId,\n role: \"assistant\",\n timestampMs: opts.timestampMs,\n parts: [part],\n agent: \"claude\",\n });\n this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);\n messages.push(message);\n return messages.length - 1;\n }\n\n private appendAssistantText(\n messages: Message[],\n opts: {\n messageId: string;\n data: Record<string, unknown>;\n msg: Record<string, unknown>;\n timestampMs: number;\n text: string;\n countedUsageKeys: Set<string>;\n },\n currentIndex: number | null,\n ): number {\n const part = this.buildTextPart(opts.text, opts.timestampMs);\n\n if (currentIndex !== null) {\n const message = messages[currentIndex]!;\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasTool) {\n this.appendPartIfNew(message, part);\n this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);\n return currentIndex;\n }\n }\n\n const message = this.buildMessage({\n messageId: opts.messageId,\n role: \"assistant\",\n timestampMs: opts.timestampMs,\n parts: [part],\n agent: \"claude\",\n });\n this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);\n messages.push(message);\n return messages.length - 1;\n }\n\n private attachToolCallToLatestAssistant(\n messages: Message[],\n opts: {\n messageId: string;\n data: Record<string, unknown>;\n msg: Record<string, unknown>;\n timestampMs: number;\n toolPart: MessagePart;\n latestTextIndex: number | null;\n countedUsageKeys: Set<string>;\n },\n ): [number, number] {\n if (opts.latestTextIndex !== null) {\n const message = messages[opts.latestTextIndex]!;\n message.parts.push(opts.toolPart);\n this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);\n return [opts.latestTextIndex, message.parts.length - 1];\n }\n\n const message = this.buildMessage({\n messageId: opts.messageId,\n role: \"assistant\",\n timestampMs: opts.timestampMs,\n parts: [opts.toolPart],\n agent: \"claude\",\n mode: \"tool\",\n });\n this.applyAssistantMetadata(message, opts.data, opts.msg, opts.countedUsageKeys);\n messages.push(message);\n return [messages.length - 1, 0];\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 if (typeof item === \"object\" && item !== null) {\n const ci = item as Record<string, unknown>;\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 if (typeof item === \"object\" && item !== null) {\n const text = String(\n (item as Record<string, unknown>)[\"text\"] ??\n (item as Record<string, unknown>)[\"content\"] ??\n \"\",\n );\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 messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n callId: string,\n outputParts: MessagePart[],\n stateUpdates?: Record<string, unknown>,\n ): boolean {\n if (!callId) return false;\n\n const location = pendingToolCalls.get(callId);\n if (location === undefined) return false;\n\n const [msgIndex, partIndex] = location;\n const state =\n messages[msgIndex]!.parts[partIndex]!.state ??\n (messages[msgIndex]!.parts[partIndex]!.state = {});\n\n if (outputParts.length > 0) {\n const existing = state.output;\n if (Array.isArray(existing)) {\n existing.push(...outputParts);\n } else if (existing === null || existing === undefined) {\n state.output = [...outputParts];\n } else {\n state.output = [existing, ...outputParts];\n }\n }\n\n if (stateUpdates) {\n Object.assign(state, stateUpdates);\n }\n\n if (outputParts.length > 0 && !state.status) {\n state.status = \"completed\";\n }\n\n return outputParts.length > 0 || !!stateUpdates;\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(toolUseResult: unknown): Record<string, unknown> {\n if (!toolUseResult || typeof toolUseResult !== \"object\") return {};\n\n const result = toolUseResult as Record<string, unknown>;\n const updates: Record<string, unknown> = {};\n\n const success = result[\"success\"];\n if (typeof success === \"boolean\") {\n updates[\"status\"] = success ? \"success\" : \"error\";\n }\n\n const commandName = result[\"commandName\"];\n if (commandName) {\n updates[\"meta\"] = { 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 }): Message | null {\n if (opts.outputParts.length === 0) return null;\n return this.buildMessage({\n messageId: opts.messageId,\n role: \"tool\",\n timestampMs: opts.timestampMs,\n parts: opts.outputParts,\n });\n }\n\n // --- Utilities ---\n\n private shouldIgnoreTool(toolName: string): boolean {\n return toolName === \"TodoWrite\";\n }\n\n private appendPartIfNew(message: Message, part: MessagePart): void {\n const parts = message.parts;\n if (parts.length > 0 && parts[parts.length - 1]!.type === part.type) {\n // Skip if identical to tail part (streaming dedup)\n const tail = parts[parts.length - 1]!;\n if (tail.text === part.text) return;\n }\n parts.push(part);\n }\n}\n","import { existsSync, statSync } from \"node:fs\";\nimport type { SessionHead, SessionData, ParseSessionResult } from \"../types/index.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 [key: string]: unknown;\n}\n\nexport interface AgentScanOptions {\n from?: number;\n to?: number;\n fast?: boolean;\n onProgress?: (progress: AgentScanProgress) => void;\n}\n\nexport interface AgentScanProgress {\n total?: number;\n processed?: number;\n sessions?: number;\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\n/** 变更检测结果 */\nexport interface ChangeCheckResult {\n /** 是否有变更 */\n hasChanges: boolean;\n /** 变更的会话 ID 列表(可选,用于精确更新) */\n changedIds?: string[];\n /** 检测时间戳 */\n timestamp: number;\n}\n\nexport interface SessionSourceRef {\n sessionId: string;\n sourcePath: string;\n fingerprint: string;\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): SessionData;\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 * 增量扫描(仅扫描变更的会话)\n * @param cachedSessions 缓存的会话列表\n * @param changedIds 变更的会话 ID 列表\n * @returns 更新后的会话列表\n */\n abstract incrementalScan(\n cachedSessions: SessionHead[],\n changedIds: string[],\n ): Promise<SessionHead[]> | SessionHead[];\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\n/**\n * 文件型 Agent 基类:每个会话对应磁盘上一个独立文件/目录。\n *\n * 子类只需实现两个文件级原语:\n * - listSessionSources(): 枚举所有源 + 计算指纹\n * - scanSessionSource(): 解析单个源(同时写入 metaMap)\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\n /** 枚举所有会话源及其指纹。 */\n abstract listSessionSources(): SessionSourceRef[];\n\n /** 解析单个源并写入 metaMap,返回会话 head(解析失败/不可见返回 null)。 */\n abstract scanSessionSource(sourcePath: string): SessionHead | null;\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 /**\n * 变更检测:枚举当前源 → 与缓存 metaMap 的指纹/路径比对。\n * 新增、变更、删除三类统一产出 changedIds。\n */\n checkForChanges(_sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const currentRefs = this.listSessionSources();\n const currentIds = new Set(currentRefs.map((ref) => ref.sessionId));\n const changedIds = new Set<string>();\n\n for (const ref of currentRefs) {\n const meta = this.sessionMetaMap.get(ref.sessionId);\n const samePath = meta?.sourcePath === ref.sourcePath;\n const sameFingerprint =\n typeof meta?.sourceFingerprint === \"string\" && meta.sourceFingerprint === ref.fingerprint;\n if (!samePath || !sameFingerprint) changedIds.add(ref.sessionId);\n }\n\n for (const session of cachedSessions) {\n if (!currentIds.has(session.id)) changedIds.add(session.id);\n }\n\n const changedIdList = [...changedIds];\n return {\n hasChanges: changedIdList.length > 0,\n changedIds: changedIdList,\n timestamp: Date.now(),\n };\n }\n\n /**\n * 增量扫描:对变更/新增源调用 scanSessionSource 重解析,\n * 删除已消失的源,合并回 cachedSessions。\n */\n incrementalScan(cachedSessions: SessionHead[], changedIds: string[]): SessionHead[] {\n const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));\n const changedSet = new Set(changedIds);\n const currentIds = new Set<string>();\n\n for (const ref of this.listSessionSources()) {\n currentIds.add(ref.sessionId);\n if (!changedSet.has(ref.sessionId)) continue;\n const head = this.scanSessionSource(ref.sourcePath);\n if (head) {\n sessionMap.set(head.id, head);\n } else {\n sessionMap.delete(ref.sessionId);\n this.sessionMetaMap.delete(ref.sessionId);\n }\n }\n\n // Drop sessions flagged as changed but no longer present on disk.\n for (const id of changedSet) {\n if (!currentIds.has(id)) {\n sessionMap.delete(id);\n this.sessionMetaMap.delete(id);\n }\n }\n\n return [...sessionMap.values()];\n }\n}\n\n/**\n * 数据库型 Agent 基类:所有会话聚合在单个 SQLite 数据库中,\n * 无法做 per-file 指纹,故变更检测退化为\"库文件 mtime 是否推进\",\n * 增量扫描退化为全量重扫。\n */\nexport abstract class DatabaseSessionSource extends BaseAgent {\n protected sessionMetaMap = new Map<string, SessionCacheMeta>();\n\n /** 返回数据库文件路径(供 mtime 检测)。 */\n protected abstract getDatabasePath(): string | null;\n\n /** 记录单个会话的缓存 meta(sourcePath = dbPath)。 */\n protected rememberSession(sessionId: string): void {\n const dbPath = this.getDatabasePath();\n if (!dbPath) return;\n this.sessionMetaMap.set(sessionId, { id: sessionId, sourcePath: dbPath });\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 /**\n * 变更检测:数据库内部变更难以按行定位,简单起见按库文件 mtime 判定。\n * 库有变更则标记全部缓存会话刷新。\n */\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const dbPath = this.getDatabasePath();\n if (!dbPath || !existsSync(dbPath)) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n\n try {\n const hasChanges = statSync(dbPath).mtimeMs > sinceTimestamp;\n return {\n hasChanges,\n changedIds: hasChanges ? cachedSessions.map((session) => session.id) : [],\n timestamp: Date.now(),\n };\n } catch {\n return { hasChanges: false, timestamp: Date.now() };\n }\n }\n\n /** 增量扫描:数据库型无法增量,直接全量重扫。 */\n incrementalScan(_cachedSessions: SessionHead[], _changedIds: string[]): SessionHead[] {\n return this.scan();\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\nfunction envPath(name: string): string | null {\n const value = process.env[name];\n if (!value) return null;\n return value;\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\nfunction getDataHome(): string {\n const xdg = envPath(\"XDG_DATA_HOME\");\n if (xdg) return xdg;\n\n const p = platform();\n if (p === \"win32\") {\n return envPath(\"LOCALAPPDATA\") ?? envPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Local\");\n }\n\n // macOS / Linux\n return join(homedir(), \".local\", \"share\");\n}\n\nexport interface ProviderRoots {\n codexRoot: string;\n claudeRoot: string;\n kimiRoot: string;\n opencodeRoot: string;\n piRoot: string;\n}\n\nexport function resolveProviderRoots(): ProviderRoots {\n const home = homedir();\n return {\n codexRoot: envPath(\"CODEX_HOME\") ?? join(home, \".codex\"),\n claudeRoot: envPath(\"CLAUDE_CONFIG_DIR\") ?? join(home, \".claude\"),\n kimiRoot: envPath(\"KIMI_SHARE_DIR\") ?? join(home, \".kimi\"),\n opencodeRoot: join(getDataHome(), \"opencode\"),\n piRoot: envPath(\"PI_HOME\") ?? join(home, \".pi\"),\n };\n}\n\nexport function getCursorDataPath(): string | null {\n const override = envPath(\"CURSOR_DATA_PATH\");\n if (override) return override;\n\n const p = platform();\n if (p === \"darwin\") {\n return firstExisting(join(homedir(), \"Library\", \"Application Support\", \"Cursor\", \"User\"));\n }\n if (p === \"linux\") {\n const xdg = envPath(\"XDG_CONFIG_HOME\") ?? join(homedir(), \".config\");\n return firstExisting(join(xdg, \"Cursor\", \"User\"));\n }\n if (p === \"win32\") {\n const appData = envPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Roaming\");\n return firstExisting(join(appData, \"Cursor\", \"User\"));\n }\n return null;\n}\n\nexport { firstExisting };\n","import { readFileSync } from \"node:fs\";\n\nexport function* parseJsonlLines(content: string): Generator<Record<string, unknown>> {\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n yield JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n // Skip malformed lines\n }\n }\n}\n\nexport function readJsonlFile(filePath: string): Generator<Record<string, unknown>> {\n const content = readFileSync(filePath, \"utf-8\");\n return parseJsonlLines(content);\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_TAGS = [\n \"command-message\",\n \"command-name\",\n \"local-command-stdout\",\n \"system-reminder\",\n];\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_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_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, ParseSessionResult } 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 parsed<T>(data: T): ParseSessionResult<T> {\n return { status: \"parsed\", data };\n}\n\nexport function skipped<T = never>(reason?: string): ParseSessionResult<T> {\n return reason ? { status: \"skipped\", reason } : { status: \"skipped\" };\n}\n\nexport function filtered<T = never>(reason?: string): ParseSessionResult<T> {\n return reason ? { status: \"filtered\", reason } : { status: \"filtered\" };\n}\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 const next: MessagePart = { ...part };\n\n if (typeof next.text === \"string\") {\n next.text = cleanInternalText(next.text);\n if (!next.text && (next.type === \"text\" || next.type === \"reasoning\" || next.type === \"plan\")) {\n return null;\n }\n }\n\n if (typeof next.title === \"string\") {\n const title = cleanInternalText(next.title);\n if (title) next.title = title;\n else delete next.title;\n }\n\n if (next.input !== undefined) {\n next.input = cleanUnknown(next.input);\n }\n if (next.output !== undefined) {\n next.output = cleanUnknown(next.output);\n }\n if (next.state !== undefined) {\n next.state = cleanUnknown(next.state) as MessagePart[\"state\"];\n }\n\n return next;\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\" || typeof part.text !== \"string\") continue;\n const title = normalizeTitleText(cleanInternalText(part.text));\n if (title) return title;\n }\n }\n return null;\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","{\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 { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\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;\n\nlet pricingCache = loadSnapshot();\nloadDiskCache();\n\nfunction normalizeKey(key: string): string {\n return key.trim().toLowerCase();\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 map.set(normalizeKey(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 = normalizeKey(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\nfunction loadDiskCache() {\n const path = getCachePath();\n if (!existsSync(path)) return;\n\n try {\n const cached = JSON.parse(readFileSync(path, \"utf-8\")) as {\n timestamp: number;\n data: Record<string, Record<string, unknown>>;\n };\n if (Date.now() - cached.timestamp <= CACHE_TTL_MS) {\n const next = loadSnapshot();\n for (const [name, rawPricing] of Object.entries(cached.data)) {\n const pricing = normalizeCachedPricing(rawPricing);\n if (!pricing) continue;\n next.set(normalizeKey(name), pricing);\n }\n pricingCache = next;\n }\n } catch {\n // ignore malformed cache\n }\n}\n\nexport function getPricingRegistry(): Map<string, ModelPricing> {\n return pricingCache;\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\nexport async function refreshPricingCache(): 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 try {\n const response = await fetch(LITELLM_URL);\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 pricingCache = next;\n mkdirSync(getCacheDir(), { recursive: true });\n writeFileSync(path, JSON.stringify({ timestamp: Date.now(), data: Object.fromEntries(next) }));\n return true;\n } catch {\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","import aliasesData from \"./data/aliases.json\";\nimport { getPricingRegistry, hasBillablePricing, type ModelPricing } 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 normalizeModelKey(model: string): string {\n return model.trim().toLowerCase().replaceAll(\"_\", \"-\");\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\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) return null;\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 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 { join } from \"node:path\";\nimport {\n DatabaseSessionSource,\n filteredSession,\n getParsedSession,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { AgentScanOptions, ParseSessionResult } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { openDbReadOnly, isSqliteAvailable, 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 {\n cleanInternalText,\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}\n\nexport class OpenCodeAgent extends DatabaseSessionSource {\n readonly name = \"opencode\";\n readonly displayName = \"OpenCode\";\n\n private dbPath: string | null = null;\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 roots = resolveProviderRoots();\n return firstExisting(join(roots.opencodeRoot, \"opencode.db\"), \"data/opencode/opencode.db\");\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) return [];\n\n try {\n const cutoffTime = options?.from ?? Date.now() - 3650 * 24 * 60 * 60 * 1000;\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 let rows: Record<string, unknown>[];\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\n FROM session s\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ORDER BY s.time_created DESC\n `)\n .all(cutoffTime);\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\n FROM session s\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ORDER BY s.time_created DESC\n `)\n .all(cutoffTime);\n }\n\n const headContexts = hasMessageTable\n ? this.buildHeadContexts(\n this.readHeadMessageRows(db, cutoffTime),\n this.readHeadPartRows(db, cutoffTime),\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 head = getParsedSession(\n this.parseSessionHeadRow(row, hasMessageTable, headContexts.get(String(row.id ?? \"\"))),\n );\n if (head) {\n heads.push(head);\n\n // Store session metadata for caching\n if (this.dbPath) {\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n sourcePath: this.dbPath,\n });\n }\n }\n processed += 1;\n options?.onProgress?.({ total: rows.length, processed, sessions: heads.length });\n }\n\n return heads;\n } catch {\n return [];\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: `opencode/${id}`,\n title: resolveSessionTitle(String(row.title ?? \"\"), messageTitle, null),\n directory: String(row.directory ?? \"\"),\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(db: SQLiteDatabase, cutoffTime: number): OpenCodeMessageRow[] {\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 private readHeadPartRows(db: SQLiteDatabase, cutoffTime: number): 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 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\n `,\n )\n .all(cutoffTime) as OpenCodePartRow[];\n }\n\n private parsePartRow(\n partRow: Pick<OpenCodePartRow, \"data\" | \"time_created\">,\n ): MessagePart | null {\n const partData = JSON.parse(String(partRow.data ?? \"{}\")) as Record<string, unknown>;\n const partType = String(partData.type ?? \"\");\n if (isInternalEventType(partType)) return null;\n\n if (partType === \"text\" || partType === \"reasoning\") {\n const text = cleanInternalText(String(partData.text ?? \"\"));\n if (!text) return null;\n return {\n type: partType as \"text\" | \"reasoning\",\n text,\n time_created: Number(partRow.time_created ?? 0),\n };\n }\n\n if (partType === \"tool\") {\n return {\n type: \"tool\",\n tool: String(partData.tool ?? \"\"),\n callID: String(partData.callID ?? \"\"),\n title: cleanInternalText(String(partData.title ?? \"\")),\n state: (partData.state ?? {}) as MessagePart[\"state\"],\n time_created: Number(partRow.time_created ?? 0),\n };\n }\n\n return null;\n }\n\n private readMessageParts(db: SQLiteDatabase, messageId: unknown): MessagePart[] {\n const partRows = db\n .prepare(\"SELECT data, time_created FROM part WHERE message_id = ? ORDER BY time_created ASC\")\n .all(messageId) as OpenCodePartRow[];\n return partRows\n .map((partRow) => this.parsePartRow(partRow))\n .filter((part): part is MessagePart => part !== null);\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 for (const row of messageRows) {\n const sessionId = String(row.session_id ?? \"\");\n if (!sessionId) continue;\n const msgData = JSON.parse(String(row.data ?? \"{}\")) as Record<string, unknown>;\n if (isInternalEventType(msgData.type)) continue;\n const parts = partsByMessage.get(String(row.id ?? \"\")) ?? [];\n if (parts.length === 0) continue;\n\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 };\n contexts.set(sessionId, context);\n }\n\n const cost = Number(msgData.cost ?? 0);\n const tokens = msgData.tokens as Record<string, unknown> | undefined;\n const inputTokens = Number(tokens?.input ?? 0);\n const outputTokens = Number(tokens?.output ?? 0);\n const model = (msgData.modelID as string | null) ?? null;\n const estimatedCost =\n cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });\n\n if (estimatedCost !== null) context.stats.cost_source = \"estimated\";\n context.stats.total_cost += cost || estimatedCost || 0;\n context.stats.total_input_tokens += inputTokens;\n context.stats.total_output_tokens += outputTokens;\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 getSessionData(sessionId: string): SessionData {\n // Ensure dbPath is set\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath) {\n throw new Error(\"OpenCode database is missing\");\n }\n\n const db = openDbReadOnly(this.dbPath);\n if (!db) {\n throw new Error(\"OpenCode 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 = `opencode/${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 totalCost = 0;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\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\")\n .all(sessionId) as Record<string, unknown>[];\n\n for (const msgRow of msgRows) {\n const msgData = JSON.parse(String(msgRow.data ?? \"{}\")) as Record<string, unknown>;\n if (isInternalEventType(msgData.type)) continue;\n\n const cost = Number(msgData.cost ?? 0);\n const tokens = msgData.tokens as Record<string, unknown> | undefined;\n const inputTokens = Number(tokens?.input ?? 0);\n const outputTokens = Number(tokens?.output ?? 0);\n const model = (msgData.modelID as string | null) ?? null;\n const estimatedCost =\n cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });\n const resolvedCost = cost || estimatedCost || 0;\n\n const parts = this.readMessageParts(db, msgRow.id);\n if (parts.length === 0) continue;\n\n messages.push({\n id: String(msgRow.id ?? \"\"),\n role: String(msgData.role ?? \"assistant\") as Message[\"role\"],\n agent: (msgData.agent as string | null) ?? null,\n mode: (msgData.mode as string | null) ?? null,\n model,\n provider: (msgData.providerID as string | null) ?? 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 for (const message of cleanedMessages) {\n totalCost += message.cost ?? 0;\n totalInputTokens += message.tokens?.input ?? 0;\n totalOutputTokens += message.tokens?.output ?? 0;\n if (message.cost_source === \"estimated\") hasEstimatedCost = true;\n }\n\n return {\n id,\n title,\n slug,\n directory,\n version: (sessionRow.version as string | null) ?? undefined,\n time_created: timeCreated,\n time_updated: timeUpdated,\n summary_files: sessionRow.summary_files ?? 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 ? (hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n },\n messages: cleanedMessages,\n };\n } finally {\n db.close();\n }\n }\n}\n","/**\n * SQLite helper — graceful degradation if better-sqlite3 is unavailable.\n */\n\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { createRequire } from \"node:module\";\n\ninterface SQLiteStatement {\n all(...params: unknown[]): DatabaseRow[];\n get(...params: unknown[]): DatabaseRow | undefined;\n run(...params: unknown[]): unknown;\n}\n\ninterface SQLiteTransaction {\n (...params: unknown[]): unknown;\n}\n\ninterface SQLitePragmaCapable {\n pragma(sql: string): unknown;\n}\n\ntype SQLiteDatabaseConstructor = (\n path: string,\n options?: { readonly?: boolean },\n) => SQLiteDatabase & SQLitePragmaCapable;\n\nlet DatabaseConstructor: SQLiteDatabaseConstructor | 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 {\n // better-sqlite3 not installed — adapters that need SQLite will gracefully skip\n}\n\nexport interface DatabaseRow {\n [key: string]: unknown;\n}\n\nexport interface SQLiteDatabase {\n prepare(sql: string): SQLiteStatement;\n exec(sql: string): void;\n transaction<T extends SQLiteTransaction>(fn: T): 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 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 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 }\n }\n\n const apply = db.transaction(() => {\n migration.migrate(db);\n setUserVersion(db, migration.version);\n });\n apply();\n currentVersion = migration.version;\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) return null;\n try {\n const db = DatabaseConstructor(dbPath, { readonly: true });\n return db;\n } catch {\n return null;\n }\n}\n\nexport function openDb(dbPath: string): SQLiteDatabase | null {\n if (!DatabaseConstructor) return null;\n try {\n mkdirSync(dirname(dbPath), { recursive: true });\n const db = DatabaseConstructor(dbPath);\n try {\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 {\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 { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, readdirSync, 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, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { parseJsonlLines } from \"../utils/jsonl.js\";\nimport { normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { cleanInternalText, cleanParsedMessages } from \"../utils/session-normalization.js\";\nimport { perf } from \"../utils/perf.js\";\nimport { estimateTokenCost } from \"../utils/cost.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\"]);\n\nfunction mapToolTitle(toolName: string): string {\n return KIMI_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\ninterface SessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n cwd: string;\n contextFile: string | null;\n wireFile: string | null;\n createdAt: number;\n metaFile: string;\n}\n\ninterface KimiWorkDir {\n path: string;\n last_session_id: string | null;\n}\n\nfunction normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\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 if (typeof item === \"object\" && item !== null && \"text\" in item) {\n const text = String((item as Record<string, unknown>).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 if (typeof item === \"object\" && item !== null) {\n const record = item as Record<string, unknown>;\n return String(record.text ?? record.content ?? \"\");\n }\n return \"\";\n })\n .join(\" \");\n}\n\nfunction extractFirstUserTitle(contextFile: string | null, wireFile: string | null): string | null {\n if (contextFile && existsSync(contextFile)) {\n const content = readFileSync(contextFile, \"utf-8\");\n for (const record of parseJsonlLines(content)) {\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 const content = readFileSync(wireFile, \"utf-8\");\n for (const record of parseJsonlLines(content)) {\n const message = (record.message ?? {}) as Record<string, unknown>;\n if (message.type !== \"TurnBegin\") continue;\n const payload = (message.payload ?? {}) as Record<string, unknown>;\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 const roots = resolveProviderRoots();\n return firstExisting(join(roots.kimiRoot, \"sessions\"), \"data/kimi\");\n }\n\n /** Parse kimi.json and build md5(project_path) → cwd mapping */\n private loadKimiConfig(): void {\n const roots = resolveProviderRoots();\n const configPath = join(roots.kimiRoot, \"kimi.json\");\n const tomlPath = join(roots.kimiRoot, \"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 = JSON.parse(readFileSync(configPath, \"utf-8\")) as Record<string, unknown>;\n const workDirs = raw?.work_dirs;\n if (!Array.isArray(workDirs)) return;\n for (const wd of workDirs) {\n const path = (wd as KimiWorkDir).path;\n if (typeof path !== \"string\") 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 try {\n return this.listSessionDirs().length > 0;\n } catch {\n // ignore\n }\n return false;\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 try {\n for (const hashEntry of readdirSync(this.basePath, { withFileTypes: true })) {\n if (!hashEntry.isDirectory()) continue;\n const hashPath = join(this.basePath, hashEntry.name);\n try {\n for (const sessionEntry of readdirSync(hashPath, { withFileTypes: true })) {\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 } catch {\n // skip unreadable hash dirs\n }\n }\n } catch {\n // skip unreadable base\n }\n return dirs;\n }\n\n /** Parse session directory, preferring state.json over metadata.json */\n private parseSessionDir(sessionDir: string): SessionMeta | null {\n return getParsedSession(this.parseSessionDirResult(sessionDir));\n }\n\n private parseSessionDirResult(sessionDir: string): ParseSessionResult<SessionMeta> {\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 if (!existsSync(contextFile) && !existsSync(wireFile)) {\n return skippedSession(\"missing transcript\");\n }\n\n const statePath = join(sessionDir, \"state.json\");\n const metaPath = join(sessionDir, \"metadata.json\");\n\n let title = \"\";\n let wireMtime: number | null = null;\n let metaFile = \"\";\n\n if (existsSync(statePath)) {\n const state = JSON.parse(readFileSync(statePath, \"utf-8\")) as Record<string, unknown>;\n title = String(state.custom_title ?? \"\");\n wireMtime = typeof state.wire_mtime === \"number\" ? state.wire_mtime : null;\n metaFile = statePath;\n } else if (existsSync(metaPath)) {\n const meta = JSON.parse(readFileSync(metaPath, \"utf-8\")) as Record<string, unknown>;\n title = String(meta.title ?? \"\");\n wireMtime = typeof meta.wire_mtime === \"number\" ? meta.wire_mtime : null;\n metaFile = metaPath;\n }\n\n const cwd = this.projectMap.get(projectHash) || \"\";\n const existingContextFile = existsSync(contextFile) ? contextFile : null;\n const existingWireFile = existsSync(wireFile) ? wireFile : null;\n const messageTitle = extractFirstUserTitle(existingContextFile, existingWireFile);\n const createdAt =\n wireMtime !== null\n ? wireMtime * 1000\n : metaFile\n ? statSync(metaFile).mtimeMs\n : statSync(sessionDir).mtimeMs;\n\n return parsedSession({\n id: sessionId,\n title: resolveSessionTitle(title, messageTitle, null),\n sourcePath: sessionDir,\n cwd,\n contextFile: existingContextFile,\n wireFile: existingWireFile,\n createdAt,\n metaFile,\n });\n } catch {\n return skippedSession(\"malformed metadata\");\n }\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n if (!this.basePath) return [];\n\n const scanMarker = perf.start(\"kimi:scan\");\n\n const listMarker = perf.start(\"listSessionDirs\");\n const sessionDirs = this.listSessionDirs();\n perf.end(listMarker);\n\n const metas: SessionMeta[] = [];\n for (const dir of sessionDirs) {\n try {\n const parseMarker = perf.start(`parseSessionDir:${basename(dir)}`);\n const meta = getParsedSession(this.parseSessionDirResult(dir));\n perf.end(parseMarker);\n if (meta && matchesScanWindow(meta.createdAt, options)) {\n metas.push(meta);\n }\n } catch {\n // skip\n }\n }\n options?.onProgress?.({ total: metas.length, processed: 0, sessions: 0 });\n\n const heads: SessionHead[] = [];\n let processed = 0;\n for (const meta of metas) {\n try {\n meta.sourceFingerprint = this.sourceFingerprint(meta);\n this.sessionMetaMap.set(meta.id, meta);\n const stats = this.extractStats(meta.sourcePath);\n heads.push({\n id: meta.id,\n slug: `kimi/${meta.id}`,\n title: meta.title,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats,\n });\n } catch {\n // skip\n } finally {\n processed += 1;\n options?.onProgress?.({ total: metas.length, processed, sessions: heads.length });\n }\n }\n\n perf.end(scanMarker);\n return heads;\n }\n\n listSessionSources(): SessionSourceRef[] {\n if (!this.basePath) return [];\n const refs: SessionSourceRef[] = [];\n for (const dir of this.listSessionDirs()) {\n const meta = getParsedSession(this.parseSessionDirResult(dir));\n if (!meta) continue;\n refs.push({\n sessionId: meta.id,\n sourcePath: meta.sourcePath,\n fingerprint: this.sourceFingerprint(meta),\n });\n }\n return refs;\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n const meta = getParsedSession(this.parseSessionDirResult(sourcePath));\n if (!meta) return null;\n meta.sourceFingerprint = this.sourceFingerprint(meta);\n this.sessionMetaMap.set(meta.id, meta);\n const stats = this.extractStats(meta.sourcePath);\n return {\n id: meta.id,\n slug: `kimi/${meta.id}`,\n title: meta.title,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats,\n };\n }\n\n getSessionData(sessionId: string): SessionData {\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): SessionData {\n if (!meta.contextFile) throw new Error(\"context.jsonl is missing\");\n\n const content = readFileSync(meta.contextFile, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n const ignoredToolCallIds = new Set<string>();\n\n let seq = 0;\n const fallbackTs = meta.createdAt;\n for (const record of parseJsonlLines(content)) {\n seq++;\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 messages.push(\n this.buildMessage({\n messageId: `context-${seq}`,\n role: \"user\",\n timestampMs: fallbackTs,\n parts: [{ type: \"text\", text, time_created: fallbackTs }],\n }),\n );\n }\n continue;\n }\n\n if (role === \"assistant\") {\n const { message, toolIndexes } = this.buildContextAssistantMessage(\n record,\n seq,\n ignoredToolCallIds,\n fallbackTs,\n );\n if (!message) continue;\n const msgIndex = messages.length;\n messages.push(message);\n for (const [callId, partIndex] of toolIndexes) {\n pendingToolCalls.set(callId, [msgIndex, partIndex]);\n }\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(messages, pendingToolCalls, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n messages.push(\n this.buildMessage({\n messageId: `context-${seq}`,\n role: \"tool\",\n timestampMs: fallbackTs,\n parts: outputParts,\n }),\n );\n }\n }\n } catch {\n // skip\n }\n }\n\n const stats = this.extractStats(meta.sourcePath);\n return this.buildSessionData(meta, messages, stats);\n }\n\n private getSessionDataFromWire(meta: SessionMeta): SessionData {\n const wirePath = meta.wireFile ?? join(meta.sourcePath, \"wire.jsonl\");\n if (!existsSync(wirePath)) throw new Error(\"wire.jsonl is missing\");\n\n const content = readFileSync(wirePath, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n const ignoredToolCallIds = new Set<string>();\n const openToolArgumentBuffer = new Map<string, string>();\n\n let currentAssistantIndex: number | null = null;\n let openToolCallId: string | null = null;\n let seq = 0;\n\n for (const record of parseJsonlLines(content)) {\n seq++;\n try {\n const message = (record.message ?? {}) as Record<string, unknown>;\n const msgType = String(message.type ?? \"\");\n if (isInternalEventType(msgType)) continue;\n const payload = (message.payload ?? {}) as Record<string, unknown>;\n const timestamp = Number(record.timestamp ?? 0);\n const timestampMs = Number.isFinite(timestamp) ? Math.floor(timestamp * 1000) : 0;\n\n // Bind usage to the most recent assistant message without tokens\n const usage = message[\"usage\"] as Record<string, unknown> | undefined;\n if (usage && typeof usage === \"object\") {\n const inputTokens = Number(usage[\"input_tokens\"] ?? 0);\n const outputTokens = Number(usage[\"output_tokens\"] ?? 0);\n if (inputTokens || outputTokens) {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role === \"assistant\" && !msg.tokens) {\n msg.tokens = { input: inputTokens, output: outputTokens };\n msg.model ??= this.defaultModel;\n const cost = estimateTokenCost(msg.model, msg.tokens);\n if (cost !== null) {\n msg.cost = cost;\n msg.cost_source = \"estimated\";\n }\n break;\n }\n }\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 messages.push(\n this.buildMessage({\n messageId: `wire-${seq}`,\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text, time_created: timestampMs }],\n }),\n );\n }\n }\n currentAssistantIndex = null;\n openToolCallId = null;\n continue;\n }\n\n if (msgType === \"ContentPart\") {\n currentAssistantIndex = this.getOrCreateWireAssistant(\n messages,\n currentAssistantIndex,\n `wire-${seq}`,\n );\n const assistant = messages[currentAssistantIndex]!;\n const partType = String(payload.type ?? \"\");\n if (partType === \"think\") {\n const text = cleanInternalText(String(payload.think ?? \"\"));\n if (text) {\n assistant.parts.push({ type: \"reasoning\", text, time_created: timestampMs });\n }\n } else if (partType === \"text\") {\n const text = cleanInternalText(String(payload.text ?? \"\"));\n if (text) {\n assistant.parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n }\n continue;\n }\n\n if (msgType === \"ToolCall\") {\n const function_ = payload.function as Record<string, unknown> | undefined;\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 currentAssistantIndex = this.getOrCreateWireAssistant(\n messages,\n currentAssistantIndex,\n `wire-${seq}`,\n );\n const assistant = messages[currentAssistantIndex]!;\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: { arguments: normalizedArgs, output: null },\n time_created: timestampMs,\n };\n\n const partIndex = assistant.parts.length;\n assistant.parts.push(toolPart);\n assistant.mode = \"tool\";\n pendingToolCalls.set(callId, [currentAssistantIndex, partIndex]);\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 messages,\n pendingToolCalls,\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(messages, pendingToolCalls, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n messages.push(\n this.buildMessage({\n messageId: `wire-${seq}`,\n role: \"tool\",\n timestampMs,\n parts: outputParts,\n }),\n );\n }\n continue;\n }\n\n // Skip StepBegin, StatusUpdate, ApprovalRequest, ApprovalResponse, TurnEnd\n } catch {\n // skip\n }\n }\n\n // Filter out messages with empty parts\n const filteredMessages = messages.filter((m) => m.parts.length > 0);\n const stats = this.extractStats(meta.sourcePath);\n return this.buildSessionData(meta, filteredMessages, stats);\n }\n\n // --- Helpers ---\n\n private sourceFingerprint(meta: SessionMeta): string {\n const fileMtime = (path: string | null) => {\n if (!path) return null;\n try {\n return statSync(path).mtimeMs;\n } catch {\n return null;\n }\n };\n return JSON.stringify([\n fileMtime(meta.metaFile),\n fileMtime(meta.contextFile),\n fileMtime(meta.wireFile),\n ]);\n }\n\n private buildMessage(opts: {\n messageId: string;\n role: string;\n timestampMs: number;\n parts: MessagePart[];\n agent?: string;\n mode?: string;\n model?: string | null;\n provider?: string | null;\n tokens?: Record<string, unknown>;\n cost?: number;\n }): Message {\n return {\n id: opts.messageId,\n role: opts.role as Message[\"role\"],\n agent: opts.agent ?? null,\n time_created: opts.timestampMs,\n mode: opts.mode ?? null,\n model: opts.model ?? null,\n provider: opts.provider ?? null,\n tokens: opts.tokens ? (opts.tokens as Message[\"tokens\"]) : undefined,\n cost: opts.cost ?? 0,\n parts: opts.parts,\n };\n }\n\n private buildContextAssistantMessage(\n record: Record<string, unknown>,\n seq: number,\n ignoredToolCallIds: Set<string>,\n fallbackTs: number,\n ): { message: Message; toolIndexes: Map<string, number> } {\n const parts: MessagePart[] = [];\n const toolIndexes = new Map<string, number>();\n\n const content = record.content;\n if (Array.isArray(content)) {\n for (const item of content) {\n if (typeof item !== \"object\" || item === null) continue;\n const ci = item as Record<string, unknown>;\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 = record.tool_calls;\n if (Array.isArray(toolCalls)) {\n for (const tc of toolCalls) {\n if (typeof tc !== \"object\" || tc === null) continue;\n const tcRecord = tc as Record<string, unknown>;\n const function_ = tcRecord.function as Record<string, unknown> | undefined;\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: { arguments: normalizeToolArguments(function_.arguments), output: null },\n time_created: fallbackTs,\n };\n toolIndexes.set(callId, parts.length);\n parts.push(part);\n }\n }\n\n if (parts.length === 0) {\n return {\n message: this.buildMessage({\n messageId: `context-${seq}`,\n role: \"assistant\",\n timestampMs: fallbackTs,\n parts: [],\n }),\n toolIndexes,\n };\n }\n\n const allTools = parts.every((p) => p.type === \"tool\");\n const message = this.buildMessage({\n messageId: `context-${seq}`,\n role: \"assistant\",\n timestampMs: fallbackTs,\n parts,\n agent: \"kimi\",\n mode: allTools ? \"tool\" : undefined,\n });\n\n return { message, toolIndexes };\n }\n\n private getOrCreateWireAssistant(\n messages: Message[],\n currentIndex: number | null,\n messageId: string,\n ): number {\n if (currentIndex !== null) return currentIndex;\n messages.push(\n this.buildMessage({\n messageId,\n role: \"assistant\",\n timestampMs: 0,\n parts: [],\n agent: \"kimi\",\n }),\n );\n return messages.length - 1;\n }\n\n private appendWireToolCallPart(\n argumentsPart: string,\n openCallId: string | null,\n buffer: Map<string, string>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n ): void {\n if (!openCallId || !pendingToolCalls.has(openCallId)) return;\n\n const existing = buffer.get(openCallId) ?? \"\";\n const combined = existing + argumentsPart;\n\n try {\n const parsed = JSON.parse(combined) as unknown;\n const location = pendingToolCalls.get(openCallId);\n if (!location) return;\n const msgPart = messages[location[0]]?.parts[location[1]];\n if (msgPart?.state) {\n msgPart.state.arguments = parsed;\n }\n buffer.delete(openCallId);\n } catch {\n buffer.set(openCallId, combined);\n }\n }\n\n private backfillToolOutput(\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n callId: string,\n outputParts: MessagePart[],\n ): boolean {\n if (!outputParts.length || !callId) return false;\n\n const location = pendingToolCalls.get(callId);\n if (!location) return false;\n\n const part = messages[location[0]]?.parts[location[1]];\n if (!part) return false;\n if (!part.state) part.state = {};\n part.state.output = [...outputParts];\n return true;\n }\n\n private extractStats(sessionDir: string): SessionData[\"stats\"] {\n let totalCost = 0;\n const stats: SessionData[\"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 const wirePath = join(sessionDir, \"wire.jsonl\");\n if (!existsSync(wirePath)) return stats;\n\n try {\n const content = readFileSync(wirePath, \"utf-8\");\n for (const line of content.split(\"\\n\").filter((l) => l.trim())) {\n try {\n const data = JSON.parse(line) as Record<string, unknown>;\n const tokenUsage = (data.message as Record<string, unknown>)?.usage as\n | Record<string, unknown>\n | undefined;\n if (!tokenUsage) continue;\n const inputTokens = Number(tokenUsage.input_tokens ?? 0);\n const outputTokens = Number(tokenUsage.output_tokens ?? 0);\n stats.total_input_tokens += inputTokens;\n stats.total_output_tokens += outputTokens;\n const cost = estimateTokenCost(this.defaultModel, {\n input: inputTokens,\n output: outputTokens,\n });\n if (cost !== null) totalCost += cost;\n } catch {\n // skip\n }\n }\n } catch {\n // skip\n }\n\n // Extract total tokens from context or wire\n const contextPath = join(sessionDir, \"context.jsonl\");\n const rawPath = existsSync(contextPath) ? contextPath : wirePath;\n if (!existsSync(rawPath)) return stats;\n\n try {\n const rawContent = readFileSync(rawPath, \"utf-8\");\n for (const line of rawContent.split(\"\\n\").filter((l) => l.trim())) {\n try {\n const data = JSON.parse(line) as Record<string, unknown>;\n if (data.role === \"_usage\" && typeof data.token_count === \"number\") {\n stats.total_tokens = data.token_count;\n }\n } catch {\n // skip\n }\n }\n } catch {\n // skip\n }\n\n stats.total_cost = Number(totalCost.toFixed(8));\n if (stats.total_cost > 0) {\n stats.cost_source = \"estimated\";\n }\n\n return stats;\n }\n\n private buildSessionData(\n meta: SessionMeta,\n messages: Message[],\n stats: SessionData[\"stats\"],\n ): SessionData {\n const cleanedMessages = cleanParsedMessages(messages);\n stats.message_count = cleanedMessages.length;\n const totalCost = cleanedMessages.reduce((sum, message) => sum + (message.cost ?? 0), 0);\n if (totalCost > 0) {\n stats.total_cost = Number(totalCost.toFixed(8));\n stats.cost_source = \"estimated\";\n }\n return {\n id: meta.id,\n title: meta.title,\n slug: `kimi/${meta.id}`,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats,\n messages: cleanedMessages,\n };\n }\n}\n","import {\n closeSync,\n existsSync,\n openSync,\n readFileSync,\n readSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport {\n FileSystemSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { ParseSessionResult } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { resolveProviderRoots, firstExisting } from \"../discovery/paths.js\";\nimport { parseJsonlLines } from \"../utils/jsonl.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport {\n cleanInternalText,\n cleanParsedMessages,\n isInternalEventType,\n} from \"../utils/session-normalization.js\";\nimport { perf } from \"../utils/perf.js\";\nimport { estimateTokenCost } from \"../utils/cost.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-v1\";\nconst PARSER_VERSION = \"codex-parser-v3\";\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 const ts = String(data[\"timestamp\"] ?? \"\").trim();\n if (!ts) return 0;\n try {\n return new Date(ts.includes(\"Z\") ? ts : ts.replace(\" \", \"T\") + \"Z\").getTime();\n } catch {\n return 0;\n }\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\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 normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\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// 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 { AgentScanOptions, SessionCacheMeta, SessionSourceRef } from \"./base.js\";\n\ninterface SessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n sourceMtimeMs: number;\n indexPath: string | null;\n indexMtimeMs: number | null;\n headIndexVersion: string;\n parserVersion: string;\n directory: string;\n model: string | null;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\n// ---------------------------------------------------------------------------\n// CodexAgent\n// ---------------------------------------------------------------------------\n\nexport class CodexAgent extends FileSystemSessionSource<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 = null;\n\n // ---- BaseAgent implementation ----\n\n private findBasePath(): string | null {\n const roots = resolveProviderRoots();\n return firstExisting(join(roots.codexRoot, \"sessions\"));\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n try {\n // Check recursively for rollout jsonl files\n const files = this.walkDirForRolloutFiles(this.basePath);\n return files.length > 0;\n } catch {\n return false;\n }\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n if (!this.basePath) return [];\n\n const scanMarker = perf.start(\"codex:scan\");\n\n // Pre-load session index for titles\n const indexMarker = perf.start(\"loadSessionIndex\");\n this.loadSessionIndex();\n perf.end(indexMarker);\n\n const heads: SessionHead[] = [];\n\n const listMarker = perf.start(\"listRolloutFiles\");\n const files = this.listRolloutFiles(options);\n perf.end(listMarker);\n options?.onProgress?.({ total: files.length, processed: 0, sessions: 0 });\n\n let processed = 0;\n for (const file of files) {\n try {\n const parseMarker = perf.start(`parseSessionHead:${basename(file)}`);\n const head = getParsedSession(this.parseSessionHeadResult(file, options));\n perf.end(parseMarker);\n\n if (head) {\n heads.push(head);\n this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, file));\n }\n } catch {\n // skip malformed files\n } finally {\n processed += 1;\n options?.onProgress?.({ total: files.length, processed, sessions: heads.length });\n }\n }\n\n perf.end(scanMarker);\n return heads;\n }\n\n listSessionSources(): SessionSourceRef[] {\n if (!this.basePath) return [];\n this.loadSessionIndex();\n return this.listRolloutFiles().map((file) => ({\n sessionId: extractSessionId(file),\n sourcePath: file,\n fingerprint: this.sourceFingerprint(file),\n }));\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n this.loadSessionIndex();\n const head = getParsedSession(this.parseSessionHeadResult(sourcePath));\n if (head) {\n this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, sourcePath));\n }\n return head;\n }\n\n getSessionData(sessionId: string): SessionData {\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 content = readFileSync(meta.sourcePath, \"utf-8\");\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCost = 0;\n\n // Assistant message grouping state\n let currentAssistantIndex: number | null = null;\n let latestAssistantTextIndex: number | null = null;\n let pendingPlan: MessagePart | null = null;\n let activeModel: string | null = meta.model;\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 parseJsonlLines(content)) {\n try {\n const recordType = String(record[\"type\"] ?? \"\");\n if (recordType === \"turn_context\") {\n const payload = (record[\"payload\"] ?? {}) as Record<string, unknown>;\n activeModel = extractModelName(payload[\"model\"]) ?? activeModel;\n }\n\n const result = this.convertRecord(\n record,\n messages,\n pendingToolCalls,\n meta.id,\n currentAssistantIndex,\n latestAssistantTextIndex,\n pendingPlan,\n );\n currentAssistantIndex = result.currentAssistantIndex;\n latestAssistantTextIndex = result.latestAssistantTextIndex;\n pendingPlan = result.pendingPlan;\n\n if (currentAssistantIndex !== null && activeModel) {\n const message = messages[currentAssistantIndex];\n if (message?.role === \"assistant\" && !message.model) {\n message.model = activeModel;\n }\n }\n\n // Process Codex token_count events\n if (recordType === \"event_msg\") {\n const payload = (record[\"payload\"] ?? {}) as Record<string, unknown>;\n if (String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const info = payload[\"info\"] as Record<string, unknown> | undefined;\n const totalUsage = info?.[\"total_token_usage\"] as Record<string, unknown> | undefined;\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 const lastUsage = info?.[\"last_token_usage\"] as Record<string, unknown> | undefined;\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 // Bind to the most recent assistant message without tokens\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role === \"assistant\" && !msg.tokens) {\n msg.tokens = {\n input: totalInput,\n output: outputTokens,\n reasoning: reasoningTokens || undefined,\n cache_read: totalCacheRead || undefined,\n };\n const cost = estimateTokenCost(msg.model ?? activeModel, msg.tokens);\n if (cost !== null) {\n msg.cost = cost;\n msg.cost_source = \"estimated\";\n totalCost += cost;\n }\n break;\n }\n }\n }\n }\n }\n }\n } catch {\n // skip malformed records\n }\n }\n\n // Finalize pending plan if any\n if (pendingPlan && currentAssistantIndex !== null) {\n messages[currentAssistantIndex]!.parts.push(pendingPlan);\n }\n const cleanedMessages = cleanParsedMessages(messages);\n\n return {\n id: meta.id,\n title: meta.title,\n slug: `codex/${meta.id}`,\n directory: meta.directory,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: {\n message_count: cleanedMessages.length,\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 messages: cleanedMessages,\n };\n }\n\n // ---- File listing ----\n\n private listRolloutFiles(options?: AgentScanOptions): string[] {\n if (!this.basePath) return [];\n try {\n return this.walkDirForRolloutFiles(this.basePath, options);\n } catch {\n return [];\n }\n }\n\n private walkDirForRolloutFiles(dir: string, options?: AgentScanOptions): string[] {\n const files: string[] = [];\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...this.walkDirForRolloutFiles(fullPath, options));\n } else if (entry.name.endsWith(\".jsonl\") && entry.name.startsWith(\"rollout-\")) {\n if (options?.from != null || options?.to != null) {\n try {\n if (!matchesScanWindow(statSync(fullPath).mtimeMs, options)) continue;\n } catch {\n continue;\n }\n }\n files.push(fullPath);\n }\n }\n } catch {\n // skip permission errors\n }\n return files;\n }\n\n private buildSessionMeta(head: SessionHead, file: string): SessionMeta {\n const indexPath = this.getSessionIndexPath();\n return {\n id: head.id,\n title: head.title,\n sourcePath: file,\n sourceFingerprint: this.sourceFingerprint(file),\n sourceMtimeMs: statSync(file).mtimeMs,\n indexPath: existsSync(indexPath) ? indexPath : null,\n indexMtimeMs: this.getFileMtimeMs(indexPath),\n headIndexVersion: HEAD_INDEX_VERSION,\n parserVersion: PARSER_VERSION,\n directory: head.directory,\n model: null,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n };\n }\n\n private sourceFingerprint(file: string): string {\n const stat = statSync(file);\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 const roots = resolveProviderRoots();\n return join(roots.codexRoot, \"session_index.jsonl\");\n }\n\n private getFileMtimeMs(filePath: string): number | null {\n try {\n return statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n }\n\n // ---- Session index ----\n\n private loadSessionIndex(): void {\n const indexPath = this.getSessionIndexPath();\n const mtime = this.getFileMtimeMs(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.sessionIndexCache.size > 0 && this.sessionIndexMtime === mtime) return;\n\n this.sessionIndexCache.clear();\n this.sessionIndexMtime = mtime;\n if (mtime === null) return;\n\n try {\n const content = readFileSync(indexPath, \"utf-8\");\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 this.sessionIndexCache.set(sid, threadName);\n }\n }\n } catch {\n // ignore\n }\n }\n\n private getTitleForSession(sessionId: string): string | null {\n this.loadSessionIndex();\n return this.sessionIndexCache.get(sessionId) ?? null;\n }\n\n // ---- Session head parsing ----\n\n private readFilePrefix(filePath: string, bytes = 64 * 1024): string {\n const fd = openSync(filePath, \"r\");\n try {\n const buffer = Buffer.alloc(bytes);\n const bytesRead = readSync(fd, buffer, 0, bytes, 0);\n return buffer.subarray(0, bytesRead).toString(\"utf-8\");\n } finally {\n closeSync(fd);\n }\n }\n\n private parseSessionHead(filePath: string, options?: AgentScanOptions): SessionHead | null {\n return getParsedSession(this.parseSessionHeadResult(filePath, options));\n }\n\n private parseSessionHeadResult(\n filePath: string,\n options?: AgentScanOptions,\n ): ParseSessionResult<SessionHead> {\n if (options?.fast) {\n return this.parseFastSessionHeadResult(filePath);\n }\n\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\").filter((l) => l.trim());\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 {\n return skippedSession(\"malformed first record\");\n }\n\n const payload = (firstRecord[\"payload\"] ?? {}) as Record<string, unknown>;\n const createdAt =\n parseTimestampMs(firstRecord) || parseTimestampMs(payload) || statSync(filePath).mtimeMs;\n\n // Try title from session index\n const indexTitle = this.getTitleForSession(sessionId);\n // Fallback: extract from first user message\n const messageTitle = this.extractTitleFromLines(lines);\n const directoryTitle = basenameTitle(payload[\"cwd\"] ? String(payload[\"cwd\"]) : null);\n\n const title = resolveSessionTitle(indexTitle, messageTitle, directoryTitle);\n\n // Walk all lines to count messages, extract model, and pre-accumulate tokens\n let updatedAt = createdAt;\n let messageCount = 0;\n let model: string | null = null;\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 lines) {\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n const payload = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n const payloadType = String(payload[\"type\"] ?? \"\");\n if (isInternalEventType(recordType) || isInternalEventType(payloadType)) continue;\n hasNonInternalRecord = true;\n const recordTs =\n parseTimestampMs(data) ||\n parseTimestampMs((data[\"payload\"] ?? {}) as Record<string, unknown>);\n if (recordTs > updatedAt) updatedAt = recordTs;\n\n if (recordType === \"session_meta\" || recordType === \"turn_context\") {\n const nextModel = extractModelName(payload[\"model\"]);\n if (nextModel) {\n activeModel = nextModel;\n model ??= 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 = p[\"info\"] as Record<string, unknown> | undefined;\n const m = info?.[\"model\"] ?? p[\"model\"];\n if (typeof m === \"string\" && m.trim()) {\n activeModel = m.trim();\n model ??= activeModel;\n }\n }\n\n if (recordType === \"event_msg\") {\n const p = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n if (String(p[\"type\"] ?? \"\") === \"token_count\") {\n const info = p[\"info\"] as Record<string, unknown> | undefined;\n const totalUsage = info?.[\"total_token_usage\"] as Record<string, unknown> | undefined;\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n\n if (cumulativeTotal > 0 && cumulativeTotal !== scanPrevCumulativeTotal) {\n scanPrevCumulativeTotal = cumulativeTotal;\n\n const lastUsage = info?.[\"last_token_usage\"] as Record<string, unknown> | undefined;\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 (!hasNonInternalRecord) return filteredSession(\"internal events only\");\n\n const directory = payload[\"cwd\"] ? String(payload[\"cwd\"]) : \"\";\n\n return parsedSession({\n id: sessionId,\n slug: `codex/${sessionId}`,\n title,\n directory,\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 parseFastSessionHead(filePath: string): SessionHead | null {\n return getParsedSession(this.parseFastSessionHeadResult(filePath));\n }\n\n private parseFastSessionHeadResult(filePath: string): ParseSessionResult<SessionHead> {\n const prefix = this.readFilePrefix(filePath);\n const lines = prefix.split(\"\\n\").filter((l) => l.trim());\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 {\n return skippedSession(\"malformed first record\");\n }\n\n const payload = (firstRecord[\"payload\"] ?? {}) as Record<string, unknown>;\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: `codex/${sessionId}`,\n title,\n directory,\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 private extractTitleFromLines(lines: string[]): string | null {\n for (const line of lines.slice(0, 20)) {\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n if (recordType !== \"response_item\" || isInternalEventType(recordType)) continue;\n\n const payload = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n const pType = String(payload[\"type\"] ?? \"\");\n if (pType !== \"message\" || isInternalEventType(pType)) continue;\n if (String(payload[\"role\"] ?? \"\") !== \"user\") continue;\n\n const content = payload[\"content\"];\n let text: string | null = null;\n if (Array.isArray(content)) {\n text = content\n .filter((item) => typeof item === \"object\" && item !== null && \"text\" in item)\n .map((item) => String((item as Record<string, unknown>)[\"text\"] ?? \"\"))\n .join(\" \");\n } else if (typeof content === \"string\") {\n text = content;\n }\n if (!text || isDeveloperLikeUserMessage(text)) continue;\n const title = normalizeTitleText(text);\n if (title) return title;\n } catch {\n // skip\n }\n }\n return null;\n }\n\n // ---- Record conversion ----\n\n private convertRecord(\n data: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n sessionId: string,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n pendingPlan: MessagePart | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const recordType = String(data[\"type\"] ?? \"\");\n if (isInternalEventType(recordType)) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Skip non-response records\n if (recordType === \"session_meta\" || recordType === \"event_msg\") {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n if (recordType !== \"response_item\") {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n const payload = (data[\"payload\"] ?? {}) as Record<string, unknown>;\n const payloadType = String(payload[\"type\"] ?? \"\");\n if (isInternalEventType(payloadType)) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\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 messages,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n pendingPlan,\n );\n }\n if (role === \"user\") {\n return this.convertUserMessage(\n payload,\n messages,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n pendingPlan,\n );\n }\n break;\n }\n\n case \"reasoning\":\n return this.convertReasoning(payload, messages, timestampMs, currentAssistantIndex);\n\n case \"function_call\":\n return this.convertFunctionCall(\n payload,\n messages,\n pendingToolCalls,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n );\n\n case \"function_call_output\":\n this.convertFunctionCallOutput(payload, messages, pendingToolCalls, timestampMs);\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n\n case \"custom_tool_call\":\n return this.convertCustomToolCall(\n payload,\n messages,\n pendingToolCalls,\n timestampMs,\n currentAssistantIndex,\n latestAssistantTextIndex,\n );\n\n case \"custom_tool_call_output\":\n this.convertCustomToolCallOutput(payload, messages, pendingToolCalls, timestampMs);\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // ---- Assistant message ----\n\n private convertAssistantMessage(\n payload: Record<string, unknown>,\n messages: Message[],\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n pendingPlan: MessagePart | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const content = payload[\"content\"];\n if (!Array.isArray(content)) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Extract output_text items\n const textParts: string[] = [];\n for (const item of content) {\n if (typeof item !== \"object\" || item === null) continue;\n const ci = item as Record<string, unknown>;\n if (String(ci[\"type\"] ?? \"\") === \"output_text\") {\n const text = String(ci[\"text\"] ?? \"\");\n if (text.trim()) textParts.push(text);\n }\n }\n\n if (textParts.length === 0) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n const fullText = textParts.join(\"\\n\");\n\n // Check for proposed plan\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 // Build text part (strip the proposed plan tags)\n const displayText = cleanInternalText(fullText.replace(PROPOSED_PLAN_PATTERN, \"\"));\n if (!displayText) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n const textPart: MessagePart = { type: \"text\", text: displayText, time_created: timestampMs };\n\n // Append to current assistant or create new one\n if (currentAssistantIndex !== null) {\n const message = messages[currentAssistantIndex]!;\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasTool) {\n message.parts.push(textPart);\n latestAssistantTextIndex = currentAssistantIndex;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n }\n\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [textPart],\n agent: \"codex\",\n }),\n );\n currentAssistantIndex = messages.length - 1;\n latestAssistantTextIndex = currentAssistantIndex;\n\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // ---- User message ----\n\n private convertUserMessage(\n payload: Record<string, unknown>,\n messages: Message[],\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n pendingPlan: MessagePart | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const content = payload[\"content\"];\n const text = Array.isArray(content)\n ? content\n .map((c) =>\n typeof c === \"object\" && c !== null\n ? String((c as Record<string, unknown>)[\"text\"] ?? \"\")\n : String(c ?? \"\"),\n )\n .join(\" \")\n : String(content ?? \"\");\n\n const visibleText = cleanInternalText(text);\n if (!visibleText) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Skip injected developer/system context messages\n if (isDeveloperLikeUserMessage(visibleText)) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Check for plan approval\n if (visibleText.trimStart().startsWith(PLAN_APPROVAL_PREFIX)) {\n // Finalize pending plan by attaching it to current assistant\n if (pendingPlan && currentAssistantIndex !== null) {\n messages[currentAssistantIndex]!.parts.push(pendingPlan);\n }\n pendingPlan = null;\n\n // The approval message itself is a user message\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: visibleText, time_created: timestampMs }],\n }),\n );\n\n currentAssistantIndex = null;\n latestAssistantTextIndex = null;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // Check for subagent notification\n const subagentMatch = visibleText.match(SUBAGENT_NOTIFICATION_PATTERN);\n if (subagentMatch) {\n try {\n const notifPayload = JSON.parse(subagentMatch[1]!) as Record<string, unknown>;\n const agentId = String(notifPayload[\"agent_id\"] ?? \"\");\n const nickname = String(notifPayload[\"nickname\"] ?? \"\");\n const completedText = String(notifPayload[\"completed\"] ?? \"\");\n\n // Convert user message with subagent notification to assistant message\n const textPart: MessagePart = {\n type: \"text\",\n text: completedText || `Subagent ${nickname} completed`,\n time_created: timestampMs,\n };\n\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [textPart],\n agent: \"codex\",\n subagent_id: agentId || undefined,\n nickname: nickname || undefined,\n }),\n );\n\n currentAssistantIndex = null;\n latestAssistantTextIndex = null;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n } catch {\n // Not valid JSON, treat as normal user message\n }\n }\n\n // Normal user message\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: visibleText, time_created: timestampMs }],\n }),\n );\n\n currentAssistantIndex = null;\n latestAssistantTextIndex = null;\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan };\n }\n\n // ---- Reasoning ----\n\n private convertReasoning(\n payload: Record<string, unknown>,\n messages: Message[],\n timestampMs: number,\n currentAssistantIndex: number | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const summary = payload[\"summary\"];\n if (!Array.isArray(summary)) {\n return { currentAssistantIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n const texts: string[] = [];\n for (const item of summary) {\n if (typeof item === \"object\" && item !== null) {\n const ci = item as Record<string, unknown>;\n if (String(ci[\"type\"] ?? \"\") === \"summary_text\") {\n const text = String(ci[\"text\"] ?? \"\");\n if (text.trim()) texts.push(text);\n }\n }\n }\n\n if (texts.length === 0) {\n return { currentAssistantIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n const reasoningText = texts.join(\"\\n\");\n const part: MessagePart = { type: \"reasoning\", text: reasoningText, time_created: timestampMs };\n\n if (currentAssistantIndex !== null) {\n const message = messages[currentAssistantIndex]!;\n const hasText = message.parts.some((p) => p.type === \"text\");\n const hasTool = message.parts.some((p) => p.type === \"tool\");\n if (!hasText && !hasTool) {\n message.parts.push(part);\n return { currentAssistantIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n }\n\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [part],\n agent: \"codex\",\n }),\n );\n\n return {\n currentAssistantIndex: messages.length - 1,\n latestAssistantTextIndex: null,\n pendingPlan: null,\n };\n }\n\n // ---- Function call ----\n\n private convertFunctionCall(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan: null };\n }\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 arguments: arguments_,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n // Attach to latest assistant text message\n const targetIndex = latestAssistantTextIndex ?? currentAssistantIndex;\n if (targetIndex !== null) {\n const message = messages[targetIndex]!;\n const partIndex = message.parts.length;\n message.parts.push(toolPart);\n message.mode = \"tool\";\n if (callId) {\n pendingToolCalls.set(callId, [targetIndex, partIndex]);\n }\n return {\n currentAssistantIndex: targetIndex,\n latestAssistantTextIndex: targetIndex,\n pendingPlan: null,\n };\n }\n\n // Fallback: create new assistant message for tool\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [toolPart],\n agent: \"codex\",\n mode: \"tool\",\n }),\n );\n const newIndex = messages.length - 1;\n if (callId) {\n pendingToolCalls.set(callId, [newIndex, 0]);\n }\n\n return { currentAssistantIndex: newIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n // ---- Function call output ----\n\n private convertFunctionCallOutput(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n if (!callId) return;\n\n const location = pendingToolCalls.get(callId);\n if (!location) return;\n\n const outputText = cleanInternalText(String(payload[\"output\"] ?? \"\"));\n const outputParts: MessagePart[] = outputText\n ? [{ type: \"text\", text: outputText, time_created: timestampMs }]\n : [];\n\n const [msgIndex, partIndex] = location;\n const state =\n messages[msgIndex]!.parts[partIndex]!.state ??\n (messages[msgIndex]!.parts[partIndex]!.state = {});\n\n if (outputParts.length > 0) {\n state.output = [...outputParts];\n state.status = \"completed\";\n }\n }\n\n // ---- Custom tool call ----\n\n private convertCustomToolCall(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n currentAssistantIndex: number | null,\n latestAssistantTextIndex: number | null,\n ): {\n currentAssistantIndex: number | null;\n latestAssistantTextIndex: number | null;\n pendingPlan: MessagePart | null;\n } {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) {\n return { currentAssistantIndex, latestAssistantTextIndex, pendingPlan: null };\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 arguments: normalizedInput,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n // Attach to latest assistant text message\n const targetIndex = latestAssistantTextIndex ?? currentAssistantIndex;\n if (targetIndex !== null) {\n const message = messages[targetIndex]!;\n const partIndex = message.parts.length;\n message.parts.push(toolPart);\n message.mode = \"tool\";\n if (callId) {\n pendingToolCalls.set(callId, [targetIndex, partIndex]);\n }\n return {\n currentAssistantIndex: targetIndex,\n latestAssistantTextIndex: targetIndex,\n pendingPlan: null,\n };\n }\n\n // Fallback: create new assistant message\n messages.push(\n this.buildMessage({\n messageId: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [toolPart],\n agent: \"codex\",\n mode: \"tool\",\n }),\n );\n const newIndex = messages.length - 1;\n if (callId) {\n pendingToolCalls.set(callId, [newIndex, 0]);\n }\n\n return { currentAssistantIndex: newIndex, latestAssistantTextIndex: null, pendingPlan: null };\n }\n\n // ---- Custom tool call output ----\n\n private convertCustomToolCallOutput(\n payload: Record<string, unknown>,\n messages: Message[],\n pendingToolCalls: Map<string, [number, number]>,\n timestampMs: number,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n if (!callId) return;\n\n const location = pendingToolCalls.get(callId);\n if (!location) return;\n\n const outputText = cleanInternalText(String(payload[\"output\"] ?? \"\"));\n const outputParts: MessagePart[] = outputText\n ? [{ type: \"text\", text: outputText, time_created: timestampMs }]\n : [];\n\n const [msgIndex, partIndex] = location;\n const state =\n messages[msgIndex]!.parts[partIndex]!.state ??\n (messages[msgIndex]!.parts[partIndex]!.state = {});\n\n if (outputParts.length > 0) {\n state.output = [...outputParts];\n state.status = \"completed\";\n }\n }\n\n // ---- Message builder ----\n\n private buildMessage(opts: {\n messageId: string;\n role: string;\n timestampMs: number;\n parts: MessagePart[];\n agent?: string;\n mode?: string;\n model?: string | null;\n provider?: string | null;\n tokens?: Record<string, unknown>;\n cost?: number;\n subagent_id?: string;\n nickname?: string;\n }): Message {\n return {\n id: opts.messageId,\n role: opts.role as Message[\"role\"],\n agent: opts.agent ?? null,\n time_created: opts.timestampMs,\n mode: opts.mode ?? null,\n model: opts.model ?? null,\n provider: opts.provider ?? null,\n tokens: opts.tokens ? (opts.tokens as Message[\"tokens\"]) : undefined,\n cost: opts.cost ?? 0,\n parts: opts.parts,\n subagent_id: opts.subagent_id,\n nickname: opts.nickname,\n };\n }\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, normalize } from \"node:path\";\nimport {\n DatabaseSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n} from \"./base.js\";\nimport type { AgentScanOptions } from \"./base.js\";\nimport type { SessionHead, SessionData, Message, MessagePart } from \"../types/index.js\";\nimport { getCursorDataPath } from \"../discovery/paths.js\";\nimport { openDbReadOnly, isSqliteAvailable, type SQLiteDatabase } 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\";\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// 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 text = String(\n (item as Record<string, unknown>).text ?? (item as Record<string, unknown>).content ?? \"\",\n );\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\n/** Build a normalized tool state object from an action entry */\nfunction buildToolState(action: ActionEntry): MessagePart[\"state\"] {\n const state: MessagePart[\"state\"] = {};\n\n // Copy input\n if (action.input) {\n state.input = action.input;\n }\n\n // Normalize output into parts\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 state.output = outputParts.length > 0 ? outputParts : action.output;\n }\n\n // Merge any explicit state fields\n if (action.state) {\n Object.assign(state, action.state);\n }\n\n // Derive status from output shape if not set\n if (!state.status) {\n if (typeof action.output === \"object\" && action.output !== null) {\n const out = action.output as Record<string, unknown>;\n if (out.success === true) state.status = \"completed\";\n else if (out.success === false) state.status = \"error\";\n else state.status = \"completed\";\n } else if (action.output != null) {\n state.status = \"completed\";\n }\n }\n\n return state;\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 return {\n type: \"tool\",\n tool: \"bash\",\n callID: \"\",\n title: description || `bash: ${command.slice(0, 60)}`,\n state: {\n input: { command },\n output:\n typeof action.output === \"string\"\n ? [{ type: \"text\" as const, text: action.output, time_created: timestampMs }]\n : normalizeToolOutputParts(action.output, timestampMs),\n },\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 // Cache composer data from scan so getSessionData can reuse it\n private composerCache = new Map<string, ComposerData>();\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 = getCursorDataPath();\n if (!dataPath) return null;\n return join(dataPath, \"globalStorage\", \"state.vscdb\");\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 = getCursorDataPath();\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 (!statSync(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 = JSON.parse(readFileSync(wsJsonPath, \"utf-8\")) as {\n folder?: string;\n workspace?: string;\n };\n const uri = data.folder ?? data.workspace ?? \"\";\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 = JSON.parse(row.value) as unknown;\n let composers: Array<{ composerId?: string; id?: string }>;\n\n if (\n parsed !== null &&\n typeof parsed === \"object\" &&\n \"allComposers\" in (parsed as Record<string, unknown>) &&\n Array.isArray((parsed as Record<string, unknown>)[\"allComposers\"])\n ) {\n composers = (parsed as { allComposers: Array<{ composerId?: string; id?: string }> })\n .allComposers;\n } else if (Array.isArray(parsed)) {\n composers = parsed as Array<{ composerId?: string; id?: string }>;\n } else {\n continue;\n }\n\n for (const c of composers) {\n const id = c.composerId ?? c.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 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) return [];\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 const heads: SessionHead[] = [];\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 = JSON.parse(row.value) as ComposerData;\n if (!composer.id && !composer.composerId) continue;\n\n const composerId = composer.id || composer.composerId || \"\";\n const createdAt = composer.createdAt ?? 0;\n const updatedAt =\n composer.updatedAt ?? composer.lastUpdatedAt ?? composer.lastSendTime ?? createdAt;\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 totalCost =\n estimateTokenCost(composer.modelConfig?.modelName ?? composer.model, {\n input: composer.inputTokenCount ?? 0,\n output: composer.outputTokenCount ?? 0,\n }) ?? 0;\n const head = getParsedSession(\n hasFastMessages && fastMessageCount === 0 && !hasSubagents\n ? filteredSession<SessionHead>(\"no visible messages\")\n : parsedSession<SessionHead>({\n id: composerId,\n slug: `cursor/${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 if (!head) continue;\n heads.push(head);\n this.composerCache.set(composerId, composer);\n this.sessionMetaMap.set(composerId, {\n id: composerId,\n sourcePath: this.dbPath || \"\",\n });\n continue;\n }\n\n // Try to extract requestId from bubbles (like agent-dump does)\n const requestId = this.extractRequestIdFromBubbles(db, composerId);\n const sessionId = requestId || composerId;\n\n // Load actual messages to filter out empty composers\n const parsedMessages = cleanParsedMessages(\n this.loadMessagesFromBubbles(\n db,\n composerId,\n sessionId,\n composer.modelConfig?.modelName ?? composer.model ?? null,\n ),\n );\n const messages = getParsedSession(\n parsedMessages.length === 0 && !hasSubagents\n ? filteredSession<Message[]>(\"no visible messages\")\n : parsedSession(parsedMessages),\n );\n if (!messages) continue;\n const messageCount = messages.length;\n const title = this.extractTitle(composer, messages);\n\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 heads.push({\n id: sessionId,\n slug: `cursor/${sessionId}`,\n title,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: messageCount,\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 // Cache with sessionId (requestId) as key\n this.composerCache.set(sessionId, composer);\n // Also cache composerId -> sessionId mapping and directory\n this.composerCache.set(`__mapping__${composerId}`, {\n sessionId,\n } as unknown as ComposerData);\n if (directory) {\n this.composerCache.set(`__dir__${composerId}`, {\n directory,\n } as unknown as ComposerData);\n }\n\n // Store session metadata for caching\n this.sessionMetaMap.set(sessionId, {\n id: sessionId,\n sourcePath: this.dbPath || \"\",\n });\n } catch {\n // skip malformed entries\n } finally {\n processed += 1;\n options?.onProgress?.({ total: rows.length, processed, sessions: heads.length });\n }\n }\n\n perf.end(scanMarker);\n return heads;\n } catch {\n return [];\n } finally {\n db.close();\n }\n }\n\n getSessionData(sessionId: string): SessionData {\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 let resolvedSessionId = 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 resolvedSessionId = sessionId; // Keep the requestId as sessionId\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 = composer.updatedAt ?? createdAt;\n\n // Load messages from bubbles (like agent-dump does)\n const messages = this.loadMessagesFromBubbles(\n db,\n composerId,\n resolvedSessionId,\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 // Retrieve directory from cache (populated during scan) or build map on demand\n const cachedDir = this.composerCache.get(`__dir__${composerId}`);\n const directory =\n (cachedDir as unknown as { directory?: string })?.directory ??\n this.buildWorkspacePathMap().get(composerId) ??\n \"\";\n\n return {\n id: resolvedSessionId,\n title,\n slug: `cursor/${resolvedSessionId}`,\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 /** Extract requestId from bubbles for a composer (like agent-dump) */\n private extractRequestIdFromBubbles(db: SQLiteDatabase, composerId: string): string | null {\n try {\n const rows = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key LIKE ? ORDER BY key\")\n .all(`bubbleId:${composerId}:%`) as Array<{ value: string }>;\n\n for (const row of rows) {\n try {\n const bubble = JSON.parse(row.value) as BubbleData;\n if (bubble.requestId && typeof bubble.requestId === \"string\" && bubble.requestId.trim()) {\n return bubble.requestId.trim();\n }\n } catch {\n // skip malformed bubbles\n }\n }\n } catch {\n // ignore errors\n }\n return null;\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 = JSON.parse(row.value) as BubbleData;\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 /** Count messages from bubbles */\n private countMessagesFromBubbles(db: SQLiteDatabase, composerId: string): number {\n try {\n const rows = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key LIKE ?\")\n .all(`bubbleId:${composerId}:%`) as Array<{ value: string }>;\n\n let count = 0;\n for (const row of rows) {\n try {\n const bubble = JSON.parse(row.value) as BubbleData;\n // type 1 = user, type 2 = assistant\n if (bubble.type === 1 || bubble.type === 2) {\n count++;\n }\n } catch {\n // skip malformed bubbles\n }\n }\n return count;\n } catch {\n return 0;\n }\n }\n\n /** Load messages from bubbles (like agent-dump) */\n private loadMessagesFromBubbles(\n db: SQLiteDatabase,\n composerId: string,\n _sessionId: string,\n initialModelName: string | null,\n ): Message[] {\n const messages: Message[] = [];\n\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE ? ORDER BY rowid ASC\")\n .all(`bubbleId:${composerId}:%`) as Array<{ key: string; value: string }>;\n\n let activeModelName: string | null = initialModelName;\n let messageIndex = 0;\n\n for (const row of rows) {\n try {\n const bubble = JSON.parse(row.value) as BubbleData;\n if (isInternalBubble(bubble)) continue;\n const bubbleId = row.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-${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 } catch {\n // skip malformed bubbles\n }\n }\n } catch {\n // ignore errors\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: MessagePart[\"state\"] = {\n status: toolData.status === \"completed\" ? \"completed\" : \"running\",\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 if (typeof toolData.result === \"string\") {\n try {\n const parsed = JSON.parse(toolData.result);\n state.output = parsed;\n if (parsed.error || parsed.message || parsed.stderr) {\n state.error = parsed.error || parsed.message || parsed.stderr;\n state.status = \"error\";\n }\n } catch {\n state.output = toolData.result;\n }\n } else {\n state.output = toolData.result;\n }\n }\n\n // Handle plan tool specially\n if (toolName === \"create_plan\") {\n const planText =\n typeof state.input === \"object\" && state.input !== null\n ? (state.input as Record<string, unknown>).plan\n : undefined;\n return {\n type: \"plan\",\n title: \"Plan\",\n input: planText,\n approval_status: state.status === \"completed\" ? \"success\" : \"fail\",\n state,\n time_created: timestampMs,\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 try {\n return JSON.parse(row.value) as ComposerData;\n } catch {\n return null;\n }\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 try {\n return JSON.parse(row.value) as BubbleData;\n } catch {\n return null;\n }\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 as ActionEntry, 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, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport {\n FileSystemSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n ParseSessionResult,\n SessionCacheMeta,\n SessionSourceRef,\n} from \"./base.js\";\nimport type { Message, MessagePart, SessionData, SessionHead } from \"../types/index.js\";\nimport { firstExisting, resolveProviderRoots } from \"../discovery/paths.js\";\nimport { parseJsonlLines } from \"../utils/jsonl.js\";\nimport { perf } from \"../utils/perf.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { cleanInternalText, cleanParsedMessages } from \"../utils/session-normalization.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\n\nconst HEAD_INDEX_VERSION = \"pi-head-v1\";\nconst PARSER_VERSION = \"pi-parser-v1\";\n\ninterface SessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n sourceMtimeMs: number;\n headIndexVersion: string;\n parserVersion: string;\n directory: string;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\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 parseTimestampMs(value: unknown): number {\n if (typeof value === \"number\") return Number.isFinite(value) ? value : 0;\n const text = String(value ?? \"\").trim();\n if (!text) return 0;\n const ts = Date.parse(text);\n return Number.isNaN(ts) ? 0 : ts;\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 buildMessage(params: {\n id: string;\n role: Message[\"role\"];\n timestampMs: number;\n parts: MessagePart[];\n agent?: string;\n provider?: string | null;\n model?: string | null;\n tokens?: Message[\"tokens\"];\n cost?: number;\n costSource?: Message[\"cost_source\"];\n}): Message {\n return {\n id: params.id,\n role: params.role,\n agent: params.agent,\n time_created: params.timestampMs,\n provider: params.provider,\n model: params.model,\n tokens: params.tokens,\n cost: params.cost,\n cost_source: params.costSource,\n parts: params.parts,\n };\n}\n\nfunction getEntryTimestamp(entry: Record<string, unknown>): number {\n return parseTimestampMs(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 FileSystemSessionSource<SessionMeta> {\n readonly name = \"pi\";\n readonly displayName = \"Pi\";\n\n private basePath: string | null = null;\n\n private findBasePath(): string | null {\n const roots = resolveProviderRoots();\n return firstExisting(join(roots.piRoot, \"agent\", \"sessions\"), \"data/pi\");\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 scan(options?: AgentScanOptions): SessionHead[] {\n if (!this.basePath) return [];\n\n const scanMarker = perf.start(\"pi:scan\");\n const files = this.listSessionFiles(options);\n options?.onProgress?.({ total: files.length, processed: 0, sessions: 0 });\n\n const heads: SessionHead[] = [];\n let processed = 0;\n for (const file of files) {\n try {\n const head = getParsedSession(this.parseSessionHeadResult(file));\n if (head) {\n heads.push(head);\n this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, file));\n }\n } catch {\n // skip malformed files\n } finally {\n processed += 1;\n options?.onProgress?.({ total: files.length, processed, sessions: heads.length });\n }\n }\n\n perf.end(scanMarker);\n return heads;\n }\n\n listSessionSources(): SessionSourceRef[] {\n if (!this.basePath) return [];\n return this.listSessionFiles().map((file) => ({\n sessionId: extractSessionIdFromFilename(file),\n sourcePath: file,\n fingerprint: this.sourceFingerprint(file),\n }));\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n const head = getParsedSession(this.parseSessionHeadResult(sourcePath));\n if (head) {\n this.sessionMetaMap.set(head.id, this.buildSessionMeta(head, sourcePath));\n }\n return head;\n }\n\n getSessionData(sessionId: string): SessionData {\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 const cleanedMessages = cleanParsedMessages(state.messages);\n\n return {\n id: meta.id,\n title: meta.title,\n slug: `pi/${meta.id}`,\n directory: meta.directory,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: {\n message_count: cleanedMessages.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.totalCost > 0 ? \"recorded\" : undefined,\n },\n messages: cleanedMessages,\n };\n }\n\n private listSessionFiles(options?: AgentScanOptions): string[] {\n if (!this.basePath) return [];\n return this.walkJsonlFiles(this.basePath, options);\n }\n\n private walkJsonlFiles(dir: string, options?: AgentScanOptions): string[] {\n const files: string[] = [];\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...this.walkJsonlFiles(fullPath, options));\n continue;\n }\n if (!entry.isFile() || !entry.name.endsWith(\".jsonl\")) continue;\n if (!matchesScanWindow(statSync(fullPath).mtimeMs, options)) continue;\n files.push(fullPath);\n }\n } catch {\n // skip inaccessible dirs\n }\n return files;\n }\n\n private buildSessionMeta(head: SessionHead, file: string): SessionMeta {\n return {\n id: head.id,\n title: head.title,\n sourcePath: file,\n sourceFingerprint: this.sourceFingerprint(file),\n sourceMtimeMs: statSync(file).mtimeMs,\n headIndexVersion: HEAD_INDEX_VERSION,\n parserVersion: PARSER_VERSION,\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 private sourceFingerprint(file: string): string {\n const stat = statSync(file);\n return JSON.stringify([HEAD_INDEX_VERSION, PARSER_VERSION, stat.mtimeMs, stat.size]);\n }\n\n private parseSessionHeadResult(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: `pi/${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.totalCost > 0 ? \"recorded\" : undefined,\n },\n model_usage: modelUsage,\n });\n }\n\n private parsePiFile(filePath: string): ParsedPiFile {\n const records = Array.from(parseJsonlLines(readFileSync(filePath, \"utf-8\")));\n if (records.length === 0) throw new Error(\"empty file\");\n\n const header = records.find((record) => record[\"type\"] === \"session\");\n if (!header) throw new Error(\"missing session header\");\n\n const entries = records.filter((record) => record[\"type\"] !== \"session\");\n const pathEntries = buildCurrentPathEntries(entries);\n if (pathEntries.length === 0) throw new Error(\"empty session tree\");\n\n const sessionId = String(header[\"id\"] ?? extractSessionIdFromFilename(filePath)).trim();\n if (!sessionId) throw new Error(\"missing session id\");\n\n const stat = statSync(filePath);\n const directory = String(header[\"cwd\"] ?? \"\").trim() || basename(filePath, \".jsonl\");\n const createdAt = parseTimestampMs(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 modelUsage: Record<string, number>;\n } {\n const messages: Message[] = [];\n const pendingToolCalls = new Map<string, [number, number]>();\n const modelUsage: Record<string, number> = {};\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCacheCreateTokens = 0;\n let totalCost = 0;\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 = entry[\"message\"];\n if (!isObject(message)) continue;\n const result = this.convertAgentMessage(\n entry,\n message,\n timestampMs,\n pendingToolCalls,\n messages.length,\n messages,\n );\n if (!result) continue;\n if (result.message) messages.push(result.message);\n totalInputTokens += result.inputTokens;\n totalOutputTokens += result.outputTokens;\n totalCacheReadTokens += result.cacheReadTokens;\n totalCacheCreateTokens += result.cacheCreateTokens;\n totalCost += result.cost;\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) messages.push(summary);\n }\n\n return {\n messages,\n totalInputTokens,\n totalOutputTokens,\n totalCacheReadTokens,\n totalCacheCreateTokens,\n totalCost,\n modelUsage,\n };\n }\n\n private convertAgentMessage(\n entry: Record<string, unknown>,\n message: Record<string, unknown>,\n timestampMs: number,\n pendingToolCalls: Map<string, [number, number]>,\n nextMessageIndex: number,\n messages: Message[],\n ): {\n message?: Message;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreateTokens: number;\n totalTokens: number;\n cost: number;\n model: string | null;\n } | null {\n const id = String(entry[\"id\"] ?? \"\");\n const role = String(message[\"role\"] ?? \"\");\n\n if (role === \"user\") {\n const parts = normalizeTextParts(message[\"content\"], timestampMs);\n if (parts.length === 0) return null;\n return this.emptyUsageResult(buildMessage({ id, role: \"user\", timestampMs, parts }));\n }\n\n if (role === \"assistant\") {\n const parts = this.normalizeAssistantParts(\n message[\"content\"],\n timestampMs,\n pendingToolCalls,\n nextMessageIndex,\n );\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 cost = usage.cost ?? estimateTokenCost(model, usage.tokens) ?? 0;\n return {\n message: buildMessage({\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: cost > 0 ? \"recorded\" : undefined,\n }),\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n cacheReadTokens: usage.cacheReadTokens,\n cacheCreateTokens: usage.cacheCreateTokens,\n totalTokens: usage.totalTokens,\n cost,\n model,\n };\n }\n\n if (role === \"toolResult\") {\n this.attachToolResult(message, timestampMs, pendingToolCalls, messages);\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(buildMessage({ 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 buildMessage({\n id,\n role: \"assistant\",\n agent: \"pi\",\n timestampMs,\n parts: [{ type: \"text\", text: summary, time_created: timestampMs }],\n }),\n );\n }\n\n return null;\n }\n\n private normalizeAssistantParts(\n content: unknown,\n timestampMs: number,\n pendingToolCalls: Map<string, [number, number]>,\n messageIndex: number,\n ): 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 if (callId) pendingToolCalls.set(callId, [messageIndex, parts.length - 1]);\n }\n }\n\n return parts;\n }\n\n private attachToolResult(\n message: Record<string, unknown>,\n timestampMs: number,\n pendingToolCalls: Map<string, [number, number]>,\n messages: Message[],\n ): void {\n const callId = String(message[\"toolCallId\"] ?? \"\").trim();\n const output = normalizeTextParts(message[\"content\"], timestampMs);\n const location = callId ? pendingToolCalls.get(callId) : undefined;\n if (!location) return;\n\n const [messageIndex, partIndex] = location;\n const target = messages[messageIndex]?.parts[partIndex];\n if (!target?.state) return;\n target.state.output = output;\n target.state.status = message[\"isError\"] === true ? \"error\" : \"completed\";\n target.state.metadata = message[\"details\"];\n pendingToolCalls.delete(callId);\n }\n\n private convertBashExecution(\n id: string,\n message: Record<string, unknown>,\n timestampMs: number,\n ): Message {\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 buildMessage({\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(entry: Record<string, unknown>, timestampMs: number): Message | 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 buildMessage({\n id: String(entry[\"id\"] ?? \"\"),\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 = isObject(raw) ? raw : {};\n const inputTokens = Number(usage[\"input\"] ?? 0);\n const outputTokens = Number(usage[\"output\"] ?? 0);\n const cacheReadTokens = Number(usage[\"cacheRead\"] ?? 0);\n const cacheCreateTokens = Number(usage[\"cacheWrite\"] ?? 0);\n const totalTokens = Number(\n usage[\"totalTokens\"] ?? inputTokens + outputTokens + cacheReadTokens + cacheCreateTokens,\n );\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?: Message): {\n message?: Message;\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreateTokens: number;\n totalTokens: number;\n cost: number;\n model: string | null;\n } {\n return {\n message,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreateTokens: 0,\n totalTokens: 0,\n cost: 0,\n model: null,\n };\n }\n}\n","import { registerAgent } from \"./registry.js\";\nimport { ClaudeCodeAgent } from \"./claudecode.js\";\nimport { OpenCodeAgent } from \"./opencode.js\";\nimport { KimiAgent } from \"./kimi.js\";\nimport { CodexAgent } from \"./codex.js\";\nimport { CursorAgent } from \"./cursor.js\";\nimport { PiAgent } from \"./pi.js\";\n\nregisterAgent({\n name: \"claudecode\",\n displayName: \"Claude Code\",\n icon: \"/icon/agent/claudecode.svg\",\n create: () => new ClaudeCodeAgent(),\n});\n\nregisterAgent({\n name: \"opencode\",\n displayName: \"OpenCode\",\n icon: \"/icon/agent/opencode.svg\",\n create: () => new OpenCodeAgent(),\n});\n\nregisterAgent({\n name: \"kimi\",\n displayName: \"Kimi-Cli\",\n icon: \"/icon/agent/kimi.svg\",\n create: () => new KimiAgent(),\n});\n\nregisterAgent({\n name: \"codex\",\n displayName: \"Codex\",\n icon: \"/icon/agent/codex.svg\",\n create: () => new CodexAgent(),\n});\n\nregisterAgent({\n name: \"pi\",\n displayName: \"Pi\",\n icon: \"/icon/agent/pi.svg\",\n create: () => new PiAgent(),\n});\n\nregisterAgent({\n name: \"cursor\",\n displayName: \"Cursor\",\n icon: \"/icon/agent/cursor.svg\",\n create: () => new CursorAgent(),\n});\n","import { availableParallelism } from \"node:os\";\nimport { Worker } from \"node:worker_threads\";\nimport type { SessionHead, SmartTag } from \"../types/index.js\";\nimport type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport { createRegisteredAgents } from \"../agents/index.js\";\nimport { filterSessionsByProjectScope } from \"../projects/index.js\";\nimport { classifySessionTags, getSmartTagSourceTimestamp, perf } from \"../utils/index.js\";\nimport {\n loadCachedSessions,\n markAgentCacheInitialized,\n saveCachedSessionChanges,\n saveCachedSessions,\n} from \"./cache.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 ScanResult {\n sessions: SessionHead[];\n byAgent: Record<string, SessionHead[]>;\n agents: BaseAgent[];\n timings?: Record<string, AgentScanTiming>;\n cacheTimestamps?: Record<string, number>;\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 if (options.from != null) {\n result = result.filter((s) => (s.time_updated ?? s.time_created) >= options.from!);\n }\n\n if (options.to != null) {\n result = result.filter((s) => (s.time_updated ?? s.time_created) <= options.to!);\n }\n\n return result;\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\ninterface AgentScanResult {\n agent: BaseAgent;\n heads: SessionHead[];\n fromCache?: boolean;\n refreshed?: boolean;\n timing?: AgentScanTiming;\n cacheTimestamp?: number;\n}\n\ninterface SmartTagWorkerResult {\n id: string;\n tags?: SmartTag[];\n sourceUpdatedAt?: number;\n error?: string;\n}\n\nfunction saveCachedSessionDiff(\n agent: BaseAgent,\n cachedSessions: SessionHead[],\n updatedSessions: SessionHead[],\n changedIds: string[] = [],\n): void {\n const diff = computeSessionDiff(cachedSessions, updatedSessions, changedIds, sessionSignature);\n saveCachedSessionChanges(\n agent.name,\n diff.changes,\n diff.removedSessionIds,\n buildAgentCacheMeta(agent),\n );\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\nfunction ensureSessionTagsSync(\n agent: BaseAgent,\n sessions: SessionHead[],\n): { sessions: SessionHead[]; changed: boolean } {\n let changed = false;\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 (currentTags && session.smart_tags_source_updated_at === sourceUpdatedAt) {\n return session;\n }\n\n try {\n const data = agent.getSessionData(session.id);\n const tags = classifySessionTags(data);\n changed = true;\n return {\n ...session,\n smart_tags: tags,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n };\n } catch {\n return session;\n }\n });\n\n return { sessions: tagged, changed };\n}\n\nasync function classifySessionTagsInWorker(\n workerUrl: URL | string,\n agentName: string,\n sessionIds: string[],\n meta: Record<string, SessionCacheMeta>,\n): Promise<SmartTagWorkerResult[]> {\n return new Promise((resolveWorker, rejectWorker) => {\n const worker = new Worker(workerUrl, {\n workerData: { agentName, sessionIds, meta },\n });\n worker.once(\"message\", (results: SmartTagWorkerResult[]) => resolveWorker(results));\n worker.once(\"error\", rejectWorker);\n worker.once(\"exit\", (code) => {\n if (code !== 0) {\n rejectWorker(new Error(`Smart tag worker exited with code ${code}`));\n }\n });\n });\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 !currentTags || session.smart_tags_source_updated_at !== sourceUpdatedAt;\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 };\n }),\n };\n } catch {\n return ensureSessionTagsSync(agent, sessions);\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 const metaMap = new Map<string, SessionCacheMeta>();\n for (const [id, meta] of Object.entries(cached.meta)) {\n metaMap.set(id, meta);\n }\n agent.setSessionMetaMap(metaMap);\n\n if (options.cacheOnly) {\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: cached.sessions.length,\n });\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: cached.sessions.length });\n const t3 = performance.now();\n const cachedWithIdentity = attachMissingProjectIdentities(cached.sessions);\n timing.identity = performance.now() - t3;\n\n const filtered = filterSessions(cachedWithIdentity, options);\n timing.total = performance.now() - agentStart;\n return {\n agent,\n heads: filtered,\n fromCache: true,\n timing,\n cacheTimestamp: cached.timestamp,\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 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 updatedSessions = await Promise.resolve(\n agent.incrementalScan(cached.sessions, checkResult.changedIds || []),\n );\n timing.scan = performance.now() - t2;\n\n const t3 = performance.now();\n const sessionsWithIdentity = attachMissingProjectIdentities(updatedSessions);\n timing.identity = performance.now() - t3;\n\n const t4 = performance.now();\n const tagged =\n options.includeSmartTags === false\n ? { sessions: sessionsWithIdentity, changed: false }\n : await ensureSessionTags(agent, sessionsWithIdentity, options.smartTagWorkerUrl);\n timing.tags = performance.now() - t4;\n\n if (options.writeCache !== false) {\n saveCachedSessionDiff(\n agent,\n cached.sessions,\n tagged.sessions,\n checkResult.changedIds ?? [],\n );\n }\n\n onProgress?.({\n agent: agent.name,\n phase: \"complete\",\n newCount: tagged.sessions.length,\n });\n\n const filtered = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return {\n agent,\n heads: filtered,\n fromCache: true,\n refreshed: true,\n timing,\n cacheTimestamp: checkResult.timestamp,\n };\n }\n\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: cached.sessions.length });\n\n const t3 = performance.now();\n const cachedWithIdentity = attachMissingProjectIdentities(cached.sessions);\n timing.identity = performance.now() - t3;\n\n const t4 = performance.now();\n const tagged =\n options.includeSmartTags === false\n ? { sessions: cachedWithIdentity, changed: false }\n : await ensureSessionTags(agent, cachedWithIdentity, options.smartTagWorkerUrl);\n timing.tags = performance.now() - t4;\n\n if (tagged.changed && options.writeCache !== false) {\n saveCachedSessionDiff(agent, cached.sessions, tagged.sessions);\n }\n\n const filtered = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return {\n agent,\n heads: filtered,\n fromCache: true,\n timing,\n cacheTimestamp: cached.timestamp,\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 heads = agent.scan({\n from: options.from,\n to: options.to,\n fast: options.fast,\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 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 // 保存到缓存\n if (options.writeCache !== false && options.from == null && options.to == null) {\n saveCachedSessions(agent.name, tagged.sessions, meta);\n markAgentCacheInitialized(agent.name);\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 { agent, heads: filtered, fromCache: false, timing };\n } catch (err) {\n console.error(`Error scanning ${agent.name}:`, err);\n return { agent, heads: [], fromCache: false };\n }\n}\n\n/**\n * 主扫描函数 - 并行扫描所有 Agent\n */\nexport async function scanSessions(\n options: ScanOptions = {},\n onProgress?: (progress: ScanProgress) => void,\n): Promise<ScanResult> {\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\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) => scanAgentSmart(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 byAgent[result.agent.name] = result.heads;\n allSessions.push(...result.heads);\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 };\n}\n\n/**\n * 异步扫描(带增量更新支持)\n */\nexport async function scanSessionsAsync(\n options: ScanOptions = {},\n onProgress?: (progress: ScanProgress) => void,\n): Promise<ScanResult> {\n return scanSessions(options, onProgress);\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 type { ProjectGroup, ProjectIdentity, SessionHead } from \"../types/index.js\";\n\nfunction getAgentName(session: SessionHead): string {\n return session.slug.split(\"/\")[0]?.toLowerCase() || \"unknown\";\n}\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 for (const session of sessions) {\n const identity = session.project_identity;\n if (!identity) continue;\n const activity = session.time_updated ?? session.time_created;\n const groupKey = `${identity.kind}:${identity.key}`;\n const current = groups.get(groupKey);\n if (current) {\n current.sources.add(getAgentName(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([getAgentName(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 * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ProjectIdentity, ProjectIdentityKind } from \"../types/index.js\";\nimport { fallbackDisplayName } from \"./display-name.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\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\nexport function normalizeGitRemote(url: string): string | null {\n if (!url) return null;\n let value = url.trim().replace(/\\.git$/, \"\");\n const sshMatch = value.match(/^[^@]+@([^:]+):(.+)$/);\n if (sshMatch) value = `${sshMatch[1]}/${sshMatch[2]}`;\n value = value.replace(/^[a-z]+:\\/\\/(?:[^@/]*@)?/i, \"\");\n if (!value.includes(\"/\")) return null;\n return value.toLowerCase();\n}\n\nexport function computeIdentity(cwd: string | null | undefined, fs: IdentityFs): ProjectIdentity {\n if (!cwd) return loose();\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)) return loose();\n if (\n homePathOps === pathOps &&\n LOOSE_HOME_DIRS.some((dir) => absoluteCwd === pathOps.join(home, dir))\n ) {\n return loose();\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 return {\n kind: \"git_remote\",\n key: normalized,\n displayName: deriveDisplayName({ kind: \"git_remote\", key: normalized, gitRoot, fs }),\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 return {\n kind: \"git_common_dir\",\n key,\n displayName: deriveDisplayName({ kind: \"git_common_dir\", key, gitRoot, fs }),\n };\n }\n }\n }\n\n const manifestDir = findManifestDir(absoluteCwd, fs, pathOps);\n if (manifestDir) {\n return {\n kind: \"manifest_path\",\n key: manifestDir,\n displayName: deriveDisplayName({ kind: \"manifest_path\", key: manifestDir, fs }),\n };\n }\n\n if (homePathOps === pathOps) {\n const synthetic = synthesizeCodexScratchIdentity(absoluteCwd, home, pathOps);\n if (synthetic) return synthetic;\n }\n\n return {\n kind: \"path\",\n key: absoluteCwd,\n displayName: fallbackDisplayName(absoluteCwd),\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(\"\\\\\\\\\") || input.includes(\"\\\\\")) {\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 { resolve, sep } from \"node:path\";\nimport type { SessionHead } from \"../types/index.js\";\nimport { computeIdentity, type IdentityFs } from \"./identity.js\";\nimport { realFs } from \"./fs.js\";\n\nexport interface ProjectScopeMatcher {\n identityKey: string;\n path: string;\n}\n\nexport function createProjectScopeMatcher(\n queryPath: string,\n fs: IdentityFs = realFs,\n): ProjectScopeMatcher {\n return {\n identityKey: computeIdentity(queryPath, fs).key,\n path: normalizeScopePath(queryPath),\n };\n}\n\nexport function matchesProjectScope(session: SessionHead, scope: ProjectScopeMatcher): boolean {\n if (!session.directory) return false;\n if (session.project_identity?.key === scope.identityKey) return true;\n return isPathScopeMatch(scope.path, session.directory);\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 = normalizeScopePath(sessionPath);\n return (\n session === queryPath ||\n session.startsWith(queryPath + \"/\") ||\n queryPath.startsWith(session + \"/\")\n );\n}\n\nfunction normalizeScopePath(path: string): string {\n return resolve(path).replaceAll(sep, \"/\");\n}\n","import type { MessagePart, SessionData, SmartTag } from \"../types/index.js\";\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<SessionData, \"time_created\" | \"time_updated\">,\n): number {\n return session.time_updated ?? session.time_created;\n}\n\nexport function classifySessionTags(session: Pick<SessionData, \"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?.arguments) || 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 typeof part.text === \"string\" ? part.text : \"\";\n}\n\nfunction stringifyToolPayload(part: MessagePart): string {\n return [\n part.tool,\n part.title,\n valueToText(part.input),\n valueToText(part.output),\n valueToText(part.state),\n ]\n .filter(Boolean)\n .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","import type {\n FileActivityKind,\n Message,\n MessagePart,\n SessionFileActivity,\n SessionFileActivityOccurrence,\n} from \"../types/index.js\";\n\ninterface CodexPatchEntry {\n type: string;\n path: string;\n oldPath: string;\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: MessagePart) {\n if (typeof part.title === \"string\" && part.title.trim()) {\n return part.title.trim().replace(/^tool:\\s*/i, \"\");\n }\n if (typeof part.tool === \"string\" && part.tool.trim()) return part.tool.trim();\n return \"tool\";\n}\n\nfunction normalizeToolName(part: MessagePart) {\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: MessagePart) {\n return part.state?.arguments ?? part.state?.input ?? part.input ?? null;\n}\n\nfunction classifyToolKind(part: MessagePart): 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 if (!type) return null;\n return {\n type,\n path: toStringValue(record.path),\n oldPath: toStringValue(record.old_path),\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 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 const kind = classifyToolKind(part);\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.latest_time = Math.max(current.latest_time, occurrence.time);\n continue;\n }\n\n grouped.set(key, {\n agent_name: agentName,\n session_id: sessionId,\n project_identity_key: projectIdentityKey,\n path: occurrence.path,\n kind: occurrence.kind,\n count: 1,\n latest_time: occurrence.time,\n });\n }\n\n return [...grouped.values()].sort((a, b) => {\n if (b.latest_time !== a.latest_time) return b.latest_time - a.latest_time;\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 infrastructure: cache paths, shared query helpers, and the FTS\n * integrity-check guard. Lower-level than schema.ts — no DB handles here.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { DatabaseRow, 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 SessionCacheMeta {\n id: string;\n sourcePath: string;\n [key: string]: unknown;\n}\n\nexport interface SessionHeadChange {\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\n// One-shot per-process FTS integrity check guard; reset by clearCache.\nlet ftsIntegrityCheckedPath: string | null = null;\n\nexport function getFtsIntegrityCheckedPath(): string | null {\n return ftsIntegrityCheckedPath;\n}\n\nexport function setFtsIntegrityCheckedPath(path: string | null): void {\n ftsIntegrityCheckedPath = 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 * Cache persistence: load / save / clear / info / initialization tracking.\n */\nimport { existsSync, rmSync, unlinkSync } from \"node:fs\";\nimport type { SessionData, SessionHead } from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport { tableExists } from \"../../utils/sqlite.js\";\nimport {\n getCachePath,\n getLegacyCachePath,\n hasCacheStorage,\n setFtsIntegrityCheckedPath,\n type ScalarRow,\n type SessionCacheMeta,\n type SessionHeadChange,\n} from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./schema.js\";\nimport {\n messageFromCachedRow,\n prepareUpsertCachedSession,\n prepareUpsertProjectSession,\n prepareUpsertSession,\n sessionFromRow,\n sourcePathFromMeta,\n upsertSessionRow,\n writeProjectSessionRow,\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\";\nexport interface CachedResult {\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n timestamp: number;\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\nexport function loadCachedSessions(agentName: string): CachedResult | null {\n if (!hasCacheStorage()) {\n return null;\n }\n\n return withCacheDb((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\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n time_created,\n time_updated,\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 meta_json\n FROM sessions\n WHERE agent_name = ?\n ORDER BY sort_index, activity_time DESC\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 isAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): boolean {\n if (!hasCacheStorage()) {\n return false;\n }\n\n return (\n 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 }) ?? false\n );\n}\n\nexport function markAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): void {\n withCacheDb((db) => {\n const now = Date.now();\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 index_version = excluded.index_version,\n last_sync_at = excluded.last_sync_at\n `,\n ).run(agentName, now, indexVersion, now);\n });\n}\n\nexport function loadCachedSessionData(agentName: string, sessionId: string): SessionData | null {\n if (!hasCacheStorage()) {\n return null;\n }\n\n return withCacheDbReadOnly((db) => {\n const row = db\n .prepare(\n `\n SELECT\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n time_created,\n time_updated,\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 meta_json\n FROM sessions\n WHERE agent_name = ? AND session_id = ?\n `,\n )\n .get(agentName, sessionId) as SessionRow | undefined;\n\n if (!row) {\n return null;\n }\n\n const messageRows = 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 subagent_id,\n nickname\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n ORDER BY message_index\n `,\n )\n .all(agentName, sessionId) as CachedMessageRow[];\n\n const head = sessionFromRow(row);\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 ...head,\n messages: messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n file_activity: fileActivityRows.map((activityRow) => fileActivityFromRow(activityRow)),\n };\n });\n}\n\nexport function saveCachedSessions(\n agentName: string,\n sessions: SessionHead[],\n meta: Record<string, SessionCacheMeta> = {},\n): void {\n withCacheDb((db) => {\n const deleteAgent = db.prepare(\"DELETE FROM agent_cache WHERE agent_name = ?\");\n const deleteLegacySessions = db.prepare(\"DELETE FROM cached_sessions WHERE agent_name = ?\");\n const deleteSession = db.prepare(\n \"DELETE FROM sessions WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteSearchDocument = 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 = ?\",\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 deleteProjectSession = db.prepare(\n \"DELETE FROM project_sessions WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteProjectSessions = db.prepare(\"DELETE FROM project_sessions WHERE agent_name = ?\");\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 upsertCachedSession = prepareUpsertCachedSession(db);\n const upsertSession = prepareUpsertSession(db);\n const upsertProjectSession = prepareUpsertProjectSession(db);\n\n const write = db.transaction(() => {\n const timestamp = Date.now();\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 deleteAgent.run(agentName);\n deleteLegacySessions.run(agentName);\n deleteProjectSessions.run(agentName);\n upsertAgent.run(agentName, timestamp);\n\n for (const row of existingSessionIds) {\n const sessionId = String(row.session_id);\n if (!sessionIds.has(sessionId)) {\n deleteSearchDocument.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId);\n deleteMessages.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteProjectSession.run(agentName, sessionId);\n deleteSession.run(agentName, sessionId);\n }\n }\n\n sessions.forEach((session, index) => {\n const identity = session.project_identity ?? computeIdentity(session.directory, realFs);\n const sessionMeta = meta[session.id];\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertCachedSession.run(agentName, session.id, JSON.stringify(session), metaJson);\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n index,\n sourcePathFromMeta(sessionMeta),\n );\n writeProjectSessionRow(upsertProjectSession, agentName, session, identity);\n });\n });\n\n write();\n deleteLegacyCacheFile();\n });\n}\n\nexport function saveCachedSessionChanges(\n agentName: string,\n changes: SessionHeadChange[],\n removedSessionIds: string[],\n meta: Record<string, SessionCacheMeta> = {},\n): void {\n if (changes.length === 0 && removedSessionIds.length === 0) {\n return;\n }\n\n withCacheDb((db) => {\n const deleteLegacySession = db.prepare(\n \"DELETE FROM cached_sessions WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteSession = db.prepare(\n \"DELETE FROM sessions WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteSearchDocument = 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 = ?\",\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 deleteProjectSession = db.prepare(\n \"DELETE FROM project_sessions 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 upsertCachedSession = prepareUpsertCachedSession(db);\n const upsertSession = prepareUpsertSession(db);\n const upsertProjectSession = prepareUpsertProjectSession(db);\n\n const write = db.transaction(() => {\n upsertAgent.run(agentName, Date.now());\n\n for (const sessionId of new Set(removedSessionIds)) {\n deleteLegacySession.run(agentName, sessionId);\n deleteSearchDocument.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId);\n deleteMessages.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteProjectSession.run(agentName, sessionId);\n deleteSession.run(agentName, sessionId);\n }\n\n for (const { session, sortIndex } of changes) {\n const identity = session.project_identity ?? computeIdentity(session.directory, realFs);\n const sessionMeta = meta[session.id];\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertCachedSession.run(agentName, session.id, JSON.stringify(session), metaJson);\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n sortIndex,\n sourcePathFromMeta(sessionMeta),\n );\n writeProjectSessionRow(upsertProjectSession, agentName, session, identity);\n }\n });\n\n write();\n deleteLegacyCacheFile();\n });\n}\n\nexport function clearCache(): void {\n setFtsIntegrityCheckedPath(null);\n if (!hasCacheStorage()) {\n deleteLegacyCacheFile();\n return;\n }\n\n withCacheDb((db) => {\n db.exec(`\n DELETE FROM agent_cache;\n DELETE FROM cache_initialization;\n DELETE FROM cached_sessions;\n DELETE FROM session_documents;\n DELETE FROM session_file_activity;\n DELETE FROM message_tools;\n DELETE FROM messages;\n DELETE FROM sessions;\n DELETE FROM project_sessions;\n `);\n });\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.prepare(\"SELECT COUNT(*) AS value FROM sessions\").get() as\n | ScalarRow\n | 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","/**\n * Structured message storage: row ↔ domain mapping, prepared-statement\n * binders, and message-text builders shared by sessions/search/file-activity.\n */\nimport type {\n Message,\n MessagePart,\n ProjectIdentity,\n ProjectIdentityKind,\n SessionData,\n SessionFileActivity,\n SessionHead,\n} from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { SessionCacheMeta, SQLiteStatement } from \"./db.js\";\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 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 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 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 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 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 prepareUpsertCachedSession(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT INTO cached_sessions(agent_name, session_id, session_json, meta_json)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n session_json = excluded.session_json,\n meta_json = excluded.meta_json\n `);\n}\n\nexport function prepareUpsertProjectSession(db: SQLiteDatabase): SQLiteStatement {\n return 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\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 project_identity_kind,\n project_identity_key,\n project_display_name,\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 meta_json\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 = excluded.source_path,\n directory = excluded.directory,\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 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 meta_json = excluded.meta_json\n `);\n}\n\nexport function prepareUpsertIndexedSession(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 project_identity_kind,\n project_identity_key,\n project_display_name,\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 meta_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\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 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 `);\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 = session.project_identity ?? computeIdentity(session.directory, realFs);\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 identity.kind,\n identity.key,\n identity.displayName,\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 metaJson,\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.agent_name,\n activity.session_id,\n activity.project_identity_key,\n activity.path,\n activity.kind,\n activity.count,\n activity.latest_time,\n );\n }\n}\n\nexport function writeProjectSessionRow(\n statement: SQLiteStatement,\n agentName: string,\n session: SessionHead,\n identity: ProjectIdentity,\n): void {\n statement.run(\n agentName,\n session.id,\n identity.kind,\n identity.key,\n identity.displayName,\n session.directory,\n session.time_updated ?? session.time_created,\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.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\n return session;\n}\n\nexport function messageFromBackfillRow(row: MessageBackfillRow): Message {\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 parts: JSON.parse(String(row.parts_json ?? \"[]\")) as MessagePart[],\n subagent_id: row.subagent_id ?? undefined,\n nickname: row.nickname ?? undefined,\n };\n}\n\nexport function messageFromCachedRow(row: CachedMessageRow): Message {\n const message = messageFromBackfillRow(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 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: MessagePart): Record<string, unknown> {\n const state =\n part.state == null\n ? undefined\n : compactRecord({\n status: part.state.status,\n error: part.state.error,\n metadata: part.state.metadata,\n });\n\n return compactRecord({\n type: part.type,\n tool: part.tool,\n title: part.title,\n nickname: part.nickname,\n callID: part.callID,\n approval_status: part.approval_status,\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 appendPlainText(part.title, chunks);\n appendPlainText(part.nickname, chunks);\n appendPlainText(part.tool, chunks);\n appendPlainText(part.text, chunks);\n appendPlainText(part.input, chunks);\n appendPlainText(part.output, chunks);\n appendPlainText(part.state, chunks);\n }\n\n return chunks.join(\"\\n\");\n}\n\nexport function normalizeMessages(session: SessionData): StructuredMessageRecord[] {\n return session.messages.map((message, index) => {\n const toolMetadata = message.parts\n .filter((part) => 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","/**\n * Schema, migrations, and the read/write DB handle factory. withCacheDb runs\n * ensureSchema on every write open, so all feature modules inherit migration.\n */\nimport type { ProjectIdentityKind, SessionHead } from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport {\n columnExists,\n getUserVersion,\n openDb,\n openDbReadOnly,\n runSchemaMigrations,\n setUserVersion,\n tableExists,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../../utils/sqlite.js\";\nimport {\n getCachePath,\n getFtsIntegrityCheckedPath,\n setFtsIntegrityCheckedPath,\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\";\n\nexport const CACHE_SCHEMA_VERSION = 13;\nexport interface IndexedSearchRow extends DatabaseRow {\n session_id?: string;\n content_hash?: string;\n}\n\nexport interface MessageCountRow extends DatabaseRow {\n session_id?: string;\n value?: number;\n}\n\nexport interface MessageToolBackfillRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_index?: number;\n tool_metadata_json?: string | null;\n}\n\nexport interface 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\nexport interface 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\nexport interface ProjectIdentityRefreshRow extends DatabaseRow {\n id?: number;\n agent_name?: string;\n session_id?: string;\n directory?: string;\n}\n\nexport function withCacheDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n const cachePath = getCachePath();\n const db = openDb(cachePath);\n if (!db) return null;\n\n try {\n ensureSchema(db, cachePath);\n return fn(db);\n } catch {\n return null;\n } finally {\n db.close();\n }\n}\n\nexport function withCacheDbReadOnly<T>(fn: (db: SQLiteDatabase) => T): T | null {\n const db = openDbReadOnly(getCachePath());\n if (!db) return null;\n\n try {\n return fn(db);\n } catch {\n return null;\n } finally {\n db.close();\n }\n}\n\nexport function 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}\n\nexport function 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 project_identity_kind TEXT NOT NULL,\n project_identity_key TEXT NOT NULL,\n project_display_name TEXT NOT NULL,\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 meta_json TEXT,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_sessions_agent_activity\n ON sessions(agent_name, activity_time);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_project\n ON sessions(project_identity_kind, project_identity_key, activity_time);\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 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\n createMessageToolTables(db);\n}\n\nexport function 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\nexport function createMessageSearchTables(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages\")) {\n createSessionTables(db);\n }\n\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(\n content_text,\n content='messages',\n content_rowid='rowid'\n );\n `);\n\n createMessageSearchTriggers(db);\n}\n\nexport function createMessageSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN\n INSERT INTO messages_fts(rowid, content_text)\n VALUES (new.rowid, new.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN\n INSERT INTO messages_fts(messages_fts, rowid, content_text)\n VALUES ('delete', old.rowid, old.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS messages_au AFTER UPDATE ON messages BEGIN\n INSERT INTO messages_fts(messages_fts, rowid, content_text)\n VALUES ('delete', old.rowid, old.content_text);\n INSERT INTO messages_fts(rowid, content_text)\n VALUES (new.rowid, new.content_text);\n END;\n `);\n}\n\nexport function dropMessageSearchTriggers(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 `);\n}\n\nexport function 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\nexport function 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\nexport function 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\nexport function 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\nexport function 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 slug TEXT NOT NULL,\n title TEXT NOT NULL,\n directory TEXT NOT NULL,\n time_created INTEGER NOT NULL,\n time_updated INTEGER,\n activity_time INTEGER NOT NULL,\n content_text TEXT NOT NULL,\n content_hash TEXT NOT NULL,\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\nexport function 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\nexport function 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\nexport function ensureProjectColumns(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) {\n return;\n }\n\n if (!columnExists(db, \"session_documents\", \"project_identity_kind\")) {\n db.exec(\n \"ALTER TABLE session_documents ADD COLUMN project_identity_kind TEXT NOT NULL DEFAULT 'path'\",\n );\n }\n if (!columnExists(db, \"session_documents\", \"project_identity_key\")) {\n db.exec(\n \"ALTER TABLE session_documents ADD COLUMN project_identity_key TEXT NOT NULL DEFAULT ''\",\n );\n }\n if (!columnExists(db, \"session_documents\", \"project_display_name\")) {\n db.exec(\n \"ALTER TABLE session_documents ADD COLUMN project_display_name TEXT NOT NULL DEFAULT ''\",\n );\n }\n}\n\nexport function createProjectTables(db: SQLiteDatabase): void {\n ensureProjectColumns(db);\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\nexport function 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 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 GROUP BY project_identity_kind, project_identity_key;\n `);\n}\n\nexport function recreateProjectGroupsView(db: SQLiteDatabase): void {\n db.exec(\"DROP VIEW IF EXISTS project_groups_v\");\n createProjectGroupsView(db);\n}\n\nexport function createLatestCacheSchema(db: SQLiteDatabase): void {\n createCacheTables(db);\n createSessionTables(db);\n createMessageSearchTables(db);\n createFileActivityTables(db);\n createSearchTables(db);\n createProjectTables(db);\n}\n\nexport function 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\nexport function 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\nexport function inferCacheSchemaVersion(db: SQLiteDatabase): number {\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\nexport function 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\nexport function 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\nexport function backfillProjectSessions(db: SQLiteDatabase): 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 identity = session.project_identity ?? computeIdentity(session.directory, realFs);\n upsert.run(\n row.agent_name,\n row.session_id,\n identity.kind,\n identity.key,\n identity.displayName,\n session.directory,\n session.time_updated ?? session.time_created,\n );\n } catch {\n continue;\n }\n }\n}\n\nexport function backfillSessionDocumentProjects(db: SQLiteDatabase): 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 = computeIdentity(String(row.directory ?? \"\"), realFs);\n update.run(identity.kind, identity.key, identity.displayName, Number(row.id));\n }\n}\n\nexport function migrateProjectIdentity(db: SQLiteDatabase): void {\n createProjectTables(db);\n backfillProjectSessions(db);\n backfillSessionDocumentProjects(db);\n}\n\nexport function refreshProjectIdentities(db: SQLiteDatabase): 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 = computeIdentity(String(row.directory ?? \"\"), realFs);\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 = computeIdentity(String(row.directory ?? \"\"), realFs);\n update.run(identity.kind, identity.key, identity.displayName, row.agent_name, row.session_id);\n }\n }\n\n backfillSessionDocumentProjects(db);\n recreateProjectGroupsView(db);\n}\n\nexport function backfillStructuredSessions(db: SQLiteDatabase): 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 session = JSON.parse(row.session_json) as SessionHead;\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 : computeIdentity(directory, realFs);\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\nexport function 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\nexport function 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\nexport function 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\nexport function 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\nexport function rebuildMessageSearchIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages_fts\")) {\n return;\n }\n db.exec(\"INSERT INTO messages_fts(messages_fts) VALUES ('rebuild')\");\n}\n\nexport function ensureFtsReady(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents_fts\")) {\n createSearchTables(db);\n }\n createSearchTriggers(db);\n\n const needsMessageSearchRebuild = !tableExists(db, \"messages_fts\");\n createMessageSearchTables(db);\n if (needsMessageSearchRebuild) {\n rebuildMessageSearchIndex(db);\n }\n}\n\nexport function ensureFtsConsistency(db: SQLiteDatabase): void {\n ensureFtsReady(db);\n const cachePath = getCachePath();\n if (getFtsIntegrityCheckedPath() === cachePath) {\n return;\n }\n\n try {\n db.exec(\n \"INSERT INTO session_documents_fts(session_documents_fts, rank) VALUES ('integrity-check', 1)\",\n );\n db.exec(\"INSERT INTO messages_fts(messages_fts, rank) VALUES ('integrity-check', 1)\");\n setFtsIntegrityCheckedPath(cachePath);\n } catch {\n rebuildSearchIndex(db);\n rebuildMessageSearchIndex(db);\n setFtsIntegrityCheckedPath(cachePath);\n }\n}\n\nexport function setCacheSchemaVersion(db: SQLiteDatabase): void {\n createCacheTables(db);\n setUserVersion(db, CACHE_SCHEMA_VERSION);\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\nexport function ensureSchema(db: SQLiteDatabase, dbPath: string): void {\n const currentVersion = getCurrentCacheSchemaVersion(db);\n if (currentVersion === 0 && !hasAnyCacheSchema(db)) {\n createLatestCacheSchema(db);\n setCacheSchemaVersion(db);\n return;\n }\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 { version: 5, migrate: migrateProjectIdentity },\n {\n version: 6,\n destructive: true,\n migrate(db) {\n createLatestCacheSchema(db);\n recreateSearchIndexSchema(db);\n invalidateSearchContentHashes(db);\n },\n },\n { version: 7, migrate: backfillStructuredSessions },\n { version: 8, migrate: backfillFileActivity },\n {\n version: 9,\n migrate(db) {\n createMessageSearchTables(db);\n rebuildMessageSearchIndex(db);\n },\n },\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);\n },\n },\n { version: 13, migrate: createCacheTables },\n ],\n });\n\n createLatestCacheSchema(db);\n\n if (getUserVersion(db) <= CACHE_SCHEMA_VERSION) {\n setCacheSchemaVersion(db);\n }\n}\n","/**\n * Full-text search: query parsing, FTS index sync, session/message search,\n * and match highlighting / snippet building.\n */\nimport type {\n FileActivityKind,\n Message,\n ProjectIdentity,\n ProjectIdentityKind,\n SessionData,\n SessionFileActivity,\n SessionHead,\n SmartTag,\n} from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport {\n escapeRegExp,\n filePathFtsQuery,\n hasCacheStorage,\n likePattern,\n SEARCH_INDEX_BULK_SYNC_THRESHOLD,\n type SessionHeadChange,\n} from \"./db.js\";\nimport {\n buildSessionContentFromMessages,\n normalizeMessages,\n normalizeToolName,\n prepareInsertFileActivity,\n prepareInsertMessageTool,\n prepareUpsertIndexedSession,\n sessionFromRow,\n upsertSessionRow,\n writeFileActivityRows,\n type SessionRow,\n type StructuredMessageRecord,\n} from \"./messages.js\";\nimport {\n createMessageSearchTriggers,\n createSearchTriggers,\n dropMessageSearchTriggers,\n dropSearchTriggers,\n ensureFtsConsistency,\n ensureFtsReady,\n rebuildMessageSearchIndex,\n rebuildSearchIndex,\n withCacheDb,\n type IndexedSearchRow,\n type MessageCountRow,\n} from \"./schema.js\";\n\nexport interface SearchIndexSyncOptions {\n isBulk?: boolean;\n bulkThreshold?: number;\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 durationMs: number;\n rebuildDurationMs?: number;\n}\n\nexport interface 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 interface LoadedSearchIndexEntry {\n session: SessionHead;\n identity: ProjectIdentity;\n messages: StructuredMessageRecord[];\n contentText: string;\n contentHash: string;\n fileActivity: SessionFileActivity[];\n sortIndex: number;\n}\n\nexport interface SearchResult {\n agentName: string;\n session: SessionHead;\n snippet: string;\n matchType: SearchMatchType;\n}\n\nexport type SearchMatchType =\n | \"recent\"\n | \"title\"\n | \"user_message\"\n | \"assistant_reply\"\n | \"tool_output\"\n | \"file_path\";\n\nexport interface SearchQueryFilters {\n agent?: string;\n project?: string;\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\nexport interface SearchOptions {\n agent?: string;\n project?: string;\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 from?: number;\n to?: number;\n limit?: number;\n}\n\nexport function shouldBulkSyncSearchIndex(\n options: SearchIndexSyncOptions,\n changedCount: number,\n): 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\nexport function 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\nexport function 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) {\n tokens.push(token);\n }\n\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\nexport function 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\nexport function appendUnique<T>(values: T[] | undefined, value: T): T[] {\n if (values?.includes(value)) return values;\n return [...(values ?? []), value];\n}\n\nexport function 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 === \"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)) {\n filters.tags = appendUnique(filters.tags, tag);\n } else {\n consumed = false;\n }\n } else if (key === \"cost\") {\n parseCostQualifier(value, filters);\n } else {\n consumed = false;\n }\n\n if (consumed) {\n hasQualifiers = true;\n } else {\n textTokens.push(token);\n }\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 const mapped = tokens\n .map((token) => {\n if (/^OR$/i.test(token)) {\n return \"OR\";\n }\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\n return mapped.join(\" \");\n}\n\nexport function loadSearchIndexEntry(\n agentName: string,\n change: SessionHeadChange,\n loadSessionData: (sessionId: string) => SessionData,\n): LoadedSearchIndexEntry | null {\n try {\n const data = loadSessionData(change.session.id);\n const messages = normalizeMessages(data);\n const identity =\n change.session.project_identity ??\n data.project_identity ??\n computeIdentity(change.session.directory, realFs);\n return {\n session: change.session,\n identity,\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 };\n } catch {\n return null;\n }\n}\n\nexport function writeSearchIndexRows(\n db: SQLiteDatabase,\n agentName: string,\n removedSessionIds: string[],\n entries: LoadedSearchIndexEntry[],\n): void {\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 upsertIndexedSession = 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 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 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 slug,\n title,\n directory,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n time_created,\n time_updated,\n activity_time,\n content_text,\n content_hash,\n indexed_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\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 time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n activity_time = excluded.activity_time,\n content_text = excluded.content_text,\n content_hash = excluded.content_hash,\n indexed_at = excluded.indexed_at\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 }\n\n for (const entry of entries) {\n const activityTime = entry.session.time_updated ?? entry.session.time_created;\n upsertSessionRow(upsertIndexedSession, agentName, entry.session, null, entry.sortIndex, null);\n deleteFileActivity.run(agentName, entry.session.id);\n deleteMessageTools.run(agentName, entry.session.id, 0);\n writeFileActivityRows(insertFileActivity, entry.fileActivity);\n for (const message of entry.messages) {\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.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 upsertRow.run(\n agentName,\n entry.session.id,\n entry.session.slug,\n entry.session.title,\n entry.session.directory,\n entry.identity.kind,\n entry.identity.key,\n entry.identity.displayName,\n entry.session.time_created,\n entry.session.time_updated ?? null,\n activityTime,\n entry.contentText,\n entry.contentHash,\n Date.now(),\n );\n }\n}\n\nexport function syncSessionSearchIndex(\n agentName: string,\n sessions: SessionHead[],\n loadSessionData: (sessionId: string) => SessionData,\n options: SearchIndexSyncOptions = {},\n): SearchIndexSyncResult | null {\n return withCacheDb((db) => {\n ensureFtsConsistency(db);\n const startedAt = performance.now();\n const existingRows = db\n .prepare(\n \"SELECT session_id, content_hash FROM session_documents WHERE agent_name = ? ORDER BY id\",\n )\n .all(agentName) as IndexedSearchRow[];\n const existingMap = new Map(\n existingRows.map((row) => [String(row.session_id), String(row.content_hash ?? \"\")]),\n );\n const sessionSortIndexMap = new Map(sessions.map((session, index) => [session.id, index]));\n const messageCountRows = db\n .prepare(\n \"SELECT session_id, COUNT(*) AS value FROM messages WHERE agent_name = ? GROUP BY session_id\",\n )\n .all(agentName) as MessageCountRow[];\n const messageCountMap = new Map(\n messageCountRows.map((row) => [String(row.session_id), Number(row.value ?? 0)]),\n );\n const sessionMap = new Map(sessions.map((session) => [session.id, session]));\n\n const toDelete = existingRows\n .map((row) => String(row.session_id))\n .filter((sessionId) => !sessionMap.has(sessionId));\n const toUpsert = sessions.filter(\n (session) =>\n existingMap.get(session.id) !== sessionContentHash(session) ||\n messageCountMap.get(session.id) !== session.stats.message_count,\n );\n const changedCount = toDelete.length + toUpsert.length;\n const isBulk = shouldBulkSyncSearchIndex(options, changedCount);\n\n const loaded = toUpsert\n .map((session) =>\n loadSearchIndexEntry(\n agentName,\n { session, sortIndex: sessionSortIndexMap.get(session.id) ?? 0 },\n loadSessionData,\n ),\n )\n .filter((entry): entry is LoadedSearchIndexEntry => entry !== null);\n\n const writeRows = () => writeSearchIndexRows(db, agentName, toDelete, loaded);\n\n let rebuildDurationMs: number | undefined;\n const needsRebuild = isBulk && (toDelete.length > 0 || loaded.length > 0);\n\n if (needsRebuild) {\n db.transaction(() => {\n dropSearchTriggers(db);\n dropMessageSearchTriggers(db);\n writeRows();\n const rebuildStartedAt = performance.now();\n rebuildSearchIndex(db);\n rebuildMessageSearchIndex(db);\n rebuildDurationMs = performance.now() - rebuildStartedAt;\n createSearchTriggers(db);\n createMessageSearchTriggers(db);\n })();\n } else {\n db.transaction(writeRows)();\n }\n\n return {\n agentName,\n mode: isBulk ? \"bulk\" : \"incremental\",\n sessions: sessions.length,\n changed: toUpsert.length,\n deleted: toDelete.length,\n indexed: loaded.length,\n skipped: toUpsert.length - loaded.length,\n durationMs: performance.now() - startedAt,\n rebuildDurationMs,\n };\n });\n}\n\nexport function syncSessionSearchIndexChanges(\n agentName: string,\n changes: SessionHeadChange[],\n removedSessionIds: string[],\n loadSessionData: (sessionId: string) => SessionData,\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 return withCacheDb((db) => {\n ensureFtsConsistency(db);\n const startedAt = performance.now();\n const getIndexedRow = db.prepare(\n \"SELECT content_hash FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const getMessageCount = db.prepare(\n \"SELECT COUNT(*) AS value FROM messages WHERE agent_name = ? AND session_id = ?\",\n );\n const toUpsert = changes.filter(({ session }) => {\n const indexed = getIndexedRow.get(agentName, session.id) as IndexedSearchRow | undefined;\n const messageCount = getMessageCount.get(agentName, session.id) as\n | MessageCountRow\n | undefined;\n return (\n String(indexed?.content_hash ?? \"\") !== sessionContentHash(session) ||\n Number(messageCount?.value ?? 0) !== session.stats.message_count\n );\n });\n const uniqueRemovedSessionIds = Array.from(new Set(removedSessionIds));\n const changedCount = uniqueRemovedSessionIds.length + toUpsert.length;\n const isBulk = shouldBulkSyncSearchIndex(options, changedCount);\n const loaded = toUpsert\n .map((change) => loadSearchIndexEntry(agentName, change, loadSessionData))\n .filter((entry): entry is LoadedSearchIndexEntry => entry !== null);\n const writeRows = () => writeSearchIndexRows(db, agentName, uniqueRemovedSessionIds, loaded);\n\n let rebuildDurationMs: number | undefined;\n const needsRebuild = isBulk && (uniqueRemovedSessionIds.length > 0 || loaded.length > 0);\n\n if (needsRebuild) {\n db.transaction(() => {\n dropSearchTriggers(db);\n dropMessageSearchTriggers(db);\n writeRows();\n const rebuildStartedAt = performance.now();\n rebuildSearchIndex(db);\n rebuildMessageSearchIndex(db);\n rebuildDurationMs = performance.now() - rebuildStartedAt;\n createSearchTriggers(db);\n createMessageSearchTriggers(db);\n })();\n } else {\n db.transaction(writeRows)();\n }\n\n return {\n agentName,\n mode: isBulk ? \"bulk\" : \"incremental\",\n sessions: changes.length,\n changed: toUpsert.length,\n deleted: uniqueRemovedSessionIds.length,\n indexed: loaded.length,\n skipped: toUpsert.length - loaded.length,\n durationMs: performance.now() - startedAt,\n rebuildDurationMs,\n };\n });\n}\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 projectKey: options.projectKey ?? parsed.filters.projectKey,\n cwd: options.cwd ?? parsed.filters.cwd,\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 sessionMatchesSearchCost(session: SessionHead, options: SearchOptions): boolean {\n const cost = session.stats.total_cost;\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.projectKey) {\n clauses.push(\"s.project_identity_key = ?\");\n params.push(options.projectKey);\n }\n if (options.cwd) {\n clauses.push(\"(s.project_identity_key = ? OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\");\n params.push(computeIdentity(options.cwd, realFs).key, likePattern(options.cwd));\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 if (options.costMin != null) {\n clauses.push(options.costMinExclusive ? \"s.total_cost > ?\" : \"s.total_cost >= ?\");\n params.push(options.costMin);\n }\n if (options.costMax != null) {\n clauses.push(options.costMaxExclusive ? \"s.total_cost < ?\" : \"s.total_cost <= ?\");\n params.push(options.costMax);\n }\n\n return {\n where: clauses.length > 0 ? ` AND ${clauses.join(\" AND \")}` : \"\",\n params,\n };\n}\n\nexport function 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\nexport function 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\nexport function 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\nexport function highlightTerm(text: string, term: string): string {\n return text.replace(new RegExp(escapeRegExp(term), \"gi\"), (match) => `<mark>${match}</mark>`);\n}\n\nexport function buildTermSnippet(\n text: string,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n): string {\n const lower = text.toLowerCase();\n const term = terms.terms.find((item) => lower.includes(item)) ?? terms.terms[0] ?? \"\";\n if (!term) return text.slice(0, 180);\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 return `${start > 0 ? \"… \" : \"\"}${highlightTerm(text.slice(start, end), term)}${\n end < text.length ? \" …\" : \"\"\n }`;\n}\n\nexport function 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\nexport function searchResultRowKey(\n row: Pick<SearchResultRow, \"agent_name\" | \"session_id\">,\n): string {\n return `${String(row.agent_name)}\\u0000${String(row.session_id)}`;\n}\n\nexport function fetchMessageSearchMatches(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n ftsQuery: string,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n): Map<string, { snippet: string; matchType: SearchMatchType }> {\n const candidates = rows.filter((row) => !textMatchesTerms(String(row.title ?? \"\"), terms));\n if (candidates.length === 0) {\n return new Map();\n }\n\n const clauses: string[] = [];\n const params: unknown[] = [ftsQuery];\n for (const row of candidates) {\n clauses.push(\"(m.agent_name = ? AND m.session_id = ?)\");\n params.push(String(row.agent_name), String(row.session_id));\n }\n\n const messageRows = db\n .prepare(\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 messages_fts\n JOIN messages m ON m.rowid = messages_fts.rowid\n WHERE messages_fts MATCH ?\n AND (${clauses.join(\" OR \")})\n ORDER BY m.message_index\n `,\n )\n .all(...params) as MessageSearchRow[];\n const matches = new Map<string, { snippet: string; 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 snippet: buildTermSnippet(text, terms),\n matchType: messageMatchType(message),\n });\n }\n\n return matches;\n}\n\nexport function resolveSearchMatch(\n row: SearchResultRow,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n messageMatches: Map<string, { snippet: string; matchType: SearchMatchType }>,\n): { snippet: string; 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 matchType: \"recent\",\n };\n }\n\n if (textMatchesTerms(title, terms)) {\n return { snippet: 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 matchType: \"assistant_reply\",\n };\n}\n\nexport function rowsToSearchResults(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n textQuery: string,\n ftsQuery = toFtsQuery(textQuery),\n): SearchResult[] {\n const terms = parseTextTerms(textQuery);\n const messageMatches =\n terms.terms.length > 0 && ftsQuery\n ? fetchMessageSearchMatches(db, rows, ftsQuery, terms)\n : new Map<string, { snippet: string; matchType: SearchMatchType }>();\n\n return rows.map((row) => {\n const match = resolveSearchMatch(row, terms, messageMatches);\n return {\n agentName: String(row.agent_name),\n session: sessionHeadFromSearchRow(row),\n snippet: match.snippet,\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 = withCacheDb((db) => {\n ensureFtsReady(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 ${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, '<mark>', '</mark>', ' … ', 18), ''),\n highlight(session_documents_fts, 0, '<mark>', '</mark>')\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 ${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, ftsQuery);\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 { FileActivityKind, SessionFileActivity, SessionHead } from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { filePathFtsQuery, hasCacheStorage, likePattern, normalizeFilePathSearch } from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./schema.js\";\nimport {\n mergeSearchQueryOptions,\n sessionHeadFromSearchRow,\n sessionMatchesSearchCost,\n type SearchOptions,\n type SearchResult,\n type SearchResultRow,\n} from \"./search.js\";\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 projectKey?: string;\n project?: string;\n cwd?: string;\n path?: string;\n kind?: FileActivityKind;\n from?: number;\n to?: number;\n limit?: number;\n}\n\nexport interface FileActivityResult extends SessionFileActivity {\n session: SessionHead;\n}\n\nexport function fileActivityFilters(options: FileActivityOptions): {\n projectKey: string | null;\n projectLike: string | null;\n cwdKey: string | null;\n cwdLike: string | null;\n path: string;\n pathLike: string | null;\n} {\n const path = options.path ? normalizeFilePathSearch(options.path) : \"\";\n return {\n projectKey: options.projectKey ?? null,\n projectLike: options.project ? likePattern(options.project) : null,\n cwdKey: options.cwd ? computeIdentity(options.cwd, realFs).key : null,\n cwdLike: options.cwd ? likePattern(options.cwd) : null,\n path,\n pathLike: path ? likePattern(path) : null,\n };\n}\n\nexport function fileActivityFromRow(row: FileActivityRow): SessionFileActivity {\n return {\n agent_name: String(row.agent_name),\n session_id: String(row.session_id),\n project_identity_key: String(row.project_identity_key ?? \"\"),\n path: String(row.path ?? \"\"),\n kind: (row.kind ?? \"read\") as FileActivityKind,\n count: Number(row.count ?? 0),\n latest_time: 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.projectKey != null) {\n clauses.push(\"fa.project_identity_key = ?\");\n params.push(filters.projectKey);\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.cwdKey != null) {\n clauses.push(\"(s.project_identity_key = ? OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\");\n params.push(filters.cwdKey, filters.cwdLike);\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\nexport function listFileActivity(options: FileActivityOptions = {}): FileActivityResult[] {\n if (!hasCacheStorage()) {\n return [];\n }\n\n const filters = buildFileActivityWhere(options);\n const queryRows = (db: SQLiteDatabase) =>\n db\n .prepare(\n `\n SELECT\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 FROM session_file_activity fa\n JOIN sessions s ON s.agent_name = fa.agent_name AND s.session_id = fa.session_id\n ${filters.where}\n ORDER BY fa.latest_time DESC, fa.count DESC, fa.path\n LIMIT ?\n `,\n )\n .all(...filters.params, options.limit ?? 50) as FileActivityRow[];\n\n let rows = withCacheDbReadOnly(queryRows);\n if (rows == null && options.path) {\n rows = withCacheDb(queryRows);\n }\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 highlightFilePath(path: string, query: string): string {\n const needle = normalizeFilePathSearch(query);\n if (!needle) return path;\n const lower = path.toLowerCase();\n const index = lower.indexOf(needle.toLowerCase());\n if (index < 0) return path;\n return `${path.slice(0, index)}<mark>${path.slice(index, index + needle.length)}</mark>${path.slice(\n index + needle.length,\n )}`;\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 = listFileActivity({\n agent: search.options.agent,\n projectKey: search.options.projectKey,\n project: search.options.project,\n cwd: search.options.cwd,\n path,\n kind: search.options.fileKind,\n from: search.options.from,\n to: search.options.to,\n limit: (search.options.limit ?? 50) * 3,\n });\n const seen = new Set<string>();\n const results: SearchResult[] = [];\n\n for (const row of rows) {\n const key = `${row.agent_name}/${row.session_id}`;\n if (seen.has(key)) continue;\n if (!sessionMatchesSearchCost(row.session, search.options)) continue;\n seen.add(key);\n results.push({\n agentName: row.agent_name,\n session: row.session,\n snippet: `${row.kind} ${highlightFilePath(row.path, path)} · ${row.count} events`,\n matchType: \"file_path\",\n });\n if (results.length >= (search.options.limit ?? 50)) break;\n }\n\n return results;\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 } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDb } 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 groups = withCacheDb((db) => {\n const rows = 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 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\n return groups ?? [];\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 type { ProjectIdentity, SessionHead } from \"../types/index.js\";\nimport type { SessionHeadChange } from \"./cache.js\";\nimport { computeIdentity, realFs } from \"../projects/index.js\";\n\nfunction createIdentityResolver() {\n const cache = new Map<string, ProjectIdentity>();\n return (directory: string | null | undefined) => {\n const key = directory || \"\";\n const cached = cache.get(key);\n if (cached) return cached;\n const identity = computeIdentity(directory, realFs);\n cache.set(key, identity);\n return identity;\n };\n}\n\n/** Attach a project identity to sessions that don't already have one. */\nexport function attachMissingProjectIdentities(sessions: SessionHead[]): SessionHead[] {\n const resolveIdentity = createIdentityResolver();\n return sessions.map((session) => {\n if (session.project_identity) return session;\n return { ...session, project_identity: resolveIdentity(session.directory) };\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\n/**\n * Stable signature for the user-visible fields that define a session's identity.\n * Used by both orchestrators to decide whether a session \"changed\". Includes\n * smart_tags_source_updated_at so that smart-tag reclassification propagates to\n * the persistence diff even when the underlying message stats are unchanged.\n */\nexport function sessionSignature(session: SessionHead): string {\n return JSON.stringify([\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_cost,\n session.stats.total_tokens ?? 0,\n session.smart_tags_source_updated_at ?? null,\n ]);\n}\n\n/** Sort sessions by activity time, newest first. */\nexport function sortSessions(sessions: SessionHead[]): SessionHead[] {\n return [...sessions].sort(\n (a, b) => (b.time_updated ?? b.time_created) - (a.time_updated ?? a.time_created),\n );\n}\n\nexport interface SessionDiffResult {\n changes: SessionHeadChange[];\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 */\nexport function computeSessionDiff(\n cachedSessions: SessionHead[],\n updatedSessions: SessionHead[],\n changedIds: string[] = [],\n signature: (session: SessionHead) => string = sessionSignature,\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: SessionHeadChange[] = [];\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 return;\n }\n const hasSignatureChange = signature(cached) !== signature(session);\n if (changedIdSet.has(session.id) || hasSignatureChange) {\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 { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { SessionStats } from \"../types/index.js\";\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 BOOKMARK_DB_FILENAME = \"state.db\";\nconst BOOKMARK_SCHEMA_VERSION = 1;\nconst MEMORY_STATE_STORE = \"memory\";\nconst memoryBookmarks = new Map<string, BookmarkRecord>();\n\nexport class BookmarkStorageUnavailableError extends Error {\n constructor() {\n super(\"SQLite state database is unavailable\");\n this.name = \"BookmarkStorageUnavailableError\";\n }\n}\n\nexport interface BookmarkRecord {\n agentKey: string;\n sessionId: string;\n fullPath: string;\n title: string;\n directory: string;\n time_created: number;\n time_updated?: number;\n stats: SessionStats;\n bookmarked_at: number;\n}\n\ninterface BookmarkRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n slug?: string;\n title?: string;\n directory?: string;\n time_created?: number;\n time_updated?: number | null;\n stats_json?: string;\n bookmarked_at?: number;\n}\n\nfunction getStateDir(): string {\n if (process.env.CODESESH_STATE_DIR) {\n return process.env.CODESESH_STATE_DIR;\n }\n\n const p = platform();\n if (p === \"darwin\") {\n return join(homedir(), \"Library\", \"Application Support\", \"codesesh\");\n }\n if (p === \"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(), BOOKMARK_DB_FILENAME);\n}\n\nfunction useMemoryStateStore(): boolean {\n return process.env.CODESESH_STATE_STORE === MEMORY_STATE_STORE;\n}\n\nfunction getBookmarkKey(agentKey: string, sessionId: string): string {\n return JSON.stringify([agentKey, sessionId]);\n}\n\nfunction getActivityTime(bookmark: BookmarkRecord): number {\n return bookmark.time_updated ?? bookmark.time_created;\n}\n\nfunction sortBookmarks(bookmarks: BookmarkRecord[]): BookmarkRecord[] {\n return bookmarks.sort((a, b) => {\n const activityDelta = getActivityTime(b) - getActivityTime(a);\n return activityDelta || b.bookmarked_at - a.bookmarked_at;\n });\n}\n\nfunction listMemoryBookmarks(): BookmarkRecord[] {\n return sortBookmarks(Array.from(memoryBookmarks.values()));\n}\n\nfunction upsertMemoryBookmark(bookmark: Omit<BookmarkRecord, \"bookmarked_at\">): BookmarkRecord {\n const key = getBookmarkKey(bookmark.agentKey, bookmark.sessionId);\n const saved = {\n ...bookmark,\n bookmarked_at: memoryBookmarks.get(key)?.bookmarked_at ?? Date.now(),\n };\n memoryBookmarks.set(key, saved);\n return saved;\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 CREATE TABLE IF NOT EXISTS bookmarks (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n slug TEXT NOT NULL,\n title TEXT NOT NULL,\n directory TEXT NOT NULL,\n time_created INTEGER NOT NULL,\n time_updated INTEGER,\n stats_json TEXT NOT NULL,\n bookmarked_at INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\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) {\n return userVersion;\n }\n\n const legacyVersion = readLegacyStateVersion(db);\n if (legacyVersion > 0) {\n return legacyVersion;\n }\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, BOOKMARK_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(BOOKMARK_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: BOOKMARK_SCHEMA_VERSION,\n backupLabel: \"state-migration\",\n backupTables: [\"bookmarks\"],\n migrations: [{ version: 1, migrate: createStateSchema }],\n });\n\n createStateSchema(db);\n\n if (getUserVersion(db) <= BOOKMARK_SCHEMA_VERSION) {\n setStateSchemaVersion(db);\n }\n}\n\nfunction withStateDb<T>(fn: (db: SQLiteDatabase) => T): T {\n const statePath = getStateDbPath();\n const db = openDb(statePath);\n if (!db) {\n throw new BookmarkStorageUnavailableError();\n }\n\n try {\n ensureSchema(db, statePath);\n return fn(db);\n } finally {\n db.close();\n }\n}\n\nfunction toBookmarkRecord(row: BookmarkRow): BookmarkRecord {\n return {\n agentKey: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n fullPath: String(row.slug ?? \"\"),\n title: String(row.title ?? \"\"),\n directory: String(row.directory ?? \"\"),\n time_created: Number(row.time_created ?? 0),\n time_updated: row.time_updated == null ? undefined : Number(row.time_updated),\n stats: JSON.parse(String(row.stats_json ?? \"{}\")) as SessionStats,\n bookmarked_at: Number(row.bookmarked_at ?? 0),\n };\n}\n\nexport function listBookmarks(): BookmarkRecord[] {\n if (useMemoryStateStore()) {\n return listMemoryBookmarks();\n }\n\n return withStateDb((db) => {\n const rows = db\n .prepare(\n `\n SELECT\n agent_name,\n session_id,\n slug,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n FROM bookmarks\n ORDER BY COALESCE(time_updated, time_created) DESC, bookmarked_at DESC\n `,\n )\n .all() as BookmarkRow[];\n\n return rows.map(toBookmarkRecord);\n });\n}\n\nexport function upsertBookmark(bookmark: Omit<BookmarkRecord, \"bookmarked_at\">): BookmarkRecord {\n if (useMemoryStateStore()) {\n return upsertMemoryBookmark(bookmark);\n }\n\n return withStateDb((db) => {\n const existing = db\n .prepare(\n `\n SELECT bookmarked_at\n FROM bookmarks\n WHERE agent_name = ? AND session_id = ?\n `,\n )\n .get(bookmark.agentKey, bookmark.sessionId) as DatabaseRow | undefined;\n const bookmarkedAt = Number(existing?.bookmarked_at ?? Date.now());\n\n db.prepare(\n `\n INSERT INTO bookmarks(\n agent_name,\n session_id,\n slug,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n stats_json = excluded.stats_json\n `,\n ).run(\n bookmark.agentKey,\n bookmark.sessionId,\n bookmark.fullPath,\n bookmark.title,\n bookmark.directory,\n bookmark.time_created,\n bookmark.time_updated ?? null,\n JSON.stringify(bookmark.stats),\n bookmarkedAt,\n );\n\n return { ...bookmark, bookmarked_at: bookmarkedAt };\n });\n}\n\nexport function importBookmarks(\n bookmarks: Omit<BookmarkRecord, \"bookmarked_at\">[],\n): BookmarkRecord[] {\n if (useMemoryStateStore()) {\n for (const bookmark of bookmarks) {\n upsertMemoryBookmark(bookmark);\n }\n return listMemoryBookmarks();\n }\n\n return withStateDb((db) => {\n const existingRows = db\n .prepare(\"SELECT agent_name, session_id, bookmarked_at FROM bookmarks\")\n .all() as DatabaseRow[];\n const existingTimes = new Map(\n existingRows.map((row) => [\n `${String(row.agent_name ?? \"\")}:${String(row.session_id ?? \"\")}`,\n Number(row.bookmarked_at ?? 0),\n ]),\n );\n\n const upsert = db.prepare(\n `\n INSERT INTO bookmarks(\n agent_name,\n session_id,\n slug,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n stats_json = excluded.stats_json\n `,\n );\n\n const write = db.transaction(() => {\n for (const bookmark of bookmarks) {\n const key = `${bookmark.agentKey}:${bookmark.sessionId}`;\n upsert.run(\n bookmark.agentKey,\n bookmark.sessionId,\n bookmark.fullPath,\n bookmark.title,\n bookmark.directory,\n bookmark.time_created,\n bookmark.time_updated ?? null,\n JSON.stringify(bookmark.stats),\n existingTimes.get(key) ?? Date.now(),\n );\n }\n });\n\n write();\n const rows = db\n .prepare(\n `\n SELECT\n agent_name,\n session_id,\n slug,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n FROM bookmarks\n ORDER BY COALESCE(time_updated, time_created) DESC, bookmarked_at DESC\n `,\n )\n .all() as BookmarkRow[];\n return rows.map(toBookmarkRecord);\n });\n}\n\nexport function deleteBookmark(agentKey: string, sessionId: string): void {\n if (useMemoryStateStore()) {\n memoryBookmarks.delete(getBookmarkKey(agentKey, sessionId));\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(agentKey, sessionId);\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, and the recent-sessions window.\n */\nimport type { AgentInfo } from \"../types/index.js\";\nimport type { SessionHead } from \"../types/session.js\";\n\nexport const DASHBOARD_RECENT_LIMIT = 10;\n\nexport interface DashboardScope {\n agent?: string;\n projectKind?: string;\n projectKey?: string;\n}\n\nexport interface DashboardAgentStat {\n name: string;\n displayName: string;\n icon: string;\n sessions: number;\n messages: number;\n tokens: number;\n}\n\nexport interface DashboardDailyBucket {\n date: string;\n sessions: number;\n messages: number;\n}\n\nexport interface DailyTokenBucket {\n date: string;\n input: number;\n output: number;\n cache_read: number;\n cache_create: number;\n}\n\nexport interface ModelDistributionEntry {\n model: string;\n tokens: number;\n sessions: number;\n}\n\nexport interface DashboardRecentSession extends SessionHead {\n agentName: string;\n}\n\ninterface DashboardAgentAggregate {\n sessions: number;\n messages: number;\n tokens: number;\n}\n\ninterface DashboardRecentCandidate {\n session: SessionHead;\n activity: number;\n}\n\nexport interface DashboardTotals {\n sessions: number;\n messages: number;\n tokens: number;\n cost: number;\n cost_source?: \"estimated\" | \"recorded\";\n latestActivity?: number;\n}\n\nexport interface DashboardAggregate {\n totals: DashboardTotals;\n perAgent: DashboardAgentStat[];\n dailyActivity: DashboardDailyBucket[];\n dailyTokenActivity: DailyTokenBucket[];\n modelDistribution: ModelDistributionEntry[];\n recentSessions: DashboardRecentSession[];\n}\n\nexport interface DashboardData extends DashboardAggregate {\n recentFileActivities: unknown[];\n window: { from?: number; to: number; days?: number };\n}\n\nexport interface DashboardOptions {\n byAgentNames: string[];\n scope: DashboardScope;\n from?: number;\n to: number;\n agentInfoMap?: Map<string, AgentInfo>;\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 session.slug.split(\"/\")[0]?.toLowerCase() || \"unknown\";\n}\n\nexport function getSessionActivityTime(session: SessionHead): number {\n return session.time_updated ?? session.time_created;\n}\n\n// --- Local-day bucketing helpers ---\n\nexport function toLocalDateKey(ts: number): string {\n const d = new Date(ts);\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(\n d.getDate(),\n ).padStart(2, \"0\")}`;\n}\n\nexport function startOfLocalDay(ts: number): number {\n const d = new Date(ts);\n d.setHours(0, 0, 0, 0);\n return d.getTime();\n}\n\n/**\n * Aggregate sessions into dashboard metrics, daily buckets, model distribution,\n * 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 } = options;\n\n const agentMetrics = new Map<string, DashboardAgentAggregate>();\n const agentMetricKeyByName = new Map<string, string>();\n for (const name of byAgentNames) {\n if (scope.agent && name.toLowerCase() !== scope.agent) continue;\n agentMetrics.set(name, { sessions: 0, messages: 0, tokens: 0 });\n agentMetricKeyByName.set(name.toLowerCase(), name);\n }\n\n let totalSessions = 0;\n let totalMessages = 0;\n let totalTokens = 0;\n let totalCost = 0;\n let hasEstimatedCost = false;\n let latestActivity = 0;\n const recentCandidates: DashboardRecentCandidate[] = [];\n const modelAgg = new Map<string, { tokens: number; sessions: number }>();\n\n const dailyMap = new Map<string, DashboardDailyBucket>();\n const dailyTokenMap = new Map<string, DailyTokenBucket>();\n if (from != null) {\n const bucketStart = startOfLocalDay(from);\n const bucketDays = Math.floor((startOfLocalDay(to) - bucketStart) / 86400000) + 1;\n for (let i = 0; i < bucketDays; i += 1) {\n const ts = bucketStart + i * 86400000;\n const key = toLocalDateKey(ts);\n dailyMap.set(key, { date: key, sessions: 0, messages: 0 });\n dailyTokenMap.set(key, { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 });\n }\n }\n\n for (const session of sessions) {\n const agentName = getSessionAgentName(session);\n if (scope.agent && agentName !== scope.agent) continue;\n if (scope.projectKey) {\n const identity = session.project_identity;\n if (!identity || identity.key !== scope.projectKey) continue;\n if (scope.projectKind && identity.kind !== scope.projectKind) continue;\n }\n\n const activity = getSessionActivityTime(session);\n if (from != null && activity < from) continue;\n if (activity > to) continue;\n\n const messageCount = session.stats.message_count;\n const sessionTokens = getTotalTokens(session.stats);\n totalSessions += 1;\n totalMessages += messageCount;\n totalTokens += sessionTokens;\n totalCost += session.stats.total_cost ?? 0;\n if (session.stats.cost_source === \"estimated\") hasEstimatedCost = true;\n if (activity > latestActivity) latestActivity = activity;\n\n const metricKey = agentMetricKeyByName.get(agentName);\n if (metricKey) {\n const metric = agentMetrics.get(metricKey)!;\n metric.sessions += 1;\n metric.messages += messageCount;\n metric.tokens += sessionTokens;\n }\n\n const key = toLocalDateKey(activity);\n let bucket = dailyMap.get(key);\n if (!bucket) {\n bucket = { date: key, sessions: 0, messages: 0 };\n dailyMap.set(key, bucket);\n }\n bucket.sessions += 1;\n bucket.messages += messageCount;\n\n let tokenBucket = dailyTokenMap.get(key);\n if (!tokenBucket) {\n tokenBucket = { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 };\n dailyTokenMap.set(key, tokenBucket);\n }\n const cacheRead = session.stats.total_cache_read_tokens ?? 0;\n const cacheCreate = session.stats.total_cache_create_tokens ?? 0;\n const pureInput = session.stats.total_input_tokens - cacheRead - cacheCreate;\n tokenBucket.input += Math.max(0, pureInput);\n tokenBucket.output += session.stats.total_output_tokens;\n tokenBucket.cache_read += cacheRead;\n tokenBucket.cache_create += cacheCreate;\n\n if (session.model_usage) {\n for (const [model, tokens] of Object.entries(session.model_usage)) {\n const entry = modelAgg.get(model);\n if (entry) {\n entry.tokens += tokens;\n entry.sessions += 1;\n } else {\n modelAgg.set(model, { tokens, sessions: 1 });\n }\n }\n }\n\n let recentIndex = recentCandidates.length;\n for (let i = 0; i < recentCandidates.length; i += 1) {\n if (activity > recentCandidates[i]!.activity) {\n recentIndex = i;\n break;\n }\n }\n if (recentIndex < DASHBOARD_RECENT_LIMIT) {\n recentCandidates.splice(recentIndex, 0, { session, activity });\n if (recentCandidates.length > DASHBOARD_RECENT_LIMIT) recentCandidates.pop();\n }\n }\n\n const perAgent: DashboardAgentStat[] = [...agentMetrics.entries()]\n .map(([name, metrics]) => {\n const info = agentInfoMap?.get(name);\n return {\n name,\n displayName: info?.displayName ?? name,\n icon: info?.icon ?? \"\",\n sessions: metrics.sessions,\n messages: metrics.messages,\n tokens: metrics.tokens,\n };\n })\n .filter((item) => item.sessions > 0)\n .sort((a, b) => b.sessions - a.sessions);\n\n const dailyActivity = [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date));\n const dailyTokenActivity = [...dailyTokenMap.values()].sort((a, b) =>\n a.date.localeCompare(b.date),\n );\n\n const modelDistribution: ModelDistributionEntry[] = [...modelAgg.entries()]\n .map(([model, { tokens, sessions: count }]) => ({ model, tokens, sessions: count }))\n .sort((a, b) => b.tokens - a.tokens);\n\n const recentSessions: DashboardRecentSession[] = recentCandidates.map(({ session }) => {\n const agentKey = getSessionAgentName(session);\n return { ...session, agentName: agentKey };\n });\n\n return {\n totals: {\n sessions: totalSessions,\n messages: totalMessages,\n tokens: totalTokens,\n cost: totalCost,\n cost_source: totalCost > 0 ? (hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n latestActivity: latestActivity || undefined,\n },\n perAgent,\n dailyActivity,\n dailyTokenActivity,\n modelDistribution,\n recentSessions,\n };\n}\n"],"mappings":"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","names":["existsSync","readFileSync","statSync","join","basename","homedir","mkdirSync","dirname","readdirSync","platform","path","isInternalEventType","message","text","require","parsed","HEAD_INDEX_VERSION","parseTimestampMs","normalizeToolArguments","payload","mapToolTitle","normalizeToolOutputParts","directory","totalCost","composerId","PARSER_VERSION","getCacheDir","getCachePath","normalizeToolName","db","amount","rows","t3","cachedWithIdentity","filtered","t4","tagged","ensureSchema"]}
|