@capybara-hq/kernel 0.1.0-rc.4 → 0.1.0-rc.5
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 +39 -13
- package/dist/admin/admin.controller.js +33 -17
- 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 +51 -22
- package/dist/agents/agents.service.js +172 -70
- 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/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/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 +6 -2
- package/dist/config/schema.js +46 -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 +69 -12
- package/dist/conversations/conversations.service.js +106 -27
- 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 +5 -0
- package/dist/ctx/create-ctx.js +15 -5
- package/dist/db/kernel-schema.d.ts +362 -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 +82 -2
- package/dist/errors.js +82 -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 +16 -4
- package/dist/evals/step-replay.d.ts +2 -5
- package/dist/evals/step-replay.js +1 -1
- 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/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 +8 -2
- package/dist/extensions/hooks.d.ts +37 -4
- package/dist/extensions/hooks.js +82 -16
- package/dist/extensions/host.d.ts +19 -1
- package/dist/extensions/host.js +30 -7
- 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/files/previewers.d.ts +8 -1
- package/dist/files/previewers.js +35 -6
- package/dist/http/api.module.js +23 -3
- package/dist/http/app.d.ts +11 -2
- package/dist/http/app.js +31 -5
- 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 +21 -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 +11 -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/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 +20 -9
- package/dist/models/purposes.js +17 -8
- 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 +1387 -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.js +2 -0
- 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 +30 -8
- package/dist/runtime/model-call.js +69 -19
- 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 +11 -5
- package/dist/runtime/run-worker.js +54 -31
- 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 +43 -29
- 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.js +17 -12
- 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 +187 -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/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,151 @@
|
|
|
1
|
+
import { type Keyring } from "../ctx/secrets.js";
|
|
2
|
+
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
3
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
4
|
+
import type { KernelLogger } from "../log.js";
|
|
5
|
+
import { OrgLock } from "../orgs/org-lock.js";
|
|
6
|
+
import { type ConfigIssue } from "./config-issues.js";
|
|
7
|
+
import { type JsonSchema } from "./config-json-schema.js";
|
|
8
|
+
import { type SecretEntry } from "./deployment-config.js";
|
|
9
|
+
import { EffectiveConfigs } from "./effective-config.js";
|
|
10
|
+
import { ExtensionHost } from "./host.js";
|
|
11
|
+
import { type FieldLevel } from "./org-levels.js";
|
|
12
|
+
/** One field of {@link OrgOverrideView}: a read-only or overridable deployment field. */
|
|
13
|
+
export interface OrgOverrideField {
|
|
14
|
+
path: string;
|
|
15
|
+
level: "readonly" | "override";
|
|
16
|
+
secret: boolean;
|
|
17
|
+
/** The platform's current value (non-secret) or only whether it is set (secret). */
|
|
18
|
+
platform: {
|
|
19
|
+
value?: unknown;
|
|
20
|
+
set?: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** With a copy, on an overridable field: the copy's value, or whether its secret is set. */
|
|
23
|
+
org?: {
|
|
24
|
+
value?: unknown;
|
|
25
|
+
set?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** With a copy, on an overridable non-secret field: the copy's value differs from the platform's. */
|
|
28
|
+
differs?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* What an org admin sees of an extension's two-level config (spec A §5.3 to §5.6): whether the org
|
|
32
|
+
* follows the platform or keeps a copy, the read-only and overridable fields (hidden fields never
|
|
33
|
+
* appear), and whether the effective config is valid. Secrets give `set` only, never a value, and
|
|
34
|
+
* are never compared.
|
|
35
|
+
*/
|
|
36
|
+
export interface OrgOverrideView {
|
|
37
|
+
state: "following" | "copy";
|
|
38
|
+
/**
|
|
39
|
+
* The deployment form JSON Schema restricted to the read-only and overridable top-level
|
|
40
|
+
* properties (as the platform form gets it, with `x-ui`, `x-secret`, `x-org`); hidden properties,
|
|
41
|
+
* their `required` entries and hints naming them are removed. Null when the extension has no
|
|
42
|
+
* deployment schema or it cannot be converted.
|
|
43
|
+
*/
|
|
44
|
+
schema: JsonSchema | null;
|
|
45
|
+
createdAt?: string;
|
|
46
|
+
fields: OrgOverrideField[];
|
|
47
|
+
valid: boolean;
|
|
48
|
+
issues: ConfigIssue[];
|
|
49
|
+
}
|
|
50
|
+
/** One org copy in the admin's extension detail (spec A §5.7). */
|
|
51
|
+
export interface OrgOverrideSummary {
|
|
52
|
+
orgId: string;
|
|
53
|
+
orgName: string;
|
|
54
|
+
createdAt: string;
|
|
55
|
+
/** The overridable non-secret fields whose copy value differs from the platform's. */
|
|
56
|
+
differing: string[];
|
|
57
|
+
secrets: {
|
|
58
|
+
path: string;
|
|
59
|
+
set: boolean;
|
|
60
|
+
}[];
|
|
61
|
+
}
|
|
62
|
+
interface Actor {
|
|
63
|
+
accountId: string;
|
|
64
|
+
tokenId?: string | undefined;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Org copies of an extension's overridable deployment config (spec A §5.4, §5.5, §5.8): one row of
|
|
68
|
+
* `extension_org_overrides` per copy (its non-secret values), each secret in `capybara.secrets`
|
|
69
|
+
* under the org (namespace `kernel`, key `plugin-override:<plugin>:<path>`), written in the same
|
|
70
|
+
* transaction under the org row lock. Writes are org-audited and evict the cached copy after the
|
|
71
|
+
* commit. Platform secrets never enter a copy.
|
|
72
|
+
*/
|
|
73
|
+
export declare class OrgOverrides {
|
|
74
|
+
private readonly kdb;
|
|
75
|
+
readonly txHost: TransactionHost;
|
|
76
|
+
private readonly keyring;
|
|
77
|
+
private readonly host;
|
|
78
|
+
/** The org row lock: re-checks `org.extensions.manage` under the lock. */
|
|
79
|
+
private readonly orgLock;
|
|
80
|
+
private readonly effective;
|
|
81
|
+
private readonly log;
|
|
82
|
+
constructor(kdb: KernelDb, txHost: TransactionHost, keyring: Keyring, host: ExtensionHost,
|
|
83
|
+
/** The org row lock: re-checks `org.extensions.manage` under the lock. */
|
|
84
|
+
orgLock: OrgLock, effective: EffectiveConfigs, log: KernelLogger);
|
|
85
|
+
private get db();
|
|
86
|
+
private running;
|
|
87
|
+
/**
|
|
88
|
+
* The running extension, for an org: one the org does not see under plugin scope (a `named`
|
|
89
|
+
* plugin without it) is answered like an unknown one, so its platform values never reach it.
|
|
90
|
+
*/
|
|
91
|
+
private runningFor;
|
|
92
|
+
/** The org's view (read-only and overridable fields, the copy state and validity). */
|
|
93
|
+
view(orgId: string, plugin: string): Promise<OrgOverrideView>;
|
|
94
|
+
/**
|
|
95
|
+
* Saves overridable fields (`values` keyed by field dot path: `null` clears, omitted keeps;
|
|
96
|
+
* secret fields too, as in the platform form) and secret record entries. The first save creates
|
|
97
|
+
* the copy from the platform's non-secret overridable values plus `values` (secret fields start
|
|
98
|
+
* empty). A path that is not an overridable field of the schema (read-only, hidden, unknown) ->
|
|
99
|
+
* 400 `extension.field_not_overridable`; an invalid result (an empty required secret included)
|
|
100
|
+
* -> 400 `extension.config_invalid`, nothing written. Audits `extension.org_override_saved`.
|
|
101
|
+
*/
|
|
102
|
+
save(orgId: string, plugin: string, values: Record<string, unknown>, secretEntries: readonly SecretEntry[], actor: Actor): Promise<OrgOverrideView>;
|
|
103
|
+
private writeSave;
|
|
104
|
+
/**
|
|
105
|
+
* Takes the platform's current values of non-secret overridable fields into the copy (spec A
|
|
106
|
+
* §5.5); the copy stays a copy. A secret, read-only, hidden or unknown path -> 400
|
|
107
|
+
* `extension.field_not_overridable`; no copy -> 404 `extension.no_org_override`. Audits
|
|
108
|
+
* `extension.org_override_taken`.
|
|
109
|
+
*/
|
|
110
|
+
take(orgId: string, plugin: string, paths: string[], actor: Actor): Promise<OrgOverrideView>;
|
|
111
|
+
private writeTake;
|
|
112
|
+
/**
|
|
113
|
+
* Drops the copy and every secret of it in one transaction; the org follows the platform again
|
|
114
|
+
* (spec A §5.5). No copy -> 404 `extension.no_org_override`. Audits `extension.org_override_reset`.
|
|
115
|
+
*/
|
|
116
|
+
reset(orgId: string, plugin: string, actor: Actor): Promise<OrgOverrideView>;
|
|
117
|
+
private writeReset;
|
|
118
|
+
/**
|
|
119
|
+
* The orgs (not deleted) holding a copy of the extension, oldest first, with the overridable
|
|
120
|
+
* non-secret fields that differ from the platform and whether each copy secret is set (spec A
|
|
121
|
+
* §5.7); never a secret value. Differences need the running schema: an extension not running on
|
|
122
|
+
* this replica lists no differences and only the secrets the copies hold.
|
|
123
|
+
*/
|
|
124
|
+
listForPlugin(plugin: string): Promise<OrgOverrideSummary[]>;
|
|
125
|
+
/** The merged copy validated with the full schema; invalid -> 400 `extension.config_invalid`. */
|
|
126
|
+
private validated;
|
|
127
|
+
private messagesOf;
|
|
128
|
+
/** The deployment form JSON Schema (hints dropped when invalid; one warning). Never throws. */
|
|
129
|
+
private formSchemaOf;
|
|
130
|
+
private lockedRow;
|
|
131
|
+
/** The keys of the org's copy secrets for `plugin` (any path, current or stale). */
|
|
132
|
+
private secretKeys;
|
|
133
|
+
private readSecrets;
|
|
134
|
+
/** Writes the copy's secrets of the current schema and drops stale keys (paths no longer secret). */
|
|
135
|
+
private writeSecrets;
|
|
136
|
+
private render;
|
|
137
|
+
private secretPathsHeld;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The form JSON Schema an org may see (spec A §5.6, "hidden fields are not sent to the org at
|
|
141
|
+
* all"): a copy with only the read-only and overridable top-level properties, `required` limited
|
|
142
|
+
* to them, and root `x-ui` hints naming a hidden field dropped (`secrets[]` by path; `order` lists
|
|
143
|
+
* none). Values are never in it: `configJsonSchema` already strips secret defaults and examples.
|
|
144
|
+
*/
|
|
145
|
+
export declare function orgFormSchema(js: JsonSchema, levels: Map<string, FieldLevel>): JsonSchema;
|
|
146
|
+
/**
|
|
147
|
+
* Issues as an org may see them: an issue on a hidden field would name a field the org never
|
|
148
|
+
* sees, so those collapse into one root issue.
|
|
149
|
+
*/
|
|
150
|
+
export declare function orgIssues(issues: ConfigIssue[], levels: Map<string, FieldLevel>): ConfigIssue[];
|
|
151
|
+
export {};
|
|
@@ -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
|
+
}
|