@alneas/eaos-server 0.0.0-stage → 0.2.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 (360) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.ja.md +49 -0
  4. package/README.md +46 -2
  5. package/dist/agentic/agent-jobs.d.ts +333 -0
  6. package/dist/agentic/agent-jobs.js +15 -0
  7. package/dist/agentic/agent-jobs.js.map +1 -0
  8. package/dist/agentic/agent-node.d.ts +40 -0
  9. package/dist/agentic/agent-node.js +7 -0
  10. package/dist/agentic/agent-node.js.map +1 -0
  11. package/dist/agentic/agent-runner.d.ts +33 -0
  12. package/dist/agentic/agent-runner.js +7 -0
  13. package/dist/agentic/agent-runner.js.map +1 -0
  14. package/dist/agentic/ai-broker.d.ts +169 -0
  15. package/dist/agentic/ai-broker.js +8 -0
  16. package/dist/agentic/ai-broker.js.map +1 -0
  17. package/dist/agentic/atomic-checkpointer.d.ts +137 -0
  18. package/dist/agentic/atomic-checkpointer.js +9 -0
  19. package/dist/agentic/atomic-checkpointer.js.map +1 -0
  20. package/dist/agentic/autonomous-worker.d.ts +122 -0
  21. package/dist/agentic/autonomous-worker.js +10 -0
  22. package/dist/agentic/autonomous-worker.js.map +1 -0
  23. package/dist/agentic/event-bridge.d.ts +350 -0
  24. package/dist/agentic/event-bridge.js +9 -0
  25. package/dist/agentic/event-bridge.js.map +1 -0
  26. package/dist/agentic/executor.d.ts +91 -0
  27. package/dist/agentic/executor.js +12 -0
  28. package/dist/agentic/executor.js.map +1 -0
  29. package/dist/agentic/graph-projection.d.ts +119 -0
  30. package/dist/agentic/graph-projection.js +7 -0
  31. package/dist/agentic/graph-projection.js.map +1 -0
  32. package/dist/agentic/graph.d.ts +524 -0
  33. package/dist/agentic/graph.js +7 -0
  34. package/dist/agentic/graph.js.map +1 -0
  35. package/dist/agentic/index.d.ts +28 -0
  36. package/dist/agentic/index.js +87 -0
  37. package/dist/agentic/index.js.map +1 -0
  38. package/dist/agentic/local-runner.d.ts +106 -0
  39. package/dist/agentic/local-runner.js +7 -0
  40. package/dist/agentic/local-runner.js.map +1 -0
  41. package/dist/agentic/remote-executor.d.ts +67 -0
  42. package/dist/agentic/remote-executor.js +8 -0
  43. package/dist/agentic/remote-executor.js.map +1 -0
  44. package/dist/agentic/types.d.ts +157 -0
  45. package/dist/agentic/types.js +7 -0
  46. package/dist/agentic/types.js.map +1 -0
  47. package/dist/agentic/workflow-catalog.d.ts +152 -0
  48. package/dist/agentic/workflow-catalog.js +7 -0
  49. package/dist/agentic/workflow-catalog.js.map +1 -0
  50. package/dist/agentic/workflow-compiler.d.ts +44 -0
  51. package/dist/agentic/workflow-compiler.js +8 -0
  52. package/dist/agentic/workflow-compiler.js.map +1 -0
  53. package/dist/agentic/workflow-coordinator.d.ts +170 -0
  54. package/dist/agentic/workflow-coordinator.js +8 -0
  55. package/dist/agentic/workflow-coordinator.js.map +1 -0
  56. package/dist/agentic/workflow-manager.d.ts +91 -0
  57. package/dist/agentic/workflow-manager.js +7 -0
  58. package/dist/agentic/workflow-manager.js.map +1 -0
  59. package/dist/agentic/workflow-registry.d.ts +334 -0
  60. package/dist/agentic/workflow-registry.js +7 -0
  61. package/dist/agentic/workflow-registry.js.map +1 -0
  62. package/dist/artifacts-CteHmCMI.d.ts +614 -0
  63. package/dist/auth-hooks/api-key.d.ts +75 -0
  64. package/dist/auth-hooks/api-key.js +7 -0
  65. package/dist/auth-hooks/api-key.js.map +1 -0
  66. package/dist/auth-hooks/index.d.ts +80 -0
  67. package/dist/auth-hooks/index.js +28 -0
  68. package/dist/auth-hooks/index.js.map +1 -0
  69. package/dist/browser-auth/account-memberships.d.ts +213 -0
  70. package/dist/browser-auth/account-memberships.js +13 -0
  71. package/dist/browser-auth/account-memberships.js.map +1 -0
  72. package/dist/browser-auth/index.d.ts +8 -0
  73. package/dist/browser-auth/index.js +59 -0
  74. package/dist/browser-auth/index.js.map +1 -0
  75. package/dist/browser-auth/kratos-session.d.ts +37 -0
  76. package/dist/browser-auth/kratos-session.js +7 -0
  77. package/dist/browser-auth/kratos-session.js.map +1 -0
  78. package/dist/browser-auth/platform-session.d.ts +120 -0
  79. package/dist/browser-auth/platform-session.js +7 -0
  80. package/dist/browser-auth/platform-session.js.map +1 -0
  81. package/dist/browser-auth/public-memberships.d.ts +22 -0
  82. package/dist/browser-auth/public-memberships.js +7 -0
  83. package/dist/browser-auth/public-memberships.js.map +1 -0
  84. package/dist/cache/index.d.ts +181 -0
  85. package/dist/cache/index.js +197 -0
  86. package/dist/cache/index.js.map +1 -0
  87. package/dist/chunk-32746UQZ.js +131 -0
  88. package/dist/chunk-32746UQZ.js.map +1 -0
  89. package/dist/chunk-3NLSWP2Y.js +223 -0
  90. package/dist/chunk-3NLSWP2Y.js.map +1 -0
  91. package/dist/chunk-3P4XTTQH.js +346 -0
  92. package/dist/chunk-3P4XTTQH.js.map +1 -0
  93. package/dist/chunk-3VITSHN3.js +15 -0
  94. package/dist/chunk-3VITSHN3.js.map +1 -0
  95. package/dist/chunk-46UWPEW2.js +226 -0
  96. package/dist/chunk-46UWPEW2.js.map +1 -0
  97. package/dist/chunk-4BARRLJR.js +180 -0
  98. package/dist/chunk-4BARRLJR.js.map +1 -0
  99. package/dist/chunk-4VORUFKR.js +45 -0
  100. package/dist/chunk-4VORUFKR.js.map +1 -0
  101. package/dist/chunk-55D4ERWO.js +1 -0
  102. package/dist/chunk-55D4ERWO.js.map +1 -0
  103. package/dist/chunk-5TBBZIND.js +18 -0
  104. package/dist/chunk-5TBBZIND.js.map +1 -0
  105. package/dist/chunk-5WOZWPZA.js +211 -0
  106. package/dist/chunk-5WOZWPZA.js.map +1 -0
  107. package/dist/chunk-6CBVZ6CT.js +168 -0
  108. package/dist/chunk-6CBVZ6CT.js.map +1 -0
  109. package/dist/chunk-6XZXYNJR.js +74 -0
  110. package/dist/chunk-6XZXYNJR.js.map +1 -0
  111. package/dist/chunk-753HWDSC.js +222 -0
  112. package/dist/chunk-753HWDSC.js.map +1 -0
  113. package/dist/chunk-7AHSS7SO.js +81 -0
  114. package/dist/chunk-7AHSS7SO.js.map +1 -0
  115. package/dist/chunk-7FTJN4SA.js +1 -0
  116. package/dist/chunk-7FTJN4SA.js.map +1 -0
  117. package/dist/chunk-AVDMLTPF.js +24 -0
  118. package/dist/chunk-AVDMLTPF.js.map +1 -0
  119. package/dist/chunk-BKAHUEIT.js +95 -0
  120. package/dist/chunk-BKAHUEIT.js.map +1 -0
  121. package/dist/chunk-CJ7OFEF7.js +134 -0
  122. package/dist/chunk-CJ7OFEF7.js.map +1 -0
  123. package/dist/chunk-EJKWDZIU.js +111 -0
  124. package/dist/chunk-EJKWDZIU.js.map +1 -0
  125. package/dist/chunk-F2J6IQ6I.js +247 -0
  126. package/dist/chunk-F2J6IQ6I.js.map +1 -0
  127. package/dist/chunk-F3O7CELI.js +23 -0
  128. package/dist/chunk-F3O7CELI.js.map +1 -0
  129. package/dist/chunk-F4IITPGX.js +221 -0
  130. package/dist/chunk-F4IITPGX.js.map +1 -0
  131. package/dist/chunk-FD6VC2NA.js +66 -0
  132. package/dist/chunk-FD6VC2NA.js.map +1 -0
  133. package/dist/chunk-FRRRWAHO.js +14 -0
  134. package/dist/chunk-FRRRWAHO.js.map +1 -0
  135. package/dist/chunk-HCKAGLLB.js +17 -0
  136. package/dist/chunk-HCKAGLLB.js.map +1 -0
  137. package/dist/chunk-HVC7FG6B.js +191 -0
  138. package/dist/chunk-HVC7FG6B.js.map +1 -0
  139. package/dist/chunk-HXFVOR7Z.js +496 -0
  140. package/dist/chunk-HXFVOR7Z.js.map +1 -0
  141. package/dist/chunk-IJWYS2PF.js +122 -0
  142. package/dist/chunk-IJWYS2PF.js.map +1 -0
  143. package/dist/chunk-INCHXAFK.js +1395 -0
  144. package/dist/chunk-INCHXAFK.js.map +1 -0
  145. package/dist/chunk-JT6BRGQM.js +1 -0
  146. package/dist/chunk-JT6BRGQM.js.map +1 -0
  147. package/dist/chunk-L6PMAEMB.js +115 -0
  148. package/dist/chunk-L6PMAEMB.js.map +1 -0
  149. package/dist/chunk-LOUGW6MU.js +126 -0
  150. package/dist/chunk-LOUGW6MU.js.map +1 -0
  151. package/dist/chunk-LYPZPE53.js +129 -0
  152. package/dist/chunk-LYPZPE53.js.map +1 -0
  153. package/dist/chunk-NNCCN7JP.js +186 -0
  154. package/dist/chunk-NNCCN7JP.js.map +1 -0
  155. package/dist/chunk-PBC3MZUL.js +212 -0
  156. package/dist/chunk-PBC3MZUL.js.map +1 -0
  157. package/dist/chunk-R4ADP2DC.js +20 -0
  158. package/dist/chunk-R4ADP2DC.js.map +1 -0
  159. package/dist/chunk-RHN4Y6VS.js +44 -0
  160. package/dist/chunk-RHN4Y6VS.js.map +1 -0
  161. package/dist/chunk-SDJNYPYK.js +770 -0
  162. package/dist/chunk-SDJNYPYK.js.map +1 -0
  163. package/dist/chunk-UGNTCOVR.js +28 -0
  164. package/dist/chunk-UGNTCOVR.js.map +1 -0
  165. package/dist/chunk-VC2PCK2S.js +31 -0
  166. package/dist/chunk-VC2PCK2S.js.map +1 -0
  167. package/dist/chunk-VF5YDZJC.js +305 -0
  168. package/dist/chunk-VF5YDZJC.js.map +1 -0
  169. package/dist/chunk-VISRDVTK.js +675 -0
  170. package/dist/chunk-VISRDVTK.js.map +1 -0
  171. package/dist/chunk-W6O3LVBY.js +102 -0
  172. package/dist/chunk-W6O3LVBY.js.map +1 -0
  173. package/dist/chunk-WFEAKJLR.js +47 -0
  174. package/dist/chunk-WFEAKJLR.js.map +1 -0
  175. package/dist/chunk-XIEY2OF4.js +67 -0
  176. package/dist/chunk-XIEY2OF4.js.map +1 -0
  177. package/dist/chunk-XITLHDG3.js +37 -0
  178. package/dist/chunk-XITLHDG3.js.map +1 -0
  179. package/dist/chunk-XMWPYZWZ.js +61 -0
  180. package/dist/chunk-XMWPYZWZ.js.map +1 -0
  181. package/dist/chunk-XUP6CNOM.js +34 -0
  182. package/dist/chunk-XUP6CNOM.js.map +1 -0
  183. package/dist/chunk-YABTQZDJ.js +25 -0
  184. package/dist/chunk-YABTQZDJ.js.map +1 -0
  185. package/dist/chunk-YMHVRBUU.js +199 -0
  186. package/dist/chunk-YMHVRBUU.js.map +1 -0
  187. package/dist/chunk-YMJ7BRKU.js +510 -0
  188. package/dist/chunk-YMJ7BRKU.js.map +1 -0
  189. package/dist/chunk-ZC3XWU7B.js +28 -0
  190. package/dist/chunk-ZC3XWU7B.js.map +1 -0
  191. package/dist/chunk-ZHMTD5KV.js +90 -0
  192. package/dist/chunk-ZHMTD5KV.js.map +1 -0
  193. package/dist/chunk-ZWZDLOE7.js +160 -0
  194. package/dist/chunk-ZWZDLOE7.js.map +1 -0
  195. package/dist/db-package/db/local-first-sqlite-adapter.d.ts +432 -0
  196. package/dist/db-package/db/local-first-sqlite-adapter.js +7 -0
  197. package/dist/db-package/db/local-first-sqlite-adapter.js.map +1 -0
  198. package/dist/db-package/index.d.ts +7 -0
  199. package/dist/db-package/index.js +16 -0
  200. package/dist/db-package/index.js.map +1 -0
  201. package/dist/db-package/migration/aggregator.d.ts +86 -0
  202. package/dist/db-package/migration/aggregator.js +7 -0
  203. package/dist/db-package/migration/aggregator.js.map +1 -0
  204. package/dist/db-package/migration/index.d.ts +3 -0
  205. package/dist/db-package/migration/index.js +8 -0
  206. package/dist/db-package/migration/index.js.map +1 -0
  207. package/dist/engine.d.ts +205 -0
  208. package/dist/engine.js +20 -0
  209. package/dist/engine.js.map +1 -0
  210. package/dist/entitlements/index.d.ts +313 -0
  211. package/dist/entitlements/index.js +23 -0
  212. package/dist/entitlements/index.js.map +1 -0
  213. package/dist/execution/chat.d.ts +7 -0
  214. package/dist/execution/chat.js +7 -0
  215. package/dist/execution/chat.js.map +1 -0
  216. package/dist/execution/index.d.ts +342 -0
  217. package/dist/execution/index.js +66 -0
  218. package/dist/execution/index.js.map +1 -0
  219. package/dist/execution/tool-agent.d.ts +7 -0
  220. package/dist/execution/tool-agent.js +8 -0
  221. package/dist/execution/tool-agent.js.map +1 -0
  222. package/dist/extensions/index.d.ts +172 -0
  223. package/dist/extensions/index.js +95 -0
  224. package/dist/extensions/index.js.map +1 -0
  225. package/dist/health/index.d.ts +35 -0
  226. package/dist/health/index.js +7 -0
  227. package/dist/health/index.js.map +1 -0
  228. package/dist/index.d.ts +43 -0
  229. package/dist/index.js +161 -0
  230. package/dist/index.js.map +1 -0
  231. package/dist/lifecycle/index.d.ts +133 -0
  232. package/dist/lifecycle/index.js +13 -0
  233. package/dist/lifecycle/index.js.map +1 -0
  234. package/dist/lifecycle-engine/backend-migration.d.ts +2 -0
  235. package/dist/lifecycle-engine/backend-migration.js +11 -0
  236. package/dist/lifecycle-engine/backend-migration.js.map +1 -0
  237. package/dist/lifecycle-engine/baseline.d.ts +2 -0
  238. package/dist/lifecycle-engine/baseline.js +9 -0
  239. package/dist/lifecycle-engine/baseline.js.map +1 -0
  240. package/dist/lifecycle-engine/index.d.ts +1497 -0
  241. package/dist/lifecycle-engine/index.js +41 -0
  242. package/dist/lifecycle-engine/index.js.map +1 -0
  243. package/dist/lifecycle-engine/platform/artifacts.d.ts +4 -0
  244. package/dist/lifecycle-engine/platform/artifacts.js +7 -0
  245. package/dist/lifecycle-engine/platform/artifacts.js.map +1 -0
  246. package/dist/lifecycle-engine/platform/control-plane.d.ts +12 -0
  247. package/dist/lifecycle-engine/platform/control-plane.js +2 -0
  248. package/dist/lifecycle-engine/platform/control-plane.js.map +1 -0
  249. package/dist/lifecycle-engine/platform/database-router.d.ts +118 -0
  250. package/dist/lifecycle-engine/platform/database-router.js +7 -0
  251. package/dist/lifecycle-engine/platform/database-router.js.map +1 -0
  252. package/dist/lifecycle-engine/platform/deployment-placements.d.ts +464 -0
  253. package/dist/lifecycle-engine/platform/deployment-placements.js +16 -0
  254. package/dist/lifecycle-engine/platform/deployment-placements.js.map +1 -0
  255. package/dist/lifecycle-engine/platform/deployment.d.ts +4 -0
  256. package/dist/lifecycle-engine/platform/deployment.js +17 -0
  257. package/dist/lifecycle-engine/platform/deployment.js.map +1 -0
  258. package/dist/lifecycle-engine/platform/index.d.ts +737 -0
  259. package/dist/lifecycle-engine/platform/index.js +60 -0
  260. package/dist/lifecycle-engine/platform/index.js.map +1 -0
  261. package/dist/lifecycle-engine/platform/runtime.d.ts +80 -0
  262. package/dist/lifecycle-engine/platform/runtime.js +11 -0
  263. package/dist/lifecycle-engine/platform/runtime.js.map +1 -0
  264. package/dist/lifecycle-engine/platform/site-publication.d.ts +102 -0
  265. package/dist/lifecycle-engine/platform/site-publication.js +7 -0
  266. package/dist/lifecycle-engine/platform/site-publication.js.map +1 -0
  267. package/dist/lifecycle-engine/platform/user-directory.d.ts +139 -0
  268. package/dist/lifecycle-engine/platform/user-directory.js +13 -0
  269. package/dist/lifecycle-engine/platform/user-directory.js.map +1 -0
  270. package/dist/mcp.d.ts +92 -0
  271. package/dist/mcp.js +10 -0
  272. package/dist/mcp.js.map +1 -0
  273. package/dist/middleware/auth.d.ts +118 -0
  274. package/dist/middleware/auth.js +7 -0
  275. package/dist/middleware/auth.js.map +1 -0
  276. package/dist/middleware/error-handler.d.ts +35 -0
  277. package/dist/middleware/error-handler.js +7 -0
  278. package/dist/middleware/error-handler.js.map +1 -0
  279. package/dist/middleware/module-guard.d.ts +33 -0
  280. package/dist/middleware/module-guard.js +7 -0
  281. package/dist/middleware/module-guard.js.map +1 -0
  282. package/dist/platform-admin/index.d.ts +37 -0
  283. package/dist/platform-admin/index.js +11 -0
  284. package/dist/platform-admin/index.js.map +1 -0
  285. package/dist/platform-admin/store.d.ts +346 -0
  286. package/dist/platform-admin/store.js +7 -0
  287. package/dist/platform-admin/store.js.map +1 -0
  288. package/dist/plugin-data/annotations.d.ts +6 -0
  289. package/dist/plugin-data/annotations.js +12 -0
  290. package/dist/plugin-data/annotations.js.map +1 -0
  291. package/dist/plugin-data/atomic-context.d.ts +41 -0
  292. package/dist/plugin-data/atomic-context.js +9 -0
  293. package/dist/plugin-data/atomic-context.js.map +1 -0
  294. package/dist/plugin-data/atomic.d.ts +6 -0
  295. package/dist/plugin-data/atomic.js +26 -0
  296. package/dist/plugin-data/atomic.js.map +1 -0
  297. package/dist/plugin-data/audit.d.ts +6 -0
  298. package/dist/plugin-data/audit.js +12 -0
  299. package/dist/plugin-data/audit.js.map +1 -0
  300. package/dist/plugin-data/commands.d.ts +6 -0
  301. package/dist/plugin-data/commands.js +8 -0
  302. package/dist/plugin-data/commands.js.map +1 -0
  303. package/dist/plugin-data/composite.d.ts +6 -0
  304. package/dist/plugin-data/composite.js +8 -0
  305. package/dist/plugin-data/composite.js.map +1 -0
  306. package/dist/plugin-data/delivery.d.ts +6 -0
  307. package/dist/plugin-data/delivery.js +16 -0
  308. package/dist/plugin-data/delivery.js.map +1 -0
  309. package/dist/plugin-data/index.d.ts +2798 -0
  310. package/dist/plugin-data/index.js +102 -0
  311. package/dist/plugin-data/index.js.map +1 -0
  312. package/dist/plugin-data/json-documents.d.ts +6 -0
  313. package/dist/plugin-data/json-documents.js +16 -0
  314. package/dist/plugin-data/json-documents.js.map +1 -0
  315. package/dist/plugin-data/outbox.d.ts +6 -0
  316. package/dist/plugin-data/outbox.js +16 -0
  317. package/dist/plugin-data/outbox.js.map +1 -0
  318. package/dist/plugin-data/scoped-records.d.ts +6 -0
  319. package/dist/plugin-data/scoped-records.js +10 -0
  320. package/dist/plugin-data/scoped-records.js.map +1 -0
  321. package/dist/plugin-sdk.d.ts +41 -0
  322. package/dist/plugin-sdk.js +10 -0
  323. package/dist/plugin-sdk.js.map +1 -0
  324. package/dist/sql-lifecycle/index.d.ts +138 -0
  325. package/dist/sql-lifecycle/index.js +167 -0
  326. package/dist/sql-lifecycle/index.js.map +1 -0
  327. package/dist/storage/index.d.ts +2 -0
  328. package/dist/storage/index.js +13 -0
  329. package/dist/storage/index.js.map +1 -0
  330. package/dist/storage/s3-compatible.d.ts +139 -0
  331. package/dist/storage/s3-compatible.js +11 -0
  332. package/dist/storage/s3-compatible.js.map +1 -0
  333. package/dist/tenant.d.ts +108 -0
  334. package/dist/tenant.js +9 -0
  335. package/dist/tenant.js.map +1 -0
  336. package/dist/workspace-context.d.ts +119 -0
  337. package/dist/workspace-context.js +9 -0
  338. package/dist/workspace-context.js.map +1 -0
  339. package/docs/api.md +30560 -0
  340. package/docs/db/README.md +49 -0
  341. package/docs/db/docs/api.md +1613 -0
  342. package/docs/db/docs/guide.md +47 -0
  343. package/docs/entitlements.md +60 -0
  344. package/docs/guide.md +92 -0
  345. package/docs/index.md +57 -0
  346. package/docs/ja/db/README.md +46 -0
  347. package/docs/ja/db/docs/guide.md +53 -0
  348. package/docs/ja/guide.md +46 -0
  349. package/docs/ja/lifecycle/README.md +46 -0
  350. package/docs/ja/lifecycle/docs/guide.md +45 -0
  351. package/docs/ja/storage/README.md +46 -0
  352. package/docs/ja/storage/docs/guide.md +43 -0
  353. package/docs/lifecycle/README.md +49 -0
  354. package/docs/lifecycle/docs/api.md +3770 -0
  355. package/docs/lifecycle/docs/baseline.md +50 -0
  356. package/docs/lifecycle/docs/guide.md +47 -0
  357. package/docs/storage/README.md +49 -0
  358. package/docs/storage/docs/api.md +470 -0
  359. package/docs/storage/docs/guide.md +47 -0
  360. package/package.json +354 -4
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agentic/event-bridge.ts"],"sourcesContent":["import type { DomainEventBus } from '@alneas/eaos-core'\nimport type { ServerAutonomousWorker } from './autonomous-worker'\nimport type { ServerAgentTaskRequest, ServerAgentTaskResult } from './types'\n\n/**\n * Maps one domain event name to a verified host task specification.\n * @see EventAgentBridge.registerRule.\n */\nexport interface EventAgentRule {\n /** Exact domain event name to subscribe to. */\n eventName: string\n /** Filter or build task request from domain event payload. Return null to skip. */\n createTask: (payload: unknown) => Omit<ServerAgentTaskRequest, 'id'> | null\n}\n\n/**\n * Host error/audit notification for event conversion, queueing, execution, result, or approval delivery.\n * @see EventAgentBridgeOptions.onError.\n */\nexport interface EventAgentBridgeError {\n /** Domain event associated with the failure. */\n eventName: string\n /** Optional generated task identifier, absent before task creation. */\n taskId?: string\n /** Stage where the failure was observed. */\n phase: 'createTask' | 'queue' | 'runTask' | 'result' | 'notification'\n /** Original failure value, which may not be an Error. */\n error: unknown\n /** Optional normalized task result associated with the failure. */\n result?: ServerAgentTaskResult\n}\n\n/**\n * Event, generated task, and pending result delivered to the host approval sink.\n * @see EventAgentBridgeOptions.onPendingApproval.\n */\nexport interface EventAgentPendingApproval {\n /** Originating domain event name. */\n eventName: string\n /** Original event payload (cloned when durable queue mode is used). */\n payload: unknown\n /** Generated verified task whose runtime requested approval. */\n task: ServerAgentTaskRequest\n /** PENDING_APPROVAL result; the host must persist/deliver the approval request. */\n result: ServerAgentTaskResult\n}\n\n/**\n * In-process backpressure, host notifications, and optional durable delivery for {@link EventAgentBridge}.\n */\nexport interface EventAgentBridgeOptions {\n /** In-process worker concurrency, safe integer 1–1024. Defaults to 1; durable run passes use this as their claim ceiling but are not globally serialized. */\n maxConcurrent?: number\n /** In-process waiting queue ceiling while workers are fully occupied, safe integer 0–1000000. Defaults to 100. */\n maxQueueSize?: number\n /** Host-owned notification/audit sink for approval requests. */\n onPendingApproval?: (pending: EventAgentPendingApproval) => Promise<void> | void\n /** Host error/audit sink; returned Promise rejection is logged. Keep the callback itself nonthrowing because synchronous errors can escape reporting. */\n onError?: (error: EventAgentBridgeError) => Promise<void> | void\n /** Optional host-owned durable queue. When set, events are persisted until runDurableOnce drains them. */\n taskStore?: EventAgentTaskStore\n}\n\n/**\n * Domain event and generated task stored as one event queue item.\n * @see EventAgentTaskStore.\n */\nexport interface QueuedEventTask {\n /** Originating subscribed event name. */\n eventName: string\n /** Associated event payload; durable enqueue receives a structured clone. */\n payload: unknown\n /** Generated task with ID and execution idempotency context. */\n task: ServerAgentTaskRequest\n}\n\n/** Host-owned durable queue for event-triggered agent work.\n * @see EventAgentBridge.withDurableTaskStore for usage.\n */\nexport interface EventAgentTaskStore {\n /**\n * Persists accepted event work before a scheduler drains it.\n * @param task - Verified generated task and cloneable event payload.\n * @returns No value; resolves after host persistence.\n * @throws Queue failures propagate to bridge error reporting.\n \n * @example\n * ```typescript\n * import type { EventAgentTaskStore } from \"@alneas/eaos-server\";\n * export async function enqueueAdmittedEventTask(\n * store: EventAgentTaskStore, task: Parameters<EventAgentTaskStore[\"enqueue\"]>[0],\n * ) {\n * // Host admission and the event-to-task mapping run before queue insertion.\n * await store.enqueue(task);\n * }\n * ```\n */\n enqueue(task: QueuedEventTask): Promise<void>\n /**\n * Exclusively claims work for one drain pass.\n * @param limit - Requested maximum item count.\n * @returns Claimed queue items, or an empty array.\n * @throws Queue failures reject the drain pass.\n \n * @example\n * ```typescript\n * import type { EventAgentTaskStore } from \"@alneas/eaos-server\";\n * export async function claimEventTasks(store: EventAgentTaskStore) {\n * const tasks = await store.claim(10);\n * return tasks; // Empty when no eligible tasks are available.\n * }\n * ```\n */\n claim(limit: number): Promise<readonly QueuedEventTask[]>\n /**\n * Persists the normalized result for a claimed task.\n * @param taskId - Claimed task identifier.\n * @param result - Runtime outcome, including failed/pending statuses.\n * @returns No value; resolves after persistence.\n * @throws Completion failure causes the bridge to call fail.\n \n * @example\n * ```typescript\n * import type { EventAgentTaskStore } from \"@alneas/eaos-server\";\n * export async function completeEventTask(\n * store: EventAgentTaskStore, claimedTaskId: string,\n * result: Parameters<EventAgentTaskStore[\"complete\"]>[1],\n * ) {\n * await store.complete(claimedTaskId, result);\n * // The host decides persistence and result retention for this queue.\n * }\n * ```\n */\n complete(taskId: string, result: ServerAgentTaskResult): Promise<void>\n /**\n * Records or handles a claimed execution/persistence failure.\n * @param taskId - Claimed task identifier.\n * @param error - Underlying execution or completion failure.\n * @returns No value; completion/retry semantics belong to the host store.\n * @throws Failures reject the drain pass.\n \n * @example\n * ```typescript\n * import type { EventAgentTaskStore } from \"@alneas/eaos-server\";\n * export async function recordEventTaskFailure(\n * store: EventAgentTaskStore, claimedTaskId: string, observedError: unknown,\n * ) {\n * await store.fail(claimedTaskId, observedError);\n * // Failure/retry policy belongs to the host store; this does not retry execution.\n * }\n * ```\n */\n fail(taskId: string, error: unknown): Promise<void>\n}\n\n/**\n * Small process-local TaskStore for development, tests and a single short-\n * lived host. It deliberately has no lease recovery or persistence and must\n * not be used as the production workflow/checkpoint store.\n * @remarks Duplicate IDs compare JSON serialization exactly. Completed history/results are retained without the active-task capacity limit. No retry, lease recovery, or durable failure history exists.\n * @example\n * ```typescript\n * import { InMemoryEventAgentTaskStore } from \"@alneas/eaos-server/agentic/event-bridge\";\n * const store = new InMemoryEventAgentTaskStore();\n * console.log(await store.claim(1)); // []\n * ```\n */\nexport class InMemoryEventAgentTaskStore implements EventAgentTaskStore {\n private readonly pending = new Map<string, QueuedEventTask>()\n private readonly claimed = new Map<string, QueuedEventTask>()\n private readonly completed = new Map<string, QueuedEventTask>()\n private readonly results = new Map<string, ServerAgentTaskResult>()\n private readonly maxTasks: number\n\n /**\n * Creates an empty local queue with an active pending/claimed capacity limit.\n * @param options - maxTasks defaults to 10000 and must be a safe integer 1–1000000.\n * @throws Invalid capacity.\n */\n constructor(options: { \n /**\n * Maximum pending plus claimed tasks retained at once; defaults to 10000 and must be a safe integer from 1 to 1000000. Completed history/results are outside this limit.\n */\n maxTasks?: number } = {}) {\n this.maxTasks = options.maxTasks ?? 10_000\n if (!Number.isSafeInteger(this.maxTasks) || this.maxTasks < 1 || this.maxTasks > 1_000_000) throw new Error('Invalid in-memory agent task store limit')\n }\n\n /**\n * Clones a queued task unless its ID is already identically retained.\n * @param task - Nonempty task ID and event name with structured-cloneable payload/task.\n * @returns No value; resolves after local insertion or matching duplicate detection.\n * @throws Missing identifiers, conflicting duplicate, active capacity exhaustion, or clone/JSON failure.\n * @example\n * ```typescript\n * import { InMemoryEventAgentTaskStore } from \"@alneas/eaos-server/agentic/event-bridge\";\n * import type { QueuedEventTask } from \"@alneas/eaos-server/agentic/event-bridge\";\n * export async function enqueue(store: InMemoryEventAgentTaskStore, task: QueuedEventTask) { await store.enqueue(task); }\n * ```\n */\n async enqueue(task: QueuedEventTask): Promise<void> {\n if (!task?.task?.id || !task.eventName) throw new Error('Invalid queued event task')\n const existing = this.pending.get(task.task.id) ?? this.claimed.get(task.task.id) ?? this.completed.get(task.task.id)\n if (existing) {\n if (JSON.stringify(existing) !== JSON.stringify(task)) throw new Error('Conflicting duplicate event agent task')\n return\n }\n if (this.pending.size + this.claimed.size >= this.maxTasks) throw new Error('In-memory agent task store is full')\n this.pending.set(task.task.id, structuredClone(task))\n }\n\n /**\n * Moves pending items into the claimed map in insertion order.\n * @param limit - Positive safe-integer maximum item count.\n * @returns Cloned claimed items, or an empty array.\n * @throws Invalid limit or clone failure; an item may already have moved before clone failure.\n * @example\n * ```typescript\n * import { InMemoryEventAgentTaskStore } from \"@alneas/eaos-server/agentic/event-bridge\";\n * const store = new InMemoryEventAgentTaskStore();\n * console.log(await store.claim(1)); // []\n * ```\n */\n async claim(limit: number): Promise<readonly QueuedEventTask[]> {\n if (!Number.isSafeInteger(limit) || limit < 1) throw new Error('Invalid in-memory agent task claim limit')\n const claimed: QueuedEventTask[] = []\n for (const [taskId, task] of this.pending) {\n this.pending.delete(taskId)\n this.claimed.set(taskId, task)\n claimed.push(structuredClone(task))\n if (claimed.length >= limit) break\n }\n return claimed\n }\n\n /**\n * Moves a claimed task into retained completion history and clones its result.\n * @param taskId - Current claimed task identifier.\n * @param result - Normalized runtime outcome, including FAILED or PENDING_APPROVAL data.\n * @returns No value; completes after retaining history and result.\n * @throws Unknown/already completed task or clone failure; history can already have changed.\n * @example\n * ```typescript\n * import { InMemoryEventAgentTaskStore } from \"@alneas/eaos-server/agentic/event-bridge\";\n * import type { ServerAgentTaskResult } from \"@alneas/eaos-server/agentic/types\";\n * export async function complete(store: InMemoryEventAgentTaskStore, taskId: string, result: ServerAgentTaskResult) { await store.complete(taskId, result); }\n * ```\n */\n async complete(taskId: string, result: ServerAgentTaskResult): Promise<void> {\n const task = this.claimed.get(taskId)\n if (!task) throw new Error('Unknown or already completed event agent task')\n this.claimed.delete(taskId)\n this.completed.set(taskId, task)\n this.results.set(taskId, structuredClone(result))\n }\n\n /**\n * Removes a claimed task without retaining failure history or rescheduling it.\n * @param taskId - Current claimed task identifier.\n * @param _error - Failure value accepted for interface compatibility and ignored.\n * @returns No value; resolves after removal.\n * @throws Unknown/already failed task.\n * @example\n * ```typescript\n * import { InMemoryEventAgentTaskStore } from \"@alneas/eaos-server/agentic/event-bridge\";\n * export async function fail(store: InMemoryEventAgentTaskStore, taskId: string, error: unknown) { await store.fail(taskId, error); }\n * ```\n */\n async fail(taskId: string, _error: unknown): Promise<void> {\n if (!this.claimed.delete(taskId)) throw new Error('Unknown or already failed event agent task')\n }\n\n /**\n * Inspects a cloned retained completion result for local tests/development.\n * @param taskId - Previously completed task identifier.\n * @returns Cloned result, or undefined if no completion result exists.\n * @throws If a retained result cannot be cloned.\n * @example\n * ```typescript\n * import { InMemoryEventAgentTaskStore } from \"@alneas/eaos-server/agentic/event-bridge\";\n * console.log(new InMemoryEventAgentTaskStore().getResult(\"missing\")); // undefined\n * ```\n */\n getResult(taskId: string): ServerAgentTaskResult | undefined {\n const result = this.results.get(taskId)\n return result ? structuredClone(result) : undefined\n }\n}\n\n/**\n * Converts subscribed domain events into bounded local execution or host-persisted agent work.\n * @remarks Without taskStore, accepted work is process-local and can be lost on restart. With taskStore, the host explicitly calls runDurableOnce; event subscription callbacks still do not await durable persistence from the publisher's perspective. Authorize identity in createTask before creating specifications. Generated task IDs/idempotency defaults are per emission, so repeated events are not automatically deduplicated. Dispose every registerRule callback to release subscriptions; no global destroy is provided.\n * @example\n * ```typescript\n * import { EventAgentBridge } from \"@alneas/eaos-server/agentic/event-bridge\";\n * import type { DomainEventBus } from \"@alneas/eaos-core\";\n * import type { ServerAutonomousWorker } from \"@alneas/eaos-server/agentic/autonomous-worker\";\n * export function bridge(eventBus: DomainEventBus, worker: ServerAutonomousWorker) { return new EventAgentBridge(eventBus, worker); }\n * ```\n */\nexport class EventAgentBridge {\n private eventBus: DomainEventBus\n private worker: ServerAutonomousWorker\n private rules: Map<string, EventAgentRule[]> = new Map()\n private subscriptions: Map<string, (payload: unknown) => void> = new Map()\n private queue: QueuedEventTask[] = []\n private activeCount = 0\n private readonly maxConcurrent: number\n private readonly maxQueueSize: number\n private readonly onPendingApproval?: EventAgentBridgeOptions['onPendingApproval']\n private readonly onError?: EventAgentBridgeOptions['onError']\n private taskStore?: EventAgentTaskStore\n private taskCounter = 0\n\n /**\n * Captures an event bus and worker and validates local backpressure limits.\n * @param eventBus - Host domain bus; subscriptions begin only on registerRule.\n * @param worker - Host worker performing gatekeeper/runtime execution.\n * @param options - Queue limits, notification/error callbacks, and optional durable store.\n * @throws Invalid limits or malformed durable store.\n */\n constructor(eventBus: DomainEventBus, worker: ServerAutonomousWorker, options: EventAgentBridgeOptions = {}) {\n this.eventBus = eventBus\n this.worker = worker\n // Safe defaults for a 1 GB application-worker and an ARM agent runtime.\n // Hosts with measured capacity may raise these explicitly.\n this.maxConcurrent = options.maxConcurrent ?? 1\n this.maxQueueSize = options.maxQueueSize ?? 100\n if (!Number.isSafeInteger(this.maxConcurrent) || this.maxConcurrent < 1 || this.maxConcurrent > 1_024) throw new Error('Invalid EventAgentBridge maxConcurrent')\n if (!Number.isSafeInteger(this.maxQueueSize) || this.maxQueueSize < 0 || this.maxQueueSize > 1_000_000) throw new Error('Invalid EventAgentBridge maxQueueSize')\n this.onPendingApproval = options.onPendingApproval\n this.onError = options.onError\n if (options.taskStore) this.withDurableTaskStore(options.taskStore)\n }\n\n /**\n * Persisted event work is deliberately drained by the host scheduler. The\n * bridge never treats its in-memory queue as a durable workflow checkpoint.\n * @param store - Host durable queue with enqueue/claim/complete/fail functions.\n * @returns This bridge after replacing its store reference.\n * @throws Missing/malformed store functions.\n * @remarks Existing local queued work is not migrated by changing this store.\n * @example\n * ```typescript\n * import { EventAgentBridge } from \"@alneas/eaos-server/agentic/event-bridge\";\n * import type { EventAgentTaskStore } from \"@alneas/eaos-server/agentic/event-bridge\";\n * export function persist(bridge: EventAgentBridge, store: EventAgentTaskStore) { return bridge.withDurableTaskStore(store); }\n * ```\n */\n withDurableTaskStore(store: EventAgentTaskStore): this {\n if (!store || typeof store.enqueue !== 'function' || typeof store.claim !== 'function' || typeof store.complete !== 'function' || typeof store.fail !== 'function') throw new Error('Invalid durable event agent task store')\n this.taskStore = store\n return this\n }\n\n /**\n * Claims one bounded durable batch and processes it sequentially.\n * @param limit - Safe integer 1–maxConcurrent; defaults to maxConcurrent.\n * @returns Claim/completion/failure persistence counts; a worker FAILED result counts completed if stored successfully.\n * @throws Missing store, invalid limit, claim/fail persistence errors, or synchronous error-sink errors.\n * @remarks Calls are not globally serialized. Notification failures are reported after result persistence. No periodic scheduler or automatic retry is installed.\n * @example\n * ```typescript\n * import { EventAgentBridge } from \"@alneas/eaos-server/agentic/event-bridge\";\n * export async function drain(bridge: EventAgentBridge) { return bridge.runDurableOnce(); }\n * ```\n */\n async runDurableOnce(limit = this.maxConcurrent): Promise<{ \n /** Number of queued tasks returned by the host claim for this pass, including tasks later recorded as completed or failed. */\n claimed: number; \n /** Number of task results successfully passed to store.complete; a returned worker FAILED or PENDING_APPROVAL status still counts when its result is stored. */\n completed: number; \n /** Number of worker throws or store.complete failures handled through store.fail; this counts persistence/execution handling failures rather than every returned worker FAILED status. */\n failed: number }> {\n if (!this.taskStore) throw new Error('Durable event agent task store is not configured')\n if (!Number.isSafeInteger(limit) || limit < 1 || limit > this.maxConcurrent) throw new Error('Invalid durable event agent task limit')\n const tasks = await this.taskStore.claim(limit)\n let completed = 0, failed = 0\n for (const queued of tasks) {\n let result: ServerAgentTaskResult\n try {\n result = await this.worker.runTask(queued.task)\n } catch (error) {\n failed++\n await this.taskStore.fail(queued.task.id, error)\n this.reportError({ eventName: queued.eventName, taskId: queued.task.id, phase: 'runTask', error })\n continue\n }\n try {\n await this.taskStore.complete(queued.task.id, result)\n completed++\n } catch (error) {\n failed++\n await this.taskStore.fail(queued.task.id, error)\n this.reportError({ eventName: queued.eventName, taskId: queued.task.id, phase: 'result', error, result })\n continue\n }\n if (result.status === 'PENDING_APPROVAL' && this.onPendingApproval) {\n try { await this.onPendingApproval({ eventName: queued.eventName, payload: queued.payload, task: queued.task, result }) }\n catch (error) { this.reportError({ eventName: queued.eventName, taskId: queued.task.id, phase: 'notification', error, result }) }\n }\n if (result.status === 'FAILED') this.reportError({ eventName: queued.eventName, taskId: queued.task.id, phase: 'result', error: result.error ?? new Error('Agent task failed'), result })\n }\n return { claimed: tasks.length, completed, failed }\n }\n\n /**\n * Subscribes a task-conversion rule and returns its individual unsubscribe callback.\n * @param rule - Exact event name and synchronous createTask callback; callback receives payload and returns verified task fields or null to skip.\n * @returns A no-argument callback returning no value; removes this rule and unsubscribes the bus handler when no rules remain.\n * @throws Event bus subscription/unsubscription errors can propagate. Event conversion errors are reported through onError.\n * @remarks The rule is retained by reference; do not mutate its eventName after registration. Already accepted tasks keep running after unsubscribe.\n * @example\n * ```typescript\n * import { EventAgentBridge } from \"@alneas/eaos-server/agentic/event-bridge\";\n * import type { EventAgentRule } from \"@alneas/eaos-server/agentic/event-bridge\";\n * export function listen(bridge: EventAgentBridge, rule: EventAgentRule) { return bridge.registerRule(rule); }\n * ```\n */\n registerRule(rule: EventAgentRule): () => void {\n if (!this.rules.has(rule.eventName)) {\n this.rules.set(rule.eventName, [])\n const handler = (payload: unknown) => {\n void this.handleEvent(rule.eventName, payload).catch(error => {\n this.reportError({ eventName: rule.eventName, phase: 'createTask', error })\n })\n }\n this.subscriptions.set(rule.eventName, handler)\n this.eventBus.subscribe(rule.eventName, handler)\n }\n this.rules.get(rule.eventName)!.push(rule)\n return () => {\n const list = this.rules.get(rule.eventName)\n if (list) {\n const index = list.indexOf(rule)\n if (index >= 0) list.splice(index, 1)\n if (list.length === 0) {\n this.rules.delete(rule.eventName)\n const handler = this.subscriptions.get(rule.eventName)\n if (handler) this.eventBus.unsubscribe(rule.eventName, handler)\n this.subscriptions.delete(rule.eventName)\n }\n }\n }\n }\n\n /**\n * Waits until the bridge's local active count and waiting queue are empty.\n * @returns No value; resolves when local work is idle. It does not wait for durable queue persistence/draining or asynchronous error sinks.\n * @remarks Polls with zero-delay timers and has no timeout/cancellation; continuously arriving work can delay completion indefinitely.\n * @example\n * ```typescript\n * import { EventAgentBridge } from \"@alneas/eaos-server/agentic/event-bridge\";\n * export async function idle(bridge: EventAgentBridge) { await bridge.whenIdle(); }\n * ```\n */\n async whenIdle(): Promise<void> {\n while (this.activeCount > 0 || this.queue.length > 0) await new Promise(resolve => setTimeout(resolve, 0))\n }\n\n private async handleEvent(eventName: string, payload: unknown): Promise<void> {\n const list = this.rules.get(eventName)\n if (!list || list.length === 0) return\n\n for (const rule of [...list]) {\n let taskSpec: Omit<ServerAgentTaskRequest, 'id'> | null\n try {\n taskSpec = rule.createTask(payload)\n } catch (error) {\n this.reportError({ eventName, phase: 'createTask', error })\n continue\n }\n if (!taskSpec) continue\n\n const taskId = `evt_${Date.now()}_${++this.taskCounter}`\n const task: ServerAgentTaskRequest = {\n ...taskSpec,\n id: taskId,\n executionContext: {\n ...taskSpec.executionContext,\n idempotencyKey: taskSpec.executionContext?.idempotencyKey ?? `event-agent:${eventName}:${taskId}`,\n },\n }\n if (this.taskStore) {\n try { await this.taskStore.enqueue({ eventName, payload: structuredClone(payload), task: structuredClone(task) }) }\n catch (error) { this.reportError({ eventName, taskId: task.id, phase: 'queue', error }) }\n continue\n }\n if (this.queue.length >= this.maxQueueSize && this.activeCount >= this.maxConcurrent) {\n this.reportError({ eventName, taskId: task.id, phase: 'queue', error: new Error('EventAgentBridge queue is full') })\n continue\n }\n this.queue.push({ eventName, payload, task })\n }\n this.drain()\n }\n\n private drain(): void {\n while (this.activeCount < this.maxConcurrent && this.queue.length > 0) {\n const queued = this.queue.shift()!\n this.activeCount += 1\n void this.execute(queued).finally(() => {\n this.activeCount -= 1\n this.drain()\n })\n }\n }\n\n private async execute(queued: QueuedEventTask): Promise<void> {\n let result: ServerAgentTaskResult\n try {\n result = await this.worker.runTask(queued.task)\n } catch (error) {\n this.reportError({ eventName: queued.eventName, taskId: queued.task.id, phase: 'runTask', error })\n return\n }\n\n if (result.status === 'PENDING_APPROVAL') {\n try {\n if (this.onPendingApproval) await this.onPendingApproval({ eventName: queued.eventName, payload: queued.payload, task: queued.task, result })\n else console.warn('[EventAgentBridge] Agent task pending approval', { eventName: queued.eventName, taskId: queued.task.id, approvalTicketId: result.approvalTicketId })\n } catch (error) {\n this.reportError({ eventName: queued.eventName, taskId: queued.task.id, phase: 'notification', error, result })\n }\n return\n }\n if (result.status === 'FAILED') this.reportError({ eventName: queued.eventName, taskId: queued.task.id, phase: 'result', error: result.error ?? new Error('Agent task failed'), result })\n }\n\n private reportError(detail: EventAgentBridgeError): void {\n if (this.onError) {\n void Promise.resolve(this.onError(detail)).catch(error => console.error('[EventAgentBridge] Error sink failed', error))\n return\n }\n console.error('[EventAgentBridge] Event task failed', {\n eventName: detail.eventName,\n taskId: detail.taskId,\n phase: detail.phase,\n error: detail.error instanceof Error ? detail.error.message : String(detail.error),\n })\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,15 @@
1
+ // src/plugin-data/atomic-context.ts
2
+ var atomicSqlBindings = /* @__PURE__ */ new WeakMap();
3
+ function inheritAtomicSqlSession(source, wrapper) {
4
+ const binding = atomicSqlBindings.get(source);
5
+ if (binding) atomicSqlBindings.set(wrapper, binding);
6
+ return () => {
7
+ atomicSqlBindings.delete(wrapper);
8
+ };
9
+ }
10
+
11
+ export {
12
+ atomicSqlBindings,
13
+ inheritAtomicSqlSession
14
+ };
15
+ //# sourceMappingURL=chunk-3VITSHN3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugin-data/atomic-context.ts"],"sourcesContent":["import type { AtomicSession, AtomicSqlConnection, AtomicSqlDriver } from './atomic'\nimport type { PluginPrincipal } from './index'\n/**\n * Weak capability map joining validated session wrappers to their live SQL connection, principal and dialect; trusted adapter plumbing only.\n * \n *\n * Internal capability propagation through validated session wrappers; never a new transaction.\n * @see inheritAtomicSqlSession for canonical usage.\n */\nexport const atomicSqlBindings = new WeakMap<AtomicSession,{\n /**\n * Exact active SQL connection whose commit/rollback boundary owns this session.\n */\n connection:AtomicSqlConnection;\n /**\n * Verified tenant/user scope bound to this live connection.\n */\n principal:PluginPrincipal;\n /**\n * Trusted SQL dialect of the joined transaction driver.\n */\n dialect:AtomicSqlDriver['dialect']}>()\n/**\n * Temporarily propagate an existing joined SQL capability to a validated session wrapper.\n * @param source - Currently bound source session; if unbound no capability is created.\n * @param wrapper - Wrapper session whose lifetime must not exceed the parent callback.\n * @returns A release callback deleting the wrapper's propagated binding.\n * @remarks Internal trusted capability plumbing exposed for validated host adapters. It never opens a transaction, authenticates a principal or extends the underlying session lifetime.\n * @example\n * import { inheritAtomicSqlSession } from '@alneas/eaos-server/plugin-data/atomic-context'\n * export function withBinding(source: Parameters<typeof inheritAtomicSqlSession>[0], wrapper: Parameters<typeof inheritAtomicSqlSession>[1], work: () => void) { const release = inheritAtomicSqlSession(source, wrapper); try { work() } finally { release() } }\n */\nexport function inheritAtomicSqlSession(source:AtomicSession,wrapper:AtomicSession):()=>void {\n const binding=atomicSqlBindings.get(source)\n if(binding)atomicSqlBindings.set(wrapper,binding)\n return ()=>{atomicSqlBindings.delete(wrapper)}\n}\n"],"mappings":";AASO,IAAM,oBAAoB,oBAAI,QAYE;AAWhC,SAAS,wBAAwB,QAAqB,SAAgC;AAC5F,QAAM,UAAQ,kBAAkB,IAAI,MAAM;AAC1C,MAAG,QAAQ,mBAAkB,IAAI,SAAQ,OAAO;AAChD,SAAO,MAAI;AAAC,sBAAkB,OAAO,OAAO;AAAA,EAAC;AAC9C;","names":[]}
@@ -0,0 +1,226 @@
1
+ import {
2
+ appendAtomicAudit
3
+ } from "./chunk-INCHXAFK.js";
4
+
5
+ // src/entitlements/index.ts
6
+ import { Hono } from "hono";
7
+ import { createMiddleware } from "hono/factory";
8
+ import { assertPlatformPrincipal, assertTenantEntitlements as assertTenantEntitlements2, evaluatePluginEntitlement } from "@alneas/eaos-core";
9
+
10
+ // src/entitlements/sql.ts
11
+ import { assertTenantEntitlements } from "@alneas/eaos-core";
12
+ var tenantEntitlementContract = {
13
+ id: "platform-entitlements",
14
+ version: "1.0.0",
15
+ description: "Tenant subscription and plugin addon grants",
16
+ schema: { type: "object", required: ["tenant_id", "plan_tier", "status", "addons_json", "quotas_json", "revision", "plugin_data"], properties: {
17
+ tenant_id: { type: "string" },
18
+ plan_tier: { type: "string", enum: ["free", "standard", "pro"] },
19
+ status: { type: "string", enum: ["active", "suspended"] },
20
+ valid_until: { type: ["string", "null"] },
21
+ addons_json: { type: "string" },
22
+ quotas_json: { type: "string" },
23
+ revision: { type: "integer", minimum: 1 },
24
+ plugin_data: { type: "string", default: "{}" }
25
+ }, "x-db": { tableName: "eaos_tenant_entitlements" } },
26
+ migrations: [{ id: "001_tenant_entitlements", scope: "database", sql: {
27
+ sqlite: ["CREATE TABLE eaos_tenant_entitlements(tenant_id TEXT PRIMARY KEY NOT NULL,plan_tier TEXT NOT NULL CHECK(plan_tier IN ('free','standard','pro')),status TEXT NOT NULL CHECK(status IN ('active','suspended')),valid_until TEXT,addons_json TEXT NOT NULL CHECK(json_valid(addons_json)),quotas_json TEXT NOT NULL CHECK(json_valid(quotas_json)),revision INTEGER NOT NULL,plugin_data TEXT NOT NULL DEFAULT '{}' CHECK(json_valid(plugin_data)))"],
28
+ postgres: ["CREATE TABLE eaos_tenant_entitlements(tenant_id VARCHAR(128) PRIMARY KEY,plan_tier VARCHAR(16) NOT NULL CHECK(plan_tier IN ('free','standard','pro')),status VARCHAR(16) NOT NULL CHECK(status IN ('active','suspended')),valid_until VARCHAR(64),addons_json JSONB NOT NULL,quotas_json JSONB NOT NULL,revision BIGINT NOT NULL,plugin_data JSONB NOT NULL DEFAULT '{}')"],
29
+ oracle: ["CREATE TABLE eaos_tenant_entitlements(tenant_id VARCHAR2(128) PRIMARY KEY,plan_tier VARCHAR2(16) NOT NULL CHECK(plan_tier IN ('free','standard','pro')),status VARCHAR2(16) NOT NULL CHECK(status IN ('active','suspended')),valid_until VARCHAR2(64),addons_json CLOB NOT NULL CHECK(addons_json IS JSON),quotas_json CLOB NOT NULL CHECK(quotas_json IS JSON),revision NUMBER(19) NOT NULL,plugin_data CLOB DEFAULT '{}' NOT NULL CHECK(plugin_data IS JSON))"]
30
+ } }]
31
+ };
32
+ function createSqlTenantEntitlementLoader(driver) {
33
+ return async (tenantId) => {
34
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(tenantId)) throw Error("Verified entitlement tenant required");
35
+ const bind = driver.dialect === "oracle" ? ":1" : driver.dialect === "postgres" ? "$1" : "?";
36
+ const rows = (await driver.execute(`SELECT tenant_id,plan_tier,status,valid_until,addons_json,quotas_json FROM eaos_tenant_entitlements WHERE tenant_id=${bind}`, [tenantId])).rows ?? [];
37
+ if (!rows.length) return null;
38
+ if (rows.length !== 1) throw Error("Ambiguous tenant entitlement");
39
+ const row = Object.fromEntries(Object.entries(rows[0]).map(([k, v]) => [k.toLowerCase(), v]));
40
+ const json = (value) => typeof value === "string" ? JSON.parse(value) : value;
41
+ const result = { tenantId: String(row.tenant_id), plan: row.plan_tier, status: row.status, addons: json(row.addons_json), monthlyQuotas: json(row.quotas_json), ...row.valid_until ? { validUntil: String(row.valid_until) } : {} };
42
+ assertTenantEntitlements(result);
43
+ if (result.tenantId !== tenantId) throw Error("Entitlement tenant differs");
44
+ return result;
45
+ };
46
+ }
47
+
48
+ // src/entitlements/index.ts
49
+ var EntitlementError = class extends Error {
50
+ /**
51
+ * Creates an error whose message is the denial reason.
52
+ * @param decision - Denied decision retained as a public readonly property for status/reason mapping.
53
+ */
54
+ constructor(decision) {
55
+ super(decision.reason);
56
+ this.decision = decision;
57
+ }
58
+ decision;
59
+ };
60
+ var PluginEntitlementRuntime = class {
61
+ /**
62
+ * Retains host control-plane callbacks and repository without opening a connection.
63
+ * @param options - Trusted entitlement persistence, active-plugin checks, and optional clock.
64
+ */
65
+ constructor(options) {
66
+ this.options = options;
67
+ }
68
+ options;
69
+ /**
70
+ * Loads and validates current tenant contract data for a verified principal.
71
+ * @param principal - Verified platform principal validated by assertPlatformPrincipal.
72
+ * @param session - Optional active atomic session; loadInTransaction is used only when both are supplied.
73
+ * @returns A structured clone of current entitlements, or null when absent.
74
+ * @throws Rejects invalid principal/contract, mismatched tenant, clone errors, or host load failures.
75
+ * @example
76
+ * ```typescript
77
+ * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from "@alneas/eaos-server/entitlements";
78
+ * import type { PlatformPrincipal } from "@alneas/eaos-core";
79
+ * export async function snapshot(options: EntitlementRuntimeOptions, principal: PlatformPrincipal) {
80
+ * return new PluginEntitlementRuntime(options).snapshot(principal);
81
+ * }
82
+ * ```
83
+ */
84
+ async snapshot(principal, session) {
85
+ assertPlatformPrincipal(principal);
86
+ const result = session && this.options.loadInTransaction ? await this.options.loadInTransaction(principal, session) : await this.options.load(principal.tenantId);
87
+ if (result) assertTenantEntitlements2(result);
88
+ if (result && result.tenantId !== principal.tenantId) throw Error("Entitlement tenant differs");
89
+ return result && structuredClone(result);
90
+ }
91
+ /**
92
+ * Evaluates lifecycle and subscription policy without consuming quota.
93
+ * @param principal - Verified user/tenant principal.
94
+ * @param pluginId - Exact plugin ID used by lifecycle and entitlement evaluation.
95
+ * @param rule - Plugin access tier, allowed tenants, and optional metering declaration.
96
+ * @param session - Optional reservation transaction for a joined contract read.
97
+ * @returns Allowed/denied decision; inactive lifecycle returns denied 404 tenant-locked. This check does not reserve usage.
98
+ * @throws Rejects invalid data or propagated lifecycle/load/clock errors.
99
+ * @example
100
+ * ```typescript
101
+ * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from "@alneas/eaos-server/entitlements";
102
+ * import type { PlatformPrincipal, PluginEntitlement } from "@alneas/eaos-core";
103
+ * export async function check(options: EntitlementRuntimeOptions, principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement) {
104
+ * return new PluginEntitlementRuntime(options).check(principal, pluginId, rule);
105
+ * }
106
+ * ```
107
+ */
108
+ async check(principal, pluginId, rule, session) {
109
+ assertPlatformPrincipal(principal);
110
+ if (!await this.options.isActive(principal, pluginId)) return { allowed: false, status: 404, reason: "tenant-locked" };
111
+ return evaluatePluginEntitlement(pluginId, rule, principal.tenantId, await this.snapshot(principal, session), this.options.clock?.() ?? /* @__PURE__ */ new Date());
112
+ }
113
+ /**
114
+ * Rechecks entitlement under the repository transaction and reserves one metered attempt with an audit entry.
115
+ * @param principal - Verified principal used for tenant-scoped repository admission.
116
+ * @param pluginId - Plugin whose live entitlement is required.
117
+ * @param rule - Current plugin entitlement policy; unmetered rules perform no counter write.
118
+ * @param operation - Host operation label recorded in metering audit data.
119
+ * @returns No value; resolves after entitlement admission and any quota/audit persistence.
120
+ * @throws Rejects EntitlementError for denied policy/quota, invalid stored usage counter, or host transaction/load/lifecycle/audit failures.
121
+ * @remarks Counters use a UTC YYYY-MM period and count admitted attempts, not successful work. Calling admit repeatedly consumes repeatedly; no idempotency key is applied.
122
+ * @example
123
+ * ```typescript
124
+ * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from "@alneas/eaos-server/entitlements";
125
+ * import type { PlatformPrincipal, PluginEntitlement } from "@alneas/eaos-core";
126
+ * export async function admit(options: EntitlementRuntimeOptions, principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement) {
127
+ * await new PluginEntitlementRuntime(options).admit(principal, pluginId, rule, "example:execute");
128
+ * }
129
+ * ```
130
+ */
131
+ async admit(principal, pluginId, rule, operation) {
132
+ await this.options.repository.run(principal, async (tx) => {
133
+ const decision = await this.check(principal, pluginId, rule, tx);
134
+ if (!decision.allowed) throw new EntitlementError(decision);
135
+ if (!rule.metering) return;
136
+ const month = (this.options.clock?.() ?? /* @__PURE__ */ new Date()).toISOString().slice(0, 7);
137
+ const key = `metering/${pluginId}/${rule.metering.unit}/${month}`;
138
+ const old = await tx.get(key);
139
+ const used = old?.value.used ?? 0;
140
+ if (!Number.isSafeInteger(used) || used < 0) throw Error("Invalid durable usage counter");
141
+ if (used >= decision.quota) throw new EntitlementError({ allowed: false, status: 402, reason: "quota-exceeded" });
142
+ await tx.put(key, { used: used + 1 }, old?.revision ?? 0);
143
+ await appendAtomicAudit(tx, principal, "plugin.metered", { pluginId, unit: rule.metering.unit, month, operation }, { used: used + 1 });
144
+ });
145
+ }
146
+ /**
147
+ * Reserves admission before executing host work outside the reservation transaction.
148
+ * @typeParam T - Resolved host work result.
149
+ * @param principal - Verified tenant/user principal.
150
+ * @param pluginId - Required plugin ID.
151
+ * @param rule - Plugin entitlement policy.
152
+ * @param operation - Host operation label for metering audit.
153
+ * @param work - Called without arguments only after admission; resolves the business result.
154
+ * @returns The host work result.
155
+ * @throws Rejects admission or work failures; failed work does not refund a reservation.
156
+ * @example
157
+ * ```typescript
158
+ * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from "@alneas/eaos-server/entitlements";
159
+ * import type { PlatformPrincipal, PluginEntitlement } from "@alneas/eaos-core";
160
+ * export async function execute<T>(options: EntitlementRuntimeOptions, principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement, work: () => Promise<T>) {
161
+ * return new PluginEntitlementRuntime(options).run(principal, pluginId, rule, "example:execute", work);
162
+ * }
163
+ * ```
164
+ */
165
+ async run(principal, pluginId, rule, operation, work) {
166
+ await this.admit(principal, pluginId, rule, operation);
167
+ return work();
168
+ }
169
+ };
170
+ var resolveEngineEntitlementPrincipal = async (c) => {
171
+ const user = c.get("user"), tenantId = c.get("tenantId"), userId = c.get("userId");
172
+ return tenantId && userId && user?.tenantId === tenantId ? { tenantId, userId, roles: user.roles } : null;
173
+ };
174
+ function requiresEntitlementRuntime(rule) {
175
+ return rule.tier !== "public" || !!rule.metering || !!rule.allowedTenants;
176
+ }
177
+ function createPluginEntitlementGuard(pluginId, rule, runtime, resolvePrincipal = resolveEngineEntitlementPrincipal) {
178
+ return createMiddleware(async (c, next) => {
179
+ const p = await resolvePrincipal(c);
180
+ if (!p) return c.json({ error: "Unauthorized" }, 401);
181
+ assertPlatformPrincipal(p);
182
+ if (!requiresEntitlementRuntime(rule)) {
183
+ await next();
184
+ return;
185
+ }
186
+ if (!runtime) return c.json({ error: "Entitlement service unavailable" }, 503);
187
+ try {
188
+ await runtime.admit(p, pluginId, rule, `${c.req.method} ${c.req.path}`);
189
+ } catch (error) {
190
+ if (error instanceof EntitlementError) return c.json({ error: error.message }, error.decision.status);
191
+ throw error;
192
+ }
193
+ await next();
194
+ });
195
+ }
196
+ function createPluginAssetRouter(options) {
197
+ const router = new Hono();
198
+ router.get("/:pluginId/:assetId", async (c) => {
199
+ const p = await options.resolvePrincipal(c);
200
+ if (!p) return c.json({ error: "Unauthorized" }, 401);
201
+ const pluginId = c.req.param("pluginId"), assetId = c.req.param("assetId"), rule = options.plugins[pluginId];
202
+ const asset = options.assets.find((a) => a.pluginId === pluginId && a.id === assetId);
203
+ if (!rule || !asset) return c.json({ error: "Asset unavailable" }, 404);
204
+ const decision = await options.runtime.check(p, pluginId, rule);
205
+ if (!decision.allowed) return c.json({ error: decision.reason }, decision.status);
206
+ if (!/^[a-f0-9]{64}$/.test(asset.sha256)) throw Error("Invalid trusted asset checksum");
207
+ const url = await options.sign({ asset: structuredClone(asset), principal: p, expiresIn: 60 });
208
+ const current = await options.runtime.check(p, pluginId, rule);
209
+ if (!current.allowed) return c.json({ error: current.reason }, current.status);
210
+ c.header("Cache-Control", "private, no-store");
211
+ return c.json({ url, sha256: asset.sha256, contentType: asset.contentType, expiresIn: 60 });
212
+ });
213
+ return router;
214
+ }
215
+
216
+ export {
217
+ tenantEntitlementContract,
218
+ createSqlTenantEntitlementLoader,
219
+ EntitlementError,
220
+ PluginEntitlementRuntime,
221
+ resolveEngineEntitlementPrincipal,
222
+ requiresEntitlementRuntime,
223
+ createPluginEntitlementGuard,
224
+ createPluginAssetRouter
225
+ };
226
+ //# sourceMappingURL=chunk-46UWPEW2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/entitlements/index.ts","../src/entitlements/sql.ts"],"sourcesContent":["import { Hono, type Context } from 'hono'\nimport { createMiddleware } from 'hono/factory'\nimport { assertPlatformPrincipal, assertTenantEntitlements, evaluatePluginEntitlement, type PlatformPrincipal, type PluginEntitlement, type TenantEntitlements, type EntitlementDecision } from '@alneas/eaos-core'\nimport { appendAtomicAudit, type AtomicRepository, type AtomicSession } from '../plugin-data/index'\nexport * from './sql'\n\n/**\n * Carries a denied entitlement decision for HTTP or host failure handling.\n * @example\n * ```typescript\n * import { EntitlementError } from \"@alneas/eaos-server/entitlements\";\n * const error = new EntitlementError({ allowed: false, status: 402, reason: \"quota-exceeded\" });\n * console.log(error.decision.status);\n * ```\n */\nexport class EntitlementError extends Error {\n /**\n * Creates an error whose message is the denial reason.\n * @param decision - Denied decision retained as a public readonly property for status/reason mapping.\n */\n constructor(readonly decision: Exclude<EntitlementDecision, { \n /** Type-level allowed-branch discriminator removed by Exclude; this constructor accepts only denied decisions with allowed false. */\n allowed: true }>) { super(decision.reason) }\n}\n/**\n * Trusted control-plane reads, lifecycle policy, and reservation persistence for {@link PluginEntitlementRuntime}.\n */\nexport interface EntitlementRuntimeOptions {\n /** Shared durable control-plane repository, with transaction/CAS and tenant isolation. */\n repository: AtomicRepository\n /** Read current contracts from eaos_tenant_entitlements; never from request headers/body. */\n load: (tenantId: string) => Promise<TenantEntitlements | null>\n /** Optional joined control-plane read; quota and contract observe the same host transaction. */\n loadInTransaction?: (principal: PlatformPrincipal, session: AtomicSession) => Promise<TenantEntitlements | null>\n /** Same live lifecycle admission for HTTP, MCP, jobs, webhooks and asset delivery. */\n isActive: (principal: PlatformPrincipal, pluginId: string) => Promise<boolean>\n /** Clock for validity and UTC monthly metering period; defaults to a fresh Date per read. */\n clock?: () => Date\n}\n/**\n * Checks live plugin entitlements and durably reserves metered admission attempts.\n * @remarks A durable quota reservation counts admitted attempts, including failed handler attempts. No refund, cancellation, retry, or business-handler transaction is supplied. Shared concurrency/CAS and tenant isolation depend on the host AtomicRepository. For a contract snapshot consistent with reservation writes, supply loadInTransaction.\n * @example\n * ```typescript\n * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from \"@alneas/eaos-server/entitlements\";\n * export function entitlementRuntime(options: EntitlementRuntimeOptions) {\n * return new PluginEntitlementRuntime(options);\n * }\n * ```\n */\nexport class PluginEntitlementRuntime {\n /**\n * Retains host control-plane callbacks and repository without opening a connection.\n * @param options - Trusted entitlement persistence, active-plugin checks, and optional clock.\n */\n constructor(private readonly options: EntitlementRuntimeOptions) {}\n /**\n * Loads and validates current tenant contract data for a verified principal.\n * @param principal - Verified platform principal validated by assertPlatformPrincipal.\n * @param session - Optional active atomic session; loadInTransaction is used only when both are supplied.\n * @returns A structured clone of current entitlements, or null when absent.\n * @throws Rejects invalid principal/contract, mismatched tenant, clone errors, or host load failures.\n * @example\n * ```typescript\n * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from \"@alneas/eaos-server/entitlements\";\n * import type { PlatformPrincipal } from \"@alneas/eaos-core\";\n * export async function snapshot(options: EntitlementRuntimeOptions, principal: PlatformPrincipal) {\n * return new PluginEntitlementRuntime(options).snapshot(principal);\n * }\n * ```\n */\n async snapshot(principal: PlatformPrincipal, session?: AtomicSession): Promise<TenantEntitlements | null> {\n assertPlatformPrincipal(principal)\n const result = session && this.options.loadInTransaction ? await this.options.loadInTransaction(principal, session) : await this.options.load(principal.tenantId)\n if (result) assertTenantEntitlements(result)\n if (result && result.tenantId !== principal.tenantId) throw Error('Entitlement tenant differs')\n return result && structuredClone(result)\n }\n /**\n * Evaluates lifecycle and subscription policy without consuming quota.\n * @param principal - Verified user/tenant principal.\n * @param pluginId - Exact plugin ID used by lifecycle and entitlement evaluation.\n * @param rule - Plugin access tier, allowed tenants, and optional metering declaration.\n * @param session - Optional reservation transaction for a joined contract read.\n * @returns Allowed/denied decision; inactive lifecycle returns denied 404 tenant-locked. This check does not reserve usage.\n * @throws Rejects invalid data or propagated lifecycle/load/clock errors.\n * @example\n * ```typescript\n * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from \"@alneas/eaos-server/entitlements\";\n * import type { PlatformPrincipal, PluginEntitlement } from \"@alneas/eaos-core\";\n * export async function check(options: EntitlementRuntimeOptions, principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement) {\n * return new PluginEntitlementRuntime(options).check(principal, pluginId, rule);\n * }\n * ```\n */\n async check(principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement, session?: AtomicSession): Promise<EntitlementDecision> {\n assertPlatformPrincipal(principal)\n if (!await this.options.isActive(principal, pluginId)) return { allowed: false, status: 404, reason: 'tenant-locked' }\n return evaluatePluginEntitlement(pluginId, rule, principal.tenantId, await this.snapshot(principal, session), this.options.clock?.() ?? new Date())\n }\n /**\n * Rechecks entitlement under the repository transaction and reserves one metered attempt with an audit entry.\n * @param principal - Verified principal used for tenant-scoped repository admission.\n * @param pluginId - Plugin whose live entitlement is required.\n * @param rule - Current plugin entitlement policy; unmetered rules perform no counter write.\n * @param operation - Host operation label recorded in metering audit data.\n * @returns No value; resolves after entitlement admission and any quota/audit persistence.\n * @throws Rejects EntitlementError for denied policy/quota, invalid stored usage counter, or host transaction/load/lifecycle/audit failures.\n * @remarks Counters use a UTC YYYY-MM period and count admitted attempts, not successful work. Calling admit repeatedly consumes repeatedly; no idempotency key is applied.\n * @example\n * ```typescript\n * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from \"@alneas/eaos-server/entitlements\";\n * import type { PlatformPrincipal, PluginEntitlement } from \"@alneas/eaos-core\";\n * export async function admit(options: EntitlementRuntimeOptions, principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement) {\n * await new PluginEntitlementRuntime(options).admit(principal, pluginId, rule, \"example:execute\");\n * }\n * ```\n */\n async admit(principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement, operation: string): Promise<void> {\n // Read again inside the serialized reservation; a discovery check never reserves quota.\n await this.options.repository.run(principal, async tx => {\n const decision = await this.check(principal, pluginId, rule, tx)\n if (!decision.allowed) throw new EntitlementError(decision)\n if (!rule.metering) return\n const month = (this.options.clock?.() ?? new Date()).toISOString().slice(0, 7)\n const key = `metering/${pluginId}/${rule.metering.unit}/${month}`\n const old = await tx.get<{ used: number }>(key)\n const used = old?.value.used ?? 0\n if (!Number.isSafeInteger(used) || used < 0) throw Error('Invalid durable usage counter')\n if (used >= decision.quota!) throw new EntitlementError({ allowed: false, status: 402, reason: 'quota-exceeded' })\n await tx.put(key, { used: used + 1 }, old?.revision ?? 0)\n await appendAtomicAudit(tx, principal, 'plugin.metered', { pluginId, unit: rule.metering.unit, month, operation }, { used: used + 1 })\n })\n }\n /**\n * Reserves admission before executing host work outside the reservation transaction.\n * @typeParam T - Resolved host work result.\n * @param principal - Verified tenant/user principal.\n * @param pluginId - Required plugin ID.\n * @param rule - Plugin entitlement policy.\n * @param operation - Host operation label for metering audit.\n * @param work - Called without arguments only after admission; resolves the business result.\n * @returns The host work result.\n * @throws Rejects admission or work failures; failed work does not refund a reservation.\n * @example\n * ```typescript\n * import { PluginEntitlementRuntime, type EntitlementRuntimeOptions } from \"@alneas/eaos-server/entitlements\";\n * import type { PlatformPrincipal, PluginEntitlement } from \"@alneas/eaos-core\";\n * export async function execute<T>(options: EntitlementRuntimeOptions, principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement, work: () => Promise<T>) {\n * return new PluginEntitlementRuntime(options).run(principal, pluginId, rule, \"example:execute\", work);\n * }\n * ```\n */\n async run<T>(principal: PlatformPrincipal, pluginId: string, rule: PluginEntitlement, operation: string, work: () => Promise<T>): Promise<T> {\n await this.admit(principal, pluginId, rule, operation)\n return work()\n }\n}\n/**\n * Host callback resolving authenticated user/tenant membership from a request.\n * @param context - Hono request context after host authentication.\n * @returns Verified platform principal, or null to deny authentication.\n * @throws Host failures propagate through request handling.\n * @see createPluginEntitlementGuard for usage.\n */\nexport type EntitlementPrincipalResolver = (context: Context) => Promise<PlatformPrincipal | null>\n/**\n * Resolves the engine context principal only when user.tenantId matches tenantId and userId exists.\n * @param c - Hono context populated exclusively by trusted host authentication middleware.\n * @returns Principal using context IDs and user roles, or null for missing/mismatched identity.\n * @remarks Does not independently query live membership or authenticate headers.\n * @example\n * ```typescript\n * import { Hono } from \"hono\";\n * import { resolveEngineEntitlementPrincipal } from \"@alneas/eaos-server/entitlements\";\n * const app = new Hono();\n * app.get(\"/identity-state\", async c => c.json({ authenticated: !!await resolveEngineEntitlementPrincipal(c) }));\n * ```\n */\nexport const resolveEngineEntitlementPrincipal: EntitlementPrincipalResolver = async c => {\n const user = c.get('user'), tenantId = c.get('tenantId'), userId = c.get('userId')\n return tenantId && userId && user?.tenantId === tenantId ? { tenantId, userId, roles: user.roles } : null\n}\n/**\n * Determines whether a plugin rule needs the external entitlement runtime.\n * @param rule - Declared plugin entitlement policy.\n * @returns True for nonpublic tier, any metering, or any allowedTenants property; otherwise false.\n * @remarks Public unmetered rules still require authentication and host lifecycle/resource admission.\n * @example\n * ```typescript\n * import { requiresEntitlementRuntime } from \"@alneas/eaos-server/entitlements\";\n * import type { PluginEntitlement } from \"@alneas/eaos-core\";\n * export function needsSubscription(rule: PluginEntitlement) { return requiresEntitlementRuntime(rule); }\n * ```\n */\nexport function requiresEntitlementRuntime(rule: PluginEntitlement): boolean {\n return rule.tier !== 'public' || !!rule.metering || !!rule.allowedTenants\n}\n/**\n * Creates a request guard reserving current restricted/metered plugin admission before downstream work.\n * @param pluginId - Exact plugin ID to admit.\n * @param rule - Declared plugin access and metering policy.\n * @param runtime - Required for restricted/metered/allowed-tenant rules; absence returns 503.\n * @param resolvePrincipal - Verified request principal callback; defaults to resolveEngineEntitlementPrincipal.\n * @returns Hono middleware returning 401 for absent identity, policy status for EntitlementError, or completing downstream work without a value.\n * @throws Request handling propagates invalid principal, host runtime, resolver, and downstream errors outside normalized entitlement denial.\n * @remarks Public unmetered rules skip runtime checks after principal validation; host lifecycle/resource authorization remains required. Metered admission counts failed downstream attempts.\n * @example\n * ```typescript\n * import { Hono } from \"hono\";\n * import { createPluginEntitlementGuard, type PluginEntitlementRuntime, type EntitlementPrincipalResolver } from \"@alneas/eaos-server/entitlements\";\n * import type { PluginEntitlement } from \"@alneas/eaos-core\";\n * export function protectedApp(rule: PluginEntitlement, runtime: PluginEntitlementRuntime, resolvePrincipal: EntitlementPrincipalResolver) {\n * const app = new Hono();\n * app.use(\"*\", createPluginEntitlementGuard(\"example-plugin\", rule, runtime, resolvePrincipal));\n * return app;\n * }\n * ```\n */\nexport function createPluginEntitlementGuard(pluginId: string, rule: PluginEntitlement, runtime?: PluginEntitlementRuntime, resolvePrincipal: EntitlementPrincipalResolver = resolveEngineEntitlementPrincipal) {\n return createMiddleware(async (c, next) => {\n const p = await resolvePrincipal(c)\n if (!p) return c.json({ error: 'Unauthorized' }, 401)\n assertPlatformPrincipal(p)\n if (!requiresEntitlementRuntime(rule)) { await next(); return }\n if (!runtime) return c.json({ error: 'Entitlement service unavailable' }, 503)\n try { await runtime.admit(p, pluginId, rule, `${c.req.method} ${c.req.path}`) }\n catch (error) { if (error instanceof EntitlementError) return c.json({ error: error.message }, error.decision.status); throw error }\n await next()\n })\n}\n/**\n * Trusted downloadable asset catalog entry; client input selects IDs rather than object keys.\n * @see createPluginAssetRouter.\n */\nexport interface ProtectedPluginAsset {\n /** Public asset ID unique within a plugin catalog. */\n id: string\n /** Owning plugin ID. */\n pluginId: string\n /** Host storage object key passed to the signing port. */\n key: string\n /** Lowercase 64-hex checksum validated before signing. */\n sha256: string\n /** Host-declared media type returned as metadata. */\n contentType: string\n}\n/**\n * Creates entitled asset URL delivery using a trusted catalog and host signing transport.\n * @param options - runtime checks current entitlement; resolvePrincipal authenticates the request; plugins supplies rules; assets supplies trusted object metadata; sign receives cloned asset, verified principal, and expiresIn=60 seconds and resolves a capability URL.\n * @returns A router serving GET /:pluginId/:assetId with URL/checksum/contentType/60-second lifetime, or 401/404/policy denial responses. Successful responses use private, no-store caching.\n * @throws Request handling propagates resolver/runtime/signing errors or invalid trusted checksums.\n * @remarks Entitlement is checked before and after external signing, but no quota is reserved by this route. Signed URLs may remain usable after later revocation until expiry; the signing port must enforce private access and the requested lifetime. Catalogs, keys, and credentials must remain host-controlled.\n * @example\n * ```typescript\n * import { createPluginAssetRouter } from \"@alneas/eaos-server/entitlements\";\n * export function assetRoutes(options: Parameters<typeof createPluginAssetRouter>[0]) {\n * return createPluginAssetRouter(options);\n * }\n * ```\n */\nexport function createPluginAssetRouter(options: {\n /**\n * Current lifecycle/subscription policy checker; URL delivery checks it before signing and immediately before returning the capability.\n */\n runtime: PluginEntitlementRuntime\n /**\n * Authenticates each asset request and resolves a verified tenant/user principal or null to return 401; errors propagate through Hono.\n */\n resolvePrincipal: EntitlementPrincipalResolver\n /**\n * Trusted plugin-ID to entitlement-policy catalog; an unknown plugin is returned as unavailable.\n */\n plugins: Readonly<Record<string, PluginEntitlement>>\n /**\n * Trusted asset catalog looked up by plugin ID and asset ID; client input never supplies storage object keys.\n */\n assets: readonly ProtectedPluginAsset[]\n /**\n * Host signing callback invoked after initial admission with exact asset/principal and a 60-second lifetime; resolves a private capability URL and may reject.\n */\n sign: (input: {\n /**\n * Structured clone of the trusted catalog asset, including storage key and validated lowercase SHA-256.\n */\n asset: ProtectedPluginAsset;\n /**\n * Verified principal for the current asset request; use it for host signing authorization.\n */\n principal: PlatformPrincipal;\n /**\n * Requested signed URL lifetime in seconds; this router always supplies 60.\n */\n expiresIn: number }) => Promise<string>\n}) {\n const router = new Hono()\n router.get('/:pluginId/:assetId', async c => {\n const p = await options.resolvePrincipal(c)\n if (!p) return c.json({ error: 'Unauthorized' }, 401)\n const pluginId = c.req.param('pluginId'), assetId = c.req.param('assetId'), rule = options.plugins[pluginId]\n const asset = options.assets.find(a => a.pluginId === pluginId && a.id === assetId)\n if (!rule || !asset) return c.json({ error: 'Asset unavailable' }, 404)\n const decision = await options.runtime.check(p, pluginId, rule)\n if (!decision.allowed) return c.json({ error: decision.reason }, decision.status)\n if (!/^[a-f0-9]{64}$/.test(asset.sha256)) throw Error('Invalid trusted asset checksum')\n const url = await options.sign({ asset: structuredClone(asset), principal: p, expiresIn: 60 })\n // Signing may call an external service; recheck revocation before returning the capability.\n const current = await options.runtime.check(p, pluginId, rule)\n if (!current.allowed) return c.json({ error: current.reason }, current.status)\n c.header('Cache-Control', 'private, no-store')\n return c.json({ url, sha256: asset.sha256, contentType: asset.contentType, expiresIn: 60 })\n })\n return router\n}\n","import { assertTenantEntitlements, type TenantEntitlements } from '@alneas/eaos-core'\nimport type { DataContract, Dialect } from '@alneas/eaos-server/lifecycle-engine'\n/**\n * Declares reviewed control-plane storage for tenant subscription/addon/quota state across supported SQL dialects.\n * @remarks Hosts install this contract through reviewed lifecycle operations; importing the constant performs no migration.\n * @see createSqlTenantEntitlementLoader for the reader usage example.\n */\nexport const tenantEntitlementContract: DataContract = {\n id: 'platform-entitlements', version: '1.0.0', description: 'Tenant subscription and plugin addon grants',\n schema: { type: 'object', required: ['tenant_id', 'plan_tier', 'status', 'addons_json', 'quotas_json', 'revision', 'plugin_data'], properties: {\n tenant_id: { type: 'string' }, plan_tier: { type: 'string', enum: ['free', 'standard', 'pro'] }, status: { type: 'string', enum: ['active', 'suspended'] },\n valid_until: { type: ['string', 'null'] }, addons_json: { type: 'string' }, quotas_json: { type: 'string' }, revision: { type: 'integer', minimum: 1 }, plugin_data: { type: 'string', default: '{}' },\n }, 'x-db': { tableName: 'eaos_tenant_entitlements' } },\n migrations: [{ id: '001_tenant_entitlements', scope: 'database', sql: {\n sqlite: [\"CREATE TABLE eaos_tenant_entitlements(tenant_id TEXT PRIMARY KEY NOT NULL,plan_tier TEXT NOT NULL CHECK(plan_tier IN ('free','standard','pro')),status TEXT NOT NULL CHECK(status IN ('active','suspended')),valid_until TEXT,addons_json TEXT NOT NULL CHECK(json_valid(addons_json)),quotas_json TEXT NOT NULL CHECK(json_valid(quotas_json)),revision INTEGER NOT NULL,plugin_data TEXT NOT NULL DEFAULT '{}' CHECK(json_valid(plugin_data)))\"],\n postgres: [\"CREATE TABLE eaos_tenant_entitlements(tenant_id VARCHAR(128) PRIMARY KEY,plan_tier VARCHAR(16) NOT NULL CHECK(plan_tier IN ('free','standard','pro')),status VARCHAR(16) NOT NULL CHECK(status IN ('active','suspended')),valid_until VARCHAR(64),addons_json JSONB NOT NULL,quotas_json JSONB NOT NULL,revision BIGINT NOT NULL,plugin_data JSONB NOT NULL DEFAULT '{}')\"],\n oracle: [\"CREATE TABLE eaos_tenant_entitlements(tenant_id VARCHAR2(128) PRIMARY KEY,plan_tier VARCHAR2(16) NOT NULL CHECK(plan_tier IN ('free','standard','pro')),status VARCHAR2(16) NOT NULL CHECK(status IN ('active','suspended')),valid_until VARCHAR2(64),addons_json CLOB NOT NULL CHECK(addons_json IS JSON),quotas_json CLOB NOT NULL CHECK(quotas_json IS JSON),revision NUMBER(19) NOT NULL,plugin_data CLOB DEFAULT '{}' NOT NULL CHECK(plugin_data IS JSON))\"],\n } }],\n}\n/**\n * Builds a parameterized tenant entitlement reader for the reviewed control-plane table.\n * @param driver - Host SQL dialect and execute callback; execute receives SQL and one tenant binding and resolves optional rows. Credentials and connection lifecycle remain host-owned.\n * @returns An async loader accepting a verified 1–128-character tenant ID (letters/digits/underscore/dot/hyphen, starting alphanumeric) and resolving validated entitlements or null when no row exists.\n * @throws Loader calls reject invalid tenant IDs, multiple rows, malformed JSON/contracts, tenant mismatch, and propagated SQL errors.\n * @remarks Row keys are normalized to lowercase; JSON columns may be strings or already parsed values. No row-level authorization or shared transaction is established by this factory.\n * @example\n * ```typescript\n * import { createSqlTenantEntitlementLoader } from \"@alneas/eaos-server/entitlements\";\n * export function entitlementLoader(driver: Parameters<typeof createSqlTenantEntitlementLoader>[0]) {\n * return createSqlTenantEntitlementLoader(driver);\n * }\n * ```\n */\nexport function createSqlTenantEntitlementLoader(driver: {\n /**\n * SQL placeholder dialect: Oracle uses :1, PostgreSQL $1, and SQLite ? for the tenant binding.\n */\ndialect: Dialect;\n /**\n * Executes the loader's parameterized tenant SELECT through the trusted host connection.\n * @param sql - SQL supplied by the loader with one dialect-correct tenant placeholder.\n * @param bindings - One verified tenant ID in placeholder order.\n * @returns Optional result rows; no rows resolves to null at the loader boundary.\n * @throws Host query errors reject the entitlement lookup.\n * @example\n * ```typescript\n * import { createSqlTenantEntitlementLoader } from '@alneas/eaos-server/entitlements';\n * export async function loadContract(driver: Parameters<typeof createSqlTenantEntitlementLoader>[0], verifiedTenantId: string) {\n * // The host supplies the reviewed schema and privileged read connection.\n * return createSqlTenantEntitlementLoader(driver)(verifiedTenantId);\n * }\n * ```\n */\nexecute(sql: string, bindings: unknown[]): Promise<{\n /**\n * Optional result rows; missing rows is treated as an empty result, while more than one row rejects as ambiguous.\n */\nrows?: Record<string, unknown>[] }> }) {\n return async (tenantId: string): Promise<TenantEntitlements | null> => {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(tenantId)) throw Error('Verified entitlement tenant required')\n const bind = driver.dialect === 'oracle' ? ':1' : driver.dialect === 'postgres' ? '$1' : '?'\n const rows = (await driver.execute(`SELECT tenant_id,plan_tier,status,valid_until,addons_json,quotas_json FROM eaos_tenant_entitlements WHERE tenant_id=${bind}`, [tenantId])).rows ?? []\n if (!rows.length) return null\n if (rows.length !== 1) throw Error('Ambiguous tenant entitlement')\n const row = Object.fromEntries(Object.entries(rows[0]).map(([k, v]) => [k.toLowerCase(), v]))\n const json = (value: unknown) => typeof value === 'string' ? JSON.parse(value) : value\n const result: TenantEntitlements = { tenantId: String(row.tenant_id), plan: row.plan_tier as TenantEntitlements['plan'], status: row.status as TenantEntitlements['status'], addons: json(row.addons_json), monthlyQuotas: json(row.quotas_json), ...(row.valid_until ? { validUntil: String(row.valid_until) } : {}) }\n assertTenantEntitlements(result)\n if (result.tenantId !== tenantId) throw Error('Entitlement tenant differs')\n return result\n }\n}\n"],"mappings":"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","names":["assertTenantEntitlements","assertTenantEntitlements"]}
@@ -0,0 +1,180 @@
1
+ import {
2
+ createChatClient
3
+ } from "./chunk-YMHVRBUU.js";
4
+
5
+ // src/execution/tool-agent.ts
6
+ import { createActionToolBridge, createExecutionSession } from "@alneas/appkit-core/ai/action";
7
+ function createToolAgent(options) {
8
+ const { session: makeSession, disclose, authorizeCall, authorize } = options;
9
+ const maxRounds = options.maxRounds ?? 6, maxCalls = options.maxCalls ?? 10, maxChars = options.maxInputChars ?? 2e5;
10
+ if (typeof makeSession !== "function" || typeof disclose !== "function" || typeof authorizeCall !== "function" || typeof authorize !== "function" || !Number.isSafeInteger(maxRounds) || maxRounds < 1 || maxRounds > 20 || !Number.isSafeInteger(maxCalls) || maxCalls < 1 || maxCalls > 100) throw new Error("Agent policy and valid limits required");
11
+ const chatOptions = { ...options, parameters: structuredClone(options.parameters), modelAdapters: options.modelAdapters && Object.freeze({ ...options.modelAdapters }) };
12
+ const execution = createExecutionSession();
13
+ return {
14
+ /**
15
+ * Request cooperative cancellation of the current Appkit execution.
16
+ * @returns No value; Appkit marks active work cancelling without rolling back completed effects.
17
+ * @example
18
+ * ```typescript
19
+ * import { createToolAgent } from '@alneas/eaos-server/execution/tool-agent';
20
+ * export function cancel(agent: ReturnType<typeof createToolAgent>) { return agent.cancel(); }
21
+ * ```
22
+ */
23
+ cancel: () => execution.cancel(),
24
+ /**
25
+ * Read Appkit's summary-only in-memory execution history.
26
+ * @returns Appkit execution summaries; raw model inputs/results are not stored in these summaries.
27
+ * @example
28
+ * ```typescript
29
+ * import { createToolAgent } from '@alneas/eaos-server/execution/tool-agent';
30
+ * export function snapshot(agent: ReturnType<typeof createToolAgent>) { return agent.getSnapshot(); }
31
+ * ```
32
+ */
33
+ getSnapshot: () => execution.getSnapshot(),
34
+ /**
35
+ * Subscribe to Appkit execution summary changes.
36
+ * @param listener - Callback notified when execution state changes; do not expose raw secrets in UI callbacks.
37
+ * @returns Unsubscribe function owned by the subscribing host.
38
+ * @example
39
+ * ```typescript
40
+ * import { createToolAgent } from '@alneas/eaos-server/execution/tool-agent';
41
+ * export function observe(agent: ReturnType<typeof createToolAgent>, listener: () => void) { return agent.subscribe(listener); }
42
+ * ```
43
+ */
44
+ subscribe: (listener) => execution.subscribe(listener),
45
+ /**
46
+ * Close the Appkit session and request cooperative cancellation.
47
+ * @returns No value; the session no longer admits new runs.
48
+ * @example
49
+ * ```typescript
50
+ * import { createToolAgent } from '@alneas/eaos-server/execution/tool-agent';
51
+ * export function close(agent: ReturnType<typeof createToolAgent>) { agent.close(); }
52
+ * ```
53
+ */
54
+ close: () => execution.close(),
55
+ /**
56
+ * Run a single authorized model/Action conversation.
57
+ * @param principal - Verified current tenant/user identity, copied before host callbacks.
58
+ * @param input - Detached initial messages and optional cooperative cancellation signal.
59
+ * @returns Appkit execution outcome containing a ToolAgentResult on success; failed/cancelled outcomes omit it.
60
+ * @throws Appkit rejects concurrent or closed session admission; run failures otherwise become outcomes.
61
+ * @example
62
+ * ```typescript
63
+ * import { createToolAgent } from '@alneas/eaos-server/execution/tool-agent';
64
+ * export function run(agent: ReturnType<typeof createToolAgent>, ...args: Parameters<typeof agent.run>) { return agent.run(...args); }
65
+ * ```
66
+ */
67
+ async run(principal, input) {
68
+ const p = structuredClone(principal), messages = structuredClone(input.messages);
69
+ return execution.run("AI tool session", async (context) => {
70
+ const externalAbort = () => execution.cancel();
71
+ input.signal?.addEventListener("abort", externalAbort, { once: true });
72
+ if (input.signal?.aborted) externalAbort();
73
+ let bridge;
74
+ let callsExecuted = 0;
75
+ const check = async () => {
76
+ if (context.signal.aborted) throw new DOMException("Agent cancelled", "AbortError");
77
+ if (!p || [p.tenantId, p.userId].some((v) => typeof v !== "string" || !v.trim()) || await authorize(structuredClone(p), "model:chat") !== true) throw new Error("Agent access denied");
78
+ if (context.signal.aborted) throw new DOMException("Agent cancelled", "AbortError");
79
+ if (!Array.isArray(messages) || !messages.length || messages.length > 1e3 || JSON.stringify(messages).length > maxChars) throw new Error("Agent history limit");
80
+ };
81
+ const allowed = async (call) => {
82
+ await check();
83
+ if (await disclose(structuredClone(p), call.name) !== true || await authorizeCall(structuredClone(p), structuredClone(call)) !== true) throw new Error("Agent tool access denied");
84
+ await check();
85
+ };
86
+ const result = (status, pending = []) => ({ status, messages: structuredClone(messages), pending: structuredClone(pending), callsExecuted });
87
+ try {
88
+ await check();
89
+ const session = await makeSession(structuredClone(p));
90
+ await check();
91
+ if (!Array.isArray(session.tools) || session.tools.length > 100 || session.tools.some((tool) => !["read", "handoff"].includes(tool.mode))) throw new Error("Invalid agent tool policy");
92
+ const modes = new Map(session.tools.map((tool) => [tool.binding.name, tool.mode]));
93
+ const registrations = new Map(session.tools.filter((tool) => tool.binding.kind === "action").map((tool) => {
94
+ const binding = tool.binding;
95
+ return [binding.name, { id: binding.actionId, action: session.registry.getAction(binding.actionId) }];
96
+ }));
97
+ bridge = createActionToolBridge(session.registry, { tools: session.tools.map((tool) => tool.binding), maxCalls });
98
+ const activeBridge = bridge;
99
+ const authorizeHistory = async (history) => {
100
+ const prior = /* @__PURE__ */ new Map(), results = /* @__PURE__ */ new Set();
101
+ for (const message of history) for (const part of message.parts) {
102
+ if (part.type === "tool-call") {
103
+ if (prior.has(part.callId) || !modes.has(part.name)) throw new Error("Agent retained tool history is invalid");
104
+ const call = { callId: part.callId, name: part.name, arguments: part.input };
105
+ prior.set(call.callId, call);
106
+ await allowed(call);
107
+ } else if (part.type === "tool-result") {
108
+ const call = prior.get(part.callId);
109
+ if (!call || call.name !== part.name || results.has(part.callId)) throw new Error("Agent retained tool result has no unique authorized call");
110
+ results.add(part.callId);
111
+ await allowed(call);
112
+ }
113
+ }
114
+ };
115
+ const authorizeAdapter = (transport) => ({
116
+ id: transport.id,
117
+ capabilities: transport.capabilities,
118
+ async *stream(request) {
119
+ for (const descriptor of request.tools ?? []) {
120
+ if (!modes.has(descriptor.name) || await disclose(structuredClone(p), descriptor.name) !== true) throw new Error("Agent tool descriptor disclosure denied");
121
+ }
122
+ await check();
123
+ await authorizeHistory(request.messages);
124
+ request.signal?.throwIfAborted();
125
+ yield* transport.stream(request);
126
+ }
127
+ });
128
+ const chat = createChatClient({
129
+ ...chatOptions,
130
+ authorize: async (actor, operation) => {
131
+ if (await authorize(actor, operation) !== true) return false;
132
+ await authorizeHistory(messages);
133
+ return true;
134
+ },
135
+ adapter: authorizeAdapter(chatOptions.adapter),
136
+ ...chatOptions.modelAdapters ? { modelAdapters: Object.fromEntries(Object.entries(chatOptions.modelAdapters).map(([model, adapter]) => [model, authorizeAdapter(adapter)])) } : {},
137
+ tools: async () => {
138
+ const tools = [];
139
+ for (const tool of activeBridge.listTools()) if (await disclose(structuredClone(p), tool.name) === true) tools.push(tool);
140
+ return tools;
141
+ }
142
+ });
143
+ for (let round = 0; round < maxRounds; round++) {
144
+ await check();
145
+ const answer = await chat.complete(p, { messages, signal: context.signal, tools: "catalog" });
146
+ messages.push(answer.message);
147
+ await check();
148
+ if (answer.finishReason === "stop") return result("completed");
149
+ const calls = answer.message.parts.filter((part) => part.type === "tool-call").map((part) => ({ callId: part.callId, name: part.name, arguments: part.input }));
150
+ for (const call of calls) await allowed(call);
151
+ if (calls.some((call) => modes.get(call.name) === "handoff")) return result("handoff", calls);
152
+ if (callsExecuted + calls.length > maxCalls || round + 1 === maxRounds) return result("limited", calls);
153
+ for (let index = 0; index < calls.length; index++) {
154
+ const call = calls[index];
155
+ await allowed(call);
156
+ const registration = registrations.get(call.name);
157
+ if (registration && session.registry.getAction(registration.id) !== registration.action) throw new Error("Agent action registration changed");
158
+ const output = await activeBridge.execute(call, context);
159
+ callsExecuted++;
160
+ await allowed(call);
161
+ messages.push({ id: crypto.randomUUID(), role: "tool", parts: [{ type: "tool-result", callId: call.callId, name: call.name, output: output.ok ? output.data : { code: output.code, error: output.error }, ...!output.ok ? { isError: true } : {} }] });
162
+ await check();
163
+ context.reportProgress({ completed: callsExecuted, total: maxCalls });
164
+ if (!output.ok) return result("tool-error", calls.slice(index + 1));
165
+ }
166
+ }
167
+ return result("limited");
168
+ } finally {
169
+ bridge?.close();
170
+ input.signal?.removeEventListener("abort", externalAbort);
171
+ }
172
+ });
173
+ }
174
+ };
175
+ }
176
+
177
+ export {
178
+ createToolAgent
179
+ };
180
+ //# sourceMappingURL=chunk-4BARRLJR.js.map