@bevel-software/platform-core-backend 0.25.2 → 0.27.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/agent-guide/access-control.md +251 -0
- package/agent-guide/conventions.md +35 -0
- package/agent-guide/directory-structure.md +145 -0
- package/agent-guide/finding-things.md +7 -0
- package/agent-guide/html-views.md +83 -0
- package/agent-guide/introduction.md +27 -0
- package/agent-guide/new-knowledge-base.md +24 -0
- package/agent-guide/skills.md +47 -0
- package/agent-guide/tool-manuals.md +227 -0
- package/agent-guide/where-a-new-file-goes.md +36 -0
- package/dist/assets.d.ts +26 -0
- package/dist/assets.d.ts.map +1 -1
- package/dist/assets.js +35 -2
- package/dist/assets.js.map +1 -1
- package/dist/core/catalog-revision.d.ts +19 -1
- package/dist/core/catalog-revision.d.ts.map +1 -1
- package/dist/core/catalog-revision.js +14 -3
- package/dist/core/catalog-revision.js.map +1 -1
- package/dist/core/core-ports.d.ts +11 -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 +5 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +65 -3
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +35 -0
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +114 -12
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +16 -1
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +18 -1
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core-config.d.ts +21 -0
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +22 -1
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +17 -0
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +2 -0
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +27 -0
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/directory-sync-bot.js +1 -1
- package/dist/modules/access/directory-sync-bot.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.d.ts +145 -0
- package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -0
- package/dist/modules/agent-guide/agent-guide.js +199 -0
- package/dist/modules/agent-guide/agent-guide.js.map +1 -0
- package/dist/modules/agent-guide/agent-guide.tools.d.ts +24 -0
- package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -0
- package/dist/modules/agent-guide/agent-guide.tools.js +100 -0
- package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -0
- package/dist/modules/agent-guide/index.d.ts +4 -0
- package/dist/modules/agent-guide/index.d.ts.map +1 -0
- package/dist/modules/agent-guide/index.js +4 -0
- package/dist/modules/agent-guide/index.js.map +1 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +3 -2
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.js +3 -2
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +14 -6
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +28 -8
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/index.d.ts +1 -1
- package/dist/modules/agent-instructions/index.d.ts.map +1 -1
- package/dist/modules/agent-instructions/index.js +1 -1
- package/dist/modules/agent-instructions/index.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +10 -50
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.js +51 -104
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
- package/dist/modules/audit/agent-audit.service.d.ts +21 -2
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
- package/dist/modules/audit/agent-audit.service.js +43 -2
- package/dist/modules/audit/agent-audit.service.js.map +1 -1
- package/dist/modules/audit/agent-connection.routes.d.ts +34 -0
- package/dist/modules/audit/agent-connection.routes.d.ts.map +1 -0
- package/dist/modules/audit/agent-connection.routes.js +38 -0
- package/dist/modules/audit/agent-connection.routes.js.map +1 -0
- package/dist/modules/audit/audit.contract.d.ts +24 -0
- package/dist/modules/audit/audit.contract.d.ts.map +1 -1
- package/dist/modules/audit/audit.contract.js.map +1 -1
- package/dist/modules/audit/index.d.ts +1 -0
- package/dist/modules/audit/index.d.ts.map +1 -1
- package/dist/modules/audit/index.js +1 -0
- package/dist/modules/audit/index.js.map +1 -1
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +10 -3
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.middleware.d.ts +7 -0
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
- package/dist/modules/auth/auth.middleware.js +1 -1
- package/dist/modules/auth/auth.middleware.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 +11 -3
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +96 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +32 -3
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/embed/account-link.service.d.ts +42 -0
- package/dist/modules/embed/account-link.service.d.ts.map +1 -0
- package/dist/modules/embed/account-link.service.js +50 -0
- package/dist/modules/embed/account-link.service.js.map +1 -0
- package/dist/modules/embed/embed-link.d.ts +58 -0
- package/dist/modules/embed/embed-link.d.ts.map +1 -0
- package/dist/modules/embed/embed-link.js +160 -0
- package/dist/modules/embed/embed-link.js.map +1 -0
- package/dist/modules/embed/embed.errors.d.ts +30 -0
- package/dist/modules/embed/embed.errors.d.ts.map +1 -0
- package/dist/modules/embed/embed.errors.js +42 -0
- package/dist/modules/embed/embed.errors.js.map +1 -0
- package/dist/modules/embed/embed.interface.d.ts +204 -0
- package/dist/modules/embed/embed.interface.d.ts.map +1 -0
- package/dist/modules/embed/embed.interface.js +2 -0
- package/dist/modules/embed/embed.interface.js.map +1 -0
- package/dist/modules/embed/embed.routes.d.ts +59 -0
- package/dist/modules/embed/embed.routes.d.ts.map +1 -0
- package/dist/modules/embed/embed.routes.js +343 -0
- package/dist/modules/embed/embed.routes.js.map +1 -0
- package/dist/modules/embed/embed.service.d.ts +169 -0
- package/dist/modules/embed/embed.service.d.ts.map +1 -0
- package/dist/modules/embed/embed.service.js +627 -0
- package/dist/modules/embed/embed.service.js.map +1 -0
- package/dist/modules/embed/embed.tools.d.ts +51 -0
- package/dist/modules/embed/embed.tools.d.ts.map +1 -0
- package/dist/modules/embed/embed.tools.js +170 -0
- package/dist/modules/embed/embed.tools.js.map +1 -0
- package/dist/modules/embed/mcp-app.d.ts +64 -0
- package/dist/modules/embed/mcp-app.d.ts.map +1 -0
- package/dist/modules/embed/mcp-app.js +147 -0
- package/dist/modules/embed/mcp-app.js.map +1 -0
- package/dist/modules/embed/mcp-app.routes.d.ts +21 -0
- package/dist/modules/embed/mcp-app.routes.d.ts.map +1 -0
- package/dist/modules/embed/mcp-app.routes.js +36 -0
- package/dist/modules/embed/mcp-app.routes.js.map +1 -0
- package/dist/modules/github-app/github-app.connection.d.ts +15 -0
- package/dist/modules/github-app/github-app.connection.d.ts.map +1 -1
- package/dist/modules/github-app/github-app.connection.js +34 -3
- package/dist/modules/github-app/github-app.connection.js.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.d.ts +65 -0
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +300 -0
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.interface.d.ts +5 -0
- package/dist/modules/kb-sync/kb-sync.interface.d.ts.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 +6 -0
- package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +2 -1
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +57 -3
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +177 -24
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +32 -4
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/tool-schema-guard.d.ts +105 -0
- package/dist/modules/mcp/tool-schema-guard.d.ts.map +1 -0
- package/dist/modules/mcp/tool-schema-guard.js +171 -0
- package/dist/modules/mcp/tool-schema-guard.js.map +1 -0
- package/dist/modules/onboarding/onboarding.contract.d.ts +80 -0
- package/dist/modules/onboarding/onboarding.contract.d.ts.map +1 -0
- package/dist/modules/onboarding/onboarding.contract.js +7 -0
- package/dist/modules/onboarding/onboarding.contract.js.map +1 -0
- package/dist/modules/onboarding/onboarding.routes.d.ts +18 -0
- package/dist/modules/onboarding/onboarding.routes.d.ts.map +1 -0
- package/dist/modules/onboarding/onboarding.routes.js +81 -0
- package/dist/modules/onboarding/onboarding.routes.js.map +1 -0
- package/dist/modules/onboarding/starter-pack.service.d.ts +213 -0
- package/dist/modules/onboarding/starter-pack.service.d.ts.map +1 -0
- package/dist/modules/onboarding/starter-pack.service.js +492 -0
- package/dist/modules/onboarding/starter-pack.service.js.map +1 -0
- package/dist/modules/onboarding/starter-packs.d.ts +78 -0
- package/dist/modules/onboarding/starter-packs.d.ts.map +1 -0
- package/dist/modules/onboarding/starter-packs.js +156 -0
- package/dist/modules/onboarding/starter-packs.js.map +1 -0
- 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/plugin-provision.service.d.ts +19 -0
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +18 -1
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +0 -36
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +31 -0
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.tools.d.ts +36 -2
- package/dist/modules/plugins/plugins.tools.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.tools.js +71 -14
- package/dist/modules/plugins/plugins.tools.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +34 -7
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +148 -54
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/repository-source.d.ts +1 -0
- package/dist/modules/settings/repository-source.d.ts.map +1 -1
- package/dist/modules/settings/repository-source.js +3 -3
- package/dist/modules/settings/repository-source.js.map +1 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +3 -6
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +103 -43
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/connection-key-rejection.d.ts +10 -1
- package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -1
- package/dist/modules/tool-auth/connection-key-rejection.js +11 -3
- package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +8 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts +24 -2
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +59 -2
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +9 -4
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/index.d.ts +28 -1
- package/dist/modules/tool-helpers/index.d.ts.map +1 -1
- package/dist/modules/tool-helpers/index.js +28 -1
- package/dist/modules/tool-helpers/index.js.map +1 -1
- package/dist/modules/tool-helpers/route-argument-check.d.ts +10 -0
- package/dist/modules/tool-helpers/route-argument-check.d.ts.map +1 -0
- package/dist/modules/tool-helpers/route-argument-check.js +132 -0
- package/dist/modules/tool-helpers/route-argument-check.js.map +1 -0
- package/dist/modules/tool-helpers/route-tool-schemas.d.ts +89 -0
- package/dist/modules/tool-helpers/route-tool-schemas.d.ts.map +1 -0
- package/dist/modules/tool-helpers/route-tool-schemas.js +113 -0
- package/dist/modules/tool-helpers/route-tool-schemas.js.map +1 -0
- package/dist/modules/tool-helpers/tool-def.d.ts +71 -0
- package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-def.js +70 -6
- package/dist/modules/tool-helpers/tool-def.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts +46 -6
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +157 -8
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +9 -0
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +23 -4
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -0
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +14 -0
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +7 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +77 -38
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/description-length.d.ts +20 -16
- package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
- package/dist/modules/tool-registry/description-length.js +50 -30
- package/dist/modules/tool-registry/description-length.js.map +1 -1
- package/dist/modules/tool-registry/guide-first.d.ts +27 -0
- package/dist/modules/tool-registry/guide-first.d.ts.map +1 -0
- package/dist/modules/tool-registry/guide-first.js +40 -0
- package/dist/modules/tool-registry/guide-first.js.map +1 -0
- package/dist/modules/tool-registry/tool-registry.d.ts +6 -0
- package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -1
- package/dist/modules/tool-registry/tool-registry.js +9 -2
- package/dist/modules/tool-registry/tool-registry.js.map +1 -1
- package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts +449 -0
- package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-read-shape.js +481 -0
- package/dist/modules/workflow/agent-tools/change-request-read-shape.js.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +126 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.js +611 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +12 -1
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/change-request-summary.js +5 -1
- package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +8 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +133 -37
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/file-lock.service.d.ts +29 -5
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
- package/dist/modules/workflow/file-lock.service.js +62 -5
- package/dist/modules/workflow/file-lock.service.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +282 -14
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +627 -126
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/merge-commit.d.ts +73 -0
- package/dist/modules/workflow/git/merge-commit.d.ts.map +1 -0
- package/dist/modules/workflow/git/merge-commit.js +89 -0
- package/dist/modules/workflow/git/merge-commit.js.map +1 -0
- package/dist/modules/workflow/git/node-git-runner.d.ts +15 -0
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.js +78 -6
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts +94 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +332 -37
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts +15 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +25 -1
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.d.ts +6 -1
- package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.js +23 -6
- package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
- package/dist/modules/workflow/recovery-bot.js +1 -1
- package/dist/modules/workflow/recovery-bot.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +35 -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 +180 -13
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/sanitize-error.d.ts +16 -0
- package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
- package/dist/modules/workflow/sanitize-error.js +45 -0
- package/dist/modules/workflow/sanitize-error.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts +6 -2
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +7 -2
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +187 -15
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +808 -106
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/agent-download.builder.d.ts +105 -0
- package/dist/modules/workspace/agent-download.builder.d.ts.map +1 -0
- package/dist/modules/workspace/agent-download.builder.js +238 -0
- package/dist/modules/workspace/agent-download.builder.js.map +1 -0
- package/dist/modules/workspace/agent-download.routes.d.ts +77 -0
- package/dist/modules/workspace/agent-download.routes.d.ts.map +1 -0
- package/dist/modules/workspace/agent-download.routes.js +156 -0
- package/dist/modules/workspace/agent-download.routes.js.map +1 -0
- package/dist/modules/workspace/agent-download.store.d.ts +225 -0
- package/dist/modules/workspace/agent-download.store.d.ts.map +1 -0
- package/dist/modules/workspace/agent-download.store.js +423 -0
- package/dist/modules/workspace/agent-download.store.js.map +1 -0
- package/dist/modules/workspace/agent-upload.store.d.ts +10 -1
- package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -1
- package/dist/modules/workspace/agent-upload.store.js +16 -6
- package/dist/modules/workspace/agent-upload.store.js.map +1 -1
- package/dist/modules/workspace/file-readers/raw-mime.d.ts +6 -0
- package/dist/modules/workspace/file-readers/raw-mime.d.ts.map +1 -0
- package/dist/modules/workspace/file-readers/raw-mime.js +38 -0
- package/dist/modules/workspace/file-readers/raw-mime.js.map +1 -0
- package/dist/modules/workspace/file-readers/text-reader.d.ts +5 -5
- package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/text-reader.js +5 -8
- package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
- package/dist/modules/workspace/first-run.d.ts +111 -0
- package/dist/modules/workspace/first-run.d.ts.map +1 -0
- package/dist/modules/workspace/first-run.js +181 -0
- package/dist/modules/workspace/first-run.js.map +1 -0
- package/dist/modules/workspace/move-links.d.ts +92 -0
- package/dist/modules/workspace/move-links.d.ts.map +1 -0
- package/dist/modules/workspace/move-links.js +173 -0
- package/dist/modules/workspace/move-links.js.map +1 -0
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +24 -39
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +58 -52
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +209 -223
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +5 -3
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +5 -3
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +63 -22
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +75 -2
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +197 -24
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +68 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +642 -71
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/write-access/write-access.d.ts.map +1 -1
- package/dist/modules/write-access/write-access.js +9 -0
- package/dist/modules/write-access/write-access.js.map +1 -1
- package/dist/shared/domain-errors.d.ts +84 -1
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +100 -12
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/git.contract.d.ts +10 -1
- package/dist/shared/git.contract.d.ts.map +1 -1
- package/dist/shared/git.contract.js.map +1 -1
- package/dist/shared/hidden-tools.d.ts +44 -0
- package/dist/shared/hidden-tools.d.ts.map +1 -0
- package/dist/shared/hidden-tools.js +13 -0
- package/dist/shared/hidden-tools.js.map +1 -0
- package/dist/shared/utf8-text.d.ts +15 -0
- package/dist/shared/utf8-text.d.ts.map +1 -0
- package/dist/shared/utf8-text.js +20 -0
- package/dist/shared/utf8-text.js.map +1 -0
- package/dist/tenancy/static-tenant-source.d.ts +2 -1
- package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
- package/dist/tenancy/static-tenant-source.js +9 -2
- package/dist/tenancy/static-tenant-source.js.map +1 -1
- package/kb-template/.bevelignore +0 -5
- package/mcp-app/page.html +349 -0
- package/migrations/0017_atlassian_account_links.sql +37 -0
- package/migrations/meta/0017_snapshot.json +2396 -0
- package/migrations/meta/_journal.json +8 -1
- package/package.json +6 -3
- package/src/__tests__/kb-layout-config.test.ts +10 -100
- package/src/__tests__/packaged-assets-ship.test.ts +66 -0
- package/src/assets.ts +38 -2
- package/src/core/__tests__/catalog-revision.test.ts +40 -0
- package/src/core/__tests__/gated-boot.test.ts +1 -0
- package/src/core/__tests__/lifecycle.test.ts +14 -0
- package/src/core/catalog-revision.ts +15 -2
- package/src/core/core-ports.ts +11 -0
- package/src/core/create-core-server.ts +78 -3
- package/src/core/create-core-services.ts +168 -10
- package/src/core/lifecycle.ts +28 -2
- package/src/core-config.ts +24 -1
- package/src/index.ts +2 -2
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +58 -0
- package/src/modules/access/__tests__/access-control.platform-restore.test.ts +8 -7
- package/src/modules/access/__tests__/access-control.service.test.ts +19 -0
- package/src/modules/access/__tests__/access-personal-plugin.test.ts +1 -18
- package/src/modules/access/access-control.interface.ts +28 -0
- package/src/modules/access/access-control.service.ts +37 -0
- package/src/modules/access/directory-sync-bot.ts +1 -1
- package/src/modules/agent-guide/__tests__/agent-guide.test.ts +386 -0
- package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +207 -0
- package/src/modules/agent-guide/agent-guide.tools.ts +122 -0
- package/src/modules/agent-guide/agent-guide.ts +300 -0
- package/src/modules/agent-guide/index.ts +22 -0
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +39 -118
- package/src/modules/agent-instructions/agent-instructions.routes.ts +3 -2
- package/src/modules/agent-instructions/compose.ts +26 -8
- package/src/modules/agent-instructions/index.ts +0 -3
- package/src/modules/agent-instructions/shared-file-rules.ts +50 -112
- package/src/modules/audit/__tests__/agent-audit.service.test.ts +64 -4
- package/src/modules/audit/__tests__/agent-connection.routes.test.ts +102 -0
- package/src/modules/audit/agent-audit.service.ts +58 -3
- package/src/modules/audit/agent-connection.routes.ts +56 -0
- package/src/modules/audit/audit.contract.ts +26 -0
- package/src/modules/audit/index.ts +1 -0
- package/src/modules/auth/__tests__/account.routes.test.ts +5 -3
- package/src/modules/auth/account.routes.ts +10 -3
- package/src/modules/auth/auth.middleware.ts +1 -1
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +18 -2
- package/src/modules/code-mode/code-mode.tool.ts +13 -2
- package/src/modules/database/core-schema.ts +33 -3
- package/src/modules/embed/__tests__/account-links.migration.test.ts +98 -0
- package/src/modules/embed/__tests__/embed-link.test.ts +122 -0
- package/src/modules/embed/__tests__/embed.routes.test.ts +362 -0
- package/src/modules/embed/__tests__/embed.service.lock.test.ts +193 -0
- package/src/modules/embed/__tests__/embed.service.test.ts +805 -0
- package/src/modules/embed/__tests__/embed.tools.test.ts +304 -0
- package/src/modules/embed/__tests__/mcp-app.test.ts +207 -0
- package/src/modules/embed/account-link.service.ts +76 -0
- package/src/modules/embed/embed-link.ts +180 -0
- package/src/modules/embed/embed.errors.ts +43 -0
- package/src/modules/embed/embed.interface.ts +203 -0
- package/src/modules/embed/embed.routes.ts +363 -0
- package/src/modules/embed/embed.service.ts +705 -0
- package/src/modules/embed/embed.tools.ts +206 -0
- package/src/modules/embed/mcp-app.routes.ts +41 -0
- package/src/modules/embed/mcp-app.ts +173 -0
- package/src/modules/github-app/__tests__/github-app.test.ts +76 -0
- package/src/modules/github-app/github-app.connection.ts +38 -4
- package/src/modules/kb-fs/__tests__/move-with-edits.test.ts +304 -0
- package/src/modules/kb-fs/locking-filesystem.ts +287 -0
- package/src/modules/kb-sync/__tests__/kb-sync.service.test.ts +35 -0
- package/src/modules/kb-sync/kb-sync.interface.ts +2 -0
- package/src/modules/kb-sync/kb-sync.service.ts +6 -0
- package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +68 -11
- package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +14 -3
- package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +37 -2
- package/src/modules/mcp/__tests__/mcp.app.e2e.test.ts +200 -0
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +252 -0
- package/src/modules/mcp/__tests__/mcp.service.test.ts +42 -24
- package/src/modules/mcp/__tests__/tool-call-interface.e2e.test.ts +499 -0
- package/src/modules/mcp/__tests__/tool-schema-guard.test.ts +266 -0
- package/src/modules/mcp/mcp-auth.middleware.ts +2 -1
- package/src/modules/mcp/mcp.service.ts +218 -31
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +42 -4
- package/src/modules/mcp/tool-schema-guard.ts +196 -0
- package/src/modules/onboarding/__tests__/onboarding.routes.test.ts +163 -0
- package/src/modules/onboarding/__tests__/starter-pack.service.test.ts +635 -0
- package/src/modules/onboarding/__tests__/starter-packs.test.ts +169 -0
- package/src/modules/onboarding/onboarding.contract.ts +85 -0
- package/src/modules/onboarding/onboarding.routes.ts +85 -0
- package/src/modules/onboarding/starter-pack.service.ts +580 -0
- package/src/modules/onboarding/starter-packs.ts +182 -0
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +177 -4
- package/src/modules/plugins/index.ts +1 -0
- package/src/modules/plugins/plugin-provision.service.ts +22 -1
- package/src/modules/plugins/plugins.routes.ts +29 -0
- package/src/modules/plugins/plugins.tools.ts +75 -15
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +176 -56
- package/src/modules/settings/__tests__/repository-source.test.ts +9 -0
- package/src/modules/settings/deployment-settings.service.ts +144 -55
- package/src/modules/settings/repository-source.ts +4 -4
- package/src/modules/settings/setup.routes.ts +3 -6
- package/src/modules/skills/__tests__/skills.tools.description.test.ts +95 -0
- package/src/modules/skills/skills.tools.ts +112 -46
- package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +32 -0
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +65 -0
- package/src/modules/tool-auth/connection-key-rejection.ts +13 -3
- package/src/modules/tool-auth/external-api-key.interface.ts +9 -0
- package/src/modules/tool-auth/external-api-key.service.ts +61 -4
- package/src/modules/tool-auth/tool-auth.middleware.ts +13 -4
- package/src/modules/tool-helpers/__tests__/branch-declaration.test.ts +502 -0
- package/src/modules/tool-helpers/__tests__/route-argument-check.test.ts +337 -0
- package/src/modules/tool-helpers/index.ts +34 -1
- package/src/modules/tool-helpers/route-argument-check.ts +149 -0
- package/src/modules/tool-helpers/route-tool-schemas.ts +171 -0
- package/src/modules/tool-helpers/tool-def.ts +132 -7
- package/src/modules/tool-helpers/tool-handler.ts +196 -8
- package/src/modules/tool-helpers/tool.contract.ts +9 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +57 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +73 -4
- package/src/modules/tool-manuals/tool-manuals.contract.ts +24 -4
- package/src/modules/tool-manuals/tool-manuals.service.ts +17 -0
- package/src/modules/tool-manuals/tool-manuals.tools.ts +86 -38
- package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +173 -0
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +81 -66
- package/src/modules/tool-registry/description-length.ts +57 -32
- package/src/modules/tool-registry/guide-first.ts +41 -0
- package/src/modules/tool-registry/tool-registry.ts +9 -2
- package/src/modules/workflow/__tests__/apply-failure.test.ts +6 -1
- package/src/modules/workflow/__tests__/file-lock.service.deletion-gate.test.ts +104 -0
- package/src/modules/workflow/__tests__/pending-commits.repository-replaced.test.ts +66 -0
- package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +31 -2
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +110 -6
- package/src/modules/workflow/__tests__/sanitize-error.test.ts +89 -1
- package/src/modules/workflow/__tests__/workflow.routes.push-refused.test.ts +202 -0
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +6 -6
- package/src/modules/workflow/__tests__/workflow.service.delete-branch.test.ts +1026 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +468 -10
- package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +4 -0
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +5 -4
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +54 -2
- package/src/modules/workflow/agent-tools/__tests__/change-request-read-shape.test.ts +705 -0
- package/src/modules/workflow/agent-tools/__tests__/change-request-read.tools.test.ts +1554 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +150 -4
- package/src/modules/workflow/agent-tools/change-request-read-shape.ts +712 -0
- package/src/modules/workflow/agent-tools/change-request-read.tools.ts +759 -0
- package/src/modules/workflow/agent-tools/change-request-summary.ts +5 -1
- package/src/modules/workflow/agent-tools/workflow.tools.ts +137 -35
- package/src/modules/workflow/file-lock.service.ts +67 -5
- package/src/modules/workflow/git/__tests__/git.service.appliedChange.test.ts +285 -0
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +164 -0
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +334 -0
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +48 -1
- package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +231 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +72 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +24 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +620 -1
- package/src/modules/workflow/git/git.service.ts +714 -133
- package/src/modules/workflow/git/merge-commit.ts +88 -0
- package/src/modules/workflow/git/node-git-runner.ts +82 -7
- package/src/modules/workflow/git/pull-request.service.ts +380 -54
- package/src/modules/workflow/pending-commits.service.ts +29 -1
- package/src/modules/workflow/pending-commits.worker.ts +24 -6
- package/src/modules/workflow/recovery-bot.ts +1 -1
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +7 -1
- package/src/modules/workflow/review-workflow/__tests__/merge-records-own-commit.test.ts +407 -0
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +191 -12
- package/src/modules/workflow/sanitize-error.ts +50 -0
- package/src/modules/workflow/workflow.routes.ts +7 -2
- package/src/modules/workflow/workflow.service.ts +886 -112
- package/src/modules/workspace/__tests__/agent-downloads.test.ts +823 -0
- package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +4 -3
- package/src/modules/workspace/__tests__/first-run.test.ts +234 -0
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +5 -2
- package/src/modules/workspace/__tests__/md-links.test.ts +353 -0
- package/src/modules/workspace/__tests__/move-links.test.ts +261 -0
- package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +219 -0
- package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -0
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +102 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +52 -5
- package/src/modules/workspace/__tests__/workspace.routes.folder-zip-access.test.ts +190 -0
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +21 -10
- package/src/modules/workspace/__tests__/workspace.service.forget-clone-races.test.ts +8 -4
- package/src/modules/workspace/__tests__/workspace.service.test.ts +50 -8
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +33 -55
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +44 -1
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +664 -34
- package/src/modules/workspace/agent-download.builder.ts +308 -0
- package/src/modules/workspace/agent-download.routes.ts +183 -0
- package/src/modules/workspace/agent-download.store.ts +533 -0
- package/src/modules/workspace/agent-upload.store.ts +23 -7
- package/src/modules/workspace/file-readers/raw-mime.ts +40 -0
- package/src/modules/workspace/file-readers/text-reader.ts +5 -8
- package/src/modules/workspace/first-run.ts +222 -0
- package/src/modules/workspace/move-links.ts +237 -0
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +191 -489
- package/src/modules/workspace/startup/steps/seed-tree.ts +23 -38
- package/src/modules/workspace/startup/steps/template-files.step.ts +217 -249
- package/src/modules/workspace/startup/steps/template-source.ts +5 -3
- package/src/modules/workspace/workspace.routes.ts +64 -22
- package/src/modules/workspace/workspace.service.ts +202 -25
- package/src/modules/workspace/workspace.tools.ts +707 -68
- package/src/modules/write-access/__tests__/write-access.test.ts +13 -0
- package/src/modules/write-access/write-access.ts +9 -0
- package/src/shared/domain-errors.ts +123 -11
- package/src/shared/git.contract.ts +8 -1
- package/src/shared/hidden-tools.ts +45 -0
- package/src/shared/utf8-text.ts +21 -0
- package/src/tenancy/__tests__/static-tenant-source.test.ts +1 -0
- package/src/tenancy/static-tenant-source.ts +10 -2
- package/starter-packs/README.md +103 -0
- package/starter-packs/engineering/KnowledgeBase/About us.md +9 -0
- package/starter-packs/engineering/KnowledgeBase/Architecture.md +9 -0
- package/starter-packs/engineering/KnowledgeBase/Glossary.md +9 -0
- package/starter-packs/engineering/KnowledgeBase/How we ship.md +9 -0
- package/starter-packs/engineering/Plugins/engineering-starter/LICENSE +21 -0
- package/starter-packs/engineering/Plugins/engineering-starter/SOURCE.md +20 -0
- package/starter-packs/engineering/Plugins/engineering-starter/access.md +19 -0
- package/starter-packs/engineering/Plugins/engineering-starter/plugin.json +10 -0
- package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/SKILL.md +171 -0
- package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2a-startup-diagnostic.md +157 -0
- package/starter-packs/engineering/Plugins/engineering-starter/skills/office-hours/sections/phase-2b-builder-brainstorm.md +39 -0
- package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-ceo-review/SKILL.md +144 -0
- package/starter-packs/engineering/Plugins/engineering-starter/skills/plan-eng-review/SKILL.md +144 -0
- package/starter-packs/engineering/Plugins/engineering-starter/skills/review/SKILL.md +80 -0
- package/starter-packs/engineering/Plugins/engineering-starter/skills/review/checklist.md +184 -0
- package/starter-packs/engineering/pack.yaml +11 -0
- package/starter-packs/general/KnowledgeBase/About us.md +9 -0
- package/starter-packs/general/KnowledgeBase/Glossary.md +9 -0
- package/starter-packs/general/KnowledgeBase/How we work.md +9 -0
- package/starter-packs/general/Plugins/general-starter/LICENSE +202 -0
- package/starter-packs/general/Plugins/general-starter/SOURCE.md +10 -0
- package/starter-packs/general/Plugins/general-starter/access.md +19 -0
- package/starter-packs/general/Plugins/general-starter/plugin.json +10 -0
- package/starter-packs/general/Plugins/general-starter/skills/memory-management/SKILL.md +332 -0
- package/starter-packs/general/Plugins/general-starter/skills/productivity-start/SKILL.md +163 -0
- package/starter-packs/general/Plugins/general-starter/skills/productivity-update/SKILL.md +167 -0
- package/starter-packs/general/Plugins/general-starter/skills/task-management/SKILL.md +83 -0
- package/starter-packs/general/pack.yaml +10 -0
- package/starter-packs/operations/KnowledgeBase/Glossary.md +9 -0
- package/starter-packs/operations/KnowledgeBase/How we work.md +9 -0
- package/starter-packs/operations/KnowledgeBase/Processes.md +9 -0
- package/starter-packs/operations/KnowledgeBase/Tools we use.md +9 -0
- package/starter-packs/operations/KnowledgeBase/Vendors.md +9 -0
- package/starter-packs/operations/Plugins/operations-starter/LICENSE +202 -0
- package/starter-packs/operations/Plugins/operations-starter/SOURCE.md +10 -0
- package/starter-packs/operations/Plugins/operations-starter/access.md +19 -0
- package/starter-packs/operations/Plugins/operations-starter/plugin.json +10 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/capacity-plan/SKILL.md +111 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/change-request/SKILL.md +119 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/compliance-tracking/SKILL.md +44 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/process-doc/SKILL.md +80 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/process-optimization/SKILL.md +39 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/risk-assessment/SKILL.md +40 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/runbook/SKILL.md +85 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/status-report/SKILL.md +75 -0
- package/starter-packs/operations/Plugins/operations-starter/skills/vendor-review/SKILL.md +102 -0
- package/starter-packs/operations/pack.yaml +12 -0
- package/starter-packs/sales/KnowledgeBase/About us.md +9 -0
- package/starter-packs/sales/KnowledgeBase/Customers.md +9 -0
- package/starter-packs/sales/KnowledgeBase/Glossary.md +9 -0
- package/starter-packs/sales/KnowledgeBase/How we sell.md +9 -0
- package/starter-packs/sales/KnowledgeBase/Objections.md +9 -0
- package/starter-packs/sales/KnowledgeBase/Pricing.md +9 -0
- package/starter-packs/sales/Plugins/sales-starter/LICENSE +202 -0
- package/starter-packs/sales/Plugins/sales-starter/SOURCE.md +10 -0
- package/starter-packs/sales/Plugins/sales-starter/access.md +19 -0
- package/starter-packs/sales/Plugins/sales-starter/plugin.json +10 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/account-context/SKILL.md +94 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/account-plan/SKILL.md +95 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/account-research/SKILL.md +99 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/account-tiering/SKILL.md +101 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/call-prep/SKILL.md +111 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/call-summary/SKILL.md +111 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/close-plan/SKILL.md +106 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/competitive-intelligence/SKILL.md +102 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/create-an-asset/SKILL.md +105 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/crm-hygiene-check/SKILL.md +103 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/customer-health/SKILL.md +108 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/customer-voice/SKILL.md +94 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/daily-briefing/SKILL.md +61 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/deal-advance-gap/SKILL.md +102 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/deal-review/SKILL.md +105 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/deal-signals/SKILL.md +96 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/deal-slip-scenario/SKILL.md +104 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/draft-outreach/SKILL.md +116 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/end-of-day/SKILL.md +114 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/expansion-whitespace/SKILL.md +97 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/forecast/SKILL.md +100 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/handle-objection/SKILL.md +93 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/inbox-sweep/SKILL.md +114 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/lead-triage/SKILL.md +106 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/log-activity/SKILL.md +111 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/pipeline-review/SKILL.md +97 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/renewal-radar/SKILL.md +95 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/rep-context/SKILL.md +90 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/route-lead/SKILL.md +111 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/sales-setup/SKILL.md +200 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/schedule-meeting/SKILL.md +99 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/stakeholder-map/SKILL.md +107 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/team-pipeline/SKILL.md +105 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/update-opportunity/SKILL.md +112 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/weekly-wrap/SKILL.md +90 -0
- package/starter-packs/sales/Plugins/sales-starter/skills/win-loss-review/SKILL.md +88 -0
- package/starter-packs/sales/pack.yaml +13 -0
- package/starter-packs/support/KnowledgeBase/Escalations.md +9 -0
- package/starter-packs/support/KnowledgeBase/Glossary.md +9 -0
- package/starter-packs/support/KnowledgeBase/Known issues.md +9 -0
- package/starter-packs/support/KnowledgeBase/Products.md +9 -0
- package/starter-packs/support/KnowledgeBase/Tone of voice.md +9 -0
- package/starter-packs/support/Plugins/support-starter/LICENSE +202 -0
- package/starter-packs/support/Plugins/support-starter/SOURCE.md +10 -0
- package/starter-packs/support/Plugins/support-starter/access.md +19 -0
- package/starter-packs/support/Plugins/support-starter/plugin.json +10 -0
- package/starter-packs/support/Plugins/support-starter/skills/customer-escalation/SKILL.md +246 -0
- package/starter-packs/support/Plugins/support-starter/skills/customer-research/SKILL.md +250 -0
- package/starter-packs/support/Plugins/support-starter/skills/draft-response/SKILL.md +416 -0
- package/starter-packs/support/Plugins/support-starter/skills/kb-article/SKILL.md +350 -0
- package/starter-packs/support/Plugins/support-starter/skills/ticket-triage/SKILL.md +273 -0
- package/starter-packs/support/pack.yaml +12 -0
- package/kb-template/AGENTS.md +0 -730
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { MOVE_LINK_EDIT_CAP, UNSEARCHED_SENTENCE, planMoveLinks, type MoveLinksInput } from '../move-links.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The plan `move_file` builds for its links: which pages it edits, which it
|
|
6
|
+
* names and leaves, and what it never discloses.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const KB = 'knowledge-base';
|
|
10
|
+
|
|
11
|
+
function inputOf(
|
|
12
|
+
files: Record<string, string>,
|
|
13
|
+
over: Partial<MoveLinksInput> = {},
|
|
14
|
+
): MoveLinksInput & { reads: string[] } {
|
|
15
|
+
const reads: string[] = [];
|
|
16
|
+
return {
|
|
17
|
+
src: `${KB}/Old`,
|
|
18
|
+
dest: `${KB}/New/Old`,
|
|
19
|
+
branch: 'main',
|
|
20
|
+
kbDirName: KB,
|
|
21
|
+
allFiles: Object.keys(files),
|
|
22
|
+
canRead: async (paths) => new Map(paths.map((p) => [p, true])),
|
|
23
|
+
writeBlocked: async () => [],
|
|
24
|
+
readText: async (p) => {
|
|
25
|
+
reads.push(p);
|
|
26
|
+
return files[p];
|
|
27
|
+
},
|
|
28
|
+
readRefused: async () => false,
|
|
29
|
+
writeRefusal: async () => null,
|
|
30
|
+
reads,
|
|
31
|
+
...over,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('planMoveLinks', () => {
|
|
36
|
+
it('edits inbound pages and moved pages, reporting each edit at the file’s new path', async () => {
|
|
37
|
+
const files = {
|
|
38
|
+
[`${KB}/Old/One.md`]: '---\nnodeType: "[T](../NodeTypes/Task.md)"\n---\n[two](Two.md)\n',
|
|
39
|
+
[`${KB}/Old/Two.md`]: 'no links\n',
|
|
40
|
+
[`${KB}/Index.md`]: '[one](Old/One.md) and [elsewhere](Other.md)\n',
|
|
41
|
+
[`${KB}/Unrelated.md`]: '[x](Other.md)\n',
|
|
42
|
+
[`${KB}/Old/pic.png`]: 'binary',
|
|
43
|
+
};
|
|
44
|
+
const input = inputOf(files);
|
|
45
|
+
const plan = await planMoveLinks(input);
|
|
46
|
+
expect(plan.report).toEqual({
|
|
47
|
+
filesEdited: 2,
|
|
48
|
+
linksRewritten: 2,
|
|
49
|
+
edits: [
|
|
50
|
+
{ path: `${KB}/Index.md`, from: 'Old/One.md', to: 'New/Old/One.md' },
|
|
51
|
+
{ path: `${KB}/New/Old/One.md`, from: '../NodeTypes/Task.md', to: '../../NodeTypes/Task.md' },
|
|
52
|
+
],
|
|
53
|
+
notRewritten: [],
|
|
54
|
+
});
|
|
55
|
+
expect(plan.edits.map((e) => [e.lockAt, e.path])).toEqual([
|
|
56
|
+
[`${KB}/Index.md`, `${KB}/Index.md`],
|
|
57
|
+
[`${KB}/Old/One.md`, `${KB}/New/Old/One.md`],
|
|
58
|
+
]);
|
|
59
|
+
// Binary files are never read.
|
|
60
|
+
expect(input.reads).not.toContain(`${KB}/Old/pic.png`);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('a readable page the caller may not change is named with its links, and not edited', async () => {
|
|
64
|
+
const files = {
|
|
65
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
66
|
+
[`${KB}/Locked/Page.md`]: '[one](../Old/One.md)\n',
|
|
67
|
+
};
|
|
68
|
+
const plan = await planMoveLinks(inputOf(files, { writeBlocked: async (paths) => paths.filter((p) => p.includes('Locked')) }));
|
|
69
|
+
expect(plan.edits).toEqual([]);
|
|
70
|
+
expect(plan.report.notRewritten).toEqual([
|
|
71
|
+
{ path: `${KB}/Locked/Page.md`, reason: 'no write access', links: ['../Old/One.md'] },
|
|
72
|
+
]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('a page the caller cannot read is never opened, named or counted — one sentence instead', async () => {
|
|
76
|
+
const files = {
|
|
77
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
78
|
+
[`${KB}/Secret/A.md`]: '[one](../Old/One.md)\n',
|
|
79
|
+
[`${KB}/Secret/B.md`]: '[one](../Old/One.md)\n',
|
|
80
|
+
};
|
|
81
|
+
const input = inputOf(files, {
|
|
82
|
+
canRead: async (paths) => new Map(paths.map((p) => [p, !p.includes('Secret')])),
|
|
83
|
+
});
|
|
84
|
+
const plan = await planMoveLinks(input);
|
|
85
|
+
expect(input.reads.some((p) => p.includes('Secret'))).toBe(false);
|
|
86
|
+
expect(plan.report.unsearched).toBe(UNSEARCHED_SENTENCE);
|
|
87
|
+
expect(JSON.stringify(plan.report)).not.toMatch(/Secret|\b2\b/);
|
|
88
|
+
expect(plan.report.filesEdited).toBe(0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('transcripts/ and probes/ folders are never searched', async () => {
|
|
92
|
+
const files = {
|
|
93
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
94
|
+
[`${KB}/T/transcripts/01.md`]: '[one](../../Old/One.md)\n',
|
|
95
|
+
[`${KB}/T/probes/p.md`]: '[one](../../Old/One.md)\n',
|
|
96
|
+
};
|
|
97
|
+
const input = inputOf(files);
|
|
98
|
+
const plan = await planMoveLinks(input);
|
|
99
|
+
expect(plan.report.filesEdited).toBe(0);
|
|
100
|
+
expect(input.reads.filter((p) => /transcripts|probes/.test(p))).toEqual([]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('an HTML page is reported, not rewritten', async () => {
|
|
104
|
+
const files = {
|
|
105
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
106
|
+
[`${KB}/Board.html`]: '<a href="Old/One.md">one</a>',
|
|
107
|
+
};
|
|
108
|
+
const plan = await planMoveLinks(inputOf(files));
|
|
109
|
+
expect(plan.edits).toEqual([]);
|
|
110
|
+
expect(plan.report.notRewritten).toEqual([{ path: `${KB}/Board.html`, reason: 'html page', links: ['Old/One.md'] }]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('raw HTML inside a markdown page is reported, not rewritten — beside the markdown links that are', async () => {
|
|
114
|
+
const files = {
|
|
115
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
116
|
+
[`${KB}/Old/pic.png`]: '',
|
|
117
|
+
// One markdown link, which is rewritten, and one raw `<img>`, which is not.
|
|
118
|
+
[`${KB}/Gallery.md`]: '[one](Old/One.md)\n\n<img src="Old/pic.png" alt="pic">\n',
|
|
119
|
+
// A page whose raw HTML points elsewhere is not named.
|
|
120
|
+
[`${KB}/Other.md`]: '<a href="Elsewhere.md">x</a> mentions Old in prose\n',
|
|
121
|
+
};
|
|
122
|
+
const plan = await planMoveLinks(inputOf(files));
|
|
123
|
+
expect(plan.edits.map((e) => e.path)).toEqual([`${KB}/Gallery.md`]);
|
|
124
|
+
expect(plan.edits[0].content).toBe('[one](New/Old/One.md)\n\n<img src="Old/pic.png" alt="pic">\n');
|
|
125
|
+
expect(plan.report.notRewritten).toEqual([
|
|
126
|
+
{ path: `${KB}/Gallery.md`, reason: 'html in markdown', links: ['Old/pic.png'] },
|
|
127
|
+
]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('raw HTML inside code or escaped — a fence, an indented block, a code span, a `\\<` — is an example, not reported', async () => {
|
|
131
|
+
const files = {
|
|
132
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
133
|
+
[`${KB}/Howto.md`]:
|
|
134
|
+
'Write it like `<a href="Old/One.md">` or \\<a href="Old/One.md"> or:\n\n```html\n<a href="Old/One.md">one</a>\n```\n\n' +
|
|
135
|
+
' <img src="Old/One.md">\n\nAnd a live one: <a href="Old/One.md">one</a>\n',
|
|
136
|
+
};
|
|
137
|
+
const plan = await planMoveLinks(inputOf(files));
|
|
138
|
+
expect(plan.edits).toEqual([]);
|
|
139
|
+
expect(plan.report.notRewritten).toEqual([
|
|
140
|
+
{ path: `${KB}/Howto.md`, reason: 'html in markdown', links: ['Old/One.md'] },
|
|
141
|
+
]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it(`more than ${MOVE_LINK_EDIT_CAP} edited files is refused, saying how to split or switch off`, async () => {
|
|
145
|
+
const files: Record<string, string> = { [`${KB}/Old/One.md`]: 'x\n' };
|
|
146
|
+
for (let i = 0; i <= MOVE_LINK_EDIT_CAP; i++) files[`${KB}/Pages/P${i}.md`] = '[one](../Old/One.md)\n';
|
|
147
|
+
const writeRefusal = vi.fn(async () => null);
|
|
148
|
+
const plan = await planMoveLinks(inputOf(files, { writeRefusal }));
|
|
149
|
+
expect(plan.overCap).toMatch(/201 files.*rewriteLinks: false/s);
|
|
150
|
+
expect(plan.overCap).toMatch(/subfolder/);
|
|
151
|
+
expect(plan.edits).toEqual([]);
|
|
152
|
+
// Nothing is edited, so the write hook hears of nothing.
|
|
153
|
+
expect(writeRefusal).not.toHaveBeenCalled();
|
|
154
|
+
// Exactly at the cap is allowed.
|
|
155
|
+
delete files[`${KB}/Pages/P0.md`];
|
|
156
|
+
expect((await planMoveLinks(inputOf(files))).overCap).toBeUndefined();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('only edited files reach the hooks; a refusal leaves that file named and unedited', async () => {
|
|
160
|
+
const files = {
|
|
161
|
+
[`${KB}/Old/One.md`]: '[t](../T.md)\n',
|
|
162
|
+
[`${KB}/A.md`]: '[one](Old/One.md)\n',
|
|
163
|
+
[`${KB}/B.md`]: '[one](Old/One.md)\n',
|
|
164
|
+
[`${KB}/Searched.md`]: 'mentions Old but links nowhere\n',
|
|
165
|
+
};
|
|
166
|
+
const readRefused = vi.fn(async () => false);
|
|
167
|
+
const writeRefusal = vi.fn(async (_lockAt: string, path: string) =>
|
|
168
|
+
path.endsWith('B.md') ? 'refused: not in this session' : null);
|
|
169
|
+
const plan = await planMoveLinks(inputOf(files, { readRefused, writeRefusal }));
|
|
170
|
+
// The pages the answer names, and not the one merely searched.
|
|
171
|
+
expect(readRefused.mock.calls.map((c) => c[0]).sort()).toEqual([`${KB}/A.md`, `${KB}/B.md`, `${KB}/Old/One.md`]);
|
|
172
|
+
expect(writeRefusal.mock.calls.map((c) => c[0]).sort()).toEqual([`${KB}/A.md`, `${KB}/B.md`, `${KB}/Old/One.md`]);
|
|
173
|
+
expect(plan.edits.map((e) => e.path)).toEqual([`${KB}/A.md`, `${KB}/New/Old/One.md`]);
|
|
174
|
+
expect(plan.report.notRewritten).toEqual([{ path: `${KB}/B.md`, reason: 'refused: not in this session', links: ['Old/One.md'] }]);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('a page the read hook refuses is treated as unreadable: never named, one sentence instead', async () => {
|
|
178
|
+
const files = {
|
|
179
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
180
|
+
[`${KB}/Hidden.md`]: '[one](Old/One.md) [secret](Secret/Target.md)\n',
|
|
181
|
+
};
|
|
182
|
+
const plan = await planMoveLinks(inputOf(files, { readRefused: async () => true }));
|
|
183
|
+
expect(plan.edits).toEqual([]);
|
|
184
|
+
expect(plan.report.notRewritten).toEqual([]);
|
|
185
|
+
expect(plan.report.unsearched).toBe(UNSEARCHED_SENTENCE);
|
|
186
|
+
expect(JSON.stringify(plan.report)).not.toMatch(/Hidden|Secret|read denied/);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('a page the read hook refuses is not named for its raw HTML, nor as one the caller may not change', async () => {
|
|
190
|
+
// Every way a page gets NAMED passes the same gate: an HTML page, raw
|
|
191
|
+
// HTML in a markdown page, and a page left unedited for want of write
|
|
192
|
+
// access are all pages the answer would quote links from.
|
|
193
|
+
const files = {
|
|
194
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
195
|
+
[`${KB}/Board.html`]: '<a href="Old/One.md">one</a>',
|
|
196
|
+
[`${KB}/Gallery.md`]: '<img src="Old/One.md">\n',
|
|
197
|
+
[`${KB}/Locked.md`]: '[one](Old/One.md)\n',
|
|
198
|
+
[`${KB}/Shown.md`]: '[one](Old/One.md)\n',
|
|
199
|
+
};
|
|
200
|
+
const readRefused = vi.fn(async (path: string) => path !== `${KB}/Shown.md`);
|
|
201
|
+
const plan = await planMoveLinks(
|
|
202
|
+
inputOf(files, { readRefused, writeBlocked: async (paths) => paths.filter((p) => p.endsWith('Locked.md')) }),
|
|
203
|
+
);
|
|
204
|
+
expect(plan.edits.map((e) => e.path)).toEqual([`${KB}/Shown.md`]);
|
|
205
|
+
expect(plan.report.notRewritten).toEqual([]);
|
|
206
|
+
expect(plan.report.unsearched).toBe(UNSEARCHED_SENTENCE);
|
|
207
|
+
expect(JSON.stringify(plan.report)).not.toMatch(/Board|Gallery|Locked/);
|
|
208
|
+
// Asked once per page named, never for one merely searched — the moved
|
|
209
|
+
// file itself links nowhere, so it is not named and not asked about.
|
|
210
|
+
expect(readRefused.mock.calls.map((c) => c[0]).sort()).toEqual([
|
|
211
|
+
`${KB}/Board.html`,
|
|
212
|
+
`${KB}/Gallery.md`,
|
|
213
|
+
`${KB}/Locked.md`,
|
|
214
|
+
`${KB}/Shown.md`,
|
|
215
|
+
]);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('a link spelling the moved name with percent-encoding or escapes is still found', async () => {
|
|
219
|
+
const files = {
|
|
220
|
+
[`${KB}/My Old (1)/One.md`]: 'x\n',
|
|
221
|
+
[`${KB}/Lower.md`]: '[one](My%20Old%20%281%29/One.md)\n',
|
|
222
|
+
[`${KB}/Partial.md`]: '[one](My%20Old%20(1)/One.md)\n',
|
|
223
|
+
[`${KB}/Escaped.md`]: '[one](My%20Old%20\\(1\\)/One.md)\n',
|
|
224
|
+
[`${KB}/Mixed.md`]: '[one](%4dy%20Old%20%281%29/One.md)\n',
|
|
225
|
+
};
|
|
226
|
+
const plan = await planMoveLinks(inputOf(files, { src: `${KB}/My Old (1)`, dest: `${KB}/New/My Old (1)` }));
|
|
227
|
+
expect(plan.edits.map((e) => e.path).sort()).toEqual([`${KB}/Escaped.md`, `${KB}/Lower.md`, `${KB}/Mixed.md`, `${KB}/Partial.md`]);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('a page gone between the listing and its read is skipped; one that cannot be opened marks the search incomplete', async () => {
|
|
231
|
+
const files = {
|
|
232
|
+
[`${KB}/Old/One.md`]: 'x\n',
|
|
233
|
+
[`${KB}/Gone.md`]: '[one](Old/One.md)\n',
|
|
234
|
+
[`${KB}/Index.md`]: '[one](Old/One.md)\n',
|
|
235
|
+
};
|
|
236
|
+
const failWith = (code: string) => async (p: string) => {
|
|
237
|
+
if (p.endsWith('Gone.md')) throw Object.assign(new Error(code), { code });
|
|
238
|
+
return files[p as keyof typeof files];
|
|
239
|
+
};
|
|
240
|
+
const gone = await planMoveLinks(inputOf(files, { readText: failWith('ENOENT') }));
|
|
241
|
+
expect(gone.edits.map((e) => e.path)).toEqual([`${KB}/Index.md`]);
|
|
242
|
+
expect(gone.report.unsearched).toBeUndefined();
|
|
243
|
+
// Its folder became a file: gone all the same.
|
|
244
|
+
const folderGone = await planMoveLinks(inputOf(files, { readText: failWith('ENOTDIR') }));
|
|
245
|
+
expect(folderGone.edits.map((e) => e.path)).toEqual([`${KB}/Index.md`]);
|
|
246
|
+
expect(folderGone.report.unsearched).toBeUndefined();
|
|
247
|
+
const denied = await planMoveLinks(inputOf(files, { readText: failWith('EACCES') }));
|
|
248
|
+
expect(denied.edits.map((e) => e.path)).toEqual([`${KB}/Index.md`]);
|
|
249
|
+
expect(denied.report.unsearched).toBe(UNSEARCHED_SENTENCE);
|
|
250
|
+
expect(JSON.stringify(denied.report)).not.toMatch(/Gone/);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('lists at most 100 edits while counting all of them', async () => {
|
|
254
|
+
const files: Record<string, string> = { [`${KB}/Old/One.md`]: 'x\n' };
|
|
255
|
+
for (let i = 0; i < 60; i++) files[`${KB}/Pages/P${i}.md`] = '[a](../Old/One.md) [b](../Old/One.md#x)\n';
|
|
256
|
+
const plan = await planMoveLinks(inputOf(files));
|
|
257
|
+
expect(plan.report.filesEdited).toBe(60);
|
|
258
|
+
expect(plan.report.linksRewritten).toBe(120);
|
|
259
|
+
expect(plan.report.edits).toHaveLength(100);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { Server as HttpServer } from 'node:http';
|
|
2
|
+
import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
7
|
+
import { LocalFilesystem } from '@mastra/core/workspace';
|
|
8
|
+
import { testKbContext } from '../../../__tests__/kb-context.js';
|
|
9
|
+
import { ToolRegistry } from '../../tool-registry/tool-registry.js';
|
|
10
|
+
import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
|
|
11
|
+
import { routeToolSchemas } from '../../tool-helpers/route-tool-schemas.js';
|
|
12
|
+
import type { ToolContext } from '../../tool-helpers/tool.contract.js';
|
|
13
|
+
import type { ToolAuth } from '../../tool-auth/tool-auth.middleware.js';
|
|
14
|
+
import { registerWorkspaceTools } from '../workspace.tools.js';
|
|
15
|
+
import { RoutineWritePolicyService } from '../routine-write-policy.js';
|
|
16
|
+
import { WorkflowHooks } from '../../workflow/workflow-hooks.js';
|
|
17
|
+
import { ToolDescriptionNotes } from '../agent-access.gate.js';
|
|
18
|
+
import { SpillStore } from '../spill-store.js';
|
|
19
|
+
import { DocExtractService } from '../file-readers/doc-extract.service.js';
|
|
20
|
+
import { AccessControlService } from '../../access/access-control.service.js';
|
|
21
|
+
import { NodeFs } from '../../kb-fs/node-fs.js';
|
|
22
|
+
import { BRANCH_REQUIRED_MESSAGE } from '../../../shared/domain-errors.js';
|
|
23
|
+
import { callLine, compileCheck, exampleArguments } from '@bevel-software/platform-mcp-core';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The REST route a script, a runner or a CI job calls with a connection key —
|
|
27
|
+
* `POST /api/agent/tools/<name>` — driven against the REAL workspace tools.
|
|
28
|
+
*
|
|
29
|
+
* This is the surface the first implementation left unprotected: `write_file`
|
|
30
|
+
* without `content` answered a 500 `TypeError`, `move_file` without `dest` the
|
|
31
|
+
* same, and `grep` without `pattern` answered 200 having matched every file in
|
|
32
|
+
* the knowledge base. The three calls the ticket names are here, with their own
|
|
33
|
+
* schemas and their own route handlers, so the refusal under test is the one a
|
|
34
|
+
* caller really gets.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const KB = 'knowledge-base';
|
|
38
|
+
const BRANCH = 'main';
|
|
39
|
+
|
|
40
|
+
const TREE: Record<string, string> = {
|
|
41
|
+
'roles.yaml': 'roles:\n Admin:\n - author@x.io\n',
|
|
42
|
+
'access.md': '---\nread:\n - everyone\nwrite:\n - everyone\n---\n',
|
|
43
|
+
'KnowledgeBase/Note.md': '# Note\n\nthe needle is here\n',
|
|
44
|
+
'KnowledgeBase/Other.md': '# Other\n\nthe needle is here too\n',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
let root = '';
|
|
48
|
+
let docCache = '';
|
|
49
|
+
let base = '';
|
|
50
|
+
let server: HttpServer;
|
|
51
|
+
|
|
52
|
+
beforeAll(async () => {
|
|
53
|
+
root = await mkdtemp(join(tmpdir(), 'rest-tool-arguments-'));
|
|
54
|
+
for (const [rel, text] of Object.entries(TREE)) {
|
|
55
|
+
const abs = join(root, KB, rel);
|
|
56
|
+
await mkdir(dirname(abs), { recursive: true });
|
|
57
|
+
await writeFile(abs, text);
|
|
58
|
+
}
|
|
59
|
+
const workspaceService = {
|
|
60
|
+
getWorkspacePath: async () => root,
|
|
61
|
+
ensureRemotesFetched: async () => undefined,
|
|
62
|
+
} as unknown as Parameters<typeof AccessControlService.prototype.constructor>[0];
|
|
63
|
+
const access = new AccessControlService(workspaceService as never, KB, new NodeFs());
|
|
64
|
+
const fs = new LocalFilesystem({ basePath: root, contained: true });
|
|
65
|
+
const resolve = async (auth: ToolAuth, signal: AbortSignal): Promise<ToolContext> =>
|
|
66
|
+
({
|
|
67
|
+
user: { id: 'u', email: 'author@x.io', name: 'Author' },
|
|
68
|
+
scope: auth.scope,
|
|
69
|
+
source: auth.source,
|
|
70
|
+
abortSignal: signal,
|
|
71
|
+
workspaceService: workspaceService as never,
|
|
72
|
+
workflowService: {} as never,
|
|
73
|
+
events: {} as never,
|
|
74
|
+
getFilesystem: async () => fs,
|
|
75
|
+
}) as unknown as ToolContext;
|
|
76
|
+
const app = express();
|
|
77
|
+
app.use(express.json());
|
|
78
|
+
const router = express.Router();
|
|
79
|
+
docCache = await mkdtemp(join(tmpdir(), 'rest-tool-arguments-doc-'));
|
|
80
|
+
registerWorkspaceTools(
|
|
81
|
+
new ToolRegistry(),
|
|
82
|
+
router,
|
|
83
|
+
(req, _res, next) => {
|
|
84
|
+
req.toolAuth = { source: 'external', userId: 'u', scope: 'write' };
|
|
85
|
+
next();
|
|
86
|
+
},
|
|
87
|
+
createToolHandlerFactory(resolve),
|
|
88
|
+
new SpillStore(join(tmpdir(), 'bevel-test-spills')),
|
|
89
|
+
new DocExtractService(docCache),
|
|
90
|
+
access,
|
|
91
|
+
testKbContext({ kbDirName: KB }),
|
|
92
|
+
{ recoveryBotEmail: 'recovery-bot@bevel.local', hooks: new WorkflowHooks(), notes: new ToolDescriptionNotes() },
|
|
93
|
+
new RoutineWritePolicyService(),
|
|
94
|
+
{} as never,
|
|
95
|
+
);
|
|
96
|
+
app.use('/api', router);
|
|
97
|
+
server = await new Promise<HttpServer>((r) => {
|
|
98
|
+
const s = app.listen(0, () => r(s));
|
|
99
|
+
});
|
|
100
|
+
base = `http://127.0.0.1:${(server.address() as { port: number }).port}`;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
afterAll(async () => {
|
|
104
|
+
await new Promise<void>((r) => server.close(() => r()));
|
|
105
|
+
await rm(root, { recursive: true, force: true });
|
|
106
|
+
await rm(docCache, { recursive: true, force: true });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
interface Answered {
|
|
110
|
+
status: number;
|
|
111
|
+
body: { error?: string; kind?: string; matches?: unknown[]; truncated?: boolean };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** One call on the REST route, exactly as a script with a connection key makes it. */
|
|
115
|
+
async function callTool(tool: string, body: unknown): Promise<Answered> {
|
|
116
|
+
const res = await fetch(`${base}/api/agent/tools/${tool}`, {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
headers: { 'content-type': 'application/json', authorization: 'Bearer connection-key' },
|
|
119
|
+
body: JSON.stringify(body),
|
|
120
|
+
});
|
|
121
|
+
return { status: res.status, body: (await res.json()) as Answered['body'] };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const exists = (rel: string) =>
|
|
125
|
+
stat(join(root, rel))
|
|
126
|
+
.then(() => true)
|
|
127
|
+
.catch(() => false);
|
|
128
|
+
|
|
129
|
+
describe('POST /api/agent/tools/<name> checks the arguments against the tool', () => {
|
|
130
|
+
it('refuses write_file without `content` — the 400 with the interface, not a 500, and writes nothing', async () => {
|
|
131
|
+
const { status, body } = await callTool('write_file', {
|
|
132
|
+
branch: BRANCH,
|
|
133
|
+
path: `${KB}/KnowledgeBase/New.md`,
|
|
134
|
+
sessionId: 's-1',
|
|
135
|
+
});
|
|
136
|
+
expect(status).toBe(400);
|
|
137
|
+
expect(body.kind).toBe('arguments-do-not-match');
|
|
138
|
+
expect(body.error).toContain('The arguments do not match the "write_file" tool.');
|
|
139
|
+
expect(body.error).toContain('"content" is required, and was not given.');
|
|
140
|
+
expect(body.error).toContain('Interface of "write_file":');
|
|
141
|
+
expect(body.error).toContain('content (string, required)');
|
|
142
|
+
expect(body.error).toContain('path (string, required)');
|
|
143
|
+
expect(body.error?.split('\n').pop()).toBe(
|
|
144
|
+
callLine('KNOWLEDGE_BASE.write_file', routeToolSchemas('write_file')!.wire),
|
|
145
|
+
);
|
|
146
|
+
// The call ran nothing: no file was created.
|
|
147
|
+
expect(await exists(`${KB}/KnowledgeBase/New.md`)).toBe(false);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('refuses move_file without `dest`, and moves nothing', async () => {
|
|
151
|
+
const { status, body } = await callTool('move_file', {
|
|
152
|
+
branch: BRANCH,
|
|
153
|
+
src: `${KB}/KnowledgeBase/Note.md`,
|
|
154
|
+
});
|
|
155
|
+
expect(status).toBe(400);
|
|
156
|
+
expect(body.kind).toBe('arguments-do-not-match');
|
|
157
|
+
expect(body.error).toContain('"dest" is required, and was not given.');
|
|
158
|
+
expect(body.error).toContain('dest (string, required)');
|
|
159
|
+
expect(await readFile(join(root, KB, 'KnowledgeBase/Note.md'), 'utf8')).toContain('the needle is here');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('refuses grep without `pattern`, and searches nothing', async () => {
|
|
163
|
+
const { status, body } = await callTool('grep', { branch: BRANCH });
|
|
164
|
+
expect(status).toBe(400);
|
|
165
|
+
expect(body.kind).toBe('arguments-do-not-match');
|
|
166
|
+
expect(body.error).toContain('"pattern" is required, and was not given.');
|
|
167
|
+
expect(body.error).toContain('pattern (string, required) — JavaScript regular expression.');
|
|
168
|
+
// Not a 200 that matched every file, which is what this surface answered
|
|
169
|
+
// before the check lived in the route.
|
|
170
|
+
expect(body.matches).toBeUndefined();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('names an argument of the wrong type, and one the tool does not have', async () => {
|
|
174
|
+
const wrongType = await callTool('grep', { branch: BRANCH, pattern: 'needle', max_results: 'ten' });
|
|
175
|
+
expect(wrongType.status).toBe(400);
|
|
176
|
+
expect(wrongType.body.error).toContain('"max_results" must be integer, but string was given.');
|
|
177
|
+
const unknown = await callTool('grep', { branch: BRANCH, pattern: 'needle', recursive: true });
|
|
178
|
+
expect(unknown.status).toBe(400);
|
|
179
|
+
expect(unknown.body.error).toContain('"recursive" is not an argument of this tool.');
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('keeps the refusal that names a missing branch, word for word', async () => {
|
|
183
|
+
const { status, body } = await callTool('read_file', { path: `${KB}/KnowledgeBase/Note.md` });
|
|
184
|
+
expect(status).toBe(400);
|
|
185
|
+
expect(body.kind).toBe('branch-required');
|
|
186
|
+
expect(body.error).toBe(BRANCH_REQUIRED_MESSAGE);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('passes a matching call on with exactly the arguments that were sent', async () => {
|
|
190
|
+
const { status, body } = await callTool('grep', {
|
|
191
|
+
branch: BRANCH,
|
|
192
|
+
pattern: 'needle',
|
|
193
|
+
path: `${KB}/KnowledgeBase`,
|
|
194
|
+
max_results: 1,
|
|
195
|
+
});
|
|
196
|
+
expect(status).toBe(200);
|
|
197
|
+
// `max_results: 1` was honoured, so the argument reached the tool as sent —
|
|
198
|
+
// the check neither dropped it nor rewrote it.
|
|
199
|
+
expect(body.matches).toHaveLength(1);
|
|
200
|
+
expect(body.truncated).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('every mounted tool can be called with its own generated example', async () => {
|
|
204
|
+
const names = ['read_file', 'write_file', 'move_file', 'grep', 'list_files'];
|
|
205
|
+
for (const name of names) {
|
|
206
|
+
const schemas = routeToolSchemas(name);
|
|
207
|
+
expect(schemas, name).toBeDefined();
|
|
208
|
+
// The example an agent is told to copy is generated from the WIRE schema;
|
|
209
|
+
// what its route checks is the FLAT one. Both must accept it, or the
|
|
210
|
+
// platform publishes an example its own check refuses.
|
|
211
|
+
const flat = compileCheck(schemas!.flat);
|
|
212
|
+
expect(flat.checkable, name).toBe(true);
|
|
213
|
+
if (flat.checkable) expect(flat.check(exampleArguments(schemas!.flat)), name).toEqual([]);
|
|
214
|
+
const wire = compileCheck(schemas!.wire);
|
|
215
|
+
expect(wire.checkable, name).toBe(true);
|
|
216
|
+
if (wire.checkable) expect(wire.check(exampleArguments(schemas!.wire)), name).toEqual([]);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
});
|
|
@@ -70,6 +70,9 @@ async function makeHarness(): Promise<Harness> {
|
|
|
70
70
|
asked.push(p);
|
|
71
71
|
return true;
|
|
72
72
|
},
|
|
73
|
+
// Each file of a zipped folder is judged too; this suite is about where
|
|
74
|
+
// the FOLDER is placed, so the files all pass.
|
|
75
|
+
canDownloadBatch: async (_w: string, _e: string, paths: string[]) => new Map(paths.map((p) => [p, true])),
|
|
73
76
|
} as unknown as IAccessControl;
|
|
74
77
|
|
|
75
78
|
const locked: string[] = [];
|
|
@@ -15,6 +15,7 @@ import type { IAdminAccessService } from '../../admin/admin.interface.js';
|
|
|
15
15
|
import { createWorkspaceRoutes } from '../workspace.routes.js';
|
|
16
16
|
import type { ICreatorAccess } from '../../access-model/creator.js';
|
|
17
17
|
import type { WorkspaceService } from '../workspace.service.js';
|
|
18
|
+
import { AccessDeniedError } from '../../access-model/access-errors.js';
|
|
18
19
|
|
|
19
20
|
const stubCreatorAccess: ICreatorAccess = {
|
|
20
21
|
planForCreate: async () => null,
|
|
@@ -46,6 +47,8 @@ interface Harness {
|
|
|
46
47
|
repoDir: string;
|
|
47
48
|
/** Exposed so a test can assert the PATH the route handed the service. */
|
|
48
49
|
deleteFileMock: ReturnType<typeof vi.fn>;
|
|
50
|
+
/** Exposed so a test can make the write gate inside it refuse. */
|
|
51
|
+
acquireLockMock: ReturnType<typeof vi.fn>;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
async function makeHarness(): Promise<Harness> {
|
|
@@ -125,6 +128,7 @@ async function makeHarness(): Promise<Harness> {
|
|
|
125
128
|
workspaceDir,
|
|
126
129
|
repoDir: path.join(workspaceDir, KB),
|
|
127
130
|
deleteFileMock: workspaceServiceMock.deleteFile as unknown as ReturnType<typeof vi.fn>,
|
|
131
|
+
acquireLockMock: workflowServiceMock.acquireLock as unknown as ReturnType<typeof vi.fn>,
|
|
128
132
|
};
|
|
129
133
|
}
|
|
130
134
|
|
|
@@ -218,3 +222,101 @@ describe('DELETE /workspace/:id/file — one file identity', () => {
|
|
|
218
222
|
}
|
|
219
223
|
});
|
|
220
224
|
});
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* The root's `access.md` and `roles.yaml` govern the whole repository, so the
|
|
228
|
+
* app's delete route refuses them — with the sentence `delete_file` and the
|
|
229
|
+
* explorer use — before a lock is taken. A nested `access.md` is a file like
|
|
230
|
+
* any other here: the lock gate decides whether the caller may write it.
|
|
231
|
+
*/
|
|
232
|
+
describe('DELETE /workspace/:id/file — the repository\'s own files', () => {
|
|
233
|
+
let h: Harness | null = null;
|
|
234
|
+
afterEach(async () => {
|
|
235
|
+
if (h) {
|
|
236
|
+
await closeServer(h.server);
|
|
237
|
+
await fs.rm(h.workspaceDir, { recursive: true, force: true });
|
|
238
|
+
}
|
|
239
|
+
h = null;
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const del = (base: string, p: string) =>
|
|
243
|
+
fetch(`${base}/api/workspace/${WORKSPACE_ID}/file?path=${encodeURIComponent(p)}`, { method: 'DELETE' });
|
|
244
|
+
|
|
245
|
+
it.each(['access.md', 'roles.yaml'])('refuses the root %s with one sentence and leaves it', async (name) => {
|
|
246
|
+
h = await makeHarness();
|
|
247
|
+
await fs.mkdir(h.repoDir, { recursive: true });
|
|
248
|
+
await fs.writeFile(path.join(h.repoDir, name), 'x', 'utf-8');
|
|
249
|
+
|
|
250
|
+
const res = await del(h.baseUrl, name);
|
|
251
|
+
|
|
252
|
+
expect(res.status).toBe(409);
|
|
253
|
+
expect(await res.json()).toEqual({ error: `${name} is the repository's own file and cannot be deleted.` });
|
|
254
|
+
expect(h.deleteFileMock).not.toHaveBeenCalled();
|
|
255
|
+
expect(await exists(path.join(h.repoDir, name))).toBe(true);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('deletes a nested access.md like any file, and a nested roles.yaml too', async () => {
|
|
259
|
+
h = await makeHarness();
|
|
260
|
+
await fs.mkdir(path.join(h.repoDir, 'Team'), { recursive: true });
|
|
261
|
+
await fs.writeFile(path.join(h.repoDir, 'Team/access.md'), '---\nread: Admin\n---\n', 'utf-8');
|
|
262
|
+
await fs.writeFile(path.join(h.repoDir, 'Team/roles.yaml'), 'content', 'utf-8');
|
|
263
|
+
// Not emptied by these deletes, so no placeholder needs keeping.
|
|
264
|
+
await fs.writeFile(path.join(h.repoDir, 'Team/notes.md'), 'n', 'utf-8');
|
|
265
|
+
|
|
266
|
+
for (const p of ['Team/access.md', 'Team/roles.yaml']) {
|
|
267
|
+
const res = await del(h.baseUrl, p);
|
|
268
|
+
expect(res.status).toBe(200);
|
|
269
|
+
expect(h.deleteFileMock).toHaveBeenCalledWith(WORKSPACE_ID, `${KB}/${p}`);
|
|
270
|
+
expect(await exists(path.join(h.repoDir, p))).toBe(false);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('refuses a nested access.md with the ordinary write refusal when the caller may not write it', async () => {
|
|
275
|
+
h = await makeHarness();
|
|
276
|
+
await fs.mkdir(path.join(h.repoDir, 'Team'), { recursive: true });
|
|
277
|
+
await fs.writeFile(path.join(h.repoDir, 'Team/access.md'), '---\nwrite: Admin\n---\n', 'utf-8');
|
|
278
|
+
// The write gate lives inside `acquireLock`; it refuses as it does for any file.
|
|
279
|
+
const refusal = new AccessDeniedError({ path: 'Team/access.md', eligibleRoles: ['Admin'], eligibleUsers: [] });
|
|
280
|
+
h.acquireLockMock.mockRejectedValueOnce(refusal);
|
|
281
|
+
|
|
282
|
+
const res = await del(h.baseUrl, 'Team/access.md');
|
|
283
|
+
|
|
284
|
+
expect(res.status).toBe(403);
|
|
285
|
+
const body = (await res.json()) as { error: string };
|
|
286
|
+
expect(body.error).toBe(refusal.message);
|
|
287
|
+
expect(body.error).not.toContain('platform file');
|
|
288
|
+
expect(body.error).not.toContain("repository's own file");
|
|
289
|
+
expect(h.deleteFileMock).not.toHaveBeenCalled();
|
|
290
|
+
expect(await exists(path.join(h.repoDir, 'Team/access.md'))).toBe(true);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('refuses a reserved top-level folder as delete_folder does, and leaves what it holds', async () => {
|
|
294
|
+
h = await makeHarness();
|
|
295
|
+
await fs.mkdir(path.join(h.repoDir, 'KnowledgeBase/Product'), { recursive: true });
|
|
296
|
+
await fs.writeFile(path.join(h.repoDir, 'KnowledgeBase/Product/Plan.md'), 'p', 'utf-8');
|
|
297
|
+
|
|
298
|
+
const res = await del(h.baseUrl, `${KB}/KnowledgeBase`);
|
|
299
|
+
|
|
300
|
+
expect(res.status).toBe(409);
|
|
301
|
+
expect(await res.json()).toEqual({ error: 'KnowledgeBase/ is a platform folder and cannot be moved or deleted.' });
|
|
302
|
+
expect(h.deleteFileMock).not.toHaveBeenCalled();
|
|
303
|
+
expect(await exists(path.join(h.repoDir, 'KnowledgeBase/Product/Plan.md'))).toBe(true);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it.each([KB, `${KB}/`])('refuses the repository root as a folder (%j) and leaves its own files', async (p) => {
|
|
307
|
+
h = await makeHarness();
|
|
308
|
+
await fs.mkdir(path.join(h.repoDir, 'Team'), { recursive: true });
|
|
309
|
+
await fs.writeFile(path.join(h.repoDir, 'access.md'), 'x', 'utf-8');
|
|
310
|
+
await fs.writeFile(path.join(h.repoDir, 'roles.yaml'), 'x', 'utf-8');
|
|
311
|
+
await fs.writeFile(path.join(h.repoDir, 'Team/notes.md'), 'n', 'utf-8');
|
|
312
|
+
|
|
313
|
+
const res = await del(h.baseUrl, p);
|
|
314
|
+
|
|
315
|
+
expect(res.status).toBe(409);
|
|
316
|
+
expect(await res.json()).toEqual({ error: 'The repository root is a platform folder and cannot be moved or deleted.' });
|
|
317
|
+
expect(h.deleteFileMock).not.toHaveBeenCalled();
|
|
318
|
+
for (const f of ['access.md', 'roles.yaml', 'Team/notes.md']) {
|
|
319
|
+
expect(await exists(path.join(h.repoDir, f))).toBe(true);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
});
|