@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,304 @@
|
|
|
1
|
+
import type { Server } from 'node:http';
|
|
2
|
+
import type { AddressInfo } from 'node:net';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { ToolRegistry } from '../../tool-registry/tool-registry.js';
|
|
6
|
+
import { createToolHandlerFactory } from '../../tool-helpers/tool-handler.js';
|
|
7
|
+
import { ToolError, type ToolContext } from '../../tool-helpers/tool.contract.js';
|
|
8
|
+
import type { ReadForTool } from '../../workspace/workspace.tools.js';
|
|
9
|
+
import { ToolDescriptionNotes } from '../../workspace/agent-access.gate.js';
|
|
10
|
+
import { testKbContext, TEST_BRANCH_MODEL } from '../../../__tests__/kb-context.js';
|
|
11
|
+
import {
|
|
12
|
+
HTTP_DEPLOYMENT_NOTE,
|
|
13
|
+
OPEN_PAGE_TOOL,
|
|
14
|
+
registerEmbedTools,
|
|
15
|
+
toRepoRelative,
|
|
16
|
+
} from '../embed.tools.js';
|
|
17
|
+
|
|
18
|
+
const KB = 'knowledge-base';
|
|
19
|
+
const BRANCH = TEST_BRANCH_MODEL.defaultBranch;
|
|
20
|
+
const PAGE = '# Thing\n\nWhat it is.\n';
|
|
21
|
+
|
|
22
|
+
let server: Server | null = null;
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
if (server) await new Promise<void>((resolve) => server!.close(() => resolve()));
|
|
25
|
+
server = null;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
interface Opts {
|
|
29
|
+
/** What `read_file`'s own read answers — or throws. */
|
|
30
|
+
read?: ReadForTool;
|
|
31
|
+
canBeReached?: boolean;
|
|
32
|
+
/** The deployment's notes for the gated tools; a fresh, empty set when absent. */
|
|
33
|
+
notes?: ToolDescriptionNotes;
|
|
34
|
+
/** The caller the tool auth resolves to: a signed-in session, or a connection key's owner. */
|
|
35
|
+
caller?: { id: string; email: string; name: string; tokenId?: string };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function serve(opts: Opts = {}) {
|
|
39
|
+
const caller = opts.caller ?? { id: 'u-1', email: 'alice@bevel.software', name: 'Alice' };
|
|
40
|
+
const registry = new ToolRegistry();
|
|
41
|
+
const router = express.Router();
|
|
42
|
+
const auth: express.RequestHandler = (req, _res, next) => {
|
|
43
|
+
req.toolAuth = {
|
|
44
|
+
source: 'external',
|
|
45
|
+
userId: caller.id,
|
|
46
|
+
scope: 'write',
|
|
47
|
+
...(caller.tokenId ? { tokenId: caller.tokenId } : {}),
|
|
48
|
+
} as never;
|
|
49
|
+
next();
|
|
50
|
+
};
|
|
51
|
+
const resolve = async (): Promise<ToolContext> =>
|
|
52
|
+
({
|
|
53
|
+
user: { id: caller.id, email: caller.email, name: caller.name },
|
|
54
|
+
scope: 'write',
|
|
55
|
+
source: 'external',
|
|
56
|
+
...(caller.tokenId ? { tokenId: caller.tokenId } : {}),
|
|
57
|
+
abortSignal: new AbortController().signal,
|
|
58
|
+
workspaceService: {} as never,
|
|
59
|
+
workflowService: {} as never,
|
|
60
|
+
events: {} as never,
|
|
61
|
+
getFilesystem: async () => {
|
|
62
|
+
throw new Error('open_page reads through readForTool, not the filesystem');
|
|
63
|
+
},
|
|
64
|
+
}) as unknown as ToolContext;
|
|
65
|
+
|
|
66
|
+
const mints: Array<{ userId: string; reference: string }> = [];
|
|
67
|
+
const embedService = {
|
|
68
|
+
mintForUser: vi.fn(async (input: { userId: string; reference: string }) => {
|
|
69
|
+
mints.push(input);
|
|
70
|
+
return { token: 'tok', embedUrl: `https://hexis.example/embed?token=tok` };
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
const readForTool: ReadForTool =
|
|
74
|
+
opts.read ?? (async () => ({ kind: 'text', text: PAGE }));
|
|
75
|
+
|
|
76
|
+
const notes = opts.notes ?? new ToolDescriptionNotes();
|
|
77
|
+
registerEmbedTools(registry, router, auth, createToolHandlerFactory(resolve), {
|
|
78
|
+
embedService: embedService as never,
|
|
79
|
+
kb: testKbContext({ kbDirName: KB }),
|
|
80
|
+
readForTool,
|
|
81
|
+
canBeReached: () => opts.canBeReached ?? true,
|
|
82
|
+
appUrlFor: (repoRelative, slug) =>
|
|
83
|
+
`https://hexis.example/workspace/${encodeURIComponent(BRANCH)}/${KB}/${repoRelative}` +
|
|
84
|
+
(slug ? `#${slug}` : ''),
|
|
85
|
+
notes,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const app = express();
|
|
89
|
+
app.use(express.json());
|
|
90
|
+
app.use('/api', router);
|
|
91
|
+
server = app.listen(0);
|
|
92
|
+
await new Promise<void>((r) => server!.once('listening', () => r()));
|
|
93
|
+
const base = `http://127.0.0.1:${(server!.address() as AddressInfo).port}`;
|
|
94
|
+
|
|
95
|
+
const call = async (body: unknown) => {
|
|
96
|
+
const res = await fetch(`${base}/api/agent/tools/${OPEN_PAGE_TOOL}`, {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
headers: { 'content-type': 'application/json' },
|
|
99
|
+
body: JSON.stringify(body),
|
|
100
|
+
});
|
|
101
|
+
return { status: res.status, body: (await res.json()) as Record<string, unknown> };
|
|
102
|
+
};
|
|
103
|
+
return { call, registry, embedService, mints, notes };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** `open_page`'s definition as the external listing carries it, with its `sessionId` input. */
|
|
107
|
+
async function openPageDef(registry: ToolRegistry) {
|
|
108
|
+
const def = (await registry.listExternal()).find((t) => t.name === OPEN_PAGE_TOOL)!;
|
|
109
|
+
const body = (def.inputs as { properties: { body: { properties: Record<string, { description?: string }> } } })
|
|
110
|
+
.properties.body;
|
|
111
|
+
return { description: def.description, sessionId: body.properties.sessionId };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
describe('open_page: the listing', () => {
|
|
115
|
+
it('is advertised to an external agent, and is not an in-app tool', async () => {
|
|
116
|
+
const { registry } = await serve();
|
|
117
|
+
const external = (await registry.listExternal()).map((t) => t.name);
|
|
118
|
+
const internal = (await registry.listInternal()).map((t) => t.name);
|
|
119
|
+
expect(external).toContain(OPEN_PAGE_TOOL);
|
|
120
|
+
// The in-app reader is already looking at the app, where every page is a
|
|
121
|
+
// click away; an iframe of the page they are standing on cannot help.
|
|
122
|
+
expect(internal).not.toContain(OPEN_PAGE_TOOL);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('takes a path and an optional heading, and no branch at all', async () => {
|
|
126
|
+
const { registry } = await serve();
|
|
127
|
+
const def = (await registry.listExternal()).find((t) => t.name === OPEN_PAGE_TOOL)!;
|
|
128
|
+
const body = (def.inputs as { properties: { body: { properties: Record<string, unknown>; required: string[] } } })
|
|
129
|
+
.properties.body;
|
|
130
|
+
// `sessionId` as `read_file` takes it: the read is `read_file`'s own, and
|
|
131
|
+
// a deployment whose read hook wants the session must be able to get it.
|
|
132
|
+
expect(Object.keys(body.properties).sort()).toEqual(['heading', 'path', 'sessionId']);
|
|
133
|
+
expect(body.required).toEqual(['path']);
|
|
134
|
+
// The embedded view is editable, and an editable embed targets the
|
|
135
|
+
// default branch only — so there is nothing for a caller to choose.
|
|
136
|
+
expect(body.properties).not.toHaveProperty('branch');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The read is `read_file`'s own, so the access contract an agent reads
|
|
141
|
+
* about it is `read_file`'s too: the note a deployment registers for the
|
|
142
|
+
* gated tools, and the `sessionId` note — whether registered before this
|
|
143
|
+
* tool was mounted or after (an overlay registers from the tool-surface
|
|
144
|
+
* hook, which runs once the tools are up).
|
|
145
|
+
*/
|
|
146
|
+
it('carries the deployment notes for the gated tools and the sessionId input, registered before or after mounting', async () => {
|
|
147
|
+
const early = new ToolDescriptionNotes();
|
|
148
|
+
early.registerGatedToolNote(' Early gated note.');
|
|
149
|
+
early.registerSessionIdNote(' Early session note.');
|
|
150
|
+
const before = await serve({ notes: early });
|
|
151
|
+
const seenEarly = await openPageDef(before.registry);
|
|
152
|
+
expect(seenEarly.description.endsWith(' Early gated note.')).toBe(true);
|
|
153
|
+
expect(seenEarly.sessionId.description).toBe(early.sessionIdDescription());
|
|
154
|
+
expect(seenEarly.sessionId.description?.endsWith(' Early session note.')).toBe(true);
|
|
155
|
+
if (server) await new Promise<void>((resolve) => server!.close(() => resolve()));
|
|
156
|
+
server = null;
|
|
157
|
+
|
|
158
|
+
const { registry, notes } = await serve();
|
|
159
|
+
const plain = await openPageDef(registry);
|
|
160
|
+
expect(plain.description.endsWith(' Early gated note.')).toBe(false);
|
|
161
|
+
expect(plain.sessionId.description).toBe(notes.sessionIdDescription());
|
|
162
|
+
notes.registerGatedToolNote(' Late gated note.');
|
|
163
|
+
notes.registerSessionIdNote(' Late session note.');
|
|
164
|
+
const late = await openPageDef(registry);
|
|
165
|
+
expect(late.description).toBe(plain.description + ' Late gated note.');
|
|
166
|
+
expect(late.sessionId.description).toBe(notes.sessionIdDescription());
|
|
167
|
+
expect(late.sessionId.description?.endsWith(' Late session note.')).toBe(true);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe('open_page: the answer', () => {
|
|
172
|
+
it('answers the page, the embed address, the app address, the path and the branch', async () => {
|
|
173
|
+
const { call } = await serve();
|
|
174
|
+
const { status, body } = await call({ path: `${KB}/Data/Thing.md` });
|
|
175
|
+
expect(status).toBe(200);
|
|
176
|
+
expect(body).toEqual({
|
|
177
|
+
path: `${KB}/Data/Thing.md`,
|
|
178
|
+
content: PAGE,
|
|
179
|
+
embedUrl: 'https://hexis.example/embed?token=tok',
|
|
180
|
+
appUrl: `https://hexis.example/workspace/${encodeURIComponent(BRANCH)}/${KB}/Data/Thing.md`,
|
|
181
|
+
branch: BRANCH,
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('mints for the caller identity — which under a connection key is the key owner', async () => {
|
|
186
|
+
const { call, mints } = await serve({
|
|
187
|
+
caller: { id: 'owner-9', email: 'owner@bevel.software', name: 'Owner', tokenId: 'tok-1' },
|
|
188
|
+
});
|
|
189
|
+
await call({ path: 'Data/Thing.md' });
|
|
190
|
+
expect(mints).toEqual([{ userId: 'owner-9', reference: 'Data/Thing.md' }]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('passes the heading through to the mint and into the app address', async () => {
|
|
194
|
+
const { call, mints } = await serve();
|
|
195
|
+
const { body } = await call({ path: 'Data/Thing.md', heading: 'what-it-is' });
|
|
196
|
+
expect(mints[0].reference).toBe('Data/Thing.md#what-it-is');
|
|
197
|
+
expect(body.appUrl).toContain('#what-it-is');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('accepts a path with or without the knowledge-base prefix, as read_file documents', async () => {
|
|
201
|
+
const { call, mints } = await serve();
|
|
202
|
+
await call({ path: 'Data/Thing.md' });
|
|
203
|
+
await call({ path: `/${KB}/Data/Thing.md` });
|
|
204
|
+
expect(mints.map((m) => m.reference)).toEqual(['Data/Thing.md', 'Data/Thing.md']);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('answers an image with the reader own note, and still shows the picture in the view', async () => {
|
|
208
|
+
const { call } = await serve({
|
|
209
|
+
read: async () => ({ kind: 'image', data: 'AAA', mimeType: 'image/png', note: '[image Shots/x.png]' }),
|
|
210
|
+
});
|
|
211
|
+
const { body } = await call({ path: 'Shots/x.png' });
|
|
212
|
+
expect(body.content).toBe('[image Shots/x.png]');
|
|
213
|
+
expect(body.embedUrl).toBe('https://hexis.example/embed?token=tok');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('answers a refusal the reader gives as the file text, as read_file does', async () => {
|
|
217
|
+
const { call } = await serve({
|
|
218
|
+
read: async () => ({ kind: 'refusal', message: 'This .zip cannot be read as text.' }),
|
|
219
|
+
});
|
|
220
|
+
const { body } = await call({ path: 'Archive/x.zip' });
|
|
221
|
+
expect(body.content).toBe('This .zip cannot be read as text.');
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('open_page: refusals', () => {
|
|
226
|
+
/**
|
|
227
|
+
* The read comes FIRST and it is `read_file`'s own, so the refusal is the
|
|
228
|
+
* one `read_file` gives — and no token is minted, because the mint is below
|
|
229
|
+
* that line.
|
|
230
|
+
*/
|
|
231
|
+
it('refuses a path the caller may not read, in read_file own words, and mints nothing', async () => {
|
|
232
|
+
const { call, embedService } = await serve({
|
|
233
|
+
read: async () => {
|
|
234
|
+
throw new ToolError(`You don't have permission to read "${KB}/Secret.md".`, 403);
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
const { status, body } = await call({ path: `${KB}/Secret.md` });
|
|
238
|
+
expect(status).toBe(403);
|
|
239
|
+
expect(body.error).toBe(`You don't have permission to read "${KB}/Secret.md".`);
|
|
240
|
+
expect(embedService.mintForUser).not.toHaveBeenCalled();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('refuses a path that does not exist, in read_file own words, and mints nothing', async () => {
|
|
244
|
+
const { call, embedService } = await serve({
|
|
245
|
+
read: async () => {
|
|
246
|
+
throw new ToolError(`"${KB}/Gone.md" does not exist.`, 404);
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
const { status, body } = await call({ path: `${KB}/Gone.md` });
|
|
250
|
+
expect(status).toBe(404);
|
|
251
|
+
expect(body.error).toBe(`"${KB}/Gone.md" does not exist.`);
|
|
252
|
+
expect(embedService.mintForUser).not.toHaveBeenCalled();
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('refuses a path outside the knowledge base, and a missing one', async () => {
|
|
256
|
+
const { call, embedService } = await serve();
|
|
257
|
+
expect((await call({ path: '' })).status).toBe(400);
|
|
258
|
+
expect((await call({ path: '../../etc/passwd' })).status).toBe(400);
|
|
259
|
+
expect((await call({})).status).toBe(400);
|
|
260
|
+
expect(embedService.mintForUser).not.toHaveBeenCalled();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe('open_page: a deployment that cannot be framed', () => {
|
|
265
|
+
/**
|
|
266
|
+
* A host runs an app view in a sandboxed https iframe, and no browser lets
|
|
267
|
+
* an https document frame a plain-http one. So the tool still answers the
|
|
268
|
+
* text and the app address, says why there is no view, and mints nothing —
|
|
269
|
+
* a token nobody can open is only a token in a transcript.
|
|
270
|
+
*/
|
|
271
|
+
it('answers the text and the app address, and says the view needs https', async () => {
|
|
272
|
+
const { call, embedService } = await serve({ canBeReached: false });
|
|
273
|
+
const { status, body } = await call({ path: 'Data/Thing.md' });
|
|
274
|
+
expect(status).toBe(200);
|
|
275
|
+
expect(body.content).toBe(PAGE);
|
|
276
|
+
expect(body.appUrl).toContain('/workspace/');
|
|
277
|
+
expect(body.branch).toBe(BRANCH);
|
|
278
|
+
expect(body).not.toHaveProperty('embedUrl');
|
|
279
|
+
expect(body.note).toBe(HTTP_DEPLOYMENT_NOTE);
|
|
280
|
+
expect(String(body.note)).toContain('https');
|
|
281
|
+
expect(embedService.mintForUser).not.toHaveBeenCalled();
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
describe('toRepoRelative', () => {
|
|
286
|
+
it.each([
|
|
287
|
+
['a bare path', 'Data/Thing.md', 'Data/Thing.md'],
|
|
288
|
+
['the kb prefix', `${KB}/Data/Thing.md`, 'Data/Thing.md'],
|
|
289
|
+
['a leading slash', `/${KB}/Data/Thing.md`, 'Data/Thing.md'],
|
|
290
|
+
['a dot-slash', './Data/Thing.md', 'Data/Thing.md'],
|
|
291
|
+
['a trailing slash', 'Data/Thing.md/', 'Data/Thing.md'],
|
|
292
|
+
])('reads %s', (_label, input, expected) => {
|
|
293
|
+
expect(toRepoRelative(input, KB)).toBe(expected);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// A backslash is refused, as `read_file` refuses it: read as a separator it
|
|
297
|
+
// would name a file other than the one the caller wrote, in a signed token.
|
|
298
|
+
it.each([['empty', ''], ['the folder itself', KB], ['traversal', 'Data/../../x'], ['a newline', 'a\nb'], ['DEL', 'a\x7fb'], ['a backslash', 'Data\\Thing.md']])(
|
|
299
|
+
'refuses %s',
|
|
300
|
+
(_label, input) => {
|
|
301
|
+
expect(toRepoRelative(input, KB)).toBeNull();
|
|
302
|
+
},
|
|
303
|
+
);
|
|
304
|
+
});
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import type { Server } from 'node:http';
|
|
5
|
+
import type { AddressInfo } from 'node:net';
|
|
6
|
+
import express from 'express';
|
|
7
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
8
|
+
import { MCP_APP_MIME_TYPE, MCP_APP_URI_SCHEME } from '@bevel-software/platform-mcp-core';
|
|
9
|
+
import { OPEN_PAGE_TOOL } from '../embed.tools.js';
|
|
10
|
+
import {
|
|
11
|
+
isSandboxReachableOrigin,
|
|
12
|
+
McpAppService,
|
|
13
|
+
OPEN_PAGE_VIEW_URI_PREFIX,
|
|
14
|
+
openPageViewUri,
|
|
15
|
+
originOf,
|
|
16
|
+
} from '../mcp-app.js';
|
|
17
|
+
import { createMcpAppRoutes } from '../mcp-app.routes.js';
|
|
18
|
+
|
|
19
|
+
let server: Server | null = null;
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
if (server) await new Promise<void>((resolve) => server!.close(() => resolve()));
|
|
22
|
+
server = null;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const PUBLIC = 'https://hexis.example';
|
|
26
|
+
|
|
27
|
+
describe('the open_page view', () => {
|
|
28
|
+
it('is named by the tool and served under the MCP App media type', async () => {
|
|
29
|
+
const manifest = await new McpAppService({ publicFrontendUrl: PUBLIC }).manifest();
|
|
30
|
+
expect(manifest.resources).toHaveLength(1);
|
|
31
|
+
const { uri } = manifest.resources[0];
|
|
32
|
+
expect(manifest.tools[OPEN_PAGE_TOOL]).toEqual({ resourceUri: uri });
|
|
33
|
+
expect(uri.startsWith(MCP_APP_URI_SCHEME)).toBe(true);
|
|
34
|
+
expect(uri.startsWith(OPEN_PAGE_VIEW_URI_PREFIX)).toBe(true);
|
|
35
|
+
expect(manifest.resources[0]).toMatchObject({ uri, mimeType: MCP_APP_MIME_TYPE });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A host caches a view by its URI, so a changed view under an unchanged
|
|
40
|
+
* URI is served stale until the host happens to refetch — Claude kept
|
|
41
|
+
* rendering the cached, pre-#391 view, the one that goes blank. Naming the
|
|
42
|
+
* view by its content makes every change a new URI.
|
|
43
|
+
*/
|
|
44
|
+
it('is named by its content, so a changed view is a new resource and the same view the same one', async () => {
|
|
45
|
+
const dir = mkdtempSync(path.join(tmpdir(), 'mcp-app-view-'));
|
|
46
|
+
try {
|
|
47
|
+
const at = async (html: string) => {
|
|
48
|
+
writeFileSync(path.join(dir, 'page.html'), html);
|
|
49
|
+
return (await new McpAppService({ publicFrontendUrl: PUBLIC, viewDir: dir }).manifest()).resources[0].uri;
|
|
50
|
+
};
|
|
51
|
+
const first = await at('<!doctype html><p>one</p>');
|
|
52
|
+
const same = await at('<!doctype html><p>one</p>');
|
|
53
|
+
const changed = await at('<!doctype html><p>two</p>');
|
|
54
|
+
expect(first).toMatch(/^ui:\/\/hexis\/page-[0-9a-f]{12}\.html$/);
|
|
55
|
+
expect(same).toBe(first);
|
|
56
|
+
expect(changed).not.toBe(first);
|
|
57
|
+
expect(first).toBe(openPageViewUri('<!doctype html><p>one</p>'));
|
|
58
|
+
} finally {
|
|
59
|
+
rmSync(dir, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The view reaches ONE origin — the deployment that served it — for two
|
|
65
|
+
* things: fetching its build manifest and the token-only embed API
|
|
66
|
+
* (connect), and loading the embed bundle (resources). It frames nothing:
|
|
67
|
+
* Claude's host drops `frameDomains` and pins `frame-src` to `'self'`,
|
|
68
|
+
* which is why the view runs the bundle in its own document.
|
|
69
|
+
*/
|
|
70
|
+
it('declares exactly the deployment own public origin for connecting and loading, and no frames', async () => {
|
|
71
|
+
const manifest = await new McpAppService({ publicFrontendUrl: `${PUBLIC}/sub/path` }).manifest();
|
|
72
|
+
expect(manifest.resources[0].ui.csp).toEqual({ connectDomains: [PUBLIC], resourceDomains: [PUBLIC] });
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The sandbox `domain` field's format is each host's own to define and
|
|
77
|
+
* validate, and a value a host rejects is a view that never renders. The
|
|
78
|
+
* view keeps no storage and has no OAuth callback, so it asks for no
|
|
79
|
+
* dedicated origin and takes the host's default sandbox.
|
|
80
|
+
*/
|
|
81
|
+
it('asks the host for no sandbox domain of its own', async () => {
|
|
82
|
+
const manifest = await new McpAppService({ publicFrontendUrl: PUBLIC }).manifest();
|
|
83
|
+
expect(manifest.resources[0].ui).not.toHaveProperty('domain');
|
|
84
|
+
expect(manifest.resources[0].ui.prefersBorder).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('is the HTML that runs the deployment embed bundle and relays a link, and nothing that renders content', async () => {
|
|
88
|
+
const manifest = await new McpAppService({ publicFrontendUrl: PUBLIC }).manifest();
|
|
89
|
+
const html = manifest.resources[0].text;
|
|
90
|
+
expect(html).toContain('ui/initialize');
|
|
91
|
+
expect(html).toContain('ui/notifications/tool-result');
|
|
92
|
+
expect(html).toContain('ui/open-link');
|
|
93
|
+
expect(html).toContain('structuredContent');
|
|
94
|
+
// The deployment's embed bundle, found through its build manifest and
|
|
95
|
+
// handed the page — not a frame of `/embed`, which a chat host's sandbox
|
|
96
|
+
// blocks.
|
|
97
|
+
expect(html).toContain('embed-manifest.json');
|
|
98
|
+
expect(html).toContain('__HEXIS_EMBED__');
|
|
99
|
+
expect(html).not.toContain('<iframe');
|
|
100
|
+
// No second rendering path: the view runs the app's renderers, it does not draw the page itself.
|
|
101
|
+
expect(html).not.toContain('marked');
|
|
102
|
+
expect(html).not.toContain('<markdown');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('serves the view by URI, and nothing else', async () => {
|
|
106
|
+
const apps = new McpAppService({ publicFrontendUrl: PUBLIC });
|
|
107
|
+
const { uri } = (await apps.manifest()).resources[0];
|
|
108
|
+
expect(await apps.resource(uri)).not.toBeNull();
|
|
109
|
+
expect(await apps.resource('ui://hexis/not-a-view.html')).toBeNull();
|
|
110
|
+
// The unversioned name the view had before #391 is not served either: a
|
|
111
|
+
// host still asking for it gets "no such resource", not a stale view.
|
|
112
|
+
expect(await apps.resource('ui://hexis/page.html')).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('reads the view once and caches it — resources/read is on a handshake path', async () => {
|
|
116
|
+
const apps = new McpAppService({ publicFrontendUrl: PUBLIC });
|
|
117
|
+
const [a, b] = await Promise.all([apps.manifest(), apps.manifest()]);
|
|
118
|
+
expect(a).toBe(b);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('originOf / isSandboxReachableOrigin', () => {
|
|
123
|
+
it('reduces an address to its origin, and refuses one that does not parse', () => {
|
|
124
|
+
expect(originOf(`${PUBLIC}/sub?x=1#y`)).toBe(PUBLIC);
|
|
125
|
+
expect(originOf('not a url')).toBeNull();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* A host runs an app view in a sandboxed https iframe, and no browser lets
|
|
130
|
+
* an https document load scripts from, or fetch from, a plain-http origin —
|
|
131
|
+
* so a deployment reached over http has no embedded view, and `open_page`
|
|
132
|
+
* says so.
|
|
133
|
+
*/
|
|
134
|
+
it.each([
|
|
135
|
+
['https', 'https://hexis.example', true],
|
|
136
|
+
['plain http', 'http://hexis.example', false],
|
|
137
|
+
['localhost over http', 'http://localhost:3001', false],
|
|
138
|
+
['nonsense', 'not a url', false],
|
|
139
|
+
])('%s is reachable from a sandbox: %s', (_label, url, expected) => {
|
|
140
|
+
expect(isSandboxReachableOrigin(url)).toBe(expected);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('the manifest route the local MCP server reads', () => {
|
|
145
|
+
async function serve() {
|
|
146
|
+
const app = express();
|
|
147
|
+
const pass: express.RequestHandler = (_req, _res, next) => next();
|
|
148
|
+
app.use('/api', createMcpAppRoutes(new McpAppService({ publicFrontendUrl: PUBLIC }), pass));
|
|
149
|
+
server = app.listen(0);
|
|
150
|
+
await new Promise<void>((r) => server!.once('listening', () => r()));
|
|
151
|
+
return `http://127.0.0.1:${(server!.address() as AddressInfo).port}`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
it('answers the tool metadata and the view, so the local server can serve both', async () => {
|
|
155
|
+
const base = await serve();
|
|
156
|
+
const res = await fetch(`${base}/api/agent/mcp-app`);
|
|
157
|
+
expect(res.status).toBe(200);
|
|
158
|
+
const body = (await res.json()) as {
|
|
159
|
+
tools: Record<string, { resourceUri: string }>;
|
|
160
|
+
resources: Array<{ uri: string; mimeType: string; text: string; ui: Record<string, unknown> }>;
|
|
161
|
+
};
|
|
162
|
+
expect(body.tools[OPEN_PAGE_TOOL].resourceUri).toBe(body.resources[0].uri);
|
|
163
|
+
expect(body.resources[0].uri.startsWith(OPEN_PAGE_VIEW_URI_PREFIX)).toBe(true);
|
|
164
|
+
expect(body.resources[0].mimeType).toBe(MCP_APP_MIME_TYPE);
|
|
165
|
+
expect(body.resources[0].text).toContain('ui/initialize');
|
|
166
|
+
expect(body.resources[0].ui).toMatchObject({
|
|
167
|
+
csp: { connectDomains: [PUBLIC], resourceDomains: [PUBLIC] },
|
|
168
|
+
prefersBorder: false,
|
|
169
|
+
});
|
|
170
|
+
expect(body.resources[0].ui).not.toHaveProperty('domain');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('is behind the agent credential, like the rest of that surface', async () => {
|
|
174
|
+
const app = express();
|
|
175
|
+
const refuse: express.RequestHandler = (_req, res) => {
|
|
176
|
+
res.status(401).json({ error: 'Unauthenticated' });
|
|
177
|
+
};
|
|
178
|
+
app.use('/api', createMcpAppRoutes(new McpAppService({ publicFrontendUrl: PUBLIC }), refuse));
|
|
179
|
+
server = app.listen(0);
|
|
180
|
+
await new Promise<void>((r) => server!.once('listening', () => r()));
|
|
181
|
+
const base = `http://127.0.0.1:${(server!.address() as AddressInfo).port}`;
|
|
182
|
+
expect((await fetch(`${base}/api/agent/mcp-app`)).status).toBe(401);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* A deployment whose packaged view cannot be read must serve NO app rather
|
|
188
|
+
* than half of one: a `resourceUri` with no resource behind it would have a
|
|
189
|
+
* host preload a failure and show an empty frame where the tool's text was.
|
|
190
|
+
*/
|
|
191
|
+
describe('a view that cannot be read', () => {
|
|
192
|
+
it('leaves the deployment with no apps at all', async () => {
|
|
193
|
+
// The REAL build, pointed at a folder with no view in it — the read
|
|
194
|
+
// fails exactly as it does in an image that shipped without `mcp-app/`,
|
|
195
|
+
// and nothing packaged is touched under a parallel test run.
|
|
196
|
+
const empty = mkdtempSync(path.join(tmpdir(), 'no-mcp-app-'));
|
|
197
|
+
try {
|
|
198
|
+
const service = new McpAppService({ publicFrontendUrl: PUBLIC, viewDir: empty });
|
|
199
|
+
const manifest = await service.manifest();
|
|
200
|
+
expect(manifest.tools).toEqual({});
|
|
201
|
+
expect(manifest.resources).toEqual([]);
|
|
202
|
+
expect(await service.resource(openPageViewUri(''))).toBeNull();
|
|
203
|
+
} finally {
|
|
204
|
+
rmSync(empty, { recursive: true, force: true });
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { and, eq } from 'drizzle-orm';
|
|
2
|
+
import type { Database } from '../database/connection.js';
|
|
3
|
+
import { atlassianAccountLinks } from '../database/schema.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Maps an outside system's account id — today an Atlassian (Forge) account —
|
|
7
|
+
* to a Hexis user. Keyed on the account id because the embed always knows it
|
|
8
|
+
* (`context.accountId`), unlike email which a user can hide. Written by the
|
|
9
|
+
* `/embed/link` flow; read on every embed load, lock and save minted for such
|
|
10
|
+
* an account, to resolve who the viewer is.
|
|
11
|
+
*
|
|
12
|
+
* An embed minted for a Hexis user (the MCP `open_page` path) consults none of
|
|
13
|
+
* this: its token names the user id directly, so there is nothing to link.
|
|
14
|
+
*/
|
|
15
|
+
/** The account links as the embed service consumes them — the port a deployment may substitute. */
|
|
16
|
+
export interface IAccountLinkService {
|
|
17
|
+
/** Resolve an account id to its linked Hexis user id, or null. */
|
|
18
|
+
getUserId(accountId: string): Promise<string | null>;
|
|
19
|
+
link(accountId: string, userId: string): Promise<void>;
|
|
20
|
+
listForUser(userId: string): Promise<Array<{ atlassianAccountId: string; createdAt: Date }>>;
|
|
21
|
+
unlink(userId: string, accountId: string): Promise<boolean>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class AccountLinkService implements IAccountLinkService {
|
|
25
|
+
constructor(private readonly db: Database) {}
|
|
26
|
+
|
|
27
|
+
/** Resolve an account id to its linked Hexis user id, or null. */
|
|
28
|
+
async getUserId(accountId: string): Promise<string | null> {
|
|
29
|
+
const [row] = await this.db
|
|
30
|
+
.select()
|
|
31
|
+
.from(atlassianAccountLinks)
|
|
32
|
+
.where(eq(atlassianAccountLinks.atlassianAccountId, accountId))
|
|
33
|
+
.limit(1);
|
|
34
|
+
return row?.userId ?? null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Link (or re-link) an account id to a Hexis user. Idempotent. */
|
|
38
|
+
async link(accountId: string, userId: string): Promise<void> {
|
|
39
|
+
await this.db
|
|
40
|
+
.insert(atlassianAccountLinks)
|
|
41
|
+
.values({ atlassianAccountId: accountId, userId })
|
|
42
|
+
.onConflictDoUpdate({
|
|
43
|
+
target: atlassianAccountLinks.atlassianAccountId,
|
|
44
|
+
set: { userId, updatedAt: new Date() },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Every account linked to `userId` (one per outside site). */
|
|
49
|
+
async listForUser(userId: string): Promise<Array<{ atlassianAccountId: string; createdAt: Date }>> {
|
|
50
|
+
return this.db
|
|
51
|
+
.select({
|
|
52
|
+
atlassianAccountId: atlassianAccountLinks.atlassianAccountId,
|
|
53
|
+
createdAt: atlassianAccountLinks.createdAt,
|
|
54
|
+
})
|
|
55
|
+
.from(atlassianAccountLinks)
|
|
56
|
+
.where(eq(atlassianAccountLinks.userId, userId));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Remove one of `userId`'s links. Scoped to the owner — the userId
|
|
61
|
+
* condition makes deleting someone else's link structurally impossible,
|
|
62
|
+
* not a caller responsibility. Returns whether a row was actually removed.
|
|
63
|
+
*/
|
|
64
|
+
async unlink(userId: string, accountId: string): Promise<boolean> {
|
|
65
|
+
const deleted = await this.db
|
|
66
|
+
.delete(atlassianAccountLinks)
|
|
67
|
+
.where(
|
|
68
|
+
and(
|
|
69
|
+
eq(atlassianAccountLinks.atlassianAccountId, accountId),
|
|
70
|
+
eq(atlassianAccountLinks.userId, userId),
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
.returning({ atlassianAccountId: atlassianAccountLinks.atlassianAccountId });
|
|
74
|
+
return deleted.length > 0;
|
|
75
|
+
}
|
|
76
|
+
}
|