@capybara-hq/kernel 0.0.0-stage → 0.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +20 -2
- package/bootstrap.json +22 -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 +1125 -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 +223 -0
- package/dist/config/schema.js +1151 -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 +422 -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 +150 -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 +210 -0
- package/dist/errors.js +212 -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 +789 -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 +149 -0
- package/dist/extensions/bootstrap.js +441 -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 +170 -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 +67 -0
- package/dist/index.js +65 -0
- package/dist/kernel.d.ts +256 -0
- package/dist/kernel.js +1326 -0
- package/dist/log.d.ts +48 -0
- package/dist/log.js +229 -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 +271 -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 +147 -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 +805 -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 +550 -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 +114 -0
- package/dist/tools/builtins/sandbox/common.js +304 -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 +67 -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,327 @@
|
|
|
1
|
+
import { SDK_VERSION } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
import { ApiError } from "../errors.js";
|
|
4
|
+
import { lockEnterpriseAdminsAndAuthorize } from "../identity/enterprise-admin.js";
|
|
5
|
+
import { ExtensionApprovals, snapshotCovers, writeSnapshot, } from "./approvals.js";
|
|
6
|
+
import { PLUGINS_CHANGED_TOPIC, STALE_RECONCILE_PERIODS } from "./lifecycle.js";
|
|
7
|
+
import { ExtensionPackageError, permissionSetOfPackage, readExtensionPackage } from "./package.js";
|
|
8
|
+
import { buildPermissionSet, diffPermissions } from "./permission-set.js";
|
|
9
|
+
import { deriveExtensionStatus, migrationWarnings, permissionGroups, permissionKeyItems, reviewHash, } from "./permission-view.js";
|
|
10
|
+
export { PLUGINS_CHANGED_TOPIC };
|
|
11
|
+
/** 内容寻址的包 → 权限集合(包不可变,缓存安全;只作缓存,不是跨副本状态)。 */
|
|
12
|
+
const PACKAGE_SET_CACHE_MAX = 256;
|
|
13
|
+
/** 空权限集合(包读不到的降级项)。 */
|
|
14
|
+
const EMPTY_SET = buildPermissionSet({
|
|
15
|
+
provides: [],
|
|
16
|
+
config: { deployment: [], org: [] },
|
|
17
|
+
tables: [],
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* The package cannot be read -> `extension.package_unavailable`, or is in the pre-0.1.0 format ->
|
|
21
|
+
* `extension.legacy_format` (details and approval cannot be based on an unreadable package).
|
|
22
|
+
*/
|
|
23
|
+
function assertReadable(s) {
|
|
24
|
+
if (s.legacy)
|
|
25
|
+
throw new ApiError("extension.legacy_format", s.broken);
|
|
26
|
+
if (s.broken !== undefined) {
|
|
27
|
+
throw new ApiError("extension.package_unavailable", `The package of extension ${s.name} cannot be read: ${s.broken}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 部署级插件后台(企业管理员):列表 / 详情与网页批准权限(D8)。无状态,多副本共用;
|
|
32
|
+
* 状态由 PG(安装记录、快照、各副本状态行)与本副本宿主(配置声明插件的清单)推出。
|
|
33
|
+
*/
|
|
34
|
+
export class ExtensionAdmin {
|
|
35
|
+
d;
|
|
36
|
+
packageSets = new Map();
|
|
37
|
+
constructor(d) {
|
|
38
|
+
this.d = d;
|
|
39
|
+
}
|
|
40
|
+
/** 全部插件(配置声明 → 安装记录,各自按名字)。 */
|
|
41
|
+
async list() {
|
|
42
|
+
const subjects = await this.subjects();
|
|
43
|
+
return this.views(subjects);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A single extension; unknown -> `extension.not_found`; package unreadable ->
|
|
47
|
+
* `extension.package_unavailable`. With `allowUnreadable` an unreadable package returns the same
|
|
48
|
+
* degraded item as {@link list} (status failed, with `error`): used after a write has committed, so
|
|
49
|
+
* an operation that took effect is not reported as failed. A package in the pre-0.1.0 format is
|
|
50
|
+
* a state, not an error: it always returns the item with status `legacy_format` (so the admin can
|
|
51
|
+
* see it and uninstall it).
|
|
52
|
+
*/
|
|
53
|
+
async get(name, opts = {}) {
|
|
54
|
+
const s = (await this.subjects(name))[0];
|
|
55
|
+
if (!s)
|
|
56
|
+
throw new ApiError("extension.not_found", `Extension ${name} is not known to this deployment`);
|
|
57
|
+
if (!opts.allowUnreadable && !s.legacy)
|
|
58
|
+
assertReadable(s);
|
|
59
|
+
return (await this.views([s]))[0];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Web approval: re-checks the enterprise admin under the lock, compares the reviewed package
|
|
63
|
+
* (`sha256`) and permission digest (`reviewHash`), writes the snapshot (source web) and the
|
|
64
|
+
* `extension.permissions_approved` audit; after the commit publishes `kernel.plugins.changed` (a
|
|
65
|
+
* failure only warns) and waits for one reconcile on this replica (other replicas converge through
|
|
66
|
+
* the bus, the periodic job catches lost messages). Returns the view after approval.
|
|
67
|
+
* - Unknown -> `extension.not_found`;
|
|
68
|
+
* - the install record's `sha256` differs from the current one, or `reviewHash` differs from the one
|
|
69
|
+
* recomputed now -> `extension.approval_stale`; a config-declared extension's `sha256` must be
|
|
70
|
+
* null (otherwise `validation_failed`);
|
|
71
|
+
* - the snapshot already covers the current permission set (nothing to approve, F-N) ->
|
|
72
|
+
* `extension.not_pending`.
|
|
73
|
+
*/
|
|
74
|
+
async approve(actor, name, body, opts = {}) {
|
|
75
|
+
const s = (await this.subjects(name))[0];
|
|
76
|
+
if (!s)
|
|
77
|
+
throw new ApiError("extension.not_found", `Extension ${name} is not known to this deployment`);
|
|
78
|
+
assertReadable(s);
|
|
79
|
+
if (s.install === null && body.sha256 !== null) {
|
|
80
|
+
throw new ApiError("validation_failed", `Extension ${name} is declared in the startup config; approve it with sha256 null`);
|
|
81
|
+
}
|
|
82
|
+
const stale = () => new ApiError("extension.approval_stale", `The permissions of extension ${name} changed since they were reviewed; review them again`);
|
|
83
|
+
if (s.install !== null && body.sha256 !== s.install.sha256)
|
|
84
|
+
throw stale();
|
|
85
|
+
if (body.reviewHash !== reviewHash(s.set, s.warnings))
|
|
86
|
+
throw stale();
|
|
87
|
+
await this.d.db.transaction().execute(async (trx) => {
|
|
88
|
+
await lockEnterpriseAdminsAndAuthorize(trx, actor);
|
|
89
|
+
await sql `SELECT pg_advisory_xact_lock(hashtext(${`capybara.plugin-approve:${name}`}))`.execute(trx);
|
|
90
|
+
if (s.install !== null) {
|
|
91
|
+
// 审阅之后安装记录可能已换包(T14 升级):锁行复核
|
|
92
|
+
const row = await trx
|
|
93
|
+
.selectFrom("extension_installs")
|
|
94
|
+
.select("sha256")
|
|
95
|
+
.where("name", "=", name)
|
|
96
|
+
.forUpdate()
|
|
97
|
+
.executeTakeFirst();
|
|
98
|
+
if (row?.sha256 !== s.install.sha256)
|
|
99
|
+
throw stale();
|
|
100
|
+
}
|
|
101
|
+
const snapRow = await trx
|
|
102
|
+
.selectFrom("extension_permission_snapshots")
|
|
103
|
+
.select(["version", "permissions"])
|
|
104
|
+
.where("plugin", "=", name)
|
|
105
|
+
.forUpdate()
|
|
106
|
+
.executeTakeFirst();
|
|
107
|
+
const snap = snapRow && {
|
|
108
|
+
version: snapRow.version,
|
|
109
|
+
permissions: snapRow.permissions,
|
|
110
|
+
};
|
|
111
|
+
if (snapshotCovers(snap, s.set)) {
|
|
112
|
+
throw new ApiError("extension.not_pending", `Extension ${name} ${s.version} has no new permissions awaiting approval`);
|
|
113
|
+
}
|
|
114
|
+
const { added, removed } = diffPermissions(snap?.permissions, s.set);
|
|
115
|
+
await writeSnapshot(trx, name, s.version, s.set, {
|
|
116
|
+
source: "web",
|
|
117
|
+
approvedBy: actor,
|
|
118
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
119
|
+
audit: { added, removed, sha256: s.install?.sha256 ?? null },
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
try {
|
|
123
|
+
await this.d.bus.publish(PLUGINS_CHANGED_TOPIC, { plugin: name });
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
// 快照已写入;其他副本由周期 reconcile(T14)兜底
|
|
127
|
+
this.d.log.warn("cannot publish plugins.changed after approval", { plugin: name, err });
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
await this.d.reconcile?.(`approved:${name}`);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
this.d.log.error("loading approved plugins on this replica failed", { plugin: name, err });
|
|
134
|
+
}
|
|
135
|
+
return this.get(name);
|
|
136
|
+
}
|
|
137
|
+
/** 配置声明 → 安装记录(与配置声明重名的安装记录不生效,不单列)。`only` 给出时只取这一个。 */
|
|
138
|
+
async subjects(only) {
|
|
139
|
+
const declared = this.d.host
|
|
140
|
+
.declaredPlugins()
|
|
141
|
+
.filter((p) => only === undefined || p.name === only);
|
|
142
|
+
const taken = new Set(this.d.host.declaredPlugins().map((p) => p.name));
|
|
143
|
+
const out = [...declared]
|
|
144
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
145
|
+
.map((p) => ({
|
|
146
|
+
name: p.name,
|
|
147
|
+
source: p.source,
|
|
148
|
+
version: p.version,
|
|
149
|
+
set: p.permissions,
|
|
150
|
+
install: null,
|
|
151
|
+
configurable: p.configurable,
|
|
152
|
+
configValid: p.configValid,
|
|
153
|
+
warnings: [],
|
|
154
|
+
}));
|
|
155
|
+
if (only !== undefined && out.length > 0)
|
|
156
|
+
return out;
|
|
157
|
+
const rows = (await this.d.installs.list()).filter((r) => !taken.has(r.name) && (only === undefined || r.name === only));
|
|
158
|
+
for (const r of rows) {
|
|
159
|
+
let info;
|
|
160
|
+
try {
|
|
161
|
+
info = await this.packageInfo(r.sha256);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
// One unreadable package (bytes missing / corrupt, over the current limit) does not break
|
|
165
|
+
// the list: it becomes a failed item; a pre-0.1.0 package becomes a legacy_format item.
|
|
166
|
+
const legacy = err instanceof ExtensionPackageError && err.code === "extension.legacy_format";
|
|
167
|
+
const detail = legacy
|
|
168
|
+
? err.message
|
|
169
|
+
: `package ${r.name} ${r.version} (${r.sha256}) cannot be read: ${err instanceof Error ? err.message : String(err)}`;
|
|
170
|
+
// A pre-0.1.0 package is an expected state (repack needed), logged without a stack trace.
|
|
171
|
+
this.d.log.warn("plugin package unreadable for the admin view", {
|
|
172
|
+
plugin: r.name,
|
|
173
|
+
sha256: r.sha256,
|
|
174
|
+
...(legacy ? { reason: detail } : { err }),
|
|
175
|
+
});
|
|
176
|
+
out.push({
|
|
177
|
+
name: r.name,
|
|
178
|
+
source: "install",
|
|
179
|
+
version: r.version,
|
|
180
|
+
set: EMPTY_SET,
|
|
181
|
+
install: r,
|
|
182
|
+
configurable: false,
|
|
183
|
+
configValid: null,
|
|
184
|
+
broken: detail,
|
|
185
|
+
...(legacy && { legacy }),
|
|
186
|
+
warnings: [],
|
|
187
|
+
});
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const { set, configurable, warnings } = info;
|
|
191
|
+
out.push({
|
|
192
|
+
name: r.name,
|
|
193
|
+
source: "install",
|
|
194
|
+
version: r.version,
|
|
195
|
+
set,
|
|
196
|
+
install: r,
|
|
197
|
+
configurable,
|
|
198
|
+
configValid: null,
|
|
199
|
+
warnings,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 包的权限集合(静态清单 + 迁移 SQL,与上传时的审阅相同)、迁移审阅警告与是否有部署级配置字段;按 sha256 缓存。
|
|
206
|
+
*/
|
|
207
|
+
async packageInfo(sha256) {
|
|
208
|
+
let cached = this.packageSets.get(sha256);
|
|
209
|
+
if (!cached) {
|
|
210
|
+
const pkg = await readExtensionPackage(await this.d.blobs.get(sha256), {
|
|
211
|
+
maxBytes: this.d.config().packages.maxBytes,
|
|
212
|
+
hostSdkVersion: SDK_VERSION,
|
|
213
|
+
});
|
|
214
|
+
cached = {
|
|
215
|
+
set: permissionSetOfPackage(pkg),
|
|
216
|
+
warnings: migrationWarnings(pkg.migrationSql, pkg.section.manifest.name),
|
|
217
|
+
};
|
|
218
|
+
if (this.packageSets.size >= PACKAGE_SET_CACHE_MAX)
|
|
219
|
+
this.packageSets.clear();
|
|
220
|
+
this.packageSets.set(sha256, cached);
|
|
221
|
+
}
|
|
222
|
+
return { ...cached, configurable: cached.set.config.deployment.length > 0 };
|
|
223
|
+
}
|
|
224
|
+
async views(subjects) {
|
|
225
|
+
if (subjects.length === 0)
|
|
226
|
+
return [];
|
|
227
|
+
const names = subjects.map((s) => s.name);
|
|
228
|
+
const snapshots = await new ExtensionApprovals(this.d.db).all();
|
|
229
|
+
const staleSeconds = STALE_RECONCILE_PERIODS * this.d.config().extensionHost.reconcileIntervalSeconds;
|
|
230
|
+
const rows = await this.d.db
|
|
231
|
+
.selectFrom("extension_replica_status")
|
|
232
|
+
.selectAll()
|
|
233
|
+
.where("plugin", "in", names)
|
|
234
|
+
.where("heartbeat_at", ">", sql `now() - make_interval(secs => ${staleSeconds})`)
|
|
235
|
+
.orderBy("replica_id")
|
|
236
|
+
.execute();
|
|
237
|
+
return subjects.map((s) => {
|
|
238
|
+
const replicas = rows.filter((r) => r.plugin === s.name);
|
|
239
|
+
const snap = snapshots.get(s.name);
|
|
240
|
+
const { added, removed } = diffPermissions(snap?.permissions, s.set);
|
|
241
|
+
const target = s.install?.sha256 ?? null;
|
|
242
|
+
const configValid = s.configValid ??
|
|
243
|
+
!replicas.some((r) => r.state === "pending" && r.reason === "config" && r.sha256 === target);
|
|
244
|
+
const install = s.install;
|
|
245
|
+
if (s.broken !== undefined) {
|
|
246
|
+
return {
|
|
247
|
+
name: s.name,
|
|
248
|
+
version: s.version,
|
|
249
|
+
source: s.source,
|
|
250
|
+
sha256: target,
|
|
251
|
+
status: s.legacy ? "legacy_format" : "failed",
|
|
252
|
+
desired: install && {
|
|
253
|
+
version: install.version,
|
|
254
|
+
sha256: install.sha256,
|
|
255
|
+
state: install.desiredState,
|
|
256
|
+
},
|
|
257
|
+
replicas: replicas.map(replicaView),
|
|
258
|
+
permissions: [],
|
|
259
|
+
added: [],
|
|
260
|
+
addedItems: [],
|
|
261
|
+
removed: [],
|
|
262
|
+
reviewHash: reviewHash(s.set),
|
|
263
|
+
sensitive: false,
|
|
264
|
+
warnings: [],
|
|
265
|
+
snapshot: snapshotView(snap),
|
|
266
|
+
configurable: false,
|
|
267
|
+
configValid,
|
|
268
|
+
removable: install?.required !== true,
|
|
269
|
+
required: install?.required === true,
|
|
270
|
+
installSource: install?.source ?? null,
|
|
271
|
+
error: s.broken,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const permissions = permissionGroups(s.set);
|
|
275
|
+
return {
|
|
276
|
+
name: s.name,
|
|
277
|
+
version: s.version,
|
|
278
|
+
source: s.source,
|
|
279
|
+
sha256: target,
|
|
280
|
+
status: deriveExtensionStatus({
|
|
281
|
+
source: s.source,
|
|
282
|
+
desired: install && { sha256: install.sha256, state: install.desiredState },
|
|
283
|
+
pendingApproval: !snapshotCovers(snap, s.set),
|
|
284
|
+
configValid,
|
|
285
|
+
migratedSha: install?.migratedSha ?? null,
|
|
286
|
+
replicas: replicas.map((r) => ({ state: r.state, reason: r.reason, sha256: r.sha256 })),
|
|
287
|
+
}),
|
|
288
|
+
desired: install && {
|
|
289
|
+
version: install.version,
|
|
290
|
+
sha256: install.sha256,
|
|
291
|
+
state: install.desiredState,
|
|
292
|
+
},
|
|
293
|
+
replicas: replicas.map(replicaView),
|
|
294
|
+
permissions,
|
|
295
|
+
added,
|
|
296
|
+
addedItems: permissionKeyItems(added),
|
|
297
|
+
removed,
|
|
298
|
+
reviewHash: reviewHash(s.set, s.warnings),
|
|
299
|
+
sensitive: permissions.some((g) => g.sensitive),
|
|
300
|
+
warnings: s.warnings,
|
|
301
|
+
snapshot: snapshotView(snap),
|
|
302
|
+
configurable: s.configurable,
|
|
303
|
+
configValid,
|
|
304
|
+
removable: s.source === "install" && install?.required !== true,
|
|
305
|
+
required: install?.required === true,
|
|
306
|
+
installSource: install?.source ?? null,
|
|
307
|
+
};
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const replicaView = (r) => ({
|
|
312
|
+
replicaId: r.replica_id,
|
|
313
|
+
version: r.version,
|
|
314
|
+
state: r.state,
|
|
315
|
+
reason: r.reason,
|
|
316
|
+
detail: r.detail,
|
|
317
|
+
servingVersion: r.serving_version,
|
|
318
|
+
heartbeatAt: r.heartbeat_at.toISOString(),
|
|
319
|
+
});
|
|
320
|
+
const snapshotView = (snap) => snap
|
|
321
|
+
? {
|
|
322
|
+
version: snap.version,
|
|
323
|
+
approvedAt: snap.approvedAt.toISOString(),
|
|
324
|
+
approvedBy: snap.approvedBy,
|
|
325
|
+
source: snap.source,
|
|
326
|
+
}
|
|
327
|
+
: null;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { type ExtensionManifest } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { type Transaction } from "kysely";
|
|
3
|
+
import type { KernelDatabase, KernelDb } from "../db/kernel-schema.js";
|
|
4
|
+
import { type PermissionSet } from "./permission-set.js";
|
|
5
|
+
/** An approved permission snapshot (one row of `capybara.extension_permission_snapshots`). */
|
|
6
|
+
export interface PermissionSnapshot {
|
|
7
|
+
plugin: string;
|
|
8
|
+
version: string;
|
|
9
|
+
permissions: PermissionSet;
|
|
10
|
+
approvedBy: string | null;
|
|
11
|
+
approvedAt: Date;
|
|
12
|
+
/** cli:`capybara extensions approve`;auto:`extensionPermissions.autoApprove`;web:后台网页批准(T13);bootstrap: the bootstrap step (core vouched for the version). */
|
|
13
|
+
source: "cli" | "auto" | "web" | "bootstrap";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* An extension pending approval and not loaded this time (one item of `ExtensionHost.pending()` /
|
|
17
|
+
* `capybara extensions review`).
|
|
18
|
+
* reason: new = no snapshot (first seen); added = more permissions than the snapshot;
|
|
19
|
+
* dependency = needs no approval itself, but an extension point it `requires` is provided only by
|
|
20
|
+
* extensions pending approval (or not loaded because of that); the same when it declares
|
|
21
|
+
* `permissions.storage` and `object-store@1` has no provider that will load (providers may be empty).
|
|
22
|
+
*/
|
|
23
|
+
export interface PendingExtension {
|
|
24
|
+
plugin: string;
|
|
25
|
+
version: string;
|
|
26
|
+
added: string[];
|
|
27
|
+
removed: string[];
|
|
28
|
+
reason: "new" | "added" | "dependency";
|
|
29
|
+
/**
|
|
30
|
+
* When reason is dependency: the extension points blocking it and their providers (only providers
|
|
31
|
+
* that are not loading; empty when there is no provider at all).
|
|
32
|
+
*/
|
|
33
|
+
blockedBy?: {
|
|
34
|
+
extensionPoint: string;
|
|
35
|
+
providers: string[];
|
|
36
|
+
}[];
|
|
37
|
+
}
|
|
38
|
+
/** {@link planApprovals} 对单个插件的结论。 */
|
|
39
|
+
export type ApprovalDecision = {
|
|
40
|
+
plugin: string;
|
|
41
|
+
action: "load";
|
|
42
|
+
/** 需要批准但 autoApprove 开启:调用方以 source auto 写快照。 */
|
|
43
|
+
autoApprove: boolean;
|
|
44
|
+
added: string[];
|
|
45
|
+
removed: string[];
|
|
46
|
+
/** 快照需要写入或更新(无快照、权限或版本变了)。 */
|
|
47
|
+
changed: boolean;
|
|
48
|
+
} | {
|
|
49
|
+
plugin: string;
|
|
50
|
+
action: "pending";
|
|
51
|
+
pending: PendingExtension;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* 按依赖拓扑序(`ordered`)比对快照,决定每个插件加载还是待批准:
|
|
55
|
+
* - 无快照或比快照多出任何需要批准的一项({@link blockingKeys}:`ui.view:*` 除外)→ 待批准
|
|
56
|
+
* (`autoApprove` 时改为加载,由调用方写快照);只多出 `ui.view:*` 时照常加载,`changed` 为真,
|
|
57
|
+
* 调用方经 `refresh` 把它们补进快照;
|
|
58
|
+
* - 权限变少或不变 → 加载,`changed` 表示快照需要更新(权限或版本变了);版本比快照旧时照常加载但不更新快照;
|
|
59
|
+
* - 某个 `requires` 能力的提供方全都不加载 → 同样不加载(reason dependency);`optional` 不受影响;
|
|
60
|
+
* - 声明了 `permissions.storage` 而 `object-store@1` 没有提供方、或提供方全都不加载 → 同样不加载(reason dependency)。
|
|
61
|
+
*/
|
|
62
|
+
export declare function planApprovals(ordered: ExtensionManifest[], sets: Map<string, PermissionSet>, snapshots: Map<string, PermissionSnapshot>, opts?: {
|
|
63
|
+
autoApprove?: boolean;
|
|
64
|
+
}): ApprovalDecision[];
|
|
65
|
+
/**
|
|
66
|
+
* 给已决定加载的插件(生效的实例)补一份与当前权限集合相同的快照,
|
|
67
|
+
* 让 {@link planApprovals} 视其为「已批准、无变化」:不进待批准、不写快照,依赖它的插件照常判定。
|
|
68
|
+
*/
|
|
69
|
+
export declare function withPreApproved(snapshots: Map<string, PermissionSnapshot>, manifests: ExtensionManifest[], sets: Map<string, PermissionSet>): Map<string, PermissionSnapshot>;
|
|
70
|
+
/** 快照是否已覆盖该权限集合(没有需要批准的新增;F-N:「待批准」只看这一条,与期望状态无关)。 */
|
|
71
|
+
export declare function snapshotCovers(snap: Pick<PermissionSnapshot, "permissions"> | undefined, set: PermissionSet): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Writes (adds or overwrites) a snapshot in the caller's transaction; with `audit`, the
|
|
74
|
+
* `extension.permissions_approved` audit is written in the same transaction (actor is `approvedBy`,
|
|
75
|
+
* empty for the CLI).
|
|
76
|
+
*/
|
|
77
|
+
export declare function writeSnapshot(trx: Transaction<KernelDatabase>, plugin: string, version: string, permissions: PermissionSet, opts: {
|
|
78
|
+
source: PermissionSnapshot["source"];
|
|
79
|
+
approvedBy?: string | null;
|
|
80
|
+
actorTokenId?: string;
|
|
81
|
+
/** `app`:经应用包导入一次批准时的应用(T25)。 */
|
|
82
|
+
audit?: {
|
|
83
|
+
added: string[];
|
|
84
|
+
removed: string[];
|
|
85
|
+
sha256?: string | null;
|
|
86
|
+
app?: {
|
|
87
|
+
name: string;
|
|
88
|
+
version: string;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
}): Promise<void>;
|
|
92
|
+
/** 读写权限快照(直连 PG;内核启动与 CLI 共用)。 */
|
|
93
|
+
export declare class ExtensionApprovals {
|
|
94
|
+
private readonly db;
|
|
95
|
+
constructor(db: KernelDb);
|
|
96
|
+
/** 全部快照,按插件名索引。 */
|
|
97
|
+
all(): Promise<Map<string, PermissionSnapshot>>;
|
|
98
|
+
/**
|
|
99
|
+
* Approves (adds or overwrites) a snapshot: writes the current permission set and version,
|
|
100
|
+
* approved_at is now. With `audit`, the `extension.permissions_approved` audit is written in the
|
|
101
|
+
* same transaction (actor is `approvedBy`, empty for the CLI).
|
|
102
|
+
*/
|
|
103
|
+
approve(plugin: string, version: string, permissions: PermissionSet, opts: {
|
|
104
|
+
source: PermissionSnapshot["source"];
|
|
105
|
+
approvedBy?: string | null;
|
|
106
|
+
audit?: {
|
|
107
|
+
added: string[];
|
|
108
|
+
removed: string[];
|
|
109
|
+
sha256?: string | null;
|
|
110
|
+
};
|
|
111
|
+
}): Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* 权限变少、不变或只多出 `ui.view:*`(不卡加载)时更新快照的权限集合与版本;批准人、批准时间与来源保持不变,
|
|
114
|
+
* 不写审计(与 autoApprove 一样,Ruling A4;调用方记日志)。
|
|
115
|
+
* 在事务内锁行后重新核对(多副本并发启动时以库里的当前快照为准):快照不存在、`version` 比快照旧、
|
|
116
|
+
* 或当前集合相对快照有需要批准的新增时不更新。返回是否更新。
|
|
117
|
+
*/
|
|
118
|
+
refresh(plugin: string, version: string, permissions: PermissionSet): Promise<boolean>;
|
|
119
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { OBJECT_STORE_EXTENSION_POINT } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
import semver from "semver";
|
|
4
|
+
import { audit } from "../identity/audit.js";
|
|
5
|
+
import { blockingKeys, diffPermissions, permissionKeys, } from "./permission-set.js";
|
|
6
|
+
/**
|
|
7
|
+
* 按依赖拓扑序(`ordered`)比对快照,决定每个插件加载还是待批准:
|
|
8
|
+
* - 无快照或比快照多出任何需要批准的一项({@link blockingKeys}:`ui.view:*` 除外)→ 待批准
|
|
9
|
+
* (`autoApprove` 时改为加载,由调用方写快照);只多出 `ui.view:*` 时照常加载,`changed` 为真,
|
|
10
|
+
* 调用方经 `refresh` 把它们补进快照;
|
|
11
|
+
* - 权限变少或不变 → 加载,`changed` 表示快照需要更新(权限或版本变了);版本比快照旧时照常加载但不更新快照;
|
|
12
|
+
* - 某个 `requires` 能力的提供方全都不加载 → 同样不加载(reason dependency);`optional` 不受影响;
|
|
13
|
+
* - 声明了 `permissions.storage` 而 `object-store@1` 没有提供方、或提供方全都不加载 → 同样不加载(reason dependency)。
|
|
14
|
+
*/
|
|
15
|
+
export function planApprovals(ordered, sets, snapshots, opts = {}) {
|
|
16
|
+
const skipped = new Set();
|
|
17
|
+
const out = [];
|
|
18
|
+
for (const m of ordered) {
|
|
19
|
+
const set = sets.get(m.name);
|
|
20
|
+
const snap = snapshots.get(m.name);
|
|
21
|
+
const { added, removed } = diffPermissions(snap?.permissions, set);
|
|
22
|
+
const needsApproval = !snap || blockingKeys(added).length > 0;
|
|
23
|
+
if (needsApproval && !opts.autoApprove) {
|
|
24
|
+
skipped.add(m.name);
|
|
25
|
+
out.push({
|
|
26
|
+
plugin: m.name,
|
|
27
|
+
action: "pending",
|
|
28
|
+
pending: {
|
|
29
|
+
plugin: m.name,
|
|
30
|
+
version: m.version,
|
|
31
|
+
added,
|
|
32
|
+
removed,
|
|
33
|
+
reason: snap ? "added" : "new",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const blockedBy = [];
|
|
39
|
+
for (const cap of m.requires ?? []) {
|
|
40
|
+
const providers = ordered.filter((p) => p.provides.includes(cap)).map((p) => p.name);
|
|
41
|
+
if (providers.length > 0 && providers.every((p) => skipped.has(p))) {
|
|
42
|
+
blockedBy.push({ extensionPoint: cap, providers });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (m.permissions?.storage) {
|
|
46
|
+
const providers = ordered
|
|
47
|
+
.filter((p) => p !== m && p.provides.includes(OBJECT_STORE_EXTENSION_POINT))
|
|
48
|
+
.map((p) => p.name);
|
|
49
|
+
if (providers.every((p) => skipped.has(p))) {
|
|
50
|
+
blockedBy.push({ extensionPoint: OBJECT_STORE_EXTENSION_POINT, providers });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (blockedBy.length > 0) {
|
|
54
|
+
skipped.add(m.name);
|
|
55
|
+
out.push({
|
|
56
|
+
plugin: m.name,
|
|
57
|
+
action: "pending",
|
|
58
|
+
pending: {
|
|
59
|
+
plugin: m.name,
|
|
60
|
+
version: m.version,
|
|
61
|
+
added,
|
|
62
|
+
removed,
|
|
63
|
+
reason: "dependency",
|
|
64
|
+
blockedBy,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// 权限集合由清单规范化得到,键相同即集合相同(jsonb 会重排对象键,不能比 JSON 文本)
|
|
70
|
+
// 比快照版本旧(滚动升级中重启的旧副本、或有意回滚):照常加载但不缩减快照,
|
|
71
|
+
// 否则旧副本会把新版本已批准的权限写没,之后的新副本又变成待批准
|
|
72
|
+
const changed = !snap ||
|
|
73
|
+
(!isOlder(m.version, snap.version) &&
|
|
74
|
+
(snap.version !== m.version ||
|
|
75
|
+
permissionKeys(snap.permissions).join("\n") !== permissionKeys(set).join("\n")));
|
|
76
|
+
out.push({
|
|
77
|
+
plugin: m.name,
|
|
78
|
+
action: "load",
|
|
79
|
+
autoApprove: needsApproval,
|
|
80
|
+
added,
|
|
81
|
+
removed,
|
|
82
|
+
changed,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 给已决定加载的插件(生效的实例)补一份与当前权限集合相同的快照,
|
|
89
|
+
* 让 {@link planApprovals} 视其为「已批准、无变化」:不进待批准、不写快照,依赖它的插件照常判定。
|
|
90
|
+
*/
|
|
91
|
+
export function withPreApproved(snapshots, manifests, sets) {
|
|
92
|
+
const out = new Map(snapshots);
|
|
93
|
+
for (const m of manifests) {
|
|
94
|
+
out.set(m.name, {
|
|
95
|
+
plugin: m.name,
|
|
96
|
+
version: m.version,
|
|
97
|
+
permissions: sets.get(m.name),
|
|
98
|
+
approvedBy: null,
|
|
99
|
+
approvedAt: new Date(0),
|
|
100
|
+
source: "auto",
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
/** 快照是否已覆盖该权限集合(没有需要批准的新增;F-N:「待批准」只看这一条,与期望状态无关)。 */
|
|
106
|
+
export function snapshotCovers(snap, set) {
|
|
107
|
+
return (snap !== undefined && blockingKeys(diffPermissions(snap.permissions, set).added).length === 0);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Writes (adds or overwrites) a snapshot in the caller's transaction; with `audit`, the
|
|
111
|
+
* `extension.permissions_approved` audit is written in the same transaction (actor is `approvedBy`,
|
|
112
|
+
* empty for the CLI).
|
|
113
|
+
*/
|
|
114
|
+
export async function writeSnapshot(trx, plugin, version, permissions, opts) {
|
|
115
|
+
const values = {
|
|
116
|
+
plugin,
|
|
117
|
+
version,
|
|
118
|
+
permissions: JSON.stringify(permissions),
|
|
119
|
+
approved_by: opts.approvedBy ?? null,
|
|
120
|
+
approved_at: sql `now()`,
|
|
121
|
+
source: opts.source,
|
|
122
|
+
};
|
|
123
|
+
await trx
|
|
124
|
+
.insertInto("extension_permission_snapshots")
|
|
125
|
+
.values(values)
|
|
126
|
+
.onConflict((oc) => oc.column("plugin").doUpdateSet({
|
|
127
|
+
version: values.version,
|
|
128
|
+
permissions: values.permissions,
|
|
129
|
+
approved_by: values.approved_by,
|
|
130
|
+
approved_at: values.approved_at,
|
|
131
|
+
source: values.source,
|
|
132
|
+
}))
|
|
133
|
+
.execute();
|
|
134
|
+
if (opts.audit) {
|
|
135
|
+
await audit(trx, {
|
|
136
|
+
...(opts.approvedBy && { actorAccountId: opts.approvedBy }),
|
|
137
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
138
|
+
action: "extension.permissions_approved",
|
|
139
|
+
target: plugin,
|
|
140
|
+
detail: { plugin, version, source: opts.source, ...opts.audit },
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** `version` 是否比 `than` 旧(任一方不是合法 semver 时视为不旧)。 */
|
|
145
|
+
const isOlder = (version, than) => semver.valid(version) !== null && semver.valid(than) !== null && semver.lt(version, than);
|
|
146
|
+
/** 读写权限快照(直连 PG;内核启动与 CLI 共用)。 */
|
|
147
|
+
export class ExtensionApprovals {
|
|
148
|
+
db;
|
|
149
|
+
constructor(db) {
|
|
150
|
+
this.db = db;
|
|
151
|
+
}
|
|
152
|
+
/** 全部快照,按插件名索引。 */
|
|
153
|
+
async all() {
|
|
154
|
+
const rows = await this.db.selectFrom("extension_permission_snapshots").selectAll().execute();
|
|
155
|
+
return new Map(rows.map((r) => [
|
|
156
|
+
r.plugin,
|
|
157
|
+
{
|
|
158
|
+
plugin: r.plugin,
|
|
159
|
+
version: r.version,
|
|
160
|
+
permissions: r.permissions,
|
|
161
|
+
approvedBy: r.approved_by,
|
|
162
|
+
approvedAt: r.approved_at,
|
|
163
|
+
source: r.source,
|
|
164
|
+
},
|
|
165
|
+
]));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Approves (adds or overwrites) a snapshot: writes the current permission set and version,
|
|
169
|
+
* approved_at is now. With `audit`, the `extension.permissions_approved` audit is written in the
|
|
170
|
+
* same transaction (actor is `approvedBy`, empty for the CLI).
|
|
171
|
+
*/
|
|
172
|
+
async approve(plugin, version, permissions, opts) {
|
|
173
|
+
await this.db
|
|
174
|
+
.transaction()
|
|
175
|
+
.execute((trx) => writeSnapshot(trx, plugin, version, permissions, opts));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 权限变少、不变或只多出 `ui.view:*`(不卡加载)时更新快照的权限集合与版本;批准人、批准时间与来源保持不变,
|
|
179
|
+
* 不写审计(与 autoApprove 一样,Ruling A4;调用方记日志)。
|
|
180
|
+
* 在事务内锁行后重新核对(多副本并发启动时以库里的当前快照为准):快照不存在、`version` 比快照旧、
|
|
181
|
+
* 或当前集合相对快照有需要批准的新增时不更新。返回是否更新。
|
|
182
|
+
*/
|
|
183
|
+
async refresh(plugin, version, permissions) {
|
|
184
|
+
return this.db.transaction().execute(async (trx) => {
|
|
185
|
+
const row = await trx
|
|
186
|
+
.selectFrom("extension_permission_snapshots")
|
|
187
|
+
.select(["version", "permissions"])
|
|
188
|
+
.where("plugin", "=", plugin)
|
|
189
|
+
.forUpdate()
|
|
190
|
+
.executeTakeFirst();
|
|
191
|
+
if (!row || isOlder(version, row.version))
|
|
192
|
+
return false;
|
|
193
|
+
const { added } = diffPermissions(row.permissions, permissions);
|
|
194
|
+
if (blockingKeys(added).length > 0) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
await trx
|
|
198
|
+
.updateTable("extension_permission_snapshots")
|
|
199
|
+
.set({ version, permissions: JSON.stringify(permissions) })
|
|
200
|
+
.where("plugin", "=", plugin)
|
|
201
|
+
.execute();
|
|
202
|
+
return true;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|