@bevel-software/platform-core-backend 0.1.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/LICENSE +202 -0
- package/dist/assets.d.ts +5 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +23 -0
- package/dist/assets.js.map +1 -0
- package/dist/core/core-ports.d.ts +83 -0
- package/dist/core/core-ports.d.ts.map +1 -0
- package/dist/core/core-ports.js +12 -0
- package/dist/core/core-ports.js.map +1 -0
- package/dist/core/create-core-server.d.ts +62 -0
- package/dist/core/create-core-server.d.ts.map +1 -0
- package/dist/core/create-core-server.js +204 -0
- package/dist/core/create-core-server.js.map +1 -0
- package/dist/core/create-core-services.d.ts +95 -0
- package/dist/core/create-core-services.d.ts.map +1 -0
- package/dist/core/create-core-services.js +352 -0
- package/dist/core/create-core-services.js.map +1 -0
- package/dist/core-config.d.ts +119 -0
- package/dist/core-config.d.ts.map +1 -0
- package/dist/core-config.js +240 -0
- package/dist/core-config.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/access/access-control.interface.d.ts +348 -0
- package/dist/modules/access/access-control.interface.d.ts.map +1 -0
- package/dist/modules/access/access-control.interface.js +2 -0
- package/dist/modules/access/access-control.interface.js.map +1 -0
- package/dist/modules/access/access-control.service.d.ts +323 -0
- package/dist/modules/access/access-control.service.d.ts.map +1 -0
- package/dist/modules/access/access-control.service.js +1431 -0
- package/dist/modules/access/access-control.service.js.map +1 -0
- package/dist/modules/access/access-errors.d.ts +34 -0
- package/dist/modules/access/access-errors.d.ts.map +1 -0
- package/dist/modules/access/access-errors.js +40 -0
- package/dist/modules/access/access-errors.js.map +1 -0
- package/dist/modules/access/access-mutation.service.d.ts +176 -0
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -0
- package/dist/modules/access/access-mutation.service.js +307 -0
- package/dist/modules/access/access-mutation.service.js.map +1 -0
- package/dist/modules/access/access-splice.d.ts +98 -0
- package/dist/modules/access/access-splice.d.ts.map +1 -0
- package/dist/modules/access/access-splice.js +346 -0
- package/dist/modules/access/access-splice.js.map +1 -0
- package/dist/modules/access/access.routes.d.ts +10 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -0
- package/dist/modules/access/access.routes.js +757 -0
- package/dist/modules/access/access.routes.js.map +1 -0
- package/dist/modules/access/creator-access.d.ts +113 -0
- package/dist/modules/access/creator-access.d.ts.map +1 -0
- package/dist/modules/access/creator-access.js +212 -0
- package/dist/modules/access/creator-access.js.map +1 -0
- package/dist/modules/access/kb-read-filter.d.ts +41 -0
- package/dist/modules/access/kb-read-filter.d.ts.map +1 -0
- package/dist/modules/access/kb-read-filter.js +60 -0
- package/dist/modules/access/kb-read-filter.js.map +1 -0
- package/dist/modules/access/roles-admin.service.d.ts +240 -0
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -0
- package/dist/modules/access/roles-admin.service.js +630 -0
- package/dist/modules/access/roles-admin.service.js.map +1 -0
- package/dist/modules/access/roles-edit.d.ts +91 -0
- package/dist/modules/access/roles-edit.d.ts.map +1 -0
- package/dist/modules/access/roles-edit.js +232 -0
- package/dist/modules/access/roles-edit.js.map +1 -0
- package/dist/modules/access/roles-yaml-guard.d.ts +56 -0
- package/dist/modules/access/roles-yaml-guard.d.ts.map +1 -0
- package/dist/modules/access/roles-yaml-guard.js +79 -0
- package/dist/modules/access/roles-yaml-guard.js.map +1 -0
- package/dist/modules/admin/admin-access.routes.d.ts +18 -0
- package/dist/modules/admin/admin-access.routes.d.ts.map +1 -0
- package/dist/modules/admin/admin-access.routes.js +26 -0
- package/dist/modules/admin/admin-access.routes.js.map +1 -0
- package/dist/modules/admin/admin-access.service.d.ts +24 -0
- package/dist/modules/admin/admin-access.service.d.ts.map +1 -0
- package/dist/modules/admin/admin-access.service.js +41 -0
- package/dist/modules/admin/admin-access.service.js.map +1 -0
- package/dist/modules/admin/admin.interface.d.ts +11 -0
- package/dist/modules/admin/admin.interface.d.ts.map +1 -0
- package/dist/modules/admin/admin.interface.js +2 -0
- package/dist/modules/admin/admin.interface.js.map +1 -0
- package/dist/modules/auth/account-erasure.service.d.ts +80 -0
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -0
- package/dist/modules/auth/account-erasure.service.js +91 -0
- package/dist/modules/auth/account-erasure.service.js.map +1 -0
- package/dist/modules/auth/auth.middleware.d.ts +23 -0
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -0
- package/dist/modules/auth/auth.middleware.js +68 -0
- package/dist/modules/auth/auth.middleware.js.map +1 -0
- package/dist/modules/auth/auth.routes.d.ts +25 -0
- package/dist/modules/auth/auth.routes.d.ts.map +1 -0
- package/dist/modules/auth/auth.routes.js +72 -0
- package/dist/modules/auth/auth.routes.js.map +1 -0
- package/dist/modules/auth/auth.service.d.ts +76 -0
- package/dist/modules/auth/auth.service.d.ts.map +1 -0
- package/dist/modules/auth/auth.service.js +168 -0
- package/dist/modules/auth/auth.service.js.map +1 -0
- package/dist/modules/code-mode/code-mode-names.d.ts +16 -0
- package/dist/modules/code-mode/code-mode-names.d.ts.map +1 -0
- package/dist/modules/code-mode/code-mode-names.js +30 -0
- package/dist/modules/code-mode/code-mode-names.js.map +1 -0
- package/dist/modules/code-mode/code-mode.tool.d.ts +13 -0
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -0
- package/dist/modules/code-mode/code-mode.tool.js +112 -0
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -0
- package/dist/modules/code-mode/index.d.ts +3 -0
- package/dist/modules/code-mode/index.d.ts.map +1 -0
- package/dist/modules/code-mode/index.js +3 -0
- package/dist/modules/code-mode/index.js.map +1 -0
- package/dist/modules/database/connection.d.ts +6 -0
- package/dist/modules/database/connection.d.ts.map +1 -0
- package/dist/modules/database/connection.js +12 -0
- package/dist/modules/database/connection.js.map +1 -0
- package/dist/modules/database/core-schema.d.ts +2273 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -0
- package/dist/modules/database/core-schema.js +413 -0
- package/dist/modules/database/core-schema.js.map +1 -0
- package/dist/modules/database/migrate.d.ts +10 -0
- package/dist/modules/database/migrate.d.ts.map +1 -0
- package/dist/modules/database/migrate.js +40 -0
- package/dist/modules/database/migrate.js.map +1 -0
- package/dist/modules/database/schema.d.ts +12 -0
- package/dist/modules/database/schema.d.ts.map +1 -0
- package/dist/modules/database/schema.js +12 -0
- package/dist/modules/database/schema.js.map +1 -0
- package/dist/modules/diff/diff-paths.d.ts +2 -0
- package/dist/modules/diff/diff-paths.d.ts.map +1 -0
- package/dist/modules/diff/diff-paths.js +9 -0
- package/dist/modules/diff/diff-paths.js.map +1 -0
- package/dist/modules/diff/diff.config.d.ts +8 -0
- package/dist/modules/diff/diff.config.d.ts.map +1 -0
- package/dist/modules/diff/diff.config.js +13 -0
- package/dist/modules/diff/diff.config.js.map +1 -0
- package/dist/modules/diff/diff.interface.d.ts +73 -0
- package/dist/modules/diff/diff.interface.d.ts.map +1 -0
- package/dist/modules/diff/diff.interface.js +2 -0
- package/dist/modules/diff/diff.interface.js.map +1 -0
- package/dist/modules/diff/diff.routes.d.ts +35 -0
- package/dist/modules/diff/diff.routes.d.ts.map +1 -0
- package/dist/modules/diff/diff.routes.js +228 -0
- package/dist/modules/diff/diff.routes.js.map +1 -0
- package/dist/modules/diff/diff.service.d.ts +51 -0
- package/dist/modules/diff/diff.service.d.ts.map +1 -0
- package/dist/modules/diff/diff.service.js +489 -0
- package/dist/modules/diff/diff.service.js.map +1 -0
- package/dist/modules/diff/line-diff.d.ts +16 -0
- package/dist/modules/diff/line-diff.d.ts.map +1 -0
- package/dist/modules/diff/line-diff.js +67 -0
- package/dist/modules/diff/line-diff.js.map +1 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +27 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -0
- package/dist/modules/mcp/mcp-auth.middleware.js +116 -0
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -0
- package/dist/modules/mcp/mcp-session-store.d.ts +74 -0
- package/dist/modules/mcp/mcp-session-store.d.ts.map +1 -0
- package/dist/modules/mcp/mcp-session-store.js +131 -0
- package/dist/modules/mcp/mcp-session-store.js.map +1 -0
- package/dist/modules/mcp/mcp.routes.d.ts +24 -0
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -0
- package/dist/modules/mcp/mcp.routes.js +229 -0
- package/dist/modules/mcp/mcp.routes.js.map +1 -0
- package/dist/modules/mcp/mcp.service.d.ts +198 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -0
- package/dist/modules/mcp/mcp.service.js +840 -0
- package/dist/modules/mcp/mcp.service.js.map +1 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +76 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +291 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +18 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +52 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -0
- package/dist/modules/mcp/oauth/oauth-state.d.ts +32 -0
- package/dist/modules/mcp/oauth/oauth-state.d.ts.map +1 -0
- package/dist/modules/mcp/oauth/oauth-state.js +34 -0
- package/dist/modules/mcp/oauth/oauth-state.js.map +1 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +92 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +728 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -0
- package/dist/modules/secrets-vault/index.d.ts +7 -0
- package/dist/modules/secrets-vault/index.d.ts.map +1 -0
- package/dist/modules/secrets-vault/index.js +6 -0
- package/dist/modules/secrets-vault/index.js.map +1 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts +63 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +269 -0
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +46 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.js +87 -0
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +210 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js +90 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +30 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.js +490 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -0
- package/dist/modules/skills/index.d.ts +5 -0
- package/dist/modules/skills/index.d.ts.map +1 -0
- package/dist/modules/skills/index.js +4 -0
- package/dist/modules/skills/index.js.map +1 -0
- package/dist/modules/skills/skills.contract.d.ts +58 -0
- package/dist/modules/skills/skills.contract.d.ts.map +1 -0
- package/dist/modules/skills/skills.contract.js +10 -0
- package/dist/modules/skills/skills.contract.js.map +1 -0
- package/dist/modules/skills/skills.routes.d.ts +15 -0
- package/dist/modules/skills/skills.routes.d.ts.map +1 -0
- package/dist/modules/skills/skills.routes.js +34 -0
- package/dist/modules/skills/skills.routes.js.map +1 -0
- package/dist/modules/skills/skills.service.d.ts +21 -0
- package/dist/modules/skills/skills.service.d.ts.map +1 -0
- package/dist/modules/skills/skills.service.js +202 -0
- package/dist/modules/skills/skills.service.js.map +1 -0
- package/dist/modules/skills/skills.tools.d.ts +15 -0
- package/dist/modules/skills/skills.tools.d.ts.map +1 -0
- package/dist/modules/skills/skills.tools.js +96 -0
- package/dist/modules/skills/skills.tools.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.errors.d.ts +14 -0
- package/dist/modules/tool-auth/external-api-key.errors.d.ts.map +1 -0
- package/dist/modules/tool-auth/external-api-key.errors.js +23 -0
- package/dist/modules/tool-auth/external-api-key.errors.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +90 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -0
- package/dist/modules/tool-auth/external-api-key.interface.js +2 -0
- package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.service.d.ts +25 -0
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -0
- package/dist/modules/tool-auth/external-api-key.service.js +164 -0
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -0
- package/dist/modules/tool-auth/internal-token.service.d.ts +62 -0
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -0
- package/dist/modules/tool-auth/internal-token.service.js +85 -0
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -0
- package/dist/modules/tool-auth/llm-usage-meter.d.ts +16 -0
- package/dist/modules/tool-auth/llm-usage-meter.d.ts.map +1 -0
- package/dist/modules/tool-auth/llm-usage-meter.js +6 -0
- package/dist/modules/tool-auth/llm-usage-meter.js.map +1 -0
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +101 -0
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -0
- package/dist/modules/tool-auth/tool-auth.middleware.js +166 -0
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -0
- package/dist/modules/tool-helpers/index.d.ts +19 -0
- package/dist/modules/tool-helpers/index.d.ts.map +1 -0
- package/dist/modules/tool-helpers/index.js +18 -0
- package/dist/modules/tool-helpers/index.js.map +1 -0
- package/dist/modules/tool-helpers/tool-context.d.ts +35 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool-context.js +66 -0
- package/dist/modules/tool-helpers/tool-context.js.map +1 -0
- package/dist/modules/tool-helpers/tool-def.d.ts +33 -0
- package/dist/modules/tool-helpers/tool-def.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool-def.js +57 -0
- package/dist/modules/tool-helpers/tool-def.js.map +1 -0
- package/dist/modules/tool-helpers/tool-handler.d.ts +19 -0
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool-handler.js +84 -0
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -0
- package/dist/modules/tool-helpers/tool.contract.d.ts +64 -0
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -0
- package/dist/modules/tool-helpers/tool.contract.js +24 -0
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -0
- package/dist/modules/tool-helpers/validate-token.d.ts +31 -0
- package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -0
- package/dist/modules/tool-helpers/validate-token.js +20 -0
- package/dist/modules/tool-helpers/validate-token.js.map +1 -0
- package/dist/modules/tool-manuals/index.d.ts +5 -0
- package/dist/modules/tool-manuals/index.d.ts.map +1 -0
- package/dist/modules/tool-manuals/index.js +5 -0
- package/dist/modules/tool-manuals/index.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +182 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.js +19 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +24 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.js +102 -0
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +108 -0
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.service.js +710 -0
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +35 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.js +157 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -0
- package/dist/modules/tool-registry/manual.routes.d.ts +6 -0
- package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -0
- package/dist/modules/tool-registry/manual.routes.js +76 -0
- package/dist/modules/tool-registry/manual.routes.js.map +1 -0
- package/dist/modules/tool-registry/tool-registry.d.ts +23 -0
- package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -0
- package/dist/modules/tool-registry/tool-registry.js +46 -0
- package/dist/modules/tool-registry/tool-registry.js.map +1 -0
- package/dist/modules/tool-registry/tool.contract.d.ts +48 -0
- package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -0
- package/dist/modules/tool-registry/tool.contract.js +2 -0
- package/dist/modules/tool-registry/tool.contract.js.map +1 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +14 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.js +437 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -0
- package/dist/modules/workflow/event-bus.d.ts +107 -0
- package/dist/modules/workflow/event-bus.d.ts.map +1 -0
- package/dist/modules/workflow/event-bus.js +224 -0
- package/dist/modules/workflow/event-bus.js.map +1 -0
- package/dist/modules/workflow/events.routes.d.ts +80 -0
- package/dist/modules/workflow/events.routes.d.ts.map +1 -0
- package/dist/modules/workflow/events.routes.js +216 -0
- package/dist/modules/workflow/events.routes.js.map +1 -0
- package/dist/modules/workflow/file-change-notifier.d.ts +38 -0
- package/dist/modules/workflow/file-change-notifier.d.ts.map +1 -0
- package/dist/modules/workflow/file-change-notifier.js +22 -0
- package/dist/modules/workflow/file-change-notifier.js.map +1 -0
- package/dist/modules/workflow/file-lock.service.d.ts +57 -0
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -0
- package/dist/modules/workflow/file-lock.service.js +202 -0
- package/dist/modules/workflow/file-lock.service.js.map +1 -0
- package/dist/modules/workflow/git/branch-name.d.ts +10 -0
- package/dist/modules/workflow/git/branch-name.d.ts.map +1 -0
- package/dist/modules/workflow/git/branch-name.js +76 -0
- package/dist/modules/workflow/git/branch-name.js.map +1 -0
- package/dist/modules/workflow/git/clone-config.d.ts +61 -0
- package/dist/modules/workflow/git/clone-config.d.ts.map +1 -0
- package/dist/modules/workflow/git/clone-config.js +69 -0
- package/dist/modules/workflow/git/clone-config.js.map +1 -0
- package/dist/modules/workflow/git/git-version.d.ts +34 -0
- package/dist/modules/workflow/git/git-version.d.ts.map +1 -0
- package/dist/modules/workflow/git/git-version.js +63 -0
- package/dist/modules/workflow/git/git-version.js.map +1 -0
- package/dist/modules/workflow/git/git.service.d.ts +427 -0
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -0
- package/dist/modules/workflow/git/git.service.js +1987 -0
- package/dist/modules/workflow/git/git.service.js.map +1 -0
- package/dist/modules/workflow/git/mutex.d.ts +11 -0
- package/dist/modules/workflow/git/mutex.d.ts.map +1 -0
- package/dist/modules/workflow/git/mutex.js +23 -0
- package/dist/modules/workflow/git/mutex.js.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts +124 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.js +328 -0
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -0
- package/dist/modules/workflow/locking-filesystem.d.ts +133 -0
- package/dist/modules/workflow/locking-filesystem.d.ts.map +1 -0
- package/dist/modules/workflow/locking-filesystem.js +400 -0
- package/dist/modules/workflow/locking-filesystem.js.map +1 -0
- package/dist/modules/workflow/pending-commits.service.d.ts +221 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -0
- package/dist/modules/workflow/pending-commits.service.js +364 -0
- package/dist/modules/workflow/pending-commits.service.js.map +1 -0
- package/dist/modules/workflow/pending-commits.worker.d.ts +148 -0
- package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -0
- package/dist/modules/workflow/pending-commits.worker.js +245 -0
- package/dist/modules/workflow/pending-commits.worker.js.map +1 -0
- package/dist/modules/workflow/read-only-filesystem.d.ts +24 -0
- package/dist/modules/workflow/read-only-filesystem.d.ts.map +1 -0
- package/dist/modules/workflow/read-only-filesystem.js +39 -0
- package/dist/modules/workflow/read-only-filesystem.js.map +1 -0
- package/dist/modules/workflow/recovery-bot.d.ts +31 -0
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -0
- package/dist/modules/workflow/recovery-bot.js +64 -0
- package/dist/modules/workflow/recovery-bot.js.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +137 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.js +2 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.js.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +26 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +636 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -0
- package/dist/modules/workflow/sanitize-error.d.ts +29 -0
- package/dist/modules/workflow/sanitize-error.d.ts.map +1 -0
- package/dist/modules/workflow/sanitize-error.js +60 -0
- package/dist/modules/workflow/sanitize-error.js.map +1 -0
- package/dist/modules/workflow/session-ontology.policy.d.ts +52 -0
- package/dist/modules/workflow/session-ontology.policy.d.ts.map +1 -0
- package/dist/modules/workflow/session-ontology.policy.js +62 -0
- package/dist/modules/workflow/session-ontology.policy.js.map +1 -0
- package/dist/modules/workflow/session-ontology.service.d.ts +100 -0
- package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -0
- package/dist/modules/workflow/session-ontology.service.js +143 -0
- package/dist/modules/workflow/session-ontology.service.js.map +1 -0
- package/dist/modules/workflow/workflow-hooks.d.ts +87 -0
- package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -0
- package/dist/modules/workflow/workflow-hooks.js +35 -0
- package/dist/modules/workflow/workflow-hooks.js.map +1 -0
- package/dist/modules/workflow/workflow.errors.d.ts +171 -0
- package/dist/modules/workflow/workflow.errors.d.ts.map +1 -0
- package/dist/modules/workflow/workflow.errors.js +260 -0
- package/dist/modules/workflow/workflow.errors.js.map +1 -0
- package/dist/modules/workflow/workflow.routes.d.ts +26 -0
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -0
- package/dist/modules/workflow/workflow.routes.js +804 -0
- package/dist/modules/workflow/workflow.routes.js.map +1 -0
- package/dist/modules/workflow/workflow.service.d.ts +385 -0
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -0
- package/dist/modules/workflow/workflow.service.js +1155 -0
- package/dist/modules/workflow/workflow.service.js.map +1 -0
- package/dist/modules/workspace/bevel-ignore.d.ts +25 -0
- package/dist/modules/workspace/bevel-ignore.d.ts.map +1 -0
- package/dist/modules/workspace/bevel-ignore.js +57 -0
- package/dist/modules/workspace/bevel-ignore.js.map +1 -0
- package/dist/modules/workspace/kb-seed.interface.d.ts +36 -0
- package/dist/modules/workspace/kb-seed.interface.d.ts.map +1 -0
- package/dist/modules/workspace/kb-seed.interface.js +2 -0
- package/dist/modules/workspace/kb-seed.interface.js.map +1 -0
- package/dist/modules/workspace/kb-seed.service.d.ts +70 -0
- package/dist/modules/workspace/kb-seed.service.d.ts.map +1 -0
- package/dist/modules/workspace/kb-seed.service.js +325 -0
- package/dist/modules/workspace/kb-seed.service.js.map +1 -0
- package/dist/modules/workspace/routine-write-policy.d.ts +49 -0
- package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -0
- package/dist/modules/workspace/routine-write-policy.js +46 -0
- package/dist/modules/workspace/routine-write-policy.js.map +1 -0
- package/dist/modules/workspace/session-ontology.gate.d.ts +112 -0
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -0
- package/dist/modules/workspace/session-ontology.gate.js +161 -0
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -0
- package/dist/modules/workspace/session-sink.d.ts +25 -0
- package/dist/modules/workspace/session-sink.d.ts.map +1 -0
- package/dist/modules/workspace/session-sink.js +8 -0
- package/dist/modules/workspace/session-sink.js.map +1 -0
- package/dist/modules/workspace/spill-store.d.ts +24 -0
- package/dist/modules/workspace/spill-store.d.ts.map +1 -0
- package/dist/modules/workspace/spill-store.js +87 -0
- package/dist/modules/workspace/spill-store.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts +25 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -0
- package/dist/modules/workspace/workspace.routes.js +1046 -0
- package/dist/modules/workspace/workspace.routes.js.map +1 -0
- package/dist/modules/workspace/workspace.service.d.ts +339 -0
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -0
- package/dist/modules/workspace/workspace.service.js +1221 -0
- package/dist/modules/workspace/workspace.service.js.map +1 -0
- package/dist/modules/workspace/workspace.tools.d.ts +19 -0
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -0
- package/dist/modules/workspace/workspace.tools.js +767 -0
- package/dist/modules/workspace/workspace.tools.js.map +1 -0
- package/dist/shared/frontmatter-id.d.ts +35 -0
- package/dist/shared/frontmatter-id.d.ts.map +1 -0
- package/dist/shared/frontmatter-id.js +68 -0
- package/dist/shared/frontmatter-id.js.map +1 -0
- package/dist/shared/fs-walk.d.ts +9 -0
- package/dist/shared/fs-walk.d.ts.map +1 -0
- package/dist/shared/fs-walk.js +34 -0
- package/dist/shared/fs-walk.js.map +1 -0
- package/dist/shared/hash-email.d.ts +11 -0
- package/dist/shared/hash-email.d.ts.map +1 -0
- package/dist/shared/hash-email.js +14 -0
- package/dist/shared/hash-email.js.map +1 -0
- package/dist/shared/kb-layout.d.ts +38 -0
- package/dist/shared/kb-layout.d.ts.map +1 -0
- package/dist/shared/kb-layout.js +102 -0
- package/dist/shared/kb-layout.js.map +1 -0
- package/dist/shared/kb-layout.test.d.ts +2 -0
- package/dist/shared/kb-layout.test.d.ts.map +1 -0
- package/dist/shared/kb-layout.test.js +67 -0
- package/dist/shared/kb-layout.test.js.map +1 -0
- package/dist/shared/ssrf.d.ts +20 -0
- package/dist/shared/ssrf.d.ts.map +1 -0
- package/dist/shared/ssrf.js +89 -0
- package/dist/shared/ssrf.js.map +1 -0
- package/dist/shared/token-crypto.d.ts +16 -0
- package/dist/shared/token-crypto.d.ts.map +1 -0
- package/dist/shared/token-crypto.js +49 -0
- package/dist/shared/token-crypto.js.map +1 -0
- package/dist/shared/ttl-cache.d.ts +16 -0
- package/dist/shared/ttl-cache.d.ts.map +1 -0
- package/dist/shared/ttl-cache.js +27 -0
- package/dist/shared/ttl-cache.js.map +1 -0
- package/dist/shared/utcp-namespace.d.ts +46 -0
- package/dist/shared/utcp-namespace.d.ts.map +1 -0
- package/dist/shared/utcp-namespace.js +82 -0
- package/dist/shared/utcp-namespace.js.map +1 -0
- package/dist/version.d.ts +17 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/kb-template/.bevelignore +21 -0
- package/kb-template/Agents/.gitkeep +0 -0
- package/kb-template/Agents/README.md +38 -0
- package/kb-template/CLAUDE.md +419 -0
- package/kb-template/Data/.gitkeep +0 -0
- package/kb-template/Data/README.md +39 -0
- package/kb-template/KnowledgeBase/.gitkeep +0 -0
- package/kb-template/KnowledgeBase/README.md +37 -0
- package/kb-template/Pipelines/.gitkeep +0 -0
- package/kb-template/Pipelines/README.md +38 -0
- package/kb-template/Skills/.gitkeep +0 -0
- package/kb-template/Skills/README.md +32 -0
- package/kb-template/Tools/.gitkeep +0 -0
- package/kb-template/Tools/README.md +42 -0
- package/kb-template/access.md +36 -0
- package/migrations/0000_core_init.sql +243 -0
- package/migrations/meta/0000_snapshot.json +1480 -0
- package/migrations/meta/_journal.json +13 -0
- package/package.json +80 -0
- package/src/assets.ts +25 -0
- package/src/core/core-ports.ts +91 -0
- package/src/core/create-core-server.ts +338 -0
- package/src/core/create-core-services.ts +501 -0
- package/src/core-config.ts +257 -0
- package/src/index.ts +69 -0
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +98 -0
- package/src/modules/access/__tests__/access-control.read-batch.test.ts +132 -0
- package/src/modules/access/__tests__/access-control.service.test.ts +1011 -0
- package/src/modules/access/__tests__/access-mutation.service.test.ts +439 -0
- package/src/modules/access/__tests__/access-splice.test.ts +247 -0
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +407 -0
- package/src/modules/access/__tests__/creator-access.test.ts +217 -0
- package/src/modules/access/__tests__/grant-sources.test.ts +204 -0
- package/src/modules/access/__tests__/kb-read-filter.test.ts +70 -0
- package/src/modules/access/__tests__/roles-admin.service.test.ts +469 -0
- package/src/modules/access/__tests__/roles-edit.test.ts +138 -0
- package/src/modules/access/__tests__/roles-yaml-guard.test.ts +70 -0
- package/src/modules/access/__tests__/roles.routes.test.ts +234 -0
- package/src/modules/access/access-control.interface.ts +383 -0
- package/src/modules/access/access-control.service.ts +1794 -0
- package/src/modules/access/access-errors.ts +60 -0
- package/src/modules/access/access-mutation.service.ts +369 -0
- package/src/modules/access/access-splice.ts +413 -0
- package/src/modules/access/access.routes.ts +894 -0
- package/src/modules/access/creator-access.ts +270 -0
- package/src/modules/access/kb-read-filter.ts +76 -0
- package/src/modules/access/roles-admin.service.ts +741 -0
- package/src/modules/access/roles-edit.ts +248 -0
- package/src/modules/access/roles-yaml-guard.ts +89 -0
- package/src/modules/admin/admin-access.routes.ts +29 -0
- package/src/modules/admin/admin-access.service.ts +38 -0
- package/src/modules/admin/admin.interface.ts +10 -0
- package/src/modules/auth/account-erasure.service.ts +183 -0
- package/src/modules/auth/auth.middleware.ts +78 -0
- package/src/modules/auth/auth.routes.ts +97 -0
- package/src/modules/auth/auth.service.ts +199 -0
- package/src/modules/code-mode/code-mode-names.ts +38 -0
- package/src/modules/code-mode/code-mode.tool.ts +117 -0
- package/src/modules/code-mode/index.ts +6 -0
- package/src/modules/database/connection.ts +15 -0
- package/src/modules/database/core-schema.ts +431 -0
- package/src/modules/database/migrate.ts +43 -0
- package/src/modules/database/schema.ts +11 -0
- package/src/modules/diff/__tests__/diff.routes.read-gate.test.ts +87 -0
- package/src/modules/diff/__tests__/diff.routes.rejectPathsLocked.test.ts +150 -0
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +184 -0
- package/src/modules/diff/__tests__/diff.service.test.ts +202 -0
- package/src/modules/diff/diff-paths.ts +9 -0
- package/src/modules/diff/diff.config.ts +12 -0
- package/src/modules/diff/diff.interface.ts +78 -0
- package/src/modules/diff/diff.routes.ts +277 -0
- package/src/modules/diff/diff.service.ts +508 -0
- package/src/modules/diff/line-diff.ts +79 -0
- package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +287 -0
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +249 -0
- package/src/modules/mcp/__tests__/mcp-proxy-helpers.test.ts +253 -0
- package/src/modules/mcp/__tests__/mcp-session-store.test.ts +151 -0
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +150 -0
- package/src/modules/mcp/__tests__/mcp.routes.delete.test.ts +92 -0
- package/src/modules/mcp/__tests__/mcp.service.test.ts +414 -0
- package/src/modules/mcp/mcp-auth.middleware.ts +126 -0
- package/src/modules/mcp/mcp-session-store.ts +162 -0
- package/src/modules/mcp/mcp.routes.ts +263 -0
- package/src/modules/mcp/mcp.service.ts +973 -0
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +401 -0
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +60 -0
- package/src/modules/mcp/oauth/oauth-state.ts +61 -0
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +277 -0
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +206 -0
- package/src/modules/secrets-vault/__tests__/mcp-oauth-discovery.service.test.ts +178 -0
- package/src/modules/secrets-vault/__tests__/scopes-covered.test.ts +101 -0
- package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +54 -0
- package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +143 -0
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +792 -0
- package/src/modules/secrets-vault/index.ts +25 -0
- package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +289 -0
- package/src/modules/secrets-vault/secrets-variable-loader.ts +104 -0
- package/src/modules/secrets-vault/secrets-vault.contract.ts +270 -0
- package/src/modules/secrets-vault/secrets-vault.routes.ts +526 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +176 -0
- package/src/modules/skills/index.ts +10 -0
- package/src/modules/skills/skills.contract.ts +54 -0
- package/src/modules/skills/skills.routes.ts +38 -0
- package/src/modules/skills/skills.service.ts +245 -0
- package/src/modules/skills/skills.tools.ts +121 -0
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +358 -0
- package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +79 -0
- package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +88 -0
- package/src/modules/tool-auth/external-api-key.errors.ts +25 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +99 -0
- package/src/modules/tool-auth/external-api-key.service.ts +209 -0
- package/src/modules/tool-auth/internal-token.service.ts +124 -0
- package/src/modules/tool-auth/llm-usage-meter.ts +19 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +220 -0
- package/src/modules/tool-helpers/__tests__/phase0-loopback-spike.test.ts +129 -0
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +95 -0
- package/src/modules/tool-helpers/__tests__/tools-surface.test.ts +146 -0
- package/src/modules/tool-helpers/__tests__/validate-token.test.ts +75 -0
- package/src/modules/tool-helpers/index.ts +18 -0
- package/src/modules/tool-helpers/tool-context.ts +98 -0
- package/src/modules/tool-helpers/tool-def.ts +73 -0
- package/src/modules/tool-helpers/tool-handler.ts +91 -0
- package/src/modules/tool-helpers/tool.contract.ts +85 -0
- package/src/modules/tool-helpers/validate-token.ts +50 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +200 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +499 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +156 -0
- package/src/modules/tool-manuals/index.ts +12 -0
- package/src/modules/tool-manuals/tool-manuals.contract.ts +183 -0
- package/src/modules/tool-manuals/tool-manuals.routes.ts +110 -0
- package/src/modules/tool-manuals/tool-manuals.service.ts +781 -0
- package/src/modules/tool-manuals/tool-manuals.tools.ts +202 -0
- package/src/modules/tool-registry/__tests__/tool-registry.test.ts +64 -0
- package/src/modules/tool-registry/manual.routes.ts +87 -0
- package/src/modules/tool-registry/tool-registry.ts +55 -0
- package/src/modules/tool-registry/tool.contract.ts +52 -0
- package/src/modules/workflow/__tests__/event-bus.test.ts +322 -0
- package/src/modules/workflow/__tests__/file-change-notifier.test.ts +51 -0
- package/src/modules/workflow/__tests__/format-affected-owners.test.ts +67 -0
- package/src/modules/workflow/__tests__/locking-filesystem.test.ts +445 -0
- package/src/modules/workflow/__tests__/pending-commits.canonical.test.ts +36 -0
- package/src/modules/workflow/__tests__/pending-commits.worker.test.ts +243 -0
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +308 -0
- package/src/modules/workflow/__tests__/sanitize-error.test.ts +67 -0
- package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +62 -0
- package/src/modules/workflow/__tests__/session-ontology.service.test.ts +200 -0
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +232 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +380 -0
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +340 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +192 -0
- package/src/modules/workflow/agent-tools/workflow.tools.ts +502 -0
- package/src/modules/workflow/event-bus.ts +262 -0
- package/src/modules/workflow/events.routes.ts +266 -0
- package/src/modules/workflow/file-change-notifier.ts +54 -0
- package/src/modules/workflow/file-lock.service.ts +269 -0
- package/src/modules/workflow/git/__tests__/branch-name.test.ts +86 -0
- package/src/modules/workflow/git/__tests__/branchAuthor.test.ts +80 -0
- package/src/modules/workflow/git/__tests__/clone-config.test.ts +15 -0
- package/src/modules/workflow/git/__tests__/git-test-helpers.ts +47 -0
- package/src/modules/workflow/git/__tests__/git-version.failure.test.ts +24 -0
- package/src/modules/workflow/git/__tests__/git-version.test.ts +49 -0
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +389 -0
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
- package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +105 -0
- package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +211 -0
- package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +154 -0
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +320 -0
- package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +202 -0
- package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +453 -0
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +198 -0
- package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +125 -0
- package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +219 -0
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +145 -0
- package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +240 -0
- package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +272 -0
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +232 -0
- package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +101 -0
- package/src/modules/workflow/git/__tests__/git.service.status.test.ts +127 -0
- package/src/modules/workflow/git/__tests__/mutex.test.ts +78 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +225 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +101 -0
- package/src/modules/workflow/git/branch-name.ts +70 -0
- package/src/modules/workflow/git/clone-config.ts +71 -0
- package/src/modules/workflow/git/git-version.ts +70 -0
- package/src/modules/workflow/git/git.service.ts +2248 -0
- package/src/modules/workflow/git/mutex.ts +22 -0
- package/src/modules/workflow/git/pull-request.service.ts +447 -0
- package/src/modules/workflow/locking-filesystem.ts +489 -0
- package/src/modules/workflow/pending-commits.service.ts +444 -0
- package/src/modules/workflow/pending-commits.worker.ts +361 -0
- package/src/modules/workflow/read-only-filesystem.ts +54 -0
- package/src/modules/workflow/recovery-bot.ts +73 -0
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +560 -0
- package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +176 -0
- package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +258 -0
- package/src/modules/workflow/review-workflow/review-workflow.interface.ts +199 -0
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +806 -0
- package/src/modules/workflow/sanitize-error.ts +62 -0
- package/src/modules/workflow/session-ontology.policy.ts +70 -0
- package/src/modules/workflow/session-ontology.service.ts +178 -0
- package/src/modules/workflow/workflow-hooks.ts +101 -0
- package/src/modules/workflow/workflow.errors.ts +285 -0
- package/src/modules/workflow/workflow.routes.ts +858 -0
- package/src/modules/workflow/workflow.service.ts +1555 -0
- package/src/modules/workspace/__tests__/kb-seed.service.test.ts +213 -0
- package/src/modules/workspace/__tests__/routine-write-policy.test.ts +68 -0
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +237 -0
- package/src/modules/workspace/__tests__/spill-store.test.ts +43 -0
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +233 -0
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +176 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +303 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +276 -0
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +120 -0
- package/src/modules/workspace/__tests__/workspace.service.test.ts +565 -0
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +504 -0
- package/src/modules/workspace/bevel-ignore.ts +62 -0
- package/src/modules/workspace/kb-seed.interface.ts +36 -0
- package/src/modules/workspace/kb-seed.service.ts +361 -0
- package/src/modules/workspace/routine-write-policy.ts +79 -0
- package/src/modules/workspace/session-ontology.gate.ts +189 -0
- package/src/modules/workspace/session-sink.ts +25 -0
- package/src/modules/workspace/spill-store.ts +87 -0
- package/src/modules/workspace/workspace.routes.ts +1114 -0
- package/src/modules/workspace/workspace.service.ts +1343 -0
- package/src/modules/workspace/workspace.tools.ts +885 -0
- package/src/shared/__tests__/frontmatter-id.test.ts +88 -0
- package/src/shared/__tests__/fs-walk.test.ts +42 -0
- package/src/shared/__tests__/ssrf.test.ts +53 -0
- package/src/shared/__tests__/utcp-namespace.test.ts +19 -0
- package/src/shared/frontmatter-id.ts +72 -0
- package/src/shared/fs-walk.ts +30 -0
- package/src/shared/hash-email.ts +14 -0
- package/src/shared/kb-layout.test.ts +88 -0
- package/src/shared/kb-layout.ts +101 -0
- package/src/shared/ssrf.ts +78 -0
- package/src/shared/token-crypto.ts +54 -0
- package/src/shared/ttl-cache.ts +27 -0
- package/src/shared/utcp-namespace.ts +88 -0
- package/src/version.ts +19 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import type { WorkspaceService } from '../../../workspace/workspace.service.js';
|
|
8
|
+
import { WorkflowHooks } from '../../workflow-hooks.js';
|
|
9
|
+
import { GitService } from '../git.service.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `GitService.commitFile` — the `skipValidator` flag. The reject flow passes
|
|
13
|
+
* `skipValidator: true` because it re-commits a pre-agent baseline that was
|
|
14
|
+
* already validated when first written; running the (advisory) KB validator
|
|
15
|
+
* there is pure latency.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const execFileAsync = promisify(execFile);
|
|
19
|
+
const PROCESS_MAP_DIR = 'knowledge-base';
|
|
20
|
+
const USER = { id: 'u-alice', name: 'Alice', email: 'alice@bevel.software' };
|
|
21
|
+
|
|
22
|
+
async function runGit(cwd: string, args: string[]): Promise<void> {
|
|
23
|
+
await execFileAsync('git', args, {
|
|
24
|
+
cwd,
|
|
25
|
+
env: {
|
|
26
|
+
...process.env,
|
|
27
|
+
GIT_AUTHOR_NAME: 'Test',
|
|
28
|
+
GIT_AUTHOR_EMAIL: 't@x.com',
|
|
29
|
+
GIT_COMMITTER_NAME: 'Test',
|
|
30
|
+
GIT_COMMITTER_EMAIL: 't@x.com',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function seedWorkspace(
|
|
36
|
+
root: string,
|
|
37
|
+
workspaceId: string,
|
|
38
|
+
): Promise<{ workspaceDir: string; repo: string }> {
|
|
39
|
+
const workspaceDir = path.join(root, workspaceId);
|
|
40
|
+
const repo = path.join(workspaceDir, PROCESS_MAP_DIR);
|
|
41
|
+
await fs.mkdir(repo, { recursive: true });
|
|
42
|
+
// A feature branch — not a protected branch — so `commitFile` skips the
|
|
43
|
+
// protected-branch access gate; this test is only about the validator.
|
|
44
|
+
await runGit(repo, ['init', '-b', 'feature-test']);
|
|
45
|
+
await runGit(repo, ['config', 'user.email', 'test@bevel.local']);
|
|
46
|
+
await runGit(repo, ['config', 'user.name', 'Test Runner']);
|
|
47
|
+
// An initial commit so HEAD exists.
|
|
48
|
+
await fs.writeFile(path.join(repo, 'seed.md'), 'seed\n');
|
|
49
|
+
await runGit(repo, ['add', 'seed.md']);
|
|
50
|
+
await runGit(repo, ['commit', '-m', 'seed']);
|
|
51
|
+
return { workspaceDir, repo };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function stubWorkspaceService(workspaceId: string, workspaceDir: string): WorkspaceService {
|
|
55
|
+
return {
|
|
56
|
+
getWorkspacePath: async (id: string) => {
|
|
57
|
+
if (id !== workspaceId) throw new Error(`unexpected workspace ${id}`);
|
|
58
|
+
return workspaceDir;
|
|
59
|
+
},
|
|
60
|
+
} as unknown as WorkspaceService;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function makeValidator(): { hooks: WorkflowHooks; runValidation: ReturnType<typeof vi.fn> } {
|
|
64
|
+
const report = { ok: true, mustFix: [], warnings: [], rawOutput: '' };
|
|
65
|
+
const runValidation = vi.fn(async () => report);
|
|
66
|
+
// Registered as a commit-validation hook — the seam GitService consults
|
|
67
|
+
// where it used to call the injected validator.
|
|
68
|
+
const hooks = new WorkflowHooks();
|
|
69
|
+
hooks.onCommitValidation(() => runValidation());
|
|
70
|
+
return { hooks, runValidation };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
describe('GitService.commitFile — skipValidator', () => {
|
|
74
|
+
let root: string;
|
|
75
|
+
const workspaceId = 'ws-commitfile-1';
|
|
76
|
+
|
|
77
|
+
beforeEach(async () => {
|
|
78
|
+
root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-git-commitfile-'));
|
|
79
|
+
});
|
|
80
|
+
afterEach(async () => {
|
|
81
|
+
await fs.rm(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('skipValidator=true commits the file WITHOUT running the KB validator', async () => {
|
|
85
|
+
const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
|
|
86
|
+
const { hooks, runValidation } = makeValidator();
|
|
87
|
+
const svc = new GitService(
|
|
88
|
+
stubWorkspaceService(workspaceId, workspaceDir),
|
|
89
|
+
hooks,
|
|
90
|
+
'knowledge-base',
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
await fs.writeFile(path.join(repo, 'Foo.md'), 'reverted content\n');
|
|
94
|
+
const change = await svc.commitFile(workspaceId, USER, 'Foo.md', 'Revert agent change', true);
|
|
95
|
+
|
|
96
|
+
expect(runValidation).not.toHaveBeenCalled();
|
|
97
|
+
expect(change?.sha).toBeTruthy();
|
|
98
|
+
expect(change?.subject).toBe('Revert agent change');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('runs the KB validator when skipValidator is omitted', async () => {
|
|
102
|
+
const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
|
|
103
|
+
const { hooks, runValidation } = makeValidator();
|
|
104
|
+
const svc = new GitService(
|
|
105
|
+
stubWorkspaceService(workspaceId, workspaceDir),
|
|
106
|
+
hooks,
|
|
107
|
+
'knowledge-base',
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
await fs.writeFile(path.join(repo, 'Bar.md'), 'new content\n');
|
|
111
|
+
const change = await svc.commitFile(workspaceId, USER, 'Bar.md', 'normal commit');
|
|
112
|
+
|
|
113
|
+
expect(runValidation).toHaveBeenCalledTimes(1);
|
|
114
|
+
expect(change?.sha).toBeTruthy();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Regression: filenames with bracketed prefixes (`[Approved] …`, `[New] …`,
|
|
118
|
+
// `[Updated 03.09.2025] …`) used to be rejected at `assertValidRelativePath`
|
|
119
|
+
// because their `[` / `]` characters would be interpreted by `git add -- <path>`
|
|
120
|
+
// as pathspec globs. The fix is `GIT_LITERAL_PATHSPECS=1` on the subprocess
|
|
121
|
+
// env (set in `GitService.git()`), which forces literal matching. This test
|
|
122
|
+
// commits one of the user-reported offenders end-to-end through real git so
|
|
123
|
+
// a regression in the env-var plumbing would surface as a subprocess failure
|
|
124
|
+
// here rather than as a 400 on the upload route.
|
|
125
|
+
it('commits a filename containing pathspec glob characters (regression: [Approved] / [New] prefixes)', async () => {
|
|
126
|
+
const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
|
|
127
|
+
const { hooks } = makeValidator();
|
|
128
|
+
const svc = new GitService(
|
|
129
|
+
stubWorkspaceService(workspaceId, workspaceDir),
|
|
130
|
+
hooks,
|
|
131
|
+
'knowledge-base',
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const relPath = 'Purchasing/[Updated 03.09.2025] Purchasing_How to search_Product detail page.md';
|
|
135
|
+
await fs.mkdir(path.join(repo, 'Purchasing'), { recursive: true });
|
|
136
|
+
await fs.writeFile(path.join(repo, relPath), 'content\n');
|
|
137
|
+
|
|
138
|
+
const change = await svc.commitFile(workspaceId, USER, relPath);
|
|
139
|
+
|
|
140
|
+
expect(change?.sha).toBeTruthy();
|
|
141
|
+
// Working tree must end up clean — `git add -- <path>` literally matched
|
|
142
|
+
// the bracketed name, so there's no leftover untracked file ghost on disk.
|
|
143
|
+
const { stdout: status } = await execFileAsync('git', ['-C', repo, 'status', '--porcelain'], {
|
|
144
|
+
env: { ...process.env, GIT_LITERAL_PATHSPECS: '1' },
|
|
145
|
+
});
|
|
146
|
+
expect(status.trim()).toBe('');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Regression: deep KB paths (≥194 chars) made the default `Update <path>`
|
|
150
|
+
// subject exceed the 200-char limit, so the lock-release auto-commit
|
|
151
|
+
// propagated `commit summary must be ≤ 200 characters` back through the
|
|
152
|
+
// agent's write tool. The default now falls back to the basename when the
|
|
153
|
+
// full path doesn't fit.
|
|
154
|
+
it('truncates the default subject when the path makes "Update <path>" exceed 200 chars', async () => {
|
|
155
|
+
const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
|
|
156
|
+
const { hooks } = makeValidator();
|
|
157
|
+
const svc = new GitService(
|
|
158
|
+
stubWorkspaceService(workspaceId, workspaceDir),
|
|
159
|
+
hooks,
|
|
160
|
+
'knowledge-base',
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
const deepDir = path.join(
|
|
164
|
+
'Product',
|
|
165
|
+
'Knowledge',
|
|
166
|
+
'1. Service Commitment Management',
|
|
167
|
+
'1.1 In - Architecture Layering (AL)',
|
|
168
|
+
'0-Governance',
|
|
169
|
+
'0.5-Layer-Group-Specific-Governance-Principles',
|
|
170
|
+
);
|
|
171
|
+
const fileName = '0.5.5-Buyer-Side-Commercial-Agreement-Governance.md';
|
|
172
|
+
const relPath = path.posix.join(deepDir.split(path.sep).join('/'), fileName);
|
|
173
|
+
expect(`Update ${relPath}`.length).toBeGreaterThan(200);
|
|
174
|
+
|
|
175
|
+
await fs.mkdir(path.join(repo, deepDir), { recursive: true });
|
|
176
|
+
await fs.writeFile(path.join(repo, deepDir, fileName), 'content\n');
|
|
177
|
+
|
|
178
|
+
const change = await svc.commitFile(workspaceId, USER, relPath);
|
|
179
|
+
|
|
180
|
+
expect(change?.subject).toBe(`Update ${fileName}`);
|
|
181
|
+
expect(change?.subject.length).toBeLessThanOrEqual(200);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Regression: pathspec literal handling. `git checkout HEAD -- '[Approved] x.md'`
|
|
185
|
+
// and `git ls-files --error-unmatch -- '[Approved] x.md'` would interpret the
|
|
186
|
+
// brackets as a character-class glob, so discardPath would either silently
|
|
187
|
+
// no-op or fail to revert the on-disk content. Belongs alongside the
|
|
188
|
+
// commitFile regression because no dedicated discardPath test file exists
|
|
189
|
+
// yet — its full surface is covered transitively elsewhere.
|
|
190
|
+
it('discardPath reverts an unstaged modification to a bracketed-name file', async () => {
|
|
191
|
+
const { workspaceDir, repo } = await seedWorkspace(root, workspaceId);
|
|
192
|
+
const { hooks } = makeValidator();
|
|
193
|
+
const svc = new GitService(
|
|
194
|
+
stubWorkspaceService(workspaceId, workspaceDir),
|
|
195
|
+
hooks,
|
|
196
|
+
'knowledge-base',
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const relPath = '[Approved] config.md';
|
|
200
|
+
const committed = 'committed content\n';
|
|
201
|
+
await fs.writeFile(path.join(repo, relPath), committed);
|
|
202
|
+
await svc.commitFile(workspaceId, USER, relPath, 'add bracketed config');
|
|
203
|
+
|
|
204
|
+
// Dirty the working tree.
|
|
205
|
+
await fs.writeFile(path.join(repo, relPath), 'dirty content\n');
|
|
206
|
+
await svc.discardPath(workspaceId, relPath);
|
|
207
|
+
|
|
208
|
+
const restored = await fs.readFile(path.join(repo, relPath), 'utf-8');
|
|
209
|
+
expect(restored).toBe(committed);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import type { WorkspaceService } from '../../../workspace/workspace.service.js';
|
|
8
|
+
import { WorkflowHooks } from '../../workflow-hooks.js';
|
|
9
|
+
import { GitService } from '../git.service.js';
|
|
10
|
+
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
|
|
13
|
+
async function mkTmpRoot(): Promise<string> {
|
|
14
|
+
return fs.mkdtemp(path.join(os.tmpdir(), 'bevel-git-createBranch-'));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function runGit(cwd: string, args: string[]): Promise<void> {
|
|
18
|
+
await execFileAsync('git', args, {
|
|
19
|
+
cwd,
|
|
20
|
+
env: {
|
|
21
|
+
...process.env,
|
|
22
|
+
GIT_AUTHOR_NAME: 'Test', GIT_AUTHOR_EMAIL: 't@x.com',
|
|
23
|
+
GIT_COMMITTER_NAME: 'Test', GIT_COMMITTER_EMAIL: 't@x.com',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function gitOut(cwd: string, args: string[]): Promise<string> {
|
|
29
|
+
const { stdout } = await execFileAsync('git', args, { cwd });
|
|
30
|
+
return stdout.trim();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Seeds a bare upstream + a single clone on `target-company-state`, mirroring
|
|
35
|
+
* the prod layout: `<root>/<workspaceId>/knowledge-base`. The clone has
|
|
36
|
+
* `origin` wired to the bare upstream so any push from `GitService` can land
|
|
37
|
+
* on a real remote that downstream `git clone` / `ls-remote` can observe.
|
|
38
|
+
*/
|
|
39
|
+
async function seedWorkspace(root: string, workspaceId: string): Promise<{
|
|
40
|
+
upstream: string;
|
|
41
|
+
repo: string;
|
|
42
|
+
}> {
|
|
43
|
+
const upstream = path.join(root, 'upstream.git');
|
|
44
|
+
await runGit(root, ['init', '--bare', '-b', 'target-company-state', upstream]);
|
|
45
|
+
|
|
46
|
+
const seed = path.join(root, '.seed');
|
|
47
|
+
await fs.mkdir(seed);
|
|
48
|
+
await runGit(seed, ['init', '-b', 'target-company-state']);
|
|
49
|
+
await runGit(seed, ['remote', 'add', 'origin', upstream]);
|
|
50
|
+
await runGit(seed, ['commit', '--allow-empty', '-m', 'init']);
|
|
51
|
+
await runGit(seed, ['push', 'origin', 'target-company-state']);
|
|
52
|
+
await runGit(upstream, ['symbolic-ref', 'HEAD', 'refs/heads/target-company-state']);
|
|
53
|
+
|
|
54
|
+
const workspaceDir = path.join(root, workspaceId);
|
|
55
|
+
const repo = path.join(workspaceDir, 'knowledge-base');
|
|
56
|
+
await fs.mkdir(workspaceDir, { recursive: true });
|
|
57
|
+
await runGit(root, ['clone', upstream, repo]);
|
|
58
|
+
return { upstream, repo };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
function stubWorkspaceService(workspaceId: string, workspaceDir: string): WorkspaceService {
|
|
63
|
+
return {
|
|
64
|
+
getWorkspacePath: async (id: string) => {
|
|
65
|
+
if (id !== workspaceId) throw new Error(`unexpected workspace ${id}`);
|
|
66
|
+
return workspaceDir;
|
|
67
|
+
},
|
|
68
|
+
} as unknown as WorkspaceService;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe('GitService.createBranch', () => {
|
|
72
|
+
let root: string;
|
|
73
|
+
const workspaceId = 'target-company-state';
|
|
74
|
+
|
|
75
|
+
beforeEach(async () => {
|
|
76
|
+
root = await mkTmpRoot();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
afterEach(async () => {
|
|
80
|
+
await fs.rm(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Bug 1: the per-branch workspace bootstrap (`WorkspaceService.getOrCreateForBranch`)
|
|
84
|
+
// clones with `git clone -b <name>` from origin, so the new draft's ref MUST exist on
|
|
85
|
+
// origin before any user navigates to its URL. If `createBranch` leaves the branch
|
|
86
|
+
// local-only, the next workspace bootstrap fails with "Remote branch not found in
|
|
87
|
+
// upstream origin" and the user lands on a dead URL.
|
|
88
|
+
it('publishes the new draft to origin so a fresh clone -b <name> can find it', async () => {
|
|
89
|
+
const { upstream } = await seedWorkspace(root, workspaceId);
|
|
90
|
+
const svc = new GitService(
|
|
91
|
+
stubWorkspaceService(workspaceId, path.join(root, workspaceId)),
|
|
92
|
+
new WorkflowHooks(),
|
|
93
|
+
'knowledge-base',
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const info = await svc.createBranch(workspaceId, 'alice/new-draft');
|
|
97
|
+
|
|
98
|
+
// The draft must be on origin — `BranchInfo.hasRemote` is the contract
|
|
99
|
+
// signalling to the workspace-bootstrap path that the ref is reachable.
|
|
100
|
+
expect(info.hasRemote).toBe(true);
|
|
101
|
+
|
|
102
|
+
// And `git ls-remote` against the bare upstream must actually see it,
|
|
103
|
+
// because the bootstrap shells out to `git clone -b <name>` against
|
|
104
|
+
// exactly this remote — assertion-on-disk, not just on the return value.
|
|
105
|
+
const lsRemote = await gitOut(path.join(root, workspaceId, 'knowledge-base'), [
|
|
106
|
+
'ls-remote', '--heads', upstream, 'alice/new-draft',
|
|
107
|
+
]);
|
|
108
|
+
expect(lsRemote).toMatch(/refs\/heads\/alice\/new-draft$/);
|
|
109
|
+
|
|
110
|
+
// End-to-end safeguard: a fresh, independent clone with `-b <name>` must
|
|
111
|
+
// succeed. This is the exact command `cloneProcessMapForBranch` runs when
|
|
112
|
+
// the user navigates to the new draft's URL — if it fails here, Bug 1 is
|
|
113
|
+
// still live regardless of what `hasRemote` says.
|
|
114
|
+
const newWorkspace = path.join(root, 'new-workspace');
|
|
115
|
+
await fs.mkdir(newWorkspace);
|
|
116
|
+
await runGit(root, ['clone', '-b', 'alice/new-draft', upstream, path.join(newWorkspace, 'knowledge-base')]);
|
|
117
|
+
const checkedOut = await gitOut(
|
|
118
|
+
path.join(newWorkspace, 'knowledge-base'),
|
|
119
|
+
['rev-parse', '--abbrev-ref', 'HEAD'],
|
|
120
|
+
);
|
|
121
|
+
expect(checkedOut).toBe('alice/new-draft');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Regression: createBranch must NOT leave a local `refs/heads/<name>` in the
|
|
125
|
+
// creating workspace's clone. Under the per-branch workspace model the new
|
|
126
|
+
// draft lives in its own workspace; a stray local head here survives
|
|
127
|
+
// `fetch --prune` after the draft is deleted from another workspace, so it
|
|
128
|
+
// resurfaces in the picker as a phantom orphan that "won't delete". The draft
|
|
129
|
+
// must exist only as a remote-tracking ref in this clone.
|
|
130
|
+
it('leaves no local head in the creating clone — only a remote-tracking ref', async () => {
|
|
131
|
+
await seedWorkspace(root, workspaceId);
|
|
132
|
+
const repo = path.join(root, workspaceId, 'knowledge-base');
|
|
133
|
+
const svc = new GitService(
|
|
134
|
+
stubWorkspaceService(workspaceId, path.join(root, workspaceId)),
|
|
135
|
+
new WorkflowHooks(),
|
|
136
|
+
'knowledge-base',
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
await svc.createBranch(workspaceId, 'alice/new-draft');
|
|
140
|
+
|
|
141
|
+
// No local head for the draft (the bug left one here).
|
|
142
|
+
const localHead = await gitOut(repo, [
|
|
143
|
+
'for-each-ref', '--format=%(refname)', 'refs/heads/alice/new-draft',
|
|
144
|
+
]);
|
|
145
|
+
expect(localHead).toBe('');
|
|
146
|
+
|
|
147
|
+
// But it IS reachable as a remote-tracking ref, so the picker still lists it
|
|
148
|
+
// and `fetch --prune` can clean it up when origin drops it.
|
|
149
|
+
const remoteTracking = await gitOut(repo, [
|
|
150
|
+
'for-each-ref', '--format=%(refname)', 'refs/remotes/origin/alice/new-draft',
|
|
151
|
+
]);
|
|
152
|
+
expect(remoteTracking).toBe('refs/remotes/origin/alice/new-draft');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import type { AuthUser } from '@bevel-software/platform-shared';
|
|
8
|
+
import type { WorkspaceService } from '../../../workspace/workspace.service.js';
|
|
9
|
+
import { WorkflowHooks } from '../../workflow-hooks.js';
|
|
10
|
+
import type { IAccessControl } from '../../../access/access-control.interface.js';
|
|
11
|
+
import { GitService } from '../git.service.js';
|
|
12
|
+
import {
|
|
13
|
+
BranchAuthorshipError,
|
|
14
|
+
ProtectedBranchError,
|
|
15
|
+
WorkflowValidationError,
|
|
16
|
+
} from '../../workflow.errors.js';
|
|
17
|
+
|
|
18
|
+
const execFileAsync = promisify(execFile);
|
|
19
|
+
|
|
20
|
+
async function mkTmpRoot(): Promise<string> {
|
|
21
|
+
return fs.mkdtemp(path.join(os.tmpdir(), 'bevel-git-deleteBranch-'));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function runGit(cwd: string, args: string[]): Promise<void> {
|
|
25
|
+
await execFileAsync('git', args, {
|
|
26
|
+
cwd,
|
|
27
|
+
env: {
|
|
28
|
+
...process.env,
|
|
29
|
+
GIT_AUTHOR_NAME: 'Test', GIT_AUTHOR_EMAIL: 't@x.com',
|
|
30
|
+
GIT_COMMITTER_NAME: 'Test', GIT_COMMITTER_EMAIL: 't@x.com',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function gitOut(cwd: string, args: string[]): Promise<string> {
|
|
36
|
+
const { stdout } = await execFileAsync('git', args, { cwd });
|
|
37
|
+
return stdout.trim();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function remoteHasRef(upstream: string, ref: string): Promise<boolean> {
|
|
41
|
+
const out = await gitOut(upstream, ['for-each-ref', `refs/heads/${ref}`, '--format', '%(refname)']);
|
|
42
|
+
return out.length > 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Seeds a bare upstream + a clone with three pushed branches:
|
|
47
|
+
* - target-company-state (protected, the workspace's HEAD)
|
|
48
|
+
* - alice/my-draft (owned by alice@example.com)
|
|
49
|
+
* - bob/other-draft (owned by someone else)
|
|
50
|
+
*/
|
|
51
|
+
async function seedWorkspace(root: string, workspaceId: string): Promise<{
|
|
52
|
+
upstream: string;
|
|
53
|
+
repo: string;
|
|
54
|
+
}> {
|
|
55
|
+
const upstream = path.join(root, 'upstream.git');
|
|
56
|
+
await runGit(root, ['init', '--bare', '-b', 'target-company-state', upstream]);
|
|
57
|
+
|
|
58
|
+
const seed = path.join(root, '.seed');
|
|
59
|
+
await fs.mkdir(seed);
|
|
60
|
+
await runGit(seed, ['init', '-b', 'target-company-state']);
|
|
61
|
+
await runGit(seed, ['remote', 'add', 'origin', upstream]);
|
|
62
|
+
await runGit(seed, ['commit', '--allow-empty', '-m', 'init']);
|
|
63
|
+
await runGit(seed, ['branch', 'alice/my-draft']);
|
|
64
|
+
await runGit(seed, ['branch', 'bob/other-draft']);
|
|
65
|
+
await runGit(seed, ['push', 'origin', 'target-company-state', 'alice/my-draft', 'bob/other-draft']);
|
|
66
|
+
await runGit(upstream, ['symbolic-ref', 'HEAD', 'refs/heads/target-company-state']);
|
|
67
|
+
|
|
68
|
+
const workspaceDir = path.join(root, workspaceId);
|
|
69
|
+
const repo = path.join(workspaceDir, 'knowledge-base');
|
|
70
|
+
await fs.mkdir(workspaceDir, { recursive: true });
|
|
71
|
+
await runGit(root, ['clone', upstream, repo]);
|
|
72
|
+
// Realistic production state: the user has worked on alice/my-draft from
|
|
73
|
+
// this workspace at some point, so a local tracking ref exists alongside
|
|
74
|
+
// the remote ref. bob/other-draft is remote-only (alice has never opened
|
|
75
|
+
// it). This forces deleteBranch to handle the "delete both refs" case.
|
|
76
|
+
await runGit(repo, ['branch', 'alice/my-draft', 'origin/alice/my-draft']);
|
|
77
|
+
return { upstream, repo };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
function stubWorkspaceService(workspaceId: string, workspaceDir: string): WorkspaceService {
|
|
82
|
+
return {
|
|
83
|
+
getWorkspacePath: async (id: string) => {
|
|
84
|
+
if (id !== workspaceId) throw new Error(`unexpected workspace ${id}`);
|
|
85
|
+
return workspaceDir;
|
|
86
|
+
},
|
|
87
|
+
} as unknown as WorkspaceService;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const ALICE: AuthUser = {
|
|
91
|
+
id: 'u-alice',
|
|
92
|
+
email: 'alice@example.com',
|
|
93
|
+
name: 'Alice Test',
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const CAROL: AuthUser = {
|
|
97
|
+
id: 'u-carol',
|
|
98
|
+
email: 'carol@example.com',
|
|
99
|
+
name: 'Carol Admin',
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Minimal `IAccessControl` stub. `deleteBranch` only consults `canWrite` with
|
|
104
|
+
* a `relativePath` of `'roles.yaml'` — which the production service already
|
|
105
|
+
* uses as the admin-membership signal. Returns true for that path iff the
|
|
106
|
+
* caller's email is in the admin allowlist; every other method throws so an
|
|
107
|
+
* unexpected dependency surfaces loudly in the test rather than silently
|
|
108
|
+
* passing through.
|
|
109
|
+
*/
|
|
110
|
+
function fakeAccessControl(adminEmails: string[]): IAccessControl {
|
|
111
|
+
const admins = new Set(adminEmails.map((e) => e.trim().toLowerCase()));
|
|
112
|
+
const notImpl = () => {
|
|
113
|
+
throw new Error('IAccessControl method not stubbed for this test');
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
canWrite: async (_ws, email, relativePath) => {
|
|
117
|
+
if (relativePath !== 'roles.yaml') {
|
|
118
|
+
throw new Error(`unexpected canWrite path "${relativePath}" in deleteBranch test`);
|
|
119
|
+
}
|
|
120
|
+
return admins.has(email.trim().toLowerCase());
|
|
121
|
+
},
|
|
122
|
+
canWriteBatch: async () => notImpl(),
|
|
123
|
+
eligibleWriters: async () => notImpl(),
|
|
124
|
+
eligibleOwners: async () => notImpl(),
|
|
125
|
+
eligibleDownloaders: async () => notImpl(),
|
|
126
|
+
eligibleWriterEmails: async () => notImpl(),
|
|
127
|
+
eligibleOwnerEmails: async () => notImpl(),
|
|
128
|
+
grantSources: async () => notImpl(),
|
|
129
|
+
canDownload: async () => notImpl(),
|
|
130
|
+
canRead: async () => notImpl(),
|
|
131
|
+
canReadBatch: async () => notImpl(),
|
|
132
|
+
eligibleReaders: async () => notImpl(),
|
|
133
|
+
canReadAtRef: async () => notImpl(),
|
|
134
|
+
canOwner: async () => notImpl(),
|
|
135
|
+
invalidate: () => {},
|
|
136
|
+
findEmailByHash: async () => null,
|
|
137
|
+
kbPrincipals: async () => ({ groups: [], people: [] }),
|
|
138
|
+
validateRolesYaml: () => ({ ok: true }),
|
|
139
|
+
referencesToRole: async () => [],
|
|
140
|
+
canWriteAtRef: async () => null,
|
|
141
|
+
canWriteBatchAtRef: async () => null,
|
|
142
|
+
eligibleWritersAtRef: async () => null,
|
|
143
|
+
eligibleWritersForPathsAtRef: async () => null,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
describe('GitService.deleteBranch — authorship + remote delete', () => {
|
|
148
|
+
let root: string;
|
|
149
|
+
const workspaceId = 'target-company-state';
|
|
150
|
+
|
|
151
|
+
beforeEach(async () => {
|
|
152
|
+
root = await mkTmpRoot();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
afterEach(async () => {
|
|
156
|
+
await fs.rm(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
function makeService(): GitService {
|
|
160
|
+
return new GitService(
|
|
161
|
+
stubWorkspaceService(workspaceId, path.join(root, workspaceId)),
|
|
162
|
+
new WorkflowHooks(),
|
|
163
|
+
'knowledge-base',
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
it('lets the author delete their own draft — removes both local and remote refs', async () => {
|
|
168
|
+
const { upstream } = await seedWorkspace(root, workspaceId);
|
|
169
|
+
const svc = makeService();
|
|
170
|
+
|
|
171
|
+
await svc.deleteBranch(workspaceId, 'alice/my-draft', ALICE);
|
|
172
|
+
|
|
173
|
+
// Local ref gone — `for-each-ref` returns empty when ref is missing
|
|
174
|
+
const localRefs = await gitOut(
|
|
175
|
+
path.join(root, workspaceId, 'knowledge-base'),
|
|
176
|
+
['for-each-ref', 'refs/heads/alice/my-draft', '--format', '%(refname)'],
|
|
177
|
+
);
|
|
178
|
+
expect(localRefs).toBe('');
|
|
179
|
+
|
|
180
|
+
// Remote ref ALSO gone — this is the new behaviour, the original
|
|
181
|
+
// implementation only deleted locally and left the orphan on origin.
|
|
182
|
+
expect(await remoteHasRef(upstream, 'alice/my-draft')).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("refuses when the user isn't the author — leaves the remote ref intact", async () => {
|
|
186
|
+
const { upstream } = await seedWorkspace(root, workspaceId);
|
|
187
|
+
const svc = makeService();
|
|
188
|
+
|
|
189
|
+
await expect(
|
|
190
|
+
svc.deleteBranch(workspaceId, 'bob/other-draft', ALICE),
|
|
191
|
+
).rejects.toBeInstanceOf(BranchAuthorshipError);
|
|
192
|
+
|
|
193
|
+
// Refused delete must not push to origin — bob's draft must still be
|
|
194
|
+
// there for him.
|
|
195
|
+
expect(await remoteHasRef(upstream, 'bob/other-draft')).toBe(true);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('refuses to delete a branch with no recognisable author prefix', async () => {
|
|
199
|
+
const { repo } = await seedWorkspace(root, workspaceId);
|
|
200
|
+
// Create a `fix/...` style branch (no email prefix) locally + push.
|
|
201
|
+
await runGit(repo, ['branch', 'fix/no-author']);
|
|
202
|
+
await runGit(repo, ['push', 'origin', 'fix/no-author']);
|
|
203
|
+
|
|
204
|
+
const svc = makeService();
|
|
205
|
+
await expect(
|
|
206
|
+
svc.deleteBranch(workspaceId, 'fix/no-author', ALICE),
|
|
207
|
+
).rejects.toBeInstanceOf(BranchAuthorshipError);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('still rejects protected branches with ProtectedBranchError (regression guard)', async () => {
|
|
211
|
+
await seedWorkspace(root, workspaceId);
|
|
212
|
+
const svc = makeService();
|
|
213
|
+
|
|
214
|
+
await expect(
|
|
215
|
+
svc.deleteBranch(workspaceId, 'target-company-state', ALICE),
|
|
216
|
+
).rejects.toBeInstanceOf(ProtectedBranchError);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('still rejects deleting the currently-checked-out branch (regression guard)', async () => {
|
|
220
|
+
const { repo } = await seedWorkspace(root, workspaceId);
|
|
221
|
+
// Switch to alice's draft so it's the checked-out branch.
|
|
222
|
+
await runGit(repo, ['checkout', 'alice/my-draft']);
|
|
223
|
+
|
|
224
|
+
const svc = makeService();
|
|
225
|
+
await expect(
|
|
226
|
+
svc.deleteBranch(workspaceId, 'alice/my-draft', ALICE),
|
|
227
|
+
).rejects.toBeInstanceOf(WorkflowValidationError);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('onlyIfNoRemote: true bypasses the authorship check (orphan-tidy-up path stays open)', async () => {
|
|
231
|
+
const { repo, upstream } = await seedWorkspace(root, workspaceId);
|
|
232
|
+
// Simulate an orphan: branch exists locally but its remote counterpart
|
|
233
|
+
// was already pruned (e.g. PR merged + remote head deleted on GitHub).
|
|
234
|
+
await runGit(repo, ['branch', 'someone-else/orphan']);
|
|
235
|
+
// Don't push it — so origin never had it.
|
|
236
|
+
|
|
237
|
+
const svc = makeService();
|
|
238
|
+
await svc.deleteBranch(workspaceId, 'someone-else/orphan', ALICE, { onlyIfNoRemote: true });
|
|
239
|
+
|
|
240
|
+
const localRefs = await gitOut(repo, [
|
|
241
|
+
'for-each-ref', 'refs/heads/someone-else/orphan', '--format', '%(refname)',
|
|
242
|
+
]);
|
|
243
|
+
expect(localRefs).toBe('');
|
|
244
|
+
// Origin never had it; sanity check the workspace clone's remote cache too.
|
|
245
|
+
expect(await remoteHasRef(upstream, 'someone-else/orphan')).toBe(false);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('refuses orphan delete when remote still has the ref (onlyIfNoRemote contract)', async () => {
|
|
249
|
+
// Regression: even with onlyIfNoRemote, if origin still has the ref the
|
|
250
|
+
// delete is refused — preserves the existing safety property.
|
|
251
|
+
await seedWorkspace(root, workspaceId);
|
|
252
|
+
const svc = makeService();
|
|
253
|
+
|
|
254
|
+
await expect(
|
|
255
|
+
svc.deleteBranch(workspaceId, 'alice/my-draft', ALICE, { onlyIfNoRemote: true }),
|
|
256
|
+
).rejects.toBeInstanceOf(WorkflowValidationError);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Admin-can-delete: when the user is in the `Admin` role per `roles.yaml`
|
|
260
|
+
// (detected via canWrite on that file — its existing source of truth), the
|
|
261
|
+
// gate opens for any non-protected, non-current branch, including teammates'
|
|
262
|
+
// drafts and unprefixed CLI branches with no recognisable author.
|
|
263
|
+
function makeServiceWithAccess(ac: IAccessControl): GitService {
|
|
264
|
+
return new GitService(
|
|
265
|
+
stubWorkspaceService(workspaceId, path.join(root, workspaceId)),
|
|
266
|
+
new WorkflowHooks(),
|
|
267
|
+
'knowledge-base',
|
|
268
|
+
undefined,
|
|
269
|
+
ac,
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
it("lets an admin delete another user's draft — removes both local and remote refs", async () => {
|
|
274
|
+
const { repo, upstream } = await seedWorkspace(root, workspaceId);
|
|
275
|
+
// Realistic state: carol has opened bob's draft from this workspace at
|
|
276
|
+
// some point, so a local tracking ref exists. deleteBranch must clean
|
|
277
|
+
// both sides.
|
|
278
|
+
await runGit(repo, ['branch', 'bob/other-draft', 'origin/bob/other-draft']);
|
|
279
|
+
const svc = makeServiceWithAccess(fakeAccessControl([CAROL.email]));
|
|
280
|
+
|
|
281
|
+
await svc.deleteBranch(workspaceId, 'bob/other-draft', CAROL);
|
|
282
|
+
|
|
283
|
+
const localRefs = await gitOut(repo, [
|
|
284
|
+
'for-each-ref', 'refs/heads/bob/other-draft', '--format', '%(refname)',
|
|
285
|
+
]);
|
|
286
|
+
expect(localRefs).toBe('');
|
|
287
|
+
expect(await remoteHasRef(upstream, 'bob/other-draft')).toBe(false);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('lets an admin delete an unprefixed CLI branch (no recognisable author)', async () => {
|
|
291
|
+
const { repo, upstream } = await seedWorkspace(root, workspaceId);
|
|
292
|
+
await runGit(repo, ['branch', 'fix/no-author']);
|
|
293
|
+
await runGit(repo, ['push', 'origin', 'fix/no-author']);
|
|
294
|
+
|
|
295
|
+
const svc = makeServiceWithAccess(fakeAccessControl([CAROL.email]));
|
|
296
|
+
await svc.deleteBranch(workspaceId, 'fix/no-author', CAROL);
|
|
297
|
+
|
|
298
|
+
expect(await remoteHasRef(upstream, 'fix/no-author')).toBe(false);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("still refuses a non-admin non-author — the gate didn't widen for everyone", async () => {
|
|
302
|
+
const { upstream } = await seedWorkspace(root, workspaceId);
|
|
303
|
+
// Alice is not admin and not bob's author → must still reject.
|
|
304
|
+
const svc = makeServiceWithAccess(fakeAccessControl([CAROL.email]));
|
|
305
|
+
|
|
306
|
+
await expect(
|
|
307
|
+
svc.deleteBranch(workspaceId, 'bob/other-draft', ALICE),
|
|
308
|
+
).rejects.toBeInstanceOf(BranchAuthorshipError);
|
|
309
|
+
expect(await remoteHasRef(upstream, 'bob/other-draft')).toBe(true);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('admin power does NOT extend to protected branches', async () => {
|
|
313
|
+
await seedWorkspace(root, workspaceId);
|
|
314
|
+
const svc = makeServiceWithAccess(fakeAccessControl([CAROL.email]));
|
|
315
|
+
|
|
316
|
+
await expect(
|
|
317
|
+
svc.deleteBranch(workspaceId, 'target-company-state', CAROL),
|
|
318
|
+
).rejects.toBeInstanceOf(ProtectedBranchError);
|
|
319
|
+
});
|
|
320
|
+
});
|