codesesh 1.0.7 → 1.0.9
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 +17 -1
- package/dist/{chunk-WIWK7BXS.js → chunk-5YY675UR.js} +25 -26
- package/dist/chunk-5YY675UR.js.map +1 -0
- package/dist/{chunk-VVCSQU5B.js → chunk-CIMPLUT6.js} +6 -6
- package/dist/chunk-CIMPLUT6.js.map +1 -0
- package/dist/{chunk-QHWSZFRM.js → chunk-MOZLVHCC.js} +23 -5
- package/dist/chunk-MOZLVHCC.js.map +1 -0
- package/dist/{chunk-DE6UJMOY.js → chunk-QFG33PKR.js} +3 -2
- package/dist/chunk-QFG33PKR.js.map +1 -0
- package/dist/{chunk-YEQTRALH.js → chunk-RDTQ2WPR.js} +3 -3
- package/dist/chunk-RDTQ2WPR.js.map +1 -0
- package/dist/{chunk-SII3M66U.js → chunk-ZDH2BKQK.js} +701 -9
- package/dist/chunk-ZDH2BKQK.js.map +1 -0
- package/dist/{chunk-EYZ73CYP.js → chunk-ZLU7ODBV.js} +2 -2
- package/dist/{discovery-4WAEYSTR.js → discovery-MS2ZSMZ5.js} +5 -5
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/project-identity-worker.js +4 -4
- package/dist/scan-refresh-worker.js +6 -6
- package/dist/search-index-worker.js +6 -6
- package/dist/session-detail-worker.js +6 -6
- package/dist/smart-tag-worker.js +3 -3
- package/dist/web/assets/CustomTimeWindowDialog-CGPvUFkc.js +1 -0
- package/dist/web/assets/DetailLanding-Dgb2Qg8H.js +1 -0
- package/dist/web/assets/DialogTitle-B8zPwJB8.js +1 -0
- package/dist/web/assets/InteractiveReceipt-SckXLiPB.js +1 -0
- package/dist/web/assets/OverviewScreen-D44AMeDu.js +1 -0
- package/dist/web/assets/PrismHighlighter-D7JLjKja.js +6 -0
- package/dist/web/assets/Projects-DVHOqH2Z.js +1 -0
- package/dist/web/assets/SearchResultsPanel-B1WEw9Q5.js +1 -0
- package/dist/web/assets/SessionDetail-J00I4QfE.js +53 -0
- package/dist/web/assets/SmartTagChips-BMP9pPRw.js +1 -0
- package/dist/web/assets/{api-ToidoNW6.js → api-CtZGdxlN.js} +1 -1
- package/dist/web/assets/index-BIpTq_7T.js +1423 -0
- package/dist/web/assets/index-BXhaumu7.css +1 -0
- package/dist/web/assets/jsx-runtime-D3jfb0Ew.js +1 -0
- package/dist/web/assets/panel-B-5dVddJ.js +1 -0
- package/dist/web/assets/session-indexes-3LjxBYNe.js +4 -0
- package/dist/web/assets/translate-CLoII3EO.js +2 -0
- package/dist/web/assets/utils-BuYa9y6l.js +1 -0
- package/dist/web/icon/agent/cherrystudio.svg +7 -0
- package/dist/web/icon/agent/deepchat.LICENSE.txt +206 -0
- package/dist/web/icon/agent/deepchat.svg +6 -0
- package/dist/web/index.html +10 -196
- package/package.json +3 -3
- package/dist/chunk-DE6UJMOY.js.map +0 -1
- package/dist/chunk-QHWSZFRM.js.map +0 -1
- package/dist/chunk-SII3M66U.js.map +0 -1
- package/dist/chunk-VVCSQU5B.js.map +0 -1
- package/dist/chunk-WIWK7BXS.js.map +0 -1
- package/dist/chunk-YEQTRALH.js.map +0 -1
- package/dist/web/assets/CustomTimeWindowDialog-CVURkiVO.js +0 -1
- package/dist/web/assets/InteractiveReceipt-DGC-xV7U.js +0 -1
- package/dist/web/assets/OverviewScreen-DoXrZ5qp.js +0 -1
- package/dist/web/assets/PrismHighlighter-02695Lmx.js +0 -6
- package/dist/web/assets/Projects-DZiYh6hp.js +0 -1
- package/dist/web/assets/SearchResultsPanel-CAQe8Di0.js +0 -1
- package/dist/web/assets/SessionDetail-Da8EBygt.js +0 -53
- package/dist/web/assets/index-Bl8pbRFj.js +0 -1423
- package/dist/web/assets/index-CRI1m3xN.css +0 -1
- package/dist/web/assets/jsx-runtime-B-hcVAMW.js +0 -1
- package/dist/web/assets/session-indexes-D5gps7K8.js +0 -4
- package/dist/web/assets/translate-BDFu3ZiK.js +0 -2
- package/dist/web/assets/utils-BIZi2up3.js +0 -1
- /package/dist/{chunk-EYZ73CYP.js.map → chunk-ZLU7ODBV.js.map} +0 -0
- /package/dist/{discovery-4WAEYSTR.js.map → discovery-MS2ZSMZ5.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../core/src/discovery/cache/version.ts","../../core/src/discovery/cache/db.ts","../../core/src/discovery/cache/errors.ts","../../core/src/discovery/cache/publication-staging.ts","../../core/src/discovery/cache/content-migrations.ts","../../core/src/discovery/cache/messages.ts","../../core/src/discovery/cache/schema-definitions.ts","../../core/src/discovery/cache/schema-fts.ts","../../core/src/discovery/cache/schema-version.ts","../../core/src/discovery/cache/schema.ts","../../core/src/discovery/cache/connection.ts","../../core/src/discovery/cache/analytics-revision.ts","../../core/src/discovery/cache/detail-version.ts","../../core/src/discovery/cache/search-index-state.ts","../../core/src/discovery/cache/message-cursor.ts","../../core/src/discovery/cache/session-materialization-writer.ts","../../core/src/discovery/cache/search-index-writer.ts","../../core/src/discovery/cache/session-scope.ts","../../core/src/discovery/cache/search-query-parser.ts","../../core/src/discovery/cache/search.ts","../../core/src/discovery/cache/file-activity.ts","../../core/src/discovery/session-scope.ts","../../core/src/discovery/cache/sessions.ts","../../core/src/discovery/orchestrate.ts","../../core/src/discovery/session-tags.ts","../../core/src/discovery/agent-scan-plan.ts","../../core/src/discovery/scanner.ts","../../core/src/discovery/session-detail.ts","../../core/src/discovery/cache/project-groups.ts","../../core/src/discovery/cache/cost-facts.ts","../../core/src/discovery/cache/model-cost.ts","../../core/src/discovery/cache/publication.ts","../../core/src/discovery/cache/active-hours.ts"],"sourcesContent":["export const CACHE_SCHEMA_VERSION = 34;\n","/** Cache paths, process-local connections, and shared query helpers. */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport { openDb, type DatabaseRow, type SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { SessionHead } from \"../../types/index.js\";\nimport { normalizeProjectScopePath } from \"../../projects/scope.js\";\n\nconst CACHE_FILENAME = \"codesesh.db\";\nconst LEGACY_CACHE_FILENAME = \"scan-cache.json\";\nexport const SEARCH_INDEX_BULK_SYNC_THRESHOLD = 100;\n\nexport interface PersistedSessionHeadChange<T extends SessionHead = SessionHead> {\n session: T;\n sortIndex: number;\n}\n\nexport interface ScalarRow extends DatabaseRow {\n value?: number;\n}\n\nexport interface CacheRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n session_json?: string;\n meta_json?: string | null;\n sort_index?: number;\n}\n\nexport type SQLiteStatement = ReturnType<SQLiteDatabase[\"prepare\"]>;\n\nexport interface CacheConnection {\n db: SQLiteDatabase;\n ftsReady: boolean;\n publicationStagingCleaned: boolean;\n}\n\nconst cacheConnections = new Map<string, CacheConnection>();\nlet schemaEnsuredPath: string | null = null;\n\nexport function getCacheConnection(path: string): CacheConnection | null {\n const cached = cacheConnections.get(path);\n if (cached) return cached;\n\n const db = openDb(path);\n if (!db) return null;\n db.function(\"codesesh_project_scope_path\", { deterministic: true }, (directory) =>\n normalizeProjectScopePath(String(directory ?? \"\")),\n );\n\n const connection = { db, ftsReady: false, publicationStagingCleaned: false };\n cacheConnections.set(path, connection);\n return connection;\n}\n\nexport function discardCacheConnection(path: string, connection: CacheConnection): void {\n if (cacheConnections.get(path) !== connection) return;\n cacheConnections.delete(path);\n closeConnection(path, connection);\n}\n\nfunction closeConnection(path: string, connection: CacheConnection): void {\n try {\n connection.db.close();\n } catch (error) {\n getCoreDiagnostics()?.warn(\"cache.close_failed\", {\n dbPath: path,\n message: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nexport function closeCacheStorage(): void {\n const connections = [...cacheConnections];\n cacheConnections.clear();\n schemaEnsuredPath = null;\n for (const [path, connection] of connections) closeConnection(path, connection);\n}\n\nexport function getSchemaEnsuredPath(): string | null {\n return schemaEnsuredPath;\n}\n\nexport function setSchemaEnsuredPath(path: string | null): void {\n if (path === null) {\n closeCacheStorage();\n return;\n }\n schemaEnsuredPath = path;\n}\n\nexport function getCacheDir(): string {\n return join(homedir(), \".cache\", \"codesesh\");\n}\n\nexport function getCachePath(): string {\n return join(getCacheDir(), CACHE_FILENAME);\n}\n\nexport function getLegacyCachePath(): string {\n return join(getCacheDir(), LEGACY_CACHE_FILENAME);\n}\n\nexport function hasCacheStorage(): boolean {\n return existsSync(getCachePath());\n}\n\nexport function likePattern(value: string): string {\n return `%${value\n .trim()\n .toLowerCase()\n .replace(/[\\\\%_]/g, \"\\\\$&\")}%`;\n}\n\nexport function filePathFtsQuery(value: string): string | null {\n const path = normalizeFilePathSearch(value);\n if (path.length < 3) return null;\n return `\"${path.replaceAll('\"', '\"\"')}\"`;\n}\n\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport function normalizeFilePathSearch(value: string): string {\n return value.trim().replace(/^\"|\"$/g, \"\");\n}\n","export class CacheDataIntegrityError extends Error {\n readonly code = \"CACHE_DATA_INTEGRITY\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"CacheDataIntegrityError\";\n }\n}\n\nexport class UnsupportedCacheSchemaVersionError extends Error {\n constructor(\n readonly currentVersion: number,\n readonly supportedVersion: number,\n ) {\n super(\n `Cache schema version ${currentVersion} is newer than supported version ${supportedVersion}`,\n );\n this.name = \"UnsupportedCacheSchemaVersionError\";\n }\n}\n","import type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\n\ninterface StagedPublicationRow extends DatabaseRow {\n session_id?: string;\n payload_json?: string;\n}\n\nconst PUBLICATION_READ_BATCH_SIZE = 64;\nconst STAGING_TABLE = \"temp.search_index_publication_entries\";\n\nexport interface PublicationPayload {\n sessionId: string;\n json: string;\n}\n\n/**\n * Staged payloads are scratch for one in-process publication — nothing resumes\n * one across processes. Holding them in the connection's TEMP schema makes an\n * orphan unrepresentable: an abrupt exit returns the bytes to the OS instead of\n * leaving a corpus-sized copy inside the durable cache for a sweeper to find.\n */\nfunction ensureStagingTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TEMP TABLE IF NOT EXISTS search_index_publication_entries (\n publication_id TEXT NOT NULL,\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n payload_json TEXT NOT NULL,\n PRIMARY KEY (publication_id, agent_name, session_id)\n );\n `);\n}\n\nexport function stagePublicationPayloads(\n db: SQLiteDatabase,\n publicationId: string,\n agentName: string,\n payloads: Iterable<PublicationPayload>,\n): number {\n ensureStagingTable(db);\n const upsert = db.prepare(`\n INSERT INTO ${STAGING_TABLE}(\n publication_id,\n agent_name,\n session_id,\n payload_json\n ) VALUES (?, ?, ?, ?)\n ON CONFLICT(publication_id, agent_name, session_id) DO UPDATE SET\n payload_json = excluded.payload_json\n `);\n let staged = 0;\n for (const payload of payloads) {\n upsert.run(publicationId, agentName, payload.sessionId, payload.json);\n staged += 1;\n }\n return staged;\n}\n\n/**\n * Deliberately does not create the table: staging and commit must share one\n * connection, so a missing temp schema means that invariant broke and must fail\n * loudly instead of silently indexing nothing.\n */\nexport function* readPublicationPayloads(\n db: SQLiteDatabase,\n publicationId: string,\n agentName: string,\n): Generator<string> {\n const readBatch = db.prepare(`\n SELECT session_id, payload_json\n FROM ${STAGING_TABLE}\n WHERE publication_id = ? AND agent_name = ? AND session_id > ?\n ORDER BY session_id\n LIMIT ?\n `);\n let cursor = \"\";\n while (true) {\n const rows = readBatch.all(\n publicationId,\n agentName,\n cursor,\n PUBLICATION_READ_BATCH_SIZE,\n ) as StagedPublicationRow[];\n if (rows.length === 0) return;\n for (const row of rows) yield String(row.payload_json ?? \"\");\n cursor = String(rows.at(-1)?.session_id ?? \"\");\n }\n}\n\nexport function deletePublicationPayloads(\n db: SQLiteDatabase,\n publicationId: string,\n agentName: string,\n): void {\n ensureStagingTable(db);\n db.prepare(`DELETE FROM ${STAGING_TABLE} WHERE publication_id = ? AND agent_name = ?`).run(\n publicationId,\n agentName,\n );\n}\n\nexport function hasLegacyPublicationRows(db: SQLiteDatabase, publicationId?: string): boolean {\n const predicate = publicationId ? \"publication_id = ?\" : \"publication_id IS NOT NULL\";\n const params = publicationId ? [publicationId] : [];\n return (\n db.prepare(`SELECT 1 FROM sessions WHERE ${predicate} LIMIT 1`).get(...params) !== undefined\n );\n}\n\nexport function deleteLegacyPublicationRows(db: SQLiteDatabase, publicationId?: string): void {\n // Schema v21 could leave staged heads and their live detail rows after an interruption.\n const predicate = publicationId\n ? \"staged.publication_id = ?\"\n : \"staged.publication_id IS NOT NULL\";\n const params = publicationId ? [publicationId] : [];\n for (const [table, alias] of [\n [\"message_tools\", \"target\"],\n [\"messages\", \"target\"],\n [\"session_file_activity\", \"target\"],\n [\"session_documents\", \"target\"],\n [\"pending_reindex\", \"target\"],\n ] as const) {\n db.prepare(`\n DELETE FROM ${table} AS ${alias}\n WHERE EXISTS (\n SELECT 1\n FROM sessions AS staged\n WHERE staged.agent_name = ${alias}.agent_name\n AND staged.session_id = ${alias}.session_id\n AND ${predicate}\n )\n `).run(...params);\n }\n db.prepare(\n publicationId\n ? \"DELETE FROM sessions WHERE publication_id = ?\"\n : \"DELETE FROM sessions WHERE publication_id IS NOT NULL\",\n ).run(...params);\n}\n\nexport function discardPublicationStaging(\n db: SQLiteDatabase,\n publicationId: string,\n agentName: string,\n): void {\n if (hasLegacyPublicationRows(db, publicationId)) {\n deleteLegacyPublicationRows(db, publicationId);\n }\n deletePublicationPayloads(db, publicationId, agentName);\n}\n","import { tableExists, type SQLiteDatabase } from \"../../utils/sqlite.js\";\n\ninterface CacheContentMigration {\n readonly key: string;\n readonly apply: (db: SQLiteDatabase) => void;\n}\n\nconst CACHE_CONTENT_MIGRATIONS: readonly CacheContentMigration[] = [\n {\n key: \"pi_automated_messages_v1\",\n apply(db) {\n if (!tableExists(db, \"sessions\") || !tableExists(db, \"pending_reindex\")) return;\n db.exec(\n \"INSERT OR IGNORE INTO pending_reindex(agent_name, session_id) SELECT agent_name, session_id FROM sessions WHERE agent_name = 'pi'\",\n );\n },\n },\n {\n key: \"codex_exec_decode_migrated_v3\",\n apply(db) {\n if (!tableExists(db, \"sessions\") || !tableExists(db, \"pending_reindex\")) return;\n // Head hashes stay stable when only detail decoding changes, so queue targeted rebuilds.\n db.exec(\n \"INSERT OR IGNORE INTO pending_reindex(agent_name, session_id) \" +\n \"SELECT agent_name, session_id FROM sessions WHERE agent_name = 'codex'\",\n );\n },\n },\n {\n key: \"opencode_subagent_fold_v1\",\n apply(db) {\n if (!tableExists(db, \"agent_cache\")) return;\n db.prepare(\"DELETE FROM agent_cache WHERE agent_name IN ('zcode', 'opencode')\").run();\n },\n },\n {\n key: \"subagent_tree_v1\",\n apply(db) {\n if (!tableExists(db, \"agent_cache\")) return;\n db.prepare(\n \"DELETE FROM agent_cache WHERE agent_name IN ('codex', 'zcode', 'opencode')\",\n ).run();\n },\n },\n];\n\nexport function runCacheContentMigrations(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cache_meta\")) return;\n\n const readMarker = db.prepare(\"SELECT value FROM cache_meta WHERE key = ?\");\n const writeMarker = db.prepare(\n \"INSERT INTO cache_meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'\",\n );\n\n for (const migration of CACHE_CONTENT_MIGRATIONS) {\n if (readMarker.get(migration.key)) continue;\n migration.apply(db);\n writeMarker.run(migration.key);\n }\n}\n","/**\n * Structured message storage: row ↔ domain mapping, prepared-statement\n * binders, and message-text builders shared by sessions/search/file-activity.\n */\nimport type { SessionCacheMeta } from \"../../agents/session-source-types.js\";\nimport { assertIdentifiedSessionHead } from \"../../contract/session.js\";\nimport type {\n IdentifiedSessionHead,\n Message,\n MessagePart,\n ProjectIdentity,\n ProjectIdentityKind,\n SessionDetail,\n SessionFileActivity,\n SessionHead,\n ToolPart,\n} from \"../../types/index.js\";\nimport { normalizeMessageParts } from \"../../contract/message-part.js\";\nimport { assertSessionIdentity, createSessionIdentity } from \"../../contract/session-reference.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { SQLiteStatement } from \"./db.js\";\nimport { CacheDataIntegrityError } from \"./errors.js\";\nimport type { MessageCursorContent } from \"./message-cursor.js\";\n\nexport const MESSAGE_PARTS_FORMAT_VERSION = 1;\n\nexport interface SessionRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n sort_index?: number;\n title?: string;\n source_path?: string | null;\n directory?: string;\n parent_agent_name?: string | null;\n parent_session_id?: string | null;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n project_identity_resolver_revision?: string | null;\n project_identity_input_signature?: string | null;\n time_created?: number;\n time_updated?: number | null;\n activity_time?: number;\n message_count?: number;\n total_input_tokens?: number;\n total_output_tokens?: number;\n total_cache_read_tokens?: number | null;\n total_cache_create_tokens?: number | null;\n total_cost?: number;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"] | null;\n total_tokens?: number | null;\n model_usage_json?: string | null;\n smart_tags_json?: string | null;\n smart_tags_source_updated_at?: number | null;\n smart_tags_classifier_revision?: string | null;\n meta_json?: string | null;\n}\n\nexport interface MessageBackfillRow extends DatabaseRow {\n message_id?: string;\n role?: Message[\"role\"];\n time_created?: number;\n time_completed?: number | null;\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n parts_json?: string;\n subagent_id?: string | null;\n nickname?: string | null;\n automated?: number;\n}\n\nexport interface CachedMessageRow extends MessageBackfillRow {\n parts_format_version?: number | string;\n content_chain_digest?: string | null;\n tokens_json?: string | null;\n cost?: number | null;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"] | null;\n}\n\nexport interface StructuredMessageRecord {\n index: number;\n id: string;\n role: Message[\"role\"];\n timeCreated: number;\n timeCompleted?: number | null;\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n tokensJson?: string | null;\n cost?: number | null;\n costSource?: string | null;\n partsJson: string;\n subagentId?: string | null;\n nickname?: string | null;\n automated?: number;\n contentText: string;\n toolMetadataJson?: string | null;\n toolNames: string[];\n}\n\nexport function messageCursorContentFromCachedRow(row: CachedMessageRow): MessageCursorContent {\n return {\n messageId: String(row.message_id),\n role: String(row.role),\n timeCreated: Number(row.time_created),\n timeCompleted: row.time_completed,\n agent: row.agent,\n mode: row.mode,\n model: row.model,\n provider: row.provider,\n tokensJson: row.tokens_json,\n cost: row.cost,\n costSource: row.cost_source,\n partsJson: String(row.parts_json),\n partsFormatVersion: row.parts_format_version,\n subagentId: row.subagent_id,\n nickname: row.nickname,\n automated: row.automated,\n };\n}\n\nexport function messageCursorContentFromStructuredRecord(\n record: StructuredMessageRecord,\n): MessageCursorContent {\n return {\n messageId: record.id,\n role: record.role,\n timeCreated: record.timeCreated,\n timeCompleted: record.timeCompleted,\n agent: record.agent,\n mode: record.mode,\n model: record.model,\n provider: record.provider,\n tokensJson: record.tokensJson,\n cost: record.cost,\n costSource: record.costSource,\n partsJson: record.partsJson,\n partsFormatVersion: MESSAGE_PARTS_FORMAT_VERSION,\n subagentId: record.subagentId,\n nickname: record.nickname,\n automated: record.automated,\n };\n}\n\nexport function stringifyOptionalJson(value: unknown): string | null {\n return value == null ? null : JSON.stringify(value);\n}\n\nexport function parseOptionalJson<T>(value: unknown): T | undefined {\n if (value == null) return undefined;\n try {\n return JSON.parse(String(value)) as T;\n } catch (error) {\n throw new CacheDataIntegrityError(\"Cached JSON field is malformed\", { cause: error });\n }\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 try {\n const meta = JSON.parse(metaJson) as SessionCacheMeta;\n return sourcePathFromMeta(meta);\n } catch (error) {\n throw new CacheDataIntegrityError(\"Cached session metadata is malformed\", { cause: error });\n }\n}\n\nexport function requireSessionProjectIdentity(\n agentName: string,\n session: SessionHead,\n): ProjectIdentity {\n assertSessionIdentity(session, agentName);\n assertIdentifiedSessionHead(session);\n return session.project_identity;\n}\n\nexport function assertSessionProjectIdentities(\n agentName: string,\n sessions: Iterable<SessionHead>,\n): void {\n for (const session of sessions) requireSessionProjectIdentity(agentName, session);\n}\n\nexport function prepareUpsertSession(\n db: SQLiteDatabase,\n mode: \"cache\" | \"materialization\" = \"cache\",\n): SQLiteStatement {\n const cacheAssignments =\n mode === \"cache\"\n ? `sort_index = excluded.sort_index,\n source_path = CASE\n WHEN excluded.meta_json IS NULL THEN sessions.source_path\n ELSE excluded.source_path\n END,\n meta_json = COALESCE(excluded.meta_json, sessions.meta_json),`\n : \"\";\n return db.prepare(`\n INSERT INTO sessions(\n agent_name,\n session_id,\n sort_index,\n title,\n source_path,\n directory,\n parent_agent_name,\n parent_session_id,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n project_identity_resolver_revision,\n project_identity_input_signature,\n time_created,\n time_updated,\n activity_time,\n message_count,\n total_input_tokens,\n total_output_tokens,\n total_cache_read_tokens,\n total_cache_create_tokens,\n total_cost,\n cost_source,\n total_tokens,\n model_usage_json,\n smart_tags_json,\n smart_tags_source_updated_at,\n smart_tags_classifier_revision,\n meta_json,\n publication_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n ${cacheAssignments}\n title = excluded.title,\n directory = excluded.directory,\n parent_agent_name = excluded.parent_agent_name,\n parent_session_id = excluded.parent_session_id,\n project_identity_kind = excluded.project_identity_kind,\n project_identity_key = excluded.project_identity_key,\n project_display_name = excluded.project_display_name,\n project_identity_resolver_revision = excluded.project_identity_resolver_revision,\n project_identity_input_signature = excluded.project_identity_input_signature,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n activity_time = excluded.activity_time,\n message_count = excluded.message_count,\n total_input_tokens = excluded.total_input_tokens,\n total_output_tokens = excluded.total_output_tokens,\n total_cache_read_tokens = excluded.total_cache_read_tokens,\n total_cache_create_tokens = excluded.total_cache_create_tokens,\n total_cost = excluded.total_cost,\n cost_source = excluded.cost_source,\n total_tokens = excluded.total_tokens,\n model_usage_json = excluded.model_usage_json,\n smart_tags_json = excluded.smart_tags_json,\n smart_tags_source_updated_at = excluded.smart_tags_source_updated_at,\n smart_tags_classifier_revision = excluded.smart_tags_classifier_revision,\n publication_id = excluded.publication_id\n `);\n}\n\nexport function upsertSessionRow(\n statement: SQLiteStatement,\n agentName: string,\n session: SessionHead,\n metaJson: string | null,\n sortIndex: number,\n sourcePath: string | null,\n): void {\n const identity = requireSessionProjectIdentity(agentName, session);\n const activityTime = session.time_updated ?? session.time_created;\n statement.run(\n session.reference.agentName,\n session.reference.sessionId,\n sortIndex,\n session.title,\n sourcePath,\n session.directory,\n session.parent_reference?.agentName ?? null,\n session.parent_reference?.sessionId ?? null,\n identity.kind,\n identity.key,\n identity.displayName,\n session.project_identity_resolver_revision ?? null,\n session.project_identity_input_signature ?? null,\n session.time_created,\n session.time_updated ?? null,\n activityTime,\n session.stats.message_count,\n session.stats.total_input_tokens,\n session.stats.total_output_tokens,\n session.stats.total_cache_read_tokens ?? null,\n session.stats.total_cache_create_tokens ?? null,\n session.stats.total_cost,\n session.stats.cost_source ?? null,\n session.stats.total_tokens ?? null,\n stringifyOptionalJson(session.model_usage),\n stringifyOptionalJson(session.smart_tags),\n session.smart_tags_source_updated_at ?? null,\n session.smart_tags_classifier_revision ?? null,\n metaJson,\n null,\n );\n}\n\nexport function prepareInsertFileActivity(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT INTO session_file_activity(\n agent_name,\n session_id,\n project_identity_key,\n path,\n kind,\n count,\n latest_time\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n}\n\nexport function prepareInsertMessageTool(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT OR IGNORE INTO message_tools(\n agent_name,\n session_id,\n message_index,\n tool_name\n ) VALUES (?, ?, ?, ?)\n `);\n}\n\nexport function writeFileActivityRows(\n statement: SQLiteStatement,\n activities: SessionFileActivity[],\n): void {\n for (const activity of activities) {\n statement.run(\n activity.reference.agentName,\n activity.reference.sessionId,\n activity.projectIdentityKey,\n activity.path,\n activity.kind,\n activity.count,\n activity.latestTime,\n );\n }\n}\n\nexport function sessionFromRow(row: SessionRow): IdentifiedSessionHead {\n const session: SessionHead = {\n ...createSessionIdentity({\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n }),\n title: String(row.title),\n directory: String(row.directory),\n time_created: Number(row.time_created),\n stats: {\n message_count: Number(row.message_count ?? 0),\n total_input_tokens: Number(row.total_input_tokens ?? 0),\n total_output_tokens: Number(row.total_output_tokens ?? 0),\n total_cost: Number(row.total_cost ?? 0),\n },\n };\n\n if (row.project_identity_key) {\n session.project_identity = {\n kind: row.project_identity_kind ?? \"path\",\n key: String(row.project_identity_key),\n displayName: String(row.project_display_name ?? \"\"),\n };\n }\n if (row.project_identity_resolver_revision) {\n session.project_identity_resolver_revision = String(row.project_identity_resolver_revision);\n }\n if (row.project_identity_input_signature) {\n session.project_identity_input_signature = String(row.project_identity_input_signature);\n }\n if (row.parent_agent_name && row.parent_session_id) {\n session.parent_reference = {\n agentName: String(row.parent_agent_name),\n sessionId: String(row.parent_session_id),\n };\n }\n if (row.time_updated != null) {\n session.time_updated = Number(row.time_updated);\n }\n if (row.total_cache_read_tokens != null) {\n session.stats.total_cache_read_tokens = Number(row.total_cache_read_tokens);\n }\n if (row.total_cache_create_tokens != null) {\n session.stats.total_cache_create_tokens = Number(row.total_cache_create_tokens);\n }\n if (row.cost_source) {\n session.stats.cost_source = row.cost_source;\n }\n if (row.total_tokens != null) {\n session.stats.total_tokens = Number(row.total_tokens);\n }\n\n const modelUsage = parseOptionalJson<Record<string, number>>(row.model_usage_json);\n if (modelUsage) {\n session.model_usage = modelUsage;\n }\n\n const smartTags = parseOptionalJson<SessionHead[\"smart_tags\"]>(row.smart_tags_json);\n if (smartTags) {\n session.smart_tags = smartTags;\n }\n if (row.smart_tags_source_updated_at != null) {\n session.smart_tags_source_updated_at = Number(row.smart_tags_source_updated_at);\n }\n if (row.smart_tags_classifier_revision) {\n session.smart_tags_classifier_revision = String(row.smart_tags_classifier_revision);\n }\n\n try {\n assertIdentifiedSessionHead(session);\n } catch (error) {\n throw new CacheDataIntegrityError(\"Cached session identity is incomplete\", { cause: error });\n }\n return session;\n}\n\nfunction messageMetadataFromBackfillRow(row: MessageBackfillRow): Omit<Message, \"parts\"> {\n const role = row.role === \"assistant\" || row.role === \"tool\" ? row.role : \"user\";\n return {\n id: String(row.message_id ?? \"\"),\n role,\n agent: row.agent ?? null,\n time_created: Number(row.time_created ?? 0),\n time_completed: row.time_completed == null ? null : Number(row.time_completed),\n mode: row.mode ?? null,\n model: row.model ?? null,\n provider: row.provider ?? null,\n subagent_id: row.subagent_id ?? undefined,\n nickname: row.nickname ?? undefined,\n ...(row.automated ? { automated: true } : {}),\n };\n}\n\nfunction messageMetadataFromCachedRow(row: CachedMessageRow): Omit<Message, \"parts\"> {\n const message = messageMetadataFromBackfillRow(row);\n const tokens = parseOptionalJson<Message[\"tokens\"]>(row.tokens_json);\n if (tokens) {\n message.tokens = tokens;\n }\n if (row.cost != null) {\n message.cost = Number(row.cost);\n }\n if (row.cost_source) {\n message.cost_source = row.cost_source;\n }\n return message;\n}\n\nexport function messageFromBackfillRow(row: MessageBackfillRow): Message {\n return {\n ...messageMetadataFromBackfillRow(row),\n parts: messagePartsFromJson(row.parts_json),\n };\n}\n\nexport function messageFromCachedRow(row: CachedMessageRow): Message {\n return {\n ...messageMetadataFromCachedRow(row),\n parts: messagePartsFromJson(row.parts_json),\n };\n}\n\nfunction messagePartsFromJson(value: unknown): MessagePart[] {\n try {\n return normalizeMessageParts(JSON.parse(String(value ?? \"[]\")));\n } catch {\n return [];\n }\n}\n\nexport function normalizeMessagePartsJson(value: unknown): string {\n return JSON.stringify(messagePartsFromJson(value));\n}\n\nexport function messageJsonFromCachedRow(row: CachedMessageRow): string {\n const metadataJson = JSON.stringify(messageMetadataFromBackfillRow(row));\n const fields: string[] = [];\n if (row.tokens_json != null) {\n fields.push(`\"tokens\":${String(row.tokens_json)}`);\n }\n if (row.cost != null) {\n fields.push(`\"cost\":${JSON.stringify(Number(row.cost))}`);\n }\n if (row.cost_source) {\n fields.push(`\"cost_source\":${JSON.stringify(row.cost_source)}`);\n }\n const partsJson =\n Number(row.parts_format_version) >= MESSAGE_PARTS_FORMAT_VERSION\n ? String(row.parts_json ?? \"[]\")\n : normalizeMessagePartsJson(row.parts_json);\n fields.push(`\"parts\":${partsJson}`);\n return `${metadataJson.slice(0, -1)},${fields.join(\",\")}}`;\n}\n\nexport function appendPlainText(value: unknown, chunks: string[]): void {\n if (value == null) return;\n\n if (typeof value === \"string\") {\n const normalized = value.trim();\n if (normalized) {\n chunks.push(normalized);\n }\n return;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n chunks.push(String(value));\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n appendPlainText(item, chunks);\n }\n return;\n }\n\n if (typeof value === \"object\") {\n for (const nested of Object.values(value as Record<string, unknown>)) {\n appendPlainText(nested, chunks);\n }\n }\n}\n\nexport function compactRecord(record: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(record).filter(([, value]) => value != null));\n}\n\nexport function normalizeToolName(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const name = value.trim().toLowerCase();\n return name || null;\n}\n\nexport function toolNamesFromMetadataJson(value: unknown): string[] {\n if (!value) return [];\n\n try {\n const metadata = JSON.parse(String(value));\n if (!Array.isArray(metadata)) return [];\n const tools = new Set<string>();\n for (const item of metadata) {\n if (item == null || typeof item !== \"object\") continue;\n const toolName = normalizeToolName((item as Record<string, unknown>).tool);\n if (toolName) tools.add(toolName);\n }\n return [...tools];\n } catch {\n return [];\n }\n}\n\nexport function toolNamesFromMessage(message: Message): string[] {\n const tools = new Set<string>();\n for (const part of message.parts) {\n if (part.type !== \"tool\") continue;\n const toolName = normalizeToolName(part.tool);\n if (toolName) tools.add(toolName);\n }\n return [...tools];\n}\n\nexport function summarizeToolPart(part: ToolPart): Record<string, unknown> {\n const state = compactRecord({\n status: part.state.status,\n error: part.state.error,\n metadata: part.state.metadata,\n });\n return compactRecord({\n type: part.type,\n tool: part.tool,\n title: part.title,\n callID: part.callID,\n state,\n });\n}\n\nexport function buildMessageText(message: Message): string {\n const chunks: string[] = [];\n\n chunks.push(message.role);\n appendPlainText(message.agent, chunks);\n appendPlainText(message.model, chunks);\n\n for (const part of message.parts) {\n appendPlainText(part.type, chunks);\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"plan\") {\n appendPlainText(part.text, chunks);\n } else if (part.type === \"tool\") {\n appendPlainText(part.title, chunks);\n appendPlainText(part.tool, chunks);\n appendPlainText(part.state, chunks);\n }\n }\n\n return chunks.join(\"\\n\");\n}\n\nexport function normalizeMessages(session: SessionDetail): StructuredMessageRecord[] {\n return session.messages.map((message, index) => {\n const toolMetadata = message.parts\n .filter((part): part is ToolPart => part.type === \"tool\")\n .map((part) => summarizeToolPart(part));\n\n return {\n index,\n id: message.id || `${session.reference.sessionId}:${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 automated: message.automated ? 1 : 0,\n contentText: buildMessageText(message),\n toolMetadataJson: toolMetadata.length > 0 ? JSON.stringify(toolMetadata) : null,\n toolNames: toolNamesFromMessage(message),\n };\n });\n}\n\nexport function buildSessionContentFromMessages(\n title: string | null | undefined,\n messages: StructuredMessageRecord[],\n): string {\n const chunks: string[] = [];\n appendPlainText(title, chunks);\n for (const message of messages) {\n appendPlainText(message.contentText, chunks);\n }\n return chunks.join(\"\\n\");\n}\n","import { columnExists, tableExists, type SQLiteDatabase } from \"../../utils/sqlite.js\";\n\nexport function createCacheMetadataTables(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 cache_initialization (\n agent_name TEXT PRIMARY KEY,\n initialized_at INTEGER NOT NULL,\n index_version TEXT NOT NULL,\n last_sync_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS pending_reindex (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\n}\n\nexport function createLegacyCacheTables(db: SQLiteDatabase): void {\n createCacheMetadataTables(db);\n db.exec(`\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}\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 title TEXT NOT NULL,\n source_path TEXT,\n directory TEXT NOT NULL,\n parent_agent_name TEXT,\n parent_session_id TEXT,\n project_identity_kind TEXT NOT NULL,\n project_identity_key TEXT NOT NULL,\n project_display_name TEXT NOT NULL,\n project_identity_resolver_revision TEXT,\n project_identity_input_signature TEXT,\n time_created INTEGER NOT NULL,\n time_updated INTEGER,\n activity_time INTEGER NOT NULL,\n message_count INTEGER NOT NULL,\n total_input_tokens INTEGER NOT NULL,\n total_output_tokens INTEGER NOT NULL,\n total_cache_read_tokens INTEGER,\n total_cache_create_tokens INTEGER,\n total_cost REAL NOT NULL,\n cost_source TEXT,\n total_tokens INTEGER,\n model_usage_json TEXT,\n smart_tags_json TEXT,\n smart_tags_source_updated_at INTEGER,\n smart_tags_classifier_revision TEXT,\n meta_json TEXT,\n publication_id TEXT,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_sessions_agent_activity_order\n ON sessions(agent_name, activity_time DESC, session_id);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_activity\n ON sessions(activity_time DESC, agent_name, session_id);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_project\n ON sessions(project_identity_kind, project_identity_key, activity_time);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_parent\n ON sessions(parent_agent_name, parent_session_id);\n\n CREATE TABLE IF NOT EXISTS messages (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_index INTEGER NOT NULL,\n message_id TEXT NOT NULL,\n role TEXT NOT NULL,\n time_created INTEGER NOT NULL,\n time_completed INTEGER,\n agent TEXT,\n mode TEXT,\n model TEXT,\n provider TEXT,\n tokens_json TEXT,\n cost REAL,\n cost_source TEXT,\n parts_json TEXT NOT NULL,\n parts_format_version INTEGER NOT NULL DEFAULT 0,\n content_chain_digest TEXT,\n subagent_id TEXT,\n nickname TEXT,\n automated INTEGER NOT NULL DEFAULT 0,\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 createMessageUsageIndex(db);\n createSessionModelCostTable(db);\n createSessionCostSummaryTable(db);\n createMessageToolTables(db);\n}\n\nexport function createMessageUsageIndex(db: SQLiteDatabase): void {\n // Keep analytics reads off message rows containing large transcript payloads.\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_usage_time\n ON messages(\n CASE\n WHEN time_completed > 0 THEN time_completed\n WHEN time_created > 0 THEN time_created\n END,\n agent_name,\n session_id,\n message_index,\n model,\n tokens_json,\n cost,\n cost_source\n );\n `);\n}\n\n/**\n * Per-(session, model) cost rollup maintained in the same transaction that\n * writes message rows, so dashboard model-cost aggregation reads\n * sessions×models rows instead of scanning the full messages table (CS-270).\n */\nexport function createSessionModelCostTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_model_cost (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n model TEXT NOT NULL,\n cost REAL NOT NULL,\n cost_recorded REAL NOT NULL,\n PRIMARY KEY (agent_name, session_id, model),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n `);\n}\n\nfunction createSessionCostSummaryTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_cost_summary (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_count INTEGER NOT NULL DEFAULT 0,\n untimed_message_count INTEGER NOT NULL DEFAULT 0,\n input_tokens INTEGER NOT NULL DEFAULT 0,\n output_tokens INTEGER NOT NULL DEFAULT 0,\n reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n cache_read_tokens INTEGER NOT NULL DEFAULT 0,\n cache_create_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_input_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_output_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_cache_read_tokens INTEGER NOT NULL DEFAULT 0,\n untimed_cache_create_tokens INTEGER NOT NULL DEFAULT 0,\n message_cost REAL NOT NULL,\n untimed_message_cost REAL NOT NULL,\n PRIMARY KEY (agent_name, session_id),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n `);\n}\n\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 dropLegacyMessageSearchIndex(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS messages_ai;\n DROP TRIGGER IF EXISTS messages_ad;\n DROP TRIGGER IF EXISTS messages_au;\n DROP TABLE IF EXISTS messages_fts;\n `);\n}\n\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\nfunction createFileActivityPathSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_ai\n AFTER INSERT ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(rowid, path)\n VALUES (new.rowid, new.path);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_ad\n AFTER DELETE ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts, rowid, path)\n VALUES ('delete', old.rowid, old.path);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_au\n AFTER UPDATE ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts, rowid, path)\n VALUES ('delete', old.rowid, old.path);\n INSERT INTO session_file_activity_path_fts(rowid, path)\n VALUES (new.rowid, new.path);\n END;\n `);\n}\n\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 title TEXT NOT NULL,\n content_text TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n indexed_message_count INTEGER NOT NULL,\n detail_version TEXT NOT NULL DEFAULT '',\n indexed_at INTEGER NOT NULL,\n UNIQUE(agent_name, session_id)\n );\n\n CREATE VIRTUAL TABLE IF NOT EXISTS session_documents_fts USING fts5(\n title,\n content_text,\n content='session_documents',\n content_rowid='id'\n );\n `);\n\n createSearchTriggers(db);\n}\n\n/**\n * Covers the search-index freshness probe (see readSearchIndexState) so it never\n * has to read past content_text in the document rows.\n *\n * Created only once the schema has reached the target version: createSearchTables\n * doubles as the v4 migration and still sees the legacy column set there.\n */\nexport function createSearchStateIndex(db: SQLiteDatabase): void {\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_session_documents_state\n ON session_documents(\n agent_name,\n session_id,\n content_hash,\n indexed_message_count,\n detail_version\n )\n `);\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 addIndexedMessageCount(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) return;\n\n if (!columnExists(db, \"session_documents\", \"indexed_message_count\")) {\n db.exec(\n \"ALTER TABLE session_documents ADD COLUMN indexed_message_count INTEGER NOT NULL DEFAULT 0\",\n );\n }\n if (!tableExists(db, \"messages\")) return;\n\n db.exec(`\n UPDATE session_documents\n SET indexed_message_count = (\n SELECT COUNT(*)\n FROM messages\n WHERE messages.agent_name = session_documents.agent_name\n AND messages.session_id = session_documents.session_id\n )\n `);\n}\n\nexport function addDetailVersion(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) return;\n createCacheMetadataTables(db);\n if (!columnExists(db, \"session_documents\", \"detail_version\")) {\n db.exec(\"ALTER TABLE session_documents ADD COLUMN detail_version TEXT NOT NULL DEFAULT ''\");\n }\n if (tableExists(db, \"sessions\") && tableExists(db, \"pending_reindex\")) {\n db.exec(`\n INSERT OR IGNORE INTO pending_reindex(agent_name, session_id)\n SELECT agent_name, session_id FROM sessions\n `);\n }\n}\n\nexport function addProjectIdentityProvenance(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n if (!columnExists(db, \"sessions\", \"project_identity_resolver_revision\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN project_identity_resolver_revision TEXT\");\n }\n if (!columnExists(db, \"sessions\", \"project_identity_input_signature\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN project_identity_input_signature TEXT\");\n }\n if (!columnExists(db, \"sessions\", \"smart_tags_classifier_revision\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN smart_tags_classifier_revision TEXT\");\n }\n}\n\nexport function addSessionPublicationId(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n if (!columnExists(db, \"sessions\", \"publication_id\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN publication_id TEXT\");\n }\n recreateProjectGroupsView(db);\n}\n\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\nconst LEGACY_SESSION_DOCUMENT_COLUMNS = [\n [\"slug\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"directory\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"time_created\", \"INTEGER NOT NULL DEFAULT 0\"],\n [\"time_updated\", \"INTEGER\"],\n [\"activity_time\", \"INTEGER NOT NULL DEFAULT 0\"],\n [\"project_identity_kind\", \"TEXT NOT NULL DEFAULT 'path'\"],\n [\"project_identity_key\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"project_display_name\", \"TEXT NOT NULL DEFAULT ''\"],\n] as const;\n\nexport function ensureLegacySessionDocumentColumns(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) {\n return;\n }\n\n for (const [name, definition] of LEGACY_SESSION_DOCUMENT_COLUMNS) {\n if (!columnExists(db, \"session_documents\", name)) {\n db.exec(`ALTER TABLE session_documents ADD COLUMN ${name} ${definition}`);\n }\n }\n}\n\nexport function createLegacyProjectTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS project_sessions (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n identity_kind TEXT NOT NULL,\n identity_key TEXT NOT NULL,\n display_name TEXT NOT NULL,\n directory TEXT NOT NULL,\n activity_time INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_project_sessions_identity\n ON project_sessions(identity_kind, identity_key);\n `);\n createProjectGroupsView(db);\n}\n\nfunction createProjectGroupsView(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) {\n db.exec(`\n CREATE VIEW IF NOT EXISTS project_groups_v AS\n SELECT\n identity_kind,\n identity_key,\n MIN(display_name) AS display_name,\n GROUP_CONCAT(DISTINCT agent_name) AS sources_csv,\n COUNT(*) AS session_count,\n MAX(activity_time) AS last_activity\n FROM project_sessions\n GROUP BY identity_kind, identity_key;\n `);\n return;\n }\n\n const hasParentReference =\n columnExists(db, \"sessions\", \"parent_agent_name\") &&\n columnExists(db, \"sessions\", \"parent_session_id\");\n const predicates = [\n ...(hasParentReference ? [\"parent_agent_name IS NULL OR parent_session_id IS NULL\"] : []),\n ...(columnExists(db, \"sessions\", \"publication_id\") ? [\"publication_id IS NULL\"] : []),\n ];\n db.exec(`\n CREATE VIEW IF NOT EXISTS project_groups_v AS\n SELECT\n project_identity_kind AS identity_kind,\n project_identity_key AS identity_key,\n MIN(project_display_name) AS display_name,\n GROUP_CONCAT(DISTINCT agent_name) AS sources_csv,\n COUNT(*) AS session_count,\n MAX(activity_time) AS last_activity\n FROM sessions\n ${predicates.length > 0 ? `WHERE ${predicates.map((predicate) => `(${predicate})`).join(\" AND \")}` : \"\"}\n GROUP BY project_identity_kind, project_identity_key;\n `);\n}\n\nexport function recreateProjectGroupsView(db: SQLiteDatabase): void {\n db.exec(\"DROP VIEW IF EXISTS project_groups_v\");\n createProjectGroupsView(db);\n}\n\nexport function createUserActivityIndex(db: SQLiteDatabase): void {\n db.exec(`CREATE INDEX IF NOT EXISTS idx_messages_user_activity\n ON messages(time_created, agent_name, session_id)\n WHERE role = 'user' AND automated = 0 AND time_created > 0`);\n}\n","import { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport { tableExists, type SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { CacheConnection } from \"./db.js\";\nimport {\n createSearchTables,\n createSearchTriggers,\n dropSearchTriggers,\n} from \"./schema-definitions.js\";\n\ninterface SearchIndexWriteResult<T> {\n value: T;\n rebuildDurationMs?: number;\n}\n\nexport function runSearchIndexWrite<T>(\n db: SQLiteDatabase,\n rebuild: boolean,\n write: () => T,\n transaction: \"immediate\" | \"caller\" = \"immediate\",\n): SearchIndexWriteResult<T> {\n const execute = () => {\n if (rebuild) {\n dropSearchTriggers(db);\n }\n\n const value = write();\n let rebuildDurationMs: number | undefined;\n\n if (rebuild) {\n const rebuildStartedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"search_index.fts_rebuild.started\");\n rebuildSearchIndex(db);\n rebuildDurationMs = performance.now() - rebuildStartedAt;\n getCoreDiagnostics()?.info?.(\"search_index.fts_rebuild.completed\", {\n duration_ms: Math.round(rebuildDurationMs),\n });\n createSearchTriggers(db);\n }\n\n return { value, rebuildDurationMs };\n };\n\n return transaction === \"caller\" ? execute() : db.transaction(execute).immediate();\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\nfunction triggerExists(db: SQLiteDatabase, triggerName: string): boolean {\n return (\n db\n .prepare(\"SELECT 1 AS value FROM sqlite_master WHERE name = ? AND type = 'trigger' LIMIT 1\")\n .get(triggerName) !== undefined\n );\n}\n\nfunction hasAllTriggers(db: SQLiteDatabase, triggerNames: string[]): boolean {\n return triggerNames.every((triggerName) => triggerExists(db, triggerName));\n}\n\nfunction rebuildSearchFtsIndex(db: SQLiteDatabase, reason: \"corruption\" | \"schema_missing\"): void {\n const indexes = [\"session_documents_fts\"];\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.fts_rebuild.started\", { indexes, reason });\n try {\n rebuildSearchIndex(db);\n getCoreDiagnostics()?.info?.(\"sqlite.fts_rebuild.completed\", {\n indexes,\n reason,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.fts_rebuild.failed\", {\n indexes,\n reason,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n\nexport function ensureFtsReady(db: SQLiteDatabase): void {\n const needsSearchRebuild =\n !tableExists(db, \"session_documents_fts\") ||\n !hasAllTriggers(db, [\"session_documents_ai\", \"session_documents_ad\", \"session_documents_au\"]);\n\n createSearchTables(db);\n if (needsSearchRebuild) rebuildSearchFtsIndex(db, \"schema_missing\");\n}\n\nfunction ensureFtsConsistency(db: SQLiteDatabase): void {\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.fts_integrity.started\", {\n indexes: 1,\n });\n try {\n db.exec(\n \"INSERT INTO session_documents_fts(session_documents_fts, rank) VALUES ('integrity-check', 1)\",\n );\n getCoreDiagnostics()?.info?.(\"sqlite.fts_integrity.completed\", {\n indexes: 1,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.fts_integrity.failed\", {\n indexes: 1,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n rebuildSearchFtsIndex(db, \"corruption\");\n }\n}\n\nfunction isFtsCorruptionError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"SQLITE_CORRUPT_VTAB\"\n );\n}\n\nexport function runWithFtsRecovery<T>(\n connection: CacheConnection,\n fn: (db: SQLiteDatabase) => T,\n): T {\n const { db } = connection;\n if (!connection.ftsReady) {\n ensureFtsReady(db);\n connection.ftsReady = true;\n }\n try {\n return fn(db);\n } catch (error) {\n if (!isFtsCorruptionError(error)) throw error;\n getCoreDiagnostics()?.warn(\"sqlite.fts_corruption.detected\", {\n message: error instanceof Error ? error.message : String(error),\n });\n ensureFtsConsistency(db);\n return fn(db);\n }\n}\n","import type { ProjectIdentity, SessionHead } from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport {\n columnExists,\n getUserVersion,\n tableExists,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../../utils/sqlite.js\";\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}\nexport type LegacyProjectIdentityResolver = (directory: string) => ProjectIdentity;\n\n// Schema migrations hold an immediate SQLite transaction, so identity discovery\n// must complete before the migration runner starts one.\nexport function prepareLegacyProjectIdentityResolver(\n db: SQLiteDatabase,\n currentVersion: number,\n): LegacyProjectIdentityResolver {\n const directories = new Set<string>();\n\n if (currentVersion < 7 && tableExists(db, \"cached_sessions\")) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, session_json FROM cached_sessions\")\n .all() as ProjectBackfillSessionRow[];\n for (const row of rows) {\n if (!row.session_json) continue;\n try {\n const session = JSON.parse(row.session_json) as SessionHead;\n if (session.directory != null) {\n directories.add(String(session.directory));\n } else {\n getCoreDiagnostics()?.warn(\"sqlite.migration.identity_precompute.missing_directory\", {\n agent_name: row.agent_name,\n session_id: row.session_id,\n });\n }\n } catch {\n continue;\n }\n }\n }\n\n if (currentVersion < 12) {\n for (const table of [\"session_documents\", \"sessions\", \"project_sessions\"]) {\n if (!tableExists(db, table) || !columnExists(db, table, \"directory\")) continue;\n const rows = db.prepare(`SELECT directory FROM ${table}`).all() as Array<{\n directory?: unknown;\n }>;\n for (const row of rows) directories.add(String(row.directory ?? \"\"));\n }\n }\n\n const identities = new Map<string, ProjectIdentity | Error>();\n for (const directory of directories) {\n try {\n identities.set(directory, computeIdentity(directory, realFs));\n } catch (error) {\n identities.set(directory, error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n return (directory) => {\n const identity = identities.get(directory);\n if (identity instanceof Error) throw identity;\n if (identity) return identity;\n throw new Error(`Missing precomputed project identity for legacy directory: ${directory}`);\n };\n}\n\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\nfunction inferCacheSchemaVersion(db: SQLiteDatabase): number {\n if (columnExists(db, \"session_documents\", \"indexed_message_count\")) {\n return columnExists(db, \"session_documents\", \"slug\") ? 14 : 15;\n }\n if (tableExists(db, \"message_tools\")) {\n return 11;\n }\n if (tableExists(db, \"session_file_activity_path_fts\")) {\n return 10;\n }\n if (tableExists(db, \"messages_fts\")) {\n return 9;\n }\n if (tableExists(db, \"session_file_activity\")) {\n return 8;\n }\n if (tableExists(db, \"sessions\") || tableExists(db, \"messages\")) {\n return 7;\n }\n if (\n tableExists(db, \"project_sessions\") ||\n columnExists(db, \"session_documents\", \"project_identity_key\")\n ) {\n return 5;\n }\n if (tableExists(db, \"session_documents\")) {\n return 4;\n }\n if (tableExists(db, \"cached_sessions\") || tableExists(db, \"agent_cache\")) {\n return 3;\n }\n return 0;\n}\n\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","/** Cache schema creation, migration, and search-index repair. */\nimport type { ProjectIdentityKind, SessionHead } from \"../../types/index.js\";\nimport { createSessionIdentity } from \"../../contract/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport {\n columnExists,\n getUserVersion,\n runSchemaMigrations,\n setUserVersion,\n tableExists,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../../utils/sqlite.js\";\nimport { runCacheContentMigrations } from \"./content-migrations.js\";\nimport { type CacheRow } from \"./db.js\";\nimport {\n messageFromBackfillRow,\n prepareInsertFileActivity,\n prepareInsertMessageTool,\n prepareUpsertSession,\n sourcePathFromMetaJson,\n toolNamesFromMetadataJson,\n upsertSessionRow,\n writeFileActivityRows,\n type MessageBackfillRow,\n type SessionRow,\n} from \"./messages.js\";\nimport {\n addDetailVersion,\n addIndexedMessageCount,\n addProjectIdentityProvenance,\n addSessionPublicationId,\n createCacheMetadataTables,\n createLegacyCacheTables,\n createFileActivityPathSearchTables,\n createFileActivityTables,\n createMessageToolTables,\n createMessageUsageIndex,\n createUserActivityIndex,\n createLegacyProjectTables,\n createSearchStateIndex,\n createSearchTables,\n createSessionTables,\n createSessionModelCostTable,\n dropLegacyMessageSearchIndex,\n dropSearchTriggers,\n ensureLegacySessionDocumentColumns,\n rebuildFileActivityPathIndex,\n recreateProjectGroupsView,\n} from \"./schema-definitions.js\";\nimport { ensureFtsReady, rebuildSearchIndex } from \"./schema-fts.js\";\nimport {\n getCurrentCacheSchemaVersion,\n hasAnyCacheSchema,\n prepareLegacyProjectIdentityResolver,\n readLegacyCacheVersion,\n type LegacyProjectIdentityResolver,\n type ProjectBackfillSessionRow,\n} from \"./schema-version.js\";\nimport { CACHE_SCHEMA_VERSION } from \"./version.js\";\nimport { UnsupportedCacheSchemaVersionError } from \"./errors.js\";\n\nexport { runSearchIndexWrite, runWithFtsRecovery } from \"./schema-fts.js\";\n\ninterface MessageToolBackfillRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_index?: number;\n tool_metadata_json?: string | null;\n}\n\ninterface ProjectBackfillDocumentRow extends DatabaseRow {\n id?: number;\n agent_name?: string;\n session_id?: string;\n slug?: string;\n title?: string;\n directory?: string;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n time_created?: number;\n time_updated?: number | null;\n activity_time?: number;\n}\n\ninterface ProjectIdentityRefreshRow extends DatabaseRow {\n id?: number;\n agent_name?: string;\n session_id?: string;\n directory?: string;\n}\n\nfunction getLegacySessionDirectory(session: SessionHead): string | null {\n return typeof session.directory === \"string\" ? session.directory : null;\n}\n\nfunction removeLegacySessionIdentityFields(session: SessionHead): SessionHead {\n const normalized = { ...session } as SessionHead & { id?: unknown; slug?: unknown };\n delete normalized.id;\n delete normalized.slug;\n return normalized;\n}\n\nfunction createLatestCacheSchema(db: SQLiteDatabase): void {\n createCacheMetadataTables(db);\n createSessionTables(db);\n createFileActivityTables(db);\n recreateProjectGroupsView(db);\n ensureFtsReady(db);\n}\n\nfunction recreateSearchIndexSchema(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS session_documents_ai;\n DROP TRIGGER IF EXISTS session_documents_ad;\n DROP TRIGGER IF EXISTS session_documents_au;\n DROP TABLE IF EXISTS session_documents_fts;\n `);\n createSearchTables(db);\n rebuildSearchIndex(db);\n}\n\nfunction backfillProjectSessions(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n if (!tableExists(db, \"cached_sessions\") || !tableExists(db, \"project_sessions\")) {\n return;\n }\n\n const rows = db\n .prepare(\"SELECT agent_name, session_id, session_json FROM cached_sessions\")\n .all() as ProjectBackfillSessionRow[];\n const upsert = db.prepare(`\n INSERT INTO project_sessions(\n agent_name,\n session_id,\n identity_kind,\n identity_key,\n display_name,\n directory,\n activity_time\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n identity_kind = excluded.identity_kind,\n identity_key = excluded.identity_key,\n display_name = excluded.display_name,\n directory = excluded.directory,\n activity_time = excluded.activity_time\n `);\n\n for (const row of rows) {\n if (!row.session_json || !row.agent_name || !row.session_id) {\n continue;\n }\n\n try {\n const session = JSON.parse(row.session_json) as SessionHead;\n const directory = getLegacySessionDirectory(session);\n if (directory == null) continue;\n const identity = session.project_identity ?? resolveIdentity(directory);\n upsert.run(\n row.agent_name,\n row.session_id,\n identity.kind,\n identity.key,\n identity.displayName,\n directory,\n session.time_updated ?? session.time_created,\n );\n } catch {\n continue;\n }\n }\n}\n\nfunction backfillSessionDocumentProjects(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n if (\n !tableExists(db, \"session_documents\") ||\n !columnExists(db, \"session_documents\", \"project_identity_key\")\n ) {\n return;\n }\n\n const rows = db\n .prepare(\"SELECT id, directory FROM session_documents\")\n .all() as ProjectBackfillDocumentRow[];\n const update = db.prepare(`\n UPDATE session_documents\n SET\n project_identity_kind = ?,\n project_identity_key = ?,\n project_display_name = ?\n WHERE id = ?\n `);\n\n for (const row of rows) {\n const identity = resolveIdentity(String(row.directory ?? \"\"));\n update.run(identity.kind, identity.key, identity.displayName, Number(row.id));\n }\n}\n\nfunction migrateProjectIdentity(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n ensureLegacySessionDocumentColumns(db);\n createLegacyProjectTables(db);\n backfillProjectSessions(db, resolveIdentity);\n backfillSessionDocumentProjects(db, resolveIdentity);\n}\n\nfunction refreshProjectIdentities(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n if (\n tableExists(db, \"sessions\") &&\n columnExists(db, \"sessions\", \"project_identity_key\") &&\n columnExists(db, \"sessions\", \"directory\")\n ) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, directory FROM sessions\")\n .all() as ProjectIdentityRefreshRow[];\n const update = db.prepare(`\n UPDATE sessions\n SET\n project_identity_kind = ?,\n project_identity_key = ?,\n project_display_name = ?\n WHERE agent_name = ? AND session_id = ?\n `);\n const updateFileActivity =\n tableExists(db, \"session_file_activity\") &&\n columnExists(db, \"session_file_activity\", \"project_identity_key\")\n ? db.prepare(`\n UPDATE session_file_activity\n SET project_identity_key = ?\n WHERE agent_name = ? AND session_id = ?\n `)\n : null;\n\n for (const row of rows) {\n const identity = resolveIdentity(String(row.directory ?? \"\"));\n update.run(identity.kind, identity.key, identity.displayName, row.agent_name, row.session_id);\n updateFileActivity?.run(identity.key, row.agent_name, row.session_id);\n }\n }\n\n if (\n tableExists(db, \"project_sessions\") &&\n columnExists(db, \"project_sessions\", \"identity_key\") &&\n columnExists(db, \"project_sessions\", \"directory\")\n ) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, directory FROM project_sessions\")\n .all() as ProjectIdentityRefreshRow[];\n const update = db.prepare(`\n UPDATE project_sessions\n SET\n identity_kind = ?,\n identity_key = ?,\n display_name = ?\n WHERE agent_name = ? AND session_id = ?\n `);\n\n for (const row of rows) {\n const identity = resolveIdentity(String(row.directory ?? \"\"));\n update.run(identity.kind, identity.key, identity.displayName, row.agent_name, row.session_id);\n }\n }\n\n backfillSessionDocumentProjects(db, resolveIdentity);\n recreateProjectGroupsView(db);\n}\n\nfunction backfillStructuredSessions(\n db: SQLiteDatabase,\n resolveIdentity: LegacyProjectIdentityResolver,\n): void {\n createSessionTables(db);\n recreateProjectGroupsView(db);\n const upsertSession = prepareUpsertSession(db);\n\n if (tableExists(db, \"cached_sessions\")) {\n const rows = db\n .prepare(\n \"SELECT agent_name, session_id, session_json, meta_json, rowid AS sort_index FROM cached_sessions ORDER BY agent_name, rowid\",\n )\n .all() as CacheRow[];\n\n for (const row of rows) {\n if (!row.agent_name || !row.session_json) {\n continue;\n }\n\n try {\n const parsed = JSON.parse(row.session_json) as SessionHead;\n const directory = getLegacySessionDirectory(parsed);\n if (directory == null) continue;\n const session = {\n ...removeLegacySessionIdentityFields(parsed),\n ...createSessionIdentity({\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n }),\n project_identity: parsed.project_identity ?? resolveIdentity(directory),\n };\n upsertSessionRow(\n upsertSession,\n String(row.agent_name),\n session,\n row.meta_json ?? null,\n Number(row.sort_index ?? 0),\n sourcePathFromMetaJson(row.meta_json),\n );\n } catch {\n continue;\n }\n }\n }\n\n if (!tableExists(db, \"session_documents\")) {\n return;\n }\n\n const documentRows = db\n .prepare(\n `\n SELECT\n d.agent_name,\n d.session_id,\n d.slug,\n d.title,\n d.directory,\n d.project_identity_kind,\n d.project_identity_key,\n d.project_display_name,\n d.time_created,\n d.time_updated,\n d.activity_time,\n d.id\n FROM session_documents d\n LEFT JOIN sessions s ON s.agent_name = d.agent_name AND s.session_id = d.session_id\n WHERE s.session_id IS NULL\n ORDER BY d.id\n `,\n )\n .all() as ProjectBackfillDocumentRow[];\n\n for (const row of documentRows) {\n const directory = String(row.directory ?? \"\");\n const identity =\n row.project_identity_key && row.project_identity_kind && row.project_display_name\n ? {\n kind: row.project_identity_kind,\n key: String(row.project_identity_key),\n displayName: String(row.project_display_name),\n }\n : resolveIdentity(directory);\n\n upsertSessionRow(\n upsertSession,\n String(row.agent_name),\n {\n ...createSessionIdentity({\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n }),\n title: String(row.title),\n directory,\n project_identity: identity,\n time_created: Number(row.time_created ?? row.activity_time ?? 0),\n time_updated: row.time_updated == null ? undefined : Number(row.time_updated),\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n },\n null,\n Number(row.id ?? 0),\n null,\n );\n }\n}\n\nfunction backfillMessageTools(db: SQLiteDatabase): void {\n createMessageToolTables(db);\n if (!tableExists(db, \"messages\")) {\n return;\n }\n\n db.exec(\"DELETE FROM message_tools\");\n const rows = db\n .prepare(\n `\n SELECT agent_name, session_id, message_index, tool_metadata_json\n FROM messages\n WHERE tool_metadata_json IS NOT NULL\n `,\n )\n .all() as MessageToolBackfillRow[];\n const insertTool = prepareInsertMessageTool(db);\n\n for (const row of rows) {\n if (!row.agent_name || !row.session_id || row.message_index == null) {\n continue;\n }\n\n for (const toolName of toolNamesFromMetadataJson(row.tool_metadata_json)) {\n insertTool.run(row.agent_name, row.session_id, row.message_index, toolName);\n }\n }\n}\n\nfunction backfillFileActivity(db: SQLiteDatabase): void {\n createFileActivityTables(db);\n if (!tableExists(db, \"sessions\") || !tableExists(db, \"messages\")) {\n return;\n }\n\n const sessions = db\n .prepare(\n `\n SELECT agent_name, session_id, project_identity_key\n FROM sessions\n ORDER BY agent_name, session_id\n `,\n )\n .all() as SessionRow[];\n const loadMessages = db.prepare(`\n SELECT\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n parts_json,\n subagent_id,\n nickname\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n ORDER BY message_index\n `);\n const deleteActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const insertActivity = prepareInsertFileActivity(db);\n\n for (const session of sessions) {\n if (!session.agent_name || !session.session_id || !session.project_identity_key) {\n continue;\n }\n\n try {\n const rows = loadMessages.all(session.agent_name, session.session_id) as MessageBackfillRow[];\n const messages = rows.map((row) => messageFromBackfillRow(row));\n const activities = extractSessionFileActivity(\n String(session.agent_name),\n String(session.session_id),\n String(session.project_identity_key),\n messages,\n );\n deleteActivity.run(session.agent_name, session.session_id);\n writeFileActivityRows(insertActivity, activities);\n } catch {\n continue;\n }\n }\n}\n\nfunction invalidateSearchContentHashes(db: SQLiteDatabase): void {\n if (\n tableExists(db, \"session_documents\") &&\n columnExists(db, \"session_documents\", \"content_hash\")\n ) {\n db.exec(\"UPDATE session_documents SET content_hash = ''\");\n }\n}\n\nfunction addAtomicPublicationStaging(db: SQLiteDatabase): void {\n invalidateSearchContentHashes(db);\n if (tableExists(db, \"sessions\") && tableExists(db, \"pending_reindex\")) {\n db.exec(`\n INSERT OR IGNORE INTO pending_reindex(agent_name, session_id)\n SELECT agent_name, session_id\n FROM sessions\n WHERE publication_id IS NULL\n `);\n }\n}\n\nfunction dropDurablePublicationStaging(db: SQLiteDatabase): void {\n db.exec(\"DROP TABLE IF EXISTS search_index_publication_entries\");\n}\n\nfunction replaceSessionActivityIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n db.exec(`\n DROP INDEX IF EXISTS idx_sessions_agent_activity;\n CREATE INDEX IF NOT EXISTS idx_sessions_agent_activity_order\n ON sessions(agent_name, activity_time DESC, session_id);\n `);\n}\n\n/**\n * The unfiltered \"recent sessions\" query orders by bare activity_time; every\n * existing index leads with agent_name, so the planner fell back to a full\n * scan plus a temp B-tree sort (verified via EXPLAIN QUERY PLAN, CS-271).\n */\nfunction addSessionActivityIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_sessions_activity\n ON sessions(activity_time DESC, agent_name, session_id)\n `);\n}\n\nfunction addSessionModelCostRollup(db: SQLiteDatabase): void {\n createSessionModelCostTable(db);\n if (!tableExists(db, \"messages\")) return;\n db.exec(`\n INSERT OR REPLACE INTO session_model_cost(agent_name, session_id, model, cost, cost_recorded)\n SELECT\n agent_name,\n session_id,\n model,\n SUM(COALESCE(cost, 0)),\n SUM(CASE WHEN cost_source = 'recorded' THEN COALESCE(cost, 0) ELSE 0 END)\n FROM messages\n WHERE model IS NOT NULL AND model <> ''\n GROUP BY agent_name, session_id, model\n `);\n}\n\nfunction addSessionCostSummary(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_cost_summary (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_cost REAL NOT NULL,\n untimed_message_cost REAL NOT NULL,\n PRIMARY KEY (agent_name, session_id),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n `);\n if (!tableExists(db, \"messages\")) return;\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_messages_cost_time\n ON messages(\n CASE\n WHEN time_completed > 0 THEN time_completed\n WHEN time_created > 0 THEN time_created\n END,\n agent_name,\n session_id\n )\n WHERE cost > 0;\n `);\n\n if (columnExists(db, \"session_cost_summary\", \"message_count\")) return;\n db.exec(`\n\n INSERT OR REPLACE INTO session_cost_summary(\n agent_name,\n session_id,\n message_cost,\n untimed_message_cost\n )\n SELECT\n m.agent_name,\n m.session_id,\n SUM(CASE WHEN m.cost > 0 THEN m.cost ELSE 0 END),\n SUM(\n CASE\n WHEN m.cost > 0\n AND COALESCE(m.time_completed, 0) <= 0\n AND COALESCE(m.time_created, 0) <= 0\n THEN m.cost\n ELSE 0\n END\n )\n FROM messages m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n GROUP BY m.agent_name, m.session_id\n `);\n}\n\nfunction addSessionUsageSummary(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_cost_summary\")) addSessionCostSummary(db);\n const columns: Record<string, string> = {\n message_count: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_message_count: \"INTEGER NOT NULL DEFAULT 0\",\n input_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n output_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n reasoning_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n cache_read_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n cache_create_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_input_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_output_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_reasoning_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_cache_read_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n untimed_cache_create_tokens: \"INTEGER NOT NULL DEFAULT 0\",\n };\n for (const [name, definition] of Object.entries(columns)) {\n if (!columnExists(db, \"session_cost_summary\", name)) {\n db.exec(`ALTER TABLE session_cost_summary ADD COLUMN ${name} ${definition}`);\n }\n }\n if (!tableExists(db, \"messages\")) return;\n\n db.exec(`\n DROP INDEX IF EXISTS idx_messages_cost_time;\n CREATE INDEX IF NOT EXISTS idx_messages_usage_time\n ON messages(\n CASE\n WHEN time_completed > 0 THEN time_completed\n WHEN time_created > 0 THEN time_created\n END,\n agent_name,\n session_id\n );\n\n DELETE FROM session_cost_summary;\n WITH normalized AS (\n SELECT\n m.agent_name,\n m.session_id,\n COALESCE(m.time_completed, 0) <= 0 AND COALESCE(m.time_created, 0) <= 0 AS untimed,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.input'), 0) AS INTEGER), 0) AS input_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.output'), 0) AS INTEGER), 0) AS output_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.reasoning'), 0) AS INTEGER), 0) AS reasoning_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.cache_read'), 0) AS INTEGER), 0) AS cache_read_tokens,\n MAX(CAST(COALESCE(json_extract(m.tokens_json, '$.cache_create'), 0) AS INTEGER), 0) AS cache_create_tokens,\n CASE WHEN m.cost > 0 THEN m.cost ELSE 0 END AS cost\n FROM messages m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n )\n INSERT INTO session_cost_summary(\n agent_name,\n session_id,\n message_count,\n untimed_message_count,\n input_tokens,\n output_tokens,\n reasoning_tokens,\n cache_read_tokens,\n cache_create_tokens,\n untimed_input_tokens,\n untimed_output_tokens,\n untimed_reasoning_tokens,\n untimed_cache_read_tokens,\n untimed_cache_create_tokens,\n message_cost,\n untimed_message_cost\n )\n SELECT\n agent_name,\n session_id,\n COUNT(*),\n SUM(CASE WHEN untimed THEN 1 ELSE 0 END),\n SUM(input_tokens),\n SUM(output_tokens),\n SUM(reasoning_tokens),\n SUM(cache_read_tokens),\n SUM(cache_create_tokens),\n SUM(CASE WHEN untimed THEN input_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN output_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN reasoning_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_read_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_create_tokens ELSE 0 END),\n SUM(cost),\n SUM(CASE WHEN untimed THEN cost ELSE 0 END)\n FROM normalized\n GROUP BY agent_name, session_id;\n `);\n}\n\nfunction compactSessionDocuments(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) {\n createSearchTables(db);\n return;\n }\n\n dropSearchTriggers(db);\n db.exec(`\n DROP TABLE IF EXISTS session_documents_fts;\n DROP TABLE IF EXISTS session_documents_legacy_v14;\n ALTER TABLE session_documents RENAME TO session_documents_legacy_v14;\n `);\n createSearchTables(db);\n db.exec(`\n INSERT INTO session_documents(\n id,\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n indexed_at\n )\n SELECT\n id,\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n indexed_at\n FROM session_documents_legacy_v14;\n\n DROP TABLE session_documents_legacy_v14;\n `);\n}\n\nfunction addMessagePartsFormatVersion(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages\") || columnExists(db, \"messages\", \"parts_format_version\")) {\n return;\n }\n db.exec(\"ALTER TABLE messages ADD COLUMN parts_format_version INTEGER NOT NULL DEFAULT 0\");\n}\n\nfunction addMessageContentChainDigest(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages\") || columnExists(db, \"messages\", \"content_chain_digest\")) {\n return;\n }\n db.exec(\"ALTER TABLE messages ADD COLUMN content_chain_digest TEXT\");\n}\n\nfunction addSessionParentReference(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n\n if (!columnExists(db, \"sessions\", \"parent_agent_name\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN parent_agent_name TEXT\");\n }\n if (!columnExists(db, \"sessions\", \"parent_session_id\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN parent_session_id TEXT\");\n }\n db.exec(\n \"CREATE INDEX IF NOT EXISTS idx_sessions_parent ON sessions(parent_agent_name, parent_session_id)\",\n );\n recreateProjectGroupsView(db);\n}\n\nfunction dropDerivedSessionSlug(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\") || !columnExists(db, \"sessions\", \"slug\")) return;\n\n const row = db\n .prepare(\n `\n SELECT\n COUNT(*) AS row_count,\n COALESCE(SUM(slug != agent_name || '/' || session_id), 0) AS mismatch_count\n FROM sessions\n `,\n )\n .get() as { row_count?: number; mismatch_count?: number } | undefined;\n const details = {\n row_count: Number(row?.row_count ?? 0),\n mismatch_count: Number(row?.mismatch_count ?? 0),\n };\n if (details.mismatch_count > 0) {\n getCoreDiagnostics()?.warn(\"sqlite.migration.session_identity.mismatch\", details);\n } else {\n getCoreDiagnostics()?.info?.(\"sqlite.migration.session_identity.validated\", details);\n }\n\n db.exec(\"ALTER TABLE sessions DROP COLUMN slug\");\n}\n\nfunction dropLegacyCacheTables(db: SQLiteDatabase): void {\n db.exec(`\n DROP VIEW IF EXISTS project_groups_v;\n DROP TABLE IF EXISTS cached_sessions;\n DROP TABLE IF EXISTS project_sessions;\n `);\n recreateProjectGroupsView(db);\n}\n\nfunction setCacheMetaVersion(db: SQLiteDatabase): void {\n createCacheMetadataTables(db);\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES ('version', ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(String(CACHE_SCHEMA_VERSION));\n}\n\nfunction setCacheSchemaVersion(db: SQLiteDatabase): void {\n setUserVersion(db, CACHE_SCHEMA_VERSION);\n setCacheMetaVersion(db);\n}\n\nexport function ensureCacheSchema(db: SQLiteDatabase, dbPath: string): void {\n const currentVersion = getCurrentCacheSchemaVersion(db);\n if (currentVersion > CACHE_SCHEMA_VERSION) {\n throw new UnsupportedCacheSchemaVersionError(currentVersion, CACHE_SCHEMA_VERSION);\n }\n if (currentVersion === 0 && !hasAnyCacheSchema(db)) {\n createLatestCacheSchema(db);\n createUserActivityIndex(db);\n createSearchStateIndex(db);\n setCacheSchemaVersion(db);\n runCacheContentMigrations(db);\n return;\n }\n\n const resolveLegacyProjectIdentity = prepareLegacyProjectIdentityResolver(db, currentVersion);\n\n runSchemaMigrations(db, {\n dbPath,\n currentVersion,\n targetVersion: CACHE_SCHEMA_VERSION,\n backupLabel: \"cache-migration\",\n backupTables: [\n \"agent_cache\",\n \"cache_initialization\",\n \"cached_sessions\",\n \"sessions\",\n \"messages\",\n \"message_tools\",\n \"session_file_activity\",\n \"session_documents\",\n \"project_sessions\",\n ],\n migrations: [\n { version: 3, migrate: createLegacyCacheTables },\n { version: 4, migrate: createSearchTables },\n {\n version: 5,\n migrate: (migrationDb) => migrateProjectIdentity(migrationDb, resolveLegacyProjectIdentity),\n },\n {\n version: 6,\n destructive: true,\n migrate(db) {\n createLatestCacheSchema(db);\n recreateSearchIndexSchema(db);\n invalidateSearchContentHashes(db);\n },\n },\n {\n version: 7,\n migrate(db) {\n addSessionParentReference(db);\n backfillStructuredSessions(db, resolveLegacyProjectIdentity);\n },\n },\n { version: 8, migrate: backfillFileActivity },\n {\n version: 10,\n migrate(db) {\n createFileActivityPathSearchTables(db);\n rebuildFileActivityPathIndex(db);\n },\n },\n {\n version: 11,\n migrate(db) {\n backfillMessageTools(db);\n },\n },\n {\n version: 12,\n migrate(db) {\n refreshProjectIdentities(db, resolveLegacyProjectIdentity);\n },\n },\n { version: 13, migrate: createLegacyCacheTables },\n { version: 14, migrate: addIndexedMessageCount },\n { version: 15, destructive: true, migrate: compactSessionDocuments },\n { version: 17, migrate: addMessagePartsFormatVersion },\n { version: 18, migrate: addSessionParentReference },\n { version: 19, migrate: addDetailVersion },\n { version: 20, migrate: addProjectIdentityProvenance },\n { version: 21, migrate: addSessionPublicationId },\n { version: 22, migrate: addAtomicPublicationStaging },\n { version: 23, migrate: replaceSessionActivityIndex },\n { version: 24, migrate: dropLegacyMessageSearchIndex },\n { version: 25, migrate: addMessageContentChainDigest },\n { version: 26, migrate: addSessionActivityIndex },\n { version: 27, migrate: addSessionModelCostRollup },\n { version: 28, migrate: addSessionCostSummary },\n { version: 29, migrate: addSessionUsageSummary },\n { version: 30, destructive: true, migrate: dropDerivedSessionSlug },\n { version: 31, migrate: dropDurablePublicationStaging },\n { version: 32, migrate: dropLegacyCacheTables },\n {\n version: 33,\n migrate(db) {\n db.exec(\"DROP INDEX IF EXISTS idx_messages_usage_time\");\n createMessageUsageIndex(db);\n },\n },\n {\n version: 34,\n migrate(db) {\n if (!columnExists(db, \"messages\", \"automated\")) {\n db.exec(\"ALTER TABLE messages ADD COLUMN automated INTEGER NOT NULL DEFAULT 0\");\n }\n createUserActivityIndex(db);\n },\n },\n ],\n });\n\n createLatestCacheSchema(db);\n createUserActivityIndex(db);\n createSearchStateIndex(db);\n\n // Only stamp when behind: every thread's first connection runs ensureSchema,\n // and an unconditional PRAGMA user_version write would contend for the write\n // lock against concurrent checkpoint/index writers on every startup.\n const userVersion = getUserVersion(db);\n if (userVersion < CACHE_SCHEMA_VERSION) {\n setCacheSchemaVersion(db);\n } else if (\n userVersion === CACHE_SCHEMA_VERSION &&\n readLegacyCacheVersion(db) !== CACHE_SCHEMA_VERSION\n ) {\n setCacheMetaVersion(db);\n }\n\n runCacheContentMigrations(db);\n}\n","/**\n * Cache connection boundary. It owns connection recovery and exposes ready\n * database capabilities while schema creation and FTS repair remain in schema.\n */\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport {\n discardCacheConnection,\n getCacheConnection,\n getCachePath,\n getSchemaEnsuredPath,\n hasCacheStorage,\n setSchemaEnsuredPath,\n type CacheConnection,\n} from \"./db.js\";\nimport { CacheDataIntegrityError } from \"./errors.js\";\nimport { deleteLegacyPublicationRows, hasLegacyPublicationRows } from \"./publication-staging.js\";\nimport { ensureCacheSchema, runWithFtsRecovery } from \"./schema.js\";\n\ntype CacheFailureEvent = \"cache.write_failed\" | \"cache.read_failed\";\n\nfunction isRecoverableCacheError(error: unknown): boolean {\n if (error instanceof CacheDataIntegrityError) return true;\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n typeof error.code === \"string\" &&\n error.code.startsWith(\"SQLITE_\")\n );\n}\n\nfunction reportCacheFailure(\n cachePath: string,\n connection: CacheConnection,\n event: CacheFailureEvent,\n error: unknown,\n): null {\n getCoreDiagnostics()?.warn(event, {\n message: error instanceof Error ? error.message : String(error),\n code: (error as { code?: string })?.code,\n error_class: error instanceof Error ? error.name : typeof error,\n ...(event === \"cache.write_failed\" && error instanceof Error ? { stack: error.stack } : {}),\n });\n discardCacheConnection(cachePath, connection);\n return null;\n}\n\nfunction withCacheConnection<T>(\n callbackFailureEvent: CacheFailureEvent,\n fn: (connection: CacheConnection) => T,\n): T | null {\n const cachePath = getCachePath();\n const connection = getCacheConnection(cachePath);\n if (!connection) return null;\n\n try {\n if (getSchemaEnsuredPath() !== cachePath) {\n ensureCacheSchema(connection.db, cachePath);\n setSchemaEnsuredPath(cachePath);\n }\n } catch (error) {\n return reportCacheFailure(cachePath, connection, \"cache.write_failed\", error);\n }\n\n try {\n return fn(connection);\n } catch (error) {\n if (!isRecoverableCacheError(error)) throw error;\n return reportCacheFailure(cachePath, connection, callbackFailureEvent, error);\n }\n}\n\nfunction cleanPublicationStaging(connection: CacheConnection): void {\n if (connection.publicationStagingCleaned) return;\n\n const startedAt = performance.now();\n const reclaimed = hasLegacyPublicationRows(connection.db);\n if (reclaimed) {\n connection.db.transaction(() => deleteLegacyPublicationRows(connection.db)).immediate();\n }\n connection.publicationStagingCleaned = true;\n getCoreDiagnostics()?.info?.(\"sqlite.publication_staging_cleanup.completed\", {\n duration_ms: Math.round(performance.now() - startedAt),\n reclaimed,\n });\n}\n\nexport function withCacheDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheConnection(\"cache.write_failed\", ({ db }) => fn(db));\n}\n\nexport type CacheReadOutcome<T> = { status: \"success\"; value: T } | { status: \"failed\" };\n\n/** Preserves the difference between a failed read and a successful nullish payload. */\nexport function withCacheDbOutcome<T>(fn: (db: SQLiteDatabase) => T): CacheReadOutcome<T> {\n let outcome: CacheReadOutcome<T> = { status: \"failed\" };\n withCacheConnection(\"cache.read_failed\", ({ db }) => {\n outcome = { status: \"success\", value: fn(db) };\n });\n return outcome;\n}\n\nexport function withCacheDbReadOnly<T>(fn: (db: SQLiteDatabase) => T): CacheReadOutcome<T> {\n const cachePath = getCachePath();\n if (!hasCacheStorage()) return { status: \"failed\" };\n\n const connection = getCacheConnection(cachePath);\n if (!connection) return { status: \"failed\" };\n try {\n return { status: \"success\", value: fn(connection.db) };\n } catch (error) {\n if (!isRecoverableCacheError(error)) throw error;\n reportCacheFailure(cachePath, connection, \"cache.read_failed\", error);\n return { status: \"failed\" };\n }\n}\n\nexport function withSearchDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheConnection(\"cache.read_failed\", (connection) =>\n runWithFtsRecovery(connection, fn),\n );\n}\n\nexport function withSearchIndexDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheConnection(\"cache.write_failed\", (connection) => {\n cleanPublicationStaging(connection);\n return runWithFtsRecovery(connection, fn);\n });\n}\n","import type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDbReadOnly } from \"./connection.js\";\n\nconst ANALYTICS_REVISION_KEY = \"analytics_revision\";\n\ninterface AnalyticsRevisionRow {\n value?: string | number;\n}\n\nexport function readAnalyticsRevision(db: SQLiteDatabase): string {\n const row = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(ANALYTICS_REVISION_KEY) as AnalyticsRevisionRow | undefined;\n return String(row?.value ?? \"0\");\n}\n\nexport function advanceAnalyticsRevision(db: SQLiteDatabase): void {\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES (?, '1')\n ON CONFLICT(key) DO UPDATE SET value = CAST(value AS INTEGER) + 1\n `,\n ).run(ANALYTICS_REVISION_KEY);\n}\n\nexport function getAnalyticsRevision(): string | null {\n if (!hasCacheStorage()) return null;\n\n const read = withCacheDbReadOnly((db) => readAnalyticsRevision(db));\n return read.status === \"success\" ? read.value : null;\n}\n","import type { SessionCacheMeta } from \"../../agents/session-source-types.js\";\n\nconst DETAIL_PROJECTION_VERSION = \"session-detail-v1\";\n\nexport function sessionDetailVersion(meta: SessionCacheMeta | null | undefined): string {\n const parserVersions = Object.entries(meta ?? {})\n .filter(\n ([key, value]) => key.toLowerCase().endsWith(\"parserversion\") && typeof value === \"string\",\n )\n .sort(([left], [right]) => left.localeCompare(right));\n return JSON.stringify([\n DETAIL_PROJECTION_VERSION,\n typeof meta?.sourceFingerprint === \"string\" ? meta.sourceFingerprint : null,\n parserVersions,\n ]);\n}\n","import type { SessionCacheMeta } from \"../../agents/session-source-types.js\";\nimport type { SessionHead } from \"../../types/index.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { withCacheDbReadOnly } from \"./connection.js\";\nimport { sessionDetailVersion } from \"./detail-version.js\";\nimport type { SessionSnapshotCompleteness } from \"./snapshot-types.js\";\n\nexport type SearchIndexPublicationStage =\n | \"started\"\n | \"prepared\"\n | \"cache_staged\"\n | \"search_staged\"\n | \"committed\";\n\nexport interface SearchIndexSyncOptions {\n isBulk?: boolean;\n bulkThreshold?: number;\n includePendingReindex?: boolean;\n detailVersions?: Readonly<Record<string, string>>;\n completeness?: SessionSnapshotCompleteness;\n removedSessionIds?: readonly string[];\n publicationId?: string;\n onPublicationStage?: (stage: SearchIndexPublicationStage) => void;\n}\n\nexport interface PendingSearchIndexMaintenance {\n sessionIds: string[];\n total: number;\n}\n\nexport interface SearchIndexState {\n contentHashBySessionId: Map<string, string>;\n publishedContentHashBySessionId: Map<string, string>;\n publishedDetailFactsHashBySessionId: Map<string, string>;\n indexedMessageCountBySessionId: Map<string, number>;\n messageCountBySessionId: Map<string, number>;\n detailVersionBySessionId: Map<string, string>;\n targetDetailVersionBySessionId: Map<string, string>;\n pendingReindexSessionIds: Set<string>;\n}\n\ninterface IndexedSearchRow {\n session_id?: string;\n content_hash?: string;\n indexed_message_count?: number;\n detail_version?: string;\n meta_json?: string | null;\n}\n\ninterface PublishedSessionRow {\n session_title?: string | null;\n session_directory?: string | null;\n session_time_created?: number | null;\n session_time_updated?: number | null;\n session_message_count?: number | null;\n session_total_input_tokens?: number | null;\n session_total_output_tokens?: number | null;\n session_total_cache_read_tokens?: number | null;\n session_total_cache_create_tokens?: number | null;\n session_total_cost?: number | null;\n session_cost_source?: string | null;\n session_total_tokens?: number | null;\n session_project_identity_kind?: string | null;\n session_project_identity_key?: string | null;\n session_project_display_name?: string | null;\n session_project_identity_resolver_revision?: string | null;\n session_project_identity_input_signature?: string | null;\n}\n\ninterface MessageCountRow {\n session_id?: string;\n value?: number;\n}\n\ntype SearchIndexStateRow = IndexedSearchRow & MessageCountRow & PublishedSessionRow;\n\ninterface SearchIndexSessionFacts {\n title: string;\n directory: string;\n timeCreated: number;\n timeUpdated: number;\n messageCount: number;\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCacheReadTokens: number;\n totalCacheCreateTokens: number;\n totalCost: number;\n costSource: string;\n totalTokens: number;\n projectIdentityKind: string;\n projectIdentityKey: string;\n projectDisplayName: string;\n projectIdentityResolverRevision: string;\n projectIdentityInputSignature: string;\n}\n\ntype SearchIndexDetailFacts = Pick<\n SearchIndexSessionFacts,\n | \"timeCreated\"\n | \"timeUpdated\"\n | \"messageCount\"\n | \"totalInputTokens\"\n | \"totalOutputTokens\"\n | \"totalCacheReadTokens\"\n | \"totalCacheCreateTokens\"\n | \"totalCost\"\n | \"costSource\"\n | \"totalTokens\"\n>;\n\nconst SEARCH_INDEX_STATE_BATCH_SIZE = 900;\n\nfunction readPendingReindexIds(db: SQLiteDatabase, agentName: string): Set<string> {\n const rows = db\n .prepare(\"SELECT session_id FROM pending_reindex WHERE agent_name = ?\")\n .all(agentName) as Array<{ session_id?: string }>;\n return new Set(rows.map((row) => String(row.session_id)));\n}\n\nfunction searchIndexSessionFacts(session: SessionHead): SearchIndexSessionFacts {\n return {\n title: session.title,\n directory: session.directory,\n timeCreated: session.time_created,\n timeUpdated: session.time_updated ?? session.time_created,\n messageCount: session.stats.message_count,\n totalInputTokens: session.stats.total_input_tokens,\n totalOutputTokens: session.stats.total_output_tokens,\n totalCacheReadTokens: session.stats.total_cache_read_tokens ?? 0,\n totalCacheCreateTokens: session.stats.total_cache_create_tokens ?? 0,\n totalCost: session.stats.total_cost,\n costSource: session.stats.cost_source ?? \"\",\n totalTokens: session.stats.total_tokens ?? 0,\n projectIdentityKind: session.project_identity?.kind ?? \"\",\n projectIdentityKey: session.project_identity?.key ?? \"\",\n projectDisplayName: session.project_identity?.displayName ?? \"\",\n projectIdentityResolverRevision: session.project_identity_resolver_revision ?? \"\",\n projectIdentityInputSignature: session.project_identity_input_signature ?? \"\",\n };\n}\n\nfunction hashSearchIndexSessionFacts(facts: SearchIndexSessionFacts): string {\n return JSON.stringify(facts);\n}\n\nfunction searchIndexDetailFacts(facts: SearchIndexSessionFacts): SearchIndexDetailFacts {\n return {\n timeCreated: facts.timeCreated,\n timeUpdated: facts.timeUpdated,\n messageCount: facts.messageCount,\n totalInputTokens: facts.totalInputTokens,\n totalOutputTokens: facts.totalOutputTokens,\n totalCacheReadTokens: facts.totalCacheReadTokens,\n totalCacheCreateTokens: facts.totalCacheCreateTokens,\n totalCost: facts.totalCost,\n costSource: facts.costSource,\n totalTokens: facts.totalTokens,\n };\n}\n\nfunction hashSearchIndexDetailFacts(facts: SearchIndexSessionFacts): string {\n return JSON.stringify(searchIndexDetailFacts(facts));\n}\n\nexport function sessionContentHash(session: SessionHead): string {\n return hashSearchIndexSessionFacts(searchIndexSessionFacts(session));\n}\n\nfunction publishedSessionContentHash(row: PublishedSessionRow): string | null {\n if (row.session_title == null) return null;\n return hashSearchIndexSessionFacts(searchIndexSessionFactsFromRow(row));\n}\n\nfunction publishedSessionDetailFactsHash(row: PublishedSessionRow): string | null {\n if (row.session_title == null) return null;\n return hashSearchIndexDetailFacts(searchIndexSessionFactsFromRow(row));\n}\n\nfunction searchIndexSessionFactsFromRow(row: PublishedSessionRow): SearchIndexSessionFacts {\n return {\n title: String(row.session_title),\n directory: row.session_directory ?? \"\",\n timeCreated: Number(row.session_time_created ?? 0),\n timeUpdated: Number(row.session_time_updated ?? row.session_time_created ?? 0),\n messageCount: Number(row.session_message_count ?? 0),\n totalInputTokens: Number(row.session_total_input_tokens ?? 0),\n totalOutputTokens: Number(row.session_total_output_tokens ?? 0),\n totalCacheReadTokens: Number(row.session_total_cache_read_tokens ?? 0),\n totalCacheCreateTokens: Number(row.session_total_cache_create_tokens ?? 0),\n totalCost: Number(row.session_total_cost ?? 0),\n costSource: row.session_cost_source ?? \"\",\n totalTokens: Number(row.session_total_tokens ?? 0),\n projectIdentityKind: row.session_project_identity_kind ?? \"\",\n projectIdentityKey: row.session_project_identity_key ?? \"\",\n projectDisplayName: row.session_project_display_name ?? \"\",\n projectIdentityResolverRevision: row.session_project_identity_resolver_revision ?? \"\",\n projectIdentityInputSignature: row.session_project_identity_input_signature ?? \"\",\n };\n}\n\nexport function sessionDetailFactsHash(session: SessionHead): string {\n return hashSearchIndexDetailFacts(searchIndexSessionFacts(session));\n}\n\nexport function detailVersionFromMetaJson(value: string | null | undefined): string {\n if (!value) return sessionDetailVersion(null);\n try {\n return sessionDetailVersion(JSON.parse(value) as SessionCacheMeta);\n } catch {\n return sessionDetailVersion(null);\n }\n}\n\nfunction searchIndexStateFromRows(\n indexedRows: SearchIndexStateRow[],\n messageCountRows: MessageCountRow[],\n pendingReindexSessionIds: Set<string> = new Set(),\n): SearchIndexState {\n return {\n contentHashBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), String(row.content_hash ?? \"\")]),\n ),\n publishedContentHashBySessionId: new Map(\n indexedRows.flatMap((row) => {\n const contentHash = publishedSessionContentHash(row);\n return contentHash == null ? [] : [[String(row.session_id), contentHash]];\n }),\n ),\n publishedDetailFactsHashBySessionId: new Map(\n indexedRows.flatMap((row) => {\n const detailFactsHash = publishedSessionDetailFactsHash(row);\n return detailFactsHash == null ? [] : [[String(row.session_id), detailFactsHash]];\n }),\n ),\n indexedMessageCountBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), Number(row.indexed_message_count ?? 0)]),\n ),\n messageCountBySessionId: new Map(\n messageCountRows.map((row) => [String(row.session_id), Number(row.value ?? 0)]),\n ),\n detailVersionBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), String(row.detail_version ?? \"\")]),\n ),\n targetDetailVersionBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), detailVersionFromMetaJson(row.meta_json)]),\n ),\n pendingReindexSessionIds,\n };\n}\n\n/**\n * Freshness probe for a batch of sessions: is each one's indexed document still\n * in step with its cached head?\n *\n * INDEXED BY is not a micro-optimisation. Without stats SQLite prefers the\n * UNIQUE(agent_name, session_id) auto-index, and reaching content_hash then\n * means reading each row past content_text through its overflow chain — proving\n * an unchanged agent is up to date would cost the size of the indexed corpus.\n * Pinning the covering index keeps the probe proportional to the session count.\n */\nexport function searchIndexStateQuery(sessionIdCount: number): string {\n const requestedRows = Array.from({ length: sessionIdCount }, () => \"(?)\").join(\", \");\n return `\n WITH requested_session_ids(session_id) AS (VALUES ${requestedRows})\n SELECT\n requested.session_id,\n documents.content_hash,\n documents.indexed_message_count,\n documents.detail_version,\n sessions.meta_json,\n sessions.title AS session_title,\n sessions.directory AS session_directory,\n sessions.time_created AS session_time_created,\n sessions.time_updated AS session_time_updated,\n sessions.message_count AS session_message_count,\n sessions.total_input_tokens AS session_total_input_tokens,\n sessions.total_output_tokens AS session_total_output_tokens,\n sessions.total_cache_read_tokens AS session_total_cache_read_tokens,\n sessions.total_cache_create_tokens AS session_total_cache_create_tokens,\n sessions.total_cost AS session_total_cost,\n sessions.cost_source AS session_cost_source,\n sessions.total_tokens AS session_total_tokens,\n sessions.project_identity_kind AS session_project_identity_kind,\n sessions.project_identity_key AS session_project_identity_key,\n sessions.project_display_name AS session_project_display_name,\n sessions.project_identity_resolver_revision AS session_project_identity_resolver_revision,\n sessions.project_identity_input_signature AS session_project_identity_input_signature,\n (\n SELECT COUNT(*)\n FROM messages\n WHERE messages.agent_name = ?\n AND messages.session_id = requested.session_id\n ) AS value\n FROM requested_session_ids AS requested\n LEFT JOIN session_documents AS documents\n INDEXED BY idx_session_documents_state\n ON documents.agent_name = ? AND documents.session_id = requested.session_id\n LEFT JOIN sessions\n ON sessions.agent_name = ? AND sessions.session_id = requested.session_id\n `;\n}\n\nexport function readSearchIndexState(\n db: SQLiteDatabase,\n agentName: string,\n sessionIds: string[],\n): SearchIndexState {\n const rows: SearchIndexStateRow[] = [];\n const uniqueSessionIds = [...new Set(sessionIds)];\n\n for (let offset = 0; offset < uniqueSessionIds.length; offset += SEARCH_INDEX_STATE_BATCH_SIZE) {\n const batch = uniqueSessionIds.slice(offset, offset + SEARCH_INDEX_STATE_BATCH_SIZE);\n const batchRows = db\n .prepare(searchIndexStateQuery(batch.length))\n .all(...batch, agentName, agentName, agentName) as SearchIndexStateRow[];\n rows.push(...batchRows);\n }\n\n return searchIndexStateFromRows(rows, rows, readPendingReindexIds(db, agentName));\n}\n\nexport function targetDetailVersion(\n state: SearchIndexState,\n sessionId: string,\n options: SearchIndexSyncOptions,\n): string {\n return (\n options.detailVersions?.[sessionId] ??\n state.targetDetailVersionBySessionId.get(sessionId) ??\n sessionDetailVersion(null)\n );\n}\n\nexport function searchIndexEntryNeedsUpdate(\n state: SearchIndexState,\n session: SessionHead,\n options: SearchIndexSyncOptions,\n): boolean {\n const sessionId = session.reference.sessionId;\n const pendingMaintenance = state.pendingReindexSessionIds.has(sessionId);\n const targetVersion = targetDetailVersion(state, sessionId, options);\n if (pendingMaintenance && options.includePendingReindex === false) {\n return (\n state.publishedContentHashBySessionId.get(sessionId) !== sessionContentHash(session) ||\n state.targetDetailVersionBySessionId.get(sessionId) !== targetVersion\n );\n }\n return (\n pendingMaintenance ||\n state.detailVersionBySessionId.get(sessionId) !== targetVersion ||\n state.contentHashBySessionId.get(sessionId) !== sessionContentHash(session) ||\n state.indexedMessageCountBySessionId.get(sessionId) !==\n (state.messageCountBySessionId.get(sessionId) ?? 0)\n );\n}\n\nexport function readPendingSearchIndexMaintenance(\n agentName: string,\n limit: number,\n): PendingSearchIndexMaintenance | null {\n const boundedLimit = Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 0;\n const outcome = withCacheDbReadOnly((db) => {\n const totalRow = db\n .prepare(\n `\n SELECT COUNT(*) AS value\n FROM pending_reindex AS pending\n INNER JOIN sessions\n ON sessions.agent_name = pending.agent_name\n AND sessions.session_id = pending.session_id\n WHERE pending.agent_name = ?\n AND sessions.publication_id IS NULL\n `,\n )\n .get(agentName) as { value?: number } | undefined;\n const rows = db\n .prepare(\n `\n SELECT pending.session_id\n FROM pending_reindex AS pending\n INNER JOIN sessions\n ON sessions.agent_name = pending.agent_name\n AND sessions.session_id = pending.session_id\n WHERE pending.agent_name = ?\n AND sessions.publication_id IS NULL\n ORDER BY sessions.sort_index, pending.session_id\n LIMIT ?\n `,\n )\n .all(agentName, boundedLimit) as Array<{ session_id?: string }>;\n return {\n sessionIds: rows.map((row) => String(row.session_id)),\n total: Number(totalRow?.value ?? 0),\n };\n });\n return outcome.status === \"success\" ? outcome.value : null;\n}\n","import { createHash, type Hash } from \"node:crypto\";\nimport type { SessionReference } from \"../../contract/index.js\";\n\nexport const MESSAGE_CURSOR_VERSION = 2;\n\nexport interface MessageCursorContent {\n messageId: string;\n role: string;\n timeCreated: number;\n timeCompleted: number | null | undefined;\n agent: string | null | undefined;\n mode: string | null | undefined;\n model: string | null | undefined;\n provider: string | null | undefined;\n tokensJson: string | null | undefined;\n cost: number | null | undefined;\n costSource: string | null | undefined;\n partsJson: string;\n partsFormatVersion: number | string | null | undefined;\n subagentId: string | null | undefined;\n nickname: string | null | undefined;\n automated?: number;\n}\n\nfunction updateField(hash: Hash, value: string | number | null | undefined): void {\n if (value == null) {\n hash.update(\"n;\");\n return;\n }\n const text = String(value);\n hash.update(`v${text.length}:`).update(text).update(\";\");\n}\n\nfunction updateMessageContent(hash: Hash, content: MessageCursorContent): void {\n updateField(hash, content.messageId);\n updateField(hash, content.role);\n updateField(hash, content.timeCreated);\n updateField(hash, content.timeCompleted);\n updateField(hash, content.agent);\n updateField(hash, content.mode);\n updateField(hash, content.model);\n updateField(hash, content.provider);\n updateField(hash, content.tokensJson);\n updateField(hash, content.cost);\n updateField(hash, content.costSource);\n updateField(hash, content.partsJson);\n updateField(hash, content.partsFormatVersion);\n updateField(hash, content.subagentId);\n updateField(hash, content.nickname);\n // Keep existing cursors valid for messages whose origin has not changed.\n if (content.automated) updateField(hash, \"automated\");\n}\n\nexport function initialMessageCursorDigest(reference: SessionReference): string {\n const hash = createHash(\"sha256\");\n hash.update(\"codesesh-session-messages\\0\");\n updateField(hash, MESSAGE_CURSOR_VERSION);\n updateField(hash, reference.agentName);\n updateField(hash, reference.sessionId);\n return hash.digest(\"hex\");\n}\n\nexport function advanceMessageCursorDigest(\n previousDigest: string,\n content: MessageCursorContent,\n): string {\n const hash = createHash(\"sha256\");\n hash.update(\"codesesh-session-messages-chain\\0\");\n updateField(hash, previousDigest);\n updateMessageContent(hash, content);\n return hash.digest(\"hex\");\n}\n\nexport function computeMessageCursorDigest(\n reference: SessionReference,\n messages: Iterable<MessageCursorContent>,\n): string {\n let digest = initialMessageCursorDigest(reference);\n for (const message of messages) {\n digest = advanceMessageCursorDigest(digest, message);\n }\n return digest;\n}\n","import type { SessionFileActivity, SessionHead } from \"../../types/index.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport {\n messageCursorContentFromStructuredRecord,\n MESSAGE_PARTS_FORMAT_VERSION,\n prepareInsertFileActivity,\n prepareInsertMessageTool,\n prepareUpsertSession,\n requireSessionProjectIdentity,\n upsertSessionRow,\n writeFileActivityRows,\n type StructuredMessageRecord,\n} from \"./messages.js\";\nimport { advanceMessageCursorDigest, initialMessageCursorDigest } from \"./message-cursor.js\";\n\nexport interface SessionMaterializationEntry {\n session: SessionHead;\n messages: StructuredMessageRecord[];\n fileActivity: SessionFileActivity[];\n sortIndex: number;\n}\n\nexport interface SessionMaterializationWriter {\n deleteSession(sessionId: string): void;\n reuseSessionHead(session: SessionHead, sortIndex: number): void;\n writeSession(entry: SessionMaterializationEntry): void;\n}\n\nexport function prepareSessionMaterializationWriter(\n db: SQLiteDatabase,\n agentName: string,\n): SessionMaterializationWriter {\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 updateFileActivityIdentity = db.prepare(\n \"UPDATE session_file_activity SET project_identity_key = ? WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteModelCost = db.prepare(\n \"DELETE FROM session_model_cost WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteCostSummary = db.prepare(\n \"DELETE FROM session_cost_summary WHERE agent_name = ? AND session_id = ?\",\n );\n // Rebuild both rollups from the message rows in the same transaction so\n // derived cost facts cannot drift from their source.\n const rebuildModelCost = db.prepare(`\n INSERT INTO session_model_cost(agent_name, session_id, model, cost, cost_recorded)\n SELECT\n agent_name,\n session_id,\n model,\n SUM(COALESCE(cost, 0)),\n SUM(CASE WHEN cost_source = 'recorded' THEN COALESCE(cost, 0) ELSE 0 END)\n FROM messages\n WHERE agent_name = ? AND session_id = ? AND model IS NOT NULL AND model <> ''\n GROUP BY agent_name, session_id, model\n `);\n const rebuildCostSummary = db.prepare(`\n WITH normalized AS (\n SELECT\n agent_name,\n session_id,\n COALESCE(time_completed, 0) <= 0 AND COALESCE(time_created, 0) <= 0 AS untimed,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.input'), 0) AS INTEGER), 0) AS input_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.output'), 0) AS INTEGER), 0) AS output_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.reasoning'), 0) AS INTEGER), 0) AS reasoning_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.cache_read'), 0) AS INTEGER), 0) AS cache_read_tokens,\n MAX(CAST(COALESCE(json_extract(tokens_json, '$.cache_create'), 0) AS INTEGER), 0) AS cache_create_tokens,\n CASE WHEN cost > 0 THEN cost ELSE 0 END AS normalized_cost\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n )\n INSERT INTO session_cost_summary(\n agent_name,\n session_id,\n message_count,\n untimed_message_count,\n input_tokens,\n output_tokens,\n reasoning_tokens,\n cache_read_tokens,\n cache_create_tokens,\n untimed_input_tokens,\n untimed_output_tokens,\n untimed_reasoning_tokens,\n untimed_cache_read_tokens,\n untimed_cache_create_tokens,\n message_cost,\n untimed_message_cost\n )\n SELECT\n agent_name,\n session_id,\n COUNT(*),\n SUM(CASE WHEN untimed THEN 1 ELSE 0 END),\n SUM(input_tokens),\n SUM(output_tokens),\n SUM(reasoning_tokens),\n SUM(cache_read_tokens),\n SUM(cache_create_tokens),\n SUM(CASE WHEN untimed THEN input_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN output_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN reasoning_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_read_tokens ELSE 0 END),\n SUM(CASE WHEN untimed THEN cache_create_tokens ELSE 0 END),\n SUM(normalized_cost),\n SUM(CASE WHEN untimed THEN normalized_cost ELSE 0 END)\n FROM normalized\n GROUP BY agent_name, session_id\n `);\n const writeMaterializedSession = prepareUpsertSession(db, \"materialization\");\n const insertFileActivity = prepareInsertFileActivity(db);\n const insertMessageTool = prepareInsertMessageTool(db);\n const upsertMessage = db.prepare(`\n INSERT INTO messages(\n agent_name,\n session_id,\n message_index,\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n tokens_json,\n cost,\n cost_source,\n parts_json,\n parts_format_version,\n content_chain_digest,\n subagent_id,\n nickname,\n automated,\n content_text,\n tool_metadata_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id, message_index) DO UPDATE SET\n message_id = excluded.message_id,\n role = excluded.role,\n time_created = excluded.time_created,\n time_completed = excluded.time_completed,\n agent = excluded.agent,\n mode = excluded.mode,\n model = excluded.model,\n provider = excluded.provider,\n tokens_json = excluded.tokens_json,\n cost = excluded.cost,\n cost_source = excluded.cost_source,\n parts_json = excluded.parts_json,\n parts_format_version = excluded.parts_format_version,\n content_chain_digest = excluded.content_chain_digest,\n subagent_id = excluded.subagent_id,\n nickname = excluded.nickname,\n automated = excluded.automated,\n content_text = excluded.content_text,\n tool_metadata_json = excluded.tool_metadata_json\n `);\n\n const writeSessionHead = (session: SessionHead, sortIndex: number): void => {\n upsertSessionRow(writeMaterializedSession, agentName, session, null, sortIndex, null);\n };\n\n return {\n deleteSession(sessionId) {\n deleteFileActivity.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId, 0);\n deleteMessages.run(agentName, sessionId, 0);\n deleteModelCost.run(agentName, sessionId);\n deleteCostSummary.run(agentName, sessionId);\n },\n reuseSessionHead(session, sortIndex) {\n writeSessionHead(session, sortIndex);\n updateFileActivityIdentity.run(\n requireSessionProjectIdentity(agentName, session).key,\n agentName,\n session.reference.sessionId,\n );\n },\n writeSession(entry) {\n const sessionId = entry.session.reference.sessionId;\n writeSessionHead(entry.session, entry.sortIndex);\n deleteFileActivity.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId, 0);\n writeFileActivityRows(insertFileActivity, entry.fileActivity);\n let contentChainDigest = initialMessageCursorDigest({ agentName, sessionId });\n for (const message of entry.messages) {\n contentChainDigest = advanceMessageCursorDigest(\n contentChainDigest,\n messageCursorContentFromStructuredRecord(message),\n );\n upsertMessage.run(\n agentName,\n sessionId,\n message.index,\n message.id,\n message.role,\n message.timeCreated,\n message.timeCompleted ?? null,\n message.agent ?? null,\n message.mode ?? null,\n message.model ?? null,\n message.provider ?? null,\n message.tokensJson ?? null,\n message.cost ?? null,\n message.costSource ?? null,\n message.partsJson,\n MESSAGE_PARTS_FORMAT_VERSION,\n contentChainDigest,\n message.subagentId ?? null,\n message.nickname ?? null,\n message.automated ?? 0,\n message.contentText,\n message.toolMetadataJson ?? null,\n );\n for (const toolName of message.toolNames) {\n insertMessageTool.run(agentName, sessionId, message.index, toolName);\n }\n }\n deleteMessages.run(agentName, sessionId, entry.messages.length);\n deleteModelCost.run(agentName, sessionId);\n deleteCostSummary.run(agentName, sessionId);\n rebuildModelCost.run(agentName, sessionId);\n rebuildCostSummary.run(agentName, sessionId);\n },\n };\n}\n","import type { SessionDetail, SessionHead } from \"../../types/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport {\n SEARCH_INDEX_BULK_SYNC_THRESHOLD,\n type PersistedSessionHeadChange,\n type SQLiteStatement,\n} from \"./db.js\";\nimport { advanceAnalyticsRevision } from \"./analytics-revision.js\";\nimport {\n appendPlainText,\n buildSessionContentFromMessages,\n normalizeMessages,\n assertSessionProjectIdentities,\n requireSessionProjectIdentity,\n} from \"./messages.js\";\nimport { withSearchIndexDb } from \"./connection.js\";\nimport { runSearchIndexWrite } from \"./schema.js\";\nimport { sessionDetailVersion } from \"./detail-version.js\";\nimport {\n deletePublicationPayloads,\n discardPublicationStaging,\n readPublicationPayloads,\n stagePublicationPayloads,\n} from \"./publication-staging.js\";\nimport {\n prepareSessionMaterializationWriter,\n type SessionMaterializationEntry,\n} from \"./session-materialization-writer.js\";\nimport {\n detailVersionFromMetaJson,\n readSearchIndexState,\n searchIndexEntryNeedsUpdate,\n sessionContentHash,\n sessionDetailFactsHash,\n targetDetailVersion,\n type SearchIndexState,\n type SearchIndexSyncOptions,\n} from \"./search-index-state.js\";\n\nexport {\n readPendingSearchIndexMaintenance,\n searchIndexStateQuery,\n type PendingSearchIndexMaintenance,\n type SearchIndexPublicationStage,\n type SearchIndexSyncOptions,\n} from \"./search-index-state.js\";\n\nexport interface SearchIndexSyncFailure {\n sessionId: string;\n reason: \"parse-failed\" | \"superseded\";\n message?: string;\n}\n\nexport interface SearchIndexSyncResult {\n agentName: string;\n mode: \"bulk\" | \"incremental\";\n sessions: number;\n changed: number;\n deleted: number;\n indexed: number;\n skipped: number;\n failures?: SearchIndexSyncFailure[];\n durationMs: number;\n rebuildDurationMs?: number;\n planningDurationMs: number;\n getSessionDataCalls: number;\n reusedMaterializations: number;\n getSessionDataDurationMs: number;\n materializationDurationMs: number;\n}\n\nconst SEARCH_INDEX_COMMIT_CHUNK_SIZE = 64;\n\ninterface LoadedSearchIndexEntryBase {\n session: SessionHead;\n contentText: string;\n contentHash: string;\n detailVersion: string;\n sortIndex: number;\n messageCount: number;\n}\n\ninterface ParsedSearchIndexEntry extends LoadedSearchIndexEntryBase, SessionMaterializationEntry {\n materialization: \"replace\";\n}\n\ninterface ReusedSearchIndexEntry extends LoadedSearchIndexEntryBase {\n materialization: \"reuse\";\n}\n\ntype LoadedSearchIndexEntry = ParsedSearchIndexEntry | ReusedSearchIndexEntry;\n\ninterface SearchIndexRowWriteOptions {\n verifySupersession?: boolean;\n}\n\ninterface SearchIndexLoadTiming {\n calls: number;\n reused: number;\n getSessionDataMs: number;\n materializationMs: number;\n}\n\ntype SearchIndexPlanRequest =\n | { kind: \"snapshot\"; sessions: SessionHead[] }\n | {\n kind: \"changes\";\n changes: PersistedSessionHeadChange[];\n removedSessionIds: readonly string[];\n };\n\ninterface SearchIndexPlan {\n agentName: string;\n mode: \"bulk\" | \"incremental\";\n sessionCount: number;\n changes: PersistedSessionHeadChange[];\n removedSessionIds: string[];\n detailVersionBySessionId: Map<string, string>;\n reusableMessageCountBySessionId: Map<string, number>;\n needsRebuild: boolean;\n startedAt: number;\n}\n\ninterface SearchIndexPlanInput {\n agentName: string;\n sessionCount: number;\n candidates: PersistedSessionHeadChange[];\n removedSessionIds: string[];\n state: SearchIndexState;\n options: SearchIndexSyncOptions;\n startedAt: number;\n}\n\n/** Full snapshots bound memory with durable chunks; targeted changes retain one atomic write. */\ntype LargeBacklogWriteStrategy = \"atomic\" | \"chunked\";\n\ninterface PreparedSearchIndexPublication {\n agentName: string;\n mode: \"bulk\" | \"incremental\";\n sessions: number;\n changed: number;\n removedSessionIds: string[];\n entries: LoadedSearchIndexEntry[];\n publicationId?: string;\n /** Full entries stored outside the live tables until the atomic commit. */\n preStaged: number;\n failures: SearchIndexSyncFailure[];\n needsRebuild: boolean;\n startedAt: number;\n planningDurationMs: number;\n loadTiming: SearchIndexLoadTiming;\n}\n\nfunction createSearchIndexLoadTiming(): SearchIndexLoadTiming {\n return { calls: 0, reused: 0, getSessionDataMs: 0, materializationMs: 0 };\n}\n\nfunction shouldBulkSyncSearchIndex(\n db: SQLiteDatabase,\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 if (!(threshold > 0 && changedCount >= threshold)) return false;\n\n // Automatic rebuilds must not retokenize previously indexed sessions from any agent.\n return (\n options.bulkThreshold != null ||\n db.prepare(\"SELECT 1 FROM session_documents LIMIT 1\").get() === undefined\n );\n}\n\nfunction loadSearchIndexEntry(\n agentName: string,\n change: PersistedSessionHeadChange,\n loadSessionData: (sessionId: string) => SessionDetail,\n detailVersion: string,\n failures: SearchIndexSyncFailure[],\n timing: SearchIndexLoadTiming,\n): LoadedSearchIndexEntry | null {\n const sessionId = change.session.reference.sessionId;\n try {\n timing.calls += 1;\n const loadStartedAt = performance.now();\n let data: SessionDetail;\n try {\n data = loadSessionData(sessionId);\n } finally {\n timing.getSessionDataMs += performance.now() - loadStartedAt;\n }\n const materializationStartedAt = performance.now();\n try {\n const messages = normalizeMessages(data);\n const identity = requireSessionProjectIdentity(agentName, change.session);\n return {\n session: change.session,\n materialization: \"replace\",\n messages,\n contentText: buildSessionContentFromMessages(data.title ?? change.session.title, messages),\n contentHash: sessionContentHash(change.session),\n fileActivity: extractSessionFileActivity(agentName, sessionId, identity.key, data.messages),\n sortIndex: change.sortIndex,\n messageCount: messages.length,\n detailVersion,\n };\n } finally {\n timing.materializationMs += performance.now() - materializationStartedAt;\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n failures.push({ sessionId, reason: \"parse-failed\", message });\n getCoreDiagnostics()?.warn(\"search_index.session_parse_failed\", {\n agent: agentName,\n session_id: sessionId,\n message,\n });\n return null;\n }\n}\n\nfunction loadReusedSearchIndexEntry(\n readCachedContent: SQLiteStatement,\n agentName: string,\n change: PersistedSessionHeadChange,\n detailVersion: string,\n expectedMessageCount: number,\n timing: SearchIndexLoadTiming,\n): ReusedSearchIndexEntry | null {\n const sessionId = change.session.reference.sessionId;\n const startedAt = performance.now();\n try {\n const rows = readCachedContent.all(agentName, sessionId) as Array<{\n content_text?: string | null;\n }>;\n if (rows.length !== expectedMessageCount) return null;\n\n const chunks: string[] = [];\n appendPlainText(change.session.title, chunks);\n for (const row of rows) appendPlainText(row.content_text, chunks);\n timing.reused += 1;\n return {\n session: change.session,\n materialization: \"reuse\",\n contentText: chunks.join(\"\\n\"),\n contentHash: sessionContentHash(change.session),\n detailVersion,\n sortIndex: change.sortIndex,\n messageCount: rows.length,\n };\n } finally {\n timing.materializationMs += performance.now() - startedAt;\n }\n}\n\nfunction* loadSearchIndexEntries(\n db: SQLiteDatabase,\n agentName: string,\n changes: Iterable<PersistedSessionHeadChange>,\n loadSessionData: (sessionId: string) => SessionDetail,\n detailVersionFor: (sessionId: string) => string,\n failures: SearchIndexSyncFailure[],\n timing: SearchIndexLoadTiming,\n reusableMessageCountBySessionId: ReadonlyMap<string, number>,\n): Generator<LoadedSearchIndexEntry> {\n const readCachedContent = db.prepare(\n \"SELECT content_text FROM messages WHERE agent_name = ? AND session_id = ? ORDER BY message_index\",\n );\n for (const change of changes) {\n const sessionId = change.session.reference.sessionId;\n const detailVersion = detailVersionFor(sessionId);\n const reusableMessageCount = reusableMessageCountBySessionId.get(sessionId);\n if (reusableMessageCount !== undefined) {\n const reused = loadReusedSearchIndexEntry(\n readCachedContent,\n agentName,\n change,\n detailVersion,\n reusableMessageCount,\n timing,\n );\n if (reused) {\n yield reused;\n continue;\n }\n }\n const entry = loadSearchIndexEntry(\n agentName,\n change,\n loadSessionData,\n detailVersion,\n failures,\n timing,\n );\n if (entry) yield entry;\n }\n}\n\nfunction writeSearchIndexRows(\n db: SQLiteDatabase,\n agentName: string,\n removedSessionIds: string[],\n entries: Iterable<LoadedSearchIndexEntry>,\n failures: SearchIndexSyncFailure[],\n options: SearchIndexRowWriteOptions = {},\n): number {\n const { verifySupersession = true } = options;\n const deleteRow = db.prepare(\n \"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const materialization = prepareSessionMaterializationWriter(db, agentName);\n const upsertRow = db.prepare(`\n INSERT INTO session_documents(\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n detail_version,\n indexed_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n title = excluded.title,\n content_text = excluded.content_text,\n content_hash = excluded.content_hash,\n indexed_message_count = excluded.indexed_message_count,\n detail_version = excluded.detail_version,\n indexed_at = excluded.indexed_at\n `);\n\n const readCurrentMeta = db.prepare(\n \"SELECT meta_json FROM sessions WHERE agent_name = ? AND session_id = ?\",\n );\n\n const clearPendingReindex = db.prepare(\n \"DELETE FROM pending_reindex WHERE agent_name = ? AND session_id = ?\",\n );\n\n for (const sessionId of new Set(removedSessionIds)) {\n deleteRow.run(agentName, sessionId);\n materialization.deleteSession(sessionId);\n clearPendingReindex.run(agentName, sessionId);\n }\n\n let indexed = 0;\n for (const entry of entries) {\n const sessionId = entry.session.reference.sessionId;\n if (verifySupersession) {\n const current = readCurrentMeta.get(agentName, sessionId) as\n | { meta_json?: string | null }\n | undefined;\n if (entry.detailVersion !== detailVersionFromMetaJson(current?.meta_json)) {\n failures.push({ sessionId, reason: \"superseded\" });\n continue;\n }\n }\n clearPendingReindex.run(agentName, sessionId);\n if (entry.materialization === \"reuse\") {\n materialization.reuseSessionHead(entry.session, entry.sortIndex);\n } else {\n materialization.writeSession(entry);\n }\n upsertRow.run(\n agentName,\n sessionId,\n entry.session.title,\n entry.contentText,\n entry.contentHash,\n entry.messageCount,\n entry.detailVersion,\n Date.now(),\n );\n indexed += 1;\n }\n return indexed;\n}\n\n/**\n * Loaded entries carry full message bodies, so a backlog larger than one commit\n * chunk cannot be held in memory at once — a first-time index of a large agent\n * (multi-GB codex rollouts) used to OOM the search-index worker. Larger\n * backlogs are serialized into a shadow table in chunks. The final transaction\n * streams those payloads into the live tables, keeping memory bounded without\n * publishing any detail facts ahead of their session heads.\n */\nfunction loadOrPreStageEntries(\n db: SQLiteDatabase,\n agentName: string,\n changes: PersistedSessionHeadChange[],\n loadSessionData: (sessionId: string) => SessionDetail,\n detailVersionFor: (sessionId: string) => string,\n failures: SearchIndexSyncFailure[],\n timing: SearchIndexLoadTiming,\n reusableMessageCountBySessionId: ReadonlyMap<string, number>,\n publicationId?: string,\n): { entries: LoadedSearchIndexEntry[]; preStaged: number } {\n if (changes.length <= SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n return {\n entries: [\n ...loadSearchIndexEntries(\n db,\n agentName,\n changes,\n loadSessionData,\n detailVersionFor,\n failures,\n timing,\n reusableMessageCountBySessionId,\n ),\n ],\n preStaged: 0,\n };\n }\n\n if (!publicationId) {\n throw new Error(\"Large durable publications require a publication id\");\n }\n\n let preStaged = 0;\n for (let offset = 0; offset < changes.length; offset += SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n const chunk = changes.slice(offset, offset + SEARCH_INDEX_COMMIT_CHUNK_SIZE);\n runSearchIndexWrite(db, false, () => {\n const entries = loadSearchIndexEntries(\n db,\n agentName,\n chunk,\n loadSessionData,\n detailVersionFor,\n failures,\n timing,\n reusableMessageCountBySessionId,\n );\n preStaged += stagePublicationPayloads(\n db,\n publicationId,\n agentName,\n (function* () {\n for (const entry of entries) {\n yield {\n sessionId: entry.session.reference.sessionId,\n json: JSON.stringify(entry),\n };\n }\n })(),\n );\n });\n }\n getCoreDiagnostics()?.info?.(\"search_index.pre_staged\", {\n agent: agentName,\n changed: changes.length,\n staged: preStaged,\n });\n return { entries: [], preStaged };\n}\n\nfunction readSearchIndexPlanInput(\n db: SQLiteDatabase,\n agentName: string,\n request: SearchIndexPlanRequest,\n options: SearchIndexSyncOptions,\n): SearchIndexPlanInput {\n const startedAt = performance.now();\n let candidates: PersistedSessionHeadChange[];\n let removedSessionIds: string[];\n let sessionCount: number;\n\n if (request.kind === \"snapshot\") {\n const existingRows = db\n .prepare(\"SELECT session_id FROM session_documents WHERE agent_name = ? ORDER BY id\")\n .all(agentName) as Array<{ session_id?: string }>;\n const includedSessionIds = new Set(\n request.sessions.map((session) => session.reference.sessionId),\n );\n const sortIndexBySessionId = new Map(\n request.sessions.map((session, sortIndex) => [session.reference.sessionId, sortIndex]),\n );\n const explicitRemovedSessionIds = new Set(options.removedSessionIds ?? []);\n const completeness = options.completeness ?? \"complete\";\n removedSessionIds = existingRows\n .map((row) => String(row.session_id))\n .filter(\n (sessionId) =>\n explicitRemovedSessionIds.has(sessionId) ||\n (completeness === \"complete\" && !includedSessionIds.has(sessionId)),\n );\n candidates = request.sessions.map((session) => ({\n session,\n sortIndex: sortIndexBySessionId.get(session.reference.sessionId) ?? 0,\n }));\n sessionCount = request.sessions.length;\n } else {\n candidates = request.changes;\n removedSessionIds = [...new Set(request.removedSessionIds)];\n sessionCount = request.changes.length;\n }\n\n const state = readSearchIndexState(\n db,\n agentName,\n candidates.map(({ session }) => session.reference.sessionId),\n );\n\n return {\n agentName,\n sessionCount,\n candidates,\n removedSessionIds,\n state,\n options,\n startedAt,\n };\n}\n\nfunction planSearchIndexWrite(\n db: SQLiteDatabase,\n agentName: string,\n request: SearchIndexPlanRequest,\n options: SearchIndexSyncOptions,\n): SearchIndexPlan {\n const input = readSearchIndexPlanInput(db, agentName, request, options);\n const changes = input.candidates.filter(({ session }) =>\n searchIndexEntryNeedsUpdate(input.state, session, input.options),\n );\n const detailVersionBySessionId = new Map(\n changes.map(({ session }) => {\n const sessionId = session.reference.sessionId;\n return [sessionId, targetDetailVersion(input.state, sessionId, input.options)];\n }),\n );\n const unversionedDetail = sessionDetailVersion(null);\n // Reuse is safe only when the source-backed detail version, normalized message rows,\n // and every message-derived head fact still match.\n const reusableMessageCountBySessionId = new Map(\n changes.flatMap(({ session }) => {\n const sessionId = session.reference.sessionId;\n const targetVersion = detailVersionBySessionId.get(sessionId);\n const storedMessageCount = input.state.messageCountBySessionId.get(sessionId);\n const canReuse =\n typeof targetVersion === \"string\" &&\n targetVersion !== unversionedDetail &&\n typeof storedMessageCount === \"number\" &&\n input.state.detailVersionBySessionId.get(sessionId) === targetVersion &&\n input.state.indexedMessageCountBySessionId.get(sessionId) === storedMessageCount &&\n input.state.publishedDetailFactsHashBySessionId.get(sessionId) ===\n sessionDetailFactsHash(session) &&\n !input.state.pendingReindexSessionIds.has(sessionId);\n return canReuse ? ([[sessionId, storedMessageCount]] as const) : [];\n }),\n );\n const changedCount = input.removedSessionIds.length + changes.length;\n const isBulk = shouldBulkSyncSearchIndex(db, input.options, changedCount);\n\n return {\n agentName: input.agentName,\n mode: isBulk ? \"bulk\" : \"incremental\",\n sessionCount: input.sessionCount,\n changes,\n removedSessionIds: input.removedSessionIds,\n detailVersionBySessionId,\n reusableMessageCountBySessionId,\n needsRebuild: isBulk && changedCount > 0,\n startedAt: input.startedAt,\n };\n}\n\nfunction detailVersionForPlan(plan: SearchIndexPlan, sessionId: string): string {\n return plan.detailVersionBySessionId.get(sessionId) ?? sessionDetailVersion(null);\n}\n\nfunction prepareSearchIndexPublication(\n db: SQLiteDatabase,\n plan: SearchIndexPlan,\n loadSessionData: (sessionId: string) => SessionDetail,\n publicationId?: string,\n): PreparedSearchIndexPublication {\n getCoreDiagnostics()?.info?.(\"search_index.publication_plan\", {\n agent: plan.agentName,\n sessions: plan.sessionCount,\n changed: plan.changes.length,\n removed: plan.removedSessionIds.length,\n mode: plan.mode,\n planning_ms: Math.round(performance.now() - plan.startedAt),\n });\n const failures: SearchIndexSyncFailure[] = [];\n const planningDurationMs = performance.now() - plan.startedAt;\n const loadTiming = createSearchIndexLoadTiming();\n const { entries, preStaged } = loadOrPreStageEntries(\n db,\n plan.agentName,\n plan.changes,\n loadSessionData,\n (sessionId) => detailVersionForPlan(plan, sessionId),\n failures,\n loadTiming,\n plan.reusableMessageCountBySessionId,\n publicationId,\n );\n\n return {\n agentName: plan.agentName,\n mode: plan.mode,\n sessions: plan.sessionCount,\n changed: plan.changes.length,\n removedSessionIds: plan.removedSessionIds,\n entries,\n publicationId,\n preStaged,\n failures,\n needsRebuild: plan.needsRebuild,\n startedAt: plan.startedAt,\n planningDurationMs,\n loadTiming,\n };\n}\n\nexport function prepareSessionSnapshotSearchIndex(\n db: SQLiteDatabase,\n agentName: string,\n sessions: SessionHead[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): PreparedSearchIndexPublication {\n return prepareSearchIndexPublication(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"snapshot\", sessions }, options),\n loadSessionData,\n options.publicationId,\n );\n}\n\nexport function prepareSessionChangesSearchIndex(\n db: SQLiteDatabase,\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): PreparedSearchIndexPublication {\n return prepareSearchIndexPublication(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"changes\", changes, removedSessionIds }, options),\n loadSessionData,\n options.publicationId,\n );\n}\n\nexport function writePreparedSessionSearchIndex(\n db: SQLiteDatabase,\n publication: PreparedSearchIndexPublication,\n): SearchIndexSyncResult {\n let indexed = 0;\n const { rebuildDurationMs } = runSearchIndexWrite(\n db,\n publication.needsRebuild,\n () => {\n const entries = (function* (): Generator<LoadedSearchIndexEntry> {\n yield* publication.entries;\n if (!publication.publicationId || publication.preStaged === 0) return;\n for (const payload of readPublicationPayloads(\n db,\n publication.publicationId,\n publication.agentName,\n )) {\n yield JSON.parse(payload) as LoadedSearchIndexEntry;\n }\n })();\n indexed += writeSearchIndexRows(\n db,\n publication.agentName,\n publication.removedSessionIds,\n entries,\n publication.failures,\n );\n if (publication.publicationId) {\n deletePublicationPayloads(db, publication.publicationId, publication.agentName);\n }\n },\n \"caller\",\n );\n\n return {\n agentName: publication.agentName,\n mode: publication.mode,\n sessions: publication.sessions,\n changed: publication.changed,\n deleted: publication.removedSessionIds.length,\n indexed,\n skipped: publication.changed - indexed,\n failures: publication.failures.length > 0 ? publication.failures : undefined,\n durationMs: performance.now() - publication.startedAt,\n rebuildDurationMs,\n planningDurationMs: publication.planningDurationMs,\n getSessionDataCalls: publication.loadTiming.calls,\n reusedMaterializations: publication.loadTiming.reused,\n getSessionDataDurationMs: publication.loadTiming.getSessionDataMs,\n materializationDurationMs: publication.loadTiming.materializationMs,\n };\n}\n\nexport function discardPreparedSessionSearchIndex(publicationId: string, agentName: string): void {\n withSearchIndexDb((db) =>\n db.transaction(() => discardPublicationStaging(db, publicationId, agentName)).immediate(),\n );\n}\n\nfunction searchIndexSyncResult(\n plan: SearchIndexPlan,\n indexed: number,\n failures: SearchIndexSyncFailure[],\n planningDurationMs: number,\n loadTiming: SearchIndexLoadTiming,\n rebuildDurationMs?: number,\n mode = plan.mode,\n): SearchIndexSyncResult {\n return {\n agentName: plan.agentName,\n mode,\n sessions: plan.sessionCount,\n changed: plan.changes.length,\n deleted: plan.removedSessionIds.length,\n indexed,\n skipped: plan.changes.length - indexed,\n failures: failures.length > 0 ? failures : undefined,\n durationMs: performance.now() - plan.startedAt,\n rebuildDurationMs,\n planningDurationMs,\n getSessionDataCalls: loadTiming.calls,\n reusedMaterializations: loadTiming.reused,\n getSessionDataDurationMs: loadTiming.getSessionDataMs,\n materializationDurationMs: loadTiming.materializationMs,\n };\n}\n\nfunction executeSearchIndexPlan(\n db: SQLiteDatabase,\n plan: SearchIndexPlan,\n loadSessionData: (sessionId: string) => SessionDetail,\n largeBacklogStrategy: LargeBacklogWriteStrategy,\n): SearchIndexSyncResult {\n let indexed = 0;\n const failures: SearchIndexSyncFailure[] = [];\n const planningDurationMs = performance.now() - plan.startedAt;\n const loadTiming = createSearchIndexLoadTiming();\n const loadEntries = (changes: PersistedSessionHeadChange[]) =>\n loadSearchIndexEntries(\n db,\n plan.agentName,\n changes,\n loadSessionData,\n (sessionId) => detailVersionForPlan(plan, sessionId),\n failures,\n loadTiming,\n plan.reusableMessageCountBySessionId,\n );\n\n if (largeBacklogStrategy === \"chunked\" && plan.changes.length > SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n runSearchIndexWrite(db, false, () => {\n indexed += writeSearchIndexRows(db, plan.agentName, plan.removedSessionIds, [], failures);\n if (plan.removedSessionIds.length > 0) advanceAnalyticsRevision(db);\n });\n for (let offset = 0; offset < plan.changes.length; offset += SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n const chunk = plan.changes.slice(offset, offset + SEARCH_INDEX_COMMIT_CHUNK_SIZE);\n runSearchIndexWrite(db, false, () => {\n const chunkIndexed = writeSearchIndexRows(\n db,\n plan.agentName,\n [],\n loadEntries(chunk),\n failures,\n );\n indexed += chunkIndexed;\n if (chunkIndexed > 0) advanceAnalyticsRevision(db);\n });\n }\n return searchIndexSyncResult(\n plan,\n indexed,\n failures,\n planningDurationMs,\n loadTiming,\n undefined,\n \"incremental\",\n );\n }\n\n const { rebuildDurationMs } = runSearchIndexWrite(db, plan.needsRebuild, () => {\n indexed = writeSearchIndexRows(\n db,\n plan.agentName,\n plan.removedSessionIds,\n loadEntries(plan.changes),\n failures,\n );\n if (indexed > 0 || plan.removedSessionIds.length > 0) advanceAnalyticsRevision(db);\n });\n return searchIndexSyncResult(\n plan,\n indexed,\n failures,\n planningDurationMs,\n loadTiming,\n rebuildDurationMs,\n );\n}\n\nexport function syncSessionSearchIndex(\n agentName: string,\n sessions: SessionHead[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): SearchIndexSyncResult | null {\n assertSessionProjectIdentities(agentName, sessions);\n return withSearchIndexDb((db) =>\n executeSearchIndexPlan(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"snapshot\", sessions }, options),\n loadSessionData,\n \"chunked\",\n ),\n );\n}\n\nexport function syncSessionSearchIndexChanges(\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): SearchIndexSyncResult | null {\n if (changes.length === 0 && removedSessionIds.length === 0) {\n return {\n agentName,\n mode: \"incremental\",\n sessions: 0,\n changed: 0,\n deleted: 0,\n indexed: 0,\n skipped: 0,\n durationMs: 0,\n planningDurationMs: 0,\n getSessionDataCalls: 0,\n reusedMaterializations: 0,\n getSessionDataDurationMs: 0,\n materializationDurationMs: 0,\n };\n }\n\n assertSessionProjectIdentities(\n agentName,\n changes.map(({ session }) => session),\n );\n\n return withSearchIndexDb((db) =>\n executeSearchIndexPlan(\n db,\n planSearchIndexWrite(db, agentName, { kind: \"changes\", changes, removedSessionIds }, options),\n loadSessionData,\n \"atomic\",\n ),\n );\n}\n","import { normalizeProjectScopePath } from \"../../projects/scope.js\";\nimport type { SessionQueryScope } from \"../session-scope.js\";\n\nexport function buildSessionQueryScopeFilters(scope?: SessionQueryScope): {\n clauses: string[];\n params: unknown[];\n} {\n const clauses: string[] = [];\n const params: unknown[] = [];\n if (scope?.agents?.length) {\n clauses.push(`s.agent_name IN (${scope.agents.map(() => \"?\").join(\", \")})`);\n params.push(...scope.agents);\n }\n if (scope?.projectScope) {\n const project = scope.projectScope;\n const path = normalizeProjectScopePath(project.path);\n const directory = \"codesesh_project_scope_path(s.directory)\";\n clauses.push(\n `((s.project_identity_kind = ? AND s.project_identity_key = ?) OR (s.directory <> '' AND (${directory} = ? OR instr(${directory}, ? || '/') = 1 OR instr(?, ${directory} || '/') = 1)))`,\n );\n params.push(project.identity.kind, project.identity.key, path, path, path);\n }\n return { clauses, params };\n}\n","import { isSmartTag, type SmartTag } from \"../../contract/index.js\";\nimport type { FileActivityKind, ProjectIdentityKind } from \"../../types/index.js\";\nimport { isProjectIdentityKind } from \"../../projects/index.js\";\n\nexport interface SearchQueryFilters {\n agent?: string;\n project?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n cwd?: string;\n tags?: SmartTag[];\n tools?: string[];\n file?: string;\n fileKind?: FileActivityKind;\n costMin?: number;\n costMax?: number;\n costMinExclusive?: boolean;\n costMaxExclusive?: boolean;\n}\n\nexport interface ParsedSearchQuery {\n text: string;\n filters: SearchQueryFilters;\n hasQualifiers: boolean;\n}\n\nfunction escapeFtsTerm(value: string): string {\n return value.replaceAll('\"', '\"\"');\n}\n\nexport function splitSearchTokens(input: string): string[] {\n const tokens: string[] = [];\n let token = \"\";\n let inQuote = false;\n\n for (const char of input) {\n if (char === '\"') {\n inQuote = !inQuote;\n token += char;\n continue;\n }\n if (/\\s/.test(char) && !inQuote) {\n if (token) {\n tokens.push(token);\n token = \"\";\n }\n continue;\n }\n token += char;\n }\n\n if (token) tokens.push(token);\n return tokens;\n}\n\nexport function unwrapSearchValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1).trim();\n }\n return trimmed;\n}\n\nfunction parseCostQualifier(value: string, filters: SearchQueryFilters): void {\n const raw = unwrapSearchValue(value);\n const range = raw.match(/^(\\d+(?:\\.\\d+)?)\\.\\.(\\d+(?:\\.\\d+)?)$/);\n if (range) {\n setCostMinimum(filters, Number(range[1]), false);\n setCostMaximum(filters, Number(range[2]), false);\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 setCostMinimum(filters, amount, comparison[1] === \">\");\n } else {\n setCostMaximum(filters, amount, comparison[1] === \"<\");\n }\n return;\n }\n\n const amount = Number(raw);\n if (!Number.isNaN(amount)) {\n setCostMinimum(filters, amount, false);\n setCostMaximum(filters, amount, false);\n }\n}\n\nfunction setCostMinimum(filters: SearchQueryFilters, value: number, exclusive: boolean): void {\n filters.costMin = value;\n if (exclusive) filters.costMinExclusive = true;\n else delete filters.costMinExclusive;\n}\n\nfunction setCostMaximum(filters: SearchQueryFilters, value: number, exclusive: boolean): void {\n filters.costMax = value;\n if (exclusive) filters.costMaxExclusive = true;\n else delete filters.costMaxExclusive;\n}\n\nfunction appendUnique<T>(values: T[] | undefined, value: T): T[] {\n if (values?.includes(value)) return values;\n return [...(values ?? []), value];\n}\n\nexport function parseSearchQuery(input: string): ParsedSearchQuery {\n const filters: SearchQueryFilters = {};\n const textTokens: string[] = [];\n let hasQualifiers = false;\n\n for (const token of splitSearchTokens(input)) {\n const match = token.match(/^([a-zA-Z][a-zA-Z_-]*):(.+)$/);\n if (!match) {\n textTokens.push(token);\n continue;\n }\n\n const key = match[1]!.toLowerCase();\n const value = unwrapSearchValue(match[2]!);\n if (!value) continue;\n\n let consumed = true;\n if (key === \"agent\") filters.agent = value.toLowerCase();\n else if (key === \"project\") filters.project = value;\n else if (key === \"projectkey\" || key === \"project-key\") filters.projectKey = value;\n else if (key === \"projectkind\" || key === \"project-kind\") {\n if (isProjectIdentityKind(value)) filters.projectKind = value;\n else consumed = false;\n } else if (key === \"cwd\") filters.cwd = value;\n else if (key === \"tool\") filters.tools = appendUnique(filters.tools, value.toLowerCase());\n else if (key === \"file\" || key === \"path\") filters.file = value;\n else if (key === \"kind\" || key === \"filekind\" || key === \"file-kind\") {\n if (value === \"read\" || value === \"edit\" || value === \"write\" || value === \"delete\") {\n filters.fileKind = value;\n } else {\n consumed = false;\n }\n } else if (key === \"tag\" || key === \"signal\") {\n const tag = value.toLowerCase();\n if (isSmartTag(tag)) filters.tags = appendUnique(filters.tags, tag);\n else consumed = false;\n } else if (key === \"cost\") {\n parseCostQualifier(value, filters);\n } else {\n consumed = false;\n }\n\n if (consumed) hasQualifiers = true;\n else textTokens.push(token);\n }\n\n return {\n text: textTokens.join(\" \").trim(),\n filters,\n hasQualifiers,\n };\n}\n\nexport function toFtsQuery(input: string): string {\n const tokens = splitSearchTokens(input);\n return tokens\n .map((token) => {\n if (/^OR$/i.test(token)) return \"OR\";\n if (token.startsWith('\"') && token.endsWith('\"')) {\n return `\"${escapeFtsTerm(token.slice(1, -1))}\"`;\n }\n return `\"${escapeFtsTerm(token)}\"`;\n })\n .filter(\n (token, index, values) =>\n token !== \"OR\" ||\n (index > 0 &&\n index < values.length - 1 &&\n values[index - 1] !== \"OR\" &&\n values[index + 1] !== \"OR\"),\n )\n .join(\" \");\n}\n","/**\n * Full-text query reader and the stable search cache export surface.\n */\nimport type {\n FileActivityKind,\n IdentifiedSessionHead,\n Message,\n ProjectIdentityKind,\n SessionHead,\n SmartTag,\n} from \"../../types/index.js\";\nimport {\n getSessionReferenceKey,\n type SearchHighlightRange,\n type SearchMatchType,\n type SearchResult,\n} from \"../../contract/index.js\";\nimport type { ProjectScopeMatcher } from \"../../projects/scope.js\";\nimport type { SessionQueryScope } from \"../session-scope.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { escapeRegExp, filePathFtsQuery, hasCacheStorage, likePattern } from \"./db.js\";\nimport { normalizeToolName, sessionFromRow, type SessionRow } from \"./messages.js\";\nimport { withSearchDb } from \"./connection.js\";\nimport { buildSessionQueryScopeFilters } from \"./session-scope.js\";\nimport {\n parseSearchQuery,\n splitSearchTokens,\n toFtsQuery,\n unwrapSearchValue,\n type ParsedSearchQuery,\n type SearchQueryFilters,\n} from \"./search-query-parser.js\";\n\ninterface MessageSearchRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_index?: number;\n role?: Message[\"role\"];\n mode?: string | null;\n content_text?: string;\n tool_metadata_json?: string | null;\n}\n\nexport interface SearchResultRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n title?: string;\n directory?: string;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n time_created?: number;\n time_updated?: number | null;\n message_count?: number;\n total_input_tokens?: number;\n total_output_tokens?: number;\n total_cache_read_tokens?: number | null;\n total_cache_create_tokens?: number | null;\n total_cost?: number;\n cost_source?: string | null;\n total_tokens?: number | null;\n model_usage_json?: string | null;\n smart_tags_json?: string | null;\n smart_tags_source_updated_at?: number | null;\n snippet?: string | null;\n}\n\nexport type { SearchMatchType, SearchResult };\n\nexport { parseSearchQuery, type ParsedSearchQuery, type SearchQueryFilters };\n\nexport interface SearchOptions {\n agent?: string;\n project?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n projectScope?: ProjectScopeMatcher;\n tags?: SmartTag[];\n tools?: string[];\n file?: string;\n fileKind?: FileActivityKind;\n costMin?: number;\n costMax?: number;\n costMinExclusive?: boolean;\n costMaxExclusive?: boolean;\n from?: number;\n to?: number;\n limit?: number;\n}\n\nexport interface SearchRequestOptions extends SearchOptions {\n cwd?: string;\n}\n\nexport {\n readPendingSearchIndexMaintenance,\n syncSessionSearchIndex,\n syncSessionSearchIndexChanges,\n type PendingSearchIndexMaintenance,\n type SearchIndexPublicationStage,\n type SearchIndexSyncOptions,\n type SearchIndexSyncFailure,\n type SearchIndexSyncResult,\n} from \"./search-index-writer.js\";\nexport { sessionDetailVersion } from \"./detail-version.js\";\n\nexport function sessionHeadFromSearchRow(row: SearchResultRow): IdentifiedSessionHead {\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\nfunction mergeCostLimit(\n optionValue: number | undefined,\n optionExclusive: boolean | undefined,\n qualifierValue: number | undefined,\n qualifierExclusive: boolean | undefined,\n) {\n if (optionValue !== undefined) {\n return { value: optionValue, exclusive: optionExclusive };\n }\n if (qualifierValue !== undefined) {\n return { value: qualifierValue, exclusive: qualifierExclusive };\n }\n return { value: undefined, exclusive: undefined };\n}\n\nexport function mergeSearchQueryOptions(query: string, options: SearchOptions) {\n const parsed = parseSearchQuery(query);\n const costMin = mergeCostLimit(\n options.costMin,\n options.costMinExclusive,\n parsed.filters.costMin,\n parsed.filters.costMinExclusive,\n );\n const costMax = mergeCostLimit(\n options.costMax,\n options.costMaxExclusive,\n parsed.filters.costMax,\n parsed.filters.costMaxExclusive,\n );\n return {\n text: parsed.text || (parsed.hasQualifiers ? \"\" : query.trim()),\n options: {\n ...options,\n agent: options.agent ?? parsed.filters.agent,\n project: options.project ?? parsed.filters.project,\n projectKind: options.projectKind ?? parsed.filters.projectKind,\n projectKey: options.projectKey ?? parsed.filters.projectKey,\n tags: mergeSearchLists(options.tags, parsed.filters.tags),\n tools: mergeSearchLists(options.tools, parsed.filters.tools),\n file: options.file ?? parsed.filters.file,\n fileKind: options.fileKind ?? parsed.filters.fileKind,\n costMin: costMin.value,\n costMax: costMax.value,\n costMinExclusive: costMin.exclusive,\n costMaxExclusive: costMax.exclusive,\n },\n parsed,\n };\n}\n\nexport function getSearchProjectDirectory(\n query: string,\n options: SearchRequestOptions,\n): string | undefined {\n return options.cwd ?? parseSearchQuery(query).filters.cwd;\n}\n\nexport function sessionMatchesSearchCost(\n session: SessionHead,\n options: SearchOptions,\n cost = session.stats.total_cost,\n): boolean {\n if (options.costMin != null) {\n if (options.costMinExclusive ? cost <= options.costMin : cost < options.costMin) {\n return false;\n }\n }\n if (options.costMax != null) {\n if (options.costMaxExclusive ? cost >= options.costMax : cost > options.costMax) {\n return false;\n }\n }\n return true;\n}\n\nexport function buildSessionSearchFilters(\n options: SearchOptions,\n queryScope?: SessionQueryScope,\n): {\n where: string;\n params: unknown[];\n} {\n const { clauses, params } = buildSessionQueryScopeFilters(queryScope);\n\n if (options.agent) {\n clauses.push(\"s.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.projectKind || options.projectKey) {\n if (options.projectKind && options.projectKey) {\n clauses.push(\"s.project_identity_kind = ? AND s.project_identity_key = ?\");\n params.push(options.projectKind, options.projectKey);\n } else {\n clauses.push(\"0\");\n }\n }\n if (options.projectScope) {\n const project = buildSessionQueryScopeFilters({ projectScope: options.projectScope });\n clauses.push(...project.clauses);\n params.push(...project.params);\n }\n if (options.project) {\n clauses.push(\n \"(LOWER(s.project_identity_key) LIKE ? ESCAPE '\\\\' OR LOWER(s.project_display_name) LIKE ? ESCAPE '\\\\' OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n const pattern = likePattern(options.project);\n params.push(pattern, pattern, pattern);\n }\n for (const tag of options.tags ?? []) {\n clauses.push(\"s.smart_tags_json LIKE ?\");\n params.push(`%\"${tag}\"%`);\n }\n for (const tool of options.tools ?? []) {\n const toolName = normalizeToolName(tool);\n if (!toolName) continue;\n clauses.push(\n \"EXISTS (SELECT 1 FROM message_tools mt WHERE mt.tool_name = ? AND mt.agent_name = s.agent_name AND mt.session_id = s.session_id)\",\n );\n params.push(toolName);\n }\n if (options.file || options.fileKind) {\n const fileClauses = [\"fa.agent_name = s.agent_name\", \"fa.session_id = s.session_id\"];\n if (options.file) {\n const pathQuery = filePathFtsQuery(options.file);\n if (pathQuery) {\n fileClauses.push(\n \"fa.rowid IN (SELECT rowid FROM session_file_activity_path_fts WHERE path MATCH ?)\",\n );\n params.push(pathQuery);\n } else {\n fileClauses.push(\"LOWER(fa.path) LIKE ? ESCAPE '\\\\'\");\n params.push(likePattern(options.file));\n }\n }\n if (options.fileKind) {\n fileClauses.push(\"fa.kind = ?\");\n params.push(options.fileKind);\n }\n clauses.push(\n `EXISTS (SELECT 1 FROM session_file_activity fa WHERE ${fileClauses.join(\" AND \")})`,\n );\n }\n if (options.from != null) {\n clauses.push(\"s.activity_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"s.activity_time <= ?\");\n params.push(options.to);\n }\n appendInclusiveCostFilter(clauses, params, options);\n\n return {\n where: clauses.length > 0 ? ` AND ${clauses.join(\" AND \")}` : \"\",\n params,\n };\n}\n\nfunction appendInclusiveCostFilter(\n clauses: string[],\n params: unknown[],\n options: SearchOptions,\n): void {\n const predicates: string[] = [];\n if (options.costMin != null) {\n predicates.push(options.costMinExclusive ? \"SUM(own_cost) > ?\" : \"SUM(own_cost) >= ?\");\n params.push(options.costMin);\n }\n if (options.costMax != null) {\n predicates.push(options.costMaxExclusive ? \"SUM(own_cost) < ?\" : \"SUM(own_cost) <= ?\");\n params.push(options.costMax);\n }\n if (predicates.length === 0) return;\n\n // UNION makes malformed parent cycles converge while preserving one row per session.\n clauses.push(`EXISTS (\n WITH RECURSIVE session_subtree(agent_name, session_id, own_cost) AS (\n SELECT s.agent_name, s.session_id, s.total_cost\n UNION\n SELECT child.agent_name, child.session_id, child.total_cost\n FROM sessions child\n JOIN session_subtree parent\n ON child.parent_agent_name = parent.agent_name\n AND child.parent_session_id = parent.session_id\n WHERE child.publication_id IS NULL\n )\n SELECT SUM(own_cost)\n FROM session_subtree\n HAVING ${predicates.join(\" AND \")}\n )`);\n}\n\nexport interface SessionSearchReference {\n agentName: string;\n sessionId: string;\n}\n\nconst SQLITE_REFERENCE_BATCH_SIZE = 200;\n\nexport function filterIndexedSessionReferences(\n references: SessionSearchReference[],\n options: SearchOptions,\n): Set<string> {\n if (references.length === 0 || !hasCacheStorage()) return new Set();\n\n const matches = withSearchDb((db) => {\n const filters = buildSessionSearchFilters(options);\n const result = new Set<string>();\n\n for (let offset = 0; offset < references.length; offset += SQLITE_REFERENCE_BATCH_SIZE) {\n const batch = references.slice(offset, offset + SQLITE_REFERENCE_BATCH_SIZE);\n const referenceClauses = batch.map(() => \"(s.agent_name = ? AND s.session_id = ?)\");\n const referenceParams = batch.flatMap(({ agentName, sessionId }) => [agentName, sessionId]);\n const rows = db\n .prepare(\n `\n SELECT s.agent_name, s.session_id\n FROM sessions s\n WHERE (${referenceClauses.join(\" OR \")})\n AND s.publication_id IS NULL\n ${filters.where}\n `,\n )\n .all(...referenceParams, ...filters.params) as SearchResultRow[];\n\n for (const row of rows) {\n result.add(searchResultRowKey(row));\n }\n }\n\n return result;\n });\n\n return matches ?? new Set();\n}\n\nfunction searchSessionColumns(): string {\n return `\n s.agent_name,\n s.session_id,\n s.title,\n s.directory,\n s.project_identity_kind,\n s.project_identity_key,\n s.project_display_name,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at\n `;\n}\n\nfunction parseTextTerms(input: string): { terms: string[]; mode: \"all\" | \"any\" } {\n const tokens = splitSearchTokens(input);\n return {\n terms: tokens\n .filter((token) => !/^OR$/i.test(token))\n .map((token) => unwrapSearchValue(token).toLowerCase())\n .filter(Boolean),\n mode: tokens.some((token) => /^OR$/i.test(token)) ? \"any\" : \"all\",\n };\n}\n\nfunction textMatchesTerms(text: string, terms: { terms: string[]; mode: \"all\" | \"any\" }) {\n const lower = text.toLowerCase();\n if (terms.terms.length === 0) return true;\n if (terms.mode === \"any\") return terms.terms.some((term) => lower.includes(term));\n return terms.terms.every((term) => lower.includes(term));\n}\n\ninterface SearchSnippet {\n snippet: string;\n snippetHighlights: SearchHighlightRange[];\n}\n\nfunction findHighlightRanges(text: string, terms: string[]): SearchHighlightRange[] {\n const ranges = terms.flatMap((term) =>\n Array.from(text.matchAll(new RegExp(escapeRegExp(term), \"giu\")), (match) => ({\n start: match.index,\n end: match.index + match[0].length,\n })),\n );\n ranges.sort((left, right) => left.start - right.start || right.end - left.end);\n\n return ranges.reduce<SearchHighlightRange[]>((merged, range) => {\n const previous = merged.at(-1);\n if (previous && range.start <= previous.end) {\n previous.end = Math.max(previous.end, range.end);\n } else {\n merged.push(range);\n }\n return merged;\n }, []);\n}\n\nfunction buildTermSnippet(\n text: string,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n): SearchSnippet {\n const lower = text.toLowerCase();\n const term = terms.terms.find((item) => lower.includes(item)) ?? terms.terms[0] ?? \"\";\n if (!term) {\n return { snippet: text.slice(0, 180), snippetHighlights: [] };\n }\n\n const index = lower.indexOf(term);\n const start = Math.max(0, index - 80);\n const end = Math.min(text.length, index + term.length + 80);\n const snippet = `${start > 0 ? \"… \" : \"\"}${text.slice(start, end)}${\n end < text.length ? \" …\" : \"\"\n }`;\n return {\n snippet,\n snippetHighlights: findHighlightRanges(snippet, terms.terms),\n };\n}\n\nfunction messageMatchType(row: MessageSearchRow): SearchMatchType {\n if (row.role === \"user\") return \"user_message\";\n if (row.role === \"tool\" || row.mode === \"tool\" || row.tool_metadata_json) return \"tool_output\";\n return \"assistant_reply\";\n}\n\nfunction searchResultRowKey(row: Pick<SearchResultRow, \"agent_name\" | \"session_id\">): string {\n return getSessionReferenceKey({\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n });\n}\n\nfunction fetchMessageSearchMatches(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n): Map<string, SearchSnippet & { matchType: SearchMatchType }> {\n const startedAt = performance.now();\n const candidates = rows.filter((row) => !textMatchesTerms(String(row.title ?? \"\"), terms));\n if (candidates.length === 0) {\n return new Map();\n }\n\n const candidateValues = candidates.map(() => \"(?, ?)\").join(\", \");\n const candidateParams = candidates.flatMap((row) => [\n String(row.agent_name),\n String(row.session_id),\n ]);\n let predicateEvaluations = 0;\n db.function(\"codesesh_message_matches_terms\", { deterministic: true }, (text) => {\n predicateEvaluations += 1;\n return textMatchesTerms(String(text ?? \"\"), terms) ? 1 : 0;\n });\n\n const messageRows = db\n .prepare(\n `\n WITH candidate_sessions(agent_name, session_id) AS (\n VALUES ${candidateValues}\n ),\n first_message_matches AS MATERIALIZED (\n SELECT\n c.agent_name,\n c.session_id,\n (\n SELECT m.rowid\n FROM messages m INDEXED BY idx_messages_session\n WHERE m.agent_name = c.agent_name\n AND m.session_id = c.session_id\n AND codesesh_message_matches_terms(m.content_text)\n ORDER BY m.message_index\n LIMIT 1\n ) AS message_rowid\n FROM candidate_sessions c\n )\n SELECT\n m.agent_name,\n m.session_id,\n m.message_index,\n m.role,\n m.mode,\n m.content_text,\n m.tool_metadata_json\n FROM first_message_matches f\n JOIN messages m ON m.rowid = f.message_rowid\n `,\n )\n .all(...candidateParams) as MessageSearchRow[];\n const matches = new Map<string, SearchSnippet & { matchType: SearchMatchType }>();\n\n for (const message of messageRows) {\n const key = searchResultRowKey(message);\n if (matches.has(key)) continue;\n\n const text = String(message.content_text ?? \"\");\n if (!textMatchesTerms(text, terms)) continue;\n\n matches.set(key, {\n ...buildTermSnippet(text, terms),\n matchType: messageMatchType(message),\n });\n }\n\n getCoreDiagnostics()?.info?.(\"search.message_match_projection\", {\n candidate_sessions: candidates.length,\n predicate_evaluations: predicateEvaluations,\n matched_sessions: matches.size,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n\n return matches;\n}\n\nfunction resolveSearchMatch(\n row: SearchResultRow,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n messageMatches: Map<string, SearchSnippet & { matchType: SearchMatchType }>,\n): SearchSnippet & { matchType: SearchMatchType } {\n const title = String(row.title ?? \"\");\n\n if (terms.terms.length === 0) {\n return {\n snippet: `Recent session · ${String(row.directory ?? \"\")}`,\n snippetHighlights: [],\n matchType: \"recent\",\n };\n }\n\n if (textMatchesTerms(title, terms)) {\n return { ...buildTermSnippet(title, terms), matchType: \"title\" };\n }\n\n const messageMatch = messageMatches.get(searchResultRowKey(row));\n if (messageMatch) {\n return messageMatch;\n }\n\n return {\n snippet: String(row.snippet ?? \"\"),\n snippetHighlights: findHighlightRanges(String(row.snippet ?? \"\"), terms.terms),\n matchType: \"assistant_reply\",\n };\n}\n\nfunction rowsToSearchResults(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n textQuery: string,\n): SearchResult[] {\n const terms = parseTextTerms(textQuery);\n const messageMatches =\n terms.terms.length > 0\n ? fetchMessageSearchMatches(db, rows, terms)\n : new Map<string, SearchSnippet & { matchType: SearchMatchType }>();\n\n return rows.map((row) => {\n const match = resolveSearchMatch(row, terms, messageMatches);\n return {\n reference: {\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n },\n session: sessionHeadFromSearchRow(row),\n snippet: match.snippet,\n snippetHighlights: match.snippetHighlights,\n matchType: match.matchType,\n };\n });\n}\n\nexport function searchSessions(\n query: string,\n options: SearchOptions = {},\n queryScope?: SessionQueryScope,\n): SearchResult[] {\n const search = mergeSearchQueryOptions(query, options);\n const normalizedQuery = search.text.trim();\n if (!hasCacheStorage()) {\n return [];\n }\n\n const results = withSearchDb((db) => {\n const filters = buildSessionSearchFilters(search.options, queryScope);\n\n if (!normalizedQuery) {\n const rows = db\n .prepare(\n `\n SELECT\n ${searchSessionColumns()},\n '' AS snippet\n FROM sessions s\n WHERE 1 = 1\n AND s.publication_id IS NULL\n ${filters.where}\n ORDER BY s.activity_time DESC\n LIMIT ?\n `,\n )\n .all(...filters.params, search.options.limit ?? 50) as SearchResultRow[];\n\n return rowsToSearchResults(db, rows, \"\");\n }\n\n const ftsQuery = toFtsQuery(normalizedQuery);\n if (!ftsQuery) return [];\n const rows = db\n .prepare(\n `\n SELECT\n ${searchSessionColumns()},\n COALESCE(\n NULLIF(snippet(session_documents_fts, 1, '', '', ' … ', 18), ''),\n highlight(session_documents_fts, 0, '', '')\n ) AS snippet\n FROM session_documents_fts\n JOIN session_documents d ON d.id = session_documents_fts.rowid\n JOIN sessions s ON s.agent_name = d.agent_name AND s.session_id = d.session_id\n WHERE session_documents_fts MATCH ?\n AND s.publication_id IS NULL\n ${filters.where}\n ORDER BY bm25(session_documents_fts, 8.0, 1.0), s.activity_time DESC\n LIMIT ?\n `,\n )\n .all(ftsQuery, ...filters.params, search.options.limit ?? 50) as SearchResultRow[];\n\n return rowsToSearchResults(db, rows, normalizedQuery);\n });\n\n return results ?? [];\n}\n","/**\n * File activity aggregation: per-session / cross-session file activity queries\n * and file-path search.\n */\nimport type {\n FileActivityKind,\n ProjectIdentityKind,\n SessionFileActivity,\n} from \"../../types/index.js\";\nimport type { FileActivityResult, SearchHighlightRange } from \"../../contract/index.js\";\nimport type { ProjectScopeMatcher } from \"../../projects/scope.js\";\nimport type { SessionQueryScope } from \"../session-scope.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { filePathFtsQuery, hasCacheStorage, likePattern, normalizeFilePathSearch } from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./connection.js\";\nimport { buildSessionQueryScopeFilters } from \"./session-scope.js\";\nimport {\n buildSessionSearchFilters,\n mergeSearchQueryOptions,\n sessionHeadFromSearchRow,\n type SearchOptions,\n type SearchResult,\n type SearchResultRow,\n} from \"./search.js\";\n\nexport type { FileActivityResult };\n\nexport interface FileActivityRow extends SearchResultRow {\n project_identity_key?: string;\n path?: string;\n kind?: FileActivityKind;\n count?: number;\n latest_time?: number;\n}\n\nexport interface FileActivityOptions {\n agent?: string;\n sessionId?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n project?: string;\n projectScope?: ProjectScopeMatcher;\n path?: string;\n kind?: FileActivityKind;\n from?: number;\n to?: number;\n limit?: number;\n}\n\nexport function fileActivityFilters(options: FileActivityOptions): {\n projectKind: ProjectIdentityKind | null;\n projectKey: string | null;\n projectLike: string | null;\n path: string;\n pathLike: string | null;\n} {\n const path = options.path ? normalizeFilePathSearch(options.path) : \"\";\n return {\n projectKind: options.projectKind ?? null,\n projectKey: options.projectKey ?? null,\n projectLike: options.project ? likePattern(options.project) : null,\n path,\n pathLike: path ? likePattern(path) : null,\n };\n}\n\nexport function fileActivityFromRow(row: FileActivityRow): SessionFileActivity {\n return {\n reference: {\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n },\n projectIdentityKey: String(row.project_identity_key ?? \"\"),\n path: String(row.path ?? \"\"),\n kind: (row.kind ?? \"read\") as FileActivityKind,\n count: Number(row.count ?? 0),\n latestTime: Number(row.latest_time ?? 0),\n };\n}\n\nexport function buildFileActivityWhere(\n options: FileActivityOptions,\n queryScope?: SessionQueryScope,\n): {\n where: string;\n params: unknown[];\n} {\n const filters = fileActivityFilters(options);\n const { clauses, params } = buildSessionQueryScopeFilters(queryScope);\n\n if (options.agent != null) {\n clauses.push(\"fa.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.sessionId != null) {\n clauses.push(\"fa.session_id = ?\");\n params.push(options.sessionId);\n }\n if (filters.projectKind != null || filters.projectKey != null) {\n if (filters.projectKind != null && filters.projectKey != null) {\n clauses.push(\"s.project_identity_kind = ? AND fa.project_identity_key = ?\");\n params.push(filters.projectKind, filters.projectKey);\n } else {\n clauses.push(\"0\");\n }\n }\n if (filters.projectLike != null) {\n clauses.push(\n \"(LOWER(fa.project_identity_key) LIKE ? ESCAPE '\\\\' OR LOWER(s.project_display_name) LIKE ? ESCAPE '\\\\' OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n params.push(filters.projectLike, filters.projectLike, filters.projectLike);\n }\n if (options.projectScope) {\n const project = buildSessionQueryScopeFilters({ projectScope: options.projectScope });\n clauses.push(...project.clauses);\n params.push(...project.params);\n }\n if (filters.pathLike != null) {\n const pathQuery = filePathFtsQuery(filters.path);\n if (pathQuery) {\n clauses.push(\n \"fa.rowid IN (SELECT rowid FROM session_file_activity_path_fts WHERE path MATCH ?)\",\n );\n params.push(pathQuery);\n } else {\n clauses.push(\"LOWER(fa.path) LIKE ? ESCAPE '\\\\'\");\n params.push(filters.pathLike);\n }\n }\n if (options.kind != null) {\n clauses.push(\"fa.kind = ?\");\n params.push(options.kind);\n }\n if (options.from != null) {\n clauses.push(\"fa.latest_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"fa.latest_time <= ?\");\n params.push(options.to);\n }\n\n return {\n where: clauses.length > 0 ? `WHERE ${clauses.join(\" AND \")}` : \"\",\n params,\n };\n}\n\nconst FILE_ACTIVITY_COLUMNS = `\n fa.agent_name,\n fa.session_id,\n fa.project_identity_key,\n fa.path,\n fa.kind,\n fa.count,\n fa.latest_time,\n s.title,\n s.directory,\n s.project_identity_kind,\n s.project_display_name,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at\n`;\n\nconst FILE_ACTIVITY_JOIN = `\n FROM session_file_activity fa\n JOIN sessions s\n ON s.agent_name = fa.agent_name\n AND s.session_id = fa.session_id\n AND s.publication_id IS NULL\n`;\n\n/** Most recent first, then busiest, then path — the tie-break every caller relies on. */\nconst FILE_ACTIVITY_ORDER = \"fa.latest_time DESC, fa.count DESC, fa.path\";\n\nexport function listFileActivity(\n options: FileActivityOptions = {},\n queryScope?: SessionQueryScope,\n): FileActivityResult[] {\n return queryFileActivity({ options, queryScope });\n}\n\ninterface FileActivityQuery {\n options: FileActivityOptions;\n queryScope?: SessionQueryScope;\n sessionSearchOptions?: SearchOptions;\n /** Keep only each session's top-ranked row, so the limit counts sessions. */\n onePerSession?: boolean;\n}\n\nfunction fileActivityWhere(query: FileActivityQuery): { where: string; params: unknown[] } {\n const filters = buildFileActivityWhere(query.options, query.queryScope);\n const sessionFilters = query.sessionSearchOptions\n ? buildSessionSearchFilters(query.sessionSearchOptions)\n : { where: \"\", params: [] };\n const clauses = [\n filters.where.replace(/^WHERE /, \"\"),\n sessionFilters.where.replace(/^ AND /, \"\"),\n ].filter(Boolean);\n return {\n where: clauses.length > 0 ? `WHERE ${clauses.join(\" AND \")}` : \"\",\n params: [...filters.params, ...sessionFilters.params],\n };\n}\n\nfunction fileActivitySql(query: FileActivityQuery, where: string): string {\n if (!query.onePerSession) {\n return `\n SELECT ${FILE_ACTIVITY_COLUMNS}\n ${FILE_ACTIVITY_JOIN}\n ${where}\n ORDER BY ${FILE_ACTIVITY_ORDER}\n LIMIT ?\n `;\n }\n\n return `\n SELECT ${FILE_ACTIVITY_COLUMNS}\n FROM (\n SELECT\n fa.rowid AS activity_rowid,\n ROW_NUMBER() OVER (\n PARTITION BY fa.agent_name, fa.session_id\n ORDER BY ${FILE_ACTIVITY_ORDER}\n ) AS session_rank\n ${FILE_ACTIVITY_JOIN}\n ${where}\n ) ranked\n JOIN session_file_activity fa ON fa.rowid = ranked.activity_rowid\n JOIN sessions s\n ON s.agent_name = fa.agent_name\n AND s.session_id = fa.session_id\n AND s.publication_id IS NULL\n WHERE ranked.session_rank = 1\n ORDER BY ${FILE_ACTIVITY_ORDER}\n LIMIT ?\n `;\n}\n\nfunction queryFileActivity(query: FileActivityQuery): FileActivityResult[] {\n if (!hasCacheStorage()) {\n return [];\n }\n\n const { options } = query;\n const { where, params } = fileActivityWhere(query);\n const sql = fileActivitySql(query, where);\n const queryRows = (db: SQLiteDatabase) =>\n db.prepare(sql).all(...params, options.limit ?? 50) as FileActivityRow[];\n\n const read = withCacheDbReadOnly(queryRows);\n const rows =\n read.status === \"success\" ? read.value : options.path ? withCacheDb(queryRows) : null;\n\n return (rows ?? []).map((row) => ({\n ...fileActivityFromRow(row),\n session: sessionHeadFromSearchRow(row),\n }));\n}\n\nexport function listSessionFileActivity(\n agentName: string,\n sessionId: string,\n): SessionFileActivity[] {\n return listFileActivity({ agent: agentName, sessionId, limit: 500 }).map(\n ({ session: _session, ...activity }) => activity,\n );\n}\n\nexport function findFilePathHighlightRanges(path: string, query: string): SearchHighlightRange[] {\n const needle = normalizeFilePathSearch(query);\n if (!needle) return [];\n const lower = path.toLowerCase();\n const index = lower.indexOf(needle.toLowerCase());\n if (index < 0) return [];\n return [{ start: index, end: index + needle.length }];\n}\n\nexport function searchFileActivitySessions(\n query: string,\n options: SearchOptions = {},\n queryScope?: SessionQueryScope,\n): SearchResult[] {\n const search = mergeSearchQueryOptions(query, options);\n const path = normalizeFilePathSearch(search.options.file ?? search.text);\n if (!path) return [];\n\n const rows = queryFileActivity({\n options: {\n path,\n kind: search.options.fileKind,\n limit: search.options.limit ?? 50,\n },\n sessionSearchOptions: search.options,\n onePerSession: true,\n queryScope,\n });\n\n return rows.map((row) => {\n const prefix = `${row.kind} `;\n return {\n reference: row.reference,\n session: row.session,\n snippet: `${prefix}${row.path} · ${row.count} events`,\n snippetHighlights: findFilePathHighlightRanges(row.path, path).map((range) => ({\n start: prefix.length + range.start,\n end: prefix.length + range.end,\n })),\n matchType: \"file_path\",\n };\n });\n}\n","import type { SessionHead } from \"../types/index.js\";\nimport { matchesProjectScope, type ProjectScopeMatcher } from \"../projects/scope.js\";\n\nexport interface SessionQueryScope {\n agents?: readonly string[];\n projectScope?: ProjectScopeMatcher;\n}\n\nexport function matchesSessionQueryScope(session: SessionHead, scope?: SessionQueryScope): boolean {\n if (scope?.agents?.length && !scope.agents.includes(session.reference.agentName)) return false;\n return !scope?.projectScope || matchesProjectScope(session, scope.projectScope);\n}\n","/**\n * Cache persistence: load / save / clear / info / initialization tracking.\n */\nimport { existsSync, rmSync, unlinkSync } from \"node:fs\";\nimport type { SessionCacheMeta } from \"../../agents/session-source-types.js\";\nimport type { ReferencedSessionHead, SessionReference } from \"../../contract/index.js\";\nimport { formatSessionReference, normalizeSessionReference } from \"../../contract/index.js\";\nimport type {\n IdentifiedSessionDetail,\n IdentifiedSessionHead,\n SessionHead,\n} from \"../../types/index.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport { tableExists, type SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport {\n closeCacheStorage,\n getCachePath,\n getLegacyCachePath,\n hasCacheStorage,\n type ScalarRow,\n type PersistedSessionHeadChange,\n} from \"./db.js\";\nimport { advanceAnalyticsRevision } from \"./analytics-revision.js\";\nimport {\n withCacheDb,\n withCacheDbOutcome,\n withCacheDbReadOnly,\n type CacheReadOutcome,\n} from \"./connection.js\";\nimport {\n assertSessionProjectIdentities,\n messageFromCachedRow,\n prepareUpsertSession,\n sessionFromRow,\n sourcePathFromMeta,\n upsertSessionRow,\n type CachedMessageRow,\n type SessionRow,\n} from \"./messages.js\";\nimport { fileActivityFromRow, type FileActivityRow } from \"./file-activity.js\";\n\nexport const CACHE_INITIALIZATION_VERSION = \"session-cache-v2\";\nconst FULL_SYNC_CURSOR_PREFIX = \"full_sync_cursor:\";\nconst SESSION_REFERENCE_QUERY_CHUNK_SIZE = 400;\nconst SESSION_ROW_DELETE_ORDER = [\n \"pending_reindex\",\n \"session_documents\",\n \"message_tools\",\n \"messages\",\n \"session_model_cost\",\n \"session_cost_summary\",\n \"session_file_activity\",\n \"sessions\",\n] as const;\nconst SESSION_HEAD_SELECT_COLUMNS = `\n s.agent_name,\n s.session_id,\n s.sort_index,\n s.title,\n s.source_path,\n s.directory,\n s.parent_agent_name,\n s.parent_session_id,\n s.project_identity_kind,\n s.project_identity_key,\n s.project_display_name,\n s.project_identity_resolver_revision,\n s.project_identity_input_signature,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at,\n s.smart_tags_classifier_revision,\n s.meta_json\n`;\nexport interface CachedResult {\n sessions: IdentifiedSessionHead[];\n meta: Record<string, SessionCacheMeta>;\n timestamp: number;\n}\n\nexport interface CachedSessionDataEntry {\n data: IdentifiedSessionDetail;\n meta: SessionCacheMeta | null;\n}\n\ninterface CachedSessionEntryBase {\n data: Omit<IdentifiedSessionDetail, \"messages\">;\n meta: SessionCacheMeta | null;\n detailVersion: string | null;\n pendingReindex: boolean;\n}\n\nexport interface CachedSessionRawEntry extends CachedSessionEntryBase {\n messageRows: CachedMessageRow[];\n}\n\nexport interface CachedSessionCursorEntry extends CachedSessionEntryBase {\n messageCount: number;\n messageDigest: string | null;\n}\n\nexport interface CachedSessionCursorReader {\n messageDigest(messageCount: number): string | null;\n messageRows(startIndex: number): CachedMessageRow[];\n}\n\nexport type { SessionSnapshotCompleteness } from \"./snapshot-types.js\";\nimport type { SessionSnapshotCompleteness } from \"./snapshot-types.js\";\n\nexport interface SaveCachedSessionsOptions {\n completeness?: SessionSnapshotCompleteness;\n removedSessionIds?: readonly string[];\n}\n\nfunction parseCachedSessionMeta(value: string | null | undefined): SessionCacheMeta | null {\n if (!value) return null;\n try {\n return JSON.parse(value) as SessionCacheMeta;\n } catch {\n return null;\n }\n}\n\nexport function deleteLegacyCacheFile(): void {\n const legacyPath = getLegacyCachePath();\n if (!existsSync(legacyPath)) {\n return;\n }\n\n try {\n unlinkSync(legacyPath);\n } catch {\n // Ignore legacy cleanup errors\n }\n}\n\n/**\n * Distinguishes \"no cache yet\" (success with null) from \"the database read\n * failed\" so callers can log the degradation instead of silently rescanning.\n */\nexport function readCachedSessions(agentName: string): CacheReadOutcome<CachedResult | null> {\n if (!hasCacheStorage()) {\n return { status: \"success\", value: null };\n }\n\n return withCacheDbOutcome((db) => {\n const timestampRow = db\n .prepare(\"SELECT timestamp AS value FROM agent_cache WHERE agent_name = ?\")\n .get(agentName) as ScalarRow | undefined;\n const timestamp = Number(timestampRow?.value ?? 0);\n\n if (!timestamp) {\n return null;\n }\n\n const rows = db\n .prepare(\n `\n SELECT ${SESSION_HEAD_SELECT_COLUMNS}\n FROM sessions s\n WHERE s.agent_name = ? AND s.publication_id IS NULL\n ORDER BY s.activity_time DESC, s.session_id\n `,\n )\n .all(agentName) as SessionRow[];\n\n const sessions: IdentifiedSessionHead[] = [];\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.reference.sessionId] = JSON.parse(row.meta_json) as SessionCacheMeta;\n }\n }\n\n return { sessions, meta, timestamp };\n });\n}\n\nexport function loadCachedSessionHeads(\n references: readonly SessionReference[],\n): ReferencedSessionHead[] {\n if (references.length === 0 || !hasCacheStorage()) return [];\n\n const unique = new Map<string, SessionReference>();\n for (const reference of references) {\n const normalized = normalizeSessionReference(reference);\n const key = formatSessionReference(normalized);\n if (!unique.has(key)) unique.set(key, normalized);\n }\n\n const outcome = withCacheDbReadOnly((db) => {\n const resolved: ReferencedSessionHead[] = [];\n const normalized = [...unique.values()];\n for (let offset = 0; offset < normalized.length; offset += SESSION_REFERENCE_QUERY_CHUNK_SIZE) {\n const chunk = normalized.slice(offset, offset + SESSION_REFERENCE_QUERY_CHUNK_SIZE);\n const values = chunk.map(() => \"(?, ?)\").join(\", \");\n const params = chunk.flatMap((reference) => [reference.agentName, reference.sessionId]);\n const rows = db\n .prepare(\n `\n WITH requested(agent_name, session_id) AS (\n VALUES ${values}\n )\n SELECT ${SESSION_HEAD_SELECT_COLUMNS}\n FROM requested r\n JOIN sessions s\n ON s.agent_name = r.agent_name\n AND s.session_id = r.session_id\n AND s.publication_id IS NULL\n `,\n )\n .all(...params) as SessionRow[];\n\n for (const row of rows) {\n resolved.push({\n reference: normalizeSessionReference({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n }),\n session: sessionFromRow(row),\n });\n }\n }\n return resolved;\n });\n return outcome.status === \"success\" ? outcome.value : [];\n}\n\nexport function readAgentCacheInitialization(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): CacheReadOutcome<boolean> {\n if (!hasCacheStorage()) {\n return { status: \"success\", value: false };\n }\n\n return withCacheDbReadOnly((db) => {\n if (!tableExists(db, \"cache_initialization\")) return false;\n const row = db\n .prepare(\n `\n SELECT index_version\n FROM cache_initialization\n WHERE agent_name = ?\n `,\n )\n .get(agentName) as { index_version?: string } | undefined;\n return row?.index_version === indexVersion;\n });\n}\n\nexport function isAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): boolean {\n const outcome = readAgentCacheInitialization(agentName, indexVersion);\n return outcome.status === \"success\" && outcome.value;\n}\n\n/**\n * Marks the cache as warm/usable so refreshes can rely on incremental checks\n * instead of a raw full scan. This is deliberately independent of full-history\n * reconciliation: a first scan may be bounded to a display window, so\n * last_sync_at defaults to 0 (never synced) here and is only advanced by\n * markAgentFullSyncCompleted once a genuine unbounded pass completes.\n */\nexport function markAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): void {\n withCacheDb((db) => {\n db.prepare(\n `\n INSERT INTO cache_initialization(agent_name, initialized_at, index_version, last_sync_at)\n VALUES (?, ?, ?, 0)\n ON CONFLICT(agent_name) DO UPDATE SET\n index_version = excluded.index_version\n `,\n ).run(agentName, Date.now(), indexVersion);\n });\n}\n\n/**\n * Mark a full-history reconciliation as incomplete until it commits.\n * Returns whether the write reached disk, like saveCachedSessions.\n */\nexport function markAgentFullSyncStarted(agentName: string): boolean {\n const persisted = withCacheDb((db) => {\n db.prepare(\n `\n UPDATE cache_initialization\n SET last_sync_at = 0\n WHERE agent_name = ?\n `,\n ).run(agentName);\n return true;\n });\n return persisted ?? false;\n}\n\n/** Return the last durable source position reached by an incomplete full sync. */\nexport function getAgentFullSyncCursor(agentName: string): string | null {\n if (!hasCacheStorage()) return null;\n\n const outcome = withCacheDbReadOnly((db) => {\n const row = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(`${FULL_SYNC_CURSOR_PREFIX}${agentName}`) as { value?: string } | undefined;\n return row?.value || null;\n });\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\n/**\n * Persist a full-sync cursor only after the corresponding checkpoint is\n * durable. Returns whether the write reached disk — a dropped cursor means\n * every restart re-walks the whole history, so callers must not report the\n * checkpoint as durable on false.\n */\nexport function markAgentFullSyncProgress(agentName: string, cursor: string): boolean {\n if (!cursor) return true;\n\n const persisted = withCacheDb((db) => {\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(`${FULL_SYNC_CURSOR_PREFIX}${agentName}`, cursor);\n return true;\n });\n return persisted ?? false;\n}\n\nexport function readAgentLastFullSyncAt(agentName: string): CacheReadOutcome<number | null> {\n if (!hasCacheStorage()) {\n return { status: \"success\", value: null };\n }\n\n return withCacheDbReadOnly((db) => {\n if (!tableExists(db, \"cache_initialization\")) return null;\n const row = db\n .prepare(\n `\n SELECT last_sync_at\n FROM cache_initialization\n WHERE agent_name = ?\n `,\n )\n .get(agentName) as { last_sync_at?: number } | undefined;\n return row?.last_sync_at || null;\n });\n}\n\n/** Timestamp of the agent's last full (unbounded) history reconciliation, or null if none yet. */\nexport function getAgentLastFullSyncAt(agentName: string): number | null {\n const outcome = readAgentLastFullSyncAt(agentName);\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\n/**\n * Record that a full (unbounded) history reconciliation just completed for\n * this agent. Returns whether the write reached disk.\n */\nexport function markAgentFullSyncCompleted(agentName: string): boolean {\n const completedAt = Date.now();\n const persisted = withCacheDb((db) => {\n db.transaction(() => {\n // Upsert: on a fresh cache the initialization row may not exist yet,\n // and a bare UPDATE would silently record nothing (last_sync_at would\n // read back as \"never synced\" and re-trigger a full backfill).\n db.prepare(\n `\n INSERT INTO cache_initialization(agent_name, initialized_at, index_version, last_sync_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET\n last_sync_at = excluded.last_sync_at\n `,\n ).run(agentName, completedAt, CACHE_INITIALIZATION_VERSION, completedAt);\n db.prepare(\"DELETE FROM cache_meta WHERE key = ?\").run(\n `${FULL_SYNC_CURSOR_PREFIX}${agentName}`,\n );\n }).immediate();\n return true;\n });\n return persisted ?? false;\n}\n\nfunction loadCachedSessionEntryBase(\n db: SQLiteDatabase,\n agentName: string,\n sessionId: string,\n): CachedSessionEntryBase | null {\n const row = db\n .prepare(\n `\n SELECT\n sessions.*,\n documents.detail_version AS detail_version\n FROM sessions\n LEFT JOIN session_documents AS documents\n ON documents.agent_name = sessions.agent_name\n AND documents.session_id = sessions.session_id\n WHERE sessions.agent_name = ?\n AND sessions.session_id = ?\n AND sessions.publication_id IS NULL\n `,\n )\n .get(agentName, sessionId) as SessionRow | undefined;\n\n if (!row) return null;\n\n const pendingReindex =\n db\n .prepare(\"SELECT 1 FROM pending_reindex WHERE agent_name = ? AND session_id = ?\")\n .get(agentName, sessionId) != null;\n const fileActivityRows = db\n .prepare(\n `\n SELECT agent_name, session_id, project_identity_key, path, kind, count, latest_time\n FROM session_file_activity\n WHERE agent_name = ? AND session_id = ?\n ORDER BY latest_time DESC, count DESC, path\n LIMIT 500\n `,\n )\n .all(agentName, sessionId) as FileActivityRow[];\n\n return {\n data: {\n ...sessionFromRow(row),\n reference: { agentName, sessionId },\n file_activity: fileActivityRows.map((activityRow) => fileActivityFromRow(activityRow)),\n },\n meta: parseCachedSessionMeta(row.meta_json),\n detailVersion: typeof row.detail_version === \"string\" ? row.detail_version : null,\n pendingReindex,\n };\n}\n\nfunction readCachedSessionMessageRows(\n db: SQLiteDatabase,\n agentName: string,\n sessionId: string,\n startIndex: number,\n): CachedMessageRow[] {\n return db\n .prepare(\n `\n SELECT\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n tokens_json,\n cost,\n cost_source,\n parts_json,\n parts_format_version,\n content_chain_digest,\n subagent_id,\n nickname,\n automated\n FROM messages\n WHERE agent_name = ? AND session_id = ? AND message_index >= ?\n ORDER BY message_index\n `,\n )\n .all(agentName, sessionId, startIndex) as CachedMessageRow[];\n}\n\nexport function loadCachedSessionRawEntry(\n agentName: string,\n sessionId: string,\n): CachedSessionRawEntry | null {\n if (!hasCacheStorage()) return null;\n\n const outcome = withCacheDbReadOnly((db) =>\n db.transaction(() => {\n const entry = loadCachedSessionEntryBase(db, agentName, sessionId);\n return entry\n ? { ...entry, messageRows: readCachedSessionMessageRows(db, agentName, sessionId, 0) }\n : null;\n })(),\n );\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\nfunction readCachedSessionMessageDigest(\n db: SQLiteDatabase,\n agentName: string,\n sessionId: string,\n messageCount: number,\n): string | null {\n if (!Number.isSafeInteger(messageCount) || messageCount <= 0) return null;\n const row = db\n .prepare(\n `\n SELECT content_chain_digest\n FROM messages\n WHERE agent_name = ? AND session_id = ? AND message_index = ?\n `,\n )\n .get(agentName, sessionId, messageCount - 1) as { content_chain_digest?: string | null };\n return typeof row?.content_chain_digest === \"string\" ? row.content_chain_digest : null;\n}\n\nexport function readCachedSessionCursor<T>(\n agentName: string,\n sessionId: string,\n read: (entry: CachedSessionCursorEntry, cursor: CachedSessionCursorReader) => T,\n): T | null {\n if (!hasCacheStorage()) return null;\n\n // A deferred transaction keeps cursor metadata and suffix rows in one snapshot.\n const outcome = withCacheDbReadOnly((db) =>\n db.transaction(() => {\n const entryBase = loadCachedSessionEntryBase(db, agentName, sessionId);\n if (!entryBase) return null;\n const messageState = db\n .prepare(\n `\n SELECT\n COUNT(*) AS message_count,\n (\n SELECT content_chain_digest\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n ORDER BY message_index DESC\n LIMIT 1\n ) AS content_chain_digest\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n `,\n )\n .get(agentName, sessionId, agentName, sessionId) as {\n message_count?: number;\n content_chain_digest?: string | null;\n };\n const entry: CachedSessionCursorEntry = {\n ...entryBase,\n messageCount: Number(messageState.message_count ?? 0),\n messageDigest:\n typeof messageState.content_chain_digest === \"string\"\n ? messageState.content_chain_digest\n : null,\n };\n return read(entry, {\n messageDigest: (messageCount) =>\n readCachedSessionMessageDigest(db, agentName, sessionId, messageCount),\n messageRows: (startIndex) =>\n Number.isSafeInteger(startIndex) && startIndex >= 0\n ? readCachedSessionMessageRows(db, agentName, sessionId, startIndex)\n : [],\n });\n })(),\n );\n return outcome.status === \"success\" ? outcome.value : null;\n}\n\nexport function loadCachedSessionDataEntry(\n agentName: string,\n sessionId: string,\n): CachedSessionDataEntry | null {\n const entry = loadCachedSessionRawEntry(agentName, sessionId);\n if (!entry) return null;\n return {\n data: {\n ...entry.data,\n messages: entry.pendingReindex\n ? []\n : entry.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n },\n meta: entry.meta,\n };\n}\n\nexport function loadCachedSessionData(\n agentName: string,\n sessionId: string,\n): IdentifiedSessionDetail | null {\n return loadCachedSessionDataEntry(agentName, sessionId)?.data ?? null;\n}\n\n/**\n * Returns whether the write reached disk; on `false`, callers must not mark the cache initialized\n * or a full sync complete.\n */\nexport function saveCachedSessions(\n agentName: string,\n sessions: SessionHead[],\n meta: Record<string, SessionCacheMeta> = {},\n options: SaveCachedSessionsOptions = {},\n): boolean {\n assertSessionProjectIdentities(agentName, sessions);\n const persisted = withCacheDb((db) => {\n db.transaction(() => {\n writeCachedSessionSnapshot(db, agentName, sessions, meta, options);\n advanceAnalyticsRevision(db);\n }).immediate();\n deleteLegacyCacheFile();\n return true;\n });\n\n return persisted ?? false;\n}\n\nexport function writeCachedSessionSnapshot(\n db: SQLiteDatabase,\n agentName: string,\n sessions: SessionHead[],\n meta: Record<string, SessionCacheMeta> = {},\n options: SaveCachedSessionsOptions = {},\n): void {\n const completeness = options.completeness ?? \"complete\";\n const upsertAgent = db.prepare(`\n INSERT INTO agent_cache(agent_name, timestamp)\n VALUES (?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET timestamp = excluded.timestamp\n `);\n const upsertSession = prepareUpsertSession(db);\n const sessionIds = new Set(sessions.map((session) => session.reference.sessionId));\n const existingSessionIds = db\n .prepare(\"SELECT session_id FROM sessions WHERE agent_name = ?\")\n .all(agentName) as SessionRow[];\n\n upsertAgent.run(agentName, Date.now());\n\n const sessionIdsToDelete = new Set(options.removedSessionIds ?? []);\n if (completeness === \"complete\") {\n for (const row of existingSessionIds) {\n const sessionId = String(row.session_id);\n if (!sessionIds.has(sessionId)) sessionIdsToDelete.add(sessionId);\n }\n }\n deleteCachedSessionRows(db, agentName, sessionIdsToDelete);\n\n sessions.forEach((session, index) => {\n const sessionMeta = meta[session.reference.sessionId];\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n index,\n sourcePathFromMeta(sessionMeta),\n );\n });\n}\n\n/**\n * Returns whether the write reached disk. On `false`, callers may serve the in-memory result\n * but must not advance the persistence timestamp, initialization marker, or durable baseline.\n */\nexport function saveCachedSessionChanges(\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n meta: Record<string, SessionCacheMeta> = {},\n): boolean {\n assertSessionProjectIdentities(\n agentName,\n changes.map(({ session }) => session),\n );\n const persisted = withCacheDb((db) => {\n db.transaction(() => {\n writeCachedSessionChanges(db, agentName, changes, removedSessionIds, meta);\n if (changes.length > 0 || removedSessionIds.length > 0) {\n advanceAnalyticsRevision(db);\n }\n }).immediate();\n deleteLegacyCacheFile();\n return true;\n });\n\n return persisted ?? false;\n}\n\nexport function writeCachedSessionChanges(\n db: SQLiteDatabase,\n agentName: string,\n changes: PersistedSessionHeadChange[],\n removedSessionIds: string[],\n meta: Record<string, SessionCacheMeta> = {},\n): void {\n const upsertAgent = db.prepare(`\n INSERT INTO agent_cache(agent_name, timestamp)\n VALUES (?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET timestamp = excluded.timestamp\n `);\n const upsertSession = prepareUpsertSession(db);\n\n upsertAgent.run(agentName, Date.now());\n\n deleteCachedSessionRows(db, agentName, removedSessionIds);\n\n for (const { session, sortIndex } of changes) {\n const sessionId = session.reference.sessionId;\n const sessionMeta = meta[sessionId];\n if (!sessionMeta) {\n getCoreDiagnostics()?.warn(\"cache.session_meta_missing\", {\n agent: agentName,\n session_id: sessionId,\n });\n }\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n sortIndex,\n sourcePathFromMeta(sessionMeta),\n );\n }\n}\n\nfunction deleteCachedSessionRows(\n db: SQLiteDatabase,\n agentName: string,\n sessionIds: Iterable<string>,\n): void {\n const deleteStatements = SESSION_ROW_DELETE_ORDER.map((table) =>\n db.prepare(`DELETE FROM ${table} WHERE agent_name = ? AND session_id = ?`),\n );\n for (const sessionId of new Set(sessionIds)) {\n for (const statement of deleteStatements) statement.run(agentName, sessionId);\n }\n}\n\nexport function clearCache(): void {\n closeCacheStorage();\n if (!hasCacheStorage()) {\n deleteLegacyCacheFile();\n return;\n }\n\n withCacheDb((db) => {\n db.transaction(() => {\n db.exec(`\n DELETE FROM agent_cache;\n DELETE FROM cache_initialization;\n DELETE FROM pending_reindex;\n DELETE FROM session_documents;\n DELETE FROM session_file_activity;\n DELETE FROM message_tools;\n DELETE FROM messages;\n DELETE FROM session_model_cost;\n DELETE FROM session_cost_summary;\n DELETE FROM sessions;\n -- analytics_revision is an invalidation counter, not cached data.\n DELETE FROM cache_meta WHERE key <> 'analytics_revision';\n `);\n advanceAnalyticsRevision(db);\n }).immediate();\n });\n closeCacheStorage();\n\n deleteLegacyCacheFile();\n\n const cachePath = getCachePath();\n const walPath = `${cachePath}-wal`;\n const shmPath = `${cachePath}-shm`;\n\n for (const filePath of [walPath, shmPath]) {\n if (!existsSync(filePath)) {\n continue;\n }\n try {\n rmSync(filePath, { force: true });\n } catch {\n // Ignore sidecar cleanup errors\n }\n }\n}\n\nexport function getCacheInfo(): { lastScanTime: number | null; size: number } {\n if (!hasCacheStorage()) {\n return { lastScanTime: null, size: 0 };\n }\n\n const info = withCacheDb((db) => {\n const timestampRow = db.prepare(\"SELECT MAX(timestamp) AS value FROM agent_cache\").get() as\n | ScalarRow\n | undefined;\n const sizeRow = db\n .prepare(\"SELECT COUNT(*) AS value FROM sessions WHERE publication_id IS NULL\")\n .get() as ScalarRow | undefined;\n\n const lastScanTime = Number(timestampRow?.value ?? 0) || null;\n const size = Number(sizeRow?.value ?? 0);\n\n return { lastScanTime, size };\n });\n\n return info ?? { lastScanTime: null, size: 0 };\n}\n","/**\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 { assertIdentifiedSessionHead } from \"../contract/index.js\";\nimport { sortSessionsByActivity } from \"../contract/session-index.js\";\nimport type {\n IdentifiedSessionHead,\n ProjectIdentity,\n SessionHead,\n SessionReference,\n SessionStats,\n} from \"../types/index.js\";\nimport type { PersistedSessionHeadChange } from \"./cache/db.js\";\nimport type { SessionSnapshotCompleteness } from \"./cache/sessions.js\";\nimport {\n computeIdentityProjection,\n normalizeProjectDirectory,\n realFs,\n type ProjectIdentityProjection,\n} from \"../projects/index.js\";\n\ntype ProjectIdentityResolver = (directory: string) => ProjectIdentityProjection;\n\n/** Attach or refresh project identities once per normalized directory. */\nexport function attachMissingProjectIdentities(\n sessions: SessionHead[],\n resolve: ProjectIdentityResolver = (directory) => computeIdentityProjection(directory, realFs),\n): IdentifiedSessionHead[] {\n const projections = new Map<string, ProjectIdentityProjection>();\n\n return sessions.map((session) => {\n const directory = normalizeProjectDirectory(session.directory);\n let projection = projections.get(directory);\n if (!projection) {\n projection = resolve(directory);\n projections.set(directory, projection);\n }\n\n const identity = session.project_identity;\n if (\n identity?.kind === projection.identity.kind &&\n identity.key === projection.identity.key &&\n identity.displayName === projection.identity.displayName &&\n session.project_identity_resolver_revision === projection.resolverRevision &&\n session.project_identity_input_signature === projection.inputSignature\n ) {\n assertIdentifiedSessionHead(session);\n return session;\n }\n\n return {\n ...session,\n project_identity: projection.identity,\n project_identity_resolver_revision: projection.resolverRevision,\n project_identity_input_signature: projection.inputSignature,\n };\n });\n}\n\n/** Export an agent's cache metadata, optionally restricted to a set of ids. */\nexport function buildAgentCacheMeta(\n agent: BaseAgent,\n sessionIds?: Set<string>,\n): Record<string, SessionCacheMeta> {\n return agent.snapshotSessionCacheMeta(sessionIds);\n}\n\ntype SignatureValue = string | number | boolean | null | readonly SignatureValue[];\n\ntype SignatureSpec<Value extends object, Field extends keyof Value = keyof Value> = {\n [Key in Field]-?: (value: Value) => readonly SignatureValue[];\n};\n\ntype ObjectSignatureSpec<Value extends object> = {\n [Key in keyof Value]-?: (value: Value) => SignatureValue;\n};\n\nfunction signatureValues<Value extends object, Field extends keyof Value>(\n value: Value,\n spec: SignatureSpec<Value, Field>,\n): SignatureValue[] {\n const values: SignatureValue[] = [];\n for (const key of Object.keys(spec) as Array<Extract<Field, string>>) {\n values.push(...spec[key](value));\n }\n return values;\n}\n\nfunction objectSignatureValues<Value extends object>(\n value: Value | undefined,\n spec: ObjectSignatureSpec<Value>,\n): SignatureValue[] {\n const keys = Object.keys(spec) as Array<Extract<keyof Value, string>>;\n if (!value) return keys.map(() => null);\n return keys.map((key) => spec[key](value));\n}\n\nconst SESSION_REFERENCE_SIGNATURE_SPEC = {\n agentName: (reference) => reference.agentName,\n sessionId: (reference) => reference.sessionId,\n} satisfies ObjectSignatureSpec<SessionReference>;\n\nconst PROJECT_IDENTITY_SIGNATURE_SPEC = {\n kind: (identity) => identity.kind,\n key: (identity) => identity.key,\n displayName: (identity) => identity.displayName,\n} satisfies ObjectSignatureSpec<ProjectIdentity>;\n\nconst SESSION_STATS_SIGNATURE_SPEC = {\n message_count: (stats) => stats.message_count,\n total_input_tokens: (stats) => stats.total_input_tokens,\n total_output_tokens: (stats) => stats.total_output_tokens,\n total_cost: (stats) => stats.total_cost,\n cost_source: (stats) => stats.cost_source ?? null,\n total_tokens: (stats) => stats.total_tokens ?? 0,\n total_cache_read_tokens: (stats) => stats.total_cache_read_tokens ?? 0,\n total_cache_create_tokens: (stats) => stats.total_cache_create_tokens ?? 0,\n} satisfies ObjectSignatureSpec<SessionStats>;\n\n/** `display_title` is local API decoration, not a source-session fact. */\ntype SessionHeadSignatureExcludedField = \"display_title\";\n\ntype SessionHeadSignatureField = Exclude<keyof SessionHead, SessionHeadSignatureExcludedField>;\n\nfunction modelUsageSignature(modelUsage: SessionHead[\"model_usage\"]): SignatureValue {\n if (!modelUsage) return null;\n return Object.entries(modelUsage)\n .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n .map(([model, tokens]) => [model, tokens]);\n}\n\nconst SESSION_HEAD_SIGNATURE_SPEC = {\n reference: (session) =>\n objectSignatureValues(session.reference, SESSION_REFERENCE_SIGNATURE_SPEC),\n title: (session) => [session.title],\n directory: (session) => [session.directory],\n parent_reference: (session) =>\n objectSignatureValues(session.parent_reference, SESSION_REFERENCE_SIGNATURE_SPEC),\n project_identity: (session) =>\n objectSignatureValues(session.project_identity, PROJECT_IDENTITY_SIGNATURE_SPEC),\n project_identity_resolver_revision: (session) => [\n session.project_identity_resolver_revision ?? null,\n ],\n project_identity_input_signature: (session) => [session.project_identity_input_signature ?? null],\n time_created: (session) => [session.time_created],\n time_updated: (session) => [session.time_updated ?? session.time_created],\n stats: (session) => objectSignatureValues(session.stats, SESSION_STATS_SIGNATURE_SPEC),\n model_usage: (session) => [modelUsageSignature(session.model_usage)],\n smart_tags: (session) => [session.smart_tags ? [...session.smart_tags].sort() : null],\n smart_tags_source_updated_at: (session) => [session.smart_tags_source_updated_at ?? null],\n smart_tags_classifier_revision: (session) => [session.smart_tags_classifier_revision ?? null],\n} satisfies SignatureSpec<SessionHead, SessionHeadSignatureField>;\n\n/** Stable signature for canonical session fields used by both scan orchestrators. */\nexport function sessionSignature(session: SessionHead): string {\n return JSON.stringify(signatureValues(session, SESSION_HEAD_SIGNATURE_SPEC));\n}\n\n/** Sort sessions by activity time, newest first. */\nexport function sortSessions<T extends SessionHead>(sessions: T[]): T[] {\n return sortSessionsByActivity(sessions);\n}\n\nexport interface SessionDiffResult<T extends SessionHead = SessionHead> {\n changes: PersistedSessionHeadChange<T>[];\n removedSessionIds: string[];\n counts: { new: number; updated: number; removed: number };\n}\n\n/**\n * Compute the diff between a cached session set and an updated one.\n *\n * `signature` is injected so callers control the equality口径: a session counts\n * as \"changed\" if it is new, if its id is in `changedIds`, or if its signature\n * differs from the cached copy. The algorithm is pure — event assembly and\n * no-op short-circuiting stay with the caller.\n *\n * `signatureCache` is an optional id→signature memo the caller owns across\n * calls (e.g. across refresh cycles). On the cached side it's consulted before\n * falling back to `signature(cached)`; every updated session's signature is\n * written back into it, so the next call's cached-side lookups for unchanged\n * sessions can skip recomputation entirely. Mutating this caller-supplied map\n * is the only side effect — there's no module-level state. Callers must only\n * pass a cache whose lineage matches `cachedSessions`: if `cachedSessions` can\n * be a baseline the cache was never populated from (e.g. a DB snapshot instead\n * of the previous call's `updatedSessions`), a stale or mismatched hit will\n * silently suppress a real change.\n */\nexport function computeSessionDiff<T extends SessionHead>(\n cachedSessions: SessionHead[],\n updatedSessions: T[],\n changedIds: readonly string[] = [],\n signature: (session: SessionHead) => string = sessionSignature,\n signatureCache?: Map<string, string>,\n): SessionDiffResult<T> {\n const cachedMap = new Map(\n cachedSessions.map((session) => [session.reference.sessionId, session]),\n );\n const updatedIds = new Set(updatedSessions.map((session) => session.reference.sessionId));\n const changedIdSet = new Set(changedIds);\n const changes: PersistedSessionHeadChange<T>[] = [];\n const removedSessionIds: string[] = [];\n let newCount = 0;\n let updatedCount = 0;\n\n updatedSessions.forEach((session, sortIndex) => {\n const sessionId = session.reference.sessionId;\n const cached = cachedMap.get(sessionId);\n if (!cached) {\n newCount += 1;\n changes.push({ session, sortIndex });\n signatureCache?.set(sessionId, signature(session));\n return;\n }\n const cachedSignature = signatureCache?.get(cached.reference.sessionId) ?? signature(cached);\n const updatedSignature = signature(session);\n signatureCache?.set(sessionId, updatedSignature);\n if (changedIdSet.has(sessionId) || cachedSignature !== updatedSignature) {\n updatedCount += 1;\n changes.push({ session, sortIndex });\n }\n });\n\n for (const session of cachedSessions) {\n const sessionId = session.reference.sessionId;\n if (!updatedIds.has(sessionId)) {\n removedSessionIds.push(sessionId);\n }\n }\n\n return {\n changes,\n removedSessionIds,\n counts: { new: newCount, updated: updatedCount, removed: removedSessionIds.length },\n };\n}\n\nexport interface SessionPersistenceDiff<T extends SessionHead> {\n changedSessions: PersistedSessionHeadChange<T>[];\n removedSessionIds: string[];\n}\n\nexport interface SessionPersistenceDiffOptions {\n candidateChangedIds?: readonly string[];\n completeness?: SessionSnapshotCompleteness;\n explicitRemovedSessionIds?: readonly string[];\n}\n\nexport function buildSessionPersistenceDiff<T extends SessionHead>(\n previousSessions: SessionHead[],\n nextSessions: T[],\n options: SessionPersistenceDiffOptions = {},\n): SessionPersistenceDiff<T> {\n const { changes, removedSessionIds } = computeSessionDiff(\n previousSessions,\n nextSessions,\n options.candidateChangedIds,\n sessionSignature,\n );\n if ((options.completeness ?? \"complete\") === \"complete\") {\n return { changedSessions: changes, removedSessionIds };\n }\n\n const explicitRemovals = new Set(options.explicitRemovedSessionIds);\n return {\n changedSessions: changes,\n removedSessionIds: removedSessionIds.filter((sessionId) => explicitRemovals.has(sessionId)),\n };\n}\n","import { availableParallelism } from \"node:os\";\nimport { Worker } from \"node:worker_threads\";\nimport type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport type { SessionDetail, SessionHead, SmartTag } from \"../types/index.js\";\nimport {\n classifySessionTags,\n getSmartTagSourceTimestamp,\n isWorkerLogMessage,\n SMART_TAG_CLASSIFIER_REVISION,\n type WorkerLogMessage,\n} from \"../utils/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport { getPricingGeneration } from \"../pricing/index.js\";\nimport { buildAgentCacheMeta } from \"./orchestrate.js\";\n\nexport interface SessionTagTiming {\n sessions: number;\n cacheHits: number;\n staleSessions: number;\n failedSessions: number;\n getSessionDataCalls: number;\n getSessionDataMs: number;\n classifySessionTagsCalls: number;\n classifySessionTagsMs: number;\n}\n\ninterface SmartTagWorkerResult {\n id: string;\n tags?: SmartTag[];\n sourceUpdatedAt?: number;\n error?: string;\n}\n\nconst SMART_TAG_WORKER_TIMEOUT_MS = 300_000;\n\nexport function hasStaleSessionTags(\n session: SessionHead,\n classifierRevision = SMART_TAG_CLASSIFIER_REVISION,\n): boolean {\n const sourceUpdatedAt = session.time_updated ?? session.time_created;\n return (\n !Array.isArray(session.smart_tags) ||\n session.smart_tags_source_updated_at !== sourceUpdatedAt ||\n session.smart_tags_classifier_revision !== classifierRevision\n );\n}\n\n/** Preserve cached tags until the shared freshness check proves they need recomputing. */\nexport function inheritSessionTags(\n sessions: SessionHead[],\n previousSessions: SessionHead[],\n): SessionHead[] {\n const previousById = new Map(\n previousSessions.map((session) => [session.reference.sessionId, session]),\n );\n return sessions.map((session) => {\n if (Array.isArray(session.smart_tags)) return session;\n const previous = previousById.get(session.reference.sessionId);\n if (!previous || !Array.isArray(previous.smart_tags)) return session;\n return {\n ...session,\n smart_tags: previous.smart_tags,\n smart_tags_source_updated_at: previous.smart_tags_source_updated_at,\n smart_tags_classifier_revision: previous.smart_tags_classifier_revision,\n };\n });\n}\n\nexport function ensureSessionTagsSync(\n agent: BaseAgent,\n sessions: SessionHead[],\n onProgress?: (processed: number, total: number) => void,\n classifierRevision = SMART_TAG_CLASSIFIER_REVISION,\n): { sessions: SessionHead[]; changed: boolean; timing: SessionTagTiming } {\n let changed = false;\n let processed = 0;\n const total = sessions.length;\n const timing: SessionTagTiming = {\n sessions: total,\n cacheHits: 0,\n staleSessions: 0,\n failedSessions: 0,\n getSessionDataCalls: 0,\n getSessionDataMs: 0,\n classifySessionTagsCalls: 0,\n classifySessionTagsMs: 0,\n };\n\n const tagged = sessions.map((session) => {\n if (!hasStaleSessionTags(session, classifierRevision)) {\n timing.cacheHits += 1;\n processed += 1;\n onProgress?.(processed, total);\n return session;\n }\n\n timing.staleSessions += 1;\n try {\n timing.getSessionDataCalls += 1;\n const getSessionDataStartedAt = performance.now();\n let data: SessionDetail;\n try {\n data = agent.getSessionData(session.reference.sessionId);\n } finally {\n timing.getSessionDataMs += performance.now() - getSessionDataStartedAt;\n }\n\n timing.classifySessionTagsCalls += 1;\n const classifySessionTagsStartedAt = performance.now();\n let tags: SmartTag[];\n try {\n tags = classifySessionTags(data);\n } finally {\n timing.classifySessionTagsMs += performance.now() - classifySessionTagsStartedAt;\n }\n\n changed = true;\n return {\n ...session,\n smart_tags: tags,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n smart_tags_classifier_revision: classifierRevision,\n };\n } catch {\n timing.failedSessions += 1;\n return session;\n } finally {\n processed += 1;\n onProgress?.(processed, total);\n }\n });\n\n return { sessions: tagged, changed, timing };\n}\n\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\nasync function classifySessionTagsInWorker(\n workerUrl: URL | string,\n agentName: string,\n sessionIds: string[],\n meta: Record<string, SessionCacheMeta>,\n): Promise<SmartTagWorkerResult[]> {\n const worker = new Worker(workerUrl, {\n workerData: {\n pricingGenerationId: getPricingGeneration().id,\n agentName,\n sessionIds,\n meta,\n },\n });\n let timer: NodeJS.Timeout | undefined;\n try {\n return await new Promise<SmartTagWorkerResult[]>((resolveWorker, rejectWorker) => {\n timer = setTimeout(() => {\n rejectWorker(\n new Error(`Smart tag worker timed out after ${SMART_TAG_WORKER_TIMEOUT_MS}ms`),\n );\n }, SMART_TAG_WORKER_TIMEOUT_MS);\n worker.on(\"message\", (message: unknown) => {\n if (isWorkerLogMessage(message)) {\n relayWorkerLogMessage(message);\n return;\n }\n const results = message as SmartTagWorkerResult[];\n // A non-empty request with no results means the worker failed before\n // classification, so fall back instead of publishing untagged sessions.\n if (results.length === 0 && sessionIds.length > 0) {\n rejectWorker(new Error(\"Smart tag worker returned no results\"));\n return;\n }\n resolveWorker(results);\n });\n worker.once(\"error\", rejectWorker);\n // A clean exit before a result is still a failure; otherwise this promise\n // remains pending and blocks startup indefinitely.\n worker.once(\"exit\", (code) => {\n rejectWorker(new Error(`Smart tag worker exited with code ${code} before responding`));\n });\n });\n } finally {\n if (timer) clearTimeout(timer);\n worker.terminate().catch(() => {});\n }\n}\n\nfunction relayWorkerLogMessage(message: WorkerLogMessage): void {\n const detail = {\n ...message.data,\n worker_ts: message.ts,\n worker_pid: message.pid,\n worker_thread_id: message.threadId,\n worker_level: message.level,\n };\n if (message.level === \"warn\" || message.level === \"error\") {\n getCoreDiagnostics()?.warn(message.event, detail);\n return;\n }\n getCoreDiagnostics()?.info?.(message.event, detail);\n}\n\nexport async function ensureSessionTags(\n agent: BaseAgent,\n sessions: SessionHead[],\n workerUrl?: URL | string,\n): Promise<{ sessions: SessionHead[]; changed: boolean }> {\n const staleSessions = sessions.filter((session) => hasStaleSessionTags(session));\n if (staleSessions.length === 0) return { sessions, changed: false };\n\n const workerCount = workerUrl ? getSmartTagWorkerCount(staleSessions.length) : 1;\n if (workerCount <= 1) return ensureSessionTagsSync(agent, sessions);\n\n const meta = buildAgentCacheMeta(agent);\n try {\n const results = (\n await Promise.all(\n chunkSessions(\n staleSessions.map((session) => session.reference.sessionId),\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.reference.sessionId);\n if (!result?.tags || result.sourceUpdatedAt == null) return session;\n return {\n ...session,\n smart_tags: result.tags,\n smart_tags_source_updated_at: result.sourceUpdatedAt,\n smart_tags_classifier_revision: SMART_TAG_CLASSIFIER_REVISION,\n };\n }),\n };\n } catch {\n return ensureSessionTagsSync(agent, sessions);\n }\n}\n","import type {\n AggregateSessionSourceCapability,\n AgentScanOptions,\n BaseAgent,\n ChangeCheckResult,\n EnumeratedSessionSourceCapability,\n SessionSourceFailure,\n SessionSourceCapability,\n SessionSourceSynchronizationBaseline,\n SessionSourceSynchronizationTiming,\n} from \"../agents/index.js\";\nimport type { SessionHead } from \"../types/index.js\";\nimport type { SessionSnapshotCompleteness } from \"./cache/snapshot-types.js\";\nimport { inheritSessionTags } from \"./session-tags.js\";\n\nexport type AgentScanIntent = \"reload\" | \"refresh\" | \"backfill\" | \"recompute-derived\";\n\nexport type AgentScanPlan =\n | { kind: \"scan\" }\n | {\n kind: \"synchronize\";\n requestKind: \"reload\" | \"refresh\";\n source: EnumeratedSessionSourceCapability;\n }\n | { kind: \"check-for-changes\"; source: AggregateSessionSourceCapability }\n | { kind: \"reuse-baseline\" };\n\ntype SourceScanPlan = Extract<AgentScanPlan, { kind: \"scan\" | \"synchronize\" }>;\ntype RefreshScanPlan = Extract<AgentScanPlan, { kind: \"synchronize\" | \"check-for-changes\" }>;\ntype RecomputeScanPlan = Extract<AgentScanPlan, { kind: \"reuse-baseline\" }>;\nexport type ExecutableAgentScanPlan = Exclude<AgentScanPlan, { kind: \"check-for-changes\" }>;\n\nexport interface AgentScanPlanExecution {\n sessions: SessionHead[];\n detectedSessionIds: string[];\n changedSessionIds: string[];\n finalizeSessionIds?: string[];\n explicitRemovedSessionIds: string[];\n sourceFailures: SessionSourceFailure[];\n completeness: SessionSnapshotCompleteness;\n sourceSynchronization?: {\n sourceCount: number;\n removedSourceCount: number;\n timing: SessionSourceSynchronizationTiming;\n };\n}\n\ntype SuccessfulChangeCheck = Exclude<ChangeCheckResult, { status: \"failed\" }>;\n\nexport function resolveSessionSnapshotCompleteness(\n options: Pick<AgentScanOptions, \"from\" | \"to\">,\n sourceFailures: readonly SessionSourceFailure[],\n): SessionSnapshotCompleteness {\n return options.from == null && options.to == null && sourceFailures.length === 0\n ? \"complete\"\n : \"partial\";\n}\n\nexport function executeAgentScanPlan(\n agent: BaseAgent,\n plan: ExecutableAgentScanPlan,\n baseline: SessionSourceSynchronizationBaseline,\n scanOptions: AgentScanOptions = {},\n): AgentScanPlanExecution {\n if (plan.kind === \"synchronize\") {\n const result = plan.source.synchronize(baseline, {\n kind: plan.requestKind,\n scanOptions,\n });\n return {\n sessions: result.sessions,\n detectedSessionIds: result.detectedSessionIds,\n changedSessionIds: result.changedSessionIds,\n finalizeSessionIds: result.finalizeSessionIds,\n explicitRemovedSessionIds: result.explicitRemovedSessionIds,\n sourceFailures: result.sourceFailures,\n completeness: result.completeness,\n sourceSynchronization: {\n sourceCount: result.sourceCount,\n removedSourceCount: result.removedSourceCount,\n timing: result.timing,\n },\n };\n }\n\n const sessions =\n plan.kind === \"reuse-baseline\"\n ? baseline.sessions\n : inheritSessionTags(agent.scan(scanOptions), baseline.sessions);\n const sourceFailures: SessionSourceFailure[] = [];\n return {\n sessions,\n detectedSessionIds: [],\n changedSessionIds: [],\n explicitRemovedSessionIds: [],\n sourceFailures,\n completeness: resolveSessionSnapshotCompleteness(scanOptions, sourceFailures),\n };\n}\n\nexport type AgentRefreshInspection =\n | {\n kind: \"synchronize\";\n source: EnumeratedSessionSourceCapability;\n }\n | {\n kind: \"failed\";\n failure: Extract<ChangeCheckResult, { status: \"failed\" }>[\"failure\"];\n checkDurationMs: number;\n }\n | {\n kind: \"unchanged\";\n source: AggregateSessionSourceCapability;\n check: SuccessfulChangeCheck;\n checkDurationMs: number;\n }\n | {\n kind: \"scan\";\n source: AggregateSessionSourceCapability;\n check: SuccessfulChangeCheck;\n checkDurationMs: number;\n };\n\nexport type AgentRefreshSelection =\n | { kind: \"unavailable\"; availabilityDurationMs: number }\n | { kind: \"initialize\"; availabilityDurationMs: number }\n | ({ kind: \"synchronize\"; source: EnumeratedSessionSourceCapability } & {\n availabilityDurationMs: number;\n })\n | ({\n kind: \"failed\";\n failure: Extract<ChangeCheckResult, { status: \"failed\" }>[\"failure\"];\n checkDurationMs: number;\n } & { availabilityDurationMs: number })\n | ({\n kind: \"recompute-derived\";\n source: AggregateSessionSourceCapability;\n check: SuccessfulChangeCheck;\n checkDurationMs: number;\n } & { availabilityDurationMs: number })\n | ({\n kind: \"full-scan\";\n source: AggregateSessionSourceCapability;\n check: SuccessfulChangeCheck;\n checkDurationMs: number;\n } & { availabilityDurationMs: number })\n | ({\n kind: \"incremental-scan\";\n source: AggregateSessionSourceCapability;\n check: SuccessfulChangeCheck & { changedIds: string[] };\n checkDurationMs: number;\n } & { availabilityDurationMs: number });\n\ntype CommittableAgentRefresh = Extract<\n AgentRefreshSelection,\n { kind: \"recompute-derived\" | \"full-scan\" | \"incremental-scan\" }\n>;\n\nexport interface AgentRefreshTransaction {\n selection: AgentRefreshSelection;\n commit(): void;\n}\n\nexport function planAgentScan(\n source: SessionSourceCapability,\n intent: \"reload\" | \"backfill\",\n): SourceScanPlan;\nexport function planAgentScan(source: SessionSourceCapability, intent: \"refresh\"): RefreshScanPlan;\nexport function planAgentScan(\n source: SessionSourceCapability,\n intent: \"recompute-derived\",\n): RecomputeScanPlan;\nexport function planAgentScan(\n source: SessionSourceCapability,\n intent: AgentScanIntent,\n): AgentScanPlan;\nexport function planAgentScan(\n source: SessionSourceCapability,\n intent: AgentScanIntent,\n): AgentScanPlan {\n if (intent === \"recompute-derived\") return { kind: \"reuse-baseline\" };\n\n if (source.kind === \"enumerated\") {\n return {\n kind: \"synchronize\",\n requestKind: intent === \"reload\" ? \"reload\" : \"refresh\",\n source,\n };\n }\n\n return intent === \"refresh\" ? { kind: \"check-for-changes\", source } : { kind: \"scan\" };\n}\n\nexport async function inspectAgentRefresh(\n source: SessionSourceCapability,\n sinceTimestamp: number,\n cachedSessions: SessionHead[],\n): Promise<AgentRefreshInspection> {\n const plan = planAgentScan(source, \"refresh\");\n if (plan.kind === \"synchronize\") {\n return { kind: \"synchronize\", source: plan.source };\n }\n\n const startedAt = performance.now();\n const check = await Promise.resolve(plan.source.checkForChanges(sinceTimestamp, cachedSessions));\n const checkDurationMs = performance.now() - startedAt;\n if (check.status === \"failed\") {\n return { kind: \"failed\", failure: check.failure, checkDurationMs };\n }\n return check.hasChanges\n ? { kind: \"scan\", source: plan.source, check, checkDurationMs }\n : { kind: \"unchanged\", source: plan.source, check, checkDurationMs };\n}\n\nexport async function selectAgentRefresh(\n agent: Pick<BaseAgent, \"isAvailable\" | \"sessionSourceAccess\">,\n options: {\n initialized: boolean;\n sinceTimestamp: number;\n cachedSessions: SessionHead[];\n },\n): Promise<AgentRefreshSelection> {\n const availabilityStartedAt = performance.now();\n const available = agent.isAvailable();\n const availabilityDurationMs = performance.now() - availabilityStartedAt;\n if (!available) return { kind: \"unavailable\", availabilityDurationMs };\n if (!options.initialized) return { kind: \"initialize\", availabilityDurationMs };\n\n const inspection = await inspectAgentRefresh(\n agent.sessionSourceAccess,\n options.sinceTimestamp,\n options.cachedSessions,\n );\n if (inspection.kind === \"unchanged\") {\n return { ...inspection, kind: \"recompute-derived\", availabilityDurationMs };\n }\n if (inspection.kind === \"scan\") {\n return inspection.check.changedIds === undefined\n ? { ...inspection, kind: \"full-scan\", availabilityDurationMs }\n : {\n ...inspection,\n kind: \"incremental-scan\",\n check: { ...inspection.check, changedIds: inspection.check.changedIds },\n availabilityDurationMs,\n };\n }\n return { ...inspection, availabilityDurationMs };\n}\n\nexport async function beginAgentRefresh(\n agent: Pick<BaseAgent, \"isAvailable\" | \"sessionSourceAccess\">,\n options: {\n initialized: boolean;\n sinceTimestamp: number;\n cachedSessions: SessionHead[];\n },\n): Promise<AgentRefreshTransaction> {\n const selection = await selectAgentRefresh(agent, options);\n return {\n selection,\n commit: () => {\n if (\n selection.kind === \"recompute-derived\" ||\n selection.kind === \"full-scan\" ||\n selection.kind === \"incremental-scan\"\n ) {\n commitAgentRefreshCheck(selection);\n }\n },\n };\n}\n\nexport function commitAgentRefreshCheck(refresh: CommittableAgentRefresh): void {\n refresh.source.commitChangeCheck();\n}\n","import type { IdentifiedSessionHead, SessionHead } from \"../types/index.js\";\nimport { assertIdentifiedSessionHead } from \"../contract/session.js\";\nimport { assertSessionIdentity } from \"../contract/session-reference.js\";\nimport { filterSessionTreeByActivityWindow } from \"../contract/session-tree.js\";\nimport type {\n AgentScanFailure,\n AgentScanOptions,\n BaseAgent,\n EnumeratedSessionSourceCapability,\n SessionSourceSynchronizationTiming,\n} from \"../agents/index.js\";\nimport {\n createAgentScanFailure,\n createRegisteredAgents,\n reportAgentScanFailure,\n SessionScanError,\n} from \"../agents/index.js\";\nimport { filterSessionsByProjectScope } from \"../projects/index.js\";\nimport { perf } from \"../utils/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport {\n markAgentCacheInitialized,\n markAgentFullSyncCompleted,\n readCachedSessions,\n saveCachedSessionChanges,\n saveCachedSessions,\n type CachedResult,\n} from \"./cache/sessions.js\";\nimport {\n attachMissingProjectIdentities,\n buildAgentCacheMeta,\n buildSessionPersistenceDiff,\n} from \"./orchestrate.js\";\nimport {\n beginAgentRefresh,\n executeAgentScanPlan,\n planAgentScan,\n resolveSessionSnapshotCompleteness,\n} from \"./agent-scan-plan.js\";\nimport { ensureSessionTags } from \"./session-tags.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 /** Return cached session heads without validating the filesystem */\n cacheOnly?: boolean;\n /** Persist scan results to the SQLite cache */\n writeCache?: boolean;\n /** Classify sessions by reading full conversation content */\n includeSmartTags?: boolean;\n /** Prefer lightweight metadata over complete statistics when the UI needs a fast first paint */\n fast?: boolean;\n /** URL to the compiled smart-tag worker file; omit to use synchronous fallback */\n smartTagWorkerUrl?: URL | string;\n}\n\nexport interface LiveSnapshot {\n sessions: IdentifiedSessionHead[];\n byAgent: Record<string, IdentifiedSessionHead[]>;\n agents: BaseAgent[];\n timings?: Record<string, AgentScanTiming>;\n cacheTimestamps?: Record<string, number>;\n cacheFailures?: Record<string, AgentCacheFailure>;\n scanFailures?: Record<string, AgentScanFailure>;\n}\n\nexport interface AgentCacheFailure {\n agentName: string;\n operation: \"read\" | \"write\";\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<T extends SessionHead>(sessions: T[], options: ScanOptions): T[] {\n let result = sessions;\n\n if (options.cwd) {\n result = filterSessionsByProjectScope(result, options.cwd);\n }\n\n return filterSessionTreeByActivityWindow(result, options.from, options.to);\n}\n\nexport interface AgentScanTiming {\n cacheLoad?: number;\n checkChanges?: number;\n scan?: number;\n identity?: number;\n tags?: number;\n sourceEnumeration?: number;\n sourceDiff?: number;\n sourceParse?: number;\n enumeratedSources?: number;\n changedSources?: number;\n processedSources?: number;\n total: number;\n}\n\nfunction applySessionSourceTiming(\n target: AgentScanTiming,\n source: SessionSourceSynchronizationTiming,\n): void {\n target.sourceEnumeration = source.enumerationMs;\n target.sourceDiff = source.diffMs;\n target.sourceParse = source.parseMs;\n target.enumeratedSources = source.enumeratedSourceCount;\n target.changedSources = source.changedSourceCount;\n target.processedSources = source.processedSourceCount;\n}\n\nfunction buildAgentScanOptions(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): AgentScanOptions {\n return {\n from: options.from,\n to: options.to,\n fast: options.fast,\n includeRelatedSessions: true,\n onProgress: (progress) => {\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n cachedCount: progress.total,\n newCount: progress.sessions,\n changedCount: progress.processed,\n });\n },\n };\n}\n\ntype CachePersistence = \"persisted\" | \"failed\" | \"not-requested\";\n\ninterface SuccessfulAgentScanResult {\n status: \"complete\" | \"partial\";\n agent: BaseAgent;\n heads: IdentifiedSessionHead[];\n cachePersistence: CachePersistence;\n fromCache?: boolean;\n refreshed?: boolean;\n timing?: AgentScanTiming;\n cacheTimestamp?: number;\n}\n\ninterface FailedAgentScanResult {\n status: \"failed\";\n agent: BaseAgent;\n failure: AgentScanFailure;\n retainedHeads?: IdentifiedSessionHead[];\n cacheTimestamp?: number;\n timing: AgentScanTiming;\n}\n\ntype AgentScanResult = SuccessfulAgentScanResult | FailedAgentScanResult;\n\ninterface AgentScanExecution {\n agentName: string;\n result: AgentScanResult | null;\n cacheReadFailed: boolean;\n}\n\ninterface CacheReadState {\n attempted: boolean;\n failed: boolean;\n}\n\nfunction identifiedSessionHeads(sessions: SessionHead[]): IdentifiedSessionHead[] {\n return sessions.map((session) => {\n assertIdentifiedSessionHead(session);\n return session;\n });\n}\n\nfunction finalizeAgentScanFailure(\n agent: BaseAgent,\n failure: AgentScanFailure,\n options: ScanOptions,\n cached: CachedResult | null,\n timing: AgentScanTiming,\n startedAt: number,\n): FailedAgentScanResult {\n const retainedHeads = cached\n ? identifiedSessionHeads(filterSessions(agent.filterCachedSessions(cached.sessions), options))\n : undefined;\n reportAgentScanFailure(failure, retainedHeads !== undefined);\n timing.total = performance.now() - startedAt;\n return {\n status: \"failed\",\n agent,\n failure,\n ...(retainedHeads !== undefined ? { retainedHeads } : {}),\n ...(cached ? { cacheTimestamp: cached.timestamp } : {}),\n timing,\n };\n}\n\ntype AgentScanFinalization =\n | { kind: \"cache-only\"; cached: CachedResult }\n | { kind: \"unchanged\"; cached: CachedResult }\n | {\n kind: \"incremental\";\n cached: CachedResult;\n changedIds: string[];\n explicitRemovedSessionIds?: string[];\n cacheTimestamp: number;\n };\n\ninterface FinalizeAgentScanContext {\n finalization: AgentScanFinalization;\n options: ScanOptions;\n timing: AgentScanTiming;\n agentStart: number;\n completeness: \"complete\" | \"partial\";\n onProgress?: (progress: ScanProgress) => void;\n}\n\nfunction saveCachedSessionDiff(\n agent: BaseAgent,\n cachedSessions: SessionHead[],\n updatedSessions: SessionHead[],\n changedIds: string[] = [],\n completeness: \"complete\" | \"partial\" = \"complete\",\n explicitRemovedSessionIds: readonly string[] = [],\n): boolean {\n const diff = buildSessionPersistenceDiff(cachedSessions, updatedSessions, {\n candidateChangedIds: changedIds,\n completeness,\n explicitRemovedSessionIds,\n });\n const persisted = saveCachedSessionChanges(\n agent.name,\n diff.changedSessions,\n diff.removedSessionIds,\n buildAgentCacheMeta(agent),\n );\n if (persisted === false) {\n getCoreDiagnostics()?.warn(\"cache.save_failed\", {\n agent: agent.name,\n changed_sessions: diff.changedSessions.length,\n removed_sessions: diff.removedSessionIds.length,\n });\n }\n return persisted;\n}\n\nexport async function finalizeAgentScan(\n agent: BaseAgent,\n sessions: SessionHead[],\n context: FinalizeAgentScanContext,\n): Promise<SuccessfulAgentScanResult> {\n const { finalization, options, timing, agentStart, onProgress } = context;\n const isIncremental = finalization.kind === \"incremental\";\n for (const session of sessions) assertSessionIdentity(session, agent.name);\n\n if (!isIncremental) {\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: sessions.length });\n }\n\n const identityStart = performance.now();\n const sessionsWithIdentity =\n finalization.kind === \"cache-only\"\n ? identifiedSessionHeads(sessions)\n : attachMissingProjectIdentities(sessions);\n const identityChanged = sessionsWithIdentity.some(\n (session, index) => session !== sessions[index],\n );\n timing.identity = performance.now() - identityStart;\n\n let tagged = { sessions: sessionsWithIdentity, changed: false };\n if (finalization.kind !== \"cache-only\") {\n const tagsStart = performance.now();\n const tagResult =\n options.includeSmartTags === false\n ? tagged\n : await ensureSessionTags(agent, sessionsWithIdentity, options.smartTagWorkerUrl);\n tagged = { ...tagResult, sessions: identifiedSessionHeads(tagResult.sessions) };\n timing.tags = performance.now() - tagsStart;\n }\n\n let cachePersistence: CachePersistence = \"not-requested\";\n if (options.writeCache !== false) {\n if (finalization.kind === \"incremental\") {\n cachePersistence =\n saveCachedSessionDiff(\n agent,\n finalization.cached.sessions,\n tagged.sessions,\n finalization.changedIds,\n context.completeness,\n finalization.explicitRemovedSessionIds,\n ) === false\n ? \"failed\"\n : \"persisted\";\n } else if (finalization.kind === \"unchanged\" && (identityChanged || tagged.changed)) {\n cachePersistence =\n saveCachedSessionDiff(agent, finalization.cached.sessions, tagged.sessions) === false\n ? \"failed\"\n : \"persisted\";\n }\n }\n\n if (isIncremental) {\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: tagged.sessions.length });\n }\n\n const heads = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return {\n status: context.completeness,\n agent,\n heads,\n cachePersistence,\n fromCache: true,\n ...(isIncremental ? { refreshed: true } : {}),\n timing,\n cacheTimestamp:\n isIncremental && cachePersistence === \"persisted\"\n ? finalization.cacheTimestamp\n : finalization.cached.timestamp,\n };\n}\n\nasync function refreshCachedEnumeratedAgent(\n agent: BaseAgent,\n source: EnumeratedSessionSourceCapability,\n cached: CachedResult,\n options: ScanOptions,\n timing: AgentScanTiming,\n agentStart: number,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<SuccessfulAgentScanResult> {\n const scanStartedAt = performance.now();\n const execution = executeAgentScanPlan(\n agent,\n { kind: \"synchronize\", requestKind: \"refresh\", source },\n { sessions: cached.sessions, meta: cached.meta },\n {\n onProgress: (progress) => {\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n cachedCount: progress.total,\n newCount: progress.sessions,\n changedCount: progress.processed,\n });\n },\n },\n );\n timing.scan = performance.now() - scanStartedAt;\n applySessionSourceTiming(timing, execution.sourceSynchronization!.timing);\n const hasSourceChanges =\n execution.detectedSessionIds.length > 0 || execution.sourceFailures.length > 0;\n\n if (!hasSourceChanges) {\n return finalizeAgentScan(agent, execution.sessions, {\n finalization: { kind: \"unchanged\", cached },\n options,\n timing,\n agentStart,\n completeness: execution.completeness,\n onProgress,\n });\n }\n\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n changedCount: execution.detectedSessionIds.length,\n });\n return finalizeAgentScan(agent, execution.sessions, {\n finalization: {\n kind: \"incremental\",\n cached,\n changedIds: execution.changedSessionIds,\n explicitRemovedSessionIds: execution.explicitRemovedSessionIds,\n cacheTimestamp: Date.now(),\n },\n options,\n timing,\n agentStart,\n completeness: execution.completeness,\n onProgress,\n });\n}\n\n/**\n * 智能扫描单个 Agent\n * 1. 优先使用缓存立即返回\n * 2. 后台检测变更\n * 3. 增量刷新(仅更新变更的部分)\n */\nasync function scanAgentSmart(\n agent: BaseAgent,\n options: ScanOptions,\n cacheReadState: CacheReadState,\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 let cached: CachedResult | null = null;\n if (useCache) {\n const t0 = performance.now();\n cacheReadState.attempted = true;\n const outcome = readCachedSessions(agent.name);\n timing.cacheLoad = performance.now() - t0;\n if (outcome.status === \"failed\") {\n cacheReadState.failed = true;\n } else {\n cached = outcome.value;\n }\n\n if (cached !== null) {\n // 恢复元数据\n agent.restoreSessionCacheMeta(cached.meta);\n\n if (options.cacheOnly) {\n const visibleSessions = agent.filterCachedSessions(cached.sessions);\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: visibleSessions.length,\n });\n return finalizeAgentScan(agent, visibleSessions, {\n finalization: { kind: \"cache-only\", cached },\n options,\n timing,\n agentStart,\n completeness: \"partial\",\n onProgress,\n });\n }\n\n const refreshTransaction = await beginAgentRefresh(agent, {\n initialized: true,\n sinceTimestamp: cached.timestamp,\n cachedSessions: cached.sessions,\n });\n const refresh = refreshTransaction.selection;\n if (refresh.kind === \"unavailable\") {\n return finalizeAgentScanFailure(\n agent,\n {\n agentName: agent.name,\n stage: \"checking availability\",\n errorClass: \"AgentUnavailableError\",\n message: `Agent ${agent.name} is unavailable`,\n },\n options,\n cached,\n timing,\n agentStart,\n );\n }\n if (refresh.kind === \"initialize\") {\n return scanAgentFull(\n agent,\n options,\n cached,\n cacheReadState,\n onProgress,\n timing,\n agentStart,\n );\n }\n\n // 通知缓存已加载\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: cached.sessions.length,\n });\n\n onProgress?.({ agent: agent.name, phase: \"checking\" });\n\n if (refresh.kind !== \"synchronize\") timing.checkChanges = refresh.checkDurationMs;\n if (refresh.kind === \"synchronize\") {\n return refreshCachedEnumeratedAgent(\n agent,\n refresh.source,\n cached,\n options,\n timing,\n agentStart,\n onProgress,\n );\n }\n if (refresh.kind === \"failed\") {\n return finalizeAgentScanFailure(\n agent,\n {\n agentName: agent.name,\n stage: \"checking for changes\",\n sourcePath: refresh.failure.sourcePath,\n errorClass: refresh.failure.errorClass,\n message: refresh.failure.message,\n },\n options,\n cached,\n timing,\n agentStart,\n );\n }\n\n if (refresh.kind === \"full-scan\" || refresh.kind === \"incremental-scan\") {\n const checkResult = refresh.check;\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n changedCount: checkResult.changedIds?.length,\n });\n\n const t2 = performance.now();\n const scanOptions = buildAgentScanOptions(agent, options, onProgress);\n const updatedSessions = await Promise.resolve(\n refresh.source.incrementalScan(\n cached.sessions,\n checkResult.changedIds ?? [],\n checkResult.refs,\n scanOptions,\n ),\n );\n timing.scan = performance.now() - t2;\n const result = await finalizeAgentScan(agent, updatedSessions, {\n finalization: {\n kind: \"incremental\",\n cached,\n changedIds: checkResult.changedIds ?? [],\n cacheTimestamp: checkResult.timestamp,\n },\n options,\n timing,\n agentStart,\n completeness: resolveSessionSnapshotCompleteness(\n options,\n checkResult.sourceFailures ?? [],\n ),\n onProgress,\n });\n if (result.cachePersistence === \"persisted\") refreshTransaction.commit();\n return result;\n }\n\n const result = await finalizeAgentScan(agent, cached.sessions, {\n finalization: { kind: \"unchanged\", cached },\n options,\n timing,\n agentStart,\n completeness: \"complete\",\n onProgress,\n });\n refreshTransaction.commit();\n return result;\n }\n }\n\n if (options.cacheOnly) {\n timing.total = performance.now() - agentStart;\n return null;\n }\n\n // 无缓存或缓存失效,执行完整扫描\n return scanAgentFull(agent, options, cached, cacheReadState, onProgress, timing, agentStart);\n}\n\n/**\n * 完整扫描 Agent(无缓存时使用)\n */\nasync function scanAgentFull(\n agent: BaseAgent,\n options: ScanOptions,\n cached: CachedResult | null,\n cacheReadState: CacheReadState,\n onProgress?: (progress: ScanProgress) => void,\n timing: AgentScanTiming = { total: 0 },\n agentStart = performance.now(),\n): Promise<AgentScanResult | null> {\n const availMarker = perf.start(`agent:${agent.name}:isAvailable`);\n const isAvail = agent.isAvailable();\n perf.end(availMarker);\n\n if (!isAvail) {\n return null;\n }\n\n try {\n const scanMarker = perf.start(`agent:${agent.name}:scan`);\n const t0 = performance.now();\n const agentScanOptions = buildAgentScanOptions(agent, options, onProgress);\n const scanPlan = planAgentScan(agent.sessionSourceAccess, \"reload\");\n if (scanPlan.kind === \"synchronize\" && !cacheReadState.attempted) {\n cacheReadState.attempted = true;\n const outcome = readCachedSessions(agent.name);\n if (outcome.status === \"failed\") {\n cacheReadState.failed = true;\n } else {\n cached = outcome.value;\n }\n }\n const execution = executeAgentScanPlan(\n agent,\n scanPlan,\n { sessions: cached?.sessions ?? [], meta: cached?.meta ?? {} },\n agentScanOptions,\n );\n const heads = execution.sessions;\n const sourceFailures = execution.sourceFailures;\n if (execution.sourceSynchronization) {\n applySessionSourceTiming(timing, execution.sourceSynchronization.timing);\n }\n for (const session of heads) assertSessionIdentity(session, agent.name);\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 tagResult =\n options.includeSmartTags === false\n ? { sessions: headsWithIdentity, changed: false }\n : await ensureSessionTags(agent, headsWithIdentity, options.smartTagWorkerUrl);\n const tagged = { ...tagResult, sessions: identifiedSessionHeads(tagResult.sessions) };\n timing.tags = performance.now() - t2;\n\n // 收集元数据\n const meta = buildAgentCacheMeta(agent);\n\n let cachePersistence: CachePersistence = \"not-requested\";\n if (options.writeCache !== false) {\n const isFullWindow = options.from == null && options.to == null;\n const persisted = saveCachedSessions(agent.name, tagged.sessions, meta, {\n completeness: execution.completeness,\n });\n if (persisted !== false) {\n cachePersistence = \"persisted\";\n markAgentCacheInitialized(agent.name);\n if (\n isFullWindow &&\n sourceFailures.length === 0 &&\n !markAgentFullSyncCompleted(agent.name)\n ) {\n getCoreDiagnostics()?.warn(\"cache.full_sync_marker_failed\", { agent: agent.name });\n }\n } else {\n cachePersistence = \"failed\";\n getCoreDiagnostics()?.warn(\"cache.save_failed\", {\n agent: agent.name,\n sessions: tagged.sessions.length,\n });\n }\n }\n\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: tagged.sessions.length });\n\n const filtered = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return {\n status: execution.completeness,\n agent,\n heads: filtered,\n cachePersistence,\n fromCache: false,\n timing,\n };\n } catch (err) {\n if (err instanceof SessionScanError) throw err;\n throw new SessionScanError(agent.name, \"scanning sessions\", { cause: err });\n }\n}\n\nasync function scanAgentOutcome(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<AgentScanExecution> {\n const startedAt = performance.now();\n const cacheReadState: CacheReadState = { attempted: false, failed: false };\n try {\n return {\n agentName: agent.name,\n result: await scanAgentSmart(agent, options, cacheReadState, onProgress),\n cacheReadFailed: cacheReadState.failed,\n };\n } catch (error) {\n let cached: CachedResult | null = null;\n if (options.useCache ?? true) {\n cacheReadState.attempted = true;\n const outcome = readCachedSessions(agent.name);\n if (outcome.status === \"failed\") {\n cacheReadState.failed = true;\n } else {\n cached = outcome.value;\n }\n }\n if (cached) agent.restoreSessionCacheMeta(cached.meta);\n const failure = createAgentScanFailure(agent.name, \"scanning sessions\", error);\n return {\n agentName: agent.name,\n result: finalizeAgentScanFailure(agent, failure, options, cached, { total: 0 }, startedAt),\n cacheReadFailed: cacheReadState.failed,\n };\n }\n}\n\n/**\n * 主扫描函数 - 并行扫描所有 Agent\n */\nexport async function scanSessions(\n options: ScanOptions = {},\n onProgress?: (progress: ScanProgress) => void,\n): Promise<LiveSnapshot> {\n const scanMarker = perf.start(\"scanSessions\");\n const agents = createRegisteredAgents();\n const byAgent: Record<string, IdentifiedSessionHead[]> = {};\n const allSessions: IdentifiedSessionHead[] = [];\n const availableAgents: BaseAgent[] = [];\n const cacheTimestamps: Record<string, number> = {};\n const cacheFailures: Record<string, AgentCacheFailure> = {};\n const scanFailures: Record<string, AgentScanFailure> = {};\n\n const agentFilter = options.agents?.length\n ? new Set(options.agents.map((a) => a.toLowerCase()))\n : null;\n\n // 过滤需要扫描的 Agent\n const agentsToScan = agents.filter((agent) => {\n if (agentFilter && !agentFilter.has(agent.name.toLowerCase())) {\n return false;\n }\n return true;\n });\n\n // 并行扫描所有 Agent\n const scanPromises = agentsToScan.map((agent) => scanAgentOutcome(agent, options, onProgress));\n\n const results = await Promise.all(scanPromises);\n\n // 处理结果\n const timings: Record<string, AgentScanTiming> = {};\n for (const execution of results) {\n const { result } = execution;\n if (execution.cacheReadFailed) {\n cacheFailures[execution.agentName] = {\n agentName: execution.agentName,\n operation: \"read\",\n };\n }\n if (result) {\n availableAgents.push(result.agent);\n if (result.status === \"failed\") {\n scanFailures[result.agent.name] = result.failure;\n if (result.retainedHeads !== undefined) {\n byAgent[result.agent.name] = result.retainedHeads;\n allSessions.push(...result.retainedHeads);\n }\n } else {\n byAgent[result.agent.name] = result.heads;\n allSessions.push(...result.heads);\n if (result.cachePersistence === \"failed\") {\n cacheFailures[result.agent.name] = {\n agentName: result.agent.name,\n operation: \"write\",\n };\n }\n }\n if (result.timing) {\n timings[result.agent.name] = result.timing;\n }\n if (result.cacheTimestamp != null) {\n cacheTimestamps[result.agent.name] = result.cacheTimestamp;\n }\n }\n }\n\n perf.end(scanMarker);\n return {\n sessions: allSessions,\n byAgent,\n agents: availableAgents,\n timings,\n cacheTimestamps: Object.keys(cacheTimestamps).length > 0 ? cacheTimestamps : undefined,\n cacheFailures: Object.keys(cacheFailures).length > 0 ? cacheFailures : undefined,\n scanFailures: Object.keys(scanFailures).length > 0 ? scanFailures : undefined,\n };\n}\n","import type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport {\n assertSessionIdentity,\n getSessionReferenceKey,\n type SessionReference,\n} from \"../contract/index.js\";\nimport type {\n IdentifiedSessionDetail,\n IdentifiedSessionHead,\n ProjectIdentity,\n SessionDetail,\n} from \"../types/index.js\";\nimport {\n classifySessionTags,\n extractSessionFileActivity,\n getSmartTagSourceTimestamp,\n SMART_TAG_CLASSIFIER_REVISION,\n} from \"../utils/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport { listSessionFileActivity } from \"./cache/file-activity.js\";\nimport { sessionDetailVersion } from \"./cache/detail-version.js\";\nimport {\n loadCachedSessionRawEntry,\n readCachedSessionCursor,\n type CachedSessionCursorEntry,\n type CachedSessionCursorReader,\n type CachedSessionRawEntry,\n} from \"./cache/sessions.js\";\nimport {\n messageCursorContentFromCachedRow,\n messageFromCachedRow,\n messageJsonFromCachedRow,\n type CachedMessageRow,\n} from \"./cache/messages.js\";\nimport {\n computeMessageCursorDigest,\n initialMessageCursorDigest,\n MESSAGE_CURSOR_VERSION,\n} from \"./cache/message-cursor.js\";\nimport type { LiveSnapshot } from \"./scanner.js\";\n\nexport type SessionDetailResult =\n | { status: \"found\"; data: IdentifiedSessionDetail }\n | { status: \"unknown-agent\" }\n | { status: \"not-ready\" };\n\nexport type SessionDetailResponseResult =\n | SessionDetailResult\n | {\n status: \"found-json\";\n data: Omit<IdentifiedSessionDetail, \"messages\">;\n messages: Iterable<string>;\n messageCount: number;\n sentMessageCount: number;\n };\n\nexport interface SessionDetailResponseOptions {\n messageCursor?: string;\n}\n\ninterface SessionDetailLookup {\n agentsByName: Map<string, BaseAgent>;\n headsByReference: Map<string, IdentifiedSessionHead>;\n}\n\ninterface SessionDetailContext {\n agent: BaseAgent;\n head: IdentifiedSessionHead | undefined;\n}\n\nconst sessionDetailLookups = new WeakMap<IdentifiedSessionHead[], SessionDetailLookup>();\nconst MAX_MESSAGE_CURSOR_LENGTH = 512;\n\ninterface MessageCursorPayload {\n version: typeof MESSAGE_CURSOR_VERSION;\n count: number;\n digest: string;\n}\n\nfunction parseMessageCursor(value: string | undefined): MessageCursorPayload | null {\n if (!value || value.length > MAX_MESSAGE_CURSOR_LENGTH) return null;\n try {\n const payload = JSON.parse(\n Buffer.from(value, \"base64url\").toString(\"utf8\"),\n ) as Partial<MessageCursorPayload>;\n if (\n payload.version !== MESSAGE_CURSOR_VERSION ||\n !Number.isSafeInteger(payload.count) ||\n payload.count == null ||\n payload.count < 0 ||\n typeof payload.digest !== \"string\" ||\n !/^[a-f0-9]{64}$/.test(payload.digest)\n ) {\n return null;\n }\n return payload as MessageCursorPayload;\n } catch {\n return null;\n }\n}\n\nfunction encodeMessageCursor(count: number, digest: string): string {\n return Buffer.from(JSON.stringify({ version: MESSAGE_CURSOR_VERSION, count, digest })).toString(\n \"base64url\",\n );\n}\n\ninterface CachedMessageStream {\n cursor: string;\n update: \"append\" | \"reset\";\n messageRows: CachedMessageRow[];\n messageCount: number;\n}\n\nfunction loadCachedMessageStream(\n reference: SessionReference,\n entry: CachedSessionCursorEntry,\n cursor: CachedSessionCursorReader,\n requestedCursor: string | undefined,\n): CachedMessageStream {\n const requested = parseMessageCursor(requestedCursor);\n const initialDigest = initialMessageCursorDigest(reference);\n const hasStoredChain = entry.messageCount === 0 || entry.messageDigest !== null;\n const canCheckAppend =\n hasStoredChain && requested !== null && requested.count <= entry.messageCount;\n const requestedDigest =\n canCheckAppend && requested\n ? requested.count === 0\n ? initialDigest\n : cursor.messageDigest(requested.count)\n : null;\n const canAppend = canCheckAppend && requested !== null && requestedDigest === requested.digest;\n let startIndex = canAppend ? requested.count : 0;\n let update: CachedMessageStream[\"update\"] = canAppend ? \"append\" : \"reset\";\n let messageRows = entry.messageCount === 0 ? [] : cursor.messageRows(startIndex);\n\n let messageCount = entry.messageCount;\n let digest = entry.messageCount === 0 ? initialDigest : entry.messageDigest;\n if (messageRows.length !== entry.messageCount - startIndex) {\n startIndex = 0;\n update = \"reset\";\n messageRows = cursor.messageRows(startIndex);\n messageCount = messageRows.length;\n digest = null;\n }\n\n if (!digest) {\n digest = computeMessageCursorDigest(\n reference,\n messageRows.map((row) => messageCursorContentFromCachedRow(row)),\n );\n }\n return {\n cursor: encodeMessageCursor(messageCount, digest),\n update,\n messageRows,\n messageCount,\n };\n}\n\nfunction assertSessionMatchesReference(\n session: IdentifiedSessionHead | SessionDetail,\n reference: SessionReference,\n): void {\n assertSessionIdentity(session, reference.agentName);\n if (session.reference.sessionId !== reference.sessionId) {\n throw new Error(\"Session reference does not match expected session\");\n }\n}\n\n/**\n * The canonical sessions array is replaced atomically with each scan snapshot,\n * so its identity also versions this lazily built lookup.\n */\nfunction getSessionDetailLookup(scanResult: LiveSnapshot): SessionDetailLookup {\n const cached = sessionDetailLookups.get(scanResult.sessions);\n if (cached) return cached;\n\n const agentsByName = new Map<string, BaseAgent>();\n for (const agent of scanResult.agents) {\n if (!agentsByName.has(agent.name)) agentsByName.set(agent.name, agent);\n }\n const headsByReference = new Map<string, IdentifiedSessionHead>();\n for (const sessions of Object.values(scanResult.byAgent)) {\n for (const session of sessions) {\n const key = getSessionReferenceKey(session.reference);\n if (!headsByReference.has(key)) headsByReference.set(key, session);\n }\n }\n\n const lookup = { agentsByName, headsByReference };\n sessionDetailLookups.set(scanResult.sessions, lookup);\n return lookup;\n}\n\nfunction getSessionDetailContext(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n): SessionDetailContext | null {\n const lookup = getSessionDetailLookup(scanResult);\n const agent = lookup.agentsByName.get(reference.agentName);\n if (!agent) return null;\n return {\n agent,\n head: lookup.headsByReference.get(getSessionReferenceKey(reference)),\n };\n}\n\ntype CachedDetailState = \"fresh\" | \"stale\" | \"missing\";\ntype CachedSessionDetailEntry = Pick<\n CachedSessionRawEntry,\n \"data\" | \"detailVersion\" | \"pendingReindex\"\n>;\n\nfunction cachedDetailState(\n cachedEntry: CachedSessionDetailEntry | null,\n currentMeta: SessionCacheMeta | undefined,\n messageCount: number,\n): CachedDetailState {\n if (!cachedEntry || (messageCount === 0 && cachedEntry.data.stats.message_count > 0)) {\n return \"missing\";\n }\n return !cachedEntry.pendingReindex &&\n cachedEntry.detailVersion === sessionDetailVersion(currentMeta)\n ? \"fresh\"\n : \"stale\";\n}\n\nfunction getProjectIdentity(\n data: Pick<SessionDetail, \"reference\" | \"project_identity\">,\n head: IdentifiedSessionHead | undefined,\n): ProjectIdentity {\n const identity = head?.project_identity ?? data.project_identity;\n if (identity) return identity;\n throw new Error(\n `Session ${data.reference.agentName}/${data.reference.sessionId} reached detail materialization without project_identity`,\n );\n}\n\nfunction getSmartTags(data: SessionDetail) {\n if (\n Array.isArray(data.smart_tags) &&\n data.smart_tags_classifier_revision === SMART_TAG_CLASSIFIER_REVISION\n ) {\n return data.smart_tags;\n }\n return classifySessionTags(data);\n}\n\nfunction materializeStructuredSessionDetail(\n context: SessionDetailContext,\n reference: SessionReference,\n cachedEntry = loadCachedSessionRawEntry(reference.agentName, reference.sessionId),\n): SessionDetailResult {\n const { agent, head } = context;\n const currentMeta = head ? agent.getSessionCacheMeta(reference.sessionId) : undefined;\n const cacheState = cachedDetailState(\n cachedEntry,\n currentMeta,\n cachedEntry?.messageRows.length ?? 0,\n );\n let useCache = cacheState === \"fresh\";\n let freshness: SessionDetail[\"detail_freshness\"] = useCache ? \"fresh\" : undefined;\n let data: SessionDetail | null = useCache\n ? {\n ...cachedEntry!.data,\n messages: cachedEntry!.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n }\n : null;\n let sourceError: unknown;\n if (!data && head) {\n const sourceStartedAt = performance.now();\n try {\n data = agent.getSessionData(reference.sessionId);\n if (data) freshness = \"fresh\";\n } catch (error) {\n sourceError = error;\n } finally {\n getCoreDiagnostics()?.info?.(\"session_detail.source_read\", {\n agent: reference.agentName,\n session_id: reference.sessionId,\n duration_ms: Math.round(performance.now() - sourceStartedAt),\n failed: sourceError != null,\n });\n }\n }\n if (!data && cacheState === \"stale\" && cachedEntry) {\n useCache = true;\n freshness = \"stale\";\n data = {\n ...cachedEntry.data,\n messages: cachedEntry.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n };\n getCoreDiagnostics()?.warn(\"session_detail.stale_fallback\", {\n agent: reference.agentName,\n session_id: reference.sessionId,\n stored_version: cachedEntry.detailVersion,\n target_version: sessionDetailVersion(currentMeta),\n error: sourceError instanceof Error ? sourceError.message : undefined,\n });\n }\n if (sourceError && !data) throw sourceError;\n\n if (!data) {\n return { status: \"not-ready\" };\n }\n assertSessionMatchesReference(data, reference);\n\n const projectIdentity = getProjectIdentity(data, head);\n const fileActivity =\n data.file_activity ??\n (useCache\n ? listSessionFileActivity(reference.agentName, reference.sessionId)\n : extractSessionFileActivity(\n reference.agentName,\n reference.sessionId,\n projectIdentity.key,\n data.messages,\n ));\n\n return {\n status: \"found\",\n data: {\n ...data,\n detail_freshness: freshness,\n project_identity: projectIdentity,\n project_identity_resolver_revision:\n head?.project_identity_resolver_revision ?? data.project_identity_resolver_revision,\n project_identity_input_signature:\n head?.project_identity_input_signature ?? data.project_identity_input_signature,\n smart_tags: getSmartTags(data),\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n smart_tags_classifier_revision: SMART_TAG_CLASSIFIER_REVISION,\n file_activity: fileActivity,\n },\n };\n}\n\nfunction* serializeCachedMessages(messageRows: CachedMessageRow[]): IterableIterator<string> {\n for (const messageRow of messageRows) {\n yield messageJsonFromCachedRow(messageRow);\n }\n}\n\nexport function materializeSessionDetail(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n): SessionDetailResult {\n const context = getSessionDetailContext(scanResult, reference);\n if (!context) return { status: \"unknown-agent\" };\n return materializeStructuredSessionDetail(context, reference);\n}\n\nexport function materializeCachedSessionDetailResponse(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n options: SessionDetailResponseOptions = {},\n): SessionDetailResponseResult | null {\n const context = getSessionDetailContext(scanResult, reference);\n if (!context) return { status: \"unknown-agent\" };\n\n const currentMeta = context.head\n ? context.agent.getSessionCacheMeta(reference.sessionId)\n : undefined;\n const startedAt = performance.now();\n const cursorRead = readCachedSessionCursor(\n reference.agentName,\n reference.sessionId,\n (entry, cursor) => {\n const cacheState = cachedDetailState(entry, currentMeta, entry.messageCount);\n const stream =\n cacheState === \"fresh\" &&\n entry.data.smart_tags != null &&\n entry.data.smart_tags_classifier_revision === SMART_TAG_CLASSIFIER_REVISION\n ? loadCachedMessageStream(reference, entry, cursor, options.messageCursor)\n : null;\n return { entry, cacheState, stream };\n },\n );\n const cachedEntry = cursorRead?.entry ?? null;\n const cacheState = cursorRead?.cacheState ?? \"missing\";\n if (\n !cachedEntry ||\n cacheState !== \"fresh\" ||\n cachedEntry.data.smart_tags == null ||\n cachedEntry.data.smart_tags_classifier_revision !== SMART_TAG_CLASSIFIER_REVISION\n ) {\n return null;\n }\n\n const data = cachedEntry.data;\n assertSessionMatchesReference(data, reference);\n const projectIdentity = getProjectIdentity(data, context.head);\n const stream = cursorRead?.stream;\n if (!stream) {\n return null;\n }\n const partsJsonBytes = stream.messageRows.reduce(\n (total, row) => total + Buffer.byteLength(String(row.parts_json)),\n 0,\n );\n getCoreDiagnostics()?.info?.(\"session_detail.cursor_stream\", {\n update: stream.update,\n message_count: stream.messageCount,\n sent_message_count: stream.messageRows.length,\n parts_json_bytes: partsJsonBytes,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return {\n status: \"found-json\",\n data: {\n ...data,\n detail_freshness: \"fresh\",\n message_cursor: stream.cursor,\n message_update: stream.update,\n project_identity: projectIdentity,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n file_activity:\n data.file_activity ?? listSessionFileActivity(reference.agentName, reference.sessionId),\n },\n messages: serializeCachedMessages(stream.messageRows),\n messageCount: stream.messageCount,\n sentMessageCount: stream.messageRows.length,\n };\n}\n\nexport function materializeSessionDetailResponse(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n options: SessionDetailResponseOptions = {},\n): SessionDetailResponseResult {\n const cached = materializeCachedSessionDetailResponse(scanResult, reference, options);\n if (cached) return cached;\n const result = materializeSessionDetail(scanResult, reference);\n return result.status === \"found\"\n ? { ...result, data: { ...result.data, message_update: \"reset\" } }\n : result;\n}\n","/**\n * Project grouping: reads the project_groups_v view (or falls back to an\n * in-memory build) to list cached project groups.\n */\nimport type { ProjectGroup, ProjectIdentityKind, SessionHead } from \"../../types/index.js\";\nimport { buildProjectGroups } from \"../../projects/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./connection.js\";\n\nexport interface ProjectGroupRow extends DatabaseRow {\n identity_kind?: ProjectIdentityKind;\n identity_key?: string;\n display_name?: string;\n sources_csv?: string | null;\n session_count?: number;\n last_activity?: number | null;\n}\n\nexport function listCachedProjectGroups(sessions?: SessionHead[]): ProjectGroup[] {\n if (sessions) {\n return buildProjectGroups(sessions);\n }\n\n if (!hasCacheStorage()) {\n return [];\n }\n\n const queryRows = (db: SQLiteDatabase) =>\n db\n .prepare(\n `\n SELECT identity_kind, identity_key, display_name, sources_csv, session_count, last_activity\n FROM project_groups_v\n ORDER BY\n CASE identity_kind WHEN 'loose' THEN 1 ELSE 0 END,\n last_activity IS NULL,\n last_activity DESC\n `,\n )\n .all() as ProjectGroupRow[];\n\n const read = withCacheDbReadOnly(queryRows);\n const rows = read.status === \"success\" ? read.value : withCacheDb(queryRows);\n\n return (rows ?? []).map((row) => ({\n identityKind: row.identity_kind ?? \"path\",\n identityKey: String(row.identity_key ?? \"\"),\n displayName: String(row.display_name ?? \"\"),\n sources: String(row.sources_csv ?? \"\")\n .split(\",\")\n .filter(Boolean)\n .sort(),\n sessionCount: Number(row.session_count ?? 0),\n lastActivity: row.last_activity == null ? null : Number(row.last_activity),\n }));\n}\n","import type {\n DashboardCostFacts,\n MessageCostFact,\n SessionCostSummary,\n} from \"../../analytics/cost-facts.js\";\nimport { getSessionReferenceKey, type CostSource } from \"../../contract/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDbReadOnly } from \"./connection.js\";\n\nexport interface CostFactOptions {\n from?: number;\n to?: number;\n includeModelCosts?: boolean;\n}\n\ninterface CostSummaryRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_count?: number;\n untimed_message_count?: number;\n input_tokens?: number;\n output_tokens?: number;\n reasoning_tokens?: number;\n cache_read_tokens?: number;\n cache_create_tokens?: number;\n untimed_input_tokens?: number;\n untimed_output_tokens?: number;\n untimed_reasoning_tokens?: number;\n untimed_cache_read_tokens?: number;\n untimed_cache_create_tokens?: number;\n message_cost?: number;\n untimed_message_cost?: number;\n}\n\ninterface MessageCostRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n cost_time?: number;\n model?: string | null;\n input_tokens?: number;\n output_tokens?: number;\n reasoning_tokens?: number;\n cache_read_tokens?: number;\n cache_create_tokens?: number;\n cost?: number;\n cost_source?: string | null;\n}\n\ninterface ModelCostRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n model?: string;\n cost?: number;\n cost_recorded?: number;\n}\n\nconst EFFECTIVE_COST_TIME = `CASE\n WHEN m.time_completed > 0 THEN m.time_completed\n WHEN m.time_created > 0 THEN m.time_created\nEND`;\n\nfunction costSource(value: string | null | undefined): CostSource | undefined {\n return value === \"recorded\" || value === \"estimated\" ? value : undefined;\n}\n\nfunction nonNegative(value: number | undefined): number {\n return Math.max(0, Number(value ?? 0));\n}\n\nfunction readCostFacts(db: SQLiteDatabase, options: CostFactOptions): DashboardCostFacts {\n const summaries = db\n .prepare(\n `\n SELECT\n c.agent_name,\n c.session_id,\n c.message_count,\n c.untimed_message_count,\n c.input_tokens,\n c.output_tokens,\n c.reasoning_tokens,\n c.cache_read_tokens,\n c.cache_create_tokens,\n c.untimed_input_tokens,\n c.untimed_output_tokens,\n c.untimed_reasoning_tokens,\n c.untimed_cache_read_tokens,\n c.untimed_cache_create_tokens,\n c.message_cost,\n c.untimed_message_cost\n FROM session_cost_summary c\n JOIN sessions s\n ON s.agent_name = c.agent_name\n AND s.session_id = c.session_id\n AND s.publication_id IS NULL\n ORDER BY c.agent_name, c.session_id\n `,\n )\n .all() as CostSummaryRow[];\n\n const bySession = new Map<string, SessionCostSummary>();\n for (const row of summaries) {\n const agentName = String(row.agent_name ?? \"\");\n const sessionId = String(row.session_id ?? \"\");\n const summary: SessionCostSummary = {\n reference: { agentName, sessionId },\n messageCount: nonNegative(row.message_count),\n untimedMessageCount: nonNegative(row.untimed_message_count),\n inputTokens: nonNegative(row.input_tokens),\n outputTokens: nonNegative(row.output_tokens),\n reasoningTokens: nonNegative(row.reasoning_tokens),\n cacheReadTokens: nonNegative(row.cache_read_tokens),\n cacheCreateTokens: nonNegative(row.cache_create_tokens),\n untimedInputTokens: nonNegative(row.untimed_input_tokens),\n untimedOutputTokens: nonNegative(row.untimed_output_tokens),\n untimedReasoningTokens: nonNegative(row.untimed_reasoning_tokens),\n untimedCacheReadTokens: nonNegative(row.untimed_cache_read_tokens),\n untimedCacheCreateTokens: nonNegative(row.untimed_cache_create_tokens),\n messageCost: Number(row.message_cost ?? 0),\n untimedMessageCost: Number(row.untimed_message_cost ?? 0),\n modelCosts: [],\n };\n bySession.set(getSessionReferenceKey({ agentName, sessionId }), summary);\n }\n\n const modelRows =\n options.includeModelCosts === false\n ? []\n : (db\n .prepare(\n `\n SELECT\n m.agent_name,\n m.session_id,\n m.model,\n m.cost,\n m.cost_recorded\n FROM session_model_cost m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n AND s.publication_id IS NULL\n ORDER BY m.agent_name, m.session_id, m.model\n `,\n )\n .all() as ModelCostRow[]);\n for (const row of modelRows) {\n const summary = bySession.get(\n getSessionReferenceKey({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n }),\n );\n if (!summary) continue;\n summary.modelCosts.push({\n model: String(row.model ?? \"\"),\n cost: Number(row.cost ?? 0),\n costRecorded: Number(row.cost_recorded ?? 0),\n });\n }\n\n const clauses = [`${EFFECTIVE_COST_TIME} IS NOT NULL`];\n const params: unknown[] = [];\n if (options.from != null) {\n clauses.push(`${EFFECTIVE_COST_TIME} >= ?`);\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(`${EFFECTIVE_COST_TIME} <= ?`);\n params.push(options.to);\n }\n\n const messageRows = db\n .prepare(\n `\n SELECT\n m.agent_name,\n m.session_id,\n ${EFFECTIVE_COST_TIME} AS cost_time,\n m.model,\n CAST(COALESCE(json_extract(m.tokens_json, '$.input'), 0) AS INTEGER) AS input_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.output'), 0) AS INTEGER) AS output_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.reasoning'), 0) AS INTEGER) AS reasoning_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.cache_read'), 0) AS INTEGER) AS cache_read_tokens,\n CAST(COALESCE(json_extract(m.tokens_json, '$.cache_create'), 0) AS INTEGER) AS cache_create_tokens,\n m.cost,\n m.cost_source\n FROM messages m INDEXED BY idx_messages_usage_time\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n AND s.publication_id IS NULL\n WHERE ${clauses.join(\" AND \")}\n ORDER BY cost_time, m.agent_name, m.session_id, m.message_index\n `,\n )\n .all(...params) as MessageCostRow[];\n\n const messages: MessageCostFact[] = messageRows.map((row) => {\n const model = typeof row.model === \"string\" && row.model.length > 0 ? row.model : undefined;\n return {\n reference: {\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n },\n time: Number(row.cost_time ?? 0),\n inputTokens: nonNegative(row.input_tokens),\n outputTokens: nonNegative(row.output_tokens),\n reasoningTokens: nonNegative(row.reasoning_tokens),\n cacheReadTokens: nonNegative(row.cache_read_tokens),\n cacheCreateTokens: nonNegative(row.cache_create_tokens),\n cost: Number(row.cost ?? 0),\n costSource: costSource(row.cost_source),\n ...(model ? { model } : {}),\n };\n });\n\n return { messages, sessions: [...bySession.values()] };\n}\n\nexport function listDashboardCostFacts(options: CostFactOptions = {}): DashboardCostFacts | null {\n if (!hasCacheStorage()) return null;\n\n const read = withCacheDbReadOnly((db: SQLiteDatabase) =>\n db.transaction(() => readCostFacts(db, options))(),\n );\n return read.status === \"success\" ? read.value : null;\n}\n","/**\n * Per-model cost aggregation. Session heads only carry per-model token totals,\n * so the cost split by model is only derivable from the cached message rows.\n */\nimport type { ModelCostEntry } from \"../../contract/index.js\";\nimport type { ProjectIdentityKind } from \"../../types/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDbReadOnly } from \"./connection.js\";\n\nexport type { ModelCostEntry };\n\nexport interface ModelCostOptions {\n agent?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n from?: number;\n to?: number;\n limit?: number;\n}\n\ninterface ModelCostRow extends DatabaseRow {\n model?: string;\n cost?: number;\n cost_recorded?: number;\n cost_estimated?: number;\n}\n\nconst DEFAULT_MODEL_COST_LIMIT = 20;\n\nfunction buildModelCostWhere(options: ModelCostOptions): {\n where: string;\n params: unknown[];\n} {\n const clauses = [\"m.model IS NOT NULL\", \"m.model <> ''\"];\n const params: unknown[] = [];\n\n if (options.agent != null) {\n clauses.push(\"s.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.projectKind != null || options.projectKey != null) {\n if (options.projectKind != null && options.projectKey != null) {\n clauses.push(\"s.project_identity_kind = ? AND s.project_identity_key = ?\");\n params.push(options.projectKind, options.projectKey);\n } else {\n // A half-specified identity can never match — mirrors listFileActivity.\n clauses.push(\"0\");\n }\n }\n if (options.from != null) {\n clauses.push(\"s.activity_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"s.activity_time <= ?\");\n params.push(options.to);\n }\n\n return { where: `WHERE ${clauses.join(\" AND \")}`, params };\n}\n\n/**\n * Sub-session messages are included on purpose: a parent's cost is defined to\n * cover its whole subtree. An unset `cost_source` counts as estimated, so\n * `costRecorded + costEstimated === cost` always holds.\n *\n * Reads the per-(session, model) rollup maintained alongside message writes\n * (CS-270) — sessions×models rows instead of a full messages-table scan.\n */\nconst MODEL_COST_SQL = `\n SELECT\n m.model AS model,\n SUM(m.cost) AS cost,\n SUM(m.cost_recorded) AS cost_recorded,\n SUM(m.cost - m.cost_recorded) AS cost_estimated\n FROM session_model_cost m\n JOIN sessions s\n ON s.agent_name = m.agent_name\n AND s.session_id = m.session_id\n AND s.publication_id IS NULL\n`;\n\n/**\n * Returns null when no cache database is available (--no-cache, or the\n * search-index worker has not created it yet). Callers MUST propagate the null\n * rather than substituting zeros.\n */\nexport function listModelCostDistribution(options: ModelCostOptions = {}): ModelCostEntry[] | null {\n if (!hasCacheStorage()) {\n return null;\n }\n\n const { where, params } = buildModelCostWhere(options);\n const sql = `\n ${MODEL_COST_SQL}\n ${where}\n GROUP BY m.model\n ORDER BY cost DESC, m.model\n LIMIT ?\n `;\n\n const read = withCacheDbReadOnly(\n (db: SQLiteDatabase) =>\n db.prepare(sql).all(...params, options.limit ?? DEFAULT_MODEL_COST_LIMIT) as ModelCostRow[],\n );\n if (read.status === \"failed\") {\n return null;\n }\n\n return read.value.map((row) => ({\n model: String(row.model ?? \"\"),\n cost: Number(row.cost ?? 0),\n costRecorded: Number(row.cost_recorded ?? 0),\n costEstimated: Number(row.cost_estimated ?? 0),\n }));\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { SessionCacheMeta } from \"../../agents/session-source-types.js\";\nimport type { IdentifiedSessionHead, SessionDetail } from \"../../types/index.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport type { PersistedSessionHeadChange } from \"./db.js\";\nimport { advanceAnalyticsRevision } from \"./analytics-revision.js\";\nimport { sessionDetailVersion } from \"./detail-version.js\";\nimport { assertSessionProjectIdentities } from \"./messages.js\";\nimport {\n prepareSessionChangesSearchIndex,\n prepareSessionSnapshotSearchIndex,\n discardPreparedSessionSearchIndex,\n writePreparedSessionSearchIndex,\n type SearchIndexSyncOptions,\n type SearchIndexSyncResult,\n} from \"./search-index-writer.js\";\nimport { withSearchIndexDb } from \"./connection.js\";\nimport {\n deleteLegacyCacheFile,\n writeCachedSessionChanges,\n writeCachedSessionSnapshot,\n} from \"./sessions.js\";\nimport type { SessionSnapshotCompleteness } from \"./snapshot-types.js\";\nimport type { SearchIndexPublicationStage } from \"./search-index-state.js\";\n\nexport type DurableSessionPublication =\n | {\n kind: \"snapshot\";\n agentName: string;\n sessions: IdentifiedSessionHead[];\n meta: Record<string, SessionCacheMeta>;\n completeness: SessionSnapshotCompleteness;\n removedSessionIds: string[];\n publicationId?: string;\n }\n | {\n kind: \"changes\";\n agentName: string;\n changes: PersistedSessionHeadChange<IdentifiedSessionHead>[];\n removedSessionIds: string[];\n meta: Record<string, SessionCacheMeta>;\n publicationId?: string;\n };\n\nexport type DurableSessionPublicationFailureStage = \"prepare\" | \"cache\" | \"search_index\" | \"commit\";\n\nexport type DurableSessionPublicationCommitResult =\n | {\n status: \"committed\";\n publicationId: string;\n searchIndex: SearchIndexSyncResult;\n }\n | {\n status: \"rolled-back\";\n publicationId: string;\n stage: DurableSessionPublicationFailureStage;\n };\n\nfunction publicationSessionCount(publication: DurableSessionPublication): number {\n return publication.kind === \"snapshot\" ? publication.sessions.length : publication.changes.length;\n}\n\nfunction reportPublicationStage(\n detail: Record<string, unknown>,\n stage: SearchIndexPublicationStage,\n options: SearchIndexSyncOptions,\n): void {\n getCoreDiagnostics()?.info?.(\"search_index.publication_stage\", { ...detail, stage });\n try {\n options.onPublicationStage?.(stage);\n } catch {}\n}\n\nfunction publicationSearchOptions(\n publication: DurableSessionPublication,\n options: SearchIndexSyncOptions,\n publicationId: string,\n): SearchIndexSyncOptions {\n return {\n ...options,\n includePendingReindex: false,\n publicationId,\n ...(publication.kind === \"snapshot\"\n ? {\n completeness: publication.completeness,\n removedSessionIds: publication.removedSessionIds,\n }\n : {}),\n detailVersions: Object.fromEntries(\n Object.entries(publication.meta).map(([sessionId, meta]) => [\n sessionId,\n sessionDetailVersion(meta),\n ]),\n ),\n };\n}\n\nexport function commitDurableSessionPublication(\n publication: DurableSessionPublication,\n loadSessionData: (sessionId: string) => SessionDetail,\n searchOptions: SearchIndexSyncOptions = {},\n): DurableSessionPublicationCommitResult {\n assertSessionProjectIdentities(\n publication.agentName,\n publication.kind === \"snapshot\"\n ? publication.sessions\n : publication.changes.map(({ session }) => session),\n );\n const publicationId = publication.publicationId ?? randomUUID();\n let failureStage: DurableSessionPublicationFailureStage = \"prepare\";\n const detail = {\n agent: publication.agentName,\n publication_id: publicationId,\n sessions: publicationSessionCount(publication),\n };\n reportPublicationStage(detail, \"started\", searchOptions);\n\n const searchIndex = withSearchIndexDb((db) => {\n const options = publicationSearchOptions(publication, searchOptions, publicationId);\n const prepared =\n publication.kind === \"snapshot\"\n ? prepareSessionSnapshotSearchIndex(\n db,\n publication.agentName,\n publication.sessions,\n loadSessionData,\n options,\n )\n : prepareSessionChangesSearchIndex(\n db,\n publication.agentName,\n publication.changes,\n publication.removedSessionIds,\n loadSessionData,\n options,\n );\n reportPublicationStage(detail, \"prepared\", options);\n\n return db\n .transaction(() => {\n failureStage = \"cache\";\n if (publication.kind === \"snapshot\") {\n writeCachedSessionSnapshot(\n db,\n publication.agentName,\n publication.sessions,\n publication.meta,\n {\n completeness: publication.completeness,\n removedSessionIds: publication.removedSessionIds,\n },\n );\n } else {\n writeCachedSessionChanges(\n db,\n publication.agentName,\n publication.changes,\n publication.removedSessionIds,\n publication.meta,\n );\n }\n reportPublicationStage(detail, \"cache_staged\", options);\n\n failureStage = \"search_index\";\n const result = writePreparedSessionSearchIndex(db, prepared);\n reportPublicationStage(detail, \"search_staged\", options);\n advanceAnalyticsRevision(db);\n failureStage = \"commit\";\n return result;\n })\n .immediate();\n });\n\n if (!searchIndex) {\n discardPreparedSessionSearchIndex(publicationId, publication.agentName);\n getCoreDiagnostics()?.warn(\"search_index.publication_stage\", {\n ...detail,\n stage: \"rolled_back\",\n failure_stage: failureStage,\n });\n return { status: \"rolled-back\", publicationId, stage: failureStage };\n }\n\n deleteLegacyCacheFile();\n reportPublicationStage(detail, \"committed\", searchOptions);\n return { status: \"committed\", publicationId, searchIndex };\n}\n","import type { DashboardActiveHours } from \"../../contract/dashboard.js\";\nimport type { DashboardScope } from \"../../analytics/dashboard.js\";\nimport type { SessionQueryScope } from \"../session-scope.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDbReadOnly } from \"./connection.js\";\nimport { buildSessionQueryScopeFilters } from \"./session-scope.js\";\n\nexport interface ActiveHoursOptions extends DashboardScope {\n from?: number;\n to: number;\n timeZone: string;\n}\n\nexport function listDashboardActiveHours(\n options: ActiveHoursOptions,\n queryScope?: SessionQueryScope,\n): DashboardActiveHours | null {\n if (!hasCacheStorage()) return null;\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: options.timeZone,\n weekday: \"short\",\n hour: \"2-digit\",\n hourCycle: \"h23\",\n });\n const weekdays = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n const { clauses, params } = buildSessionQueryScopeFilters(queryScope);\n clauses.push(\n \"s.publication_id IS NULL\",\n \"s.parent_agent_name IS NULL AND s.parent_session_id IS NULL\",\n \"m.role = 'user' AND m.automated = 0 AND m.time_created > 0\",\n \"m.time_created <= ?\",\n );\n params.push(options.to);\n if (options.from != null) {\n clauses.push(\"m.time_created >= ?\");\n params.push(options.from);\n }\n if (options.agent) {\n clauses.push(\"s.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.projectKind != null || options.projectKey != null) {\n clauses.push(\"s.project_identity_kind = ? AND s.project_identity_key = ?\");\n params.push(options.projectKind ?? null, options.projectKey ?? null);\n }\n const read = withCacheDbReadOnly((db) => {\n const counts = Array<number>(84).fill(0);\n // Avoid the session-first plan, which reads every message before filtering user activity.\n const rows = db\n .prepare(`\n SELECT m.time_created FROM messages m INDEXED BY idx_messages_user_activity\n JOIN sessions s ON s.agent_name = m.agent_name AND s.session_id = m.session_id\n WHERE ${clauses.join(\" AND \")}\n `)\n .iterate(...params);\n for (const row of rows) {\n const time = Number(row.time_created);\n if (Number.isNaN(new Date(time).getTime())) continue;\n const parts = formatter.formatToParts(time);\n const weekday = weekdays.indexOf(parts.find((part) => part.type === \"weekday\")!.value);\n const hour = Number(parts.find((part) => part.type === \"hour\")!.value);\n counts[weekday * 12 + Math.floor(hour / 2)]! += 1;\n }\n return { timeZone: options.timeZone, counts };\n });\n return read.status === \"success\" ? read.value : null;\n}\n"],"mappings":"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","names":["db","amount","rows","existsSync","result","cacheState","stream"]}
|