@soleri/core 2.10.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 (499) 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/playbooks/index.d.ts +2 -0
  202. package/dist/playbooks/index.d.ts.map +1 -1
  203. package/dist/playbooks/index.js +2 -0
  204. package/dist/playbooks/index.js.map +1 -1
  205. package/dist/playbooks/playbook-executor.d.ts +100 -0
  206. package/dist/playbooks/playbook-executor.d.ts.map +1 -0
  207. package/dist/playbooks/playbook-executor.js +207 -0
  208. package/dist/playbooks/playbook-executor.js.map +1 -0
  209. package/dist/plugins/index.d.ts +7 -0
  210. package/dist/plugins/index.d.ts.map +1 -0
  211. package/dist/plugins/index.js +7 -0
  212. package/dist/plugins/index.js.map +1 -0
  213. package/dist/plugins/plugin-loader.d.ts +28 -0
  214. package/dist/plugins/plugin-loader.d.ts.map +1 -0
  215. package/dist/plugins/plugin-loader.js +150 -0
  216. package/dist/plugins/plugin-loader.js.map +1 -0
  217. package/dist/plugins/plugin-registry.d.ts +58 -0
  218. package/dist/plugins/plugin-registry.d.ts.map +1 -0
  219. package/dist/plugins/plugin-registry.js +157 -0
  220. package/dist/plugins/plugin-registry.js.map +1 -0
  221. package/dist/plugins/types.d.ts +180 -0
  222. package/dist/plugins/types.d.ts.map +1 -0
  223. package/dist/plugins/types.js +48 -0
  224. package/dist/plugins/types.js.map +1 -0
  225. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  226. package/dist/runtime/admin-extra-ops.js +181 -8
  227. package/dist/runtime/admin-extra-ops.js.map +1 -1
  228. package/dist/runtime/capture-ops.d.ts.map +1 -1
  229. package/dist/runtime/capture-ops.js +106 -7
  230. package/dist/runtime/capture-ops.js.map +1 -1
  231. package/dist/runtime/deprecation.d.ts +33 -0
  232. package/dist/runtime/deprecation.d.ts.map +1 -0
  233. package/dist/runtime/deprecation.js +41 -0
  234. package/dist/runtime/deprecation.js.map +1 -0
  235. package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
  236. package/dist/runtime/facades/admin-facade.js +12 -1
  237. package/dist/runtime/facades/admin-facade.js.map +1 -1
  238. package/dist/runtime/facades/agency-facade.d.ts +7 -0
  239. package/dist/runtime/facades/agency-facade.d.ts.map +1 -0
  240. package/dist/runtime/facades/agency-facade.js +103 -0
  241. package/dist/runtime/facades/agency-facade.js.map +1 -0
  242. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  243. package/dist/runtime/facades/brain-facade.js +58 -0
  244. package/dist/runtime/facades/brain-facade.js.map +1 -1
  245. package/dist/runtime/facades/chat-facade.d.ts +7 -0
  246. package/dist/runtime/facades/chat-facade.d.ts.map +1 -0
  247. package/dist/runtime/facades/chat-facade.js +808 -0
  248. package/dist/runtime/facades/chat-facade.js.map +1 -0
  249. package/dist/runtime/facades/context-facade.d.ts +7 -0
  250. package/dist/runtime/facades/context-facade.d.ts.map +1 -0
  251. package/dist/runtime/facades/context-facade.js +45 -0
  252. package/dist/runtime/facades/context-facade.js.map +1 -0
  253. package/dist/runtime/facades/index.d.ts.map +1 -1
  254. package/dist/runtime/facades/index.js +18 -0
  255. package/dist/runtime/facades/index.js.map +1 -1
  256. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  257. package/dist/runtime/facades/vault-facade.js +247 -1
  258. package/dist/runtime/facades/vault-facade.js.map +1 -1
  259. package/dist/runtime/feature-flags.d.ts +18 -0
  260. package/dist/runtime/feature-flags.d.ts.map +1 -0
  261. package/dist/runtime/feature-flags.js +90 -0
  262. package/dist/runtime/feature-flags.js.map +1 -0
  263. package/dist/runtime/pack-ops.d.ts +9 -0
  264. package/dist/runtime/pack-ops.d.ts.map +1 -0
  265. package/dist/runtime/pack-ops.js +76 -0
  266. package/dist/runtime/pack-ops.js.map +1 -0
  267. package/dist/runtime/playbook-ops.d.ts +3 -7
  268. package/dist/runtime/playbook-ops.d.ts.map +1 -1
  269. package/dist/runtime/playbook-ops.js +101 -10
  270. package/dist/runtime/playbook-ops.js.map +1 -1
  271. package/dist/runtime/plugin-ops.d.ts +9 -0
  272. package/dist/runtime/plugin-ops.d.ts.map +1 -0
  273. package/dist/runtime/plugin-ops.js +235 -0
  274. package/dist/runtime/plugin-ops.js.map +1 -0
  275. package/dist/runtime/runtime.d.ts.map +1 -1
  276. package/dist/runtime/runtime.js +72 -5
  277. package/dist/runtime/runtime.js.map +1 -1
  278. package/dist/runtime/telemetry-ops.d.ts +10 -0
  279. package/dist/runtime/telemetry-ops.d.ts.map +1 -0
  280. package/dist/runtime/telemetry-ops.js +53 -0
  281. package/dist/runtime/telemetry-ops.js.map +1 -0
  282. package/dist/runtime/types.d.ts +35 -0
  283. package/dist/runtime/types.d.ts.map +1 -1
  284. package/dist/runtime/vault-sharing-ops.d.ts +13 -0
  285. package/dist/runtime/vault-sharing-ops.d.ts.map +1 -0
  286. package/dist/runtime/vault-sharing-ops.js +345 -0
  287. package/dist/runtime/vault-sharing-ops.js.map +1 -0
  288. package/dist/streams/index.d.ts +1 -1
  289. package/dist/streams/index.d.ts.map +1 -1
  290. package/dist/streams/index.js +1 -1
  291. package/dist/streams/index.js.map +1 -1
  292. package/dist/streams/replayable-stream.d.ts +13 -1
  293. package/dist/streams/replayable-stream.d.ts.map +1 -1
  294. package/dist/streams/replayable-stream.js +27 -3
  295. package/dist/streams/replayable-stream.js.map +1 -1
  296. package/dist/text/similarity.d.ts +0 -1
  297. package/dist/text/similarity.d.ts.map +1 -1
  298. package/dist/text/similarity.js +1 -1
  299. package/dist/text/similarity.js.map +1 -1
  300. package/dist/transport/http-server.d.ts +56 -0
  301. package/dist/transport/http-server.d.ts.map +1 -0
  302. package/dist/transport/http-server.js +210 -0
  303. package/dist/transport/http-server.js.map +1 -0
  304. package/dist/transport/index.d.ts +11 -0
  305. package/dist/transport/index.d.ts.map +1 -0
  306. package/dist/transport/index.js +10 -0
  307. package/dist/transport/index.js.map +1 -0
  308. package/dist/transport/lsp-server.d.ts +140 -0
  309. package/dist/transport/lsp-server.d.ts.map +1 -0
  310. package/dist/transport/lsp-server.js +239 -0
  311. package/dist/transport/lsp-server.js.map +1 -0
  312. package/dist/transport/rate-limiter.d.ts +35 -0
  313. package/dist/transport/rate-limiter.d.ts.map +1 -0
  314. package/dist/transport/rate-limiter.js +72 -0
  315. package/dist/transport/rate-limiter.js.map +1 -0
  316. package/dist/transport/session-manager.d.ts +49 -0
  317. package/dist/transport/session-manager.d.ts.map +1 -0
  318. package/dist/transport/session-manager.js +83 -0
  319. package/dist/transport/session-manager.js.map +1 -0
  320. package/dist/transport/token-auth.d.ts +29 -0
  321. package/dist/transport/token-auth.d.ts.map +1 -0
  322. package/dist/transport/token-auth.js +84 -0
  323. package/dist/transport/token-auth.js.map +1 -0
  324. package/dist/transport/types.d.ts +61 -0
  325. package/dist/transport/types.d.ts.map +1 -0
  326. package/dist/transport/types.js +5 -0
  327. package/dist/transport/types.js.map +1 -0
  328. package/dist/transport/ws-server.d.ts +78 -0
  329. package/dist/transport/ws-server.d.ts.map +1 -0
  330. package/dist/transport/ws-server.js +342 -0
  331. package/dist/transport/ws-server.js.map +1 -0
  332. package/dist/vault/git-vault-sync.d.ts +107 -0
  333. package/dist/vault/git-vault-sync.d.ts.map +1 -0
  334. package/dist/vault/git-vault-sync.js +251 -0
  335. package/dist/vault/git-vault-sync.js.map +1 -0
  336. package/dist/vault/knowledge-review.d.ts +67 -0
  337. package/dist/vault/knowledge-review.d.ts.map +1 -0
  338. package/dist/vault/knowledge-review.js +133 -0
  339. package/dist/vault/knowledge-review.js.map +1 -0
  340. package/dist/vault/obsidian-sync.d.ts +94 -0
  341. package/dist/vault/obsidian-sync.d.ts.map +1 -0
  342. package/dist/vault/obsidian-sync.js +247 -0
  343. package/dist/vault/obsidian-sync.js.map +1 -0
  344. package/dist/vault/scope-detector.d.ts +31 -0
  345. package/dist/vault/scope-detector.d.ts.map +1 -0
  346. package/dist/vault/scope-detector.js +182 -0
  347. package/dist/vault/scope-detector.js.map +1 -0
  348. package/dist/vault/vault-branching.d.ts +71 -0
  349. package/dist/vault/vault-branching.d.ts.map +1 -0
  350. package/dist/vault/vault-branching.js +180 -0
  351. package/dist/vault/vault-branching.js.map +1 -0
  352. package/dist/vault/vault-manager.d.ts +89 -0
  353. package/dist/vault/vault-manager.d.ts.map +1 -0
  354. package/dist/vault/vault-manager.js +199 -0
  355. package/dist/vault/vault-manager.js.map +1 -0
  356. package/dist/vault/vault-types.d.ts +30 -0
  357. package/dist/vault/vault-types.d.ts.map +1 -0
  358. package/dist/vault/vault-types.js +10 -0
  359. package/dist/vault/vault-types.js.map +1 -0
  360. package/dist/vault/vault.d.ts +10 -0
  361. package/dist/vault/vault.d.ts.map +1 -1
  362. package/dist/vault/vault.js +36 -3
  363. package/dist/vault/vault.js.map +1 -1
  364. package/package.json +1 -1
  365. package/src/__tests__/admin-extra-ops.test.ts +31 -11
  366. package/src/__tests__/agency-manager.test.ts +374 -0
  367. package/src/__tests__/agent-loop.test.ts +256 -0
  368. package/src/__tests__/capture-ops.test.ts +275 -0
  369. package/src/__tests__/chat-differentiators.test.ts +251 -0
  370. package/src/__tests__/chat-enhanced.test.ts +390 -0
  371. package/src/__tests__/chat-transport.test.ts +665 -0
  372. package/src/__tests__/claudemd.test.ts +282 -0
  373. package/src/__tests__/context-engine.test.ts +256 -0
  374. package/src/__tests__/core-ops.test.ts +97 -5
  375. package/src/__tests__/deprecation.test.ts +78 -0
  376. package/src/__tests__/enforcement.test.ts +153 -0
  377. package/src/__tests__/facade-factory.test.ts +271 -0
  378. package/src/__tests__/feature-flags.test.ts +138 -0
  379. package/src/__tests__/git-vault-sync.test.ts +230 -0
  380. package/src/__tests__/health-registry.test.ts +173 -0
  381. package/src/__tests__/knowledge-review.test.ts +104 -0
  382. package/src/__tests__/lsp-transport.test.ts +442 -0
  383. package/src/__tests__/migration-runner.test.ts +170 -0
  384. package/src/__tests__/normalize.test.ts +10 -0
  385. package/src/__tests__/obsidian-sync.test.ts +354 -0
  386. package/src/__tests__/pack-lockfile.test.ts +261 -0
  387. package/src/__tests__/pack-ops.test.ts +146 -0
  388. package/src/__tests__/pack-system.test.ts +423 -0
  389. package/src/__tests__/playbook-executor.test.ts +249 -0
  390. package/src/__tests__/playbook-ops-execution.test.ts +189 -0
  391. package/src/__tests__/plugin-ops.test.ts +411 -0
  392. package/src/__tests__/plugin-system.test.ts +509 -0
  393. package/src/__tests__/postgres-provider.test.ts +64 -6
  394. package/src/__tests__/replayable-stream.test.ts +112 -1
  395. package/src/__tests__/scope-detector.test.ts +121 -0
  396. package/src/__tests__/session-lifecycle.test.ts +259 -0
  397. package/src/__tests__/transport.test.ts +758 -0
  398. package/src/__tests__/vault-branching.test.ts +274 -0
  399. package/src/__tests__/vault-connect.test.ts +179 -0
  400. package/src/__tests__/vault-integrity.test.ts +71 -0
  401. package/src/__tests__/vault-manager.test.ts +238 -0
  402. package/src/__tests__/vault-scaling.test.ts +281 -0
  403. package/src/__tests__/vault-sharing.test.ts +270 -0
  404. package/src/__tests__/ws-transport.test.ts +479 -0
  405. package/src/agency/agency-manager.ts +326 -0
  406. package/src/agency/index.ts +13 -0
  407. package/src/agency/types.ts +88 -0
  408. package/src/brain/brain.ts +15 -11
  409. package/src/brain/intelligence.ts +103 -0
  410. package/src/brain/types.ts +26 -0
  411. package/src/chat/agent-loop-types.ts +99 -0
  412. package/src/chat/agent-loop.ts +357 -0
  413. package/src/chat/auth-manager.ts +171 -0
  414. package/src/chat/browser-session.ts +188 -0
  415. package/src/chat/cancellation.ts +99 -0
  416. package/src/chat/chat-session.ts +283 -0
  417. package/src/chat/file-handler.ts +230 -0
  418. package/src/chat/fragment-buffer.ts +160 -0
  419. package/src/chat/index.ts +72 -0
  420. package/src/chat/mcp-bridge.ts +135 -0
  421. package/src/chat/notifications.ts +164 -0
  422. package/src/chat/output-compressor.ts +116 -0
  423. package/src/chat/queue.ts +208 -0
  424. package/src/chat/response-chunker.ts +200 -0
  425. package/src/chat/self-update.ts +117 -0
  426. package/src/chat/types.ts +126 -0
  427. package/src/chat/voice.ts +134 -0
  428. package/src/claudemd/compose.ts +142 -0
  429. package/src/claudemd/index.ts +17 -0
  430. package/src/claudemd/inject.ts +170 -0
  431. package/src/claudemd/types.ts +45 -0
  432. package/src/context/context-engine.ts +302 -0
  433. package/src/context/index.ts +11 -0
  434. package/src/context/types.ts +69 -0
  435. package/src/enforcement/adapters/claude-code.ts +135 -0
  436. package/src/enforcement/adapters/index.ts +1 -0
  437. package/src/enforcement/index.ts +10 -0
  438. package/src/enforcement/registry.ts +82 -0
  439. package/src/enforcement/types.ts +56 -0
  440. package/src/facades/facade-factory.ts +138 -5
  441. package/src/facades/types.ts +21 -0
  442. package/src/health/health-registry.ts +165 -0
  443. package/src/health/index.ts +11 -0
  444. package/src/health/vault-integrity.ts +66 -0
  445. package/src/index.ts +294 -2
  446. package/src/intake/intake-pipeline.ts +1 -1
  447. package/src/intelligence/types.ts +1 -0
  448. package/src/migrations/index.ts +6 -0
  449. package/src/migrations/migration-runner.ts +185 -0
  450. package/src/packs/index.ts +20 -0
  451. package/src/packs/lockfile.ts +180 -0
  452. package/src/packs/pack-installer.ts +289 -0
  453. package/src/packs/resolver.ts +237 -0
  454. package/src/packs/types.ts +125 -0
  455. package/src/persistence/postgres-provider.ts +211 -58
  456. package/src/playbooks/index.ts +11 -0
  457. package/src/playbooks/playbook-executor.ts +301 -0
  458. package/src/plugins/index.ts +19 -0
  459. package/src/plugins/plugin-loader.ts +183 -0
  460. package/src/plugins/plugin-registry.ts +187 -0
  461. package/src/plugins/types.ts +119 -0
  462. package/src/runtime/admin-extra-ops.ts +193 -8
  463. package/src/runtime/capture-ops.ts +113 -8
  464. package/src/runtime/deprecation.ts +58 -0
  465. package/src/runtime/facades/admin-facade.ts +16 -1
  466. package/src/runtime/facades/agency-facade.ts +111 -0
  467. package/src/runtime/facades/brain-facade.ts +60 -0
  468. package/src/runtime/facades/chat-facade.ts +918 -0
  469. package/src/runtime/facades/context-facade.ts +55 -0
  470. package/src/runtime/facades/index.ts +22 -1
  471. package/src/runtime/facades/vault-facade.ts +261 -1
  472. package/src/runtime/feature-flags.ts +101 -0
  473. package/src/runtime/pack-ops.ts +85 -0
  474. package/src/runtime/playbook-ops.ts +113 -9
  475. package/src/runtime/plugin-ops.ts +258 -0
  476. package/src/runtime/runtime.ts +84 -5
  477. package/src/runtime/telemetry-ops.ts +57 -0
  478. package/src/runtime/types.ts +35 -0
  479. package/src/runtime/vault-sharing-ops.ts +372 -0
  480. package/src/streams/index.ts +1 -1
  481. package/src/streams/replayable-stream.ts +34 -3
  482. package/src/text/similarity.ts +1 -1
  483. package/src/transport/http-server.ts +269 -0
  484. package/src/transport/index.ts +48 -0
  485. package/src/transport/lsp-server.ts +401 -0
  486. package/src/transport/rate-limiter.ts +97 -0
  487. package/src/transport/session-manager.ts +120 -0
  488. package/src/transport/token-auth.ts +96 -0
  489. package/src/transport/types.ts +66 -0
  490. package/src/transport/ws-server.ts +415 -0
  491. package/src/vault/git-vault-sync.ts +318 -0
  492. package/src/vault/knowledge-review.ts +221 -0
  493. package/src/vault/obsidian-sync.ts +346 -0
  494. package/src/vault/scope-detector.ts +219 -0
  495. package/src/vault/vault-branching.ts +264 -0
  496. package/src/vault/vault-manager.ts +237 -0
  497. package/src/vault/vault-types.ts +50 -0
  498. package/src/vault/vault.ts +41 -3
  499. package/src/governance/index.ts +0 -18
@@ -0,0 +1,918 @@
1
+ /**
2
+ * Chat facade — session management, response chunking, auth for chat transports.
3
+ */
4
+
5
+ import { z } from 'zod';
6
+ import type { OpDefinition } from '../../facades/types.js';
7
+ import type { AgentRuntime } from '../types.js';
8
+ import { ChatSessionManager } from '../../chat/chat-session.js';
9
+ import { ChatAuthManager } from '../../chat/auth-manager.js';
10
+ import { TaskCancellationManager } from '../../chat/cancellation.js';
11
+ import { SelfUpdateManager } from '../../chat/self-update.js';
12
+ import { NotificationEngine } from '../../chat/notifications.js';
13
+ import {
14
+ detectFileIntent,
15
+ buildMultimodalContent,
16
+ cleanupTempFiles,
17
+ } from '../../chat/file-handler.js';
18
+ import type { FileInfo } from '../../chat/file-handler.js';
19
+ import { transcribeAudio, synthesizeSpeech } from '../../chat/voice.js';
20
+ import { MessageQueue } from '../../chat/queue.js';
21
+ import { BrowserSessionManager } from '../../chat/browser-session.js';
22
+ import { chunkResponse } from '../../chat/response-chunker.js';
23
+ import { McpToolBridge } from '../../chat/mcp-bridge.js';
24
+ import { createOutputCompressor } from '../../chat/output-compressor.js';
25
+ import type { ChatSessionConfig, ChatAuthConfig, ChunkConfig } from '../../chat/types.js';
26
+
27
+ /**
28
+ * Chat transport state — lazily initialized on first use.
29
+ * Config comes from runtime flags or op params.
30
+ */
31
+ interface ChatState {
32
+ sessions: ChatSessionManager | null;
33
+ auth: ChatAuthManager | null;
34
+ bridge: McpToolBridge | null;
35
+ cancellation: TaskCancellationManager | null;
36
+ updater: SelfUpdateManager | null;
37
+ notifications: NotificationEngine | null;
38
+ queue: MessageQueue | null;
39
+ browser: BrowserSessionManager | null;
40
+ }
41
+
42
+ function getOrCreateSessions(state: ChatState, config: ChatSessionConfig): ChatSessionManager {
43
+ if (!state.sessions) {
44
+ state.sessions = new ChatSessionManager(config);
45
+ state.sessions.startReaper();
46
+ }
47
+ return state.sessions;
48
+ }
49
+
50
+ function getOrCreateAuth(state: ChatState, config: ChatAuthConfig): ChatAuthManager {
51
+ if (!state.auth) {
52
+ state.auth = new ChatAuthManager(config);
53
+ }
54
+ return state.auth;
55
+ }
56
+
57
+ export function createChatFacadeOps(_runtime: AgentRuntime): OpDefinition[] {
58
+ const state: ChatState = {
59
+ sessions: null,
60
+ auth: null,
61
+ bridge: null,
62
+ cancellation: null,
63
+ updater: null,
64
+ notifications: null,
65
+ queue: null,
66
+ browser: null,
67
+ };
68
+
69
+ return [
70
+ // ─── Session Ops ──────────────────────────────────────────────
71
+
72
+ {
73
+ name: 'chat_session_init',
74
+ description:
75
+ 'Initialize chat session management. Must be called before other session ops. Provide the storage directory path.',
76
+ auth: 'write',
77
+ schema: z.object({
78
+ storageDir: z.string().describe('Directory for session persistence.'),
79
+ ttlMs: z.number().optional().describe('Session TTL in ms. Default: 7200000 (2 hours).'),
80
+ compactionThreshold: z
81
+ .number()
82
+ .optional()
83
+ .describe('Messages before compaction. Default: 100.'),
84
+ compactionKeep: z
85
+ .number()
86
+ .optional()
87
+ .describe('Messages to keep after compaction. Default: 40.'),
88
+ }),
89
+ handler: async (params) => {
90
+ const config: ChatSessionConfig = {
91
+ storageDir: params.storageDir as string,
92
+ ttlMs: params.ttlMs as number | undefined,
93
+ compactionThreshold: params.compactionThreshold as number | undefined,
94
+ compactionKeep: params.compactionKeep as number | undefined,
95
+ };
96
+ const sessions = getOrCreateSessions(state, config);
97
+ return {
98
+ initialized: true,
99
+ activeSessions: sessions.size,
100
+ storageDir: config.storageDir,
101
+ };
102
+ },
103
+ },
104
+
105
+ {
106
+ name: 'chat_session_get',
107
+ description: 'Get or create a chat session by ID. Returns session with message history.',
108
+ auth: 'read',
109
+ schema: z.object({
110
+ sessionId: z.string().describe('Session/chat ID.'),
111
+ storageDir: z.string().describe('Storage directory (auto-initializes if needed).'),
112
+ }),
113
+ handler: async (params) => {
114
+ const sessions = getOrCreateSessions(state, {
115
+ storageDir: params.storageDir as string,
116
+ });
117
+ const session = sessions.getOrCreate(params.sessionId as string);
118
+ return {
119
+ id: session.id,
120
+ messageCount: session.messages.length,
121
+ createdAt: session.createdAt,
122
+ lastActiveAt: session.lastActiveAt,
123
+ meta: session.meta,
124
+ };
125
+ },
126
+ },
127
+
128
+ {
129
+ name: 'chat_session_append',
130
+ description: 'Append a message to a chat session.',
131
+ auth: 'write',
132
+ schema: z.object({
133
+ sessionId: z.string().describe('Session/chat ID.'),
134
+ storageDir: z.string().describe('Storage directory.'),
135
+ role: z.enum(['user', 'assistant', 'system', 'tool']).describe('Message role.'),
136
+ content: z.string().describe('Message content.'),
137
+ }),
138
+ handler: async (params) => {
139
+ const sessions = getOrCreateSessions(state, {
140
+ storageDir: params.storageDir as string,
141
+ });
142
+ sessions.appendMessage(params.sessionId as string, {
143
+ role: params.role as 'user' | 'assistant' | 'system' | 'tool',
144
+ content: params.content as string,
145
+ timestamp: Date.now(),
146
+ });
147
+ return {
148
+ sessionId: params.sessionId,
149
+ messageCount: sessions.messageCount(params.sessionId as string),
150
+ };
151
+ },
152
+ },
153
+
154
+ {
155
+ name: 'chat_session_clear',
156
+ description: 'Clear message history for a session (keeps session alive).',
157
+ auth: 'write',
158
+ schema: z.object({
159
+ sessionId: z.string().describe('Session/chat ID.'),
160
+ storageDir: z.string().describe('Storage directory.'),
161
+ }),
162
+ handler: async (params) => {
163
+ const sessions = getOrCreateSessions(state, {
164
+ storageDir: params.storageDir as string,
165
+ });
166
+ sessions.clear(params.sessionId as string);
167
+ return { cleared: true, sessionId: params.sessionId };
168
+ },
169
+ },
170
+
171
+ {
172
+ name: 'chat_session_delete',
173
+ description: 'Delete a session entirely (memory + disk).',
174
+ auth: 'write',
175
+ schema: z.object({
176
+ sessionId: z.string().describe('Session/chat ID.'),
177
+ storageDir: z.string().describe('Storage directory.'),
178
+ }),
179
+ handler: async (params) => {
180
+ const sessions = getOrCreateSessions(state, {
181
+ storageDir: params.storageDir as string,
182
+ });
183
+ sessions.delete(params.sessionId as string);
184
+ return { deleted: true, sessionId: params.sessionId };
185
+ },
186
+ },
187
+
188
+ {
189
+ name: 'chat_session_list',
190
+ description: 'List all session IDs (active + persisted).',
191
+ auth: 'read',
192
+ schema: z.object({
193
+ storageDir: z.string().describe('Storage directory.'),
194
+ }),
195
+ handler: async (params) => {
196
+ const sessions = getOrCreateSessions(state, {
197
+ storageDir: params.storageDir as string,
198
+ });
199
+ const ids = sessions.listAll();
200
+ return { sessions: ids, count: ids.length, active: sessions.size };
201
+ },
202
+ },
203
+
204
+ // ─── Response Chunking ────────────────────────────────────────
205
+
206
+ {
207
+ name: 'chat_chunk_response',
208
+ description:
209
+ 'Split a long response into chunks for chat platforms. Converts Markdown to HTML by default.',
210
+ auth: 'read',
211
+ schema: z.object({
212
+ text: z.string().describe('The response text to chunk.'),
213
+ maxChunkSize: z.number().optional().describe('Max characters per chunk. Default: 4000.'),
214
+ format: z
215
+ .enum(['html', 'markdown', 'plain'])
216
+ .optional()
217
+ .describe('Output format. Default: html.'),
218
+ }),
219
+ handler: async (params) => {
220
+ const config: ChunkConfig = {
221
+ maxChunkSize: params.maxChunkSize as number | undefined,
222
+ format: params.format as 'html' | 'markdown' | 'plain' | undefined,
223
+ };
224
+ const chunks = chunkResponse(params.text as string, config);
225
+ return { chunks, count: chunks.length };
226
+ },
227
+ },
228
+
229
+ // ─── Authentication ───────────────────────────────────────────
230
+
231
+ {
232
+ name: 'chat_auth_init',
233
+ description: 'Initialize chat authentication. Provide passphrase and optional allowlist.',
234
+ auth: 'write',
235
+ schema: z.object({
236
+ storagePath: z.string().describe('Path to auth persistence file.'),
237
+ passphrase: z.string().optional().describe('Auth passphrase. If unset, auth is disabled.'),
238
+ allowedUsers: z
239
+ .array(z.union([z.string(), z.number()]))
240
+ .optional()
241
+ .describe('Allowed user IDs. Empty = any user.'),
242
+ }),
243
+ handler: async (params) => {
244
+ const config: ChatAuthConfig = {
245
+ storagePath: params.storagePath as string,
246
+ passphrase: params.passphrase as string | undefined,
247
+ allowedUsers: params.allowedUsers as (string | number)[] | undefined,
248
+ };
249
+ const auth = getOrCreateAuth(state, config);
250
+ return {
251
+ initialized: true,
252
+ enabled: auth.enabled,
253
+ authenticatedCount: auth.authenticatedCount,
254
+ };
255
+ },
256
+ },
257
+
258
+ {
259
+ name: 'chat_auth_check',
260
+ description: 'Check if a user is authenticated.',
261
+ auth: 'read',
262
+ schema: z.object({
263
+ userId: z.union([z.string(), z.number()]).describe('User ID to check.'),
264
+ storagePath: z.string().describe('Auth storage path (auto-initializes if needed).'),
265
+ }),
266
+ handler: async (params) => {
267
+ const auth = getOrCreateAuth(state, {
268
+ storagePath: params.storagePath as string,
269
+ });
270
+ const userId = params.userId as string | number;
271
+ return {
272
+ userId,
273
+ authenticated: auth.isAuthenticated(userId),
274
+ lockedOut: auth.isLockedOut(userId),
275
+ };
276
+ },
277
+ },
278
+
279
+ {
280
+ name: 'chat_auth_authenticate',
281
+ description: 'Attempt to authenticate a user with a passphrase.',
282
+ auth: 'write',
283
+ schema: z.object({
284
+ userId: z.union([z.string(), z.number()]).describe('User ID.'),
285
+ passphrase: z.string().describe('Passphrase to verify.'),
286
+ storagePath: z.string().describe('Auth storage path.'),
287
+ }),
288
+ handler: async (params) => {
289
+ const auth = getOrCreateAuth(state, {
290
+ storagePath: params.storagePath as string,
291
+ });
292
+ const success = auth.authenticate(
293
+ params.userId as string | number,
294
+ params.passphrase as string,
295
+ );
296
+ return {
297
+ userId: params.userId,
298
+ success,
299
+ lockedOut: auth.isLockedOut(params.userId as string | number),
300
+ };
301
+ },
302
+ },
303
+
304
+ {
305
+ name: 'chat_auth_revoke',
306
+ description: 'Revoke authentication for a user.',
307
+ auth: 'write',
308
+ schema: z.object({
309
+ userId: z.union([z.string(), z.number()]).describe('User ID to revoke.'),
310
+ storagePath: z.string().describe('Auth storage path.'),
311
+ }),
312
+ handler: async (params) => {
313
+ const auth = getOrCreateAuth(state, {
314
+ storagePath: params.storagePath as string,
315
+ });
316
+ auth.revoke(params.userId as string | number);
317
+ return { revoked: true, userId: params.userId };
318
+ },
319
+ },
320
+
321
+ {
322
+ name: 'chat_auth_status',
323
+ description: 'Get authentication status — enabled, user count, list.',
324
+ auth: 'read',
325
+ schema: z.object({
326
+ storagePath: z.string().describe('Auth storage path.'),
327
+ }),
328
+ handler: async (params) => {
329
+ const auth = getOrCreateAuth(state, {
330
+ storagePath: params.storagePath as string,
331
+ });
332
+ return {
333
+ enabled: auth.enabled,
334
+ authenticatedCount: auth.authenticatedCount,
335
+ authenticatedUsers: auth.listAuthenticated(),
336
+ };
337
+ },
338
+ },
339
+
340
+ // ─── MCP Bridge Ops ─────────────────────────────────────────────
341
+
342
+ {
343
+ name: 'chat_bridge_init',
344
+ description:
345
+ 'Initialize the MCP tool bridge for local tool execution. Optional allowlist filters which tools are registered.',
346
+ auth: 'write',
347
+ schema: z.object({
348
+ allowlist: z
349
+ .array(z.string())
350
+ .optional()
351
+ .describe('Tool name allowlist. If unset, all tools are allowed.'),
352
+ maxOutput: z
353
+ .number()
354
+ .optional()
355
+ .describe('Max output length per tool call. Default: 10000.'),
356
+ }),
357
+ handler: async (params) => {
358
+ state.bridge = new McpToolBridge({
359
+ allowlist: params.allowlist as string[] | undefined,
360
+ compressor: createOutputCompressor(),
361
+ maxOutput: params.maxOutput as number | undefined,
362
+ });
363
+ return { initialized: true, toolCount: 0 };
364
+ },
365
+ },
366
+
367
+ {
368
+ name: 'chat_bridge_register',
369
+ description: 'Register a tool with the MCP bridge.',
370
+ auth: 'write',
371
+ schema: z.object({
372
+ name: z.string().describe('Tool name.'),
373
+ description: z.string().describe('Tool description.'),
374
+ inputSchema: z.record(z.unknown()).describe('JSON Schema for tool input.'),
375
+ }),
376
+ handler: async (params) => {
377
+ if (!state.bridge) {
378
+ state.bridge = new McpToolBridge({ compressor: createOutputCompressor() });
379
+ }
380
+ // Handler is a no-op since we can't pass functions through JSON
381
+ // Real handler registration happens in code, not via ops
382
+ state.bridge.register({
383
+ name: params.name as string,
384
+ description: params.description as string,
385
+ inputSchema: params.inputSchema as Record<string, unknown>,
386
+ handler: async () => ({ message: 'Registered via op — handler is a placeholder' }),
387
+ });
388
+ return { registered: true, name: params.name, totalTools: state.bridge.size };
389
+ },
390
+ },
391
+
392
+ {
393
+ name: 'chat_bridge_list',
394
+ description: 'List all tools registered with the MCP bridge.',
395
+ auth: 'read',
396
+ handler: async () => {
397
+ if (!state.bridge) return { tools: [], count: 0 };
398
+ const tools = state.bridge.listTools();
399
+ return { tools, count: tools.length };
400
+ },
401
+ },
402
+
403
+ {
404
+ name: 'chat_bridge_execute',
405
+ description: 'Execute a registered tool via the MCP bridge.',
406
+ auth: 'write',
407
+ schema: z.object({
408
+ name: z.string().describe('Tool name to execute.'),
409
+ input: z.record(z.unknown()).optional().describe('Tool input parameters.'),
410
+ }),
411
+ handler: async (params) => {
412
+ if (!state.bridge) return { output: 'Bridge not initialized', isError: true };
413
+ const result = await state.bridge.execute(
414
+ params.name as string,
415
+ (params.input as Record<string, unknown>) ?? {},
416
+ );
417
+ return result;
418
+ },
419
+ },
420
+
421
+ {
422
+ name: 'chat_compress_output',
423
+ description: 'Compress verbose tool output for chat display. Uses JSON-aware truncation.',
424
+ auth: 'read',
425
+ schema: z.object({
426
+ toolName: z.string().describe('Tool name (for compressor lookup).'),
427
+ output: z.string().describe('Raw tool output to compress.'),
428
+ maxLength: z.number().optional().describe('Max output length. Default: 4000.'),
429
+ }),
430
+ handler: async (params) => {
431
+ const compressor = createOutputCompressor();
432
+ const compressed = compressor(
433
+ params.toolName as string,
434
+ params.output as string,
435
+ params.maxLength as number | undefined,
436
+ );
437
+ return {
438
+ compressed,
439
+ originalLength: (params.output as string).length,
440
+ compressedLength: compressed.length,
441
+ };
442
+ },
443
+ },
444
+
445
+ // ─── Task Cancellation Ops ─────────────────────────────────────
446
+
447
+ {
448
+ name: 'chat_cancel_create',
449
+ description:
450
+ 'Create an AbortSignal for a chat task. If a task is already running for this chat, it is cancelled first. Returns signal status.',
451
+ auth: 'write',
452
+ schema: z.object({
453
+ chatId: z.string().describe('Chat/session ID.'),
454
+ description: z.string().optional().describe('Description of what is running.'),
455
+ }),
456
+ handler: async (params) => {
457
+ if (!state.cancellation) {
458
+ state.cancellation = new TaskCancellationManager();
459
+ }
460
+ const signal = state.cancellation.create(
461
+ params.chatId as string,
462
+ params.description as string | undefined,
463
+ );
464
+ return {
465
+ chatId: params.chatId,
466
+ created: true,
467
+ aborted: signal.aborted,
468
+ activeTasks: state.cancellation.size,
469
+ };
470
+ },
471
+ },
472
+
473
+ {
474
+ name: 'chat_cancel_stop',
475
+ description: 'Cancel the running task for a chat. Aborts the associated AbortController.',
476
+ auth: 'write',
477
+ schema: z.object({
478
+ chatId: z.string().describe('Chat/session ID to cancel.'),
479
+ }),
480
+ handler: async (params) => {
481
+ if (!state.cancellation) {
482
+ return { cancelled: false, reason: 'No cancellation manager initialized.' };
483
+ }
484
+ const info = state.cancellation.cancel(params.chatId as string);
485
+ if (!info) {
486
+ return { cancelled: false, reason: 'No running task for this chat.' };
487
+ }
488
+ return {
489
+ cancelled: true,
490
+ chatId: params.chatId,
491
+ description: info.description ?? null,
492
+ ranForMs: Date.now() - info.startedAt,
493
+ activeTasks: state.cancellation.size,
494
+ };
495
+ },
496
+ },
497
+
498
+ {
499
+ name: 'chat_cancel_status',
500
+ description: 'Get cancellation status — running tasks, per-chat info.',
501
+ auth: 'read',
502
+ schema: z.object({
503
+ chatId: z.string().optional().describe('Specific chat to check. Omit for all.'),
504
+ }),
505
+ handler: async (params) => {
506
+ if (!state.cancellation) {
507
+ return { activeTasks: 0, running: [] };
508
+ }
509
+ if (params.chatId) {
510
+ const info = state.cancellation.getInfo(params.chatId as string);
511
+ return {
512
+ chatId: params.chatId,
513
+ running: !!info,
514
+ description: info?.description ?? null,
515
+ startedAt: info?.startedAt ?? null,
516
+ ranForMs: info ? Date.now() - info.startedAt : null,
517
+ };
518
+ }
519
+ const running = state.cancellation.listRunning();
520
+ return {
521
+ activeTasks: state.cancellation.size,
522
+ running: running.map((id) => {
523
+ const info = state.cancellation!.getInfo(id);
524
+ return {
525
+ chatId: id,
526
+ description: info?.description ?? null,
527
+ startedAt: info?.startedAt ?? null,
528
+ };
529
+ }),
530
+ };
531
+ },
532
+ },
533
+
534
+ // ─── Self-Update Ops ───────────────────────────────────────────
535
+
536
+ {
537
+ name: 'chat_update_init',
538
+ description: 'Initialize self-update manager. Provide path for restart context persistence.',
539
+ auth: 'write',
540
+ schema: z.object({
541
+ contextPath: z.string().describe('Path for restart context JSON file.'),
542
+ }),
543
+ handler: async (params) => {
544
+ state.updater = new SelfUpdateManager(params.contextPath as string);
545
+ const pending = state.updater.loadContext();
546
+ return {
547
+ initialized: true,
548
+ hasPendingRestart: !!pending,
549
+ pendingContext: pending,
550
+ };
551
+ },
552
+ },
553
+
554
+ {
555
+ name: 'chat_update_request',
556
+ description: 'Request a restart. Saves context for post-restart confirmation.',
557
+ auth: 'write',
558
+ schema: z.object({
559
+ chatId: z.string().describe('Chat ID for post-restart confirmation.'),
560
+ reason: z
561
+ .enum(['self-update', 'rebuild', 'manual'])
562
+ .optional()
563
+ .describe('Restart reason. Default: manual.'),
564
+ commitSha: z.string().optional().describe('Git commit SHA if self-update.'),
565
+ contextPath: z.string().describe('Path for restart context.'),
566
+ }),
567
+ handler: async (params) => {
568
+ if (!state.updater) {
569
+ state.updater = new SelfUpdateManager(params.contextPath as string);
570
+ }
571
+ return state.updater.requestRestart(
572
+ params.chatId as string,
573
+ (params.reason as 'self-update' | 'rebuild' | 'manual') ?? 'manual',
574
+ params.commitSha as string | undefined,
575
+ );
576
+ },
577
+ },
578
+
579
+ {
580
+ name: 'chat_update_confirm',
581
+ description: 'Clear restart context after successful startup.',
582
+ auth: 'write',
583
+ schema: z.object({
584
+ contextPath: z.string().describe('Path for restart context.'),
585
+ }),
586
+ handler: async (params) => {
587
+ if (!state.updater) {
588
+ state.updater = new SelfUpdateManager(params.contextPath as string);
589
+ }
590
+ const context = state.updater.loadContext();
591
+ state.updater.clearContext();
592
+ return { confirmed: true, previousContext: context };
593
+ },
594
+ },
595
+
596
+ // ─── File Handling Ops ─────────────────────────────────────────
597
+
598
+ {
599
+ name: 'chat_file_detect_intent',
600
+ description: 'Detect user intent for a file — vision, text, or intake.',
601
+ auth: 'read',
602
+ schema: z.object({
603
+ filename: z.string().describe('Original filename.'),
604
+ mimeType: z.string().describe('MIME type.'),
605
+ userText: z.string().optional().describe('Accompanying user message text.'),
606
+ }),
607
+ handler: async (params) => {
608
+ const intent = detectFileIntent(
609
+ params.filename as string,
610
+ params.mimeType as string,
611
+ params.userText as string | undefined,
612
+ );
613
+ return { filename: params.filename, mimeType: params.mimeType, intent };
614
+ },
615
+ },
616
+
617
+ {
618
+ name: 'chat_file_build_content',
619
+ description: 'Build multimodal content from a file for the Anthropic API.',
620
+ auth: 'read',
621
+ schema: z.object({
622
+ filename: z.string().describe('Original filename.'),
623
+ mimeType: z.string().describe('MIME type.'),
624
+ dataBase64: z.string().describe('File content as base64.'),
625
+ intent: z.enum(['vision', 'text', 'intake']).describe('Detected intent.'),
626
+ }),
627
+ handler: async (params) => {
628
+ const file: FileInfo = {
629
+ name: params.filename as string,
630
+ mimeType: params.mimeType as string,
631
+ size: Buffer.byteLength(params.dataBase64 as string, 'base64'),
632
+ data: Buffer.from(params.dataBase64 as string, 'base64'),
633
+ };
634
+ return buildMultimodalContent(file, params.intent as 'vision' | 'text' | 'intake');
635
+ },
636
+ },
637
+
638
+ {
639
+ name: 'chat_file_cleanup',
640
+ description: 'Clean up temp files older than maxAgeMs.',
641
+ auth: 'write',
642
+ schema: z.object({
643
+ uploadDir: z.string().describe('Temp upload directory.'),
644
+ maxAgeMs: z.number().optional().describe('Max age in ms. Default: 1 hour.'),
645
+ }),
646
+ handler: async (params) => {
647
+ const removed = cleanupTempFiles(
648
+ params.uploadDir as string,
649
+ params.maxAgeMs as number | undefined,
650
+ );
651
+ return { removed, uploadDir: params.uploadDir };
652
+ },
653
+ },
654
+
655
+ // ─── Notification Ops ──────────────────────────────────────────
656
+
657
+ {
658
+ name: 'chat_notify_init',
659
+ description:
660
+ 'Initialize the notification engine. Notifications are delivered via the provided callback pattern.',
661
+ auth: 'write',
662
+ schema: z.object({
663
+ intervalMs: z.number().optional().describe('Polling interval in ms. Default: 30 minutes.'),
664
+ defaultCooldownMs: z
665
+ .number()
666
+ .optional()
667
+ .describe('Default cooldown between notifications. Default: 4 hours.'),
668
+ }),
669
+ handler: async (params) => {
670
+ // The onNotify callback can't be passed via JSON — it's set up in code.
671
+ // This op initializes with a no-op that logs to console.
672
+ state.notifications = new NotificationEngine({
673
+ intervalMs: params.intervalMs as number | undefined,
674
+ defaultCooldownMs: params.defaultCooldownMs as number | undefined,
675
+ onNotify: async (checkId, message) => {
676
+ console.log(`[notification] ${checkId}: ${message}`);
677
+ },
678
+ });
679
+ return { initialized: true };
680
+ },
681
+ },
682
+
683
+ {
684
+ name: 'chat_notify_start',
685
+ description: 'Start the notification polling loop.',
686
+ auth: 'write',
687
+ handler: async () => {
688
+ if (!state.notifications) {
689
+ return { started: false, reason: 'Notification engine not initialized.' };
690
+ }
691
+ state.notifications.start();
692
+ return { started: true, ...state.notifications.stats() };
693
+ },
694
+ },
695
+
696
+ {
697
+ name: 'chat_notify_stop',
698
+ description: 'Stop the notification polling loop.',
699
+ auth: 'write',
700
+ handler: async () => {
701
+ if (!state.notifications) {
702
+ return { stopped: false, reason: 'Notification engine not initialized.' };
703
+ }
704
+ state.notifications.stop();
705
+ return { stopped: true, ...state.notifications.stats() };
706
+ },
707
+ },
708
+
709
+ {
710
+ name: 'chat_notify_poll',
711
+ description: 'Run all notification checks once (manual trigger).',
712
+ auth: 'write',
713
+ handler: async () => {
714
+ if (!state.notifications) {
715
+ return { polled: false, reason: 'Notification engine not initialized.' };
716
+ }
717
+ const notified = await state.notifications.poll();
718
+ return { polled: true, notified, ...state.notifications.stats() };
719
+ },
720
+ },
721
+
722
+ {
723
+ name: 'chat_notify_status',
724
+ description: 'Get notification engine status.',
725
+ auth: 'read',
726
+ handler: async () => {
727
+ if (!state.notifications) {
728
+ return { initialized: false, checks: 0, running: false, sent: 0, lastPollAt: null };
729
+ }
730
+ return { initialized: true, ...state.notifications.stats() };
731
+ },
732
+ },
733
+
734
+ // ─── Voice Ops ─────────────────────────────────────────────────
735
+
736
+ {
737
+ name: 'chat_voice_transcribe',
738
+ description: 'Transcribe audio using OpenAI Whisper. Provide base64-encoded audio.',
739
+ auth: 'write',
740
+ schema: z.object({
741
+ audioBase64: z.string().describe('Base64-encoded audio data.'),
742
+ openaiApiKey: z.string().describe('OpenAI API key.'),
743
+ filename: z.string().optional().describe('Audio filename. Default: audio.ogg.'),
744
+ }),
745
+ handler: async (params) => {
746
+ const buffer = Buffer.from(params.audioBase64 as string, 'base64');
747
+ return transcribeAudio(
748
+ buffer,
749
+ {
750
+ openaiApiKey: params.openaiApiKey as string,
751
+ },
752
+ params.filename as string | undefined,
753
+ );
754
+ },
755
+ },
756
+
757
+ {
758
+ name: 'chat_voice_synthesize',
759
+ description: 'Synthesize speech from text using OpenAI TTS. Returns base64 MP3.',
760
+ auth: 'write',
761
+ schema: z.object({
762
+ text: z.string().describe('Text to synthesize.'),
763
+ openaiApiKey: z.string().describe('OpenAI API key.'),
764
+ voice: z.string().optional().describe('Voice ID. Default: onyx.'),
765
+ }),
766
+ handler: async (params) => {
767
+ const result = await synthesizeSpeech(params.text as string, {
768
+ openaiApiKey: params.openaiApiKey as string,
769
+ ttsVoice: params.voice as string | undefined,
770
+ });
771
+ if (!result) return { success: false, reason: 'No API key.' };
772
+ return {
773
+ success: result.success,
774
+ audioBase64: result.audio.toString('base64'),
775
+ audioSize: result.audio.length,
776
+ };
777
+ },
778
+ },
779
+
780
+ // ─── Queue Ops ─────────────────────────────────────────────────
781
+
782
+ {
783
+ name: 'chat_queue_init',
784
+ description: 'Initialize the message queue for disk-based chat relay.',
785
+ auth: 'write',
786
+ schema: z.object({
787
+ queueDir: z.string().describe('Base directory for inbox/outbox.'),
788
+ }),
789
+ handler: async (params) => {
790
+ state.queue = new MessageQueue({ queueDir: params.queueDir as string });
791
+ return {
792
+ initialized: true,
793
+ inbox: state.queue.inboxCount(),
794
+ outbox: state.queue.outboxCount(),
795
+ };
796
+ },
797
+ },
798
+
799
+ {
800
+ name: 'chat_queue_inbox',
801
+ description: 'Read pending messages from the queue inbox.',
802
+ auth: 'read',
803
+ schema: z.object({
804
+ queueDir: z.string().describe('Queue directory (auto-initializes).'),
805
+ }),
806
+ handler: async (params) => {
807
+ if (!state.queue) {
808
+ state.queue = new MessageQueue({ queueDir: params.queueDir as string });
809
+ }
810
+ const messages = state.queue.readInbox();
811
+ return { messages, count: messages.length, formatted: state.queue.formatInbox() };
812
+ },
813
+ },
814
+
815
+ {
816
+ name: 'chat_queue_reply',
817
+ description: 'Send a reply to a queued message. Removes from inbox, writes to outbox.',
818
+ auth: 'write',
819
+ schema: z.object({
820
+ messageId: z.string().describe('Original message ID.'),
821
+ chatId: z.string().describe('Target chat ID.'),
822
+ text: z.string().describe('Response text.'),
823
+ queueDir: z.string().describe('Queue directory.'),
824
+ }),
825
+ handler: async (params) => {
826
+ if (!state.queue) {
827
+ state.queue = new MessageQueue({ queueDir: params.queueDir as string });
828
+ }
829
+ const response = state.queue.sendResponse(
830
+ params.messageId as string,
831
+ params.chatId as string,
832
+ params.text as string,
833
+ );
834
+ return { sent: true, response };
835
+ },
836
+ },
837
+
838
+ {
839
+ name: 'chat_queue_drain',
840
+ description: 'Drain outbox — read and remove all pending responses.',
841
+ auth: 'write',
842
+ schema: z.object({
843
+ queueDir: z.string().describe('Queue directory.'),
844
+ }),
845
+ handler: async (params) => {
846
+ if (!state.queue) {
847
+ state.queue = new MessageQueue({ queueDir: params.queueDir as string });
848
+ }
849
+ const responses = state.queue.drainOutbox();
850
+ return { responses, count: responses.length };
851
+ },
852
+ },
853
+
854
+ // ─── Browser Session Ops ───────────────────────────────────────
855
+
856
+ {
857
+ name: 'chat_browser_init',
858
+ description: 'Initialize the browser session manager for per-chat Playwright isolation.',
859
+ auth: 'write',
860
+ schema: z.object({
861
+ maxSessions: z.number().optional().describe('Max concurrent sessions. Default: 3.'),
862
+ idleTimeoutMs: z.number().optional().describe('Idle timeout in ms. Default: 5 minutes.'),
863
+ }),
864
+ handler: async (params) => {
865
+ state.browser = new BrowserSessionManager({
866
+ maxSessions: params.maxSessions as number | undefined,
867
+ idleTimeoutMs: params.idleTimeoutMs as number | undefined,
868
+ });
869
+ return { initialized: true, maxSessions: params.maxSessions ?? 3 };
870
+ },
871
+ },
872
+
873
+ {
874
+ name: 'chat_browser_acquire',
875
+ description: 'Get or create a browser session for a chat. Spawns Playwright if needed.',
876
+ auth: 'write',
877
+ schema: z.object({
878
+ chatId: z.string().describe('Chat ID for isolation.'),
879
+ }),
880
+ handler: async (params) => {
881
+ if (!state.browser) {
882
+ state.browser = new BrowserSessionManager();
883
+ }
884
+ const session = state.browser.acquire(params.chatId as string);
885
+ return {
886
+ chatId: params.chatId,
887
+ pid: session.process.pid ?? null,
888
+ activeSessions: state.browser.size,
889
+ };
890
+ },
891
+ },
892
+
893
+ {
894
+ name: 'chat_browser_release',
895
+ description: 'Release a browser session for a chat.',
896
+ auth: 'write',
897
+ schema: z.object({
898
+ chatId: z.string().describe('Chat ID to release.'),
899
+ }),
900
+ handler: async (params) => {
901
+ if (!state.browser) return { released: false, reason: 'No browser manager.' };
902
+ const released = state.browser.release(params.chatId as string);
903
+ return { released, activeSessions: state.browser.size };
904
+ },
905
+ },
906
+
907
+ {
908
+ name: 'chat_browser_status',
909
+ description: 'Get browser session status — active sessions, per-chat info.',
910
+ auth: 'read',
911
+ handler: async () => {
912
+ if (!state.browser) return { initialized: false, activeSessions: 0, sessions: [] };
913
+ const sessions = state.browser.listSessions().map((id) => (Object.assign({chatId:id}, state.browser! .getInfo(id))));
914
+ return { initialized: true, activeSessions: state.browser.size, sessions };
915
+ },
916
+ },
917
+ ];
918
+ }