@bevel-software/platform-core-backend 0.20.0 → 0.22.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/dist/core/catalog-cache-invalidation.d.ts +7 -2
- package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
- package/dist/core/catalog-cache-invalidation.js +8 -9
- package/dist/core/catalog-cache-invalidation.js.map +1 -1
- package/dist/core/core-ports.d.ts +19 -0
- package/dist/core/core-ports.d.ts.map +1 -1
- package/dist/core/core-ports.js.map +1 -1
- package/dist/core/create-core-server.d.ts +2 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +55 -107
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +41 -4
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +183 -82
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +74 -28
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +157 -20
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/public-config.d.ts +5 -1
- package/dist/core/public-config.d.ts.map +1 -1
- package/dist/core/public-config.js +7 -5
- package/dist/core/public-config.js.map +1 -1
- package/dist/core-config.d.ts +95 -1
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +24 -8
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +18 -1
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +19 -8
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-requests.contract.d.ts +75 -0
- package/dist/modules/access/access-requests.contract.d.ts.map +1 -0
- package/dist/modules/access/access-requests.contract.js +20 -0
- package/dist/modules/access/access-requests.contract.js.map +1 -0
- package/dist/modules/access/access-requests.routes.d.ts +35 -0
- package/dist/modules/access/access-requests.routes.d.ts.map +1 -0
- package/dist/modules/access/access-requests.routes.js +237 -0
- package/dist/modules/access/access-requests.routes.js.map +1 -0
- package/dist/modules/access/access-requests.service.d.ts +123 -0
- package/dist/modules/access/access-requests.service.d.ts.map +1 -0
- package/dist/modules/access/access-requests.service.js +337 -0
- package/dist/modules/access/access-requests.service.js.map +1 -0
- package/dist/modules/access/access.routes.d.ts +2 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +10 -10
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/change-read-gate.d.ts +6 -3
- package/dist/modules/access/change-read-gate.d.ts.map +1 -1
- package/dist/modules/access/change-read-gate.js +9 -6
- package/dist/modules/access/change-read-gate.js.map +1 -1
- package/dist/modules/access/creator-access.d.ts +4 -2
- package/dist/modules/access/creator-access.d.ts.map +1 -1
- package/dist/modules/access/creator-access.js +7 -4
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +12 -0
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +24 -0
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/agent-instructions/read-preamble.d.ts +2 -1
- package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -1
- package/dist/modules/agent-instructions/read-preamble.js +6 -9
- package/dist/modules/agent-instructions/read-preamble.js.map +1 -1
- package/dist/modules/auth/account-admission.d.ts +40 -0
- package/dist/modules/auth/account-admission.d.ts.map +1 -0
- package/dist/modules/auth/account-admission.js +17 -0
- package/dist/modules/auth/account-admission.js.map +1 -0
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +4 -1
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +45 -2
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +44 -3
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +9 -0
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +10 -2
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/advisory-lock.d.ts +17 -0
- package/dist/modules/database/advisory-lock.d.ts.map +1 -1
- package/dist/modules/database/advisory-lock.js +24 -3
- package/dist/modules/database/advisory-lock.js.map +1 -1
- package/dist/modules/database/connection.d.ts +67 -2
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +118 -12
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/migrate.d.ts +1 -1
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +27 -3
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/github-app/github-app.client.d.ts +101 -0
- package/dist/modules/github-app/github-app.client.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.client.js +222 -0
- package/dist/modules/github-app/github-app.client.js.map +1 -0
- package/dist/modules/github-app/github-app.connection.d.ts +102 -0
- package/dist/modules/github-app/github-app.connection.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.connection.js +185 -0
- package/dist/modules/github-app/github-app.connection.js.map +1 -0
- package/dist/modules/github-app/github-app.routes.d.ts +59 -0
- package/dist/modules/github-app/github-app.routes.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.routes.js +323 -0
- package/dist/modules/github-app/github-app.routes.js.map +1 -0
- package/dist/modules/github-app/index.d.ts +4 -0
- package/dist/modules/github-app/index.d.ts.map +1 -0
- package/dist/modules/github-app/index.js +4 -0
- package/dist/modules/github-app/index.js.map +1 -0
- package/dist/modules/kb-fs/branch-name.d.ts +0 -1
- package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
- package/dist/modules/kb-fs/branch-name.js +3 -3
- package/dist/modules/kb-fs/branch-name.js.map +1 -1
- package/dist/modules/kb-fs/clone-config.d.ts +9 -8
- package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
- package/dist/modules/kb-fs/clone-config.js +14 -12
- package/dist/modules/kb-fs/clone-config.js.map +1 -1
- package/dist/modules/kb-fs/remote-url.d.ts +22 -0
- package/dist/modules/kb-fs/remote-url.d.ts.map +1 -0
- package/dist/modules/kb-fs/remote-url.js +35 -0
- package/dist/modules/kb-fs/remote-url.js.map +1 -0
- package/dist/modules/mcp/mcp.service.d.ts +7 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +4 -4
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
- package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -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 +5 -3
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
- package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
- package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
- package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/native.source.js +4 -2
- package/dist/modules/plugins/discovery/native.source.js.map +1 -1
- package/dist/modules/plugins/index.d.ts +1 -1
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js +1 -1
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/join-proposals.d.ts +17 -5
- package/dist/modules/plugins/join-proposals.d.ts.map +1 -1
- package/dist/modules/plugins/join-proposals.js +76 -22
- package/dist/modules/plugins/join-proposals.js.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.js +6 -6
- package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
- package/dist/modules/plugins/join-requests.service.d.ts +113 -18
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-requests.service.js +178 -33
- package/dist/modules/plugins/join-requests.service.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +65 -10
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js +136 -31
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
- package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.service.js +151 -21
- package/dist/modules/plugins/plugin-links.service.js.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +33 -26
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
- package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.js +10 -12
- package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +3 -0
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +48 -17
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.service.d.ts +4 -4
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.service.js +7 -10
- package/dist/modules/plugins/plugins.service.js.map +1 -1
- package/dist/modules/plugins/teams.routes.d.ts +4 -1
- package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
- package/dist/modules/plugins/teams.routes.js +11 -9
- package/dist/modules/plugins/teams.routes.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 +1 -1
- package/dist/modules/secrets-vault/index.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +34 -9
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +113 -26
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/managed-repository.d.ts +43 -0
- package/dist/modules/settings/managed-repository.d.ts.map +1 -0
- package/dist/modules/settings/managed-repository.js +60 -0
- package/dist/modules/settings/managed-repository.js.map +1 -0
- package/dist/modules/settings/repository-source.d.ts +128 -0
- package/dist/modules/settings/repository-source.d.ts.map +1 -0
- package/dist/modules/settings/repository-source.js +150 -0
- package/dist/modules/settings/repository-source.js.map +1 -0
- package/dist/modules/settings/setup.routes.d.ts +34 -4
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +198 -18
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
- package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
- package/dist/modules/skills/allowed-tools-check.js +8 -8
- package/dist/modules/skills/allowed-tools-check.js.map +1 -1
- package/dist/modules/skills/pending-skills.service.d.ts +3 -1
- package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
- package/dist/modules/skills/pending-skills.service.js +9 -6
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts +8 -9
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.js +26 -65
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
- package/dist/modules/skills/skills.routes.d.ts +4 -1
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +4 -4
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +4 -2
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +13 -11
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +15 -0
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -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 -10
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
- package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
- package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
- package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +47 -11
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +14 -6
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +40 -18
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.js +40 -5
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts +45 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +99 -0
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
- package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
- package/dist/modules/workflow/session-ontology.service.js +6 -2
- package/dist/modules/workflow/session-ontology.service.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +3 -1
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +42 -10
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +181 -71
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.js +3 -3
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
- package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
- package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-git.js +15 -13
- package/dist/modules/workspace/startup/kb-git.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +70 -7
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +183 -38
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
- 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 +23 -16
- 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 +7 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
- 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 +12 -5
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +10 -6
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/workspace.routes.d.ts +2 -1
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +8 -7
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +18 -12
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +49 -29
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +2 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +48 -20
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +3 -2
- package/dist/modules/workspace/write-denial.d.ts.map +1 -1
- package/dist/modules/workspace/write-denial.js +6 -5
- package/dist/modules/workspace/write-denial.js.map +1 -1
- package/dist/shared/domain-errors.d.ts +39 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +55 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/git.contract.d.ts +62 -7
- package/dist/shared/git.contract.d.ts.map +1 -1
- package/dist/shared/git.contract.js +30 -8
- package/dist/shared/git.contract.js.map +1 -1
- package/dist/shared/kb-context.d.ts +76 -0
- package/dist/shared/kb-context.d.ts.map +1 -0
- package/dist/shared/kb-context.js +108 -0
- package/dist/shared/kb-context.js.map +1 -0
- package/dist/shared/kb-layout.d.ts +3 -2
- package/dist/shared/kb-layout.d.ts.map +1 -1
- package/dist/shared/kb-layout.js +4 -3
- package/dist/shared/kb-layout.js.map +1 -1
- package/dist/shared/kb-layout.test.js +35 -27
- package/dist/shared/kb-layout.test.js.map +1 -1
- package/dist/shared/pending-proposals.d.ts +4 -1
- package/dist/shared/pending-proposals.d.ts.map +1 -1
- package/dist/shared/pending-proposals.js +3 -4
- package/dist/shared/pending-proposals.js.map +1 -1
- package/dist/shared/redact-secret.d.ts +5 -5
- package/dist/shared/redact-secret.js +5 -5
- package/dist/tenancy/index.d.ts +13 -0
- package/dist/tenancy/index.d.ts.map +1 -0
- package/dist/tenancy/index.js +13 -0
- package/dist/tenancy/index.js.map +1 -0
- package/dist/tenancy/static-tenant-source.d.ts +98 -0
- package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
- package/dist/tenancy/static-tenant-source.js +220 -0
- package/dist/tenancy/static-tenant-source.js.map +1 -0
- package/dist/tenancy/tenant-host.d.ts +80 -0
- package/dist/tenancy/tenant-host.d.ts.map +1 -0
- package/dist/tenancy/tenant-host.js +217 -0
- package/dist/tenancy/tenant-host.js.map +1 -0
- package/dist/tenancy/tenant-runtime.d.ts +91 -0
- package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
- package/dist/tenancy/tenant-runtime.js +174 -0
- package/dist/tenancy/tenant-runtime.js.map +1 -0
- package/dist/tenancy/tenant-secrets.d.ts +24 -0
- package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
- package/dist/tenancy/tenant-secrets.js +30 -0
- package/dist/tenancy/tenant-secrets.js.map +1 -0
- package/dist/tenancy/tenant-source.contract.d.ts +45 -0
- package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
- package/dist/tenancy/tenant-source.contract.js +21 -0
- package/dist/tenancy/tenant-source.contract.js.map +1 -0
- package/migrations/0000_core_init.sql +14 -14
- package/migrations/0003_deployment_settings.sql +1 -1
- package/migrations/0005_github_facade.sql +1 -1
- package/migrations/0012_agent_audit.sql +6 -6
- package/package.json +3 -3
- package/src/__tests__/branch-model.test.ts +7 -6
- package/src/__tests__/kb-context.ts +30 -0
- package/src/__tests__/kb-layout-config.test.ts +35 -30
- package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
- package/src/core/__tests__/lifecycle.test.ts +78 -1
- package/src/core/__tests__/public-config.test.ts +5 -1
- package/src/core/catalog-cache-invalidation.ts +16 -11
- package/src/core/core-ports.ts +19 -0
- package/src/core/create-core-server.ts +64 -107
- package/src/core/create-core-services.ts +238 -96
- package/src/core/lifecycle.ts +214 -29
- package/src/core/public-config.ts +8 -5
- package/src/core-config.ts +107 -8
- package/src/index.ts +25 -2
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
- package/src/modules/access/__tests__/access-requests.recut.test.ts +134 -0
- package/src/modules/access/__tests__/access-requests.routes.test.ts +610 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
- package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
- package/src/modules/access/__tests__/creator-access.test.ts +3 -2
- package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
- package/src/modules/access/access-control.service.ts +20 -6
- package/src/modules/access/access-requests.contract.ts +93 -0
- package/src/modules/access/access-requests.routes.ts +286 -0
- package/src/modules/access/access-requests.service.ts +420 -0
- package/src/modules/access/access.routes.ts +10 -13
- package/src/modules/access/change-read-gate.ts +10 -4
- package/src/modules/access/creator-access.ts +7 -2
- package/src/modules/access-model/access-grammar.ts +22 -0
- package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
- package/src/modules/agent-instructions/read-preamble.ts +10 -12
- package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
- package/src/modules/auth/__tests__/auth.service.test.ts +98 -0
- package/src/modules/auth/account-admission.ts +44 -0
- package/src/modules/auth/account.routes.ts +4 -1
- package/src/modules/auth/auth.service.ts +61 -2
- package/src/modules/auth/oidc-auth-provider.ts +9 -0
- package/src/modules/connection-probe/connection-probe.service.ts +7 -1
- package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
- package/src/modules/database/__tests__/connection.test.ts +98 -0
- package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
- package/src/modules/database/advisory-lock.ts +28 -4
- package/src/modules/database/connection.ts +143 -13
- package/src/modules/database/migrate.ts +48 -14
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
- package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
- package/src/modules/github-app/__tests__/github-app.test.ts +848 -0
- package/src/modules/github-app/github-app.client.ts +268 -0
- package/src/modules/github-app/github-app.connection.ts +204 -0
- package/src/modules/github-app/github-app.routes.ts +359 -0
- package/src/modules/github-app/index.ts +19 -0
- package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
- package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
- package/src/modules/kb-fs/__tests__/remote-url.test.ts +38 -0
- package/src/modules/kb-fs/branch-name.ts +3 -3
- package/src/modules/kb-fs/clone-config.ts +15 -12
- package/src/modules/kb-fs/remote-url.ts +35 -0
- package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
- package/src/modules/mcp/mcp.service.ts +11 -4
- package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
- package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
- package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
- package/src/modules/plugins/__tests__/join-proposals.test.ts +100 -19
- package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
- package/src/modules/plugins/__tests__/join-requests.service.test.ts +28 -11
- package/src/modules/plugins/__tests__/join-requests.settlement.test.ts +371 -0
- package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
- package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
- package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
- package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +12 -3
- package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
- package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
- package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
- package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
- package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
- package/src/modules/plugins/discovery/native.source.ts +4 -1
- package/src/modules/plugins/index.ts +1 -1
- package/src/modules/plugins/join-proposals.ts +87 -19
- package/src/modules/plugins/join-request-jobs.service.ts +8 -7
- package/src/modules/plugins/join-requests.service.ts +203 -43
- package/src/modules/plugins/plugin-links.service.ts +192 -19
- package/src/modules/plugins/plugin-links.ts +147 -27
- package/src/modules/plugins/plugin-provision.service.ts +54 -27
- package/src/modules/plugins/plugin-rename.service.ts +10 -10
- package/src/modules/plugins/plugins.routes.ts +48 -17
- package/src/modules/plugins/plugins.service.ts +7 -11
- package/src/modules/plugins/teams.routes.ts +16 -8
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
- package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
- package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
- package/src/modules/secrets-vault/index.ts +2 -0
- package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
- package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +24 -11
- package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
- package/src/modules/settings/__tests__/repository-source.test.ts +191 -0
- package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
- package/src/modules/settings/__tests__/setup.routes.git-mode.test.ts +353 -0
- package/src/modules/settings/__tests__/setup.routes.github-app.test.ts +282 -0
- package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
- package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +233 -0
- package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
- package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
- package/src/modules/settings/deployment-settings.service.ts +130 -23
- package/src/modules/settings/managed-repository.ts +68 -0
- package/src/modules/settings/repository-source.ts +197 -0
- package/src/modules/settings/setup.routes.ts +233 -19
- package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
- package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +7 -2
- package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
- package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
- package/src/modules/skills/allowed-tools-check.ts +7 -6
- package/src/modules/skills/pending-skills.service.ts +9 -8
- package/src/modules/skills/skill-access-requests.routes.ts +29 -79
- package/src/modules/skills/skills.routes.ts +4 -3
- package/src/modules/skills/skills.service.ts +13 -9
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
- package/src/modules/tool-helpers/tool-context.ts +15 -0
- package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
- 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 +4 -1
- package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
- package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
- package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
- package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
- package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
- package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
- package/src/modules/workflow/__tests__/apply-failure.test.ts +11 -2
- package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
- package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
- package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +187 -35
- package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +148 -41
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +143 -2
- package/src/modules/workflow/agent-tools/workflow.tools.ts +60 -12
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
- package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
- package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
- package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
- package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
- package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
- package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
- package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
- package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +130 -8
- package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
- package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
- package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
- package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +145 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-delete.test.ts +166 -0
- package/src/modules/workflow/git/git.service.ts +49 -17
- package/src/modules/workflow/git/node-git-runner.ts +43 -4
- package/src/modules/workflow/git/pull-request.service.ts +119 -0
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
- package/src/modules/workflow/session-ontology.service.ts +7 -2
- package/src/modules/workflow/workflow.routes.ts +3 -1
- package/src/modules/workflow/workflow.service.ts +201 -76
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +10 -9
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
- package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
- package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
- 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 +2 -1
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
- package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +45 -1
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +237 -10
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +44 -11
- package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
- package/src/modules/workspace/session-ontology.gate.ts +6 -4
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +240 -21
- package/src/modules/workspace/startup/kb-git.ts +15 -22
- package/src/modules/workspace/startup/kb-startup-runner.ts +198 -45
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
- package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
- package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
- package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
- package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
- package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
- package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
- package/src/modules/workspace/startup/steps/template-source.ts +8 -5
- package/src/modules/workspace/workspace.routes.ts +8 -7
- package/src/modules/workspace/workspace.service.ts +47 -28
- package/src/modules/workspace/workspace.tools.ts +56 -20
- package/src/modules/workspace/write-denial.ts +7 -5
- package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
- package/src/shared/domain-errors.ts +58 -0
- package/src/shared/git.contract.ts +80 -8
- package/src/shared/kb-context.ts +130 -0
- package/src/shared/kb-layout.test.ts +37 -27
- package/src/shared/kb-layout.ts +4 -3
- package/src/shared/pending-proposals.ts +7 -4
- package/src/shared/redact-secret.ts +5 -5
- package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
- package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
- package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
- package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
- package/src/tenancy/index.ts +35 -0
- package/src/tenancy/static-tenant-source.ts +296 -0
- package/src/tenancy/tenant-host.ts +261 -0
- package/src/tenancy/tenant-runtime.ts +208 -0
- package/src/tenancy/tenant-secrets.ts +41 -0
- package/src/tenancy/tenant-source.contract.ts +59 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { testKbContext } from '../../../__tests__/kb-context.js';
|
|
2
3
|
import type { AuthUser, PullRequestDetail } from '@bevel-software/platform-shared';
|
|
3
4
|
import type { GitService } from '../git/git.service.js';
|
|
4
5
|
import type { PullRequestService } from '../git/pull-request.service.js';
|
|
@@ -44,17 +45,26 @@ function detail(overrides: Partial<PullRequestDetail> = {}): PullRequestDetail {
|
|
|
44
45
|
branch: 'alice/deal',
|
|
45
46
|
base: 'current-company-state',
|
|
46
47
|
behind: true,
|
|
48
|
+
needsUpdate: true,
|
|
47
49
|
viewerCanUpdate: true,
|
|
48
50
|
headSha: HEAD,
|
|
49
51
|
mergeBaseSha: 'c'.repeat(40),
|
|
52
|
+
// The pre-flight read asks for no patches, but it still names the files —
|
|
53
|
+
// which is what the fallback for a failed diff answers with.
|
|
54
|
+
files: [{ path: 'Sales/Deal.md' }],
|
|
50
55
|
...overrides,
|
|
51
|
-
} as PullRequestDetail;
|
|
56
|
+
} as unknown as PullRequestDetail;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
function harness(opts: {
|
|
55
60
|
first?: PullRequestDetail | null;
|
|
56
61
|
/** The published head of the proposal branch as resolved just before the merge. */
|
|
57
62
|
publishedHead?: string;
|
|
63
|
+
/**
|
|
64
|
+
* The published head AFTER the merge. Defaults to the merge commit; set it
|
|
65
|
+
* equal to the pre-merge head to describe a merge that moved nothing.
|
|
66
|
+
*/
|
|
67
|
+
headAfterMerge?: string;
|
|
58
68
|
resolveError?: Error;
|
|
59
69
|
merge?: { kind: 'clean'; alreadyUpToDate: boolean } | { kind: 'conflicts'; paths: string[] };
|
|
60
70
|
pullError?: Error;
|
|
@@ -63,31 +73,42 @@ function harness(opts: {
|
|
|
63
73
|
changedPathsError?: Error;
|
|
64
74
|
/** How many approval rows the carry-forward wrote. */
|
|
65
75
|
carried?: number;
|
|
66
|
-
/**
|
|
67
|
-
|
|
76
|
+
/** Does the clone hold commits origin has not seen? */
|
|
77
|
+
unpushed?: boolean;
|
|
78
|
+
unpushedError?: Error;
|
|
68
79
|
}) {
|
|
80
|
+
// Two resolves per update: once after the pull (where the branch IS), once
|
|
81
|
+
// after the merge (where it ended up). One mock that answers in order, so a
|
|
82
|
+
// test can describe a head that moved without stubbing call indices.
|
|
83
|
+
const preMergeHead = opts.publishedHead ?? HEAD;
|
|
84
|
+
const postMergeHead = opts.headAfterMerge ?? MERGED_HEAD;
|
|
85
|
+
const resolvePrShas = opts.resolveError
|
|
86
|
+
? vi.fn().mockRejectedValue(opts.resolveError)
|
|
87
|
+
: vi
|
|
88
|
+
.fn()
|
|
89
|
+
.mockResolvedValueOnce({ baseSha: 'b'.repeat(40), headSha: preMergeHead })
|
|
90
|
+
.mockResolvedValue({ baseSha: 'b'.repeat(40), headSha: postMergeHead });
|
|
69
91
|
const git = {
|
|
70
92
|
pull: opts.pullError
|
|
71
93
|
? vi.fn().mockRejectedValue(opts.pullError)
|
|
72
94
|
: vi.fn().mockResolvedValue({ treeChanged: false }),
|
|
73
95
|
mergeFromOrigin: vi.fn().mockResolvedValue(opts.merge ?? { kind: 'clean', alreadyUpToDate: false }),
|
|
74
96
|
push: vi.fn().mockResolvedValue(undefined),
|
|
97
|
+
hasUnpushedCommits: opts.unpushedError
|
|
98
|
+
? vi.fn().mockRejectedValue(opts.unpushedError)
|
|
99
|
+
: vi.fn().mockResolvedValue(opts.unpushed ?? true),
|
|
75
100
|
pathsChangedBetween: opts.changedPathsError
|
|
76
101
|
? vi.fn().mockRejectedValue(opts.changedPathsError)
|
|
77
102
|
: vi.fn().mockResolvedValue(opts.changedPaths ?? []),
|
|
78
|
-
resolvePrShas
|
|
79
|
-
? vi.fn().mockRejectedValue(opts.resolveError)
|
|
80
|
-
: vi.fn().mockResolvedValue({
|
|
81
|
-
baseSha: 'b'.repeat(40),
|
|
82
|
-
headSha: opts.publishedHead ?? HEAD,
|
|
83
|
-
}),
|
|
103
|
+
resolvePrShas,
|
|
84
104
|
};
|
|
85
|
-
const refreshed = detail({ behind: false, headSha:
|
|
105
|
+
const refreshed = detail({ behind: false, needsUpdate: false, headSha: postMergeHead });
|
|
106
|
+
// Exactly two reads per update: the pre-flight (authority, branch names)
|
|
107
|
+
// and the one that goes back. A third would be the cost this ticket removed.
|
|
86
108
|
const getPrDetail = vi
|
|
87
109
|
.fn()
|
|
88
110
|
.mockResolvedValueOnce(opts.first === undefined ? detail() : opts.first)
|
|
89
|
-
.
|
|
90
|
-
.mockResolvedValue(opts.withApprovals ?? refreshed);
|
|
111
|
+
.mockResolvedValue(refreshed);
|
|
91
112
|
const prs = { getPrDetail, invalidateDetailCache: vi.fn() };
|
|
92
113
|
const pendingCommits = { enqueueIfAbsent: vi.fn().mockResolvedValue(true) };
|
|
93
114
|
const reviewWorkflow = {
|
|
@@ -102,7 +123,7 @@ function harness(opts: {
|
|
|
102
123
|
{} as unknown as IAccessControl,
|
|
103
124
|
{} as unknown as FileLockService,
|
|
104
125
|
pendingCommits as unknown as PendingCommitsService,
|
|
105
|
-
|
|
126
|
+
testKbContext(),
|
|
106
127
|
openChangeGate(),
|
|
107
128
|
);
|
|
108
129
|
return { svc, git, prs, pendingCommits, reviewWorkflow, refreshed };
|
|
@@ -110,14 +131,19 @@ function harness(opts: {
|
|
|
110
131
|
|
|
111
132
|
describe('WorkflowService.updateFromTarget', () => {
|
|
112
133
|
it('merges the target into the proposal, pushes, and returns the refreshed detail', async () => {
|
|
113
|
-
const h = harness({});
|
|
114
|
-
await expect(h.svc.updateFromTarget(WS, USER, 7)).resolves.
|
|
134
|
+
const h = harness({ changedPaths: ['Sales/Deal.md'] });
|
|
135
|
+
await expect(h.svc.updateFromTarget(WS, USER, 7)).resolves.toEqual({
|
|
136
|
+
...h.refreshed,
|
|
137
|
+
updatedPaths: ['Sales/Deal.md'],
|
|
138
|
+
});
|
|
115
139
|
|
|
116
|
-
// The permission read is computed for THIS caller
|
|
140
|
+
// The permission read is computed for THIS caller — and asks for no
|
|
141
|
+
// patches: all it decides is authority, state and the two branch names.
|
|
117
142
|
expect(h.prs.getPrDetail).toHaveBeenNthCalledWith(1, 7, {
|
|
118
143
|
fresh: true,
|
|
119
144
|
workspaceId: WS,
|
|
120
145
|
viewerEmail: USER.email,
|
|
146
|
+
patches: false,
|
|
121
147
|
});
|
|
122
148
|
expect(h.git.mergeFromOrigin).toHaveBeenCalledWith(WS, 'alice/deal', 'current-company-state', USER);
|
|
123
149
|
expect(h.git.push).toHaveBeenCalledWith(WS, USER);
|
|
@@ -125,6 +151,29 @@ describe('WorkflowService.updateFromTarget', () => {
|
|
|
125
151
|
expect(h.refreshed.behind).toBe(false);
|
|
126
152
|
});
|
|
127
153
|
|
|
154
|
+
it('costs ONE detail read after the merge', async () => {
|
|
155
|
+
// The whole point of the ticket on the server side. Two reads total: the
|
|
156
|
+
// pre-flight that decides authority, and the one that goes back. The
|
|
157
|
+
// carry-forward runs BEFORE that second read rather than correcting it
|
|
158
|
+
// with a third.
|
|
159
|
+
const h = harness({ changedPaths: ['Sales/Deal.md'], carried: 2 });
|
|
160
|
+
await h.svc.updateFromTarget(WS, USER, 7);
|
|
161
|
+
expect(h.prs.getPrDetail).toHaveBeenCalledTimes(2);
|
|
162
|
+
const carriedAt = h.reviewWorkflow.carryApprovalsForward.mock.invocationCallOrder[0];
|
|
163
|
+
const lastReadAt = h.prs.getPrDetail.mock.invocationCallOrder[1];
|
|
164
|
+
expect(carriedAt).toBeLessThan(lastReadAt);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('replays the pull with --rebase-merges, so an unpushed merge stays a merge', async () => {
|
|
168
|
+
// A plain rebase flattens a merge commit origin has not seen into
|
|
169
|
+
// cherry-picks of the target's commits, which drops the target as a
|
|
170
|
+
// parent — and the request never contains the target's head however many
|
|
171
|
+
// times the update runs.
|
|
172
|
+
const h = harness({});
|
|
173
|
+
await h.svc.updateFromTarget(WS, USER, 7);
|
|
174
|
+
expect(h.git.pull).toHaveBeenCalledWith(WS, { preserveMerges: true });
|
|
175
|
+
});
|
|
176
|
+
|
|
128
177
|
it('refuses a viewer who is neither the author nor able to apply — nothing is merged', async () => {
|
|
129
178
|
const h = harness({ first: detail({ viewerCanUpdate: false }) });
|
|
130
179
|
const err = await h.svc.updateFromTarget(WS, USER, 7).catch((e: unknown) => e);
|
|
@@ -156,13 +205,54 @@ describe('WorkflowService.updateFromTarget', () => {
|
|
|
156
205
|
expect(h.git.push).not.toHaveBeenCalled();
|
|
157
206
|
});
|
|
158
207
|
|
|
159
|
-
it('an already up-to-date merge
|
|
160
|
-
const h = harness({
|
|
161
|
-
|
|
208
|
+
it('an already up-to-date merge with nothing unpushed pushes nothing', async () => {
|
|
209
|
+
const h = harness({
|
|
210
|
+
merge: { kind: 'clean', alreadyUpToDate: true },
|
|
211
|
+
unpushed: false,
|
|
212
|
+
headAfterMerge: HEAD,
|
|
213
|
+
});
|
|
214
|
+
await expect(h.svc.updateFromTarget(WS, USER, 7)).resolves.toEqual({
|
|
215
|
+
...h.refreshed,
|
|
216
|
+
updatedPaths: [],
|
|
217
|
+
});
|
|
162
218
|
expect(h.git.push).not.toHaveBeenCalled();
|
|
163
219
|
expect(h.prs.invalidateDetailCache).toHaveBeenCalledWith(7);
|
|
164
220
|
});
|
|
165
221
|
|
|
222
|
+
it('retries a push that failed last time, even though this merge has nothing to do', async () => {
|
|
223
|
+
// The loop this ticket closes. An earlier update merged the target in and
|
|
224
|
+
// its push failed, so the merge is sitting in the clone. This update's
|
|
225
|
+
// merge is therefore ALREADY up to date — and the old gate, which pushed
|
|
226
|
+
// only when the merge authored a commit, skipped the push and left the
|
|
227
|
+
// request behind on the remote for the next open to find.
|
|
228
|
+
const h = harness({
|
|
229
|
+
merge: { kind: 'clean', alreadyUpToDate: true },
|
|
230
|
+
unpushed: true,
|
|
231
|
+
publishedHead: HEAD,
|
|
232
|
+
headAfterMerge: MERGED_HEAD,
|
|
233
|
+
changedPaths: ['Sales/Deal.md'],
|
|
234
|
+
});
|
|
235
|
+
await h.svc.updateFromTarget(WS, USER, 7);
|
|
236
|
+
expect(h.git.hasUnpushedCommits).toHaveBeenCalledWith(WS);
|
|
237
|
+
expect(h.git.push).toHaveBeenCalledWith(WS, USER);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('falls back to "did this merge author a commit" when git cannot say what is unpushed', async () => {
|
|
241
|
+
// Never "push anyway": a push on a clone with nothing to push is a wasted
|
|
242
|
+
// round trip on every update.
|
|
243
|
+
const clean = harness({ unpushedError: new Error('git exploded') });
|
|
244
|
+
await clean.svc.updateFromTarget(WS, USER, 7);
|
|
245
|
+
expect(clean.git.push).toHaveBeenCalledWith(WS, USER);
|
|
246
|
+
|
|
247
|
+
const nothingToDo = harness({
|
|
248
|
+
unpushedError: new Error('git exploded'),
|
|
249
|
+
merge: { kind: 'clean', alreadyUpToDate: true },
|
|
250
|
+
headAfterMerge: HEAD,
|
|
251
|
+
});
|
|
252
|
+
await nothingToDo.svc.updateFromTarget(WS, USER, 7);
|
|
253
|
+
expect(nothingToDo.git.push).not.toHaveBeenCalled();
|
|
254
|
+
});
|
|
255
|
+
|
|
166
256
|
it('a rebase conflict refreshing the checkout queues recovery for the saves, then refuses', async () => {
|
|
167
257
|
const conflict = new PullRebaseConflictError('alice/deal', ['Sales/Deal.md'], 'rebase stopped');
|
|
168
258
|
const h = harness({ pullError: conflict });
|
|
@@ -182,15 +272,13 @@ describe('WorkflowService.updateFromTarget', () => {
|
|
|
182
272
|
});
|
|
183
273
|
|
|
184
274
|
describe('WorkflowService.updateFromTarget: the approvals the merge did not touch', () => {
|
|
185
|
-
it('carries them onto the new head,
|
|
186
|
-
const
|
|
187
|
-
const h = harness({
|
|
188
|
-
changedPaths: ['Sales/Deal.md'],
|
|
189
|
-
carried: 2,
|
|
190
|
-
withApprovals,
|
|
191
|
-
});
|
|
275
|
+
it('carries them onto the new head, before the one detail read that goes back', async () => {
|
|
276
|
+
const h = harness({ changedPaths: ['Sales/Deal.md'], carried: 2 });
|
|
192
277
|
|
|
193
|
-
await expect(h.svc.updateFromTarget(WS, USER, 7)).resolves.
|
|
278
|
+
await expect(h.svc.updateFromTarget(WS, USER, 7)).resolves.toEqual({
|
|
279
|
+
...h.refreshed,
|
|
280
|
+
updatedPaths: ['Sales/Deal.md'],
|
|
281
|
+
});
|
|
194
282
|
|
|
195
283
|
// What moved is git's answer between the two heads — never a guess, and
|
|
196
284
|
// never the request's own three-dot diff against the target.
|
|
@@ -201,23 +289,33 @@ describe('WorkflowService.updateFromTarget: the approvals the merge did not touc
|
|
|
201
289
|
MERGED_HEAD,
|
|
202
290
|
['Sales/Deal.md'],
|
|
203
291
|
);
|
|
204
|
-
// The first refreshed detail was assembled before the rows existed, so it
|
|
205
|
-
// is not the one that goes back.
|
|
206
|
-
expect(h.prs.getPrDetail).toHaveBeenCalledTimes(3);
|
|
207
292
|
});
|
|
208
293
|
|
|
209
|
-
it('
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
294
|
+
it('answers the same list as updatedPaths — carried and re-read cannot disagree', async () => {
|
|
295
|
+
// A file whose approval was carried (so: untouched by the merge) that the
|
|
296
|
+
// dialog then re-read would be the dialog discarding content the server
|
|
297
|
+
// just called unchanged.
|
|
298
|
+
const h = harness({ changedPaths: ['Sales/Deal.md', 'Sales/Terms.md'], carried: 1 });
|
|
299
|
+
const result = await h.svc.updateFromTarget(WS, USER, 7);
|
|
300
|
+
expect(result.updatedPaths).toEqual(['Sales/Deal.md', 'Sales/Terms.md']);
|
|
301
|
+
expect(h.reviewWorkflow.carryApprovalsForward).toHaveBeenCalledWith(
|
|
302
|
+
7,
|
|
303
|
+
HEAD,
|
|
304
|
+
MERGED_HEAD,
|
|
305
|
+
result.updatedPaths,
|
|
306
|
+
);
|
|
214
307
|
});
|
|
215
308
|
|
|
216
|
-
it('touches nothing when the
|
|
217
|
-
const h = harness({
|
|
218
|
-
|
|
309
|
+
it('touches nothing when the head did not move', async () => {
|
|
310
|
+
const h = harness({
|
|
311
|
+
merge: { kind: 'clean', alreadyUpToDate: true },
|
|
312
|
+
unpushed: false,
|
|
313
|
+
headAfterMerge: HEAD,
|
|
314
|
+
});
|
|
315
|
+
const result = await h.svc.updateFromTarget(WS, USER, 7);
|
|
219
316
|
expect(h.git.pathsChangedBetween).not.toHaveBeenCalled();
|
|
220
317
|
expect(h.reviewWorkflow.carryApprovalsForward).not.toHaveBeenCalled();
|
|
318
|
+
expect(result.updatedPaths).toEqual([]);
|
|
221
319
|
});
|
|
222
320
|
|
|
223
321
|
it('touches nothing when the merge conflicted — the rows describe a head that still stands', async () => {
|
|
@@ -249,10 +347,12 @@ describe('WorkflowService.updateFromTarget: the approvals the merge did not touc
|
|
|
249
347
|
it('falls back to the head the detail reported when that head cannot be resolved', async () => {
|
|
250
348
|
// Bookkeeping never costs the update: an unresolvable ref leaves the
|
|
251
349
|
// carry-forward working off the detail's head, exactly as it did before.
|
|
350
|
+
// Both resolves fail, so the head reads as unmoved from the detail's own
|
|
351
|
+
// — there is no pair of shas to diff, and the update still lands.
|
|
252
352
|
const h = harness({ resolveError: new Error('no such ref'), carried: 1 });
|
|
253
353
|
await h.svc.updateFromTarget(WS, USER, 7);
|
|
254
354
|
expect(h.git.push).toHaveBeenCalledWith(WS, USER);
|
|
255
|
-
expect(h.reviewWorkflow.carryApprovalsForward).
|
|
355
|
+
expect(h.reviewWorkflow.carryApprovalsForward).not.toHaveBeenCalled();
|
|
256
356
|
});
|
|
257
357
|
|
|
258
358
|
it('carries nothing when there is no head to compare at all', async () => {
|
|
@@ -265,7 +365,10 @@ describe('WorkflowService.updateFromTarget: the approvals the merge did not touc
|
|
|
265
365
|
resolveError: new Error('no such ref'),
|
|
266
366
|
carried: 1,
|
|
267
367
|
});
|
|
268
|
-
await expect(h.svc.updateFromTarget(WS, USER, 7)).resolves.
|
|
368
|
+
await expect(h.svc.updateFromTarget(WS, USER, 7)).resolves.toEqual({
|
|
369
|
+
...h.refreshed,
|
|
370
|
+
updatedPaths: [],
|
|
371
|
+
});
|
|
269
372
|
expect(h.git.push).toHaveBeenCalledWith(WS, USER);
|
|
270
373
|
expect(h.git.pathsChangedBetween).not.toHaveBeenCalled();
|
|
271
374
|
expect(h.reviewWorkflow.carryApprovalsForward).not.toHaveBeenCalled();
|
|
@@ -275,7 +378,11 @@ describe('WorkflowService.updateFromTarget: the approvals the merge did not touc
|
|
|
275
378
|
// A request that IS up to date is worth more than the carry-forward: the
|
|
276
379
|
// approvals simply go stale, exactly as they did before this existed.
|
|
277
380
|
const h = harness({ changedPathsError: new Error('git exploded') });
|
|
278
|
-
await
|
|
381
|
+
const result = await h.svc.updateFromTarget(WS, USER, 7);
|
|
382
|
+
expect(result).toMatchObject({ number: 7, behind: false });
|
|
279
383
|
expect(h.reviewWorkflow.carryApprovalsForward).not.toHaveBeenCalled();
|
|
384
|
+
// Which files moved is unknown, so every file the request had is named:
|
|
385
|
+
// slow beats a dialog that goes on presenting pre-merge text as current.
|
|
386
|
+
expect(result.updatedPaths).toEqual(['Sales/Deal.md']);
|
|
280
387
|
});
|
|
281
388
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Server as HttpServer } from 'node:http';
|
|
2
2
|
import express from 'express';
|
|
3
3
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
|
+
import { testKbContext } from '../../../../__tests__/kb-context.js';
|
|
4
5
|
import { ToolRegistry } from '../../../tool-registry/tool-registry.js';
|
|
5
6
|
import { InternalTokenService } from '../../../tool-auth/internal-token.service.js';
|
|
6
7
|
import { createToolAuthMiddleware } from '../../../tool-auth/tool-auth.middleware.js';
|
|
@@ -96,7 +97,7 @@ async function start(): Promise<string> {
|
|
|
96
97
|
const toolHandler = createToolHandlerFactory(resolve);
|
|
97
98
|
|
|
98
99
|
const router = express.Router();
|
|
99
|
-
registerWorkflowTools(registry, router, toolAuth, toolHandler,
|
|
100
|
+
registerWorkflowTools(registry, router, toolAuth, toolHandler, testKbContext());
|
|
100
101
|
router.use(createManualRoutes(registry, toolAuth));
|
|
101
102
|
|
|
102
103
|
const app = express();
|
|
@@ -277,9 +278,149 @@ describe('registerWorkflowTools', () => {
|
|
|
277
278
|
expect(calls.filter((c) => c[0] === 'createBranch')).toHaveLength(0);
|
|
278
279
|
});
|
|
279
280
|
|
|
281
|
+
/**
|
|
282
|
+
* These tools address their workspace by ID — `workspaceIdForBranch(branch)`
|
|
283
|
+
* straight from the argument — so they never pass the `getFilesystem` choke
|
|
284
|
+
* point that guards the file tools. A branch-less call used to commit to a
|
|
285
|
+
* workspace id that was literally the string "undefined" — and `create_branch`
|
|
286
|
+
* used to fork from one, cloning a branch of that name and answering "There is
|
|
287
|
+
* no branch named undefined." The guard sits on the mount and is keyed on
|
|
288
|
+
* whether the tool's declared inputs REQUIRE `branch`, so it covers the
|
|
289
|
+
* injected input and a tool's own alike, without any of them remembering it.
|
|
290
|
+
*/
|
|
291
|
+
describe('a branch-less call to a tool that declares `branch`', () => {
|
|
292
|
+
/**
|
|
293
|
+
* Every tool whose DECLARED inputs require `branch`, read off the mounted
|
|
294
|
+
* registry — not a list written by hand. The hand-written list is how the
|
|
295
|
+
* gap that failed Local Testing stayed invisible: it named the three tools
|
|
296
|
+
* that take the injected input and missed `create_branch`, whose `branch`
|
|
297
|
+
* is its own (the fork base) and is just as required. Anything mounted
|
|
298
|
+
* later is swept in without this file being touched.
|
|
299
|
+
*/
|
|
300
|
+
const branchTakingTools = async (): Promise<string[]> =>
|
|
301
|
+
(await registryRef!.listInternal())
|
|
302
|
+
.filter((t) => {
|
|
303
|
+
const body = (t.inputs as { properties?: { body?: { required?: string[] } } }).properties?.body;
|
|
304
|
+
return (body?.required ?? []).includes('branch');
|
|
305
|
+
})
|
|
306
|
+
.map((t) => t.name);
|
|
307
|
+
|
|
308
|
+
// The inputs each tool needs BESIDES `branch`, so the only thing wrong with
|
|
309
|
+
// every call below is the missing branch.
|
|
310
|
+
const bodyFor = (tool: string): Record<string, unknown> =>
|
|
311
|
+
({
|
|
312
|
+
commit_change: { summary: 's' },
|
|
313
|
+
save_file: { path: 'KnowledgeBase/x.md', content: 'c' },
|
|
314
|
+
create_branch: { name: 'alice/new-draft' },
|
|
315
|
+
write_file: { path: 'KnowledgeBase/x.md', content: 'c' },
|
|
316
|
+
})[tool] ?? {};
|
|
317
|
+
|
|
318
|
+
it('400s branch-required on every mounted tool that declares `branch`, and acts on nothing', async () => {
|
|
319
|
+
const base = await start();
|
|
320
|
+
const tools = await branchTakingTools();
|
|
321
|
+
// Both kinds are in here: the injected input and a tool's own required
|
|
322
|
+
// `branch`. `create_branch` is the one the reported bug survived on.
|
|
323
|
+
expect(tools).toContain('commit_change');
|
|
324
|
+
expect(tools).toContain('create_branch');
|
|
325
|
+
expect(tools).toContain('switch_branch');
|
|
326
|
+
|
|
327
|
+
for (const tool of tools) {
|
|
328
|
+
const res = await post(`${base}/api/agent/tools/${tool}`, writeTok(), bodyFor(tool));
|
|
329
|
+
|
|
330
|
+
expect(res.status, `${tool} must 400 on a branch-less call`).toBe(400);
|
|
331
|
+
expect(await res.json(), `${tool} must answer the shared refusal`).toEqual({
|
|
332
|
+
kind: 'branch-required',
|
|
333
|
+
error: '`branch` is required: pass the branch (draft) you are working on.',
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
// No workflow call was made at all — least of all one naming a workspace
|
|
337
|
+
// id built out of the missing value, or a branch forked from it.
|
|
338
|
+
expect(calls).toEqual([]);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* The exact shapes Local Testing drove over MCP against `create_branch`:
|
|
343
|
+
* a missing branch answered 404 `There is no branch named undefined.`
|
|
344
|
+
* (a clone of that "branch" was attempted), an empty one 500 'Invalid
|
|
345
|
+
* workspace ID', and `["main"]` — which `encodeURIComponent` stringifies
|
|
346
|
+
* straight back to `main` — answered 200 and really created and pushed a
|
|
347
|
+
* branch off the default. All four are one refusal now.
|
|
348
|
+
*/
|
|
349
|
+
it('refuses every absent shape on create_branch, and forks from nothing', async () => {
|
|
350
|
+
const base = await start();
|
|
351
|
+
const absent: Array<[string, Record<string, unknown>]> = [
|
|
352
|
+
['missing', { name: 'alice/new-draft' }],
|
|
353
|
+
['empty', { name: 'alice/new-draft', branch: '' }],
|
|
354
|
+
['null', { name: 'alice/new-draft', branch: null }],
|
|
355
|
+
['a number', { name: 'alice/new-draft', branch: 42 }],
|
|
356
|
+
['an array (stringifies to a real branch name)', { name: 'alice/new-draft', branch: ['main'] }],
|
|
357
|
+
['the literal "undefined"', { name: 'alice/new-draft', branch: 'undefined' }],
|
|
358
|
+
['the literal "null"', { name: 'alice/new-draft', branch: 'null' }],
|
|
359
|
+
];
|
|
360
|
+
|
|
361
|
+
for (const [label, body] of absent) {
|
|
362
|
+
const res = await post(`${base}/api/agent/tools/create_branch`, writeTok(), body);
|
|
363
|
+
expect(res.status, `branch ${label} must 400`).toBe(400);
|
|
364
|
+
const answered = await res.json();
|
|
365
|
+
expect(answered.kind, `branch ${label} must answer branch-required`).toBe('branch-required');
|
|
366
|
+
expect(JSON.stringify(answered), `branch ${label} must not echo an absent value`).not.toContain('undefined');
|
|
367
|
+
}
|
|
368
|
+
// Nothing was forked, from any workspace id.
|
|
369
|
+
expect(calls).toEqual([]);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* `create_branch` compares `branch` (the fork base) to `name` and refuses
|
|
374
|
+
* the two being equal, QUOTING the name. A call that sent neither compared
|
|
375
|
+
* undefined to undefined, matched, and answered "not 'undefined', the draft
|
|
376
|
+
* being created" — an absent value presented as a draft name. `name` is
|
|
377
|
+
* refused by name instead, so no such sentence can be produced.
|
|
378
|
+
*/
|
|
379
|
+
it('refuses a missing `name` without quoting it back', async () => {
|
|
380
|
+
const base = await start();
|
|
381
|
+
|
|
382
|
+
const res = await post(`${base}/api/agent/tools/create_branch`, writeTok(), { branch: 'main' });
|
|
383
|
+
|
|
384
|
+
expect(res.status).toBe(400);
|
|
385
|
+
const answered = await res.json();
|
|
386
|
+
expect(answered).toEqual({ kind: 'name-required', error: '`name` is required: pass the name of the draft to create.' });
|
|
387
|
+
expect(JSON.stringify(answered)).not.toContain('undefined');
|
|
388
|
+
expect(calls).toEqual([]);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('still forks from a named base once both inputs are given', async () => {
|
|
392
|
+
const base = await start();
|
|
393
|
+
// The guards refuse absent inputs, not the tool.
|
|
394
|
+
const res = await post(`${base}/api/agent/tools/create_branch`, writeTok(), { name: 'alice/new-draft', branch: 'main' });
|
|
395
|
+
|
|
396
|
+
expect(res.status).toBe(200);
|
|
397
|
+
expect(calls).toContainEqual(['createBranch', 'main', 'alice/new-draft']);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('refuses the stringified absent values the same way', async () => {
|
|
401
|
+
const base = await start();
|
|
402
|
+
for (const literal of ['undefined', 'null']) {
|
|
403
|
+
const res = await post(`${base}/api/agent/tools/commit_change`, writeTok(), { summary: 's', branch: literal });
|
|
404
|
+
expect(res.status, `branch "${literal}" must 400`).toBe(400);
|
|
405
|
+
expect((await res.json()).kind).toBe('branch-required');
|
|
406
|
+
}
|
|
407
|
+
expect(calls).toEqual([]);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('leaves a tool that declares no `branch` alone', async () => {
|
|
411
|
+
const base = await start();
|
|
412
|
+
// `list_branches` is repo-global and deliberately takes no branch: the
|
|
413
|
+
// guard must not start demanding one from the tools that opted out.
|
|
414
|
+
expect((await post(`${base}/api/agent/tools/list_branches`, writeTok(), {})).status).toBe(200);
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
|
|
280
418
|
it('works under a connection key too (both surface)', async () => {
|
|
281
419
|
const base = await start();
|
|
282
|
-
|
|
420
|
+
// `branch` is named because every caller must name it — this test is about
|
|
421
|
+
// the connection-key SURFACE, and an external key is precisely the caller
|
|
422
|
+
// that carries no focused branch to fall back on.
|
|
423
|
+
expect((await post(`${base}/api/agent/tools/commit_change`, 'bevel_key', { summary: 's', branch: WS })).status).toBe(200);
|
|
283
424
|
});
|
|
284
425
|
|
|
285
426
|
it('switch_branch validates + pre-warms + emits a user-scoped event (internal-only)', async () => {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Router, RequestHandler } from 'express';
|
|
2
|
-
import { DEFAULT_BRANCH, PROTECTED_BRANCHES } from '@bevel-software/platform-shared';
|
|
3
2
|
import type { IToolRegistry, JsonSchema } from '../../tool-registry/tool.contract.js';
|
|
4
3
|
import { ToolError, type ToolContext, type ToolHandler } from '../../tool-helpers/tool.contract.js';
|
|
5
4
|
import { toolDef, withBranchInput } from '../../tool-helpers/tool-def.js';
|
|
6
5
|
import type { ToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
|
|
7
6
|
import { requireInternalSource } from '../../tool-auth/tool-auth.middleware.js';
|
|
7
|
+
import type { KbContext } from '../../../shared/kb-context.js';
|
|
8
|
+
import { assertBranchProvided } from '../../../shared/domain-errors.js';
|
|
8
9
|
import { workspaceIdForBranch } from '../../../shared/workspace-id.js';
|
|
9
10
|
import { assertInsideRepo, normalizePathArgs } from '../../kb-fs/repo-path.js';
|
|
10
11
|
import { RETIRED_TOOL_MESSAGES } from '@bevel-software/platform-mcp-core';
|
|
@@ -14,9 +15,10 @@ function stripKbDir(path: string, kbDirName: string): string {
|
|
|
14
15
|
return path.startsWith(`${kbDirName}/`) ? path.slice(kbDirName.length + 1) : path;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
const protectedInline = (
|
|
18
|
+
// Read at call time, not captured: the branch model is applied during boot,
|
|
19
|
+
// and a value taken at registration would be the empty set that exists before it.
|
|
20
|
+
const protectedInline = (kb: Pick<KbContext, 'protectedBranches'>) =>
|
|
21
|
+
[...kb.protectedBranches].map((b) => `\`${b}\``).join(' / ');
|
|
20
22
|
|
|
21
23
|
// Output sub-schemas for the git-aliased workflow payloads (Branch, Change,
|
|
22
24
|
// ChangeRequestComment, …). Defined once and referenced by the individual tool
|
|
@@ -131,9 +133,10 @@ export function registerWorkflowTools(
|
|
|
131
133
|
router: Router,
|
|
132
134
|
toolAuth: RequestHandler,
|
|
133
135
|
toolHandler: ToolHandlerFactory,
|
|
134
|
-
/** The clone folder at the workspace root
|
|
135
|
-
|
|
136
|
+
/** The clone folder at the workspace root (`save_file` refuses a path outside it) and the branch model. */
|
|
137
|
+
kb: Pick<KbContext, 'kbDirName' | 'defaultBranch' | 'defaultWorkspaceId' | 'protectedBranches'>,
|
|
136
138
|
): void {
|
|
139
|
+
const { kbDirName } = kb;
|
|
137
140
|
const mount = (spec: {
|
|
138
141
|
name: string;
|
|
139
142
|
description: string;
|
|
@@ -142,16 +145,30 @@ export function registerWorkflowTools(
|
|
|
142
145
|
write: boolean;
|
|
143
146
|
/** Register on the internal catalog only (e.g. agent-control tools that make no sense to a remote caller). */
|
|
144
147
|
internalOnly?: boolean;
|
|
145
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* Skip the auto-injected `branch` input — for a tool that declares its own
|
|
150
|
+
* `branch` with its own meaning (`create_branch`'s fork base,
|
|
151
|
+
* `switch_branch`'s target draft) or none at all (`merge_branch`,
|
|
152
|
+
* `open_change_request`, the repo-global reads). It says NOTHING about
|
|
153
|
+
* whether the tool requires a branch: that is read off the declared schema
|
|
154
|
+
* below, because reading it off this flag is what let `create_branch` opt
|
|
155
|
+
* out of the check while still demanding the input.
|
|
156
|
+
*/
|
|
146
157
|
skipBranch?: boolean;
|
|
147
158
|
handler: ToolHandler;
|
|
148
159
|
}): void => {
|
|
149
160
|
const path = `/api/agent/tools/${spec.name}`;
|
|
161
|
+
const inputs = spec.skipBranch ? spec.inputs : withBranchInput(spec.inputs);
|
|
162
|
+
// The tool's OWN declaration is the only honest answer to "must this call
|
|
163
|
+
// name a branch": the injected input and a hand-declared one (the fork
|
|
164
|
+
// base, the draft to switch to) are equally required, and a tool that adds
|
|
165
|
+
// or drops the input later moves this with it.
|
|
166
|
+
const requiresBranch = ((inputs as { required?: string[] }).required ?? []).includes('branch');
|
|
150
167
|
const def = toolDef({
|
|
151
168
|
name: spec.name,
|
|
152
169
|
description: spec.description,
|
|
153
170
|
path,
|
|
154
|
-
inputs
|
|
171
|
+
inputs,
|
|
155
172
|
outputs: spec.outputs,
|
|
156
173
|
tags: spec.write ? ['workflow', 'write'] : ['workflow'],
|
|
157
174
|
});
|
|
@@ -169,7 +186,27 @@ export function registerWorkflowTools(
|
|
|
169
186
|
// normaliser: the root-anchored `/<kbDirName>/…` form names the same
|
|
170
187
|
// workspace path, and a path with no prefix is placed under
|
|
171
188
|
// `<kbDirName>/` rather than refused.
|
|
172
|
-
toolHandler(
|
|
189
|
+
toolHandler(
|
|
190
|
+
(args, ctx) => {
|
|
191
|
+
// These tools hand `branch` STRAIGHT to `workspaceIdForBranch` —
|
|
192
|
+
// they address a workspace by id rather than going through
|
|
193
|
+
// `getFilesystem`, so the choke point that guards the file tools
|
|
194
|
+
// never sees them. Without this, a branch-less `commit_change`
|
|
195
|
+
// commits to a workspace id literally named "undefined", and a
|
|
196
|
+
// branch-less `create_branch` forks from one: it clones a branch of
|
|
197
|
+
// that name, fails, and answers `There is no branch named undefined.`
|
|
198
|
+
//
|
|
199
|
+
// Keyed on whether the SCHEMA requires `branch`, not on whether the
|
|
200
|
+
// input was injected. `create_branch` and `switch_branch` declare
|
|
201
|
+
// their own required `branch`; a check keyed on the injection skipped
|
|
202
|
+
// exactly those two, which is how the reported bug survived on
|
|
203
|
+
// `create_branch` — the one tool whose `branch` is a branch the
|
|
204
|
+
// caller must already have.
|
|
205
|
+
if (requiresBranch) assertBranchProvided(args.branch);
|
|
206
|
+
return spec.handler(normalizePathArgs(args, kbDirName), ctx);
|
|
207
|
+
},
|
|
208
|
+
{ write: spec.write },
|
|
209
|
+
),
|
|
173
210
|
);
|
|
174
211
|
};
|
|
175
212
|
|
|
@@ -180,7 +217,7 @@ export function registerWorkflowTools(
|
|
|
180
217
|
// just to run a global op. Falls back to the default branch on a cold start
|
|
181
218
|
// with no workspaces yet.
|
|
182
219
|
const repoGlobalWorkspaceId = async (ctx: ToolContext): Promise<string> =>
|
|
183
|
-
(await ctx.workspaceService.findAnyWorkspaceId()) ??
|
|
220
|
+
(await ctx.workspaceService.findAnyWorkspaceId()) ?? kb.defaultWorkspaceId();
|
|
184
221
|
|
|
185
222
|
mount({
|
|
186
223
|
name: 'list_branches',
|
|
@@ -303,7 +340,7 @@ export function registerWorkflowTools(
|
|
|
303
340
|
name: 'create_branch',
|
|
304
341
|
description:
|
|
305
342
|
'Create a new unprotected draft named `name`, forked from the existing branch `branch`. The ' +
|
|
306
|
-
`backend rejects protected names (${protectedInline()}) and filesystem-invalid names — surface ` +
|
|
343
|
+
`backend rejects protected names (${protectedInline(kb)}) and filesystem-invalid names — surface ` +
|
|
307
344
|
'those errors verbatim. Convention: `<email-localpart>/<kebab-slug>`. Does NOT switch the ' +
|
|
308
345
|
'agent onto the new draft.',
|
|
309
346
|
// `branch` here is the fork BASE — its own meaning — so skip the generic
|
|
@@ -328,6 +365,17 @@ export function registerWorkflowTools(
|
|
|
328
365
|
handler: async (args, ctx: ToolContext) => {
|
|
329
366
|
const name = args.name as string;
|
|
330
367
|
const base = args.branch as string;
|
|
368
|
+
// `name` is declared required too, and the same-name refusal below quotes
|
|
369
|
+
// it. With nothing enforcing it, a call that named neither input compared
|
|
370
|
+
// undefined to undefined, matched, and answered "not 'undefined', the
|
|
371
|
+
// draft being created" — an absent value presented as a draft name, the
|
|
372
|
+
// very sentence this ticket exists to stop. Refused by name instead,
|
|
373
|
+
// without echoing what was not sent.
|
|
374
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
375
|
+
throw new ToolError('`name` is required: pass the name of the draft to create.', 400, {
|
|
376
|
+
kind: 'name-required',
|
|
377
|
+
});
|
|
378
|
+
}
|
|
331
379
|
// The git op runs in the base's workspace, whose clone has the base
|
|
332
380
|
// checked out — the new draft forks from its HEAD. Resolving a workspace
|
|
333
381
|
// lazily clones its branch from origin, so a `branch` naming the
|
|
@@ -356,7 +404,7 @@ export function registerWorkflowTools(
|
|
|
356
404
|
type: 'object',
|
|
357
405
|
properties: {
|
|
358
406
|
sourceBranch: { type: 'string', minLength: 1, description: 'The draft branch carrying the changes.' },
|
|
359
|
-
targetBranch: { type: 'string', minLength: 1, description: `The branch to apply to (e.g. '${
|
|
407
|
+
targetBranch: { type: 'string', minLength: 1, description: `The branch to apply to (e.g. '${kb.defaultBranch}').` },
|
|
360
408
|
title: { type: 'string', minLength: 1, maxLength: 256, description: 'Short imperative title (≤256 chars).' },
|
|
361
409
|
description: { type: 'string', description: 'Optional markdown body shown verbatim to reviewers.' },
|
|
362
410
|
},
|