@capybara-hq/kernel 0.1.0-rc.4 → 0.1.0-rc.6
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 +61 -5
- package/dist/admin/admin.controller.d.ts +51 -14
- package/dist/admin/admin.controller.js +60 -19
- package/dist/admin/extensions.controller.d.ts +16 -2
- package/dist/admin/extensions.controller.js +26 -6
- package/dist/admin/setup-lock.d.ts +1 -1
- package/dist/admin/setup-lock.js +1 -1
- package/dist/admin/setup.controller.d.ts +1 -1
- package/dist/admin/setup.controller.js +1 -1
- package/dist/admin/setup.service.d.ts +4 -4
- package/dist/admin/setup.service.js +8 -8
- package/dist/agents/agent-lookup.d.ts +16 -0
- package/dist/agents/agent-lookup.js +11 -0
- package/dist/agents/agents.controller.d.ts +76 -1
- package/dist/agents/agents.controller.js +90 -11
- package/dist/agents/agents.module.d.ts +4 -1
- package/dist/agents/agents.module.js +32 -6
- package/dist/agents/agents.service.d.ts +54 -23
- package/dist/agents/agents.service.js +180 -76
- package/dist/agents/definition.d.ts +49 -0
- package/dist/agents/definition.js +45 -0
- package/dist/agents/from-template.d.ts +106 -0
- package/dist/agents/from-template.js +649 -0
- package/dist/agents/from-template.service.d.ts +60 -0
- package/dist/agents/from-template.service.js +161 -0
- package/dist/agents/models.controller.d.ts +34 -5
- package/dist/agents/models.controller.js +50 -6
- package/dist/agents/org-templates.d.ts +176 -0
- package/dist/agents/org-templates.js +827 -0
- package/dist/agents/pending-connector-requests.d.ts +77 -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/readiness.controller.d.ts +5 -5
- package/dist/agents/readiness.controller.js +6 -6
- package/dist/agents/templates.controller.d.ts +86 -5
- package/dist/agents/templates.controller.js +171 -7
- package/dist/agents/templates.d.ts +127 -23
- package/dist/agents/templates.js +475 -52
- package/dist/background/background.module.js +8 -1
- package/dist/background/finish.d.ts +3 -2
- package/dist/background/launch-lock.d.ts +4 -3
- package/dist/background/launch-lock.js +4 -3
- package/dist/background/poll.job.d.ts +9 -6
- package/dist/background/poll.job.js +30 -22
- package/dist/background/session.d.ts +13 -2
- package/dist/background/session.js +13 -0
- package/dist/background/stop.d.ts +12 -6
- package/dist/background/stop.js +57 -39
- package/dist/background/store.d.ts +18 -6
- package/dist/background/store.js +12 -6
- package/dist/background/tasks.service.d.ts +15 -5
- package/dist/background/tasks.service.js +42 -17
- package/dist/background/wake-rules.d.ts +27 -18
- package/dist/background/wake-rules.js +52 -22
- package/dist/background/wake.d.ts +13 -11
- package/dist/background/wake.js +20 -14
- package/dist/catalog/admin-catalog.controller.d.ts +129 -30
- package/dist/catalog/admin-catalog.controller.js +213 -42
- package/dist/catalog/catalog-content.d.ts +58 -32
- package/dist/catalog/catalog-content.js +34 -8
- 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 +111 -7
- package/dist/catalog/catalog-items.js +279 -13
- package/dist/catalog/catalog-scope.service.d.ts +260 -0
- package/dist/catalog/catalog-scope.service.js +1116 -0
- package/dist/catalog/catalog.module.d.ts +7 -9
- package/dist/catalog/catalog.module.js +41 -31
- package/dist/catalog/catalog.service.d.ts +101 -29
- package/dist/catalog/catalog.service.js +104 -106
- package/dist/catalog/cli.d.ts +11 -1
- package/dist/catalog/cli.js +26 -1
- 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 +152 -0
- package/dist/catalog/component-scope.controller.js +287 -0
- package/dist/catalog/component-scope.service.d.ts +303 -0
- package/dist/catalog/component-scope.service.js +936 -0
- package/dist/catalog/component-state.d.ts +174 -0
- package/dist/catalog/component-state.js +437 -0
- package/dist/catalog/job-ids.d.ts +30 -0
- package/dist/catalog/job-ids.js +25 -0
- package/dist/catalog/marketplace-fetch.d.ts +1 -1
- package/dist/catalog/marketplaces.controller.d.ts +22 -5
- package/dist/catalog/marketplaces.controller.js +56 -7
- package/dist/catalog/marketplaces.service.d.ts +54 -14
- package/dist/catalog/marketplaces.service.js +71 -22
- package/dist/catalog/org-catalog.controller.d.ts +125 -34
- package/dist/catalog/org-catalog.controller.js +181 -65
- package/dist/catalog/org-catalog.service.d.ts +65 -33
- package/dist/catalog/org-catalog.service.js +324 -157
- 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 +119 -0
- package/dist/catalog/org-extension.controller.js +266 -0
- package/dist/catalog/org-plugin-uploads.controller.d.ts +98 -0
- package/dist/catalog/org-plugin-uploads.controller.js +213 -0
- package/dist/catalog/org-plugin-uploads.d.ts +63 -0
- package/dist/catalog/org-plugin-uploads.js +116 -0
- package/dist/catalog/owned-items.d.ts +184 -0
- package/dist/catalog/owned-items.js +789 -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 +221 -0
- package/dist/catalog/platform-components.js +761 -0
- package/dist/catalog/platform-migration.d.ts +115 -0
- package/dist/catalog/platform-migration.js +582 -0
- package/dist/catalog/plugin-import.d.ts +178 -34
- package/dist/catalog/plugin-import.js +622 -82
- package/dist/catalog/plugin-install.d.ts +185 -41
- package/dist/catalog/plugin-install.js +758 -126
- package/dist/catalog/plugin-upgrade.d.ts +260 -225
- package/dist/catalog/plugin-upgrade.js +1147 -1136
- package/dist/catalog/request-rules.d.ts +65 -0
- package/dist/catalog/request-rules.js +217 -0
- package/dist/catalog/requests.service.d.ts +193 -118
- package/dist/catalog/requests.service.js +526 -343
- 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 +118 -0
- package/dist/channels/actions.js +1 -0
- package/dist/channels/cards.js +20 -2
- package/dist/channels/channels.module.js +2 -0
- package/dist/channels/inbound.d.ts +9 -1
- package/dist/channels/inbound.js +67 -5
- package/dist/channels/phrases.d.ts +35 -0
- package/dist/channels/phrases.js +29 -0
- package/dist/config/docs.js +3 -1
- package/dist/config/schema.d.ts +10 -2
- package/dist/config/schema.js +70 -22
- package/dist/conversations/access.d.ts +6 -4
- package/dist/conversations/access.js +27 -5
- package/dist/conversations/agent-tree.d.ts +46 -0
- package/dist/conversations/agent-tree.js +92 -0
- package/dist/conversations/conversations.controller.d.ts +43 -18
- package/dist/conversations/conversations.controller.js +79 -38
- package/dist/conversations/conversations.module.d.ts +1 -1
- package/dist/conversations/conversations.module.js +7 -7
- package/dist/conversations/conversations.service.d.ts +73 -15
- package/dist/conversations/conversations.service.js +115 -35
- package/dist/conversations/environment-status.d.ts +24 -0
- package/dist/conversations/environment-status.js +71 -0
- package/dist/conversations/event-log.d.ts +20 -5
- package/dist/conversations/event-log.js +60 -0
- package/dist/conversations/events.d.ts +84 -2
- package/dist/conversations/events.js +91 -17
- package/dist/conversations/queue.service.d.ts +1 -1
- package/dist/conversations/queue.service.js +5 -0
- package/dist/conversations/titles.d.ts +5 -3
- package/dist/conversations/titles.js +21 -8
- package/dist/conversations/tree.d.ts +17 -0
- package/dist/conversations/tree.js +42 -0
- package/dist/ctx/create-ctx.d.ts +20 -1
- package/dist/ctx/create-ctx.js +38 -7
- package/dist/db/kernel-schema.d.ts +386 -18
- package/dist/environments/access.d.ts +41 -0
- package/dist/environments/access.js +77 -0
- package/dist/environments/conversation-environments.d.ts +61 -0
- package/dist/environments/conversation-environments.js +170 -0
- package/dist/environments/dto.d.ts +25 -0
- package/dist/environments/dto.js +12 -0
- package/dist/environments/environments.controller.d.ts +33 -0
- package/dist/environments/environments.controller.js +110 -0
- package/dist/environments/environments.module.d.ts +8 -0
- package/dist/environments/environments.module.js +27 -0
- package/dist/environments/environments.service.d.ts +153 -0
- package/dist/environments/environments.service.js +541 -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 +85 -2
- package/dist/errors.js +85 -2
- package/dist/evals/reconstruct.d.ts +18 -9
- package/dist/evals/reconstruct.js +26 -7
- package/dist/evals/run-replay.d.ts +4 -2
- package/dist/evals/run-replay.js +20 -6
- package/dist/evals/runs.service.d.ts +2 -1
- package/dist/evals/runs.service.js +13 -12
- package/dist/evals/step-replay.d.ts +4 -6
- package/dist/evals/step-replay.js +4 -3
- package/dist/evals/trajectory.service.d.ts +8 -3
- package/dist/evals/trajectory.service.js +26 -14
- package/dist/evals/worker.d.ts +5 -5
- package/dist/evals/worker.js +9 -3
- package/dist/extensions/admin-ops.d.ts +36 -10
- package/dist/extensions/admin-ops.js +65 -42
- package/dist/extensions/admin-view.d.ts +37 -10
- package/dist/extensions/admin-view.js +103 -20
- package/dist/extensions/bootstrap.d.ts +17 -4
- package/dist/extensions/bootstrap.js +70 -9
- package/dist/extensions/cli.d.ts +12 -0
- package/dist/extensions/cli.js +11 -2
- package/dist/extensions/config-hash.d.ts +10 -0
- package/dist/extensions/config-hash.js +38 -0
- package/dist/extensions/deployment-config.d.ts +28 -5
- package/dist/extensions/deployment-config.js +48 -7
- package/dist/extensions/effective-config.d.ts +127 -0
- package/dist/extensions/effective-config.js +368 -0
- package/dist/extensions/extensions.module.js +11 -11
- package/dist/extensions/hooks.d.ts +37 -4
- package/dist/extensions/hooks.js +82 -16
- package/dist/extensions/host.d.ts +24 -10
- package/dist/extensions/host.js +49 -54
- package/dist/extensions/installs.d.ts +20 -8
- package/dist/extensions/installs.js +37 -15
- package/dist/extensions/org-config.d.ts +75 -6
- package/dist/extensions/org-config.js +184 -32
- 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/permission-view.d.ts +16 -4
- package/dist/extensions/permission-view.js +4 -4
- package/dist/extensions/plugin-items.d.ts +21 -0
- package/dist/extensions/plugin-items.js +42 -0
- package/dist/extensions/point-defaults.d.ts +12 -5
- package/dist/extensions/point-defaults.js +37 -9
- package/dist/extensions/resolve.d.ts +5 -1
- package/dist/extensions/resolve.js +15 -2
- package/dist/extensions/state.module.d.ts +9 -0
- package/dist/extensions/state.module.js +38 -0
- package/dist/files/previewers.d.ts +8 -1
- package/dist/files/previewers.js +35 -6
- package/dist/http/api.module.js +25 -3
- package/dist/http/app.d.ts +11 -2
- package/dist/http/app.js +31 -5
- package/dist/http/plugin-dispatch.d.ts +4 -1
- package/dist/http/plugin-dispatch.js +14 -2
- package/dist/identity/accounts.d.ts +29 -29
- package/dist/identity/accounts.js +47 -47
- package/dist/identity/audit.d.ts +2 -1
- package/dist/identity/auth.guard.d.ts +13 -5
- package/dist/identity/auth.guard.js +26 -9
- package/dist/identity/identity.module.d.ts +1 -1
- package/dist/identity/identity.module.js +4 -4
- package/dist/identity/me.controller.js +1 -1
- package/dist/identity/principal.d.ts +3 -3
- package/dist/identity/principal.js +3 -3
- package/dist/identity/settings.d.ts +22 -11
- package/dist/identity/settings.js +53 -18
- package/dist/identity/{enterprise-admin.d.ts → super-admin.d.ts} +5 -5
- package/dist/identity/{enterprise-admin.js → super-admin.js} +24 -24
- package/dist/inbox/inbox.module.d.ts +4 -1
- package/dist/inbox/inbox.module.js +7 -3
- package/dist/inbox/inbox.service.d.ts +62 -3
- package/dist/inbox/inbox.service.js +74 -4
- 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 +1 -1
- package/dist/index.js +1 -1
- package/dist/infra/cli/kernel-cli.module.js +9 -1
- package/dist/infra/config/kernel-config.service.js +24 -1
- package/dist/infra/database/xact-lock.d.ts +1 -1
- package/dist/infra/database/xact-lock.js +1 -1
- package/dist/infra/events/kernel-events.d.ts +19 -2
- package/dist/infra/queue/add-job-once.d.ts +14 -0
- package/dist/infra/queue/add-job-once.js +16 -0
- package/dist/kernel.module.js +6 -0
- package/dist/lifecycle/kernel-lifecycle.d.ts +1 -1
- package/dist/lifecycle/kernel-lifecycle.js +4 -4
- 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 +99 -0
- package/dist/models/enablement.js +263 -0
- package/dist/models/models.module.d.ts +5 -1
- package/dist/models/models.module.js +16 -4
- package/dist/models/prices.d.ts +5 -5
- package/dist/models/prices.js +4 -4
- package/dist/models/purposes.controller.d.ts +6 -4
- package/dist/models/purposes.controller.js +13 -7
- package/dist/models/purposes.d.ts +37 -12
- package/dist/models/purposes.js +63 -17
- package/dist/orgs/directory-sync.d.ts +14 -5
- package/dist/orgs/directory-sync.js +41 -17
- package/dist/orgs/offboarding.d.ts +9 -7
- package/dist/orgs/offboarding.js +28 -17
- package/dist/orgs/org-lock.d.ts +5 -0
- package/dist/orgs/org-lock.js +13 -0
- package/dist/orgs/org.guard.d.ts +10 -0
- package/dist/orgs/org.guard.js +43 -32
- package/dist/orgs/orgs.module.js +3 -0
- package/dist/orgs/orgs.service.d.ts +20 -7
- package/dist/orgs/orgs.service.js +32 -12
- package/dist/orgs/roles.d.ts +1 -1
- package/dist/orgs/roles.js +5 -1
- package/dist/orgs/settings.controller.d.ts +1 -1
- package/dist/orgs/settings.service.d.ts +15 -3
- package/dist/orgs/settings.service.js +6 -2
- package/dist/overrides.d.ts +3 -0
- package/dist/overrides.js +2 -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 +11 -0
- package/dist/platform/errors.js +26 -0
- package/dist/platform/exclusions.d.ts +12 -0
- package/dist/platform/exclusions.js +1405 -0
- package/dist/platform/method.d.ts +6 -0
- package/dist/platform/method.js +15 -0
- package/dist/platform/operation.d.ts +92 -0
- package/dist/platform/operation.js +35 -0
- package/dist/platform/ops/agent-templates.ops.d.ts +14 -0
- package/dist/platform/ops/agent-templates.ops.js +92 -0
- package/dist/platform/ops/agents.ops.d.ts +19 -0
- package/dist/platform/ops/agents.ops.js +294 -0
- package/dist/platform/ops/connectors.ops.d.ts +15 -0
- package/dist/platform/ops/connectors.ops.js +126 -0
- package/dist/platform/ops/errors.d.ts +11 -0
- package/dist/platform/ops/errors.js +22 -0
- package/dist/platform/ops/extensions.ops.d.ts +19 -0
- package/dist/platform/ops/extensions.ops.js +116 -0
- package/dist/platform/ops/marketplaces.ops.d.ts +16 -0
- package/dist/platform/ops/marketplaces.ops.js +157 -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 +23 -0
- package/dist/platform/ops/platform.ops.js +158 -0
- package/dist/platform/ops/plugins.ops.d.ts +33 -0
- package/dist/platform/ops/plugins.ops.js +377 -0
- package/dist/platform/ops/requests.ops.d.ts +14 -0
- package/dist/platform/ops/requests.ops.js +153 -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 +13 -0
- package/dist/platform/ops/skills.ops.js +98 -0
- package/dist/platform/ops/summary.d.ts +10 -0
- package/dist/platform/ops/summary.js +18 -0
- package/dist/platform/platform-ops.module.d.ts +7 -0
- package/dist/platform/platform-ops.module.js +55 -0
- package/dist/platform/platform.module.d.ts +8 -0
- package/dist/platform/platform.module.js +25 -0
- package/dist/platform/redact-orgs.d.ts +7 -0
- package/dist/platform/redact-orgs.js +52 -0
- package/dist/platform/registry.d.ts +30 -0
- package/dist/platform/registry.js +111 -0
- package/dist/roles/worker-role.d.ts +6 -4
- package/dist/roles/worker-role.js +14 -7
- package/dist/roles/worker.module.d.ts +1 -1
- package/dist/roles/worker.module.js +9 -1
- package/dist/runtime/context/build.d.ts +6 -4
- package/dist/runtime/context/build.js +26 -7
- package/dist/runtime/context/claude-tools.d.ts +2 -1
- package/dist/runtime/context/claude-tools.js +5 -4
- package/dist/runtime/context/compaction.js +9 -0
- package/dist/runtime/context/reminders.d.ts +2 -0
- package/dist/runtime/context/reminders.js +2 -0
- package/dist/runtime/context/skills.js +9 -2
- package/dist/runtime/context/tool-changes.d.ts +27 -0
- package/dist/runtime/context/tool-changes.js +60 -0
- package/dist/runtime/hook-calls.d.ts +8 -1
- package/dist/runtime/hook-calls.js +40 -7
- package/dist/runtime/langgraph-loop.d.ts +3 -1
- package/dist/runtime/langgraph-loop.js +35 -17
- package/dist/runtime/loop.d.ts +32 -4
- package/dist/runtime/maintenance.d.ts +7 -4
- package/dist/runtime/maintenance.js +23 -8
- package/dist/runtime/model-call.d.ts +38 -11
- package/dist/runtime/model-call.js +97 -24
- package/dist/runtime/providers.d.ts +146 -32
- package/dist/runtime/providers.js +321 -67
- package/dist/runtime/run-control.d.ts +11 -1
- package/dist/runtime/run-control.js +12 -0
- package/dist/runtime/run-drafts.d.ts +85 -0
- package/dist/runtime/run-drafts.js +230 -0
- package/dist/runtime/run-jobs.d.ts +3 -5
- package/dist/runtime/run-jobs.js +3 -7
- package/dist/runtime/run-queue.d.ts +37 -3
- package/dist/runtime/run-queue.js +188 -11
- package/dist/runtime/run-worker.d.ts +12 -6
- package/dist/runtime/run-worker.js +58 -35
- package/dist/runtime/runtime.module.js +3 -0
- package/dist/runtime/step-log.d.ts +9 -4
- package/dist/runtime/step-log.js +8 -5
- package/dist/runtime/stream.controller.d.ts +23 -1
- package/dist/runtime/stream.controller.js +60 -3
- package/dist/runtime/stream.d.ts +4 -1
- package/dist/runtime/stream.js +27 -3
- package/dist/runtime/subagents/child.d.ts +55 -7
- package/dist/runtime/subagents/child.js +105 -7
- package/dist/runtime/subagents/definition.d.ts +12 -3
- package/dist/runtime/subagents/definition.js +46 -32
- package/dist/runtime/subagents/deliveries.d.ts +71 -0
- package/dist/runtime/subagents/deliveries.js +228 -0
- package/dist/runtime/subagents/dispatch.d.ts +115 -26
- package/dist/runtime/subagents/dispatch.js +212 -141
- package/dist/runtime/subagents/limits.d.ts +24 -5
- package/dist/runtime/subagents/limits.js +40 -6
- package/dist/runtime/subagents/messages.d.ts +95 -0
- package/dist/runtime/subagents/messages.js +328 -0
- package/dist/runtime/subagents/preamble.d.ts +4 -4
- package/dist/runtime/subagents/preamble.js +9 -7
- package/dist/runtime/subagents/progress.d.ts +8 -6
- 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 +24 -7
- package/dist/runtime/subagents/roster.js +47 -11
- package/dist/runtime/subagents/skill-fork.d.ts +3 -2
- package/dist/runtime/subagents/skill-fork.js +8 -4
- 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 +7 -4
- package/dist/runtime/subagents/subagents.service.js +11 -6
- 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 +33 -38
- package/dist/runtime/usage-report.js +169 -96
- package/dist/runtime/waits.d.ts +140 -37
- package/dist/runtime/waits.js +394 -106
- package/dist/sandbox/jobs.d.ts +40 -13
- package/dist/sandbox/jobs.js +57 -20
- package/dist/sandbox/leases.d.ts +37 -54
- package/dist/sandbox/leases.js +71 -115
- package/dist/sandbox/providers.d.ts +2 -2
- package/dist/sandbox/providers.js +1 -1
- package/dist/sandbox/sandbox.module.d.ts +3 -2
- package/dist/sandbox/sandbox.module.js +4 -3
- package/dist/sandbox/sandbox.service.d.ts +229 -134
- package/dist/sandbox/sandbox.service.js +630 -409
- package/dist/skills/catalog.d.ts +3 -2
- package/dist/skills/catalog.js +21 -43
- package/dist/skills/changes.controller.d.ts +7 -0
- package/dist/skills/changes.controller.js +19 -1
- package/dist/skills/invoke.js +8 -3
- package/dist/skills/package.d.ts +20 -1
- package/dist/skills/package.js +28 -1
- package/dist/skills/skills.controller.d.ts +39 -4
- package/dist/skills/skills.controller.js +88 -10
- package/dist/skills/skills.module.js +10 -1
- package/dist/skills/skills.service.d.ts +106 -26
- package/dist/skills/skills.service.js +421 -75
- package/dist/skills/usable.d.ts +81 -0
- package/dist/skills/usable.js +379 -0
- package/dist/tools/approvals.service.d.ts +20 -2
- package/dist/tools/approvals.service.js +23 -4
- package/dist/tools/builtin-names.d.ts +21 -5
- package/dist/tools/builtin-names.js +30 -5
- package/dist/tools/builtins/agent.d.ts +23 -21
- package/dist/tools/builtins/agent.js +62 -55
- package/dist/tools/builtins/builtin-tools.d.ts +6 -2
- package/dist/tools/builtins/builtin-tools.js +37 -12
- package/dist/tools/builtins/handback.d.ts +28 -0
- package/dist/tools/builtins/handback.js +53 -0
- package/dist/tools/builtins/platform.d.ts +34 -0
- package/dist/tools/builtins/platform.js +362 -0
- package/dist/tools/builtins/sandbox/bash.js +13 -3
- package/dist/tools/builtins/sandbox/common.d.ts +43 -24
- package/dist/tools/builtins/sandbox/common.js +80 -45
- package/dist/tools/builtins/sandbox/edit.js +2 -2
- package/dist/tools/builtins/sandbox/glob.js +2 -2
- package/dist/tools/builtins/sandbox/grep.js +2 -4
- package/dist/tools/builtins/sandbox/index.d.ts +1 -1
- package/dist/tools/builtins/sandbox/index.js +1 -1
- package/dist/tools/builtins/sandbox/read.js +1 -1
- package/dist/tools/builtins/sandbox/task-output.d.ts +14 -3
- package/dist/tools/builtins/sandbox/task-output.js +30 -5
- package/dist/tools/builtins/sandbox/task-stop.js +2 -1
- package/dist/tools/builtins/sandbox/write.js +2 -2
- 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 +22 -14
- package/dist/tools/builtins/skill-load.js +86 -57
- package/dist/tools/builtins/skill-write.js +1 -1
- package/dist/tools/builtins/web/extract.js +5 -1
- package/dist/tools/builtins/web/fetch.js +1 -0
- package/dist/tools/builtins/web/search.js +1 -0
- package/dist/tools/connectors.controller.d.ts +10 -0
- package/dist/tools/connectors.controller.js +12 -0
- package/dist/tools/connectors.service.d.ts +46 -5
- package/dist/tools/connectors.service.js +94 -15
- 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 +42 -1
- package/dist/tools/info.js +64 -1
- package/dist/tools/org-tool-switches.d.ts +74 -0
- package/dist/tools/org-tool-switches.js +184 -0
- package/dist/tools/pipeline.d.ts +46 -40
- package/dist/tools/pipeline.js +193 -364
- package/dist/tools/policy.d.ts +1 -1
- package/dist/tools/policy.js +36 -16
- package/dist/tools/registry.d.ts +98 -5
- package/dist/tools/registry.js +87 -9
- package/dist/tools/tools.module.js +12 -2
- package/dist/ui/views.d.ts +2 -1
- package/dist/ui/views.js +17 -3
- package/package.json +3 -3
- 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/dist/catalog/upgrade-targets.d.ts +0 -56
- package/dist/catalog/upgrade-targets.js +0 -90
- package/dist/conversations/sandbox-status.d.ts +0 -24
- package/dist/conversations/sandbox-status.js +0 -52
- package/dist/extensions/org-config.controller.d.ts +0 -32
- package/dist/extensions/org-config.controller.js +0 -70
|
@@ -0,0 +1,524 @@
|
|
|
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
|
+
};
|
|
10
|
+
import { isDeepStrictEqual } from "node:util";
|
|
11
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
12
|
+
import { configFields, getPath } from "../config/fields.js";
|
|
13
|
+
import { createSecrets } from "../ctx/secrets.js";
|
|
14
|
+
import { ApiError } from "../errors.js";
|
|
15
|
+
import { audit } from "../identity/audit.js";
|
|
16
|
+
import { afterCommit } from "../infra/database/after-commit.js";
|
|
17
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
18
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
19
|
+
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
20
|
+
import { KERNEL_LOGGER, KEYRING } from "../infra/tokens.js";
|
|
21
|
+
import { OrgLock } from "../orgs/org-lock.js";
|
|
22
|
+
import { toIssues } from "./config-issues.js";
|
|
23
|
+
import { configMessages, safeConfigFormSchema } from "./config-json-schema.js";
|
|
24
|
+
import { applySecretEntries } from "./deployment-config.js";
|
|
25
|
+
import { deleteDeep, setDeep } from "./deployment-config-store.js";
|
|
26
|
+
import { EffectiveConfigs, mergeCopy, OVERRIDE_SECRETS_NAMESPACE, overrideSecretKey, overrideSecretPaths, platformOverrideValues, } from "./effective-config.js";
|
|
27
|
+
import { ExtensionHost } from "./host.js";
|
|
28
|
+
import { extensionVisibleTo } from "./org-config.js";
|
|
29
|
+
import { fieldLevels } from "./org-levels.js";
|
|
30
|
+
const levelOf = (levels, path) => levels.get(path.split(".")[0]) ?? "hidden";
|
|
31
|
+
const notOverridable = (plugin, paths) => new ApiError("extension.field_not_overridable", `These config fields of extension ${plugin} cannot be set by an organization: ${paths.join(", ")}`, paths.map((path) => ({ path })));
|
|
32
|
+
const noCopy = (plugin) => new ApiError("extension.no_org_override", `This organization follows the platform configuration of extension ${plugin}`);
|
|
33
|
+
/**
|
|
34
|
+
* Org copies of an extension's overridable deployment config (spec A §5.4, §5.5, §5.8): one row of
|
|
35
|
+
* `extension_org_overrides` per copy (its non-secret values), each secret in `capybara.secrets`
|
|
36
|
+
* under the org (namespace `kernel`, key `plugin-override:<plugin>:<path>`), written in the same
|
|
37
|
+
* transaction under the org row lock. Writes are org-audited and evict the cached copy after the
|
|
38
|
+
* commit. Platform secrets never enter a copy.
|
|
39
|
+
*/
|
|
40
|
+
let OrgOverrides = class OrgOverrides {
|
|
41
|
+
kdb;
|
|
42
|
+
txHost;
|
|
43
|
+
keyring;
|
|
44
|
+
host;
|
|
45
|
+
orgLock;
|
|
46
|
+
effective;
|
|
47
|
+
log;
|
|
48
|
+
constructor(kdb, txHost, keyring, host,
|
|
49
|
+
/** The org row lock: re-checks `org.extensions.manage` under the lock. */
|
|
50
|
+
orgLock, effective, log) {
|
|
51
|
+
this.kdb = kdb;
|
|
52
|
+
this.txHost = txHost;
|
|
53
|
+
this.keyring = keyring;
|
|
54
|
+
this.host = host;
|
|
55
|
+
this.orgLock = orgLock;
|
|
56
|
+
this.effective = effective;
|
|
57
|
+
this.log = log;
|
|
58
|
+
}
|
|
59
|
+
get db() {
|
|
60
|
+
return this.kdb.db;
|
|
61
|
+
}
|
|
62
|
+
running(plugin) {
|
|
63
|
+
const inst = this.host.current(plugin);
|
|
64
|
+
if (!inst)
|
|
65
|
+
throw new ApiError("extension.not_found", `Extension ${plugin} is not installed`);
|
|
66
|
+
const schema = inst.manifest.config?.deployment;
|
|
67
|
+
return { inst, schema, levels: fieldLevels(schema) };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The running extension, for an org: one the org does not see under plugin scope (a `named`
|
|
71
|
+
* plugin without it) is answered like an unknown one, so its platform values never reach it.
|
|
72
|
+
*/
|
|
73
|
+
async runningFor(orgId, plugin) {
|
|
74
|
+
const run = this.running(plugin);
|
|
75
|
+
if (!(await extensionVisibleTo(this.db, orgId, plugin))) {
|
|
76
|
+
throw new ApiError("extension.not_found", `Extension ${plugin} is not installed`);
|
|
77
|
+
}
|
|
78
|
+
return run;
|
|
79
|
+
}
|
|
80
|
+
/** The org's view (read-only and overridable fields, the copy state and validity). */
|
|
81
|
+
async view(orgId, plugin) {
|
|
82
|
+
return this.render(orgId, await this.runningFor(orgId, plugin));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Saves overridable fields (`values` keyed by field dot path: `null` clears, omitted keeps;
|
|
86
|
+
* secret fields too, as in the platform form) and secret record entries. The first save creates
|
|
87
|
+
* the copy from the platform's non-secret overridable values plus `values` (secret fields start
|
|
88
|
+
* empty). A path that is not an overridable field of the schema (read-only, hidden, unknown) ->
|
|
89
|
+
* 400 `extension.field_not_overridable`; an invalid result (an empty required secret included)
|
|
90
|
+
* -> 400 `extension.config_invalid`, nothing written. Audits `extension.org_override_saved`.
|
|
91
|
+
*/
|
|
92
|
+
async save(orgId, plugin, values, secretEntries, actor) {
|
|
93
|
+
const run = await this.runningFor(orgId, plugin);
|
|
94
|
+
const fields = new Map((run.schema ? configFields(run.schema) : []).map((f) => [f.path, f.meta?.secret === true]));
|
|
95
|
+
const paths = [...Object.keys(values), ...secretEntries.map((e) => e.path)];
|
|
96
|
+
const refused = [
|
|
97
|
+
...new Set(paths.filter((p) => !fields.has(p) || levelOf(run.levels, p) !== "override")),
|
|
98
|
+
];
|
|
99
|
+
if (refused.length > 0)
|
|
100
|
+
throw notOverridable(plugin, refused);
|
|
101
|
+
const badEntries = secretEntries.filter((e) => fields.get(e.path) !== true || Object.hasOwn(values, e.path));
|
|
102
|
+
if (badEntries.length > 0) {
|
|
103
|
+
throw new ApiError("validation_failed", `Invalid secret entries for the organization config of extension ${plugin}`, badEntries.map((e) => ({
|
|
104
|
+
path: e.path,
|
|
105
|
+
message: Object.hasOwn(values, e.path)
|
|
106
|
+
? "given both in values and in secretEntries"
|
|
107
|
+
: "not a secret field",
|
|
108
|
+
})));
|
|
109
|
+
}
|
|
110
|
+
return this.writeSave(orgId, plugin, run, fields, values, secretEntries, actor);
|
|
111
|
+
}
|
|
112
|
+
async writeSave(orgId, plugin, run, fields, values, secretEntries, actor) {
|
|
113
|
+
const schema = run.schema;
|
|
114
|
+
const t = this.db;
|
|
115
|
+
await this.orgLock.lockFor(orgId, actor.accountId, "org.extensions.manage");
|
|
116
|
+
const row = await this.lockedRow(orgId, plugin);
|
|
117
|
+
const platform = await this.host.rawDeploymentConfig(plugin);
|
|
118
|
+
const prior = row
|
|
119
|
+
? { config: structuredClone(row.config), secrets: await this.readSecrets(orgId, plugin) }
|
|
120
|
+
: undefined;
|
|
121
|
+
const copy = prior
|
|
122
|
+
? structuredClone(prior)
|
|
123
|
+
: { config: platformOverrideValues(schema, platform), secrets: {} };
|
|
124
|
+
for (const [path, v] of Object.entries(values)) {
|
|
125
|
+
if (fields.get(path)) {
|
|
126
|
+
if (v === null)
|
|
127
|
+
delete copy.secrets[path];
|
|
128
|
+
else
|
|
129
|
+
copy.secrets[path] = structuredClone(v);
|
|
130
|
+
}
|
|
131
|
+
else if (v === null)
|
|
132
|
+
deleteDeep(copy.config, path);
|
|
133
|
+
else
|
|
134
|
+
setDeep(copy.config, path, structuredClone(v));
|
|
135
|
+
}
|
|
136
|
+
if (secretEntries.length > 0) {
|
|
137
|
+
const records = {};
|
|
138
|
+
for (const e of secretEntries) {
|
|
139
|
+
if (copy.secrets[e.path] !== undefined) {
|
|
140
|
+
setDeep(records, e.path, structuredClone(copy.secrets[e.path]));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
applySecretEntries(records, secretEntries);
|
|
144
|
+
for (const e of secretEntries) {
|
|
145
|
+
const v = getPath(records, e.path);
|
|
146
|
+
if (v === undefined)
|
|
147
|
+
delete copy.secrets[e.path];
|
|
148
|
+
else
|
|
149
|
+
copy.secrets[e.path] = v;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const merged = this.validated(plugin, run, platform, copy);
|
|
153
|
+
// a secret is compared only with the copy's own previous value, never with the platform's
|
|
154
|
+
// (an audit that said "unchanged" would tell the org its key equals the platform's, A §5.5);
|
|
155
|
+
// on a first save every touched secret counts as changed
|
|
156
|
+
const before = prior ? mergeCopy(schema, platform, prior) : platform;
|
|
157
|
+
const changed = [...new Set(touchedPaths(values, secretEntries))]
|
|
158
|
+
.filter((p) => fields.get(p)
|
|
159
|
+
? !prior || !isDeepStrictEqual(prior.secrets[p], copy.secrets[p])
|
|
160
|
+
: !isDeepStrictEqual(getPath(before, p), getPath(merged, p)))
|
|
161
|
+
.sort();
|
|
162
|
+
await t
|
|
163
|
+
.insertInto("extension_org_overrides")
|
|
164
|
+
.values({
|
|
165
|
+
plugin,
|
|
166
|
+
org_id: orgId,
|
|
167
|
+
config: JSON.stringify(copy.config),
|
|
168
|
+
created_by: actor.accountId,
|
|
169
|
+
updated_by: actor.accountId,
|
|
170
|
+
})
|
|
171
|
+
.onConflict((oc) => oc.columns(["plugin", "org_id"]).doUpdateSet({
|
|
172
|
+
config: JSON.stringify(copy.config),
|
|
173
|
+
updated_by: actor.accountId,
|
|
174
|
+
updated_at: new Date(),
|
|
175
|
+
}))
|
|
176
|
+
.execute();
|
|
177
|
+
await this.writeSecrets(orgId, plugin, schema, run.levels, copy.secrets);
|
|
178
|
+
await audit(t, {
|
|
179
|
+
actorAccountId: actor.accountId,
|
|
180
|
+
...(actor.tokenId !== undefined && { actorTokenId: actor.tokenId }),
|
|
181
|
+
orgId,
|
|
182
|
+
action: "extension.org_override_saved",
|
|
183
|
+
target: plugin,
|
|
184
|
+
detail: { changedPaths: changed },
|
|
185
|
+
});
|
|
186
|
+
const secretValues = Object.values(copy.secrets);
|
|
187
|
+
afterCommit(async () => {
|
|
188
|
+
if (secretValues.length > 0)
|
|
189
|
+
this.log.addOrgSecrets(secretValues);
|
|
190
|
+
await this.effective.invalidate(orgId, plugin);
|
|
191
|
+
});
|
|
192
|
+
return this.render(orgId, run);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Takes the platform's current values of non-secret overridable fields into the copy (spec A
|
|
196
|
+
* §5.5); the copy stays a copy. A secret, read-only, hidden or unknown path -> 400
|
|
197
|
+
* `extension.field_not_overridable`; no copy -> 404 `extension.no_org_override`. Audits
|
|
198
|
+
* `extension.org_override_taken`.
|
|
199
|
+
*/
|
|
200
|
+
async take(orgId, plugin, paths, actor) {
|
|
201
|
+
const run = await this.runningFor(orgId, plugin);
|
|
202
|
+
const fields = new Map((run.schema ? configFields(run.schema) : []).map((f) => [f.path, f.meta?.secret === true]));
|
|
203
|
+
const refused = [
|
|
204
|
+
...new Set(paths.filter((p) => fields.get(p) !== false || levelOf(run.levels, p) !== "override")),
|
|
205
|
+
];
|
|
206
|
+
if (refused.length > 0)
|
|
207
|
+
throw notOverridable(plugin, refused);
|
|
208
|
+
return this.writeTake(orgId, plugin, run, paths, actor);
|
|
209
|
+
}
|
|
210
|
+
async writeTake(orgId, plugin, run, paths, actor) {
|
|
211
|
+
const t = this.db;
|
|
212
|
+
await this.orgLock.lockFor(orgId, actor.accountId, "org.extensions.manage");
|
|
213
|
+
const row = await this.lockedRow(orgId, plugin);
|
|
214
|
+
if (!row)
|
|
215
|
+
throw noCopy(plugin);
|
|
216
|
+
const copy = {
|
|
217
|
+
config: structuredClone(row.config),
|
|
218
|
+
secrets: await this.readSecrets(orgId, plugin),
|
|
219
|
+
};
|
|
220
|
+
const platform = await this.host.rawDeploymentConfig(plugin);
|
|
221
|
+
const changed = [];
|
|
222
|
+
for (const p of [...new Set(paths)]) {
|
|
223
|
+
const v = getPath(platform, p);
|
|
224
|
+
if (!isDeepStrictEqual(getPath(copy.config, p), v))
|
|
225
|
+
changed.push(p);
|
|
226
|
+
if (v === undefined)
|
|
227
|
+
deleteDeep(copy.config, p);
|
|
228
|
+
else
|
|
229
|
+
setDeep(copy.config, p, structuredClone(v));
|
|
230
|
+
}
|
|
231
|
+
this.validated(plugin, run, platform, copy);
|
|
232
|
+
await t
|
|
233
|
+
.updateTable("extension_org_overrides")
|
|
234
|
+
.set({
|
|
235
|
+
config: JSON.stringify(copy.config),
|
|
236
|
+
updated_by: actor.accountId,
|
|
237
|
+
updated_at: new Date(),
|
|
238
|
+
})
|
|
239
|
+
.where("plugin", "=", plugin)
|
|
240
|
+
.where("org_id", "=", orgId)
|
|
241
|
+
.execute();
|
|
242
|
+
await audit(t, {
|
|
243
|
+
actorAccountId: actor.accountId,
|
|
244
|
+
...(actor.tokenId !== undefined && { actorTokenId: actor.tokenId }),
|
|
245
|
+
orgId,
|
|
246
|
+
action: "extension.org_override_taken",
|
|
247
|
+
target: plugin,
|
|
248
|
+
detail: { changedPaths: changed.sort() },
|
|
249
|
+
});
|
|
250
|
+
afterCommit(() => this.effective.invalidate(orgId, plugin));
|
|
251
|
+
return this.render(orgId, run);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Drops the copy and every secret of it in one transaction; the org follows the platform again
|
|
255
|
+
* (spec A §5.5). No copy -> 404 `extension.no_org_override`. Audits `extension.org_override_reset`.
|
|
256
|
+
*/
|
|
257
|
+
async reset(orgId, plugin, actor) {
|
|
258
|
+
return this.writeReset(orgId, plugin, await this.runningFor(orgId, plugin), actor);
|
|
259
|
+
}
|
|
260
|
+
async writeReset(orgId, plugin, run, actor) {
|
|
261
|
+
const t = this.db;
|
|
262
|
+
await this.orgLock.lockFor(orgId, actor.accountId, "org.extensions.manage");
|
|
263
|
+
const gone = await t
|
|
264
|
+
.deleteFrom("extension_org_overrides")
|
|
265
|
+
.where("plugin", "=", plugin)
|
|
266
|
+
.where("org_id", "=", orgId)
|
|
267
|
+
.returning("plugin")
|
|
268
|
+
.executeTakeFirst();
|
|
269
|
+
if (!gone)
|
|
270
|
+
throw noCopy(plugin);
|
|
271
|
+
const store = createSecrets(t, this.keyring, OVERRIDE_SECRETS_NAMESPACE);
|
|
272
|
+
for (const key of await this.secretKeys(orgId, plugin))
|
|
273
|
+
await store.delete(orgId, key);
|
|
274
|
+
await audit(t, {
|
|
275
|
+
actorAccountId: actor.accountId,
|
|
276
|
+
...(actor.tokenId !== undefined && { actorTokenId: actor.tokenId }),
|
|
277
|
+
orgId,
|
|
278
|
+
action: "extension.org_override_reset",
|
|
279
|
+
target: plugin,
|
|
280
|
+
});
|
|
281
|
+
afterCommit(() => this.effective.invalidate(orgId, plugin));
|
|
282
|
+
return this.render(orgId, run);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* The orgs (not deleted) holding a copy of the extension, oldest first, with the overridable
|
|
286
|
+
* non-secret fields that differ from the platform and whether each copy secret is set (spec A
|
|
287
|
+
* §5.7); never a secret value. Differences need the running schema: an extension not running on
|
|
288
|
+
* this replica lists no differences and only the secrets the copies hold.
|
|
289
|
+
*/
|
|
290
|
+
async listForPlugin(plugin) {
|
|
291
|
+
const t = this.db;
|
|
292
|
+
const rows = await t
|
|
293
|
+
.selectFrom("extension_org_overrides as ov")
|
|
294
|
+
.innerJoin("orgs", "orgs.id", "ov.org_id")
|
|
295
|
+
.select(["ov.org_id", "orgs.name", "ov.created_at", "ov.config"])
|
|
296
|
+
.where("ov.plugin", "=", plugin)
|
|
297
|
+
.where("orgs.deleted_at", "is", null)
|
|
298
|
+
.orderBy("ov.created_at")
|
|
299
|
+
.orderBy("ov.org_id")
|
|
300
|
+
.execute();
|
|
301
|
+
const inst = this.host.current(plugin);
|
|
302
|
+
const schema = inst?.manifest.config?.deployment;
|
|
303
|
+
const levels = fieldLevels(schema);
|
|
304
|
+
const secretPaths = schema ? overrideSecretPaths(schema, levels) : undefined;
|
|
305
|
+
const plain = schema
|
|
306
|
+
? configFields(schema).filter((f) => f.meta?.secret !== true && levelOf(levels, f.path) === "override")
|
|
307
|
+
: [];
|
|
308
|
+
const platform = rows.length > 0 ? await this.host.rawDeploymentConfig(plugin) : undefined;
|
|
309
|
+
const out = [];
|
|
310
|
+
for (const r of rows) {
|
|
311
|
+
const keys = await this.secretKeys(r.org_id, plugin);
|
|
312
|
+
const prefix = overrideSecretKey(plugin, "");
|
|
313
|
+
const held = new Set(keys.map((k) => k.slice(prefix.length)));
|
|
314
|
+
out.push({
|
|
315
|
+
orgId: r.org_id,
|
|
316
|
+
orgName: r.name,
|
|
317
|
+
createdAt: new Date(r.created_at).toISOString(),
|
|
318
|
+
differing: plain
|
|
319
|
+
.filter((f) => {
|
|
320
|
+
const own = getPath(r.config, f.path);
|
|
321
|
+
return own !== undefined && !isDeepStrictEqual(own, getPath(platform, f.path));
|
|
322
|
+
})
|
|
323
|
+
.map((f) => f.path),
|
|
324
|
+
secrets: (secretPaths ?? [...held].sort()).map((path) => ({ path, set: held.has(path) })),
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
/** The merged copy validated with the full schema; invalid -> 400 `extension.config_invalid`. */
|
|
330
|
+
validated(plugin, run, platform, copy) {
|
|
331
|
+
const schema = run.schema;
|
|
332
|
+
const merged = mergeCopy(schema, platform, copy);
|
|
333
|
+
const r = schema.safeParse(merged);
|
|
334
|
+
if (!r.success) {
|
|
335
|
+
throw new ApiError("extension.config_invalid", `Invalid organization copy of the configuration of extension ${plugin}`, orgIssues(toIssues(r.error, this.messagesOf(plugin, run)), run.levels));
|
|
336
|
+
}
|
|
337
|
+
return merged;
|
|
338
|
+
}
|
|
339
|
+
messagesOf(plugin, run) {
|
|
340
|
+
return configMessages(this.formSchemaOf(plugin, run));
|
|
341
|
+
}
|
|
342
|
+
/** The deployment form JSON Schema (hints dropped when invalid; one warning). Never throws. */
|
|
343
|
+
formSchemaOf(plugin, run) {
|
|
344
|
+
if (!run.schema)
|
|
345
|
+
return undefined;
|
|
346
|
+
const r = safeConfigFormSchema(run.schema, "deployment", (err, fallback) => this.log.warn("the deployment config form schema could not be built with its UI hints; hints dropped", { plugin, version: run.inst.manifest.version, schema: fallback, err }));
|
|
347
|
+
return r?.schema;
|
|
348
|
+
}
|
|
349
|
+
async lockedRow(orgId, plugin) {
|
|
350
|
+
return this.db
|
|
351
|
+
.selectFrom("extension_org_overrides")
|
|
352
|
+
.select(["config", "created_at"])
|
|
353
|
+
.where("plugin", "=", plugin)
|
|
354
|
+
.where("org_id", "=", orgId)
|
|
355
|
+
.forUpdate()
|
|
356
|
+
.executeTakeFirst();
|
|
357
|
+
}
|
|
358
|
+
/** The keys of the org's copy secrets for `plugin` (any path, current or stale). */
|
|
359
|
+
async secretKeys(orgId, plugin) {
|
|
360
|
+
const prefix = overrideSecretKey(plugin, "");
|
|
361
|
+
const rows = await this.db
|
|
362
|
+
.selectFrom("secrets")
|
|
363
|
+
.select("key")
|
|
364
|
+
.where("namespace", "=", OVERRIDE_SECRETS_NAMESPACE)
|
|
365
|
+
.where("org_id", "=", orgId)
|
|
366
|
+
.where("key", "like", `${prefix}%`)
|
|
367
|
+
.execute();
|
|
368
|
+
return rows.map((r) => r.key).filter((k) => k.startsWith(prefix));
|
|
369
|
+
}
|
|
370
|
+
async readSecrets(orgId, plugin) {
|
|
371
|
+
const prefix = overrideSecretKey(plugin, "");
|
|
372
|
+
const store = createSecrets(this.db, this.keyring, OVERRIDE_SECRETS_NAMESPACE);
|
|
373
|
+
const out = {};
|
|
374
|
+
for (const key of await this.secretKeys(orgId, plugin)) {
|
|
375
|
+
const v = await store.get(orgId, key);
|
|
376
|
+
if (v !== null)
|
|
377
|
+
out[key.slice(prefix.length)] = JSON.parse(v);
|
|
378
|
+
}
|
|
379
|
+
return out;
|
|
380
|
+
}
|
|
381
|
+
/** Writes the copy's secrets of the current schema and drops stale keys (paths no longer secret). */
|
|
382
|
+
async writeSecrets(orgId, plugin, schema, levels, secrets) {
|
|
383
|
+
const store = createSecrets(this.db, this.keyring, OVERRIDE_SECRETS_NAMESPACE);
|
|
384
|
+
const live = overrideSecretPaths(schema, levels);
|
|
385
|
+
for (const p of live) {
|
|
386
|
+
const v = secrets[p];
|
|
387
|
+
if (v === undefined)
|
|
388
|
+
await store.delete(orgId, overrideSecretKey(plugin, p));
|
|
389
|
+
else
|
|
390
|
+
await store.set(orgId, overrideSecretKey(plugin, p), JSON.stringify(v));
|
|
391
|
+
}
|
|
392
|
+
const keep = new Set(live.map((p) => overrideSecretKey(plugin, p)));
|
|
393
|
+
for (const key of await this.secretKeys(orgId, plugin)) {
|
|
394
|
+
if (!keep.has(key))
|
|
395
|
+
await store.delete(orgId, key);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
async render(orgId, run) {
|
|
399
|
+
const row = await this.db
|
|
400
|
+
.selectFrom("extension_org_overrides")
|
|
401
|
+
.select(["config", "created_at"])
|
|
402
|
+
.where("plugin", "=", run.inst.name)
|
|
403
|
+
.where("org_id", "=", orgId)
|
|
404
|
+
.executeTakeFirst();
|
|
405
|
+
const held = row ? new Set(await this.secretPathsHeld(orgId, run.inst.name)) : new Set();
|
|
406
|
+
// readonly values and secret state as the running instance has them (defaults applied, as
|
|
407
|
+
// the platform form shows); overridable values raw, as a copy stores and `take` copies them
|
|
408
|
+
const parsed = run.inst.config;
|
|
409
|
+
const raw = await this.host.rawDeploymentConfig(run.inst.name);
|
|
410
|
+
const fields = [];
|
|
411
|
+
for (const f of run.schema ? configFields(run.schema) : []) {
|
|
412
|
+
const level = levelOf(run.levels, f.path);
|
|
413
|
+
if (level === "hidden")
|
|
414
|
+
continue;
|
|
415
|
+
const secret = f.meta?.secret === true;
|
|
416
|
+
const pv = level === "override" && !secret
|
|
417
|
+
? (getPath(raw, f.path) ?? getPath(parsed, f.path))
|
|
418
|
+
: getPath(parsed, f.path);
|
|
419
|
+
const field = {
|
|
420
|
+
path: f.path,
|
|
421
|
+
level,
|
|
422
|
+
secret,
|
|
423
|
+
platform: secret
|
|
424
|
+
? { set: pv !== undefined }
|
|
425
|
+
: pv === undefined
|
|
426
|
+
? {}
|
|
427
|
+
: { value: structuredClone(pv) },
|
|
428
|
+
};
|
|
429
|
+
if (row && level === "override") {
|
|
430
|
+
if (secret)
|
|
431
|
+
field.org = { set: held.has(f.path) };
|
|
432
|
+
else {
|
|
433
|
+
const ov = getPath(row.config, f.path);
|
|
434
|
+
field.org = ov === undefined ? {} : { value: structuredClone(ov) };
|
|
435
|
+
field.differs = ov !== undefined && !isDeepStrictEqual(ov, pv);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
fields.push(field);
|
|
439
|
+
}
|
|
440
|
+
const eff = await this.effective.get(orgId, run.inst.name);
|
|
441
|
+
const form = this.formSchemaOf(run.inst.name, run);
|
|
442
|
+
return {
|
|
443
|
+
state: row ? "copy" : "following",
|
|
444
|
+
schema: form ? orgFormSchema(form, run.levels) : null,
|
|
445
|
+
...(row && { createdAt: new Date(row.created_at).toISOString() }),
|
|
446
|
+
fields,
|
|
447
|
+
valid: eff.ok,
|
|
448
|
+
issues: eff.ok ? [] : orgIssues(eff.issues, run.levels),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
async secretPathsHeld(orgId, plugin) {
|
|
452
|
+
const prefix = overrideSecretKey(plugin, "");
|
|
453
|
+
return (await this.secretKeys(orgId, plugin)).map((k) => k.slice(prefix.length));
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
__decorate([
|
|
457
|
+
Transactional()
|
|
458
|
+
], OrgOverrides.prototype, "writeSave", null);
|
|
459
|
+
__decorate([
|
|
460
|
+
Transactional()
|
|
461
|
+
], OrgOverrides.prototype, "writeTake", null);
|
|
462
|
+
__decorate([
|
|
463
|
+
Transactional()
|
|
464
|
+
], OrgOverrides.prototype, "writeReset", null);
|
|
465
|
+
__decorate([
|
|
466
|
+
Transactional({ isolationLevel: "repeatable read", accessMode: "read only" })
|
|
467
|
+
], OrgOverrides.prototype, "listForPlugin", null);
|
|
468
|
+
OrgOverrides = __decorate([
|
|
469
|
+
Injectable(),
|
|
470
|
+
__param(0, Inject(KernelDb)),
|
|
471
|
+
__param(1, Inject(TransactionHost)),
|
|
472
|
+
__param(2, Inject(KEYRING)),
|
|
473
|
+
__param(3, Inject(ExtensionHost)),
|
|
474
|
+
__param(4, Inject(OrgLock)),
|
|
475
|
+
__param(5, Inject(EffectiveConfigs)),
|
|
476
|
+
__param(6, Inject(KERNEL_LOGGER))
|
|
477
|
+
], OrgOverrides);
|
|
478
|
+
export { OrgOverrides };
|
|
479
|
+
/**
|
|
480
|
+
* The form JSON Schema an org may see (spec A §5.6, "hidden fields are not sent to the org at
|
|
481
|
+
* all"): a copy with only the read-only and overridable top-level properties, `required` limited
|
|
482
|
+
* to them, and root `x-ui` hints naming a hidden field dropped (`secrets[]` by path; `order` lists
|
|
483
|
+
* none). Values are never in it: `configJsonSchema` already strips secret defaults and examples.
|
|
484
|
+
*/
|
|
485
|
+
export function orgFormSchema(js, levels) {
|
|
486
|
+
const out = structuredClone(js);
|
|
487
|
+
const shown = (key) => (levels.get(key) ?? "hidden") !== "hidden";
|
|
488
|
+
const props = out.properties;
|
|
489
|
+
if (typeof props === "object" && props !== null) {
|
|
490
|
+
out.properties = Object.fromEntries(Object.entries(props).filter(([k]) => shown(k)));
|
|
491
|
+
}
|
|
492
|
+
if (Array.isArray(out.required)) {
|
|
493
|
+
out.required = out.required.filter((k) => typeof k === "string" && shown(k));
|
|
494
|
+
}
|
|
495
|
+
const ui = out["x-ui"];
|
|
496
|
+
if (typeof ui === "object" && ui !== null && !Array.isArray(ui)) {
|
|
497
|
+
const hints = ui;
|
|
498
|
+
if (Array.isArray(hints.secrets)) {
|
|
499
|
+
hints.secrets = hints.secrets.filter((e) => typeof e?.path === "string" && shown(e.path.split(".")[0]));
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return out;
|
|
503
|
+
}
|
|
504
|
+
/** Every path a save touches. */
|
|
505
|
+
function touchedPaths(values, entries) {
|
|
506
|
+
return [...Object.keys(values), ...entries.map((e) => e.path)];
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Issues as an org may see them: an issue on a hidden field would name a field the org never
|
|
510
|
+
* sees, so those collapse into one root issue.
|
|
511
|
+
*/
|
|
512
|
+
export function orgIssues(issues, levels) {
|
|
513
|
+
const shown = issues.filter((i) => i.path !== "" && levelOf(levels, i.path) !== "hidden");
|
|
514
|
+
if (shown.length === issues.length)
|
|
515
|
+
return issues;
|
|
516
|
+
return [
|
|
517
|
+
...shown,
|
|
518
|
+
{
|
|
519
|
+
path: "",
|
|
520
|
+
segments: [],
|
|
521
|
+
message: "the platform configuration of this extension is incomplete",
|
|
522
|
+
},
|
|
523
|
+
];
|
|
524
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LocalizedName } from "@capybara-hq/plugin-sdk";
|
|
2
|
+
import type { PluginScope } from "../catalog/scope.js";
|
|
2
3
|
import { type PermissionSet } from "./permission-set.js";
|
|
3
4
|
import type { ExtensionSource } from "./sources.js";
|
|
4
5
|
/**
|
|
@@ -36,10 +37,10 @@ export interface PermissionItem {
|
|
|
36
37
|
reason?: SensitiveReason;
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
|
-
* 敏感的能力(D10 + 计划扩展,F-AI):`sandbox@
|
|
40
|
+
* 敏感的能力(D10 + 计划扩展,F-AI):`sandbox@2` 在部署里执行任意命令、`object-store@1` 保管全部附件与插件包(D10);
|
|
40
41
|
* `channel@1` 收到组织在 IM 里的对话内容(Ruling A33)、`directory@1` 能把人加进组织(并为其建账号、建身份)、
|
|
41
42
|
* `identity-source@1` 决定谁能登录成哪个账号。插件提供其中任何一个时,「提供」一组标为敏感,
|
|
42
|
-
* 后台插件列表的 `sensitive`
|
|
43
|
+
* 后台插件列表的 `sensitive` 为真,须超级管理员批准。只影响展示,不改权限快照的键。
|
|
43
44
|
*/
|
|
44
45
|
export declare const SENSITIVE_EXTENSION_POINTS: readonly string[];
|
|
45
46
|
/**
|
|
@@ -59,7 +60,7 @@ export type DeploymentExtensionStatus = "enabled" | "disabled" | "pending_approv
|
|
|
59
60
|
/** The stored package is in the pre-0.1.0 format: reinstall it from a repacked tgz. */
|
|
60
61
|
| "legacy_format";
|
|
61
62
|
/**
|
|
62
|
-
*
|
|
63
|
+
* 需要超级管理员处理的状态(后台概览「需要处理的插件」):待批准、待配置、失败、依赖缺失,以及副本不一致
|
|
63
64
|
* (`converging` 收敛中、`pending_migration` 待迁移)。
|
|
64
65
|
*/
|
|
65
66
|
export declare function extensionNeedsAction(status: DeploymentExtensionStatus): boolean;
|
|
@@ -114,13 +115,24 @@ export interface AdminExtensionView {
|
|
|
114
115
|
/** 有部署级配置字段。 */
|
|
115
116
|
configurable: boolean;
|
|
116
117
|
configValid: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Only when the platform config leaves required overridable fields empty (spec A §5.4a; the
|
|
120
|
+
* extension still runs): the number of orgs where it is on and that still need their own config.
|
|
121
|
+
*/
|
|
122
|
+
orgsNeedingConfig?: number;
|
|
117
123
|
/** 能从部署卸载(只有安装记录,必需的引导插件除外;卸载前须先停用)。 */
|
|
118
124
|
removable: boolean;
|
|
119
125
|
/**
|
|
120
126
|
* A required bootstrap plugin (package ecosystem spec §7): enabled in every org, cannot be
|
|
121
|
-
* disabled or uninstalled;
|
|
127
|
+
* disabled or uninstalled; a super admin may upgrade it.
|
|
122
128
|
*/
|
|
123
129
|
required: boolean;
|
|
130
|
+
/** The scope of the catalog plugin the extension ships in (builtin: `all`); null without one. */
|
|
131
|
+
scope: PluginScope | null;
|
|
132
|
+
/** Orgs where the extension is enabled (a required plugin: every org). */
|
|
133
|
+
enabledOrgs: number;
|
|
134
|
+
/** Shipped with the deployment (a builtin plugin or a required bootstrap plugin). */
|
|
135
|
+
builtin: boolean;
|
|
124
136
|
/** Where the install record came from (`bootstrap` for the bootstrap step); null for config-declared. */
|
|
125
137
|
installSource: "npm" | "file" | "catalog" | "bootstrap" | null;
|
|
126
138
|
/**
|
|
@@ -18,16 +18,16 @@ export function reviewHash(set, warnings = []) {
|
|
|
18
18
|
return h.digest("hex").slice(0, 16);
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* 敏感的能力(D10 + 计划扩展,F-AI):`sandbox@
|
|
21
|
+
* 敏感的能力(D10 + 计划扩展,F-AI):`sandbox@2` 在部署里执行任意命令、`object-store@1` 保管全部附件与插件包(D10);
|
|
22
22
|
* `channel@1` 收到组织在 IM 里的对话内容(Ruling A33)、`directory@1` 能把人加进组织(并为其建账号、建身份)、
|
|
23
23
|
* `identity-source@1` 决定谁能登录成哪个账号。插件提供其中任何一个时,「提供」一组标为敏感,
|
|
24
|
-
* 后台插件列表的 `sensitive`
|
|
24
|
+
* 后台插件列表的 `sensitive` 为真,须超级管理员批准。只影响展示,不改权限快照的键。
|
|
25
25
|
*/
|
|
26
26
|
export const SENSITIVE_EXTENSION_POINTS = [
|
|
27
27
|
"channel@1",
|
|
28
28
|
"directory@1",
|
|
29
29
|
"identity-source@1",
|
|
30
|
-
"sandbox@
|
|
30
|
+
"sandbox@2",
|
|
31
31
|
"object-store@1",
|
|
32
32
|
];
|
|
33
33
|
/** 总是敏感的类别。 */
|
|
@@ -159,7 +159,7 @@ export function permissionGroups(set) {
|
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
161
|
/**
|
|
162
|
-
*
|
|
162
|
+
* 需要超级管理员处理的状态(后台概览「需要处理的插件」):待批准、待配置、失败、依赖缺失,以及副本不一致
|
|
163
163
|
* (`converging` 收敛中、`pending_migration` 待迁移)。
|
|
164
164
|
*/
|
|
165
165
|
export function extensionNeedsAction(status) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { PluginScope } from "../catalog/scope.js";
|
|
2
|
+
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
3
|
+
/** The catalog item (the plugin) an extension ships in. */
|
|
4
|
+
export interface ExtensionPluginItem {
|
|
5
|
+
id: string;
|
|
6
|
+
scope: PluginScope;
|
|
7
|
+
builtin: boolean;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The live catalog items of each extension in `names`, the one recorded on its install
|
|
12
|
+
* (`extension_installs.catalog_item_id`) first, then its other `extension_catalog_sources` by id.
|
|
13
|
+
* An extension without a live item (declared in the startup config, or its items deleted) is absent.
|
|
14
|
+
* `db` may be a transaction.
|
|
15
|
+
*/
|
|
16
|
+
export declare function pluginItemsOf(db: KernelSchemaDb, names: readonly string[]): Promise<Map<string, ExtensionPluginItem[]>>;
|
|
17
|
+
/**
|
|
18
|
+
* Whether an item keeps its plugin on in every org (builtin only: an org may switch off an `all`
|
|
19
|
+
* one, layering spec §4): its switch cannot go off.
|
|
20
|
+
*/
|
|
21
|
+
export declare const itemLocked: (i: ExtensionPluginItem) => boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live catalog items of each extension in `names`, the one recorded on its install
|
|
3
|
+
* (`extension_installs.catalog_item_id`) first, then its other `extension_catalog_sources` by id.
|
|
4
|
+
* An extension without a live item (declared in the startup config, or its items deleted) is absent.
|
|
5
|
+
* `db` may be a transaction.
|
|
6
|
+
*/
|
|
7
|
+
export async function pluginItemsOf(db, names) {
|
|
8
|
+
const out = new Map();
|
|
9
|
+
if (names.length === 0)
|
|
10
|
+
return out;
|
|
11
|
+
const add = (plugin, item) => {
|
|
12
|
+
const list = out.get(plugin) ?? [];
|
|
13
|
+
if (!list.some((i) => i.id === item.id))
|
|
14
|
+
list.push(item);
|
|
15
|
+
out.set(plugin, list);
|
|
16
|
+
};
|
|
17
|
+
const own = await db
|
|
18
|
+
.selectFrom("extension_installs as e")
|
|
19
|
+
.innerJoin("catalog_items as i", "i.id", "e.catalog_item_id")
|
|
20
|
+
.select(["e.name as plugin", "i.id", "i.scope", "i.builtin", "i.disabled"])
|
|
21
|
+
.where("e.name", "in", [...names])
|
|
22
|
+
.where("i.deleted_at", "is", null)
|
|
23
|
+
.execute();
|
|
24
|
+
for (const r of own)
|
|
25
|
+
add(r.plugin, r);
|
|
26
|
+
const sources = await db
|
|
27
|
+
.selectFrom("extension_catalog_sources as s")
|
|
28
|
+
.innerJoin("catalog_items as i", "i.id", "s.item_id")
|
|
29
|
+
.select(["s.plugin", "i.id", "i.scope", "i.builtin", "i.disabled"])
|
|
30
|
+
.where("s.plugin", "in", [...names])
|
|
31
|
+
.where("i.deleted_at", "is", null)
|
|
32
|
+
.orderBy("i.id")
|
|
33
|
+
.execute();
|
|
34
|
+
for (const r of sources)
|
|
35
|
+
add(r.plugin, r);
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Whether an item keeps its plugin on in every org (builtin only: an org may switch off an `all`
|
|
40
|
+
* one, layering spec §4): its switch cannot go off.
|
|
41
|
+
*/
|
|
42
|
+
export const itemLocked = (i) => i.builtin;
|