@soleri/core 2.9.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (503) hide show
  1. package/dist/agency/agency-manager.d.ts +47 -0
  2. package/dist/agency/agency-manager.d.ts.map +1 -0
  3. package/dist/agency/agency-manager.js +281 -0
  4. package/dist/agency/agency-manager.js.map +1 -0
  5. package/dist/agency/index.d.ts +3 -0
  6. package/dist/agency/index.d.ts.map +1 -0
  7. package/dist/agency/index.js +2 -0
  8. package/dist/agency/index.js.map +1 -0
  9. package/dist/agency/types.d.ts +69 -0
  10. package/dist/agency/types.d.ts.map +1 -0
  11. package/dist/agency/types.js +5 -0
  12. package/dist/agency/types.js.map +1 -0
  13. package/dist/brain/brain.d.ts +0 -1
  14. package/dist/brain/brain.d.ts.map +1 -1
  15. package/dist/brain/brain.js +14 -0
  16. package/dist/brain/brain.js.map +1 -1
  17. package/dist/brain/intelligence.d.ts +5 -1
  18. package/dist/brain/intelligence.d.ts.map +1 -1
  19. package/dist/brain/intelligence.js +83 -0
  20. package/dist/brain/intelligence.js.map +1 -1
  21. package/dist/brain/types.d.ts +21 -0
  22. package/dist/brain/types.d.ts.map +1 -1
  23. package/dist/chat/agent-loop-types.d.ts +82 -0
  24. package/dist/chat/agent-loop-types.d.ts.map +1 -0
  25. package/dist/chat/agent-loop-types.js +8 -0
  26. package/dist/chat/agent-loop-types.js.map +1 -0
  27. package/dist/chat/agent-loop.d.ts +19 -0
  28. package/dist/chat/agent-loop.d.ts.map +1 -0
  29. package/dist/chat/agent-loop.js +261 -0
  30. package/dist/chat/agent-loop.js.map +1 -0
  31. package/dist/chat/auth-manager.d.ts +49 -0
  32. package/dist/chat/auth-manager.d.ts.map +1 -0
  33. package/dist/chat/auth-manager.js +152 -0
  34. package/dist/chat/auth-manager.js.map +1 -0
  35. package/dist/chat/browser-session.d.ts +86 -0
  36. package/dist/chat/browser-session.d.ts.map +1 -0
  37. package/dist/chat/browser-session.js +143 -0
  38. package/dist/chat/browser-session.js.map +1 -0
  39. package/dist/chat/cancellation.d.ts +54 -0
  40. package/dist/chat/cancellation.d.ts.map +1 -0
  41. package/dist/chat/cancellation.js +80 -0
  42. package/dist/chat/cancellation.js.map +1 -0
  43. package/dist/chat/chat-session.d.ts +86 -0
  44. package/dist/chat/chat-session.d.ts.map +1 -0
  45. package/dist/chat/chat-session.js +252 -0
  46. package/dist/chat/chat-session.js.map +1 -0
  47. package/dist/chat/file-handler.d.ts +63 -0
  48. package/dist/chat/file-handler.d.ts.map +1 -0
  49. package/dist/chat/file-handler.js +182 -0
  50. package/dist/chat/file-handler.js.map +1 -0
  51. package/dist/chat/fragment-buffer.d.ts +49 -0
  52. package/dist/chat/fragment-buffer.d.ts.map +1 -0
  53. package/dist/chat/fragment-buffer.js +130 -0
  54. package/dist/chat/fragment-buffer.js.map +1 -0
  55. package/dist/chat/index.d.ts +24 -0
  56. package/dist/chat/index.d.ts.map +1 -0
  57. package/dist/chat/index.js +15 -0
  58. package/dist/chat/index.js.map +1 -0
  59. package/dist/chat/mcp-bridge.d.ts +60 -0
  60. package/dist/chat/mcp-bridge.d.ts.map +1 -0
  61. package/dist/chat/mcp-bridge.js +111 -0
  62. package/dist/chat/mcp-bridge.js.map +1 -0
  63. package/dist/chat/notifications.d.ts +82 -0
  64. package/dist/chat/notifications.d.ts.map +1 -0
  65. package/dist/chat/notifications.js +119 -0
  66. package/dist/chat/notifications.js.map +1 -0
  67. package/dist/chat/output-compressor.d.ts +30 -0
  68. package/dist/chat/output-compressor.d.ts.map +1 -0
  69. package/dist/chat/output-compressor.js +95 -0
  70. package/dist/chat/output-compressor.js.map +1 -0
  71. package/dist/chat/queue.d.ts +91 -0
  72. package/dist/chat/queue.d.ts.map +1 -0
  73. package/dist/chat/queue.js +146 -0
  74. package/dist/chat/queue.js.map +1 -0
  75. package/dist/chat/response-chunker.d.ts +29 -0
  76. package/dist/chat/response-chunker.d.ts.map +1 -0
  77. package/dist/chat/response-chunker.js +163 -0
  78. package/dist/chat/response-chunker.js.map +1 -0
  79. package/dist/chat/self-update.d.ts +62 -0
  80. package/dist/chat/self-update.d.ts.map +1 -0
  81. package/dist/chat/self-update.js +90 -0
  82. package/dist/chat/self-update.js.map +1 -0
  83. package/dist/chat/types.d.ts +105 -0
  84. package/dist/chat/types.d.ts.map +1 -0
  85. package/dist/chat/types.js +8 -0
  86. package/dist/chat/types.js.map +1 -0
  87. package/dist/chat/voice.d.ts +39 -0
  88. package/dist/chat/voice.d.ts.map +1 -0
  89. package/dist/chat/voice.js +80 -0
  90. package/dist/chat/voice.js.map +1 -0
  91. package/dist/claudemd/compose.d.ts +31 -0
  92. package/dist/claudemd/compose.d.ts.map +1 -0
  93. package/dist/claudemd/compose.js +105 -0
  94. package/dist/claudemd/compose.js.map +1 -0
  95. package/dist/claudemd/index.d.ts +5 -0
  96. package/dist/claudemd/index.d.ts.map +1 -0
  97. package/dist/claudemd/index.js +3 -0
  98. package/dist/claudemd/index.js.map +1 -0
  99. package/dist/claudemd/inject.d.ts +31 -0
  100. package/dist/claudemd/inject.d.ts.map +1 -0
  101. package/dist/claudemd/inject.js +157 -0
  102. package/dist/claudemd/inject.js.map +1 -0
  103. package/dist/claudemd/types.d.ts +41 -0
  104. package/dist/claudemd/types.d.ts.map +1 -0
  105. package/dist/claudemd/types.js +5 -0
  106. package/dist/claudemd/types.js.map +1 -0
  107. package/dist/context/context-engine.d.ts +31 -0
  108. package/dist/context/context-engine.d.ts.map +1 -0
  109. package/dist/context/context-engine.js +245 -0
  110. package/dist/context/context-engine.js.map +1 -0
  111. package/dist/context/index.d.ts +3 -0
  112. package/dist/context/index.d.ts.map +1 -0
  113. package/dist/context/index.js +2 -0
  114. package/dist/context/index.js.map +1 -0
  115. package/dist/context/types.d.ts +54 -0
  116. package/dist/context/types.d.ts.map +1 -0
  117. package/dist/context/types.js +5 -0
  118. package/dist/context/types.js.map +1 -0
  119. package/dist/enforcement/adapters/claude-code.d.ts +18 -0
  120. package/dist/enforcement/adapters/claude-code.d.ts.map +1 -0
  121. package/dist/enforcement/adapters/claude-code.js +106 -0
  122. package/dist/enforcement/adapters/claude-code.js.map +1 -0
  123. package/dist/enforcement/adapters/index.d.ts +2 -0
  124. package/dist/enforcement/adapters/index.d.ts.map +1 -0
  125. package/dist/enforcement/adapters/index.js +2 -0
  126. package/dist/enforcement/adapters/index.js.map +1 -0
  127. package/dist/enforcement/index.d.ts +4 -0
  128. package/dist/enforcement/index.d.ts.map +1 -0
  129. package/dist/enforcement/index.js +3 -0
  130. package/dist/enforcement/index.js.map +1 -0
  131. package/dist/enforcement/registry.d.ts +23 -0
  132. package/dist/enforcement/registry.d.ts.map +1 -0
  133. package/dist/enforcement/registry.js +63 -0
  134. package/dist/enforcement/registry.js.map +1 -0
  135. package/dist/enforcement/types.d.ts +51 -0
  136. package/dist/enforcement/types.d.ts.map +1 -0
  137. package/dist/enforcement/types.js +8 -0
  138. package/dist/enforcement/types.js.map +1 -0
  139. package/dist/facades/facade-factory.d.ts +10 -3
  140. package/dist/facades/facade-factory.d.ts.map +1 -1
  141. package/dist/facades/facade-factory.js +94 -5
  142. package/dist/facades/facade-factory.js.map +1 -1
  143. package/dist/facades/types.d.ts +15 -1
  144. package/dist/facades/types.d.ts.map +1 -1
  145. package/dist/facades/types.js +6 -0
  146. package/dist/facades/types.js.map +1 -1
  147. package/dist/health/health-registry.d.ts +40 -0
  148. package/dist/health/health-registry.d.ts.map +1 -0
  149. package/dist/health/health-registry.js +134 -0
  150. package/dist/health/health-registry.js.map +1 -0
  151. package/dist/health/index.d.ts +5 -0
  152. package/dist/health/index.d.ts.map +1 -0
  153. package/dist/health/index.js +3 -0
  154. package/dist/health/index.js.map +1 -0
  155. package/dist/health/vault-integrity.d.ts +13 -0
  156. package/dist/health/vault-integrity.d.ts.map +1 -0
  157. package/dist/health/vault-integrity.js +49 -0
  158. package/dist/health/vault-integrity.js.map +1 -0
  159. package/dist/index.d.ts +67 -6
  160. package/dist/index.d.ts.map +1 -1
  161. package/dist/index.js +51 -3
  162. package/dist/index.js.map +1 -1
  163. package/dist/intake/intake-pipeline.d.ts +0 -7
  164. package/dist/intake/intake-pipeline.d.ts.map +1 -1
  165. package/dist/intake/intake-pipeline.js +1 -1
  166. package/dist/intake/intake-pipeline.js.map +1 -1
  167. package/dist/intelligence/types.d.ts +1 -0
  168. package/dist/intelligence/types.d.ts.map +1 -1
  169. package/dist/migrations/index.d.ts +6 -0
  170. package/dist/migrations/index.d.ts.map +1 -0
  171. package/dist/migrations/index.js +5 -0
  172. package/dist/migrations/index.js.map +1 -0
  173. package/dist/migrations/migration-runner.d.ts +51 -0
  174. package/dist/migrations/migration-runner.d.ts.map +1 -0
  175. package/dist/migrations/migration-runner.js +141 -0
  176. package/dist/migrations/migration-runner.js.map +1 -0
  177. package/dist/packs/index.d.ts +10 -0
  178. package/dist/packs/index.d.ts.map +1 -0
  179. package/dist/packs/index.js +8 -0
  180. package/dist/packs/index.js.map +1 -0
  181. package/dist/packs/lockfile.d.ts +97 -0
  182. package/dist/packs/lockfile.d.ts.map +1 -0
  183. package/dist/packs/lockfile.js +129 -0
  184. package/dist/packs/lockfile.js.map +1 -0
  185. package/dist/packs/pack-installer.d.ts +41 -0
  186. package/dist/packs/pack-installer.d.ts.map +1 -0
  187. package/dist/packs/pack-installer.js +253 -0
  188. package/dist/packs/pack-installer.js.map +1 -0
  189. package/dist/packs/resolver.d.ts +51 -0
  190. package/dist/packs/resolver.d.ts.map +1 -0
  191. package/dist/packs/resolver.js +195 -0
  192. package/dist/packs/resolver.js.map +1 -0
  193. package/dist/packs/types.d.ts +186 -0
  194. package/dist/packs/types.d.ts.map +1 -0
  195. package/dist/packs/types.js +69 -0
  196. package/dist/packs/types.js.map +1 -0
  197. package/dist/persistence/postgres-provider.d.ts +42 -7
  198. package/dist/persistence/postgres-provider.d.ts.map +1 -1
  199. package/dist/persistence/postgres-provider.js +187 -46
  200. package/dist/persistence/postgres-provider.js.map +1 -1
  201. package/dist/planning/gap-analysis.d.ts.map +1 -1
  202. package/dist/planning/gap-analysis.js +3 -1
  203. package/dist/planning/gap-analysis.js.map +1 -1
  204. package/dist/playbooks/index.d.ts +2 -0
  205. package/dist/playbooks/index.d.ts.map +1 -1
  206. package/dist/playbooks/index.js +2 -0
  207. package/dist/playbooks/index.js.map +1 -1
  208. package/dist/playbooks/playbook-executor.d.ts +100 -0
  209. package/dist/playbooks/playbook-executor.d.ts.map +1 -0
  210. package/dist/playbooks/playbook-executor.js +207 -0
  211. package/dist/playbooks/playbook-executor.js.map +1 -0
  212. package/dist/plugins/index.d.ts +7 -0
  213. package/dist/plugins/index.d.ts.map +1 -0
  214. package/dist/plugins/index.js +7 -0
  215. package/dist/plugins/index.js.map +1 -0
  216. package/dist/plugins/plugin-loader.d.ts +28 -0
  217. package/dist/plugins/plugin-loader.d.ts.map +1 -0
  218. package/dist/plugins/plugin-loader.js +150 -0
  219. package/dist/plugins/plugin-loader.js.map +1 -0
  220. package/dist/plugins/plugin-registry.d.ts +58 -0
  221. package/dist/plugins/plugin-registry.d.ts.map +1 -0
  222. package/dist/plugins/plugin-registry.js +157 -0
  223. package/dist/plugins/plugin-registry.js.map +1 -0
  224. package/dist/plugins/types.d.ts +180 -0
  225. package/dist/plugins/types.d.ts.map +1 -0
  226. package/dist/plugins/types.js +48 -0
  227. package/dist/plugins/types.js.map +1 -0
  228. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  229. package/dist/runtime/admin-extra-ops.js +181 -8
  230. package/dist/runtime/admin-extra-ops.js.map +1 -1
  231. package/dist/runtime/capture-ops.d.ts.map +1 -1
  232. package/dist/runtime/capture-ops.js +106 -7
  233. package/dist/runtime/capture-ops.js.map +1 -1
  234. package/dist/runtime/deprecation.d.ts +33 -0
  235. package/dist/runtime/deprecation.d.ts.map +1 -0
  236. package/dist/runtime/deprecation.js +41 -0
  237. package/dist/runtime/deprecation.js.map +1 -0
  238. package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
  239. package/dist/runtime/facades/admin-facade.js +12 -1
  240. package/dist/runtime/facades/admin-facade.js.map +1 -1
  241. package/dist/runtime/facades/agency-facade.d.ts +7 -0
  242. package/dist/runtime/facades/agency-facade.d.ts.map +1 -0
  243. package/dist/runtime/facades/agency-facade.js +103 -0
  244. package/dist/runtime/facades/agency-facade.js.map +1 -0
  245. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  246. package/dist/runtime/facades/brain-facade.js +58 -0
  247. package/dist/runtime/facades/brain-facade.js.map +1 -1
  248. package/dist/runtime/facades/chat-facade.d.ts +7 -0
  249. package/dist/runtime/facades/chat-facade.d.ts.map +1 -0
  250. package/dist/runtime/facades/chat-facade.js +808 -0
  251. package/dist/runtime/facades/chat-facade.js.map +1 -0
  252. package/dist/runtime/facades/context-facade.d.ts +7 -0
  253. package/dist/runtime/facades/context-facade.d.ts.map +1 -0
  254. package/dist/runtime/facades/context-facade.js +45 -0
  255. package/dist/runtime/facades/context-facade.js.map +1 -0
  256. package/dist/runtime/facades/index.d.ts.map +1 -1
  257. package/dist/runtime/facades/index.js +18 -0
  258. package/dist/runtime/facades/index.js.map +1 -1
  259. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  260. package/dist/runtime/facades/vault-facade.js +247 -1
  261. package/dist/runtime/facades/vault-facade.js.map +1 -1
  262. package/dist/runtime/feature-flags.d.ts +18 -0
  263. package/dist/runtime/feature-flags.d.ts.map +1 -0
  264. package/dist/runtime/feature-flags.js +90 -0
  265. package/dist/runtime/feature-flags.js.map +1 -0
  266. package/dist/runtime/pack-ops.d.ts +9 -0
  267. package/dist/runtime/pack-ops.d.ts.map +1 -0
  268. package/dist/runtime/pack-ops.js +76 -0
  269. package/dist/runtime/pack-ops.js.map +1 -0
  270. package/dist/runtime/playbook-ops.d.ts +3 -7
  271. package/dist/runtime/playbook-ops.d.ts.map +1 -1
  272. package/dist/runtime/playbook-ops.js +101 -10
  273. package/dist/runtime/playbook-ops.js.map +1 -1
  274. package/dist/runtime/plugin-ops.d.ts +9 -0
  275. package/dist/runtime/plugin-ops.d.ts.map +1 -0
  276. package/dist/runtime/plugin-ops.js +235 -0
  277. package/dist/runtime/plugin-ops.js.map +1 -0
  278. package/dist/runtime/runtime.d.ts.map +1 -1
  279. package/dist/runtime/runtime.js +72 -5
  280. package/dist/runtime/runtime.js.map +1 -1
  281. package/dist/runtime/telemetry-ops.d.ts +10 -0
  282. package/dist/runtime/telemetry-ops.d.ts.map +1 -0
  283. package/dist/runtime/telemetry-ops.js +53 -0
  284. package/dist/runtime/telemetry-ops.js.map +1 -0
  285. package/dist/runtime/types.d.ts +35 -0
  286. package/dist/runtime/types.d.ts.map +1 -1
  287. package/dist/runtime/vault-sharing-ops.d.ts +13 -0
  288. package/dist/runtime/vault-sharing-ops.d.ts.map +1 -0
  289. package/dist/runtime/vault-sharing-ops.js +345 -0
  290. package/dist/runtime/vault-sharing-ops.js.map +1 -0
  291. package/dist/streams/index.d.ts +1 -1
  292. package/dist/streams/index.d.ts.map +1 -1
  293. package/dist/streams/index.js +1 -1
  294. package/dist/streams/index.js.map +1 -1
  295. package/dist/streams/replayable-stream.d.ts +13 -1
  296. package/dist/streams/replayable-stream.d.ts.map +1 -1
  297. package/dist/streams/replayable-stream.js +27 -3
  298. package/dist/streams/replayable-stream.js.map +1 -1
  299. package/dist/text/similarity.d.ts +0 -1
  300. package/dist/text/similarity.d.ts.map +1 -1
  301. package/dist/text/similarity.js +1 -1
  302. package/dist/text/similarity.js.map +1 -1
  303. package/dist/transport/http-server.d.ts +56 -0
  304. package/dist/transport/http-server.d.ts.map +1 -0
  305. package/dist/transport/http-server.js +210 -0
  306. package/dist/transport/http-server.js.map +1 -0
  307. package/dist/transport/index.d.ts +11 -0
  308. package/dist/transport/index.d.ts.map +1 -0
  309. package/dist/transport/index.js +10 -0
  310. package/dist/transport/index.js.map +1 -0
  311. package/dist/transport/lsp-server.d.ts +140 -0
  312. package/dist/transport/lsp-server.d.ts.map +1 -0
  313. package/dist/transport/lsp-server.js +239 -0
  314. package/dist/transport/lsp-server.js.map +1 -0
  315. package/dist/transport/rate-limiter.d.ts +35 -0
  316. package/dist/transport/rate-limiter.d.ts.map +1 -0
  317. package/dist/transport/rate-limiter.js +72 -0
  318. package/dist/transport/rate-limiter.js.map +1 -0
  319. package/dist/transport/session-manager.d.ts +49 -0
  320. package/dist/transport/session-manager.d.ts.map +1 -0
  321. package/dist/transport/session-manager.js +83 -0
  322. package/dist/transport/session-manager.js.map +1 -0
  323. package/dist/transport/token-auth.d.ts +29 -0
  324. package/dist/transport/token-auth.d.ts.map +1 -0
  325. package/dist/transport/token-auth.js +84 -0
  326. package/dist/transport/token-auth.js.map +1 -0
  327. package/dist/transport/types.d.ts +61 -0
  328. package/dist/transport/types.d.ts.map +1 -0
  329. package/dist/transport/types.js +5 -0
  330. package/dist/transport/types.js.map +1 -0
  331. package/dist/transport/ws-server.d.ts +78 -0
  332. package/dist/transport/ws-server.d.ts.map +1 -0
  333. package/dist/transport/ws-server.js +342 -0
  334. package/dist/transport/ws-server.js.map +1 -0
  335. package/dist/vault/git-vault-sync.d.ts +107 -0
  336. package/dist/vault/git-vault-sync.d.ts.map +1 -0
  337. package/dist/vault/git-vault-sync.js +251 -0
  338. package/dist/vault/git-vault-sync.js.map +1 -0
  339. package/dist/vault/knowledge-review.d.ts +67 -0
  340. package/dist/vault/knowledge-review.d.ts.map +1 -0
  341. package/dist/vault/knowledge-review.js +133 -0
  342. package/dist/vault/knowledge-review.js.map +1 -0
  343. package/dist/vault/obsidian-sync.d.ts +94 -0
  344. package/dist/vault/obsidian-sync.d.ts.map +1 -0
  345. package/dist/vault/obsidian-sync.js +247 -0
  346. package/dist/vault/obsidian-sync.js.map +1 -0
  347. package/dist/vault/scope-detector.d.ts +31 -0
  348. package/dist/vault/scope-detector.d.ts.map +1 -0
  349. package/dist/vault/scope-detector.js +182 -0
  350. package/dist/vault/scope-detector.js.map +1 -0
  351. package/dist/vault/vault-branching.d.ts +71 -0
  352. package/dist/vault/vault-branching.d.ts.map +1 -0
  353. package/dist/vault/vault-branching.js +180 -0
  354. package/dist/vault/vault-branching.js.map +1 -0
  355. package/dist/vault/vault-manager.d.ts +89 -0
  356. package/dist/vault/vault-manager.d.ts.map +1 -0
  357. package/dist/vault/vault-manager.js +199 -0
  358. package/dist/vault/vault-manager.js.map +1 -0
  359. package/dist/vault/vault-types.d.ts +30 -0
  360. package/dist/vault/vault-types.d.ts.map +1 -0
  361. package/dist/vault/vault-types.js +10 -0
  362. package/dist/vault/vault-types.js.map +1 -0
  363. package/dist/vault/vault.d.ts +10 -0
  364. package/dist/vault/vault.d.ts.map +1 -1
  365. package/dist/vault/vault.js +36 -3
  366. package/dist/vault/vault.js.map +1 -1
  367. package/package.json +1 -1
  368. package/src/__tests__/admin-extra-ops.test.ts +31 -11
  369. package/src/__tests__/agency-manager.test.ts +374 -0
  370. package/src/__tests__/agent-loop.test.ts +256 -0
  371. package/src/__tests__/capture-ops.test.ts +275 -0
  372. package/src/__tests__/chat-differentiators.test.ts +251 -0
  373. package/src/__tests__/chat-enhanced.test.ts +390 -0
  374. package/src/__tests__/chat-transport.test.ts +665 -0
  375. package/src/__tests__/claudemd.test.ts +282 -0
  376. package/src/__tests__/context-engine.test.ts +256 -0
  377. package/src/__tests__/core-ops.test.ts +97 -5
  378. package/src/__tests__/deprecation.test.ts +78 -0
  379. package/src/__tests__/enforcement.test.ts +153 -0
  380. package/src/__tests__/facade-factory.test.ts +271 -0
  381. package/src/__tests__/feature-flags.test.ts +138 -0
  382. package/src/__tests__/git-vault-sync.test.ts +230 -0
  383. package/src/__tests__/health-registry.test.ts +173 -0
  384. package/src/__tests__/knowledge-review.test.ts +104 -0
  385. package/src/__tests__/lsp-transport.test.ts +442 -0
  386. package/src/__tests__/migration-runner.test.ts +170 -0
  387. package/src/__tests__/normalize.test.ts +10 -0
  388. package/src/__tests__/obsidian-sync.test.ts +354 -0
  389. package/src/__tests__/pack-lockfile.test.ts +261 -0
  390. package/src/__tests__/pack-ops.test.ts +146 -0
  391. package/src/__tests__/pack-system.test.ts +423 -0
  392. package/src/__tests__/playbook-executor.test.ts +249 -0
  393. package/src/__tests__/playbook-ops-execution.test.ts +189 -0
  394. package/src/__tests__/plugin-ops.test.ts +411 -0
  395. package/src/__tests__/plugin-system.test.ts +509 -0
  396. package/src/__tests__/postgres-provider.test.ts +64 -6
  397. package/src/__tests__/replayable-stream.test.ts +112 -1
  398. package/src/__tests__/scope-detector.test.ts +121 -0
  399. package/src/__tests__/session-lifecycle.test.ts +259 -0
  400. package/src/__tests__/transport.test.ts +758 -0
  401. package/src/__tests__/vault-branching.test.ts +274 -0
  402. package/src/__tests__/vault-connect.test.ts +179 -0
  403. package/src/__tests__/vault-integrity.test.ts +71 -0
  404. package/src/__tests__/vault-manager.test.ts +238 -0
  405. package/src/__tests__/vault-scaling.test.ts +281 -0
  406. package/src/__tests__/vault-sharing.test.ts +270 -0
  407. package/src/__tests__/ws-transport.test.ts +479 -0
  408. package/src/agency/agency-manager.ts +326 -0
  409. package/src/agency/index.ts +13 -0
  410. package/src/agency/types.ts +88 -0
  411. package/src/brain/brain.ts +15 -11
  412. package/src/brain/intelligence.ts +103 -0
  413. package/src/brain/types.ts +26 -0
  414. package/src/chat/agent-loop-types.ts +99 -0
  415. package/src/chat/agent-loop.ts +357 -0
  416. package/src/chat/auth-manager.ts +171 -0
  417. package/src/chat/browser-session.ts +188 -0
  418. package/src/chat/cancellation.ts +99 -0
  419. package/src/chat/chat-session.ts +283 -0
  420. package/src/chat/file-handler.ts +230 -0
  421. package/src/chat/fragment-buffer.ts +160 -0
  422. package/src/chat/index.ts +72 -0
  423. package/src/chat/mcp-bridge.ts +135 -0
  424. package/src/chat/notifications.ts +164 -0
  425. package/src/chat/output-compressor.ts +116 -0
  426. package/src/chat/queue.ts +208 -0
  427. package/src/chat/response-chunker.ts +200 -0
  428. package/src/chat/self-update.ts +117 -0
  429. package/src/chat/types.ts +126 -0
  430. package/src/chat/voice.ts +134 -0
  431. package/src/claudemd/compose.ts +142 -0
  432. package/src/claudemd/index.ts +17 -0
  433. package/src/claudemd/inject.ts +170 -0
  434. package/src/claudemd/types.ts +45 -0
  435. package/src/context/context-engine.ts +302 -0
  436. package/src/context/index.ts +11 -0
  437. package/src/context/types.ts +69 -0
  438. package/src/enforcement/adapters/claude-code.ts +135 -0
  439. package/src/enforcement/adapters/index.ts +1 -0
  440. package/src/enforcement/index.ts +10 -0
  441. package/src/enforcement/registry.ts +82 -0
  442. package/src/enforcement/types.ts +56 -0
  443. package/src/facades/facade-factory.ts +138 -5
  444. package/src/facades/types.ts +21 -0
  445. package/src/health/health-registry.ts +165 -0
  446. package/src/health/index.ts +11 -0
  447. package/src/health/vault-integrity.ts +66 -0
  448. package/src/index.ts +294 -2
  449. package/src/intake/intake-pipeline.ts +1 -1
  450. package/src/intelligence/types.ts +1 -0
  451. package/src/migrations/index.ts +6 -0
  452. package/src/migrations/migration-runner.ts +185 -0
  453. package/src/packs/index.ts +20 -0
  454. package/src/packs/lockfile.ts +180 -0
  455. package/src/packs/pack-installer.ts +289 -0
  456. package/src/packs/resolver.ts +237 -0
  457. package/src/packs/types.ts +125 -0
  458. package/src/persistence/postgres-provider.ts +211 -58
  459. package/src/planning/gap-analysis.ts +52 -7
  460. package/src/playbooks/index.ts +11 -0
  461. package/src/playbooks/playbook-executor.ts +301 -0
  462. package/src/plugins/index.ts +19 -0
  463. package/src/plugins/plugin-loader.ts +183 -0
  464. package/src/plugins/plugin-registry.ts +187 -0
  465. package/src/plugins/types.ts +119 -0
  466. package/src/runtime/admin-extra-ops.ts +193 -8
  467. package/src/runtime/capture-ops.ts +113 -8
  468. package/src/runtime/deprecation.ts +58 -0
  469. package/src/runtime/facades/admin-facade.ts +16 -1
  470. package/src/runtime/facades/agency-facade.ts +111 -0
  471. package/src/runtime/facades/brain-facade.ts +60 -0
  472. package/src/runtime/facades/chat-facade.ts +918 -0
  473. package/src/runtime/facades/context-facade.ts +55 -0
  474. package/src/runtime/facades/index.ts +22 -1
  475. package/src/runtime/facades/vault-facade.ts +261 -1
  476. package/src/runtime/feature-flags.ts +101 -0
  477. package/src/runtime/pack-ops.ts +85 -0
  478. package/src/runtime/playbook-ops.ts +113 -9
  479. package/src/runtime/plugin-ops.ts +258 -0
  480. package/src/runtime/runtime.ts +84 -5
  481. package/src/runtime/telemetry-ops.ts +57 -0
  482. package/src/runtime/types.ts +35 -0
  483. package/src/runtime/vault-sharing-ops.ts +372 -0
  484. package/src/streams/index.ts +1 -1
  485. package/src/streams/replayable-stream.ts +34 -3
  486. package/src/text/similarity.ts +1 -1
  487. package/src/transport/http-server.ts +269 -0
  488. package/src/transport/index.ts +48 -0
  489. package/src/transport/lsp-server.ts +401 -0
  490. package/src/transport/rate-limiter.ts +97 -0
  491. package/src/transport/session-manager.ts +120 -0
  492. package/src/transport/token-auth.ts +96 -0
  493. package/src/transport/types.ts +66 -0
  494. package/src/transport/ws-server.ts +415 -0
  495. package/src/vault/git-vault-sync.ts +318 -0
  496. package/src/vault/knowledge-review.ts +221 -0
  497. package/src/vault/obsidian-sync.ts +346 -0
  498. package/src/vault/scope-detector.ts +219 -0
  499. package/src/vault/vault-branching.ts +264 -0
  500. package/src/vault/vault-manager.ts +237 -0
  501. package/src/vault/vault-types.ts +50 -0
  502. package/src/vault/vault.ts +41 -3
  503. package/src/governance/index.ts +0 -18
@@ -0,0 +1,401 @@
1
+ /**
2
+ * LSP Server — Language Server Protocol transport for editor-native agent integration.
3
+ *
4
+ * Speaks JSON-RPC 2.0 over stdio using the LSP wire format:
5
+ * Content-Length: <N>\r\n\r\n<JSON payload>
6
+ *
7
+ * Maps agent capabilities to LSP features:
8
+ * - Completions → vault search suggestions
9
+ * - Diagnostics → quality gate violations
10
+ * - Hover → pattern documentation
11
+ * - Code actions → agent ops
12
+ *
13
+ * Uses only node:readline + node:process (zero deps).
14
+ */
15
+
16
+ import type { LspTransportConfig, LspCapabilities } from './types.js';
17
+
18
+ // =============================================================================
19
+ // LSP TYPES (subset of the spec needed for transport)
20
+ // =============================================================================
21
+
22
+ /** JSON-RPC 2.0 request */
23
+ export interface LspRequest {
24
+ jsonrpc: '2.0';
25
+ id: number | string;
26
+ method: string;
27
+ params?: unknown;
28
+ }
29
+
30
+ /** JSON-RPC 2.0 notification (no id) */
31
+ export interface LspNotification {
32
+ jsonrpc: '2.0';
33
+ method: string;
34
+ params?: unknown;
35
+ }
36
+
37
+ /** JSON-RPC 2.0 response */
38
+ export interface LspResponse {
39
+ jsonrpc: '2.0';
40
+ id: number | string | null;
41
+ result?: unknown;
42
+ error?: { code: number; message: string; data?: unknown };
43
+ }
44
+
45
+ /** LSP Position */
46
+ export interface LspPosition {
47
+ line: number;
48
+ character: number;
49
+ }
50
+
51
+ /** LSP Range */
52
+ export interface LspRange {
53
+ start: LspPosition;
54
+ end: LspPosition;
55
+ }
56
+
57
+ /** LSP Diagnostic */
58
+ export interface LspDiagnostic {
59
+ range: LspRange;
60
+ severity?: number; // 1=Error, 2=Warning, 3=Info, 4=Hint
61
+ source?: string;
62
+ message: string;
63
+ code?: string | number;
64
+ }
65
+
66
+ /** LSP Completion Item */
67
+ export interface LspCompletionItem {
68
+ label: string;
69
+ kind?: number; // 1=Text, 6=Variable, 15=Snippet, etc.
70
+ detail?: string;
71
+ documentation?: string | { kind: 'markdown' | 'plaintext'; value: string };
72
+ insertText?: string;
73
+ }
74
+
75
+ /** LSP Hover */
76
+ export interface LspHover {
77
+ contents: string | { kind: 'markdown' | 'plaintext'; value: string };
78
+ range?: LspRange;
79
+ }
80
+
81
+ /** LSP Code Action */
82
+ export interface LspCodeAction {
83
+ title: string;
84
+ kind?: string; // e.g. 'quickfix', 'refactor', 'source'
85
+ diagnostics?: LspDiagnostic[];
86
+ command?: { title: string; command: string; arguments?: unknown[] };
87
+ }
88
+
89
+ // =============================================================================
90
+ // CALLBACKS
91
+ // =============================================================================
92
+
93
+ export interface LspServerCallbacks {
94
+ /** Return completions for the given document URI and position. */
95
+ onCompletion?: (uri: string, position: LspPosition) => Promise<LspCompletionItem[]>;
96
+ /** Return hover info for the given document URI and position. */
97
+ onHover?: (uri: string, position: LspPosition) => Promise<LspHover | null>;
98
+ /** Return diagnostics for the given document URI and content. */
99
+ onDiagnostics?: (uri: string, content: string) => Promise<LspDiagnostic[]>;
100
+ /** Return code actions for the given document URI, range, and current diagnostics. */
101
+ onCodeAction?: (
102
+ uri: string,
103
+ range: LspRange,
104
+ diagnostics: LspDiagnostic[],
105
+ ) => Promise<LspCodeAction[]>;
106
+ /** Called when the server is initialized. Return additional server info if desired. */
107
+ onInitialize?: () => Promise<{ name?: string; version?: string }>;
108
+ /** Called when a document is opened or changed. */
109
+ onDocumentChange?: (uri: string, content: string) => Promise<void>;
110
+ /** Called on shutdown. */
111
+ onShutdown?: () => Promise<void>;
112
+ }
113
+
114
+ // =============================================================================
115
+ // LSP SERVER
116
+ // =============================================================================
117
+
118
+ export class LspServer {
119
+ private config: LspTransportConfig;
120
+ private callbacks: LspServerCallbacks;
121
+ private capabilities: Required<LspCapabilities>;
122
+ private input: NodeJS.ReadableStream;
123
+ private output: NodeJS.WritableStream;
124
+ private running = false;
125
+ private buffer = '';
126
+ private contentLength = -1;
127
+ private initialized = false;
128
+
129
+ constructor(
130
+ config: LspTransportConfig,
131
+ callbacks: LspServerCallbacks,
132
+ input?: NodeJS.ReadableStream,
133
+ output?: NodeJS.WritableStream,
134
+ ) {
135
+ this.config = config;
136
+ this.callbacks = callbacks;
137
+ this.capabilities = {
138
+ completions: config.capabilities?.completions ?? true,
139
+ diagnostics: config.capabilities?.diagnostics ?? true,
140
+ hover: config.capabilities?.hover ?? true,
141
+ codeActions: config.capabilities?.codeActions ?? false,
142
+ };
143
+ this.input = input ?? process.stdin;
144
+ this.output = output ?? process.stdout;
145
+ }
146
+
147
+ /** Start listening for LSP messages on stdio. */
148
+ start(): void {
149
+ if (this.running) return;
150
+ this.running = true;
151
+ this.input.setEncoding('utf-8');
152
+ this.input.on('data', (chunk: string) => this.onData(chunk));
153
+ this.input.on('end', () => {
154
+ this.running = false;
155
+ });
156
+ }
157
+
158
+ /** Stop the server. */
159
+ async stop(): Promise<void> {
160
+ this.running = false;
161
+ this.input.removeAllListeners('data');
162
+ this.input.removeAllListeners('end');
163
+ }
164
+
165
+ /** Whether the server is currently running. */
166
+ get isRunning(): boolean {
167
+ return this.running;
168
+ }
169
+
170
+ /** Send a notification to the client (e.g., diagnostics). */
171
+ notify(method: string, params?: unknown): void {
172
+ this.writeMessage({ jsonrpc: '2.0', method, params });
173
+ }
174
+
175
+ /** Push diagnostics for a document. */
176
+ publishDiagnostics(uri: string, diagnostics: LspDiagnostic[]): void {
177
+ this.notify('textDocument/publishDiagnostics', { uri, diagnostics });
178
+ }
179
+
180
+ // ─── Message Parsing (LSP wire format) ─────────────────────────────
181
+
182
+ private onData(chunk: string): void {
183
+ this.buffer += chunk;
184
+ this.processBuffer();
185
+ }
186
+
187
+ private processBuffer(): void {
188
+ while (true) {
189
+ if (this.contentLength < 0) {
190
+ // Looking for headers
191
+ const headerEnd = this.buffer.indexOf('\r\n\r\n');
192
+ if (headerEnd < 0) return; // incomplete headers
193
+
194
+ const headers = this.buffer.substring(0, headerEnd);
195
+ const match = headers.match(/Content-Length:\s*(\d+)/i);
196
+ if (!match) {
197
+ // Skip malformed header
198
+ this.buffer = this.buffer.substring(headerEnd + 4);
199
+ continue;
200
+ }
201
+
202
+ this.contentLength = parseInt(match[1], 10);
203
+ this.buffer = this.buffer.substring(headerEnd + 4);
204
+ }
205
+
206
+ // Check if we have the full body
207
+ if (Buffer.byteLength(this.buffer, 'utf-8') < this.contentLength) return;
208
+
209
+ // Extract exactly contentLength bytes
210
+ const bodyBytes = Buffer.from(this.buffer, 'utf-8');
211
+ const body = bodyBytes.subarray(0, this.contentLength).toString('utf-8');
212
+ this.buffer = bodyBytes.subarray(this.contentLength).toString('utf-8');
213
+ this.contentLength = -1;
214
+
215
+ try {
216
+ const message = JSON.parse(body) as LspRequest | LspNotification;
217
+ this.handleMessage(message).catch(() => {
218
+ // Silently handle errors in message processing
219
+ });
220
+ } catch {
221
+ // Invalid JSON — skip
222
+ }
223
+ }
224
+ }
225
+
226
+ // ─── Message Handling ──────────────────────────────────────────────
227
+
228
+ private async handleMessage(message: LspRequest | LspNotification): Promise<void> {
229
+ const method = message.method;
230
+ const id = 'id' in message ? message.id : undefined;
231
+
232
+ switch (method) {
233
+ case 'initialize':
234
+ await this.handleInitialize(id as number | string);
235
+ break;
236
+ case 'initialized':
237
+ // Client acknowledgement — no response needed
238
+ break;
239
+ case 'shutdown':
240
+ await this.callbacks.onShutdown?.();
241
+ if (id !== undefined) {
242
+ this.respond(id as number | string, null);
243
+ }
244
+ break;
245
+ case 'exit':
246
+ this.running = false;
247
+ break;
248
+ case 'textDocument/completion':
249
+ await this.handleCompletion(id as number | string, message.params);
250
+ break;
251
+ case 'textDocument/hover':
252
+ await this.handleHover(id as number | string, message.params);
253
+ break;
254
+ case 'textDocument/codeAction':
255
+ await this.handleCodeAction(id as number | string, message.params);
256
+ break;
257
+ case 'textDocument/didOpen':
258
+ case 'textDocument/didChange':
259
+ await this.handleDocumentChange(message.params);
260
+ break;
261
+ case 'textDocument/didClose':
262
+ // No-op
263
+ break;
264
+ default:
265
+ // Unknown method — respond with MethodNotFound if it has an id
266
+ if (id !== undefined) {
267
+ this.respondError(id as number | string, -32601, `Method not found: ${method}`);
268
+ }
269
+ break;
270
+ }
271
+ }
272
+
273
+ private async handleInitialize(id: number | string): Promise<void> {
274
+ const info = await this.callbacks.onInitialize?.();
275
+
276
+ const serverCapabilities: Record<string, unknown> = {};
277
+
278
+ if (this.capabilities.completions) {
279
+ serverCapabilities.completionProvider = {
280
+ triggerCharacters: ['@', '/'],
281
+ resolveProvider: false,
282
+ };
283
+ }
284
+
285
+ if (this.capabilities.hover) {
286
+ serverCapabilities.hoverProvider = true;
287
+ }
288
+
289
+ if (this.capabilities.diagnostics) {
290
+ // Diagnostics are push-based via textDocument/publishDiagnostics
291
+ // We signal support via textDocumentSync
292
+ }
293
+
294
+ if (this.capabilities.codeActions) {
295
+ serverCapabilities.codeActionProvider = true;
296
+ }
297
+
298
+ // Always support text document sync (needed for diagnostics + change tracking)
299
+ serverCapabilities.textDocumentSync = {
300
+ openClose: true,
301
+ change: 1, // Full content on change
302
+ };
303
+
304
+ this.respond(id, {
305
+ capabilities: serverCapabilities,
306
+ serverInfo: {
307
+ name: info?.name ?? 'soleri-lsp',
308
+ version: info?.version ?? '0.1.0',
309
+ },
310
+ });
311
+
312
+ this.initialized = true;
313
+ }
314
+
315
+ private async handleCompletion(id: number | string, params: unknown): Promise<void> {
316
+ if (!this.capabilities.completions || !this.callbacks.onCompletion) {
317
+ this.respond(id, []);
318
+ return;
319
+ }
320
+
321
+ const p = params as {
322
+ textDocument: { uri: string };
323
+ position: LspPosition;
324
+ };
325
+
326
+ const items = await this.callbacks.onCompletion(p.textDocument.uri, p.position);
327
+ this.respond(id, items);
328
+ }
329
+
330
+ private async handleHover(id: number | string, params: unknown): Promise<void> {
331
+ if (!this.capabilities.hover || !this.callbacks.onHover) {
332
+ this.respond(id, null);
333
+ return;
334
+ }
335
+
336
+ const p = params as {
337
+ textDocument: { uri: string };
338
+ position: LspPosition;
339
+ };
340
+
341
+ const hover = await this.callbacks.onHover(p.textDocument.uri, p.position);
342
+ this.respond(id, hover);
343
+ }
344
+
345
+ private async handleCodeAction(id: number | string, params: unknown): Promise<void> {
346
+ if (!this.capabilities.codeActions || !this.callbacks.onCodeAction) {
347
+ this.respond(id, []);
348
+ return;
349
+ }
350
+
351
+ const p = params as {
352
+ textDocument: { uri: string };
353
+ range: LspRange;
354
+ context: { diagnostics: LspDiagnostic[] };
355
+ };
356
+
357
+ const actions = await this.callbacks.onCodeAction(
358
+ p.textDocument.uri,
359
+ p.range,
360
+ p.context.diagnostics,
361
+ );
362
+ this.respond(id, actions);
363
+ }
364
+
365
+ private async handleDocumentChange(params: unknown): Promise<void> {
366
+ const p = params as {
367
+ textDocument: { uri: string };
368
+ contentChanges?: Array<{ text: string }>;
369
+ // didOpen has text at top level via textDocument
370
+ };
371
+
372
+ const uri = p.textDocument.uri;
373
+ const content =
374
+ p.contentChanges?.[0]?.text ?? (p.textDocument as unknown as { text?: string }).text ?? '';
375
+
376
+ await this.callbacks.onDocumentChange?.(uri, content);
377
+
378
+ // If diagnostics are enabled, compute and push them
379
+ if (this.capabilities.diagnostics && this.callbacks.onDiagnostics && content) {
380
+ const diagnostics = await this.callbacks.onDiagnostics(uri, content);
381
+ this.publishDiagnostics(uri, diagnostics);
382
+ }
383
+ }
384
+
385
+ // ─── Response Helpers ──────────────────────────────────────────────
386
+
387
+ private respond(id: number | string, result: unknown): void {
388
+ this.writeMessage({ jsonrpc: '2.0', id, result });
389
+ }
390
+
391
+ private respondError(id: number | string, code: number, message: string): void {
392
+ this.writeMessage({ jsonrpc: '2.0', id, error: { code, message } });
393
+ }
394
+
395
+ private writeMessage(message: unknown): void {
396
+ const json = JSON.stringify(message);
397
+ const contentLength = Buffer.byteLength(json, 'utf-8');
398
+ const header = `Content-Length: ${contentLength}\r\n\r\n`;
399
+ this.output.write(header + json);
400
+ }
401
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Sliding Window Rate Limiter
3
+ *
4
+ * Per-key tracking (session ID or IP) with periodic self-cleanup.
5
+ * Returns Retry-After hint for 429 responses.
6
+ */
7
+
8
+ // =============================================================================
9
+ // TYPES
10
+ // =============================================================================
11
+
12
+ export interface RateLimitResult {
13
+ /** Whether the request is allowed */
14
+ allowed: boolean;
15
+ /** Remaining requests in current window */
16
+ remaining: number;
17
+ /** Milliseconds until the client can retry (0 if allowed) */
18
+ retryAfterMs: number;
19
+ }
20
+
21
+ // =============================================================================
22
+ // RATE LIMITER
23
+ // =============================================================================
24
+
25
+ export class RateLimiter {
26
+ private windows = new Map<string, number[]>();
27
+ private maxRequests: number;
28
+ private windowMs: number;
29
+ private cleanupCounter = 0;
30
+ private static readonly CLEANUP_INTERVAL = 100;
31
+
32
+ constructor(maxRequests = 100, windowMs = 60_000) {
33
+ this.maxRequests = maxRequests;
34
+ this.windowMs = windowMs;
35
+ }
36
+
37
+ /** Check if a request from the given key is allowed. Records timestamp if allowed. */
38
+ check(key: string): RateLimitResult {
39
+ const now = Date.now();
40
+ const windowStart = now - this.windowMs;
41
+
42
+ if (++this.cleanupCounter >= RateLimiter.CLEANUP_INTERVAL) {
43
+ this.cleanupCounter = 0;
44
+ this.cleanup(windowStart);
45
+ }
46
+
47
+ let timestamps = this.windows.get(key);
48
+ if (!timestamps) {
49
+ timestamps = [];
50
+ this.windows.set(key, timestamps);
51
+ }
52
+
53
+ // Remove expired timestamps
54
+ const filtered = timestamps.filter((t) => t > windowStart);
55
+ this.windows.set(key, filtered);
56
+
57
+ if (filtered.length >= this.maxRequests) {
58
+ const retryAfterMs = filtered[0] + this.windowMs - now;
59
+ return { allowed: false, remaining: 0, retryAfterMs: Math.max(retryAfterMs, 1) };
60
+ }
61
+
62
+ filtered.push(now);
63
+ return { allowed: true, remaining: this.maxRequests - filtered.length, retryAfterMs: 0 };
64
+ }
65
+
66
+ /** Reset rate limit state for a key. */
67
+ reset(key: string): void {
68
+ this.windows.delete(key);
69
+ }
70
+
71
+ /** Clear all rate limit state. */
72
+ clear(): void {
73
+ this.windows.clear();
74
+ }
75
+
76
+ /** Get current state for a key. */
77
+ getKeyState(key: string): { requestCount: number; remaining: number } {
78
+ const timestamps = this.windows.get(key);
79
+ const windowStart = Date.now() - this.windowMs;
80
+
81
+ if (!timestamps) return { requestCount: 0, remaining: this.maxRequests };
82
+
83
+ const active = timestamps.filter((t) => t > windowStart).length;
84
+ return { requestCount: active, remaining: Math.max(0, this.maxRequests - active) };
85
+ }
86
+
87
+ private cleanup(windowStart: number): void {
88
+ for (const [key, timestamps] of this.windows) {
89
+ const filtered = timestamps.filter((t) => t > windowStart);
90
+ if (filtered.length === 0) {
91
+ this.windows.delete(key);
92
+ } else {
93
+ this.windows.set(key, filtered);
94
+ }
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Session Manager — tracks HTTP transport sessions with TTL-based reaping.
3
+ *
4
+ * Each connected client gets a session entry. Sessions are reaped
5
+ * automatically after their TTL expires.
6
+ */
7
+
8
+ import { randomUUID } from 'node:crypto';
9
+
10
+ // =============================================================================
11
+ // TYPES
12
+ // =============================================================================
13
+
14
+ export interface Session {
15
+ id: string;
16
+ /** Opaque transport reference — the MCP SDK's StreamableHTTPServerTransport */
17
+ transport: unknown;
18
+ /** Opaque server reference — the MCP SDK's McpServer */
19
+ server: unknown;
20
+ createdAt: number;
21
+ }
22
+
23
+ export interface SessionManagerConfig {
24
+ /** Session TTL in ms. 0 to disable reaping. Default: 3600000 (1 hour). */
25
+ ttl?: number;
26
+ /** Reaper check interval in ms. Default: 60000 (1 minute). */
27
+ reaperInterval?: number;
28
+ /** Callback when a session is reaped. */
29
+ onReap?: (session: Session) => void;
30
+ }
31
+
32
+ // =============================================================================
33
+ // SESSION MANAGER
34
+ // =============================================================================
35
+
36
+ const DEFAULT_TTL = 60 * 60 * 1000; // 1 hour
37
+ const DEFAULT_REAPER_INTERVAL = 60 * 1000; // 1 minute
38
+
39
+ export class SessionManager {
40
+ private sessions = new Map<string, Session>();
41
+ private reaperTimer: ReturnType<typeof setInterval> | undefined;
42
+ private config: SessionManagerConfig;
43
+
44
+ constructor(config: SessionManagerConfig = {}) {
45
+ this.config = config;
46
+ }
47
+
48
+ /** Generate a new session ID. */
49
+ generateId(): string {
50
+ return randomUUID();
51
+ }
52
+
53
+ /** Register a new session. */
54
+ add(id: string, transport: unknown, server: unknown): Session {
55
+ const session: Session = { id, transport, server, createdAt: Date.now() };
56
+ this.sessions.set(id, session);
57
+ return session;
58
+ }
59
+
60
+ /** Get a session by ID. */
61
+ get(id: string): Session | undefined {
62
+ return this.sessions.get(id);
63
+ }
64
+
65
+ /** Remove a session. */
66
+ remove(id: string): boolean {
67
+ return this.sessions.delete(id);
68
+ }
69
+
70
+ /** Number of active sessions. */
71
+ get size(): number {
72
+ return this.sessions.size;
73
+ }
74
+
75
+ /** List all session IDs. */
76
+ listIds(): string[] {
77
+ return Array.from(this.sessions.keys());
78
+ }
79
+
80
+ /** Start the periodic session reaper. */
81
+ startReaper(): void {
82
+ const ttl = this.config.ttl ?? DEFAULT_TTL;
83
+ if (ttl <= 0) return;
84
+
85
+ const interval = this.config.reaperInterval ?? DEFAULT_REAPER_INTERVAL;
86
+ this.reaperTimer = setInterval(() => {
87
+ this.reap(ttl);
88
+ }, interval);
89
+
90
+ // Don't prevent process exit
91
+ if (this.reaperTimer && typeof this.reaperTimer === 'object' && 'unref' in this.reaperTimer) {
92
+ (this.reaperTimer as NodeJS.Timeout).unref();
93
+ }
94
+ }
95
+
96
+ /** Stop the reaper. */
97
+ stopReaper(): void {
98
+ if (this.reaperTimer) {
99
+ clearInterval(this.reaperTimer);
100
+ this.reaperTimer = undefined;
101
+ }
102
+ }
103
+
104
+ /** Close all sessions and stop reaper. */
105
+ close(): void {
106
+ this.stopReaper();
107
+ this.sessions.clear();
108
+ }
109
+
110
+ /** Evict sessions older than TTL. */
111
+ private reap(ttlMs: number): void {
112
+ const now = Date.now();
113
+ for (const [id, session] of this.sessions) {
114
+ if (now - session.createdAt > ttlMs) {
115
+ this.sessions.delete(id);
116
+ this.config.onReap?.(session);
117
+ }
118
+ }
119
+ }
120
+ }