@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,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-(workspace, branch, path) edit lock store. The spec calls for
|
|
3
|
+
* file-scoped locks acquired on first edit and released either explicitly
|
|
4
|
+
* (with an autosave commit) or implicitly by TTL expiry — preventing a
|
|
5
|
+
* disconnected client from holding a file hostage.
|
|
6
|
+
*
|
|
7
|
+
* Lock state lives in Postgres because workspaces share state across
|
|
8
|
+
* backend instances eventually. The hot read path (does someone hold this
|
|
9
|
+
* lock?) is one indexed lookup; the hot write path (heartbeat) is a single
|
|
10
|
+
* row update. We don't bother caching in process memory — the lock table
|
|
11
|
+
* is the source of truth and any cache would lose its purpose the moment
|
|
12
|
+
* a different replica takes over.
|
|
13
|
+
*
|
|
14
|
+
* Stale-lock semantics: `get`, `acquire`, and `heartbeat` all treat a row
|
|
15
|
+
* with `expires_at <= now()` as if the lock didn't exist. We purge it
|
|
16
|
+
* lazily on next access rather than running a sweeper — the row count is
|
|
17
|
+
* bounded by concurrent editors, not history, so lazy GC is fine.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { and, eq, gt, lte } from 'drizzle-orm';
|
|
21
|
+
import type { Database } from '../database/connection.js';
|
|
22
|
+
import { fileLocks } from '../database/schema.js';
|
|
23
|
+
import type { AcquireLockResult, AuthUser, FileLock } from '@bevel-software/platform-shared';
|
|
24
|
+
import { WorkflowValidationError } from './workflow.errors.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Lock lifetime without a heartbeat. The client is expected to heartbeat
|
|
28
|
+
* every ~half this interval so a single missed ping doesn't release the
|
|
29
|
+
* lock out from under them. Bumping the TTL trades off "how long does a
|
|
30
|
+
* crashed client hold a file" against "how forgiving are we of network
|
|
31
|
+
* blips" — 60s is a balance.
|
|
32
|
+
*/
|
|
33
|
+
const LOCK_TTL_MS = 60_000;
|
|
34
|
+
|
|
35
|
+
function rowToFileLock(row: typeof fileLocks.$inferSelect): FileLock {
|
|
36
|
+
return {
|
|
37
|
+
branch: row.branch,
|
|
38
|
+
path: row.path,
|
|
39
|
+
holderUserId: row.holderUserId,
|
|
40
|
+
holderName: row.holderName,
|
|
41
|
+
acquiredAt: row.acquiredAt.toISOString(),
|
|
42
|
+
lastHeartbeatAt: row.lastHeartbeatAt.toISOString(),
|
|
43
|
+
expiresAt: row.expiresAt.toISOString(),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class FileLockService {
|
|
48
|
+
constructor(private readonly db: Database) {}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Acquire a lock for `(workspaceId, branch, path)` on behalf of `user`.
|
|
52
|
+
*
|
|
53
|
+
* Three outcomes folded into the same return shape:
|
|
54
|
+
* - No existing row: insert + return `{ acquired: true, lock }`.
|
|
55
|
+
* - Existing row, expired: take it over (update) + `{ acquired: true }`.
|
|
56
|
+
* - Existing row, live, different user: return `{ acquired: false }`
|
|
57
|
+
* with the current holder's lock state so the UI can render
|
|
58
|
+
* "Locked by X" without a follow-up call.
|
|
59
|
+
* - Existing row, live, same user: refresh TTL + `{ acquired: true }`
|
|
60
|
+
* so re-acquiring your own lock is idempotent.
|
|
61
|
+
*/
|
|
62
|
+
async acquire(
|
|
63
|
+
workspaceId: string,
|
|
64
|
+
branch: string,
|
|
65
|
+
targetPath: string,
|
|
66
|
+
user: AuthUser,
|
|
67
|
+
): Promise<AcquireLockResult> {
|
|
68
|
+
const now = new Date();
|
|
69
|
+
const expiresAt = new Date(now.getTime() + LOCK_TTL_MS);
|
|
70
|
+
|
|
71
|
+
// Atomic acquire-or-takeover, in a single statement. Two callers
|
|
72
|
+
// racing on the same `(workspace, branch, path)` would otherwise
|
|
73
|
+
// both SELECT no row → both INSERT (one PK-fails) or both SELECT a
|
|
74
|
+
// stale row → both UPDATE (one silently overwrites the other's
|
|
75
|
+
// takeover). PostgreSQL's INSERT ... ON CONFLICT DO UPDATE WHERE
|
|
76
|
+
// collapses both paths into one atomic statement:
|
|
77
|
+
//
|
|
78
|
+
// - No existing row → INSERT succeeds, RETURNING our new row.
|
|
79
|
+
// - Existing row, WHERE matches (stale OR same user) → UPDATE
|
|
80
|
+
// fires, RETURNING the updated row.
|
|
81
|
+
// - Existing row, WHERE doesn't match (live + different user) →
|
|
82
|
+
// the conflict is silently absorbed (PG's documented behavior),
|
|
83
|
+
// RETURNING is empty. We then read the live holder for the
|
|
84
|
+
// "Locked by X" payload.
|
|
85
|
+
//
|
|
86
|
+
// **Only expired rows can be taken over.** The same-user clause used
|
|
87
|
+
// to be here as an "idempotent refresh" shortcut, but it had a nasty
|
|
88
|
+
// side effect: the AGENT and the HUMAN EDITOR share the same `user.id`
|
|
89
|
+
// (agent edits attribute to the human), so the agent's
|
|
90
|
+
// `LockingFilesystem.withLock` would silently steal a lock the human
|
|
91
|
+
// had taken via the Edit button — overwriting their in-flight edits
|
|
92
|
+
// and dropping their lock on agent-release. Removing same-user from
|
|
93
|
+
// setWhere makes acquire strict: a non-expired lock is contended even
|
|
94
|
+
// by yourself, so the agent's retry/skip path kicks in and the human
|
|
95
|
+
// keeps editing. Real refresh-while-holding goes through
|
|
96
|
+
// `heartbeat()` (which has its own same-user UPDATE), and the
|
|
97
|
+
// editor's save flow detects "I already hold it" via `getLock` in
|
|
98
|
+
// `workspace.routes.withLock` rather than re-acquiring.
|
|
99
|
+
const upsertResult = await this.db
|
|
100
|
+
.insert(fileLocks)
|
|
101
|
+
.values({
|
|
102
|
+
workspaceId,
|
|
103
|
+
branch,
|
|
104
|
+
path: targetPath,
|
|
105
|
+
holderUserId: user.id,
|
|
106
|
+
holderName: user.name,
|
|
107
|
+
acquiredAt: now,
|
|
108
|
+
lastHeartbeatAt: now,
|
|
109
|
+
expiresAt,
|
|
110
|
+
})
|
|
111
|
+
.onConflictDoUpdate({
|
|
112
|
+
target: [fileLocks.workspaceId, fileLocks.branch, fileLocks.path],
|
|
113
|
+
set: {
|
|
114
|
+
holderUserId: user.id,
|
|
115
|
+
holderName: user.name,
|
|
116
|
+
acquiredAt: now,
|
|
117
|
+
lastHeartbeatAt: now,
|
|
118
|
+
expiresAt,
|
|
119
|
+
},
|
|
120
|
+
setWhere: lte(fileLocks.expiresAt, now),
|
|
121
|
+
})
|
|
122
|
+
.returning();
|
|
123
|
+
|
|
124
|
+
if (upsertResult.length > 0) {
|
|
125
|
+
return { acquired: true, lock: rowToFileLock(upsertResult[0]) };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Live lock held by another user. Fetch it for the "Locked by X" UI
|
|
129
|
+
// payload. We don't filter on `expiresAt > now` here because the
|
|
130
|
+
// upsert above already proved an unreclaimable row exists; the only
|
|
131
|
+
// way this read returns null is a tight race where the holder
|
|
132
|
+
// released between the upsert and this select — rare enough to
|
|
133
|
+
// surface as a retryable error rather than complicate the happy path.
|
|
134
|
+
const [holder] = await this.db
|
|
135
|
+
.select()
|
|
136
|
+
.from(fileLocks)
|
|
137
|
+
.where(
|
|
138
|
+
and(
|
|
139
|
+
eq(fileLocks.workspaceId, workspaceId),
|
|
140
|
+
eq(fileLocks.branch, branch),
|
|
141
|
+
eq(fileLocks.path, targetPath),
|
|
142
|
+
),
|
|
143
|
+
)
|
|
144
|
+
.limit(1);
|
|
145
|
+
if (!holder) {
|
|
146
|
+
throw new WorkflowValidationError(
|
|
147
|
+
`Lock contention race on "${targetPath}" — please retry.`,
|
|
148
|
+
{ kind: 'lock-contention-race', branch, path: targetPath },
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return { acquired: false, lock: rowToFileLock(holder) };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Extend the lock's TTL. Refuses if the lock is held by someone else or
|
|
156
|
+
* doesn't exist — the client is then expected to re-call `acquire`,
|
|
157
|
+
* which will either succeed (taking over a stale lock) or surface the
|
|
158
|
+
* current holder.
|
|
159
|
+
*/
|
|
160
|
+
async heartbeat(
|
|
161
|
+
workspaceId: string,
|
|
162
|
+
branch: string,
|
|
163
|
+
targetPath: string,
|
|
164
|
+
user: AuthUser,
|
|
165
|
+
): Promise<FileLock> {
|
|
166
|
+
const now = new Date();
|
|
167
|
+
const expiresAt = new Date(now.getTime() + LOCK_TTL_MS);
|
|
168
|
+
// The expiry guard (`expiresAt > now`) matters because an expired
|
|
169
|
+
// lock is conceptually released, even if its row hasn't been swept
|
|
170
|
+
// and no other user has taken it yet. Without it, a client whose
|
|
171
|
+
// tab was suspended past the TTL would silently extend a lock that
|
|
172
|
+
// the rest of the system considers "free for the next acquire" —
|
|
173
|
+
// any subsequent `acquire()` by another user could already have
|
|
174
|
+
// taken it (the upsert's `lte(expiresAt, now)` predicate matches),
|
|
175
|
+
// and the heartbeat would race with that takeover. Failing here
|
|
176
|
+
// forces the client to re-acquire (which goes through the proper
|
|
177
|
+
// takeover path) and surfaces the "your session went stale" state
|
|
178
|
+
// honestly.
|
|
179
|
+
const [updated] = await this.db
|
|
180
|
+
.update(fileLocks)
|
|
181
|
+
.set({ lastHeartbeatAt: now, expiresAt })
|
|
182
|
+
.where(
|
|
183
|
+
and(
|
|
184
|
+
eq(fileLocks.workspaceId, workspaceId),
|
|
185
|
+
eq(fileLocks.branch, branch),
|
|
186
|
+
eq(fileLocks.path, targetPath),
|
|
187
|
+
eq(fileLocks.holderUserId, user.id),
|
|
188
|
+
gt(fileLocks.expiresAt, now),
|
|
189
|
+
),
|
|
190
|
+
)
|
|
191
|
+
.returning();
|
|
192
|
+
if (!updated) {
|
|
193
|
+
throw new WorkflowValidationError(
|
|
194
|
+
`Cannot heartbeat lock on "${targetPath}": not held by you (or no longer exists).`,
|
|
195
|
+
{ kind: 'lock-not-held', branch, path: targetPath },
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return rowToFileLock(updated);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Idempotent release. Deletes the lock row when the caller holds it;
|
|
203
|
+
* silently no-ops otherwise (the lock may have expired and been taken
|
|
204
|
+
* over by someone else — that's not an error from the caller's POV).
|
|
205
|
+
*/
|
|
206
|
+
async release(
|
|
207
|
+
workspaceId: string,
|
|
208
|
+
branch: string,
|
|
209
|
+
targetPath: string,
|
|
210
|
+
user: AuthUser,
|
|
211
|
+
): Promise<void> {
|
|
212
|
+
await this.db
|
|
213
|
+
.delete(fileLocks)
|
|
214
|
+
.where(
|
|
215
|
+
and(
|
|
216
|
+
eq(fileLocks.workspaceId, workspaceId),
|
|
217
|
+
eq(fileLocks.branch, branch),
|
|
218
|
+
eq(fileLocks.path, targetPath),
|
|
219
|
+
eq(fileLocks.holderUserId, user.id),
|
|
220
|
+
),
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Read the current lock for `(workspace, branch, path)`. Returns null when
|
|
226
|
+
* no one holds it, OR when the existing row is expired — expired locks
|
|
227
|
+
* are purged here lazily.
|
|
228
|
+
*/
|
|
229
|
+
async get(
|
|
230
|
+
workspaceId: string,
|
|
231
|
+
branch: string,
|
|
232
|
+
targetPath: string,
|
|
233
|
+
): Promise<FileLock | null> {
|
|
234
|
+
const rows = await this.db
|
|
235
|
+
.select()
|
|
236
|
+
.from(fileLocks)
|
|
237
|
+
.where(
|
|
238
|
+
and(
|
|
239
|
+
eq(fileLocks.workspaceId, workspaceId),
|
|
240
|
+
eq(fileLocks.branch, branch),
|
|
241
|
+
eq(fileLocks.path, targetPath),
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
.limit(1);
|
|
245
|
+
if (rows.length === 0) return null;
|
|
246
|
+
const row = rows[0];
|
|
247
|
+
if (row.expiresAt.getTime() <= Date.now()) {
|
|
248
|
+
// Lazy GC — drop the stale row so the next `acquire` doesn't have
|
|
249
|
+
// to bypass it. Bind the delete to this exact row's `expiresAt` so
|
|
250
|
+
// a concurrent acquire that wrote a fresh row in the gap between
|
|
251
|
+
// our SELECT and DELETE doesn't get clobbered. Primary key
|
|
252
|
+
// `(workspaceId, branch, path)` alone isn't enough — a new acquire
|
|
253
|
+
// for the same triple updates that row in place with a future
|
|
254
|
+
// expiry, and a path-only delete here would silently nuke it.
|
|
255
|
+
await this.db
|
|
256
|
+
.delete(fileLocks)
|
|
257
|
+
.where(
|
|
258
|
+
and(
|
|
259
|
+
eq(fileLocks.workspaceId, workspaceId),
|
|
260
|
+
eq(fileLocks.branch, branch),
|
|
261
|
+
eq(fileLocks.path, targetPath),
|
|
262
|
+
eq(fileLocks.expiresAt, row.expiresAt),
|
|
263
|
+
),
|
|
264
|
+
);
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
return rowToFileLock(row);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
assertValidBranchName,
|
|
4
|
+
assertValidRelativePath,
|
|
5
|
+
isProtectedBranch,
|
|
6
|
+
} from '../branch-name.js';
|
|
7
|
+
import { BranchNameError, WorkflowValidationError } from '../../workflow.errors.js';
|
|
8
|
+
|
|
9
|
+
describe('assertValidBranchName', () => {
|
|
10
|
+
it.each([
|
|
11
|
+
'ali-raza/add-owner',
|
|
12
|
+
'feature/x',
|
|
13
|
+
'fix_123',
|
|
14
|
+
'v1.2.3',
|
|
15
|
+
'main',
|
|
16
|
+
'release-2026.04',
|
|
17
|
+
])('accepts %s', (name) => {
|
|
18
|
+
expect(() => assertValidBranchName(name)).not.toThrow();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it.each([
|
|
22
|
+
['empty', ''],
|
|
23
|
+
['leading dash', '-dangerous'],
|
|
24
|
+
['semicolon', 'foo;rm -rf /'],
|
|
25
|
+
['backtick', 'foo`whoami`'],
|
|
26
|
+
['space', 'foo bar'],
|
|
27
|
+
['double dot', 'foo..bar'],
|
|
28
|
+
['trailing slash', 'foo/'],
|
|
29
|
+
['trailing dot', 'foo.'],
|
|
30
|
+
['trailing .lock', 'foo.lock'],
|
|
31
|
+
['double slash', 'foo//bar'],
|
|
32
|
+
['ref expansion', 'HEAD@{0}'],
|
|
33
|
+
['null byte', 'foo\x00bar'],
|
|
34
|
+
['newline', 'foo\nbar'],
|
|
35
|
+
['path traversal', '../../etc/passwd'],
|
|
36
|
+
])('rejects %s (%s)', (_label, name) => {
|
|
37
|
+
expect(() => assertValidBranchName(name)).toThrow(BranchNameError);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('assertValidRelativePath', () => {
|
|
42
|
+
it.each([
|
|
43
|
+
'Knowledge/Foo.md',
|
|
44
|
+
'NodeTypes/Process.md',
|
|
45
|
+
'scripts/generate-mermaid.js',
|
|
46
|
+
'a/b/c/d.md',
|
|
47
|
+
'file-with-dash.md',
|
|
48
|
+
// Pathspec glob characters used to be rejected here, but `GitService.git()`
|
|
49
|
+
// now sets `GIT_LITERAL_PATHSPECS=1` on every git subprocess, so KB files
|
|
50
|
+
// arriving with bracketed prefixes (`[Approved]`, `[New]`, `[Updated …]`)
|
|
51
|
+
// or other glob metacharacters round-trip through commit cleanly.
|
|
52
|
+
'[Approved] Purchasing_Order archive.docx',
|
|
53
|
+
'Purchasing/[New] Purchasing_E-Invoicing DE.docx',
|
|
54
|
+
'Purchasing/[Updated 03.09.2025] Purchasing_How to search_Product detail page.docx',
|
|
55
|
+
'docs/wildcard*name.md',
|
|
56
|
+
'docs/question?name.md',
|
|
57
|
+
'docs/bang!name.md',
|
|
58
|
+
])('accepts %s', (p) => {
|
|
59
|
+
expect(() => assertValidRelativePath(p)).not.toThrow();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it.each([
|
|
63
|
+
['empty', ''],
|
|
64
|
+
['absolute unix', '/etc/passwd'],
|
|
65
|
+
['windows drive', 'C:/Users/a'],
|
|
66
|
+
['parent segment', '../etc/passwd'],
|
|
67
|
+
['nested parent', 'a/../b'],
|
|
68
|
+
['current segment', 'a/./b'],
|
|
69
|
+
['null byte', 'a\x00b'],
|
|
70
|
+
['leading dash', '-afile'],
|
|
71
|
+
])('rejects %s (%s)', (_label, p) => {
|
|
72
|
+
expect(() => assertValidRelativePath(p)).toThrow(WorkflowValidationError);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('isProtectedBranch', () => {
|
|
77
|
+
it('protects current-company-state and target-company-state', () => {
|
|
78
|
+
expect(isProtectedBranch('current-company-state')).toBe(true);
|
|
79
|
+
expect(isProtectedBranch('target-company-state')).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
it('does not protect user branches', () => {
|
|
82
|
+
expect(isProtectedBranch('ali-raza/add-owner')).toBe(false);
|
|
83
|
+
expect(isProtectedBranch('main')).toBe(false);
|
|
84
|
+
expect(isProtectedBranch('develop')).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
branchAuthorLocalpart,
|
|
4
|
+
isBranchAuthoredBy,
|
|
5
|
+
} from '@bevel-software/platform-shared';
|
|
6
|
+
|
|
7
|
+
describe('branchAuthorLocalpart', () => {
|
|
8
|
+
it('extracts and lowercases the localpart', () => {
|
|
9
|
+
expect(branchAuthorLocalpart('Alice@example.com')).toBe('alice');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('sanitizes dotted localparts to match slugifyDraftName', () => {
|
|
13
|
+
// The frontend slugifies "john.doe" → "john-doe" when creating drafts,
|
|
14
|
+
// so authorship has to recognise the same shape on lookup.
|
|
15
|
+
expect(branchAuthorLocalpart('john.doe@example.com')).toBe('john-doe');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('sanitizes plus-addressed localparts the same way', () => {
|
|
19
|
+
expect(branchAuthorLocalpart('alice+test@example.com')).toBe('alice-test');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns null for empty / missing email', () => {
|
|
23
|
+
expect(branchAuthorLocalpart('')).toBeNull();
|
|
24
|
+
expect(branchAuthorLocalpart(null)).toBeNull();
|
|
25
|
+
expect(branchAuthorLocalpart(undefined)).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('returns null when the localpart sanitizes to nothing (no auth identity)', () => {
|
|
29
|
+
// Email with only non-alphanumeric chars before @ — refuse to derive an
|
|
30
|
+
// identity rather than silently mapping to a default like "user", which
|
|
31
|
+
// would let any malformed-email user delete any "user/..." branch.
|
|
32
|
+
expect(branchAuthorLocalpart('___@example.com')).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('handles emails with no @ by treating the whole string as localpart', () => {
|
|
36
|
+
// Internal identity systems occasionally use bare usernames; sanitizing
|
|
37
|
+
// them through the same pipeline keeps the comparison consistent.
|
|
38
|
+
expect(branchAuthorLocalpart('alice')).toBe('alice');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('isBranchAuthoredBy', () => {
|
|
43
|
+
it('matches when the branch name starts with <localpart>/', () => {
|
|
44
|
+
expect(isBranchAuthoredBy('alice/my-draft', 'alice@example.com')).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('rejects when prefix is a different user', () => {
|
|
48
|
+
expect(isBranchAuthoredBy('bob/my-draft', 'alice@example.com')).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('rejects when the branch has no slash (no recognisable prefix)', () => {
|
|
52
|
+
expect(isBranchAuthoredBy('alice', 'alice@example.com')).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('rejects conventional non-author prefixes (fix/, polish/)', () => {
|
|
56
|
+
// `fix/...` is a common CLI-created prefix in this repo. It has no author
|
|
57
|
+
// claim, so the authored-by check must NOT grant ownership to anyone.
|
|
58
|
+
expect(isBranchAuthoredBy('fix/some-bug', 'alice@example.com')).toBe(false);
|
|
59
|
+
expect(isBranchAuthoredBy('polish/foo', 'alice@example.com')).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('returns false when email is null / undefined / empty', () => {
|
|
63
|
+
expect(isBranchAuthoredBy('alice/my-draft', null)).toBe(false);
|
|
64
|
+
expect(isBranchAuthoredBy('alice/my-draft', undefined)).toBe(false);
|
|
65
|
+
expect(isBranchAuthoredBy('alice/my-draft', '')).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('matches case-insensitively on the email side (branch is already lowercase by convention)', () => {
|
|
69
|
+
// slugifyDraftName lowercases the email at create time, so a user with
|
|
70
|
+
// capitals in their email still ends up owning a lowercase prefix.
|
|
71
|
+
expect(isBranchAuthoredBy('alice/draft', 'ALICE@example.com')).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('requires the slash boundary — does not treat substring as prefix', () => {
|
|
75
|
+
// "alice-extra/foo" must not look authored by "alice" — otherwise users
|
|
76
|
+
// could delete other people's branches whose prefix happens to start
|
|
77
|
+
// with their own localpart.
|
|
78
|
+
expect(isBranchAuthoredBy('alice-extra/foo', 'alice@example.com')).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { cloneTrackingConfigArgs, ORIGIN_FETCH_REFSPEC } from '../clone-config.js';
|
|
3
|
+
|
|
4
|
+
describe('cloneTrackingConfigArgs', () => {
|
|
5
|
+
// A slashed draft name is the everyday case (`<email-localpart>/<slug>`), and
|
|
6
|
+
// the branch lands verbatim inside the config KEY — pin the exact tuples so a
|
|
7
|
+
// future quoting/encoding change can't silently re-point tracking.
|
|
8
|
+
it('emits the three --replace-all tuples for a slashed branch', () => {
|
|
9
|
+
expect(cloneTrackingConfigArgs('feature/x')).toEqual([
|
|
10
|
+
['config', '--replace-all', 'remote.origin.fetch', ORIGIN_FETCH_REFSPEC],
|
|
11
|
+
['config', '--replace-all', 'branch.feature/x.remote', 'origin'],
|
|
12
|
+
['config', '--replace-all', 'branch.feature/x.merge', 'refs/heads/feature/x'],
|
|
13
|
+
]);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import type { WorkspaceService } from '../../../workspace/workspace.service.js';
|
|
4
|
+
import { WorkflowHooks } from '../../workflow-hooks.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Helpers shared by the GitService integration suites that drive a real git
|
|
8
|
+
* against temp repos (`git.service.pull.test.ts`,
|
|
9
|
+
* `git.service.postMergePull.test.ts`). Not a test file itself — vitest only
|
|
10
|
+
* picks up `*.test.ts`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const execFileAsync = promisify(execFile);
|
|
14
|
+
|
|
15
|
+
/** Run git with a pinned test committer identity, discarding output. */
|
|
16
|
+
export async function runGit(cwd: string, args: string[]): Promise<void> {
|
|
17
|
+
await execFileAsync('git', args, {
|
|
18
|
+
cwd,
|
|
19
|
+
env: {
|
|
20
|
+
...process.env,
|
|
21
|
+
GIT_AUTHOR_NAME: 'Test', GIT_AUTHOR_EMAIL: 't@x.com',
|
|
22
|
+
GIT_COMMITTER_NAME: 'Test', GIT_COMMITTER_EMAIL: 't@x.com',
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Run git and return its trimmed stdout. */
|
|
28
|
+
export async function gitOut(cwd: string, args: string[]): Promise<string> {
|
|
29
|
+
const { stdout } = await execFileAsync('git', args, { cwd });
|
|
30
|
+
return stdout.toString().trim();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** An empty hooks registry — no commit-time validation, so pulls/merges never block. */
|
|
34
|
+
export function stubWorkflowHooks(): WorkflowHooks {
|
|
35
|
+
return new WorkflowHooks();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Resolves each workspace id to its directory, like the real service does. */
|
|
39
|
+
export function stubWorkspaceService(dirs: Record<string, string>): WorkspaceService {
|
|
40
|
+
return {
|
|
41
|
+
getWorkspacePath: async (id: string) => {
|
|
42
|
+
const dir = dirs[id];
|
|
43
|
+
if (!dir) throw new Error(`unexpected workspace ${id}`);
|
|
44
|
+
return dir;
|
|
45
|
+
},
|
|
46
|
+
} as unknown as WorkspaceService;
|
|
47
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { assertGitVersion } from '../git-version.js';
|
|
3
|
+
|
|
4
|
+
// Lives in its own file (not git-version.test.ts) because `git-version.ts`
|
|
5
|
+
// binds `promisify(execFile)` at module load: the spawn failure must be mocked
|
|
6
|
+
// module-wide before that import, which would also break the sibling test that
|
|
7
|
+
// runs against the real git binary.
|
|
8
|
+
vi.mock('node:child_process', () => ({
|
|
9
|
+
execFile: (
|
|
10
|
+
_cmd: string,
|
|
11
|
+
_args: readonly string[],
|
|
12
|
+
cb: (err: Error) => void,
|
|
13
|
+
) => {
|
|
14
|
+
cb(Object.assign(new Error('spawn git ENOENT'), { code: 'ENOENT' }));
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe('assertGitVersion — git binary missing', () => {
|
|
19
|
+
it('wraps the spawn failure in the "git is required" boot error', async () => {
|
|
20
|
+
await expect(assertGitVersion()).rejects.toThrow(
|
|
21
|
+
/git is required but could not be run: .*ENOENT/,
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
MIN_GIT_VERSION,
|
|
4
|
+
parseGitVersion,
|
|
5
|
+
assertSupportedGitVersion,
|
|
6
|
+
assertGitVersion,
|
|
7
|
+
} from '../git-version.js';
|
|
8
|
+
|
|
9
|
+
describe('the git version floor', () => {
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.restoreAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('reads the major/minor out of the shapes git actually prints', () => {
|
|
15
|
+
expect(parseGitVersion('git version 2.39.5\n')).toEqual([2, 39]);
|
|
16
|
+
expect(parseGitVersion('git version 2.39.5 (Apple Git-154)\n')).toEqual([2, 39]);
|
|
17
|
+
expect(parseGitVersion('git version 2.45.1.windows.1\n')).toEqual([2, 45]);
|
|
18
|
+
expect(parseGitVersion('git version 3.0\n')).toEqual([3, 0]);
|
|
19
|
+
expect(parseGitVersion('not git at all')).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('rejects a git too old for --no-write-fetch-head', () => {
|
|
23
|
+
const [major, minor] = MIN_GIT_VERSION;
|
|
24
|
+
expect(() => assertSupportedGitVersion(`git version ${major}.${minor - 1}.0`))
|
|
25
|
+
.toThrow(/git 2\.29 or newer is required, found 2\.28/);
|
|
26
|
+
expect(() => assertSupportedGitVersion('git version 1.9.5')).toThrow(/required/);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('accepts the floor itself and anything newer', () => {
|
|
30
|
+
const [major, minor] = MIN_GIT_VERSION;
|
|
31
|
+
expect(() => assertSupportedGitVersion(`git version ${major}.${minor}.0`)).not.toThrow();
|
|
32
|
+
expect(() => assertSupportedGitVersion('git version 2.39.5')).not.toThrow();
|
|
33
|
+
expect(() => assertSupportedGitVersion('git version 3.0.0')).not.toThrow();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// A git build with an unusual version banner is far more likely than one
|
|
37
|
+
// older than 2.29, so an unreadable string must not take down the boot.
|
|
38
|
+
it('warns but does not block boot on an unreadable version string', () => {
|
|
39
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
40
|
+
expect(() => assertSupportedGitVersion('some vendored git\n')).not.toThrow();
|
|
41
|
+
expect(warn).toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// The real binary on any machine that can run this suite is well past the
|
|
45
|
+
// floor; this pins the wiring (spawn + parse) rather than the version.
|
|
46
|
+
it('passes against the git installed on this machine', async () => {
|
|
47
|
+
await expect(assertGitVersion()).resolves.toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
});
|