agor-live 0.22.0 → 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/cli/commands/admin/add-to-branch-group.d.ts +2 -13
- package/dist/cli/commands/admin/add-to-branch-group.d.ts.map +1 -1
- package/dist/cli/commands/admin/add-to-branch-group.js +133 -33
- package/dist/cli/commands/admin/create-branch-group.d.ts +2 -13
- package/dist/cli/commands/admin/create-branch-group.d.ts.map +1 -1
- package/dist/cli/commands/admin/create-branch-group.js +132 -38
- package/dist/cli/commands/admin/create-symlink.d.ts +2 -14
- package/dist/cli/commands/admin/create-symlink.d.ts.map +1 -1
- package/dist/cli/commands/admin/create-symlink.js +138 -61
- package/dist/cli/commands/admin/delete-branch-group.d.ts +2 -13
- package/dist/cli/commands/admin/delete-branch-group.d.ts.map +1 -1
- package/dist/cli/commands/admin/delete-branch-group.js +132 -28
- package/dist/cli/commands/admin/delete-user.d.ts +2 -13
- package/dist/cli/commands/admin/delete-user.d.ts.map +1 -1
- package/dist/cli/commands/admin/delete-user.js +132 -38
- package/dist/cli/commands/admin/ensure-user.d.ts +2 -14
- package/dist/cli/commands/admin/ensure-user.d.ts.map +1 -1
- package/dist/cli/commands/admin/ensure-user.js +131 -46
- package/dist/cli/commands/admin/remove-from-branch-group.d.ts +2 -13
- package/dist/cli/commands/admin/remove-from-branch-group.d.ts.map +1 -1
- package/dist/cli/commands/admin/remove-from-branch-group.js +133 -33
- package/dist/cli/commands/admin/remove-symlink.d.ts +2 -14
- package/dist/cli/commands/admin/remove-symlink.d.ts.map +1 -1
- package/dist/cli/commands/admin/remove-symlink.js +136 -49
- package/dist/cli/commands/admin/scrub-git-remotes.d.ts +2 -2
- package/dist/cli/commands/admin/scrub-git-remotes.d.ts.map +1 -1
- package/dist/cli/commands/admin/scrub-git-remotes.js +128 -86
- package/dist/cli/commands/admin/sync-user-symlinks.d.ts +2 -14
- package/dist/cli/commands/admin/sync-user-symlinks.d.ts.map +1 -1
- package/dist/cli/commands/admin/sync-user-symlinks.js +132 -43
- package/dist/cli/commands/auth/whoami.d.ts.map +1 -1
- package/dist/cli/commands/auth/whoami.js +2 -1
- package/dist/cli/commands/branch/env/request.test.d.ts +2 -0
- package/dist/cli/commands/branch/env/request.test.d.ts.map +1 -0
- package/dist/cli/commands/branch/env/request.test.js +17723 -0
- package/dist/cli/commands/branch/env/restart.d.ts.map +1 -1
- package/dist/cli/commands/branch/env/restart.js +7 -1
- package/dist/cli/commands/branch/env/start.d.ts.map +1 -1
- package/dist/cli/commands/branch/env/start.js +7 -1
- package/dist/cli/commands/branch/env/stop.d.ts.map +1 -1
- package/dist/cli/commands/branch/env/stop.js +7 -1
- package/dist/cli/commands/daemon/status.d.ts.map +1 -1
- package/dist/cli/commands/daemon/status.js +2 -1
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +140 -2
- package/dist/cli/commands/local/add-to-branch-group.d.ts +13 -0
- package/dist/cli/commands/local/add-to-branch-group.d.ts.map +1 -0
- package/dist/cli/commands/local/add-to-branch-group.js +37 -0
- package/dist/cli/commands/local/create-branch-group.d.ts +12 -0
- package/dist/cli/commands/local/create-branch-group.d.ts.map +1 -0
- package/dist/cli/commands/local/create-branch-group.js +35 -0
- package/dist/cli/commands/local/create-symlink.d.ts +14 -0
- package/dist/cli/commands/local/create-symlink.d.ts.map +1 -0
- package/dist/cli/commands/local/create-symlink.js +45 -0
- package/dist/cli/commands/{daemon → local/daemon}/sync.d.ts +1 -1
- package/dist/cli/commands/local/daemon/sync.d.ts.map +1 -0
- package/dist/cli/commands/{daemon → local/daemon}/sync.js +7 -6
- package/dist/cli/commands/local/delete-branch-group.d.ts +12 -0
- package/dist/cli/commands/local/delete-branch-group.d.ts.map +1 -0
- package/dist/cli/commands/local/delete-branch-group.js +35 -0
- package/dist/cli/commands/local/delete-user.d.ts +12 -0
- package/dist/cli/commands/local/delete-user.d.ts.map +1 -0
- package/dist/cli/commands/local/delete-user.js +36 -0
- package/dist/cli/commands/local/ensure-user.d.ts +12 -0
- package/dist/cli/commands/local/ensure-user.d.ts.map +1 -0
- package/dist/cli/commands/local/ensure-user.js +41 -0
- package/dist/cli/commands/local/remove-from-branch-group.d.ts +13 -0
- package/dist/cli/commands/local/remove-from-branch-group.d.ts.map +1 -0
- package/dist/cli/commands/local/remove-from-branch-group.js +37 -0
- package/dist/cli/commands/local/remove-symlink.d.ts +13 -0
- package/dist/cli/commands/local/remove-symlink.d.ts.map +1 -0
- package/dist/cli/commands/local/remove-symlink.js +39 -0
- package/dist/cli/commands/local/scrub-git-remotes.d.ts +9 -0
- package/dist/cli/commands/local/scrub-git-remotes.d.ts.map +1 -0
- package/dist/cli/commands/local/scrub-git-remotes.js +23 -0
- package/dist/cli/commands/{admin → local}/sync-unix.d.ts.map +1 -1
- package/dist/cli/commands/{admin → local}/sync-unix.js +3 -3
- package/dist/cli/commands/local/sync-user-symlinks.d.ts +12 -0
- package/dist/cli/commands/local/sync-user-symlinks.d.ts.map +1 -0
- package/dist/cli/commands/local/sync-user-symlinks.js +37 -0
- package/dist/cli/commands/telemetry/index.d.ts +7 -0
- package/dist/cli/commands/telemetry/index.d.ts.map +1 -0
- package/dist/cli/commands/telemetry/index.js +40 -0
- package/dist/cli/commands/telemetry/off.d.ts +6 -0
- package/dist/cli/commands/telemetry/off.d.ts.map +1 -0
- package/dist/cli/commands/telemetry/off.js +35 -0
- package/dist/cli/commands/telemetry/on.d.ts +6 -0
- package/dist/cli/commands/telemetry/on.d.ts.map +1 -0
- package/dist/cli/commands/telemetry/on.js +37 -0
- package/dist/cli/commands/telemetry/test.d.ts +6 -0
- package/dist/cli/commands/telemetry/test.d.ts.map +1 -0
- package/dist/cli/commands/telemetry/test.js +56 -0
- package/dist/cli/commands/user/create-admin.d.ts.map +1 -1
- package/dist/cli/commands/user/create-admin.js +81 -72
- package/dist/cli/commands/user/list.d.ts.map +1 -1
- package/dist/cli/commands/user/list.js +1 -0
- package/dist/cli/commands/whoami.js +2 -1
- package/dist/cli/lib/branch-environment-action.d.ts +21 -0
- package/dist/cli/lib/branch-environment-action.d.ts.map +1 -0
- package/dist/cli/lib/branch-environment-action.js +8 -0
- package/dist/core/api/index.cjs +7 -2
- package/dist/core/api/index.d.ts +13 -4
- package/dist/core/api/index.d.ts.map +1 -1
- package/dist/core/api/index.js +7 -2
- package/dist/core/claude/index.cjs +518 -89
- package/dist/core/claude/index.js +515 -88
- package/dist/core/claude-cli/index.cjs +24 -0
- package/dist/core/claude-cli/index.js +24 -0
- package/dist/core/claude-cli/pricing.d.ts.map +1 -1
- package/dist/core/client/index.cjs +52 -7
- package/dist/core/client/index.js +48 -7
- package/dist/core/config/browser.cjs +3 -5
- package/dist/core/config/browser.js +3 -5
- package/dist/core/config/config-manager.d.ts +33 -13
- package/dist/core/config/config-manager.d.ts.map +1 -1
- package/dist/core/config/index.cjs +4259 -4527
- package/dist/core/config/index.d.ts +1 -0
- package/dist/core/config/index.d.ts.map +1 -1
- package/dist/core/config/index.js +4295 -4583
- package/dist/core/config/key-resolver.d.ts.map +1 -1
- package/dist/core/config/multitenancy.d.ts +33 -0
- package/dist/core/config/multitenancy.d.ts.map +1 -0
- package/dist/core/config/security-resolver.d.ts +1 -0
- package/dist/core/config/security-resolver.d.ts.map +1 -1
- package/dist/core/config/types.d.ts +67 -4
- package/dist/core/config/types.d.ts.map +1 -1
- package/dist/core/db/client.d.ts +34 -2
- package/dist/core/db/client.d.ts.map +1 -1
- package/dist/core/db/database-wrapper.d.ts.map +1 -1
- package/dist/core/db/first-run-bootstrap.d.ts.map +1 -1
- package/dist/core/db/index.cjs +2767 -1232
- package/dist/core/db/index.d.ts +2 -1
- package/dist/core/db/index.d.ts.map +1 -1
- package/dist/core/db/index.js +2601 -1094
- package/dist/core/db/migrate.d.ts.map +1 -1
- package/dist/core/db/repositories/artifacts.d.ts +27 -2
- package/dist/core/db/repositories/artifacts.d.ts.map +1 -1
- package/dist/core/db/repositories/base.d.ts +18 -0
- package/dist/core/db/repositories/base.d.ts.map +1 -1
- package/dist/core/db/repositories/board-comments.d.ts +17 -1
- package/dist/core/db/repositories/board-comments.d.ts.map +1 -1
- package/dist/core/db/repositories/board-objects.d.ts.map +1 -1
- package/dist/core/db/repositories/boards.d.ts +54 -3
- package/dist/core/db/repositories/boards.d.ts.map +1 -1
- package/dist/core/db/repositories/branch-access.d.ts +32 -0
- package/dist/core/db/repositories/branch-access.d.ts.map +1 -1
- package/dist/core/db/repositories/branches.d.ts +52 -2
- package/dist/core/db/repositories/branches.d.ts.map +1 -1
- package/dist/core/db/repositories/cards.d.ts +15 -1
- package/dist/core/db/repositories/cards.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/gateway-outbound-messages.d.ts +19 -0
- package/dist/core/db/repositories/gateway-outbound-messages.d.ts.map +1 -0
- package/dist/core/db/repositories/index.d.ts +2 -0
- package/dist/core/db/repositories/index.d.ts.map +1 -1
- package/dist/core/db/repositories/messages.d.ts +9 -2
- package/dist/core/db/repositories/messages.d.ts.map +1 -1
- package/dist/core/db/repositories/repos.d.ts.map +1 -1
- package/dist/core/db/repositories/schedules.d.ts +12 -1
- package/dist/core/db/repositories/schedules.d.ts.map +1 -1
- package/dist/core/db/repositories/sessions.d.ts +56 -5
- package/dist/core/db/repositories/sessions.d.ts.map +1 -1
- package/dist/core/db/repositories/tasks.d.ts +7 -2
- package/dist/core/db/repositories/tasks.d.ts.map +1 -1
- package/dist/core/db/repositories/user-api-keys.d.ts +10 -1
- package/dist/core/db/repositories/user-api-keys.d.ts.map +1 -1
- package/dist/core/db/repositories/users.d.ts +8 -8
- package/dist/core/db/repositories/users.d.ts.map +1 -1
- package/dist/core/db/schema.d.ts +1460 -38
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.postgres.d.ts +1082 -37
- package/dist/core/db/schema.postgres.d.ts.map +1 -1
- package/dist/core/db/schema.sqlite.d.ts +397 -1
- package/dist/core/db/schema.sqlite.d.ts.map +1 -1
- package/dist/core/db/tenant-context.d.ts +26 -0
- package/dist/core/db/tenant-context.d.ts.map +1 -0
- package/dist/core/db/tenant-scope.d.ts +31 -0
- package/dist/core/db/tenant-scope.d.ts.map +1 -0
- package/dist/core/db/user-utils.d.ts +2 -2
- package/dist/core/db/user-utils.d.ts.map +1 -1
- package/dist/core/drizzle/postgres/0052_gateway_outbound_messages.sql +45 -0
- package/dist/core/drizzle/postgres/0053_user_token_invalidation.sql +1 -0
- package/dist/core/drizzle/postgres/0054_app_level_multitenancy.sql +219 -0
- package/dist/core/drizzle/postgres/0055_app_level_multitenancy_rls.sql +411 -0
- package/dist/core/drizzle/postgres/0056_composite_indexes.sql +15 -0
- package/dist/core/drizzle/postgres/0057_message_timestamp_indexes.sql +3 -0
- package/dist/core/drizzle/postgres/meta/_journal.json +42 -0
- package/dist/core/drizzle/sqlite/0061_gateway_outbound_messages.sql +38 -0
- package/dist/core/drizzle/sqlite/0062_user_token_invalidation.sql +1 -0
- package/dist/core/drizzle/sqlite/0063_composite_indexes.sql +10 -0
- package/dist/core/drizzle/sqlite/0064_message_timestamp_indexes.sql +2 -0
- package/dist/core/drizzle/sqlite/meta/_journal.json +28 -0
- package/dist/core/environment/render-snapshot.cjs +7 -6
- 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 +7 -6
- package/dist/core/environment/variable-resolver.cjs +3 -1
- package/dist/core/environment/variable-resolver.js +3 -1
- package/dist/core/environment/webhook.cjs +1 -4
- package/dist/core/environment/webhook.js +1 -4
- package/dist/core/gateway/connector.d.ts +10 -1
- package/dist/core/gateway/connector.d.ts.map +1 -1
- package/dist/core/gateway/connectors/slack-manifest.cjs +108 -0
- package/dist/core/gateway/connectors/slack-manifest.d.ts +85 -0
- package/dist/core/gateway/connectors/slack-manifest.d.ts.map +1 -0
- package/dist/core/gateway/connectors/slack-manifest.js +81 -0
- package/dist/core/gateway/connectors/slack.d.ts +101 -4
- package/dist/core/gateway/connectors/slack.d.ts.map +1 -1
- package/dist/core/gateway/index.cjs +495 -29
- package/dist/core/gateway/index.d.ts +4 -1
- package/dist/core/gateway/index.d.ts.map +1 -1
- package/dist/core/gateway/index.js +490 -28
- package/dist/core/gateway/system-message.d.ts.map +1 -1
- package/dist/core/git/exec.cjs +24 -0
- package/dist/core/git/exec.d.ts +6 -4
- package/dist/core/git/exec.d.ts.map +1 -1
- package/dist/core/git/exec.js +2 -0
- package/dist/core/git/index.cjs +3 -1363
- package/dist/core/git/index.d.ts +4 -614
- package/dist/core/git/index.d.ts.map +1 -1
- package/dist/core/git/index.js +1 -1304
- package/dist/core/git/pure.cjs +24 -0
- package/dist/core/git/pure.d.ts +2 -27
- package/dist/core/git/pure.d.ts.map +1 -1
- package/dist/core/git/pure.js +2 -0
- package/dist/core/index.cjs +11563 -10832
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +12203 -10962
- package/dist/core/lib/feathers-validation.cjs +9 -1
- package/dist/core/lib/feathers-validation.d.ts +2 -0
- package/dist/core/lib/feathers-validation.d.ts.map +1 -1
- package/dist/core/lib/feathers-validation.js +9 -1
- package/dist/core/local-actions/git-remotes.d.ts +7 -0
- package/dist/core/local-actions/git-remotes.d.ts.map +1 -0
- package/dist/core/local-actions/index.cjs +8008 -0
- package/dist/core/local-actions/index.d.ts +6 -0
- package/dist/core/local-actions/index.d.ts.map +1 -0
- package/dist/core/local-actions/index.js +8010 -0
- package/dist/core/local-actions/symlinks.d.ts +20 -0
- package/dist/core/local-actions/symlinks.d.ts.map +1 -0
- package/dist/core/local-actions/types.d.ts +14 -0
- package/dist/core/local-actions/types.d.ts.map +1 -0
- package/dist/core/local-actions/unix-groups.d.ts +16 -0
- package/dist/core/local-actions/unix-groups.d.ts.map +1 -0
- package/dist/core/local-actions/unix-users.d.ts +12 -0
- package/dist/core/local-actions/unix-users.d.ts.map +1 -0
- package/dist/core/mcp/index.cjs +373 -28
- 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 +369 -27
- 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 +154 -25
- package/dist/core/models/browser.js +150 -25
- package/dist/core/models/claude.d.ts +2 -2
- package/dist/core/models/claude.d.ts.map +1 -1
- package/dist/core/models/codex.d.ts +205 -21
- package/dist/core/models/codex.d.ts.map +1 -1
- package/dist/core/models/index.cjs +154 -25
- package/dist/core/models/index.js +150 -25
- package/dist/core/package.json +24 -0
- package/dist/core/seed/demo-fixtures.d.ts +87 -0
- package/dist/core/seed/demo-fixtures.d.ts.map +1 -0
- package/dist/core/seed/dev-fixtures.d.ts.map +1 -1
- package/dist/core/seed/index.cjs +8569 -5519
- package/dist/core/seed/index.d.ts +1 -0
- package/dist/core/seed/index.d.ts.map +1 -1
- package/dist/core/seed/index.js +8580 -5535
- package/dist/core/sessions/index.cjs +110 -24
- package/dist/core/sessions/index.js +110 -24
- package/dist/core/telemetry/index.cjs +361 -0
- package/dist/core/telemetry/index.d.ts +5 -0
- package/dist/core/telemetry/index.d.ts.map +1 -0
- package/dist/core/telemetry/index.js +315 -0
- package/dist/core/telemetry/logger.d.ts +44 -0
- package/dist/core/telemetry/logger.d.ts.map +1 -0
- package/dist/core/telemetry/model-normalization.d.ts +3 -0
- package/dist/core/telemetry/model-normalization.d.ts.map +1 -0
- package/dist/core/telemetry/types.d.ts +47 -0
- package/dist/core/telemetry/types.d.ts.map +1 -0
- package/dist/core/telemetry/version.d.ts +9 -0
- package/dist/core/telemetry/version.d.ts.map +1 -0
- package/dist/core/templates/agor-system-prompt.md +1 -0
- 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 +568 -114
- package/dist/core/tools/mcp/oauth-refresh.js +566 -115
- package/dist/core/types/board.d.ts +14 -0
- package/dist/core/types/board.d.ts.map +1 -1
- package/dist/core/types/branch.d.ts +13 -0
- package/dist/core/types/branch.d.ts.map +1 -1
- package/dist/core/types/config-services.d.ts.map +1 -1
- package/dist/core/types/feathers.d.ts +6 -0
- package/dist/core/types/feathers.d.ts.map +1 -1
- package/dist/core/types/gateway.d.ts +90 -1
- package/dist/core/types/gateway.d.ts.map +1 -1
- package/dist/core/types/index.cjs +42 -0
- package/dist/core/types/index.d.ts +1 -0
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/index.js +38 -0
- package/dist/core/types/schedule.d.ts +4 -3
- package/dist/core/types/schedule.d.ts.map +1 -1
- package/dist/core/types/session.d.ts +7 -1
- package/dist/core/types/session.d.ts.map +1 -1
- package/dist/core/types/tenant.d.ts +15 -0
- package/dist/core/types/tenant.d.ts.map +1 -0
- package/dist/core/types/user.d.ts +61 -0
- package/dist/core/types/user.d.ts.map +1 -1
- package/dist/core/unix/index.cjs +1123 -674
- package/dist/core/unix/index.js +1071 -624
- package/dist/core/utils/emoji-shortcodes.d.ts +13 -0
- package/dist/core/utils/emoji-shortcodes.d.ts.map +1 -0
- package/dist/core/yaml/index.cjs +8 -8
- package/dist/core/yaml/index.d.ts +1 -1
- package/dist/core/yaml/index.d.ts.map +1 -1
- package/dist/core/yaml/index.js +7 -7
- package/dist/daemon/adapters/drizzle.d.ts +26 -4
- package/dist/daemon/adapters/drizzle.d.ts.map +1 -1
- package/dist/daemon/adapters/drizzle.js +68 -7
- package/dist/daemon/auth/api-key-strategy.js +1 -1
- package/dist/daemon/auth/executor-runtime-scope.d.ts.map +1 -1
- package/dist/daemon/auth/executor-runtime-scope.js +34 -6
- 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/launch-auth.d.ts +5 -4
- package/dist/daemon/auth/launch-auth.d.ts.map +1 -1
- package/dist/daemon/auth/launch-auth.js +123 -39
- package/dist/daemon/auth/refresh-token-service.d.ts +22 -0
- package/dist/daemon/auth/refresh-token-service.d.ts.map +1 -0
- package/dist/daemon/auth/refresh-token-service.js +133 -0
- package/dist/daemon/auth/runtime-tokens.d.ts +3 -1
- package/dist/daemon/auth/runtime-tokens.d.ts.map +1 -1
- package/dist/daemon/auth/runtime-tokens.js +17 -4
- package/dist/daemon/auth/service-jwt-strategy.d.ts +2 -1
- package/dist/daemon/auth/service-jwt-strategy.d.ts.map +1 -1
- package/dist/daemon/auth/service-jwt-strategy.js +141 -3
- package/dist/daemon/auth/token-invalidation.d.ts +11 -0
- package/dist/daemon/auth/token-invalidation.d.ts.map +1 -0
- package/dist/daemon/auth/token-invalidation.js +38 -0
- package/dist/daemon/auth/user-redaction.d.ts +12 -0
- package/dist/daemon/auth/user-redaction.d.ts.map +1 -0
- package/dist/daemon/auth/user-redaction.js +13 -0
- package/dist/daemon/declarations.d.ts +5 -4
- package/dist/daemon/declarations.d.ts.map +1 -1
- package/dist/daemon/hooks/gateway-route.d.ts.map +1 -1
- package/dist/daemon/hooks/gateway-route.js +23 -13
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +8271 -2956
- package/dist/daemon/knowledge/pgvector.d.ts +3 -3
- package/dist/daemon/knowledge/pgvector.d.ts.map +1 -1
- package/dist/daemon/knowledge/pgvector.js +24 -0
- package/dist/daemon/knowledge/units.d.ts +2 -2
- package/dist/daemon/knowledge/units.d.ts.map +1 -1
- package/dist/daemon/main.js +8271 -2956
- package/dist/daemon/mcp/server.d.ts +3 -3
- package/dist/daemon/mcp/server.d.ts.map +1 -1
- package/dist/daemon/mcp/server.js +1740 -81
- package/dist/daemon/mcp/tokens.d.ts +2 -2
- package/dist/daemon/mcp/tokens.d.ts.map +1 -1
- package/dist/daemon/mcp/tokens.js +5 -1
- package/dist/daemon/mcp/tool-registry.d.ts.map +1 -1
- package/dist/daemon/mcp/tool-registry.js +1 -0
- package/dist/daemon/mcp/tools/analytics.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/analytics.js +598 -24
- package/dist/daemon/mcp/tools/artifacts.js +560 -20
- package/dist/daemon/mcp/tools/boards.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/boards.js +567 -21
- package/dist/daemon/mcp/tools/branches.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/branches.js +624 -50
- package/dist/daemon/mcp/tools/card-types.js +558 -18
- package/dist/daemon/mcp/tools/cards.js +558 -18
- package/dist/daemon/mcp/tools/environment.js +566 -18
- package/dist/daemon/mcp/tools/gateway-channels.d.ts +4 -0
- package/dist/daemon/mcp/tools/gateway-channels.d.ts.map +1 -0
- package/dist/daemon/mcp/tools/gateway-channels.js +16187 -0
- package/dist/daemon/mcp/tools/knowledge.js +558 -18
- package/dist/daemon/mcp/tools/mcp-servers.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/mcp-servers.js +893 -18
- package/dist/daemon/mcp/tools/messages.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/messages.js +618 -32
- package/dist/daemon/mcp/tools/proxies.js +568 -20
- package/dist/daemon/mcp/tools/repos.js +558 -18
- package/dist/daemon/mcp/tools/schedules.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/schedules.js +561 -19
- package/dist/daemon/mcp/tools/search.js +558 -18
- package/dist/daemon/mcp/tools/sessions.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/sessions.js +571 -24
- package/dist/daemon/mcp/tools/tasks.js +558 -18
- package/dist/daemon/mcp/tools/users.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/users.js +577 -23
- package/dist/daemon/mcp/tools/widgets.d.ts.map +1 -1
- package/dist/daemon/mcp/tools/widgets.js +759 -83
- 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 +4 -2
- package/dist/daemon/register-hooks.d.ts.map +1 -1
- package/dist/daemon/register-hooks.js +1158 -595
- package/dist/daemon/register-routes.d.ts +3 -2
- package/dist/daemon/register-routes.d.ts.map +1 -1
- package/dist/daemon/register-routes.js +3161 -812
- package/dist/daemon/register-services.d.ts +2 -2
- package/dist/daemon/register-services.d.ts.map +1 -1
- package/dist/daemon/register-services.js +2782 -739
- package/dist/daemon/services/artifacts.d.ts +34 -6
- package/dist/daemon/services/artifacts.d.ts.map +1 -1
- package/dist/daemon/services/artifacts.js +109 -8
- package/dist/daemon/services/assistant-knowledge.d.ts +2 -2
- package/dist/daemon/services/assistant-knowledge.d.ts.map +1 -1
- package/dist/daemon/services/board-comments.d.ts +8 -5
- package/dist/daemon/services/board-comments.d.ts.map +1 -1
- package/dist/daemon/services/board-comments.js +78 -13
- package/dist/daemon/services/board-objects.d.ts +8 -5
- package/dist/daemon/services/board-objects.d.ts.map +1 -1
- package/dist/daemon/services/board-objects.js +14 -4
- package/dist/daemon/services/boards.d.ts +39 -5
- package/dist/daemon/services/boards.d.ts.map +1 -1
- package/dist/daemon/services/boards.js +123 -8
- package/dist/daemon/services/branch-owners.d.ts +3 -1
- package/dist/daemon/services/branch-owners.d.ts.map +1 -1
- package/dist/daemon/services/branch-owners.js +31 -4
- package/dist/daemon/services/branches.d.ts +31 -8
- package/dist/daemon/services/branches.d.ts.map +1 -1
- package/dist/daemon/services/branches.js +272 -36
- package/dist/daemon/services/card-types.d.ts +3 -3
- package/dist/daemon/services/card-types.d.ts.map +1 -1
- package/dist/daemon/services/card-types.js +68 -7
- package/dist/daemon/services/cards.d.ts +19 -4
- package/dist/daemon/services/cards.d.ts.map +1 -1
- package/dist/daemon/services/cards.js +92 -8
- package/dist/daemon/services/check-auth.d.ts +2 -2
- package/dist/daemon/services/check-auth.d.ts.map +1 -1
- package/dist/daemon/services/claude-cli-integration.d.ts +4 -1
- package/dist/daemon/services/claude-cli-integration.d.ts.map +1 -1
- package/dist/daemon/services/claude-cli-integration.js +117 -65
- package/dist/daemon/services/claude-models.d.ts +3 -3
- package/dist/daemon/services/claude-models.d.ts.map +1 -1
- package/dist/daemon/services/claude-models.js +387 -273
- package/dist/daemon/services/config.d.ts +12 -4
- package/dist/daemon/services/config.d.ts.map +1 -1
- package/dist/daemon/services/config.js +39 -3
- package/dist/daemon/services/copilot-models.d.ts +3 -3
- package/dist/daemon/services/copilot-models.d.ts.map +1 -1
- package/dist/daemon/services/cursor-models.d.ts +3 -3
- package/dist/daemon/services/cursor-models.d.ts.map +1 -1
- package/dist/daemon/services/files.d.ts +3 -3
- package/dist/daemon/services/files.d.ts.map +1 -1
- package/dist/daemon/services/files.js +24 -5
- package/dist/daemon/services/gateway-channels-test.d.ts +24 -0
- package/dist/daemon/services/gateway-channels-test.d.ts.map +1 -0
- package/dist/daemon/services/gateway-channels-test.js +66 -0
- package/dist/daemon/services/gateway-channels.d.ts +3 -3
- package/dist/daemon/services/gateway-channels.d.ts.map +1 -1
- package/dist/daemon/services/gateway-channels.js +68 -7
- package/dist/daemon/services/gateway.d.ts +63 -3
- package/dist/daemon/services/gateway.d.ts.map +1 -1
- package/dist/daemon/services/gateway.js +640 -60
- package/dist/daemon/services/github-app-setup.d.ts +3 -3
- package/dist/daemon/services/github-app-setup.d.ts.map +1 -1
- package/dist/daemon/services/groups.d.ts +5 -5
- package/dist/daemon/services/groups.d.ts.map +1 -1
- package/dist/daemon/services/health-monitor.d.ts +34 -2
- package/dist/daemon/services/health-monitor.d.ts.map +1 -1
- package/dist/daemon/services/health-monitor.js +155 -30
- package/dist/daemon/services/knowledge-document-edits.d.ts +3 -3
- package/dist/daemon/services/knowledge-document-edits.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-documents.d.ts +3 -3
- package/dist/daemon/services/knowledge-documents.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-documents.js +92 -7
- package/dist/daemon/services/knowledge-embedding-indexer.d.ts +7 -2
- package/dist/daemon/services/knowledge-embedding-indexer.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-embedding-indexer.js +37 -3
- package/dist/daemon/services/knowledge-graph.d.ts +3 -3
- package/dist/daemon/services/knowledge-graph.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-indexing.d.ts +3 -3
- package/dist/daemon/services/knowledge-indexing.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-namespaces.d.ts +3 -3
- package/dist/daemon/services/knowledge-namespaces.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-namespaces.js +72 -8
- package/dist/daemon/services/knowledge-reindex.d.ts +3 -3
- package/dist/daemon/services/knowledge-reindex.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-reindex.js +28 -1
- package/dist/daemon/services/knowledge-search.d.ts +3 -3
- package/dist/daemon/services/knowledge-search.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-settings.d.ts +3 -3
- package/dist/daemon/services/knowledge-settings.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-settings.js +24 -0
- package/dist/daemon/services/knowledge-versions.d.ts +3 -3
- package/dist/daemon/services/knowledge-versions.d.ts.map +1 -1
- package/dist/daemon/services/knowledge-versions.js +68 -7
- package/dist/daemon/services/leaderboard.d.ts +14 -6
- package/dist/daemon/services/leaderboard.d.ts.map +1 -1
- package/dist/daemon/services/leaderboard.js +74 -15
- package/dist/daemon/services/local-actions.d.ts +13 -0
- package/dist/daemon/services/local-actions.d.ts.map +1 -0
- package/dist/daemon/services/local-actions.js +120 -0
- package/dist/daemon/services/mcp-servers.d.ts +3 -3
- package/dist/daemon/services/mcp-servers.d.ts.map +1 -1
- package/dist/daemon/services/mcp-servers.js +68 -7
- package/dist/daemon/services/messages.d.ts +10 -6
- package/dist/daemon/services/messages.d.ts.map +1 -1
- package/dist/daemon/services/messages.js +87 -7
- package/dist/daemon/services/repos.d.ts +6 -6
- package/dist/daemon/services/repos.d.ts.map +1 -1
- package/dist/daemon/services/repos.js +131 -32
- package/dist/daemon/services/scheduler.d.ts +23 -27
- package/dist/daemon/services/scheduler.d.ts.map +1 -1
- package/dist/daemon/services/scheduler.js +55 -28
- package/dist/daemon/services/schedules.d.ts +3 -3
- package/dist/daemon/services/schedules.d.ts.map +1 -1
- package/dist/daemon/services/schedules.js +68 -7
- package/dist/daemon/services/session-env-selections.d.ts +3 -3
- package/dist/daemon/services/session-env-selections.d.ts.map +1 -1
- package/dist/daemon/services/session-mcp-servers.d.ts +3 -3
- package/dist/daemon/services/session-mcp-servers.d.ts.map +1 -1
- 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 +11 -4
- package/dist/daemon/services/sessions.d.ts +9 -5
- package/dist/daemon/services/sessions.d.ts.map +1 -1
- package/dist/daemon/services/sessions.js +143 -10
- package/dist/daemon/services/tasks.d.ts +11 -5
- package/dist/daemon/services/tasks.d.ts.map +1 -1
- package/dist/daemon/services/tasks.js +199 -39
- package/dist/daemon/services/terminals.d.ts +21 -3
- package/dist/daemon/services/terminals.d.ts.map +1 -1
- package/dist/daemon/services/terminals.js +81 -25
- package/dist/daemon/services/thread-session-map.d.ts +3 -3
- package/dist/daemon/services/thread-session-map.d.ts.map +1 -1
- package/dist/daemon/services/thread-session-map.js +68 -7
- package/dist/daemon/services/user-avatar-sync.d.ts +21 -0
- package/dist/daemon/services/user-avatar-sync.d.ts.map +1 -0
- package/dist/daemon/services/user-avatar-sync.js +267 -0
- package/dist/daemon/services/users.d.ts +29 -9
- package/dist/daemon/services/users.d.ts.map +1 -1
- package/dist/daemon/services/users.js +383 -30
- package/dist/daemon/services/zone-trigger.d.ts.map +1 -1
- package/dist/daemon/services/zone-trigger.js +17 -4
- package/dist/daemon/setup/build-info.d.ts +1 -1
- package/dist/daemon/setup/build-info.d.ts.map +1 -1
- package/dist/daemon/setup/build-info.js +5 -1
- package/dist/daemon/setup/database.d.ts +8 -3
- package/dist/daemon/setup/database.d.ts.map +1 -1
- package/dist/daemon/setup/database.js +26 -6
- package/dist/daemon/setup/first-run-admin.d.ts +2 -2
- package/dist/daemon/setup/first-run-admin.d.ts.map +1 -1
- package/dist/daemon/setup/index.js +137 -25
- package/dist/daemon/setup/socketio.d.ts +10 -1
- package/dist/daemon/setup/socketio.d.ts.map +1 -1
- package/dist/daemon/setup/socketio.js +108 -18
- package/dist/daemon/startup.d.ts +13 -2
- package/dist/daemon/startup.d.ts.map +1 -1
- package/dist/daemon/startup.js +377 -94
- package/dist/daemon/utils/append-system-message.d.ts +2 -2
- package/dist/daemon/utils/append-system-message.d.ts.map +1 -1
- package/dist/daemon/utils/apply-session-config-defaults.d.ts.map +1 -1
- package/dist/daemon/utils/apply-session-config-defaults.js +12 -1
- package/dist/daemon/utils/authorization.d.ts +3 -1
- package/dist/daemon/utils/authorization.d.ts.map +1 -1
- package/dist/daemon/utils/authorization.js +36 -7
- package/dist/daemon/utils/branch-authorization.d.ts +30 -0
- package/dist/daemon/utils/branch-authorization.d.ts.map +1 -1
- package/dist/daemon/utils/branch-authorization.js +63 -5
- package/dist/daemon/utils/branch-inspect.d.ts +1 -0
- package/dist/daemon/utils/branch-inspect.d.ts.map +1 -1
- package/dist/daemon/utils/branch-inspect.js +11 -3
- 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/executor-read-impersonation.d.ts +2 -2
- package/dist/daemon/utils/executor-read-impersonation.d.ts.map +1 -1
- package/dist/daemon/utils/git-impersonation.d.ts +10 -10
- package/dist/daemon/utils/git-impersonation.d.ts.map +1 -1
- package/dist/daemon/utils/git-remote-credential-scan.d.ts +3 -3
- package/dist/daemon/utils/git-remote-credential-scan.d.ts.map +1 -1
- package/dist/daemon/utils/git-remote-credential-scan.js +6 -2
- 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/mcp-token-authorization.d.ts +18 -13
- package/dist/daemon/utils/mcp-token-authorization.d.ts.map +1 -1
- package/dist/daemon/utils/mcp-token-authorization.js +11 -5
- package/dist/daemon/utils/open-source-telemetry-config.d.ts +6 -0
- package/dist/daemon/utils/open-source-telemetry-config.d.ts.map +1 -0
- package/dist/daemon/utils/open-source-telemetry-config.js +21 -0
- package/dist/daemon/utils/open-source-telemetry-heartbeat.d.ts +7 -0
- package/dist/daemon/utils/open-source-telemetry-heartbeat.d.ts.map +1 -0
- package/dist/daemon/utils/open-source-telemetry-heartbeat.js +15 -0
- package/dist/daemon/utils/open-source-telemetry-usage.d.ts +9 -0
- package/dist/daemon/utils/open-source-telemetry-usage.d.ts.map +1 -0
- package/dist/daemon/utils/open-source-telemetry-usage.js +121 -0
- package/dist/daemon/utils/realign-repo-origin.d.ts +3 -3
- package/dist/daemon/utils/realign-repo-origin.d.ts.map +1 -1
- package/dist/daemon/utils/realign-repo-origin.js +47 -16
- 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 +26 -0
- package/dist/daemon/utils/realtime-publish.d.ts.map +1 -1
- package/dist/daemon/utils/realtime-publish.js +171 -12
- 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/utils/session-state-hooks.d.ts +3 -3
- package/dist/daemon/utils/session-state-hooks.d.ts.map +1 -1
- package/dist/daemon/utils/session-turn-lock.d.ts +8 -1
- package/dist/daemon/utils/session-turn-lock.d.ts.map +1 -1
- package/dist/daemon/utils/session-turn-lock.js +25 -2
- package/dist/daemon/utils/spawn-executor.d.ts +23 -1
- package/dist/daemon/utils/spawn-executor.d.ts.map +1 -1
- package/dist/daemon/utils/spawn-executor.js +34 -4
- package/dist/daemon/utils/tenant-db-scope.d.ts +20 -0
- package/dist/daemon/utils/tenant-db-scope.d.ts.map +1 -0
- package/dist/daemon/utils/tenant-db-scope.js +114 -0
- package/dist/daemon/utils/unix-group-init.d.ts +3 -3
- package/dist/daemon/utils/unix-group-init.d.ts.map +1 -1
- package/dist/daemon/utils/upload.d.ts +6 -9
- package/dist/daemon/utils/upload.d.ts.map +1 -1
- package/dist/daemon/utils/upload.js +30 -37
- package/dist/daemon/widgets/env-vars/index.d.ts +26 -1
- package/dist/daemon/widgets/env-vars/index.d.ts.map +1 -1
- package/dist/daemon/widgets/env-vars/index.js +145 -21
- 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 +327 -37
- 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/environment.d.ts.map +1 -1
- package/dist/executor/commands/environment.js +9 -5
- package/dist/executor/commands/git.d.ts.map +1 -1
- package/dist/executor/commands/git.js +3 -1
- 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/git/index.d.ts +8 -0
- package/dist/executor/git/index.d.ts.map +1 -0
- package/dist/executor/git/index.js +7 -0
- package/dist/executor/handlers/sdk/base-executor.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/base-executor.js +4 -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/git-safe-directory.d.ts.map +1 -1
- package/dist/executor/handlers/sdk/git-safe-directory.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/diff-enrichment.js +1 -1
- 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 +8 -12
- package/dist/executor/sdk-handlers/codex/codex-tool.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/codex/codex-tool.js +14 -17
- package/dist/executor/sdk-handlers/codex/normalizer.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/codex/normalizer.js +11 -1
- package/dist/executor/sdk-handlers/codex/pricing/litellm-openai-model-prices.json +3663 -0
- package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.d.ts +31 -0
- package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.d.ts.map +1 -0
- package/dist/executor/sdk-handlers/codex/pricing/litellm-pricing.js +46 -0
- 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 +131 -12
- package/dist/executor/sdk-handlers/codex/usage.d.ts +14 -23
- package/dist/executor/sdk-handlers/codex/usage.d.ts.map +1 -1
- package/dist/executor/sdk-handlers/codex/usage.js +18 -33
- 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 +124 -25
- package/dist/git/index.cjs +1101 -0
- package/dist/git/index.d.ts +533 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +1022 -0
- package/dist/git/package.json +21 -0
- package/dist/git/pure.cjs +185 -0
- package/dist/git/pure.d.ts +39 -0
- package/dist/git/pure.d.ts.map +1 -0
- package/dist/git/pure.js +139 -0
- 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-DjzXcP_L.js +1 -0
- 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-HmSdTLW5.js +7 -0
- 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-NNoyPA81.js +2 -0
- 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-zv5RUCuV.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-mEmYGZhC.css → SessionCanvas-Bh7Yg5dZ.css} +1 -1
- package/dist/ui/assets/SessionCanvas-Bh7Yg5dZ.css.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-wzWaqWwr.js → StreamdownDemoPage-CvWLzVsv.js} +2 -2
- package/dist/ui/assets/StreamdownDemoPage-CvWLzVsv.js.gz +0 -0
- package/dist/ui/assets/TerminalModal-ExOgsuOP.js +2 -0
- 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-rpCN9S6K.js +1 -0
- package/dist/ui/assets/{antd-CfbbHJOz.js → antd-BCqimh1J.js} +5 -5
- package/dist/ui/assets/{antd-CfbbHJOz.js.gz → antd-BCqimh1J.js.gz} +0 -0
- package/dist/ui/assets/architecture-U656AL7Q-BxSQIjrE.js +1 -0
- package/dist/ui/assets/architectureDiagram-VXUJARFQ-pDpGHSqT.js +36 -0
- package/dist/ui/assets/architectureDiagram-VXUJARFQ-pDpGHSqT.js.gz +0 -0
- package/dist/ui/assets/{blockDiagram-VD42YOAC-BhZaEN19.js → blockDiagram-VD42YOAC-uP8JTJpK.js} +4 -4
- package/dist/ui/assets/blockDiagram-VD42YOAC-uP8JTJpK.js.gz +0 -0
- package/dist/ui/assets/{c4Diagram-YG6GDRKO-Dk_UH-sY.js → c4Diagram-YG6GDRKO-qQe72Mm7.js} +2 -2
- 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-XprbG2TG.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-BJcrryHK.js → chunk-ABZYJK2D-t3Gkphds.js} +3 -3
- package/dist/ui/assets/chunk-ABZYJK2D-t3Gkphds.js.gz +0 -0
- package/dist/ui/assets/{chunk-AGHRB4JF-DvxmfbM0.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-DbeJ0OrR.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-C53q2ggf.js → chunk-B4BG7PRW-dnSEE1u-.js} +3 -3
- package/dist/ui/assets/chunk-B4BG7PRW-dnSEE1u-.js.gz +0 -0
- package/dist/ui/assets/{chunk-CVBHYZKI-B3EBSlb3.js → chunk-CVBHYZKI-BStaYnF0.js} +1 -1
- package/dist/ui/assets/{chunk-DI55MBZ5-vIyNEQN-.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-rddmfK-Z.js → chunk-FMBD7UC4-C_63gC9S.js} +1 -1
- package/dist/ui/assets/{chunk-HN2XXSSU-Dttqcg3b.js → chunk-HN2XXSSU-UFD374KI.js} +1 -1
- package/dist/ui/assets/chunk-HN2XXSSU-UFD374KI.js.gz +0 -0
- package/dist/ui/assets/chunk-JA3XYJ7Z-B60hLNeR.js +11 -0
- package/dist/ui/assets/chunk-JA3XYJ7Z-B60hLNeR.js.gz +0 -0
- package/dist/ui/assets/{chunk-JZLCHNYA-EUmx2y4H.js → chunk-JZLCHNYA-ButC6pwN.js} +5 -5
- package/dist/ui/assets/chunk-JZLCHNYA-ButC6pwN.js.gz +0 -0
- package/dist/ui/assets/{chunk-MI3HLSF2-65n9Mkyc.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-DsRKK6NR.js → chunk-QN33PNHL-tXtHZpaG.js} +1 -1
- package/dist/ui/assets/{chunk-QXUST7PY-BCYnMiS3.js → chunk-QXUST7PY-DATib_Vv.js} +2 -2
- 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-BEtfmflI.js +2 -0
- package/dist/ui/assets/chunk-S3R3BYOJ-BEtfmflI.js.gz +0 -0
- package/dist/ui/assets/{chunk-TZMSLE5B-BuQUQcTr.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-CnPB3ARO.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-DhS-k_Se.js → dagre-6UL2VRFP-D800J6qb.js} +1 -1
- package/dist/ui/assets/dagre-6UL2VRFP-D800J6qb.js.gz +0 -0
- package/dist/ui/assets/{dagre-KgLoHEuy.js → dagre-TNc4wezg.js} +1 -1
- package/dist/ui/assets/dagre-TNc4wezg.js.gz +0 -0
- package/dist/ui/assets/diagram-PSM6KHXK-CGdP9F-X.js +24 -0
- package/dist/ui/assets/diagram-PSM6KHXK-CGdP9F-X.js.gz +0 -0
- package/dist/ui/assets/{diagram-QEK2KX5R-BPCitvbo.js → diagram-QEK2KX5R-BD5lOCe5.js} +1 -1
- package/dist/ui/assets/diagram-QEK2KX5R-BD5lOCe5.js.gz +0 -0
- package/dist/ui/assets/{diagram-S2PKOQOG-NW4uK6sx.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-Bv3m24sO.js +3 -0
- package/dist/ui/assets/emoji-Bv3m24sO.js.gz +0 -0
- package/dist/ui/assets/{erDiagram-Q2GNP2WA-me1fboaf.js → erDiagram-Q2GNP2WA-CQSXRgqr.js} +2 -2
- package/dist/ui/assets/erDiagram-Q2GNP2WA-CQSXRgqr.js.gz +0 -0
- package/dist/ui/assets/flowDiagram-NV44I4VS-CKcKpkph.js +162 -0
- package/dist/ui/assets/flowDiagram-NV44I4VS-CKcKpkph.js.gz +0 -0
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-DlAHzXO5.js +267 -0
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-DlAHzXO5.js.gz +0 -0
- package/dist/ui/assets/{gitGraph-F6HP7TQM-CfFE_uAC.js → gitGraph-F6HP7TQM-DeuXy4B1.js} +1 -1
- package/dist/ui/assets/gitGraphDiagram-NY62KEGX-aB-AI4Vq.js +65 -0
- 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/{index-DxuPq13l.css → index-qkT7Qqm2.css} +1 -1
- package/dist/ui/assets/index-qkT7Qqm2.css.gz +0 -0
- package/dist/ui/assets/{info-NVLQJR56-i_xHYg3f.js → info-NVLQJR56-B9PG7xsc.js} +1 -1
- package/dist/ui/assets/{infoDiagram-ER5ION4S-2NL93b78.js → infoDiagram-ER5ION4S-C5Wpoqim.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-CZF-2DHU.js → journeyDiagram-XKPGCS4Q-CHLziqfS.js} +3 -3
- package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CHLziqfS.js.gz +0 -0
- package/dist/ui/assets/{kanban-definition-3W4ZIXB7-CfvJIOny.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-DDv8kOJk.js → line-DHKNg83I.js} +1 -1
- package/dist/ui/assets/{linear-Daef-l29.js → linear-BvUfn0I8.js} +1 -1
- package/dist/ui/assets/linear-BvUfn0I8.js.gz +0 -0
- package/dist/ui/assets/{mermaid-parser.core-CdK9QgYV.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-CxE5KezR.js +11 -0
- package/dist/ui/assets/mermaid.core-CxE5KezR.js.gz +0 -0
- package/dist/ui/assets/{mindmap-definition-VGOIOE7T-Cb3QMflX.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-Bm2uwz4i.js → packet-BFZMPI3H-JZEkVZxU.js} +1 -1
- package/dist/ui/assets/{particles-DsJFOarW.js → particles-CxMmUw86.js} +1 -1
- package/dist/ui/assets/particles-CxMmUw86.js.gz +0 -0
- package/dist/ui/assets/{pie-7BOR55EZ-5i17tVnF.js → pie-7BOR55EZ-_1II5pYQ.js} +1 -1
- package/dist/ui/assets/{pieDiagram-ADFJNKIX-BxIwQWvw.js → pieDiagram-ADFJNKIX-DrNkH33i.js} +1 -1
- package/dist/ui/assets/pieDiagram-ADFJNKIX-DrNkH33i.js.gz +0 -0
- package/dist/ui/assets/{quadrantDiagram-AYHSOK5B-B5HPe4ga.js → quadrantDiagram-AYHSOK5B-DOpC-HEF.js} +3 -3
- package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DOpC-HEF.js.gz +0 -0
- package/dist/ui/assets/{radar-NHE76QYJ-BTn-tq0k.js → radar-NHE76QYJ-DDmqhzEZ.js} +1 -1
- package/dist/ui/assets/reactflow-D98uPOMq.js +2 -0
- package/dist/ui/assets/reactflow-D98uPOMq.js.gz +0 -0
- package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-YfI6llkX.js → requirementDiagram-UZGBJVZJ-Bzx0iEPP.js} +1 -1
- package/dist/ui/assets/requirementDiagram-UZGBJVZJ-Bzx0iEPP.js.gz +0 -0
- package/dist/ui/assets/{sandpack-D7koO5op.js → sandpack-059Z4UWP.js} +38 -38
- 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-Do9pvfDv.js +10 -0
- package/dist/ui/assets/sankeyDiagram-TZEHDZUN-Do9pvfDv.js.gz +0 -0
- package/dist/ui/assets/{sequenceDiagram-WL72ISMW-DAe4Um17.js → sequenceDiagram-WL72ISMW-CN8neUTA.js} +6 -6
- package/dist/ui/assets/sequenceDiagram-WL72ISMW-CN8neUTA.js.gz +0 -0
- package/dist/ui/assets/src-DEbsv3pp.js +34 -0
- package/dist/ui/assets/src-DEbsv3pp.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-FKZM4ZOC-BluWJi8n.js +1 -0
- 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-BT1twtFc.js +521 -0
- package/dist/ui/assets/streamdown-BT1twtFc.js.gz +0 -0
- package/dist/ui/assets/syntax-CBu6nLfm.js +9 -0
- package/dist/ui/assets/syntax-CBu6nLfm.js.gz +0 -0
- package/dist/ui/assets/{timeline-definition-IT6M3QCI-D6P5txjT.js → timeline-definition-IT6M3QCI-WdUNkiRj.js} +16 -16
- package/dist/ui/assets/timeline-definition-IT6M3QCI-WdUNkiRj.js.gz +0 -0
- package/dist/ui/assets/{treemap-KMMF4GRG-Bitm3gy4.js → treemap-KMMF4GRG-CoriU4Jl.js} +1 -1
- package/dist/ui/assets/{useUserLocalStorage-Ckb8HsIw.js → useUserLocalStorage-GidNiOPC.js} +1 -1
- package/dist/ui/assets/useUserLocalStorage-GidNiOPC.js.gz +0 -0
- package/dist/ui/assets/{xychartDiagram-PRI3JC2R-CsybjUbd.js → xychartDiagram-PRI3JC2R-CgBAKNt2.js} +1 -1
- package/dist/ui/assets/xychartDiagram-PRI3JC2R-CgBAKNt2.js.gz +0 -0
- package/dist/ui/index.html +11 -11
- package/dist/ui/index.html.gz +0 -0
- package/package.json +6 -5
- package/scripts/postinstall.js +27 -19
- package/dist/cli/commands/daemon/sync.d.ts.map +0 -1
- package/dist/ui/assets/App-DcEY8Ota.js +0 -3
- package/dist/ui/assets/App-DcEY8Ota.js.gz +0 -0
- package/dist/ui/assets/ArtifactConsentModal-CiCbK9iv.js +0 -1
- package/dist/ui/assets/ArtifactConsentModal-CiCbK9iv.js.gz +0 -0
- package/dist/ui/assets/ArtifactFullscreenPage-CfsTEGKd.js +0 -9
- package/dist/ui/assets/ArtifactFullscreenPage-CfsTEGKd.js.gz +0 -0
- package/dist/ui/assets/AutocompleteTextarea-BAFFH_5e.js +0 -18
- package/dist/ui/assets/AutocompleteTextarea-BAFFH_5e.js.gz +0 -0
- package/dist/ui/assets/BoardObjectNodes-D-O6bZIG.js +0 -34
- package/dist/ui/assets/BoardObjectNodes-D-O6bZIG.js.gz +0 -0
- package/dist/ui/assets/CodeEditor.inner-DBgsP4tn.js +0 -8
- package/dist/ui/assets/CodeEditor.inner-DBgsP4tn.js.gz +0 -0
- package/dist/ui/assets/ConversationView-CUWR0gR6.js +0 -1
- package/dist/ui/assets/ConversationView-CUWR0gR6.js.gz +0 -0
- package/dist/ui/assets/KnowledgePage-B2bzlXfn.js +0 -24
- package/dist/ui/assets/KnowledgePage-B2bzlXfn.js.gz +0 -0
- package/dist/ui/assets/MarketingScreenshotPage-zv5RUCuV.js.gz +0 -0
- package/dist/ui/assets/MobileApp-VgVnsnsN.js +0 -1
- package/dist/ui/assets/MobileApp-VgVnsnsN.js.gz +0 -0
- package/dist/ui/assets/SessionCanvas-f1-1Gbcw.js +0 -20
- package/dist/ui/assets/SessionCanvas-f1-1Gbcw.js.gz +0 -0
- package/dist/ui/assets/SessionCanvas-mEmYGZhC.css.gz +0 -0
- package/dist/ui/assets/StreamdownDemoPage-wzWaqWwr.js.gz +0 -0
- package/dist/ui/assets/ThemeSwitcher-Dly2y9pi.js +0 -1
- package/dist/ui/assets/ThemeSwitcher-Dly2y9pi.js.gz +0 -0
- package/dist/ui/assets/architecture-U656AL7Q-CykGFbQU.js +0 -1
- package/dist/ui/assets/architectureDiagram-VXUJARFQ-C8HXAenz.js +0 -36
- package/dist/ui/assets/architectureDiagram-VXUJARFQ-C8HXAenz.js.gz +0 -0
- package/dist/ui/assets/blockDiagram-VD42YOAC-BhZaEN19.js.gz +0 -0
- package/dist/ui/assets/c4Diagram-YG6GDRKO-Dk_UH-sY.js.gz +0 -0
- package/dist/ui/assets/channel-D6_nUWlW.js +0 -1
- package/dist/ui/assets/chunk-55IACEB6-ByzqIgSb.js +0 -1
- package/dist/ui/assets/chunk-ABZYJK2D-BJcrryHK.js.gz +0 -0
- package/dist/ui/assets/chunk-AGHRB4JF-DvxmfbM0.js.gz +0 -0
- package/dist/ui/assets/chunk-ATLVNIR6-DbeJ0OrR.js.gz +0 -0
- package/dist/ui/assets/chunk-B4BG7PRW-C53q2ggf.js.gz +0 -0
- package/dist/ui/assets/chunk-DI55MBZ5-vIyNEQN-.js.gz +0 -0
- package/dist/ui/assets/chunk-EXTU4WIE-B3ObkuOm.js +0 -1
- package/dist/ui/assets/chunk-HN2XXSSU-Dttqcg3b.js.gz +0 -0
- package/dist/ui/assets/chunk-JA3XYJ7Z-DbNDev3D.js +0 -11
- package/dist/ui/assets/chunk-JA3XYJ7Z-DbNDev3D.js.gz +0 -0
- package/dist/ui/assets/chunk-JZLCHNYA-EUmx2y4H.js.gz +0 -0
- package/dist/ui/assets/chunk-MI3HLSF2-65n9Mkyc.js.gz +0 -0
- package/dist/ui/assets/chunk-N4CR4FBY-mv5koXqW.js +0 -2
- package/dist/ui/assets/chunk-N4CR4FBY-mv5koXqW.js.gz +0 -0
- package/dist/ui/assets/chunk-QXUST7PY-BCYnMiS3.js.gz +0 -0
- package/dist/ui/assets/chunk-QZHKN3VN-HucAw4xW.js +0 -1
- package/dist/ui/assets/chunk-S3R3BYOJ-CWMEa9Dc.js +0 -2
- package/dist/ui/assets/chunk-S3R3BYOJ-CWMEa9Dc.js.gz +0 -0
- package/dist/ui/assets/chunk-TZMSLE5B-BuQUQcTr.js.gz +0 -0
- package/dist/ui/assets/classDiagram-2ON5EDUG-CUT3rPTB.js +0 -1
- package/dist/ui/assets/classDiagram-v2-WZHVMYZB-CUT3rPTB.js +0 -1
- package/dist/ui/assets/cose-bilkent-S5V4N54A-CnPB3ARO.js.gz +0 -0
- package/dist/ui/assets/dagre-6UL2VRFP-DhS-k_Se.js.gz +0 -0
- package/dist/ui/assets/dagre-KgLoHEuy.js.gz +0 -0
- package/dist/ui/assets/diagram-PSM6KHXK-BZg3MJmb.js +0 -24
- package/dist/ui/assets/diagram-PSM6KHXK-BZg3MJmb.js.gz +0 -0
- package/dist/ui/assets/diagram-QEK2KX5R-BPCitvbo.js.gz +0 -0
- package/dist/ui/assets/diagram-S2PKOQOG-NW4uK6sx.js.gz +0 -0
- package/dist/ui/assets/editor-CzFWIUw2.js +0 -39
- package/dist/ui/assets/editor-CzFWIUw2.js.gz +0 -0
- package/dist/ui/assets/emoji-Dkz4Zzv_.js +0 -3
- package/dist/ui/assets/emoji-Dkz4Zzv_.js.gz +0 -0
- package/dist/ui/assets/erDiagram-Q2GNP2WA-me1fboaf.js.gz +0 -0
- package/dist/ui/assets/flowDiagram-NV44I4VS-DzE8dGsh.js +0 -162
- package/dist/ui/assets/flowDiagram-NV44I4VS-DzE8dGsh.js.gz +0 -0
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-CFQD09Mi.js +0 -267
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-CFQD09Mi.js.gz +0 -0
- package/dist/ui/assets/gitGraphDiagram-NY62KEGX-CaVoxU4C.js +0 -65
- package/dist/ui/assets/gitGraphDiagram-NY62KEGX-CaVoxU4C.js.gz +0 -0
- package/dist/ui/assets/index-BN5_Qq7R.js +0 -324
- package/dist/ui/assets/index-BN5_Qq7R.js.gz +0 -0
- package/dist/ui/assets/index-DxuPq13l.css.gz +0 -0
- package/dist/ui/assets/journeyDiagram-XKPGCS4Q-CZF-2DHU.js.gz +0 -0
- package/dist/ui/assets/kanban-definition-3W4ZIXB7-CfvJIOny.js.gz +0 -0
- package/dist/ui/assets/katex-CamJ39w1.js +0 -257
- package/dist/ui/assets/katex-CamJ39w1.js.gz +0 -0
- package/dist/ui/assets/linear-Daef-l29.js.gz +0 -0
- package/dist/ui/assets/mermaid-parser.core-CdK9QgYV.js.gz +0 -0
- package/dist/ui/assets/mermaid.core-D6GS9mU-.js +0 -11
- package/dist/ui/assets/mermaid.core-D6GS9mU-.js.gz +0 -0
- package/dist/ui/assets/message-SqLqNYcv.js +0 -36
- package/dist/ui/assets/message-SqLqNYcv.js.gz +0 -0
- package/dist/ui/assets/mindmap-definition-VGOIOE7T-Cb3QMflX.js.gz +0 -0
- package/dist/ui/assets/particles-DsJFOarW.js.gz +0 -0
- package/dist/ui/assets/pieDiagram-ADFJNKIX-BxIwQWvw.js.gz +0 -0
- package/dist/ui/assets/quadrantDiagram-AYHSOK5B-B5HPe4ga.js.gz +0 -0
- package/dist/ui/assets/reactflow-Bf74ngoo.js +0 -2
- package/dist/ui/assets/reactflow-Bf74ngoo.js.gz +0 -0
- package/dist/ui/assets/requirementDiagram-UZGBJVZJ-YfI6llkX.js.gz +0 -0
- package/dist/ui/assets/sandpack-D7koO5op.js.gz +0 -0
- package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DOk_B10B.js +0 -10
- package/dist/ui/assets/sankeyDiagram-TZEHDZUN-DOk_B10B.js.gz +0 -0
- package/dist/ui/assets/sequenceDiagram-WL72ISMW-DAe4Um17.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-FKZM4ZOC-CCesDu_C.js +0 -1
- package/dist/ui/assets/stateDiagram-FKZM4ZOC-CCesDu_C.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-CMlIrsoO.js +0 -1
- package/dist/ui/assets/syntax-C-M-8jOU.js +0 -10
- package/dist/ui/assets/syntax-C-M-8jOU.js.gz +0 -0
- package/dist/ui/assets/theme-BQZdiqwv.js +0 -1
- package/dist/ui/assets/timeline-definition-IT6M3QCI-D6P5txjT.js.gz +0 -0
- package/dist/ui/assets/useUserLocalStorage-Ckb8HsIw.js.gz +0 -0
- package/dist/ui/assets/xychartDiagram-PRI3JC2R-CsybjUbd.js.gz +0 -0
- /package/dist/cli/commands/{admin → local}/sync-unix.d.ts +0 -0
|
@@ -133,6 +133,13 @@ function generateTaskId() {
|
|
|
133
133
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
134
134
|
}
|
|
135
135
|
function findExecutorPath() {
|
|
136
|
+
const configuredPath = process.env.AGOR_EXECUTOR_PATH;
|
|
137
|
+
if (configuredPath) {
|
|
138
|
+
if (!existsSync(configuredPath)) {
|
|
139
|
+
throw new Error(`Configured AGOR_EXECUTOR_PATH does not exist: ${configuredPath}`);
|
|
140
|
+
}
|
|
141
|
+
return configuredPath;
|
|
142
|
+
}
|
|
136
143
|
const dirname = typeof __dirname !== "undefined" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
|
|
137
144
|
const possiblePaths = [
|
|
138
145
|
path.join(dirname, "../executor/cli.js"),
|
|
@@ -243,6 +250,12 @@ function spawnExecutorLocal(payload, options) {
|
|
|
243
250
|
options.onExit?.(127);
|
|
244
251
|
return;
|
|
245
252
|
}
|
|
253
|
+
let reportedExit = false;
|
|
254
|
+
const reportExit = (code) => {
|
|
255
|
+
if (reportedExit) return;
|
|
256
|
+
reportedExit = true;
|
|
257
|
+
options.onExit?.(code);
|
|
258
|
+
};
|
|
246
259
|
const executorProcess = spawn(cmd, args, {
|
|
247
260
|
cwd,
|
|
248
261
|
env: asUser ? void 0 : { ...envWithDaemonUrl },
|
|
@@ -256,6 +269,7 @@ function spawnExecutorLocal(payload, options) {
|
|
|
256
269
|
onSpawn?.(executorProcess);
|
|
257
270
|
executorProcess.on("error", (error) => {
|
|
258
271
|
console.error(`${logPrefix} Spawn error:`, error.message);
|
|
272
|
+
reportExit(127);
|
|
259
273
|
});
|
|
260
274
|
executorProcess.on("exit", (code) => {
|
|
261
275
|
if (code === 0) {
|
|
@@ -263,7 +277,7 @@ function spawnExecutorLocal(payload, options) {
|
|
|
263
277
|
} else {
|
|
264
278
|
console.error(`${logPrefix} Executor exited with code ${code}`);
|
|
265
279
|
}
|
|
266
|
-
|
|
280
|
+
reportExit(code);
|
|
267
281
|
});
|
|
268
282
|
executorProcess.stdin?.write(JSON.stringify(payload));
|
|
269
283
|
executorProcess.stdin?.end();
|
|
@@ -276,6 +290,12 @@ function spawnExecutorWithTemplate(payload, options) {
|
|
|
276
290
|
console.log(`${logPrefix} Task ID: ${templateVariables.task_id}`);
|
|
277
291
|
console.log(`${logPrefix} Command: ${payload.command}`);
|
|
278
292
|
console.log(`${logPrefix} Template command (first 200 chars): ${command.slice(0, 200)}...`);
|
|
293
|
+
let reportedExit = false;
|
|
294
|
+
const reportExit = (code) => {
|
|
295
|
+
if (reportedExit) return;
|
|
296
|
+
reportedExit = true;
|
|
297
|
+
options.onExit?.(code);
|
|
298
|
+
};
|
|
279
299
|
const executorProcess = spawn("sh", ["-c", command], {
|
|
280
300
|
env: { ...process.env, LOG_LEVEL: logLevel },
|
|
281
301
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -289,6 +309,7 @@ function spawnExecutorWithTemplate(payload, options) {
|
|
|
289
309
|
});
|
|
290
310
|
executorProcess.on("error", (error) => {
|
|
291
311
|
console.error(`${logPrefix} Spawn error:`, error.message);
|
|
312
|
+
reportExit(127);
|
|
292
313
|
});
|
|
293
314
|
executorProcess.on("exit", (code) => {
|
|
294
315
|
if (code === 0) {
|
|
@@ -300,7 +321,7 @@ function spawnExecutorWithTemplate(payload, options) {
|
|
|
300
321
|
`${logPrefix} Executor exited with code ${code} (task: ${templateVariables.task_id})`
|
|
301
322
|
);
|
|
302
323
|
}
|
|
303
|
-
|
|
324
|
+
reportExit(code);
|
|
304
325
|
});
|
|
305
326
|
executorProcess.stdin?.write(JSON.stringify(payload));
|
|
306
327
|
executorProcess.stdin?.end();
|
|
@@ -579,12 +600,19 @@ function createServiceToken(jwtSecret, expiresIn, scope = {}) {
|
|
|
579
600
|
expiresIn || "5m"
|
|
580
601
|
);
|
|
581
602
|
}
|
|
582
|
-
function
|
|
603
|
+
function serviceTokenScopeForParams(params) {
|
|
604
|
+
const tenantId = params?.tenant?.tenant_id ?? params?.tenant_id ?? params?.user?.tenant_id;
|
|
605
|
+
return tenantId ? { tenant_id: tenantId } : {};
|
|
606
|
+
}
|
|
607
|
+
function generateSessionToken(app, scope = {}) {
|
|
583
608
|
const jwtSecret = app.settings.authentication?.secret;
|
|
584
609
|
if (!jwtSecret) {
|
|
585
610
|
throw new Error("JWT secret not configured in app settings");
|
|
586
611
|
}
|
|
587
|
-
return createServiceToken(jwtSecret);
|
|
612
|
+
return createServiceToken(jwtSecret, void 0, scope);
|
|
613
|
+
}
|
|
614
|
+
function generateScopedServiceToken(app, params) {
|
|
615
|
+
return generateSessionToken(app, serviceTokenScopeForParams(params));
|
|
588
616
|
}
|
|
589
617
|
var configuredDaemonUrl, configuredExecutorDefaults, EXECUTOR_RESULT_PREFIX, spawnExecutorFireAndForget;
|
|
590
618
|
var init_spawn_executor = __esm({
|
|
@@ -600,12 +628,21 @@ var init_spawn_executor = __esm({
|
|
|
600
628
|
});
|
|
601
629
|
|
|
602
630
|
// src/utils/mcp-token-authorization.ts
|
|
603
|
-
import { hasMinimumRole as
|
|
631
|
+
import { hasMinimumRole as hasMinimumRole6, ROLES as ROLES7 } from "@agor/core/types";
|
|
632
|
+
function hasExplicitMinimumRole(userRole, minimumRole) {
|
|
633
|
+
return !!userRole && hasMinimumRole6(userRole, minimumRole);
|
|
634
|
+
}
|
|
604
635
|
function canReceiveMcpTokenForSession(params) {
|
|
636
|
+
const { callerUserId, callerRole } = params;
|
|
637
|
+
const isServiceExecutor = callerRole === "service";
|
|
638
|
+
const isAuthenticatedMember = !!callerUserId && hasExplicitMinimumRole(callerRole, ROLES7.MEMBER);
|
|
639
|
+
return isAuthenticatedMember || isServiceExecutor;
|
|
640
|
+
}
|
|
641
|
+
function canControlCliSession(params) {
|
|
605
642
|
const { callerUserId, callerRole, sessionCreatedBy } = params;
|
|
606
|
-
const isSuperadmin =
|
|
643
|
+
const isSuperadmin = hasExplicitMinimumRole(callerRole, ROLES7.SUPERADMIN);
|
|
607
644
|
const isServiceExecutor = callerRole === "service";
|
|
608
|
-
const isCreatorMember = !!callerUserId && callerUserId === sessionCreatedBy &&
|
|
645
|
+
const isCreatorMember = !!callerUserId && callerUserId === sessionCreatedBy && hasExplicitMinimumRole(callerRole, ROLES7.MEMBER);
|
|
609
646
|
return isCreatorMember || isSuperadmin || isServiceExecutor;
|
|
610
647
|
}
|
|
611
648
|
var init_mcp_token_authorization = __esm({
|
|
@@ -626,12 +663,16 @@ __export(tokens_exports, {
|
|
|
626
663
|
validateSessionToken: () => validateSessionToken
|
|
627
664
|
});
|
|
628
665
|
import { MCP_TOKEN } from "@agor/core/config";
|
|
629
|
-
import {
|
|
666
|
+
import {
|
|
667
|
+
generateId as generateId2,
|
|
668
|
+
SessionRepository as SessionRepository2,
|
|
669
|
+
shortId as shortId3
|
|
670
|
+
} from "@agor/core/db";
|
|
630
671
|
import {
|
|
631
672
|
MCP_TOKEN_AUDIENCE,
|
|
632
673
|
MCP_TOKEN_ISSUER
|
|
633
674
|
} from "@agor/core/types";
|
|
634
|
-
import
|
|
675
|
+
import jwt4 from "jsonwebtoken";
|
|
635
676
|
import { MCP_TOKEN_AUDIENCE as MCP_TOKEN_AUDIENCE2, MCP_TOKEN_ISSUER as MCP_TOKEN_ISSUER2 } from "@agor/core/types";
|
|
636
677
|
function mcpTokenDebug(...args) {
|
|
637
678
|
if (DEBUG_MCP_TOKENS) {
|
|
@@ -703,7 +744,7 @@ async function generateSessionToken2(app, sessionId, userId) {
|
|
|
703
744
|
exp: expSec,
|
|
704
745
|
jti
|
|
705
746
|
};
|
|
706
|
-
const token =
|
|
747
|
+
const token = jwt4.sign(payload, jwtSecret, { algorithm: "HS256" });
|
|
707
748
|
s.tokenCache.set(cacheKey, { token, expiresAtMs });
|
|
708
749
|
mcpTokenDebug(
|
|
709
750
|
`\u{1F3AB} MCP token issued: session=${shortId3(sessionId)} jti=${jti.substring(0, 8)} exp=+${Math.floor(s.expirationMs / 1e3)}s`
|
|
@@ -719,15 +760,15 @@ async function validateSessionToken(app, token) {
|
|
|
719
760
|
}
|
|
720
761
|
let payload;
|
|
721
762
|
try {
|
|
722
|
-
payload =
|
|
763
|
+
payload = jwt4.verify(token, jwtSecret, {
|
|
723
764
|
audience: MCP_TOKEN_AUDIENCE,
|
|
724
765
|
issuer: MCP_TOKEN_ISSUER,
|
|
725
766
|
algorithms: ["HS256"]
|
|
726
767
|
});
|
|
727
768
|
} catch (err) {
|
|
728
|
-
if (err instanceof
|
|
769
|
+
if (err instanceof jwt4.TokenExpiredError) {
|
|
729
770
|
console.warn("[mcp-tokens] token rejected: expired");
|
|
730
|
-
} else if (err instanceof
|
|
771
|
+
} else if (err instanceof jwt4.JsonWebTokenError) {
|
|
731
772
|
console.warn(`[mcp-tokens] token rejected: ${err.message}`);
|
|
732
773
|
} else {
|
|
733
774
|
console.error("[mcp-tokens] token verify error:", err);
|
|
@@ -1179,6 +1220,7 @@ __export(claude_cli_integration_exports, {
|
|
|
1179
1220
|
rehydrateCliWatchers: () => rehydrateCliWatchers,
|
|
1180
1221
|
resolveClaudeCliMcpConfigTargetUnixUser: () => resolveClaudeCliMcpConfigTargetUnixUser,
|
|
1181
1222
|
resolveHomeDirForCliSession: () => resolveHomeDirForCliSession,
|
|
1223
|
+
scanCliWatcherRehydrateSessions: () => scanCliWatcherRehydrateSessions,
|
|
1182
1224
|
setPendingCliTask: () => setPendingCliTask,
|
|
1183
1225
|
writeClaudeCliMcpConfigFile: () => writeClaudeCliMcpConfigFile,
|
|
1184
1226
|
writeClaudeCliMcpConfigForSession: () => writeClaudeCliMcpConfigForSession
|
|
@@ -1195,8 +1237,12 @@ import {
|
|
|
1195
1237
|
permissionModeForCli,
|
|
1196
1238
|
slugForCwd
|
|
1197
1239
|
} from "@agor/core/claude-cli";
|
|
1240
|
+
import { resolveMultiTenancyConfig as resolveMultiTenancyConfig3 } from "@agor/core/config";
|
|
1198
1241
|
import {
|
|
1199
1242
|
generateId as generateId4,
|
|
1243
|
+
getCurrentTenantId as getCurrentTenantId3,
|
|
1244
|
+
runWithoutTenantDatabaseScope as runWithoutTenantDatabaseScope2,
|
|
1245
|
+
runWithTenantDatabaseScope as runWithTenantDatabaseScope4,
|
|
1200
1246
|
SessionRepository as SessionRepository3,
|
|
1201
1247
|
shortId as shortId4,
|
|
1202
1248
|
TaskRepository
|
|
@@ -1214,6 +1260,22 @@ function getDb(app) {
|
|
|
1214
1260
|
const db = app.get("database") ?? app.get("db");
|
|
1215
1261
|
return db ?? null;
|
|
1216
1262
|
}
|
|
1263
|
+
function getCliFallbackTenantId(app) {
|
|
1264
|
+
const config = app.get("config");
|
|
1265
|
+
return resolveMultiTenancyConfig3(config ?? {}).static_tenant_id;
|
|
1266
|
+
}
|
|
1267
|
+
function captureCliWatcherTenantId(app) {
|
|
1268
|
+
return getCurrentTenantId3() ?? getCliFallbackTenantId(app);
|
|
1269
|
+
}
|
|
1270
|
+
function rememberCliWatcherTenant(sessionId, tenantId) {
|
|
1271
|
+
cliWatcherTenantBySession.set(sessionId, tenantId);
|
|
1272
|
+
}
|
|
1273
|
+
async function runCliCallbackDatabaseScope(app, sessionId, work) {
|
|
1274
|
+
const db = getDb(app);
|
|
1275
|
+
if (!db) return work();
|
|
1276
|
+
const tenantId = cliWatcherTenantBySession.get(sessionId) ?? captureCliWatcherTenantId(app);
|
|
1277
|
+
return runWithTenantDatabaseScope4(db, tenantId, work);
|
|
1278
|
+
}
|
|
1217
1279
|
async function persistActiveTurnSnapshot(app, sessionId, turn) {
|
|
1218
1280
|
const db = getDb(app);
|
|
1219
1281
|
if (!db) return;
|
|
@@ -1287,52 +1349,60 @@ function stopTaskWatchdog(sessionId) {
|
|
|
1287
1349
|
}
|
|
1288
1350
|
function startTaskWatchdog(app, sessionId) {
|
|
1289
1351
|
stopTaskWatchdog(sessionId);
|
|
1290
|
-
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1352
|
+
runWithoutTenantDatabaseScope2(() => {
|
|
1353
|
+
const timer = setInterval(() => {
|
|
1354
|
+
void runCliCallbackDatabaseScope(app, sessionId, async () => {
|
|
1355
|
+
const active = activeCliTurn.get(sessionId);
|
|
1356
|
+
if (!active) {
|
|
1357
|
+
stopTaskWatchdog(sessionId);
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
const idleMs = Date.now() - (Date.parse(active.lastTimestamp) || active.startedAtMs);
|
|
1361
|
+
if (idleMs < WATCHDOG_IDLE_THRESHOLD_MS) return;
|
|
1362
|
+
const alive = await isClaudeRunningFor(sessionId);
|
|
1363
|
+
if (alive) return;
|
|
1364
|
+
console.log(
|
|
1365
|
+
JSON.stringify({
|
|
1366
|
+
layer: "claude-cli-watcher.watchdog",
|
|
1367
|
+
sessionId,
|
|
1368
|
+
idleMs,
|
|
1369
|
+
note: "claude process not running \u2014 closing stale turn"
|
|
1370
|
+
})
|
|
1371
|
+
);
|
|
1372
|
+
try {
|
|
1373
|
+
await closeActiveTurnDispatch?.(sessionId, "claude_exited", (/* @__PURE__ */ new Date()).toISOString());
|
|
1374
|
+
} catch (err) {
|
|
1375
|
+
console.warn("[claude-cli-watcher.watchdog] close dispatch failed", err);
|
|
1376
|
+
}
|
|
1377
|
+
stopTaskWatchdog(sessionId);
|
|
1378
|
+
}).catch((err) => {
|
|
1379
|
+
console.warn("[claude-cli-watcher.watchdog] scoped tick failed", err);
|
|
1380
|
+
});
|
|
1381
|
+
}, WATCHDOG_TICK_MS);
|
|
1382
|
+
timer.unref?.();
|
|
1383
|
+
watchdogTimers.set(sessionId, timer);
|
|
1384
|
+
});
|
|
1317
1385
|
}
|
|
1318
1386
|
function buildCliPersister(app) {
|
|
1319
1387
|
return {
|
|
1320
1388
|
async saveOffset(sessionId, update2) {
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1389
|
+
await runCliCallbackDatabaseScope(app, sessionId, async () => {
|
|
1390
|
+
const db = getDb(app);
|
|
1391
|
+
if (!db) return;
|
|
1392
|
+
const repo = new SessionRepository3(db);
|
|
1393
|
+
const row = await repo.findById(sessionId).catch(() => null);
|
|
1394
|
+
if (!row) return;
|
|
1395
|
+
const existing = row.cli_state ?? {};
|
|
1396
|
+
const patch = {
|
|
1397
|
+
cli_state: {
|
|
1398
|
+
...existing,
|
|
1399
|
+
watcher_offset: update2.watcher_offset,
|
|
1400
|
+
last_event_ts: update2.last_event_ts ?? existing.last_event_ts,
|
|
1401
|
+
last_event_uuid: update2.last_event_uuid ?? existing.last_event_uuid
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
await repo.update(sessionId, patch);
|
|
1405
|
+
});
|
|
1336
1406
|
}
|
|
1337
1407
|
};
|
|
1338
1408
|
}
|
|
@@ -1710,14 +1780,17 @@ function buildCliEventSink(app) {
|
|
|
1710
1780
|
throw err;
|
|
1711
1781
|
}
|
|
1712
1782
|
};
|
|
1783
|
+
const scopedSink = (sessionId, event) => runCliCallbackDatabaseScope(app, sessionId, async () => {
|
|
1784
|
+
await sink(sessionId, event);
|
|
1785
|
+
});
|
|
1713
1786
|
closeActiveTurnDispatch = async (sessionId, _reason, ts) => {
|
|
1714
|
-
await
|
|
1787
|
+
await scopedSink(sessionId, {
|
|
1715
1788
|
type: "turn_end",
|
|
1716
1789
|
messageId: "watchdog-synthetic",
|
|
1717
1790
|
timestamp: ts
|
|
1718
1791
|
});
|
|
1719
1792
|
};
|
|
1720
|
-
return
|
|
1793
|
+
return scopedSink;
|
|
1721
1794
|
}
|
|
1722
1795
|
function resolveHomeDirForCliSession(session) {
|
|
1723
1796
|
if (session.unix_username) {
|
|
@@ -1853,13 +1926,13 @@ function writeClaudeCliMcpConfigFile(params) {
|
|
|
1853
1926
|
async function writeClaudeCliMcpConfigForSession(app, session, opts = {}) {
|
|
1854
1927
|
const config = app.get("config");
|
|
1855
1928
|
if (config?.daemon?.mcpEnabled === false) return void 0;
|
|
1856
|
-
if (opts.actor && !
|
|
1929
|
+
if (opts.actor && !canControlCliSession({
|
|
1857
1930
|
callerUserId: opts.actor.user_id,
|
|
1858
1931
|
callerRole: opts.actor.role,
|
|
1859
1932
|
sessionCreatedBy: session.created_by
|
|
1860
1933
|
})) {
|
|
1861
1934
|
console.warn(
|
|
1862
|
-
`[claude-cli-integration] not writing owner-scoped MCP config for session ${shortId4(session.session_id)}: caller ${opts.actor.user_id ?? "anonymous"}
|
|
1935
|
+
`[claude-cli-integration] not writing owner-scoped MCP config for session ${shortId4(session.session_id)}: caller ${opts.actor.user_id ?? "anonymous"} is not allowed to control the owner-scoped CLI MCP config`
|
|
1863
1936
|
);
|
|
1864
1937
|
return void 0;
|
|
1865
1938
|
}
|
|
@@ -1938,13 +2011,18 @@ async function onCliSessionCreated(app, session, branchCwd) {
|
|
|
1938
2011
|
}
|
|
1939
2012
|
try {
|
|
1940
2013
|
const reg = getCliWatcherRegistry(app);
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2014
|
+
const watcherTenantId = captureCliWatcherTenantId(app);
|
|
2015
|
+
await runWithoutTenantDatabaseScope2(async () => {
|
|
2016
|
+
rememberCliWatcherTenant(session.session_id, watcherTenantId);
|
|
2017
|
+
await reg.register({
|
|
2018
|
+
sessionId: session.session_id,
|
|
2019
|
+
cwd: branchCwd,
|
|
2020
|
+
homeDir,
|
|
2021
|
+
startOffset: session.cli_state?.watcher_offset ?? 0
|
|
2022
|
+
});
|
|
1946
2023
|
});
|
|
1947
2024
|
} catch (err) {
|
|
2025
|
+
cliWatcherTenantBySession.delete(session.session_id);
|
|
1948
2026
|
console.warn(
|
|
1949
2027
|
`[claude-cli-integration] watcher register failed for session ${session.session_id}:`,
|
|
1950
2028
|
err
|
|
@@ -1974,30 +2052,37 @@ async function onCliSessionEnded(app, sessionId) {
|
|
|
1974
2052
|
await reg.unregister(sessionId);
|
|
1975
2053
|
stopTaskWatchdog(sessionId);
|
|
1976
2054
|
activeCliTurn.delete(sessionId);
|
|
2055
|
+
cliWatcherTenantBySession.delete(sessionId);
|
|
1977
2056
|
}
|
|
1978
|
-
async function
|
|
2057
|
+
async function scanCliWatcherRehydrateSessions(app) {
|
|
1979
2058
|
const db = getDb(app);
|
|
1980
|
-
if (!db) return;
|
|
2059
|
+
if (!db) return [];
|
|
1981
2060
|
const repo = new SessionRepository3(db);
|
|
1982
|
-
|
|
2061
|
+
return repo.findAll();
|
|
2062
|
+
}
|
|
2063
|
+
async function rehydrateCliWatchers(app, branchCwdLookup, sessions, options) {
|
|
1983
2064
|
const reg = getCliWatcherRegistry(app);
|
|
1984
2065
|
let rehydrated = 0;
|
|
1985
|
-
for (const session of
|
|
2066
|
+
for (const session of sessions) {
|
|
1986
2067
|
if (session.agentic_tool !== "claude-code-cli") continue;
|
|
1987
2068
|
if (session.status === "completed" || session.status === "failed") continue;
|
|
1988
2069
|
if (session.archived) continue;
|
|
1989
2070
|
const cwd = await branchCwdLookup(session.branch_id);
|
|
1990
2071
|
if (!cwd) continue;
|
|
1991
|
-
primeActiveCliTurnFromSession(app, session);
|
|
1992
2072
|
try {
|
|
1993
|
-
await
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
2073
|
+
await runWithoutTenantDatabaseScope2(async () => {
|
|
2074
|
+
rememberCliWatcherTenant(session.session_id, options.tenantId);
|
|
2075
|
+
primeActiveCliTurnFromSession(app, session);
|
|
2076
|
+
await reg.register({
|
|
2077
|
+
sessionId: session.session_id,
|
|
2078
|
+
cwd,
|
|
2079
|
+
homeDir: resolveHomeDirForCliSession(session),
|
|
2080
|
+
startOffset: session.cli_state?.watcher_offset ?? 0
|
|
2081
|
+
});
|
|
1998
2082
|
});
|
|
1999
2083
|
rehydrated++;
|
|
2000
2084
|
} catch (err) {
|
|
2085
|
+
cliWatcherTenantBySession.delete(session.session_id);
|
|
2001
2086
|
console.warn(
|
|
2002
2087
|
`[claude-cli-integration] failed to rehydrate watcher for ${session.session_id}:`,
|
|
2003
2088
|
err
|
|
@@ -2008,7 +2093,7 @@ async function rehydrateCliWatchers(app, branchCwdLookup) {
|
|
|
2008
2093
|
console.log(`[claude-cli-integration] rehydrated ${rehydrated} CLI watcher(s)`);
|
|
2009
2094
|
}
|
|
2010
2095
|
}
|
|
2011
|
-
var activeCliTurn, WATCHDOG_TICK_MS, WATCHDOG_IDLE_THRESHOLD_MS, watchdogTimers, closeActiveTurnDispatch, pendingCliTask, registrySingleton;
|
|
2096
|
+
var cliWatcherTenantBySession, activeCliTurn, WATCHDOG_TICK_MS, WATCHDOG_IDLE_THRESHOLD_MS, watchdogTimers, closeActiveTurnDispatch, pendingCliTask, registrySingleton;
|
|
2012
2097
|
var init_claude_cli_integration = __esm({
|
|
2013
2098
|
"src/services/claude-cli-integration.ts"() {
|
|
2014
2099
|
"use strict";
|
|
@@ -2018,6 +2103,7 @@ var init_claude_cli_integration = __esm({
|
|
|
2018
2103
|
init_spawn_executor();
|
|
2019
2104
|
init_claude_cli_watcher();
|
|
2020
2105
|
init_claude_cli_watcher();
|
|
2106
|
+
cliWatcherTenantBySession = /* @__PURE__ */ new Map();
|
|
2021
2107
|
activeCliTurn = /* @__PURE__ */ new Map();
|
|
2022
2108
|
WATCHDOG_TICK_MS = 6e4;
|
|
2023
2109
|
WATCHDOG_IDLE_THRESHOLD_MS = 9e4;
|
|
@@ -2033,12 +2119,16 @@ import { analyticsLogger } from "@agor/core/analytics";
|
|
|
2033
2119
|
import {
|
|
2034
2120
|
isUnixImpersonationEnabled,
|
|
2035
2121
|
loadConfig,
|
|
2122
|
+
resolveExecutionSecurityMode,
|
|
2123
|
+
resolveMultiTenancyConfig as resolveMultiTenancyConfig4,
|
|
2124
|
+
resolveMultiTenancyDatabaseDialect,
|
|
2125
|
+
resolveTenantContext as resolveTenantContext3,
|
|
2126
|
+
TenantResolutionError as TenantResolutionError3,
|
|
2036
2127
|
validateRepoEnvironment,
|
|
2037
2128
|
wrapV1AsV2
|
|
2038
2129
|
} from "@agor/core/config";
|
|
2039
2130
|
import {
|
|
2040
2131
|
ArtifactRepository,
|
|
2041
|
-
BoardObjectRepository as BoardObjectRepository2,
|
|
2042
2132
|
BoardRepository as BoardRepository2,
|
|
2043
2133
|
ScheduleRepository,
|
|
2044
2134
|
shortId as shortId5,
|
|
@@ -2050,7 +2140,7 @@ import {
|
|
|
2050
2140
|
validateRenderedManagedEnvUrlFields,
|
|
2051
2141
|
validateRepoEnvironmentLifecyclePolicy
|
|
2052
2142
|
} from "@agor/core/environment/webhook";
|
|
2053
|
-
import { BadRequest as
|
|
2143
|
+
import { BadRequest as BadRequest5, Forbidden as Forbidden9, NotAuthenticated as NotAuthenticated8 } from "@agor/core/feathers";
|
|
2054
2144
|
import {
|
|
2055
2145
|
boardCommentQueryValidator,
|
|
2056
2146
|
boardObjectQueryValidator,
|
|
@@ -2063,17 +2153,50 @@ import {
|
|
|
2063
2153
|
typedValidateQuery,
|
|
2064
2154
|
userQueryValidator
|
|
2065
2155
|
} from "@agor/core/lib/feathers-validation";
|
|
2066
|
-
import {
|
|
2156
|
+
import {
|
|
2157
|
+
GATEWAY_REDACTED_SENTINEL,
|
|
2158
|
+
GATEWAY_SENSITIVE_CONFIG_FIELDS,
|
|
2159
|
+
hasMinimumRole as hasMinimumRole9,
|
|
2160
|
+
ROLES as ROLES10
|
|
2161
|
+
} from "@agor/core/types";
|
|
2067
2162
|
|
|
2068
2163
|
// src/auth/executor-runtime-scope.ts
|
|
2069
2164
|
import { Forbidden } from "@agor/core/feathers";
|
|
2165
|
+
|
|
2166
|
+
// src/auth/executor-session-token.ts
|
|
2167
|
+
var EXECUTOR_SESSION_TOKEN_TYPE = "executor-session";
|
|
2168
|
+
var EXECUTOR_SESSION_TOKEN_PURPOSE = "executor-task";
|
|
2169
|
+
function isExecutorSessionTokenPayload(payload) {
|
|
2170
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return false;
|
|
2171
|
+
const record = payload;
|
|
2172
|
+
return record.type === EXECUTOR_SESSION_TOKEN_TYPE && record.purpose === EXECUTOR_SESSION_TOKEN_PURPOSE;
|
|
2173
|
+
}
|
|
2174
|
+
function getExecutorSessionTokenSessionId(payload) {
|
|
2175
|
+
return payload.session_id ?? payload.sessionId;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
// src/auth/executor-runtime-scope.ts
|
|
2070
2179
|
function scopedPayload(context) {
|
|
2071
|
-
const
|
|
2072
|
-
|
|
2073
|
-
if (payload
|
|
2074
|
-
|
|
2180
|
+
const params = context.params;
|
|
2181
|
+
const payload = params.authentication?.payload;
|
|
2182
|
+
if (payload?.type === EXECUTOR_SESSION_TOKEN_TYPE) {
|
|
2183
|
+
if (!isExecutorSessionTokenPayload(payload)) {
|
|
2184
|
+
throw new Forbidden("Executor token is not valid for this request");
|
|
2185
|
+
}
|
|
2186
|
+
return payload;
|
|
2075
2187
|
}
|
|
2076
|
-
|
|
2188
|
+
if (params.authentication?.strategy === "jwt" && params.task_id) {
|
|
2189
|
+
return {
|
|
2190
|
+
type: EXECUTOR_SESSION_TOKEN_TYPE,
|
|
2191
|
+
purpose: EXECUTOR_SESSION_TOKEN_PURPOSE,
|
|
2192
|
+
task_id: params.task_id,
|
|
2193
|
+
session_id: params.session_id,
|
|
2194
|
+
sessionId: params.sessionId,
|
|
2195
|
+
branch_id: params.branch_id
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
if (payload?.type !== void 0) return null;
|
|
2199
|
+
return null;
|
|
2077
2200
|
}
|
|
2078
2201
|
function expectClaim(claim, label) {
|
|
2079
2202
|
if (!claim) {
|
|
@@ -2175,7 +2298,7 @@ function executorRuntimeScopeGuard() {
|
|
|
2175
2298
|
const payload = scopedPayload(context);
|
|
2176
2299
|
if (!payload) return context;
|
|
2177
2300
|
const scope = {
|
|
2178
|
-
sessionId: payload
|
|
2301
|
+
sessionId: getExecutorSessionTokenSessionId(payload),
|
|
2179
2302
|
taskId: payload.task_id,
|
|
2180
2303
|
branchId: payload.branch_id
|
|
2181
2304
|
};
|
|
@@ -2352,13 +2475,16 @@ var gatewayRouteHook = async (context) => {
|
|
|
2352
2475
|
const latestToolUse = extractLatestToolUseFromMessage(message);
|
|
2353
2476
|
if (latestToolUse) {
|
|
2354
2477
|
try {
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2478
|
+
gatewayService.updateProgressAfterCommit(
|
|
2479
|
+
{
|
|
2480
|
+
session_id: message.session_id,
|
|
2481
|
+
state: "working",
|
|
2482
|
+
task_id: message.task_id,
|
|
2483
|
+
tool_name: latestToolUse.name,
|
|
2484
|
+
tool_input: latestToolUse.input
|
|
2485
|
+
},
|
|
2486
|
+
context.params
|
|
2487
|
+
);
|
|
2362
2488
|
} catch (error) {
|
|
2363
2489
|
console.warn("[gateway-route] Failed to route tool progress:", error);
|
|
2364
2490
|
}
|
|
@@ -2377,6 +2503,11 @@ var gatewayRouteHook = async (context) => {
|
|
|
2377
2503
|
return context;
|
|
2378
2504
|
}
|
|
2379
2505
|
shouldRoute = true;
|
|
2506
|
+
} else if (message.role === "system") {
|
|
2507
|
+
const systemMeta = message.metadata?.system;
|
|
2508
|
+
if (systemMeta?.render_hint === "context" || /^\[system\]/i.test(messageText.trim())) {
|
|
2509
|
+
shouldRoute = true;
|
|
2510
|
+
}
|
|
2380
2511
|
} else if (message.role === "user") {
|
|
2381
2512
|
const source = message.metadata?.source;
|
|
2382
2513
|
if (source === "agor") {
|
|
@@ -2403,37 +2534,25 @@ var gatewayRouteHook = async (context) => {
|
|
|
2403
2534
|
return context;
|
|
2404
2535
|
}
|
|
2405
2536
|
try {
|
|
2406
|
-
gatewayService.
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2537
|
+
gatewayService.routeMessageAfterCommit(
|
|
2538
|
+
{
|
|
2539
|
+
session_id: message.session_id,
|
|
2540
|
+
message: messageText,
|
|
2541
|
+
metadata: message.metadata
|
|
2542
|
+
},
|
|
2543
|
+
context.params
|
|
2544
|
+
);
|
|
2412
2545
|
} catch (error) {
|
|
2413
2546
|
console.warn("[gateway-route] Failed to invoke gateway service:", error);
|
|
2414
2547
|
}
|
|
2415
2548
|
return context;
|
|
2416
2549
|
};
|
|
2417
2550
|
|
|
2418
|
-
// src/
|
|
2419
|
-
import {
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
const { board_id, branch_id, card_id, zone_id, entity_type } = query;
|
|
2424
|
-
const requestedSkip = Number(query.$skip ?? 0);
|
|
2425
|
-
const requestedLimit = typeof query.$limit === "number" ? query.$limit : void 0;
|
|
2426
|
-
const filters = Object.fromEntries(
|
|
2427
|
-
Object.entries({ board_id, branch_id, card_id, zone_id, entity_type }).filter(
|
|
2428
|
-
([, value]) => value !== void 0
|
|
2429
|
-
)
|
|
2430
|
-
);
|
|
2431
|
-
return {
|
|
2432
|
-
filters,
|
|
2433
|
-
pagination: requestedLimit !== void 0 || requestedSkip > 0 ? { limit: requestedLimit, offset: requestedSkip } : {},
|
|
2434
|
-
limit: requestedLimit ?? 100,
|
|
2435
|
-
skip: requestedSkip
|
|
2436
|
-
};
|
|
2551
|
+
// src/oauth-auth-helpers.ts
|
|
2552
|
+
import { runWithTenantDatabaseScope } from "@agor/core/db";
|
|
2553
|
+
function resolveForUserIdWithGate(opts) {
|
|
2554
|
+
const canUseExplicitUser = opts.isServiceAccount === true || opts.authPayloadType === "executor-session" && opts.queryForUserId === opts.callerUserId;
|
|
2555
|
+
return opts.queryForUserId && canUseExplicitUser ? opts.queryForUserId : opts.callerUserId;
|
|
2437
2556
|
}
|
|
2438
2557
|
|
|
2439
2558
|
// src/services/groups.ts
|
|
@@ -2670,37 +2789,6 @@ function paginateClientSide(rows, query, skipFilterKeys = /* @__PURE__ */ new Se
|
|
|
2670
2789
|
data: filtered.slice(skip, skip + limit)
|
|
2671
2790
|
};
|
|
2672
2791
|
}
|
|
2673
|
-
function scopeSessionQuery(sessionRepo, options) {
|
|
2674
|
-
return async (context) => {
|
|
2675
|
-
if (!context.params.provider) {
|
|
2676
|
-
return context;
|
|
2677
|
-
}
|
|
2678
|
-
if (context.params.user?._isServiceAccount) {
|
|
2679
|
-
return context;
|
|
2680
|
-
}
|
|
2681
|
-
if (context.method !== "find") {
|
|
2682
|
-
return context;
|
|
2683
|
-
}
|
|
2684
|
-
const userId = context.params.user?.user_id;
|
|
2685
|
-
if (!userId) {
|
|
2686
|
-
context.result = {
|
|
2687
|
-
total: 0,
|
|
2688
|
-
limit: 0,
|
|
2689
|
-
skip: 0,
|
|
2690
|
-
data: []
|
|
2691
|
-
};
|
|
2692
|
-
return context;
|
|
2693
|
-
}
|
|
2694
|
-
const userRole = context.params.user?.role;
|
|
2695
|
-
const allowSuperadmin = options?.allowSuperadmin ?? true;
|
|
2696
|
-
const accessibleSessions = isSuperAdmin(userRole, allowSuperadmin) ? await sessionRepo.findAll() : await sessionRepo.findAccessibleSessions(userId);
|
|
2697
|
-
context.result = paginateClientSide(
|
|
2698
|
-
accessibleSessions,
|
|
2699
|
-
context.params.query
|
|
2700
|
-
);
|
|
2701
|
-
return context;
|
|
2702
|
-
};
|
|
2703
|
-
}
|
|
2704
2792
|
function loadSessionBranch(sessionService, branchRepo) {
|
|
2705
2793
|
return async (context) => {
|
|
2706
2794
|
if (!context.params.provider) {
|
|
@@ -2997,7 +3085,7 @@ function emptyFindResult(context) {
|
|
|
2997
3085
|
};
|
|
2998
3086
|
return context;
|
|
2999
3087
|
}
|
|
3000
|
-
async function
|
|
3088
|
+
async function resolveFindSqlScopeAccess(context, options) {
|
|
3001
3089
|
if (context.method !== "find") return { kind: "passThrough" };
|
|
3002
3090
|
if (!context.params.provider) return { kind: "passThrough" };
|
|
3003
3091
|
if (context.params.user?._isServiceAccount) return { kind: "passThrough" };
|
|
@@ -3009,57 +3097,30 @@ async function resolveFindScopeAccess(context, options, loadAccessibleIds) {
|
|
|
3009
3097
|
const userRole = context.params.user?.role;
|
|
3010
3098
|
const allowSuperadmin = options?.allowSuperadmin ?? true;
|
|
3011
3099
|
if (isSuperAdmin(userRole, allowSuperadmin)) return { kind: "passThrough" };
|
|
3012
|
-
|
|
3013
|
-
return { kind: "filter", accessibleIds: new Set(ids) };
|
|
3100
|
+
return { kind: "filter", userId };
|
|
3014
3101
|
}
|
|
3015
|
-
function
|
|
3016
|
-
const query = context.params.query ?? {};
|
|
3017
|
-
const existing = query[field];
|
|
3018
|
-
if (typeof existing === "string") {
|
|
3019
|
-
if (!accessibleIds.has(existing)) return emptyFindResult(context);
|
|
3020
|
-
return context;
|
|
3021
|
-
}
|
|
3022
|
-
if (existing && typeof existing === "object" && Array.isArray(existing.$in)) {
|
|
3023
|
-
const intersect = existing.$in.filter((id) => accessibleIds.has(id));
|
|
3024
|
-
if (intersect.length === 0) return emptyFindResult(context);
|
|
3025
|
-
query[field] = { $in: intersect };
|
|
3026
|
-
context.params.query = query;
|
|
3027
|
-
return context;
|
|
3028
|
-
}
|
|
3029
|
-
if (accessibleIds.size === 0) return emptyFindResult(context);
|
|
3030
|
-
query[field] = { $in: Array.from(accessibleIds) };
|
|
3031
|
-
context.params.query = query;
|
|
3032
|
-
return context;
|
|
3033
|
-
}
|
|
3034
|
-
function scopeFindToAccessibleBranches(branchRepo, options) {
|
|
3102
|
+
function scopeFindToAccessibleBranchesSql(options) {
|
|
3035
3103
|
return async (context) => {
|
|
3036
|
-
const decision = await
|
|
3037
|
-
const accessible = await branchRepo.findAccessibleBranches(uid);
|
|
3038
|
-
return accessible.map((w) => w.branch_id);
|
|
3039
|
-
});
|
|
3104
|
+
const decision = await resolveFindSqlScopeAccess(context, options);
|
|
3040
3105
|
if (decision.kind !== "filter") return context;
|
|
3041
|
-
|
|
3106
|
+
context.params._agorSqlBranchAccessUserId = decision.userId;
|
|
3107
|
+
return context;
|
|
3042
3108
|
};
|
|
3043
3109
|
}
|
|
3044
|
-
function
|
|
3110
|
+
function scopeFindToAccessibleSessionsSql(options) {
|
|
3045
3111
|
return async (context) => {
|
|
3046
|
-
const decision = await
|
|
3047
|
-
const accessible = await sessionRepo.findAccessibleSessions(uid);
|
|
3048
|
-
return accessible.map((s) => s.session_id);
|
|
3049
|
-
});
|
|
3112
|
+
const decision = await resolveFindSqlScopeAccess(context, options);
|
|
3050
3113
|
if (decision.kind !== "filter") return context;
|
|
3051
|
-
|
|
3114
|
+
context.params._agorSqlSessionAccessUserId = decision.userId;
|
|
3115
|
+
return context;
|
|
3052
3116
|
};
|
|
3053
3117
|
}
|
|
3054
|
-
function
|
|
3118
|
+
function scopeFindToAccessibleBoardsSql(options) {
|
|
3055
3119
|
return async (context) => {
|
|
3056
|
-
const decision = await
|
|
3057
|
-
context,
|
|
3058
|
-
options,
|
|
3059
|
-
(uid) => boardRepo.findVisibleBoardIds(uid)
|
|
3060
|
-
);
|
|
3120
|
+
const decision = await resolveFindSqlScopeAccess(context, options);
|
|
3061
3121
|
if (decision.kind !== "filter") return context;
|
|
3062
|
-
|
|
3122
|
+
context.params._agorSqlBoardAccessUserId = decision.userId;
|
|
3123
|
+
return context;
|
|
3063
3124
|
};
|
|
3064
3125
|
}
|
|
3065
3126
|
function scopeScheduleQuery(scheduleRepo, options) {
|
|
@@ -3182,8 +3243,13 @@ import {
|
|
|
3182
3243
|
SessionRepository,
|
|
3183
3244
|
UsersRepository
|
|
3184
3245
|
} from "@agor/core/db";
|
|
3185
|
-
import { Forbidden as Forbidden4 } from "@agor/core/feathers";
|
|
3186
|
-
import {
|
|
3246
|
+
import { BadRequest as BadRequest2, Forbidden as Forbidden4 } from "@agor/core/feathers";
|
|
3247
|
+
import {
|
|
3248
|
+
formatModelToolMismatchWarning,
|
|
3249
|
+
formatUnsupportedAgorCodexModelMessage,
|
|
3250
|
+
isUnsupportedAgorCodexModel,
|
|
3251
|
+
lintModelToolMatch
|
|
3252
|
+
} from "@agor/core/models";
|
|
3187
3253
|
import { resolveChildSessionConfig } from "@agor/core/sessions";
|
|
3188
3254
|
import { ROLES as ROLES3, SessionStatus } from "@agor/core/types";
|
|
3189
3255
|
var remoteRelationshipsEnrichedResults = /* @__PURE__ */ new WeakSet();
|
|
@@ -3206,6 +3272,7 @@ import {
|
|
|
3206
3272
|
validateEnvVar
|
|
3207
3273
|
} from "@agor/core/config";
|
|
3208
3274
|
import {
|
|
3275
|
+
and,
|
|
3209
3276
|
compare,
|
|
3210
3277
|
decryptApiKey,
|
|
3211
3278
|
deleteFrom,
|
|
@@ -3217,16 +3284,29 @@ import {
|
|
|
3217
3284
|
update,
|
|
3218
3285
|
users
|
|
3219
3286
|
} from "@agor/core/db";
|
|
3220
|
-
import { Forbidden as
|
|
3221
|
-
import { isLikelyGitToken } from "@agor/core/git";
|
|
3287
|
+
import { Forbidden as Forbidden6, NotAuthenticated as NotAuthenticated3 } from "@agor/core/feathers";
|
|
3288
|
+
import { isLikelyGitToken } from "@agor/core/git/pure";
|
|
3222
3289
|
import {
|
|
3223
3290
|
extractAgenticToolsPublicValues,
|
|
3224
|
-
hasMinimumRole as
|
|
3291
|
+
hasMinimumRole as hasMinimumRole4,
|
|
3225
3292
|
normalizeRole,
|
|
3226
|
-
ROLES as
|
|
3293
|
+
ROLES as ROLES5,
|
|
3227
3294
|
toAgenticToolsStatus
|
|
3228
3295
|
} from "@agor/core/types";
|
|
3296
|
+
|
|
3297
|
+
// src/services/user-avatar-sync.ts
|
|
3298
|
+
import {
|
|
3299
|
+
AppVariableRepository,
|
|
3300
|
+
GatewayChannelRepository,
|
|
3301
|
+
UsersRepository as UsersRepository2
|
|
3302
|
+
} from "@agor/core/db";
|
|
3303
|
+
import { Forbidden as Forbidden5 } from "@agor/core/feathers";
|
|
3304
|
+
import { SlackConnector } from "@agor/core/gateway";
|
|
3305
|
+
import { hasMinimumRole as hasMinimumRole3, ROLES as ROLES4 } from "@agor/core/types";
|
|
3306
|
+
|
|
3307
|
+
// src/services/users.ts
|
|
3229
3308
|
var LOCAL_AUTH_LOOKUP_PARAM = Symbol("agor.users.local-auth-lookup");
|
|
3309
|
+
var AUTH_INTERNAL_USER_LOOKUP_PARAM = Symbol("agor.users.auth-internal-lookup");
|
|
3230
3310
|
function isLocalAuthenticationLookup(params) {
|
|
3231
3311
|
return params?.[LOCAL_AUTH_LOOKUP_PARAM] === true;
|
|
3232
3312
|
}
|
|
@@ -3250,6 +3330,11 @@ function buildSessionCreatedAnalyticsProperties(session) {
|
|
|
3250
3330
|
}
|
|
3251
3331
|
|
|
3252
3332
|
// src/utils/apply-session-config-defaults.ts
|
|
3333
|
+
import { BadRequest as BadRequest3 } from "@agor/core/feathers";
|
|
3334
|
+
import {
|
|
3335
|
+
formatUnsupportedAgorCodexModelMessage as formatUnsupportedAgorCodexModelMessage2,
|
|
3336
|
+
isUnsupportedAgorCodexModel as isUnsupportedAgorCodexModel2
|
|
3337
|
+
} from "@agor/core/models";
|
|
3253
3338
|
import { resolveSessionDefaults } from "@agor/core/sessions";
|
|
3254
3339
|
function applySessionConfigDefaults(opts = {}) {
|
|
3255
3340
|
const { warnOnExternalDefaultFill = true } = opts;
|
|
@@ -3261,9 +3346,12 @@ function applySessionConfigDefaults(opts = {}) {
|
|
|
3261
3346
|
if (!data) return context;
|
|
3262
3347
|
const hasPermission = data.permission_config != null;
|
|
3263
3348
|
const hasModel = !!data.model_config?.model;
|
|
3264
|
-
if (hasPermission && hasModel) return context;
|
|
3265
3349
|
const agenticTool = data.agentic_tool;
|
|
3266
3350
|
if (!agenticTool) return context;
|
|
3351
|
+
if (agenticTool === "codex" && data.model_config?.model && isUnsupportedAgorCodexModel2(data.model_config.model)) {
|
|
3352
|
+
throw new BadRequest3(formatUnsupportedAgorCodexModelMessage2(data.model_config.model));
|
|
3353
|
+
}
|
|
3354
|
+
if (hasPermission && hasModel) return context;
|
|
3267
3355
|
const userId = data.created_by;
|
|
3268
3356
|
if (!userId) return context;
|
|
3269
3357
|
let user;
|
|
@@ -3282,6 +3370,9 @@ function applySessionConfigDefaults(opts = {}) {
|
|
|
3282
3370
|
user,
|
|
3283
3371
|
overrides: { modelConfig: data.model_config ?? void 0 }
|
|
3284
3372
|
});
|
|
3373
|
+
if (resolved.model_config?.model && agenticTool === "codex" && isUnsupportedAgorCodexModel2(resolved.model_config.model)) {
|
|
3374
|
+
throw new BadRequest3(formatUnsupportedAgorCodexModelMessage2(resolved.model_config.model));
|
|
3375
|
+
}
|
|
3285
3376
|
if (!hasPermission) {
|
|
3286
3377
|
data.permission_config = resolved.permission_config;
|
|
3287
3378
|
if (warnOnExternalDefaultFill && context.params.provider) {
|
|
@@ -3298,8 +3389,8 @@ function applySessionConfigDefaults(opts = {}) {
|
|
|
3298
3389
|
}
|
|
3299
3390
|
|
|
3300
3391
|
// src/utils/authorization.ts
|
|
3301
|
-
import { Forbidden as
|
|
3302
|
-
import { hasMinimumRole as
|
|
3392
|
+
import { Forbidden as Forbidden7, NotAuthenticated as NotAuthenticated4 } from "@agor/core/feathers";
|
|
3393
|
+
import { hasMinimumRole as hasMinimumRole5, ROLES as ROLES6 } from "@agor/core/types";
|
|
3303
3394
|
function ensureMinimumRole(params, minimumRole, action = "perform this action") {
|
|
3304
3395
|
if (!params?.provider) {
|
|
3305
3396
|
return;
|
|
@@ -3310,8 +3401,8 @@ function ensureMinimumRole(params, minimumRole, action = "perform this action")
|
|
|
3310
3401
|
if (params.user._isServiceAccount === true) {
|
|
3311
3402
|
return;
|
|
3312
3403
|
}
|
|
3313
|
-
if (!
|
|
3314
|
-
throw new
|
|
3404
|
+
if (!hasMinimumRole5(params.user.role, minimumRole)) {
|
|
3405
|
+
throw new Forbidden7(`You need ${minimumRole} access to ${action}`);
|
|
3315
3406
|
}
|
|
3316
3407
|
}
|
|
3317
3408
|
function requireMinimumRole(minimumRole, action) {
|
|
@@ -3320,7 +3411,7 @@ function requireMinimumRole(minimumRole, action) {
|
|
|
3320
3411
|
return context;
|
|
3321
3412
|
};
|
|
3322
3413
|
}
|
|
3323
|
-
var DEFAULT_MANAGED_ENVS_MINIMUM_ROLE =
|
|
3414
|
+
var DEFAULT_MANAGED_ENVS_MINIMUM_ROLE = ROLES6.MEMBER;
|
|
3324
3415
|
var ENV_COMMAND_FIELDS = [
|
|
3325
3416
|
"environment",
|
|
3326
3417
|
// Repo-level: v2 named variants (source of truth)
|
|
@@ -3348,13 +3439,13 @@ function requireAdminForEnvConfig() {
|
|
|
3348
3439
|
}
|
|
3349
3440
|
ensureMinimumRole(
|
|
3350
3441
|
context.params,
|
|
3351
|
-
|
|
3442
|
+
ROLES6.ADMIN,
|
|
3352
3443
|
"modify environment commands (up_command, down_command, etc.)"
|
|
3353
3444
|
);
|
|
3354
3445
|
return context;
|
|
3355
3446
|
};
|
|
3356
3447
|
}
|
|
3357
|
-
function registerAuthenticatedRoute(app, path4, service, authConfig, requireAuth) {
|
|
3448
|
+
function registerAuthenticatedRoute(app, path4, service, authConfig, requireAuth, options = {}) {
|
|
3358
3449
|
app.use(path4, service);
|
|
3359
3450
|
const hooks = {};
|
|
3360
3451
|
for (const [method, config] of Object.entries(authConfig)) {
|
|
@@ -3365,6 +3456,7 @@ function registerAuthenticatedRoute(app, path4, service, authConfig, requireAuth
|
|
|
3365
3456
|
];
|
|
3366
3457
|
}
|
|
3367
3458
|
app.service(path4).hooks({
|
|
3459
|
+
...options.around ? { around: { all: options.around } } : {},
|
|
3368
3460
|
before: hooks
|
|
3369
3461
|
});
|
|
3370
3462
|
}
|
|
@@ -3376,7 +3468,8 @@ function isBranchInspectResult(value) {
|
|
|
3376
3468
|
}
|
|
3377
3469
|
async function inspectBranchViaExecutor(app, branchId, options = {}) {
|
|
3378
3470
|
const sessionToken = generateSessionToken(
|
|
3379
|
-
app
|
|
3471
|
+
app,
|
|
3472
|
+
options.serviceTokenScope
|
|
3380
3473
|
);
|
|
3381
3474
|
const result = await runExecutorCommand(
|
|
3382
3475
|
{
|
|
@@ -3401,7 +3494,7 @@ async function inspectBranchViaExecutor(app, branchId, options = {}) {
|
|
|
3401
3494
|
|
|
3402
3495
|
// src/utils/executor-read-impersonation.ts
|
|
3403
3496
|
import { loadConfigSync as loadConfigSync2 } from "@agor/core/config";
|
|
3404
|
-
import { UsersRepository as
|
|
3497
|
+
import { UsersRepository as UsersRepository3 } from "@agor/core/db";
|
|
3405
3498
|
async function resolveExecutorReadAsUser(db, userOrId) {
|
|
3406
3499
|
const config = loadConfigSync2();
|
|
3407
3500
|
const unixMode = config.execution?.unix_user_mode ?? "simple";
|
|
@@ -3410,7 +3503,7 @@ async function resolveExecutorReadAsUser(db, userOrId) {
|
|
|
3410
3503
|
}
|
|
3411
3504
|
let user;
|
|
3412
3505
|
if (typeof userOrId === "string") {
|
|
3413
|
-
user = await new
|
|
3506
|
+
user = await new UsersRepository3(db).findById(userOrId);
|
|
3414
3507
|
} else {
|
|
3415
3508
|
user = userOrId;
|
|
3416
3509
|
}
|
|
@@ -3456,11 +3549,26 @@ function injectCreatedBy() {
|
|
|
3456
3549
|
// src/utils/mcp-header-secrets.ts
|
|
3457
3550
|
import { redactMCPAuthSecrets } from "@agor/core/tools/mcp/auth-secrets";
|
|
3458
3551
|
import { redactMCPCustomHeaders } from "@agor/core/tools/mcp/http-headers";
|
|
3552
|
+
import jwt2 from "jsonwebtoken";
|
|
3459
3553
|
function shouldExposeMCPServerSecretsForSessionToken(params, options = {}) {
|
|
3460
|
-
const payload = params?.authentication?.payload;
|
|
3461
|
-
const sessionId = params?.session_id ?? payload
|
|
3554
|
+
const payload = params?.authentication?.payload ?? decodeExecutorSessionPayload(params);
|
|
3555
|
+
const sessionId = params?.session_id ?? getPayloadSessionId(payload);
|
|
3462
3556
|
return !!params?.provider && (params.authentication?.strategy === "session-token" || payload?.type === "executor-session") && !!sessionId && (!options.sessionId || sessionId === options.sessionId);
|
|
3463
3557
|
}
|
|
3558
|
+
function decodeExecutorSessionPayload(params) {
|
|
3559
|
+
if (params?.authentication?.strategy !== "jwt" || !params.authentication.accessToken) {
|
|
3560
|
+
return void 0;
|
|
3561
|
+
}
|
|
3562
|
+
const decoded = jwt2.decode(params.authentication.accessToken);
|
|
3563
|
+
if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) {
|
|
3564
|
+
return void 0;
|
|
3565
|
+
}
|
|
3566
|
+
if (!isExecutorSessionTokenPayload(decoded)) return void 0;
|
|
3567
|
+
return decoded;
|
|
3568
|
+
}
|
|
3569
|
+
function getPayloadSessionId(payload) {
|
|
3570
|
+
return payload ? getExecutorSessionTokenSessionId(payload) : void 0;
|
|
3571
|
+
}
|
|
3464
3572
|
function shouldExposeMCPServerSecrets(params, options = {}) {
|
|
3465
3573
|
if (!params?.provider) return true;
|
|
3466
3574
|
if (params.user?._isServiceAccount || params.user?.role === "service") return true;
|
|
@@ -3482,12 +3590,13 @@ init_mcp_token_authorization();
|
|
|
3482
3590
|
|
|
3483
3591
|
// src/utils/realign-repo-origin.ts
|
|
3484
3592
|
init_spawn_executor();
|
|
3485
|
-
async function ensureRepoOriginAlignedForRepo(app, repo) {
|
|
3593
|
+
async function ensureRepoOriginAlignedForRepo(app, repo, params) {
|
|
3486
3594
|
if (repo.repo_type !== "remote") return;
|
|
3487
3595
|
if (!repo.remote_url) return;
|
|
3488
3596
|
if (!repo.local_path) return;
|
|
3489
|
-
const sessionToken =
|
|
3490
|
-
app
|
|
3597
|
+
const sessionToken = generateScopedServiceToken(
|
|
3598
|
+
app,
|
|
3599
|
+
params
|
|
3491
3600
|
);
|
|
3492
3601
|
spawnExecutorFireAndForget(
|
|
3493
3602
|
{
|
|
@@ -3516,12 +3625,14 @@ function realignRepoOriginAfterPatchHook() {
|
|
|
3516
3625
|
const repos = Array.isArray(result) ? result : [result];
|
|
3517
3626
|
for (const repo of repos) {
|
|
3518
3627
|
if (!repo?.repo_id) continue;
|
|
3519
|
-
ensureRepoOriginAlignedForRepo(context.app, repo).catch(
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3628
|
+
ensureRepoOriginAlignedForRepo(context.app, repo, context.params).catch(
|
|
3629
|
+
(err) => {
|
|
3630
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3631
|
+
console.warn(
|
|
3632
|
+
`\u26A0\uFE0F [repos.after.patch] ensureRepoOriginAlignedForRepo failed for repo ${repo.repo_id}: ${message}`
|
|
3633
|
+
);
|
|
3634
|
+
}
|
|
3635
|
+
);
|
|
3525
3636
|
}
|
|
3526
3637
|
return context;
|
|
3527
3638
|
};
|
|
@@ -3543,6 +3654,7 @@ var RealtimeAccessCache = class {
|
|
|
3543
3654
|
}
|
|
3544
3655
|
branchVisibility = /* @__PURE__ */ new Map();
|
|
3545
3656
|
sessionBranches = /* @__PURE__ */ new Map();
|
|
3657
|
+
sessionOwners = /* @__PURE__ */ new Map();
|
|
3546
3658
|
branchVisibilityTtlMs;
|
|
3547
3659
|
sessionBranchTtlMs;
|
|
3548
3660
|
now;
|
|
@@ -3559,6 +3671,27 @@ var RealtimeAccessCache = class {
|
|
|
3559
3671
|
});
|
|
3560
3672
|
return branchId;
|
|
3561
3673
|
}
|
|
3674
|
+
/**
|
|
3675
|
+
* Owning user id for a session, cached on the same cadence as the
|
|
3676
|
+
* session→branch map. Used only to offer streaming events to the session
|
|
3677
|
+
* creator's own connections as a fallback when they haven't subscribed to
|
|
3678
|
+
* the per-session stream channel yet.
|
|
3679
|
+
*/
|
|
3680
|
+
async getSessionOwnerId(sessionId) {
|
|
3681
|
+
const cached = this.sessionOwners.get(sessionId);
|
|
3682
|
+
const now = this.now();
|
|
3683
|
+
if (cached && cached.expiresAt > now) {
|
|
3684
|
+
return cached.ownerId;
|
|
3685
|
+
}
|
|
3686
|
+
const ownerId = await this.options.sessionsRepository.findCreatedByBySessionId(
|
|
3687
|
+
sessionId
|
|
3688
|
+
) ?? null;
|
|
3689
|
+
this.sessionOwners.set(sessionId, {
|
|
3690
|
+
ownerId,
|
|
3691
|
+
expiresAt: now + this.sessionBranchTtlMs
|
|
3692
|
+
});
|
|
3693
|
+
return ownerId;
|
|
3694
|
+
}
|
|
3562
3695
|
async getBranchVisibility(branchId) {
|
|
3563
3696
|
const cached = this.branchVisibility.get(branchId);
|
|
3564
3697
|
const now = this.now();
|
|
@@ -3594,6 +3727,7 @@ var RealtimeAccessCache = class {
|
|
|
3594
3727
|
}
|
|
3595
3728
|
invalidateSession(sessionId) {
|
|
3596
3729
|
this.sessionBranches.delete(sessionId);
|
|
3730
|
+
this.sessionOwners.delete(sessionId);
|
|
3597
3731
|
}
|
|
3598
3732
|
clearVisibility() {
|
|
3599
3733
|
this.branchVisibility.clear();
|
|
@@ -3601,6 +3735,7 @@ var RealtimeAccessCache = class {
|
|
|
3601
3735
|
clearAll() {
|
|
3602
3736
|
this.branchVisibility.clear();
|
|
3603
3737
|
this.sessionBranches.clear();
|
|
3738
|
+
this.sessionOwners.clear();
|
|
3604
3739
|
}
|
|
3605
3740
|
visibilityFromEntry(entry) {
|
|
3606
3741
|
return entry.mode === "allAuthenticated" ? { mode: "allAuthenticated" } : { mode: "explicitUsers", userIds: entry.userIds };
|
|
@@ -3608,8 +3743,22 @@ var RealtimeAccessCache = class {
|
|
|
3608
3743
|
};
|
|
3609
3744
|
|
|
3610
3745
|
// src/utils/realtime-publish.ts
|
|
3611
|
-
import {
|
|
3612
|
-
|
|
3746
|
+
import {
|
|
3747
|
+
resolveTenantContext,
|
|
3748
|
+
TenantResolutionError
|
|
3749
|
+
} from "@agor/core/config";
|
|
3750
|
+
import { getCurrentTenantId, shortId as shortId2 } from "@agor/core/db";
|
|
3751
|
+
import { hasMinimumRole as hasMinimumRole7, ROLES as ROLES8 } from "@agor/core/types";
|
|
3752
|
+
function tenantChannelName(tenantId) {
|
|
3753
|
+
return `tenant:${tenantId}`;
|
|
3754
|
+
}
|
|
3755
|
+
var SESSION_STREAM_CHANNEL_PREFIX = "session-stream:";
|
|
3756
|
+
function sessionStreamChannelName(sessionId) {
|
|
3757
|
+
return `${SESSION_STREAM_CHANNEL_PREFIX}${sessionId}`;
|
|
3758
|
+
}
|
|
3759
|
+
function existingChannel(app, name) {
|
|
3760
|
+
return (app.channels ?? []).includes(name) ? app.channel(name) : null;
|
|
3761
|
+
}
|
|
3613
3762
|
var DEBUG_REALTIME_PUBLISH = process.env.AGOR_DEBUG_REALTIME_PUBLISH === "1" || process.env.DEBUG?.includes("realtime-publish");
|
|
3614
3763
|
function realtimePublishDebug(...args) {
|
|
3615
3764
|
if (DEBUG_REALTIME_PUBLISH) {
|
|
@@ -3625,8 +3774,27 @@ var SESSION_ID_SCOPED_PATHS = /* @__PURE__ */ new Set([
|
|
|
3625
3774
|
"session-env-selections"
|
|
3626
3775
|
]);
|
|
3627
3776
|
var OPTIONAL_BRANCH_OR_SESSION_SCOPED_PATHS = /* @__PURE__ */ new Set(["board-objects", "board-comments"]);
|
|
3777
|
+
var MESSAGE_STREAMING_EVENTS = /* @__PURE__ */ new Set([
|
|
3778
|
+
"streaming:start",
|
|
3779
|
+
"streaming:chunk",
|
|
3780
|
+
"streaming:end",
|
|
3781
|
+
"streaming:error",
|
|
3782
|
+
"thinking:start",
|
|
3783
|
+
"thinking:chunk",
|
|
3784
|
+
"thinking:end"
|
|
3785
|
+
]);
|
|
3786
|
+
var TASK_STREAMING_EVENTS = /* @__PURE__ */ new Set(["thinking:chunk", "tool:start", "tool:complete"]);
|
|
3628
3787
|
function isStreamingEvent(context) {
|
|
3629
|
-
|
|
3788
|
+
if (context.path === "messages/streaming") return true;
|
|
3789
|
+
const event = context.event;
|
|
3790
|
+
if (!event) return false;
|
|
3791
|
+
if (context.path === "messages") {
|
|
3792
|
+
return event.startsWith("streaming:") || MESSAGE_STREAMING_EVENTS.has(event);
|
|
3793
|
+
}
|
|
3794
|
+
if (context.path === "tasks") {
|
|
3795
|
+
return TASK_STREAMING_EVENTS.has(event);
|
|
3796
|
+
}
|
|
3797
|
+
return false;
|
|
3630
3798
|
}
|
|
3631
3799
|
function asRecord2(value) {
|
|
3632
3800
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -3676,7 +3844,7 @@ function isServiceConnection(connection) {
|
|
|
3676
3844
|
}
|
|
3677
3845
|
function isAdminConnection(connection, allowSuperadmin) {
|
|
3678
3846
|
const user = userFromConnection(connection);
|
|
3679
|
-
if (!user?._isServiceAccount && user?.role &&
|
|
3847
|
+
if (!user?._isServiceAccount && user?.role && hasMinimumRole7(user.role, ROLES8.ADMIN)) {
|
|
3680
3848
|
return true;
|
|
3681
3849
|
}
|
|
3682
3850
|
return isSuperAdmin(user?.role, allowSuperadmin);
|
|
@@ -3762,6 +3930,47 @@ async function resolvePublishScope(data, context, accessCache) {
|
|
|
3762
3930
|
function filterToServiceConnections(authenticated) {
|
|
3763
3931
|
return authenticated.filter((connection) => isServiceConnection(connection));
|
|
3764
3932
|
}
|
|
3933
|
+
async function resolveStreamingDelivery(app, data, tenantScoped, accessCache, branchRbacEnabled, allowSuperadmin) {
|
|
3934
|
+
const serviceConnections = filterToServiceConnections(tenantScoped);
|
|
3935
|
+
const sessionId = extractSessionId(data);
|
|
3936
|
+
if (!sessionId) return serviceConnections;
|
|
3937
|
+
const tenantConnections = new Set(
|
|
3938
|
+
tenantScoped.connections
|
|
3939
|
+
);
|
|
3940
|
+
const existingRoom = existingChannel(app, sessionStreamChannelName(sessionId));
|
|
3941
|
+
const room = existingRoom ? existingRoom.filter((connection) => tenantConnections.has(connection)) : null;
|
|
3942
|
+
let ownerId = null;
|
|
3943
|
+
try {
|
|
3944
|
+
ownerId = await accessCache.getSessionOwnerId(sessionId);
|
|
3945
|
+
} catch {
|
|
3946
|
+
}
|
|
3947
|
+
const ownerChannel = () => tenantScoped.filter(
|
|
3948
|
+
(connection) => userFromConnection(connection)?.user_id === ownerId
|
|
3949
|
+
);
|
|
3950
|
+
if (!branchRbacEnabled) {
|
|
3951
|
+
const channels2 = [serviceConnections];
|
|
3952
|
+
if (room) channels2.push(room);
|
|
3953
|
+
if (ownerId) channels2.push(ownerChannel());
|
|
3954
|
+
return channels2;
|
|
3955
|
+
}
|
|
3956
|
+
const branchId = await accessCache.getBranchIdForSession(sessionId);
|
|
3957
|
+
const visibility = branchId ? await accessCache.getBranchVisibility(branchId) : null;
|
|
3958
|
+
if (!visibility) return serviceConnections;
|
|
3959
|
+
if (visibility.mode === "allAuthenticated") {
|
|
3960
|
+
const channels2 = [serviceConnections];
|
|
3961
|
+
if (room) channels2.push(room);
|
|
3962
|
+
if (ownerId) channels2.push(ownerChannel());
|
|
3963
|
+
return channels2;
|
|
3964
|
+
}
|
|
3965
|
+
const channels = [serviceConnections];
|
|
3966
|
+
if (room) {
|
|
3967
|
+
channels.push(filterToUserIdsOrSuperadmins(room, visibility.userIds, allowSuperadmin));
|
|
3968
|
+
}
|
|
3969
|
+
if (ownerId && visibility.userIds.has(ownerId)) {
|
|
3970
|
+
channels.push(ownerChannel());
|
|
3971
|
+
}
|
|
3972
|
+
return channels;
|
|
3973
|
+
}
|
|
3765
3974
|
function filterToUserIdsOrAdmins(authenticated, userIds, allowSuperadmin) {
|
|
3766
3975
|
return authenticated.filter((connection) => {
|
|
3767
3976
|
if (isServiceConnection(connection) || isAdminConnection(connection, allowSuperadmin)) {
|
|
@@ -3780,6 +3989,22 @@ function filterToUserIdsOrSuperadmins(authenticated, userIds, allowSuperadmin) {
|
|
|
3780
3989
|
return typeof userId === "string" && userIds.has(userId);
|
|
3781
3990
|
});
|
|
3782
3991
|
}
|
|
3992
|
+
function extractConnectionTenantId(context) {
|
|
3993
|
+
const params = context.params;
|
|
3994
|
+
const tenant = params?.connection?.tenant ?? params?.connection?.data?.tenant;
|
|
3995
|
+
return tenant && typeof tenant === "object" && "tenant_id" in tenant ? typeof tenant.tenant_id === "string" ? tenant.tenant_id : void 0 : void 0;
|
|
3996
|
+
}
|
|
3997
|
+
function resolveRealtimeTenantId(multiTenancy, context) {
|
|
3998
|
+
try {
|
|
3999
|
+
return resolveTenantContext(multiTenancy, { params: context.params }).tenant_id;
|
|
4000
|
+
} catch (error) {
|
|
4001
|
+
const connectionTenantId = extractConnectionTenantId(context);
|
|
4002
|
+
if (error instanceof TenantResolutionError && connectionTenantId) return connectionTenantId;
|
|
4003
|
+
const ambientTenantId = getCurrentTenantId();
|
|
4004
|
+
if (error instanceof TenantResolutionError && ambientTenantId) return ambientTenantId;
|
|
4005
|
+
throw error;
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
3783
4008
|
function configureRealtimePublish(options) {
|
|
3784
4009
|
const {
|
|
3785
4010
|
app,
|
|
@@ -3790,7 +4015,8 @@ function configureRealtimePublish(options) {
|
|
|
3790
4015
|
branchRepository,
|
|
3791
4016
|
sessionsRepository
|
|
3792
4017
|
}),
|
|
3793
|
-
allowSuperadmin = true
|
|
4018
|
+
allowSuperadmin = true,
|
|
4019
|
+
multiTenancy
|
|
3794
4020
|
} = options;
|
|
3795
4021
|
app.publish(async (data, context) => {
|
|
3796
4022
|
if (context.path && context.method && !isStreamingEvent(context)) {
|
|
@@ -3801,12 +4027,39 @@ function configureRealtimePublish(options) {
|
|
|
3801
4027
|
);
|
|
3802
4028
|
}
|
|
3803
4029
|
const authenticated = app.channel("authenticated");
|
|
3804
|
-
|
|
4030
|
+
let tenantScoped = authenticated;
|
|
4031
|
+
if (multiTenancy) {
|
|
4032
|
+
try {
|
|
4033
|
+
const tenantId = resolveRealtimeTenantId(multiTenancy, context);
|
|
4034
|
+
tenantScoped = app.channel(tenantChannelName(tenantId));
|
|
4035
|
+
} catch (error) {
|
|
4036
|
+
if (error instanceof TenantResolutionError) {
|
|
4037
|
+
console.warn("[realtime] Suppressing event without tenant context", {
|
|
4038
|
+
path: context.path,
|
|
4039
|
+
event: context.event,
|
|
4040
|
+
method: context.method
|
|
4041
|
+
});
|
|
4042
|
+
return filterToServiceConnections(authenticated);
|
|
4043
|
+
}
|
|
4044
|
+
throw error;
|
|
4045
|
+
}
|
|
4046
|
+
}
|
|
4047
|
+
if (isStreamingEvent(context)) {
|
|
4048
|
+
return resolveStreamingDelivery(
|
|
4049
|
+
app,
|
|
4050
|
+
data,
|
|
4051
|
+
tenantScoped,
|
|
4052
|
+
accessCache,
|
|
4053
|
+
branchRbacEnabled,
|
|
4054
|
+
allowSuperadmin
|
|
4055
|
+
);
|
|
4056
|
+
}
|
|
4057
|
+
if (!branchRbacEnabled) return tenantScoped;
|
|
3805
4058
|
const scope = await resolvePublishScope(data, context, accessCache);
|
|
3806
|
-
if (scope.kind === "global") return
|
|
3807
|
-
if (scope.kind === "serviceOnly") return filterToServiceConnections(
|
|
4059
|
+
if (scope.kind === "global") return tenantScoped;
|
|
4060
|
+
if (scope.kind === "serviceOnly") return filterToServiceConnections(tenantScoped);
|
|
3808
4061
|
if (scope.kind === "users") {
|
|
3809
|
-
return filterToUserIdsOrAdmins(
|
|
4062
|
+
return filterToUserIdsOrAdmins(tenantScoped, scope.userIds, allowSuperadmin);
|
|
3810
4063
|
}
|
|
3811
4064
|
if (!scope.branchId) {
|
|
3812
4065
|
console.warn("[realtime] Suppressing scoped event without resolvable branch context", {
|
|
@@ -3814,7 +4067,7 @@ function configureRealtimePublish(options) {
|
|
|
3814
4067
|
event: context.event,
|
|
3815
4068
|
method: context.method
|
|
3816
4069
|
});
|
|
3817
|
-
return filterToServiceConnections(
|
|
4070
|
+
return filterToServiceConnections(tenantScoped);
|
|
3818
4071
|
}
|
|
3819
4072
|
const visibility = await accessCache.getBranchVisibility(scope.branchId);
|
|
3820
4073
|
if (!visibility) {
|
|
@@ -3823,18 +4076,18 @@ function configureRealtimePublish(options) {
|
|
|
3823
4076
|
event: context.event,
|
|
3824
4077
|
method: context.method
|
|
3825
4078
|
});
|
|
3826
|
-
return filterToServiceConnections(
|
|
4079
|
+
return filterToServiceConnections(tenantScoped);
|
|
3827
4080
|
}
|
|
3828
4081
|
if (visibility.mode === "allAuthenticated") {
|
|
3829
|
-
return
|
|
4082
|
+
return tenantScoped;
|
|
3830
4083
|
}
|
|
3831
|
-
return filterToUserIdsOrSuperadmins(
|
|
4084
|
+
return filterToUserIdsOrSuperadmins(tenantScoped, visibility.userIds, allowSuperadmin);
|
|
3832
4085
|
});
|
|
3833
4086
|
}
|
|
3834
4087
|
|
|
3835
4088
|
// src/utils/schedule-hooks.ts
|
|
3836
|
-
import { BadRequest as
|
|
3837
|
-
import { hasMinimumRole as
|
|
4089
|
+
import { BadRequest as BadRequest4, Forbidden as Forbidden8, NotAuthenticated as NotAuthenticated6 } from "@agor/core/feathers";
|
|
4090
|
+
import { hasMinimumRole as hasMinimumRole8, ROLES as ROLES9 } from "@agor/core/types";
|
|
3838
4091
|
function ensureCurrentScheduleLoaded(scheduleRepo) {
|
|
3839
4092
|
return async (context) => {
|
|
3840
4093
|
if (context.method !== "patch") return context;
|
|
@@ -3856,21 +4109,21 @@ function validateScheduleConfig() {
|
|
|
3856
4109
|
const { isValidCron } = await import("@agor/core/utils/cron");
|
|
3857
4110
|
const tz = merged.timezone_mode === "local" && merged.timezone ? merged.timezone : "UTC";
|
|
3858
4111
|
if (!isValidCron(data.cron_expression, tz)) {
|
|
3859
|
-
throw new
|
|
4112
|
+
throw new BadRequest4(`Invalid cron expression: '${data.cron_expression}'`);
|
|
3860
4113
|
}
|
|
3861
4114
|
}
|
|
3862
4115
|
if (merged.timezone_mode === "local" && !merged.timezone) {
|
|
3863
|
-
throw new
|
|
4116
|
+
throw new BadRequest4("timezone_mode='local' requires a non-empty IANA timezone.");
|
|
3864
4117
|
}
|
|
3865
4118
|
if (data.timezone) {
|
|
3866
4119
|
try {
|
|
3867
4120
|
new Intl.DateTimeFormat("en-US", { timeZone: data.timezone });
|
|
3868
4121
|
} catch {
|
|
3869
|
-
throw new
|
|
4122
|
+
throw new BadRequest4(`Unknown IANA timezone: '${data.timezone}'`);
|
|
3870
4123
|
}
|
|
3871
4124
|
}
|
|
3872
4125
|
if (data.prompt !== void 0 && data.prompt.trim() === "") {
|
|
3873
|
-
throw new
|
|
4126
|
+
throw new BadRequest4("Schedule prompt cannot be empty.");
|
|
3874
4127
|
}
|
|
3875
4128
|
return context;
|
|
3876
4129
|
};
|
|
@@ -3889,14 +4142,14 @@ function ensureScheduleRunsAsCaller(options) {
|
|
|
3889
4142
|
}
|
|
3890
4143
|
const data = context.data;
|
|
3891
4144
|
if (data?.created_by !== void 0 && data.created_by !== schedule.created_by) {
|
|
3892
|
-
throw new
|
|
4145
|
+
throw new Forbidden8("Cannot change the user a schedule runs as.");
|
|
3893
4146
|
}
|
|
3894
4147
|
const allowSuperadmin = options?.allowSuperadmin ?? true;
|
|
3895
|
-
if (allowSuperadmin &&
|
|
4148
|
+
if (allowSuperadmin && hasMinimumRole8(user.role, ROLES9.SUPERADMIN)) {
|
|
3896
4149
|
return context;
|
|
3897
4150
|
}
|
|
3898
4151
|
if (schedule.created_by !== user.user_id) {
|
|
3899
|
-
throw new
|
|
4152
|
+
throw new Forbidden8(
|
|
3900
4153
|
"Schedules run as the user who created them. You can only modify or run schedules you created."
|
|
3901
4154
|
);
|
|
3902
4155
|
}
|
|
@@ -3933,6 +4186,165 @@ function recomputeNextRunAt() {
|
|
|
3933
4186
|
};
|
|
3934
4187
|
}
|
|
3935
4188
|
|
|
4189
|
+
// src/utils/session-queue-tenant-scope.ts
|
|
4190
|
+
import { resolveMultiTenancyConfig as resolveMultiTenancyConfig2 } from "@agor/core/config";
|
|
4191
|
+
import { runWithTenantDatabaseScope as runWithTenantDatabaseScope3 } from "@agor/core/db";
|
|
4192
|
+
|
|
4193
|
+
// src/utils/tenant-db-scope.ts
|
|
4194
|
+
init_runtime_tokens();
|
|
4195
|
+
import {
|
|
4196
|
+
resolveMultiTenancyConfig,
|
|
4197
|
+
resolveTenantContext as resolveTenantContext2,
|
|
4198
|
+
TenantResolutionError as TenantResolutionError2
|
|
4199
|
+
} from "@agor/core/config";
|
|
4200
|
+
import {
|
|
4201
|
+
enqueueTenantDatabasePostCommitCallback,
|
|
4202
|
+
getCurrentTenantId as getCurrentTenantId2,
|
|
4203
|
+
runWithoutTenantDatabaseScope,
|
|
4204
|
+
runWithTenantDatabaseScope as runWithTenantDatabaseScope2
|
|
4205
|
+
} from "@agor/core/db";
|
|
4206
|
+
import { NotAuthenticated as NotAuthenticated7 } from "@agor/core/feathers";
|
|
4207
|
+
import jwt3 from "jsonwebtoken";
|
|
4208
|
+
function readHeaderValue(headers, name) {
|
|
4209
|
+
if (!headers) return null;
|
|
4210
|
+
const wanted = name.toLowerCase();
|
|
4211
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
4212
|
+
if (key.toLowerCase() !== wanted) continue;
|
|
4213
|
+
const raw = Array.isArray(value) ? value[0] : value;
|
|
4214
|
+
return typeof raw === "string" && raw.trim() ? raw.trim() : null;
|
|
4215
|
+
}
|
|
4216
|
+
return null;
|
|
4217
|
+
}
|
|
4218
|
+
function resolveTenantIdForDeferredScope(params) {
|
|
4219
|
+
const scopedParams = params;
|
|
4220
|
+
return scopedParams?.tenant?.tenant_id ?? getCurrentTenantId2();
|
|
4221
|
+
}
|
|
4222
|
+
function deferWithTenantDatabaseScope(db, params, work, onError) {
|
|
4223
|
+
const tenantId = resolveTenantIdForDeferredScope(params);
|
|
4224
|
+
if (!tenantId) {
|
|
4225
|
+
const error = new Error("Missing tenant context for deferred tenant-scoped work");
|
|
4226
|
+
if (onError) {
|
|
4227
|
+
onError(error);
|
|
4228
|
+
} else {
|
|
4229
|
+
console.error("[tenant-db-scope] Deferred tenant-scoped work skipped:", error);
|
|
4230
|
+
}
|
|
4231
|
+
return;
|
|
4232
|
+
}
|
|
4233
|
+
const schedule = () => {
|
|
4234
|
+
runWithoutTenantDatabaseScope(() => {
|
|
4235
|
+
setImmediate(() => {
|
|
4236
|
+
void runWithTenantDatabaseScope2(db, tenantId, work).catch((error) => {
|
|
4237
|
+
if (onError) {
|
|
4238
|
+
onError(error);
|
|
4239
|
+
return;
|
|
4240
|
+
}
|
|
4241
|
+
console.error("[tenant-db-scope] Deferred tenant-scoped work failed:", error);
|
|
4242
|
+
});
|
|
4243
|
+
});
|
|
4244
|
+
});
|
|
4245
|
+
};
|
|
4246
|
+
if (enqueueTenantDatabasePostCommitCallback(async () => schedule())) {
|
|
4247
|
+
return;
|
|
4248
|
+
}
|
|
4249
|
+
schedule();
|
|
4250
|
+
}
|
|
4251
|
+
function createTenantDatabaseScopeAroundHook(options) {
|
|
4252
|
+
const multiTenancy = resolveMultiTenancyConfig(options.config);
|
|
4253
|
+
const bearerPayloadFromHeaders = (headers) => {
|
|
4254
|
+
const authorization = readHeaderValue(headers, "authorization");
|
|
4255
|
+
const match = authorization?.match(/^Bearer\s+(.+)$/i);
|
|
4256
|
+
if (!match || !options.jwtSecret) return void 0;
|
|
4257
|
+
try {
|
|
4258
|
+
return jwt3.verify(match[1], options.jwtSecret, {
|
|
4259
|
+
issuer: RUNTIME_JWT_ISSUER,
|
|
4260
|
+
audience: RUNTIME_JWT_AUDIENCE
|
|
4261
|
+
});
|
|
4262
|
+
} catch {
|
|
4263
|
+
return void 0;
|
|
4264
|
+
}
|
|
4265
|
+
};
|
|
4266
|
+
const resolveTenantForDatabaseScope = (context) => {
|
|
4267
|
+
const params = context.params;
|
|
4268
|
+
const connectionTenant = params.connection?.tenant ?? params.connection?.data?.tenant;
|
|
4269
|
+
const paramsWithConnectionTenant = connectionTenant && typeof connectionTenant === "object" && "tenant_id" in connectionTenant ? { ...params, tenant: params.tenant ?? connectionTenant } : params;
|
|
4270
|
+
try {
|
|
4271
|
+
return resolveTenantContext2(multiTenancy, {
|
|
4272
|
+
params: paramsWithConnectionTenant,
|
|
4273
|
+
authPayload: paramsWithConnectionTenant.authentication?.payload ?? bearerPayloadFromHeaders(paramsWithConnectionTenant.headers),
|
|
4274
|
+
headers: paramsWithConnectionTenant.headers
|
|
4275
|
+
});
|
|
4276
|
+
} catch (error) {
|
|
4277
|
+
const inheritedTenantId = getCurrentTenantId2();
|
|
4278
|
+
if (error instanceof TenantResolutionError2 && inheritedTenantId) {
|
|
4279
|
+
return { tenant_id: inheritedTenantId, source: "explicit" };
|
|
4280
|
+
}
|
|
4281
|
+
throw error;
|
|
4282
|
+
}
|
|
4283
|
+
};
|
|
4284
|
+
return async (context, next) => {
|
|
4285
|
+
try {
|
|
4286
|
+
context.params.tenant = resolveTenantForDatabaseScope(context);
|
|
4287
|
+
} catch (error) {
|
|
4288
|
+
if (error instanceof TenantResolutionError2) {
|
|
4289
|
+
throw new NotAuthenticated7(error.message);
|
|
4290
|
+
}
|
|
4291
|
+
throw error;
|
|
4292
|
+
}
|
|
4293
|
+
await runWithTenantDatabaseScope2(options.db, context.params.tenant?.tenant_id, next);
|
|
4294
|
+
};
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4297
|
+
// src/utils/session-queue-tenant-scope.ts
|
|
4298
|
+
function staticTenantId(config) {
|
|
4299
|
+
const multiTenancy = resolveMultiTenancyConfig2(config);
|
|
4300
|
+
return multiTenancy.mode === "static" ? multiTenancy.static_tenant_id : void 0;
|
|
4301
|
+
}
|
|
4302
|
+
function trustedTenantIdHint(options) {
|
|
4303
|
+
const hint = options.tenantIdHint?.trim();
|
|
4304
|
+
return hint || void 0;
|
|
4305
|
+
}
|
|
4306
|
+
function queueTenantParams(params, tenantId, source = "explicit") {
|
|
4307
|
+
const currentTenant = params?.tenant;
|
|
4308
|
+
return {
|
|
4309
|
+
...params ?? {},
|
|
4310
|
+
tenant: {
|
|
4311
|
+
...currentTenant,
|
|
4312
|
+
tenant_id: tenantId,
|
|
4313
|
+
source: currentTenant?.source ?? source
|
|
4314
|
+
}
|
|
4315
|
+
};
|
|
4316
|
+
}
|
|
4317
|
+
function deferWithSessionQueueTenantScope(options, work, onError) {
|
|
4318
|
+
const handleError = (error) => {
|
|
4319
|
+
if (onError) {
|
|
4320
|
+
onError(error);
|
|
4321
|
+
return;
|
|
4322
|
+
}
|
|
4323
|
+
console.error(`\u274C [Queue] ${options.label} failed:`, error);
|
|
4324
|
+
};
|
|
4325
|
+
const capturedTenantId = resolveTenantIdForDeferredScope(options.params);
|
|
4326
|
+
if (capturedTenantId) {
|
|
4327
|
+
const scopedParams2 = queueTenantParams(options.params, capturedTenantId, "explicit");
|
|
4328
|
+
deferWithTenantDatabaseScope(options.db, scopedParams2, () => work(scopedParams2), handleError);
|
|
4329
|
+
return;
|
|
4330
|
+
}
|
|
4331
|
+
const tenantIdHint = trustedTenantIdHint(options);
|
|
4332
|
+
if (tenantIdHint) {
|
|
4333
|
+
const scopedParams2 = queueTenantParams(options.params, tenantIdHint, "explicit");
|
|
4334
|
+
deferWithTenantDatabaseScope(options.db, scopedParams2, () => work(scopedParams2), handleError);
|
|
4335
|
+
return;
|
|
4336
|
+
}
|
|
4337
|
+
const configuredStaticTenantId = staticTenantId(options.config);
|
|
4338
|
+
if (!configuredStaticTenantId) {
|
|
4339
|
+
handleError(
|
|
4340
|
+
new Error(`${options.label} skipped for session ${options.sessionId}: missing tenant context`)
|
|
4341
|
+
);
|
|
4342
|
+
return;
|
|
4343
|
+
}
|
|
4344
|
+
const scopedParams = queueTenantParams(options.params, configuredStaticTenantId, "static");
|
|
4345
|
+
deferWithTenantDatabaseScope(options.db, scopedParams, () => work(scopedParams), handleError);
|
|
4346
|
+
}
|
|
4347
|
+
|
|
3936
4348
|
// src/utils/session-task-state.ts
|
|
3937
4349
|
import {
|
|
3938
4350
|
isTerminalTaskStatus,
|
|
@@ -3980,7 +4392,7 @@ function validateRepoEnvPolicyHook() {
|
|
|
3980
4392
|
const env = validateRepoEnvironment(item.environment);
|
|
3981
4393
|
validateRepoEnvironmentLifecyclePolicy(env, mode);
|
|
3982
4394
|
} catch (error) {
|
|
3983
|
-
throw new
|
|
4395
|
+
throw new BadRequest5(error instanceof Error ? error.message : "Invalid repo environment");
|
|
3984
4396
|
}
|
|
3985
4397
|
}
|
|
3986
4398
|
if (Object.hasOwn(item, "environment_config") && shouldValidateRepoEnvironmentPayload(item.environment_config)) {
|
|
@@ -3988,7 +4400,7 @@ function validateRepoEnvPolicyHook() {
|
|
|
3988
4400
|
const env = wrapV1AsV2(item.environment_config);
|
|
3989
4401
|
if (env) validateRepoEnvironmentLifecyclePolicy(env, mode, "legacy repo environment");
|
|
3990
4402
|
} catch (error) {
|
|
3991
|
-
throw new
|
|
4403
|
+
throw new BadRequest5(
|
|
3992
4404
|
error instanceof Error ? error.message : "Invalid legacy repo environment"
|
|
3993
4405
|
);
|
|
3994
4406
|
}
|
|
@@ -4030,7 +4442,7 @@ function validateBranchEnvPolicyHook() {
|
|
|
4030
4442
|
app: item.app_url
|
|
4031
4443
|
});
|
|
4032
4444
|
} catch (error) {
|
|
4033
|
-
throw new
|
|
4445
|
+
throw new BadRequest5(error instanceof Error ? error.message : "Invalid branch environment");
|
|
4034
4446
|
}
|
|
4035
4447
|
}
|
|
4036
4448
|
return context;
|
|
@@ -4057,6 +4469,10 @@ function shouldRunSessionPostTurnHooks(session) {
|
|
|
4057
4469
|
function shouldDrainQueueAfterSessionPostTurnPatch(session, params) {
|
|
4058
4470
|
return shouldRunSessionPostTurnHooks(session) && session.ready_for_prompt === true && !isTerminalQueueProcessingSuppressed(params);
|
|
4059
4471
|
}
|
|
4472
|
+
function getTrustedSessionTenantId(session) {
|
|
4473
|
+
const tenantId = session?.tenant_id;
|
|
4474
|
+
return typeof tenantId === "string" && tenantId.length > 0 ? tenantId : void 0;
|
|
4475
|
+
}
|
|
4060
4476
|
async function enrichSessionFindResultWithRemoteRelationships(result, sessionsService) {
|
|
4061
4477
|
if (isRemoteRelationshipsEnrichedResult(result)) return result;
|
|
4062
4478
|
if (Array.isArray(result)) {
|
|
@@ -4069,6 +4485,56 @@ async function enrichSessionFindResultWithRemoteRelationships(result, sessionsSe
|
|
|
4069
4485
|
data: await sessionsService.enrichRemoteRelationships(result.data)
|
|
4070
4486
|
});
|
|
4071
4487
|
}
|
|
4488
|
+
var TENANT_OWNED_SERVICE_PATHS = [
|
|
4489
|
+
"sessions",
|
|
4490
|
+
"sessions/:id/mcp-servers",
|
|
4491
|
+
"session-relationships",
|
|
4492
|
+
"tasks",
|
|
4493
|
+
"messages",
|
|
4494
|
+
"boards",
|
|
4495
|
+
"repos",
|
|
4496
|
+
"branches",
|
|
4497
|
+
"branches/:id/owners",
|
|
4498
|
+
"boards/:id/owners",
|
|
4499
|
+
"schedules",
|
|
4500
|
+
"users",
|
|
4501
|
+
"groups",
|
|
4502
|
+
"group-memberships",
|
|
4503
|
+
"branches/:id/group-grants",
|
|
4504
|
+
"boards/:id/group-grants",
|
|
4505
|
+
"app-variables",
|
|
4506
|
+
"mcp-servers",
|
|
4507
|
+
"mcp-servers/discover",
|
|
4508
|
+
"mcp-servers/oauth-auth-headers",
|
|
4509
|
+
"mcp-servers/oauth-complete",
|
|
4510
|
+
"mcp-servers/oauth-disconnect",
|
|
4511
|
+
"mcp-servers/oauth-refresh",
|
|
4512
|
+
"mcp-servers/oauth-start",
|
|
4513
|
+
"mcp-servers/oauth-status",
|
|
4514
|
+
"mcp-servers/test-oauth",
|
|
4515
|
+
"card-types",
|
|
4516
|
+
"cards",
|
|
4517
|
+
"artifacts",
|
|
4518
|
+
"artifact-trust-grants",
|
|
4519
|
+
"board-objects",
|
|
4520
|
+
"session-mcp-servers",
|
|
4521
|
+
"user-mcp-oauth-tokens",
|
|
4522
|
+
"board-comments",
|
|
4523
|
+
"gateway-channels",
|
|
4524
|
+
"gateway",
|
|
4525
|
+
"thread-session-map",
|
|
4526
|
+
"gateway-outbound-messages",
|
|
4527
|
+
"session-env-selections",
|
|
4528
|
+
"kb/namespaces",
|
|
4529
|
+
"kb/documents",
|
|
4530
|
+
"kb/document-edits",
|
|
4531
|
+
"kb/versions",
|
|
4532
|
+
"kb/search",
|
|
4533
|
+
"kb/settings",
|
|
4534
|
+
"kb/indexing/status",
|
|
4535
|
+
"kb/indexing/reindex",
|
|
4536
|
+
"leaderboard"
|
|
4537
|
+
];
|
|
4072
4538
|
function registerHooks(ctx) {
|
|
4073
4539
|
const {
|
|
4074
4540
|
db,
|
|
@@ -4092,6 +4558,76 @@ function registerHooks(ctx) {
|
|
|
4092
4558
|
return void 0;
|
|
4093
4559
|
}
|
|
4094
4560
|
};
|
|
4561
|
+
const multiTenancy = resolveMultiTenancyConfig4(config);
|
|
4562
|
+
const tenantColumnsEnabled = resolveMultiTenancyDatabaseDialect(config) === "postgresql";
|
|
4563
|
+
const executionMode = resolveExecutionSecurityMode(config);
|
|
4564
|
+
const tenantOwnedServicePaths = TENANT_OWNED_SERVICE_PATHS;
|
|
4565
|
+
const stampTenantData = (data, tenantId) => {
|
|
4566
|
+
if (Array.isArray(data)) return data.map((item) => stampTenantData(item, tenantId));
|
|
4567
|
+
if (!data || typeof data !== "object") return data;
|
|
4568
|
+
return { ...data, tenant_id: tenantId };
|
|
4569
|
+
};
|
|
4570
|
+
const stripTenantData = (data) => {
|
|
4571
|
+
if (Array.isArray(data)) return data.map(stripTenantData);
|
|
4572
|
+
if (!data || typeof data !== "object") return data;
|
|
4573
|
+
const clone = { ...data };
|
|
4574
|
+
delete clone.tenant_id;
|
|
4575
|
+
return clone;
|
|
4576
|
+
};
|
|
4577
|
+
const resultBelongsToTenant = (result, tenantId) => {
|
|
4578
|
+
if (Array.isArray(result)) return result.every((item) => resultBelongsToTenant(item, tenantId));
|
|
4579
|
+
if (!result || typeof result !== "object") return true;
|
|
4580
|
+
const record = result;
|
|
4581
|
+
if (Array.isArray(record.data))
|
|
4582
|
+
return record.data.every((item) => resultBelongsToTenant(item, tenantId));
|
|
4583
|
+
if (!("tenant_id" in record)) return true;
|
|
4584
|
+
return record.tenant_id === tenantId;
|
|
4585
|
+
};
|
|
4586
|
+
const tenantDatabaseScopeAround = createTenantDatabaseScopeAroundHook({
|
|
4587
|
+
db,
|
|
4588
|
+
config,
|
|
4589
|
+
jwtSecret
|
|
4590
|
+
});
|
|
4591
|
+
const ensureTenantContext = async (context) => {
|
|
4592
|
+
try {
|
|
4593
|
+
context.params.tenant = resolveTenantContext3(multiTenancy, { params: context.params });
|
|
4594
|
+
return context;
|
|
4595
|
+
} catch (error) {
|
|
4596
|
+
if (error instanceof TenantResolutionError3) {
|
|
4597
|
+
throw new NotAuthenticated8(error.message);
|
|
4598
|
+
}
|
|
4599
|
+
throw error;
|
|
4600
|
+
}
|
|
4601
|
+
};
|
|
4602
|
+
const scopeTenantBefore = async (context) => {
|
|
4603
|
+
await ensureTenantContext(context);
|
|
4604
|
+
const tenantId = context.params.tenant?.tenant_id;
|
|
4605
|
+
if (!tenantId) return context;
|
|
4606
|
+
if (context.method === "create") {
|
|
4607
|
+
context.data = stampTenantData(context.data, tenantId);
|
|
4608
|
+
} else if (context.method === "update" || context.method === "patch") {
|
|
4609
|
+
context.data = stripTenantData(context.data);
|
|
4610
|
+
}
|
|
4611
|
+
return context;
|
|
4612
|
+
};
|
|
4613
|
+
const assertTenantAfter = async (context) => {
|
|
4614
|
+
const tenantId = context.params.tenant?.tenant_id;
|
|
4615
|
+
if (tenantId && !resultBelongsToTenant(context.result, tenantId)) {
|
|
4616
|
+
throw new NotAuthenticated8("Tenant isolation check failed");
|
|
4617
|
+
}
|
|
4618
|
+
return context;
|
|
4619
|
+
};
|
|
4620
|
+
const registerTenantHooks = () => {
|
|
4621
|
+
for (const path4 of tenantOwnedServicePaths) {
|
|
4622
|
+
const service = safeService(path4);
|
|
4623
|
+
if (!service) continue;
|
|
4624
|
+
service.hooks({
|
|
4625
|
+
around: { all: [tenantDatabaseScopeAround] },
|
|
4626
|
+
before: { all: [scopeTenantBefore] },
|
|
4627
|
+
after: { all: [assertTenantAfter] }
|
|
4628
|
+
});
|
|
4629
|
+
}
|
|
4630
|
+
};
|
|
4095
4631
|
const realtimeAccessCache = new RealtimeAccessCache({
|
|
4096
4632
|
branchRepository,
|
|
4097
4633
|
sessionsRepository
|
|
@@ -4114,12 +4650,21 @@ function registerHooks(ctx) {
|
|
|
4114
4650
|
await invalidateRealtimeBranchAccess(context.params.route?.id);
|
|
4115
4651
|
return context;
|
|
4116
4652
|
};
|
|
4117
|
-
const
|
|
4118
|
-
if (!jwtSecret) return;
|
|
4119
|
-
|
|
4653
|
+
const createExecutorServiceToken = (params, scope) => {
|
|
4654
|
+
if (!jwtSecret) return void 0;
|
|
4655
|
+
return createServiceToken(jwtSecret, void 0, {
|
|
4656
|
+
...serviceTokenScopeForParams(params),
|
|
4657
|
+
...scope
|
|
4658
|
+
});
|
|
4659
|
+
};
|
|
4660
|
+
const syncBranchUnixAccess = (branchId, logPrefix, params, options) => {
|
|
4661
|
+
if (!executionMode.unixFsIsolationEnabled) return;
|
|
4662
|
+
const serviceToken = createExecutorServiceToken(params, {
|
|
4663
|
+
...options?.scope,
|
|
4120
4664
|
branch_id: branchId,
|
|
4121
4665
|
command: "unix.sync-branch"
|
|
4122
4666
|
});
|
|
4667
|
+
if (!serviceToken) return;
|
|
4123
4668
|
spawnExecutorFireAndForget(
|
|
4124
4669
|
{
|
|
4125
4670
|
command: "unix.sync-branch",
|
|
@@ -4127,14 +4672,16 @@ function registerHooks(ctx) {
|
|
|
4127
4672
|
daemonUrl: getDaemonUrl(),
|
|
4128
4673
|
params: {
|
|
4129
4674
|
branchId,
|
|
4130
|
-
daemonUser: config.daemon?.unix_user
|
|
4675
|
+
daemonUser: config.daemon?.unix_user,
|
|
4676
|
+
...options?.delete ? { delete: true } : {}
|
|
4131
4677
|
}
|
|
4132
4678
|
},
|
|
4133
4679
|
{ logPrefix }
|
|
4134
4680
|
);
|
|
4135
4681
|
};
|
|
4136
|
-
const syncUnixAccessForBoardAlignedBranches = async (boardId, logPrefix) => {
|
|
4137
|
-
if (!
|
|
4682
|
+
const syncUnixAccessForBoardAlignedBranches = async (boardId, logPrefix, params) => {
|
|
4683
|
+
if (!executionMode.unixFsIsolationEnabled) return;
|
|
4684
|
+
if (typeof boardId !== "string" || boardId.length === 0) return;
|
|
4138
4685
|
const alignedBranches = await branchRepository.findBoardAlignedBranches(boardId);
|
|
4139
4686
|
if (alignedBranches.length === 0) return;
|
|
4140
4687
|
console.log(
|
|
@@ -4143,10 +4690,11 @@ function registerHooks(ctx) {
|
|
|
4143
4690
|
for (const branch of alignedBranches) {
|
|
4144
4691
|
await invalidateRealtimeBranchAccess(branch.branch_id);
|
|
4145
4692
|
}
|
|
4146
|
-
const serviceToken =
|
|
4693
|
+
const serviceToken = createExecutorServiceToken(params, {
|
|
4147
4694
|
board_id: boardId,
|
|
4148
4695
|
command: "unix.sync-board"
|
|
4149
4696
|
});
|
|
4697
|
+
if (!serviceToken) return;
|
|
4150
4698
|
spawnExecutorFireAndForget(
|
|
4151
4699
|
{
|
|
4152
4700
|
command: "unix.sync-board",
|
|
@@ -4161,15 +4709,43 @@ function registerHooks(ctx) {
|
|
|
4161
4709
|
);
|
|
4162
4710
|
};
|
|
4163
4711
|
const syncUnixAccessForBoardFromRoute = async (context, logPrefix) => {
|
|
4164
|
-
await syncUnixAccessForBoardAlignedBranches(
|
|
4712
|
+
await syncUnixAccessForBoardAlignedBranches(
|
|
4713
|
+
context.params.route?.id,
|
|
4714
|
+
logPrefix,
|
|
4715
|
+
context.params
|
|
4716
|
+
);
|
|
4165
4717
|
return context;
|
|
4166
4718
|
};
|
|
4167
|
-
const
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4719
|
+
const membershipGroupIdFromContext = (context) => {
|
|
4720
|
+
const resultGroupId = context.result?.group_id;
|
|
4721
|
+
if (typeof resultGroupId === "string" && resultGroupId.length > 0) {
|
|
4722
|
+
return resultGroupId;
|
|
4723
|
+
}
|
|
4724
|
+
const dataGroupId = context.data?.group_id;
|
|
4725
|
+
if (typeof dataGroupId === "string" && dataGroupId.length > 0) return dataGroupId;
|
|
4726
|
+
const queryGroupId = context.params.query?.group_id;
|
|
4727
|
+
if (typeof queryGroupId === "string" && queryGroupId.length > 0) return queryGroupId;
|
|
4728
|
+
const routeGroupId = context.params.route?.groupId;
|
|
4729
|
+
if (typeof routeGroupId === "string" && routeGroupId.length > 0) return routeGroupId;
|
|
4730
|
+
return void 0;
|
|
4731
|
+
};
|
|
4732
|
+
const syncUnixAccessForGroupGrantedBranches = async (context, logPrefix) => {
|
|
4733
|
+
if (!executionMode.unixFsIsolationEnabled) return context;
|
|
4734
|
+
const groupId = membershipGroupIdFromContext(context);
|
|
4735
|
+
if (!groupId) {
|
|
4736
|
+
console.warn(
|
|
4737
|
+
`[Unix Integration] Could not resolve group_id for ${context.path}.${context.method}; skipping group membership permission sync`
|
|
4738
|
+
);
|
|
4739
|
+
return context;
|
|
4740
|
+
}
|
|
4741
|
+
const branchIds = await branchRepository.findExplicitFsAccessBranchIdsForGroup(groupId);
|
|
4742
|
+
if (branchIds.length === 0) return context;
|
|
4743
|
+
console.log(
|
|
4744
|
+
`[Unix Integration] Queueing group membership permission sync for ${branchIds.length} branch(es) granted to group ${shortId5(groupId)}`
|
|
4745
|
+
);
|
|
4746
|
+
for (const branchId of branchIds) {
|
|
4747
|
+
syncBranchUnixAccess(branchId, logPrefix, context.params);
|
|
4748
|
+
await invalidateRealtimeBranchAccess(branchId);
|
|
4173
4749
|
}
|
|
4174
4750
|
return context;
|
|
4175
4751
|
};
|
|
@@ -4185,7 +4761,7 @@ function registerHooks(ctx) {
|
|
|
4185
4761
|
// RBAC: Scope messages.find() to sessions the caller can access.
|
|
4186
4762
|
// Without this backstop, any authenticated member could list messages
|
|
4187
4763
|
// across every session/branch by omitting the session_id filter.
|
|
4188
|
-
...branchRbacEnabled ? [
|
|
4764
|
+
...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
|
|
4189
4765
|
],
|
|
4190
4766
|
get: [
|
|
4191
4767
|
...branchRbacEnabled ? [
|
|
@@ -4197,7 +4773,7 @@ function registerHooks(ctx) {
|
|
|
4197
4773
|
] : []
|
|
4198
4774
|
],
|
|
4199
4775
|
create: [
|
|
4200
|
-
requireMinimumRole(
|
|
4776
|
+
requireMinimumRole(ROLES10.MEMBER, "create messages"),
|
|
4201
4777
|
...branchRbacEnabled ? [
|
|
4202
4778
|
resolveSessionContext(),
|
|
4203
4779
|
loadSession(sessionsService),
|
|
@@ -4209,7 +4785,7 @@ function registerHooks(ctx) {
|
|
|
4209
4785
|
] : []
|
|
4210
4786
|
],
|
|
4211
4787
|
patch: [
|
|
4212
|
-
requireMinimumRole(
|
|
4788
|
+
requireMinimumRole(ROLES10.MEMBER, "update messages"),
|
|
4213
4789
|
...branchRbacEnabled ? [
|
|
4214
4790
|
resolveSessionContext(),
|
|
4215
4791
|
loadSession(sessionsService),
|
|
@@ -4219,7 +4795,7 @@ function registerHooks(ctx) {
|
|
|
4219
4795
|
] : []
|
|
4220
4796
|
],
|
|
4221
4797
|
remove: [
|
|
4222
|
-
requireMinimumRole(
|
|
4798
|
+
requireMinimumRole(ROLES10.MEMBER, "delete messages"),
|
|
4223
4799
|
...branchRbacEnabled ? [
|
|
4224
4800
|
resolveSessionContext(),
|
|
4225
4801
|
loadSession(sessionsService),
|
|
@@ -4253,141 +4829,51 @@ function registerHooks(ctx) {
|
|
|
4253
4829
|
]
|
|
4254
4830
|
}
|
|
4255
4831
|
});
|
|
4256
|
-
const boardObjectRepository = new BoardObjectRepository2(db);
|
|
4257
4832
|
safeService("board-objects")?.hooks({
|
|
4258
4833
|
before: {
|
|
4259
4834
|
all: [
|
|
4260
4835
|
typedValidateQuery(boardObjectQueryValidator),
|
|
4261
4836
|
requireAuth,
|
|
4262
|
-
requireMinimumRole(
|
|
4837
|
+
requireMinimumRole(ROLES10.MEMBER, "manage board objects")
|
|
4263
4838
|
],
|
|
4264
|
-
//
|
|
4265
|
-
//
|
|
4266
|
-
//
|
|
4267
|
-
//
|
|
4268
|
-
|
|
4269
|
-
// SQL query that preserves card/zone rows while scoping branch-bound ones.
|
|
4270
|
-
find: [
|
|
4271
|
-
...branchRbacEnabled ? [
|
|
4272
|
-
async (context) => {
|
|
4273
|
-
if (!context.params.provider) return context;
|
|
4274
|
-
const userId = context.params.user?.user_id;
|
|
4275
|
-
const normalized = normalizeBoardObjectFindQuery(context.params.query);
|
|
4276
|
-
if (!userId) {
|
|
4277
|
-
context.result = {
|
|
4278
|
-
total: 0,
|
|
4279
|
-
limit: normalized.limit,
|
|
4280
|
-
skip: normalized.skip,
|
|
4281
|
-
data: []
|
|
4282
|
-
};
|
|
4283
|
-
return context;
|
|
4284
|
-
}
|
|
4285
|
-
const [total, data] = await Promise.all([
|
|
4286
|
-
boardObjectRepository.countVisibleToUser(userId, normalized.filters),
|
|
4287
|
-
boardObjectRepository.findVisibleToUser(
|
|
4288
|
-
userId,
|
|
4289
|
-
normalized.filters,
|
|
4290
|
-
normalized.pagination
|
|
4291
|
-
)
|
|
4292
|
-
]);
|
|
4293
|
-
context.result = {
|
|
4294
|
-
total,
|
|
4295
|
-
limit: normalized.limit,
|
|
4296
|
-
skip: normalized.skip,
|
|
4297
|
-
data
|
|
4298
|
-
};
|
|
4299
|
-
context.params._boardObjectsRbacScoped = true;
|
|
4300
|
-
return context;
|
|
4301
|
-
}
|
|
4302
|
-
] : []
|
|
4303
|
-
]
|
|
4304
|
-
},
|
|
4305
|
-
after: {
|
|
4306
|
-
find: [
|
|
4307
|
-
...branchRbacEnabled ? [
|
|
4308
|
-
// Filter board-objects based on branch access permissions
|
|
4309
|
-
async (context) => {
|
|
4310
|
-
if (context.params._boardObjectsRbacScoped) {
|
|
4311
|
-
return context;
|
|
4312
|
-
}
|
|
4313
|
-
if (!context.params.provider) {
|
|
4314
|
-
return context;
|
|
4315
|
-
}
|
|
4316
|
-
const userId = context.params.user?.user_id;
|
|
4317
|
-
if (!userId) {
|
|
4318
|
-
context.result = {
|
|
4319
|
-
total: 0,
|
|
4320
|
-
limit: context.result?.limit ?? 0,
|
|
4321
|
-
skip: context.result?.skip ?? 0,
|
|
4322
|
-
data: []
|
|
4323
|
-
};
|
|
4324
|
-
return context;
|
|
4325
|
-
}
|
|
4326
|
-
const boardObjects = context.result?.data ?? context.result ?? [];
|
|
4327
|
-
const authorizedBoardObjects = [];
|
|
4328
|
-
for (const boardObject of boardObjects) {
|
|
4329
|
-
if (boardObject.branch_id) {
|
|
4330
|
-
const branch = await branchRepository.findById(boardObject.branch_id);
|
|
4331
|
-
if (!branch) {
|
|
4332
|
-
continue;
|
|
4333
|
-
}
|
|
4334
|
-
const effectivePermission = await branchRepository.resolveUserPermission(
|
|
4335
|
-
branch,
|
|
4336
|
-
userId
|
|
4337
|
-
);
|
|
4338
|
-
const hasAccess = PERMISSION_RANK[effectivePermission] >= PERMISSION_RANK.view;
|
|
4339
|
-
if (hasAccess) {
|
|
4340
|
-
authorizedBoardObjects.push(boardObject);
|
|
4341
|
-
}
|
|
4342
|
-
} else if (boardObject.card_id) {
|
|
4343
|
-
authorizedBoardObjects.push(boardObject);
|
|
4344
|
-
} else {
|
|
4345
|
-
authorizedBoardObjects.push(boardObject);
|
|
4346
|
-
}
|
|
4347
|
-
}
|
|
4348
|
-
if (context.result?.data) {
|
|
4349
|
-
context.result.data = authorizedBoardObjects;
|
|
4350
|
-
context.result.total = authorizedBoardObjects.length;
|
|
4351
|
-
} else {
|
|
4352
|
-
context.result = authorizedBoardObjects;
|
|
4353
|
-
}
|
|
4354
|
-
return context;
|
|
4355
|
-
}
|
|
4356
|
-
] : []
|
|
4357
|
-
]
|
|
4839
|
+
// Board-objects may reference a branch or may be loose board/card/layout
|
|
4840
|
+
// rows. The service composes this marker into an object-specific SQL
|
|
4841
|
+
// predicate: branch-bound rows require branch access; loose rows require
|
|
4842
|
+
// board visibility.
|
|
4843
|
+
find: [...branchRbacEnabled ? [scopeFindToAccessibleBoardsSql(superadminOpts)] : []]
|
|
4358
4844
|
}
|
|
4359
4845
|
});
|
|
4360
4846
|
safeService("card-types")?.hooks({
|
|
4361
4847
|
before: {
|
|
4362
4848
|
all: [requireAuth],
|
|
4363
|
-
create: [requireMinimumRole(
|
|
4364
|
-
patch: [requireMinimumRole(
|
|
4365
|
-
remove: [requireMinimumRole(
|
|
4849
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "create card types")],
|
|
4850
|
+
patch: [requireMinimumRole(ROLES10.MEMBER, "update card types")],
|
|
4851
|
+
remove: [requireMinimumRole(ROLES10.MEMBER, "delete card types")]
|
|
4366
4852
|
}
|
|
4367
4853
|
});
|
|
4368
4854
|
safeService("cards")?.hooks({
|
|
4369
4855
|
before: {
|
|
4370
4856
|
all: [requireAuth],
|
|
4371
|
-
create: [requireMinimumRole(
|
|
4372
|
-
patch: [requireMinimumRole(
|
|
4373
|
-
remove: [requireMinimumRole(
|
|
4857
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "create cards"), injectCreatedBy()],
|
|
4858
|
+
patch: [requireMinimumRole(ROLES10.MEMBER, "update cards")],
|
|
4859
|
+
remove: [requireMinimumRole(ROLES10.MEMBER, "delete cards")]
|
|
4374
4860
|
}
|
|
4375
4861
|
});
|
|
4376
4862
|
const ensureArtifactOwnerOrAdmin = () => async (context) => {
|
|
4377
4863
|
if (!context.params.provider) return context;
|
|
4378
4864
|
const user = context.params?.user;
|
|
4379
|
-
if (!user) throw new
|
|
4865
|
+
if (!user) throw new NotAuthenticated8("Authentication required");
|
|
4380
4866
|
if (user._isServiceAccount) return context;
|
|
4381
|
-
if (
|
|
4867
|
+
if (hasMinimumRole9(user.role, ROLES10.ADMIN)) return context;
|
|
4382
4868
|
const artifactId = context.id;
|
|
4383
4869
|
if (artifactId === void 0 || artifactId === null) return context;
|
|
4384
4870
|
const artifactRepo = new ArtifactRepository(db);
|
|
4385
4871
|
const artifact = await artifactRepo.findById(String(artifactId));
|
|
4386
4872
|
if (!artifact) {
|
|
4387
|
-
throw new
|
|
4873
|
+
throw new Forbidden9(`Artifact ${artifactId} not found or not accessible`);
|
|
4388
4874
|
}
|
|
4389
4875
|
if (artifact.created_by && artifact.created_by === user.user_id) return context;
|
|
4390
|
-
throw new
|
|
4876
|
+
throw new Forbidden9(
|
|
4391
4877
|
"Only the artifact's creator or an admin may modify it. Use agor_artifacts_publish to create your own copy."
|
|
4392
4878
|
);
|
|
4393
4879
|
};
|
|
@@ -4396,15 +4882,14 @@ function registerHooks(ctx) {
|
|
|
4396
4882
|
all: [requireAuth],
|
|
4397
4883
|
find: [
|
|
4398
4884
|
// RBAC: Artifacts carry a `branch_id` (nullable — survives branch deletion).
|
|
4399
|
-
// Scope find() to the branches the caller can access.
|
|
4400
|
-
//
|
|
4401
|
-
//
|
|
4402
|
-
|
|
4403
|
-
...branchRbacEnabled ? [scopeFindToAccessibleBranches(branchRepository, superadminOpts)] : []
|
|
4885
|
+
// Scope find() to the branches the caller can access. The service pushes
|
|
4886
|
+
// this into SQL as a correlated visibility predicate rather than
|
|
4887
|
+
// preloading ids and injecting `branch_id IN (...)`.
|
|
4888
|
+
...branchRbacEnabled ? [scopeFindToAccessibleBranchesSql(superadminOpts)] : []
|
|
4404
4889
|
],
|
|
4405
|
-
create: [requireMinimumRole(
|
|
4406
|
-
patch: [requireMinimumRole(
|
|
4407
|
-
remove: [requireMinimumRole(
|
|
4890
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "create artifacts"), injectCreatedBy()],
|
|
4891
|
+
patch: [requireMinimumRole(ROLES10.MEMBER, "update artifacts"), ensureArtifactOwnerOrAdmin()],
|
|
4892
|
+
remove: [requireMinimumRole(ROLES10.MEMBER, "delete artifacts"), ensureArtifactOwnerOrAdmin()]
|
|
4408
4893
|
}
|
|
4409
4894
|
});
|
|
4410
4895
|
if (svcEnabled("artifacts")) {
|
|
@@ -4419,7 +4904,7 @@ function registerHooks(ctx) {
|
|
|
4419
4904
|
return artifactsService.getPayload(artifactId, _params.user?.user_id);
|
|
4420
4905
|
}
|
|
4421
4906
|
},
|
|
4422
|
-
{ find: { role:
|
|
4907
|
+
{ find: { role: ROLES10.VIEWER, action: "get artifact payload" } },
|
|
4423
4908
|
requireAuth
|
|
4424
4909
|
);
|
|
4425
4910
|
registerAuthenticatedRoute(
|
|
@@ -4446,7 +4931,7 @@ function registerHooks(ctx) {
|
|
|
4446
4931
|
}
|
|
4447
4932
|
},
|
|
4448
4933
|
{
|
|
4449
|
-
create: { role:
|
|
4934
|
+
create: { role: ROLES10.MEMBER, action: "post artifact console logs" }
|
|
4450
4935
|
},
|
|
4451
4936
|
requireAuth
|
|
4452
4937
|
);
|
|
@@ -4475,7 +4960,7 @@ function registerHooks(ctx) {
|
|
|
4475
4960
|
}
|
|
4476
4961
|
},
|
|
4477
4962
|
{
|
|
4478
|
-
create: { role:
|
|
4963
|
+
create: { role: ROLES10.MEMBER, action: "post artifact sandpack error" }
|
|
4479
4964
|
},
|
|
4480
4965
|
requireAuth
|
|
4481
4966
|
);
|
|
@@ -4516,7 +5001,7 @@ function registerHooks(ctx) {
|
|
|
4516
5001
|
}
|
|
4517
5002
|
},
|
|
4518
5003
|
{
|
|
4519
|
-
create: { role:
|
|
5004
|
+
create: { role: ROLES10.MEMBER, action: "post artifact runtime response" }
|
|
4520
5005
|
},
|
|
4521
5006
|
requireAuth
|
|
4522
5007
|
);
|
|
@@ -4538,7 +5023,7 @@ function registerHooks(ctx) {
|
|
|
4538
5023
|
}
|
|
4539
5024
|
},
|
|
4540
5025
|
{
|
|
4541
|
-
create: { role:
|
|
5026
|
+
create: { role: ROLES10.MEMBER, action: "create artifact trust grant" }
|
|
4542
5027
|
},
|
|
4543
5028
|
requireAuth
|
|
4544
5029
|
);
|
|
@@ -4562,8 +5047,8 @@ function registerHooks(ctx) {
|
|
|
4562
5047
|
}
|
|
4563
5048
|
},
|
|
4564
5049
|
{
|
|
4565
|
-
find: { role:
|
|
4566
|
-
remove: { role:
|
|
5050
|
+
find: { role: ROLES10.VIEWER, action: "list artifact trust grants" },
|
|
5051
|
+
remove: { role: ROLES10.MEMBER, action: "revoke artifact trust grant" }
|
|
4567
5052
|
},
|
|
4568
5053
|
requireAuth
|
|
4569
5054
|
);
|
|
@@ -4571,9 +5056,15 @@ function registerHooks(ctx) {
|
|
|
4571
5056
|
safeService("board-comments")?.hooks({
|
|
4572
5057
|
before: {
|
|
4573
5058
|
all: [typedValidateQuery(boardCommentQueryValidator), requireAuth],
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
5059
|
+
find: [
|
|
5060
|
+
// Board comments inherit board visibility for pure board/spatial
|
|
5061
|
+
// comments and branch/session/task/message visibility for attached
|
|
5062
|
+
// comments. The service pushes the marker into SQL.
|
|
5063
|
+
...branchRbacEnabled ? [scopeFindToAccessibleBoardsSql(superadminOpts)] : []
|
|
5064
|
+
],
|
|
5065
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "create board comments"), injectCreatedBy()],
|
|
5066
|
+
patch: [requireMinimumRole(ROLES10.MEMBER, "update board comments")],
|
|
5067
|
+
remove: [requireMinimumRole(ROLES10.MEMBER, "delete board comments")]
|
|
4577
5068
|
}
|
|
4578
5069
|
});
|
|
4579
5070
|
app.service("repos").hooks({
|
|
@@ -4581,24 +5072,24 @@ function registerHooks(ctx) {
|
|
|
4581
5072
|
all: [
|
|
4582
5073
|
typedValidateQuery(repoQueryValidator),
|
|
4583
5074
|
requireAuth,
|
|
4584
|
-
requireMinimumRole(
|
|
5075
|
+
requireMinimumRole(ROLES10.MEMBER, "access repositories")
|
|
4585
5076
|
],
|
|
4586
5077
|
create: [
|
|
4587
|
-
requireMinimumRole(
|
|
5078
|
+
requireMinimumRole(ROLES10.MEMBER, "create repositories"),
|
|
4588
5079
|
requireAdminForEnvConfig(),
|
|
4589
5080
|
validateRepoEnvPolicyHook()
|
|
4590
5081
|
],
|
|
4591
5082
|
update: [
|
|
4592
|
-
requireMinimumRole(
|
|
5083
|
+
requireMinimumRole(ROLES10.MEMBER, "update repositories"),
|
|
4593
5084
|
requireAdminForEnvConfig(),
|
|
4594
5085
|
validateRepoEnvPolicyHook()
|
|
4595
5086
|
],
|
|
4596
5087
|
patch: [
|
|
4597
|
-
requireMinimumRole(
|
|
5088
|
+
requireMinimumRole(ROLES10.MEMBER, "update repositories"),
|
|
4598
5089
|
requireAdminForEnvConfig(),
|
|
4599
5090
|
validateRepoEnvPolicyHook()
|
|
4600
5091
|
],
|
|
4601
|
-
remove: [requireMinimumRole(
|
|
5092
|
+
remove: [requireMinimumRole(ROLES10.MEMBER, "delete repositories")]
|
|
4602
5093
|
},
|
|
4603
5094
|
after: {
|
|
4604
5095
|
patch: [realignRepoOriginAfterPatchHook()]
|
|
@@ -4610,12 +5101,12 @@ function registerHooks(ctx) {
|
|
|
4610
5101
|
typedValidateQuery(branchQueryValidator),
|
|
4611
5102
|
requireAuth,
|
|
4612
5103
|
executorRuntimeScopeGuard(),
|
|
4613
|
-
requireMinimumRole(
|
|
5104
|
+
requireMinimumRole(ROLES10.MEMBER, "access branches")
|
|
4614
5105
|
],
|
|
4615
5106
|
find: [
|
|
4616
|
-
// RBAC:
|
|
4617
|
-
//
|
|
4618
|
-
...branchRbacEnabled ? [
|
|
5107
|
+
// RBAC: mark external regular-user finds for BranchesService to compose
|
|
5108
|
+
// the shared branch visibility predicate directly into its SQL read.
|
|
5109
|
+
...branchRbacEnabled ? [scopeFindToAccessibleBranchesSql(superadminOpts)] : []
|
|
4619
5110
|
],
|
|
4620
5111
|
get: [
|
|
4621
5112
|
...branchRbacEnabled ? [
|
|
@@ -4625,13 +5116,13 @@ function registerHooks(ctx) {
|
|
|
4625
5116
|
] : []
|
|
4626
5117
|
],
|
|
4627
5118
|
create: [
|
|
4628
|
-
requireMinimumRole(
|
|
5119
|
+
requireMinimumRole(ROLES10.MEMBER, "create branches"),
|
|
4629
5120
|
requireAdminForEnvConfig(),
|
|
4630
5121
|
validateBranchEnvPolicyHook(),
|
|
4631
5122
|
injectCreatedBy()
|
|
4632
5123
|
],
|
|
4633
5124
|
update: [
|
|
4634
|
-
requireMinimumRole(
|
|
5125
|
+
requireMinimumRole(ROLES10.MEMBER, "update branches"),
|
|
4635
5126
|
requireAdminForEnvConfig(),
|
|
4636
5127
|
validateBranchEnvPolicyHook()
|
|
4637
5128
|
],
|
|
@@ -4643,13 +5134,13 @@ function registerHooks(ctx) {
|
|
|
4643
5134
|
ensureBranchPermission("all", "update branches", superadminOpts)
|
|
4644
5135
|
// Require 'all' permission to update
|
|
4645
5136
|
] : [],
|
|
4646
|
-
// Capture previous others_fs_access for comparison in after hook
|
|
4647
|
-
...
|
|
5137
|
+
// Capture previous others_fs_access for comparison in after Unix sync hook.
|
|
5138
|
+
...executionMode.unixFsIsolationEnabled ? [
|
|
4648
5139
|
async (context) => {
|
|
4649
5140
|
const patchData = context.data;
|
|
4650
5141
|
const params = context.params;
|
|
4651
5142
|
if (Object.hasOwn(patchData, "others_fs_access") && !params._skipUnixSync) {
|
|
4652
|
-
const branch = await context.service.get(context.id);
|
|
5143
|
+
const branch = await context.service.get(context.id, context.params);
|
|
4653
5144
|
params._previousOthersFsAccess = branch.others_fs_access;
|
|
4654
5145
|
}
|
|
4655
5146
|
return context;
|
|
@@ -4684,7 +5175,7 @@ function registerHooks(ctx) {
|
|
|
4684
5175
|
],
|
|
4685
5176
|
patch: [
|
|
4686
5177
|
invalidateRealtimeBranchFromResult,
|
|
4687
|
-
...
|
|
5178
|
+
...executionMode.unixFsIsolationEnabled ? [
|
|
4688
5179
|
async (context) => {
|
|
4689
5180
|
const params = context.params;
|
|
4690
5181
|
if (params._skipUnixSync) {
|
|
@@ -4708,56 +5199,29 @@ function registerHooks(ctx) {
|
|
|
4708
5199
|
);
|
|
4709
5200
|
return context;
|
|
4710
5201
|
}
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
spawnExecutorFireAndForget(
|
|
4720
|
-
{
|
|
4721
|
-
command: "unix.sync-branch",
|
|
4722
|
-
sessionToken: serviceToken,
|
|
4723
|
-
daemonUrl: getDaemonUrl(),
|
|
4724
|
-
params: {
|
|
4725
|
-
branchId: branch.branch_id,
|
|
4726
|
-
daemonUser: config.daemon?.unix_user
|
|
4727
|
-
}
|
|
4728
|
-
},
|
|
4729
|
-
{ logPrefix: "[Executor/branch.patch]" }
|
|
4730
|
-
);
|
|
4731
|
-
}
|
|
5202
|
+
console.log(
|
|
5203
|
+
`[Unix Integration] Syncing permissions for branch ${shortId5(branch.branch_id)} (others_fs_access: ${previousValue} -> ${branch.others_fs_access})`
|
|
5204
|
+
);
|
|
5205
|
+
syncBranchUnixAccess(
|
|
5206
|
+
branch.branch_id,
|
|
5207
|
+
"[Executor/branch.patch]",
|
|
5208
|
+
context.params
|
|
5209
|
+
);
|
|
4732
5210
|
return context;
|
|
4733
5211
|
}
|
|
4734
5212
|
] : []
|
|
4735
5213
|
],
|
|
4736
5214
|
remove: [
|
|
4737
5215
|
invalidateRealtimeBranchFromResult,
|
|
4738
|
-
...
|
|
5216
|
+
...executionMode.unixFsIsolationEnabled ? [
|
|
4739
5217
|
async (context) => {
|
|
4740
5218
|
const branchId = context.id;
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
}
|
|
4746
|
-
|
|
4747
|
-
{
|
|
4748
|
-
command: "unix.sync-branch",
|
|
4749
|
-
sessionToken: serviceToken,
|
|
4750
|
-
daemonUrl: getDaemonUrl(),
|
|
4751
|
-
params: {
|
|
4752
|
-
branchId,
|
|
4753
|
-
daemonUser: config.daemon?.unix_user,
|
|
4754
|
-
delete: true
|
|
4755
|
-
// Signal to delete the group instead of syncing
|
|
4756
|
-
}
|
|
4757
|
-
},
|
|
4758
|
-
{ logPrefix: "[Executor/branch.remove]" }
|
|
4759
|
-
);
|
|
4760
|
-
}
|
|
5219
|
+
syncBranchUnixAccess(
|
|
5220
|
+
branchId,
|
|
5221
|
+
"[Executor/branch.remove]",
|
|
5222
|
+
context.params,
|
|
5223
|
+
{ delete: true }
|
|
5224
|
+
);
|
|
4761
5225
|
return context;
|
|
4762
5226
|
}
|
|
4763
5227
|
] : []
|
|
@@ -4767,28 +5231,28 @@ function registerHooks(ctx) {
|
|
|
4767
5231
|
safeService("kb/namespaces")?.hooks({
|
|
4768
5232
|
before: {
|
|
4769
5233
|
all: [requireAuth],
|
|
4770
|
-
create: [requireMinimumRole(
|
|
4771
|
-
patch: [requireMinimumRole(
|
|
4772
|
-
update: [requireMinimumRole(
|
|
4773
|
-
remove: [requireMinimumRole(
|
|
4774
|
-
saveWithAcl: [requireMinimumRole(
|
|
4775
|
-
listAcl: [requireMinimumRole(
|
|
4776
|
-
setAcl: [requireMinimumRole(
|
|
4777
|
-
removeAcl: [requireMinimumRole(
|
|
5234
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "create knowledge namespaces")],
|
|
5235
|
+
patch: [requireMinimumRole(ROLES10.MEMBER, "update knowledge namespaces")],
|
|
5236
|
+
update: [requireMinimumRole(ROLES10.MEMBER, "update knowledge namespaces")],
|
|
5237
|
+
remove: [requireMinimumRole(ROLES10.MEMBER, "delete knowledge namespaces")],
|
|
5238
|
+
saveWithAcl: [requireMinimumRole(ROLES10.MEMBER, "save knowledge namespace permissions")],
|
|
5239
|
+
listAcl: [requireMinimumRole(ROLES10.MEMBER, "manage knowledge namespace permissions")],
|
|
5240
|
+
setAcl: [requireMinimumRole(ROLES10.MEMBER, "manage knowledge namespace permissions")],
|
|
5241
|
+
removeAcl: [requireMinimumRole(ROLES10.MEMBER, "manage knowledge namespace permissions")]
|
|
4778
5242
|
}
|
|
4779
5243
|
});
|
|
4780
5244
|
safeService("kb/documents")?.hooks({
|
|
4781
5245
|
before: {
|
|
4782
5246
|
all: [requireAuth],
|
|
4783
|
-
create: [requireMinimumRole(
|
|
4784
|
-
patch: [requireMinimumRole(
|
|
4785
|
-
update: [requireMinimumRole(
|
|
4786
|
-
remove: [requireMinimumRole(
|
|
5247
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "create knowledge documents")],
|
|
5248
|
+
patch: [requireMinimumRole(ROLES10.MEMBER, "update knowledge documents")],
|
|
5249
|
+
update: [requireMinimumRole(ROLES10.MEMBER, "update knowledge documents")],
|
|
5250
|
+
remove: [requireMinimumRole(ROLES10.MEMBER, "delete knowledge documents")]
|
|
4787
5251
|
}
|
|
4788
5252
|
});
|
|
4789
5253
|
safeService("kb/document-edits")?.hooks({
|
|
4790
5254
|
before: {
|
|
4791
|
-
all: [requireAuth, requireMinimumRole(
|
|
5255
|
+
all: [requireAuth, requireMinimumRole(ROLES10.MEMBER, "edit knowledge documents")]
|
|
4792
5256
|
}
|
|
4793
5257
|
});
|
|
4794
5258
|
safeService("kb/versions")?.hooks({
|
|
@@ -4803,29 +5267,35 @@ function registerHooks(ctx) {
|
|
|
4803
5267
|
});
|
|
4804
5268
|
safeService("kb/settings")?.hooks({
|
|
4805
5269
|
before: {
|
|
4806
|
-
all: [requireAuth, requireMinimumRole(
|
|
5270
|
+
all: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "configure Knowledge semantic search")]
|
|
4807
5271
|
}
|
|
4808
5272
|
});
|
|
4809
5273
|
safeService("kb/indexing/status")?.hooks({
|
|
4810
5274
|
before: {
|
|
4811
|
-
all: [requireAuth, requireMinimumRole(
|
|
5275
|
+
all: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "view Knowledge indexing status")]
|
|
4812
5276
|
}
|
|
4813
5277
|
});
|
|
4814
5278
|
safeService("kb/indexing/reindex")?.hooks({
|
|
4815
5279
|
before: {
|
|
4816
|
-
all: [requireAuth, requireMinimumRole(
|
|
5280
|
+
all: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "reindex Knowledge embeddings")]
|
|
4817
5281
|
}
|
|
4818
5282
|
});
|
|
4819
5283
|
safeService("kb/graph")?.hooks?.({
|
|
4820
5284
|
before: {
|
|
4821
5285
|
all: [requireAuth],
|
|
4822
|
-
create: [requireMinimumRole(
|
|
4823
|
-
link: [requireMinimumRole(
|
|
5286
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "link knowledge graph nodes")],
|
|
5287
|
+
link: [requireMinimumRole(ROLES10.MEMBER, "link knowledge graph nodes")]
|
|
4824
5288
|
}
|
|
4825
5289
|
});
|
|
4826
5290
|
const injectPerUserOAuthTokens = async (context) => {
|
|
4827
5291
|
const queryForUserId = context.params?.query?.forUserId;
|
|
4828
|
-
const
|
|
5292
|
+
const authPayloadType = context.params?.authentication?.payload?.type;
|
|
5293
|
+
const userId = resolveForUserIdWithGate({
|
|
5294
|
+
queryForUserId,
|
|
5295
|
+
isServiceAccount: context.params?.user?._isServiceAccount,
|
|
5296
|
+
authPayloadType,
|
|
5297
|
+
callerUserId: context.params?.user?.user_id
|
|
5298
|
+
});
|
|
4829
5299
|
if (!userId) {
|
|
4830
5300
|
return context;
|
|
4831
5301
|
}
|
|
@@ -4908,9 +5378,9 @@ function registerHooks(ctx) {
|
|
|
4908
5378
|
safeService("mcp-servers")?.hooks({
|
|
4909
5379
|
before: {
|
|
4910
5380
|
all: [typedValidateQuery(mcpServerQueryValidator), requireAuth],
|
|
4911
|
-
create: [requireMinimumRole(
|
|
4912
|
-
patch: [requireMinimumRole(
|
|
4913
|
-
remove: [requireMinimumRole(
|
|
5381
|
+
create: [requireMinimumRole(ROLES10.ADMIN, "create MCP servers")],
|
|
5382
|
+
patch: [requireMinimumRole(ROLES10.ADMIN, "update MCP servers")],
|
|
5383
|
+
remove: [requireMinimumRole(ROLES10.ADMIN, "delete MCP servers")]
|
|
4914
5384
|
},
|
|
4915
5385
|
after: {
|
|
4916
5386
|
find: [injectPerUserOAuthTokens, redactMCPServerSecretFields],
|
|
@@ -4924,9 +5394,9 @@ function registerHooks(ctx) {
|
|
|
4924
5394
|
before: {
|
|
4925
5395
|
all: [requireAuth],
|
|
4926
5396
|
find: [
|
|
4927
|
-
requireMinimumRole(
|
|
5397
|
+
requireMinimumRole(ROLES10.MEMBER, "list session MCP servers"),
|
|
4928
5398
|
// RBAC: Scope to sessions the caller can access.
|
|
4929
|
-
...branchRbacEnabled ? [
|
|
5399
|
+
...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
|
|
4930
5400
|
]
|
|
4931
5401
|
},
|
|
4932
5402
|
after: {
|
|
@@ -4937,9 +5407,9 @@ function registerHooks(ctx) {
|
|
|
4937
5407
|
before: {
|
|
4938
5408
|
all: [requireAuth],
|
|
4939
5409
|
find: [
|
|
4940
|
-
requireMinimumRole(
|
|
4941
|
-
//
|
|
4942
|
-
|
|
5410
|
+
requireMinimumRole(ROLES10.MEMBER, "list session env selections")
|
|
5411
|
+
// This top-level service is event-only and always returns []; do not
|
|
5412
|
+
// run RBAC preloads for an intentionally empty result set.
|
|
4943
5413
|
]
|
|
4944
5414
|
}
|
|
4945
5415
|
});
|
|
@@ -4970,7 +5440,7 @@ function registerHooks(ctx) {
|
|
|
4970
5440
|
before: {
|
|
4971
5441
|
all: [requireAuth],
|
|
4972
5442
|
create: [
|
|
4973
|
-
requireMinimumRole(
|
|
5443
|
+
requireMinimumRole(ROLES10.ADMIN, "create gateway channels"),
|
|
4974
5444
|
injectCreatedBy(),
|
|
4975
5445
|
// Encrypt env var values at rest (same pattern as user env vars / API keys)
|
|
4976
5446
|
async (context) => {
|
|
@@ -4988,7 +5458,7 @@ function registerHooks(ctx) {
|
|
|
4988
5458
|
}
|
|
4989
5459
|
],
|
|
4990
5460
|
patch: [
|
|
4991
|
-
requireMinimumRole(
|
|
5461
|
+
requireMinimumRole(ROLES10.ADMIN, "update gateway channels"),
|
|
4992
5462
|
// Resolve redacted env var sentinel values ('••••••••') back to real
|
|
4993
5463
|
// values from the database. Uses the repository directly to bypass
|
|
4994
5464
|
// the after-hook redaction that the service layer applies.
|
|
@@ -5000,6 +5470,7 @@ function registerHooks(ctx) {
|
|
|
5000
5470
|
async (context) => {
|
|
5001
5471
|
const data = context.data;
|
|
5002
5472
|
if (!data || !context.id) return context;
|
|
5473
|
+
if (data.agentic_config === null) return context;
|
|
5003
5474
|
let ac = data.agentic_config;
|
|
5004
5475
|
const hadAgenticConfigInPatch = ac !== void 0;
|
|
5005
5476
|
const ensureAc = () => {
|
|
@@ -5009,12 +5480,12 @@ function registerHooks(ctx) {
|
|
|
5009
5480
|
}
|
|
5010
5481
|
return ac;
|
|
5011
5482
|
};
|
|
5012
|
-
const SENTINEL =
|
|
5483
|
+
const SENTINEL = GATEWAY_REDACTED_SENTINEL;
|
|
5013
5484
|
const incomingVars = ac?.envVars;
|
|
5014
5485
|
if (incomingVars === void 0) {
|
|
5015
5486
|
try {
|
|
5016
|
-
const { GatewayChannelRepository } = await import("@agor/core/db");
|
|
5017
|
-
const channelRepo = new
|
|
5487
|
+
const { GatewayChannelRepository: GatewayChannelRepository2 } = await import("@agor/core/db");
|
|
5488
|
+
const channelRepo = new GatewayChannelRepository2(db);
|
|
5018
5489
|
const existing = await channelRepo.findById(String(context.id));
|
|
5019
5490
|
if (!hadAgenticConfigInPatch && existing?.agentic_config) {
|
|
5020
5491
|
ac = { ...existing.agentic_config };
|
|
@@ -5034,8 +5505,8 @@ function registerHooks(ctx) {
|
|
|
5034
5505
|
return context;
|
|
5035
5506
|
}
|
|
5036
5507
|
try {
|
|
5037
|
-
const { GatewayChannelRepository } = await import("@agor/core/db");
|
|
5038
|
-
const channelRepo = new
|
|
5508
|
+
const { GatewayChannelRepository: GatewayChannelRepository2 } = await import("@agor/core/db");
|
|
5509
|
+
const channelRepo = new GatewayChannelRepository2(db);
|
|
5039
5510
|
const existing = await channelRepo.findById(String(context.id));
|
|
5040
5511
|
const existingVars = existing?.agentic_config?.envVars ?? [];
|
|
5041
5512
|
const existingByKey = new Map(existingVars.map((v) => [v.key, v.value]));
|
|
@@ -5046,14 +5517,14 @@ function registerHooks(ctx) {
|
|
|
5046
5517
|
return v;
|
|
5047
5518
|
});
|
|
5048
5519
|
} catch (error) {
|
|
5049
|
-
throw new
|
|
5520
|
+
throw new BadRequest5(
|
|
5050
5521
|
`Failed to resolve redacted gateway env vars: ${error instanceof Error ? error.message : String(error)}`
|
|
5051
5522
|
);
|
|
5052
5523
|
}
|
|
5053
5524
|
return context;
|
|
5054
5525
|
}
|
|
5055
5526
|
],
|
|
5056
|
-
remove: [requireMinimumRole(
|
|
5527
|
+
remove: [requireMinimumRole(ROLES10.ADMIN, "delete gateway channels")]
|
|
5057
5528
|
},
|
|
5058
5529
|
after: {
|
|
5059
5530
|
all: [
|
|
@@ -5062,15 +5533,9 @@ function registerHooks(ctx) {
|
|
|
5062
5533
|
const redact = (channel) => {
|
|
5063
5534
|
if (channel?.config && typeof channel.config === "object") {
|
|
5064
5535
|
const config2 = { ...channel.config };
|
|
5065
|
-
for (const field of
|
|
5066
|
-
"bot_token",
|
|
5067
|
-
"app_token",
|
|
5068
|
-
"signing_secret",
|
|
5069
|
-
"private_key",
|
|
5070
|
-
"webhook_secret"
|
|
5071
|
-
]) {
|
|
5536
|
+
for (const field of GATEWAY_SENSITIVE_CONFIG_FIELDS) {
|
|
5072
5537
|
if (config2[field]) {
|
|
5073
|
-
config2[field] =
|
|
5538
|
+
config2[field] = GATEWAY_REDACTED_SENTINEL;
|
|
5074
5539
|
}
|
|
5075
5540
|
}
|
|
5076
5541
|
channel.config = config2;
|
|
@@ -5078,7 +5543,11 @@ function registerHooks(ctx) {
|
|
|
5078
5543
|
if (channel?.agentic_config && typeof channel.agentic_config === "object") {
|
|
5079
5544
|
const ac = channel.agentic_config;
|
|
5080
5545
|
if (Array.isArray(ac.envVars)) {
|
|
5081
|
-
ac.envVars = ac.envVars.map((v) => ({
|
|
5546
|
+
ac.envVars = ac.envVars.map((v) => ({
|
|
5547
|
+
key: v.key,
|
|
5548
|
+
value: GATEWAY_REDACTED_SENTINEL,
|
|
5549
|
+
forceOverride: v.forceOverride
|
|
5550
|
+
}));
|
|
5082
5551
|
}
|
|
5083
5552
|
}
|
|
5084
5553
|
};
|
|
@@ -5100,12 +5569,17 @@ function registerHooks(ctx) {
|
|
|
5100
5569
|
all: [requireAuth]
|
|
5101
5570
|
}
|
|
5102
5571
|
});
|
|
5572
|
+
safeService("admin/local-actions")?.hooks({
|
|
5573
|
+
before: {
|
|
5574
|
+
create: [requireAuth, requireMinimumRole(ROLES10.ADMIN, "run local admin actions")]
|
|
5575
|
+
}
|
|
5576
|
+
});
|
|
5103
5577
|
app.service("config").hooks({
|
|
5104
5578
|
before: {
|
|
5105
5579
|
all: [requireAuth],
|
|
5106
|
-
find: [requireMinimumRole(
|
|
5107
|
-
get: [requireMinimumRole(
|
|
5108
|
-
patch: [requireMinimumRole(
|
|
5580
|
+
find: [requireMinimumRole(ROLES10.ADMIN, "view configuration")],
|
|
5581
|
+
get: [requireMinimumRole(ROLES10.ADMIN, "view configuration")],
|
|
5582
|
+
patch: [requireMinimumRole(ROLES10.ADMIN, "update configuration")]
|
|
5109
5583
|
}
|
|
5110
5584
|
});
|
|
5111
5585
|
safeService("context")?.hooks({
|
|
@@ -5117,7 +5591,7 @@ function registerHooks(ctx) {
|
|
|
5117
5591
|
before: {
|
|
5118
5592
|
all: [
|
|
5119
5593
|
requireAuth,
|
|
5120
|
-
requireMinimumRole(
|
|
5594
|
+
requireMinimumRole(ROLES10.MEMBER, "search files"),
|
|
5121
5595
|
// RBAC: files service takes a sessionId query param and returns files
|
|
5122
5596
|
// from that session's branch. Verify the caller can at least 'view'
|
|
5123
5597
|
// that branch before running git ls-files. If sessionId is missing
|
|
@@ -5144,7 +5618,7 @@ function registerHooks(ctx) {
|
|
|
5144
5618
|
before: {
|
|
5145
5619
|
all: [
|
|
5146
5620
|
requireAuth,
|
|
5147
|
-
requireMinimumRole(
|
|
5621
|
+
requireMinimumRole(ROLES10.MEMBER, "read files"),
|
|
5148
5622
|
...branchRbacEnabled ? [loadBranch(branchRepository, "branch_id"), ensureCanView(superadminOpts)] : []
|
|
5149
5623
|
]
|
|
5150
5624
|
}
|
|
@@ -5156,13 +5630,13 @@ function registerHooks(ctx) {
|
|
|
5156
5630
|
requireAuth,
|
|
5157
5631
|
(context) => {
|
|
5158
5632
|
if (!webTerminalEnabled) {
|
|
5159
|
-
throw new
|
|
5633
|
+
throw new Forbidden9(
|
|
5160
5634
|
"Web terminal is disabled on this instance. Ask an administrator to unset or enable execution.allow_web_terminal in the daemon config."
|
|
5161
5635
|
);
|
|
5162
5636
|
}
|
|
5163
5637
|
return context;
|
|
5164
5638
|
},
|
|
5165
|
-
requireMinimumRole(
|
|
5639
|
+
requireMinimumRole(ROLES10.MEMBER, "access terminals")
|
|
5166
5640
|
]
|
|
5167
5641
|
}
|
|
5168
5642
|
});
|
|
@@ -5178,11 +5652,11 @@ function registerHooks(ctx) {
|
|
|
5178
5652
|
after: {
|
|
5179
5653
|
create: [
|
|
5180
5654
|
clearRealtimeBranchVisibility,
|
|
5181
|
-
(context) =>
|
|
5655
|
+
(context) => syncUnixAccessForGroupGrantedBranches(context, "[Executor/group-memberships.create]")
|
|
5182
5656
|
],
|
|
5183
5657
|
remove: [
|
|
5184
5658
|
clearRealtimeBranchVisibility,
|
|
5185
|
-
(context) =>
|
|
5659
|
+
(context) => syncUnixAccessForGroupGrantedBranches(context, "[Executor/group-memberships.remove]")
|
|
5186
5660
|
]
|
|
5187
5661
|
}
|
|
5188
5662
|
});
|
|
@@ -5199,7 +5673,11 @@ function registerHooks(ctx) {
|
|
|
5199
5673
|
(context) => {
|
|
5200
5674
|
const branchId = context.params.route?.id;
|
|
5201
5675
|
if (typeof branchId === "string") {
|
|
5202
|
-
syncBranchUnixAccess(
|
|
5676
|
+
syncBranchUnixAccess(
|
|
5677
|
+
branchId,
|
|
5678
|
+
"[Executor/branch-group-grants.create]",
|
|
5679
|
+
context.params
|
|
5680
|
+
);
|
|
5203
5681
|
}
|
|
5204
5682
|
return context;
|
|
5205
5683
|
}
|
|
@@ -5209,7 +5687,11 @@ function registerHooks(ctx) {
|
|
|
5209
5687
|
(context) => {
|
|
5210
5688
|
const branchId = context.params.route?.id;
|
|
5211
5689
|
if (typeof branchId === "string") {
|
|
5212
|
-
syncBranchUnixAccess(
|
|
5690
|
+
syncBranchUnixAccess(
|
|
5691
|
+
branchId,
|
|
5692
|
+
"[Executor/branch-group-grants.patch]",
|
|
5693
|
+
context.params
|
|
5694
|
+
);
|
|
5213
5695
|
}
|
|
5214
5696
|
return context;
|
|
5215
5697
|
}
|
|
@@ -5219,7 +5701,11 @@ function registerHooks(ctx) {
|
|
|
5219
5701
|
(context) => {
|
|
5220
5702
|
const branchId = context.params.route?.id;
|
|
5221
5703
|
if (typeof branchId === "string") {
|
|
5222
|
-
syncBranchUnixAccess(
|
|
5704
|
+
syncBranchUnixAccess(
|
|
5705
|
+
branchId,
|
|
5706
|
+
"[Executor/branch-group-grants.remove]",
|
|
5707
|
+
context.params
|
|
5708
|
+
);
|
|
5223
5709
|
}
|
|
5224
5710
|
return context;
|
|
5225
5711
|
}
|
|
@@ -5264,7 +5750,7 @@ function registerHooks(ctx) {
|
|
|
5264
5750
|
return context;
|
|
5265
5751
|
}
|
|
5266
5752
|
if (params.user) {
|
|
5267
|
-
ensureMinimumRole(params,
|
|
5753
|
+
ensureMinimumRole(params, ROLES10.MEMBER, "list users");
|
|
5268
5754
|
return context;
|
|
5269
5755
|
}
|
|
5270
5756
|
const query = params.query || {};
|
|
@@ -5272,12 +5758,12 @@ function registerHooks(ctx) {
|
|
|
5272
5758
|
params.query = { ...query, $limit: 1 };
|
|
5273
5759
|
return context;
|
|
5274
5760
|
}
|
|
5275
|
-
throw new
|
|
5761
|
+
throw new NotAuthenticated8("Authentication required");
|
|
5276
5762
|
}
|
|
5277
5763
|
],
|
|
5278
5764
|
get: [
|
|
5279
5765
|
(context) => {
|
|
5280
|
-
ensureMinimumRole(context.params,
|
|
5766
|
+
ensureMinimumRole(context.params, ROLES10.MEMBER, "view users");
|
|
5281
5767
|
return context;
|
|
5282
5768
|
}
|
|
5283
5769
|
],
|
|
@@ -5289,13 +5775,13 @@ function registerHooks(ctx) {
|
|
|
5289
5775
|
}
|
|
5290
5776
|
const existing = await usersService.find({ query: { $limit: 1 } });
|
|
5291
5777
|
if (existing.total > 0) {
|
|
5292
|
-
ensureMinimumRole(params,
|
|
5778
|
+
ensureMinimumRole(params, ROLES10.ADMIN, "create users");
|
|
5293
5779
|
}
|
|
5294
5780
|
const data = context.data;
|
|
5295
|
-
if (
|
|
5781
|
+
if (hasMinimumRole9(data?.role, ROLES10.SUPERADMIN)) {
|
|
5296
5782
|
const callerRole = params.user?.role;
|
|
5297
|
-
if (!
|
|
5298
|
-
throw new
|
|
5783
|
+
if (!hasMinimumRole9(callerRole, ROLES10.SUPERADMIN)) {
|
|
5784
|
+
throw new Forbidden9("Only superadmins can create superadmin users");
|
|
5299
5785
|
}
|
|
5300
5786
|
}
|
|
5301
5787
|
return context;
|
|
@@ -5306,28 +5792,28 @@ function registerHooks(ctx) {
|
|
|
5306
5792
|
const params = context.params;
|
|
5307
5793
|
const userId = context.id;
|
|
5308
5794
|
const callerRole = params.user?.role;
|
|
5309
|
-
const callerIsAdmin =
|
|
5795
|
+
const callerIsAdmin = hasMinimumRole9(callerRole, ROLES10.ADMIN);
|
|
5310
5796
|
if (!Array.isArray(context.data)) {
|
|
5311
5797
|
if (context.data?.unix_username !== void 0) {
|
|
5312
5798
|
if (!callerIsAdmin) {
|
|
5313
|
-
throw new
|
|
5799
|
+
throw new Forbidden9("Only admins can modify unix_username");
|
|
5314
5800
|
}
|
|
5315
5801
|
}
|
|
5316
5802
|
if (context.data?.role !== void 0) {
|
|
5317
5803
|
if (!callerIsAdmin) {
|
|
5318
|
-
throw new
|
|
5804
|
+
throw new Forbidden9("Only admins can modify user roles");
|
|
5319
5805
|
}
|
|
5320
|
-
if (
|
|
5806
|
+
if (hasMinimumRole9(context.data.role, ROLES10.SUPERADMIN) && !hasMinimumRole9(callerRole, ROLES10.SUPERADMIN)) {
|
|
5321
5807
|
const allUsers = await usersService.find({});
|
|
5322
|
-
const hasSuperadmin = allUsers.data.some((u) => u.role ===
|
|
5808
|
+
const hasSuperadmin = allUsers.data.some((u) => u.role === ROLES10.SUPERADMIN);
|
|
5323
5809
|
if (hasSuperadmin) {
|
|
5324
|
-
throw new
|
|
5810
|
+
throw new Forbidden9("Only superadmins can assign the superadmin role");
|
|
5325
5811
|
}
|
|
5326
5812
|
}
|
|
5327
5813
|
}
|
|
5328
5814
|
if (context.data?.must_change_password !== void 0) {
|
|
5329
5815
|
if (!callerIsAdmin) {
|
|
5330
|
-
throw new
|
|
5816
|
+
throw new Forbidden9("Only admins can force password changes");
|
|
5331
5817
|
}
|
|
5332
5818
|
}
|
|
5333
5819
|
}
|
|
@@ -5340,22 +5826,22 @@ function registerHooks(ctx) {
|
|
|
5340
5826
|
if (!context.params.provider && params.trustedEnvVarWrite === true) {
|
|
5341
5827
|
const keys = Object.keys(context.data ?? {});
|
|
5342
5828
|
if (!keys.every((k) => k === "env_vars" || k === "env_var_scopes")) {
|
|
5343
|
-
throw new
|
|
5829
|
+
throw new Forbidden9(
|
|
5344
5830
|
"trustedEnvVarWrite only permits env_vars and env_var_scopes updates"
|
|
5345
5831
|
);
|
|
5346
5832
|
}
|
|
5347
5833
|
return context;
|
|
5348
5834
|
}
|
|
5349
|
-
throw new
|
|
5835
|
+
throw new Forbidden9("You can only update your own profile");
|
|
5350
5836
|
}
|
|
5351
5837
|
],
|
|
5352
|
-
remove: [requireMinimumRole(
|
|
5838
|
+
remove: [requireMinimumRole(ROLES10.ADMIN, "delete users")]
|
|
5353
5839
|
},
|
|
5354
5840
|
after: {
|
|
5355
5841
|
// After user create/patch: optionally ensure Unix user exists and sync password
|
|
5356
5842
|
create: [
|
|
5357
5843
|
async (context) => {
|
|
5358
|
-
if (!jwtSecret) {
|
|
5844
|
+
if (!executionMode.unixImpersonationEnabled || !jwtSecret) {
|
|
5359
5845
|
return context;
|
|
5360
5846
|
}
|
|
5361
5847
|
const user = context.result;
|
|
@@ -5368,10 +5854,14 @@ function registerHooks(ctx) {
|
|
|
5368
5854
|
return context;
|
|
5369
5855
|
}
|
|
5370
5856
|
console.log(`[Unix Integration] Syncing Unix user for: ${user.unix_username}`);
|
|
5371
|
-
const serviceToken =
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5857
|
+
const serviceToken = createExecutorServiceToken(
|
|
5858
|
+
context.params,
|
|
5859
|
+
{
|
|
5860
|
+
user_id: user.user_id,
|
|
5861
|
+
command: "unix.sync-user"
|
|
5862
|
+
}
|
|
5863
|
+
);
|
|
5864
|
+
if (!serviceToken) return context;
|
|
5375
5865
|
spawnExecutorFireAndForget(
|
|
5376
5866
|
{
|
|
5377
5867
|
command: "unix.sync-user",
|
|
@@ -5388,11 +5878,27 @@ function registerHooks(ctx) {
|
|
|
5388
5878
|
{ logPrefix: "[Executor/user.create]" }
|
|
5389
5879
|
);
|
|
5390
5880
|
return context;
|
|
5881
|
+
},
|
|
5882
|
+
async (context) => {
|
|
5883
|
+
if (context.params.skipAvatarRefresh) {
|
|
5884
|
+
return context;
|
|
5885
|
+
}
|
|
5886
|
+
const user = context.result;
|
|
5887
|
+
const avatarService = safeService("users");
|
|
5888
|
+
if (avatarService?.refreshAvatarFromSettings) {
|
|
5889
|
+
avatarService.refreshAvatarFromSettings(user.user_id).catch((error) => {
|
|
5890
|
+
console.warn(
|
|
5891
|
+
`[users/avatar-sync] Failed to refresh avatar for new user ${shortId5(user.user_id)}:`,
|
|
5892
|
+
error instanceof Error ? error.message : String(error)
|
|
5893
|
+
);
|
|
5894
|
+
});
|
|
5895
|
+
}
|
|
5896
|
+
return context;
|
|
5391
5897
|
}
|
|
5392
5898
|
],
|
|
5393
5899
|
patch: [
|
|
5394
5900
|
async (context) => {
|
|
5395
|
-
if (!jwtSecret) {
|
|
5901
|
+
if (!executionMode.unixImpersonationEnabled || !jwtSecret) {
|
|
5396
5902
|
return context;
|
|
5397
5903
|
}
|
|
5398
5904
|
const data = context.data;
|
|
@@ -5408,10 +5914,14 @@ function registerHooks(ctx) {
|
|
|
5408
5914
|
return context;
|
|
5409
5915
|
}
|
|
5410
5916
|
console.log(`[Unix Integration] Syncing Unix user for: ${user.unix_username}`);
|
|
5411
|
-
const serviceToken =
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5917
|
+
const serviceToken = createExecutorServiceToken(
|
|
5918
|
+
context.params,
|
|
5919
|
+
{
|
|
5920
|
+
user_id: user.user_id,
|
|
5921
|
+
command: "unix.sync-user"
|
|
5922
|
+
}
|
|
5923
|
+
);
|
|
5924
|
+
if (!serviceToken) return context;
|
|
5415
5925
|
spawnExecutorFireAndForget(
|
|
5416
5926
|
{
|
|
5417
5927
|
command: "unix.sync-user",
|
|
@@ -5428,6 +5938,26 @@ function registerHooks(ctx) {
|
|
|
5428
5938
|
{ logPrefix: "[Executor/user.patch]" }
|
|
5429
5939
|
);
|
|
5430
5940
|
return context;
|
|
5941
|
+
},
|
|
5942
|
+
async (context) => {
|
|
5943
|
+
if (context.params.skipAvatarRefresh) {
|
|
5944
|
+
return context;
|
|
5945
|
+
}
|
|
5946
|
+
const data = context.data;
|
|
5947
|
+
if (data?.email === void 0 && data?.preferences === void 0) {
|
|
5948
|
+
return context;
|
|
5949
|
+
}
|
|
5950
|
+
const user = context.result;
|
|
5951
|
+
const avatarService = safeService("users");
|
|
5952
|
+
if (avatarService?.refreshAvatarFromSettings) {
|
|
5953
|
+
avatarService.refreshAvatarFromSettings(user.user_id).catch((error) => {
|
|
5954
|
+
console.warn(
|
|
5955
|
+
`[users/avatar-sync] Failed to refresh avatar for updated user ${shortId5(user.user_id)}:`,
|
|
5956
|
+
error instanceof Error ? error.message : String(error)
|
|
5957
|
+
);
|
|
5958
|
+
});
|
|
5959
|
+
}
|
|
5960
|
+
return context;
|
|
5431
5961
|
}
|
|
5432
5962
|
]
|
|
5433
5963
|
}
|
|
@@ -5438,14 +5968,16 @@ function registerHooks(ctx) {
|
|
|
5438
5968
|
branchRepository,
|
|
5439
5969
|
sessionsRepository,
|
|
5440
5970
|
accessCache: realtimeAccessCache,
|
|
5441
|
-
allowSuperadmin: superadminOpts.allowSuperadmin
|
|
5971
|
+
allowSuperadmin: superadminOpts.allowSuperadmin,
|
|
5972
|
+
multiTenancy
|
|
5442
5973
|
});
|
|
5443
5974
|
app.service("sessions").hooks({
|
|
5444
5975
|
before: {
|
|
5445
5976
|
all: [typedValidateQuery(sessionQueryValidator), requireAuth, executorRuntimeScopeGuard()],
|
|
5446
5977
|
find: [
|
|
5447
|
-
// RBAC:
|
|
5448
|
-
|
|
5978
|
+
// RBAC: mark external regular-user finds for SessionsService to compose
|
|
5979
|
+
// the shared branch visibility predicate directly into its SQL read.
|
|
5980
|
+
...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
|
|
5449
5981
|
],
|
|
5450
5982
|
get: [
|
|
5451
5983
|
...branchRbacEnabled ? [
|
|
@@ -5456,7 +5988,7 @@ function registerHooks(ctx) {
|
|
|
5456
5988
|
] : []
|
|
5457
5989
|
],
|
|
5458
5990
|
create: [
|
|
5459
|
-
requireMinimumRole(
|
|
5991
|
+
requireMinimumRole(ROLES10.MEMBER, "create sessions"),
|
|
5460
5992
|
...branchRbacEnabled ? [
|
|
5461
5993
|
setSessionUnixUsername(usersRepository),
|
|
5462
5994
|
// Stamp session with creator's unix_username (MUST run first)
|
|
@@ -5467,7 +5999,7 @@ function registerHooks(ctx) {
|
|
|
5467
5999
|
try {
|
|
5468
6000
|
const branch = await branchRepository.findById(data.branch_id);
|
|
5469
6001
|
if (!branch) {
|
|
5470
|
-
throw new
|
|
6002
|
+
throw new Forbidden9(`Branch not found: ${data.branch_id}`);
|
|
5471
6003
|
}
|
|
5472
6004
|
await cacheBranchAccess(context.params, branchRepository, branch);
|
|
5473
6005
|
} catch (error) {
|
|
@@ -5513,7 +6045,10 @@ function registerHooks(ctx) {
|
|
|
5513
6045
|
db,
|
|
5514
6046
|
context.params.user?.user_id
|
|
5515
6047
|
),
|
|
5516
|
-
logPrefix: `[sessions.create ${branch.name}]
|
|
6048
|
+
logPrefix: `[sessions.create ${branch.name}]`,
|
|
6049
|
+
serviceTokenScope: serviceTokenScopeForParams(
|
|
6050
|
+
context.params
|
|
6051
|
+
)
|
|
5517
6052
|
}
|
|
5518
6053
|
);
|
|
5519
6054
|
context.data.git_state = {
|
|
@@ -5535,7 +6070,7 @@ function registerHooks(ctx) {
|
|
|
5535
6070
|
}
|
|
5536
6071
|
}
|
|
5537
6072
|
const cbConfig = context.data?.callback_config;
|
|
5538
|
-
if (cbConfig?.callback_session_id) {
|
|
6073
|
+
if (cbConfig?.callback_session_id && context.params.provider) {
|
|
5539
6074
|
const authenticatedUserId = context.params.user?.user_id || "unknown";
|
|
5540
6075
|
await ensureCanPromptTargetSession(
|
|
5541
6076
|
cbConfig.callback_session_id,
|
|
@@ -5574,10 +6109,13 @@ function registerHooks(ctx) {
|
|
|
5574
6109
|
)(context);
|
|
5575
6110
|
}
|
|
5576
6111
|
] : [],
|
|
5577
|
-
// Validate user has prompt permission on callback target session's branch
|
|
6112
|
+
// Validate user has prompt permission on callback target session's branch.
|
|
6113
|
+
// Skip for internal calls (no provider) — patches from dispatchCompletionCallbacks
|
|
6114
|
+
// spread the existing callback_config (which includes callback_session_id) and must
|
|
6115
|
+
// not be blocked by this check.
|
|
5578
6116
|
async (context) => {
|
|
5579
6117
|
const patchCbConfig = context.data?.callback_config;
|
|
5580
|
-
if (patchCbConfig?.callback_session_id) {
|
|
6118
|
+
if (patchCbConfig?.callback_session_id && context.params.provider) {
|
|
5581
6119
|
const userId = context.params.user?.user_id || "unknown";
|
|
5582
6120
|
await ensureCanPromptTargetSession(
|
|
5583
6121
|
patchCbConfig.callback_session_id,
|
|
@@ -5618,13 +6156,15 @@ function registerHooks(ctx) {
|
|
|
5618
6156
|
const callerUser = context.params.user;
|
|
5619
6157
|
if (!canReceiveMcpTokenForSession({
|
|
5620
6158
|
callerUserId: callerUser?.user_id,
|
|
5621
|
-
callerRole: callerUser?.role
|
|
5622
|
-
sessionCreatedBy: session.created_by
|
|
6159
|
+
callerRole: callerUser?.role
|
|
5623
6160
|
})) {
|
|
5624
6161
|
return context;
|
|
5625
6162
|
}
|
|
5626
6163
|
const { generateSessionToken: generateSessionToken3 } = await Promise.resolve().then(() => (init_tokens(), tokens_exports));
|
|
5627
|
-
const userId =
|
|
6164
|
+
const userId = callerUser?.user_id;
|
|
6165
|
+
if (!userId) {
|
|
6166
|
+
return context;
|
|
6167
|
+
}
|
|
5628
6168
|
const jwtSecret2 = app.settings.authentication?.secret;
|
|
5629
6169
|
if (!jwtSecret2) {
|
|
5630
6170
|
console.error("\u274C JWT secret not configured - cannot generate MCP token");
|
|
@@ -5675,13 +6215,19 @@ function registerHooks(ctx) {
|
|
|
5675
6215
|
if (config.daemon?.mcpEnabled === false) {
|
|
5676
6216
|
return context;
|
|
5677
6217
|
}
|
|
5678
|
-
const
|
|
5679
|
-
if (!
|
|
6218
|
+
const callerUser = context.params.user;
|
|
6219
|
+
if (!canReceiveMcpTokenForSession({
|
|
6220
|
+
callerUserId: callerUser?.user_id,
|
|
6221
|
+
callerRole: callerUser?.role
|
|
6222
|
+
})) {
|
|
5680
6223
|
return context;
|
|
5681
6224
|
}
|
|
5682
6225
|
const { generateSessionToken: generateSessionToken3 } = await Promise.resolve().then(() => (init_tokens(), tokens_exports));
|
|
5683
6226
|
const session = context.result;
|
|
5684
|
-
const userId =
|
|
6227
|
+
const userId = callerUser?.user_id;
|
|
6228
|
+
if (!userId) {
|
|
6229
|
+
return context;
|
|
6230
|
+
}
|
|
5685
6231
|
const jwtSecret2 = app.settings.authentication?.secret;
|
|
5686
6232
|
if (!jwtSecret2) {
|
|
5687
6233
|
console.error("\u274C JWT secret not configured - cannot generate MCP token");
|
|
@@ -5702,7 +6248,7 @@ function registerHooks(ctx) {
|
|
|
5702
6248
|
// unix groups. Without this, non-owners can't access the .git/ directory
|
|
5703
6249
|
// (which uses 2770 = no others access) even if the branch directory itself
|
|
5704
6250
|
// allows "others" access via ACLs.
|
|
5705
|
-
...
|
|
6251
|
+
...executionMode.unixFsIsolationEnabled ? [
|
|
5706
6252
|
async (context) => {
|
|
5707
6253
|
const session = context.result;
|
|
5708
6254
|
if (!session.branch_id || !session.unix_username) {
|
|
@@ -5717,28 +6263,15 @@ function registerHooks(ctx) {
|
|
|
5717
6263
|
if (!branch?.others_fs_access || branch.others_fs_access === "none") {
|
|
5718
6264
|
return context;
|
|
5719
6265
|
}
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
spawnExecutorFireAndForget(
|
|
5730
|
-
{
|
|
5731
|
-
command: "unix.sync-branch",
|
|
5732
|
-
sessionToken: serviceToken,
|
|
5733
|
-
daemonUrl: getDaemonUrl(),
|
|
5734
|
-
params: {
|
|
5735
|
-
branchId: session.branch_id,
|
|
5736
|
-
daemonUser: config.daemon?.unix_user
|
|
5737
|
-
}
|
|
5738
|
-
},
|
|
5739
|
-
{ logPrefix: "[Executor/session.create.unix-group]" }
|
|
5740
|
-
);
|
|
5741
|
-
}
|
|
6266
|
+
console.log(
|
|
6267
|
+
`[Unix Integration] Non-owner session created in branch ${shortId5(session.branch_id)} by ${session.unix_username} (others_fs_access: ${branch.others_fs_access}), syncing group membership`
|
|
6268
|
+
);
|
|
6269
|
+
syncBranchUnixAccess(
|
|
6270
|
+
branch.branch_id,
|
|
6271
|
+
"[Executor/session.create.unix-group]",
|
|
6272
|
+
context.params,
|
|
6273
|
+
{ scope: { session_id: session.session_id } }
|
|
6274
|
+
);
|
|
5742
6275
|
} catch (error) {
|
|
5743
6276
|
console.error(
|
|
5744
6277
|
`[Unix Integration] Failed to trigger group sync for session ${shortId5(session.session_id)}:`,
|
|
@@ -5753,7 +6286,7 @@ function registerHooks(ctx) {
|
|
|
5753
6286
|
async (context) => {
|
|
5754
6287
|
const session = Array.isArray(context.result) ? context.result[0] : context.result;
|
|
5755
6288
|
if (session && shouldRunSessionPostTurnHooks(session)) {
|
|
5756
|
-
|
|
6289
|
+
deferWithTenantDatabaseScope(db, context.params, async () => {
|
|
5757
6290
|
try {
|
|
5758
6291
|
const gatewayService = context.app.service("gateway");
|
|
5759
6292
|
await gatewayService.flushGitHubBuffer(session.session_id);
|
|
@@ -5769,19 +6302,33 @@ function registerHooks(ctx) {
|
|
|
5769
6302
|
}
|
|
5770
6303
|
});
|
|
5771
6304
|
if (shouldDrainQueueAfterSessionPostTurnPatch(session, context.params)) {
|
|
5772
|
-
|
|
5773
|
-
|
|
6305
|
+
const sessionTenantId = getTrustedSessionTenantId(session);
|
|
6306
|
+
deferWithSessionQueueTenantScope(
|
|
6307
|
+
{
|
|
6308
|
+
db,
|
|
6309
|
+
config,
|
|
6310
|
+
sessionId: session.session_id,
|
|
6311
|
+
params: context.params,
|
|
6312
|
+
tenantIdHint: sessionTenantId,
|
|
6313
|
+
label: "SessionsService.after.patch queue drain"
|
|
6314
|
+
},
|
|
6315
|
+
async (queueParams) => {
|
|
5774
6316
|
console.log(
|
|
5775
6317
|
`\u{1F504} [SessionsService.after.patch] Session ${shortId5(session.session_id)} became promptable (${session.status}), checking for queued tasks...`
|
|
5776
6318
|
);
|
|
5777
|
-
await sessionsService.triggerQueueProcessing(session.session_id,
|
|
5778
|
-
}
|
|
6319
|
+
await sessionsService.triggerQueueProcessing(session.session_id, queueParams);
|
|
6320
|
+
},
|
|
6321
|
+
(error) => {
|
|
5779
6322
|
console.error(
|
|
5780
6323
|
`\u274C [SessionsService.after.patch] Failed to process queue for session ${shortId5(session.session_id)}:`,
|
|
5781
6324
|
error
|
|
5782
6325
|
);
|
|
5783
6326
|
}
|
|
5784
|
-
|
|
6327
|
+
);
|
|
6328
|
+
} else {
|
|
6329
|
+
console.log(
|
|
6330
|
+
`\u23ED\uFE0F [SessionsService.after.patch] Queue drain suppressed for session ${shortId5(session.session_id)} (suppressTerminalQueueProcessing or not ready)`
|
|
6331
|
+
);
|
|
5785
6332
|
}
|
|
5786
6333
|
}
|
|
5787
6334
|
return context;
|
|
@@ -5810,14 +6357,14 @@ function registerHooks(ctx) {
|
|
|
5810
6357
|
] : []
|
|
5811
6358
|
],
|
|
5812
6359
|
create: [
|
|
5813
|
-
requireMinimumRole(
|
|
6360
|
+
requireMinimumRole(ROLES10.MEMBER, "create schedules"),
|
|
5814
6361
|
...branchRbacEnabled ? [loadBranch(branchRepository, "branch_id"), ensureCanCreateSession(superadminOpts)] : [],
|
|
5815
6362
|
injectCreatedBy(),
|
|
5816
6363
|
validateScheduleConfig(),
|
|
5817
6364
|
recomputeNextRunAt()
|
|
5818
6365
|
],
|
|
5819
6366
|
patch: [
|
|
5820
|
-
requireMinimumRole(
|
|
6367
|
+
requireMinimumRole(ROLES10.MEMBER, "update schedules"),
|
|
5821
6368
|
...branchRbacEnabled ? [
|
|
5822
6369
|
loadScheduleAndBranch(scheduleRepository, branchRepository),
|
|
5823
6370
|
ensureCanModifySchedule(superadminOpts)
|
|
@@ -5832,7 +6379,7 @@ function registerHooks(ctx) {
|
|
|
5832
6379
|
recomputeNextRunAt()
|
|
5833
6380
|
],
|
|
5834
6381
|
remove: [
|
|
5835
|
-
requireMinimumRole(
|
|
6382
|
+
requireMinimumRole(ROLES10.MEMBER, "delete schedules"),
|
|
5836
6383
|
...branchRbacEnabled ? [
|
|
5837
6384
|
loadScheduleAndBranch(scheduleRepository, branchRepository),
|
|
5838
6385
|
ensureBranchPermission("all", "delete schedule", superadminOpts)
|
|
@@ -5845,7 +6392,7 @@ function registerHooks(ctx) {
|
|
|
5845
6392
|
all: [typedValidateQuery(taskQueryValidator), requireAuth, executorRuntimeScopeGuard()],
|
|
5846
6393
|
find: [
|
|
5847
6394
|
// RBAC: Scope tasks.find() to sessions the caller can access.
|
|
5848
|
-
...branchRbacEnabled ? [
|
|
6395
|
+
...branchRbacEnabled ? [scopeFindToAccessibleSessionsSql(superadminOpts)] : []
|
|
5849
6396
|
],
|
|
5850
6397
|
get: [
|
|
5851
6398
|
...branchRbacEnabled ? [
|
|
@@ -5857,7 +6404,7 @@ function registerHooks(ctx) {
|
|
|
5857
6404
|
] : []
|
|
5858
6405
|
],
|
|
5859
6406
|
create: [
|
|
5860
|
-
requireMinimumRole(
|
|
6407
|
+
requireMinimumRole(ROLES10.MEMBER, "create tasks"),
|
|
5861
6408
|
...branchRbacEnabled ? [
|
|
5862
6409
|
resolveSessionContext(),
|
|
5863
6410
|
loadSession(sessionsService),
|
|
@@ -5879,7 +6426,7 @@ function registerHooks(ctx) {
|
|
|
5879
6426
|
] : []
|
|
5880
6427
|
],
|
|
5881
6428
|
remove: [
|
|
5882
|
-
requireMinimumRole(
|
|
6429
|
+
requireMinimumRole(ROLES10.MEMBER, "delete tasks"),
|
|
5883
6430
|
// RBAC: deleting a task requires 'all' permission on the branch
|
|
5884
6431
|
// (mirrors sessions.remove). Without this, any member with 'session'
|
|
5885
6432
|
// access could delete tasks owned by other users on shared branches.
|
|
@@ -5897,21 +6444,21 @@ function registerHooks(ctx) {
|
|
|
5897
6444
|
return async (context) => {
|
|
5898
6445
|
if (!branchRbacEnabled || !context.params.provider) return context;
|
|
5899
6446
|
const user = context.params.user;
|
|
5900
|
-
if (!user) throw new
|
|
6447
|
+
if (!user) throw new NotAuthenticated8("Authentication required");
|
|
5901
6448
|
if (user._isServiceAccount) return context;
|
|
5902
6449
|
const allowSuperadmin = superadminOpts?.allowSuperadmin ?? true;
|
|
5903
|
-
if (user.role ===
|
|
6450
|
+
if (user.role === ROLES10.ADMIN || allowSuperadmin && user.role === ROLES10.SUPERADMIN) {
|
|
5904
6451
|
return context;
|
|
5905
6452
|
}
|
|
5906
6453
|
const args = context.arguments;
|
|
5907
6454
|
const firstArg = args?.[0];
|
|
5908
6455
|
const id = typeof context.id === "string" ? context.id : typeof context.params.route?.id === "string" ? context.params.route.id : typeof firstArg === "string" ? firstArg : firstArg && typeof firstArg === "object" ? firstArg.boardId ?? firstArg.id ?? firstArg.slug : void 0;
|
|
5909
|
-
if (!id) throw new
|
|
6456
|
+
if (!id) throw new BadRequest5("Board ID is required");
|
|
5910
6457
|
const board = await boardRepository.findBySlugOrId(id);
|
|
5911
|
-
if (!board) throw new
|
|
6458
|
+
if (!board) throw new Forbidden9(`Board not found: ${id}`);
|
|
5912
6459
|
const allowed = mode === "view" ? await boardRepository.canView(board.board_id, user.user_id) : await boardRepository.canMutate(board.board_id, user.user_id);
|
|
5913
6460
|
if (!allowed) {
|
|
5914
|
-
throw new
|
|
6461
|
+
throw new Forbidden9(
|
|
5915
6462
|
mode === "view" ? `You need board access to ${action}` : `You need board owner or board group 'all' access to ${action}`
|
|
5916
6463
|
);
|
|
5917
6464
|
}
|
|
@@ -5925,16 +6472,16 @@ function registerHooks(ctx) {
|
|
|
5925
6472
|
all: [typedValidateQuery(boardQueryValidator), requireAuth],
|
|
5926
6473
|
find: [
|
|
5927
6474
|
// RBAC: restrict boards.find to boards the caller created or has a
|
|
5928
|
-
// branch on.
|
|
5929
|
-
//
|
|
5930
|
-
...branchRbacEnabled ? [
|
|
6475
|
+
// branch on. The service pushes this into the repository query as one
|
|
6476
|
+
// SQL predicate, avoiding a preloaded `board_id IN (...)` list.
|
|
6477
|
+
...branchRbacEnabled ? [scopeFindToAccessibleBoardsSql(superadminOpts)] : []
|
|
5931
6478
|
],
|
|
5932
6479
|
get: [ensureCanViewBoard("view this board")],
|
|
5933
6480
|
findBySlug: [ensureCanViewBoard("view this board")],
|
|
5934
6481
|
findBySlugOrId: [ensureCanViewBoard("view this board")],
|
|
5935
|
-
create: [requireMinimumRole(
|
|
6482
|
+
create: [requireMinimumRole(ROLES10.MEMBER, "create boards"), injectCreatedBy()],
|
|
5936
6483
|
patch: [
|
|
5937
|
-
requireMinimumRole(
|
|
6484
|
+
requireMinimumRole(ROLES10.MEMBER, "update boards"),
|
|
5938
6485
|
ensureCanMutateBoard("update this board"),
|
|
5939
6486
|
async (context) => {
|
|
5940
6487
|
const contextData = context.data || {};
|
|
@@ -5986,6 +6533,17 @@ function registerHooks(ctx) {
|
|
|
5986
6533
|
context.dispatch = result;
|
|
5987
6534
|
return context;
|
|
5988
6535
|
}
|
|
6536
|
+
if (_action === "mergeObjectFields" && objects) {
|
|
6537
|
+
if (!context.id) throw new Error("Board ID required");
|
|
6538
|
+
const result = await boardsService.mergeBoardObjectFields(
|
|
6539
|
+
context.id,
|
|
6540
|
+
objects
|
|
6541
|
+
);
|
|
6542
|
+
context.result = result;
|
|
6543
|
+
app.service("boards").emit("patched", result);
|
|
6544
|
+
context.dispatch = result;
|
|
6545
|
+
return context;
|
|
6546
|
+
}
|
|
5989
6547
|
if (_action === "deleteZone" && objectId) {
|
|
5990
6548
|
if (!context.id) throw new Error("Board ID required");
|
|
5991
6549
|
const result = await boardsService.deleteZone(
|
|
@@ -6001,30 +6559,30 @@ function registerHooks(ctx) {
|
|
|
6001
6559
|
}
|
|
6002
6560
|
],
|
|
6003
6561
|
remove: [
|
|
6004
|
-
requireMinimumRole(
|
|
6562
|
+
requireMinimumRole(ROLES10.MEMBER, "delete boards"),
|
|
6005
6563
|
ensureCanMutateBoard("delete this board")
|
|
6006
6564
|
],
|
|
6007
6565
|
toBlob: [
|
|
6008
|
-
requireMinimumRole(
|
|
6566
|
+
requireMinimumRole(ROLES10.MEMBER, "export boards"),
|
|
6009
6567
|
ensureCanViewBoard("export boards")
|
|
6010
6568
|
],
|
|
6011
6569
|
toYaml: [
|
|
6012
|
-
requireMinimumRole(
|
|
6570
|
+
requireMinimumRole(ROLES10.MEMBER, "export boards"),
|
|
6013
6571
|
ensureCanViewBoard("export boards")
|
|
6014
6572
|
],
|
|
6015
|
-
fromBlob: [requireMinimumRole(
|
|
6016
|
-
fromYaml: [requireMinimumRole(
|
|
6017
|
-
clone: [requireMinimumRole(
|
|
6573
|
+
fromBlob: [requireMinimumRole(ROLES10.MEMBER, "import boards")],
|
|
6574
|
+
fromYaml: [requireMinimumRole(ROLES10.MEMBER, "import boards")],
|
|
6575
|
+
clone: [requireMinimumRole(ROLES10.MEMBER, "clone boards"), ensureCanViewBoard("clone boards")],
|
|
6018
6576
|
setPrimaryAssistant: [
|
|
6019
|
-
requireMinimumRole(
|
|
6577
|
+
requireMinimumRole(ROLES10.MEMBER, "set primary assistant"),
|
|
6020
6578
|
ensureCanMutateBoard("set primary assistant")
|
|
6021
6579
|
],
|
|
6022
6580
|
clearPrimaryAssistant: [
|
|
6023
|
-
requireMinimumRole(
|
|
6581
|
+
requireMinimumRole(ROLES10.MEMBER, "clear primary assistant"),
|
|
6024
6582
|
ensureCanMutateBoard("clear primary assistant")
|
|
6025
6583
|
],
|
|
6026
6584
|
ensureAssistantWelcomeNote: [
|
|
6027
|
-
requireMinimumRole(
|
|
6585
|
+
requireMinimumRole(ROLES10.MEMBER, "create assistant welcome note"),
|
|
6028
6586
|
ensureCanMutateBoard("create assistant welcome note")
|
|
6029
6587
|
]
|
|
6030
6588
|
},
|
|
@@ -6165,7 +6723,7 @@ function registerHooks(ctx) {
|
|
|
6165
6723
|
before: {
|
|
6166
6724
|
create: [
|
|
6167
6725
|
requireAuth,
|
|
6168
|
-
requireMinimumRole(
|
|
6726
|
+
requireMinimumRole(ROLES10.MEMBER, "archive boards"),
|
|
6169
6727
|
ensureCanMutateBoard("archive this board")
|
|
6170
6728
|
]
|
|
6171
6729
|
},
|
|
@@ -6182,17 +6740,22 @@ function registerHooks(ctx) {
|
|
|
6182
6740
|
before: {
|
|
6183
6741
|
create: [
|
|
6184
6742
|
requireAuth,
|
|
6185
|
-
requireMinimumRole(
|
|
6743
|
+
requireMinimumRole(ROLES10.MEMBER, "unarchive boards"),
|
|
6186
6744
|
ensureCanMutateBoard("unarchive this board")
|
|
6187
6745
|
]
|
|
6188
6746
|
},
|
|
6189
6747
|
after: { create: [clearRealtimeBranchVisibility] }
|
|
6190
6748
|
});
|
|
6191
6749
|
}
|
|
6750
|
+
if (tenantColumnsEnabled) {
|
|
6751
|
+
registerTenantHooks();
|
|
6752
|
+
}
|
|
6192
6753
|
}
|
|
6193
6754
|
export {
|
|
6194
6755
|
PROMPT_FLOW_PATCH_FIELDS,
|
|
6756
|
+
TENANT_OWNED_SERVICE_PATHS,
|
|
6195
6757
|
enrichSessionFindResultWithRemoteRelationships,
|
|
6758
|
+
getTrustedSessionTenantId,
|
|
6196
6759
|
isPromptFlowPatchOnly,
|
|
6197
6760
|
registerHooks,
|
|
6198
6761
|
shouldDrainQueueAfterSessionPostTurnPatch,
|