@capybara-hq/kernel 0.1.0-rc.23 → 0.1.0-rc.25
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 +25 -25
- package/dist/admin/admin.module.d.ts +2 -1
- package/dist/admin/admin.module.js +9 -3
- package/dist/admin/health.service.d.ts +2 -2
- package/dist/admin/health.service.js +6 -2
- package/dist/admin/outbox-dead.controller.d.ts +23 -0
- package/dist/admin/outbox-dead.controller.js +62 -0
- package/dist/admin/outbox-dead.schemas.d.ts +8 -0
- package/dist/admin/outbox-dead.schemas.js +18 -0
- package/dist/admin/outbox-dead.service.d.ts +66 -0
- package/dist/admin/outbox-dead.service.js +179 -0
- package/dist/admin/overview.service.d.ts +40 -5
- package/dist/admin/overview.service.js +41 -7
- package/dist/agents/agents.module.js +3 -0
- package/dist/agents/agents.service.d.ts +6 -1
- package/dist/agents/agents.service.js +11 -2
- package/dist/agents/from-template.js +1 -1
- package/dist/background/finish.d.ts +5 -2
- package/dist/background/finish.js +14 -3
- package/dist/background/launch.d.ts +2 -1
- package/dist/background/launch.js +5 -2
- package/dist/background/store.d.ts +8 -0
- package/dist/background/store.js +24 -0
- package/dist/catalog/admin-catalog.controller.d.ts +21 -2
- package/dist/catalog/admin-catalog.controller.js +45 -6
- package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
- package/dist/catalog/admin-catalog.schemas.js +8 -0
- package/dist/catalog/catalog-import.module.js +0 -4
- package/dist/catalog/catalog-scope.service.d.ts +63 -26
- package/dist/catalog/catalog-scope.service.js +146 -71
- package/dist/catalog/catalog.module.d.ts +2 -1
- package/dist/catalog/catalog.module.js +9 -4
- package/dist/catalog/catalog.service.d.ts +11 -4
- package/dist/catalog/catalog.service.js +21 -5
- package/dist/catalog/cli.d.ts +4 -3
- package/dist/catalog/cli.js +8 -13
- package/dist/catalog/job-ids.d.ts +8 -20
- package/dist/catalog/job-ids.js +11 -16
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/org-plugin-uploads.d.ts +11 -4
- package/dist/catalog/org-plugin-uploads.js +21 -6
- package/dist/catalog/owned-items.d.ts +6 -13
- package/dist/catalog/owned-items.js +11 -29
- package/dist/catalog/owned-plugin-cleanup.d.ts +8 -17
- package/dist/catalog/owned-plugin-cleanup.js +12 -66
- package/dist/catalog/platform-components.d.ts +56 -34
- package/dist/catalog/platform-components.js +68 -78
- package/dist/catalog/platform-import-update.d.ts +50 -0
- package/dist/catalog/platform-import-update.js +116 -0
- package/dist/catalog/plugin-import.d.ts +64 -26
- package/dist/catalog/plugin-import.js +113 -77
- package/dist/catalog/plugin-upgrade.d.ts +22 -4
- package/dist/catalog/plugin-upgrade.js +26 -19
- package/dist/catalog/scope-jobs.d.ts +59 -0
- package/dist/catalog/scope-jobs.js +65 -0
- package/dist/catalog/scope-sync-workers.d.ts +22 -0
- package/dist/catalog/scope-sync-workers.js +58 -2
- package/dist/catalog/scope-sync.d.ts +40 -65
- package/dist/catalog/scope-sync.js +114 -122
- package/dist/channels/channels.module.d.ts +5 -2
- package/dist/channels/channels.module.js +9 -2
- package/dist/channels/deliver-job.d.ts +25 -0
- package/dist/channels/deliver-job.js +25 -0
- package/dist/channels/inbound.d.ts +1 -1
- package/dist/channels/inbound.js +4 -17
- package/dist/channels/jobs.d.ts +28 -18
- package/dist/channels/jobs.js +63 -26
- package/dist/channels/threads.d.ts +4 -3
- package/dist/channels/threads.js +4 -3
- package/dist/config/schema.d.ts +0 -3
- package/dist/config/schema.js +11 -20
- package/dist/conversations/agent-tree.d.ts +16 -0
- package/dist/conversations/agent-tree.js +36 -0
- package/dist/conversations/conversations.controller.js +4 -2
- package/dist/conversations/conversations.service.d.ts +61 -19
- package/dist/conversations/conversations.service.js +69 -43
- package/dist/conversations/event-log.d.ts +7 -10
- package/dist/conversations/event-log.js +24 -15
- package/dist/conversations/events.d.ts +21 -0
- package/dist/conversations/events.js +26 -2
- package/dist/conversations/queue.service.d.ts +8 -3
- package/dist/conversations/queue.service.js +37 -13
- package/dist/conversations/source.d.ts +10 -0
- package/dist/conversations/source.js +17 -0
- package/dist/conversations/titles.d.ts +21 -8
- package/dist/conversations/titles.js +42 -15
- package/dist/conversations/tree.d.ts +10 -0
- package/dist/conversations/tree.js +35 -0
- package/dist/db/kernel-schema.d.ts +35 -22
- package/dist/devices/devices.service.d.ts +23 -11
- package/dist/devices/devices.service.js +34 -26
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +11 -0
- package/dist/evals/run-replay.d.ts +13 -2
- package/dist/evals/run-replay.js +42 -9
- package/dist/evals/snapshot.d.ts +7 -1
- package/dist/evals/snapshot.js +2 -1
- package/dist/extensions/extensions.module.js +3 -0
- package/dist/extensions/hooks.d.ts +22 -3
- package/dist/extensions/hooks.js +15 -1
- package/dist/extensions/lifecycle-hooks.d.ts +99 -0
- package/dist/extensions/lifecycle-hooks.js +273 -0
- package/dist/extensions/lifecycle.d.ts +6 -1
- package/dist/extensions/lifecycle.js +9 -2
- package/dist/extensions/org-config.d.ts +13 -1
- package/dist/extensions/org-config.js +19 -2
- package/dist/extensions/permission-view.d.ts +9 -5
- package/dist/extensions/permission-view.js +9 -4
- package/dist/extensions/point-defaults.d.ts +28 -1
- package/dist/extensions/point-defaults.js +44 -13
- package/dist/extensions/usage-subscribers.d.ts +43 -0
- package/dist/extensions/usage-subscribers.js +108 -0
- package/dist/http/api.module.js +2 -0
- package/dist/inbox/inbox.service.d.ts +6 -20
- package/dist/inbox/inbox.service.js +0 -3
- package/dist/inbox/org-notices.d.ts +1 -1
- package/dist/inbox/platform-inbox.service.d.ts +3 -32
- package/dist/inbox/platform-inbox.service.js +5 -54
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/infra/cli/kernel-cli.module.js +5 -0
- package/dist/infra/events/kernel-events.d.ts +9 -35
- package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
- package/dist/infra/outbox/outbox-relay.module.js +18 -0
- package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
- package/dist/infra/outbox/outbox.dispatcher.js +310 -0
- package/dist/infra/outbox/outbox.module.d.ts +24 -0
- package/dist/infra/outbox/outbox.module.js +50 -0
- package/dist/infra/outbox/outbox.relay.d.ts +31 -0
- package/dist/infra/outbox/outbox.relay.js +76 -0
- package/dist/infra/outbox/outbox.service.d.ts +51 -0
- package/dist/infra/outbox/outbox.service.js +131 -0
- package/dist/infra/outbox/registry.d.ts +244 -0
- package/dist/infra/outbox/registry.js +234 -0
- package/dist/infra/queue/queue-names.d.ts +8 -0
- package/dist/infra/queue/queue-names.js +17 -0
- package/dist/kernel.module.js +3 -0
- package/dist/local-devices/device-policy.service.d.ts +4 -0
- package/dist/local-devices/device-policy.service.js +61 -3
- package/dist/local-devices/machines.d.ts +13 -5
- package/dist/local-devices/machines.js +45 -7
- package/dist/local-devices/policy-summary.d.ts +44 -1
- package/dist/local-devices/policy-summary.js +69 -0
- package/dist/models/embeddings.d.ts +9 -9
- package/dist/models/embeddings.js +11 -18
- package/dist/models/models.module.js +3 -0
- package/dist/orgs/directory-sync.js +1 -1
- package/dist/orgs/members.service.js +1 -1
- package/dist/orgs/offboarding.d.ts +50 -57
- package/dist/orgs/offboarding.js +117 -162
- package/dist/orgs/orgs.module.js +3 -0
- package/dist/orgs/orgs.service.d.ts +11 -5
- package/dist/orgs/orgs.service.js +22 -6
- package/dist/overrides.d.ts +23 -3
- package/dist/overrides.js +12 -2
- package/dist/platform/exclusions.js +5 -0
- package/dist/platform/ops/admin.ops.js +18 -2
- package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
- package/dist/platform/ops/catalog-admin.ops.js +32 -4
- package/dist/platform/ops/inbox.ops.js +4 -20
- package/dist/platform/ops/outbox.ops.d.ts +21 -0
- package/dist/platform/ops/outbox.ops.js +125 -0
- package/dist/platform/ops/platform.ops.d.ts +1 -0
- package/dist/platform/ops/platform.ops.js +6 -3
- package/dist/platform/ops/schedules.ops.js +40 -1
- package/dist/platform/platform-ops.module.d.ts +2 -1
- package/dist/platform/platform-ops.module.js +3 -0
- package/dist/platform/route-schemas.js +3 -0
- package/dist/roles/worker-role.d.ts +10 -5
- package/dist/roles/worker-role.js +19 -9
- package/dist/roles/worker.module.js +11 -8
- package/dist/runtime/context/build.d.ts +3 -0
- package/dist/runtime/context/build.js +15 -0
- package/dist/runtime/context/plugin-context.d.ts +20 -0
- package/dist/runtime/context/plugin-context.js +30 -0
- package/dist/runtime/langgraph-loop.js +17 -5
- package/dist/runtime/limits.d.ts +15 -0
- package/dist/runtime/limits.js +25 -0
- package/dist/runtime/loop.d.ts +16 -3
- package/dist/runtime/loop.js +2 -1
- package/dist/runtime/maintenance.d.ts +7 -3
- package/dist/runtime/maintenance.js +52 -12
- package/dist/runtime/model-call.d.ts +20 -17
- package/dist/runtime/model-call.js +15 -24
- package/dist/runtime/plugin-context.service.d.ts +69 -0
- package/dist/runtime/plugin-context.service.js +208 -0
- package/dist/runtime/queue-lost-jobs.d.ts +24 -0
- package/dist/runtime/queue-lost-jobs.js +51 -0
- package/dist/runtime/run-control.d.ts +47 -5
- package/dist/runtime/run-control.js +79 -12
- package/dist/runtime/run-finish.d.ts +39 -12
- package/dist/runtime/run-finish.js +97 -14
- package/dist/runtime/run-jobs.d.ts +95 -13
- package/dist/runtime/run-jobs.js +199 -28
- package/dist/runtime/run-orphan-check.job.d.ts +142 -0
- package/dist/runtime/run-orphan-check.job.js +339 -0
- package/dist/runtime/run-processors.d.ts +16 -9
- package/dist/runtime/run-processors.js +1 -1
- package/dist/runtime/run-queue.d.ts +75 -53
- package/dist/runtime/run-queue.js +189 -263
- package/dist/runtime/run-steps.d.ts +1 -2
- package/dist/runtime/run-steps.js +8 -11
- package/dist/runtime/run-worker.d.ts +26 -16
- package/dist/runtime/run-worker.js +132 -37
- package/dist/runtime/runtime.module.d.ts +2 -3
- package/dist/runtime/runtime.module.js +7 -6
- package/dist/runtime/step-log.d.ts +16 -4
- package/dist/runtime/step-log.js +26 -6
- package/dist/runtime/stream.controller.d.ts +2 -4
- package/dist/runtime/stream.controller.js +5 -11
- package/dist/runtime/subagents/child.js +1 -1
- package/dist/runtime/subagents/definition.d.ts +2 -1
- package/dist/runtime/subagents/definition.js +4 -2
- package/dist/runtime/subagents/deliveries.d.ts +6 -3
- package/dist/runtime/subagents/deliveries.js +16 -7
- package/dist/runtime/subagents/dispatch.d.ts +12 -12
- package/dist/runtime/subagents/dispatch.js +14 -38
- package/dist/runtime/subagents/messages.d.ts +5 -1
- package/dist/runtime/subagents/messages.js +11 -3
- package/dist/runtime/subagents/skill-fork.d.ts +3 -3
- package/dist/runtime/subagents/skill-fork.js +8 -5
- package/dist/runtime/subagents/subagents.service.js +1 -1
- package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
- package/dist/runtime/subagents/tree-jobs.js +86 -0
- package/dist/runtime/usage-report-jobs.d.ts +23 -48
- package/dist/runtime/usage-report-jobs.js +67 -119
- package/dist/runtime/usage-report.d.ts +28 -77
- package/dist/runtime/usage-report.js +35 -213
- package/dist/runtime/waits.d.ts +48 -198
- package/dist/runtime/waits.js +103 -805
- package/dist/sandbox/jobs.d.ts +20 -10
- package/dist/sandbox/jobs.js +23 -17
- package/dist/sandbox/sandbox.service.d.ts +17 -4
- package/dist/sandbox/sandbox.service.js +55 -14
- package/dist/schedules/calendar.d.ts +134 -0
- package/dist/schedules/calendar.js +410 -0
- package/dist/schedules/fire.d.ts +26 -7
- package/dist/schedules/fire.js +91 -22
- package/dist/schedules/job-ids.d.ts +66 -17
- package/dist/schedules/job-ids.js +81 -13
- package/dist/schedules/run-tracker.d.ts +0 -5
- package/dist/schedules/run-tracker.js +2 -14
- package/dist/schedules/scan.job.d.ts +13 -32
- package/dist/schedules/scan.job.js +50 -164
- package/dist/schedules/schedule-math.d.ts +42 -0
- package/dist/schedules/schedule-math.js +52 -0
- package/dist/schedules/scheduled-tasks.service.d.ts +22 -6
- package/dist/schedules/scheduled-tasks.service.js +70 -14
- package/dist/schedules/schedules.controller.d.ts +5 -1
- package/dist/schedules/schedules.controller.js +15 -1
- package/dist/schedules/schedules.module.js +0 -4
- package/dist/schedules/schedules.schemas.d.ts +35 -0
- package/dist/schedules/schedules.schemas.js +27 -0
- package/dist/schedules/store.d.ts +5 -0
- package/dist/schedules/store.js +20 -0
- package/dist/skills/changes.controller.d.ts +1 -1
- package/dist/skills/changes.controller.js +1 -1
- package/dist/tools/approvals.service.d.ts +41 -11
- package/dist/tools/approvals.service.js +108 -14
- package/dist/tools/builtin-names.d.ts +5 -3
- package/dist/tools/builtin-names.js +12 -4
- package/dist/tools/builtins/builtin-tools.d.ts +1 -2
- package/dist/tools/builtins/builtin-tools.js +21 -17
- package/dist/tools/builtins/sandbox/bash.js +9 -3
- package/dist/tools/builtins/sandbox/common.d.ts +18 -1
- package/dist/tools/builtins/sandbox/common.js +14 -1
- package/dist/tools/builtins/sandbox/index.d.ts +2 -1
- package/dist/tools/builtins/sandbox/index.js +4 -1
- package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
- package/dist/tools/builtins/sandbox/task-list.js +130 -0
- package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
- package/dist/tools/builtins/sandbox/task-output.js +21 -3
- package/dist/tools/builtins/web/extract.d.ts +2 -4
- package/dist/tools/builtins/web/extract.js +2 -5
- package/dist/tools/pipeline.d.ts +12 -3
- package/dist/tools/pipeline.js +6 -1
- package/dist/tools/questions.service.d.ts +30 -10
- package/dist/tools/questions.service.js +41 -27
- package/dist/tools/registry.d.ts +12 -3
- package/dist/tools/registry.js +13 -3
- package/dist/tools/tools.module.js +4 -3
- package/package.json +3 -3
- package/src/migrations/0118_device_policy_ops.sql +6 -0
- package/src/migrations/0119_outbox.sql +22 -0
- package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
- package/src/migrations/0121_drop_platform_migration_runs.sql +12 -0
- package/src/migrations/0122_drop_scheduled_task_runs_rechecked_at.sql +5 -0
- package/src/migrations/0123_pgvector.sql +27 -0
- package/src/migrations/0124_conversation_source.sql +36 -0
- package/dist/catalog/platform-migration.d.ts +0 -115
- package/dist/catalog/platform-migration.js +0 -583
- package/dist/infra/queue/add-job-once.d.ts +0 -14
- package/dist/infra/queue/add-job-once.js +0 -16
|
@@ -0,0 +1,116 @@
|
|
|
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 { Inject, Injectable } from "@nestjs/common";
|
|
11
|
+
import { ApiError } from "../errors.js";
|
|
12
|
+
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
13
|
+
import { PluginImport } from "./plugin-import.js";
|
|
14
|
+
import { PlatformPluginUpdater, } from "./plugin-upgrade.js";
|
|
15
|
+
const notInstalled = (name) => new ApiError("plugin.upgrade_target_invalid", `Plugin ${name} is not a platform plugin of this deployment yet; install it with the import review instead`, [{ reason: "not_installed" }]);
|
|
16
|
+
/**
|
|
17
|
+
* The platform's update of an installed plugin to a version staged for import (the one wizard of
|
|
18
|
+
* the admin plugin pages, maintainer decision 2026-11-13): the import review (prepared as any
|
|
19
|
+
* import, `PluginImport.prepare`) and the platform update preview of the staged version
|
|
20
|
+
* ({@link preview}: `PlatformPluginUpdater.previewStaged`, the target read from the staging) are
|
|
21
|
+
* confirmed together ({@link confirm} with the review's `reviewHash` and the preview's `diffHash`).
|
|
22
|
+
* Nothing is written before that confirm: cancelling the wizard leaves only the staging row, which
|
|
23
|
+
* expires like any staged import.
|
|
24
|
+
*
|
|
25
|
+
* The confirm holds the item's update lock (`PlatformPluginUpdater.withItemLock`, one per item
|
|
26
|
+
* across replicas: another update -> 409 `plugin.install_in_progress`), recomputes the preview
|
|
27
|
+
* (another `diffHash` -> 409 `plugin.upgrade_stale`, nothing written), commits the import without
|
|
28
|
+
* deploying its extension (the permission snapshot is written as the review approved it), then
|
|
29
|
+
* runs the platform update, which moves the extension with its own rollback and writes the
|
|
30
|
+
* components in one transaction. When that update fails, the platform stays on its version, the
|
|
31
|
+
* extension where it was and its previous approval is put back; the imported version stays in the
|
|
32
|
+
* catalog (its 版本 tab, and 更新到 retries the update with the plain update preview): 409
|
|
33
|
+
* `plugin.imported_not_updated` says so, with the cause in the details. No in-process state.
|
|
34
|
+
*/
|
|
35
|
+
let PlatformImportUpdate = class PlatformImportUpdate {
|
|
36
|
+
pluginImport;
|
|
37
|
+
updater;
|
|
38
|
+
log;
|
|
39
|
+
constructor(pluginImport, updater, log) {
|
|
40
|
+
this.pluginImport = pluginImport;
|
|
41
|
+
this.updater = updater;
|
|
42
|
+
this.log = log;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The platform update the staged version would apply (writes nothing). The staging must be a
|
|
46
|
+
* platform staging (else 404 `plugin.staging_not_found`) of a new version of a live
|
|
47
|
+
* platform-owned plugin (else 409 `plugin.upgrade_target_invalid`, reason `not_installed`); the
|
|
48
|
+
* updater's refusals apply as for any update preview. `needsApproval` is false: the confirm
|
|
49
|
+
* approves the permissions the review shows.
|
|
50
|
+
*/
|
|
51
|
+
async preview(stagingId) {
|
|
52
|
+
const st = await this.target(stagingId);
|
|
53
|
+
return this.previewOf(st);
|
|
54
|
+
}
|
|
55
|
+
/** Confirms the import and the update together (see the class comment). */
|
|
56
|
+
async confirm(actor, stagingId, input, opts = {}) {
|
|
57
|
+
const st = await this.target(stagingId);
|
|
58
|
+
return this.updater.withItemLock(st.itemId, async () => {
|
|
59
|
+
const preview = await this.previewOf(st);
|
|
60
|
+
if (preview.diffHash !== input.diffHash) {
|
|
61
|
+
throw new ApiError("plugin.upgrade_stale", `What updating plugin ${preview.name} to ${st.version} does changed since the preview; preview it again`);
|
|
62
|
+
}
|
|
63
|
+
// The review hash is checked by the import's confirm (409 plugin.review_stale, nothing
|
|
64
|
+
// written)
|
|
65
|
+
const imported = await this.pluginImport.confirm(actor, stagingId, { reviewHash: input.reviewHash, deploy: false }, opts);
|
|
66
|
+
try {
|
|
67
|
+
const update = await this.updater.updateHeld(actor, st.itemId, { version: st.version, diffHash: input.diffHash }, opts);
|
|
68
|
+
return { item: await this.pluginImport.view(st.itemId), update };
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
let restored = imported.approval === undefined;
|
|
72
|
+
if (imported.approval !== undefined) {
|
|
73
|
+
try {
|
|
74
|
+
restored = await this.pluginImport.restoreApproval(actor, imported.approval, opts);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
this.log.error("cannot restore an extension's approval after a failed update", {
|
|
78
|
+
itemId: st.itemId,
|
|
79
|
+
err,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const cause = e instanceof ApiError ? e : undefined;
|
|
84
|
+
throw new ApiError("plugin.imported_not_updated", `Version ${st.version} of plugin ${preview.name} was imported, but updating the platform to it failed (${cause?.code ?? "internal"}); the platform stays on ${preview.from ?? "(none)"}. Update to ${st.version} from the plugin's page to retry`, [
|
|
85
|
+
{
|
|
86
|
+
version: st.version,
|
|
87
|
+
from: preview.from,
|
|
88
|
+
code: cause?.code ?? "internal",
|
|
89
|
+
...(cause !== undefined && { message: cause.message }),
|
|
90
|
+
...(cause?.details !== undefined && { causeDetails: cause.details }),
|
|
91
|
+
approvalRestored: restored,
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** The staged target, which must be a new version of a live platform-owned plugin. */
|
|
98
|
+
async target(stagingId) {
|
|
99
|
+
const st = await this.pluginImport.stagedTarget(stagingId);
|
|
100
|
+
if (!st.existing) {
|
|
101
|
+
throw notInstalled((await this.pluginImport.staged(stagingId)).review.name);
|
|
102
|
+
}
|
|
103
|
+
return st;
|
|
104
|
+
}
|
|
105
|
+
async previewOf(st) {
|
|
106
|
+
const p = await this.updater.previewStaged(st.itemId, st.version, st.target);
|
|
107
|
+
return p.extension === null ? p : { ...p, extension: { ...p.extension, needsApproval: false } };
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
PlatformImportUpdate = __decorate([
|
|
111
|
+
Injectable(),
|
|
112
|
+
__param(0, Inject(PluginImport)),
|
|
113
|
+
__param(1, Inject(PlatformPluginUpdater)),
|
|
114
|
+
__param(2, Inject(KERNEL_LOGGER))
|
|
115
|
+
], PlatformImportUpdate);
|
|
116
|
+
export { PlatformImportUpdate };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type AgentTemplate, type AgentTemplateTier, type LocalizedName, type PluginManifest, type ThemeScheme } from "@capybara-hq/plugin-sdk";
|
|
2
|
-
import type { Queue } from "bullmq";
|
|
3
2
|
import { ClientBuilds } from "../client/client-builds.service.js";
|
|
4
3
|
import { ApiError } from "../errors.js";
|
|
5
4
|
import { ExtensionAdminOps } from "../extensions/admin-ops.js";
|
|
@@ -8,6 +7,7 @@ import { ExtensionBlobs } from "../extensions/blobs.js";
|
|
|
8
7
|
import { ExtensionInstalls } from "../extensions/installs.js";
|
|
9
8
|
import { PluginApproveLock, PluginInstallLock } from "../extensions/locks.js";
|
|
10
9
|
import { ExtensionPackageError } from "../extensions/package.js";
|
|
10
|
+
import { type PermissionSet } from "../extensions/permission-set.js";
|
|
11
11
|
import { type PackageWarning, type PermissionGroup, type PermissionItem } from "../extensions/permission-view.js";
|
|
12
12
|
import { ExtensionRegistry } from "../extensions/registry.js";
|
|
13
13
|
import type { SingleProviderBlock } from "../extensions/single-provider.js";
|
|
@@ -15,6 +15,7 @@ import { SuperAdminLock } from "../identity/super-admin.js";
|
|
|
15
15
|
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
16
16
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
17
17
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
18
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
18
19
|
import type { KernelLogger } from "../log.js";
|
|
19
20
|
import { OrgLock } from "../orgs/org-lock.js";
|
|
20
21
|
import type { ProvenanceResult } from "../packages/provenance.js";
|
|
@@ -26,8 +27,6 @@ import { CatalogItemLock } from "./locks.js";
|
|
|
26
27
|
import { PlatformComponents } from "./platform-components.js";
|
|
27
28
|
import { PluginPackageError } from "./plugin-package.js";
|
|
28
29
|
import type { PluginScope } from "./scope.js";
|
|
29
|
-
/** How long after a failed post-import platform sync the migration job runs for the item. */
|
|
30
|
-
export declare const PLATFORM_SYNC_RETRY_MS = 60000;
|
|
31
30
|
/**
|
|
32
31
|
* Platform import of a plugin (package ecosystem spec §4.3): one review for every plugin, whatever
|
|
33
32
|
* it contains (an extension, skills, connector templates, dependencies), confirmed once.
|
|
@@ -53,8 +52,10 @@ export declare const PLATFORM_SYNC_RETRY_MS = 60000;
|
|
|
53
52
|
* snapshot when it is installed or upgraded by this import (source web, audit
|
|
54
53
|
* `extension.permissions_approved` carrying the plugin), and creates the item (with the scope the
|
|
55
54
|
* admin chose, default `optional`) or adds the version (`manifest` = the normalized plugin.json,
|
|
56
|
-
* `extension_sha256`, the files under the staging prefix)
|
|
57
|
-
*
|
|
55
|
+
* `extension_sha256`, the files under the staging prefix); an item's first usable version also
|
|
56
|
+
* gets its platform component rows there (their files copied before, keyed by content: a failure
|
|
57
|
+
* leaves nothing a retry copies again; no job heals an item later). After the commit the plugin's
|
|
58
|
+
* own extension is installed on the deployment and enabled (`ExtensionAdminOps.install` + `enable`;
|
|
58
59
|
* each replica reconciles, no restart); a failure is returned, not thrown, and an upgrade that was
|
|
59
60
|
* not installed gets its old snapshot back.
|
|
60
61
|
*
|
|
@@ -317,6 +318,18 @@ export interface PluginConfirmResult {
|
|
|
317
318
|
* extension (applied at once, plan Task 6).
|
|
318
319
|
*/
|
|
319
320
|
firstVersion: boolean;
|
|
321
|
+
/**
|
|
322
|
+
* A confirm with `deploy: false` that approved the extension's permissions (its snapshot
|
|
323
|
+
* written): what {@link PluginImport.restoreApproval} needs to put the previous approval back
|
|
324
|
+
* when the step that was to deploy it fails. Never sent over HTTP (the route always deploys).
|
|
325
|
+
*/
|
|
326
|
+
approval?: HeldApproval;
|
|
327
|
+
}
|
|
328
|
+
/** The approval a confirm without its deploy wrote (see {@link PluginConfirmResult.approval}). */
|
|
329
|
+
export interface HeldApproval {
|
|
330
|
+
review: PluginReview;
|
|
331
|
+
extension: PluginReviewExtension;
|
|
332
|
+
previous: PreviousSnapshot | null;
|
|
320
333
|
}
|
|
321
334
|
/** What prepare checks besides the package itself (npm and marketplace imports). */
|
|
322
335
|
export interface PluginPrepareExpect {
|
|
@@ -338,6 +351,14 @@ export interface ReviewProvenance {
|
|
|
338
351
|
provenance: ProvenanceResult;
|
|
339
352
|
warning?: "repository_mismatch";
|
|
340
353
|
}
|
|
354
|
+
/** The snapshot overwritten at confirm (restored when deploying an upgrade fails). */
|
|
355
|
+
export interface PreviousSnapshot {
|
|
356
|
+
version: string;
|
|
357
|
+
permissions: PermissionSet;
|
|
358
|
+
approvedBy: string | null;
|
|
359
|
+
approvedAt: Date;
|
|
360
|
+
source: "auto" | "web" | "cli" | "bootstrap";
|
|
361
|
+
}
|
|
341
362
|
/** What an org's staged upload targets (see {@link PluginImport.stagedTarget}). */
|
|
342
363
|
export interface StagedTarget {
|
|
343
364
|
itemId: string;
|
|
@@ -392,12 +413,14 @@ export declare class PluginImport {
|
|
|
392
413
|
private readonly registry;
|
|
393
414
|
private readonly log;
|
|
394
415
|
readonly txHost: TransactionHost;
|
|
395
|
-
/** The platform rows of a new item's components, written
|
|
416
|
+
/** The platform rows of a new item's components, written in the confirm's transaction. */
|
|
396
417
|
private readonly platform;
|
|
397
|
-
/** A failed platform sync enqueues a run of the migration job here (it heals the item). */
|
|
398
|
-
private readonly maintenance;
|
|
399
418
|
/** The client build of a dropped org upload's package is deleted with it. */
|
|
400
419
|
private readonly clientBuilds;
|
|
420
|
+
/** The scope sync's backstop, owed by the confirm's commit (ruling R24). */
|
|
421
|
+
private readonly outbox;
|
|
422
|
+
/** The backstop's delay (a test seam; default `SCOPE_BACKSTOP_DELAY_MS`). */
|
|
423
|
+
private readonly backstopDelayMs;
|
|
401
424
|
/** Where plugin files go (the kernel's object storage; the CLI's own, see {@link useCliStorage}). */
|
|
402
425
|
private files;
|
|
403
426
|
/**
|
|
@@ -415,12 +438,14 @@ export declare class PluginImport {
|
|
|
415
438
|
blobs: ExtensionBlobs,
|
|
416
439
|
/** Config-declared names, loaded connectors and extension versions (the extension registry). */
|
|
417
440
|
registry: ExtensionRegistry, log: KernelLogger, txHost: TransactionHost,
|
|
418
|
-
/** The platform rows of a new item's components, written
|
|
441
|
+
/** The platform rows of a new item's components, written in the confirm's transaction. */
|
|
419
442
|
platform: PlatformComponents,
|
|
420
|
-
/** A failed platform sync enqueues a run of the migration job here (it heals the item). */
|
|
421
|
-
maintenance: Pick<Queue, "add">,
|
|
422
443
|
/** The client build of a dropped org upload's package is deleted with it. */
|
|
423
|
-
clientBuilds: ClientBuilds
|
|
444
|
+
clientBuilds: ClientBuilds,
|
|
445
|
+
/** The scope sync's backstop, owed by the confirm's commit (ruling R24). */
|
|
446
|
+
outbox: Pick<OutboxService, "add">,
|
|
447
|
+
/** The backstop's delay (a test seam; default `SCOPE_BACKSTOP_DELAY_MS`). */
|
|
448
|
+
backstopDelayMs?: number);
|
|
424
449
|
/** The kernel-schema handle of the current context (the transaction, else the pool). */
|
|
425
450
|
private get db();
|
|
426
451
|
/**
|
|
@@ -521,8 +546,10 @@ export declare class PluginImport {
|
|
|
521
546
|
* whether the item exists (a new version of the org's own plugin) or the version is imported
|
|
522
547
|
* already (F4), and the target as the platform updater reads it: the staged manifest and files,
|
|
523
548
|
* or the imported version's for a retry. Another org's staging -> 404 `plugin.staging_not_found`.
|
|
549
|
+
* Without `owner`: a platform staging, and `existing` means a live platform-owned item (the
|
|
550
|
+
* platform's import and update, `PlatformImportUpdate`).
|
|
524
551
|
*/
|
|
525
|
-
stagedTarget(stagingId: string, owner
|
|
552
|
+
stagedTarget(stagingId: string, owner?: ImportOwner): Promise<StagedTarget>;
|
|
526
553
|
/** The catalog item's view (as a confirm returns it). */
|
|
527
554
|
view(itemId: string): Promise<CatalogItemView>;
|
|
528
555
|
/**
|
|
@@ -553,15 +580,23 @@ export declare class PluginImport {
|
|
|
553
580
|
orgs?: string[];
|
|
554
581
|
/** An org upload's new item: shared with other orgs by its owner (default false, P3-16). */
|
|
555
582
|
shareable?: boolean;
|
|
583
|
+
/**
|
|
584
|
+
* Deploy the extension after the commit (default true). false (the platform's import and
|
|
585
|
+
* update, `PlatformImportUpdate`) leaves the deployment to the platform update that follows,
|
|
586
|
+
* which moves the extension with its own rollback; the approval written is returned in
|
|
587
|
+
* `approval`.
|
|
588
|
+
*/
|
|
589
|
+
deploy?: boolean;
|
|
556
590
|
}, opts?: ActorOpts & {
|
|
557
591
|
owner?: ImportOwner;
|
|
558
592
|
}): Promise<PluginConfirmResult>;
|
|
559
593
|
/**
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
594
|
+
* The platform components of the staged version when its confirm will most likely make it the
|
|
595
|
+
* item's first usable version ({@link commit} decides under its locks): no live item of the name
|
|
596
|
+
* yet, or an org upload replacing its own first upload still awaiting confirmation. Planned from
|
|
597
|
+
* the staged content and their files copied, outside any transaction; otherwise undefined.
|
|
563
598
|
*/
|
|
564
|
-
|
|
599
|
+
private prepareFirstVersion;
|
|
565
600
|
/**
|
|
566
601
|
* The confirm's transaction: the staging row consumed, the extension's action recomputed under
|
|
567
602
|
* its install lock (stale -> `plugin.review_stale`), its snapshot approved, and the catalog
|
|
@@ -575,17 +610,15 @@ export declare class PluginImport {
|
|
|
575
610
|
* upload without an extension for an item whose first version still waits (plan Task 6) replaces
|
|
576
611
|
* that upload and applies at once: the item stops waiting and the claim is released (nothing
|
|
577
612
|
* was installed under it).
|
|
613
|
+
*
|
|
614
|
+
* The item's first usable version (a new item not waiting, or an awaiting first upload replaced)
|
|
615
|
+
* writes the platform rows of its skills, agent templates, connector templates and themes
|
|
616
|
+
* (plugin scope phase 2) from `prepared` (their files copied before the transaction, keyed by
|
|
617
|
+
* content): a failure rolls the whole confirm back, and a retry copies nothing again. A plan made
|
|
618
|
+
* for another item or version, or a component changed since it -> `plugin.review_stale`. A new
|
|
619
|
+
* version of an existing item leaves them to the platform update.
|
|
578
620
|
*/
|
|
579
621
|
private commit;
|
|
580
|
-
/**
|
|
581
|
-
* The platform components of a new item. The item is committed already, so a failure is logged
|
|
582
|
-
* and not thrown (like a failed deploy, the import itself succeeded); a run of the platform
|
|
583
|
-
* components migration job (which writes what is missing) is enqueued on `cap-kernel-maintenance`
|
|
584
|
-
* after {@link PLATFORM_SYNC_RETRY_MS}, one per item (deterministic job id). If that run fails
|
|
585
|
-
* too, its `itemsFailed` shows in the super admin's inbox; the daily run and every worker start
|
|
586
|
-
* try again.
|
|
587
|
-
*/
|
|
588
|
-
private syncPlatform;
|
|
589
622
|
/**
|
|
590
623
|
* Writes the extension's permission snapshot for the version being imported (source web; cli
|
|
591
624
|
* without an actor; bootstrap for the bootstrap step), after
|
|
@@ -603,6 +636,11 @@ export declare class PluginImport {
|
|
|
603
636
|
* admin (the package is already in the package store) with the sha256 from the result.
|
|
604
637
|
*/
|
|
605
638
|
private deploy;
|
|
639
|
+
/**
|
|
640
|
+
* Puts back the approval a confirm with `deploy: false` wrote, after the step that was to deploy
|
|
641
|
+
* the extension failed (see {@link restoreSnapshot}; false when someone changed it meanwhile).
|
|
642
|
+
*/
|
|
643
|
+
restoreApproval(actor: string | null, held: HeldApproval, opts?: ActorOpts): Promise<boolean>;
|
|
606
644
|
/**
|
|
607
645
|
* Restores the snapshot overwritten at confirm (deletes it when there was none before), audits
|
|
608
646
|
* `extension.permissions_restored`. Compare-and-write (row locked): restores only while the
|
|
@@ -9,8 +9,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
9
9
|
};
|
|
10
10
|
import { createHash, randomUUID } from "node:crypto";
|
|
11
11
|
import { appearanceIssues, PLUGIN_MANIFEST_FILE, parseSkillMd, pluginDescription, SDK_VERSION, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
|
|
12
|
-
import {
|
|
13
|
-
import { Inject, Injectable } from "@nestjs/common";
|
|
12
|
+
import { Inject, Injectable, Optional } from "@nestjs/common";
|
|
14
13
|
import { sql } from "kysely";
|
|
15
14
|
import semver from "semver";
|
|
16
15
|
import { ClientBuilds } from "../client/client-builds.service.js";
|
|
@@ -35,10 +34,10 @@ import { afterCommit } from "../infra/database/after-commit.js";
|
|
|
35
34
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
36
35
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
37
36
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
37
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
38
38
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
39
39
|
import { OrgLock } from "../orgs/org-lock.js";
|
|
40
40
|
import { packPackageTgz } from "../packages/tgz.js";
|
|
41
|
-
import { MAINTENANCE_QUEUE_NAME } from "../runtime/maintenance-queue.js";
|
|
42
41
|
import { checkSkillFiles, SkillArchiveError } from "../skills/package.js";
|
|
43
42
|
import { StorageService } from "../storage/storage.service.js";
|
|
44
43
|
import { canonicalJson } from "../tools/canonical-json.js";
|
|
@@ -52,15 +51,13 @@ import { item as reportItem, sortItems, } from "./claude/report.js";
|
|
|
52
51
|
import { isClaudePluginTree, translateClaudePlugin } from "./claude/translate.js";
|
|
53
52
|
import { CatalogItemLock } from "./locks.js";
|
|
54
53
|
import { assertNameFree, assertPackageFree, assertShareable, packageOwner, releaseExtensionClaim, shareGate, usableBy, } from "./ownership.js";
|
|
55
|
-
import { PlatformComponents } from "./platform-components.js";
|
|
56
|
-
import { PLATFORM_MIGRATION_JOB } from "./platform-migration.js";
|
|
54
|
+
import { PlanStale, PlatformComponents } from "./platform-components.js";
|
|
57
55
|
import { PluginPackageError, readPluginFiles, readPluginPackage, themeApiError, } from "./plugin-package.js";
|
|
58
56
|
import { hasImportRequests, importRequestOf, resolveImportRequests } from "./request-rules.js";
|
|
59
57
|
import { assertNameNotReserved } from "./reserved-names.js";
|
|
58
|
+
import { oweScopeItem, SCOPE_BACKSTOP_DELAY, SCOPE_BACKSTOP_DELAY_MS } from "./scope-jobs.js";
|
|
60
59
|
import { addScopeOrg } from "./scope-orgs.js";
|
|
61
60
|
import { maxSatisfying, satisfiesRange } from "./versions.js";
|
|
62
|
-
/** How long after a failed post-import platform sync the migration job runs for the item. */
|
|
63
|
-
export const PLATFORM_SYNC_RETRY_MS = 60_000;
|
|
64
61
|
/**
|
|
65
62
|
* Platform import of a plugin (package ecosystem spec §4.3): one review for every plugin, whatever
|
|
66
63
|
* it contains (an extension, skills, connector templates, dependencies), confirmed once.
|
|
@@ -86,8 +83,10 @@ export const PLATFORM_SYNC_RETRY_MS = 60_000;
|
|
|
86
83
|
* snapshot when it is installed or upgraded by this import (source web, audit
|
|
87
84
|
* `extension.permissions_approved` carrying the plugin), and creates the item (with the scope the
|
|
88
85
|
* admin chose, default `optional`) or adds the version (`manifest` = the normalized plugin.json,
|
|
89
|
-
* `extension_sha256`, the files under the staging prefix)
|
|
90
|
-
*
|
|
86
|
+
* `extension_sha256`, the files under the staging prefix); an item's first usable version also
|
|
87
|
+
* gets its platform component rows there (their files copied before, keyed by content: a failure
|
|
88
|
+
* leaves nothing a retry copies again; no job heals an item later). After the commit the plugin's
|
|
89
|
+
* own extension is installed on the deployment and enabled (`ExtensionAdminOps.install` + `enable`;
|
|
91
90
|
* each replica reconciles, no restart); a failure is returned, not thrown, and an upgrade that was
|
|
92
91
|
* not installed gets its old snapshot back.
|
|
93
92
|
*
|
|
@@ -164,8 +163,9 @@ let PluginImport = class PluginImport {
|
|
|
164
163
|
log;
|
|
165
164
|
txHost;
|
|
166
165
|
platform;
|
|
167
|
-
maintenance;
|
|
168
166
|
clientBuilds;
|
|
167
|
+
outbox;
|
|
168
|
+
backstopDelayMs;
|
|
169
169
|
/** Where plugin files go (the kernel's object storage; the CLI's own, see {@link useCliStorage}). */
|
|
170
170
|
files;
|
|
171
171
|
/**
|
|
@@ -183,12 +183,14 @@ let PluginImport = class PluginImport {
|
|
|
183
183
|
blobs,
|
|
184
184
|
/** Config-declared names, loaded connectors and extension versions (the extension registry). */
|
|
185
185
|
registry, log, txHost,
|
|
186
|
-
/** The platform rows of a new item's components, written
|
|
186
|
+
/** The platform rows of a new item's components, written in the confirm's transaction. */
|
|
187
187
|
platform,
|
|
188
|
-
/** A failed platform sync enqueues a run of the migration job here (it heals the item). */
|
|
189
|
-
maintenance,
|
|
190
188
|
/** The client build of a dropped org upload's package is deleted with it. */
|
|
191
|
-
clientBuilds
|
|
189
|
+
clientBuilds,
|
|
190
|
+
/** The scope sync's backstop, owed by the confirm's commit (ruling R24). */
|
|
191
|
+
outbox,
|
|
192
|
+
/** The backstop's delay (a test seam; default `SCOPE_BACKSTOP_DELAY_MS`). */
|
|
193
|
+
backstopDelayMs = SCOPE_BACKSTOP_DELAY_MS) {
|
|
192
194
|
this.kdb = kdb;
|
|
193
195
|
this.adminLock = adminLock;
|
|
194
196
|
this.orgLock = orgLock;
|
|
@@ -204,8 +206,9 @@ let PluginImport = class PluginImport {
|
|
|
204
206
|
this.log = log;
|
|
205
207
|
this.txHost = txHost;
|
|
206
208
|
this.platform = platform;
|
|
207
|
-
this.maintenance = maintenance;
|
|
208
209
|
this.clientBuilds = clientBuilds;
|
|
210
|
+
this.outbox = outbox;
|
|
211
|
+
this.backstopDelayMs = backstopDelayMs;
|
|
209
212
|
this.files = storage;
|
|
210
213
|
}
|
|
211
214
|
/** The kernel-schema handle of the current context (the transaction, else the pool). */
|
|
@@ -610,6 +613,8 @@ let PluginImport = class PluginImport {
|
|
|
610
613
|
* whether the item exists (a new version of the org's own plugin) or the version is imported
|
|
611
614
|
* already (F4), and the target as the platform updater reads it: the staged manifest and files,
|
|
612
615
|
* or the imported version's for a retry. Another org's staging -> 404 `plugin.staging_not_found`.
|
|
616
|
+
* Without `owner`: a platform staging, and `existing` means a live platform-owned item (the
|
|
617
|
+
* platform's import and update, `PlatformImportUpdate`).
|
|
613
618
|
*/
|
|
614
619
|
async stagedTarget(stagingId, owner) {
|
|
615
620
|
if (!UUID_RE.test(stagingId))
|
|
@@ -630,7 +635,7 @@ let PluginImport = class PluginImport {
|
|
|
630
635
|
.select(["id", "awaiting_confirmation"])
|
|
631
636
|
.where("id", "=", staged.itemId)
|
|
632
637
|
.where("deleted_at", "is", null)
|
|
633
|
-
.where("owner_org_id", "=", owner.orgId)
|
|
638
|
+
.where((eb) => owner === undefined ? eb("owner_org_id", "is", null) : eb("owner_org_id", "=", owner.orgId))
|
|
634
639
|
.executeTakeFirst();
|
|
635
640
|
const imported = staged.retry === true
|
|
636
641
|
? await this.db
|
|
@@ -732,11 +737,16 @@ let PluginImport = class PluginImport {
|
|
|
732
737
|
const stored = reviewed && reviewed.action !== "keep" && owner === undefined
|
|
733
738
|
? await this.readStored(reviewed.sha256)
|
|
734
739
|
: undefined;
|
|
740
|
+
// The platform components of the item's first usable version: planned and their files copied
|
|
741
|
+
// (keyed by content) before the transaction, their rows written in it
|
|
742
|
+
const prepared = staged.retry === true || (owner !== undefined && reviewed !== undefined)
|
|
743
|
+
? undefined
|
|
744
|
+
: await this.prepareFirstVersion(staged, row.object_prefix, owner);
|
|
735
745
|
const committed = await this.commit(actor, { stagingId, review, staged, src, manifest, objectPrefix: row.object_prefix }, {
|
|
736
746
|
scope,
|
|
737
747
|
orgs: [...new Set(orgs ?? [])].sort(),
|
|
738
748
|
...(owner !== undefined && { owner, shareable: input.shareable ?? false }),
|
|
739
|
-
}, stored, opts);
|
|
749
|
+
}, stored, opts, prepared);
|
|
740
750
|
const { now } = committed;
|
|
741
751
|
if (committed.pending) {
|
|
742
752
|
// Waits for the super admin (P3-10): no platform components, nothing deployed
|
|
@@ -748,11 +758,19 @@ let PluginImport = class PluginImport {
|
|
|
748
758
|
firstVersion: false,
|
|
749
759
|
};
|
|
750
760
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
761
|
+
if (input.deploy === false) {
|
|
762
|
+
return {
|
|
763
|
+
item: await this.itemView(committed.itemId),
|
|
764
|
+
created: committed.created,
|
|
765
|
+
deploy: null,
|
|
766
|
+
pending: false,
|
|
767
|
+
firstVersion: committed.firstVersion,
|
|
768
|
+
...(now &&
|
|
769
|
+
committed.previous !== undefined && {
|
|
770
|
+
approval: { review, extension: now, previous: committed.previous },
|
|
771
|
+
}),
|
|
772
|
+
};
|
|
773
|
+
}
|
|
756
774
|
const deploy = now && now.action !== "keep"
|
|
757
775
|
? await this.deploy(actor, review, committed.itemId, now, committed.previous, opts, input.enable ?? true)
|
|
758
776
|
: null;
|
|
@@ -765,12 +783,31 @@ let PluginImport = class PluginImport {
|
|
|
765
783
|
};
|
|
766
784
|
}
|
|
767
785
|
/**
|
|
768
|
-
*
|
|
769
|
-
*
|
|
770
|
-
*
|
|
786
|
+
* The platform components of the staged version when its confirm will most likely make it the
|
|
787
|
+
* item's first usable version ({@link commit} decides under its locks): no live item of the name
|
|
788
|
+
* yet, or an org upload replacing its own first upload still awaiting confirmation. Planned from
|
|
789
|
+
* the staged content and their files copied, outside any transaction; otherwise undefined.
|
|
771
790
|
*/
|
|
772
|
-
async
|
|
773
|
-
await this.
|
|
791
|
+
async prepareFirstVersion(staged, objectPrefix, owner) {
|
|
792
|
+
const live = await this.db
|
|
793
|
+
.selectFrom("catalog_items")
|
|
794
|
+
.select(["id", "awaiting_confirmation", "owner_org_id"])
|
|
795
|
+
.where("name", "=", staged.manifest.name)
|
|
796
|
+
.where("deleted_at", "is", null)
|
|
797
|
+
.executeTakeFirst();
|
|
798
|
+
const first = live === undefined ||
|
|
799
|
+
(owner !== undefined && live.awaiting_confirmation && live.owner_org_id === owner.orgId);
|
|
800
|
+
if (!first)
|
|
801
|
+
return undefined;
|
|
802
|
+
return this.platform.prepareImport({
|
|
803
|
+
itemId: live?.id ?? staged.itemId,
|
|
804
|
+
plugin: staged.manifest.name,
|
|
805
|
+
version: staged.version,
|
|
806
|
+
manifest: staged.manifest,
|
|
807
|
+
objectPrefix,
|
|
808
|
+
files: staged.files,
|
|
809
|
+
sourceFormat: staged.sourceFormat ?? "capybara",
|
|
810
|
+
});
|
|
774
811
|
}
|
|
775
812
|
/**
|
|
776
813
|
* The confirm's transaction: the staging row consumed, the extension's action recomputed under
|
|
@@ -785,8 +822,15 @@ let PluginImport = class PluginImport {
|
|
|
785
822
|
* upload without an extension for an item whose first version still waits (plan Task 6) replaces
|
|
786
823
|
* that upload and applies at once: the item stops waiting and the claim is released (nothing
|
|
787
824
|
* was installed under it).
|
|
825
|
+
*
|
|
826
|
+
* The item's first usable version (a new item not waiting, or an awaiting first upload replaced)
|
|
827
|
+
* writes the platform rows of its skills, agent templates, connector templates and themes
|
|
828
|
+
* (plugin scope phase 2) from `prepared` (their files copied before the transaction, keyed by
|
|
829
|
+
* content): a failure rolls the whole confirm back, and a retry copies nothing again. A plan made
|
|
830
|
+
* for another item or version, or a component changed since it -> `plugin.review_stale`. A new
|
|
831
|
+
* version of an existing item leaves them to the platform update.
|
|
788
832
|
*/
|
|
789
|
-
async commit(actor, c, scope, stored, opts) {
|
|
833
|
+
async commit(actor, c, scope, stored, opts, prepared) {
|
|
790
834
|
const { stagingId, review, staged, src, manifest } = c;
|
|
791
835
|
const reviewed = review.extension;
|
|
792
836
|
const stale = () => reviewStale(review);
|
|
@@ -1019,61 +1063,44 @@ let PluginImport = class PluginImport {
|
|
|
1019
1063
|
await markVersionApplied(t, itemId, staged.version);
|
|
1020
1064
|
await releaseExtensionClaim(t, m.name, existing.package_name);
|
|
1021
1065
|
}
|
|
1066
|
+
const firstVersion = (created && !pending) || replacedAwaiting;
|
|
1067
|
+
if (firstVersion) {
|
|
1068
|
+
if (prepared?.plan.itemId !== itemId || prepared.plan.version !== staged.version) {
|
|
1069
|
+
throw stale();
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
await this.platform.applySyncIn(prepared);
|
|
1073
|
+
}
|
|
1074
|
+
catch (e) {
|
|
1075
|
+
if (e instanceof PlanStale)
|
|
1076
|
+
throw stale();
|
|
1077
|
+
throw e;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
// The commit owes the scope sync's backstop (ruling R24) when the item's scope turns it on by
|
|
1081
|
+
// itself: the caller owes the immediate sync after the deploy, which a crash may lose
|
|
1082
|
+
if (!pending) {
|
|
1083
|
+
const item = await t
|
|
1084
|
+
.selectFrom("catalog_items")
|
|
1085
|
+
.select("scope")
|
|
1086
|
+
.where("id", "=", itemId)
|
|
1087
|
+
.executeTakeFirstOrThrow();
|
|
1088
|
+
if (item.scope !== "optional") {
|
|
1089
|
+
await oweScopeItem(this.outbox, t, itemId, {
|
|
1090
|
+
backstop: true,
|
|
1091
|
+
backstopDelayMs: this.backstopDelayMs,
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1022
1095
|
return {
|
|
1023
1096
|
itemId,
|
|
1024
1097
|
created,
|
|
1025
|
-
firstVersion
|
|
1098
|
+
firstVersion,
|
|
1026
1099
|
pending,
|
|
1027
1100
|
now,
|
|
1028
1101
|
previous,
|
|
1029
1102
|
};
|
|
1030
1103
|
}
|
|
1031
|
-
/**
|
|
1032
|
-
* The platform components of a new item. The item is committed already, so a failure is logged
|
|
1033
|
-
* and not thrown (like a failed deploy, the import itself succeeded); a run of the platform
|
|
1034
|
-
* components migration job (which writes what is missing) is enqueued on `cap-kernel-maintenance`
|
|
1035
|
-
* after {@link PLATFORM_SYNC_RETRY_MS}, one per item (deterministic job id). If that run fails
|
|
1036
|
-
* too, its `itemsFailed` shows in the super admin's inbox; the daily run and every worker start
|
|
1037
|
-
* try again.
|
|
1038
|
-
*/
|
|
1039
|
-
async syncPlatform(itemId, version) {
|
|
1040
|
-
try {
|
|
1041
|
-
await this.platform.syncFromVersion(itemId, version, { initial: true });
|
|
1042
|
-
}
|
|
1043
|
-
catch (err) {
|
|
1044
|
-
// Removed meanwhile (an org deletion racing a confirmation, P3-20): nothing to write
|
|
1045
|
-
const live = await this.db
|
|
1046
|
-
.selectFrom("catalog_items")
|
|
1047
|
-
.select("id")
|
|
1048
|
-
.where("id", "=", itemId)
|
|
1049
|
-
.where("deleted_at", "is", null)
|
|
1050
|
-
.executeTakeFirst();
|
|
1051
|
-
if (live === undefined) {
|
|
1052
|
-
this.log.info("catalog item removed before its platform components were written", {
|
|
1053
|
-
itemId,
|
|
1054
|
-
version,
|
|
1055
|
-
});
|
|
1056
|
-
return;
|
|
1057
|
-
}
|
|
1058
|
-
this.log.error("writing the platform components of a new catalog item failed", {
|
|
1059
|
-
itemId,
|
|
1060
|
-
version,
|
|
1061
|
-
err,
|
|
1062
|
-
});
|
|
1063
|
-
try {
|
|
1064
|
-
await this.maintenance.add(PLATFORM_MIGRATION_JOB, {}, {
|
|
1065
|
-
jobId: `${PLATFORM_MIGRATION_JOB}-retry-${itemId}`,
|
|
1066
|
-
delay: PLATFORM_SYNC_RETRY_MS,
|
|
1067
|
-
attempts: 1,
|
|
1068
|
-
removeOnComplete: true,
|
|
1069
|
-
removeOnFail: { age: 86_400 },
|
|
1070
|
-
});
|
|
1071
|
-
}
|
|
1072
|
-
catch (e) {
|
|
1073
|
-
this.log.warn("cannot enqueue the platform components migration", { itemId, err: e });
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
1104
|
/**
|
|
1078
1105
|
* Writes the extension's permission snapshot for the version being imported (source web; cli
|
|
1079
1106
|
* without an actor; bootstrap for the bootstrap step), after
|
|
@@ -1184,6 +1211,13 @@ let PluginImport = class PluginImport {
|
|
|
1184
1211
|
return { ...base, result: "failed", ...failure(e) };
|
|
1185
1212
|
}
|
|
1186
1213
|
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Puts back the approval a confirm with `deploy: false` wrote, after the step that was to deploy
|
|
1216
|
+
* the extension failed (see {@link restoreSnapshot}; false when someone changed it meanwhile).
|
|
1217
|
+
*/
|
|
1218
|
+
async restoreApproval(actor, held, opts = {}) {
|
|
1219
|
+
return this.restoreSnapshot(actor, held.review, held.extension, held.previous, opts);
|
|
1220
|
+
}
|
|
1187
1221
|
/**
|
|
1188
1222
|
* Restores the snapshot overwritten at confirm (deletes it when there was none before), audits
|
|
1189
1223
|
* `extension.permissions_restored`. Compare-and-write (row locked): restores only while the
|
|
@@ -1705,8 +1739,10 @@ PluginImport = __decorate([
|
|
|
1705
1739
|
__param(13, Inject(KERNEL_LOGGER)),
|
|
1706
1740
|
__param(14, Inject(TransactionHost)),
|
|
1707
1741
|
__param(15, Inject(PlatformComponents)),
|
|
1708
|
-
__param(16, Inject(
|
|
1709
|
-
__param(17, Inject(
|
|
1742
|
+
__param(16, Inject(ClientBuilds)),
|
|
1743
|
+
__param(17, Inject(OutboxService)),
|
|
1744
|
+
__param(18, Optional()),
|
|
1745
|
+
__param(18, Inject(SCOPE_BACKSTOP_DELAY))
|
|
1710
1746
|
], PluginImport);
|
|
1711
1747
|
export { PluginImport };
|
|
1712
1748
|
/**
|