@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,301 @@
1
+ /**
2
+ * Playbook Executor — in-memory runtime for step-by-step playbook execution.
3
+ *
4
+ * Lifecycle: start → step (repeat) → complete
5
+ *
6
+ * Sessions are ephemeral (in-memory, not persisted). For persistent workflows,
7
+ * use the planning system instead.
8
+ */
9
+
10
+ import type {
11
+ PlaybookDefinition,
12
+ MergedPlaybook,
13
+ PlaybookGate,
14
+ PlaybookTaskTemplate,
15
+ } from './playbook-types.js';
16
+
17
+ // =============================================================================
18
+ // TYPES
19
+ // =============================================================================
20
+
21
+ export type PlaybookStepStatus = 'pending' | 'active' | 'done' | 'skipped';
22
+
23
+ export interface PlaybookStepState {
24
+ index: number;
25
+ title: string;
26
+ description: string;
27
+ status: PlaybookStepStatus;
28
+ output?: string;
29
+ startedAt?: number;
30
+ completedAt?: number;
31
+ }
32
+
33
+ export interface PlaybookSession {
34
+ id: string;
35
+ playbookId: string;
36
+ label: string;
37
+ steps: PlaybookStepState[];
38
+ gates: PlaybookGate[];
39
+ taskTemplates: PlaybookTaskTemplate[];
40
+ tools: string[];
41
+ verificationCriteria: string[];
42
+ currentStepIndex: number;
43
+ status: 'active' | 'completed' | 'aborted';
44
+ startedAt: number;
45
+ completedAt?: number;
46
+ }
47
+
48
+ export interface StartResult {
49
+ sessionId: string;
50
+ label: string;
51
+ totalSteps: number;
52
+ currentStep: PlaybookStepState;
53
+ tools: string[];
54
+ gates: PlaybookGate[];
55
+ }
56
+
57
+ export interface StepResult {
58
+ sessionId: string;
59
+ completedStep: PlaybookStepState;
60
+ nextStep: PlaybookStepState | null;
61
+ progress: { done: number; total: number };
62
+ isComplete: boolean;
63
+ }
64
+
65
+ export interface CompleteResult {
66
+ sessionId: string;
67
+ label: string;
68
+ status: 'completed' | 'aborted';
69
+ steps: PlaybookStepState[];
70
+ gatesPassed: boolean;
71
+ unsatisfiedGates: string[];
72
+ duration: number;
73
+ }
74
+
75
+ // =============================================================================
76
+ // STEP PARSER
77
+ // =============================================================================
78
+
79
+ /**
80
+ * Parse step strings from a playbook's `steps` field into structured steps.
81
+ * Expects numbered steps like "1. Title\n - detail\n - detail"
82
+ */
83
+ function parseSteps(stepsText: string): Array<{ title: string; description: string }> {
84
+ const lines = stepsText.split('\n');
85
+ const steps: Array<{ title: string; description: string }> = [];
86
+ let current: { title: string; lines: string[] } | null = null;
87
+
88
+ for (const line of lines) {
89
+ const stepMatch = line.match(/^\s*(\d+)\.\s+(.+)/);
90
+ if (stepMatch) {
91
+ if (current) {
92
+ steps.push({ title: current.title, description: current.lines.join('\n').trim() });
93
+ }
94
+ current = { title: stepMatch[2].trim(), lines: [] };
95
+ } else if (current && line.trim()) {
96
+ current.lines.push(line);
97
+ }
98
+ }
99
+ if (current) {
100
+ steps.push({ title: current.title, description: current.lines.join('\n').trim() });
101
+ }
102
+
103
+ return steps;
104
+ }
105
+
106
+ // =============================================================================
107
+ // EXECUTOR
108
+ // =============================================================================
109
+
110
+ export class PlaybookExecutor {
111
+ private sessions = new Map<string, PlaybookSession>();
112
+
113
+ /**
114
+ * Start a playbook execution session.
115
+ * Accepts either a PlaybookDefinition or MergedPlaybook.
116
+ */
117
+ start(playbook: PlaybookDefinition | MergedPlaybook): StartResult {
118
+ const sessionId = `pbk-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
119
+
120
+ let label: string;
121
+ let playbookId: string;
122
+ let stepsText: string;
123
+ let gates: PlaybookGate[];
124
+ let taskTemplates: PlaybookTaskTemplate[];
125
+ let tools: string[];
126
+ let verificationCriteria: string[];
127
+
128
+ if ('mergedGates' in playbook) {
129
+ // MergedPlaybook
130
+ label = playbook.label;
131
+ playbookId = playbook.generic?.id ?? playbook.domain?.id ?? 'unknown';
132
+ stepsText = playbook.generic?.steps ?? playbook.domain?.steps ?? '';
133
+ gates = playbook.mergedGates;
134
+ taskTemplates = playbook.mergedTasks;
135
+ tools = playbook.mergedTools;
136
+ verificationCriteria = playbook.mergedVerification;
137
+ } else {
138
+ // PlaybookDefinition
139
+ label = playbook.title;
140
+ playbookId = playbook.id;
141
+ stepsText = playbook.steps;
142
+ gates = playbook.gates;
143
+ taskTemplates = playbook.taskTemplates;
144
+ tools = playbook.toolInjections;
145
+ verificationCriteria = playbook.verificationCriteria;
146
+ }
147
+
148
+ const parsed = parseSteps(stepsText);
149
+ if (parsed.length === 0) {
150
+ parsed.push({ title: label, description: 'Execute the playbook.' });
151
+ }
152
+
153
+ const steps: PlaybookStepState[] = parsed.map((s, i) => ({
154
+ index: i,
155
+ title: s.title,
156
+ description: s.description,
157
+ status: i === 0 ? 'active' : 'pending',
158
+ }));
159
+
160
+ const session: PlaybookSession = {
161
+ id: sessionId,
162
+ playbookId,
163
+ label,
164
+ steps,
165
+ gates,
166
+ taskTemplates,
167
+ tools,
168
+ verificationCriteria,
169
+ currentStepIndex: 0,
170
+ status: 'active',
171
+ startedAt: Date.now(),
172
+ };
173
+
174
+ steps[0].startedAt = Date.now();
175
+ this.sessions.set(sessionId, session);
176
+
177
+ return {
178
+ sessionId,
179
+ label,
180
+ totalSteps: steps.length,
181
+ currentStep: steps[0],
182
+ tools,
183
+ gates,
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Advance to the next step. Marks the current step as done (or skipped).
189
+ */
190
+ step(
191
+ sessionId: string,
192
+ options?: { output?: string; skip?: boolean },
193
+ ): StepResult | { error: string } {
194
+ const session = this.sessions.get(sessionId);
195
+ if (!session) return { error: `Session not found: ${sessionId}` };
196
+ if (session.status !== 'active') return { error: `Session is ${session.status}, not active` };
197
+
198
+ const current = session.steps[session.currentStepIndex];
199
+ current.status = options?.skip ? 'skipped' : 'done';
200
+ current.output = options?.output;
201
+ current.completedAt = Date.now();
202
+
203
+ const nextIndex = session.currentStepIndex + 1;
204
+ const isComplete = nextIndex >= session.steps.length;
205
+
206
+ let nextStep: PlaybookStepState | null = null;
207
+ if (!isComplete) {
208
+ session.currentStepIndex = nextIndex;
209
+ session.steps[nextIndex].status = 'active';
210
+ session.steps[nextIndex].startedAt = Date.now();
211
+ nextStep = session.steps[nextIndex];
212
+ }
213
+
214
+ const done = session.steps.filter((s) => s.status === 'done' || s.status === 'skipped').length;
215
+
216
+ return {
217
+ sessionId,
218
+ completedStep: current,
219
+ nextStep,
220
+ progress: { done, total: session.steps.length },
221
+ isComplete,
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Complete a playbook session. Validates gates and returns summary.
227
+ */
228
+ complete(
229
+ sessionId: string,
230
+ options?: { abort?: boolean; gateResults?: Record<string, boolean> },
231
+ ): CompleteResult | { error: string } {
232
+ const session = this.sessions.get(sessionId);
233
+ if (!session) return { error: `Session not found: ${sessionId}` };
234
+ if (session.status !== 'active') return { error: `Session is already ${session.status}` };
235
+
236
+ const abort = options?.abort ?? false;
237
+ const gateResults = options?.gateResults ?? {};
238
+
239
+ // Mark any remaining active/pending steps
240
+ for (const step of session.steps) {
241
+ if (step.status === 'active' || step.status === 'pending') {
242
+ step.status = abort ? 'skipped' : step.status;
243
+ if (step.status === 'active') {
244
+ step.status = 'done';
245
+ step.completedAt = Date.now();
246
+ }
247
+ }
248
+ }
249
+
250
+ // Validate gates
251
+ const completionGates = session.gates.filter((g) => g.phase === 'completion');
252
+ const unsatisfiedGates: string[] = [];
253
+ for (const gate of completionGates) {
254
+ if (!gateResults[gate.checkType]) {
255
+ unsatisfiedGates.push(`${gate.checkType}: ${gate.requirement}`);
256
+ }
257
+ }
258
+
259
+ session.status = abort ? 'aborted' : 'completed';
260
+ session.completedAt = Date.now();
261
+
262
+ const result: CompleteResult = {
263
+ sessionId,
264
+ label: session.label,
265
+ status: session.status,
266
+ steps: session.steps,
267
+ gatesPassed: unsatisfiedGates.length === 0,
268
+ unsatisfiedGates,
269
+ duration: session.completedAt - session.startedAt,
270
+ };
271
+
272
+ // Clean up after completion
273
+ this.sessions.delete(sessionId);
274
+
275
+ return result;
276
+ }
277
+
278
+ /**
279
+ * Get the current state of a session.
280
+ */
281
+ getSession(sessionId: string): PlaybookSession | undefined {
282
+ return this.sessions.get(sessionId);
283
+ }
284
+
285
+ /**
286
+ * List all active sessions.
287
+ */
288
+ listSessions(): Array<{ id: string; label: string; progress: string; startedAt: number }> {
289
+ return Array.from(this.sessions.values())
290
+ .filter((s) => s.status === 'active')
291
+ .map((s) => {
292
+ const done = s.steps.filter((st) => st.status === 'done' || st.status === 'skipped').length;
293
+ return {
294
+ id: s.id,
295
+ label: s.label,
296
+ progress: `${done}/${s.steps.length}`,
297
+ startedAt: s.startedAt,
298
+ };
299
+ });
300
+ }
301
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Plugin System — Barrel Exports
3
+ */
4
+
5
+ export {
6
+ pluginManifestSchema,
7
+ type PluginManifest,
8
+ type PluginStatus,
9
+ type PluginProvenance,
10
+ type LoadedPlugin,
11
+ type RegisteredPlugin,
12
+ type PluginFacadeBuilder,
13
+ type PluginContext,
14
+ type LoadResult,
15
+ } from './types.js';
16
+
17
+ export { loadPlugins, validateDependencies, sortByDependencies } from './plugin-loader.js';
18
+
19
+ export { PluginRegistry } from './plugin-registry.js';
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Plugin Loader — scans directories, validates manifests, loads plugins.
3
+ *
4
+ * Plugin directories (checked in order, first occurrence wins):
5
+ * 1. ~/.{agentId}/plugins/ (global plugins)
6
+ * 2. .{agentId}/plugins/ (project plugins)
7
+ * 3. Custom directories (via config)
8
+ *
9
+ * Each plugin is a directory containing `soleri-plugin.json`.
10
+ */
11
+
12
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
13
+ import { join } from 'node:path';
14
+ import { homedir } from 'node:os';
15
+ import {
16
+ pluginManifestSchema,
17
+ type LoadedPlugin,
18
+ type LoadResult,
19
+ type PluginProvenance,
20
+ } from './types.js';
21
+
22
+ // =============================================================================
23
+ // LOADER
24
+ // =============================================================================
25
+
26
+ const MANIFEST_FILENAME = 'soleri-plugin.json';
27
+
28
+ /**
29
+ * Load all plugins from standard + custom directories.
30
+ */
31
+ export function loadPlugins(
32
+ agentId: string,
33
+ projectPath?: string,
34
+ extraDirs: string[] = [],
35
+ ): LoadResult {
36
+ const result: LoadResult = { loaded: [], errors: [] };
37
+ const seen = new Set<string>();
38
+
39
+ const dirs: Array<{ path: string; provenance: PluginProvenance }> = [];
40
+
41
+ // Global: ~/.{agentId}/plugins/
42
+ const globalDir = join(homedir(), `.${agentId}`, 'plugins');
43
+ if (existsSync(globalDir)) {
44
+ dirs.push({ path: globalDir, provenance: 'global' });
45
+ }
46
+
47
+ // Project: .{agentId}/plugins/
48
+ if (projectPath) {
49
+ const projectDir = join(projectPath, `.${agentId}`, 'plugins');
50
+ if (existsSync(projectDir)) {
51
+ dirs.push({ path: projectDir, provenance: 'project' });
52
+ }
53
+ }
54
+
55
+ // Custom
56
+ for (const dir of extraDirs) {
57
+ if (existsSync(dir)) {
58
+ dirs.push({ path: dir, provenance: 'custom' });
59
+ }
60
+ }
61
+
62
+ for (const { path: parentDir, provenance } of dirs) {
63
+ try {
64
+ const entries = readdirSync(parentDir, { withFileTypes: true });
65
+ for (const entry of entries) {
66
+ if (!entry.isDirectory()) continue;
67
+
68
+ const pluginDir = join(parentDir, entry.name);
69
+ const loaded = loadSinglePlugin(pluginDir, provenance);
70
+
71
+ if (loaded.error) {
72
+ result.errors.push({ directory: pluginDir, error: loaded.error });
73
+ continue;
74
+ }
75
+
76
+ if (loaded.plugin) {
77
+ if (seen.has(loaded.plugin.manifest.id)) continue; // first wins
78
+ seen.add(loaded.plugin.manifest.id);
79
+ result.loaded.push(loaded.plugin);
80
+ }
81
+ }
82
+ } catch {
83
+ // Directory not scannable — skip
84
+ }
85
+ }
86
+
87
+ return result;
88
+ }
89
+
90
+ /**
91
+ * Load a single plugin from a directory.
92
+ */
93
+ function loadSinglePlugin(
94
+ pluginDir: string,
95
+ provenance: PluginProvenance,
96
+ ): { plugin?: LoadedPlugin; error?: string } {
97
+ const manifestPath = join(pluginDir, MANIFEST_FILENAME);
98
+
99
+ if (!existsSync(manifestPath)) {
100
+ return { error: `No ${MANIFEST_FILENAME} found in ${pluginDir}` };
101
+ }
102
+
103
+ let raw: unknown;
104
+ try {
105
+ raw = JSON.parse(readFileSync(manifestPath, 'utf-8'));
106
+ } catch (e) {
107
+ return {
108
+ error: `Invalid JSON in ${manifestPath}: ${e instanceof Error ? e.message : String(e)}`,
109
+ };
110
+ }
111
+
112
+ const parseResult = pluginManifestSchema.safeParse(raw);
113
+ if (!parseResult.success) {
114
+ const issues = parseResult.error.issues
115
+ .map((i) => `${i.path.join('.')}: ${i.message}`)
116
+ .join('; ');
117
+ return { error: `Invalid manifest in ${pluginDir}: ${issues}` };
118
+ }
119
+
120
+ return {
121
+ plugin: {
122
+ manifest: parseResult.data,
123
+ directory: pluginDir,
124
+ provenance,
125
+ },
126
+ };
127
+ }
128
+
129
+ // =============================================================================
130
+ // DEPENDENCY HELPERS
131
+ // =============================================================================
132
+
133
+ /**
134
+ * Validate that all plugin dependencies are satisfiable.
135
+ */
136
+ export function validateDependencies(
137
+ plugins: LoadedPlugin[],
138
+ ): Array<{ pluginId: string; missingDep: string }> {
139
+ const available = new Set(plugins.map((p) => p.manifest.id));
140
+ const errors: Array<{ pluginId: string; missingDep: string }> = [];
141
+
142
+ for (const { manifest } of plugins) {
143
+ for (const dep of manifest.dependencies) {
144
+ if (!available.has(dep)) {
145
+ errors.push({ pluginId: manifest.id, missingDep: dep });
146
+ }
147
+ }
148
+ }
149
+
150
+ return errors;
151
+ }
152
+
153
+ /**
154
+ * Topological sort by dependency order (no-deps first).
155
+ * Detects and breaks circular dependencies.
156
+ */
157
+ export function sortByDependencies(plugins: LoadedPlugin[]): LoadedPlugin[] {
158
+ const byId = new Map(plugins.map((p) => [p.manifest.id, p]));
159
+ const sorted: LoadedPlugin[] = [];
160
+ const visited = new Set<string>();
161
+ const visiting = new Set<string>();
162
+
163
+ function visit(id: string): void {
164
+ if (visited.has(id)) return;
165
+ if (visiting.has(id)) return; // circular — break
166
+ visiting.add(id);
167
+ const plugin = byId.get(id);
168
+ if (plugin) {
169
+ for (const dep of plugin.manifest.dependencies) {
170
+ visit(dep);
171
+ }
172
+ sorted.push(plugin);
173
+ }
174
+ visiting.delete(id);
175
+ visited.add(id);
176
+ }
177
+
178
+ for (const { manifest } of plugins) {
179
+ visit(manifest.id);
180
+ }
181
+
182
+ return sorted;
183
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Plugin Registry — tracks loaded plugins and their lifecycle.
3
+ *
4
+ * Not a singleton — lives on AgentRuntime for testability.
5
+ * Lifecycle: load → register → activate → (deactivate | error)
6
+ */
7
+
8
+ import type {
9
+ LoadedPlugin,
10
+ RegisteredPlugin,
11
+ PluginContext,
12
+ PluginFacadeBuilder,
13
+ } from './types.js';
14
+ import type { FacadeConfig, OpDefinition } from '../facades/types.js';
15
+ import { existsSync } from 'node:fs';
16
+ import { join } from 'node:path';
17
+ import { pathToFileURL } from 'node:url';
18
+
19
+ export class PluginRegistry {
20
+ private plugins = new Map<string, RegisteredPlugin>();
21
+
22
+ /**
23
+ * Register a loaded plugin. Does NOT activate it — call activate() separately.
24
+ */
25
+ register(loaded: LoadedPlugin): RegisteredPlugin {
26
+ const existing = this.plugins.get(loaded.manifest.id);
27
+ if (existing) {
28
+ throw new Error(`Plugin "${loaded.manifest.id}" is already registered`);
29
+ }
30
+
31
+ const registered: RegisteredPlugin = {
32
+ id: loaded.manifest.id,
33
+ manifest: loaded.manifest,
34
+ directory: loaded.directory,
35
+ provenance: loaded.provenance,
36
+ status: 'registered',
37
+ facades: [],
38
+ registeredAt: Date.now(),
39
+ };
40
+
41
+ this.plugins.set(registered.id, registered);
42
+ return registered;
43
+ }
44
+
45
+ /**
46
+ * Activate a plugin — builds facades from its manifest or JS module.
47
+ *
48
+ * If the plugin directory contains an `index.js` with a `createFacades` export,
49
+ * that function is called to build facades dynamically. Otherwise, facade stubs
50
+ * are created from the manifest's `facades` array (static ops with no-op handlers).
51
+ */
52
+ async activate(pluginId: string, ctx: PluginContext): Promise<RegisteredPlugin> {
53
+ const plugin = this.plugins.get(pluginId);
54
+ if (!plugin) throw new Error(`Plugin "${pluginId}" is not registered`);
55
+ if (plugin.status === 'active') return plugin;
56
+
57
+ try {
58
+ // Try dynamic facade builder first
59
+ let facades = await this.tryLoadFacadeBuilder(plugin, ctx);
60
+
61
+ // Fall back to static manifest facades
62
+ if (!facades) {
63
+ facades = this.buildStaticFacades(plugin);
64
+ }
65
+
66
+ plugin.facades = facades;
67
+ plugin.status = 'active';
68
+ plugin.activatedAt = Date.now();
69
+ plugin.error = undefined;
70
+ } catch (e) {
71
+ plugin.status = 'error';
72
+ plugin.error = e instanceof Error ? e.message : String(e);
73
+ }
74
+
75
+ return plugin;
76
+ }
77
+
78
+ /**
79
+ * Deactivate a plugin — removes its facades from the runtime.
80
+ */
81
+ deactivate(pluginId: string): boolean {
82
+ const plugin = this.plugins.get(pluginId);
83
+ if (!plugin) return false;
84
+
85
+ plugin.status = 'deactivated';
86
+ plugin.facades = [];
87
+ return true;
88
+ }
89
+
90
+ /**
91
+ * Unregister a plugin completely.
92
+ */
93
+ unregister(pluginId: string): boolean {
94
+ const plugin = this.plugins.get(pluginId);
95
+ if (!plugin) return false;
96
+
97
+ if (plugin.status === 'active') {
98
+ this.deactivate(pluginId);
99
+ }
100
+
101
+ return this.plugins.delete(pluginId);
102
+ }
103
+
104
+ /**
105
+ * Get a registered plugin by ID.
106
+ */
107
+ get(pluginId: string): RegisteredPlugin | undefined {
108
+ return this.plugins.get(pluginId);
109
+ }
110
+
111
+ /**
112
+ * List all registered plugins.
113
+ */
114
+ list(): RegisteredPlugin[] {
115
+ return Array.from(this.plugins.values());
116
+ }
117
+
118
+ /**
119
+ * Get all active facades from all active plugins.
120
+ */
121
+ getActiveFacades(): FacadeConfig[] {
122
+ const facades: FacadeConfig[] = [];
123
+ for (const plugin of this.plugins.values()) {
124
+ if (plugin.status === 'active') {
125
+ facades.push(...plugin.facades);
126
+ }
127
+ }
128
+ return facades;
129
+ }
130
+
131
+ /**
132
+ * Get all active ops (flattened from all active plugin facades).
133
+ */
134
+ getActiveOps(): OpDefinition[] {
135
+ return this.getActiveFacades().flatMap((f) => f.ops);
136
+ }
137
+
138
+ // ─── Private ────────────────────────────────────────────────────────
139
+
140
+ /**
141
+ * Try to load a JS module with `createFacades` export from the plugin directory.
142
+ * Returns null if no module found or no export.
143
+ */
144
+ private async tryLoadFacadeBuilder(
145
+ plugin: RegisteredPlugin,
146
+ ctx: PluginContext,
147
+ ): Promise<FacadeConfig[] | null> {
148
+ const moduleFile = join(plugin.directory, 'index.js');
149
+ if (!existsSync(moduleFile)) {
150
+ return null;
151
+ }
152
+
153
+ try {
154
+ // Dynamic import of plugin's index.js
155
+ const mod = (await import(pathToFileURL(moduleFile).href)) as {
156
+ createFacades?: PluginFacadeBuilder;
157
+ };
158
+ if (typeof mod.createFacades === 'function') {
159
+ return mod.createFacades(ctx);
160
+ }
161
+ throw new Error(`Plugin module "${moduleFile}" must export createFacades(ctx)`);
162
+ } catch (e) {
163
+ throw new Error(
164
+ `Failed to load plugin module "${moduleFile}": ${e instanceof Error ? e.message : String(e)}`, { cause: e },
165
+ );
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Build facade configs from the manifest's static facade definitions.
171
+ * These have no-op handlers — useful for schema discovery and documentation.
172
+ */
173
+ private buildStaticFacades(plugin: RegisteredPlugin): FacadeConfig[] {
174
+ return plugin.manifest.facades.map((f) => ({
175
+ name: f.name,
176
+ description: f.description,
177
+ ops: f.ops.map((op) => ({
178
+ name: op.name,
179
+ description: op.description,
180
+ auth: op.auth as 'read' | 'write' | 'admin',
181
+ handler: async () => ({
182
+ error: `Op "${op.name}" is a static plugin op — no handler implementation provided. Add an index.js with createFacades() to ${plugin.directory}`,
183
+ }),
184
+ })),
185
+ }));
186
+ }
187
+ }