@bevel-software/platform-core-backend 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/core-ports.d.ts +11 -1
- 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 +3 -3
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +46 -13
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +12 -2
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +137 -24
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +46 -1
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +99 -13
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core-config.d.ts +16 -12
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +28 -13
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +42 -12
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +67 -10
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +214 -35
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +17 -16
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
- package/dist/modules/access/directory-sync-bot.js +7 -3
- package/dist/modules/access/directory-sync-bot.js.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +8 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.js +8 -2
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +38 -6
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +39 -6
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/index.d.ts +2 -1
- package/dist/modules/agent-instructions/index.d.ts.map +1 -1
- package/dist/modules/agent-instructions/index.js +2 -1
- package/dist/modules/agent-instructions/index.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +115 -0
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -0
- package/dist/modules/agent-instructions/shared-file-rules.js +272 -0
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
- package/dist/modules/audit/agent-audit.service.js +4 -2
- package/dist/modules/audit/agent-audit.service.js.map +1 -1
- package/dist/modules/auth/account-admission.d.ts +58 -7
- package/dist/modules/auth/account-admission.d.ts.map +1 -1
- package/dist/modules/auth/account-admission.js +44 -1
- package/dist/modules/auth/account-admission.js.map +1 -1
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
- package/dist/modules/auth/account-erasure.service.js +57 -16
- package/dist/modules/auth/account-erasure.service.js.map +1 -1
- package/dist/modules/auth/account.routes.d.ts +1 -1
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +61 -5
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.middleware.d.ts +1 -1
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
- package/dist/modules/auth/auth.middleware.js +18 -7
- package/dist/modules/auth/auth.middleware.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +8 -0
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +70 -2
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +197 -18
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +7 -2
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.d.ts +20 -2
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +66 -35
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/database/connection.d.ts +16 -0
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +117 -0
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +337 -120
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +116 -58
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/database/migrate.d.ts +8 -0
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +271 -1
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
- package/dist/modules/kb-fs/branch-name.js +12 -2
- package/dist/modules/kb-fs/branch-name.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +11 -16
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +79 -0
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.d.ts +2 -2
- package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.js +14 -3
- package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -1
- package/dist/modules/kb-sync/sync-auth.d.ts +3 -1
- package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -1
- package/dist/modules/kb-sync/sync-auth.js +1 -1
- package/dist/modules/kb-sync/sync-auth.js.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +21 -6
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +8 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +38 -8
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +3 -2
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -1
- package/dist/modules/plugins/join-request-records.store.js +7 -4
- package/dist/modules/plugins/join-request-records.store.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +8 -3
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/setup.routes.d.ts +52 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +207 -19
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +90 -18
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.contract.js +4 -1
- package/dist/modules/skills/skills.contract.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +98 -9
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +239 -37
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts +7 -0
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +71 -7
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +12 -4
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +3 -3
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +16 -7
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +34 -12
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts +2 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +25 -4
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +3 -2
- 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-helpers/validate-token.js +1 -1
- package/dist/modules/tool-helpers/validate-token.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +42 -31
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/description-length.d.ts +80 -0
- package/dist/modules/tool-registry/description-length.d.ts.map +1 -0
- package/dist/modules/tool-registry/description-length.js +108 -0
- package/dist/modules/tool-registry/description-length.js.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +98 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.js +81 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +75 -35
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/file-lock.service.d.ts +24 -0
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
- package/dist/modules/workflow/file-lock.service.js +30 -0
- package/dist/modules/workflow/file-lock.service.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +94 -0
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +193 -3
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts +38 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +60 -1
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
- package/dist/modules/workflow/recovery-bot.js +7 -3
- package/dist/modules/workflow/recovery-bot.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +12 -3
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/workflow-hooks.d.ts +54 -32
- package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -1
- package/dist/modules/workflow/workflow-hooks.js +16 -1
- package/dist/modules/workflow/workflow-hooks.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +60 -6
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +115 -5
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts +94 -0
- package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -0
- package/dist/modules/workspace/agent-access.gate.js +123 -0
- package/dist/modules/workspace/agent-access.gate.js.map +1 -0
- package/dist/modules/workspace/agent-upload.routes.d.ts +77 -0
- package/dist/modules/workspace/agent-upload.routes.d.ts.map +1 -0
- package/dist/modules/workspace/agent-upload.routes.js +210 -0
- package/dist/modules/workspace/agent-upload.routes.js.map +1 -0
- package/dist/modules/workspace/agent-upload.store.d.ts +284 -0
- package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -0
- package/dist/modules/workspace/agent-upload.store.js +553 -0
- package/dist/modules/workspace/agent-upload.store.js.map +1 -0
- package/dist/modules/workspace/routine-write-policy.d.ts +5 -6
- package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -1
- package/dist/modules/workspace/routine-write-policy.js +5 -6
- package/dist/modules/workspace/routine-write-policy.js.map +1 -1
- package/dist/modules/workspace/session-sink.d.ts +5 -5
- package/dist/modules/workspace/set-aside-clone.d.ts +46 -0
- package/dist/modules/workspace/set-aside-clone.d.ts.map +1 -0
- package/dist/modules/workspace/set-aside-clone.js +92 -0
- package/dist/modules/workspace/set-aside-clone.js.map +1 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +59 -9
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +65 -24
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +3 -3
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +40 -0
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +46 -4
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/upload-limits.d.ts +13 -0
- package/dist/modules/workspace/upload-limits.d.ts.map +1 -0
- package/dist/modules/workspace/upload-limits.js +13 -0
- package/dist/modules/workspace/upload-limits.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +93 -4
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +128 -5
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +316 -58
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +13 -11
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +791 -198
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +0 -6
- package/dist/modules/workspace/write-denial.d.ts.map +1 -1
- package/dist/modules/workspace/write-denial.js +0 -6
- package/dist/modules/workspace/write-denial.js.map +1 -1
- package/dist/modules/workspace/zip-entry-rules.d.ts +114 -0
- package/dist/modules/workspace/zip-entry-rules.d.ts.map +1 -0
- package/dist/modules/workspace/zip-entry-rules.js +154 -0
- package/dist/modules/workspace/zip-entry-rules.js.map +1 -0
- package/dist/modules/write-access/write-access.d.ts +60 -0
- package/dist/modules/write-access/write-access.d.ts.map +1 -0
- package/dist/modules/write-access/write-access.js +129 -0
- package/dist/modules/write-access/write-access.js.map +1 -0
- package/dist/shared/column-crypto.d.ts +194 -0
- package/dist/shared/column-crypto.d.ts.map +1 -0
- package/dist/shared/column-crypto.js +144 -0
- package/dist/shared/column-crypto.js.map +1 -0
- package/dist/shared/domain-errors.d.ts +25 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +28 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/git.contract.d.ts +20 -0
- package/dist/shared/git.contract.d.ts.map +1 -1
- package/dist/shared/git.contract.js +26 -0
- package/dist/shared/git.contract.js.map +1 -1
- package/dist/shared/token-crypto.d.ts.map +1 -1
- package/dist/shared/token-crypto.js +25 -1
- package/dist/shared/token-crypto.js.map +1 -1
- package/dist/tenancy/static-tenant-source.d.ts +0 -1
- package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
- package/dist/tenancy/static-tenant-source.js +1 -2
- package/dist/tenancy/static-tenant-source.js.map +1 -1
- package/dist/tenancy/tenant-secrets.d.ts +5 -1
- package/dist/tenancy/tenant-secrets.d.ts.map +1 -1
- package/dist/tenancy/tenant-secrets.js +4 -0
- package/dist/tenancy/tenant-secrets.js.map +1 -1
- package/kb-template/AGENTS.md +2 -0
- package/migrations/0014_change_request_closed_reason.sql +1 -0
- package/migrations/0015_account_deactivation.sql +3 -0
- package/migrations/0016_pii_encryption.sql +20 -0
- package/migrations/meta/0014_snapshot.json +2265 -0
- package/migrations/meta/0015_snapshot.json +2271 -0
- package/migrations/meta/0016_snapshot.json +2327 -0
- package/migrations/meta/_journal.json +21 -0
- package/package.json +3 -3
- package/src/__tests__/kb-layout-config.test.ts +0 -2
- package/src/__tests__/retired-settings.test.ts +96 -0
- package/src/core/__tests__/gated-boot.test.ts +132 -0
- package/src/core/__tests__/lifecycle.test.ts +241 -5
- package/src/core/__tests__/set-aside-root-is-one-place.test.ts +63 -0
- package/src/core/core-ports.ts +11 -1
- package/src/core/create-core-server.ts +52 -16
- package/src/core/create-core-services.ts +156 -24
- package/src/core/lifecycle.ts +117 -13
- package/src/core-config.ts +31 -14
- package/src/index.ts +30 -1
- package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +385 -0
- package/src/modules/access/__tests__/access-control.prospective.test.ts +94 -18
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +6 -7
- package/src/modules/access/__tests__/users-db-double.ts +21 -12
- package/src/modules/access/access-control.interface.ts +43 -12
- package/src/modules/access/access-control.service.ts +234 -36
- package/src/modules/access/access.routes.ts +17 -16
- package/src/modules/access/directory-sync-bot.ts +7 -3
- package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +11 -5
- package/src/modules/agent-instructions/__tests__/compose.test.ts +19 -10
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +238 -0
- package/src/modules/agent-instructions/agent-instructions.routes.ts +12 -2
- package/src/modules/agent-instructions/compose.ts +50 -7
- package/src/modules/agent-instructions/index.ts +12 -0
- package/src/modules/agent-instructions/shared-file-rules.ts +314 -0
- package/src/modules/audit/agent-audit.service.ts +4 -2
- package/src/modules/auth/__tests__/account-deactivation.test.ts +253 -0
- package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +6 -2
- package/src/modules/auth/__tests__/account.routes.test.ts +87 -6
- package/src/modules/auth/__tests__/auth.middleware.test.ts +45 -22
- package/src/modules/auth/__tests__/auth.service.test.ts +4 -2
- package/src/modules/auth/account-admission.ts +78 -9
- package/src/modules/auth/account-erasure.service.ts +69 -18
- package/src/modules/auth/account.routes.ts +63 -7
- package/src/modules/auth/auth.middleware.ts +19 -8
- package/src/modules/auth/auth.routes.ts +8 -0
- package/src/modules/auth/auth.service.ts +206 -23
- package/src/modules/auth/oidc-auth-provider.ts +7 -2
- package/src/modules/code-mode/__tests__/chain-runtime.e2e.test.ts +335 -0
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +46 -2
- package/src/modules/code-mode/code-mode.tool.ts +80 -34
- package/src/modules/database/__tests__/connection.test.ts +12 -0
- package/src/modules/database/__tests__/pii-backfill.pg.test.ts +561 -0
- package/src/modules/database/connection.ts +117 -0
- package/src/modules/database/core-schema.ts +116 -58
- package/src/modules/database/migrate.ts +353 -1
- package/src/modules/kb-fs/__tests__/branch-name.test.ts +10 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +123 -0
- package/src/modules/kb-fs/branch-name.ts +14 -1
- package/src/modules/kb-fs/repo-path.ts +85 -0
- package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +26 -1
- package/src/modules/kb-sync/kb-sync.routes.ts +14 -4
- package/src/modules/kb-sync/sync-auth.ts +2 -2
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +60 -3
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +4 -3
- package/src/modules/mcp/__tests__/mcp.service.test.ts +115 -13
- package/src/modules/mcp/mcp-auth.middleware.ts +20 -6
- package/src/modules/mcp/mcp.service.ts +46 -7
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +3 -1
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +2 -1
- package/src/modules/plugins/join-request-records.store.ts +7 -4
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +16 -0
- package/src/modules/settings/__tests__/setup.routes.git-mode.test.ts +91 -58
- package/src/modules/settings/__tests__/setup.routes.github-app.test.ts +25 -8
- package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +14 -11
- package/src/modules/settings/__tests__/setup.routes.repository-change.test.ts +390 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +3 -0
- package/src/modules/settings/deployment-settings.service.ts +8 -3
- package/src/modules/settings/setup.routes.ts +263 -19
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +2 -1
- package/src/modules/skills/__tests__/branch-skills.tools.test.ts +218 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +229 -5
- package/src/modules/skills/skills.contract.ts +91 -18
- package/src/modules/skills/skills.service.ts +278 -41
- package/src/modules/skills/skills.tools.ts +80 -8
- package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +14 -1
- package/src/modules/tool-auth/external-api-key.service.ts +12 -4
- package/src/modules/tool-auth/internal-token.service.ts +3 -3
- package/src/modules/tool-auth/tool-auth.middleware.ts +34 -11
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +5 -3
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -3
- package/src/modules/tool-helpers/__tests__/validate-token.test.ts +11 -1
- package/src/modules/tool-helpers/tool-handler.ts +24 -4
- package/src/modules/tool-helpers/tool.contract.ts +3 -2
- package/src/modules/tool-helpers/validate-token.ts +1 -1
- package/src/modules/tool-manuals/tool-manuals.tools.ts +44 -31
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +378 -0
- package/src/modules/tool-registry/description-length.ts +111 -0
- package/src/modules/workflow/__tests__/pending-commits.repository-replaced.test.ts +111 -0
- package/src/modules/workflow/__tests__/workflow.routes.history-read-gate.test.ts +25 -0
- package/src/modules/workflow/__tests__/workflow.service.repository-replaced.test.ts +249 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +264 -6
- package/src/modules/workflow/agent-tools/change-request-summary.ts +182 -0
- package/src/modules/workflow/agent-tools/workflow.tools.ts +86 -35
- package/src/modules/workflow/file-lock.service.ts +31 -0
- package/src/modules/workflow/git/__tests__/git.service.fileBytesAtCommit.test.ts +260 -0
- package/src/modules/workflow/git/__tests__/git.service.prFetchFailure.test.ts +170 -0
- package/src/modules/workflow/git/git.service.ts +215 -1
- package/src/modules/workflow/pending-commits.service.ts +64 -2
- package/src/modules/workflow/recovery-bot.ts +7 -3
- package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +4 -0
- package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +25 -3
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +12 -3
- package/src/modules/workflow/workflow-hooks.ts +64 -26
- package/src/modules/workflow/workflow.service.ts +125 -5
- package/src/modules/workspace/__tests__/agent-access.gate.test.ts +208 -0
- package/src/modules/workspace/__tests__/agent-uploads.test.ts +1604 -0
- package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +394 -0
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +2 -1
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -1
- package/src/modules/workspace/__tests__/set-aside-clone.test.ts +52 -0
- package/src/modules/workspace/__tests__/workspace.routes.at-ref.test.ts +305 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -0
- package/src/modules/workspace/__tests__/workspace.service.any-workspace-credentials.test.ts +156 -0
- package/src/modules/workspace/__tests__/workspace.service.forget-clone-races.test.ts +147 -0
- package/src/modules/workspace/__tests__/workspace.service.replaced-repository.test.ts +402 -0
- package/src/modules/workspace/__tests__/workspace.service.test.ts +77 -9
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +41 -39
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +2 -3
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +766 -56
- package/src/modules/workspace/agent-access.gate.ts +164 -0
- package/src/modules/workspace/agent-upload.routes.ts +214 -0
- package/src/modules/workspace/agent-upload.store.ts +668 -0
- package/src/modules/workspace/routine-write-policy.ts +5 -6
- package/src/modules/workspace/session-sink.ts +5 -5
- package/src/modules/workspace/set-aside-clone.ts +96 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +86 -0
- package/src/modules/workspace/startup/kb-startup-runner.ts +115 -34
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +9 -9
- package/src/modules/workspace/startup/steps/seed-tree.ts +3 -6
- package/src/modules/workspace/startup/steps/template-source.ts +53 -5
- package/src/modules/workspace/upload-limits.ts +12 -0
- package/src/modules/workspace/workspace.routes.ts +96 -5
- package/src/modules/workspace/workspace.service.ts +319 -61
- package/src/modules/workspace/workspace.tools.ts +894 -214
- package/src/modules/workspace/write-denial.ts +0 -8
- package/src/modules/workspace/zip-entry-rules.ts +173 -0
- package/src/modules/write-access/__tests__/write-access.test.ts +248 -0
- package/src/modules/write-access/write-access.ts +153 -0
- package/src/shared/__tests__/column-crypto.test.ts +217 -0
- package/src/shared/column-crypto.ts +218 -0
- package/src/shared/domain-errors.ts +31 -0
- package/src/shared/git.contract.ts +27 -0
- package/src/shared/token-crypto.ts +28 -1
- package/src/tenancy/__tests__/static-tenant-source.test.ts +4 -1
- package/src/tenancy/static-tenant-source.ts +1 -3
- package/src/tenancy/tenant-secrets.ts +5 -1
- package/dist/modules/workflow/session-ontology.policy.d.ts +0 -52
- package/dist/modules/workflow/session-ontology.policy.d.ts.map +0 -1
- package/dist/modules/workflow/session-ontology.policy.js +0 -62
- package/dist/modules/workflow/session-ontology.policy.js.map +0 -1
- package/dist/modules/workflow/session-ontology.service.d.ts +0 -105
- package/dist/modules/workflow/session-ontology.service.d.ts.map +0 -1
- package/dist/modules/workflow/session-ontology.service.js +0 -147
- package/dist/modules/workflow/session-ontology.service.js.map +0 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts +0 -114
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +0 -1
- package/dist/modules/workspace/session-ontology.gate.js +0 -161
- package/dist/modules/workspace/session-ontology.gate.js.map +0 -1
- package/dist/shared/kb-layout.d.ts +0 -39
- package/dist/shared/kb-layout.d.ts.map +0 -1
- package/dist/shared/kb-layout.js +0 -103
- package/dist/shared/kb-layout.js.map +0 -1
- package/dist/shared/kb-layout.test.d.ts +0 -2
- package/dist/shared/kb-layout.test.d.ts.map +0 -1
- package/dist/shared/kb-layout.test.js +0 -75
- package/dist/shared/kb-layout.test.js.map +0 -1
- package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +0 -62
- package/src/modules/workflow/__tests__/session-ontology.service.test.ts +0 -201
- package/src/modules/workflow/session-ontology.policy.ts +0 -70
- package/src/modules/workflow/session-ontology.service.ts +0 -183
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +0 -239
- package/src/modules/workspace/session-ontology.gate.ts +0 -191
- package/src/shared/kb-layout.test.ts +0 -98
- package/src/shared/kb-layout.ts +0 -102
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { describe, test, expect, beforeEach, afterEach } from 'vitest';
|
|
2
2
|
import { NodeFs } from '../../kb-fs/node-fs.js';
|
|
3
|
-
import { mkdtemp, rm, mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { mkdtemp, rm, mkdir, writeFile, cp } from 'node:fs/promises';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { DEFAULT_BRANCH } from '@bevel-software/platform-shared';
|
|
7
|
-
import { SkillService } from '../skills.service.js';
|
|
7
|
+
import { SkillService, unmergedSkillNotice } from '../skills.service.js';
|
|
8
|
+
import { BranchNotFoundError } from '../../../shared/domain-errors.js';
|
|
8
9
|
import { workspaceIdForBranch } from '../../../shared/workspace-id.js';
|
|
9
10
|
import type { WorkspaceService } from '../../workspace/workspace.service.js';
|
|
10
11
|
import type { IAccessControl } from '../../access/access-control.interface.js';
|
|
@@ -38,11 +39,20 @@ You answer RFIs.
|
|
|
38
39
|
|
|
39
40
|
describe('SkillService', () => {
|
|
40
41
|
let root: string;
|
|
42
|
+
/**
|
|
43
|
+
* The branches that have a clone under `root`. A name that is not in here
|
|
44
|
+
* answers the way the real service does for a branch nobody ever pushed: the
|
|
45
|
+
* 404 the file tools answer, not an empty workspace.
|
|
46
|
+
*/
|
|
47
|
+
let clones: Set<string>;
|
|
41
48
|
|
|
42
|
-
// WorkspaceService stub:
|
|
43
|
-
// KB clone at <root>/<
|
|
49
|
+
// WorkspaceService stub: a branch's workspace lives at <root>/<branch's id>,
|
|
50
|
+
// its KB clone at <root>/<id>/<KB_DIR>.
|
|
44
51
|
const workspaceService = {
|
|
45
|
-
getOrCreateForBranch: async () =>
|
|
52
|
+
getOrCreateForBranch: async (branch: string) => {
|
|
53
|
+
if (!clones.has(branch)) throw new BranchNotFoundError(branch);
|
|
54
|
+
return { id: workspaceIdForBranch(branch) };
|
|
55
|
+
},
|
|
46
56
|
getWorkspacePath: async (id: string) => join(root, id),
|
|
47
57
|
readFile: async (id: string, rel: string) => fsReadFile(join(root, id, rel), 'utf-8'),
|
|
48
58
|
} as unknown as WorkspaceService;
|
|
@@ -58,6 +68,7 @@ describe('SkillService', () => {
|
|
|
58
68
|
|
|
59
69
|
beforeEach(async () => {
|
|
60
70
|
root = await mkdtemp(join(tmpdir(), 'skills-'));
|
|
71
|
+
clones = new Set([DEFAULT_BRANCH]);
|
|
61
72
|
const skills = join(root, wsId, KB_DIR, 'Plugins');
|
|
62
73
|
await mkdir(join(skills, 'rfi', 'scripts'), { recursive: true });
|
|
63
74
|
await writeFile(join(skills, 'rfi', 'SKILL.md'), RFI_SKILL);
|
|
@@ -480,4 +491,217 @@ describe('SkillService', () => {
|
|
|
480
491
|
});
|
|
481
492
|
});
|
|
482
493
|
});
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Reading a DRAFT branch: what an agent needs to try the skill it has just
|
|
497
|
+
* written, with the answer saying plainly that nobody approved it.
|
|
498
|
+
*
|
|
499
|
+
* The draft starts as a copy of the released tree — which is what a clone of
|
|
500
|
+
* a branch with no skill changes on it is — and each test changes it.
|
|
501
|
+
*/
|
|
502
|
+
describe('reading a branch', () => {
|
|
503
|
+
const DRAFT = 'juan/skill-deck';
|
|
504
|
+
const draftWsId = workspaceIdForBranch(DRAFT);
|
|
505
|
+
const user = 'user@x.eu';
|
|
506
|
+
const draftKb = () => join(root, draftWsId, KB_DIR);
|
|
507
|
+
const named = async (service = svc()) =>
|
|
508
|
+
Object.fromEntries((await service.listSkills(user, { branch: DRAFT })).map((s) => [s.name, s]));
|
|
509
|
+
|
|
510
|
+
const writeDeck = (body = '# Deck\n') =>
|
|
511
|
+
mkdir(join(draftKb(), 'Plugins', 'make-deck'), { recursive: true }).then(() =>
|
|
512
|
+
writeFile(join(draftKb(), 'Plugins', 'make-deck', 'SKILL.md'), `---\ndescription: Decks.\n---\n\n${body}`),
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
beforeEach(async () => {
|
|
516
|
+
await cp(join(root, wsId), join(root, draftWsId), { recursive: true });
|
|
517
|
+
clones.add(DRAFT);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
test('a skill that exists only on the branch is listed as unmerged; the released ones are not marked', async () => {
|
|
521
|
+
await writeDeck();
|
|
522
|
+
const list = await named();
|
|
523
|
+
expect(Object.keys(list).sort()).toEqual(['coding-guidelines', 'make-deck', 'rfi']);
|
|
524
|
+
expect(list['make-deck']).toMatchObject({ unmerged: true, branch: DRAFT, description: 'Decks.' });
|
|
525
|
+
// The skills the branch shares with the default branch are the released
|
|
526
|
+
// ones, read through a draft's clone: nothing about them is unapproved.
|
|
527
|
+
expect(list['rfi'].unmerged).toBeUndefined();
|
|
528
|
+
expect(list['rfi'].branch).toBeUndefined();
|
|
529
|
+
expect(list['coding-guidelines'].unmerged).toBeUndefined();
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
test('without a branch the draft-only skill is absent, and nothing carries a mark', async () => {
|
|
533
|
+
await writeDeck();
|
|
534
|
+
const list = await svc().listSkills(user);
|
|
535
|
+
expect(list.map((s) => s.name)).toEqual(['coding-guidelines', 'rfi']);
|
|
536
|
+
expect(list.some((s) => s.unmerged !== undefined || s.branch !== undefined)).toBe(false);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
test('get_skill loads the draft-only skill, body starting with the unmerged line', async () => {
|
|
540
|
+
await writeDeck();
|
|
541
|
+
const res = await svc().getSkill(user, 'make-deck', undefined, { branch: DRAFT });
|
|
542
|
+
expect(res.ok && res.kind === 'skill').toBe(true);
|
|
543
|
+
if (!res.ok || res.kind !== 'skill') return;
|
|
544
|
+
expect(res.skill.body.split('\n')[0]).toBe(
|
|
545
|
+
`This skill is read from the unmerged branch "${DRAFT}" and is not approved.`,
|
|
546
|
+
);
|
|
547
|
+
expect(res.skill.body.split('\n')[0]).toBe(unmergedSkillNotice(DRAFT));
|
|
548
|
+
expect(res.skill.body).toContain('# Deck');
|
|
549
|
+
expect(res.skill).toMatchObject({ unmerged: true, branch: DRAFT, path: 'Plugins/make-deck' });
|
|
550
|
+
// Without the branch there is no such skill at all.
|
|
551
|
+
expect(await svc().getSkill(user, 'make-deck')).toEqual({ ok: false, error: 'not_found' });
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test('a skill changed on the branch loads changed there and released without the branch', async () => {
|
|
555
|
+
await writeFile(
|
|
556
|
+
join(draftKb(), 'Plugins', 'rfi', 'SKILL.md'),
|
|
557
|
+
RFI_SKILL.replace('You answer RFIs.', 'You answer RFIs, in three paragraphs.'),
|
|
558
|
+
);
|
|
559
|
+
const service = svc();
|
|
560
|
+
const draft = await service.getSkill(user, 'rfi', undefined, { branch: DRAFT });
|
|
561
|
+
expect(draft.ok && draft.kind === 'skill' && draft.skill.body).toContain('in three paragraphs');
|
|
562
|
+
expect(draft.ok && draft.kind === 'skill' && draft.skill.body.split('\n')[0]).toBe(unmergedSkillNotice(DRAFT));
|
|
563
|
+
expect(draft.ok && draft.kind === 'skill' && draft.skill.unmerged).toBe(true);
|
|
564
|
+
expect((await named(service))['rfi']).toMatchObject({ unmerged: true, branch: DRAFT });
|
|
565
|
+
|
|
566
|
+
const released = await service.getSkill(user, 'rfi');
|
|
567
|
+
expect(released.ok && released.kind === 'skill' && released.skill.body).not.toContain('three paragraphs');
|
|
568
|
+
expect(released.ok && released.kind === 'skill' && released.skill.body).not.toContain('unmerged');
|
|
569
|
+
expect(released.ok && released.kind === 'skill' && released.skill.unmerged).toBeUndefined();
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test('a skill unchanged on the branch carries no mark and no line — it is the released answer', async () => {
|
|
573
|
+
const service = svc();
|
|
574
|
+
expect(await service.getSkill(user, 'rfi', undefined, { branch: DRAFT })).toEqual(
|
|
575
|
+
await service.getSkill(user, 'rfi'),
|
|
576
|
+
);
|
|
577
|
+
expect(await service.getSkill(user, 'rfi', 'scripts/build_xlsx.py', { branch: DRAFT })).toEqual(
|
|
578
|
+
await service.getSkill(user, 'rfi', 'scripts/build_xlsx.py'),
|
|
579
|
+
);
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
test('a bundled file changed on the branch makes the skill unmerged, and rides beside its content', async () => {
|
|
583
|
+
// The SKILL.md is byte-identical: the difference is in the folder.
|
|
584
|
+
await writeFile(join(draftKb(), 'Plugins', 'rfi', 'scripts', 'build_xlsx.py'), 'print("xlsx v2")\n');
|
|
585
|
+
expect((await named())['rfi']).toMatchObject({ unmerged: true, branch: DRAFT });
|
|
586
|
+
const file = await svc().getSkill(user, 'rfi', 'scripts/build_xlsx.py', { branch: DRAFT });
|
|
587
|
+
expect(file).toEqual({
|
|
588
|
+
ok: true,
|
|
589
|
+
kind: 'file',
|
|
590
|
+
file: {
|
|
591
|
+
name: 'rfi',
|
|
592
|
+
file: 'scripts/build_xlsx.py',
|
|
593
|
+
path: 'Plugins/rfi/scripts/build_xlsx.py',
|
|
594
|
+
// The notice never goes INSIDE a script.
|
|
595
|
+
content: 'print("xlsx v2")\n',
|
|
596
|
+
unmerged: true,
|
|
597
|
+
branch: DRAFT,
|
|
598
|
+
},
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
test('an asset added on the branch is a difference too', async () => {
|
|
603
|
+
await writeFile(join(draftKb(), 'Plugins', 'rfi', 'scripts', 'extra.py'), 'print("new")\n');
|
|
604
|
+
expect((await named())['rfi']).toMatchObject({ unmerged: true, branch: DRAFT });
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
test('a skill deleted on the branch is absent there and still released without it', async () => {
|
|
608
|
+
await rm(join(draftKb(), 'Plugins', 'rfi'), { recursive: true });
|
|
609
|
+
const service = svc();
|
|
610
|
+
expect(Object.keys(await named(service))).toEqual(['coding-guidelines']);
|
|
611
|
+
expect(await service.getSkill(user, 'rfi', undefined, { branch: DRAFT })).toEqual({
|
|
612
|
+
ok: false,
|
|
613
|
+
error: 'not_found',
|
|
614
|
+
});
|
|
615
|
+
expect((await service.listSkills(user)).map((s) => s.name)).toContain('rfi');
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
test("access is judged on the branch, with that branch's rules", async () => {
|
|
619
|
+
// The same caller, the same skill: readable on the default branch,
|
|
620
|
+
// denied in the draft's own workspace.
|
|
621
|
+
const perBranch: IAccessControl = {
|
|
622
|
+
canRead: async () => true,
|
|
623
|
+
canReadBatch: async (w: string, _e: string, paths: string[]) =>
|
|
624
|
+
new Map(paths.map((p) => [p, !(w === draftWsId && p.includes('/rfi/'))])),
|
|
625
|
+
} as unknown as IAccessControl;
|
|
626
|
+
const service = svc(perBranch);
|
|
627
|
+
expect(Object.keys(await named(service))).toEqual(['coding-guidelines']);
|
|
628
|
+
// Not `forbidden`: a draft skill the caller may not read there is one
|
|
629
|
+
// they must not learn exists.
|
|
630
|
+
expect(await service.getSkill(user, 'rfi', undefined, { branch: DRAFT })).toEqual({
|
|
631
|
+
ok: false,
|
|
632
|
+
error: 'not_found',
|
|
633
|
+
});
|
|
634
|
+
expect(await service.getSkill(user, 'rfi', 'scripts/build_xlsx.py', { branch: DRAFT })).toEqual({
|
|
635
|
+
ok: false,
|
|
636
|
+
error: 'not_found',
|
|
637
|
+
});
|
|
638
|
+
// The released answer is untouched by the draft's rules.
|
|
639
|
+
expect((await service.listSkills(user)).map((s) => s.name)).toContain('rfi');
|
|
640
|
+
expect((await service.getSkill(user, 'rfi')).ok).toBe(true);
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
test('a branch that does not exist is a 404 naming it, as on the file tools', async () => {
|
|
644
|
+
const service = svc();
|
|
645
|
+
await expect(service.listSkills(user, { branch: 'juan/typo' })).rejects.toMatchObject({
|
|
646
|
+
status: 404,
|
|
647
|
+
kind: 'branch-not-found',
|
|
648
|
+
branch: 'juan/typo',
|
|
649
|
+
message: 'There is no branch named juan/typo.',
|
|
650
|
+
});
|
|
651
|
+
await expect(service.getSkill(user, 'rfi', undefined, { branch: 'juan/typo' })).rejects.toMatchObject({
|
|
652
|
+
status: 404,
|
|
653
|
+
kind: 'branch-not-found',
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
test('naming the default branch answers exactly as naming nothing', async () => {
|
|
658
|
+
await writeDeck();
|
|
659
|
+
const service = svc();
|
|
660
|
+
expect(await service.listSkills(user, { branch: DEFAULT_BRANCH })).toEqual(await service.listSkills(user));
|
|
661
|
+
expect(await service.getSkill(user, 'rfi', undefined, { branch: DEFAULT_BRANCH })).toEqual(
|
|
662
|
+
await service.getSkill(user, 'rfi'),
|
|
663
|
+
);
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
test('a branch read is never cached: the next call sees what the agent just wrote', async () => {
|
|
667
|
+
const service = svc();
|
|
668
|
+
expect(Object.keys(await named(service))).not.toContain('make-deck');
|
|
669
|
+
await writeDeck();
|
|
670
|
+
// Same instance, no `invalidate()`: the released catalog is cached, a
|
|
671
|
+
// draft is not.
|
|
672
|
+
expect(Object.keys(await named(service))).toContain('make-deck');
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
// The `unmerged` verdict compares two folder digests, and the released
|
|
676
|
+
// side of that comparison is memoized per cached catalog (it used to be
|
|
677
|
+
// re-hashed once per skill per call). These two pin what the memo may and
|
|
678
|
+
// may not do.
|
|
679
|
+
test('the memo never makes a draft stale: an edit on the branch is seen on the next call', async () => {
|
|
680
|
+
const service = svc();
|
|
681
|
+
expect((await named(service))['rfi'].unmerged).toBeUndefined();
|
|
682
|
+
await writeFile(join(draftKb(), 'Plugins', 'rfi', 'scripts', 'build_xlsx.py'), 'print("on the branch")\n');
|
|
683
|
+
// Same instance, no `invalidate()`: the draft's digests are built per
|
|
684
|
+
// call along with its catalog, so the agent's own last write shows.
|
|
685
|
+
expect((await named(service))['rfi']).toMatchObject({ unmerged: true, branch: DRAFT });
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
test('the released digests live and die with the released catalog', async () => {
|
|
689
|
+
const service = svc();
|
|
690
|
+
expect((await named(service))['rfi'].unmerged).toBeUndefined();
|
|
691
|
+
// An asset of the RELEASED copy changes. The catalog caches the file
|
|
692
|
+
// list, not the contents, so this is visible to a digest the moment one
|
|
693
|
+
// is taken — and the memo holds the pre-change one for the same TTL the
|
|
694
|
+
// rest of the released answer is held for.
|
|
695
|
+
await writeFile(join(root, wsId, KB_DIR, 'Plugins', 'rfi', 'scripts', 'build_xlsx.py'), 'print("released")\n');
|
|
696
|
+
expect((await named(service))['rfi'].unmerged).toBeUndefined();
|
|
697
|
+
service.invalidate();
|
|
698
|
+
expect((await named(service))['rfi']).toMatchObject({ unmerged: true, branch: DRAFT });
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
test('the global set (no caller) can be read from a branch too', async () => {
|
|
702
|
+
await writeDeck();
|
|
703
|
+
const list = await svc().listSkills(undefined, { branch: DRAFT });
|
|
704
|
+
expect(list.find((s) => s.name === 'make-deck')).toMatchObject({ unmerged: true, branch: DRAFT });
|
|
705
|
+
});
|
|
706
|
+
});
|
|
483
707
|
});
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Skills are reusable specialist instructions living under `Plugins/<plugin>/<name>/SKILL.md`
|
|
3
3
|
* in the KB repo. Discovery/loading is pinned to the DEFAULT branch — the catalog
|
|
4
4
|
* is a single global, released set (a skill on a draft isn't discoverable until
|
|
5
|
-
* merged)
|
|
5
|
+
* merged) — UNLESS the caller names a branch, which reads the skills as they are
|
|
6
|
+
* on that draft and marks the ones the default branch does not have yet (see
|
|
7
|
+
* {@link ListSkillsOptions} and `unmerged` below). Progressive disclosure:
|
|
8
|
+
* `listSkills` = name + description (level 1),
|
|
6
9
|
* `getSkill` = full body + bundled-file paths (level 2), `getSkill(file)` = a
|
|
7
10
|
* bundled file's content (level 3).
|
|
8
11
|
*/
|
|
@@ -38,6 +41,17 @@ export interface SkillSummary {
|
|
|
38
41
|
* surfaces, which load skills by name and never by plugin.
|
|
39
42
|
*/
|
|
40
43
|
plugins?: PluginMembership[];
|
|
44
|
+
/**
|
|
45
|
+
* Set only on an answer read from a branch OTHER than the default, and only
|
|
46
|
+
* on a skill whose folder DIFFERS there: it exists only on that branch, or
|
|
47
|
+
* its content was changed on it. Nobody has approved what such a skill says
|
|
48
|
+
* — it is not merged. A skill the branch shares byte-for-byte with the
|
|
49
|
+
* default branch carries no mark, because there is nothing unapproved about
|
|
50
|
+
* it.
|
|
51
|
+
*/
|
|
52
|
+
unmerged?: true;
|
|
53
|
+
/** With `unmerged`: the branch the skill was read from. */
|
|
54
|
+
branch?: string;
|
|
41
55
|
}
|
|
42
56
|
|
|
43
57
|
export interface Skill extends SkillSummary {
|
|
@@ -57,6 +71,15 @@ export interface SkillFileContent {
|
|
|
57
71
|
/** Repo-root-relative path of the file. */
|
|
58
72
|
path: string;
|
|
59
73
|
content: string;
|
|
74
|
+
/**
|
|
75
|
+
* As on {@link SkillSummary} — the file came off a branch whose copy of this
|
|
76
|
+
* skill differs from the default branch's. A note BESIDE the content, never
|
|
77
|
+
* inside it: a bundled file is a script or a data file, and a sentence
|
|
78
|
+
* prepended to one is a syntax error rather than a warning. A skill's body,
|
|
79
|
+
* which is prose an agent reads, carries the line instead.
|
|
80
|
+
*/
|
|
81
|
+
unmerged?: true;
|
|
82
|
+
branch?: string;
|
|
60
83
|
}
|
|
61
84
|
|
|
62
85
|
export type GetSkillResult =
|
|
@@ -64,32 +87,76 @@ export type GetSkillResult =
|
|
|
64
87
|
| { ok: true; kind: 'file'; file: SkillFileContent }
|
|
65
88
|
| { ok: false; error: 'not_found' | 'forbidden' | 'invalid_file' }
|
|
66
89
|
/**
|
|
67
|
-
* A `version` was asked for that no commit of the skill's `SKILL.md`
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
90
|
+
* A `version` was asked for that no commit of the skill's `SKILL.md`
|
|
91
|
+
* declared in the history searched — the default branch's, or `branch`'s own
|
|
92
|
+
* when a branch was named. `versions` is every version that history did
|
|
93
|
+
* declare, newest first, so it too is that branch's answer: the caller picks
|
|
94
|
+
* from those or asks for the latest by leaving `version` out.
|
|
71
95
|
*/
|
|
72
96
|
| { ok: false; error: 'version_not_found'; versions: string[] };
|
|
73
97
|
|
|
98
|
+
/**
|
|
99
|
+
* What `listSkills` may be asked beyond a caller.
|
|
100
|
+
*
|
|
101
|
+
* The branch is the ONE thing that moves the catalog off the default branch.
|
|
102
|
+
* Omitted (or naming the default branch itself), every answer is exactly the
|
|
103
|
+
* released one — the browser menu and the MCP prompts take that path and are
|
|
104
|
+
* unaffected by this option existing.
|
|
105
|
+
*/
|
|
106
|
+
export interface ListSkillsOptions {
|
|
107
|
+
/**
|
|
108
|
+
* Read the skills as they are on this branch instead of the default one: a
|
|
109
|
+
* skill that exists only there is listed, one changed there is listed with
|
|
110
|
+
* its changed description and version, one deleted there is absent. Access
|
|
111
|
+
* is judged on THAT branch, with that branch's access rules. A branch the
|
|
112
|
+
* platform has never heard of is a 404 naming it, as on the file tools.
|
|
113
|
+
*
|
|
114
|
+
* Everything listed from a non-default branch that differs from the default
|
|
115
|
+
* carries `unmerged: true` and this branch name: nobody approved it.
|
|
116
|
+
*/
|
|
117
|
+
branch?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
74
120
|
/** What `getSkill` may be asked beyond a name and a file. */
|
|
75
121
|
export interface GetSkillOptions {
|
|
76
122
|
/**
|
|
77
123
|
* The version the skill declared in the copy to load — its
|
|
78
124
|
* `metadata.version`, else a top-level `version`, else `lifecycle.version`.
|
|
79
125
|
* Omitted, the skill is loaded as it is now — the latest. Given, the
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
126
|
+
* history of the skill's `SKILL.md` is searched newest first for the most
|
|
127
|
+
* recent commit that declared exactly this version, and the skill (body,
|
|
128
|
+
* bundled files, or the one `file` asked for) is served as it was at that
|
|
129
|
+
* commit. Read access is the caller's access to the skill as it is now: a
|
|
130
|
+
* skill you may read, you may read the history of.
|
|
131
|
+
*
|
|
132
|
+
* The history searched is the one belonging to the branch being read: the
|
|
133
|
+
* default branch's, or — with `branch` — that branch's own, including the
|
|
134
|
+
* `versions` a `version_not_found` lists.
|
|
85
135
|
*/
|
|
86
136
|
version?: string;
|
|
137
|
+
/**
|
|
138
|
+
* Load the skill as it is on this branch instead of the default one — see
|
|
139
|
+
* {@link ListSkillsOptions.branch}, which it mirrors exactly: same branch
|
|
140
|
+
* resolution, same 404, same access rules read on that branch. When the
|
|
141
|
+
* skill differs from the default branch's copy, the body returned BEGINS
|
|
142
|
+
* with one line saying so (a bundled file carries `unmerged` beside its
|
|
143
|
+
* content instead).
|
|
144
|
+
*
|
|
145
|
+
* With `version`, the history searched is that branch's own. The agent
|
|
146
|
+
* tools refuse the two together rather than make a caller reason about which
|
|
147
|
+
* branch a version came from; this service answers both, because the
|
|
148
|
+
* combination has exactly one sensible meaning.
|
|
149
|
+
*/
|
|
150
|
+
branch?: string;
|
|
87
151
|
}
|
|
88
152
|
|
|
89
153
|
/**
|
|
90
|
-
* The slice of git the skill service reads history through
|
|
91
|
-
*
|
|
92
|
-
*
|
|
154
|
+
* The slice of git the skill service reads history through. Every call names
|
|
155
|
+
* the workspace to read in, which is always the clone the skill itself was
|
|
156
|
+
* scanned out of — the default branch's, or the draft a `branch` named, so a
|
|
157
|
+
* version asked for on a branch is answered from that branch's history.
|
|
158
|
+
* Narrow on purpose: the catalog is a disk scan and needs none of this; only
|
|
159
|
+
* a `version` asks for history.
|
|
93
160
|
*/
|
|
94
161
|
export interface SkillHistorySource {
|
|
95
162
|
/** The commits (newest first) on `ref` that touched `repoRelativePath`, at most `limit`. */
|
|
@@ -133,17 +200,23 @@ export interface IPendingSkillService {
|
|
|
133
200
|
|
|
134
201
|
export interface ISkillService {
|
|
135
202
|
/**
|
|
136
|
-
* The default-branch skill catalog
|
|
137
|
-
*
|
|
138
|
-
*
|
|
203
|
+
* The default-branch skill catalog — or `options.branch`'s, when one is
|
|
204
|
+
* named. When `userEmail` is given, filtered to skills that user may read
|
|
205
|
+
* (`canRead`, judged on the branch being read); omit it for the global set
|
|
206
|
+
* (used to compose the tool descriptions in the manual, which always
|
|
207
|
+
* describe the default branch).
|
|
139
208
|
*/
|
|
140
|
-
listSkills(userEmail?: string): Promise<SkillSummary[]>;
|
|
209
|
+
listSkills(userEmail?: string, options?: ListSkillsOptions): Promise<SkillSummary[]>;
|
|
141
210
|
/**
|
|
142
211
|
* Load a skill's body (+ files), or a bundled file's content when `file` is
|
|
143
212
|
* given — as it is now, or as it was at the commit that declared
|
|
144
213
|
* `options.version` (see {@link GetSkillOptions}).
|
|
145
214
|
*/
|
|
146
215
|
getSkill(userEmail: string, name: string, file?: string, options?: GetSkillOptions): Promise<GetSkillResult>;
|
|
147
|
-
/**
|
|
216
|
+
/**
|
|
217
|
+
* Drop the cached DEFAULT-branch catalog (call after a merge to it). A
|
|
218
|
+
* branch read is never cached, so an agent that writes a skill on its draft
|
|
219
|
+
* and lists it right after sees what it just wrote.
|
|
220
|
+
*/
|
|
148
221
|
invalidate(): void;
|
|
149
222
|
}
|