@bevel-software/platform-core-backend 0.15.1 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +4 -4
- package/dist/core/catalog-cache-invalidation.d.ts +16 -0
- package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
- package/dist/core/catalog-cache-invalidation.js +6 -1
- package/dist/core/catalog-cache-invalidation.js.map +1 -1
- package/dist/core/catalog-revision.d.ts +39 -0
- package/dist/core/catalog-revision.d.ts.map +1 -0
- package/dist/core/catalog-revision.js +94 -0
- package/dist/core/catalog-revision.js.map +1 -0
- package/dist/core/create-core-server.d.ts +7 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +221 -75
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +52 -2
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +222 -87
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +138 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +218 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/public-config.d.ts +82 -0
- package/dist/core/public-config.d.ts.map +1 -0
- package/dist/core/public-config.js +78 -0
- package/dist/core/public-config.js.map +1 -0
- package/dist/core/readiness.d.ts +86 -0
- package/dist/core/readiness.d.ts.map +1 -0
- package/dist/core/readiness.js +56 -0
- package/dist/core/readiness.js.map +1 -0
- package/dist/core-config.d.ts +30 -0
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +64 -2
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +215 -11
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +57 -11
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +616 -155
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-mutation.service.d.ts +71 -5
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
- package/dist/modules/access/access-mutation.service.js +161 -13
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-view.d.ts +147 -0
- package/dist/modules/access/access-view.d.ts.map +1 -0
- package/dist/modules/access/access-view.js +211 -0
- package/dist/modules/access/access-view.js.map +1 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +255 -79
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/admin-locked-commit.d.ts +2 -3
- package/dist/modules/access/admin-locked-commit.d.ts.map +1 -1
- package/dist/modules/access/admin-locked-commit.js +9 -8
- package/dist/modules/access/admin-locked-commit.js.map +1 -1
- package/dist/modules/access/admin-route-helpers.d.ts.map +1 -1
- package/dist/modules/access/admin-route-helpers.js +4 -4
- package/dist/modules/access/admin-route-helpers.js.map +1 -1
- package/dist/modules/access/change-read-gate.d.ts +53 -0
- package/dist/modules/access/change-read-gate.d.ts.map +1 -0
- package/dist/modules/access/change-read-gate.js +134 -0
- package/dist/modules/access/change-read-gate.js.map +1 -0
- package/dist/modules/access/creator-access.d.ts +33 -39
- package/dist/modules/access/creator-access.d.ts.map +1 -1
- package/dist/modules/access/creator-access.js +92 -119
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
- package/dist/modules/access/directory-sync-bot.js +3 -1
- package/dist/modules/access/directory-sync-bot.js.map +1 -1
- package/dist/modules/access/groups-admin.service.d.ts +3 -3
- package/dist/modules/access/groups-admin.service.js +2 -2
- package/dist/modules/access/reference-scan.d.ts +1 -1
- package/dist/modules/access/reference-scan.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.js +5 -4
- package/dist/modules/access/reference-scan.js.map +1 -1
- package/dist/modules/access/roles-admin.service.d.ts +72 -13
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +71 -13
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/access/synced-groups-committer.d.ts.map +1 -1
- package/dist/modules/access/synced-groups-committer.js +8 -6
- package/dist/modules/access/synced-groups-committer.js.map +1 -1
- package/dist/modules/access/synced-groups-writer.d.ts.map +1 -1
- package/dist/modules/access/synced-groups-writer.js +3 -8
- package/dist/modules/access/synced-groups-writer.js.map +1 -1
- package/dist/modules/access/user-access-removal.service.d.ts +209 -0
- package/dist/modules/access/user-access-removal.service.d.ts.map +1 -0
- package/dist/modules/access/user-access-removal.service.js +662 -0
- package/dist/modules/access/user-access-removal.service.js.map +1 -0
- package/dist/modules/access-model/access-errors.d.ts +32 -1
- package/dist/modules/access-model/access-errors.d.ts.map +1 -1
- package/dist/modules/access-model/access-errors.js +38 -11
- package/dist/modules/access-model/access-errors.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +49 -24
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +68 -48
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/access-model/access-splice.d.ts.map +1 -1
- package/dist/modules/access-model/access-splice.js +18 -18
- package/dist/modules/access-model/access-splice.js.map +1 -1
- package/dist/modules/access-model/access-template.d.ts +22 -0
- package/dist/modules/access-model/access-template.d.ts.map +1 -0
- package/dist/modules/access-model/access-template.js +42 -0
- package/dist/modules/access-model/access-template.js.map +1 -0
- package/dist/modules/access-model/change-gate.d.ts +65 -0
- package/dist/modules/access-model/change-gate.d.ts.map +1 -0
- package/dist/modules/access-model/change-gate.js +25 -0
- package/dist/modules/access-model/change-gate.js.map +1 -0
- package/dist/modules/access-model/creator.d.ts +13 -16
- package/dist/modules/access-model/creator.d.ts.map +1 -1
- package/dist/modules/access-model/creator.js.map +1 -1
- package/dist/modules/access-model/frontmatter-lines.d.ts +27 -0
- package/dist/modules/access-model/frontmatter-lines.d.ts.map +1 -0
- package/dist/modules/access-model/frontmatter-lines.js +74 -0
- package/dist/modules/access-model/frontmatter-lines.js.map +1 -0
- package/dist/modules/access-model/plugin-principals.d.ts +5 -3
- package/dist/modules/access-model/plugin-principals.d.ts.map +1 -1
- package/dist/modules/access-model/plugin-principals.js +11 -17
- package/dist/modules/access-model/plugin-principals.js.map +1 -1
- package/dist/modules/access-model/roles-yaml-guard.d.ts +73 -2
- package/dist/modules/access-model/roles-yaml-guard.d.ts.map +1 -1
- package/dist/modules/access-model/roles-yaml-guard.js +153 -3
- package/dist/modules/access-model/roles-yaml-guard.js.map +1 -1
- package/dist/modules/admin/admin-access.service.d.ts.map +1 -1
- package/dist/modules/admin/admin-access.service.js +5 -2
- package/dist/modules/admin/admin-access.service.js.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +21 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.js +38 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -0
- package/dist/modules/agent-instructions/compose.d.ts +71 -0
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -0
- package/dist/modules/agent-instructions/compose.js +234 -0
- package/dist/modules/agent-instructions/compose.js.map +1 -0
- package/dist/modules/agent-instructions/index.d.ts +4 -0
- package/dist/modules/agent-instructions/index.d.ts.map +1 -0
- package/dist/modules/agent-instructions/index.js +4 -0
- package/dist/modules/agent-instructions/index.js.map +1 -0
- package/dist/modules/agent-instructions/read-preamble.d.ts +37 -0
- package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -0
- package/dist/modules/agent-instructions/read-preamble.js +81 -0
- package/dist/modules/agent-instructions/read-preamble.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts +54 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -0
- package/dist/modules/audit/agent-audit.service.js +290 -0
- package/dist/modules/audit/agent-audit.service.js.map +1 -0
- package/dist/modules/audit/agent-rest-audit.middleware.d.ts +40 -0
- package/dist/modules/audit/agent-rest-audit.middleware.d.ts.map +1 -0
- package/dist/modules/audit/agent-rest-audit.middleware.js +75 -0
- package/dist/modules/audit/agent-rest-audit.middleware.js.map +1 -0
- package/dist/modules/audit/audit.contract.d.ts +145 -0
- package/dist/modules/audit/audit.contract.d.ts.map +1 -0
- package/dist/modules/audit/audit.contract.js +35 -0
- package/dist/modules/audit/audit.contract.js.map +1 -0
- package/dist/modules/audit/audit.routes.d.ts +21 -0
- package/dist/modules/audit/audit.routes.d.ts.map +1 -0
- package/dist/modules/audit/audit.routes.js +157 -0
- package/dist/modules/audit/audit.routes.js.map +1 -0
- package/dist/modules/audit/event-classifier.d.ts +52 -0
- package/dist/modules/audit/event-classifier.d.ts.map +1 -0
- package/dist/modules/audit/event-classifier.js +123 -0
- package/dist/modules/audit/event-classifier.js.map +1 -0
- package/dist/modules/audit/index.d.ts +7 -0
- package/dist/modules/audit/index.d.ts.map +1 -0
- package/dist/modules/audit/index.js +7 -0
- package/dist/modules/audit/index.js.map +1 -0
- package/dist/modules/audit/request-audit.d.ts +57 -0
- package/dist/modules/audit/request-audit.d.ts.map +1 -0
- package/dist/modules/audit/request-audit.js +117 -0
- package/dist/modules/audit/request-audit.js.map +1 -0
- package/dist/modules/auth/account-erasure.service.d.ts +30 -4
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
- package/dist/modules/auth/account-erasure.service.js +96 -10
- package/dist/modules/auth/account-erasure.service.js.map +1 -1
- package/dist/modules/auth/account.routes.d.ts +6 -3
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +109 -10
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts +10 -3
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +9 -4
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +89 -5
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +160 -25
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts +46 -3
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +99 -21
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +14 -2
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +56 -7
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/advisory-lock.d.ts +103 -0
- package/dist/modules/database/advisory-lock.d.ts.map +1 -0
- package/dist/modules/database/advisory-lock.js +320 -0
- package/dist/modules/database/advisory-lock.js.map +1 -0
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +9 -1
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +859 -99
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +218 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +26 -6
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.js +4 -2
- package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
- package/dist/modules/diff/diff.routes.d.ts.map +1 -1
- package/dist/modules/diff/diff.routes.js +2 -4
- package/dist/modules/diff/diff.routes.js.map +1 -1
- package/dist/modules/diff/diff.service.d.ts +4 -1
- package/dist/modules/diff/diff.service.d.ts.map +1 -1
- package/dist/modules/diff/diff.service.js +84 -81
- package/dist/modules/diff/diff.service.js.map +1 -1
- package/dist/modules/{workspace → kb-fs}/bevel-ignore.d.ts +14 -9
- package/dist/modules/kb-fs/bevel-ignore.d.ts.map +1 -0
- package/dist/modules/{workspace → kb-fs}/bevel-ignore.js +24 -14
- package/dist/modules/kb-fs/bevel-ignore.js.map +1 -0
- package/dist/modules/kb-fs/file-change-notifier.d.ts.map +1 -1
- package/dist/modules/kb-fs/file-change-notifier.js +3 -1
- package/dist/modules/kb-fs/file-change-notifier.js.map +1 -1
- package/dist/modules/kb-fs/git-guarded-filesystem.d.ts +45 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.d.ts.map +1 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.js +117 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.js.map +1 -0
- package/dist/modules/kb-fs/locking-filesystem.d.ts +113 -18
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +353 -76
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/node-fs.d.ts +23 -0
- package/dist/modules/kb-fs/node-fs.d.ts.map +1 -0
- package/dist/modules/kb-fs/node-fs.js +158 -0
- package/dist/modules/kb-fs/node-fs.js.map +1 -0
- package/dist/modules/kb-fs/read-only-filesystem.d.ts +10 -9
- package/dist/modules/kb-fs/read-only-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/read-only-filesystem.js +18 -9
- package/dist/modules/kb-fs/read-only-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +100 -3
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +195 -3
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.js +4 -2
- package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.service.js +7 -5
- package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
- package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/git-http.routes.js +6 -4
- package/dist/modules/marketplace/git-http.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +12 -2
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +32 -3
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +27 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +45 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.routes.js +30 -6
- package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +21 -9
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.service.js +60 -19
- package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -1
- package/dist/modules/marketplace/github-facade/index.d.ts +1 -1
- package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/index.js +1 -1
- package/dist/modules/marketplace/github-facade/index.js.map +1 -1
- package/dist/modules/marketplace/marketplace-repo.service.d.ts +14 -1
- package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -1
- package/dist/modules/marketplace/marketplace-repo.service.js +26 -8
- package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -1
- package/dist/modules/mcp/downstream-pool.d.ts +107 -0
- package/dist/modules/mcp/downstream-pool.d.ts.map +1 -0
- package/dist/modules/mcp/downstream-pool.js +221 -0
- package/dist/modules/mcp/downstream-pool.js.map +1 -0
- package/dist/modules/mcp/downstream-token-refresh.d.ts +77 -0
- package/dist/modules/mcp/downstream-token-refresh.d.ts.map +1 -0
- package/dist/modules/mcp/downstream-token-refresh.js +166 -0
- package/dist/modules/mcp/downstream-token-refresh.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli-args.d.ts +78 -0
- package/dist/modules/mcp/first-call-probe.cli-args.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli-args.js +151 -0
- package/dist/modules/mcp/first-call-probe.cli-args.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli.d.ts +2 -0
- package/dist/modules/mcp/first-call-probe.cli.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli.js +62 -0
- package/dist/modules/mcp/first-call-probe.cli.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.d.ts +165 -0
- package/dist/modules/mcp/first-call-probe.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.js +298 -0
- package/dist/modules/mcp/first-call-probe.js.map +1 -0
- package/dist/modules/mcp/manual-failure-memo.d.ts +42 -17
- package/dist/modules/mcp/manual-failure-memo.d.ts.map +1 -1
- package/dist/modules/mcp/manual-failure-memo.js +79 -23
- package/dist/modules/mcp/manual-failure-memo.js.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +10 -5
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +56 -16
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.routes.d.ts +4 -4
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.routes.js +91 -180
- package/dist/modules/mcp/mcp.routes.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +226 -61
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +758 -161
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +59 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +184 -10
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +3 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
- package/dist/modules/mcp/surface-log-throttle.d.ts +59 -0
- package/dist/modules/mcp/surface-log-throttle.d.ts.map +1 -0
- package/dist/modules/mcp/surface-log-throttle.js +94 -0
- package/dist/modules/mcp/surface-log-throttle.js.map +1 -0
- package/dist/modules/plugins/compile/compile-marketplace.d.ts +13 -6
- package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -1
- package/dist/modules/plugins/compile/compile-marketplace.js +119 -36
- package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +8 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.js +9 -6
- package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +32 -9
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +26 -6
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js +71 -14
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +4 -2
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.js +9 -6
- package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
- package/dist/modules/plugins/discovery/native.source.d.ts +2 -1
- package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/native.source.js +22 -4
- package/dist/modules/plugins/discovery/native.source.js.map +1 -1
- package/dist/modules/plugins/discovery/plugin-source.d.ts +17 -3
- package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/index.d.ts +6 -3
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js +6 -3
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts +250 -0
- package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -0
- package/dist/modules/plugins/join-request-jobs.service.js +602 -0
- package/dist/modules/plugins/join-request-jobs.service.js.map +1 -0
- package/dist/modules/plugins/join-request-records.store.d.ts +161 -0
- package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -0
- package/dist/modules/plugins/join-request-records.store.js +179 -0
- package/dist/modules/plugins/join-request-records.store.js.map +1 -0
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-requests.service.js +4 -2
- package/dist/modules/plugins/join-requests.service.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +4 -1
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js +6 -3
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugin-links.service.d.ts +2 -5
- package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.service.js +4 -13
- package/dist/modules/plugins/plugin-links.service.js.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.d.ts +91 -19
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +183 -38
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts +3 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.js +20 -11
- package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
- package/dist/modules/plugins/plugins.contract.d.ts +52 -4
- package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +38 -5
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +190 -116
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.service.d.ts +38 -6
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.service.js +86 -17
- package/dist/modules/plugins/plugins.service.js.map +1 -1
- package/dist/modules/plugins/plugins.tools.d.ts +25 -0
- package/dist/modules/plugins/plugins.tools.d.ts.map +1 -0
- package/dist/modules/plugins/plugins.tools.js +82 -0
- package/dist/modules/plugins/plugins.tools.js.map +1 -0
- package/dist/modules/plugins/teams.routes.d.ts +42 -0
- package/dist/modules/plugins/teams.routes.d.ts.map +1 -0
- package/dist/modules/plugins/teams.routes.js +79 -0
- package/dist/modules/plugins/teams.routes.js.map +1 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +40 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +202 -37
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
- package/dist/modules/secrets-vault/index.d.ts +1 -1
- package/dist/modules/secrets-vault/index.d.ts.map +1 -1
- package/dist/modules/secrets-vault/index.js.map +1 -1
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +5 -3
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js +3 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +78 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.js +40 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +106 -52
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/connection-check.d.ts +118 -0
- package/dist/modules/settings/connection-check.d.ts.map +1 -0
- package/dist/modules/settings/connection-check.js +287 -0
- package/dist/modules/settings/connection-check.js.map +1 -0
- package/dist/modules/settings/deployment-settings.service.d.ts +162 -8
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +375 -52
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/git-root-folders.d.ts +54 -0
- package/dist/modules/settings/git-root-folders.d.ts.map +1 -0
- package/dist/modules/settings/git-root-folders.js +130 -0
- package/dist/modules/settings/git-root-folders.js.map +1 -0
- package/dist/modules/settings/oidc-check.d.ts +85 -0
- package/dist/modules/settings/oidc-check.d.ts.map +1 -0
- package/dist/modules/settings/oidc-check.js +172 -0
- package/dist/modules/settings/oidc-check.js.map +1 -0
- package/dist/modules/settings/setup.routes.d.ts +31 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +400 -108
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/allowed-tools-check.d.ts +132 -0
- package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -0
- package/dist/modules/skills/allowed-tools-check.js +260 -0
- package/dist/modules/skills/allowed-tools-check.js.map +1 -0
- package/dist/modules/skills/index.d.ts +3 -1
- package/dist/modules/skills/index.d.ts.map +1 -1
- package/dist/modules/skills/index.js +1 -0
- package/dist/modules/skills/index.js.map +1 -1
- package/dist/modules/skills/pending-skills.service.d.ts +6 -11
- package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
- package/dist/modules/skills/pending-skills.service.js +18 -70
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.js +9 -6
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +44 -10
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.d.ts +8 -1
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +16 -2
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +31 -7
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +191 -81
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts +4 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +41 -6
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/connection-key-rejection.d.ts +18 -0
- package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -0
- package/dist/modules/tool-auth/connection-key-rejection.js +20 -0
- package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts +14 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts.map +1 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.js +67 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +72 -8
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts +17 -6
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +83 -27
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +15 -2
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.js +6 -2
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
- package/dist/modules/tool-auth/key-or-session.middleware.d.ts +23 -0
- package/dist/modules/tool-auth/key-or-session.middleware.d.ts.map +1 -0
- package/dist/modules/tool-auth/key-or-session.middleware.js +39 -0
- package/dist/modules/tool-auth/key-or-session.middleware.js.map +1 -0
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +15 -1
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +17 -6
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts +14 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +28 -6
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +22 -5
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +6 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.js +7 -1
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
- package/dist/modules/tool-manuals/index.d.ts +2 -1
- package/dist/modules/tool-manuals/index.d.ts.map +1 -1
- package/dist/modules/tool-manuals/index.js +1 -0
- package/dist/modules/tool-manuals/index.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +8 -6
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +10 -2
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -15
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts +50 -0
- package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/pending-tools.service.js +149 -0
- package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-delete.service.d.ts +135 -0
- package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-delete.service.js +303 -0
- package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +161 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.js +9 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +19 -2
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +127 -57
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +119 -5
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +404 -74
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +78 -6
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +88 -54
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/event-bus.d.ts +10 -4
- package/dist/modules/workflow/event-bus.d.ts.map +1 -1
- package/dist/modules/workflow/event-bus.js +14 -11
- package/dist/modules/workflow/event-bus.js.map +1 -1
- package/dist/modules/workflow/events.routes.d.ts +17 -2
- package/dist/modules/workflow/events.routes.d.ts.map +1 -1
- package/dist/modules/workflow/events.routes.js +31 -12
- package/dist/modules/workflow/events.routes.js.map +1 -1
- package/dist/modules/workflow/file-lock.service.d.ts +22 -4
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
- package/dist/modules/workflow/file-lock.service.js +27 -4
- package/dist/modules/workflow/file-lock.service.js.map +1 -1
- package/dist/modules/workflow/git/change-request-link.d.ts +20 -0
- package/dist/modules/workflow/git/change-request-link.d.ts.map +1 -0
- package/dist/modules/workflow/git/change-request-link.js +34 -0
- package/dist/modules/workflow/git/change-request-link.js.map +1 -0
- package/dist/modules/workflow/git/git-version.d.ts.map +1 -1
- package/dist/modules/workflow/git/git-version.js +3 -1
- package/dist/modules/workflow/git/git-version.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +263 -4
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +528 -118
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.d.ts +36 -0
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -0
- package/dist/modules/workflow/git/node-git-runner.js +273 -0
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts +51 -2
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +157 -25
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts +11 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +24 -4
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.d.ts +15 -8
- package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.js +107 -58
- package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
- package/dist/modules/workflow/recovery-bot.js +3 -1
- package/dist/modules/workflow/recovery-bot.js.map +1 -1
- package/dist/modules/workflow/review-workflow/approval-lock.d.ts +60 -0
- package/dist/modules/workflow/review-workflow/approval-lock.d.ts.map +1 -0
- package/dist/modules/workflow/review-workflow/approval-lock.js +116 -0
- package/dist/modules/workflow/review-workflow/approval-lock.js.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +54 -7
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +64 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +269 -90
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/sanitize-error.d.ts +5 -2
- package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
- package/dist/modules/workflow/sanitize-error.js +8 -4
- package/dist/modules/workflow/sanitize-error.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts +2 -0
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +259 -29
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +166 -14
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +906 -106
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/empty-dirs.d.ts +15 -0
- package/dist/modules/workspace/empty-dirs.d.ts.map +1 -0
- package/dist/modules/workspace/empty-dirs.js +90 -0
- package/dist/modules/workspace/empty-dirs.js.map +1 -0
- package/dist/modules/workspace/file-readers/content-mode.d.ts +50 -0
- package/dist/modules/workspace/file-readers/content-mode.d.ts.map +1 -0
- package/dist/modules/workspace/file-readers/content-mode.js +55 -0
- package/dist/modules/workspace/file-readers/content-mode.js.map +1 -0
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +4 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js +4 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.types.d.ts +5 -2
- package/dist/modules/workspace/file-readers/doc-extract.types.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.types.js +7 -4
- package/dist/modules/workspace/file-readers/doc-extract.types.js.map +1 -1
- package/dist/modules/workspace/file-readers/document-reader.d.ts +2 -0
- package/dist/modules/workspace/file-readers/document-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/document-reader.js +5 -0
- package/dist/modules/workspace/file-readers/document-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/extract-docx.d.ts +6 -0
- package/dist/modules/workspace/file-readers/extract-docx.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/extract-docx.js +6 -0
- package/dist/modules/workspace/file-readers/extract-docx.js.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.d.ts +24 -5
- package/dist/modules/workspace/file-readers/file-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.js +11 -6
- package/dist/modules/workspace/file-readers/file-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.js +6 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.js.map +1 -1
- package/dist/modules/workspace/file-readers/image-reader.d.ts +7 -5
- package/dist/modules/workspace/file-readers/image-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/image-reader.js +9 -5
- package/dist/modules/workspace/file-readers/image-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/ooxml-text.d.ts +3 -0
- package/dist/modules/workspace/file-readers/ooxml-text.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/ooxml-text.js +39 -2
- package/dist/modules/workspace/file-readers/ooxml-text.js.map +1 -1
- package/dist/modules/workspace/file-readers/text-reader.d.ts +29 -1
- package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/text-reader.js +57 -3
- package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
- package/dist/modules/workspace/git-internals.middleware.d.ts +28 -0
- package/dist/modules/workspace/git-internals.middleware.d.ts.map +1 -0
- package/dist/modules/workspace/git-internals.middleware.js +93 -0
- package/dist/modules/workspace/git-internals.middleware.js.map +1 -0
- package/dist/modules/workspace/not-found.d.ts +80 -0
- package/dist/modules/workspace/not-found.d.ts.map +1 -0
- package/dist/modules/workspace/not-found.js +112 -0
- package/dist/modules/workspace/not-found.js.map +1 -0
- package/dist/modules/workspace/session-ontology.gate.d.ts +1 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.js +1 -1
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
- package/dist/modules/workspace/startup/beside-checkout.d.ts +42 -0
- package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -0
- package/dist/modules/workspace/startup/beside-checkout.js +110 -0
- package/dist/modules/workspace/startup/beside-checkout.js.map +1 -0
- package/dist/modules/workspace/startup/kb-git.d.ts +7 -12
- package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-git.js +34 -35
- package/dist/modules/workspace/startup/kb-git.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +95 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +257 -55
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +45 -0
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +417 -385
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +48 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js +183 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +51 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +158 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.d.ts +64 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.js +97 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +45 -81
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +3 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js +4 -12
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts +6 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +154 -78
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +96 -24
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +446 -138
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +94 -0
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/template-source.js +160 -0
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts +14 -2
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +649 -238
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +298 -12
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +933 -269
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +42 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +1626 -146
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +76 -0
- package/dist/modules/workspace/write-denial.d.ts.map +1 -0
- package/dist/modules/workspace/write-denial.js +138 -0
- package/dist/modules/workspace/write-denial.js.map +1 -0
- package/dist/shared/canonical-file-identity.d.ts +64 -0
- package/dist/shared/canonical-file-identity.d.ts.map +1 -0
- package/dist/shared/canonical-file-identity.js +92 -0
- package/dist/shared/canonical-file-identity.js.map +1 -0
- package/dist/shared/domain-errors.d.ts +108 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +137 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/email-identity.d.ts +32 -0
- package/dist/shared/email-identity.d.ts.map +1 -0
- package/dist/shared/email-identity.js +37 -0
- package/dist/shared/email-identity.js.map +1 -0
- package/dist/shared/fs.contract.d.ts +206 -0
- package/dist/shared/fs.contract.d.ts.map +1 -0
- package/dist/shared/fs.contract.js +79 -0
- package/dist/shared/fs.contract.js.map +1 -0
- package/dist/shared/git-failure.d.ts +80 -0
- package/dist/shared/git-failure.d.ts.map +1 -0
- package/dist/shared/git-failure.js +139 -0
- package/dist/shared/git-failure.js.map +1 -0
- package/dist/shared/git-internals.d.ts +23 -0
- package/dist/shared/git-internals.d.ts.map +1 -0
- package/dist/shared/git-internals.js +181 -0
- package/dist/shared/git-internals.js.map +1 -0
- package/dist/shared/git.contract.d.ts +157 -0
- package/dist/shared/git.contract.d.ts.map +1 -0
- package/dist/shared/git.contract.js +103 -0
- package/dist/shared/git.contract.js.map +1 -0
- package/dist/shared/http-errors.d.ts +33 -0
- package/dist/shared/http-errors.d.ts.map +1 -0
- package/dist/shared/http-errors.js +35 -0
- package/dist/shared/http-errors.js.map +1 -0
- package/dist/shared/logger.contract.d.ts +63 -0
- package/dist/shared/logger.contract.d.ts.map +1 -0
- package/dist/shared/logger.contract.js +126 -0
- package/dist/shared/logger.contract.js.map +1 -0
- package/dist/shared/logging.d.ts +31 -0
- package/dist/shared/logging.d.ts.map +1 -0
- package/dist/shared/logging.js +92 -0
- package/dist/shared/logging.js.map +1 -0
- package/dist/shared/path-containment.d.ts +21 -0
- package/dist/shared/path-containment.d.ts.map +1 -0
- package/dist/shared/path-containment.js +34 -0
- package/dist/shared/path-containment.js.map +1 -0
- package/dist/shared/pending-proposals.d.ts +71 -0
- package/dist/shared/pending-proposals.d.ts.map +1 -0
- package/dist/shared/pending-proposals.js +98 -0
- package/dist/shared/pending-proposals.js.map +1 -0
- package/dist/shared/printable.d.ts +22 -0
- package/dist/shared/printable.d.ts.map +1 -0
- package/dist/shared/printable.js +65 -0
- package/dist/shared/printable.js.map +1 -0
- package/dist/shared/redact-secret.d.ts +30 -0
- package/dist/shared/redact-secret.d.ts.map +1 -0
- package/dist/shared/redact-secret.js +114 -0
- package/dist/shared/redact-secret.js.map +1 -0
- package/dist/shared/rename-no-replace.d.ts +119 -0
- package/dist/shared/rename-no-replace.d.ts.map +1 -0
- package/dist/shared/rename-no-replace.js +323 -0
- package/dist/shared/rename-no-replace.js.map +1 -0
- package/dist/shared/ssrf.d.ts.map +1 -1
- package/dist/shared/ssrf.js +49 -18
- package/dist/shared/ssrf.js.map +1 -1
- package/dist/version.d.ts +10 -6
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +10 -6
- package/dist/version.js.map +1 -1
- package/kb-template/.bevelignore +4 -3
- package/kb-template/AGENTS.md +281 -36
- package/kb-template/KnowledgeBase/How to get started.md +1 -1
- package/kb-template/access.md +5 -3
- package/kb-template/mcp-description.md +27 -0
- package/migrations/0006_api_tokens_revoked_by.sql +1 -0
- package/migrations/0007_github_facade_registered.sql +1 -0
- package/migrations/0008_change_request_apply_failure.sql +4 -0
- package/migrations/0009_change_request_apply_failure_kind.sql +13 -0
- package/migrations/0010_plugin_join_requests.sql +15 -0
- package/migrations/0011_plugin_join_request_claim.sql +11 -0
- package/migrations/0012_agent_audit.sql +41 -0
- package/migrations/0013_agent_identity_and_key_soft_delete.sql +29 -0
- package/migrations/meta/0006_snapshot.json +1723 -0
- package/migrations/meta/0007_snapshot.json +1729 -0
- package/migrations/meta/0008_snapshot.json +1753 -0
- package/migrations/meta/0009_snapshot.json +1759 -0
- package/migrations/meta/0010_snapshot.json +1872 -0
- package/migrations/meta/0011_snapshot.json +1884 -0
- package/migrations/meta/0012_snapshot.json +2247 -0
- package/migrations/meta/0013_snapshot.json +2259 -0
- package/migrations/meta/_journal.json +56 -0
- package/package.json +7 -6
- package/src/__tests__/core-config.domain.test.ts +67 -2
- package/src/__tests__/kb-layout-config.test.ts +186 -1
- package/src/__tests__/open-change-gate.ts +15 -0
- package/src/core/__tests__/catalog-cache-invalidation.test.ts +83 -3
- package/src/core/__tests__/catalog-revision.test.ts +190 -0
- package/src/core/__tests__/lifecycle.test.ts +369 -0
- package/src/core/__tests__/public-config.test.ts +30 -0
- package/src/core/__tests__/readiness.test.ts +109 -0
- package/src/core/catalog-cache-invalidation.ts +20 -1
- package/src/core/catalog-revision.ts +110 -0
- package/src/core/create-core-server.ts +286 -79
- package/src/core/create-core-services.ts +315 -81
- package/src/core/lifecycle.ts +312 -0
- package/src/core/public-config.ts +86 -0
- package/src/core/readiness.ts +123 -0
- package/src/core-config.ts +70 -4
- package/src/index.ts +15 -0
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +362 -0
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +2 -1
- package/src/modules/access/__tests__/access-control.atref-cache.test.ts +46 -22
- package/src/modules/access/__tests__/access-control.deny-dependents.test.ts +215 -0
- package/src/modules/access/__tests__/access-control.download-read.test.ts +268 -0
- package/src/modules/access/__tests__/access-control.everyone-read.test.ts +145 -0
- package/src/modules/access/__tests__/access-control.group-read.test.ts +163 -0
- package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +2 -0
- package/src/modules/access/__tests__/access-control.platform-restore.test.ts +152 -0
- package/src/modules/access/__tests__/access-control.prospective.test.ts +189 -0
- package/src/modules/access/__tests__/access-control.read-batch.test.ts +2 -1
- package/src/modules/access/__tests__/access-control.service.test.ts +123 -78
- package/src/modules/access/__tests__/access-groups.test.ts +47 -14
- package/src/modules/access/__tests__/access-md-format.test.ts +2 -1
- package/src/modules/access/__tests__/access-mutation.service.test.ts +52 -4
- package/src/modules/access/__tests__/access-own-read-grant.test.ts +2 -0
- package/src/modules/access/__tests__/access-personal-plugin.test.ts +153 -0
- package/src/modules/access/__tests__/access-plugin-principals.test.ts +18 -1
- package/src/modules/access/__tests__/access-restrict-here.test.ts +450 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +139 -0
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +394 -0
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +6 -2
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +3 -2
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +234 -0
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +216 -0
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +7 -2
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +360 -0
- package/src/modules/access/__tests__/change-read-gate.test.ts +272 -0
- package/src/modules/access/__tests__/creator-access.test.ts +81 -83
- package/src/modules/access/__tests__/grant-sources.test.ts +3 -2
- package/src/modules/access/__tests__/groups-admin.service.test.ts +6 -5
- package/src/modules/access/__tests__/roles-admin.security.test.ts +196 -0
- package/src/modules/access/__tests__/roles-admin.service.test.ts +127 -2
- package/src/modules/access/__tests__/roles-capabilities.test.ts +5 -4
- package/src/modules/access/__tests__/roles.routes.test.ts +5 -2
- package/src/modules/access/__tests__/user-access-removal.service.test.ts +402 -0
- package/src/modules/access/__tests__/users-db-double.ts +63 -0
- package/src/modules/access/access-control.interface.ts +251 -11
- package/src/modules/access/access-control.service.ts +719 -164
- package/src/modules/access/access-mutation.service.ts +182 -13
- package/src/modules/access/access-view.ts +316 -0
- package/src/modules/access/access.routes.ts +293 -95
- package/src/modules/access/admin-locked-commit.ts +12 -14
- package/src/modules/access/admin-route-helpers.ts +4 -4
- package/src/modules/access/change-read-gate.ts +148 -0
- package/src/modules/access/creator-access.ts +89 -124
- package/src/modules/access/directory-sync-bot.ts +4 -1
- package/src/modules/access/groups-admin.service.ts +3 -3
- package/src/modules/access/reference-scan.ts +5 -5
- package/src/modules/access/roles-admin.service.ts +94 -15
- package/src/modules/access/synced-groups-committer.ts +10 -15
- package/src/modules/access/synced-groups-writer.ts +3 -12
- package/src/modules/access/user-access-removal.service.ts +711 -0
- package/src/modules/access-model/__tests__/access-splice.test.ts +63 -1
- package/src/modules/access-model/__tests__/frontmatter-fences.test.ts +71 -0
- package/src/modules/access-model/__tests__/roles-yaml-guard.test.ts +131 -0
- package/src/modules/access-model/access-errors.ts +56 -15
- package/src/modules/access-model/access-grammar.ts +85 -48
- package/src/modules/access-model/access-splice.ts +18 -18
- package/src/modules/access-model/access-template.ts +44 -0
- package/src/modules/access-model/change-gate.ts +80 -0
- package/src/modules/access-model/creator.ts +18 -21
- package/src/modules/access-model/frontmatter-lines.ts +98 -0
- package/src/modules/access-model/plugin-principals.ts +12 -19
- package/src/modules/access-model/roles-yaml-guard.ts +182 -4
- package/src/modules/admin/admin-access.service.ts +6 -2
- package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +100 -0
- package/src/modules/agent-instructions/__tests__/compose.test.ts +256 -0
- package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +135 -0
- package/src/modules/agent-instructions/agent-instructions.routes.ts +41 -0
- package/src/modules/agent-instructions/compose.ts +271 -0
- package/src/modules/agent-instructions/index.ts +14 -0
- package/src/modules/agent-instructions/read-preamble.ts +88 -0
- package/src/modules/audit/__tests__/agent-audit.service.test.ts +370 -0
- package/src/modules/audit/__tests__/agent-rest-audit.middleware.test.ts +113 -0
- package/src/modules/audit/__tests__/audit.routes.test.ts +201 -0
- package/src/modules/audit/__tests__/event-classifier.test.ts +121 -0
- package/src/modules/audit/agent-audit.service.ts +316 -0
- package/src/modules/audit/agent-rest-audit.middleware.ts +83 -0
- package/src/modules/audit/audit.contract.ts +164 -0
- package/src/modules/audit/audit.routes.ts +168 -0
- package/src/modules/audit/event-classifier.ts +155 -0
- package/src/modules/audit/index.ts +14 -0
- package/src/modules/audit/request-audit.ts +141 -0
- package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +209 -0
- package/src/modules/auth/__tests__/account.routes.test.ts +178 -2
- package/src/modules/auth/__tests__/auth.middleware.test.ts +78 -0
- package/src/modules/auth/__tests__/auth.service.test.ts +338 -5
- package/src/modules/auth/__tests__/oidc-auth-provider.test.ts +352 -12
- package/src/modules/auth/__tests__/onboarding-done.route.test.ts +3 -1
- package/src/modules/auth/account-erasure.service.ts +117 -10
- package/src/modules/auth/account.routes.ts +115 -14
- package/src/modules/auth/auth.routes.ts +20 -7
- package/src/modules/auth/auth.service.ts +187 -28
- package/src/modules/auth/oidc-auth-provider.ts +120 -22
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +109 -1
- package/src/modules/code-mode/code-mode.tool.ts +13 -2
- package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +78 -0
- package/src/modules/connection-probe/connection-probe.service.ts +59 -7
- package/src/modules/database/__tests__/advisory-lease.test.ts +152 -0
- package/src/modules/database/__tests__/advisory-lock.test.ts +147 -0
- package/src/modules/database/advisory-lock.ts +346 -0
- package/src/modules/database/connection.ts +9 -1
- package/src/modules/database/core-schema.ts +227 -0
- package/src/modules/database/migrate.ts +27 -6
- package/src/modules/declared-variables/declared-variables.routes.ts +6 -3
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +3 -0
- package/src/modules/diff/__tests__/diff.service.test.ts +3 -0
- package/src/modules/diff/diff.routes.ts +2 -4
- package/src/modules/diff/diff.service.ts +80 -79
- package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +472 -9
- package/src/modules/kb-fs/__tests__/node-fs.test.ts +409 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +210 -1
- package/src/modules/{workspace → kb-fs}/bevel-ignore.ts +22 -15
- package/src/modules/kb-fs/file-change-notifier.ts +4 -1
- package/src/modules/kb-fs/git-guarded-filesystem.ts +136 -0
- package/src/modules/kb-fs/locking-filesystem.ts +399 -109
- package/src/modules/kb-fs/node-fs.ts +165 -0
- package/src/modules/kb-fs/read-only-filesystem.ts +18 -9
- package/src/modules/kb-fs/repo-path.ts +213 -3
- package/src/modules/kb-sync/kb-sync.routes.ts +5 -2
- package/src/modules/kb-sync/kb-sync.service.ts +8 -5
- package/src/modules/marketplace/__tests__/github-facade.test.ts +134 -2
- package/src/modules/marketplace/__tests__/marketplace-git.test.ts +2 -1
- package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +47 -0
- package/src/modules/marketplace/git-http.routes.ts +7 -4
- package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +35 -3
- package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +55 -0
- package/src/modules/marketplace/github-facade/github-facade.routes.ts +32 -6
- package/src/modules/marketplace/github-facade/github-facade.service.ts +80 -19
- package/src/modules/marketplace/github-facade/index.ts +1 -0
- package/src/modules/marketplace/marketplace-repo.service.ts +23 -8
- package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +183 -13
- package/src/modules/mcp/__tests__/downstream-pool.test.ts +278 -0
- package/src/modules/mcp/__tests__/downstream-token-refresh.test.ts +178 -0
- package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +156 -0
- package/src/modules/mcp/__tests__/first-call-probe.cli-args.test.ts +178 -0
- package/src/modules/mcp/__tests__/first-call-probe.test.ts +414 -0
- package/src/modules/mcp/__tests__/manual-failure-memo.test.ts +98 -6
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +68 -7
- package/src/modules/mcp/__tests__/mcp-routes-harness.ts +1 -3
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +1055 -59
- package/src/modules/mcp/__tests__/mcp.routes.local-token.test.ts +24 -4
- package/src/modules/mcp/__tests__/mcp.routes.stateless.test.ts +182 -0
- package/src/modules/mcp/__tests__/mcp.service.test.ts +391 -6
- package/src/modules/mcp/__tests__/surface-log-throttle.test.ts +169 -0
- package/src/modules/mcp/downstream-pool.ts +256 -0
- package/src/modules/mcp/downstream-token-refresh.ts +170 -0
- package/src/modules/mcp/first-call-probe.cli-args.ts +159 -0
- package/src/modules/mcp/first-call-probe.cli.ts +60 -0
- package/src/modules/mcp/first-call-probe.ts +418 -0
- package/src/modules/mcp/manual-failure-memo.ts +81 -23
- package/src/modules/mcp/mcp-auth.middleware.ts +56 -16
- package/src/modules/mcp/mcp.routes.ts +386 -482
- package/src/modules/mcp/mcp.service.ts +905 -177
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +189 -8
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +4 -4
- package/src/modules/mcp/surface-log-throttle.ts +120 -0
- package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +10 -7
- package/src/modules/plugins/__tests__/bundle-dialect.test.ts +165 -0
- package/src/modules/plugins/__tests__/compile-marketplace.test.ts +139 -10
- package/src/modules/plugins/__tests__/fake-join-request-store.ts +189 -0
- package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +608 -0
- package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +241 -0
- package/src/modules/plugins/__tests__/plugin-index.service.test.ts +148 -7
- package/src/modules/plugins/__tests__/plugin-links.service.test.ts +10 -13
- package/src/modules/plugins/__tests__/plugin-names.test.ts +77 -0
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +129 -19
- package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +91 -29
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +370 -19
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +131 -0
- package/src/modules/plugins/__tests__/teams.routes.test.ts +248 -0
- package/src/modules/plugins/compile/compile-marketplace.ts +143 -46
- package/src/modules/plugins/compile/marketplace-compiler.service.ts +8 -7
- package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +56 -20
- package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +30 -9
- package/src/modules/plugins/discovery/bundle-dialect/registry.ts +93 -18
- package/src/modules/plugins/discovery/kb-plugin-source.ts +10 -7
- package/src/modules/plugins/discovery/native.source.ts +21 -3
- package/src/modules/plugins/discovery/plugin-source.ts +17 -3
- package/src/modules/plugins/index.ts +16 -3
- package/src/modules/plugins/join-request-jobs.service.ts +675 -0
- package/src/modules/plugins/join-request-records.store.ts +353 -0
- package/src/modules/plugins/join-requests.service.ts +7 -4
- package/src/modules/plugins/plugin-links.service.ts +4 -17
- package/src/modules/plugins/plugin-links.ts +6 -3
- package/src/modules/plugins/plugin-provision.service.ts +209 -37
- package/src/modules/plugins/plugin-rename.service.ts +21 -9
- package/src/modules/plugins/plugins.contract.ts +52 -4
- package/src/modules/plugins/plugins.routes.ts +204 -124
- package/src/modules/plugins/plugins.service.ts +92 -18
- package/src/modules/plugins/plugins.tools.ts +88 -0
- package/src/modules/plugins/teams.routes.ts +129 -0
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +359 -15
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +248 -0
- package/src/modules/secrets-vault/__tests__/namespace-secrets.test.ts +202 -0
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +217 -35
- package/src/modules/secrets-vault/index.ts +1 -0
- package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +6 -3
- package/src/modules/secrets-vault/secrets-variable-loader.ts +4 -4
- package/src/modules/secrets-vault/secrets-vault.contract.ts +93 -0
- package/src/modules/secrets-vault/secrets-vault.routes.ts +99 -38
- package/src/modules/settings/__tests__/connection-check.test.ts +233 -0
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +223 -6
- package/src/modules/settings/__tests__/git-root-folders.test.ts +247 -0
- package/src/modules/settings/__tests__/oidc-check.test.ts +185 -0
- package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +119 -0
- package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +170 -0
- package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +555 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +667 -16
- package/src/modules/settings/connection-check.ts +351 -0
- package/src/modules/settings/deployment-settings.service.ts +444 -59
- package/src/modules/settings/git-root-folders.ts +171 -0
- package/src/modules/settings/oidc-check.ts +229 -0
- package/src/modules/settings/setup.routes.ts +456 -110
- package/src/modules/skills/__tests__/allowed-tools-check.test.ts +224 -0
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +210 -0
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -3
- package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +91 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +223 -2
- package/src/modules/skills/allowed-tools-check.ts +352 -0
- package/src/modules/skills/index.ts +4 -0
- package/src/modules/skills/pending-skills.service.ts +21 -82
- package/src/modules/skills/skill-access-requests.routes.ts +10 -6
- package/src/modules/skills/skills.contract.ts +43 -11
- package/src/modules/skills/skills.routes.ts +16 -1
- package/src/modules/skills/skills.service.ts +214 -84
- package/src/modules/skills/skills.tools.ts +43 -5
- package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +192 -0
- package/src/modules/tool-auth/__tests__/connection-keys-admin.routes.test.ts +116 -0
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +153 -8
- package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +6 -0
- package/src/modules/tool-auth/connection-key-rejection.ts +25 -0
- package/src/modules/tool-auth/connection-keys-admin.routes.ts +76 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +78 -8
- package/src/modules/tool-auth/external-api-key.service.ts +98 -33
- package/src/modules/tool-auth/internal-token.service.ts +16 -2
- package/src/modules/tool-auth/key-or-session.middleware.ts +45 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +33 -8
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +228 -0
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +33 -4
- package/src/modules/tool-helpers/tool-context.ts +46 -7
- package/src/modules/tool-helpers/tool-handler.ts +23 -5
- package/src/modules/tool-helpers/tool.contract.ts +5 -0
- package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +411 -0
- package/src/modules/tool-manuals/__tests__/tool-delete.route.test.ts +133 -0
- package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +469 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +21 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +9 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +6 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +254 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +577 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +6 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.pending.route.test.ts +102 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +285 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +178 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +114 -2
- package/src/modules/tool-manuals/index.ts +3 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +13 -10
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +11 -14
- package/src/modules/tool-manuals/pending-tools.service.ts +179 -0
- package/src/modules/tool-manuals/tool-delete.service.ts +401 -0
- package/src/modules/tool-manuals/tool-manuals.contract.ts +165 -0
- package/src/modules/tool-manuals/tool-manuals.routes.ts +138 -54
- package/src/modules/tool-manuals/tool-manuals.service.ts +432 -87
- package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -6
- package/src/modules/workflow/__tests__/apply-failure.test.ts +1038 -0
- package/src/modules/workflow/__tests__/event-bus.test.ts +61 -9
- package/src/modules/workflow/__tests__/fake-file-lock-db.ts +199 -0
- package/src/modules/workflow/__tests__/file-lock.service.path-identity.test.ts +237 -0
- package/src/modules/workflow/__tests__/format-affected-owners.test.ts +18 -0
- package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +220 -0
- package/src/modules/workflow/__tests__/pending-commits.worker.concurrency.test.ts +187 -0
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -0
- package/src/modules/workflow/__tests__/sanitize-error.test.ts +10 -0
- package/src/modules/workflow/__tests__/workflow.routes.folder-proposals.test.ts +128 -0
- package/src/modules/workflow/__tests__/workflow.routes.fork-point-file.test.ts +149 -0
- package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +305 -0
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +294 -25
- package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +564 -0
- package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +135 -0
- package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +172 -0
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +14 -0
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -0
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +281 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +158 -7
- package/src/modules/workflow/agent-tools/workflow.tools.ts +93 -64
- package/src/modules/workflow/event-bus.ts +26 -28
- package/src/modules/workflow/events.routes.ts +56 -21
- package/src/modules/workflow/file-lock.service.ts +27 -4
- package/src/modules/workflow/git/__tests__/change-request-link.test.ts +43 -0
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +1 -0
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +238 -1
- package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +245 -0
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +35 -0
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +149 -0
- package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +177 -0
- package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +114 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +69 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +121 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +79 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-update.test.ts +111 -0
- package/src/modules/workflow/git/change-request-link.ts +35 -0
- package/src/modules/workflow/git/git-version.ts +5 -2
- package/src/modules/workflow/git/git.service.ts +684 -144
- package/src/modules/workflow/git/node-git-runner.ts +315 -0
- package/src/modules/workflow/git/pull-request.service.ts +179 -27
- package/src/modules/workflow/pending-commits.service.ts +26 -7
- package/src/modules/workflow/pending-commits.worker.ts +114 -69
- package/src/modules/workflow/recovery-bot.ts +4 -1
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +180 -1
- package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
- package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +520 -0
- package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +84 -0
- package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +89 -77
- package/src/modules/workflow/review-workflow/approval-lock.ts +122 -0
- package/src/modules/workflow/review-workflow/review-workflow.interface.ts +59 -7
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +309 -105
- package/src/modules/workflow/sanitize-error.ts +9 -4
- package/src/modules/workflow/workflow.routes.ts +273 -29
- package/src/modules/workflow/workflow.service.ts +1087 -171
- package/src/modules/workspace/__tests__/empty-dirs.test.ts +44 -0
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +301 -0
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +883 -0
- package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +464 -0
- package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +139 -0
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +189 -37
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +51 -11
- package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +161 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +109 -10
- package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +624 -0
- package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +409 -0
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +327 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +25 -6
- package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +109 -0
- package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
- package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +218 -0
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +56 -1
- package/src/modules/workspace/__tests__/workspace.service.test.ts +811 -42
- package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +197 -0
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +128 -0
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +212 -0
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +2632 -110
- package/src/modules/workspace/__tests__/write-denial.test.ts +75 -0
- package/src/modules/workspace/empty-dirs.ts +79 -0
- package/src/modules/workspace/file-readers/README.md +32 -0
- package/src/modules/workspace/file-readers/__tests__/doc-extract.test.ts +59 -2
- package/src/modules/workspace/file-readers/__tests__/file-reader.registry.test.ts +133 -4
- package/src/modules/workspace/file-readers/__tests__/fixtures/soft-break.docx +0 -0
- package/src/modules/workspace/file-readers/__tests__/fixtures/tab.docx +0 -0
- package/src/modules/workspace/file-readers/content-mode.ts +87 -0
- package/src/modules/workspace/file-readers/doc-extract.service.ts +4 -1
- package/src/modules/workspace/file-readers/doc-extract.types.ts +8 -4
- package/src/modules/workspace/file-readers/document-reader.ts +6 -0
- package/src/modules/workspace/file-readers/extract-docx.ts +6 -0
- package/src/modules/workspace/file-readers/file-reader.registry.ts +9 -1
- package/src/modules/workspace/file-readers/file-reader.ts +27 -6
- package/src/modules/workspace/file-readers/image-reader.ts +10 -5
- package/src/modules/workspace/file-readers/ooxml-text.ts +38 -2
- package/src/modules/workspace/file-readers/text-reader.ts +61 -4
- package/src/modules/workspace/git-internals.middleware.ts +86 -0
- package/src/modules/workspace/not-found.ts +119 -0
- package/src/modules/workspace/session-ontology.gate.ts +1 -1
- package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +181 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +361 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +53 -16
- package/src/modules/workspace/startup/beside-checkout.ts +112 -0
- package/src/modules/workspace/startup/kb-git.ts +43 -36
- package/src/modules/workspace/startup/kb-startup-runner.ts +303 -63
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +1215 -73
- package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +460 -417
- package/src/modules/workspace/startup/steps/personal-spaces.step.ts +191 -0
- package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +169 -0
- package/src/modules/workspace/startup/steps/plugin-layout.ts +110 -0
- package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +46 -85
- package/src/modules/workspace/startup/steps/roles-yaml.step.ts +6 -12
- package/src/modules/workspace/startup/steps/seed-tree.ts +159 -78
- package/src/modules/workspace/startup/steps/template-files.step.ts +492 -141
- package/src/modules/workspace/startup/steps/template-source.ts +168 -0
- package/src/modules/workspace/workspace.routes.ts +687 -257
- package/src/modules/workspace/workspace.service.ts +1000 -303
- package/src/modules/workspace/workspace.tools.ts +1823 -180
- package/src/modules/workspace/write-denial.ts +189 -0
- package/src/shared/__tests__/canonical-file-identity.test.ts +154 -0
- package/src/shared/__tests__/email-identity.test.ts +35 -0
- package/src/shared/__tests__/filename.test.ts +0 -0
- package/src/shared/__tests__/frontmatter-id.test.ts +5 -0
- package/src/shared/__tests__/git-failure.test.ts +198 -0
- package/src/shared/__tests__/git-internals.test.ts +156 -0
- package/src/shared/__tests__/http-errors.test.ts +42 -0
- package/src/shared/__tests__/logging.test.ts +185 -0
- package/src/shared/__tests__/path-containment.test.ts +60 -0
- package/src/shared/__tests__/pending-proposals.readAt.test.ts +102 -0
- package/src/shared/__tests__/printable.test.ts +64 -0
- package/src/shared/__tests__/redact-secret.test.ts +122 -0
- package/src/shared/__tests__/rename-no-replace.test.ts +466 -0
- package/src/shared/__tests__/ssrf.test.ts +20 -0
- package/src/shared/canonical-file-identity.ts +92 -0
- package/src/shared/domain-errors.ts +149 -0
- package/src/shared/email-identity.ts +38 -0
- package/src/shared/fs.contract.ts +225 -0
- package/src/shared/git-failure.ts +196 -0
- package/src/shared/git-internals.ts +179 -0
- package/src/shared/git.contract.ts +170 -0
- package/src/shared/http-errors.ts +36 -0
- package/src/shared/logger.contract.ts +141 -0
- package/src/shared/logging.ts +96 -0
- package/src/shared/path-containment.ts +34 -0
- package/src/shared/pending-proposals.ts +161 -0
- package/src/shared/printable.ts +68 -0
- package/src/shared/redact-secret.ts +118 -0
- package/src/shared/rename-no-replace.ts +386 -0
- package/src/shared/ssrf.ts +44 -16
- package/src/version.ts +10 -6
- package/dist/modules/access/access-errors.d.ts +0 -34
- package/dist/modules/access/access-errors.d.ts.map +0 -1
- package/dist/modules/access/access-errors.js +0 -40
- package/dist/modules/access/access-errors.js.map +0 -1
- package/dist/modules/access/access-splice.d.ts +0 -140
- package/dist/modules/access/access-splice.d.ts.map +0 -1
- package/dist/modules/access/access-splice.js +0 -389
- package/dist/modules/access/access-splice.js.map +0 -1
- package/dist/modules/access/group-files.d.ts +0 -83
- package/dist/modules/access/group-files.d.ts.map +0 -1
- package/dist/modules/access/group-files.js +0 -167
- package/dist/modules/access/group-files.js.map +0 -1
- package/dist/modules/access/kb-read-filter.d.ts +0 -41
- package/dist/modules/access/kb-read-filter.d.ts.map +0 -1
- package/dist/modules/access/kb-read-filter.js +0 -60
- package/dist/modules/access/kb-read-filter.js.map +0 -1
- package/dist/modules/access/render-roles-yaml.d.ts +0 -22
- package/dist/modules/access/render-roles-yaml.d.ts.map +0 -1
- package/dist/modules/access/render-roles-yaml.js +0 -56
- package/dist/modules/access/render-roles-yaml.js.map +0 -1
- package/dist/modules/access/roles-yaml-guard.d.ts +0 -56
- package/dist/modules/access/roles-yaml-guard.d.ts.map +0 -1
- package/dist/modules/access/roles-yaml-guard.js +0 -79
- package/dist/modules/access/roles-yaml-guard.js.map +0 -1
- package/dist/modules/diff/diff-paths.d.ts +0 -2
- package/dist/modules/diff/diff-paths.d.ts.map +0 -1
- package/dist/modules/diff/diff-paths.js +0 -9
- package/dist/modules/diff/diff-paths.js.map +0 -1
- package/dist/modules/groups/group-provision.service.d.ts +0 -130
- package/dist/modules/groups/group-provision.service.d.ts.map +0 -1
- package/dist/modules/groups/group-provision.service.js +0 -288
- package/dist/modules/groups/group-provision.service.js.map +0 -1
- package/dist/modules/groups/groups.contract.d.ts +0 -106
- package/dist/modules/groups/groups.contract.d.ts.map +0 -1
- package/dist/modules/groups/groups.contract.js +0 -36
- package/dist/modules/groups/groups.contract.js.map +0 -1
- package/dist/modules/groups/groups.routes.d.ts +0 -42
- package/dist/modules/groups/groups.routes.d.ts.map +0 -1
- package/dist/modules/groups/groups.routes.js +0 -379
- package/dist/modules/groups/groups.routes.js.map +0 -1
- package/dist/modules/groups/groups.service.d.ts +0 -60
- package/dist/modules/groups/groups.service.d.ts.map +0 -1
- package/dist/modules/groups/groups.service.js +0 -172
- package/dist/modules/groups/groups.service.js.map +0 -1
- package/dist/modules/groups/index.d.ts +0 -7
- package/dist/modules/groups/index.d.ts.map +0 -1
- package/dist/modules/groups/index.js +0 -6
- package/dist/modules/groups/index.js.map +0 -1
- package/dist/modules/groups/join-proposals.d.ts +0 -53
- package/dist/modules/groups/join-proposals.d.ts.map +0 -1
- package/dist/modules/groups/join-proposals.js +0 -67
- package/dist/modules/groups/join-proposals.js.map +0 -1
- package/dist/modules/groups/join-requests.service.d.ts +0 -81
- package/dist/modules/groups/join-requests.service.d.ts.map +0 -1
- package/dist/modules/groups/join-requests.service.js +0 -135
- package/dist/modules/groups/join-requests.service.js.map +0 -1
- package/dist/modules/mcp/mcp-session-store.d.ts +0 -74
- package/dist/modules/mcp/mcp-session-store.d.ts.map +0 -1
- package/dist/modules/mcp/mcp-session-store.js +0 -131
- package/dist/modules/mcp/mcp-session-store.js.map +0 -1
- package/dist/modules/workflow/file-change-notifier.d.ts +0 -38
- package/dist/modules/workflow/file-change-notifier.d.ts.map +0 -1
- package/dist/modules/workflow/file-change-notifier.js +0 -22
- package/dist/modules/workflow/file-change-notifier.js.map +0 -1
- package/dist/modules/workflow/git/branch-name.d.ts +0 -10
- package/dist/modules/workflow/git/branch-name.d.ts.map +0 -1
- package/dist/modules/workflow/git/branch-name.js +0 -76
- package/dist/modules/workflow/git/branch-name.js.map +0 -1
- package/dist/modules/workflow/git/clone-config.d.ts +0 -61
- package/dist/modules/workflow/git/clone-config.d.ts.map +0 -1
- package/dist/modules/workflow/git/clone-config.js +0 -69
- package/dist/modules/workflow/git/clone-config.js.map +0 -1
- package/dist/modules/workflow/git/mutex.d.ts +0 -11
- package/dist/modules/workflow/git/mutex.d.ts.map +0 -1
- package/dist/modules/workflow/git/mutex.js +0 -23
- package/dist/modules/workflow/git/mutex.js.map +0 -1
- package/dist/modules/workflow/locking-filesystem.d.ts +0 -137
- package/dist/modules/workflow/locking-filesystem.d.ts.map +0 -1
- package/dist/modules/workflow/locking-filesystem.js +0 -553
- package/dist/modules/workflow/locking-filesystem.js.map +0 -1
- package/dist/modules/workflow/read-only-filesystem.d.ts +0 -24
- package/dist/modules/workflow/read-only-filesystem.d.ts.map +0 -1
- package/dist/modules/workflow/read-only-filesystem.js +0 -39
- package/dist/modules/workflow/read-only-filesystem.js.map +0 -1
- package/dist/modules/workflow/workflow.errors.d.ts +0 -197
- package/dist/modules/workflow/workflow.errors.d.ts.map +0 -1
- package/dist/modules/workflow/workflow.errors.js +0 -298
- package/dist/modules/workflow/workflow.errors.js.map +0 -1
- package/dist/modules/workspace/bevel-ignore.d.ts.map +0 -1
- package/dist/modules/workspace/bevel-ignore.js.map +0 -1
- package/dist/modules/workspace/kb-seed.interface.d.ts +0 -36
- package/dist/modules/workspace/kb-seed.interface.d.ts.map +0 -1
- package/dist/modules/workspace/kb-seed.interface.js +0 -2
- package/dist/modules/workspace/kb-seed.interface.js.map +0 -1
- package/dist/modules/workspace/kb-seed.service.d.ts +0 -125
- package/dist/modules/workspace/kb-seed.service.d.ts.map +0 -1
- package/dist/modules/workspace/kb-seed.service.js +0 -535
- package/dist/modules/workspace/kb-seed.service.js.map +0 -1
- package/dist/modules/workspace/plugins-migration.d.ts +0 -50
- package/dist/modules/workspace/plugins-migration.d.ts.map +0 -1
- package/dist/modules/workspace/plugins-migration.js +0 -379
- package/dist/modules/workspace/plugins-migration.js.map +0 -1
- package/dist/shared/fs-errors.d.ts +0 -8
- package/dist/shared/fs-errors.d.ts.map +0 -1
- package/dist/shared/fs-errors.js +0 -11
- package/dist/shared/fs-errors.js.map +0 -1
- package/dist/shared/fs-walk.d.ts +0 -23
- package/dist/shared/fs-walk.d.ts.map +0 -1
- package/dist/shared/fs-walk.js +0 -42
- package/dist/shared/fs-walk.js.map +0 -1
- package/dist/shared/hash-email.d.ts +0 -11
- package/dist/shared/hash-email.d.ts.map +0 -1
- package/dist/shared/hash-email.js +0 -14
- package/dist/shared/hash-email.js.map +0 -1
- package/dist/shared/kb-walk.d.ts +0 -52
- package/dist/shared/kb-walk.d.ts.map +0 -1
- package/dist/shared/kb-walk.js +0 -76
- package/dist/shared/kb-walk.js.map +0 -1
- package/src/modules/diff/diff-paths.ts +0 -9
- package/src/modules/mcp/__tests__/mcp-session-store.test.ts +0 -151
- package/src/modules/mcp/__tests__/mcp.routes.session.test.ts +0 -226
- package/src/modules/mcp/mcp-session-store.ts +0 -162
- package/src/shared/__tests__/fs-walk.test.ts +0 -63
- package/src/shared/__tests__/kb-walk.test.ts +0 -107
- package/src/shared/fs-errors.ts +0 -10
- package/src/shared/fs-walk.ts +0 -45
- package/src/shared/hash-email.ts +0 -14
- package/src/shared/kb-walk.ts +0 -95
|
@@ -1,15 +1,45 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
|
+
import { logger } from '../../shared/logging.js';
|
|
3
|
+
const log = logger('workspace.routes');
|
|
2
4
|
import path from 'node:path';
|
|
3
|
-
import { IGNORE_FILENAME } from '
|
|
5
|
+
import { IGNORE_FILENAME, isAbsence } from '../../shared/fs.contract.js';
|
|
6
|
+
import { printable } from '../../shared/printable.js';
|
|
4
7
|
import express from 'express';
|
|
5
|
-
import { DEFAULT_BRANCH, KNOWLEDGE_DIR, reservedRootDirNames } from '@bevel-software/platform-shared';
|
|
8
|
+
import { DEFAULT_BRANCH, KNOWLEDGE_DIR, canonicalRelativePath, folderPlaceholderPath, isPlatformFile, isPlatformRestoreShape, platformFileCreationRefusal, platformFileRefusal, reservedRootDirNames, } from '@bevel-software/platform-shared';
|
|
6
9
|
import { FolderTooLargeError } from './workspace.service.js';
|
|
7
10
|
import { branchForWorkspaceId } from '../../shared/workspace-id.js';
|
|
11
|
+
import { EntryExistsError } from './workspace.service.js';
|
|
8
12
|
import { canReadWorkspacePath, resolveReadableMap, toKbRelative } from '../access-model/kb-read-filter.js';
|
|
9
13
|
import { isRolesYamlPath, assertRolesYamlParsable } from '../access-model/roles-yaml-guard.js';
|
|
10
|
-
import { WorkflowDomainError } from '../../shared/domain-errors.js';
|
|
14
|
+
import { PathTraversalError, WorkflowDomainError } from '../../shared/domain-errors.js';
|
|
15
|
+
import { domainErrorBody } from '../../shared/http-errors.js';
|
|
16
|
+
import { assertWithinDirectory } from '../../shared/path-containment.js';
|
|
17
|
+
import { normalizeWorkspacePath } from '../kb-fs/repo-path.js';
|
|
18
|
+
import { hasGitInternalsSegment } from '../../shared/git-internals.js';
|
|
19
|
+
import { createGitInternalsRouteGuard } from './git-internals.middleware.js';
|
|
20
|
+
import { removeEmptyDirs } from './empty-dirs.js';
|
|
11
21
|
import '../auth/auth.middleware.js'; // Express Request augmentation
|
|
12
22
|
const MAX_UPLOAD_BYTES = 50 * 1024 * 1024; // 50 MB
|
|
23
|
+
/**
|
|
24
|
+
* One file identity from one request field, or `null` when the caller sent
|
|
25
|
+
* nothing usable.
|
|
26
|
+
*
|
|
27
|
+
* TYPED, not cast: a repeated `?path=a&path=b` arrives as an array and a JSON
|
|
28
|
+
* body can hold anything, so `as string` would hand a non-string to the
|
|
29
|
+
* canonicaliser and throw a 500 on what is a client mistake.
|
|
30
|
+
*
|
|
31
|
+
* CANONICAL, because the mutating verbs on this surface coordinate on the
|
|
32
|
+
* path: `PUT` takes an in-process write turn on it, all of them take the
|
|
33
|
+
* workflow lock row keyed by it, and the bytes live at it. A save spelled
|
|
34
|
+
* `x/a.md` and a delete spelled `./x//a.md` would otherwise take two
|
|
35
|
+
* different lock rows for one file and interleave. See
|
|
36
|
+
* `canonicalRelativePath` for what it refuses to touch.
|
|
37
|
+
*/
|
|
38
|
+
function requestPath(value) {
|
|
39
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
40
|
+
return null;
|
|
41
|
+
return canonicalRelativePath(value);
|
|
42
|
+
}
|
|
13
43
|
/**
|
|
14
44
|
* Workspaces are per-branch (PLAN §3). Any authenticated user can access
|
|
15
45
|
* any branch's workspace; coordination of concurrent edits lives in the
|
|
@@ -25,8 +55,61 @@ const MAX_UPLOAD_BYTES = 50 * 1024 * 1024; // 50 MB
|
|
|
25
55
|
* exactly like the lock-aware filesystem the agent writes through. There
|
|
26
56
|
* is no separate "share" step; save and share are fused.
|
|
27
57
|
*/
|
|
28
|
-
export function createWorkspaceRoutes(workspaceService, authService, workflowService, eventBus, accessControl, kbDirName, creatorAccess, adminAccess
|
|
58
|
+
export function createWorkspaceRoutes(workspaceService, authService, workflowService, eventBus, accessControl, kbDirName, creatorAccess, adminAccess, disk,
|
|
59
|
+
/** Save-time skill check: `PUT /file` on a SKILL.md answers with `warnings` (advisory, never a refusal). */
|
|
60
|
+
skillSaveCheck,
|
|
61
|
+
/**
|
|
62
|
+
* Read-before-write, asked ahead of the lock where a route puts bytes on
|
|
63
|
+
* disk BEFORE it locks them (archive extraction). Every other route's writes
|
|
64
|
+
* meet the same gate inside `acquireLock`. Optional so route harnesses that
|
|
65
|
+
* exercise other behaviour need not wire it.
|
|
66
|
+
*/
|
|
67
|
+
changeGate) {
|
|
29
68
|
const router = express.Router();
|
|
69
|
+
const gitInternalsRouteGuard = createGitInternalsRouteGuard(workspaceService);
|
|
70
|
+
// The git folder is refused ahead of every route here by
|
|
71
|
+
// `createGitInternalsRouteGuard`, which the app mounts once for the whole
|
|
72
|
+
// `/workspace/:id` prefix (see `git-internals.middleware.ts`). Mounted here
|
|
73
|
+
// too so this router carries the rule wherever it is mounted on its own.
|
|
74
|
+
router.use("/workspace/:id", gitInternalsRouteGuard);
|
|
75
|
+
/**
|
|
76
|
+
* The REPOSITORY path a request names, or `null` once the refusal has been
|
|
77
|
+
* sent.
|
|
78
|
+
*
|
|
79
|
+
* Every handler on this surface calls this FIRST, before the access check and
|
|
80
|
+
* before the service, so one path is what is checked and what is written.
|
|
81
|
+
* That was the hole: the access helpers stripped `<kbDirName>/` when it was
|
|
82
|
+
* there and otherwise took the path as written, so an unprefixed
|
|
83
|
+
* `KnowledgeBase/Reports` was judged as a repository path and then created
|
|
84
|
+
* beside the repository — a folder, eight documents and a `Plugins/` tree on
|
|
85
|
+
* core-staging, none of it ever committed. The normaliser closes it by making
|
|
86
|
+
* the unprefixed spelling MEAN the repository path it was judged as.
|
|
87
|
+
*/
|
|
88
|
+
function inRepo(res, wsPath) {
|
|
89
|
+
try {
|
|
90
|
+
return normalizeWorkspacePath(wsPath, kbDirName);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
sendError(res, err);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A repository path's absolute location, checked against the repository root.
|
|
99
|
+
*
|
|
100
|
+
* The ONE place this router resolves a workspace path — the delete fast-path,
|
|
101
|
+
* the platform-restore look and the folder-keep all used to call
|
|
102
|
+
* `path.resolve(workspaceDir, …)` for themselves, against the WORKSPACE dir,
|
|
103
|
+
* which is the containment an unprefixed path satisfied on its way to being
|
|
104
|
+
* written beside the checkout. A drift-guard test fails if a second one
|
|
105
|
+
* appears.
|
|
106
|
+
*/
|
|
107
|
+
async function absoluteInRepo(workspaceId, repoRelative) {
|
|
108
|
+
const workspaceDir = await workspaceService.getWorkspacePath(workspaceId);
|
|
109
|
+
const absolute = path.resolve(workspaceDir, repoRelative);
|
|
110
|
+
assertWithinDirectory(absolute, path.join(workspaceDir, kbDirName));
|
|
111
|
+
return absolute;
|
|
112
|
+
}
|
|
30
113
|
function authenticated(req, res) {
|
|
31
114
|
if (!req.userId) {
|
|
32
115
|
res.status(401).json({ error: 'Unauthenticated' });
|
|
@@ -59,11 +142,47 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
59
142
|
return user;
|
|
60
143
|
}
|
|
61
144
|
catch (err) {
|
|
62
|
-
|
|
145
|
+
log.error('requireUser failed:', { err });
|
|
63
146
|
res.status(500).json({ error: 'Internal server error' });
|
|
64
147
|
return null;
|
|
65
148
|
}
|
|
66
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Whether a failed op is one that provably touched no bytes, so its lock
|
|
152
|
+
* may be released with the disk and the commit queue left exactly as they
|
|
153
|
+
* are (`releaseLockUntouched`) rather than reset to HEAD.
|
|
154
|
+
*
|
|
155
|
+
* This is not tidiness. A release that discards resets the PATH, not "this
|
|
156
|
+
* request's changes" — git has no notion of the latter — so when the path
|
|
157
|
+
* holds a landed save whose commit is still queued (commits run out of band
|
|
158
|
+
* in the pending-commits worker), the discard destroys that save. Two moves
|
|
159
|
+
* racing onto the same free name are exactly that situation: the winner
|
|
160
|
+
* lands and enqueues, the loser then takes the same destination lock, is
|
|
161
|
+
* refused because the name is now taken, and its unwind would throw the
|
|
162
|
+
* winner's file away. One refusal, two lost files.
|
|
163
|
+
*
|
|
164
|
+
* A destination-taken refusal qualifies because nothing it can do writes:
|
|
165
|
+
* the preflight throws before the move is attempted, and the move's own
|
|
166
|
+
* no-clobber calls (`link`, `mkdir`, `open` with `O_EXCL` — see
|
|
167
|
+
* `shared/rename-no-replace.ts`) fail without creating anything, with the
|
|
168
|
+
* folder claim rolling itself back. `LockingFilesystem.withLock` draws the
|
|
169
|
+
* same line for its `CheckRefusal`, in the same words: a refusal that wrote
|
|
170
|
+
* nothing releases untouched.
|
|
171
|
+
*
|
|
172
|
+
* Deliberately a closed list of refusal TYPES rather than a guess at what
|
|
173
|
+
* an op did. An unrecognised failure keeps the discarding release, which is
|
|
174
|
+
* the fail-closed side: at worst it throws away bytes nobody promised to
|
|
175
|
+
* keep, where the other mistake throws away bytes someone was told were
|
|
176
|
+
* saved.
|
|
177
|
+
*
|
|
178
|
+
* One type, not two: the move's lower-level `DestinationTakenError` never
|
|
179
|
+
* reaches this layer — `moveEntry` converts it into `EntryExistsError`, the
|
|
180
|
+
* refusal this surface answers 409 with — so recognising it here as well
|
|
181
|
+
* would be a branch nothing can take.
|
|
182
|
+
*/
|
|
183
|
+
function wroteNothing(err) {
|
|
184
|
+
return err instanceof EntryExistsError;
|
|
185
|
+
}
|
|
67
186
|
/**
|
|
68
187
|
* Acquire the workflow lock for `(workspaceId, branch, targetPath)`, run
|
|
69
188
|
* `op`, then release. Release commits + pushes the file as a one-file
|
|
@@ -122,23 +241,31 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
122
241
|
eventBus.emit({ kind: 'fs-tree-changed', workspaceId, branch });
|
|
123
242
|
return result;
|
|
124
243
|
}
|
|
125
|
-
const acquired = await workflowService.acquireLock(workspaceId, branch, targetPath, user
|
|
244
|
+
const acquired = await workflowService.acquireLock(workspaceId, branch, targetPath, user, {
|
|
245
|
+
platformRestore: options?.platformRestore,
|
|
246
|
+
});
|
|
126
247
|
if (!acquired.acquired) {
|
|
127
248
|
const holder = acquired.lock.holderName || 'another user';
|
|
128
249
|
const err = new Error(`"${targetPath}" is being edited by ${holder}. Try again in a moment.`);
|
|
129
250
|
err.status = 409;
|
|
130
251
|
throw err;
|
|
131
252
|
}
|
|
132
|
-
//
|
|
253
|
+
// Three release modes, the same three `LockingFilesystem.withLock` uses,
|
|
254
|
+
// depending on what the op did:
|
|
255
|
+
//
|
|
256
|
+
// - op() FAILED having possibly WRITTEN → drop the lock WITHOUT
|
|
257
|
+
// enqueueing a commit. The op may have written partial bytes to disk
|
|
258
|
+
// before throwing (write that errored mid-stream, etc.). A normal
|
|
259
|
+
// `releaseLock` would enqueue a commit for whatever's on disk and the
|
|
260
|
+
// worker would silently persist that partial state as a real
|
|
261
|
+
// committed change. `releaseLockNoCommit` resets the path to HEAD, so
|
|
262
|
+
// partial bytes never become a committed change with the user's name
|
|
263
|
+
// on it.
|
|
133
264
|
//
|
|
134
|
-
// - op() FAILED
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
// would silently persist that partial state as a real committed
|
|
139
|
-
// change. `releaseLockNoCommit` drops the lock row only —
|
|
140
|
-
// partial disk state stays where it is but never becomes a
|
|
141
|
-
// committed change with the user's name on it.
|
|
265
|
+
// - op() FAILED having written NOTHING → `releaseLockUntouched`: drop
|
|
266
|
+
// the lock row and leave both the disk and the commit queue exactly
|
|
267
|
+
// as they are. See `wroteNothing` for which refusals qualify and why
|
|
268
|
+
// the distinction is load-bearing rather than tidy.
|
|
142
269
|
//
|
|
143
270
|
// - op() SUCCEEDED → release. The new releaseLock enqueues a
|
|
144
271
|
// pending-commit row (the actual `commitFile + push` runs out
|
|
@@ -153,11 +280,17 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
153
280
|
opSucceeded = true;
|
|
154
281
|
}
|
|
155
282
|
catch (err) {
|
|
283
|
+
const untouched = wroteNothing(err);
|
|
156
284
|
try {
|
|
157
|
-
|
|
285
|
+
if (untouched) {
|
|
286
|
+
await workflowService.releaseLockUntouched(workspaceId, branch, targetPath, user);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
await workflowService.releaseLockNoCommit(workspaceId, branch, targetPath, user);
|
|
290
|
+
}
|
|
158
291
|
}
|
|
159
292
|
catch (releaseErr) {
|
|
160
|
-
|
|
293
|
+
log.warn(`${untouched ? 'releaseLockUntouched' : 'releaseLockNoCommit'} failed after op error for "${targetPath}":`, { err: releaseErr });
|
|
161
294
|
}
|
|
162
295
|
throw err;
|
|
163
296
|
}
|
|
@@ -182,19 +315,57 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
182
315
|
}
|
|
183
316
|
return result;
|
|
184
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Keep the folder a removal just emptied. A folder exists until it is
|
|
320
|
+
* deleted explicitly, so when deleting a file (or a subfolder), or moving
|
|
321
|
+
* one out, leaves its parent empty, the parent gets the placeholder in its
|
|
322
|
+
* own lock cycle — committed like any other save, within the same request.
|
|
323
|
+
* Only folders inside the repository qualify, never the clone folder
|
|
324
|
+
* itself.
|
|
325
|
+
*
|
|
326
|
+
* It runs in the folder's turn, which an explicit folder delete also takes,
|
|
327
|
+
* and looks again inside it: a folder that is gone by then was deleted
|
|
328
|
+
* explicitly and stays gone, and one that gained an entry needs nothing.
|
|
329
|
+
* The placeholder is only ever written into a folder that exists, and never
|
|
330
|
+
* through a link (see `writeFolderPlaceholder`).
|
|
331
|
+
*
|
|
332
|
+
* A failure is the request's failure: the removal landed, but a request
|
|
333
|
+
* that answers success would leave a folder that vanishes on the next
|
|
334
|
+
* clone, which is exactly what this rule forbids. It keeps its own status
|
|
335
|
+
* (a contended placeholder lock is still a 409) and only gains the context.
|
|
336
|
+
*/
|
|
337
|
+
async function keepFolderOf(workspaceId, user, removedPath) {
|
|
338
|
+
const trimmed = removedPath.replace(/\/+$/, '');
|
|
339
|
+
const dir = trimmed.includes('/') ? trimmed.slice(0, trimmed.lastIndexOf('/')) : '';
|
|
340
|
+
if (!dir.startsWith(`${kbDirName}/`))
|
|
341
|
+
return;
|
|
342
|
+
try {
|
|
343
|
+
const absolute = await absoluteInRepo(workspaceId, dir);
|
|
344
|
+
await workspaceService.withFolderTurn(workspaceId, dir, async () => {
|
|
345
|
+
if (!(await isEmptyFolder(absolute)))
|
|
346
|
+
return;
|
|
347
|
+
// One tree refresh per request: the removal already announced it.
|
|
348
|
+
await withLock(workspaceId, user, folderPlaceholderPath(dir), () => workspaceService.writeFolderPlaceholder(workspaceId, dir), { skipFsTreeEvent: true });
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
353
|
+
log.error(`could not keep the folder ${printable(dir)} after removing ${printable(removedPath)}: ${printable(reason)}`);
|
|
354
|
+
throw withKeptFolderContext(err, `"${removedPath}" was removed, but its folder "${dir}" could not be kept: ${reason}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
185
357
|
/**
|
|
186
358
|
* Map any thrown error to an HTTP response. Centralises the response
|
|
187
359
|
* shape so each route handler stays focused on its own logic.
|
|
188
|
-
* - `WorkflowDomainError` → its `.status` + `.payload`
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* - Could not read zip → 422
|
|
360
|
+
* - `WorkflowDomainError` → its `.status` + `.payload` (a traversal is a
|
|
361
|
+
* 403, an invalid path a 400, an unreadable archive a 422 — each by
|
|
362
|
+
* its TYPE; this surface used to recognise all three by their message)
|
|
192
363
|
* - Anything else with a `.status` → that status
|
|
193
364
|
* - Default → 500
|
|
194
365
|
*/
|
|
195
366
|
function sendError(res, err) {
|
|
196
367
|
if (err instanceof WorkflowDomainError) {
|
|
197
|
-
res.status(err.status).json(
|
|
368
|
+
res.status(err.status).json(domainErrorBody(err));
|
|
198
369
|
return;
|
|
199
370
|
}
|
|
200
371
|
const msg = err instanceof Error ? err.message : 'Unknown error';
|
|
@@ -203,18 +374,6 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
203
374
|
res.status(status).json({ error: msg });
|
|
204
375
|
return;
|
|
205
376
|
}
|
|
206
|
-
if (msg === 'Path traversal detected') {
|
|
207
|
-
res.status(403).json({ error: msg });
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
if (msg.startsWith('Invalid path') || msg.startsWith('Only .zip')) {
|
|
211
|
-
res.status(400).json({ error: msg });
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
if (msg.startsWith('Could not read zip file')) {
|
|
215
|
-
res.status(422).json({ error: msg });
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
377
|
res.status(500).json({ error: msg });
|
|
219
378
|
}
|
|
220
379
|
// GET /api/workspace[?branch=<branch>]
|
|
@@ -254,7 +413,7 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
254
413
|
// Log the full stack so the next 500 isn't a guessing game — the
|
|
255
414
|
// bare `error.message` we returned before lost most diagnostic
|
|
256
415
|
// signal (cause chain, stack frames, error class).
|
|
257
|
-
|
|
416
|
+
log.error(`GET /workspace failed branch=${req.query.branch ?? '(default)'}:`, { err: error });
|
|
258
417
|
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
259
418
|
res.status(500).json({ error: msg });
|
|
260
419
|
}
|
|
@@ -347,12 +506,11 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
347
506
|
let allowed;
|
|
348
507
|
try {
|
|
349
508
|
// `download` is a per-path verb in access.md, resolved via the same
|
|
350
|
-
// chain walk as `write`.
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
: relativePath;
|
|
509
|
+
// chain walk as `write`. The caller has already normalised the path into
|
|
510
|
+
// the repository, so this only takes the prefix off — where it used to
|
|
511
|
+
// pass an unprefixed path through untouched and judge a stray as if it
|
|
512
|
+
// were inside.
|
|
513
|
+
const repoRelative = toKbRelative(relativePath, kbDirName) ?? relativePath;
|
|
356
514
|
allowed = await accessControl.canDownload(workspaceId, user.email, repoRelative);
|
|
357
515
|
}
|
|
358
516
|
catch (err) {
|
|
@@ -427,7 +585,7 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
427
585
|
// `.bevelignore` is ADMIN-ONLY. It is the file that decides what the file
|
|
428
586
|
// tree and the agent view show at all, so it is deployment configuration
|
|
429
587
|
// rather than knowledge — and it sits alone in being visible: its
|
|
430
|
-
// siblings (`.gitignore`, `roles.yaml`, `access.md`,
|
|
588
|
+
// siblings (`.gitignore`, `roles.yaml`, `access.md`, the agent guide) are
|
|
431
589
|
// already hidden from every reader by the shipped ignore rules. Somebody
|
|
432
590
|
// who cannot act on it gains a puzzle; somebody who can needs to reach it.
|
|
433
591
|
//
|
|
@@ -440,10 +598,14 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
440
598
|
// on the default branch precisely so that editing `roles.yaml` on your
|
|
441
599
|
// own branch cannot promote you, and the same reasoning applies to
|
|
442
600
|
// anything gated on being an admin.
|
|
601
|
+
//
|
|
602
|
+
// `'unlisted'`, not `false`: hiding it withholds no content, so a
|
|
603
|
+
// non-admin in an empty knowledge base (every one ships this file) is
|
|
604
|
+
// told it is empty, not that something is being kept from them.
|
|
443
605
|
const ignoreFiles = wsRelPaths.filter((wp) => path.basename(wp) === IGNORE_FILENAME);
|
|
444
606
|
if (ignoreFiles.length > 0 && !(await adminAccess.isAdmin(userEmail))) {
|
|
445
607
|
for (const wp of ignoreFiles)
|
|
446
|
-
verdict.set(wp,
|
|
608
|
+
verdict.set(wp, 'unlisted');
|
|
447
609
|
}
|
|
448
610
|
return verdict;
|
|
449
611
|
};
|
|
@@ -457,39 +619,68 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
457
619
|
* grant on the same new directory survives. Runs BEFORE the creation itself
|
|
458
620
|
* so the explorer never shows-then-hides the new subtree; if the creation
|
|
459
621
|
* subsequently fails, the leftover is an empty new folder readable only by
|
|
460
|
-
* its creator.
|
|
461
|
-
*
|
|
622
|
+
* its creator.
|
|
623
|
+
*
|
|
624
|
+
* A failure here FAILS the creation, and propagates as it is. The seed is
|
|
625
|
+
* planned only for a new folder at a root the creator cannot read — the one
|
|
626
|
+
* creation the read gate lets past an unreadable spot — so without the
|
|
627
|
+
* grant the folder would come into existence invisible to the person who
|
|
628
|
+
* made it, which is exactly what the gate exists to prevent. The seed's
|
|
629
|
+
* own lock passes that gate too: if the folder appeared under someone else
|
|
630
|
+
* between the plan and this write, the refusal is theirs to see, and
|
|
631
|
+
* nothing lands.
|
|
462
632
|
*/
|
|
463
633
|
async function seedCreatorAccessMd(workspaceId, user, plan) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
creatorAccess.noteAccessFileWritten(workspaceId);
|
|
479
|
-
}
|
|
480
|
-
catch (err) {
|
|
481
|
-
console.warn(`[workspace.routes] creator access.md seed failed for "${plan.wsRelPath}":`, err instanceof Error ? err.message : err);
|
|
482
|
-
}
|
|
634
|
+
await withLock(workspaceId, user, plan.wsRelPath, async () => {
|
|
635
|
+
let current = '';
|
|
636
|
+
try {
|
|
637
|
+
current = await workspaceService.readFile(workspaceId, plan.wsRelPath);
|
|
638
|
+
}
|
|
639
|
+
catch {
|
|
640
|
+
// Not there yet — the normal case for a brand-new directory.
|
|
641
|
+
}
|
|
642
|
+
const next = plan.apply(current);
|
|
643
|
+
if (next !== current) {
|
|
644
|
+
await workspaceService.writeFile(workspaceId, plan.wsRelPath, next);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
creatorAccess.noteAccessFileWritten(workspaceId);
|
|
483
648
|
}
|
|
649
|
+
/**
|
|
650
|
+
* GET /workspace/:id/file/raw?path=<file>[&download=1][&v=<n>]
|
|
651
|
+
*
|
|
652
|
+
* The bytes of one workspace file: for the document renderers' fetches, the
|
|
653
|
+
* file tree's Download, and the `<img>` tags the markdown pipeline emits for
|
|
654
|
+
* ``. An `<img>` sends no Authorization header, so it
|
|
655
|
+
* is the auth middleware's `bevel_token` cookie fallback that lets a plain
|
|
656
|
+
* image tag through.
|
|
657
|
+
*
|
|
658
|
+
* request ──▶ auth: Bearer, else the cookie
|
|
659
|
+
* ──▶ read gate on the path 403 if the caller may not read it
|
|
660
|
+
* ──▶ download gate, if ?download=1 403 without the download: verb
|
|
661
|
+
* ──▶ readFileBinary 404 missing, 403 traversal
|
|
662
|
+
* ──▶ Content-Type from the extension, nosniff, a CSP sandbox for
|
|
663
|
+
* inline svg, attachment disposition for a download, and
|
|
664
|
+
* Cache-Control: private, no-cache
|
|
665
|
+
* ──▶ res.send(buffer): Express sets a weak ETag and answers 304 to
|
|
666
|
+
* a matching If-None-Match, so a revisited page costs a read
|
|
667
|
+
* and a hash per image rather than the bytes on the wire
|
|
668
|
+
*
|
|
669
|
+
* `?v=` is not read here. The frontend bumps it when it learns an image
|
|
670
|
+
* changed, so the browser asks for a URL it has not cached.
|
|
671
|
+
*/
|
|
484
672
|
router.get('/workspace/:id/file/raw', async (req, res) => {
|
|
485
673
|
const id = authenticated(req, res);
|
|
486
674
|
if (id === null)
|
|
487
675
|
return;
|
|
488
|
-
const
|
|
489
|
-
if (
|
|
676
|
+
const requested = req.query.path;
|
|
677
|
+
if (typeof requested !== 'string' || requested.length === 0) {
|
|
490
678
|
res.status(400).json({ error: 'path query parameter is required' });
|
|
491
679
|
return;
|
|
492
680
|
}
|
|
681
|
+
const filePath = inRepo(res, requested);
|
|
682
|
+
if (filePath === null)
|
|
683
|
+
return;
|
|
493
684
|
// `?download=1` flips this from inline-serve (used by PdfRenderer and
|
|
494
685
|
// the image renderers) to "save to disk" — and the save path is gated
|
|
495
686
|
// on per-path `download:` rules in access.md. The inline path stays
|
|
@@ -546,12 +737,19 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
546
737
|
const basename = (filePath.split('/').pop() || 'file').replace(/[\r\n]/g, '');
|
|
547
738
|
res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodeURIComponent(basename)}`);
|
|
548
739
|
}
|
|
740
|
+
// `private`: this is one person's authenticated file, and a shared cache
|
|
741
|
+
// (a CDN, a corporate proxy) must not hand it to the next person.
|
|
742
|
+
// `no-cache`: the browser may keep it but asks before reusing it, which
|
|
743
|
+
// the ETag answers with a 304; a picture replaced under the same name is
|
|
744
|
+
// therefore never older than one revalidation.
|
|
745
|
+
res.setHeader('Cache-Control', 'private, no-cache');
|
|
549
746
|
res.send(buffer);
|
|
550
747
|
}
|
|
551
748
|
catch (error) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
749
|
+
// A traversal is the caller's 403; every other read failure here is the
|
|
750
|
+
// route's honest 404 (the image either is not there or cannot be shown).
|
|
751
|
+
if (error instanceof PathTraversalError) {
|
|
752
|
+
sendError(res, error);
|
|
555
753
|
return;
|
|
556
754
|
}
|
|
557
755
|
res.status(404).json({ error: 'File not found' });
|
|
@@ -586,11 +784,14 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
586
784
|
// Trim whitespace and strip trailing slashes — `foo/` would otherwise
|
|
587
785
|
// basename to `''` and produce a misleading `.zip` filename. Done
|
|
588
786
|
// before the empty check so `' / '` is also caught.
|
|
589
|
-
const
|
|
590
|
-
if (!
|
|
787
|
+
const trimmedPath = rawPath.trim().replace(/\/+$/, '');
|
|
788
|
+
if (!trimmedPath) {
|
|
591
789
|
res.status(400).json({ error: 'path query parameter is required' });
|
|
592
790
|
return;
|
|
593
791
|
}
|
|
792
|
+
const folderPath = inRepo(res, trimmedPath);
|
|
793
|
+
if (folderPath === null)
|
|
794
|
+
return;
|
|
594
795
|
if (req.query.download !== '1') {
|
|
595
796
|
res.status(400).json({ error: 'download=1 is required for folder zip downloads' });
|
|
596
797
|
return;
|
|
@@ -615,11 +816,11 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
615
816
|
res.status(413).json({ error: error.message });
|
|
616
817
|
return;
|
|
617
818
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
res.status(403).json({ error: msg });
|
|
819
|
+
if (error instanceof PathTraversalError) {
|
|
820
|
+
sendError(res, error);
|
|
621
821
|
return;
|
|
622
822
|
}
|
|
823
|
+
const msg = error instanceof Error ? error.message : 'Unknown error';
|
|
623
824
|
if (msg === 'Not a directory') {
|
|
624
825
|
res.status(400).json({ error: msg });
|
|
625
826
|
return;
|
|
@@ -632,11 +833,14 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
632
833
|
const id = authenticated(req, res);
|
|
633
834
|
if (id === null)
|
|
634
835
|
return;
|
|
635
|
-
const
|
|
636
|
-
if (
|
|
836
|
+
const requested = requestPath(req.query.path);
|
|
837
|
+
if (requested === null) {
|
|
637
838
|
res.status(400).json({ error: 'path query parameter is required' });
|
|
638
839
|
return;
|
|
639
840
|
}
|
|
841
|
+
const filePath = inRepo(res, requested);
|
|
842
|
+
if (filePath === null)
|
|
843
|
+
return;
|
|
640
844
|
if (!(await requireReadPermission(req, res, id, filePath)))
|
|
641
845
|
return;
|
|
642
846
|
try {
|
|
@@ -648,23 +852,47 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
648
852
|
res.json({ content });
|
|
649
853
|
}
|
|
650
854
|
catch (error) {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
855
|
+
// 404 means ONE thing here: there is no file at this path. That is
|
|
856
|
+
// ENOENT, a parent that is not a directory (ENOTDIR), and a directory
|
|
857
|
+
// asked for as a file (EISDIR). Every other read failure keeps its own
|
|
858
|
+
// status, because callers act on the difference: the inline
|
|
859
|
+
// agent-description editor opens EMPTY on a 404 (a knowledge base older
|
|
860
|
+
// than the template has no such file yet), so dressing an unreadable
|
|
861
|
+
// file up as a missing one would offer an empty editor over content the
|
|
862
|
+
// save then overwrites.
|
|
863
|
+
if (isAbsence(error) || error.code === 'EISDIR') {
|
|
864
|
+
res.status(404).json({ error: 'File not found' });
|
|
654
865
|
return;
|
|
655
866
|
}
|
|
656
|
-
|
|
867
|
+
// Traversal stays a 403 and a malformed workspace id its domain status:
|
|
868
|
+
// both carry messages written to be read by the caller. (A traversal IS
|
|
869
|
+
// a domain error now, so the one check covers both.)
|
|
870
|
+
if (error instanceof WorkflowDomainError) {
|
|
871
|
+
sendError(res, error);
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
// Anything else is a real failure, and it says so WITHOUT quoting
|
|
875
|
+
// itself: an errno message carries absolute workspace paths and a
|
|
876
|
+
// bootstrap failure carries git's stderr, neither of which belongs in a
|
|
877
|
+
// response body. The distinction this route exists to make is still
|
|
878
|
+
// made — an unreadable file is not a missing one — it is just not
|
|
879
|
+
// narrated to the client.
|
|
880
|
+
log.warn(`GET /file failed for "${filePath}" in "${id}":`, { err: error });
|
|
881
|
+
res.status(500).json({ error: "Couldn't read the file." });
|
|
657
882
|
}
|
|
658
883
|
});
|
|
659
884
|
router.delete('/workspace/:id/file', async (req, res) => {
|
|
660
885
|
const id = authenticated(req, res);
|
|
661
886
|
if (id === null)
|
|
662
887
|
return;
|
|
663
|
-
const
|
|
664
|
-
if (
|
|
888
|
+
const requested = requestPath(req.query.path);
|
|
889
|
+
if (requested === null) {
|
|
665
890
|
res.status(400).json({ error: 'path query parameter is required' });
|
|
666
891
|
return;
|
|
667
892
|
}
|
|
893
|
+
const filePath = inRepo(res, requested);
|
|
894
|
+
if (filePath === null)
|
|
895
|
+
return;
|
|
668
896
|
const user = await requireUser(req, res);
|
|
669
897
|
if (!user)
|
|
670
898
|
return;
|
|
@@ -679,19 +907,12 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
679
907
|
// emits are also coalesced into a single end-of-batch event so the
|
|
680
908
|
// explorer doesn't refresh N times.
|
|
681
909
|
const workspaceDir = await workspaceService.getWorkspacePath(id);
|
|
682
|
-
|
|
683
|
-
//
|
|
684
|
-
//
|
|
685
|
-
//
|
|
686
|
-
//
|
|
687
|
-
|
|
688
|
-
// dir-delete branch operate on directories outside the workspace.
|
|
689
|
-
const workspaceRoot = path.resolve(workspaceDir);
|
|
690
|
-
if (absolute !== workspaceRoot && !absolute.startsWith(workspaceRoot + path.sep)) {
|
|
691
|
-
const err = new Error('Path traversal detected');
|
|
692
|
-
err.status = 403;
|
|
693
|
-
throw err;
|
|
694
|
-
}
|
|
910
|
+
// Boundary check before any `fs.*` call — against the REPOSITORY root,
|
|
911
|
+
// which is where `absoluteInRepo` holds it. The single-file path bottoms
|
|
912
|
+
// out in `workspaceService.deleteFile` (which resolves inside the
|
|
913
|
+
// repository itself), but this fast-path needs the absolute for
|
|
914
|
+
// `fs.stat` / `fs.rm` / `enumerateFilesUnder`.
|
|
915
|
+
const absolute = await absoluteInRepo(id, filePath);
|
|
695
916
|
let stat = null;
|
|
696
917
|
try {
|
|
697
918
|
stat = await fs.stat(absolute);
|
|
@@ -700,48 +921,73 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
700
921
|
// Not on disk — let workspaceService.deleteFile return its own 404.
|
|
701
922
|
}
|
|
702
923
|
if (stat?.isDirectory()) {
|
|
703
|
-
const filesInDir = await enumerateFilesUnder(absolute, workspaceDir);
|
|
704
924
|
const branch = branchForWorkspaceId(id);
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}
|
|
710
|
-
// No explicit push here — each per-file release enqueues a
|
|
711
|
-
// pending-commits row, and the background worker drains them
|
|
712
|
-
// (commit + push) on its own schedule. The N round-trips that
|
|
713
|
-
// the old skipPush+pushBranch pattern collapsed into one happen
|
|
714
|
-
// serially in the worker; user perception is unchanged because
|
|
715
|
-
// the disk-side delete is what other sessions see via
|
|
716
|
-
// `fs-tree-changed`.
|
|
717
|
-
// Sweep the now-empty directory subtree off disk. Git doesn't track
|
|
718
|
-
// empty folders, so there's nothing to commit; this is just disk
|
|
719
|
-
// hygiene so the file tree stops showing the empty containers.
|
|
720
|
-
//
|
|
721
|
-
// This MUST recurse: a folder that held *subfolders* still has those
|
|
722
|
-
// (now-empty) subdirectory shells on disk after the per-file deletes,
|
|
723
|
-
// so a single non-recursive `rmdir(absolute)` would see a non-empty
|
|
724
|
-
// dir and bail — leaving the folder visible in the tree and looking
|
|
725
|
-
// undeletable (BEVA-132). `removeEmptyDirs` walks bottom-up and only
|
|
726
|
-
// removes dirs that are *actually empty* at the moment it visits them,
|
|
727
|
-
// so a concurrent writer's new file (and its parent chain) is
|
|
728
|
-
// preserved — the same safety property the old non-recursive check had.
|
|
925
|
+
// In the folder's turn: keeping a folder under this one (a file delete
|
|
926
|
+
// racing this one) waits until the sweep is done, and then finds the
|
|
927
|
+
// folder gone instead of writing it back.
|
|
928
|
+
let filesInDir;
|
|
729
929
|
try {
|
|
730
|
-
await
|
|
930
|
+
filesInDir = await workspaceService.withFolderTurn(id, filePath, async () => {
|
|
931
|
+
const files = await enumerateFilesUnder(disk, absolute, workspaceDir);
|
|
932
|
+
for (const relFile of files) {
|
|
933
|
+
await withLock(id, user, relFile, async () => {
|
|
934
|
+
await workspaceService.deleteFile(id, relFile);
|
|
935
|
+
}, { skipFsTreeEvent: true });
|
|
936
|
+
}
|
|
937
|
+
// No explicit push here — each per-file release enqueues a
|
|
938
|
+
// pending-commits row, and the background worker drains them
|
|
939
|
+
// (commit + push) on its own schedule. The N round-trips that
|
|
940
|
+
// the old skipPush+pushBranch pattern collapsed into one happen
|
|
941
|
+
// serially in the worker; user perception is unchanged because
|
|
942
|
+
// the disk-side delete is what other sessions see via
|
|
943
|
+
// `fs-tree-changed`.
|
|
944
|
+
// This is the EXPLICIT folder delete — the one operation that removes
|
|
945
|
+
// a folder — so the walk above deleted the placeholders too, and the
|
|
946
|
+
// now-empty directory subtree is swept off disk. Git doesn't track
|
|
947
|
+
// empty folders, so there's nothing more to commit; this is disk
|
|
948
|
+
// hygiene so the file tree stops showing the deleted containers.
|
|
949
|
+
//
|
|
950
|
+
// This MUST recurse: a folder that held *subfolders* still has those
|
|
951
|
+
// (now-empty) subdirectory shells on disk after the per-file deletes,
|
|
952
|
+
// so a single non-recursive `rmdir(absolute)` would see a non-empty
|
|
953
|
+
// dir and bail — leaving the folder visible in the tree and looking
|
|
954
|
+
// undeletable (BEVA-132). `removeEmptyDirs` walks bottom-up and only
|
|
955
|
+
// removes dirs that are *actually empty* at the moment it visits them,
|
|
956
|
+
// so a concurrent writer's new file (and its parent chain) is
|
|
957
|
+
// preserved — the same safety property the old non-recursive check had.
|
|
958
|
+
// A folder that vanished or filled up under a concurrent writer
|
|
959
|
+
// is passed over inside the sweep; what reaches here is a real
|
|
960
|
+
// failure (permissions, I/O) that left the folder on disk, and
|
|
961
|
+
// the request fails — as the agent's delete does — rather than
|
|
962
|
+
// the response reporting gone a folder the tree still shows. The
|
|
963
|
+
// per-file deletes have landed either way, and the next delete
|
|
964
|
+
// of the now-empty folder either sweeps it or says why not. The
|
|
965
|
+
// cause is logged; the answer carries no path of the host's.
|
|
966
|
+
try {
|
|
967
|
+
await removeEmptyDirs(absolute);
|
|
968
|
+
}
|
|
969
|
+
catch (rmErr) {
|
|
970
|
+
log.warn(`dir cleanup failed for ${printable(filePath)}`, { err: rmErr });
|
|
971
|
+
throw new Error('The files were deleted, but the empty folder could not be removed. Delete it again.');
|
|
972
|
+
}
|
|
973
|
+
return files;
|
|
974
|
+
});
|
|
975
|
+
// The folder that HELD the deleted one was not asked to go.
|
|
976
|
+
await keepFolderOf(id, user, filePath);
|
|
731
977
|
}
|
|
732
|
-
|
|
733
|
-
//
|
|
734
|
-
//
|
|
735
|
-
//
|
|
736
|
-
|
|
978
|
+
finally {
|
|
979
|
+
// Single tree-refresh signal for the whole batch (we suppressed
|
|
980
|
+
// the per-file ones via `skipFsTreeEvent`) — sent on failure too:
|
|
981
|
+
// a batch that stops part way, or a parent that could not be kept,
|
|
982
|
+
// has still changed the tree.
|
|
983
|
+
eventBus.emit({ kind: 'fs-tree-changed', workspaceId: id, branch });
|
|
737
984
|
}
|
|
738
|
-
// Single tree-refresh signal for the whole batch (we suppressed
|
|
739
|
-
// the per-file ones via `skipFsTreeEvent`).
|
|
740
|
-
eventBus.emit({ kind: 'fs-tree-changed', workspaceId: id, branch });
|
|
741
985
|
res.json({ status: 'deleted', count: filesInDir.length });
|
|
742
986
|
return;
|
|
743
987
|
}
|
|
744
988
|
await withLock(id, user, filePath, () => workspaceService.deleteFile(id, filePath));
|
|
989
|
+
// Deleting content is not deleting structure: an emptied folder stays.
|
|
990
|
+
await keepFolderOf(id, user, filePath);
|
|
745
991
|
res.json({ status: 'deleted' });
|
|
746
992
|
}
|
|
747
993
|
catch (err) {
|
|
@@ -752,15 +998,72 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
752
998
|
const id = authenticated(req, res);
|
|
753
999
|
if (id === null)
|
|
754
1000
|
return;
|
|
755
|
-
const
|
|
756
|
-
|
|
1001
|
+
const body = (req.body ?? {});
|
|
1002
|
+
const requestedOld = requestPath(body.oldPath);
|
|
1003
|
+
const requestedNew = requestPath(body.newPath);
|
|
1004
|
+
if (requestedOld === null || requestedNew === null) {
|
|
757
1005
|
res.status(400).json({ error: 'oldPath and newPath are required in body' });
|
|
758
1006
|
return;
|
|
759
1007
|
}
|
|
1008
|
+
// Both ends inside the repository before anything is judged: the platform-file
|
|
1009
|
+
// rules, the locks and the rename all read the same two paths.
|
|
1010
|
+
const oldPath = inRepo(res, requestedOld);
|
|
1011
|
+
if (oldPath === null)
|
|
1012
|
+
return;
|
|
1013
|
+
const newPath = inRepo(res, requestedNew);
|
|
1014
|
+
if (newPath === null)
|
|
1015
|
+
return;
|
|
1016
|
+
// Two spellings of one file are now ONE path, so a move can arrive with
|
|
1017
|
+
// both ends equal. `withLock` below would survive it — the inner
|
|
1018
|
+
// acquisition sees the lock the outer just took, held by this same user,
|
|
1019
|
+
// and runs straight through — but the move itself is a rename onto
|
|
1020
|
+
// itself that commits a change and tells the diff service the path was
|
|
1021
|
+
// both deleted and rewritten. It is a client mistake, so it is a 400.
|
|
1022
|
+
if (oldPath === newPath) {
|
|
1023
|
+
res.status(400).json({ error: 'oldPath and newPath must differ' });
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
760
1026
|
const user = await requireUser(req, res);
|
|
761
1027
|
if (!user)
|
|
762
1028
|
return;
|
|
763
1029
|
try {
|
|
1030
|
+
// A platform file stays in the folder the platform reads it from —
|
|
1031
|
+
// rename, move and drag all arrive here, and all three are refused.
|
|
1032
|
+
// Moving one out is not a choice to confirm: once the root has no
|
|
1033
|
+
// `access.md`, write on the root denies everyone and the move that
|
|
1034
|
+
// would undo it is the move the gate refuses.
|
|
1035
|
+
//
|
|
1036
|
+
// The single exception is that repair: an admin putting a misplaced
|
|
1037
|
+
// copy BACK. `isPlatformRestoreShape` says whether the MOVE is that
|
|
1038
|
+
// repair — it is judged on the source's name and the destination, not
|
|
1039
|
+
// on the source being a platform file where it currently sits, because
|
|
1040
|
+
// a stray `roles.yaml` in a folder is ordinary content there and is
|
|
1041
|
+
// still the copy the root is missing. `canRestorePlatformFile` then
|
|
1042
|
+
// decides who may make it, and whether the disk agrees.
|
|
1043
|
+
const oldRel = toKbRelative(oldPath, kbDirName);
|
|
1044
|
+
const newRel = toKbRelative(newPath, kbDirName);
|
|
1045
|
+
let platformRestore = false;
|
|
1046
|
+
if (oldRel !== null && newRel !== null && isPlatformRestoreShape(oldRel, newRel)) {
|
|
1047
|
+
platformRestore = await accessControl.canRestorePlatformFile(id, user.email, newRel);
|
|
1048
|
+
}
|
|
1049
|
+
// A platform file stays where the platform reads it …
|
|
1050
|
+
if (oldRel !== null && isPlatformFile(oldRel) && !platformRestore) {
|
|
1051
|
+
res.status(409).json({ error: platformFileRefusal(oldRel) });
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
// … and nothing else becomes one. `moveEntry` is a plain rename, so
|
|
1055
|
+
// without this a note renamed to `access.md` would come back as the
|
|
1056
|
+
// folder's rules, and a note dragged ONTO the root's `access.md` would
|
|
1057
|
+
// replace the rules that are there — neither of which the rule above,
|
|
1058
|
+
// which reads only the SOURCE, says anything about. The agent's move
|
|
1059
|
+
// tool has refused both since it shipped; this is the same sentence,
|
|
1060
|
+
// from the same place. Only the restore lands on a platform path, and
|
|
1061
|
+
// only where the file is missing (`canRestorePlatformFile` checked the
|
|
1062
|
+
// disk; the destination lock below checks it again, under the lock).
|
|
1063
|
+
if (newRel !== null && isPlatformFile(newRel) && !platformRestore) {
|
|
1064
|
+
res.status(409).json({ error: platformFileCreationRefusal(newRel) });
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
764
1067
|
// Move = rename on disk + commit on both sides. We lock-and-release
|
|
765
1068
|
// the destination first (commits the new file's appearance), then
|
|
766
1069
|
// lock-and-release the source path (commits its deletion). Two
|
|
@@ -781,7 +1084,38 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
781
1084
|
// not a single merge-style rename commit, but git's log/blame
|
|
782
1085
|
// rename detection still groups them visually after the fact.
|
|
783
1086
|
const [firstLock, secondLock] = oldPath < newPath ? [oldPath, newPath] : [newPath, oldPath];
|
|
784
|
-
|
|
1087
|
+
// Only the DESTINATION side carries the restore claim. The source is an
|
|
1088
|
+
// ordinary write the caller must already hold: the exception exists so a
|
|
1089
|
+
// file can land where the platform reads it, not so an admin can take
|
|
1090
|
+
// one out of a folder that denies them.
|
|
1091
|
+
const restoreAt = (p) => ({
|
|
1092
|
+
platformRestore: platformRestore && p === newPath ? { source: oldPath } : undefined,
|
|
1093
|
+
});
|
|
1094
|
+
// The restore was authorised against a destination that was missing when
|
|
1095
|
+
// the access module looked. Both locks are in hand by the time this runs,
|
|
1096
|
+
// so nothing else can take that path from under the rename — but between
|
|
1097
|
+
// the two a writer still could, and a restore that lands on a platform
|
|
1098
|
+
// file replaces the rules it came to bring back. So the last thing the
|
|
1099
|
+
// move does before renaming is look again, inside the window it holds.
|
|
1100
|
+
const move = async () => {
|
|
1101
|
+
if (platformRestore) {
|
|
1102
|
+
const absoluteNew = await absoluteInRepo(id, newPath);
|
|
1103
|
+
const taken = await fs.stat(absoluteNew).then(() => true,
|
|
1104
|
+
// Genuine absence is the only "free": anything else is not an
|
|
1105
|
+
// answer, and an unanswered question does not clear the way onto
|
|
1106
|
+
// a platform file.
|
|
1107
|
+
(err) => !isAbsence(err));
|
|
1108
|
+
if (taken) {
|
|
1109
|
+
const err = new Error(platformFileRefusal(newPath));
|
|
1110
|
+
err.status = 409;
|
|
1111
|
+
throw err;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return workspaceService.moveEntry(id, oldPath, newPath);
|
|
1115
|
+
};
|
|
1116
|
+
await withLock(id, user, firstLock, () => withLock(id, user, secondLock, move, restoreAt(secondLock)), restoreAt(firstLock));
|
|
1117
|
+
// Moving the last entry out leaves its folder in place, like a delete.
|
|
1118
|
+
await keepFolderOf(id, user, oldPath);
|
|
785
1119
|
res.json({ status: 'moved' });
|
|
786
1120
|
}
|
|
787
1121
|
catch (err) {
|
|
@@ -792,41 +1126,89 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
792
1126
|
const id = authenticated(req, res);
|
|
793
1127
|
if (id === null)
|
|
794
1128
|
return;
|
|
795
|
-
|
|
796
|
-
|
|
1129
|
+
// ONE spelling of the target from here down. `x/a.md`, `./x/a.md` and
|
|
1130
|
+
// `x//a.md` are the same file and all pass the path validator, and this
|
|
1131
|
+
// route coordinates on that path three times over: the in-process write
|
|
1132
|
+
// turn, the workflow lock row, and the bytes themselves. Two clients
|
|
1133
|
+
// spelling one file differently would otherwise take two different locks
|
|
1134
|
+
// and both pass their own precondition.
|
|
1135
|
+
const requested = requestPath(req.query.path);
|
|
1136
|
+
if (requested === null) {
|
|
797
1137
|
res.status(400).json({ error: 'path query parameter is required' });
|
|
798
1138
|
return;
|
|
799
1139
|
}
|
|
800
|
-
const
|
|
1140
|
+
const filePath = inRepo(res, requested);
|
|
1141
|
+
if (filePath === null)
|
|
1142
|
+
return;
|
|
1143
|
+
const { content, ifAbsent, ifMatch } = req.body;
|
|
801
1144
|
if (content === undefined) {
|
|
802
1145
|
res.status(400).json({ error: 'content is required in body' });
|
|
803
1146
|
return;
|
|
804
1147
|
}
|
|
1148
|
+
if (ifMatch !== undefined && typeof ifMatch !== 'string') {
|
|
1149
|
+
res.status(400).json({ error: 'ifMatch, if provided, must be a string' });
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
805
1152
|
const user = await requireUser(req, res);
|
|
806
1153
|
if (!user)
|
|
807
1154
|
return;
|
|
1155
|
+
// A precondition ANSWERS A QUESTION ABOUT CONTENT, so it is gated on
|
|
1156
|
+
// READING, not writing. Write authorisation happens at `acquireLock`
|
|
1157
|
+
// inside `withLock` below, which is after the compare: without this gate
|
|
1158
|
+
// the 409-versus-403 difference is a content-equality oracle on a file the
|
|
1159
|
+
// caller may not read, and the confirming case is a write. Same gate and
|
|
1160
|
+
// same 403 as `GET /file`; a caller who may write but not read can still
|
|
1161
|
+
// save, just not ask questions about what is there.
|
|
1162
|
+
if (ifMatch !== undefined && !(await requireReadPermission(req, res, id, filePath)))
|
|
1163
|
+
return;
|
|
808
1164
|
try {
|
|
809
1165
|
// Refuse a hand-edit that would leave roles.yaml unparseable BEFORE any
|
|
810
1166
|
// byte hits disk — a broken roles.yaml is an app-wide admin lockout
|
|
811
|
-
// (loadModel hard-throws). The dedicated
|
|
1167
|
+
// (loadModel hard-throws). The dedicated App roles surface has its
|
|
812
1168
|
// own validate gate; this covers the raw-text editor path.
|
|
813
1169
|
if (isRolesYamlPath(filePath, kbDirName))
|
|
814
1170
|
assertRolesYamlParsable(content);
|
|
815
|
-
//
|
|
816
|
-
//
|
|
817
|
-
//
|
|
818
|
-
//
|
|
819
|
-
//
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
//
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
1171
|
+
// One turn for the whole sequence, because the DECISION spans three
|
|
1172
|
+
// steps that must agree about the same file: check the precondition,
|
|
1173
|
+
// plan a creator-access grant that COMMITS, then write. A save landing
|
|
1174
|
+
// in between would leave that grant behind for a write about to be
|
|
1175
|
+
// refused, so the check is made here, before the plan, and nothing else
|
|
1176
|
+
// in this process may touch the path until the write is done. The write
|
|
1177
|
+
// inside takes the same turn re-entrantly.
|
|
1178
|
+
//
|
|
1179
|
+
// Across instances the workflow lock below is still the coordinator;
|
|
1180
|
+
// this only orders what this server is doing.
|
|
1181
|
+
await workspaceService.withPathTurn(id, filePath, async () => {
|
|
1182
|
+
// A stale `ifMatch` is refused before anything commits.
|
|
1183
|
+
if (ifMatch !== undefined)
|
|
1184
|
+
await workspaceService.assertContentMatches(id, filePath, ifMatch);
|
|
1185
|
+
// Creator read grant: a file that starts a new folder at a root the
|
|
1186
|
+
// creator cannot read would vanish from their own explorer (read is
|
|
1187
|
+
// default-deny). Plan BEFORE the write: the new folder gets its
|
|
1188
|
+
// access.md seeded first. Anywhere else the lock's read gate has
|
|
1189
|
+
// already decided — a creation the creator could not see is refused,
|
|
1190
|
+
// and one they can see needs no grant.
|
|
1191
|
+
const plan = await creatorAccess.planForCreate(id, user, filePath, 'file');
|
|
1192
|
+
if (plan?.kind === 'seed-access-md')
|
|
1193
|
+
await seedCreatorAccessMd(id, user, plan);
|
|
1194
|
+
const toWrite = content;
|
|
1195
|
+
// `ifAbsent` = exclusive create: the service's `wx` write turns a
|
|
1196
|
+
// concurrent or stale create against an existing file into a 409
|
|
1197
|
+
// instead of a silent replace. `withLock`'s failure arm releases
|
|
1198
|
+
// without committing, so the refusal leaves no trace.
|
|
1199
|
+
//
|
|
1200
|
+
// `ifMatch` = conditional write, the same 409 for a stale UPDATE: the
|
|
1201
|
+
// file must still hold the text the caller last read, re-checked at
|
|
1202
|
+
// the write itself as the decision that counts.
|
|
1203
|
+
await withLock(id, user, filePath, () => workspaceService.writeFile(id, filePath, toWrite, {
|
|
1204
|
+
failIfExists: ifAbsent === true,
|
|
1205
|
+
expectedContent: ifMatch,
|
|
1206
|
+
}));
|
|
1207
|
+
});
|
|
1208
|
+
// After the write, and only ever advisory: the check reports what the
|
|
1209
|
+
// saved skill names, it has no say in whether it saved.
|
|
1210
|
+
const warnings = skillSaveCheck ? await skillSaveCheck.checkSave(user.email, filePath, content) : [];
|
|
1211
|
+
res.json({ status: 'written', ...(warnings.length > 0 ? { warnings } : {}) });
|
|
830
1212
|
}
|
|
831
1213
|
catch (err) {
|
|
832
1214
|
sendError(res, err);
|
|
@@ -836,11 +1218,18 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
836
1218
|
const id = authenticated(req, res);
|
|
837
1219
|
if (id === null)
|
|
838
1220
|
return;
|
|
839
|
-
const { path:
|
|
840
|
-
|
|
1221
|
+
const { path: requested, defer } = req.body;
|
|
1222
|
+
const canonical = requestPath(requested);
|
|
1223
|
+
if (canonical === null) {
|
|
841
1224
|
res.status(400).json({ error: 'path is required in body' });
|
|
842
1225
|
return;
|
|
843
1226
|
}
|
|
1227
|
+
// The folder this call creates, as a repository path. `KnowledgeBase/Reports`
|
|
1228
|
+
// is `<kbDirName>/KnowledgeBase/Reports` — the access plan below, the
|
|
1229
|
+
// `.gitkeep` lock and the mkdir all use this one spelling.
|
|
1230
|
+
const dirPath = inRepo(res, canonical);
|
|
1231
|
+
if (dirPath === null)
|
|
1232
|
+
return;
|
|
844
1233
|
const user = await requireUser(req, res);
|
|
845
1234
|
if (!user)
|
|
846
1235
|
return;
|
|
@@ -880,20 +1269,49 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
880
1269
|
if (id === null)
|
|
881
1270
|
return;
|
|
882
1271
|
const body = (req.body ?? {});
|
|
883
|
-
const
|
|
884
|
-
const
|
|
885
|
-
if (typeof
|
|
1272
|
+
const requestedZip = body.path;
|
|
1273
|
+
const requestedDest = body.destination;
|
|
1274
|
+
if (typeof requestedZip !== 'string' || requestedZip.length === 0) {
|
|
886
1275
|
res.status(400).json({ error: 'path is required in body and must be a string' });
|
|
887
1276
|
return;
|
|
888
1277
|
}
|
|
889
|
-
if (
|
|
1278
|
+
if (requestedDest !== undefined && (typeof requestedDest !== 'string' || requestedDest.length === 0)) {
|
|
890
1279
|
res.status(400).json({ error: 'destination, if provided, must be a non-empty string' });
|
|
891
1280
|
return;
|
|
892
1281
|
}
|
|
1282
|
+
const zipPath = inRepo(res, requestedZip);
|
|
1283
|
+
if (zipPath === null)
|
|
1284
|
+
return;
|
|
1285
|
+
let destination;
|
|
1286
|
+
if (requestedDest !== undefined) {
|
|
1287
|
+
const normalizedDest = inRepo(res, requestedDest);
|
|
1288
|
+
if (normalizedDest === null)
|
|
1289
|
+
return;
|
|
1290
|
+
destination = normalizedDest;
|
|
1291
|
+
}
|
|
893
1292
|
const user = await requireUser(req, res);
|
|
894
1293
|
if (!user)
|
|
895
1294
|
return;
|
|
896
1295
|
try {
|
|
1296
|
+
// The destination is asked about BEFORE anything is extracted: this is
|
|
1297
|
+
// the one route whose bytes land on disk ahead of the lock, so the
|
|
1298
|
+
// lock's read gate would find them already there. Same verdict, same
|
|
1299
|
+
// refusal, one step earlier. A destination inside a folder the caller
|
|
1300
|
+
// cannot read is refused whole; a folder they can read — or a new
|
|
1301
|
+
// folder directly under a root — extracts, and each file then meets
|
|
1302
|
+
// the lock as any other write does.
|
|
1303
|
+
//
|
|
1304
|
+
// A new root folder gets its creator's access.md seeded first, as
|
|
1305
|
+
// every other creation route does: extraction would otherwise bring
|
|
1306
|
+
// the folder into existence itself, and the first file's lock would
|
|
1307
|
+
// then find an existing folder the caller cannot read.
|
|
1308
|
+
// Both spellings are already repository paths, so the inferred parent is
|
|
1309
|
+
// one too — the same destination the service resolves.
|
|
1310
|
+
const destDir = destination ?? path.posix.dirname(zipPath);
|
|
1311
|
+
const plan = await creatorAccess.planForCreate(id, user, destDir, 'dir');
|
|
1312
|
+
if (plan?.kind === 'seed-access-md')
|
|
1313
|
+
await seedCreatorAccessMd(id, user, plan);
|
|
1314
|
+
await changeGate?.assertMayChange(id, user.email, destDir, 'dir');
|
|
897
1315
|
// Extract first (all files land on disk), then sweep each extracted
|
|
898
1316
|
// file through a lock+release so it commits + pushes as its own
|
|
899
1317
|
// one-file change. Per-file commits mean the validator runs N times
|
|
@@ -901,26 +1319,18 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
901
1319
|
// but correct for a 100-file zip. If a single file's release fails
|
|
902
1320
|
// (e.g. validator 422), the loop stops there so the user sees the
|
|
903
1321
|
// first concrete problem rather than a list of N similar failures.
|
|
904
|
-
|
|
1322
|
+
//
|
|
1323
|
+
// Each entry is asked about before it is written, through the same
|
|
1324
|
+
// gate: an archive can carry a path into a nested folder the caller
|
|
1325
|
+
// cannot read, which the destination check above cannot see. Such an
|
|
1326
|
+
// entry is skipped and reported, never written and then refused.
|
|
1327
|
+
const result = await workspaceService.unzipFile(id, zipPath, destination, async (entryPath) => {
|
|
1328
|
+
await changeGate?.assertMayChange(id, user.email, entryPath, 'file');
|
|
1329
|
+
});
|
|
905
1330
|
for (const relFile of result.extracted) {
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
// can't read (default-deny chains), splice their read grant into
|
|
910
|
-
// its frontmatter first so the committed change already carries it.
|
|
911
|
-
// Best-effort: a failed grant write must not throw — withLock's
|
|
912
|
-
// failure path releases WITHOUT committing and would discard the
|
|
913
|
-
// extracted file from disk, turning a cosmetic grant failure into
|
|
914
|
-
// data loss.
|
|
915
|
-
try {
|
|
916
|
-
const granted = await creatorAccess.grantInExtractedFile(id, user, relFile);
|
|
917
|
-
if (granted !== null)
|
|
918
|
-
await workspaceService.writeFile(id, relFile, granted);
|
|
919
|
-
}
|
|
920
|
-
catch (err) {
|
|
921
|
-
console.warn(`[workspace.routes] creator grant on extracted "${relFile}" failed:`, err instanceof Error ? err.message : err);
|
|
922
|
-
}
|
|
923
|
-
});
|
|
1331
|
+
// The file is already on disk from the unzip; the release commits +
|
|
1332
|
+
// pushes it.
|
|
1333
|
+
await withLock(id, user, relFile, async () => undefined);
|
|
924
1334
|
}
|
|
925
1335
|
res.json(result);
|
|
926
1336
|
}
|
|
@@ -932,11 +1342,17 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
932
1342
|
const id = authenticated(req, res);
|
|
933
1343
|
if (id === null)
|
|
934
1344
|
return;
|
|
935
|
-
const
|
|
936
|
-
if (
|
|
1345
|
+
const requested = requestPath(req.query.path);
|
|
1346
|
+
if (requested === null) {
|
|
937
1347
|
res.status(400).json({ error: 'path query parameter is required' });
|
|
938
1348
|
return;
|
|
939
1349
|
}
|
|
1350
|
+
// An upload with no folder lands at the repository ROOT inside the
|
|
1351
|
+
// checkout, not beside it — eight staging test documents sat beside it
|
|
1352
|
+
// because this route took the path as written.
|
|
1353
|
+
const filePath = inRepo(res, requested);
|
|
1354
|
+
if (filePath === null)
|
|
1355
|
+
return;
|
|
940
1356
|
// `?defer=true` is the bulk-upload caller's signal to suppress the
|
|
941
1357
|
// per-file `fs-tree-changed` SSE — the caller emits one combined
|
|
942
1358
|
// refresh at end-of-burst via `POST /flush`. Pushing isn't deferred
|
|
@@ -964,17 +1380,14 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
964
1380
|
chunks.push(buf);
|
|
965
1381
|
}
|
|
966
1382
|
const data = Buffer.concat(chunks);
|
|
967
|
-
// Creator read grant, mirroring PUT /file:
|
|
968
|
-
//
|
|
969
|
-
//
|
|
970
|
-
//
|
|
1383
|
+
// Creator read grant, mirroring PUT /file: an upload that starts a new
|
|
1384
|
+
// folder at a root seeds that folder's access.md first. An upload into
|
|
1385
|
+
// a folder the caller cannot read never gets this far — the lock's read
|
|
1386
|
+
// gate refuses it.
|
|
971
1387
|
const plan = await creatorAccess.planForCreate(id, user, filePath, 'file');
|
|
972
1388
|
if (plan?.kind === 'seed-access-md')
|
|
973
1389
|
await seedCreatorAccessMd(id, user, plan);
|
|
974
|
-
|
|
975
|
-
? Buffer.from(plan.apply(data.toString('utf8')), 'utf8')
|
|
976
|
-
: data;
|
|
977
|
-
await withLock(id, user, filePath, () => workspaceService.writeFileBinary(id, filePath, toWrite), defer ? { skipFsTreeEvent: true } : undefined);
|
|
1390
|
+
await withLock(id, user, filePath, () => workspaceService.writeFileBinary(id, filePath, data), defer ? { skipFsTreeEvent: true } : undefined);
|
|
978
1391
|
res.json({ status: 'uploaded' });
|
|
979
1392
|
}
|
|
980
1393
|
catch (err) {
|
|
@@ -987,6 +1400,8 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
987
1400
|
// happens out of band in the worker, so this route's only remaining
|
|
988
1401
|
// responsibility is to emit the single combined `fs-tree-changed`
|
|
989
1402
|
// event the bulk caller suppressed per file.
|
|
1403
|
+
// It takes NO path: there is nothing for the normaliser to place, which is
|
|
1404
|
+
// why this route is the one on the surface that does not call it.
|
|
990
1405
|
router.post('/workspace/:id/flush', async (req, res) => {
|
|
991
1406
|
const id = authenticated(req, res);
|
|
992
1407
|
if (id === null)
|
|
@@ -1011,67 +1426,63 @@ export function createWorkspaceRoutes(workspaceService, authService, workflowSer
|
|
|
1011
1426
|
* a recursive directory delete into per-file lock+release cycles so each
|
|
1012
1427
|
* deletion lands as its own one-file change.
|
|
1013
1428
|
*
|
|
1014
|
-
* Skips
|
|
1015
|
-
*
|
|
1016
|
-
* for predictable commit sequencing.
|
|
1429
|
+
* Skips the git folder, in any spelling (`hasGitInternalsSegment`), so a
|
|
1430
|
+
* folder delete never enumerates — or deletes — the repository's git data. Returns paths in the walk's order — stable
|
|
1431
|
+
* and lexical — for predictable commit sequencing. A link counts as a file:
|
|
1432
|
+
* it is deleted as one, never followed. A folder that cannot be listed is
|
|
1433
|
+
* the delete's error: an enumeration with a hole in it would delete what it
|
|
1434
|
+
* saw and report success over what it did not.
|
|
1017
1435
|
*/
|
|
1018
|
-
async function enumerateFilesUnder(absoluteDir, workspaceDir) {
|
|
1436
|
+
async function enumerateFilesUnder(disk, absoluteDir, workspaceDir) {
|
|
1019
1437
|
const out = [];
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
}
|
|
1438
|
+
const relOf = (dir, name) => path.relative(workspaceDir, path.join(absoluteDir, dir, name)).replace(/\\/g, '/');
|
|
1439
|
+
try {
|
|
1440
|
+
await disk.walk(absoluteDir, { skip: (e) => hasGitInternalsSegment(e.name), unreadable: 'throw' }, [
|
|
1441
|
+
{
|
|
1442
|
+
onFile: (dir, name) => void out.push(relOf(dir, name)),
|
|
1443
|
+
onOther: (dir, e) => void out.push(relOf(dir, e.name)),
|
|
1444
|
+
},
|
|
1445
|
+
]);
|
|
1446
|
+
}
|
|
1447
|
+
catch (err) {
|
|
1448
|
+
// The operator's line carries the errno and the path; the caller's answer
|
|
1449
|
+
// names only the folder they asked about — an OS message would leak the
|
|
1450
|
+
// server's spelling of the workspace, and would not help them anyway.
|
|
1451
|
+
// Both halves of the log line are user- or disk-controlled text, so both
|
|
1452
|
+
// go through `printable`: a folder name or an OS message carrying a
|
|
1453
|
+
// control character must not steer the terminal or forge a log line.
|
|
1454
|
+
const folder = path.relative(workspaceDir, absoluteDir).replace(/\\/g, '/');
|
|
1455
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
1456
|
+
logger('workspace').error(`could not list every file under ${printable(folder)} for a delete: ${printable(reason)}`);
|
|
1457
|
+
throw Object.assign(new Error(`Could not list every file under "${folder}" — nothing was deleted. Try again, or ask an admin.`), {
|
|
1458
|
+
status: 500,
|
|
1459
|
+
});
|
|
1040
1460
|
}
|
|
1041
|
-
await walk(absoluteDir);
|
|
1042
1461
|
return out;
|
|
1043
1462
|
}
|
|
1044
1463
|
/**
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1464
|
+
* The error a failed folder keep answers: the original one — its type,
|
|
1465
|
+
* status and payload decide the response — with `message` saying what
|
|
1466
|
+
* landed and what did not. Anything that is not an Error becomes one.
|
|
1467
|
+
*/
|
|
1468
|
+
function withKeptFolderContext(err, message) {
|
|
1469
|
+
if (!(err instanceof Error))
|
|
1470
|
+
return new Error(message);
|
|
1471
|
+
err.message = message;
|
|
1472
|
+
return err;
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Whether a folder exists and holds nothing. A folder that is gone answers
|
|
1476
|
+
* false: it was deleted explicitly, and keeping it would bring it back.
|
|
1053
1477
|
*/
|
|
1054
|
-
async function
|
|
1055
|
-
let entries;
|
|
1478
|
+
async function isEmptyFolder(absoluteDir) {
|
|
1056
1479
|
try {
|
|
1057
|
-
|
|
1480
|
+
return (await fs.readdir(absoluteDir)).length === 0;
|
|
1058
1481
|
}
|
|
1059
|
-
catch {
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
for (const entry of entries) {
|
|
1064
|
-
if (entry.name === '.git' && entry.isDirectory())
|
|
1065
|
-
continue;
|
|
1066
|
-
if (entry.isDirectory()) {
|
|
1067
|
-
await removeEmptyDirs(path.join(absoluteDir, entry.name));
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
// Re-read after pruning children: a subdir we just emptied now lets this
|
|
1071
|
-
// dir become removable too. Any surviving file (or `.git`) keeps it.
|
|
1072
|
-
const remaining = await fs.readdir(absoluteDir);
|
|
1073
|
-
if (remaining.length === 0) {
|
|
1074
|
-
await fs.rmdir(absoluteDir);
|
|
1482
|
+
catch (err) {
|
|
1483
|
+
if (isAbsence(err))
|
|
1484
|
+
return false;
|
|
1485
|
+
throw err;
|
|
1075
1486
|
}
|
|
1076
1487
|
}
|
|
1077
1488
|
//# sourceMappingURL=workspace.routes.js.map
|