@capybara-hq/kernel 0.1.0-rc.1 → 0.1.0-rc.11
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/bootstrap.json +85 -5
- package/dist/admin/admin.controller.d.ts +52 -71
- package/dist/admin/admin.controller.js +117 -63
- package/dist/admin/admin.module.d.ts +3 -0
- package/dist/admin/admin.module.js +22 -0
- package/dist/admin/admin.schemas.d.ts +60 -0
- package/dist/admin/admin.schemas.js +50 -0
- package/dist/admin/extensions.controller.d.ts +47 -16
- package/dist/admin/extensions.controller.js +94 -23
- package/dist/admin/extensions.schemas.d.ts +7 -0
- package/dist/admin/extensions.schemas.js +10 -0
- package/dist/admin/limit-defaults.d.ts +20 -0
- package/dist/admin/limit-defaults.js +10 -0
- package/dist/admin/setup-lock.d.ts +16 -0
- package/dist/admin/setup-lock.js +47 -0
- package/dist/admin/setup.controller.d.ts +9 -9
- package/dist/admin/setup.controller.js +28 -26
- package/dist/admin/setup.service.d.ts +20 -28
- package/dist/admin/setup.service.js +65 -65
- package/dist/agents/agent-lookup.d.ts +72 -0
- package/dist/agents/agent-lookup.js +208 -0
- package/dist/agents/agent-profile.service.d.ts +31 -0
- package/dist/agents/agent-profile.service.js +122 -0
- package/dist/agents/agents.controller.d.ts +54 -169
- package/dist/agents/agents.controller.js +172 -37
- package/dist/agents/agents.module.d.ts +10 -0
- package/dist/agents/agents.module.js +71 -0
- package/dist/agents/agents.schemas.d.ts +389 -0
- package/dist/agents/agents.schemas.js +126 -0
- package/dist/agents/agents.service.d.ts +104 -76
- package/dist/agents/agents.service.js +509 -383
- package/dist/agents/definition.d.ts +133 -21
- package/dist/agents/definition.js +361 -41
- package/dist/agents/from-template.d.ts +106 -0
- package/dist/agents/from-template.js +680 -0
- package/dist/agents/from-template.service.d.ts +72 -0
- package/dist/agents/from-template.service.js +178 -0
- package/dist/agents/instruction-files.d.ts +60 -0
- package/dist/agents/instruction-files.js +111 -0
- package/dist/agents/models.controller.d.ts +44 -6
- package/dist/agents/models.controller.js +84 -8
- package/dist/agents/org-templates.d.ts +186 -0
- package/dist/agents/org-templates.js +868 -0
- package/dist/agents/pending-connector-requests.d.ts +79 -0
- package/dist/agents/pending-connector-requests.js +215 -0
- package/dist/agents/pending-connectors.controller.d.ts +39 -0
- package/dist/agents/pending-connectors.controller.js +91 -0
- package/dist/agents/pending-connectors.service.d.ts +62 -0
- package/dist/agents/pending-connectors.service.js +282 -0
- package/dist/agents/profile.d.ts +114 -0
- package/dist/agents/profile.js +55 -0
- package/dist/agents/readiness.controller.d.ts +26 -0
- package/dist/agents/readiness.controller.js +56 -0
- package/dist/agents/templates.controller.d.ts +78 -6
- package/dist/agents/templates.controller.js +154 -8
- package/dist/agents/templates.d.ts +132 -30
- package/dist/agents/templates.js +500 -46
- package/dist/agents/templates.schemas.d.ts +20 -0
- package/dist/agents/templates.schemas.js +45 -0
- package/dist/app.d.ts +93 -0
- package/dist/app.js +150 -0
- package/dist/background/background.controller.d.ts +38 -0
- package/dist/background/background.controller.js +88 -0
- package/dist/background/background.module.d.ts +10 -0
- package/dist/background/background.module.js +39 -0
- package/dist/background/background.schemas.d.ts +10 -0
- package/dist/background/background.schemas.js +16 -0
- package/dist/background/finish.d.ts +44 -0
- package/dist/background/finish.js +95 -0
- package/dist/background/launch-lock.d.ts +15 -0
- package/dist/background/launch-lock.js +40 -0
- package/dist/background/launch.d.ts +42 -0
- package/dist/background/launch.js +77 -0
- package/dist/background/poll.job.d.ts +56 -0
- package/dist/background/poll.job.js +195 -0
- package/dist/background/render.d.ts +23 -0
- package/dist/background/render.js +48 -0
- package/dist/background/session.d.ts +48 -0
- package/dist/background/session.js +80 -0
- package/dist/background/status.d.ts +35 -0
- package/dist/background/status.js +57 -0
- package/dist/background/stop.d.ts +68 -0
- package/dist/background/stop.js +244 -0
- package/dist/background/store.d.ts +167 -0
- package/dist/background/store.js +361 -0
- package/dist/background/store.module.d.ts +6 -0
- package/dist/background/store.module.js +22 -0
- package/dist/background/tasks.service.d.ts +77 -0
- package/dist/background/tasks.service.js +216 -0
- package/dist/background/wake-rules.d.ts +66 -0
- package/dist/background/wake-rules.js +113 -0
- package/dist/background/wake.d.ts +30 -0
- package/dist/background/wake.js +63 -0
- package/dist/catalog/admin-catalog.controller.d.ts +102 -52
- package/dist/catalog/admin-catalog.controller.js +222 -67
- package/dist/catalog/admin-catalog.schemas.d.ts +72 -0
- package/dist/catalog/admin-catalog.schemas.js +92 -0
- package/dist/catalog/catalog-content.d.ts +264 -0
- package/dist/catalog/catalog-content.js +430 -0
- package/dist/catalog/catalog-files.d.ts +41 -0
- package/dist/catalog/catalog-files.js +86 -0
- package/dist/catalog/catalog-import.module.d.ts +7 -0
- package/dist/catalog/catalog-import.module.js +60 -0
- package/dist/catalog/catalog-items.d.ts +290 -0
- package/dist/catalog/catalog-items.js +677 -0
- package/dist/catalog/catalog-scope.service.d.ts +286 -0
- package/dist/catalog/catalog-scope.service.js +1196 -0
- package/dist/catalog/catalog.module.d.ts +12 -0
- package/dist/catalog/catalog.module.js +81 -0
- package/dist/catalog/catalog.service.d.ts +144 -207
- package/dist/catalog/catalog.service.js +258 -528
- package/dist/catalog/claude/agents.js +15 -10
- package/dist/catalog/claude/translate.js +3 -0
- package/dist/catalog/cli.d.ts +14 -3
- package/dist/catalog/cli.js +39 -32
- package/dist/catalog/component-promotion.d.ts +96 -0
- package/dist/catalog/component-promotion.js +395 -0
- package/dist/catalog/component-scope.controller.d.ts +90 -0
- package/dist/catalog/component-scope.controller.js +234 -0
- package/dist/catalog/component-scope.schemas.d.ts +118 -0
- package/dist/catalog/component-scope.schemas.js +97 -0
- package/dist/catalog/component-scope.service.d.ts +366 -0
- package/dist/catalog/component-scope.service.js +1115 -0
- package/dist/catalog/component-state.d.ts +197 -0
- package/dist/catalog/component-state.js +473 -0
- package/dist/catalog/git-source.d.ts +9 -1
- package/dist/catalog/git-source.js +29 -2
- package/dist/catalog/job-ids.d.ts +45 -0
- package/dist/catalog/job-ids.js +40 -0
- package/dist/catalog/jobs.d.ts +27 -0
- package/dist/catalog/jobs.js +70 -0
- package/dist/catalog/locks.d.ts +24 -0
- package/dist/catalog/locks.js +63 -0
- package/dist/catalog/marketplace-fetch.d.ts +1 -1
- package/dist/catalog/marketplace-icons.d.ts +64 -0
- package/dist/catalog/marketplace-icons.js +131 -0
- package/dist/catalog/marketplaces.controller.d.ts +53 -44
- package/dist/catalog/marketplaces.controller.js +146 -51
- package/dist/catalog/marketplaces.schemas.d.ts +48 -0
- package/dist/catalog/marketplaces.schemas.js +53 -0
- package/dist/catalog/marketplaces.service.d.ts +136 -26
- package/dist/catalog/marketplaces.service.js +663 -281
- package/dist/catalog/org-catalog.controller.d.ts +115 -63
- package/dist/catalog/org-catalog.controller.js +207 -100
- package/dist/catalog/org-catalog.schemas.d.ts +88 -0
- package/dist/catalog/org-catalog.schemas.js +93 -0
- package/dist/catalog/org-catalog.service.d.ts +89 -216
- package/dist/catalog/org-catalog.service.js +434 -472
- package/dist/catalog/org-extension-switch.d.ts +41 -0
- package/dist/catalog/org-extension-switch.js +115 -0
- package/dist/catalog/org-extension.controller.d.ts +113 -0
- package/dist/catalog/org-extension.controller.js +271 -0
- package/dist/catalog/org-extension.schemas.d.ts +15 -0
- package/dist/catalog/org-extension.schemas.js +22 -0
- package/dist/catalog/org-plugin-uploads.controller.d.ts +77 -0
- package/dist/catalog/org-plugin-uploads.controller.js +200 -0
- package/dist/catalog/org-plugin-uploads.d.ts +71 -0
- package/dist/catalog/org-plugin-uploads.js +122 -0
- package/dist/catalog/org-plugin-uploads.schemas.d.ts +20 -0
- package/dist/catalog/org-plugin-uploads.schemas.js +32 -0
- package/dist/catalog/owned-items.d.ts +188 -0
- package/dist/catalog/owned-items.js +808 -0
- package/dist/catalog/owned-plugin-cleanup.d.ts +56 -0
- package/dist/catalog/owned-plugin-cleanup.js +194 -0
- package/dist/catalog/ownership.d.ts +172 -0
- package/dist/catalog/ownership.js +326 -0
- package/dist/catalog/platform-components.d.ts +243 -0
- package/dist/catalog/platform-components.js +872 -0
- package/dist/catalog/platform-migration.d.ts +115 -0
- package/dist/catalog/platform-migration.js +583 -0
- package/dist/catalog/plugin-import.d.ts +293 -71
- package/dist/catalog/plugin-import.js +1039 -281
- package/dist/catalog/plugin-install.d.ts +271 -66
- package/dist/catalog/plugin-install.js +1198 -344
- package/dist/catalog/plugin-package.d.ts +41 -4
- package/dist/catalog/plugin-package.js +140 -7
- package/dist/catalog/plugin-upgrade.d.ts +312 -188
- package/dist/catalog/plugin-upgrade.js +1371 -1065
- package/dist/catalog/request-rules.d.ts +65 -0
- package/dist/catalog/request-rules.js +217 -0
- package/dist/catalog/requests.service.d.ts +205 -117
- package/dist/catalog/requests.service.js +612 -369
- package/dist/catalog/reserved-names.d.ts +8 -0
- package/dist/catalog/reserved-names.js +42 -0
- package/dist/catalog/scope-orgs.d.ts +21 -0
- package/dist/catalog/scope-orgs.js +67 -0
- package/dist/catalog/scope-state.d.ts +35 -0
- package/dist/catalog/scope-state.js +87 -0
- package/dist/catalog/scope-sync-workers.d.ts +7 -0
- package/dist/catalog/scope-sync-workers.js +29 -0
- package/dist/catalog/scope-sync.d.ts +176 -0
- package/dist/catalog/scope-sync.js +576 -0
- package/dist/catalog/scope.d.ts +42 -0
- package/dist/catalog/scope.js +42 -0
- package/dist/catalog/unshare.d.ts +22 -0
- package/dist/catalog/unshare.js +119 -0
- package/dist/channels/actions.d.ts +6 -4
- package/dist/channels/actions.js +11 -4
- package/dist/channels/cards.d.ts +33 -11
- package/dist/channels/cards.js +96 -24
- package/dist/channels/channels.module.d.ts +40 -0
- package/dist/channels/channels.module.js +130 -0
- package/dist/channels/channels.schemas.d.ts +37 -0
- package/dist/channels/channels.schemas.js +38 -0
- package/dist/channels/connections.controller.d.ts +44 -37
- package/dist/channels/connections.controller.js +83 -38
- package/dist/channels/connections.service.d.ts +101 -30
- package/dist/channels/connections.service.js +380 -147
- package/dist/channels/inbound.d.ts +44 -38
- package/dist/channels/inbound.js +190 -44
- package/dist/channels/job-ids.d.ts +10 -0
- package/dist/channels/job-ids.js +10 -0
- package/dist/channels/jobs.d.ts +85 -0
- package/dist/channels/jobs.js +157 -0
- package/dist/channels/outbound.d.ts +71 -80
- package/dist/channels/outbound.js +219 -202
- package/dist/channels/phrases.d.ts +33 -2
- package/dist/channels/phrases.js +29 -1
- package/dist/channels/supervisor.d.ts +88 -46
- package/dist/channels/supervisor.js +230 -132
- package/dist/channels/threads.d.ts +34 -8
- package/dist/channels/threads.js +79 -13
- package/dist/channels/webhook.d.ts +20 -14
- package/dist/channels/webhook.js +51 -20
- package/dist/config/docs.js +5 -1
- package/dist/config/load.d.ts +3 -2
- package/dist/config/load.js +3 -2
- package/dist/config/nacos-source.js +11 -2
- package/dist/config/schema.d.ts +36 -2
- package/dist/config/schema.js +226 -25
- package/dist/conversations/access.d.ts +31 -0
- package/dist/conversations/access.js +110 -0
- package/dist/conversations/agent-tree.d.ts +46 -0
- package/dist/conversations/agent-tree.js +92 -0
- package/dist/conversations/artifacts.d.ts +11 -11
- package/dist/conversations/artifacts.js +36 -10
- package/dist/conversations/attachments.controller.d.ts +1 -1
- package/dist/conversations/attachments.controller.js +8 -6
- package/dist/conversations/attachments.module.d.ts +7 -0
- package/dist/conversations/attachments.module.js +25 -0
- package/dist/conversations/attachments.service.d.ts +60 -22
- package/dist/conversations/attachments.service.js +249 -51
- package/dist/conversations/conversations.controller.d.ts +86 -50
- package/dist/conversations/conversations.controller.js +184 -103
- package/dist/conversations/conversations.module.d.ts +8 -0
- package/dist/conversations/conversations.module.js +72 -0
- package/dist/conversations/conversations.schemas.d.ts +52 -0
- package/dist/conversations/conversations.schemas.js +79 -0
- package/dist/conversations/conversations.service.d.ts +166 -49
- package/dist/conversations/conversations.service.js +383 -179
- package/dist/conversations/environment-status.d.ts +24 -0
- package/dist/conversations/environment-status.js +71 -0
- package/dist/conversations/event-log.d.ts +64 -27
- package/dist/conversations/event-log.js +167 -31
- package/dist/conversations/events.d.ts +252 -9
- package/dist/conversations/events.js +243 -32
- package/dist/conversations/files.d.ts +10 -10
- package/dist/conversations/files.js +37 -11
- package/dist/conversations/idem-keys.d.ts +5 -0
- package/dist/conversations/idem-keys.js +5 -0
- package/dist/conversations/job-ids.d.ts +6 -0
- package/dist/conversations/job-ids.js +6 -0
- package/dist/conversations/message-context.d.ts +79 -0
- package/dist/conversations/message-context.js +145 -0
- package/dist/conversations/outputs-read.d.ts +11 -11
- package/dist/conversations/outputs-read.js +31 -7
- package/dist/conversations/queue.d.ts +53 -58
- package/dist/conversations/queue.js +37 -293
- package/dist/conversations/queue.service.d.ts +60 -0
- package/dist/conversations/queue.service.js +350 -0
- package/dist/conversations/titles.d.ts +83 -27
- package/dist/conversations/titles.js +195 -71
- package/dist/conversations/tree.d.ts +17 -0
- package/dist/conversations/tree.js +42 -0
- package/dist/ctx/bus.js +9 -3
- package/dist/ctx/create-ctx.d.ts +26 -1
- package/dist/ctx/create-ctx.js +45 -16
- package/dist/ctx/lock.d.ts +7 -3
- package/dist/ctx/lock.js +9 -20
- package/dist/ctx/secrets.d.ts +10 -2
- package/dist/ctx/secrets.js +7 -3
- package/dist/db/kernel-schema.d.ts +589 -27
- package/dist/db/pool.d.ts +10 -0
- package/dist/db/pool.js +4 -0
- package/dist/devices/device-auth.controller.d.ts +42 -0
- package/dist/devices/device-auth.controller.js +116 -0
- package/dist/devices/device-auth.d.ts +119 -0
- package/dist/devices/device-auth.js +403 -0
- package/dist/devices/device-auth.module.d.ts +7 -0
- package/dist/devices/device-auth.module.js +25 -0
- package/dist/devices/device-gateway.d.ts +128 -0
- package/dist/devices/device-gateway.js +530 -0
- package/dist/devices/device-provider.d.ts +89 -0
- package/dist/devices/device-provider.js +151 -0
- package/dist/devices/device-routes.d.ts +36 -0
- package/dist/devices/device-routes.js +90 -0
- package/dist/devices/devices.module.d.ts +16 -0
- package/dist/devices/devices.module.js +44 -0
- package/dist/devices/dto.d.ts +66 -0
- package/dist/devices/dto.js +44 -0
- package/dist/devices/keys.d.ts +25 -0
- package/dist/devices/keys.js +25 -0
- package/dist/devices/machines.d.ts +118 -0
- package/dist/devices/machines.js +366 -0
- package/dist/devices/relay.d.ts +100 -0
- package/dist/devices/relay.js +373 -0
- package/dist/devices/targets.d.ts +28 -0
- package/dist/devices/targets.js +73 -0
- package/dist/environments/access.d.ts +66 -0
- package/dist/environments/access.js +113 -0
- package/dist/environments/conversation-environments.d.ts +75 -0
- package/dist/environments/conversation-environments.js +231 -0
- package/dist/environments/dto.d.ts +25 -0
- package/dist/environments/dto.js +12 -0
- package/dist/environments/environments.controller.d.ts +36 -0
- package/dist/environments/environments.controller.js +124 -0
- package/dist/environments/environments.module.d.ts +8 -0
- package/dist/environments/environments.module.js +31 -0
- package/dist/environments/environments.schemas.d.ts +3 -0
- package/dist/environments/environments.schemas.js +14 -0
- package/dist/environments/environments.service.d.ts +251 -0
- package/dist/environments/environments.service.js +791 -0
- package/dist/environments/label.d.ts +11 -0
- package/dist/environments/label.js +25 -0
- package/dist/environments/legacy-cleanup.job.d.ts +34 -0
- package/dist/environments/legacy-cleanup.job.js +141 -0
- package/dist/errors.d.ts +160 -2
- package/dist/errors.js +160 -2
- package/dist/evals/budget.d.ts +42 -21
- package/dist/evals/budget.js +114 -62
- package/dist/evals/evals.module.d.ts +31 -0
- package/dist/evals/evals.module.js +114 -0
- package/dist/evals/evals.schemas.d.ts +110 -0
- package/dist/evals/evals.schemas.js +107 -0
- package/dist/evals/jobs.d.ts +20 -0
- package/dist/evals/jobs.js +45 -0
- package/dist/evals/reconstruct.d.ts +18 -9
- package/dist/evals/reconstruct.js +36 -10
- package/dist/evals/recorded-tools.d.ts +37 -1
- package/dist/evals/recorded-tools.js +120 -10
- package/dist/evals/run-replay.d.ts +75 -10
- package/dist/evals/run-replay.js +218 -94
- package/dist/evals/runs.controller.d.ts +3 -58
- package/dist/evals/runs.controller.js +18 -50
- package/dist/evals/runs.service.d.ts +31 -52
- package/dist/evals/runs.service.js +281 -255
- package/dist/evals/sets.controller.d.ts +3 -29
- package/dist/evals/sets.controller.js +18 -39
- package/dist/evals/sets.service.d.ts +29 -13
- package/dist/evals/sets.service.js +262 -202
- package/dist/evals/snapshot.d.ts +5 -4
- package/dist/evals/snapshot.js +17 -4
- package/dist/evals/step-replay.d.ts +6 -8
- package/dist/evals/step-replay.js +17 -10
- package/dist/evals/trajectory.controller.d.ts +1 -1
- package/dist/evals/trajectory.controller.js +11 -7
- package/dist/evals/trajectory.d.ts +2 -2
- package/dist/evals/trajectory.js +1 -1
- package/dist/evals/trajectory.service.d.ts +13 -7
- package/dist/evals/trajectory.service.js +56 -21
- package/dist/evals/worker.d.ts +48 -31
- package/dist/evals/worker.js +229 -124
- package/dist/extensions/admin-ops.d.ts +133 -41
- package/dist/extensions/admin-ops.js +378 -172
- package/dist/extensions/admin-view.d.ts +82 -32
- package/dist/extensions/admin-view.js +284 -71
- package/dist/extensions/approvals.d.ts +24 -10
- package/dist/extensions/approvals.js +73 -46
- package/dist/extensions/blobs.d.ts +27 -10
- package/dist/extensions/blobs.js +112 -45
- package/dist/extensions/bootstrap.d.ts +99 -36
- package/dist/extensions/bootstrap.js +290 -134
- package/dist/extensions/cli.d.ts +32 -10
- package/dist/extensions/cli.js +52 -98
- package/dist/extensions/config-hash.d.ts +10 -0
- package/dist/extensions/config-hash.js +38 -0
- package/dist/extensions/config-issues.d.ts +19 -0
- package/dist/extensions/config-issues.js +48 -0
- package/dist/extensions/config-json-schema.d.ts +43 -7
- package/dist/extensions/config-json-schema.js +124 -58
- package/dist/extensions/deployment-config-store.d.ts +55 -0
- package/dist/extensions/deployment-config-store.js +133 -0
- package/dist/extensions/deployment-config.d.ts +146 -70
- package/dist/extensions/deployment-config.js +439 -246
- package/dist/extensions/display-name.d.ts +22 -0
- package/dist/extensions/display-name.js +77 -0
- package/dist/extensions/effective-config.d.ts +127 -0
- package/dist/extensions/effective-config.js +368 -0
- package/dist/extensions/enabled.d.ts +5 -5
- package/dist/extensions/extensions.module.d.ts +8 -0
- package/dist/extensions/extensions.module.js +96 -0
- package/dist/extensions/hooks.d.ts +40 -6
- package/dist/extensions/hooks.js +83 -17
- package/dist/extensions/host.d.ts +161 -80
- package/dist/extensions/host.js +505 -213
- package/dist/extensions/installs.d.ts +73 -19
- package/dist/extensions/installs.js +174 -37
- package/dist/extensions/job-ids.d.ts +6 -0
- package/dist/extensions/job-ids.js +6 -0
- package/dist/extensions/lifecycle-topics.d.ts +18 -0
- package/dist/extensions/lifecycle-topics.js +18 -0
- package/dist/extensions/lifecycle.d.ts +35 -47
- package/dist/extensions/lifecycle.js +103 -39
- package/dist/extensions/locks.d.ts +45 -0
- package/dist/extensions/locks.js +112 -0
- package/dist/extensions/migrate-lock.d.ts +3 -4
- package/dist/extensions/org-config.d.ts +141 -49
- package/dist/extensions/org-config.js +471 -243
- package/dist/extensions/org-levels.d.ts +37 -0
- package/dist/extensions/org-levels.js +71 -0
- package/dist/extensions/org-overrides.d.ts +151 -0
- package/dist/extensions/org-overrides.js +524 -0
- package/dist/extensions/package.d.ts +14 -1
- package/dist/extensions/package.js +51 -2
- package/dist/extensions/permission-view.d.ts +59 -6
- package/dist/extensions/permission-view.js +7 -5
- package/dist/extensions/plugin-guides.d.ts +129 -0
- package/dist/extensions/plugin-guides.js +283 -0
- package/dist/extensions/plugin-icons.d.ts +54 -0
- package/dist/extensions/plugin-icons.js +125 -0
- package/dist/extensions/plugin-items.d.ts +21 -0
- package/dist/extensions/plugin-items.js +42 -0
- package/dist/extensions/point-defaults.controller.d.ts +28 -0
- package/dist/extensions/point-defaults.controller.js +69 -0
- package/dist/extensions/point-defaults.d.ts +73 -0
- package/dist/extensions/point-defaults.js +236 -0
- package/dist/extensions/point-defaults.schemas.d.ts +9 -0
- package/dist/extensions/point-defaults.schemas.js +14 -0
- package/dist/extensions/registry.d.ts +50 -2
- package/dist/extensions/registry.js +91 -4
- package/dist/extensions/resolve.d.ts +51 -1
- package/dist/extensions/resolve.js +85 -3
- package/dist/extensions/single-provider.d.ts +92 -0
- package/dist/extensions/single-provider.js +180 -0
- package/dist/extensions/sources.d.ts +19 -10
- package/dist/extensions/sources.js +34 -13
- package/dist/extensions/state.module.d.ts +9 -0
- package/dist/extensions/state.module.js +38 -0
- package/dist/extensions/unavailable.d.ts +50 -0
- package/dist/extensions/unavailable.js +115 -0
- package/dist/files/files.module.d.ts +3 -0
- package/dist/files/files.module.js +22 -0
- package/dist/files/previewers.controller.d.ts +7 -2
- package/dist/files/previewers.controller.js +19 -12
- package/dist/files/previewers.d.ts +21 -19
- package/dist/files/previewers.js +114 -38
- package/dist/files/previewers.schemas.d.ts +10 -0
- package/dist/files/previewers.schemas.js +9 -0
- package/dist/http/adapter.d.ts +3 -0
- package/dist/http/adapter.js +25 -0
- package/dist/http/api.module.d.ts +3 -110
- package/dist/http/api.module.js +93 -358
- package/dist/http/app.d.ts +22 -17
- package/dist/http/app.js +46 -65
- package/dist/http/error-filter.module.d.ts +5 -0
- package/dist/http/error-filter.module.js +18 -0
- package/dist/http/error.filter.js +2 -2
- package/dist/http/{gateway.module.d.ts → gateway-routes.d.ts} +7 -3
- package/dist/http/gateway-routes.js +16 -0
- package/dist/http/nest-logger.d.ts +6 -5
- package/dist/http/nest-logger.js +24 -10
- package/dist/http/plugin-dispatch.d.ts +4 -1
- package/dist/http/plugin-dispatch.js +14 -2
- package/dist/identity/accounts.d.ts +137 -38
- package/dist/identity/accounts.js +386 -186
- package/dist/identity/api-tokens.d.ts +11 -7
- package/dist/identity/api-tokens.js +71 -44
- package/dist/identity/audit.d.ts +9 -5
- package/dist/identity/audit.js +5 -1
- package/dist/identity/auth.controller.d.ts +11 -10
- package/dist/identity/auth.controller.js +40 -30
- package/dist/identity/auth.guard.d.ts +16 -8
- package/dist/identity/auth.guard.js +41 -13
- package/dist/identity/binding.d.ts +9 -11
- package/dist/identity/binding.js +41 -13
- package/dist/identity/cookies.d.ts +26 -5
- package/dist/identity/cookies.js +58 -6
- package/dist/identity/external-identity-lock.d.ts +17 -0
- package/dist/identity/external-identity-lock.js +39 -0
- package/dist/identity/external.d.ts +19 -15
- package/dist/identity/external.js +163 -125
- package/dist/identity/identity.module.d.ts +6 -0
- package/dist/identity/identity.module.js +59 -0
- package/dist/identity/initial-passwords.controller.d.ts +22 -0
- package/dist/identity/initial-passwords.controller.js +49 -0
- package/dist/identity/initial-passwords.d.ts +61 -0
- package/dist/identity/initial-passwords.job.d.ts +16 -0
- package/dist/identity/initial-passwords.job.js +46 -0
- package/dist/identity/initial-passwords.js +159 -0
- package/dist/identity/me.controller.d.ts +32 -15
- package/dist/identity/me.controller.js +80 -33
- package/dist/identity/me.schemas.d.ts +24 -0
- package/dist/identity/me.schemas.js +25 -0
- package/dist/identity/principal.d.ts +11 -3
- package/dist/identity/principal.js +11 -3
- package/dist/identity/sessions.d.ts +24 -10
- package/dist/identity/sessions.js +119 -42
- package/dist/identity/settings.d.ts +69 -23
- package/dist/identity/settings.js +201 -72
- package/dist/identity/sso.controller.d.ts +7 -7
- package/dist/identity/sso.controller.js +13 -9
- package/dist/identity/sso.d.ts +9 -12
- package/dist/identity/sso.js +54 -24
- package/dist/identity/super-admin.d.ts +20 -0
- package/dist/identity/super-admin.js +81 -0
- package/dist/inbox/inbox.module.d.ts +6 -0
- package/dist/inbox/inbox.module.js +26 -0
- package/dist/inbox/inbox.schemas.d.ts +8 -0
- package/dist/inbox/inbox.schemas.js +11 -0
- package/dist/inbox/inbox.service.d.ts +68 -11
- package/dist/inbox/inbox.service.js +104 -13
- package/dist/inbox/org-notices.d.ts +63 -0
- package/dist/inbox/org-notices.js +91 -0
- package/dist/inbox/platform-inbox.controller.d.ts +23 -0
- package/dist/inbox/platform-inbox.controller.js +58 -0
- package/dist/inbox/platform-inbox.service.d.ts +151 -0
- package/dist/inbox/platform-inbox.service.js +263 -0
- package/dist/inbox/platform-notices.d.ts +19 -0
- package/dist/inbox/platform-notices.js +9 -0
- package/dist/index.d.ts +22 -13
- package/dist/index.js +16 -7
- package/dist/infra/cache/cache.module.d.ts +3 -0
- package/dist/infra/cache/cache.module.js +16 -0
- package/dist/infra/cache/cache.service.d.ts +21 -0
- package/dist/infra/cache/cache.service.js +80 -0
- package/dist/infra/cache/cacheable.decorator.d.ts +32 -0
- package/dist/infra/cache/cacheable.decorator.js +83 -0
- package/dist/infra/cli/kernel-cli.module.d.ts +66 -0
- package/dist/infra/cli/kernel-cli.module.js +173 -0
- package/dist/infra/close-within.d.ts +15 -0
- package/dist/infra/close-within.js +36 -0
- package/dist/infra/config/config.module.d.ts +13 -0
- package/dist/infra/config/config.module.js +39 -0
- package/dist/infra/config/kernel-config.service.d.ts +25 -0
- package/dist/infra/config/kernel-config.service.js +157 -0
- package/dist/infra/database/after-commit.d.ts +6 -0
- package/dist/infra/database/after-commit.js +9 -0
- package/dist/infra/database/database.module.d.ts +25 -0
- package/dist/infra/database/database.module.js +91 -0
- package/dist/infra/database/kernel-db.d.ts +22 -0
- package/dist/infra/database/kernel-db.js +65 -0
- package/dist/infra/database/transaction-host.d.ts +50 -0
- package/dist/infra/database/transaction-host.js +125 -0
- package/dist/infra/database/transactional.decorator.d.ts +15 -0
- package/dist/infra/database/transactional.decorator.js +27 -0
- package/dist/infra/database/xact-lock.d.ts +17 -0
- package/dist/infra/database/xact-lock.js +43 -0
- package/dist/infra/events/kernel-events.d.ts +121 -0
- package/dist/infra/events/kernel-events.js +65 -0
- package/dist/infra/health/health.controller.d.ts +26 -0
- package/dist/infra/health/health.controller.js +104 -0
- package/dist/infra/health/health.module.d.ts +9 -0
- package/dist/infra/health/health.module.js +24 -0
- package/dist/infra/health/health.options.d.ts +10 -0
- package/dist/infra/health/health.options.js +15 -0
- package/dist/infra/health/shutdown-state.d.ts +6 -0
- package/dist/infra/health/shutdown-state.js +2 -0
- package/dist/infra/lifecycle/graceful-shutdown.module.d.ts +6 -0
- package/dist/infra/lifecycle/graceful-shutdown.module.js +23 -0
- package/dist/infra/lifecycle/graceful-shutdown.service.d.ts +70 -0
- package/dist/infra/lifecycle/graceful-shutdown.service.js +135 -0
- package/dist/infra/lifecycle/process-guards.d.ts +52 -0
- package/dist/infra/lifecycle/process-guards.js +90 -0
- package/dist/infra/lifecycle/shutdown-signals.d.ts +30 -0
- package/dist/infra/lifecycle/shutdown-signals.js +48 -0
- package/dist/infra/lock/key-template.d.ts +13 -0
- package/dist/infra/lock/key-template.js +46 -0
- package/dist/infra/lock/lock.module.d.ts +3 -0
- package/dist/infra/lock/lock.module.js +16 -0
- package/dist/infra/lock/lock.service.d.ts +120 -0
- package/dist/infra/lock/lock.service.js +343 -0
- package/dist/infra/lock/shared-lease.d.ts +44 -0
- package/dist/infra/lock/shared-lease.js +121 -0
- package/dist/infra/lock/with-lock.decorator.d.ts +28 -0
- package/dist/infra/lock/with-lock.decorator.js +49 -0
- package/dist/infra/logging/logging.module.d.ts +18 -0
- package/dist/infra/logging/logging.module.js +52 -0
- package/dist/infra/queue/add-job-once.d.ts +14 -0
- package/dist/infra/queue/add-job-once.js +16 -0
- package/dist/infra/queue/configured-processor.d.ts +18 -0
- package/dist/infra/queue/configured-processor.js +23 -0
- package/dist/infra/queue/job-failure.d.ts +18 -0
- package/dist/infra/queue/job-failure.js +26 -0
- package/dist/infra/queue/queue-shutdown.d.ts +27 -0
- package/dist/infra/queue/queue-shutdown.js +81 -0
- package/dist/infra/queue/queue.module.d.ts +16 -0
- package/dist/infra/queue/queue.module.js +61 -0
- package/dist/infra/queue/redis-connection.d.ts +13 -0
- package/dist/infra/queue/redis-connection.js +25 -0
- package/dist/infra/queue/retired-schedulers.d.ts +7 -0
- package/dist/infra/queue/retired-schedulers.js +9 -0
- package/dist/infra/queue/run-job.d.ts +16 -0
- package/dist/infra/queue/run-job.js +19 -0
- package/dist/infra/redis/redis.module.d.ts +24 -0
- package/dist/infra/redis/redis.module.js +91 -0
- package/dist/infra/schedule/cron-tick.d.ts +12 -0
- package/dist/infra/schedule/cron-tick.js +25 -0
- package/dist/infra/schedule/locked-cron.decorator.d.ts +27 -0
- package/dist/infra/schedule/locked-cron.decorator.js +53 -0
- package/dist/infra/schedule/locked-interval.d.ts +69 -0
- package/dist/infra/schedule/locked-interval.js +190 -0
- package/dist/infra/schedule/locked-tick.d.ts +90 -0
- package/dist/infra/schedule/locked-tick.js +137 -0
- package/dist/infra/schedule/schedule.module.d.ts +8 -0
- package/dist/infra/schedule/schedule.module.js +27 -0
- package/dist/infra/schedule/scheduled-runs.d.ts +69 -0
- package/dist/infra/schedule/scheduled-runs.js +163 -0
- package/dist/infra/swagger/swagger.d.ts +16 -0
- package/dist/infra/swagger/swagger.js +31 -0
- package/dist/infra/throttler/credential-throttler.d.ts +35 -0
- package/dist/infra/throttler/credential-throttler.js +77 -0
- package/dist/infra/throttler/named-throttlers.d.ts +36 -0
- package/dist/infra/throttler/named-throttlers.js +157 -0
- package/dist/infra/throttler/redis-throttler-storage.d.ts +38 -0
- package/dist/infra/throttler/redis-throttler-storage.js +130 -0
- package/dist/infra/throttler/throttler.guard.d.ts +23 -0
- package/dist/infra/throttler/throttler.guard.js +68 -0
- package/dist/infra/throttler/throttler.module.d.ts +15 -0
- package/dist/infra/throttler/throttler.module.js +53 -0
- package/dist/infra/tokens.d.ts +20 -0
- package/dist/infra/tokens.js +20 -0
- package/dist/infra/validation/create-zod-dto.d.ts +23 -0
- package/dist/infra/validation/create-zod-dto.js +35 -0
- package/dist/infra/validation/parse-with-zod.d.ts +7 -0
- package/dist/infra/validation/parse-with-zod.js +12 -0
- package/dist/infra/validation/validation.module.d.ts +3 -0
- package/dist/infra/validation/validation.module.js +16 -0
- package/dist/infra/validation/zod-params.d.ts +7 -0
- package/dist/infra/validation/zod-params.js +42 -0
- package/dist/infra/validation/zod-validation.pipe.d.ts +11 -0
- package/dist/infra/validation/zod-validation.pipe.js +31 -0
- package/dist/kernel.d.ts +9 -244
- package/dist/kernel.js +8 -1305
- package/dist/kernel.module.d.ts +17 -0
- package/dist/kernel.module.js +145 -0
- package/dist/lifecycle/kernel-lifecycle.d.ts +140 -0
- package/dist/lifecycle/kernel-lifecycle.js +465 -0
- package/dist/lifecycle/tokens.d.ts +3 -0
- package/dist/lifecycle/tokens.js +3 -0
- package/dist/log-context.d.ts +2 -0
- package/dist/log-context.js +4 -0
- package/dist/log.d.ts +13 -1
- package/dist/log.js +93 -17
- package/dist/models/embeddings.d.ts +82 -0
- package/dist/models/embeddings.js +326 -0
- package/dist/models/enablement.controller.d.ts +40 -0
- package/dist/models/enablement.controller.js +74 -0
- package/dist/models/enablement.d.ts +101 -0
- package/dist/models/enablement.js +264 -0
- package/dist/models/models.module.d.ts +7 -0
- package/dist/models/models.module.js +36 -0
- package/dist/models/org-models.schemas.d.ts +8 -0
- package/dist/models/org-models.schemas.js +22 -0
- package/dist/models/prices.d.ts +13 -5
- package/dist/models/prices.js +69 -39
- package/dist/models/purposes.controller.d.ts +6 -4
- package/dist/models/purposes.controller.js +16 -11
- package/dist/models/purposes.d.ts +103 -23
- package/dist/models/purposes.js +208 -77
- package/dist/orgs/directory-sync.controller.d.ts +1 -1
- package/dist/orgs/directory-sync.controller.js +2 -2
- package/dist/orgs/directory-sync.d.ts +74 -35
- package/dist/orgs/directory-sync.js +243 -132
- package/dist/orgs/invitations.controller.d.ts +8 -8
- package/dist/orgs/invitations.controller.js +27 -26
- package/dist/orgs/invitations.service.d.ts +12 -9
- package/dist/orgs/invitations.service.js +130 -92
- package/dist/orgs/job-ids.d.ts +8 -0
- package/dist/orgs/job-ids.js +8 -0
- package/dist/orgs/members.service.d.ts +19 -12
- package/dist/orgs/members.service.js +161 -117
- package/dist/orgs/offboarding.d.ts +61 -60
- package/dist/orgs/offboarding.js +206 -95
- package/dist/orgs/org-lock.d.ts +33 -19
- package/dist/orgs/org-lock.js +94 -35
- package/dist/orgs/org.guard.d.ts +11 -1
- package/dist/orgs/org.guard.js +45 -34
- package/dist/orgs/orgs.controller.d.ts +13 -16
- package/dist/orgs/orgs.controller.js +29 -20
- package/dist/orgs/orgs.module.d.ts +6 -0
- package/dist/orgs/orgs.module.js +71 -0
- package/dist/orgs/orgs.schemas.d.ts +8 -0
- package/dist/orgs/orgs.schemas.js +16 -0
- package/dist/orgs/orgs.service.d.ts +47 -21
- package/dist/orgs/orgs.service.js +166 -91
- package/dist/orgs/roles.d.ts +1 -1
- package/dist/orgs/roles.js +5 -1
- package/dist/orgs/settings.controller.d.ts +2 -2
- package/dist/orgs/settings.controller.js +8 -6
- package/dist/orgs/settings.service.d.ts +76 -14
- package/dist/orgs/settings.service.js +140 -51
- package/dist/overrides.d.ts +63 -0
- package/dist/overrides.js +34 -0
- package/dist/platform/actor.d.ts +48 -0
- package/dist/platform/actor.js +100 -0
- package/dist/platform/agent-docs.d.ts +18 -0
- package/dist/platform/agent-docs.js +59 -0
- package/dist/platform/availability.d.ts +14 -0
- package/dist/platform/availability.js +43 -0
- package/dist/platform/errors.d.ts +28 -0
- package/dist/platform/errors.js +65 -0
- package/dist/platform/exclusions.d.ts +11 -0
- package/dist/platform/exclusions.js +683 -0
- package/dist/platform/method.d.ts +6 -0
- package/dist/platform/method.js +15 -0
- package/dist/platform/operation.d.ts +169 -0
- package/dist/platform/operation.js +94 -0
- package/dist/platform/ops/accounts.ops.d.ts +32 -0
- package/dist/platform/ops/accounts.ops.js +291 -0
- package/dist/platform/ops/admin.ops.d.ts +38 -0
- package/dist/platform/ops/admin.ops.js +407 -0
- package/dist/platform/ops/agent-skills.ops.d.ts +24 -0
- package/dist/platform/ops/agent-skills.ops.js +226 -0
- package/dist/platform/ops/agent-templates.ops.d.ts +17 -0
- package/dist/platform/ops/agent-templates.ops.js +272 -0
- package/dist/platform/ops/agents.ops.d.ts +37 -0
- package/dist/platform/ops/agents.ops.js +717 -0
- package/dist/platform/ops/approvals.ops.d.ts +30 -0
- package/dist/platform/ops/approvals.ops.js +116 -0
- package/dist/platform/ops/background.ops.d.ts +14 -0
- package/dist/platform/ops/background.ops.js +134 -0
- package/dist/platform/ops/catalog-admin.ops.d.ts +74 -0
- package/dist/platform/ops/catalog-admin.ops.js +599 -0
- package/dist/platform/ops/channels.ops.d.ts +16 -0
- package/dist/platform/ops/channels.ops.js +195 -0
- package/dist/platform/ops/components.ops.d.ts +46 -0
- package/dist/platform/ops/components.ops.js +854 -0
- package/dist/platform/ops/connectors.ops.d.ts +17 -0
- package/dist/platform/ops/connectors.ops.js +188 -0
- package/dist/platform/ops/conversations.ops.d.ts +30 -0
- package/dist/platform/ops/conversations.ops.js +470 -0
- package/dist/platform/ops/environments.ops.d.ts +26 -0
- package/dist/platform/ops/environments.ops.js +311 -0
- package/dist/platform/ops/errors.d.ts +16 -0
- package/dist/platform/ops/errors.js +30 -0
- package/dist/platform/ops/evals.ops.d.ts +28 -0
- package/dist/platform/ops/evals.ops.js +783 -0
- package/dist/platform/ops/extensions-admin.ops.d.ts +25 -0
- package/dist/platform/ops/extensions-admin.ops.js +372 -0
- package/dist/platform/ops/extensions.ops.d.ts +25 -0
- package/dist/platform/ops/extensions.ops.js +347 -0
- package/dist/platform/ops/inbox.ops.d.ts +25 -0
- package/dist/platform/ops/inbox.ops.js +378 -0
- package/dist/platform/ops/marketplaces.ops.d.ts +22 -0
- package/dist/platform/ops/marketplaces.ops.js +466 -0
- package/dist/platform/ops/models.ops.d.ts +25 -0
- package/dist/platform/ops/models.ops.js +232 -0
- package/dist/platform/ops/org-plugins.ops.d.ts +29 -0
- package/dist/platform/ops/org-plugins.ops.js +329 -0
- package/dist/platform/ops/org-settings.ops.d.ts +18 -0
- package/dist/platform/ops/org-settings.ops.js +127 -0
- package/dist/platform/ops/orgs.ops.d.ts +28 -0
- package/dist/platform/ops/orgs.ops.js +296 -0
- package/dist/platform/ops/other-orgs.d.ts +20 -0
- package/dist/platform/ops/other-orgs.js +72 -0
- package/dist/platform/ops/paging.d.ts +14 -0
- package/dist/platform/ops/paging.js +20 -0
- package/dist/platform/ops/platform.ops.d.ts +30 -0
- package/dist/platform/ops/platform.ops.js +231 -0
- package/dist/platform/ops/plugins.ops.d.ts +35 -0
- package/dist/platform/ops/plugins.ops.js +476 -0
- package/dist/platform/ops/previewers.ops.d.ts +14 -0
- package/dist/platform/ops/previewers.ops.js +109 -0
- package/dist/platform/ops/requests.ops.d.ts +14 -0
- package/dist/platform/ops/requests.ops.js +191 -0
- package/dist/platform/ops/role.d.ts +4 -0
- package/dist/platform/ops/role.js +10 -0
- package/dist/platform/ops/skills.ops.d.ts +17 -0
- package/dist/platform/ops/skills.ops.js +216 -0
- package/dist/platform/ops/summary.d.ts +10 -0
- package/dist/platform/ops/summary.js +18 -0
- package/dist/platform/ops/themes.ops.d.ts +14 -0
- package/dist/platform/ops/themes.ops.js +47 -0
- package/dist/platform/ops/unavailable.d.ts +23 -0
- package/dist/platform/ops/unavailable.js +118 -0
- package/dist/platform/parity.d.ts +33 -0
- package/dist/platform/parity.js +272 -0
- package/dist/platform/platform-ops.module.d.ts +40 -0
- package/dist/platform/platform-ops.module.js +127 -0
- package/dist/platform/platform.module.d.ts +8 -0
- package/dist/platform/platform.module.js +25 -0
- package/dist/platform/registry.d.ts +30 -0
- package/dist/platform/registry.js +111 -0
- package/dist/platform/route-schemas.d.ts +18 -0
- package/dist/platform/route-schemas.js +66 -0
- package/dist/roles/gateway-role.d.ts +54 -0
- package/dist/roles/gateway-role.js +118 -0
- package/dist/roles/gateway.module.d.ts +9 -0
- package/dist/roles/gateway.module.js +31 -0
- package/dist/roles/worker-role.d.ts +65 -0
- package/dist/roles/worker-role.js +151 -0
- package/dist/roles/worker.module.d.ts +14 -0
- package/dist/roles/worker.module.js +106 -0
- package/dist/runtime/abort.js +19 -2
- package/dist/runtime/checkpointer.d.ts +8 -3
- package/dist/runtime/checkpointer.js +87 -55
- package/dist/runtime/context/build.d.ts +21 -13
- package/dist/runtime/context/build.js +106 -29
- package/dist/runtime/context/claude-tools.d.ts +4 -1
- package/dist/runtime/context/claude-tools.js +13 -12
- package/dist/runtime/context/compaction.js +24 -1
- package/dist/runtime/context/environment-paths.d.ts +40 -0
- package/dist/runtime/context/environment-paths.js +48 -0
- package/dist/runtime/context/legacy-text.d.ts +22 -0
- package/dist/runtime/context/legacy-text.js +37 -0
- package/dist/runtime/context/reminders.d.ts +2 -0
- package/dist/runtime/context/reminders.js +2 -0
- package/dist/runtime/context/run-context.d.ts +65 -0
- package/dist/runtime/context/run-context.js +215 -0
- package/dist/runtime/context/skills.d.ts +29 -11
- package/dist/runtime/context/skills.js +46 -32
- package/dist/runtime/context/tool-changes.d.ts +27 -0
- package/dist/runtime/context/tool-changes.js +60 -0
- package/dist/runtime/conversation-lock.d.ts +20 -11
- package/dist/runtime/conversation-lock.js +62 -72
- package/dist/runtime/hook-calls.d.ts +11 -4
- package/dist/runtime/hook-calls.js +41 -13
- package/dist/runtime/job-ids.d.ts +10 -0
- package/dist/runtime/job-ids.js +10 -0
- package/dist/runtime/langgraph-loop.d.ts +3 -1
- package/dist/runtime/langgraph-loop.js +37 -18
- package/dist/runtime/loop.d.ts +42 -6
- package/dist/runtime/loop.js +14 -0
- package/dist/runtime/maintenance-queue.d.ts +10 -0
- package/dist/runtime/maintenance-queue.js +10 -0
- package/dist/runtime/maintenance.d.ts +50 -74
- package/dist/runtime/maintenance.js +166 -137
- package/dist/runtime/model-call.d.ts +61 -15
- package/dist/runtime/model-call.js +128 -84
- package/dist/runtime/providers.d.ts +158 -27
- package/dist/runtime/providers.js +373 -63
- package/dist/runtime/quota.d.ts +17 -3
- package/dist/runtime/quota.js +27 -2
- package/dist/runtime/retired-schedulers.d.ts +7 -0
- package/dist/runtime/retired-schedulers.js +31 -0
- package/dist/runtime/run-context.service.d.ts +65 -0
- package/dist/runtime/run-context.service.js +236 -0
- package/dist/runtime/run-control.d.ts +43 -0
- package/dist/runtime/run-control.js +89 -0
- package/dist/runtime/run-drafts.d.ts +85 -0
- package/dist/runtime/run-drafts.js +230 -0
- package/dist/runtime/run-finish.d.ts +27 -18
- package/dist/runtime/run-finish.js +98 -51
- package/dist/runtime/run-jobs.d.ts +46 -0
- package/dist/runtime/run-jobs.js +91 -0
- package/dist/runtime/run-processors.d.ts +60 -0
- package/dist/runtime/run-processors.js +185 -0
- package/dist/runtime/run-queue.d.ts +90 -58
- package/dist/runtime/run-queue.js +566 -297
- package/dist/runtime/run-steps.d.ts +39 -0
- package/dist/runtime/run-steps.js +96 -0
- package/dist/runtime/run-worker.d.ts +134 -77
- package/dist/runtime/run-worker.js +412 -237
- package/dist/runtime/runtime.module.d.ts +10 -0
- package/dist/runtime/runtime.module.js +122 -0
- package/dist/runtime/step-log.d.ts +51 -0
- package/dist/runtime/step-log.js +111 -0
- package/dist/runtime/stream.controller.d.ts +28 -9
- package/dist/runtime/stream.controller.js +72 -13
- package/dist/runtime/stream.d.ts +27 -6
- package/dist/runtime/stream.js +102 -7
- package/dist/runtime/subagents/child.d.ts +58 -51
- package/dist/runtime/subagents/child.js +105 -86
- package/dist/runtime/subagents/definition.d.ts +32 -28
- package/dist/runtime/subagents/definition.js +89 -143
- package/dist/runtime/subagents/deliveries.d.ts +71 -0
- package/dist/runtime/subagents/deliveries.js +228 -0
- package/dist/runtime/subagents/dispatch.d.ts +197 -27
- package/dist/runtime/subagents/dispatch.js +336 -270
- package/dist/runtime/subagents/limits.d.ts +32 -8
- package/dist/runtime/subagents/limits.js +44 -8
- package/dist/runtime/subagents/messages.d.ts +95 -0
- package/dist/runtime/subagents/messages.js +328 -0
- package/dist/runtime/subagents/org-agents.d.ts +4 -4
- package/dist/runtime/subagents/org-agents.js +3 -2
- package/dist/runtime/subagents/preamble.d.ts +4 -4
- package/dist/runtime/subagents/preamble.js +9 -7
- package/dist/runtime/subagents/progress.d.ts +10 -8
- package/dist/runtime/subagents/progress.js +11 -6
- package/dist/runtime/subagents/render.d.ts +30 -0
- package/dist/runtime/subagents/render.js +53 -0
- package/dist/runtime/subagents/roster.d.ts +27 -10
- package/dist/runtime/subagents/roster.js +49 -13
- package/dist/runtime/subagents/skill-fork.d.ts +10 -10
- package/dist/runtime/subagents/skill-fork.js +23 -8
- package/dist/runtime/subagents/status.d.ts +14 -0
- package/dist/runtime/subagents/status.js +23 -0
- package/dist/runtime/subagents/subagents.service.d.ts +43 -0
- package/dist/runtime/subagents/subagents.service.js +106 -0
- package/dist/runtime/usage-report-jobs.d.ts +88 -0
- package/dist/runtime/usage-report-jobs.js +158 -0
- package/dist/runtime/usage-report.d.ts +121 -83
- package/dist/runtime/usage-report.js +355 -181
- package/dist/runtime/waits.d.ts +258 -81
- package/dist/runtime/waits.js +800 -263
- package/dist/sandbox/job-ids.d.ts +10 -0
- package/dist/sandbox/job-ids.js +10 -0
- package/dist/sandbox/jobs.d.ts +68 -0
- package/dist/sandbox/jobs.js +150 -0
- package/dist/sandbox/leases.d.ts +73 -82
- package/dist/sandbox/leases.js +162 -346
- package/dist/sandbox/providers.d.ts +46 -0
- package/dist/sandbox/providers.js +83 -0
- package/dist/sandbox/sandbox.module.d.ts +9 -0
- package/dist/sandbox/sandbox.module.js +36 -0
- package/dist/sandbox/sandbox.service.d.ts +359 -151
- package/dist/sandbox/sandbox.service.js +950 -435
- package/dist/sandbox/unreachable.d.ts +30 -0
- package/dist/sandbox/unreachable.js +108 -0
- package/dist/skills/catalog.d.ts +40 -26
- package/dist/skills/catalog.js +120 -99
- package/dist/skills/changes.controller.d.ts +11 -4
- package/dist/skills/changes.controller.js +34 -9
- package/dist/skills/changes.service.d.ts +31 -21
- package/dist/skills/changes.service.js +426 -368
- package/dist/skills/invocable.controller.d.ts +2 -2
- package/dist/skills/invocable.controller.js +10 -7
- package/dist/skills/invocation-keys.d.ts +1 -1
- package/dist/skills/invocation-keys.js +1 -1
- package/dist/skills/invoke.d.ts +19 -18
- package/dist/skills/invoke.js +68 -24
- package/dist/skills/package.d.ts +20 -1
- package/dist/skills/package.js +28 -1
- package/dist/skills/skills.controller.d.ts +33 -7
- package/dist/skills/skills.controller.js +79 -12
- package/dist/skills/skills.module.d.ts +6 -0
- package/dist/skills/skills.module.js +39 -0
- package/dist/skills/skills.schemas.d.ts +48 -0
- package/dist/skills/skills.schemas.js +61 -0
- package/dist/skills/skills.service.d.ts +151 -44
- package/dist/skills/skills.service.js +636 -204
- package/dist/skills/usable.d.ts +81 -0
- package/dist/skills/usable.js +379 -0
- package/dist/storage/job-ids.d.ts +6 -0
- package/dist/storage/job-ids.js +6 -0
- package/dist/storage/purge.d.ts +22 -7
- package/dist/storage/purge.js +55 -3
- package/dist/storage/storage.module.d.ts +6 -0
- package/dist/storage/storage.module.js +23 -0
- package/dist/storage/storage.service.d.ts +18 -4
- package/dist/storage/storage.service.js +44 -3
- package/dist/themes/render-css.d.ts +12 -0
- package/dist/themes/render-css.js +132 -0
- package/dist/themes/theme-delivery.service.d.ts +34 -0
- package/dist/themes/theme-delivery.service.js +111 -0
- package/dist/themes/theme-state.d.ts +95 -0
- package/dist/themes/theme-state.js +203 -0
- package/dist/themes/theme-usage.d.ts +61 -0
- package/dist/themes/theme-usage.js +98 -0
- package/dist/themes/themes-public.controller.d.ts +28 -0
- package/dist/themes/themes-public.controller.js +92 -0
- package/dist/themes/themes.controller.d.ts +13 -0
- package/dist/themes/themes.controller.js +38 -0
- package/dist/themes/themes.module.d.ts +3 -0
- package/dist/themes/themes.module.js +21 -0
- package/dist/themes/themes.schemas.d.ts +3 -0
- package/dist/themes/themes.schemas.js +2 -0
- package/dist/themes/themes.service.d.ts +50 -0
- package/dist/themes/themes.service.js +99 -0
- package/dist/time-zone.d.ts +5 -0
- package/dist/time-zone.js +19 -0
- package/dist/tools/approvals.controller.d.ts +1 -1
- package/dist/tools/approvals.controller.js +14 -11
- package/dist/tools/approvals.schemas.d.ts +21 -0
- package/dist/tools/approvals.schemas.js +15 -0
- package/dist/tools/approvals.service.d.ts +53 -27
- package/dist/tools/approvals.service.js +365 -260
- package/dist/tools/breaker.d.ts +2 -2
- package/dist/tools/breaker.js +21 -3
- package/dist/tools/builtin-names.d.ts +109 -0
- package/dist/tools/builtin-names.js +173 -0
- package/dist/tools/builtins/agent.d.ts +27 -25
- package/dist/tools/builtins/agent.js +66 -63
- package/dist/tools/builtins/ask-user.d.ts +3 -3
- package/dist/tools/builtins/ask-user.js +3 -3
- package/dist/tools/builtins/builtin-tools.d.ts +41 -0
- package/dist/tools/builtins/builtin-tools.js +151 -0
- package/dist/tools/builtins/current-time.d.ts +26 -0
- package/dist/tools/builtins/current-time.js +99 -0
- package/dist/tools/builtins/handback.d.ts +28 -0
- package/dist/tools/builtins/handback.js +53 -0
- package/dist/tools/builtins/platform.d.ts +51 -0
- package/dist/tools/builtins/platform.js +451 -0
- package/dist/tools/builtins/read-tool-output.d.ts +3 -3
- package/dist/tools/builtins/read-tool-output.js +3 -3
- package/dist/tools/builtins/sandbox/bash.d.ts +5 -5
- package/dist/tools/builtins/sandbox/bash.js +293 -41
- package/dist/tools/builtins/sandbox/common.d.ts +137 -37
- package/dist/tools/builtins/sandbox/common.js +222 -62
- package/dist/tools/builtins/sandbox/deliver.d.ts +1 -1
- package/dist/tools/builtins/sandbox/deliver.js +21 -18
- package/dist/tools/builtins/sandbox/edit.d.ts +1 -1
- package/dist/tools/builtins/sandbox/edit.js +65 -51
- package/dist/tools/builtins/sandbox/file-state.d.ts +34 -0
- package/dist/tools/builtins/sandbox/file-state.js +34 -0
- package/dist/tools/builtins/sandbox/glob-match.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob-match.js +1 -1
- package/dist/tools/builtins/sandbox/glob.d.ts +1 -1
- package/dist/tools/builtins/sandbox/glob.js +19 -14
- package/dist/tools/builtins/sandbox/grep.d.ts +7 -4
- package/dist/tools/builtins/sandbox/grep.js +155 -36
- package/dist/tools/builtins/sandbox/index.d.ts +9 -5
- package/dist/tools/builtins/sandbox/index.js +13 -5
- package/dist/tools/builtins/sandbox/read.d.ts +2 -2
- package/dist/tools/builtins/sandbox/read.js +30 -20
- package/dist/tools/builtins/sandbox/task-output.d.ts +79 -0
- package/dist/tools/builtins/sandbox/task-output.js +334 -0
- package/dist/tools/builtins/sandbox/task-stop.d.ts +10 -0
- package/dist/tools/builtins/sandbox/task-stop.js +113 -0
- package/dist/tools/builtins/sandbox/write.d.ts +1 -1
- package/dist/tools/builtins/sandbox/write.js +52 -45
- package/dist/tools/builtins/send-message.d.ts +56 -0
- package/dist/tools/builtins/send-message.js +100 -0
- package/dist/tools/builtins/skill-load.d.ts +32 -21
- package/dist/tools/builtins/skill-load.js +125 -74
- package/dist/tools/builtins/skill-write.d.ts +4 -4
- package/dist/tools/builtins/skill-write.js +12 -12
- package/dist/tools/builtins/tool-search.d.ts +13 -9
- package/dist/tools/builtins/tool-search.js +25 -14
- package/dist/tools/builtins/web/errors.d.ts +8 -0
- package/dist/tools/builtins/web/errors.js +53 -0
- package/dist/tools/builtins/web/extract.d.ts +62 -0
- package/dist/tools/builtins/web/extract.js +271 -0
- package/dist/tools/builtins/web/fetch.d.ts +55 -0
- package/dist/tools/builtins/web/fetch.js +175 -0
- package/dist/tools/builtins/web/index.d.ts +13 -0
- package/dist/tools/builtins/web/index.js +12 -0
- package/dist/tools/builtins/web/page-cache.d.ts +25 -0
- package/dist/tools/builtins/web/page-cache.js +77 -0
- package/dist/tools/builtins/web/search.d.ts +25 -0
- package/dist/tools/builtins/web/search.js +210 -0
- package/dist/tools/builtins/web/url.d.ts +17 -0
- package/dist/tools/builtins/web/url.js +43 -0
- package/dist/tools/canonical-json.d.ts +6 -0
- package/dist/tools/canonical-json.js +16 -0
- package/dist/tools/connector-content.controller.d.ts +1 -1
- package/dist/tools/connector-content.controller.js +11 -6
- package/dist/tools/connector-content.d.ts +12 -15
- package/dist/tools/connector-content.js +53 -18
- package/dist/tools/connectors.controller.d.ts +16 -3
- package/dist/tools/connectors.controller.js +34 -14
- package/dist/tools/connectors.schemas.d.ts +12 -0
- package/dist/tools/connectors.schemas.js +19 -0
- package/dist/tools/connectors.service.d.ts +80 -18
- package/dist/tools/connectors.service.js +529 -358
- package/dist/tools/credentials.d.ts +20 -20
- package/dist/tools/credentials.js +55 -34
- package/dist/tools/display-names.d.ts +9 -0
- package/dist/tools/display-names.js +24 -0
- package/dist/tools/drift.d.ts +29 -41
- package/dist/tools/drift.js +116 -84
- package/dist/tools/elicitation.js +1 -1
- package/dist/tools/extension-tools.controller.d.ts +14 -0
- package/dist/tools/extension-tools.controller.js +37 -0
- package/dist/tools/info.d.ts +73 -13
- package/dist/tools/info.js +151 -39
- package/dist/tools/job-ids.d.ts +13 -0
- package/dist/tools/job-ids.js +15 -0
- package/dist/tools/jobs.d.ts +24 -0
- package/dist/tools/jobs.js +69 -0
- package/dist/tools/legacy-data.d.ts +34 -0
- package/dist/tools/legacy-data.js +76 -0
- package/dist/tools/legacy-keys.d.ts +51 -0
- package/dist/tools/legacy-keys.js +115 -0
- package/dist/tools/naming.d.ts +1 -5
- package/dist/tools/naming.js +1 -7
- package/dist/tools/oauth/flow-paths.d.ts +16 -0
- package/dist/tools/oauth/flow-paths.js +38 -0
- package/dist/tools/oauth/flow.d.ts +30 -30
- package/dist/tools/oauth/flow.js +109 -81
- package/dist/tools/oauth/oauth.controller.d.ts +3 -3
- package/dist/tools/oauth/oauth.controller.js +12 -9
- package/dist/tools/oauth/tokens.d.ts +45 -10
- package/dist/tools/oauth/tokens.js +70 -24
- package/dist/tools/org-tool-switches.d.ts +88 -0
- package/dist/tools/org-tool-switches.js +201 -0
- package/dist/tools/outputs.d.ts +13 -4
- package/dist/tools/outputs.js +48 -4
- package/dist/tools/pipeline.d.ts +108 -80
- package/dist/tools/pipeline.js +396 -409
- package/dist/tools/policy.d.ts +4 -17
- package/dist/tools/policy.js +49 -35
- package/dist/tools/questions.controller.d.ts +2 -2
- package/dist/tools/questions.controller.js +9 -6
- package/dist/tools/questions.service.d.ts +26 -25
- package/dist/tools/questions.service.js +201 -142
- package/dist/tools/registry.d.ts +215 -84
- package/dist/tools/registry.js +382 -264
- package/dist/tools/resources.d.ts +1 -1
- package/dist/tools/resources.js +1 -1
- package/dist/tools/specs.d.ts +5 -4
- package/dist/tools/specs.js +3 -1
- package/dist/tools/tools.module.d.ts +10 -0
- package/dist/tools/tools.module.js +113 -0
- package/dist/tools/validate.js +1 -1
- package/dist/ui/call-extension.d.ts +16 -0
- package/dist/ui/call-extension.js +38 -0
- package/dist/ui/embed-token.d.ts +9 -5
- package/dist/ui/embed-token.js +34 -6
- package/dist/ui/ui-stream.d.ts +22 -17
- package/dist/ui/ui-stream.js +72 -12
- package/dist/ui/ui.module.d.ts +7 -0
- package/dist/ui/ui.module.js +28 -0
- package/dist/ui/views.controller.d.ts +14 -12
- package/dist/ui/views.controller.js +32 -25
- package/dist/ui/views.d.ts +10 -57
- package/dist/ui/views.js +58 -46
- package/package.json +13 -3
- package/src/migrations/0063_tool_keys_claude_code.sql +220 -0
- package/src/migrations/0064_account_last_org.sql +7 -0
- package/src/migrations/0065_conversation_archive.sql +8 -0
- package/src/migrations/0066_extension_display_name.sql +4 -0
- package/src/migrations/0067_agent_profiles.sql +20 -0
- package/src/migrations/0068_agent_avatar_uploads.sql +7 -0
- package/src/migrations/0069_attachments_agent_idx.sql +3 -0
- package/src/migrations/0070_background_tasks.sql +37 -0
- package/src/migrations/0071_background_tasks_reserve.sql +6 -0
- package/src/migrations/0072_background_tasks_stopping.sql +5 -0
- package/src/migrations/0073_org_extension_point_defaults.sql +11 -0
- package/src/migrations/0074_subagent_tree.sql +50 -0
- package/src/migrations/0075_plugin_scope.sql +61 -0
- package/src/migrations/0076_skills_created_by_nullable.sql +6 -0
- package/src/migrations/0077_scope_requests.sql +52 -0
- package/src/migrations/0078_scope_grant_switches.sql +18 -0
- package/src/migrations/0079_scope_live_install_switches.sql +19 -0
- package/src/migrations/0080_rename_enterprise_admin.sql +18 -0
- package/src/migrations/0081_platform_components.sql +129 -0
- package/src/migrations/0082_platform_migration.sql +33 -0
- package/src/migrations/0083_plugin_scope_sync_failures.sql +15 -0
- package/src/migrations/0084_org_owned_items.sql +85 -0
- package/src/migrations/0085_agent_templates_phase4.sql +45 -0
- package/src/migrations/0086_org_layering.sql +30 -0
- package/src/migrations/0087_approval_summary.sql +6 -0
- package/src/migrations/0088_environments.sql +80 -0
- package/src/migrations/0089_model_kinds_usage.sql +38 -0
- package/src/migrations/0090_initial_passwords.sql +27 -0
- package/src/migrations/0091_account_time_zone.sql +4 -0
- package/src/migrations/0092_tools_default_on.sql +27 -0
- package/src/migrations/0093_connected_environments.sql +37 -0
- package/src/migrations/0094_environment_paths_idx.sql +7 -0
- package/src/migrations/0095_environment_files_resets.sql +5 -0
- package/src/migrations/0096_environment_demoted_default.sql +18 -0
- package/src/migrations/0097_extension_installs_enabled_at.sql +16 -0
- package/src/migrations/0098_single_provider_running_first.sql +41 -0
- package/src/migrations/0099_channel_connection_guide_ack.sql +6 -0
- package/src/migrations/0100_catalog_files.sql +13 -0
- package/src/migrations/0101_marketplace_icons.sql +32 -0
- package/src/migrations/0102_themes.sql +64 -0
- package/src/migrations/0103_ui_theme_setting.sql +7 -0
- package/dist/catalog/upgrade-targets.d.ts +0 -59
- package/dist/catalog/upgrade-targets.js +0 -90
- package/dist/conversations/sandbox-status.d.ts +0 -21
- package/dist/conversations/sandbox-status.js +0 -24
- package/dist/extensions/org-config.controller.d.ts +0 -24
- package/dist/extensions/org-config.controller.js +0 -59
- package/dist/http/gateway.module.js +0 -13
- package/dist/http/health.controller.d.ts +0 -26
- package/dist/http/health.controller.js +0 -79
- package/dist/http/tokens.d.ts +0 -131
- package/dist/http/tokens.js +0 -131
- package/dist/http/zod.pipe.d.ts +0 -8
- package/dist/http/zod.pipe.js +0 -14
- package/dist/identity/enterprise-admin.d.ts +0 -14
- package/dist/identity/enterprise-admin.js +0 -27
- package/dist/identity/rate-limit.d.ts +0 -55
- package/dist/identity/rate-limit.js +0 -121
- package/dist/sandbox/lifecycle.d.ts +0 -21
- package/dist/sandbox/lifecycle.js +0 -68
- package/dist/tools/builtins/sandbox/names.d.ts +0 -7
- package/dist/tools/builtins/sandbox/names.js +0 -20
|
@@ -1,28 +1,66 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
1
10
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { PLUGIN_MANIFEST_FILE, parseSkillMd, SDK_VERSION, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
|
|
11
|
+
import { PLUGIN_MANIFEST_FILE, parseSkillMd, pluginDescription, SDK_VERSION, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
|
|
12
|
+
import { getQueueToken } from "@nestjs/bullmq";
|
|
13
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
3
14
|
import { sql } from "kysely";
|
|
4
15
|
import semver from "semver";
|
|
5
16
|
import { ApiError } from "../errors.js";
|
|
17
|
+
import { ExtensionAdminOps } from "../extensions/admin-ops.js";
|
|
18
|
+
import { ExtensionAdmin } from "../extensions/admin-view.js";
|
|
6
19
|
import { writeSnapshot } from "../extensions/approvals.js";
|
|
20
|
+
import { blobKey, ExtensionBlobs } from "../extensions/blobs.js";
|
|
21
|
+
import { ExtensionInstalls } from "../extensions/installs.js";
|
|
22
|
+
import { PluginApproveLock, PluginInstallLock } from "../extensions/locks.js";
|
|
7
23
|
import { unrunMigrations } from "../extensions/migrate-lock.js";
|
|
8
24
|
import { ExtensionPackageError, permissionSetOfPackage, readExtensionPackage, } from "../extensions/package.js";
|
|
9
25
|
import { diffPermissions, permissionKeys, WARNINGS_KEY_PREFIX, } from "../extensions/permission-set.js";
|
|
10
26
|
import { reviewHash as extensionReviewHash, migrationWarnings, permissionGroups, permissionKeyItems, } from "../extensions/permission-view.js";
|
|
27
|
+
import { ExtensionRegistry } from "../extensions/registry.js";
|
|
11
28
|
import { audit } from "../identity/audit.js";
|
|
12
|
-
import {
|
|
29
|
+
import { assertCustomAllowed } from "../identity/settings.js";
|
|
30
|
+
import { SuperAdminLock } from "../identity/super-admin.js";
|
|
31
|
+
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
32
|
+
import { afterCommit } from "../infra/database/after-commit.js";
|
|
33
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
34
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
35
|
+
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
36
|
+
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
37
|
+
import { OrgLock } from "../orgs/org-lock.js";
|
|
13
38
|
import { packPackageTgz } from "../packages/tgz.js";
|
|
39
|
+
import { MAINTENANCE_QUEUE_NAME } from "../runtime/maintenance-queue.js";
|
|
14
40
|
import { checkSkillFiles, SkillArchiveError } from "../skills/package.js";
|
|
41
|
+
import { StorageService } from "../storage/storage.service.js";
|
|
42
|
+
import { canonicalJson } from "../tools/canonical-json.js";
|
|
15
43
|
import { endpointCredentialIssues } from "../tools/endpoint.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
44
|
+
import { findConnectorIn } from "./catalog-content.js";
|
|
45
|
+
import { displayFilePaths, putDisplayFiles, sweepDisplayFiles } from "./catalog-files.js";
|
|
46
|
+
import { assertOrgsExist, assertPluginNameOwner, catalogObjectPrefix, itemConfirmations, itemScopeFacts, itemView, markVersionApplied, permissionsMismatch, precheckCatalogImport, putCatalogFiles, templateProblems, unappliedOwnVersion, writeCatalogVersion, } from "./catalog-items.js";
|
|
18
47
|
import { CLAUDE_PLUGIN_FILE, claudeContentDigest, } from "./claude/manifest.js";
|
|
19
48
|
import { CLAUDE_MCP_CONNECTOR } from "./claude/mcp.js";
|
|
20
49
|
import { item as reportItem, sortItems, } from "./claude/report.js";
|
|
21
50
|
import { isClaudePluginTree, translateClaudePlugin } from "./claude/translate.js";
|
|
22
|
-
import {
|
|
51
|
+
import { CatalogItemLock } from "./locks.js";
|
|
52
|
+
import { assertNameFree, assertPackageFree, assertShareable, packageOwner, releaseExtensionClaim, shareGate, usableBy, } from "./ownership.js";
|
|
53
|
+
import { PlatformComponents } from "./platform-components.js";
|
|
54
|
+
import { PLATFORM_MIGRATION_JOB } from "./platform-migration.js";
|
|
55
|
+
import { PluginPackageError, packagePath, readPluginFiles, readPluginPackage, themeApiError, } from "./plugin-package.js";
|
|
56
|
+
import { hasImportRequests, importRequestOf, resolveImportRequests } from "./request-rules.js";
|
|
57
|
+
import { assertNameNotReserved } from "./reserved-names.js";
|
|
58
|
+
import { addScopeOrg } from "./scope-orgs.js";
|
|
23
59
|
import { maxSatisfying, satisfiesRange } from "./versions.js";
|
|
60
|
+
/** How long after a failed post-import platform sync the migration job runs for the item. */
|
|
61
|
+
export const PLATFORM_SYNC_RETRY_MS = 60_000;
|
|
24
62
|
/**
|
|
25
|
-
*
|
|
63
|
+
* Platform import of a plugin (package ecosystem spec §4.3): one review for every plugin, whatever
|
|
26
64
|
* it contains (an extension, skills, connector templates, dependencies), confirmed once.
|
|
27
65
|
*
|
|
28
66
|
* prepare: the tgz is always hostile input, and **nothing is written until every check passes**
|
|
@@ -32,27 +70,30 @@ import { maxSatisfying, satisfiesRange } from "./versions.js";
|
|
|
32
70
|
* refused; name ownership; a downgrade to a version with unrun migrations is refused), each skill by
|
|
33
71
|
* the skill package rules, each connector template against the connector loaded on this replica (or
|
|
34
72
|
* statically when the connector is provided by the plugin's own extension or by a dependency), the
|
|
35
|
-
* catalog name / version conflicts and the actor still
|
|
73
|
+
* catalog name / version conflicts and the actor still a super admin. Dependencies are only
|
|
36
74
|
* resolved against the imported catalog versions for the review (an unresolved one does not block
|
|
37
75
|
* the import, spec §4.1); they are never fetched. Only then is the extension handed to
|
|
38
|
-
* `ExtensionInstalls.ingest` (source `catalog`), the skill / template
|
|
39
|
-
* storage,
|
|
76
|
+
* `ExtensionInstalls.ingest` (source `catalog`), the skill / template files written to object
|
|
77
|
+
* storage, the display files (icons, setup guide files; `catalog-files.ts`) written to PG with a
|
|
78
|
+
* staging row (24 hours), and `catalog.plugin_staged` audited. A display file inside a skill
|
|
79
|
+
* directory or at a template's path goes to both places: each reader finds it where it looks.
|
|
40
80
|
*
|
|
41
81
|
* confirm: `reviewHash` must match the staging; in one transaction it deletes the staging row
|
|
42
82
|
* (confirm works once), locks the extension name and recomputes its deployment state (installed /
|
|
43
83
|
* upgraded / swapped after the review -> `plugin.review_stale`), writes the extension's permission
|
|
44
|
-
* snapshot when it is installed by this import (
|
|
45
|
-
* `extension.permissions_approved` carrying the plugin), and creates the item
|
|
46
|
-
* (`manifest` = the normalized plugin.json,
|
|
47
|
-
*
|
|
48
|
-
* deployment and enabled (`ExtensionAdminOps.install` + `enable`;
|
|
49
|
-
* restart); a failure is returned, not thrown, and an upgrade that was
|
|
50
|
-
* snapshot back.
|
|
84
|
+
* snapshot when it is installed or upgraded by this import (source web, audit
|
|
85
|
+
* `extension.permissions_approved` carrying the plugin), and creates the item (with the scope the
|
|
86
|
+
* admin chose, default `optional`) or adds the version (`manifest` = the normalized plugin.json,
|
|
87
|
+
* `extension_sha256`, the files under the staging prefix). After the commit the plugin's own
|
|
88
|
+
* extension is installed on the deployment and enabled (`ExtensionAdminOps.install` + `enable`;
|
|
89
|
+
* each replica reconciles, no restart); a failure is returned, not thrown, and an upgrade that was
|
|
90
|
+
* not installed gets its old snapshot back.
|
|
51
91
|
*
|
|
52
92
|
* Expired staging is cleaned by the maintenance job `app-staging-cleanup`
|
|
53
|
-
* ({@link PluginImport.cleanupExpired}): it deletes the staging row and its object prefix
|
|
54
|
-
*
|
|
55
|
-
*
|
|
93
|
+
* ({@link PluginImport.cleanupExpired}): it deletes the staging row and its object prefix, then the
|
|
94
|
+
* display files (`catalog_files`) nothing lists any more; a stored extension package stays in the
|
|
95
|
+
* content-addressed `extension_packages` (the same as importing the same tgz again; without an
|
|
96
|
+
* install record referencing it it is never loaded).
|
|
56
97
|
*/
|
|
57
98
|
/** How long a staged import is kept. */
|
|
58
99
|
export const PLUGIN_STAGING_TTL_MS = 24 * 3600_000;
|
|
@@ -67,15 +108,21 @@ const NOT_NPM = { provenance: { checked: false, reason: "not an npm package" } }
|
|
|
67
108
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
68
109
|
const notFound = () => new ApiError("plugin.staging_not_found", "This plugin import was not found or has expired (staged imports are kept for 24 hours); prepare it again");
|
|
69
110
|
const invalid = (problems) => new ApiError("catalog.invalid_manifest", `Invalid plugin package: ${problems[0] ?? "unknown problem"}`, problems.slice(0, 50));
|
|
111
|
+
const reviewStale = (review) => new ApiError("plugin.review_stale", `The review of plugin ${review.name} ${review.version} is out of date (it changed, or its extension on this deployment changed since it was prepared); review it again`);
|
|
70
112
|
const mismatch = (what) => new ApiError("marketplace.package_mismatch", `The downloaded package does not match the marketplace entry: ${what}`);
|
|
71
113
|
/**
|
|
72
114
|
* The API error of a plugin package that cannot be read in a catalog path: the pre-0.1.0 format ->
|
|
73
|
-
* `catalog.legacy_format
|
|
115
|
+
* `catalog.legacy_format`; a failing theme (themes spec §5) -> `theme.invalid` (details
|
|
116
|
+
* `[{ theme, errors }]`) or `theme.unreadable` (details `[{ theme, issues }]`, the failing pairs);
|
|
117
|
+
* anything else -> `catalog.invalid_manifest` (issues as details).
|
|
74
118
|
*/
|
|
75
119
|
export function catalogPackageError(e) {
|
|
76
120
|
const legacy = e.code === "catalog.legacy_format" || e.code === "extension.legacy_format";
|
|
77
121
|
if (legacy)
|
|
78
122
|
return new ApiError("catalog.legacy_format", e.message, e.issues);
|
|
123
|
+
if (e.code === "theme.invalid" || e.code === "theme.unreadable") {
|
|
124
|
+
return themeApiError(e);
|
|
125
|
+
}
|
|
79
126
|
return invalid(e.issues);
|
|
80
127
|
}
|
|
81
128
|
/** Runs a package read, mapping its errors with {@link catalogPackageError}. */
|
|
@@ -96,15 +143,97 @@ const fileOf = (path, data) => ({
|
|
|
96
143
|
sha256: createHash("sha256").update(data).digest("hex"),
|
|
97
144
|
data,
|
|
98
145
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
146
|
+
let PluginImport = class PluginImport {
|
|
147
|
+
kdb;
|
|
148
|
+
adminLock;
|
|
149
|
+
orgLock;
|
|
150
|
+
installLock;
|
|
151
|
+
approveLock;
|
|
152
|
+
itemLock;
|
|
153
|
+
config;
|
|
154
|
+
installs;
|
|
155
|
+
ops;
|
|
156
|
+
admin;
|
|
157
|
+
blobs;
|
|
158
|
+
registry;
|
|
159
|
+
log;
|
|
160
|
+
txHost;
|
|
161
|
+
platform;
|
|
162
|
+
maintenance;
|
|
163
|
+
/** Where plugin files go (the kernel's object storage; the CLI's own, see {@link useCliStorage}). */
|
|
164
|
+
files;
|
|
165
|
+
/**
|
|
166
|
+
* false: this process loads no connectors (the CLI), so a template of an unknown connector gets
|
|
167
|
+
* only the static endpoint checks and `endpointChecked: false`; the org install re-checks it
|
|
168
|
+
* against the loaded connector.
|
|
169
|
+
*/
|
|
170
|
+
connectorsLoaded = true;
|
|
171
|
+
constructor(kdb,
|
|
172
|
+
/** The super admin lock (identity/super-admin.ts): joins the caller's transaction. */
|
|
173
|
+
adminLock,
|
|
174
|
+
/** The owner org's lock: an org upload re-checks its admin under it (ruling P3-7). */
|
|
175
|
+
orgLock, installLock, approveLock, itemLock, config, storage, installs, ops, admin,
|
|
176
|
+
/** Reads a package from the package store (confirm recomputes the permission set). */
|
|
177
|
+
blobs,
|
|
178
|
+
/** Config-declared names, loaded connectors and extension versions (the extension registry). */
|
|
179
|
+
registry, log, txHost,
|
|
180
|
+
/** The platform rows of a new item's components, written after the confirm's commit. */
|
|
181
|
+
platform,
|
|
182
|
+
/** A failed platform sync enqueues a run of the migration job here (it heals the item). */
|
|
183
|
+
maintenance) {
|
|
184
|
+
this.kdb = kdb;
|
|
185
|
+
this.adminLock = adminLock;
|
|
186
|
+
this.orgLock = orgLock;
|
|
187
|
+
this.installLock = installLock;
|
|
188
|
+
this.approveLock = approveLock;
|
|
189
|
+
this.itemLock = itemLock;
|
|
190
|
+
this.config = config;
|
|
191
|
+
this.installs = installs;
|
|
192
|
+
this.ops = ops;
|
|
193
|
+
this.admin = admin;
|
|
194
|
+
this.blobs = blobs;
|
|
195
|
+
this.registry = registry;
|
|
196
|
+
this.log = log;
|
|
197
|
+
this.txHost = txHost;
|
|
198
|
+
this.platform = platform;
|
|
199
|
+
this.maintenance = maintenance;
|
|
200
|
+
this.files = storage;
|
|
201
|
+
}
|
|
202
|
+
/** The kernel-schema handle of the current context (the transaction, else the pool). */
|
|
203
|
+
get db() {
|
|
204
|
+
return this.kdb.db;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* CLI only (like `ExtensionHost.noteInspected`): plugin files go to the object store the CLI set
|
|
208
|
+
* up itself, and connector templates get static checks only (the CLI loads no connector). Called
|
|
209
|
+
* once, right after the command's context is created.
|
|
210
|
+
*/
|
|
211
|
+
useCliStorage(storage) {
|
|
212
|
+
this.files = storage;
|
|
213
|
+
this.connectorsLoaded = false;
|
|
214
|
+
this.platform.useCliStorage(storage);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* The super-admin re-check under the lock, in the caller's transaction. `actor` null is the
|
|
218
|
+
* CLI (the operator of the deployment: no account to re-check, audits carry no actor), like
|
|
219
|
+
* `ExtensionInstalls.ingest`. An org upload (`owner`) re-checks the actor as an admin of the
|
|
220
|
+
* owner org under the org row lock instead (`catalog.upload`; an org deleted meanwhile -> 404
|
|
221
|
+
* `org.not_found`).
|
|
222
|
+
*/
|
|
223
|
+
async authorizeActor(actor, owner) {
|
|
224
|
+
if (owner !== undefined) {
|
|
225
|
+
if (actor === null)
|
|
226
|
+
throw new Error("an org upload has an actor");
|
|
227
|
+
await this.orgLock.lockAndAuthorize(owner.orgId, actor, "catalog.upload");
|
|
228
|
+
}
|
|
229
|
+
else if (actor === null)
|
|
230
|
+
await this.adminLock.lock();
|
|
231
|
+
else
|
|
232
|
+
await this.adminLock.lockAndAuthorize(actor);
|
|
233
|
+
}
|
|
234
|
+
/** The re-check alone, in a transaction of its own (before anything is written). */
|
|
235
|
+
async authorize(actor, owner) {
|
|
236
|
+
await this.authorizeActor(actor, owner);
|
|
108
237
|
}
|
|
109
238
|
/**
|
|
110
239
|
* Reads, checks and stages a plugin (see the file header). Returns the staging id and review.
|
|
@@ -112,7 +241,7 @@ export class PluginImport {
|
|
|
112
241
|
* versioned and published by it (the version defaulting to `0.0.0-sha256.h<12>`, spec §5.3).
|
|
113
242
|
*/
|
|
114
243
|
async prepare(actor, bytes, source, opts = {}) {
|
|
115
|
-
const maxBytes = this.
|
|
244
|
+
const maxBytes = this.config.get().packages.maxBytes;
|
|
116
245
|
const pkg = await readingPackage(() => readPluginPackage(bytes, {
|
|
117
246
|
maxBytes,
|
|
118
247
|
hostSdkVersion: SDK_VERSION,
|
|
@@ -143,7 +272,7 @@ export class PluginImport {
|
|
|
143
272
|
entryVersion: opts.fallback.entryVersion,
|
|
144
273
|
}),
|
|
145
274
|
...(claude !== undefined && { overlay: claude }),
|
|
146
|
-
allowInsecureLoopback: this.
|
|
275
|
+
allowInsecureLoopback: this.config.get().marketplaces.allowInsecureLoopback,
|
|
147
276
|
}));
|
|
148
277
|
const translated = await readingPackage(async () => readPluginFiles(t.tree, {
|
|
149
278
|
hostSdkVersion: SDK_VERSION,
|
|
@@ -194,7 +323,11 @@ export class PluginImport {
|
|
|
194
323
|
* (required with an extension: it is stored in the package store); `size` is recorded.
|
|
195
324
|
*/
|
|
196
325
|
async prepareContents(actor, pkg, tgz, source, opts) {
|
|
197
|
-
const maxBytes = this.
|
|
326
|
+
const maxBytes = this.config.get().packages.maxBytes;
|
|
327
|
+
const owner = opts.owner;
|
|
328
|
+
if (owner !== undefined && source.kind !== "file") {
|
|
329
|
+
throw new Error("an org upload is a file (ruling P3-7)");
|
|
330
|
+
}
|
|
198
331
|
// 1. Every check (nothing written)
|
|
199
332
|
const m = pkg.manifest;
|
|
200
333
|
const packageName = packageNameOf(pkg);
|
|
@@ -208,25 +341,54 @@ export class PluginImport {
|
|
|
208
341
|
? await readingPackage(() => readExtensionPackage(bytes, { maxBytes, hostSdkVersion: SDK_VERSION }))
|
|
209
342
|
: undefined;
|
|
210
343
|
const content = this.checkContent(pkg, format);
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
344
|
+
// A name live for another owner (an org's for the super admin; the platform's or another
|
|
345
|
+
// org's for an org) -> 409 plugin.name_taken naming it (P3-14); the same owner adds a version
|
|
346
|
+
await assertNameFree(this.db, m.name, owner?.orgId ?? null);
|
|
347
|
+
if (owner !== undefined) {
|
|
348
|
+
// a bootstrap or marketplace plugin's name stays free for the platform (ruling P3-28)
|
|
349
|
+
await assertNameNotReserved(this.db, m.name);
|
|
350
|
+
// its npm package is an identity of this org only (ruling P3-51)
|
|
351
|
+
await assertPackageFree(this.db, packageName, owner.orgId);
|
|
352
|
+
await assertCustomContent(this.db, content);
|
|
353
|
+
}
|
|
354
|
+
// An org's own version imported but not applied: its update is retried (pre-flight F4)
|
|
355
|
+
const retry = owner !== undefined && !m.extension
|
|
356
|
+
? await unappliedOwnVersion(this.db, m.name, owner.orgId, {
|
|
357
|
+
packageName,
|
|
358
|
+
version: m.version,
|
|
359
|
+
contentDigest: pkg.contentDigest,
|
|
360
|
+
})
|
|
361
|
+
: undefined;
|
|
362
|
+
const { existing, version } = retry !== undefined
|
|
363
|
+
? { existing: { id: retry.itemId }, version: retry.version }
|
|
364
|
+
: await precheckCatalogImport(this.db, m.name, {
|
|
365
|
+
packageName,
|
|
366
|
+
version: m.version,
|
|
367
|
+
contentDigest: pkg.contentDigest,
|
|
368
|
+
...(source.integrity !== undefined && { integrity: source.integrity }),
|
|
369
|
+
...(source.detail !== undefined && { detail: source.detail }),
|
|
370
|
+
...(source.marketplaceId !== undefined && { marketplaceId: source.marketplaceId }),
|
|
371
|
+
});
|
|
219
372
|
// The catalog name space is the extension name space: a declarative plugin cannot take a
|
|
220
373
|
// config-declared or another package's extension name either
|
|
221
374
|
this.assertNotDeclared(m.name);
|
|
222
|
-
await assertPluginNameOwner(this.
|
|
375
|
+
await assertPluginNameOwner(this.db, m.name, packageName);
|
|
223
376
|
let extension;
|
|
224
377
|
if (ext) {
|
|
225
378
|
extension = await this.reviewExtension(ext, await this.extensionState(m.name, packageName));
|
|
226
|
-
await assertDowngradable(this.
|
|
379
|
+
await assertDowngradable(this.db, extension, ext.migrationSql);
|
|
380
|
+
}
|
|
381
|
+
// Display files go to PG with the staging row; skills and templates need object storage, which a
|
|
382
|
+
// bootstrap import never has (the object store may be a bootstrap plugin itself). A file that is
|
|
383
|
+
// both (an icon inside a skill directory) goes to both: the readers of each look only there
|
|
384
|
+
const displayFiles = content.files.filter((f) => content.displayPaths.has(f.path));
|
|
385
|
+
const objectFiles = content.files.filter((f) => content.objectPaths.has(f.path));
|
|
386
|
+
if (objectFiles.length > 0 && retry === undefined) {
|
|
387
|
+
if (source.kind === "bootstrap" && !this.files.available) {
|
|
388
|
+
throw new ApiError("storage.unavailable", `Bootstrap plugin ${m.name} ships skills, connector templates, agent templates or themes, which are kept in object storage, and object storage is not running yet (it may be a bootstrap plugin itself); a required bootstrap plugin may ship only an icon and setup guides, an optional one is retried once the extensions have loaded`);
|
|
389
|
+
}
|
|
390
|
+
this.files.assertAvailable();
|
|
227
391
|
}
|
|
228
|
-
if (content.files.length > 0)
|
|
229
|
-
this.d.storage.assertAvailable();
|
|
230
392
|
const src = {
|
|
231
393
|
kind: source.kind,
|
|
232
394
|
ref: source.ref,
|
|
@@ -234,7 +396,7 @@ export class PluginImport {
|
|
|
234
396
|
...(source.marketplaceId !== undefined && { marketplaceId: source.marketplaceId }),
|
|
235
397
|
...(source.detail !== undefined && { detail: source.detail }),
|
|
236
398
|
};
|
|
237
|
-
const dependencies = await this.resolveDependencies(m);
|
|
399
|
+
const dependencies = await this.resolveDependencies(m, owner);
|
|
238
400
|
let translation;
|
|
239
401
|
if (opts.claude !== undefined) {
|
|
240
402
|
const added = [
|
|
@@ -264,7 +426,8 @@ export class PluginImport {
|
|
|
264
426
|
contentDigest: pkg.contentDigest,
|
|
265
427
|
packageName,
|
|
266
428
|
publisher: m.publisher,
|
|
267
|
-
description: m.description,
|
|
429
|
+
description: pluginDescription(m.description).en,
|
|
430
|
+
descriptionZh: pluginDescription(m.description).zh ?? null,
|
|
268
431
|
...(m.displayName !== undefined && { displayName: m.displayName }),
|
|
269
432
|
...(m.license !== undefined && { license: m.license }),
|
|
270
433
|
...(m.homepage !== undefined && { homepage: m.homepage }),
|
|
@@ -272,6 +435,7 @@ export class PluginImport {
|
|
|
272
435
|
skills: content.skills,
|
|
273
436
|
connectorTemplates: content.templates,
|
|
274
437
|
...(content.agentTemplates.length > 0 && { agentTemplates: content.agentTemplates }),
|
|
438
|
+
...(content.themes.length > 0 && { themes: content.themes }),
|
|
275
439
|
dependencies,
|
|
276
440
|
source: src,
|
|
277
441
|
provenance: (opts.provenance ?? NOT_NPM).provenance,
|
|
@@ -280,14 +444,15 @@ export class PluginImport {
|
|
|
280
444
|
reviewHash: "",
|
|
281
445
|
};
|
|
282
446
|
review.reviewHash = pluginReviewHash(review, content.files);
|
|
283
|
-
// Re-check under the lock that the actor is still an
|
|
284
|
-
|
|
447
|
+
// Re-check under the lock that the actor is still a super admin (an org upload: an admin of
|
|
448
|
+
// the owner org) before writing
|
|
449
|
+
await this.authorize(actor, owner);
|
|
285
450
|
// 2. Write: the extension into the package store, files into object storage, the staging row
|
|
286
451
|
const stagingId = randomUUID();
|
|
287
452
|
const itemId = existing?.id ?? randomUUID();
|
|
288
453
|
if (ext) {
|
|
289
454
|
const bootstrap = src.kind === "bootstrap";
|
|
290
|
-
await this.
|
|
455
|
+
await this.installs.ingest(actor, bytes, bootstrap
|
|
291
456
|
? { source: "bootstrap", ref: src.ref }
|
|
292
457
|
: {
|
|
293
458
|
source: "catalog",
|
|
@@ -295,12 +460,14 @@ export class PluginImport {
|
|
|
295
460
|
}, {
|
|
296
461
|
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
297
462
|
...(bootstrap && { store: "pg" }),
|
|
463
|
+
// an org upload only stores the package (nothing runs until the super admin confirms)
|
|
464
|
+
...(owner !== undefined && { owner }),
|
|
298
465
|
});
|
|
299
466
|
}
|
|
300
467
|
let objectPrefix = null;
|
|
301
|
-
if (
|
|
468
|
+
if (objectFiles.length > 0 && retry === undefined) {
|
|
302
469
|
objectPrefix = catalogObjectPrefix(itemId, version, stagingId);
|
|
303
|
-
await putCatalogFiles(this.
|
|
470
|
+
await putCatalogFiles(this.files, objectPrefix, objectFiles);
|
|
304
471
|
}
|
|
305
472
|
const keys = ext
|
|
306
473
|
? permissionKeys(permissionSetOfPackage(ext))
|
|
@@ -321,47 +488,58 @@ export class PluginImport {
|
|
|
321
488
|
...(translation !== undefined && { translation }),
|
|
322
489
|
...(license.text !== undefined && { licenseText: license.text }),
|
|
323
490
|
...(license.truncated && { licenseTruncated: true }),
|
|
491
|
+
...(retry !== undefined && { retry: true }),
|
|
324
492
|
};
|
|
325
|
-
await this.
|
|
326
|
-
await authorizeActor(trx, actor);
|
|
327
|
-
await trx
|
|
328
|
-
.insertInto("plugin_import_staging")
|
|
329
|
-
.values({
|
|
330
|
-
id: stagingId,
|
|
331
|
-
review: JSON.stringify(review),
|
|
332
|
-
manifest: JSON.stringify(staged),
|
|
333
|
-
object_prefix: objectPrefix,
|
|
334
|
-
source: JSON.stringify(src),
|
|
335
|
-
created_by: actor,
|
|
336
|
-
expires_at: new Date(Date.now() + PLUGIN_STAGING_TTL_MS),
|
|
337
|
-
})
|
|
338
|
-
.execute();
|
|
339
|
-
await audit(trx, {
|
|
340
|
-
...(actor !== null && { actorAccountId: actor }),
|
|
341
|
-
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
342
|
-
action: "catalog.plugin_staged",
|
|
343
|
-
target: stagingId,
|
|
344
|
-
detail: {
|
|
345
|
-
stagingId,
|
|
346
|
-
name: m.name,
|
|
347
|
-
version,
|
|
348
|
-
source: src.kind,
|
|
349
|
-
sourceRef: src.ref,
|
|
350
|
-
...(src.integrity !== undefined && { integrity: src.integrity }),
|
|
351
|
-
...(src.marketplaceId !== undefined && { marketplaceId: src.marketplaceId }),
|
|
352
|
-
reviewHash: review.reviewHash,
|
|
353
|
-
...(extension && {
|
|
354
|
-
extension: { sha256: extension.sha256, action: extension.action },
|
|
355
|
-
}),
|
|
356
|
-
},
|
|
357
|
-
});
|
|
358
|
-
});
|
|
493
|
+
await this.writeStaging(actor, stagingId, review, staged, objectPrefix, src, opts, owner, displayFiles);
|
|
359
494
|
return { stagingId, review, permissionKeys: keys, permissionsMismatch: mismatch };
|
|
360
495
|
}
|
|
496
|
+
/** The staging row and the `catalog.plugin_staged` audit, the actor re-checked under the lock. */
|
|
497
|
+
async writeStaging(actor, stagingId, review, staged, objectPrefix, src, opts, owner, displayFiles) {
|
|
498
|
+
const { extension } = review;
|
|
499
|
+
const t = this.db;
|
|
500
|
+
await this.authorizeActor(actor, owner);
|
|
501
|
+
// committed with the staging row that lists them (the sweep keeps what a staging lists)
|
|
502
|
+
await putDisplayFiles(t, displayFiles);
|
|
503
|
+
await t
|
|
504
|
+
.insertInto("plugin_import_staging")
|
|
505
|
+
.values({
|
|
506
|
+
id: stagingId,
|
|
507
|
+
review: JSON.stringify(review),
|
|
508
|
+
manifest: JSON.stringify(staged),
|
|
509
|
+
object_prefix: objectPrefix,
|
|
510
|
+
source: JSON.stringify(src),
|
|
511
|
+
created_by: actor,
|
|
512
|
+
expires_at: new Date(Date.now() + PLUGIN_STAGING_TTL_MS),
|
|
513
|
+
// the org's own staging (P3-8); null = the super admin's
|
|
514
|
+
org_id: owner?.orgId ?? null,
|
|
515
|
+
})
|
|
516
|
+
.execute();
|
|
517
|
+
await audit(t, {
|
|
518
|
+
...(actor !== null && { actorAccountId: actor }),
|
|
519
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
520
|
+
action: "catalog.plugin_staged",
|
|
521
|
+
target: stagingId,
|
|
522
|
+
detail: {
|
|
523
|
+
stagingId,
|
|
524
|
+
name: review.name,
|
|
525
|
+
version: staged.version,
|
|
526
|
+
source: src.kind,
|
|
527
|
+
sourceRef: src.ref,
|
|
528
|
+
...(src.integrity !== undefined && { integrity: src.integrity }),
|
|
529
|
+
...(src.marketplaceId !== undefined && { marketplaceId: src.marketplaceId }),
|
|
530
|
+
reviewHash: review.reviewHash,
|
|
531
|
+
...(extension && {
|
|
532
|
+
extension: { sha256: extension.sha256, action: extension.action },
|
|
533
|
+
}),
|
|
534
|
+
...(owner !== undefined && { orgId: owner.orgId }),
|
|
535
|
+
...opts.auditDetail,
|
|
536
|
+
},
|
|
537
|
+
});
|
|
538
|
+
}
|
|
361
539
|
/** Fetches a plugin from the configured npm registry (verified by `dist.integrity`), then prepares it. */
|
|
362
540
|
async prepareNpm(actor, input, opts = {}) {
|
|
363
|
-
const got = await this.
|
|
364
|
-
const provenance = await this.
|
|
541
|
+
const got = await this.installs.fetchNpm(input);
|
|
542
|
+
const provenance = await this.installs.fetchProvenance({
|
|
365
543
|
package: input.package,
|
|
366
544
|
version: got.version,
|
|
367
545
|
integrity: got.integrity,
|
|
@@ -370,23 +548,25 @@ export class PluginImport {
|
|
|
370
548
|
kind: "npm",
|
|
371
549
|
ref: `${input.package}@${got.version}`,
|
|
372
550
|
integrity: got.integrity,
|
|
373
|
-
detail: { registry: new URL(this.
|
|
551
|
+
detail: { registry: new URL(this.config.get().packages.npmRegistry).origin },
|
|
374
552
|
}, { ...opts, expect: { packageName: input.package }, provenance: { provenance } });
|
|
375
553
|
return { stagingId: r.stagingId, review: r.review };
|
|
376
554
|
}
|
|
377
555
|
/**
|
|
378
556
|
* A staged import's review, as prepare returned it, with a marketplace import's permission
|
|
379
557
|
* mismatch when there is one (the import page loads `?staging=<id>` with it). Unknown, expired or
|
|
380
|
-
* already confirmed -> 404 `plugin.staging_not_found`.
|
|
558
|
+
* already confirmed -> 404 `plugin.staging_not_found`. Each sees only its own staging (P3-8):
|
|
559
|
+
* the super admin's routes the platform's (no `owner`), an org's routes that org's.
|
|
381
560
|
*/
|
|
382
|
-
async staged(stagingId) {
|
|
561
|
+
async staged(stagingId, owner) {
|
|
383
562
|
if (!UUID_RE.test(stagingId))
|
|
384
563
|
throw notFound();
|
|
385
|
-
const row = await this.
|
|
564
|
+
const row = await this.db
|
|
386
565
|
.selectFrom("plugin_import_staging")
|
|
387
566
|
.select(["id", "review", "manifest"])
|
|
388
567
|
.where("id", "=", stagingId)
|
|
389
568
|
.where("expires_at", ">", sql `now()`)
|
|
569
|
+
.where(ownStaging(owner))
|
|
390
570
|
.executeTakeFirst();
|
|
391
571
|
if (!row)
|
|
392
572
|
throw notFound();
|
|
@@ -398,107 +578,468 @@ export class PluginImport {
|
|
|
398
578
|
};
|
|
399
579
|
}
|
|
400
580
|
/**
|
|
401
|
-
*
|
|
402
|
-
*
|
|
581
|
+
* What an org's staged upload targets (P3-12, pre-flight F3): its item, version and review hash,
|
|
582
|
+
* whether the item exists (a new version of the org's own plugin) or the version is imported
|
|
583
|
+
* already (F4), and the target as the platform updater reads it: the staged manifest and files,
|
|
584
|
+
* or the imported version's for a retry. Another org's staging -> 404 `plugin.staging_not_found`.
|
|
585
|
+
*/
|
|
586
|
+
async stagedTarget(stagingId, owner) {
|
|
587
|
+
if (!UUID_RE.test(stagingId))
|
|
588
|
+
throw notFound();
|
|
589
|
+
const row = await this.db
|
|
590
|
+
.selectFrom("plugin_import_staging")
|
|
591
|
+
.select(["review", "manifest", "object_prefix"])
|
|
592
|
+
.where("id", "=", stagingId)
|
|
593
|
+
.where("expires_at", ">", sql `now()`)
|
|
594
|
+
.where(ownStaging(owner))
|
|
595
|
+
.executeTakeFirst();
|
|
596
|
+
if (!row)
|
|
597
|
+
throw notFound();
|
|
598
|
+
const review = row.review;
|
|
599
|
+
const staged = row.manifest;
|
|
600
|
+
const item = await this.db
|
|
601
|
+
.selectFrom("catalog_items")
|
|
602
|
+
.select(["id", "awaiting_confirmation"])
|
|
603
|
+
.where("id", "=", staged.itemId)
|
|
604
|
+
.where("deleted_at", "is", null)
|
|
605
|
+
.where("owner_org_id", "=", owner.orgId)
|
|
606
|
+
.executeTakeFirst();
|
|
607
|
+
const imported = staged.retry === true
|
|
608
|
+
? await this.db
|
|
609
|
+
.selectFrom("catalog_item_versions")
|
|
610
|
+
.select(["version", "manifest", "object_prefix", "files", "extension_sha256"])
|
|
611
|
+
.where("item_id", "=", staged.itemId)
|
|
612
|
+
.where("version", "=", staged.version)
|
|
613
|
+
.executeTakeFirst()
|
|
614
|
+
: undefined;
|
|
615
|
+
return {
|
|
616
|
+
itemId: staged.itemId,
|
|
617
|
+
version: staged.version,
|
|
618
|
+
reviewHash: review.reviewHash,
|
|
619
|
+
extension: review.extension !== undefined,
|
|
620
|
+
existing: item !== undefined,
|
|
621
|
+
awaiting: item?.awaiting_confirmation === true,
|
|
622
|
+
retry: staged.retry === true,
|
|
623
|
+
target: imported !== undefined
|
|
624
|
+
? {
|
|
625
|
+
version: imported.version,
|
|
626
|
+
manifest: imported.manifest,
|
|
627
|
+
object_prefix: imported.object_prefix,
|
|
628
|
+
files: imported.files,
|
|
629
|
+
extension_sha256: imported.extension_sha256,
|
|
630
|
+
}
|
|
631
|
+
: {
|
|
632
|
+
version: staged.version,
|
|
633
|
+
manifest: staged.manifest,
|
|
634
|
+
object_prefix: row.object_prefix,
|
|
635
|
+
files: staged.files,
|
|
636
|
+
extension_sha256: review.extension?.sha256 ?? null,
|
|
637
|
+
},
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
/** The catalog item's view (as a confirm returns it). */
|
|
641
|
+
async view(itemId) {
|
|
642
|
+
return this.itemView(itemId);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Confirms a staged import (see the file header). Returns the committed catalog item and the
|
|
646
|
+
* extension's deploy result (a failed deploy is returned, not thrown). `scope` (default
|
|
647
|
+
* `optional`) and `orgs` (only with `named`; each an existing org, else `validation_failed`) are
|
|
648
|
+
* written when this confirm creates the item; a new version of an existing item keeps its scope.
|
|
649
|
+
* The caller enqueues the scope sync of the item after this returns.
|
|
650
|
+
*
|
|
651
|
+
* An org upload (`opts.owner`, spec §14): only that org's staging; the actor re-checked as its
|
|
652
|
+
* admin; `scope` / `orgs` are not taken: a new item is owned by the org, scope `named: [owner]`,
|
|
653
|
+
* not shown to other orgs, `shareable` as given (default false). Custom deny, the name owner and
|
|
654
|
+
* the dependencies are checked again under the item name's lock. A package with an extension
|
|
655
|
+
* is stored and its extension name claimed, nothing approved or installed: the version waits
|
|
656
|
+
* for the super admin (`pending`, ruling P3-10; see {@link commit}).
|
|
403
657
|
*/
|
|
404
658
|
async confirm(actor, stagingId, input, opts = {}) {
|
|
405
659
|
if (!UUID_RE.test(stagingId))
|
|
406
660
|
throw notFound();
|
|
407
|
-
const
|
|
661
|
+
const owner = opts.owner;
|
|
662
|
+
if (owner !== undefined && (input.scope !== undefined || input.orgs !== undefined)) {
|
|
663
|
+
throw new Error("an org upload's scope is its owner's");
|
|
664
|
+
}
|
|
665
|
+
// A staging prepared by approving an org's `import` request defaults to that org (spec §5.1
|
|
666
|
+
// rule 3); the admin may still choose any scope
|
|
667
|
+
const linked = input.scope === undefined && owner === undefined
|
|
668
|
+
? await importRequestOf(this.db, stagingId)
|
|
669
|
+
: undefined;
|
|
670
|
+
const scope = owner !== undefined
|
|
671
|
+
? "named"
|
|
672
|
+
: (input.scope ?? (linked !== undefined ? "named" : "optional"));
|
|
673
|
+
const orgs = owner !== undefined
|
|
674
|
+
? [owner.orgId]
|
|
675
|
+
: (input.orgs ?? (linked !== undefined ? [linked.orgId] : undefined));
|
|
676
|
+
if (input.orgs !== undefined && scope !== "named") {
|
|
677
|
+
throw new ApiError("validation_failed", "orgs: only allowed with scope named", [
|
|
678
|
+
{ path: "orgs", message: "only allowed with scope named" },
|
|
679
|
+
]);
|
|
680
|
+
}
|
|
681
|
+
if (scope === "named" && (orgs ?? []).length === 0) {
|
|
682
|
+
throw new ApiError("validation_failed", "orgs: scope named needs at least one organization", [
|
|
683
|
+
{ path: "orgs", message: "scope named needs at least one organization" },
|
|
684
|
+
]);
|
|
685
|
+
}
|
|
686
|
+
const row = await this.db
|
|
408
687
|
.selectFrom("plugin_import_staging")
|
|
409
688
|
.selectAll()
|
|
410
689
|
.where("id", "=", stagingId)
|
|
411
690
|
.where("expires_at", ">", sql `now()`)
|
|
691
|
+
.where(ownStaging(owner))
|
|
412
692
|
.executeTakeFirst();
|
|
413
693
|
if (!row)
|
|
414
694
|
throw notFound();
|
|
415
695
|
const review = row.review;
|
|
416
696
|
const staged = row.manifest;
|
|
417
697
|
const src = row.source;
|
|
418
|
-
const stale = () => new ApiError("plugin.review_stale", `The review of plugin ${review.name} ${review.version} is out of date (it changed, or its extension on this deployment changed since it was prepared); review it again`);
|
|
419
698
|
if (input.reviewHash !== review.reviewHash)
|
|
420
|
-
throw
|
|
699
|
+
throw reviewStale(review);
|
|
421
700
|
const manifest = withPinned(staged.manifest, review, input.pinnedSuggestions);
|
|
422
701
|
const reviewed = review.extension;
|
|
423
|
-
// Read the stored package outside the transaction (unless it was already installed as is
|
|
424
|
-
|
|
425
|
-
const
|
|
426
|
-
await
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (!used)
|
|
434
|
-
throw notFound();
|
|
435
|
-
let now;
|
|
436
|
-
let previous;
|
|
437
|
-
if (reviewed) {
|
|
438
|
-
// The same per-name advisory lock as ExtensionAdminOps.install; under it the action is
|
|
439
|
-
// recomputed from the current deployment state (installed / upgraded / swapped since the
|
|
440
|
-
// review -> stale)
|
|
441
|
-
await sql `SELECT pg_advisory_xact_lock(hashtext(${`capybara.plugin-install:${reviewed.name}`}))`.execute(trx);
|
|
442
|
-
now = {
|
|
443
|
-
...reviewed,
|
|
444
|
-
...actionOf(await this.extensionState(reviewed.name, staged.packageName, trx), reviewed.sha256),
|
|
445
|
-
};
|
|
446
|
-
if (pluginReviewHash({ ...review, extension: now }, staged.files) !== review.reviewHash) {
|
|
447
|
-
throw stale();
|
|
448
|
-
}
|
|
449
|
-
// A foreseeable deploy failure (a downgrade to a version with unrun migrations) is refused
|
|
450
|
-
// before anything is written
|
|
451
|
-
if (input.deployExtension && now.action === "upgrade" && stored) {
|
|
452
|
-
await assertDowngradable(trx, now, stored.migrationSql);
|
|
453
|
-
}
|
|
454
|
-
if (now.action === "install" || (now.action === "upgrade" && input.deployExtension)) {
|
|
455
|
-
previous = await this.approve(trx, actor, review, staged, now, stored, opts);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
const m = manifest;
|
|
459
|
-
const itemId = await writeCatalogVersion(trx, {
|
|
460
|
-
actor,
|
|
461
|
-
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
462
|
-
name: m.name,
|
|
463
|
-
packageName: staged.packageName,
|
|
464
|
-
version: staged.version,
|
|
465
|
-
contentDigest: staged.contentDigest,
|
|
466
|
-
manifest: m,
|
|
467
|
-
listing: {
|
|
468
|
-
publisher: m.publisher,
|
|
469
|
-
description: m.description,
|
|
470
|
-
displayName: m.displayName ?? null,
|
|
471
|
-
},
|
|
472
|
-
newItemId: staged.itemId,
|
|
473
|
-
source: {
|
|
474
|
-
source: src.kind,
|
|
475
|
-
ref: src.ref,
|
|
476
|
-
...(src.integrity !== undefined && { integrity: src.integrity }),
|
|
477
|
-
...(src.detail !== undefined && { detail: src.detail }),
|
|
478
|
-
},
|
|
479
|
-
...(src.marketplaceId !== undefined && { marketplaceId: src.marketplaceId }),
|
|
480
|
-
objectPrefix: row.object_prefix,
|
|
481
|
-
extensionSha256: reviewed?.sha256 ?? null,
|
|
482
|
-
files: staged.files,
|
|
483
|
-
size: staged.size,
|
|
484
|
-
sourceFormat: staged.sourceFormat ?? "capybara",
|
|
485
|
-
translation: staged.translation ?? null,
|
|
486
|
-
licenseText: staged.licenseText ?? null,
|
|
487
|
-
licenseTruncated: staged.licenseTruncated === true,
|
|
488
|
-
auditDetail: {
|
|
489
|
-
stagingId,
|
|
490
|
-
deployExtension: input.deployExtension,
|
|
491
|
-
suggestedPinned: pinnedNames(manifest, review),
|
|
492
|
-
...(now && { extension: { name: now.name, version: now.version, action: now.action } }),
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
return { itemId, now, previous };
|
|
496
|
-
});
|
|
702
|
+
// Read the stored package outside the transaction (unless it was already installed as is, or
|
|
703
|
+
// an org upload, which approves nothing)
|
|
704
|
+
const stored = reviewed && reviewed.action !== "keep" && owner === undefined
|
|
705
|
+
? await this.readStored(reviewed.sha256)
|
|
706
|
+
: undefined;
|
|
707
|
+
const committed = await this.commit(actor, { stagingId, review, staged, src, manifest, objectPrefix: row.object_prefix }, {
|
|
708
|
+
scope,
|
|
709
|
+
orgs: [...new Set(orgs ?? [])].sort(),
|
|
710
|
+
...(owner !== undefined && { owner, shareable: input.shareable ?? false }),
|
|
711
|
+
}, stored, opts);
|
|
497
712
|
const { now } = committed;
|
|
498
|
-
|
|
713
|
+
if (committed.pending) {
|
|
714
|
+
// Waits for the super admin (P3-10): no platform components, nothing deployed
|
|
715
|
+
return {
|
|
716
|
+
item: await this.itemView(committed.itemId),
|
|
717
|
+
created: committed.created,
|
|
718
|
+
deploy: null,
|
|
719
|
+
pending: true,
|
|
720
|
+
firstVersion: false,
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
// A new item's skills, agent templates and connector templates become platform components
|
|
724
|
+
// (plugin scope phase 2); a new version of an existing item leaves them to the platform
|
|
725
|
+
// update. After the commit: it copies files in object storage
|
|
726
|
+
if (committed.firstVersion)
|
|
727
|
+
await this.syncPlatform(committed.itemId, staged.version);
|
|
728
|
+
const deploy = now && now.action !== "keep"
|
|
499
729
|
? await this.deploy(actor, review, committed.itemId, now, committed.previous, opts, input.enable ?? true)
|
|
500
730
|
: null;
|
|
501
|
-
return {
|
|
731
|
+
return {
|
|
732
|
+
item: await this.itemView(committed.itemId),
|
|
733
|
+
created: committed.created,
|
|
734
|
+
deploy,
|
|
735
|
+
pending: false,
|
|
736
|
+
firstVersion: committed.firstVersion,
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
/**
|
|
740
|
+
* Writes the platform components of an item's first usable version after a commit made
|
|
741
|
+
* elsewhere (the super admin's confirmation of an org upload, `CatalogScopeService`); a failure
|
|
742
|
+
* is logged and retried by the migration job (see {@link syncPlatform}).
|
|
743
|
+
*/
|
|
744
|
+
async writePlatformComponents(itemId, version) {
|
|
745
|
+
await this.syncPlatform(itemId, version);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* The confirm's transaction: the staging row consumed, the extension's action recomputed under
|
|
749
|
+
* its install lock (stale -> `plugin.review_stale`), its snapshot approved, and the catalog
|
|
750
|
+
* version written under the item name's lock.
|
|
751
|
+
*
|
|
752
|
+
* An org upload with an extension (ruling P3-10) approves nothing: under the install lock it
|
|
753
|
+
* claims the extension name for its package (another package's -> 409
|
|
754
|
+
* `extension.name_conflict` naming its owner, before anything is written), and the version
|
|
755
|
+
* written becomes the item's pending one (`pending_version` / `_by` / `_at`; a first version
|
|
756
|
+
* also `awaiting_confirmation`). A later upload replaces the pending version (P3-11). An org
|
|
757
|
+
* upload without an extension for an item whose first version still waits (plan Task 6) replaces
|
|
758
|
+
* that upload and applies at once: the item stops waiting and the claim is released (nothing
|
|
759
|
+
* was installed under it).
|
|
760
|
+
*/
|
|
761
|
+
async commit(actor, c, scope, stored, opts) {
|
|
762
|
+
const { stagingId, review, staged, src, manifest } = c;
|
|
763
|
+
const reviewed = review.extension;
|
|
764
|
+
const stale = () => reviewStale(review);
|
|
765
|
+
const { owner } = scope;
|
|
766
|
+
await this.authorizeActor(actor, owner);
|
|
767
|
+
const t = this.db;
|
|
768
|
+
const used = await t
|
|
769
|
+
.deleteFrom("plugin_import_staging")
|
|
770
|
+
.where("id", "=", stagingId)
|
|
771
|
+
.where("expires_at", ">", sql `now()`)
|
|
772
|
+
.where(ownStaging(owner))
|
|
773
|
+
.returning("id")
|
|
774
|
+
.executeTakeFirst();
|
|
775
|
+
if (!used)
|
|
776
|
+
throw notFound();
|
|
777
|
+
if (owner !== undefined) {
|
|
778
|
+
await assertCustomContent(t, {
|
|
779
|
+
skills: review.skills,
|
|
780
|
+
agentTemplates: review.agentTemplates ?? [],
|
|
781
|
+
templates: review.connectorTemplates,
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
await assertOrgsExist(t, scope.orgs);
|
|
785
|
+
// Checked again before this upload claims anything (ruling P3-51)
|
|
786
|
+
if (owner !== undefined)
|
|
787
|
+
await assertPackageFree(t, staged.packageName, owner.orgId);
|
|
788
|
+
let now;
|
|
789
|
+
let previous;
|
|
790
|
+
if (reviewed) {
|
|
791
|
+
// The same per-name advisory lock as ExtensionAdminOps.install; under it the action is
|
|
792
|
+
// recomputed from the current deployment state (installed / upgraded / swapped since the
|
|
793
|
+
// review -> stale)
|
|
794
|
+
await this.installLock.lock(reviewed.name);
|
|
795
|
+
now = {
|
|
796
|
+
...reviewed,
|
|
797
|
+
...actionOf(await this.extensionState(reviewed.name, staged.packageName), reviewed.sha256, reviewed.version),
|
|
798
|
+
};
|
|
799
|
+
if (pluginReviewHash({ ...review, extension: now }, staged.files) !== review.reviewHash) {
|
|
800
|
+
throw stale();
|
|
801
|
+
}
|
|
802
|
+
if (owner !== undefined) {
|
|
803
|
+
// An org upload only claims the name (P3-10): the super admin approves and installs it
|
|
804
|
+
await t
|
|
805
|
+
.insertInto("extension_name_owners")
|
|
806
|
+
.values({ name: reviewed.name, package_name: staged.packageName })
|
|
807
|
+
.onConflict((oc) => oc.column("name").doNothing())
|
|
808
|
+
.execute();
|
|
809
|
+
await assertPluginNameOwner(t, reviewed.name, staged.packageName);
|
|
810
|
+
}
|
|
811
|
+
// A foreseeable deploy failure (a downgrade to a version with unrun migrations) is refused
|
|
812
|
+
// before anything is written
|
|
813
|
+
if (now.action === "upgrade" && stored) {
|
|
814
|
+
await assertDowngradable(t, now, stored.migrationSql);
|
|
815
|
+
}
|
|
816
|
+
if (owner === undefined && (now.action === "install" || now.action === "upgrade")) {
|
|
817
|
+
previous = await this.approve(actor, review, staged, now, stored, opts);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
const m = manifest;
|
|
821
|
+
await this.itemLock.lock(m.name);
|
|
822
|
+
// Under the name's lock: the first confirm of a name wins, a later one of another owner is
|
|
823
|
+
// refused naming it, before anything of it is written (P3-14)
|
|
824
|
+
await assertNameFree(t, m.name, owner?.orgId ?? null);
|
|
825
|
+
if (owner !== undefined) {
|
|
826
|
+
await assertNameNotReserved(t, m.name);
|
|
827
|
+
await this.resolveDependencies(m, owner);
|
|
828
|
+
}
|
|
829
|
+
// The scope the audit records: the review's for a new item, the item's own for a new version
|
|
830
|
+
// of a live item (which keeps its scope)
|
|
831
|
+
const existing = await t
|
|
832
|
+
.selectFrom("catalog_items")
|
|
833
|
+
.select(["id", "scope", "awaiting_confirmation", "package_name"])
|
|
834
|
+
.where("name", "=", m.name)
|
|
835
|
+
.where("deleted_at", "is", null)
|
|
836
|
+
.forUpdate()
|
|
837
|
+
.executeTakeFirst();
|
|
838
|
+
const actual = existing === undefined
|
|
839
|
+
? scope
|
|
840
|
+
: {
|
|
841
|
+
scope: existing.scope,
|
|
842
|
+
orgs: (await t
|
|
843
|
+
.selectFrom("catalog_item_scope_orgs")
|
|
844
|
+
.select("org_id")
|
|
845
|
+
.where("item_id", "=", existing.id)
|
|
846
|
+
.orderBy("org_id")
|
|
847
|
+
.execute()).map((r) => r.org_id),
|
|
848
|
+
};
|
|
849
|
+
if (staged.retry === true) {
|
|
850
|
+
// An org's own version imported already (pre-flight F4): nothing to write, the caller
|
|
851
|
+
// retries its update; it must still be there as reviewed
|
|
852
|
+
const v = existing === undefined
|
|
853
|
+
? undefined
|
|
854
|
+
: await t
|
|
855
|
+
.selectFrom("catalog_item_versions")
|
|
856
|
+
.select("version")
|
|
857
|
+
.where("item_id", "=", existing.id)
|
|
858
|
+
.where("version", "=", staged.version)
|
|
859
|
+
.where("content_digest", "=", staged.contentDigest)
|
|
860
|
+
.executeTakeFirst();
|
|
861
|
+
if (existing === undefined || existing.id !== staged.itemId || v === undefined)
|
|
862
|
+
throw stale();
|
|
863
|
+
return {
|
|
864
|
+
itemId: existing.id,
|
|
865
|
+
created: false,
|
|
866
|
+
firstVersion: false,
|
|
867
|
+
pending: false,
|
|
868
|
+
now,
|
|
869
|
+
previous,
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
const { id: itemId, created } = await writeCatalogVersion(t, {
|
|
873
|
+
// an org's version becomes its latest only when applied or confirmed (P3-34)
|
|
874
|
+
...(owner !== undefined && { keepLatest: true }),
|
|
875
|
+
actor,
|
|
876
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
877
|
+
name: m.name,
|
|
878
|
+
packageName: staged.packageName,
|
|
879
|
+
version: staged.version,
|
|
880
|
+
contentDigest: staged.contentDigest,
|
|
881
|
+
manifest: m,
|
|
882
|
+
listing: {
|
|
883
|
+
publisher: m.publisher,
|
|
884
|
+
description: pluginDescription(m.description).en,
|
|
885
|
+
displayName: m.displayName ?? null,
|
|
886
|
+
},
|
|
887
|
+
newItemId: staged.itemId,
|
|
888
|
+
source: {
|
|
889
|
+
source: src.kind,
|
|
890
|
+
ref: src.ref,
|
|
891
|
+
...(src.integrity !== undefined && { integrity: src.integrity }),
|
|
892
|
+
...(src.detail !== undefined && { detail: src.detail }),
|
|
893
|
+
},
|
|
894
|
+
...(src.marketplaceId !== undefined && { marketplaceId: src.marketplaceId }),
|
|
895
|
+
objectPrefix: c.objectPrefix,
|
|
896
|
+
extensionSha256: reviewed?.sha256 ?? null,
|
|
897
|
+
files: staged.files,
|
|
898
|
+
size: staged.size,
|
|
899
|
+
sourceFormat: staged.sourceFormat ?? "capybara",
|
|
900
|
+
translation: staged.translation ?? null,
|
|
901
|
+
licenseText: staged.licenseText ?? null,
|
|
902
|
+
licenseTruncated: staged.licenseTruncated === true,
|
|
903
|
+
auditDetail: {
|
|
904
|
+
stagingId,
|
|
905
|
+
scope: actual.scope,
|
|
906
|
+
...(actual.scope === "named" && { orgs: actual.orgs }),
|
|
907
|
+
suggestedPinned: pinnedNames(manifest, review),
|
|
908
|
+
...(now && { extension: { name: now.name, version: now.version, action: now.action } }),
|
|
909
|
+
},
|
|
910
|
+
});
|
|
911
|
+
// A new item gets the scope chosen in the review; a new version keeps the item's scope, its
|
|
912
|
+
// org list and its scope version (prepare reuses the live item's id, so the id cannot tell)
|
|
913
|
+
if (created) {
|
|
914
|
+
await t
|
|
915
|
+
.updateTable("catalog_items")
|
|
916
|
+
.set({
|
|
917
|
+
scope: scope.scope,
|
|
918
|
+
// an org upload: the org owns it, nobody else sees it until shared and shown (P3-16)
|
|
919
|
+
...(owner !== undefined && {
|
|
920
|
+
owner_org_id: owner.orgId,
|
|
921
|
+
shareable: scope.shareable === true,
|
|
922
|
+
shown_to_others: false,
|
|
923
|
+
}),
|
|
924
|
+
})
|
|
925
|
+
.where("id", "=", itemId)
|
|
926
|
+
.execute();
|
|
927
|
+
if (scope.scope === "named" && scope.orgs.length > 0) {
|
|
928
|
+
await t
|
|
929
|
+
.insertInto("catalog_item_scope_orgs")
|
|
930
|
+
.values(scope.orgs.map((org_id) => ({ item_id: itemId, org_id })))
|
|
931
|
+
.onConflict((oc) => oc.doNothing())
|
|
932
|
+
.execute();
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
// The org requests this staging answers resolve with the confirm; on an item that existed
|
|
936
|
+
// already (imported meanwhile) a `named` scope gains their orgs. An org-owned item held back by
|
|
937
|
+
// the share gate fails closed before any request is marked (ruling P3-26; P3-14 refuses a
|
|
938
|
+
// super admin import of an org-owned name, so this should not be reached)
|
|
939
|
+
const item = created
|
|
940
|
+
? undefined
|
|
941
|
+
: await t
|
|
942
|
+
.selectFrom("catalog_items")
|
|
943
|
+
.select(["id", "name", "scope", "builtin", "owner_org_id", "shareable"])
|
|
944
|
+
.where("id", "=", itemId)
|
|
945
|
+
.forUpdate()
|
|
946
|
+
.executeTakeFirstOrThrow();
|
|
947
|
+
if (item !== undefined && !shareGate(item) && (await hasImportRequests(t, stagingId))) {
|
|
948
|
+
assertShareable(item);
|
|
949
|
+
}
|
|
950
|
+
const requestOrgs = await resolveImportRequests(t, stagingId, itemId, actor, opts);
|
|
951
|
+
if (item !== undefined) {
|
|
952
|
+
for (const org of requestOrgs)
|
|
953
|
+
await addScopeOrg(t, actor, item, org, opts);
|
|
954
|
+
}
|
|
955
|
+
const pending = owner !== undefined && reviewed !== undefined;
|
|
956
|
+
// An org's first version without an extension is installed at once: applied (P3-52)
|
|
957
|
+
if (owner !== undefined && created && !pending)
|
|
958
|
+
await markVersionApplied(t, itemId, staged.version);
|
|
959
|
+
if (pending) {
|
|
960
|
+
// Waits for the super admin; a later upload replaces the pending version (P3-10, P3-11)
|
|
961
|
+
await t
|
|
962
|
+
.updateTable("catalog_items")
|
|
963
|
+
.set({
|
|
964
|
+
...(created && { awaiting_confirmation: true }),
|
|
965
|
+
pending_version: staged.version,
|
|
966
|
+
pending_by: actor,
|
|
967
|
+
pending_at: sql `now()`,
|
|
968
|
+
})
|
|
969
|
+
.where("id", "=", itemId)
|
|
970
|
+
.execute();
|
|
971
|
+
}
|
|
972
|
+
// A first version still waiting replaced by one without an extension: applied at once
|
|
973
|
+
const replacedAwaiting = owner !== undefined && !pending && existing?.awaiting_confirmation === true;
|
|
974
|
+
if (replacedAwaiting) {
|
|
975
|
+
await t
|
|
976
|
+
.updateTable("catalog_items")
|
|
977
|
+
.set({
|
|
978
|
+
awaiting_confirmation: false,
|
|
979
|
+
pending_version: null,
|
|
980
|
+
pending_by: null,
|
|
981
|
+
pending_at: null,
|
|
982
|
+
latest_version: staged.version,
|
|
983
|
+
})
|
|
984
|
+
.where("id", "=", itemId)
|
|
985
|
+
.execute();
|
|
986
|
+
await markVersionApplied(t, itemId, staged.version);
|
|
987
|
+
await releaseExtensionClaim(t, m.name, existing.package_name);
|
|
988
|
+
}
|
|
989
|
+
return {
|
|
990
|
+
itemId,
|
|
991
|
+
created,
|
|
992
|
+
firstVersion: (created && !pending) || replacedAwaiting,
|
|
993
|
+
pending,
|
|
994
|
+
now,
|
|
995
|
+
previous,
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* The platform components of a new item. The item is committed already, so a failure is logged
|
|
1000
|
+
* and not thrown (like a failed deploy, the import itself succeeded); a run of the platform
|
|
1001
|
+
* components migration job (which writes what is missing) is enqueued on `cap-kernel-maintenance`
|
|
1002
|
+
* after {@link PLATFORM_SYNC_RETRY_MS}, one per item (deterministic job id). If that run fails
|
|
1003
|
+
* too, its `itemsFailed` shows in the super admin's inbox; the daily run and every worker start
|
|
1004
|
+
* try again.
|
|
1005
|
+
*/
|
|
1006
|
+
async syncPlatform(itemId, version) {
|
|
1007
|
+
try {
|
|
1008
|
+
await this.platform.syncFromVersion(itemId, version, { initial: true });
|
|
1009
|
+
}
|
|
1010
|
+
catch (err) {
|
|
1011
|
+
// Removed meanwhile (an org deletion racing a confirmation, P3-20): nothing to write
|
|
1012
|
+
const live = await this.db
|
|
1013
|
+
.selectFrom("catalog_items")
|
|
1014
|
+
.select("id")
|
|
1015
|
+
.where("id", "=", itemId)
|
|
1016
|
+
.where("deleted_at", "is", null)
|
|
1017
|
+
.executeTakeFirst();
|
|
1018
|
+
if (live === undefined) {
|
|
1019
|
+
this.log.info("catalog item removed before its platform components were written", {
|
|
1020
|
+
itemId,
|
|
1021
|
+
version,
|
|
1022
|
+
});
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
this.log.error("writing the platform components of a new catalog item failed", {
|
|
1026
|
+
itemId,
|
|
1027
|
+
version,
|
|
1028
|
+
err,
|
|
1029
|
+
});
|
|
1030
|
+
try {
|
|
1031
|
+
await this.maintenance.add(PLATFORM_MIGRATION_JOB, {}, {
|
|
1032
|
+
jobId: `${PLATFORM_MIGRATION_JOB}-retry-${itemId}`,
|
|
1033
|
+
delay: PLATFORM_SYNC_RETRY_MS,
|
|
1034
|
+
attempts: 1,
|
|
1035
|
+
removeOnComplete: true,
|
|
1036
|
+
removeOnFail: { age: 86_400 },
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
catch (e) {
|
|
1040
|
+
this.log.warn("cannot enqueue the platform components migration", { itemId, err: e });
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
502
1043
|
}
|
|
503
1044
|
/**
|
|
504
1045
|
* Writes the extension's permission snapshot for the version being imported (source web; cli
|
|
@@ -506,23 +1047,24 @@ export class PluginImport {
|
|
|
506
1047
|
* registering the name owner like ExtensionAdminOps.install (Ruling P3). Returns the snapshot it
|
|
507
1048
|
* overwrote (null when there was none).
|
|
508
1049
|
*/
|
|
509
|
-
async approve(
|
|
1050
|
+
async approve(actor, review, staged, p, pkg, opts) {
|
|
510
1051
|
const set = permissionSetOfPackage(pkg);
|
|
511
|
-
await
|
|
512
|
-
const
|
|
1052
|
+
await this.approveLock.lock(p.name);
|
|
1053
|
+
const t = this.db;
|
|
1054
|
+
const snapRow = await t
|
|
513
1055
|
.selectFrom("extension_permission_snapshots")
|
|
514
1056
|
.selectAll()
|
|
515
1057
|
.where("plugin", "=", p.name)
|
|
516
1058
|
.forUpdate()
|
|
517
1059
|
.executeTakeFirst();
|
|
518
|
-
await
|
|
1060
|
+
await t
|
|
519
1061
|
.insertInto("extension_name_owners")
|
|
520
1062
|
.values({ name: p.name, package_name: staged.packageName })
|
|
521
1063
|
.onConflict((oc) => oc.column("name").doNothing())
|
|
522
1064
|
.execute();
|
|
523
|
-
await assertPluginNameOwner(
|
|
1065
|
+
await assertPluginNameOwner(t, p.name, staged.packageName);
|
|
524
1066
|
const { added, removed } = diffPermissions(snapRow?.permissions, set);
|
|
525
|
-
await writeSnapshot(
|
|
1067
|
+
await writeSnapshot(t, p.name, p.version, set, {
|
|
526
1068
|
source: review.source.kind === "bootstrap" ? "bootstrap" : actor === null ? "cli" : "web",
|
|
527
1069
|
approvedBy: actor,
|
|
528
1070
|
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
@@ -545,7 +1087,9 @@ export class PluginImport {
|
|
|
545
1087
|
}
|
|
546
1088
|
/**
|
|
547
1089
|
* Deploys the plugin's extension after the commit: `install` (a new install is disabled, a version
|
|
548
|
-
* change keeps the desired state) then `enable
|
|
1090
|
+
* change keeps the desired state) then `enable`, unless another enabled extension provides one of
|
|
1091
|
+
* its single-provider extension points: then it stays disabled (result `installed` with code
|
|
1092
|
+
* `extension.single_provider_enabled`). Nothing is thrown; the result says what happened.
|
|
549
1093
|
* When an upgrade was not installed, the snapshot overwritten at confirm is restored (the old
|
|
550
1094
|
* version keeps running, F-O; audit `extension.permissions_restored`). Retry through the extension
|
|
551
1095
|
* admin (the package is already in the package store) with the sha256 from the result.
|
|
@@ -560,13 +1104,14 @@ export class PluginImport {
|
|
|
560
1104
|
const failure = (e) => e instanceof ApiError
|
|
561
1105
|
? { code: e.code, message: e.message }
|
|
562
1106
|
: { code: "internal", message: "Internal error" };
|
|
1107
|
+
let installed;
|
|
563
1108
|
try {
|
|
564
|
-
await this.
|
|
1109
|
+
installed = await this.ops.install(p.name, p.sha256, actor, opts.actorTokenId, {
|
|
565
1110
|
catalogItemId: itemId,
|
|
566
1111
|
});
|
|
567
1112
|
}
|
|
568
1113
|
catch (e) {
|
|
569
|
-
this.
|
|
1114
|
+
this.log.warn("installing a plugin's extension on the deployment failed", {
|
|
570
1115
|
plugin: review.name,
|
|
571
1116
|
err: e,
|
|
572
1117
|
});
|
|
@@ -579,7 +1124,7 @@ export class PluginImport {
|
|
|
579
1124
|
}
|
|
580
1125
|
}
|
|
581
1126
|
catch (err) {
|
|
582
|
-
this.
|
|
1127
|
+
this.log.error("cannot restore the permission snapshot of a plugin's extension", {
|
|
583
1128
|
plugin: p.name,
|
|
584
1129
|
err,
|
|
585
1130
|
});
|
|
@@ -587,14 +1132,22 @@ export class PluginImport {
|
|
|
587
1132
|
}
|
|
588
1133
|
return result;
|
|
589
1134
|
}
|
|
1135
|
+
// An upgrade of an enabled extension that newly provides a held single-provider point: left
|
|
1136
|
+
// disabled by the install, and why
|
|
1137
|
+
if (installed.leftDisabled !== undefined) {
|
|
1138
|
+
return { ...base, result: "installed", ...installed.leftDisabled };
|
|
1139
|
+
}
|
|
590
1140
|
if (!enable)
|
|
591
1141
|
return { ...base, result: "installed" };
|
|
592
1142
|
try {
|
|
593
|
-
await this.
|
|
594
|
-
|
|
1143
|
+
const r = await this.ops.enableUnlessOccupied(p.name, actor, opts.actorTokenId);
|
|
1144
|
+
if (r.enabled)
|
|
1145
|
+
return { ...base, result: "enabled" };
|
|
1146
|
+
// A single-provider point another enabled extension provides: installed disabled, and why
|
|
1147
|
+
return { ...base, result: "installed", ...r.note };
|
|
595
1148
|
}
|
|
596
1149
|
catch (e) {
|
|
597
|
-
this.
|
|
1150
|
+
this.log.warn("enabling a plugin's extension failed", { plugin: p.name, err: e });
|
|
598
1151
|
return { ...base, result: "failed", ...failure(e) };
|
|
599
1152
|
}
|
|
600
1153
|
}
|
|
@@ -605,59 +1158,68 @@ export class PluginImport {
|
|
|
605
1158
|
* approved or changed it meanwhile it is left alone and false is returned.
|
|
606
1159
|
*/
|
|
607
1160
|
async restoreSnapshot(actor, review, p, prev, opts) {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
1161
|
+
const t = this.db;
|
|
1162
|
+
await this.approveLock.lock(p.name);
|
|
1163
|
+
const current = await t
|
|
1164
|
+
.selectFrom("extension_permission_snapshots")
|
|
1165
|
+
.select(["version", "approved_by"])
|
|
1166
|
+
.where("plugin", "=", p.name)
|
|
1167
|
+
.forUpdate()
|
|
1168
|
+
.executeTakeFirst();
|
|
1169
|
+
if (current?.version !== p.version || current.approved_by !== actor)
|
|
1170
|
+
return false;
|
|
1171
|
+
if (prev) {
|
|
1172
|
+
await t
|
|
1173
|
+
.updateTable("extension_permission_snapshots")
|
|
1174
|
+
.set({
|
|
1175
|
+
version: prev.version,
|
|
1176
|
+
permissions: JSON.stringify(prev.permissions),
|
|
1177
|
+
approved_by: prev.approvedBy,
|
|
1178
|
+
approved_at: prev.approvedAt,
|
|
1179
|
+
source: prev.source,
|
|
1180
|
+
})
|
|
613
1181
|
.where("plugin", "=", p.name)
|
|
614
|
-
.
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
}
|
|
631
|
-
else {
|
|
632
|
-
await trx
|
|
633
|
-
.deleteFrom("extension_permission_snapshots")
|
|
634
|
-
.where("plugin", "=", p.name)
|
|
635
|
-
.execute();
|
|
636
|
-
}
|
|
637
|
-
await audit(trx, {
|
|
638
|
-
...(actor !== null && { actorAccountId: actor }),
|
|
639
|
-
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
640
|
-
action: "extension.permissions_restored",
|
|
641
|
-
target: p.name,
|
|
642
|
-
detail: {
|
|
643
|
-
plugin: p.name,
|
|
644
|
-
restoredVersion: prev?.version ?? null,
|
|
645
|
-
reason: "plugin_deploy_failed",
|
|
646
|
-
app: { name: review.name, version: review.version },
|
|
647
|
-
},
|
|
648
|
-
});
|
|
649
|
-
return true;
|
|
1182
|
+
.execute();
|
|
1183
|
+
}
|
|
1184
|
+
else {
|
|
1185
|
+
await t.deleteFrom("extension_permission_snapshots").where("plugin", "=", p.name).execute();
|
|
1186
|
+
}
|
|
1187
|
+
await audit(t, {
|
|
1188
|
+
...(actor !== null && { actorAccountId: actor }),
|
|
1189
|
+
...(opts.actorTokenId !== undefined && { actorTokenId: opts.actorTokenId }),
|
|
1190
|
+
action: "extension.permissions_restored",
|
|
1191
|
+
target: p.name,
|
|
1192
|
+
detail: {
|
|
1193
|
+
plugin: p.name,
|
|
1194
|
+
restoredVersion: prev?.version ?? null,
|
|
1195
|
+
reason: "plugin_deploy_failed",
|
|
1196
|
+
app: { name: review.name, version: review.version },
|
|
1197
|
+
},
|
|
650
1198
|
});
|
|
1199
|
+
return true;
|
|
651
1200
|
}
|
|
652
1201
|
/**
|
|
653
|
-
* Deletes expired staging rows and their object prefixes (maintenance job `app-staging-cleanup`)
|
|
654
|
-
* Row by row: objects first, then the
|
|
655
|
-
*
|
|
1202
|
+
* Deletes expired staging rows and their object prefixes (maintenance job `app-staging-cleanup`),
|
|
1203
|
+
* then the unused display files ({@link sweepDisplayFiles}). Row by row: objects first, then the
|
|
1204
|
+
* row (a failed object delete keeps the row for the next round); concurrent replicas skip each
|
|
1205
|
+
* other's rows (`SKIP LOCKED`). Returns the rows deleted.
|
|
656
1206
|
*/
|
|
657
1207
|
async cleanupExpired() {
|
|
1208
|
+
const total = await this.cleanupStagingRows();
|
|
1209
|
+
// display files no version or staging lists (an abandoned import's), older than a staging
|
|
1210
|
+
try {
|
|
1211
|
+
await sweepDisplayFiles(this.db, PLUGIN_STAGING_TTL_MS);
|
|
1212
|
+
}
|
|
1213
|
+
catch (err) {
|
|
1214
|
+
this.log.warn("cannot sweep unused catalog display files", { err });
|
|
1215
|
+
}
|
|
1216
|
+
return total;
|
|
1217
|
+
}
|
|
1218
|
+
/** The expired staging rows, batch by batch; returns the rows deleted. */
|
|
1219
|
+
async cleanupStagingRows() {
|
|
658
1220
|
let total = 0;
|
|
659
1221
|
for (;;) {
|
|
660
|
-
const batch = await this.
|
|
1222
|
+
const batch = await this.db
|
|
661
1223
|
.selectFrom("plugin_import_staging")
|
|
662
1224
|
.select(["id", "object_prefix"])
|
|
663
1225
|
.where("expires_at", "<=", sql `now()`)
|
|
@@ -669,35 +1231,100 @@ export class PluginImport {
|
|
|
669
1231
|
let progressed = 0;
|
|
670
1232
|
for (const r of batch) {
|
|
671
1233
|
try {
|
|
672
|
-
const done = await this.
|
|
673
|
-
const locked = await trx
|
|
674
|
-
.selectFrom("plugin_import_staging")
|
|
675
|
-
.select("id")
|
|
676
|
-
.where("id", "=", r.id)
|
|
677
|
-
.where("expires_at", "<=", sql `now()`)
|
|
678
|
-
.forUpdate()
|
|
679
|
-
.skipLocked()
|
|
680
|
-
.executeTakeFirst();
|
|
681
|
-
if (!locked)
|
|
682
|
-
return false;
|
|
683
|
-
if (r.object_prefix)
|
|
684
|
-
await this.d.storage.deployment().deletePrefix(r.object_prefix);
|
|
685
|
-
await trx.deleteFrom("plugin_import_staging").where("id", "=", r.id).execute();
|
|
686
|
-
return true;
|
|
687
|
-
});
|
|
1234
|
+
const done = await this.cleanupOne(r);
|
|
688
1235
|
if (done) {
|
|
689
1236
|
total++;
|
|
690
1237
|
progressed++;
|
|
691
1238
|
}
|
|
692
1239
|
}
|
|
693
1240
|
catch (err) {
|
|
694
|
-
this.
|
|
1241
|
+
this.log.warn("cannot clean up an expired plugin import", { stagingId: r.id, err });
|
|
695
1242
|
}
|
|
696
1243
|
}
|
|
697
1244
|
if (progressed === 0 || batch.length < CLEANUP_BATCH)
|
|
698
1245
|
return total;
|
|
699
1246
|
}
|
|
700
1247
|
}
|
|
1248
|
+
/**
|
|
1249
|
+
* One expired staging row (row lock, `SKIP LOCKED`): its objects, then the row; false when another
|
|
1250
|
+
* replica has it or it is gone.
|
|
1251
|
+
*/
|
|
1252
|
+
async cleanupOne(r) {
|
|
1253
|
+
const t = this.db;
|
|
1254
|
+
const locked = await t
|
|
1255
|
+
.selectFrom("plugin_import_staging")
|
|
1256
|
+
.select(["id", "org_id", "review", "manifest"])
|
|
1257
|
+
.where("id", "=", r.id)
|
|
1258
|
+
.where("expires_at", "<=", sql `now()`)
|
|
1259
|
+
.forUpdate()
|
|
1260
|
+
.skipLocked()
|
|
1261
|
+
.executeTakeFirst();
|
|
1262
|
+
if (!locked)
|
|
1263
|
+
return false;
|
|
1264
|
+
if (r.object_prefix)
|
|
1265
|
+
await this.files.deployment().deletePrefix(r.object_prefix);
|
|
1266
|
+
await t.deleteFrom("plugin_import_staging").where("id", "=", r.id).execute();
|
|
1267
|
+
await this.dropOrgPackage(locked);
|
|
1268
|
+
return true;
|
|
1269
|
+
}
|
|
1270
|
+
/**
|
|
1271
|
+
* An expired org staging's extension package (an org upload stores it at prepare, P3-10): removed
|
|
1272
|
+
* with the staging unless something else uses it — an install (running or migrated), a catalog
|
|
1273
|
+
* version, another staging — or it was stored by anyone else (the package row's source must be
|
|
1274
|
+
* this staging's own `catalog` ref). A platform staging keeps its package, as before. Its object
|
|
1275
|
+
* is deleted after the commit.
|
|
1276
|
+
*/
|
|
1277
|
+
async dropOrgPackage(row) {
|
|
1278
|
+
const sha = row.review.extension?.sha256;
|
|
1279
|
+
if (row.org_id === null || sha === undefined)
|
|
1280
|
+
return;
|
|
1281
|
+
const staged = row.manifest;
|
|
1282
|
+
const t = this.db;
|
|
1283
|
+
const pkg = await t
|
|
1284
|
+
.selectFrom("extension_packages")
|
|
1285
|
+
.select("blob_store")
|
|
1286
|
+
.where("sha256", "=", sha)
|
|
1287
|
+
.where("source", "=", "catalog")
|
|
1288
|
+
.where("source_ref", "=", `${staged.itemId}@${staged.version}`)
|
|
1289
|
+
.forUpdate()
|
|
1290
|
+
.executeTakeFirst();
|
|
1291
|
+
if (!pkg)
|
|
1292
|
+
return;
|
|
1293
|
+
const used = (await t
|
|
1294
|
+
.selectFrom("extension_installs")
|
|
1295
|
+
.select("name")
|
|
1296
|
+
.where((eb) => eb.or([eb("sha256", "=", sha), eb("migrated_sha", "=", sha)]))
|
|
1297
|
+
.executeTakeFirst()) ??
|
|
1298
|
+
(await t
|
|
1299
|
+
.selectFrom("catalog_item_versions")
|
|
1300
|
+
.select("version")
|
|
1301
|
+
.where("extension_sha256", "=", sha)
|
|
1302
|
+
.executeTakeFirst()) ??
|
|
1303
|
+
(await t
|
|
1304
|
+
.selectFrom("plugin_import_staging")
|
|
1305
|
+
.select("id")
|
|
1306
|
+
.where(sql `review->'extension'->>'sha256' = ${sha}`)
|
|
1307
|
+
.executeTakeFirst());
|
|
1308
|
+
if (used !== undefined)
|
|
1309
|
+
return;
|
|
1310
|
+
// extension_blobs (a PG-stored package) goes with the row (ON DELETE CASCADE)
|
|
1311
|
+
await t.deleteFrom("extension_packages").where("sha256", "=", sha).execute();
|
|
1312
|
+
// The object only once the row is gone for good: a failure leaves an unreferenced object
|
|
1313
|
+
// (harmless; a later upload of the same bytes rewrites it), never a row without its bytes
|
|
1314
|
+
if (pkg.blob_store === "object") {
|
|
1315
|
+
afterCommit(async () => {
|
|
1316
|
+
try {
|
|
1317
|
+
await this.files.deployment().delete(blobKey(sha));
|
|
1318
|
+
}
|
|
1319
|
+
catch (err) {
|
|
1320
|
+
this.log.warn("cannot delete an expired org upload's extension package object", {
|
|
1321
|
+
sha256: sha,
|
|
1322
|
+
err,
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
701
1328
|
// ---------------------------------------------------------------------------------------------
|
|
702
1329
|
/** npm / marketplace imports: the package must be the one that was asked for. */
|
|
703
1330
|
checkExpected(pkg, expect, format = "capybara") {
|
|
@@ -723,7 +1350,7 @@ export class PluginImport {
|
|
|
723
1350
|
}
|
|
724
1351
|
/** A config-declared extension's name cannot be taken by an imported plugin. */
|
|
725
1352
|
assertNotDeclared(name) {
|
|
726
|
-
const declared = this.
|
|
1353
|
+
const declared = this.registry.declared().get(name);
|
|
727
1354
|
if (declared === "config") {
|
|
728
1355
|
throw new ApiError("extension.config_declared", `Extension ${name} is declared in the startup config (extensions); remove it there before importing a plugin with this name`);
|
|
729
1356
|
}
|
|
@@ -744,8 +1371,16 @@ export class PluginImport {
|
|
|
744
1371
|
if (data !== undefined && !stored.has(path))
|
|
745
1372
|
stored.set(path, fileOf(path, data));
|
|
746
1373
|
};
|
|
747
|
-
|
|
748
|
-
|
|
1374
|
+
const objectPaths = new Set();
|
|
1375
|
+
const keepObject = (path) => {
|
|
1376
|
+
keep(path);
|
|
1377
|
+
if (stored.has(path))
|
|
1378
|
+
objectPaths.add(path);
|
|
1379
|
+
};
|
|
1380
|
+
// The plugin icon and the setup guide templates (rendered by PluginGuides): display files
|
|
1381
|
+
const displayPaths = displayFilePaths(m, pkg.connectorTemplates.flatMap((c) => (c.file.icon === undefined ? [] : [c.file.icon])));
|
|
1382
|
+
for (const path of displayPaths)
|
|
1383
|
+
keep(path);
|
|
749
1384
|
const skills = [];
|
|
750
1385
|
for (const s of pkg.skills) {
|
|
751
1386
|
const files = s.files.map((f) => fileOf(f, pkg.files.get(`${s.dir}/${f}`)));
|
|
@@ -764,7 +1399,7 @@ export class PluginImport {
|
|
|
764
1399
|
suggestPinned: pinned.get(s.dir) === true,
|
|
765
1400
|
});
|
|
766
1401
|
for (const f of s.files)
|
|
767
|
-
|
|
1402
|
+
keepObject(`${s.dir}/${f}`);
|
|
768
1403
|
}
|
|
769
1404
|
catch (e) {
|
|
770
1405
|
if (!(e instanceof SkillArchiveError))
|
|
@@ -783,10 +1418,10 @@ export class PluginImport {
|
|
|
783
1418
|
// The result depends on which connectors the replica serving this request has loaded right
|
|
784
1419
|
// now: it is the import-time gate, not the last word (an org install checks again against the
|
|
785
1420
|
// connector of the moment)
|
|
786
|
-
const loaded = this.
|
|
1421
|
+
const loaded = findConnectorIn(this.registry, t.plugin, t.connector);
|
|
787
1422
|
if (loaded) {
|
|
788
1423
|
problems.push(...templateProblems(loaded, t, at));
|
|
789
|
-
const v = this.
|
|
1424
|
+
const v = this.registry.manifests().find((x) => x.name === t.plugin)?.version;
|
|
790
1425
|
if (t.pluginVersion !== undefined &&
|
|
791
1426
|
v !== undefined &&
|
|
792
1427
|
!satisfiesRange(v, t.pluginVersion)) {
|
|
@@ -794,7 +1429,7 @@ export class PluginImport {
|
|
|
794
1429
|
}
|
|
795
1430
|
}
|
|
796
1431
|
else if (local.has(t.plugin) ||
|
|
797
|
-
this.
|
|
1432
|
+
!this.connectorsLoaded ||
|
|
798
1433
|
(format === "claude-code" && t.plugin === CLAUDE_MCP_CONNECTOR.plugin)) {
|
|
799
1434
|
// The connector comes with this plugin or a dependency (or this process loads no
|
|
800
1435
|
// connectors, or a translated Claude template targets connector-mcp, which may not be
|
|
@@ -808,10 +1443,8 @@ export class PluginImport {
|
|
|
808
1443
|
else {
|
|
809
1444
|
problems.push(`${at}.connector: extension ${t.plugin} providing connector "${t.connector}" is not loaded in this deployment and is neither this plugin's extension nor a dependency`);
|
|
810
1445
|
}
|
|
811
|
-
|
|
1446
|
+
keepObject(c.path);
|
|
812
1447
|
templatePaths.set(c.id, c.path);
|
|
813
|
-
if (c.file.icon !== undefined)
|
|
814
|
-
keep(packagePath(c.file.icon));
|
|
815
1448
|
return {
|
|
816
1449
|
id: c.id,
|
|
817
1450
|
displayName: c.file.displayName,
|
|
@@ -825,50 +1458,96 @@ export class PluginImport {
|
|
|
825
1458
|
};
|
|
826
1459
|
});
|
|
827
1460
|
const agentTemplates = pkg.agentTemplates.map((a) => {
|
|
828
|
-
|
|
1461
|
+
keepObject(a.path);
|
|
829
1462
|
const { name, description, instructions, model, ...rest } = a.template;
|
|
830
1463
|
return { name, path: a.path, description, instructions, model: model ?? "inherit", ...rest };
|
|
831
1464
|
});
|
|
1465
|
+
// Themes: the file as written, the assets as sanitized by the reader (never the uploaded
|
|
1466
|
+
// originals: a shared path, e.g. the plugin icon, is stored sanitized too)
|
|
1467
|
+
const themes = pkg.themes.map((t) => {
|
|
1468
|
+
keepObject(t.path);
|
|
1469
|
+
for (const [path, data] of t.assets) {
|
|
1470
|
+
stored.set(path, fileOf(path, data));
|
|
1471
|
+
objectPaths.add(path);
|
|
1472
|
+
}
|
|
1473
|
+
const logo = t.theme.logo;
|
|
1474
|
+
return {
|
|
1475
|
+
id: t.id,
|
|
1476
|
+
name: t.theme.name,
|
|
1477
|
+
schemes: ["dark", "light"].filter((k) => t.theme.schemes[k] !== undefined),
|
|
1478
|
+
fonts: t.theme.fonts?.length ?? 0,
|
|
1479
|
+
logo: logo !== undefined && Object.keys(logo).length > 0,
|
|
1480
|
+
};
|
|
1481
|
+
});
|
|
832
1482
|
if (problems.length > 0)
|
|
833
1483
|
throw invalid(problems);
|
|
834
1484
|
return {
|
|
835
1485
|
files: [...stored.values()],
|
|
1486
|
+
displayPaths,
|
|
1487
|
+
objectPaths,
|
|
836
1488
|
templates,
|
|
837
1489
|
skills,
|
|
838
1490
|
agentTemplates,
|
|
1491
|
+
themes,
|
|
839
1492
|
notLoaded,
|
|
840
1493
|
templatePaths,
|
|
841
1494
|
};
|
|
842
1495
|
}
|
|
843
1496
|
/**
|
|
844
1497
|
* The highest imported, non-deleted catalog version satisfying each dependency's range (null when
|
|
845
|
-
* none does).
|
|
1498
|
+
* none does). An org upload (`owner`, P3-13) resolves only against items the org can use
|
|
1499
|
+
* ({@link usableBy}: confirmed, not disabled, offered to it), and any dependency left unresolved
|
|
1500
|
+
* -> 409 `plugin.dependency_unavailable` (details `[{ dependencies }]`, their names): an org
|
|
1501
|
+
* upload never brings in anything the org could not install itself.
|
|
846
1502
|
*/
|
|
847
|
-
async resolveDependencies(m) {
|
|
1503
|
+
async resolveDependencies(m, owner) {
|
|
848
1504
|
const deps = m.dependencies ?? [];
|
|
849
1505
|
if (deps.length === 0)
|
|
850
1506
|
return [];
|
|
851
|
-
const
|
|
1507
|
+
const names = deps.map((d) => d.name);
|
|
1508
|
+
const versions = this.db
|
|
852
1509
|
.selectFrom("catalog_items as i")
|
|
853
1510
|
.innerJoin("catalog_item_versions as v", "v.item_id", "i.id")
|
|
854
|
-
.select(["i.name", "v.version", "v.imported_at"])
|
|
855
1511
|
.where("i.deleted_at", "is", null)
|
|
856
|
-
.where("i.name", "in",
|
|
857
|
-
|
|
858
|
-
|
|
1512
|
+
.where("i.name", "in", names);
|
|
1513
|
+
const rows = owner === undefined
|
|
1514
|
+
? await versions.select(["i.name", "v.version", "v.imported_at"]).execute()
|
|
1515
|
+
: (await versions
|
|
1516
|
+
// the org's own row of a `named` list (usableBy reads whether it is listed)
|
|
1517
|
+
.leftJoin("catalog_item_scope_orgs as so", (j) => j.onRef("so.item_id", "=", "i.id").on("so.org_id", "=", owner.orgId))
|
|
1518
|
+
.select([
|
|
1519
|
+
"i.name",
|
|
1520
|
+
"v.version",
|
|
1521
|
+
"v.imported_at",
|
|
1522
|
+
"i.scope",
|
|
1523
|
+
"i.builtin",
|
|
1524
|
+
"i.disabled",
|
|
1525
|
+
"i.deleted_at",
|
|
1526
|
+
"i.awaiting_confirmation",
|
|
1527
|
+
"i.owner_org_id",
|
|
1528
|
+
"i.shareable",
|
|
1529
|
+
"so.org_id as listed",
|
|
1530
|
+
])
|
|
1531
|
+
.execute()).filter((r) => usableBy(r, owner.orgId, r.listed !== null));
|
|
1532
|
+
const resolved = deps.map((d) => ({
|
|
859
1533
|
name: d.name,
|
|
860
1534
|
range: d.version,
|
|
861
1535
|
resolved: maxSatisfying(rows
|
|
862
1536
|
.filter((r) => r.name === d.name)
|
|
863
1537
|
.map((r) => ({ version: r.version, importedAt: r.imported_at })), d.version)?.version ?? null,
|
|
864
1538
|
}));
|
|
1539
|
+
const missing = resolved.filter((d) => d.resolved === null).map((d) => d.name);
|
|
1540
|
+
if (owner !== undefined && missing.length > 0) {
|
|
1541
|
+
throw new ApiError("plugin.dependency_unavailable", `Dependencies not available to this organization: ${missing.join(", ")}`, [{ dependencies: missing }]);
|
|
1542
|
+
}
|
|
1543
|
+
return resolved;
|
|
865
1544
|
}
|
|
866
1545
|
/**
|
|
867
1546
|
* The extension's state on the deployment; installed from another npm package ->
|
|
868
1547
|
* `extension.name_conflict`.
|
|
869
1548
|
*/
|
|
870
|
-
async extensionState(name, packageName
|
|
871
|
-
const r = await db
|
|
1549
|
+
async extensionState(name, packageName) {
|
|
1550
|
+
const r = await this.db
|
|
872
1551
|
.selectFrom("extension_installs")
|
|
873
1552
|
.innerJoin("extension_packages", "extension_packages.sha256", "extension_installs.sha256")
|
|
874
1553
|
.select([
|
|
@@ -879,7 +1558,7 @@ export class PluginImport {
|
|
|
879
1558
|
.where("extension_installs.name", "=", name)
|
|
880
1559
|
.executeTakeFirst();
|
|
881
1560
|
if (r && r.package_name !== packageName) {
|
|
882
|
-
throw new ApiError("extension.name_conflict", `Extension ${name} is already installed from package ${r.package_name}; package ${packageName} cannot use it
|
|
1561
|
+
throw new ApiError("extension.name_conflict", `Extension ${name} is already installed from package ${r.package_name}; package ${packageName} cannot use it`, [{ owner: await packageOwner(this.db, r.package_name, name) }]);
|
|
883
1562
|
}
|
|
884
1563
|
return r
|
|
885
1564
|
? { kind: "installed", version: r.version, sha256: r.sha256, packageName: r.package_name }
|
|
@@ -888,7 +1567,7 @@ export class PluginImport {
|
|
|
888
1567
|
/** The review of the extension: permissions, the change against the snapshot, warnings, action. */
|
|
889
1568
|
async reviewExtension(pkg, state) {
|
|
890
1569
|
const name = pkg.section.name;
|
|
891
|
-
const snap = await this.
|
|
1570
|
+
const snap = await this.db
|
|
892
1571
|
.selectFrom("extension_permission_snapshots")
|
|
893
1572
|
.select("permissions")
|
|
894
1573
|
.where("plugin", "=", name)
|
|
@@ -901,7 +1580,7 @@ export class PluginImport {
|
|
|
901
1580
|
name,
|
|
902
1581
|
version: pkg.section.version,
|
|
903
1582
|
sha256: pkg.sha256,
|
|
904
|
-
...actionOf(state, pkg.sha256),
|
|
1583
|
+
...actionOf(state, pkg.sha256, pkg.section.version),
|
|
905
1584
|
permissions,
|
|
906
1585
|
added,
|
|
907
1586
|
addedItems: permissionKeyItems(added),
|
|
@@ -912,33 +1591,79 @@ export class PluginImport {
|
|
|
912
1591
|
};
|
|
913
1592
|
}
|
|
914
1593
|
async readStored(sha256) {
|
|
915
|
-
const bytes = await this.
|
|
1594
|
+
const bytes = await this.blobs.get(sha256);
|
|
916
1595
|
return readingPackage(() => readExtensionPackage(bytes, {
|
|
917
|
-
maxBytes: this.
|
|
1596
|
+
maxBytes: this.config.get().packages.maxBytes,
|
|
918
1597
|
hostSdkVersion: SDK_VERSION,
|
|
919
1598
|
}));
|
|
920
1599
|
}
|
|
921
1600
|
async itemView(itemId) {
|
|
922
|
-
const item = await this.
|
|
1601
|
+
const item = await this.db
|
|
923
1602
|
.selectFrom("catalog_items")
|
|
924
1603
|
.selectAll()
|
|
925
1604
|
.where("id", "=", itemId)
|
|
926
1605
|
.executeTakeFirstOrThrow();
|
|
927
|
-
const versions = await this.
|
|
1606
|
+
const versions = await this.db
|
|
928
1607
|
.selectFrom("catalog_item_versions")
|
|
929
|
-
.select(["version", "source", "imported_at"])
|
|
1608
|
+
.select(["version", "source", "imported_at", "extension_sha256", "manifest", "source_format"])
|
|
930
1609
|
.where("item_id", "=", itemId)
|
|
931
1610
|
.execute();
|
|
932
|
-
|
|
1611
|
+
const facts = await itemScopeFacts(this.db, [item], await itemConfirmations(this.admin, [item], new Map([[item.id, versions]])));
|
|
1612
|
+
return itemView(item, versions, 0, undefined, facts.get(item.id));
|
|
933
1613
|
}
|
|
934
|
-
}
|
|
1614
|
+
};
|
|
1615
|
+
__decorate([
|
|
1616
|
+
Transactional({ propagation: "mandatory" })
|
|
1617
|
+
], PluginImport.prototype, "authorizeActor", null);
|
|
1618
|
+
__decorate([
|
|
1619
|
+
Transactional()
|
|
1620
|
+
], PluginImport.prototype, "authorize", null);
|
|
1621
|
+
__decorate([
|
|
1622
|
+
Transactional()
|
|
1623
|
+
], PluginImport.prototype, "writeStaging", null);
|
|
1624
|
+
__decorate([
|
|
1625
|
+
Transactional()
|
|
1626
|
+
], PluginImport.prototype, "commit", null);
|
|
1627
|
+
__decorate([
|
|
1628
|
+
Transactional({ propagation: "mandatory" })
|
|
1629
|
+
], PluginImport.prototype, "approve", null);
|
|
1630
|
+
__decorate([
|
|
1631
|
+
Transactional()
|
|
1632
|
+
], PluginImport.prototype, "restoreSnapshot", null);
|
|
1633
|
+
__decorate([
|
|
1634
|
+
Transactional()
|
|
1635
|
+
], PluginImport.prototype, "cleanupOne", null);
|
|
1636
|
+
__decorate([
|
|
1637
|
+
Transactional({ propagation: "mandatory" })
|
|
1638
|
+
], PluginImport.prototype, "dropOrgPackage", null);
|
|
1639
|
+
PluginImport = __decorate([
|
|
1640
|
+
Injectable(),
|
|
1641
|
+
__param(0, Inject(KernelDb)),
|
|
1642
|
+
__param(1, Inject(SuperAdminLock)),
|
|
1643
|
+
__param(2, Inject(OrgLock)),
|
|
1644
|
+
__param(3, Inject(PluginInstallLock)),
|
|
1645
|
+
__param(4, Inject(PluginApproveLock)),
|
|
1646
|
+
__param(5, Inject(CatalogItemLock)),
|
|
1647
|
+
__param(6, Inject(KernelConfigService)),
|
|
1648
|
+
__param(7, Inject(StorageService)),
|
|
1649
|
+
__param(8, Inject(ExtensionInstalls)),
|
|
1650
|
+
__param(9, Inject(ExtensionAdminOps)),
|
|
1651
|
+
__param(10, Inject(ExtensionAdmin)),
|
|
1652
|
+
__param(11, Inject(ExtensionBlobs)),
|
|
1653
|
+
__param(12, Inject(ExtensionRegistry)),
|
|
1654
|
+
__param(13, Inject(KERNEL_LOGGER)),
|
|
1655
|
+
__param(14, Inject(TransactionHost)),
|
|
1656
|
+
__param(15, Inject(PlatformComponents)),
|
|
1657
|
+
__param(16, Inject(getQueueToken(MAINTENANCE_QUEUE_NAME)))
|
|
1658
|
+
], PluginImport);
|
|
1659
|
+
export { PluginImport };
|
|
935
1660
|
/**
|
|
936
1661
|
* plugin.json as stored on the version: skills and connector templates listed explicitly (what was
|
|
937
1662
|
* scanned when the manifest omitted them), `pinned` kept from the listing.
|
|
938
1663
|
*/
|
|
939
1664
|
function normalizedManifest(pkg) {
|
|
940
1665
|
const pinned = new Map((pkg.manifest.skills ?? []).map((s) => [packagePath(s.path), s.pinned]));
|
|
941
|
-
const { agents: _, ...manifest } = pkg.manifest;
|
|
1666
|
+
const { agents: _, themes: __, ...manifest } = pkg.manifest;
|
|
942
1667
|
return {
|
|
943
1668
|
...manifest,
|
|
944
1669
|
skills: pkg.skills.map((s) => {
|
|
@@ -950,6 +1675,7 @@ function normalizedManifest(pkg) {
|
|
|
950
1675
|
...(pkg.agentTemplates.length > 0 && {
|
|
951
1676
|
agents: pkg.agentTemplates.map((a) => ({ path: `./${a.path}` })),
|
|
952
1677
|
}),
|
|
1678
|
+
...(pkg.themes.length > 0 && { themes: pkg.themes.map((t) => ({ path: `./${t.path}` })) }),
|
|
953
1679
|
};
|
|
954
1680
|
}
|
|
955
1681
|
/** package.json `name`, or null without one (a git plugin; never the string "undefined"). */
|
|
@@ -958,13 +1684,20 @@ function packageNameOf(pkg) {
|
|
|
958
1684
|
return typeof name === "string" ? name : null;
|
|
959
1685
|
}
|
|
960
1686
|
/** The extension's deployment state -> action and current version. */
|
|
961
|
-
function actionOf(s, sha256) {
|
|
1687
|
+
function actionOf(s, sha256, version) {
|
|
962
1688
|
if (s.kind === "installed") {
|
|
1689
|
+
// A version below the deployed one is recorded in the catalog only: an import never
|
|
1690
|
+
// downgrades the deployment (ruling H)
|
|
1691
|
+
const older = s.sha256 !== sha256 &&
|
|
1692
|
+
semver.valid(version) !== null &&
|
|
1693
|
+
semver.valid(s.version) !== null &&
|
|
1694
|
+
semver.lt(version, s.version);
|
|
963
1695
|
return {
|
|
964
|
-
action: s.sha256 === sha256 ? "keep" : "upgrade",
|
|
1696
|
+
action: s.sha256 === sha256 || older ? "keep" : "upgrade",
|
|
965
1697
|
deployed: true,
|
|
966
1698
|
currentVersion: s.version,
|
|
967
1699
|
currentSha256: s.sha256,
|
|
1700
|
+
...(older && { olderThanDeployed: true }),
|
|
968
1701
|
};
|
|
969
1702
|
}
|
|
970
1703
|
return { action: "install", deployed: false, currentVersion: null, currentSha256: null };
|
|
@@ -974,7 +1707,8 @@ function actionOf(s, sha256) {
|
|
|
974
1707
|
* current version / package, its own review digest), every template field, each skill's name / path
|
|
975
1708
|
* / file count, the dependency resolution, the sha256 of every stored file, the format, the
|
|
976
1709
|
* translation report's items, the sha256 of the license text and the two review flags
|
|
977
|
-
* (`claudeManifestIgnored`, `licenseTruncated`),
|
|
1710
|
+
* (`claudeManifestIgnored`, `licenseTruncated`), the agent templates when there are any and the
|
|
1711
|
+
* themes when there are any.
|
|
978
1712
|
* Exported for tests. `repository` is display only.
|
|
979
1713
|
*/
|
|
980
1714
|
export function pluginReviewHash(r, files) {
|
|
@@ -1007,6 +1741,10 @@ export function pluginReviewHash(r, files) {
|
|
|
1007
1741
|
...((r.agentTemplates ?? []).length > 0
|
|
1008
1742
|
? [(r.agentTemplates ?? []).map((a) => [a.path, canonicalJson(a)])]
|
|
1009
1743
|
: []),
|
|
1744
|
+
// themes, only when there are any, tagged (never read as agent templates)
|
|
1745
|
+
...((r.themes ?? []).length > 0
|
|
1746
|
+
? [{ themes: (r.themes ?? []).map((t) => [t.id, canonicalJson(t)]) }]
|
|
1747
|
+
: []),
|
|
1010
1748
|
]);
|
|
1011
1749
|
return createHash("sha256").update(canonical).digest("hex").slice(0, 32);
|
|
1012
1750
|
}
|
|
@@ -1067,3 +1805,23 @@ function pinnedNames(m, review) {
|
|
|
1067
1805
|
const byPath = new Map(review.skills.map((s) => [s.path, s.name]));
|
|
1068
1806
|
return (m.skills ?? []).filter((s) => s.pinned === true).map((s) => byPath.get(s.path) ?? s.path);
|
|
1069
1807
|
}
|
|
1808
|
+
/**
|
|
1809
|
+
* The staging rows a route may see (P3-8): the platform's (`org_id` null) without an owner, else
|
|
1810
|
+
* the owner org's.
|
|
1811
|
+
*/
|
|
1812
|
+
function ownStaging(owner) {
|
|
1813
|
+
return (eb) => owner === undefined ? eb("org_id", "is", null) : eb("org_id", "=", owner.orgId);
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* An org upload's custom deny, by content (ruling P3-15'): skills or agent templates ->
|
|
1817
|
+
* `customSkills`, connector templates -> `customConnectors`; each `deny` -> 403
|
|
1818
|
+
* `catalog.custom_disabled`. A package carrying neither passes; themes are covered by neither
|
|
1819
|
+
* switch (themes spec §6), so a themes-only upload passes.
|
|
1820
|
+
*/
|
|
1821
|
+
async function assertCustomContent(db, content) {
|
|
1822
|
+
if (content.skills.length > 0 || content.agentTemplates.length > 0) {
|
|
1823
|
+
await assertCustomAllowed(db, "customSkills");
|
|
1824
|
+
}
|
|
1825
|
+
if (content.templates.length > 0)
|
|
1826
|
+
await assertCustomAllowed(db, "customConnectors");
|
|
1827
|
+
}
|