tracelattice 1.3.2 → 1.3.3
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 +25 -25
- package/dist/ServerConfig.d.ts +2 -23
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/__tests__/eval/fixtures/scenarios.d.ts.map +1 -1
- package/dist/__tests__/helpers/factories.d.ts +13 -1
- package/dist/__tests__/helpers/factories.d.ts.map +1 -1
- package/dist/cache/DiscoveryCache.d.ts +1 -1
- package/dist/cache/DiscoveryCache.d.ts.map +1 -1
- package/dist/cache/DiscoveryCache.js.map +1 -1
- package/dist/cli.js +3483 -8
- package/dist/config/ConfigLoader.d.ts +2 -2
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +6 -4
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -0
- package/dist/contracts/features.d.ts +39 -0
- package/dist/contracts/features.d.ts.map +1 -0
- package/dist/contracts/features.js +15 -0
- package/dist/contracts/features.js.map +1 -0
- package/dist/contracts/ids.d.ts +58 -0
- package/dist/contracts/ids.d.ts.map +1 -0
- package/dist/contracts/ids.js +31 -0
- package/dist/contracts/ids.js.map +1 -0
- package/dist/contracts/interfaces.d.ts +6 -3
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/strategy.d.ts +2 -2
- package/dist/contracts/strategy.d.ts.map +1 -1
- package/dist/contracts/suspension.d.ts +3 -2
- package/dist/contracts/suspension.d.ts.map +1 -1
- package/dist/contracts/transport.d.ts +25 -0
- package/dist/contracts/transport.d.ts.map +1 -0
- package/dist/core/HistoryManager.d.ts +2 -3
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +10 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/IThoughtFormatter.d.ts +51 -0
- package/dist/core/IThoughtFormatter.d.ts.map +1 -0
- package/dist/core/IThoughtFormatter.js +1 -0
- package/dist/core/InputNormalizer.d.ts.map +1 -1
- package/dist/core/InputNormalizer.js +4 -3
- package/dist/core/InputNormalizer.js.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +1 -1
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/ThoughtFormatter.d.ts +2 -1
- package/dist/core/ThoughtFormatter.d.ts.map +1 -1
- package/dist/core/ThoughtFormatter.js +3 -0
- package/dist/core/ThoughtFormatter.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +2 -2
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +8 -3
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/compression/CompressionService.js +3 -3
- package/dist/core/compression/CompressionService.js.map +1 -1
- package/dist/core/compression/Summary.d.ts +4 -3
- package/dist/core/compression/Summary.d.ts.map +1 -1
- package/dist/core/graph/Edge.d.ts +11 -4
- package/dist/core/graph/Edge.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +5 -5
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.d.ts +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/StrategyFactory.js.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +5 -0
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/core/reasoning.d.ts +8 -1
- package/dist/core/reasoning.d.ts.map +1 -1
- package/dist/core/step.d.ts +5 -0
- package/dist/core/step.d.ts.map +1 -1
- package/dist/core/thought.d.ts +4 -3
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/core/tools/InMemorySuspensionStore.d.ts +3 -1
- package/dist/core/tools/InMemorySuspensionStore.d.ts.map +1 -1
- package/dist/core/tools/InMemorySuspensionStore.js +2 -2
- package/dist/core/tools/InMemorySuspensionStore.js.map +1 -1
- package/dist/di/Container.d.ts +6 -3
- package/dist/di/Container.d.ts.map +1 -1
- package/dist/di/Container.js.map +1 -1
- package/dist/di/ServiceRegistry.d.ts +3 -3
- package/dist/di/ServiceRegistry.d.ts.map +1 -1
- package/dist/errors.d.ts +36 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +49 -22
- package/dist/errors.js.map +1 -1
- package/dist/health/HealthChecker.d.ts +1 -1
- package/dist/health/HealthChecker.d.ts.map +1 -1
- package/dist/health/HealthChecker.js.map +1 -1
- package/dist/lib.d.ts +60 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +2 -2
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +1 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceFactory.d.ts +1 -1
- package/dist/persistence/PersistenceFactory.d.ts.map +1 -1
- package/dist/persistence/PersistenceFactory.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +1 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts +11 -13
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/pool/IConnectionPool.d.ts +100 -0
- package/dist/pool/IConnectionPool.d.ts.map +1 -0
- package/dist/pool/IConnectionPool.js +1 -0
- package/dist/registry/BaseRegistry.d.ts +1 -1
- package/dist/registry/BaseRegistry.d.ts.map +1 -1
- package/dist/registry/BaseRegistry.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/transport/BaseTransport.d.ts +3 -2
- package/dist/transport/BaseTransport.d.ts.map +1 -1
- package/dist/transport/BaseTransport.js +1 -1
- package/dist/transport/BaseTransport.js.map +1 -1
- package/dist/transport/HttpTransport.d.ts +4 -2
- package/dist/transport/HttpTransport.d.ts.map +1 -1
- package/dist/transport/HttpTransport.js +4 -1
- package/dist/transport/HttpTransport.js.map +1 -1
- package/dist/transport/SseTransport.d.ts +4 -2
- package/dist/transport/SseTransport.d.ts.map +1 -1
- package/dist/transport/SseTransport.js +3 -0
- package/dist/transport/SseTransport.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +4 -2
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +4 -1
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/dist/types/skill.d.ts +5 -0
- package/dist/types/skill.d.ts.map +1 -1
- package/dist/types/tool.d.ts +5 -0
- package/dist/types/tool.d.ts.map +1 -1
- package/package.json +11 -11
- package/dist/__tests__/helpers/index.d.ts +0 -3
- package/dist/__tests__/helpers/index.d.ts.map +0 -1
- package/dist/contracts/index.d.ts +0 -14
- package/dist/contracts/index.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1
- package/dist/persistence/PersistenceBackend.d.ts.map +0 -1
- /package/dist/{persistence → contracts}/PersistenceBackend.d.ts +0 -0
- /package/dist/{persistence → contracts}/PersistenceBackend.js +0 -0
- /package/dist/contracts/{index.js → transport.js} +0 -0
|
@@ -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 '
|
|
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';\n\n/**\n * Configuration options for MemoryPersistence.\n */\nexport interface MemoryPersistenceOptions {\n\t/**\n\t * Maximum number of thoughts to keep in memory.\n\t * Older thoughts are trimmed when limit is exceeded.\n\t * Set to 0 or undefined for unlimited.\n\t * @default undefined (unlimited)\n\t */\n\tmaxSize?: number;\n}\n\n/**\n * In-memory persistence backend for testing purposes.\n *\n * This backend stores all data in memory and provides no durability.\n * It's useful for testing and development where persistence is not needed.\n *\n * @example\n * ```typescript\n * // Unlimited history\n * const backend = new MemoryPersistence();\n *\n * // Limited to 1000 thoughts\n * const backend = new MemoryPersistence({ maxSize: 1000 });\n *\n * await backend.saveThought(thought);\n * const history = await backend.loadHistory();\n * ```\n */\nexport class MemoryPersistence implements PersistenceBackend {\n\tprivate _history: ThoughtData[] = [];\n\tprivate _branches: Map<string, ThoughtData[]> = new Map();\n\tprivate _maxSize?: number;\n\tprivate _edges: Map<string, Edge[]> = new Map();\n\tprivate _summaries: Map<string, Summary[]> = new Map();\n\n\tconstructor(options: MemoryPersistenceOptions = {}) {\n\t\tthis._maxSize = options.maxSize && options.maxSize > 0 ? options.maxSize : undefined;\n\t}\n\n\tpublic async saveThought(thought: ThoughtData): Promise<void> {\n\t\tthis._history.push(thought);\n\n\t\t// Trim if maxSize is set and exceeded\n\t\tif (this._maxSize !== undefined && this._history.length > this._maxSize) {\n\t\t\tthis._history = this._history.slice(-this._maxSize);\n\t\t}\n\t}\n\n\tpublic async loadHistory(): Promise<ThoughtData[]> {\n\t\treturn [...this._history];\n\t}\n\n\tpublic async saveBranch(branchId: string, thoughts: ThoughtData[]): Promise<void> {\n\t\tthis._branches.set(branchId, [...thoughts]);\n\t}\n\n\tpublic async loadBranch(branchId: string): Promise<ThoughtData[] | undefined> {\n\t\tconst branch = this._branches.get(branchId);\n\t\treturn branch ? [...branch] : undefined;\n\t}\n\n\tpublic async listBranches(): Promise<string[]> {\n\t\treturn this.getBranchIds();\n\t}\n\n\t/**\n\t * In-memory backend is always healthy.\n\t */\n\tpublic async healthy(): Promise<boolean> {\n\t\treturn true;\n\t}\n\n\t/**\n\t * Clear all data from memory.\n\t */\n\tpublic async clear(): Promise<void> {\n\t\tthis._history = [];\n\t\tthis._branches.clear();\n\t\tthis._edges.clear();\n\t\tthis._summaries.clear();\n\t}\n\n\t/**\n\t * No resources to release for in-memory backend.\n\t */\n\tpublic async close(): Promise<void> {\n\t\t// No-op for in-memory backend\n\t}\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\tpublic async saveEdges(sessionId: string, edges: readonly Edge[]): Promise<void> {\n\t\tif (edges.length === 0) {\n\t\t\tthis._edges.delete(sessionId);\n\t\t} else {\n\t\t\tthis._edges.set(sessionId, [...edges]);\n\t\t}\n\t}\n\n\t/**\n\t * Load edges for a session from memory.\n\t * Returns edges sorted by createdAt ascending.\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\tpublic async loadEdges(sessionId: string): Promise<Edge[]> {\n\t\tconst edges = this._edges.get(sessionId);\n\t\tif (!edges) return [];\n\t\treturn [...edges].sort((a, b) => a.createdAt - b.createdAt);\n\t}\n\n\t/**\n\t * List all session IDs that have persisted edges in memory.\n\t *\n\t * @returns Array of session identifiers with persisted edges\n\t */\n\tpublic async listEdgeSessions(): Promise<string[]> {\n\t\treturn Array.from(this._edges.keys());\n\t}\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\tpublic async saveSummaries(sessionId: string, summaries: readonly Summary[]): Promise<void> {\n\t\tif (summaries.length === 0) {\n\t\t\tthis._summaries.delete(sessionId);\n\t\t} else {\n\t\t\tthis._summaries.set(sessionId, [...summaries]);\n\t\t}\n\t}\n\n\t/**\n\t * Load summaries for a session from memory.\n\t * Returns summaries sorted by createdAt ascending.\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\tpublic async loadSummaries(sessionId: string): Promise<Summary[]> {\n\t\tconst summaries = this._summaries.get(sessionId);\n\t\tif (!summaries) return [];\n\t\treturn [...summaries].sort((a, b) => a.createdAt - b.createdAt);\n\t}\n\n\t/**\n\t * Get the current number of thoughts in memory.\n\t */\n\tpublic getHistorySize(): number {\n\t\treturn this._history.length;\n\t}\n\n\t/**\n\t * Get the current number of branches in memory.\n\t */\n\tpublic getBranchCount(): number {\n\t\treturn this._branches.size;\n\t}\n\n\t/**\n\t * Get all branch IDs.\n\t */\n\tpublic getBranchIds(): string[] {\n\t\treturn Array.from(this._branches.keys());\n\t}\n}\n"],"names":["MemoryPersistence","Map","options","undefined","thought","branchId","thoughts","branch","sessionId","edges","a","b","Array","summaries"],"mappings":"AAoCO,MAAMA;IACJ,WAA0B,EAAE,CAAC;IAC7B,YAAwC,IAAIC,MAAM;IAClD,SAAkB;IAClB,SAA8B,IAAIA,MAAM;IACxC,aAAqC,IAAIA,MAAM;IAEvD,YAAYC,UAAoC,CAAC,CAAC,CAAE;QACnD,IAAI,CAAC,QAAQ,GAAGA,QAAQ,OAAO,IAAIA,QAAQ,OAAO,GAAG,IAAIA,QAAQ,OAAO,GAAGC;IAC5E;IAEA,MAAa,YAAYC,OAAoB,EAAiB;QAC7D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAACA;QAGnB,IAAI,AAAkBD,WAAlB,IAAI,CAAC,QAAQ,IAAkB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,EACtE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ;IAEpD;IAEA,MAAa,cAAsC;QAClD,OAAO;eAAI,IAAI,CAAC,QAAQ;SAAC;IAC1B;IAEA,MAAa,WAAWE,QAAgB,EAAEC,QAAuB,EAAiB;QACjF,IAAI,CAAC,SAAS,CAAC,GAAG,CAACD,UAAU;eAAIC;SAAS;IAC3C;IAEA,MAAa,WAAWD,QAAgB,EAAsC;QAC7E,MAAME,SAAS,IAAI,CAAC,SAAS,CAAC,GAAG,CAACF;QAClC,OAAOE,SAAS;eAAIA;SAAO,GAAGJ;IAC/B;IAEA,MAAa,eAAkC;QAC9C,OAAO,IAAI,CAAC,YAAY;IACzB;IAKA,MAAa,UAA4B;QACxC,OAAO;IACR;IAKA,MAAa,QAAuB;QACnC,IAAI,CAAC,QAAQ,GAAG,EAAE;QAClB,IAAI,CAAC,SAAS,CAAC,KAAK;QACpB,IAAI,CAAC,MAAM,CAAC,KAAK;QACjB,IAAI,CAAC,UAAU,CAAC,KAAK;IACtB;IAKA,MAAa,QAAuB,CAEpC;IAQA,MAAa,UAAUK,SAAiB,EAAEC,KAAsB,EAAiB;QAChF,IAAIA,AAAiB,MAAjBA,MAAM,MAAM,EACf,IAAI,CAAC,MAAM,CAAC,MAAM,CAACD;aAEnB,IAAI,CAAC,MAAM,CAAC,GAAG,CAACA,WAAW;eAAIC;SAAM;IAEvC;IASA,MAAa,UAAUD,SAAiB,EAAmB;QAC1D,MAAMC,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,CAACD;QAC9B,IAAI,CAACC,OAAO,OAAO,EAAE;QACrB,OAAO;eAAIA;SAAM,CAAC,IAAI,CAAC,CAACC,GAAGC,IAAMD,EAAE,SAAS,GAAGC,EAAE,SAAS;IAC3D;IAOA,MAAa,mBAAsC;QAClD,OAAOC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI;IACnC;IAQA,MAAa,cAAcJ,SAAiB,EAAEK,SAA6B,EAAiB;QAC3F,IAAIA,AAAqB,MAArBA,UAAU,MAAM,EACnB,IAAI,CAAC,UAAU,CAAC,MAAM,CAACL;aAEvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAACA,WAAW;eAAIK;SAAU;IAE/C;IASA,MAAa,cAAcL,SAAiB,EAAsB;QACjE,MAAMK,YAAY,IAAI,CAAC,UAAU,CAAC,GAAG,CAACL;QACtC,IAAI,CAACK,WAAW,OAAO,EAAE;QACzB,OAAO;eAAIA;SAAU,CAAC,IAAI,CAAC,CAACH,GAAGC,IAAMD,EAAE,SAAS,GAAGC,EAAE,SAAS;IAC/D;IAKO,iBAAyB;QAC/B,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM;IAC5B;IAKO,iBAAyB;QAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI;IAC3B;IAKO,eAAyB;QAC/B,OAAOC,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI;IACtC;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersistenceFactory.d.ts","sourceRoot":"","sources":["../../src/persistence/PersistenceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"PersistenceFactory.d.ts","sourceRoot":"","sources":["../../src/persistence/PersistenceFactory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEhG;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,wBAAwB,CAC7C,MAAM,EAAE,iBAAiB,GACvB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAwBpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/PersistenceFactory.js","sources":["../../src/persistence/PersistenceFactory.ts"],"sourcesContent":["import type { PersistenceBackend, PersistenceConfig } from '
|
|
1
|
+
{"version":3,"file":"persistence/PersistenceFactory.js","sources":["../../src/persistence/PersistenceFactory.ts"],"sourcesContent":["import type { PersistenceBackend, PersistenceConfig } from '../contracts/PersistenceBackend.js';\n\n/**\n * Create a persistence backend based on the provided configuration.\n *\n * Uses dynamic imports to avoid loading unused backends,\n * keeping the factory decoupled from concrete implementations.\n *\n * @param config - Persistence configuration\n * @returns A configured persistence backend, or null if disabled\n *\n * @example\n * ```typescript\n * const backend = createPersistenceBackend({\n * enabled: true,\n * backend: 'file',\n * options: { dataDir: './data' }\n * });\n * ```\n */\nexport async function createPersistenceBackend(\n\tconfig: PersistenceConfig\n): Promise<PersistenceBackend | null> {\n\tif (!config.enabled) {\n\t\treturn null;\n\t}\n\n\tswitch (config.backend) {\n\t\tcase 'file': {\n\t\t\tconst { FilePersistence } = await import('./FilePersistence.js');\n\t\t\treturn new FilePersistence(config.options);\n\t\t}\n\n\t\tcase 'sqlite': {\n\t\t\tconst { SqlitePersistence } = await import('./SqlitePersistence.js');\n\t\t\treturn await SqlitePersistence.create(config.options);\n\t\t}\n\n\t\tcase 'memory': {\n\t\t\tconst { MemoryPersistence } = await import('./MemoryPersistence.js');\n\t\t\treturn new MemoryPersistence();\n\t\t}\n\n\t\tdefault:\n\t\t\tthrow new Error(`Unknown persistence backend: ${config.backend}`);\n\t}\n}\n"],"names":["createPersistenceBackend","config","FilePersistence","SqlitePersistence","MemoryPersistence","Error"],"mappings":"AAoBO,eAAeA,yBACrBC,MAAyB;IAEzB,IAAI,CAACA,OAAO,OAAO,EAClB,OAAO;IAGR,OAAQA,OAAO,OAAO;QACrB,KAAK;YAAQ;gBACZ,MAAM,EAAEC,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC;gBACzC,OAAO,IAAIA,gBAAgBD,OAAO,OAAO;YAC1C;QAEA,KAAK;YAAU;gBACd,MAAM,EAAEE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC;gBAC3C,OAAO,MAAMA,kBAAkB,MAAM,CAACF,OAAO,OAAO;YACrD;QAEA,KAAK;YAAU;gBACd,MAAM,EAAEG,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC;gBAC3C,OAAO,IAAIA;YACZ;QAEA;YACC,MAAM,IAAIC,MAAM,CAAC,6BAA6B,EAAEJ,OAAO,OAAO,EAAE;IAClE;AACD"}
|
|
@@ -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, PersistenceConfig } from '
|
|
4
|
+
import type { PersistenceBackend, PersistenceConfig } from '../contracts/PersistenceBackend.js';
|
|
5
5
|
/**
|
|
6
6
|
* SQLite-based persistence backend.
|
|
7
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqlitePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SqlitePersistence.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"SqlitePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SqlitePersistence.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAwBhG;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAkB,YAAW,kBAAkB;IAC3D,OAAO,CAAC,GAAG,CAAW;IACtB,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,gBAAgB,CAAU;IAElC,OAAO;IAOP;;;;;;;;;;;;;;OAcG;WACU,MAAM,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAmCvF,OAAO,CAAC,iBAAiB;IAwEZ,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBhD,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAerC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpE,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC;IAoBhE,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAUjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAUxC;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYnC;;;;;;;OAOG;IACU,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BhF;;;;;OAKG;IACU,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAyB1D;;;;OAIG;IACU,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAOlD;;;;;;;;OAQG;IACU,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B3F;;;;;OAKG;IACU,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAgCjE;;OAEG;IACI,QAAQ,IAAI;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;KACf;CAiBD"}
|
|
@@ -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 { ThoughtData } from '../core/thought.js';\nimport type { Edge, EdgeKind } from '../core/graph/Edge.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { PersistenceBackend, PersistenceConfig } from './PersistenceBackend.js';\n\n/**\n * Type definition for the better-sqlite3 Database interface.\n * This allows us to use the library without importing it directly.\n */\ninterface Database {\n\texec(sql: string): void;\n\tprepare(sql: string): Statement;\n\tclose(): void;\n\tpragma(pragma: string): unknown;\n}\n\ninterface Statement {\n\trun(...params: unknown[]): RunResult;\n\tget(...params: unknown[]): unknown;\n\tall(...params: unknown[]): unknown[];\n}\n\ninterface RunResult {\n\tchanges: number;\n\tlastInsertRowid: number;\n}\n\n/**\n * SQLite-based persistence backend.\n *\n * Provides efficient, transactional persistence using SQLite.\n * Requires the 'better-sqlite3' package to be installed.\n *\n * @example\n * ```typescript\n * const backend = await SqlitePersistence.create({\n * dbPath: './data/history.db',\n * enableWAL: true\n * });\n * ```\n */\nexport class SqlitePersistence implements PersistenceBackend {\n\tprivate _db: Database;\n\tprivate _maxHistorySize: number;\n\tprivate _persistBranches: boolean;\n\n\tprivate constructor(db: Database, options: PersistenceConfig['options']) {\n\t\tthis._db = db;\n\t\tthis._maxHistorySize = options?.maxHistorySize ?? 10000;\n\t\tthis._persistBranches = options?.persistBranches ?? true;\n\t\tthis._initializeSchema();\n\t}\n\n\t/**\n\t * Creates a new SqlitePersistence instance with dynamic import of better-sqlite3.\n\t *\n\t * @param options - Configuration options\n\t * @returns A Promise that resolves to a SqlitePersistence instance\n\t * @throws Error if better-sqlite3 is not installed\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = await SqlitePersistence.create({\n\t * dbPath: './data/history.db',\n\t * enableWAL: true\n\t * });\n\t * ```\n\t */\n\tstatic async create(options?: PersistenceConfig['options']): Promise<SqlitePersistence> {\n\t\t// Default to .claude/data in current directory or home directory\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\n\t\t// Load better-sqlite3 dynamically (optional dependency)\n\t\tlet Database: new (path: string) => Database;\n\t\ttry {\n\t\t\tconst module = await import('better-sqlite3');\n\t\t\tDatabase = module.default;\n\t\t} catch {\n\t\t\tthrow new Error(\n\t\t\t\t`SQLite persistence requires 'better-sqlite3' package. Install it with: npm install better-sqlite3`\n\t\t\t);\n\t\t}\n\n\t\tconst db = new Database(dbPath);\n\n\t\t// Enable WAL mode for better concurrency if specified\n\t\tif (options?.enableWAL !== false) {\n\t\t\tdb.pragma('journal_mode = WAL');\n\t\t}\n\n\t\t// Performance and safety PRAGMAs\n\t\tdb.pragma('synchronous = NORMAL');\n\t\tdb.pragma('foreign_keys = ON');\n\t\tdb.pragma('busy_timeout = 5000');\n\t\tdb.pragma('cache_size = -64000'); // 64MB\n\t\tdb.pragma('temp_store = MEMORY');\n\n\t\treturn new SqlitePersistence(db, options);\n\t}\n\n\tprivate _initializeSchema(): void {\n\t\t// Create thoughts table\n\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS thoughts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n data TEXT NOT NULL,\n created_at INTEGER DEFAULT (strftime('%s', 'now'))\n )\n `);\n\n\t\t// Create branches table\n\t\tif (this._persistBranches) {\n\t\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS branches (\n branch_id TEXT PRIMARY KEY,\n data TEXT NOT NULL,\n updated_at INTEGER DEFAULT (strftime('%s', 'now'))\n )\n `);\n\t\t}\n\n\t\t// Create indexes for better performance\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_thoughts_created_at ON thoughts(created_at)\n `);\n\n\t\t// Create edges table for DAG edge storage\n\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n metadata TEXT\n )\n `);\n\n\t\t// Indexes for edge queries\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_edges_session ON edges(session_id)\n `);\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(session_id, from_id)\n `);\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(session_id, to_id)\n `);\n\n\t\t// Create summaries table for compression subsystem\n\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS summaries (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n branch_id TEXT,\n root_thought_id TEXT NOT NULL,\n covered_ids TEXT NOT NULL,\n covered_range_start INTEGER NOT NULL,\n covered_range_end INTEGER NOT NULL,\n topics TEXT NOT NULL,\n aggregate_confidence REAL NOT NULL,\n created_at INTEGER NOT NULL,\n meta TEXT\n )\n `);\n\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_summaries_session ON summaries(session_id)\n `);\n\t}\n\n\tpublic async saveThought(thought: ThoughtData): Promise<void> {\n\t\tconst stmt = this._db.prepare('INSERT INTO thoughts (data) VALUES (?)');\n\t\tstmt.run(JSON.stringify(thought));\n\n\t\t// Trim old thoughts if over limit\n\t\tconst countStmt = this._db.prepare('SELECT COUNT(*) as count FROM thoughts');\n\t\tconst { count } = countStmt.get() as { count: number };\n\n\t\tif (count > this._maxHistorySize) {\n\t\t\tconst deleteStmt = this._db.prepare(\n\t\t\t\t`DELETE FROM thoughts WHERE id IN (\n SELECT id FROM thoughts ORDER BY id ASC LIMIT ?\n )`\n\t\t\t);\n\t\t\tdeleteStmt.run(count - this._maxHistorySize);\n\t\t}\n\t}\n\n\tpublic async loadHistory(): Promise<ThoughtData[]> {\n\t\tconst stmt = this._db.prepare('SELECT data FROM thoughts ORDER BY id ASC');\n\t\tconst rows = stmt.all() as { data: string }[];\n\n\t\treturn rows\n\t\t\t.map((row) => {\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.parse(row.data) as ThoughtData;\n\t\t\t\t} catch {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.filter((t): t is ThoughtData => t !== null);\n\t}\n\n\tpublic async saveBranch(branchId: string, thoughts: ThoughtData[]): Promise<void> {\n\t\tif (!this._persistBranches) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst stmt = this._db.prepare(\n\t\t\t'INSERT OR REPLACE INTO branches (branch_id, data, updated_at) VALUES (?, ?, strftime(\"%s\", \"now\"))'\n\t\t);\n\t\tstmt.run(branchId, JSON.stringify(thoughts));\n\t}\n\n\tpublic async loadBranch(branchId: string): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst stmt = this._db.prepare('SELECT data FROM branches WHERE branch_id = ?');\n\t\tconst row = stmt.get(branchId) as { data: string } | undefined;\n\n\t\tif (!row) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst data = JSON.parse(row.data) as ThoughtData[];\n\t\t\treturn Array.isArray(data) ? data : undefined;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tpublic async listBranches(): Promise<string[]> {\n\t\tif (!this._persistBranches) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst stmt = this._db.prepare('SELECT branch_id FROM branches ORDER BY branch_id ASC');\n\t\tconst rows = stmt.all() as { branch_id: string }[];\n\t\treturn rows.map((row) => row.branch_id);\n\t}\n\n\tpublic async clear(): Promise<void> {\n\t\tthis._db.exec('DELETE FROM thoughts');\n\t\tif (this._persistBranches) {\n\t\t\tthis._db.exec('DELETE FROM branches');\n\t\t}\n\t\tthis._db.exec('DELETE FROM edges');\n\t\tthis._db.exec('DELETE FROM summaries');\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\t// Simple health check - try to execute a query\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Close the database connection with proper cleanup.\n\t * Runs WAL checkpoint before closing to ensure all data is persisted.\n\t */\n\tpublic async close(): Promise<void> {\n\t\tif (this._db) {\n\t\t\ttry {\n\t\t\t\t// Run WAL checkpoint to ensure all data is persisted\n\t\t\t\tthis._db.pragma('wal_checkpoint(TRUNCATE)');\n\t\t\t} catch {\n\t\t\t\t// Ignore checkpoint errors - still try to close\n\t\t\t}\n\t\t\tthis._db.close();\n\t\t}\n\t}\n\n\t/**\n\t * Persist edges for a session using replace semantics: deletes any existing\n\t * edges for the session, then inserts the provided edges within a transaction.\n\t *\n\t * @param sessionId - Session identifier whose edges are being replaced\n\t * @param edges - The edges to persist for the session\n\t * @returns A Promise that resolves when the edges are persisted\n\t */\n\tpublic async saveEdges(sessionId: string, edges: readonly Edge[]): Promise<void> {\n\t\tconst deleteStmt = this._db.prepare('DELETE FROM edges WHERE session_id = ?');\n\t\tconst insertStmt = this._db.prepare(\n\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t);\n\n\t\tconst dbWithTx = this._db as Database & {\n\t\t\ttransaction: (fn: () => void) => () => void;\n\t\t};\n\t\tconst transaction = dbWithTx.transaction(() => {\n\t\t\tdeleteStmt.run(sessionId);\n\t\t\tfor (const edge of edges) {\n\t\t\t\tinsertStmt.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 ? JSON.stringify(edge.metadata) : null\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\ttransaction();\n\t}\n\n\t/**\n\t * Load all edges for a session, ordered by `created_at` ascending.\n\t *\n\t * @param sessionId - Session identifier to load edges for\n\t * @returns A Promise that resolves to the session's edges in chronological order\n\t */\n\tpublic async loadEdges(sessionId: string): Promise<Edge[]> {\n\t\tconst stmt = this._db.prepare(\n\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'\n\t\t);\n\t\tconst rows = stmt.all(sessionId) as Array<{\n\t\t\tid: string;\n\t\t\tsession_id: string;\n\t\t\tfrom_id: string;\n\t\t\tto_id: string;\n\t\t\tkind: string;\n\t\t\tcreated_at: number;\n\t\t\tmetadata: string | null;\n\t\t}>;\n\n\t\treturn rows.map((row) => ({\n\t\t\tid: row.id,\n\t\t\tsessionId: row.session_id,\n\t\t\tfrom: row.from_id,\n\t\t\tto: row.to_id,\n\t\t\tkind: row.kind as EdgeKind,\n\t\t\tcreatedAt: row.created_at,\n\t\t\t...(row.metadata ? { metadata: JSON.parse(row.metadata) as Record<string, unknown> } : {}),\n\t\t}));\n\t}\n\n\t/**\n\t * List all session IDs that have persisted edges in the database.\n\t *\n\t * @returns Array of distinct session identifiers from the edges table\n\t */\n\tpublic async listEdgeSessions(): Promise<string[]> {\n\t\tconst rows = this._db\n\t\t\t.prepare('SELECT DISTINCT session_id FROM edges')\n\t\t\t.all() as { session_id: string }[];\n\t\treturn rows.map((r) => r.session_id);\n\t}\n\n\t/**\n\t * Persist summaries for a session using replace semantics: deletes any\n\t * existing summaries for the session, then inserts the provided summaries\n\t * within a transaction.\n\t *\n\t * @param sessionId - Session identifier whose summaries are being replaced\n\t * @param summaries - The summaries to persist for the session\n\t * @returns A Promise that resolves when the summaries are persisted\n\t */\n\tpublic async saveSummaries(sessionId: string, summaries: readonly Summary[]): Promise<void> {\n\t\tconst deleteStmt = this._db.prepare('DELETE FROM summaries WHERE session_id = ?');\n\t\tconst insertStmt = this._db.prepare(\n\t\t\t'INSERT OR REPLACE 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);\n\n\t\tconst dbWithTx = this._db as Database & {\n\t\t\ttransaction: (fn: () => void) => () => void;\n\t\t};\n\t\tconst transaction = dbWithTx.transaction(() => {\n\t\t\tdeleteStmt.run(sessionId);\n\t\t\tfor (const summary of summaries) {\n\t\t\t\tinsertStmt.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 ? JSON.stringify(summary.meta) : null\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\ttransaction();\n\t}\n\n\t/**\n\t * Load all summaries for a session, ordered by `created_at` ascending.\n\t *\n\t * @param sessionId - Session identifier to load summaries for\n\t * @returns A Promise that resolves to the session's summaries in chronological order\n\t */\n\tpublic async loadSummaries(sessionId: string): Promise<Summary[]> {\n\t\tconst stmt = this._db.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 WHERE session_id = ? ORDER BY created_at ASC'\n\t\t);\n\t\tconst rows = stmt.all(sessionId) as Array<{\n\t\t\tid: string;\n\t\t\tsession_id: string;\n\t\t\tbranch_id: string | null;\n\t\t\troot_thought_id: string;\n\t\t\tcovered_ids: string;\n\t\t\tcovered_range_start: number;\n\t\t\tcovered_range_end: number;\n\t\t\ttopics: string;\n\t\t\taggregate_confidence: number;\n\t\t\tcreated_at: number;\n\t\t\tmeta: string | null;\n\t\t}>;\n\n\t\treturn rows.map((row) => ({\n\t\t\tid: row.id,\n\t\t\tsessionId: row.session_id,\n\t\t\t...(row.branch_id !== null ? { branchId: row.branch_id } : {}),\n\t\t\trootThoughtId: row.root_thought_id,\n\t\t\tcoveredIds: JSON.parse(row.covered_ids) as string[],\n\t\t\tcoveredRange: [row.covered_range_start, row.covered_range_end] as [number, number],\n\t\t\ttopics: JSON.parse(row.topics) as string[],\n\t\t\taggregateConfidence: row.aggregate_confidence,\n\t\t\tcreatedAt: row.created_at,\n\t\t\t...(row.meta ? { meta: JSON.parse(row.meta) as Record<string, unknown> } : {}),\n\t\t}));\n\t}\n\n\t/**\n\t * Get statistics about the persisted data.\n\t */\n\tpublic getStats(): {\n\t\tthoughtCount: number;\n\t\tbranchCount: number;\n\t\tdbSize: number;\n\t} {\n\t\tconst thoughtStmt = this._db.prepare('SELECT COUNT(*) as count FROM thoughts');\n\t\tconst { count: thoughtCount } = thoughtStmt.get() as { count: number };\n\n\t\tlet branchCount = 0;\n\t\tif (this._persistBranches) {\n\t\t\tconst branchStmt = this._db.prepare('SELECT COUNT(*) as count FROM branches');\n\t\t\tconst result = branchStmt.get() as { count: number } | undefined;\n\t\t\tbranchCount = result?.count ?? 0;\n\t\t}\n\n\t\treturn {\n\t\t\tthoughtCount,\n\t\t\tbranchCount,\n\t\t\tdbSize: 0, // Would need to check file size\n\t\t};\n\t}\n}\n"],"names":["SqlitePersistence","db","options","defaultDataDir","existsSync","join","homedir","dbPath","Database","module","Error","thought","stmt","JSON","countStmt","count","deleteStmt","rows","row","t","branchId","thoughts","data","Array","undefined","sessionId","edges","insertStmt","dbWithTx","transaction","edge","r","summaries","summary","thoughtStmt","thoughtCount","branchCount","branchStmt","result"],"mappings":";;;AA4CO,MAAMA;IACJ,IAAc;IACd,gBAAwB;IACxB,iBAA0B;IAElC,YAAoBC,EAAY,EAAEC,OAAqC,CAAE;QACxE,IAAI,CAAC,GAAG,GAAGD;QACX,IAAI,CAAC,eAAe,GAAGC,SAAS,kBAAkB;QAClD,IAAI,CAAC,gBAAgB,GAAGA,SAAS,mBAAmB;QACpD,IAAI,CAAC,iBAAiB;IACvB;IAiBA,aAAa,OAAOA,OAAsC,EAA8B;QAEvF,MAAMC,iBAAiBC,WAAW,kBAC/B,iBACAC,KAAKC,WAAW;QACnB,MAAMC,SAASL,SAAS,UAAUG,KAAKF,gBAAgB;QAGvD,IAAIK;QACJ,IAAI;YACH,MAAMC,SAAS,MAAM,MAAM,CAAC;YAC5BD,WAAWC,OAAO,OAAO;QAC1B,EAAE,OAAM;YACP,MAAM,IAAIC,MACT;QAEF;QAEA,MAAMT,KAAK,IAAIO,SAASD;QAGxB,IAAIL,SAAS,cAAc,OAC1BD,GAAG,MAAM,CAAC;QAIXA,GAAG,MAAM,CAAC;QACVA,GAAG,MAAM,CAAC;QACVA,GAAG,MAAM,CAAC;QACVA,GAAG,MAAM,CAAC;QACVA,GAAG,MAAM,CAAC;QAEV,OAAO,IAAID,kBAAkBC,IAAIC;IAClC;IAEQ,oBAA0B;QAEjC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;;;;;IAMb,CAAC;QAGH,IAAI,IAAI,CAAC,gBAAgB,EACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;;;;;MAMZ,CAAC;QAIL,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;IAEb,CAAC;QAGH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;IAUb,CAAC;QAGH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;IAEb,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;IAEb,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;IAEb,CAAC;QAGH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;;IAcb,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;IAEb,CAAC;IACJ;IAEA,MAAa,YAAYS,OAAoB,EAAiB;QAC7D,MAAMC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QAC9BA,KAAK,GAAG,CAACC,KAAK,SAAS,CAACF;QAGxB,MAAMG,YAAY,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QACnC,MAAM,EAAEC,KAAK,EAAE,GAAGD,UAAU,GAAG;QAE/B,IAAIC,QAAQ,IAAI,CAAC,eAAe,EAAE;YACjC,MAAMC,aAAa,IAAI,CAAC,GAAG,CAAC,OAAO,CAClC,CAAC;;SAEI,CAAC;YAEPA,WAAW,GAAG,CAACD,QAAQ,IAAI,CAAC,eAAe;QAC5C;IACD;IAEA,MAAa,cAAsC;QAClD,MAAMH,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QAC9B,MAAMK,OAAOL,KAAK,GAAG;QAErB,OAAOK,KACL,GAAG,CAAC,CAACC;YACL,IAAI;gBACH,OAAOL,KAAK,KAAK,CAACK,IAAI,IAAI;YAC3B,EAAE,OAAM;gBACP,OAAO;YACR;QACD,GACC,MAAM,CAAC,CAACC,IAAwBA,AAAM,SAANA;IACnC;IAEA,MAAa,WAAWC,QAAgB,EAAEC,QAAuB,EAAiB;QACjF,IAAI,CAAC,IAAI,CAAC,gBAAgB,EACzB;QAGD,MAAMT,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAC5B;QAEDA,KAAK,GAAG,CAACQ,UAAUP,KAAK,SAAS,CAACQ;IACnC;IAEA,MAAa,WAAWD,QAAgB,EAAsC;QAC7E,IAAI,CAAC,IAAI,CAAC,gBAAgB,EACzB;QAGD,MAAMR,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QAC9B,MAAMM,MAAMN,KAAK,GAAG,CAACQ;QAErB,IAAI,CAACF,KACJ;QAGD,IAAI;YACH,MAAMI,OAAOT,KAAK,KAAK,CAACK,IAAI,IAAI;YAChC,OAAOK,MAAM,OAAO,CAACD,QAAQA,OAAOE;QACrC,EAAE,OAAM;YACP;QACD;IACD;IAEA,MAAa,eAAkC;QAC9C,IAAI,CAAC,IAAI,CAAC,gBAAgB,EACzB,OAAO,EAAE;QAGV,MAAMZ,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QAC9B,MAAMK,OAAOL,KAAK,GAAG;QACrB,OAAOK,KAAK,GAAG,CAAC,CAACC,MAAQA,IAAI,SAAS;IACvC;IAEA,MAAa,QAAuB;QACnC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QACd,IAAI,IAAI,CAAC,gBAAgB,EACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAEf,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QACd,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACf;IAEA,MAAa,UAA4B;QACxC,IAAI;YAEH,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,GAAG;YAChC,OAAO;QACR,EAAE,OAAM;YACP,OAAO;QACR;IACD;IAMA,MAAa,QAAuB;QACnC,IAAI,IAAI,CAAC,GAAG,EAAE;YACb,IAAI;gBAEH,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YACjB,EAAE,OAAM,CAER;YACA,IAAI,CAAC,GAAG,CAAC,KAAK;QACf;IACD;IAUA,MAAa,UAAUO,SAAiB,EAAEC,KAAsB,EAAiB;QAChF,MAAMV,aAAa,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QACpC,MAAMW,aAAa,IAAI,CAAC,GAAG,CAAC,OAAO,CAClC;QAGD,MAAMC,WAAW,IAAI,CAAC,GAAG;QAGzB,MAAMC,cAAcD,SAAS,WAAW,CAAC;YACxCZ,WAAW,GAAG,CAACS;YACf,KAAK,MAAMK,QAAQJ,MAClBC,WAAW,GAAG,CACbG,KAAK,EAAE,EACPA,KAAK,SAAS,EACdA,KAAK,IAAI,EACTA,KAAK,EAAE,EACPA,KAAK,IAAI,EACTA,KAAK,SAAS,EACdA,KAAK,QAAQ,GAAGjB,KAAK,SAAS,CAACiB,KAAK,QAAQ,IAAI;QAGnD;QAEAD;IACD;IAQA,MAAa,UAAUJ,SAAiB,EAAmB;QAC1D,MAAMb,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAC5B;QAED,MAAMK,OAAOL,KAAK,GAAG,CAACa;QAUtB,OAAOR,KAAK,GAAG,CAAC,CAACC,MAAS;gBACzB,IAAIA,IAAI,EAAE;gBACV,WAAWA,IAAI,UAAU;gBACzB,MAAMA,IAAI,OAAO;gBACjB,IAAIA,IAAI,KAAK;gBACb,MAAMA,IAAI,IAAI;gBACd,WAAWA,IAAI,UAAU;gBACzB,GAAIA,IAAI,QAAQ,GAAG;oBAAE,UAAUL,KAAK,KAAK,CAACK,IAAI,QAAQ;gBAA6B,IAAI,CAAC,CAAC;YAC1F;IACD;IAOA,MAAa,mBAAsC;QAClD,MAAMD,OAAO,IAAI,CAAC,GAAG,CACnB,OAAO,CAAC,yCACR,GAAG;QACL,OAAOA,KAAK,GAAG,CAAC,CAACc,IAAMA,EAAE,UAAU;IACpC;IAWA,MAAa,cAAcN,SAAiB,EAAEO,SAA6B,EAAiB;QAC3F,MAAMhB,aAAa,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QACpC,MAAMW,aAAa,IAAI,CAAC,GAAG,CAAC,OAAO,CAClC;QAGD,MAAMC,WAAW,IAAI,CAAC,GAAG;QAGzB,MAAMC,cAAcD,SAAS,WAAW,CAAC;YACxCZ,WAAW,GAAG,CAACS;YACf,KAAK,MAAMQ,WAAWD,UACrBL,WAAW,GAAG,CACbM,QAAQ,EAAE,EACVA,QAAQ,SAAS,EACjBA,QAAQ,QAAQ,IAAI,MACpBA,QAAQ,aAAa,EACrBpB,KAAK,SAAS,CAACoB,QAAQ,UAAU,GACjCA,QAAQ,YAAY,CAAC,EAAE,EACvBA,QAAQ,YAAY,CAAC,EAAE,EACvBpB,KAAK,SAAS,CAACoB,QAAQ,MAAM,GAC7BA,QAAQ,mBAAmB,EAC3BA,QAAQ,SAAS,EACjBA,QAAQ,IAAI,GAAGpB,KAAK,SAAS,CAACoB,QAAQ,IAAI,IAAI;QAGjD;QAEAJ;IACD;IAQA,MAAa,cAAcJ,SAAiB,EAAsB;QACjE,MAAMb,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAC5B;QAED,MAAMK,OAAOL,KAAK,GAAG,CAACa;QActB,OAAOR,KAAK,GAAG,CAAC,CAACC,MAAS;gBACzB,IAAIA,IAAI,EAAE;gBACV,WAAWA,IAAI,UAAU;gBACzB,GAAIA,AAAkB,SAAlBA,IAAI,SAAS,GAAY;oBAAE,UAAUA,IAAI,SAAS;gBAAC,IAAI,CAAC,CAAC;gBAC7D,eAAeA,IAAI,eAAe;gBAClC,YAAYL,KAAK,KAAK,CAACK,IAAI,WAAW;gBACtC,cAAc;oBAACA,IAAI,mBAAmB;oBAAEA,IAAI,iBAAiB;iBAAC;gBAC9D,QAAQL,KAAK,KAAK,CAACK,IAAI,MAAM;gBAC7B,qBAAqBA,IAAI,oBAAoB;gBAC7C,WAAWA,IAAI,UAAU;gBACzB,GAAIA,IAAI,IAAI,GAAG;oBAAE,MAAML,KAAK,KAAK,CAACK,IAAI,IAAI;gBAA6B,IAAI,CAAC,CAAC;YAC9E;IACD;IAKO,WAIL;QACD,MAAMgB,cAAc,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;QACrC,MAAM,EAAE,OAAOC,YAAY,EAAE,GAAGD,YAAY,GAAG;QAE/C,IAAIE,cAAc;QAClB,IAAI,IAAI,CAAC,gBAAgB,EAAE;YAC1B,MAAMC,aAAa,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YACpC,MAAMC,SAASD,WAAW,GAAG;YAC7BD,cAAcE,QAAQ,SAAS;QAChC;QAEA,OAAO;YACNH;YACAC;YACA,QAAQ;QACT;IACD;AACD"}
|
|
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 { ThoughtData } from '../core/thought.js';\nimport type { Edge, EdgeKind } from '../core/graph/Edge.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { PersistenceBackend, PersistenceConfig } from '../contracts/PersistenceBackend.js';\n\n/**\n * Type definition for the better-sqlite3 Database interface.\n * This allows us to use the library without importing it directly.\n */\ninterface Database {\n\texec(sql: string): void;\n\tprepare(sql: string): Statement;\n\tclose(): void;\n\tpragma(pragma: string): unknown;\n}\n\ninterface Statement {\n\trun(...params: unknown[]): RunResult;\n\tget(...params: unknown[]): unknown;\n\tall(...params: unknown[]): unknown[];\n}\n\ninterface RunResult {\n\tchanges: number;\n\tlastInsertRowid: number;\n}\n\n/**\n * SQLite-based persistence backend.\n *\n * Provides efficient, transactional persistence using SQLite.\n * Requires the 'better-sqlite3' package to be installed.\n *\n * @example\n * ```typescript\n * const backend = await SqlitePersistence.create({\n * dbPath: './data/history.db',\n * enableWAL: true\n * });\n * ```\n */\nexport class SqlitePersistence implements PersistenceBackend {\n\tprivate _db: Database;\n\tprivate _maxHistorySize: number;\n\tprivate _persistBranches: boolean;\n\n\tprivate constructor(db: Database, options: PersistenceConfig['options']) {\n\t\tthis._db = db;\n\t\tthis._maxHistorySize = options?.maxHistorySize ?? 10000;\n\t\tthis._persistBranches = options?.persistBranches ?? true;\n\t\tthis._initializeSchema();\n\t}\n\n\t/**\n\t * Creates a new SqlitePersistence instance with dynamic import of better-sqlite3.\n\t *\n\t * @param options - Configuration options\n\t * @returns A Promise that resolves to a SqlitePersistence instance\n\t * @throws Error if better-sqlite3 is not installed\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = await SqlitePersistence.create({\n\t * dbPath: './data/history.db',\n\t * enableWAL: true\n\t * });\n\t * ```\n\t */\n\tstatic async create(options?: PersistenceConfig['options']): Promise<SqlitePersistence> {\n\t\t// Default to .claude/data in current directory or home directory\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\n\t\t// Load better-sqlite3 dynamically (optional dependency)\n\t\tlet Database: new (path: string) => Database;\n\t\ttry {\n\t\t\tconst module = await import('better-sqlite3');\n\t\t\tDatabase = module.default;\n\t\t} catch {\n\t\t\tthrow new Error(\n\t\t\t\t`SQLite persistence requires 'better-sqlite3' package. Install it with: npm install better-sqlite3`\n\t\t\t);\n\t\t}\n\n\t\tconst db = new Database(dbPath);\n\n\t\t// Enable WAL mode for better concurrency if specified\n\t\tif (options?.enableWAL !== false) {\n\t\t\tdb.pragma('journal_mode = WAL');\n\t\t}\n\n\t\t// Performance and safety PRAGMAs\n\t\tdb.pragma('synchronous = NORMAL');\n\t\tdb.pragma('foreign_keys = ON');\n\t\tdb.pragma('busy_timeout = 5000');\n\t\tdb.pragma('cache_size = -64000'); // 64MB\n\t\tdb.pragma('temp_store = MEMORY');\n\n\t\treturn new SqlitePersistence(db, options);\n\t}\n\n\tprivate _initializeSchema(): void {\n\t\t// Create thoughts table\n\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS thoughts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n data TEXT NOT NULL,\n created_at INTEGER DEFAULT (strftime('%s', 'now'))\n )\n `);\n\n\t\t// Create branches table\n\t\tif (this._persistBranches) {\n\t\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS branches (\n branch_id TEXT PRIMARY KEY,\n data TEXT NOT NULL,\n updated_at INTEGER DEFAULT (strftime('%s', 'now'))\n )\n `);\n\t\t}\n\n\t\t// Create indexes for better performance\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_thoughts_created_at ON thoughts(created_at)\n `);\n\n\t\t// Create edges table for DAG edge storage\n\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n metadata TEXT\n )\n `);\n\n\t\t// Indexes for edge queries\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_edges_session ON edges(session_id)\n `);\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(session_id, from_id)\n `);\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(session_id, to_id)\n `);\n\n\t\t// Create summaries table for compression subsystem\n\t\tthis._db.exec(`\n CREATE TABLE IF NOT EXISTS summaries (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n branch_id TEXT,\n root_thought_id TEXT NOT NULL,\n covered_ids TEXT NOT NULL,\n covered_range_start INTEGER NOT NULL,\n covered_range_end INTEGER NOT NULL,\n topics TEXT NOT NULL,\n aggregate_confidence REAL NOT NULL,\n created_at INTEGER NOT NULL,\n meta TEXT\n )\n `);\n\n\t\tthis._db.exec(`\n CREATE INDEX IF NOT EXISTS idx_summaries_session ON summaries(session_id)\n `);\n\t}\n\n\tpublic async saveThought(thought: ThoughtData): Promise<void> {\n\t\tconst stmt = this._db.prepare('INSERT INTO thoughts (data) VALUES (?)');\n\t\tstmt.run(JSON.stringify(thought));\n\n\t\t// Trim old thoughts if over limit\n\t\tconst countStmt = this._db.prepare('SELECT COUNT(*) as count FROM thoughts');\n\t\tconst { count } = countStmt.get() as { count: number };\n\n\t\tif (count > this._maxHistorySize) {\n\t\t\tconst deleteStmt = this._db.prepare(\n\t\t\t\t`DELETE FROM thoughts WHERE id IN (\n SELECT id FROM thoughts ORDER BY id ASC LIMIT ?\n )`\n\t\t\t);\n\t\t\tdeleteStmt.run(count - this._maxHistorySize);\n\t\t}\n\t}\n\n\tpublic async loadHistory(): Promise<ThoughtData[]> {\n\t\tconst stmt = this._db.prepare('SELECT data FROM thoughts ORDER BY id ASC');\n\t\tconst rows = stmt.all() as { data: string }[];\n\n\t\treturn rows\n\t\t\t.map((row) => {\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.parse(row.data) as ThoughtData;\n\t\t\t\t} catch {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.filter((t): t is ThoughtData => t !== null);\n\t}\n\n\tpublic async saveBranch(branchId: string, thoughts: ThoughtData[]): Promise<void> {\n\t\tif (!this._persistBranches) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst stmt = this._db.prepare(\n\t\t\t'INSERT OR REPLACE INTO branches (branch_id, data, updated_at) VALUES (?, ?, strftime(\"%s\", \"now\"))'\n\t\t);\n\t\tstmt.run(branchId, JSON.stringify(thoughts));\n\t}\n\n\tpublic async loadBranch(branchId: string): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst stmt = this._db.prepare('SELECT data FROM branches WHERE branch_id = ?');\n\t\tconst row = stmt.get(branchId) as { data: string } | undefined;\n\n\t\tif (!row) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst data = JSON.parse(row.data) as ThoughtData[];\n\t\t\treturn Array.isArray(data) ? data : undefined;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tpublic async listBranches(): Promise<string[]> {\n\t\tif (!this._persistBranches) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst stmt = this._db.prepare('SELECT branch_id FROM branches ORDER BY branch_id ASC');\n\t\tconst rows = stmt.all() as { branch_id: string }[];\n\t\treturn rows.map((row) => row.branch_id);\n\t}\n\n\tpublic async clear(): Promise<void> {\n\t\tthis._db.exec('DELETE FROM thoughts');\n\t\tif (this._persistBranches) {\n\t\t\tthis._db.exec('DELETE FROM branches');\n\t\t}\n\t\tthis._db.exec('DELETE FROM edges');\n\t\tthis._db.exec('DELETE FROM summaries');\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\t// Simple health check - try to execute a query\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Close the database connection with proper cleanup.\n\t * Runs WAL checkpoint before closing to ensure all data is persisted.\n\t */\n\tpublic async close(): Promise<void> {\n\t\tif (this._db) {\n\t\t\ttry {\n\t\t\t\t// Run WAL checkpoint to ensure all data is persisted\n\t\t\t\tthis._db.pragma('wal_checkpoint(TRUNCATE)');\n\t\t\t} catch {\n\t\t\t\t// Ignore checkpoint errors - still try to close\n\t\t\t}\n\t\t\tthis._db.close();\n\t\t}\n\t}\n\n\t/**\n\t * Persist edges for a session using replace semantics: deletes any existing\n\t * edges for the session, then inserts the provided edges within a transaction.\n\t *\n\t * @param sessionId - Session identifier whose edges are being replaced\n\t * @param edges - The edges to persist for the session\n\t * @returns A Promise that resolves when the edges are persisted\n\t */\n\tpublic async saveEdges(sessionId: string, edges: readonly Edge[]): Promise<void> {\n\t\tconst deleteStmt = this._db.prepare('DELETE FROM edges WHERE session_id = ?');\n\t\tconst insertStmt = this._db.prepare(\n\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t);\n\n\t\tconst dbWithTx = this._db as Database & {\n\t\t\ttransaction: (fn: () => void) => () => void;\n\t\t};\n\t\tconst transaction = dbWithTx.transaction(() => {\n\t\t\tdeleteStmt.run(sessionId);\n\t\t\tfor (const edge of edges) {\n\t\t\t\tinsertStmt.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 ? JSON.stringify(edge.metadata) : null\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\ttransaction();\n\t}\n\n\t/**\n\t * Load all edges for a session, ordered by `created_at` ascending.\n\t *\n\t * @param sessionId - Session identifier to load edges for\n\t * @returns A Promise that resolves to the session's edges in chronological order\n\t */\n\tpublic async loadEdges(sessionId: string): Promise<Edge[]> {\n\t\tconst stmt = this._db.prepare(\n\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'\n\t\t);\n\t\tconst rows = stmt.all(sessionId) as Array<{\n\t\t\tid: string;\n\t\t\tsession_id: string;\n\t\t\tfrom_id: string;\n\t\t\tto_id: string;\n\t\t\tkind: string;\n\t\t\tcreated_at: number;\n\t\t\tmetadata: string | null;\n\t\t}>;\n\n\t\treturn rows.map((row) => ({\n\t\t\tid: row.id as Edge['id'],\n\t\t\tsessionId: row.session_id as Edge['sessionId'],\n\t\t\tfrom: row.from_id as Edge['from'],\n\t\t\tto: row.to_id as Edge['to'],\n\t\t\tkind: row.kind as EdgeKind,\n\t\t\tcreatedAt: row.created_at,\n\t\t\t...(row.metadata ? { metadata: JSON.parse(row.metadata) as Record<string, unknown> } : {}),\n\t\t}));\n\t}\n\n\t/**\n\t * List all session IDs that have persisted edges in the database.\n\t *\n\t * @returns Array of distinct session identifiers from the edges table\n\t */\n\tpublic async listEdgeSessions(): Promise<string[]> {\n\t\tconst rows = this._db\n\t\t\t.prepare('SELECT DISTINCT session_id FROM edges')\n\t\t\t.all() as { session_id: string }[];\n\t\treturn rows.map((r) => r.session_id);\n\t}\n\n\t/**\n\t * Persist summaries for a session using replace semantics: deletes any\n\t * existing summaries for the session, then inserts the provided summaries\n\t * within a transaction.\n\t *\n\t * @param sessionId - Session identifier whose summaries are being replaced\n\t * @param summaries - The summaries to persist for the session\n\t * @returns A Promise that resolves when the summaries are persisted\n\t */\n\tpublic async saveSummaries(sessionId: string, summaries: readonly Summary[]): Promise<void> {\n\t\tconst deleteStmt = this._db.prepare('DELETE FROM summaries WHERE session_id = ?');\n\t\tconst insertStmt = this._db.prepare(\n\t\t\t'INSERT OR REPLACE 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);\n\n\t\tconst dbWithTx = this._db as Database & {\n\t\t\ttransaction: (fn: () => void) => () => void;\n\t\t};\n\t\tconst transaction = dbWithTx.transaction(() => {\n\t\t\tdeleteStmt.run(sessionId);\n\t\t\tfor (const summary of summaries) {\n\t\t\t\tinsertStmt.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 ? JSON.stringify(summary.meta) : null\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\ttransaction();\n\t}\n\n\t/**\n\t * Load all summaries for a session, ordered by `created_at` ascending.\n\t *\n\t * @param sessionId - Session identifier to load summaries for\n\t * @returns A Promise that resolves to the session's summaries in chronological order\n\t */\n\tpublic async loadSummaries(sessionId: string): Promise<Summary[]> {\n\t\tconst stmt = this._db.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 WHERE session_id = ? ORDER BY created_at ASC'\n\t\t);\n\t\tconst rows = stmt.all(sessionId) as Array<{\n\t\t\tid: string;\n\t\t\tsession_id: string;\n\t\t\tbranch_id: string | null;\n\t\t\troot_thought_id: string;\n\t\t\tcovered_ids: string;\n\t\t\tcovered_range_start: number;\n\t\t\tcovered_range_end: number;\n\t\t\ttopics: string;\n\t\t\taggregate_confidence: number;\n\t\t\tcreated_at: number;\n\t\t\tmeta: string | null;\n\t\t}>;\n\n\t\treturn rows.map((row) => ({\n\t\t\tid: row.id,\n\t\t\tsessionId: row.session_id as Summary['sessionId'],\n\t\t\t...(row.branch_id !== null ? { branchId: row.branch_id } : {}),\n\t\t\trootThoughtId: row.root_thought_id as Summary['rootThoughtId'],\n\t\t\tcoveredIds: JSON.parse(row.covered_ids) as Summary['coveredIds'],\n\t\t\tcoveredRange: [row.covered_range_start, row.covered_range_end] as [number, number],\n\t\t\ttopics: JSON.parse(row.topics) as string[],\n\t\t\taggregateConfidence: row.aggregate_confidence,\n\t\t\tcreatedAt: row.created_at,\n\t\t\t...(row.meta ? { meta: JSON.parse(row.meta) as Record<string, unknown> } : {}),\n\t\t}));\n\t}\n\n\t/**\n\t * Get statistics about the persisted data.\n\t */\n\tpublic getStats(): {\n\t\tthoughtCount: number;\n\t\tbranchCount: number;\n\t\tdbSize: number;\n\t} {\n\t\tconst thoughtStmt = this._db.prepare('SELECT COUNT(*) as count FROM thoughts');\n\t\tconst { count: thoughtCount } = thoughtStmt.get() as { count: number };\n\n\t\tlet branchCount = 0;\n\t\tif (this._persistBranches) {\n\t\t\tconst branchStmt = this._db.prepare('SELECT COUNT(*) as count FROM branches');\n\t\t\tconst result = branchStmt.get() as { count: number } | undefined;\n\t\t\tbranchCount = result?.count ?? 0;\n\t\t}\n\n\t\treturn {\n\t\t\tthoughtCount,\n\t\t\tbranchCount,\n\t\t\tdbSize: 0, // Would need to check file size\n\t\t};\n\t}\n}\n"],"names":["SqlitePersistence","db","options","defaultDataDir","existsSync","join","homedir","dbPath","Database","module","Error","thought","stmt","JSON","countStmt","count","deleteStmt","rows","row","t","branchId","thoughts","data","Array","undefined","sessionId","edges","insertStmt","dbWithTx","transaction","edge","r","summaries","summary","thoughtStmt","thoughtCount","branchCount","branchStmt","result"],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { ThoughtData } from '../core/thought.js';
|
|
20
20
|
import type { Logger } from '../logger/StructuredLogger.js';
|
|
21
|
-
import type {
|
|
21
|
+
import type { ConnectionPoolStats, IConnectionPool } from './IConnectionPool.js';
|
|
22
22
|
export interface SessionOptions {
|
|
23
23
|
/**
|
|
24
24
|
* Maximum number of concurrent sessions
|
|
@@ -57,11 +57,15 @@ export interface SessionServer {
|
|
|
57
57
|
processThought(input: ThoughtData): Promise<ProcessResult>;
|
|
58
58
|
stop(): void | Promise<void>;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Represents a content block in a process result.
|
|
62
|
+
*/
|
|
63
|
+
export type ContentBlock = {
|
|
64
|
+
type: 'text';
|
|
65
|
+
text: string;
|
|
66
|
+
};
|
|
60
67
|
export interface ProcessResult {
|
|
61
|
-
content:
|
|
62
|
-
type: string;
|
|
63
|
-
text: string;
|
|
64
|
-
}>;
|
|
68
|
+
content: ContentBlock[];
|
|
65
69
|
isError?: boolean;
|
|
66
70
|
}
|
|
67
71
|
/**
|
|
@@ -112,7 +116,7 @@ export declare class Session {
|
|
|
112
116
|
* Each session has its own server instance with isolated state,
|
|
113
117
|
* allowing multiple users to interact with the system simultaneously.
|
|
114
118
|
*/
|
|
115
|
-
export declare class ConnectionPool implements
|
|
119
|
+
export declare class ConnectionPool implements IConnectionPool {
|
|
116
120
|
private _sessions;
|
|
117
121
|
private _createSessionLock;
|
|
118
122
|
private _maxSessions;
|
|
@@ -167,13 +171,7 @@ export declare class ConnectionPool implements IDisposable {
|
|
|
167
171
|
/**
|
|
168
172
|
* Get connection pool statistics.
|
|
169
173
|
*/
|
|
170
|
-
getStats():
|
|
171
|
-
totalSessions: number;
|
|
172
|
-
activeSessions: number;
|
|
173
|
-
maxSessions: number;
|
|
174
|
-
cleanupEnabled: boolean;
|
|
175
|
-
sessionTimeout: number;
|
|
176
|
-
};
|
|
174
|
+
getStats(): ConnectionPoolStats;
|
|
177
175
|
/**
|
|
178
176
|
* Start the automatic cleanup timer.
|
|
179
177
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/ConnectionPool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"ConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/ConnectionPool.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool/ConnectionPool.js","sources":["../../src/pool/ConnectionPool.ts"],"sourcesContent":["/**\n * Connection Pool for managing concurrent user sessions.\n *\n * This module provides session management for multi-user scenarios,\n * allowing multiple concurrent clients to each have isolated state.\n *\n * @example\n * ```typescript\n * const pool = new ConnectionPool({\n * maxSessions: 100,\n * sessionTimeout: 300000 // 5 minutes\n * });\n *\n * const sessionId = await pool.createSession();\n * await pool.process(sessionId, thought);\n * await pool.closeSession(sessionId);\n * ```\n */\n\nimport type { ThoughtData } from '../core/thought.js';\nimport {\n\tMaxSessionsReachedError,\n\tPoolTerminatedError,\n\tSessionNotActiveError,\n\tSessionNotFoundError,\n} from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { IDisposable } from '../types/disposable.js';\n\nexport interface SessionOptions {\n\t/**\n\t * Maximum number of concurrent sessions\n\t * @default 100\n\t */\n\tmaxSessions?: number;\n\n\t/**\n\t * Logger instance\n\t */\n\tlogger?: Logger;\n\n\tserverFactory?: () => Promise<SessionServer>;\n\n\t/**\n\t * Session timeout in milliseconds\n\t * @default 300000 (5 minutes)\n\t */\n\tsessionTimeout?: number;\n\n\t/**\n\t * Whether to enable automatic session cleanup\n\t * @default true\n\t */\n\tautoCleanup?: boolean;\n\n\t/**\n\t * Cleanup interval in milliseconds\n\t * @default 60000 (1 minute)\n\t */\n\tcleanupInterval?: number;\n}\n\nexport interface SessionInfo {\n\tid: string;\n\tserver: SessionServer;\n\tcreatedAt: number;\n\tlastActivityAt: number;\n\tisActive: boolean;\n}\n\nexport interface SessionServer {\n\tprocessThought(input: ThoughtData): Promise<ProcessResult>;\n\tstop(): void | Promise<void>;\n}\n\nexport interface ProcessResult {\n\tcontent: Array<{\n\t\ttype: string;\n\t\ttext: string;\n\t}>;\n\tisError?: boolean;\n}\n\n/**\n * Represents a user session with its own server instance.\n */\nexport class Session {\n\tprivate _server: SessionServer;\n\tprivate _id: string;\n\tprivate _createdAt: number;\n\tprivate _lastActivityAt: number;\n\tprivate _isActiveValue: boolean;\n\tprivate _timeout: number;\n\tprivate _cleanupTimer: NodeJS.Timeout | null = null;\n\tprivate _logger: Logger;\n\n\tconstructor(id: string, server: SessionServer, timeout: number, logger: Logger) {\n\t\tthis._server = server;\n\t\tthis._id = id;\n\t\tthis._createdAt = Date.now();\n\t\tthis._lastActivityAt = this._createdAt;\n\t\tthis._isActiveValue = true;\n\t\tthis._timeout = timeout;\n\t\tthis._logger = logger;\n\n\t\t// Start session timeout timer\n\t\tthis._startTimeout();\n\t}\n\n\t/**\n\t * Check if the session is active.\n\t */\n\tget isActive(): boolean {\n\t\treturn this._isActiveValue;\n\t}\n\n\t/**\n\t * Process a thought through this session's server instance.\n\t */\n\tasync process(input: ThoughtData): Promise<ProcessResult> {\n\t\tif (!this.isActive) {\n\t\t\tthrow new SessionNotActiveError(this._id);\n\t\t}\n\n\t\t// Update last activity\n\t\tthis._lastActivityAt = Date.now();\n\n\t\t// Reset timeout timer\n\t\tthis._resetTimeout();\n\n\t\t// Process the thought\n\t\treturn this._server.processThought(input);\n\t}\n\n\t/**\n\t * Get session information.\n\t */\n\tgetInfo(): SessionInfo {\n\t\treturn {\n\t\t\tid: this._id,\n\t\t\tserver: this._server,\n\t\t\tcreatedAt: this._createdAt,\n\t\t\tlastActivityAt: this._lastActivityAt,\n\t\t\tisActive: this.isActive,\n\t\t};\n\t}\n\n\t/**\n\t * Check if the session has timed out.\n\t */\n\tisTimedOut(): boolean {\n\t\treturn Date.now() - this._lastActivityAt > this._timeout;\n\t}\n\n\t/**\n\t * Close the session and stop the server.\n\t */\n\tasync close(): Promise<void> {\n\t\tthis._isActiveValue = false;\n\n\t\t// Stop timeout timer\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t\tthis._cleanupTimer = null;\n\t\t}\n\n\t\t// Stop the server\n\t\tthis._server.stop();\n\t}\n\n\t/**\n\t * Start the session timeout timer.\n\t */\n\tprivate _startTimeout(): void {\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t}\n\n\t\tthis._cleanupTimer = setTimeout(() => {\n\t\t\tif (this.isTimedOut()) {\n\t\t\t\tthis._logger.warn(`Session ${this._id} timed out, closing`);\n\t\t\t\tthis.close().catch((err) => {\n\t\t\t\t\tthis._logger.error(`Error closing timed out session ${this._id}:`, err);\n\t\t\t\t});\n\t\t\t}\n\t\t}, this._timeout);\n\t}\n\n\t/**\n\t * Reset the timeout timer after activity.\n\t */\n\tprivate _resetTimeout(): void {\n\t\tthis._startTimeout();\n\t}\n}\n\n/**\n * ConnectionPool manages multiple concurrent user sessions.\n *\n * Each session has its own server instance with isolated state,\n * allowing multiple users to interact with the system simultaneously.\n */\nexport class ConnectionPool implements IDisposable {\n\tprivate _sessions: Map<string, Session> = new Map();\n\tprivate _createSessionLock: Promise<void> | null = null;\n\tprivate _maxSessions: number;\n\tprivate _sessionTimeout: number;\n\tprivate _autoCleanup: boolean;\n\tprivate _cleanupInterval: number;\n\tprivate _cleanupTimerId: number | null = null;\n\tprivate _terminated: boolean = false;\n\tprivate _logger: Logger;\n\tprivate _serverFactory: (() => Promise<SessionServer>) | null;\n\n\tconstructor(options: SessionOptions = {}) {\n\t\tthis._maxSessions = options.maxSessions ?? 100;\n\t\tthis._sessionTimeout = options.sessionTimeout ?? 300000; // 5 minutes\n\t\tthis._autoCleanup = options.autoCleanup ?? true;\n\t\tthis._cleanupInterval = options.cleanupInterval ?? 60000; // 1 minute\n\t\tthis._serverFactory = options.serverFactory ?? null;\n\t\tthis._logger = options.logger ?? this._createNoopLogger();\n\n\t\tif (this._autoCleanup) {\n\t\t\tthis._startCleanup();\n\t\t}\n\t}\n\n\t/**\n\t * Create a no-op logger when none is provided.\n\t */\n\tprivate _createNoopLogger(): Logger {\n\t\treturn {\n\t\t\tinfo: (): void => {},\n\t\t\twarn: (): void => {},\n\t\t\terror: (): void => {},\n\t\t\tdebug: (): void => {},\n\t\t\tsetLevel: (): void => {},\n\t\t\tgetLevel: (): 'info' => 'info',\n\t\t};\n\t}\n\n\t/**\n\t * Create a new session.\n\t *\n\t * @returns The session ID\n\t * @throws Error if max sessions reached\n\t */\n\tasync createSession(): Promise<string> {\n\t\twhile (this._createSessionLock) {\n\t\t\tawait this._createSessionLock;\n\t\t}\n\n\t\tif (this._terminated) {\n\t\t\tthrow new PoolTerminatedError();\n\t\t}\n\n\t\tif (this._sessions.size >= this._maxSessions) {\n\t\t\tthrow new MaxSessionsReachedError(this._maxSessions);\n\t\t}\n\n\t\tif (!this._serverFactory) {\n\t\t\tthrow new Error('ConnectionPool requires a serverFactory option to create sessions');\n\t\t}\n\n\t\tlet resolveLock!: () => void;\n\t\tthis._createSessionLock = new Promise<void>((resolve) => {\n\t\t\tresolveLock = resolve;\n\t\t});\n\n\t\ttry {\n\t\t\t// Generate unique session ID\n\t\t\tconst sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n\n\t\t\t// Create a new server instance for this session\n\t\t\tconst server = await this._serverFactory();\n\n\t\t\t// Create session\n\t\t\tconst session = new Session(sessionId, server, this._sessionTimeout, this._logger);\n\t\t\tthis._sessions.set(sessionId, session);\n\n\t\t\tthis._logger.info(\n\t\t\t\t`Created session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t\treturn sessionId;\n\t\t} finally {\n\t\t\tresolveLock();\n\t\t\tthis._createSessionLock = null;\n\t\t}\n\t}\n\n\t/**\n\t * Process a thought in the specified session.\n\t *\n\t * @param sessionId - The session ID\n\t * @param input - The thought data to process\n\t * @returns Promise with the processing result\n\t * @throws Error if session not found\n\t */\n\tasync process(sessionId: string, input: ThoughtData): Promise<ProcessResult> {\n\t\tconst session = this._sessions.get(sessionId);\n\n\t\tif (!session) {\n\t\t\tthrow new SessionNotFoundError(sessionId);\n\t\t}\n\n\t\treturn session.process(input);\n\t}\n\n\t/**\n\t * Close a session and release resources.\n\t *\n\t * @param sessionId - The session ID to close\n\t * @throws Error if session not found\n\t */\n\tasync closeSession(sessionId: string): Promise<void> {\n\t\tconst session = this._sessions.get(sessionId);\n\n\t\tif (!session) {\n\t\t\tthrow new SessionNotFoundError(sessionId);\n\t\t}\n\n\t\tawait session.close();\n\t\tthis._sessions.delete(sessionId);\n\n\t\tthis._logger.info(\n\t\t\t`Closed session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t);\n\t}\n\n\t/**\n\t * Get information about a session.\n\t *\n\t * @param sessionId - The session ID\n\t * @returns Session info or undefined if not found\n\t */\n\tgetSessionInfo(sessionId: string): SessionInfo | undefined {\n\t\treturn this._sessions.get(sessionId)?.getInfo();\n\t}\n\n\t/**\n\t * Get all active sessions.\n\t *\n\t * @returns Array of session information\n\t */\n\tgetActiveSessions(): SessionInfo[] {\n\t\treturn Array.from(this._sessions.values())\n\t\t\t.filter((s) => s.isActive)\n\t\t\t.map((s) => s.getInfo());\n\t}\n\n\t/**\n\t * Get connection pool statistics.\n\t */\n\tgetStats(): {\n\t\ttotalSessions: number;\n\t\tactiveSessions: number;\n\t\tmaxSessions: number;\n\t\tcleanupEnabled: boolean;\n\t\tsessionTimeout: number;\n\t} {\n\t\tconst activeSessions = this.getActiveSessions();\n\n\t\treturn {\n\t\t\ttotalSessions: this._sessions.size,\n\t\t\tactiveSessions: activeSessions.length,\n\t\t\tmaxSessions: this._maxSessions,\n\t\t\tcleanupEnabled: this._autoCleanup,\n\t\t\tsessionTimeout: this._sessionTimeout,\n\t\t};\n\t}\n\n\t/**\n\t * Start the automatic cleanup timer.\n\t */\n\tprivate _startCleanup(): void {\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t}\n\n\t\tthis._cleanupTimerId = setInterval(() => {\n\t\t\tthis._cleanupTimedOutSessions();\n\t\t}, this._cleanupInterval) as unknown as number;\n\t}\n\n\t/**\n\t * Remove timed-out sessions.\n\t */\n\tprivate _cleanupTimedOutSessions(): void {\n\t\tlet cleaned = 0;\n\n\t\tfor (const [sessionId, session] of this._sessions.entries()) {\n\t\t\tif (session.isTimedOut()) {\n\t\t\t\tsession.close().catch((err) => {\n\t\t\t\t\tthis._logger.error(`Error closing timed out session ${sessionId}:`, err);\n\t\t\t\t});\n\t\t\t\tthis._sessions.delete(sessionId);\n\t\t\t\tcleaned++;\n\t\t\t}\n\t\t}\n\n\t\tif (cleaned > 0) {\n\t\t\tthis._logger.info(\n\t\t\t\t`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Close all sessions and stop the cleanup timer.\n\t */\n\tasync terminate(): Promise<void> {\n\t\tif (this._terminated) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._terminated = true;\n\n\t\t// Stop cleanup timer\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t\tthis._cleanupTimerId = null;\n\t\t}\n\n\t\t// Close all sessions\n\t\tconst closePromises = Array.from(this._sessions.values()).map((session) =>\n\t\t\tsession.close().catch((err) => {\n\t\t\t\tthis._logger.error(`Error closing session ${session.getInfo().id}:`, err);\n\t\t\t})\n\t\t);\n\n\t\tawait Promise.all(closePromises);\n\t\tthis._sessions.clear();\n\n\t\tthis._logger.info('ConnectionPool terminated');\n\t}\n\n\t/**\n\t * Dispose of the connection pool, releasing all resources.\n\t * Implements the IDisposable interface.\n\t * Delegates to terminate() for backward compatibility.\n\t */\n\tasync dispose(): Promise<void> {\n\t\tawait this.terminate();\n\t}\n\n\t/**\n\t * Check if the connection pool is active.\n\t */\n\tisRunning(): boolean {\n\t\treturn !this._terminated;\n\t}\n}\n\n/**\n * Create a connection pool with the given options.\n *\n * @param options - Connection pool configuration\n * @returns A configured connection pool\n *\n * @example\n * ```typescript\n * const pool = createConnectionPool({\n * maxSessions: 50,\n * sessionTimeout: 300000\n * });\n * ```\n */\nexport function createConnectionPool(options?: SessionOptions): ConnectionPool {\n\treturn new ConnectionPool(options);\n}\n"],"names":["Session","id","server","timeout","logger","Date","input","SessionNotActiveError","clearTimeout","setTimeout","err","ConnectionPool","Map","options","PoolTerminatedError","MaxSessionsReachedError","Error","resolveLock","Promise","resolve","sessionId","Math","session","SessionNotFoundError","Array","s","activeSessions","clearInterval","setInterval","cleaned","closePromises","createConnectionPool"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pool/ConnectionPool.js","sources":["../../src/pool/ConnectionPool.ts"],"sourcesContent":["/**\n * Connection Pool for managing concurrent user sessions.\n *\n * This module provides session management for multi-user scenarios,\n * allowing multiple concurrent clients to each have isolated state.\n *\n * @example\n * ```typescript\n * const pool = new ConnectionPool({\n * maxSessions: 100,\n * sessionTimeout: 300000 // 5 minutes\n * });\n *\n * const sessionId = await pool.createSession();\n * await pool.process(sessionId, thought);\n * await pool.closeSession(sessionId);\n * ```\n */\n\nimport type { ThoughtData } from '../core/thought.js';\nimport {\n\tMaxSessionsReachedError,\n\tPoolTerminatedError,\n\tSessionNotActiveError,\n\tSessionNotFoundError,\n} from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { ConnectionPoolStats, IConnectionPool } from './IConnectionPool.js';\n\nexport interface SessionOptions {\n\t/**\n\t * Maximum number of concurrent sessions\n\t * @default 100\n\t */\n\tmaxSessions?: number;\n\n\t/**\n\t * Logger instance\n\t */\n\tlogger?: Logger;\n\n\tserverFactory?: () => Promise<SessionServer>;\n\n\t/**\n\t * Session timeout in milliseconds\n\t * @default 300000 (5 minutes)\n\t */\n\tsessionTimeout?: number;\n\n\t/**\n\t * Whether to enable automatic session cleanup\n\t * @default true\n\t */\n\tautoCleanup?: boolean;\n\n\t/**\n\t * Cleanup interval in milliseconds\n\t * @default 60000 (1 minute)\n\t */\n\tcleanupInterval?: number;\n}\n\nexport interface SessionInfo {\n\tid: string;\n\tserver: SessionServer;\n\tcreatedAt: number;\n\tlastActivityAt: number;\n\tisActive: boolean;\n}\n\nexport interface SessionServer {\n\tprocessThought(input: ThoughtData): Promise<ProcessResult>;\n\tstop(): void | Promise<void>;\n}\n\n/**\n * Represents a content block in a process result.\n */\nexport type ContentBlock = { type: 'text'; text: string };\n\nexport interface ProcessResult {\n\tcontent: ContentBlock[];\n\tisError?: boolean;\n}\n\n/**\n * Represents a user session with its own server instance.\n */\nexport class Session {\n\tprivate _server: SessionServer;\n\tprivate _id: string;\n\tprivate _createdAt: number;\n\tprivate _lastActivityAt: number;\n\tprivate _isActiveValue: boolean;\n\tprivate _timeout: number;\n\tprivate _cleanupTimer: NodeJS.Timeout | null = null;\n\tprivate _logger: Logger;\n\n\tconstructor(id: string, server: SessionServer, timeout: number, logger: Logger) {\n\t\tthis._server = server;\n\t\tthis._id = id;\n\t\tthis._createdAt = Date.now();\n\t\tthis._lastActivityAt = this._createdAt;\n\t\tthis._isActiveValue = true;\n\t\tthis._timeout = timeout;\n\t\tthis._logger = logger;\n\n\t\t// Start session timeout timer\n\t\tthis._startTimeout();\n\t}\n\n\t/**\n\t * Check if the session is active.\n\t */\n\tget isActive(): boolean {\n\t\treturn this._isActiveValue;\n\t}\n\n\t/**\n\t * Process a thought through this session's server instance.\n\t */\n\tasync process(input: ThoughtData): Promise<ProcessResult> {\n\t\tif (!this.isActive) {\n\t\t\tthrow new SessionNotActiveError(this._id);\n\t\t}\n\n\t\t// Update last activity\n\t\tthis._lastActivityAt = Date.now();\n\n\t\t// Reset timeout timer\n\t\tthis._resetTimeout();\n\n\t\t// Process the thought\n\t\treturn this._server.processThought(input);\n\t}\n\n\t/**\n\t * Get session information.\n\t */\n\tgetInfo(): SessionInfo {\n\t\treturn {\n\t\t\tid: this._id,\n\t\t\tserver: this._server,\n\t\t\tcreatedAt: this._createdAt,\n\t\t\tlastActivityAt: this._lastActivityAt,\n\t\t\tisActive: this.isActive,\n\t\t};\n\t}\n\n\t/**\n\t * Check if the session has timed out.\n\t */\n\tisTimedOut(): boolean {\n\t\treturn Date.now() - this._lastActivityAt > this._timeout;\n\t}\n\n\t/**\n\t * Close the session and stop the server.\n\t */\n\tasync close(): Promise<void> {\n\t\tthis._isActiveValue = false;\n\n\t\t// Stop timeout timer\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t\tthis._cleanupTimer = null;\n\t\t}\n\n\t\t// Stop the server\n\t\tthis._server.stop();\n\t}\n\n\t/**\n\t * Start the session timeout timer.\n\t */\n\tprivate _startTimeout(): void {\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t}\n\n\t\tthis._cleanupTimer = setTimeout(() => {\n\t\t\tif (this.isTimedOut()) {\n\t\t\t\tthis._logger.warn(`Session ${this._id} timed out, closing`);\n\t\t\t\tthis.close().catch((err) => {\n\t\t\t\t\tthis._logger.error(`Error closing timed out session ${this._id}:`, err);\n\t\t\t\t});\n\t\t\t}\n\t\t}, this._timeout);\n\t}\n\n\t/**\n\t * Reset the timeout timer after activity.\n\t */\n\tprivate _resetTimeout(): void {\n\t\tthis._startTimeout();\n\t}\n}\n\n/**\n * ConnectionPool manages multiple concurrent user sessions.\n *\n * Each session has its own server instance with isolated state,\n * allowing multiple users to interact with the system simultaneously.\n */\nexport class ConnectionPool implements IConnectionPool {\n\tprivate _sessions: Map<string, Session> = new Map();\n\tprivate _createSessionLock: Promise<void> | null = null;\n\tprivate _maxSessions: number;\n\tprivate _sessionTimeout: number;\n\tprivate _autoCleanup: boolean;\n\tprivate _cleanupInterval: number;\n\tprivate _cleanupTimerId: number | null = null;\n\tprivate _terminated: boolean = false;\n\tprivate _logger: Logger;\n\tprivate _serverFactory: (() => Promise<SessionServer>) | null;\n\n\tconstructor(options: SessionOptions = {}) {\n\t\tthis._maxSessions = options.maxSessions ?? 100;\n\t\tthis._sessionTimeout = options.sessionTimeout ?? 300000; // 5 minutes\n\t\tthis._autoCleanup = options.autoCleanup ?? true;\n\t\tthis._cleanupInterval = options.cleanupInterval ?? 60000; // 1 minute\n\t\tthis._serverFactory = options.serverFactory ?? null;\n\t\tthis._logger = options.logger ?? this._createNoopLogger();\n\n\t\tif (this._autoCleanup) {\n\t\t\tthis._startCleanup();\n\t\t}\n\t}\n\n\t/**\n\t * Create a no-op logger when none is provided.\n\t */\n\tprivate _createNoopLogger(): Logger {\n\t\treturn {\n\t\t\tinfo: (): void => {},\n\t\t\twarn: (): void => {},\n\t\t\terror: (): void => {},\n\t\t\tdebug: (): void => {},\n\t\t\tsetLevel: (): void => {},\n\t\t\tgetLevel: (): 'info' => 'info',\n\t\t};\n\t}\n\n\t/**\n\t * Create a new session.\n\t *\n\t * @returns The session ID\n\t * @throws Error if max sessions reached\n\t */\n\tasync createSession(): Promise<string> {\n\t\twhile (this._createSessionLock) {\n\t\t\tawait this._createSessionLock;\n\t\t}\n\n\t\tif (this._terminated) {\n\t\t\tthrow new PoolTerminatedError();\n\t\t}\n\n\t\tif (this._sessions.size >= this._maxSessions) {\n\t\t\tthrow new MaxSessionsReachedError(this._maxSessions);\n\t\t}\n\n\t\tif (!this._serverFactory) {\n\t\t\tthrow new Error('ConnectionPool requires a serverFactory option to create sessions');\n\t\t}\n\n\t\tlet resolveLock!: () => void;\n\t\tthis._createSessionLock = new Promise<void>((resolve) => {\n\t\t\tresolveLock = resolve;\n\t\t});\n\n\t\ttry {\n\t\t\t// Generate unique session ID\n\t\t\tconst sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n\n\t\t\t// Create a new server instance for this session\n\t\t\tconst server = await this._serverFactory();\n\n\t\t\t// Create session\n\t\t\tconst session = new Session(sessionId, server, this._sessionTimeout, this._logger);\n\t\t\tthis._sessions.set(sessionId, session);\n\n\t\t\tthis._logger.info(\n\t\t\t\t`Created session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t\treturn sessionId;\n\t\t} finally {\n\t\t\tresolveLock();\n\t\t\tthis._createSessionLock = null;\n\t\t}\n\t}\n\n\t/**\n\t * Process a thought in the specified session.\n\t *\n\t * @param sessionId - The session ID\n\t * @param input - The thought data to process\n\t * @returns Promise with the processing result\n\t * @throws Error if session not found\n\t */\n\tasync process(sessionId: string, input: ThoughtData): Promise<ProcessResult> {\n\t\tconst session = this._sessions.get(sessionId);\n\n\t\tif (!session) {\n\t\t\tthrow new SessionNotFoundError(sessionId);\n\t\t}\n\n\t\treturn session.process(input);\n\t}\n\n\t/**\n\t * Close a session and release resources.\n\t *\n\t * @param sessionId - The session ID to close\n\t * @throws Error if session not found\n\t */\n\tasync closeSession(sessionId: string): Promise<void> {\n\t\tconst session = this._sessions.get(sessionId);\n\n\t\tif (!session) {\n\t\t\tthrow new SessionNotFoundError(sessionId);\n\t\t}\n\n\t\tawait session.close();\n\t\tthis._sessions.delete(sessionId);\n\n\t\tthis._logger.info(\n\t\t\t`Closed session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t);\n\t}\n\n\t/**\n\t * Get information about a session.\n\t *\n\t * @param sessionId - The session ID\n\t * @returns Session info or undefined if not found\n\t */\n\tgetSessionInfo(sessionId: string): SessionInfo | undefined {\n\t\treturn this._sessions.get(sessionId)?.getInfo();\n\t}\n\n\t/**\n\t * Get all active sessions.\n\t *\n\t * @returns Array of session information\n\t */\n\tgetActiveSessions(): SessionInfo[] {\n\t\treturn Array.from(this._sessions.values())\n\t\t\t.filter((s) => s.isActive)\n\t\t\t.map((s) => s.getInfo());\n\t}\n\n\t/**\n\t * Get connection pool statistics.\n\t */\n\tgetStats(): ConnectionPoolStats {\n\t\tconst activeSessions = this.getActiveSessions();\n\n\t\treturn {\n\t\t\ttotalSessions: this._sessions.size,\n\t\t\tactiveSessions: activeSessions.length,\n\t\t\tmaxSessions: this._maxSessions,\n\t\t\tcleanupEnabled: this._autoCleanup,\n\t\t\tsessionTimeout: this._sessionTimeout,\n\t\t};\n\t}\n\n\t/**\n\t * Start the automatic cleanup timer.\n\t */\n\tprivate _startCleanup(): void {\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t}\n\n\t\tthis._cleanupTimerId = setInterval(() => {\n\t\t\tthis._cleanupTimedOutSessions();\n\t\t}, this._cleanupInterval) as unknown as number;\n\t}\n\n\t/**\n\t * Remove timed-out sessions.\n\t */\n\tprivate _cleanupTimedOutSessions(): void {\n\t\tlet cleaned = 0;\n\n\t\tfor (const [sessionId, session] of this._sessions.entries()) {\n\t\t\tif (session.isTimedOut()) {\n\t\t\t\tsession.close().catch((err) => {\n\t\t\t\t\tthis._logger.error(`Error closing timed out session ${sessionId}:`, err);\n\t\t\t\t});\n\t\t\t\tthis._sessions.delete(sessionId);\n\t\t\t\tcleaned++;\n\t\t\t}\n\t\t}\n\n\t\tif (cleaned > 0) {\n\t\t\tthis._logger.info(\n\t\t\t\t`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Close all sessions and stop the cleanup timer.\n\t */\n\tasync terminate(): Promise<void> {\n\t\tif (this._terminated) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._terminated = true;\n\n\t\t// Stop cleanup timer\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t\tthis._cleanupTimerId = null;\n\t\t}\n\n\t\t// Close all sessions\n\t\tconst closePromises = Array.from(this._sessions.values()).map((session) =>\n\t\t\tsession.close().catch((err) => {\n\t\t\t\tthis._logger.error(`Error closing session ${session.getInfo().id}:`, err);\n\t\t\t})\n\t\t);\n\n\t\tawait Promise.all(closePromises);\n\t\tthis._sessions.clear();\n\n\t\tthis._logger.info('ConnectionPool terminated');\n\t}\n\n\t/**\n\t * Dispose of the connection pool, releasing all resources.\n\t * Implements the IDisposable interface.\n\t * Delegates to terminate() for backward compatibility.\n\t */\n\tasync dispose(): Promise<void> {\n\t\tawait this.terminate();\n\t}\n\n\t/**\n\t * Check if the connection pool is active.\n\t */\n\tisRunning(): boolean {\n\t\treturn !this._terminated;\n\t}\n}\n\n/**\n * Create a connection pool with the given options.\n *\n * @param options - Connection pool configuration\n * @returns A configured connection pool\n *\n * @example\n * ```typescript\n * const pool = createConnectionPool({\n * maxSessions: 50,\n * sessionTimeout: 300000\n * });\n * ```\n */\nexport function createConnectionPool(options?: SessionOptions): ConnectionPool {\n\treturn new ConnectionPool(options);\n}\n"],"names":["Session","id","server","timeout","logger","Date","input","SessionNotActiveError","clearTimeout","setTimeout","err","ConnectionPool","Map","options","PoolTerminatedError","MaxSessionsReachedError","Error","resolveLock","Promise","resolve","sessionId","Math","session","SessionNotFoundError","Array","s","activeSessions","clearInterval","setInterval","cleaned","closePromises","createConnectionPool"],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for the connection pool managing concurrent user sessions.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the `IConnectionPool` interface which defines the
|
|
5
|
+
* contract for connection pool implementations. This allows for decoupling
|
|
6
|
+
* and testability for multi-user transports.
|
|
7
|
+
*
|
|
8
|
+
* @module IConnectionPool
|
|
9
|
+
*/
|
|
10
|
+
import type { ThoughtData } from '../core/thought.js';
|
|
11
|
+
import type { IDisposable } from '../types/disposable.js';
|
|
12
|
+
import type { ProcessResult, SessionInfo } from './ConnectionPool.js';
|
|
13
|
+
/**
|
|
14
|
+
* Statistics describing the current state of the connection pool.
|
|
15
|
+
*/
|
|
16
|
+
export interface ConnectionPoolStats {
|
|
17
|
+
totalSessions: number;
|
|
18
|
+
activeSessions: number;
|
|
19
|
+
maxSessions: number;
|
|
20
|
+
cleanupEnabled: boolean;
|
|
21
|
+
sessionTimeout: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Interface for the connection pool.
|
|
25
|
+
*
|
|
26
|
+
* This interface defines the contract for managing multiple concurrent
|
|
27
|
+
* user sessions, each with its own isolated server instance. Supports
|
|
28
|
+
* dependency injection and mocking for testing purposes.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* class MockPool implements IConnectionPool {
|
|
33
|
+
* async createSession(): Promise<string> { return 'mock'; }
|
|
34
|
+
* // ...
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export interface IConnectionPool extends IDisposable {
|
|
39
|
+
/**
|
|
40
|
+
* Create a new session.
|
|
41
|
+
*
|
|
42
|
+
* @returns The new session ID
|
|
43
|
+
* @throws PoolTerminatedError if the pool has been terminated
|
|
44
|
+
* @throws MaxSessionsReachedError if the maximum number of sessions is reached
|
|
45
|
+
*/
|
|
46
|
+
createSession(): Promise<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Process a thought in the specified session.
|
|
49
|
+
*
|
|
50
|
+
* @param sessionId - The session ID
|
|
51
|
+
* @param input - The thought data to process
|
|
52
|
+
* @returns The processing result
|
|
53
|
+
* @throws SessionNotFoundError if the session does not exist
|
|
54
|
+
*/
|
|
55
|
+
process(sessionId: string, input: ThoughtData): Promise<ProcessResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Close a session and release its resources.
|
|
58
|
+
*
|
|
59
|
+
* @param sessionId - The session ID to close
|
|
60
|
+
* @throws SessionNotFoundError if the session does not exist
|
|
61
|
+
*/
|
|
62
|
+
closeSession(sessionId: string): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Get information about a session.
|
|
65
|
+
*
|
|
66
|
+
* @param sessionId - The session ID
|
|
67
|
+
* @returns Session info, or undefined if not found
|
|
68
|
+
*/
|
|
69
|
+
getSessionInfo(sessionId: string): SessionInfo | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Get all active sessions.
|
|
72
|
+
*
|
|
73
|
+
* @returns Array of session information for currently active sessions
|
|
74
|
+
*/
|
|
75
|
+
getActiveSessions(): SessionInfo[];
|
|
76
|
+
/**
|
|
77
|
+
* Get connection pool statistics.
|
|
78
|
+
*
|
|
79
|
+
* @returns A snapshot of the pool's statistics
|
|
80
|
+
*/
|
|
81
|
+
getStats(): ConnectionPoolStats;
|
|
82
|
+
/**
|
|
83
|
+
* Close all sessions and stop the cleanup timer.
|
|
84
|
+
*/
|
|
85
|
+
terminate(): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Dispose of the connection pool, releasing all resources.
|
|
88
|
+
*
|
|
89
|
+
* Implements the {@link IDisposable} interface. Typically delegates
|
|
90
|
+
* to {@link IConnectionPool.terminate}.
|
|
91
|
+
*/
|
|
92
|
+
dispose(): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Check if the connection pool is active (not terminated).
|
|
95
|
+
*
|
|
96
|
+
* @returns true if the pool is still running
|
|
97
|
+
*/
|
|
98
|
+
isRunning(): boolean;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=IConnectionPool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/IConnectionPool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IACnD;;;;;;OAMG;IACH,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjC;;;;;;;OAOG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEvE;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C;;;;;OAKG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IAE3D;;;;OAIG;IACH,iBAAiB,IAAI,WAAW,EAAE,CAAC;IAEnC;;;;OAIG;IACH,QAAQ,IAAI,mBAAmB,CAAC;IAEhC;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3B;;;;;OAKG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;;OAIG;IACH,SAAS,IAAI,OAAO,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -97,7 +97,7 @@ export declare abstract class BaseRegistry<T extends {
|
|
|
97
97
|
* The entity name used in log messages (e.g., 'tool', 'skill').
|
|
98
98
|
*/
|
|
99
99
|
protected abstract readonly _entityName: string;
|
|
100
|
-
constructor(options: BaseRegistryOptions
|
|
100
|
+
constructor(options: BaseRegistryOptions);
|
|
101
101
|
/**
|
|
102
102
|
* Internal logging method.
|
|
103
103
|
* @param message - The message to log
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/BaseRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAG5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kCAAkC;IAClC,KAAK,CAAC,EAAE,cAAc,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAEzC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,8BAAsB,YAAY,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;IAC5D,kDAAkD;IAClD,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEjC,8BAA8B;IAC9B,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAE1B,kCAAkC;IAClC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAEpC,2CAA2C;IAC3C,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAEhC,4CAA4C;IAC5C,SAAS,CAAC,WAAW,EAAE,OAAO,CAAS;IAEvC,mEAAmE;IACnE,SAAS,CAAC,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAQ;IAE3D,iDAAiD;IACjD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IAEtD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;IAE7D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAE7D;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK;IAE5E;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAEvF;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAE7D;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI;IAE3D;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEpC,OAAO,EAAE,mBAAmB
|
|
1
|
+
{"version":3,"file":"BaseRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/BaseRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAG5D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kCAAkC;IAClC,KAAK,CAAC,EAAE,cAAc,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAEzC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,8BAAsB,YAAY,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;IAC5D,kDAAkD;IAClD,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEjC,8BAA8B;IAC9B,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAE1B,kCAAkC;IAClC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAEpC,2CAA2C;IAC3C,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAEhC,4CAA4C;IAC5C,SAAS,CAAC,WAAW,EAAE,OAAO,CAAS;IAEvC,mEAAmE;IACnE,SAAS,CAAC,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAQ;IAE3D,iDAAiD;IACjD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IAEtD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;IAE7D;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAE7D;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK;IAE5E;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAEvF;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAE7D;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI;IAE3D;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEpC,OAAO,EAAE,mBAAmB;IAQxC;;;;OAIG;IACH,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIpE;;;;;OAKG;IACI,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAazB;;;;;OAKG;IACI,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWjC;;;;;;OAMG;IACI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IAatD;;;;;OAKG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAIvC;;;;;;OAMG;IACI,MAAM,IAAI,CAAC,EAAE;IAepB;;;;;OAKG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;;;OAIG;IACI,QAAQ,IAAI,MAAM,EAAE;IAI3B;;OAEG;IACI,KAAK,IAAI,IAAI;IAOpB;;;;OAIG;IACI,IAAI,IAAI,MAAM;IAIrB;;;;;;;OAOG;IACU,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAuB7C;;;;;;;OAOG;cACa,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAwDpD;;;;;;;OAOG;IACH,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAQ9E;;;;;;OAMG;IACI,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI;CAgB/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry/BaseRegistry.js","sources":["../../src/registry/BaseRegistry.ts"],"sourcesContent":["/**\n * Base registry providing shared CRUD, caching, and discovery logic.\n *\n * This abstract generic class extracts the common patterns from `ToolRegistry`\n * and `SkillRegistry` into a single reusable base. Subclasses only need to\n * implement item-specific parsing, file filtering, and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n * @module registry\n */\n\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { getErrorMessage } from '../errors.js';\n\n/**\n * Configuration options for creating a `BaseRegistry` instance.\n */\nexport interface BaseRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for lookups. */\n\tcache?: DiscoveryCache<{ name: string }>;\n\n\t/**\n\t * Directory paths to search for items.\n\t */\n\tsearchDirs?: string[];\n\n\t/**\n\t * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\n/**\n * Abstract base registry for managing named items with discovery and caching.\n *\n * Provides shared CRUD operations, filesystem discovery with deduplication,\n * and optional LRU caching. Subclasses implement item-specific parsing logic\n * and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n */\nexport abstract class BaseRegistry<T extends { name: string }> {\n\t/** Internal storage for items indexed by name. */\n\tprotected _items: Map<string, T>;\n\n\t/** Logger for diagnostics. */\n\tprotected _logger: Logger;\n\n\t/** Optional cache for lookups. */\n\tprotected _cache: DiscoveryCache<T>;\n\n\t/** Directory paths to search for items. */\n\tprotected _searchDirs: string[];\n\n\t/** Whether discovery has been performed. */\n\tprotected _discovered: boolean = false;\n\n\t/** Promise for in-progress discovery (null if not in progress). */\n\tprotected _discoveryPromise: Promise<number> | null = null;\n\n\t/** File extensions to match during discovery. */\n\tprotected abstract readonly _fileExtensions: string[];\n\n\t/**\n\t * Creates an error for invalid item data.\n\t * @param reason - The reason for the validation failure\n\t */\n\tprotected abstract _createInvalidError(reason: string): Error;\n\n\t/**\n\t * Creates an error for duplicate items.\n\t * @param name - The name of the duplicate item\n\t */\n\tprotected abstract _createDuplicateError(name: string): Error;\n\n\t/**\n\t * Creates an error for items not found.\n\t * @param name - The name of the missing item\n\t * @param action - The action that was attempted\n\t */\n\tprotected abstract _createNotFoundError(name: string, action: string): Error;\n\n\t/**\n\t * Parses frontmatter content into a partial item.\n\t * @param content - The file content to parse\n\t * @returns A partial item, with an `_error` property if parsing failed\n\t */\n\tprotected abstract _parseFrontmatter(content: string): Partial<T> & { _error?: string };\n\n\t/**\n\t * Determines whether a file should be skipped during discovery.\n\t * @param fileName - The name of the file to check\n\t * @returns true if the file should be skipped\n\t */\n\tprotected abstract _shouldSkipFile(fileName: string): boolean;\n\n\t/**\n\t * Constructs a complete item from parsed frontmatter data.\n\t * Returns null if the parsed data is insufficient.\n\t * @param parsed - The parsed frontmatter data\n\t * @returns A complete item, or null if data is insufficient\n\t */\n\tprotected abstract _buildItem(parsed: Partial<T>): T | null;\n\n\t/**\n\t * The entity name used in log messages (e.g., 'tool', 'skill').\n\t */\n\tprotected abstract readonly _entityName: string;\n\n\tconstructor(options: BaseRegistryOptions & Record<string, unknown>) {\n\t\tthis._items = new Map();\n\t\tthis._logger = (options.logger ?? new NullLogger()) as Logger;\n\t\tthis._cache = (options.cache ||\n\t\t\tnew DiscoveryCache<T>({ maxSize: 50, ttl: 300000 })) as DiscoveryCache<T>;\n\t\tthis._searchDirs = (options.searchDirs ?? []) as string[];\n\t}\n\n\t/**\n\t * Internal logging method.\n\t * @param message - The message to log\n\t * @param meta - Optional metadata\n\t */\n\tprotected log(message: string, meta?: Record<string, unknown>): void {\n\t\tthis._logger.info(message, meta);\n\t}\n\n\t/**\n\t * Adds an item to the registry.\n\t *\n\t * @param item - The item to add\n\t * @throws If item already exists or name is invalid\n\t */\n\tpublic add(item: T): void {\n\t\tif (!item.name) {\n\t\t\tthrow this._createInvalidError(`${this._entityName} must have a valid name`);\n\t\t}\n\t\tif (this._items.has(item.name)) {\n\t\t\tthrow this._createDuplicateError(item.name);\n\t\t}\n\t\tthis._items.set(item.name, item);\n\t\tthis.log(`Added ${this._entityName}: ${item.name}`, { [`${this._entityName}Name`]: item.name });\n\t\t// Invalidate cache when adding a new item\n\t\tthis._cache?.invalidate('all');\n\t}\n\n\t/**\n\t * Removes an item from the registry.\n\t *\n\t * @param name - The name of the item to remove\n\t * @throws If item not found\n\t */\n\tpublic remove(name: string): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'remove');\n\t\t}\n\t\tthis._items.delete(name);\n\t\tthis.log(`Removed ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when removing an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Updates an existing item with partial data.\n\t *\n\t * @param name - The name of the item to update\n\t * @param updates - Partial item data with fields to update\n\t * @throws If item not found\n\t */\n\tpublic update(name: string, updates: Partial<T>): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'update');\n\t\t}\n\t\tconst existing = this._items.get(name)!;\n\t\tconst updated = { ...existing, ...updates };\n\t\tthis._items.set(name, updated);\n\t\tthis.log(`Updated ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when updating an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Gets an item by name.\n\t *\n\t * @param name - The name of the item to get\n\t * @returns The item if found, undefined otherwise\n\t */\n\tpublic get(name: string): T | undefined {\n\t\treturn this._items.get(name);\n\t}\n\n\t/**\n\t * Gets all items as an array.\n\t *\n\t * Uses cache if available for performance.\n\t *\n\t * @returns An array of all registered items\n\t */\n\tpublic getAll(): T[] {\n\t\t// Check cache first\n\t\tif (this._cache) {\n\t\t\tconst cached = this._cache.get('all');\n\t\t\tif (cached) {\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t}\n\t\t// Get from storage\n\t\tconst items = Array.from(this._items.values());\n\t\t// Cache the result\n\t\tthis._cache?.set('all', items);\n\t\treturn items;\n\t}\n\n\t/**\n\t * Checks if an item exists in the registry.\n\t *\n\t * @param name - The name of the item to check\n\t * @returns true if the item exists, false otherwise\n\t */\n\tpublic has(name: string): boolean {\n\t\treturn this._items.has(name);\n\t}\n\n\t/**\n\t * Gets all item names as an array.\n\t *\n\t * @returns An array of item names\n\t */\n\tpublic getNames(): string[] {\n\t\treturn Array.from(this._items.keys());\n\t}\n\n\t/**\n\t * Clears all items from the registry.\n\t */\n\tpublic clear(): void {\n\t\tthis._items.clear();\n\t\tthis.log(`Cleared all ${this._entityName}s`);\n\t\t// Invalidate cache when clearing all items\n\t\tthis._cache?.clear();\n\t}\n\n\t/**\n\t * Gets the number of items in the registry.\n\t *\n\t * @returns The count of registered items\n\t */\n\tpublic size(): number {\n\t\treturn this._items.size;\n\t}\n\n\t/**\n\t * Asynchronously discovers items from the configured directories.\n\t *\n\t * Multiple concurrent calls share the same discovery promise.\n\t * Subsequent calls return cached results if discovery has already completed.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tpublic async discoverAsync(): Promise<number> {\n\t\t// Return existing promise if discovery is in progress\n\t\tif (this._discoveryPromise) {\n\t\t\treturn this._discoveryPromise;\n\t\t}\n\n\t\t// Use cached results if already discovered\n\t\tif (this._discovered) {\n\t\t\tconst cached = this._cache.get('all');\n\t\t\treturn cached?.length ?? 0;\n\t\t}\n\n\t\t// Create discovery promise\n\t\tthis._discoveryPromise = this._performDiscovery();\n\n\t\ttry {\n\t\t\tconst count = await this._discoveryPromise;\n\t\t\treturn count;\n\t\t} finally {\n\t\t\tthis._discoveryPromise = null;\n\t\t}\n\t}\n\n\t/**\n\t * Performs the actual discovery operation.\n\t *\n\t * Scans configured directories for item files, parses their frontmatter,\n\t * and adds valid items to the registry.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tprotected async _performDiscovery(): Promise<number> {\n\t\tlet discoveredCount = 0;\n\n\t\tfor (const dir of this._searchDirs) {\n\t\t\ttry {\n\t\t\t\tif (!existsSync(dir)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst entries = await readdir(dir, { withFileTypes: true });\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tif (this._shouldSkipFile(entry.name)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (entry.isFile() && this._fileExtensions.some((ext) => entry.name.endsWith(ext))) {\n\t\t\t\t\t\tconst filePath = join(dir, entry.name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst content = await readFile(filePath, 'utf-8');\n\t\t\t\t\t\t\tconst parsed = this._parseFrontmatter(content);\n\t\t\t\t\t\t\tif (parsed._error) {\n\t\t\t\t\t\t\t\tthis.log(`Skipped ${entry.name}: ${parsed._error}`);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (parsed.name) {\n\t\t\t\t\t\t\t\t// Check if already exists before adding\n\t\t\t\t\t\t\t\tif (!this._items.has(parsed.name)) {\n\t\t\t\t\t\t\t\t\tconst item = this._buildItem(parsed);\n\t\t\t\t\t\t\t\t\tif (item) {\n\t\t\t\t\t\t\t\t\t\tthis._items.set(item.name, item);\n\t\t\t\t\t\t\t\t\t\tdiscoveredCount++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (readError) {\n\t\t\t\t\t\t\tthis.log(`Failed to read ${this._entityName} file ${entry.name}`, {\n\t\t\t\t\t\t\t\terror: getErrorMessage(readError),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.log(`Failed to scan ${this._entityName} directory: ${dir}`, {\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis._discovered = true;\n\t\tthis._cache?.set('all', Array.from(this._items.values()));\n\t\tthis.log(`Discovery complete: found ${discoveredCount} ${this._entityName}s`, {\n\t\t\tdiscoveredCount,\n\t\t});\n\t\treturn discoveredCount;\n\t}\n\n\t/**\n\t * Parses YAML frontmatter from file content.\n\t *\n\t * This is a shared utility for subclasses that parse YAML frontmatter.\n\t *\n\t * @param content - The file content to parse\n\t * @returns The parsed YAML object, or null if no frontmatter found\n\t */\n\tprotected _extractFrontmatter(content: string): Record<string, unknown> | null {\n\t\tconst match = content.match(/^---\\n([\\s\\S]+?)\\n---/);\n\t\tif (!match) {\n\t\t\treturn null;\n\t\t}\n\t\treturn parseYaml(match[1]!) as Record<string, unknown>;\n\t}\n\n\t/**\n\t * Sets items from an external source.\n\t *\n\t * Clears existing items and adds new ones from the provided array.\n\t *\n\t * @param items - Array of items from an external source\n\t */\n\tpublic setAll(items: T[]): void {\n\t\tthis.clear();\n\t\tfor (const item of items) {\n\t\t\ttry {\n\t\t\t\tthis.add(item);\n\t\t\t} catch (error) {\n\t\t\t\tthis.log(`Error adding ${this._entityName} '${item.name}':`, {\n\t\t\t\t\t[`${this._entityName}Name`]: item.name,\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.log(`Set ${items.length} ${this._entityName}s from external source`, {\n\t\t\t[`${this._entityName}Count`]: items.length,\n\t\t});\n\t}\n}\n"],"names":["BaseRegistry","options","Map","NullLogger","DiscoveryCache","message","meta","item","name","updates","existing","updated","cached","items","Array","count","discoveredCount","dir","existsSync","entries","readdir","entry","ext","filePath","join","content","readFile","parsed","readError","getErrorMessage","error","match","parseYaml"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"registry/BaseRegistry.js","sources":["../../src/registry/BaseRegistry.ts"],"sourcesContent":["/**\n * Base registry providing shared CRUD, caching, and discovery logic.\n *\n * This abstract generic class extracts the common patterns from `ToolRegistry`\n * and `SkillRegistry` into a single reusable base. Subclasses only need to\n * implement item-specific parsing, file filtering, and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n * @module registry\n */\n\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { getErrorMessage } from '../errors.js';\n\n/**\n * Configuration options for creating a `BaseRegistry` instance.\n */\nexport interface BaseRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for lookups. */\n\tcache?: DiscoveryCache<{ name: string }>;\n\n\t/**\n\t * Directory paths to search for items.\n\t */\n\tsearchDirs?: string[];\n\n\t/**\n\t * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\n/**\n * Abstract base registry for managing named items with discovery and caching.\n *\n * Provides shared CRUD operations, filesystem discovery with deduplication,\n * and optional LRU caching. Subclasses implement item-specific parsing logic\n * and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n */\nexport abstract class BaseRegistry<T extends { name: string }> {\n\t/** Internal storage for items indexed by name. */\n\tprotected _items: Map<string, T>;\n\n\t/** Logger for diagnostics. */\n\tprotected _logger: Logger;\n\n\t/** Optional cache for lookups. */\n\tprotected _cache: DiscoveryCache<T>;\n\n\t/** Directory paths to search for items. */\n\tprotected _searchDirs: string[];\n\n\t/** Whether discovery has been performed. */\n\tprotected _discovered: boolean = false;\n\n\t/** Promise for in-progress discovery (null if not in progress). */\n\tprotected _discoveryPromise: Promise<number> | null = null;\n\n\t/** File extensions to match during discovery. */\n\tprotected abstract readonly _fileExtensions: string[];\n\n\t/**\n\t * Creates an error for invalid item data.\n\t * @param reason - The reason for the validation failure\n\t */\n\tprotected abstract _createInvalidError(reason: string): Error;\n\n\t/**\n\t * Creates an error for duplicate items.\n\t * @param name - The name of the duplicate item\n\t */\n\tprotected abstract _createDuplicateError(name: string): Error;\n\n\t/**\n\t * Creates an error for items not found.\n\t * @param name - The name of the missing item\n\t * @param action - The action that was attempted\n\t */\n\tprotected abstract _createNotFoundError(name: string, action: string): Error;\n\n\t/**\n\t * Parses frontmatter content into a partial item.\n\t * @param content - The file content to parse\n\t * @returns A partial item, with an `_error` property if parsing failed\n\t */\n\tprotected abstract _parseFrontmatter(content: string): Partial<T> & { _error?: string };\n\n\t/**\n\t * Determines whether a file should be skipped during discovery.\n\t * @param fileName - The name of the file to check\n\t * @returns true if the file should be skipped\n\t */\n\tprotected abstract _shouldSkipFile(fileName: string): boolean;\n\n\t/**\n\t * Constructs a complete item from parsed frontmatter data.\n\t * Returns null if the parsed data is insufficient.\n\t * @param parsed - The parsed frontmatter data\n\t * @returns A complete item, or null if data is insufficient\n\t */\n\tprotected abstract _buildItem(parsed: Partial<T>): T | null;\n\n\t/**\n\t * The entity name used in log messages (e.g., 'tool', 'skill').\n\t */\n\tprotected abstract readonly _entityName: string;\n\n\tconstructor(options: BaseRegistryOptions) {\n\t\tthis._items = new Map();\n\t\tthis._logger = (options.logger ?? new NullLogger()) as Logger;\n\t\tthis._cache = (options.cache ||\n\t\t\tnew DiscoveryCache<T>({ maxSize: 50, ttl: 300000 })) as DiscoveryCache<T>;\n\t\tthis._searchDirs = (options.searchDirs ?? []) as string[];\n\t}\n\n\t/**\n\t * Internal logging method.\n\t * @param message - The message to log\n\t * @param meta - Optional metadata\n\t */\n\tprotected log(message: string, meta?: Record<string, unknown>): void {\n\t\tthis._logger.info(message, meta);\n\t}\n\n\t/**\n\t * Adds an item to the registry.\n\t *\n\t * @param item - The item to add\n\t * @throws If item already exists or name is invalid\n\t */\n\tpublic add(item: T): void {\n\t\tif (!item.name) {\n\t\t\tthrow this._createInvalidError(`${this._entityName} must have a valid name`);\n\t\t}\n\t\tif (this._items.has(item.name)) {\n\t\t\tthrow this._createDuplicateError(item.name);\n\t\t}\n\t\tthis._items.set(item.name, item);\n\t\tthis.log(`Added ${this._entityName}: ${item.name}`, { [`${this._entityName}Name`]: item.name });\n\t\t// Invalidate cache when adding a new item\n\t\tthis._cache?.invalidate('all');\n\t}\n\n\t/**\n\t * Removes an item from the registry.\n\t *\n\t * @param name - The name of the item to remove\n\t * @throws If item not found\n\t */\n\tpublic remove(name: string): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'remove');\n\t\t}\n\t\tthis._items.delete(name);\n\t\tthis.log(`Removed ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when removing an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Updates an existing item with partial data.\n\t *\n\t * @param name - The name of the item to update\n\t * @param updates - Partial item data with fields to update\n\t * @throws If item not found\n\t */\n\tpublic update(name: string, updates: Partial<T>): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'update');\n\t\t}\n\t\tconst existing = this._items.get(name)!;\n\t\tconst updated = { ...existing, ...updates };\n\t\tthis._items.set(name, updated);\n\t\tthis.log(`Updated ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when updating an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Gets an item by name.\n\t *\n\t * @param name - The name of the item to get\n\t * @returns The item if found, undefined otherwise\n\t */\n\tpublic get(name: string): T | undefined {\n\t\treturn this._items.get(name);\n\t}\n\n\t/**\n\t * Gets all items as an array.\n\t *\n\t * Uses cache if available for performance.\n\t *\n\t * @returns An array of all registered items\n\t */\n\tpublic getAll(): T[] {\n\t\t// Check cache first\n\t\tif (this._cache) {\n\t\t\tconst cached = this._cache.get('all');\n\t\t\tif (cached) {\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t}\n\t\t// Get from storage\n\t\tconst items = Array.from(this._items.values());\n\t\t// Cache the result\n\t\tthis._cache?.set('all', items);\n\t\treturn items;\n\t}\n\n\t/**\n\t * Checks if an item exists in the registry.\n\t *\n\t * @param name - The name of the item to check\n\t * @returns true if the item exists, false otherwise\n\t */\n\tpublic has(name: string): boolean {\n\t\treturn this._items.has(name);\n\t}\n\n\t/**\n\t * Gets all item names as an array.\n\t *\n\t * @returns An array of item names\n\t */\n\tpublic getNames(): string[] {\n\t\treturn Array.from(this._items.keys());\n\t}\n\n\t/**\n\t * Clears all items from the registry.\n\t */\n\tpublic clear(): void {\n\t\tthis._items.clear();\n\t\tthis.log(`Cleared all ${this._entityName}s`);\n\t\t// Invalidate cache when clearing all items\n\t\tthis._cache?.clear();\n\t}\n\n\t/**\n\t * Gets the number of items in the registry.\n\t *\n\t * @returns The count of registered items\n\t */\n\tpublic size(): number {\n\t\treturn this._items.size;\n\t}\n\n\t/**\n\t * Asynchronously discovers items from the configured directories.\n\t *\n\t * Multiple concurrent calls share the same discovery promise.\n\t * Subsequent calls return cached results if discovery has already completed.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tpublic async discoverAsync(): Promise<number> {\n\t\t// Return existing promise if discovery is in progress\n\t\tif (this._discoveryPromise) {\n\t\t\treturn this._discoveryPromise;\n\t\t}\n\n\t\t// Use cached results if already discovered\n\t\tif (this._discovered) {\n\t\t\tconst cached = this._cache.get('all');\n\t\t\treturn cached?.length ?? 0;\n\t\t}\n\n\t\t// Create discovery promise\n\t\tthis._discoveryPromise = this._performDiscovery();\n\n\t\ttry {\n\t\t\tconst count = await this._discoveryPromise;\n\t\t\treturn count;\n\t\t} finally {\n\t\t\tthis._discoveryPromise = null;\n\t\t}\n\t}\n\n\t/**\n\t * Performs the actual discovery operation.\n\t *\n\t * Scans configured directories for item files, parses their frontmatter,\n\t * and adds valid items to the registry.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tprotected async _performDiscovery(): Promise<number> {\n\t\tlet discoveredCount = 0;\n\n\t\tfor (const dir of this._searchDirs) {\n\t\t\ttry {\n\t\t\t\tif (!existsSync(dir)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst entries = await readdir(dir, { withFileTypes: true });\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tif (this._shouldSkipFile(entry.name)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (entry.isFile() && this._fileExtensions.some((ext) => entry.name.endsWith(ext))) {\n\t\t\t\t\t\tconst filePath = join(dir, entry.name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst content = await readFile(filePath, 'utf-8');\n\t\t\t\t\t\t\tconst parsed = this._parseFrontmatter(content);\n\t\t\t\t\t\t\tif (parsed._error) {\n\t\t\t\t\t\t\t\tthis.log(`Skipped ${entry.name}: ${parsed._error}`);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (parsed.name) {\n\t\t\t\t\t\t\t\t// Check if already exists before adding\n\t\t\t\t\t\t\t\tif (!this._items.has(parsed.name)) {\n\t\t\t\t\t\t\t\t\tconst item = this._buildItem(parsed);\n\t\t\t\t\t\t\t\t\tif (item) {\n\t\t\t\t\t\t\t\t\t\tthis._items.set(item.name, item);\n\t\t\t\t\t\t\t\t\t\tdiscoveredCount++;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (readError) {\n\t\t\t\t\t\t\tthis.log(`Failed to read ${this._entityName} file ${entry.name}`, {\n\t\t\t\t\t\t\t\terror: getErrorMessage(readError),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.log(`Failed to scan ${this._entityName} directory: ${dir}`, {\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis._discovered = true;\n\t\tthis._cache?.set('all', Array.from(this._items.values()));\n\t\tthis.log(`Discovery complete: found ${discoveredCount} ${this._entityName}s`, {\n\t\t\tdiscoveredCount,\n\t\t});\n\t\treturn discoveredCount;\n\t}\n\n\t/**\n\t * Parses YAML frontmatter from file content.\n\t *\n\t * This is a shared utility for subclasses that parse YAML frontmatter.\n\t *\n\t * @param content - The file content to parse\n\t * @returns The parsed YAML object, or null if no frontmatter found\n\t */\n\tprotected _extractFrontmatter(content: string): Record<string, unknown> | null {\n\t\tconst match = content.match(/^---\\n([\\s\\S]+?)\\n---/);\n\t\tif (!match) {\n\t\t\treturn null;\n\t\t}\n\t\treturn parseYaml(match[1]!) as Record<string, unknown>;\n\t}\n\n\t/**\n\t * Sets items from an external source.\n\t *\n\t * Clears existing items and adds new ones from the provided array.\n\t *\n\t * @param items - Array of items from an external source\n\t */\n\tpublic setAll(items: T[]): void {\n\t\tthis.clear();\n\t\tfor (const item of items) {\n\t\t\ttry {\n\t\t\t\tthis.add(item);\n\t\t\t} catch (error) {\n\t\t\t\tthis.log(`Error adding ${this._entityName} '${item.name}':`, {\n\t\t\t\t\t[`${this._entityName}Name`]: item.name,\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.log(`Set ${items.length} ${this._entityName}s from external source`, {\n\t\t\t[`${this._entityName}Count`]: items.length,\n\t\t});\n\t}\n}\n"],"names":["BaseRegistry","options","Map","NullLogger","DiscoveryCache","message","meta","item","name","updates","existing","updated","cached","items","Array","count","discoveredCount","dir","existsSync","entries","readdir","entry","ext","filePath","join","content","readFile","parsed","readError","getErrorMessage","error","match","parseYaml"],"mappings":"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"}
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAiH5C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;aAkBnC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;aA4BpC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAanC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;aAsB1C,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAe1C,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA0LnC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,wBAAwB,EAAE,IAItC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB;;;;;aAmB/B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,cAAc,kWASW,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAiH5C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;aAkBnC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;aA4BpC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAanC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;aAsB1C,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAe1C,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA0LnC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,wBAAwB,EAAE,IAItC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB;;;;;aAmB/B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,cAAc,kWASW,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;aAQmH,CAAC"}
|