@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,441 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { bootstrapFileName, parseBootstrapManifest, SDK_VERSION, } from "@capybara-hq/plugin-sdk";
|
|
6
|
+
import { sql } from "kysely";
|
|
7
|
+
import pg from "pg";
|
|
8
|
+
import semver from "semver";
|
|
9
|
+
import { catalogPackageError } from "../catalog/plugin-import.js";
|
|
10
|
+
import { PluginPackageError, readPluginPackage } from "../catalog/plugin-package.js";
|
|
11
|
+
import { pgConnectOptions } from "../db/pool.js";
|
|
12
|
+
import { ApiError } from "../errors.js";
|
|
13
|
+
import { audit } from "../identity/audit.js";
|
|
14
|
+
import { writeSnapshot } from "./approvals.js";
|
|
15
|
+
import { ExtensionPackageError, permissionSetOfPackage, readExtensionPackage } from "./package.js";
|
|
16
|
+
import { diffPermissions } from "./permission-set.js";
|
|
17
|
+
/**
|
|
18
|
+
* The bootstrap step (package ecosystem spec §7): installs the plugins pinned by the bootstrap
|
|
19
|
+
* manifest (`packages/kernel/bootstrap.json`) from the tgz files baked into the image. It replaced
|
|
20
|
+
* the builtin extensions.
|
|
21
|
+
*
|
|
22
|
+
* - Every file (`<dir>/<name>-<version>.tgz`) is checked against the entry's sha512 before anything
|
|
23
|
+
* is read or written; a missing file is `bootstrap.missing_file`, a mismatch
|
|
24
|
+
* `bootstrap.integrity_mismatch` (both name the plugin), and then nothing is written. It never
|
|
25
|
+
* touches the network.
|
|
26
|
+
* - The whole run holds the session advisory lock `capybara.bootstrap` on a connection of its own
|
|
27
|
+
* (taken with `pg_try_advisory_lock` in a backoff loop that observes the signal, and closed
|
|
28
|
+
* afterwards, so the lock never outlives the run): when several replicas start together only one
|
|
29
|
+
* runs it; the others wait, then find it done. "Done" is a `bootstrap_runs` row for the
|
|
30
|
+
* manifest's sha256 (written with the audit `bootstrap.completed` only when every entry
|
|
31
|
+
* succeeded; otherwise the next start runs it again, which is idempotent). A lock connection
|
|
32
|
+
* that drops mid-run is not detected (its errors are swallowed) and the run goes on without the
|
|
33
|
+
* lock, so a second replica could run concurrently: accepted, since a concurrent import or
|
|
34
|
+
* install degrades to `catalog.version_exists` and a deploy from the package store.
|
|
35
|
+
* - Only entries new to the manifest are installed (Ruling 5): an optional entry that the last
|
|
36
|
+
* completed run already handled and that is not installed now (an enterprise admin uninstalled
|
|
37
|
+
* it) stays uninstalled -> `kept`. A required entry is always installed.
|
|
38
|
+
* - Per entry, by the installed state of its extension:
|
|
39
|
+
* - not installed (and new, or required): imported into the catalog (source `bootstrap`, ref
|
|
40
|
+
* `bootstrap:<name>@<version>`, like a marketplace import), installed, approved (snapshot
|
|
41
|
+
* source `bootstrap`, audited `extension.permissions_approved` with `source: "bootstrap"`)
|
|
42
|
+
* and enabled -> `installed`;
|
|
43
|
+
* - installed from `bootstrap` at a lower version: upgraded the same way (core's release vouched
|
|
44
|
+
* for the version, so new permissions are pre-approved and audited), keeping the desired state
|
|
45
|
+
* an enterprise admin chose (a disabled optional plugin stays disabled) -> `upgraded`;
|
|
46
|
+
* - installed at a higher version, or from another source (an enterprise admin upgraded it), or
|
|
47
|
+
* the name is config-declared (`declared`: config wins, no install record is created):
|
|
48
|
+
* untouched, never downgraded -> `kept`;
|
|
49
|
+
* - a declarative plugin (no extension): imported into the catalog only -> `imported` (`kept`
|
|
50
|
+
* when that version is already there, or when the entry is not new).
|
|
51
|
+
* Every extension entry gets `extension_installs.required` from the manifest, and a required one
|
|
52
|
+
* is enabled on the deployment.
|
|
53
|
+
* - Package bytes are content-addressed: when the very same tgz was ingested before with another
|
|
54
|
+
* source (e.g. imported from a marketplace), its `extension_packages` row keeps that source and
|
|
55
|
+
* so does the install record, which is then not a bootstrap install and never upgraded by a
|
|
56
|
+
* later manifest (`kept`, like a plugin the admin installed).
|
|
57
|
+
* - An install record still `required` whose entry left the manifest is not uninstalled; it only
|
|
58
|
+
* loses `required` -> `required_cleared`.
|
|
59
|
+
* A failed entry does not stop the others; the run then throws {@link BootstrapFailedError} naming
|
|
60
|
+
* them. The packages are kept in PG (`blob_store = 'pg'`), so installing an extension never needs
|
|
61
|
+
* the object store (object-store-s3 is itself a bootstrap plugin); a declarative plugin's catalog
|
|
62
|
+
* files do.
|
|
63
|
+
*/
|
|
64
|
+
/** The bootstrap manifest that ships with the kernel package. */
|
|
65
|
+
export const BOOTSTRAP_MANIFEST_FILE = fileURLToPath(new URL("../../bootstrap.json", import.meta.url));
|
|
66
|
+
/** Some entries failed (the others were done); the run is not recorded as done. */
|
|
67
|
+
export class BootstrapFailedError extends Error {
|
|
68
|
+
failures;
|
|
69
|
+
results;
|
|
70
|
+
/**
|
|
71
|
+
* @param results what the entries that did not fail did (pass them as `carry` to a later run in
|
|
72
|
+
* the same start, so its record keeps `installed` instead of `kept`).
|
|
73
|
+
*/
|
|
74
|
+
constructor(failures, results = []) {
|
|
75
|
+
super(`bootstrap failed for ${failures.map((f) => `${f.name}${f.required ? " (required)" : ""}: ${f.message}`).join("; ")}`);
|
|
76
|
+
this.failures = failures;
|
|
77
|
+
this.results = results;
|
|
78
|
+
this.name = "BootstrapFailedError";
|
|
79
|
+
}
|
|
80
|
+
/** A required entry failed: the kernel must not serve without it. */
|
|
81
|
+
get requiredFailed() {
|
|
82
|
+
return this.failures.some((f) => f.required);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** sha256 (hex) of a manifest: of its JSON text as parsed (key order kept). */
|
|
86
|
+
export function bootstrapManifestSha256(manifest) {
|
|
87
|
+
return createHash("sha256").update(JSON.stringify(manifest)).digest("hex");
|
|
88
|
+
}
|
|
89
|
+
/** Reads and parses a bootstrap manifest file; an invalid one throws with its problems. */
|
|
90
|
+
export async function readBootstrapManifest(file = BOOTSTRAP_MANIFEST_FILE) {
|
|
91
|
+
const parsed = parseBootstrapManifest(JSON.parse(await readFile(file, "utf8")));
|
|
92
|
+
if ("errors" in parsed) {
|
|
93
|
+
throw new Error(`invalid bootstrap manifest ${file}: ${parsed.errors.join("; ")}`);
|
|
94
|
+
}
|
|
95
|
+
return parsed;
|
|
96
|
+
}
|
|
97
|
+
const integrityOf = (bytes) => `sha512-${createHash("sha512").update(bytes).digest("base64")}`;
|
|
98
|
+
/** The advisory lock around a whole run. */
|
|
99
|
+
const LOCK_KEY = "capybara.bootstrap";
|
|
100
|
+
export class BootstrapService {
|
|
101
|
+
d;
|
|
102
|
+
constructor(d) {
|
|
103
|
+
this.d = d;
|
|
104
|
+
}
|
|
105
|
+
/** Whether the bootstrap step completed for the manifest with this sha256. */
|
|
106
|
+
async isDone(manifestSha256) {
|
|
107
|
+
const row = await this.d.db
|
|
108
|
+
.selectFrom("bootstrap_runs")
|
|
109
|
+
.select("manifest_sha256")
|
|
110
|
+
.where("manifest_sha256", "=", manifestSha256)
|
|
111
|
+
.executeTakeFirst();
|
|
112
|
+
return row !== undefined;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Runs the bootstrap step (see the file header); when it is already done for this manifest
|
|
116
|
+
* (also when another replica finished it while this one waited for the lock) returns the
|
|
117
|
+
* recorded result without doing anything. `carry`: the results of an earlier, failed run in the
|
|
118
|
+
* same start ({@link BootstrapFailedError.results}); an entry it installed, upgraded or imported
|
|
119
|
+
* keeps that action instead of `kept` in this run's record.
|
|
120
|
+
*/
|
|
121
|
+
async run(o) {
|
|
122
|
+
const manifestSha256 = bootstrapManifestSha256(o.manifest);
|
|
123
|
+
const files = await this.verifyFiles(o.manifest, o.dir);
|
|
124
|
+
return this.locked(o.signal, async () => {
|
|
125
|
+
const done = await this.d.db
|
|
126
|
+
.selectFrom("bootstrap_runs")
|
|
127
|
+
.select("results")
|
|
128
|
+
.where("manifest_sha256", "=", manifestSha256)
|
|
129
|
+
.executeTakeFirst();
|
|
130
|
+
if (done) {
|
|
131
|
+
return { manifestSha256, results: done.results };
|
|
132
|
+
}
|
|
133
|
+
const handled = await this.lastRunNames();
|
|
134
|
+
const results = [];
|
|
135
|
+
const failures = [];
|
|
136
|
+
for (const e of o.manifest.plugins) {
|
|
137
|
+
o.signal?.throwIfAborted();
|
|
138
|
+
try {
|
|
139
|
+
const r = await this.entry(e, files.get(e.name), handled);
|
|
140
|
+
results.push(carried(r, o.carry));
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
this.d.log.error("bootstrap: a plugin could not be installed", {
|
|
144
|
+
plugin: e.name,
|
|
145
|
+
version: e.version,
|
|
146
|
+
required: e.required,
|
|
147
|
+
err,
|
|
148
|
+
});
|
|
149
|
+
failures.push({
|
|
150
|
+
name: e.name,
|
|
151
|
+
required: e.required,
|
|
152
|
+
code: err instanceof ApiError ? err.code : "internal",
|
|
153
|
+
message: err instanceof Error ? err.message : String(err),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
results.push(...(await this.clearRemoved(o.manifest)));
|
|
158
|
+
if (failures.length > 0)
|
|
159
|
+
throw new BootstrapFailedError(failures, results);
|
|
160
|
+
await this.d.db.transaction().execute(async (trx) => {
|
|
161
|
+
await trx
|
|
162
|
+
.insertInto("bootstrap_runs")
|
|
163
|
+
.values({
|
|
164
|
+
manifest_sha256: manifestSha256,
|
|
165
|
+
completed_at: sql `now()`,
|
|
166
|
+
results: JSON.stringify(results),
|
|
167
|
+
})
|
|
168
|
+
.execute();
|
|
169
|
+
await audit(trx, {
|
|
170
|
+
action: "bootstrap.completed",
|
|
171
|
+
target: manifestSha256,
|
|
172
|
+
detail: { manifestSha256, results },
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
this.d.log.info("bootstrap completed", { manifestSha256, results });
|
|
176
|
+
return { manifestSha256, results };
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Runs `fn` holding the session advisory lock on a connection of its own: `pg_try_advisory_lock`
|
|
181
|
+
* retried with a backoff (100 ms doubling to 1 s) that stops when `signal` aborts. The connection
|
|
182
|
+
* is closed afterwards in every case, which releases the lock even when the unlock failed.
|
|
183
|
+
*/
|
|
184
|
+
async locked(signal, fn) {
|
|
185
|
+
const client = new pg.Client({
|
|
186
|
+
connectionString: this.d.dbUrl,
|
|
187
|
+
...pgConnectOptions({ connectTimeoutMs: this.d.connectTimeoutMs }),
|
|
188
|
+
});
|
|
189
|
+
client.on("error", () => { });
|
|
190
|
+
try {
|
|
191
|
+
await client.connect();
|
|
192
|
+
for (let wait = 100;; wait = Math.min(wait * 2, 1_000)) {
|
|
193
|
+
signal?.throwIfAborted();
|
|
194
|
+
const r = await client.query("SELECT pg_try_advisory_lock(hashtext($1)) AS ok", [LOCK_KEY]);
|
|
195
|
+
if (r.rows[0]?.ok === true)
|
|
196
|
+
break;
|
|
197
|
+
await sleep(wait, signal);
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
return await fn();
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
await client
|
|
204
|
+
.query("SELECT pg_advisory_unlock(hashtext($1))", [LOCK_KEY])
|
|
205
|
+
.catch((err) => this.d.log.warn("bootstrap: cannot release the advisory lock; closing its connection", {
|
|
206
|
+
err,
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
await client.end().catch(() => { });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/** The entry names the last completed run handled (undefined before any run completed). */
|
|
215
|
+
async lastRunNames() {
|
|
216
|
+
const row = await this.d.db
|
|
217
|
+
.selectFrom("bootstrap_runs")
|
|
218
|
+
.select("results")
|
|
219
|
+
.orderBy("completed_at", "desc")
|
|
220
|
+
.limit(1)
|
|
221
|
+
.executeTakeFirst();
|
|
222
|
+
if (!row)
|
|
223
|
+
return undefined;
|
|
224
|
+
return new Set(row.results
|
|
225
|
+
.filter((r) => r.action !== "required_cleared")
|
|
226
|
+
.map((r) => r.name));
|
|
227
|
+
}
|
|
228
|
+
/** Reads every entry's file and checks its sha512 (before the lock: nothing is written yet). */
|
|
229
|
+
async verifyFiles(manifest, dir) {
|
|
230
|
+
const out = new Map();
|
|
231
|
+
for (const e of manifest.plugins) {
|
|
232
|
+
const file = join(dir, bootstrapFileName(e));
|
|
233
|
+
let bytes;
|
|
234
|
+
try {
|
|
235
|
+
bytes = new Uint8Array(await readFile(file));
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
if (err.code !== "ENOENT")
|
|
239
|
+
throw err;
|
|
240
|
+
throw new ApiError("bootstrap.missing_file", `Bootstrap plugin ${e.name} ${e.version}: ${file} is missing; the image must carry every package bootstrap.json pins`);
|
|
241
|
+
}
|
|
242
|
+
const actual = integrityOf(bytes);
|
|
243
|
+
if (actual !== e.integrity) {
|
|
244
|
+
throw new ApiError("bootstrap.integrity_mismatch", `Bootstrap plugin ${e.name} ${e.version}: ${file} does not match its pinned sha512 (expected ${e.integrity.slice(0, 19)}…, got ${actual.slice(0, 19)}…); refusing to install anything`);
|
|
245
|
+
}
|
|
246
|
+
out.set(e.name, bytes);
|
|
247
|
+
}
|
|
248
|
+
return out;
|
|
249
|
+
}
|
|
250
|
+
async entry(e, bytes, handled) {
|
|
251
|
+
const pkg = await readPluginPackage(bytes, {
|
|
252
|
+
maxBytes: this.d.config().packages.maxBytes,
|
|
253
|
+
hostSdkVersion: SDK_VERSION,
|
|
254
|
+
}).catch((err) => {
|
|
255
|
+
throw err instanceof PluginPackageError ? catalogPackageError(err) : err;
|
|
256
|
+
});
|
|
257
|
+
if (pkg.manifest.name !== e.name || pkg.manifest.version !== e.version) {
|
|
258
|
+
throw new ApiError("catalog.invalid_manifest", `The package for bootstrap entry ${e.name} ${e.version} contains plugin ${pkg.manifest.name} ${pkg.manifest.version}`);
|
|
259
|
+
}
|
|
260
|
+
const ref = `bootstrap:${e.name}@${e.version}`;
|
|
261
|
+
// Not new to the manifest: an optional entry left out on purpose stays out (Ruling 5)
|
|
262
|
+
const isNew = handled === undefined || !handled.has(e.name);
|
|
263
|
+
if (!pkg.manifest.extension) {
|
|
264
|
+
if (!isNew)
|
|
265
|
+
return { name: e.name, action: "kept", version: e.version };
|
|
266
|
+
const imported = await this.importOnly(e, bytes, ref);
|
|
267
|
+
return { name: e.name, action: imported ? "imported" : "kept", version: e.version };
|
|
268
|
+
}
|
|
269
|
+
if (this.d.declared?.().has(e.name)) {
|
|
270
|
+
this.d.log.warn("bootstrap: the plugin is declared in the extensions config list; the config plugin is used", { plugin: e.name });
|
|
271
|
+
return { name: e.name, action: "kept", version: e.version };
|
|
272
|
+
}
|
|
273
|
+
const row = await this.d.db
|
|
274
|
+
.selectFrom("extension_installs")
|
|
275
|
+
.select(["version", "source", "required", "desired_state", "sha256"])
|
|
276
|
+
.where("name", "=", e.name)
|
|
277
|
+
.executeTakeFirst();
|
|
278
|
+
if (!row && !isNew && !e.required) {
|
|
279
|
+
this.d.log.info("bootstrap: an optional plugin that is not installed stays uninstalled", {
|
|
280
|
+
plugin: e.name,
|
|
281
|
+
});
|
|
282
|
+
return { name: e.name, action: "kept", version: e.version };
|
|
283
|
+
}
|
|
284
|
+
let result;
|
|
285
|
+
if (!row) {
|
|
286
|
+
await this.deploy(e, bytes, ref, true);
|
|
287
|
+
result = { name: e.name, action: "installed", version: e.version };
|
|
288
|
+
}
|
|
289
|
+
else if (row.source === "bootstrap" && isLower(row.version, e.version)) {
|
|
290
|
+
// The desired state the admin chose is kept; a required plugin is enabled below anyway
|
|
291
|
+
await this.deploy(e, bytes, ref, row.desired_state === "enabled");
|
|
292
|
+
result = { name: e.name, action: "upgraded", version: e.version };
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
if (row.source === "bootstrap" &&
|
|
296
|
+
row.version === e.version &&
|
|
297
|
+
row.sha256 !== createHash("sha256").update(bytes).digest("hex")) {
|
|
298
|
+
// The pin changed bytes without a version bump (an image built from main between
|
|
299
|
+
// releases): the installed package stays, so say so instead of keeping it silently
|
|
300
|
+
this.d.log.warn("bootstrap: the image's package differs from the installed one at the same version; the installed package is kept (bump the version to roll it out)", { plugin: e.name, version: e.version });
|
|
301
|
+
}
|
|
302
|
+
result = { name: e.name, action: "kept", version: row.version };
|
|
303
|
+
}
|
|
304
|
+
if (row?.required !== e.required) {
|
|
305
|
+
await this.d.db
|
|
306
|
+
.updateTable("extension_installs")
|
|
307
|
+
.set({ required: e.required })
|
|
308
|
+
.where("name", "=", e.name)
|
|
309
|
+
.execute();
|
|
310
|
+
}
|
|
311
|
+
// A required install must run on the deployment (an org cannot use it otherwise)
|
|
312
|
+
if (e.required && row?.desired_state === "disabled") {
|
|
313
|
+
await this.d.ops.enable(e.name, null);
|
|
314
|
+
}
|
|
315
|
+
return result;
|
|
316
|
+
}
|
|
317
|
+
/** A declarative plugin: catalog only. Returns false when that version is already imported. */
|
|
318
|
+
async importOnly(e, bytes, ref) {
|
|
319
|
+
try {
|
|
320
|
+
const { stagingId, review } = await this.d.imports.prepare(null, bytes, {
|
|
321
|
+
kind: "bootstrap",
|
|
322
|
+
ref,
|
|
323
|
+
integrity: e.integrity,
|
|
324
|
+
});
|
|
325
|
+
await this.d.imports.confirm(null, stagingId, {
|
|
326
|
+
reviewHash: review.reviewHash,
|
|
327
|
+
deployExtension: false,
|
|
328
|
+
});
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
if (err instanceof ApiError && err.code === "catalog.version_exists")
|
|
333
|
+
return false;
|
|
334
|
+
throw err;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Imports, approves, installs and enables (one review, confirmed with `deployExtension`). When
|
|
339
|
+
* the catalog already has this version (an earlier run stopped after importing, or the same
|
|
340
|
+
* package came from a marketplace), the extension is deployed from the package store instead.
|
|
341
|
+
*/
|
|
342
|
+
async deploy(e, bytes, ref, enable) {
|
|
343
|
+
let staged;
|
|
344
|
+
try {
|
|
345
|
+
staged = await this.d.imports.prepare(null, bytes, {
|
|
346
|
+
kind: "bootstrap",
|
|
347
|
+
ref,
|
|
348
|
+
integrity: e.integrity,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
if (err instanceof ApiError && err.code === "catalog.version_exists") {
|
|
353
|
+
await this.deployFromStore(e, bytes, ref, enable);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
throw err;
|
|
357
|
+
}
|
|
358
|
+
const r = await this.d.imports.confirm(null, staged.stagingId, {
|
|
359
|
+
reviewHash: staged.review.reviewHash,
|
|
360
|
+
deployExtension: true,
|
|
361
|
+
enable,
|
|
362
|
+
});
|
|
363
|
+
if (r.deploy?.result === "failed") {
|
|
364
|
+
throw new ApiError((r.deploy.code ?? "internal"), r.deploy.message ?? `installing extension ${e.name} failed`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/** The extension of a catalog version already imported: ingest, approve, install (, enable). */
|
|
368
|
+
async deployFromStore(e, bytes, ref, enable) {
|
|
369
|
+
const review = await this.d.installs.ingest(null, bytes, { source: "bootstrap", ref }, { store: "pg" });
|
|
370
|
+
let set;
|
|
371
|
+
try {
|
|
372
|
+
set = permissionSetOfPackage(await readExtensionPackage(bytes, {
|
|
373
|
+
maxBytes: this.d.config().packages.maxBytes,
|
|
374
|
+
hostSdkVersion: SDK_VERSION,
|
|
375
|
+
}));
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
throw err instanceof ExtensionPackageError ? catalogPackageError(err) : err;
|
|
379
|
+
}
|
|
380
|
+
await this.d.db.transaction().execute(async (trx) => {
|
|
381
|
+
await sql `SELECT pg_advisory_xact_lock(hashtext(${`capybara.plugin-approve:${e.name}`}))`.execute(trx);
|
|
382
|
+
const snap = await trx
|
|
383
|
+
.selectFrom("extension_permission_snapshots")
|
|
384
|
+
.select("permissions")
|
|
385
|
+
.where("plugin", "=", e.name)
|
|
386
|
+
.forUpdate()
|
|
387
|
+
.executeTakeFirst();
|
|
388
|
+
const { added, removed } = diffPermissions(snap?.permissions, set);
|
|
389
|
+
await writeSnapshot(trx, e.name, e.version, set, {
|
|
390
|
+
source: "bootstrap",
|
|
391
|
+
audit: { added, removed, sha256: review.sha256 },
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
const item = await this.d.db
|
|
395
|
+
.selectFrom("catalog_items")
|
|
396
|
+
.select("id")
|
|
397
|
+
.where("name", "=", e.name)
|
|
398
|
+
.where("deleted_at", "is", null)
|
|
399
|
+
.executeTakeFirst();
|
|
400
|
+
await this.d.ops.install(e.name, review.sha256, null, undefined, item ? { catalogItemId: item.id } : {});
|
|
401
|
+
if (enable)
|
|
402
|
+
await this.d.ops.enable(e.name, null);
|
|
403
|
+
}
|
|
404
|
+
/** Install records still `required` whose entry left the manifest lose `required`. */
|
|
405
|
+
async clearRemoved(manifest) {
|
|
406
|
+
const names = manifest.plugins.map((p) => p.name);
|
|
407
|
+
let q = this.d.db
|
|
408
|
+
.updateTable("extension_installs")
|
|
409
|
+
.set({ required: false })
|
|
410
|
+
.where("required", "=", true);
|
|
411
|
+
if (names.length > 0)
|
|
412
|
+
q = q.where("name", "not in", names);
|
|
413
|
+
const rows = await q.returning(["name", "version"]).execute();
|
|
414
|
+
return rows.map((r) => ({ name: r.name, action: "required_cleared", version: r.version }));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/** A `kept` result whose entry an earlier pass of the same start installed / upgraded / imported. */
|
|
418
|
+
function carried(r, carry) {
|
|
419
|
+
if (r.action !== "kept")
|
|
420
|
+
return r;
|
|
421
|
+
const before = carry?.find((c) => c.name === r.name && c.version === r.version);
|
|
422
|
+
return before !== undefined && before.action !== "kept" && before.action !== "required_cleared"
|
|
423
|
+
? before
|
|
424
|
+
: r;
|
|
425
|
+
}
|
|
426
|
+
/** Resolves after `ms`; rejects with the abort reason when `signal` aborts first. */
|
|
427
|
+
function sleep(ms, signal) {
|
|
428
|
+
return new Promise((resolve, reject) => {
|
|
429
|
+
const onAbort = () => {
|
|
430
|
+
clearTimeout(timer);
|
|
431
|
+
reject(signal?.reason);
|
|
432
|
+
};
|
|
433
|
+
const timer = setTimeout(() => {
|
|
434
|
+
signal?.removeEventListener("abort", onAbort);
|
|
435
|
+
resolve();
|
|
436
|
+
}, ms);
|
|
437
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
/** `installed` is below `pinned` (a version that is not semver is never upgraded). */
|
|
441
|
+
const isLower = (installed, pinned) => semver.valid(installed) !== null && semver.valid(pinned) !== null && semver.lt(installed, pinned);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { KernelConfig } from "../config/schema.js";
|
|
3
|
+
import { type KernelDb } from "../db/kernel-schema.js";
|
|
4
|
+
import type { KernelLogger } from "../log.js";
|
|
5
|
+
import { ExtensionAdminOps } from "./admin-ops.js";
|
|
6
|
+
import { ExtensionAdmin } from "./admin-view.js";
|
|
7
|
+
import { ExtensionApprovals } from "./approvals.js";
|
|
8
|
+
import { type ConfigIssue } from "./deployment-config.js";
|
|
9
|
+
import { type InspectedExtension } from "./host.js";
|
|
10
|
+
import { ExtensionInstalls } from "./installs.js";
|
|
11
|
+
import type { PermissionSet } from "./permission-set.js";
|
|
12
|
+
/** {@link openExtensionCli} 的结果:CLI 的 `capybara extensions *` 共用。 */
|
|
13
|
+
export interface ExtensionCli {
|
|
14
|
+
config: KernelConfig;
|
|
15
|
+
db: KernelDb;
|
|
16
|
+
/** 配置声明的插件(导入、按依赖排序,不 setup)。 */
|
|
17
|
+
inspected: InspectedExtension[];
|
|
18
|
+
/**
|
|
19
|
+
* 配置声明插件的部署配置问题(启动配置与 PG 里保存的合并后按 schema 校验;只有路径与说明,不含值):
|
|
20
|
+
* 有问题的插件内核不加载(待配置)。没有问题的不在这里。
|
|
21
|
+
*/
|
|
22
|
+
configIssues: ReadonlyMap<string, ConfigIssue[]>;
|
|
23
|
+
/** The valid merged deployment config (secrets decrypted) of the declared extensions that have one. */
|
|
24
|
+
deploymentConfigs: ReadonlyMap<string, unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* The deployment config of any extension (an install record too) validated against `schema`: the
|
|
27
|
+
* startup config completed by the fields stored in PG, as the kernel merges it. No schema = `{}`.
|
|
28
|
+
*/
|
|
29
|
+
deploymentConfigOf(name: string, schema: z.ZodTypeAny | undefined): Promise<{
|
|
30
|
+
ok: true;
|
|
31
|
+
value: unknown;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
issues: ConfigIssue[];
|
|
35
|
+
}>;
|
|
36
|
+
installs: ExtensionInstalls;
|
|
37
|
+
admin: ExtensionAdmin;
|
|
38
|
+
ops: ExtensionAdminOps;
|
|
39
|
+
approvals: ExtensionApprovals;
|
|
40
|
+
/** CLI 本次刚导入的包字节(降级判断等读包时优先用它:包可能存在 CLI 读不到的对象存储里)。 */
|
|
41
|
+
remember(sha256: string, bytes: Uint8Array): void;
|
|
42
|
+
/** 安装记录包的权限集合(与后台审阅相同);包在对象存储里时 CLI 读不到,抛错。 */
|
|
43
|
+
packageSet(sha256: string): Promise<PermissionSet>;
|
|
44
|
+
/** The bytes of a stored package (this process's imports first, then the package store in PG). */
|
|
45
|
+
readPackage(sha256: string): Promise<Uint8Array>;
|
|
46
|
+
/** 写完 PG 后经 Redis 发布 `kernel.plugins.changed`(C18);失败只告警,返回是否发布成功。 */
|
|
47
|
+
publishChanged(plugin: string): Promise<boolean>;
|
|
48
|
+
close(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The CLI's extension management context (C18, F-Q): connects only to PG (and Redis for publishing),
|
|
52
|
+
* starts no extension host and runs no extension's `setup` (a catalog import sets up the declared
|
|
53
|
+
* object-store extension itself, see `openCatalogCli`). Packages the CLI imports are always
|
|
54
|
+
* stored in PG (`blob_store = 'pg'`); replicas read by `blob_store`. Install / enable / disable /
|
|
55
|
+
* uninstall share {@link ExtensionAdminOps} with the admin console (actor null, audits without an
|
|
56
|
+
* actor); after writing PG it publishes `kernel.plugins.changed` and running replicas reconcile; a
|
|
57
|
+
* failed publish only warns (the periodic reconcile catches up).
|
|
58
|
+
*/
|
|
59
|
+
export declare function openExtensionCli(config: KernelConfig, log: KernelLogger, opts?: {
|
|
60
|
+
resolveFrom?: string;
|
|
61
|
+
}): Promise<ExtensionCli>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { SDK_VERSION } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import { Redis } from "ioredis";
|
|
3
|
+
import { createBus } from "../ctx/bus.js";
|
|
4
|
+
import { createKeyring } from "../ctx/secrets.js";
|
|
5
|
+
import { kernelDb } from "../db/kernel-schema.js";
|
|
6
|
+
import { createDb } from "../db/pool.js";
|
|
7
|
+
import { ExtensionAdminOps } from "./admin-ops.js";
|
|
8
|
+
import { ExtensionAdmin } from "./admin-view.js";
|
|
9
|
+
import { ExtensionApprovals } from "./approvals.js";
|
|
10
|
+
import { ExtensionBlobs } from "./blobs.js";
|
|
11
|
+
import { mergeDeploymentConfig, readStoredDeploymentConfig, schemaFields, secretPathsOf, } from "./deployment-config.js";
|
|
12
|
+
import { ExtensionHost } from "./host.js";
|
|
13
|
+
import { ExtensionInstalls } from "./installs.js";
|
|
14
|
+
import { PLUGINS_CHANGED_TOPIC } from "./lifecycle.js";
|
|
15
|
+
import { toIssues } from "./org-config.js";
|
|
16
|
+
import { ExtensionPackageError, extensionPackageApiError, permissionSetOfPackage, readExtensionPackage, } from "./package.js";
|
|
17
|
+
/** CLI 发布 bus 消息时连 Redis 的时限(连不上只告警)。 */
|
|
18
|
+
const CLI_REDIS_CONNECT_TIMEOUT_MS = 3_000;
|
|
19
|
+
/**
|
|
20
|
+
* The CLI's extension management context (C18, F-Q): connects only to PG (and Redis for publishing),
|
|
21
|
+
* starts no extension host and runs no extension's `setup` (a catalog import sets up the declared
|
|
22
|
+
* object-store extension itself, see `openCatalogCli`). Packages the CLI imports are always
|
|
23
|
+
* stored in PG (`blob_store = 'pg'`); replicas read by `blob_store`. Install / enable / disable /
|
|
24
|
+
* uninstall share {@link ExtensionAdminOps} with the admin console (actor null, audits without an
|
|
25
|
+
* actor); after writing PG it publishes `kernel.plugins.changed` and running replicas reconcile; a
|
|
26
|
+
* failed publish only warns (the periodic reconcile catches up).
|
|
27
|
+
*/
|
|
28
|
+
export async function openExtensionCli(config, log, opts = {}) {
|
|
29
|
+
const inspected = await ExtensionHost.inspect(config.extensions, {
|
|
30
|
+
...(opts.resolveFrom !== undefined && { resolveFrom: opts.resolveFrom }),
|
|
31
|
+
});
|
|
32
|
+
const raw = createDb(config.db.url, 2, (err) => log.error("pg idle client error", { err }), {
|
|
33
|
+
connectTimeoutMs: config.db.connectTimeoutMs,
|
|
34
|
+
});
|
|
35
|
+
const db = kernelDb(raw);
|
|
36
|
+
const local = new Map();
|
|
37
|
+
const stored = new ExtensionBlobs({ db, maxBytes: () => config.packages.maxBytes });
|
|
38
|
+
const blobs = {
|
|
39
|
+
get: async (sha256) => local.get(sha256) ?? stored.get(sha256),
|
|
40
|
+
};
|
|
41
|
+
const declared = new Map(inspected.map((p) => [p.manifest.name, p.source]));
|
|
42
|
+
// 部署配置 = 启动配置补上后台保存在 PG 的字段(C10);不合法的插件内核不加载(待配置)
|
|
43
|
+
const keyring = createKeyring(Buffer.from(config.masterKey, "base64"), config.masterKeyPrevious.map((k) => Buffer.from(k, "base64")));
|
|
44
|
+
const deploymentConfigOf = async (name, schema) => {
|
|
45
|
+
if (!schema)
|
|
46
|
+
return { ok: true, value: {} };
|
|
47
|
+
const stored = await readStoredDeploymentConfig(db, keyring, name, {
|
|
48
|
+
secretPaths: secretPathsOf(schemaFields(schema)),
|
|
49
|
+
});
|
|
50
|
+
const r = schema.safeParse(mergeDeploymentConfig(stored, config.extensionConfig[name], schemaFields(schema).map((f) => f.path)));
|
|
51
|
+
return r.success ? { ok: true, value: r.data } : { ok: false, issues: toIssues(r.error) };
|
|
52
|
+
};
|
|
53
|
+
const configIssues = new Map();
|
|
54
|
+
const deploymentConfigs = new Map();
|
|
55
|
+
try {
|
|
56
|
+
for (const p of inspected) {
|
|
57
|
+
const schema = p.manifest.config?.deployment;
|
|
58
|
+
if (!schema)
|
|
59
|
+
continue;
|
|
60
|
+
const r = await deploymentConfigOf(p.manifest.name, schema);
|
|
61
|
+
if (r.ok)
|
|
62
|
+
deploymentConfigs.set(p.manifest.name, r.value);
|
|
63
|
+
else
|
|
64
|
+
configIssues.set(p.manifest.name, r.issues);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
await raw.destroy().catch(() => { });
|
|
69
|
+
throw e;
|
|
70
|
+
}
|
|
71
|
+
const declaredInfo = inspected.map((p) => ({
|
|
72
|
+
name: p.manifest.name,
|
|
73
|
+
source: p.source,
|
|
74
|
+
version: p.manifest.version,
|
|
75
|
+
permissions: p.permissions,
|
|
76
|
+
configurable: p.manifest.config?.deployment !== undefined,
|
|
77
|
+
configValid: !configIssues.has(p.manifest.name),
|
|
78
|
+
}));
|
|
79
|
+
let redis;
|
|
80
|
+
const publisher = {
|
|
81
|
+
async publish(topic, payload) {
|
|
82
|
+
if (!redis) {
|
|
83
|
+
redis = new Redis(config.redis.url, {
|
|
84
|
+
lazyConnect: true,
|
|
85
|
+
enableOfflineQueue: false,
|
|
86
|
+
maxRetriesPerRequest: 0,
|
|
87
|
+
connectTimeout: CLI_REDIS_CONNECT_TIMEOUT_MS,
|
|
88
|
+
retryStrategy: () => null,
|
|
89
|
+
});
|
|
90
|
+
redis.on("error", () => { });
|
|
91
|
+
}
|
|
92
|
+
if (redis.status !== "ready")
|
|
93
|
+
await redis.connect();
|
|
94
|
+
// 与内核 bus 同一个频道命名(cap:kernel:<topic>);CLI 只发布,不订阅
|
|
95
|
+
const bus = createBus(redis, {
|
|
96
|
+
subscribe: () => Promise.reject(new Error("the CLI does not subscribe")),
|
|
97
|
+
}, "kernel", log);
|
|
98
|
+
await bus.publish(topic, payload);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
const installs = new ExtensionInstalls({
|
|
102
|
+
db,
|
|
103
|
+
blobs: stored,
|
|
104
|
+
config: () => config,
|
|
105
|
+
declared: () => declared,
|
|
106
|
+
});
|
|
107
|
+
const admin = new ExtensionAdmin({
|
|
108
|
+
db,
|
|
109
|
+
blobs,
|
|
110
|
+
installs,
|
|
111
|
+
config: () => config,
|
|
112
|
+
host: { declaredPlugins: () => declaredInfo },
|
|
113
|
+
bus: publisher,
|
|
114
|
+
log,
|
|
115
|
+
});
|
|
116
|
+
const ops = new ExtensionAdminOps({
|
|
117
|
+
db,
|
|
118
|
+
view: (name) => admin.get(name, { allowUnreadable: true }),
|
|
119
|
+
declared: () => declared,
|
|
120
|
+
blobs,
|
|
121
|
+
config: () => config,
|
|
122
|
+
bus: publisher,
|
|
123
|
+
log,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
config,
|
|
127
|
+
db,
|
|
128
|
+
inspected,
|
|
129
|
+
configIssues,
|
|
130
|
+
deploymentConfigs,
|
|
131
|
+
deploymentConfigOf,
|
|
132
|
+
installs,
|
|
133
|
+
admin,
|
|
134
|
+
ops,
|
|
135
|
+
approvals: new ExtensionApprovals(db),
|
|
136
|
+
remember: (sha256, bytes) => {
|
|
137
|
+
local.set(sha256, bytes);
|
|
138
|
+
},
|
|
139
|
+
readPackage: (sha256) => blobs.get(sha256),
|
|
140
|
+
async packageSet(sha256) {
|
|
141
|
+
// a stored package in the pre-0.1.0 format -> extension.legacy_format
|
|
142
|
+
const pkg = await readExtensionPackage(await blobs.get(sha256), {
|
|
143
|
+
maxBytes: config.packages.maxBytes,
|
|
144
|
+
hostSdkVersion: SDK_VERSION,
|
|
145
|
+
}).catch((e) => {
|
|
146
|
+
throw e instanceof ExtensionPackageError ? extensionPackageApiError(e) : e;
|
|
147
|
+
});
|
|
148
|
+
return permissionSetOfPackage(pkg);
|
|
149
|
+
},
|
|
150
|
+
async publishChanged(plugin) {
|
|
151
|
+
try {
|
|
152
|
+
await publisher.publish(PLUGINS_CHANGED_TOPIC, { plugin });
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
log.warn("cannot publish plugins.changed; running replicas pick the change up on their next periodic reconcile", { plugin, err });
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
async close() {
|
|
161
|
+
redis?.disconnect();
|
|
162
|
+
await raw.destroy().catch(() => { });
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export type JsonSchema = Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* 把插件配置 schema 转成 JSON Schema(供界面渲染表单):
|
|
5
|
+
* - `secret()` 字段带 `"x-secret": true`(去掉 zod 附带的 `secret` 元数据键);
|
|
6
|
+
* - 无法表达的类型为 `{ "x-unsupported": true }`,不抛错;
|
|
7
|
+
* - 以输入侧形态输出(含 default),不带 `$schema`。
|
|
8
|
+
*/
|
|
9
|
+
export declare function configToJsonSchema(schema: z.ZodType): JsonSchema;
|