@capybara-hq/kernel 0.0.0-stage → 0.1.0-rc.1
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/NOTICE +2 -0
- package/README.md +20 -2
- package/bootstrap.json +26 -0
- package/dist/admin/admin.controller.d.ts +139 -0
- package/dist/admin/admin.controller.js +238 -0
- package/dist/admin/extensions.controller.d.ts +100 -0
- package/dist/admin/extensions.controller.js +226 -0
- package/dist/admin/setup.controller.d.ts +36 -0
- package/dist/admin/setup.controller.js +106 -0
- package/dist/admin/setup.service.d.ts +47 -0
- package/dist/admin/setup.service.js +90 -0
- package/dist/agents/agents.controller.d.ts +205 -0
- package/dist/agents/agents.controller.js +144 -0
- package/dist/agents/agents.service.d.ts +177 -0
- package/dist/agents/agents.service.js +677 -0
- package/dist/agents/definition.d.ts +198 -0
- package/dist/agents/definition.js +152 -0
- package/dist/agents/models.controller.d.ts +13 -0
- package/dist/agents/models.controller.js +31 -0
- package/dist/agents/templates.controller.d.ts +15 -0
- package/dist/agents/templates.controller.js +37 -0
- package/dist/agents/templates.d.ts +83 -0
- package/dist/agents/templates.js +173 -0
- package/dist/catalog/admin-catalog.controller.d.ts +143 -0
- package/dist/catalog/admin-catalog.controller.js +245 -0
- package/dist/catalog/catalog.service.d.ts +430 -0
- package/dist/catalog/catalog.service.js +882 -0
- package/dist/catalog/claude/agents.d.ts +27 -0
- package/dist/catalog/claude/agents.js +270 -0
- package/dist/catalog/claude/commands.d.ts +50 -0
- package/dist/catalog/claude/commands.js +179 -0
- package/dist/catalog/claude/manifest.d.ts +69 -0
- package/dist/catalog/claude/manifest.js +134 -0
- package/dist/catalog/claude/marketplace.d.ts +35 -0
- package/dist/catalog/claude/marketplace.js +194 -0
- package/dist/catalog/claude/mcp.d.ts +33 -0
- package/dist/catalog/claude/mcp.js +226 -0
- package/dist/catalog/claude/report.d.ts +86 -0
- package/dist/catalog/claude/report.js +121 -0
- package/dist/catalog/claude/translate.d.ts +56 -0
- package/dist/catalog/claude/translate.js +857 -0
- package/dist/catalog/cli.d.ts +46 -0
- package/dist/catalog/cli.js +211 -0
- package/dist/catalog/git-source.d.ts +127 -0
- package/dist/catalog/git-source.js +520 -0
- package/dist/catalog/marketplace-fetch.d.ts +99 -0
- package/dist/catalog/marketplace-fetch.js +203 -0
- package/dist/catalog/marketplaces.controller.d.ts +97 -0
- package/dist/catalog/marketplaces.controller.js +197 -0
- package/dist/catalog/marketplaces.service.d.ts +340 -0
- package/dist/catalog/marketplaces.service.js +1217 -0
- package/dist/catalog/org-catalog.controller.d.ts +128 -0
- package/dist/catalog/org-catalog.controller.js +277 -0
- package/dist/catalog/org-catalog.service.d.ts +246 -0
- package/dist/catalog/org-catalog.service.js +625 -0
- package/dist/catalog/plugin-import.d.ts +436 -0
- package/dist/catalog/plugin-import.js +1069 -0
- package/dist/catalog/plugin-install.d.ts +447 -0
- package/dist/catalog/plugin-install.js +1333 -0
- package/dist/catalog/plugin-package.d.ts +143 -0
- package/dist/catalog/plugin-package.js +382 -0
- package/dist/catalog/plugin-upgrade.d.ts +222 -0
- package/dist/catalog/plugin-upgrade.js +1219 -0
- package/dist/catalog/requests.service.d.ts +162 -0
- package/dist/catalog/requests.service.js +504 -0
- package/dist/catalog/schema-path.d.ts +7 -0
- package/dist/catalog/schema-path.js +63 -0
- package/dist/catalog/upgrade-targets.d.ts +59 -0
- package/dist/catalog/upgrade-targets.js +90 -0
- package/dist/catalog/versions.d.ts +31 -0
- package/dist/catalog/versions.js +44 -0
- package/dist/channels/actions.d.ts +37 -0
- package/dist/channels/actions.js +121 -0
- package/dist/channels/cards.d.ts +44 -0
- package/dist/channels/cards.js +156 -0
- package/dist/channels/connections.controller.d.ts +59 -0
- package/dist/channels/connections.controller.js +115 -0
- package/dist/channels/connections.service.d.ts +187 -0
- package/dist/channels/connections.service.js +534 -0
- package/dist/channels/features.d.ts +12 -0
- package/dist/channels/features.js +22 -0
- package/dist/channels/inbound.d.ts +120 -0
- package/dist/channels/inbound.js +332 -0
- package/dist/channels/outbound.d.ts +140 -0
- package/dist/channels/outbound.js +1126 -0
- package/dist/channels/phrases.d.ts +100 -0
- package/dist/channels/phrases.js +81 -0
- package/dist/channels/supervisor.d.ts +182 -0
- package/dist/channels/supervisor.js +625 -0
- package/dist/channels/threads.d.ts +29 -0
- package/dist/channels/threads.js +104 -0
- package/dist/channels/webhook-url.d.ts +16 -0
- package/dist/channels/webhook-url.js +34 -0
- package/dist/channels/webhook.controller.d.ts +19 -0
- package/dist/channels/webhook.controller.js +72 -0
- package/dist/channels/webhook.d.ts +73 -0
- package/dist/channels/webhook.js +274 -0
- package/dist/config/docs.d.ts +9 -0
- package/dist/config/docs.js +85 -0
- package/dist/config/env.d.ts +6 -0
- package/dist/config/env.js +73 -0
- package/dist/config/fields.d.ts +42 -0
- package/dist/config/fields.js +214 -0
- package/dist/config/file-source.d.ts +3 -0
- package/dist/config/file-source.js +31 -0
- package/dist/config/load.d.ts +20 -0
- package/dist/config/load.js +98 -0
- package/dist/config/nacos-source.d.ts +31 -0
- package/dist/config/nacos-source.js +229 -0
- package/dist/config/schema.d.ts +237 -0
- package/dist/config/schema.js +1192 -0
- package/dist/config/sources.d.ts +18 -0
- package/dist/config/sources.js +59 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.js +7 -0
- package/dist/conversations/artifacts.d.ts +52 -0
- package/dist/conversations/artifacts.js +137 -0
- package/dist/conversations/attachments.controller.d.ts +28 -0
- package/dist/conversations/attachments.controller.js +96 -0
- package/dist/conversations/attachments.service.d.ts +180 -0
- package/dist/conversations/attachments.service.js +578 -0
- package/dist/conversations/conversations.controller.d.ts +288 -0
- package/dist/conversations/conversations.controller.js +607 -0
- package/dist/conversations/conversations.service.d.ts +321 -0
- package/dist/conversations/conversations.service.js +754 -0
- package/dist/conversations/event-log.d.ts +122 -0
- package/dist/conversations/event-log.js +259 -0
- package/dist/conversations/events.d.ts +856 -0
- package/dist/conversations/events.js +639 -0
- package/dist/conversations/files.d.ts +92 -0
- package/dist/conversations/files.js +213 -0
- package/dist/conversations/outputs-read.d.ts +34 -0
- package/dist/conversations/outputs-read.js +37 -0
- package/dist/conversations/queue.d.ts +169 -0
- package/dist/conversations/queue.js +527 -0
- package/dist/conversations/sandbox-status.d.ts +21 -0
- package/dist/conversations/sandbox-status.js +24 -0
- package/dist/conversations/selection.d.ts +46 -0
- package/dist/conversations/selection.js +75 -0
- package/dist/conversations/titles.d.ts +93 -0
- package/dist/conversations/titles.js +423 -0
- package/dist/ctx/bus.d.ts +16 -0
- package/dist/ctx/bus.js +101 -0
- package/dist/ctx/create-ctx.d.ts +109 -0
- package/dist/ctx/create-ctx.js +592 -0
- package/dist/ctx/kv.d.ts +4 -0
- package/dist/ctx/kv.js +31 -0
- package/dist/ctx/lock.d.ts +4 -0
- package/dist/ctx/lock.js +39 -0
- package/dist/ctx/namespace.d.ts +6 -0
- package/dist/ctx/namespace.js +12 -0
- package/dist/ctx/queue.d.ts +25 -0
- package/dist/ctx/queue.js +151 -0
- package/dist/ctx/secrets.d.ts +45 -0
- package/dist/ctx/secrets.js +175 -0
- package/dist/db/kernel-schema.d.ts +1122 -0
- package/dist/db/kernel-schema.js +5 -0
- package/dist/db/migrator.d.ts +28 -0
- package/dist/db/migrator.js +140 -0
- package/dist/db/pool.d.ts +21 -0
- package/dist/db/pool.js +28 -0
- package/dist/db/sql-statements.d.ts +34 -0
- package/dist/db/sql-statements.js +168 -0
- package/dist/errors.d.ts +211 -0
- package/dist/errors.js +213 -0
- package/dist/evals/budget.d.ts +61 -0
- package/dist/evals/budget.js +181 -0
- package/dist/evals/diff.d.ts +55 -0
- package/dist/evals/diff.js +133 -0
- package/dist/evals/judge.d.ts +53 -0
- package/dist/evals/judge.js +149 -0
- package/dist/evals/plan.d.ts +47 -0
- package/dist/evals/plan.js +77 -0
- package/dist/evals/reconstruct.d.ts +137 -0
- package/dist/evals/reconstruct.js +322 -0
- package/dist/evals/recorded-tools.d.ts +54 -0
- package/dist/evals/recorded-tools.js +167 -0
- package/dist/evals/run-replay.d.ts +86 -0
- package/dist/evals/run-replay.js +502 -0
- package/dist/evals/runs.controller.d.ts +100 -0
- package/dist/evals/runs.controller.js +199 -0
- package/dist/evals/runs.service.d.ts +275 -0
- package/dist/evals/runs.service.js +836 -0
- package/dist/evals/sets.controller.d.ts +61 -0
- package/dist/evals/sets.controller.js +183 -0
- package/dist/evals/sets.service.d.ts +128 -0
- package/dist/evals/sets.service.js +558 -0
- package/dist/evals/snapshot.d.ts +76 -0
- package/dist/evals/snapshot.js +207 -0
- package/dist/evals/step-replay.d.ts +113 -0
- package/dist/evals/step-replay.js +181 -0
- package/dist/evals/trajectory.controller.d.ts +41 -0
- package/dist/evals/trajectory.controller.js +88 -0
- package/dist/evals/trajectory.d.ts +144 -0
- package/dist/evals/trajectory.js +338 -0
- package/dist/evals/trajectory.service.d.ts +108 -0
- package/dist/evals/trajectory.service.js +323 -0
- package/dist/evals/worker.d.ts +101 -0
- package/dist/evals/worker.js +790 -0
- package/dist/extensions/admin-ops.d.ts +105 -0
- package/dist/extensions/admin-ops.js +353 -0
- package/dist/extensions/admin-view.d.ts +79 -0
- package/dist/extensions/admin-view.js +327 -0
- package/dist/extensions/approvals.d.ts +119 -0
- package/dist/extensions/approvals.js +205 -0
- package/dist/extensions/blobs.d.ts +45 -0
- package/dist/extensions/blobs.js +160 -0
- package/dist/extensions/bootstrap.d.ts +176 -0
- package/dist/extensions/bootstrap.js +535 -0
- package/dist/extensions/cli.d.ts +61 -0
- package/dist/extensions/cli.js +165 -0
- package/dist/extensions/config-json-schema.d.ts +9 -0
- package/dist/extensions/config-json-schema.js +73 -0
- package/dist/extensions/deployment-config.d.ts +138 -0
- package/dist/extensions/deployment-config.js +394 -0
- package/dist/extensions/enabled.d.ts +31 -0
- package/dist/extensions/enabled.js +55 -0
- package/dist/extensions/hooks.d.ts +161 -0
- package/dist/extensions/hooks.js +425 -0
- package/dist/extensions/host.d.ts +577 -0
- package/dist/extensions/host.js +2071 -0
- package/dist/extensions/inflight.d.ts +69 -0
- package/dist/extensions/inflight.js +277 -0
- package/dist/extensions/installs.d.ts +166 -0
- package/dist/extensions/installs.js +253 -0
- package/dist/extensions/instance.d.ts +167 -0
- package/dist/extensions/instance.js +329 -0
- package/dist/extensions/ledger.d.ts +30 -0
- package/dist/extensions/ledger.js +50 -0
- package/dist/extensions/lifecycle.d.ts +80 -0
- package/dist/extensions/lifecycle.js +152 -0
- package/dist/extensions/migrate-lock.d.ts +51 -0
- package/dist/extensions/migrate-lock.js +100 -0
- package/dist/extensions/org-config.controller.d.ts +24 -0
- package/dist/extensions/org-config.controller.js +59 -0
- package/dist/extensions/org-config.d.ts +169 -0
- package/dist/extensions/org-config.js +520 -0
- package/dist/extensions/package.d.ts +115 -0
- package/dist/extensions/package.js +246 -0
- package/dist/extensions/permission-set.d.ts +117 -0
- package/dist/extensions/permission-set.js +184 -0
- package/dist/extensions/permission-view.d.ts +194 -0
- package/dist/extensions/permission-view.js +284 -0
- package/dist/extensions/registry.d.ts +24 -0
- package/dist/extensions/registry.js +56 -0
- package/dist/extensions/resolve.d.ts +12 -0
- package/dist/extensions/resolve.js +71 -0
- package/dist/extensions/sources.d.ts +69 -0
- package/dist/extensions/sources.js +120 -0
- package/dist/extensions/sync.d.ts +40 -0
- package/dist/extensions/sync.js +242 -0
- package/dist/files/previewers.controller.d.ts +46 -0
- package/dist/files/previewers.controller.js +105 -0
- package/dist/files/previewers.d.ts +100 -0
- package/dist/files/previewers.js +250 -0
- package/dist/http/api.module.d.ts +114 -0
- package/dist/http/api.module.js +448 -0
- package/dist/http/app.d.ts +77 -0
- package/dist/http/app.js +220 -0
- package/dist/http/error.filter.d.ts +21 -0
- package/dist/http/error.filter.js +85 -0
- package/dist/http/gateway.module.d.ts +15 -0
- package/dist/http/gateway.module.js +13 -0
- package/dist/http/health.controller.d.ts +26 -0
- package/dist/http/health.controller.js +79 -0
- package/dist/http/nest-logger.d.ts +20 -0
- package/dist/http/nest-logger.js +28 -0
- package/dist/http/plugin-dispatch.d.ts +68 -0
- package/dist/http/plugin-dispatch.js +200 -0
- package/dist/http/tokens.d.ts +131 -0
- package/dist/http/tokens.js +131 -0
- package/dist/http/zod.pipe.d.ts +8 -0
- package/dist/http/zod.pipe.js +14 -0
- package/dist/identity/accounts.d.ts +93 -0
- package/dist/identity/accounts.js +367 -0
- package/dist/identity/api-tokens.d.ts +73 -0
- package/dist/identity/api-tokens.js +197 -0
- package/dist/identity/audit.d.ts +23 -0
- package/dist/identity/audit.js +41 -0
- package/dist/identity/auth.controller.d.ts +40 -0
- package/dist/identity/auth.controller.js +130 -0
- package/dist/identity/auth.guard.d.ts +41 -0
- package/dist/identity/auth.guard.js +162 -0
- package/dist/identity/binding.d.ts +47 -0
- package/dist/identity/binding.js +84 -0
- package/dist/identity/cookies.d.ts +16 -0
- package/dist/identity/cookies.js +32 -0
- package/dist/identity/credential-check.d.ts +17 -0
- package/dist/identity/credential-check.js +24 -0
- package/dist/identity/enterprise-admin.d.ts +14 -0
- package/dist/identity/enterprise-admin.js +27 -0
- package/dist/identity/external.d.ts +106 -0
- package/dist/identity/external.js +337 -0
- package/dist/identity/hash.d.ts +2 -0
- package/dist/identity/hash.js +3 -0
- package/dist/identity/login.d.ts +6 -0
- package/dist/identity/login.js +20 -0
- package/dist/identity/me.controller.d.ts +61 -0
- package/dist/identity/me.controller.js +159 -0
- package/dist/identity/passwords.d.ts +6 -0
- package/dist/identity/passwords.js +37 -0
- package/dist/identity/principal.d.ts +56 -0
- package/dist/identity/principal.js +38 -0
- package/dist/identity/rate-limit.d.ts +55 -0
- package/dist/identity/rate-limit.js +121 -0
- package/dist/identity/sessions.d.ts +84 -0
- package/dist/identity/sessions.js +306 -0
- package/dist/identity/settings.d.ts +121 -0
- package/dist/identity/settings.js +248 -0
- package/dist/identity/sso.controller.d.ts +59 -0
- package/dist/identity/sso.controller.js +192 -0
- package/dist/identity/sso.d.ts +83 -0
- package/dist/identity/sso.js +202 -0
- package/dist/inbox/inbox.service.d.ts +43 -0
- package/dist/inbox/inbox.service.js +57 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.js +67 -0
- package/dist/kernel.d.ts +259 -0
- package/dist/kernel.js +1326 -0
- package/dist/log-config.d.ts +9 -0
- package/dist/log-config.js +27 -0
- package/dist/log-context.d.ts +32 -0
- package/dist/log-context.js +40 -0
- package/dist/log-loki.d.ts +34 -0
- package/dist/log-loki.js +145 -0
- package/dist/log.d.ts +79 -0
- package/dist/log.js +303 -0
- package/dist/models/prices.d.ts +53 -0
- package/dist/models/prices.js +121 -0
- package/dist/models/purposes.controller.d.ts +19 -0
- package/dist/models/purposes.controller.js +56 -0
- package/dist/models/purposes.d.ts +140 -0
- package/dist/models/purposes.js +267 -0
- package/dist/net/proxy.d.ts +44 -0
- package/dist/net/proxy.js +162 -0
- package/dist/net/public-address.d.ts +60 -0
- package/dist/net/public-address.js +272 -0
- package/dist/net/safe-fetch.d.ts +38 -0
- package/dist/net/safe-fetch.js +140 -0
- package/dist/orgs/directory-sync.controller.d.ts +14 -0
- package/dist/orgs/directory-sync.controller.js +40 -0
- package/dist/orgs/directory-sync.d.ts +166 -0
- package/dist/orgs/directory-sync.js +558 -0
- package/dist/orgs/invitations.controller.d.ts +58 -0
- package/dist/orgs/invitations.controller.js +137 -0
- package/dist/orgs/invitations.service.d.ts +80 -0
- package/dist/orgs/invitations.service.js +217 -0
- package/dist/orgs/members.service.d.ts +63 -0
- package/dist/orgs/members.service.js +234 -0
- package/dist/orgs/offboarding.d.ts +141 -0
- package/dist/orgs/offboarding.js +398 -0
- package/dist/orgs/org-lock.d.ts +32 -0
- package/dist/orgs/org-lock.js +46 -0
- package/dist/orgs/org.guard.d.ts +35 -0
- package/dist/orgs/org.guard.js +95 -0
- package/dist/orgs/orgs.controller.d.ts +78 -0
- package/dist/orgs/orgs.controller.js +192 -0
- package/dist/orgs/orgs.service.d.ts +61 -0
- package/dist/orgs/orgs.service.js +209 -0
- package/dist/orgs/roles.d.ts +13 -0
- package/dist/orgs/roles.js +58 -0
- package/dist/orgs/settings.controller.d.ts +20 -0
- package/dist/orgs/settings.controller.js +53 -0
- package/dist/orgs/settings.service.d.ts +120 -0
- package/dist/orgs/settings.service.js +178 -0
- package/dist/packages/npm.d.ts +50 -0
- package/dist/packages/npm.js +218 -0
- package/dist/packages/provenance.d.ts +47 -0
- package/dist/packages/provenance.js +147 -0
- package/dist/packages/tgz.d.ts +76 -0
- package/dist/packages/tgz.js +225 -0
- package/dist/runtime/abort.d.ts +32 -0
- package/dist/runtime/abort.js +71 -0
- package/dist/runtime/checkpointer.d.ts +32 -0
- package/dist/runtime/checkpointer.js +243 -0
- package/dist/runtime/context/build.d.ts +254 -0
- package/dist/runtime/context/build.js +693 -0
- package/dist/runtime/context/claude-tools.d.ts +11 -0
- package/dist/runtime/context/claude-tools.js +24 -0
- package/dist/runtime/context/compaction.d.ts +26 -0
- package/dist/runtime/context/compaction.js +195 -0
- package/dist/runtime/context/pairing.d.ts +11 -0
- package/dist/runtime/context/pairing.js +82 -0
- package/dist/runtime/context/reminders.d.ts +5 -0
- package/dist/runtime/context/reminders.js +11 -0
- package/dist/runtime/context/skills.d.ts +105 -0
- package/dist/runtime/context/skills.js +283 -0
- package/dist/runtime/context/tokens.d.ts +19 -0
- package/dist/runtime/context/tokens.js +104 -0
- package/dist/runtime/conversation-lock.d.ts +40 -0
- package/dist/runtime/conversation-lock.js +97 -0
- package/dist/runtime/hook-calls.d.ts +84 -0
- package/dist/runtime/hook-calls.js +136 -0
- package/dist/runtime/langgraph-loop.d.ts +52 -0
- package/dist/runtime/langgraph-loop.js +247 -0
- package/dist/runtime/loop.d.ts +93 -0
- package/dist/runtime/loop.js +7 -0
- package/dist/runtime/maintenance.d.ts +80 -0
- package/dist/runtime/maintenance.js +148 -0
- package/dist/runtime/media-cache.d.ts +21 -0
- package/dist/runtime/media-cache.js +51 -0
- package/dist/runtime/model-call.d.ts +176 -0
- package/dist/runtime/model-call.js +1049 -0
- package/dist/runtime/providers.d.ts +86 -0
- package/dist/runtime/providers.js +224 -0
- package/dist/runtime/quota.d.ts +29 -0
- package/dist/runtime/quota.js +70 -0
- package/dist/runtime/run-finish.d.ts +45 -0
- package/dist/runtime/run-finish.js +69 -0
- package/dist/runtime/run-queue.d.ts +121 -0
- package/dist/runtime/run-queue.js +493 -0
- package/dist/runtime/run-worker.d.ts +138 -0
- package/dist/runtime/run-worker.js +806 -0
- package/dist/runtime/stream.controller.d.ts +34 -0
- package/dist/runtime/stream.controller.js +122 -0
- package/dist/runtime/stream.d.ts +63 -0
- package/dist/runtime/stream.js +262 -0
- package/dist/runtime/subagents/child.d.ts +80 -0
- package/dist/runtime/subagents/child.js +225 -0
- package/dist/runtime/subagents/definition.d.ts +103 -0
- package/dist/runtime/subagents/definition.js +392 -0
- package/dist/runtime/subagents/dispatch.d.ts +69 -0
- package/dist/runtime/subagents/dispatch.js +502 -0
- package/dist/runtime/subagents/limits.d.ts +23 -0
- package/dist/runtime/subagents/limits.js +34 -0
- package/dist/runtime/subagents/org-agents.d.ts +50 -0
- package/dist/runtime/subagents/org-agents.js +70 -0
- package/dist/runtime/subagents/preamble.d.ts +7 -0
- package/dist/runtime/subagents/preamble.js +11 -0
- package/dist/runtime/subagents/progress.d.ts +26 -0
- package/dist/runtime/subagents/progress.js +36 -0
- package/dist/runtime/subagents/roster.d.ts +55 -0
- package/dist/runtime/subagents/roster.js +111 -0
- package/dist/runtime/subagents/skill-fork.d.ts +123 -0
- package/dist/runtime/subagents/skill-fork.js +259 -0
- package/dist/runtime/usage-report.d.ts +163 -0
- package/dist/runtime/usage-report.js +551 -0
- package/dist/runtime/waits.d.ts +233 -0
- package/dist/runtime/waits.js +883 -0
- package/dist/sandbox/leases.d.ts +169 -0
- package/dist/sandbox/leases.js +515 -0
- package/dist/sandbox/lifecycle.d.ts +21 -0
- package/dist/sandbox/lifecycle.js +68 -0
- package/dist/sandbox/sandbox.service.d.ts +249 -0
- package/dist/sandbox/sandbox.service.js +908 -0
- package/dist/skills/catalog.d.ts +149 -0
- package/dist/skills/catalog.js +405 -0
- package/dist/skills/changes.controller.d.ts +56 -0
- package/dist/skills/changes.controller.js +136 -0
- package/dist/skills/changes.service.d.ts +175 -0
- package/dist/skills/changes.service.js +805 -0
- package/dist/skills/invocable.controller.d.ts +23 -0
- package/dist/skills/invocable.controller.js +50 -0
- package/dist/skills/invocation-keys.d.ts +23 -0
- package/dist/skills/invocation-keys.js +44 -0
- package/dist/skills/invoke.d.ts +135 -0
- package/dist/skills/invoke.js +286 -0
- package/dist/skills/package.d.ts +87 -0
- package/dist/skills/package.js +227 -0
- package/dist/skills/skills.controller.d.ts +40 -0
- package/dist/skills/skills.controller.js +110 -0
- package/dist/skills/skills.service.d.ts +192 -0
- package/dist/skills/skills.service.js +567 -0
- package/dist/storage/prefix.d.ts +36 -0
- package/dist/storage/prefix.js +104 -0
- package/dist/storage/purge.d.ts +27 -0
- package/dist/storage/purge.js +75 -0
- package/dist/storage/storage.service.d.ts +44 -0
- package/dist/storage/storage.service.js +145 -0
- package/dist/text.d.ts +13 -0
- package/dist/text.js +13 -0
- package/dist/tools/approvals.controller.d.ts +53 -0
- package/dist/tools/approvals.controller.js +128 -0
- package/dist/tools/approvals.service.d.ts +172 -0
- package/dist/tools/approvals.service.js +568 -0
- package/dist/tools/breaker.d.ts +28 -0
- package/dist/tools/breaker.js +72 -0
- package/dist/tools/builtins/agent.d.ts +81 -0
- package/dist/tools/builtins/agent.js +223 -0
- package/dist/tools/builtins/ask-user.d.ts +28 -0
- package/dist/tools/builtins/ask-user.js +139 -0
- package/dist/tools/builtins/read-tool-output.d.ts +18 -0
- package/dist/tools/builtins/read-tool-output.js +108 -0
- package/dist/tools/builtins/sandbox/bash.d.ts +16 -0
- package/dist/tools/builtins/sandbox/bash.js +137 -0
- package/dist/tools/builtins/sandbox/common.d.ts +116 -0
- package/dist/tools/builtins/sandbox/common.js +306 -0
- package/dist/tools/builtins/sandbox/deliver.d.ts +5 -0
- package/dist/tools/builtins/sandbox/deliver.js +180 -0
- package/dist/tools/builtins/sandbox/edit.d.ts +4 -0
- package/dist/tools/builtins/sandbox/edit.js +98 -0
- package/dist/tools/builtins/sandbox/glob-match.d.ts +25 -0
- package/dist/tools/builtins/sandbox/glob-match.js +240 -0
- package/dist/tools/builtins/sandbox/glob.d.ts +4 -0
- package/dist/tools/builtins/sandbox/glob.js +104 -0
- package/dist/tools/builtins/sandbox/grep.d.ts +9 -0
- package/dist/tools/builtins/sandbox/grep.js +133 -0
- package/dist/tools/builtins/sandbox/index.d.ts +12 -0
- package/dist/tools/builtins/sandbox/index.js +27 -0
- package/dist/tools/builtins/sandbox/names.d.ts +7 -0
- package/dist/tools/builtins/sandbox/names.js +20 -0
- package/dist/tools/builtins/sandbox/read.d.ts +8 -0
- package/dist/tools/builtins/sandbox/read.js +121 -0
- package/dist/tools/builtins/sandbox/write.d.ts +4 -0
- package/dist/tools/builtins/sandbox/write.js +88 -0
- package/dist/tools/builtins/skill-load.d.ts +53 -0
- package/dist/tools/builtins/skill-load.js +446 -0
- package/dist/tools/builtins/skill-write.d.ts +59 -0
- package/dist/tools/builtins/skill-write.js +244 -0
- package/dist/tools/builtins/tool-search.d.ts +31 -0
- package/dist/tools/builtins/tool-search.js +171 -0
- package/dist/tools/connector-content.controller.d.ts +34 -0
- package/dist/tools/connector-content.controller.js +78 -0
- package/dist/tools/connector-content.d.ts +104 -0
- package/dist/tools/connector-content.js +267 -0
- package/dist/tools/connectors.controller.d.ts +210 -0
- package/dist/tools/connectors.controller.js +234 -0
- package/dist/tools/connectors.service.d.ts +303 -0
- package/dist/tools/connectors.service.js +1102 -0
- package/dist/tools/credentials.d.ts +139 -0
- package/dist/tools/credentials.js +351 -0
- package/dist/tools/drift.d.ts +141 -0
- package/dist/tools/drift.js +539 -0
- package/dist/tools/elicitation.d.ts +81 -0
- package/dist/tools/elicitation.js +266 -0
- package/dist/tools/endpoint.d.ts +18 -0
- package/dist/tools/endpoint.js +115 -0
- package/dist/tools/info.d.ts +67 -0
- package/dist/tools/info.js +113 -0
- package/dist/tools/naming.d.ts +27 -0
- package/dist/tools/naming.js +47 -0
- package/dist/tools/oauth/discovery.d.ts +65 -0
- package/dist/tools/oauth/discovery.js +307 -0
- package/dist/tools/oauth/flow.d.ts +63 -0
- package/dist/tools/oauth/flow.js +237 -0
- package/dist/tools/oauth/oauth.controller.d.ts +31 -0
- package/dist/tools/oauth/oauth.controller.js +95 -0
- package/dist/tools/oauth/tokens.d.ts +111 -0
- package/dist/tools/oauth/tokens.js +258 -0
- package/dist/tools/outputs.d.ts +61 -0
- package/dist/tools/outputs.js +156 -0
- package/dist/tools/pipeline.d.ts +322 -0
- package/dist/tools/pipeline.js +1236 -0
- package/dist/tools/policy.d.ts +60 -0
- package/dist/tools/policy.js +236 -0
- package/dist/tools/questions.controller.d.ts +24 -0
- package/dist/tools/questions.controller.js +58 -0
- package/dist/tools/questions.service.d.ts +103 -0
- package/dist/tools/questions.service.js +295 -0
- package/dist/tools/redact.d.ts +20 -0
- package/dist/tools/redact.js +60 -0
- package/dist/tools/registry.d.ts +246 -0
- package/dist/tools/registry.js +481 -0
- package/dist/tools/resources.d.ts +16 -0
- package/dist/tools/resources.js +76 -0
- package/dist/tools/specs.d.ts +14 -0
- package/dist/tools/specs.js +31 -0
- package/dist/tools/validate.d.ts +20 -0
- package/dist/tools/validate.js +183 -0
- package/dist/tools/view.d.ts +43 -0
- package/dist/tools/view.js +225 -0
- package/dist/ui/embed-token.d.ts +31 -0
- package/dist/ui/embed-token.js +132 -0
- package/dist/ui/registry.d.ts +58 -0
- package/dist/ui/registry.js +90 -0
- package/dist/ui/ui-stream.d.ts +37 -0
- package/dist/ui/ui-stream.js +162 -0
- package/dist/ui/views.controller.d.ts +81 -0
- package/dist/ui/views.controller.js +261 -0
- package/dist/ui/views.d.ts +155 -0
- package/dist/ui/views.js +306 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +6 -0
- package/package.json +69 -3
- package/src/migrations/0001_init.sql +8 -0
- package/src/migrations/0002_secrets.sql +8 -0
- package/src/migrations/0003_identity.sql +117 -0
- package/src/migrations/0004_plugin_org_config_nullable.sql +3 -0
- package/src/migrations/0005_agents.sql +27 -0
- package/src/migrations/0006_conversations.sql +37 -0
- package/src/migrations/0007_checkpoints.sql +26 -0
- package/src/migrations/0008_runs_trigger_seq.sql +3 -0
- package/src/migrations/0009_runs_active_unique.sql +4 -0
- package/src/migrations/0010_tools.sql +125 -0
- package/src/migrations/0011_approvals_spec.sql +10 -0
- package/src/migrations/0012_run_waits.sql +24 -0
- package/src/migrations/0013_app_tools_source.sql +4 -0
- package/src/migrations/0014_tool_specs.sql +8 -0
- package/src/migrations/0015_tool_drift.sql +20 -0
- package/src/migrations/0016_plugin_permissions.sql +11 -0
- package/src/migrations/0017_identity_sources.sql +6 -0
- package/src/migrations/0018_channels.sql +74 -0
- package/src/migrations/0019_identity_trust.sql +17 -0
- package/src/migrations/0020_channel_card_lookup.sql +10 -0
- package/src/migrations/0021_org_storage_purge.sql +9 -0
- package/src/migrations/0022_attachments.sql +29 -0
- package/src/migrations/0023_sandboxes.sql +37 -0
- package/src/migrations/0024_skills.sql +46 -0
- package/src/migrations/0025_skills_catalog_idx.sql +6 -0
- package/src/migrations/0026_skill_changes.sql +34 -0
- package/src/migrations/0027_model_prices.sql +18 -0
- package/src/migrations/0028_evals.sql +105 -0
- package/src/migrations/0029_model_purposes.sql +18 -0
- package/src/migrations/0030_plugin_installs.sql +73 -0
- package/src/migrations/0031_plugin_snapshot_source.sql +6 -0
- package/src/migrations/0032_plugin_deployment_configs.sql +10 -0
- package/src/migrations/0033_rename_apps_to_connectors.sql +25 -0
- package/src/migrations/0034_directory.sql +49 -0
- package/src/migrations/0035_catalogs.sql +40 -0
- package/src/migrations/0036_app_import_staging.sql +17 -0
- package/src/migrations/0037_directory_installs.sql +92 -0
- package/src/migrations/0038_channel_inbound_mode.sql +6 -0
- package/src/migrations/0039_channel_card_pending.sql +8 -0
- package/src/migrations/0040_usage_report_sweep.sql +10 -0
- package/src/migrations/0041_rename_plugins_to_extensions.sql +38 -0
- package/src/migrations/0042_rename_directory_to_catalog.sql +80 -0
- package/src/migrations/0043_rename_app_installs_to_plugin_installs.sql +20 -0
- package/src/migrations/0044_catalog_one_kind.sql +90 -0
- package/src/migrations/0045_plugin_dependencies.sql +9 -0
- package/src/migrations/0046_git_sources.sql +25 -0
- package/src/migrations/0047_marketplace_entry_heads.sql +7 -0
- package/src/migrations/0048_marketplace_entry_trees.sql +8 -0
- package/src/migrations/0049_plugin_upgrades.sql +37 -0
- package/src/migrations/0050_bootstrap.sql +53 -0
- package/src/migrations/0051_claude_compat.sql +26 -0
- package/src/migrations/0052_conversations_account_agent_idx.sql +5 -0
- package/src/migrations/0053_subagents.sql +73 -0
- package/src/migrations/0054_subagent_wait_expiry.sql +7 -0
- package/src/migrations/0055_subagent_parent_indexes.sql +10 -0
- package/src/migrations/0056_approval_reason.sql +3 -0
- package/src/migrations/0057_conversation_titles.sql +11 -0
- package/src/migrations/0058_conversation_selection.sql +4 -0
- package/src/migrations/0059_conversation_queue.sql +22 -0
- package/src/migrations/0060_file_previewers.sql +10 -0
- package/src/migrations/0061_queue_selection.sql +5 -0
- package/src/migrations/0062_queued_skill.sql +8 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
|
+
import { errors as joseErrors, jwtVerify, SignJWT } from "jose";
|
|
3
|
+
import { sql } from "kysely";
|
|
4
|
+
import { ACCESS_TOKEN_TTL_MAX_SECONDS } from "../config/schema.js";
|
|
5
|
+
import { ApiError } from "../errors.js";
|
|
6
|
+
import { ACCOUNT_COLUMNS, toAccount } from "./accounts.js";
|
|
7
|
+
import { sha256Hex } from "./hash.js";
|
|
8
|
+
/** 旧 refresh token 在被轮换后多久内重放视为并发刷新(不吊销会话)。 */
|
|
9
|
+
export const REFRESH_RACE_GRACE_MS = 30_000;
|
|
10
|
+
const REFRESH_PREFIX = "cap_rt_";
|
|
11
|
+
const ACCESS_KEY_INFO = "access-token/v1";
|
|
12
|
+
const revokedKey = (sid) => `capk:revoked-sid:${sid}`;
|
|
13
|
+
/**
|
|
14
|
+
* 吊销标记的 TTL:按 schema 允许的 access token 最长寿命 + 60s 计算,而不是本实例配置的寿命——
|
|
15
|
+
* 滚动修改 `auth.accessTokenTtlSeconds` 时,按旧(更长)寿命签发的 token 不会在标记过期后复活。
|
|
16
|
+
*/
|
|
17
|
+
const REVOKED_MARKER_TTL_SECONDS = ACCESS_TOKEN_TTL_MAX_SECONDS + 60;
|
|
18
|
+
const VERIFY_OPTS = { algorithms: ["HS256"], requiredClaims: ["exp", "sub"] };
|
|
19
|
+
const newRefreshToken = () => REFRESH_PREFIX + randomBytes(32).toString("base64url");
|
|
20
|
+
/** 按 JWS 头里的 kid 选派生密钥;找不到时抛出,由调用方映射为 `auth.required`。 */
|
|
21
|
+
class UnknownKidError extends Error {
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Web 会话服务:短期 access token(HS256 JWT,密钥由主密钥环派生)+ PG 中可吊销、一次一换的 refresh token。
|
|
25
|
+
* 吊销会在 Redis 写 `capk:revoked-sid:<sid>`(TTL 覆盖任何配置下 access token 的最长剩余寿命),使所有副本立即拒绝该会话的 access token;
|
|
26
|
+
* 验证 access token 时还会读 PG 的 `sessions.revoked_at`,Redis 丢数据也不会让已吊销的会话复活。
|
|
27
|
+
* 框架无关,由调用方注入依赖。
|
|
28
|
+
*/
|
|
29
|
+
export class SessionService {
|
|
30
|
+
db;
|
|
31
|
+
redis;
|
|
32
|
+
opts;
|
|
33
|
+
keys;
|
|
34
|
+
constructor(db, redis, keyring, opts) {
|
|
35
|
+
this.db = db;
|
|
36
|
+
this.redis = redis;
|
|
37
|
+
this.opts = opts;
|
|
38
|
+
this.keys = keyring.deriveKey(ACCESS_KEY_INFO);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 新建会话。传入 `trx` 时会话行在调用方的事务里写入(如初始化、凭邀请注册:与账号同一事务,
|
|
42
|
+
* 失败整体回滚);Cookie 由调用方在提交之后再设置。
|
|
43
|
+
*/
|
|
44
|
+
async create(accountId, meta, trx) {
|
|
45
|
+
const id = randomUUID();
|
|
46
|
+
const refreshToken = newRefreshToken();
|
|
47
|
+
const row = await (trx ?? this.db)
|
|
48
|
+
.insertInto("sessions")
|
|
49
|
+
.values({
|
|
50
|
+
id,
|
|
51
|
+
account_id: accountId,
|
|
52
|
+
refresh_hash: sha256Hex(refreshToken),
|
|
53
|
+
user_agent: meta.userAgent ?? null,
|
|
54
|
+
ip: meta.ip ?? null,
|
|
55
|
+
expires_at: sql `now() + make_interval(days => ${this.opts.refreshTtlDays})`,
|
|
56
|
+
})
|
|
57
|
+
.returning(["expires_at"])
|
|
58
|
+
.executeTakeFirstOrThrow();
|
|
59
|
+
return this.issue(id, accountId, refreshToken, row.expires_at);
|
|
60
|
+
}
|
|
61
|
+
async refresh(refreshToken, meta) {
|
|
62
|
+
const oldHash = sha256Hex(refreshToken);
|
|
63
|
+
const next = newRefreshToken();
|
|
64
|
+
// 原子轮换:并发的两次刷新只有一个能匹配 refresh_hash = old
|
|
65
|
+
const row = await this.db
|
|
66
|
+
.updateTable("sessions")
|
|
67
|
+
.set((eb) => ({
|
|
68
|
+
prev_refresh_hash: eb.ref("refresh_hash"),
|
|
69
|
+
refresh_hash: sha256Hex(next),
|
|
70
|
+
rotated_at: sql `now()`,
|
|
71
|
+
last_used_at: sql `now()`,
|
|
72
|
+
...(meta.userAgent !== undefined && { user_agent: meta.userAgent }),
|
|
73
|
+
...(meta.ip !== undefined && { ip: meta.ip }),
|
|
74
|
+
}))
|
|
75
|
+
.where("refresh_hash", "=", oldHash)
|
|
76
|
+
.where("revoked_at", "is", null)
|
|
77
|
+
.where("expires_at", ">", sql `now()`)
|
|
78
|
+
.returning(["id", "account_id", "expires_at"])
|
|
79
|
+
.executeTakeFirst();
|
|
80
|
+
if (!row)
|
|
81
|
+
return this.rejectRefresh(oldHash);
|
|
82
|
+
const account = await this.db
|
|
83
|
+
.selectFrom("accounts")
|
|
84
|
+
.select("status")
|
|
85
|
+
.where("id", "=", row.account_id)
|
|
86
|
+
.executeTakeFirst();
|
|
87
|
+
if (account?.status !== "active") {
|
|
88
|
+
await this.revoke(row.id);
|
|
89
|
+
throw new ApiError("auth.account_disabled", "Account is disabled");
|
|
90
|
+
}
|
|
91
|
+
return this.issue(row.id, row.account_id, next, row.expires_at);
|
|
92
|
+
}
|
|
93
|
+
/** 旧 refresh token 未能轮换:区分并发刷新(宽限期内)与重放(吊销会话)。 */
|
|
94
|
+
async rejectRefresh(oldHash) {
|
|
95
|
+
const prev = await this.db
|
|
96
|
+
.selectFrom("sessions")
|
|
97
|
+
.select((eb) => [
|
|
98
|
+
"id",
|
|
99
|
+
eb
|
|
100
|
+
.and([
|
|
101
|
+
eb("revoked_at", "is", null),
|
|
102
|
+
eb("expires_at", ">", sql `now()`),
|
|
103
|
+
eb("rotated_at", ">", sql `now() - make_interval(secs => ${REFRESH_RACE_GRACE_MS / 1000})`),
|
|
104
|
+
])
|
|
105
|
+
.as("in_grace"),
|
|
106
|
+
])
|
|
107
|
+
.where("prev_refresh_hash", "=", oldHash)
|
|
108
|
+
.executeTakeFirst();
|
|
109
|
+
if (prev?.in_grace) {
|
|
110
|
+
throw new ApiError("auth.refresh_race", "Refresh token was just rotated by another request");
|
|
111
|
+
}
|
|
112
|
+
if (prev)
|
|
113
|
+
await this.revoke(prev.id);
|
|
114
|
+
throw new ApiError("auth.refresh_invalid", "Refresh token is invalid");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 验证 access token 并读出会话所属账号(不判断账号状态,由调用方决定)。
|
|
118
|
+
* Redis 吊销标记是快速路径;PG 的 `sessions.revoked_at` 才是事实来源——Redis 被清空 / 故障切换丢数据时,
|
|
119
|
+
* 已登出或因改密码被吊销的会话不能复活(spec 8.1)。吊销检查与账号读取合并为一条按主键的 JOIN 查询。
|
|
120
|
+
*/
|
|
121
|
+
async verifyAccess(accessToken) {
|
|
122
|
+
let sub;
|
|
123
|
+
let sid;
|
|
124
|
+
try {
|
|
125
|
+
const { payload } = await jwtVerify(accessToken, this.keyFor, VERIFY_OPTS);
|
|
126
|
+
sub = payload.sub;
|
|
127
|
+
sid = payload.sid;
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
if (e instanceof joseErrors.JWTExpired) {
|
|
131
|
+
throw new ApiError("auth.token_expired", "Access token has expired");
|
|
132
|
+
}
|
|
133
|
+
throw new ApiError("auth.required", "Authentication required");
|
|
134
|
+
}
|
|
135
|
+
if (typeof sub !== "string" || typeof sid !== "string") {
|
|
136
|
+
throw new ApiError("auth.required", "Authentication required");
|
|
137
|
+
}
|
|
138
|
+
if (await this.redis.exists(revokedKey(sid))) {
|
|
139
|
+
throw new ApiError("auth.session_revoked", "Session has been revoked");
|
|
140
|
+
}
|
|
141
|
+
const row = await this.db
|
|
142
|
+
.selectFrom("sessions")
|
|
143
|
+
.innerJoin("accounts", "accounts.id", "sessions.account_id")
|
|
144
|
+
.select(["sessions.revoked_at", ...ACCOUNT_COLUMNS])
|
|
145
|
+
.where("sessions.id", "=", sid)
|
|
146
|
+
.executeTakeFirst();
|
|
147
|
+
if (!row || row.revoked_at !== null) {
|
|
148
|
+
throw new ApiError("auth.session_revoked", "Session has been revoked");
|
|
149
|
+
}
|
|
150
|
+
if (row.id !== sub)
|
|
151
|
+
throw new ApiError("auth.required", "Authentication required");
|
|
152
|
+
return { accountId: sub, sessionId: sid, account: toAccount(row) };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 只验签不看过期,供登出使用:过期的 token 也接受(取 `JWTExpired` 里已验签的 payload);
|
|
156
|
+
* 签名无效或缺 sid 返回 undefined。
|
|
157
|
+
*/
|
|
158
|
+
async sessionIdFromAccess(accessToken) {
|
|
159
|
+
let sid;
|
|
160
|
+
try {
|
|
161
|
+
sid = (await jwtVerify(accessToken, this.keyFor, VERIFY_OPTS)).payload.sid;
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
// JWTExpired 只会在签名校验通过之后抛出,其 payload 可信
|
|
165
|
+
if (!(e instanceof joseErrors.JWTExpired))
|
|
166
|
+
return undefined;
|
|
167
|
+
sid = e.payload.sid;
|
|
168
|
+
}
|
|
169
|
+
return typeof sid === "string" ? sid : undefined;
|
|
170
|
+
}
|
|
171
|
+
/** 按 refresh token 吊销其当前会话(供登出使用);无匹配则什么都不做。 */
|
|
172
|
+
async revokeByRefresh(refreshToken) {
|
|
173
|
+
const row = await this.db
|
|
174
|
+
.selectFrom("sessions")
|
|
175
|
+
.select("id")
|
|
176
|
+
.where("refresh_hash", "=", sha256Hex(refreshToken))
|
|
177
|
+
.where("revoked_at", "is", null)
|
|
178
|
+
.executeTakeFirst();
|
|
179
|
+
if (row)
|
|
180
|
+
await this.revoke(row.id);
|
|
181
|
+
}
|
|
182
|
+
async revoke(sessionId) {
|
|
183
|
+
await this.db
|
|
184
|
+
.updateTable("sessions")
|
|
185
|
+
.set({ revoked_at: sql `now()` })
|
|
186
|
+
.where("id", "=", sessionId)
|
|
187
|
+
.where("revoked_at", "is", null)
|
|
188
|
+
.execute();
|
|
189
|
+
await this.redis.set(revokedKey(sessionId), "1", "EX", REVOKED_MARKER_TTL_SECONDS);
|
|
190
|
+
}
|
|
191
|
+
async revokeAllForAccount(accountId, exceptSessionId) {
|
|
192
|
+
let q = this.db
|
|
193
|
+
.updateTable("sessions")
|
|
194
|
+
.set({ revoked_at: sql `now()` })
|
|
195
|
+
.where("account_id", "=", accountId)
|
|
196
|
+
.where("revoked_at", "is", null);
|
|
197
|
+
if (exceptSessionId !== undefined)
|
|
198
|
+
q = q.where("id", "!=", exceptSessionId);
|
|
199
|
+
const rows = await q.returning("id").execute();
|
|
200
|
+
await this.markRevoked(rows.map((r) => r.id));
|
|
201
|
+
return rows.length;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 给已在 PG 中吊销的会话写 Redis 吊销标记(快速路径);任一写入失败即抛出。
|
|
205
|
+
* 鉴权以 PG `revoked_at` 为准,调用方可以把这一步当作尽力而为。
|
|
206
|
+
*/
|
|
207
|
+
async markRevoked(sessionIds) {
|
|
208
|
+
if (sessionIds.length === 0)
|
|
209
|
+
return;
|
|
210
|
+
const pipe = this.redis.pipeline();
|
|
211
|
+
for (const id of sessionIds)
|
|
212
|
+
pipe.set(revokedKey(id), "1", "EX", REVOKED_MARKER_TTL_SECONDS);
|
|
213
|
+
const results = (await pipe.exec()) ?? [];
|
|
214
|
+
const failed = results.find(([err]) => err);
|
|
215
|
+
if (failed)
|
|
216
|
+
throw failed[0];
|
|
217
|
+
}
|
|
218
|
+
/** 设当前组织;会话已吊销、已过期或不存在 → `auth.session_revoked`。 */
|
|
219
|
+
async setCurrentOrg(sessionId, orgId) {
|
|
220
|
+
const r = await this.db
|
|
221
|
+
.updateTable("sessions")
|
|
222
|
+
.set({ current_org_id: orgId })
|
|
223
|
+
.where("id", "=", sessionId)
|
|
224
|
+
.where("revoked_at", "is", null)
|
|
225
|
+
.where("expires_at", ">", sql `now()`)
|
|
226
|
+
.executeTakeFirst();
|
|
227
|
+
if (r.numUpdatedRows === 0n) {
|
|
228
|
+
throw new ApiError("auth.session_revoked", "Session has been revoked");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* 切换当前组织(Web 会话):同一事务内先 `SELECT … FROM memberships WHERE org_id = $1 AND account_id = $2 FOR SHARE`
|
|
233
|
+
* 锁住这一条成员关系(且组织未软删除),再写会话——与「移出成员」(DELETE memberships 后清空会话当前组织)互斥,
|
|
234
|
+
* 不会留下指向已移出组织的 `current_org_id`。非成员或组织已软删除 → `org.not_found`;`null` 清空,不查成员关系。
|
|
235
|
+
*/
|
|
236
|
+
async switchCurrentOrg(sessionId, accountId, orgId) {
|
|
237
|
+
if (orgId === null)
|
|
238
|
+
return this.setCurrentOrg(sessionId, null);
|
|
239
|
+
await this.db.transaction().execute(async (t) => {
|
|
240
|
+
// 加锁顺序与移出成员一致:先组织行、再成员关系行(sessions.current_org_id 的外键检查也会锁组织行,
|
|
241
|
+
// 若先锁成员关系,会与持有组织行锁的移出成员互相等待而死锁)
|
|
242
|
+
const org = await t
|
|
243
|
+
.selectFrom("orgs")
|
|
244
|
+
.select("id")
|
|
245
|
+
.where("id", "=", orgId)
|
|
246
|
+
.where("deleted_at", "is", null)
|
|
247
|
+
.forShare()
|
|
248
|
+
.executeTakeFirst();
|
|
249
|
+
const m = org &&
|
|
250
|
+
(await t
|
|
251
|
+
.selectFrom("memberships")
|
|
252
|
+
.select("role")
|
|
253
|
+
.where("org_id", "=", orgId)
|
|
254
|
+
.where("account_id", "=", accountId)
|
|
255
|
+
.forShare()
|
|
256
|
+
.executeTakeFirst());
|
|
257
|
+
if (!m)
|
|
258
|
+
throw new ApiError("org.not_found", "Organization not found");
|
|
259
|
+
const r = await t
|
|
260
|
+
.updateTable("sessions")
|
|
261
|
+
.set({ current_org_id: orgId })
|
|
262
|
+
.where("id", "=", sessionId)
|
|
263
|
+
.where("revoked_at", "is", null)
|
|
264
|
+
.where("expires_at", ">", sql `now()`)
|
|
265
|
+
.executeTakeFirst();
|
|
266
|
+
if (r.numUpdatedRows === 0n) {
|
|
267
|
+
throw new ApiError("auth.session_revoked", "Session has been revoked");
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
/** 有效(未吊销且未过期)的会话;否则返回 undefined。 */
|
|
272
|
+
async get(sessionId) {
|
|
273
|
+
const row = await this.db
|
|
274
|
+
.selectFrom("sessions")
|
|
275
|
+
.select(["id", "account_id", "current_org_id"])
|
|
276
|
+
.where("id", "=", sessionId)
|
|
277
|
+
.where("revoked_at", "is", null)
|
|
278
|
+
.where("expires_at", ">", sql `now()`)
|
|
279
|
+
.executeTakeFirst();
|
|
280
|
+
return row && { id: row.id, accountId: row.account_id, currentOrgId: row.current_org_id };
|
|
281
|
+
}
|
|
282
|
+
keyFor = (header) => {
|
|
283
|
+
const key = header.kid === undefined ? undefined : this.keys.byId(header.kid);
|
|
284
|
+
if (!key)
|
|
285
|
+
throw new UnknownKidError("unknown kid");
|
|
286
|
+
return key;
|
|
287
|
+
};
|
|
288
|
+
async issue(sessionId, accountId, refreshToken, refreshExpiresAt) {
|
|
289
|
+
const iat = Math.floor(Date.now() / 1000);
|
|
290
|
+
const exp = iat + this.opts.accessTtlSeconds;
|
|
291
|
+
const accessToken = await new SignJWT({ sid: sessionId })
|
|
292
|
+
.setProtectedHeader({ alg: "HS256", kid: this.keys.currentId })
|
|
293
|
+
.setSubject(accountId)
|
|
294
|
+
.setIssuedAt(iat)
|
|
295
|
+
.setExpirationTime(exp)
|
|
296
|
+
.sign(this.keys.current);
|
|
297
|
+
return {
|
|
298
|
+
sessionId,
|
|
299
|
+
accountId,
|
|
300
|
+
accessToken,
|
|
301
|
+
refreshToken,
|
|
302
|
+
accessExpiresAt: new Date(exp * 1000),
|
|
303
|
+
refreshExpiresAt,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { Logger } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import type { Transaction } from "kysely";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import type { KernelDatabase, KernelDb } from "../db/kernel-schema.js";
|
|
5
|
+
/** 沙箱 cpu(核)与内存(MB)覆盖的范围(C19)。 */
|
|
6
|
+
export declare const SANDBOX_CPU_RANGE: {
|
|
7
|
+
readonly min: 0.25;
|
|
8
|
+
readonly max: 64;
|
|
9
|
+
};
|
|
10
|
+
export declare const SANDBOX_MEMORY_MB_RANGE: {
|
|
11
|
+
readonly min: 256;
|
|
12
|
+
readonly max: 262144;
|
|
13
|
+
};
|
|
14
|
+
/** 一个组织的沙箱限额覆盖:至少给一项;未给的项用部署默认。 */
|
|
15
|
+
export declare const SANDBOX_LIMIT_OVERRIDE: z.ZodObject<{
|
|
16
|
+
cpu: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
memoryMb: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
}, z.core.$strict>;
|
|
19
|
+
export type SandboxLimitOverride = z.infer<typeof SANDBOX_LIMIT_OVERRIDE>;
|
|
20
|
+
/**
|
|
21
|
+
* One organization's sub-agent limits (sub-agents spec §8.2): any of the three `subagents.*`
|
|
22
|
+
* values, within the same bounds; the ones not given use the deployment's config.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SUBAGENT_LIMIT_OVERRIDE: z.ZodObject<{
|
|
25
|
+
maxConcurrentPerRun: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
maxDispatchesPerRun: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
maxTokensPerRun: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
}, z.core.$strict>;
|
|
29
|
+
export type SubagentLimitOverride = z.infer<typeof SUBAGENT_LIMIT_OVERRIDE>;
|
|
30
|
+
export declare const DEPLOYMENT_SETTINGS: z.ZodObject<{
|
|
31
|
+
orgCreation: z.ZodDefault<z.ZodEnum<{
|
|
32
|
+
anyone: "anyone";
|
|
33
|
+
enterprise_admin: "enterprise_admin";
|
|
34
|
+
}>>;
|
|
35
|
+
runConcurrencyOverrides: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
36
|
+
priceCurrency: z.ZodDefault<z.ZodString>;
|
|
37
|
+
sandboxLimitOverrides: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
38
|
+
cpu: z.ZodOptional<z.ZodNumber>;
|
|
39
|
+
memoryMb: z.ZodOptional<z.ZodNumber>;
|
|
40
|
+
}, z.core.$strict>>>;
|
|
41
|
+
subagentLimitOverrides: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
42
|
+
maxConcurrentPerRun: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
maxDispatchesPerRun: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
maxTokensPerRun: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
}, z.core.$strict>>>;
|
|
46
|
+
customConnectors: z.ZodDefault<z.ZodEnum<{
|
|
47
|
+
allow: "allow";
|
|
48
|
+
deny: "deny";
|
|
49
|
+
}>>;
|
|
50
|
+
customSkills: z.ZodDefault<z.ZodEnum<{
|
|
51
|
+
allow: "allow";
|
|
52
|
+
deny: "deny";
|
|
53
|
+
}>>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
export type DeploymentSettings = z.infer<typeof DEPLOYMENT_SETTINGS>;
|
|
56
|
+
/**
|
|
57
|
+
* 设置的修改(PUT /api/v1/admin/settings 的 body):只改给出的键。
|
|
58
|
+
* `runConcurrencyOverrides` 按组织合并:值为正整数 → 设置该组织的上限;值为 null → 删除该组织的覆盖
|
|
59
|
+
* (回到 `runtime.orgConcurrency`);未列出的组织保持不变。
|
|
60
|
+
* `sandboxLimitOverrides` 同样按组织合并:给出的组织整项替换(未给的 cpu / memoryMb 回到部署默认),null 删除。
|
|
61
|
+
* `subagentLimitOverrides` merges by organization the same way: a given organization's entry is
|
|
62
|
+
* replaced whole (values left out go back to `subagents.*`), null removes it.
|
|
63
|
+
*/
|
|
64
|
+
export declare const DEPLOYMENT_SETTINGS_PATCH: z.ZodObject<{
|
|
65
|
+
orgCreation: z.ZodOptional<z.ZodEnum<{
|
|
66
|
+
anyone: "anyone";
|
|
67
|
+
enterprise_admin: "enterprise_admin";
|
|
68
|
+
}>>;
|
|
69
|
+
runConcurrencyOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodNumber>>>;
|
|
70
|
+
priceCurrency: z.ZodOptional<z.ZodString>;
|
|
71
|
+
sandboxLimitOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodObject<{
|
|
72
|
+
cpu: z.ZodOptional<z.ZodNumber>;
|
|
73
|
+
memoryMb: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
}, z.core.$strict>>>>;
|
|
75
|
+
subagentLimitOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodObject<{
|
|
76
|
+
maxConcurrentPerRun: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
maxDispatchesPerRun: z.ZodOptional<z.ZodNumber>;
|
|
78
|
+
maxTokensPerRun: z.ZodOptional<z.ZodNumber>;
|
|
79
|
+
}, z.core.$strict>>>>;
|
|
80
|
+
customConnectors: z.ZodOptional<z.ZodEnum<{
|
|
81
|
+
allow: "allow";
|
|
82
|
+
deny: "deny";
|
|
83
|
+
}>>;
|
|
84
|
+
customSkills: z.ZodOptional<z.ZodEnum<{
|
|
85
|
+
allow: "allow";
|
|
86
|
+
deny: "deny";
|
|
87
|
+
}>>;
|
|
88
|
+
}, z.core.$strict>;
|
|
89
|
+
export type DeploymentSettingsPatch = z.infer<typeof DEPLOYMENT_SETTINGS_PATCH>;
|
|
90
|
+
/**
|
|
91
|
+
* 读某个组织的沙箱限额覆盖(创建沙箱、组织设置页用);每次实时读 PG,多副本下改动立即生效。
|
|
92
|
+
* 只解析这个组织的那一条:没有设置、组织不在其中、或这一条存量值非法 → undefined;别的组织的条目非法不影响它。
|
|
93
|
+
*/
|
|
94
|
+
export declare function readSandboxLimitOverride(db: KernelDb, orgId: string): Promise<SandboxLimitOverride | undefined>;
|
|
95
|
+
/**
|
|
96
|
+
* One organization's sub-agent limit override, read live from PG (so a change applies on every
|
|
97
|
+
* replica at once); in the caller's transaction when one is given. Only this organization's entry
|
|
98
|
+
* is parsed: no setting, no entry, or an invalid stored entry → undefined.
|
|
99
|
+
*/
|
|
100
|
+
export declare function readSubagentLimitOverride(db: KernelDb | Transaction<KernelDatabase>, orgId: string): Promise<SubagentLimitOverride | undefined>;
|
|
101
|
+
/**
|
|
102
|
+
* When orgs may not create their own connectors / skills (deployment setting `customConnectors` /
|
|
103
|
+
* `customSkills` is `deny`, C22) throws `catalog.custom_disabled`: install from the enterprise
|
|
104
|
+
* catalog only. Reads PG live every time (can read in the caller's transaction); an invalid stored
|
|
105
|
+
* value counts as allow.
|
|
106
|
+
*/
|
|
107
|
+
export declare function assertCustomAllowed(db: KernelDb | Transaction<KernelDatabase>, key: "customConnectors" | "customSkills"): Promise<void>;
|
|
108
|
+
/** 部署级设置:每个键一行,读时缺省用默认值。 */
|
|
109
|
+
export declare class SettingsService {
|
|
110
|
+
private readonly db;
|
|
111
|
+
private readonly log?;
|
|
112
|
+
constructor(db: KernelDb, log?: Pick<Logger, "warn"> | undefined);
|
|
113
|
+
/**
|
|
114
|
+
* 读全部设置;传 `trx` 时在该事务内读(调用方已持有事务连接时不再占用池里的第二个连接)。
|
|
115
|
+
* 逐个键校验:库里某个键的值非法时该键用默认值并 warn 点名,其余合法的键照常生效;
|
|
116
|
+
* 不认识的键(如新版本写入的)忽略。
|
|
117
|
+
*/
|
|
118
|
+
get(trx?: Transaction<KernelDatabase>): Promise<DeploymentSettings>;
|
|
119
|
+
/** 更新设置:事务内取企业管理员锁并复核发起人仍是活跃企业管理员(否则 `forbidden`)。 */
|
|
120
|
+
update(patch: DeploymentSettingsPatch, actorAccountId: string, actorTokenId?: string): Promise<DeploymentSettings>;
|
|
121
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ApiError } from "../errors.js";
|
|
3
|
+
import { audit } from "./audit.js";
|
|
4
|
+
import { lockEnterpriseAdminsAndAuthorize } from "./enterprise-admin.js";
|
|
5
|
+
/** 币种代码:ISO 4217 的三位大写字母(如 USD、CNY)。 */
|
|
6
|
+
const CurrencyCode = z.string().regex(/^[A-Z]{3}$/, "must be a 3-letter ISO 4217 currency code");
|
|
7
|
+
/** 沙箱 cpu(核)与内存(MB)覆盖的范围(C19)。 */
|
|
8
|
+
export const SANDBOX_CPU_RANGE = { min: 0.25, max: 64 };
|
|
9
|
+
export const SANDBOX_MEMORY_MB_RANGE = { min: 256, max: 262_144 };
|
|
10
|
+
/** 一个组织的沙箱限额覆盖:至少给一项;未给的项用部署默认。 */
|
|
11
|
+
export const SANDBOX_LIMIT_OVERRIDE = z
|
|
12
|
+
.object({
|
|
13
|
+
cpu: z.number().min(SANDBOX_CPU_RANGE.min).max(SANDBOX_CPU_RANGE.max).optional(),
|
|
14
|
+
memoryMb: z
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.min(SANDBOX_MEMORY_MB_RANGE.min)
|
|
18
|
+
.max(SANDBOX_MEMORY_MB_RANGE.max)
|
|
19
|
+
.optional(),
|
|
20
|
+
})
|
|
21
|
+
.strict()
|
|
22
|
+
.refine((o) => o.cpu !== undefined || o.memoryMb !== undefined, {
|
|
23
|
+
message: "give cpu, memoryMb or both",
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* One organization's sub-agent limits (sub-agents spec §8.2): any of the three `subagents.*`
|
|
27
|
+
* values, within the same bounds; the ones not given use the deployment's config.
|
|
28
|
+
*/
|
|
29
|
+
export const SUBAGENT_LIMIT_OVERRIDE = z
|
|
30
|
+
.object({
|
|
31
|
+
maxConcurrentPerRun: z.number().int().min(1).max(20).optional(),
|
|
32
|
+
maxDispatchesPerRun: z.number().int().min(1).max(500).optional(),
|
|
33
|
+
maxTokensPerRun: z.number().int().min(10_000).optional(),
|
|
34
|
+
})
|
|
35
|
+
.strict()
|
|
36
|
+
.refine((o) => Object.values(o).some((v) => v !== undefined), {
|
|
37
|
+
message: "give maxConcurrentPerRun, maxDispatchesPerRun or maxTokensPerRun",
|
|
38
|
+
});
|
|
39
|
+
/** 组织能否自建连接器 / 技能(C22):`deny` 时只能从企业目录安装(T26 执行)。 */
|
|
40
|
+
const CustomPolicy = z.enum(["allow", "deny"]);
|
|
41
|
+
export const DEPLOYMENT_SETTINGS = z.object({
|
|
42
|
+
orgCreation: z.enum(["anyone", "enterprise_admin"]).default("anyone"),
|
|
43
|
+
/** 按组织覆盖运行并发上限(orgId → 上限);未列出的组织用 `runtime.orgConcurrency`。 */
|
|
44
|
+
runConcurrencyOverrides: z.record(z.string().min(1), z.number().int().positive()).default({}),
|
|
45
|
+
/** 模型价格表(`model_prices`)的币种;只用于显示估算成本,不做换算。 */
|
|
46
|
+
priceCurrency: CurrencyCode.default("USD"),
|
|
47
|
+
/** 按组织覆盖沙箱 cpu / 内存(orgId → 覆盖,C19);只对之后新建的沙箱生效。组织管理员只读。 */
|
|
48
|
+
sandboxLimitOverrides: z.record(z.string().min(1), SANDBOX_LIMIT_OVERRIDE).default({}),
|
|
49
|
+
/**
|
|
50
|
+
* Per-organization sub-agent limits (orgId → override); organizations not listed, and values
|
|
51
|
+
* not given, use `subagents.*`. Read live on every dispatch and tool resolution.
|
|
52
|
+
*/
|
|
53
|
+
subagentLimitOverrides: z.record(z.string().min(1), SUBAGENT_LIMIT_OVERRIDE).default({}),
|
|
54
|
+
/** 组织能否自建连接器(不经企业目录)。 */
|
|
55
|
+
customConnectors: CustomPolicy.default("allow"),
|
|
56
|
+
/**
|
|
57
|
+
* 组织能否自建技能(不经企业目录):deny 时组织管理员不能上传技能包。agent 自写技能(`skill_write`,私有 agent 的
|
|
58
|
+
* agent 级技能与共享 agent 经负责人审批的变更)不受此开关约束——那是 agent 定义的一部分,由 R3 / R4 把关。
|
|
59
|
+
*/
|
|
60
|
+
customSkills: CustomPolicy.default("allow"),
|
|
61
|
+
});
|
|
62
|
+
const DEFAULTS = DEPLOYMENT_SETTINGS.parse({});
|
|
63
|
+
/**
|
|
64
|
+
* 设置的修改(PUT /api/v1/admin/settings 的 body):只改给出的键。
|
|
65
|
+
* `runConcurrencyOverrides` 按组织合并:值为正整数 → 设置该组织的上限;值为 null → 删除该组织的覆盖
|
|
66
|
+
* (回到 `runtime.orgConcurrency`);未列出的组织保持不变。
|
|
67
|
+
* `sandboxLimitOverrides` 同样按组织合并:给出的组织整项替换(未给的 cpu / memoryMb 回到部署默认),null 删除。
|
|
68
|
+
* `subagentLimitOverrides` merges by organization the same way: a given organization's entry is
|
|
69
|
+
* replaced whole (values left out go back to `subagents.*`), null removes it.
|
|
70
|
+
*/
|
|
71
|
+
export const DEPLOYMENT_SETTINGS_PATCH = z
|
|
72
|
+
.object({
|
|
73
|
+
orgCreation: z.enum(["anyone", "enterprise_admin"]).optional(),
|
|
74
|
+
runConcurrencyOverrides: z
|
|
75
|
+
.record(z.string().min(1), z.number().int().positive().nullable())
|
|
76
|
+
.optional(),
|
|
77
|
+
priceCurrency: CurrencyCode.optional(),
|
|
78
|
+
sandboxLimitOverrides: z
|
|
79
|
+
.record(z.string().min(1), SANDBOX_LIMIT_OVERRIDE.nullable())
|
|
80
|
+
.optional(),
|
|
81
|
+
subagentLimitOverrides: z
|
|
82
|
+
.record(z.string().min(1), SUBAGENT_LIMIT_OVERRIDE.nullable())
|
|
83
|
+
.optional(),
|
|
84
|
+
customConnectors: CustomPolicy.optional(),
|
|
85
|
+
customSkills: CustomPolicy.optional(),
|
|
86
|
+
})
|
|
87
|
+
.strict();
|
|
88
|
+
/**
|
|
89
|
+
* 读某个组织的沙箱限额覆盖(创建沙箱、组织设置页用);每次实时读 PG,多副本下改动立即生效。
|
|
90
|
+
* 只解析这个组织的那一条:没有设置、组织不在其中、或这一条存量值非法 → undefined;别的组织的条目非法不影响它。
|
|
91
|
+
*/
|
|
92
|
+
export async function readSandboxLimitOverride(db, orgId) {
|
|
93
|
+
const row = await db
|
|
94
|
+
.selectFrom("deployment_settings")
|
|
95
|
+
.select("value")
|
|
96
|
+
.where("key", "=", "sandboxLimitOverrides")
|
|
97
|
+
.executeTakeFirst();
|
|
98
|
+
if (!row)
|
|
99
|
+
return undefined;
|
|
100
|
+
const all = row.value;
|
|
101
|
+
if (typeof all !== "object" || all === null || Array.isArray(all) || !Object.hasOwn(all, orgId)) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
const parsed = SANDBOX_LIMIT_OVERRIDE.safeParse(all[orgId]);
|
|
105
|
+
return parsed.success ? parsed.data : undefined;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* One organization's sub-agent limit override, read live from PG (so a change applies on every
|
|
109
|
+
* replica at once); in the caller's transaction when one is given. Only this organization's entry
|
|
110
|
+
* is parsed: no setting, no entry, or an invalid stored entry → undefined.
|
|
111
|
+
*/
|
|
112
|
+
export async function readSubagentLimitOverride(db, orgId) {
|
|
113
|
+
const row = await db
|
|
114
|
+
.selectFrom("deployment_settings")
|
|
115
|
+
.select("value")
|
|
116
|
+
.where("key", "=", "subagentLimitOverrides")
|
|
117
|
+
.executeTakeFirst();
|
|
118
|
+
if (!row)
|
|
119
|
+
return undefined;
|
|
120
|
+
const all = row.value;
|
|
121
|
+
if (typeof all !== "object" || all === null || Array.isArray(all) || !Object.hasOwn(all, orgId)) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
const parsed = SUBAGENT_LIMIT_OVERRIDE.safeParse(all[orgId]);
|
|
125
|
+
return parsed.success ? parsed.data : undefined;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* When orgs may not create their own connectors / skills (deployment setting `customConnectors` /
|
|
129
|
+
* `customSkills` is `deny`, C22) throws `catalog.custom_disabled`: install from the enterprise
|
|
130
|
+
* catalog only. Reads PG live every time (can read in the caller's transaction); an invalid stored
|
|
131
|
+
* value counts as allow.
|
|
132
|
+
*/
|
|
133
|
+
export async function assertCustomAllowed(db, key) {
|
|
134
|
+
const row = await db
|
|
135
|
+
.selectFrom("deployment_settings")
|
|
136
|
+
.select("value")
|
|
137
|
+
.where("key", "=", key)
|
|
138
|
+
.executeTakeFirst();
|
|
139
|
+
if (!row)
|
|
140
|
+
return;
|
|
141
|
+
const parsed = CustomPolicy.safeParse(row.value);
|
|
142
|
+
if (parsed.success && parsed.data === "deny") {
|
|
143
|
+
throw new ApiError("catalog.custom_disabled", key === "customConnectors"
|
|
144
|
+
? "Custom connectors are disabled in this deployment; install connectors from the enterprise catalog"
|
|
145
|
+
: "Custom skills are disabled in this deployment; install skills from the enterprise catalog");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/** 按组织合并覆盖:值为 null 删除该组织,其余整项替换;未列出的组织不变。 */
|
|
149
|
+
function mergeByOrg(current, patch) {
|
|
150
|
+
const merged = { ...current };
|
|
151
|
+
for (const [orgId, value] of Object.entries(patch)) {
|
|
152
|
+
if (value === null)
|
|
153
|
+
delete merged[orgId];
|
|
154
|
+
else
|
|
155
|
+
merged[orgId] = value;
|
|
156
|
+
}
|
|
157
|
+
return merged;
|
|
158
|
+
}
|
|
159
|
+
/** 部署级设置:每个键一行,读时缺省用默认值。 */
|
|
160
|
+
export class SettingsService {
|
|
161
|
+
db;
|
|
162
|
+
log;
|
|
163
|
+
constructor(db, log) {
|
|
164
|
+
this.db = db;
|
|
165
|
+
this.log = log;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 读全部设置;传 `trx` 时在该事务内读(调用方已持有事务连接时不再占用池里的第二个连接)。
|
|
169
|
+
* 逐个键校验:库里某个键的值非法时该键用默认值并 warn 点名,其余合法的键照常生效;
|
|
170
|
+
* 不认识的键(如新版本写入的)忽略。
|
|
171
|
+
*/
|
|
172
|
+
async get(trx) {
|
|
173
|
+
const rows = await (trx ?? this.db)
|
|
174
|
+
.selectFrom("deployment_settings")
|
|
175
|
+
.select(["key", "value"])
|
|
176
|
+
.execute();
|
|
177
|
+
const stored = new Map(rows.map((r) => [r.key, r.value]));
|
|
178
|
+
const out = { ...DEFAULTS };
|
|
179
|
+
for (const [key, field] of Object.entries(DEPLOYMENT_SETTINGS.shape)) {
|
|
180
|
+
if (!stored.has(key))
|
|
181
|
+
continue;
|
|
182
|
+
const parsed = field.safeParse(stored.get(key));
|
|
183
|
+
if (parsed.success) {
|
|
184
|
+
out[key] = parsed.data;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
this.log?.warn("invalid deployment setting; using default", {
|
|
188
|
+
key,
|
|
189
|
+
issues: parsed.error.issues.map((i) => i.message),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
/** 更新设置:事务内取企业管理员锁并复核发起人仍是活跃企业管理员(否则 `forbidden`)。 */
|
|
196
|
+
async update(patch, actorAccountId, actorTokenId) {
|
|
197
|
+
const check = DEPLOYMENT_SETTINGS_PATCH.safeParse(patch);
|
|
198
|
+
if (!check.success) {
|
|
199
|
+
throw new ApiError("validation_failed", "Invalid deployment settings", check.error.issues.map((i) => ({ path: i.path.join("."), message: i.message })));
|
|
200
|
+
}
|
|
201
|
+
await this.db.transaction().execute(async (trx) => {
|
|
202
|
+
await lockEnterpriseAdminsAndAuthorize(trx, actorAccountId);
|
|
203
|
+
// 企业管理员锁串行化所有设置修改:在锁内读当前覆盖再合并,不会丢失并发修改。
|
|
204
|
+
const next = {};
|
|
205
|
+
if (check.data.orgCreation !== undefined)
|
|
206
|
+
next.orgCreation = check.data.orgCreation;
|
|
207
|
+
if (check.data.priceCurrency !== undefined)
|
|
208
|
+
next.priceCurrency = check.data.priceCurrency;
|
|
209
|
+
if (check.data.customConnectors !== undefined) {
|
|
210
|
+
next.customConnectors = check.data.customConnectors;
|
|
211
|
+
}
|
|
212
|
+
if (check.data.customSkills !== undefined)
|
|
213
|
+
next.customSkills = check.data.customSkills;
|
|
214
|
+
const { runConcurrencyOverrides: runPatch, sandboxLimitOverrides: sandboxPatch, subagentLimitOverrides: subagentPatch, } = check.data;
|
|
215
|
+
if (runPatch !== undefined || sandboxPatch !== undefined || subagentPatch !== undefined) {
|
|
216
|
+
const current = await this.get(trx);
|
|
217
|
+
if (runPatch !== undefined) {
|
|
218
|
+
next.runConcurrencyOverrides = mergeByOrg(current.runConcurrencyOverrides, runPatch);
|
|
219
|
+
}
|
|
220
|
+
if (sandboxPatch !== undefined) {
|
|
221
|
+
next.sandboxLimitOverrides = mergeByOrg(current.sandboxLimitOverrides, sandboxPatch);
|
|
222
|
+
}
|
|
223
|
+
if (subagentPatch !== undefined) {
|
|
224
|
+
next.subagentLimitOverrides = mergeByOrg(current.subagentLimitOverrides, subagentPatch);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
for (const [key, value] of Object.entries(next)) {
|
|
228
|
+
if (value === undefined)
|
|
229
|
+
continue;
|
|
230
|
+
const json = JSON.stringify(value);
|
|
231
|
+
await trx
|
|
232
|
+
.insertInto("deployment_settings")
|
|
233
|
+
.values({ key, value: json, updated_by: actorAccountId })
|
|
234
|
+
.onConflict((oc) => oc
|
|
235
|
+
.column("key")
|
|
236
|
+
.doUpdateSet({ value: json, updated_by: actorAccountId, updated_at: new Date() }))
|
|
237
|
+
.execute();
|
|
238
|
+
}
|
|
239
|
+
await audit(trx, {
|
|
240
|
+
actorAccountId,
|
|
241
|
+
...(actorTokenId !== undefined && { actorTokenId }),
|
|
242
|
+
action: "deployment.settings.updated",
|
|
243
|
+
detail: check.data,
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
return this.get();
|
|
247
|
+
}
|
|
248
|
+
}
|