@bevel-software/platform-core-backend 0.13.6 → 0.15.1
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 +6 -6
- package/dist/core/catalog-cache-invalidation.d.ts +29 -0
- package/dist/core/catalog-cache-invalidation.d.ts.map +1 -0
- package/dist/core/catalog-cache-invalidation.js +71 -0
- package/dist/core/catalog-cache-invalidation.js.map +1 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +101 -9
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +20 -1
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +105 -43
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +12 -5
- package/dist/core-config.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +18 -6
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +26 -1
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +213 -71
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +59 -7
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +51 -1
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +95 -1
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/access-model/group-files.d.ts.map +1 -1
- package/dist/modules/access-model/group-files.js +4 -1
- package/dist/modules/access-model/group-files.js.map +1 -1
- package/dist/modules/access-model/kb-read-filter.d.ts +12 -0
- package/dist/modules/access-model/kb-read-filter.d.ts.map +1 -1
- package/dist/modules/access-model/kb-read-filter.js +15 -0
- package/dist/modules/access-model/kb-read-filter.js.map +1 -1
- package/dist/modules/access-model/plugin-principals.d.ts +49 -0
- package/dist/modules/access-model/plugin-principals.d.ts.map +1 -0
- package/dist/modules/access-model/plugin-principals.js +125 -0
- package/dist/modules/access-model/plugin-principals.js.map +1 -0
- package/dist/modules/connection-probe/connection-probe.contract.d.ts +43 -0
- package/dist/modules/connection-probe/connection-probe.contract.d.ts.map +1 -0
- package/dist/modules/connection-probe/connection-probe.contract.js +2 -0
- package/dist/modules/connection-probe/connection-probe.contract.js.map +1 -0
- package/dist/modules/connection-probe/connection-probe.service.d.ts +94 -0
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -0
- package/dist/modules/connection-probe/connection-probe.service.js +684 -0
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -0
- package/dist/modules/connection-probe/index.d.ts +3 -0
- package/dist/modules/connection-probe/index.d.ts.map +1 -0
- package/dist/modules/connection-probe/index.js +3 -0
- package/dist/modules/connection-probe/index.js.map +1 -0
- package/dist/modules/database/core-schema.d.ts +326 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +52 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/diff/diff.routes.d.ts.map +1 -1
- package/dist/modules/diff/diff.routes.js +3 -5
- package/dist/modules/diff/diff.routes.js.map +1 -1
- package/dist/modules/kb-fs/mutex.d.ts +37 -0
- package/dist/modules/kb-fs/mutex.d.ts.map +1 -1
- package/dist/modules/kb-fs/mutex.js +48 -5
- package/dist/modules/kb-fs/mutex.js.map +1 -1
- package/dist/modules/kb-sync/index.d.ts +6 -0
- package/dist/modules/kb-sync/index.d.ts.map +1 -0
- package/dist/modules/kb-sync/index.js +5 -0
- package/dist/modules/kb-sync/index.js.map +1 -0
- package/dist/modules/kb-sync/kb-sync.interface.d.ts +77 -0
- package/dist/modules/kb-sync/kb-sync.interface.d.ts.map +1 -0
- package/dist/modules/kb-sync/kb-sync.interface.js +2 -0
- package/dist/modules/kb-sync/kb-sync.interface.js.map +1 -0
- package/dist/modules/kb-sync/kb-sync.routes.d.ts +70 -0
- package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -0
- package/dist/modules/kb-sync/kb-sync.routes.js +135 -0
- package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -0
- package/dist/modules/kb-sync/kb-sync.service.d.ts +45 -0
- package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -0
- package/dist/modules/kb-sync/kb-sync.service.js +183 -0
- package/dist/modules/kb-sync/kb-sync.service.js.map +1 -0
- package/dist/modules/kb-sync/sync-auth.d.ts +59 -0
- package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -0
- package/dist/modules/kb-sync/sync-auth.js +62 -0
- package/dist/modules/kb-sync/sync-auth.js.map +1 -0
- package/dist/modules/kb-sync/sync-payload.d.ts +32 -0
- package/dist/modules/kb-sync/sync-payload.d.ts.map +1 -0
- package/dist/modules/kb-sync/sync-payload.js +105 -0
- package/dist/modules/kb-sync/sync-payload.js.map +1 -0
- package/dist/modules/marketplace/git-http.routes.d.ts +42 -0
- package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -0
- package/dist/modules/marketplace/git-http.routes.js +190 -0
- package/dist/modules/marketplace/git-http.routes.js.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +23 -0
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +59 -0
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts +59 -0
- package/dist/modules/marketplace/github-facade/github-facade-codes.store.d.ts.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade-codes.store.js +96 -0
- package/dist/modules/marketplace/github-facade/github-facade-codes.store.js.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +99 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +147 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts +47 -0
- package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade.routes.js +228 -0
- package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +109 -0
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -0
- package/dist/modules/marketplace/github-facade/github-facade.service.js +172 -0
- package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -0
- package/dist/modules/marketplace/github-facade/index.d.ts +6 -0
- package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -0
- package/dist/modules/marketplace/github-facade/index.js +6 -0
- package/dist/modules/marketplace/github-facade/index.js.map +1 -0
- package/dist/modules/marketplace/index.d.ts +4 -0
- package/dist/modules/marketplace/index.d.ts.map +1 -0
- package/dist/modules/marketplace/index.js +4 -0
- package/dist/modules/marketplace/index.js.map +1 -0
- package/dist/modules/marketplace/marketplace-repo.service.d.ts +122 -0
- package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -0
- package/dist/modules/marketplace/marketplace-repo.service.js +300 -0
- package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +4 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +14 -8
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +13 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-state.d.ts +13 -2
- package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-state.js +3 -1
- package/dist/modules/mcp/oauth/oauth-state.js.map +1 -1
- package/dist/modules/plugins/compile/compile-marketplace.d.ts +97 -0
- package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -0
- package/dist/modules/plugins/compile/compile-marketplace.js +240 -0
- package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -0
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +66 -0
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -0
- package/dist/modules/plugins/compile/marketplace-compiler.service.js +132 -0
- package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -0
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +37 -0
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -0
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +135 -0
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -0
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +45 -0
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -0
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js +147 -0
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -0
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +37 -0
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -0
- package/dist/modules/plugins/discovery/kb-plugin-source.js +107 -0
- package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -0
- package/dist/modules/plugins/discovery/native.source.d.ts +15 -0
- package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -0
- package/dist/modules/plugins/discovery/native.source.js +102 -0
- package/dist/modules/plugins/discovery/native.source.js.map +1 -0
- package/dist/modules/plugins/discovery/plugin-source.d.ts +96 -0
- package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -0
- package/dist/modules/plugins/discovery/plugin-source.js +2 -0
- package/dist/modules/plugins/discovery/plugin-source.js.map +1 -0
- package/dist/modules/plugins/index.d.ts +10 -1
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js +8 -0
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +66 -0
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -0
- package/dist/modules/plugins/plugin-links.js +160 -0
- package/dist/modules/plugins/plugin-links.js.map +1 -0
- package/dist/modules/plugins/plugin-links.service.d.ts +114 -0
- package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -0
- package/dist/modules/plugins/plugin-links.service.js +304 -0
- package/dist/modules/plugins/plugin-links.service.js.map +1 -0
- package/dist/modules/plugins/plugin-provision.service.d.ts +39 -3
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +152 -52
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts +69 -0
- package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -0
- package/dist/modules/plugins/plugin-rename.service.js +245 -0
- package/dist/modules/plugins/plugin-rename.service.js.map +1 -0
- package/dist/modules/plugins/plugins.contract.d.ts +27 -1
- package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +7 -1
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +120 -12
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.service.d.ts +50 -3
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.service.js +108 -47
- package/dist/modules/plugins/plugins.service.js.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +6 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +31 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +9 -0
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +82 -2
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/setup.routes.d.ts +26 -0
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +9 -1
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/index.d.ts +1 -0
- 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.map +1 -1
- package/dist/modules/skills/pending-skills.service.js +9 -4
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts +38 -0
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -0
- package/dist/modules/skills/skill-access-requests.routes.js +168 -0
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -0
- package/dist/modules/skills/skills.contract.d.ts +31 -0
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.d.ts +28 -3
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +42 -3
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +4 -0
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +83 -22
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +18 -1
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.js +2 -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 +13 -4
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +26 -9
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +36 -0
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +130 -83
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.js +10 -4
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +83 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +15 -2
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +199 -38
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +58 -3
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +325 -60
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts +6 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +8 -0
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts +2 -1
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +98 -9
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +133 -9
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +462 -52
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +35 -0
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +121 -0
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +46 -2
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +112 -25
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +11 -14
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +38 -1
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +131 -20
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/shared/domain-errors.d.ts +20 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +29 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/fs-errors.d.ts +8 -0
- package/dist/shared/fs-errors.d.ts.map +1 -0
- package/dist/shared/fs-errors.js +11 -0
- package/dist/shared/fs-errors.js.map +1 -0
- package/dist/shared/fs-walk.d.ts +20 -6
- package/dist/shared/fs-walk.d.ts.map +1 -1
- package/dist/shared/fs-walk.js +35 -27
- package/dist/shared/fs-walk.js.map +1 -1
- package/dist/shared/kb-walk.d.ts +52 -0
- package/dist/shared/kb-walk.d.ts.map +1 -0
- package/dist/shared/kb-walk.js +76 -0
- package/dist/shared/kb-walk.js.map +1 -0
- package/dist/shared/path-order.d.ts +18 -0
- package/dist/shared/path-order.d.ts.map +1 -0
- package/dist/shared/path-order.js +35 -0
- package/dist/shared/path-order.js.map +1 -0
- package/dist/shared/token-crypto.d.ts +17 -2
- package/dist/shared/token-crypto.d.ts.map +1 -1
- package/dist/shared/token-crypto.js +25 -8
- package/dist/shared/token-crypto.js.map +1 -1
- package/dist/shared/ttl-cache.d.ts +28 -1
- package/dist/shared/ttl-cache.d.ts.map +1 -1
- package/dist/shared/ttl-cache.js +33 -1
- package/dist/shared/ttl-cache.js.map +1 -1
- package/kb-template/.bevelignore +1 -1
- package/kb-template/AGENTS.md +95 -30
- package/kb-template/Skills/.gitkeep +0 -0
- package/migrations/0005_github_facade.sql +25 -0
- package/migrations/meta/0005_snapshot.json +1717 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/src/__tests__/core-config.admin.test.ts +21 -0
- package/src/__tests__/kb-layout-config.test.ts +110 -0
- package/src/core/__tests__/catalog-cache-invalidation.test.ts +146 -0
- package/src/core/catalog-cache-invalidation.ts +92 -0
- package/src/core/create-core-server.ts +126 -7
- package/src/core/create-core-services.ts +173 -41
- package/src/core-config.ts +14 -7
- package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +86 -0
- package/src/modules/access/__tests__/access-control.service.test.ts +19 -3
- package/src/modules/access/__tests__/access-plugin-principals.test.ts +368 -0
- package/src/modules/access/__tests__/groups-admin.service.test.ts +8 -0
- package/src/modules/access/access-control.interface.ts +20 -9
- package/src/modules/access/access-control.service.ts +240 -78
- package/src/modules/access/access.routes.ts +96 -14
- package/src/modules/access-model/__tests__/access-grammar.test.ts +18 -0
- package/src/modules/access-model/__tests__/plugin-token-canonical.test.ts +40 -0
- package/src/modules/access-model/access-grammar.ts +114 -2
- package/src/modules/access-model/group-files.ts +4 -0
- package/src/modules/access-model/kb-read-filter.ts +22 -0
- package/src/modules/access-model/plugin-principals.ts +137 -0
- package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +685 -0
- package/src/modules/connection-probe/connection-probe.contract.ts +44 -0
- package/src/modules/connection-probe/connection-probe.service.ts +734 -0
- package/src/modules/connection-probe/index.ts +2 -0
- package/src/modules/database/core-schema.ts +54 -0
- package/src/modules/diff/diff.routes.ts +9 -5
- package/src/modules/kb-fs/__tests__/mutex.test.ts +107 -0
- package/src/modules/kb-fs/mutex.ts +50 -5
- package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +297 -0
- package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +295 -0
- package/src/modules/kb-sync/__tests__/sync-auth.test.ts +118 -0
- package/src/modules/kb-sync/__tests__/sync-payload.test.ts +148 -0
- package/src/modules/kb-sync/index.ts +19 -0
- package/src/modules/kb-sync/kb-sync.interface.ts +79 -0
- package/src/modules/kb-sync/kb-sync.routes.ts +197 -0
- package/src/modules/kb-sync/kb-sync.service.ts +201 -0
- package/src/modules/kb-sync/sync-auth.ts +118 -0
- package/src/modules/kb-sync/sync-payload.ts +143 -0
- package/src/modules/marketplace/__tests__/github-facade.test.ts +443 -0
- package/src/modules/marketplace/__tests__/marketplace-git.test.ts +179 -0
- package/src/modules/marketplace/git-http.routes.ts +193 -0
- package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +78 -0
- package/src/modules/marketplace/github-facade/github-facade-codes.store.ts +145 -0
- package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +208 -0
- package/src/modules/marketplace/github-facade/github-facade.routes.ts +268 -0
- package/src/modules/marketplace/github-facade/github-facade.service.ts +221 -0
- package/src/modules/marketplace/github-facade/index.ts +25 -0
- package/src/modules/marketplace/index.ts +3 -0
- package/src/modules/marketplace/marketplace-repo.service.ts +337 -0
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +3 -0
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +24 -2
- package/src/modules/mcp/oauth/oauth-state.ts +15 -3
- package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +163 -0
- package/src/modules/plugins/__tests__/compile-marketplace.test.ts +294 -0
- package/src/modules/plugins/__tests__/plugin-index.service.test.ts +56 -12
- package/src/modules/plugins/__tests__/plugin-links.service.test.ts +287 -0
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +205 -5
- package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +394 -0
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +80 -33
- package/src/modules/plugins/compile/compile-marketplace.ts +403 -0
- package/src/modules/plugins/compile/marketplace-compiler.service.ts +150 -0
- package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +329 -0
- package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +140 -0
- package/src/modules/plugins/discovery/bundle-dialect/registry.ts +175 -0
- package/src/modules/plugins/discovery/kb-plugin-source.ts +114 -0
- package/src/modules/plugins/discovery/native.source.ts +122 -0
- package/src/modules/plugins/discovery/plugin-source.ts +99 -0
- package/src/modules/plugins/index.ts +10 -0
- package/src/modules/plugins/plugin-links.service.ts +363 -0
- package/src/modules/plugins/plugin-links.ts +184 -0
- package/src/modules/plugins/plugin-provision.service.ts +160 -54
- package/src/modules/plugins/plugin-rename.service.ts +298 -0
- package/src/modules/plugins/plugins.contract.ts +28 -1
- package/src/modules/plugins/plugins.routes.ts +128 -11
- package/src/modules/plugins/plugins.service.ts +106 -53
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +12 -0
- package/src/modules/secrets-vault/__tests__/oauth-return-to.route.test.ts +10 -3
- package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +26 -0
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +1 -1
- package/src/modules/secrets-vault/secrets-vault.routes.ts +35 -1
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +57 -0
- package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +77 -0
- package/src/modules/settings/deployment-settings.service.ts +95 -2
- package/src/modules/settings/setup.routes.ts +24 -0
- package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +128 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +85 -0
- package/src/modules/skills/index.ts +1 -0
- package/src/modules/skills/pending-skills.service.ts +7 -5
- package/src/modules/skills/skill-access-requests.routes.ts +199 -0
- package/src/modules/skills/skills.contract.ts +32 -0
- package/src/modules/skills/skills.routes.ts +59 -3
- package/src/modules/skills/skills.service.ts +84 -22
- package/src/modules/tool-auth/external-api-key.interface.ts +20 -1
- package/src/modules/tool-auth/external-api-key.service.ts +31 -13
- package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +35 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +2 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.health-check.test.ts +104 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +56 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +154 -76
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -4
- package/src/modules/tool-manuals/tool-manuals.contract.ts +89 -0
- package/src/modules/tool-manuals/tool-manuals.service.ts +210 -37
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +1 -1
- package/src/modules/workflow/__tests__/workflow.routes.history-read-gate.test.ts +139 -0
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +337 -0
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +1 -0
- package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +7 -1
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +97 -10
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +119 -2
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +437 -0
- package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +86 -0
- package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +3 -3
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +47 -4
- package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +253 -0
- package/src/modules/workflow/git/git.service.ts +354 -63
- package/src/modules/workflow/git/pull-request.service.ts +9 -0
- package/src/modules/workflow/workflow.routes.ts +104 -4
- package/src/modules/workflow/workflow.service.ts +505 -64
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +6 -7
- package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +93 -0
- package/src/modules/workspace/__tests__/workspace.service.missing-branch.test.ts +28 -0
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +42 -12
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +219 -4
- package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +129 -0
- package/src/modules/workspace/startup/steps/seed-tree.ts +44 -2
- package/src/modules/workspace/startup/steps/template-files.step.ts +131 -27
- package/src/modules/workspace/workspace.routes.ts +17 -21
- package/src/modules/workspace/workspace.service.ts +128 -19
- package/src/shared/__tests__/filename.test.ts +0 -0
- package/src/shared/__tests__/fs-walk.test.ts +22 -1
- package/src/shared/__tests__/kb-walk.test.ts +107 -0
- package/src/shared/__tests__/path-order.test.ts +24 -0
- package/src/shared/__tests__/token-crypto.test.ts +34 -0
- package/src/shared/__tests__/ttl-cache.test.ts +55 -0
- package/src/shared/domain-errors.ts +29 -0
- package/src/shared/fs-errors.ts +10 -0
- package/src/shared/fs-walk.ts +38 -23
- package/src/shared/kb-walk.ts +95 -0
- package/src/shared/path-order.ts +33 -0
- package/src/shared/token-crypto.ts +28 -10
- package/src/shared/ttl-cache.ts +33 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
import type { AuthProviderPlugin } from '../modules/auth/auth.routes.js';
|
|
2
3
|
import type { AuthUser } from '@bevel-software/platform-shared';
|
|
3
4
|
import {
|
|
@@ -5,7 +6,7 @@ import {
|
|
|
5
6
|
configureBranchModel,
|
|
6
7
|
validateBranchModel,
|
|
7
8
|
PROTECTED_BRANCHES,
|
|
8
|
-
|
|
9
|
+
configureKbLayout,
|
|
9
10
|
} from '@bevel-software/platform-shared';
|
|
10
11
|
import { CoreConfig } from '../core-config.js';
|
|
11
12
|
import { getDb, type Database } from '../modules/database/connection.js';
|
|
@@ -15,10 +16,20 @@ import { WorkspaceService } from '../modules/workspace/workspace.service.js';
|
|
|
15
16
|
import { RoutineWritePolicyService } from '../modules/workspace/routine-write-policy.js';
|
|
16
17
|
import { KbStartupRunner } from '../modules/workspace/startup/kb-startup-runner.js';
|
|
17
18
|
import { GroupsToPluginsStep } from '../modules/workspace/startup/steps/groups-to-plugins.step.js';
|
|
19
|
+
import { PluginManifestsStep } from '../modules/workspace/startup/steps/plugin-manifests.step.js';
|
|
18
20
|
import { TemplateFilesStep } from '../modules/workspace/startup/steps/template-files.step.js';
|
|
19
21
|
import { RolesYamlStep } from '../modules/workspace/startup/steps/roles-yaml.step.js';
|
|
20
22
|
import { buildSeedTree } from '../modules/workspace/startup/steps/seed-tree.js';
|
|
21
23
|
import { DeploymentSettingsService } from '../modules/settings/deployment-settings.service.js';
|
|
24
|
+
import { KbSyncService } from '../modules/kb-sync/kb-sync.service.js';
|
|
25
|
+
|
|
26
|
+
/** The hosted MCP endpoint at a deployment address, with any userinfo stripped. */
|
|
27
|
+
function mcpEndpointUrl(publicBackendUrl: string): string {
|
|
28
|
+
const url = new URL('/api/mcp', publicBackendUrl);
|
|
29
|
+
url.username = '';
|
|
30
|
+
url.password = '';
|
|
31
|
+
return url.toString();
|
|
32
|
+
}
|
|
22
33
|
|
|
23
34
|
/** `a.com, b.com` → `['a.com','b.com']`, tolerating a leading `@` or `.`. */
|
|
24
35
|
function parseDomainList(raw: string): string[] {
|
|
@@ -40,12 +51,32 @@ import { GroupsAdminService } from '../modules/access/groups-admin.service.js';
|
|
|
40
51
|
import { PendingSkillsService, SkillService } from '../modules/skills/index.js';
|
|
41
52
|
import { ToolManualService } from '../modules/tool-manuals/index.js';
|
|
42
53
|
import { McpServerEditService } from '../modules/tool-manuals/mcp-server-edit.service.js';
|
|
43
|
-
import {
|
|
54
|
+
import {
|
|
55
|
+
PluginIndexService,
|
|
56
|
+
PluginProvisionService,
|
|
57
|
+
JoinRequestsService,
|
|
58
|
+
PluginLinkIndex,
|
|
59
|
+
PluginLinksService,
|
|
60
|
+
PluginRenameService,
|
|
61
|
+
MarketplaceCompilerService,
|
|
62
|
+
KbPluginSource,
|
|
63
|
+
} from '../modules/plugins/index.js';
|
|
64
|
+
import { MarketplaceRepoService } from '../modules/marketplace/index.js';
|
|
65
|
+
import {
|
|
66
|
+
GitHubFacadeCredentialsService,
|
|
67
|
+
GitHubFacade,
|
|
68
|
+
DbGitHubFacadeCodeStore,
|
|
69
|
+
DbGitHubFacadeCredentialsStore,
|
|
70
|
+
CLAUDE_CONSUMER,
|
|
71
|
+
GITHUB_LINK_KEY_KIND,
|
|
72
|
+
GITHUB_LINK_KEY_PREFIX,
|
|
73
|
+
} from '../modules/marketplace/github-facade/index.js';
|
|
44
74
|
import {
|
|
45
75
|
DbSecretsVaultService,
|
|
46
76
|
McpOAuthDiscoveryService,
|
|
47
77
|
registerBevelSecretsVariableLoader,
|
|
48
78
|
} from '../modules/secrets-vault/index.js';
|
|
79
|
+
import { ConnectionProbeService } from '../modules/connection-probe/index.js';
|
|
49
80
|
import { GitService } from '../modules/workflow/git/git.service.js';
|
|
50
81
|
import { PullRequestService } from '../modules/workflow/git/pull-request.service.js';
|
|
51
82
|
import { WorkspaceMutex } from '../modules/kb-fs/mutex.js';
|
|
@@ -93,6 +124,7 @@ import { TokenCrypto } from '../shared/token-crypto.js';
|
|
|
93
124
|
import { UpdateCheckService } from '../modules/update-check/update-check.service.js';
|
|
94
125
|
import { resolveAppVersion } from '../version.js';
|
|
95
126
|
import { noopRecoveryAgent, type CorePorts } from './core-ports.js';
|
|
127
|
+
import { registerCatalogCacheInvalidation } from './catalog-cache-invalidation.js';
|
|
96
128
|
|
|
97
129
|
/**
|
|
98
130
|
* Everything the CORE composition builds: the core services `createCoreServer`
|
|
@@ -127,6 +159,18 @@ export interface CoreServices {
|
|
|
127
159
|
pluginIndexService: PluginIndexService;
|
|
128
160
|
pluginProvisionService: PluginProvisionService;
|
|
129
161
|
joinRequestsService: JoinRequestsService;
|
|
162
|
+
/** Which plugins hold which skills (inline or linked) — see `PluginLinkIndex`. */
|
|
163
|
+
pluginLinkIndex: PluginLinkIndex;
|
|
164
|
+
/** Link / unlink / repair shared skills into plugins. */
|
|
165
|
+
pluginLinksService: PluginLinksService;
|
|
166
|
+
pluginRenameService: PluginRenameService;
|
|
167
|
+
/** Source layout → distribution layout, for one audience. */
|
|
168
|
+
marketplaceCompiler: MarketplaceCompilerService;
|
|
169
|
+
/** The bare repository the per-user marketplace git endpoint serves from. */
|
|
170
|
+
marketplaceRepo: MarketplaceRepoService;
|
|
171
|
+
/** The GitHub Enterprise facade products such as claude.ai add the marketplace through. */
|
|
172
|
+
githubFacade: GitHubFacade;
|
|
173
|
+
githubFacadeCredentials: GitHubFacadeCredentialsService;
|
|
130
174
|
authService: AuthService;
|
|
131
175
|
authMiddleware: ReturnType<typeof createAuthMiddleware>;
|
|
132
176
|
accountErasureService: AccountErasureService;
|
|
@@ -136,6 +180,8 @@ export interface CoreServices {
|
|
|
136
180
|
reviewWorkflowService: ReviewWorkflowService;
|
|
137
181
|
fileLockService: FileLockService;
|
|
138
182
|
workflowService: WorkflowService;
|
|
183
|
+
/** Remote sync (`POST /api/sync`): a git host or pipeline makes the clones catch up. */
|
|
184
|
+
kbSyncService: KbSyncService;
|
|
139
185
|
eventBus: WorkflowEventBus;
|
|
140
186
|
fileChangeNotifier: FileChangeNotifier;
|
|
141
187
|
pendingCommitsService: PendingCommitsService;
|
|
@@ -169,6 +215,7 @@ export interface CoreServices {
|
|
|
169
215
|
*/
|
|
170
216
|
kbDirName: string;
|
|
171
217
|
secretsVaultService: DbSecretsVaultService;
|
|
218
|
+
connectionProbeService: ConnectionProbeService;
|
|
172
219
|
externalApiKeyService: ExternalApiKeyService;
|
|
173
220
|
internalTokenService: InternalTokenService;
|
|
174
221
|
mcpService: McpService;
|
|
@@ -240,6 +287,11 @@ export async function createCoreServices(
|
|
|
240
287
|
protectedBranches: settings.resolve('protectedBranches'),
|
|
241
288
|
};
|
|
242
289
|
if (!validateBranchModel(branchModel)) configureBranchModel(branchModel);
|
|
290
|
+
// The KB layout — the three renameable roots — applied the same way and at
|
|
291
|
+
// the same moment, before any service captures a root name. Unlike the
|
|
292
|
+
// branch model it always resolves (every root has a default), so an invalid
|
|
293
|
+
// value is a real misconfiguration and stops the boot.
|
|
294
|
+
configureKbLayout(settings.resolveKbLayout());
|
|
243
295
|
// A token supplied through the setup screen has to reach the credential
|
|
244
296
|
// helper, which reads `$GITHUB_TOKEN` at call time.
|
|
245
297
|
settings.syncGitTokenEnv();
|
|
@@ -267,6 +319,7 @@ export async function createCoreServices(
|
|
|
267
319
|
// whatever the distribution appends.
|
|
268
320
|
const kbStartupSteps = [
|
|
269
321
|
new GroupsToPluginsStep(),
|
|
322
|
+
new PluginManifestsStep(),
|
|
270
323
|
new TemplateFilesStep(extraDirs),
|
|
271
324
|
new RolesYamlStep([config.adminEmail]),
|
|
272
325
|
...(ports.kbStartupSteps ?? []),
|
|
@@ -322,17 +375,27 @@ export async function createCoreServices(
|
|
|
322
375
|
// Tool manuals: user-authored `*.tool` files under `Plugins/` in the default
|
|
323
376
|
// branch — access-controlled like Skills, served to external agents via
|
|
324
377
|
// `GET /api/agent/all-tools` and registered on the MCP proxy's UTCP client.
|
|
325
|
-
|
|
378
|
+
// Where plugins come from: one walk of the plugins root that reads every
|
|
379
|
+
// plugin folder in whichever file shape it carries (see
|
|
380
|
+
// modules/plugins/discovery). Nothing to configure, nothing to document.
|
|
381
|
+
const pluginSource = new KbPluginSource();
|
|
382
|
+
const toolManualService = new ToolManualService(workspaceService, accessControl, kbDirName, Date.now, pluginSource);
|
|
326
383
|
// Plugins: the folders under `Plugins/` that carry a
|
|
327
384
|
// team's skills AND the tools they need. Enumerated for EVERY authenticated
|
|
328
385
|
// caller — a plugin they cannot read still exists for them, as a locked one —
|
|
329
386
|
// with the counts read off the two catalogs above rather than a second scan.
|
|
387
|
+
// The link index resolves manifests against the released catalog, and the
|
|
388
|
+
// plugin index counts through it (inline + linked), so it comes first.
|
|
389
|
+
const pluginLinkIndex = new PluginLinkIndex(workspaceService, skillService, accessControl, kbDirName, Date.now, pluginSource);
|
|
330
390
|
const pluginIndexService = new PluginIndexService(
|
|
331
391
|
workspaceService,
|
|
332
392
|
accessControl,
|
|
333
393
|
skillService,
|
|
334
394
|
toolManualService,
|
|
335
395
|
kbDirName,
|
|
396
|
+
Date.now,
|
|
397
|
+
pluginLinkIndex,
|
|
398
|
+
pluginSource,
|
|
336
399
|
);
|
|
337
400
|
// Auth service — resolves identities for login, PR author attribution, and
|
|
338
401
|
// access lookups. (Change requests now store the author email directly, so
|
|
@@ -448,6 +511,62 @@ export async function createCoreServices(
|
|
|
448
511
|
// only needs to read files at refs and to close a request whose proposals
|
|
449
512
|
// have all landed.
|
|
450
513
|
const joinRequestsService = new JoinRequestsService(workspaceService, workflowService);
|
|
514
|
+
// Links land as ordinary default-branch commits and change what the plugin
|
|
515
|
+
// index counts, so a link drops that cache too.
|
|
516
|
+
const pluginLinksService = new PluginLinksService(
|
|
517
|
+
workspaceService,
|
|
518
|
+
workflowService,
|
|
519
|
+
accessControl,
|
|
520
|
+
skillService,
|
|
521
|
+
pluginLinkIndex,
|
|
522
|
+
kbDirName,
|
|
523
|
+
eventBus,
|
|
524
|
+
() => pluginIndexService.invalidate(),
|
|
525
|
+
);
|
|
526
|
+
// A rename rewrites grants across the knowledge base in one batch commit,
|
|
527
|
+
// then drops every cache that keyed on the old identity.
|
|
528
|
+
const pluginRenameService = new PluginRenameService(
|
|
529
|
+
workspaceService,
|
|
530
|
+
workflowService,
|
|
531
|
+
accessControl,
|
|
532
|
+
pluginSource,
|
|
533
|
+
kbDirName,
|
|
534
|
+
eventBus,
|
|
535
|
+
() => {
|
|
536
|
+
pluginIndexService.invalidate();
|
|
537
|
+
pluginLinkIndex.invalidate();
|
|
538
|
+
},
|
|
539
|
+
);
|
|
540
|
+
// Source → distribution. The marketplace's identity is fixed for now; the
|
|
541
|
+
// per-user git endpoint and any mirror both compile through this.
|
|
542
|
+
const marketplaceCompiler = new MarketplaceCompilerService(
|
|
543
|
+
workspaceService,
|
|
544
|
+
accessControl,
|
|
545
|
+
skillService,
|
|
546
|
+
pluginLinkIndex,
|
|
547
|
+
kbDirName,
|
|
548
|
+
{
|
|
549
|
+
name: 'hexis',
|
|
550
|
+
owner: 'Hexis',
|
|
551
|
+
description: 'Skills and plugins from this knowledge base',
|
|
552
|
+
// The knowledge base as a tool, shipped in the skills plugin so an
|
|
553
|
+
// agent installing from the marketplace can read what its skills refer
|
|
554
|
+
// to. The same address `/api/config` and the OAuth metadata publish,
|
|
555
|
+
// userinfo stripped; the client's OAuth flow supplies the identity.
|
|
556
|
+
knowledgeBaseMcp: { name: 'hexis', url: mcpEndpointUrl(config.publicBackendUrl) },
|
|
557
|
+
},
|
|
558
|
+
pluginSource,
|
|
559
|
+
);
|
|
560
|
+
// Sibling of the workspaces root, like the spill store: one bare repo, one
|
|
561
|
+
// git namespace per caller (see marketplace-repo.service.ts).
|
|
562
|
+
const marketplaceRepo = new MarketplaceRepoService(
|
|
563
|
+
path.resolve(config.workspacesRoot, '..', 'marketplace.git'),
|
|
564
|
+
marketplaceCompiler,
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
// Remote sync. Drives the workflow module's per-branch pull-and-announce
|
|
568
|
+
// over every clone the workspace service knows about; owns no git of its own.
|
|
569
|
+
const kbSyncService = new KbSyncService(workflowService, workspaceService);
|
|
451
570
|
// Server-scoped MCP editing — the tool page's edit form. One server's truth
|
|
452
571
|
// spans a plugin's mcp.json AND plugin.json extensions block, and this is
|
|
453
572
|
// the ONE writer that rewrites both entries and commits them together (see
|
|
@@ -484,43 +603,16 @@ export async function createCoreServices(
|
|
|
484
603
|
workflowService,
|
|
485
604
|
);
|
|
486
605
|
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
// default
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
// touch check drives all three caches. An access grant lands as a
|
|
498
|
-
// default-branch change to `Plugins/<plugin>/access.md`, so this is also
|
|
499
|
-
// what makes a newly-granted plugin unlock within one round-trip instead
|
|
500
|
-
// of one TTL.
|
|
501
|
-
const touched = paths.some((p) => p.startsWith(`${kbDirName}/${PLUGINS_DIR}/`));
|
|
502
|
-
if (touched) {
|
|
503
|
-
toolManualService.invalidate();
|
|
504
|
-
skillService.invalidate();
|
|
505
|
-
pluginIndexService.invalidate();
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
// Subscriber B — WRITE-time freshness for the same three caches. The
|
|
511
|
-
// workspace routes emit `fs-tree-changed` the moment bytes hit a working
|
|
512
|
-
// tree; Subscriber A above fires only when the ASYNC commit lands. Between
|
|
513
|
-
// the two, "create a skill, reload the catalog" raced the commit pipeline
|
|
514
|
-
// and lost — the new skill's card stayed invisible until a refresh outlived
|
|
515
|
-
// the TTL. The catalogs scan the working tree anyway, so invalidating at
|
|
516
|
-
// write time makes the very next read see the file. No path filter: this
|
|
517
|
-
// event carries none, and a spurious drop only costs one re-scan.
|
|
518
|
-
eventBus.onEmit((event) => {
|
|
519
|
-
if (event.kind !== 'fs-tree-changed') return;
|
|
520
|
-
if (!('branch' in event) || event.branch !== DEFAULT_BRANCH) return;
|
|
521
|
-
toolManualService.invalidate();
|
|
522
|
-
skillService.invalidate();
|
|
523
|
-
pluginIndexService.invalidate();
|
|
606
|
+
// Catalog freshness: the skill / tool-manual / plugin-index caches all scan
|
|
607
|
+
// the DEFAULT branch's working tree, and all three go stale on the same
|
|
608
|
+
// events (a commit, a working-tree write, a merge). Wired in one place so a
|
|
609
|
+
// new way of reaching the default branch cannot refresh two of them and
|
|
610
|
+
// leave the third serving last minute's answer.
|
|
611
|
+
registerCatalogCacheInvalidation({
|
|
612
|
+
eventBus,
|
|
613
|
+
fileChangeNotifier,
|
|
614
|
+
kbDirName,
|
|
615
|
+
catalogs: [toolManualService, skillService, pluginIndexService, pluginLinkIndex],
|
|
524
616
|
});
|
|
525
617
|
|
|
526
618
|
// Admin = `Admin` role in roles.yaml, resolved through the access model on the
|
|
@@ -562,6 +654,14 @@ export async function createCoreServices(
|
|
|
562
654
|
// UTCP client can resolve `${VAR}` from the caller's secrets at tool-call time.
|
|
563
655
|
registerBevelSecretsVariableLoader(secretsVaultService);
|
|
564
656
|
|
|
657
|
+
// The credential probe: whether a tool's stored credential actually WORKS, as
|
|
658
|
+
// distinct from whether one is stored. Built here — after the vault and the
|
|
659
|
+
// tool catalog — because a probe needs both: the catalog to know what to
|
|
660
|
+
// call, the vault to resolve the credential to call it with. Holds no state
|
|
661
|
+
// and takes no `db`: a verdict is returned to the caller that asked for it and
|
|
662
|
+
// never outlives their page (see `ProbeVerdict`).
|
|
663
|
+
const connectionProbeService = new ConnectionProbeService(toolManualService, secretsVaultService);
|
|
664
|
+
|
|
565
665
|
// Zero-config OAuth for bare `type: mcp` `.tool`s: when the remote server
|
|
566
666
|
// demands OAuth (MCP authorization spec), discover its authorization server,
|
|
567
667
|
// dynamically register a public PKCE client, and persist the provider as the
|
|
@@ -599,7 +699,30 @@ export async function createCoreServices(
|
|
|
599
699
|
// GENERIC proxy: per session it discovers the UTCP manual at /api/agent/utcp
|
|
600
700
|
// over loopback and re-exposes every tool, dispatching calls back through the
|
|
601
701
|
// REST tool surface (so agent logic + metering live there, once).
|
|
602
|
-
|
|
702
|
+
// Connection keys also come as GitHub-shaped links (`gho_…`, kind
|
|
703
|
+
// `github-link`): the same key, minted by the marketplace facade below when
|
|
704
|
+
// a person connects an account on claude.ai, told apart by its stored kind.
|
|
705
|
+
const externalApiKeyService = new ExternalApiKeyService(db, config.externalApiKeyPrefix, {
|
|
706
|
+
[GITHUB_LINK_KEY_KIND]: GITHUB_LINK_KEY_PREFIX,
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
// The facade that lets products which sync marketplaces only from a GitHub
|
|
710
|
+
// Enterprise Server (claude.ai, Cowork) add the per-user marketplace:
|
|
711
|
+
// generated app credentials an Owner registers once, and the connect flow
|
|
712
|
+
// that turns a hexis session into a connection key the product holds.
|
|
713
|
+
// Reuses the MCP flow's signed state and /connect page — see
|
|
714
|
+
// modules/marketplace/github-facade.
|
|
715
|
+
const githubFacadeCredentials = new GitHubFacadeCredentialsService(
|
|
716
|
+
new DbGitHubFacadeCredentialsStore(db, config.secretsEncKey ? new TokenCrypto(config.secretsEncKey) : null),
|
|
717
|
+
);
|
|
718
|
+
const githubFacade = new GitHubFacade({
|
|
719
|
+
credentials: githubFacadeCredentials,
|
|
720
|
+
codes: new DbGitHubFacadeCodeStore(db),
|
|
721
|
+
keys: externalApiKeyService,
|
|
722
|
+
consumers: [CLAUDE_CONSUMER],
|
|
723
|
+
stateSecret: config.jwtSecret,
|
|
724
|
+
publicFrontendUrl: config.publicFrontendUrl,
|
|
725
|
+
});
|
|
603
726
|
const mcpSessionStore = new McpSessionStore();
|
|
604
727
|
const mcpService = new McpService(
|
|
605
728
|
mcpSessionStore,
|
|
@@ -816,6 +939,13 @@ export async function createCoreServices(
|
|
|
816
939
|
pluginIndexService,
|
|
817
940
|
pluginProvisionService,
|
|
818
941
|
joinRequestsService,
|
|
942
|
+
pluginLinkIndex,
|
|
943
|
+
pluginLinksService,
|
|
944
|
+
pluginRenameService,
|
|
945
|
+
marketplaceCompiler,
|
|
946
|
+
marketplaceRepo,
|
|
947
|
+
githubFacade,
|
|
948
|
+
githubFacadeCredentials,
|
|
819
949
|
authService,
|
|
820
950
|
authMiddleware,
|
|
821
951
|
accountErasureService,
|
|
@@ -825,6 +955,7 @@ export async function createCoreServices(
|
|
|
825
955
|
reviewWorkflowService,
|
|
826
956
|
fileLockService,
|
|
827
957
|
workflowService,
|
|
958
|
+
kbSyncService,
|
|
828
959
|
eventBus,
|
|
829
960
|
fileChangeNotifier,
|
|
830
961
|
pendingCommitsService,
|
|
@@ -835,6 +966,7 @@ export async function createCoreServices(
|
|
|
835
966
|
createSyncedGroupsMaterializer,
|
|
836
967
|
updateCheckService,
|
|
837
968
|
secretsVaultService,
|
|
969
|
+
connectionProbeService,
|
|
838
970
|
externalApiKeyService,
|
|
839
971
|
internalTokenService,
|
|
840
972
|
mcpService,
|
package/src/core-config.ts
CHANGED
|
@@ -2,6 +2,7 @@ import dotenv from 'dotenv';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { defaultKbTemplateDir } from './assets.js';
|
|
5
|
+
import { assertKeyDecodesTo32Bytes } from './shared/token-crypto.js';
|
|
5
6
|
|
|
6
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
8
|
dotenv.config({ path: path.resolve(__dirname, '../../../.env') });
|
|
@@ -337,19 +338,25 @@ export class CoreConfig {
|
|
|
337
338
|
.split(/[\s,]+/)
|
|
338
339
|
.map((d) => d.trim().toLowerCase().replace(/^[@.]+/, ''))
|
|
339
340
|
.filter((d) => d.length > 0);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
''
|
|
345
|
-
).trim();
|
|
346
|
-
|
|
341
|
+
// Which variable actually supplied the key decides whose name a bad key
|
|
342
|
+
// is reported under: a legacy deploy still on the fallback chain must be
|
|
343
|
+
// told to fix the variable it set, not one it never heard of.
|
|
344
|
+
const secretsKeySource = (
|
|
345
|
+
['SECRETS_ENC_KEY', 'CONNECTOR_CONFIG_ENC_KEY', 'SHAREPOINT_TOKEN_ENC_KEY'] as const
|
|
346
|
+
).find((name) => (process.env[name] ?? '').trim() !== '');
|
|
347
|
+
this.secretsEncKey = secretsKeySource ? process.env[secretsKeySource]!.trim() : '';
|
|
348
|
+
if (!secretsKeySource) {
|
|
347
349
|
throw new Error(
|
|
348
350
|
'SECRETS_ENC_KEY is required — it encrypts the secrets vault, the MCP OAuth ' +
|
|
349
351
|
'tokens and the git credential saved from the setup screen. Generate one ' +
|
|
350
352
|
`with: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"`,
|
|
351
353
|
);
|
|
352
354
|
}
|
|
355
|
+
// Validate the LENGTH here too, while the winning variable's name is in
|
|
356
|
+
// hand. Every later `new TokenCrypto(config.secretsEncKey)` blames
|
|
357
|
+
// SECRETS_ENC_KEY by default, which is only certainly right because a bad
|
|
358
|
+
// key never gets past this line.
|
|
359
|
+
assertKeyDecodesTo32Bytes(this.secretsEncKey, secretsKeySource);
|
|
353
360
|
this.internalTokenSecret = (process.env.INTERNAL_TOKEN_SECRET || '').trim();
|
|
354
361
|
// Setting DOMAIN declares "the bundled Caddy `https` profile fronts this
|
|
355
362
|
// deployment" — one proxy hop, and the public origin IS that domain. The
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
|
|
6
|
+
import type { WorkspaceService } from '../../workspace/workspace.service.js';
|
|
7
|
+
import { AccessControlService } from '../access-control.service.js';
|
|
8
|
+
|
|
9
|
+
const KB_DIR = 'knowledge-base';
|
|
10
|
+
|
|
11
|
+
async function writeFile(repo: string, rel: string, contents: string): Promise<void> {
|
|
12
|
+
const abs = path.join(repo, rel);
|
|
13
|
+
await fs.mkdir(path.dirname(abs), { recursive: true });
|
|
14
|
+
await fs.writeFile(abs, contents);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* `invalidate()` fires exactly when the tree changes under a model load that
|
|
19
|
+
* is still reading it: a marketplace compile for one caller drops the caches
|
|
20
|
+
* while a compile for another caller is mid-load, or a commit lands while the
|
|
21
|
+
* explorer builds. The load that started on the OLD tree must not store its
|
|
22
|
+
* model after the drop — otherwise every read for the next TTL resolves
|
|
23
|
+
* against a tree that is already gone.
|
|
24
|
+
*/
|
|
25
|
+
describe('AccessControlService — a load that straddles invalidate() never repopulates the cache', () => {
|
|
26
|
+
let root: string;
|
|
27
|
+
const workspaceId = 'ws-invalidate-race';
|
|
28
|
+
|
|
29
|
+
beforeEach(async () => {
|
|
30
|
+
root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-invalidate-race-'));
|
|
31
|
+
});
|
|
32
|
+
afterEach(async () => {
|
|
33
|
+
vi.restoreAllMocks();
|
|
34
|
+
await fs.rm(root, { recursive: true, force: true });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('a read that starts after the drop keeps seeing the new tree once the old load lands', async () => {
|
|
38
|
+
const workspaceDir = path.join(root, workspaceId);
|
|
39
|
+
const repo = path.join(workspaceDir, KB_DIR);
|
|
40
|
+
await writeFile(repo, 'roles.yaml', 'roles:\n Admin:\n - admin@x.io\n');
|
|
41
|
+
await writeFile(repo, 'access.md', '---\nwrite:\n - Admin\n---\n');
|
|
42
|
+
// Notes is closed to zoe on the old tree.
|
|
43
|
+
await writeFile(repo, 'Notes/access.md', '---\nread:\n - Admin\n---\n');
|
|
44
|
+
await writeFile(repo, 'Notes/plan.md', '# plan\n');
|
|
45
|
+
const service = new AccessControlService(
|
|
46
|
+
{ getWorkspacePath: async () => workspaceDir } as unknown as WorkspaceService,
|
|
47
|
+
KB_DIR,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// Hold the OLD load exactly where the walk reads Notes/access.md: the
|
|
51
|
+
// bytes are read now (the closed rules), but the load cannot finish until
|
|
52
|
+
// released — which is what a slow disk or a large tree does for free.
|
|
53
|
+
const realReadFile = fs.readFile.bind(fs);
|
|
54
|
+
let release: () => void = () => undefined;
|
|
55
|
+
const held = new Promise<void>((resolve) => (release = resolve));
|
|
56
|
+
let reachedHold: () => void = () => undefined;
|
|
57
|
+
const reached = new Promise<void>((resolve) => (reachedHold = resolve));
|
|
58
|
+
let holdOnce = true;
|
|
59
|
+
vi.spyOn(fs, 'readFile').mockImplementation(async (file, ...rest) => {
|
|
60
|
+
const result = await (realReadFile as (...a: unknown[]) => Promise<unknown>)(file, ...rest);
|
|
61
|
+
if (holdOnce && String(file).endsWith(path.join('Notes', 'access.md'))) {
|
|
62
|
+
holdOnce = false;
|
|
63
|
+
reachedHold();
|
|
64
|
+
await held;
|
|
65
|
+
}
|
|
66
|
+
return result as never;
|
|
67
|
+
});
|
|
68
|
+
const oldLoad = service.canRead(workspaceId, 'zoe@x.io', 'Notes/plan.md');
|
|
69
|
+
await reached;
|
|
70
|
+
|
|
71
|
+
// The tree moves and the caches are dropped while that load is in flight.
|
|
72
|
+
await writeFile(repo, 'Notes/access.md', '---\nread:\n - Admin\n - Zoe <zoe@x.io>\n---\n');
|
|
73
|
+
service.invalidate(workspaceId);
|
|
74
|
+
try {
|
|
75
|
+
await expect(service.canRead(workspaceId, 'zoe@x.io', 'Notes/plan.md')).resolves.toBe(true);
|
|
76
|
+
} finally {
|
|
77
|
+
// The old load lands (also on a failed assertion, so the test cannot hang).
|
|
78
|
+
release();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// It answers for the tree it read — closed — but must not become the
|
|
82
|
+
// cached model for the reads that follow.
|
|
83
|
+
await expect(oldLoad).resolves.toBe(false);
|
|
84
|
+
await expect(service.canRead(workspaceId, 'zoe@x.io', 'Notes/plan.md')).resolves.toBe(true);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -953,7 +953,7 @@ describe('AccessControlService', () => {
|
|
|
953
953
|
|
|
954
954
|
const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
|
|
955
955
|
const e = await svc.eligibleReaders(workspaceId, 'Knowledge/Foo.md');
|
|
956
|
-
expect(e).toEqual({ restricted: true, principals: [], roles: [], users: [] });
|
|
956
|
+
expect(e).toEqual({ restricted: true, principals: [], roles: [], users: [], publicVia: [] });
|
|
957
957
|
});
|
|
958
958
|
|
|
959
959
|
it('reports restricted=false when read: everyone applies', async () => {
|
|
@@ -963,7 +963,17 @@ describe('AccessControlService', () => {
|
|
|
963
963
|
|
|
964
964
|
const svc = new AccessControlService(stubWorkspaceService(workspaceId, workspaceDir), PROCESS_MAP_DIR);
|
|
965
965
|
const e = await svc.eligibleReaders(workspaceId, 'Knowledge/Foo.md');
|
|
966
|
-
|
|
966
|
+
// The flag says public; the lists still name the grants (write folds into read).
|
|
967
|
+
expect(e).toEqual({
|
|
968
|
+
restricted: false,
|
|
969
|
+
principals: [
|
|
970
|
+
{ name: 'Admin', kind: 'role' },
|
|
971
|
+
{ name: 'everyone', kind: 'role' },
|
|
972
|
+
],
|
|
973
|
+
roles: ['Admin', 'everyone'],
|
|
974
|
+
users: [],
|
|
975
|
+
publicVia: [], // public by a literal line, through no plugin
|
|
976
|
+
});
|
|
967
977
|
});
|
|
968
978
|
|
|
969
979
|
it('restricted=false when a closer everyone grant shadows a farther by-name deny', async () => {
|
|
@@ -978,7 +988,13 @@ describe('AccessControlService', () => {
|
|
|
978
988
|
// node really is readable by everyone — not restricted.
|
|
979
989
|
expect(await svc.canRead(workspaceId, 'felix@example.com', 'Knowledge/Open/Foo.md')).toBe(true);
|
|
980
990
|
const e = await svc.eligibleReaders(workspaceId, 'Knowledge/Open/Foo.md');
|
|
981
|
-
expect(e).toEqual({
|
|
991
|
+
expect(e).toEqual({
|
|
992
|
+
restricted: false,
|
|
993
|
+
principals: [{ name: 'everyone', kind: 'role' }],
|
|
994
|
+
roles: ['everyone'],
|
|
995
|
+
users: [],
|
|
996
|
+
publicVia: [],
|
|
997
|
+
});
|
|
982
998
|
});
|
|
983
999
|
|
|
984
1000
|
it('restricted=true when a same-scope by-name deny carves someone out of read: everyone', async () => {
|