@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,361 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { execFile } from 'node:child_process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import {
|
|
7
|
+
AGENTS_DIR,
|
|
8
|
+
DATA_DIR,
|
|
9
|
+
KNOWLEDGE_BASE_DIR,
|
|
10
|
+
PIPELINES_DIR,
|
|
11
|
+
SKILLS_DIR,
|
|
12
|
+
TOOLS_DIR,
|
|
13
|
+
} from '@bevel-software/platform-shared';
|
|
14
|
+
import type { IKbSeedService } from './kb-seed.interface.js';
|
|
15
|
+
|
|
16
|
+
const execFileAsync = promisify(execFile);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Fallback committer identity for seed commits. Mirrors the workspace clone's
|
|
20
|
+
* bot identity so seed commits attribute to the same bot in `git log`.
|
|
21
|
+
*/
|
|
22
|
+
const BOT_NAME = 'Bevel Workflow';
|
|
23
|
+
const BOT_EMAIL = 'bevel-workflow@bevel.software';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The **required scaffolding** — the minimum an operational KB needs. When a
|
|
27
|
+
* branch is loaded, any of these that are missing are added to it; the sample
|
|
28
|
+
* ontology is NOT (it only seeds a fully-empty repo).
|
|
29
|
+
*
|
|
30
|
+
* Two kinds:
|
|
31
|
+
* - {@link REQUIRED_FILES}: repo-root files added when the file is missing.
|
|
32
|
+
* - {@link REQUIRED_DIRS}: well-known root dirs the app expects to exist; when a
|
|
33
|
+
* dir is entirely absent it's created by adding its `<dir>/.gitkeep`. Keyed on
|
|
34
|
+
* the *directory's* existence, not the `.gitkeep` file — so a branch that
|
|
35
|
+
* already has content under `KnowledgeBase/` never gets a pointless placeholder.
|
|
36
|
+
*
|
|
37
|
+
* `roles.yaml` is in neither, and is not part of the template at all: it is
|
|
38
|
+
* generated from `SEED_ADMIN_EMAILS` (see {@link renderRolesYaml}) and written
|
|
39
|
+
* directly, so a repo can't be seeded with a stale hard-coded Admin list.
|
|
40
|
+
*/
|
|
41
|
+
const REQUIRED_FILES: readonly string[] = ['access.md', 'CLAUDE.md', '.bevelignore', '.gitignore'];
|
|
42
|
+
const REQUIRED_DIRS: readonly string[] = [
|
|
43
|
+
KNOWLEDGE_BASE_DIR,
|
|
44
|
+
DATA_DIR,
|
|
45
|
+
AGENTS_DIR,
|
|
46
|
+
PIPELINES_DIR,
|
|
47
|
+
SKILLS_DIR,
|
|
48
|
+
TOOLS_DIR,
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/** Redact the token from any string that might surface in a log or error. */
|
|
52
|
+
function redact(s: string): string {
|
|
53
|
+
const token = process.env.GITHUB_TOKEN;
|
|
54
|
+
return token ? s.replaceAll(token, '***') : s;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Generate `roles.yaml` granting Admin to each seed email. */
|
|
58
|
+
function renderRolesYaml(adminEmails: readonly string[]): string {
|
|
59
|
+
const lines = adminEmails.map((e) => ` - ${e}`).join('\n');
|
|
60
|
+
return (
|
|
61
|
+
'# Identity → role mapping for access control.\n' +
|
|
62
|
+
'# Role names are case- and whitespace-insensitive. The `Admin` role is special:\n' +
|
|
63
|
+
'# only Admins may edit this file, and at least one Admin must always exist.\n' +
|
|
64
|
+
'#\n' +
|
|
65
|
+
'# Generated by the Bevel platform at KB-seed time from SEED_ADMIN_EMAILS.\n' +
|
|
66
|
+
'roles:\n' +
|
|
67
|
+
' Admin:\n' +
|
|
68
|
+
`${lines}\n`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Seeds/tops-up the KB *remote* so the rest of the app's assumption — that the
|
|
74
|
+
* repo it clones already carries the protected branches and base scaffolding —
|
|
75
|
+
* holds even for a brand-new or partially-populated GitHub repo. The template
|
|
76
|
+
* ships inside the platform (`kb-template/`); this reads from it.
|
|
77
|
+
*
|
|
78
|
+
* Split into two moments so the file-level top-up rides along with the clone the
|
|
79
|
+
* app already performs, rather than doing its own extra clones:
|
|
80
|
+
* - {@link ensureRemoteSeeded} runs once before the first clone (an empty remote
|
|
81
|
+
* can't be `clone -b`'d): it seeds an empty repo and makes sure every
|
|
82
|
+
* protected branch *exists* as a ref.
|
|
83
|
+
* - {@link topUpWorkspace} runs on the freshly-cloned workspace of whatever
|
|
84
|
+
* branch a user loads: it fills in any missing base files on that branch.
|
|
85
|
+
*/
|
|
86
|
+
export class KbSeedService implements IKbSeedService {
|
|
87
|
+
/** Single-flight: the first caller runs the remote pass; the rest await its result. */
|
|
88
|
+
private inFlight: Promise<void> | null = null;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param kbRepoUrl Clone/push URL of the KB remote.
|
|
92
|
+
* @param kbTemplateDir Filesystem path to the `kb-template/` seed source.
|
|
93
|
+
* @param protectedBranches Branch names that must exist (e.g. current/target-company-state).
|
|
94
|
+
* @param defaultBranch The branch new checkouts land on — used as the init
|
|
95
|
+
* branch of the empty-seed commit and the preferred
|
|
96
|
+
* base when creating a missing protected branch.
|
|
97
|
+
* @param seedAdminEmails Admins written into the generated `roles.yaml`.
|
|
98
|
+
* @param gitUsername Basic-auth username for git-over-HTTPS (provider-specific).
|
|
99
|
+
*/
|
|
100
|
+
constructor(
|
|
101
|
+
private readonly kbRepoUrl: string,
|
|
102
|
+
private readonly kbTemplateDir: string,
|
|
103
|
+
private readonly protectedBranches: readonly string[],
|
|
104
|
+
private readonly defaultBranch: string,
|
|
105
|
+
private readonly seedAdminEmails: readonly string[],
|
|
106
|
+
private readonly gitUsername: string = 'x-access-token',
|
|
107
|
+
) {}
|
|
108
|
+
|
|
109
|
+
ensureRemoteSeeded(): Promise<void> {
|
|
110
|
+
// Cache the promise, not just a boolean, so concurrent first-callers share
|
|
111
|
+
// one run. On failure we clear it so a later call can retry (a transient
|
|
112
|
+
// network blip on ls-remote shouldn't wedge seeding for the whole process).
|
|
113
|
+
if (!this.inFlight) {
|
|
114
|
+
this.inFlight = this.run().catch((err) => {
|
|
115
|
+
this.inFlight = null;
|
|
116
|
+
throw err;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return this.inFlight;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private async run(): Promise<void> {
|
|
123
|
+
const heads = await this.lsRemoteHeads();
|
|
124
|
+
|
|
125
|
+
if (heads.size === 0) {
|
|
126
|
+
if (this.seedAdminEmails.length === 0) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`KB remote ${redact(this.kbRepoUrl)} is empty and cannot be seeded: ` +
|
|
129
|
+
'set SEED_ADMIN_EMAILS to the initial Admin email(s). A seeded KB with ' +
|
|
130
|
+
'no Admin is unusable (access resolution requires at least one Admin).',
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
await this.seedEmptyRemote();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Non-empty remote: make sure every protected branch exists as a ref so a
|
|
138
|
+
// later `clone -b <branch>` succeeds. This creates the branch pointer only;
|
|
139
|
+
// per-branch file top-up happens in `topUpWorkspace` when the branch loads.
|
|
140
|
+
const base = this.pickBase(heads);
|
|
141
|
+
for (const branch of this.protectedBranches) {
|
|
142
|
+
if (!heads.has(branch)) {
|
|
143
|
+
await this.createBranchOnRemote(branch, base);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Add any missing base scaffolding to an already-cloned workspace of `branch`,
|
|
150
|
+
* then commit + push it. Called once per fresh clone (any branch a user loads),
|
|
151
|
+
* so the check reuses the clone the app already made instead of a dedicated one.
|
|
152
|
+
*
|
|
153
|
+
* Best-effort: never throws. If the push is rejected (e.g. a concurrent update
|
|
154
|
+
* to the branch), the local scaffolding commit is rolled back so the workspace
|
|
155
|
+
* stays consistent with origin, and the top-up is retried on a future clone.
|
|
156
|
+
*/
|
|
157
|
+
async topUpWorkspace(repoDir: string, branch: string): Promise<void> {
|
|
158
|
+
try {
|
|
159
|
+
const added: string[] = [];
|
|
160
|
+
for (const rel of REQUIRED_FILES) {
|
|
161
|
+
if (!(await this.exists(path.join(repoDir, rel)))) {
|
|
162
|
+
await this.copyTemplateFile(rel, repoDir);
|
|
163
|
+
added.push(rel);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const rootDir of REQUIRED_DIRS) {
|
|
167
|
+
if (!(await this.exists(path.join(repoDir, rootDir)))) {
|
|
168
|
+
const keep = `${rootDir}/.gitkeep`;
|
|
169
|
+
await this.copyTemplateFile(keep, repoDir);
|
|
170
|
+
added.push(keep);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (!(await this.exists(path.join(repoDir, 'roles.yaml')))) {
|
|
174
|
+
if (this.seedAdminEmails.length > 0) {
|
|
175
|
+
await fs.writeFile(
|
|
176
|
+
path.join(repoDir, 'roles.yaml'),
|
|
177
|
+
renderRolesYaml(this.seedAdminEmails),
|
|
178
|
+
'utf8',
|
|
179
|
+
);
|
|
180
|
+
added.push('roles.yaml');
|
|
181
|
+
} else {
|
|
182
|
+
console.warn(
|
|
183
|
+
`[kb-seed] Branch "${branch}" is missing roles.yaml but SEED_ADMIN_EMAILS ` +
|
|
184
|
+
'is unset — leaving it absent. Access resolution will fail until an ' +
|
|
185
|
+
'Admin roles.yaml exists; set SEED_ADMIN_EMAILS or add roles.yaml manually.',
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (added.length === 0) return; // already fully scaffolded → no-op
|
|
191
|
+
|
|
192
|
+
// Stamp the bot identity so the commit has an author even if the clone
|
|
193
|
+
// wasn't configured with one (the workspace clone already sets the same
|
|
194
|
+
// values, so this is a harmless no-op there).
|
|
195
|
+
await this.stampIdentity(repoDir);
|
|
196
|
+
await this.git(repoDir, ['add', '--', ...added]);
|
|
197
|
+
await this.git(repoDir, ['commit', '-m', `Add missing KB scaffolding: ${added.join(', ')}`]);
|
|
198
|
+
try {
|
|
199
|
+
await this.git(repoDir, ['push', 'origin', `HEAD:refs/heads/${branch}`]);
|
|
200
|
+
console.log(`[kb-seed] Topped up "${branch}" with: ${added.join(', ')}`);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
// Roll the local branch back to origin so the workspace never sits ahead
|
|
203
|
+
// of the remote (which would confuse the workflow git layer). The files
|
|
204
|
+
// simply aren't present this session; a later fresh clone retries.
|
|
205
|
+
console.warn(
|
|
206
|
+
`[kb-seed] Could not push scaffolding to "${branch}", rolling back local commit:`,
|
|
207
|
+
err instanceof Error ? redact(err.message) : String(err),
|
|
208
|
+
);
|
|
209
|
+
await this.git(repoDir, ['reset', '--hard', `origin/${branch}`]).catch(() => {});
|
|
210
|
+
}
|
|
211
|
+
} catch (err) {
|
|
212
|
+
// Top-up is best-effort infrastructure — a failure here must not block the
|
|
213
|
+
// user from loading the branch.
|
|
214
|
+
console.warn(
|
|
215
|
+
`[kb-seed] Scaffolding top-up for "${branch}" failed (non-fatal):`,
|
|
216
|
+
err instanceof Error ? redact(err.message) : String(err),
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Prefer the default branch as a base, else the first protected branch present, else any head. */
|
|
222
|
+
private pickBase(heads: Set<string>): string {
|
|
223
|
+
if (heads.has(this.defaultBranch)) return this.defaultBranch;
|
|
224
|
+
const protectedPresent = this.protectedBranches.find((b) => heads.has(b));
|
|
225
|
+
if (protectedPresent) return protectedPresent;
|
|
226
|
+
// Deterministic pick so repeated runs behave identically.
|
|
227
|
+
return [...heads].sort()[0];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** `-c` args that inject credentials + longpaths, mirroring the workspace clone. */
|
|
231
|
+
private credArgs(): string[] {
|
|
232
|
+
const args = ['-c', 'core.longpaths=true'];
|
|
233
|
+
const token = process.env.GITHUB_TOKEN;
|
|
234
|
+
if (token) {
|
|
235
|
+
// The helper reads GITHUB_TOKEN at runtime, so the value never appears in argv.
|
|
236
|
+
// Username is provider-specific; the token is always the Basic-auth password.
|
|
237
|
+
args.push(
|
|
238
|
+
'-c',
|
|
239
|
+
`credential.helper=!f() { echo "username=${this.gitUsername}"; echo "password=$GITHUB_TOKEN"; }; f`,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
return args;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private async git(cwd: string | null, args: string[]): Promise<string> {
|
|
246
|
+
try {
|
|
247
|
+
const { stdout } = await execFileAsync('git', args, {
|
|
248
|
+
cwd: cwd ?? undefined,
|
|
249
|
+
env: { ...process.env, LC_ALL: 'C', LANG: 'C' },
|
|
250
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
251
|
+
});
|
|
252
|
+
return stdout.toString();
|
|
253
|
+
} catch (err) {
|
|
254
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
255
|
+
let i = 0;
|
|
256
|
+
while (i < args.length && args[i] === '-c') i += 2;
|
|
257
|
+
throw new Error(`git ${args[i] ?? args[0]} failed: ${redact(msg)}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Set of branch names on the remote (empty ⇒ uninitialised repo). */
|
|
262
|
+
private async lsRemoteHeads(): Promise<Set<string>> {
|
|
263
|
+
const out = await this.git(null, [...this.credArgs(), 'ls-remote', '--heads', this.kbRepoUrl]);
|
|
264
|
+
const heads = new Set<string>();
|
|
265
|
+
for (const line of out.split('\n')) {
|
|
266
|
+
const m = line.match(/\srefs\/heads\/(.+)$/);
|
|
267
|
+
if (m) heads.add(m[1].trim());
|
|
268
|
+
}
|
|
269
|
+
return heads;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Run a block against a throwaway temp dir, always cleaned up. */
|
|
273
|
+
private async withTempDir<T>(fn: (dir: string) => Promise<T>): Promise<T> {
|
|
274
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'kb-seed-'));
|
|
275
|
+
try {
|
|
276
|
+
return await fn(dir);
|
|
277
|
+
} finally {
|
|
278
|
+
await fs.rm(dir, { recursive: true, force: true }).catch(() => {});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private async stampIdentity(repo: string): Promise<void> {
|
|
283
|
+
await this.git(repo, ['config', 'user.name', BOT_NAME]);
|
|
284
|
+
await this.git(repo, ['config', 'user.email', BOT_EMAIL]);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Copy the entire template tree into `dest` (roles.yaml isn't in it — it's generated). */
|
|
288
|
+
private async copyTemplateTree(dest: string): Promise<void> {
|
|
289
|
+
const walk = async (relDir: string): Promise<void> => {
|
|
290
|
+
const abs = path.join(this.kbTemplateDir, relDir);
|
|
291
|
+
const entries = await fs.readdir(abs, { withFileTypes: true });
|
|
292
|
+
for (const entry of entries) {
|
|
293
|
+
const rel = relDir ? path.join(relDir, entry.name) : entry.name;
|
|
294
|
+
if (entry.isDirectory()) {
|
|
295
|
+
await walk(rel);
|
|
296
|
+
} else {
|
|
297
|
+
await this.copyTemplateFile(rel, dest);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
await walk('');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Copy one template file (by repo-relative path) into `dest`, creating parents. */
|
|
305
|
+
private async copyTemplateFile(relPath: string, dest: string): Promise<void> {
|
|
306
|
+
const from = path.join(this.kbTemplateDir, relPath);
|
|
307
|
+
const to = path.join(dest, relPath);
|
|
308
|
+
await fs.mkdir(path.dirname(to), { recursive: true });
|
|
309
|
+
await fs.copyFile(from, to);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** `git init` a temp repo, lay down the full template + generated roles.yaml, commit. */
|
|
313
|
+
private async buildSeedCommit(dir: string): Promise<void> {
|
|
314
|
+
await this.git(dir, ['init', '-b', this.defaultBranch]);
|
|
315
|
+
await this.stampIdentity(dir);
|
|
316
|
+
await this.copyTemplateTree(dir);
|
|
317
|
+
await fs.writeFile(path.join(dir, 'roles.yaml'), renderRolesYaml(this.seedAdminEmails), 'utf8');
|
|
318
|
+
await this.git(dir, ['add', '-A']);
|
|
319
|
+
await this.git(dir, ['commit', '-m', 'Seed knowledge base from Bevel template']);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Empty remote → one seed commit pushed to every protected branch. */
|
|
323
|
+
private async seedEmptyRemote(): Promise<void> {
|
|
324
|
+
await this.withTempDir(async (dir) => {
|
|
325
|
+
await this.buildSeedCommit(dir);
|
|
326
|
+
// Point every protected branch at the seed commit. The init branch is
|
|
327
|
+
// already `defaultBranch`; create the rest as refs to HEAD.
|
|
328
|
+
for (const branch of this.protectedBranches) {
|
|
329
|
+
if (branch !== this.defaultBranch) {
|
|
330
|
+
await this.git(dir, ['branch', branch]);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
await this.git(dir, ['remote', 'add', 'origin', this.kbRepoUrl]);
|
|
334
|
+
// Push only the protected branches — never the stray init branch if it
|
|
335
|
+
// isn't itself protected.
|
|
336
|
+
await this.git(dir, [...this.credArgs(), 'push', '-u', 'origin', ...this.protectedBranches]);
|
|
337
|
+
console.log(
|
|
338
|
+
`[kb-seed] Seeded empty KB remote with branches: ${this.protectedBranches.join(', ')}`,
|
|
339
|
+
);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** Create a missing protected branch on the remote, pointed at `base`'s tip. */
|
|
344
|
+
private async createBranchOnRemote(branch: string, base: string): Promise<void> {
|
|
345
|
+
await this.withTempDir(async (dir) => {
|
|
346
|
+
await this.git(dir, [...this.credArgs(), 'clone', '--depth', '1', '-b', base, this.kbRepoUrl, dir]);
|
|
347
|
+
// Push base's fetched tip up under the new branch name.
|
|
348
|
+
await this.git(dir, [...this.credArgs(), 'push', 'origin', `HEAD:refs/heads/${branch}`]);
|
|
349
|
+
console.log(`[kb-seed] Created missing protected branch "${branch}" from "${base}"`);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private async exists(p: string): Promise<boolean> {
|
|
354
|
+
try {
|
|
355
|
+
await fs.access(p);
|
|
356
|
+
return true;
|
|
357
|
+
} catch {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-run write restriction for background/routine agents.
|
|
3
|
+
*
|
|
4
|
+
* The ontology-session gate ({@link ../workflow/session-ontology.service}) bounds
|
|
5
|
+
* WHICH ontology a run may write; this narrower gate bounds WHAT KIND of file a
|
|
6
|
+
* run may write, by extension. It exists for the `watchlist_check` routine, which is
|
|
7
|
+
* allowed to refresh dashboard views (`.html`) but must never touch the
|
|
8
|
+
* knowledge-graph nodes (`.md`) or any other file — a hard, code-level guarantee
|
|
9
|
+
* rather than a prompt request (a prompt-only rule has already proven insufficient).
|
|
10
|
+
*
|
|
11
|
+
* Keyed by the agent run's `sessionId` (the background agent passes its run id as
|
|
12
|
+
* the session id, which the internal token then carries onto every loopback tool
|
|
13
|
+
* call as `ctx.sessionId`). A restriction lives only for the duration of one
|
|
14
|
+
* in-process run, so the store is a plain in-memory map — no durability needed,
|
|
15
|
+
* unlike the ontology touched-set which must survive restarts and span the MCP
|
|
16
|
+
* proxy. The executor sets the restriction before streaming and clears it after.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { ToolError } from '../tool-helpers/tool.contract.js';
|
|
20
|
+
|
|
21
|
+
export interface IRoutineWritePolicy {
|
|
22
|
+
/**
|
|
23
|
+
* Confine a session's writes to the given file extensions (each including the
|
|
24
|
+
* leading dot, e.g. `['.html', '.htm']`). Overwrites any prior restriction for
|
|
25
|
+
* the session. A session with no restriction is unrestricted (the default for
|
|
26
|
+
* chat + `ontology_ingest` runs).
|
|
27
|
+
*/
|
|
28
|
+
restrictToExtensions(sessionId: string, extensions: readonly string[]): void;
|
|
29
|
+
/** Drop a session's restriction (called at run end). */
|
|
30
|
+
clear(sessionId: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Throw a 403 `ToolError` when the session is restricted and `wsPath`'s
|
|
33
|
+
* extension is not on its allow-list. No session id, or no active restriction,
|
|
34
|
+
* always passes — so this is a no-op for every non-restricted caller.
|
|
35
|
+
*/
|
|
36
|
+
assertPathWritable(sessionId: string | undefined, wsPath: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Throw a 403 `ToolError` when the session is restricted at all — for write
|
|
39
|
+
* tools with no single target path to check (arbitrary shell), which a
|
|
40
|
+
* restricted run must not be able to use as a write bypass.
|
|
41
|
+
*/
|
|
42
|
+
assertUnrestricted(sessionId: string | undefined): void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class RoutineWritePolicyService implements IRoutineWritePolicy {
|
|
46
|
+
/** sessionId → allowed lowercased extensions. Absent = unrestricted. */
|
|
47
|
+
private readonly restrictions = new Map<string, Set<string>>();
|
|
48
|
+
|
|
49
|
+
restrictToExtensions(sessionId: string, extensions: readonly string[]): void {
|
|
50
|
+
this.restrictions.set(sessionId, new Set(extensions.map((e) => e.toLowerCase())));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
clear(sessionId: string): void {
|
|
54
|
+
this.restrictions.delete(sessionId);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
assertPathWritable(sessionId: string | undefined, wsPath: string): void {
|
|
58
|
+
const allowed = sessionId ? this.restrictions.get(sessionId) : undefined;
|
|
59
|
+
if (!allowed) return;
|
|
60
|
+
const lower = wsPath.toLowerCase();
|
|
61
|
+
for (const ext of allowed) {
|
|
62
|
+
if (lower.endsWith(ext)) return;
|
|
63
|
+
}
|
|
64
|
+
throw new ToolError(
|
|
65
|
+
`This run may only write ${[...allowed].join(', ')} files (dashboard views); "${wsPath}" is blocked. ` +
|
|
66
|
+
'Knowledge-graph nodes and other files are read-only for this routine.',
|
|
67
|
+
403,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
assertUnrestricted(sessionId: string | undefined): void {
|
|
72
|
+
if (sessionId && this.restrictions.has(sessionId)) {
|
|
73
|
+
throw new ToolError(
|
|
74
|
+
'This run is restricted to writing dashboard views only, so shell commands (which could write any file) are disabled.',
|
|
75
|
+
403,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ontology-session boundary — the per-call gate used by the agent tool handlers.
|
|
3
|
+
*
|
|
4
|
+
* One decision fn, called by every gated file/graph handler:
|
|
5
|
+
* READS (isWrite=false) record the touched ontology and always allow.
|
|
6
|
+
* WRITES (isWrite=true) run the registered BLOCKING `preWrite` hooks
|
|
7
|
+
* (`WorkflowHooks`), then record. The core registers
|
|
8
|
+
* no hook, so core alone only TRACKS; the enterprise
|
|
9
|
+
* overlay registers the ontology block (see
|
|
10
|
+
* `modules/kb/ontology-block.hook.ts`), restoring
|
|
11
|
+
* "allowed only while the session is confined to a
|
|
12
|
+
* single ontology; once it has touched ≥2, all
|
|
13
|
+
* writes are blocked".
|
|
14
|
+
*
|
|
15
|
+
* Skips entirely when: the flag is off, the path is neutral (`ontologyOf` →
|
|
16
|
+
* null), the caller is not an agent, or the caller is the recovery bot. Fails
|
|
17
|
+
* CLOSED for an agent named-path operation that carries no `sessionId`.
|
|
18
|
+
*
|
|
19
|
+
* Lives beside `assertCanRead` in the workspace tools — it does NOT touch
|
|
20
|
+
* `acquireLock` (that gate is protected-branch-only; this boundary applies on
|
|
21
|
+
* all branches and to reads). See `docs/rp4-ontology-boundary-plan-v2.md`.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { ontologyOf } from '../../shared/kb-layout.js';
|
|
25
|
+
import type { JsonSchema } from '../tool-registry/tool.contract.js';
|
|
26
|
+
import { ToolError, type ToolContext } from '../tool-helpers/tool.contract.js';
|
|
27
|
+
import type { ISessionOntologyService } from '../workflow/session-ontology.service.js';
|
|
28
|
+
import type { WorkflowHooks } from '../workflow/workflow-hooks.js';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The `sessionId` input the ontology-session boundary reads: the agent run /
|
|
32
|
+
* conversation id. The in-process agent supplies its thread id automatically
|
|
33
|
+
* (via its per-run internal token); an external agent has no ambient run id,
|
|
34
|
+
* so it must first mint one with the `start_session` tool and then pass it
|
|
35
|
+
* EXPLICITLY on every gated call — the MCP proxy is a pure passthrough and
|
|
36
|
+
* never injects args.
|
|
37
|
+
*/
|
|
38
|
+
export const SESSION_ID_INPUT: JsonSchema = {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description:
|
|
41
|
+
'The KnowledgeBase session id that scopes this run to one ontology. External agents (direct MCP calls and `call_tool_chain` alike): call the `start_session` tool ONCE at the very start of your work to obtain it, then pass that id here on EVERY gated call. The in-process agent runtime supplies this automatically (do not set it yourself).',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Boundary warning appended to ontology-gated tool descriptions so the agent
|
|
46
|
+
* knows the restriction before it calls one. Action-then-why phrasing per
|
|
47
|
+
* docs/glossary.md.
|
|
48
|
+
*/
|
|
49
|
+
export const ONTOLOGY_BOUNDARY_NOTE =
|
|
50
|
+
' Stay within one KnowledgeBase ontology per conversation: once this run has read or written files in two different ontologies, every later content write (write_file/edit_file/mkdir/unzip, and both endpoints of move_file/copy_file) is blocked with a 403 and no override. Reads and delete_file never block — but each one records the ontology it touched and can poison a later content write, so do broad cross-ontology exploration only when you do not intend to write. Note move_file/copy_file are blocked outright when source and destination are different ontologies, since they would carry content across.';
|
|
51
|
+
|
|
52
|
+
/** Thrown when a write is refused because the session has crossed ontologies. */
|
|
53
|
+
export class OntologyWriteBlockedError extends ToolError {
|
|
54
|
+
constructor(touched: string[], attempted: string, reason: 'multi-ontology' | 'different-ontology') {
|
|
55
|
+
const msg =
|
|
56
|
+
reason === 'multi-ontology'
|
|
57
|
+
? `This conversation has already read across multiple ontologies (${touched.join(', ')}), so writing is no longer allowed. Start a new conversation to write to "${attempted}".`
|
|
58
|
+
: `This conversation is working in ${touched.join(', ')}, so it can't write to a different ontology ("${attempted}"). Start a new conversation to work in "${attempted}".`;
|
|
59
|
+
super(msg, 403);
|
|
60
|
+
this.name = 'OntologyWriteBlockedError';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Thrown when an agent op on a named ontology carries no session id (fail closed). */
|
|
65
|
+
export class MissingSessionError extends ToolError {
|
|
66
|
+
constructor() {
|
|
67
|
+
super(
|
|
68
|
+
'This operation needs a KnowledgeBase session id and none was provided. Call the `start_session` tool once at the start of your work to obtain a sessionId, then pass it explicitly as `sessionId` on every gated call (direct MCP calls and `call_tool_chain` alike).',
|
|
69
|
+
403,
|
|
70
|
+
);
|
|
71
|
+
this.name = 'MissingSessionError';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface SessionOntologyGate {
|
|
76
|
+
service: ISessionOntologyService;
|
|
77
|
+
enabled: boolean;
|
|
78
|
+
kbDirName: string;
|
|
79
|
+
/** Lowercased email of the recovery/merge bot, which is exempt. */
|
|
80
|
+
recoveryBotEmail: string;
|
|
81
|
+
/**
|
|
82
|
+
* The workflow lifecycle-hook registry whose BLOCKING `preWrite` hooks
|
|
83
|
+
* decide whether a gated write/shell op proceeds. Core registers none (the
|
|
84
|
+
* gate then only tracks); the enterprise composition root registers the
|
|
85
|
+
* ontology block against `workflowService.hooks` — pass that same instance
|
|
86
|
+
* here.
|
|
87
|
+
*/
|
|
88
|
+
hooks: WorkflowHooks;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Only internal/external agent callers are gated; `session` (browser JWT) and humans are not. */
|
|
92
|
+
function isAgentSource(ctx: ToolContext): boolean {
|
|
93
|
+
return ctx.source === 'internal' || ctx.source === 'external';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Shared gate preamble for the two per-path operations below. Returns `'skip'`
|
|
98
|
+
* when the boundary doesn't apply to this call (flag off, neutral path,
|
|
99
|
+
* non-agent caller, or recovery bot), otherwise the session id to evaluate
|
|
100
|
+
* against — throwing `MissingSessionError` (fail closed) when an agent op on a
|
|
101
|
+
* named ontology carries none.
|
|
102
|
+
*/
|
|
103
|
+
function resolveGatedSession(gate: SessionOntologyGate, ctx: ToolContext, wsPath: string): string | 'skip' {
|
|
104
|
+
if (!gate.enabled) return 'skip';
|
|
105
|
+
// Neutral paths never pin/record/block — skip before any identity work.
|
|
106
|
+
if (ontologyOf(wsPath, gate.kbDirName) === null) return 'skip';
|
|
107
|
+
// Humans (UI routes) and browser-JWT callers never hit these tools; only
|
|
108
|
+
// agent tool calls are gated.
|
|
109
|
+
if (!isAgentSource(ctx)) return 'skip';
|
|
110
|
+
// The recovery/merge bot legitimately spans ontologies — exempt by identity.
|
|
111
|
+
if (ctx.user.email.toLowerCase() === gate.recoveryBotEmail) return 'skip';
|
|
112
|
+
// Fail closed: an agent operation on a named ontology must carry a session id.
|
|
113
|
+
if (!ctx.sessionId) throw new MissingSessionError();
|
|
114
|
+
return ctx.sessionId;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Record a read of `wsPath`'s ontology into the session's touched set. Reads are
|
|
119
|
+
* always allowed — recording is the only effect — but each one widens the
|
|
120
|
+
* touched set and so can poison a later write (see {@link assertOntologyWriteAllowed}).
|
|
121
|
+
* Fails closed (`MissingSessionError`) for an agent read of a named ontology
|
|
122
|
+
* with no session id.
|
|
123
|
+
*/
|
|
124
|
+
export async function recordOntologyRead(gate: SessionOntologyGate, ctx: ToolContext, wsPath: string): Promise<void> {
|
|
125
|
+
const sessionId = resolveGatedSession(gate, ctx, wsPath);
|
|
126
|
+
if (sessionId === 'skip') return;
|
|
127
|
+
// checkOperation(isWrite=false) records the touch and always allows.
|
|
128
|
+
await gate.service.checkOperation(sessionId, wsPath, false, gate.kbDirName);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Assert a write to `wsPath` is allowed, then record it. A write that would
|
|
133
|
+
* carry information into a second ontology is the thing the boundary blocks:
|
|
134
|
+
* permitted only while the session stays confined to the target ontology, and
|
|
135
|
+
* refused with `OntologyWriteBlockedError` once it has touched ≥2. Note `delete`
|
|
136
|
+
* is NOT a write here — removing a node propagates no cross-ontology
|
|
137
|
+
* information, so it goes through {@link recordOntologyRead}.
|
|
138
|
+
*
|
|
139
|
+
* The BLOCKING decision itself lives behind the `preWrite` hooks: the
|
|
140
|
+
* enterprise-registered ontology block evaluates-and-records atomically via
|
|
141
|
+
* `checkOperation(isWrite=true)` and throws to refuse (identical behavior to
|
|
142
|
+
* the previous in-gate decision). Core registers no hook, so with none the
|
|
143
|
+
* write is allowed and only the touch is recorded (tracking stays core). The
|
|
144
|
+
* follow-up read-record after the hooks is idempotent — a no-op when a hook
|
|
145
|
+
* already recorded the allowed write.
|
|
146
|
+
*/
|
|
147
|
+
export async function assertOntologyWriteAllowed(
|
|
148
|
+
gate: SessionOntologyGate,
|
|
149
|
+
ctx: ToolContext,
|
|
150
|
+
wsPath: string,
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
const sessionId = resolveGatedSession(gate, ctx, wsPath);
|
|
153
|
+
if (sessionId === 'skip') return;
|
|
154
|
+
await gate.hooks.runPreWrite({ kind: 'file-write', sessionId, wsPath });
|
|
155
|
+
// Tracking stays core: record the (now-allowed) write's ontology touch.
|
|
156
|
+
// A blocked write never reaches this line, so it records nothing — same as
|
|
157
|
+
// before the hook split.
|
|
158
|
+
await gate.service.checkOperation(sessionId, wsPath, false, gate.kbDirName);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Session-level write-eligibility gate for write-capable tools that have no
|
|
163
|
+
* single resolvable target path to check per-call — currently `execute_command`
|
|
164
|
+
* (arbitrary shell). Such a tool cannot be path-confined, so we enforce the
|
|
165
|
+
* boundary at the coarser session level: once the run has crossed into ≥2
|
|
166
|
+
* ontologies (the point at which EVERY path-checked write is already refused),
|
|
167
|
+
* we refuse the tool outright, so shell can't become a write path around the
|
|
168
|
+
* boundary. A fresh or single-ontology session is still allowed; a residual gap
|
|
169
|
+
* remains (a single-ontology session could shell-write a *different* ontology),
|
|
170
|
+
* accepted because arbitrary shell cannot be path-confined and blocking all
|
|
171
|
+
* shell after one KB read would gut its read-style diagnostic use (git/grep/ls).
|
|
172
|
+
*
|
|
173
|
+
* Skips when: the flag is off, the caller is not an agent, the caller is the
|
|
174
|
+
* recovery bot, or there is no session id — there is no named path here to fail
|
|
175
|
+
* closed on, and with no session there is no touched set to evaluate.
|
|
176
|
+
*
|
|
177
|
+
* Like {@link assertOntologyWriteAllowed}, the refusal itself is the
|
|
178
|
+
* enterprise-registered `preWrite` hook's (it evaluates the touched set and
|
|
179
|
+
* throws); core registers none, so shell is never refused in a core-only
|
|
180
|
+
* deployment.
|
|
181
|
+
*/
|
|
182
|
+
export async function assertShellAllowedWithinOntology(gate: SessionOntologyGate, ctx: ToolContext): Promise<void> {
|
|
183
|
+
if (!gate.enabled) return;
|
|
184
|
+
if (!isAgentSource(ctx)) return;
|
|
185
|
+
if (ctx.user.email.toLowerCase() === gate.recoveryBotEmail) return;
|
|
186
|
+
if (!ctx.sessionId) return;
|
|
187
|
+
|
|
188
|
+
await gate.hooks.runPreWrite({ kind: 'shell', sessionId: ctx.sessionId });
|
|
189
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Port behind `start_session` (workspace.tools.ts): mints the session id an
|
|
5
|
+
* external agent scopes its ontology boundary under. The workspace module owns
|
|
6
|
+
* the port; WHAT backs the id is the composition root's choice:
|
|
7
|
+
*
|
|
8
|
+
* - Core default ({@link UuidSessionSink}): a bare random id — sufficient for
|
|
9
|
+
* the session-ontology gate, with no app-side session record.
|
|
10
|
+
* - The enterprise app substitutes a sink that mints a REAL chat thread, so the
|
|
11
|
+
* same id also works end to end with `ask` (its sessionId IS a chat thread).
|
|
12
|
+
* See the `start_session` comment in workspace.tools.ts for why that
|
|
13
|
+
* unification matters.
|
|
14
|
+
*/
|
|
15
|
+
export interface ISessionSink {
|
|
16
|
+
/** Mint a session id for an external agent run started at `startedAt`. */
|
|
17
|
+
createSession(userId: string, startedAt: Date): Promise<{ sessionId: string }>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Core default: a bare random id — no app-side session record. */
|
|
21
|
+
export class UuidSessionSink implements ISessionSink {
|
|
22
|
+
async createSession(): Promise<{ sessionId: string }> {
|
|
23
|
+
return { sessionId: randomUUID() };
|
|
24
|
+
}
|
|
25
|
+
}
|