@iworkforces/tracelattice 2.0.8 → 2.1.1

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.
Files changed (174) hide show
  1. package/README.md +88 -64
  2. package/dist/ServerConfig.d.ts +1 -1
  3. package/dist/ServerConfig.js.map +1 -1
  4. package/dist/cli.js +18 -73
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/ConfigLoader.d.ts +29 -26
  7. package/dist/config/ConfigLoader.d.ts.map +1 -1
  8. package/dist/config/ConfigLoader.js +40 -36
  9. package/dist/config/ConfigLoader.js.map +1 -1
  10. package/dist/contracts/PersistenceBackend.d.ts +7 -108
  11. package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
  12. package/dist/contracts/PersistenceBackend.js +1 -6
  13. package/dist/contracts/calibrator.d.ts +6 -6
  14. package/dist/contracts/calibrator.d.ts.map +1 -1
  15. package/dist/contracts/ids.d.ts +1 -8
  16. package/dist/contracts/ids.d.ts.map +1 -1
  17. package/dist/contracts/ids.js +2 -3
  18. package/dist/contracts/ids.js.map +1 -1
  19. package/dist/contracts/interfaces.d.ts +4 -6
  20. package/dist/contracts/interfaces.d.ts.map +1 -1
  21. package/dist/contracts/persistence-work.d.ts +2 -3
  22. package/dist/contracts/persistence-work.d.ts.map +1 -1
  23. package/dist/core/HistoryManager.d.ts +12 -16
  24. package/dist/core/HistoryManager.d.ts.map +1 -1
  25. package/dist/core/HistoryManager.js +19 -40
  26. package/dist/core/HistoryManager.js.map +1 -1
  27. package/dist/core/IHistoryManager.d.ts +22 -30
  28. package/dist/core/IHistoryManager.d.ts.map +1 -1
  29. package/dist/core/InputNormalizer.d.ts +7 -24
  30. package/dist/core/InputNormalizer.d.ts.map +1 -1
  31. package/dist/core/InputNormalizer.js +3 -9
  32. package/dist/core/InputNormalizer.js.map +1 -1
  33. package/dist/core/PersistenceBuffer.d.ts +3 -20
  34. package/dist/core/PersistenceBuffer.d.ts.map +1 -1
  35. package/dist/core/PersistenceBuffer.js +1 -4
  36. package/dist/core/PersistenceBuffer.js.map +1 -1
  37. package/dist/core/PersistenceRestore.d.ts.map +1 -1
  38. package/dist/core/PersistenceRestore.js +4 -10
  39. package/dist/core/PersistenceRestore.js.map +1 -1
  40. package/dist/core/PersistenceWriter.d.ts.map +1 -1
  41. package/dist/core/PersistenceWriter.js +3 -12
  42. package/dist/core/PersistenceWriter.js.map +1 -1
  43. package/dist/core/SessionErrors.d.ts +0 -11
  44. package/dist/core/SessionErrors.d.ts.map +1 -1
  45. package/dist/core/SessionErrors.js +1 -14
  46. package/dist/core/SessionErrors.js.map +1 -1
  47. package/dist/core/SessionLock.d.ts +4 -5
  48. package/dist/core/SessionLock.d.ts.map +1 -1
  49. package/dist/core/SessionLock.js +5 -10
  50. package/dist/core/SessionLock.js.map +1 -1
  51. package/dist/core/SessionManager.d.ts +0 -2
  52. package/dist/core/SessionManager.d.ts.map +1 -1
  53. package/dist/core/SessionManager.js +3 -5
  54. package/dist/core/SessionManager.js.map +1 -1
  55. package/dist/core/SessionResetCoordinator.d.ts +10 -7
  56. package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
  57. package/dist/core/SessionResetCoordinator.js +10 -28
  58. package/dist/core/SessionResetCoordinator.js.map +1 -1
  59. package/dist/core/ThoughtEvaluator.d.ts +5 -5
  60. package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
  61. package/dist/core/ThoughtEvaluator.js +4 -40
  62. package/dist/core/ThoughtEvaluator.js.map +1 -1
  63. package/dist/core/ThoughtProcessor.d.ts +10 -3
  64. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  65. package/dist/core/ThoughtProcessor.js +34 -38
  66. package/dist/core/ThoughtProcessor.js.map +1 -1
  67. package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
  68. package/dist/core/VerificationOutcomeAdmission.js +5 -7
  69. package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
  70. package/dist/core/evaluator/Calibrator.d.ts +1 -1
  71. package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
  72. package/dist/core/evaluator/Calibrator.js +2 -5
  73. package/dist/core/evaluator/Calibrator.js.map +1 -1
  74. package/dist/core/evaluator/internals.d.ts +0 -4
  75. package/dist/core/evaluator/internals.d.ts.map +1 -1
  76. package/dist/core/evaluator/internals.js +1 -3
  77. package/dist/core/evaluator/internals.js.map +1 -1
  78. package/dist/core/graph/Edge.d.ts +1 -1
  79. package/dist/core/graph/EdgeEmitter.d.ts +2 -4
  80. package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
  81. package/dist/core/graph/EdgeEmitter.js +2 -4
  82. package/dist/core/graph/EdgeEmitter.js.map +1 -1
  83. package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
  84. package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
  85. package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
  86. package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
  87. package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
  88. package/dist/core/thought.d.ts +2 -1
  89. package/dist/core/thought.d.ts.map +1 -1
  90. package/dist/errors.d.ts +4 -20
  91. package/dist/errors.d.ts.map +1 -1
  92. package/dist/errors.js +2 -28
  93. package/dist/errors.js.map +1 -1
  94. package/dist/lib.d.ts +13 -20
  95. package/dist/lib.d.ts.map +1 -1
  96. package/dist/lib.js +4 -7
  97. package/dist/lib.js.map +1 -1
  98. package/dist/logger/NullLogger.d.ts +9 -11
  99. package/dist/logger/NullLogger.d.ts.map +1 -1
  100. package/dist/logger/NullLogger.js.map +1 -1
  101. package/dist/persistence/FilePersistence.d.ts +3 -12
  102. package/dist/persistence/FilePersistence.d.ts.map +1 -1
  103. package/dist/persistence/FilePersistence.js +9 -61
  104. package/dist/persistence/FilePersistence.js.map +1 -1
  105. package/dist/persistence/FileSnapshotV2.d.ts +2 -2
  106. package/dist/persistence/FileSnapshotV2.js +2 -2
  107. package/dist/persistence/FileSnapshotV2.js.map +1 -1
  108. package/dist/persistence/FileWriter.d.ts +1 -0
  109. package/dist/persistence/FileWriter.d.ts.map +1 -1
  110. package/dist/persistence/FileWriter.js +3 -3
  111. package/dist/persistence/FileWriter.js.map +1 -1
  112. package/dist/persistence/MemoryPersistence.d.ts +5 -15
  113. package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
  114. package/dist/persistence/MemoryPersistence.js +6 -40
  115. package/dist/persistence/MemoryPersistence.js.map +1 -1
  116. package/dist/persistence/PersistenceCodec.js +1 -3
  117. package/dist/persistence/PersistenceCodec.js.map +1 -1
  118. package/dist/persistence/PersistenceErrors.d.ts +0 -6
  119. package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
  120. package/dist/persistence/PersistenceErrors.js +1 -9
  121. package/dist/persistence/PersistenceErrors.js.map +1 -1
  122. package/dist/persistence/PersistenceScope.d.ts.map +1 -1
  123. package/dist/persistence/PersistenceScope.js +2 -2
  124. package/dist/persistence/PersistenceScope.js.map +1 -1
  125. package/dist/persistence/SqlitePersistence.d.ts +3 -10
  126. package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
  127. package/dist/persistence/SqlitePersistence.js +2 -26
  128. package/dist/persistence/SqlitePersistence.js.map +1 -1
  129. package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
  130. package/dist/persistence/SqliteSchemaV2.js +3 -12
  131. package/dist/persistence/SqliteSchemaV2.js.map +1 -1
  132. package/dist/pool/ConnectionPool.d.ts +3 -12
  133. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  134. package/dist/pool/ConnectionPool.js +5 -8
  135. package/dist/pool/ConnectionPool.js.map +1 -1
  136. package/dist/pool/IConnectionPool.d.ts +3 -9
  137. package/dist/pool/IConnectionPool.d.ts.map +1 -1
  138. package/dist/registry/SkillRegistry.d.ts +1 -7
  139. package/dist/registry/SkillRegistry.d.ts.map +1 -1
  140. package/dist/registry/SkillRegistry.js +0 -15
  141. package/dist/registry/SkillRegistry.js.map +1 -1
  142. package/dist/registry/ToolRegistry.d.ts +1 -9
  143. package/dist/registry/ToolRegistry.d.ts.map +1 -1
  144. package/dist/registry/ToolRegistry.js +0 -21
  145. package/dist/registry/ToolRegistry.js.map +1 -1
  146. package/dist/schema.d.ts +2 -1
  147. package/dist/schema.d.ts.map +1 -1
  148. package/dist/schema.js +3 -3
  149. package/dist/schema.js.map +1 -1
  150. package/dist/transport/BaseTransport.d.ts +0 -9
  151. package/dist/transport/BaseTransport.d.ts.map +1 -1
  152. package/dist/transport/BaseTransport.js +0 -11
  153. package/dist/transport/BaseTransport.js.map +1 -1
  154. package/dist/watchers/SkillWatcher.d.ts.map +1 -1
  155. package/dist/watchers/SkillWatcher.js +1 -1
  156. package/dist/watchers/SkillWatcher.js.map +1 -1
  157. package/package.json +1 -1
  158. package/dist/contracts/PersistenceBackend.js.map +0 -1
  159. package/dist/persistence/FileLegacyImport.d.ts +0 -2
  160. package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
  161. package/dist/persistence/FileLegacyImport.js +0 -183
  162. package/dist/persistence/FileLegacyImport.js.map +0 -1
  163. package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
  164. package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
  165. package/dist/persistence/SessionScopedPersistence.js +0 -9
  166. package/dist/persistence/SessionScopedPersistence.js.map +0 -1
  167. package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
  168. package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
  169. package/dist/persistence/SqliteLegacyImport.js +0 -136
  170. package/dist/persistence/SqliteLegacyImport.js.map +0 -1
  171. package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
  172. package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
  173. package/dist/persistence/SqliteLegacySchema.js +0 -72
  174. package/dist/persistence/SqliteLegacySchema.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"watchers/SkillWatcher.js","sources":["../../src/watchers/SkillWatcher.ts"],"sourcesContent":["import { watch, type FSWatcher } from 'chokidar';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { getErrorMessage } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { SkillRegistry } from '../registry/SkillRegistry.js';\n\n/** Watches skill discovery directories and serializes registry refreshes. */\nexport class SkillWatcher {\n\tprivate _watcher: FSWatcher | null = null;\n\tprivate readonly _logger: Logger;\n\tprivate readonly _readyPromise: Promise<void>;\n\tprivate _pendingRefresh: Promise<void> | null = null;\n\tprivate _refreshQueued = false;\n\tprivate _stopped = false;\n\tprivate _stopPromise: Promise<void> | null = null;\n\n\tconstructor(\n\t\tprivate readonly _skillRegistry: SkillRegistry,\n\t\tlogger?: Logger,\n\t\twatchDirs: readonly string[] = ['.claude/skills', join(homedir(), '.claude/skills')]\n\t) {\n\t\tthis._logger = logger ?? this._createNoopLogger();\n\t\tthis._readyPromise = this._setupWatcher(watchDirs);\n\t}\n\n\tprivate _createNoopLogger(): Logger {\n\t\treturn {\n\t\t\tinfo: () => {},\n\t\t\twarn: () => {},\n\t\t\terror: () => {},\n\t\t\tdebug: () => {},\n\t\t\tsetLevel: () => {},\n\t\t\tgetLevel: () => 'info',\n\t\t};\n\t}\n\n\tprivate _setupWatcher(watchDirs: readonly string[]): Promise<void> {\n\t\tif (watchDirs.length === 0) return Promise.resolve();\n\t\tconst watcher = watch([...watchDirs], {\n\t\t\tignored: [/node_modules/, /\\.DS_Store$/],\n\t\t\tpersistent: true,\n\t\t\tignoreInitial: true,\n\t\t});\n\t\tthis._watcher = watcher;\n\t\twatcher.on('add', (path) => this._handleEvent('added', path));\n\t\twatcher.on('change', (path) => this._handleEvent('modified', path));\n\t\twatcher.on('unlink', (path) => this._handleEvent('removed', path));\n\t\treturn new Promise((resolve) => watcher.on('ready', () => resolve()));\n\t}\n\n\tprivate _handleEvent(action: string, path: string): Promise<void> {\n\t\tif (this._stopped) return Promise.resolve();\n\t\tif (!path.includes('.DS_Store')) this._log(`Skill ${action}: ${path.split(/[/\\\\]/).pop()}`);\n\t\treturn this._scheduleRefresh(path);\n\t}\n\n\tprivate _scheduleRefresh(path: string): Promise<void> {\n\t\tthis._refreshQueued = true;\n\t\tif (!this._pendingRefresh) {\n\t\t\tthis._pendingRefresh = this._drainRefreshes(path).finally(() => {\n\t\t\t\tthis._pendingRefresh = null;\n\t\t\t});\n\t\t}\n\t\treturn this._pendingRefresh;\n\t}\n\n\tprivate async _drainRefreshes(path: string): Promise<void> {\n\t\twhile (this._refreshQueued) {\n\t\t\tthis._refreshQueued = false;\n\t\t\ttry {\n\t\t\t\tawait this._skillRegistry.refreshAsync();\n\t\t\t} catch (error) {\n\t\t\t\tthis._logger.error('Skill discovery refresh failed', {\n\t\t\t\t\tpath,\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _log(message: string): void {\n\t\tif (process.env.WATCHER_VERBOSE === 'true') this._logger.debug(`[Watcher] ${message}`);\n\t}\n\n\t/** Resolves when Chokidar has completed its initial scan. */\n\tpublic ready(): Promise<void> {\n\t\treturn this._readyPromise;\n\t}\n\n\t/** Closes Chokidar and joins any refresh accepted before shutdown. */\n\tpublic stop(): Promise<void> {\n\t\tif (this._stopPromise) return this._stopPromise;\n\t\tthis._stopped = true;\n\t\tconst watcher = this._watcher;\n\t\tconst pendingRefresh = this._pendingRefresh;\n\t\tthis._watcher = null;\n\t\tthis._stopPromise = Promise.all([watcher?.close(), pendingRefresh]).then(() => undefined);\n\t\treturn this._stopPromise;\n\t}\n}\n"],"names":["SkillWatcher","_skillRegistry","logger","watchDirs","join","homedir","Promise","watcher","watch","path","resolve","action","error","getErrorMessage","message","process","pendingRefresh","undefined"],"mappings":"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"}
1
+ {"version":3,"file":"watchers/SkillWatcher.js","sources":["../../src/watchers/SkillWatcher.ts"],"sourcesContent":["import { watch, type FSWatcher } from 'chokidar';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { getErrorMessage } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { SkillRegistry } from '../registry/SkillRegistry.js';\n\n/** Watches skill discovery directories and serializes registry refreshes. */\nexport class SkillWatcher {\n\tprivate _watcher: FSWatcher | null = null;\n\tprivate readonly _logger: Logger;\n\tprivate readonly _readyPromise: Promise<void>;\n\tprivate _pendingRefresh: Promise<void> | null = null;\n\tprivate _refreshQueued = false;\n\tprivate _stopped = false;\n\tprivate _stopPromise: Promise<void> | null = null;\n\n\tconstructor(\n\t\tprivate readonly _skillRegistry: SkillRegistry,\n\t\tlogger?: Logger,\n\t\twatchDirs: readonly string[] = ['.claude/skills', join(homedir(), '.claude/skills')]\n\t) {\n\t\tthis._logger = logger ?? this._createNoopLogger();\n\t\tthis._readyPromise = this._setupWatcher(watchDirs);\n\t}\n\n\tprivate _createNoopLogger(): Logger {\n\t\treturn {\n\t\t\tinfo: () => {},\n\t\t\twarn: () => {},\n\t\t\terror: () => {},\n\t\t\tdebug: () => {},\n\t\t\tsetLevel: () => {},\n\t\t\tgetLevel: () => 'info',\n\t\t};\n\t}\n\n\tprivate _setupWatcher(watchDirs: readonly string[]): Promise<void> {\n\t\tif (watchDirs.length === 0) return Promise.resolve();\n\t\tconst watcher = watch([...watchDirs], {\n\t\t\tignored: [/node_modules/, /\\.DS_Store$/],\n\t\t\tpersistent: true,\n\t\t\tignoreInitial: true,\n\t\t});\n\t\tthis._watcher = watcher;\n\t\twatcher.on('add', (path) => this._handleEvent('added', path));\n\t\twatcher.on('change', (path) => this._handleEvent('modified', path));\n\t\twatcher.on('unlink', (path) => this._handleEvent('removed', path));\n\t\treturn new Promise((resolve) => watcher.on('ready', () => resolve()));\n\t}\n\n\tprivate _handleEvent(action: string, path: string): Promise<void> {\n\t\tif (this._stopped) return Promise.resolve();\n\t\tif (!path.includes('.DS_Store')) this._log(`Skill ${action}: ${path.split(/[/\\\\]/).pop()}`);\n\t\treturn this._scheduleRefresh(path);\n\t}\n\n\tprivate _scheduleRefresh(path: string): Promise<void> {\n\t\tthis._refreshQueued = true;\n\t\tif (!this._pendingRefresh) {\n\t\t\tthis._pendingRefresh = this._drainRefreshes(path).finally(() => {\n\t\t\t\tthis._pendingRefresh = null;\n\t\t\t});\n\t\t}\n\t\treturn this._pendingRefresh;\n\t}\n\n\tprivate async _drainRefreshes(path: string): Promise<void> {\n\t\twhile (this._refreshQueued) {\n\t\t\tthis._refreshQueued = false;\n\t\t\ttry {\n\t\t\t\tawait this._skillRegistry.refreshAsync();\n\t\t\t} catch (error) {\n\t\t\t\tthis._logger.error('Skill discovery refresh failed', {\n\t\t\t\t\tpath,\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _log(message: string): void {\n\t\tif (process.env.TRACELATTICE_WATCHER_VERBOSE === 'true') {\n\t\t\tthis._logger.debug(`[Watcher] ${message}`);\n\t\t}\n\t}\n\n\t/** Resolves when Chokidar has completed its initial scan. */\n\tpublic ready(): Promise<void> {\n\t\treturn this._readyPromise;\n\t}\n\n\t/** Closes Chokidar and joins any refresh accepted before shutdown. */\n\tpublic stop(): Promise<void> {\n\t\tif (this._stopPromise) return this._stopPromise;\n\t\tthis._stopped = true;\n\t\tconst watcher = this._watcher;\n\t\tconst pendingRefresh = this._pendingRefresh;\n\t\tthis._watcher = null;\n\t\tthis._stopPromise = Promise.all([watcher?.close(), pendingRefresh]).then(() => undefined);\n\t\treturn this._stopPromise;\n\t}\n}\n"],"names":["SkillWatcher","_skillRegistry","logger","watchDirs","join","homedir","Promise","watcher","watch","path","resolve","action","error","getErrorMessage","message","process","pendingRefresh","undefined"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iworkforces/tracelattice",
3
- "version": "2.0.8",
3
+ "version": "2.1.1",
4
4
  "description": "Semantic Sequential Thinking Layer For AI Agents.",
5
5
  "type": "module",
6
6
  "main": "dist/lib.js",
@@ -1 +0,0 @@
1
- {"version":3,"file":"contracts/PersistenceBackend.js","sources":["../../src/contracts/PersistenceBackend.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 { BranchId, SessionId } from './ids.js';\n\n/**\n * Persistence backend interface for storing thought history and branches.\n *\n * Implementations can store data in various formats (JSON files, SQLite, etc.)\n * while providing a unified API for HistoryManager.\n */\nexport interface PersistenceBackend {\n\t/**\n\t * Save a single thought to persistent storage.\n\t *\n\t * @param thought - The thought data to persist\n\t */\n\tsaveThought(thought: ThoughtData): Promise<void>;\n\n\t/**\n\t * Load all thoughts from persistent storage.\n\t * Returns thoughts in chronological order (oldest first).\n\t *\n\t * @returns Array of all persisted thoughts\n\t */\n\tloadHistory(): Promise<ThoughtData[]>;\n\n\t/**\n\t * Save all thoughts in a branch to persistent storage.\n\t *\n\t * @param branchId - The unique identifier for the branch\n\t * @param thoughts - Array of thoughts in branch\n\t */\n\tsaveBranch(branchId: BranchId, thoughts: ThoughtData[]): Promise<void>;\n\n\t/**\n\t * Delete one global branch without treating an empty branch as deletion.\n\t *\n\t * Optional on legacy backends; the complete scoped capability requires it.\n\t *\n\t * @param branchId - The branch identifier to delete\n\t */\n\tdeleteBranch?(branchId: BranchId): Promise<void>;\n\n\t/**\n\t * Load all thoughts for a specific branch.\n\t *\n\t * @param branchId - The unique identifier for the branch\n\t * @returns Array of thoughts in branch, or undefined if branch doesn't exist\n\t */\n\tloadBranch(branchId: BranchId): Promise<ThoughtData[] | undefined>;\n\n\t/**\n\t * List all branch IDs that are persisted.\n\t *\n\t * @returns Array of branch identifiers\n\t */\n\tlistBranches(): Promise<BranchId[]>;\n\n\t/**\n\t * Check if backend is healthy.\n\t * @returns Promise that resolves to true if healthy, false otherwise\n\t */\n\thealthy(): Promise<boolean>;\n\n\t/**\n\t * Clear all persisted data (history and branches).\n\t * Use with caution - this cannot be undone.\n\t */\n\tclear(): Promise<void>;\n\n\t/**\n\t * Close the backend and release resources.\n\t * Should be called during graceful shutdown to ensure data is flushed.\n\t */\n\tclose(): Promise<void>;\n\n\t/**\n\t * Save edges for a session, replacing any previously saved edges.\n\t *\n\t * @param sessionId - The session whose edges to persist\n\t * @param edges - Array of edges to save\n\t */\n\tsaveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void>;\n\n\t/**\n\t * Load edges for a session from persistent storage.\n\t * Returns edges in chronological order (by createdAt ascending).\n\t * Returns empty array if no edges exist for the session.\n\t *\n\t * @param sessionId - The session whose edges to load\n\t * @returns Array of persisted edges, sorted by createdAt\n\t */\n\tloadEdges(sessionId: SessionId): Promise<Edge[]>;\n\n\t/**\n\t * List all session IDs that have persisted edge data.\n\t *\n\t * @returns Array of session identifiers with persisted edges\n\t */\n\tlistEdgeSessions(): Promise<SessionId[]>;\n\n\t/**\n\t * Save summaries for a session, replacing any previously saved summaries.\n\t *\n\t * @param sessionId - The session whose summaries to persist\n\t * @param summaries - Array of summaries to save\n\t */\n\tsaveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void>;\n\n\t/**\n\t * Load summaries for a session from persistent storage.\n\t * Returns summaries in chronological order (by createdAt ascending).\n\t * Returns empty array if no summaries exist for the session.\n\t *\n\t * @param sessionId - The session whose summaries to load\n\t * @returns Array of persisted summaries, sorted by createdAt\n\t */\n\tloadSummaries(sessionId: SessionId): Promise<Summary[]>;\n}\n\n/** Session-scoped persistence operations implemented as one indivisible capability. */\nexport type SessionScopedPersistenceOperation =\n\t| 'saveThoughtForSession'\n\t| 'loadHistoryForSession'\n\t| 'saveBranchForSession'\n\t| 'deleteBranch'\n\t| 'deleteBranchForSession'\n\t| 'loadBranchForSession'\n\t| 'listBranchesForSession'\n\t| 'listSessions'\n\t| 'clearSession';\n\n/** Persistence contract for durable named-session isolation. */\nexport interface SessionScopedPersistenceBackend extends PersistenceBackend {\n\tdeleteBranch(branchId: BranchId): Promise<void>;\n\tsaveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void>;\n\tloadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]>;\n\tsaveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void>;\n\tdeleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void>;\n\tloadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined>;\n\tlistBranchesForSession(sessionId: SessionId): Promise<BranchId[]>;\n\tlistSessions(): Promise<SessionId[]>;\n\tclearSession(sessionId: SessionId): Promise<void>;\n}\n\n/** Return whether a backend implements every session-scoped operation. */\nexport function supportsSessionScopedPersistence(\n\tbackend: PersistenceBackend\n): backend is SessionScopedPersistenceBackend {\n\treturn (\n\t\t'saveThoughtForSession' in backend &&\n\t\ttypeof backend.saveThoughtForSession === 'function' &&\n\t\t'loadHistoryForSession' in backend &&\n\t\ttypeof backend.loadHistoryForSession === 'function' &&\n\t\t'saveBranchForSession' in backend &&\n\t\ttypeof backend.saveBranchForSession === 'function' &&\n\t\t'deleteBranch' in backend &&\n\t\ttypeof backend.deleteBranch === 'function' &&\n\t\t'deleteBranchForSession' in backend &&\n\t\ttypeof backend.deleteBranchForSession === 'function' &&\n\t\t'loadBranchForSession' in backend &&\n\t\ttypeof backend.loadBranchForSession === 'function' &&\n\t\t'listBranchesForSession' in backend &&\n\t\ttypeof backend.listBranchesForSession === 'function' &&\n\t\t'listSessions' in backend &&\n\t\ttypeof backend.listSessions === 'function' &&\n\t\t'clearSession' in backend &&\n\t\ttypeof backend.clearSession === 'function'\n\t);\n}\n\nexport interface PersistenceConfig {\n\tenabled?: boolean;\n\tbackend?: 'file' | 'sqlite' | 'memory';\n\toptions?: {\n\t\tdataDir?: string;\n\t\tdbPath?: string;\n\t\tenableWAL?: boolean;\n\t\tmaxHistorySize?: number;\n\t\tpersistBranches?: boolean;\n\t};\n}\n"],"names":["supportsSessionScopedPersistence","backend"],"mappings":"AA0JO,SAASA,iCACfC,OAA2B;IAE3B,OACC,2BAA2BA,WAC3B,AAAyC,cAAzC,OAAOA,QAAQ,qBAAqB,IACpC,2BAA2BA,WAC3B,AAAyC,cAAzC,OAAOA,QAAQ,qBAAqB,IACpC,0BAA0BA,WAC1B,AAAwC,cAAxC,OAAOA,QAAQ,oBAAoB,IACnC,kBAAkBA,WAClB,AAAgC,cAAhC,OAAOA,QAAQ,YAAY,IAC3B,4BAA4BA,WAC5B,AAA0C,cAA1C,OAAOA,QAAQ,sBAAsB,IACrC,0BAA0BA,WAC1B,AAAwC,cAAxC,OAAOA,QAAQ,oBAAoB,IACnC,4BAA4BA,WAC5B,AAA0C,cAA1C,OAAOA,QAAQ,sBAAsB,IACrC,kBAAkBA,WAClB,AAAgC,cAAhC,OAAOA,QAAQ,YAAY,IAC3B,kBAAkBA,WAClB,AAAgC,cAAhC,OAAOA,QAAQ,YAAY;AAE7B"}
@@ -1,2 +0,0 @@
1
- export declare function importLegacyFileV1(sourceDataDir: string, destinationDataDir: string): Promise<void>;
2
- //# sourceMappingURL=FileLegacyImport.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileLegacyImport.d.ts","sourceRoot":"","sources":["../../src/persistence/FileLegacyImport.ts"],"names":[],"mappings":"AA4LA,wBAAsB,kBAAkB,CACvC,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
@@ -1,183 +0,0 @@
1
- import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm } from "node:fs/promises";
2
- import { basename, dirname, join } from "node:path";
3
- import { GLOBAL_SESSION_ID, asSessionId } from "../contracts/ids.js";
4
- import { PersistenceCompatibilityError, PersistenceCorruptionError, PersistenceLegacyAmbiguityError } from "../errors.js";
5
- import { EdgeSchema } from "../schema.js";
6
- import { SummarySchema } from "../core/compression/Summary.js";
7
- import { parseEdge, parseSummary, parseThoughtData } from "./PersistenceCodec.js";
8
- import { EMPTY_FILE_SNAPSHOT_V2, parseFileSnapshotV2, serializeFileSnapshotV2 } from "./FileSnapshotV2.js";
9
- import { FileWriter, isFileNotFound } from "./FileWriter.js";
10
- import { compareCodePoint, parsePersistenceBranchId } from "./PersistenceScope.js";
11
- import * as __rspack_external_valibot from "valibot";
12
- const LEGACY_NAMESPACES = [
13
- 'branches',
14
- 'edges',
15
- 'summaries'
16
- ];
17
- async function destinationIsAbsent(path) {
18
- try {
19
- await lstat(path);
20
- return false;
21
- } catch (error) {
22
- if (isFileNotFound(error)) return true;
23
- throw error;
24
- }
25
- }
26
- async function parseJson(path) {
27
- try {
28
- return JSON.parse(await readFile(path, 'utf-8'));
29
- } catch (error) {
30
- if (error instanceof SyntaxError) throw new PersistenceCorruptionError(path, error);
31
- throw error;
32
- }
33
- }
34
- async function parseThoughtArray(path) {
35
- const raw = await parseJson(path);
36
- try {
37
- return __rspack_external_valibot.parse(__rspack_external_valibot.array(__rspack_external_valibot.unknown()), raw).map((thought)=>parseThoughtData(thought, path));
38
- } catch (error) {
39
- if (error instanceof PersistenceCompatibilityError) throw error;
40
- throw new PersistenceCorruptionError(path, error);
41
- }
42
- }
43
- async function namespaceFiles(sourceDataDir, namespace) {
44
- const directory = join(sourceDataDir, namespace);
45
- try {
46
- const entries = await readdir(directory, {
47
- withFileTypes: true
48
- });
49
- for (const entry of entries)if (!entry.isFile() || !entry.name.endsWith('.json')) throw new PersistenceCompatibilityError(directory, `unknown legacy artifact '${entry.name}'`);
50
- return entries.map((entry)=>join(directory, entry.name)).sort(compareCodePoint);
51
- } catch (error) {
52
- if (isFileNotFound(error)) return [];
53
- throw error;
54
- }
55
- }
56
- async function validateLegacyLayout(sourceDataDir) {
57
- const entries = await readdir(sourceDataDir, {
58
- withFileTypes: true
59
- });
60
- const allowed = new Set([
61
- 'history.json',
62
- ...LEGACY_NAMESPACES
63
- ]);
64
- for (const entry of entries){
65
- if (!allowed.has(entry.name)) throw new PersistenceCompatibilityError(sourceDataDir, `unknown legacy artifact '${entry.name}'`);
66
- if ('history.json' === entry.name ? !entry.isFile() : !entry.isDirectory()) throw new PersistenceCompatibilityError(sourceDataDir, `invalid legacy artifact '${entry.name}'`);
67
- }
68
- }
69
- function groupHistory(thoughts) {
70
- const grouped = new Map();
71
- for (const thought of thoughts){
72
- const sessionId = thought.session_id ?? GLOBAL_SESSION_ID;
73
- const history = grouped.get(sessionId) ?? [];
74
- history.push(thought);
75
- grouped.set(sessionId, history);
76
- }
77
- return [
78
- ...grouped
79
- ].map(([sessionId, sessionThoughts])=>({
80
- sessionId,
81
- thoughts: sessionThoughts
82
- }));
83
- }
84
- async function loadLegacyHistory(sourceDataDir) {
85
- const historyPath = join(sourceDataDir, 'history.json');
86
- try {
87
- return groupHistory(await parseThoughtArray(historyPath));
88
- } catch (error) {
89
- if (isFileNotFound(error)) return [];
90
- throw error;
91
- }
92
- }
93
- async function loadLegacyBranches(sourceDataDir) {
94
- const records = [];
95
- for (const path of (await namespaceFiles(sourceDataDir, 'branches'))){
96
- const branchId = parsePersistenceBranchId(basename(path, '.json'), path);
97
- const thoughts = await parseThoughtArray(path);
98
- if (0 === thoughts.length) throw new PersistenceLegacyAmbiguityError(path, 'empty branch has no inferable session');
99
- const sessions = new Set(thoughts.map((thought)=>thought.session_id ?? GLOBAL_SESSION_ID));
100
- if (1 !== sessions.size) throw new PersistenceLegacyAmbiguityError(path, 'branch thoughts resolve to multiple sessions');
101
- const [sessionId] = sessions;
102
- if (void 0 === sessionId) throw new PersistenceLegacyAmbiguityError(path, 'branch session is absent');
103
- records.push({
104
- sessionId,
105
- branchId,
106
- thoughts
107
- });
108
- }
109
- return records;
110
- }
111
- async function loadLegacyEdges(sourceDataDir) {
112
- const records = [];
113
- for (const path of (await namespaceFiles(sourceDataDir, 'edges'))){
114
- const sessionId = asSessionId(basename(path, '.json'));
115
- try {
116
- const edges = __rspack_external_valibot.parse(__rspack_external_valibot.array(EdgeSchema), await parseJson(path)).map(parseEdge);
117
- if (edges.length > 0) records.push({
118
- sessionId,
119
- edges
120
- });
121
- } catch (error) {
122
- if (error instanceof PersistenceCorruptionError) throw error;
123
- throw new PersistenceCorruptionError(path, error);
124
- }
125
- }
126
- return records;
127
- }
128
- async function loadLegacySummaries(sourceDataDir) {
129
- const records = [];
130
- for (const path of (await namespaceFiles(sourceDataDir, 'summaries'))){
131
- const sessionId = asSessionId(basename(path, '.json'));
132
- try {
133
- const summaries = __rspack_external_valibot.parse(__rspack_external_valibot.array(SummarySchema), await parseJson(path)).map((summary)=>parseSummary(summary, path));
134
- if (summaries.length > 0) records.push({
135
- sessionId,
136
- summaries
137
- });
138
- } catch (error) {
139
- if (error instanceof PersistenceCorruptionError) throw error;
140
- throw new PersistenceCorruptionError(path, error);
141
- }
142
- }
143
- return records;
144
- }
145
- async function loadLegacySnapshot(sourceDataDir) {
146
- await validateLegacyLayout(sourceDataDir);
147
- return {
148
- ...EMPTY_FILE_SNAPSHOT_V2,
149
- thoughts: await loadLegacyHistory(sourceDataDir),
150
- branches: await loadLegacyBranches(sourceDataDir),
151
- edges: await loadLegacyEdges(sourceDataDir),
152
- summaries: await loadLegacySummaries(sourceDataDir)
153
- };
154
- }
155
- async function importLegacyFileV1(sourceDataDir, destinationDataDir) {
156
- if (!await destinationIsAbsent(destinationDataDir)) throw new PersistenceCompatibilityError(destinationDataDir, 'destination must be absent');
157
- const snapshot = await loadLegacySnapshot(sourceDataDir);
158
- await mkdir(dirname(destinationDataDir), {
159
- recursive: true
160
- });
161
- const stagingDir = await mkdtemp(join(dirname(destinationDataDir), `.${basename(destinationDataDir)}.import-`));
162
- const writer = new FileWriter(stagingDir);
163
- try {
164
- await writer.ready();
165
- await writer.run(async (dataDir)=>{
166
- const snapshotPath = join(dataDir, 'snapshot.json');
167
- await writer.publish(snapshotPath, serializeFileSnapshotV2(snapshot, snapshotPath));
168
- });
169
- await writer.close();
170
- parseFileSnapshotV2(await readFile(join(stagingDir, 'snapshot.json'), 'utf-8'), join(stagingDir, 'snapshot.json'));
171
- await rename(stagingDir, destinationDataDir);
172
- } catch (error) {
173
- await writer.close();
174
- await rm(stagingDir, {
175
- recursive: true,
176
- force: true
177
- });
178
- throw error;
179
- }
180
- }
181
- export { importLegacyFileV1 };
182
-
183
- //# sourceMappingURL=FileLegacyImport.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"persistence/FileLegacyImport.js","sources":["../../src/persistence/FileLegacyImport.ts"],"sourcesContent":["import { lstat, mkdtemp, mkdir, readFile, readdir, rename, rm } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport * as v from 'valibot';\nimport { asSessionId, GLOBAL_SESSION_ID, type SessionId } from '../contracts/ids.js';\nimport {\n\tPersistenceCompatibilityError,\n\tPersistenceCorruptionError,\n\tPersistenceLegacyAmbiguityError,\n} from '../errors.js';\nimport { EdgeSchema } from '../schema.js';\nimport { SummarySchema } from '../core/compression/Summary.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { parseEdge, parseSummary, parseThoughtData } from './PersistenceCodec.js';\nimport {\n\tEMPTY_FILE_SNAPSHOT_V2,\n\tparseFileSnapshotV2,\n\tserializeFileSnapshotV2,\n} from './FileSnapshotV2.js';\nimport type {\n\tBranchRecordV2,\n\tEdgeSessionV2,\n\tFileSnapshotV2,\n\tSummarySessionV2,\n\tThoughtSessionV2,\n} from './FileSnapshotTypes.js';\nimport { FileWriter, isFileNotFound } from './FileWriter.js';\nimport { compareCodePoint, parsePersistenceBranchId } from './PersistenceScope.js';\n\nconst LEGACY_NAMESPACES = ['branches', 'edges', 'summaries'] as const;\n\nasync function destinationIsAbsent(path: string): Promise<boolean> {\n\ttry {\n\t\tawait lstat(path);\n\t\treturn false;\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return true;\n\t\tthrow error;\n\t}\n}\n\nasync function parseJson(path: string): Promise<unknown> {\n\ttry {\n\t\treturn JSON.parse(await readFile(path, 'utf-8'));\n\t} catch (error) {\n\t\tif (error instanceof SyntaxError) throw new PersistenceCorruptionError(path, error);\n\t\tthrow error;\n\t}\n}\n\nasync function parseThoughtArray(path: string): Promise<ThoughtData[]> {\n\tconst raw = await parseJson(path);\n\ttry {\n\t\treturn v.parse(v.array(v.unknown()), raw).map((thought) => parseThoughtData(thought, path));\n\t} catch (error) {\n\t\tif (error instanceof PersistenceCompatibilityError) throw error;\n\t\tthrow new PersistenceCorruptionError(path, error);\n\t}\n}\n\nasync function namespaceFiles(sourceDataDir: string, namespace: string): Promise<string[]> {\n\tconst directory = join(sourceDataDir, namespace);\n\ttry {\n\t\tconst entries = await readdir(directory, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isFile() || !entry.name.endsWith('.json')) {\n\t\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t\tdirectory,\n\t\t\t\t\t`unknown legacy artifact '${entry.name}'`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn entries.map((entry) => join(directory, entry.name)).sort(compareCodePoint);\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return [];\n\t\tthrow error;\n\t}\n}\n\nasync function validateLegacyLayout(sourceDataDir: string): Promise<void> {\n\tconst entries = await readdir(sourceDataDir, { withFileTypes: true });\n\tconst allowed = new Set<string>(['history.json', ...LEGACY_NAMESPACES]);\n\tfor (const entry of entries) {\n\t\tif (!allowed.has(entry.name)) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tsourceDataDir,\n\t\t\t\t`unknown legacy artifact '${entry.name}'`\n\t\t\t);\n\t\t}\n\t\tif (entry.name === 'history.json' ? !entry.isFile() : !entry.isDirectory()) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tsourceDataDir,\n\t\t\t\t`invalid legacy artifact '${entry.name}'`\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction groupHistory(thoughts: readonly ThoughtData[]): ThoughtSessionV2[] {\n\tconst grouped = new Map<SessionId, ThoughtData[]>();\n\tfor (const thought of thoughts) {\n\t\tconst sessionId = thought.session_id ?? GLOBAL_SESSION_ID;\n\t\tconst history = grouped.get(sessionId) ?? [];\n\t\thistory.push(thought);\n\t\tgrouped.set(sessionId, history);\n\t}\n\treturn [...grouped].map(([sessionId, sessionThoughts]) => ({\n\t\tsessionId,\n\t\tthoughts: sessionThoughts,\n\t}));\n}\n\nasync function loadLegacyHistory(sourceDataDir: string): Promise<ThoughtSessionV2[]> {\n\tconst historyPath = join(sourceDataDir, 'history.json');\n\ttry {\n\t\treturn groupHistory(await parseThoughtArray(historyPath));\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return [];\n\t\tthrow error;\n\t}\n}\n\nasync function loadLegacyBranches(sourceDataDir: string): Promise<BranchRecordV2[]> {\n\tconst records: BranchRecordV2[] = [];\n\tfor (const path of await namespaceFiles(sourceDataDir, 'branches')) {\n\t\tconst branchId = parsePersistenceBranchId(basename(path, '.json'), path);\n\t\tconst thoughts = await parseThoughtArray(path);\n\t\tif (thoughts.length === 0) {\n\t\t\tthrow new PersistenceLegacyAmbiguityError(path, 'empty branch has no inferable session');\n\t\t}\n\t\tconst sessions = new Set(thoughts.map((thought) => thought.session_id ?? GLOBAL_SESSION_ID));\n\t\tif (sessions.size !== 1) {\n\t\t\tthrow new PersistenceLegacyAmbiguityError(\n\t\t\t\tpath,\n\t\t\t\t'branch thoughts resolve to multiple sessions'\n\t\t\t);\n\t\t}\n\t\tconst [sessionId] = sessions;\n\t\tif (sessionId === undefined) {\n\t\t\tthrow new PersistenceLegacyAmbiguityError(path, 'branch session is absent');\n\t\t}\n\t\trecords.push({ sessionId, branchId, thoughts });\n\t}\n\treturn records;\n}\n\nasync function loadLegacyEdges(sourceDataDir: string): Promise<EdgeSessionV2[]> {\n\tconst records: EdgeSessionV2[] = [];\n\tfor (const path of await namespaceFiles(sourceDataDir, 'edges')) {\n\t\tconst sessionId = asSessionId(basename(path, '.json'));\n\t\ttry {\n\t\t\tconst edges = v.parse(v.array(EdgeSchema), await parseJson(path)).map(parseEdge);\n\t\t\tif (edges.length > 0) records.push({ sessionId, edges });\n\t\t} catch (error) {\n\t\t\tif (error instanceof PersistenceCorruptionError) throw error;\n\t\t\tthrow new PersistenceCorruptionError(path, error);\n\t\t}\n\t}\n\treturn records;\n}\n\nasync function loadLegacySummaries(sourceDataDir: string): Promise<SummarySessionV2[]> {\n\tconst records: SummarySessionV2[] = [];\n\tfor (const path of await namespaceFiles(sourceDataDir, 'summaries')) {\n\t\tconst sessionId = asSessionId(basename(path, '.json'));\n\t\ttry {\n\t\t\tconst summaries = v\n\t\t\t\t.parse(v.array(SummarySchema), await parseJson(path))\n\t\t\t\t.map((summary) => parseSummary(summary, path));\n\t\t\tif (summaries.length > 0) records.push({ sessionId, summaries });\n\t\t} catch (error) {\n\t\t\tif (error instanceof PersistenceCorruptionError) throw error;\n\t\t\tthrow new PersistenceCorruptionError(path, error);\n\t\t}\n\t}\n\treturn records;\n}\n\nasync function loadLegacySnapshot(sourceDataDir: string): Promise<FileSnapshotV2> {\n\tawait validateLegacyLayout(sourceDataDir);\n\treturn {\n\t\t...EMPTY_FILE_SNAPSHOT_V2,\n\t\tthoughts: await loadLegacyHistory(sourceDataDir),\n\t\tbranches: await loadLegacyBranches(sourceDataDir),\n\t\tedges: await loadLegacyEdges(sourceDataDir),\n\t\tsummaries: await loadLegacySummaries(sourceDataDir),\n\t};\n}\n\nexport async function importLegacyFileV1(\n\tsourceDataDir: string,\n\tdestinationDataDir: string\n): Promise<void> {\n\tif (!(await destinationIsAbsent(destinationDataDir))) {\n\t\tthrow new PersistenceCompatibilityError(destinationDataDir, 'destination must be absent');\n\t}\n\tconst snapshot = await loadLegacySnapshot(sourceDataDir);\n\tawait mkdir(dirname(destinationDataDir), { recursive: true });\n\tconst stagingDir = await mkdtemp(\n\t\tjoin(dirname(destinationDataDir), `.${basename(destinationDataDir)}.import-`)\n\t);\n\tconst writer = new FileWriter(stagingDir);\n\ttry {\n\t\tawait writer.ready();\n\t\tawait writer.run(async (dataDir) => {\n\t\t\tconst snapshotPath = join(dataDir, 'snapshot.json');\n\t\t\tawait writer.publish(snapshotPath, serializeFileSnapshotV2(snapshot, snapshotPath));\n\t\t});\n\t\tawait writer.close();\n\t\tparseFileSnapshotV2(\n\t\t\tawait readFile(join(stagingDir, 'snapshot.json'), 'utf-8'),\n\t\t\tjoin(stagingDir, 'snapshot.json')\n\t\t);\n\t\tawait rename(stagingDir, destinationDataDir);\n\t} catch (error) {\n\t\tawait writer.close();\n\t\tawait rm(stagingDir, { recursive: true, force: true });\n\t\tthrow error;\n\t}\n}\n"],"names":["LEGACY_NAMESPACES","destinationIsAbsent","path","lstat","error","isFileNotFound","parseJson","JSON","readFile","SyntaxError","PersistenceCorruptionError","parseThoughtArray","raw","v","thought","parseThoughtData","PersistenceCompatibilityError","namespaceFiles","sourceDataDir","namespace","directory","join","entries","readdir","entry","compareCodePoint","validateLegacyLayout","allowed","Set","groupHistory","thoughts","grouped","Map","sessionId","GLOBAL_SESSION_ID","history","sessionThoughts","loadLegacyHistory","historyPath","loadLegacyBranches","records","branchId","parsePersistenceBranchId","basename","PersistenceLegacyAmbiguityError","sessions","undefined","loadLegacyEdges","asSessionId","edges","EdgeSchema","parseEdge","loadLegacySummaries","summaries","SummarySchema","summary","parseSummary","loadLegacySnapshot","EMPTY_FILE_SNAPSHOT_V2","importLegacyFileV1","destinationDataDir","snapshot","mkdir","dirname","stagingDir","mkdtemp","writer","FileWriter","dataDir","snapshotPath","serializeFileSnapshotV2","parseFileSnapshotV2","rename","rm"],"mappings":"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"}
@@ -1,4 +0,0 @@
1
- import type { PersistenceBackend, SessionScopedPersistenceBackend, SessionScopedPersistenceOperation } from '../contracts/PersistenceBackend.js';
2
- /** Require the complete scoped capability without falling back to legacy global operations. */
3
- export declare function requireSessionScopedPersistence(backend: PersistenceBackend, operation: SessionScopedPersistenceOperation): SessionScopedPersistenceBackend;
4
- //# sourceMappingURL=SessionScopedPersistence.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SessionScopedPersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SessionScopedPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAClB,+BAA+B,EAC/B,iCAAiC,EACjC,MAAM,oCAAoC,CAAC;AAI5C,+FAA+F;AAC/F,wBAAgB,+BAA+B,CAC9C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,iCAAiC,GAC1C,+BAA+B,CAKjC"}
@@ -1,9 +0,0 @@
1
- import { supportsSessionScopedPersistence } from "../contracts/PersistenceBackend.js";
2
- import { PersistenceCapabilityError } from "./PersistenceErrors.js";
3
- function requireSessionScopedPersistence(backend, operation) {
4
- if (!supportsSessionScopedPersistence(backend)) throw new PersistenceCapabilityError(operation);
5
- return backend;
6
- }
7
- export { requireSessionScopedPersistence };
8
-
9
- //# sourceMappingURL=SessionScopedPersistence.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"persistence/SessionScopedPersistence.js","sources":["../../src/persistence/SessionScopedPersistence.ts"],"sourcesContent":["import type {\n\tPersistenceBackend,\n\tSessionScopedPersistenceBackend,\n\tSessionScopedPersistenceOperation,\n} from '../contracts/PersistenceBackend.js';\nimport { supportsSessionScopedPersistence } from '../contracts/PersistenceBackend.js';\nimport { PersistenceCapabilityError } from './PersistenceErrors.js';\n\n/** Require the complete scoped capability without falling back to legacy global operations. */\nexport function requireSessionScopedPersistence(\n\tbackend: PersistenceBackend,\n\toperation: SessionScopedPersistenceOperation\n): SessionScopedPersistenceBackend {\n\tif (!supportsSessionScopedPersistence(backend)) {\n\t\tthrow new PersistenceCapabilityError(operation);\n\t}\n\treturn backend;\n}\n"],"names":["requireSessionScopedPersistence","backend","operation","supportsSessionScopedPersistence","PersistenceCapabilityError"],"mappings":";;AASO,SAASA,gCACfC,OAA2B,EAC3BC,SAA4C;IAE5C,IAAI,CAACC,iCAAiCF,UACrC,MAAM,IAAIG,2BAA2BF;IAEtC,OAAOD;AACR"}
@@ -1,14 +0,0 @@
1
- /**
2
- * Imports an immutable SQLite v1 database into a separately published SQLite v2 destination.
3
- *
4
- * @param sourceDbPath - Existing frozen v1 source database opened read-only.
5
- * @param destinationDbPath - Absent destination path atomically published after validation.
6
- * @returns A promise that resolves after the validated v2 database is published.
7
- *
8
- * @example
9
- * ```ts
10
- * await importLegacySqliteV1('fixtures/legacy.db', 'output/history.db');
11
- * ```
12
- */
13
- export declare function importLegacySqliteV1(sourceDbPath: string, destinationDbPath: string): Promise<void>;
14
- //# sourceMappingURL=SqliteLegacyImport.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SqliteLegacyImport.d.ts","sourceRoot":"","sources":["../../src/persistence/SqliteLegacyImport.ts"],"names":[],"mappings":"AA6KA;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACzC,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAaf"}
@@ -1,136 +0,0 @@
1
- import { link as promises_link, lstat, mkdir, mkdtemp, rm } from "node:fs/promises";
2
- import { basename, dirname, join } from "node:path";
3
- import { GLOBAL_SESSION_ID } from "../contracts/ids.js";
4
- import { PersistenceCompatibilityError, PersistenceCorruptionError, PersistenceLegacyAmbiguityError } from "../errors.js";
5
- import { parseFileSnapshotV2, serializeFileSnapshotV2 } from "./FileSnapshotV2.js";
6
- import { isFileNotFound } from "./FileWriter.js";
7
- import { validateSqliteV1Schema } from "./SqliteLegacySchema.js";
8
- import { decodeEdgeRow, decodeSummaryRow, decodeThoughtRow, parseSqliteJson, stringField } from "./SqlitePayload.js";
9
- import { parsePersistenceBranchId } from "./PersistenceScope.js";
10
- import { writeSqliteSnapshot } from "./SqliteSnapshotWriter.js";
11
- async function pathIsAbsent(path) {
12
- try {
13
- await lstat(path);
14
- return false;
15
- } catch (error) {
16
- if (isFileNotFound(error)) return true;
17
- throw error;
18
- }
19
- }
20
- function groupBySession(values, sessionOf) {
21
- const grouped = new Map();
22
- for (const value of values){
23
- const sessionId = sessionOf(value);
24
- const sessionValues = grouped.get(sessionId) ?? [];
25
- sessionValues.push(value);
26
- grouped.set(sessionId, sessionValues);
27
- }
28
- return grouped;
29
- }
30
- function loadLegacyThoughts(database, sourcePath) {
31
- const thoughts = database.prepare('SELECT data FROM thoughts ORDER BY id ASC').all().map((row, index)=>decodeThoughtRow(row, `${sourcePath}:thoughts:${index}`));
32
- return [
33
- ...groupBySession(thoughts, (thought)=>thought.session_id ?? GLOBAL_SESSION_ID)
34
- ].map(([sessionId, sessionThoughts])=>({
35
- sessionId,
36
- thoughts: sessionThoughts
37
- }));
38
- }
39
- function decodeLegacyBranch(row, sourcePath) {
40
- const branchId = parsePersistenceBranchId(stringField(row, 'branch_id', sourcePath), sourcePath);
41
- const data = parseSqliteJson(stringField(row, 'data', sourcePath), sourcePath);
42
- if (!Array.isArray(data)) throw new PersistenceCorruptionError(sourcePath, new TypeError('branch data is not an array'));
43
- const thoughts = data.map((value, index)=>decodeThoughtRow({
44
- data: JSON.stringify(value)
45
- }, `${sourcePath}:thought:${index}`));
46
- if (0 === thoughts.length) throw new PersistenceLegacyAmbiguityError(sourcePath, 'empty branch has no inferable session');
47
- const sessions = new Set(thoughts.map((thought)=>thought.session_id ?? GLOBAL_SESSION_ID));
48
- if (1 !== sessions.size) throw new PersistenceLegacyAmbiguityError(sourcePath, 'branch thoughts resolve to multiple sessions');
49
- const sessionId = sessions.values().next().value;
50
- if (void 0 === sessionId) throw new PersistenceLegacyAmbiguityError(sourcePath, 'branch session is absent');
51
- return {
52
- sessionId,
53
- branchId,
54
- thoughts
55
- };
56
- }
57
- function loadLegacyBranches(database, sourcePath, hasBranches) {
58
- if (!hasBranches) return [];
59
- return database.prepare('SELECT branch_id, data FROM branches ORDER BY branch_id ASC').all().map((row, index)=>decodeLegacyBranch(row, `${sourcePath}:branches:${index}`));
60
- }
61
- function loadLegacyEdges(database, sourcePath) {
62
- const edges = database.prepare('SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges ORDER BY created_at ASC, id ASC').all().map((row, index)=>decodeEdgeRow(row, `${sourcePath}:edges:${index}`));
63
- return [
64
- ...groupBySession(edges, (edge)=>edge.sessionId)
65
- ].map(([sessionId, sessionEdges])=>({
66
- sessionId,
67
- edges: sessionEdges
68
- }));
69
- }
70
- function loadLegacySummaries(database, sourcePath) {
71
- const summaries = database.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 ORDER BY created_at ASC, id ASC').all().map((row, index)=>decodeSummaryRow(row, `${sourcePath}:summaries:${index}`));
72
- return [
73
- ...groupBySession(summaries, (summary)=>summary.sessionId)
74
- ].map(([sessionId, sessionSummaries])=>({
75
- sessionId,
76
- summaries: sessionSummaries
77
- }));
78
- }
79
- function loadLegacySnapshot(database, sourcePath) {
80
- const hasBranches = validateSqliteV1Schema(database, sourcePath);
81
- const snapshot = {
82
- version: 2,
83
- thoughts: loadLegacyThoughts(database, sourcePath),
84
- branches: loadLegacyBranches(database, sourcePath, hasBranches),
85
- edges: loadLegacyEdges(database, sourcePath),
86
- summaries: loadLegacySummaries(database, sourcePath)
87
- };
88
- return parseFileSnapshotV2(serializeFileSnapshotV2(snapshot, sourcePath), sourcePath);
89
- }
90
- async function importWithDriver(sourceDbPath, destinationDbPath, Database) {
91
- if (!await pathIsAbsent(destinationDbPath)) throw new PersistenceCompatibilityError(destinationDbPath, 'destination must be absent');
92
- const source = new Database(sourceDbPath, {
93
- readonly: true,
94
- fileMustExist: true
95
- });
96
- let snapshot;
97
- try {
98
- snapshot = loadLegacySnapshot(source, sourceDbPath);
99
- } finally{
100
- source.close();
101
- }
102
- await mkdir(dirname(destinationDbPath), {
103
- recursive: true
104
- });
105
- const stagingDir = await mkdtemp(join(dirname(destinationDbPath), `.${basename(destinationDbPath)}.import-`));
106
- const stagedDbPath = join(stagingDir, basename(destinationDbPath));
107
- let destination;
108
- try {
109
- destination = new Database(stagedDbPath);
110
- writeSqliteSnapshot(destination, snapshot, stagedDbPath);
111
- destination.close();
112
- destination = void 0;
113
- await promises_link(stagedDbPath, destinationDbPath);
114
- } catch (error) {
115
- destination?.close();
116
- throw error;
117
- } finally{
118
- await rm(stagingDir, {
119
- recursive: true,
120
- force: true
121
- });
122
- }
123
- }
124
- async function importLegacySqliteV1(sourceDbPath, destinationDbPath) {
125
- let Database;
126
- try {
127
- const module = await import("better-sqlite3");
128
- Database = module.default;
129
- } catch (error) {
130
- throw new PersistenceCompatibilityError(sourceDbPath, "SQLite import requires the optional 'better-sqlite3' package", error);
131
- }
132
- await importWithDriver(sourceDbPath, destinationDbPath, Database);
133
- }
134
- export { importLegacySqliteV1 };
135
-
136
- //# sourceMappingURL=SqliteLegacyImport.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"persistence/SqliteLegacyImport.js","sources":["../../src/persistence/SqliteLegacyImport.ts"],"sourcesContent":["import { lstat, link, mkdir, mkdtemp, rm } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { GLOBAL_SESSION_ID, type SessionId } from '../contracts/ids.js';\nimport {\n\tPersistenceCompatibilityError,\n\tPersistenceCorruptionError,\n\tPersistenceLegacyAmbiguityError,\n} from '../errors.js';\nimport { parseFileSnapshotV2, serializeFileSnapshotV2 } from './FileSnapshotV2.js';\nimport type {\n\tBranchRecordV2,\n\tEdgeSessionV2,\n\tFileSnapshotV2,\n\tSummarySessionV2,\n\tThoughtSessionV2,\n} from './FileSnapshotTypes.js';\nimport { isFileNotFound } from './FileWriter.js';\nimport type { SqliteDatabase, SqliteDatabaseConstructor } from './SqliteDriver.js';\nimport { validateSqliteV1Schema } from './SqliteLegacySchema.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tparseSqliteJson,\n\tstringField,\n} from './SqlitePayload.js';\nimport { parsePersistenceBranchId } from './PersistenceScope.js';\nimport { writeSqliteSnapshot } from './SqliteSnapshotWriter.js';\n\nasync function pathIsAbsent(path: string): Promise<boolean> {\n\ttry {\n\t\tawait lstat(path);\n\t\treturn false;\n\t} catch (error) {\n\t\tif (isFileNotFound(error)) return true;\n\t\tthrow error;\n\t}\n}\n\nfunction groupBySession<T>(\n\tvalues: readonly T[],\n\tsessionOf: (value: T) => SessionId\n): Map<SessionId, T[]> {\n\tconst grouped = new Map<SessionId, T[]>();\n\tfor (const value of values) {\n\t\tconst sessionId = sessionOf(value);\n\t\tconst sessionValues = grouped.get(sessionId) ?? [];\n\t\tsessionValues.push(value);\n\t\tgrouped.set(sessionId, sessionValues);\n\t}\n\treturn grouped;\n}\n\nfunction loadLegacyThoughts(database: SqliteDatabase, sourcePath: string): ThoughtSessionV2[] {\n\tconst thoughts = database\n\t\t.prepare('SELECT data FROM thoughts ORDER BY id ASC')\n\t\t.all()\n\t\t.map((row, index) => decodeThoughtRow(row, `${sourcePath}:thoughts:${index}`));\n\treturn [...groupBySession(thoughts, (thought) => thought.session_id ?? GLOBAL_SESSION_ID)].map(\n\t\t([sessionId, sessionThoughts]) => ({ sessionId, thoughts: sessionThoughts })\n\t);\n}\n\nfunction decodeLegacyBranch(row: unknown, sourcePath: string): BranchRecordV2 {\n\tconst branchId = parsePersistenceBranchId(stringField(row, 'branch_id', sourcePath), sourcePath);\n\tconst data = parseSqliteJson(stringField(row, 'data', sourcePath), sourcePath);\n\tif (!Array.isArray(data)) {\n\t\tthrow new PersistenceCorruptionError(sourcePath, new TypeError('branch data is not an array'));\n\t}\n\tconst thoughts = data.map((value, index) =>\n\t\tdecodeThoughtRow({ data: JSON.stringify(value) }, `${sourcePath}:thought:${index}`)\n\t);\n\tif (thoughts.length === 0) {\n\t\tthrow new PersistenceLegacyAmbiguityError(sourcePath, 'empty branch has no inferable session');\n\t}\n\tconst sessions = new Set(thoughts.map((thought) => thought.session_id ?? GLOBAL_SESSION_ID));\n\tif (sessions.size !== 1) {\n\t\tthrow new PersistenceLegacyAmbiguityError(\n\t\t\tsourcePath,\n\t\t\t'branch thoughts resolve to multiple sessions'\n\t\t);\n\t}\n\tconst sessionId = sessions.values().next().value;\n\tif (sessionId === undefined) {\n\t\tthrow new PersistenceLegacyAmbiguityError(sourcePath, 'branch session is absent');\n\t}\n\treturn { sessionId, branchId, thoughts };\n}\n\nfunction loadLegacyBranches(\n\tdatabase: SqliteDatabase,\n\tsourcePath: string,\n\thasBranches: boolean\n): BranchRecordV2[] {\n\tif (!hasBranches) return [];\n\treturn database\n\t\t.prepare('SELECT branch_id, data FROM branches ORDER BY branch_id ASC')\n\t\t.all()\n\t\t.map((row, index) => decodeLegacyBranch(row, `${sourcePath}:branches:${index}`));\n}\n\nfunction loadLegacyEdges(database: SqliteDatabase, sourcePath: string): EdgeSessionV2[] {\n\tconst edges = database\n\t\t.prepare(\n\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges ORDER BY created_at ASC, id ASC'\n\t\t)\n\t\t.all()\n\t\t.map((row, index) => decodeEdgeRow(row, `${sourcePath}:edges:${index}`));\n\treturn [...groupBySession(edges, (edge) => edge.sessionId)].map(([sessionId, sessionEdges]) => ({\n\t\tsessionId,\n\t\tedges: sessionEdges,\n\t}));\n}\n\nfunction loadLegacySummaries(database: SqliteDatabase, sourcePath: string): SummarySessionV2[] {\n\tconst summaries = database\n\t\t.prepare(\n\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 ORDER BY created_at ASC, id ASC'\n\t\t)\n\t\t.all()\n\t\t.map((row, index) => decodeSummaryRow(row, `${sourcePath}:summaries:${index}`));\n\treturn [...groupBySession(summaries, (summary) => summary.sessionId)].map(\n\t\t([sessionId, sessionSummaries]) => ({ sessionId, summaries: sessionSummaries })\n\t);\n}\n\nfunction loadLegacySnapshot(database: SqliteDatabase, sourcePath: string): FileSnapshotV2 {\n\tconst hasBranches = validateSqliteV1Schema(database, sourcePath);\n\tconst snapshot: FileSnapshotV2 = {\n\t\tversion: 2,\n\t\tthoughts: loadLegacyThoughts(database, sourcePath),\n\t\tbranches: loadLegacyBranches(database, sourcePath, hasBranches),\n\t\tedges: loadLegacyEdges(database, sourcePath),\n\t\tsummaries: loadLegacySummaries(database, sourcePath),\n\t};\n\treturn parseFileSnapshotV2(serializeFileSnapshotV2(snapshot, sourcePath), sourcePath);\n}\n\nasync function importWithDriver(\n\tsourceDbPath: string,\n\tdestinationDbPath: string,\n\tDatabase: SqliteDatabaseConstructor\n): Promise<void> {\n\tif (!(await pathIsAbsent(destinationDbPath))) {\n\t\tthrow new PersistenceCompatibilityError(destinationDbPath, 'destination must be absent');\n\t}\n\tconst source = new Database(sourceDbPath, { readonly: true, fileMustExist: true });\n\tlet snapshot: FileSnapshotV2;\n\ttry {\n\t\tsnapshot = loadLegacySnapshot(source, sourceDbPath);\n\t} finally {\n\t\tsource.close();\n\t}\n\tawait mkdir(dirname(destinationDbPath), { recursive: true });\n\tconst stagingDir = await mkdtemp(\n\t\tjoin(dirname(destinationDbPath), `.${basename(destinationDbPath)}.import-`)\n\t);\n\tconst stagedDbPath = join(stagingDir, basename(destinationDbPath));\n\tlet destination: SqliteDatabase | undefined;\n\ttry {\n\t\tdestination = new Database(stagedDbPath);\n\t\twriteSqliteSnapshot(destination, snapshot, stagedDbPath);\n\t\tdestination.close();\n\t\tdestination = undefined;\n\t\tawait link(stagedDbPath, destinationDbPath);\n\t} catch (error) {\n\t\tdestination?.close();\n\t\tthrow error;\n\t} finally {\n\t\tawait rm(stagingDir, { recursive: true, force: true });\n\t}\n}\n\n/**\n * Imports an immutable SQLite v1 database into a separately published SQLite v2 destination.\n *\n * @param sourceDbPath - Existing frozen v1 source database opened read-only.\n * @param destinationDbPath - Absent destination path atomically published after validation.\n * @returns A promise that resolves after the validated v2 database is published.\n *\n * @example\n * ```ts\n * await importLegacySqliteV1('fixtures/legacy.db', 'output/history.db');\n * ```\n */\nexport async function importLegacySqliteV1(\n\tsourceDbPath: string,\n\tdestinationDbPath: string\n): Promise<void> {\n\tlet Database: SqliteDatabaseConstructor;\n\ttry {\n\t\tconst module = await import('better-sqlite3');\n\t\tDatabase = module.default;\n\t} catch (error) {\n\t\tthrow new PersistenceCompatibilityError(\n\t\t\tsourceDbPath,\n\t\t\t\"SQLite import requires the optional 'better-sqlite3' package\",\n\t\t\terror\n\t\t);\n\t}\n\tawait importWithDriver(sourceDbPath, destinationDbPath, Database);\n}\n"],"names":["pathIsAbsent","path","lstat","error","isFileNotFound","groupBySession","values","sessionOf","grouped","Map","value","sessionId","sessionValues","loadLegacyThoughts","database","sourcePath","thoughts","row","index","decodeThoughtRow","thought","GLOBAL_SESSION_ID","sessionThoughts","decodeLegacyBranch","branchId","parsePersistenceBranchId","stringField","data","parseSqliteJson","Array","PersistenceCorruptionError","TypeError","JSON","PersistenceLegacyAmbiguityError","sessions","Set","undefined","loadLegacyBranches","hasBranches","loadLegacyEdges","edges","decodeEdgeRow","edge","sessionEdges","loadLegacySummaries","summaries","decodeSummaryRow","summary","sessionSummaries","loadLegacySnapshot","validateSqliteV1Schema","snapshot","parseFileSnapshotV2","serializeFileSnapshotV2","importWithDriver","sourceDbPath","destinationDbPath","Database","PersistenceCompatibilityError","source","mkdir","dirname","stagingDir","mkdtemp","join","basename","stagedDbPath","destination","writeSqliteSnapshot","link","rm","importLegacySqliteV1","module"],"mappings":"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"}
@@ -1,15 +0,0 @@
1
- import type { SqliteDatabase } from './SqliteDriver.js';
2
- /**
3
- * Validates the frozen, unversioned SQLite v1 schema without mutating it.
4
- *
5
- * @param database - Read-only source database.
6
- * @param sourcePath - Source name used by typed compatibility errors.
7
- * @returns Whether the optional legacy branches table is present.
8
- *
9
- * @example
10
- * ```ts
11
- * const hasBranches = validateSqliteV1Schema(database, 'legacy.db');
12
- * ```
13
- */
14
- export declare function validateSqliteV1Schema(database: SqliteDatabase, sourcePath: string): boolean;
15
- //# sourceMappingURL=SqliteLegacySchema.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SqliteLegacySchema.d.ts","sourceRoot":"","sources":["../../src/persistence/SqliteLegacySchema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAoDxD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAuB5F"}
@@ -1,72 +0,0 @@
1
- import { PersistenceCompatibilityError } from "../errors.js";
2
- const LEGACY_TABLES = new Map([
3
- [
4
- 'thoughts',
5
- "CREATE TABLE thoughts (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT NOT NULL, created_at INTEGER DEFAULT (strftime('%s', 'now')))"
6
- ],
7
- [
8
- 'branches',
9
- "CREATE TABLE branches (branch_id TEXT PRIMARY KEY, data TEXT NOT NULL, updated_at INTEGER DEFAULT (strftime('%s', 'now')))"
10
- ],
11
- [
12
- 'edges',
13
- 'CREATE TABLE edges (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, from_id TEXT NOT NULL, to_id TEXT NOT NULL, kind TEXT NOT NULL, created_at INTEGER NOT NULL, metadata TEXT)'
14
- ],
15
- [
16
- 'summaries',
17
- 'CREATE TABLE summaries (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, branch_id TEXT, root_thought_id TEXT NOT NULL, covered_ids TEXT NOT NULL, covered_range_start INTEGER NOT NULL, covered_range_end INTEGER NOT NULL, topics TEXT NOT NULL, aggregate_confidence REAL NOT NULL, created_at INTEGER NOT NULL, meta TEXT)'
18
- ]
19
- ]);
20
- const LEGACY_INDEXES = new Map([
21
- [
22
- 'idx_thoughts_created_at',
23
- 'CREATE INDEX idx_thoughts_created_at ON thoughts(created_at)'
24
- ],
25
- [
26
- 'idx_edges_session',
27
- 'CREATE INDEX idx_edges_session ON edges(session_id)'
28
- ],
29
- [
30
- 'idx_edges_from',
31
- 'CREATE INDEX idx_edges_from ON edges(session_id, from_id)'
32
- ],
33
- [
34
- 'idx_edges_to',
35
- 'CREATE INDEX idx_edges_to ON edges(session_id, to_id)'
36
- ],
37
- [
38
- 'idx_summaries_session',
39
- 'CREATE INDEX idx_summaries_session ON summaries(session_id)'
40
- ]
41
- ]);
42
- function normalizeSql(sql) {
43
- return sql.replace(/\s+/g, ' ').replace(/;$/, '').trim().toLowerCase();
44
- }
45
- function readObject(value, sourcePath) {
46
- if ('object' != typeof value || null === value) throw new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master row');
47
- const type = 'type' in value ? value.type : void 0;
48
- const name = 'name' in value ? value.name : void 0;
49
- const sql = 'sql' in value ? value.sql : void 0;
50
- if ('string' != typeof type || 'string' != typeof name || 'string' != typeof sql) throw new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master fields');
51
- return {
52
- type,
53
- name,
54
- sql
55
- };
56
- }
57
- function validateSqliteV1Schema(database, sourcePath) {
58
- const objects = database.prepare("SELECT type, name, sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY type, name").all().map((row)=>readObject(row, sourcePath));
59
- const hasBranches = objects.some(({ type, name })=>'table' === type && 'branches' === name);
60
- const expected = new Map();
61
- for (const [name, sql] of LEGACY_TABLES)if ('branches' !== name || hasBranches) expected.set(`table:${name}`, normalizeSql(sql));
62
- for (const [name, sql] of LEGACY_INDEXES)expected.set(`index:${name}`, normalizeSql(sql));
63
- if (objects.length !== expected.size) throw new PersistenceCompatibilityError(sourcePath, 'SQLite v1 object set does not match');
64
- for (const object of objects){
65
- const expectedSql = expected.get(`${object.type}:${object.name}`);
66
- if (void 0 === expectedSql || normalizeSql(object.sql) !== expectedSql) throw new PersistenceCompatibilityError(sourcePath, `SQLite v1 drift at '${object.name}'`);
67
- }
68
- return hasBranches;
69
- }
70
- export { validateSqliteV1Schema };
71
-
72
- //# sourceMappingURL=SqliteLegacySchema.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"persistence/SqliteLegacySchema.js","sources":["../../src/persistence/SqliteLegacySchema.ts"],"sourcesContent":["import { PersistenceCompatibilityError } from '../errors.js';\nimport type { SqliteDatabase } from './SqliteDriver.js';\n\ntype LegacySchemaObject = {\n\treadonly type: string;\n\treadonly name: string;\n\treadonly sql: string;\n};\n\nconst LEGACY_TABLES = new Map<string, string>([\n\t[\n\t\t'thoughts',\n\t\t\"CREATE TABLE thoughts (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT NOT NULL, created_at INTEGER DEFAULT (strftime('%s', 'now')))\",\n\t],\n\t[\n\t\t'branches',\n\t\t\"CREATE TABLE branches (branch_id TEXT PRIMARY KEY, data TEXT NOT NULL, updated_at INTEGER DEFAULT (strftime('%s', 'now')))\",\n\t],\n\t[\n\t\t'edges',\n\t\t'CREATE TABLE edges (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, from_id TEXT NOT NULL, to_id TEXT NOT NULL, kind TEXT NOT NULL, created_at INTEGER NOT NULL, metadata TEXT)',\n\t],\n\t[\n\t\t'summaries',\n\t\t'CREATE TABLE summaries (id TEXT PRIMARY KEY, session_id TEXT NOT NULL, branch_id TEXT, root_thought_id TEXT NOT NULL, covered_ids TEXT NOT NULL, covered_range_start INTEGER NOT NULL, covered_range_end INTEGER NOT NULL, topics TEXT NOT NULL, aggregate_confidence REAL NOT NULL, created_at INTEGER NOT NULL, meta TEXT)',\n\t],\n]);\n\nconst LEGACY_INDEXES = new Map<string, string>([\n\t['idx_thoughts_created_at', 'CREATE INDEX idx_thoughts_created_at ON thoughts(created_at)'],\n\t['idx_edges_session', 'CREATE INDEX idx_edges_session ON edges(session_id)'],\n\t['idx_edges_from', 'CREATE INDEX idx_edges_from ON edges(session_id, from_id)'],\n\t['idx_edges_to', 'CREATE INDEX idx_edges_to ON edges(session_id, to_id)'],\n\t['idx_summaries_session', 'CREATE INDEX idx_summaries_session ON summaries(session_id)'],\n]);\n\nfunction normalizeSql(sql: string): string {\n\treturn sql.replace(/\\s+/g, ' ').replace(/;$/, '').trim().toLowerCase();\n}\n\nfunction readObject(value: unknown, sourcePath: string): LegacySchemaObject {\n\tif (typeof value !== 'object' || value === null) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master row');\n\t}\n\tconst type = 'type' in value ? value.type : undefined;\n\tconst name = 'name' in value ? value.name : undefined;\n\tconst sql = 'sql' in value ? value.sql : undefined;\n\tif (typeof type !== 'string' || typeof name !== 'string' || typeof sql !== 'string') {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master fields');\n\t}\n\treturn { type, name, sql };\n}\n\n/**\n * Validates the frozen, unversioned SQLite v1 schema without mutating it.\n *\n * @param database - Read-only source database.\n * @param sourcePath - Source name used by typed compatibility errors.\n * @returns Whether the optional legacy branches table is present.\n *\n * @example\n * ```ts\n * const hasBranches = validateSqliteV1Schema(database, 'legacy.db');\n * ```\n */\nexport function validateSqliteV1Schema(database: SqliteDatabase, sourcePath: string): boolean {\n\tconst objects = database\n\t\t.prepare(\n\t\t\t\"SELECT type, name, sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY type, name\"\n\t\t)\n\t\t.all()\n\t\t.map((row) => readObject(row, sourcePath));\n\tconst hasBranches = objects.some(({ type, name }) => type === 'table' && name === 'branches');\n\tconst expected = new Map<string, string>();\n\tfor (const [name, sql] of LEGACY_TABLES) {\n\t\tif (name !== 'branches' || hasBranches) expected.set(`table:${name}`, normalizeSql(sql));\n\t}\n\tfor (const [name, sql] of LEGACY_INDEXES) expected.set(`index:${name}`, normalizeSql(sql));\n\tif (objects.length !== expected.size) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'SQLite v1 object set does not match');\n\t}\n\tfor (const object of objects) {\n\t\tconst expectedSql = expected.get(`${object.type}:${object.name}`);\n\t\tif (expectedSql === undefined || normalizeSql(object.sql) !== expectedSql) {\n\t\t\tthrow new PersistenceCompatibilityError(sourcePath, `SQLite v1 drift at '${object.name}'`);\n\t\t}\n\t}\n\treturn hasBranches;\n}\n"],"names":["LEGACY_TABLES","Map","LEGACY_INDEXES","normalizeSql","sql","readObject","value","sourcePath","PersistenceCompatibilityError","type","undefined","name","validateSqliteV1Schema","database","objects","row","hasBranches","expected","object","expectedSql"],"mappings":";AASA,MAAMA,gBAAgB,IAAIC,IAAoB;IAC7C;QACC;QACA;KACA;IACD;QACC;QACA;KACA;IACD;QACC;QACA;KACA;IACD;QACC;QACA;KACA;CACD;AAED,MAAMC,iBAAiB,IAAID,IAAoB;IAC9C;QAAC;QAA2B;KAA+D;IAC3F;QAAC;QAAqB;KAAsD;IAC5E;QAAC;QAAkB;KAA4D;IAC/E;QAAC;QAAgB;KAAwD;IACzE;QAAC;QAAyB;KAA8D;CACxF;AAED,SAASE,aAAaC,GAAW;IAChC,OAAOA,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,MAAM,IAAI,IAAI,GAAG,WAAW;AACrE;AAEA,SAASC,WAAWC,KAAc,EAAEC,UAAkB;IACrD,IAAI,AAAiB,YAAjB,OAAOD,SAAsBA,AAAU,SAAVA,OAChC,MAAM,IAAIE,8BAA8BD,YAAY;IAErD,MAAME,OAAO,UAAUH,QAAQA,MAAM,IAAI,GAAGI;IAC5C,MAAMC,OAAO,UAAUL,QAAQA,MAAM,IAAI,GAAGI;IAC5C,MAAMN,MAAM,SAASE,QAAQA,MAAM,GAAG,GAAGI;IACzC,IAAI,AAAgB,YAAhB,OAAOD,QAAqB,AAAgB,YAAhB,OAAOE,QAAqB,AAAe,YAAf,OAAOP,KAClE,MAAM,IAAII,8BAA8BD,YAAY;IAErD,OAAO;QAAEE;QAAME;QAAMP;IAAI;AAC1B;AAcO,SAASQ,uBAAuBC,QAAwB,EAAEN,UAAkB;IAClF,MAAMO,UAAUD,SACd,OAAO,CACP,gGAEA,GAAG,GACH,GAAG,CAAC,CAACE,MAAQV,WAAWU,KAAKR;IAC/B,MAAMS,cAAcF,QAAQ,IAAI,CAAC,CAAC,EAAEL,IAAI,EAAEE,IAAI,EAAE,GAAKF,AAAS,YAATA,QAAoBE,AAAS,eAATA;IACzE,MAAMM,WAAW,IAAIhB;IACrB,KAAK,MAAM,CAACU,MAAMP,IAAI,IAAIJ,cACzB,IAAIW,AAAS,eAATA,QAAuBK,aAAaC,SAAS,GAAG,CAAC,CAAC,MAAM,EAAEN,MAAM,EAAER,aAAaC;IAEpF,KAAK,MAAM,CAACO,MAAMP,IAAI,IAAIF,eAAgBe,SAAS,GAAG,CAAC,CAAC,MAAM,EAAEN,MAAM,EAAER,aAAaC;IACrF,IAAIU,QAAQ,MAAM,KAAKG,SAAS,IAAI,EACnC,MAAM,IAAIT,8BAA8BD,YAAY;IAErD,KAAK,MAAMW,UAAUJ,QAAS;QAC7B,MAAMK,cAAcF,SAAS,GAAG,CAAC,GAAGC,OAAO,IAAI,CAAC,CAAC,EAAEA,OAAO,IAAI,EAAE;QAChE,IAAIC,AAAgBT,WAAhBS,eAA6BhB,aAAae,OAAO,GAAG,MAAMC,aAC7D,MAAM,IAAIX,8BAA8BD,YAAY,CAAC,oBAAoB,EAAEW,OAAO,IAAI,CAAC,CAAC,CAAC;IAE3F;IACA,OAAOF;AACR"}