@bevel-software/platform-core-backend 0.14.0 → 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 +99 -8
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +18 -1
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +96 -43
- package/dist/core/create-core-services.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/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/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/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/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 -92
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +6 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +18 -25
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +40 -2
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +227 -54
- 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.service.d.ts +52 -1
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +242 -9
- 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 +9 -9
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +33 -0
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +110 -16
- 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/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__/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 +123 -7
- package/src/core/create-core-services.ts +162 -41
- 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/plugin-principals.ts +137 -0
- package/src/modules/database/core-schema.ts +54 -0
- 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/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 +24 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +2 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +154 -88
- package/src/modules/tool-manuals/tool-manuals.service.ts +14 -23
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +1 -1
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +1 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +2 -2
- 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.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 +239 -56
- package/src/modules/workflow/git/pull-request.service.ts +9 -0
- package/src/modules/workflow/workflow.service.ts +260 -9
- 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 +9 -17
- package/src/modules/workspace/workspace.service.ts +107 -16
- 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__/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/ttl-cache.ts +33 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { PERSONAL_PLUGIN_PREFIX, PLUGIN_MANIFEST_FILE, isPluginIdentifier, pluginDisplayNameOf, pluginManifestName, } from '@bevel-software/platform-shared';
|
|
4
|
+
import { PushNeedsAgentResolutionError } from '../../shared/domain-errors.js';
|
|
5
|
+
import { walkKb } from '../../shared/kb-walk.js';
|
|
6
|
+
import { PLUGIN_TOKEN_PREFIX, canonicalPluginToken, hasAccessFrontmatterExtension, parsePluginPrincipalKey, } from '../access-model/access-grammar.js';
|
|
7
|
+
import { linksWorkspaceId } from './plugin-links.js';
|
|
8
|
+
export class PluginRenameError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
payload;
|
|
11
|
+
constructor(message, status, payload = {}) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.payload = payload;
|
|
15
|
+
this.name = 'PluginRenameError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Renaming a plugin — its identifier, its display name, or both.
|
|
20
|
+
*
|
|
21
|
+
* The identifier (the manifest's `name`) IS the plugin: the marketplace
|
|
22
|
+
* publishes it, the URLs key on it, and every grant of `plugin/<name>/<verb>`
|
|
23
|
+
* spells it. Changing it is therefore a rename of a PRINCIPAL, and a
|
|
24
|
+
* principal that is renamed in one file and not another is two principals,
|
|
25
|
+
* one of which nobody is a member of. So the rename is one commit: the
|
|
26
|
+
* manifest, plus every access entry in the knowledge base that names the old
|
|
27
|
+
* identifier, rewritten to the new one. Membership does not change — the
|
|
28
|
+
* same people hold the same verbs through the new spelling — but the caller
|
|
29
|
+
* still needs write on each file the commit touches: the protected-branch
|
|
30
|
+
* gate checks every path, and a rename that lands in some files and is
|
|
31
|
+
* refused in others is the split it exists to prevent. The refusal names the
|
|
32
|
+
* files, so the manager can ask their editors or an admin.
|
|
33
|
+
*
|
|
34
|
+
* The display name is free text with no consequences: the manifest changes,
|
|
35
|
+
* nothing else does.
|
|
36
|
+
*/
|
|
37
|
+
export class PluginRenameService {
|
|
38
|
+
workspaceService;
|
|
39
|
+
commits;
|
|
40
|
+
accessControl;
|
|
41
|
+
source;
|
|
42
|
+
kbDirName;
|
|
43
|
+
events;
|
|
44
|
+
onChanged;
|
|
45
|
+
constructor(workspaceService, commits, accessControl, source, kbDirName, events, onChanged) {
|
|
46
|
+
this.workspaceService = workspaceService;
|
|
47
|
+
this.commits = commits;
|
|
48
|
+
this.accessControl = accessControl;
|
|
49
|
+
this.source = source;
|
|
50
|
+
this.kbDirName = kbDirName;
|
|
51
|
+
this.events = events;
|
|
52
|
+
this.onChanged = onChanged;
|
|
53
|
+
}
|
|
54
|
+
noteChanged(wsId) {
|
|
55
|
+
noteChangedFor(this.accessControl, this.events, this.onChanged, wsId);
|
|
56
|
+
}
|
|
57
|
+
/** The READ phase must have seen everything it needed; a hole refuses the rename before any write. */
|
|
58
|
+
assertComplete(unreadable) {
|
|
59
|
+
if (unreadable.length === 0)
|
|
60
|
+
return;
|
|
61
|
+
throw new PluginRenameError(`Some of the knowledge base could not be read (${unreadable.join(', ')}), so the rename cannot be checked against every plugin and grant. Try again, or ask an admin.`, 503, { kind: 'incomplete-discovery', unreadable });
|
|
62
|
+
}
|
|
63
|
+
async rename(user, current, patch) {
|
|
64
|
+
const wsId = linksWorkspaceId();
|
|
65
|
+
const kbRoot = path.join(await this.workspaceService.getWorkspacePath(wsId), this.kbDirName);
|
|
66
|
+
// ONE walk of the checkout for everything the rename needs to know:
|
|
67
|
+
// the plugins (discovery's listener) and every file that can carry a
|
|
68
|
+
// grant (this one's), seeing one set of holes. Listing is all that
|
|
69
|
+
// happens here — no file is read, nothing is decided — so it can run
|
|
70
|
+
// before authorization without telling anyone anything.
|
|
71
|
+
const grantFiles = [];
|
|
72
|
+
const grantListener = {
|
|
73
|
+
onFile(dir, name) {
|
|
74
|
+
if (hasAccessFrontmatterExtension(name))
|
|
75
|
+
grantFiles.push(dir ? `${dir}/${name}` : name);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const { discovery, holes } = this.source.walkWith
|
|
79
|
+
? await this.source.walkWith(kbRoot, [grantListener])
|
|
80
|
+
: { discovery: await this.source.discover(kbRoot), holes: (await walkKb(kbRoot, [grantListener])).holes };
|
|
81
|
+
const { plugins } = discovery;
|
|
82
|
+
const unreadable = [...new Set([...discovery.unreadable, ...holes])];
|
|
83
|
+
// Three phases: READ everything, DECIDE, then WRITE. Nothing about the
|
|
84
|
+
// tree — not even that part of it could not be read — reaches a caller
|
|
85
|
+
// before they are known to manage the plugin they name.
|
|
86
|
+
const plugin = plugins.find((p) => p.name === current.trim() && !p.personal && p.exists);
|
|
87
|
+
// Fail closed, like every plugin surface: unknown and not-yours answer alike.
|
|
88
|
+
if (!plugin || !(await this.accessControl.canWrite(wsId, user.email, `${plugin.folder}/access.md`))) {
|
|
89
|
+
throw new PluginRenameError('Unknown plugin', 404, { kind: 'unknown-plugin' });
|
|
90
|
+
}
|
|
91
|
+
if (!plugin.linksAreManaged) {
|
|
92
|
+
throw new PluginRenameError(`${plugin.name} is read from an external plugin format; rename it in that repository.`, 409, { kind: 'read-only' });
|
|
93
|
+
}
|
|
94
|
+
const nextName = patch.name === undefined ? plugin.name : String(patch.name).trim();
|
|
95
|
+
// The rules govern a NEW identifier only. The current one is whatever the
|
|
96
|
+
// manifest says — a hand-written name that predates a rule (a reserved
|
|
97
|
+
// prefix, say) must not block a display-name change, and cannot be
|
|
98
|
+
// "fixed" by a rename that keeps it.
|
|
99
|
+
const identifierChanges = nextName !== plugin.name;
|
|
100
|
+
// A NEW identifier is claimed against EVERY plugin there is and rewritten
|
|
101
|
+
// into every grant there is. A listing with a hole in it — a folder or
|
|
102
|
+
// manifest that exists but could not be read — is neither set: the name
|
|
103
|
+
// could belong to what was not seen, the grant could live there. Fail
|
|
104
|
+
// closed; nothing is written. A display-name change claims nothing and
|
|
105
|
+
// touches one manifest, so it needs no more than its own plugin read.
|
|
106
|
+
if (identifierChanges)
|
|
107
|
+
this.assertComplete(unreadable);
|
|
108
|
+
// An identifier must be its own slug: the marketplace and the collision
|
|
109
|
+
// checks key on `pluginManifestName(name)`, so a name that does not
|
|
110
|
+
// round-trip (longer than the slug's 64 characters, say) would be one
|
|
111
|
+
// thing here and another everywhere it is published.
|
|
112
|
+
if (identifierChanges && (!isPluginIdentifier(nextName) || pluginManifestName(nextName) !== nextName)) {
|
|
113
|
+
throw new PluginRenameError('A plugin identifier is lowercase kebab-case: letters, digits and single hyphens, like "sales-team".', 422, { kind: 'bad-name' });
|
|
114
|
+
}
|
|
115
|
+
if (identifierChanges && nextName.startsWith(PERSONAL_PLUGIN_PREFIX)) {
|
|
116
|
+
throw new PluginRenameError(`The "${PERSONAL_PLUGIN_PREFIX}" namespace is reserved for personal folders. Pick another identifier.`, 422, { kind: 'bad-name' });
|
|
117
|
+
}
|
|
118
|
+
// Taken by SLUG, not by spelling: a bundle may declare a name that is not
|
|
119
|
+
// an identifier, and the marketplace folds every name to its slug — a
|
|
120
|
+
// collision there drops one of the two from the catalog.
|
|
121
|
+
if (identifierChanges && plugins.some((p) => p !== plugin && pluginManifestName(p.name) === nextName)) {
|
|
122
|
+
throw new PluginRenameError(`A plugin named "${nextName}" already exists.`, 409, { kind: 'name-taken' });
|
|
123
|
+
}
|
|
124
|
+
const folderName = path.posix.basename(plugin.folder);
|
|
125
|
+
const nextDisplay = patch.displayName === undefined ? plugin.displayName : String(patch.displayName).trim();
|
|
126
|
+
// The manifest, with everything else in it kept.
|
|
127
|
+
const manifest = { ...(plugin.manifest ?? {}), name: nextName };
|
|
128
|
+
if (nextDisplay && nextDisplay !== folderName)
|
|
129
|
+
manifest.displayName = nextDisplay;
|
|
130
|
+
else
|
|
131
|
+
delete manifest.displayName;
|
|
132
|
+
const manifestRel = `${this.kbDirName}/${plugin.folder}/${PLUGIN_MANIFEST_FILE}`;
|
|
133
|
+
const writes = [
|
|
134
|
+
{ rel: manifestRel, text: `${JSON.stringify(manifest, null, 2)}\n`, before: plugin.manifestText },
|
|
135
|
+
];
|
|
136
|
+
if (identifierChanges) {
|
|
137
|
+
// Every access entry in the knowledge base that names the old
|
|
138
|
+
// principal — in a folder's access.md or in the own frontmatter of any
|
|
139
|
+
// file kind the resolver reads grants from (`.md`, `.tool`, whatever
|
|
140
|
+
// an overlay registered). The files came from the walk above, whose
|
|
141
|
+
// holes have already refused: a folder that could not be listed would
|
|
142
|
+
// leave the old spelling live in it, and a principal renamed in some
|
|
143
|
+
// files and not others is two principals. A file the walk listed but
|
|
144
|
+
// that cannot be opened is the same hole: every such file is
|
|
145
|
+
// collected, then refused together.
|
|
146
|
+
const unopened = [];
|
|
147
|
+
for (const rel of grantFiles) {
|
|
148
|
+
const abs = path.join(kbRoot, rel);
|
|
149
|
+
let before;
|
|
150
|
+
try {
|
|
151
|
+
before = await fs.readFile(abs, 'utf-8');
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
unopened.push(rel);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const after = renamePluginPrincipalInText(before, plugin.name, nextName);
|
|
158
|
+
if (after !== before)
|
|
159
|
+
writes.push({ rel: `${this.kbDirName}/${rel}`, text: after, before });
|
|
160
|
+
}
|
|
161
|
+
this.assertComplete(unopened);
|
|
162
|
+
const denied = [];
|
|
163
|
+
for (const w of writes.slice(1)) {
|
|
164
|
+
const repoRel = w.rel.slice(this.kbDirName.length + 1);
|
|
165
|
+
if (!(await this.accessControl.canWrite(wsId, user.email, repoRel)))
|
|
166
|
+
denied.push(repoRel);
|
|
167
|
+
}
|
|
168
|
+
if (denied.length > 0) {
|
|
169
|
+
throw new PluginRenameError(`Renaming ${plugin.name} would rewrite grants in files you can't edit: ${denied.join(', ')}. Ask their editors, or an admin.`, 409, { kind: 'needs-write', files: denied });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Writes and commit share ONE failure envelope: whichever of them fails,
|
|
173
|
+
// the working tree goes back to what origin has — a half-written batch
|
|
174
|
+
// is as much a split principal as a refused commit.
|
|
175
|
+
try {
|
|
176
|
+
for (const w of writes)
|
|
177
|
+
await this.workspaceService.writeFile(wsId, w.rel, w.text);
|
|
178
|
+
const summary = identifierChanges
|
|
179
|
+
? `Rename plugin ${plugin.name} to ${nextName}`
|
|
180
|
+
: `Rename plugin ${plugin.name}: display name`;
|
|
181
|
+
await this.commits.commitChanges(wsId, user, summary, writes.map((w) => w.rel));
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
// One failure is NOT a failed commit: the commit landed locally and only
|
|
185
|
+
// the push did not (the typed hand-off the workflow throws). Restoring
|
|
186
|
+
// the old bytes then would stack an uncommitted inverse of a real
|
|
187
|
+
// commit; the recovery flow owns that state, so it is left alone — and
|
|
188
|
+
// since the tree DID change, every cache keyed on the old identity is
|
|
189
|
+
// dropped before the error goes up, exactly as on success.
|
|
190
|
+
if (err instanceof PushNeedsAgentResolutionError) {
|
|
191
|
+
this.noteChanged(wsId);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
for (const w of writes) {
|
|
195
|
+
if (w.before !== null)
|
|
196
|
+
await this.workspaceService.writeFile(wsId, w.rel, w.before).catch(() => undefined);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
this.noteChanged(wsId);
|
|
202
|
+
return {
|
|
203
|
+
name: nextName,
|
|
204
|
+
displayName: pluginDisplayNameOf(manifest, folderName),
|
|
205
|
+
rewritten: writes.slice(1).map((w) => w.rel.slice(this.kbDirName.length + 1)),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* The tree changed: drop the resolver's model and the plugin caches, and
|
|
211
|
+
* tell every session. The ONE place this happens, for the landed commit and
|
|
212
|
+
* for the committed-but-unpushed one alike.
|
|
213
|
+
*/
|
|
214
|
+
function noteChangedFor(accessControl, events, onChanged, wsId) {
|
|
215
|
+
accessControl.invalidate(wsId);
|
|
216
|
+
events?.emit({ kind: 'fs-tree-changed', workspaceId: wsId, branch: linksWorkspaceIdBranch() });
|
|
217
|
+
onChanged?.();
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Every access entry line naming `plugin/<old>/<verb>` — in ANY spelling the
|
|
221
|
+
* parser accepts — rewritten to `plugin/<next>/<verb>`, the rest of the
|
|
222
|
+
* line (indent, `- `, a `deny` prefix, the line ending) kept. Lines that are
|
|
223
|
+
* not such an entry are untouched, so the file's own formatting survives.
|
|
224
|
+
*/
|
|
225
|
+
export function renamePluginPrincipalInText(text, oldName, nextName) {
|
|
226
|
+
const oldSlug = pluginManifestName(oldName);
|
|
227
|
+
return text
|
|
228
|
+
.split('\n')
|
|
229
|
+
.map((line) => {
|
|
230
|
+
const m = /^(\s*-\s+(?:deny\s+)?)(\S.*?)(\s*)$/i.exec(line);
|
|
231
|
+
if (!m)
|
|
232
|
+
return line;
|
|
233
|
+
const key = canonicalPluginToken(m[2]);
|
|
234
|
+
const parsed = key === null ? null : parsePluginPrincipalKey(key);
|
|
235
|
+
if (!parsed || parsed.slug !== oldSlug)
|
|
236
|
+
return line;
|
|
237
|
+
return `${m[1]}${PLUGIN_TOKEN_PREFIX}${nextName}/${parsed.verb}${m[3]}`;
|
|
238
|
+
})
|
|
239
|
+
.join('\n');
|
|
240
|
+
}
|
|
241
|
+
function linksWorkspaceIdBranch() {
|
|
242
|
+
// The default branch's workspace id IS its encoded branch name.
|
|
243
|
+
return decodeURIComponent(linksWorkspaceId());
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=plugin-rename.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-rename.service.js","sourceRoot":"","sources":["../../../src/modules/plugins/plugin-rename.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
* via Manage access, which makes the CR moot). To agents these are plain
|
|
33
33
|
* change requests; only the UI dresses them up.
|
|
34
34
|
*/
|
|
35
|
+
export type { PluginMembership } from '../skills/skills.contract.js';
|
|
35
36
|
/** Access-rule principals as the resolver hands them back. */
|
|
36
37
|
export interface ResolvedPrincipals {
|
|
37
38
|
roles: string[];
|
|
@@ -45,10 +46,14 @@ export interface ResolvedReaders extends ResolvedPrincipals {
|
|
|
45
46
|
}
|
|
46
47
|
/** One plugin as `GET /api/plugins` reports it, resolved for ONE caller. */
|
|
47
48
|
export interface PluginSummary {
|
|
48
|
-
/**
|
|
49
|
+
/** The plugin's identity — its manifest name, e.g. `gtm`. */
|
|
49
50
|
name: string;
|
|
51
|
+
/** What a person sees it called, e.g. `GTM`. */
|
|
52
|
+
displayName: string;
|
|
50
53
|
/** Repo-relative constituent folders, e.g. `['Plugins/GTM']`. */
|
|
51
54
|
folders: string[];
|
|
55
|
+
/** Whether this platform writes the plugin's links — see `PluginCatalogEntry`. */
|
|
56
|
+
linksAreManaged: boolean;
|
|
52
57
|
/**
|
|
53
58
|
* Per-caller: the caller can read the FOLDER (membership). Every returned
|
|
54
59
|
* plugin has at least one of `canRead` / `canWrite` / discoverability; a
|
|
@@ -71,6 +76,16 @@ export interface PluginSummary {
|
|
|
71
76
|
/** Caller-INDEPENDENT total (the plugin's whole content, not the caller's slice). */
|
|
72
77
|
skillCount: number;
|
|
73
78
|
toolCount: number;
|
|
79
|
+
/**
|
|
80
|
+
* Caller-INDEPENDENT: how many of the plugin's LINKED skills its members
|
|
81
|
+
* cannot read — the link is in the manifest, but the skill folder no
|
|
82
|
+
* longer grants the plugin's readers. Counted here, from the unfiltered
|
|
83
|
+
* link index, because the people who most need the warning are the
|
|
84
|
+
* plugin's managers, and they are exactly the people a missing grant
|
|
85
|
+
* locks out: a count derived from what the caller can read would be zero
|
|
86
|
+
* for them. Zero for a plugin whose links are not managed here.
|
|
87
|
+
*/
|
|
88
|
+
brokenLinks: number;
|
|
74
89
|
/** For display: "Run by …" (fallback chain: owners → writers → 'the workspace admins'). */
|
|
75
90
|
owners: ResolvedPrincipals;
|
|
76
91
|
writers: ResolvedPrincipals;
|
|
@@ -89,10 +104,21 @@ export interface PluginSummary {
|
|
|
89
104
|
* appears at all) are resolved per request in the route.
|
|
90
105
|
*/
|
|
91
106
|
export interface PluginCatalogEntry {
|
|
107
|
+
/** The plugin's identity — its manifest name. */
|
|
92
108
|
name: string;
|
|
109
|
+
/** What a person sees it called — the manifest's `displayName`, else the folder name. */
|
|
110
|
+
displayName: string;
|
|
93
111
|
folders: string[];
|
|
112
|
+
/**
|
|
113
|
+
* Whether this platform writes the plugin's links (a native `plugin.json`)
|
|
114
|
+
* — false for a plugin read from an external format, whose links are
|
|
115
|
+
* edited in that repository and which the link endpoints refuse.
|
|
116
|
+
*/
|
|
117
|
+
linksAreManaged: boolean;
|
|
94
118
|
skillCount: number;
|
|
95
119
|
toolCount: number;
|
|
120
|
+
/** Linked skills the members cannot read — see `PluginSummary.brokenLinks`. */
|
|
121
|
+
brokenLinks: number;
|
|
96
122
|
owners: ResolvedPrincipals;
|
|
97
123
|
writers: ResolvedPrincipals;
|
|
98
124
|
readers: ResolvedReaders;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.contract.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/plugins.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,
|
|
1
|
+
{"version":3,"file":"plugins.contract.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/plugins.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,8DAA8D;AAC9D,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kFAAkF;IAClF,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,EAAE,eAAe,CAAC;IACzB;;;OAGG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB,yEAAyE;IACzE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,kFAAkF;IAClF,OAAO,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IACzC,wFAAwF;IACxF,UAAU,IAAI,IAAI,CAAC;CACpB"}
|
|
@@ -4,6 +4,8 @@ import { type AuthUser, type IWorkflowService } from '@bevel-software/platform-s
|
|
|
4
4
|
import type { IAccessControl } from '../access/access-control.interface.js';
|
|
5
5
|
import type { WorkspaceService } from '../workspace/workspace.service.js';
|
|
6
6
|
import { type PluginProvisionService } from './plugin-provision.service.js';
|
|
7
|
+
import { type PluginLinksService } from './plugin-links.service.js';
|
|
8
|
+
import { type PluginRenameService } from './plugin-rename.service.js';
|
|
7
9
|
import type { JoinRequestsService } from './join-requests.service.js';
|
|
8
10
|
import type { IPluginIndexService } from './plugins.contract.js';
|
|
9
11
|
/**
|
|
@@ -38,5 +40,9 @@ import type { IPluginIndexService } from './plugins.contract.js';
|
|
|
38
40
|
* middleware change can never silently un-gate one. Nothing here is reachable
|
|
39
41
|
* with an agent connection key or a manual-auth bearer.
|
|
40
42
|
*/
|
|
41
|
-
export declare function createPluginsRoutes(pluginIndex: IPluginIndexService, accessControl: IAccessControl, workflow: IWorkflowService, workspaceService: WorkspaceService, joinRequests: JoinRequestsService, provision: PluginProvisionService, kbDirName: string, resolveUser: (req: express.Request) => Promise<AuthUser | null
|
|
43
|
+
export declare function createPluginsRoutes(pluginIndex: IPluginIndexService, accessControl: IAccessControl, workflow: IWorkflowService, workspaceService: WorkspaceService, joinRequests: JoinRequestsService, provision: PluginProvisionService, kbDirName: string, resolveUser: (req: express.Request) => Promise<AuthUser | null>,
|
|
44
|
+
/** Optional: a host without the link machinery simply has no link routes. */
|
|
45
|
+
links?: PluginLinksService,
|
|
46
|
+
/** Optional: a host without it has no rename route. */
|
|
47
|
+
rename?: PluginRenameService): express.Router;
|
|
42
48
|
//# sourceMappingURL=plugins.routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/plugins.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,4BAA4B,CAAC;AACpC,OAAO,EAGL,KAAK,QAAQ,EAEb,KAAK,gBAAgB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAClG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAGV,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,mBAAmB,EAChC,aAAa,EAAE,cAAc,EAC7B,QAAQ,EAAE,gBAAgB,EAC1B,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,mBAAmB,EACjC,SAAS,EAAE,sBAAsB,EACjC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"plugins.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/plugins/plugins.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,4BAA4B,CAAC;AACpC,OAAO,EAGL,KAAK,QAAQ,EAEb,KAAK,gBAAgB,EACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAClG,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAGV,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,mBAAmB,EAChC,aAAa,EAAE,cAAc,EAC7B,QAAQ,EAAE,gBAAgB,EAC1B,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,mBAAmB,EACjC,SAAS,EAAE,sBAAsB,EACjC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC/D,6EAA6E;AAC7E,KAAK,CAAC,EAAE,kBAAkB;AAC1B,uDAAuD;AACvD,MAAM,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,MAAM,CAgehB"}
|
|
@@ -5,6 +5,8 @@ import { spliceGrant } from '../access-model/access-splice.js';
|
|
|
5
5
|
import { WorkflowDomainError } from '../../shared/domain-errors.js';
|
|
6
6
|
import { pluginsWorkspaceId } from './plugins.service.js';
|
|
7
7
|
import { PluginProvisionError } from './plugin-provision.service.js';
|
|
8
|
+
import { PluginLinkError } from './plugin-links.service.js';
|
|
9
|
+
import { PluginRenameError } from './plugin-rename.service.js';
|
|
8
10
|
/**
|
|
9
11
|
* Browser-facing (JWT) plugin routes, mounted behind `authMiddleware`:
|
|
10
12
|
*
|
|
@@ -37,12 +39,111 @@ import { PluginProvisionError } from './plugin-provision.service.js';
|
|
|
37
39
|
* middleware change can never silently un-gate one. Nothing here is reachable
|
|
38
40
|
* with an agent connection key or a manual-auth bearer.
|
|
39
41
|
*/
|
|
40
|
-
export function createPluginsRoutes(pluginIndex, accessControl, workflow, workspaceService, joinRequests, provision, kbDirName, resolveUser
|
|
42
|
+
export function createPluginsRoutes(pluginIndex, accessControl, workflow, workspaceService, joinRequests, provision, kbDirName, resolveUser,
|
|
43
|
+
/** Optional: a host without the link machinery simply has no link routes. */
|
|
44
|
+
links,
|
|
45
|
+
/** Optional: a host without it has no rename route. */
|
|
46
|
+
rename) {
|
|
41
47
|
const router = express.Router();
|
|
48
|
+
/**
|
|
49
|
+
* Rename a plugin — its identifier, its display name, or both. The
|
|
50
|
+
* MANAGER's verb (write on the folder's access.md, the gate linking uses).
|
|
51
|
+
* An identifier change rewrites every grant naming the old identifier in
|
|
52
|
+
* the same commit; see `PluginRenameService`.
|
|
53
|
+
*
|
|
54
|
+
* PATCH /api/plugins/:name { name?, displayName? } → { name, displayName, rewritten }
|
|
55
|
+
*/
|
|
56
|
+
if (rename) {
|
|
57
|
+
router.patch('/plugins/:name', async (req, res) => {
|
|
58
|
+
if (!req.userEmail) {
|
|
59
|
+
res.status(401).json({ error: 'Unauthenticated' });
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const user = await resolveUser(req);
|
|
63
|
+
if (!user) {
|
|
64
|
+
res.status(401).json({ error: 'Unauthenticated' });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const body = (req.body ?? {});
|
|
68
|
+
try {
|
|
69
|
+
res.json(await rename.rename(user, String(req.params.name), { name: body.name, displayName: body.displayName }));
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
if (err instanceof PluginRenameError) {
|
|
73
|
+
res.status(err.status).json({ error: err.message, ...err.payload });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (err instanceof WorkflowDomainError) {
|
|
77
|
+
res.status(err.status).json({ error: err.message, ...(err.payload ?? {}) });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
console.error('[plugins] rename failed:', err);
|
|
81
|
+
res.status(500).json({ error: 'Failed to rename the plugin' });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Linking shared skills — see `PluginLinksService` for the two-sided write.
|
|
87
|
+
*
|
|
88
|
+
* POST /api/plugins/:name/links { skillPath } → { root, skills }
|
|
89
|
+
* DELETE /api/plugins/:name/links?skillPath= → { root, revoked }
|
|
90
|
+
* POST /api/plugins/:name/links/repair { skillPath } → { root }
|
|
91
|
+
*
|
|
92
|
+
* Refusals carry a `kind` the UI branches on — `needs-skill-write` (409) is
|
|
93
|
+
* the one that becomes "request write access".
|
|
94
|
+
*/
|
|
95
|
+
if (links) {
|
|
96
|
+
const linkOp = async (req, res, op, skillPathOf) => {
|
|
97
|
+
if (!req.userEmail) {
|
|
98
|
+
res.status(401).json({ error: 'Unauthenticated' });
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const user = await resolveUser(req);
|
|
102
|
+
if (!user) {
|
|
103
|
+
res.status(401).json({ error: 'Unauthenticated' });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const skillPath = skillPathOf(req);
|
|
107
|
+
if (typeof skillPath !== 'string' || !skillPath.trim()) {
|
|
108
|
+
res.status(400).json({ error: 'skillPath is required' });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
res.json(await op(user, String(req.params.name), skillPath));
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (err instanceof PluginLinkError) {
|
|
116
|
+
res.status(err.status).json({ error: err.message, ...err.payload });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (err instanceof WorkflowDomainError) {
|
|
120
|
+
res.status(err.status).json({ error: err.message, ...(err.payload ?? {}) });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
console.error('[plugins] link operation failed:', err);
|
|
124
|
+
res.status(500).json({ error: 'Failed to update the plugin\'s links' });
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const bodyPath = (req) => (req.body ?? {}).skillPath;
|
|
128
|
+
router.post('/plugins/:name/links', (req, res) => linkOp(req, res, (u, p, s) => links.link(u, p, s), bodyPath));
|
|
129
|
+
router.post('/plugins/:name/links/repair', (req, res) => linkOp(req, res, (u, p, s) => links.repair(u, p, s), bodyPath));
|
|
130
|
+
router.delete('/plugins/:name/links', (req, res) => linkOp(req, res, (u, p, s) => links.unlink(u, p, s), (r) => r.query.skillPath));
|
|
131
|
+
}
|
|
42
132
|
/** The folder-chain probe for MEMBERSHIP — the folder itself. */
|
|
43
133
|
const memberProbe = (folder) => folder;
|
|
44
134
|
/** The FILE probe for discovery/management — the folder's access.md. */
|
|
45
135
|
const accessMdOf = (folder) => `${folder}/access.md`;
|
|
136
|
+
/** A plugin folder's path BELOW the plugins root: `GTM`, or `teams/deep`. */
|
|
137
|
+
const folderBelowRoot = (folder) => folder.slice(folder.indexOf('/') + 1);
|
|
138
|
+
/**
|
|
139
|
+
* What a join request is keyed by: the plugin's primary FOLDER path below
|
|
140
|
+
* the root, not its identity. The request writes into that folder's rules;
|
|
141
|
+
* a top-level folder keys exactly as every join branch already on a remote
|
|
142
|
+
* was cut (its name), a nested one by its whole path, so two plugins whose
|
|
143
|
+
* folders share a basename never share a branch; and a rename of the
|
|
144
|
+
* identity moves no folder, so it orphans no open request.
|
|
145
|
+
*/
|
|
146
|
+
const joinKeyOf = (g) => folderBelowRoot(g.folders[0]);
|
|
46
147
|
const probesFor = (plugins) => [
|
|
47
148
|
...new Set(plugins.flatMap((g) => g.folders.flatMap((f) => [memberProbe(f), accessMdOf(f)]))),
|
|
48
149
|
];
|
|
@@ -90,15 +191,18 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
90
191
|
const discoverable = member || any(readable, g, accessMdOf);
|
|
91
192
|
if (!member && !manager && !discoverable)
|
|
92
193
|
continue; // absent — fail closed
|
|
93
|
-
const joinCr = member ? null : openJoinCr(mine, email, g
|
|
194
|
+
const joinCr = member ? null : openJoinCr(mine, email, joinKeyOf(g));
|
|
94
195
|
plugins.push({
|
|
95
196
|
name: g.name,
|
|
197
|
+
displayName: g.displayName,
|
|
96
198
|
folders: g.folders,
|
|
97
199
|
canRead: member,
|
|
98
200
|
canWrite: manager,
|
|
99
201
|
isOwner: owner,
|
|
202
|
+
linksAreManaged: g.linksAreManaged,
|
|
100
203
|
skillCount: g.skillCount,
|
|
101
204
|
toolCount: g.toolCount,
|
|
205
|
+
brokenLinks: g.brokenLinks,
|
|
102
206
|
owners: g.owners,
|
|
103
207
|
writers: g.writers,
|
|
104
208
|
readers: g.readers,
|
|
@@ -198,7 +302,7 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
198
302
|
res.status(401).json({ error: 'Unauthenticated' });
|
|
199
303
|
return;
|
|
200
304
|
}
|
|
201
|
-
//
|
|
305
|
+
// By identity — the manifest name the catalog keys on.
|
|
202
306
|
const plugin = (await pluginIndex.catalog()).find((g) => g.name === req.params.name);
|
|
203
307
|
const wsId = pluginsWorkspaceId();
|
|
204
308
|
const ownerVerdicts = plugin
|
|
@@ -208,7 +312,10 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
208
312
|
res.status(404).json({ error: 'Unknown plugin', kind: 'unknown-plugin' });
|
|
209
313
|
return;
|
|
210
314
|
}
|
|
211
|
-
|
|
315
|
+
// Provisioning works on FOLDERS (it created one); the identity only
|
|
316
|
+
// found the plugin. The whole path below the root, so a nested plugin
|
|
317
|
+
// is deleted where it is.
|
|
318
|
+
await provision.deletePlugin(user, folderBelowRoot(plugin.folders[0]));
|
|
212
319
|
pluginIndex.invalidate();
|
|
213
320
|
res.json({ ok: true });
|
|
214
321
|
}
|
|
@@ -234,7 +341,7 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
234
341
|
return;
|
|
235
342
|
}
|
|
236
343
|
const catalog = await pluginIndex.catalog();
|
|
237
|
-
//
|
|
344
|
+
// By identity — the manifest name the catalog keys on.
|
|
238
345
|
const plugin = catalog.find((g) => g.name === req.params.name);
|
|
239
346
|
const wsId = pluginsWorkspaceId();
|
|
240
347
|
// Same ANY-folder shape `GET /plugins` resolves with, so a plugin can
|
|
@@ -258,8 +365,8 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
258
365
|
// summary's `folders[0]` names and the banner's touched-path check
|
|
259
366
|
// expects.
|
|
260
367
|
const folder = plugin.folders[0];
|
|
261
|
-
const branch = joinBranchFor(email, plugin
|
|
262
|
-
const existing = openJoinCr(await workflow.listChangeRequestsAuthoredBy(email), email, plugin
|
|
368
|
+
const branch = joinBranchFor(email, joinKeyOf(plugin));
|
|
369
|
+
const existing = openJoinCr(await workflow.listChangeRequestsAuthoredBy(email), email, joinKeyOf(plugin));
|
|
263
370
|
if (existing) {
|
|
264
371
|
res.json({ ok: true, number: existing.number });
|
|
265
372
|
return;
|
|
@@ -278,13 +385,14 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
278
385
|
const spliced = spliceGrant(current, 'read', { kind: 'user', email: user.email, displayName: user.name }, { target: 'folder' });
|
|
279
386
|
if (spliced.changed) {
|
|
280
387
|
await workspaceService.writeFile(ws.id, accessPath, spliced.text);
|
|
281
|
-
await workflow.commitChanges(ws.id, user, `Request access to ${plugin.
|
|
388
|
+
await workflow.commitChanges(ws.id, user, `Request access to ${plugin.displayName}`);
|
|
282
389
|
}
|
|
283
390
|
const detail = await workflow.openChangeRequest(ws.id, user, {
|
|
284
391
|
sourceBranch: branch,
|
|
285
392
|
targetBranch: DEFAULT_BRANCH,
|
|
286
|
-
|
|
287
|
-
|
|
393
|
+
// People read these: the display name, not the identifier.
|
|
394
|
+
title: `Join request: ${plugin.displayName}`,
|
|
395
|
+
description: `${user.name} asked to join ${plugin.displayName}. A manager of the plugin accepts by ` +
|
|
288
396
|
`granting the access this branch proposes; the request closes itself once ` +
|
|
289
397
|
`every proposal has landed.`,
|
|
290
398
|
});
|
|
@@ -338,7 +446,7 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
338
446
|
return;
|
|
339
447
|
const crs = await workflow.listChangeRequests();
|
|
340
448
|
res.json({
|
|
341
|
-
requests: await joinRequests.list(ctx.plugin
|
|
449
|
+
requests: await joinRequests.list(joinKeyOf(ctx.plugin), ctx.folder, crs, ctx.user),
|
|
342
450
|
});
|
|
343
451
|
}
|
|
344
452
|
catch (err) {
|
|
@@ -367,7 +475,7 @@ export function createPluginsRoutes(pluginIndex, accessControl, workflow, worksp
|
|
|
367
475
|
res.status(404).json({ error: 'Not found' });
|
|
368
476
|
return;
|
|
369
477
|
}
|
|
370
|
-
res.json({ closed: await joinRequests.reconcile(ctx.plugin
|
|
478
|
+
res.json({ closed: await joinRequests.reconcile(joinKeyOf(ctx.plugin), ctx.folder, cr, ctx.user) });
|
|
371
479
|
}
|
|
372
480
|
catch (err) {
|
|
373
481
|
console.error('[plugins] failed to reconcile a join request:', err);
|