@bevel-software/platform-core-backend 0.26.0 → 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 +17 -0
- package/agent-guide/conventions.md +8 -0
- package/agent-guide/html-views.md +83 -0
- package/agent-guide/new-knowledge-base.md +24 -0
- package/agent-guide/tool-manuals.md +10 -0
- package/dist/assets.d.ts +19 -0
- package/dist/assets.d.ts.map +1 -1
- package/dist/assets.js +26 -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/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 +54 -3
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +26 -0
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +100 -8
- 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 +8 -0
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +1 -0
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +11 -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 +6 -0
- package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.js +8 -0
- package/dist/modules/agent-guide/agent-guide.js.map +1 -1
- package/dist/modules/agent-guide/index.d.ts +1 -1
- package/dist/modules/agent-guide/index.d.ts.map +1 -1
- package/dist/modules/agent-guide/index.js +1 -1
- package/dist/modules/agent-guide/index.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +5 -0
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +19 -2
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.js +19 -19
- 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 +28 -1
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +64 -8
- 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/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/settings/deployment-settings.service.d.ts +34 -0
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +134 -1
- 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/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +50 -32
- 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.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +14 -5
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/description-length.d.ts +6 -2
- package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
- package/dist/modules/tool-registry/description-length.js +27 -5
- package/dist/modules/tool-registry/description-length.js.map +1 -1
- package/dist/modules/tool-registry/guide-first.d.ts +4 -0
- package/dist/modules/tool-registry/guide-first.d.ts.map +1 -1
- package/dist/modules/tool-registry/guide-first.js +9 -1
- package/dist/modules/tool-registry/guide-first.js.map +1 -1
- package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +53 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/change-request-read.tools.js +97 -68
- package/dist/modules/workflow/agent-tools/change-request-read.tools.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 +124 -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 +72 -1
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +172 -36
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- 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/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.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +2 -1
- 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.service.d.ts +183 -15
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +805 -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 +3 -13
- package/dist/modules/workspace/startup/steps/seed-tree.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 +59 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +443 -65
- 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 +73 -1
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +86 -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/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/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 +5 -3
- package/src/__tests__/packaged-assets-ship.test.ts +16 -4
- package/src/assets.ts +28 -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/create-core-server.ts +67 -3
- package/src/core/create-core-services.ts +140 -6
- 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.service.test.ts +19 -0
- package/src/modules/access/access-control.interface.ts +13 -0
- package/src/modules/access/access-control.service.ts +16 -0
- package/src/modules/access/directory-sync-bot.ts +1 -1
- package/src/modules/agent-guide/__tests__/agent-guide.test.ts +58 -0
- package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +19 -1
- package/src/modules/agent-guide/agent-guide.ts +9 -0
- package/src/modules/agent-guide/index.ts +1 -0
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +14 -0
- package/src/modules/agent-instructions/compose.ts +17 -2
- package/src/modules/agent-instructions/shared-file-rules.ts +19 -19
- 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__/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 +3 -1
- package/src/modules/mcp/__tests__/mcp.service.test.ts +23 -13
- package/src/modules/mcp/__tests__/tool-call-interface.e2e.test.ts +499 -0
- package/src/modules/mcp/mcp-auth.middleware.ts +2 -1
- package/src/modules/mcp/mcp.service.ts +81 -12
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +42 -4
- 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 +25 -2
- 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/settings/__tests__/deployment-settings.service.test.ts +150 -1
- package/src/modules/settings/__tests__/repository-source.test.ts +9 -0
- package/src/modules/settings/deployment-settings.service.ts +131 -1
- package/src/modules/settings/repository-source.ts +4 -4
- package/src/modules/skills/__tests__/skills.tools.description.test.ts +5 -1
- package/src/modules/skills/skills.tools.ts +55 -35
- 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/tool-manuals.tools.ts +15 -5
- package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +14 -1
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +23 -10
- package/src/modules/tool-registry/description-length.ts +34 -7
- package/src/modules/tool-registry/guide-first.ts +8 -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.tools.test.ts +41 -5
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +127 -2
- package/src/modules/workflow/agent-tools/change-request-read.tools.ts +157 -122
- package/src/modules/workflow/agent-tools/workflow.tools.ts +129 -35
- package/src/modules/workflow/file-lock.service.ts +67 -5
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +164 -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/git.service.ts +176 -38
- package/src/modules/workflow/git/node-git-runner.ts +82 -7
- 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/review-workflow.service.ts +2 -1
- package/src/modules/workflow/sanitize-error.ts +50 -0
- package/src/modules/workflow/workflow.service.ts +879 -112
- package/src/modules/workspace/__tests__/agent-downloads.test.ts +823 -0
- 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.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.branch-errors.test.ts +44 -1
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +409 -12
- 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/seed-tree.ts +3 -12
- 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 +492 -63
- 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 +108 -11
- package/src/shared/git.contract.ts +8 -1
- 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
|
@@ -3,6 +3,7 @@ import type { IToolRegistry, UtcpTool } from '../tool-registry/tool.contract.js'
|
|
|
3
3
|
import type { KbContext } from '../../shared/kb-context.js';
|
|
4
4
|
import type { ToolContext } from '../tool-helpers/tool.contract.js';
|
|
5
5
|
import { toolDef } from '../tool-helpers/tool-def.js';
|
|
6
|
+
import { declareRouteTool } from '../tool-helpers/route-tool-schemas.js';
|
|
6
7
|
import type { ToolHandlerFactory } from '../tool-helpers/tool-handler.js';
|
|
7
8
|
import type { IAccessControl } from '../access/access-control.interface.js';
|
|
8
9
|
import { utcpNamespacedKey } from '../../shared/utcp-namespace.js';
|
|
@@ -54,6 +55,11 @@ export function registerToolManualsTools(
|
|
|
54
55
|
): void {
|
|
55
56
|
registry.registerExternalTool((ctx) => buildListLocalToolsDef(toolManualService, ctx.userEmail));
|
|
56
57
|
registry.registerInternalTool((ctx) => buildListLocalToolsDef(toolManualService, ctx.userEmail));
|
|
58
|
+
// The def above is built per catalog listing (its description names the
|
|
59
|
+
// tools configured for THIS caller), so declare the arguments here as well:
|
|
60
|
+
// a direct REST call that lands before the first listing must be checked
|
|
61
|
+
// against them too.
|
|
62
|
+
declareRouteTool('list_local_tools', LIST_LOCAL_TOOLS_INPUTS);
|
|
57
63
|
|
|
58
64
|
router.post(
|
|
59
65
|
'/agent/tools/list_local_tools',
|
|
@@ -79,13 +85,14 @@ export function registerToolManualsTools(
|
|
|
79
85
|
// answers and the four things an agent cannot read off a field.
|
|
80
86
|
//
|
|
81
87
|
// It sits a few characters under `TOOL_DESCRIPTION_CAP` WITH the guide-first
|
|
82
|
-
// sentence the registry puts in front of it (`tool-registry/guide-first.ts`)
|
|
88
|
+
// sentence the registry puts in front of it (`tool-registry/guide-first.ts`)
|
|
89
|
+
// and the `Call:` line generated ahead of everything,
|
|
83
90
|
// which is why every sentence here is the short form: the `hiddenTools`
|
|
84
91
|
// clause and that opener both came out of the same budget, and what a
|
|
85
92
|
// hidden tool's entry CONTAINS is on the field below rather than here.
|
|
86
93
|
description:
|
|
87
|
-
'Configuration status of every `.tool` the current user can access: what each
|
|
88
|
-
'
|
|
94
|
+
'Configuration status of every `.tool` the current user can access: what each needs set up and what is ' +
|
|
95
|
+
'configured, as `{ tools, invalid, onBranchOnly, note? }`. Scoped to the CALLER: a `.tool` it cannot ' +
|
|
89
96
|
'READ is absent, and every flag is the caller\'s own. ' +
|
|
90
97
|
'Secret VALUES are never returned and can never be set through a tool: an admin enters them in the tool ' +
|
|
91
98
|
'editor; users sign in on /connect. ' +
|
|
@@ -96,7 +103,7 @@ export function registerToolManualsTools(
|
|
|
96
103
|
'The listing is the RELEASED catalog, built from the default branch only: a server or `.tool` you declared on a ' +
|
|
97
104
|
'draft is not listed, callable or signed-in-able until it is merged. Pass `branch` (the draft you wrote the ' +
|
|
98
105
|
'declaration on) and `onBranchOnly` names every tool declared there that the default branch does not serve ' +
|
|
99
|
-
'yet — open a change request and ask the user to merge it
|
|
106
|
+
'yet — open a change request and ask the user to merge it.',
|
|
100
107
|
path: '/api/agent/tools/list_tool_setup',
|
|
101
108
|
inputs: {
|
|
102
109
|
type: 'object',
|
|
@@ -303,6 +310,9 @@ async function localToolsLine(svc: IToolManualService, userEmail?: string): Prom
|
|
|
303
310
|
return `Local-only tools configured for you: ${tools.map((t) => `\`${t.name}\``).join(', ')}.`;
|
|
304
311
|
}
|
|
305
312
|
|
|
313
|
+
/** `list_local_tools` takes nothing; a const so the route and the def share one declaration. */
|
|
314
|
+
const LIST_LOCAL_TOOLS_INPUTS = { type: 'object' as const, properties: {}, additionalProperties: false };
|
|
315
|
+
|
|
306
316
|
async function buildListLocalToolsDef(svc: IToolManualService, userEmail?: string): Promise<UtcpTool> {
|
|
307
317
|
return toolDef({
|
|
308
318
|
name: 'list_local_tools',
|
|
@@ -318,7 +328,7 @@ async function buildListLocalToolsDef(svc: IToolManualService, userEmail?: strin
|
|
|
318
328
|
'setup by hand. ' +
|
|
319
329
|
(await localToolsLine(svc, userEmail)),
|
|
320
330
|
path: '/api/agent/tools/list_local_tools',
|
|
321
|
-
inputs:
|
|
331
|
+
inputs: LIST_LOCAL_TOOLS_INPUTS,
|
|
322
332
|
outputs: {
|
|
323
333
|
type: 'object',
|
|
324
334
|
properties: {
|
|
@@ -9,6 +9,7 @@ import { registerWorkspaceTools } from '../../workspace/workspace.tools.js';
|
|
|
9
9
|
import { registerSkillsTools } from '../../skills/skills.tools.js';
|
|
10
10
|
import { registerPluginsTools } from '../../plugins/plugins.tools.js';
|
|
11
11
|
import { registerToolManualsTools } from '../../tool-manuals/tool-manuals.tools.js';
|
|
12
|
+
import { registerEmbedTools } from '../../embed/embed.tools.js';
|
|
12
13
|
import { registerAgentGuideTool } from '../../agent-guide/agent-guide.tools.js';
|
|
13
14
|
import { ToolDescriptionNotes } from '../../workspace/agent-access.gate.js';
|
|
14
15
|
import { testKbContext } from '../../../__tests__/kb-context.js';
|
|
@@ -58,7 +59,7 @@ const CORE_SERVER_SOURCE = new URL('../../../core/create-core-server.ts', import
|
|
|
58
59
|
const MODULES: ReadonlyArray<{ name: string; register: (registry: ToolRegistry) => void }> = [
|
|
59
60
|
{
|
|
60
61
|
name: 'registerWorkflowTools',
|
|
61
|
-
register: (registry) => registerWorkflowTools(registry, express.Router(), pass, handler, testKbContext()),
|
|
62
|
+
register: (registry) => registerWorkflowTools(registry, express.Router(), pass, handler, testKbContext(), async () => true),
|
|
62
63
|
},
|
|
63
64
|
{
|
|
64
65
|
name: 'registerChangeRequestReadTools',
|
|
@@ -93,6 +94,18 @@ const MODULES: ReadonlyArray<{ name: string; register: (registry: ToolRegistry)
|
|
|
93
94
|
register: (registry) => registerSkillsTools(registry, express.Router(), pass, handler, nothing),
|
|
94
95
|
},
|
|
95
96
|
{ name: 'registerPluginsTools', register: (registry) => registerPluginsTools(registry, testKbContext()) },
|
|
97
|
+
{
|
|
98
|
+
name: 'registerEmbedTools',
|
|
99
|
+
register: (registry) =>
|
|
100
|
+
registerEmbedTools(registry, express.Router(), pass, handler, {
|
|
101
|
+
embedService: nothing,
|
|
102
|
+
kb: testKbContext(),
|
|
103
|
+
readForTool: nothing,
|
|
104
|
+
canBeReached: () => true,
|
|
105
|
+
appUrlFor: (repoRelative) => `https://example.test/workspace/main/knowledge-base/${repoRelative}`,
|
|
106
|
+
notes: new ToolDescriptionNotes(),
|
|
107
|
+
}),
|
|
108
|
+
},
|
|
96
109
|
{
|
|
97
110
|
name: 'registerToolManualsTools',
|
|
98
111
|
register: (registry) =>
|
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
CALL_TOOL_CHAIN_NAME,
|
|
5
5
|
CHAIN_FAILURES_RULE,
|
|
6
6
|
CHAIN_LARGE_RESULTS_RULE,
|
|
7
|
+
callLine,
|
|
7
8
|
codeModeMetaTools,
|
|
9
|
+
splitCallLine,
|
|
8
10
|
} from '@bevel-software/platform-mcp-core';
|
|
9
11
|
import { testKbContext } from '../../../__tests__/kb-context.js';
|
|
10
12
|
import { EXTERNAL_KB_MANUAL_NAME } from '../../tool-manuals/tool-manuals.contract.js';
|
|
@@ -103,8 +105,12 @@ async function hexisTools(): Promise<UtcpTool[]> {
|
|
|
103
105
|
// every real composition supplies one: without it they would be the two
|
|
104
106
|
// descriptions this suite never measured.
|
|
105
107
|
unused(),
|
|
108
|
+
// The guide reader, not needed to build defs; then the download store,
|
|
109
|
+
// mounted on the same terms as the upload one.
|
|
110
|
+
undefined,
|
|
111
|
+
unused(),
|
|
106
112
|
);
|
|
107
|
-
registerWorkflowTools(registry, router, toolAuth, toolHandler, kb);
|
|
113
|
+
registerWorkflowTools(registry, router, toolAuth, toolHandler, kb, async () => true);
|
|
108
114
|
registerPluginsTools(registry, kb);
|
|
109
115
|
registerSkillsTools(registry, router, toolAuth, toolHandler, emptySkills);
|
|
110
116
|
registerToolManualsTools(registry, router, toolAuth, toolHandler, emptyManuals, {
|
|
@@ -170,8 +176,10 @@ describe('no Hexis tool description is long enough to be cut', () => {
|
|
|
170
176
|
// ONE predicate for both halves, so no description falls between them: a
|
|
171
177
|
// tool whose own description is empty is served the sentence alone, and
|
|
172
178
|
// one with text after it has whitespace between — not `here.Read`.
|
|
179
|
+
// Behind the `Call:` line, when the description already carries one (the
|
|
180
|
+
// meta-tools are built with theirs): that line comes first on every tool.
|
|
173
181
|
const opensWithGuide = (t: UtcpTool): boolean => {
|
|
174
|
-
const description = t.description ?? '';
|
|
182
|
+
const description = splitCallLine(t.description ?? '').rest;
|
|
175
183
|
if (description === GUIDE_FIRST_SENTENCE) return true;
|
|
176
184
|
return description.startsWith(GUIDE_FIRST_SENTENCE) && /^\s/.test(description.slice(GUIDE_FIRST_SENTENCE.length));
|
|
177
185
|
};
|
|
@@ -202,12 +210,15 @@ describe('no Hexis tool description is long enough to be cut', () => {
|
|
|
202
210
|
it('fails, naming the tool, when a paragraph takes a description over the cap', () => {
|
|
203
211
|
const padded = { name: 'write_file', description: 'x'.repeat(TOOL_DESCRIPTION_CAP + 1) } as UtcpTool;
|
|
204
212
|
expect(clientVisibleLength(padded)).toBeGreaterThan(TOOL_DESCRIPTION_CAP);
|
|
205
|
-
// A tool with no description at all is
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
//
|
|
210
|
-
|
|
213
|
+
// A tool with no description at all is handed its `Call:` line alone —
|
|
214
|
+
// the example counts toward the cap like any other text a client gets.
|
|
215
|
+
const nothingCall = callLine(`${EXTERNAL_KB_MANUAL_NAME}.nothing`, undefined);
|
|
216
|
+
expect(clientVisibleLength({ name: 'nothing' } as UtcpTool)).toBe(nothingCall.length);
|
|
217
|
+
// A PREFIXED one is handed the prefix too, behind the line (no
|
|
218
|
+
// description, so no blank line after the prefix), and that text is what
|
|
219
|
+
// the client was handed. Measuring it as nothing would hide what it got.
|
|
220
|
+
const readCall = callLine(`${EXTERNAL_KB_MANUAL_NAME}.read_file`, undefined);
|
|
221
|
+
expect(clientVisibleLength({ name: 'read_file' } as UtcpTool)).toBe(readCall.length + 2 + TOOL_PREFIX_CAP);
|
|
211
222
|
});
|
|
212
223
|
|
|
213
224
|
it('measures the catalog, which is what a client lists — and says what is outside it', async () => {
|
|
@@ -292,13 +303,15 @@ describe('the shared rules describe the tools they name', () => {
|
|
|
292
303
|
// to the rules. Composed at the mount, because `mcp-core` builds the
|
|
293
304
|
// constant without knowing where this deployment states them.
|
|
294
305
|
const served = (await hexisTools()).find((t) => t.name === CALL_TOOL_CHAIN_NAME)!;
|
|
295
|
-
|
|
306
|
+
// Behind its `Call:` line, which is the first line of every description.
|
|
307
|
+
expect(served.description!.startsWith('Call: call_tool_chain(')).toBe(true);
|
|
308
|
+
expect(splitCallLine(served.description!).rest.startsWith(`${GUIDE_FIRST_SENTENCE} `)).toBe(true);
|
|
296
309
|
expect(served.description!.split(GUIDE_FIRST_SENTENCE)).toHaveLength(2);
|
|
297
310
|
expect(served.description!.trimEnd().endsWith('.')).toBe(true);
|
|
298
311
|
expect(clientVisibleLength(served)).toBeLessThanOrEqual(TOOL_DESCRIPTION_CAP);
|
|
299
312
|
// The other two open the same way: the guide comes before the registry too.
|
|
300
313
|
for (const tool of servedMetaTools([]).filter((t) => t.name !== CALL_TOOL_CHAIN_NAME)) {
|
|
301
|
-
expect(tool.description
|
|
314
|
+
expect(splitCallLine(tool.description!).rest.startsWith(`${GUIDE_FIRST_SENTENCE} `), tool.name).toBe(true);
|
|
302
315
|
}
|
|
303
316
|
});
|
|
304
317
|
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
* what makes the cap below reachable rather than aspirational.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import { callLine, splitCallLine } from '@bevel-software/platform-mcp-core';
|
|
14
15
|
import { TOOL_PREFIX_CAP } from '@bevel-software/platform-shared';
|
|
15
16
|
import { PREFIXED_TOOLS } from '../agent-instructions/compose.js';
|
|
17
|
+
import { EXTERNAL_KB_MANUAL_NAME } from '../tool-manuals/tool-manuals.contract.js';
|
|
16
18
|
import { GUIDE_FIRST_SENTENCE } from './guide-first.js';
|
|
17
19
|
import type { UtcpTool } from './tool.contract.js';
|
|
18
20
|
|
|
@@ -61,6 +63,25 @@ export const TOOL_DESCRIPTION_CAP = 1_200;
|
|
|
61
63
|
*/
|
|
62
64
|
export const CLIENT_SHORT_CUT = 500;
|
|
63
65
|
|
|
66
|
+
/** What these measurements read of a tool: its name, its text and the schema its `Call:` line is generated from. */
|
|
67
|
+
export type MeasuredTool = Pick<UtcpTool, 'name' | 'description'> & { inputs?: unknown };
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The `Call:` line a client is handed ahead of everything else, and the blank
|
|
71
|
+
* line after it — counted, because it is part of what a client cuts. Taken
|
|
72
|
+
* from the description when it already opens with one (a meta-tool is built
|
|
73
|
+
* with its line), generated from the tool's inputs under the namespace the
|
|
74
|
+
* hosted endpoint serves otherwise, as mcp-core's `withCallExample` does at
|
|
75
|
+
* listing time. The rest of the description comes back beside it.
|
|
76
|
+
*/
|
|
77
|
+
function splitServedCallLine(tool: MeasuredTool): { callChars: number; rest: string } {
|
|
78
|
+
const { call, rest } = splitCallLine(tool.description ?? '');
|
|
79
|
+
const line = call ?? callLine(`${EXTERNAL_KB_MANUAL_NAME}.${tool.name}`, tool.inputs);
|
|
80
|
+
// The blank line after it only when something follows it.
|
|
81
|
+
const followed = rest !== '' || PREFIXED_TOOLS.has(tool.name);
|
|
82
|
+
return { callChars: line.length + (followed ? 2 : 0), rest };
|
|
83
|
+
}
|
|
84
|
+
|
|
64
85
|
/**
|
|
65
86
|
* Where the tool's OWN opening sentence ends in the text a client is handed:
|
|
66
87
|
* the purpose prefix counted at its cap, as in {@link clientVisibleLength},
|
|
@@ -71,9 +92,9 @@ export const CLIENT_SHORT_CUT = 500;
|
|
|
71
92
|
* A description with no sentence-ending punctuation counts whole — the honest
|
|
72
93
|
* answer for text that never finishes a sentence.
|
|
73
94
|
*/
|
|
74
|
-
export function firstSentenceEnd(tool:
|
|
75
|
-
const
|
|
76
|
-
const
|
|
95
|
+
export function firstSentenceEnd(tool: MeasuredTool): number {
|
|
96
|
+
const { callChars, rest: description } = splitServedCallLine(tool);
|
|
97
|
+
const prefix = callChars + (PREFIXED_TOOLS.has(tool.name) ? TOOL_PREFIX_CAP + 2 : 0);
|
|
77
98
|
if (description === '') return prefix;
|
|
78
99
|
// The opener and whatever whitespace follows it: `guideFirstDescription`
|
|
79
100
|
// joins with one space, and leaves a description that already opens with
|
|
@@ -97,13 +118,19 @@ export function firstSentenceEnd(tool: Pick<UtcpTool, 'name' | 'description'>):
|
|
|
97
118
|
* The guide-first sentence every listed tool opens with is already in the
|
|
98
119
|
* description the registry lists, so it is measured as the text it is.
|
|
99
120
|
*/
|
|
100
|
-
export function clientVisibleLength(tool:
|
|
101
|
-
const
|
|
121
|
+
export function clientVisibleLength(tool: MeasuredTool): number {
|
|
122
|
+
const { callChars, rest } = splitServedCallLine(tool);
|
|
123
|
+
return callChars + ownVisibleLength(tool.name, rest);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** {@link clientVisibleLength} without the `Call:` line: the purpose prefix and the tool's own text. */
|
|
127
|
+
function ownVisibleLength(name: string, description: string): number {
|
|
128
|
+
const own = description.length;
|
|
102
129
|
// A prefixed tool with no description of its own is still handed the prefix,
|
|
103
130
|
// and nothing else — `prefixToolDescription` sends the prefix alone, with no
|
|
104
131
|
// blank line after it. Measuring that as zero would under-report the only
|
|
105
132
|
// text the client got.
|
|
106
|
-
if (own === 0) return PREFIXED_TOOLS.has(
|
|
133
|
+
if (own === 0) return PREFIXED_TOOLS.has(name) ? TOOL_PREFIX_CAP : 0;
|
|
107
134
|
// `+ 2` for the blank line `prefixToolDescription` puts between the two.
|
|
108
|
-
return PREFIXED_TOOLS.has(
|
|
135
|
+
return PREFIXED_TOOLS.has(name) ? own + TOOL_PREFIX_CAP + 2 : own;
|
|
109
136
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { splitCallLine } from '@bevel-software/platform-mcp-core';
|
|
1
2
|
import type { UtcpTool } from './tool.contract.js';
|
|
2
3
|
|
|
3
4
|
/** The one tool that returns the platform's guide (see `modules/agent-guide`). */
|
|
@@ -19,9 +20,15 @@ export const GUIDE_FIRST_SENTENCE = `Call \`${GET_AGENT_GUIDE_TOOL}\` first and
|
|
|
19
20
|
* sentence is put in front of a description — the registry for the tools it
|
|
20
21
|
* lists, the MCP service for the meta-tools it builds itself — so the two
|
|
21
22
|
* cannot drift apart on what "once" means.
|
|
23
|
+
*
|
|
24
|
+
* Behind a `Call:` line, never ahead of it: the call example is the first
|
|
25
|
+
* line of every description (see mcp-core's `withCallExample`), and the
|
|
26
|
+
* sentence opens what follows it.
|
|
22
27
|
*/
|
|
23
28
|
export function guideFirstDescription(description: string | undefined): string {
|
|
24
|
-
const
|
|
29
|
+
const { call, rest } = splitCallLine(description ?? '');
|
|
30
|
+
if (call !== null) return `${call}\n\n${guideFirstDescription(rest)}`;
|
|
31
|
+
const own = rest;
|
|
25
32
|
if (own.startsWith(GUIDE_FIRST_SENTENCE)) return own;
|
|
26
33
|
return own ? `${GUIDE_FIRST_SENTENCE} ${own}` : GUIDE_FIRST_SENTENCE;
|
|
27
34
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import type { AuthUser } from '@bevel-software/platform-shared';
|
|
3
|
+
import type { Database } from '../../database/connection.js';
|
|
4
|
+
import { FileLockService } from '../file-lock.service.js';
|
|
5
|
+
import { WorkflowValidationError } from '../../../shared/domain-errors.js';
|
|
6
|
+
import { makeFakeLockDb, type FakeLockDb } from './fake-file-lock-db.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A deletion runs its last "is any save landing?" check inside
|
|
10
|
+
* `whileNoneAcquired`, and a save starts by taking its file lock. An acquire
|
|
11
|
+
* that passed the gate before the deletion began, but whose row was still
|
|
12
|
+
* being written, must be seen by that check — not land after it.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const ALICE: AuthUser = { id: '11111111-1111-4111-8111-111111111111', email: 'alice@example.com', name: 'Alice' };
|
|
16
|
+
const WS = 'alice%2Fdraft';
|
|
17
|
+
const BRANCH = 'alice/draft';
|
|
18
|
+
const PATH = 'knowledge-base/a.md';
|
|
19
|
+
|
|
20
|
+
/** The fake lock db, with every INSERT held until `release()`. */
|
|
21
|
+
function withHeldInserts(fake: FakeLockDb): { db: Database; release: () => void } {
|
|
22
|
+
let release!: () => void;
|
|
23
|
+
const gate = new Promise<void>((resolve) => {
|
|
24
|
+
release = resolve;
|
|
25
|
+
});
|
|
26
|
+
const base = fake.db as unknown as { insert: () => { values: (row: unknown) => Record<string, unknown> } };
|
|
27
|
+
const db = {
|
|
28
|
+
...base,
|
|
29
|
+
insert: () => ({
|
|
30
|
+
values: (row: unknown) => {
|
|
31
|
+
const chain = base.insert().values(row) as {
|
|
32
|
+
onConflictDoUpdate: (arg: unknown) => unknown;
|
|
33
|
+
returning: () => Promise<unknown>;
|
|
34
|
+
};
|
|
35
|
+
const held = {
|
|
36
|
+
onConflictDoUpdate: (arg: unknown) => {
|
|
37
|
+
chain.onConflictDoUpdate(arg);
|
|
38
|
+
return held;
|
|
39
|
+
},
|
|
40
|
+
returning: async () => {
|
|
41
|
+
await gate;
|
|
42
|
+
return chain.returning();
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
return held;
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
} as unknown as Database;
|
|
49
|
+
return { db, release };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
describe('FileLockService deletion gate', () => {
|
|
53
|
+
let fake: FakeLockDb;
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
fake = makeFakeLockDb();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('waits for an acquire already under way, so the check inside sees its lock', async () => {
|
|
60
|
+
const { db, release } = withHeldInserts(fake);
|
|
61
|
+
const locks = new FileLockService(db);
|
|
62
|
+
|
|
63
|
+
const acquire = locks.acquire(WS, BRANCH, PATH, ALICE);
|
|
64
|
+
let sawLock: boolean | null = null;
|
|
65
|
+
const deletion = locks.whileNoneAcquired(BRANCH, async () => {
|
|
66
|
+
sawLock = await locks.hasAnyActive(WS);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
70
|
+
// The acquire's row is not written yet, so the check has not run.
|
|
71
|
+
expect(sawLock).toBeNull();
|
|
72
|
+
|
|
73
|
+
release();
|
|
74
|
+
await expect(acquire).resolves.toMatchObject({ acquired: true });
|
|
75
|
+
await deletion;
|
|
76
|
+
expect(sawLock).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('refuses an acquire that starts while the deletion runs', async () => {
|
|
80
|
+
const locks = new FileLockService(fake.db);
|
|
81
|
+
let refused: unknown = null;
|
|
82
|
+
await locks.whileNoneAcquired(BRANCH, async () => {
|
|
83
|
+
refused = await locks.acquire(WS, BRANCH, PATH, ALICE).catch((err: unknown) => err);
|
|
84
|
+
});
|
|
85
|
+
expect(refused).toBeInstanceOf(WorkflowValidationError);
|
|
86
|
+
expect(fake.rows()).toHaveLength(0);
|
|
87
|
+
// And grants it again once the deletion is over.
|
|
88
|
+
await expect(locks.acquire(WS, BRANCH, PATH, ALICE)).resolves.toMatchObject({ acquired: true });
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('does not wait for an acquire on another branch', async () => {
|
|
92
|
+
const { db, release } = withHeldInserts(fake);
|
|
93
|
+
const locks = new FileLockService(db);
|
|
94
|
+
|
|
95
|
+
const other = locks.acquire('bob%2Fdraft', 'bob/draft', PATH, ALICE);
|
|
96
|
+
let ran = false;
|
|
97
|
+
await locks.whileNoneAcquired(BRANCH, async () => {
|
|
98
|
+
ran = true;
|
|
99
|
+
});
|
|
100
|
+
expect(ran).toBe(true);
|
|
101
|
+
release();
|
|
102
|
+
await other;
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -109,3 +109,69 @@ describe('PendingCommitsService.markNeedsAttentionInWorkspace', () => {
|
|
|
109
109
|
await expect(new PendingCommitsService(db).markNeedsAttentionInWorkspace('main', 'whatever')).resolves.toBe(0);
|
|
110
110
|
});
|
|
111
111
|
});
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* What `mergeBranch` waits on: the commits still between a branch's saved
|
|
115
|
+
* files and its remote. `pending` and `running` both count — a row the worker
|
|
116
|
+
* holds is not pushed yet — and a `needs_attention` row is reported with its
|
|
117
|
+
* message, because nothing will land it without a person.
|
|
118
|
+
*/
|
|
119
|
+
describe('PendingCommitsService.queuedOnBranch', () => {
|
|
120
|
+
function selectDb(rows: Array<{ status: string; lastError: string | null }>) {
|
|
121
|
+
const orderBy = vi.fn(async () => rows);
|
|
122
|
+
const where = vi.fn(() => ({ orderBy }));
|
|
123
|
+
const db = { select: vi.fn(() => ({ from: () => ({ where }) })) } as unknown as Database;
|
|
124
|
+
return { db, where, orderBy };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
it('counts pending and running rows, and reports no attention when none is stuck', async () => {
|
|
128
|
+
const { db, where } = selectDb([
|
|
129
|
+
{ status: 'pending', lastError: null },
|
|
130
|
+
{ status: 'running', lastError: null },
|
|
131
|
+
]);
|
|
132
|
+
await expect(new PendingCommitsService(db).queuedOnBranch('alice/draft')).resolves.toEqual({
|
|
133
|
+
queued: 2,
|
|
134
|
+
stuck: 0,
|
|
135
|
+
needsAttention: null,
|
|
136
|
+
});
|
|
137
|
+
// Keyed on the branch column.
|
|
138
|
+
const sql = new PgDialect().sqlToQuery((where.mock.calls[0] as unknown as [SQL])[0]);
|
|
139
|
+
expect(sql.sql).toMatch(/"branch" = \$1/);
|
|
140
|
+
expect(sql.params).toEqual(['alice/draft']);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('reports the oldest needs_attention row\'s message alongside the count', async () => {
|
|
144
|
+
const { db, orderBy } = selectDb([
|
|
145
|
+
{ status: 'pending', lastError: null },
|
|
146
|
+
{ status: 'needs_attention', lastError: 'push rejected' },
|
|
147
|
+
{ status: 'needs_attention', lastError: 'later' },
|
|
148
|
+
]);
|
|
149
|
+
await expect(new PendingCommitsService(db).queuedOnBranch('alice/draft')).resolves.toEqual({
|
|
150
|
+
queued: 1,
|
|
151
|
+
stuck: 2,
|
|
152
|
+
needsAttention: 'push rejected',
|
|
153
|
+
});
|
|
154
|
+
// "Oldest" is the query's order, so every call reports the same message.
|
|
155
|
+
const dialect = new PgDialect();
|
|
156
|
+
const order = (orderBy.mock.calls[0] as unknown as SQL[]).map((o) => dialect.sqlToQuery(o).sql);
|
|
157
|
+
expect(order).toEqual(['"pending_commits"."queued_at" asc', '"pending_commits"."id" asc']);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('falls back to a message when a stuck row has an empty error, so it is never read as retryable', async () => {
|
|
161
|
+
const { db } = selectDb([{ status: 'needs_attention', lastError: '' }]);
|
|
162
|
+
await expect(new PendingCommitsService(db).queuedOnBranch('alice/draft')).resolves.toEqual({
|
|
163
|
+
queued: 0,
|
|
164
|
+
stuck: 1,
|
|
165
|
+
needsAttention: 'A queued commit on this branch failed and needs a person.',
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('answers nothing queued for a quiet branch', async () => {
|
|
170
|
+
const { db } = selectDb([]);
|
|
171
|
+
await expect(new PendingCommitsService(db).queuedOnBranch('quiet')).resolves.toEqual({
|
|
172
|
+
queued: 0,
|
|
173
|
+
stuck: 0,
|
|
174
|
+
needsAttention: null,
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -139,6 +139,30 @@ describe('PendingCommitsWorker.drainOnce', () => {
|
|
|
139
139
|
expect(feedback.send).not.toHaveBeenCalled();
|
|
140
140
|
});
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* The author's synthetic id reaches log lines (`user=<id>` when a push or
|
|
144
|
+
* its recovery fails), and log lines carry no email addresses: the id is
|
|
145
|
+
* opaque, and the same person gets the same one however their address was
|
|
146
|
+
* typed.
|
|
147
|
+
*/
|
|
148
|
+
it("the commit author's id carries no address, and is the same for one person", async () => {
|
|
149
|
+
const seen: string[] = [];
|
|
150
|
+
workflow.runPendingCommit.mockImplementation(async (_ws: string, _b: string, _p: string, user: AuthUser) => {
|
|
151
|
+
seen.push(user.id);
|
|
152
|
+
});
|
|
153
|
+
for (const authorEmail of ['alice@example.com', 'Alice@Example.com ', 'bob@example.com']) {
|
|
154
|
+
(service.claimNext as ReturnType<typeof vi.fn>).mockResolvedValueOnce(makeRow({ authorEmail }));
|
|
155
|
+
await worker.drainOnce();
|
|
156
|
+
}
|
|
157
|
+
expect(seen).toHaveLength(3);
|
|
158
|
+
for (const id of seen) {
|
|
159
|
+
expect(id).not.toContain('@');
|
|
160
|
+
expect(id).not.toMatch(/alice|bob|example/i);
|
|
161
|
+
}
|
|
162
|
+
expect(seen[0]).toBe(seen[1]);
|
|
163
|
+
expect(seen[0]).not.toBe(seen[2]);
|
|
164
|
+
});
|
|
165
|
+
|
|
142
166
|
it('skips work entirely when claimNext returns null (idle queue)', async () => {
|
|
143
167
|
(service.claimNext as ReturnType<typeof vi.fn>).mockResolvedValueOnce(null);
|
|
144
168
|
|
|
@@ -225,7 +249,11 @@ describe('PendingCommitsWorker.drainOnce', () => {
|
|
|
225
249
|
expect(call.message).toContain('ws-1');
|
|
226
250
|
expect(call.message).toContain('Foo.md');
|
|
227
251
|
expect(call.message).toContain('unrecoverable');
|
|
228
|
-
|
|
252
|
+
// The author is on the queue row the notice names — never in the body,
|
|
253
|
+
// which a core-only deployment writes to its log.
|
|
254
|
+
expect(call.message).toContain('Queue row: row-1');
|
|
255
|
+
expect(call.message).not.toContain('@');
|
|
256
|
+
expect(call.message).not.toContain('Alice');
|
|
229
257
|
});
|
|
230
258
|
|
|
231
259
|
it('a path-outside-repo refusal escalates at once: no retry, no recovery agent, the notice names the corrected path', async () => {
|
|
@@ -258,7 +286,8 @@ describe('PendingCommitsWorker.drainOnce', () => {
|
|
|
258
286
|
// The correction survives the truncation: it rides on the error payload,
|
|
259
287
|
// not on the message.
|
|
260
288
|
expect(call.message).toContain('Use instead: knowledge-base/KnowledgeBase/Reviews/PR-12.html');
|
|
261
|
-
expect(call.message).toContain('
|
|
289
|
+
expect(call.message).toContain('Queue row: row-1');
|
|
290
|
+
expect(call.message).not.toContain('@');
|
|
262
291
|
});
|
|
263
292
|
|
|
264
293
|
it('a feedback-sink failure does not throw — the row stays needs_attention regardless', async () => {
|