tracelattice 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +112 -0
  3. package/dist/ServerConfig.d.ts +229 -0
  4. package/dist/ServerConfig.d.ts.map +1 -0
  5. package/dist/ServerConfig.js +121 -0
  6. package/dist/ServerConfig.js.map +1 -0
  7. package/dist/__tests__/base-registry.test.d.ts +2 -0
  8. package/dist/__tests__/base-registry.test.d.ts.map +1 -0
  9. package/dist/__tests__/base-transport-cov.test.d.ts +2 -0
  10. package/dist/__tests__/base-transport-cov.test.d.ts.map +1 -0
  11. package/dist/__tests__/base-transport.test.d.ts +2 -0
  12. package/dist/__tests__/base-transport.test.d.ts.map +1 -0
  13. package/dist/__tests__/config-loader.test.d.ts +2 -0
  14. package/dist/__tests__/config-loader.test.d.ts.map +1 -0
  15. package/dist/__tests__/connection-pool-cov.test.d.ts +2 -0
  16. package/dist/__tests__/connection-pool-cov.test.d.ts.map +1 -0
  17. package/dist/__tests__/connection-pool.test.d.ts +2 -0
  18. package/dist/__tests__/connection-pool.test.d.ts.map +1 -0
  19. package/dist/__tests__/container.test.d.ts +2 -0
  20. package/dist/__tests__/container.test.d.ts.map +1 -0
  21. package/dist/__tests__/crud.test.d.ts +2 -0
  22. package/dist/__tests__/crud.test.d.ts.map +1 -0
  23. package/dist/__tests__/discovery-cache.test.d.ts +2 -0
  24. package/dist/__tests__/discovery-cache.test.d.ts.map +1 -0
  25. package/dist/__tests__/errors.test.d.ts +2 -0
  26. package/dist/__tests__/errors.test.d.ts.map +1 -0
  27. package/dist/__tests__/factories.test.d.ts +2 -0
  28. package/dist/__tests__/factories.test.d.ts.map +1 -0
  29. package/dist/__tests__/health-checker-cov.test.d.ts +2 -0
  30. package/dist/__tests__/health-checker-cov.test.d.ts.map +1 -0
  31. package/dist/__tests__/health-checker.test.d.ts +2 -0
  32. package/dist/__tests__/health-checker.test.d.ts.map +1 -0
  33. package/dist/__tests__/helpers/factories.d.ts +36 -0
  34. package/dist/__tests__/helpers/factories.d.ts.map +1 -0
  35. package/dist/__tests__/helpers/index.d.ts +3 -0
  36. package/dist/__tests__/helpers/index.d.ts.map +1 -0
  37. package/dist/__tests__/helpers/timers.d.ts +4 -0
  38. package/dist/__tests__/helpers/timers.d.ts.map +1 -0
  39. package/dist/__tests__/history-manager.test.d.ts +2 -0
  40. package/dist/__tests__/history-manager.test.d.ts.map +1 -0
  41. package/dist/__tests__/http-helpers-cov.test.d.ts +2 -0
  42. package/dist/__tests__/http-helpers-cov.test.d.ts.map +1 -0
  43. package/dist/__tests__/http-transport-cov.test.d.ts +2 -0
  44. package/dist/__tests__/http-transport-cov.test.d.ts.map +1 -0
  45. package/dist/__tests__/http-transport.test.d.ts +2 -0
  46. package/dist/__tests__/http-transport.test.d.ts.map +1 -0
  47. package/dist/__tests__/input-normalizer.test.d.ts +8 -0
  48. package/dist/__tests__/input-normalizer.test.d.ts.map +1 -0
  49. package/dist/__tests__/integration.test.d.ts +2 -0
  50. package/dist/__tests__/integration.test.d.ts.map +1 -0
  51. package/dist/__tests__/lib-server.test.d.ts +2 -0
  52. package/dist/__tests__/lib-server.test.d.ts.map +1 -0
  53. package/dist/__tests__/memory-persistence.test.d.ts +2 -0
  54. package/dist/__tests__/memory-persistence.test.d.ts.map +1 -0
  55. package/dist/__tests__/metrics-integration.test.d.ts +2 -0
  56. package/dist/__tests__/metrics-integration.test.d.ts.map +1 -0
  57. package/dist/__tests__/persistence.test.d.ts +2 -0
  58. package/dist/__tests__/persistence.test.d.ts.map +1 -0
  59. package/dist/__tests__/reasoning-integration.test.d.ts +11 -0
  60. package/dist/__tests__/reasoning-integration.test.d.ts.map +1 -0
  61. package/dist/__tests__/reasoning-types.test.d.ts +2 -0
  62. package/dist/__tests__/reasoning-types.test.d.ts.map +1 -0
  63. package/dist/__tests__/request-context.test.d.ts +2 -0
  64. package/dist/__tests__/request-context.test.d.ts.map +1 -0
  65. package/dist/__tests__/sanitize.test.d.ts +2 -0
  66. package/dist/__tests__/sanitize.test.d.ts.map +1 -0
  67. package/dist/__tests__/schema.test.d.ts +2 -0
  68. package/dist/__tests__/schema.test.d.ts.map +1 -0
  69. package/dist/__tests__/sequentialthinking-tools.test.d.ts +2 -0
  70. package/dist/__tests__/sequentialthinking-tools.test.d.ts.map +1 -0
  71. package/dist/__tests__/server-config.test.d.ts +2 -0
  72. package/dist/__tests__/server-config.test.d.ts.map +1 -0
  73. package/dist/__tests__/skill-discovery.test.d.ts +2 -0
  74. package/dist/__tests__/skill-discovery.test.d.ts.map +1 -0
  75. package/dist/__tests__/skill-registry.test.d.ts +2 -0
  76. package/dist/__tests__/skill-registry.test.d.ts.map +1 -0
  77. package/dist/__tests__/skill-watcher.test.d.ts +2 -0
  78. package/dist/__tests__/skill-watcher.test.d.ts.map +1 -0
  79. package/dist/__tests__/sqlite-persistence.test.d.ts +2 -0
  80. package/dist/__tests__/sqlite-persistence.test.d.ts.map +1 -0
  81. package/dist/__tests__/sse-transport-cov.test.d.ts +2 -0
  82. package/dist/__tests__/sse-transport-cov.test.d.ts.map +1 -0
  83. package/dist/__tests__/sse-transport.test.d.ts +2 -0
  84. package/dist/__tests__/sse-transport.test.d.ts.map +1 -0
  85. package/dist/__tests__/streamable-http-cov.test.d.ts +2 -0
  86. package/dist/__tests__/streamable-http-cov.test.d.ts.map +1 -0
  87. package/dist/__tests__/streamable-http-transport.test.d.ts +2 -0
  88. package/dist/__tests__/streamable-http-transport.test.d.ts.map +1 -0
  89. package/dist/__tests__/structured-logger.test.d.ts +2 -0
  90. package/dist/__tests__/structured-logger.test.d.ts.map +1 -0
  91. package/dist/__tests__/thought-evaluator.test.d.ts +2 -0
  92. package/dist/__tests__/thought-evaluator.test.d.ts.map +1 -0
  93. package/dist/__tests__/thought-formatter.test.d.ts +2 -0
  94. package/dist/__tests__/thought-formatter.test.d.ts.map +1 -0
  95. package/dist/__tests__/thought-processor.test.d.ts +8 -0
  96. package/dist/__tests__/thought-processor.test.d.ts.map +1 -0
  97. package/dist/__tests__/tool-registry-cov.test.d.ts +2 -0
  98. package/dist/__tests__/tool-registry-cov.test.d.ts.map +1 -0
  99. package/dist/__tests__/tool-registry.test.d.ts +2 -0
  100. package/dist/__tests__/tool-registry.test.d.ts.map +1 -0
  101. package/dist/__tests__/tool-watcher.test.d.ts +2 -0
  102. package/dist/__tests__/tool-watcher.test.d.ts.map +1 -0
  103. package/dist/__tests__/worker-manager-cov.test.d.ts +2 -0
  104. package/dist/__tests__/worker-manager-cov.test.d.ts.map +1 -0
  105. package/dist/__tests__/worker-manager.test.d.ts +2 -0
  106. package/dist/__tests__/worker-manager.test.d.ts.map +1 -0
  107. package/dist/cache/DiscoveryCache.d.ts +269 -0
  108. package/dist/cache/DiscoveryCache.d.ts.map +1 -0
  109. package/dist/cache/DiscoveryCache.js +100 -0
  110. package/dist/cache/DiscoveryCache.js.map +1 -0
  111. package/dist/cli.d.ts +3 -0
  112. package/dist/cli.d.ts.map +1 -0
  113. package/dist/cli.js +114 -0
  114. package/dist/cli.js.map +1 -0
  115. package/dist/cluster/WorkerManager.d.ts +166 -0
  116. package/dist/cluster/WorkerManager.d.ts.map +1 -0
  117. package/dist/cluster/WorkerManager.js +202 -0
  118. package/dist/cluster/WorkerManager.js.map +1 -0
  119. package/dist/cluster/worker.d.ts +11 -0
  120. package/dist/cluster/worker.d.ts.map +1 -0
  121. package/dist/cluster/worker.js +36 -0
  122. package/dist/cluster/worker.js.map +1 -0
  123. package/dist/config/ConfigLoader.d.ts +224 -0
  124. package/dist/config/ConfigLoader.d.ts.map +1 -0
  125. package/dist/config/ConfigLoader.js +85 -0
  126. package/dist/config/ConfigLoader.js.map +1 -0
  127. package/dist/context/RequestContext.d.ts +61 -0
  128. package/dist/context/RequestContext.d.ts.map +1 -0
  129. package/dist/context/RequestContext.js +17 -0
  130. package/dist/context/RequestContext.js.map +1 -0
  131. package/dist/contracts/index.d.ts +10 -0
  132. package/dist/contracts/index.d.ts.map +1 -0
  133. package/dist/contracts/index.js +1 -0
  134. package/dist/contracts/interfaces.d.ts +107 -0
  135. package/dist/contracts/interfaces.d.ts.map +1 -0
  136. package/dist/contracts/interfaces.js +1 -0
  137. package/dist/core/HistoryManager.d.ts +514 -0
  138. package/dist/core/HistoryManager.d.ts.map +1 -0
  139. package/dist/core/HistoryManager.js +331 -0
  140. package/dist/core/HistoryManager.js.map +1 -0
  141. package/dist/core/IHistoryManager.d.ts +100 -0
  142. package/dist/core/IHistoryManager.d.ts.map +1 -0
  143. package/dist/core/IHistoryManager.js +1 -0
  144. package/dist/core/InputNormalizer.d.ts +139 -0
  145. package/dist/core/InputNormalizer.d.ts.map +1 -0
  146. package/dist/core/InputNormalizer.js +101 -0
  147. package/dist/core/InputNormalizer.js.map +1 -0
  148. package/dist/core/ThoughtEvaluator.d.ts +127 -0
  149. package/dist/core/ThoughtEvaluator.d.ts.map +1 -0
  150. package/dist/core/ThoughtEvaluator.js +346 -0
  151. package/dist/core/ThoughtEvaluator.js.map +1 -0
  152. package/dist/core/ThoughtFormatter.d.ts +133 -0
  153. package/dist/core/ThoughtFormatter.d.ts.map +1 -0
  154. package/dist/core/ThoughtFormatter.js +70 -0
  155. package/dist/core/ThoughtFormatter.js.map +1 -0
  156. package/dist/core/ThoughtProcessor.d.ts +218 -0
  157. package/dist/core/ThoughtProcessor.d.ts.map +1 -0
  158. package/dist/core/ThoughtProcessor.js +205 -0
  159. package/dist/core/ThoughtProcessor.js.map +1 -0
  160. package/dist/core/reasoning.d.ts +169 -0
  161. package/dist/core/reasoning.d.ts.map +1 -0
  162. package/dist/core/reasoning.js +1 -0
  163. package/dist/core/step.d.ts +45 -0
  164. package/dist/core/step.d.ts.map +1 -0
  165. package/dist/core/step.js +1 -0
  166. package/dist/core/thought.d.ts +190 -0
  167. package/dist/core/thought.d.ts.map +1 -0
  168. package/dist/core/thought.js +1 -0
  169. package/dist/di/Container.d.ts +226 -0
  170. package/dist/di/Container.d.ts.map +1 -0
  171. package/dist/di/Container.js +96 -0
  172. package/dist/di/Container.js.map +1 -0
  173. package/dist/di/ServiceRegistry.d.ts +32 -0
  174. package/dist/di/ServiceRegistry.d.ts.map +1 -0
  175. package/dist/di/ServiceRegistry.js +1 -0
  176. package/dist/errors.d.ts +482 -0
  177. package/dist/errors.d.ts.map +1 -0
  178. package/dist/errors.js +108 -0
  179. package/dist/errors.js.map +1 -0
  180. package/dist/health/HealthChecker.d.ts +73 -0
  181. package/dist/health/HealthChecker.d.ts.map +1 -0
  182. package/dist/health/HealthChecker.js +69 -0
  183. package/dist/health/HealthChecker.js.map +1 -0
  184. package/dist/index.d.ts +2 -0
  185. package/dist/index.d.ts.map +1 -0
  186. package/dist/index.js +1 -0
  187. package/dist/lib.d.ts +205 -0
  188. package/dist/lib.d.ts.map +1 -0
  189. package/dist/lib.js +219 -0
  190. package/dist/lib.js.map +1 -0
  191. package/dist/logger/NullLogger.d.ts +154 -0
  192. package/dist/logger/NullLogger.d.ts.map +1 -0
  193. package/dist/logger/NullLogger.js +24 -0
  194. package/dist/logger/NullLogger.js.map +1 -0
  195. package/dist/logger/StructuredLogger.d.ts +327 -0
  196. package/dist/logger/StructuredLogger.d.ts.map +1 -0
  197. package/dist/logger/StructuredLogger.js +72 -0
  198. package/dist/logger/StructuredLogger.js.map +1 -0
  199. package/dist/metrics/__tests__/metrics.test.d.ts +2 -0
  200. package/dist/metrics/__tests__/metrics.test.d.ts.map +1 -0
  201. package/dist/metrics/metrics.impl.d.ts +252 -0
  202. package/dist/metrics/metrics.impl.d.ts.map +1 -0
  203. package/dist/metrics/metrics.impl.js +197 -0
  204. package/dist/metrics/metrics.impl.js.map +1 -0
  205. package/dist/persistence/FilePersistence.d.ts +66 -0
  206. package/dist/persistence/FilePersistence.d.ts.map +1 -0
  207. package/dist/persistence/FilePersistence.js +132 -0
  208. package/dist/persistence/FilePersistence.js.map +1 -0
  209. package/dist/persistence/MemoryPersistence.d.ts +68 -0
  210. package/dist/persistence/MemoryPersistence.d.ts.map +1 -0
  211. package/dist/persistence/MemoryPersistence.js +51 -0
  212. package/dist/persistence/MemoryPersistence.js.map +1 -0
  213. package/dist/persistence/PersistenceBackend.d.ts +69 -0
  214. package/dist/persistence/PersistenceBackend.d.ts.map +1 -0
  215. package/dist/persistence/PersistenceBackend.js +1 -0
  216. package/dist/persistence/PersistenceFactory.d.ts +21 -0
  217. package/dist/persistence/PersistenceFactory.d.ts.map +1 -0
  218. package/dist/persistence/PersistenceFactory.js +25 -0
  219. package/dist/persistence/PersistenceFactory.js.map +1 -0
  220. package/dist/persistence/SqlitePersistence.d.ts +60 -0
  221. package/dist/persistence/SqlitePersistence.d.ts.map +1 -0
  222. package/dist/persistence/SqlitePersistence.js +136 -0
  223. package/dist/persistence/SqlitePersistence.js.map +1 -0
  224. package/dist/pool/ConnectionPool.d.ts +215 -0
  225. package/dist/pool/ConnectionPool.d.ts.map +1 -0
  226. package/dist/pool/ConnectionPool.js +187 -0
  227. package/dist/pool/ConnectionPool.js.map +1 -0
  228. package/dist/registry/BaseRegistry.d.ts +203 -0
  229. package/dist/registry/BaseRegistry.d.ts.map +1 -0
  230. package/dist/registry/BaseRegistry.js +165 -0
  231. package/dist/registry/BaseRegistry.js.map +1 -0
  232. package/dist/registry/SkillRegistry.d.ts +69 -0
  233. package/dist/registry/SkillRegistry.d.ts.map +1 -0
  234. package/dist/registry/SkillRegistry.js +88 -0
  235. package/dist/registry/SkillRegistry.js.map +1 -0
  236. package/dist/registry/ToolRegistry.d.ts +69 -0
  237. package/dist/registry/ToolRegistry.d.ts.map +1 -0
  238. package/dist/registry/ToolRegistry.js +93 -0
  239. package/dist/registry/ToolRegistry.js.map +1 -0
  240. package/dist/sanitize.d.ts +63 -0
  241. package/dist/sanitize.d.ts.map +1 -0
  242. package/dist/sanitize.js +14 -0
  243. package/dist/sanitize.js.map +1 -0
  244. package/dist/schema.d.ts +531 -0
  245. package/dist/schema.d.ts.map +1 -0
  246. package/dist/schema.js +204 -0
  247. package/dist/schema.js.map +1 -0
  248. package/dist/telemetry/Telemetry.d.ts +36 -0
  249. package/dist/telemetry/Telemetry.d.ts.map +1 -0
  250. package/dist/telemetry/Telemetry.js +68 -0
  251. package/dist/telemetry/Telemetry.js.map +1 -0
  252. package/dist/telemetry/__tests__/Telemetry.test.d.ts +2 -0
  253. package/dist/telemetry/__tests__/Telemetry.test.d.ts.map +1 -0
  254. package/dist/transport/BaseTransport.d.ts +184 -0
  255. package/dist/transport/BaseTransport.d.ts.map +1 -0
  256. package/dist/transport/BaseTransport.js +200 -0
  257. package/dist/transport/BaseTransport.js.map +1 -0
  258. package/dist/transport/HttpHelpers.d.ts +60 -0
  259. package/dist/transport/HttpHelpers.d.ts.map +1 -0
  260. package/dist/transport/HttpHelpers.js +50 -0
  261. package/dist/transport/HttpHelpers.js.map +1 -0
  262. package/dist/transport/HttpTransport.d.ts +134 -0
  263. package/dist/transport/HttpTransport.d.ts.map +1 -0
  264. package/dist/transport/HttpTransport.js +175 -0
  265. package/dist/transport/HttpTransport.js.map +1 -0
  266. package/dist/transport/SseTransport.d.ts +133 -0
  267. package/dist/transport/SseTransport.d.ts.map +1 -0
  268. package/dist/transport/SseTransport.js +318 -0
  269. package/dist/transport/SseTransport.js.map +1 -0
  270. package/dist/transport/StreamableHttpTransport.d.ts +224 -0
  271. package/dist/transport/StreamableHttpTransport.d.ts.map +1 -0
  272. package/dist/transport/StreamableHttpTransport.js +407 -0
  273. package/dist/transport/StreamableHttpTransport.js.map +1 -0
  274. package/dist/types/disposable.d.ts +22 -0
  275. package/dist/types/disposable.d.ts.map +1 -0
  276. package/dist/types/disposable.js +1 -0
  277. package/dist/types/server-config.d.ts +32 -0
  278. package/dist/types/server-config.d.ts.map +1 -0
  279. package/dist/types/server-config.js +1 -0
  280. package/dist/types/skill.d.ts +69 -0
  281. package/dist/types/skill.d.ts.map +1 -0
  282. package/dist/types/skill.js +1 -0
  283. package/dist/types/tool.d.ts +68 -0
  284. package/dist/types/tool.d.ts.map +1 -0
  285. package/dist/types/tool.js +1 -0
  286. package/dist/watchers/SkillWatcher.d.ts +132 -0
  287. package/dist/watchers/SkillWatcher.d.ts.map +1 -0
  288. package/dist/watchers/SkillWatcher.js +73 -0
  289. package/dist/watchers/SkillWatcher.js.map +1 -0
  290. package/dist/watchers/ToolWatcher.d.ts +109 -0
  291. package/dist/watchers/ToolWatcher.d.ts.map +1 -0
  292. package/dist/watchers/ToolWatcher.js +71 -0
  293. package/dist/watchers/ToolWatcher.js.map +1 -0
  294. package/package.json +95 -0
@@ -0,0 +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 { 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\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}\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 * 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","thoughtStmt","thoughtCount","branchCount","branchStmt","result"],"mappings":"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"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Connection Pool for managing concurrent user sessions.
3
+ *
4
+ * This module provides session management for multi-user scenarios,
5
+ * allowing multiple concurrent clients to each have isolated state.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const pool = new ConnectionPool({
10
+ * maxSessions: 100,
11
+ * sessionTimeout: 300000 // 5 minutes
12
+ * });
13
+ *
14
+ * const sessionId = await pool.createSession();
15
+ * await pool.process(sessionId, thought);
16
+ * await pool.closeSession(sessionId);
17
+ * ```
18
+ */
19
+ import type { ThoughtData } from '../core/thought.js';
20
+ import type { Logger } from '../logger/StructuredLogger.js';
21
+ import type { IDisposable } from '../types/disposable.js';
22
+ export interface SessionOptions {
23
+ /**
24
+ * Maximum number of concurrent sessions
25
+ * @default 100
26
+ */
27
+ maxSessions?: number;
28
+ /**
29
+ * Logger instance
30
+ */
31
+ logger?: Logger;
32
+ serverFactory?: () => Promise<SessionServer>;
33
+ /**
34
+ * Session timeout in milliseconds
35
+ * @default 300000 (5 minutes)
36
+ */
37
+ sessionTimeout?: number;
38
+ /**
39
+ * Whether to enable automatic session cleanup
40
+ * @default true
41
+ */
42
+ autoCleanup?: boolean;
43
+ /**
44
+ * Cleanup interval in milliseconds
45
+ * @default 60000 (1 minute)
46
+ */
47
+ cleanupInterval?: number;
48
+ }
49
+ export interface SessionInfo {
50
+ id: string;
51
+ server: SessionServer;
52
+ createdAt: number;
53
+ lastActivityAt: number;
54
+ isActive: boolean;
55
+ }
56
+ export interface SessionServer {
57
+ processThought(input: ThoughtData): Promise<ProcessResult>;
58
+ stop(): void | Promise<void>;
59
+ }
60
+ export interface ProcessResult {
61
+ content: Array<{
62
+ type: string;
63
+ text: string;
64
+ }>;
65
+ isError?: boolean;
66
+ }
67
+ /**
68
+ * Represents a user session with its own server instance.
69
+ */
70
+ export declare class Session {
71
+ private _server;
72
+ private _id;
73
+ private _createdAt;
74
+ private _lastActivityAt;
75
+ private _isActiveValue;
76
+ private _timeout;
77
+ private _cleanupTimer;
78
+ private _logger;
79
+ constructor(id: string, server: SessionServer, timeout: number, logger: Logger);
80
+ /**
81
+ * Check if the session is active.
82
+ */
83
+ get isActive(): boolean;
84
+ /**
85
+ * Process a thought through this session's server instance.
86
+ */
87
+ process(input: ThoughtData): Promise<ProcessResult>;
88
+ /**
89
+ * Get session information.
90
+ */
91
+ getInfo(): SessionInfo;
92
+ /**
93
+ * Check if the session has timed out.
94
+ */
95
+ isTimedOut(): boolean;
96
+ /**
97
+ * Close the session and stop the server.
98
+ */
99
+ close(): Promise<void>;
100
+ /**
101
+ * Start the session timeout timer.
102
+ */
103
+ private _startTimeout;
104
+ /**
105
+ * Reset the timeout timer after activity.
106
+ */
107
+ private _resetTimeout;
108
+ }
109
+ /**
110
+ * ConnectionPool manages multiple concurrent user sessions.
111
+ *
112
+ * Each session has its own server instance with isolated state,
113
+ * allowing multiple users to interact with the system simultaneously.
114
+ */
115
+ export declare class ConnectionPool implements IDisposable {
116
+ private _sessions;
117
+ private _createSessionLock;
118
+ private _maxSessions;
119
+ private _sessionTimeout;
120
+ private _autoCleanup;
121
+ private _cleanupInterval;
122
+ private _cleanupTimerId;
123
+ private _terminated;
124
+ private _logger;
125
+ private _serverFactory;
126
+ constructor(options?: SessionOptions);
127
+ /**
128
+ * Create a no-op logger when none is provided.
129
+ */
130
+ private _createNoopLogger;
131
+ /**
132
+ * Create a new session.
133
+ *
134
+ * @returns The session ID
135
+ * @throws Error if max sessions reached
136
+ */
137
+ createSession(): Promise<string>;
138
+ /**
139
+ * Process a thought in the specified session.
140
+ *
141
+ * @param sessionId - The session ID
142
+ * @param input - The thought data to process
143
+ * @returns Promise with the processing result
144
+ * @throws Error if session not found
145
+ */
146
+ process(sessionId: string, input: ThoughtData): Promise<ProcessResult>;
147
+ /**
148
+ * Close a session and release resources.
149
+ *
150
+ * @param sessionId - The session ID to close
151
+ * @throws Error if session not found
152
+ */
153
+ closeSession(sessionId: string): Promise<void>;
154
+ /**
155
+ * Get information about a session.
156
+ *
157
+ * @param sessionId - The session ID
158
+ * @returns Session info or undefined if not found
159
+ */
160
+ getSessionInfo(sessionId: string): SessionInfo | undefined;
161
+ /**
162
+ * Get all active sessions.
163
+ *
164
+ * @returns Array of session information
165
+ */
166
+ getActiveSessions(): SessionInfo[];
167
+ /**
168
+ * Get connection pool statistics.
169
+ */
170
+ getStats(): {
171
+ totalSessions: number;
172
+ activeSessions: number;
173
+ maxSessions: number;
174
+ cleanupEnabled: boolean;
175
+ sessionTimeout: number;
176
+ };
177
+ /**
178
+ * Start the automatic cleanup timer.
179
+ */
180
+ private _startCleanup;
181
+ /**
182
+ * Remove timed-out sessions.
183
+ */
184
+ private _cleanupTimedOutSessions;
185
+ /**
186
+ * Close all sessions and stop the cleanup timer.
187
+ */
188
+ terminate(): Promise<void>;
189
+ /**
190
+ * Dispose of the connection pool, releasing all resources.
191
+ * Implements the IDisposable interface.
192
+ * Delegates to terminate() for backward compatibility.
193
+ */
194
+ dispose(): Promise<void>;
195
+ /**
196
+ * Check if the connection pool is active.
197
+ */
198
+ isRunning(): boolean;
199
+ }
200
+ /**
201
+ * Create a connection pool with the given options.
202
+ *
203
+ * @param options - Connection pool configuration
204
+ * @returns A configured connection pool
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * const pool = createConnectionPool({
209
+ * maxSessions: 50,
210
+ * sessionTimeout: 300000
211
+ * });
212
+ * ```
213
+ */
214
+ export declare function createConnectionPool(options?: SessionOptions): ConnectionPool;
215
+ //# sourceMappingURL=ConnectionPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/ConnectionPool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ import { MaxSessionsReachedError, PoolTerminatedError, SessionNotActiveError, SessionNotFoundError } from "../errors.js";
2
+ class Session {
3
+ _server;
4
+ _id;
5
+ _createdAt;
6
+ _lastActivityAt;
7
+ _isActiveValue;
8
+ _timeout;
9
+ _cleanupTimer = null;
10
+ _logger;
11
+ constructor(id, server, timeout, logger){
12
+ this._server = server;
13
+ this._id = id;
14
+ this._createdAt = Date.now();
15
+ this._lastActivityAt = this._createdAt;
16
+ this._isActiveValue = true;
17
+ this._timeout = timeout;
18
+ this._logger = logger;
19
+ this._startTimeout();
20
+ }
21
+ get isActive() {
22
+ return this._isActiveValue;
23
+ }
24
+ async process(input) {
25
+ if (!this.isActive) throw new SessionNotActiveError(this._id);
26
+ this._lastActivityAt = Date.now();
27
+ this._resetTimeout();
28
+ return this._server.processThought(input);
29
+ }
30
+ getInfo() {
31
+ return {
32
+ id: this._id,
33
+ server: this._server,
34
+ createdAt: this._createdAt,
35
+ lastActivityAt: this._lastActivityAt,
36
+ isActive: this.isActive
37
+ };
38
+ }
39
+ isTimedOut() {
40
+ return Date.now() - this._lastActivityAt > this._timeout;
41
+ }
42
+ async close() {
43
+ this._isActiveValue = false;
44
+ if (this._cleanupTimer) {
45
+ clearTimeout(this._cleanupTimer);
46
+ this._cleanupTimer = null;
47
+ }
48
+ this._server.stop();
49
+ }
50
+ _startTimeout() {
51
+ if (this._cleanupTimer) clearTimeout(this._cleanupTimer);
52
+ this._cleanupTimer = setTimeout(()=>{
53
+ if (this.isTimedOut()) {
54
+ this._logger.warn(`Session ${this._id} timed out, closing`);
55
+ this.close().catch((err)=>{
56
+ this._logger.error(`Error closing timed out session ${this._id}:`, err);
57
+ });
58
+ }
59
+ }, this._timeout);
60
+ }
61
+ _resetTimeout() {
62
+ this._startTimeout();
63
+ }
64
+ }
65
+ class ConnectionPool {
66
+ _sessions = new Map();
67
+ _createSessionLock = null;
68
+ _maxSessions;
69
+ _sessionTimeout;
70
+ _autoCleanup;
71
+ _cleanupInterval;
72
+ _cleanupTimerId = null;
73
+ _terminated = false;
74
+ _logger;
75
+ _serverFactory;
76
+ constructor(options = {}){
77
+ this._maxSessions = options.maxSessions ?? 100;
78
+ this._sessionTimeout = options.sessionTimeout ?? 300000;
79
+ this._autoCleanup = options.autoCleanup ?? true;
80
+ this._cleanupInterval = options.cleanupInterval ?? 60000;
81
+ this._serverFactory = options.serverFactory ?? null;
82
+ this._logger = options.logger ?? this._createNoopLogger();
83
+ if (this._autoCleanup) this._startCleanup();
84
+ }
85
+ _createNoopLogger() {
86
+ return {
87
+ info: ()=>{},
88
+ warn: ()=>{},
89
+ error: ()=>{},
90
+ debug: ()=>{},
91
+ setLevel: ()=>{},
92
+ getLevel: ()=>'info'
93
+ };
94
+ }
95
+ async createSession() {
96
+ while(this._createSessionLock)await this._createSessionLock;
97
+ if (this._terminated) throw new PoolTerminatedError();
98
+ if (this._sessions.size >= this._maxSessions) throw new MaxSessionsReachedError(this._maxSessions);
99
+ if (!this._serverFactory) throw new Error('ConnectionPool requires a serverFactory option to create sessions');
100
+ let resolveLock;
101
+ this._createSessionLock = new Promise((resolve)=>{
102
+ resolveLock = resolve;
103
+ });
104
+ try {
105
+ const sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
106
+ const server = await this._serverFactory();
107
+ const session = new Session(sessionId, server, this._sessionTimeout, this._logger);
108
+ this._sessions.set(sessionId, session);
109
+ this._logger.info(`Created session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`);
110
+ return sessionId;
111
+ } finally{
112
+ resolveLock();
113
+ this._createSessionLock = null;
114
+ }
115
+ }
116
+ async process(sessionId, input) {
117
+ const session = this._sessions.get(sessionId);
118
+ if (!session) throw new SessionNotFoundError(sessionId);
119
+ return session.process(input);
120
+ }
121
+ async closeSession(sessionId) {
122
+ const session = this._sessions.get(sessionId);
123
+ if (!session) throw new SessionNotFoundError(sessionId);
124
+ await session.close();
125
+ this._sessions.delete(sessionId);
126
+ this._logger.info(`Closed session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`);
127
+ }
128
+ getSessionInfo(sessionId) {
129
+ return this._sessions.get(sessionId)?.getInfo();
130
+ }
131
+ getActiveSessions() {
132
+ return Array.from(this._sessions.values()).filter((s)=>s.isActive).map((s)=>s.getInfo());
133
+ }
134
+ getStats() {
135
+ const activeSessions = this.getActiveSessions();
136
+ return {
137
+ totalSessions: this._sessions.size,
138
+ activeSessions: activeSessions.length,
139
+ maxSessions: this._maxSessions,
140
+ cleanupEnabled: this._autoCleanup,
141
+ sessionTimeout: this._sessionTimeout
142
+ };
143
+ }
144
+ _startCleanup() {
145
+ if (null !== this._cleanupTimerId) clearInterval(this._cleanupTimerId);
146
+ this._cleanupTimerId = setInterval(()=>{
147
+ this._cleanupTimedOutSessions();
148
+ }, this._cleanupInterval);
149
+ }
150
+ _cleanupTimedOutSessions() {
151
+ let cleaned = 0;
152
+ for (const [sessionId, session] of this._sessions.entries())if (session.isTimedOut()) {
153
+ session.close().catch((err)=>{
154
+ this._logger.error(`Error closing timed out session ${sessionId}:`, err);
155
+ });
156
+ this._sessions.delete(sessionId);
157
+ cleaned++;
158
+ }
159
+ if (cleaned > 0) this._logger.info(`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`);
160
+ }
161
+ async terminate() {
162
+ if (this._terminated) return;
163
+ this._terminated = true;
164
+ if (null !== this._cleanupTimerId) {
165
+ clearInterval(this._cleanupTimerId);
166
+ this._cleanupTimerId = null;
167
+ }
168
+ const closePromises = Array.from(this._sessions.values()).map((session)=>session.close().catch((err)=>{
169
+ this._logger.error(`Error closing session ${session.getInfo().id}:`, err);
170
+ }));
171
+ await Promise.all(closePromises);
172
+ this._sessions.clear();
173
+ this._logger.info('ConnectionPool terminated');
174
+ }
175
+ async dispose() {
176
+ await this.terminate();
177
+ }
178
+ isRunning() {
179
+ return !this._terminated;
180
+ }
181
+ }
182
+ function createConnectionPool(options) {
183
+ return new ConnectionPool(options);
184
+ }
185
+ export { ConnectionPool, Session, createConnectionPool };
186
+
187
+ //# sourceMappingURL=ConnectionPool.js.map
@@ -0,0 +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":";AAsFO,MAAMA;IACJ,QAAuB;IACvB,IAAY;IACZ,WAAmB;IACnB,gBAAwB;IACxB,eAAwB;IACxB,SAAiB;IACjB,gBAAuC,KAAK;IAC5C,QAAgB;IAExB,YAAYC,EAAU,EAAEC,MAAqB,EAAEC,OAAe,EAAEC,MAAc,CAAE;QAC/E,IAAI,CAAC,OAAO,GAAGF;QACf,IAAI,CAAC,GAAG,GAAGD;QACX,IAAI,CAAC,UAAU,GAAGI,KAAK,GAAG;QAC1B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,UAAU;QACtC,IAAI,CAAC,cAAc,GAAG;QACtB,IAAI,CAAC,QAAQ,GAAGF;QAChB,IAAI,CAAC,OAAO,GAAGC;QAGf,IAAI,CAAC,aAAa;IACnB;IAKA,IAAI,WAAoB;QACvB,OAAO,IAAI,CAAC,cAAc;IAC3B;IAKA,MAAM,QAAQE,KAAkB,EAA0B;QACzD,IAAI,CAAC,IAAI,CAAC,QAAQ,EACjB,MAAM,IAAIC,sBAAsB,IAAI,CAAC,GAAG;QAIzC,IAAI,CAAC,eAAe,GAAGF,KAAK,GAAG;QAG/B,IAAI,CAAC,aAAa;QAGlB,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,CAACC;IACpC;IAKA,UAAuB;QACtB,OAAO;YACN,IAAI,IAAI,CAAC,GAAG;YACZ,QAAQ,IAAI,CAAC,OAAO;YACpB,WAAW,IAAI,CAAC,UAAU;YAC1B,gBAAgB,IAAI,CAAC,eAAe;YACpC,UAAU,IAAI,CAAC,QAAQ;QACxB;IACD;IAKA,aAAsB;QACrB,OAAOD,KAAK,GAAG,KAAK,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,QAAQ;IACzD;IAKA,MAAM,QAAuB;QAC5B,IAAI,CAAC,cAAc,GAAG;QAGtB,IAAI,IAAI,CAAC,aAAa,EAAE;YACvBG,aAAa,IAAI,CAAC,aAAa;YAC/B,IAAI,CAAC,aAAa,GAAG;QACtB;QAGA,IAAI,CAAC,OAAO,CAAC,IAAI;IAClB;IAKQ,gBAAsB;QAC7B,IAAI,IAAI,CAAC,aAAa,EACrBA,aAAa,IAAI,CAAC,aAAa;QAGhC,IAAI,CAAC,aAAa,GAAGC,WAAW;YAC/B,IAAI,IAAI,CAAC,UAAU,IAAI;gBACtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC;gBAC1D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAACC;oBACnB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,gCAAgC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAEA;gBACpE;YACD;QACD,GAAG,IAAI,CAAC,QAAQ;IACjB;IAKQ,gBAAsB;QAC7B,IAAI,CAAC,aAAa;IACnB;AACD;AAQO,MAAMC;IACJ,YAAkC,IAAIC,MAAM;IAC5C,qBAA2C,KAAK;IAChD,aAAqB;IACrB,gBAAwB;IACxB,aAAsB;IACtB,iBAAyB;IACzB,kBAAiC,KAAK;IACtC,cAAuB,MAAM;IAC7B,QAAgB;IAChB,eAAsD;IAE9D,YAAYC,UAA0B,CAAC,CAAC,CAAE;QACzC,IAAI,CAAC,YAAY,GAAGA,QAAQ,WAAW,IAAI;QAC3C,IAAI,CAAC,eAAe,GAAGA,QAAQ,cAAc,IAAI;QACjD,IAAI,CAAC,YAAY,GAAGA,QAAQ,WAAW,IAAI;QAC3C,IAAI,CAAC,gBAAgB,GAAGA,QAAQ,eAAe,IAAI;QACnD,IAAI,CAAC,cAAc,GAAGA,QAAQ,aAAa,IAAI;QAC/C,IAAI,CAAC,OAAO,GAAGA,QAAQ,MAAM,IAAI,IAAI,CAAC,iBAAiB;QAEvD,IAAI,IAAI,CAAC,YAAY,EACpB,IAAI,CAAC,aAAa;IAEpB;IAKQ,oBAA4B;QACnC,OAAO;YACN,MAAM,KAAa;YACnB,MAAM,KAAa;YACnB,OAAO,KAAa;YACpB,OAAO,KAAa;YACpB,UAAU,KAAa;YACvB,UAAU,IAAc;QACzB;IACD;IAQA,MAAM,gBAAiC;QACtC,MAAO,IAAI,CAAC,kBAAkB,CAC7B,MAAM,IAAI,CAAC,kBAAkB;QAG9B,IAAI,IAAI,CAAC,WAAW,EACnB,MAAM,IAAIC;QAGX,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,YAAY,EAC3C,MAAM,IAAIC,wBAAwB,IAAI,CAAC,YAAY;QAGpD,IAAI,CAAC,IAAI,CAAC,cAAc,EACvB,MAAM,IAAIC,MAAM;QAGjB,IAAIC;QACJ,IAAI,CAAC,kBAAkB,GAAG,IAAIC,QAAc,CAACC;YAC5CF,cAAcE;QACf;QAEA,IAAI;YAEH,MAAMC,YAAY,CAAC,QAAQ,EAAEf,KAAK,GAAG,GAAG,CAAC,EAAEgB,KAAK,MAAM,GAAG,QAAQ,CAAC,IAAI,SAAS,CAAC,GAAG,KAAK;YAGxF,MAAMnB,SAAS,MAAM,IAAI,CAAC,cAAc;YAGxC,MAAMoB,UAAU,IAAItB,QAAQoB,WAAWlB,QAAQ,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,OAAO;YACjF,IAAI,CAAC,SAAS,CAAC,GAAG,CAACkB,WAAWE;YAE9B,IAAI,CAAC,OAAO,CAAC,IAAI,CAChB,CAAC,gBAAgB,EAAEF,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC;YAE7F,OAAOA;QACR,SAAU;YACTH;YACA,IAAI,CAAC,kBAAkB,GAAG;QAC3B;IACD;IAUA,MAAM,QAAQG,SAAiB,EAAEd,KAAkB,EAA0B;QAC5E,MAAMgB,UAAU,IAAI,CAAC,SAAS,CAAC,GAAG,CAACF;QAEnC,IAAI,CAACE,SACJ,MAAM,IAAIC,qBAAqBH;QAGhC,OAAOE,QAAQ,OAAO,CAAChB;IACxB;IAQA,MAAM,aAAac,SAAiB,EAAiB;QACpD,MAAME,UAAU,IAAI,CAAC,SAAS,CAAC,GAAG,CAACF;QAEnC,IAAI,CAACE,SACJ,MAAM,IAAIC,qBAAqBH;QAGhC,MAAME,QAAQ,KAAK;QACnB,IAAI,CAAC,SAAS,CAAC,MAAM,CAACF;QAEtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAChB,CAAC,eAAe,EAAEA,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC;IAE7F;IAQA,eAAeA,SAAiB,EAA2B;QAC1D,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAACA,YAAY;IACvC;IAOA,oBAAmC;QAClC,OAAOI,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,IACrC,MAAM,CAAC,CAACC,IAAMA,EAAE,QAAQ,EACxB,GAAG,CAAC,CAACA,IAAMA,EAAE,OAAO;IACvB;IAKA,WAME;QACD,MAAMC,iBAAiB,IAAI,CAAC,iBAAiB;QAE7C,OAAO;YACN,eAAe,IAAI,CAAC,SAAS,CAAC,IAAI;YAClC,gBAAgBA,eAAe,MAAM;YACrC,aAAa,IAAI,CAAC,YAAY;YAC9B,gBAAgB,IAAI,CAAC,YAAY;YACjC,gBAAgB,IAAI,CAAC,eAAe;QACrC;IACD;IAKQ,gBAAsB;QAC7B,IAAI,AAAyB,SAAzB,IAAI,CAAC,eAAe,EACvBC,cAAc,IAAI,CAAC,eAAe;QAGnC,IAAI,CAAC,eAAe,GAAGC,YAAY;YAClC,IAAI,CAAC,wBAAwB;QAC9B,GAAG,IAAI,CAAC,gBAAgB;IACzB;IAKQ,2BAAiC;QACxC,IAAIC,UAAU;QAEd,KAAK,MAAM,CAACT,WAAWE,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,GACxD,IAAIA,QAAQ,UAAU,IAAI;YACzBA,QAAQ,KAAK,GAAG,KAAK,CAAC,CAACZ;gBACtB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,gCAAgC,EAAEU,UAAU,CAAC,CAAC,EAAEV;YACrE;YACA,IAAI,CAAC,SAAS,CAAC,MAAM,CAACU;YACtBS;QACD;QAGD,IAAIA,UAAU,GACb,IAAI,CAAC,OAAO,CAAC,IAAI,CAChB,CAAC,QAAQ,EAAEA,QAAQ,qBAAqB,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC;IAGxG;IAKA,MAAM,YAA2B;QAChC,IAAI,IAAI,CAAC,WAAW,EACnB;QAGD,IAAI,CAAC,WAAW,GAAG;QAGnB,IAAI,AAAyB,SAAzB,IAAI,CAAC,eAAe,EAAW;YAClCF,cAAc,IAAI,CAAC,eAAe;YAClC,IAAI,CAAC,eAAe,GAAG;QACxB;QAGA,MAAMG,gBAAgBN,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,GAAG,CAAC,CAACF,UAC9DA,QAAQ,KAAK,GAAG,KAAK,CAAC,CAACZ;gBACtB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,sBAAsB,EAAEY,QAAQ,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,EAAEZ;YACtE;QAGD,MAAMQ,QAAQ,GAAG,CAACY;QAClB,IAAI,CAAC,SAAS,CAAC,KAAK;QAEpB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IACnB;IAOA,MAAM,UAAyB;QAC9B,MAAM,IAAI,CAAC,SAAS;IACrB;IAKA,YAAqB;QACpB,OAAO,CAAC,IAAI,CAAC,WAAW;IACzB;AACD;AAgBO,SAASC,qBAAqBlB,OAAwB;IAC5D,OAAO,IAAIF,eAAeE;AAC3B"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Base registry providing shared CRUD, caching, and discovery logic.
3
+ *
4
+ * This abstract generic class extracts the common patterns from `ToolRegistry`
5
+ * and `SkillRegistry` into a single reusable base. Subclasses only need to
6
+ * implement item-specific parsing, file filtering, and error construction.
7
+ *
8
+ * @template T - The registry item type (must have a `name` property)
9
+ * @module registry
10
+ */
11
+ import { DiscoveryCache } from '../cache/DiscoveryCache.js';
12
+ import type { Logger } from '../logger/StructuredLogger.js';
13
+ /**
14
+ * Configuration options for creating a `BaseRegistry` instance.
15
+ */
16
+ export interface BaseRegistryOptions {
17
+ /** Optional logger for diagnostics. */
18
+ logger?: Logger;
19
+ /** Optional cache for lookups. */
20
+ cache?: DiscoveryCache<{
21
+ name: string;
22
+ }>;
23
+ /**
24
+ * Directory paths to search for items.
25
+ */
26
+ searchDirs?: string[];
27
+ /**
28
+ * Enable lazy discovery (discover on first access instead of startup).
29
+ * @default false
30
+ */
31
+ lazyDiscovery?: boolean;
32
+ }
33
+ /**
34
+ * Abstract base registry for managing named items with discovery and caching.
35
+ *
36
+ * Provides shared CRUD operations, filesystem discovery with deduplication,
37
+ * and optional LRU caching. Subclasses implement item-specific parsing logic
38
+ * and error construction.
39
+ *
40
+ * @template T - The registry item type (must have a `name` property)
41
+ */
42
+ export declare abstract class BaseRegistry<T extends {
43
+ name: string;
44
+ }> {
45
+ /** Internal storage for items indexed by name. */
46
+ protected _items: Map<string, T>;
47
+ /** Logger for diagnostics. */
48
+ protected _logger: Logger;
49
+ /** Optional cache for lookups. */
50
+ protected _cache: DiscoveryCache<T>;
51
+ /** Directory paths to search for items. */
52
+ protected _searchDirs: string[];
53
+ /** Whether discovery has been performed. */
54
+ protected _discovered: boolean;
55
+ /** Promise for in-progress discovery (null if not in progress). */
56
+ protected _discoveryPromise: Promise<number> | null;
57
+ /** File extensions to match during discovery. */
58
+ protected abstract readonly _fileExtensions: string[];
59
+ /**
60
+ * Creates an error for invalid item data.
61
+ * @param reason - The reason for the validation failure
62
+ */
63
+ protected abstract _createInvalidError(reason: string): Error;
64
+ /**
65
+ * Creates an error for duplicate items.
66
+ * @param name - The name of the duplicate item
67
+ */
68
+ protected abstract _createDuplicateError(name: string): Error;
69
+ /**
70
+ * Creates an error for items not found.
71
+ * @param name - The name of the missing item
72
+ * @param action - The action that was attempted
73
+ */
74
+ protected abstract _createNotFoundError(name: string, action: string): Error;
75
+ /**
76
+ * Parses frontmatter content into a partial item.
77
+ * @param content - The file content to parse
78
+ * @returns A partial item, with an `_error` property if parsing failed
79
+ */
80
+ protected abstract _parseFrontmatter(content: string): Partial<T> & {
81
+ _error?: string;
82
+ };
83
+ /**
84
+ * Determines whether a file should be skipped during discovery.
85
+ * @param fileName - The name of the file to check
86
+ * @returns true if the file should be skipped
87
+ */
88
+ protected abstract _shouldSkipFile(fileName: string): boolean;
89
+ /**
90
+ * Constructs a complete item from parsed frontmatter data.
91
+ * Returns null if the parsed data is insufficient.
92
+ * @param parsed - The parsed frontmatter data
93
+ * @returns A complete item, or null if data is insufficient
94
+ */
95
+ protected abstract _buildItem(parsed: Partial<T>): T | null;
96
+ /**
97
+ * The entity name used in log messages (e.g., 'tool', 'skill').
98
+ */
99
+ protected abstract readonly _entityName: string;
100
+ constructor(options: BaseRegistryOptions & Record<string, unknown>);
101
+ /**
102
+ * Internal logging method.
103
+ * @param message - The message to log
104
+ * @param meta - Optional metadata
105
+ */
106
+ protected log(message: string, meta?: Record<string, unknown>): void;
107
+ /**
108
+ * Adds an item to the registry.
109
+ *
110
+ * @param item - The item to add
111
+ * @throws If item already exists or name is invalid
112
+ */
113
+ add(item: T): void;
114
+ /**
115
+ * Removes an item from the registry.
116
+ *
117
+ * @param name - The name of the item to remove
118
+ * @throws If item not found
119
+ */
120
+ remove(name: string): void;
121
+ /**
122
+ * Updates an existing item with partial data.
123
+ *
124
+ * @param name - The name of the item to update
125
+ * @param updates - Partial item data with fields to update
126
+ * @throws If item not found
127
+ */
128
+ update(name: string, updates: Partial<T>): void;
129
+ /**
130
+ * Gets an item by name.
131
+ *
132
+ * @param name - The name of the item to get
133
+ * @returns The item if found, undefined otherwise
134
+ */
135
+ get(name: string): T | undefined;
136
+ /**
137
+ * Gets all items as an array.
138
+ *
139
+ * Uses cache if available for performance.
140
+ *
141
+ * @returns An array of all registered items
142
+ */
143
+ getAll(): T[];
144
+ /**
145
+ * Checks if an item exists in the registry.
146
+ *
147
+ * @param name - The name of the item to check
148
+ * @returns true if the item exists, false otherwise
149
+ */
150
+ has(name: string): boolean;
151
+ /**
152
+ * Gets all item names as an array.
153
+ *
154
+ * @returns An array of item names
155
+ */
156
+ getNames(): string[];
157
+ /**
158
+ * Clears all items from the registry.
159
+ */
160
+ clear(): void;
161
+ /**
162
+ * Gets the number of items in the registry.
163
+ *
164
+ * @returns The count of registered items
165
+ */
166
+ size(): number;
167
+ /**
168
+ * Asynchronously discovers items from the configured directories.
169
+ *
170
+ * Multiple concurrent calls share the same discovery promise.
171
+ * Subsequent calls return cached results if discovery has already completed.
172
+ *
173
+ * @returns A Promise resolving to the number of items discovered
174
+ */
175
+ discoverAsync(): Promise<number>;
176
+ /**
177
+ * Performs the actual discovery operation.
178
+ *
179
+ * Scans configured directories for item files, parses their frontmatter,
180
+ * and adds valid items to the registry.
181
+ *
182
+ * @returns A Promise resolving to the number of items discovered
183
+ */
184
+ protected _performDiscovery(): Promise<number>;
185
+ /**
186
+ * Parses YAML frontmatter from file content.
187
+ *
188
+ * This is a shared utility for subclasses that parse YAML frontmatter.
189
+ *
190
+ * @param content - The file content to parse
191
+ * @returns The parsed YAML object, or null if no frontmatter found
192
+ */
193
+ protected _extractFrontmatter(content: string): Record<string, unknown> | null;
194
+ /**
195
+ * Sets items from an external source.
196
+ *
197
+ * Clears existing items and adds new ones from the provided array.
198
+ *
199
+ * @param items - Array of items from an external source
200
+ */
201
+ setAll(items: T[]): void;
202
+ }
203
+ //# sourceMappingURL=BaseRegistry.d.ts.map