@iworkforces/tracelattice 2.3.5 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -5
- package/dist/ServerConfig.d.ts +16 -0
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js +11 -0
- package/dist/ServerConfig.js.map +1 -1
- package/dist/cli.js +239 -22
- package/dist/cli.js.map +1 -1
- package/dist/config/ConfigLoader.d.ts +2 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +2 -0
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts +26 -0
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/persistence-backlog.d.ts +21 -0
- package/dist/contracts/persistence-backlog.d.ts.map +1 -0
- package/dist/contracts/persistence-backlog.js +1 -0
- package/dist/core/HistoryManager.d.ts +15 -1
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +12 -2
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +2 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +25 -0
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +27 -5
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceBufferErrors.d.ts +10 -0
- package/dist/core/PersistenceBufferErrors.d.ts.map +1 -1
- package/dist/core/PersistenceBufferErrors.js +13 -1
- package/dist/core/PersistenceBufferErrors.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +25 -30
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWorkQueue.d.ts +9 -0
- package/dist/core/PersistenceWorkQueue.d.ts.map +1 -1
- package/dist/core/PersistenceWorkQueue.js +18 -0
- package/dist/core/PersistenceWorkQueue.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +6 -0
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +15 -1
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +3 -10
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/evaluator/VerificationLinks.d.ts +5 -0
- package/dist/core/evaluator/VerificationLinks.d.ts.map +1 -1
- package/dist/core/evaluator/VerificationLinks.js +47 -53
- package/dist/core/evaluator/VerificationLinks.js.map +1 -1
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts.map +1 -1
- package/dist/core/reasoning/ActiveEvidenceProjection.js +4 -3
- package/dist/core/reasoning/ActiveEvidenceProjection.js.map +1 -1
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -1
- package/dist/errors.js.map +1 -1
- package/dist/health/HealthChecker.d.ts +42 -1
- package/dist/health/HealthChecker.d.ts.map +1 -1
- package/dist/health/HealthChecker.js +60 -8
- package/dist/health/HealthChecker.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/metrics/metrics.impl.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +2 -1
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +6 -1
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -0
- package/dist/persistence/FileSnapshotV2.d.ts.map +1 -1
- package/dist/persistence/FileSnapshotV2.js +39 -1
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +4 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +30 -0
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +6 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +31 -4
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +12 -0
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +19 -5
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/package.json +20 -20
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/FilePersistence.js","sources":["../../src/persistence/FilePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport type { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError } from '../errors.js';\nimport {\n\tEMPTY_FILE_SNAPSHOT_V2,\n\tparseFileSnapshotV2,\n\tserializeFileSnapshotV2,\n\tsessionsInSnapshot,\n} from './FileSnapshotV2.js';\nimport type { FileSnapshotV2 } from './FileSnapshotTypes.js';\nimport { stageBacktrackPersistence } from './BacktrackPersistence.js';\nimport { FILE_WRITER_LOCK_NAME, FileWriter, type FileWriterOperations } from './FileWriter.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n} from './PersistenceScope.js';\n\ntype FilePersistenceOptions = NonNullable<PersistenceConfig['options']> & {\n\treadonly metrics?: IMetrics;\n\treadonly writerOperations?: FileWriterOperations;\n};\n\nconst SNAPSHOT_NAME = 'snapshot.json';\n\nexport class FilePersistence implements PersistenceBackend {\n\tprivate readonly _dataDir: string;\n\tprivate readonly _maxHistorySize: number;\n\tprivate readonly _persistBranches: boolean;\n\tprivate readonly _metrics: IMetrics | undefined;\n\tprivate readonly _writer: FileWriter;\n\n\tconstructor(options?: FilePersistenceOptions) {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tthis._dataDir = options?.dataDir ?? defaultDataDir;\n\t\tthis._maxHistorySize = options?.maxHistorySize ?? 10000;\n\t\tthis._persistBranches = options?.persistBranches ?? true;\n\t\tthis._metrics = options?.metrics;\n\t\tthis._writer = new FileWriter(this._dataDir, options?.writerOperations);\n\t}\n\n\tpublic static async create(options?: FilePersistenceOptions): Promise<FilePersistence> {\n\t\tconst persistence = new FilePersistence(options);\n\t\ttry {\n\t\t\tawait persistence._writer.ready();\n\t\t\tawait persistence._writer.run(async (dataDir) => await persistence._loadSnapshot(dataDir));\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tawait persistence.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tawait this._saveThought(validatedSessionId, thought);\n\t}\n\n\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tawait this._mutate('save_backtrack', (snapshot) => {\n\t\t\tconst staged = stageBacktrackPersistence(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === validatedSessionId)?.thoughts ?? [],\n\t\t\t\tsnapshot.branches\n\t\t\t\t\t.filter((record) => record.sessionId === validatedSessionId)\n\t\t\t\t\t.map((record) => ({ branchId: record.branchId, thoughts: record.thoughts })),\n\t\t\t\tthought,\n\t\t\t\ttargetThoughtId,\n\t\t\t\tthis._maxHistorySize\n\t\t\t);\n\t\t\treturn {\n\t\t\t\t...snapshot,\n\t\t\t\tthoughts: [\n\t\t\t\t\t...snapshot.thoughts.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t\t{ sessionId: validatedSessionId, thoughts: staged.history },\n\t\t\t\t],\n\t\t\t\tbranches: [\n\t\t\t\t\t...snapshot.branches.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t\t...staged.branches.map((branch) => ({\n\t\t\t\t\t\tsessionId: validatedSessionId,\n\t\t\t\t\t\tbranchId: branch.branchId,\n\t\t\t\t\t\tthoughts: branch.thoughts,\n\t\t\t\t\t})),\n\t\t\t\t],\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate async _saveThought(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tassertPersistableThoughts([thought], `${sessionId}/thoughts`);\n\t\tawait this._mutate('save_thought', (snapshot) => {\n\t\t\tconst current =\n\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [];\n\t\t\tconst prospective = [...current, thought];\n\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t[\n\t\t\t\t\t{ sessionId, thoughts: prospective },\n\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t],\n\t\t\t\t`${sessionId}/thoughts`\n\t\t\t);\n\t\t\tconst retained =\n\t\t\t\tthis._maxHistorySize > 0 ? prospective.slice(-this._maxHistorySize) : prospective;\n\t\t\treturn {\n\t\t\t\t...snapshot,\n\t\t\t\tthoughts: [\n\t\t\t\t\t...snapshot.thoughts.filter((record) => record.sessionId !== sessionId),\n\t\t\t\t\t{ sessionId, thoughts: retained },\n\t\t\t\t],\n\t\t\t};\n\t\t});\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('load_history', (snapshot) => [\n\t\t\t...(snapshot.thoughts.find((record) => record.sessionId === validatedSessionId)?.thoughts ??\n\t\t\t\t[]),\n\t\t]);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tawait this._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate async _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tassertPersistableThoughtCollections(\n\t\t\t[{ sessionId, thoughts }],\n\t\t\t`${sessionId}/branches/${branchId}`\n\t\t);\n\t\tif (!this._persistBranches) {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshot = await this._loadSnapshot(dataDir);\n\t\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tthoughts:\n\t\t\t\t\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [],\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t\t\t{ sessionId, thoughts },\n\t\t\t\t\t],\n\t\t\t\t\t`${sessionId}/branches/${branchId}`\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tawait this._mutate('save_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: [\n\t\t\t\t...snapshot.branches.filter(\n\t\t\t\t\t(record) => record.sessionId !== sessionId || record.branchId !== branchId\n\t\t\t\t),\n\t\t\t\t{ sessionId, branchId, thoughts: [...thoughts] },\n\t\t\t],\n\t\t}));\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tawait this._mutate('delete_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: snapshot.branches.filter(\n\t\t\t\t(record) => record.sessionId !== validatedSessionId || record.branchId !== validatedBranchId\n\t\t\t),\n\t\t}));\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\treturn await this._read('load_branch', (snapshot) => {\n\t\t\tconst thoughts = snapshot.branches.find(\n\t\t\t\t(record) => record.sessionId === validatedSessionId && record.branchId === validatedBranchId\n\t\t\t)?.thoughts;\n\t\t\treturn thoughts === undefined ? undefined : [...thoughts];\n\t\t});\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('list_branches', (snapshot) =>\n\t\t\tsnapshot.branches\n\t\t\t\t.filter((record) => record.sessionId === validatedSessionId)\n\t\t\t\t.map((record) => record.branchId)\n\t\t\t\t.sort(compareCodePoint)\n\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn await this._read('list_sessions', sessionsInSnapshot);\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\tawait this._mutate('clear_all', () => EMPTY_FILE_SNAPSHOT_V2);\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tawait this._mutate('clear_session', (snapshot) => ({\n\t\t\tversion: 2,\n\t\t\tthoughts: snapshot.thoughts.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tbranches: snapshot.branches.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tedges: snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tsummaries: snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\n\t\t}));\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\tawait this._mutate('save_edges', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tedges: [\n\t\t\t\t...snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(edges.length === 0 ? [] : [{ sessionId: validatedSessionId, edges: [...edges] }]),\n\t\t\t],\n\t\t}));\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('load_edges', (snapshot) => [\n\t\t\t...(snapshot.edges.find((record) => record.sessionId === validatedSessionId)?.edges ?? []),\n\t\t]);\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\tawait this._mutate('save_summaries', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tsummaries: [\n\t\t\t\t...snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(summaries.length === 0\n\t\t\t\t\t? []\n\t\t\t\t\t: [{ sessionId: validatedSessionId, summaries: [...summaries] }]),\n\t\t\t],\n\t\t}));\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('load_summaries', (snapshot) => [\n\t\t\t...(snapshot.summaries.find((record) => record.sessionId === validatedSessionId)?.summaries ??\n\t\t\t\t[]),\n\t\t]);\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tawait this._writer.run(async (dataDir) => await this._loadSnapshot(dataDir));\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic getDataDir(): string {\n\t\treturn this._dataDir;\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tawait this._writer.close();\n\t}\n\n\tprivate async _read<T>(operation: string, select: (snapshot: FileSnapshotV2) => T): Promise<T> {\n\t\treturn await this._measure(\n\t\t\toperation,\n\t\t\tasync () =>\n\t\t\t\tawait this._writer.run(async (dataDir) => select(await this._loadSnapshot(dataDir)))\n\t\t);\n\t}\n\n\tprivate async _mutate(\n\t\toperation: string,\n\t\tmutate: (snapshot: FileSnapshotV2) => FileSnapshotV2\n\t): Promise<void> {\n\t\tawait this._measure(operation, async () => {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\t\t\tconst updated = mutate(await this._loadSnapshot(dataDir));\n\t\t\t\tawait this._writer.publish(snapshotPath, serializeFileSnapshotV2(updated, snapshotPath));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate async _loadSnapshot(dataDir: string): Promise<FileSnapshotV2> {\n\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\tconst layoutEntries = (await readdir(dataDir)).filter(\n\t\t\t(entry) => entry !== FILE_WRITER_LOCK_NAME\n\t\t);\n\t\tif (layoutEntries.length === 0) return EMPTY_FILE_SNAPSHOT_V2;\n\t\tif (layoutEntries.length !== 1 || layoutEntries[0] !== SNAPSHOT_NAME) {\n\t\t\tthrow new PersistenceCompatibilityError(dataDir, 'directory does not match File v2 layout');\n\t\t}\n\t\treturn parseFileSnapshotV2(await readFile(snapshotPath, 'utf-8'), snapshotPath);\n\t}\n\n\tprivate async _measure<T>(operation: string, action: () => Promise<T>): Promise<T> {\n\t\tconst startTime = Date.now();\n\t\ttry {\n\t\t\treturn await action();\n\t\t} finally {\n\t\t\tthis._metrics?.histogram('persistence_op_duration_seconds', (Date.now() - startTime) / 1000, {\n\t\t\t\toperation,\n\t\t\t});\n\t\t}\n\t}\n}\n"],"names":["SNAPSHOT_NAME","FilePersistence","options","defaultDataDir","existsSync","join","homedir","FileWriter","persistence","dataDir","error","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","targetThoughtId","snapshot","staged","stageBacktrackPersistence","record","branch","assertPersistableThoughts","current","prospective","assertPersistableThoughtCollections","retained","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","undefined","compareCodePoint","sessionsInSnapshot","EMPTY_FILE_SNAPSHOT_V2","edges","assertEdgeScopes","summaries","assertSummaryScopes","Error","operation","select","mutate","snapshotPath","updated","serializeFileSnapshotV2","layoutEntries","readdir","entry","FILE_WRITER_LOCK_NAME","PersistenceCompatibilityError","parseFileSnapshotV2","readFile","action","startTime","Date"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persistence/FilePersistence.js","sources":["../../src/persistence/FilePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport type {\n\tPersistenceConfig,\n\tPersistenceBackend,\n\tPersistenceRestoreRead,\n} from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError } from '../errors.js';\nimport {\n\tEMPTY_FILE_SNAPSHOT_V2,\n\tparseFileSnapshotV2,\n\trestoreRecordsInSnapshot,\n\tserializeFileSnapshotV2,\n\tsessionsInSnapshot,\n} from './FileSnapshotV2.js';\nimport type { FileSnapshotV2 } from './FileSnapshotTypes.js';\nimport { stageBacktrackPersistence } from './BacktrackPersistence.js';\nimport { FILE_WRITER_LOCK_NAME, FileWriter, type FileWriterOperations } from './FileWriter.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n} from './PersistenceScope.js';\n\ntype FilePersistenceOptions = NonNullable<PersistenceConfig['options']> & {\n\treadonly metrics?: IMetrics;\n\treadonly writerOperations?: FileWriterOperations;\n};\n\nconst SNAPSHOT_NAME = 'snapshot.json';\n\nexport class FilePersistence implements PersistenceBackend {\n\tprivate readonly _dataDir: string;\n\tprivate readonly _maxHistorySize: number;\n\tprivate readonly _persistBranches: boolean;\n\tprivate readonly _metrics: IMetrics | undefined;\n\tprivate readonly _writer: FileWriter;\n\n\tconstructor(options?: FilePersistenceOptions) {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tthis._dataDir = options?.dataDir ?? defaultDataDir;\n\t\tthis._maxHistorySize = options?.maxHistorySize ?? 10000;\n\t\tthis._persistBranches = options?.persistBranches ?? true;\n\t\tthis._metrics = options?.metrics;\n\t\tthis._writer = new FileWriter(this._dataDir, options?.writerOperations);\n\t}\n\n\tpublic static async create(options?: FilePersistenceOptions): Promise<FilePersistence> {\n\t\tconst persistence = new FilePersistence(options);\n\t\ttry {\n\t\t\tawait persistence._writer.ready();\n\t\t\tawait persistence._writer.run(async (dataDir) => await persistence._loadSnapshot(dataDir));\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tawait persistence.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tawait this._saveThought(validatedSessionId, thought);\n\t}\n\n\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tawait this._mutate('save_backtrack', (snapshot) => {\n\t\t\tconst staged = stageBacktrackPersistence(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === validatedSessionId)?.thoughts ?? [],\n\t\t\t\tsnapshot.branches\n\t\t\t\t\t.filter((record) => record.sessionId === validatedSessionId)\n\t\t\t\t\t.map((record) => ({ branchId: record.branchId, thoughts: record.thoughts })),\n\t\t\t\tthought,\n\t\t\t\ttargetThoughtId,\n\t\t\t\tthis._maxHistorySize\n\t\t\t);\n\t\t\treturn {\n\t\t\t\t...snapshot,\n\t\t\t\tthoughts: [\n\t\t\t\t\t...snapshot.thoughts.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t\t{ sessionId: validatedSessionId, thoughts: staged.history },\n\t\t\t\t],\n\t\t\t\tbranches: [\n\t\t\t\t\t...snapshot.branches.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t\t...staged.branches.map((branch) => ({\n\t\t\t\t\t\tsessionId: validatedSessionId,\n\t\t\t\t\t\tbranchId: branch.branchId,\n\t\t\t\t\t\tthoughts: branch.thoughts,\n\t\t\t\t\t})),\n\t\t\t\t],\n\t\t\t};\n\t\t});\n\t}\n\n\tprivate async _saveThought(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tassertPersistableThoughts([thought], `${sessionId}/thoughts`);\n\t\tawait this._mutate('save_thought', (snapshot) => {\n\t\t\tconst current =\n\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [];\n\t\t\tconst prospective = [...current, thought];\n\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t[\n\t\t\t\t\t{ sessionId, thoughts: prospective },\n\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t],\n\t\t\t\t`${sessionId}/thoughts`\n\t\t\t);\n\t\t\tconst retained =\n\t\t\t\tthis._maxHistorySize > 0 ? prospective.slice(-this._maxHistorySize) : prospective;\n\t\t\treturn {\n\t\t\t\t...snapshot,\n\t\t\t\tthoughts: [\n\t\t\t\t\t...snapshot.thoughts.filter((record) => record.sessionId !== sessionId),\n\t\t\t\t\t{ sessionId, thoughts: retained },\n\t\t\t\t],\n\t\t\t};\n\t\t});\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('load_history', (snapshot) => [\n\t\t\t...(snapshot.thoughts.find((record) => record.sessionId === validatedSessionId)?.thoughts ??\n\t\t\t\t[]),\n\t\t]);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tawait this._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate async _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tassertPersistableThoughtCollections(\n\t\t\t[{ sessionId, thoughts }],\n\t\t\t`${sessionId}/branches/${branchId}`\n\t\t);\n\t\tif (!this._persistBranches) {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshot = await this._loadSnapshot(dataDir);\n\t\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tthoughts:\n\t\t\t\t\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [],\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t\t\t{ sessionId, thoughts },\n\t\t\t\t\t],\n\t\t\t\t\t`${sessionId}/branches/${branchId}`\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tawait this._mutate('save_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: [\n\t\t\t\t...snapshot.branches.filter(\n\t\t\t\t\t(record) => record.sessionId !== sessionId || record.branchId !== branchId\n\t\t\t\t),\n\t\t\t\t{ sessionId, branchId, thoughts: [...thoughts] },\n\t\t\t],\n\t\t}));\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tawait this._mutate('delete_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: snapshot.branches.filter(\n\t\t\t\t(record) => record.sessionId !== validatedSessionId || record.branchId !== validatedBranchId\n\t\t\t),\n\t\t}));\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\treturn await this._read('load_branch', (snapshot) => {\n\t\t\tconst thoughts = snapshot.branches.find(\n\t\t\t\t(record) => record.sessionId === validatedSessionId && record.branchId === validatedBranchId\n\t\t\t)?.thoughts;\n\t\t\treturn thoughts === undefined ? undefined : [...thoughts];\n\t\t});\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('list_branches', (snapshot) =>\n\t\t\tsnapshot.branches\n\t\t\t\t.filter((record) => record.sessionId === validatedSessionId)\n\t\t\t\t.map((record) => record.branchId)\n\t\t\t\t.sort(compareCodePoint)\n\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn await this._read('list_sessions', sessionsInSnapshot);\n\t}\n\n\tpublic async loadAllSessionsForRestore(): Promise<PersistenceRestoreRead> {\n\t\treturn await this._read('load_restore', (snapshot) => ({\n\t\t\tsessions: restoreRecordsInSnapshot(snapshot, this._persistBranches),\n\t\t}));\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\tawait this._mutate('clear_all', () => EMPTY_FILE_SNAPSHOT_V2);\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tawait this._mutate('clear_session', (snapshot) => ({\n\t\t\tversion: 2,\n\t\t\tthoughts: snapshot.thoughts.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tbranches: snapshot.branches.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tedges: snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tsummaries: snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\n\t\t}));\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\tawait this._mutate('save_edges', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tedges: [\n\t\t\t\t...snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(edges.length === 0 ? [] : [{ sessionId: validatedSessionId, edges: [...edges] }]),\n\t\t\t],\n\t\t}));\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('load_edges', (snapshot) => [\n\t\t\t...(snapshot.edges.find((record) => record.sessionId === validatedSessionId)?.edges ?? []),\n\t\t]);\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\tawait this._mutate('save_summaries', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tsummaries: [\n\t\t\t\t...snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(summaries.length === 0\n\t\t\t\t\t? []\n\t\t\t\t\t: [{ sessionId: validatedSessionId, summaries: [...summaries] }]),\n\t\t\t],\n\t\t}));\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('load_summaries', (snapshot) => [\n\t\t\t...(snapshot.summaries.find((record) => record.sessionId === validatedSessionId)?.summaries ??\n\t\t\t\t[]),\n\t\t]);\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tawait this._writer.run(async (dataDir) => await this._loadSnapshot(dataDir));\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic getDataDir(): string {\n\t\treturn this._dataDir;\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tawait this._writer.close();\n\t}\n\n\tprivate async _read<T>(operation: string, select: (snapshot: FileSnapshotV2) => T): Promise<T> {\n\t\treturn await this._measure(\n\t\t\toperation,\n\t\t\tasync () =>\n\t\t\t\tawait this._writer.run(async (dataDir) => select(await this._loadSnapshot(dataDir)))\n\t\t);\n\t}\n\n\tprivate async _mutate(\n\t\toperation: string,\n\t\tmutate: (snapshot: FileSnapshotV2) => FileSnapshotV2\n\t): Promise<void> {\n\t\tawait this._measure(operation, async () => {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\t\t\tconst updated = mutate(await this._loadSnapshot(dataDir));\n\t\t\t\tawait this._writer.publish(snapshotPath, serializeFileSnapshotV2(updated, snapshotPath));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate async _loadSnapshot(dataDir: string): Promise<FileSnapshotV2> {\n\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\tconst layoutEntries = (await readdir(dataDir)).filter(\n\t\t\t(entry) => entry !== FILE_WRITER_LOCK_NAME\n\t\t);\n\t\tif (layoutEntries.length === 0) return EMPTY_FILE_SNAPSHOT_V2;\n\t\tif (layoutEntries.length !== 1 || layoutEntries[0] !== SNAPSHOT_NAME) {\n\t\t\tthrow new PersistenceCompatibilityError(dataDir, 'directory does not match File v2 layout');\n\t\t}\n\t\treturn parseFileSnapshotV2(await readFile(snapshotPath, 'utf-8'), snapshotPath);\n\t}\n\n\tprivate async _measure<T>(operation: string, action: () => Promise<T>): Promise<T> {\n\t\tconst startTime = Date.now();\n\t\ttry {\n\t\t\treturn await action();\n\t\t} finally {\n\t\t\tthis._metrics?.histogram('persistence_op_duration_seconds', (Date.now() - startTime) / 1000, {\n\t\t\t\toperation,\n\t\t\t});\n\t\t}\n\t}\n}\n"],"names":["SNAPSHOT_NAME","FilePersistence","options","defaultDataDir","existsSync","join","homedir","FileWriter","persistence","dataDir","error","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","targetThoughtId","snapshot","staged","stageBacktrackPersistence","record","branch","assertPersistableThoughts","current","prospective","assertPersistableThoughtCollections","retained","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","undefined","compareCodePoint","sessionsInSnapshot","restoreRecordsInSnapshot","EMPTY_FILE_SNAPSHOT_V2","edges","assertEdgeScopes","summaries","assertSummaryScopes","Error","operation","select","mutate","snapshotPath","updated","serializeFileSnapshotV2","layoutEntries","readdir","entry","FILE_WRITER_LOCK_NAME","PersistenceCompatibilityError","parseFileSnapshotV2","readFile","action","startTime","Date"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
+
import type { PersistedSessionRecord } from '../contracts/PersistenceBackend.js';
|
|
2
3
|
import type { SessionId } from '../contracts/ids.js';
|
|
3
4
|
import type { ThoughtData } from '../core/thought.js';
|
|
4
5
|
import type { FileSnapshotV2 } from './FileSnapshotTypes.js';
|
|
@@ -375,5 +376,6 @@ export declare const EMPTY_FILE_SNAPSHOT_V2: FileSnapshotV2;
|
|
|
375
376
|
export declare function parseFileSnapshotV2(content: string, sourcePath: string): FileSnapshotV2;
|
|
376
377
|
export declare function serializeFileSnapshotV2(snapshot: FileSnapshotV2, sourcePath: string): string;
|
|
377
378
|
export declare function sessionsInSnapshot(snapshot: FileSnapshotV2): SessionId[];
|
|
379
|
+
export declare function restoreRecordsInSnapshot(snapshot: FileSnapshotV2, includeBranches: boolean): PersistedSessionRecord[];
|
|
378
380
|
export declare function sessionForThought(thought: ThoughtData): SessionId;
|
|
379
381
|
//# sourceMappingURL=FileSnapshotV2.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileSnapshotV2.d.ts","sourceRoot":"","sources":["../../src/persistence/FileSnapshotV2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAgC7D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAM/B,CAAC;AAEH,eAAO,MAAM,sBAAsB,EAAE,cAMpC,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAmCvF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAuB5F;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,EAAE,CAWxE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAEjE"}
|
|
1
|
+
{"version":3,"file":"FileSnapshotV2.d.ts","sourceRoot":"","sources":["../../src/persistence/FileSnapshotV2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,EAEX,sBAAsB,EACtB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAgC7D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAM/B,CAAC;AAEH,eAAO,MAAM,sBAAsB,EAAE,cAMpC,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAmCvF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAuB5F;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,EAAE,CAWxE;AAED,wBAAgB,wBAAwB,CACvC,QAAQ,EAAE,cAAc,EACxB,eAAe,EAAE,OAAO,GACtB,sBAAsB,EAAE,CAuB1B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAEjE"}
|
|
@@ -120,9 +120,47 @@ function sessionsInSnapshot(snapshot) {
|
|
|
120
120
|
...sessions
|
|
121
121
|
].sort(compareCodePoint);
|
|
122
122
|
}
|
|
123
|
+
function restoreRecordsInSnapshot(snapshot, includeBranches) {
|
|
124
|
+
const histories = new Map(snapshot.thoughts.map((record)=>[
|
|
125
|
+
record.sessionId,
|
|
126
|
+
record.thoughts
|
|
127
|
+
]));
|
|
128
|
+
const edges = new Map(snapshot.edges.map((record)=>[
|
|
129
|
+
record.sessionId,
|
|
130
|
+
record.edges
|
|
131
|
+
]));
|
|
132
|
+
const summaries = new Map(snapshot.summaries.map((record)=>[
|
|
133
|
+
record.sessionId,
|
|
134
|
+
record.summaries
|
|
135
|
+
]));
|
|
136
|
+
const branches = new Map();
|
|
137
|
+
for (const record of includeBranches ? snapshot.branches : []){
|
|
138
|
+
const siblings = branches.get(record.sessionId) ?? [];
|
|
139
|
+
siblings.push({
|
|
140
|
+
branchId: record.branchId,
|
|
141
|
+
thoughts: [
|
|
142
|
+
...record.thoughts
|
|
143
|
+
]
|
|
144
|
+
});
|
|
145
|
+
branches.set(record.sessionId, siblings);
|
|
146
|
+
}
|
|
147
|
+
return sessionsInSnapshot(snapshot).map((sessionId)=>({
|
|
148
|
+
sessionId,
|
|
149
|
+
history: [
|
|
150
|
+
...histories.get(sessionId) ?? []
|
|
151
|
+
],
|
|
152
|
+
branches: (branches.get(sessionId) ?? []).sort((left, right)=>compareCodePoint(left.branchId, right.branchId)),
|
|
153
|
+
edges: [
|
|
154
|
+
...edges.get(sessionId) ?? []
|
|
155
|
+
],
|
|
156
|
+
summaries: [
|
|
157
|
+
...summaries.get(sessionId) ?? []
|
|
158
|
+
]
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
123
161
|
function sessionForThought(thought) {
|
|
124
162
|
return asSessionId(thought.session_id);
|
|
125
163
|
}
|
|
126
|
-
export { EMPTY_FILE_SNAPSHOT_V2, FileSnapshotV2Schema, parseFileSnapshotV2, serializeFileSnapshotV2, sessionForThought, sessionsInSnapshot };
|
|
164
|
+
export { EMPTY_FILE_SNAPSHOT_V2, FileSnapshotV2Schema, parseFileSnapshotV2, restoreRecordsInSnapshot, serializeFileSnapshotV2, sessionForThought, sessionsInSnapshot };
|
|
127
165
|
|
|
128
166
|
//# sourceMappingURL=FileSnapshotV2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/FileSnapshotV2.js","sources":["../../src/persistence/FileSnapshotV2.ts"],"sourcesContent":["import * as v from 'valibot';\nimport type { SessionId } from '../contracts/ids.js';\nimport { asSessionId } from '../contracts/ids.js';\nimport { SummarySchema } from '../core/compression/Summary.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError, PersistenceCorruptionError } from '../errors.js';\nimport { EdgeSchema, SequentialThinkingSchema } from '../schema.js';\nimport { parseEdge, parseSummary, parseThoughtData } from './PersistenceCodec.js';\nimport type { FileSnapshotV2 } from './FileSnapshotTypes.js';\nimport {\n\tcompareCodePoint,\n\tcompareCreatedThenId,\n\tparsePersistenceBranchId,\n} from './PersistenceScope.js';\nimport { validateFileSnapshotV2 } from './FileSnapshotValidation.js';\n\nconst SessionIdStringSchema = v.pipe(v.string(), v.regex(/^[A-Za-z0-9_-]{1,100}$/));\nconst BranchIdStringSchema = v.pipe(v.string(), v.regex(/^[A-Za-z0-9_-]{1,50}$/));\nconst PersistedThoughtV2Schema = v.object({\n\t...SequentialThinkingSchema.entries,\n\tretracted: v.optional(v.boolean()),\n});\nconst ThoughtSessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tthoughts: v.array(PersistedThoughtV2Schema),\n});\nconst BranchRecordV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tbranchId: BranchIdStringSchema,\n\tthoughts: v.array(PersistedThoughtV2Schema),\n});\nconst EdgeSessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tedges: v.array(EdgeSchema),\n});\nconst SummarySessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tsummaries: v.array(SummarySchema),\n});\n\nexport const FileSnapshotV2Schema = v.strictObject({\n\tversion: v.literal(2),\n\tthoughts: v.array(ThoughtSessionV2Schema),\n\tbranches: v.array(BranchRecordV2Schema),\n\tedges: v.array(EdgeSessionV2Schema),\n\tsummaries: v.array(SummarySessionV2Schema),\n});\n\nexport const EMPTY_FILE_SNAPSHOT_V2: FileSnapshotV2 = {\n\tversion: 2,\n\tthoughts: [],\n\tbranches: [],\n\tedges: [],\n\tsummaries: [],\n};\n\nexport function parseFileSnapshotV2(content: string, sourcePath: string): FileSnapshotV2 {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new PersistenceCorruptionError(sourcePath, error);\n\t}\n\ttry {\n\t\tconst parsed = v.parse(FileSnapshotV2Schema, raw);\n\t\tconst snapshot: FileSnapshotV2 = {\n\t\t\tversion: 2,\n\t\t\tthoughts: parsed.thoughts.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tthoughts: record.thoughts.map((thought) => parseThoughtData(thought, sourcePath)),\n\t\t\t})),\n\t\t\tbranches: parsed.branches.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tbranchId: parsePersistenceBranchId(record.branchId, sourcePath),\n\t\t\t\tthoughts: record.thoughts.map((thought) => parseThoughtData(thought, sourcePath)),\n\t\t\t})),\n\t\t\tedges: parsed.edges.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tedges: record.edges.map(parseEdge),\n\t\t\t})),\n\t\t\tsummaries: parsed.summaries.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tsummaries: record.summaries.map((summary) => parseSummary(summary, sourcePath)),\n\t\t\t})),\n\t\t};\n\t\tvalidateFileSnapshotV2(snapshot, sourcePath);\n\t\treturn snapshot;\n\t} catch (error) {\n\t\tif (error instanceof PersistenceCompatibilityError) throw error;\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'document does not match File v2', error);\n\t}\n}\n\nexport function serializeFileSnapshotV2(snapshot: FileSnapshotV2, sourcePath: string): string {\n\tconst canonical: FileSnapshotV2 = {\n\t\tversion: 2,\n\t\tthoughts: [...snapshot.thoughts].sort((left, right) =>\n\t\t\tcompareCodePoint(left.sessionId, right.sessionId)\n\t\t),\n\t\tbranches: [...snapshot.branches].sort(\n\t\t\t(left, right) =>\n\t\t\t\tcompareCodePoint(left.sessionId, right.sessionId) ||\n\t\t\t\tcompareCodePoint(left.branchId, right.branchId)\n\t\t),\n\t\tedges: [...snapshot.edges]\n\t\t\t.sort((left, right) => compareCodePoint(left.sessionId, right.sessionId))\n\t\t\t.map((record) => ({ ...record, edges: [...record.edges].sort(compareCreatedThenId) })),\n\t\tsummaries: [...snapshot.summaries]\n\t\t\t.sort((left, right) => compareCodePoint(left.sessionId, right.sessionId))\n\t\t\t.map((record) => ({\n\t\t\t\t...record,\n\t\t\t\tsummaries: [...record.summaries].sort(compareCreatedThenId),\n\t\t\t})),\n\t};\n\tvalidateFileSnapshotV2(canonical, sourcePath);\n\treturn `${JSON.stringify(canonical, null, 2)}\\n`;\n}\n\nexport function sessionsInSnapshot(snapshot: FileSnapshotV2): SessionId[] {\n\tconst sessions = new Set<SessionId>();\n\tfor (const records of [\n\t\tsnapshot.thoughts,\n\t\tsnapshot.branches,\n\t\tsnapshot.edges,\n\t\tsnapshot.summaries,\n\t]) {\n\t\tfor (const record of records) sessions.add(record.sessionId);\n\t}\n\treturn [...sessions].sort(compareCodePoint);\n}\n\nexport function sessionForThought(thought: ThoughtData): SessionId {\n\treturn asSessionId(thought.session_id);\n}\n"],"names":["SessionIdStringSchema","v","BranchIdStringSchema","PersistedThoughtV2Schema","SequentialThinkingSchema","ThoughtSessionV2Schema","BranchRecordV2Schema","EdgeSessionV2Schema","EdgeSchema","SummarySessionV2Schema","SummarySchema","FileSnapshotV2Schema","EMPTY_FILE_SNAPSHOT_V2","parseFileSnapshotV2","content","sourcePath","raw","JSON","error","PersistenceCorruptionError","parsed","snapshot","record","asSessionId","thought","parseThoughtData","parsePersistenceBranchId","parseEdge","summary","parseSummary","validateFileSnapshotV2","PersistenceCompatibilityError","serializeFileSnapshotV2","canonical","left","right","compareCodePoint","compareCreatedThenId","sessionsInSnapshot","sessions","Set","records","sessionForThought"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persistence/FileSnapshotV2.js","sources":["../../src/persistence/FileSnapshotV2.ts"],"sourcesContent":["import * as v from 'valibot';\nimport type {\n\tPersistedBranchRecord,\n\tPersistedSessionRecord,\n} from '../contracts/PersistenceBackend.js';\nimport type { SessionId } from '../contracts/ids.js';\nimport { asSessionId } from '../contracts/ids.js';\nimport { SummarySchema } from '../core/compression/Summary.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError, PersistenceCorruptionError } from '../errors.js';\nimport { EdgeSchema, SequentialThinkingSchema } from '../schema.js';\nimport { parseEdge, parseSummary, parseThoughtData } from './PersistenceCodec.js';\nimport type { FileSnapshotV2 } from './FileSnapshotTypes.js';\nimport {\n\tcompareCodePoint,\n\tcompareCreatedThenId,\n\tparsePersistenceBranchId,\n} from './PersistenceScope.js';\nimport { validateFileSnapshotV2 } from './FileSnapshotValidation.js';\n\nconst SessionIdStringSchema = v.pipe(v.string(), v.regex(/^[A-Za-z0-9_-]{1,100}$/));\nconst BranchIdStringSchema = v.pipe(v.string(), v.regex(/^[A-Za-z0-9_-]{1,50}$/));\nconst PersistedThoughtV2Schema = v.object({\n\t...SequentialThinkingSchema.entries,\n\tretracted: v.optional(v.boolean()),\n});\nconst ThoughtSessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tthoughts: v.array(PersistedThoughtV2Schema),\n});\nconst BranchRecordV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tbranchId: BranchIdStringSchema,\n\tthoughts: v.array(PersistedThoughtV2Schema),\n});\nconst EdgeSessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tedges: v.array(EdgeSchema),\n});\nconst SummarySessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tsummaries: v.array(SummarySchema),\n});\n\nexport const FileSnapshotV2Schema = v.strictObject({\n\tversion: v.literal(2),\n\tthoughts: v.array(ThoughtSessionV2Schema),\n\tbranches: v.array(BranchRecordV2Schema),\n\tedges: v.array(EdgeSessionV2Schema),\n\tsummaries: v.array(SummarySessionV2Schema),\n});\n\nexport const EMPTY_FILE_SNAPSHOT_V2: FileSnapshotV2 = {\n\tversion: 2,\n\tthoughts: [],\n\tbranches: [],\n\tedges: [],\n\tsummaries: [],\n};\n\nexport function parseFileSnapshotV2(content: string, sourcePath: string): FileSnapshotV2 {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new PersistenceCorruptionError(sourcePath, error);\n\t}\n\ttry {\n\t\tconst parsed = v.parse(FileSnapshotV2Schema, raw);\n\t\tconst snapshot: FileSnapshotV2 = {\n\t\t\tversion: 2,\n\t\t\tthoughts: parsed.thoughts.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tthoughts: record.thoughts.map((thought) => parseThoughtData(thought, sourcePath)),\n\t\t\t})),\n\t\t\tbranches: parsed.branches.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tbranchId: parsePersistenceBranchId(record.branchId, sourcePath),\n\t\t\t\tthoughts: record.thoughts.map((thought) => parseThoughtData(thought, sourcePath)),\n\t\t\t})),\n\t\t\tedges: parsed.edges.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tedges: record.edges.map(parseEdge),\n\t\t\t})),\n\t\t\tsummaries: parsed.summaries.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tsummaries: record.summaries.map((summary) => parseSummary(summary, sourcePath)),\n\t\t\t})),\n\t\t};\n\t\tvalidateFileSnapshotV2(snapshot, sourcePath);\n\t\treturn snapshot;\n\t} catch (error) {\n\t\tif (error instanceof PersistenceCompatibilityError) throw error;\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'document does not match File v2', error);\n\t}\n}\n\nexport function serializeFileSnapshotV2(snapshot: FileSnapshotV2, sourcePath: string): string {\n\tconst canonical: FileSnapshotV2 = {\n\t\tversion: 2,\n\t\tthoughts: [...snapshot.thoughts].sort((left, right) =>\n\t\t\tcompareCodePoint(left.sessionId, right.sessionId)\n\t\t),\n\t\tbranches: [...snapshot.branches].sort(\n\t\t\t(left, right) =>\n\t\t\t\tcompareCodePoint(left.sessionId, right.sessionId) ||\n\t\t\t\tcompareCodePoint(left.branchId, right.branchId)\n\t\t),\n\t\tedges: [...snapshot.edges]\n\t\t\t.sort((left, right) => compareCodePoint(left.sessionId, right.sessionId))\n\t\t\t.map((record) => ({ ...record, edges: [...record.edges].sort(compareCreatedThenId) })),\n\t\tsummaries: [...snapshot.summaries]\n\t\t\t.sort((left, right) => compareCodePoint(left.sessionId, right.sessionId))\n\t\t\t.map((record) => ({\n\t\t\t\t...record,\n\t\t\t\tsummaries: [...record.summaries].sort(compareCreatedThenId),\n\t\t\t})),\n\t};\n\tvalidateFileSnapshotV2(canonical, sourcePath);\n\treturn `${JSON.stringify(canonical, null, 2)}\\n`;\n}\n\nexport function sessionsInSnapshot(snapshot: FileSnapshotV2): SessionId[] {\n\tconst sessions = new Set<SessionId>();\n\tfor (const records of [\n\t\tsnapshot.thoughts,\n\t\tsnapshot.branches,\n\t\tsnapshot.edges,\n\t\tsnapshot.summaries,\n\t]) {\n\t\tfor (const record of records) sessions.add(record.sessionId);\n\t}\n\treturn [...sessions].sort(compareCodePoint);\n}\n\nexport function restoreRecordsInSnapshot(\n\tsnapshot: FileSnapshotV2,\n\tincludeBranches: boolean\n): PersistedSessionRecord[] {\n\tconst histories = new Map(\n\t\tsnapshot.thoughts.map((record) => [record.sessionId, record.thoughts] as const)\n\t);\n\tconst edges = new Map(snapshot.edges.map((record) => [record.sessionId, record.edges] as const));\n\tconst summaries = new Map(\n\t\tsnapshot.summaries.map((record) => [record.sessionId, record.summaries] as const)\n\t);\n\tconst branches = new Map<SessionId, PersistedBranchRecord[]>();\n\tfor (const record of includeBranches ? snapshot.branches : []) {\n\t\tconst siblings = branches.get(record.sessionId) ?? [];\n\t\tsiblings.push({ branchId: record.branchId, thoughts: [...record.thoughts] });\n\t\tbranches.set(record.sessionId, siblings);\n\t}\n\treturn sessionsInSnapshot(snapshot).map((sessionId) => ({\n\t\tsessionId,\n\t\thistory: [...(histories.get(sessionId) ?? [])],\n\t\tbranches: (branches.get(sessionId) ?? []).sort((left, right) =>\n\t\t\tcompareCodePoint(left.branchId, right.branchId)\n\t\t),\n\t\tedges: [...(edges.get(sessionId) ?? [])],\n\t\tsummaries: [...(summaries.get(sessionId) ?? [])],\n\t}));\n}\n\nexport function sessionForThought(thought: ThoughtData): SessionId {\n\treturn asSessionId(thought.session_id);\n}\n"],"names":["SessionIdStringSchema","v","BranchIdStringSchema","PersistedThoughtV2Schema","SequentialThinkingSchema","ThoughtSessionV2Schema","BranchRecordV2Schema","EdgeSessionV2Schema","EdgeSchema","SummarySessionV2Schema","SummarySchema","FileSnapshotV2Schema","EMPTY_FILE_SNAPSHOT_V2","parseFileSnapshotV2","content","sourcePath","raw","JSON","error","PersistenceCorruptionError","parsed","snapshot","record","asSessionId","thought","parseThoughtData","parsePersistenceBranchId","parseEdge","summary","parseSummary","validateFileSnapshotV2","PersistenceCompatibilityError","serializeFileSnapshotV2","canonical","left","right","compareCodePoint","compareCreatedThenId","sessionsInSnapshot","sessions","Set","records","restoreRecordsInSnapshot","includeBranches","histories","Map","edges","summaries","branches","siblings","sessionId","sessionForThought"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ThoughtData } from '../core/thought.js';
|
|
2
2
|
import type { Edge } from '../core/graph/Edge.js';
|
|
3
3
|
import type { Summary } from '../core/compression/Summary.js';
|
|
4
|
-
import type { PersistenceBackend } from '../contracts/PersistenceBackend.js';
|
|
4
|
+
import type { PersistenceBackend, PersistenceRestoreRead } from '../contracts/PersistenceBackend.js';
|
|
5
5
|
import { type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';
|
|
6
6
|
export interface MemoryPersistenceOptions {
|
|
7
7
|
maxSize?: number;
|
|
@@ -24,6 +24,9 @@ export declare class MemoryPersistence implements PersistenceBackend {
|
|
|
24
24
|
loadBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<ThoughtData[] | undefined>;
|
|
25
25
|
listBranchesForSession(sessionId: SessionId): Promise<BranchId[]>;
|
|
26
26
|
listSessions(): Promise<SessionId[]>;
|
|
27
|
+
loadAllSessionsForRestore(): Promise<PersistenceRestoreRead>;
|
|
28
|
+
private _sessionIds;
|
|
29
|
+
private _branchRecords;
|
|
27
30
|
healthy(): Promise<boolean>;
|
|
28
31
|
clearAll(): Promise<void>;
|
|
29
32
|
clearSession(sessionId: SessionId): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryPersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/MemoryPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"MemoryPersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/MemoryPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAEX,kBAAkB,EAClB,sBAAsB,EACtB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAejG,MAAM,WAAW,wBAAwB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,qBAAa,iBAAkB,YAAW,kBAAkB;IAC3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsD;IAChF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;gBAE/B,OAAO,GAAE,wBAA6B;IAOrC,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBhF,uBAAuB,CACnC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,WAAW,EACpB,eAAe,EAAE,SAAS,GACxB,OAAO,CAAC,IAAI,CAAC;IAoBH,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAInE,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;IAuBH,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/E,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC;IAQxB,sBAAsB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAKjE,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIpC,yBAAyB,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAYzE,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;IAMT,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAI3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAEtB,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtE,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAIhD,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjF,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAGpE"}
|
|
@@ -104,6 +104,26 @@ class MemoryPersistence {
|
|
|
104
104
|
].sort(compareCodePoint);
|
|
105
105
|
}
|
|
106
106
|
async listSessions() {
|
|
107
|
+
return this._sessionIds();
|
|
108
|
+
}
|
|
109
|
+
async loadAllSessionsForRestore() {
|
|
110
|
+
return {
|
|
111
|
+
sessions: this._sessionIds().map((sessionId)=>({
|
|
112
|
+
sessionId,
|
|
113
|
+
history: [
|
|
114
|
+
...this._histories.get(sessionId) ?? []
|
|
115
|
+
],
|
|
116
|
+
branches: this._persistBranches ? this._branchRecords(sessionId) : [],
|
|
117
|
+
edges: [
|
|
118
|
+
...this._edges.get(sessionId) ?? []
|
|
119
|
+
].sort(compareCreatedThenId),
|
|
120
|
+
summaries: [
|
|
121
|
+
...this._summaries.get(sessionId) ?? []
|
|
122
|
+
].sort(compareCreatedThenId)
|
|
123
|
+
}))
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
_sessionIds() {
|
|
107
127
|
const sessions = new Set();
|
|
108
128
|
for (const namespace of [
|
|
109
129
|
this._histories,
|
|
@@ -115,6 +135,16 @@ class MemoryPersistence {
|
|
|
115
135
|
...sessions
|
|
116
136
|
].sort(compareCodePoint);
|
|
117
137
|
}
|
|
138
|
+
_branchRecords(sessionId) {
|
|
139
|
+
return [
|
|
140
|
+
...this._branches.get(sessionId) ?? []
|
|
141
|
+
].sort(([left], [right])=>compareCodePoint(left, right)).map(([branchId, thoughts])=>({
|
|
142
|
+
branchId,
|
|
143
|
+
thoughts: [
|
|
144
|
+
...thoughts
|
|
145
|
+
]
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
118
148
|
async healthy() {
|
|
119
149
|
return true;
|
|
120
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/MemoryPersistence.js","sources":["../../src/persistence/MemoryPersistence.ts"],"sourcesContent":["import type { ThoughtData } from '../core/thought.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';\nimport { stageBacktrackPersistence } from './BacktrackPersistence.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tassertUniqueRecordIds,\n\tcompareCodePoint,\n\tcompareCreatedThenId,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\n\nexport interface MemoryPersistenceOptions {\n\tmaxSize?: number;\n\tmaxHistorySize?: number;\n\tpersistBranches?: boolean;\n}\n\nexport class MemoryPersistence implements PersistenceBackend {\n\tprivate readonly _histories = new Map<SessionId, ThoughtData[]>();\n\tprivate readonly _branches = new Map<SessionId, Map<BranchId, ThoughtData[]>>();\n\tprivate readonly _edges = new Map<SessionId, Edge[]>();\n\tprivate readonly _summaries = new Map<SessionId, Summary[]>();\n\tprivate readonly _maxSize: number | undefined;\n\tprivate readonly _persistBranches: boolean;\n\n\tconstructor(options: MemoryPersistenceOptions = {}) {\n\t\tconst configuredSize = options.maxHistorySize ?? options.maxSize;\n\t\tthis._maxSize =\n\t\t\tconfiguredSize === undefined ? 10_000 : configuredSize > 0 ? configuredSize : undefined;\n\t\tthis._persistBranches = options.persistBranches ?? true;\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tconst history = [...(this._histories.get(validatedSessionId) ?? []), thought];\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{ sessionId: validatedSessionId, thoughts: history },\n\t\t];\n\t\tfor (const branch of this._branches.get(validatedSessionId)?.values() ?? []) {\n\t\t\tcollections.push({ sessionId: validatedSessionId, thoughts: branch });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, `${validatedSessionId}/thoughts`);\n\t\tthis._histories.set(\n\t\t\tvalidatedSessionId,\n\t\t\tthis._maxSize === undefined ? history : history.slice(-this._maxSize)\n\t\t);\n\t}\n\n\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst branches = this._branches.get(validatedSessionId) ?? new Map();\n\t\tconst staged = stageBacktrackPersistence(\n\t\t\tvalidatedSessionId,\n\t\t\tthis._histories.get(validatedSessionId) ?? [],\n\t\t\t[...branches].map(([branchId, thoughts]) => ({ branchId, thoughts })),\n\t\t\tthought,\n\t\t\ttargetThoughtId,\n\t\t\tthis._maxSize ?? 0\n\t\t);\n\t\tthis._histories.set(validatedSessionId, [...staged.history]);\n\t\tif (this._persistBranches) {\n\t\t\tthis._branches.set(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tnew Map(staged.branches.map((branch) => [branch.branchId, [...branch.thoughts]]))\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\treturn [...(this._histories.get(asSessionId(sessionId)) ?? [])];\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tconst branches = new Map(this._branches.get(validatedSessionId) ?? []);\n\t\tbranches.set(validatedBranchId, [...thoughts]);\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId: validatedSessionId,\n\t\t\t\tthoughts: this._histories.get(validatedSessionId) ?? [],\n\t\t\t},\n\t\t];\n\t\tfor (const branch of branches.values()) {\n\t\t\tcollections.push({ sessionId: validatedSessionId, thoughts: branch });\n\t\t}\n\t\tassertPersistableThoughtCollections(\n\t\t\tcollections,\n\t\t\t`${validatedSessionId}/branches/${validatedBranchId}`\n\t\t);\n\t\tif (!this._persistBranches) return;\n\t\tthis._branches.set(validatedSessionId, branches);\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tconst branches = this._branches.get(validatedSessionId);\n\t\tif (branches === undefined) return;\n\t\tbranches.delete(validatedBranchId);\n\t\tif (branches.size === 0) this._branches.delete(validatedSessionId);\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tconst branch = this._branches.get(validatedSessionId)?.get(validatedBranchId);\n\t\treturn branch === undefined ? undefined : [...branch];\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn [...(this._branches.get(asSessionId(sessionId))?.keys() ?? [])].sort(compareCodePoint);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\tconst sessions = new Set<SessionId>();\n\t\tfor (const namespace of [this._histories, this._branches, this._edges, this._summaries]) {\n\t\t\tfor (const sessionId of namespace.keys()) sessions.add(sessionId);\n\t\t}\n\t\treturn [...sessions].sort(compareCodePoint);\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\treturn true;\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\tthis._histories.clear();\n\t\tthis._branches.clear();\n\t\tthis._edges.clear();\n\t\tthis._summaries.clear();\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tthis._histories.delete(validatedSessionId);\n\t\tthis._branches.delete(validatedSessionId);\n\t\tthis._edges.delete(validatedSessionId);\n\t\tthis._summaries.delete(validatedSessionId);\n\t}\n\n\tpublic async close(): Promise<void> {}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\tassertUniqueRecordIds(edges, `${validatedSessionId}/edges`, 'edge');\n\t\tif (edges.length === 0) this._edges.delete(validatedSessionId);\n\t\telse this._edges.set(validatedSessionId, [...edges].sort(compareCreatedThenId));\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\treturn [...(this._edges.get(asSessionId(sessionId)) ?? [])].sort(compareCreatedThenId);\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\tassertUniqueRecordIds(summaries, `${validatedSessionId}/summaries`, 'summary');\n\t\tif (summaries.length === 0) this._summaries.delete(validatedSessionId);\n\t\telse this._summaries.set(validatedSessionId, [...summaries].sort(compareCreatedThenId));\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\treturn [...(this._summaries.get(asSessionId(sessionId)) ?? [])].sort(compareCreatedThenId);\n\t}\n}\n"],"names":["MemoryPersistence","Map","options","configuredSize","undefined","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","history","collections","branch","assertPersistableThoughtCollections","targetThoughtId","branches","staged","stageBacktrackPersistence","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","compareCodePoint","sessions","Set","namespace","edges","assertEdgeScopes","assertUniqueRecordIds","compareCreatedThenId","summaries","assertSummaryScopes"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persistence/MemoryPersistence.js","sources":["../../src/persistence/MemoryPersistence.ts"],"sourcesContent":["import type { ThoughtData } from '../core/thought.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type {\n\tPersistedBranchRecord,\n\tPersistenceBackend,\n\tPersistenceRestoreRead,\n} from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';\nimport { stageBacktrackPersistence } from './BacktrackPersistence.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tassertUniqueRecordIds,\n\tcompareCodePoint,\n\tcompareCreatedThenId,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\n\nexport interface MemoryPersistenceOptions {\n\tmaxSize?: number;\n\tmaxHistorySize?: number;\n\tpersistBranches?: boolean;\n}\n\nexport class MemoryPersistence implements PersistenceBackend {\n\tprivate readonly _histories = new Map<SessionId, ThoughtData[]>();\n\tprivate readonly _branches = new Map<SessionId, Map<BranchId, ThoughtData[]>>();\n\tprivate readonly _edges = new Map<SessionId, Edge[]>();\n\tprivate readonly _summaries = new Map<SessionId, Summary[]>();\n\tprivate readonly _maxSize: number | undefined;\n\tprivate readonly _persistBranches: boolean;\n\n\tconstructor(options: MemoryPersistenceOptions = {}) {\n\t\tconst configuredSize = options.maxHistorySize ?? options.maxSize;\n\t\tthis._maxSize =\n\t\t\tconfiguredSize === undefined ? 10_000 : configuredSize > 0 ? configuredSize : undefined;\n\t\tthis._persistBranches = options.persistBranches ?? true;\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tconst history = [...(this._histories.get(validatedSessionId) ?? []), thought];\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{ sessionId: validatedSessionId, thoughts: history },\n\t\t];\n\t\tfor (const branch of this._branches.get(validatedSessionId)?.values() ?? []) {\n\t\t\tcollections.push({ sessionId: validatedSessionId, thoughts: branch });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, `${validatedSessionId}/thoughts`);\n\t\tthis._histories.set(\n\t\t\tvalidatedSessionId,\n\t\t\tthis._maxSize === undefined ? history : history.slice(-this._maxSize)\n\t\t);\n\t}\n\n\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst branches = this._branches.get(validatedSessionId) ?? new Map();\n\t\tconst staged = stageBacktrackPersistence(\n\t\t\tvalidatedSessionId,\n\t\t\tthis._histories.get(validatedSessionId) ?? [],\n\t\t\t[...branches].map(([branchId, thoughts]) => ({ branchId, thoughts })),\n\t\t\tthought,\n\t\t\ttargetThoughtId,\n\t\t\tthis._maxSize ?? 0\n\t\t);\n\t\tthis._histories.set(validatedSessionId, [...staged.history]);\n\t\tif (this._persistBranches) {\n\t\t\tthis._branches.set(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tnew Map(staged.branches.map((branch) => [branch.branchId, [...branch.thoughts]]))\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\treturn [...(this._histories.get(asSessionId(sessionId)) ?? [])];\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tconst branches = new Map(this._branches.get(validatedSessionId) ?? []);\n\t\tbranches.set(validatedBranchId, [...thoughts]);\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId: validatedSessionId,\n\t\t\t\tthoughts: this._histories.get(validatedSessionId) ?? [],\n\t\t\t},\n\t\t];\n\t\tfor (const branch of branches.values()) {\n\t\t\tcollections.push({ sessionId: validatedSessionId, thoughts: branch });\n\t\t}\n\t\tassertPersistableThoughtCollections(\n\t\t\tcollections,\n\t\t\t`${validatedSessionId}/branches/${validatedBranchId}`\n\t\t);\n\t\tif (!this._persistBranches) return;\n\t\tthis._branches.set(validatedSessionId, branches);\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tconst branches = this._branches.get(validatedSessionId);\n\t\tif (branches === undefined) return;\n\t\tbranches.delete(validatedBranchId);\n\t\tif (branches.size === 0) this._branches.delete(validatedSessionId);\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);\n\t\tconst branch = this._branches.get(validatedSessionId)?.get(validatedBranchId);\n\t\treturn branch === undefined ? undefined : [...branch];\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn [...(this._branches.get(asSessionId(sessionId))?.keys() ?? [])].sort(compareCodePoint);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn this._sessionIds();\n\t}\n\n\tpublic async loadAllSessionsForRestore(): Promise<PersistenceRestoreRead> {\n\t\treturn {\n\t\t\tsessions: this._sessionIds().map((sessionId) => ({\n\t\t\t\tsessionId,\n\t\t\t\thistory: [...(this._histories.get(sessionId) ?? [])],\n\t\t\t\tbranches: this._persistBranches ? this._branchRecords(sessionId) : [],\n\t\t\t\tedges: [...(this._edges.get(sessionId) ?? [])].sort(compareCreatedThenId),\n\t\t\t\tsummaries: [...(this._summaries.get(sessionId) ?? [])].sort(compareCreatedThenId),\n\t\t\t})),\n\t\t};\n\t}\n\n\tprivate _sessionIds(): SessionId[] {\n\t\tconst sessions = new Set<SessionId>();\n\t\tfor (const namespace of [this._histories, this._branches, this._edges, this._summaries]) {\n\t\t\tfor (const sessionId of namespace.keys()) sessions.add(sessionId);\n\t\t}\n\t\treturn [...sessions].sort(compareCodePoint);\n\t}\n\n\tprivate _branchRecords(sessionId: SessionId): PersistedBranchRecord[] {\n\t\treturn [...(this._branches.get(sessionId) ?? [])]\n\t\t\t.sort(([left], [right]) => compareCodePoint(left, right))\n\t\t\t.map(([branchId, thoughts]) => ({ branchId, thoughts: [...thoughts] }));\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\treturn true;\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\tthis._histories.clear();\n\t\tthis._branches.clear();\n\t\tthis._edges.clear();\n\t\tthis._summaries.clear();\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tthis._histories.delete(validatedSessionId);\n\t\tthis._branches.delete(validatedSessionId);\n\t\tthis._edges.delete(validatedSessionId);\n\t\tthis._summaries.delete(validatedSessionId);\n\t}\n\n\tpublic async close(): Promise<void> {}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\tassertUniqueRecordIds(edges, `${validatedSessionId}/edges`, 'edge');\n\t\tif (edges.length === 0) this._edges.delete(validatedSessionId);\n\t\telse this._edges.set(validatedSessionId, [...edges].sort(compareCreatedThenId));\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\treturn [...(this._edges.get(asSessionId(sessionId)) ?? [])].sort(compareCreatedThenId);\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\tassertUniqueRecordIds(summaries, `${validatedSessionId}/summaries`, 'summary');\n\t\tif (summaries.length === 0) this._summaries.delete(validatedSessionId);\n\t\telse this._summaries.set(validatedSessionId, [...summaries].sort(compareCreatedThenId));\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\treturn [...(this._summaries.get(asSessionId(sessionId)) ?? [])].sort(compareCreatedThenId);\n\t}\n}\n"],"names":["MemoryPersistence","Map","options","configuredSize","undefined","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","history","collections","branch","assertPersistableThoughtCollections","targetThoughtId","branches","staged","stageBacktrackPersistence","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","compareCodePoint","compareCreatedThenId","sessions","Set","namespace","left","right","edges","assertEdgeScopes","assertUniqueRecordIds","summaries","assertSummaryScopes"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';
|
|
1
|
+
import type { PersistenceConfig, PersistenceBackend, PersistenceRestoreRead } from '../contracts/PersistenceBackend.js';
|
|
2
2
|
import { type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';
|
|
3
3
|
import type { Summary } from '../core/compression/Summary.js';
|
|
4
4
|
import type { Edge } from '../core/graph/Edge.js';
|
|
@@ -24,12 +24,17 @@ export declare class SqlitePersistence implements PersistenceBackend {
|
|
|
24
24
|
loadBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<ThoughtData[] | undefined>;
|
|
25
25
|
listBranchesForSession(sessionId: SessionId): Promise<BranchId[]>;
|
|
26
26
|
listSessions(): Promise<SessionId[]>;
|
|
27
|
+
loadAllSessionsForRestore(): Promise<PersistenceRestoreRead>;
|
|
28
|
+
private _selectSessionIds;
|
|
29
|
+
private _restoreRecord;
|
|
27
30
|
clearAll(): Promise<void>;
|
|
28
31
|
clearSession(sessionId: SessionId): Promise<void>;
|
|
29
32
|
saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void>;
|
|
30
33
|
loadEdges(sessionId: SessionId): Promise<Edge[]>;
|
|
34
|
+
private _selectEdges;
|
|
31
35
|
saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void>;
|
|
32
36
|
loadSummaries(sessionId: SessionId): Promise<Summary[]>;
|
|
37
|
+
private _selectSummaries;
|
|
33
38
|
healthy(): Promise<boolean>;
|
|
34
39
|
close(): Promise<void>;
|
|
35
40
|
getStats(): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlitePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SqlitePersistence.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"SqlitePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SqlitePersistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -115,8 +115,31 @@ class SqlitePersistence {
|
|
|
115
115
|
return this._db.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC').all(asSessionId(sessionId)).map((row)=>parsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath));
|
|
116
116
|
}
|
|
117
117
|
async listSessions() {
|
|
118
|
+
return this._selectSessionIds();
|
|
119
|
+
}
|
|
120
|
+
async loadAllSessionsForRestore() {
|
|
121
|
+
return runSqliteReadTransaction(this._db, ()=>({
|
|
122
|
+
sessions: this._selectSessionIds().map((sessionId)=>this._restoreRecord(sessionId))
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
_selectSessionIds() {
|
|
118
126
|
return this._db.prepare('SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries').all().map((row)=>asSessionId(stringField(row, 'session_id', this._sourcePath))).sort(compareCodePoint);
|
|
119
127
|
}
|
|
128
|
+
_restoreRecord(sessionId) {
|
|
129
|
+
const state = this._loadValidatedThoughtState(sessionId);
|
|
130
|
+
return {
|
|
131
|
+
sessionId,
|
|
132
|
+
history: state.history,
|
|
133
|
+
branches: this._persistBranches ? [
|
|
134
|
+
...state.branches
|
|
135
|
+
].map(([branchId, thoughts])=>({
|
|
136
|
+
branchId,
|
|
137
|
+
thoughts
|
|
138
|
+
})).sort((left, right)=>compareCodePoint(left.branchId, right.branchId)) : [],
|
|
139
|
+
edges: this._selectEdges(sessionId),
|
|
140
|
+
summaries: this._selectSummaries(sessionId)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
120
143
|
async clearAll() {
|
|
121
144
|
runSqliteTransaction(this._db, ()=>{
|
|
122
145
|
for (const table of [
|
|
@@ -148,8 +171,10 @@ class SqlitePersistence {
|
|
|
148
171
|
});
|
|
149
172
|
}
|
|
150
173
|
async loadEdges(sessionId) {
|
|
151
|
-
|
|
152
|
-
|
|
174
|
+
return this._selectEdges(asSessionId(sessionId));
|
|
175
|
+
}
|
|
176
|
+
_selectEdges(sessionId) {
|
|
177
|
+
return this._db.prepare('SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC').all(sessionId).map((row, index)=>decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));
|
|
153
178
|
}
|
|
154
179
|
async saveSummaries(sessionId, summaries) {
|
|
155
180
|
const validatedSessionId = asSessionId(sessionId);
|
|
@@ -161,8 +186,10 @@ class SqlitePersistence {
|
|
|
161
186
|
});
|
|
162
187
|
}
|
|
163
188
|
async loadSummaries(sessionId) {
|
|
164
|
-
|
|
165
|
-
|
|
189
|
+
return this._selectSummaries(asSessionId(sessionId));
|
|
190
|
+
}
|
|
191
|
+
_selectSummaries(sessionId) {
|
|
192
|
+
return this._db.prepare('SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries WHERE session_id = ? ORDER BY created_at ASC, id ASC').all(sessionId).map((row, index)=>decodeSummaryRow(row, `${this._sourcePath}:summaries:${index}`));
|
|
166
193
|
}
|
|
167
194
|
async healthy() {
|
|
168
195
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/SqlitePersistence.js","sources":["../../src/persistence/SqlitePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCorruptionError } from '../errors.js';\nimport type { SqliteDatabase } from './SqliteDriver.js';\nimport { loadSqliteDatabaseConstructor, type SqliteDriverRuntime } from './SqliteDriverLoader.js';\nimport { runSqliteReadTransaction, runSqliteTransaction } from './SqliteDriver.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tnumberField,\n\tstringField,\n} from './SqlitePayload.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\nimport { initializeOrValidateSqliteV2 } from './SqliteSchemaV2.js';\nimport { stageBacktrackPersistence } from './BacktrackPersistence.js';\n\ntype SqliteOptions = PersistenceConfig['options'];\n\ntype ValidatedThoughtState = {\n\treadonly history: ThoughtData[];\n\treadonly branches: ReadonlyMap<BranchId, ThoughtData[]>;\n};\n\nexport class SqlitePersistence implements PersistenceBackend {\n\tprivate constructor(\n\t\tprivate readonly _db: SqliteDatabase,\n\t\tprivate readonly _sourcePath: string,\n\t\tprivate readonly _maxHistorySize: number,\n\t\tprivate readonly _persistBranches: boolean\n\t) {}\n\n\tpublic static createWithDatabase(\n\t\tdatabase: SqliteDatabase,\n\t\toptions: SqliteOptions = {},\n\t\tsourcePath = '<structural-sqlite>'\n\t): SqlitePersistence {\n\t\tinitializeOrValidateSqliteV2(database, sourcePath);\n\t\treturn new SqlitePersistence(\n\t\t\tdatabase,\n\t\t\tsourcePath,\n\t\t\toptions?.maxHistorySize ?? 10000,\n\t\t\toptions?.persistBranches ?? true\n\t\t);\n\t}\n\n\tpublic static async create(\n\t\toptions?: SqliteOptions,\n\t\truntime?: SqliteDriverRuntime\n\t): Promise<SqlitePersistence> {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tconst dbPath = options?.dbPath ?? join(defaultDataDir, 'history.db');\n\t\tconst Database = await loadSqliteDatabaseConstructor(dbPath, runtime);\n\t\tconst database = new Database(dbPath);\n\t\ttry {\n\t\t\tconst persistence = SqlitePersistence.createWithDatabase(database, options, dbPath);\n\t\t\tif (options?.enableWAL !== false) database.pragma('journal_mode = WAL');\n\t\t\tdatabase.pragma('synchronous = NORMAL');\n\t\t\tdatabase.pragma('foreign_keys = ON');\n\t\t\tdatabase.pragma('busy_timeout = 5000');\n\t\t\tdatabase.pragma('cache_size = -64000');\n\t\t\tdatabase.pragma('temp_store = MEMORY');\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tdatabase.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tthis._saveThought(validatedSessionId, thought);\n\t}\n\n\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tconst current = this._loadValidatedThoughtState(validatedSessionId);\n\t\t\tconst staged = stageBacktrackPersistence(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tcurrent.history,\n\t\t\t\t[...current.branches].map(([branchId, thoughts]) => ({ branchId, thoughts })),\n\t\t\t\tthought,\n\t\t\t\ttargetThoughtId,\n\t\t\t\tthis._maxHistorySize\n\t\t\t);\n\t\t\tthis._db.prepare('DELETE FROM thoughts WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insertThought = this._db.prepare(\n\t\t\t\t'INSERT INTO thoughts (session_id, data) VALUES (?, ?)'\n\t\t\t);\n\t\t\tfor (const retained of staged.history) {\n\t\t\t\tinsertThought.run(validatedSessionId, JSON.stringify(retained));\n\t\t\t}\n\t\t\tconst replaceBranch = this._db.prepare(\n\t\t\t\t'INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const branch of staged.branches) {\n\t\t\t\treplaceBranch.run(validatedSessionId, branch.branchId, JSON.stringify(branch.thoughts));\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate _saveThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, [thought]);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT INTO thoughts (session_id, data) VALUES (?, ?)')\n\t\t\t\t.run(sessionId, JSON.stringify(thought));\n\t\t\tif (this._maxHistorySize > 0) {\n\t\t\t\tconst countRow = this._db\n\t\t\t\t\t.prepare('SELECT COUNT(*) AS count FROM thoughts WHERE session_id = ?')\n\t\t\t\t\t.get(sessionId);\n\t\t\t\tconst excess =\n\t\t\t\t\tnumberField(countRow, 'count', `${this._sourcePath}:thought-count`) -\n\t\t\t\t\tthis._maxHistorySize;\n\t\t\t\tif (excess > 0) {\n\t\t\t\t\tthis._db\n\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t'DELETE FROM thoughts WHERE id IN (SELECT id FROM thoughts WHERE session_id = ? ORDER BY id ASC LIMIT ?)'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.run(sessionId, excess);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn runSqliteReadTransaction(\n\t\t\tthis._db,\n\t\t\t() => this._loadValidatedThoughtState(validatedSessionId).history\n\t\t);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tthis._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tassertPersistableThoughts(thoughts, `${this._sourcePath}:branch:${branchId}`);\n\t\tif (!this._persistBranches) {\n\t\t\trunSqliteReadTransaction(this._db, () =>\n\t\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)')\n\t\t\t\t.run(sessionId, branchId, JSON.stringify(thoughts));\n\t\t});\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db\n\t\t\t\t.prepare('DELETE FROM branches WHERE session_id = ? AND branch_id = ?')\n\t\t\t\t.run(validatedSessionId, validatedBranchId);\n\t\t});\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\treturn runSqliteReadTransaction(this._db, () =>\n\t\t\tthis._loadValidatedThoughtState(validatedSessionId).branches.get(validatedBranchId)\n\t\t);\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn this._db\n\t\t\t.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC')\n\t\t\t.all(asSessionId(sessionId))\n\t\t\t.map((row) =>\n\t\t\t\tparsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath)\n\t\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries'\n\t\t\t)\n\t\t\t.all()\n\t\t\t.map((row) => asSessionId(stringField(row, 'session_id', this._sourcePath)))\n\t\t\t.sort(compareCodePoint);\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries'])\n\t\t\t\tthis._db.exec(`DELETE FROM ${table}`);\n\t\t});\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries']) {\n\t\t\t\tthis._db.prepare(`DELETE FROM ${table} WHERE session_id = ?`).run(validatedSessionId);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM edges WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const edge of edges)\n\t\t\t\tinsert.run(\n\t\t\t\t\tedge.id,\n\t\t\t\t\tedge.sessionId,\n\t\t\t\t\tedge.from,\n\t\t\t\t\tedge.to,\n\t\t\t\t\tedge.kind,\n\t\t\t\t\tedge.createdAt,\n\t\t\t\t\tedge.metadata === undefined ? null : JSON.stringify(edge.metadata)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM summaries WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO summaries (id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const summary of summaries)\n\t\t\t\tinsert.run(\n\t\t\t\t\tsummary.id,\n\t\t\t\t\tsummary.sessionId,\n\t\t\t\t\tsummary.branchId ?? null,\n\t\t\t\t\tsummary.rootThoughtId,\n\t\t\t\t\tJSON.stringify(summary.coveredIds),\n\t\t\t\t\tsummary.coveredRange[0],\n\t\t\t\t\tsummary.coveredRange[1],\n\t\t\t\t\tJSON.stringify(summary.topics),\n\t\t\t\t\tsummary.aggregateConfidence,\n\t\t\t\t\tsummary.createdAt,\n\t\t\t\t\tsummary.meta === undefined ? null : JSON.stringify(summary.meta)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeSummaryRow(row, `${this._sourcePath}:summaries:${index}`));\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis._db.close();\n\t}\n\n\tpublic getStats(): {\n\t\treadonly thoughtCount: number;\n\t\treadonly branchCount: number;\n\t\treadonly dbSize: number;\n\t} {\n\t\tconst thoughtCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM thoughts').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\tconst branchCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM branches').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\treturn { thoughtCount, branchCount: this._persistBranches ? branchCount : 0, dbSize: 0 };\n\t}\n\n\tprivate _loadValidatedThoughtState(\n\t\tsessionId: SessionId,\n\t\tcandidates: readonly ThoughtData[] = [],\n\t\treplacingBranch?: BranchId\n\t): ValidatedThoughtState {\n\t\tconst history = this.loadHistoryRows(sessionId);\n\t\tfor (const thought of history) {\n\t\t\tassertThoughtScope('saveThoughtForSession', sessionId, thought);\n\t\t}\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId,\n\t\t\t\tthoughts: replacingBranch === undefined ? [...history, ...candidates] : history,\n\t\t\t},\n\t\t];\n\t\tconst branches = new Map<BranchId, ThoughtData[]>();\n\t\tfor (const row of this._db\n\t\t\t.prepare('SELECT branch_id, data FROM branches WHERE session_id = ?')\n\t\t\t.all(sessionId)) {\n\t\t\tconst branchId = parsePersistenceBranchId(\n\t\t\t\tstringField(row, 'branch_id', this._sourcePath),\n\t\t\t\tthis._sourcePath\n\t\t\t);\n\t\t\tconst data = stringField(row, 'data', this._sourcePath);\n\t\t\tlet values: unknown;\n\t\t\ttry {\n\t\t\t\tvalues = JSON.parse(data);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new PersistenceCorruptionError(this._sourcePath, error);\n\t\t\t}\n\t\t\tif (!Array.isArray(values))\n\t\t\t\tthrow new PersistenceCorruptionError(\n\t\t\t\t\tthis._sourcePath,\n\t\t\t\t\tnew TypeError('branch data is not an array')\n\t\t\t\t);\n\t\t\tconst thoughts = values.map((value, index) =>\n\t\t\t\tdecodeThoughtRow(\n\t\t\t\t\t{ data: JSON.stringify(value) },\n\t\t\t\t\t`${this._sourcePath}:branch:${sessionId}:${branchId}:${index}`\n\t\t\t\t)\n\t\t\t);\n\t\t\tassertBranchScope('saveBranchForSession', sessionId, branchId, thoughts);\n\t\t\tbranches.set(branchId, thoughts);\n\t\t\tif (branchId !== replacingBranch) collections.push({ sessionId, thoughts });\n\t\t}\n\t\tif (replacingBranch !== undefined) {\n\t\t\tcollections.push({ sessionId, thoughts: candidates });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, this._sourcePath);\n\t\treturn { history, branches };\n\t}\n\n\tprivate loadHistoryRows(sessionId: SessionId): ThoughtData[] {\n\t\treturn this._db\n\t\t\t.prepare('SELECT data FROM thoughts WHERE session_id = ? ORDER BY id ASC')\n\t\t\t.all(sessionId)\n\t\t\t.map((row) => decodeThoughtRow(row, this._sourcePath));\n\t}\n}\n"],"names":["SqlitePersistence","_db","_sourcePath","_maxHistorySize","_persistBranches","database","options","sourcePath","initializeOrValidateSqliteV2","runtime","defaultDataDir","existsSync","join","homedir","dbPath","Database","loadSqliteDatabaseConstructor","persistence","error","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","targetThoughtId","runSqliteTransaction","current","staged","stageBacktrackPersistence","branchId","thoughts","insertThought","retained","JSON","replaceBranch","branch","countRow","excess","numberField","runSqliteReadTransaction","validatedBranchId","parsePersistenceBranchId","assertBranchScope","assertPersistableThoughts","row","stringField","compareCodePoint","table","edges","assertEdgeScopes","insert","edge","undefined","index","decodeEdgeRow","summaries","assertSummaryScopes","summary","decodeSummaryRow","Error","thoughtCount","branchCount","candidates","replacingBranch","history","collections","branches","Map","data","values","PersistenceCorruptionError","Array","TypeError","value","decodeThoughtRow","assertPersistableThoughtCollections"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persistence/SqlitePersistence.js","sources":["../../src/persistence/SqlitePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type {\n\tPersistedSessionRecord,\n\tPersistenceConfig,\n\tPersistenceBackend,\n\tPersistenceRestoreRead,\n} from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCorruptionError } from '../errors.js';\nimport type { SqliteDatabase } from './SqliteDriver.js';\nimport { loadSqliteDatabaseConstructor, type SqliteDriverRuntime } from './SqliteDriverLoader.js';\nimport { runSqliteReadTransaction, runSqliteTransaction } from './SqliteDriver.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tnumberField,\n\tstringField,\n} from './SqlitePayload.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\nimport { initializeOrValidateSqliteV2 } from './SqliteSchemaV2.js';\nimport { stageBacktrackPersistence } from './BacktrackPersistence.js';\n\ntype SqliteOptions = PersistenceConfig['options'];\n\ntype ValidatedThoughtState = {\n\treadonly history: ThoughtData[];\n\treadonly branches: ReadonlyMap<BranchId, ThoughtData[]>;\n};\n\nexport class SqlitePersistence implements PersistenceBackend {\n\tprivate constructor(\n\t\tprivate readonly _db: SqliteDatabase,\n\t\tprivate readonly _sourcePath: string,\n\t\tprivate readonly _maxHistorySize: number,\n\t\tprivate readonly _persistBranches: boolean\n\t) {}\n\n\tpublic static createWithDatabase(\n\t\tdatabase: SqliteDatabase,\n\t\toptions: SqliteOptions = {},\n\t\tsourcePath = '<structural-sqlite>'\n\t): SqlitePersistence {\n\t\tinitializeOrValidateSqliteV2(database, sourcePath);\n\t\treturn new SqlitePersistence(\n\t\t\tdatabase,\n\t\t\tsourcePath,\n\t\t\toptions?.maxHistorySize ?? 10000,\n\t\t\toptions?.persistBranches ?? true\n\t\t);\n\t}\n\n\tpublic static async create(\n\t\toptions?: SqliteOptions,\n\t\truntime?: SqliteDriverRuntime\n\t): Promise<SqlitePersistence> {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tconst dbPath = options?.dbPath ?? join(defaultDataDir, 'history.db');\n\t\tconst Database = await loadSqliteDatabaseConstructor(dbPath, runtime);\n\t\tconst database = new Database(dbPath);\n\t\ttry {\n\t\t\tconst persistence = SqlitePersistence.createWithDatabase(database, options, dbPath);\n\t\t\tif (options?.enableWAL !== false) database.pragma('journal_mode = WAL');\n\t\t\tdatabase.pragma('synchronous = NORMAL');\n\t\t\tdatabase.pragma('foreign_keys = ON');\n\t\t\tdatabase.pragma('busy_timeout = 5000');\n\t\t\tdatabase.pragma('cache_size = -64000');\n\t\t\tdatabase.pragma('temp_store = MEMORY');\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tdatabase.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tthis._saveThought(validatedSessionId, thought);\n\t}\n\n\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tconst current = this._loadValidatedThoughtState(validatedSessionId);\n\t\t\tconst staged = stageBacktrackPersistence(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tcurrent.history,\n\t\t\t\t[...current.branches].map(([branchId, thoughts]) => ({ branchId, thoughts })),\n\t\t\t\tthought,\n\t\t\t\ttargetThoughtId,\n\t\t\t\tthis._maxHistorySize\n\t\t\t);\n\t\t\tthis._db.prepare('DELETE FROM thoughts WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insertThought = this._db.prepare(\n\t\t\t\t'INSERT INTO thoughts (session_id, data) VALUES (?, ?)'\n\t\t\t);\n\t\t\tfor (const retained of staged.history) {\n\t\t\t\tinsertThought.run(validatedSessionId, JSON.stringify(retained));\n\t\t\t}\n\t\t\tconst replaceBranch = this._db.prepare(\n\t\t\t\t'INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const branch of staged.branches) {\n\t\t\t\treplaceBranch.run(validatedSessionId, branch.branchId, JSON.stringify(branch.thoughts));\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate _saveThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, [thought]);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT INTO thoughts (session_id, data) VALUES (?, ?)')\n\t\t\t\t.run(sessionId, JSON.stringify(thought));\n\t\t\tif (this._maxHistorySize > 0) {\n\t\t\t\tconst countRow = this._db\n\t\t\t\t\t.prepare('SELECT COUNT(*) AS count FROM thoughts WHERE session_id = ?')\n\t\t\t\t\t.get(sessionId);\n\t\t\t\tconst excess =\n\t\t\t\t\tnumberField(countRow, 'count', `${this._sourcePath}:thought-count`) -\n\t\t\t\t\tthis._maxHistorySize;\n\t\t\t\tif (excess > 0) {\n\t\t\t\t\tthis._db\n\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t'DELETE FROM thoughts WHERE id IN (SELECT id FROM thoughts WHERE session_id = ? ORDER BY id ASC LIMIT ?)'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.run(sessionId, excess);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn runSqliteReadTransaction(\n\t\t\tthis._db,\n\t\t\t() => this._loadValidatedThoughtState(validatedSessionId).history\n\t\t);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tthis._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tassertPersistableThoughts(thoughts, `${this._sourcePath}:branch:${branchId}`);\n\t\tif (!this._persistBranches) {\n\t\t\trunSqliteReadTransaction(this._db, () =>\n\t\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)')\n\t\t\t\t.run(sessionId, branchId, JSON.stringify(thoughts));\n\t\t});\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db\n\t\t\t\t.prepare('DELETE FROM branches WHERE session_id = ? AND branch_id = ?')\n\t\t\t\t.run(validatedSessionId, validatedBranchId);\n\t\t});\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\treturn runSqliteReadTransaction(this._db, () =>\n\t\t\tthis._loadValidatedThoughtState(validatedSessionId).branches.get(validatedBranchId)\n\t\t);\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn this._db\n\t\t\t.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC')\n\t\t\t.all(asSessionId(sessionId))\n\t\t\t.map((row) =>\n\t\t\t\tparsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath)\n\t\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn this._selectSessionIds();\n\t}\n\n\tpublic async loadAllSessionsForRestore(): Promise<PersistenceRestoreRead> {\n\t\treturn runSqliteReadTransaction(this._db, () => ({\n\t\t\tsessions: this._selectSessionIds().map((sessionId) => this._restoreRecord(sessionId)),\n\t\t}));\n\t}\n\n\tprivate _selectSessionIds(): SessionId[] {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries'\n\t\t\t)\n\t\t\t.all()\n\t\t\t.map((row) => asSessionId(stringField(row, 'session_id', this._sourcePath)))\n\t\t\t.sort(compareCodePoint);\n\t}\n\n\tprivate _restoreRecord(sessionId: SessionId): PersistedSessionRecord {\n\t\tconst state = this._loadValidatedThoughtState(sessionId);\n\t\treturn {\n\t\t\tsessionId,\n\t\t\thistory: state.history,\n\t\t\tbranches: this._persistBranches\n\t\t\t\t? [...state.branches]\n\t\t\t\t\t\t.map(([branchId, thoughts]) => ({ branchId, thoughts }))\n\t\t\t\t\t\t.sort((left, right) => compareCodePoint(left.branchId, right.branchId))\n\t\t\t\t: [],\n\t\t\tedges: this._selectEdges(sessionId),\n\t\t\tsummaries: this._selectSummaries(sessionId),\n\t\t};\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries'])\n\t\t\t\tthis._db.exec(`DELETE FROM ${table}`);\n\t\t});\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries']) {\n\t\t\t\tthis._db.prepare(`DELETE FROM ${table} WHERE session_id = ?`).run(validatedSessionId);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM edges WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const edge of edges)\n\t\t\t\tinsert.run(\n\t\t\t\t\tedge.id,\n\t\t\t\t\tedge.sessionId,\n\t\t\t\t\tedge.from,\n\t\t\t\t\tedge.to,\n\t\t\t\t\tedge.kind,\n\t\t\t\t\tedge.createdAt,\n\t\t\t\t\tedge.metadata === undefined ? null : JSON.stringify(edge.metadata)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\treturn this._selectEdges(asSessionId(sessionId));\n\t}\n\n\tprivate _selectEdges(sessionId: SessionId): Edge[] {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(sessionId)\n\t\t\t.map((row, index) => decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM summaries WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO summaries (id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const summary of summaries)\n\t\t\t\tinsert.run(\n\t\t\t\t\tsummary.id,\n\t\t\t\t\tsummary.sessionId,\n\t\t\t\t\tsummary.branchId ?? null,\n\t\t\t\t\tsummary.rootThoughtId,\n\t\t\t\t\tJSON.stringify(summary.coveredIds),\n\t\t\t\t\tsummary.coveredRange[0],\n\t\t\t\t\tsummary.coveredRange[1],\n\t\t\t\t\tJSON.stringify(summary.topics),\n\t\t\t\t\tsummary.aggregateConfidence,\n\t\t\t\t\tsummary.createdAt,\n\t\t\t\t\tsummary.meta === undefined ? null : JSON.stringify(summary.meta)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\treturn this._selectSummaries(asSessionId(sessionId));\n\t}\n\n\tprivate _selectSummaries(sessionId: SessionId): Summary[] {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(sessionId)\n\t\t\t.map((row, index) => decodeSummaryRow(row, `${this._sourcePath}:summaries:${index}`));\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis._db.close();\n\t}\n\n\tpublic getStats(): {\n\t\treadonly thoughtCount: number;\n\t\treadonly branchCount: number;\n\t\treadonly dbSize: number;\n\t} {\n\t\tconst thoughtCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM thoughts').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\tconst branchCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM branches').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\treturn { thoughtCount, branchCount: this._persistBranches ? branchCount : 0, dbSize: 0 };\n\t}\n\n\tprivate _loadValidatedThoughtState(\n\t\tsessionId: SessionId,\n\t\tcandidates: readonly ThoughtData[] = [],\n\t\treplacingBranch?: BranchId\n\t): ValidatedThoughtState {\n\t\tconst history = this.loadHistoryRows(sessionId);\n\t\tfor (const thought of history) {\n\t\t\tassertThoughtScope('saveThoughtForSession', sessionId, thought);\n\t\t}\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId,\n\t\t\t\tthoughts: replacingBranch === undefined ? [...history, ...candidates] : history,\n\t\t\t},\n\t\t];\n\t\tconst branches = new Map<BranchId, ThoughtData[]>();\n\t\tfor (const row of this._db\n\t\t\t.prepare('SELECT branch_id, data FROM branches WHERE session_id = ?')\n\t\t\t.all(sessionId)) {\n\t\t\tconst branchId = parsePersistenceBranchId(\n\t\t\t\tstringField(row, 'branch_id', this._sourcePath),\n\t\t\t\tthis._sourcePath\n\t\t\t);\n\t\t\tconst data = stringField(row, 'data', this._sourcePath);\n\t\t\tlet values: unknown;\n\t\t\ttry {\n\t\t\t\tvalues = JSON.parse(data);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new PersistenceCorruptionError(this._sourcePath, error);\n\t\t\t}\n\t\t\tif (!Array.isArray(values))\n\t\t\t\tthrow new PersistenceCorruptionError(\n\t\t\t\t\tthis._sourcePath,\n\t\t\t\t\tnew TypeError('branch data is not an array')\n\t\t\t\t);\n\t\t\tconst thoughts = values.map((value, index) =>\n\t\t\t\tdecodeThoughtRow(\n\t\t\t\t\t{ data: JSON.stringify(value) },\n\t\t\t\t\t`${this._sourcePath}:branch:${sessionId}:${branchId}:${index}`\n\t\t\t\t)\n\t\t\t);\n\t\t\tassertBranchScope('saveBranchForSession', sessionId, branchId, thoughts);\n\t\t\tbranches.set(branchId, thoughts);\n\t\t\tif (branchId !== replacingBranch) collections.push({ sessionId, thoughts });\n\t\t}\n\t\tif (replacingBranch !== undefined) {\n\t\t\tcollections.push({ sessionId, thoughts: candidates });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, this._sourcePath);\n\t\treturn { history, branches };\n\t}\n\n\tprivate loadHistoryRows(sessionId: SessionId): ThoughtData[] {\n\t\treturn this._db\n\t\t\t.prepare('SELECT data FROM thoughts WHERE session_id = ? ORDER BY id ASC')\n\t\t\t.all(sessionId)\n\t\t\t.map((row) => decodeThoughtRow(row, this._sourcePath));\n\t}\n}\n"],"names":["SqlitePersistence","_db","_sourcePath","_maxHistorySize","_persistBranches","database","options","sourcePath","initializeOrValidateSqliteV2","runtime","defaultDataDir","existsSync","join","homedir","dbPath","Database","loadSqliteDatabaseConstructor","persistence","error","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","targetThoughtId","runSqliteTransaction","current","staged","stageBacktrackPersistence","branchId","thoughts","insertThought","retained","JSON","replaceBranch","branch","countRow","excess","numberField","runSqliteReadTransaction","validatedBranchId","parsePersistenceBranchId","assertBranchScope","assertPersistableThoughts","row","stringField","compareCodePoint","state","left","right","table","edges","assertEdgeScopes","insert","edge","undefined","index","decodeEdgeRow","summaries","assertSummaryScopes","summary","decodeSummaryRow","Error","thoughtCount","branchCount","candidates","replacingBranch","history","collections","branches","Map","data","values","PersistenceCorruptionError","Array","TypeError","value","decodeThoughtRow","assertPersistableThoughtCollections"],"mappings":"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"}
|