@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,225 @@
|
|
|
1
|
+
/** How long an issued link, and the bytes behind it, stay usable. */
|
|
2
|
+
export declare const DOWNLOAD_TOKEN_TTL_MS: number;
|
|
3
|
+
/**
|
|
4
|
+
* THE one refusal for every way a download link can fail to be usable: it was
|
|
5
|
+
* never issued, it has already been fetched, it has expired, or it belongs to
|
|
6
|
+
* somebody else. One sentence for all four, for the reason the upload token
|
|
7
|
+
* gives (`UPLOAD_TOKEN_REFUSAL`): the token is the whole credential the route
|
|
8
|
+
* has, and an answer that told the cases apart would let a guesser learn which
|
|
9
|
+
* guesses exist.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DOWNLOAD_TOKEN_REFUSAL: string;
|
|
12
|
+
/**
|
|
13
|
+
* How many download REQUESTS one user may hold open at once — however many
|
|
14
|
+
* links each carries. A request with forty files and two folders is one.
|
|
15
|
+
*
|
|
16
|
+
* A request is permission to keep up to the whole download limit on the
|
|
17
|
+
* deployment's disk for a TTL; without a bound, one caller asks for a hundred.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MAX_OPEN_DOWNLOADS_PER_USER = 10;
|
|
20
|
+
/** A refusal with the HTTP status the download route and the tool both answer. */
|
|
21
|
+
export declare class DownloadTokenError extends Error {
|
|
22
|
+
readonly status: number;
|
|
23
|
+
constructor(message: string, status: number);
|
|
24
|
+
}
|
|
25
|
+
/** One thing a link serves: a file's bytes, or a folder's zip. */
|
|
26
|
+
export interface DownloadArtifact {
|
|
27
|
+
/** The bytes, captured when the request was made. */
|
|
28
|
+
data: Buffer;
|
|
29
|
+
/** The `Content-Type` the link answers with. */
|
|
30
|
+
contentType: string;
|
|
31
|
+
/** The name the attachment is saved under. */
|
|
32
|
+
filename: string;
|
|
33
|
+
}
|
|
34
|
+
/** What the `issue` {@link AgentDownloadStore.withRequestSlot} hands its work answers: one link per artifact, in order, and the terms. */
|
|
35
|
+
export interface IssuedDownload {
|
|
36
|
+
/** One absolute URL per artifact, in the order the artifacts were given. */
|
|
37
|
+
downloadUrls: string[];
|
|
38
|
+
/** ISO-8601 instant after which every link of the request, and its bytes, are gone. */
|
|
39
|
+
expiresAt: string;
|
|
40
|
+
/** Seconds from now until `expiresAt`, so a caller need not parse the date. */
|
|
41
|
+
expiresInSeconds: number;
|
|
42
|
+
}
|
|
43
|
+
/** A link being fetched: what to send, and how. */
|
|
44
|
+
export interface ClaimedDownload {
|
|
45
|
+
/** Absolute path of the stored bytes — OUTSIDE every workspace. */
|
|
46
|
+
absolutePath: string;
|
|
47
|
+
contentType: string;
|
|
48
|
+
filename: string;
|
|
49
|
+
bytes: number;
|
|
50
|
+
}
|
|
51
|
+
export interface AgentDownloadStoreOptions {
|
|
52
|
+
/** Directory the bytes are written to. A sibling of `workspacesRoot`, never inside one. */
|
|
53
|
+
root: string;
|
|
54
|
+
/** Absolute base URL of this deployment's API, e.g. `https://core.example.com`. */
|
|
55
|
+
publicBaseUrl: string;
|
|
56
|
+
/** Token prefix, so a leaked credential can be recognised by shape. */
|
|
57
|
+
tokenPrefix?: string;
|
|
58
|
+
ttlMs?: number;
|
|
59
|
+
/** How many requests one user may hold open at once. Defaults to {@link MAX_OPEN_DOWNLOADS_PER_USER}. */
|
|
60
|
+
maxOpenPerUser?: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The download links an agent takes files OUT of the knowledge base by — the
|
|
64
|
+
* twin of the upload store (`agent-upload.store.ts`), and built on the same
|
|
65
|
+
* three properties, because the download route is likewise authenticated by
|
|
66
|
+
* a token alone:
|
|
67
|
+
*
|
|
68
|
+
* - **Unguessable.** 32 random bytes, base64url, per link.
|
|
69
|
+
* - **Never stored in the clear.** Records are keyed by the token's SHA-256.
|
|
70
|
+
* - **Bound and single-use.** A link answers ONE fetch; a second, an expired
|
|
71
|
+
* one and an unknown one all meet {@link DOWNLOAD_TOKEN_REFUSAL}.
|
|
72
|
+
*
|
|
73
|
+
* The bytes are captured at request time (by `request_file_download`, which
|
|
74
|
+
* judges every file before it gets here) and written under `root/<request>/` —
|
|
75
|
+
* a directory beside the workspaces root, which no file tool can name. A link
|
|
76
|
+
* fetched has its bytes deleted once the response ends, however it ends; a
|
|
77
|
+
* link nobody fetched is deleted when it expires.
|
|
78
|
+
*/
|
|
79
|
+
/**
|
|
80
|
+
* The download store as its consumers see it — the port the tool, the
|
|
81
|
+
* download routes and the lifecycle depend on, so a deployment may substitute
|
|
82
|
+
* its own keeper of one-time links.
|
|
83
|
+
*/
|
|
84
|
+
export interface IAgentDownloadStore {
|
|
85
|
+
/** The absolute address a token's link is fetched at. */
|
|
86
|
+
downloadUrlFor(token: string): string;
|
|
87
|
+
/** Refuse, with the cap's sentence, when `user` holds the most requests allowed. */
|
|
88
|
+
assertCanIssue(user: {
|
|
89
|
+
id: string;
|
|
90
|
+
}): void;
|
|
91
|
+
/** Take one of `user`'s request slots and run `work` in their turn — see the class. */
|
|
92
|
+
withRequestSlot<T>(user: {
|
|
93
|
+
id: string;
|
|
94
|
+
}, work: (issue: (items: DownloadArtifact[]) => Promise<IssuedDownload>) => Promise<T>): Promise<T>;
|
|
95
|
+
/** Take `token`'s link for ONE fetch and answer what to send. */
|
|
96
|
+
claim(token: string, fetcherIds?: readonly string[]): ClaimedDownload;
|
|
97
|
+
/** A fetch is over: the link's bytes are gone. Idempotent. */
|
|
98
|
+
finish(token: string): Promise<void>;
|
|
99
|
+
/** How many requests `userId` holds open. */
|
|
100
|
+
openRequestsOf(userId: string): number;
|
|
101
|
+
/** Delete every expired request and every orphaned directory, once. */
|
|
102
|
+
sweepNow(): Promise<void>;
|
|
103
|
+
/** Sweep now, and keep sweeping. */
|
|
104
|
+
startSweeping(intervalMs?: number): void;
|
|
105
|
+
/** Stop the sweeps. */
|
|
106
|
+
stopSweeping(): void;
|
|
107
|
+
/** Wait for a sweep in flight, so a root can be torn down after it. */
|
|
108
|
+
drainSweep(): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
export declare class AgentDownloadStore implements IAgentDownloadStore {
|
|
111
|
+
/** Token hash → the one artifact that link serves. */
|
|
112
|
+
private readonly artifacts;
|
|
113
|
+
/** Request id → the request its links belong to. */
|
|
114
|
+
private readonly requests;
|
|
115
|
+
/** Per user, the request in flight — see {@link withRequestSlot}. */
|
|
116
|
+
private readonly building;
|
|
117
|
+
/** Per user, slots held by calls still waiting, building or writing — counted as open. */
|
|
118
|
+
private readonly reserved;
|
|
119
|
+
/**
|
|
120
|
+
* Request ids whose bytes are being written right now: named in no map yet,
|
|
121
|
+
* and not the sweep's to reclaim. Entered before the first write and left
|
|
122
|
+
* once the request is recorded or its directory removed.
|
|
123
|
+
*/
|
|
124
|
+
private readonly writing;
|
|
125
|
+
/** The users whose turn the current async context is running in — see {@link withRequestSlot}. */
|
|
126
|
+
private readonly inTurn;
|
|
127
|
+
private readonly root;
|
|
128
|
+
private readonly publicBaseUrl;
|
|
129
|
+
private readonly tokenPrefix;
|
|
130
|
+
private readonly ttlMs;
|
|
131
|
+
private readonly maxOpenPerUser;
|
|
132
|
+
private sweepTimer;
|
|
133
|
+
private sweeping;
|
|
134
|
+
private stopped;
|
|
135
|
+
constructor(options: AgentDownloadStoreOptions);
|
|
136
|
+
/** The URL a link's bytes are fetched from. The one spelling of this route's address. */
|
|
137
|
+
downloadUrlFor(token: string): string;
|
|
138
|
+
/**
|
|
139
|
+
* Refuse `user` a new request when they already hold the most one user may
|
|
140
|
+
* — issued requests and slots still being filled alike.
|
|
141
|
+
*/
|
|
142
|
+
assertCanIssue(user: {
|
|
143
|
+
id: string;
|
|
144
|
+
}): void;
|
|
145
|
+
/**
|
|
146
|
+
* Take one of `user`'s request slots, then run `work` after any request of
|
|
147
|
+
* theirs already running; `work` is handed the `issue` that fills the slot.
|
|
148
|
+
*
|
|
149
|
+
* The slot is taken AT ONCE, before the turn is waited for, and counts as an
|
|
150
|
+
* open request until `work` ends: a caller at the cap is refused before the
|
|
151
|
+
* server spends a zip's worth of work on it, and ten calls in parallel cannot
|
|
152
|
+
* all pass the count and then all build. A call that ends without issuing
|
|
153
|
+
* (nothing included, a refusal, a failure) gives its slot back.
|
|
154
|
+
*
|
|
155
|
+
* The build AND the write of its bytes run in the turn: a build reads every
|
|
156
|
+
* included file into memory and may zip up to the download limit, so one
|
|
157
|
+
* request at a time per user bounds what one caller can make the process
|
|
158
|
+
* hold or the disk stage. Different users do not wait on each other.
|
|
159
|
+
*
|
|
160
|
+
* The ONE way a request is issued: there is no public `issue` to call on
|
|
161
|
+
* the side. `work`'s `issue` fills the slot once — a second call would be
|
|
162
|
+
* a second request on one slot, past the cap — and a `withRequestSlot` for
|
|
163
|
+
* the same user from inside `work` throws rather than wait for the turn it
|
|
164
|
+
* is itself holding, which would never come.
|
|
165
|
+
*/
|
|
166
|
+
withRequestSlot<T>(user: {
|
|
167
|
+
id: string;
|
|
168
|
+
}, work: (issue: (items: DownloadArtifact[]) => Promise<IssuedDownload>) => Promise<T>): Promise<T>;
|
|
169
|
+
/** Give back one of `userId`'s reserved slots. */
|
|
170
|
+
private releaseReservation;
|
|
171
|
+
/**
|
|
172
|
+
* Store every artifact of one request and answer a link per artifact, all
|
|
173
|
+
* sharing the request's expiry, within a slot already held: the slot is the
|
|
174
|
+
* capacity check. Nothing is issued unless every artifact is on disk: a
|
|
175
|
+
* request whose bytes could not all be written leaves nothing.
|
|
176
|
+
*/
|
|
177
|
+
private write;
|
|
178
|
+
/**
|
|
179
|
+
* Take `token`'s link for ONE fetch and answer what to send. Spent the
|
|
180
|
+
* moment it is claimed, before a byte goes out: a second fetch arriving
|
|
181
|
+
* while the first is still sending is refused, not served twice.
|
|
182
|
+
*
|
|
183
|
+
* `fetcherIds` are the users the fetch identified itself as, by every
|
|
184
|
+
* credential it carried — usually none. The link works for anyone holding
|
|
185
|
+
* it — an agent's `curl` carries no session — but a fetch that says it is
|
|
186
|
+
* SOMEONE ELSE, by any of its credentials, is refused: that user holds a
|
|
187
|
+
* link issued to another.
|
|
188
|
+
*/
|
|
189
|
+
claim(token: string, fetcherIds?: readonly string[]): ClaimedDownload;
|
|
190
|
+
/**
|
|
191
|
+
* The fetch of `token` has ended — sent in full, failed, or the client went
|
|
192
|
+
* away. The bytes go either way: a link answers once, so nothing will ever
|
|
193
|
+
* read them again. Idempotent.
|
|
194
|
+
*/
|
|
195
|
+
finish(token: string): Promise<void>;
|
|
196
|
+
/**
|
|
197
|
+
* How many requests `userId` holds open: unexpired with a link unfetched, or
|
|
198
|
+
* with a fetch still sending — and the slots of calls still under way.
|
|
199
|
+
*/
|
|
200
|
+
openRequestsOf(userId: string): number;
|
|
201
|
+
/**
|
|
202
|
+
* Delete every request whose links have expired, with its bytes — then any
|
|
203
|
+
* directory in the root that no live request names and that has outlived
|
|
204
|
+
* every link that could name it (a process killed between issue and fetch
|
|
205
|
+
* leaves one no map will ever mention again; by AGE, because during a
|
|
206
|
+
* restart two processes share the root, as the upload store explains).
|
|
207
|
+
*/
|
|
208
|
+
sweepNow(): Promise<void>;
|
|
209
|
+
/** Sweep now, and keep sweeping. Started by the first request issued; idempotent; `unref`'d. */
|
|
210
|
+
startSweeping(intervalMs?: number): void;
|
|
211
|
+
/** Stop sweeping for good — see `AgentUploadStore.stopSweeping` for why a stopped graph must. */
|
|
212
|
+
stopSweeping(): void;
|
|
213
|
+
/** Wait for the sweep in flight, if any. Pairs with {@link stopSweeping} on shutdown. */
|
|
214
|
+
drainSweep(): Promise<void>;
|
|
215
|
+
private sweep;
|
|
216
|
+
/** Whether a fetch of one of `request`'s links is still sending, within its grace. */
|
|
217
|
+
private sending;
|
|
218
|
+
/** Drop one artifact's link and bytes; the request goes with its last one. */
|
|
219
|
+
private forget;
|
|
220
|
+
private dropRequest;
|
|
221
|
+
private outlivedEveryLink;
|
|
222
|
+
/** Best-effort delete of one request's directory. Never throws. */
|
|
223
|
+
private removeDir;
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=agent-download.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-download.store.d.ts","sourceRoot":"","sources":["../../../src/modules/workspace/agent-download.store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
|
+
import { promises as fs } from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { logger } from '../../shared/logging.js';
|
|
6
|
+
const log = logger('agent-downloads');
|
|
7
|
+
/** How long an issued link, and the bytes behind it, stay usable. */
|
|
8
|
+
export const DOWNLOAD_TOKEN_TTL_MS = 15 * 60 * 1000; // 15 minutes
|
|
9
|
+
/** How often the store looks for links that have expired. */
|
|
10
|
+
const SWEEP_INTERVAL_MS = 60 * 1000;
|
|
11
|
+
/**
|
|
12
|
+
* How long past its expiry a fetch that is still SENDING keeps its bytes.
|
|
13
|
+
*
|
|
14
|
+
* A link fetched a moment before it expires may take longer than the moment
|
|
15
|
+
* to send a large file. Its bytes are being read right now, so the sweep
|
|
16
|
+
* leaves them alone — but only for this long: a response that has neither
|
|
17
|
+
* finished nor failed within it belongs to a process that died, and the
|
|
18
|
+
* record is in memory, so there is no third possibility.
|
|
19
|
+
*/
|
|
20
|
+
const SEND_GRACE_MS = 10 * 60 * 1000; // 10 minutes
|
|
21
|
+
/**
|
|
22
|
+
* THE one refusal for every way a download link can fail to be usable: it was
|
|
23
|
+
* never issued, it has already been fetched, it has expired, or it belongs to
|
|
24
|
+
* somebody else. One sentence for all four, for the reason the upload token
|
|
25
|
+
* gives (`UPLOAD_TOKEN_REFUSAL`): the token is the whole credential the route
|
|
26
|
+
* has, and an answer that told the cases apart would let a guesser learn which
|
|
27
|
+
* guesses exist.
|
|
28
|
+
*/
|
|
29
|
+
export const DOWNLOAD_TOKEN_REFUSAL = 'That download link cannot be used: it is unknown, already fetched, expired, or was issued to someone else. ' +
|
|
30
|
+
'Call `request_file_download` for a new one.';
|
|
31
|
+
/**
|
|
32
|
+
* How many download REQUESTS one user may hold open at once — however many
|
|
33
|
+
* links each carries. A request with forty files and two folders is one.
|
|
34
|
+
*
|
|
35
|
+
* A request is permission to keep up to the whole download limit on the
|
|
36
|
+
* deployment's disk for a TTL; without a bound, one caller asks for a hundred.
|
|
37
|
+
*/
|
|
38
|
+
export const MAX_OPEN_DOWNLOADS_PER_USER = 10;
|
|
39
|
+
/** A refusal with the HTTP status the download route and the tool both answer. */
|
|
40
|
+
export class DownloadTokenError extends Error {
|
|
41
|
+
status;
|
|
42
|
+
constructor(message, status) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.status = status;
|
|
45
|
+
this.name = 'DownloadTokenError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export class AgentDownloadStore {
|
|
49
|
+
/** Token hash → the one artifact that link serves. */
|
|
50
|
+
artifacts = new Map();
|
|
51
|
+
/** Request id → the request its links belong to. */
|
|
52
|
+
requests = new Map();
|
|
53
|
+
/** Per user, the request in flight — see {@link withRequestSlot}. */
|
|
54
|
+
building = new Map();
|
|
55
|
+
/** Per user, slots held by calls still waiting, building or writing — counted as open. */
|
|
56
|
+
reserved = new Map();
|
|
57
|
+
/**
|
|
58
|
+
* Request ids whose bytes are being written right now: named in no map yet,
|
|
59
|
+
* and not the sweep's to reclaim. Entered before the first write and left
|
|
60
|
+
* once the request is recorded or its directory removed.
|
|
61
|
+
*/
|
|
62
|
+
writing = new Set();
|
|
63
|
+
/** The users whose turn the current async context is running in — see {@link withRequestSlot}. */
|
|
64
|
+
inTurn = new AsyncLocalStorage();
|
|
65
|
+
root;
|
|
66
|
+
publicBaseUrl;
|
|
67
|
+
tokenPrefix;
|
|
68
|
+
ttlMs;
|
|
69
|
+
maxOpenPerUser;
|
|
70
|
+
sweepTimer = null;
|
|
71
|
+
sweeping = null;
|
|
72
|
+
stopped = false;
|
|
73
|
+
constructor(options) {
|
|
74
|
+
this.root = options.root;
|
|
75
|
+
this.publicBaseUrl = options.publicBaseUrl.replace(/\/+$/, '');
|
|
76
|
+
this.tokenPrefix = options.tokenPrefix ?? '';
|
|
77
|
+
this.ttlMs = options.ttlMs ?? DOWNLOAD_TOKEN_TTL_MS;
|
|
78
|
+
this.maxOpenPerUser = options.maxOpenPerUser ?? MAX_OPEN_DOWNLOADS_PER_USER;
|
|
79
|
+
}
|
|
80
|
+
/** The URL a link's bytes are fetched from. The one spelling of this route's address. */
|
|
81
|
+
downloadUrlFor(token) {
|
|
82
|
+
return `${this.publicBaseUrl}/api/agent/downloads/${encodeURIComponent(token)}`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Refuse `user` a new request when they already hold the most one user may
|
|
86
|
+
* — issued requests and slots still being filled alike.
|
|
87
|
+
*/
|
|
88
|
+
assertCanIssue(user) {
|
|
89
|
+
const open = this.openRequestsOf(user.id);
|
|
90
|
+
if (open >= this.maxOpenPerUser) {
|
|
91
|
+
throw new DownloadTokenError(`You already hold ${open} open download requests, the most one user may have at once. Fetch their links, ` +
|
|
92
|
+
'or wait for them to expire, then ask again. One request carries any number of files and folders.', 429);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Take one of `user`'s request slots, then run `work` after any request of
|
|
97
|
+
* theirs already running; `work` is handed the `issue` that fills the slot.
|
|
98
|
+
*
|
|
99
|
+
* The slot is taken AT ONCE, before the turn is waited for, and counts as an
|
|
100
|
+
* open request until `work` ends: a caller at the cap is refused before the
|
|
101
|
+
* server spends a zip's worth of work on it, and ten calls in parallel cannot
|
|
102
|
+
* all pass the count and then all build. A call that ends without issuing
|
|
103
|
+
* (nothing included, a refusal, a failure) gives its slot back.
|
|
104
|
+
*
|
|
105
|
+
* The build AND the write of its bytes run in the turn: a build reads every
|
|
106
|
+
* included file into memory and may zip up to the download limit, so one
|
|
107
|
+
* request at a time per user bounds what one caller can make the process
|
|
108
|
+
* hold or the disk stage. Different users do not wait on each other.
|
|
109
|
+
*
|
|
110
|
+
* The ONE way a request is issued: there is no public `issue` to call on
|
|
111
|
+
* the side. `work`'s `issue` fills the slot once — a second call would be
|
|
112
|
+
* a second request on one slot, past the cap — and a `withRequestSlot` for
|
|
113
|
+
* the same user from inside `work` throws rather than wait for the turn it
|
|
114
|
+
* is itself holding, which would never come.
|
|
115
|
+
*/
|
|
116
|
+
async withRequestSlot(user, work) {
|
|
117
|
+
const held = this.inTurn.getStore();
|
|
118
|
+
if (held?.has(user.id)) {
|
|
119
|
+
throw new Error('A download request slot was asked for inside one already held for the same user.');
|
|
120
|
+
}
|
|
121
|
+
this.assertCanIssue(user);
|
|
122
|
+
this.reserved.set(user.id, (this.reserved.get(user.id) ?? 0) + 1);
|
|
123
|
+
// Once the request is recorded, the record is what counts as open and the
|
|
124
|
+
// reservation is given back by `write` — not here as well, which would
|
|
125
|
+
// count the request twice while `work` finishes.
|
|
126
|
+
let issued = false;
|
|
127
|
+
try {
|
|
128
|
+
const issue = (items) => {
|
|
129
|
+
if (issued)
|
|
130
|
+
return Promise.reject(new Error('A download request slot issues once.'));
|
|
131
|
+
issued = true;
|
|
132
|
+
return this.write(user, items);
|
|
133
|
+
};
|
|
134
|
+
const turn = new Set(held ?? []).add(user.id);
|
|
135
|
+
const before = this.building.get(user.id) ?? Promise.resolve();
|
|
136
|
+
const mine = before.catch(() => undefined).then(() => this.inTurn.run(turn, () => work(issue)));
|
|
137
|
+
this.building.set(user.id, mine);
|
|
138
|
+
try {
|
|
139
|
+
return await mine;
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
if (this.building.get(user.id) === mine)
|
|
143
|
+
this.building.delete(user.id);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
if (!issued)
|
|
148
|
+
this.releaseReservation(user.id);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** Give back one of `userId`'s reserved slots. */
|
|
152
|
+
releaseReservation(userId) {
|
|
153
|
+
const left = (this.reserved.get(userId) ?? 1) - 1;
|
|
154
|
+
if (left > 0)
|
|
155
|
+
this.reserved.set(userId, left);
|
|
156
|
+
else
|
|
157
|
+
this.reserved.delete(userId);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Store every artifact of one request and answer a link per artifact, all
|
|
161
|
+
* sharing the request's expiry, within a slot already held: the slot is the
|
|
162
|
+
* capacity check. Nothing is issued unless every artifact is on disk: a
|
|
163
|
+
* request whose bytes could not all be written leaves nothing.
|
|
164
|
+
*/
|
|
165
|
+
async write(user, items) {
|
|
166
|
+
if (items.length === 0)
|
|
167
|
+
throw new Error('A download request must carry at least one artifact.');
|
|
168
|
+
const requestId = `download-${Date.now()}-${randomBytes(8).toString('hex')}`;
|
|
169
|
+
const dir = path.join(this.root, requestId);
|
|
170
|
+
const minted = [];
|
|
171
|
+
// Reserved BEFORE the first filesystem await: a sweep running while a slow
|
|
172
|
+
// disk takes these writes would otherwise find a directory no request
|
|
173
|
+
// names and, past the age bound, reclaim it under the write.
|
|
174
|
+
this.writing.add(requestId);
|
|
175
|
+
try {
|
|
176
|
+
await fs.mkdir(dir, { recursive: true });
|
|
177
|
+
for (let i = 0; i < items.length; i++) {
|
|
178
|
+
const item = items[i];
|
|
179
|
+
const file = String(i);
|
|
180
|
+
await fs.writeFile(path.join(dir, file), item.data);
|
|
181
|
+
const token = this.tokenPrefix + randomBytes(32).toString('base64url');
|
|
182
|
+
minted.push({
|
|
183
|
+
key: hash(token),
|
|
184
|
+
token,
|
|
185
|
+
record: {
|
|
186
|
+
requestId,
|
|
187
|
+
file,
|
|
188
|
+
contentType: item.contentType,
|
|
189
|
+
filename: item.filename,
|
|
190
|
+
bytes: item.data.byteLength,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
try {
|
|
197
|
+
await this.removeDir(requestId);
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
this.writing.delete(requestId);
|
|
201
|
+
// Nothing issued: the slot goes back here, since `withRequestSlot`
|
|
202
|
+
// treats an `issue` that was called as one that filled its slot.
|
|
203
|
+
this.releaseReservation(user.id);
|
|
204
|
+
}
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
// The TTL runs from the moment the links exist, not from when the build
|
|
208
|
+
// started: a 500 MB build must not hand out links with minutes already gone.
|
|
209
|
+
const expiresAt = Date.now() + this.ttlMs;
|
|
210
|
+
const request = { id: requestId, userId: user.id, expiresAt, pending: new Set() };
|
|
211
|
+
for (const { key, record } of minted) {
|
|
212
|
+
this.artifacts.set(key, record);
|
|
213
|
+
request.pending.add(key);
|
|
214
|
+
}
|
|
215
|
+
this.requests.set(requestId, request);
|
|
216
|
+
this.writing.delete(requestId);
|
|
217
|
+
// The record counts as open from here; the reservation that held the
|
|
218
|
+
// place until now is given back, so the request is counted once.
|
|
219
|
+
this.releaseReservation(user.id);
|
|
220
|
+
// AFTER the records exist: the first sweep runs at once and would
|
|
221
|
+
// otherwise take this request's directory for an orphan. And never once
|
|
222
|
+
// the store is stopped: a request finishing after shutdown's
|
|
223
|
+
// `stopSweeping` must not re-arm the sweeper that was stopped for good.
|
|
224
|
+
if (!this.stopped)
|
|
225
|
+
this.startSweeping();
|
|
226
|
+
return {
|
|
227
|
+
downloadUrls: minted.map((m) => this.downloadUrlFor(m.token)),
|
|
228
|
+
expiresAt: new Date(expiresAt).toISOString(),
|
|
229
|
+
expiresInSeconds: Math.round(this.ttlMs / 1000),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Take `token`'s link for ONE fetch and answer what to send. Spent the
|
|
234
|
+
* moment it is claimed, before a byte goes out: a second fetch arriving
|
|
235
|
+
* while the first is still sending is refused, not served twice.
|
|
236
|
+
*
|
|
237
|
+
* `fetcherIds` are the users the fetch identified itself as, by every
|
|
238
|
+
* credential it carried — usually none. The link works for anyone holding
|
|
239
|
+
* it — an agent's `curl` carries no session — but a fetch that says it is
|
|
240
|
+
* SOMEONE ELSE, by any of its credentials, is refused: that user holds a
|
|
241
|
+
* link issued to another.
|
|
242
|
+
*/
|
|
243
|
+
claim(token, fetcherIds = []) {
|
|
244
|
+
const key = hash(token);
|
|
245
|
+
const record = this.artifacts.get(key);
|
|
246
|
+
if (!record || record.claimedAt !== undefined)
|
|
247
|
+
throw refusal();
|
|
248
|
+
const request = this.requests.get(record.requestId);
|
|
249
|
+
if (!request)
|
|
250
|
+
throw refusal();
|
|
251
|
+
if (request.expiresAt <= Date.now()) {
|
|
252
|
+
void this.forget(key);
|
|
253
|
+
throw refusal();
|
|
254
|
+
}
|
|
255
|
+
if (fetcherIds.some((id) => id !== request.userId))
|
|
256
|
+
throw refusal();
|
|
257
|
+
record.claimedAt = Date.now();
|
|
258
|
+
return {
|
|
259
|
+
absolutePath: path.join(this.root, record.requestId, record.file),
|
|
260
|
+
contentType: record.contentType,
|
|
261
|
+
filename: record.filename,
|
|
262
|
+
bytes: record.bytes,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* The fetch of `token` has ended — sent in full, failed, or the client went
|
|
267
|
+
* away. The bytes go either way: a link answers once, so nothing will ever
|
|
268
|
+
* read them again. Idempotent.
|
|
269
|
+
*/
|
|
270
|
+
async finish(token) {
|
|
271
|
+
const key = hash(token);
|
|
272
|
+
const record = this.artifacts.get(key);
|
|
273
|
+
if (!record)
|
|
274
|
+
return;
|
|
275
|
+
await this.forget(key);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* How many requests `userId` holds open: unexpired with a link unfetched, or
|
|
279
|
+
* with a fetch still sending — and the slots of calls still under way.
|
|
280
|
+
*/
|
|
281
|
+
openRequestsOf(userId) {
|
|
282
|
+
const now = Date.now();
|
|
283
|
+
let open = this.reserved.get(userId) ?? 0;
|
|
284
|
+
for (const request of this.requests.values()) {
|
|
285
|
+
if (request.userId !== userId)
|
|
286
|
+
continue;
|
|
287
|
+
if (request.expiresAt > now || this.sending(request, now))
|
|
288
|
+
open += 1;
|
|
289
|
+
}
|
|
290
|
+
return open;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Delete every request whose links have expired, with its bytes — then any
|
|
294
|
+
* directory in the root that no live request names and that has outlived
|
|
295
|
+
* every link that could name it (a process killed between issue and fetch
|
|
296
|
+
* leaves one no map will ever mention again; by AGE, because during a
|
|
297
|
+
* restart two processes share the root, as the upload store explains).
|
|
298
|
+
*/
|
|
299
|
+
async sweepNow() {
|
|
300
|
+
if (this.stopped)
|
|
301
|
+
return;
|
|
302
|
+
const now = Date.now();
|
|
303
|
+
for (const request of [...this.requests.values()]) {
|
|
304
|
+
if (request.expiresAt > now)
|
|
305
|
+
continue;
|
|
306
|
+
if (this.sending(request, now))
|
|
307
|
+
continue;
|
|
308
|
+
await this.dropRequest(request);
|
|
309
|
+
}
|
|
310
|
+
let names;
|
|
311
|
+
try {
|
|
312
|
+
names = await fs.readdir(this.root);
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
return; // root not created yet — nothing to reclaim
|
|
316
|
+
}
|
|
317
|
+
// Read AFTER the listing, so a request issued while it was read is named.
|
|
318
|
+
const live = new Set(this.requests.keys());
|
|
319
|
+
for (const name of names) {
|
|
320
|
+
if (this.stopped)
|
|
321
|
+
return;
|
|
322
|
+
if (live.has(name) || this.writing.has(name))
|
|
323
|
+
continue;
|
|
324
|
+
if (await this.outlivedEveryLink(name, now))
|
|
325
|
+
await this.removeDir(name);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/** Sweep now, and keep sweeping. Started by the first request issued; idempotent; `unref`'d. */
|
|
329
|
+
startSweeping(intervalMs = SWEEP_INTERVAL_MS) {
|
|
330
|
+
if (this.sweepTimer)
|
|
331
|
+
return;
|
|
332
|
+
this.stopped = false;
|
|
333
|
+
this.sweep();
|
|
334
|
+
this.sweepTimer = setInterval(() => this.sweep(), intervalMs);
|
|
335
|
+
this.sweepTimer.unref?.();
|
|
336
|
+
}
|
|
337
|
+
/** Stop sweeping for good — see `AgentUploadStore.stopSweeping` for why a stopped graph must. */
|
|
338
|
+
stopSweeping() {
|
|
339
|
+
this.stopped = true;
|
|
340
|
+
if (this.sweepTimer)
|
|
341
|
+
clearInterval(this.sweepTimer);
|
|
342
|
+
this.sweepTimer = null;
|
|
343
|
+
}
|
|
344
|
+
/** Wait for the sweep in flight, if any. Pairs with {@link stopSweeping} on shutdown. */
|
|
345
|
+
async drainSweep() {
|
|
346
|
+
await this.sweeping;
|
|
347
|
+
}
|
|
348
|
+
sweep() {
|
|
349
|
+
// One sweep at a time: a second starting while the first still deletes
|
|
350
|
+
// would make `drainSweep` wait for the newer and miss the older.
|
|
351
|
+
if (this.sweeping)
|
|
352
|
+
return;
|
|
353
|
+
const running = this.sweepNow()
|
|
354
|
+
.catch((err) => {
|
|
355
|
+
log.warn('could not sweep expired downloads:', { err });
|
|
356
|
+
})
|
|
357
|
+
.finally(() => {
|
|
358
|
+
if (this.sweeping === running)
|
|
359
|
+
this.sweeping = null;
|
|
360
|
+
});
|
|
361
|
+
this.sweeping = running;
|
|
362
|
+
}
|
|
363
|
+
/** Whether a fetch of one of `request`'s links is still sending, within its grace. */
|
|
364
|
+
sending(request, now) {
|
|
365
|
+
for (const key of request.pending) {
|
|
366
|
+
const claimedAt = this.artifacts.get(key)?.claimedAt;
|
|
367
|
+
if (claimedAt !== undefined && now - claimedAt < SEND_GRACE_MS)
|
|
368
|
+
return true;
|
|
369
|
+
}
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
/** Drop one artifact's link and bytes; the request goes with its last one. */
|
|
373
|
+
async forget(key) {
|
|
374
|
+
const record = this.artifacts.get(key);
|
|
375
|
+
if (!record)
|
|
376
|
+
return;
|
|
377
|
+
this.artifacts.delete(key);
|
|
378
|
+
const request = this.requests.get(record.requestId);
|
|
379
|
+
request?.pending.delete(key);
|
|
380
|
+
if (request && request.pending.size === 0) {
|
|
381
|
+
this.requests.delete(request.id);
|
|
382
|
+
await this.removeDir(request.id);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
await fs.rm(path.join(this.root, record.requestId, record.file), { force: true });
|
|
387
|
+
}
|
|
388
|
+
catch (err) {
|
|
389
|
+
log.warn(`could not delete a fetched download of "${record.requestId}":`, { err });
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
async dropRequest(request) {
|
|
393
|
+
for (const key of request.pending)
|
|
394
|
+
this.artifacts.delete(key);
|
|
395
|
+
this.requests.delete(request.id);
|
|
396
|
+
await this.removeDir(request.id);
|
|
397
|
+
}
|
|
398
|
+
async outlivedEveryLink(name, now) {
|
|
399
|
+
try {
|
|
400
|
+
const { mtimeMs } = await fs.stat(path.join(this.root, name));
|
|
401
|
+
return now - mtimeMs > this.ttlMs + SEND_GRACE_MS;
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/** Best-effort delete of one request's directory. Never throws. */
|
|
408
|
+
async removeDir(id) {
|
|
409
|
+
try {
|
|
410
|
+
await fs.rm(path.join(this.root, id), { recursive: true, force: true });
|
|
411
|
+
}
|
|
412
|
+
catch (err) {
|
|
413
|
+
log.warn(`could not delete the stored download "${id}":`, { err });
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
function refusal() {
|
|
418
|
+
return new DownloadTokenError(DOWNLOAD_TOKEN_REFUSAL, 404);
|
|
419
|
+
}
|
|
420
|
+
function hash(token) {
|
|
421
|
+
return createHash('sha256').update(token).digest('hex');
|
|
422
|
+
}
|
|
423
|
+
//# sourceMappingURL=agent-download.store.js.map
|