@bevel-software/platform-core-backend 0.15.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +4 -4
- package/dist/core/catalog-cache-invalidation.d.ts +16 -0
- package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
- package/dist/core/catalog-cache-invalidation.js +6 -1
- package/dist/core/catalog-cache-invalidation.js.map +1 -1
- package/dist/core/catalog-revision.d.ts +39 -0
- package/dist/core/catalog-revision.d.ts.map +1 -0
- package/dist/core/catalog-revision.js +94 -0
- package/dist/core/catalog-revision.js.map +1 -0
- package/dist/core/create-core-server.d.ts +7 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +199 -75
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +49 -2
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +212 -86
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +138 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +218 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/public-config.d.ts +82 -0
- package/dist/core/public-config.d.ts.map +1 -0
- package/dist/core/public-config.js +78 -0
- package/dist/core/public-config.js.map +1 -0
- package/dist/core/readiness.d.ts +86 -0
- package/dist/core/readiness.d.ts.map +1 -0
- package/dist/core/readiness.js +56 -0
- package/dist/core/readiness.js.map +1 -0
- package/dist/core-config.d.ts +30 -0
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +64 -2
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +215 -11
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +57 -11
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +616 -155
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-mutation.service.d.ts +71 -5
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
- package/dist/modules/access/access-mutation.service.js +161 -13
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-view.d.ts +147 -0
- package/dist/modules/access/access-view.d.ts.map +1 -0
- package/dist/modules/access/access-view.js +211 -0
- package/dist/modules/access/access-view.js.map +1 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +255 -79
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/admin-locked-commit.d.ts +2 -3
- package/dist/modules/access/admin-locked-commit.d.ts.map +1 -1
- package/dist/modules/access/admin-locked-commit.js +9 -8
- package/dist/modules/access/admin-locked-commit.js.map +1 -1
- package/dist/modules/access/admin-route-helpers.d.ts.map +1 -1
- package/dist/modules/access/admin-route-helpers.js +4 -4
- package/dist/modules/access/admin-route-helpers.js.map +1 -1
- package/dist/modules/access/change-read-gate.d.ts +53 -0
- package/dist/modules/access/change-read-gate.d.ts.map +1 -0
- package/dist/modules/access/change-read-gate.js +134 -0
- package/dist/modules/access/change-read-gate.js.map +1 -0
- package/dist/modules/access/creator-access.d.ts +33 -39
- package/dist/modules/access/creator-access.d.ts.map +1 -1
- package/dist/modules/access/creator-access.js +92 -119
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
- package/dist/modules/access/directory-sync-bot.js +3 -1
- package/dist/modules/access/directory-sync-bot.js.map +1 -1
- package/dist/modules/access/groups-admin.service.d.ts +3 -3
- package/dist/modules/access/groups-admin.service.js +2 -2
- package/dist/modules/access/reference-scan.d.ts +1 -1
- package/dist/modules/access/reference-scan.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.js +5 -4
- package/dist/modules/access/reference-scan.js.map +1 -1
- package/dist/modules/access/roles-admin.service.d.ts +72 -13
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +71 -13
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/access/synced-groups-committer.d.ts.map +1 -1
- package/dist/modules/access/synced-groups-committer.js +8 -6
- package/dist/modules/access/synced-groups-committer.js.map +1 -1
- package/dist/modules/access/synced-groups-writer.d.ts.map +1 -1
- package/dist/modules/access/synced-groups-writer.js +3 -8
- package/dist/modules/access/synced-groups-writer.js.map +1 -1
- package/dist/modules/access/user-access-removal.service.d.ts +209 -0
- package/dist/modules/access/user-access-removal.service.d.ts.map +1 -0
- package/dist/modules/access/user-access-removal.service.js +662 -0
- package/dist/modules/access/user-access-removal.service.js.map +1 -0
- package/dist/modules/access-model/access-errors.d.ts +32 -1
- package/dist/modules/access-model/access-errors.d.ts.map +1 -1
- package/dist/modules/access-model/access-errors.js +38 -11
- package/dist/modules/access-model/access-errors.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +49 -24
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +68 -48
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/access-model/access-splice.d.ts.map +1 -1
- package/dist/modules/access-model/access-splice.js +18 -18
- package/dist/modules/access-model/access-splice.js.map +1 -1
- package/dist/modules/access-model/access-template.d.ts +22 -0
- package/dist/modules/access-model/access-template.d.ts.map +1 -0
- package/dist/modules/access-model/access-template.js +42 -0
- package/dist/modules/access-model/access-template.js.map +1 -0
- package/dist/modules/access-model/change-gate.d.ts +65 -0
- package/dist/modules/access-model/change-gate.d.ts.map +1 -0
- package/dist/modules/access-model/change-gate.js +25 -0
- package/dist/modules/access-model/change-gate.js.map +1 -0
- package/dist/modules/access-model/creator.d.ts +13 -16
- package/dist/modules/access-model/creator.d.ts.map +1 -1
- package/dist/modules/access-model/creator.js.map +1 -1
- package/dist/modules/access-model/frontmatter-lines.d.ts +27 -0
- package/dist/modules/access-model/frontmatter-lines.d.ts.map +1 -0
- package/dist/modules/access-model/frontmatter-lines.js +74 -0
- package/dist/modules/access-model/frontmatter-lines.js.map +1 -0
- package/dist/modules/access-model/plugin-principals.d.ts +5 -3
- package/dist/modules/access-model/plugin-principals.d.ts.map +1 -1
- package/dist/modules/access-model/plugin-principals.js +11 -17
- package/dist/modules/access-model/plugin-principals.js.map +1 -1
- package/dist/modules/access-model/roles-yaml-guard.d.ts +73 -2
- package/dist/modules/access-model/roles-yaml-guard.d.ts.map +1 -1
- package/dist/modules/access-model/roles-yaml-guard.js +153 -3
- package/dist/modules/access-model/roles-yaml-guard.js.map +1 -1
- package/dist/modules/admin/admin-access.service.d.ts.map +1 -1
- package/dist/modules/admin/admin-access.service.js +5 -2
- package/dist/modules/admin/admin-access.service.js.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +21 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.js +38 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -0
- package/dist/modules/agent-instructions/compose.d.ts +71 -0
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -0
- package/dist/modules/agent-instructions/compose.js +234 -0
- package/dist/modules/agent-instructions/compose.js.map +1 -0
- package/dist/modules/agent-instructions/index.d.ts +4 -0
- package/dist/modules/agent-instructions/index.d.ts.map +1 -0
- package/dist/modules/agent-instructions/index.js +4 -0
- package/dist/modules/agent-instructions/index.js.map +1 -0
- package/dist/modules/agent-instructions/read-preamble.d.ts +37 -0
- package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -0
- package/dist/modules/agent-instructions/read-preamble.js +81 -0
- package/dist/modules/agent-instructions/read-preamble.js.map +1 -0
- package/dist/modules/auth/account-erasure.service.d.ts +30 -4
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
- package/dist/modules/auth/account-erasure.service.js +96 -10
- package/dist/modules/auth/account-erasure.service.js.map +1 -1
- package/dist/modules/auth/account.routes.d.ts +6 -3
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +109 -10
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts +10 -3
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +9 -4
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +89 -5
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +160 -25
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts +46 -3
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +99 -21
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +14 -2
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +56 -7
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/advisory-lock.d.ts +103 -0
- package/dist/modules/database/advisory-lock.d.ts.map +1 -0
- package/dist/modules/database/advisory-lock.js +320 -0
- package/dist/modules/database/advisory-lock.js.map +1 -0
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +9 -1
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +346 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +119 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +26 -6
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.js +4 -2
- package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
- package/dist/modules/diff/diff.routes.d.ts.map +1 -1
- package/dist/modules/diff/diff.routes.js +2 -4
- package/dist/modules/diff/diff.routes.js.map +1 -1
- package/dist/modules/diff/diff.service.d.ts +4 -1
- package/dist/modules/diff/diff.service.d.ts.map +1 -1
- package/dist/modules/diff/diff.service.js +79 -81
- package/dist/modules/diff/diff.service.js.map +1 -1
- package/dist/modules/kb-fs/bevel-ignore.d.ts +35 -0
- package/dist/modules/kb-fs/bevel-ignore.d.ts.map +1 -0
- package/dist/modules/kb-fs/bevel-ignore.js +71 -0
- package/dist/modules/kb-fs/bevel-ignore.js.map +1 -0
- package/dist/modules/kb-fs/file-change-notifier.d.ts.map +1 -1
- package/dist/modules/kb-fs/file-change-notifier.js +3 -1
- package/dist/modules/kb-fs/file-change-notifier.js.map +1 -1
- package/dist/modules/kb-fs/git-guarded-filesystem.d.ts +37 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.d.ts.map +1 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.js +104 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.js.map +1 -0
- package/dist/modules/kb-fs/locking-filesystem.d.ts +113 -18
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +353 -76
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/node-fs.d.ts +23 -0
- package/dist/modules/kb-fs/node-fs.d.ts.map +1 -0
- package/dist/modules/kb-fs/node-fs.js +158 -0
- package/dist/modules/kb-fs/node-fs.js.map +1 -0
- package/dist/modules/kb-fs/read-only-filesystem.d.ts +10 -9
- package/dist/modules/kb-fs/read-only-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/read-only-filesystem.js +18 -9
- package/dist/modules/kb-fs/read-only-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +100 -3
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +195 -3
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.js +4 -2
- package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.service.js +7 -5
- package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
- package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/git-http.routes.js +6 -4
- package/dist/modules/marketplace/git-http.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +12 -2
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +32 -3
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +27 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +45 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.routes.js +30 -6
- package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +21 -9
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.service.js +60 -19
- package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -1
- package/dist/modules/marketplace/github-facade/index.d.ts +1 -1
- package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/index.js +1 -1
- package/dist/modules/marketplace/github-facade/index.js.map +1 -1
- package/dist/modules/marketplace/marketplace-repo.service.d.ts +14 -1
- package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -1
- package/dist/modules/marketplace/marketplace-repo.service.js +26 -8
- package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -1
- package/dist/modules/mcp/downstream-pool.d.ts +107 -0
- package/dist/modules/mcp/downstream-pool.d.ts.map +1 -0
- package/dist/modules/mcp/downstream-pool.js +221 -0
- package/dist/modules/mcp/downstream-pool.js.map +1 -0
- package/dist/modules/mcp/downstream-token-refresh.d.ts +77 -0
- package/dist/modules/mcp/downstream-token-refresh.d.ts.map +1 -0
- package/dist/modules/mcp/downstream-token-refresh.js +166 -0
- package/dist/modules/mcp/downstream-token-refresh.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli-args.d.ts +78 -0
- package/dist/modules/mcp/first-call-probe.cli-args.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli-args.js +151 -0
- package/dist/modules/mcp/first-call-probe.cli-args.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli.d.ts +2 -0
- package/dist/modules/mcp/first-call-probe.cli.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli.js +62 -0
- package/dist/modules/mcp/first-call-probe.cli.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.d.ts +165 -0
- package/dist/modules/mcp/first-call-probe.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.js +298 -0
- package/dist/modules/mcp/first-call-probe.js.map +1 -0
- package/dist/modules/mcp/manual-failure-memo.d.ts +42 -17
- package/dist/modules/mcp/manual-failure-memo.d.ts.map +1 -1
- package/dist/modules/mcp/manual-failure-memo.js +79 -23
- package/dist/modules/mcp/manual-failure-memo.js.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +9 -5
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +24 -16
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.routes.d.ts +4 -4
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.routes.js +83 -179
- package/dist/modules/mcp/mcp.routes.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +218 -61
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +713 -159
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +4 -2
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +3 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
- package/dist/modules/mcp/surface-log-throttle.d.ts +59 -0
- package/dist/modules/mcp/surface-log-throttle.d.ts.map +1 -0
- package/dist/modules/mcp/surface-log-throttle.js +94 -0
- package/dist/modules/mcp/surface-log-throttle.js.map +1 -0
- package/dist/modules/plugins/compile/compile-marketplace.d.ts +13 -6
- package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -1
- package/dist/modules/plugins/compile/compile-marketplace.js +119 -36
- package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +8 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.js +9 -6
- package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +32 -9
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +26 -6
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js +71 -14
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +4 -2
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.js +9 -6
- package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
- package/dist/modules/plugins/discovery/native.source.d.ts +2 -1
- package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/native.source.js +22 -4
- package/dist/modules/plugins/discovery/native.source.js.map +1 -1
- package/dist/modules/plugins/discovery/plugin-source.d.ts +17 -3
- package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/index.d.ts +6 -3
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js +6 -3
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts +250 -0
- package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -0
- package/dist/modules/plugins/join-request-jobs.service.js +602 -0
- package/dist/modules/plugins/join-request-jobs.service.js.map +1 -0
- package/dist/modules/plugins/join-request-records.store.d.ts +161 -0
- package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -0
- package/dist/modules/plugins/join-request-records.store.js +179 -0
- package/dist/modules/plugins/join-request-records.store.js.map +1 -0
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-requests.service.js +4 -2
- package/dist/modules/plugins/join-requests.service.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +4 -1
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js +6 -3
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugin-links.service.d.ts +2 -5
- package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.service.js +4 -13
- package/dist/modules/plugins/plugin-links.service.js.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.d.ts +91 -19
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +183 -38
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts +3 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.js +20 -11
- package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
- package/dist/modules/plugins/plugins.contract.d.ts +52 -4
- package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +38 -5
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +190 -116
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.service.d.ts +38 -6
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.service.js +86 -17
- package/dist/modules/plugins/plugins.service.js.map +1 -1
- package/dist/modules/plugins/plugins.tools.d.ts +25 -0
- package/dist/modules/plugins/plugins.tools.d.ts.map +1 -0
- package/dist/modules/plugins/plugins.tools.js +82 -0
- package/dist/modules/plugins/plugins.tools.js.map +1 -0
- package/dist/modules/plugins/teams.routes.d.ts +42 -0
- package/dist/modules/plugins/teams.routes.d.ts.map +1 -0
- package/dist/modules/plugins/teams.routes.js +79 -0
- package/dist/modules/plugins/teams.routes.js.map +1 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +40 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +202 -37
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
- package/dist/modules/secrets-vault/index.d.ts +1 -1
- package/dist/modules/secrets-vault/index.d.ts.map +1 -1
- package/dist/modules/secrets-vault/index.js.map +1 -1
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +5 -3
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js +3 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +78 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.js +40 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +106 -52
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/connection-check.d.ts +118 -0
- package/dist/modules/settings/connection-check.d.ts.map +1 -0
- package/dist/modules/settings/connection-check.js +287 -0
- package/dist/modules/settings/connection-check.js.map +1 -0
- package/dist/modules/settings/deployment-settings.service.d.ts +153 -7
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +348 -51
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/git-root-folders.d.ts +54 -0
- package/dist/modules/settings/git-root-folders.d.ts.map +1 -0
- package/dist/modules/settings/git-root-folders.js +130 -0
- package/dist/modules/settings/git-root-folders.js.map +1 -0
- package/dist/modules/settings/oidc-check.d.ts +85 -0
- package/dist/modules/settings/oidc-check.d.ts.map +1 -0
- package/dist/modules/settings/oidc-check.js +172 -0
- package/dist/modules/settings/oidc-check.js.map +1 -0
- package/dist/modules/settings/setup.routes.d.ts +31 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +400 -108
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/allowed-tools-check.d.ts +132 -0
- package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -0
- package/dist/modules/skills/allowed-tools-check.js +260 -0
- package/dist/modules/skills/allowed-tools-check.js.map +1 -0
- package/dist/modules/skills/index.d.ts +3 -1
- package/dist/modules/skills/index.d.ts.map +1 -1
- package/dist/modules/skills/index.js +1 -0
- package/dist/modules/skills/index.js.map +1 -1
- package/dist/modules/skills/pending-skills.service.d.ts +6 -11
- package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
- package/dist/modules/skills/pending-skills.service.js +18 -70
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.js +9 -6
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +44 -10
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.d.ts +8 -1
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +16 -2
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +31 -7
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +191 -81
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts +4 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +41 -6
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/connection-key-rejection.d.ts +18 -0
- package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -0
- package/dist/modules/tool-auth/connection-key-rejection.js +20 -0
- package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts +14 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts.map +1 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.js +67 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +51 -3
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts +16 -6
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +61 -18
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +5 -2
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.js +5 -2
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
- package/dist/modules/tool-auth/key-or-session.middleware.d.ts +23 -0
- package/dist/modules/tool-auth/key-or-session.middleware.d.ts.map +1 -0
- package/dist/modules/tool-auth/key-or-session.middleware.js +39 -0
- package/dist/modules/tool-auth/key-or-session.middleware.js.map +1 -0
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +7 -1
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +8 -5
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts +14 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +28 -6
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +22 -5
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +6 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.js +7 -1
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
- package/dist/modules/tool-manuals/index.d.ts +2 -1
- package/dist/modules/tool-manuals/index.d.ts.map +1 -1
- package/dist/modules/tool-manuals/index.js +1 -0
- package/dist/modules/tool-manuals/index.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +8 -6
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +10 -2
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -15
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts +50 -0
- package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/pending-tools.service.js +149 -0
- package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-delete.service.d.ts +135 -0
- package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-delete.service.js +303 -0
- package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +161 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.js +9 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +19 -2
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +127 -57
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +119 -5
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +404 -74
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +78 -6
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +88 -54
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/event-bus.d.ts +10 -4
- package/dist/modules/workflow/event-bus.d.ts.map +1 -1
- package/dist/modules/workflow/event-bus.js +14 -11
- package/dist/modules/workflow/event-bus.js.map +1 -1
- package/dist/modules/workflow/events.routes.d.ts +17 -2
- package/dist/modules/workflow/events.routes.d.ts.map +1 -1
- package/dist/modules/workflow/events.routes.js +31 -12
- package/dist/modules/workflow/events.routes.js.map +1 -1
- package/dist/modules/workflow/file-lock.service.d.ts +22 -4
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
- package/dist/modules/workflow/file-lock.service.js +27 -4
- package/dist/modules/workflow/file-lock.service.js.map +1 -1
- package/dist/modules/workflow/git/change-request-link.d.ts +20 -0
- package/dist/modules/workflow/git/change-request-link.d.ts.map +1 -0
- package/dist/modules/workflow/git/change-request-link.js +34 -0
- package/dist/modules/workflow/git/change-request-link.js.map +1 -0
- package/dist/modules/workflow/git/git-version.d.ts.map +1 -1
- package/dist/modules/workflow/git/git-version.js +3 -1
- package/dist/modules/workflow/git/git-version.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +263 -4
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +528 -118
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.d.ts +36 -0
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -0
- package/dist/modules/workflow/git/node-git-runner.js +273 -0
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts +51 -2
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +157 -25
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts +11 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +24 -4
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.d.ts +15 -8
- package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.js +107 -58
- package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
- package/dist/modules/workflow/recovery-bot.js +3 -1
- package/dist/modules/workflow/recovery-bot.js.map +1 -1
- package/dist/modules/workflow/review-workflow/approval-lock.d.ts +60 -0
- package/dist/modules/workflow/review-workflow/approval-lock.d.ts.map +1 -0
- package/dist/modules/workflow/review-workflow/approval-lock.js +116 -0
- package/dist/modules/workflow/review-workflow/approval-lock.js.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +54 -7
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +64 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +269 -90
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/sanitize-error.d.ts +5 -2
- package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
- package/dist/modules/workflow/sanitize-error.js +8 -4
- package/dist/modules/workflow/sanitize-error.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts +2 -0
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +259 -29
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +166 -14
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +906 -106
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/empty-dirs.d.ts +15 -0
- package/dist/modules/workspace/empty-dirs.d.ts.map +1 -0
- package/dist/modules/workspace/empty-dirs.js +90 -0
- package/dist/modules/workspace/empty-dirs.js.map +1 -0
- package/dist/modules/workspace/file-readers/content-mode.d.ts +50 -0
- package/dist/modules/workspace/file-readers/content-mode.d.ts.map +1 -0
- package/dist/modules/workspace/file-readers/content-mode.js +55 -0
- package/dist/modules/workspace/file-readers/content-mode.js.map +1 -0
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +4 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js +4 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.types.d.ts +5 -2
- package/dist/modules/workspace/file-readers/doc-extract.types.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.types.js +7 -4
- package/dist/modules/workspace/file-readers/doc-extract.types.js.map +1 -1
- package/dist/modules/workspace/file-readers/document-reader.d.ts +2 -0
- package/dist/modules/workspace/file-readers/document-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/document-reader.js +5 -0
- package/dist/modules/workspace/file-readers/document-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/extract-docx.d.ts +6 -0
- package/dist/modules/workspace/file-readers/extract-docx.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/extract-docx.js +6 -0
- package/dist/modules/workspace/file-readers/extract-docx.js.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.d.ts +24 -5
- package/dist/modules/workspace/file-readers/file-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.js +11 -6
- package/dist/modules/workspace/file-readers/file-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.js +6 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.js.map +1 -1
- package/dist/modules/workspace/file-readers/image-reader.d.ts +7 -5
- package/dist/modules/workspace/file-readers/image-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/image-reader.js +9 -5
- package/dist/modules/workspace/file-readers/image-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/ooxml-text.d.ts +3 -0
- package/dist/modules/workspace/file-readers/ooxml-text.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/ooxml-text.js +39 -2
- package/dist/modules/workspace/file-readers/ooxml-text.js.map +1 -1
- package/dist/modules/workspace/file-readers/text-reader.d.ts +29 -1
- package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/text-reader.js +57 -3
- package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
- package/dist/modules/workspace/git-internals.middleware.d.ts +28 -0
- package/dist/modules/workspace/git-internals.middleware.d.ts.map +1 -0
- package/dist/modules/workspace/git-internals.middleware.js +93 -0
- package/dist/modules/workspace/git-internals.middleware.js.map +1 -0
- package/dist/modules/workspace/not-found.d.ts +80 -0
- package/dist/modules/workspace/not-found.d.ts.map +1 -0
- package/dist/modules/workspace/not-found.js +112 -0
- package/dist/modules/workspace/not-found.js.map +1 -0
- package/dist/modules/workspace/session-ontology.gate.d.ts +1 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.js +1 -1
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
- package/dist/modules/workspace/startup/beside-checkout.d.ts +42 -0
- package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -0
- package/dist/modules/workspace/startup/beside-checkout.js +110 -0
- package/dist/modules/workspace/startup/beside-checkout.js.map +1 -0
- package/dist/modules/workspace/startup/kb-git.d.ts +7 -12
- package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-git.js +34 -35
- package/dist/modules/workspace/startup/kb-git.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +95 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +257 -55
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +45 -0
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +417 -385
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +48 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js +183 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +51 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +158 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.d.ts +64 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.js +97 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +45 -81
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +3 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js +4 -12
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts +6 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +154 -78
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +96 -24
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +446 -138
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +94 -0
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/template-source.js +160 -0
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts +14 -2
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +649 -238
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +290 -12
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +924 -269
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +42 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +1590 -146
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +76 -0
- package/dist/modules/workspace/write-denial.d.ts.map +1 -0
- package/dist/modules/workspace/write-denial.js +138 -0
- package/dist/modules/workspace/write-denial.js.map +1 -0
- package/dist/shared/canonical-file-identity.d.ts +64 -0
- package/dist/shared/canonical-file-identity.d.ts.map +1 -0
- package/dist/shared/canonical-file-identity.js +92 -0
- package/dist/shared/canonical-file-identity.js.map +1 -0
- package/dist/shared/domain-errors.d.ts +108 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +137 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/email-identity.d.ts +32 -0
- package/dist/shared/email-identity.d.ts.map +1 -0
- package/dist/shared/email-identity.js +37 -0
- package/dist/shared/email-identity.js.map +1 -0
- package/dist/shared/fs.contract.d.ts +206 -0
- package/dist/shared/fs.contract.d.ts.map +1 -0
- package/dist/shared/fs.contract.js +79 -0
- package/dist/shared/fs.contract.js.map +1 -0
- package/dist/shared/git-failure.d.ts +80 -0
- package/dist/shared/git-failure.d.ts.map +1 -0
- package/dist/shared/git-failure.js +139 -0
- package/dist/shared/git-failure.js.map +1 -0
- package/dist/shared/git-internals.d.ts +17 -0
- package/dist/shared/git-internals.d.ts.map +1 -0
- package/dist/shared/git-internals.js +123 -0
- package/dist/shared/git-internals.js.map +1 -0
- package/dist/shared/git.contract.d.ts +157 -0
- package/dist/shared/git.contract.d.ts.map +1 -0
- package/dist/shared/git.contract.js +103 -0
- package/dist/shared/git.contract.js.map +1 -0
- package/dist/shared/http-errors.d.ts +33 -0
- package/dist/shared/http-errors.d.ts.map +1 -0
- package/dist/shared/http-errors.js +35 -0
- package/dist/shared/http-errors.js.map +1 -0
- package/dist/shared/logger.contract.d.ts +63 -0
- package/dist/shared/logger.contract.d.ts.map +1 -0
- package/dist/shared/logger.contract.js +126 -0
- package/dist/shared/logger.contract.js.map +1 -0
- package/dist/shared/logging.d.ts +31 -0
- package/dist/shared/logging.d.ts.map +1 -0
- package/dist/shared/logging.js +92 -0
- package/dist/shared/logging.js.map +1 -0
- package/dist/shared/path-containment.d.ts +21 -0
- package/dist/shared/path-containment.d.ts.map +1 -0
- package/dist/shared/path-containment.js +34 -0
- package/dist/shared/path-containment.js.map +1 -0
- package/dist/shared/pending-proposals.d.ts +71 -0
- package/dist/shared/pending-proposals.d.ts.map +1 -0
- package/dist/shared/pending-proposals.js +98 -0
- package/dist/shared/pending-proposals.js.map +1 -0
- package/dist/shared/printable.d.ts +22 -0
- package/dist/shared/printable.d.ts.map +1 -0
- package/dist/shared/printable.js +65 -0
- package/dist/shared/printable.js.map +1 -0
- package/dist/shared/redact-secret.d.ts +30 -0
- package/dist/shared/redact-secret.d.ts.map +1 -0
- package/dist/shared/redact-secret.js +114 -0
- package/dist/shared/redact-secret.js.map +1 -0
- package/dist/shared/rename-no-replace.d.ts +119 -0
- package/dist/shared/rename-no-replace.d.ts.map +1 -0
- package/dist/shared/rename-no-replace.js +323 -0
- package/dist/shared/rename-no-replace.js.map +1 -0
- package/dist/shared/ssrf.d.ts.map +1 -1
- package/dist/shared/ssrf.js +49 -18
- package/dist/shared/ssrf.js.map +1 -1
- package/dist/version.d.ts +10 -6
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +10 -6
- package/dist/version.js.map +1 -1
- package/kb-template/.bevelignore +4 -3
- package/kb-template/AGENTS.md +281 -36
- package/kb-template/KnowledgeBase/How to get started.md +1 -1
- package/kb-template/access.md +5 -3
- package/kb-template/mcp-description.md +27 -0
- package/migrations/0006_api_tokens_revoked_by.sql +1 -0
- package/migrations/0007_github_facade_registered.sql +1 -0
- package/migrations/0008_change_request_apply_failure.sql +4 -0
- package/migrations/0009_change_request_apply_failure_kind.sql +13 -0
- package/migrations/0010_plugin_join_requests.sql +15 -0
- package/migrations/0011_plugin_join_request_claim.sql +11 -0
- package/migrations/meta/0006_snapshot.json +1723 -0
- package/migrations/meta/0007_snapshot.json +1729 -0
- package/migrations/meta/0008_snapshot.json +1753 -0
- package/migrations/meta/0009_snapshot.json +1759 -0
- package/migrations/meta/0010_snapshot.json +1872 -0
- package/migrations/meta/0011_snapshot.json +1884 -0
- package/migrations/meta/_journal.json +42 -0
- package/package.json +6 -5
- package/src/__tests__/core-config.domain.test.ts +67 -2
- package/src/__tests__/kb-layout-config.test.ts +186 -1
- package/src/__tests__/open-change-gate.ts +15 -0
- package/src/core/__tests__/catalog-cache-invalidation.test.ts +83 -3
- package/src/core/__tests__/catalog-revision.test.ts +190 -0
- package/src/core/__tests__/lifecycle.test.ts +369 -0
- package/src/core/__tests__/public-config.test.ts +30 -0
- package/src/core/__tests__/readiness.test.ts +109 -0
- package/src/core/catalog-cache-invalidation.ts +20 -1
- package/src/core/catalog-revision.ts +110 -0
- package/src/core/create-core-server.ts +258 -79
- package/src/core/create-core-services.ts +302 -81
- package/src/core/lifecycle.ts +312 -0
- package/src/core/public-config.ts +86 -0
- package/src/core/readiness.ts +123 -0
- package/src/core-config.ts +70 -4
- package/src/index.ts +15 -0
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +362 -0
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +2 -1
- package/src/modules/access/__tests__/access-control.atref-cache.test.ts +46 -22
- package/src/modules/access/__tests__/access-control.deny-dependents.test.ts +215 -0
- package/src/modules/access/__tests__/access-control.download-read.test.ts +268 -0
- package/src/modules/access/__tests__/access-control.everyone-read.test.ts +145 -0
- package/src/modules/access/__tests__/access-control.group-read.test.ts +163 -0
- package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +2 -0
- package/src/modules/access/__tests__/access-control.platform-restore.test.ts +152 -0
- package/src/modules/access/__tests__/access-control.prospective.test.ts +189 -0
- package/src/modules/access/__tests__/access-control.read-batch.test.ts +2 -1
- package/src/modules/access/__tests__/access-control.service.test.ts +123 -78
- package/src/modules/access/__tests__/access-groups.test.ts +47 -14
- package/src/modules/access/__tests__/access-md-format.test.ts +2 -1
- package/src/modules/access/__tests__/access-mutation.service.test.ts +52 -4
- package/src/modules/access/__tests__/access-own-read-grant.test.ts +2 -0
- package/src/modules/access/__tests__/access-personal-plugin.test.ts +153 -0
- package/src/modules/access/__tests__/access-plugin-principals.test.ts +18 -1
- package/src/modules/access/__tests__/access-restrict-here.test.ts +450 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +139 -0
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +394 -0
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +6 -2
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +3 -2
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +234 -0
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +216 -0
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +7 -2
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +360 -0
- package/src/modules/access/__tests__/change-read-gate.test.ts +272 -0
- package/src/modules/access/__tests__/creator-access.test.ts +81 -83
- package/src/modules/access/__tests__/grant-sources.test.ts +3 -2
- package/src/modules/access/__tests__/groups-admin.service.test.ts +6 -5
- package/src/modules/access/__tests__/roles-admin.security.test.ts +196 -0
- package/src/modules/access/__tests__/roles-admin.service.test.ts +127 -2
- package/src/modules/access/__tests__/roles-capabilities.test.ts +5 -4
- package/src/modules/access/__tests__/roles.routes.test.ts +5 -2
- package/src/modules/access/__tests__/user-access-removal.service.test.ts +402 -0
- package/src/modules/access/__tests__/users-db-double.ts +63 -0
- package/src/modules/access/access-control.interface.ts +251 -11
- package/src/modules/access/access-control.service.ts +719 -164
- package/src/modules/access/access-mutation.service.ts +182 -13
- package/src/modules/access/access-view.ts +316 -0
- package/src/modules/access/access.routes.ts +293 -95
- package/src/modules/access/admin-locked-commit.ts +12 -14
- package/src/modules/access/admin-route-helpers.ts +4 -4
- package/src/modules/access/change-read-gate.ts +148 -0
- package/src/modules/access/creator-access.ts +89 -124
- package/src/modules/access/directory-sync-bot.ts +4 -1
- package/src/modules/access/groups-admin.service.ts +3 -3
- package/src/modules/access/reference-scan.ts +5 -5
- package/src/modules/access/roles-admin.service.ts +94 -15
- package/src/modules/access/synced-groups-committer.ts +10 -15
- package/src/modules/access/synced-groups-writer.ts +3 -12
- package/src/modules/access/user-access-removal.service.ts +711 -0
- package/src/modules/access-model/__tests__/access-splice.test.ts +63 -1
- package/src/modules/access-model/__tests__/frontmatter-fences.test.ts +71 -0
- package/src/modules/access-model/__tests__/roles-yaml-guard.test.ts +131 -0
- package/src/modules/access-model/access-errors.ts +56 -15
- package/src/modules/access-model/access-grammar.ts +85 -48
- package/src/modules/access-model/access-splice.ts +18 -18
- package/src/modules/access-model/access-template.ts +44 -0
- package/src/modules/access-model/change-gate.ts +80 -0
- package/src/modules/access-model/creator.ts +18 -21
- package/src/modules/access-model/frontmatter-lines.ts +98 -0
- package/src/modules/access-model/plugin-principals.ts +12 -19
- package/src/modules/access-model/roles-yaml-guard.ts +182 -4
- package/src/modules/admin/admin-access.service.ts +6 -2
- package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +100 -0
- package/src/modules/agent-instructions/__tests__/compose.test.ts +256 -0
- package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +135 -0
- package/src/modules/agent-instructions/agent-instructions.routes.ts +41 -0
- package/src/modules/agent-instructions/compose.ts +271 -0
- package/src/modules/agent-instructions/index.ts +14 -0
- package/src/modules/agent-instructions/read-preamble.ts +88 -0
- package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +209 -0
- package/src/modules/auth/__tests__/account.routes.test.ts +178 -2
- package/src/modules/auth/__tests__/auth.middleware.test.ts +78 -0
- package/src/modules/auth/__tests__/auth.service.test.ts +338 -5
- package/src/modules/auth/__tests__/oidc-auth-provider.test.ts +352 -12
- package/src/modules/auth/__tests__/onboarding-done.route.test.ts +3 -1
- package/src/modules/auth/account-erasure.service.ts +117 -10
- package/src/modules/auth/account.routes.ts +115 -14
- package/src/modules/auth/auth.routes.ts +20 -7
- package/src/modules/auth/auth.service.ts +187 -28
- package/src/modules/auth/oidc-auth-provider.ts +120 -22
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +109 -1
- package/src/modules/code-mode/code-mode.tool.ts +13 -2
- package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +78 -0
- package/src/modules/connection-probe/connection-probe.service.ts +59 -7
- package/src/modules/database/__tests__/advisory-lease.test.ts +152 -0
- package/src/modules/database/__tests__/advisory-lock.test.ts +147 -0
- package/src/modules/database/advisory-lock.ts +346 -0
- package/src/modules/database/connection.ts +9 -1
- package/src/modules/database/core-schema.ts +123 -0
- package/src/modules/database/migrate.ts +27 -6
- package/src/modules/declared-variables/declared-variables.routes.ts +6 -3
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +3 -0
- package/src/modules/diff/__tests__/diff.service.test.ts +3 -0
- package/src/modules/diff/diff.routes.ts +2 -4
- package/src/modules/diff/diff.service.ts +75 -79
- package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +472 -9
- package/src/modules/kb-fs/__tests__/node-fs.test.ts +409 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +210 -1
- package/src/modules/{workspace → kb-fs}/bevel-ignore.ts +22 -15
- package/src/modules/kb-fs/file-change-notifier.ts +4 -1
- package/src/modules/kb-fs/git-guarded-filesystem.ts +123 -0
- package/src/modules/kb-fs/locking-filesystem.ts +399 -109
- package/src/modules/kb-fs/node-fs.ts +165 -0
- package/src/modules/kb-fs/read-only-filesystem.ts +18 -9
- package/src/modules/kb-fs/repo-path.ts +213 -3
- package/src/modules/kb-sync/kb-sync.routes.ts +5 -2
- package/src/modules/kb-sync/kb-sync.service.ts +8 -5
- package/src/modules/marketplace/__tests__/github-facade.test.ts +134 -2
- package/src/modules/marketplace/__tests__/marketplace-git.test.ts +2 -1
- package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +47 -0
- package/src/modules/marketplace/git-http.routes.ts +7 -4
- package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +35 -3
- package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +55 -0
- package/src/modules/marketplace/github-facade/github-facade.routes.ts +32 -6
- package/src/modules/marketplace/github-facade/github-facade.service.ts +80 -19
- package/src/modules/marketplace/github-facade/index.ts +1 -0
- package/src/modules/marketplace/marketplace-repo.service.ts +23 -8
- package/src/modules/mcp/__tests__/downstream-pool.test.ts +278 -0
- package/src/modules/mcp/__tests__/downstream-token-refresh.test.ts +178 -0
- package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +156 -0
- package/src/modules/mcp/__tests__/first-call-probe.cli-args.test.ts +178 -0
- package/src/modules/mcp/__tests__/first-call-probe.test.ts +414 -0
- package/src/modules/mcp/__tests__/manual-failure-memo.test.ts +98 -6
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +8 -5
- package/src/modules/mcp/__tests__/mcp-routes-harness.ts +1 -3
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +1055 -59
- package/src/modules/mcp/__tests__/mcp.routes.stateless.test.ts +182 -0
- package/src/modules/mcp/__tests__/mcp.service.test.ts +274 -6
- package/src/modules/mcp/__tests__/surface-log-throttle.test.ts +169 -0
- package/src/modules/mcp/downstream-pool.ts +256 -0
- package/src/modules/mcp/downstream-token-refresh.ts +170 -0
- package/src/modules/mcp/first-call-probe.cli-args.ts +159 -0
- package/src/modules/mcp/first-call-probe.cli.ts +60 -0
- package/src/modules/mcp/first-call-probe.ts +418 -0
- package/src/modules/mcp/manual-failure-memo.ts +81 -23
- package/src/modules/mcp/mcp-auth.middleware.ts +25 -16
- package/src/modules/mcp/mcp.routes.ts +376 -482
- package/src/modules/mcp/mcp.service.ts +846 -176
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +5 -2
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +4 -4
- package/src/modules/mcp/surface-log-throttle.ts +120 -0
- package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +10 -7
- package/src/modules/plugins/__tests__/bundle-dialect.test.ts +165 -0
- package/src/modules/plugins/__tests__/compile-marketplace.test.ts +139 -10
- package/src/modules/plugins/__tests__/fake-join-request-store.ts +189 -0
- package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +608 -0
- package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +241 -0
- package/src/modules/plugins/__tests__/plugin-index.service.test.ts +148 -7
- package/src/modules/plugins/__tests__/plugin-links.service.test.ts +10 -13
- package/src/modules/plugins/__tests__/plugin-names.test.ts +77 -0
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +129 -19
- package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +91 -29
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +370 -19
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +131 -0
- package/src/modules/plugins/__tests__/teams.routes.test.ts +248 -0
- package/src/modules/plugins/compile/compile-marketplace.ts +143 -46
- package/src/modules/plugins/compile/marketplace-compiler.service.ts +8 -7
- package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +56 -20
- package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +30 -9
- package/src/modules/plugins/discovery/bundle-dialect/registry.ts +93 -18
- package/src/modules/plugins/discovery/kb-plugin-source.ts +10 -7
- package/src/modules/plugins/discovery/native.source.ts +21 -3
- package/src/modules/plugins/discovery/plugin-source.ts +17 -3
- package/src/modules/plugins/index.ts +16 -3
- package/src/modules/plugins/join-request-jobs.service.ts +675 -0
- package/src/modules/plugins/join-request-records.store.ts +353 -0
- package/src/modules/plugins/join-requests.service.ts +7 -4
- package/src/modules/plugins/plugin-links.service.ts +4 -17
- package/src/modules/plugins/plugin-links.ts +6 -3
- package/src/modules/plugins/plugin-provision.service.ts +209 -37
- package/src/modules/plugins/plugin-rename.service.ts +21 -9
- package/src/modules/plugins/plugins.contract.ts +52 -4
- package/src/modules/plugins/plugins.routes.ts +204 -124
- package/src/modules/plugins/plugins.service.ts +92 -18
- package/src/modules/plugins/plugins.tools.ts +88 -0
- package/src/modules/plugins/teams.routes.ts +129 -0
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +359 -15
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +248 -0
- package/src/modules/secrets-vault/__tests__/namespace-secrets.test.ts +202 -0
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +217 -35
- package/src/modules/secrets-vault/index.ts +1 -0
- package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +6 -3
- package/src/modules/secrets-vault/secrets-variable-loader.ts +4 -4
- package/src/modules/secrets-vault/secrets-vault.contract.ts +93 -0
- package/src/modules/secrets-vault/secrets-vault.routes.ts +99 -38
- package/src/modules/settings/__tests__/connection-check.test.ts +233 -0
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +188 -6
- package/src/modules/settings/__tests__/git-root-folders.test.ts +247 -0
- package/src/modules/settings/__tests__/oidc-check.test.ts +185 -0
- package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +119 -0
- package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +170 -0
- package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +555 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +667 -16
- package/src/modules/settings/connection-check.ts +351 -0
- package/src/modules/settings/deployment-settings.service.ts +403 -57
- package/src/modules/settings/git-root-folders.ts +171 -0
- package/src/modules/settings/oidc-check.ts +229 -0
- package/src/modules/settings/setup.routes.ts +456 -110
- package/src/modules/skills/__tests__/allowed-tools-check.test.ts +224 -0
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +210 -0
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -3
- package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +91 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +223 -2
- package/src/modules/skills/allowed-tools-check.ts +352 -0
- package/src/modules/skills/index.ts +4 -0
- package/src/modules/skills/pending-skills.service.ts +21 -82
- package/src/modules/skills/skill-access-requests.routes.ts +10 -6
- package/src/modules/skills/skills.contract.ts +43 -11
- package/src/modules/skills/skills.routes.ts +16 -1
- package/src/modules/skills/skills.service.ts +214 -84
- package/src/modules/skills/skills.tools.ts +43 -5
- package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +192 -0
- package/src/modules/tool-auth/__tests__/connection-keys-admin.routes.test.ts +116 -0
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +124 -0
- package/src/modules/tool-auth/connection-key-rejection.ts +25 -0
- package/src/modules/tool-auth/connection-keys-admin.routes.ts +76 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +56 -3
- package/src/modules/tool-auth/external-api-key.service.ts +73 -25
- package/src/modules/tool-auth/internal-token.service.ts +5 -2
- package/src/modules/tool-auth/key-or-session.middleware.ts +45 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +16 -7
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +228 -0
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +33 -4
- package/src/modules/tool-helpers/tool-context.ts +46 -7
- package/src/modules/tool-helpers/tool-handler.ts +23 -5
- package/src/modules/tool-helpers/tool.contract.ts +5 -0
- package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +411 -0
- package/src/modules/tool-manuals/__tests__/tool-delete.route.test.ts +133 -0
- package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +469 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +21 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +9 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +6 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +254 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +577 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +6 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.pending.route.test.ts +102 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +285 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +178 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +114 -2
- package/src/modules/tool-manuals/index.ts +3 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +13 -10
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +11 -14
- package/src/modules/tool-manuals/pending-tools.service.ts +179 -0
- package/src/modules/tool-manuals/tool-delete.service.ts +401 -0
- package/src/modules/tool-manuals/tool-manuals.contract.ts +165 -0
- package/src/modules/tool-manuals/tool-manuals.routes.ts +138 -54
- package/src/modules/tool-manuals/tool-manuals.service.ts +432 -87
- package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -6
- package/src/modules/workflow/__tests__/apply-failure.test.ts +1038 -0
- package/src/modules/workflow/__tests__/event-bus.test.ts +61 -9
- package/src/modules/workflow/__tests__/fake-file-lock-db.ts +199 -0
- package/src/modules/workflow/__tests__/file-lock.service.path-identity.test.ts +237 -0
- package/src/modules/workflow/__tests__/format-affected-owners.test.ts +18 -0
- package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +220 -0
- package/src/modules/workflow/__tests__/pending-commits.worker.concurrency.test.ts +187 -0
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -0
- package/src/modules/workflow/__tests__/sanitize-error.test.ts +10 -0
- package/src/modules/workflow/__tests__/workflow.routes.folder-proposals.test.ts +128 -0
- package/src/modules/workflow/__tests__/workflow.routes.fork-point-file.test.ts +149 -0
- package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +305 -0
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +294 -25
- package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +564 -0
- package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +135 -0
- package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +172 -0
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +14 -0
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -0
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +281 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +158 -7
- package/src/modules/workflow/agent-tools/workflow.tools.ts +93 -64
- package/src/modules/workflow/event-bus.ts +26 -28
- package/src/modules/workflow/events.routes.ts +56 -21
- package/src/modules/workflow/file-lock.service.ts +27 -4
- package/src/modules/workflow/git/__tests__/change-request-link.test.ts +43 -0
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +1 -0
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +238 -1
- package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +245 -0
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +35 -0
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +149 -0
- package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +177 -0
- package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +114 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +69 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +121 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +79 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-update.test.ts +111 -0
- package/src/modules/workflow/git/change-request-link.ts +35 -0
- package/src/modules/workflow/git/git-version.ts +5 -2
- package/src/modules/workflow/git/git.service.ts +684 -144
- package/src/modules/workflow/git/node-git-runner.ts +315 -0
- package/src/modules/workflow/git/pull-request.service.ts +179 -27
- package/src/modules/workflow/pending-commits.service.ts +26 -7
- package/src/modules/workflow/pending-commits.worker.ts +114 -69
- package/src/modules/workflow/recovery-bot.ts +4 -1
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +180 -1
- package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
- package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +520 -0
- package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +84 -0
- package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +89 -77
- package/src/modules/workflow/review-workflow/approval-lock.ts +122 -0
- package/src/modules/workflow/review-workflow/review-workflow.interface.ts +59 -7
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +309 -105
- package/src/modules/workflow/sanitize-error.ts +9 -4
- package/src/modules/workflow/workflow.routes.ts +273 -29
- package/src/modules/workflow/workflow.service.ts +1087 -171
- package/src/modules/workspace/__tests__/empty-dirs.test.ts +44 -0
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +301 -0
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +792 -0
- package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +464 -0
- package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +139 -0
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +189 -37
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +51 -11
- package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +161 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +109 -10
- package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +624 -0
- package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +409 -0
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +327 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +25 -6
- package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +109 -0
- package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
- package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +218 -0
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +56 -1
- package/src/modules/workspace/__tests__/workspace.service.test.ts +811 -42
- package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +197 -0
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +128 -0
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +212 -0
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +2632 -110
- package/src/modules/workspace/__tests__/write-denial.test.ts +75 -0
- package/src/modules/workspace/empty-dirs.ts +79 -0
- package/src/modules/workspace/file-readers/README.md +32 -0
- package/src/modules/workspace/file-readers/__tests__/doc-extract.test.ts +59 -2
- package/src/modules/workspace/file-readers/__tests__/file-reader.registry.test.ts +133 -4
- package/src/modules/workspace/file-readers/__tests__/fixtures/soft-break.docx +0 -0
- package/src/modules/workspace/file-readers/__tests__/fixtures/tab.docx +0 -0
- package/src/modules/workspace/file-readers/content-mode.ts +87 -0
- package/src/modules/workspace/file-readers/doc-extract.service.ts +4 -1
- package/src/modules/workspace/file-readers/doc-extract.types.ts +8 -4
- package/src/modules/workspace/file-readers/document-reader.ts +6 -0
- package/src/modules/workspace/file-readers/extract-docx.ts +6 -0
- package/src/modules/workspace/file-readers/file-reader.registry.ts +9 -1
- package/src/modules/workspace/file-readers/file-reader.ts +27 -6
- package/src/modules/workspace/file-readers/image-reader.ts +10 -5
- package/src/modules/workspace/file-readers/ooxml-text.ts +38 -2
- package/src/modules/workspace/file-readers/text-reader.ts +61 -4
- package/src/modules/workspace/git-internals.middleware.ts +86 -0
- package/src/modules/workspace/not-found.ts +119 -0
- package/src/modules/workspace/session-ontology.gate.ts +1 -1
- package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +181 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +361 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +53 -16
- package/src/modules/workspace/startup/beside-checkout.ts +112 -0
- package/src/modules/workspace/startup/kb-git.ts +43 -36
- package/src/modules/workspace/startup/kb-startup-runner.ts +303 -63
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +1215 -73
- package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +460 -417
- package/src/modules/workspace/startup/steps/personal-spaces.step.ts +191 -0
- package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +169 -0
- package/src/modules/workspace/startup/steps/plugin-layout.ts +110 -0
- package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +46 -85
- package/src/modules/workspace/startup/steps/roles-yaml.step.ts +6 -12
- package/src/modules/workspace/startup/steps/seed-tree.ts +159 -78
- package/src/modules/workspace/startup/steps/template-files.step.ts +492 -141
- package/src/modules/workspace/startup/steps/template-source.ts +168 -0
- package/src/modules/workspace/workspace.routes.ts +687 -257
- package/src/modules/workspace/workspace.service.ts +991 -303
- package/src/modules/workspace/workspace.tools.ts +1787 -180
- package/src/modules/workspace/write-denial.ts +189 -0
- package/src/shared/__tests__/canonical-file-identity.test.ts +154 -0
- package/src/shared/__tests__/email-identity.test.ts +35 -0
- package/src/shared/__tests__/filename.test.ts +0 -0
- package/src/shared/__tests__/frontmatter-id.test.ts +5 -0
- package/src/shared/__tests__/git-failure.test.ts +198 -0
- package/src/shared/__tests__/git-internals.test.ts +115 -0
- package/src/shared/__tests__/http-errors.test.ts +42 -0
- package/src/shared/__tests__/logging.test.ts +185 -0
- package/src/shared/__tests__/path-containment.test.ts +60 -0
- package/src/shared/__tests__/pending-proposals.readAt.test.ts +102 -0
- package/src/shared/__tests__/printable.test.ts +64 -0
- package/src/shared/__tests__/redact-secret.test.ts +122 -0
- package/src/shared/__tests__/rename-no-replace.test.ts +466 -0
- package/src/shared/__tests__/ssrf.test.ts +20 -0
- package/src/shared/canonical-file-identity.ts +92 -0
- package/src/shared/domain-errors.ts +149 -0
- package/src/shared/email-identity.ts +38 -0
- package/src/shared/fs.contract.ts +225 -0
- package/src/shared/git-failure.ts +196 -0
- package/src/shared/git-internals.ts +124 -0
- package/src/shared/git.contract.ts +170 -0
- package/src/shared/http-errors.ts +36 -0
- package/src/shared/logger.contract.ts +141 -0
- package/src/shared/logging.ts +96 -0
- package/src/shared/path-containment.ts +34 -0
- package/src/shared/pending-proposals.ts +161 -0
- package/src/shared/printable.ts +68 -0
- package/src/shared/redact-secret.ts +118 -0
- package/src/shared/rename-no-replace.ts +386 -0
- package/src/shared/ssrf.ts +44 -16
- package/src/version.ts +10 -6
- package/src/modules/diff/diff-paths.ts +0 -9
- package/src/modules/mcp/__tests__/mcp-session-store.test.ts +0 -151
- package/src/modules/mcp/__tests__/mcp.routes.session.test.ts +0 -226
- package/src/modules/mcp/mcp-session-store.ts +0 -162
- package/src/shared/__tests__/fs-walk.test.ts +0 -63
- package/src/shared/__tests__/kb-walk.test.ts +0 -107
- package/src/shared/fs-errors.ts +0 -10
- package/src/shared/fs-walk.ts +0 -45
- package/src/shared/hash-email.ts +0 -14
- package/src/shared/kb-walk.ts +0 -95
|
@@ -1,30 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { logger } from '../../shared/logging.js';
|
|
3
|
+
const log = logger('mcp');
|
|
2
4
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
-
import {
|
|
4
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, McpError, ErrorCode, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, McpError, ErrorCode, isInitializeRequest, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
6
|
import '@utcp/http'; // side effect: registers the 'http' UTCP communication protocol
|
|
6
7
|
import '@utcp/mcp'; // side effect: registers the 'mcp' protocol (native MCP-server `.tool` sources)
|
|
7
|
-
import { UtcpClientConfigSerializer, CallTemplateSerializer, } from '@utcp/sdk';
|
|
8
|
+
import { UtcpClientConfigSerializer, CallTemplateSerializer, UtcpManualSchema, } from '@utcp/sdk';
|
|
8
9
|
import { CodeModeUtcpClient } from '@utcp/code-mode';
|
|
9
|
-
import { CODE_MODE_META_TOOLS, META_TOOL_NAMES, dispatchMetaTool, dispatchToolCall, registerManual, flattenManualTool, toListedTool, toolError, needsAuthorizationResult, skillPromptText, } from '@bevel-software/platform-mcp-core';
|
|
10
|
+
import { CODE_MODE_META_TOOLS, META_TOOL_NAMES, dispatchMetaTool, dispatchToolCall, registerManual, installSessionRecovery, flattenManualTool, toListedTool, toolError, retiredToolMessage, needsAuthorizationResult, skillPromptText, } from '@bevel-software/platform-mcp-core';
|
|
10
11
|
import { bevelSecretsLoaderConfig } from '../secrets-vault/index.js';
|
|
11
|
-
import { scopesCovered } from '../secrets-vault/secrets-vault.contract.js';
|
|
12
|
+
import { scopesCovered, } from '../secrets-vault/secrets-vault.contract.js';
|
|
12
13
|
import { EXTERNAL_KB_MANUAL_NAME } from '../tool-manuals/tool-manuals.contract.js';
|
|
13
14
|
import { seedBevelHostedManualVars } from '../../shared/utcp-namespace.js';
|
|
14
15
|
import { ManualFailureMemo } from './manual-failure-memo.js';
|
|
16
|
+
import { DownstreamPool, POOL_KEY_SEPARATOR } from './downstream-pool.js';
|
|
17
|
+
import { SurfaceLogThrottle } from './surface-log-throttle.js';
|
|
18
|
+
import { DownstreamRefreshGuard, isDownstreamTokenRejection } from './downstream-token-refresh.js';
|
|
19
|
+
import { printable } from '../../shared/printable.js';
|
|
20
|
+
import { composeAgentInstructions, prefixToolDescription, PREFIXED_TOOLS, } from '../agent-instructions/index.js';
|
|
15
21
|
/**
|
|
16
22
|
* Upper bound on one `loopbackJson` round-trip (manual list, skill fetch) so a
|
|
17
|
-
* hung loopback can't stall
|
|
18
|
-
*
|
|
23
|
+
* hung loopback can't stall a request. Generous: these endpoints answer in
|
|
24
|
+
* milliseconds; only a wedged process ever comes near it.
|
|
19
25
|
*/
|
|
20
26
|
const LOOPBACK_TIMEOUT_MS = 15_000;
|
|
21
27
|
/**
|
|
22
|
-
* Lifetime of the internal token minted as an OAuth/JWT
|
|
23
|
-
* bearer.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* session CAN outlive it — its tool calls then fail at the loopback and the
|
|
27
|
-
* client recovers by re-initializing, which mints a fresh token.
|
|
28
|
+
* Lifetime of the internal token minted as an OAuth/JWT request's loopback
|
|
29
|
+
* bearer. A request only needs it for as long as it runs, but one `tools/call`
|
|
30
|
+
* can legitimately run for a long time (`ask`, a long `call_tool_chain`), so
|
|
31
|
+
* the lifetime is generous rather than tight.
|
|
28
32
|
*
|
|
29
33
|
* Exported because `POST /api/mcp/local-token` (mcp.routes.ts) performs the
|
|
30
34
|
* same OAuth-access-token → internal-token exchange for the LOCAL MCP server,
|
|
@@ -33,133 +37,189 @@ const LOOPBACK_TIMEOUT_MS = 15_000;
|
|
|
33
37
|
*/
|
|
34
38
|
export const MCP_LOOPBACK_TOKEN_TTL_MS = 5 * 60 * 60 * 1000;
|
|
35
39
|
const callTemplateSerializer = new CallTemplateSerializer();
|
|
40
|
+
/** The {@link DownstreamRoute.afterFailure} answer that means "refreshed — retry once". */
|
|
41
|
+
const RETRY_WITH_REFRESHED_TOKEN = Symbol('retry-with-refreshed-token');
|
|
36
42
|
/**
|
|
37
|
-
* The MCP server is a GENERIC proxy over the UTCP tool surface. It
|
|
38
|
-
* logic
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
+
* The MCP server is a GENERIC, STATELESS proxy over the UTCP tool surface. It
|
|
44
|
+
* owns no tool logic and no session: every HTTP request gets its own MCP
|
|
45
|
+
* `Server`, built from that request's bearer. When the request needs tools it
|
|
46
|
+
* stands up a `UtcpClient` pointed at the backend's own `GET /api/agent/all-tools`
|
|
47
|
+
* catalog (over loopback, authenticated as the caller, so ACL filtering lives
|
|
48
|
+
* ONCE behind the REST surface), discovers every tool, and re-exposes each one
|
|
49
|
+
* to the MCP client. A tool call is dispatched straight back through the same
|
|
50
|
+
* REST endpoint the tool's UTCP `tool_call_template` names — so the agent logic,
|
|
43
51
|
* thread continuity, and per-key token metering all live ONCE behind that REST
|
|
44
52
|
* endpoint (`AgentAskService` for `ask`), never duplicated here.
|
|
45
53
|
*
|
|
54
|
+
* Because nothing is held between requests, a platform restart between two
|
|
55
|
+
* requests of one client conversation is undetectable by the client.
|
|
56
|
+
*
|
|
57
|
+
* There is NO catalog cache at this layer, deliberately: the catalog is
|
|
58
|
+
* re-derived per request, and if that ever proves too slow the fix belongs in
|
|
59
|
+
* the source path (all-tools/ACL), which serves every other caller too.
|
|
60
|
+
*
|
|
61
|
+
* The one exception to "nothing between requests" is proxied third-party MCP
|
|
62
|
+
* servers (`mcp` manuals): those are session-ful by nature, so their
|
|
63
|
+
* connections live in a {@link DownstreamPool} keyed by (user, manual) — lazy,
|
|
64
|
+
* single-flight, idle-evicted, bounded, and healed by session recovery. Losing
|
|
65
|
+
* any of it costs a reconnect, never correctness.
|
|
66
|
+
*
|
|
46
67
|
* Dispatch always uses `callToolStreaming`, which is uniform across tool kinds:
|
|
47
68
|
* a plain `http` tool yields exactly one chunk (its final result, emitted as
|
|
48
69
|
* the tool result with no progress), while a `streamable_http` tool yields many
|
|
49
|
-
* (the all-but-last become `notifications/progress
|
|
50
|
-
*
|
|
51
|
-
* touches this file.
|
|
70
|
+
* (the all-but-last become `notifications/progress` on the request's own
|
|
71
|
+
* response stream, the last is the result).
|
|
52
72
|
*
|
|
53
73
|
* Auth note: `/api/agent/*` accepts connection keys and internal tokens only.
|
|
54
|
-
* Connection-key
|
|
55
|
-
* OAuth/JWT
|
|
56
|
-
*
|
|
57
|
-
*
|
|
74
|
+
* Connection-key requests pass the caller's own key through to the loopback;
|
|
75
|
+
* OAuth/JWT requests can't (their bearer would 401 there), so the proxy mints a
|
|
76
|
+
* least-privilege internal token for the resolved user and uses THAT as the
|
|
77
|
+
* request's loopback bearer instead.
|
|
58
78
|
*/
|
|
59
79
|
export class McpService {
|
|
60
|
-
sessionStore;
|
|
61
80
|
opts;
|
|
62
81
|
secretsVault;
|
|
63
82
|
toolManuals;
|
|
64
83
|
internalTokens;
|
|
65
84
|
revokeOAuthAccess;
|
|
66
85
|
// Circuit breaker for manuals whose credentials just failed — see the memo.
|
|
86
|
+
// Retry policy, not session state: it survives the move to statelessness.
|
|
67
87
|
manualFailures = new ManualFailureMemo();
|
|
88
|
+
surfaceLog = new SurfaceLogThrottle();
|
|
89
|
+
// One forced token refresh per (user, manual) per minute — see downstream-token-refresh.
|
|
90
|
+
tokenRefreshes;
|
|
68
91
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
92
|
+
* The tools each pooled manual last advertised, by manual definition. A
|
|
93
|
+
* downstream can only be asked what its tools are over a connection, and a
|
|
94
|
+
* caller whose sign-in is missing or broken has no connection — so their
|
|
95
|
+
* tools would silently vanish from the surface, and a call would answer
|
|
96
|
+
* "Unknown tool" instead of "sign in again on /connect". These definitions
|
|
97
|
+
* keep the manual on the surface for such a caller; the call-time credential
|
|
98
|
+
* check then answers with the link, and an interactive client is sent back
|
|
99
|
+
* through authorization. Definitions, never credentials or results. Keyed
|
|
100
|
+
* by catalog name — one entry per manual, replaced when the manual is next
|
|
101
|
+
* discovered — and used only while the manual's definition is the one the
|
|
102
|
+
* tools were discovered from, so an edited `mcp.json` never serves the old
|
|
103
|
+
* server's tools.
|
|
72
104
|
*/
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.manualFailures.clearUser(userId);
|
|
78
|
-
}
|
|
79
|
-
constructor(sessionStore, opts,
|
|
105
|
+
knownDownstreamTools = new Map();
|
|
106
|
+
// The downstream connection pool for `mcp` manuals — see the class doc.
|
|
107
|
+
downstream;
|
|
108
|
+
constructor(opts,
|
|
80
109
|
// The vault + manual catalog, used to check a caller's per-user credentials
|
|
81
110
|
// before dispatching a tool. Optional so existing constructions/tests that
|
|
82
111
|
// don't exercise the check keep working (the check is skipped when absent).
|
|
83
112
|
secretsVault, toolManuals,
|
|
84
|
-
// Mints the loopback bearer for OAuth/JWT
|
|
85
|
-
// Optional for the same test-compat reason; without it those
|
|
113
|
+
// Mints the loopback bearer for OAuth/JWT requests (see class doc).
|
|
114
|
+
// Optional for the same test-compat reason; without it those requests
|
|
86
115
|
// fall back to the old pass-through (and 401 at the loopback hop).
|
|
87
116
|
internalTokens,
|
|
88
117
|
// Revokes an MCP OAuth access token (BevelOAuthProvider.revokeByAccessToken)
|
|
89
|
-
// — the reset that sends an interactive
|
|
118
|
+
// — the reset that sends an interactive client back through the browser
|
|
90
119
|
// authorization when one of its TOOL sign-ins breaks. Optional: without
|
|
91
120
|
// it, broken sign-ins surface only as the /connect link in the result.
|
|
92
121
|
revokeOAuthAccess) {
|
|
93
|
-
this.sessionStore = sessionStore;
|
|
94
122
|
this.opts = opts;
|
|
95
123
|
this.secretsVault = secretsVault;
|
|
96
124
|
this.toolManuals = toolManuals;
|
|
97
125
|
this.internalTokens = internalTokens;
|
|
98
126
|
this.revokeOAuthAccess = revokeOAuthAccess;
|
|
127
|
+
this.downstream = new DownstreamPool({
|
|
128
|
+
...opts.downstreamPool,
|
|
129
|
+
// Since @utcp/sdk 1.2.0 a client closes only the protocol instances it
|
|
130
|
+
// created, and @utcp/mcp registers as a factory — so this closes exactly
|
|
131
|
+
// this entry's MCP sessions and touches no other client's.
|
|
132
|
+
dispose: (entry) => entry.client.close(),
|
|
133
|
+
});
|
|
134
|
+
// Paced on the pool's clock, so a test that moves one moves both.
|
|
135
|
+
this.tokenRefreshes = new DownstreamRefreshGuard(undefined, opts.downstreamPool?.now);
|
|
99
136
|
}
|
|
100
137
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
138
|
+
* A secret changed — wired to the secrets vault's mutation listener.
|
|
139
|
+
* `null` = a shared secret changed (affects everyone).
|
|
140
|
+
*
|
|
141
|
+
* Two things were built from the old value: remembered manual failures (so a
|
|
142
|
+
* just-repaired credential is retried on the very next request) and pooled
|
|
143
|
+
* downstream connections (dialed and discovered with the old credential).
|
|
144
|
+
* Both are dropped; the next request rebuilds whatever it needs.
|
|
103
145
|
*/
|
|
104
|
-
|
|
105
|
-
|
|
146
|
+
onSecretsChanged(userId) {
|
|
147
|
+
this.forgetStaleRefreshWindows(userId);
|
|
148
|
+
if (userId === null) {
|
|
149
|
+
this.manualFailures.clearAll();
|
|
150
|
+
this.downstream.closeAll();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.manualFailures.clearUser(userId);
|
|
154
|
+
this.downstream.evictWhere((key) => key.startsWith(`${userId}${POOL_KEY_SEPARATOR}`));
|
|
106
155
|
}
|
|
107
156
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
157
|
+
* A credential changed, so a refresh window that FAILED to produce one no
|
|
158
|
+
* longer describes anything: a token the user has just re-authorized (or an
|
|
159
|
+
* admin has just re-keyed) must be tried on the very next rejection, not sit
|
|
160
|
+
* out the remainder of a minute earned by the credential it replaced.
|
|
161
|
+
*
|
|
162
|
+
* Only settled, non-`refreshed` windows are forgotten. A refresh of our own
|
|
163
|
+
* is itself a secrets mutation, and clearing on that would hand a provider
|
|
164
|
+
* that keeps minting tokens the downstream keeps refusing one refresh per
|
|
165
|
+
* call — precisely the loop the once-a-minute guard exists to bound. An
|
|
166
|
+
* in-flight attempt (no outcome yet) is left alone for the same reason: it
|
|
167
|
+
* may be the very refresh that raised this notification.
|
|
112
168
|
*/
|
|
113
|
-
|
|
169
|
+
forgetStaleRefreshWindows(userId) {
|
|
170
|
+
const mine = (key) => userId === null || key.startsWith(`${userId}${POOL_KEY_SEPARATOR}`);
|
|
171
|
+
this.tokenRefreshes.clearWhere((key, outcome) => mine(key) && outcome !== undefined && outcome !== 'refreshed');
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Build the MCP `Server` for ONE request. The route connects it to a fresh
|
|
175
|
+
* stateless transport, lets it answer, and closes both with the response.
|
|
176
|
+
*
|
|
177
|
+
* Cheap by construction: nothing is fetched up front except what the
|
|
178
|
+
* request's own messages need. The agent instructions are read only when the
|
|
179
|
+
* request carries an `initialize` (the only place they ride); the tool
|
|
180
|
+
* catalog is built on the first handler that needs it and shared by every
|
|
181
|
+
* message of the request (a JSON-RPC batch), never beyond it.
|
|
182
|
+
*/
|
|
183
|
+
async createRequestServer(caller, messages) {
|
|
184
|
+
const { userId, tokenId, bearer } = caller;
|
|
114
185
|
// The loopback surface (`/api/agent/*`) accepts connection keys and
|
|
115
|
-
// internal tokens only. A connection-key
|
|
116
|
-
// key through (per-key metering rides on it); an OAuth/JWT
|
|
186
|
+
// internal tokens only. A connection-key request passes the caller's own
|
|
187
|
+
// key through (per-key metering rides on it); an OAuth/JWT request's
|
|
117
188
|
// bearer would 401 there, so mint a least-privilege internal token for
|
|
118
189
|
// the resolved user instead — flagged `externalProxy` so the tool-auth
|
|
119
190
|
// verifier resolves it to `source: 'external'`: the caller IS an external
|
|
120
191
|
// agent and must be treated like one (admitted to `start_session`/`ask`,
|
|
121
|
-
// refused from internal-only tools).
|
|
122
|
-
// idle eviction — an evicted session re-initializes and re-mints.
|
|
192
|
+
// refused from internal-only tools).
|
|
123
193
|
const loopbackBearer = tokenId == null && this.internalTokens
|
|
124
194
|
? this.internalTokens.mint({ userId, externalProxy: true }, MCP_LOOPBACK_TOKEN_TTL_MS)
|
|
125
195
|
: bearer;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
`discovered ${tools.length} tool(s) across ${manuals.length} manual(s)`);
|
|
137
|
-
const transport = new StreamableHTTPServerTransport({
|
|
138
|
-
sessionIdGenerator: () => randomUUID(),
|
|
139
|
-
onsessioninitialized: (sessionId) => {
|
|
140
|
-
this.sessionStore.create(sessionId, userId, tokenId);
|
|
141
|
-
onSessionInitialized(sessionId);
|
|
142
|
-
},
|
|
143
|
-
onsessionclosed: (sessionId) => {
|
|
144
|
-
this.sessionStore.delete(sessionId);
|
|
145
|
-
},
|
|
196
|
+
let instructions;
|
|
197
|
+
const agentInstructions = () => (instructions ??= this.composeAgentInstructions());
|
|
198
|
+
let surface;
|
|
199
|
+
const requestSurface = () => (surface ??= this.buildSurface(userId, tokenId, loopbackBearer));
|
|
200
|
+
const initializing = (Array.isArray(messages) ? messages : [messages]).some((m) => isInitializeRequest(m));
|
|
201
|
+
const server = new Server({ name: 'bevel-mcp', version: '0.1.0' }, {
|
|
202
|
+
capabilities: { tools: {}, prompts: {} },
|
|
203
|
+
// `instructions` rides the initialize result; clients that honour it
|
|
204
|
+
// place the text in the model's system prompt without the model acting.
|
|
205
|
+
...(initializing ? { instructions: (await agentInstructions()).instructions } : {}),
|
|
146
206
|
});
|
|
147
|
-
const server = new Server({ name: 'bevel-mcp', version: '0.1.0' }, { capabilities: { tools: {}, prompts: {} } });
|
|
148
207
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
208
|
+
const [{ tools, catalogNames }, { toolPrefix }] = await Promise.all([requestSurface(), agentInstructions()]);
|
|
149
209
|
// A discovered tool whose name collides with a meta-tool would be
|
|
150
210
|
// listed but never callable (the dispatcher routes the name to the
|
|
151
211
|
// meta-tool first), so drop it from the listing entirely.
|
|
152
212
|
let listed = tools.filter((t) => !META_TOOL_NAMES.has(t.mcpName));
|
|
153
|
-
// Connection-key
|
|
213
|
+
// Connection-key callers are autonomous pipelines — nobody is present
|
|
154
214
|
// to complete a sign-in mid-run, so register ONLY the tools whose
|
|
155
215
|
// per-user credentials are already satisfied. Interactive (OAuth/JWT)
|
|
156
|
-
//
|
|
216
|
+
// callers keep the full listing: they can configure a tool on
|
|
157
217
|
// /connect when the call-time check points them there.
|
|
158
218
|
if (tokenId != null) {
|
|
159
219
|
const ready = await Promise.all(
|
|
160
220
|
// A per-tool check that throws must NOT reject the whole list (which
|
|
161
221
|
// would blank every tool) — fail that one tool closed and move on.
|
|
162
|
-
listed.map((t) => this.missingUserSecrets(userId, t).then((missing) => missing.length === 0, () => false)));
|
|
222
|
+
listed.map((t) => this.missingUserSecrets(userId, catalogNames.get(t.manualName) ?? t.manualName).then((missing) => missing.length === 0, () => false)));
|
|
163
223
|
listed = listed.filter((_, i) => ready[i]);
|
|
164
224
|
}
|
|
165
225
|
// Validate + dedupe each discovered tool so ONE non-conforming or
|
|
@@ -180,14 +240,20 @@ export class McpService {
|
|
|
180
240
|
continue;
|
|
181
241
|
}
|
|
182
242
|
seen.add(entry.name);
|
|
183
|
-
|
|
243
|
+
// The four knowledge-base tools carry the purpose prefix: the one
|
|
244
|
+
// pre-call channel every client shows the model, for the clients that
|
|
245
|
+
// drop the handshake's `instructions`. Applied AFTER the credential
|
|
246
|
+
// filter above, so a connection-key caller's listing carries it too.
|
|
247
|
+
// Every other tool, meta-tools included, keeps its description as is.
|
|
248
|
+
direct.push(PREFIXED_TOOLS.has(entry.name)
|
|
249
|
+
? { ...entry, description: prefixToolDescription(toolPrefix, entry.description) }
|
|
250
|
+
: entry);
|
|
184
251
|
}
|
|
185
252
|
// Log only when a tool was dropped (name/schema/duplicate) — that's the
|
|
186
253
|
// anomaly worth surfacing, since a downstream client would otherwise hide
|
|
187
|
-
// it by rejecting the whole response.
|
|
188
|
-
// already visible once per session in the createSession log above.
|
|
254
|
+
// it by rejecting the whole response.
|
|
189
255
|
if (dropped.length) {
|
|
190
|
-
|
|
256
|
+
log.warn(`tools/list: serving ${CODE_MODE_META_TOOLS.length + direct.length} tool(s); ` +
|
|
191
257
|
`dropped ${dropped.length} non-listable: ${dropped.join(', ')}`);
|
|
192
258
|
}
|
|
193
259
|
return {
|
|
@@ -196,44 +262,66 @@ export class McpService {
|
|
|
196
262
|
};
|
|
197
263
|
});
|
|
198
264
|
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
199
|
-
|
|
200
|
-
|
|
265
|
+
const { client, tools, unavailable, catalogNames } = await requestSurface();
|
|
266
|
+
const toolName = request.params.name;
|
|
267
|
+
if (META_TOOL_NAMES.has(toolName)) {
|
|
268
|
+
return this.dispatchMetaTool(client, toolName, request.params.arguments ?? {});
|
|
201
269
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
270
|
+
/**
|
|
271
|
+
* The needs-authorization answer, when the caller's sign-in for the
|
|
272
|
+
* manual registered as `utcpName` is missing or broken; `null` to
|
|
273
|
+
* proceed. Stops before running a tool whose personal (user-scoped)
|
|
274
|
+
* credentials the caller hasn't provided — a setup link instead of a
|
|
275
|
+
* blank-credential request that would fail opaquely at the provider.
|
|
276
|
+
* The credential catalog keys manuals by their CATALOG name; a tool
|
|
277
|
+
* carries the registered (rewritten) one, so it is translated back.
|
|
278
|
+
*/
|
|
279
|
+
const needsAuthorization = async (utcpName) => {
|
|
280
|
+
const needsAuth = await this.checkUserSecrets(userId, toolName, catalogNames.get(utcpName) ?? utcpName);
|
|
281
|
+
if (!needsAuth)
|
|
282
|
+
return null;
|
|
211
283
|
// A sign-in that EXISTS but is broken (expired grant, abandoned
|
|
212
|
-
// consent, missing scopes) on an interactive OAuth
|
|
284
|
+
// consent, missing scopes) on an interactive OAuth caller: revoke the
|
|
213
285
|
// agent's own grant too. Its next request then 401s, its refresh
|
|
214
286
|
// fails, and it re-runs the browser authorization — landing the user
|
|
215
287
|
// on /connect where the broken sign-in shows as not-connected, to
|
|
216
288
|
// re-authorize or deselect. Never-configured tools keep the plain
|
|
217
289
|
// link (revoking for those would loop on every poke at a tool the
|
|
218
|
-
// user simply hasn't set up). Connection-key
|
|
290
|
+
// user simply hasn't set up). Connection-key callers have no grant
|
|
219
291
|
// to reset; the revoke no-ops on non-OAuth bearers anyway.
|
|
220
292
|
if (needsAuth.brokenSignIn && tokenId == null && this.revokeOAuthAccess) {
|
|
221
293
|
try {
|
|
222
294
|
await this.revokeOAuthAccess(bearer);
|
|
223
295
|
}
|
|
224
296
|
catch (err) {
|
|
225
|
-
|
|
297
|
+
log.warn('failed to reset the caller grant for re-auth:', { err });
|
|
226
298
|
}
|
|
227
299
|
}
|
|
228
300
|
return needsAuth.result;
|
|
301
|
+
};
|
|
302
|
+
const proxied = tools.find((t) => t.mcpName === toolName);
|
|
303
|
+
if (!proxied) {
|
|
304
|
+
// Not on the surface — but if the name belongs to a manual that is off
|
|
305
|
+
// it only because this caller's sign-in is gone (and nothing in this
|
|
306
|
+
// process has seen its tools yet), the honest answer is the sign-in
|
|
307
|
+
// link, exactly as if the tool were listed. Longest matching prefix:
|
|
308
|
+
// manual names may themselves contain underscores.
|
|
309
|
+
const owner = unavailable
|
|
310
|
+
.filter((m) => toolName.startsWith(`${m.utcpName}_`))
|
|
311
|
+
.sort((a, b) => b.utcpName.length - a.utcpName.length)[0];
|
|
312
|
+
const answer = owner ? await needsAuthorization(owner.utcpName) : null;
|
|
313
|
+
return answer ?? toolError(retiredToolMessage(toolName) ?? `Unknown tool "${toolName}".`);
|
|
229
314
|
}
|
|
315
|
+
const needsAuth = await needsAuthorization(proxied.manualName);
|
|
316
|
+
if (needsAuth)
|
|
317
|
+
return needsAuth;
|
|
230
318
|
return this.dispatch(client, proxied, request, extra);
|
|
231
319
|
});
|
|
232
320
|
// Prompts = skills. Each skill becomes a user-callable prompt (slash command
|
|
233
321
|
// in MCP clients). Backed by the same skill endpoints the tools use, over
|
|
234
322
|
// loopback with the caller's key — so the default-branch catalog, access
|
|
235
323
|
// filtering, and progressive disclosure all live ONCE behind that REST
|
|
236
|
-
// surface, never duplicated here.
|
|
324
|
+
// surface, never duplicated here. Neither handler needs the tool catalog.
|
|
237
325
|
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
238
326
|
const skills = await this.fetchSkillList(loopbackBearer);
|
|
239
327
|
const prompts = skills.map((s) => ({
|
|
@@ -253,7 +341,57 @@ export class McpService {
|
|
|
253
341
|
messages: [{ role: 'user', content: { type: 'text', text: skillPromptText(skill) } }],
|
|
254
342
|
};
|
|
255
343
|
});
|
|
256
|
-
return
|
|
344
|
+
return server;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* The request's tool surface: catalog over loopback, a fresh UTCP client,
|
|
348
|
+
* every manual registered (pooled for `mcp` ones), tools flattened.
|
|
349
|
+
*
|
|
350
|
+
* Logs one line with the time each half took — the per-request overhead
|
|
351
|
+
* the stateless design trades for restart-invisibility, kept visible so it
|
|
352
|
+
* is measured rather than assumed.
|
|
353
|
+
*/
|
|
354
|
+
async buildSurface(userId, tokenId, loopbackBearer) {
|
|
355
|
+
const started = performance.now();
|
|
356
|
+
// The list of manuals this caller gets: the KB manual + each `.tool` they
|
|
357
|
+
// can read. Fetched over loopback with the caller's key, so ACL filtering
|
|
358
|
+
// lives ONCE behind the REST surface.
|
|
359
|
+
const manuals = await this.fetchManualTemplates(loopbackBearer);
|
|
360
|
+
const catalogMs = performance.now() - started;
|
|
361
|
+
const client = await this.buildClient(loopbackBearer, userId, manuals);
|
|
362
|
+
const { tools, unavailable, catalogNames } = await this.discoverTools(client, manuals, userId);
|
|
363
|
+
const totalMs = performance.now() - started;
|
|
364
|
+
// Per user: on a shape change or once per interval, never per request —
|
|
365
|
+
// see SurfaceLogThrottle for why both halves matter.
|
|
366
|
+
const decision = this.surfaceLog.decide(userId, { tools: tools.length, manuals: manuals.length });
|
|
367
|
+
if (decision.log) {
|
|
368
|
+
log.info(
|
|
369
|
+
// Both ids come from the request (an identity provider's subject, a
|
|
370
|
+
// connection key's id), so neither is interpolated raw — see printable.
|
|
371
|
+
`request surface: user=${printable(userId)} tokenId=${tokenId ? printable(tokenId) : 'none'} — ` +
|
|
372
|
+
`${tools.length} tool(s) across ${manuals.length} manual(s) in ${totalMs.toFixed(0)}ms ` +
|
|
373
|
+
`(catalog ${catalogMs.toFixed(0)}ms, registration ${(totalMs - catalogMs).toFixed(0)}ms)` +
|
|
374
|
+
(decision.suppressed > 0 ? ` [+${decision.suppressed} identical rebuild(s) since last line]` : ''));
|
|
375
|
+
}
|
|
376
|
+
return { client, tools, unavailable, catalogNames };
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* The instructions and tool prefix. A reader failure (a disk fault; ENOENT
|
|
380
|
+
* is not one, the reader answers null for that) falls back to the header
|
|
381
|
+
* alone and the fixed prefix line with a logged warning: a request never
|
|
382
|
+
* fails over its preamble.
|
|
383
|
+
*/
|
|
384
|
+
async composeAgentInstructions() {
|
|
385
|
+
const read = this.opts.readAgentPreamble;
|
|
386
|
+
if (!read)
|
|
387
|
+
return composeAgentInstructions(null);
|
|
388
|
+
try {
|
|
389
|
+
return composeAgentInstructions(await read());
|
|
390
|
+
}
|
|
391
|
+
catch (err) {
|
|
392
|
+
log.warn('could not read mcp-description.md; this request gets the platform header alone:', { err });
|
|
393
|
+
return composeAgentInstructions(null);
|
|
394
|
+
}
|
|
257
395
|
}
|
|
258
396
|
/** Loopback GET of the default-branch skill catalog (via the `list_skills` tool). */
|
|
259
397
|
async fetchSkillList(bearer) {
|
|
@@ -272,10 +410,9 @@ export class McpService {
|
|
|
272
410
|
* The ONE loopback round-trip: fetch `path` on our own REST surface with the
|
|
273
411
|
* caller's bearer, parse JSON. Failures are logged under `label` (never the
|
|
274
412
|
* bearer) and degrade to null — a loopback hiccup must not throw into the
|
|
275
|
-
* MCP
|
|
276
|
-
* Bounded: a hung loopback (e.g. mid-restart) must not block
|
|
277
|
-
*
|
|
278
|
-
* like any other failure.
|
|
413
|
+
* MCP request. GET when `json` is absent, POST with a JSON body when present.
|
|
414
|
+
* Bounded: a hung loopback (e.g. mid-restart) must not block a request
|
|
415
|
+
* indefinitely; a timeout aborts and degrades to null like any other failure.
|
|
279
416
|
*/
|
|
280
417
|
async loopbackJson(bearer, path, label, json) {
|
|
281
418
|
try {
|
|
@@ -288,13 +425,13 @@ export class McpService {
|
|
|
288
425
|
signal: AbortSignal.timeout(LOOPBACK_TIMEOUT_MS),
|
|
289
426
|
});
|
|
290
427
|
if (!res.ok) {
|
|
291
|
-
|
|
428
|
+
log.error(`${label} loopback failed: HTTP ${res.status} ${await res.text().catch(() => '')}`);
|
|
292
429
|
return null;
|
|
293
430
|
}
|
|
294
431
|
return await res.json();
|
|
295
432
|
}
|
|
296
433
|
catch (err) {
|
|
297
|
-
|
|
434
|
+
log.error(`${label} loopback threw:`, { err });
|
|
298
435
|
return null;
|
|
299
436
|
}
|
|
300
437
|
}
|
|
@@ -307,7 +444,7 @@ export class McpService {
|
|
|
307
444
|
* validated into `CallTemplate`s at the boundary. The KB manual is guaranteed
|
|
308
445
|
* present (a fallback covers an unavailable endpoint); a user manual that
|
|
309
446
|
* fails validation is dropped + logged so one bad `.tool` can't break the
|
|
310
|
-
*
|
|
447
|
+
* request. HTTP transport loses the `CallTemplate` type, so we re-validate the
|
|
311
448
|
* received JSON even though the producing endpoint already validated it.
|
|
312
449
|
*/
|
|
313
450
|
async fetchManualTemplates(bearer) {
|
|
@@ -328,7 +465,7 @@ export class McpService {
|
|
|
328
465
|
const name = String(raw?.name ?? '');
|
|
329
466
|
if (isKb)
|
|
330
467
|
throw err; // the KB manual must be valid — the core toolset depends on it
|
|
331
|
-
|
|
468
|
+
log.warn(`skipping manual "${name}": ${err instanceof Error ? err.message : String(err)}`);
|
|
332
469
|
}
|
|
333
470
|
}
|
|
334
471
|
// Always include the KB manual, even if `all-tools` was unavailable/regressed.
|
|
@@ -348,75 +485,360 @@ export class McpService {
|
|
|
348
485
|
});
|
|
349
486
|
}
|
|
350
487
|
/**
|
|
351
|
-
* One `CodeModeUtcpClient` per
|
|
488
|
+
* One `CodeModeUtcpClient` per request. Reserved `API_URL`/`CONNECTION_KEY` are
|
|
352
489
|
* seeded (namespaced) ONLY for Bevel-hosted manuals — the KB manual and inline
|
|
353
490
|
* `.tool` sub-manuals, whose discovery template targets the loopback (`${API_URL}`).
|
|
354
491
|
* Third-party http/mcp `.tool`s point at arbitrary user URLs, so we must NOT seed
|
|
355
492
|
* them the caller's bearer: a malicious `.tool` referencing `${CONNECTION_KEY}`
|
|
356
493
|
* would otherwise exfiltrate the caller's token to its own endpoint. Tool
|
|
357
494
|
* `${SECRET}` refs resolve lazily via the per-user `bevel-secrets` loader.
|
|
495
|
+
*
|
|
496
|
+
* Not `close()`d: a request's client holds no connection of its own (its
|
|
497
|
+
* `mcp` manuals route to the pool, so its own `mcp` protocol instance never
|
|
498
|
+
* opens a session), and dropping the reference is the whole teardown.
|
|
358
499
|
*/
|
|
359
500
|
async buildClient(bearer, userId, manuals) {
|
|
360
|
-
// Bevel-hosted manuals (KB + inline `.tool` sub-manuals, discovery url
|
|
361
|
-
// `${API_URL}/…`) get the loopback creds; third-party `.tool` URLs are never
|
|
362
|
-
// seeded so the bearer can't leak. Same rule the in-process agent factory uses.
|
|
363
501
|
const variables = seedBevelHostedManualVars(manuals, this.opts.loopbackBaseUrl, bearer);
|
|
364
|
-
|
|
365
|
-
variables,
|
|
366
|
-
load_variables_from: [bevelSecretsLoaderConfig(userId)],
|
|
367
|
-
});
|
|
368
|
-
return CodeModeUtcpClient.create(process.cwd(), config);
|
|
502
|
+
return CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, variables));
|
|
369
503
|
}
|
|
370
504
|
/**
|
|
371
|
-
* Register EVERY manual
|
|
372
|
-
* the proxy's advertised shape.
|
|
373
|
-
*
|
|
374
|
-
*
|
|
505
|
+
* Register EVERY manual for this request, then flatten each discovered tool
|
|
506
|
+
* into the proxy's advertised shape. Manuals register concurrently — they are
|
|
507
|
+
* independent, and a request pays for the slowest one rather than the sum. A
|
|
508
|
+
* failure registering a user `.tool` is isolated (logged + skipped) so one
|
|
509
|
+
* broken manual never breaks the request; the KB manual failing is fatal (the
|
|
510
|
+
* core toolset is unusable).
|
|
375
511
|
*
|
|
376
|
-
*
|
|
377
|
-
* {@link
|
|
378
|
-
*
|
|
379
|
-
*
|
|
512
|
+
* `mcp` manuals never dial from here: they are attached from the downstream
|
|
513
|
+
* pool (see {@link attachDownstream}).
|
|
514
|
+
*
|
|
515
|
+
* Failures are memoized per (user, manual definition) for a few minutes (see
|
|
516
|
+
* {@link ManualFailureMemo}): the catalog is rebuilt on every request, and a
|
|
517
|
+
* manual with a broken credential (expired OAuth, revoked key) would
|
|
518
|
+
* otherwise re-dial its provider on every single one. The definition's
|
|
519
|
+
* fingerprint is part of the key, so a manual edited after a failure (a
|
|
520
|
+
* corrected `mcp.json` URL) is tried on the very next request.
|
|
380
521
|
*/
|
|
381
522
|
async discoverTools(client, manuals, userId) {
|
|
523
|
+
const routes = new Map();
|
|
524
|
+
const unavailable = [];
|
|
525
|
+
const catalogNames = new Map();
|
|
526
|
+
for (const m of manuals) {
|
|
527
|
+
if (m.call_template_type === 'mcp')
|
|
528
|
+
catalogNames.set(utcpManualName(m), String(m.name));
|
|
529
|
+
}
|
|
530
|
+
// The shared layer rewrites every manual name (`[^\w]` → `_`) and tools
|
|
531
|
+
// route by the rewritten prefix, so two manuals whose names rewrite to one
|
|
532
|
+
// identifier would silently share it. Sequential registration used to
|
|
533
|
+
// throw "already registered" for the second; concurrent registration
|
|
534
|
+
// (below) would let both pass the shared layer's pre-check, one
|
|
535
|
+
// overwriting the other in the repository while `routes` kept whichever
|
|
536
|
+
// resolved last — tools/list from one server, tools/call to the other.
|
|
537
|
+
// Decided here, over the whole list, before anything is registered: every
|
|
538
|
+
// manual in a colliding group fails with a message naming the others. The
|
|
539
|
+
// KB manual always keeps its name — a `.tool` colliding with it fails,
|
|
540
|
+
// the KB manual does not.
|
|
541
|
+
const byRewrittenName = new Map();
|
|
382
542
|
for (const m of manuals) {
|
|
543
|
+
const rewritten = utcpManualName(m);
|
|
544
|
+
byRewrittenName.set(rewritten, [...(byRewrittenName.get(rewritten) ?? []), String(m.name)]);
|
|
545
|
+
}
|
|
546
|
+
const outcomes = await Promise.all(manuals.map(async (m) => {
|
|
383
547
|
const isKb = m.name === EXTERNAL_KB_MANUAL_NAME;
|
|
384
548
|
const name = String(m.name);
|
|
549
|
+
// Both taken before registration, which renames the template in place.
|
|
550
|
+
const rewritten = utcpManualName(m);
|
|
551
|
+
const siblings = (byRewrittenName.get(rewritten) ?? []).filter((s) => s !== name);
|
|
552
|
+
// A collision is a property of the LIST, not of this manual's
|
|
553
|
+
// definition, so the memo key carries the siblings: the moment one is
|
|
554
|
+
// renamed away, the key changes and the survivor is tried on the very
|
|
555
|
+
// next request instead of sitting out the memo's TTL.
|
|
556
|
+
const memoKey = `${name}${POOL_KEY_SEPARATOR}${templateFingerprint(m)}` +
|
|
557
|
+
(siblings.length > 0 ? `${POOL_KEY_SEPARATOR}collides:${[...siblings].sort().join(',')}` : '');
|
|
385
558
|
if (!isKb) {
|
|
386
|
-
const recent = this.manualFailures.recentFailure(userId,
|
|
559
|
+
const recent = this.manualFailures.recentFailure(userId, memoKey);
|
|
387
560
|
if (recent !== undefined) {
|
|
388
|
-
|
|
389
|
-
|
|
561
|
+
log.warn(`skipping manual "${name}" (recent failure, not retried): ${recent}`);
|
|
562
|
+
return { isKb, ok: true };
|
|
390
563
|
}
|
|
391
564
|
}
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
565
|
+
// Begun BEFORE the awaited attempt: if a secrets change (or a
|
|
566
|
+
// concurrent success of this same manual) clears the memo while
|
|
567
|
+
// registration is in flight, the stale failure must not resurrect an
|
|
568
|
+
// entry the clear removed.
|
|
569
|
+
const generation = this.manualFailures.beginAttempt();
|
|
570
|
+
try {
|
|
571
|
+
// Neither path throws: a discovery/network failure and a validation
|
|
572
|
+
// failure both come back as `{ ok: false }`, because the retry
|
|
573
|
+
// policy — this memo — is ours, not the shared layer's.
|
|
574
|
+
const result = !isKb && siblings.length > 0
|
|
575
|
+
? {
|
|
576
|
+
ok: false,
|
|
577
|
+
error: `manual name "${name}" rewrites to "${rewritten}", the same identifier as ` +
|
|
578
|
+
`${siblings.map((s) => `"${s}"`).join(', ')} — rename one; a colliding manual is not registered`,
|
|
579
|
+
}
|
|
580
|
+
: m.call_template_type === 'mcp'
|
|
581
|
+
? await this.attachDownstream(client, m, userId, routes)
|
|
582
|
+
: await registerManual(client, m);
|
|
583
|
+
if (!result.ok) {
|
|
584
|
+
if (isKb)
|
|
585
|
+
return { isKb, ok: false, error: result.error };
|
|
586
|
+
// A failure the manual may recover from on its own schedule (a
|
|
587
|
+
// token refresh that hasn't settled) is reported but NOT
|
|
588
|
+
// remembered: the memo's five minutes would outlast the refresh
|
|
589
|
+
// policy's one and hold the manual down after the provider is back.
|
|
590
|
+
if (!result.retryable)
|
|
591
|
+
this.manualFailures.recordFailure(userId, memoKey, result.error, generation);
|
|
592
|
+
if (result.signInMissing)
|
|
593
|
+
unavailable.push({ utcpName: rewritten });
|
|
594
|
+
log.warn(`skipping manual "${name}": ${result.error}`);
|
|
595
|
+
}
|
|
596
|
+
else if (!isKb) {
|
|
597
|
+
this.manualFailures.clear(userId, memoKey);
|
|
598
|
+
}
|
|
405
599
|
}
|
|
406
|
-
|
|
407
|
-
this.manualFailures.
|
|
600
|
+
finally {
|
|
601
|
+
this.manualFailures.endAttempt(generation);
|
|
408
602
|
}
|
|
409
|
-
|
|
603
|
+
return { isKb, ok: true };
|
|
604
|
+
}));
|
|
605
|
+
const kbFailure = outcomes.find((o) => o.isKb && !o.ok);
|
|
606
|
+
if (kbFailure && !kbFailure.ok)
|
|
607
|
+
throw new Error(`Bevel tool discovery failed: ${kbFailure.error}`);
|
|
608
|
+
if (routes.size > 0)
|
|
609
|
+
routeToDownstream(client, routes);
|
|
410
610
|
const utcpTools = await client.getTools();
|
|
411
|
-
return
|
|
611
|
+
return {
|
|
612
|
+
tools: utcpTools.map((tool) => flattenManualTool(tool, EXTERNAL_KB_MANUAL_NAME)),
|
|
613
|
+
unavailable,
|
|
614
|
+
catalogNames,
|
|
615
|
+
};
|
|
412
616
|
}
|
|
413
617
|
/**
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
618
|
+
* Make one `mcp` manual's tools part of this request's client, backed by the
|
|
619
|
+
* pooled connection for (user, manual).
|
|
620
|
+
*
|
|
621
|
+
* The pooled client's discovered tools are copied into the request client's
|
|
622
|
+
* repository — so `tools/list`, `list_tools`/`tools_info` and the TypeScript
|
|
623
|
+
* interfaces `call_tool_chain` generates all see them exactly as if they had
|
|
624
|
+
* been registered here — and `routes` records that calls to this manual go to
|
|
625
|
+
* the pool. The route re-acquires at CALL time rather than holding the pooled
|
|
626
|
+
* client, so an entry evicted between discovery and the call is transparently
|
|
627
|
+
* re-created instead of used after its connection was closed. Each use holds
|
|
628
|
+
* a pool lease only for its own duration, so the pool never closes a
|
|
629
|
+
* connection an operation is still using.
|
|
419
630
|
*/
|
|
631
|
+
async attachDownstream(client, template, userId, routes) {
|
|
632
|
+
const key = downstreamPoolKey(userId, template);
|
|
633
|
+
// The catalog name, which is what the manual's per-user variables are keyed by.
|
|
634
|
+
const catalogName = String(template.name ?? '');
|
|
635
|
+
const manualName = utcpManualName(template);
|
|
636
|
+
const definition = templateFingerprint(template);
|
|
637
|
+
const acquire = () => this.downstream.acquire(key, () => this.connectDownstream(userId, template));
|
|
638
|
+
const afterFailure = (err) => this.afterDownstreamFailure(userId, catalogName, key, err);
|
|
639
|
+
const attach = async (tools) => {
|
|
640
|
+
await client.config.tool_repository.saveManual({ ...template, name: manualName }, UtcpManualSchema.parse({ tools }));
|
|
641
|
+
routes.set(manualName, { acquire, afterFailure });
|
|
642
|
+
};
|
|
643
|
+
// Set when the handshake failed on a credential the provider may yet
|
|
644
|
+
// renew: the caller must NOT remember that as a dead manual (see below).
|
|
645
|
+
let credentialTransient = false;
|
|
646
|
+
try {
|
|
647
|
+
let lease;
|
|
648
|
+
try {
|
|
649
|
+
lease = await acquire();
|
|
650
|
+
}
|
|
651
|
+
catch (err) {
|
|
652
|
+
// A connection dialed with a token the server refuses fails right here,
|
|
653
|
+
// at the handshake — the same refresh-and-retry applies.
|
|
654
|
+
const verdict = await this.classifyDownstreamFailure(userId, catalogName, key, err);
|
|
655
|
+
if (!verdict.retry) {
|
|
656
|
+
credentialTransient = verdict.credentialTransient;
|
|
657
|
+
throw verdict.error;
|
|
658
|
+
}
|
|
659
|
+
lease = await acquire();
|
|
660
|
+
}
|
|
661
|
+
let tools;
|
|
662
|
+
try {
|
|
663
|
+
tools = (await lease.value.client.getTools()).filter((t) => t.name.startsWith(`${manualName}.`));
|
|
664
|
+
}
|
|
665
|
+
finally {
|
|
666
|
+
lease.release();
|
|
667
|
+
}
|
|
668
|
+
this.knownDownstreamTools.set(catalogName, { definition, tools });
|
|
669
|
+
await attach(tools);
|
|
670
|
+
return { ok: true };
|
|
671
|
+
}
|
|
672
|
+
catch (err) {
|
|
673
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
674
|
+
// No connection because this CALLER has no usable sign-in for the manual
|
|
675
|
+
// (never signed in, or the grant was just found dead and wiped): the
|
|
676
|
+
// manual is not broken, the sign-in is. Keep its tools on the surface
|
|
677
|
+
// from what the downstream last advertised, so a call answers with the
|
|
678
|
+
// sign-in link — and never remember the failure, since re-authorizing is
|
|
679
|
+
// one visit to /connect away and the next attempt costs no network.
|
|
680
|
+
if (await this.signInMissing(userId, catalogName)) {
|
|
681
|
+
const known = this.knownDownstreamTools.get(catalogName);
|
|
682
|
+
if (known && known.definition === definition) {
|
|
683
|
+
await attach(known.tools);
|
|
684
|
+
return { ok: true };
|
|
685
|
+
}
|
|
686
|
+
return { ok: false, error, retryable: true, signInMissing: true };
|
|
687
|
+
}
|
|
688
|
+
// `retryable` keeps a transient credential failure out of the caller's
|
|
689
|
+
// five-minute failure memo: the refresh-and-retry policy for a rejected
|
|
690
|
+
// token is one minute, and a memo entry would silently outlast it.
|
|
691
|
+
return { ok: false, error, retryable: credentialTransient };
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
/** Whether the caller's sign-in for the manual named `catalogName` is missing or broken — a check that must never throw here. */
|
|
695
|
+
async signInMissing(userId, catalogName) {
|
|
696
|
+
try {
|
|
697
|
+
return (await this.missingUserSecrets(userId, catalogName)).length > 0;
|
|
698
|
+
}
|
|
699
|
+
catch {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Create one pooled downstream connection: a client registering just this
|
|
705
|
+
* manual.
|
|
706
|
+
*
|
|
707
|
+
* `@utcp/mcp` (1.2.0+) registers its protocol as a FACTORY, so this client
|
|
708
|
+
* gets an `mcp` protocol instance of its own: the session it opens lives in
|
|
709
|
+
* that instance, is reachable from no other client, and ends with
|
|
710
|
+
* `client.close()`. That is what makes a pool entry per (user, server) an
|
|
711
|
+
* actual isolation boundary — two users with byte-identical server
|
|
712
|
+
* definitions still never share a connection — with nothing reached into.
|
|
713
|
+
*
|
|
714
|
+
* SESSION RECOVERY is installed on the pooled client: a downstream server
|
|
715
|
+
* that restarts (or expires a session) answers our next call with the spec's
|
|
716
|
+
* 404/`-32001`, and recovery re-registers in place and retries once. It is
|
|
717
|
+
* deliberately clear of {@link ManualFailureMemo}: that memo is a circuit
|
|
718
|
+
* breaker for manuals whose REGISTRATION failed, so a recovery neither
|
|
719
|
+
* consults it nor records into it.
|
|
720
|
+
*
|
|
721
|
+
* A registration that fails closes the client it built (ending whatever the
|
|
722
|
+
* attempt opened) and throws, so the pool caches nothing and the caller's
|
|
723
|
+
* memo records the failure.
|
|
724
|
+
*/
|
|
725
|
+
async connectDownstream(userId, template) {
|
|
726
|
+
// Third-party manuals are never seeded loopback credentials (see
|
|
727
|
+
// `buildClient`), so a pooled client carries no request-scoped bearer.
|
|
728
|
+
const client = await CodeModeUtcpClient.create(process.cwd(), utcpClientConfig(userId, {}));
|
|
729
|
+
// Our own copy: registration renames the template in place, and recovery
|
|
730
|
+
// re-registers from exactly what discovery used.
|
|
731
|
+
const own = structuredClone(template);
|
|
732
|
+
const manualName = utcpManualName(own);
|
|
733
|
+
installSessionRecovery(client, { manualTemplate: (name) => (name === manualName ? own : undefined) });
|
|
734
|
+
const result = await registerManual(client, own);
|
|
735
|
+
if (!result.ok) {
|
|
736
|
+
await client.close().catch(() => { });
|
|
737
|
+
throw new Error(result.error);
|
|
738
|
+
}
|
|
739
|
+
return { client };
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* A pooled manual's operation failed: may it be retried with a refreshed
|
|
743
|
+
* token? Answers {@link RETRY_WITH_REFRESHED_TOKEN} when so, otherwise the
|
|
744
|
+
* error the caller should see.
|
|
745
|
+
*
|
|
746
|
+
* Only a token rejection (401 / `invalid_token`) qualifies. Then the
|
|
747
|
+
* caller's OAuth token for this manual is refreshed once, ignoring its
|
|
748
|
+
* stored expiry, and:
|
|
749
|
+
* - refreshed → the pooled connection (dialed with the dead token) is
|
|
750
|
+
* dropped and the operation retried once, on a fresh one;
|
|
751
|
+
* - rejected → the grant is gone and the vault has wiped it; the caller is
|
|
752
|
+
* told to re-authorize on /connect, where it now shows as not connected;
|
|
753
|
+
* - transient, or no refresh allowed / possible → the original error.
|
|
754
|
+
*/
|
|
755
|
+
async afterDownstreamFailure(userId, manualName, poolKey, err) {
|
|
756
|
+
const verdict = await this.classifyDownstreamFailure(userId, manualName, poolKey, err);
|
|
757
|
+
return verdict.retry ? RETRY_WITH_REFRESHED_TOKEN : verdict.error;
|
|
758
|
+
}
|
|
759
|
+
/** {@link afterDownstreamFailure}, keeping the one distinction its symbol-or-error answer drops. */
|
|
760
|
+
async classifyDownstreamFailure(userId, manualName, poolKey, err) {
|
|
761
|
+
if (!isDownstreamTokenRejection(err))
|
|
762
|
+
return { retry: false, error: err, credentialTransient: false };
|
|
763
|
+
const outcome = await this.refreshDownstreamToken(userId, manualName);
|
|
764
|
+
if (outcome === 'refreshed') {
|
|
765
|
+
// The vault's mutation signal evicts this user's connections too; doing it
|
|
766
|
+
// here as well keeps the retry correct whether or not that is wired.
|
|
767
|
+
this.downstream.evictWhere((k) => k === poolKey);
|
|
768
|
+
return { retry: true };
|
|
769
|
+
}
|
|
770
|
+
if (outcome === 'rejected') {
|
|
771
|
+
// The connection was dialed with a grant that no longer exists; the
|
|
772
|
+
// vault's mutation signal drops it too, this keeps the next request
|
|
773
|
+
// honest whether or not that is wired.
|
|
774
|
+
this.downstream.evictWhere((k) => k === poolKey);
|
|
775
|
+
return {
|
|
776
|
+
retry: false,
|
|
777
|
+
credentialTransient: false,
|
|
778
|
+
error: new Error(`Your sign-in for "${manualName}" was rejected and has been disconnected. ` +
|
|
779
|
+
`Re-authorize it on ${this.opts.publicFrontendUrl}/connect, then run the tool again.`),
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
// The token stands and so does the call's own error. Whether the NEXT
|
|
783
|
+
// call may try again depends on why: a refresh that failed transiently, or
|
|
784
|
+
// one the window refused, will be worth attempting shortly — while
|
|
785
|
+
// "nothing here to refresh" (no vault, no OAuth variable, no stored token)
|
|
786
|
+
// is a standing condition, and the failure memo should hold the manual
|
|
787
|
+
// down exactly as it does for any other broken credential.
|
|
788
|
+
const mayRecoverSoon = outcome === 'transient' || outcome === 'guarded';
|
|
789
|
+
return { retry: false, error: err, credentialTransient: mayRecoverSoon };
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Force-refresh the caller's OAuth token(s) for `manualName`, at most once per
|
|
793
|
+
* (user, manual) per minute. Logs ONE line per attempt — manual, user,
|
|
794
|
+
* outcome, never token material.
|
|
795
|
+
*
|
|
796
|
+
* `'guarded'` when the window refused this one (a refresh just ran, or is
|
|
797
|
+
* running, for this pair); `undefined` when there was nothing to refresh at
|
|
798
|
+
* all: no vault wired, or no OAuth variable on the manual. The two are not
|
|
799
|
+
* the same thing to the caller — see {@link classifyDownstreamFailure}.
|
|
800
|
+
*/
|
|
801
|
+
async refreshDownstreamToken(userId, manualName) {
|
|
802
|
+
const vault = this.secretsVault;
|
|
803
|
+
if (!vault || !this.toolManuals || !manualName)
|
|
804
|
+
return undefined;
|
|
805
|
+
let keys;
|
|
806
|
+
try {
|
|
807
|
+
keys = (await this.toolManuals.userScopedKeysForManual(manualName)).filter((v) => v.oauth).map((v) => v.key);
|
|
808
|
+
}
|
|
809
|
+
catch (err) {
|
|
810
|
+
// The error's own message is caller-controlled as well (it quotes the
|
|
811
|
+
// manual, and may quote a provider's reply), and a raw Error handed to
|
|
812
|
+
// the logger renders its message and stack verbatim — so it goes through
|
|
813
|
+
// the same escaper rather than travelling as an object.
|
|
814
|
+
log.warn(`downstream token refresh: could not read the variables of manual=${printable(manualName)}: ` +
|
|
815
|
+
printable(err instanceof Error ? err.message : String(err)));
|
|
816
|
+
return undefined;
|
|
817
|
+
}
|
|
818
|
+
if (keys.length === 0)
|
|
819
|
+
return undefined;
|
|
820
|
+
const attempt = this.tokenRefreshes.run(`${userId}${POOL_KEY_SEPARATOR}${manualName}`, async () => {
|
|
821
|
+
const outcomes = [];
|
|
822
|
+
for (const key of keys) {
|
|
823
|
+
// A vault fault is not a verdict on the grant: keep the token, try later.
|
|
824
|
+
outcomes.push(await vault.forceRefresh(userId, key).catch(() => 'transient'));
|
|
825
|
+
}
|
|
826
|
+
const outcome = outcomes.includes('rejected')
|
|
827
|
+
? 'rejected'
|
|
828
|
+
: outcomes.includes('transient')
|
|
829
|
+
? 'transient'
|
|
830
|
+
: outcomes.includes('refreshed')
|
|
831
|
+
? 'refreshed'
|
|
832
|
+
: 'skipped';
|
|
833
|
+
if (outcome !== 'skipped') {
|
|
834
|
+
// Both values reach the log from outside (a catalog name, an identity
|
|
835
|
+
// provider's id), so both are escaped: one event stays one line.
|
|
836
|
+
log.info(`downstream token refresh: manual=${printable(manualName)} user=${printable(userId)} outcome=${outcome}`);
|
|
837
|
+
}
|
|
838
|
+
return outcome;
|
|
839
|
+
});
|
|
840
|
+
return attempt ? await attempt : 'guarded';
|
|
841
|
+
}
|
|
420
842
|
/**
|
|
421
843
|
* If the tool declares per-user credentials the caller hasn't set, return a
|
|
422
844
|
* needs-authorization result (naming the tool + a setup link); otherwise null
|
|
@@ -426,15 +848,15 @@ export class McpService {
|
|
|
426
848
|
* services aren't wired, or the tool's manual declares no per-user credential
|
|
427
849
|
* (e.g. the built-in KB tools).
|
|
428
850
|
*/
|
|
429
|
-
async checkUserSecrets(userId,
|
|
430
|
-
const missing = await this.missingUserSecrets(userId,
|
|
851
|
+
async checkUserSecrets(userId, toolName, manualName) {
|
|
852
|
+
const missing = await this.missingUserSecrets(userId, manualName);
|
|
431
853
|
if (missing.length === 0)
|
|
432
854
|
return null;
|
|
433
855
|
return {
|
|
434
|
-
result: needsAuthorizationResult(
|
|
856
|
+
result: needsAuthorizationResult(toolName, missing.map((v) => v.label ?? v.name), `${this.opts.publicFrontendUrl}/connect`),
|
|
435
857
|
// At least one missing item is a sign-in the caller already HAS a row
|
|
436
858
|
// for (dead grant, abandoned consent, or missing scopes) — the state
|
|
437
|
-
// that warrants resetting an interactive
|
|
859
|
+
// that warrants resetting an interactive client for re-auth, as
|
|
438
860
|
// opposed to a tool the caller never set up at all.
|
|
439
861
|
brokenSignIn: missing.some((v) => v.brokenSignIn),
|
|
440
862
|
};
|
|
@@ -442,14 +864,14 @@ export class McpService {
|
|
|
442
864
|
/**
|
|
443
865
|
* The per-user variables of `tool`'s manual the caller has NOT satisfied.
|
|
444
866
|
* Shared by the call-time needs-authorization check above and the
|
|
445
|
-
* listing-time filter for connection-key
|
|
867
|
+
* listing-time filter for connection-key callers (which registers only
|
|
446
868
|
* ready tools). Empty when the vault/manual services aren't wired or the
|
|
447
869
|
* manual declares no per-user credential.
|
|
448
870
|
*/
|
|
449
|
-
async missingUserSecrets(userId,
|
|
450
|
-
if (!this.secretsVault || !this.toolManuals || !
|
|
871
|
+
async missingUserSecrets(userId, manualName) {
|
|
872
|
+
if (!this.secretsVault || !this.toolManuals || !manualName)
|
|
451
873
|
return [];
|
|
452
|
-
const userVars = await this.toolManuals.userScopedKeysForManual(
|
|
874
|
+
const userVars = await this.toolManuals.userScopedKeysForManual(manualName);
|
|
453
875
|
if (userVars.length === 0)
|
|
454
876
|
return [];
|
|
455
877
|
const status = await this.secretsVault.statusFor(userId, userVars.map((v) => v.key));
|
|
@@ -464,6 +886,17 @@ export class McpService {
|
|
|
464
886
|
missing.push({ name: v.name, label: v.label, brokenSignIn }); // no row at all → needs a value / sign-in
|
|
465
887
|
continue;
|
|
466
888
|
}
|
|
889
|
+
// A row of the OTHER kind is not this credential: a `.tool` edited from
|
|
890
|
+
// an OAuth sign-in to a plain key (or back) leaves the old row behind,
|
|
891
|
+
// and serving a token where a key is declared — or a key where a
|
|
892
|
+
// sign-in is — fails opaquely at the provider. Not a broken sign-in
|
|
893
|
+
// either: nothing to reset, the user has to set the credential up as
|
|
894
|
+
// the manual now declares it.
|
|
895
|
+
const declaredKind = v.oauth ? 'oauth' : 'static';
|
|
896
|
+
if (st.userKind && st.userKind !== declaredKind) {
|
|
897
|
+
missing.push({ name: v.name, label: v.label, brokenSignIn: false });
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
467
900
|
// An OAuth-backed var whose row exists but has no token yet is NOT ready —
|
|
468
901
|
// the user has registered but not completed sign-in. Fail closed: anything
|
|
469
902
|
// other than a confirmed `true` (including a non-oauth row → undefined)
|
|
@@ -483,6 +916,14 @@ export class McpService {
|
|
|
483
916
|
}
|
|
484
917
|
return missing;
|
|
485
918
|
}
|
|
919
|
+
/**
|
|
920
|
+
* Run one tool call through `callToolStreaming` with a one-chunk lookahead:
|
|
921
|
+
* every chunk except the last becomes a progress notification — sent on THIS
|
|
922
|
+
* request's own response stream — and the last is the result. Continuity is
|
|
923
|
+
* the caller's: a tool that supports it (e.g. `ask`) returns its `sessionId`
|
|
924
|
+
* in the result verbatim, and the caller echoes it back per the tool's own
|
|
925
|
+
* schema — the proxy never rewrites args.
|
|
926
|
+
*/
|
|
486
927
|
async dispatch(client, tool, request,
|
|
487
928
|
// `sendNotification` typed loosely (`any`) so a `notifications/progress`
|
|
488
929
|
// payload without a `progressToken` is accepted — same approach the prior
|
|
@@ -500,8 +941,8 @@ export class McpService {
|
|
|
500
941
|
}
|
|
501
942
|
/**
|
|
502
943
|
* Handle a code-mode meta-tool. The shared implementation reflects on this
|
|
503
|
-
*
|
|
504
|
-
* this
|
|
944
|
+
* request's client, so `list_tools`/`tools_info` describe exactly the catalog
|
|
945
|
+
* this request discovered and `call_tool_chain` runs in that client's
|
|
505
946
|
* isolated-vm — resolving over loopback with the caller's key. The workspace
|
|
506
947
|
* spill store is passed in so an oversized chain result comes back as a
|
|
507
948
|
* `read_file`-able ref rather than a wall of JSON.
|
|
@@ -510,6 +951,119 @@ export class McpService {
|
|
|
510
951
|
return dispatchMetaTool(client, name, args, this.opts.spillStore);
|
|
511
952
|
}
|
|
512
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* The UTCP client config for `userId`: the given variables, plus the per-user
|
|
956
|
+
* `bevel-secrets` loader that resolves every `${SECRET}` ref lazily. Shared by
|
|
957
|
+
* request clients and pooled downstream clients, so both resolve a manual's
|
|
958
|
+
* variables through exactly the same tiers.
|
|
959
|
+
*/
|
|
960
|
+
function utcpClientConfig(userId, variables) {
|
|
961
|
+
return new UtcpClientConfigSerializer().validateDict({
|
|
962
|
+
variables,
|
|
963
|
+
load_variables_from: [bevelSecretsLoaderConfig(userId)],
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* The name a manual is registered under. `UtcpClient.registerManual` rewrites
|
|
968
|
+
* every non-word character to `_`, and tool names are prefixed with the result,
|
|
969
|
+
* so routing has to key on the same rewrite.
|
|
970
|
+
*/
|
|
971
|
+
function utcpManualName(template) {
|
|
972
|
+
return String(template.name ?? '').replace(/[^\w]/g, '_');
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* The pool key for (user, manual). The template's fingerprint is part of it, so
|
|
976
|
+
* an edited `mcp.json` (new URL, new headers) gets a new connection rather than
|
|
977
|
+
* the one dialed for the old definition, which simply idles out. Hashed: the
|
|
978
|
+
* template can carry credentials and the key must stay log-safe.
|
|
979
|
+
*/
|
|
980
|
+
function downstreamPoolKey(userId, template) {
|
|
981
|
+
return [userId, utcpManualName(template), templateFingerprint(template)].join(POOL_KEY_SEPARATOR);
|
|
982
|
+
}
|
|
983
|
+
/** A short, log-safe hash of a manual's whole definition: changes whenever the definition does. */
|
|
984
|
+
function templateFingerprint(template) {
|
|
985
|
+
return createHash('sha256').update(JSON.stringify(template)).digest('hex').slice(0, 16);
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Route tool calls for pooled manuals to their pooled client, in place on the
|
|
989
|
+
* request client. Both entry points are wrapped — `callToolStreaming` is the
|
|
990
|
+
* MCP dispatch path, `callTool` is what `call_tool_chain` bridges every
|
|
991
|
+
* in-isolate tool function to — so the two can never disagree. Every other
|
|
992
|
+
* manual's calls go through the request client unchanged.
|
|
993
|
+
*
|
|
994
|
+
* Each routed call holds its pool lease until the call ends — for a stream,
|
|
995
|
+
* until the consumer finishes or abandons it (`for await` returns the
|
|
996
|
+
* generator, which runs the `finally`).
|
|
997
|
+
*
|
|
998
|
+
* A call the downstream refuses for its token (401 / `invalid_token`) goes to
|
|
999
|
+
* the route's `afterFailure`, which may refresh the token and ask for ONE retry
|
|
1000
|
+
* on a fresh connection. Retrying is safe for the same reason session recovery
|
|
1001
|
+
* is: authentication is decided before the request reaches a tool, so the
|
|
1002
|
+
* refused attempt ran nothing.
|
|
1003
|
+
*/
|
|
1004
|
+
function routeToDownstream(client, routes) {
|
|
1005
|
+
const callTool = client.callTool.bind(client);
|
|
1006
|
+
const callToolStreaming = client.callToolStreaming.bind(client);
|
|
1007
|
+
const routeOf = (toolName) => routes.get(toolName.split('.')[0] ?? '');
|
|
1008
|
+
client.callTool = async function routedCallTool(toolName, toolArgs) {
|
|
1009
|
+
const route = routeOf(toolName);
|
|
1010
|
+
if (!route)
|
|
1011
|
+
return callTool(toolName, toolArgs);
|
|
1012
|
+
const once = async () => {
|
|
1013
|
+
const lease = await route.acquire();
|
|
1014
|
+
try {
|
|
1015
|
+
return await lease.value.client.callTool(toolName, toolArgs);
|
|
1016
|
+
}
|
|
1017
|
+
finally {
|
|
1018
|
+
lease.release();
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
try {
|
|
1022
|
+
return await once();
|
|
1023
|
+
}
|
|
1024
|
+
catch (err) {
|
|
1025
|
+
const next = await route.afterFailure(err);
|
|
1026
|
+
if (next !== RETRY_WITH_REFRESHED_TOKEN)
|
|
1027
|
+
throw next;
|
|
1028
|
+
// Exactly one retry: whatever it produces is what the caller sees.
|
|
1029
|
+
return await once();
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
client.callToolStreaming = async function* routedCallToolStreaming(toolName, toolArgs) {
|
|
1033
|
+
const route = routeOf(toolName);
|
|
1034
|
+
if (!route) {
|
|
1035
|
+
yield* callToolStreaming(toolName, toolArgs);
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
const once = async function* () {
|
|
1039
|
+
const lease = await route.acquire();
|
|
1040
|
+
try {
|
|
1041
|
+
yield* lease.value.client.callToolStreaming(toolName, toolArgs);
|
|
1042
|
+
}
|
|
1043
|
+
finally {
|
|
1044
|
+
lease.release();
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
let yielded = false;
|
|
1048
|
+
try {
|
|
1049
|
+
for await (const chunk of once()) {
|
|
1050
|
+
yielded = true;
|
|
1051
|
+
yield chunk;
|
|
1052
|
+
}
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
catch (err) {
|
|
1056
|
+
// A stream that already produced output was accepted — a rejection can
|
|
1057
|
+
// only come before the first chunk, and replaying would duplicate output.
|
|
1058
|
+
if (yielded)
|
|
1059
|
+
throw err;
|
|
1060
|
+
const next = await route.afterFailure(err);
|
|
1061
|
+
if (next !== RETRY_WITH_REFRESHED_TOKEN)
|
|
1062
|
+
throw next;
|
|
1063
|
+
}
|
|
1064
|
+
yield* once();
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
513
1067
|
/**
|
|
514
1068
|
* The pieces of the proxy that are shared with the local MCP server now live in
|
|
515
1069
|
* `@bevel-software/platform-mcp-core`. Re-exported here because this module is
|