codesesh 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-BIXOP5QX.js → chunk-GCOAE7KI.js} +62 -14
- package/dist/chunk-GCOAE7KI.js.map +1 -0
- package/dist/{dist-T737I76S.js → dist-TZTL6VP4.js} +14 -2
- package/dist/index.js +224 -47
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +35 -9
- package/dist/scan-refresh-worker.js.map +1 -1
- package/dist/search-index-worker.js +6 -1
- package/dist/search-index-worker.js.map +1 -1
- package/dist/smart-tag-worker.js +1 -1
- package/dist/web/assets/index-D05hsCzb.css +2 -0
- package/dist/web/assets/index-DOy8q3la.js +113 -0
- package/dist/web/assets/markdown-CGVJZBE7.js +14 -0
- package/dist/web/assets/{react-CGUTVnhO.js → react-DkEeEGji.js} +1 -1
- package/dist/web/assets/{syntax-Cjw-OADI.js → syntax-CFQ-7fm6.js} +2 -2
- package/dist/web/assets/vendor-B2nLfkMs.js +80 -0
- package/dist/web/index.html +6 -6
- package/package.json +1 -1
- package/dist/chunk-BIXOP5QX.js.map +0 -1
- package/dist/web/assets/index-DlZEB-Op.css +0 -2
- package/dist/web/assets/index-O6YSX0s1.js +0 -113
- package/dist/web/assets/markdown-Bm__FT1K.js +0 -14
- package/dist/web/assets/vendor-CR3FdUHs.js +0 -40
- /package/dist/{dist-T737I76S.js.map → dist-TZTL6VP4.js.map} +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/api/routes.ts","../src/logging.ts","../src/api/handlers.ts","../src/live-scan.ts","../src/session-watcher.ts","../src/output.ts","../src/version.ts","../src/ports.ts"],"sourcesContent":["import { defineCommand, runMain } from \"citty\";\nimport { createServer, getServerStartupErrorMessage } from \"./server.js\";\nimport { LiveScanStore } from \"./live-scan.js\";\nimport { printScanResults } from \"./output.js\";\nimport { VERSION } from \"./version.js\";\nimport { appLogger } from \"./logging.js\";\nimport {\n DEFAULT_PORT,\n DEFAULT_PORT_FALLBACK_ATTEMPTS,\n hasExplicitPortArg,\n parsePort,\n} from \"./ports.js\";\nimport {\n createRegisteredAgents,\n getAgentInfoMap,\n refreshPricingCache,\n type ScanOptions,\n perf,\n} from \"@codesesh/core\";\n\nfunction parseDateToTimestamp(dateStr: string): number {\n const date = new Date(dateStr);\n if (Number.isNaN(date.getTime())) {\n throw new Error(`Invalid date: ${dateStr}`);\n }\n return date.getTime();\n}\n\nfunction parseSessionUri(uri: string): { agent: string; sessionId: string } | null {\n const match = uri.match(/^([a-z]+):\\/\\/(.+)$/i);\n if (!match) return null;\n return { agent: match[1]!, sessionId: match[2]! };\n}\n\nconst main = defineCommand({\n meta: {\n name: \"codesesh\",\n description: \"Discover, aggregate, and visualize AI coding agent sessions\",\n version: VERSION,\n },\n args: {\n port: {\n type: \"string\",\n alias: \"p\",\n description: \"HTTP server port\",\n default: String(DEFAULT_PORT),\n },\n agent: {\n type: \"string\",\n alias: \"a\",\n description: \"Filter to specific agent(s), comma-separated\",\n },\n days: {\n type: \"string\",\n alias: \"d\",\n description: \"Only include sessions active in the last N days (0 = all time)\",\n default: \"7\",\n },\n cwd: {\n type: \"string\",\n description: \"Filter to sessions from a specific project directory (use '.' for current dir)\",\n },\n from: {\n type: \"string\",\n description: \"Sessions active after this date, YYYY-MM-DD (overrides --days)\",\n },\n to: {\n type: \"string\",\n description: \"Sessions active before this date (YYYY-MM-DD)\",\n },\n session: {\n type: \"string\",\n alias: \"s\",\n description: \"Directly open a specific session (agent://session-id)\",\n },\n json: {\n type: \"boolean\",\n alias: \"j\",\n description: \"Output session index as JSON to stdout (no server)\",\n default: false,\n },\n noOpen: {\n type: \"boolean\",\n description: \"Don't auto-open browser\",\n default: false,\n },\n trace: {\n type: \"boolean\",\n description: \"Show performance trace logs\",\n default: false,\n },\n cache: {\n type: \"boolean\",\n description: \"Use cached scan results if available\",\n default: true,\n },\n \"clear-cache\": {\n type: \"boolean\",\n description: \"Clear scan cache before starting\",\n default: false,\n },\n },\n async run({ args }) {\n const startedAt = performance.now();\n const port = parsePort(args.port as string | undefined);\n const explicitPort = hasExplicitPortArg(process.argv.slice(2));\n const noOpen = args.noOpen as boolean;\n const jsonOnly = args.json as boolean;\n const trace = args.trace as boolean;\n const useCache = args.cache as boolean;\n const clearCache = args[\"clear-cache\"] as boolean;\n\n if (trace) {\n perf.enable();\n }\n\n appLogger.info(\"cli.start\", {\n version: VERSION,\n argv: process.argv.slice(2),\n port,\n json: jsonOnly,\n no_open: noOpen,\n cache: useCache,\n log_path: appLogger.getLogPath(),\n });\n\n if (clearCache) {\n const { clearCache: clear } = await import(\"@codesesh/core\");\n clear();\n appLogger.info(\"cache.clear\");\n console.log(\"Cache cleared.\");\n }\n\n void refreshPricingCache();\n\n // Parse session URI if provided\n let targetSession: { agent: string; sessionId: string } | null = null;\n if (args.session) {\n targetSession = parseSessionUri(args.session as string);\n if (!targetSession) {\n console.error(`Invalid session format: ${args.session}. Expected: agent://session-id`);\n process.exit(1);\n }\n }\n\n // Resolve cwd filter: '.' => process.cwd()\n let cwdFilter = args.cwd as string | undefined;\n if (cwdFilter === \".\") {\n cwdFilter = process.cwd();\n }\n\n // Resolve app-level default window (shared across /api/agents, /sessions, /dashboard).\n // Priority: --from (absolute) over --days (relative).\n let listDefaultFrom: number | undefined;\n let listDefaultDays: number | undefined;\n if (args.from) {\n listDefaultFrom = parseDateToTimestamp(args.from as string);\n } else {\n const days = parseInt(args.days as string, 10);\n if (!Number.isNaN(days) && days > 0) {\n listDefaultFrom = Date.now() - days * 24 * 60 * 60 * 1000;\n listDefaultDays = days;\n } else if (days === 0) {\n listDefaultDays = 0;\n }\n }\n const listDefaultTo = args.to ? parseDateToTimestamp(args.to as string) : undefined;\n\n const scanOptions: ScanOptions = {\n agents: targetSession\n ? [targetSession.agent]\n : args.agent\n ? (args.agent as string).split(\",\").map((a) => a.trim())\n : undefined,\n cwd: cwdFilter,\n useCache: useCache,\n };\n const startupScanOptions =\n targetSession || jsonOnly ? {} : { from: listDefaultFrom, to: listDefaultTo };\n\n const store = new LiveScanStore(!jsonOnly, scanOptions, startupScanOptions, {\n deferInitialRefresh: !jsonOnly,\n });\n await store.initialize();\n const result = store.getSnapshot();\n appLogger.info(\"cli.scan_ready\", {\n duration_ms: Math.round(performance.now() - startedAt),\n sessions: result.sessions.length,\n agents: Object.fromEntries(\n Object.entries(result.byAgent).map(([key, value]) => [key, value.length]),\n ),\n startup_from: startupScanOptions.from,\n startup_to: startupScanOptions.to,\n });\n\n if (trace) {\n console.log(perf.getReport());\n }\n\n if (jsonOnly) {\n // Apply --days/--from/--to window to the JSON output so CLI semantics are preserved.\n const windowed = result.sessions.filter((s) => {\n const activity = s.time_updated ?? s.time_created;\n if (listDefaultFrom != null && activity < listDefaultFrom) return false;\n if (listDefaultTo != null && activity > listDefaultTo) return false;\n return true;\n });\n const info = getAgentInfoMap(\n Object.fromEntries(Object.entries(result.byAgent).map(([k, v]) => [k, v.length])),\n );\n const output = {\n agents: info.map(({ name, displayName, count }) => ({\n name,\n displayName,\n count,\n available: count > 0,\n })),\n sessions: windowed,\n };\n appLogger.info(\"cli.json_output\", {\n sessions: windowed.length,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n console.log(JSON.stringify(output, null, 2));\n return;\n }\n\n // Print console output\n const agents = createRegisteredAgents();\n printScanResults(agents);\n\n // Start server\n let app: Awaited<ReturnType<typeof createServer>>;\n try {\n app = await createServer(port, store, {\n defaultSessionFrom: listDefaultFrom,\n defaultSessionTo: listDefaultTo,\n defaultSessionDays: listDefaultDays,\n portFallbackAttempts: explicitPort ? 1 : DEFAULT_PORT_FALLBACK_ATTEMPTS,\n });\n } catch (error) {\n console.error(getServerStartupErrorMessage(error, port));\n process.exit(1);\n }\n\n const { url } = app;\n if (!jsonOnly) {\n store.startBackgroundRefresh();\n }\n let shuttingDown = false;\n const shutdown = async (signal: NodeJS.Signals) => {\n if (shuttingDown) return;\n shuttingDown = true;\n appLogger.info(\"cli.shutdown\", { signal });\n await app.shutdown();\n process.exit(0);\n };\n process.once(\"SIGINT\", (signal) => {\n void shutdown(signal);\n });\n process.once(\"SIGTERM\", (signal) => {\n void shutdown(signal);\n });\n\n console.log(` ${url}`);\n console.log(\"\");\n appLogger.info(\"cli.ready\", {\n url,\n duration_ms: Math.round(performance.now() - startedAt),\n log_path: appLogger.getLogPath(),\n });\n\n if (!noOpen) {\n const open = (await import(\"open\")).default;\n const targetUrl = targetSession\n ? `${url}/${targetSession.agent.toLowerCase()}/${targetSession.sessionId}`\n : url;\n appLogger.info(\"browser.open\", { url: targetUrl });\n await open(targetUrl);\n }\n },\n});\n\nif (process.argv.slice(2).includes(\"-v\")) {\n console.log(VERSION);\n process.exit(0);\n}\n\nrunMain(main);\n","import { Hono } from \"hono\";\nimport { serve } from \"@hono/node-server\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { existsSync } from \"node:fs\";\nimport type { Server } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ScanResultSource } from \"./api/handlers.js\";\nimport { createApiRoutes, type ApiRouteOptions } from \"./api/routes.js\";\nimport { LiveScanStore } from \"./live-scan.js\";\nimport { appLogger } from \"./logging.js\";\n\nexport interface CreateServerOptions {\n defaultSessionFrom?: number;\n defaultSessionTo?: number;\n defaultSessionDays?: number;\n portFallbackAttempts?: number;\n}\n\nfunction findWebDistPath(): string | null {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n // Priority 1: Packaged web dist (copied during build)\n const packagedPath = resolve(__dirname, \"web\");\n if (existsSync(packagedPath)) {\n return packagedPath;\n }\n\n // Priority 2: Development path (monorepo)\n const devPath = resolve(__dirname, \"../../../apps/web/dist\");\n if (existsSync(devPath)) {\n return devPath;\n }\n\n return null;\n}\n\nfunction waitForListening(server: Server): Promise<void> {\n return new Promise((resolve, reject) => {\n const handleListening = () => {\n server.off(\"error\", handleError);\n resolve();\n };\n const handleError = (error: Error) => {\n server.off(\"listening\", handleListening);\n reject(error);\n };\n\n server.once(\"listening\", handleListening);\n server.once(\"error\", handleError);\n });\n}\n\nexport function getServerStartupErrorMessage(error: unknown, port: number): string {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"EADDRINUSE\"\n ) {\n return `Port ${port} 已被占用,请关闭现有 CodeSesh 进程或改用 --port 指定其他端口。`;\n }\n\n return error instanceof Error ? error.message : `启动服务器失败: ${String(error)}`;\n}\n\nfunction isAddressInUse(error: unknown): boolean {\n return (\n typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"EADDRINUSE\"\n );\n}\n\nfunction getListeningPort(server: Server, fallback: number): number {\n const address = server.address();\n return typeof address === \"object\" && address !== null ? (address as AddressInfo).port : fallback;\n}\n\nexport async function createServer(\n port: number,\n store: ScanResultSource &\n Partial<\n Pick<LiveScanStore, \"getScanStatus\" | \"subscribe\" | \"subscribeScanStatus\" | \"shutdown\">\n >,\n options: CreateServerOptions = {},\n): Promise<{ url: string; shutdown: () => Promise<void> }> {\n const app = new Hono();\n\n app.use(\"*\", async (c, next) => {\n const startedAt = performance.now();\n let thrown: unknown;\n\n try {\n await next();\n } catch (error) {\n thrown = error;\n throw error;\n } finally {\n const url = new URL(c.req.url);\n appLogger.info(\"http.request\", {\n method: c.req.method,\n path: url.pathname,\n query_keys: [...url.searchParams.keys()].toSorted(),\n status: c.res.status,\n duration_ms: Math.round(performance.now() - startedAt),\n error: thrown instanceof Error ? thrown.message : undefined,\n });\n }\n });\n\n // API routes\n const routeOptions: ApiRouteOptions = {\n defaultSessionFrom: options.defaultSessionFrom,\n defaultSessionTo: options.defaultSessionTo,\n defaultSessionDays: options.defaultSessionDays,\n };\n app.route(\n \"/api\",\n createApiRoutes(\n store,\n \"subscribe\" in store ? (store as LiveScanStore) : undefined,\n routeOptions,\n ),\n );\n\n // Serve static files from web dist (if available)\n const webDistPath = findWebDistPath();\n\n if (webDistPath) {\n app.use(\"/*\", serveStatic({ root: webDistPath }));\n app.get(\"/*\", serveStatic({ root: webDistPath, path: \"index.html\" }));\n }\n\n const attempts = Math.max(1, options.portFallbackAttempts ?? 1);\n let server: Server | null = null;\n let actualPort = port;\n\n for (let offset = 0; offset < attempts; offset += 1) {\n const candidatePort = port + offset;\n server = serve({ fetch: app.fetch, port: candidatePort });\n\n try {\n await waitForListening(server);\n actualPort = getListeningPort(server, candidatePort);\n break;\n } catch (error) {\n appLogger.error(\"server.listen.error\", { port: candidatePort, error });\n server.close();\n\n if (isAddressInUse(error) && offset < attempts - 1) {\n continue;\n }\n\n if (store.shutdown) {\n await store.shutdown();\n }\n\n if (isAddressInUse(error) && attempts > 1) {\n throw new Error(\n `端口 ${port}-${port + attempts - 1} 均已被占用,请关闭现有进程或改用 --port 指定其他端口。`,\n );\n }\n\n throw new Error(getServerStartupErrorMessage(error, candidatePort));\n }\n }\n\n const url = `http://localhost:${actualPort}`;\n appLogger.info(\"server.listen\", { port: actualPort, requested_port: port, url });\n\n return {\n url,\n shutdown: async () => {\n appLogger.info(\"server.shutdown\", { port: actualPort });\n await new Promise<void>((resolve) => {\n if (!server) {\n resolve();\n return;\n }\n server.close(() => resolve());\n });\n if (store.shutdown) {\n await store.shutdown();\n }\n },\n };\n}\n","import { Hono } from \"hono\";\nimport {\n handleGetAgents,\n handleGetBookmarks,\n handleGetConfig,\n handleGetDashboard,\n handleGetFileActivity,\n handleGetProjects,\n handleGetScanStatus,\n handleDeleteBookmark,\n handleImportBookmarks,\n handlePostClientLog,\n handleSearchSessions,\n handleGetSessions,\n handleGetSessionData,\n handlePutBookmark,\n type ScanResultSource,\n type SessionListDefaults,\n} from \"./handlers.js\";\nimport type { LiveScanStore } from \"../live-scan.js\";\n\nexport interface ApiRouteOptions {\n defaultSessionFrom?: number;\n defaultSessionTo?: number;\n defaultSessionDays?: number;\n}\n\nfunction createSseResponse(store: LiveScanStore, signal: AbortSignal): Response {\n const encoder = new TextEncoder();\n\n return new Response(\n new ReadableStream({\n start(controller) {\n const write = (event: string, data: unknown) => {\n controller.enqueue(encoder.encode(`event: ${event}\\n`));\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\\n\\n`));\n };\n\n write(\"connected\", { timestamp: Date.now() });\n write(\"scan-status\", store.getScanStatus());\n\n const unsubscribeSessions = store.subscribe((event) => {\n write(event.type, event);\n });\n const unsubscribeScanStatus = store.subscribeScanStatus((event) => {\n write(event.type, event);\n });\n\n const heartbeat = setInterval(() => {\n controller.enqueue(encoder.encode(\": keepalive\\n\\n\"));\n }, 15000);\n\n const close = () => {\n clearInterval(heartbeat);\n unsubscribeSessions();\n unsubscribeScanStatus();\n controller.close();\n };\n\n signal.addEventListener(\"abort\", close, { once: true });\n },\n cancel() {\n return;\n },\n }),\n {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n },\n },\n );\n}\n\nexport function createApiRoutes(\n scanSource: ScanResultSource,\n store?: LiveScanStore,\n options: ApiRouteOptions = {},\n): Hono {\n const api = new Hono();\n const listDefaults: SessionListDefaults = {\n from: options.defaultSessionFrom,\n to: options.defaultSessionTo,\n days: options.defaultSessionDays,\n };\n\n api.get(\"/config\", (c) => handleGetConfig(c, listDefaults));\n if (store) {\n api.get(\"/status\", (c) => handleGetScanStatus(c, store));\n }\n api.get(\"/agents\", (c) => handleGetAgents(c, scanSource, listDefaults));\n api.get(\"/projects\", (c) => handleGetProjects(c, scanSource, listDefaults));\n api.get(\"/sessions\", (c) => handleGetSessions(c, scanSource, listDefaults));\n api.get(\"/search\", (c) => handleSearchSessions(c, scanSource, listDefaults));\n api.get(\"/file-activity\", (c) => handleGetFileActivity(c, listDefaults));\n api.get(\"/sessions/:agent/:id\", (c) => handleGetSessionData(c, scanSource));\n api.get(\"/dashboard\", (c) => handleGetDashboard(c, scanSource, listDefaults));\n api.get(\"/bookmarks\", (c) => handleGetBookmarks(c));\n api.put(\"/bookmarks\", (c) => handlePutBookmark(c));\n api.post(\"/bookmarks/import\", (c) => handleImportBookmarks(c));\n api.delete(\"/bookmarks/:agent/:id\", (c) => handleDeleteBookmark(c));\n api.post(\"/logs\", (c) => handlePostClientLog(c));\n if (store) {\n api.get(\"/events\", (c) => createSseResponse(store, c.req.raw.signal));\n }\n\n return api;\n}\n","import {\n appendFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { SearchIndexSyncResult } from \"@codesesh/core\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LEVEL_WEIGHT: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\n\nexport interface LoggerOptions {\n logDir?: string;\n level?: LogLevel;\n maxBytes?: number;\n maxFiles?: number;\n}\n\nfunction parseLevel(value: string | undefined): LogLevel {\n if (value === \"debug\" || value === \"info\" || value === \"warn\" || value === \"error\") {\n return value;\n }\n return \"info\";\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;\n}\n\nfunction getDefaultLogDir(): string {\n const base = process.env.XDG_CACHE_HOME ?? join(homedir(), \".cache\");\n return join(base, \"codesesh\", \"logs\");\n}\n\nfunction toLogValue(value: unknown, depth = 0): unknown {\n if (value == null || typeof value === \"string\" || typeof value === \"number\") return value;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"bigint\") return value.toString();\n if (value instanceof Error) {\n return {\n name: value.name,\n message: value.message,\n stack: value.stack,\n };\n }\n if (depth >= 4) return \"[truncated]\";\n if (Array.isArray(value)) return value.slice(0, 50).map((item) => toLogValue(item, depth + 1));\n if (typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, item]) => [\n key,\n toLogValue(item, depth + 1),\n ]),\n );\n }\n return String(value);\n}\n\nfunction timestampForFile(date = new Date()): string {\n return date.toISOString().replace(/[:.]/g, \"-\");\n}\n\nexport class AppLogger {\n private readonly logDir: string;\n private readonly level: LogLevel;\n private readonly maxBytes: number;\n private readonly maxFiles: number;\n private readonly currentPath: string;\n private rotationIndex = 0;\n\n constructor(options: LoggerOptions = {}) {\n this.logDir = options.logDir ?? process.env.CODESESH_LOG_DIR ?? getDefaultLogDir();\n this.level = options.level ?? parseLevel(process.env.CODESESH_LOG_LEVEL);\n this.maxBytes =\n options.maxBytes ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_BYTES, 5_000_000);\n this.maxFiles = options.maxFiles ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_FILES, 5);\n this.currentPath = join(this.logDir, \"codesesh.log\");\n }\n\n getLogPath(): string {\n return this.currentPath;\n }\n\n debug(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"debug\", event, data);\n }\n\n info(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"info\", event, data);\n }\n\n warn(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"warn\", event, data);\n }\n\n error(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"error\", event, data);\n }\n\n private write(level: LogLevel, event: string, data: Record<string, unknown>): void {\n if (LEVEL_WEIGHT[level] < LEVEL_WEIGHT[this.level]) return;\n\n try {\n mkdirSync(this.logDir, { recursive: true });\n const line = `${JSON.stringify({\n ts: new Date().toISOString(),\n level,\n event,\n pid: process.pid,\n ...toLogValue(data),\n })}\\n`;\n this.rotateIfNeeded(Buffer.byteLength(line));\n appendFileSync(this.currentPath, line, \"utf8\");\n } catch {}\n }\n\n private rotateIfNeeded(nextBytes: number): void {\n if (!existsSync(this.currentPath)) {\n this.removeExpiredLogs();\n return;\n }\n\n const currentSize = statSync(this.currentPath).size;\n if (currentSize + nextBytes <= this.maxBytes) return;\n\n this.rotationIndex += 1;\n const rotatedPath = join(\n this.logDir,\n `codesesh-${timestampForFile()}-${process.pid}-${this.rotationIndex}.log`,\n );\n renameSync(this.currentPath, rotatedPath);\n this.removeExpiredLogs();\n }\n\n private removeExpiredLogs(): void {\n const rotated = readdirSync(this.logDir)\n .filter((name) => /^codesesh-.+\\.log$/.test(name))\n .map((name) => {\n const path = join(this.logDir, name);\n return { path, mtimeMs: statSync(path).mtimeMs };\n })\n .toSorted((a, b) => b.mtimeMs - a.mtimeMs);\n\n for (const item of rotated.slice(Math.max(0, this.maxFiles - 1))) {\n unlinkSync(item.path);\n }\n }\n}\n\nexport const appLogger = new AppLogger();\n\nexport function logSearchIndexSync(\n context: string,\n result: SearchIndexSyncResult | null,\n data: Record<string, unknown> = {},\n): void {\n if (!result || result.mode !== \"bulk\" || result.rebuildDurationMs == null) {\n return;\n }\n\n appLogger.info(\"search_index.sync\", {\n context,\n agent: result.agentName,\n mode: result.mode,\n sessions: result.sessions,\n changed: result.changed,\n deleted: result.deleted,\n indexed: result.indexed,\n skipped: result.skipped,\n duration_ms: Math.round(result.durationMs),\n rebuild_duration_ms: Math.round(result.rebuildDurationMs),\n ...data,\n });\n}\n","import type { Context } from \"hono\";\nimport type {\n BookmarkRecord,\n ProjectGroup,\n ScanResult,\n SessionData,\n SessionHead,\n SmartTag,\n} from \"@codesesh/core\";\nimport {\n BookmarkStorageUnavailableError,\n createProjectScopeMatcher,\n deleteBookmark,\n getAgentInfoMap,\n classifySessionTags,\n computeIdentity,\n extractSessionFileActivity,\n getSmartTagSourceTimestamp,\n importBookmarks,\n loadCachedSessionData,\n listFileActivity,\n listSessionFileActivity,\n listCachedProjectGroups,\n listBookmarks,\n parseSearchQuery,\n realFs,\n searchFileActivitySessions,\n searchSessions,\n upsertBookmark,\n matchesProjectScope as sessionMatchesProjectScope,\n buildDashboard,\n getSessionAgentName,\n getSessionActivityTime,\n getTotalTokens,\n startOfLocalDay,\n type DashboardData,\n type DashboardScope,\n type FileActivityKind,\n type ProjectScopeMatcher,\n type SearchMatchType,\n type SearchOptions,\n type SearchQueryFilters,\n} from \"@codesesh/core\";\nimport { appLogger } from \"../logging.js\";\n\nexport interface ScanResultSource {\n getSnapshot(): ScanResult;\n}\n\nexport interface ScanStatusSource {\n getScanStatus(): {\n type: \"scan-status\";\n active: boolean;\n phase: \"idle\" | \"indexing\" | \"initializing\" | \"scanning\";\n pendingAgents: string[];\n scanningAgents: string[];\n completedAgents: string[];\n agentStatuses: Record<\n string,\n {\n agentName: string;\n status: \"pending\" | \"scanning\" | \"complete\";\n total?: number;\n processed?: number;\n sessions?: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n }\n >;\n totalAgents: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n };\n}\n\nexport interface SessionListDefaults {\n from?: number;\n to?: number;\n /** When --days was used, original value — kept for UI \"last N days\" label */\n days?: number;\n}\n\ninterface ClientLogPayload {\n event?: unknown;\n data?: unknown;\n}\n\ninterface ApiSearchResult {\n agentName: string;\n session: SessionHead;\n snippet: string;\n matchType: SearchMatchType;\n}\n\ninterface ApiProjectAgentStat {\n name: string;\n sessions: number;\n messages: number;\n tokens: number;\n cost: number;\n}\n\ninterface ApiProjectGroup extends ProjectGroup {\n messages: number;\n tokens: number;\n cost: number;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"];\n agentStats: ApiProjectAgentStat[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isSessionStats(value: unknown): value is SessionHead[\"stats\"] {\n if (!isRecord(value)) return false;\n return (\n typeof value.message_count === \"number\" &&\n typeof value.total_input_tokens === \"number\" &&\n typeof value.total_output_tokens === \"number\" &&\n typeof value.total_cost === \"number\" &&\n (value.total_tokens == null || typeof value.total_tokens === \"number\")\n );\n}\n\nfunction parseBookmarkPayload(value: unknown): Omit<BookmarkRecord, \"bookmarked_at\"> | null {\n if (!isRecord(value)) return null;\n if (\n typeof value.agentKey !== \"string\" ||\n typeof value.sessionId !== \"string\" ||\n typeof value.fullPath !== \"string\" ||\n typeof value.title !== \"string\" ||\n typeof value.directory !== \"string\" ||\n typeof value.time_created !== \"number\" ||\n (value.time_updated != null && typeof value.time_updated !== \"number\") ||\n !isSessionStats(value.stats)\n ) {\n return null;\n }\n\n return {\n agentKey: value.agentKey,\n sessionId: value.sessionId,\n fullPath: value.fullPath,\n title: value.title,\n directory: value.directory,\n time_created: value.time_created,\n time_updated: value.time_updated,\n stats: value.stats,\n };\n}\n\nfunction parseDateParam(\n value: string | undefined,\n fallback: number | undefined,\n): number | undefined {\n if (value == null) return fallback;\n const ts = new Date(value).getTime();\n return Number.isNaN(ts) ? fallback : ts;\n}\n\nfunction parseNumberParam(value: string | undefined): number | undefined {\n if (value == null || !value.trim()) return undefined;\n const number = Number(value);\n return Number.isFinite(number) ? number : undefined;\n}\n\nfunction searchParams(c: Context): URLSearchParams {\n return new URL(c.req.url ?? \"http://localhost/\", \"http://localhost/\").searchParams;\n}\n\nfunction queryValues(params: URLSearchParams, ...names: string[]): string[] {\n return names.flatMap((name) =>\n params\n .getAll(name)\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter(Boolean),\n );\n}\n\nfunction parseSmartTags(values: string[]): SmartTag[] | undefined {\n const tags = values\n .map((value) => value.toLowerCase())\n .filter((value): value is SmartTag =>\n [\n \"bugfix\",\n \"refactoring\",\n \"feature-dev\",\n \"testing\",\n \"docs\",\n \"git-ops\",\n \"build-deploy\",\n \"exploration\",\n \"planning\",\n ].includes(value),\n );\n return tags.length > 0 ? [...new Set(tags)] : undefined;\n}\n\nfunction parseSearchOptions(c: Context, defaults: SessionListDefaults): SearchOptions {\n const params = searchParams(c);\n const limitValue = parseNumberParam(params.get(\"limit\") ?? undefined);\n return {\n agent: optionalQueryValue(params.get(\"agent\") ?? undefined),\n project: optionalQueryValue(params.get(\"project\") ?? undefined),\n projectKey: optionalQueryValue(params.get(\"projectKey\") ?? undefined),\n cwd: optionalQueryValue(params.get(\"cwd\") ?? undefined),\n tags: parseSmartTags(queryValues(params, \"tag\", \"tags\", \"signal\")),\n tools: queryValues(params, \"tool\", \"tools\").map((tool) => tool.toLowerCase()),\n file: optionalQueryValue(params.get(\"file\") ?? params.get(\"path\") ?? undefined),\n fileKind: parseFileActivityKind(\n optionalQueryValue(params.get(\"fileKind\") ?? params.get(\"fileActivity\") ?? undefined),\n ),\n costMin: parseNumberParam(params.get(\"costMin\") ?? undefined),\n costMax: parseNumberParam(params.get(\"costMax\") ?? undefined),\n from: parseDateParam(params.get(\"from\") ?? undefined, defaults.from),\n to: parseDateParam(params.get(\"to\") ?? undefined, defaults.to),\n limit: limitValue && limitValue > 0 ? Math.min(limitValue, 100) : 50,\n };\n}\n\nfunction filterSessionsByWindow(\n sessions: SessionHead[],\n from: number | undefined,\n to: number | undefined,\n): SessionHead[] {\n return filterSessionsByActivityWindow(sessions, from, to);\n}\n\nfunction filterSessionsByActivityWindow(\n sessions: SessionHead[],\n from: number | undefined,\n to: number | undefined,\n): SessionHead[] {\n if (from == null && to == null) return sessions;\n return sessions.filter((session) => {\n const activity = getSessionActivityTime(session);\n if (from != null && activity < from) return false;\n if (to != null && activity > to) return false;\n return true;\n });\n}\n\nfunction sanitizeClientLogData(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) return {};\n\n return Object.fromEntries(\n Object.entries(value)\n .slice(0, 30)\n .map(([key, item]) => {\n if (typeof item === \"string\") return [key, item.slice(0, 300)];\n if (typeof item === \"number\" || typeof item === \"boolean\" || item == null) {\n return [key, item];\n }\n return [key, String(item).slice(0, 300)];\n }),\n );\n}\n\nfunction sessionMatchesCostFilter(session: SessionHead, options: SearchOptions): boolean {\n const cost = session.stats.total_cost;\n if (options.costMin != null) {\n if (options.costMinExclusive ? cost <= options.costMin : cost < options.costMin) return false;\n }\n if (options.costMax != null) {\n if (options.costMaxExclusive ? cost >= options.costMax : cost > options.costMax) return false;\n }\n return true;\n}\n\nfunction mergeSearchLists<T>(left: T[] | undefined, right: T[] | undefined): T[] | undefined {\n const values = [...(left ?? []), ...(right ?? [])];\n return values.length > 0 ? [...new Set(values)] : undefined;\n}\n\nfunction mergeSearchOptions(options: SearchOptions, filters: SearchQueryFilters): SearchOptions {\n return {\n ...options,\n agent: options.agent ?? filters.agent,\n project: options.project ?? filters.project,\n projectKey: options.projectKey ?? filters.projectKey,\n cwd: options.cwd ?? filters.cwd,\n tags: mergeSearchLists(options.tags, filters.tags),\n tools: mergeSearchLists(options.tools, filters.tools),\n file: options.file ?? filters.file,\n fileKind: options.fileKind ?? filters.fileKind,\n costMin: options.costMin ?? filters.costMin,\n costMax: options.costMax ?? filters.costMax,\n costMinExclusive: options.costMinExclusive ?? filters.costMinExclusive,\n costMaxExclusive: options.costMaxExclusive ?? filters.costMaxExclusive,\n };\n}\n\nfunction mergeSearchResults(results: ApiSearchResult[], limit: number): ApiSearchResult[] {\n const seen = new Set<string>();\n const merged: ApiSearchResult[] = [];\n\n for (const result of results) {\n const key = `${result.agentName}/${result.session.id}`;\n if (seen.has(key)) continue;\n seen.add(key);\n merged.push(result);\n if (merged.length >= limit) break;\n }\n\n return merged;\n}\n\nfunction getProjectGroupKey(identityKind: string, identityKey: string): string {\n return `${identityKind}:${identityKey}`;\n}\n\nfunction attachProjectMetrics(\n projects: ProjectGroup[],\n sessions: SessionHead[],\n): ApiProjectGroup[] {\n const metrics = new Map<\n string,\n {\n messages: number;\n tokens: number;\n cost: number;\n hasEstimatedCost: boolean;\n agentStats: Map<string, ApiProjectAgentStat>;\n }\n >();\n\n for (const session of sessions) {\n const identity = session.project_identity;\n if (!identity) continue;\n const key = getProjectGroupKey(identity.kind, identity.key);\n let current = metrics.get(key);\n if (!current) {\n current = {\n messages: 0,\n tokens: 0,\n cost: 0,\n hasEstimatedCost: false,\n agentStats: new Map(),\n };\n metrics.set(key, current);\n }\n\n const tokens = getTotalTokens(session.stats);\n const cost = session.stats.total_cost ?? 0;\n current.messages += session.stats.message_count;\n current.tokens += tokens;\n current.cost += cost;\n if (session.stats.cost_source === \"estimated\") current.hasEstimatedCost = true;\n\n const agentName = getSessionAgentName(session);\n const agent = current.agentStats.get(agentName);\n if (agent) {\n agent.sessions += 1;\n agent.messages += session.stats.message_count;\n agent.tokens += tokens;\n agent.cost += cost;\n } else {\n current.agentStats.set(agentName, {\n name: agentName,\n sessions: 1,\n messages: session.stats.message_count,\n tokens,\n cost,\n });\n }\n }\n\n return projects.map((project) => {\n const metric = metrics.get(getProjectGroupKey(project.identityKind, project.identityKey));\n return {\n ...project,\n messages: metric?.messages ?? 0,\n tokens: metric?.tokens ?? 0,\n cost: metric?.cost ?? 0,\n cost_source:\n metric && metric.cost > 0\n ? metric.hasEstimatedCost\n ? \"estimated\"\n : \"recorded\"\n : undefined,\n agentStats: [...(metric?.agentStats.values() ?? [])].sort((a, b) => b.sessions - a.sessions),\n };\n });\n}\n\nfunction matchesRecentSearchFilters(\n session: SessionHead,\n options: SearchOptions,\n projectScope: ProjectScopeMatcher | null,\n): boolean {\n if (options.projectKey && session.project_identity?.key !== options.projectKey) return false;\n if (projectScope && !sessionMatchesProjectScope(session, projectScope)) return false;\n if (options.project) {\n const projectNeedle = options.project.toLowerCase();\n const projectText = [\n session.project_identity?.key,\n session.project_identity?.displayName,\n session.directory,\n ]\n .filter(Boolean)\n .join(\"\\n\")\n .toLowerCase();\n if (!projectText.includes(projectNeedle)) return false;\n }\n if (options.tags?.length && !options.tags.every((tag) => session.smart_tags?.includes(tag))) {\n return false;\n }\n if (!sessionMatchesCostFilter(session, options)) return false;\n return true;\n}\n\nfunction recentSearchSessions(\n scanResult: ScanResult,\n options: SearchOptions & { limit: number },\n): ApiSearchResult[] {\n const projectScope = options.cwd ? createProjectScopeMatcher(options.cwd) : null;\n const entries = options.agent\n ? ([[options.agent, scanResult.byAgent[options.agent] ?? []]] as Array<[string, SessionHead[]]>)\n : Object.entries(scanResult.byAgent);\n\n return entries\n .flatMap(([agentName, sessions]) =>\n filterSessionsByActivityWindow(sessions, options.from, options.to)\n .filter((session) => matchesRecentSearchFilters(session, options, projectScope))\n .map((session) => ({ agentName, session })),\n )\n .toSorted(\n (a, b) =>\n (b.session.time_updated ?? b.session.time_created) -\n (a.session.time_updated ?? a.session.time_created),\n )\n .slice(0, options.limit)\n .map(({ agentName, session }) => ({\n agentName,\n session,\n snippet: `Recent session · ${session.directory}`,\n matchType: \"recent\",\n }));\n}\n\nexport function handleGetConfig(c: Context, defaults: SessionListDefaults) {\n return c.json({\n window: {\n from: defaults.from,\n to: defaults.to,\n days: defaults.days,\n },\n });\n}\n\nexport function handleGetScanStatus(c: Context, scanSource: ScanStatusSource) {\n return c.json(scanSource.getScanStatus());\n}\n\nexport function handleGetAgents(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const { from, to } = defaults;\n const counts = Object.fromEntries(\n Object.entries(scanResult.byAgent).map(([agentName, sessions]) => [\n agentName,\n filterSessionsByWindow(sessions, from, to).length,\n ]),\n );\n const info = getAgentInfoMap(counts).filter((agent) => agent.count > 0);\n return c.json(info);\n}\n\nexport function handleGetProjects(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const { from, to } = defaults;\n const sessions = filterSessionsByActivityWindow(scanResult.sessions, from, to);\n return c.json({\n projects: attachProjectMetrics(listCachedProjectGroups(sessions), sessions),\n });\n}\n\nexport function handleGetSessions(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const agent = c.req.query(\"agent\");\n const q = c.req.query(\"q\")?.toLowerCase();\n const cwd = c.req.query(\"cwd\");\n const projectKey = c.req.query(\"projectKey\");\n const tag = c.req.query(\"tag\")?.toLowerCase();\n const from = parseDateParam(c.req.query(\"from\"), defaults.from);\n const to = parseDateParam(c.req.query(\"to\"), defaults.to);\n\n let sessions: SessionHead[] = [];\n\n // If agent filter is specified, use byAgent directly\n if (agent && scanResult.byAgent[agent]) {\n sessions = [...scanResult.byAgent[agent]!];\n } else {\n sessions = [...scanResult.sessions];\n }\n\n if (projectKey) {\n sessions = sessions.filter((s) => s.project_identity?.key === projectKey);\n } else if (cwd) {\n const projectScope = createProjectScopeMatcher(cwd);\n sessions = sessions.filter((s) => sessionMatchesProjectScope(s, projectScope));\n }\n sessions = filterSessionsByActivityWindow(sessions, from, to);\n if (tag) {\n sessions = sessions.filter((s) => s.smart_tags?.includes(tag as SmartTag));\n }\n\n if (q) {\n sessions = sessions.filter((s) => s.title.toLowerCase().includes(q));\n }\n\n return c.json({ sessions });\n}\n\nexport function handleSearchSessions(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const query = c.req.query(\"q\")?.trim() ?? \"\";\n const scanResult = scanSource.getSnapshot();\n const searchOptions = parseSearchOptions(c, defaults);\n const parsedQuery = parseSearchQuery(query);\n const mergedSearchOptions = mergeSearchOptions(searchOptions, parsedQuery.filters);\n const textQuery = parsedQuery.text || (parsedQuery.hasQualifiers ? \"\" : query);\n const needsIndexedSearch = Boolean(\n textQuery ||\n mergedSearchOptions.file ||\n mergedSearchOptions.fileKind ||\n mergedSearchOptions.tools?.length,\n );\n\n if (!needsIndexedSearch) {\n return c.json({\n results: recentSearchSessions(\n scanResult,\n mergedSearchOptions as SearchOptions & { limit: number },\n ),\n });\n }\n\n const fileQuery =\n mergedSearchOptions.file ??\n (!parsedQuery.text ? parsedQuery.filters.file : undefined) ??\n (!parsedQuery.hasQualifiers && query ? parsedQuery.text || query : \"\");\n const results: ApiSearchResult[] = mergeSearchResults(\n [\n ...(fileQuery ? searchFileActivitySessions(fileQuery, mergedSearchOptions) : []),\n ...searchSessions(query, mergedSearchOptions),\n ],\n mergedSearchOptions.limit ?? 50,\n );\n\n return c.json({ results });\n}\n\nfunction parseFileActivityKind(value: string | undefined): FileActivityKind | undefined {\n if (value === \"read\" || value === \"edit\" || value === \"write\" || value === \"delete\") {\n return value;\n }\n return undefined;\n}\n\nfunction optionalQueryValue(value: string | undefined): string | undefined {\n const normalized = value?.trim();\n return normalized ? normalized : undefined;\n}\n\nexport function handleGetFileActivity(c: Context, defaults: SessionListDefaults = {}) {\n const limitValue = Number(c.req.query(\"limit\"));\n const limit = Number.isFinite(limitValue) && limitValue > 0 ? Math.min(limitValue, 200) : 50;\n\n return c.json({\n activity: listFileActivity({\n agent: optionalQueryValue(c.req.query(\"agent\")),\n sessionId: optionalQueryValue(c.req.query(\"sessionId\")),\n projectKey: optionalQueryValue(c.req.query(\"projectKey\")),\n project: optionalQueryValue(c.req.query(\"project\")),\n cwd: optionalQueryValue(c.req.query(\"cwd\")),\n path: optionalQueryValue(c.req.query(\"path\")),\n kind: parseFileActivityKind(optionalQueryValue(c.req.query(\"kind\"))),\n from: parseDateParam(c.req.query(\"from\"), defaults.from),\n to: parseDateParam(c.req.query(\"to\"), defaults.to),\n limit,\n }),\n });\n}\n\nexport async function handleGetSessionData(c: Context, scanSource: ScanResultSource) {\n const startedAt = performance.now();\n const scanResult = scanSource.getSnapshot();\n const agentName = c.req.param(\"agent\");\n const sessionId = c.req.param(\"id\");\n\n if (!sessionId) {\n return c.json({ error: \"Missing session ID\" }, 400);\n }\n\n const agent = scanResult.agents.find((a) => a.name === agentName);\n\n if (!agent) {\n return c.json({ error: `Unknown agent: ${agentName}` }, 404);\n }\n\n try {\n const head = scanResult.byAgent[agentName]?.find((item) => item.id === sessionId);\n const loadStartedAt = performance.now();\n const cachedData = loadCachedSessionData(agentName, sessionId);\n const cachedMessageCount = cachedData?.stats.message_count ?? 0;\n const cacheHasExpectedMessages =\n cachedData !== null && (cachedData.messages.length > 0 || cachedMessageCount === 0);\n const data: SessionData | null = cacheHasExpectedMessages\n ? cachedData\n : head\n ? agent.getSessionData(sessionId)\n : null;\n const loadDuration = performance.now() - loadStartedAt;\n if (!data) {\n appLogger.warn(\"api.session_data.cache_miss\", {\n agent: agentName,\n session_id: sessionId,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return c.json({ error: \"Session cache not ready\" }, 404);\n }\n const tagStartedAt = performance.now();\n const smartTags = data.smart_tags ?? classifySessionTags(data);\n const tagDuration = performance.now() - tagStartedAt;\n const projectIdentity =\n data.project_identity ?? head?.project_identity ?? computeIdentity(data.directory, realFs);\n const fileActivity =\n data.file_activity ??\n (cacheHasExpectedMessages && cachedData\n ? listSessionFileActivity(agentName, sessionId)\n : extractSessionFileActivity(agentName, sessionId, projectIdentity.key, data.messages));\n appLogger.info(\"api.session_data\", {\n agent: agentName,\n session_id: sessionId,\n messages: data.messages.length,\n load_duration_ms: Math.round(loadDuration),\n tag_duration_ms: Math.round(tagDuration),\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return c.json({\n ...data,\n project_identity: projectIdentity,\n smart_tags: smartTags,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n file_activity: fileActivity,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Failed to load session\";\n appLogger.error(\"api.session_data.error\", {\n agent: agentName,\n session_id: sessionId,\n duration_ms: Math.round(performance.now() - startedAt),\n error: message,\n });\n return c.json({ error: message }, 500);\n }\n}\n\nexport async function handlePostClientLog(c: Context) {\n const payload = (await c.req.json().catch(() => null)) as ClientLogPayload | null;\n const rawEvent = payload?.event;\n\n if (typeof rawEvent !== \"string\" || !rawEvent.trim()) {\n return c.json({ ok: false }, 400);\n }\n\n const event = rawEvent\n .trim()\n .replace(/[^a-zA-Z0-9_.:-]/g, \"_\")\n .slice(0, 120);\n appLogger.info(`client.${event}`, sanitizeClientLogData(payload?.data));\n return c.json({ ok: true });\n}\n\nexport function handleGetBookmarks(c: Context) {\n try {\n return c.json({ bookmarks: listBookmarks(), storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ bookmarks: [], storageAvailable: false });\n }\n throw error;\n }\n}\n\nexport async function handlePutBookmark(c: Context) {\n const payload = parseBookmarkPayload(await c.req.json().catch(() => null));\n if (!payload) {\n return c.json({ error: \"Invalid bookmark payload\" }, 400);\n }\n\n try {\n return c.json({ bookmark: upsertBookmark(payload), storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ error: \"Bookmark storage is unavailable\" }, 503);\n }\n throw error;\n }\n}\n\nexport async function handleImportBookmarks(c: Context) {\n const payload = await c.req.json().catch(() => null);\n if (!Array.isArray(payload)) {\n return c.json({ error: \"Invalid bookmark payload\" }, 400);\n }\n\n const bookmarks = payload\n .map((entry) => parseBookmarkPayload(entry))\n .filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n\n if (bookmarks.length !== payload.length) {\n return c.json({ error: \"Invalid bookmark payload\" }, 400);\n }\n\n try {\n return c.json({ bookmarks: importBookmarks(bookmarks), storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ error: \"Bookmark storage is unavailable\" }, 503);\n }\n throw error;\n }\n}\n\nexport function handleDeleteBookmark(c: Context) {\n const agentKey = c.req.param(\"agent\");\n const sessionId = c.req.param(\"id\");\n if (!agentKey || !sessionId) {\n return c.json({ error: \"Missing bookmark identifier\" }, 400);\n }\n\n try {\n deleteBookmark(agentKey, sessionId);\n return c.json({ ok: true, storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ error: \"Bookmark storage is unavailable\" }, 503);\n }\n throw error;\n }\n}\n\nfunction resolveDashboardWindow(\n defaults: SessionListDefaults,\n queryDays: string | undefined,\n queryFrom: string | undefined,\n queryTo: string | undefined,\n): { from?: number; to: number; days?: number } {\n const now = Date.now();\n\n const toTs = parseDateParam(queryTo, defaults.to) ?? now;\n\n // Resolve days (preferred): query, defaults.days, or derive from defaults.from\n const hasQueryDays = queryDays != null && queryDays.trim() !== \"\";\n const parsedDays = hasQueryDays ? parseInt(queryDays, 10) : NaN;\n let days: number | undefined =\n Number.isFinite(parsedDays) && parsedDays > 0 ? parsedDays : defaults.days;\n\n const fromFromQuery = parseDateParam(queryFrom, undefined);\n let fromTs: number;\n if (fromFromQuery != null) {\n fromTs = fromFromQuery;\n days ??= Math.max(1, Math.ceil((toTs - fromTs) / 86400000));\n } else if (parsedDays === 0 || (!hasQueryDays && defaults.days === 0)) {\n days = 0;\n return { to: toTs, days };\n } else if (defaults.from != null) {\n fromTs = defaults.from;\n days ??= Math.max(1, Math.ceil((toTs - fromTs) / 86400000));\n } else if (days && days > 0) {\n fromTs = startOfLocalDay(toTs) - (days - 1) * 86400000;\n } else {\n days = 30;\n fromTs = startOfLocalDay(toTs) - (days - 1) * 86400000;\n }\n\n return { from: fromTs, to: toTs, days };\n}\n\nexport function handleGetDashboard(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const { from, to, days } = resolveDashboardWindow(\n defaults,\n c.req.query(\"days\"),\n c.req.query(\"from\"),\n c.req.query(\"to\"),\n );\n const scope: DashboardScope = {\n agent: optionalQueryValue(c.req.query(\"agent\"))?.toLowerCase(),\n projectKind: optionalQueryValue(c.req.query(\"projectKind\")),\n projectKey: optionalQueryValue(c.req.query(\"projectKey\")),\n };\n\n const agentInfo = getAgentInfoMap({});\n const agentInfoMap = new Map(agentInfo.map((a) => [a.name, a]));\n\n const aggregate = buildDashboard(scanResult.sessions, {\n byAgentNames: Object.keys(scanResult.byAgent),\n scope,\n from,\n to,\n agentInfoMap,\n });\n\n const data: DashboardData = {\n ...aggregate,\n recentFileActivities: listFileActivity({\n agent: scope.agent,\n projectKey: scope.projectKey,\n from,\n to,\n limit: 12,\n }),\n window: { from, to, days },\n };\n\n return c.json(data);\n}\n","import { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport {\n createRegisteredAgents,\n filterSessions,\n isAgentCacheInitialized,\n loadCachedSessions,\n scanSessions,\n FileSystemSessionSource,\n attachMissingProjectIdentities,\n buildAgentCacheMeta,\n computeSessionDiff,\n sessionSignature,\n sortSessions,\n type AgentScanProgress,\n type BaseAgent,\n type ScanResult,\n type ScanOptions,\n type SessionCacheMeta,\n type SessionHeadChange,\n type SessionHead,\n} from \"@codesesh/core\";\nimport type { SearchIndexWorkerJob, SearchIndexWorkerMessage } from \"./search-index-worker.js\";\nimport type { ScanRefreshWorkerMessage } from \"./scan-refresh-worker.js\";\nimport { SessionWatcher, resolveAgentWatchTargets } from \"./session-watcher.js\";\n\nexport { resolveAgentWatchTargets };\nimport { appLogger, logSearchIndexSync } from \"./logging.js\";\n\nexport interface SessionsUpdatedEvent {\n type: \"sessions-updated\";\n changedAgents: string[];\n newSessions: number;\n updatedSessions: number;\n removedSessions: number;\n totalSessions: number;\n timestamp: number;\n changedSessionHeads: Array<{ agentName: string; session: SessionHead }>;\n removedSessionRefs: Array<{ agentName: string; sessionId: string }>;\n}\n\nexport interface ScanStatusEvent {\n type: \"scan-status\";\n active: boolean;\n phase: \"idle\" | \"indexing\" | \"initializing\" | \"scanning\";\n pendingAgents: string[];\n scanningAgents: string[];\n completedAgents: string[];\n agentStatuses: Record<string, AgentScanStatus>;\n totalAgents: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n}\n\nexport interface AgentScanStatus {\n agentName: string;\n status: \"pending\" | \"scanning\" | \"complete\";\n total?: number;\n processed?: number;\n sessions?: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n}\n\ntype StoreListener = (event: SessionsUpdatedEvent) => void;\ntype ScanStatusListener = (event: ScanStatusEvent) => void;\n\ninterface SessionRefreshDiff {\n event: SessionsUpdatedEvent | null;\n changedSessions: SessionHeadChange[];\n removedSessionIds: string[];\n}\n\ninterface SearchIndexJobBatch {\n context: string;\n jobs: SearchIndexWorkerJob[];\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface LiveScanStoreOptions {\n deferInitialRefresh?: boolean;\n}\n\nconst REFRESH_DEBOUNCE_MS = 200;\nconst EMPTY_AGENT_REFRESH_DEBOUNCE_MS = 30_000;\nconst PENDING_REFRESH_DELAY_MS = 100;\nconst NEW_SESSION_EVENT_WINDOW_MS = 250;\nconst SEARCH_INDEX_BULK_PENDING_PATH_THRESHOLD = 100;\n\nfunction buildRefreshDiff(\n agentName: string,\n previousSessions: SessionHead[],\n nextSessions: SessionHead[],\n candidateChangedIds: string[] = [],\n): SessionRefreshDiff {\n const { changes, removedSessionIds, counts } = computeSessionDiff(\n previousSessions,\n nextSessions,\n candidateChangedIds,\n sessionSignature,\n );\n\n if (counts.new === 0 && counts.updated === 0 && counts.removed === 0) {\n return { event: null, changedSessions: changes, removedSessionIds };\n }\n\n return {\n changedSessions: changes,\n removedSessionIds,\n event: {\n type: \"sessions-updated\",\n changedAgents: [agentName],\n newSessions: counts.new,\n updatedSessions: counts.updated,\n removedSessions: counts.removed,\n totalSessions: nextSessions.length,\n timestamp: Date.now(),\n changedSessionHeads: changes.map(({ session }) => ({ agentName, session })),\n removedSessionRefs: removedSessionIds.map((sessionId) => ({ agentName, sessionId })),\n },\n };\n}\n\nfunction restoreAgentCacheMeta(agent: BaseAgent, meta: Record<string, SessionCacheMeta>): void {\n agent.setSessionMetaMap(new Map(Object.entries(meta)));\n}\n\nfunction mergeEvents(\n previous: SessionsUpdatedEvent,\n next: SessionsUpdatedEvent,\n): SessionsUpdatedEvent {\n const changedSessionHeads = new Map<string, { agentName: string; session: SessionHead }>();\n const removedSessionRefs = new Map<string, { agentName: string; sessionId: string }>();\n const sessionKey = (agentName: string, sessionId: string) => `${agentName}\\0${sessionId}`;\n const addChanged = (item: { agentName: string; session: SessionHead }) => {\n const key = sessionKey(item.agentName, item.session.id);\n removedSessionRefs.delete(key);\n changedSessionHeads.set(key, item);\n };\n const addRemoved = (item: { agentName: string; sessionId: string }) => {\n const key = sessionKey(item.agentName, item.sessionId);\n changedSessionHeads.delete(key);\n removedSessionRefs.set(key, item);\n };\n\n for (const item of previous.changedSessionHeads) addChanged(item);\n for (const item of previous.removedSessionRefs) addRemoved(item);\n for (const item of next.changedSessionHeads) addChanged(item);\n for (const item of next.removedSessionRefs) addRemoved(item);\n\n return {\n type: \"sessions-updated\",\n changedAgents: Array.from(new Set([...previous.changedAgents, ...next.changedAgents])),\n newSessions: previous.newSessions + next.newSessions,\n updatedSessions: previous.updatedSessions + next.updatedSessions,\n removedSessions: previous.removedSessions + next.removedSessions,\n totalSessions: next.totalSessions,\n timestamp: next.timestamp,\n changedSessionHeads: [...changedSessionHeads.values()],\n removedSessionRefs: [...removedSessionRefs.values()],\n };\n}\n\nexport class LiveScanStore {\n private agents: BaseAgent[] = [];\n private byAgent: Record<string, SessionHead[]> = {};\n private sessions: SessionHead[] = [];\n private listeners = new Set<StoreListener>();\n private scanStatusListeners = new Set<ScanStatusListener>();\n private scanStatus: Omit<ScanStatusEvent, \"type\"> = {\n active: false,\n phase: \"idle\",\n pendingAgents: [],\n scanningAgents: [],\n completedAgents: [],\n agentStatuses: {},\n totalAgents: 0,\n updatedAt: Date.now(),\n };\n private refreshTimers = new Map<string, NodeJS.Timeout>();\n private refreshTimestamps = new Map<string, number>();\n private refreshInFlight = new Set<string>();\n private pendingRefreshes = new Set<string>();\n private pendingRefreshPathCounts = new Map<string, number>();\n private watcher: SessionWatcher | null = null;\n private pendingEvent: SessionsUpdatedEvent | null = null;\n private pendingEventTimer: NodeJS.Timeout | null = null;\n private backgroundRefreshTimer: NodeJS.Timeout | null = null;\n private searchIndexWorker: Worker | null = null;\n private pendingSearchIndexJobs: SearchIndexJobBatch[] = [];\n private shuttingDown = false;\n\n constructor(\n private readonly watchEnabled = true,\n private readonly scanOptions: ScanOptions = {},\n private readonly startupScanOptions: Pick<ScanOptions, \"from\" | \"to\"> = {},\n private readonly storeOptions: LiveScanStoreOptions = {},\n ) {}\n\n async initialize(): Promise<void> {\n const startedAt = performance.now();\n const deferInitialRefresh = this.storeOptions.deferInitialRefresh === true;\n appLogger.info(\"scan.initial.start\", {\n watch_enabled: this.watchEnabled,\n agents: this.scanOptions.agents,\n use_cache: this.scanOptions.useCache ?? true,\n startup_from: this.startupScanOptions.from,\n startup_to: this.startupScanOptions.to,\n deferred: deferInitialRefresh || undefined,\n });\n const initialResult = await scanSessions({\n ...this.scanOptions,\n ...(deferInitialRefresh ? this.startupScanOptions : {}),\n useCache: this.scanOptions.useCache ?? true,\n smartRefresh: false,\n cacheOnly: deferInitialRefresh,\n writeCache: deferInitialRefresh ? false : this.scanOptions.writeCache,\n smartTagWorkerUrl: this.getSmartTagWorkerUrl() ?? undefined,\n includeSmartTags: deferInitialRefresh ? false : undefined,\n });\n this.applyScanResult(initialResult);\n const indexStartedAt = performance.now();\n if (!deferInitialRefresh) {\n await this.enqueueSearchIndexJobs(\n \"scan.initial\",\n this.buildFullSearchIndexJobs(\"scan.initial\"),\n );\n }\n const indexDuration = performance.now() - indexStartedAt;\n appLogger.info(\"scan.initial.done\", {\n duration_ms: Math.round(performance.now() - startedAt),\n index_ms: deferInitialRefresh ? undefined : Math.round(indexDuration),\n deferred: deferInitialRefresh || undefined,\n sessions: this.sessions.length,\n agents: Object.fromEntries(\n Object.entries(this.byAgent).map(([key, value]) => [key, value.length]),\n ),\n agent_timings: initialResult.timings\n ? Object.fromEntries(\n Object.entries(initialResult.timings).map(([name, t]) => [\n name,\n {\n total_ms: Math.round(t.total),\n cache_load_ms: t.cacheLoad != null ? Math.round(t.cacheLoad) : undefined,\n check_changes_ms: t.checkChanges != null ? Math.round(t.checkChanges) : undefined,\n scan_ms: t.scan != null ? Math.round(t.scan) : undefined,\n identity_ms: t.identity != null ? Math.round(t.identity) : undefined,\n tags_ms: t.tags != null ? Math.round(t.tags) : undefined,\n },\n ]),\n )\n : undefined,\n });\n if (this.watchEnabled) {\n this.watcher = new SessionWatcher();\n this.watcher.onAgentsChanged((agentNames) => {\n for (const agentName of agentNames) {\n this.pendingRefreshPathCounts.set(\n agentName,\n (this.pendingRefreshPathCounts.get(agentName) ?? 0) + 1,\n );\n const delayMs =\n (this.byAgent[agentName]?.length ?? 0) === 0\n ? EMPTY_AGENT_REFRESH_DEBOUNCE_MS\n : REFRESH_DEBOUNCE_MS;\n this.scheduleRefresh(agentName, delayMs);\n }\n });\n this.watcher.start(this.agents.map((agent) => agent.name));\n }\n }\n\n startBackgroundRefresh(): void {\n if (this.backgroundRefreshTimer) {\n return;\n }\n const agentNames = this.agents.map((agent) => agent.name);\n this.startScanBatch(agentNames, \"scanning\");\n this.backgroundRefreshTimer = setTimeout(() => {\n this.backgroundRefreshTimer = null;\n for (const agentName of agentNames) {\n this.scheduleRefresh(agentName, 0);\n }\n if (agentNames.length === 0) {\n this.finishScanBatch();\n }\n }, 0);\n }\n\n getSnapshot(): ScanResult {\n return {\n sessions: this.sessions,\n byAgent: this.byAgent,\n agents: this.agents,\n };\n }\n\n getScanStatus(): ScanStatusEvent {\n return {\n type: \"scan-status\",\n ...this.scanStatus,\n pendingAgents: [...this.scanStatus.pendingAgents],\n scanningAgents: [...this.scanStatus.scanningAgents],\n completedAgents: [...this.scanStatus.completedAgents],\n agentStatuses: Object.fromEntries(\n Object.entries(this.scanStatus.agentStatuses).map(([agentName, status]) => [\n agentName,\n { ...status },\n ]),\n ),\n };\n }\n\n subscribe(listener: StoreListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n subscribeScanStatus(listener: ScanStatusListener): () => void {\n this.scanStatusListeners.add(listener);\n return () => {\n this.scanStatusListeners.delete(listener);\n };\n }\n\n async shutdown(): Promise<void> {\n this.shuttingDown = true;\n for (const timer of this.refreshTimers.values()) {\n clearTimeout(timer);\n }\n this.refreshTimers.clear();\n this.pendingRefreshPathCounts.clear();\n\n if (this.pendingEventTimer) {\n clearTimeout(this.pendingEventTimer);\n this.pendingEventTimer = null;\n }\n if (this.backgroundRefreshTimer) {\n clearTimeout(this.backgroundRefreshTimer);\n this.backgroundRefreshTimer = null;\n }\n if (this.searchIndexWorker) {\n await this.searchIndexWorker.terminate();\n this.searchIndexWorker = null;\n }\n for (const batch of this.pendingSearchIndexJobs) {\n batch.reject(new Error(\"Live scan store shut down\"));\n }\n this.pendingSearchIndexJobs = [];\n this.pendingEvent = null;\n\n if (this.watcher) {\n await this.watcher.dispose();\n this.watcher = null;\n }\n }\n\n private emit(event: SessionsUpdatedEvent): void {\n if (this.pendingEvent || event.newSessions > 0) {\n this.queueEvent(event);\n return;\n }\n\n this.emitNow(event);\n }\n\n private emitNow(event: SessionsUpdatedEvent): void {\n for (const listener of this.listeners) {\n listener(event);\n }\n }\n\n private emitScanStatus(): void {\n const event = this.getScanStatus();\n for (const listener of this.scanStatusListeners) {\n listener(event);\n }\n }\n\n private updateScanStatus(next: Omit<ScanStatusEvent, \"type\">): void {\n this.scanStatus = next;\n this.emitScanStatus();\n }\n\n private startScanBatch(agentNames: string[], phase: ScanStatusEvent[\"phase\"]): void {\n const uniqueAgentNames = [...new Set(agentNames)];\n const now = Date.now();\n const agentStatuses = Object.fromEntries(\n uniqueAgentNames.map((agentName) => [\n agentName,\n {\n agentName,\n status: \"pending\" as const,\n processed: 0,\n sessions: this.byAgent[agentName]?.length ?? 0,\n updatedAt: now,\n },\n ]),\n );\n this.updateScanStatus({\n active: uniqueAgentNames.length > 0,\n phase: uniqueAgentNames.length > 0 ? phase : \"idle\",\n pendingAgents: uniqueAgentNames,\n scanningAgents: [],\n completedAgents: [],\n agentStatuses,\n totalAgents: uniqueAgentNames.length,\n startedAt: uniqueAgentNames.length > 0 ? now : undefined,\n updatedAt: now,\n completedAt: uniqueAgentNames.length > 0 ? undefined : now,\n });\n }\n\n private setScanPhase(phase: ScanStatusEvent[\"phase\"]): void {\n if (!this.scanStatus.active) return;\n this.updateScanStatus({\n ...this.scanStatus,\n phase,\n updatedAt: Date.now(),\n });\n }\n\n private beginAgentScan(agentName: string): void {\n if (!this.scanStatus.active) {\n this.startScanBatch([agentName], \"scanning\");\n }\n\n const pendingAgents = this.scanStatus.pendingAgents.filter((agent) => agent !== agentName);\n const scanningAgents = [...new Set([...this.scanStatus.scanningAgents, agentName])];\n const completedAgents = this.scanStatus.completedAgents.filter((agent) => agent !== agentName);\n const existingStatus = this.scanStatus.agentStatuses[agentName];\n const agentStatuses = {\n ...this.scanStatus.agentStatuses,\n [agentName]: {\n agentName,\n status: \"scanning\" as const,\n total: existingStatus?.total,\n processed: existingStatus?.processed ?? 0,\n sessions: existingStatus?.sessions ?? this.byAgent[agentName]?.length ?? 0,\n startedAt: existingStatus?.startedAt ?? Date.now(),\n updatedAt: Date.now(),\n },\n };\n this.updateScanStatus({\n ...this.scanStatus,\n active: true,\n phase: this.scanStatus.phase === \"initializing\" ? \"initializing\" : \"scanning\",\n pendingAgents,\n scanningAgents,\n completedAgents,\n agentStatuses,\n totalAgents: Math.max(\n this.scanStatus.totalAgents,\n pendingAgents.length + scanningAgents.length,\n ),\n updatedAt: Date.now(),\n completedAt: undefined,\n });\n }\n\n private updateAgentScanProgress(agentName: string, progress: AgentScanProgress): void {\n const status = this.scanStatus.agentStatuses[agentName];\n if (!status || status.status !== \"scanning\") return;\n this.updateScanStatus({\n ...this.scanStatus,\n agentStatuses: {\n ...this.scanStatus.agentStatuses,\n [agentName]: {\n ...status,\n total: progress.total ?? status.total,\n processed: progress.processed ?? status.processed,\n sessions: progress.sessions ?? status.sessions,\n updatedAt: Date.now(),\n },\n },\n updatedAt: Date.now(),\n });\n }\n\n private finishAgentScan(agentName: string): void {\n const pendingAgents = this.scanStatus.pendingAgents.filter((agent) => agent !== agentName);\n const scanningAgents = this.scanStatus.scanningAgents.filter((agent) => agent !== agentName);\n const completedAgents = [...new Set([...this.scanStatus.completedAgents, agentName])];\n const active = pendingAgents.length > 0 || scanningAgents.length > 0;\n const now = Date.now();\n const previousStatus = this.scanStatus.agentStatuses[agentName];\n const sessions = this.byAgent[agentName]?.length ?? previousStatus?.sessions ?? 0;\n const total = previousStatus?.total ?? previousStatus?.processed;\n\n this.updateScanStatus({\n ...this.scanStatus,\n active,\n phase: active ? \"scanning\" : \"idle\",\n pendingAgents,\n scanningAgents,\n completedAgents,\n agentStatuses: {\n ...this.scanStatus.agentStatuses,\n [agentName]: {\n agentName,\n status: \"complete\",\n total,\n processed: total,\n sessions,\n startedAt: previousStatus?.startedAt,\n updatedAt: now,\n completedAt: now,\n },\n },\n updatedAt: now,\n completedAt: active ? undefined : now,\n });\n }\n\n private finishScanBatch(): void {\n const now = Date.now();\n this.updateScanStatus({\n ...this.scanStatus,\n active: false,\n phase: \"idle\",\n pendingAgents: [],\n scanningAgents: [],\n agentStatuses: Object.fromEntries(\n Object.entries(this.scanStatus.agentStatuses).map(([agentName, status]) => [\n agentName,\n { ...status, status: \"complete\", completedAt: status.completedAt ?? now, updatedAt: now },\n ]),\n ),\n updatedAt: now,\n completedAt: now,\n });\n }\n\n private queueEvent(event: SessionsUpdatedEvent): void {\n this.pendingEvent = this.pendingEvent ? mergeEvents(this.pendingEvent, event) : event;\n if (this.pendingEventTimer) {\n return;\n }\n\n this.pendingEventTimer = setTimeout(() => {\n const pending = this.pendingEvent;\n this.pendingEvent = null;\n this.pendingEventTimer = null;\n if (pending) {\n this.emitNow(pending);\n }\n }, NEW_SESSION_EVENT_WINDOW_MS);\n }\n\n private rebuildSessions(): void {\n this.sessions = sortSessions(Object.values(this.byAgent).flat());\n }\n\n private getSearchIndexWorkerUrl(): URL | null {\n const workerUrl = new URL(\"./search-index-worker.js\", import.meta.url);\n if (workerUrl.protocol === \"file:\" && !existsSync(fileURLToPath(workerUrl))) {\n return null;\n }\n return workerUrl;\n }\n\n private getSmartTagWorkerUrl(): URL | null {\n const workerUrl = new URL(\"./smart-tag-worker.js\", import.meta.url);\n if (workerUrl.protocol === \"file:\" && !existsSync(fileURLToPath(workerUrl))) {\n return null;\n }\n return workerUrl;\n }\n\n private getScanRefreshWorkerUrl(): URL {\n return new URL(\"./scan-refresh-worker.js\", import.meta.url);\n }\n\n private scanAgentInWorker(\n agent: BaseAgent,\n previousSessions: SessionHead[],\n changedIds: string[] | null,\n scanOptions: Pick<ScanOptions, \"from\" | \"to\" | \"fast\">,\n workerOptions: { sourceSync?: boolean; meta?: Record<string, SessionCacheMeta> } = {},\n ): Promise<{\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n changedIds?: string[];\n }> {\n const workerUrl = this.getScanRefreshWorkerUrl();\n\n return new Promise((resolve, reject) => {\n const worker = new Worker(workerUrl, {\n workerData: {\n agentName: agent.name,\n previousSessions,\n changedIds,\n sourceSync: workerOptions.sourceSync,\n scanOptions,\n meta: workerOptions.meta ?? buildAgentCacheMeta(agent),\n },\n });\n worker.unref();\n\n let settled = false;\n const finish = (callback: () => void) => {\n if (settled) return;\n settled = true;\n void worker.terminate();\n callback();\n };\n\n worker.on(\"message\", (message: ScanRefreshWorkerMessage) => {\n if (message.type === \"progress\") {\n this.updateAgentScanProgress(agent.name, message.progress);\n return;\n }\n if (message.type === \"done\") {\n finish(() =>\n resolve({\n sessions: message.sessions,\n meta: message.meta,\n changedIds: message.changedIds,\n }),\n );\n return;\n }\n finish(() => reject(new Error(message.error)));\n });\n worker.once(\"error\", (error) => {\n finish(() => reject(error));\n });\n worker.once(\"exit\", (code) => {\n if (!settled && code !== 0) {\n finish(() => reject(new Error(`Scan refresh worker exited with code ${code}`)));\n }\n });\n });\n }\n\n private buildFullSearchIndexJobs(context: string): SearchIndexWorkerJob[] {\n return this.agents.map((agent) => {\n const cached = loadCachedSessions(agent.name);\n if (cached) {\n return {\n kind: \"full\",\n context,\n agentName: agent.name,\n sessions: cached.sessions,\n meta: cached.meta,\n };\n }\n return {\n kind: \"full\",\n context,\n agentName: agent.name,\n sessions: this.byAgent[agent.name] ?? [],\n meta: buildAgentCacheMeta(agent),\n };\n });\n }\n\n private enqueueSearchIndexJobs(context: string, jobs: SearchIndexWorkerJob[]): Promise<void> {\n if (jobs.length === 0) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n const batch: SearchIndexJobBatch = { context, jobs, resolve, reject };\n\n if (this.searchIndexWorker) {\n this.pendingSearchIndexJobs.push(batch);\n appLogger.debug(\"search_index.worker_queued\", {\n context,\n jobs: jobs.length,\n pending_jobs: this.pendingSearchIndexJobs.length,\n });\n return;\n }\n\n this.startSearchIndexJobBatch(batch);\n });\n }\n\n private startSearchIndexJobBatch(batch: SearchIndexJobBatch): void {\n const workerUrl = this.getSearchIndexWorkerUrl();\n if (!workerUrl) {\n appLogger.warn(\"search_index.worker_missing\", { context: batch.context });\n batch.resolve();\n return;\n }\n\n let settled = false;\n const worker = new Worker(workerUrl, {\n workerData: {\n context: batch.context,\n jobs: batch.jobs,\n agentNames: [],\n sessionsByAgent: {},\n metaByAgent: {},\n },\n });\n worker.unref();\n this.searchIndexWorker = worker;\n\n worker.on(\"message\", (message: SearchIndexWorkerMessage) => {\n if (message.type === \"sync-result\") {\n logSearchIndexSync(message.context, message.result);\n } else if (message.type === \"done\") {\n appLogger.info(`${message.context}.done`, {\n duration_ms: Math.round(message.durationMs),\n sessions: message.sessions,\n });\n settled = true;\n batch.resolve();\n }\n });\n worker.on(\"error\", (error) => {\n appLogger.error(\"search_index.worker_error\", { context: batch.context, error });\n if (!settled) {\n settled = true;\n batch.reject(error);\n }\n });\n worker.on(\"exit\", (code) => {\n this.searchIndexWorker = null;\n if (code !== 0) {\n appLogger.warn(\"search_index.worker_exit\", { context: batch.context, code });\n if (!settled) {\n settled = true;\n batch.reject(new Error(`Search index worker exited with code ${code}`));\n }\n }\n if (this.pendingSearchIndexJobs.length > 0) {\n const pendingBatch = this.pendingSearchIndexJobs.shift()!;\n this.startSearchIndexJobBatch(pendingBatch);\n }\n });\n }\n\n private applyScanResult(result: ScanResult): void {\n const knownAgents = createRegisteredAgents();\n const agentMap = new Map<string, BaseAgent>();\n const allowedAgents = this.getAllowedAgents();\n\n for (const agent of result.agents) {\n agentMap.set(agent.name, agent);\n }\n for (const agent of knownAgents) {\n if (!agentMap.has(agent.name)) {\n agentMap.set(agent.name, agent);\n }\n }\n\n this.agents = [...agentMap.values()].filter((agent) => {\n if (!allowedAgents) {\n return true;\n }\n return allowedAgents.has(agent.name.toLowerCase());\n });\n\n this.byAgent = {};\n for (const agent of this.agents) {\n this.byAgent[agent.name] = sortSessions(result.byAgent[agent.name] ?? []);\n this.refreshTimestamps.set(agent.name, result.cacheTimestamps?.[agent.name] ?? Date.now());\n }\n\n this.rebuildSessions();\n }\n\n private getAllowedAgents(): Set<string> | null {\n if (!this.scanOptions.agents?.length) {\n return null;\n }\n return new Set(this.scanOptions.agents.map((agent) => agent.toLowerCase()));\n }\n\n private applyFilters(sessions: SessionHead[]): SessionHead[] {\n return filterSessions(sessions, { ...this.scanOptions, ...this.startupScanOptions });\n }\n\n private async refreshInitialIndex(): Promise<void> {\n const startedAt = performance.now();\n const context = \"scan.initial.background\";\n\n try {\n await this.enqueueSearchIndexJobs(context, this.buildFullSearchIndexJobs(context));\n appLogger.info(`${context}.complete`, {\n duration_ms: Math.round(performance.now() - startedAt),\n sessions: this.sessions.length,\n });\n } catch (error) {\n if (this.shuttingDown) {\n return;\n }\n appLogger.error(`${context}.error`, { error });\n console.error(\"[search] Background index sync failed:\", error);\n }\n }\n\n private scheduleRefresh(agentName: string, delayMs = REFRESH_DEBOUNCE_MS): void {\n appLogger.debug(\"scan.refresh.schedule\", { agent: agentName, delay_ms: delayMs });\n const existing = this.refreshTimers.get(agentName);\n if (existing) {\n clearTimeout(existing);\n }\n\n const timer = setTimeout(() => {\n this.refreshTimers.delete(agentName);\n void this.refreshAgent(agentName);\n }, delayMs);\n\n this.refreshTimers.set(agentName, timer);\n }\n\n private async refreshAgent(agentName: string): Promise<void> {\n if (this.refreshInFlight.has(agentName)) {\n appLogger.debug(\"scan.refresh.pending\", { agent: agentName });\n this.pendingRefreshes.add(agentName);\n return;\n }\n\n this.refreshInFlight.add(agentName);\n this.beginAgentScan(agentName);\n\n try {\n await this.runRefresh(agentName);\n } catch (error) {\n appLogger.error(\"scan.refresh.error\", { agent: agentName, error });\n console.error(`[${agentName}] Session refresh failed:`, error);\n } finally {\n this.refreshInFlight.delete(agentName);\n this.finishAgentScan(agentName);\n\n if (this.pendingRefreshes.delete(agentName)) {\n this.scheduleRefresh(agentName, PENDING_REFRESH_DELAY_MS);\n }\n }\n }\n\n private async runRefresh(agentName: string): Promise<void> {\n const startedAt = performance.now();\n const pendingPathCount = this.pendingRefreshPathCounts.get(agentName) ?? 0;\n this.pendingRefreshPathCounts.delete(agentName);\n const agent = this.agents.find((item) => item.name === agentName);\n if (!agent) {\n appLogger.warn(\"scan.refresh.missing_agent\", { agent: agentName });\n return;\n }\n\n const previousSessions = this.byAgent[agentName] ?? [];\n const cached = loadCachedSessions(agentName);\n const refreshBaseline = cached?.sessions ?? previousSessions;\n const cacheTimestamp = cached?.timestamp ?? this.refreshTimestamps.get(agentName) ?? 0;\n if (cached) {\n restoreAgentCacheMeta(agent, cached.meta);\n }\n const isInitialized = isAgentCacheInitialized(agentName);\n let nextSessions = previousSessions;\n let fullScanSessions: SessionHead[] | null = null;\n let preciseChangedIds: string[] | null = null;\n let usedIncrementalScan = false;\n let persistenceDiff: Pick<SessionRefreshDiff, \"changedSessions\" | \"removedSessionIds\"> | null =\n null;\n let availabilityDuration = 0;\n let checkDuration = 0;\n let scanDuration = 0;\n let filterDuration = 0;\n let diffDuration = 0;\n let persistDuration = 0;\n let searchIndexDuration = 0;\n let persistentJobKind: SearchIndexWorkerJob[\"kind\"] | undefined;\n\n const availabilityStartedAt = performance.now();\n const isAvailable = agent.isAvailable();\n availabilityDuration = performance.now() - availabilityStartedAt;\n\n if (!isAvailable) {\n nextSessions = [];\n this.refreshTimestamps.set(agentName, Date.now());\n } else if (!isInitialized) {\n this.setScanPhase(\"initializing\");\n const scanStartedAt = performance.now();\n const result = await this.scanAgentInWorker(agent, previousSessions, null, {});\n nextSessions = result.sessions;\n agent.setSessionMetaMap?.(new Map(Object.entries(result.meta)));\n fullScanSessions = attachMissingProjectIdentities(nextSessions);\n nextSessions = fullScanSessions;\n scanDuration = performance.now() - scanStartedAt;\n this.refreshTimestamps.set(agentName, Date.now());\n } else if (cached && agent instanceof FileSystemSessionSource) {\n // File-system agents refresh via precise per-source fingerprint sync.\n // Database agents lack per-file fingerprints and fall through to the\n // checkForChanges branch below.\n const scanStartedAt = performance.now();\n const result = await this.scanAgentInWorker(\n agent,\n cached.sessions,\n null,\n {},\n {\n sourceSync: true,\n meta: cached.meta,\n },\n );\n nextSessions = result.sessions;\n agent.setSessionMetaMap(new Map(Object.entries(result.meta)));\n preciseChangedIds = result.changedIds ?? [];\n usedIncrementalScan = true;\n persistenceDiff = buildRefreshDiff(\n agentName,\n cached.sessions,\n attachMissingProjectIdentities(nextSessions),\n preciseChangedIds,\n );\n scanDuration = performance.now() - scanStartedAt;\n this.refreshTimestamps.set(agentName, Date.now());\n if (preciseChangedIds.length === 0) {\n appLogger.debug(\"scan.refresh.unchanged\", {\n agent: agentName,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n }\n } else if (refreshBaseline.length > 0) {\n const checkStartedAt = performance.now();\n const checkResult = await Promise.resolve(\n agent.checkForChanges(cacheTimestamp, refreshBaseline),\n );\n checkDuration = performance.now() - checkStartedAt;\n\n this.refreshTimestamps.set(agentName, checkResult.timestamp);\n if (!checkResult.hasChanges) {\n appLogger.debug(\"scan.refresh.unchanged\", {\n agent: agentName,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return;\n }\n\n preciseChangedIds = checkResult.changedIds ?? null;\n usedIncrementalScan = Array.isArray(checkResult.changedIds);\n const scanStartedAt = performance.now();\n nextSessions = await Promise.resolve(\n agent.incrementalScan(refreshBaseline, checkResult.changedIds ?? []),\n );\n const nextBaseline = attachMissingProjectIdentities(nextSessions);\n persistenceDiff = buildRefreshDiff(\n agentName,\n refreshBaseline,\n nextBaseline,\n preciseChangedIds ?? [],\n );\n nextSessions = nextBaseline;\n scanDuration = performance.now() - scanStartedAt;\n } else {\n const scanStartedAt = performance.now();\n const result = await this.scanAgentInWorker(agent, previousSessions, null, {});\n nextSessions = result.sessions;\n agent.setSessionMetaMap(new Map(Object.entries(result.meta)));\n fullScanSessions = attachMissingProjectIdentities(nextSessions);\n nextSessions = fullScanSessions;\n scanDuration = performance.now() - scanStartedAt;\n this.refreshTimestamps.set(agentName, Date.now());\n }\n\n nextSessions = attachMissingProjectIdentities(nextSessions);\n\n const filterStartedAt = performance.now();\n nextSessions = this.applyFilters(nextSessions);\n filterDuration = performance.now() - filterStartedAt;\n const diffStartedAt = performance.now();\n const diff = buildRefreshDiff(\n agentName,\n previousSessions,\n nextSessions,\n preciseChangedIds ?? [],\n );\n diffDuration = performance.now() - diffStartedAt;\n const searchIndexOptions =\n pendingPathCount >= SEARCH_INDEX_BULK_PENDING_PATH_THRESHOLD ? { isBulk: true } : undefined;\n const canPersistIncrementally = usedIncrementalScan;\n const persistentChanges = persistenceDiff?.changedSessions ?? diff.changedSessions;\n const persistentRemovedSessionIds =\n persistenceDiff?.removedSessionIds ?? diff.removedSessionIds;\n const changedSessionIds = canPersistIncrementally\n ? new Set(persistentChanges.map(({ session }) => session.id))\n : undefined;\n const cacheMeta = buildAgentCacheMeta(agent, changedSessionIds);\n const persistStartedAt = performance.now();\n const persistentJob: SearchIndexWorkerJob | null = canPersistIncrementally\n ? {\n kind: \"changes\",\n context: \"scan.refresh\",\n agentName,\n changes: persistentChanges,\n removedSessionIds: persistentRemovedSessionIds,\n meta: cacheMeta,\n ...(searchIndexOptions ? { searchIndexOptions } : {}),\n }\n : fullScanSessions\n ? {\n kind: \"full\",\n context: \"scan.refresh\",\n agentName,\n sessions: fullScanSessions,\n meta: buildAgentCacheMeta(agent),\n saveCache: true,\n ...(searchIndexOptions ? { searchIndexOptions } : {}),\n }\n : null;\n if (persistentJob) {\n persistentJobKind = persistentJob.kind;\n const persist = this.enqueueSearchIndexJobs(\"scan.refresh\", [persistentJob]);\n if (!isInitialized && persistentJob.kind === \"full\") {\n await persist;\n } else {\n void persist.catch((error) => {\n appLogger.error(\"scan.refresh.persist.error\", { agent: agentName, error });\n console.error(`[${agentName}] Session persistence failed:`, error);\n });\n }\n }\n persistDuration = performance.now() - persistStartedAt;\n const searchIndexStartedAt = performance.now();\n searchIndexDuration = performance.now() - searchIndexStartedAt;\n logSearchIndexSync(\"scan.refresh\", null, { pending_paths: pendingPathCount });\n\n const event = diff.event;\n this.byAgent[agentName] = sortSessions(nextSessions);\n this.rebuildSessions();\n\n if (event) {\n event.totalSessions = this.sessions.length;\n this.emit(event);\n }\n appLogger.info(\"scan.refresh.done\", {\n agent: agentName,\n duration_ms: Math.round(performance.now() - startedAt),\n sessions: nextSessions.length,\n new_sessions: event?.newSessions ?? 0,\n updated_sessions: event?.updatedSessions ?? 0,\n removed_sessions: event?.removedSessions ?? 0,\n pending_paths: pendingPathCount,\n availability_ms: Math.round(availabilityDuration),\n check_ms: Math.round(checkDuration),\n scan_ms: Math.round(scanDuration),\n filter_ms: Math.round(filterDuration),\n diff_ms: Math.round(diffDuration),\n persist_ms: Math.round(persistDuration),\n search_index_ms: Math.round(searchIndexDuration),\n persistent_index_worker_job: persistentJobKind,\n persistent_index_skipped: !persistentJob || undefined,\n });\n }\n}\n","/**\n * SessionWatcher — a deep module that hides platform-specific file watching\n * (recursive watch availability, non-recursive fallback trees, write-stability\n * polling, debounce) behind a tiny interface.\n *\n * Consumers only need to know: start watching these agent names, stop, and get\n * notified (post write-stability + debounce) which agents' data changed. The\n * recursive-vs-fallback strategy, APFS mtime quirks, and path-stability polling\n * are all internal details.\n */\nimport { existsSync, readdirSync, statSync, watch, type FSWatcher } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { getCursorDataPath, resolveProviderRoots } from \"@codesesh/core\";\nimport { appLogger } from \"./logging.js\";\n\nconst WRITE_STABILITY_THRESHOLD_MS = 250;\nconst WRITE_STABILITY_POLL_MS = 100;\n\nexport interface WatchTarget {\n path: string;\n root?: string;\n}\n\ninterface WatchScope {\n agentName: string;\n targetPath: string;\n}\n\ninterface StablePathState {\n path: string;\n agentNames: Set<string>;\n lastMtimeMs: number | null;\n lastSize: number | null;\n stableSince: number;\n timer: NodeJS.Timeout | null;\n}\n\nexport type AgentsChangedListener = (agentNames: Set<string>) => void;\n\nexport function toAbsolutePath(path: string): string {\n return isAbsolute(path) ? path : resolve(path);\n}\n\nfunction closestWatchablePath(targetPath: string): string | null {\n if (!isAbsolute(targetPath) && !existsSync(targetPath)) {\n return null;\n }\n\n let current = toAbsolutePath(targetPath);\n\n while (!existsSync(current)) {\n const parent = dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n\n return current;\n}\n\nfunction getWatchRoot(path: string): string {\n const stat = statSync(path);\n return stat.isDirectory() ? path : dirname(path);\n}\n\nexport function isRecursiveWatchSupported(\n platform = process.platform,\n nodeVersion = process.versions.node,\n): boolean {\n if (platform === \"darwin\" || platform === \"win32\") {\n return true;\n }\n if (platform !== \"linux\" && platform !== \"aix\" && platform !== \"ibmi\") {\n return false;\n }\n\n const [major = 0, minor = 0] = nodeVersion.split(\".\").map((part) => Number(part));\n return major > 19 || (major === 19 && minor >= 1);\n}\n\nfunction isRecursiveWatchUnavailable(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"ERR_FEATURE_UNAVAILABLE_ON_PLATFORM\"\n );\n}\n\nfunction isSameOrChildPath(parentPath: string, childPath: string): boolean {\n const path = relative(parentPath, childPath);\n return path === \"\" || (!path.startsWith(\"..\") && !isAbsolute(path));\n}\n\nfunction isRelatedPath(changedPath: string, targetPath: string): boolean {\n return isSameOrChildPath(targetPath, changedPath) || isSameOrChildPath(changedPath, targetPath);\n}\n\nfunction mergeScopes(target: WatchScope[], scopes: WatchScope[]): void {\n for (const scope of scopes) {\n if (\n !target.some(\n (item) => item.agentName === scope.agentName && item.targetPath === scope.targetPath,\n )\n ) {\n target.push(scope);\n }\n }\n}\n\nfunction resolveWatchEventPath(watchPath: string, filename: string | Buffer | null): string {\n const filenameText = filename?.toString();\n if (!filenameText) {\n return watchPath;\n }\n return isAbsolute(filenameText) ? filenameText : join(watchPath, filenameText);\n}\n\nexport function resolveAgentWatchTargets(agentName: string): WatchTarget[] {\n const roots = resolveProviderRoots();\n const cursorDataPath = getCursorDataPath();\n\n switch (agentName) {\n case \"claudecode\":\n return [\n { root: roots.claudeRoot, path: join(roots.claudeRoot, \"projects\") },\n { path: \"data/claudecode\" },\n ];\n case \"codex\":\n return [\n { path: join(roots.codexRoot, \"sessions\") },\n { path: join(roots.codexRoot, \"session_index.jsonl\") },\n ];\n case \"pi\":\n return [\n { root: roots.piRoot, path: join(roots.piRoot, \"agent\", \"sessions\") },\n { root: \"data/pi\", path: \"data/pi\" },\n ];\n case \"cursor\":\n return cursorDataPath\n ? [\n {\n root: cursorDataPath,\n path: join(cursorDataPath, \"globalStorage\", \"state.vscdb\"),\n },\n { root: cursorDataPath, path: join(cursorDataPath, \"workspaceStorage\") },\n ]\n : [];\n case \"kimi\":\n return [\n { root: roots.kimiRoot, path: join(roots.kimiRoot, \"sessions\") },\n { path: \"data/kimi\" },\n ];\n case \"opencode\":\n return [\n { root: roots.opencodeRoot, path: join(roots.opencodeRoot, \"opencode.db\") },\n { root: \"data/opencode\", path: \"data/opencode/opencode.db\" },\n ];\n case \"zcode\":\n return roots.zcodeRoot\n ? [{ root: roots.zcodeRoot, path: join(roots.zcodeRoot, \"cli\", \"db\", \"db.sqlite\") }]\n : [];\n default:\n return [];\n }\n}\n\nexport class SessionWatcher {\n private watchers: FSWatcher[] = [];\n private fallbackWatchScopes = new Map<string, WatchScope[]>();\n private stablePaths = new Map<string, StablePathState>();\n private listeners = new Set<AgentsChangedListener>();\n\n /** Register a listener fired (after write-stability polling) with the changed agent set. */\n onAgentsChanged(cb: AgentsChangedListener): () => void {\n this.listeners.add(cb);\n return () => {\n this.listeners.delete(cb);\n };\n }\n\n /** Begin watching the given agent names' data directories. */\n start(agentNames: string[]): void {\n const scopesByRoot = new Map<string, WatchScope[]>();\n\n for (const agentName of agentNames) {\n const watchTargets = resolveAgentWatchTargets(agentName);\n\n if (watchTargets.length === 0) {\n appLogger.debug(\"watch.skip\", { agent: agentName });\n continue;\n }\n\n for (const target of watchTargets) {\n const watchRootPath = closestWatchablePath(target.root ?? target.path);\n if (!watchRootPath) continue;\n\n let rootPath: string;\n try {\n rootPath = getWatchRoot(watchRootPath);\n } catch (error) {\n this.reportWatchError(\"watch.resolve.error\", { path: watchRootPath, error });\n continue;\n }\n const targetPath = toAbsolutePath(target.path);\n const scopes = scopesByRoot.get(rootPath) ?? [];\n if (\n !scopes.some((scope) => scope.agentName === agentName && scope.targetPath === targetPath)\n ) {\n scopes.push({ agentName, targetPath });\n }\n scopesByRoot.set(rootPath, scopes);\n }\n }\n\n for (const [rootPath, scopes] of scopesByRoot.entries()) {\n const agents = Array.from(new Set(scopes.map((scope) => scope.agentName)));\n appLogger.info(\"watch.start\", {\n root: rootPath,\n agents,\n targets: scopes.map((scope) => ({\n agent: scope.agentName,\n path: scope.targetPath,\n })),\n });\n\n if (isRecursiveWatchSupported()) {\n const started = this.watchDirectory(rootPath, scopes, true);\n if (started) {\n continue;\n }\n }\n\n this.watchDirectoryTree(rootPath, scopes);\n }\n }\n\n /** Stop all watchers and clear pending stability polls. */\n async dispose(): Promise<void> {\n for (const state of this.stablePaths.values()) {\n if (state.timer) {\n clearTimeout(state.timer);\n }\n }\n this.stablePaths.clear();\n\n await Promise.all(this.watchers.map((watcher) => watcher.close()));\n this.watchers = [];\n this.fallbackWatchScopes.clear();\n this.listeners.clear();\n }\n\n private watchDirectory(path: string, scopes: WatchScope[], recursive: boolean): boolean {\n try {\n const watcher = watch(path, { recursive }, (eventType, filename) => {\n queueMicrotask(() => {\n try {\n const activeScopes = recursive\n ? scopes\n : (this.fallbackWatchScopes.get(path) ?? scopes);\n this.handleWatchEvent(path, activeScopes, eventType, filename);\n if (!recursive) {\n this.watchNewDirectories(path, filename, activeScopes);\n }\n } catch (error) {\n this.reportWatchError(\"watch.event.error\", { path, recursive, error });\n }\n });\n });\n\n watcher.on(\"error\", (error) => {\n this.reportWatchError(\"watch.error\", { path, recursive, error });\n });\n\n this.watchers.push(watcher);\n return true;\n } catch (error) {\n if (recursive && isRecursiveWatchUnavailable(error)) {\n appLogger.warn(\"watch.recursive_unavailable\", { path, error });\n return false;\n }\n\n this.reportWatchError(\"watch.start.error\", { path, recursive, error });\n return false;\n }\n }\n\n private watchDirectoryTree(rootPath: string, scopes: WatchScope[]): void {\n const pending = [rootPath];\n\n while (pending.length > 0) {\n const dirPath = pending.pop()!;\n this.watchFallbackDirectory(dirPath, scopes);\n\n try {\n for (const entry of readdirSync(dirPath, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n pending.push(join(dirPath, entry.name));\n }\n }\n } catch (error) {\n this.reportWatchError(\"watch.scan.error\", { path: dirPath, error });\n }\n }\n }\n\n private watchFallbackDirectory(path: string, scopes: WatchScope[]): void {\n const existingScopes = this.fallbackWatchScopes.get(path);\n if (existingScopes) {\n mergeScopes(existingScopes, scopes);\n return;\n }\n\n const storedScopes = [...scopes];\n this.fallbackWatchScopes.set(path, storedScopes);\n if (!this.watchDirectory(path, storedScopes, false)) {\n this.fallbackWatchScopes.delete(path);\n }\n }\n\n private watchNewDirectories(\n watchPath: string,\n filename: string | Buffer | null,\n scopes: WatchScope[],\n ): void {\n const path = resolveWatchEventPath(watchPath, filename);\n try {\n if (statSync(path).isDirectory()) {\n this.watchDirectoryTree(path, scopes);\n }\n } catch {}\n }\n\n private handleWatchEvent(\n watchPath: string,\n scopes: WatchScope[],\n eventType: string,\n filename: string | Buffer | null,\n ): void {\n const changedPath = resolveWatchEventPath(watchPath, filename);\n const agentNames = new Set(\n scopes\n .filter((scope) => isRelatedPath(changedPath, scope.targetPath))\n .map((scope) => scope.agentName),\n );\n\n if (agentNames.size === 0) {\n return;\n }\n\n appLogger.debug(\"watch.event\", {\n event: eventType,\n path: changedPath,\n agents: Array.from(agentNames),\n });\n this.waitForStablePath(changedPath, agentNames);\n }\n\n private waitForStablePath(path: string, agentNames: Set<string>): void {\n const existing = this.stablePaths.get(path);\n if (existing) {\n for (const agentName of agentNames) {\n existing.agentNames.add(agentName);\n }\n return;\n }\n\n const state: StablePathState = {\n path,\n agentNames: new Set(agentNames),\n lastMtimeMs: null,\n lastSize: null,\n stableSince: Date.now(),\n timer: null,\n };\n this.stablePaths.set(path, state);\n this.pollStablePath(path);\n }\n\n private pollStablePath(path: string): void {\n const state = this.stablePaths.get(path);\n if (!state) {\n return;\n }\n\n let size: number;\n let mtimeMs: number;\n try {\n const stat = statSync(path);\n size = stat.size;\n mtimeMs = stat.mtimeMs;\n } catch {\n this.stablePaths.delete(path);\n this.emitAgentsChanged(state.agentNames);\n return;\n }\n\n const now = Date.now();\n const unchanged = state.lastSize === size && state.lastMtimeMs === mtimeMs;\n if (!unchanged) {\n state.lastSize = size;\n state.lastMtimeMs = mtimeMs;\n state.stableSince = now;\n }\n\n if (unchanged && now - state.stableSince >= WRITE_STABILITY_THRESHOLD_MS) {\n this.stablePaths.delete(path);\n this.emitAgentsChanged(state.agentNames);\n return;\n }\n\n state.timer = setTimeout(() => this.pollStablePath(path), WRITE_STABILITY_POLL_MS);\n }\n\n private emitAgentsChanged(agentNames: Set<string>): void {\n if (agentNames.size === 0) return;\n for (const listener of this.listeners) {\n listener(new Set(agentNames));\n }\n }\n\n private reportWatchError(event: string, data: Record<string, unknown>): void {\n appLogger.error(event, data);\n console.error(\"[watch] File watcher failed:\", data.error);\n }\n}\n","import { consola } from \"consola\";\nimport type { BaseAgent } from \"@codesesh/core\";\nimport { VERSION } from \"./version.js\";\n\nexport function printScanResults(agents: BaseAgent[]): void {\n consola.log(\"\");\n consola.box({\n title: \"CodeSesh\",\n message: `v${VERSION} • local session browser`,\n style: {\n padding: 1,\n borderColor: \"cyan\",\n },\n });\n consola.log(\"\");\n consola.info(\n `Indexing ${agents.map((agent) => agent.displayName).join(\", \")} sessions in the background.`,\n );\n consola.info(\"The Web UI will update automatically as sessions are discovered.\");\n consola.log(\"\");\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(resolve(__dirname, \"../package.json\"), \"utf-8\"));\n\nexport const VERSION = pkg.version;\n","export const DEFAULT_PORT = 4521;\nexport const DEFAULT_PORT_FALLBACK_ATTEMPTS = 20;\n\nexport function parsePort(value: string | undefined): number {\n const port = parseInt(value ?? \"\", 10);\n return Number.isNaN(port) ? DEFAULT_PORT : port;\n}\n\nexport function hasExplicitPortArg(argv: string[]): boolean {\n return argv.some((arg, index) => {\n if (arg === \"--port\" || arg === \"-p\") return index < argv.length - 1;\n return arg.startsWith(\"--port=\") || /^-p\\d+$/.test(arg);\n });\n}\n"],"mappings":"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","names":["Hono","existsSync","__dirname","existsSync","resolve","Hono","url","existsSync","fileURLToPath","existsSync","readdirSync","statSync","dirname","join","resolve","resolve","existsSync","dirname","statSync","join","readdirSync","existsSync","fileURLToPath","resolve","resolve","dirname","fileURLToPath"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/api/routes.ts","../src/logging.ts","../src/api/handlers.ts","../src/live-scan.ts","../src/session-watcher.ts","../src/output.ts","../src/version.ts","../src/ports.ts"],"sourcesContent":["import { defineCommand, runMain } from \"citty\";\nimport { createServer, getServerStartupErrorMessage } from \"./server.js\";\nimport { LiveScanStore } from \"./live-scan.js\";\nimport { printScanResults } from \"./output.js\";\nimport { VERSION } from \"./version.js\";\nimport { appLogger } from \"./logging.js\";\nimport {\n DEFAULT_PORT,\n DEFAULT_PORT_FALLBACK_ATTEMPTS,\n hasExplicitPortArg,\n parsePort,\n} from \"./ports.js\";\nimport {\n createRegisteredAgents,\n getAgentInfoMap,\n refreshPricingCache,\n type ScanOptions,\n perf,\n} from \"@codesesh/core\";\n\nfunction parseDateToTimestamp(dateStr: string): number {\n const date = new Date(dateStr);\n if (Number.isNaN(date.getTime())) {\n throw new Error(`Invalid date: ${dateStr}`);\n }\n return date.getTime();\n}\n\nfunction parseSessionUri(uri: string): { agent: string; sessionId: string } | null {\n const match = uri.match(/^([a-z]+):\\/\\/(.+)$/i);\n if (!match) return null;\n return { agent: match[1]!, sessionId: match[2]! };\n}\n\nconst main = defineCommand({\n meta: {\n name: \"codesesh\",\n description: \"Discover, aggregate, and visualize AI coding agent sessions\",\n version: VERSION,\n },\n args: {\n port: {\n type: \"string\",\n alias: \"p\",\n description: \"HTTP server port\",\n default: String(DEFAULT_PORT),\n },\n host: {\n type: \"string\",\n description: \"HTTP server bind address (default 127.0.0.1, local access only)\",\n default: \"127.0.0.1\",\n },\n agent: {\n type: \"string\",\n alias: \"a\",\n description: \"Filter to specific agent(s), comma-separated\",\n },\n days: {\n type: \"string\",\n alias: \"d\",\n description: \"Only include sessions active in the last N days (0 = all time)\",\n default: \"7\",\n },\n cwd: {\n type: \"string\",\n description: \"Filter to sessions from a specific project directory (use '.' for current dir)\",\n },\n from: {\n type: \"string\",\n description: \"Sessions active after this date, YYYY-MM-DD (overrides --days)\",\n },\n to: {\n type: \"string\",\n description: \"Sessions active before this date (YYYY-MM-DD)\",\n },\n session: {\n type: \"string\",\n alias: \"s\",\n description: \"Directly open a specific session (agent://session-id)\",\n },\n json: {\n type: \"boolean\",\n alias: \"j\",\n description: \"Output session index as JSON to stdout (no server)\",\n default: false,\n },\n noOpen: {\n type: \"boolean\",\n description: \"Don't auto-open browser\",\n default: false,\n },\n trace: {\n type: \"boolean\",\n description: \"Show performance trace logs\",\n default: false,\n },\n cache: {\n type: \"boolean\",\n description: \"Use cached scan results if available\",\n default: true,\n },\n \"clear-cache\": {\n type: \"boolean\",\n description: \"Clear scan cache before starting\",\n default: false,\n },\n },\n async run({ args }) {\n const startedAt = performance.now();\n const port = parsePort(args.port as string | undefined);\n const explicitPort = hasExplicitPortArg(process.argv.slice(2));\n const noOpen = args.noOpen as boolean;\n const jsonOnly = args.json as boolean;\n const trace = args.trace as boolean;\n const useCache = args.cache as boolean;\n const clearCache = args[\"clear-cache\"] as boolean;\n\n if (trace) {\n perf.enable();\n }\n\n appLogger.info(\"cli.start\", {\n version: VERSION,\n argv: process.argv.slice(2),\n port,\n json: jsonOnly,\n no_open: noOpen,\n cache: useCache,\n log_path: appLogger.getLogPath(),\n });\n\n if (clearCache) {\n const { clearCache: clear } = await import(\"@codesesh/core\");\n clear();\n appLogger.info(\"cache.clear\");\n console.log(\"Cache cleared.\");\n }\n\n void refreshPricingCache();\n\n // Parse session URI if provided\n let targetSession: { agent: string; sessionId: string } | null = null;\n if (args.session) {\n targetSession = parseSessionUri(args.session as string);\n if (!targetSession) {\n console.error(`Invalid session format: ${args.session}. Expected: agent://session-id`);\n process.exit(1);\n }\n }\n\n // Resolve cwd filter: '.' => process.cwd()\n let cwdFilter = args.cwd as string | undefined;\n if (cwdFilter === \".\") {\n cwdFilter = process.cwd();\n }\n\n // Resolve app-level default window (shared across /api/agents, /sessions, /dashboard).\n // Priority: --from (absolute) over --days (relative).\n let listDefaultFrom: number | undefined;\n let listDefaultDays: number | undefined;\n if (args.from) {\n listDefaultFrom = parseDateToTimestamp(args.from as string);\n } else {\n const days = parseInt(args.days as string, 10);\n if (!Number.isNaN(days) && days > 0) {\n listDefaultFrom = Date.now() - days * 24 * 60 * 60 * 1000;\n listDefaultDays = days;\n } else if (days === 0) {\n listDefaultDays = 0;\n }\n }\n const listDefaultTo = args.to ? parseDateToTimestamp(args.to as string) : undefined;\n\n const scanOptions: ScanOptions = {\n agents: targetSession\n ? [targetSession.agent]\n : args.agent\n ? (args.agent as string).split(\",\").map((a) => a.trim())\n : undefined,\n cwd: cwdFilter,\n useCache: useCache,\n };\n const startupScanOptions =\n targetSession || jsonOnly ? {} : { from: listDefaultFrom, to: listDefaultTo };\n\n const store = new LiveScanStore(!jsonOnly, scanOptions, startupScanOptions, {\n deferInitialRefresh: !jsonOnly,\n });\n await store.initialize();\n const result = store.getSnapshot();\n appLogger.info(\"cli.scan_ready\", {\n duration_ms: Math.round(performance.now() - startedAt),\n sessions: result.sessions.length,\n agents: Object.fromEntries(\n Object.entries(result.byAgent).map(([key, value]) => [key, value.length]),\n ),\n startup_from: startupScanOptions.from,\n startup_to: startupScanOptions.to,\n });\n\n if (trace) {\n console.log(perf.getReport());\n }\n\n if (jsonOnly) {\n // Apply --days/--from/--to window to the JSON output so CLI semantics are preserved.\n const windowed = result.sessions.filter((s) => {\n const activity = s.time_updated ?? s.time_created;\n if (listDefaultFrom != null && activity < listDefaultFrom) return false;\n if (listDefaultTo != null && activity > listDefaultTo) return false;\n return true;\n });\n const info = getAgentInfoMap(\n Object.fromEntries(Object.entries(result.byAgent).map(([k, v]) => [k, v.length])),\n );\n const output = {\n agents: info.map(({ name, displayName, count }) => ({\n name,\n displayName,\n count,\n available: count > 0,\n })),\n sessions: windowed,\n };\n appLogger.info(\"cli.json_output\", {\n sessions: windowed.length,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n console.log(JSON.stringify(output, null, 2));\n return;\n }\n\n // Print console output\n const agents = createRegisteredAgents();\n printScanResults(agents);\n\n // Start server\n let app: Awaited<ReturnType<typeof createServer>>;\n try {\n app = await createServer(port, store, {\n defaultSessionFrom: listDefaultFrom,\n defaultSessionTo: listDefaultTo,\n defaultSessionDays: listDefaultDays,\n portFallbackAttempts: explicitPort ? 1 : DEFAULT_PORT_FALLBACK_ATTEMPTS,\n hostname: args.host as string,\n });\n } catch (error) {\n console.error(getServerStartupErrorMessage(error, port));\n process.exit(1);\n }\n\n const { url } = app;\n if (!jsonOnly) {\n store.startBackgroundRefresh();\n }\n let shuttingDown = false;\n const shutdown = async (signal: NodeJS.Signals) => {\n if (shuttingDown) return;\n shuttingDown = true;\n appLogger.info(\"cli.shutdown\", { signal });\n await app.shutdown();\n process.exit(0);\n };\n process.once(\"SIGINT\", (signal) => {\n void shutdown(signal);\n });\n process.once(\"SIGTERM\", (signal) => {\n void shutdown(signal);\n });\n\n console.log(` ${url}`);\n console.log(\"\");\n appLogger.info(\"cli.ready\", {\n url,\n duration_ms: Math.round(performance.now() - startedAt),\n log_path: appLogger.getLogPath(),\n });\n\n if (!noOpen) {\n const open = (await import(\"open\")).default;\n const targetUrl = targetSession\n ? `${url}/${targetSession.agent.toLowerCase()}/${targetSession.sessionId}`\n : url;\n appLogger.info(\"browser.open\", { url: targetUrl });\n await open(targetUrl);\n }\n },\n});\n\nif (process.argv.slice(2).includes(\"-v\")) {\n console.log(VERSION);\n process.exit(0);\n}\n\nrunMain(main);\n","import { Hono } from \"hono\";\nimport { serve } from \"@hono/node-server\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { existsSync } from \"node:fs\";\nimport type { Server } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { ScanResultSource } from \"./api/handlers.js\";\nimport { createApiRoutes, type ApiRouteOptions } from \"./api/routes.js\";\nimport { LiveScanStore } from \"./live-scan.js\";\nimport { appLogger } from \"./logging.js\";\n\nexport interface CreateServerOptions {\n defaultSessionFrom?: number;\n defaultSessionTo?: number;\n defaultSessionDays?: number;\n portFallbackAttempts?: number;\n hostname?: string;\n}\n\nfunction findWebDistPath(): string | null {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n // Priority 1: Packaged web dist (copied during build)\n const packagedPath = resolve(__dirname, \"web\");\n if (existsSync(packagedPath)) {\n return packagedPath;\n }\n\n // Priority 2: Development path (monorepo)\n const devPath = resolve(__dirname, \"../../../apps/web/dist\");\n if (existsSync(devPath)) {\n return devPath;\n }\n\n return null;\n}\n\nfunction waitForListening(server: Server): Promise<void> {\n return new Promise((resolve, reject) => {\n const handleListening = () => {\n server.off(\"error\", handleError);\n resolve();\n };\n const handleError = (error: Error) => {\n server.off(\"listening\", handleListening);\n reject(error);\n };\n\n server.once(\"listening\", handleListening);\n server.once(\"error\", handleError);\n });\n}\n\nexport function getServerStartupErrorMessage(error: unknown, port: number): string {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"EADDRINUSE\"\n ) {\n return `Port ${port} 已被占用,请关闭现有 CodeSesh 进程或改用 --port 指定其他端口。`;\n }\n\n return error instanceof Error ? error.message : `启动服务器失败: ${String(error)}`;\n}\n\nfunction isAddressInUse(error: unknown): boolean {\n return (\n typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"EADDRINUSE\"\n );\n}\n\nfunction getListeningPort(server: Server, fallback: number): number {\n const address = server.address();\n return typeof address === \"object\" && address !== null ? (address as AddressInfo).port : fallback;\n}\n\nexport async function createServer(\n port: number,\n store: ScanResultSource &\n Partial<\n Pick<LiveScanStore, \"getScanStatus\" | \"subscribe\" | \"subscribeScanStatus\" | \"shutdown\">\n >,\n options: CreateServerOptions = {},\n): Promise<{ url: string; shutdown: () => Promise<void> }> {\n const app = new Hono();\n\n app.use(\"*\", async (c, next) => {\n const startedAt = performance.now();\n let thrown: unknown;\n\n try {\n await next();\n } catch (error) {\n thrown = error;\n throw error;\n } finally {\n const url = new URL(c.req.url);\n appLogger.info(\"http.request\", {\n method: c.req.method,\n path: url.pathname,\n query_keys: [...url.searchParams.keys()].toSorted(),\n status: c.res.status,\n duration_ms: Math.round(performance.now() - startedAt),\n error: thrown instanceof Error ? thrown.message : undefined,\n });\n }\n });\n\n // API routes\n const routeOptions: ApiRouteOptions = {\n defaultSessionFrom: options.defaultSessionFrom,\n defaultSessionTo: options.defaultSessionTo,\n defaultSessionDays: options.defaultSessionDays,\n };\n app.route(\n \"/api\",\n createApiRoutes(\n store,\n \"subscribe\" in store ? (store as LiveScanStore) : undefined,\n routeOptions,\n ),\n );\n\n // Serve static files from web dist (if available)\n const webDistPath = findWebDistPath();\n\n if (webDistPath) {\n app.use(\"/*\", serveStatic({ root: webDistPath }));\n app.get(\"/*\", serveStatic({ root: webDistPath, path: \"index.html\" }));\n }\n\n const attempts = Math.max(1, options.portFallbackAttempts ?? 1);\n const hostname = options.hostname ?? \"127.0.0.1\";\n let server: Server | null = null;\n let actualPort = port;\n\n for (let offset = 0; offset < attempts; offset += 1) {\n const candidatePort = port + offset;\n server = serve({ fetch: app.fetch, port: candidatePort, hostname });\n\n try {\n await waitForListening(server);\n actualPort = getListeningPort(server, candidatePort);\n break;\n } catch (error) {\n appLogger.error(\"server.listen.error\", { port: candidatePort, error });\n server.close();\n\n if (isAddressInUse(error) && offset < attempts - 1) {\n continue;\n }\n\n if (store.shutdown) {\n await store.shutdown();\n }\n\n if (isAddressInUse(error) && attempts > 1) {\n throw new Error(\n `端口 ${port}-${port + attempts - 1} 均已被占用,请关闭现有进程或改用 --port 指定其他端口。`,\n );\n }\n\n throw new Error(getServerStartupErrorMessage(error, candidatePort));\n }\n }\n\n const isLoopback = hostname === \"127.0.0.1\" || hostname === \"localhost\";\n const url = isLoopback ? `http://localhost:${actualPort}` : `http://${hostname}:${actualPort}`;\n appLogger.info(\"server.listen\", { port: actualPort, requested_port: port, hostname, url });\n\n if (!isLoopback) {\n appLogger.warn(\"server.listen.exposed\", { hostname, port: actualPort });\n console.warn(\n `\\n⚠ 服务监听 ${hostname},局域网内其他设备可读取你的全部 AI 会话记录(无鉴权)。\\n`,\n );\n }\n\n return {\n url,\n shutdown: async () => {\n appLogger.info(\"server.shutdown\", { port: actualPort });\n await new Promise<void>((resolve) => {\n if (!server) {\n resolve();\n return;\n }\n server.close(() => resolve());\n });\n if (store.shutdown) {\n await store.shutdown();\n }\n },\n };\n}\n","import { Hono } from \"hono\";\nimport {\n handleGetAgents,\n handleGetBookmarks,\n handleGetConfig,\n handleGetDashboard,\n handleGetFileActivity,\n handleGetProjects,\n handleGetScanStatus,\n handleDeleteBookmark,\n handleImportBookmarks,\n handlePostClientLog,\n handleSearchSessions,\n handleGetSessions,\n handleGetSessionData,\n handlePutBookmark,\n type ScanResultSource,\n type SessionListDefaults,\n} from \"./handlers.js\";\nimport type { LiveScanStore } from \"../live-scan.js\";\n\nexport interface ApiRouteOptions {\n defaultSessionFrom?: number;\n defaultSessionTo?: number;\n defaultSessionDays?: number;\n}\n\nfunction createSseResponse(store: LiveScanStore, signal: AbortSignal): Response {\n const encoder = new TextEncoder();\n\n return new Response(\n new ReadableStream({\n start(controller) {\n const write = (event: string, data: unknown) => {\n controller.enqueue(encoder.encode(`event: ${event}\\n`));\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\\n\\n`));\n };\n\n write(\"connected\", { timestamp: Date.now() });\n write(\"scan-status\", store.getScanStatus());\n\n const unsubscribeSessions = store.subscribe((event) => {\n write(event.type, event);\n });\n const unsubscribeScanStatus = store.subscribeScanStatus((event) => {\n write(event.type, event);\n });\n\n const heartbeat = setInterval(() => {\n controller.enqueue(encoder.encode(\": keepalive\\n\\n\"));\n }, 15000);\n\n const close = () => {\n clearInterval(heartbeat);\n unsubscribeSessions();\n unsubscribeScanStatus();\n controller.close();\n };\n\n signal.addEventListener(\"abort\", close, { once: true });\n },\n cancel() {\n return;\n },\n }),\n {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n },\n },\n );\n}\n\nexport function createApiRoutes(\n scanSource: ScanResultSource,\n store?: LiveScanStore,\n options: ApiRouteOptions = {},\n): Hono {\n const api = new Hono();\n const listDefaults: SessionListDefaults = {\n from: options.defaultSessionFrom,\n to: options.defaultSessionTo,\n days: options.defaultSessionDays,\n };\n\n api.get(\"/config\", (c) => handleGetConfig(c, listDefaults));\n if (store) {\n api.get(\"/status\", (c) => handleGetScanStatus(c, store));\n }\n api.get(\"/agents\", (c) => handleGetAgents(c, scanSource, listDefaults));\n api.get(\"/projects\", (c) => handleGetProjects(c, scanSource, listDefaults));\n api.get(\"/sessions\", (c) => handleGetSessions(c, scanSource, listDefaults));\n api.get(\"/search\", (c) => handleSearchSessions(c, scanSource, listDefaults));\n api.get(\"/file-activity\", (c) => handleGetFileActivity(c, listDefaults));\n api.get(\"/sessions/:agent/:id\", (c) => handleGetSessionData(c, scanSource));\n api.get(\"/dashboard\", (c) => handleGetDashboard(c, scanSource, listDefaults));\n api.get(\"/bookmarks\", (c) => handleGetBookmarks(c));\n api.put(\"/bookmarks\", (c) => handlePutBookmark(c));\n api.post(\"/bookmarks/import\", (c) => handleImportBookmarks(c));\n api.delete(\"/bookmarks/:agent/:id\", (c) => handleDeleteBookmark(c));\n api.post(\"/logs\", (c) => handlePostClientLog(c));\n if (store) {\n api.get(\"/events\", (c) => createSseResponse(store, c.req.raw.signal));\n }\n\n return api;\n}\n","import {\n appendFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { SearchIndexSyncResult } from \"@codesesh/core\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LEVEL_WEIGHT: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\n\nexport interface LoggerOptions {\n logDir?: string;\n level?: LogLevel;\n maxBytes?: number;\n maxFiles?: number;\n}\n\nfunction parseLevel(value: string | undefined): LogLevel {\n if (value === \"debug\" || value === \"info\" || value === \"warn\" || value === \"error\") {\n return value;\n }\n return \"info\";\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;\n}\n\nfunction getDefaultLogDir(): string {\n const base = process.env.XDG_CACHE_HOME ?? join(homedir(), \".cache\");\n return join(base, \"codesesh\", \"logs\");\n}\n\nfunction toLogValue(value: unknown, depth = 0): unknown {\n if (value == null || typeof value === \"string\" || typeof value === \"number\") return value;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"bigint\") return value.toString();\n if (value instanceof Error) {\n return {\n name: value.name,\n message: value.message,\n stack: value.stack,\n };\n }\n if (depth >= 4) return \"[truncated]\";\n if (Array.isArray(value)) return value.slice(0, 50).map((item) => toLogValue(item, depth + 1));\n if (typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, item]) => [\n key,\n toLogValue(item, depth + 1),\n ]),\n );\n }\n return String(value);\n}\n\nfunction timestampForFile(date = new Date()): string {\n return date.toISOString().replace(/[:.]/g, \"-\");\n}\n\nexport class AppLogger {\n private readonly logDir: string;\n private readonly level: LogLevel;\n private readonly maxBytes: number;\n private readonly maxFiles: number;\n private readonly currentPath: string;\n private rotationIndex = 0;\n\n constructor(options: LoggerOptions = {}) {\n this.logDir = options.logDir ?? process.env.CODESESH_LOG_DIR ?? getDefaultLogDir();\n this.level = options.level ?? parseLevel(process.env.CODESESH_LOG_LEVEL);\n this.maxBytes =\n options.maxBytes ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_BYTES, 5_000_000);\n this.maxFiles = options.maxFiles ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_FILES, 5);\n this.currentPath = join(this.logDir, \"codesesh.log\");\n }\n\n getLogPath(): string {\n return this.currentPath;\n }\n\n debug(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"debug\", event, data);\n }\n\n info(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"info\", event, data);\n }\n\n warn(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"warn\", event, data);\n }\n\n error(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"error\", event, data);\n }\n\n private write(level: LogLevel, event: string, data: Record<string, unknown>): void {\n if (LEVEL_WEIGHT[level] < LEVEL_WEIGHT[this.level]) return;\n\n try {\n mkdirSync(this.logDir, { recursive: true });\n const line = `${JSON.stringify({\n ts: new Date().toISOString(),\n level,\n event,\n pid: process.pid,\n ...toLogValue(data),\n })}\\n`;\n this.rotateIfNeeded(Buffer.byteLength(line));\n appendFileSync(this.currentPath, line, \"utf8\");\n } catch {}\n }\n\n private rotateIfNeeded(nextBytes: number): void {\n if (!existsSync(this.currentPath)) {\n this.removeExpiredLogs();\n return;\n }\n\n const currentSize = statSync(this.currentPath).size;\n if (currentSize + nextBytes <= this.maxBytes) return;\n\n this.rotationIndex += 1;\n const rotatedPath = join(\n this.logDir,\n `codesesh-${timestampForFile()}-${process.pid}-${this.rotationIndex}.log`,\n );\n renameSync(this.currentPath, rotatedPath);\n this.removeExpiredLogs();\n }\n\n private removeExpiredLogs(): void {\n const rotated = readdirSync(this.logDir)\n .filter((name) => /^codesesh-.+\\.log$/.test(name))\n .map((name) => {\n const path = join(this.logDir, name);\n return { path, mtimeMs: statSync(path).mtimeMs };\n })\n .toSorted((a, b) => b.mtimeMs - a.mtimeMs);\n\n for (const item of rotated.slice(Math.max(0, this.maxFiles - 1))) {\n unlinkSync(item.path);\n }\n }\n}\n\nexport const appLogger = new AppLogger();\n\nexport function logSearchIndexSync(\n context: string,\n result: SearchIndexSyncResult | null,\n data: Record<string, unknown> = {},\n): void {\n if (!result || result.mode !== \"bulk\" || result.rebuildDurationMs == null) {\n return;\n }\n\n appLogger.info(\"search_index.sync\", {\n context,\n agent: result.agentName,\n mode: result.mode,\n sessions: result.sessions,\n changed: result.changed,\n deleted: result.deleted,\n indexed: result.indexed,\n skipped: result.skipped,\n duration_ms: Math.round(result.durationMs),\n rebuild_duration_ms: Math.round(result.rebuildDurationMs),\n ...data,\n });\n}\n","import type { Context } from \"hono\";\nimport type {\n BookmarkRecord,\n ProjectGroup,\n ScanResult,\n SessionData,\n SessionHead,\n SmartTag,\n} from \"@codesesh/core\";\nimport {\n BookmarkStorageUnavailableError,\n createProjectScopeMatcher,\n deleteBookmark,\n getAgentInfoMap,\n classifySessionTags,\n computeIdentity,\n extractSessionFileActivity,\n getSmartTagSourceTimestamp,\n importBookmarks,\n loadCachedSessionData,\n listFileActivity,\n listSessionFileActivity,\n listCachedProjectGroups,\n listBookmarks,\n parseSearchQuery,\n realFs,\n searchFileActivitySessions,\n searchSessions,\n upsertBookmark,\n matchesProjectScope as sessionMatchesProjectScope,\n buildDashboard,\n getSessionAgentName,\n getSessionActivityTime,\n getTotalTokens,\n startOfLocalDay,\n type DashboardData,\n type DashboardScope,\n type FileActivityKind,\n type ProjectScopeMatcher,\n type SearchMatchType,\n type SearchOptions,\n type SearchQueryFilters,\n} from \"@codesesh/core\";\nimport { appLogger } from \"../logging.js\";\n\nexport interface ScanResultSource {\n getSnapshot(): ScanResult;\n}\n\nexport interface ScanStatusSource {\n getScanStatus(): {\n type: \"scan-status\";\n active: boolean;\n phase: \"idle\" | \"indexing\" | \"initializing\" | \"scanning\";\n pendingAgents: string[];\n scanningAgents: string[];\n completedAgents: string[];\n agentStatuses: Record<\n string,\n {\n agentName: string;\n status: \"pending\" | \"scanning\" | \"complete\";\n total?: number;\n processed?: number;\n sessions?: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n }\n >;\n totalAgents: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n backfill: {\n active: boolean;\n pendingAgents: string[];\n currentAgent?: string;\n completedAgents: string[];\n };\n };\n}\n\nexport interface SessionListDefaults {\n from?: number;\n to?: number;\n /** When --days was used, original value — kept for UI \"last N days\" label */\n days?: number;\n}\n\ninterface ClientLogPayload {\n event?: unknown;\n data?: unknown;\n}\n\ninterface ApiSearchResult {\n agentName: string;\n session: SessionHead;\n snippet: string;\n matchType: SearchMatchType;\n}\n\ninterface ApiProjectAgentStat {\n name: string;\n sessions: number;\n messages: number;\n tokens: number;\n cost: number;\n}\n\ninterface ApiProjectGroup extends ProjectGroup {\n messages: number;\n tokens: number;\n cost: number;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"];\n agentStats: ApiProjectAgentStat[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isSessionStats(value: unknown): value is SessionHead[\"stats\"] {\n if (!isRecord(value)) return false;\n return (\n typeof value.message_count === \"number\" &&\n typeof value.total_input_tokens === \"number\" &&\n typeof value.total_output_tokens === \"number\" &&\n typeof value.total_cost === \"number\" &&\n (value.total_tokens == null || typeof value.total_tokens === \"number\")\n );\n}\n\nfunction parseBookmarkPayload(value: unknown): Omit<BookmarkRecord, \"bookmarked_at\"> | null {\n if (!isRecord(value)) return null;\n if (\n typeof value.agentKey !== \"string\" ||\n typeof value.sessionId !== \"string\" ||\n typeof value.fullPath !== \"string\" ||\n typeof value.title !== \"string\" ||\n typeof value.directory !== \"string\" ||\n typeof value.time_created !== \"number\" ||\n (value.time_updated != null && typeof value.time_updated !== \"number\") ||\n !isSessionStats(value.stats)\n ) {\n return null;\n }\n\n return {\n agentKey: value.agentKey,\n sessionId: value.sessionId,\n fullPath: value.fullPath,\n title: value.title,\n directory: value.directory,\n time_created: value.time_created,\n time_updated: value.time_updated,\n stats: value.stats,\n };\n}\n\nfunction parseDateParam(\n value: string | undefined,\n fallback: number | undefined,\n): number | undefined {\n if (value == null) return fallback;\n const ts = new Date(value).getTime();\n return Number.isNaN(ts) ? fallback : ts;\n}\n\nfunction parseNumberParam(value: string | undefined): number | undefined {\n if (value == null || !value.trim()) return undefined;\n const number = Number(value);\n return Number.isFinite(number) ? number : undefined;\n}\n\nfunction searchParams(c: Context): URLSearchParams {\n return new URL(c.req.url ?? \"http://localhost/\", \"http://localhost/\").searchParams;\n}\n\nfunction queryValues(params: URLSearchParams, ...names: string[]): string[] {\n return names.flatMap((name) =>\n params\n .getAll(name)\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter(Boolean),\n );\n}\n\nfunction parseSmartTags(values: string[]): SmartTag[] | undefined {\n const tags = values\n .map((value) => value.toLowerCase())\n .filter((value): value is SmartTag =>\n [\n \"bugfix\",\n \"refactoring\",\n \"feature-dev\",\n \"testing\",\n \"docs\",\n \"git-ops\",\n \"build-deploy\",\n \"exploration\",\n \"planning\",\n ].includes(value),\n );\n return tags.length > 0 ? [...new Set(tags)] : undefined;\n}\n\nfunction parseSearchOptions(c: Context, defaults: SessionListDefaults): SearchOptions {\n const params = searchParams(c);\n const limitValue = parseNumberParam(params.get(\"limit\") ?? undefined);\n return {\n agent: optionalQueryValue(params.get(\"agent\") ?? undefined),\n project: optionalQueryValue(params.get(\"project\") ?? undefined),\n projectKey: optionalQueryValue(params.get(\"projectKey\") ?? undefined),\n cwd: optionalQueryValue(params.get(\"cwd\") ?? undefined),\n tags: parseSmartTags(queryValues(params, \"tag\", \"tags\", \"signal\")),\n tools: queryValues(params, \"tool\", \"tools\").map((tool) => tool.toLowerCase()),\n file: optionalQueryValue(params.get(\"file\") ?? params.get(\"path\") ?? undefined),\n fileKind: parseFileActivityKind(\n optionalQueryValue(params.get(\"fileKind\") ?? params.get(\"fileActivity\") ?? undefined),\n ),\n costMin: parseNumberParam(params.get(\"costMin\") ?? undefined),\n costMax: parseNumberParam(params.get(\"costMax\") ?? undefined),\n from: parseDateParam(params.get(\"from\") ?? undefined, defaults.from),\n to: parseDateParam(params.get(\"to\") ?? undefined, defaults.to),\n limit: limitValue && limitValue > 0 ? Math.min(limitValue, 100) : 50,\n };\n}\n\nfunction filterSessionsByWindow(\n sessions: SessionHead[],\n from: number | undefined,\n to: number | undefined,\n): SessionHead[] {\n return filterSessionsByActivityWindow(sessions, from, to);\n}\n\nfunction filterSessionsByActivityWindow(\n sessions: SessionHead[],\n from: number | undefined,\n to: number | undefined,\n): SessionHead[] {\n if (from == null && to == null) return sessions;\n return sessions.filter((session) => {\n const activity = getSessionActivityTime(session);\n if (from != null && activity < from) return false;\n if (to != null && activity > to) return false;\n return true;\n });\n}\n\nfunction sanitizeClientLogData(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) return {};\n\n return Object.fromEntries(\n Object.entries(value)\n .slice(0, 30)\n .map(([key, item]) => {\n if (typeof item === \"string\") return [key, item.slice(0, 300)];\n if (typeof item === \"number\" || typeof item === \"boolean\" || item == null) {\n return [key, item];\n }\n return [key, String(item).slice(0, 300)];\n }),\n );\n}\n\nfunction sessionMatchesCostFilter(session: SessionHead, options: SearchOptions): boolean {\n const cost = session.stats.total_cost;\n if (options.costMin != null) {\n if (options.costMinExclusive ? cost <= options.costMin : cost < options.costMin) return false;\n }\n if (options.costMax != null) {\n if (options.costMaxExclusive ? cost >= options.costMax : cost > options.costMax) return false;\n }\n return true;\n}\n\nfunction mergeSearchLists<T>(left: T[] | undefined, right: T[] | undefined): T[] | undefined {\n const values = [...(left ?? []), ...(right ?? [])];\n return values.length > 0 ? [...new Set(values)] : undefined;\n}\n\nfunction mergeSearchOptions(options: SearchOptions, filters: SearchQueryFilters): SearchOptions {\n return {\n ...options,\n agent: options.agent ?? filters.agent,\n project: options.project ?? filters.project,\n projectKey: options.projectKey ?? filters.projectKey,\n cwd: options.cwd ?? filters.cwd,\n tags: mergeSearchLists(options.tags, filters.tags),\n tools: mergeSearchLists(options.tools, filters.tools),\n file: options.file ?? filters.file,\n fileKind: options.fileKind ?? filters.fileKind,\n costMin: options.costMin ?? filters.costMin,\n costMax: options.costMax ?? filters.costMax,\n costMinExclusive: options.costMinExclusive ?? filters.costMinExclusive,\n costMaxExclusive: options.costMaxExclusive ?? filters.costMaxExclusive,\n };\n}\n\nfunction mergeSearchResults(results: ApiSearchResult[], limit: number): ApiSearchResult[] {\n const seen = new Set<string>();\n const merged: ApiSearchResult[] = [];\n\n for (const result of results) {\n const key = `${result.agentName}/${result.session.id}`;\n if (seen.has(key)) continue;\n seen.add(key);\n merged.push(result);\n if (merged.length >= limit) break;\n }\n\n return merged;\n}\n\nfunction getProjectGroupKey(identityKind: string, identityKey: string): string {\n return `${identityKind}:${identityKey}`;\n}\n\nfunction attachProjectMetrics(\n projects: ProjectGroup[],\n sessions: SessionHead[],\n): ApiProjectGroup[] {\n const metrics = new Map<\n string,\n {\n messages: number;\n tokens: number;\n cost: number;\n hasEstimatedCost: boolean;\n agentStats: Map<string, ApiProjectAgentStat>;\n }\n >();\n\n for (const session of sessions) {\n const identity = session.project_identity;\n if (!identity) continue;\n const key = getProjectGroupKey(identity.kind, identity.key);\n let current = metrics.get(key);\n if (!current) {\n current = {\n messages: 0,\n tokens: 0,\n cost: 0,\n hasEstimatedCost: false,\n agentStats: new Map(),\n };\n metrics.set(key, current);\n }\n\n const tokens = getTotalTokens(session.stats);\n const cost = session.stats.total_cost ?? 0;\n current.messages += session.stats.message_count;\n current.tokens += tokens;\n current.cost += cost;\n if (session.stats.cost_source === \"estimated\") current.hasEstimatedCost = true;\n\n const agentName = getSessionAgentName(session);\n const agent = current.agentStats.get(agentName);\n if (agent) {\n agent.sessions += 1;\n agent.messages += session.stats.message_count;\n agent.tokens += tokens;\n agent.cost += cost;\n } else {\n current.agentStats.set(agentName, {\n name: agentName,\n sessions: 1,\n messages: session.stats.message_count,\n tokens,\n cost,\n });\n }\n }\n\n return projects.map((project) => {\n const metric = metrics.get(getProjectGroupKey(project.identityKind, project.identityKey));\n return {\n ...project,\n messages: metric?.messages ?? 0,\n tokens: metric?.tokens ?? 0,\n cost: metric?.cost ?? 0,\n cost_source:\n metric && metric.cost > 0\n ? metric.hasEstimatedCost\n ? \"estimated\"\n : \"recorded\"\n : undefined,\n agentStats: [...(metric?.agentStats.values() ?? [])].sort((a, b) => b.sessions - a.sessions),\n };\n });\n}\n\nfunction matchesRecentSearchFilters(\n session: SessionHead,\n options: SearchOptions,\n projectScope: ProjectScopeMatcher | null,\n): boolean {\n if (options.projectKey && session.project_identity?.key !== options.projectKey) return false;\n if (projectScope && !sessionMatchesProjectScope(session, projectScope)) return false;\n if (options.project) {\n const projectNeedle = options.project.toLowerCase();\n const projectText = [\n session.project_identity?.key,\n session.project_identity?.displayName,\n session.directory,\n ]\n .filter(Boolean)\n .join(\"\\n\")\n .toLowerCase();\n if (!projectText.includes(projectNeedle)) return false;\n }\n if (options.tags?.length && !options.tags.every((tag) => session.smart_tags?.includes(tag))) {\n return false;\n }\n if (!sessionMatchesCostFilter(session, options)) return false;\n return true;\n}\n\nfunction recentSearchSessions(\n scanResult: ScanResult,\n options: SearchOptions & { limit: number },\n): ApiSearchResult[] {\n const projectScope = options.cwd ? createProjectScopeMatcher(options.cwd) : null;\n const entries = options.agent\n ? ([[options.agent, scanResult.byAgent[options.agent] ?? []]] as Array<[string, SessionHead[]]>)\n : Object.entries(scanResult.byAgent);\n\n return entries\n .flatMap(([agentName, sessions]) =>\n filterSessionsByActivityWindow(sessions, options.from, options.to)\n .filter((session) => matchesRecentSearchFilters(session, options, projectScope))\n .map((session) => ({ agentName, session })),\n )\n .toSorted(\n (a, b) =>\n (b.session.time_updated ?? b.session.time_created) -\n (a.session.time_updated ?? a.session.time_created),\n )\n .slice(0, options.limit)\n .map(({ agentName, session }) => ({\n agentName,\n session,\n snippet: `Recent session · ${session.directory}`,\n matchType: \"recent\",\n }));\n}\n\nexport function handleGetConfig(c: Context, defaults: SessionListDefaults) {\n return c.json({\n window: {\n from: defaults.from,\n to: defaults.to,\n days: defaults.days,\n },\n });\n}\n\nexport function handleGetScanStatus(c: Context, scanSource: ScanStatusSource) {\n return c.json(scanSource.getScanStatus());\n}\n\nexport function handleGetAgents(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const { from, to } = defaults;\n const counts = Object.fromEntries(\n Object.entries(scanResult.byAgent).map(([agentName, sessions]) => [\n agentName,\n filterSessionsByWindow(sessions, from, to).length,\n ]),\n );\n const info = getAgentInfoMap(counts).filter((agent) => agent.count > 0);\n return c.json(info);\n}\n\nexport function handleGetProjects(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const { from, to } = defaults;\n const sessions = filterSessionsByActivityWindow(scanResult.sessions, from, to);\n return c.json({\n projects: attachProjectMetrics(listCachedProjectGroups(sessions), sessions),\n });\n}\n\nexport function handleGetSessions(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const agent = c.req.query(\"agent\");\n const q = c.req.query(\"q\")?.toLowerCase();\n const cwd = c.req.query(\"cwd\");\n const projectKey = c.req.query(\"projectKey\");\n const tag = c.req.query(\"tag\")?.toLowerCase();\n const from = parseDateParam(c.req.query(\"from\"), defaults.from);\n const to = parseDateParam(c.req.query(\"to\"), defaults.to);\n\n let sessions: SessionHead[] = [];\n\n // If agent filter is specified, use byAgent directly\n if (agent && scanResult.byAgent[agent]) {\n sessions = [...scanResult.byAgent[agent]!];\n } else {\n sessions = [...scanResult.sessions];\n }\n\n if (projectKey) {\n sessions = sessions.filter((s) => s.project_identity?.key === projectKey);\n } else if (cwd) {\n const projectScope = createProjectScopeMatcher(cwd);\n sessions = sessions.filter((s) => sessionMatchesProjectScope(s, projectScope));\n }\n sessions = filterSessionsByActivityWindow(sessions, from, to);\n if (tag) {\n sessions = sessions.filter((s) => s.smart_tags?.includes(tag as SmartTag));\n }\n\n if (q) {\n sessions = sessions.filter((s) => s.title.toLowerCase().includes(q));\n }\n\n return c.json({ sessions });\n}\n\nexport function handleSearchSessions(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const query = c.req.query(\"q\")?.trim() ?? \"\";\n const scanResult = scanSource.getSnapshot();\n const searchOptions = parseSearchOptions(c, defaults);\n const parsedQuery = parseSearchQuery(query);\n const mergedSearchOptions = mergeSearchOptions(searchOptions, parsedQuery.filters);\n const textQuery = parsedQuery.text || (parsedQuery.hasQualifiers ? \"\" : query);\n const needsIndexedSearch = Boolean(\n textQuery ||\n mergedSearchOptions.file ||\n mergedSearchOptions.fileKind ||\n mergedSearchOptions.tools?.length,\n );\n\n if (!needsIndexedSearch) {\n return c.json({\n results: recentSearchSessions(\n scanResult,\n mergedSearchOptions as SearchOptions & { limit: number },\n ),\n });\n }\n\n const fileQuery =\n mergedSearchOptions.file ??\n (!parsedQuery.text ? parsedQuery.filters.file : undefined) ??\n (!parsedQuery.hasQualifiers && query ? parsedQuery.text || query : \"\");\n const results: ApiSearchResult[] = mergeSearchResults(\n [\n ...(fileQuery ? searchFileActivitySessions(fileQuery, mergedSearchOptions) : []),\n ...searchSessions(query, mergedSearchOptions),\n ],\n mergedSearchOptions.limit ?? 50,\n );\n\n return c.json({ results });\n}\n\nfunction parseFileActivityKind(value: string | undefined): FileActivityKind | undefined {\n if (value === \"read\" || value === \"edit\" || value === \"write\" || value === \"delete\") {\n return value;\n }\n return undefined;\n}\n\nfunction optionalQueryValue(value: string | undefined): string | undefined {\n const normalized = value?.trim();\n return normalized ? normalized : undefined;\n}\n\nexport function handleGetFileActivity(c: Context, defaults: SessionListDefaults = {}) {\n const limitValue = Number(c.req.query(\"limit\"));\n const limit = Number.isFinite(limitValue) && limitValue > 0 ? Math.min(limitValue, 200) : 50;\n\n return c.json({\n activity: listFileActivity({\n agent: optionalQueryValue(c.req.query(\"agent\")),\n sessionId: optionalQueryValue(c.req.query(\"sessionId\")),\n projectKey: optionalQueryValue(c.req.query(\"projectKey\")),\n project: optionalQueryValue(c.req.query(\"project\")),\n cwd: optionalQueryValue(c.req.query(\"cwd\")),\n path: optionalQueryValue(c.req.query(\"path\")),\n kind: parseFileActivityKind(optionalQueryValue(c.req.query(\"kind\"))),\n from: parseDateParam(c.req.query(\"from\"), defaults.from),\n to: parseDateParam(c.req.query(\"to\"), defaults.to),\n limit,\n }),\n });\n}\n\nexport async function handleGetSessionData(c: Context, scanSource: ScanResultSource) {\n const startedAt = performance.now();\n const scanResult = scanSource.getSnapshot();\n const agentName = c.req.param(\"agent\");\n const sessionId = c.req.param(\"id\");\n\n if (!sessionId) {\n return c.json({ error: \"Missing session ID\" }, 400);\n }\n\n const agent = scanResult.agents.find((a) => a.name === agentName);\n\n if (!agent) {\n return c.json({ error: `Unknown agent: ${agentName}` }, 404);\n }\n\n try {\n const head = scanResult.byAgent[agentName]?.find((item) => item.id === sessionId);\n const loadStartedAt = performance.now();\n const cachedData = loadCachedSessionData(agentName, sessionId);\n const cachedMessageCount = cachedData?.stats.message_count ?? 0;\n const cacheHasExpectedMessages =\n cachedData !== null && (cachedData.messages.length > 0 || cachedMessageCount === 0);\n const data: SessionData | null = cacheHasExpectedMessages\n ? cachedData\n : head\n ? agent.getSessionData(sessionId)\n : null;\n const loadDuration = performance.now() - loadStartedAt;\n if (!data) {\n appLogger.warn(\"api.session_data.cache_miss\", {\n agent: agentName,\n session_id: sessionId,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return c.json({ error: \"Session cache not ready\" }, 404);\n }\n const tagStartedAt = performance.now();\n const smartTags = data.smart_tags ?? classifySessionTags(data);\n const tagDuration = performance.now() - tagStartedAt;\n const projectIdentity =\n data.project_identity ?? head?.project_identity ?? computeIdentity(data.directory, realFs);\n const fileActivity =\n data.file_activity ??\n (cacheHasExpectedMessages && cachedData\n ? listSessionFileActivity(agentName, sessionId)\n : extractSessionFileActivity(agentName, sessionId, projectIdentity.key, data.messages));\n appLogger.info(\"api.session_data\", {\n agent: agentName,\n session_id: sessionId,\n messages: data.messages.length,\n load_duration_ms: Math.round(loadDuration),\n tag_duration_ms: Math.round(tagDuration),\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return c.json({\n ...data,\n project_identity: projectIdentity,\n smart_tags: smartTags,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n file_activity: fileActivity,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Failed to load session\";\n appLogger.error(\"api.session_data.error\", {\n agent: agentName,\n session_id: sessionId,\n duration_ms: Math.round(performance.now() - startedAt),\n error: message,\n });\n return c.json({ error: message }, 500);\n }\n}\n\nexport async function handlePostClientLog(c: Context) {\n const payload = (await c.req.json().catch(() => null)) as ClientLogPayload | null;\n const rawEvent = payload?.event;\n\n if (typeof rawEvent !== \"string\" || !rawEvent.trim()) {\n return c.json({ ok: false }, 400);\n }\n\n const event = rawEvent\n .trim()\n .replace(/[^a-zA-Z0-9_.:-]/g, \"_\")\n .slice(0, 120);\n appLogger.info(`client.${event}`, sanitizeClientLogData(payload?.data));\n return c.json({ ok: true });\n}\n\nexport function handleGetBookmarks(c: Context) {\n try {\n return c.json({ bookmarks: listBookmarks(), storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ bookmarks: [], storageAvailable: false });\n }\n throw error;\n }\n}\n\nexport async function handlePutBookmark(c: Context) {\n const payload = parseBookmarkPayload(await c.req.json().catch(() => null));\n if (!payload) {\n return c.json({ error: \"Invalid bookmark payload\" }, 400);\n }\n\n try {\n return c.json({ bookmark: upsertBookmark(payload), storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ error: \"Bookmark storage is unavailable\" }, 503);\n }\n throw error;\n }\n}\n\nexport async function handleImportBookmarks(c: Context) {\n const payload = await c.req.json().catch(() => null);\n if (!Array.isArray(payload)) {\n return c.json({ error: \"Invalid bookmark payload\" }, 400);\n }\n\n const bookmarks = payload\n .map((entry) => parseBookmarkPayload(entry))\n .filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n\n if (bookmarks.length !== payload.length) {\n return c.json({ error: \"Invalid bookmark payload\" }, 400);\n }\n\n try {\n return c.json({ bookmarks: importBookmarks(bookmarks), storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ error: \"Bookmark storage is unavailable\" }, 503);\n }\n throw error;\n }\n}\n\nexport function handleDeleteBookmark(c: Context) {\n const agentKey = c.req.param(\"agent\");\n const sessionId = c.req.param(\"id\");\n if (!agentKey || !sessionId) {\n return c.json({ error: \"Missing bookmark identifier\" }, 400);\n }\n\n try {\n deleteBookmark(agentKey, sessionId);\n return c.json({ ok: true, storageAvailable: true });\n } catch (error) {\n if (error instanceof BookmarkStorageUnavailableError) {\n return c.json({ error: \"Bookmark storage is unavailable\" }, 503);\n }\n throw error;\n }\n}\n\nfunction resolveDashboardWindow(\n defaults: SessionListDefaults,\n queryDays: string | undefined,\n queryFrom: string | undefined,\n queryTo: string | undefined,\n): { from?: number; to: number; days?: number } {\n const now = Date.now();\n\n const toTs = parseDateParam(queryTo, defaults.to) ?? now;\n\n // Resolve days (preferred): query, defaults.days, or derive from defaults.from\n const hasQueryDays = queryDays != null && queryDays.trim() !== \"\";\n const parsedDays = hasQueryDays ? parseInt(queryDays, 10) : NaN;\n let days: number | undefined =\n Number.isFinite(parsedDays) && parsedDays > 0 ? parsedDays : defaults.days;\n\n const fromFromQuery = parseDateParam(queryFrom, undefined);\n let fromTs: number;\n if (fromFromQuery != null) {\n fromTs = fromFromQuery;\n days ??= Math.max(1, Math.ceil((toTs - fromTs) / 86400000));\n } else if (parsedDays === 0 || (!hasQueryDays && defaults.days === 0)) {\n days = 0;\n return { to: toTs, days };\n } else if (defaults.from != null) {\n fromTs = defaults.from;\n days ??= Math.max(1, Math.ceil((toTs - fromTs) / 86400000));\n } else if (days && days > 0) {\n fromTs = startOfLocalDay(toTs) - (days - 1) * 86400000;\n } else {\n days = 30;\n fromTs = startOfLocalDay(toTs) - (days - 1) * 86400000;\n }\n\n return { from: fromTs, to: toTs, days };\n}\n\nexport function handleGetDashboard(\n c: Context,\n scanSource: ScanResultSource,\n defaults: SessionListDefaults = {},\n) {\n const scanResult = scanSource.getSnapshot();\n const { from, to, days } = resolveDashboardWindow(\n defaults,\n c.req.query(\"days\"),\n c.req.query(\"from\"),\n c.req.query(\"to\"),\n );\n const scope: DashboardScope = {\n agent: optionalQueryValue(c.req.query(\"agent\"))?.toLowerCase(),\n projectKind: optionalQueryValue(c.req.query(\"projectKind\")),\n projectKey: optionalQueryValue(c.req.query(\"projectKey\")),\n };\n\n const agentInfo = getAgentInfoMap({});\n const agentInfoMap = new Map(agentInfo.map((a) => [a.name, a]));\n\n const aggregate = buildDashboard(scanResult.sessions, {\n byAgentNames: Object.keys(scanResult.byAgent),\n scope,\n from,\n to,\n agentInfoMap,\n });\n\n const data: DashboardData = {\n ...aggregate,\n recentFileActivities: listFileActivity({\n agent: scope.agent,\n projectKey: scope.projectKey,\n from,\n to,\n limit: 12,\n }),\n window: { from, to, days },\n };\n\n return c.json(data);\n}\n","import { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport {\n createRegisteredAgents,\n filterSessions,\n getAgentLastFullSyncAt,\n isAgentCacheInitialized,\n loadCachedSessions,\n markAgentFullSyncCompleted,\n scanSessions,\n FileSystemSessionSource,\n attachMissingProjectIdentities,\n buildAgentCacheMeta,\n computeSessionDiff,\n sessionSignature,\n sortSessions,\n type AgentScanProgress,\n type BaseAgent,\n type ScanResult,\n type ScanOptions,\n type SessionCacheMeta,\n type SessionHeadChange,\n type SessionHead,\n} from \"@codesesh/core\";\nimport type { SearchIndexWorkerJob, SearchIndexWorkerMessage } from \"./search-index-worker.js\";\nimport type { ScanRefreshWorkerMessage } from \"./scan-refresh-worker.js\";\nimport { SessionWatcher, resolveAgentWatchTargets } from \"./session-watcher.js\";\n\nexport { resolveAgentWatchTargets };\nimport { appLogger, logSearchIndexSync } from \"./logging.js\";\n\nexport interface SessionsUpdatedEvent {\n type: \"sessions-updated\";\n changedAgents: string[];\n newSessions: number;\n updatedSessions: number;\n removedSessions: number;\n totalSessions: number;\n timestamp: number;\n changedSessionHeads: Array<{ agentName: string; session: SessionHead }>;\n removedSessionRefs: Array<{ agentName: string; sessionId: string }>;\n}\n\nexport interface ScanStatusEvent {\n type: \"scan-status\";\n active: boolean;\n phase: \"idle\" | \"indexing\" | \"initializing\" | \"scanning\";\n pendingAgents: string[];\n scanningAgents: string[];\n completedAgents: string[];\n agentStatuses: Record<string, AgentScanStatus>;\n totalAgents: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n backfill: BackfillStatus;\n}\n\n/**\n * Full-history reconciliation runs independently of the main scan phase above:\n * startup only syncs the display window, so a low-priority background pass\n * (capped at one agent at a time) periodically re-checks the rest of history.\n */\nexport interface BackfillStatus {\n active: boolean;\n pendingAgents: string[];\n currentAgent?: string;\n completedAgents: string[];\n}\n\nexport interface AgentScanStatus {\n agentName: string;\n status: \"pending\" | \"scanning\" | \"complete\";\n total?: number;\n processed?: number;\n sessions?: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n}\n\ntype StoreListener = (event: SessionsUpdatedEvent) => void;\ntype ScanStatusListener = (event: ScanStatusEvent) => void;\n\ninterface SessionRefreshDiff {\n event: SessionsUpdatedEvent | null;\n changedSessions: SessionHeadChange[];\n removedSessionIds: string[];\n}\n\ninterface SearchIndexJobBatch {\n context: string;\n jobs: SearchIndexWorkerJob[];\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\ninterface LiveScanStoreOptions {\n deferInitialRefresh?: boolean;\n}\n\ninterface AgentRefreshState {\n timer: NodeJS.Timeout | null;\n /** Absolute time the pending timer is due to fire; lets scheduleRefresh throttle instead of debounce. */\n timerDeadline: number;\n inFlight: boolean;\n pendingRerun: boolean;\n lastRefreshAt: number;\n lastRefreshDurationMs: number;\n pendingPathCount: number;\n}\n\nconst REFRESH_DEBOUNCE_MS = 200;\nconst EMPTY_AGENT_REFRESH_DEBOUNCE_MS = 30_000;\nconst PENDING_REFRESH_DELAY_MS = 100;\n/** Cap on the adaptive backoff so a single expensive scan can't stall refreshes indefinitely. */\nconst MAX_ADAPTIVE_REFRESH_DELAY_MS = 30_000;\n/** Space refreshes out to roughly 4x their own cost, so a slow agent doesn't dominate the event loop. */\nconst ADAPTIVE_REFRESH_DELAY_MULTIPLIER = 4;\nconst NEW_SESSION_EVENT_WINDOW_MS = 250;\nconst SEARCH_INDEX_BULK_PENDING_PATH_THRESHOLD = 100;\n/** Old files rarely change, but it's not impossible — reconcile full history at most this often. */\nconst BACKFILL_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\nfunction buildRefreshDiff(\n agentName: string,\n previousSessions: SessionHead[],\n nextSessions: SessionHead[],\n candidateChangedIds: string[] = [],\n): SessionRefreshDiff {\n const { changes, removedSessionIds, counts } = computeSessionDiff(\n previousSessions,\n nextSessions,\n candidateChangedIds,\n sessionSignature,\n );\n\n if (counts.new === 0 && counts.updated === 0 && counts.removed === 0) {\n return { event: null, changedSessions: changes, removedSessionIds };\n }\n\n return {\n changedSessions: changes,\n removedSessionIds,\n event: {\n type: \"sessions-updated\",\n changedAgents: [agentName],\n newSessions: counts.new,\n updatedSessions: counts.updated,\n removedSessions: counts.removed,\n totalSessions: nextSessions.length,\n timestamp: Date.now(),\n changedSessionHeads: changes.map(({ session }) => ({ agentName, session })),\n removedSessionRefs: removedSessionIds.map((sessionId) => ({ agentName, sessionId })),\n },\n };\n}\n\nfunction restoreAgentCacheMeta(agent: BaseAgent, meta: Record<string, SessionCacheMeta>): void {\n agent.setSessionMetaMap(new Map(Object.entries(meta)));\n}\n\nfunction mergeEvents(\n previous: SessionsUpdatedEvent,\n next: SessionsUpdatedEvent,\n): SessionsUpdatedEvent {\n const changedSessionHeads = new Map<string, { agentName: string; session: SessionHead }>();\n const removedSessionRefs = new Map<string, { agentName: string; sessionId: string }>();\n const sessionKey = (agentName: string, sessionId: string) => `${agentName}\\0${sessionId}`;\n const addChanged = (item: { agentName: string; session: SessionHead }) => {\n const key = sessionKey(item.agentName, item.session.id);\n removedSessionRefs.delete(key);\n changedSessionHeads.set(key, item);\n };\n const addRemoved = (item: { agentName: string; sessionId: string }) => {\n const key = sessionKey(item.agentName, item.sessionId);\n changedSessionHeads.delete(key);\n removedSessionRefs.set(key, item);\n };\n\n for (const item of previous.changedSessionHeads) addChanged(item);\n for (const item of previous.removedSessionRefs) addRemoved(item);\n for (const item of next.changedSessionHeads) addChanged(item);\n for (const item of next.removedSessionRefs) addRemoved(item);\n\n return {\n type: \"sessions-updated\",\n changedAgents: Array.from(new Set([...previous.changedAgents, ...next.changedAgents])),\n newSessions: previous.newSessions + next.newSessions,\n updatedSessions: previous.updatedSessions + next.updatedSessions,\n removedSessions: previous.removedSessions + next.removedSessions,\n totalSessions: next.totalSessions,\n timestamp: next.timestamp,\n changedSessionHeads: [...changedSessionHeads.values()],\n removedSessionRefs: [...removedSessionRefs.values()],\n };\n}\n\nexport class LiveScanStore {\n private agents: BaseAgent[] = [];\n private byAgent: Record<string, SessionHead[]> = {};\n private sessions: SessionHead[] = [];\n private listeners = new Set<StoreListener>();\n private scanStatusListeners = new Set<ScanStatusListener>();\n private scanStatus: Omit<ScanStatusEvent, \"type\"> = {\n active: false,\n phase: \"idle\",\n pendingAgents: [],\n scanningAgents: [],\n completedAgents: [],\n agentStatuses: {},\n totalAgents: 0,\n updatedAt: Date.now(),\n backfill: { active: false, pendingAgents: [], completedAgents: [] },\n };\n private backfillQueue: string[] = [];\n private backfillRunning = false;\n private refreshStates = new Map<string, AgentRefreshState>();\n private watcher: SessionWatcher | null = null;\n private pendingEvent: SessionsUpdatedEvent | null = null;\n private pendingEventTimer: NodeJS.Timeout | null = null;\n private backgroundRefreshTimer: NodeJS.Timeout | null = null;\n private searchIndexWorker: Worker | null = null;\n private pendingSearchIndexJobs: SearchIndexJobBatch[] = [];\n private shuttingDown = false;\n /** Set once a search-index worker in this process has completed the FTS integrity check. */\n private ftsIntegrityChecked = false;\n\n constructor(\n private readonly watchEnabled = true,\n private readonly scanOptions: ScanOptions = {},\n private readonly startupScanOptions: Pick<ScanOptions, \"from\" | \"to\"> = {},\n private readonly storeOptions: LiveScanStoreOptions = {},\n ) {}\n\n private getRefreshState(agentName: string): AgentRefreshState {\n let state = this.refreshStates.get(agentName);\n if (!state) {\n state = {\n timer: null,\n timerDeadline: 0,\n inFlight: false,\n pendingRerun: false,\n lastRefreshAt: 0,\n lastRefreshDurationMs: 0,\n pendingPathCount: 0,\n };\n this.refreshStates.set(agentName, state);\n }\n return state;\n }\n\n async initialize(): Promise<void> {\n const startedAt = performance.now();\n const deferInitialRefresh = this.storeOptions.deferInitialRefresh === true;\n appLogger.info(\"scan.initial.start\", {\n watch_enabled: this.watchEnabled,\n agents: this.scanOptions.agents,\n use_cache: this.scanOptions.useCache ?? true,\n startup_from: this.startupScanOptions.from,\n startup_to: this.startupScanOptions.to,\n deferred: deferInitialRefresh || undefined,\n });\n const initialResult = await scanSessions({\n ...this.scanOptions,\n ...(deferInitialRefresh ? this.startupScanOptions : {}),\n useCache: this.scanOptions.useCache ?? true,\n smartRefresh: false,\n cacheOnly: deferInitialRefresh,\n writeCache: deferInitialRefresh ? false : this.scanOptions.writeCache,\n smartTagWorkerUrl: this.getSmartTagWorkerUrl() ?? undefined,\n includeSmartTags: deferInitialRefresh ? false : undefined,\n });\n this.applyScanResult(initialResult);\n const indexStartedAt = performance.now();\n if (!deferInitialRefresh) {\n await this.enqueueSearchIndexJobs(\n \"scan.initial\",\n this.buildFullSearchIndexJobs(\"scan.initial\"),\n );\n }\n const indexDuration = performance.now() - indexStartedAt;\n appLogger.info(\"scan.initial.done\", {\n duration_ms: Math.round(performance.now() - startedAt),\n index_ms: deferInitialRefresh ? undefined : Math.round(indexDuration),\n deferred: deferInitialRefresh || undefined,\n sessions: this.sessions.length,\n agents: Object.fromEntries(\n Object.entries(this.byAgent).map(([key, value]) => [key, value.length]),\n ),\n agent_timings: initialResult.timings\n ? Object.fromEntries(\n Object.entries(initialResult.timings).map(([name, t]) => [\n name,\n {\n total_ms: Math.round(t.total),\n cache_load_ms: t.cacheLoad != null ? Math.round(t.cacheLoad) : undefined,\n check_changes_ms: t.checkChanges != null ? Math.round(t.checkChanges) : undefined,\n scan_ms: t.scan != null ? Math.round(t.scan) : undefined,\n identity_ms: t.identity != null ? Math.round(t.identity) : undefined,\n tags_ms: t.tags != null ? Math.round(t.tags) : undefined,\n },\n ]),\n )\n : undefined,\n });\n if (this.watchEnabled) {\n this.watcher = new SessionWatcher();\n this.watcher.onAgentsChanged((agentNames) => {\n for (const agentName of agentNames) {\n this.getRefreshState(agentName).pendingPathCount += 1;\n const delayMs =\n (this.byAgent[agentName]?.length ?? 0) === 0\n ? EMPTY_AGENT_REFRESH_DEBOUNCE_MS\n : REFRESH_DEBOUNCE_MS;\n this.scheduleRefresh(agentName, delayMs);\n }\n });\n this.watcher.start(this.agents.map((agent) => agent.name));\n }\n }\n\n startBackgroundRefresh(): void {\n if (this.backgroundRefreshTimer) {\n return;\n }\n const agentNames = this.agents.map((agent) => agent.name);\n this.startScanBatch(agentNames, \"scanning\");\n this.backgroundRefreshTimer = setTimeout(() => {\n this.backgroundRefreshTimer = null;\n for (const agentName of agentNames) {\n this.scheduleRefresh(agentName, 0);\n }\n if (agentNames.length === 0) {\n this.finishScanBatch();\n }\n for (const agent of this.agents) {\n if (this.needsBackfill(agent)) {\n this.enqueueBackfill(agent.name);\n }\n }\n }, 0);\n }\n\n getSnapshot(): ScanResult {\n return {\n sessions: this.sessions,\n byAgent: this.byAgent,\n agents: this.agents,\n };\n }\n\n getScanStatus(): ScanStatusEvent {\n return {\n type: \"scan-status\",\n ...this.scanStatus,\n pendingAgents: [...this.scanStatus.pendingAgents],\n scanningAgents: [...this.scanStatus.scanningAgents],\n completedAgents: [...this.scanStatus.completedAgents],\n agentStatuses: Object.fromEntries(\n Object.entries(this.scanStatus.agentStatuses).map(([agentName, status]) => [\n agentName,\n { ...status },\n ]),\n ),\n backfill: {\n ...this.scanStatus.backfill,\n pendingAgents: [...this.scanStatus.backfill.pendingAgents],\n completedAgents: [...this.scanStatus.backfill.completedAgents],\n },\n };\n }\n\n subscribe(listener: StoreListener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n subscribeScanStatus(listener: ScanStatusListener): () => void {\n this.scanStatusListeners.add(listener);\n return () => {\n this.scanStatusListeners.delete(listener);\n };\n }\n\n async shutdown(): Promise<void> {\n this.shuttingDown = true;\n for (const state of this.refreshStates.values()) {\n if (state.timer) {\n clearTimeout(state.timer);\n state.timer = null;\n state.timerDeadline = 0;\n }\n }\n\n if (this.pendingEventTimer) {\n clearTimeout(this.pendingEventTimer);\n this.pendingEventTimer = null;\n }\n if (this.backgroundRefreshTimer) {\n clearTimeout(this.backgroundRefreshTimer);\n this.backgroundRefreshTimer = null;\n }\n if (this.searchIndexWorker) {\n await this.searchIndexWorker.terminate();\n this.searchIndexWorker = null;\n }\n for (const batch of this.pendingSearchIndexJobs) {\n batch.reject(new Error(\"Live scan store shut down\"));\n }\n this.pendingSearchIndexJobs = [];\n this.pendingEvent = null;\n\n if (this.watcher) {\n await this.watcher.dispose();\n this.watcher = null;\n }\n }\n\n private emit(event: SessionsUpdatedEvent): void {\n if (this.pendingEvent || event.newSessions > 0) {\n this.queueEvent(event);\n return;\n }\n\n this.emitNow(event);\n }\n\n private emitNow(event: SessionsUpdatedEvent): void {\n for (const listener of this.listeners) {\n listener(event);\n }\n }\n\n private emitScanStatus(): void {\n const event = this.getScanStatus();\n for (const listener of this.scanStatusListeners) {\n listener(event);\n }\n }\n\n private updateScanStatus(next: Omit<ScanStatusEvent, \"type\">): void {\n this.scanStatus = next;\n this.emitScanStatus();\n }\n\n private startScanBatch(agentNames: string[], phase: ScanStatusEvent[\"phase\"]): void {\n const uniqueAgentNames = [...new Set(agentNames)];\n const now = Date.now();\n const agentStatuses = Object.fromEntries(\n uniqueAgentNames.map((agentName) => [\n agentName,\n {\n agentName,\n status: \"pending\" as const,\n processed: 0,\n sessions: this.byAgent[agentName]?.length ?? 0,\n updatedAt: now,\n },\n ]),\n );\n this.updateScanStatus({\n ...this.scanStatus,\n active: uniqueAgentNames.length > 0,\n phase: uniqueAgentNames.length > 0 ? phase : \"idle\",\n pendingAgents: uniqueAgentNames,\n scanningAgents: [],\n completedAgents: [],\n agentStatuses,\n totalAgents: uniqueAgentNames.length,\n startedAt: uniqueAgentNames.length > 0 ? now : undefined,\n updatedAt: now,\n completedAt: uniqueAgentNames.length > 0 ? undefined : now,\n });\n }\n\n private setScanPhase(phase: ScanStatusEvent[\"phase\"]): void {\n if (!this.scanStatus.active) return;\n this.updateScanStatus({\n ...this.scanStatus,\n phase,\n updatedAt: Date.now(),\n });\n }\n\n private beginAgentScan(agentName: string): void {\n if (!this.scanStatus.active) {\n this.startScanBatch([agentName], \"scanning\");\n }\n\n const pendingAgents = this.scanStatus.pendingAgents.filter((agent) => agent !== agentName);\n const scanningAgents = [...new Set([...this.scanStatus.scanningAgents, agentName])];\n const completedAgents = this.scanStatus.completedAgents.filter((agent) => agent !== agentName);\n const existingStatus = this.scanStatus.agentStatuses[agentName];\n const agentStatuses = {\n ...this.scanStatus.agentStatuses,\n [agentName]: {\n agentName,\n status: \"scanning\" as const,\n total: existingStatus?.total,\n processed: existingStatus?.processed ?? 0,\n sessions: existingStatus?.sessions ?? this.byAgent[agentName]?.length ?? 0,\n startedAt: existingStatus?.startedAt ?? Date.now(),\n updatedAt: Date.now(),\n },\n };\n this.updateScanStatus({\n ...this.scanStatus,\n active: true,\n phase: this.scanStatus.phase === \"initializing\" ? \"initializing\" : \"scanning\",\n pendingAgents,\n scanningAgents,\n completedAgents,\n agentStatuses,\n totalAgents: Math.max(\n this.scanStatus.totalAgents,\n pendingAgents.length + scanningAgents.length,\n ),\n updatedAt: Date.now(),\n completedAt: undefined,\n });\n }\n\n private updateAgentScanProgress(agentName: string, progress: AgentScanProgress): void {\n const status = this.scanStatus.agentStatuses[agentName];\n if (!status || status.status !== \"scanning\") return;\n this.updateScanStatus({\n ...this.scanStatus,\n agentStatuses: {\n ...this.scanStatus.agentStatuses,\n [agentName]: {\n ...status,\n total: progress.total ?? status.total,\n processed: progress.processed ?? status.processed,\n sessions: progress.sessions ?? status.sessions,\n updatedAt: Date.now(),\n },\n },\n updatedAt: Date.now(),\n });\n }\n\n private finishAgentScan(agentName: string): void {\n const pendingAgents = this.scanStatus.pendingAgents.filter((agent) => agent !== agentName);\n const scanningAgents = this.scanStatus.scanningAgents.filter((agent) => agent !== agentName);\n const completedAgents = [...new Set([...this.scanStatus.completedAgents, agentName])];\n const active = pendingAgents.length > 0 || scanningAgents.length > 0;\n const now = Date.now();\n const previousStatus = this.scanStatus.agentStatuses[agentName];\n const sessions = this.byAgent[agentName]?.length ?? previousStatus?.sessions ?? 0;\n const total = previousStatus?.total ?? previousStatus?.processed;\n\n this.updateScanStatus({\n ...this.scanStatus,\n active,\n phase: active ? \"scanning\" : \"idle\",\n pendingAgents,\n scanningAgents,\n completedAgents,\n agentStatuses: {\n ...this.scanStatus.agentStatuses,\n [agentName]: {\n agentName,\n status: \"complete\",\n total,\n processed: total,\n sessions,\n startedAt: previousStatus?.startedAt,\n updatedAt: now,\n completedAt: now,\n },\n },\n updatedAt: now,\n completedAt: active ? undefined : now,\n });\n }\n\n private finishScanBatch(): void {\n const now = Date.now();\n this.updateScanStatus({\n ...this.scanStatus,\n active: false,\n phase: \"idle\",\n pendingAgents: [],\n scanningAgents: [],\n agentStatuses: Object.fromEntries(\n Object.entries(this.scanStatus.agentStatuses).map(([agentName, status]) => [\n agentName,\n { ...status, status: \"complete\", completedAt: status.completedAt ?? now, updatedAt: now },\n ]),\n ),\n updatedAt: now,\n completedAt: now,\n });\n }\n\n private updateBackfillStatus(patch: Partial<BackfillStatus>): void {\n this.updateScanStatus({\n ...this.scanStatus,\n backfill: { ...this.scanStatus.backfill, ...patch },\n updatedAt: Date.now(),\n });\n }\n\n /**\n * Only FileSystemSessionSource agents pay the O(history) enumeration cost this\n * guards against: database agents already do a cheap single-file mtime check.\n * With no startup window configured, the regular refresh path already walks\n * full history, so backfill would be redundant.\n */\n private needsBackfill(agent: BaseAgent): boolean {\n if (this.startupScanOptions.from == null && this.startupScanOptions.to == null) return false;\n if (!(agent instanceof FileSystemSessionSource)) return false;\n if (!agent.isAvailable()) return false;\n const lastSyncAt = getAgentLastFullSyncAt(agent.name);\n return lastSyncAt == null || Date.now() - lastSyncAt > BACKFILL_INTERVAL_MS;\n }\n\n private enqueueBackfill(agentName: string): void {\n if (\n this.backfillQueue.includes(agentName) ||\n this.scanStatus.backfill.currentAgent === agentName\n ) {\n return;\n }\n this.backfillQueue.push(agentName);\n this.updateBackfillStatus({ active: true, pendingAgents: [...this.backfillQueue] });\n this.pumpBackfillQueue();\n }\n\n private pumpBackfillQueue(): void {\n if (this.backfillRunning) return;\n const agentName = this.backfillQueue.shift();\n if (!agentName) return;\n\n this.backfillRunning = true;\n this.updateBackfillStatus({ currentAgent: agentName, pendingAgents: [...this.backfillQueue] });\n\n void this.runBackfill(agentName).finally(() => {\n this.backfillRunning = false;\n this.updateBackfillStatus({\n currentAgent: undefined,\n completedAgents: [...new Set([...this.scanStatus.backfill.completedAgents, agentName])],\n active: this.backfillQueue.length > 0,\n });\n this.pumpBackfillQueue();\n });\n }\n\n /** Unbounded per-source sync to reconcile the full session history, not just the display window. */\n private async runBackfill(agentName: string): Promise<void> {\n const startedAt = performance.now();\n const agent = this.agents.find((item) => item.name === agentName);\n if (!agent || !(agent instanceof FileSystemSessionSource) || !agent.isAvailable()) {\n return;\n }\n\n const cached = loadCachedSessions(agentName);\n const baseline = cached?.sessions ?? this.byAgent[agentName] ?? [];\n const meta = cached?.meta ?? buildAgentCacheMeta(agent);\n if (cached) {\n restoreAgentCacheMeta(agent, cached.meta);\n }\n\n try {\n const result = await this.scanAgentInWorker(\n agent,\n baseline,\n null,\n {},\n { sourceSync: true, meta },\n );\n agent.setSessionMetaMap(new Map(Object.entries(result.meta)));\n const fullSessions = attachMissingProjectIdentities(result.sessions);\n const filtered = this.applyFilters(fullSessions);\n const diff = buildRefreshDiff(\n agentName,\n this.byAgent[agentName] ?? [],\n filtered,\n result.changedIds ?? [],\n );\n\n this.byAgent[agentName] = sortSessions(filtered);\n this.rebuildSessions();\n\n await this.enqueueSearchIndexJobs(\"scan.backfill\", [\n {\n kind: \"full\",\n context: \"scan.backfill\",\n agentName,\n sessions: fullSessions,\n meta: buildAgentCacheMeta(agent),\n saveCache: true,\n },\n ]);\n markAgentFullSyncCompleted(agentName);\n\n if (diff.event) {\n diff.event.totalSessions = this.sessions.length;\n this.emit(diff.event);\n }\n appLogger.info(\"scan.backfill.done\", {\n agent: agentName,\n duration_ms: Math.round(performance.now() - startedAt),\n sessions: fullSessions.length,\n changed: result.changedIds?.length ?? 0,\n });\n } catch (error) {\n appLogger.error(\"scan.backfill.error\", { agent: agentName, error });\n console.error(`[${agentName}] Backfill failed:`, error);\n }\n }\n\n private queueEvent(event: SessionsUpdatedEvent): void {\n this.pendingEvent = this.pendingEvent ? mergeEvents(this.pendingEvent, event) : event;\n if (this.pendingEventTimer) {\n return;\n }\n\n this.pendingEventTimer = setTimeout(() => {\n const pending = this.pendingEvent;\n this.pendingEvent = null;\n this.pendingEventTimer = null;\n if (pending) {\n this.emitNow(pending);\n }\n }, NEW_SESSION_EVENT_WINDOW_MS);\n }\n\n private rebuildSessions(): void {\n this.sessions = sortSessions(Object.values(this.byAgent).flat());\n }\n\n private getSearchIndexWorkerUrl(): URL | null {\n const workerUrl = new URL(\"./search-index-worker.js\", import.meta.url);\n if (workerUrl.protocol === \"file:\" && !existsSync(fileURLToPath(workerUrl))) {\n return null;\n }\n return workerUrl;\n }\n\n private getSmartTagWorkerUrl(): URL | null {\n const workerUrl = new URL(\"./smart-tag-worker.js\", import.meta.url);\n if (workerUrl.protocol === \"file:\" && !existsSync(fileURLToPath(workerUrl))) {\n return null;\n }\n return workerUrl;\n }\n\n private getScanRefreshWorkerUrl(): URL {\n return new URL(\"./scan-refresh-worker.js\", import.meta.url);\n }\n\n private scanAgentInWorker(\n agent: BaseAgent,\n previousSessions: SessionHead[],\n changedIds: string[] | null,\n scanOptions: Pick<ScanOptions, \"from\" | \"to\" | \"fast\">,\n workerOptions: { sourceSync?: boolean; meta?: Record<string, SessionCacheMeta> } = {},\n ): Promise<{\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n changedIds?: string[];\n }> {\n const workerUrl = this.getScanRefreshWorkerUrl();\n\n return new Promise((resolve, reject) => {\n const worker = new Worker(workerUrl, {\n workerData: {\n agentName: agent.name,\n previousSessions,\n changedIds,\n sourceSync: workerOptions.sourceSync,\n scanOptions,\n meta: workerOptions.meta ?? buildAgentCacheMeta(agent),\n },\n });\n worker.unref();\n\n let settled = false;\n const finish = (callback: () => void) => {\n if (settled) return;\n settled = true;\n void worker.terminate();\n callback();\n };\n\n worker.on(\"message\", (message: ScanRefreshWorkerMessage) => {\n if (message.type === \"progress\") {\n this.updateAgentScanProgress(agent.name, message.progress);\n return;\n }\n if (message.type === \"done\") {\n finish(() =>\n resolve({\n sessions: message.sessions,\n meta: message.meta,\n changedIds: message.changedIds,\n }),\n );\n return;\n }\n finish(() => reject(new Error(message.error)));\n });\n worker.once(\"error\", (error) => {\n finish(() => reject(error));\n });\n worker.once(\"exit\", (code) => {\n if (!settled && code !== 0) {\n finish(() => reject(new Error(`Scan refresh worker exited with code ${code}`)));\n }\n });\n });\n }\n\n private buildFullSearchIndexJobs(context: string): SearchIndexWorkerJob[] {\n return this.agents.map((agent) => {\n const cached = loadCachedSessions(agent.name);\n if (cached) {\n return {\n kind: \"full\",\n context,\n agentName: agent.name,\n sessions: cached.sessions,\n meta: cached.meta,\n };\n }\n return {\n kind: \"full\",\n context,\n agentName: agent.name,\n sessions: this.byAgent[agent.name] ?? [],\n meta: buildAgentCacheMeta(agent),\n };\n });\n }\n\n private enqueueSearchIndexJobs(context: string, jobs: SearchIndexWorkerJob[]): Promise<void> {\n if (jobs.length === 0) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n const batch: SearchIndexJobBatch = { context, jobs, resolve, reject };\n\n if (this.searchIndexWorker) {\n this.pendingSearchIndexJobs.push(batch);\n appLogger.debug(\"search_index.worker_queued\", {\n context,\n jobs: jobs.length,\n pending_jobs: this.pendingSearchIndexJobs.length,\n });\n return;\n }\n\n this.startSearchIndexJobBatch(batch);\n });\n }\n\n private startSearchIndexJobBatch(batch: SearchIndexJobBatch): void {\n const workerUrl = this.getSearchIndexWorkerUrl();\n if (!workerUrl) {\n appLogger.warn(\"search_index.worker_missing\", { context: batch.context });\n batch.resolve();\n return;\n }\n\n let settled = false;\n const worker = new Worker(workerUrl, {\n workerData: {\n context: batch.context,\n jobs: batch.jobs,\n agentNames: [],\n sessionsByAgent: {},\n metaByAgent: {},\n skipFtsIntegrityCheck: this.ftsIntegrityChecked,\n },\n });\n worker.unref();\n this.searchIndexWorker = worker;\n\n worker.on(\"message\", (message: SearchIndexWorkerMessage) => {\n if (message.type === \"sync-result\") {\n logSearchIndexSync(message.context, message.result);\n } else if (message.type === \"done\") {\n appLogger.info(`${message.context}.done`, {\n duration_ms: Math.round(message.durationMs),\n sessions: message.sessions,\n });\n settled = true;\n this.ftsIntegrityChecked = true;\n batch.resolve();\n }\n });\n worker.on(\"error\", (error) => {\n appLogger.error(\"search_index.worker_error\", { context: batch.context, error });\n if (!settled) {\n settled = true;\n batch.reject(error);\n }\n });\n worker.on(\"exit\", (code) => {\n this.searchIndexWorker = null;\n if (code !== 0) {\n appLogger.warn(\"search_index.worker_exit\", { context: batch.context, code });\n if (!settled) {\n settled = true;\n batch.reject(new Error(`Search index worker exited with code ${code}`));\n }\n }\n if (this.pendingSearchIndexJobs.length > 0) {\n const pendingBatch = this.pendingSearchIndexJobs.shift()!;\n this.startSearchIndexJobBatch(pendingBatch);\n }\n });\n }\n\n private applyScanResult(result: ScanResult): void {\n const knownAgents = createRegisteredAgents();\n const agentMap = new Map<string, BaseAgent>();\n const allowedAgents = this.getAllowedAgents();\n\n for (const agent of result.agents) {\n agentMap.set(agent.name, agent);\n }\n for (const agent of knownAgents) {\n if (!agentMap.has(agent.name)) {\n agentMap.set(agent.name, agent);\n }\n }\n\n this.agents = [...agentMap.values()].filter((agent) => {\n if (!allowedAgents) {\n return true;\n }\n return allowedAgents.has(agent.name.toLowerCase());\n });\n\n this.byAgent = {};\n for (const agent of this.agents) {\n this.byAgent[agent.name] = sortSessions(result.byAgent[agent.name] ?? []);\n this.getRefreshState(agent.name).lastRefreshAt =\n result.cacheTimestamps?.[agent.name] ?? Date.now();\n }\n\n this.rebuildSessions();\n }\n\n private getAllowedAgents(): Set<string> | null {\n if (!this.scanOptions.agents?.length) {\n return null;\n }\n return new Set(this.scanOptions.agents.map((agent) => agent.toLowerCase()));\n }\n\n private applyFilters(sessions: SessionHead[]): SessionHead[] {\n return filterSessions(sessions, { ...this.scanOptions, ...this.startupScanOptions });\n }\n\n private async refreshInitialIndex(): Promise<void> {\n const startedAt = performance.now();\n const context = \"scan.initial.background\";\n\n try {\n await this.enqueueSearchIndexJobs(context, this.buildFullSearchIndexJobs(context));\n appLogger.info(`${context}.complete`, {\n duration_ms: Math.round(performance.now() - startedAt),\n sessions: this.sessions.length,\n });\n } catch (error) {\n if (this.shuttingDown) {\n return;\n }\n appLogger.error(`${context}.error`, { error });\n console.error(\"[search] Background index sync failed:\", error);\n }\n }\n\n /**\n * Throttles rather than debounces: a pending timer only gets replaced by a\n * request with an earlier deadline. Plain debounce (reset on every call)\n * would let a steady stream of events — each arriving before the adaptive\n * backoff elapses — push the deadline out forever and starve the refresh.\n */\n private scheduleRefresh(agentName: string, delayMs = REFRESH_DEBOUNCE_MS): void {\n const state = this.getRefreshState(agentName);\n const adaptiveDelayMs = Math.min(\n state.lastRefreshDurationMs * ADAPTIVE_REFRESH_DELAY_MULTIPLIER,\n MAX_ADAPTIVE_REFRESH_DELAY_MS,\n );\n const effectiveDelayMs = Math.max(delayMs, adaptiveDelayMs);\n const deadline = Date.now() + effectiveDelayMs;\n\n if (state.timer !== null) {\n if (deadline >= state.timerDeadline) {\n return;\n }\n clearTimeout(state.timer);\n }\n\n appLogger.debug(\"scan.refresh.schedule\", { agent: agentName, delay_ms: effectiveDelayMs });\n state.timerDeadline = deadline;\n state.timer = setTimeout(() => {\n state.timer = null;\n void this.refreshAgent(agentName);\n }, effectiveDelayMs);\n }\n\n private async refreshAgent(agentName: string): Promise<void> {\n const state = this.getRefreshState(agentName);\n if (state.inFlight) {\n appLogger.debug(\"scan.refresh.pending\", { agent: agentName });\n state.pendingRerun = true;\n return;\n }\n\n state.inFlight = true;\n this.beginAgentScan(agentName);\n\n try {\n await this.runRefresh(agentName);\n } catch (error) {\n appLogger.error(\"scan.refresh.error\", { agent: agentName, error });\n console.error(`[${agentName}] Session refresh failed:`, error);\n } finally {\n state.inFlight = false;\n this.finishAgentScan(agentName);\n\n if (state.pendingRerun) {\n state.pendingRerun = false;\n this.scheduleRefresh(agentName, PENDING_REFRESH_DELAY_MS);\n }\n }\n }\n\n private async runRefresh(agentName: string): Promise<void> {\n const startedAt = performance.now();\n const state = this.getRefreshState(agentName);\n const pendingPathCount = state.pendingPathCount;\n state.pendingPathCount = 0;\n const agent = this.agents.find((item) => item.name === agentName);\n if (!agent) {\n appLogger.warn(\"scan.refresh.missing_agent\", { agent: agentName });\n return;\n }\n\n const previousSessions = this.byAgent[agentName] ?? [];\n const cached = loadCachedSessions(agentName);\n const refreshBaseline = cached?.sessions ?? previousSessions;\n const cacheTimestamp = cached?.timestamp ?? state.lastRefreshAt;\n if (cached) {\n restoreAgentCacheMeta(agent, cached.meta);\n }\n const isInitialized = isAgentCacheInitialized(agentName);\n let nextSessions = previousSessions;\n let fullScanSessions: SessionHead[] | null = null;\n let preciseChangedIds: string[] | null = null;\n let usedIncrementalScan = false;\n let persistenceDiff: Pick<SessionRefreshDiff, \"changedSessions\" | \"removedSessionIds\"> | null =\n null;\n let availabilityDuration = 0;\n let checkDuration = 0;\n let scanDuration = 0;\n let filterDuration = 0;\n let diffDuration = 0;\n let persistDuration = 0;\n let searchIndexDuration = 0;\n let persistentJobKind: SearchIndexWorkerJob[\"kind\"] | undefined;\n\n const availabilityStartedAt = performance.now();\n const isAvailable = agent.isAvailable();\n availabilityDuration = performance.now() - availabilityStartedAt;\n\n if (!isAvailable) {\n nextSessions = [];\n state.lastRefreshAt = Date.now();\n } else if (!isInitialized) {\n // First-ever scan is bounded to the display window so startup stays fast;\n // needsBackfill() picks up the rest of history in the background.\n this.setScanPhase(\"initializing\");\n const scanStartedAt = performance.now();\n const result = await this.scanAgentInWorker(\n agent,\n previousSessions,\n null,\n this.startupScanOptions,\n );\n nextSessions = result.sessions;\n agent.setSessionMetaMap?.(new Map(Object.entries(result.meta)));\n fullScanSessions = attachMissingProjectIdentities(nextSessions);\n nextSessions = fullScanSessions;\n scanDuration = performance.now() - scanStartedAt;\n state.lastRefreshAt = Date.now();\n } else if (cached && agent instanceof FileSystemSessionSource) {\n // File-system agents refresh via precise per-source fingerprint sync,\n // bounded to the display window; the background backfill pass\n // periodically reconciles sessions outside it. Database agents lack\n // per-file fingerprints and fall through to the checkForChanges branch below.\n const scanStartedAt = performance.now();\n const result = await this.scanAgentInWorker(\n agent,\n cached.sessions,\n null,\n this.startupScanOptions,\n {\n sourceSync: true,\n meta: cached.meta,\n },\n );\n nextSessions = result.sessions;\n agent.setSessionMetaMap(new Map(Object.entries(result.meta)));\n preciseChangedIds = result.changedIds ?? [];\n usedIncrementalScan = true;\n persistenceDiff = buildRefreshDiff(\n agentName,\n cached.sessions,\n attachMissingProjectIdentities(nextSessions),\n preciseChangedIds,\n );\n scanDuration = performance.now() - scanStartedAt;\n state.lastRefreshAt = Date.now();\n if (preciseChangedIds.length === 0) {\n appLogger.debug(\"scan.refresh.unchanged\", {\n agent: agentName,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n }\n } else if (refreshBaseline.length > 0) {\n const checkStartedAt = performance.now();\n const checkResult = await Promise.resolve(\n agent.checkForChanges(cacheTimestamp, refreshBaseline),\n );\n checkDuration = performance.now() - checkStartedAt;\n\n state.lastRefreshAt = checkResult.timestamp;\n if (!checkResult.hasChanges) {\n appLogger.debug(\"scan.refresh.unchanged\", {\n agent: agentName,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n return;\n }\n\n preciseChangedIds = checkResult.changedIds ?? null;\n usedIncrementalScan = Array.isArray(checkResult.changedIds);\n const scanStartedAt = performance.now();\n nextSessions = await Promise.resolve(\n agent.incrementalScan(refreshBaseline, checkResult.changedIds ?? []),\n );\n const nextBaseline = attachMissingProjectIdentities(nextSessions);\n persistenceDiff = buildRefreshDiff(\n agentName,\n refreshBaseline,\n nextBaseline,\n preciseChangedIds ?? [],\n );\n nextSessions = nextBaseline;\n scanDuration = performance.now() - scanStartedAt;\n } else {\n const scanStartedAt = performance.now();\n const result = await this.scanAgentInWorker(agent, previousSessions, null, {});\n nextSessions = result.sessions;\n agent.setSessionMetaMap(new Map(Object.entries(result.meta)));\n fullScanSessions = attachMissingProjectIdentities(nextSessions);\n nextSessions = fullScanSessions;\n scanDuration = performance.now() - scanStartedAt;\n state.lastRefreshAt = Date.now();\n }\n\n nextSessions = attachMissingProjectIdentities(nextSessions);\n\n const filterStartedAt = performance.now();\n nextSessions = this.applyFilters(nextSessions);\n filterDuration = performance.now() - filterStartedAt;\n const diffStartedAt = performance.now();\n const diff = buildRefreshDiff(\n agentName,\n previousSessions,\n nextSessions,\n preciseChangedIds ?? [],\n );\n diffDuration = performance.now() - diffStartedAt;\n const searchIndexOptions =\n pendingPathCount >= SEARCH_INDEX_BULK_PENDING_PATH_THRESHOLD ? { isBulk: true } : undefined;\n const canPersistIncrementally = usedIncrementalScan;\n const persistentChanges = persistenceDiff?.changedSessions ?? diff.changedSessions;\n const persistentRemovedSessionIds =\n persistenceDiff?.removedSessionIds ?? diff.removedSessionIds;\n const changedSessionIds = canPersistIncrementally\n ? new Set(persistentChanges.map(({ session }) => session.id))\n : undefined;\n const cacheMeta = buildAgentCacheMeta(agent, changedSessionIds);\n const persistStartedAt = performance.now();\n const persistentJob: SearchIndexWorkerJob | null = canPersistIncrementally\n ? {\n kind: \"changes\",\n context: \"scan.refresh\",\n agentName,\n changes: persistentChanges,\n removedSessionIds: persistentRemovedSessionIds,\n meta: cacheMeta,\n ...(searchIndexOptions ? { searchIndexOptions } : {}),\n }\n : fullScanSessions\n ? {\n kind: \"full\",\n context: \"scan.refresh\",\n agentName,\n sessions: fullScanSessions,\n meta: buildAgentCacheMeta(agent),\n saveCache: true,\n ...(searchIndexOptions ? { searchIndexOptions } : {}),\n }\n : null;\n if (persistentJob) {\n persistentJobKind = persistentJob.kind;\n const persist = this.enqueueSearchIndexJobs(\"scan.refresh\", [persistentJob]);\n if (!isInitialized && persistentJob.kind === \"full\") {\n await persist;\n } else {\n void persist.catch((error) => {\n appLogger.error(\"scan.refresh.persist.error\", { agent: agentName, error });\n console.error(`[${agentName}] Session persistence failed:`, error);\n });\n }\n }\n persistDuration = performance.now() - persistStartedAt;\n const searchIndexStartedAt = performance.now();\n searchIndexDuration = performance.now() - searchIndexStartedAt;\n logSearchIndexSync(\"scan.refresh\", null, { pending_paths: pendingPathCount });\n\n const event = diff.event;\n this.byAgent[agentName] = sortSessions(nextSessions);\n this.rebuildSessions();\n\n if (event) {\n event.totalSessions = this.sessions.length;\n this.emit(event);\n }\n const totalDurationMs = performance.now() - startedAt;\n state.lastRefreshDurationMs = totalDurationMs;\n appLogger.info(\"scan.refresh.done\", {\n agent: agentName,\n duration_ms: Math.round(totalDurationMs),\n sessions: nextSessions.length,\n new_sessions: event?.newSessions ?? 0,\n updated_sessions: event?.updatedSessions ?? 0,\n removed_sessions: event?.removedSessions ?? 0,\n pending_paths: pendingPathCount,\n availability_ms: Math.round(availabilityDuration),\n check_ms: Math.round(checkDuration),\n scan_ms: Math.round(scanDuration),\n filter_ms: Math.round(filterDuration),\n diff_ms: Math.round(diffDuration),\n persist_ms: Math.round(persistDuration),\n search_index_ms: Math.round(searchIndexDuration),\n persistent_index_worker_job: persistentJobKind,\n persistent_index_skipped: !persistentJob || undefined,\n });\n }\n}\n","/**\n * SessionWatcher — a deep module that hides platform-specific file watching\n * (recursive watch availability, non-recursive fallback trees, write-stability\n * polling, debounce) behind a tiny interface.\n *\n * Consumers only need to know: start watching these agent names, stop, and get\n * notified (post write-stability + debounce) which agents' data changed. The\n * recursive-vs-fallback strategy, APFS mtime quirks, and path-stability polling\n * are all internal details.\n */\nimport { existsSync, readdirSync, statSync, watch, type FSWatcher } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { getCursorDataPath, resolveProviderRoots } from \"@codesesh/core\";\nimport { appLogger } from \"./logging.js\";\n\nconst WRITE_STABILITY_THRESHOLD_MS = 250;\nconst WRITE_STABILITY_POLL_MS = 100;\n\nexport interface WatchTarget {\n path: string;\n root?: string;\n}\n\ninterface WatchScope {\n agentName: string;\n targetPath: string;\n}\n\ninterface StablePathState {\n path: string;\n agentNames: Set<string>;\n lastMtimeMs: number | null;\n lastSize: number | null;\n stableSince: number;\n timer: NodeJS.Timeout | null;\n}\n\nexport type AgentsChangedListener = (agentNames: Set<string>) => void;\n\nexport function toAbsolutePath(path: string): string {\n return isAbsolute(path) ? path : resolve(path);\n}\n\nfunction closestWatchablePath(targetPath: string): string | null {\n if (!isAbsolute(targetPath) && !existsSync(targetPath)) {\n return null;\n }\n\n let current = toAbsolutePath(targetPath);\n\n while (!existsSync(current)) {\n const parent = dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n\n return current;\n}\n\nfunction getWatchRoot(path: string): string {\n const stat = statSync(path);\n return stat.isDirectory() ? path : dirname(path);\n}\n\nexport function isRecursiveWatchSupported(\n platform = process.platform,\n nodeVersion = process.versions.node,\n): boolean {\n if (platform === \"darwin\" || platform === \"win32\") {\n return true;\n }\n if (platform !== \"linux\" && platform !== \"aix\" && platform !== \"ibmi\") {\n return false;\n }\n\n const [major = 0, minor = 0] = nodeVersion.split(\".\").map((part) => Number(part));\n return major > 19 || (major === 19 && minor >= 1);\n}\n\nfunction isRecursiveWatchUnavailable(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"ERR_FEATURE_UNAVAILABLE_ON_PLATFORM\"\n );\n}\n\nfunction isSameOrChildPath(parentPath: string, childPath: string): boolean {\n const path = relative(parentPath, childPath);\n return path === \"\" || (!path.startsWith(\"..\") && !isAbsolute(path));\n}\n\nfunction isRelatedPath(changedPath: string, targetPath: string): boolean {\n return isSameOrChildPath(targetPath, changedPath) || isSameOrChildPath(changedPath, targetPath);\n}\n\nfunction mergeScopes(target: WatchScope[], scopes: WatchScope[]): void {\n for (const scope of scopes) {\n if (\n !target.some(\n (item) => item.agentName === scope.agentName && item.targetPath === scope.targetPath,\n )\n ) {\n target.push(scope);\n }\n }\n}\n\nfunction resolveWatchEventPath(watchPath: string, filename: string | Buffer | null): string {\n const filenameText = filename?.toString();\n if (!filenameText) {\n return watchPath;\n }\n return isAbsolute(filenameText) ? filenameText : join(watchPath, filenameText);\n}\n\nexport function resolveAgentWatchTargets(agentName: string): WatchTarget[] {\n const roots = resolveProviderRoots();\n const cursorDataPath = getCursorDataPath();\n\n switch (agentName) {\n case \"claudecode\":\n return [\n { root: roots.claudeRoot, path: join(roots.claudeRoot, \"projects\") },\n { path: \"data/claudecode\" },\n ];\n case \"codex\":\n return [\n { path: join(roots.codexRoot, \"sessions\") },\n { path: join(roots.codexRoot, \"session_index.jsonl\") },\n ];\n case \"pi\":\n return [\n { root: roots.piRoot, path: join(roots.piRoot, \"agent\", \"sessions\") },\n { root: \"data/pi\", path: \"data/pi\" },\n ];\n case \"cursor\":\n return cursorDataPath\n ? [\n {\n root: cursorDataPath,\n path: join(cursorDataPath, \"globalStorage\", \"state.vscdb\"),\n },\n { root: cursorDataPath, path: join(cursorDataPath, \"workspaceStorage\") },\n ]\n : [];\n case \"kimi\":\n return [\n { root: roots.kimiRoot, path: join(roots.kimiRoot, \"sessions\") },\n { path: \"data/kimi\" },\n ];\n case \"opencode\":\n return [\n { root: roots.opencodeRoot, path: join(roots.opencodeRoot, \"opencode.db\") },\n { root: \"data/opencode\", path: \"data/opencode/opencode.db\" },\n ];\n case \"zcode\":\n return roots.zcodeRoot\n ? [{ root: roots.zcodeRoot, path: join(roots.zcodeRoot, \"cli\", \"db\", \"db.sqlite\") }]\n : [];\n default:\n return [];\n }\n}\n\nexport class SessionWatcher {\n private watchers: FSWatcher[] = [];\n private fallbackWatchScopes = new Map<string, WatchScope[]>();\n private stablePaths = new Map<string, StablePathState>();\n private listeners = new Set<AgentsChangedListener>();\n\n /** Register a listener fired (after write-stability polling) with the changed agent set. */\n onAgentsChanged(cb: AgentsChangedListener): () => void {\n this.listeners.add(cb);\n return () => {\n this.listeners.delete(cb);\n };\n }\n\n /** Begin watching the given agent names' data directories. */\n start(agentNames: string[]): void {\n const scopesByRoot = new Map<string, WatchScope[]>();\n\n for (const agentName of agentNames) {\n const watchTargets = resolveAgentWatchTargets(agentName);\n\n if (watchTargets.length === 0) {\n appLogger.debug(\"watch.skip\", { agent: agentName });\n continue;\n }\n\n for (const target of watchTargets) {\n const watchRootPath = closestWatchablePath(target.root ?? target.path);\n if (!watchRootPath) continue;\n\n let rootPath: string;\n try {\n rootPath = getWatchRoot(watchRootPath);\n } catch (error) {\n this.reportWatchError(\"watch.resolve.error\", { path: watchRootPath, error });\n continue;\n }\n const targetPath = toAbsolutePath(target.path);\n const scopes = scopesByRoot.get(rootPath) ?? [];\n if (\n !scopes.some((scope) => scope.agentName === agentName && scope.targetPath === targetPath)\n ) {\n scopes.push({ agentName, targetPath });\n }\n scopesByRoot.set(rootPath, scopes);\n }\n }\n\n for (const [rootPath, scopes] of scopesByRoot.entries()) {\n const agents = Array.from(new Set(scopes.map((scope) => scope.agentName)));\n appLogger.info(\"watch.start\", {\n root: rootPath,\n agents,\n targets: scopes.map((scope) => ({\n agent: scope.agentName,\n path: scope.targetPath,\n })),\n });\n\n if (isRecursiveWatchSupported()) {\n const started = this.watchDirectory(rootPath, scopes, true);\n if (started) {\n continue;\n }\n }\n\n this.watchDirectoryTree(rootPath, scopes);\n }\n }\n\n /** Stop all watchers and clear pending stability polls. */\n async dispose(): Promise<void> {\n for (const state of this.stablePaths.values()) {\n if (state.timer) {\n clearTimeout(state.timer);\n }\n }\n this.stablePaths.clear();\n\n await Promise.all(this.watchers.map((watcher) => watcher.close()));\n this.watchers = [];\n this.fallbackWatchScopes.clear();\n this.listeners.clear();\n }\n\n private watchDirectory(path: string, scopes: WatchScope[], recursive: boolean): boolean {\n try {\n const watcher = watch(path, { recursive }, (eventType, filename) => {\n queueMicrotask(() => {\n try {\n const activeScopes = recursive\n ? scopes\n : (this.fallbackWatchScopes.get(path) ?? scopes);\n this.handleWatchEvent(path, activeScopes, eventType, filename);\n if (!recursive) {\n this.watchNewDirectories(path, filename, activeScopes);\n }\n } catch (error) {\n this.reportWatchError(\"watch.event.error\", { path, recursive, error });\n }\n });\n });\n\n watcher.on(\"error\", (error) => {\n this.reportWatchError(\"watch.error\", { path, recursive, error });\n });\n\n this.watchers.push(watcher);\n return true;\n } catch (error) {\n if (recursive && isRecursiveWatchUnavailable(error)) {\n appLogger.warn(\"watch.recursive_unavailable\", { path, error });\n return false;\n }\n\n this.reportWatchError(\"watch.start.error\", { path, recursive, error });\n return false;\n }\n }\n\n private watchDirectoryTree(rootPath: string, scopes: WatchScope[]): void {\n const pending = [rootPath];\n\n while (pending.length > 0) {\n const dirPath = pending.pop()!;\n this.watchFallbackDirectory(dirPath, scopes);\n\n try {\n for (const entry of readdirSync(dirPath, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n pending.push(join(dirPath, entry.name));\n }\n }\n } catch (error) {\n this.reportWatchError(\"watch.scan.error\", { path: dirPath, error });\n }\n }\n }\n\n private watchFallbackDirectory(path: string, scopes: WatchScope[]): void {\n const existingScopes = this.fallbackWatchScopes.get(path);\n if (existingScopes) {\n mergeScopes(existingScopes, scopes);\n return;\n }\n\n const storedScopes = [...scopes];\n this.fallbackWatchScopes.set(path, storedScopes);\n if (!this.watchDirectory(path, storedScopes, false)) {\n this.fallbackWatchScopes.delete(path);\n }\n }\n\n private watchNewDirectories(\n watchPath: string,\n filename: string | Buffer | null,\n scopes: WatchScope[],\n ): void {\n const path = resolveWatchEventPath(watchPath, filename);\n try {\n if (statSync(path).isDirectory()) {\n this.watchDirectoryTree(path, scopes);\n }\n } catch {}\n }\n\n private handleWatchEvent(\n watchPath: string,\n scopes: WatchScope[],\n eventType: string,\n filename: string | Buffer | null,\n ): void {\n const changedPath = resolveWatchEventPath(watchPath, filename);\n const agentNames = new Set(\n scopes\n .filter((scope) => isRelatedPath(changedPath, scope.targetPath))\n .map((scope) => scope.agentName),\n );\n\n if (agentNames.size === 0) {\n return;\n }\n\n appLogger.debug(\"watch.event\", {\n event: eventType,\n path: changedPath,\n agents: Array.from(agentNames),\n });\n this.waitForStablePath(changedPath, agentNames);\n }\n\n private waitForStablePath(path: string, agentNames: Set<string>): void {\n const existing = this.stablePaths.get(path);\n if (existing) {\n for (const agentName of agentNames) {\n existing.agentNames.add(agentName);\n }\n return;\n }\n\n const state: StablePathState = {\n path,\n agentNames: new Set(agentNames),\n lastMtimeMs: null,\n lastSize: null,\n stableSince: Date.now(),\n timer: null,\n };\n this.stablePaths.set(path, state);\n this.pollStablePath(path);\n }\n\n private pollStablePath(path: string): void {\n const state = this.stablePaths.get(path);\n if (!state) {\n return;\n }\n\n let size: number;\n let mtimeMs: number;\n try {\n const stat = statSync(path);\n size = stat.size;\n mtimeMs = stat.mtimeMs;\n } catch {\n this.stablePaths.delete(path);\n this.emitAgentsChanged(state.agentNames);\n return;\n }\n\n const now = Date.now();\n const unchanged = state.lastSize === size && state.lastMtimeMs === mtimeMs;\n if (!unchanged) {\n state.lastSize = size;\n state.lastMtimeMs = mtimeMs;\n state.stableSince = now;\n }\n\n if (unchanged && now - state.stableSince >= WRITE_STABILITY_THRESHOLD_MS) {\n this.stablePaths.delete(path);\n this.emitAgentsChanged(state.agentNames);\n return;\n }\n\n state.timer = setTimeout(() => this.pollStablePath(path), WRITE_STABILITY_POLL_MS);\n }\n\n private emitAgentsChanged(agentNames: Set<string>): void {\n if (agentNames.size === 0) return;\n for (const listener of this.listeners) {\n listener(new Set(agentNames));\n }\n }\n\n private reportWatchError(event: string, data: Record<string, unknown>): void {\n appLogger.error(event, data);\n console.error(\"[watch] File watcher failed:\", data.error);\n }\n}\n","import { consola } from \"consola\";\nimport type { BaseAgent } from \"@codesesh/core\";\nimport { VERSION } from \"./version.js\";\n\nexport function printScanResults(agents: BaseAgent[]): void {\n consola.log(\"\");\n consola.box({\n title: \"CodeSesh\",\n message: `v${VERSION} • local session browser`,\n style: {\n padding: 1,\n borderColor: \"cyan\",\n },\n });\n consola.log(\"\");\n consola.info(\n `Indexing ${agents.map((agent) => agent.displayName).join(\", \")} sessions in the background.`,\n );\n consola.info(\"The Web UI will update automatically as sessions are discovered.\");\n consola.log(\"\");\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(resolve(__dirname, \"../package.json\"), \"utf-8\"));\n\nexport const VERSION = pkg.version;\n","export const DEFAULT_PORT = 4521;\nexport const DEFAULT_PORT_FALLBACK_ATTEMPTS = 20;\n\nexport function parsePort(value: string | undefined): number {\n const port = parseInt(value ?? \"\", 10);\n return Number.isNaN(port) ? DEFAULT_PORT : port;\n}\n\nexport function hasExplicitPortArg(argv: string[]): boolean {\n return argv.some((arg, index) => {\n if (arg === \"--port\" || arg === \"-p\") return index < argv.length - 1;\n return arg.startsWith(\"--port=\") || /^-p\\d+$/.test(arg);\n });\n}\n"],"mappings":"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","names":["Hono","existsSync","__dirname","existsSync","resolve","Hono","url","existsSync","fileURLToPath","existsSync","readdirSync","statSync","dirname","join","resolve","resolve","existsSync","dirname","statSync","join","readdirSync","existsSync","fileURLToPath","resolve","resolve","dirname","fileURLToPath"]}
|