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.
- package/dist/core/claude/index.cjs +51 -27
- package/dist/core/claude/index.js +51 -27
- package/dist/core/claude-cli/index.cjs +13 -0
- package/dist/core/claude-cli/index.js +13 -0
- package/dist/core/claude-cli/pricing.d.ts.map +1 -1
- package/dist/core/client/index.cjs +17 -0
- package/dist/core/client/index.js +16 -0
- package/dist/core/db/index.cjs +618 -421
- package/dist/core/db/index.js +550 -353
- package/dist/core/db/repositories/boards.d.ts +27 -0
- package/dist/core/db/repositories/boards.d.ts.map +1 -1
- package/dist/core/db/repositories/branches.d.ts +11 -1
- package/dist/core/db/repositories/branches.d.ts.map +1 -1
- package/dist/core/db/repositories/gateway-channels.d.ts +9 -0
- package/dist/core/db/repositories/gateway-channels.d.ts.map +1 -1
- package/dist/core/db/repositories/sessions.d.ts +7 -0
- package/dist/core/db/repositories/sessions.d.ts.map +1 -1
- package/dist/core/environment/render-snapshot.cjs +6 -2
- package/dist/core/environment/render-snapshot.d.ts +2 -0
- package/dist/core/environment/render-snapshot.d.ts.map +1 -1
- package/dist/core/environment/render-snapshot.js +6 -2
- package/dist/core/environment/variable-resolver.cjs +3 -1
- package/dist/core/environment/variable-resolver.js +3 -1
- package/dist/core/index.cjs +684 -486
- package/dist/core/index.js +684 -486
- package/dist/core/lib/feathers-validation.cjs +3 -0
- package/dist/core/lib/feathers-validation.d.ts +1 -0
- package/dist/core/lib/feathers-validation.d.ts.map +1 -1
- package/dist/core/lib/feathers-validation.js +3 -0
- package/dist/core/local-actions/index.cjs +123 -56
- package/dist/core/local-actions/index.js +121 -54
- package/dist/core/mcp/index.cjs +21 -3
- package/dist/core/mcp/index.d.ts +1 -1
- package/dist/core/mcp/index.d.ts.map +1 -1
- package/dist/core/mcp/index.js +18 -3
- package/dist/core/mcp/template-patterns.d.ts +15 -0
- package/dist/core/mcp/template-patterns.d.ts.map +1 -0
- package/dist/core/mcp/template-resolver.d.ts +13 -0
- package/dist/core/mcp/template-resolver.d.ts.map +1 -1
- package/dist/core/models/browser.cjs +6 -0
- package/dist/core/models/browser.js +6 -0
- package/dist/core/models/claude.d.ts.map +1 -1
- package/dist/core/models/index.cjs +6 -0
- package/dist/core/models/index.js +6 -0
- package/dist/core/seed/index.cjs +360 -216
- package/dist/core/seed/index.js +329 -185
- package/dist/core/templates/handlebars-helpers.cjs +3 -1
- package/dist/core/templates/handlebars-helpers.d.ts +5 -0
- package/dist/core/templates/handlebars-helpers.d.ts.map +1 -1
- package/dist/core/templates/handlebars-helpers.js +3 -1
- package/dist/core/tools/mcp/auth-secrets.cjs +3460 -3
- package/dist/core/tools/mcp/auth-secrets.d.ts.map +1 -1
- package/dist/core/tools/mcp/auth-secrets.js +3477 -3
- package/dist/core/tools/mcp/http-headers.cjs +17 -1
- package/dist/core/tools/mcp/http-headers.d.ts.map +1 -1
- package/dist/core/tools/mcp/http-headers.js +15 -1
- package/dist/core/tools/mcp/oauth-refresh.cjs +67 -43
- package/dist/core/tools/mcp/oauth-refresh.js +65 -41
- package/dist/core/types/board.d.ts +12 -0
- package/dist/core/types/board.d.ts.map +1 -1
- package/dist/core/types/gateway.d.ts +14 -0
- package/dist/core/types/gateway.d.ts.map +1 -1
- package/dist/core/types/index.cjs +17 -0
- package/dist/core/types/index.js +16 -0
- package/dist/core/unix/index.cjs +67 -0
- package/dist/core/unix/index.js +67 -0
- package/dist/daemon/auth/executor-runtime-scope.d.ts.map +1 -1
- package/dist/daemon/auth/executor-runtime-scope.js +19 -5
- package/dist/daemon/auth/executor-session-token.d.ts +15 -0
- package/dist/daemon/auth/executor-session-token.d.ts.map +1 -0
- package/dist/daemon/auth/executor-session-token.js +17 -0
- package/dist/daemon/auth/issue-browser-tokens-hook.d.ts +24 -0
- package/dist/daemon/auth/issue-browser-tokens-hook.d.ts.map +1 -0
- package/dist/daemon/auth/issue-browser-tokens-hook.js +95 -0
- package/dist/daemon/auth/service-jwt-strategy.d.ts.map +1 -1
- package/dist/daemon/auth/service-jwt-strategy.js +14 -2
- package/dist/daemon/declarations.d.ts +1 -0
- package/dist/daemon/declarations.d.ts.map +1 -1
- package/dist/daemon/index.js +1365 -418
- package/dist/daemon/main.js +1365 -418
- package/dist/daemon/mcp/server.js +294 -31
- package/dist/daemon/mcp/tools/analytics.js +73 -24
- package/dist/daemon/mcp/tools/artifacts.js +73 -24
- package/dist/daemon/mcp/tools/boards.js +73 -24
- package/dist/daemon/mcp/tools/branches.js +73 -24
- package/dist/daemon/mcp/tools/card-types.js +73 -24
- package/dist/daemon/mcp/tools/cards.js +73 -24
- package/dist/daemon/mcp/tools/environment.js +73 -24
- package/dist/daemon/mcp/tools/gateway-channels.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/gateway-channels.js +190 -38
- package/dist/daemon/mcp/tools/knowledge.js +73 -24
- package/dist/daemon/mcp/tools/mcp-servers.js +73 -24
- package/dist/daemon/mcp/tools/messages.js +73 -24
- package/dist/daemon/mcp/tools/proxies.js +73 -24
- package/dist/daemon/mcp/tools/repos.js +73 -24
- package/dist/daemon/mcp/tools/schedules.js +73 -24
- package/dist/daemon/mcp/tools/search.js +73 -24
- package/dist/daemon/mcp/tools/sessions.js +73 -24
- package/dist/daemon/mcp/tools/tasks.js +73 -24
- package/dist/daemon/mcp/tools/users.js +76 -27
- package/dist/daemon/mcp/tools/widgets.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/widgets.js +257 -99
- package/dist/daemon/oauth-auth-helpers.d.ts +35 -0
- package/dist/daemon/oauth-auth-helpers.d.ts.map +1 -0
- package/dist/daemon/oauth-auth-helpers.js +14 -0
- package/dist/daemon/register-hooks.d.ts +1 -0
- package/dist/daemon/register-hooks.d.ts.map +1 -1
- package/dist/daemon/register-hooks.js +304 -53
- package/dist/daemon/register-routes.d.ts.map +1 -1
- package/dist/daemon/register-routes.js +738 -288
- package/dist/daemon/register-services.d.ts.map +1 -1
- package/dist/daemon/register-services.js +386 -155
- package/dist/daemon/services/boards.d.ts +5 -0
- package/dist/daemon/services/boards.d.ts.map +1 -1
- package/dist/daemon/services/boards.js +7 -0
- package/dist/daemon/services/branches.d.ts.map +1 -1
- package/dist/daemon/services/branches.js +31 -2
- package/dist/daemon/services/claude-models.d.ts.map +1 -1
- package/dist/daemon/services/claude-models.js +4 -1
- package/dist/daemon/services/gateway.d.ts +15 -0
- package/dist/daemon/services/gateway.d.ts.map +1 -1
- package/dist/daemon/services/gateway.js +34 -0
- package/dist/daemon/services/health-monitor.d.ts.map +1 -1
- package/dist/daemon/services/health-monitor.js +10 -7
- package/dist/daemon/services/session-streams.d.ts +29 -0
- package/dist/daemon/services/session-streams.d.ts.map +1 -0
- package/dist/daemon/services/session-streams.js +84 -0
- package/dist/daemon/services/session-token-service.d.ts.map +1 -1
- package/dist/daemon/services/session-token-service.js +8 -4
- package/dist/daemon/setup/index.js +43 -11
- package/dist/daemon/setup/socketio.d.ts.map +1 -1
- package/dist/daemon/setup/socketio.js +43 -11
- package/dist/daemon/startup.d.ts.map +1 -1
- package/dist/daemon/startup.js +37 -16
- package/dist/daemon/utils/authorization.js +19 -5
- package/dist/daemon/utils/emit-service-event.d.ts +56 -0
- package/dist/daemon/utils/emit-service-event.d.ts.map +1 -0
- package/dist/daemon/utils/emit-service-event.js +23 -0
- package/dist/daemon/utils/mcp-header-secrets.d.ts +3 -5
- package/dist/daemon/utils/mcp-header-secrets.d.ts.map +1 -1
- package/dist/daemon/utils/mcp-header-secrets.js +31 -2
- package/dist/daemon/utils/realtime-access-cache.d.ts +9 -0
- package/dist/daemon/utils/realtime-access-cache.d.ts.map +1 -1
- package/dist/daemon/utils/realtime-access-cache.js +24 -0
- package/dist/daemon/utils/realtime-publish.d.ts +24 -0
- package/dist/daemon/utils/realtime-publish.d.ts.map +1 -1
- package/dist/daemon/utils/realtime-publish.js +120 -2
- package/dist/daemon/utils/session-queue-tenant-scope.d.ts +24 -0
- package/dist/daemon/utils/session-queue-tenant-scope.d.ts.map +1 -0
- package/dist/daemon/utils/session-queue-tenant-scope.js +133 -0
- package/dist/daemon/widgets/gateway-token/index.d.ts +114 -0
- package/dist/daemon/widgets/gateway-token/index.d.ts.map +1 -0
- package/dist/daemon/widgets/gateway-token/index.js +14711 -0
- package/dist/daemon/widgets/index.d.ts.map +1 -1
- package/dist/daemon/widgets/index.js +190 -16
- package/dist/daemon/widgets/registry.d.ts +7 -0
- package/dist/daemon/widgets/registry.d.ts.map +1 -1
- package/dist/daemon/widgets/submissions.js +12 -9
- package/dist/executor/commands/git.d.ts.map +1 -1
- package/dist/executor/commands/git.js +2 -0
- package/dist/executor/db/feathers-repositories.d.ts +19 -1
- package/dist/executor/db/feathers-repositories.d.ts.map +1 -1
- package/dist/executor/db/feathers-repositories.js +31 -1
- package/dist/executor/handlers/sdk/claude.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/claude.js +1 -1
- package/dist/executor/handlers/sdk/codex.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/codex.js +1 -1
- package/dist/executor/handlers/sdk/copilot.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/copilot.js +1 -1
- package/dist/executor/handlers/sdk/cursor.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/cursor.js +1 -0
- package/dist/executor/handlers/sdk/gemini.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/gemini.js +1 -1
- package/dist/executor/handlers/sdk/opencode.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/opencode.js +1 -1
- package/dist/executor/payload-types.d.ts +5 -5
- package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts +8 -1
- package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/base/mcp-scoping.js +58 -6
- package/dist/executor/sdk-handlers/claude/claude-tool.d.ts +2 -2
- package/dist/executor/sdk-handlers/claude/claude-tool.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/claude/claude-tool.js +2 -2
- package/dist/executor/sdk-handlers/claude/prompt-service.d.ts +13 -3
- package/dist/executor/sdk-handlers/claude/prompt-service.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/claude/prompt-service.js +16 -3
- package/dist/executor/sdk-handlers/claude/query-builder.d.ts +2 -1
- package/dist/executor/sdk-handlers/claude/query-builder.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/claude/query-builder.js +2 -1
- package/dist/executor/sdk-handlers/codex/codex-tool.d.ts +2 -2
- package/dist/executor/sdk-handlers/codex/codex-tool.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/codex/codex-tool.js +2 -2
- package/dist/executor/sdk-handlers/codex/prompt-service.d.ts +3 -2
- package/dist/executor/sdk-handlers/codex/prompt-service.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/codex/prompt-service.js +70 -6
- package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts +2 -2
- package/dist/executor/sdk-handlers/copilot/copilot-tool.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/copilot/copilot-tool.js +2 -2
- package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts +3 -2
- package/dist/executor/sdk-handlers/copilot/prompt-service.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/copilot/prompt-service.js +4 -1
- package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts +2 -2
- package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/gemini/gemini-tool.js +2 -2
- package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts +3 -2
- package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/gemini/prompt-service.js +4 -1
- package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts +3 -2
- package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/opencode/opencode-tool.js +4 -1
- package/dist/executor/services/feathers-client.d.ts.map +1 -1
- package/dist/executor/services/feathers-client.js +119 -20
- package/dist/ui/assets/AgorEmojiPickerInner-leeNywMc.js +1 -0
- package/dist/ui/assets/App-Dpl4Cc0U.js +4 -0
- package/dist/ui/assets/App-Dpl4Cc0U.js.gz +0 -0
- package/dist/ui/assets/AppNode-wN3UZlFK.js +1 -0
- package/dist/ui/assets/AppNode-wN3UZlFK.js.gz +0 -0
- package/dist/ui/assets/{ArtifactConsentModal-oMMzRn8L.js → ArtifactConsentModal-DjzXcP_L.js} +1 -1
- package/dist/ui/assets/ArtifactConsentModal-DjzXcP_L.js.gz +0 -0
- package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js +9 -0
- package/dist/ui/assets/ArtifactFullscreenPage-B3b_EZ0F.js.gz +0 -0
- package/dist/ui/assets/ArtifactNode-DISy2T-6.js +9 -0
- package/dist/ui/assets/ArtifactNode-DISy2T-6.js.gz +0 -0
- package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js +19 -0
- package/dist/ui/assets/AutocompleteTextarea-DUpsoEGr.js.gz +0 -0
- package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js +34 -0
- package/dist/ui/assets/BoardObjectNodes-BakeGpIX.js.gz +0 -0
- package/dist/ui/assets/{CodeEditor.inner-Cuj6RuLL.js → CodeEditor.inner-HmSdTLW5.js} +1 -1
- package/dist/ui/assets/CodeEditor.inner-HmSdTLW5.js.gz +0 -0
- package/dist/ui/assets/ConversationView-mWaA-B1f.js +1 -0
- package/dist/ui/assets/ConversationView-mWaA-B1f.js.gz +0 -0
- package/dist/ui/assets/{EmbeddedTerminal-Lx5I9EOJ.js → EmbeddedTerminal-NNoyPA81.js} +1 -1
- package/dist/ui/assets/EmbeddedTerminal-NNoyPA81.js.gz +0 -0
- package/dist/ui/assets/KnowledgePage-CkxVnRvz.js +24 -0
- package/dist/ui/assets/KnowledgePage-CkxVnRvz.js.gz +0 -0
- package/dist/ui/assets/{MarketingScreenshotPage-CmDPBHOl.js → MarketingScreenshotPage-B86Gs8jx.js} +2 -2
- package/dist/ui/assets/MarketingScreenshotPage-B86Gs8jx.js.gz +0 -0
- package/dist/ui/assets/MobileApp-BPs-SXvz.js +1 -0
- package/dist/ui/assets/MobileApp-BPs-SXvz.js.gz +0 -0
- package/dist/ui/assets/SessionCanvas-xVfDoEtz.js +13 -0
- package/dist/ui/assets/SessionCanvas-xVfDoEtz.js.gz +0 -0
- package/dist/ui/assets/{StreamdownDemoPage-okKKR2QH.js → StreamdownDemoPage-CvWLzVsv.js} +2 -2
- package/dist/ui/assets/StreamdownDemoPage-CvWLzVsv.js.gz +0 -0
- package/dist/ui/assets/{TerminalModal-D9jMGZXv.js → TerminalModal-ExOgsuOP.js} +2 -2
- package/dist/ui/assets/TerminalModal-ExOgsuOP.js.gz +0 -0
- package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js +1 -0
- package/dist/ui/assets/ThemeSwitcher-Cgyp5ruu.js.gz +0 -0
- package/dist/ui/assets/{ThemedSyntaxHighlighter.inner-C1FdIHn0.js → ThemedSyntaxHighlighter.inner-rpCN9S6K.js} +1 -1
- package/dist/ui/assets/{antd-DT5ackd0.js → antd-BCqimh1J.js} +5 -5
- package/dist/ui/assets/{antd-DT5ackd0.js.gz → antd-BCqimh1J.js.gz} +0 -0
- package/dist/ui/assets/architecture-U656AL7Q-BxSQIjrE.js +1 -0
- package/dist/ui/assets/{architectureDiagram-VXUJARFQ-DwTJGGoj.js → architectureDiagram-VXUJARFQ-pDpGHSqT.js} +1 -1
- package/dist/ui/assets/architectureDiagram-VXUJARFQ-pDpGHSqT.js.gz +0 -0
- package/dist/ui/assets/{blockDiagram-VD42YOAC-Dh1_TVW2.js → blockDiagram-VD42YOAC-uP8JTJpK.js} +1 -1
- package/dist/ui/assets/blockDiagram-VD42YOAC-uP8JTJpK.js.gz +0 -0
- package/dist/ui/assets/{c4Diagram-YG6GDRKO-B1e96AcB.js → c4Diagram-YG6GDRKO-qQe72Mm7.js} +1 -1
- package/dist/ui/assets/c4Diagram-YG6GDRKO-qQe72Mm7.js.gz +0 -0
- package/dist/ui/assets/channel-CoUBs6Zn.js +1 -0
- package/dist/ui/assets/{chunk-4BX2VUAB-BODpCjJx.js → chunk-4BX2VUAB-sz-YE8Nt.js} +1 -1
- package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js +3 -0
- package/dist/ui/assets/chunk-4ZMWKKQ3-3oKtfWXp.js.gz +0 -0
- package/dist/ui/assets/chunk-55IACEB6-BS04dgKF.js +1 -0
- package/dist/ui/assets/{chunk-ABZYJK2D-DCTXWSzV.js → chunk-ABZYJK2D-t3Gkphds.js} +3 -3
- package/dist/ui/assets/chunk-ABZYJK2D-t3Gkphds.js.gz +0 -0
- package/dist/ui/assets/{chunk-AGHRB4JF-CbNphBjE.js → chunk-AGHRB4JF-D_QmWxbY.js} +1 -1
- package/dist/ui/assets/chunk-AGHRB4JF-D_QmWxbY.js.gz +0 -0
- package/dist/ui/assets/{chunk-ATLVNIR6-rWg3qxof.js → chunk-ATLVNIR6-Bmg7-Ufz.js} +1 -1
- package/dist/ui/assets/chunk-ATLVNIR6-Bmg7-Ufz.js.gz +0 -0
- package/dist/ui/assets/{chunk-B4BG7PRW-CgtLCbpE.js → chunk-B4BG7PRW-dnSEE1u-.js} +1 -1
- package/dist/ui/assets/chunk-B4BG7PRW-dnSEE1u-.js.gz +0 -0
- package/dist/ui/assets/{chunk-CVBHYZKI-DTL6Zgr0.js → chunk-CVBHYZKI-BStaYnF0.js} +1 -1
- package/dist/ui/assets/{chunk-DI55MBZ5-Dwvx2Kva.js → chunk-DI55MBZ5-28dvx6o3.js} +1 -1
- package/dist/ui/assets/chunk-DI55MBZ5-28dvx6o3.js.gz +0 -0
- package/dist/ui/assets/chunk-EXTU4WIE-X-FURkEh.js +1 -0
- package/dist/ui/assets/{chunk-FMBD7UC4-BogA_9CV.js → chunk-FMBD7UC4-C_63gC9S.js} +1 -1
- package/dist/ui/assets/{chunk-HN2XXSSU-2blQO3Gb.js → chunk-HN2XXSSU-UFD374KI.js} +1 -1
- package/dist/ui/assets/chunk-HN2XXSSU-UFD374KI.js.gz +0 -0
- package/dist/ui/assets/{chunk-JA3XYJ7Z-Cr1rmOui.js → chunk-JA3XYJ7Z-B60hLNeR.js} +1 -1
- package/dist/ui/assets/chunk-JA3XYJ7Z-B60hLNeR.js.gz +0 -0
- package/dist/ui/assets/{chunk-JZLCHNYA-BsgZ79Fa.js → chunk-JZLCHNYA-ButC6pwN.js} +1 -1
- package/dist/ui/assets/chunk-JZLCHNYA-ButC6pwN.js.gz +0 -0
- package/dist/ui/assets/{chunk-MI3HLSF2-dwYeUy5S.js → chunk-MI3HLSF2-BivYzoSV.js} +1 -1
- package/dist/ui/assets/chunk-MI3HLSF2-BivYzoSV.js.gz +0 -0
- package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js +2 -0
- package/dist/ui/assets/chunk-N4CR4FBY-mVWzo5wJ.js.gz +0 -0
- package/dist/ui/assets/{chunk-QN33PNHL-DxdIDCAa.js → chunk-QN33PNHL-tXtHZpaG.js} +1 -1
- package/dist/ui/assets/{chunk-QXUST7PY-BCK2V0i-.js → chunk-QXUST7PY-DATib_Vv.js} +1 -1
- package/dist/ui/assets/chunk-QXUST7PY-DATib_Vv.js.gz +0 -0
- package/dist/ui/assets/chunk-QZHKN3VN-y6l249e5.js +1 -0
- package/dist/ui/assets/{chunk-S3R3BYOJ-GP3zIxrB.js → chunk-S3R3BYOJ-BEtfmflI.js} +1 -1
- package/dist/ui/assets/chunk-S3R3BYOJ-BEtfmflI.js.gz +0 -0
- package/dist/ui/assets/{chunk-TZMSLE5B-dX5RaM6g.js → chunk-TZMSLE5B-BY1ZtogK.js} +1 -1
- package/dist/ui/assets/chunk-TZMSLE5B-BY1ZtogK.js.gz +0 -0
- package/dist/ui/assets/classDiagram-2ON5EDUG-BYvq-uPY.js +1 -0
- package/dist/ui/assets/classDiagram-v2-WZHVMYZB-BYvq-uPY.js +1 -0
- package/dist/ui/assets/constants-CYzQKfD1.js +1 -0
- package/dist/ui/assets/{cose-bilkent-S5V4N54A-Dx0BJVDl.js → cose-bilkent-S5V4N54A-DPvYrqGG.js} +1 -1
- package/dist/ui/assets/cose-bilkent-S5V4N54A-DPvYrqGG.js.gz +0 -0
- package/dist/ui/assets/{dagre-6UL2VRFP-DiQSUxqN.js → dagre-6UL2VRFP-D800J6qb.js} +1 -1
- package/dist/ui/assets/dagre-6UL2VRFP-D800J6qb.js.gz +0 -0
- package/dist/ui/assets/{dagre-Bekd9Vdj.js → dagre-TNc4wezg.js} +1 -1
- package/dist/ui/assets/dagre-TNc4wezg.js.gz +0 -0
- package/dist/ui/assets/{diagram-PSM6KHXK-DtJnDQjc.js → diagram-PSM6KHXK-CGdP9F-X.js} +1 -1
- package/dist/ui/assets/diagram-PSM6KHXK-CGdP9F-X.js.gz +0 -0
- package/dist/ui/assets/{diagram-QEK2KX5R-CobkCRdj.js → diagram-QEK2KX5R-BD5lOCe5.js} +1 -1
- package/dist/ui/assets/diagram-QEK2KX5R-BD5lOCe5.js.gz +0 -0
- package/dist/ui/assets/{diagram-S2PKOQOG-DHEZYivc.js → diagram-S2PKOQOG-cp3l22vN.js} +1 -1
- package/dist/ui/assets/diagram-S2PKOQOG-cp3l22vN.js.gz +0 -0
- package/dist/ui/assets/editor-Cr0W5BQI.js +39 -0
- package/dist/ui/assets/editor-Cr0W5BQI.js.gz +0 -0
- package/dist/ui/assets/{emoji-B0hLmSLZ.js → emoji-Bv3m24sO.js} +1 -1
- package/dist/ui/assets/emoji-Bv3m24sO.js.gz +0 -0
- package/dist/ui/assets/{erDiagram-Q2GNP2WA-BVNeTZPQ.js → erDiagram-Q2GNP2WA-CQSXRgqr.js} +1 -1
- package/dist/ui/assets/erDiagram-Q2GNP2WA-CQSXRgqr.js.gz +0 -0
- package/dist/ui/assets/{flowDiagram-NV44I4VS-C73VFdyk.js → flowDiagram-NV44I4VS-CKcKpkph.js} +1 -1
- package/dist/ui/assets/flowDiagram-NV44I4VS-CKcKpkph.js.gz +0 -0
- package/dist/ui/assets/{ganttDiagram-LVOFAZNH-B_RosuD1.js → ganttDiagram-LVOFAZNH-DlAHzXO5.js} +1 -1
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-DlAHzXO5.js.gz +0 -0
- package/dist/ui/assets/{gitGraph-F6HP7TQM-DMFIqn4h.js → gitGraph-F6HP7TQM-DeuXy4B1.js} +1 -1
- package/dist/ui/assets/{gitGraphDiagram-NY62KEGX-hxbgwNA1.js → gitGraphDiagram-NY62KEGX-aB-AI4Vq.js} +1 -1
- package/dist/ui/assets/gitGraphDiagram-NY62KEGX-aB-AI4Vq.js.gz +0 -0
- package/dist/ui/assets/index-B-qHc0o5.js +63 -0
- package/dist/ui/assets/index-B-qHc0o5.js.gz +0 -0
- package/dist/ui/assets/{info-NVLQJR56-DZ3K-w48.js → info-NVLQJR56-B9PG7xsc.js} +1 -1
- package/dist/ui/assets/{infoDiagram-ER5ION4S-CxnBJQu6.js → infoDiagram-ER5ION4S-C5Wpoqim.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-CHYNj-f8.js → journeyDiagram-XKPGCS4Q-CHLziqfS.js} +1 -1
- package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHLziqfS.js.gz +0 -0
- package/dist/ui/assets/{kanban-definition-3W4ZIXB7-DQPCCsj2.js → kanban-definition-3W4ZIXB7-Dq7GzQE_.js} +1 -1
- package/dist/ui/assets/kanban-definition-3W4ZIXB7-Dq7GzQE_.js.gz +0 -0
- package/dist/ui/assets/{line-DBRjKmfa.js → line-DHKNg83I.js} +1 -1
- package/dist/ui/assets/{linear-DFao5Wyp.js → linear-BvUfn0I8.js} +1 -1
- package/dist/ui/assets/linear-BvUfn0I8.js.gz +0 -0
- package/dist/ui/assets/{mermaid-parser.core-DYCfacHj.js → mermaid-parser.core-C6d9tKoo.js} +2 -2
- package/dist/ui/assets/mermaid-parser.core-C6d9tKoo.js.gz +0 -0
- package/dist/ui/assets/{mermaid.core-C6xGFSdE.js → mermaid.core-CxE5KezR.js} +3 -3
- package/dist/ui/assets/mermaid.core-CxE5KezR.js.gz +0 -0
- package/dist/ui/assets/{mindmap-definition-VGOIOE7T-L3Pw-YM7.js → mindmap-definition-VGOIOE7T-DmPoQ48w.js} +1 -1
- package/dist/ui/assets/mindmap-definition-VGOIOE7T-DmPoQ48w.js.gz +0 -0
- package/dist/ui/assets/{packet-BFZMPI3H-CpL6iNoa.js → packet-BFZMPI3H-JZEkVZxU.js} +1 -1
- package/dist/ui/assets/{particles-CT8hcJOA.js → particles-CxMmUw86.js} +1 -1
- package/dist/ui/assets/particles-CxMmUw86.js.gz +0 -0
- package/dist/ui/assets/{pie-7BOR55EZ-hTqChbTo.js → pie-7BOR55EZ-_1II5pYQ.js} +1 -1
- package/dist/ui/assets/{pieDiagram-ADFJNKIX-Bf4Nou75.js → pieDiagram-ADFJNKIX-DrNkH33i.js} +1 -1
- package/dist/ui/assets/pieDiagram-ADFJNKIX-DrNkH33i.js.gz +0 -0
- package/dist/ui/assets/{quadrantDiagram-AYHSOK5B-DpjUTLB1.js → quadrantDiagram-AYHSOK5B-DOpC-HEF.js} +1 -1
- package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DOpC-HEF.js.gz +0 -0
- package/dist/ui/assets/{radar-NHE76QYJ-myy7OENC.js → radar-NHE76QYJ-DDmqhzEZ.js} +1 -1
- package/dist/ui/assets/{reactflow-Cubtnk8i.js → reactflow-D98uPOMq.js} +1 -1
- package/dist/ui/assets/reactflow-D98uPOMq.js.gz +0 -0
- package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-Bfrfh-0-.js → requirementDiagram-UZGBJVZJ-Bzx0iEPP.js} +1 -1
- package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bzx0iEPP.js.gz +0 -0
- package/dist/ui/assets/{sandpack-C58bwfIS.js → sandpack-059Z4UWP.js} +1 -1
- package/dist/ui/assets/sandpack-059Z4UWP.js.gz +0 -0
- package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js +1 -0
- package/dist/ui/assets/sandpackDefaults-CPMNDsw7.js.gz +0 -0
- package/dist/ui/assets/{sankeyDiagram-TZEHDZUN-ClZAZ6va.js → sankeyDiagram-TZEHDZUN-Do9pvfDv.js} +1 -1
- package/dist/ui/assets/sankeyDiagram-TZEHDZUN-Do9pvfDv.js.gz +0 -0
- package/dist/ui/assets/{sequenceDiagram-WL72ISMW-CNgly63p.js → sequenceDiagram-WL72ISMW-CN8neUTA.js} +1 -1
- package/dist/ui/assets/sequenceDiagram-WL72ISMW-CN8neUTA.js.gz +0 -0
- package/dist/ui/assets/{src-DAeyG22O.js → src-DEbsv3pp.js} +2 -2
- package/dist/ui/assets/src-DEbsv3pp.js.gz +0 -0
- package/dist/ui/assets/{stateDiagram-FKZM4ZOC-BrEAoDpE.js → stateDiagram-FKZM4ZOC-BluWJi8n.js} +1 -1
- package/dist/ui/assets/stateDiagram-FKZM4ZOC-BluWJi8n.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-DeyqBMDR.js +1 -0
- package/dist/ui/assets/{streamdown-BdAVfkeF.js → streamdown-BT1twtFc.js} +5 -5
- package/dist/ui/assets/streamdown-BT1twtFc.js.gz +0 -0
- package/dist/ui/assets/{syntax-BOfTnQiy.js → syntax-CBu6nLfm.js} +1 -1
- package/dist/ui/assets/syntax-CBu6nLfm.js.gz +0 -0
- package/dist/ui/assets/{timeline-definition-IT6M3QCI-CaRH3k4l.js → timeline-definition-IT6M3QCI-WdUNkiRj.js} +1 -1
- package/dist/ui/assets/timeline-definition-IT6M3QCI-WdUNkiRj.js.gz +0 -0
- package/dist/ui/assets/{treemap-KMMF4GRG-CUaLOV_B.js → treemap-KMMF4GRG-CoriU4Jl.js} +1 -1
- package/dist/ui/assets/{useUserLocalStorage-C8sgXgXR.js → useUserLocalStorage-GidNiOPC.js} +1 -1
- package/dist/ui/assets/useUserLocalStorage-GidNiOPC.js.gz +0 -0
- package/dist/ui/assets/{xychartDiagram-PRI3JC2R-BlhkI9T_.js → xychartDiagram-PRI3JC2R-CgBAKNt2.js} +1 -1
- package/dist/ui/assets/xychartDiagram-PRI3JC2R-CgBAKNt2.js.gz +0 -0
- package/dist/ui/index.html +9 -8
- package/dist/ui/index.html.gz +0 -0
- package/package.json +2 -2
- package/dist/ui/assets/AgorEmojiPickerInner-DQjr8M3_.js +0 -1
- package/dist/ui/assets/App-hJtcOxHv.js +0 -5
- package/dist/ui/assets/App-hJtcOxHv.js.gz +0 -0
- package/dist/ui/assets/AppNode-BhuMpn8O.js +0 -1
- package/dist/ui/assets/AppNode-BhuMpn8O.js.gz +0 -0
- package/dist/ui/assets/ArtifactConsentModal-oMMzRn8L.js.gz +0 -0
- package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js +0 -9
- package/dist/ui/assets/ArtifactFullscreenPage-B3wT8t8f.js.gz +0 -0
- package/dist/ui/assets/ArtifactNode-BzQcrwFS.js +0 -9
- package/dist/ui/assets/ArtifactNode-BzQcrwFS.js.gz +0 -0
- package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js +0 -19
- package/dist/ui/assets/AutocompleteTextarea-Dau-V_30.js.gz +0 -0
- package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js +0 -34
- package/dist/ui/assets/BoardObjectNodes-DdKWv_ZT.js.gz +0 -0
- package/dist/ui/assets/CodeEditor.inner-Cuj6RuLL.js.gz +0 -0
- package/dist/ui/assets/ConversationView-9-3ma1u-.js +0 -1
- package/dist/ui/assets/ConversationView-9-3ma1u-.js.gz +0 -0
- package/dist/ui/assets/EmbeddedTerminal-Lx5I9EOJ.js.gz +0 -0
- package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js +0 -24
- package/dist/ui/assets/KnowledgePage-Dz8YAMYC.js.gz +0 -0
- package/dist/ui/assets/MarketingScreenshotPage-CmDPBHOl.js.gz +0 -0
- package/dist/ui/assets/MobileApp-BpgSG_gz.js +0 -1
- package/dist/ui/assets/MobileApp-BpgSG_gz.js.gz +0 -0
- package/dist/ui/assets/SessionCanvas-B6_mtlxK.js +0 -13
- package/dist/ui/assets/SessionCanvas-B6_mtlxK.js.gz +0 -0
- package/dist/ui/assets/StreamdownDemoPage-okKKR2QH.js.gz +0 -0
- package/dist/ui/assets/TerminalModal-D9jMGZXv.js.gz +0 -0
- package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js +0 -1
- package/dist/ui/assets/ThemeSwitcher-D9HgT37l.js.gz +0 -0
- package/dist/ui/assets/architecture-U656AL7Q-DMnxkQRZ.js +0 -1
- package/dist/ui/assets/architectureDiagram-VXUJARFQ-DwTJGGoj.js.gz +0 -0
- package/dist/ui/assets/blockDiagram-VD42YOAC-Dh1_TVW2.js.gz +0 -0
- package/dist/ui/assets/c4Diagram-YG6GDRKO-B1e96AcB.js.gz +0 -0
- package/dist/ui/assets/channel-Jv4dT4S5.js +0 -1
- package/dist/ui/assets/chunk-55IACEB6-lJXvUquf.js +0 -1
- package/dist/ui/assets/chunk-ABZYJK2D-DCTXWSzV.js.gz +0 -0
- package/dist/ui/assets/chunk-AGHRB4JF-CbNphBjE.js.gz +0 -0
- package/dist/ui/assets/chunk-ATLVNIR6-rWg3qxof.js.gz +0 -0
- package/dist/ui/assets/chunk-B4BG7PRW-CgtLCbpE.js.gz +0 -0
- package/dist/ui/assets/chunk-DI55MBZ5-Dwvx2Kva.js.gz +0 -0
- package/dist/ui/assets/chunk-EXTU4WIE-DHyaqTsP.js +0 -1
- package/dist/ui/assets/chunk-HN2XXSSU-2blQO3Gb.js.gz +0 -0
- package/dist/ui/assets/chunk-JA3XYJ7Z-Cr1rmOui.js.gz +0 -0
- package/dist/ui/assets/chunk-JZLCHNYA-BsgZ79Fa.js.gz +0 -0
- package/dist/ui/assets/chunk-MI3HLSF2-dwYeUy5S.js.gz +0 -0
- package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js +0 -2
- package/dist/ui/assets/chunk-N4CR4FBY-DEMgSRVe.js.gz +0 -0
- package/dist/ui/assets/chunk-QXUST7PY-BCK2V0i-.js.gz +0 -0
- package/dist/ui/assets/chunk-QZHKN3VN-CALjGrEE.js +0 -1
- package/dist/ui/assets/chunk-S3R3BYOJ-GP3zIxrB.js.gz +0 -0
- package/dist/ui/assets/chunk-TZMSLE5B-dX5RaM6g.js.gz +0 -0
- package/dist/ui/assets/classDiagram-2ON5EDUG-C3_RVP70.js +0 -1
- package/dist/ui/assets/classDiagram-v2-WZHVMYZB-C3_RVP70.js +0 -1
- package/dist/ui/assets/constants-GjIDNVyt.js +0 -1
- package/dist/ui/assets/cose-bilkent-S5V4N54A-Dx0BJVDl.js.gz +0 -0
- package/dist/ui/assets/dagre-6UL2VRFP-DiQSUxqN.js.gz +0 -0
- package/dist/ui/assets/dagre-Bekd9Vdj.js.gz +0 -0
- package/dist/ui/assets/diagram-PSM6KHXK-DtJnDQjc.js.gz +0 -0
- package/dist/ui/assets/diagram-QEK2KX5R-CobkCRdj.js.gz +0 -0
- package/dist/ui/assets/diagram-S2PKOQOG-DHEZYivc.js.gz +0 -0
- package/dist/ui/assets/editor-DQIG-JYZ.js +0 -43
- package/dist/ui/assets/editor-DQIG-JYZ.js.gz +0 -0
- package/dist/ui/assets/emoji-B0hLmSLZ.js.gz +0 -0
- package/dist/ui/assets/erDiagram-Q2GNP2WA-BVNeTZPQ.js.gz +0 -0
- package/dist/ui/assets/flowDiagram-NV44I4VS-C73VFdyk.js.gz +0 -0
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-B_RosuD1.js.gz +0 -0
- package/dist/ui/assets/gitGraphDiagram-NY62KEGX-hxbgwNA1.js.gz +0 -0
- package/dist/ui/assets/index-DTz1Dif6.js +0 -64
- package/dist/ui/assets/index-DTz1Dif6.js.gz +0 -0
- package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHYNj-f8.js.gz +0 -0
- package/dist/ui/assets/kanban-definition-3W4ZIXB7-DQPCCsj2.js.gz +0 -0
- package/dist/ui/assets/linear-DFao5Wyp.js.gz +0 -0
- package/dist/ui/assets/mermaid-parser.core-DYCfacHj.js.gz +0 -0
- package/dist/ui/assets/mermaid.core-C6xGFSdE.js.gz +0 -0
- package/dist/ui/assets/mindmap-definition-VGOIOE7T-L3Pw-YM7.js.gz +0 -0
- package/dist/ui/assets/particles-CT8hcJOA.js.gz +0 -0
- package/dist/ui/assets/pieDiagram-ADFJNKIX-Bf4Nou75.js.gz +0 -0
- package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DpjUTLB1.js.gz +0 -0
- package/dist/ui/assets/reactflow-Cubtnk8i.js.gz +0 -0
- package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bfrfh-0-.js.gz +0 -0
- package/dist/ui/assets/sandpack-C58bwfIS.js.gz +0 -0
- package/dist/ui/assets/sandpackDefaults-Bkga8XAE.js +0 -1
- package/dist/ui/assets/sankeyDiagram-TZEHDZUN-ClZAZ6va.js.gz +0 -0
- package/dist/ui/assets/sequenceDiagram-WL72ISMW-CNgly63p.js.gz +0 -0
- package/dist/ui/assets/src-DAeyG22O.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-FKZM4ZOC-BrEAoDpE.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-BNL52_oN.js +0 -1
- package/dist/ui/assets/streamdown-BdAVfkeF.js.gz +0 -0
- package/dist/ui/assets/syntax-BOfTnQiy.js.gz +0 -0
- package/dist/ui/assets/timeline-definition-IT6M3QCI-CaRH3k4l.js.gz +0 -0
- package/dist/ui/assets/useUserLocalStorage-C8sgXgXR.js.gz +0 -0
- 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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
1613
|
+
if (err instanceof jwt8.TokenExpiredError) {
|
|
1595
1614
|
console.warn("[mcp-tokens] token rejected: expired");
|
|
1596
|
-
} else if (err instanceof
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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: () =>
|
|
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
|
|
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: () =>
|
|
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
|
-
|
|
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
|
|
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
|
|
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)
|
|
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({
|
|
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.
|
|
21560
|
-
|
|
21561
|
-
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
|
|
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
|
|
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 === "
|
|
21587
|
-
for (const field of ["app_id", "
|
|
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
|
|
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
|
|
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
|
|
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
|
|
27858
|
+
hasMinimumRole as hasMinimumRole11,
|
|
27567
27859
|
MessageRole as MessageRole4,
|
|
27568
|
-
ROLES as
|
|
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
|
|
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 ===
|
|
28441
|
-
if (payload
|
|
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:
|
|
28449
|
-
purpose:
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
29531
|
-
|
|
29532
|
-
|
|
29533
|
-
|
|
29534
|
-
|
|
29535
|
-
|
|
29536
|
-
|
|
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 (!
|
|
29600
|
-
throw new
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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:
|
|
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:
|
|
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
|
-
|
|
30684
|
-
|
|
30685
|
-
|
|
30686
|
-
|
|
30687
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
31063
|
-
create: { role:
|
|
31064
|
-
patch: { role:
|
|
31065
|
-
remove: { role:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
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
|
|
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 && !
|
|
31249
|
-
throw new
|
|
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(
|
|
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
|
|
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 && !
|
|
31285
|
-
throw new
|
|
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(
|
|
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 && !
|
|
31345
|
-
throw new
|
|
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(
|
|
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 && !
|
|
31424
|
-
throw new
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
31631
|
-
create: { role:
|
|
31632
|
-
remove: { role:
|
|
31633
|
-
patch: { role:
|
|
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:
|
|
31723
|
-
create: { role:
|
|
31724
|
-
remove: { role:
|
|
31725
|
-
patch: { role:
|
|
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
|
);
|