agor-live 0.23.1 → 0.23.2

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 (469) hide show
  1. package/dist/core/claude/index.cjs +51 -27
  2. package/dist/core/claude/index.js +51 -27
  3. package/dist/core/claude-cli/index.cjs +13 -0
  4. package/dist/core/claude-cli/index.js +13 -0
  5. package/dist/core/claude-cli/pricing.d.ts.map +1 -1
  6. package/dist/core/client/index.cjs +17 -0
  7. package/dist/core/client/index.js +16 -0
  8. package/dist/core/db/index.cjs +618 -421
  9. package/dist/core/db/index.js +550 -353
  10. package/dist/core/db/repositories/boards.d.ts +27 -0
  11. package/dist/core/db/repositories/boards.d.ts.map +1 -1
  12. package/dist/core/db/repositories/branches.d.ts +11 -1
  13. package/dist/core/db/repositories/branches.d.ts.map +1 -1
  14. package/dist/core/db/repositories/gateway-channels.d.ts +9 -0
  15. package/dist/core/db/repositories/gateway-channels.d.ts.map +1 -1
  16. package/dist/core/db/repositories/sessions.d.ts +7 -0
  17. package/dist/core/db/repositories/sessions.d.ts.map +1 -1
  18. package/dist/core/environment/render-snapshot.cjs +6 -2
  19. package/dist/core/environment/render-snapshot.d.ts +2 -0
  20. package/dist/core/environment/render-snapshot.d.ts.map +1 -1
  21. package/dist/core/environment/render-snapshot.js +6 -2
  22. package/dist/core/environment/variable-resolver.cjs +3 -1
  23. package/dist/core/environment/variable-resolver.js +3 -1
  24. package/dist/core/index.cjs +684 -486
  25. package/dist/core/index.js +684 -486
  26. package/dist/core/lib/feathers-validation.cjs +3 -0
  27. package/dist/core/lib/feathers-validation.d.ts +1 -0
  28. package/dist/core/lib/feathers-validation.d.ts.map +1 -1
  29. package/dist/core/lib/feathers-validation.js +3 -0
  30. package/dist/core/local-actions/index.cjs +123 -56
  31. package/dist/core/local-actions/index.js +121 -54
  32. package/dist/core/mcp/index.cjs +21 -3
  33. package/dist/core/mcp/index.d.ts +1 -1
  34. package/dist/core/mcp/index.d.ts.map +1 -1
  35. package/dist/core/mcp/index.js +18 -3
  36. package/dist/core/mcp/template-patterns.d.ts +15 -0
  37. package/dist/core/mcp/template-patterns.d.ts.map +1 -0
  38. package/dist/core/mcp/template-resolver.d.ts +13 -0
  39. package/dist/core/mcp/template-resolver.d.ts.map +1 -1
  40. package/dist/core/models/browser.cjs +6 -0
  41. package/dist/core/models/browser.js +6 -0
  42. package/dist/core/models/claude.d.ts.map +1 -1
  43. package/dist/core/models/index.cjs +6 -0
  44. package/dist/core/models/index.js +6 -0
  45. package/dist/core/seed/index.cjs +360 -216
  46. package/dist/core/seed/index.js +329 -185
  47. package/dist/core/templates/handlebars-helpers.cjs +3 -1
  48. package/dist/core/templates/handlebars-helpers.d.ts +5 -0
  49. package/dist/core/templates/handlebars-helpers.d.ts.map +1 -1
  50. package/dist/core/templates/handlebars-helpers.js +3 -1
  51. package/dist/core/tools/mcp/auth-secrets.cjs +3460 -3
  52. package/dist/core/tools/mcp/auth-secrets.d.ts.map +1 -1
  53. package/dist/core/tools/mcp/auth-secrets.js +3477 -3
  54. package/dist/core/tools/mcp/http-headers.cjs +17 -1
  55. package/dist/core/tools/mcp/http-headers.d.ts.map +1 -1
  56. package/dist/core/tools/mcp/http-headers.js +15 -1
  57. package/dist/core/tools/mcp/oauth-refresh.cjs +67 -43
  58. package/dist/core/tools/mcp/oauth-refresh.js +65 -41
  59. package/dist/core/types/board.d.ts +12 -0
  60. package/dist/core/types/board.d.ts.map +1 -1
  61. package/dist/core/types/gateway.d.ts +14 -0
  62. package/dist/core/types/gateway.d.ts.map +1 -1
  63. package/dist/core/types/index.cjs +17 -0
  64. package/dist/core/types/index.js +16 -0
  65. package/dist/core/unix/index.cjs +67 -0
  66. package/dist/core/unix/index.js +67 -0
  67. package/dist/daemon/auth/executor-runtime-scope.d.ts.map +1 -1
  68. package/dist/daemon/auth/executor-runtime-scope.js +19 -5
  69. package/dist/daemon/auth/executor-session-token.d.ts +15 -0
  70. package/dist/daemon/auth/executor-session-token.d.ts.map +1 -0
  71. package/dist/daemon/auth/executor-session-token.js +17 -0
  72. package/dist/daemon/auth/issue-browser-tokens-hook.d.ts +24 -0
  73. package/dist/daemon/auth/issue-browser-tokens-hook.d.ts.map +1 -0
  74. package/dist/daemon/auth/issue-browser-tokens-hook.js +95 -0
  75. package/dist/daemon/auth/service-jwt-strategy.d.ts.map +1 -1
  76. package/dist/daemon/auth/service-jwt-strategy.js +14 -2
  77. package/dist/daemon/declarations.d.ts +1 -0
  78. package/dist/daemon/declarations.d.ts.map +1 -1
  79. package/dist/daemon/index.js +1365 -418
  80. package/dist/daemon/main.js +1365 -418
  81. package/dist/daemon/mcp/server.js +294 -31
  82. package/dist/daemon/mcp/tools/analytics.js +73 -24
  83. package/dist/daemon/mcp/tools/artifacts.js +73 -24
  84. package/dist/daemon/mcp/tools/boards.js +73 -24
  85. package/dist/daemon/mcp/tools/branches.js +73 -24
  86. package/dist/daemon/mcp/tools/card-types.js +73 -24
  87. package/dist/daemon/mcp/tools/cards.js +73 -24
  88. package/dist/daemon/mcp/tools/environment.js +73 -24
  89. package/dist/daemon/mcp/tools/gateway-channels.d.ts.map +1 -1
  90. package/dist/daemon/mcp/tools/gateway-channels.js +190 -38
  91. package/dist/daemon/mcp/tools/knowledge.js +73 -24
  92. package/dist/daemon/mcp/tools/mcp-servers.js +73 -24
  93. package/dist/daemon/mcp/tools/messages.js +73 -24
  94. package/dist/daemon/mcp/tools/proxies.js +73 -24
  95. package/dist/daemon/mcp/tools/repos.js +73 -24
  96. package/dist/daemon/mcp/tools/schedules.js +73 -24
  97. package/dist/daemon/mcp/tools/search.js +73 -24
  98. package/dist/daemon/mcp/tools/sessions.js +73 -24
  99. package/dist/daemon/mcp/tools/tasks.js +73 -24
  100. package/dist/daemon/mcp/tools/users.js +76 -27
  101. package/dist/daemon/mcp/tools/widgets.d.ts.map +1 -1
  102. package/dist/daemon/mcp/tools/widgets.js +257 -99
  103. package/dist/daemon/oauth-auth-helpers.d.ts +35 -0
  104. package/dist/daemon/oauth-auth-helpers.d.ts.map +1 -0
  105. package/dist/daemon/oauth-auth-helpers.js +14 -0
  106. package/dist/daemon/register-hooks.d.ts +1 -0
  107. package/dist/daemon/register-hooks.d.ts.map +1 -1
  108. package/dist/daemon/register-hooks.js +304 -53
  109. package/dist/daemon/register-routes.d.ts.map +1 -1
  110. package/dist/daemon/register-routes.js +738 -288
  111. package/dist/daemon/register-services.d.ts.map +1 -1
  112. package/dist/daemon/register-services.js +386 -155
  113. package/dist/daemon/services/boards.d.ts +5 -0
  114. package/dist/daemon/services/boards.d.ts.map +1 -1
  115. package/dist/daemon/services/boards.js +7 -0
  116. package/dist/daemon/services/branches.d.ts.map +1 -1
  117. package/dist/daemon/services/branches.js +31 -2
  118. package/dist/daemon/services/claude-models.d.ts.map +1 -1
  119. package/dist/daemon/services/claude-models.js +4 -1
  120. package/dist/daemon/services/gateway.d.ts +15 -0
  121. package/dist/daemon/services/gateway.d.ts.map +1 -1
  122. package/dist/daemon/services/gateway.js +34 -0
  123. package/dist/daemon/services/health-monitor.d.ts.map +1 -1
  124. package/dist/daemon/services/health-monitor.js +10 -7
  125. package/dist/daemon/services/session-streams.d.ts +29 -0
  126. package/dist/daemon/services/session-streams.d.ts.map +1 -0
  127. package/dist/daemon/services/session-streams.js +84 -0
  128. package/dist/daemon/services/session-token-service.d.ts.map +1 -1
  129. package/dist/daemon/services/session-token-service.js +8 -4
  130. package/dist/daemon/setup/index.js +43 -11
  131. package/dist/daemon/setup/socketio.d.ts.map +1 -1
  132. package/dist/daemon/setup/socketio.js +43 -11
  133. package/dist/daemon/startup.d.ts.map +1 -1
  134. package/dist/daemon/startup.js +37 -16
  135. package/dist/daemon/utils/authorization.js +19 -5
  136. package/dist/daemon/utils/emit-service-event.d.ts +56 -0
  137. package/dist/daemon/utils/emit-service-event.d.ts.map +1 -0
  138. package/dist/daemon/utils/emit-service-event.js +23 -0
  139. package/dist/daemon/utils/mcp-header-secrets.d.ts +3 -5
  140. package/dist/daemon/utils/mcp-header-secrets.d.ts.map +1 -1
  141. package/dist/daemon/utils/mcp-header-secrets.js +31 -2
  142. package/dist/daemon/utils/realtime-access-cache.d.ts +9 -0
  143. package/dist/daemon/utils/realtime-access-cache.d.ts.map +1 -1
  144. package/dist/daemon/utils/realtime-access-cache.js +24 -0
  145. package/dist/daemon/utils/realtime-publish.d.ts +24 -0
  146. package/dist/daemon/utils/realtime-publish.d.ts.map +1 -1
  147. package/dist/daemon/utils/realtime-publish.js +120 -2
  148. package/dist/daemon/utils/session-queue-tenant-scope.d.ts +24 -0
  149. package/dist/daemon/utils/session-queue-tenant-scope.d.ts.map +1 -0
  150. package/dist/daemon/utils/session-queue-tenant-scope.js +133 -0
  151. package/dist/daemon/widgets/gateway-token/index.d.ts +114 -0
  152. package/dist/daemon/widgets/gateway-token/index.d.ts.map +1 -0
  153. package/dist/daemon/widgets/gateway-token/index.js +14711 -0
  154. package/dist/daemon/widgets/index.d.ts.map +1 -1
  155. package/dist/daemon/widgets/index.js +190 -16
  156. package/dist/daemon/widgets/registry.d.ts +7 -0
  157. package/dist/daemon/widgets/registry.d.ts.map +1 -1
  158. package/dist/daemon/widgets/submissions.js +12 -9
  159. package/dist/executor/commands/git.d.ts.map +1 -1
  160. package/dist/executor/commands/git.js +2 -0
  161. package/dist/executor/db/feathers-repositories.d.ts +19 -1
  162. package/dist/executor/db/feathers-repositories.d.ts.map +1 -1
  163. package/dist/executor/db/feathers-repositories.js +31 -1
  164. package/dist/executor/handlers/sdk/claude.d.ts.map +1 -1
  165. package/dist/executor/handlers/sdk/claude.js +1 -1
  166. package/dist/executor/handlers/sdk/codex.d.ts.map +1 -1
  167. package/dist/executor/handlers/sdk/codex.js +1 -1
  168. package/dist/executor/handlers/sdk/copilot.d.ts.map +1 -1
  169. package/dist/executor/handlers/sdk/copilot.js +1 -1
  170. package/dist/executor/handlers/sdk/cursor.d.ts.map +1 -1
  171. package/dist/executor/handlers/sdk/cursor.js +1 -0
  172. package/dist/executor/handlers/sdk/gemini.d.ts.map +1 -1
  173. package/dist/executor/handlers/sdk/gemini.js +1 -1
  174. package/dist/executor/handlers/sdk/opencode.d.ts.map +1 -1
  175. package/dist/executor/handlers/sdk/opencode.js +1 -1
  176. package/dist/executor/payload-types.d.ts +5 -5
  177. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts +8 -1
  178. package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts.map +1 -1
  179. package/dist/executor/sdk-handlers/base/mcp-scoping.js +58 -6
  180. package/dist/executor/sdk-handlers/claude/claude-tool.d.ts +2 -2
  181. package/dist/executor/sdk-handlers/claude/claude-tool.d.ts.map +1 -1
  182. package/dist/executor/sdk-handlers/claude/claude-tool.js +2 -2
  183. package/dist/executor/sdk-handlers/claude/prompt-service.d.ts +13 -3
  184. package/dist/executor/sdk-handlers/claude/prompt-service.d.ts.map +1 -1
  185. package/dist/executor/sdk-handlers/claude/prompt-service.js +16 -3
  186. package/dist/executor/sdk-handlers/claude/query-builder.d.ts +2 -1
  187. package/dist/executor/sdk-handlers/claude/query-builder.d.ts.map +1 -1
  188. package/dist/executor/sdk-handlers/claude/query-builder.js +2 -1
  189. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts +2 -2
  190. package/dist/executor/sdk-handlers/codex/codex-tool.d.ts.map +1 -1
  191. package/dist/executor/sdk-handlers/codex/codex-tool.js +2 -2
  192. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts +3 -2
  193. package/dist/executor/sdk-handlers/codex/prompt-service.d.ts.map +1 -1
  194. package/dist/executor/sdk-handlers/codex/prompt-service.js +70 -6
  195. package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts +2 -2
  196. package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts.map +1 -1
  197. package/dist/executor/sdk-handlers/copilot/copilot-tool.js +2 -2
  198. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts +3 -2
  199. package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts.map +1 -1
  200. package/dist/executor/sdk-handlers/copilot/prompt-service.js +4 -1
  201. package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts +2 -2
  202. package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts.map +1 -1
  203. package/dist/executor/sdk-handlers/gemini/gemini-tool.js +2 -2
  204. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts +3 -2
  205. package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts.map +1 -1
  206. package/dist/executor/sdk-handlers/gemini/prompt-service.js +4 -1
  207. package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts +3 -2
  208. package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts.map +1 -1
  209. package/dist/executor/sdk-handlers/opencode/opencode-tool.js +4 -1
  210. package/dist/executor/services/feathers-client.d.ts.map +1 -1
  211. package/dist/executor/services/feathers-client.js +119 -20
  212. package/dist/ui/assets/AgorEmojiPickerInner-leeNywMc.js +1 -0
  213. package/dist/ui/assets/App-Dpl4Cc0U.js +4 -0
  214. package/dist/ui/assets/App-Dpl4Cc0U.js.gz +0 -0
  215. package/dist/ui/assets/AppNode-wN3UZlFK.js +1 -0
  216. package/dist/ui/assets/AppNode-wN3UZlFK.js.gz +0 -0
  217. package/dist/ui/assets/{ArtifactConsentModal-oMMzRn8L.js → ArtifactConsentModal-DjzXcP_L.js} +1 -1
  218. package/dist/ui/assets/ArtifactConsentModal-DjzXcP_L.js.gz +0 -0
  219. package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js +9 -0
  220. package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js.gz +0 -0
  221. package/dist/ui/assets/ArtifactNode-DISy2T-6.js +9 -0
  222. package/dist/ui/assets/ArtifactNode-DISy2T-6.js.gz +0 -0
  223. package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js +19 -0
  224. package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js.gz +0 -0
  225. package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js +34 -0
  226. package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js.gz +0 -0
  227. package/dist/ui/assets/{CodeEditor.inner-Cuj6RuLL.js → CodeEditor.inner-HmSdTLW5.js} +1 -1
  228. package/dist/ui/assets/CodeEditor.inner-HmSdTLW5.js.gz +0 -0
  229. package/dist/ui/assets/ConversationView-mWaA-B1f.js +1 -0
  230. package/dist/ui/assets/ConversationView-mWaA-B1f.js.gz +0 -0
  231. package/dist/ui/assets/{EmbeddedTerminal-Lx5I9EOJ.js → EmbeddedTerminal-NNoyPA81.js} +1 -1
  232. package/dist/ui/assets/EmbeddedTerminal-NNoyPA81.js.gz +0 -0
  233. package/dist/ui/assets/KnowledgePage-CkxVnRvz.js +24 -0
  234. package/dist/ui/assets/KnowledgePage-CkxVnRvz.js.gz +0 -0
  235. package/dist/ui/assets/{MarketingScreenshotPage-CmDPBHOl.js → MarketingScreenshotPage-B86Gs8jx.js} +2 -2
  236. package/dist/ui/assets/MarketingScreenshotPage-B86Gs8jx.js.gz +0 -0
  237. package/dist/ui/assets/MobileApp-BPs-SXvz.js +1 -0
  238. package/dist/ui/assets/MobileApp-BPs-SXvz.js.gz +0 -0
  239. package/dist/ui/assets/SessionCanvas-xVfDoEtz.js +13 -0
  240. package/dist/ui/assets/SessionCanvas-xVfDoEtz.js.gz +0 -0
  241. package/dist/ui/assets/{StreamdownDemoPage-okKKR2QH.js → StreamdownDemoPage-CvWLzVsv.js} +2 -2
  242. package/dist/ui/assets/StreamdownDemoPage-CvWLzVsv.js.gz +0 -0
  243. package/dist/ui/assets/{TerminalModal-D9jMGZXv.js → TerminalModal-ExOgsuOP.js} +2 -2
  244. package/dist/ui/assets/TerminalModal-ExOgsuOP.js.gz +0 -0
  245. package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js +1 -0
  246. package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js.gz +0 -0
  247. package/dist/ui/assets/{ThemedSyntaxHighlighter.inner-C1FdIHn0.js → ThemedSyntaxHighlighter.inner-rpCN9S6K.js} +1 -1
  248. package/dist/ui/assets/{antd-DT5ackd0.js → antd-BCqimh1J.js} +5 -5
  249. package/dist/ui/assets/{antd-DT5ackd0.js.gz → antd-BCqimh1J.js.gz} +0 -0
  250. package/dist/ui/assets/architecture-U656AL7Q-BxSQIjrE.js +1 -0
  251. package/dist/ui/assets/{architectureDiagram-VXUJARFQ-DwTJGGoj.js → architectureDiagram-VXUJARFQ-pDpGHSqT.js} +1 -1
  252. package/dist/ui/assets/architectureDiagram-VXUJARFQ-pDpGHSqT.js.gz +0 -0
  253. package/dist/ui/assets/{blockDiagram-VD42YOAC-Dh1_TVW2.js → blockDiagram-VD42YOAC-uP8JTJpK.js} +1 -1
  254. package/dist/ui/assets/blockDiagram-VD42YOAC-uP8JTJpK.js.gz +0 -0
  255. package/dist/ui/assets/{c4Diagram-YG6GDRKO-B1e96AcB.js → c4Diagram-YG6GDRKO-qQe72Mm7.js} +1 -1
  256. package/dist/ui/assets/c4Diagram-YG6GDRKO-qQe72Mm7.js.gz +0 -0
  257. package/dist/ui/assets/channel-CoUBs6Zn.js +1 -0
  258. package/dist/ui/assets/{chunk-4BX2VUAB-BODpCjJx.js → chunk-4BX2VUAB-sz-YE8Nt.js} +1 -1
  259. package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js +3 -0
  260. package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js.gz +0 -0
  261. package/dist/ui/assets/chunk-55IACEB6-BS04dgKF.js +1 -0
  262. package/dist/ui/assets/{chunk-ABZYJK2D-DCTXWSzV.js → chunk-ABZYJK2D-t3Gkphds.js} +3 -3
  263. package/dist/ui/assets/chunk-ABZYJK2D-t3Gkphds.js.gz +0 -0
  264. package/dist/ui/assets/{chunk-AGHRB4JF-CbNphBjE.js → chunk-AGHRB4JF-D_QmWxbY.js} +1 -1
  265. package/dist/ui/assets/chunk-AGHRB4JF-D_QmWxbY.js.gz +0 -0
  266. package/dist/ui/assets/{chunk-ATLVNIR6-rWg3qxof.js → chunk-ATLVNIR6-Bmg7-Ufz.js} +1 -1
  267. package/dist/ui/assets/chunk-ATLVNIR6-Bmg7-Ufz.js.gz +0 -0
  268. package/dist/ui/assets/{chunk-B4BG7PRW-CgtLCbpE.js → chunk-B4BG7PRW-dnSEE1u-.js} +1 -1
  269. package/dist/ui/assets/chunk-B4BG7PRW-dnSEE1u-.js.gz +0 -0
  270. package/dist/ui/assets/{chunk-CVBHYZKI-DTL6Zgr0.js → chunk-CVBHYZKI-BStaYnF0.js} +1 -1
  271. package/dist/ui/assets/{chunk-DI55MBZ5-Dwvx2Kva.js → chunk-DI55MBZ5-28dvx6o3.js} +1 -1
  272. package/dist/ui/assets/chunk-DI55MBZ5-28dvx6o3.js.gz +0 -0
  273. package/dist/ui/assets/chunk-EXTU4WIE-X-FURkEh.js +1 -0
  274. package/dist/ui/assets/{chunk-FMBD7UC4-BogA_9CV.js → chunk-FMBD7UC4-C_63gC9S.js} +1 -1
  275. package/dist/ui/assets/{chunk-HN2XXSSU-2blQO3Gb.js → chunk-HN2XXSSU-UFD374KI.js} +1 -1
  276. package/dist/ui/assets/chunk-HN2XXSSU-UFD374KI.js.gz +0 -0
  277. package/dist/ui/assets/{chunk-JA3XYJ7Z-Cr1rmOui.js → chunk-JA3XYJ7Z-B60hLNeR.js} +1 -1
  278. package/dist/ui/assets/chunk-JA3XYJ7Z-B60hLNeR.js.gz +0 -0
  279. package/dist/ui/assets/{chunk-JZLCHNYA-BsgZ79Fa.js → chunk-JZLCHNYA-ButC6pwN.js} +1 -1
  280. package/dist/ui/assets/chunk-JZLCHNYA-ButC6pwN.js.gz +0 -0
  281. package/dist/ui/assets/{chunk-MI3HLSF2-dwYeUy5S.js → chunk-MI3HLSF2-BivYzoSV.js} +1 -1
  282. package/dist/ui/assets/chunk-MI3HLSF2-BivYzoSV.js.gz +0 -0
  283. package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js +2 -0
  284. package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js.gz +0 -0
  285. package/dist/ui/assets/{chunk-QN33PNHL-DxdIDCAa.js → chunk-QN33PNHL-tXtHZpaG.js} +1 -1
  286. package/dist/ui/assets/{chunk-QXUST7PY-BCK2V0i-.js → chunk-QXUST7PY-DATib_Vv.js} +1 -1
  287. package/dist/ui/assets/chunk-QXUST7PY-DATib_Vv.js.gz +0 -0
  288. package/dist/ui/assets/chunk-QZHKN3VN-y6l249e5.js +1 -0
  289. package/dist/ui/assets/{chunk-S3R3BYOJ-GP3zIxrB.js → chunk-S3R3BYOJ-BEtfmflI.js} +1 -1
  290. package/dist/ui/assets/chunk-S3R3BYOJ-BEtfmflI.js.gz +0 -0
  291. package/dist/ui/assets/{chunk-TZMSLE5B-dX5RaM6g.js → chunk-TZMSLE5B-BY1ZtogK.js} +1 -1
  292. package/dist/ui/assets/chunk-TZMSLE5B-BY1ZtogK.js.gz +0 -0
  293. package/dist/ui/assets/classDiagram-2ON5EDUG-BYvq-uPY.js +1 -0
  294. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-BYvq-uPY.js +1 -0
  295. package/dist/ui/assets/constants-CYzQKfD1.js +1 -0
  296. package/dist/ui/assets/{cose-bilkent-S5V4N54A-Dx0BJVDl.js → cose-bilkent-S5V4N54A-DPvYrqGG.js} +1 -1
  297. package/dist/ui/assets/cose-bilkent-S5V4N54A-DPvYrqGG.js.gz +0 -0
  298. package/dist/ui/assets/{dagre-6UL2VRFP-DiQSUxqN.js → dagre-6UL2VRFP-D800J6qb.js} +1 -1
  299. package/dist/ui/assets/dagre-6UL2VRFP-D800J6qb.js.gz +0 -0
  300. package/dist/ui/assets/{dagre-Bekd9Vdj.js → dagre-TNc4wezg.js} +1 -1
  301. package/dist/ui/assets/dagre-TNc4wezg.js.gz +0 -0
  302. package/dist/ui/assets/{diagram-PSM6KHXK-DtJnDQjc.js → diagram-PSM6KHXK-CGdP9F-X.js} +1 -1
  303. package/dist/ui/assets/diagram-PSM6KHXK-CGdP9F-X.js.gz +0 -0
  304. package/dist/ui/assets/{diagram-QEK2KX5R-CobkCRdj.js → diagram-QEK2KX5R-BD5lOCe5.js} +1 -1
  305. package/dist/ui/assets/diagram-QEK2KX5R-BD5lOCe5.js.gz +0 -0
  306. package/dist/ui/assets/{diagram-S2PKOQOG-DHEZYivc.js → diagram-S2PKOQOG-cp3l22vN.js} +1 -1
  307. package/dist/ui/assets/diagram-S2PKOQOG-cp3l22vN.js.gz +0 -0
  308. package/dist/ui/assets/editor-Cr0W5BQI.js +39 -0
  309. package/dist/ui/assets/editor-Cr0W5BQI.js.gz +0 -0
  310. package/dist/ui/assets/{emoji-B0hLmSLZ.js → emoji-Bv3m24sO.js} +1 -1
  311. package/dist/ui/assets/emoji-Bv3m24sO.js.gz +0 -0
  312. package/dist/ui/assets/{erDiagram-Q2GNP2WA-BVNeTZPQ.js → erDiagram-Q2GNP2WA-CQSXRgqr.js} +1 -1
  313. package/dist/ui/assets/erDiagram-Q2GNP2WA-CQSXRgqr.js.gz +0 -0
  314. package/dist/ui/assets/{flowDiagram-NV44I4VS-C73VFdyk.js → flowDiagram-NV44I4VS-CKcKpkph.js} +1 -1
  315. package/dist/ui/assets/flowDiagram-NV44I4VS-CKcKpkph.js.gz +0 -0
  316. package/dist/ui/assets/{ganttDiagram-LVOFAZNH-B_RosuD1.js → ganttDiagram-LVOFAZNH-DlAHzXO5.js} +1 -1
  317. package/dist/ui/assets/ganttDiagram-LVOFAZNH-DlAHzXO5.js.gz +0 -0
  318. package/dist/ui/assets/{gitGraph-F6HP7TQM-DMFIqn4h.js → gitGraph-F6HP7TQM-DeuXy4B1.js} +1 -1
  319. package/dist/ui/assets/{gitGraphDiagram-NY62KEGX-hxbgwNA1.js → gitGraphDiagram-NY62KEGX-aB-AI4Vq.js} +1 -1
  320. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-aB-AI4Vq.js.gz +0 -0
  321. package/dist/ui/assets/index-B-qHc0o5.js +63 -0
  322. package/dist/ui/assets/index-B-qHc0o5.js.gz +0 -0
  323. package/dist/ui/assets/{info-NVLQJR56-DZ3K-w48.js → info-NVLQJR56-B9PG7xsc.js} +1 -1
  324. package/dist/ui/assets/{infoDiagram-ER5ION4S-CxnBJQu6.js → infoDiagram-ER5ION4S-C5Wpoqim.js} +1 -1
  325. package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-CHYNj-f8.js → journeyDiagram-XKPGCS4Q-CHLziqfS.js} +1 -1
  326. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHLziqfS.js.gz +0 -0
  327. package/dist/ui/assets/{kanban-definition-3W4ZIXB7-DQPCCsj2.js → kanban-definition-3W4ZIXB7-Dq7GzQE_.js} +1 -1
  328. package/dist/ui/assets/kanban-definition-3W4ZIXB7-Dq7GzQE_.js.gz +0 -0
  329. package/dist/ui/assets/{line-DBRjKmfa.js → line-DHKNg83I.js} +1 -1
  330. package/dist/ui/assets/{linear-DFao5Wyp.js → linear-BvUfn0I8.js} +1 -1
  331. package/dist/ui/assets/linear-BvUfn0I8.js.gz +0 -0
  332. package/dist/ui/assets/{mermaid-parser.core-DYCfacHj.js → mermaid-parser.core-C6d9tKoo.js} +2 -2
  333. package/dist/ui/assets/mermaid-parser.core-C6d9tKoo.js.gz +0 -0
  334. package/dist/ui/assets/{mermaid.core-C6xGFSdE.js → mermaid.core-CxE5KezR.js} +3 -3
  335. package/dist/ui/assets/mermaid.core-CxE5KezR.js.gz +0 -0
  336. package/dist/ui/assets/{mindmap-definition-VGOIOE7T-L3Pw-YM7.js → mindmap-definition-VGOIOE7T-DmPoQ48w.js} +1 -1
  337. package/dist/ui/assets/mindmap-definition-VGOIOE7T-DmPoQ48w.js.gz +0 -0
  338. package/dist/ui/assets/{packet-BFZMPI3H-CpL6iNoa.js → packet-BFZMPI3H-JZEkVZxU.js} +1 -1
  339. package/dist/ui/assets/{particles-CT8hcJOA.js → particles-CxMmUw86.js} +1 -1
  340. package/dist/ui/assets/particles-CxMmUw86.js.gz +0 -0
  341. package/dist/ui/assets/{pie-7BOR55EZ-hTqChbTo.js → pie-7BOR55EZ-_1II5pYQ.js} +1 -1
  342. package/dist/ui/assets/{pieDiagram-ADFJNKIX-Bf4Nou75.js → pieDiagram-ADFJNKIX-DrNkH33i.js} +1 -1
  343. package/dist/ui/assets/pieDiagram-ADFJNKIX-DrNkH33i.js.gz +0 -0
  344. package/dist/ui/assets/{quadrantDiagram-AYHSOK5B-DpjUTLB1.js → quadrantDiagram-AYHSOK5B-DOpC-HEF.js} +1 -1
  345. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DOpC-HEF.js.gz +0 -0
  346. package/dist/ui/assets/{radar-NHE76QYJ-myy7OENC.js → radar-NHE76QYJ-DDmqhzEZ.js} +1 -1
  347. package/dist/ui/assets/{reactflow-Cubtnk8i.js → reactflow-D98uPOMq.js} +1 -1
  348. package/dist/ui/assets/reactflow-D98uPOMq.js.gz +0 -0
  349. package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-Bfrfh-0-.js → requirementDiagram-UZGBJVZJ-Bzx0iEPP.js} +1 -1
  350. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bzx0iEPP.js.gz +0 -0
  351. package/dist/ui/assets/{sandpack-C58bwfIS.js → sandpack-059Z4UWP.js} +1 -1
  352. package/dist/ui/assets/sandpack-059Z4UWP.js.gz +0 -0
  353. package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js +1 -0
  354. package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js.gz +0 -0
  355. package/dist/ui/assets/{sankeyDiagram-TZEHDZUN-ClZAZ6va.js → sankeyDiagram-TZEHDZUN-Do9pvfDv.js} +1 -1
  356. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-Do9pvfDv.js.gz +0 -0
  357. package/dist/ui/assets/{sequenceDiagram-WL72ISMW-CNgly63p.js → sequenceDiagram-WL72ISMW-CN8neUTA.js} +1 -1
  358. package/dist/ui/assets/sequenceDiagram-WL72ISMW-CN8neUTA.js.gz +0 -0
  359. package/dist/ui/assets/{src-DAeyG22O.js → src-DEbsv3pp.js} +2 -2
  360. package/dist/ui/assets/src-DEbsv3pp.js.gz +0 -0
  361. package/dist/ui/assets/{stateDiagram-FKZM4ZOC-BrEAoDpE.js → stateDiagram-FKZM4ZOC-BluWJi8n.js} +1 -1
  362. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BluWJi8n.js.gz +0 -0
  363. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-DeyqBMDR.js +1 -0
  364. package/dist/ui/assets/{streamdown-BdAVfkeF.js → streamdown-BT1twtFc.js} +5 -5
  365. package/dist/ui/assets/streamdown-BT1twtFc.js.gz +0 -0
  366. package/dist/ui/assets/{syntax-BOfTnQiy.js → syntax-CBu6nLfm.js} +1 -1
  367. package/dist/ui/assets/syntax-CBu6nLfm.js.gz +0 -0
  368. package/dist/ui/assets/{timeline-definition-IT6M3QCI-CaRH3k4l.js → timeline-definition-IT6M3QCI-WdUNkiRj.js} +1 -1
  369. package/dist/ui/assets/timeline-definition-IT6M3QCI-WdUNkiRj.js.gz +0 -0
  370. package/dist/ui/assets/{treemap-KMMF4GRG-CUaLOV_B.js → treemap-KMMF4GRG-CoriU4Jl.js} +1 -1
  371. package/dist/ui/assets/{useUserLocalStorage-C8sgXgXR.js → useUserLocalStorage-GidNiOPC.js} +1 -1
  372. package/dist/ui/assets/useUserLocalStorage-GidNiOPC.js.gz +0 -0
  373. package/dist/ui/assets/{xychartDiagram-PRI3JC2R-BlhkI9T_.js → xychartDiagram-PRI3JC2R-CgBAKNt2.js} +1 -1
  374. package/dist/ui/assets/xychartDiagram-PRI3JC2R-CgBAKNt2.js.gz +0 -0
  375. package/dist/ui/index.html +9 -8
  376. package/dist/ui/index.html.gz +0 -0
  377. package/package.json +2 -2
  378. package/dist/ui/assets/AgorEmojiPickerInner-DQjr8M3_.js +0 -1
  379. package/dist/ui/assets/App-hJtcOxHv.js +0 -5
  380. package/dist/ui/assets/App-hJtcOxHv.js.gz +0 -0
  381. package/dist/ui/assets/AppNode-BhuMpn8O.js +0 -1
  382. package/dist/ui/assets/AppNode-BhuMpn8O.js.gz +0 -0
  383. package/dist/ui/assets/ArtifactConsentModal-oMMzRn8L.js.gz +0 -0
  384. package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js +0 -9
  385. package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js.gz +0 -0
  386. package/dist/ui/assets/ArtifactNode-BzQcrwFS.js +0 -9
  387. package/dist/ui/assets/ArtifactNode-BzQcrwFS.js.gz +0 -0
  388. package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js +0 -19
  389. package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js.gz +0 -0
  390. package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js +0 -34
  391. package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js.gz +0 -0
  392. package/dist/ui/assets/CodeEditor.inner-Cuj6RuLL.js.gz +0 -0
  393. package/dist/ui/assets/ConversationView-9-3ma1u-.js +0 -1
  394. package/dist/ui/assets/ConversationView-9-3ma1u-.js.gz +0 -0
  395. package/dist/ui/assets/EmbeddedTerminal-Lx5I9EOJ.js.gz +0 -0
  396. package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js +0 -24
  397. package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js.gz +0 -0
  398. package/dist/ui/assets/MarketingScreenshotPage-CmDPBHOl.js.gz +0 -0
  399. package/dist/ui/assets/MobileApp-BpgSG_gz.js +0 -1
  400. package/dist/ui/assets/MobileApp-BpgSG_gz.js.gz +0 -0
  401. package/dist/ui/assets/SessionCanvas-B6_mtlxK.js +0 -13
  402. package/dist/ui/assets/SessionCanvas-B6_mtlxK.js.gz +0 -0
  403. package/dist/ui/assets/StreamdownDemoPage-okKKR2QH.js.gz +0 -0
  404. package/dist/ui/assets/TerminalModal-D9jMGZXv.js.gz +0 -0
  405. package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js +0 -1
  406. package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js.gz +0 -0
  407. package/dist/ui/assets/architecture-U656AL7Q-DMnxkQRZ.js +0 -1
  408. package/dist/ui/assets/architectureDiagram-VXUJARFQ-DwTJGGoj.js.gz +0 -0
  409. package/dist/ui/assets/blockDiagram-VD42YOAC-Dh1_TVW2.js.gz +0 -0
  410. package/dist/ui/assets/c4Diagram-YG6GDRKO-B1e96AcB.js.gz +0 -0
  411. package/dist/ui/assets/channel-Jv4dT4S5.js +0 -1
  412. package/dist/ui/assets/chunk-55IACEB6-lJXvUquf.js +0 -1
  413. package/dist/ui/assets/chunk-ABZYJK2D-DCTXWSzV.js.gz +0 -0
  414. package/dist/ui/assets/chunk-AGHRB4JF-CbNphBjE.js.gz +0 -0
  415. package/dist/ui/assets/chunk-ATLVNIR6-rWg3qxof.js.gz +0 -0
  416. package/dist/ui/assets/chunk-B4BG7PRW-CgtLCbpE.js.gz +0 -0
  417. package/dist/ui/assets/chunk-DI55MBZ5-Dwvx2Kva.js.gz +0 -0
  418. package/dist/ui/assets/chunk-EXTU4WIE-DHyaqTsP.js +0 -1
  419. package/dist/ui/assets/chunk-HN2XXSSU-2blQO3Gb.js.gz +0 -0
  420. package/dist/ui/assets/chunk-JA3XYJ7Z-Cr1rmOui.js.gz +0 -0
  421. package/dist/ui/assets/chunk-JZLCHNYA-BsgZ79Fa.js.gz +0 -0
  422. package/dist/ui/assets/chunk-MI3HLSF2-dwYeUy5S.js.gz +0 -0
  423. package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js +0 -2
  424. package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js.gz +0 -0
  425. package/dist/ui/assets/chunk-QXUST7PY-BCK2V0i-.js.gz +0 -0
  426. package/dist/ui/assets/chunk-QZHKN3VN-CALjGrEE.js +0 -1
  427. package/dist/ui/assets/chunk-S3R3BYOJ-GP3zIxrB.js.gz +0 -0
  428. package/dist/ui/assets/chunk-TZMSLE5B-dX5RaM6g.js.gz +0 -0
  429. package/dist/ui/assets/classDiagram-2ON5EDUG-C3_RVP70.js +0 -1
  430. package/dist/ui/assets/classDiagram-v2-WZHVMYZB-C3_RVP70.js +0 -1
  431. package/dist/ui/assets/constants-GjIDNVyt.js +0 -1
  432. package/dist/ui/assets/cose-bilkent-S5V4N54A-Dx0BJVDl.js.gz +0 -0
  433. package/dist/ui/assets/dagre-6UL2VRFP-DiQSUxqN.js.gz +0 -0
  434. package/dist/ui/assets/dagre-Bekd9Vdj.js.gz +0 -0
  435. package/dist/ui/assets/diagram-PSM6KHXK-DtJnDQjc.js.gz +0 -0
  436. package/dist/ui/assets/diagram-QEK2KX5R-CobkCRdj.js.gz +0 -0
  437. package/dist/ui/assets/diagram-S2PKOQOG-DHEZYivc.js.gz +0 -0
  438. package/dist/ui/assets/editor-DQIG-JYZ.js +0 -43
  439. package/dist/ui/assets/editor-DQIG-JYZ.js.gz +0 -0
  440. package/dist/ui/assets/emoji-B0hLmSLZ.js.gz +0 -0
  441. package/dist/ui/assets/erDiagram-Q2GNP2WA-BVNeTZPQ.js.gz +0 -0
  442. package/dist/ui/assets/flowDiagram-NV44I4VS-C73VFdyk.js.gz +0 -0
  443. package/dist/ui/assets/ganttDiagram-LVOFAZNH-B_RosuD1.js.gz +0 -0
  444. package/dist/ui/assets/gitGraphDiagram-NY62KEGX-hxbgwNA1.js.gz +0 -0
  445. package/dist/ui/assets/index-DTz1Dif6.js +0 -64
  446. package/dist/ui/assets/index-DTz1Dif6.js.gz +0 -0
  447. package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHYNj-f8.js.gz +0 -0
  448. package/dist/ui/assets/kanban-definition-3W4ZIXB7-DQPCCsj2.js.gz +0 -0
  449. package/dist/ui/assets/linear-DFao5Wyp.js.gz +0 -0
  450. package/dist/ui/assets/mermaid-parser.core-DYCfacHj.js.gz +0 -0
  451. package/dist/ui/assets/mermaid.core-C6xGFSdE.js.gz +0 -0
  452. package/dist/ui/assets/mindmap-definition-VGOIOE7T-L3Pw-YM7.js.gz +0 -0
  453. package/dist/ui/assets/particles-CT8hcJOA.js.gz +0 -0
  454. package/dist/ui/assets/pieDiagram-ADFJNKIX-Bf4Nou75.js.gz +0 -0
  455. package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DpjUTLB1.js.gz +0 -0
  456. package/dist/ui/assets/reactflow-Cubtnk8i.js.gz +0 -0
  457. package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bfrfh-0-.js.gz +0 -0
  458. package/dist/ui/assets/sandpack-C58bwfIS.js.gz +0 -0
  459. package/dist/ui/assets/sandpackDefaults-Bkga8XAE.js +0 -1
  460. package/dist/ui/assets/sankeyDiagram-TZEHDZUN-ClZAZ6va.js.gz +0 -0
  461. package/dist/ui/assets/sequenceDiagram-WL72ISMW-CNgly63p.js.gz +0 -0
  462. package/dist/ui/assets/src-DAeyG22O.js.gz +0 -0
  463. package/dist/ui/assets/stateDiagram-FKZM4ZOC-BrEAoDpE.js.gz +0 -0
  464. package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-BNL52_oN.js +0 -1
  465. package/dist/ui/assets/streamdown-BdAVfkeF.js.gz +0 -0
  466. package/dist/ui/assets/syntax-BOfTnQiy.js.gz +0 -0
  467. package/dist/ui/assets/timeline-definition-IT6M3QCI-CaRH3k4l.js.gz +0 -0
  468. package/dist/ui/assets/useUserLocalStorage-C8sgXgXR.js.gz +0 -0
  469. package/dist/ui/assets/xychartDiagram-PRI3JC2R-BlhkI9T_.js.gz +0 -0
@@ -193,6 +193,24 @@ var init_append_system_message = __esm({
193
193
  }
194
194
  });
195
195
 
196
+ // src/auth/executor-session-token.ts
197
+ function isExecutorSessionTokenPayload(payload) {
198
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) return false;
199
+ const record2 = payload;
200
+ return record2.type === EXECUTOR_SESSION_TOKEN_TYPE && record2.purpose === EXECUTOR_SESSION_TOKEN_PURPOSE;
201
+ }
202
+ function getExecutorSessionTokenSessionId(payload) {
203
+ return payload.session_id ?? payload.sessionId;
204
+ }
205
+ var EXECUTOR_SESSION_TOKEN_TYPE, EXECUTOR_SESSION_TOKEN_PURPOSE;
206
+ var init_executor_session_token = __esm({
207
+ "src/auth/executor-session-token.ts"() {
208
+ "use strict";
209
+ EXECUTOR_SESSION_TOKEN_TYPE = "executor-session";
210
+ EXECUTOR_SESSION_TOKEN_PURPOSE = "executor-task";
211
+ }
212
+ });
213
+
196
214
  // src/utils/branch-authorization.ts
197
215
  import { shortId as shortId4 } from "@agor/core/db";
198
216
  import { Forbidden as Forbidden7, NotAuthenticated as NotAuthenticated7, NotFound } from "@agor/core/feathers";
@@ -479,7 +497,7 @@ __export(service_jwt_strategy_exports, {
479
497
  ServiceJWTStrategy: () => ServiceJWTStrategy
480
498
  });
481
499
  import { JWTStrategy } from "@agor/core/feathers";
482
- import jwt6 from "jsonwebtoken";
500
+ import jwt7 from "jsonwebtoken";
483
501
  function persistExecutorJwtPayloadOnConnection(params, accessToken, payload) {
484
502
  const connection = params?.connection;
485
503
  if (!connection) return;
@@ -508,6 +526,7 @@ var init_service_jwt_strategy = __esm({
508
526
  "src/auth/service-jwt-strategy.ts"() {
509
527
  "use strict";
510
528
  init_users();
529
+ init_executor_session_token();
511
530
  init_runtime_tokens();
512
531
  init_token_invalidation();
513
532
  ServiceJWTStrategy = class extends JWTStrategy {
@@ -549,7 +568,7 @@ var init_service_jwt_strategy = __esm({
549
568
  */
550
569
  // biome-ignore lint/suspicious/noExplicitAny: Feathers type compatibility
551
570
  async authenticate(authentication, params) {
552
- const decoded = jwt6.decode(authentication?.accessToken);
571
+ const decoded = jwt7.decode(authentication?.accessToken);
553
572
  propagateTenantFromJwtPayload(params, decoded, this.tenantClaim);
554
573
  const result = await super.authenticate(authentication, params);
555
574
  const payload = result.authentication?.payload;
@@ -568,14 +587,14 @@ var init_service_jwt_strategy = __esm({
568
587
  };
569
588
  }
570
589
  if (payload?.type === "executor-session") {
571
- if (payload.purpose !== "executor-task") {
590
+ if (!isExecutorSessionTokenPayload(payload)) {
572
591
  throw new Error("Invalid executor token purpose");
573
592
  }
574
593
  const token = authentication?.accessToken;
575
594
  if (!token || !this.sessionTokenService) {
576
595
  throw new Error("Executor token validation unavailable");
577
596
  }
578
- const sessionId = payload.session_id ?? payload.sessionId;
597
+ const sessionId = getExecutorSessionTokenSessionId(payload);
579
598
  const sessionInfo = await this.sessionTokenService.validateToken(token, {
580
599
  sessionId,
581
600
  taskId: payload.task_id,
@@ -1497,7 +1516,7 @@ import {
1497
1516
  MCP_TOKEN_AUDIENCE,
1498
1517
  MCP_TOKEN_ISSUER
1499
1518
  } from "@agor/core/types";
1500
- import jwt7 from "jsonwebtoken";
1519
+ import jwt8 from "jsonwebtoken";
1501
1520
  import { MCP_TOKEN_AUDIENCE as MCP_TOKEN_AUDIENCE2, MCP_TOKEN_ISSUER as MCP_TOKEN_ISSUER2 } from "@agor/core/types";
1502
1521
  function mcpTokenDebug(...args) {
1503
1522
  if (DEBUG_MCP_TOKENS) {
@@ -1569,7 +1588,7 @@ async function generateSessionToken2(app, sessionId, userId) {
1569
1588
  exp: expSec,
1570
1589
  jti
1571
1590
  };
1572
- const token = jwt7.sign(payload, jwtSecret, { algorithm: "HS256" });
1591
+ const token = jwt8.sign(payload, jwtSecret, { algorithm: "HS256" });
1573
1592
  s.tokenCache.set(cacheKey, { token, expiresAtMs });
1574
1593
  mcpTokenDebug(
1575
1594
  `\u{1F3AB} MCP token issued: session=${shortId8(sessionId)} jti=${jti.substring(0, 8)} exp=+${Math.floor(s.expirationMs / 1e3)}s`
@@ -1585,15 +1604,15 @@ async function validateSessionToken(app, token) {
1585
1604
  }
1586
1605
  let payload;
1587
1606
  try {
1588
- payload = jwt7.verify(token, jwtSecret, {
1607
+ payload = jwt8.verify(token, jwtSecret, {
1589
1608
  audience: MCP_TOKEN_AUDIENCE,
1590
1609
  issuer: MCP_TOKEN_ISSUER,
1591
1610
  algorithms: ["HS256"]
1592
1611
  });
1593
1612
  } catch (err) {
1594
- if (err instanceof jwt7.TokenExpiredError) {
1613
+ if (err instanceof jwt8.TokenExpiredError) {
1595
1614
  console.warn("[mcp-tokens] token rejected: expired");
1596
- } else if (err instanceof jwt7.JsonWebTokenError) {
1615
+ } else if (err instanceof jwt8.JsonWebTokenError) {
1597
1616
  console.warn(`[mcp-tokens] token rejected: ${err.message}`);
1598
1617
  } else {
1599
1618
  console.error("[mcp-tokens] token verify error:", err);
@@ -1660,12 +1679,12 @@ import {
1660
1679
  permissionModeForCli,
1661
1680
  slugForCwd
1662
1681
  } from "@agor/core/claude-cli";
1663
- import { resolveMultiTenancyConfig as resolveMultiTenancyConfig3 } from "@agor/core/config";
1682
+ import { resolveMultiTenancyConfig as resolveMultiTenancyConfig4 } from "@agor/core/config";
1664
1683
  import {
1665
1684
  generateId as generateId6,
1666
1685
  getCurrentTenantId as getCurrentTenantId3,
1667
1686
  runWithoutTenantDatabaseScope as runWithoutTenantDatabaseScope2,
1668
- runWithTenantDatabaseScope as runWithTenantDatabaseScope4,
1687
+ runWithTenantDatabaseScope as runWithTenantDatabaseScope6,
1669
1688
  SessionRepository as SessionRepository4,
1670
1689
  shortId as shortId9,
1671
1690
  TaskRepository
@@ -1685,7 +1704,7 @@ function getDb(app) {
1685
1704
  }
1686
1705
  function getCliFallbackTenantId(app) {
1687
1706
  const config2 = app.get("config");
1688
- return resolveMultiTenancyConfig3(config2 ?? {}).static_tenant_id;
1707
+ return resolveMultiTenancyConfig4(config2 ?? {}).static_tenant_id;
1689
1708
  }
1690
1709
  function captureCliWatcherTenantId(app) {
1691
1710
  return getCurrentTenantId3() ?? getCliFallbackTenantId(app);
@@ -1697,7 +1716,7 @@ async function runCliCallbackDatabaseScope(app, sessionId, work) {
1697
1716
  const db = getDb(app);
1698
1717
  if (!db) return work();
1699
1718
  const tenantId = cliWatcherTenantBySession.get(sessionId) ?? captureCliWatcherTenantId(app);
1700
- return runWithTenantDatabaseScope4(db, tenantId, work);
1719
+ return runWithTenantDatabaseScope6(db, tenantId, work);
1701
1720
  }
1702
1721
  async function persistActiveTurnSnapshot(app, sessionId, turn) {
1703
1722
  const db = getDb(app);
@@ -15850,7 +15869,7 @@ __export(schemas_exports2, {
15850
15869
  ipv4: () => ipv42,
15851
15870
  ipv6: () => ipv62,
15852
15871
  json: () => json,
15853
- jwt: () => jwt8,
15872
+ jwt: () => jwt9,
15854
15873
  keyof: () => keyof,
15855
15874
  ksuid: () => ksuid2,
15856
15875
  lazy: () => lazy,
@@ -16017,7 +16036,7 @@ function base64url2(params) {
16017
16036
  function e1642(params) {
16018
16037
  return _e164(ZodE164, params);
16019
16038
  }
16020
- function jwt8(params) {
16039
+ function jwt9(params) {
16021
16040
  return _jwt(ZodJWT, params);
16022
16041
  }
16023
16042
  function stringFormat(format, fnOrRegex, _params = {}) {
@@ -17907,7 +17926,7 @@ __export(external_exports, {
17907
17926
  ipv6: () => ipv62,
17908
17927
  iso: () => iso_exports2,
17909
17928
  json: () => json,
17910
- jwt: () => jwt8,
17929
+ jwt: () => jwt9,
17911
17930
  keyof: () => keyof,
17912
17931
  ksuid: () => ksuid2,
17913
17932
  lazy: () => lazy,
@@ -21041,11 +21060,15 @@ import {
21041
21060
  ThreadSessionMapRepository
21042
21061
  } from "@agor/core/db";
21043
21062
  import {
21044
- getConnector
21063
+ buildSlackManifest,
21064
+ getConnector,
21065
+ requiredBotEvents,
21066
+ requiredBotScopes
21045
21067
  } from "@agor/core/gateway";
21046
21068
  import {
21047
21069
  GATEWAY_REDACTED_SENTINEL,
21048
21070
  GATEWAY_SENSITIVE_CONFIG_FIELDS,
21071
+ getRequiredSecretFields,
21049
21072
  hasMinimumRole as hasMinimumRole7,
21050
21073
  ROLES as ROLES8
21051
21074
  } from "@agor/core/types";
@@ -21054,6 +21077,19 @@ function requireAdmin(ctx, action) {
21054
21077
  throw new Error(`Access denied: admin role required to ${action}`);
21055
21078
  }
21056
21079
  }
21080
+ async function resolveCallerSessionBranchId(ctx) {
21081
+ if (!ctx.sessionId) return null;
21082
+ const session = await new SessionRepository5(ctx.db).findById(ctx.sessionId);
21083
+ if (!session) {
21084
+ throw new Error("Gateway access denied: calling session not found");
21085
+ }
21086
+ return session.branch_id;
21087
+ }
21088
+ function sessionBranchReadDeniedError() {
21089
+ return new Error(
21090
+ "Gateway read denied: this Slack thread belongs to a gateway channel targeting a different branch than the calling session's. Sessions can read Slack thread history only through gateway channels whose target branch matches their own."
21091
+ );
21092
+ }
21057
21093
  async function canUseGatewayOutbound(ctx, branchRepo, branch) {
21058
21094
  if (hasMinimumRole7(ctx.authenticatedUser?.role, ROLES8.ADMIN)) return true;
21059
21095
  const userId = ctx.userId;
@@ -21134,16 +21170,23 @@ async function resolveSlackThreadHistoryTarget(ctx, args) {
21134
21170
  const channelRepo = new GatewayChannelRepository2(ctx.db);
21135
21171
  const threadMapRepo = new ThreadSessionMapRepository(ctx.db);
21136
21172
  const branchRepo = new BranchRepository4(ctx.db);
21173
+ const callerSessionBranchId = await resolveCallerSessionBranchId(ctx);
21137
21174
  if (args.sessionId) {
21138
21175
  const session = await ctx.app.service("sessions").get(args.sessionId, ctx.baseServiceParams);
21139
21176
  const mapping2 = await threadMapRepo.findBySession(session.session_id);
21140
21177
  if (!mapping2) {
21141
21178
  throw new Error(`No gateway thread mapping found for session ${session.session_id}.`);
21142
21179
  }
21180
+ if (callerSessionBranchId && mapping2.branch_id !== callerSessionBranchId) {
21181
+ throw sessionBranchReadDeniedError();
21182
+ }
21143
21183
  const channel2 = await channelRepo.findById(mapping2.channel_id);
21144
21184
  if (!channel2) {
21145
21185
  throw new Error(`Gateway channel not found for session mapping ${mapping2.id}.`);
21146
21186
  }
21187
+ if (callerSessionBranchId && channel2.target_branch_id !== callerSessionBranchId) {
21188
+ throw sessionBranchReadDeniedError();
21189
+ }
21147
21190
  const branch2 = await branchRepo.findById(mapping2.branch_id);
21148
21191
  return {
21149
21192
  channel: channel2,
@@ -21158,6 +21201,9 @@ async function resolveSlackThreadHistoryTarget(ctx, args) {
21158
21201
  if (!channel) {
21159
21202
  throw new Error(`Gateway channel not found: ${args.gatewayChannelId}`);
21160
21203
  }
21204
+ if (callerSessionBranchId && channel.target_branch_id !== callerSessionBranchId) {
21205
+ throw sessionBranchReadDeniedError();
21206
+ }
21161
21207
  const mapping = await threadMapRepo.findByChannelAndThread(channel.id, args.threadId);
21162
21208
  if (mapping) {
21163
21209
  const branch2 = await branchRepo.findById(mapping.branch_id);
@@ -21251,6 +21297,34 @@ function toServiceUpdateData(args) {
21251
21297
  }
21252
21298
  return updates;
21253
21299
  }
21300
+ function toSlackWizardOptions(args) {
21301
+ return {
21302
+ appName: args.appName,
21303
+ ...args.botDisplayName ? { botDisplayName: args.botDisplayName } : {},
21304
+ publicChannels: args.publicChannels,
21305
+ privateChannels: args.privateChannels,
21306
+ groupDms: args.groupDms,
21307
+ alignUsers: args.alignUsers,
21308
+ outbound: args.outbound
21309
+ };
21310
+ }
21311
+ function toCreateChannelConfigHint(args) {
21312
+ const config2 = {
21313
+ connection_mode: "socket",
21314
+ enable_channels: args.publicChannels,
21315
+ enable_groups: args.privateChannels,
21316
+ enable_mpim: args.groupDms,
21317
+ align_slack_users: args.alignUsers,
21318
+ outbound_enabled: args.outbound
21319
+ };
21320
+ if (args.restrictToChannelIds && args.restrictToChannelIds.length > 0) {
21321
+ config2.allowed_channel_ids = args.restrictToChannelIds;
21322
+ }
21323
+ return { channelType: "slack", config: config2 };
21324
+ }
21325
+ function identityModeSetupStep(alignUsers) {
21326
+ return alignUsers ? "Identity: the channel is set to align Slack users \u2014 each Slack user runs as their matched Agor account and unmatched users are rejected, so no run-as user is needed. Tell me if you would rather every message run as one fixed Agor user (that requires picking a user and passing agorUserId)." : "Identity: the channel is set to run every message as one fixed Agor user, which requires passing agorUserId to agor_gateway_channels_create. Tell me if you would rather align Slack users so each runs as their own matched Agor account instead.";
21327
+ }
21254
21328
  function registerGatewayChannelTools(server, ctx) {
21255
21329
  server.registerTool(
21256
21330
  "agor_gateway_channels_list",
@@ -21296,7 +21370,7 @@ function registerGatewayChannelTools(server, ctx) {
21296
21370
  server.registerTool(
21297
21371
  "agor_gateway_channels_create",
21298
21372
  {
21299
- description: 'Create a gateway channel definition (admin-only) through the same gateway-channels service used by the UI. Current connectors: Slack, GitHub, Teams. Slack example config: { bot_token, app_token, connection_mode:"socket", enable_channels:true, require_mention:true, allowed_channel_ids:["C123"] }. Secrets are encrypted by the service and returned redacted; prefer environment/template references where possible because raw secrets in tool arguments may appear in the MCP transcript.',
21373
+ description: 'Create a gateway channel definition (admin-only) through the same gateway-channels service used by the UI. Current connectors: Slack, GitHub, Teams. For interactive/agent-driven setup, create the channel disabled and without secrets (enabled:false, no tokens), then collect credentials with agor_widgets_request_gateway_token so the user enters them in a secure inline form \u2014 raw secrets passed in tool arguments leak into the MCP transcript. Passing secrets directly here is for programmatic/non-interactive use only. Non-interactive Slack example config: { bot_token, app_token, connection_mode:"socket", enable_channels:true, require_mention:true, allowed_channel_ids:["C123"] }. Secrets are encrypted by the service and returned redacted.',
21300
21374
  annotations: { destructiveHint: false, idempotentHint: false },
21301
21375
  inputSchema: gatewayChannelCreateSchema
21302
21376
  },
@@ -21306,12 +21380,50 @@ function registerGatewayChannelTools(server, ctx) {
21306
21380
  return textResult({
21307
21381
  gateway_channel: redactGatewayChannel(created),
21308
21382
  next_steps: [
21383
+ "If this channel was created disabled without tokens (the recommended interactive path), collect its credentials by calling agor_widgets_request_gateway_token for this channel so the user enters the tokens in the secure form that appears at the end of this message. Do NOT ask the user to paste xoxb-/xapp- tokens into the chat, and do NOT pass tokens as agor_gateway_channels_create arguments during interactive setup.",
21384
+ ...created.channel_type === "slack" ? [
21385
+ identityModeSetupStep(
21386
+ created.config?.align_slack_users === true
21387
+ )
21388
+ ] : [],
21309
21389
  "Verify the channel in Settings > Gateway Channels or with agor_gateway_channels_list.",
21310
21390
  "Channel credentials, env vars, and inbound channel keys are intentionally redacted from MCP responses."
21311
21391
  ]
21312
21392
  });
21313
21393
  }
21314
21394
  );
21395
+ server.registerTool(
21396
+ "agor_gateway_slack_manifest_generate",
21397
+ {
21398
+ description: "Generate a ready-to-install Slack app manifest from desired gateway capabilities (admin-only). The agent-driven equivalent of the Slack setup wizard, backed by the same core generator. Returns the manifest JSON, the derived bot scopes/events, ordered setup steps, and the channel config to pass to agor_gateway_channels_create. This is pure: it creates no Slack app, no Agor channel, and validates no tokens.",
21399
+ annotations: { readOnlyHint: true },
21400
+ inputSchema: slackManifestGenerateSchema
21401
+ },
21402
+ async (args) => {
21403
+ requireAdmin(ctx, "generate Slack app manifests");
21404
+ const options = toSlackWizardOptions(args);
21405
+ return textResult({
21406
+ manifest: buildSlackManifest(options),
21407
+ bot_scopes: requiredBotScopes(options),
21408
+ bot_events: requiredBotEvents(options),
21409
+ setup_steps: [
21410
+ 'Open https://api.slack.com/apps?new_app=1 and choose "Create New App".',
21411
+ 'Select "From a manifest", pick the target workspace, paste the manifest JSON below, and click "Create".',
21412
+ 'Install the app to the workspace, then open OAuth & Permissions and copy the Bot User OAuth Token (starts with "xoxb-").',
21413
+ 'Open Basic Information \u2192 App-Level Tokens \u2192 Generate Token and Scopes, add the connections:write scope, generate it, and copy the App-Level Token (starts with "xapp-").',
21414
+ 'Once the app is installed and you hold the xoxb-/xapp- tokens, call agor_gateway_channels_create with channelType "slack", enabled:false, no tokens, and create_channel_config_hint below to create the channel as a draft.',
21415
+ "Then call agor_widgets_request_gateway_token for that channel so the user enters the xoxb-/xapp- tokens in the secure form that appears at the end of this message, which enables the channel. Do NOT ask the user to paste xoxb-/xapp- tokens into the chat, and do NOT pass tokens as agor_gateway_channels_create arguments.",
21416
+ identityModeSetupStep(args.alignUsers)
21417
+ ],
21418
+ create_channel_config_hint: toCreateChannelConfigHint(args),
21419
+ caveats: [
21420
+ "GENERATED ONLY \u2014 no Slack app created, no Agor channel created, no tokens validated, no event delivery verified.",
21421
+ "The app-level connections:write token is generated manually and is NOT part of the manifest bot scopes.",
21422
+ "restrictToChannelIds maps to config.allowed_channel_ids when you call create \u2014 it does NOT change the manifest scopes or events."
21423
+ ]
21424
+ });
21425
+ }
21426
+ );
21315
21427
  server.registerTool(
21316
21428
  "agor_gateway_channels_update",
21317
21429
  {
@@ -21335,7 +21447,7 @@ function registerGatewayChannelTools(server, ctx) {
21335
21447
  server.registerTool(
21336
21448
  "agor_gateway_outbound_targets_list",
21337
21449
  {
21338
- description: "List Slack gateway outbound targets the caller can use. Returns only outbound-enabled channels where the caller has branch all permission or admin access. Secrets and inbound channel keys are never returned.",
21450
+ description: "List Slack gateway outbound targets the caller can use. Returns only outbound-enabled channels where the caller has branch all permission or admin access; when called from a session, results are additionally scoped to channels targeting the session's branch. Secrets and inbound channel keys are never returned.",
21339
21451
  annotations: { readOnlyHint: true },
21340
21452
  inputSchema: external_exports.strictObject({
21341
21453
  branchId: mcpOptionalId("branchId", "Branch", "Filter by target branch ID."),
@@ -21350,15 +21462,24 @@ function registerGatewayChannelTools(server, ctx) {
21350
21462
  async (args) => {
21351
21463
  const channelRepo = new GatewayChannelRepository2(ctx.db);
21352
21464
  const branchRepo = new BranchRepository4(ctx.db);
21465
+ const callerSessionBranchId = await resolveCallerSessionBranchId(ctx);
21353
21466
  const branchFilter = args.branchId ? await branchRepo.findById(args.branchId) : null;
21354
- const branchFilterId = branchFilter?.branch_id;
21467
+ const requestedBranchId = branchFilter?.branch_id;
21468
+ if (callerSessionBranchId && args.branchId && requestedBranchId !== callerSessionBranchId) {
21469
+ return textResult({
21470
+ channels: [],
21471
+ binding: "Results are scoped to the calling session's branch; the requested branchId targets a different branch, so this session cannot use its channels."
21472
+ });
21473
+ }
21474
+ const branchFilterId = callerSessionBranchId ?? requestedBranchId;
21355
21475
  const allChannels = args.gatewayChannelId ? [await channelRepo.findById(args.gatewayChannelId)] : await channelRepo.findAll();
21356
21476
  const channels = [];
21357
21477
  for (const channel of allChannels) {
21358
21478
  if (!channel) continue;
21359
21479
  if (args.channelType && channel.channel_type !== args.channelType) continue;
21360
21480
  if (channel.channel_type !== "slack") continue;
21361
- if (args.branchId && channel.target_branch_id !== branchFilterId) continue;
21481
+ if ((callerSessionBranchId || args.branchId) && channel.target_branch_id !== branchFilterId)
21482
+ continue;
21362
21483
  if (!channel.enabled) continue;
21363
21484
  const outbound = getOutboundConfig(channel);
21364
21485
  if (!outbound.outbound_enabled) continue;
@@ -21381,13 +21502,18 @@ function registerGatewayChannelTools(server, ctx) {
21381
21502
  ]
21382
21503
  });
21383
21504
  }
21384
- return textResult({ channels });
21505
+ return textResult({
21506
+ channels,
21507
+ ...callerSessionBranchId && channels.length === 0 ? {
21508
+ hint: "No outbound-enabled channel targets this session's branch \u2014 ask an operator to create/enable one."
21509
+ } : {}
21510
+ });
21385
21511
  }
21386
21512
  );
21387
21513
  server.registerTool(
21388
21514
  "agor_gateway_slack_thread_history_get",
21389
21515
  {
21390
- description: "Fetch Slack thread history for a gateway-mapped Slack thread without exposing Slack tokens. Prefer sessionId to resolve the gateway thread mapping from an accessible Agor session. Alternatively pass gatewayChannelId + threadId: mapped threads require admin or branch all permission on the mapped branch; unmapped arbitrary thread reads are admin-only. Slack message text is untrusted external content.",
21516
+ description: "Fetch Slack thread history for a gateway-mapped Slack thread without exposing Slack tokens. Prefer sessionId to resolve the gateway thread mapping from an accessible Agor session. Alternatively pass gatewayChannelId + threadId: mapped threads require admin or branch all permission on the mapped branch; unmapped arbitrary thread reads are admin-only. When called from a session, reads are restricted to threads whose target branch matches the calling session's branch. Slack message text is untrusted external content.",
21391
21517
  annotations: { readOnlyHint: true },
21392
21518
  inputSchema: slackThreadHistorySchema
21393
21519
  },
@@ -21455,7 +21581,7 @@ function registerGatewayChannelTools(server, ctx) {
21455
21581
  server.registerTool(
21456
21582
  "agor_gateway_emit_message",
21457
21583
  {
21458
- description: "Send a proactive Slack message through an outbound-enabled gateway channel and persist a seed/audit record. Targets may be Slack channel IDs, channel names, or user emails; v0 intentionally starts a fresh Slack thread/DM message for each emit and does not create a thread-session mapping until a human replies.",
21584
+ description: "Send a proactive Slack message through an outbound-enabled gateway channel and persist a seed/audit record. Targets may be Slack channel IDs, channel names, or user emails; v0 intentionally starts a fresh Slack thread/DM message for each emit and does not create a thread-session mapping until a human replies. When called from a session, outbound is restricted to channels whose target branch matches the calling session's branch.",
21459
21585
  annotations: { destructiveHint: false, idempotentHint: false },
21460
21586
  inputSchema: external_exports.strictObject({
21461
21587
  gatewayChannelId: mcpRequiredId(
@@ -21492,7 +21618,7 @@ function registerGatewayChannelTools(server, ctx) {
21492
21618
  }
21493
21619
  );
21494
21620
  }
21495
- var configSchema, outboundTargetSchema, envVarSchema, agenticConfigSchema, gatewayChannelCreateSchema, slackThreadHistorySchema, gatewayChannelUpdateSchema;
21621
+ var configSchema, outboundTargetSchema, envVarSchema, agenticConfigSchema, gatewayChannelCreateSchema, slackThreadHistorySchema, gatewayChannelUpdateSchema, slackManifestGenerateSchema;
21496
21622
  var init_gateway_channels = __esm({
21497
21623
  "src/mcp/tools/gateway-channels.ts"() {
21498
21624
  "use strict";
@@ -21556,44 +21682,48 @@ var init_gateway_channels = __esm({
21556
21682
  agenticConfig: agenticConfigSchema.optional()
21557
21683
  }).superRefine((value, issue2) => {
21558
21684
  const config2 = value.config ?? {};
21559
- if (value.channelType === "slack") {
21560
- if (!config2.bot_token) {
21561
- issue2.addIssue({
21562
- code: "custom",
21563
- path: ["config", "bot_token"],
21564
- message: "config.bot_token is required for Slack. Prefer a bot token stored outside the transcript when possible."
21565
- });
21566
- }
21567
- if (config2.connection_mode === "socket" && !config2.app_token) {
21568
- issue2.addIssue({
21569
- code: "custom",
21570
- path: ["config", "app_token"],
21571
- message: "config.app_token is required for Slack Socket Mode."
21572
- });
21573
- }
21574
- }
21575
- if (value.channelType === "github") {
21576
- for (const field of ["app_id", "private_key", "installation_id", "watch_repos"]) {
21685
+ if (value.enabled !== false) {
21686
+ const requiredSecretMessages = {
21687
+ bot_token: "config.bot_token is required for Slack. Prefer a bot token stored outside the transcript when possible.",
21688
+ app_token: "config.app_token is required for Slack Socket Mode.",
21689
+ private_key: "config.private_key is required for GitHub gateway channels.",
21690
+ app_password: "config.app_password is required for Teams gateway channels."
21691
+ };
21692
+ for (const field of getRequiredSecretFields(value.channelType, config2)) {
21577
21693
  if (!config2[field]) {
21578
21694
  issue2.addIssue({
21579
21695
  code: "custom",
21580
21696
  path: ["config", field],
21581
- message: `config.${field} is required for GitHub gateway channels.`
21697
+ message: requiredSecretMessages[field] ?? `config.${field} is required for ${value.channelType} gateway channels.`
21582
21698
  });
21583
21699
  }
21584
21700
  }
21585
21701
  }
21586
- if (value.channelType === "teams") {
21587
- for (const field of ["app_id", "app_password"]) {
21702
+ if (value.channelType === "github") {
21703
+ for (const field of ["app_id", "installation_id", "watch_repos"]) {
21588
21704
  if (!config2[field]) {
21589
21705
  issue2.addIssue({
21590
21706
  code: "custom",
21591
21707
  path: ["config", field],
21592
- message: `config.${field} is required for Teams gateway channels.`
21708
+ message: `config.${field} is required for GitHub gateway channels.`
21593
21709
  });
21594
21710
  }
21595
21711
  }
21596
21712
  }
21713
+ if (value.channelType === "teams" && !config2.app_id) {
21714
+ issue2.addIssue({
21715
+ code: "custom",
21716
+ path: ["config", "app_id"],
21717
+ message: "config.app_id is required for Teams gateway channels."
21718
+ });
21719
+ }
21720
+ if (value.channelType === "slack" && config2.align_slack_users !== true && !value.agorUserId) {
21721
+ issue2.addIssue({
21722
+ code: "custom",
21723
+ path: ["agorUserId"],
21724
+ message: "Run-as-selected-user needs agorUserId \u2014 set config.align_slack_users:true to align by email, or pass agorUserId."
21725
+ });
21726
+ }
21597
21727
  });
21598
21728
  slackThreadHistorySchema = external_exports.strictObject({
21599
21729
  sessionId: mcpOptionalId(
@@ -21657,6 +21787,23 @@ var init_gateway_channels = __esm({
21657
21787
  ),
21658
21788
  agenticConfig: agenticConfigSchema.nullable().optional().describe("Replace agent/session defaults. null clears the gateway agentic config.")
21659
21789
  });
21790
+ slackManifestGenerateSchema = external_exports.strictObject({
21791
+ appName: mcpRequiredString("appName", 'Slack app display name, e.g. "Agor".'),
21792
+ botDisplayName: mcpOptionalNonEmptyString(
21793
+ "botDisplayName",
21794
+ "Bot user display name. Defaults to appName."
21795
+ ),
21796
+ publicChannels: external_exports.boolean().default(false).describe("Listen in public channels (#channel) via @mention."),
21797
+ privateChannels: external_exports.boolean().default(false).describe("Listen in private channels (groups) via @mention."),
21798
+ groupDms: external_exports.boolean().default(false).describe("Listen in group DMs (multi-person IMs) via @mention."),
21799
+ alignUsers: external_exports.boolean().default(true).describe(
21800
+ "Resolve Slack user email \u2192 Agor user (adds the users:read.email scope). Defaults to true: each Slack user runs as their matched Agor account and unmatched users are rejected, so no fixed run-as user is needed. Set false to run every message as one fixed Agor user (then pass agorUserId to agor_gateway_channels_create)."
21801
+ ),
21802
+ outbound: external_exports.boolean().default(false).describe("Proactive outbound: post to channels by name and DM users by email."),
21803
+ restrictToChannelIds: external_exports.array(external_exports.string().min(1)).optional().describe(
21804
+ "Slack channel ID whitelist. Maps to config.allowed_channel_ids when you call agor_gateway_channels_create; it does NOT change the manifest scopes or events."
21805
+ )
21806
+ });
21660
21807
  }
21661
21808
  });
21662
21809
 
@@ -26844,8 +26991,53 @@ var init_env_vars = __esm({
26844
26991
  }
26845
26992
  });
26846
26993
 
26994
+ // src/widgets/gateway-token/index.ts
26995
+ import { Forbidden as Forbidden10 } from "@agor/core/feathers";
26996
+ import {
26997
+ GATEWAY_SENSITIVE_CONFIG_FIELDS as GATEWAY_SENSITIVE_CONFIG_FIELDS2,
26998
+ hasMinimumRole as hasMinimumRole9,
26999
+ ROLES as ROLES11
27000
+ } from "@agor/core/types";
27001
+ function isSupportedGatewayTokenChannelType(channelType) {
27002
+ return SUPPORTED_CHANNEL_TYPES.includes(channelType);
27003
+ }
27004
+ var SUPPORTED_CHANNEL_TYPES, MAX_TOKEN_LENGTH, gatewayTokenParamsSchema, gatewayTokenSubmitSchema;
27005
+ var init_gateway_token = __esm({
27006
+ "src/widgets/gateway-token/index.ts"() {
27007
+ "use strict";
27008
+ init_zod();
27009
+ init_registry();
27010
+ SUPPORTED_CHANNEL_TYPES = [
27011
+ "slack",
27012
+ "github",
27013
+ "teams"
27014
+ ];
27015
+ MAX_TOKEN_LENGTH = 8192;
27016
+ gatewayTokenParamsSchema = external_exports.object({
27017
+ gatewayChannelId: external_exports.string().min(1).describe("Gateway channel whose credentials are being set."),
27018
+ channelType: external_exports.enum(["slack", "discord", "whatsapp", "telegram", "github", "teams"]).describe("Platform type of the channel; drives per-field placeholders."),
27019
+ channelName: external_exports.string().min(1).max(200).describe("Human-readable channel name for the form heading and prompts."),
27020
+ fields: external_exports.array(external_exports.enum(GATEWAY_SENSITIVE_CONFIG_FIELDS2)).min(1).max(GATEWAY_SENSITIVE_CONFIG_FIELDS2.length).refine((fields) => new Set(fields).size === fields.length, {
27021
+ message: "Token field names must be unique"
27022
+ }).describe("Secret config field names to collect (subset of the sensitive fields)."),
27023
+ reason: external_exports.string().min(1).max(200).describe("One sentence explaining why the tokens are needed. Renders as a muted line.")
27024
+ }).strict();
27025
+ gatewayTokenSubmitSchema = external_exports.object({
27026
+ tokens: external_exports.partialRecord(
27027
+ external_exports.enum(GATEWAY_SENSITIVE_CONFIG_FIELDS2),
27028
+ external_exports.string().min(1).max(MAX_TOKEN_LENGTH)
27029
+ ).describe("Map of sensitive field name \u2192 credential value.")
27030
+ }).strict();
27031
+ }
27032
+ });
27033
+
26847
27034
  // src/mcp/tools/widgets.ts
26848
- import { MessageRole as MessageRole3 } from "@agor/core/types";
27035
+ import { getRequiredSecretFields as getRequiredSecretFields2, hasMinimumRole as hasMinimumRole10, MessageRole as MessageRole3, ROLES as ROLES12 } from "@agor/core/types";
27036
+ function requireAdmin2(ctx, action) {
27037
+ if (!hasMinimumRole10(ctx.authenticatedUser?.role, ROLES12.ADMIN)) {
27038
+ throw new Error(`Access denied: admin role required to ${action}`);
27039
+ }
27040
+ }
26849
27041
  function widgetContentPreview(params) {
26850
27042
  const list = params.names.join(", ");
26851
27043
  return params.names.length === 1 ? `Please provide ${list}: ${params.reason}` : `Please provide ${list}: ${params.reason}`;
@@ -26964,13 +27156,113 @@ function registerWidgetTools(server, ctx) {
26964
27156
  return textResult({ widget_id: widgetId, status: "requested" });
26965
27157
  }
26966
27158
  );
27159
+ server.registerTool(
27160
+ "agor_widgets_request_gateway_token",
27161
+ {
27162
+ description: "Ask an admin to securely provide a gateway channel's platform tokens (Slack bot/app tokens, GitHub private key, Teams app password) via a compact form that appears at the end of your message, so setup finishes without anyone pasting xoxb-/xapp- tokens into chat. FIRE-AND-FORGET: the widget renders inline at the end of your turn; end your turn after calling. You will receive a user-role message when it is resolved. Token values never enter your context \u2014 only the channel identity and field NAMES do. Admin-only: a non-admin agent cannot mint this widget. Keep `reason` to ONE short sentence (\u2264200 chars).",
27163
+ annotations: { destructiveHint: false, openWorldHint: false },
27164
+ inputSchema: external_exports.object({
27165
+ gatewayChannelId: external_exports.string().min(1).describe("Gateway channel ID (UUIDv7 or short ID) whose tokens are being set."),
27166
+ reason: external_exports.string().max(200).optional().describe("One short sentence explaining why the tokens are needed.")
27167
+ })
27168
+ },
27169
+ async (args) => {
27170
+ if (!ctx.sessionId) return sessionContextRequiredResult();
27171
+ const currentSessionId = ctx.sessionId;
27172
+ requireAdmin2(ctx, "set gateway channel tokens");
27173
+ const channel = await ctx.app.service("gateway-channels").get(args.gatewayChannelId, ctx.baseServiceParams);
27174
+ const channelType = channel.channel_type;
27175
+ if (!isSupportedGatewayTokenChannelType(channelType)) {
27176
+ throw new Error(
27177
+ `Gateway channel type "${channelType}" does not support token entry via this widget.`
27178
+ );
27179
+ }
27180
+ const fields = getRequiredSecretFields2(channelType, channel.config);
27181
+ if (fields.length === 0) {
27182
+ throw new Error(
27183
+ `Gateway channel "${channel.name}" has no required secret fields to collect.`
27184
+ );
27185
+ }
27186
+ const params = gatewayTokenParamsSchema.parse({
27187
+ gatewayChannelId: channel.id,
27188
+ channelType,
27189
+ channelName: channel.name,
27190
+ fields,
27191
+ reason: args.reason ?? `Provide the ${channelType} credentials to finish connecting "${channel.name}".`
27192
+ });
27193
+ const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
27194
+ const baseWidgetMeta = {
27195
+ widget_type: "gateway_token",
27196
+ schema_version: 1,
27197
+ params,
27198
+ status: "pending",
27199
+ requested_at: requestedAt,
27200
+ auto_resume: true
27201
+ };
27202
+ const hostTask = await findHostTaskForSession(
27203
+ ctx.app,
27204
+ currentSessionId,
27205
+ ctx.baseServiceParams
27206
+ );
27207
+ const hostTaskId = hostTask?.task_id;
27208
+ const created = await appendSystemMessage({
27209
+ app: ctx.app,
27210
+ db: ctx.db,
27211
+ sessionId: currentSessionId,
27212
+ taskId: hostTaskId,
27213
+ content: `Please provide the ${channelType} tokens for "${channel.name}": ${params.reason}`,
27214
+ contentPreview: `Widget: gateway_token (${channel.name})`,
27215
+ type: "widget_request",
27216
+ role: MessageRole3.SYSTEM,
27217
+ metadata: {
27218
+ widget: {
27219
+ ...baseWidgetMeta,
27220
+ widget_id: "pending"
27221
+ }
27222
+ }
27223
+ });
27224
+ const widgetId = created.message_id;
27225
+ if (hostTask?.message_range) {
27226
+ try {
27227
+ await ctx.app.service("tasks").patch(
27228
+ hostTask.task_id,
27229
+ {
27230
+ message_range: {
27231
+ start_index: hostTask.message_range.start_index,
27232
+ end_index: created.index
27233
+ }
27234
+ },
27235
+ ctx.baseServiceParams
27236
+ );
27237
+ } catch (err) {
27238
+ console.warn(
27239
+ `[widgets] failed to extend task.message_range for widget ${widgetId}:`,
27240
+ err
27241
+ );
27242
+ }
27243
+ }
27244
+ await ctx.app.service("messages").patch(
27245
+ widgetId,
27246
+ {
27247
+ metadata: {
27248
+ ...created.metadata ?? {},
27249
+ widget: { ...baseWidgetMeta, widget_id: widgetId }
27250
+ }
27251
+ },
27252
+ ctx.baseServiceParams
27253
+ );
27254
+ return textResult({ widget_id: widgetId, status: "requested" });
27255
+ }
27256
+ );
26967
27257
  }
26968
27258
  var init_widgets = __esm({
26969
27259
  "src/mcp/tools/widgets.ts"() {
26970
27260
  "use strict";
27261
+ init_zod();
26971
27262
  init_append_system_message();
26972
27263
  init_session_tasks();
26973
27264
  init_env_vars();
27265
+ init_gateway_token();
26974
27266
  init_server();
26975
27267
  }
26976
27268
  });
@@ -27534,7 +27826,7 @@ Discover tools: search domains/summaries \u2192 get details for one tool \u2192
27534
27826
  import {
27535
27827
  loadConfig as loadConfig3,
27536
27828
  resolveBranchStorageConfig,
27537
- resolveMultiTenancyConfig as resolveMultiTenancyConfig4
27829
+ resolveMultiTenancyConfig as resolveMultiTenancyConfig5
27538
27830
  } from "@agor/core/config";
27539
27831
  import {
27540
27832
  BranchRepository as BranchRepository8,
@@ -27555,7 +27847,7 @@ import {
27555
27847
  BadRequest as BadRequest5,
27556
27848
  Conflict as Conflict2,
27557
27849
  errorHandler,
27558
- Forbidden as Forbidden10,
27850
+ Forbidden as Forbidden11,
27559
27851
  LocalStrategy,
27560
27852
  NotAuthenticated as NotAuthenticated12,
27561
27853
  NotFound as NotFound5
@@ -27563,9 +27855,9 @@ import {
27563
27855
  import { PermissionService } from "@agor/core/permissions";
27564
27856
  import {
27565
27857
  AGENTIC_TOOL_CAPABILITIES as AGENTIC_TOOL_CAPABILITIES2,
27566
- hasMinimumRole as hasMinimumRole9,
27858
+ hasMinimumRole as hasMinimumRole11,
27567
27859
  MessageRole as MessageRole4,
27568
- ROLES as ROLES11,
27860
+ ROLES as ROLES13,
27569
27861
  SERVICE_GROUP_NAMES as SERVICE_GROUP_NAMES2,
27570
27862
  SessionStatus as SessionStatus5,
27571
27863
  TaskStatus as TaskStatus5
@@ -27573,6 +27865,58 @@ import {
27573
27865
  import { NotFoundError as NotFoundError4 } from "@agor/core/utils/errors";
27574
27866
  import { rateLimit as rateLimit2 } from "express-rate-limit";
27575
27867
 
27868
+ // src/auth/issue-browser-tokens-hook.ts
27869
+ init_runtime_tokens();
27870
+ init_token_invalidation();
27871
+
27872
+ // src/auth/user-redaction.ts
27873
+ function redactUserAuthMetadata(user) {
27874
+ const {
27875
+ tokens_valid_after: _tokensValidAfter,
27876
+ password: _password,
27877
+ tenant_id: _tenantId,
27878
+ ...publicUser
27879
+ } = user;
27880
+ return publicUser;
27881
+ }
27882
+
27883
+ // src/auth/issue-browser-tokens-hook.ts
27884
+ var MACHINE_TOKEN_TYPES = /* @__PURE__ */ new Set(["executor-session", "service"]);
27885
+ function createIssueBrowserTokensHook(options) {
27886
+ const { jwtSecret, accessTokenTtl, refreshTokenTtl, tenantClaim, debug } = options;
27887
+ return async (context) => {
27888
+ debug?.("\u2705 Authentication succeeded:", {
27889
+ strategy: context.result?.authentication?.strategy,
27890
+ hasUser: !!context.result?.user,
27891
+ user_id: context.result?.user?.user_id,
27892
+ hasAccessToken: !!context.result?.accessToken
27893
+ });
27894
+ if (!context.result?.user) {
27895
+ return context;
27896
+ }
27897
+ const payloadType = context.result.authentication?.payload?.type;
27898
+ if (typeof payloadType === "string" && MACHINE_TOKEN_TYPES.has(payloadType)) {
27899
+ context.result.user = redactUserAuthMetadata(context.result.user);
27900
+ return context;
27901
+ }
27902
+ const tenantId = context.params?.tenant?.tenant_id ?? context.result.user.tenant_id;
27903
+ const tokens = issueRuntimeTokenPair(
27904
+ context.result.user,
27905
+ jwtSecret,
27906
+ accessTokenTtl,
27907
+ refreshTokenTtl,
27908
+ {
27909
+ ...authTokenIssuedAtClaim(Date.now(), context.result.user),
27910
+ ...runtimeTenantClaims(tenantId, tenantClaim)
27911
+ }
27912
+ );
27913
+ context.result.accessToken = tokens.accessToken;
27914
+ context.result.refreshToken = tokens.refreshToken;
27915
+ context.result.user = redactUserAuthMetadata(context.result.user);
27916
+ return context;
27917
+ };
27918
+ }
27919
+
27576
27920
  // src/auth/launch-auth.ts
27577
27921
  init_runtime_tokens();
27578
27922
  init_token_invalidation();
@@ -27596,19 +27940,6 @@ import {
27596
27940
  import { BadRequest, NotAuthenticated as NotAuthenticated2 } from "@agor/core/feathers";
27597
27941
  import { normalizeRole, ROLES } from "@agor/core/types";
27598
27942
  import jwt2 from "jsonwebtoken";
27599
-
27600
- // src/auth/user-redaction.ts
27601
- function redactUserAuthMetadata(user) {
27602
- const {
27603
- tokens_valid_after: _tokensValidAfter,
27604
- password: _password,
27605
- tenant_id: _tenantId,
27606
- ...publicUser
27607
- } = user;
27608
- return publicUser;
27609
- }
27610
-
27611
- // src/auth/launch-auth.ts
27612
27943
  var DEFAULT_TIMEOUT_MS = 1e4;
27613
27944
  var DEFAULT_SERVICE_TOKEN_ENV = "AGOR_EXTERNAL_LAUNCH_SERVICE_TOKEN";
27614
27945
  var DEFAULT_SHARED_SECRET_ENV = "AGOR_EXTERNAL_LAUNCH_SHARED_SECRET";
@@ -28055,6 +28386,13 @@ function killExecutorProcess(sessionId) {
28055
28386
  return true;
28056
28387
  }
28057
28388
 
28389
+ // src/oauth-auth-helpers.ts
28390
+ import { runWithTenantDatabaseScope as runWithTenantDatabaseScope2 } from "@agor/core/db";
28391
+ function resolveForUserIdWithGate(opts) {
28392
+ const canUseExplicitUser = opts.isServiceAccount === true || opts.authPayloadType === "executor-session" && opts.queryForUserId === opts.callerUserId;
28393
+ return opts.queryForUserId && canUseExplicitUser ? opts.queryForUserId : opts.callerUserId;
28394
+ }
28395
+
28058
28396
  // src/services/scheduler.ts
28059
28397
  import {
28060
28398
  advisoryLockKeyForUuid,
@@ -28062,7 +28400,7 @@ import {
28062
28400
  getCurrentTenantId,
28063
28401
  isPostgresDatabase,
28064
28402
  runWithSystemDatabaseScope,
28065
- runWithTenantDatabaseScope as runWithTenantDatabaseScope2,
28403
+ runWithTenantDatabaseScope as runWithTenantDatabaseScope3,
28066
28404
  ScheduleRepository,
28067
28405
  SessionMCPServerRepository,
28068
28406
  SessionRepository,
@@ -28433,20 +28771,21 @@ import { Forbidden as Forbidden6, NotAuthenticated as NotAuthenticated6 } from "
28433
28771
  import { hasMinimumRole as hasMinimumRole3, ROLES as ROLES4 } from "@agor/core/types";
28434
28772
 
28435
28773
  // src/auth/executor-runtime-scope.ts
28774
+ init_executor_session_token();
28436
28775
  import { Forbidden as Forbidden5 } from "@agor/core/feathers";
28437
28776
  function scopedPayload(context) {
28438
28777
  const params = context.params;
28439
28778
  const payload = params.authentication?.payload;
28440
- if (payload?.type === "executor-session") {
28441
- if (payload.purpose !== "executor-task") {
28779
+ if (payload?.type === EXECUTOR_SESSION_TOKEN_TYPE) {
28780
+ if (!isExecutorSessionTokenPayload(payload)) {
28442
28781
  throw new Forbidden5("Executor token is not valid for this request");
28443
28782
  }
28444
28783
  return payload;
28445
28784
  }
28446
28785
  if (params.authentication?.strategy === "jwt" && params.task_id) {
28447
28786
  return {
28448
- type: "executor-session",
28449
- purpose: "executor-task",
28787
+ type: EXECUTOR_SESSION_TOKEN_TYPE,
28788
+ purpose: EXECUTOR_SESSION_TOKEN_PURPOSE,
28450
28789
  task_id: params.task_id,
28451
28790
  session_id: params.session_id,
28452
28791
  sessionId: params.sessionId,
@@ -28556,7 +28895,7 @@ function executorRuntimeScopeGuard() {
28556
28895
  const payload = scopedPayload(context);
28557
28896
  if (!payload) return context;
28558
28897
  const scope = {
28559
- sessionId: payload.session_id ?? payload.sessionId,
28898
+ sessionId: getExecutorSessionTokenSessionId(payload),
28560
28899
  taskId: payload.task_id,
28561
28900
  branchId: payload.branch_id
28562
28901
  };
@@ -28768,13 +29107,29 @@ ${rawPrompt}`,
28768
29107
  }
28769
29108
 
28770
29109
  // src/utils/mcp-header-secrets.ts
29110
+ init_executor_session_token();
28771
29111
  import { redactMCPAuthSecrets } from "@agor/core/tools/mcp/auth-secrets";
28772
29112
  import { redactMCPCustomHeaders } from "@agor/core/tools/mcp/http-headers";
29113
+ import jwt5 from "jsonwebtoken";
28773
29114
  function shouldExposeMCPServerSecretsForSessionToken(params, options = {}) {
28774
- const payload = params?.authentication?.payload;
28775
- const sessionId = params?.session_id ?? payload?.session_id ?? payload?.sessionId;
29115
+ const payload = params?.authentication?.payload ?? decodeExecutorSessionPayload(params);
29116
+ const sessionId = params?.session_id ?? getPayloadSessionId(payload);
28776
29117
  return !!params?.provider && (params.authentication?.strategy === "session-token" || payload?.type === "executor-session") && !!sessionId && (!options.sessionId || sessionId === options.sessionId);
28777
29118
  }
29119
+ function decodeExecutorSessionPayload(params) {
29120
+ if (params?.authentication?.strategy !== "jwt" || !params.authentication.accessToken) {
29121
+ return void 0;
29122
+ }
29123
+ const decoded = jwt5.decode(params.authentication.accessToken);
29124
+ if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) {
29125
+ return void 0;
29126
+ }
29127
+ if (!isExecutorSessionTokenPayload(decoded)) return void 0;
29128
+ return decoded;
29129
+ }
29130
+ function getPayloadSessionId(payload) {
29131
+ return payload ? getExecutorSessionTokenSessionId(payload) : void 0;
29132
+ }
28778
29133
  function shouldExposeMCPServerSecrets(params, options = {}) {
28779
29134
  if (!params?.provider) return true;
28780
29135
  if (params.user?._isServiceAccount || params.user?.role === "service") return true;
@@ -28826,6 +29181,186 @@ function ensureScheduleRunsAsCaller(options) {
28826
29181
  };
28827
29182
  }
28828
29183
 
29184
+ // src/utils/session-queue-tenant-scope.ts
29185
+ import { resolveMultiTenancyConfig as resolveMultiTenancyConfig3 } from "@agor/core/config";
29186
+ import { runWithTenantDatabaseScope as runWithTenantDatabaseScope5 } from "@agor/core/db";
29187
+
29188
+ // src/utils/tenant-db-scope.ts
29189
+ init_runtime_tokens();
29190
+ import {
29191
+ resolveMultiTenancyConfig as resolveMultiTenancyConfig2,
29192
+ resolveTenantContext as resolveTenantContext2,
29193
+ TenantResolutionError as TenantResolutionError2
29194
+ } from "@agor/core/config";
29195
+ import {
29196
+ enqueueTenantDatabasePostCommitCallback,
29197
+ getCurrentTenantId as getCurrentTenantId2,
29198
+ runWithoutTenantDatabaseScope,
29199
+ runWithTenantDatabaseScope as runWithTenantDatabaseScope4
29200
+ } from "@agor/core/db";
29201
+ import { NotAuthenticated as NotAuthenticated9 } from "@agor/core/feathers";
29202
+ import jwt6 from "jsonwebtoken";
29203
+ function readHeaderValue(headers, name) {
29204
+ if (!headers) return null;
29205
+ const wanted = name.toLowerCase();
29206
+ for (const [key, value] of Object.entries(headers)) {
29207
+ if (key.toLowerCase() !== wanted) continue;
29208
+ const raw = Array.isArray(value) ? value[0] : value;
29209
+ return typeof raw === "string" && raw.trim() ? raw.trim() : null;
29210
+ }
29211
+ return null;
29212
+ }
29213
+ function resolveTenantIdForDeferredScope(params) {
29214
+ const scopedParams = params;
29215
+ return scopedParams?.tenant?.tenant_id ?? getCurrentTenantId2();
29216
+ }
29217
+ function deferWithTenantDatabaseScope(db, params, work, onError) {
29218
+ const tenantId = resolveTenantIdForDeferredScope(params);
29219
+ if (!tenantId) {
29220
+ const error51 = new Error("Missing tenant context for deferred tenant-scoped work");
29221
+ if (onError) {
29222
+ onError(error51);
29223
+ } else {
29224
+ console.error("[tenant-db-scope] Deferred tenant-scoped work skipped:", error51);
29225
+ }
29226
+ return;
29227
+ }
29228
+ const schedule = () => {
29229
+ runWithoutTenantDatabaseScope(() => {
29230
+ setImmediate(() => {
29231
+ void runWithTenantDatabaseScope4(db, tenantId, work).catch((error51) => {
29232
+ if (onError) {
29233
+ onError(error51);
29234
+ return;
29235
+ }
29236
+ console.error("[tenant-db-scope] Deferred tenant-scoped work failed:", error51);
29237
+ });
29238
+ });
29239
+ });
29240
+ };
29241
+ if (enqueueTenantDatabasePostCommitCallback(async () => schedule())) {
29242
+ return;
29243
+ }
29244
+ schedule();
29245
+ }
29246
+ function createTenantDatabaseScopeAroundHook(options) {
29247
+ const multiTenancy = resolveMultiTenancyConfig2(options.config);
29248
+ const bearerPayloadFromHeaders = (headers) => {
29249
+ const authorization = readHeaderValue(headers, "authorization");
29250
+ const match = authorization?.match(/^Bearer\s+(.+)$/i);
29251
+ if (!match || !options.jwtSecret) return void 0;
29252
+ try {
29253
+ return jwt6.verify(match[1], options.jwtSecret, {
29254
+ issuer: RUNTIME_JWT_ISSUER,
29255
+ audience: RUNTIME_JWT_AUDIENCE
29256
+ });
29257
+ } catch {
29258
+ return void 0;
29259
+ }
29260
+ };
29261
+ const resolveTenantForDatabaseScope = (context) => {
29262
+ const params = context.params;
29263
+ const connectionTenant = params.connection?.tenant ?? params.connection?.data?.tenant;
29264
+ const paramsWithConnectionTenant = connectionTenant && typeof connectionTenant === "object" && "tenant_id" in connectionTenant ? { ...params, tenant: params.tenant ?? connectionTenant } : params;
29265
+ try {
29266
+ return resolveTenantContext2(multiTenancy, {
29267
+ params: paramsWithConnectionTenant,
29268
+ authPayload: paramsWithConnectionTenant.authentication?.payload ?? bearerPayloadFromHeaders(paramsWithConnectionTenant.headers),
29269
+ headers: paramsWithConnectionTenant.headers
29270
+ });
29271
+ } catch (error51) {
29272
+ const inheritedTenantId = getCurrentTenantId2();
29273
+ if (error51 instanceof TenantResolutionError2 && inheritedTenantId) {
29274
+ return { tenant_id: inheritedTenantId, source: "explicit" };
29275
+ }
29276
+ throw error51;
29277
+ }
29278
+ };
29279
+ return async (context, next) => {
29280
+ try {
29281
+ context.params.tenant = resolveTenantForDatabaseScope(context);
29282
+ } catch (error51) {
29283
+ if (error51 instanceof TenantResolutionError2) {
29284
+ throw new NotAuthenticated9(error51.message);
29285
+ }
29286
+ throw error51;
29287
+ }
29288
+ await runWithTenantDatabaseScope4(options.db, context.params.tenant?.tenant_id, next);
29289
+ };
29290
+ }
29291
+
29292
+ // src/utils/session-queue-tenant-scope.ts
29293
+ function staticTenantId(config2) {
29294
+ const multiTenancy = resolveMultiTenancyConfig3(config2);
29295
+ return multiTenancy.mode === "static" ? multiTenancy.static_tenant_id : void 0;
29296
+ }
29297
+ function trustedTenantIdHint(options) {
29298
+ const hint = options.tenantIdHint?.trim();
29299
+ return hint || void 0;
29300
+ }
29301
+ function queueTenantParams(params, tenantId, source = "explicit") {
29302
+ const currentTenant = params?.tenant;
29303
+ return {
29304
+ ...params ?? {},
29305
+ tenant: {
29306
+ ...currentTenant,
29307
+ tenant_id: tenantId,
29308
+ source: currentTenant?.source ?? source
29309
+ }
29310
+ };
29311
+ }
29312
+ async function runWithSessionQueueTenantScope(options, work) {
29313
+ const capturedTenantId = resolveTenantIdForDeferredScope(options.params);
29314
+ if (capturedTenantId) {
29315
+ const scopedParams2 = queueTenantParams(options.params, capturedTenantId, "explicit");
29316
+ return runWithTenantDatabaseScope5(options.db, capturedTenantId, () => work(scopedParams2));
29317
+ }
29318
+ const tenantIdHint = trustedTenantIdHint(options);
29319
+ if (tenantIdHint) {
29320
+ const scopedParams2 = queueTenantParams(options.params, tenantIdHint, "explicit");
29321
+ return runWithTenantDatabaseScope5(options.db, tenantIdHint, () => work(scopedParams2));
29322
+ }
29323
+ const configuredStaticTenantId = staticTenantId(options.config);
29324
+ if (!configuredStaticTenantId) {
29325
+ console.error(
29326
+ `\u274C [Queue] ${options.label} skipped for session ${options.sessionId}: missing tenant context`
29327
+ );
29328
+ return void 0;
29329
+ }
29330
+ const scopedParams = queueTenantParams(options.params, configuredStaticTenantId, "static");
29331
+ return runWithTenantDatabaseScope5(options.db, configuredStaticTenantId, () => work(scopedParams));
29332
+ }
29333
+ function deferWithSessionQueueTenantScope(options, work, onError) {
29334
+ const handleError = (error51) => {
29335
+ if (onError) {
29336
+ onError(error51);
29337
+ return;
29338
+ }
29339
+ console.error(`\u274C [Queue] ${options.label} failed:`, error51);
29340
+ };
29341
+ const capturedTenantId = resolveTenantIdForDeferredScope(options.params);
29342
+ if (capturedTenantId) {
29343
+ const scopedParams2 = queueTenantParams(options.params, capturedTenantId, "explicit");
29344
+ deferWithTenantDatabaseScope(options.db, scopedParams2, () => work(scopedParams2), handleError);
29345
+ return;
29346
+ }
29347
+ const tenantIdHint = trustedTenantIdHint(options);
29348
+ if (tenantIdHint) {
29349
+ const scopedParams2 = queueTenantParams(options.params, tenantIdHint, "explicit");
29350
+ deferWithTenantDatabaseScope(options.db, scopedParams2, () => work(scopedParams2), handleError);
29351
+ return;
29352
+ }
29353
+ const configuredStaticTenantId = staticTenantId(options.config);
29354
+ if (!configuredStaticTenantId) {
29355
+ handleError(
29356
+ new Error(`${options.label} skipped for session ${options.sessionId}: missing tenant context`)
29357
+ );
29358
+ return;
29359
+ }
29360
+ const scopedParams = queueTenantParams(options.params, configuredStaticTenantId, "static");
29361
+ deferWithTenantDatabaseScope(options.db, scopedParams, () => work(scopedParams), handleError);
29362
+ }
29363
+
28829
29364
  // src/utils/session-stop.ts
28830
29365
  init_session_tasks();
28831
29366
  import { shortId as shortId6 } from "@agor/core/db";
@@ -28981,110 +29516,6 @@ function normalizeMessageSource(input, params) {
28981
29516
  return input;
28982
29517
  }
28983
29518
 
28984
- // src/utils/tenant-db-scope.ts
28985
- init_runtime_tokens();
28986
- import {
28987
- resolveMultiTenancyConfig as resolveMultiTenancyConfig2,
28988
- resolveTenantContext as resolveTenantContext2,
28989
- TenantResolutionError as TenantResolutionError2
28990
- } from "@agor/core/config";
28991
- import {
28992
- enqueueTenantDatabasePostCommitCallback,
28993
- getCurrentTenantId as getCurrentTenantId2,
28994
- runWithoutTenantDatabaseScope,
28995
- runWithTenantDatabaseScope as runWithTenantDatabaseScope3
28996
- } from "@agor/core/db";
28997
- import { NotAuthenticated as NotAuthenticated9 } from "@agor/core/feathers";
28998
- import jwt5 from "jsonwebtoken";
28999
- function readHeaderValue(headers, name) {
29000
- if (!headers) return null;
29001
- const wanted = name.toLowerCase();
29002
- for (const [key, value] of Object.entries(headers)) {
29003
- if (key.toLowerCase() !== wanted) continue;
29004
- const raw = Array.isArray(value) ? value[0] : value;
29005
- return typeof raw === "string" && raw.trim() ? raw.trim() : null;
29006
- }
29007
- return null;
29008
- }
29009
- function resolveTenantIdForDeferredScope(params) {
29010
- const scopedParams = params;
29011
- return scopedParams?.tenant?.tenant_id ?? getCurrentTenantId2();
29012
- }
29013
- function deferWithTenantDatabaseScope(db, params, work, onError) {
29014
- const tenantId = resolveTenantIdForDeferredScope(params);
29015
- if (!tenantId) {
29016
- const error51 = new Error("Missing tenant context for deferred tenant-scoped work");
29017
- if (onError) {
29018
- onError(error51);
29019
- } else {
29020
- console.error("[tenant-db-scope] Deferred tenant-scoped work skipped:", error51);
29021
- }
29022
- return;
29023
- }
29024
- const schedule = () => {
29025
- runWithoutTenantDatabaseScope(() => {
29026
- setImmediate(() => {
29027
- void runWithTenantDatabaseScope3(db, tenantId, work).catch((error51) => {
29028
- if (onError) {
29029
- onError(error51);
29030
- return;
29031
- }
29032
- console.error("[tenant-db-scope] Deferred tenant-scoped work failed:", error51);
29033
- });
29034
- });
29035
- });
29036
- };
29037
- if (enqueueTenantDatabasePostCommitCallback(async () => schedule())) {
29038
- return;
29039
- }
29040
- schedule();
29041
- }
29042
- function createTenantDatabaseScopeAroundHook(options) {
29043
- const multiTenancy = resolveMultiTenancyConfig2(options.config);
29044
- const bearerPayloadFromHeaders = (headers) => {
29045
- const authorization = readHeaderValue(headers, "authorization");
29046
- const match = authorization?.match(/^Bearer\s+(.+)$/i);
29047
- if (!match || !options.jwtSecret) return void 0;
29048
- try {
29049
- return jwt5.verify(match[1], options.jwtSecret, {
29050
- issuer: RUNTIME_JWT_ISSUER,
29051
- audience: RUNTIME_JWT_AUDIENCE
29052
- });
29053
- } catch {
29054
- return void 0;
29055
- }
29056
- };
29057
- const resolveTenantForDatabaseScope = (context) => {
29058
- const params = context.params;
29059
- const connectionTenant = params.connection?.tenant ?? params.connection?.data?.tenant;
29060
- const paramsWithConnectionTenant = connectionTenant && typeof connectionTenant === "object" && "tenant_id" in connectionTenant ? { ...params, tenant: params.tenant ?? connectionTenant } : params;
29061
- try {
29062
- return resolveTenantContext2(multiTenancy, {
29063
- params: paramsWithConnectionTenant,
29064
- authPayload: paramsWithConnectionTenant.authentication?.payload ?? bearerPayloadFromHeaders(paramsWithConnectionTenant.headers),
29065
- headers: paramsWithConnectionTenant.headers
29066
- });
29067
- } catch (error51) {
29068
- const inheritedTenantId = getCurrentTenantId2();
29069
- if (error51 instanceof TenantResolutionError2 && inheritedTenantId) {
29070
- return { tenant_id: inheritedTenantId, source: "explicit" };
29071
- }
29072
- throw error51;
29073
- }
29074
- };
29075
- return async (context, next) => {
29076
- try {
29077
- context.params.tenant = resolveTenantForDatabaseScope(context);
29078
- } catch (error51) {
29079
- if (error51 instanceof TenantResolutionError2) {
29080
- throw new NotAuthenticated9(error51.message);
29081
- }
29082
- throw error51;
29083
- }
29084
- await runWithTenantDatabaseScope3(options.db, context.params.tenant?.tenant_id, next);
29085
- };
29086
- }
29087
-
29088
29519
  // src/utils/upload.ts
29089
29520
  import fs from "fs/promises";
29090
29521
  import path from "path";
@@ -29307,6 +29738,14 @@ async function doResolveWidget(widgetId, action, caller, deps) {
29307
29738
  const entry = getWidget(widget.widget_type);
29308
29739
  let resultMeta;
29309
29740
  let autoResumePrompt;
29741
+ const ctx = {
29742
+ // biome-ignore lint/suspicious/noExplicitAny: Pass-through Feathers Application
29743
+ app: deps.app,
29744
+ sessionId: message.session_id,
29745
+ submitterUserId: caller.user_id,
29746
+ submitterRole: caller.role,
29747
+ sessionCreatorUserId: session.created_by
29748
+ };
29310
29749
  if (action.kind === "submit") {
29311
29750
  if (!entry) {
29312
29751
  throw new NotFound3(
@@ -29318,18 +29757,13 @@ async function doResolveWidget(widgetId, action, caller, deps) {
29318
29757
  throw new Forbidden9(`Invalid submit payload: ${parsed.error.message}`);
29319
29758
  }
29320
29759
  const submit = parsed.data;
29321
- const submitCtx = {
29322
- // biome-ignore lint/suspicious/noExplicitAny: Pass-through Feathers Application
29323
- app: deps.app,
29324
- sessionId: message.session_id,
29325
- submitterUserId: caller.user_id,
29326
- submitterRole: caller.role,
29327
- sessionCreatorUserId: session.created_by
29328
- };
29329
- await entry.applySubmit(submitCtx, submit, widget.params);
29760
+ await entry.applySubmit(ctx, submit, widget.params);
29330
29761
  resultMeta = entry.buildResultMeta(submit);
29331
29762
  autoResumePrompt = entry.buildAutoResumePrompt(resultMeta, widget.params);
29332
29763
  } else {
29764
+ if (entry?.authorizeDismiss) {
29765
+ await entry.authorizeDismiss(ctx, widget.params);
29766
+ }
29333
29767
  autoResumePrompt = entry ? entry.buildDismissedPrompt(widget.params) : `[Agor] User dismissed a widget request. Do not re-request immediately \u2014 ask whether to proceed without, or move on to other work.`;
29334
29768
  }
29335
29769
  const newStatus = action.kind === "submit" ? "submitted" : "dismissed";
@@ -29462,7 +29896,7 @@ async function registerRoutes(ctx) {
29462
29896
  const appRecord = app;
29463
29897
  const sessionTokenService = appRecord.sessionTokenService;
29464
29898
  const authStrategiesArray = ["api-key", "jwt", "local"];
29465
- const multiTenancy = resolveMultiTenancyConfig4(config2);
29899
+ const multiTenancy = resolveMultiTenancyConfig5(config2);
29466
29900
  const tenantTokenClaim = multiTenancy.auth_claim ?? "tenant_id";
29467
29901
  if (sessionTokenService) {
29468
29902
  authStrategiesArray.push("session-token");
@@ -29527,32 +29961,13 @@ async function registerRoutes(ctx) {
29527
29961
  authService.hooks({
29528
29962
  after: {
29529
29963
  create: [
29530
- // biome-ignore lint/suspicious/noExplicitAny: FeathersJS context type not fully typed
29531
- async (context) => {
29532
- authEventDebug("\u2705 Authentication succeeded:", {
29533
- strategy: context.result?.authentication?.strategy,
29534
- hasUser: !!context.result?.user,
29535
- user_id: context.result?.user?.user_id,
29536
- hasAccessToken: !!context.result?.accessToken
29537
- });
29538
- if (context.result?.user) {
29539
- const tenantId = context.params?.tenant?.tenant_id ?? context.result.user.tenant_id;
29540
- const tokens = issueRuntimeTokenPair(
29541
- context.result.user,
29542
- jwtSecret,
29543
- ACCESS_TOKEN_TTL,
29544
- REFRESH_TOKEN_TTL,
29545
- {
29546
- ...authTokenIssuedAtClaim(Date.now(), context.result.user),
29547
- ...runtimeTenantClaims(tenantId, tenantTokenClaim)
29548
- }
29549
- );
29550
- context.result.accessToken = tokens.accessToken;
29551
- context.result.refreshToken = tokens.refreshToken;
29552
- context.result.user = redactUserAuthMetadata(context.result.user);
29553
- }
29554
- return context;
29555
- }
29964
+ createIssueBrowserTokensHook({
29965
+ jwtSecret,
29966
+ accessTokenTtl: ACCESS_TOKEN_TTL,
29967
+ refreshTokenTtl: REFRESH_TOKEN_TTL,
29968
+ tenantClaim: tenantTokenClaim,
29969
+ debug: authEventDebug
29970
+ })
29556
29971
  ]
29557
29972
  }
29558
29973
  });
@@ -29596,12 +30011,12 @@ async function registerRoutes(ctx) {
29596
30011
  throw new NotAuthenticated12("Authentication required");
29597
30012
  }
29598
30013
  const caller = authParams.user;
29599
- if (!hasMinimumRole9(caller.role, ROLES11.SUPERADMIN)) {
29600
- throw new Forbidden10("Superadmin role required for impersonation");
30014
+ if (!hasMinimumRole11(caller.role, ROLES13.SUPERADMIN)) {
30015
+ throw new Forbidden11("Superadmin role required for impersonation");
29601
30016
  }
29602
30017
  const authPayload = authParams.authentication?.payload;
29603
30018
  if (authPayload?.is_impersonated === true) {
29604
- throw new Forbidden10("Cannot impersonate from an already-impersonated token");
30019
+ throw new Forbidden11("Cannot impersonate from an already-impersonated token");
29605
30020
  }
29606
30021
  if (!data?.user_id) {
29607
30022
  throw new BadRequest5("user_id is required");
@@ -29682,7 +30097,7 @@ async function registerRoutes(ctx) {
29682
30097
  }
29683
30098
  },
29684
30099
  {
29685
- create: { role: ROLES11.MEMBER, action: "create messages" }
30100
+ create: { role: ROLES13.MEMBER, action: "create messages" }
29686
30101
  },
29687
30102
  requireAuth
29688
30103
  );
@@ -29704,7 +30119,7 @@ async function registerRoutes(ctx) {
29704
30119
  }
29705
30120
  },
29706
30121
  {
29707
- create: { role: ROLES11.MEMBER, action: "broadcast streaming events" }
30122
+ create: { role: ROLES13.MEMBER, action: "broadcast streaming events" }
29708
30123
  },
29709
30124
  requireAuth
29710
30125
  );
@@ -29732,10 +30147,12 @@ async function registerRoutes(ctx) {
29732
30147
  }
29733
30148
  },
29734
30149
  {
29735
- create: { role: ROLES11.MEMBER, action: "broadcast task streaming events" }
30150
+ create: { role: ROLES13.MEMBER, action: "broadcast task streaming events" }
29736
30151
  },
29737
30152
  requireAuth
29738
30153
  );
30154
+ app.service("/messages/streaming").publish(() => []);
30155
+ app.service("/tasks/streaming").publish(() => []);
29739
30156
  registerAuthenticatedRoute2(
29740
30157
  app,
29741
30158
  "/sessions/:id/fork",
@@ -29754,7 +30171,7 @@ async function registerRoutes(ctx) {
29754
30171
  }
29755
30172
  },
29756
30173
  {
29757
- create: { role: ROLES11.MEMBER, action: "fork sessions" }
30174
+ create: { role: ROLES13.MEMBER, action: "fork sessions" }
29758
30175
  },
29759
30176
  requireAuth
29760
30177
  );
@@ -29776,7 +30193,7 @@ async function registerRoutes(ctx) {
29776
30193
  }
29777
30194
  },
29778
30195
  {
29779
- create: { role: ROLES11.MEMBER, action: "spawn sessions" }
30196
+ create: { role: ROLES13.MEMBER, action: "spawn sessions" }
29780
30197
  },
29781
30198
  requireAuth
29782
30199
  );
@@ -29792,7 +30209,7 @@ async function registerRoutes(ctx) {
29792
30209
  // biome-ignore lint/suspicious/noExplicitAny: FeathersJS route handler type mismatch with Express RouteParams
29793
30210
  },
29794
30211
  {
29795
- find: { role: ROLES11.MEMBER, action: "view session genealogy" }
30212
+ find: { role: ROLES13.MEMBER, action: "view session genealogy" }
29796
30213
  },
29797
30214
  requireAuth
29798
30215
  );
@@ -29816,7 +30233,7 @@ async function registerRoutes(ctx) {
29816
30233
  callerRole: params.user?.role,
29817
30234
  sessionCreatedBy: session.created_by
29818
30235
  })) {
29819
- throw new Forbidden10("You can only restart Claude CLI sessions you created.");
30236
+ throw new Forbidden11("You can only restart Claude CLI sessions you created.");
29820
30237
  }
29821
30238
  const tabName = `cli-${shortId14(session.session_id)}`;
29822
30239
  const channel = `user/${targetUserId}/terminal`;
@@ -29867,7 +30284,7 @@ async function registerRoutes(ctx) {
29867
30284
  // biome-ignore lint/suspicious/noExplicitAny: FeathersJS route handler type mismatch
29868
30285
  },
29869
30286
  {
29870
- create: { role: ROLES11.MEMBER, action: "restart claude CLI session" }
30287
+ create: { role: ROLES13.MEMBER, action: "restart claude CLI session" }
29871
30288
  },
29872
30289
  requireAuth
29873
30290
  );
@@ -30213,7 +30630,7 @@ ${errorMessage}`;
30213
30630
  }
30214
30631
  },
30215
30632
  {
30216
- create: { role: ROLES11.MEMBER, action: "execute prompts" }
30633
+ create: { role: ROLES13.MEMBER, action: "execute prompts" }
30217
30634
  },
30218
30635
  requireAuth
30219
30636
  );
@@ -30243,7 +30660,7 @@ ${errorMessage}`;
30243
30660
  } else {
30244
30661
  const userId = params.user?.user_id;
30245
30662
  if (!userId) {
30246
- throw new Forbidden10("Authentication required to run tasks");
30663
+ throw new Forbidden11("Authentication required to run tasks");
30247
30664
  }
30248
30665
  const wt = await branchRepository.findById(session.branch_id);
30249
30666
  if (!wt) {
@@ -30261,7 +30678,7 @@ ${errorMessage}`;
30261
30678
  );
30262
30679
  const canRun = PERMISSION_RANK[effectiveLevel] >= PERMISSION_RANK.prompt || effectiveLevel === "session" && session.created_by === userId;
30263
30680
  if (!canRun) {
30264
- throw new Forbidden10(
30681
+ throw new Forbidden11(
30265
30682
  `You have '${effectiveLevel}' permission on this branch, which does not allow running tasks. Need 'prompt' or 'all' (or 'session' for own sessions).`
30266
30683
  );
30267
30684
  }
@@ -30304,7 +30721,7 @@ ${errorMessage}`;
30304
30721
  }
30305
30722
  },
30306
30723
  {
30307
- create: { role: ROLES11.MEMBER, action: "execute prompts" }
30724
+ create: { role: ROLES13.MEMBER, action: "execute prompts" }
30308
30725
  },
30309
30726
  requireAuth
30310
30727
  );
@@ -30331,7 +30748,7 @@ ${errorMessage}`;
30331
30748
  }
30332
30749
  },
30333
30750
  {
30334
- create: { role: ROLES11.MEMBER, action: "send spawn-subsession prompts" }
30751
+ create: { role: ROLES13.MEMBER, action: "send spawn-subsession prompts" }
30335
30752
  },
30336
30753
  requireAuth
30337
30754
  );
@@ -30380,7 +30797,7 @@ ${errorMessage}`;
30380
30797
  }
30381
30798
  },
30382
30799
  {
30383
- create: { role: ROLES11.MEMBER, action: "fire zone triggers" }
30800
+ create: { role: ROLES13.MEMBER, action: "fire zone triggers" }
30384
30801
  },
30385
30802
  requireAuth
30386
30803
  );
@@ -30391,7 +30808,7 @@ ${errorMessage}`;
30391
30808
  try {
30392
30809
  const { sessionId } = req.params;
30393
30810
  const params = req.feathers;
30394
- ensureMinimumRole(params, ROLES11.MEMBER, "upload files");
30811
+ ensureMinimumRole(params, ROLES13.MEMBER, "upload files");
30395
30812
  const session = await sessionsService.get(sessionId, params);
30396
30813
  if (!session) {
30397
30814
  console.error(`\u274C [Upload Authz] Session not found: ${shortId14(sessionId)}`);
@@ -30635,7 +31052,7 @@ ${errorMessage}`;
30635
31052
  }
30636
31053
  },
30637
31054
  {
30638
- create: { role: ROLES11.MEMBER, action: "stop sessions" }
31055
+ create: { role: ROLES13.MEMBER, action: "stop sessions" }
30639
31056
  },
30640
31057
  requireAuth
30641
31058
  );
@@ -30656,12 +31073,24 @@ ${errorMessage}`;
30656
31073
  // biome-ignore lint/suspicious/noExplicitAny: Service type not compatible with Express
30657
31074
  },
30658
31075
  {
30659
- find: { role: ROLES11.MEMBER, action: "view queue" }
31076
+ find: { role: ROLES13.MEMBER, action: "view queue" }
30660
31077
  },
30661
31078
  requireAuth
30662
31079
  );
30663
31080
  const queueRetryScheduled = /* @__PURE__ */ new Set();
30664
31081
  async function processNextQueuedTask(sessionId, params) {
31082
+ await runWithSessionQueueTenantScope(
31083
+ {
31084
+ db,
31085
+ config: config2,
31086
+ sessionId,
31087
+ params,
31088
+ label: "processNextQueuedTask"
31089
+ },
31090
+ async (scopedParams) => processNextQueuedTaskInTenantScope(sessionId, scopedParams)
31091
+ );
31092
+ }
31093
+ async function processNextQueuedTaskInTenantScope(sessionId, params) {
30665
31094
  const existingLock = sessionTurnLocks.get(sessionId);
30666
31095
  if (existingLock) {
30667
31096
  console.log(`\u23F3 [Queue] Session turn in progress for ${shortId14(sessionId)}, waiting...`);
@@ -30680,14 +31109,27 @@ ${errorMessage}`;
30680
31109
  }
30681
31110
  if (!queueRetryScheduled.has(sessionId)) {
30682
31111
  queueRetryScheduled.add(sessionId);
30683
- deferInFreshTenantScope(params, async () => {
30684
- queueRetryScheduled.delete(sessionId);
30685
- try {
30686
- await processNextQueuedTask(sessionId, params);
30687
- } catch (error51) {
31112
+ deferWithSessionQueueTenantScope(
31113
+ {
31114
+ db,
31115
+ config: config2,
31116
+ sessionId,
31117
+ params,
31118
+ label: "processNextQueuedTask retry"
31119
+ },
31120
+ async (retryParams) => {
31121
+ queueRetryScheduled.delete(sessionId);
31122
+ try {
31123
+ await processNextQueuedTask(sessionId, retryParams);
31124
+ } catch (error51) {
31125
+ console.error(`\u274C [Queue] Retry failed for session ${shortId14(sessionId)}:`, error51);
31126
+ }
31127
+ },
31128
+ (error51) => {
31129
+ queueRetryScheduled.delete(sessionId);
30688
31130
  console.error(`\u274C [Queue] Retry failed for session ${shortId14(sessionId)}:`, error51);
30689
31131
  }
30690
- });
31132
+ );
30691
31133
  } else {
30692
31134
  console.log(
30693
31135
  `\u23ED\uFE0F [Queue] Retry already scheduled for session ${shortId14(sessionId)}, not queueing another`
@@ -30842,7 +31284,7 @@ ${errorMessage}`;
30842
31284
  }
30843
31285
  },
30844
31286
  {
30845
- create: { role: ROLES11.MEMBER, action: "respond to permission requests" }
31287
+ create: { role: ROLES13.MEMBER, action: "respond to permission requests" }
30846
31288
  },
30847
31289
  requireAuth
30848
31290
  );
@@ -30871,7 +31313,7 @@ ${errorMessage}`;
30871
31313
  }
30872
31314
  },
30873
31315
  {
30874
- create: { role: ROLES11.MEMBER, action: "submit widgets" }
31316
+ create: { role: ROLES13.MEMBER, action: "submit widgets" }
30875
31317
  },
30876
31318
  requireAuth
30877
31319
  );
@@ -30894,7 +31336,7 @@ ${errorMessage}`;
30894
31336
  }
30895
31337
  },
30896
31338
  {
30897
- create: { role: ROLES11.MEMBER, action: "dismiss widgets" }
31339
+ create: { role: ROLES13.MEMBER, action: "dismiss widgets" }
30898
31340
  },
30899
31341
  requireAuth
30900
31342
  );
@@ -30907,7 +31349,7 @@ ${errorMessage}`;
30907
31349
  }
30908
31350
  },
30909
31351
  {
30910
- create: { role: ROLES11.MEMBER, action: "create tasks" }
31352
+ create: { role: ROLES13.MEMBER, action: "create tasks" }
30911
31353
  },
30912
31354
  requireAuth
30913
31355
  );
@@ -30922,7 +31364,7 @@ ${errorMessage}`;
30922
31364
  }
30923
31365
  },
30924
31366
  {
30925
- create: { role: ROLES11.MEMBER, action: "complete tasks" }
31367
+ create: { role: ROLES13.MEMBER, action: "complete tasks" }
30926
31368
  },
30927
31369
  requireAuth
30928
31370
  );
@@ -30937,7 +31379,7 @@ ${errorMessage}`;
30937
31379
  }
30938
31380
  },
30939
31381
  {
30940
- create: { role: ROLES11.MEMBER, action: "fail tasks" }
31382
+ create: { role: ROLES13.MEMBER, action: "fail tasks" }
30941
31383
  },
30942
31384
  requireAuth
30943
31385
  );
@@ -30950,7 +31392,7 @@ ${errorMessage}`;
30950
31392
  }
30951
31393
  },
30952
31394
  {
30953
- create: { role: ROLES11.MEMBER, action: "add local repositories" }
31395
+ create: { role: ROLES13.MEMBER, action: "add local repositories" }
30954
31396
  },
30955
31397
  requireAuth
30956
31398
  );
@@ -30963,7 +31405,7 @@ ${errorMessage}`;
30963
31405
  }
30964
31406
  },
30965
31407
  {
30966
- create: { role: ROLES11.MEMBER, action: "clone repositories" }
31408
+ create: { role: ROLES13.MEMBER, action: "clone repositories" }
30967
31409
  },
30968
31410
  requireAuth
30969
31411
  );
@@ -30982,7 +31424,7 @@ ${errorMessage}`;
30982
31424
  }
30983
31425
  },
30984
31426
  {
30985
- create: { role: ROLES11.MEMBER, action: "create branches" }
31427
+ create: { role: ROLES13.MEMBER, action: "create branches" }
30986
31428
  },
30987
31429
  requireAuth
30988
31430
  );
@@ -30999,7 +31441,7 @@ ${errorMessage}`;
30999
31441
  }
31000
31442
  },
31001
31443
  {
31002
- remove: { role: ROLES11.MEMBER, action: "remove branches" }
31444
+ remove: { role: ROLES13.MEMBER, action: "remove branches" }
31003
31445
  },
31004
31446
  requireAuth
31005
31447
  );
@@ -31015,7 +31457,7 @@ ${errorMessage}`;
31015
31457
  }
31016
31458
  },
31017
31459
  {
31018
- create: { role: ROLES11.ADMIN, action: "import environment config from .agor.yml" }
31460
+ create: { role: ROLES13.ADMIN, action: "import environment config from .agor.yml" }
31019
31461
  },
31020
31462
  requireAuth
31021
31463
  );
@@ -31034,7 +31476,7 @@ ${errorMessage}`;
31034
31476
  // Admin-only, matching Import and repo.environment edit. Export writes a
31035
31477
  // file to the branch working tree, so even though the content is
31036
31478
  // derivable, the side effect warrants the same permission bar as import.
31037
- create: { role: ROLES11.ADMIN, action: "export .agor.yml" }
31479
+ create: { role: ROLES13.ADMIN, action: "export .agor.yml" }
31038
31480
  },
31039
31481
  requireAuth
31040
31482
  );
@@ -31059,10 +31501,10 @@ ${errorMessage}`;
31059
31501
  }
31060
31502
  },
31061
31503
  {
31062
- find: { role: ROLES11.MEMBER, action: "list API keys" },
31063
- create: { role: ROLES11.MEMBER, action: "create API keys" },
31064
- patch: { role: ROLES11.MEMBER, action: "update API keys" },
31065
- remove: { role: ROLES11.MEMBER, action: "delete API keys" }
31504
+ find: { role: ROLES13.MEMBER, action: "list API keys" },
31505
+ create: { role: ROLES13.MEMBER, action: "create API keys" },
31506
+ patch: { role: ROLES13.MEMBER, action: "update API keys" },
31507
+ remove: { role: ROLES13.MEMBER, action: "delete API keys" }
31066
31508
  },
31067
31509
  requireAuth
31068
31510
  );
@@ -31083,7 +31525,7 @@ ${errorMessage}`;
31083
31525
  }
31084
31526
  },
31085
31527
  {
31086
- create: { role: ROLES11.MEMBER, action: "react to board comments" }
31528
+ create: { role: ROLES13.MEMBER, action: "react to board comments" }
31087
31529
  },
31088
31530
  requireAuth
31089
31531
  );
@@ -31105,7 +31547,7 @@ ${errorMessage}`;
31105
31547
  }
31106
31548
  },
31107
31549
  {
31108
- create: { role: ROLES11.MEMBER, action: "reply to board comments" }
31550
+ create: { role: ROLES13.MEMBER, action: "reply to board comments" }
31109
31551
  },
31110
31552
  requireAuth
31111
31553
  );
@@ -31124,7 +31566,7 @@ ${errorMessage}`;
31124
31566
  // Branch `all`/admin control is enforced at the service layer. This
31125
31567
  // route-level gate is just "authenticated" so the service remains
31126
31568
  // the single source of truth across REST, WebSocket, and MCP.
31127
- create: { role: ROLES11.VIEWER, action: "start branch environments" }
31569
+ create: { role: ROLES13.VIEWER, action: "start branch environments" }
31128
31570
  },
31129
31571
  requireAuth
31130
31572
  );
@@ -31140,7 +31582,7 @@ ${errorMessage}`;
31140
31582
  },
31141
31583
  {
31142
31584
  // Branch `all`/admin control is enforced at the service layer.
31143
- create: { role: ROLES11.VIEWER, action: "stop branch environments" }
31585
+ create: { role: ROLES13.VIEWER, action: "stop branch environments" }
31144
31586
  },
31145
31587
  requireAuth
31146
31588
  );
@@ -31159,7 +31601,7 @@ ${errorMessage}`;
31159
31601
  },
31160
31602
  {
31161
31603
  // Branch `all`/admin control is enforced at the service layer.
31162
- create: { role: ROLES11.VIEWER, action: "restart branch environments" }
31604
+ create: { role: ROLES13.VIEWER, action: "restart branch environments" }
31163
31605
  },
31164
31606
  requireAuth
31165
31607
  );
@@ -31175,7 +31617,7 @@ ${errorMessage}`;
31175
31617
  },
31176
31618
  {
31177
31619
  // Branch `all`/admin control is enforced at the service layer.
31178
- create: { role: ROLES11.VIEWER, action: "nuke branch environments" }
31620
+ create: { role: ROLES13.VIEWER, action: "nuke branch environments" }
31179
31621
  },
31180
31622
  requireAuth
31181
31623
  );
@@ -31195,7 +31637,7 @@ ${errorMessage}`;
31195
31637
  },
31196
31638
  {
31197
31639
  // Branch `all`/admin control is enforced at the service layer.
31198
- create: { role: ROLES11.VIEWER, action: "render branch environment" }
31640
+ create: { role: ROLES13.VIEWER, action: "render branch environment" }
31199
31641
  },
31200
31642
  requireAuth
31201
31643
  );
@@ -31211,7 +31653,7 @@ ${errorMessage}`;
31211
31653
  // biome-ignore lint/suspicious/noExplicitAny: Service type not compatible with Express
31212
31654
  },
31213
31655
  {
31214
- find: { role: ROLES11.VIEWER, action: "check branch health" }
31656
+ find: { role: ROLES13.VIEWER, action: "check branch health" }
31215
31657
  },
31216
31658
  requireAuth
31217
31659
  );
@@ -31231,13 +31673,13 @@ ${errorMessage}`;
31231
31673
  before: {
31232
31674
  create: [
31233
31675
  requireAuth,
31234
- requireMinimumRole(ROLES11.MEMBER, "archive or delete branches"),
31676
+ requireMinimumRole(ROLES13.MEMBER, "archive or delete branches"),
31235
31677
  async (context) => {
31236
31678
  const id = context.params.route?.id;
31237
31679
  if (!id) throw new Error("Branch ID required");
31238
31680
  const branch = await branchRepository.findById(id);
31239
31681
  if (!branch) {
31240
- throw new Forbidden10(`Branch not found: ${id}`);
31682
+ throw new Forbidden11(`Branch not found: ${id}`);
31241
31683
  }
31242
31684
  await cacheBranchAccess(context.params, branchRepository, branch);
31243
31685
  return context;
@@ -31245,8 +31687,8 @@ ${errorMessage}`;
31245
31687
  branchRbacEnabled ? ensureBranchPermission("all", "archive or delete branches", superadminOpts) : (context) => {
31246
31688
  const isOwner = context.params.isBranchOwner;
31247
31689
  const userRole = context.params.user?.role;
31248
- if (!isOwner && !hasMinimumRole9(userRole, ROLES11.ADMIN)) {
31249
- throw new Forbidden10(
31690
+ if (!isOwner && !hasMinimumRole11(userRole, ROLES13.ADMIN)) {
31691
+ throw new Forbidden11(
31250
31692
  "You must be the branch owner or a global admin to archive/delete branches"
31251
31693
  );
31252
31694
  }
@@ -31267,13 +31709,13 @@ ${errorMessage}`;
31267
31709
  before: {
31268
31710
  create: [
31269
31711
  requireAuth,
31270
- requireMinimumRole(ROLES11.MEMBER, "unarchive branches"),
31712
+ requireMinimumRole(ROLES13.MEMBER, "unarchive branches"),
31271
31713
  async (context) => {
31272
31714
  const id = context.params.route?.id;
31273
31715
  if (!id) throw new Error("Branch ID required");
31274
31716
  const branch = await branchRepository.findById(id);
31275
31717
  if (!branch) {
31276
- throw new Forbidden10(`Branch not found: ${id}`);
31718
+ throw new Forbidden11(`Branch not found: ${id}`);
31277
31719
  }
31278
31720
  await cacheBranchAccess(context.params, branchRepository, branch);
31279
31721
  return context;
@@ -31281,8 +31723,8 @@ ${errorMessage}`;
31281
31723
  branchRbacEnabled ? ensureBranchPermission("all", "unarchive branches", superadminOpts) : (context) => {
31282
31724
  const isOwner = context.params.isBranchOwner;
31283
31725
  const userRole = context.params.user?.role;
31284
- if (!isOwner && !hasMinimumRole9(userRole, ROLES11.ADMIN)) {
31285
- throw new Forbidden10(
31726
+ if (!isOwner && !hasMinimumRole11(userRole, ROLES13.ADMIN)) {
31727
+ throw new Forbidden11(
31286
31728
  "You must be the branch owner or a global admin to unarchive branches"
31287
31729
  );
31288
31730
  }
@@ -31332,7 +31774,7 @@ ${errorMessage}`;
31332
31774
  before: {
31333
31775
  create: [
31334
31776
  requireAuth,
31335
- requireMinimumRole(ROLES11.MEMBER, "run schedule"),
31777
+ requireMinimumRole(ROLES13.MEMBER, "run schedule"),
31336
31778
  // Reuse the canonical hook so caching semantics (params.schedule
31337
31779
  // / params.branch / params.isBranchOwner) match every other
31338
31780
  // schedule-touching path.
@@ -31341,8 +31783,8 @@ ${errorMessage}`;
31341
31783
  branchRbacEnabled ? ensureBranchPermission("all", "run schedule", superadminOpts) : (context) => {
31342
31784
  const isOwner = context.params.isBranchOwner;
31343
31785
  const userRole = context.params.user?.role;
31344
- if (!isOwner && !hasMinimumRole9(userRole, ROLES11.ADMIN)) {
31345
- throw new Forbidden10(
31786
+ if (!isOwner && !hasMinimumRole11(userRole, ROLES13.ADMIN)) {
31787
+ throw new Forbidden11(
31346
31788
  "You must be the branch owner or a global admin to run schedules"
31347
31789
  );
31348
31790
  }
@@ -31406,7 +31848,7 @@ ${errorMessage}`;
31406
31848
  before: {
31407
31849
  create: [
31408
31850
  requireAuth,
31409
- requireMinimumRole(ROLES11.MEMBER, "execute scheduled runs"),
31851
+ requireMinimumRole(ROLES13.MEMBER, "execute scheduled runs"),
31410
31852
  async (context) => {
31411
31853
  const id = context.params.route?.id;
31412
31854
  if (!id) throw new BadRequest5("Branch ID required");
@@ -31420,8 +31862,8 @@ ${errorMessage}`;
31420
31862
  branchRbacEnabled ? ensureBranchPermission("all", "execute scheduled runs", superadminOpts) : (context) => {
31421
31863
  const isOwner = context.params.isBranchOwner;
31422
31864
  const userRole = context.params.user?.role;
31423
- if (!isOwner && !hasMinimumRole9(userRole, ROLES11.ADMIN)) {
31424
- throw new Forbidden10(
31865
+ if (!isOwner && !hasMinimumRole11(userRole, ROLES13.ADMIN)) {
31866
+ throw new Forbidden11(
31425
31867
  "You must be the branch owner or a global admin to execute scheduled runs"
31426
31868
  );
31427
31869
  }
@@ -31445,7 +31887,7 @@ ${errorMessage}`;
31445
31887
  },
31446
31888
  {
31447
31889
  // Branch `all`/admin control is enforced at the service layer.
31448
- find: { role: ROLES11.VIEWER, action: "view branch logs" }
31890
+ find: { role: ROLES13.VIEWER, action: "view branch logs" }
31449
31891
  },
31450
31892
  requireAuth
31451
31893
  );
@@ -31462,7 +31904,7 @@ ${errorMessage}`;
31462
31904
  }
31463
31905
  },
31464
31906
  {
31465
- create: { role: ROLES11.MEMBER, action: "modify board sessions" }
31907
+ create: { role: ROLES13.MEMBER, action: "modify board sessions" }
31466
31908
  },
31467
31909
  requireAuth
31468
31910
  );
@@ -31492,7 +31934,15 @@ ${errorMessage}`;
31492
31934
  const includeGlobal = params.query?.includeGlobal === "true" || params.query?.includeGlobal === true;
31493
31935
  const includeMetadata = params.query?.includeMetadata === "true" || params.query?.includeMetadata === true;
31494
31936
  const mcpService = app.service("mcp-servers");
31495
- const userId = params.user?.user_id;
31937
+ const queryForUserId = typeof params.query?.forUserId === "string" ? params.query.forUserId : void 0;
31938
+ const authPayloadType = params.authentication?.payload?.type;
31939
+ const routeUser = params.user;
31940
+ const userId = resolveForUserIdWithGate({
31941
+ queryForUserId,
31942
+ isServiceAccount: routeUser?._isServiceAccount,
31943
+ authPayloadType,
31944
+ callerUserId: params.user?.user_id
31945
+ });
31496
31946
  const rawLookupParams = {
31497
31947
  ...params,
31498
31948
  provider: void 0,
@@ -31627,10 +32077,10 @@ ${errorMessage}`;
31627
32077
  // biome-ignore lint/suspicious/noExplicitAny: Service type not compatible with Express
31628
32078
  },
31629
32079
  {
31630
- find: { role: ROLES11.MEMBER, action: "view session MCP servers" },
31631
- create: { role: ROLES11.MEMBER, action: "modify session MCP servers" },
31632
- remove: { role: ROLES11.MEMBER, action: "modify session MCP servers" },
31633
- patch: { role: ROLES11.MEMBER, action: "modify session MCP servers" }
32080
+ find: { role: ROLES13.MEMBER, action: "view session MCP servers" },
32081
+ create: { role: ROLES13.MEMBER, action: "modify session MCP servers" },
32082
+ remove: { role: ROLES13.MEMBER, action: "modify session MCP servers" },
32083
+ patch: { role: ROLES13.MEMBER, action: "modify session MCP servers" }
31634
32084
  },
31635
32085
  requireAuth
31636
32086
  );
@@ -31719,10 +32169,10 @@ ${errorMessage}`;
31719
32169
  // biome-ignore lint/suspicious/noExplicitAny: Service type not compatible with Express
31720
32170
  },
31721
32171
  {
31722
- find: { role: ROLES11.MEMBER, action: "view session env selections" },
31723
- create: { role: ROLES11.MEMBER, action: "modify session env selections" },
31724
- remove: { role: ROLES11.MEMBER, action: "modify session env selections" },
31725
- patch: { role: ROLES11.MEMBER, action: "modify session env selections" }
32172
+ find: { role: ROLES13.MEMBER, action: "view session env selections" },
32173
+ create: { role: ROLES13.MEMBER, action: "modify session env selections" },
32174
+ remove: { role: ROLES13.MEMBER, action: "modify session env selections" },
32175
+ patch: { role: ROLES13.MEMBER, action: "modify session env selections" }
31726
32176
  },
31727
32177
  requireAuth
31728
32178
  );