@bevel-software/platform-core-backend 0.33.0 → 0.35.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 +146 -289
- package/agent-guide/conventions.md +23 -25
- package/agent-guide/directory-structure.md +72 -120
- package/agent-guide/drafts-and-change-requests.md +92 -0
- package/agent-guide/for-git-users.md +47 -0
- package/agent-guide/glossary.md +36 -0
- package/agent-guide/how-agents-find-things.md +49 -0
- package/agent-guide/html-views.md +239 -8
- package/agent-guide/new-knowledge-base.md +9 -8
- package/agent-guide/skills.md +67 -42
- package/agent-guide/start-here.md +65 -0
- package/agent-guide/tool-manuals.md +133 -155
- package/agent-guide/tools.md +67 -0
- package/agent-guide/where-a-new-file-goes.md +45 -28
- package/dist/core/catalog-revision.d.ts +12 -1
- package/dist/core/catalog-revision.d.ts.map +1 -1
- package/dist/core/catalog-revision.js +23 -3
- package/dist/core/catalog-revision.js.map +1 -1
- package/dist/core/core-ports.d.ts +41 -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.map +1 -1
- package/dist/core/create-core-server.js +15 -8
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +22 -5
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +44 -16
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +16 -0
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +12 -2
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +39 -9
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +15 -3
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +239 -75
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-mutation.service.d.ts +22 -24
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
- package/dist/modules/access/access-mutation.service.js +48 -51
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-view.d.ts.map +1 -1
- package/dist/modules/access/access-view.js +12 -11
- package/dist/modules/access/access-view.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts +3 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +58 -33
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/groups-admin.routes.d.ts.map +1 -1
- package/dist/modules/access/groups-admin.routes.js +4 -2
- package/dist/modules/access/groups-admin.routes.js.map +1 -1
- package/dist/modules/access/groups-admin.service.d.ts +44 -13
- package/dist/modules/access/groups-admin.service.d.ts.map +1 -1
- package/dist/modules/access/groups-admin.service.js +80 -38
- package/dist/modules/access/groups-admin.service.js.map +1 -1
- package/dist/modules/access/groups-edit.d.ts +1 -1
- package/dist/modules/access/groups-edit.d.ts.map +1 -1
- package/dist/modules/access/groups-edit.js +1 -1
- package/dist/modules/access/groups-edit.js.map +1 -1
- package/dist/modules/access/index.d.ts +1 -1
- package/dist/modules/access/index.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.d.ts +116 -24
- package/dist/modules/access/reference-scan.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.js +305 -44
- package/dist/modules/access/reference-scan.js.map +1 -1
- package/dist/modules/access/roles-admin.service.d.ts +17 -8
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +32 -23
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +35 -10
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +60 -20
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/access-model/access-splice.d.ts +22 -18
- package/dist/modules/access-model/access-splice.d.ts.map +1 -1
- package/dist/modules/access-model/access-splice.js +20 -14
- package/dist/modules/access-model/access-splice.js.map +1 -1
- package/dist/modules/access-model/group-files.d.ts +1 -0
- package/dist/modules/access-model/group-files.d.ts.map +1 -1
- package/dist/modules/access-model/group-files.js +5 -1
- package/dist/modules/access-model/group-files.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.d.ts +47 -7
- package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.js +103 -13
- package/dist/modules/agent-guide/agent-guide.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.d.ts +6 -2
- package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.js +46 -22
- package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -1
- package/dist/modules/agent-guide/guide-budget.d.ts +48 -0
- package/dist/modules/agent-guide/guide-budget.d.ts.map +1 -0
- package/dist/modules/agent-guide/guide-budget.js +67 -0
- package/dist/modules/agent-guide/guide-budget.js.map +1 -0
- package/dist/modules/agent-guide/index.d.ts +2 -1
- package/dist/modules/agent-guide/index.d.ts.map +1 -1
- package/dist/modules/agent-guide/index.js +2 -1
- package/dist/modules/agent-guide/index.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +3 -1
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +7 -1
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +5 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.js +26 -9
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
- package/dist/modules/agent-scope/agent-scope.contract.d.ts +67 -0
- package/dist/modules/agent-scope/agent-scope.contract.d.ts.map +1 -0
- package/dist/modules/agent-scope/agent-scope.contract.js +27 -0
- package/dist/modules/agent-scope/agent-scope.contract.js.map +1 -0
- package/dist/modules/agent-scope/connection-scope.d.ts +111 -0
- package/dist/modules/agent-scope/connection-scope.d.ts.map +1 -0
- package/dist/modules/agent-scope/connection-scope.js +165 -0
- package/dist/modules/agent-scope/connection-scope.js.map +1 -0
- package/dist/modules/agent-scope/index.d.ts +3 -0
- package/dist/modules/agent-scope/index.d.ts.map +1 -0
- package/dist/modules/agent-scope/index.js +3 -0
- package/dist/modules/agent-scope/index.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
- package/dist/modules/audit/agent-audit.service.js +2 -0
- package/dist/modules/audit/agent-audit.service.js.map +1 -1
- package/dist/modules/audit/audit.contract.d.ts +6 -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/auth/account-admission.d.ts +12 -0
- package/dist/modules/auth/account-admission.d.ts.map +1 -1
- package/dist/modules/auth/account-admission.js +15 -0
- package/dist/modules/auth/account-admission.js.map +1 -1
- package/dist/modules/auth/auth.middleware.d.ts +27 -1
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
- package/dist/modules/auth/auth.middleware.js +42 -4
- package/dist/modules/auth/auth.middleware.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts +13 -9
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +35 -29
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +55 -6
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +128 -34
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/index.d.ts +1 -1
- package/dist/modules/auth/index.d.ts.map +1 -1
- package/dist/modules/auth/index.js +1 -1
- package/dist/modules/auth/index.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +2 -9
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +2 -2
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts +0 -12
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +1 -38
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +68 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +33 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts +8 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.js +13 -2
- package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
- package/dist/modules/embed/embed.tools.d.ts.map +1 -1
- package/dist/modules/embed/embed.tools.js +5 -0
- package/dist/modules/embed/embed.tools.js.map +1 -1
- package/dist/modules/kb-fs/index.d.ts +2 -0
- package/dist/modules/kb-fs/index.d.ts.map +1 -1
- package/dist/modules/kb-fs/index.js +1 -0
- package/dist/modules/kb-fs/index.js.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +7 -1
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +26 -6
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +22 -7
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-fs/tmp-ref.d.ts +36 -0
- package/dist/modules/kb-fs/tmp-ref.d.ts.map +1 -0
- package/dist/modules/kb-fs/tmp-ref.js +76 -0
- package/dist/modules/kb-fs/tmp-ref.js.map +1 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +7 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +14 -1
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.routes.d.ts +7 -1
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.routes.js +39 -4
- package/dist/modules/mcp/mcp.routes.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +11 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +74 -48
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +45 -10
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +9 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +34 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
- 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.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +18 -2
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +5 -1
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +32 -5
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +11 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +159 -24
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
- package/dist/modules/secrets-vault/index.d.ts +1 -1
- package/dist/modules/secrets-vault/index.d.ts.map +1 -1
- package/dist/modules/secrets-vault/index.js +1 -1
- package/dist/modules/secrets-vault/index.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +53 -11
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.js +27 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +9 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +100 -42
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/oidc-check.d.ts.map +1 -1
- package/dist/modules/settings/oidc-check.js +5 -17
- package/dist/modules/settings/oidc-check.js.map +1 -1
- package/dist/modules/skills/index.d.ts +3 -3
- package/dist/modules/skills/index.d.ts.map +1 -1
- package/dist/modules/skills/index.js +0 -2
- package/dist/modules/skills/index.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +16 -0
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +6 -1
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +25 -13
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +11 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts +1 -0
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +4 -1
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/index.d.ts +1 -1
- package/dist/modules/tool-auth/index.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +9 -0
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.js +1 -0
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +27 -3
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +32 -6
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts +7 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +3 -0
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-helpers/tool-def.js +1 -1
- package/dist/modules/tool-helpers/tool-def.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts +15 -0
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +19 -0
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +10 -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-helpers/validate-token.d.ts +3 -1
- package/dist/modules/tool-helpers/validate-token.d.ts.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/index.d.ts +3 -3
- package/dist/modules/tool-manuals/index.d.ts.map +1 -1
- package/dist/modules/tool-manuals/index.js +0 -2
- package/dist/modules/tool-manuals/index.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +7 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +69 -38
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +46 -6
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +7 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +41 -4
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +24 -13
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +138 -59
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +8 -2
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +56 -20
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/manual.routes.d.ts +8 -1
- package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -1
- package/dist/modules/tool-registry/manual.routes.js +27 -7
- package/dist/modules/tool-registry/manual.routes.js.map +1 -1
- package/dist/modules/tool-registry/tool.contract.d.ts +7 -0
- package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-registry/tool.contract.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +36 -27
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +2 -2
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +20 -35
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +2 -1
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +3 -0
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -1
- package/dist/modules/workspace/agent-access.gate.js +1 -1
- package/dist/modules/workspace/agent-access.gate.js.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +28 -4
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js +61 -40
- package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
- package/dist/modules/workspace/index.d.ts +8 -0
- package/dist/modules/workspace/index.d.ts.map +1 -1
- package/dist/modules/workspace/index.js +8 -0
- package/dist/modules/workspace/index.js.map +1 -1
- package/dist/modules/workspace/nul-scan.d.ts +19 -0
- package/dist/modules/workspace/nul-scan.d.ts.map +1 -0
- package/dist/modules/workspace/nul-scan.js +55 -0
- package/dist/modules/workspace/nul-scan.js.map +1 -0
- package/dist/modules/workspace/pattern-matcher.contract.d.ts +110 -27
- package/dist/modules/workspace/pattern-matcher.contract.d.ts.map +1 -1
- package/dist/modules/workspace/pattern-matcher.contract.js +30 -13
- package/dist/modules/workspace/pattern-matcher.contract.js.map +1 -1
- package/dist/modules/workspace/ripgrep-search.d.ts +54 -0
- package/dist/modules/workspace/ripgrep-search.d.ts.map +1 -0
- package/dist/modules/workspace/ripgrep-search.js +657 -0
- package/dist/modules/workspace/ripgrep-search.js.map +1 -0
- package/dist/modules/workspace/ripgrep-version.d.ts +15 -0
- package/dist/modules/workspace/ripgrep-version.d.ts.map +1 -0
- package/dist/modules/workspace/ripgrep-version.js +31 -0
- package/dist/modules/workspace/ripgrep-version.js.map +1 -0
- package/dist/modules/workspace/startup/beside-checkout.d.ts +8 -5
- package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -1
- package/dist/modules/workspace/startup/beside-checkout.js +14 -5
- package/dist/modules/workspace/startup/beside-checkout.js.map +1 -1
- package/dist/modules/workspace/worker-pool.d.ts +3 -4
- package/dist/modules/workspace/worker-pool.d.ts.map +1 -1
- package/dist/modules/workspace/worker-pool.js.map +1 -1
- package/dist/modules/workspace/workspace-tmp.d.ts +146 -0
- package/dist/modules/workspace/workspace-tmp.d.ts.map +1 -0
- package/dist/modules/workspace/workspace-tmp.js +435 -0
- package/dist/modules/workspace/workspace-tmp.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +5 -26
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +47 -6
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +86 -6
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +3 -2
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +531 -137
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/shared/oauth-token-error.d.ts +23 -0
- package/dist/shared/oauth-token-error.d.ts.map +1 -0
- package/dist/shared/oauth-token-error.js +47 -0
- package/dist/shared/oauth-token-error.js.map +1 -0
- package/dist/shared/path-order.d.ts +28 -8
- package/dist/shared/path-order.d.ts.map +1 -1
- package/dist/shared/path-order.js +37 -8
- package/dist/shared/path-order.js.map +1 -1
- package/dist/shared/read-capped.d.ts +19 -0
- package/dist/shared/read-capped.d.ts.map +1 -0
- package/dist/shared/read-capped.js +45 -0
- package/dist/shared/read-capped.js.map +1 -0
- package/migrations/0022_session_version.sql +6 -0
- package/migrations/0023_agent_path.sql +3 -0
- package/migrations/meta/0022_snapshot.json +2360 -0
- package/migrations/meta/0023_snapshot.json +2378 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +4 -3
- package/src/__tests__/hexis-catalog.ts +144 -0
- package/src/__tests__/pg-scratch.test.ts +69 -0
- package/src/__tests__/pg-scratch.ts +31 -0
- package/src/__tests__/real-disk.ts +21 -0
- package/src/__tests__/slow-ripgrep.ts +65 -0
- package/src/__tests__/tokens.ts +19 -0
- package/src/__tests__/tool-manuals.ts +32 -0
- package/src/__tests__/tool-wiring.ts +25 -0
- package/src/core/__tests__/boot-without-ripgrep.test.ts +34 -0
- package/src/core/__tests__/catalog-revision.test.ts +89 -0
- package/src/core/__tests__/damaged-document.tools.test.ts +2 -2
- package/src/core/__tests__/gated-boot.test.ts +8 -1
- package/src/core/__tests__/lifecycle.test.ts +46 -13
- package/src/core/__tests__/oauth-sign-in-real-file.test.ts +179 -0
- package/src/core/catalog-revision.ts +24 -2
- package/src/core/core-ports.ts +42 -0
- package/src/core/create-core-server.ts +14 -1
- package/src/core/create-core-services.ts +62 -15
- package/src/core/lifecycle.ts +26 -2
- package/src/index.ts +1 -1
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +12 -0
- package/src/modules/access/__tests__/access-control.colliding-name-cases.test.ts +113 -0
- package/src/modules/access/__tests__/access-control.frontmatter-head.test.ts +117 -0
- package/src/modules/access/__tests__/access-control.group-named-admin.test.ts +122 -0
- package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +50 -0
- package/src/modules/access/__tests__/access-declarations.test.ts +19 -0
- package/src/modules/access/__tests__/access-groups.test.ts +55 -22
- package/src/modules/access/__tests__/access-mutation.service.test.ts +85 -59
- package/src/modules/access/__tests__/access-restrict-here.test.ts +7 -5
- package/src/modules/access/__tests__/access.routes.admins.test.ts +1 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -0
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -0
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +50 -14
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +1 -0
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +52 -10
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +18 -13
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -0
- package/src/modules/access/__tests__/grant-sources.test.ts +20 -15
- package/src/modules/access/__tests__/groups-admin.routes.test.ts +61 -0
- package/src/modules/access/__tests__/groups-admin.service.test.ts +211 -18
- package/src/modules/access/__tests__/holder-changes.test.ts +127 -0
- package/src/modules/access/__tests__/reference-scan.test.ts +366 -14
- package/src/modules/access/__tests__/roles-admin.security.test.ts +1 -1
- package/src/modules/access/__tests__/roles-admin.service.test.ts +43 -22
- package/src/modules/access/__tests__/roles-capabilities.test.ts +6 -2
- package/src/modules/access/__tests__/roles.routes.test.ts +1 -1
- package/src/modules/access/access-control.interface.ts +43 -10
- package/src/modules/access/access-control.service.ts +250 -72
- package/src/modules/access/access-mutation.service.ts +48 -53
- package/src/modules/access/access-view.ts +12 -10
- package/src/modules/access/access.routes.ts +66 -37
- package/src/modules/access/groups-admin.routes.ts +4 -2
- package/src/modules/access/groups-admin.service.ts +114 -44
- package/src/modules/access/groups-edit.ts +1 -1
- package/src/modules/access/index.ts +1 -1
- package/src/modules/access/reference-scan.ts +319 -46
- package/src/modules/access/roles-admin.service.ts +43 -26
- package/src/modules/access/synced-groups-writer.ts +1 -1
- package/src/modules/access-model/__tests__/access-grammar.test.ts +38 -1
- package/src/modules/access-model/__tests__/access-splice.test.ts +50 -8
- package/src/modules/access-model/access-grammar.ts +65 -20
- package/src/modules/access-model/access-splice.ts +31 -23
- package/src/modules/access-model/group-files.ts +5 -0
- package/src/modules/agent-guide/__tests__/agent-guide.test.ts +110 -25
- package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +38 -11
- package/src/modules/agent-guide/__tests__/guide-budget.test.ts +95 -0
- package/src/modules/agent-guide/__tests__/guide-eval.test.ts +182 -0
- package/src/modules/agent-guide/__tests__/guide-matches-code.test.ts +263 -0
- package/src/modules/agent-guide/__tests__/tool-surface.json +514 -0
- package/src/modules/agent-guide/__tests__/tool-surface.test.ts +75 -0
- package/src/modules/agent-guide/agent-guide.tools.ts +51 -22
- package/src/modules/agent-guide/agent-guide.ts +120 -13
- package/src/modules/agent-guide/guide-budget.ts +73 -0
- package/src/modules/agent-guide/index.ts +12 -0
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +5 -4
- package/src/modules/agent-instructions/compose.ts +7 -1
- package/src/modules/agent-instructions/shared-file-rules.ts +27 -9
- package/src/modules/agent-scope/__tests__/agent-surfaces.connect-as.test.ts +421 -0
- package/src/modules/agent-scope/__tests__/connection-scope.test.ts +46 -0
- package/src/modules/agent-scope/__tests__/in-memory-kb.ts +148 -0
- package/src/modules/agent-scope/agent-scope.contract.ts +83 -0
- package/src/modules/agent-scope/connection-scope.ts +199 -0
- package/src/modules/agent-scope/index.ts +15 -0
- package/src/modules/audit/agent-audit.service.ts +2 -0
- package/src/modules/audit/audit.contract.ts +6 -0
- package/src/modules/auth/__tests__/auth.middleware.test.ts +30 -2
- package/src/modules/auth/__tests__/auth.routes.test.ts +71 -5
- package/src/modules/auth/__tests__/auth.service.test.ts +90 -9
- package/src/modules/auth/__tests__/password-change-sessions.pg.test.ts +269 -0
- package/src/modules/auth/account-admission.ts +19 -0
- package/src/modules/auth/auth.middleware.ts +45 -4
- package/src/modules/auth/auth.routes.ts +46 -29
- package/src/modules/auth/auth.service.ts +135 -34
- package/src/modules/auth/index.ts +2 -0
- package/src/modules/auth/oidc-auth-provider.ts +2 -9
- package/src/modules/code-mode/code-mode.tool.ts +2 -2
- package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +5 -24
- package/src/modules/connection-probe/connection-probe.service.ts +1 -34
- package/src/modules/database/__tests__/session-version-migration.pg.test.ts +133 -0
- package/src/modules/database/core-schema.ts +33 -0
- package/src/modules/declared-variables/__tests__/declared-variables.route.test.ts +44 -1
- package/src/modules/declared-variables/declared-variables.routes.ts +12 -1
- package/src/modules/embed/__tests__/embed.tools.test.ts +12 -0
- package/src/modules/embed/embed.tools.ts +5 -0
- package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +25 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +53 -8
- package/src/modules/kb-fs/index.ts +2 -0
- package/src/modules/kb-fs/locking-filesystem.ts +7 -1
- package/src/modules/kb-fs/repo-path.ts +33 -7
- package/src/modules/kb-fs/tmp-ref.ts +81 -0
- package/src/modules/mcp/__tests__/connect-as.pg.test.ts +137 -0
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +29 -5
- package/src/modules/mcp/__tests__/mcp-routes-harness.ts +8 -0
- package/src/modules/mcp/__tests__/mcp.connect-as.test.ts +195 -0
- package/src/modules/mcp/__tests__/mcp.routes.connect-as.test.ts +192 -0
- package/src/modules/mcp/__tests__/oauth-consent.connect-as.test.ts +146 -0
- package/src/modules/mcp/mcp-auth.middleware.ts +19 -2
- package/src/modules/mcp/mcp.routes.ts +39 -3
- package/src/modules/mcp/mcp.service.ts +112 -52
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +46 -8
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +41 -1
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +38 -2
- package/src/modules/plugins/index.ts +1 -1
- package/src/modules/plugins/plugin-links.ts +19 -2
- package/src/modules/plugins/plugins.routes.ts +35 -4
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +113 -0
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +430 -3
- package/src/modules/secrets-vault/__tests__/oauth-live-declaration.route.test.ts +218 -0
- package/src/modules/secrets-vault/__tests__/oauth-return-to.route.test.ts +39 -6
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +170 -27
- package/src/modules/secrets-vault/index.ts +1 -1
- package/src/modules/secrets-vault/secrets-vault.contract.ts +61 -11
- package/src/modules/secrets-vault/secrets-vault.routes.ts +114 -42
- package/src/modules/settings/oidc-check.ts +5 -18
- package/src/modules/skills/__tests__/skills.service.test.ts +34 -0
- package/src/modules/skills/index.ts +7 -2
- package/src/modules/skills/skills.contract.ts +17 -0
- package/src/modules/skills/skills.service.ts +5 -1
- package/src/modules/skills/skills.tools.ts +45 -14
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +4 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +11 -1
- package/src/modules/tool-auth/external-api-key.service.ts +5 -2
- package/src/modules/tool-auth/index.ts +1 -1
- package/src/modules/tool-auth/internal-token.service.ts +10 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +45 -3
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +19 -11
- package/src/modules/tool-helpers/__tests__/can-write.tools.test.ts +3 -1
- package/src/modules/tool-helpers/__tests__/route-tool-schemas.catalog.test.ts +38 -0
- package/src/modules/tool-helpers/tool-context.ts +10 -0
- package/src/modules/tool-helpers/tool-def.ts +1 -1
- package/src/modules/tool-helpers/tool-handler.ts +34 -0
- package/src/modules/tool-helpers/tool.contract.ts +10 -0
- package/src/modules/tool-helpers/validate-token.ts +4 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +80 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +197 -11
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +42 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +99 -8
- package/src/modules/tool-manuals/index.ts +6 -2
- package/src/modules/tool-manuals/mcp-json-discovery.ts +73 -34
- package/src/modules/tool-manuals/tool-manuals.contract.ts +40 -6
- package/src/modules/tool-manuals/tool-manuals.routes.ts +40 -3
- package/src/modules/tool-manuals/tool-manuals.service.ts +169 -61
- package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -25
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +6 -113
- package/src/modules/tool-registry/manual.routes.ts +26 -5
- package/src/modules/tool-registry/tool.contract.ts +7 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +1 -1
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +54 -3
- package/src/modules/workflow/agent-tools/workflow.tools.ts +36 -27
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +130 -3
- package/src/modules/workflow/git/git.service.ts +29 -48
- package/src/modules/workflow/workflow.service.ts +5 -0
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -2
- package/src/modules/workspace/__tests__/holds-nul.test.ts +66 -0
- package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +3 -3
- package/src/modules/workspace/__tests__/ripgrep-search.test.ts +570 -0
- package/src/modules/workspace/__tests__/ripgrep-version.test.ts +29 -0
- package/src/modules/workspace/__tests__/workspace-tmp.tools.test.ts +928 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +17 -37
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +20 -8
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -12
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +22 -10
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +549 -162
- package/src/modules/workspace/agent-access.gate.ts +1 -1
- package/src/modules/workspace/file-readers/__tests__/doc-extract.service.test.ts +10 -0
- package/src/modules/workspace/file-readers/doc-extract.service.ts +71 -38
- package/src/modules/workspace/index.ts +20 -0
- package/src/modules/workspace/nul-scan.ts +50 -0
- package/src/modules/workspace/pattern-matcher.contract.ts +123 -32
- package/src/modules/workspace/ripgrep-search.ts +715 -0
- package/src/modules/workspace/ripgrep-version.ts +35 -0
- package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +11 -0
- package/src/modules/workspace/startup/beside-checkout.ts +13 -5
- package/src/modules/workspace/worker-pool.ts +3 -4
- package/src/modules/workspace/workspace-tmp.ts +457 -0
- package/src/modules/workspace/workspace.routes.ts +6 -27
- package/src/modules/workspace/workspace.service.ts +92 -15
- package/src/modules/workspace/workspace.tools.ts +574 -176
- package/src/shared/__tests__/read-capped.test.ts +68 -0
- package/src/shared/oauth-token-error.ts +46 -0
- package/src/shared/path-order.ts +37 -8
- package/src/shared/read-capped.ts +40 -0
- package/starter-packs/engineering/Plugins/engineering-starter/access.md +1 -1
- package/starter-packs/general/Plugins/general-starter/access.md +1 -1
- package/starter-packs/operations/Plugins/operations-starter/access.md +1 -1
- package/starter-packs/sales/Plugins/sales-starter/access.md +1 -1
- package/starter-packs/support/Plugins/support-starter/access.md +1 -1
- package/agent-guide/finding-things.md +0 -7
- package/agent-guide/introduction.md +0 -27
- package/dist/modules/workspace/bounded-matcher.d.ts +0 -73
- package/dist/modules/workspace/bounded-matcher.d.ts.map +0 -1
- package/dist/modules/workspace/bounded-matcher.js +0 -200
- package/dist/modules/workspace/bounded-matcher.js.map +0 -1
- package/src/modules/workspace/__tests__/bounded-matcher.test.ts +0 -213
- package/src/modules/workspace/bounded-matcher.ts +0 -271
|
@@ -155,6 +155,20 @@
|
|
|
155
155
|
"when": 1792491290917,
|
|
156
156
|
"tag": "0021_data_migrations_ledger",
|
|
157
157
|
"breakpoints": true
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"idx": 22,
|
|
161
|
+
"version": "7",
|
|
162
|
+
"when": 1792657514328,
|
|
163
|
+
"tag": "0022_session_version",
|
|
164
|
+
"breakpoints": true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"idx": 23,
|
|
168
|
+
"version": "7",
|
|
169
|
+
"when": 1793089896833,
|
|
170
|
+
"tag": "0023_agent_path",
|
|
171
|
+
"breakpoints": true
|
|
158
172
|
}
|
|
159
173
|
]
|
|
160
174
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bevel-software/platform-core-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Open-source core backend of the Bevel platform: git-backed knowledge workspace, workflow (branches/change requests/locks/SSE), skills, tools, secrets vault, access control and the remote MCP surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
56
56
|
"yaml": "^2.9.0",
|
|
57
57
|
"zod": "^3.24.0",
|
|
58
|
-
"@bevel-software/platform-mcp-core": "0.
|
|
59
|
-
"@bevel-software/platform-shared": "0.
|
|
58
|
+
"@bevel-software/platform-mcp-core": "0.35.0",
|
|
59
|
+
"@bevel-software/platform-shared": "0.35.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/adm-zip": "^0.5.8",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"@types/pg": "^8.20.0",
|
|
69
69
|
"@types/qs": "^6.15.1",
|
|
70
70
|
"drizzle-kit": "^0.31.10",
|
|
71
|
+
"js-tiktoken": "^1.0.21",
|
|
71
72
|
"tsx": "^4.19.0",
|
|
72
73
|
"typescript": "^5.8.0",
|
|
73
74
|
"vitest": "^3.2.6"
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { codeModeMetaTools } from '@bevel-software/platform-mcp-core';
|
|
3
|
+
import { testKbContext } from './kb-context.js';
|
|
4
|
+
import { EXTERNAL_KB_MANUAL_NAME, registerToolManualsTools } from '../modules/tool-manuals/index.js';
|
|
5
|
+
import { ToolRegistry, guideFirstDescription, type UtcpTool } from '../modules/tool-registry/index.js';
|
|
6
|
+
import type { ToolAuth } from '../modules/tool-auth/index.js';
|
|
7
|
+
import { RipgrepPatternMatcher, ToolDescriptionNotes } from '../modules/workspace/index.js';
|
|
8
|
+
import { registerPluginsTools } from '../modules/plugins/index.js';
|
|
9
|
+
import { registerSkillsTools } from '../modules/skills/index.js';
|
|
10
|
+
import { agentGuideSections, registerAgentGuideTool } from '../modules/agent-guide/index.js';
|
|
11
|
+
import {
|
|
12
|
+
RoutineWritePolicyService,
|
|
13
|
+
UuidSessionSink,
|
|
14
|
+
WorkflowHooks,
|
|
15
|
+
createToolHandlerFactory,
|
|
16
|
+
registerChangeRequestReadTools,
|
|
17
|
+
registerEmbedTools,
|
|
18
|
+
registerWorkflowTools,
|
|
19
|
+
registerWorkspaceTools,
|
|
20
|
+
} from './tool-wiring.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The tool catalog Hexis itself registers, built on stand-ins for the tests
|
|
24
|
+
* that read what an agent is TOLD: the description caps, the guide checks and
|
|
25
|
+
* the guide's budgets. Every registrar Hexis owns is mounted, because the
|
|
26
|
+
* definitions are the only thing under test: a stand-in that is never called
|
|
27
|
+
* is honest about that. Tools PROXIED from connected MCP servers are not here:
|
|
28
|
+
* their text is the other server's.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** Dependencies the registrars take but never touch while they are only building defs. */
|
|
32
|
+
export const unused = <T,>(): T => ({}) as T;
|
|
33
|
+
|
|
34
|
+
/** A `.tool` catalog with nothing in it: the shortest honest answer for a listing. */
|
|
35
|
+
const emptyManuals = {
|
|
36
|
+
listLocalOnly: async () => [],
|
|
37
|
+
listAll: async () => [],
|
|
38
|
+
list: async () => [],
|
|
39
|
+
listInvalid: async () => [],
|
|
40
|
+
} as unknown as Parameters<typeof registerToolManualsTools>[4];
|
|
41
|
+
|
|
42
|
+
/** A skill catalog with nothing in it — the per-user skill line is then one fixed sentence. */
|
|
43
|
+
export const emptySkills = { listSkills: async () => [] } as unknown as Parameters<typeof registerSkillsTools>[4];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The meta-tools as the hosted endpoint builds them (`mcp.service.ts`):
|
|
47
|
+
* examples written against the namespace it registers the knowledge-base tools
|
|
48
|
+
* under and against the catalog it serves, and the chain without the rules it
|
|
49
|
+
* states only in the shared places. So the chain description measured here
|
|
50
|
+
* carries the worked call a client is really sent, which is its longest form.
|
|
51
|
+
*/
|
|
52
|
+
export function servedMetaTools(external: readonly UtcpTool[]) {
|
|
53
|
+
return codeModeMetaTools(
|
|
54
|
+
EXTERNAL_KB_MANUAL_NAME,
|
|
55
|
+
external.map((t) => ({ utcpName: `${EXTERNAL_KB_MANUAL_NAME}.${t.name}`, inputSchema: t.inputs })),
|
|
56
|
+
{ sharedRulesPointer: '' },
|
|
57
|
+
// As the hosted endpoint serves them: opening with the guide-first
|
|
58
|
+
// sentence, through the one helper the endpoint itself uses.
|
|
59
|
+
).map((t) => ({ ...t, description: guideFirstDescription(t.description) }));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Every tool Hexis itself registers, by surface: what the in-process agent is
|
|
64
|
+
* handed, what the hosted endpoint lists to an MCP client, and the three
|
|
65
|
+
* meta-tools it lists beside them.
|
|
66
|
+
*/
|
|
67
|
+
export async function hexisCatalog(
|
|
68
|
+
skills: Parameters<typeof registerSkillsTools>[4] = emptySkills,
|
|
69
|
+
): Promise<{ internal: UtcpTool[]; external: UtcpTool[]; metaTools: ReturnType<typeof servedMetaTools> }> {
|
|
70
|
+
const registry = new ToolRegistry();
|
|
71
|
+
const router = express.Router();
|
|
72
|
+
const toolAuth = ((_req, _res, next) => next()) as unknown as ToolAuth;
|
|
73
|
+
const toolHandler = createToolHandlerFactory(unused());
|
|
74
|
+
const kb = testKbContext();
|
|
75
|
+
const gate = { recoveryBotEmail: 'bot@x', hooks: new WorkflowHooks(), notes: new ToolDescriptionNotes() };
|
|
76
|
+
|
|
77
|
+
// The change-request readers come first, as the root mounts them: they
|
|
78
|
+
// gate their whole payload on the caller's read access and take the access
|
|
79
|
+
// service and nothing else.
|
|
80
|
+
registerChangeRequestReadTools(registry, router, toolAuth, toolHandler, unused(), kb);
|
|
81
|
+
const workspaceTools = registerWorkspaceTools(
|
|
82
|
+
registry,
|
|
83
|
+
router,
|
|
84
|
+
toolAuth,
|
|
85
|
+
toolHandler,
|
|
86
|
+
unused(),
|
|
87
|
+
unused(),
|
|
88
|
+
unused(),
|
|
89
|
+
kb,
|
|
90
|
+
gate,
|
|
91
|
+
new RoutineWritePolicyService(),
|
|
92
|
+
new UuidSessionSink(),
|
|
93
|
+
undefined,
|
|
94
|
+
undefined,
|
|
95
|
+
// The two upload tools are mounted only when a store is supplied, and
|
|
96
|
+
// every real composition supplies one: without it they would be the two
|
|
97
|
+
// descriptions this suite never measured.
|
|
98
|
+
unused(),
|
|
99
|
+
// The guide reader, not needed to build defs; then the download store,
|
|
100
|
+
// mounted on the same terms as the upload one.
|
|
101
|
+
undefined,
|
|
102
|
+
unused(),
|
|
103
|
+
// Starter packs and the tree walk, not needed; then the grep matcher,
|
|
104
|
+
// mounted on the same terms (it spawns no worker until a search runs).
|
|
105
|
+
undefined,
|
|
106
|
+
undefined,
|
|
107
|
+
new RipgrepPatternMatcher(),
|
|
108
|
+
);
|
|
109
|
+
registerWorkflowTools(registry, router, toolAuth, toolHandler, kb, async () => true, { canRead: async () => true, canReadAtRef: async () => true, canReadBatch: async () => new Map(), canReadBatchAtRef: async () => new Map(), canWrite: async () => true } as never, { recoveryBotEmail: 'recovery@x', hooks: { runAgentRead: async () => undefined }, notes: { onChange: () => undefined } } as never);
|
|
110
|
+
registerPluginsTools(registry, kb);
|
|
111
|
+
registerSkillsTools(registry, router, toolAuth, toolHandler, skills);
|
|
112
|
+
registerToolManualsTools(registry, router, toolAuth, toolHandler, emptyManuals, {
|
|
113
|
+
accessControl: unused(),
|
|
114
|
+
variableStatus: unused(),
|
|
115
|
+
kb,
|
|
116
|
+
});
|
|
117
|
+
// `open_page`, on the file tools' router with `read_file`'s own read, as the
|
|
118
|
+
// root mounts it; its stand-ins answer nothing, since only its def is read.
|
|
119
|
+
registerEmbedTools(registry, router, toolAuth, toolHandler, {
|
|
120
|
+
embedService: unused(),
|
|
121
|
+
kb,
|
|
122
|
+
readForTool: workspaceTools.readForTool,
|
|
123
|
+
canBeReached: () => true,
|
|
124
|
+
appUrlFor: () => '',
|
|
125
|
+
notes: gate.notes,
|
|
126
|
+
});
|
|
127
|
+
// The guide's own tool, with the platform's sections: the one description
|
|
128
|
+
// that lists the sections is measured with the list it really carries.
|
|
129
|
+
registerAgentGuideTool(registry, router, toolAuth, toolHandler, () => agentGuideSections(kb.layout));
|
|
130
|
+
|
|
131
|
+
// The meta-tools as a client is served them (`mcp.service.ts` opens each
|
|
132
|
+
// with the guide-first sentence at the mount), so the catalog measured here
|
|
133
|
+
// is the catalog that goes out rather than the bare constant.
|
|
134
|
+
const external = (await registry.listExternal()) as UtcpTool[];
|
|
135
|
+
return { internal: (await registry.listInternal()) as UtcpTool[], external, metaTools: servedMetaTools(external) };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Every tool Hexis itself registers, on both surfaces, deduplicated by name. */
|
|
139
|
+
export async function hexisTools(skills: Parameters<typeof registerSkillsTools>[4] = emptySkills): Promise<UtcpTool[]> {
|
|
140
|
+
const { internal, external, metaTools } = await hexisCatalog(skills);
|
|
141
|
+
const byName = new Map<string, UtcpTool>();
|
|
142
|
+
for (const tool of [...internal, ...external, ...metaTools]) byName.set(tool.name, tool as UtcpTool);
|
|
143
|
+
return [...byName.values()];
|
|
144
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `openMigratedScratchDb` owns the pool it opens until it hands the handle
|
|
5
|
+
* over: when the migrations fail, the caller never receives `close`, so the
|
|
6
|
+
* helper must close the pool itself and let the error through. No Postgres
|
|
7
|
+
* here — the connection, the migrations and the `pg` admin client are stubs,
|
|
8
|
+
* since the subject is the helper's ownership of what it opened, not the
|
|
9
|
+
* database.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const stubs = vi.hoisted(() => ({
|
|
13
|
+
db: { kind: 'fake-db' },
|
|
14
|
+
createDb: vi.fn(),
|
|
15
|
+
closeDb: vi.fn(async () => {}),
|
|
16
|
+
runCoreMigrations: vi.fn(async () => {}),
|
|
17
|
+
adminQuery: vi.fn(async () => ({ rows: [] })),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
vi.mock('../modules/database/connection.js', () => ({
|
|
21
|
+
createDb: stubs.createDb,
|
|
22
|
+
closeDb: stubs.closeDb,
|
|
23
|
+
}));
|
|
24
|
+
vi.mock('../modules/database/migrate.js', () => ({
|
|
25
|
+
runCoreMigrations: stubs.runCoreMigrations,
|
|
26
|
+
}));
|
|
27
|
+
vi.mock('../assets.js', () => ({ coreMigrationsDir: () => '/migrations' }));
|
|
28
|
+
vi.mock('pg', () => ({
|
|
29
|
+
default: {
|
|
30
|
+
Client: class {
|
|
31
|
+
connect = async () => {};
|
|
32
|
+
query = stubs.adminQuery;
|
|
33
|
+
end = async () => {};
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
// Read once, at import: a URL the stubbed admin client will never dial.
|
|
39
|
+
process.env.TEST_DATABASE_URL = 'postgres://scratch:scratch@127.0.0.1:1/admin';
|
|
40
|
+
const { openMigratedScratchDb } = await import('./pg-scratch.js');
|
|
41
|
+
|
|
42
|
+
describe('openMigratedScratchDb', () => {
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
stubs.createDb.mockReturnValue(stubs.db);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
vi.clearAllMocks();
|
|
49
|
+
stubs.runCoreMigrations.mockResolvedValue(undefined);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('hands the migrated database over with a close the caller owns', async () => {
|
|
53
|
+
const opened = await openMigratedScratchDb('hexis_owned');
|
|
54
|
+
expect(opened.db).toBe(stubs.db);
|
|
55
|
+
expect(stubs.runCoreMigrations).toHaveBeenCalledWith(stubs.db, '/migrations');
|
|
56
|
+
// The pool stays open until the caller closes it.
|
|
57
|
+
expect(stubs.closeDb).not.toHaveBeenCalled();
|
|
58
|
+
await opened.close();
|
|
59
|
+
expect(stubs.closeDb).toHaveBeenCalledWith(stubs.db);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('closes the pool it opened when the migrations fail, and lets the failure through', async () => {
|
|
63
|
+
stubs.runCoreMigrations.mockRejectedValueOnce(new Error('migration 0022 failed'));
|
|
64
|
+
await expect(openMigratedScratchDb('hexis_failed')).rejects.toThrow('migration 0022 failed');
|
|
65
|
+
// Closed by the helper: the caller never received a handle to close.
|
|
66
|
+
expect(stubs.closeDb).toHaveBeenCalledTimes(1);
|
|
67
|
+
expect(stubs.closeDb).toHaveBeenCalledWith(stubs.db);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import pg from 'pg';
|
|
3
|
+
import { closeDb, createDb, type Database } from '../modules/database/connection.js';
|
|
4
|
+
import { runCoreMigrations } from '../modules/database/migrate.js';
|
|
5
|
+
import { coreMigrationsDir } from '../assets.js';
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* The one fixture for tests that cross a real Postgres. They run where
|
|
@@ -9,6 +12,11 @@ import pg from 'pg';
|
|
|
9
12
|
* of its own, made by {@link scratchDatabaseUrl} and dropped by
|
|
10
13
|
* {@link dropScratchDatabases}; the database the URL names is only connected
|
|
11
14
|
* to, never written.
|
|
15
|
+
*
|
|
16
|
+
* A test that wants the schema as a deployment has it opens the database
|
|
17
|
+
* through {@link openMigratedScratchDb}: this fixture is the one place
|
|
18
|
+
* outside the database module that knows how a core database is connected
|
|
19
|
+
* to and migrated, so a module's test need not import those files itself.
|
|
12
20
|
*/
|
|
13
21
|
export const PG_ADMIN_URL = process.env.TEST_DATABASE_URL;
|
|
14
22
|
|
|
@@ -38,6 +46,29 @@ export async function scratchDatabaseUrl(prefix: string): Promise<string> {
|
|
|
38
46
|
return url.toString();
|
|
39
47
|
}
|
|
40
48
|
|
|
49
|
+
/**
|
|
50
|
+
* A scratch database at the current core schema — created, connected to with
|
|
51
|
+
* the PII key given (a fresh random one when none is), and every core
|
|
52
|
+
* migration run — as a module's test wants it. `close` ends the connection;
|
|
53
|
+
* {@link dropScratchDatabases} drops the database afterwards as for any other.
|
|
54
|
+
*/
|
|
55
|
+
export async function openMigratedScratchDb(
|
|
56
|
+
prefix: string,
|
|
57
|
+
opts: { piiKey?: string } = {},
|
|
58
|
+
): Promise<{ db: Database; close: () => Promise<void> }> {
|
|
59
|
+
const piiKey = opts.piiKey ?? randomBytes(32).toString('base64');
|
|
60
|
+
const db = createDb(await scratchDatabaseUrl(prefix), { piiKey });
|
|
61
|
+
try {
|
|
62
|
+
await runCoreMigrations(db, coreMigrationsDir());
|
|
63
|
+
} catch (err) {
|
|
64
|
+
// The caller never receives the handle on this path, so the pool is
|
|
65
|
+
// closed here; the database itself is dropped with the others.
|
|
66
|
+
await closeDb(db);
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
return { db, close: () => closeDb(db) };
|
|
70
|
+
}
|
|
71
|
+
|
|
41
72
|
/** Drop every scratch database this file made; for `afterAll`, with {@link PG_TEST_TIMEOUT}. */
|
|
42
73
|
export async function dropScratchDatabases(): Promise<void> {
|
|
43
74
|
const names = created.splice(0);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NodeFs } from '../modules/kb-fs/node-fs.js';
|
|
2
|
+
import { KbPluginSource } from '../modules/plugins/index.js';
|
|
3
|
+
import type { KbContext } from '../shared/kb-context.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The real disk, and the plugin source that reads it, wired the way the
|
|
7
|
+
* composition root wires them (`core/create-core-services.ts`: one `NodeFs`,
|
|
8
|
+
* one `KbPluginSource` over it). A module's suite that drives its service over
|
|
9
|
+
* real files takes them from HERE rather than constructing another module's
|
|
10
|
+
* implementation itself: the root is the one place that knows those files
|
|
11
|
+
* (`NodeFs` is on no module entry, by design — a filesystem arrives by
|
|
12
|
+
* injection), and this fixture stands in for the root, as `kb-context.ts`
|
|
13
|
+
* does for the knowledge-base context.
|
|
14
|
+
*/
|
|
15
|
+
export function realDisk(): NodeFs {
|
|
16
|
+
return new NodeFs();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function realPluginSource(disk: NodeFs, kb: KbContext): KbPluginSource {
|
|
20
|
+
return new KbPluginSource(disk, kb);
|
|
21
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { chmod, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { delimiter, join } from 'node:path';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A ripgrep that never finishes a TREE search, for the suites about the
|
|
9
|
+
* search budget and about stopping: an `rg` put first on this process's PATH,
|
|
10
|
+
* where the server finds its ripgrep. A run reading stdin (the pattern check,
|
|
11
|
+
* a document's text) is handed to the real `rg`, so a pattern is judged as it
|
|
12
|
+
* always is; a walk records its process id and sleeps for a minute, which no
|
|
13
|
+
* budget waits out — or, given `walkMs`, sleeps that long and then finishes
|
|
14
|
+
* having found nothing, which is how a suite spends a budget in parts.
|
|
15
|
+
*
|
|
16
|
+
* `alive()` answers which of the walks it started are still running, so a
|
|
17
|
+
* suite can assert that a stopped search left no process behind. `remove()`
|
|
18
|
+
* puts the PATH back.
|
|
19
|
+
*/
|
|
20
|
+
export interface SlowRipgrep {
|
|
21
|
+
alive(): Promise<number[]>;
|
|
22
|
+
remove(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function slowRipgrep(opts: { walkMs?: number } = {}): Promise<SlowRipgrep> {
|
|
26
|
+
const seconds = opts.walkMs === undefined ? '60' : (opts.walkMs / 1000).toFixed(3);
|
|
27
|
+
const real = (await promisify(execFile)('sh', ['-c', 'command -v rg'])).stdout.trim();
|
|
28
|
+
const dir = await mkdtemp(join(tmpdir(), 'slow-rg-'));
|
|
29
|
+
const pids = join(dir, 'pids');
|
|
30
|
+
const binary = join(dir, 'rg');
|
|
31
|
+
await writeFile(
|
|
32
|
+
binary,
|
|
33
|
+
[
|
|
34
|
+
'#!/bin/sh',
|
|
35
|
+
'for a in "$@"; do last="$a"; done',
|
|
36
|
+
`if [ "$last" = "-" ]; then exec '${real}' "$@"; fi`,
|
|
37
|
+
`echo $$ >> '${pids}'`,
|
|
38
|
+
`exec sleep ${seconds}`,
|
|
39
|
+
'',
|
|
40
|
+
].join('\n'),
|
|
41
|
+
);
|
|
42
|
+
await chmod(binary, 0o755);
|
|
43
|
+
const path = process.env.PATH;
|
|
44
|
+
process.env.PATH = `${dir}${delimiter}${path ?? ''}`;
|
|
45
|
+
return {
|
|
46
|
+
async alive() {
|
|
47
|
+
const started = (await readFile(pids, 'utf8').catch(() => ''))
|
|
48
|
+
.split('\n')
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.map(Number);
|
|
51
|
+
return started.filter((pid) => {
|
|
52
|
+
try {
|
|
53
|
+
process.kill(pid, 0);
|
|
54
|
+
return true;
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
async remove() {
|
|
61
|
+
process.env.PATH = path;
|
|
62
|
+
await rm(dir, { recursive: true, force: true });
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Tiktoken } from 'js-tiktoken/lite';
|
|
2
|
+
import o200kBase from 'js-tiktoken/ranks/o200k_base';
|
|
3
|
+
import { GUIDE_TOKEN_ENCODING } from '../modules/agent-guide/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Token counts for the tests that hold agent-facing text to a budget
|
|
7
|
+
* (`modules/agent-guide/guide-budget.ts`): a real BPE tokenizer, offline and
|
|
8
|
+
* deterministic, so a count in CI is the count on a laptop. Built once: the
|
|
9
|
+
* rank table is large and the counts never change between calls.
|
|
10
|
+
*/
|
|
11
|
+
const encoder = new Tiktoken(o200kBase);
|
|
12
|
+
|
|
13
|
+
if (GUIDE_TOKEN_ENCODING !== 'o200k_base') {
|
|
14
|
+
throw new Error(`The budgets name ${GUIDE_TOKEN_ENCODING}, but the counter is built on o200k_base.`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function countTokens(text: string): number {
|
|
18
|
+
return encoder.encode(text).length;
|
|
19
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ToolManualService, type McpAuthDiscoveryPort } from '../modules/tool-manuals/tool-manuals.service.js';
|
|
2
|
+
import type { IAccessControl } from '../modules/access/index.js';
|
|
3
|
+
import type { WorkspaceService } from '../modules/workspace/index.js';
|
|
4
|
+
import type { KbContext } from '../shared/kb-context.js';
|
|
5
|
+
import { realDisk, realPluginSource } from './real-disk.js';
|
|
6
|
+
|
|
7
|
+
export type { McpAuthDiscoveryPort };
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The tool-manual service over real files, wired the way the composition root
|
|
11
|
+
* wires it (`core/create-core-services.ts`): the real disk, the plugin source
|
|
12
|
+
* reading that same disk, and the discovery port set afterwards. A suite that
|
|
13
|
+
* drives the service over real tool files takes it from HERE and never
|
|
14
|
+
* constructs the class from its file — the class is on no module entry (a
|
|
15
|
+
* service arrives by injection), and this fixture stands in for the root, as
|
|
16
|
+
* `kb-context.ts` and `real-disk.ts` do for what they wire.
|
|
17
|
+
*/
|
|
18
|
+
export function realToolManualService(
|
|
19
|
+
deps: {
|
|
20
|
+
workspaceService: WorkspaceService;
|
|
21
|
+
accessControl: IAccessControl;
|
|
22
|
+
kb: KbContext;
|
|
23
|
+
/** The disk the suite writes its files to; the service reads the same one. */
|
|
24
|
+
disk?: ReturnType<typeof realDisk>;
|
|
25
|
+
},
|
|
26
|
+
discovery?: McpAuthDiscoveryPort,
|
|
27
|
+
): ToolManualService {
|
|
28
|
+
const disk = deps.disk ?? realDisk();
|
|
29
|
+
const svc = new ToolManualService(deps.workspaceService, deps.accessControl, deps.kb, disk, realPluginSource(disk, deps.kb));
|
|
30
|
+
if (discovery) svc.setMcpAuthDiscovery(discovery);
|
|
31
|
+
return svc;
|
|
32
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pieces the composition root wires from module internals, for a suite
|
|
3
|
+
* that builds a tool surface the way `core/create-core-server.ts` does: the
|
|
4
|
+
* handler factory and context resolver, the tool-auth middleware, the two
|
|
5
|
+
* registrars that take their dependencies by hand, the session sink, the
|
|
6
|
+
* routine write policy, the access resolver and the workflow hooks.
|
|
7
|
+
*
|
|
8
|
+
* A module's entry holds its contracts, and a suite asserts through entries.
|
|
9
|
+
* These are not contracts: they are what the root composes, so a suite that
|
|
10
|
+
* needs them reaches them here, the one root fixture that imports past the
|
|
11
|
+
* entries, as the root itself does. A suite that imports one of these files
|
|
12
|
+
* directly is a second wiring that drifts from the root's.
|
|
13
|
+
*/
|
|
14
|
+
export { createToolHandlerFactory } from '../modules/tool-helpers/tool-handler.js';
|
|
15
|
+
export { createToolContextResolver } from '../modules/tool-helpers/tool-context.js';
|
|
16
|
+
export { createToolAuthMiddleware } from '../modules/tool-auth/tool-auth.middleware.js';
|
|
17
|
+
export { InternalTokenService } from '../modules/tool-auth/internal-token.service.js';
|
|
18
|
+
export { registerWorkspaceTools } from '../modules/workspace/workspace.tools.js';
|
|
19
|
+
export { registerWorkflowTools } from '../modules/workflow/agent-tools/workflow.tools.js';
|
|
20
|
+
export { registerChangeRequestReadTools } from '../modules/workflow/agent-tools/change-request-read.tools.js';
|
|
21
|
+
export { registerEmbedTools } from '../modules/embed/embed.tools.js';
|
|
22
|
+
export { UuidSessionSink } from '../modules/workspace/session-sink.js';
|
|
23
|
+
export { RoutineWritePolicyService } from '../modules/workspace/routine-write-policy.js';
|
|
24
|
+
export { AccessControlService, loadActiveGroups } from '../modules/access/access-control.service.js';
|
|
25
|
+
export { WorkflowHooks, type AgentOperationContext } from '../modules/workflow/workflow-hooks.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { mkdtemp, rm, symlink } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
7
|
+
import { createCoreServices } from '../../index.js';
|
|
8
|
+
import type { TenantConfig } from '../../core-config.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The server's boot, through the package's own entry, on a PATH that carries
|
|
12
|
+
* git and no ripgrep: it refuses to build any service, naming the binary.
|
|
13
|
+
*/
|
|
14
|
+
describe('booting without ripgrep', () => {
|
|
15
|
+
const path = process.env.PATH;
|
|
16
|
+
let bin = '';
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
process.env.PATH = path;
|
|
19
|
+
if (bin) await rm(bin, { recursive: true, force: true });
|
|
20
|
+
bin = '';
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('refuses to start, naming rg and the Dockerfile that installs it', async () => {
|
|
24
|
+
const git = (await promisify(execFile)('sh', ['-c', 'command -v git'])).stdout.trim();
|
|
25
|
+
bin = await mkdtemp(join(tmpdir(), 'no-rg-'));
|
|
26
|
+
await symlink(git, join(bin, 'git'));
|
|
27
|
+
process.env.PATH = bin;
|
|
28
|
+
// The binaries are checked before the configuration is read, so none is needed.
|
|
29
|
+
const err = (await createCoreServices({} as TenantConfig).catch((e: unknown) => e)) as Error;
|
|
30
|
+
expect(err).toBeInstanceOf(Error);
|
|
31
|
+
expect(err.message).toMatch(/^ripgrep \(`rg`\) is required on the server's PATH but could not be run: .*ENOENT/);
|
|
32
|
+
expect(err.message).toContain('The Hexis Dockerfile installs it');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -4,6 +4,7 @@ import type { Server } from 'node:http';
|
|
|
4
4
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
5
|
import type { SkillSummary } from '../../modules/skills/skills.contract.js';
|
|
6
6
|
import { catalogRevision, createCatalogRevisionRoutes } from '../catalog-revision.js';
|
|
7
|
+
import { agentFile, agentScopeOver, inMemoryKb, type InMemoryKb } from '../../modules/agent-scope/__tests__/in-memory-kb.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* The fingerprint a long-lived client polls to learn that the released catalog
|
|
@@ -228,3 +229,91 @@ describe('GET /agent/catalog-revision', () => {
|
|
|
228
229
|
expect(await res.json()).toEqual({ revision: catalogRevision([], []), tools: 0, skills: 0 });
|
|
229
230
|
});
|
|
230
231
|
});
|
|
232
|
+
|
|
233
|
+
describe('GET /agent/catalog-revision, for a connection made as an .agent file', () => {
|
|
234
|
+
let http: Server | null = null;
|
|
235
|
+
|
|
236
|
+
afterEach(async () => {
|
|
237
|
+
if (http) await new Promise<void>((resolve) => http!.close(() => resolve()));
|
|
238
|
+
http = null;
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const lines = [
|
|
242
|
+
['ops', 'ops', 'Plugins/Ops/ops.tool', 'http', 'remote', '', 's'].join('\u0000'),
|
|
243
|
+
['crm', 'crm', 'Plugins/Sales/crm.tool', 'http', 'remote', '', 's'].join('\u0000'),
|
|
244
|
+
];
|
|
245
|
+
const paths = ['Plugins/Ops/ops.tool', 'Plugins/Sales/crm.tool'];
|
|
246
|
+
const skills = [skill({ name: 'notes', path: 'Skills/Release/notes' }), skill({ name: 'pitch', path: 'Skills/Sales/pitch' })];
|
|
247
|
+
|
|
248
|
+
async function mount(kb: InMemoryKb, agentPath: string | undefined) {
|
|
249
|
+
// The two services narrow by the predicate they are handed, AFTER their
|
|
250
|
+
// own read gate — stood in for here by the lists above, all readable.
|
|
251
|
+
const catalogFingerprints = vi.fn(async (_email: string, within?: (p: string) => boolean) =>
|
|
252
|
+
lines.filter((_, i) => !within || within(paths[i]!)),
|
|
253
|
+
);
|
|
254
|
+
const listSkills = vi.fn(async (_email: string, opts?: { within?: (p: string) => boolean }) =>
|
|
255
|
+
skills.filter((s) => !opts?.within || opts.within(s.path)),
|
|
256
|
+
);
|
|
257
|
+
const agentScope = agentScopeOver(kb);
|
|
258
|
+
const resolve = vi.spyOn(agentScope, 'resolve');
|
|
259
|
+
const app = express();
|
|
260
|
+
app.use(
|
|
261
|
+
createCatalogRevisionRoutes({
|
|
262
|
+
toolManuals: { catalogFingerprints } as never,
|
|
263
|
+
skills: { listSkills } as never,
|
|
264
|
+
manualAuth: (req, _res, next) => {
|
|
265
|
+
req.toolAuth = { userId: 'u1', ...(agentPath ? { agentPath } : {}) } as never;
|
|
266
|
+
next();
|
|
267
|
+
},
|
|
268
|
+
resolveUserEmail: async () => 'ada@example.com',
|
|
269
|
+
agentScope,
|
|
270
|
+
}),
|
|
271
|
+
);
|
|
272
|
+
http = app.listen(0);
|
|
273
|
+
await new Promise<void>((r) => http!.once('listening', r));
|
|
274
|
+
const url = `http://127.0.0.1:${(http.address() as AddressInfo).port}/agent/catalog-revision`;
|
|
275
|
+
const read = async () =>
|
|
276
|
+
(await (await fetch(url)).json()) as { revision: string; tools: number; skills: number; connection?: unknown };
|
|
277
|
+
return { read, catalogFingerprints, listSkills, resolve };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
it('Everything is the revision it always was: nothing resolved, nothing narrowed, no `connection`', async () => {
|
|
281
|
+
const { read, catalogFingerprints, listSkills, resolve } = await mount(inMemoryKb({}), undefined);
|
|
282
|
+
expect(await read()).toEqual({ revision: catalogRevision(lines, skills), tools: 2, skills: 2 });
|
|
283
|
+
expect(catalogFingerprints).toHaveBeenCalledWith('ada@example.com');
|
|
284
|
+
expect(listSkills).toHaveBeenCalledWith('ada@example.com');
|
|
285
|
+
expect(resolve).not.toHaveBeenCalled();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it("is the fingerprint of what the agent loads, and names the agent", async () => {
|
|
289
|
+
const kb = inMemoryKb({ 'Agents/ops.agent': agentFile('name: ops\nconnectors: [Plugins/Ops]\nskills: [Skills/Release]') });
|
|
290
|
+
const { read } = await mount(kb, 'Agents/ops.agent');
|
|
291
|
+
const body = await read();
|
|
292
|
+
expect(body.tools).toBe(1);
|
|
293
|
+
expect(body.skills).toBe(1);
|
|
294
|
+
expect(body.connection).toEqual({ agent: { path: 'Agents/ops.agent', name: 'ops' } });
|
|
295
|
+
expect(body.revision).not.toBe(catalogRevision(lines, skills));
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('moves at the next read after the .agent file is edited — no reconnect', async () => {
|
|
299
|
+
const kb = inMemoryKb({ 'Agents/ops.agent': agentFile('connectors: [Plugins/Ops]') });
|
|
300
|
+
const { read } = await mount(kb, 'Agents/ops.agent');
|
|
301
|
+
const before = await read();
|
|
302
|
+
expect(await read()).toEqual(before);
|
|
303
|
+
kb.files.set('Agents/ops.agent', agentFile('connectors: [Plugins/Ops]\nskills: [Skills/Sales]'));
|
|
304
|
+
const after = await read();
|
|
305
|
+
expect(after.revision).not.toBe(before.revision);
|
|
306
|
+
expect(after.skills).toBe(1);
|
|
307
|
+
// Even an edit that changes nothing listed moves it: the file is the configuration.
|
|
308
|
+
kb.files.set('Agents/ops.agent', agentFile('connectors: [Plugins/Ops]\nskills: [Skills/Sales]\ndescription: now described'));
|
|
309
|
+
expect((await read()).revision).not.toBe(after.revision);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('a deleted file is an empty catalog with the reason, never Everything', async () => {
|
|
313
|
+
const { read } = await mount(inMemoryKb({}), 'Agents/gone.agent');
|
|
314
|
+
const body = await read();
|
|
315
|
+
expect(body.tools).toBe(0);
|
|
316
|
+
expect(body.skills).toBe(0);
|
|
317
|
+
expect((body.connection as { unavailable?: string }).unavailable).toMatch(/no longer exists or which you can no longer read/);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
@@ -16,7 +16,7 @@ import { RoutineWritePolicyService } from '../../modules/workspace/routine-write
|
|
|
16
16
|
import { WorkflowHooks } from '../../modules/workflow/workflow-hooks.js';
|
|
17
17
|
import { ToolDescriptionNotes } from '../../modules/workspace/agent-access.gate.js';
|
|
18
18
|
import { SpillStore } from '../../modules/workspace/spill-store.js';
|
|
19
|
-
import {
|
|
19
|
+
import { RipgrepPatternMatcher } from '../../modules/workspace/index.js';
|
|
20
20
|
import { DocExtractService, type UnreadableDocument } from '../../modules/workspace/file-readers/doc-extract.service.js';
|
|
21
21
|
import type { IDocumentExtractor } from '../../modules/workspace/file-readers/document-extractor.contract.js';
|
|
22
22
|
import { WorkerDocumentExtractor, type WorkerDocumentExtractorOptions } from '../../modules/workspace/file-readers/extract-in-worker.js';
|
|
@@ -82,7 +82,7 @@ async function startPlatform(extractorOpts: WorkerDocumentExtractorOptions = {})
|
|
|
82
82
|
};
|
|
83
83
|
const told: UnreadableDocument[] = [];
|
|
84
84
|
const docExtract = new DocExtractService(join(tempDir, '.doc-extract'), counting, { onUnreadable: (d) => told.push(d) });
|
|
85
|
-
const matcher = new
|
|
85
|
+
const matcher = new RipgrepPatternMatcher();
|
|
86
86
|
|
|
87
87
|
const registry = new ToolRegistry();
|
|
88
88
|
const resolve = async (auth: ToolAuth, signal: AbortSignal, sessionId?: string): Promise<ToolContext> => ({
|
|
@@ -37,7 +37,7 @@ afterEach(async () => {
|
|
|
37
37
|
|
|
38
38
|
/** A core whose startup phase fails in a way the test picks. */
|
|
39
39
|
function bootable(runAll: () => Promise<void>) {
|
|
40
|
-
const retries = { started: 0 };
|
|
40
|
+
const retries = { started: 0, tmpSweeps: 0 };
|
|
41
41
|
const core: BootableCore = {
|
|
42
42
|
config: { workspacesRoot },
|
|
43
43
|
kbDirName: 'knowledge-base',
|
|
@@ -53,6 +53,11 @@ function bootable(runAll: () => Promise<void>) {
|
|
|
53
53
|
tidyAfterSweep: async () => ({ closedEmpty: 0, removedLeftovers: 0 }),
|
|
54
54
|
} as BootableCore['workflowService'],
|
|
55
55
|
pluginJoinRequestJobs: { startSweeping() {} } as BootableCore['pluginJoinRequestJobs'],
|
|
56
|
+
tmpSweeper: {
|
|
57
|
+
startSweeping() {
|
|
58
|
+
retries.tmpSweeps += 1;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
56
61
|
startupRetry: null,
|
|
57
62
|
};
|
|
58
63
|
return { core, retries };
|
|
@@ -79,6 +84,8 @@ describe('startCore over a repository the host will not serve', () => {
|
|
|
79
84
|
// that is granted access to it, needs no settings change on this side.
|
|
80
85
|
expect(retries.started).toBe(1);
|
|
81
86
|
expect(core.startupRetry).not.toBeNull();
|
|
87
|
+
// The tmp sweep reads the workspaces root alone, so a gated boot still runs it.
|
|
88
|
+
expect(retries.tmpSweeps).toBe(1);
|
|
82
89
|
});
|
|
83
90
|
|
|
84
91
|
it('comes up gated when the host rejected the credentials', async () => {
|