@bevel-software/platform-core-backend 0.33.0 → 0.34.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 +19 -8
- package/agent-guide/html-views.md +231 -5
- package/agent-guide/tool-manuals.md +1 -1
- 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 +14 -7
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +16 -5
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +37 -12
- 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 +17 -9
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +12 -2
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +164 -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 +35 -29
- 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/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.tools.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.js +13 -3
- package/dist/modules/agent-guide/agent-guide.tools.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 +3 -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 +16 -1
- 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/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 +68 -13
- 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/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 +15 -3
- package/dist/modules/secrets-vault/secrets-vault.routes.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 +24 -12
- 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-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/tool-manuals.contract.d.ts +19 -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 +13 -6
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +23 -15
- package/dist/modules/tool-manuals/tool-manuals.service.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 +25 -10
- 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 +14 -9
- 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/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.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +460 -116
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- 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/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 +3 -3
- package/src/__tests__/pg-scratch.test.ts +69 -0
- package/src/__tests__/pg-scratch.ts +31 -0
- package/src/__tests__/slow-ripgrep.ts +65 -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/catalog-revision.ts +24 -2
- package/src/core/core-ports.ts +42 -0
- package/src/core/create-core-server.ts +13 -0
- package/src/core/create-core-services.ts +49 -12
- 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 +2 -0
- 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__/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 +17 -10
- package/src/modules/access/access-control.service.ts +158 -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 +43 -33
- 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/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 +31 -0
- package/src/modules/agent-guide/agent-guide.tools.ts +13 -2
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +1 -0
- package/src/modules/agent-instructions/compose.ts +3 -1
- package/src/modules/agent-instructions/shared-file-rules.ts +17 -1
- 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/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 +107 -17
- 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/secrets-vault.routes.ts +23 -3
- 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 +44 -13
- 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__/can-write.tools.test.ts +3 -1
- package/src/modules/tool-helpers/tool-context.ts +10 -0
- 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.service.test.ts +42 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +3 -3
- package/src/modules/tool-manuals/index.ts +6 -2
- package/src/modules/tool-manuals/tool-manuals.contract.ts +18 -6
- package/src/modules/tool-manuals/tool-manuals.routes.ts +40 -3
- package/src/modules/tool-manuals/tool-manuals.service.ts +31 -15
- package/src/modules/tool-manuals/tool-manuals.tools.ts +28 -11
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +2 -2
- 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 +14 -9
- 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 +2 -2
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +22 -10
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +393 -113
- 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 +500 -155
- package/src/shared/path-order.ts +37 -8
- 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/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
|
@@ -8,6 +8,8 @@ import os from 'node:os';
|
|
|
8
8
|
import type { WorkspaceService } from '../../../workspace/workspace.service.js';
|
|
9
9
|
import { WorkflowHooks } from '../../workflow-hooks.js';
|
|
10
10
|
import { GitService } from '../git.service.js';
|
|
11
|
+
import { NodeGitRunner } from '../node-git-runner.js';
|
|
12
|
+
import type { IGitRunner } from '../../../../shared/git.contract.js';
|
|
11
13
|
|
|
12
14
|
const execFileAsync = promisify(execFile);
|
|
13
15
|
|
|
@@ -155,7 +157,7 @@ describe('GitService.listBranches', () => {
|
|
|
155
157
|
expect(names).toEqual(['alice/draft-one', 'current-company-state', 'target-company-state']);
|
|
156
158
|
});
|
|
157
159
|
|
|
158
|
-
it('returns local branches before remote-only ones,
|
|
160
|
+
it('returns local branches before remote-only ones, then alphabetically', async () => {
|
|
159
161
|
await seedWorkspace(root, workspaceId);
|
|
160
162
|
const svc = new GitService(
|
|
161
163
|
stubWorkspaceService(workspaceId, path.join(root, workspaceId)),
|
|
@@ -165,8 +167,7 @@ describe('GitService.listBranches', () => {
|
|
|
165
167
|
|
|
166
168
|
// current-company-state is the workspace clone's checked-out branch (the
|
|
167
169
|
// only local head); the rest are remote-only. The result order must be
|
|
168
|
-
// local-first then alphabetical
|
|
169
|
-
// with `Promise.all`, so this pins that the mapping preserves row order.
|
|
170
|
+
// local-first then alphabetical.
|
|
170
171
|
const branches = await svc.listBranches(workspaceId);
|
|
171
172
|
expect(branches.map((b) => b.name)).toEqual([
|
|
172
173
|
'current-company-state',
|
|
@@ -231,4 +232,130 @@ describe('GitService.listBranches', () => {
|
|
|
231
232
|
expect.arrayContaining([expect.objectContaining({ name: 'alice/draft-one' })]),
|
|
232
233
|
);
|
|
233
234
|
});
|
|
235
|
+
|
|
236
|
+
// A listing names branches; it counts nothing. Counting cost one to three
|
|
237
|
+
// `rev-list` spawns a branch — about 120 git processes a listing on a
|
|
238
|
+
// knowledge base with 121 branches — for numbers no listing reader shows.
|
|
239
|
+
it('runs no git per branch: a listing over many branches spawns the same few commands as one over three', async () => {
|
|
240
|
+
const { upstream } = await seedWorkspace(root, workspaceId);
|
|
241
|
+
const pusher = path.join(root, '.pusher');
|
|
242
|
+
await runGit(root, ['clone', upstream, pusher]);
|
|
243
|
+
const drafts = Array.from({ length: 12 }, (_, i) => `team/draft-${String(i).padStart(2, '0')}`);
|
|
244
|
+
for (const d of drafts) {
|
|
245
|
+
await runGit(pusher, ['checkout', '-q', '-b', d, 'origin/current-company-state']);
|
|
246
|
+
await runGit(pusher, ['commit', '--allow-empty', '-m', d]);
|
|
247
|
+
}
|
|
248
|
+
await runGit(pusher, ['push', '-q', 'origin', ...drafts]);
|
|
249
|
+
// The workspace's own branch carries an upstream and local commits too:
|
|
250
|
+
// exactly what the old listing counted against.
|
|
251
|
+
const repo = path.join(root, workspaceId, 'knowledge-base');
|
|
252
|
+
await runGit(repo, ['commit', '--allow-empty', '-m', 'unshared']);
|
|
253
|
+
|
|
254
|
+
const { runner, commands } = recordingRunner();
|
|
255
|
+
const svc = new GitService(
|
|
256
|
+
stubWorkspaceService(workspaceId, path.join(root, workspaceId)),
|
|
257
|
+
new WorkflowHooks(),
|
|
258
|
+
testKbContext(),
|
|
259
|
+
undefined,
|
|
260
|
+
null,
|
|
261
|
+
runner,
|
|
262
|
+
);
|
|
263
|
+
const branches = await svc.listBranches(workspaceId);
|
|
264
|
+
|
|
265
|
+
expect(branches.map((b) => b.name)).toEqual([
|
|
266
|
+
'current-company-state',
|
|
267
|
+
'alice/draft-one',
|
|
268
|
+
'target-company-state',
|
|
269
|
+
...drafts,
|
|
270
|
+
]);
|
|
271
|
+
expect(branches[0]).toEqual({ name: 'current-company-state', isProtected: true, hasRemote: true });
|
|
272
|
+
for (const b of branches) expect(Object.keys(b).sort()).toEqual(['hasRemote', 'isProtected', 'name']);
|
|
273
|
+
expect(commands.filter((c) => c === 'rev-list')).toEqual([]);
|
|
274
|
+
// Its fetch, and the two reads of what the repository holds — whatever
|
|
275
|
+
// the number of branches.
|
|
276
|
+
expect([...commands].sort()).toEqual(['fetch', 'for-each-ref', 'symbolic-ref']);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
/** The real runner, recording the subcommand of every git it is asked to run. */
|
|
281
|
+
function recordingRunner(): { runner: IGitRunner; commands: string[] } {
|
|
282
|
+
const inner = new NodeGitRunner();
|
|
283
|
+
const commands: string[] = [];
|
|
284
|
+
const runner = {
|
|
285
|
+
defaultTimeoutMs: inner.defaultTimeoutMs,
|
|
286
|
+
credentials: inner.credentials,
|
|
287
|
+
run: async (cwd: string, args: string[], opts?: object) => {
|
|
288
|
+
// Skip `-c key=value` pairs: the subcommand is the first bare word.
|
|
289
|
+
let i = 0;
|
|
290
|
+
while (i < args.length && args[i].startsWith('-')) i += args[i] === '-c' ? 2 : 1;
|
|
291
|
+
commands.push(args[i] ?? '');
|
|
292
|
+
return inner.run(cwd, args, opts as never);
|
|
293
|
+
},
|
|
294
|
+
} as unknown as IGitRunner;
|
|
295
|
+
return { runner, commands };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
describe('GitService.branchCounts', () => {
|
|
299
|
+
let root: string;
|
|
300
|
+
|
|
301
|
+
beforeEach(async () => {
|
|
302
|
+
root = await mkTmpRoot();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
afterEach(async () => {
|
|
306
|
+
await fs.rm(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const draftWs = encodeURIComponent('alice/draft-one');
|
|
310
|
+
|
|
311
|
+
/** The draft's own workspace, on the draft, three commits ahead of what it shared. */
|
|
312
|
+
async function seedDraft(): Promise<{ upstream: string; repo: string }> {
|
|
313
|
+
const { upstream, repo } = await seedWorkspace(root, draftWs);
|
|
314
|
+
await runGit(repo, ['checkout', '-q', 'alice/draft-one']);
|
|
315
|
+
for (const m of ['one', 'two', 'three']) await runGit(repo, ['commit', '--allow-empty', '-m', m]);
|
|
316
|
+
return { upstream, repo };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function svcFor(runner: IGitRunner = new NodeGitRunner(), kb = testKbContext()): GitService {
|
|
320
|
+
return new GitService(stubWorkspaceService(draftWs, path.join(root, draftWs)), new WorkflowHooks(), kb, undefined, null, runner);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
it('counts the workspace\'s own branch against its upstream, with rev-list for that branch alone', async () => {
|
|
324
|
+
const { upstream, repo } = await seedDraft();
|
|
325
|
+
// A teammate shares one commit on the same draft, which this clone fetches.
|
|
326
|
+
const pusher = path.join(root, '.pusher');
|
|
327
|
+
await runGit(root, ['clone', '-q', '-b', 'alice/draft-one', upstream, pusher]);
|
|
328
|
+
await runGit(pusher, ['commit', '--allow-empty', '-m', 'teammate']);
|
|
329
|
+
await runGit(pusher, ['push', '-q', 'origin', 'alice/draft-one']);
|
|
330
|
+
await runGit(repo, ['fetch', '-q', 'origin']);
|
|
331
|
+
|
|
332
|
+
const { runner, commands } = recordingRunner();
|
|
333
|
+
await expect(svcFor(runner).branchCounts(draftWs)).resolves.toEqual({ ahead: 3, behind: 1 });
|
|
334
|
+
// The upstream resolved, so one count was enough.
|
|
335
|
+
expect(commands.filter((c) => c === 'rev-list')).toHaveLength(1);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('falls back to the protected branch on origin it is fewest commits ahead of when it has no upstream', async () => {
|
|
339
|
+
const { upstream, repo } = await seedDraft();
|
|
340
|
+
await runGit(repo, ['branch', '--unset-upstream']);
|
|
341
|
+
// `target-company-state` moves on by two commits; `current-company-state` stays.
|
|
342
|
+
const pusher = path.join(root, '.pusher');
|
|
343
|
+
await runGit(root, ['clone', '-q', '-b', 'target-company-state', upstream, pusher]);
|
|
344
|
+
for (const m of ['t1', 't2']) await runGit(pusher, ['commit', '--allow-empty', '-m', m]);
|
|
345
|
+
await runGit(pusher, ['push', '-q', 'origin', 'target-company-state']);
|
|
346
|
+
await runGit(repo, ['fetch', '-q', 'origin']);
|
|
347
|
+
|
|
348
|
+
const { runner, commands } = recordingRunner();
|
|
349
|
+
// Three ahead of both; ties keep the first protected branch, which is behind by nothing.
|
|
350
|
+
await expect(svcFor(runner).branchCounts(draftWs)).resolves.toEqual({ ahead: 3, behind: 0 });
|
|
351
|
+
// The upstream it tried, then each protected branch.
|
|
352
|
+
expect(commands.filter((c) => c === 'rev-list')).toHaveLength(3);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('answers null for a branch never shared, with no protected base to count against', async () => {
|
|
356
|
+
const { repo } = await seedDraft();
|
|
357
|
+
await runGit(repo, ['branch', '--unset-upstream']);
|
|
358
|
+
const kb = testKbContext({ branchModel: { defaultBranch: 'main', protectedBranches: ['main'] } });
|
|
359
|
+
await expect(svcFor(undefined, kb).branchCounts(draftWs)).resolves.toEqual({ ahead: null, behind: null });
|
|
360
|
+
});
|
|
234
361
|
});
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
AppliedChangeRef,
|
|
6
6
|
AppliedMergeResult,
|
|
7
7
|
AuthUser,
|
|
8
|
+
BranchCounts,
|
|
8
9
|
BranchInfo,
|
|
9
10
|
ChangedPathPair,
|
|
10
11
|
CommitAttribution,
|
|
@@ -60,6 +61,7 @@ import {
|
|
|
60
61
|
} from '../../../shared/git.contract.js';
|
|
61
62
|
import { NodeGitRunner } from './node-git-runner.js';
|
|
62
63
|
import { printable } from '../../../shared/printable.js';
|
|
64
|
+
import { branchForWorkspaceId } from '../../../shared/workspace-id.js';
|
|
63
65
|
import { sanitizeError } from '../sanitize-error.js';
|
|
64
66
|
|
|
65
67
|
const log = logger('git');
|
|
@@ -292,11 +294,6 @@ export class GitService implements IGitService {
|
|
|
292
294
|
/** Whether the last implicit fetch per workspace SUCCEEDED — see `fetchOriginIfStale`. */
|
|
293
295
|
private readonly lastImplicitFetchOk = new Map<string, boolean>();
|
|
294
296
|
private static readonly IMPLICIT_FETCH_TTL_MS = 5_000;
|
|
295
|
-
// Cap on concurrent `aheadBehindForBranch` calls inside `listBranches`. Each
|
|
296
|
-
// call serializes up to 3 `git rev-list` spawns, so 8 workers ≈ ≤24
|
|
297
|
-
// concurrent processes worst case — fast for typical (<8) feature-branch
|
|
298
|
-
// counts, calm under large branch lists.
|
|
299
|
-
private static readonly MAX_AHEAD_BEHIND_CONCURRENCY = 8;
|
|
300
297
|
|
|
301
298
|
/**
|
|
302
299
|
* A change request's changed entries, keyed by the two commits its diff
|
|
@@ -545,7 +542,7 @@ export class GitService implements IGitService {
|
|
|
545
542
|
)
|
|
546
543
|
).trim();
|
|
547
544
|
|
|
548
|
-
type Row = { shortName: string;
|
|
545
|
+
type Row = { shortName: string; hasLocal: boolean; hasRemote: boolean };
|
|
549
546
|
const buckets = new Map<string, Row>();
|
|
550
547
|
for (const line of stdout.split('\n')) {
|
|
551
548
|
const trimmed = line.trim();
|
|
@@ -573,16 +570,12 @@ export class GitService implements IGitService {
|
|
|
573
570
|
if (!existing) {
|
|
574
571
|
buckets.set(shortName, {
|
|
575
572
|
shortName,
|
|
576
|
-
ref,
|
|
577
573
|
hasLocal: isLocal,
|
|
578
574
|
hasRemote: !isLocal,
|
|
579
575
|
});
|
|
580
576
|
continue;
|
|
581
577
|
}
|
|
582
|
-
// Prefer the local entry's ref when both exist — ahead/behind against the
|
|
583
|
-
// configured upstream is more meaningful than against origin directly.
|
|
584
578
|
if (isLocal && !existing.hasLocal) {
|
|
585
|
-
existing.ref = ref;
|
|
586
579
|
existing.hasLocal = true;
|
|
587
580
|
} else if (!isLocal) {
|
|
588
581
|
existing.hasRemote = true;
|
|
@@ -594,36 +587,14 @@ export class GitService implements IGitService {
|
|
|
594
587
|
return a.shortName.localeCompare(b.shortName);
|
|
595
588
|
});
|
|
596
589
|
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
await Promise.all(
|
|
606
|
-
Array.from({ length: workerCount }, async () => {
|
|
607
|
-
while (true) {
|
|
608
|
-
const i = nextIndex++;
|
|
609
|
-
if (i >= rows.length) return;
|
|
610
|
-
const row = rows[i];
|
|
611
|
-
const { ahead, behind } = await this.aheadBehindForBranch(
|
|
612
|
-
cwd,
|
|
613
|
-
row.shortName,
|
|
614
|
-
row.ref,
|
|
615
|
-
row.hasLocal,
|
|
616
|
-
);
|
|
617
|
-
infos[i] = {
|
|
618
|
-
name: row.shortName,
|
|
619
|
-
isProtected: this.kb.isProtectedBranch(row.shortName),
|
|
620
|
-
ahead,
|
|
621
|
-
behind,
|
|
622
|
-
hasRemote: row.hasRemote,
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
}),
|
|
626
|
-
);
|
|
590
|
+
// No git per branch: commit counts are not part of a listing (they cost
|
|
591
|
+
// one to three `rev-list` spawns a branch, over every branch the
|
|
592
|
+
// repository has). The one branch that wants them asks `branchCounts`.
|
|
593
|
+
const infos: BranchInfo[] = rows.map((row) => ({
|
|
594
|
+
name: row.shortName,
|
|
595
|
+
isProtected: this.kb.isProtectedBranch(row.shortName),
|
|
596
|
+
hasRemote: row.hasRemote,
|
|
597
|
+
}));
|
|
627
598
|
// Every name this listing showed — origin's refs and the local heads
|
|
628
599
|
// alike, since a branch checked out here is one the platform has
|
|
629
600
|
// plainly heard of. A listener that misbehaves must not turn a good
|
|
@@ -639,6 +610,24 @@ export class GitService implements IGitService {
|
|
|
639
610
|
});
|
|
640
611
|
}
|
|
641
612
|
|
|
613
|
+
async branchCounts(workspaceId: string): Promise<BranchCounts> {
|
|
614
|
+
return this.mutex.run(workspaceId, async () => {
|
|
615
|
+
const cwd = await this.repoDir(workspaceId);
|
|
616
|
+
const branch = branchForWorkspaceId(workspaceId);
|
|
617
|
+
// The workspace's own branch is its local head while it is checked out;
|
|
618
|
+
// otherwise only origin's ref names it — as a listing would read it.
|
|
619
|
+
const ownBranch = (
|
|
620
|
+
await this.git(cwd, ['symbolic-ref', '--quiet', '--short', 'HEAD']).then(
|
|
621
|
+
(r) => r.stdout,
|
|
622
|
+
() => '',
|
|
623
|
+
)
|
|
624
|
+
).trim();
|
|
625
|
+
return ownBranch === branch
|
|
626
|
+
? this.aheadBehindForBranch(cwd, branch, `refs/heads/${branch}`, true)
|
|
627
|
+
: this.aheadBehindForBranch(cwd, branch, `refs/remotes/origin/${branch}`, false);
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
|
|
642
631
|
/**
|
|
643
632
|
* Run `git fetch --prune origin` outside the workspace mutex, with a short
|
|
644
633
|
* TTL so back-to-back callers (mount + dropdown-open + 30s poll) coalesce
|
|
@@ -757,12 +746,6 @@ export class GitService implements IGitService {
|
|
|
757
746
|
await this.git(cwd, ['branch', '-D', name]).catch(() => undefined);
|
|
758
747
|
throw err;
|
|
759
748
|
}
|
|
760
|
-
const { ahead, behind } = await this.aheadBehindForBranch(
|
|
761
|
-
cwd,
|
|
762
|
-
name,
|
|
763
|
-
`refs/heads/${name}`,
|
|
764
|
-
true,
|
|
765
|
-
);
|
|
766
749
|
// Drop the now-vestigial local head. Under the per-branch workspace model
|
|
767
750
|
// this clone's identity is its OWN branch; the new draft lives in its own
|
|
768
751
|
// workspace (cloned from origin on first navigation), so this clone never
|
|
@@ -782,8 +765,6 @@ export class GitService implements IGitService {
|
|
|
782
765
|
return {
|
|
783
766
|
name,
|
|
784
767
|
isProtected: false,
|
|
785
|
-
ahead,
|
|
786
|
-
behind,
|
|
787
768
|
hasRemote: true,
|
|
788
769
|
};
|
|
789
770
|
});
|
|
@@ -37,6 +37,7 @@ import type {
|
|
|
37
37
|
AcquireLockResult,
|
|
38
38
|
AuthUser,
|
|
39
39
|
Branch,
|
|
40
|
+
BranchCounts,
|
|
40
41
|
BranchSyncOutcome,
|
|
41
42
|
BranchWorkspaceStatus,
|
|
42
43
|
CancelChangeRequestResult,
|
|
@@ -932,6 +933,10 @@ export class WorkflowService implements IWorkflowService {
|
|
|
932
933
|
return this.git.status(workspaceId);
|
|
933
934
|
}
|
|
934
935
|
|
|
936
|
+
branchCounts(workspaceId: string): Promise<BranchCounts> {
|
|
937
|
+
return this.git.branchCounts(workspaceId);
|
|
938
|
+
}
|
|
939
|
+
|
|
935
940
|
// `discardWorkingChanges` removed: under save=share there's nothing dirty
|
|
936
941
|
// to discard.
|
|
937
942
|
|
|
@@ -36,11 +36,11 @@ import { createDiffRoutes } from '../../diff/diff.routes.js';
|
|
|
36
36
|
import { DiffService } from '../../diff/diff.service.js';
|
|
37
37
|
import { WorkspaceMutex } from '../../kb-fs/mutex.js';
|
|
38
38
|
import { WorkspaceService } from '../workspace.service.js';
|
|
39
|
-
import {
|
|
39
|
+
import { RipgrepPatternMatcher } from '../index.js';
|
|
40
40
|
import { newWorkspaceService } from '../../../__tests__/workspace-service.js';
|
|
41
41
|
|
|
42
42
|
/** The grep matcher this file's harness wires, closed once the file is done. */
|
|
43
|
-
const patternMatcher = new
|
|
43
|
+
const patternMatcher = new RipgrepPatternMatcher();
|
|
44
44
|
afterAll(() => patternMatcher.close());
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { lstat, mkdtemp, rename, rm, symlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { holdsNul } from '../nul-scan.js';
|
|
6
|
+
import { PatternTooExpensiveError, type IPatternSearch } from '../pattern-matcher.contract.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The unit `grep` asks whether a named text file ripgrep answered no line from
|
|
10
|
+
* is binary (`nul-scan.ts`). What a caller observes — a NUL past the first
|
|
11
|
+
* chunk makes the answer "no searchable text" — is pinned through the grep
|
|
12
|
+
* tool itself in `workspace.tools.test.ts`. Two properties stay here because
|
|
13
|
+
* no caller can stage them: the file swapped for another, or for a link,
|
|
14
|
+
* between the stat that judged it and the open that reads it is a race a tool
|
|
15
|
+
* call cannot time; and a budget already spent is told apart from ripgrep's
|
|
16
|
+
* own spending only by handing the unit a search whose budget is gone.
|
|
17
|
+
*/
|
|
18
|
+
let dir = '';
|
|
19
|
+
const free: IPatternSearch = {
|
|
20
|
+
files: () => (async function* () {})(),
|
|
21
|
+
list: async () => [],
|
|
22
|
+
matchingLines: async (texts) => texts.map(() => []),
|
|
23
|
+
charged: (work) => work(),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
dir = await mkdtemp(join(tmpdir(), 'holds-nul-'));
|
|
28
|
+
});
|
|
29
|
+
afterEach(async () => {
|
|
30
|
+
await rm(dir, { recursive: true, force: true });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('holdsNul', () => {
|
|
34
|
+
it('finds a NUL wherever it is, past the first chunk too, and answers false for text', async () => {
|
|
35
|
+
const text = join(dir, 'text.md');
|
|
36
|
+
const late = join(dir, 'late.bin');
|
|
37
|
+
await writeFile(text, 'plain text\n'.repeat(20_000));
|
|
38
|
+
await writeFile(late, Buffer.concat([Buffer.alloc(200 * 1024, 'x'), Buffer.from([0])]));
|
|
39
|
+
expect(await holdsNul(text, await lstat(text), free)).toBe(false);
|
|
40
|
+
expect(await holdsNul(late, await lstat(late), free)).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it.skipIf(process.platform === 'win32')('reads nothing from a file swapped in since it was judged, nor through a link', async () => {
|
|
44
|
+
const p = join(dir, 'named.md');
|
|
45
|
+
await writeFile(p, 'text\n');
|
|
46
|
+
const judged = await lstat(p);
|
|
47
|
+
// Another file holding a NUL, moved in under the judged name.
|
|
48
|
+
await writeFile(join(dir, 'other'), Buffer.from([0]));
|
|
49
|
+
await rename(join(dir, 'other'), p);
|
|
50
|
+
expect(await holdsNul(p, judged, free)).toBe(false);
|
|
51
|
+
// A link to a file holding a NUL, under the judged name.
|
|
52
|
+
await writeFile(join(dir, 'outside'), Buffer.from([0]));
|
|
53
|
+
await rm(p);
|
|
54
|
+
await symlink(join(dir, 'outside'), p);
|
|
55
|
+
expect(await holdsNul(p, judged, free)).toBe(false);
|
|
56
|
+
expect(await holdsNul(p, await lstat(join(dir, 'outside')), free)).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('runs under the search budget: a budget already spent answers for it', async () => {
|
|
60
|
+
const p = join(dir, 'named.md');
|
|
61
|
+
await writeFile(p, 'text\n');
|
|
62
|
+
const spent = new PatternTooExpensiveError('needle', 5_000);
|
|
63
|
+
const exhausted: IPatternSearch = { ...free, charged: () => Promise.reject(spent) };
|
|
64
|
+
await expect(holdsNul(p, await lstat(p), exhausted)).rejects.toBe(spent);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -22,10 +22,10 @@ import { AccessControlService } from '../../access/access-control.service.js';
|
|
|
22
22
|
import { NodeFs } from '../../kb-fs/node-fs.js';
|
|
23
23
|
import { BRANCH_REQUIRED_MESSAGE } from '../../../shared/domain-errors.js';
|
|
24
24
|
import { callLine, compileCheck, exampleArguments } from '@bevel-software/platform-mcp-core';
|
|
25
|
-
import {
|
|
25
|
+
import { RipgrepPatternMatcher } from '../index.js';
|
|
26
26
|
|
|
27
27
|
/** The grep matcher this file's harness wires, closed once the file is done. */
|
|
28
|
-
const patternMatcher = new
|
|
28
|
+
const patternMatcher = new RipgrepPatternMatcher();
|
|
29
29
|
afterAll(() => patternMatcher.close());
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -179,7 +179,7 @@ describe('POST /api/agent/tools/<name> checks the arguments against the tool', (
|
|
|
179
179
|
expect(status).toBe(400);
|
|
180
180
|
expect(body.kind).toBe('arguments-do-not-match');
|
|
181
181
|
expect(body.error).toContain('"pattern" is required, and was not given.');
|
|
182
|
-
expect(body.error).toContain('pattern (string, required) —
|
|
182
|
+
expect(body.error).toContain('pattern (string, required) — Regular expression, RE2-style (ripgrep): no look-around, no backreferences.');
|
|
183
183
|
// Not a 200 that matched every file, which is what this surface answered
|
|
184
184
|
// before the check lived in the route.
|
|
185
185
|
expect(body.matches).toBeUndefined();
|