codesesh 0.11.0 → 0.13.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.
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  FileSystemSessionSource,
4
- createRegisteredAgents
5
- } from "./chunk-BIXOP5QX.js";
4
+ attachMissingProjectIdentities,
5
+ createRegisteredAgents,
6
+ ensureSessionTagsSync,
7
+ matchesScanWindow
8
+ } from "./chunk-BV65IEWZ.js";
6
9
 
7
10
  // src/scan-refresh-worker.ts
8
11
  import { parentPort, workerData } from "worker_threads";
@@ -34,9 +37,14 @@ function sourceFingerprintMatches(source, cachedSession, cached) {
34
37
  function sourcePathFromMeta(meta) {
35
38
  return typeof meta?.sourcePath === "string" ? meta.sourcePath : null;
36
39
  }
37
- function syncAgentSources(agent, cachedSessions, cachedMeta) {
40
+ function wasEnumeratedThisPass(cached, windowOptions) {
41
+ if (windowOptions?.from == null && windowOptions?.to == null) return true;
42
+ const mtimeMs = cached?.sourceMtimeMs;
43
+ return typeof mtimeMs !== "number" || matchesScanWindow(mtimeMs, windowOptions);
44
+ }
45
+ function syncAgentSources(agent, cachedSessions, cachedMeta, windowOptions) {
38
46
  const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));
39
- const sourceRefs = agent.listSessionSources();
47
+ const sourceRefs = agent.listSessionSources(windowOptions);
40
48
  const currentIds = new Set(sourceRefs.map((source) => source.sessionId));
41
49
  const changedIds = /* @__PURE__ */ new Set();
42
50
  for (const source of sourceRefs) {
@@ -54,13 +62,27 @@ function syncAgentSources(agent, cachedSessions, cachedMeta) {
54
62
  }
55
63
  }
56
64
  for (const session of cachedSessions) {
57
- if (!currentIds.has(session.id)) {
58
- sessionMap.delete(session.id);
59
- changedIds.add(session.id);
60
- }
65
+ if (currentIds.has(session.id)) continue;
66
+ if (!wasEnumeratedThisPass(cachedMeta[session.id], windowOptions)) continue;
67
+ sessionMap.delete(session.id);
68
+ changedIds.add(session.id);
61
69
  }
62
70
  return { sessions: [...sessionMap.values()], changedIds: [...changedIds] };
63
71
  }
72
+ var TAG_SETTLE_MS = 6e4;
73
+ function isSettled(session, now) {
74
+ return now - (session.time_updated ?? session.time_created) >= TAG_SETTLE_MS;
75
+ }
76
+ function finalizeSessions(agent, sessions) {
77
+ const withIdentity = attachMissingProjectIdentities(sessions);
78
+ const now = Date.now();
79
+ const settled = withIdentity.filter((session) => isSettled(session, now));
80
+ if (settled.length === 0) return withIdentity;
81
+ const taggedById = new Map(
82
+ ensureSessionTagsSync(agent, settled).sessions.map((session) => [session.id, session])
83
+ );
84
+ return withIdentity.map((session) => taggedById.get(session.id) ?? session);
85
+ }
64
86
  var data = workerData;
65
87
  var startedAt = performance.now();
66
88
  async function run() {
@@ -75,7 +97,7 @@ async function run() {
75
97
  if (!isAvailable) {
76
98
  sessions = [];
77
99
  } else if (data.sourceSync && agent instanceof FileSystemSessionSource) {
78
- const result = syncAgentSources(agent, data.previousSessions, data.meta);
100
+ const result = syncAgentSources(agent, data.previousSessions, data.meta, data.scanOptions);
79
101
  sessions = result.sessions;
80
102
  changedIds = result.changedIds;
81
103
  } else if (data.changedIds) {
@@ -93,6 +115,7 @@ async function run() {
93
115
  })
94
116
  );
95
117
  }
118
+ sessions = finalizeSessions(agent, sessions);
96
119
  parentPort?.postMessage({
97
120
  type: "done",
98
121
  sessions,
@@ -110,4 +133,7 @@ try {
110
133
  durationMs: performance.now() - startedAt
111
134
  });
112
135
  }
136
+ export {
137
+ finalizeSessions
138
+ };
113
139
  //# sourceMappingURL=scan-refresh-worker.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/scan-refresh-worker.ts"],"sourcesContent":["import { parentPort, workerData } from \"node:worker_threads\";\nimport {\n createRegisteredAgents,\n FileSystemSessionSource,\n type AgentScanProgress,\n type ScanOptions,\n type SessionCacheMeta,\n type SessionHead,\n type SessionSourceRef,\n} from \"@codesesh/core\";\n\nexport type ScanRefreshWorkerMessage =\n | {\n type: \"progress\";\n progress: AgentScanProgress;\n }\n | {\n type: \"done\";\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n changedIds?: string[];\n durationMs: number;\n }\n | {\n type: \"error\";\n error: string;\n durationMs: number;\n };\n\ninterface ScanRefreshWorkerData {\n agentName: string;\n previousSessions: SessionHead[];\n changedIds: string[] | null;\n sourceSync?: boolean;\n scanOptions: Pick<ScanOptions, \"from\" | \"to\" | \"fast\">;\n meta: Record<string, SessionCacheMeta>;\n}\n\nfunction serializeMeta(agent: {\n getSessionMetaMap: () => Map<string, SessionCacheMeta>;\n}): Record<string, SessionCacheMeta> {\n const metaMap = agent.getSessionMetaMap();\n const meta: Record<string, SessionCacheMeta> = {};\n for (const [id, data] of metaMap.entries()) {\n meta[id] = { id, ...(data as Record<string, unknown>) } as SessionCacheMeta;\n }\n return meta;\n}\n\nfunction sourceFingerprintFromMeta(meta: SessionCacheMeta | undefined): string | null {\n return typeof meta?.sourceFingerprint === \"string\" ? meta.sourceFingerprint : null;\n}\n\nfunction parseSourceFingerprint(fingerprint: string): unknown[] | null {\n try {\n const parsed = JSON.parse(fingerprint);\n return Array.isArray(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Compare a live source fingerprint against the cached meta. A direct string\n * match is the fast path; the fallback tolerates older cache entries written by\n * a different fingerprint format as long as the underlying mtime (array slot 2)\n * is unchanged, so a fingerprint-format bump does not force a full rescan.\n */\nfunction sourceFingerprintMatches(\n source: SessionSourceRef,\n cachedSession: SessionHead,\n cached: SessionCacheMeta | undefined,\n): boolean {\n if (sourceFingerprintFromMeta(cached) === source.fingerprint) return true;\n\n const current = parseSourceFingerprint(source.fingerprint);\n if (!current || current.length < 5) return false;\n\n return (\n typeof cached?.sourceMtimeMs === \"number\" &&\n cached.sourceMtimeMs === current[2] &&\n (current[4] == null || cachedSession.title === current[4])\n );\n}\n\nfunction sourcePathFromMeta(meta: SessionCacheMeta | undefined): string | null {\n return typeof meta?.sourcePath === \"string\" ? meta.sourcePath : null;\n}\n\n/**\n * Source-level incremental sync, mirroring FileSystemSessionSource.incrementalScan.\n * Kept standalone because the worker cannot share the agent's live metaMap with\n * the main thread — it receives cached meta via workerData instead.\n */\nfunction syncAgentSources(\n agent: FileSystemSessionSource,\n cachedSessions: SessionHead[],\n cachedMeta: Record<string, SessionCacheMeta>,\n): { sessions: SessionHead[]; changedIds: string[] } {\n const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));\n const sourceRefs = agent.listSessionSources();\n const currentIds = new Set(sourceRefs.map((source) => source.sessionId));\n const changedIds = new Set<string>();\n\n for (const source of sourceRefs) {\n const cachedSession = sessionMap.get(source.sessionId);\n const cached = cachedMeta[source.sessionId];\n const sameSource = sourcePathFromMeta(cached) === source.sourcePath;\n const sameFingerprint =\n cachedSession && sourceFingerprintMatches(source, cachedSession, cached);\n if (cachedSession && sameSource && sameFingerprint) continue;\n\n const next = agent.scanSessionSource(source.sourcePath);\n changedIds.add(source.sessionId);\n if (next) {\n sessionMap.set(next.id, next);\n } else {\n sessionMap.delete(source.sessionId);\n }\n }\n\n for (const session of cachedSessions) {\n if (!currentIds.has(session.id)) {\n sessionMap.delete(session.id);\n changedIds.add(session.id);\n }\n }\n\n return { sessions: [...sessionMap.values()], changedIds: [...changedIds] };\n}\n\nconst data = workerData as ScanRefreshWorkerData;\nconst startedAt = performance.now();\n\nasync function run(): Promise<void> {\n const agent = createRegisteredAgents().find((item) => item.name === data.agentName);\n if (!agent) {\n throw new Error(`Unknown agent: ${data.agentName}`);\n }\n\n agent.setSessionMetaMap(new Map(Object.entries(data.meta)));\n\n const isAvailable = agent.isAvailable();\n let sessions: SessionHead[];\n let changedIds: string[] | undefined;\n\n if (!isAvailable) {\n sessions = [];\n } else if (data.sourceSync && agent instanceof FileSystemSessionSource) {\n const result = syncAgentSources(agent, data.previousSessions, data.meta);\n sessions = result.sessions;\n changedIds = result.changedIds;\n } else if (data.changedIds) {\n sessions = await Promise.resolve(agent.incrementalScan(data.previousSessions, data.changedIds));\n } else {\n sessions = await Promise.resolve(\n agent.scan({\n ...data.scanOptions,\n onProgress: (progress) => {\n parentPort?.postMessage({\n type: \"progress\",\n progress,\n } satisfies ScanRefreshWorkerMessage);\n },\n }),\n );\n }\n\n parentPort?.postMessage({\n type: \"done\",\n sessions,\n meta: serializeMeta(agent),\n changedIds,\n durationMs: performance.now() - startedAt,\n } satisfies ScanRefreshWorkerMessage);\n}\n\ntry {\n await run();\n} catch (error) {\n parentPort?.postMessage({\n type: \"error\",\n error: error instanceof Error ? error.message : String(error),\n durationMs: performance.now() - startedAt,\n } satisfies ScanRefreshWorkerMessage);\n}\n"],"mappings":"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","names":["data"]}
1
+ {"version":3,"sources":["../src/scan-refresh-worker.ts"],"sourcesContent":["import { parentPort, workerData } from \"node:worker_threads\";\nimport {\n attachMissingProjectIdentities,\n createRegisteredAgents,\n ensureSessionTagsSync,\n FileSystemSessionSource,\n matchesScanWindow,\n type AgentScanProgress,\n type BaseAgent,\n type ScanOptions,\n type SessionCacheMeta,\n type SessionHead,\n type SessionSourceRef,\n} from \"@codesesh/core\";\n\nexport type ScanRefreshWorkerMessage =\n | {\n type: \"progress\";\n progress: AgentScanProgress;\n }\n | {\n type: \"done\";\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n changedIds?: string[];\n durationMs: number;\n }\n | {\n type: \"error\";\n error: string;\n durationMs: number;\n };\n\ninterface ScanRefreshWorkerData {\n agentName: string;\n previousSessions: SessionHead[];\n changedIds: string[] | null;\n sourceSync?: boolean;\n scanOptions: Pick<ScanOptions, \"from\" | \"to\" | \"fast\">;\n meta: Record<string, SessionCacheMeta>;\n}\n\nfunction serializeMeta(agent: {\n getSessionMetaMap: () => Map<string, SessionCacheMeta>;\n}): Record<string, SessionCacheMeta> {\n const metaMap = agent.getSessionMetaMap();\n const meta: Record<string, SessionCacheMeta> = {};\n for (const [id, data] of metaMap.entries()) {\n meta[id] = { id, ...(data as Record<string, unknown>) } as SessionCacheMeta;\n }\n return meta;\n}\n\nfunction sourceFingerprintFromMeta(meta: SessionCacheMeta | undefined): string | null {\n return typeof meta?.sourceFingerprint === \"string\" ? meta.sourceFingerprint : null;\n}\n\nfunction parseSourceFingerprint(fingerprint: string): unknown[] | null {\n try {\n const parsed = JSON.parse(fingerprint);\n return Array.isArray(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Compare a live source fingerprint against the cached meta. A direct string\n * match is the fast path; the fallback tolerates older cache entries written by\n * a different fingerprint format as long as the underlying mtime (array slot 2)\n * is unchanged, so a fingerprint-format bump does not force a full rescan.\n */\nfunction sourceFingerprintMatches(\n source: SessionSourceRef,\n cachedSession: SessionHead,\n cached: SessionCacheMeta | undefined,\n): boolean {\n if (sourceFingerprintFromMeta(cached) === source.fingerprint) return true;\n\n const current = parseSourceFingerprint(source.fingerprint);\n if (!current || current.length < 5) return false;\n\n return (\n typeof cached?.sourceMtimeMs === \"number\" &&\n cached.sourceMtimeMs === current[2] &&\n (current[4] == null || cachedSession.title === current[4])\n );\n}\n\nfunction sourcePathFromMeta(meta: SessionCacheMeta | undefined): string | null {\n return typeof meta?.sourcePath === \"string\" ? meta.sourcePath : null;\n}\n\n/**\n * A cached session outside the current scan window was never enumerated this\n * pass, so its absence from sourceRefs doesn't mean it was deleted on disk —\n * treat it as still present. Sessions with no recorded mtime predate this\n * field; keep them too rather than risk a false-positive removal.\n */\nfunction wasEnumeratedThisPass(\n cached: SessionCacheMeta | undefined,\n windowOptions: Pick<ScanOptions, \"from\" | \"to\"> | undefined,\n): boolean {\n if (windowOptions?.from == null && windowOptions?.to == null) return true;\n const mtimeMs = cached?.sourceMtimeMs;\n return typeof mtimeMs !== \"number\" || matchesScanWindow(mtimeMs, windowOptions);\n}\n\n/**\n * Source-level incremental sync, mirroring FileSystemSessionSource.incrementalScan.\n * Kept standalone because the worker cannot share the agent's live metaMap with\n * the main thread — it receives cached meta via workerData instead.\n */\nfunction syncAgentSources(\n agent: FileSystemSessionSource,\n cachedSessions: SessionHead[],\n cachedMeta: Record<string, SessionCacheMeta>,\n windowOptions?: Pick<ScanOptions, \"from\" | \"to\">,\n): { sessions: SessionHead[]; changedIds: string[] } {\n const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));\n const sourceRefs = agent.listSessionSources(windowOptions);\n const currentIds = new Set(sourceRefs.map((source) => source.sessionId));\n const changedIds = new Set<string>();\n\n for (const source of sourceRefs) {\n const cachedSession = sessionMap.get(source.sessionId);\n const cached = cachedMeta[source.sessionId];\n const sameSource = sourcePathFromMeta(cached) === source.sourcePath;\n const sameFingerprint =\n cachedSession && sourceFingerprintMatches(source, cachedSession, cached);\n if (cachedSession && sameSource && sameFingerprint) continue;\n\n const next = agent.scanSessionSource(source.sourcePath);\n changedIds.add(source.sessionId);\n if (next) {\n sessionMap.set(next.id, next);\n } else {\n sessionMap.delete(source.sessionId);\n }\n }\n\n for (const session of cachedSessions) {\n if (currentIds.has(session.id)) continue;\n if (!wasEnumeratedThisPass(cachedMeta[session.id], windowOptions)) continue;\n sessionMap.delete(session.id);\n changedIds.add(session.id);\n }\n\n return { sessions: [...sessionMap.values()], changedIds: [...changedIds] };\n}\n\n/**\n * A session still receiving writes will be stale again within seconds, so\n * recomputing its tags every refresh cycle is wasted work — wait for it to\n * settle before paying the getSessionData() parse cost.\n */\nconst TAG_SETTLE_MS = 60_000;\n\nfunction isSettled(session: SessionHead, now: number): boolean {\n return now - (session.time_updated ?? session.time_created) >= TAG_SETTLE_MS;\n}\n\n/**\n * Runs identity resolution (spawns git) and stale smart-tag reclassification\n * on the worker thread, off the server's main event loop.\n */\nexport function finalizeSessions(agent: BaseAgent, sessions: SessionHead[]): SessionHead[] {\n const withIdentity = attachMissingProjectIdentities(sessions);\n\n const now = Date.now();\n const settled = withIdentity.filter((session) => isSettled(session, now));\n if (settled.length === 0) return withIdentity;\n\n const taggedById = new Map(\n ensureSessionTagsSync(agent, settled).sessions.map((session) => [session.id, session]),\n );\n return withIdentity.map((session) => taggedById.get(session.id) ?? session);\n}\n\nconst data = workerData as ScanRefreshWorkerData;\nconst startedAt = performance.now();\n\nasync function run(): Promise<void> {\n const agent = createRegisteredAgents().find((item) => item.name === data.agentName);\n if (!agent) {\n throw new Error(`Unknown agent: ${data.agentName}`);\n }\n\n agent.setSessionMetaMap(new Map(Object.entries(data.meta)));\n\n const isAvailable = agent.isAvailable();\n let sessions: SessionHead[];\n let changedIds: string[] | undefined;\n\n if (!isAvailable) {\n sessions = [];\n } else if (data.sourceSync && agent instanceof FileSystemSessionSource) {\n const result = syncAgentSources(agent, data.previousSessions, data.meta, data.scanOptions);\n sessions = result.sessions;\n changedIds = result.changedIds;\n } else if (data.changedIds) {\n sessions = await Promise.resolve(agent.incrementalScan(data.previousSessions, data.changedIds));\n } else {\n sessions = await Promise.resolve(\n agent.scan({\n ...data.scanOptions,\n onProgress: (progress) => {\n parentPort?.postMessage({\n type: \"progress\",\n progress,\n } satisfies ScanRefreshWorkerMessage);\n },\n }),\n );\n }\n\n sessions = finalizeSessions(agent, sessions);\n\n parentPort?.postMessage({\n type: \"done\",\n sessions,\n meta: serializeMeta(agent),\n changedIds,\n durationMs: performance.now() - startedAt,\n } satisfies ScanRefreshWorkerMessage);\n}\n\ntry {\n await run();\n} catch (error) {\n parentPort?.postMessage({\n type: \"error\",\n error: error instanceof Error ? error.message : String(error),\n durationMs: performance.now() - startedAt,\n } satisfies ScanRefreshWorkerMessage);\n}\n"],"mappings":"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","names":["data"]}
@@ -1,16 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createRegisteredAgents,
4
+ getCachePath2,
4
5
  markAgentCacheInitialized,
5
6
  saveCachedSessionChanges,
6
7
  saveCachedSessions,
8
+ setFtsIntegrityCheckedPath,
7
9
  syncSessionSearchIndex,
8
10
  syncSessionSearchIndexChanges
9
- } from "./chunk-BIXOP5QX.js";
11
+ } from "./chunk-BV65IEWZ.js";
10
12
 
11
13
  // src/search-index-worker.ts
12
14
  import { parentPort, workerData } from "worker_threads";
13
15
  var data = workerData;
16
+ if (data.skipFtsIntegrityCheck) {
17
+ setFtsIntegrityCheckedPath(getCachePath2());
18
+ }
14
19
  var startedAt = performance.now();
15
20
  var agents = createRegisteredAgents();
16
21
  var jobs = data.jobs ?? data.agentNames.map(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/search-index-worker.ts"],"sourcesContent":["import { parentPort, workerData } from \"node:worker_threads\";\nimport {\n createRegisteredAgents,\n markAgentCacheInitialized,\n saveCachedSessionChanges,\n saveCachedSessions,\n syncSessionSearchIndex,\n syncSessionSearchIndexChanges,\n type SearchIndexSyncResult,\n type SearchIndexSyncOptions,\n type SessionCacheMeta,\n type SessionHeadChange,\n type SessionHead,\n} from \"@codesesh/core\";\n\nexport type SearchIndexWorkerMessage =\n | {\n type: \"sync-result\";\n context: string;\n result: SearchIndexSyncResult | null;\n }\n | {\n type: \"done\";\n context: string;\n durationMs: number;\n sessions: number;\n };\n\nexport type SearchIndexWorkerJob =\n | {\n kind: \"full\";\n context: string;\n agentName: string;\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n saveCache?: boolean;\n searchIndexOptions?: SearchIndexSyncOptions;\n }\n | {\n kind: \"changes\";\n context: string;\n agentName: string;\n changes: SessionHeadChange[];\n removedSessionIds: string[];\n meta: Record<string, SessionCacheMeta>;\n searchIndexOptions?: SearchIndexSyncOptions;\n };\n\ninterface SearchIndexWorkerData {\n jobs?: SearchIndexWorkerJob[];\n context: string;\n agentNames: string[];\n sessionsByAgent: Record<string, SessionHead[]>;\n metaByAgent: Record<string, Record<string, SessionCacheMeta>>;\n}\n\nconst data = workerData as SearchIndexWorkerData;\nconst startedAt = performance.now();\nconst agents = createRegisteredAgents();\nconst jobs =\n data.jobs ??\n data.agentNames.map(\n (agentName): SearchIndexWorkerJob => ({\n kind: \"full\",\n context: data.context,\n agentName,\n sessions: data.sessionsByAgent[agentName] ?? [],\n meta: data.metaByAgent[agentName] ?? {},\n }),\n );\n\nfor (const job of jobs) {\n const agent = agents.find((item) => item.name === job.agentName);\n if (!agent) continue;\n\n if (agent.setSessionMetaMap) {\n agent.setSessionMetaMap(new Map(Object.entries(job.meta)));\n }\n\n let result: SearchIndexSyncResult | null;\n if (job.kind === \"changes\") {\n saveCachedSessionChanges(job.agentName, job.changes, job.removedSessionIds, job.meta);\n result = syncSessionSearchIndexChanges(\n job.agentName,\n job.changes,\n job.removedSessionIds,\n (sessionId) => agent.getSessionData(sessionId),\n job.searchIndexOptions,\n );\n } else {\n if (job.saveCache) {\n saveCachedSessions(job.agentName, job.sessions, job.meta);\n }\n result = syncSessionSearchIndex(\n job.agentName,\n job.sessions,\n (sessionId) => agent.getSessionData(sessionId),\n job.searchIndexOptions,\n );\n if (job.saveCache && result?.skipped === 0) {\n markAgentCacheInitialized(job.agentName);\n }\n }\n parentPort?.postMessage({\n type: \"sync-result\",\n context: job.context,\n result,\n } satisfies SearchIndexWorkerMessage);\n}\n\nparentPort?.postMessage({\n type: \"done\",\n context: data.context,\n durationMs: performance.now() - startedAt,\n sessions: jobs.reduce(\n (total, job) => total + (job.kind === \"full\" ? job.sessions.length : job.changes.length),\n 0,\n ),\n} satisfies SearchIndexWorkerMessage);\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,YAAY,kBAAkB;AAwDvC,IAAM,OAAO;AACb,IAAM,YAAY,YAAY,IAAI;AAClC,IAAM,SAAS,uBAAuB;AACtC,IAAM,OACJ,KAAK,QACL,KAAK,WAAW;AAAA,EACd,CAAC,eAAqC;AAAA,IACpC,MAAM;AAAA,IACN,SAAS,KAAK;AAAA,IACd;AAAA,IACA,UAAU,KAAK,gBAAgB,SAAS,KAAK,CAAC;AAAA,IAC9C,MAAM,KAAK,YAAY,SAAS,KAAK,CAAC;AAAA,EACxC;AACF;AAEF,WAAW,OAAO,MAAM;AACtB,QAAM,QAAQ,OAAO,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS;AAC/D,MAAI,CAAC,MAAO;AAEZ,MAAI,MAAM,mBAAmB;AAC3B,UAAM,kBAAkB,IAAI,IAAI,OAAO,QAAQ,IAAI,IAAI,CAAC,CAAC;AAAA,EAC3D;AAEA,MAAI;AACJ,MAAI,IAAI,SAAS,WAAW;AAC1B,6BAAyB,IAAI,WAAW,IAAI,SAAS,IAAI,mBAAmB,IAAI,IAAI;AACpF,aAAS;AAAA,MACP,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,CAAC,cAAc,MAAM,eAAe,SAAS;AAAA,MAC7C,IAAI;AAAA,IACN;AAAA,EACF,OAAO;AACL,QAAI,IAAI,WAAW;AACjB,yBAAmB,IAAI,WAAW,IAAI,UAAU,IAAI,IAAI;AAAA,IAC1D;AACA,aAAS;AAAA,MACP,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,CAAC,cAAc,MAAM,eAAe,SAAS;AAAA,MAC7C,IAAI;AAAA,IACN;AACA,QAAI,IAAI,aAAa,QAAQ,YAAY,GAAG;AAC1C,gCAA0B,IAAI,SAAS;AAAA,IACzC;AAAA,EACF;AACA,cAAY,YAAY;AAAA,IACtB,MAAM;AAAA,IACN,SAAS,IAAI;AAAA,IACb;AAAA,EACF,CAAoC;AACtC;AAEA,YAAY,YAAY;AAAA,EACtB,MAAM;AAAA,EACN,SAAS,KAAK;AAAA,EACd,YAAY,YAAY,IAAI,IAAI;AAAA,EAChC,UAAU,KAAK;AAAA,IACb,CAAC,OAAO,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,SAAS,SAAS,IAAI,QAAQ;AAAA,IACjF;AAAA,EACF;AACF,CAAoC;","names":[]}
1
+ {"version":3,"sources":["../src/search-index-worker.ts"],"sourcesContent":["import { parentPort, workerData } from \"node:worker_threads\";\nimport {\n createRegisteredAgents,\n getCachePath,\n markAgentCacheInitialized,\n saveCachedSessionChanges,\n saveCachedSessions,\n setFtsIntegrityCheckedPath,\n syncSessionSearchIndex,\n syncSessionSearchIndexChanges,\n type SearchIndexSyncResult,\n type SearchIndexSyncOptions,\n type SessionCacheMeta,\n type SessionHeadChange,\n type SessionHead,\n} from \"@codesesh/core\";\n\nexport type SearchIndexWorkerMessage =\n | {\n type: \"sync-result\";\n context: string;\n result: SearchIndexSyncResult | null;\n }\n | {\n type: \"done\";\n context: string;\n durationMs: number;\n sessions: number;\n };\n\nexport type SearchIndexWorkerJob =\n | {\n kind: \"full\";\n context: string;\n agentName: string;\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n saveCache?: boolean;\n searchIndexOptions?: SearchIndexSyncOptions;\n }\n | {\n kind: \"changes\";\n context: string;\n agentName: string;\n changes: SessionHeadChange[];\n removedSessionIds: string[];\n meta: Record<string, SessionCacheMeta>;\n searchIndexOptions?: SearchIndexSyncOptions;\n };\n\ninterface SearchIndexWorkerData {\n jobs?: SearchIndexWorkerJob[];\n context: string;\n agentNames: string[];\n sessionsByAgent: Record<string, SessionHead[]>;\n metaByAgent: Record<string, Record<string, SessionCacheMeta>>;\n /** Set once this process has already run the FTS integrity check in an earlier batch. */\n skipFtsIntegrityCheck?: boolean;\n}\n\nconst data = workerData as SearchIndexWorkerData;\nif (data.skipFtsIntegrityCheck) {\n setFtsIntegrityCheckedPath(getCachePath());\n}\nconst startedAt = performance.now();\nconst agents = createRegisteredAgents();\nconst jobs =\n data.jobs ??\n data.agentNames.map(\n (agentName): SearchIndexWorkerJob => ({\n kind: \"full\",\n context: data.context,\n agentName,\n sessions: data.sessionsByAgent[agentName] ?? [],\n meta: data.metaByAgent[agentName] ?? {},\n }),\n );\n\nfor (const job of jobs) {\n const agent = agents.find((item) => item.name === job.agentName);\n if (!agent) continue;\n\n if (agent.setSessionMetaMap) {\n agent.setSessionMetaMap(new Map(Object.entries(job.meta)));\n }\n\n let result: SearchIndexSyncResult | null;\n if (job.kind === \"changes\") {\n saveCachedSessionChanges(job.agentName, job.changes, job.removedSessionIds, job.meta);\n result = syncSessionSearchIndexChanges(\n job.agentName,\n job.changes,\n job.removedSessionIds,\n (sessionId) => agent.getSessionData(sessionId),\n job.searchIndexOptions,\n );\n } else {\n if (job.saveCache) {\n saveCachedSessions(job.agentName, job.sessions, job.meta);\n }\n result = syncSessionSearchIndex(\n job.agentName,\n job.sessions,\n (sessionId) => agent.getSessionData(sessionId),\n job.searchIndexOptions,\n );\n if (job.saveCache && result?.skipped === 0) {\n markAgentCacheInitialized(job.agentName);\n }\n }\n parentPort?.postMessage({\n type: \"sync-result\",\n context: job.context,\n result,\n } satisfies SearchIndexWorkerMessage);\n}\n\nparentPort?.postMessage({\n type: \"done\",\n context: data.context,\n durationMs: performance.now() - startedAt,\n sessions: jobs.reduce(\n (total, job) => total + (job.kind === \"full\" ? job.sessions.length : job.changes.length),\n 0,\n ),\n} satisfies SearchIndexWorkerMessage);\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,YAAY,kBAAkB;AA4DvC,IAAM,OAAO;AACb,IAAI,KAAK,uBAAuB;AAC9B,6BAA2B,cAAa,CAAC;AAC3C;AACA,IAAM,YAAY,YAAY,IAAI;AAClC,IAAM,SAAS,uBAAuB;AACtC,IAAM,OACJ,KAAK,QACL,KAAK,WAAW;AAAA,EACd,CAAC,eAAqC;AAAA,IACpC,MAAM;AAAA,IACN,SAAS,KAAK;AAAA,IACd;AAAA,IACA,UAAU,KAAK,gBAAgB,SAAS,KAAK,CAAC;AAAA,IAC9C,MAAM,KAAK,YAAY,SAAS,KAAK,CAAC;AAAA,EACxC;AACF;AAEF,WAAW,OAAO,MAAM;AACtB,QAAM,QAAQ,OAAO,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS;AAC/D,MAAI,CAAC,MAAO;AAEZ,MAAI,MAAM,mBAAmB;AAC3B,UAAM,kBAAkB,IAAI,IAAI,OAAO,QAAQ,IAAI,IAAI,CAAC,CAAC;AAAA,EAC3D;AAEA,MAAI;AACJ,MAAI,IAAI,SAAS,WAAW;AAC1B,6BAAyB,IAAI,WAAW,IAAI,SAAS,IAAI,mBAAmB,IAAI,IAAI;AACpF,aAAS;AAAA,MACP,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,CAAC,cAAc,MAAM,eAAe,SAAS;AAAA,MAC7C,IAAI;AAAA,IACN;AAAA,EACF,OAAO;AACL,QAAI,IAAI,WAAW;AACjB,yBAAmB,IAAI,WAAW,IAAI,UAAU,IAAI,IAAI;AAAA,IAC1D;AACA,aAAS;AAAA,MACP,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,CAAC,cAAc,MAAM,eAAe,SAAS;AAAA,MAC7C,IAAI;AAAA,IACN;AACA,QAAI,IAAI,aAAa,QAAQ,YAAY,GAAG;AAC1C,gCAA0B,IAAI,SAAS;AAAA,IACzC;AAAA,EACF;AACA,cAAY,YAAY;AAAA,IACtB,MAAM;AAAA,IACN,SAAS,IAAI;AAAA,IACb;AAAA,EACF,CAAoC;AACtC;AAEA,YAAY,YAAY;AAAA,EACtB,MAAM;AAAA,EACN,SAAS,KAAK;AAAA,EACd,YAAY,YAAY,IAAI,IAAI;AAAA,EAChC,UAAU,KAAK;AAAA,IACb,CAAC,OAAO,QAAQ,SAAS,IAAI,SAAS,SAAS,IAAI,SAAS,SAAS,IAAI,QAAQ;AAAA,IACjF;AAAA,EACF;AACF,CAAoC;","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  classifySessionTags,
4
4
  createRegisteredAgents,
5
5
  getSmartTagSourceTimestamp
6
- } from "./chunk-BIXOP5QX.js";
6
+ } from "./chunk-BV65IEWZ.js";
7
7
 
8
8
  // src/smart-tag-worker.ts
9
9
  import { parentPort, workerData } from "worker_threads";