@bevel-software/platform-core-backend 0.33.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-guide/access-control.md +146 -289
- package/agent-guide/conventions.md +23 -25
- package/agent-guide/directory-structure.md +72 -120
- package/agent-guide/drafts-and-change-requests.md +92 -0
- package/agent-guide/for-git-users.md +47 -0
- package/agent-guide/glossary.md +36 -0
- package/agent-guide/how-agents-find-things.md +49 -0
- package/agent-guide/html-views.md +239 -8
- package/agent-guide/new-knowledge-base.md +9 -8
- package/agent-guide/skills.md +67 -42
- package/agent-guide/start-here.md +65 -0
- package/agent-guide/tool-manuals.md +133 -155
- package/agent-guide/tools.md +67 -0
- package/agent-guide/where-a-new-file-goes.md +45 -28
- package/dist/core/catalog-revision.d.ts +12 -1
- package/dist/core/catalog-revision.d.ts.map +1 -1
- package/dist/core/catalog-revision.js +23 -3
- package/dist/core/catalog-revision.js.map +1 -1
- package/dist/core/core-ports.d.ts +41 -0
- package/dist/core/core-ports.d.ts.map +1 -1
- package/dist/core/core-ports.js.map +1 -1
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +15 -8
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +22 -5
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +44 -16
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +16 -0
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +12 -2
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +39 -9
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +15 -3
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +239 -75
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-mutation.service.d.ts +22 -24
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
- package/dist/modules/access/access-mutation.service.js +48 -51
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-view.d.ts.map +1 -1
- package/dist/modules/access/access-view.js +12 -11
- package/dist/modules/access/access-view.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts +3 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +58 -33
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/groups-admin.routes.d.ts.map +1 -1
- package/dist/modules/access/groups-admin.routes.js +4 -2
- package/dist/modules/access/groups-admin.routes.js.map +1 -1
- package/dist/modules/access/groups-admin.service.d.ts +44 -13
- package/dist/modules/access/groups-admin.service.d.ts.map +1 -1
- package/dist/modules/access/groups-admin.service.js +80 -38
- package/dist/modules/access/groups-admin.service.js.map +1 -1
- package/dist/modules/access/groups-edit.d.ts +1 -1
- package/dist/modules/access/groups-edit.d.ts.map +1 -1
- package/dist/modules/access/groups-edit.js +1 -1
- package/dist/modules/access/groups-edit.js.map +1 -1
- package/dist/modules/access/index.d.ts +1 -1
- package/dist/modules/access/index.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.d.ts +116 -24
- package/dist/modules/access/reference-scan.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.js +305 -44
- package/dist/modules/access/reference-scan.js.map +1 -1
- package/dist/modules/access/roles-admin.service.d.ts +17 -8
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +32 -23
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +35 -10
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +60 -20
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/access-model/access-splice.d.ts +22 -18
- package/dist/modules/access-model/access-splice.d.ts.map +1 -1
- package/dist/modules/access-model/access-splice.js +20 -14
- package/dist/modules/access-model/access-splice.js.map +1 -1
- package/dist/modules/access-model/group-files.d.ts +1 -0
- package/dist/modules/access-model/group-files.d.ts.map +1 -1
- package/dist/modules/access-model/group-files.js +5 -1
- package/dist/modules/access-model/group-files.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.d.ts +47 -7
- package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.js +103 -13
- package/dist/modules/agent-guide/agent-guide.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.d.ts +6 -2
- package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.js +46 -22
- package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -1
- package/dist/modules/agent-guide/guide-budget.d.ts +48 -0
- package/dist/modules/agent-guide/guide-budget.d.ts.map +1 -0
- package/dist/modules/agent-guide/guide-budget.js +67 -0
- package/dist/modules/agent-guide/guide-budget.js.map +1 -0
- package/dist/modules/agent-guide/index.d.ts +2 -1
- package/dist/modules/agent-guide/index.d.ts.map +1 -1
- package/dist/modules/agent-guide/index.js +2 -1
- package/dist/modules/agent-guide/index.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +3 -1
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +7 -1
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +5 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.js +26 -9
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
- package/dist/modules/agent-scope/agent-scope.contract.d.ts +67 -0
- package/dist/modules/agent-scope/agent-scope.contract.d.ts.map +1 -0
- package/dist/modules/agent-scope/agent-scope.contract.js +27 -0
- package/dist/modules/agent-scope/agent-scope.contract.js.map +1 -0
- package/dist/modules/agent-scope/connection-scope.d.ts +111 -0
- package/dist/modules/agent-scope/connection-scope.d.ts.map +1 -0
- package/dist/modules/agent-scope/connection-scope.js +165 -0
- package/dist/modules/agent-scope/connection-scope.js.map +1 -0
- package/dist/modules/agent-scope/index.d.ts +3 -0
- package/dist/modules/agent-scope/index.d.ts.map +1 -0
- package/dist/modules/agent-scope/index.js +3 -0
- package/dist/modules/agent-scope/index.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
- package/dist/modules/audit/agent-audit.service.js +2 -0
- package/dist/modules/audit/agent-audit.service.js.map +1 -1
- package/dist/modules/audit/audit.contract.d.ts +6 -0
- package/dist/modules/audit/audit.contract.d.ts.map +1 -1
- package/dist/modules/audit/audit.contract.js.map +1 -1
- package/dist/modules/auth/account-admission.d.ts +12 -0
- package/dist/modules/auth/account-admission.d.ts.map +1 -1
- package/dist/modules/auth/account-admission.js +15 -0
- package/dist/modules/auth/account-admission.js.map +1 -1
- package/dist/modules/auth/auth.middleware.d.ts +27 -1
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
- package/dist/modules/auth/auth.middleware.js +42 -4
- package/dist/modules/auth/auth.middleware.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts +13 -9
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +35 -29
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +55 -6
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +128 -34
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/index.d.ts +1 -1
- package/dist/modules/auth/index.d.ts.map +1 -1
- package/dist/modules/auth/index.js +1 -1
- package/dist/modules/auth/index.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +2 -9
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +2 -2
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts +0 -12
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +1 -38
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +68 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +33 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts +8 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.js +13 -2
- package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
- package/dist/modules/embed/embed.tools.d.ts.map +1 -1
- package/dist/modules/embed/embed.tools.js +5 -0
- package/dist/modules/embed/embed.tools.js.map +1 -1
- package/dist/modules/kb-fs/index.d.ts +2 -0
- package/dist/modules/kb-fs/index.d.ts.map +1 -1
- package/dist/modules/kb-fs/index.js +1 -0
- package/dist/modules/kb-fs/index.js.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +7 -1
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +26 -6
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +22 -7
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-fs/tmp-ref.d.ts +36 -0
- package/dist/modules/kb-fs/tmp-ref.d.ts.map +1 -0
- package/dist/modules/kb-fs/tmp-ref.js +76 -0
- package/dist/modules/kb-fs/tmp-ref.js.map +1 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +7 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +14 -1
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.routes.d.ts +7 -1
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.routes.js +39 -4
- package/dist/modules/mcp/mcp.routes.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +11 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +74 -48
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +45 -10
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +9 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +34 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
- package/dist/modules/plugins/index.d.ts +1 -1
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +18 -2
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +5 -1
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +32 -5
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +11 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +159 -24
- package/dist/modules/secrets-vault/db-secrets-vault.service.js.map +1 -1
- package/dist/modules/secrets-vault/index.d.ts +1 -1
- package/dist/modules/secrets-vault/index.d.ts.map +1 -1
- package/dist/modules/secrets-vault/index.js +1 -1
- package/dist/modules/secrets-vault/index.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +53 -11
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.js +27 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +9 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +100 -42
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/oidc-check.d.ts.map +1 -1
- package/dist/modules/settings/oidc-check.js +5 -17
- package/dist/modules/settings/oidc-check.js.map +1 -1
- package/dist/modules/skills/index.d.ts +3 -3
- package/dist/modules/skills/index.d.ts.map +1 -1
- package/dist/modules/skills/index.js +0 -2
- package/dist/modules/skills/index.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +16 -0
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +6 -1
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +25 -13
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +11 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts +1 -0
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +4 -1
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/index.d.ts +1 -1
- package/dist/modules/tool-auth/index.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +9 -0
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.js +1 -0
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +27 -3
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +32 -6
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts +7 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +3 -0
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-helpers/tool-def.js +1 -1
- package/dist/modules/tool-helpers/tool-def.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts +15 -0
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +19 -0
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +10 -0
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
- package/dist/modules/tool-helpers/validate-token.d.ts +3 -1
- package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -1
- package/dist/modules/tool-helpers/validate-token.js +1 -1
- package/dist/modules/tool-helpers/validate-token.js.map +1 -1
- package/dist/modules/tool-manuals/index.d.ts +3 -3
- package/dist/modules/tool-manuals/index.d.ts.map +1 -1
- package/dist/modules/tool-manuals/index.js +0 -2
- package/dist/modules/tool-manuals/index.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +7 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +69 -38
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +46 -6
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +7 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +41 -4
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +24 -13
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +138 -59
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +8 -2
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +56 -20
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/manual.routes.d.ts +8 -1
- package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -1
- package/dist/modules/tool-registry/manual.routes.js +27 -7
- package/dist/modules/tool-registry/manual.routes.js.map +1 -1
- package/dist/modules/tool-registry/tool.contract.d.ts +7 -0
- package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-registry/tool.contract.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +36 -27
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +2 -2
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +20 -35
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +2 -1
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +3 -0
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -1
- package/dist/modules/workspace/agent-access.gate.js +1 -1
- package/dist/modules/workspace/agent-access.gate.js.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +28 -4
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js +61 -40
- package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
- package/dist/modules/workspace/index.d.ts +8 -0
- package/dist/modules/workspace/index.d.ts.map +1 -1
- package/dist/modules/workspace/index.js +8 -0
- package/dist/modules/workspace/index.js.map +1 -1
- package/dist/modules/workspace/nul-scan.d.ts +19 -0
- package/dist/modules/workspace/nul-scan.d.ts.map +1 -0
- package/dist/modules/workspace/nul-scan.js +55 -0
- package/dist/modules/workspace/nul-scan.js.map +1 -0
- package/dist/modules/workspace/pattern-matcher.contract.d.ts +110 -27
- package/dist/modules/workspace/pattern-matcher.contract.d.ts.map +1 -1
- package/dist/modules/workspace/pattern-matcher.contract.js +30 -13
- package/dist/modules/workspace/pattern-matcher.contract.js.map +1 -1
- package/dist/modules/workspace/ripgrep-search.d.ts +54 -0
- package/dist/modules/workspace/ripgrep-search.d.ts.map +1 -0
- package/dist/modules/workspace/ripgrep-search.js +657 -0
- package/dist/modules/workspace/ripgrep-search.js.map +1 -0
- package/dist/modules/workspace/ripgrep-version.d.ts +15 -0
- package/dist/modules/workspace/ripgrep-version.d.ts.map +1 -0
- package/dist/modules/workspace/ripgrep-version.js +31 -0
- package/dist/modules/workspace/ripgrep-version.js.map +1 -0
- package/dist/modules/workspace/startup/beside-checkout.d.ts +8 -5
- package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -1
- package/dist/modules/workspace/startup/beside-checkout.js +14 -5
- package/dist/modules/workspace/startup/beside-checkout.js.map +1 -1
- package/dist/modules/workspace/worker-pool.d.ts +3 -4
- package/dist/modules/workspace/worker-pool.d.ts.map +1 -1
- package/dist/modules/workspace/worker-pool.js.map +1 -1
- package/dist/modules/workspace/workspace-tmp.d.ts +146 -0
- package/dist/modules/workspace/workspace-tmp.d.ts.map +1 -0
- package/dist/modules/workspace/workspace-tmp.js +435 -0
- package/dist/modules/workspace/workspace-tmp.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +5 -26
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +47 -6
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +86 -6
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +3 -2
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +531 -137
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/shared/oauth-token-error.d.ts +23 -0
- package/dist/shared/oauth-token-error.d.ts.map +1 -0
- package/dist/shared/oauth-token-error.js +47 -0
- package/dist/shared/oauth-token-error.js.map +1 -0
- package/dist/shared/path-order.d.ts +28 -8
- package/dist/shared/path-order.d.ts.map +1 -1
- package/dist/shared/path-order.js +37 -8
- package/dist/shared/path-order.js.map +1 -1
- package/dist/shared/read-capped.d.ts +19 -0
- package/dist/shared/read-capped.d.ts.map +1 -0
- package/dist/shared/read-capped.js +45 -0
- package/dist/shared/read-capped.js.map +1 -0
- package/migrations/0022_session_version.sql +6 -0
- package/migrations/0023_agent_path.sql +3 -0
- package/migrations/meta/0022_snapshot.json +2360 -0
- package/migrations/meta/0023_snapshot.json +2378 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +4 -3
- package/src/__tests__/hexis-catalog.ts +144 -0
- package/src/__tests__/pg-scratch.test.ts +69 -0
- package/src/__tests__/pg-scratch.ts +31 -0
- package/src/__tests__/real-disk.ts +21 -0
- package/src/__tests__/slow-ripgrep.ts +65 -0
- package/src/__tests__/tokens.ts +19 -0
- package/src/__tests__/tool-manuals.ts +32 -0
- package/src/__tests__/tool-wiring.ts +25 -0
- package/src/core/__tests__/boot-without-ripgrep.test.ts +34 -0
- package/src/core/__tests__/catalog-revision.test.ts +89 -0
- package/src/core/__tests__/damaged-document.tools.test.ts +2 -2
- package/src/core/__tests__/gated-boot.test.ts +8 -1
- package/src/core/__tests__/lifecycle.test.ts +46 -13
- package/src/core/__tests__/oauth-sign-in-real-file.test.ts +179 -0
- package/src/core/catalog-revision.ts +24 -2
- package/src/core/core-ports.ts +42 -0
- package/src/core/create-core-server.ts +14 -1
- package/src/core/create-core-services.ts +62 -15
- package/src/core/lifecycle.ts +26 -2
- package/src/index.ts +1 -1
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +12 -0
- package/src/modules/access/__tests__/access-control.colliding-name-cases.test.ts +113 -0
- package/src/modules/access/__tests__/access-control.frontmatter-head.test.ts +117 -0
- package/src/modules/access/__tests__/access-control.group-named-admin.test.ts +122 -0
- package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +50 -0
- package/src/modules/access/__tests__/access-declarations.test.ts +19 -0
- package/src/modules/access/__tests__/access-groups.test.ts +55 -22
- package/src/modules/access/__tests__/access-mutation.service.test.ts +85 -59
- package/src/modules/access/__tests__/access-restrict-here.test.ts +7 -5
- package/src/modules/access/__tests__/access.routes.admins.test.ts +1 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -0
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -0
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +50 -14
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +1 -0
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +52 -10
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +18 -13
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -0
- package/src/modules/access/__tests__/grant-sources.test.ts +20 -15
- package/src/modules/access/__tests__/groups-admin.routes.test.ts +61 -0
- package/src/modules/access/__tests__/groups-admin.service.test.ts +211 -18
- package/src/modules/access/__tests__/holder-changes.test.ts +127 -0
- package/src/modules/access/__tests__/reference-scan.test.ts +366 -14
- package/src/modules/access/__tests__/roles-admin.security.test.ts +1 -1
- package/src/modules/access/__tests__/roles-admin.service.test.ts +43 -22
- package/src/modules/access/__tests__/roles-capabilities.test.ts +6 -2
- package/src/modules/access/__tests__/roles.routes.test.ts +1 -1
- package/src/modules/access/access-control.interface.ts +43 -10
- package/src/modules/access/access-control.service.ts +250 -72
- package/src/modules/access/access-mutation.service.ts +48 -53
- package/src/modules/access/access-view.ts +12 -10
- package/src/modules/access/access.routes.ts +66 -37
- package/src/modules/access/groups-admin.routes.ts +4 -2
- package/src/modules/access/groups-admin.service.ts +114 -44
- package/src/modules/access/groups-edit.ts +1 -1
- package/src/modules/access/index.ts +1 -1
- package/src/modules/access/reference-scan.ts +319 -46
- package/src/modules/access/roles-admin.service.ts +43 -26
- package/src/modules/access/synced-groups-writer.ts +1 -1
- package/src/modules/access-model/__tests__/access-grammar.test.ts +38 -1
- package/src/modules/access-model/__tests__/access-splice.test.ts +50 -8
- package/src/modules/access-model/access-grammar.ts +65 -20
- package/src/modules/access-model/access-splice.ts +31 -23
- package/src/modules/access-model/group-files.ts +5 -0
- package/src/modules/agent-guide/__tests__/agent-guide.test.ts +110 -25
- package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +38 -11
- package/src/modules/agent-guide/__tests__/guide-budget.test.ts +95 -0
- package/src/modules/agent-guide/__tests__/guide-eval.test.ts +182 -0
- package/src/modules/agent-guide/__tests__/guide-matches-code.test.ts +263 -0
- package/src/modules/agent-guide/__tests__/tool-surface.json +514 -0
- package/src/modules/agent-guide/__tests__/tool-surface.test.ts +75 -0
- package/src/modules/agent-guide/agent-guide.tools.ts +51 -22
- package/src/modules/agent-guide/agent-guide.ts +120 -13
- package/src/modules/agent-guide/guide-budget.ts +73 -0
- package/src/modules/agent-guide/index.ts +12 -0
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +5 -4
- package/src/modules/agent-instructions/compose.ts +7 -1
- package/src/modules/agent-instructions/shared-file-rules.ts +27 -9
- package/src/modules/agent-scope/__tests__/agent-surfaces.connect-as.test.ts +421 -0
- package/src/modules/agent-scope/__tests__/connection-scope.test.ts +46 -0
- package/src/modules/agent-scope/__tests__/in-memory-kb.ts +148 -0
- package/src/modules/agent-scope/agent-scope.contract.ts +83 -0
- package/src/modules/agent-scope/connection-scope.ts +199 -0
- package/src/modules/agent-scope/index.ts +15 -0
- package/src/modules/audit/agent-audit.service.ts +2 -0
- package/src/modules/audit/audit.contract.ts +6 -0
- package/src/modules/auth/__tests__/auth.middleware.test.ts +30 -2
- package/src/modules/auth/__tests__/auth.routes.test.ts +71 -5
- package/src/modules/auth/__tests__/auth.service.test.ts +90 -9
- package/src/modules/auth/__tests__/password-change-sessions.pg.test.ts +269 -0
- package/src/modules/auth/account-admission.ts +19 -0
- package/src/modules/auth/auth.middleware.ts +45 -4
- package/src/modules/auth/auth.routes.ts +46 -29
- package/src/modules/auth/auth.service.ts +135 -34
- package/src/modules/auth/index.ts +2 -0
- package/src/modules/auth/oidc-auth-provider.ts +2 -9
- package/src/modules/code-mode/code-mode.tool.ts +2 -2
- package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +5 -24
- package/src/modules/connection-probe/connection-probe.service.ts +1 -34
- package/src/modules/database/__tests__/session-version-migration.pg.test.ts +133 -0
- package/src/modules/database/core-schema.ts +33 -0
- package/src/modules/declared-variables/__tests__/declared-variables.route.test.ts +44 -1
- package/src/modules/declared-variables/declared-variables.routes.ts +12 -1
- package/src/modules/embed/__tests__/embed.tools.test.ts +12 -0
- package/src/modules/embed/embed.tools.ts +5 -0
- package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +25 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +53 -8
- package/src/modules/kb-fs/index.ts +2 -0
- package/src/modules/kb-fs/locking-filesystem.ts +7 -1
- package/src/modules/kb-fs/repo-path.ts +33 -7
- package/src/modules/kb-fs/tmp-ref.ts +81 -0
- package/src/modules/mcp/__tests__/connect-as.pg.test.ts +137 -0
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +29 -5
- package/src/modules/mcp/__tests__/mcp-routes-harness.ts +8 -0
- package/src/modules/mcp/__tests__/mcp.connect-as.test.ts +195 -0
- package/src/modules/mcp/__tests__/mcp.routes.connect-as.test.ts +192 -0
- package/src/modules/mcp/__tests__/oauth-consent.connect-as.test.ts +146 -0
- package/src/modules/mcp/mcp-auth.middleware.ts +19 -2
- package/src/modules/mcp/mcp.routes.ts +39 -3
- package/src/modules/mcp/mcp.service.ts +112 -52
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +46 -8
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +41 -1
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +38 -2
- package/src/modules/plugins/index.ts +1 -1
- package/src/modules/plugins/plugin-links.ts +19 -2
- package/src/modules/plugins/plugins.routes.ts +35 -4
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +113 -0
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +430 -3
- package/src/modules/secrets-vault/__tests__/oauth-live-declaration.route.test.ts +218 -0
- package/src/modules/secrets-vault/__tests__/oauth-return-to.route.test.ts +39 -6
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +170 -27
- package/src/modules/secrets-vault/index.ts +1 -1
- package/src/modules/secrets-vault/secrets-vault.contract.ts +61 -11
- package/src/modules/secrets-vault/secrets-vault.routes.ts +114 -42
- package/src/modules/settings/oidc-check.ts +5 -18
- package/src/modules/skills/__tests__/skills.service.test.ts +34 -0
- package/src/modules/skills/index.ts +7 -2
- package/src/modules/skills/skills.contract.ts +17 -0
- package/src/modules/skills/skills.service.ts +5 -1
- package/src/modules/skills/skills.tools.ts +45 -14
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +4 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +11 -1
- package/src/modules/tool-auth/external-api-key.service.ts +5 -2
- package/src/modules/tool-auth/index.ts +1 -1
- package/src/modules/tool-auth/internal-token.service.ts +10 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +45 -3
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +19 -11
- package/src/modules/tool-helpers/__tests__/can-write.tools.test.ts +3 -1
- package/src/modules/tool-helpers/__tests__/route-tool-schemas.catalog.test.ts +38 -0
- package/src/modules/tool-helpers/tool-context.ts +10 -0
- package/src/modules/tool-helpers/tool-def.ts +1 -1
- package/src/modules/tool-helpers/tool-handler.ts +34 -0
- package/src/modules/tool-helpers/tool.contract.ts +10 -0
- package/src/modules/tool-helpers/validate-token.ts +4 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +80 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +197 -11
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +42 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +99 -8
- package/src/modules/tool-manuals/index.ts +6 -2
- package/src/modules/tool-manuals/mcp-json-discovery.ts +73 -34
- package/src/modules/tool-manuals/tool-manuals.contract.ts +40 -6
- package/src/modules/tool-manuals/tool-manuals.routes.ts +40 -3
- package/src/modules/tool-manuals/tool-manuals.service.ts +169 -61
- package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -25
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +6 -113
- package/src/modules/tool-registry/manual.routes.ts +26 -5
- package/src/modules/tool-registry/tool.contract.ts +7 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +1 -1
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +54 -3
- package/src/modules/workflow/agent-tools/workflow.tools.ts +36 -27
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +130 -3
- package/src/modules/workflow/git/git.service.ts +29 -48
- package/src/modules/workflow/workflow.service.ts +5 -0
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -2
- package/src/modules/workspace/__tests__/holds-nul.test.ts +66 -0
- package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +3 -3
- package/src/modules/workspace/__tests__/ripgrep-search.test.ts +570 -0
- package/src/modules/workspace/__tests__/ripgrep-version.test.ts +29 -0
- package/src/modules/workspace/__tests__/workspace-tmp.tools.test.ts +928 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +17 -37
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +20 -8
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -12
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +22 -10
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +549 -162
- package/src/modules/workspace/agent-access.gate.ts +1 -1
- package/src/modules/workspace/file-readers/__tests__/doc-extract.service.test.ts +10 -0
- package/src/modules/workspace/file-readers/doc-extract.service.ts +71 -38
- package/src/modules/workspace/index.ts +20 -0
- package/src/modules/workspace/nul-scan.ts +50 -0
- package/src/modules/workspace/pattern-matcher.contract.ts +123 -32
- package/src/modules/workspace/ripgrep-search.ts +715 -0
- package/src/modules/workspace/ripgrep-version.ts +35 -0
- package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +11 -0
- package/src/modules/workspace/startup/beside-checkout.ts +13 -5
- package/src/modules/workspace/worker-pool.ts +3 -4
- package/src/modules/workspace/workspace-tmp.ts +457 -0
- package/src/modules/workspace/workspace.routes.ts +6 -27
- package/src/modules/workspace/workspace.service.ts +92 -15
- package/src/modules/workspace/workspace.tools.ts +574 -176
- package/src/shared/__tests__/read-capped.test.ts +68 -0
- package/src/shared/oauth-token-error.ts +46 -0
- package/src/shared/path-order.ts +37 -8
- package/src/shared/read-capped.ts +40 -0
- package/starter-packs/engineering/Plugins/engineering-starter/access.md +1 -1
- package/starter-packs/general/Plugins/general-starter/access.md +1 -1
- package/starter-packs/operations/Plugins/operations-starter/access.md +1 -1
- package/starter-packs/sales/Plugins/sales-starter/access.md +1 -1
- package/starter-packs/support/Plugins/support-starter/access.md +1 -1
- package/agent-guide/finding-things.md +0 -7
- package/agent-guide/introduction.md +0 -27
- package/dist/modules/workspace/bounded-matcher.d.ts +0 -73
- package/dist/modules/workspace/bounded-matcher.d.ts.map +0 -1
- package/dist/modules/workspace/bounded-matcher.js +0 -200
- package/dist/modules/workspace/bounded-matcher.js.map +0 -1
- package/src/modules/workspace/__tests__/bounded-matcher.test.ts +0 -213
- package/src/modules/workspace/bounded-matcher.ts +0 -271
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
scopesCovered,
|
|
11
11
|
missingScopes,
|
|
12
12
|
configuredAs,
|
|
13
|
+
type DeclaredOAuthProvider,
|
|
13
14
|
type ISecretsVaultService,
|
|
14
15
|
} from './secrets-vault.contract.js';
|
|
15
16
|
import type { IToolManualService, ToolManualSummary, ToolVariable } from '../tool-manuals/index.js';
|
|
@@ -17,10 +18,19 @@ import type { IConnectionProbeService } from '../connection-probe/index.js';
|
|
|
17
18
|
import { utcpNamespacedKey } from '../../shared/utcp-namespace.js';
|
|
18
19
|
import type { IAccessControl } from '../access/index.js';
|
|
19
20
|
import type { KbContext } from '../../shared/kb-context.js';
|
|
21
|
+
import { resolveConnectionScope, type IAgentScopeResolver } from '../agent-scope/index.js';
|
|
20
22
|
import '../auth/index.js'; // Express Request augmentation (req.userId / req.userEmail)
|
|
21
23
|
|
|
22
24
|
export interface SecretsVaultRoutesDeps {
|
|
23
25
|
secretsVault: ISecretsVaultService;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves what a connection made as an agent configuration loads, so the connect
|
|
28
|
+
* page can list only the tools the chosen agent would reach (`?agent=`).
|
|
29
|
+
* Optional: a construction without one answers such a request as a
|
|
30
|
+
* connection that loads nothing — a narrowing that cannot be read is never
|
|
31
|
+
* read as Everything.
|
|
32
|
+
*/
|
|
33
|
+
agents?: Pick<IAgentScopeResolver, 'resolve'>;
|
|
24
34
|
/** The released branch's clone — where the `.tool` files the access verdicts are read from live. */
|
|
25
35
|
kb: Pick<KbContext, 'defaultWorkspaceId'>;
|
|
26
36
|
/** Source of `.tool` manuals + their declared variable scopes (default-branch catalog). */
|
|
@@ -44,6 +54,38 @@ function redirectUriFor(publicBackendUrl: string): string {
|
|
|
44
54
|
return `${publicBackendUrl}/api/secrets/oauth/callback`;
|
|
45
55
|
}
|
|
46
56
|
|
|
57
|
+
/**
|
|
58
|
+
* What of a declared sign-in is its provider configuration — ONE reading, for
|
|
59
|
+
* the client-secret save (which stores it as a record) and the sign-in start
|
|
60
|
+
* (which runs from it). `null` while the declaration has no endpoints: it named
|
|
61
|
+
* only its client id and the server's metadata could not complete it.
|
|
62
|
+
*/
|
|
63
|
+
function declaredProvider(variable: ToolVariable): DeclaredOAuthProvider | null {
|
|
64
|
+
const oauth = variable.oauth;
|
|
65
|
+
if (!oauth?.authorizationUrl || !oauth.tokenUrl) return null;
|
|
66
|
+
return {
|
|
67
|
+
authorizationUrl: oauth.authorizationUrl,
|
|
68
|
+
tokenUrl: oauth.tokenUrl,
|
|
69
|
+
clientId: oauth.clientId,
|
|
70
|
+
scopes: oauth.scopes,
|
|
71
|
+
// Static authorize params (e.g. Google's `access_type=offline`) so the
|
|
72
|
+
// provider returns a refresh token.
|
|
73
|
+
authParams: oauth.authParams,
|
|
74
|
+
// PKCE unless the declaration opted out; the resource indicator when the
|
|
75
|
+
// server (or the declaration) names one.
|
|
76
|
+
pkce: oauth.pkce !== false,
|
|
77
|
+
resource: oauth.resource,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Why a declared sign-in has no endpoints — the discovery's own reason when it gave one. */
|
|
82
|
+
function endpointsUnknown(manual: ToolManualSummary): string {
|
|
83
|
+
const why = manual.setup?.reason;
|
|
84
|
+
return why
|
|
85
|
+
? `The sign-in endpoints for this server aren't known yet: ${why}.`
|
|
86
|
+
: "The sign-in endpoints for this server aren't known yet — declare `authorizationUrl` and `tokenUrl` on the sign-in variable.";
|
|
87
|
+
}
|
|
88
|
+
|
|
47
89
|
/**
|
|
48
90
|
* Is this a SAME-ORIGIN path we're willing to bounce the browser back to after a
|
|
49
91
|
* sign-in? The callback builds `${publicFrontendUrl}${dest}#…`, so anything that
|
|
@@ -267,12 +309,21 @@ export function createSecretsVaultRoutes(deps: SecretsVaultRoutesDeps): express.
|
|
|
267
309
|
// that is already set is nobody's outstanding work, so it is dropped. What is
|
|
268
310
|
// not relaxed is readability: the listing is still built from `listAccessible`,
|
|
269
311
|
// so a tool the caller may not read is named here in no state at all.
|
|
312
|
+
//
|
|
313
|
+
// `?agent=<path>` — the consent step's "Connect as" choice — narrows the
|
|
314
|
+
// listing to what a connection made as that agent configuration would load, by the
|
|
315
|
+
// ONE answer every agent surface asks (`ConnectionScope.allowsConnector`,
|
|
316
|
+
// applied after the read gate exactly as the tool listing applies it). A
|
|
317
|
+
// sign-in the connection will never reach is not on a page about what the
|
|
318
|
+
// connection needs. Absent, the listing is Everything's, as it always was.
|
|
270
319
|
router.get('/connect/pending', async (req, res) => {
|
|
271
320
|
const userId = req.userId;
|
|
272
321
|
const email = req.userEmail;
|
|
273
322
|
if (!userId || !email) return void res.status(401).json({ error: 'Not authenticated' });
|
|
274
323
|
try {
|
|
275
|
-
const
|
|
324
|
+
const agentPath = typeof req.query.agent === 'string' && req.query.agent.trim() !== '' ? req.query.agent : null;
|
|
325
|
+
const scope = await resolveConnectionScope(deps.agents, email, agentPath);
|
|
326
|
+
const manuals = (await toolManualService.listAccessible(email)).filter((m) => scope.allowsConnector(m.path));
|
|
276
327
|
// BOTH tiers now — the workspace values are reported as well, so their
|
|
277
328
|
// stored state has to be asked for.
|
|
278
329
|
const allKeys = manuals.flatMap((m) => (m.variables ?? []).map((v) => varKey(m.name, v.name)));
|
|
@@ -371,9 +422,11 @@ export function createSecretsVaultRoutes(deps: SecretsVaultRoutesDeps): express.
|
|
|
371
422
|
// Secrets page. A TOOL sign-in provisions a per-user row in the same
|
|
372
423
|
// table (keyed `<manual>_<VAR>`), so exclude every tool-var key here or
|
|
373
424
|
// an authorized tool sign-in would render twice — once as a toolOAuth
|
|
374
|
-
// row and again as a "standalone" one.
|
|
425
|
+
// row and again as a "standalone" one. They belong to no connector, so
|
|
426
|
+
// a connection narrowed to an agent's connectors has nothing to do with
|
|
427
|
+
// them: listed for Everything only.
|
|
375
428
|
const toolOAuthKeys = new Set(toolOAuth.map((o) => o.key));
|
|
376
|
-
const secrets = await secretsVault.list(userId);
|
|
429
|
+
const secrets = scope.isEverything() ? await secretsVault.list(userId) : [];
|
|
377
430
|
const oauth = secrets
|
|
378
431
|
.filter((s) => s.kind === 'oauth' && !toolOAuthKeys.has(s.key))
|
|
379
432
|
.map((s) => ({ id: s.id, key: s.key, label: s.label, authorized: s.authorized ?? false }));
|
|
@@ -441,8 +494,8 @@ export function createSecretsVaultRoutes(deps: SecretsVaultRoutesDeps): express.
|
|
|
441
494
|
|
|
442
495
|
// Set the confidential client secret for a tool's OAuth-backed variable — the
|
|
443
496
|
// ONLY place the secret is provided. Requires WRITE on the `.tool`. The provider
|
|
444
|
-
// config
|
|
445
|
-
//
|
|
497
|
+
// config of the variable's own `oauth` declaration is stored with the secret as
|
|
498
|
+
// a record of the save; a sign-in start reads the declaration afresh.
|
|
446
499
|
router.put('/secrets/tools/:slug/vars/:var/oauth/admin', async (req, res) => {
|
|
447
500
|
const userId = req.userId;
|
|
448
501
|
const email = req.userEmail;
|
|
@@ -456,38 +509,17 @@ export function createSecretsVaultRoutes(deps: SecretsVaultRoutesDeps): express.
|
|
|
456
509
|
if (!(await accessControl.canWrite(defaultWs(), email, found.manual.path))) {
|
|
457
510
|
return void res.status(403).json({ error: 'You need write access to this tool to set its client secret.' });
|
|
458
511
|
}
|
|
459
|
-
const { authorizationUrl, tokenUrl } = found.variable.oauth;
|
|
460
512
|
// A declaration that names only its client id is completed from the
|
|
461
|
-
// server's OAuth metadata
|
|
462
|
-
//
|
|
463
|
-
//
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
return void res.status(422).json({
|
|
467
|
-
error: why
|
|
468
|
-
? `The sign-in endpoints for this server aren't known yet: ${why}.`
|
|
469
|
-
: "The sign-in endpoints for this server aren't known yet — declare `authorizationUrl` and `tokenUrl` on the sign-in variable.",
|
|
470
|
-
});
|
|
471
|
-
}
|
|
513
|
+
// server's OAuth metadata. When that didn't happen, storing the secret
|
|
514
|
+
// with a provider that has no endpoints would leave every sign-in failing
|
|
515
|
+
// later with a far less specific error than the catalog's own.
|
|
516
|
+
const provider = declaredProvider(found.variable);
|
|
517
|
+
if (!provider) return void res.status(422).json({ error: endpointsUnknown(found.manual) });
|
|
472
518
|
const clientSecret = (req.body ?? {}).clientSecret;
|
|
473
519
|
await secretsVault.putSharedOAuthClientSecret({
|
|
474
520
|
key: varKey(found.manual.name, found.variable.name),
|
|
475
521
|
clientSecret,
|
|
476
|
-
provider
|
|
477
|
-
authorizationUrl,
|
|
478
|
-
tokenUrl,
|
|
479
|
-
clientId: found.variable.oauth.clientId,
|
|
480
|
-
scopes: found.variable.oauth.scopes,
|
|
481
|
-
// Static authorize params (e.g. Google's `access_type=offline`) so the
|
|
482
|
-
// provider returns a refresh token — stored with the secret so a later
|
|
483
|
-
// `.tool` edit can't redirect the flow.
|
|
484
|
-
authParams: found.variable.oauth.authParams,
|
|
485
|
-
// PKCE unless the declaration opted out; the resource indicator when
|
|
486
|
-
// the server (or the declaration) names one. Both pinned here for the
|
|
487
|
-
// same reason as the rest: the flow runs from the stored row.
|
|
488
|
-
pkce: found.variable.oauth.pkce !== false,
|
|
489
|
-
resource: found.variable.oauth.resource,
|
|
490
|
-
},
|
|
522
|
+
provider,
|
|
491
523
|
});
|
|
492
524
|
res.status(201).json({ ok: true });
|
|
493
525
|
} catch (err) {
|
|
@@ -505,12 +537,37 @@ export function createSecretsVaultRoutes(deps: SecretsVaultRoutesDeps): express.
|
|
|
505
537
|
const email = req.userEmail;
|
|
506
538
|
if (!userId || !email) return void res.status(401).json({ error: 'Not authenticated' });
|
|
507
539
|
try {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
540
|
+
// Two sources, one per kind of sign-in. A DECLARED one follows its tool
|
|
541
|
+
// file as it reads now — never the catalog's scan, which can be a refresh
|
|
542
|
+
// behind the file, and never the copy the client-secret save stored. A
|
|
543
|
+
// client the platform registered itself (oauth-auto) is described by no
|
|
544
|
+
// file: the catalog's discovery surfaced it, and its stored row is the
|
|
545
|
+
// only description of it there is.
|
|
546
|
+
const [live, catalog] = await Promise.all([
|
|
547
|
+
toolManualService.liveDeclaration(email, req.params.slug, req.params.var),
|
|
548
|
+
findManualVar(email, req.params.slug, req.params.var),
|
|
549
|
+
]);
|
|
550
|
+
// The file is there but its declaration is refused as it reads now (an
|
|
551
|
+
// http:// or private endpoint, say): the parser's reason is the answer,
|
|
552
|
+
// and neither a catalog still holding the earlier version nor the stored
|
|
553
|
+
// row stands in for it. Nothing is sent anywhere.
|
|
554
|
+
if (live?.refused) return void res.status(422).json({ error: live.refused });
|
|
555
|
+
const manual = live?.manual ?? catalog?.manual;
|
|
556
|
+
if (!manual || (!live?.variable && !catalog)) {
|
|
557
|
+
return void res.status(404).json({ error: 'Tool or variable not found' });
|
|
512
558
|
}
|
|
513
|
-
const key = varKey(
|
|
559
|
+
const key = varKey(manual.name, req.params.var);
|
|
560
|
+
const declared = live?.variable?.oauth ? live.variable : null;
|
|
561
|
+
const registered =
|
|
562
|
+
!declared && catalog?.manual.setup?.kind === 'oauth-auto' && catalog.variable.oauth ? catalog.variable : null;
|
|
563
|
+
const signIn = declared ?? registered;
|
|
564
|
+
// No sign-in in the file and none the platform registered: whatever the
|
|
565
|
+
// shared row still holds is not used.
|
|
566
|
+
if (!signIn?.oauth) {
|
|
567
|
+
throw new SecretOAuthError("This tool's owner hasn't finished setting this up");
|
|
568
|
+
}
|
|
569
|
+
const provider = declared ? declaredProvider(declared) : undefined;
|
|
570
|
+
if (provider === null) return void res.status(422).json({ error: endpointsUnknown(manual) });
|
|
514
571
|
// Provision the caller's oauth row (from the owner-set secret) FIRST — its id
|
|
515
572
|
// is what the un-authed callback keys on. Pass an empty state placeholder; we
|
|
516
573
|
// sign the real state below with the returned id and swap it into the URL, so
|
|
@@ -520,10 +577,10 @@ export function createSecretsVaultRoutes(deps: SecretsVaultRoutesDeps): express.
|
|
|
520
577
|
key,
|
|
521
578
|
redirectUri: redirectUriFor(deps.publicBackendUrl),
|
|
522
579
|
state: '',
|
|
523
|
-
// Request the permissions the tool file declares RIGHT NOW
|
|
524
|
-
//
|
|
525
|
-
|
|
526
|
-
|
|
580
|
+
// Request the permissions the tool file declares RIGHT NOW, so adding a
|
|
581
|
+
// scope takes effect on the next sign-in.
|
|
582
|
+
scopes: signIn.oauth.scopes,
|
|
583
|
+
provider,
|
|
527
584
|
});
|
|
528
585
|
// The return path is signed INTO the state (HMAC-SHA256) rather than kept
|
|
529
586
|
// in a query param or a cookie: the callback arrives un-authenticated from
|
|
@@ -637,7 +694,22 @@ export function createSecretsVaultPublicRoutes(deps: SecretsVaultRoutesDeps): ex
|
|
|
637
694
|
back(`authorized=${encodeURIComponent(state.i)}`, dest);
|
|
638
695
|
} catch (err) {
|
|
639
696
|
log.error('oauth callback failed:', { err });
|
|
640
|
-
|
|
697
|
+
// A provider's REFUSAL (the vault's error carrying the provider's HTTP
|
|
698
|
+
// status) names the provider's error code and Hexis's own sentence for
|
|
699
|
+
// it — the one thing the person on the Connect page (or the agent they
|
|
700
|
+
// paste it to) can act on: a client the provider does not accept, a
|
|
701
|
+
// refused authorization code. Nothing of the provider's text is in it.
|
|
702
|
+
// Every other failure stays the generic line: a transport error quotes
|
|
703
|
+
// what fetch said, which is not a provider's word.
|
|
704
|
+
const refusal = err instanceof SecretOAuthError && err.providerStatus !== undefined ? err.message : null;
|
|
705
|
+
back(
|
|
706
|
+
`error=${encodeURIComponent(
|
|
707
|
+
refusal
|
|
708
|
+
? `Authorization failed. ${refusal}`
|
|
709
|
+
: 'Authorization failed. Check the provider configuration and try again.',
|
|
710
|
+
)}`,
|
|
711
|
+
dest,
|
|
712
|
+
);
|
|
641
713
|
}
|
|
642
714
|
});
|
|
643
715
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { isStandardTokenErrorCode } from '../../shared/oauth-token-error.js';
|
|
2
3
|
|
|
3
4
|
/** The single sign-on configuration a deployment would sign people in with. */
|
|
4
5
|
export interface OidcConfiguration {
|
|
@@ -55,21 +56,6 @@ const REQUEST_TIMEOUT_MS = 10_000;
|
|
|
55
56
|
*/
|
|
56
57
|
const CODE_REJECTIONS: readonly string[] = ['invalid_grant'];
|
|
57
58
|
|
|
58
|
-
/**
|
|
59
|
-
* The other error codes RFC 6749 §5.2 (and OIDC Core §3.1.2.6) define — the
|
|
60
|
-
* only ones echoed back in an "unverified" message. Anything else in `error`
|
|
61
|
-
* is text of the provider's choosing, and could be the secret reflected back.
|
|
62
|
-
*/
|
|
63
|
-
const ECHOED_ERRORS: readonly string[] = [
|
|
64
|
-
'invalid_request',
|
|
65
|
-
'unauthorized_client',
|
|
66
|
-
'unsupported_grant_type',
|
|
67
|
-
'invalid_scope',
|
|
68
|
-
'access_denied',
|
|
69
|
-
'server_error',
|
|
70
|
-
'temporarily_unavailable',
|
|
71
|
-
];
|
|
72
|
-
|
|
73
59
|
/** The issuer as the provider appends `/.well-known/...` to it: no trailing slash. */
|
|
74
60
|
export function normalizeIssuerUrl(issuerUrl: string): string {
|
|
75
61
|
return issuerUrl.trim().replace(/\/+$/, '');
|
|
@@ -219,9 +205,10 @@ export async function checkOidcConfiguration(
|
|
|
219
205
|
};
|
|
220
206
|
}
|
|
221
207
|
if (CODE_REJECTIONS.includes(errorCode)) return { outcome: 'verified' };
|
|
222
|
-
// Only a standard error code is echoed
|
|
223
|
-
// provider's choosing,
|
|
224
|
-
|
|
208
|
+
// Only a standard error code is echoed (the one list the vault reads a
|
|
209
|
+
// refusal by too) — anything else could be text of the provider's choosing,
|
|
210
|
+
// the secret included.
|
|
211
|
+
const code = isStandardTokenErrorCode(errorCode) ? ` (${errorCode})` : ` (HTTP ${status})`;
|
|
225
212
|
return {
|
|
226
213
|
outcome: 'unverified',
|
|
227
214
|
error: `The application ID and secret could not be verified — the provider gave an answer that does not say whether they are right${code}.`,
|
|
@@ -280,6 +280,40 @@ describe('SkillService', () => {
|
|
|
280
280
|
expect(await svc(denyRfi).getSkill('user@x.eu', 'rfi')).toEqual({ ok: false, error: 'forbidden' });
|
|
281
281
|
});
|
|
282
282
|
|
|
283
|
+
/**
|
|
284
|
+
* A connection made as an `.agent` file narrows the skills (`within`) —
|
|
285
|
+
* AFTER the person's read gate, so it can take a skill away and never give
|
|
286
|
+
* one: a skill its lists name that the person may not read stays out.
|
|
287
|
+
*/
|
|
288
|
+
describe('narrowed to a connection’s skills', () => {
|
|
289
|
+
const denyGuidelines = {
|
|
290
|
+
canRead: async () => true,
|
|
291
|
+
canReadBatch: async (_w: string, _e: string, paths: string[]) =>
|
|
292
|
+
new Map(paths.map((p) => [p, !p.startsWith('Plugins/Development/')])),
|
|
293
|
+
} as unknown as IAccessControl;
|
|
294
|
+
const everyPluginSkill = (folder: string) => folder.startsWith('Plugins/');
|
|
295
|
+
|
|
296
|
+
test('lists only what is both readable and within, and loads nothing else', async () => {
|
|
297
|
+
const list = await svc(denyGuidelines).listSkills('user@x.eu', { within: everyPluginSkill });
|
|
298
|
+
expect(list.map((s) => s.name)).toEqual(['rfi']);
|
|
299
|
+
expect(await svc().listSkills('user@x.eu', { within: (p) => p === 'Plugins/Development/coding-guidelines' })).toEqual([
|
|
300
|
+
expect.objectContaining({ name: 'coding-guidelines' }),
|
|
301
|
+
]);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test('getSkill outside it is not there for the connection; inside it, the read gate still answers', async () => {
|
|
305
|
+
expect(await svc().getSkill('user@x.eu', 'rfi', undefined, { within: () => false })).toEqual({
|
|
306
|
+
ok: false,
|
|
307
|
+
error: 'not_found',
|
|
308
|
+
});
|
|
309
|
+
const inside = await svc().getSkill('user@x.eu', 'rfi', undefined, { within: everyPluginSkill });
|
|
310
|
+
expect(inside.ok).toBe(true);
|
|
311
|
+
expect(
|
|
312
|
+
await svc(denyGuidelines).getSkill('user@x.eu', 'coding-guidelines', undefined, { within: everyPluginSkill }),
|
|
313
|
+
).toEqual({ ok: false, error: 'forbidden' });
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
283
317
|
/**
|
|
284
318
|
* The listing and the loader must never disagree about the same skill at the
|
|
285
319
|
* same instant.
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// The services are types here: the composition root constructs them from
|
|
2
|
+
// their files, so a module that imports this entry for a helper or a type
|
|
3
|
+
// does not load the implementations.
|
|
4
|
+
export type { SkillService } from './skills.service.js';
|
|
5
|
+
export type { PendingSkillsService } from './pending-skills.service.js';
|
|
3
6
|
export { registerSkillsTools } from './skills.tools.js';
|
|
4
7
|
export { createSkillsRoutes } from './skills.routes.js';
|
|
5
8
|
export { AllowedToolsChecker } from './allowed-tools-check.js';
|
|
@@ -14,7 +17,9 @@ export type {
|
|
|
14
17
|
PendingSkill,
|
|
15
18
|
GetSkillResult,
|
|
16
19
|
GetSkillOptions,
|
|
20
|
+
ListSkillsOptions,
|
|
17
21
|
SkillHistorySource,
|
|
22
|
+
SkillScope,
|
|
18
23
|
} from './skills.contract.js';
|
|
19
24
|
// Reached by other modules; exported here so they stop importing the files.
|
|
20
25
|
export type { PluginMembership } from './skills.contract.js';
|
|
@@ -119,8 +119,19 @@ export interface ListSkillsOptions {
|
|
|
119
119
|
* carries `unmerged: true` and this branch name: nobody approved it.
|
|
120
120
|
*/
|
|
121
121
|
branch?: string;
|
|
122
|
+
/** Narrow the listing to a connection's skills — see {@link SkillScope}. */
|
|
123
|
+
within?: SkillScope;
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
/**
|
|
127
|
+
* A connection's narrowing of the skills: whether the skill in `skillFolder`
|
|
128
|
+
* (repo-relative) is one the connection loads. Applied AFTER the caller's read
|
|
129
|
+
* gate, so it can only take skills away. The agent surfaces pass the
|
|
130
|
+
* connection scope's `allowsSkill` (`modules/agent-scope`); absent is every
|
|
131
|
+
* skill the caller may read.
|
|
132
|
+
*/
|
|
133
|
+
export type SkillScope = (skillFolder: string) => boolean;
|
|
134
|
+
|
|
124
135
|
/** What `getSkill` may be asked beyond a name and a file. */
|
|
125
136
|
export interface GetSkillOptions {
|
|
126
137
|
/**
|
|
@@ -152,6 +163,12 @@ export interface GetSkillOptions {
|
|
|
152
163
|
* combination has exactly one sensible meaning.
|
|
153
164
|
*/
|
|
154
165
|
branch?: string;
|
|
166
|
+
/**
|
|
167
|
+
* Narrow to a connection's skills — see {@link SkillScope}. A skill outside
|
|
168
|
+
* it answers `not_found`, as a name nobody used does: to this connection it
|
|
169
|
+
* is not there.
|
|
170
|
+
*/
|
|
171
|
+
within?: SkillScope;
|
|
155
172
|
}
|
|
156
173
|
|
|
157
174
|
/**
|
|
@@ -108,7 +108,9 @@ export class SkillService implements ISkillService {
|
|
|
108
108
|
|
|
109
109
|
async listSkills(userEmail?: string, options: ListSkillsOptions = {}): Promise<SkillSummary[]> {
|
|
110
110
|
const { catalog, branch } = await this.catalogFor(options.branch);
|
|
111
|
-
const
|
|
111
|
+
const readable = userEmail ? await this.readableSkills(catalog, userEmail) : catalog.skills;
|
|
112
|
+
const within = options.within;
|
|
113
|
+
const visible = within ? readable.filter((s) => within(s.summary.path)) : readable;
|
|
112
114
|
if (branch === undefined) return visible.map((s) => s.summary);
|
|
113
115
|
// Marking reads both copies of a folder, so it happens only here, on a
|
|
114
116
|
// branch read that asked for it — the released catalog every other surface
|
|
@@ -135,6 +137,8 @@ export class SkillService implements ISkillService {
|
|
|
135
137
|
// A skill the branch deleted is not a skill as far as this answer goes:
|
|
136
138
|
// the same `not_found` a name nobody ever used gets.
|
|
137
139
|
if (!found) return { ok: false, error: 'not_found' };
|
|
140
|
+
// Outside the connection's skills: not there, for this connection.
|
|
141
|
+
if (options.within && !options.within(found.summary.path)) return { ok: false, error: 'not_found' };
|
|
138
142
|
|
|
139
143
|
// Through `readable`, not a bare `canRead`: the two gates must never
|
|
140
144
|
// disagree. `canRead` reads a file's own frontmatter rules off disk on
|
|
@@ -4,7 +4,7 @@ import type { IToolRegistry, JsonSchema, UtcpTool } from '../tool-registry/index
|
|
|
4
4
|
import { TOOL_DESCRIPTION_CAP, GUIDE_FIRST_SENTENCE } from '../tool-registry/index.js';
|
|
5
5
|
import { ToolError, type ToolContext, toolDef, bodyEnvelope, declareRouteTool, CAN_WRITE_CLAUSE, defaultBranchWriteVerdicts, type DefaultBranchWriteDeps } from '../tool-helpers/index.js';
|
|
6
6
|
import type { ToolHandlerFactory } from '../tool-helpers/index.js';
|
|
7
|
-
import type { ISkillService } from './skills.contract.js';
|
|
7
|
+
import type { ISkillService, SkillScope } from './skills.contract.js';
|
|
8
8
|
import { EXTERNAL_KB_MANUAL_NAME } from '../tool-manuals/index.js';
|
|
9
9
|
import type { IAllowedToolsChecker } from './allowed-tools-check.js';
|
|
10
10
|
|
|
@@ -33,7 +33,7 @@ const LIST_SKILLS_INPUTS = {
|
|
|
33
33
|
const GET_SKILL_INPUTS = {
|
|
34
34
|
type: 'object' as const,
|
|
35
35
|
properties: {
|
|
36
|
-
name: { type: 'string' as const, minLength: 1, description: 'Skill name (its folder name
|
|
36
|
+
name: { type: 'string' as const, minLength: 1, description: 'Skill name, as `list_skills` gives it (its `id`, else its `name`, else its folder name; e.g. `rfi`).' },
|
|
37
37
|
file: {
|
|
38
38
|
type: 'string' as const,
|
|
39
39
|
description:
|
|
@@ -130,9 +130,13 @@ export function registerSkillsTools(
|
|
|
130
130
|
return { paths: committed.includes(skillMdOf(loaded)) ? committed : [skillMdOf(loaded), ...loaded.files], at };
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
-
registry.registerExternalTool((ctx) =>
|
|
133
|
+
registry.registerExternalTool((ctx) =>
|
|
134
|
+
buildListSkillsDef(skillService, ctx.userEmail, ctx.connectionScope?.skillFilter()),
|
|
135
|
+
);
|
|
134
136
|
registry.registerInternalTool((ctx) => buildListSkillsDef(skillService, ctx.userEmail));
|
|
135
|
-
registry.registerExternalTool((ctx) =>
|
|
137
|
+
registry.registerExternalTool((ctx) =>
|
|
138
|
+
buildGetSkillDef(skillService, ctx.userEmail, ctx.connectionScope?.skillFilter()),
|
|
139
|
+
);
|
|
136
140
|
registry.registerInternalTool((ctx) => buildGetSkillDef(skillService, ctx.userEmail));
|
|
137
141
|
// Both defs are built per catalog listing (their descriptions name the skills
|
|
138
142
|
// THIS caller may read), so declare the arguments here as well: a direct REST
|
|
@@ -140,17 +144,24 @@ export function registerSkillsTools(
|
|
|
140
144
|
declareRouteTool('list_skills', LIST_SKILLS_INPUTS);
|
|
141
145
|
declareRouteTool('get_skill', GET_SKILL_INPUTS);
|
|
142
146
|
|
|
147
|
+
// Both skill routes are also how prompts are read (`discovery`): a
|
|
148
|
+
// connection made as an agent configuration that names skills has them as
|
|
149
|
+
// prompts even when its `platformTools` does not offer these two tools.
|
|
143
150
|
router.post(
|
|
144
151
|
'/agent/tools/list_skills',
|
|
145
152
|
toolAuth,
|
|
146
153
|
toolHandler(async (args, ctx: ToolContext) => {
|
|
147
|
-
const
|
|
154
|
+
const within = ctx.connectionScope?.skillFilter();
|
|
155
|
+
const skills = await skillService.listSkills(ctx.user.email, {
|
|
156
|
+
branch: branchArg(args),
|
|
157
|
+
...(within ? { within } : {}),
|
|
158
|
+
});
|
|
148
159
|
// Judged on each skill's SKILL.md, by the default branch's rules — a
|
|
149
160
|
// skill only on a draft is judged where it would land. Each verdict goes
|
|
150
161
|
// onto a COPY: the summaries may be the catalog shared across users.
|
|
151
162
|
const verdicts = await verdictsFor(ctx, skills.map(skillMdOf));
|
|
152
163
|
return { skills: skills.map((s) => ({ ...s, canWrite: verdicts.get(skillMdOf(s)) === true })) };
|
|
153
|
-
}),
|
|
164
|
+
}, { discovery: true }),
|
|
154
165
|
);
|
|
155
166
|
|
|
156
167
|
router.post(
|
|
@@ -174,7 +185,12 @@ export function registerSkillsTools(
|
|
|
174
185
|
400,
|
|
175
186
|
);
|
|
176
187
|
}
|
|
177
|
-
const
|
|
188
|
+
const within = ctx.connectionScope?.skillFilter();
|
|
189
|
+
const result = await skillService.getSkill(ctx.user.email, name, file, {
|
|
190
|
+
version,
|
|
191
|
+
branch,
|
|
192
|
+
...(within ? { within } : {}),
|
|
193
|
+
});
|
|
178
194
|
if (!result.ok) return result;
|
|
179
195
|
if (result.kind === 'file') {
|
|
180
196
|
const verdicts = await verdictsFor(ctx, [result.file.path]);
|
|
@@ -193,7 +209,7 @@ export function registerSkillsTools(
|
|
|
193
209
|
};
|
|
194
210
|
if (!allowedTools) return { ...result, skill };
|
|
195
211
|
return { ...result, skill, warnings: await allowedTools.check(ctx.user.email, result.skill.allowedTools) };
|
|
196
|
-
}),
|
|
212
|
+
}, { discovery: true }),
|
|
197
213
|
);
|
|
198
214
|
}
|
|
199
215
|
|
|
@@ -223,8 +239,13 @@ function branchArg(args: Record<string, unknown>): string | undefined {
|
|
|
223
239
|
* the tool's fixed text leaves under {@link TOOL_DESCRIPTION_CAP} once the
|
|
224
240
|
* guide-first sentence the registry puts in front is counted.
|
|
225
241
|
*/
|
|
226
|
-
async function availableSkillsLine(
|
|
227
|
-
|
|
242
|
+
async function availableSkillsLine(
|
|
243
|
+
skillService: ISkillService,
|
|
244
|
+
userEmail: string | undefined,
|
|
245
|
+
budget: number,
|
|
246
|
+
within?: SkillScope,
|
|
247
|
+
): Promise<string> {
|
|
248
|
+
const skills = await skillService.listSkills(userEmail, within ? { within } : {});
|
|
228
249
|
if (skills.length === 0) return 'No skills are currently available.';
|
|
229
250
|
const names = skills.map((s) => `\`${s.name}\``);
|
|
230
251
|
const rest = (shown: number): string =>
|
|
@@ -276,12 +297,17 @@ const LIST_SKILLS_DESCRIPTION =
|
|
|
276
297
|
'Each skill carries `canWrite`: whether you may change its SKILL.md directly on the default branch. ' +
|
|
277
298
|
`${CAN_WRITE_CLAUSE} `;
|
|
278
299
|
|
|
279
|
-
async function buildListSkillsDef(skillService: ISkillService, userEmail?: string): Promise<UtcpTool> {
|
|
300
|
+
async function buildListSkillsDef(skillService: ISkillService, userEmail?: string, within?: SkillScope): Promise<UtcpTool> {
|
|
280
301
|
return toolDef({
|
|
281
302
|
name: 'list_skills',
|
|
282
303
|
description:
|
|
283
304
|
LIST_SKILLS_DESCRIPTION +
|
|
284
|
-
(await availableSkillsLine(
|
|
305
|
+
(await availableSkillsLine(
|
|
306
|
+
skillService,
|
|
307
|
+
userEmail,
|
|
308
|
+
skillsLineBudget('list_skills', LIST_SKILLS_INPUTS, LIST_SKILLS_DESCRIPTION),
|
|
309
|
+
within,
|
|
310
|
+
)),
|
|
285
311
|
path: '/api/agent/tools/list_skills',
|
|
286
312
|
inputs: LIST_SKILLS_INPUTS,
|
|
287
313
|
outputs: {
|
|
@@ -334,12 +360,17 @@ const GET_SKILL_DESCRIPTION =
|
|
|
334
360
|
'The skill (or `file`) carries `canWrite`: whether you may change all of it directly on the default branch. ' +
|
|
335
361
|
`${CAN_WRITE_CLAUSE} `;
|
|
336
362
|
|
|
337
|
-
async function buildGetSkillDef(skillService: ISkillService, userEmail?: string): Promise<UtcpTool> {
|
|
363
|
+
async function buildGetSkillDef(skillService: ISkillService, userEmail?: string, within?: SkillScope): Promise<UtcpTool> {
|
|
338
364
|
return toolDef({
|
|
339
365
|
name: 'get_skill',
|
|
340
366
|
description:
|
|
341
367
|
GET_SKILL_DESCRIPTION +
|
|
342
|
-
(await availableSkillsLine(
|
|
368
|
+
(await availableSkillsLine(
|
|
369
|
+
skillService,
|
|
370
|
+
userEmail,
|
|
371
|
+
skillsLineBudget('get_skill', GET_SKILL_INPUTS, GET_SKILL_DESCRIPTION),
|
|
372
|
+
within,
|
|
373
|
+
)),
|
|
343
374
|
path: '/api/agent/tools/get_skill',
|
|
344
375
|
inputs: GET_SKILL_INPUTS,
|
|
345
376
|
outputs: {
|
|
@@ -150,6 +150,7 @@ describe('ExternalApiKeyService', () => {
|
|
|
150
150
|
revokedAt: null,
|
|
151
151
|
revokedBy: null,
|
|
152
152
|
deletedAt: null,
|
|
153
|
+
agentPath: null,
|
|
153
154
|
});
|
|
154
155
|
});
|
|
155
156
|
|
|
@@ -370,6 +371,7 @@ describe('ExternalApiKeyService', () => {
|
|
|
370
371
|
revokedAt: null,
|
|
371
372
|
revokedBy: null,
|
|
372
373
|
deletedAt: null,
|
|
374
|
+
agentPath: null,
|
|
373
375
|
});
|
|
374
376
|
expect(summaries[1].revokedAt).toBe(rows[1].revokedAt!.getTime());
|
|
375
377
|
// sanity-check that ordering was requested (we can't introspect the
|
|
@@ -401,6 +403,7 @@ describe('ExternalApiKeyService', () => {
|
|
|
401
403
|
revokedAt: null,
|
|
402
404
|
revokedBy: null,
|
|
403
405
|
deletedAt: null,
|
|
406
|
+
agentPath: null,
|
|
404
407
|
user: { id: 'u-alice', email: 'alice@example.com', name: 'Alice' },
|
|
405
408
|
},
|
|
406
409
|
{
|
|
@@ -412,6 +415,7 @@ describe('ExternalApiKeyService', () => {
|
|
|
412
415
|
revokedAt: bobKey.revokedAt!.getTime(),
|
|
413
416
|
revokedBy: null,
|
|
414
417
|
deletedAt: null,
|
|
418
|
+
agentPath: null,
|
|
415
419
|
user: { id: 'u-bob', email: 'bob@example.com', name: 'Bob' },
|
|
416
420
|
},
|
|
417
421
|
]);
|
|
@@ -43,6 +43,11 @@ export interface ExternalApiKeySummary {
|
|
|
43
43
|
* its row stays so the Audit log's events keep their principal.
|
|
44
44
|
*/
|
|
45
45
|
deletedAt: number | null;
|
|
46
|
+
/**
|
|
47
|
+
* The agent configuration the key connects as (a repo-relative knowledge-base
|
|
48
|
+
* path), or null for Everything — chosen when the key was minted.
|
|
49
|
+
*/
|
|
50
|
+
agentPath: string | null;
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
/** Who revoked a key: its owner, or an admin acting across the deployment. */
|
|
@@ -97,6 +102,11 @@ export interface KeyKindSpec {
|
|
|
97
102
|
*/
|
|
98
103
|
export interface MintOptions {
|
|
99
104
|
kind?: string;
|
|
105
|
+
/**
|
|
106
|
+
* The agent configuration the key connects as, already checked to be one the
|
|
107
|
+
* owner may choose (`IAgentScopeResolver.choosable`). Absent: Everything.
|
|
108
|
+
*/
|
|
109
|
+
agentPath?: string;
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
/**
|
|
@@ -138,7 +148,7 @@ export interface IExternalApiKeyService {
|
|
|
138
148
|
*/
|
|
139
149
|
verifyAndLoadToken(
|
|
140
150
|
plaintext: string,
|
|
141
|
-
): Promise<{ tokenId: string; user: AuthUser } | null>;
|
|
151
|
+
): Promise<{ tokenId: string; user: AuthUser; agentPath?: string | null } | null>;
|
|
142
152
|
|
|
143
153
|
/**
|
|
144
154
|
* For a key {@link verifyAndLoadToken} refused: whether it is a live key
|
|
@@ -89,7 +89,7 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
|
|
|
89
89
|
|
|
90
90
|
const [row] = await this.db
|
|
91
91
|
.insert(externalApiKeys)
|
|
92
|
-
.values({ userId, tokenHash, label: trimmed, kind })
|
|
92
|
+
.values({ userId, tokenHash, label: trimmed, kind, ...(options.agentPath ? { agentPath: options.agentPath } : {}) })
|
|
93
93
|
.returning();
|
|
94
94
|
|
|
95
95
|
return {
|
|
@@ -118,7 +118,7 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
|
|
|
118
118
|
|
|
119
119
|
async verifyAndLoadToken(
|
|
120
120
|
plaintext: string,
|
|
121
|
-
): Promise<{ tokenId: string; user: AuthUser } | null> {
|
|
121
|
+
): Promise<{ tokenId: string; user: AuthUser; agentPath: string | null } | null> {
|
|
122
122
|
if (!this.looksLikeExternalApiKey(plaintext)) {
|
|
123
123
|
return null;
|
|
124
124
|
}
|
|
@@ -135,6 +135,7 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
|
|
|
135
135
|
tokenId: externalApiKeys.id,
|
|
136
136
|
label: externalApiKeys.label,
|
|
137
137
|
lastUsedAt: externalApiKeys.lastUsedAt,
|
|
138
|
+
agentPath: externalApiKeys.agentPath,
|
|
138
139
|
userId: users.id,
|
|
139
140
|
email: users.email,
|
|
140
141
|
name: users.name,
|
|
@@ -176,6 +177,7 @@ export class ExternalApiKeyService implements IExternalApiKeyService {
|
|
|
176
177
|
|
|
177
178
|
return {
|
|
178
179
|
tokenId: row.tokenId,
|
|
180
|
+
agentPath: row.agentPath,
|
|
179
181
|
user: {
|
|
180
182
|
id: row.userId,
|
|
181
183
|
email: row.email,
|
|
@@ -353,5 +355,6 @@ function toSummary(row: typeof externalApiKeys.$inferSelect): ExternalApiKeySumm
|
|
|
353
355
|
revokedAt: row.revokedAt ? row.revokedAt.getTime() : null,
|
|
354
356
|
revokedBy: (row.revokedBy as RevokedBy | null) ?? null,
|
|
355
357
|
deletedAt: row.deletedAt ? row.deletedAt.getTime() : null,
|
|
358
|
+
agentPath: row.agentPath ?? null,
|
|
356
359
|
};
|
|
357
360
|
}
|
|
@@ -10,5 +10,5 @@ import './external-api-key.interface.js';
|
|
|
10
10
|
export type { InternalTokenService } from './internal-token.service.js';
|
|
11
11
|
export type { ILlmUsageMeter } from './llm-usage-meter.js';
|
|
12
12
|
export { createTokenVerifier, requireExternalSource, requireInternalSource } from './tool-auth.middleware.js';
|
|
13
|
-
export type { ToolAuth } from './tool-auth.middleware.js';
|
|
13
|
+
export type { ConnectionChoices, ToolAuth } from './tool-auth.middleware.js';
|
|
14
14
|
import './tool-auth.middleware.js';
|