@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.
Files changed (293) hide show
  1. package/bootstrap.json +25 -25
  2. package/dist/admin/admin.module.d.ts +2 -1
  3. package/dist/admin/admin.module.js +9 -3
  4. package/dist/admin/health.service.d.ts +2 -2
  5. package/dist/admin/health.service.js +6 -2
  6. package/dist/admin/outbox-dead.controller.d.ts +23 -0
  7. package/dist/admin/outbox-dead.controller.js +62 -0
  8. package/dist/admin/outbox-dead.schemas.d.ts +8 -0
  9. package/dist/admin/outbox-dead.schemas.js +18 -0
  10. package/dist/admin/outbox-dead.service.d.ts +66 -0
  11. package/dist/admin/outbox-dead.service.js +179 -0
  12. package/dist/admin/overview.service.d.ts +40 -5
  13. package/dist/admin/overview.service.js +41 -7
  14. package/dist/agents/agents.module.js +3 -0
  15. package/dist/agents/agents.service.d.ts +6 -1
  16. package/dist/agents/agents.service.js +11 -2
  17. package/dist/agents/from-template.js +1 -1
  18. package/dist/background/finish.d.ts +5 -2
  19. package/dist/background/finish.js +14 -3
  20. package/dist/background/launch.d.ts +2 -1
  21. package/dist/background/launch.js +5 -2
  22. package/dist/background/store.d.ts +8 -0
  23. package/dist/background/store.js +24 -0
  24. package/dist/catalog/admin-catalog.controller.d.ts +21 -2
  25. package/dist/catalog/admin-catalog.controller.js +45 -6
  26. package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
  27. package/dist/catalog/admin-catalog.schemas.js +8 -0
  28. package/dist/catalog/catalog-import.module.js +0 -4
  29. package/dist/catalog/catalog-scope.service.d.ts +63 -26
  30. package/dist/catalog/catalog-scope.service.js +146 -71
  31. package/dist/catalog/catalog.module.d.ts +2 -1
  32. package/dist/catalog/catalog.module.js +9 -4
  33. package/dist/catalog/catalog.service.d.ts +11 -4
  34. package/dist/catalog/catalog.service.js +21 -5
  35. package/dist/catalog/cli.d.ts +4 -3
  36. package/dist/catalog/cli.js +8 -13
  37. package/dist/catalog/job-ids.d.ts +8 -20
  38. package/dist/catalog/job-ids.js +11 -16
  39. package/dist/catalog/marketplaces.service.d.ts +1 -1
  40. package/dist/catalog/org-plugin-uploads.d.ts +11 -4
  41. package/dist/catalog/org-plugin-uploads.js +21 -6
  42. package/dist/catalog/owned-items.d.ts +6 -13
  43. package/dist/catalog/owned-items.js +11 -29
  44. package/dist/catalog/owned-plugin-cleanup.d.ts +8 -17
  45. package/dist/catalog/owned-plugin-cleanup.js +12 -66
  46. package/dist/catalog/platform-components.d.ts +56 -34
  47. package/dist/catalog/platform-components.js +68 -78
  48. package/dist/catalog/platform-import-update.d.ts +50 -0
  49. package/dist/catalog/platform-import-update.js +116 -0
  50. package/dist/catalog/plugin-import.d.ts +64 -26
  51. package/dist/catalog/plugin-import.js +113 -77
  52. package/dist/catalog/plugin-upgrade.d.ts +22 -4
  53. package/dist/catalog/plugin-upgrade.js +26 -19
  54. package/dist/catalog/scope-jobs.d.ts +59 -0
  55. package/dist/catalog/scope-jobs.js +65 -0
  56. package/dist/catalog/scope-sync-workers.d.ts +22 -0
  57. package/dist/catalog/scope-sync-workers.js +58 -2
  58. package/dist/catalog/scope-sync.d.ts +40 -65
  59. package/dist/catalog/scope-sync.js +114 -122
  60. package/dist/channels/channels.module.d.ts +5 -2
  61. package/dist/channels/channels.module.js +9 -2
  62. package/dist/channels/deliver-job.d.ts +25 -0
  63. package/dist/channels/deliver-job.js +25 -0
  64. package/dist/channels/inbound.d.ts +1 -1
  65. package/dist/channels/inbound.js +4 -17
  66. package/dist/channels/jobs.d.ts +28 -18
  67. package/dist/channels/jobs.js +63 -26
  68. package/dist/channels/threads.d.ts +4 -3
  69. package/dist/channels/threads.js +4 -3
  70. package/dist/config/schema.d.ts +0 -3
  71. package/dist/config/schema.js +11 -20
  72. package/dist/conversations/agent-tree.d.ts +16 -0
  73. package/dist/conversations/agent-tree.js +36 -0
  74. package/dist/conversations/conversations.controller.js +4 -2
  75. package/dist/conversations/conversations.service.d.ts +61 -19
  76. package/dist/conversations/conversations.service.js +69 -43
  77. package/dist/conversations/event-log.d.ts +7 -10
  78. package/dist/conversations/event-log.js +24 -15
  79. package/dist/conversations/events.d.ts +21 -0
  80. package/dist/conversations/events.js +26 -2
  81. package/dist/conversations/queue.service.d.ts +8 -3
  82. package/dist/conversations/queue.service.js +37 -13
  83. package/dist/conversations/source.d.ts +10 -0
  84. package/dist/conversations/source.js +17 -0
  85. package/dist/conversations/titles.d.ts +21 -8
  86. package/dist/conversations/titles.js +42 -15
  87. package/dist/conversations/tree.d.ts +10 -0
  88. package/dist/conversations/tree.js +35 -0
  89. package/dist/db/kernel-schema.d.ts +35 -22
  90. package/dist/devices/devices.service.d.ts +23 -11
  91. package/dist/devices/devices.service.js +34 -26
  92. package/dist/errors.d.ts +11 -0
  93. package/dist/errors.js +11 -0
  94. package/dist/evals/run-replay.d.ts +13 -2
  95. package/dist/evals/run-replay.js +42 -9
  96. package/dist/evals/snapshot.d.ts +7 -1
  97. package/dist/evals/snapshot.js +2 -1
  98. package/dist/extensions/extensions.module.js +3 -0
  99. package/dist/extensions/hooks.d.ts +22 -3
  100. package/dist/extensions/hooks.js +15 -1
  101. package/dist/extensions/lifecycle-hooks.d.ts +99 -0
  102. package/dist/extensions/lifecycle-hooks.js +273 -0
  103. package/dist/extensions/lifecycle.d.ts +6 -1
  104. package/dist/extensions/lifecycle.js +9 -2
  105. package/dist/extensions/org-config.d.ts +13 -1
  106. package/dist/extensions/org-config.js +19 -2
  107. package/dist/extensions/permission-view.d.ts +9 -5
  108. package/dist/extensions/permission-view.js +9 -4
  109. package/dist/extensions/point-defaults.d.ts +28 -1
  110. package/dist/extensions/point-defaults.js +44 -13
  111. package/dist/extensions/usage-subscribers.d.ts +43 -0
  112. package/dist/extensions/usage-subscribers.js +108 -0
  113. package/dist/http/api.module.js +2 -0
  114. package/dist/inbox/inbox.service.d.ts +6 -20
  115. package/dist/inbox/inbox.service.js +0 -3
  116. package/dist/inbox/org-notices.d.ts +1 -1
  117. package/dist/inbox/platform-inbox.service.d.ts +3 -32
  118. package/dist/inbox/platform-inbox.service.js +5 -54
  119. package/dist/index.d.ts +1 -0
  120. package/dist/index.js +1 -0
  121. package/dist/infra/cli/kernel-cli.module.js +5 -0
  122. package/dist/infra/events/kernel-events.d.ts +9 -35
  123. package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
  124. package/dist/infra/outbox/outbox-relay.module.js +18 -0
  125. package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
  126. package/dist/infra/outbox/outbox.dispatcher.js +310 -0
  127. package/dist/infra/outbox/outbox.module.d.ts +24 -0
  128. package/dist/infra/outbox/outbox.module.js +50 -0
  129. package/dist/infra/outbox/outbox.relay.d.ts +31 -0
  130. package/dist/infra/outbox/outbox.relay.js +76 -0
  131. package/dist/infra/outbox/outbox.service.d.ts +51 -0
  132. package/dist/infra/outbox/outbox.service.js +131 -0
  133. package/dist/infra/outbox/registry.d.ts +244 -0
  134. package/dist/infra/outbox/registry.js +234 -0
  135. package/dist/infra/queue/queue-names.d.ts +8 -0
  136. package/dist/infra/queue/queue-names.js +17 -0
  137. package/dist/kernel.module.js +3 -0
  138. package/dist/local-devices/device-policy.service.d.ts +4 -0
  139. package/dist/local-devices/device-policy.service.js +61 -3
  140. package/dist/local-devices/machines.d.ts +13 -5
  141. package/dist/local-devices/machines.js +45 -7
  142. package/dist/local-devices/policy-summary.d.ts +44 -1
  143. package/dist/local-devices/policy-summary.js +69 -0
  144. package/dist/models/embeddings.d.ts +9 -9
  145. package/dist/models/embeddings.js +11 -18
  146. package/dist/models/models.module.js +3 -0
  147. package/dist/orgs/directory-sync.js +1 -1
  148. package/dist/orgs/members.service.js +1 -1
  149. package/dist/orgs/offboarding.d.ts +50 -57
  150. package/dist/orgs/offboarding.js +117 -162
  151. package/dist/orgs/orgs.module.js +3 -0
  152. package/dist/orgs/orgs.service.d.ts +11 -5
  153. package/dist/orgs/orgs.service.js +22 -6
  154. package/dist/overrides.d.ts +23 -3
  155. package/dist/overrides.js +12 -2
  156. package/dist/platform/exclusions.js +5 -0
  157. package/dist/platform/ops/admin.ops.js +18 -2
  158. package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
  159. package/dist/platform/ops/catalog-admin.ops.js +32 -4
  160. package/dist/platform/ops/inbox.ops.js +4 -20
  161. package/dist/platform/ops/outbox.ops.d.ts +21 -0
  162. package/dist/platform/ops/outbox.ops.js +125 -0
  163. package/dist/platform/ops/platform.ops.d.ts +1 -0
  164. package/dist/platform/ops/platform.ops.js +6 -3
  165. package/dist/platform/ops/schedules.ops.js +40 -1
  166. package/dist/platform/platform-ops.module.d.ts +2 -1
  167. package/dist/platform/platform-ops.module.js +3 -0
  168. package/dist/platform/route-schemas.js +3 -0
  169. package/dist/roles/worker-role.d.ts +10 -5
  170. package/dist/roles/worker-role.js +19 -9
  171. package/dist/roles/worker.module.js +11 -8
  172. package/dist/runtime/context/build.d.ts +3 -0
  173. package/dist/runtime/context/build.js +15 -0
  174. package/dist/runtime/context/plugin-context.d.ts +20 -0
  175. package/dist/runtime/context/plugin-context.js +30 -0
  176. package/dist/runtime/langgraph-loop.js +17 -5
  177. package/dist/runtime/limits.d.ts +15 -0
  178. package/dist/runtime/limits.js +25 -0
  179. package/dist/runtime/loop.d.ts +16 -3
  180. package/dist/runtime/loop.js +2 -1
  181. package/dist/runtime/maintenance.d.ts +7 -3
  182. package/dist/runtime/maintenance.js +52 -12
  183. package/dist/runtime/model-call.d.ts +20 -17
  184. package/dist/runtime/model-call.js +15 -24
  185. package/dist/runtime/plugin-context.service.d.ts +69 -0
  186. package/dist/runtime/plugin-context.service.js +208 -0
  187. package/dist/runtime/queue-lost-jobs.d.ts +24 -0
  188. package/dist/runtime/queue-lost-jobs.js +51 -0
  189. package/dist/runtime/run-control.d.ts +47 -5
  190. package/dist/runtime/run-control.js +79 -12
  191. package/dist/runtime/run-finish.d.ts +39 -12
  192. package/dist/runtime/run-finish.js +97 -14
  193. package/dist/runtime/run-jobs.d.ts +95 -13
  194. package/dist/runtime/run-jobs.js +199 -28
  195. package/dist/runtime/run-orphan-check.job.d.ts +142 -0
  196. package/dist/runtime/run-orphan-check.job.js +339 -0
  197. package/dist/runtime/run-processors.d.ts +16 -9
  198. package/dist/runtime/run-processors.js +1 -1
  199. package/dist/runtime/run-queue.d.ts +75 -53
  200. package/dist/runtime/run-queue.js +189 -263
  201. package/dist/runtime/run-steps.d.ts +1 -2
  202. package/dist/runtime/run-steps.js +8 -11
  203. package/dist/runtime/run-worker.d.ts +26 -16
  204. package/dist/runtime/run-worker.js +132 -37
  205. package/dist/runtime/runtime.module.d.ts +2 -3
  206. package/dist/runtime/runtime.module.js +7 -6
  207. package/dist/runtime/step-log.d.ts +16 -4
  208. package/dist/runtime/step-log.js +26 -6
  209. package/dist/runtime/stream.controller.d.ts +2 -4
  210. package/dist/runtime/stream.controller.js +5 -11
  211. package/dist/runtime/subagents/child.js +1 -1
  212. package/dist/runtime/subagents/definition.d.ts +2 -1
  213. package/dist/runtime/subagents/definition.js +4 -2
  214. package/dist/runtime/subagents/deliveries.d.ts +6 -3
  215. package/dist/runtime/subagents/deliveries.js +16 -7
  216. package/dist/runtime/subagents/dispatch.d.ts +12 -12
  217. package/dist/runtime/subagents/dispatch.js +14 -38
  218. package/dist/runtime/subagents/messages.d.ts +5 -1
  219. package/dist/runtime/subagents/messages.js +11 -3
  220. package/dist/runtime/subagents/skill-fork.d.ts +3 -3
  221. package/dist/runtime/subagents/skill-fork.js +8 -5
  222. package/dist/runtime/subagents/subagents.service.js +1 -1
  223. package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
  224. package/dist/runtime/subagents/tree-jobs.js +86 -0
  225. package/dist/runtime/usage-report-jobs.d.ts +23 -48
  226. package/dist/runtime/usage-report-jobs.js +67 -119
  227. package/dist/runtime/usage-report.d.ts +28 -77
  228. package/dist/runtime/usage-report.js +35 -213
  229. package/dist/runtime/waits.d.ts +48 -198
  230. package/dist/runtime/waits.js +103 -805
  231. package/dist/sandbox/jobs.d.ts +20 -10
  232. package/dist/sandbox/jobs.js +23 -17
  233. package/dist/sandbox/sandbox.service.d.ts +17 -4
  234. package/dist/sandbox/sandbox.service.js +55 -14
  235. package/dist/schedules/calendar.d.ts +134 -0
  236. package/dist/schedules/calendar.js +410 -0
  237. package/dist/schedules/fire.d.ts +26 -7
  238. package/dist/schedules/fire.js +91 -22
  239. package/dist/schedules/job-ids.d.ts +66 -17
  240. package/dist/schedules/job-ids.js +81 -13
  241. package/dist/schedules/run-tracker.d.ts +0 -5
  242. package/dist/schedules/run-tracker.js +2 -14
  243. package/dist/schedules/scan.job.d.ts +13 -32
  244. package/dist/schedules/scan.job.js +50 -164
  245. package/dist/schedules/schedule-math.d.ts +42 -0
  246. package/dist/schedules/schedule-math.js +52 -0
  247. package/dist/schedules/scheduled-tasks.service.d.ts +22 -6
  248. package/dist/schedules/scheduled-tasks.service.js +70 -14
  249. package/dist/schedules/schedules.controller.d.ts +5 -1
  250. package/dist/schedules/schedules.controller.js +15 -1
  251. package/dist/schedules/schedules.module.js +0 -4
  252. package/dist/schedules/schedules.schemas.d.ts +35 -0
  253. package/dist/schedules/schedules.schemas.js +27 -0
  254. package/dist/schedules/store.d.ts +5 -0
  255. package/dist/schedules/store.js +20 -0
  256. package/dist/skills/changes.controller.d.ts +1 -1
  257. package/dist/skills/changes.controller.js +1 -1
  258. package/dist/tools/approvals.service.d.ts +41 -11
  259. package/dist/tools/approvals.service.js +108 -14
  260. package/dist/tools/builtin-names.d.ts +5 -3
  261. package/dist/tools/builtin-names.js +12 -4
  262. package/dist/tools/builtins/builtin-tools.d.ts +1 -2
  263. package/dist/tools/builtins/builtin-tools.js +21 -17
  264. package/dist/tools/builtins/sandbox/bash.js +9 -3
  265. package/dist/tools/builtins/sandbox/common.d.ts +18 -1
  266. package/dist/tools/builtins/sandbox/common.js +14 -1
  267. package/dist/tools/builtins/sandbox/index.d.ts +2 -1
  268. package/dist/tools/builtins/sandbox/index.js +4 -1
  269. package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
  270. package/dist/tools/builtins/sandbox/task-list.js +130 -0
  271. package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
  272. package/dist/tools/builtins/sandbox/task-output.js +21 -3
  273. package/dist/tools/builtins/web/extract.d.ts +2 -4
  274. package/dist/tools/builtins/web/extract.js +2 -5
  275. package/dist/tools/pipeline.d.ts +12 -3
  276. package/dist/tools/pipeline.js +6 -1
  277. package/dist/tools/questions.service.d.ts +30 -10
  278. package/dist/tools/questions.service.js +41 -27
  279. package/dist/tools/registry.d.ts +12 -3
  280. package/dist/tools/registry.js +13 -3
  281. package/dist/tools/tools.module.js +4 -3
  282. package/package.json +3 -3
  283. package/src/migrations/0118_device_policy_ops.sql +6 -0
  284. package/src/migrations/0119_outbox.sql +22 -0
  285. package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
  286. package/src/migrations/0121_drop_platform_migration_runs.sql +12 -0
  287. package/src/migrations/0122_drop_scheduled_task_runs_rechecked_at.sql +5 -0
  288. package/src/migrations/0123_pgvector.sql +27 -0
  289. package/src/migrations/0124_conversation_source.sql +36 -0
  290. package/dist/catalog/platform-migration.d.ts +0 -115
  291. package/dist/catalog/platform-migration.js +0 -583
  292. package/dist/infra/queue/add-job-once.d.ts +0 -14
  293. package/dist/infra/queue/add-job-once.js +0 -16
@@ -9,9 +9,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
9
9
  };
10
10
  // Taking out the extension of a removed org-owned plugin (plugin scope phase 3, spec §14, P3-20,
11
11
  // P3-21; pre-flight F9, F10): the one-off job `owned-plugin-cleanup-<itemId>` on
12
- // `cap-kernel-maintenance` (dispatched by `MaintenanceProcessor`) and its daily sweep. Worker-only:
13
- // `OwnedPluginCleanupModule` is imported only by `MaintenanceModule`, which only `WorkerModule`
14
- // imports.
12
+ // `cap-kernel-maintenance` (dispatched by `MaintenanceProcessor`), owed in the outbox by the
13
+ // removal's transaction (transactional outbox spec §8.1). Worker-only: `OwnedPluginCleanupModule`
14
+ // is imported only by `MaintenanceModule`, which only `WorkerModule` imports.
15
15
  import { Inject, Injectable, Module } from "@nestjs/common";
16
16
  import { ApiError } from "../errors.js";
17
17
  import { ExtensionAdminOps } from "../extensions/admin-ops.js";
@@ -19,11 +19,8 @@ import { ExtensionsModule } from "../extensions/extensions.module.js";
19
19
  import { KernelDb } from "../infra/database/kernel-db.js";
20
20
  import { TransactionHost } from "../infra/database/transaction-host.js";
21
21
  import { Transactional } from "../infra/database/transactional.decorator.js";
22
- import { LockService } from "../infra/lock/lock.service.js";
23
- import { LockedCron } from "../infra/schedule/locked-cron.decorator.js";
24
22
  import { KERNEL_LOGGER } from "../infra/tokens.js";
25
23
  import { CatalogImportModule } from "./catalog.module.js";
26
- import { OWNED_PLUGIN_CLEANUP_SWEEP_JOB } from "./job-ids.js";
27
24
  import { CatalogItemLock } from "./locks.js";
28
25
  import { releaseExtensionClaim } from "./ownership.js";
29
26
  /** Codes that mean another run (or the confirmation's own take-out) got there first. */
@@ -31,27 +28,24 @@ const GONE = new Set(["extension.not_found", "extension.not_disabled"]);
31
28
  /**
32
29
  * The cleanup of a removed org-owned plugin: {@link run} disables and uninstalls its extension (an
33
30
  * install of the item's name from the item's package) when no live catalog item uses it any more
34
- * ({@link OwnedPluginCleanup.referenced}), then releases the extension name claim, in one transaction under the import's item name lock
35
- * (pre-flight F10: the claim of an
36
- * installed extension is released here, never at the removal). Idempotent: a live item (a
37
- * transferred one), a platform item or nothing installed changes nothing but the claim. The
38
- * extension's data, secrets and configs stay, as with every uninstall. {@link sweep} runs it daily
39
- * for every removed org-owned item whose extension is still installed (a lost enqueue).
31
+ * ({@link OwnedPluginCleanup.referenced}), then releases the extension name claim, in one
32
+ * transaction under the import's item name lock (pre-flight F10: the claim of an installed
33
+ * extension is released here, never at the removal). Idempotent: a live item (a transferred one),
34
+ * a platform item or nothing installed changes nothing but the claim. The extension's data,
35
+ * secrets and configs stay, as with every uninstall.
40
36
  */
41
37
  let OwnedPluginCleanup = class OwnedPluginCleanup {
42
38
  kdb;
43
39
  ops;
44
40
  itemLock;
45
- lockService;
46
41
  log;
47
42
  txHost;
48
43
  constructor(kdb, ops,
49
44
  /** The import's item name lock (M5: no uninstall racing a re-import of the package). */
50
- itemLock, lockService, log, txHost) {
45
+ itemLock, log, txHost) {
51
46
  this.kdb = kdb;
52
47
  this.ops = ops;
53
48
  this.itemLock = itemLock;
54
- this.lockService = lockService;
55
49
  this.log = log;
56
50
  this.txHost = txHost;
57
51
  }
@@ -100,50 +94,6 @@ let OwnedPluginCleanup = class OwnedPluginCleanup {
100
94
  }
101
95
  await releaseExtensionClaim(this.db, name, pkg);
102
96
  }
103
- /**
104
- * Daily: {@link run} for every removed org-owned item no live item {@link referenced} names
105
- * whose extension is still installed, or whose name claim is still held (a lost enqueue, or a
106
- * run that uninstalled and failed before releasing the claim).
107
- */
108
- async sweep() {
109
- const rows = await this.db
110
- .selectFrom("catalog_items as ci")
111
- .select("ci.id")
112
- .where("ci.deleted_at", "is not", null)
113
- .where("ci.owner_org_id", "is not", null)
114
- .where("ci.package_name", "is not", null)
115
- .where(({ and, or, not, exists, selectFrom }) => and([
116
- not(exists(selectFrom("catalog_items as live")
117
- .select("live.id")
118
- .whereRef("live.name", "=", "ci.name")
119
- .whereRef("live.package_name", "=", "ci.package_name")
120
- .where("live.deleted_at", "is", null)
121
- .where((eb) => eb.or([
122
- eb("live.owner_org_id", "is", null),
123
- eb("live.owner_org_id", "=", eb.ref("ci.owner_org_id")),
124
- ])))),
125
- or([
126
- exists(selectFrom("extension_installs as x")
127
- .innerJoin("extension_packages as p", "p.sha256", "x.sha256")
128
- .select("x.name")
129
- .whereRef("x.name", "=", "ci.name")
130
- .whereRef("p.package_name", "=", "ci.package_name")),
131
- exists(selectFrom("extension_name_owners as o")
132
- .select("o.name")
133
- .whereRef("o.name", "=", "ci.name")
134
- .whereRef("o.package_name", "=", "ci.package_name")),
135
- ]),
136
- ]))
137
- .execute();
138
- for (const r of rows) {
139
- try {
140
- await this.run(r.id);
141
- }
142
- catch (err) {
143
- this.log.error("owned plugin cleanup failed", { itemId: r.id, err });
144
- }
145
- }
146
- }
147
97
  /**
148
98
  * A live catalog item still uses the extension: one named like it (a plugin and its extension
149
99
  * share one name) from the same package whose owner is the removed item's owner (a re-upload)
@@ -165,22 +115,18 @@ let OwnedPluginCleanup = class OwnedPluginCleanup {
165
115
  __decorate([
166
116
  Transactional()
167
117
  ], OwnedPluginCleanup.prototype, "takeOut", null);
168
- __decorate([
169
- LockedCron("40 3 * * *", { name: OWNED_PLUGIN_CLEANUP_SWEEP_JOB })
170
- ], OwnedPluginCleanup.prototype, "sweep", null);
171
118
  OwnedPluginCleanup = __decorate([
172
119
  Injectable(),
173
120
  __param(0, Inject(KernelDb)),
174
121
  __param(1, Inject(ExtensionAdminOps)),
175
122
  __param(2, Inject(CatalogItemLock)),
176
- __param(3, Inject(LockService)),
177
- __param(4, Inject(KERNEL_LOGGER)),
178
- __param(5, Inject(TransactionHost))
123
+ __param(3, Inject(KERNEL_LOGGER)),
124
+ __param(4, Inject(TransactionHost))
179
125
  ], OwnedPluginCleanup);
180
126
  export { OwnedPluginCleanup };
181
127
  /**
182
128
  * {@link OwnedPluginCleanup}: imported only by `MaintenanceModule` (the job's dispatcher), which
183
- * only the worker role imports, so the sweep runs on worker replicas only.
129
+ * only the worker role imports.
184
130
  */
185
131
  let OwnedPluginCleanupModule = class OwnedPluginCleanupModule {
186
132
  };
@@ -1,4 +1,4 @@
1
- import { type AgentTemplate, type ConnectorTemplateFile, type ParsedTheme } from "@capybara-hq/plugin-sdk";
1
+ import { type AgentTemplate, type ConnectorTemplateFile, type ParsedTheme, type PluginManifest } from "@capybara-hq/plugin-sdk";
2
2
  import type { SkillManifest, SourceFormat } from "../db/kernel-schema.js";
3
3
  import { KernelDb } from "../infra/database/kernel-db.js";
4
4
  import { TransactionHost } from "../infra/database/transaction-host.js";
@@ -26,7 +26,7 @@ export interface ChangedConnectorTemplateRef {
26
26
  from: string | null;
27
27
  to: string;
28
28
  }
29
- /** What {@link PlatformComponents.syncFromVersion} changed (unchanged components are not listed). */
29
+ /** What {@link PlatformComponents.applySyncIn} changed (unchanged components are not listed). */
30
30
  export interface PlatformSyncResult {
31
31
  skills: ChangedRef[];
32
32
  agentTemplates: ChangedRef[];
@@ -37,11 +37,6 @@ export interface PlatformSyncResult {
37
37
  export declare const platformSkillPrefix: (id: string, version: number) => string;
38
38
  /** The prefix (in `deployment/`) of a platform agent template version's file. */
39
39
  export declare const platformAgentTemplatePrefix: (id: string, version: number) => string;
40
- /**
41
- * The prefix (in `deployment/`) of a platform theme's files (themes spec §6); a version's fonts
42
- * and logo are under `<prefix><version>-<catalog version>/` ({@link syncVersionPrefix}).
43
- */
44
- export declare const platformThemePrefix: (id: string) => string;
45
40
  /**
46
41
  * A fresh prefix (in `deployment/`) for a version written before its transaction (ruling P3-45):
47
42
  * `<id>/<version>-<uuid>/`, so two writers racing for one version number never overwrite each
@@ -49,12 +44,20 @@ export declare const platformThemePrefix: (id: string) => string;
49
44
  */
50
45
  export declare const uniqueVersionPrefix: (base: string) => string;
51
46
  /**
52
- * The prefix of a version a plugin sync writes: `<id>/<version>-<catalog version>/` (the catalog
53
- * version made key-safe), so syncs of two catalog versions racing for one number never overwrite
54
- * each other. Stored on the version row; readers use the stored prefix, so rows written before keep
47
+ * The prefix (in `deployment/`) of the files a plugin sync writes for a component version:
48
+ * `platform/<kind>/sha256-<digest>/`, the digest of the files' paths and contents
49
+ * ({@link skillFilesDigest}). The files are copied before the transaction that writes the rows (no
50
+ * storage call holds a row lock), so the same content always lands on the same keys: a sync or an
51
+ * import that is retried after its transaction rolled back writes nothing new, and versions with
52
+ * the same content share their objects. Objects are immutable and nothing deletes them (versions
53
+ * are kept), so an import that rolled back leaves at most objects a later import of that content
54
+ * reuses. Stored on the version row; readers use the stored prefix, so rows written before keep
55
55
  * theirs.
56
56
  */
57
- export declare const syncVersionPrefix: (base: string, catalogVersion: string) => string;
57
+ export declare const contentPrefix: (kind: "skills" | "agent-templates" | "themes", files: {
58
+ path: string;
59
+ sha256: string;
60
+ }[]) => string;
58
61
  /** The live component a plan was made against (absent: the plan creates it). */
59
62
  interface Base<V> {
60
63
  id: string;
@@ -112,12 +115,32 @@ export interface SyncPlan {
112
115
  export declare class PlanStale extends Error {
113
116
  }
114
117
  /**
115
- * A sync planned and its files copied ({@link PlatformComponents.prepareSync}), waiting for its rows
116
- * ({@link PlatformComponents.applySyncIn}). Opaque outside this module.
118
+ * A sync planned and its files copied ({@link PlatformComponents.prepareSync},
119
+ * {@link PlatformComponents.prepareImport}), waiting for its rows
120
+ * ({@link PlatformComponents.applySyncIn}). Opaque outside this module but for the item and the
121
+ * catalog version it was planned for.
117
122
  */
118
123
  export interface PreparedSync {
119
124
  readonly plan: SyncPlan;
120
125
  }
126
+ /**
127
+ * The catalog version a sync plans from: its row, or a staged import whose row its transaction
128
+ * is about to write (the files are in object storage under `objectPrefix` already).
129
+ */
130
+ export interface SyncSource {
131
+ itemId: string;
132
+ /** The plugin (the catalog item's name). */
133
+ plugin: string;
134
+ version: string;
135
+ manifest: PluginManifest;
136
+ objectPrefix: string | null;
137
+ files: {
138
+ path: string;
139
+ size: number;
140
+ sha256: string;
141
+ }[];
142
+ sourceFormat: SourceFormat;
143
+ }
121
144
  /** A component version written by an upload ({@link PlatformComponents.uploadSkillVersion}). */
122
145
  export interface UploadedComponentVersion {
123
146
  kind: "skill" | "agent_template";
@@ -145,8 +168,9 @@ export interface UploadActor {
145
168
  auditDetail?: Record<string, unknown>;
146
169
  }
147
170
  /**
148
- * Writes the platform rows of a catalog version's components. Called by the import confirm that
149
- * creates a catalog item (`initial`), and by the platform plugin update for a new version.
171
+ * Writes the platform rows of a catalog version's components, in the transaction of the import
172
+ * confirm that makes an item's first usable version, of the super admin's confirmation of an org
173
+ * upload's first version, and of the platform plugin update to a new version.
150
174
  */
151
175
  export declare class PlatformComponents {
152
176
  private readonly kdb;
@@ -160,26 +184,19 @@ export declare class PlatformComponents {
160
184
  /** CLI only (see `PluginImport.useCliStorage`): files go to the object store the CLI set up. */
161
185
  useCliStorage(storage: PrefixedStorage): void;
162
186
  /**
163
- * Creates or updates the platform rows of every component of catalog version `version` of item
164
- * `itemId`: a component is matched by plugin and name (connector templates by item and template
165
- * id) and gets a new version only when its content changed (skills by their files' digest,
166
- * templates by canonical JSON); new rows follow the plugin's scope (`scope_mode: follow`).
167
- * Files are copied from the catalog prefix to `deployment/platform/…` before the rows are
168
- * written (outside the transaction), so a sync that stops midway leaves at most unreferenced
169
- * files, and running it again is a no-op once it succeeded. `initial` is the confirm that
170
- * created the item. Components missing from the version are left alone (the platform update
171
- * decides what a removal means). On success the item records `version` as
172
- * `platform_synced_version`.
187
+ * The first phase of a sync inside a caller's transaction (the platform plugin update, the super
188
+ * admin's confirmation of an org upload's first version: `confirming`, the item still awaiting
189
+ * it): plans the version's components and copies their files, outside any transaction (no
190
+ * storage call holds a row lock). {@link applySyncIn} writes the rows.
173
191
  */
174
- syncFromVersion(itemId: string, version: string, opts: {
175
- initial: boolean;
176
- }): Promise<PlatformSyncResult>;
192
+ prepareSync(itemId: string, version: string, opts?: {
193
+ confirming?: boolean;
194
+ }): Promise<PreparedSync>;
177
195
  /**
178
- * The first phase of a sync inside a caller's transaction (the platform plugin update): plans the
179
- * version's components and copies their files, outside any transaction (no storage call holds a
180
- * row lock). {@link applySyncIn} writes the rows.
196
+ * {@link prepareSync} for an import whose transaction writes the catalog version (the item may
197
+ * not exist yet): plans from the staged content and copies the files, before that transaction.
181
198
  */
182
- prepareSync(itemId: string, version: string): Promise<PreparedSync>;
199
+ prepareImport(source: SyncSource): Promise<PreparedSync>;
183
200
  /**
184
201
  * The second phase: writes the prepared rows in the caller's transaction and records
185
202
  * `platform_synced_version`. A component changed since the plan -> {@link PlanStale} (the caller
@@ -226,11 +243,16 @@ export declare class PlatformComponents {
226
243
  private writeTemplateVersionIn;
227
244
  /**
228
245
  * Records that the item's platform components are written from `version`
229
- * (`catalog_items.platform_synced_version`): the migration job syncs only items without it.
246
+ * (`catalog_items.platform_synced_version`, the version orgs install).
230
247
  */
231
248
  private markSynced;
249
+ /**
250
+ * The stored catalog version `version` of live item `itemId`. An org upload still waiting for the
251
+ * super admin has no platform components (P3-9) unless this is its `confirming`.
252
+ */
253
+ private source;
232
254
  /** Reads the version's components and the live platform rows; keeps only what changed. */
233
- private plan;
255
+ private planFrom;
234
256
  /** Copies the planned versions' files to their platform prefixes. */
235
257
  private writeFiles;
236
258
  /**
@@ -9,8 +9,10 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
9
9
  };
10
10
  // Platform components (plugin scope phase 2, rulings A2 and C2): the skills, agent templates,
11
11
  // connector templates and themes of a catalog item, stored once for the deployment. Files live
12
- // under `deployment/platform/{skills,agent-templates,themes}/<id>/<version>…/`, never under an org
13
- // prefix (orgs are purged by prefix).
12
+ // under `deployment/platform/{skills,agent-templates,themes}/…/`, never under an org prefix (orgs
13
+ // are purged by prefix): a plugin sync's under the digest of their content
14
+ // (`sha256-<digest>/`, {@link contentPrefix}), an upload's or a promotion's under
15
+ // `<id>/<version>-<uuid>/`.
14
16
  import { createHash, randomUUID } from "node:crypto";
15
17
  import { parseAgentTemplate, } from "@capybara-hq/plugin-sdk";
16
18
  import { Inject, Injectable } from "@nestjs/common";
@@ -32,11 +34,6 @@ import { assertNotAwaiting } from "./ownership.js";
32
34
  export const platformSkillPrefix = (id, version) => `platform/skills/${id}/${version}/`;
33
35
  /** The prefix (in `deployment/`) of a platform agent template version's file. */
34
36
  export const platformAgentTemplatePrefix = (id, version) => `platform/agent-templates/${id}/${version}/`;
35
- /**
36
- * The prefix (in `deployment/`) of a platform theme's files (themes spec §6); a version's fonts
37
- * and logo are under `<prefix><version>-<catalog version>/` ({@link syncVersionPrefix}).
38
- */
39
- export const platformThemePrefix = (id) => `platform/themes/${id}/`;
40
37
  /**
41
38
  * A fresh prefix (in `deployment/`) for a version written before its transaction (ruling P3-45):
42
39
  * `<id>/<version>-<uuid>/`, so two writers racing for one version number never overwrite each
@@ -44,22 +41,26 @@ export const platformThemePrefix = (id) => `platform/themes/${id}/`;
44
41
  */
45
42
  export const uniqueVersionPrefix = (base) => `${base.slice(0, -1)}-${randomUUID()}/`;
46
43
  /**
47
- * The prefix of a version a plugin sync writes: `<id>/<version>-<catalog version>/` (the catalog
48
- * version made key-safe), so syncs of two catalog versions racing for one number never overwrite
49
- * each other. Stored on the version row; readers use the stored prefix, so rows written before keep
44
+ * The prefix (in `deployment/`) of the files a plugin sync writes for a component version:
45
+ * `platform/<kind>/sha256-<digest>/`, the digest of the files' paths and contents
46
+ * ({@link skillFilesDigest}). The files are copied before the transaction that writes the rows (no
47
+ * storage call holds a row lock), so the same content always lands on the same keys: a sync or an
48
+ * import that is retried after its transaction rolled back writes nothing new, and versions with
49
+ * the same content share their objects. Objects are immutable and nothing deletes them (versions
50
+ * are kept), so an import that rolled back leaves at most objects a later import of that content
51
+ * reuses. Stored on the version row; readers use the stored prefix, so rows written before keep
50
52
  * theirs.
51
53
  */
52
- export const syncVersionPrefix = (base, catalogVersion) => `${base.slice(0, -1)}-${catalogVersion.replace(/[^0-9A-Za-z.-]/g, "_")}/`;
54
+ export const contentPrefix = (kind, files) => `platform/${kind}/sha256-${skillFilesDigest(files)}/`;
53
55
  /** 409 `catalog.not_owned`: an org's own promoted item is versioned by its owner only (P3-48). */
54
56
  const ownedByOrg = (what, name) => new ApiError("catalog.not_owned", `The ${what} ${name} belongs to an organization that shared it: only that organization uploads its versions`);
55
57
  /** A component changed between the plan and its write (a concurrent sync): plan again. */
56
58
  export class PlanStale extends Error {
57
59
  }
58
- /** Plans are retried this many times against concurrent syncs of the same item. */
59
- const SYNC_ATTEMPTS = 3;
60
60
  /**
61
- * Writes the platform rows of a catalog version's components. Called by the import confirm that
62
- * creates a catalog item (`initial`), and by the platform plugin update for a new version.
61
+ * Writes the platform rows of a catalog version's components, in the transaction of the import
62
+ * confirm that makes an item's first usable version, of the super admin's confirmation of an org
63
+ * upload's first version, and of the platform plugin update to a new version.
63
64
  */
64
65
  let PlatformComponents = class PlatformComponents {
65
66
  kdb;
@@ -82,56 +83,30 @@ let PlatformComponents = class PlatformComponents {
82
83
  useCliStorage(storage) {
83
84
  this.files = storage;
84
85
  }
86
+ // A plugin sync matches a component by plugin and name (connector templates by item and template
87
+ // id) and gives it a new version only when its content changed (skills by their files' digest,
88
+ // templates by canonical JSON); new rows follow the plugin's scope (`scope_mode: follow`).
89
+ // Components missing from the version are left alone (the platform update decides what a removal
90
+ // means). It runs in two phases: {@link prepareImport} / {@link prepareSync} plan and copy the
91
+ // files (keyed by content, {@link contentPrefix}) before the caller's transaction, and
92
+ // {@link applySyncIn} writes the rows and `platform_synced_version` in it.
85
93
  /**
86
- * Creates or updates the platform rows of every component of catalog version `version` of item
87
- * `itemId`: a component is matched by plugin and name (connector templates by item and template
88
- * id) and gets a new version only when its content changed (skills by their files' digest,
89
- * templates by canonical JSON); new rows follow the plugin's scope (`scope_mode: follow`).
90
- * Files are copied from the catalog prefix to `deployment/platform/…` before the rows are
91
- * written (outside the transaction), so a sync that stops midway leaves at most unreferenced
92
- * files, and running it again is a no-op once it succeeded. `initial` is the confirm that
93
- * created the item. Components missing from the version are left alone (the platform update
94
- * decides what a removal means). On success the item records `version` as
95
- * `platform_synced_version`.
94
+ * The first phase of a sync inside a caller's transaction (the platform plugin update, the super
95
+ * admin's confirmation of an org upload's first version: `confirming`, the item still awaiting
96
+ * it): plans the version's components and copies their files, outside any transaction (no
97
+ * storage call holds a row lock). {@link applySyncIn} writes the rows.
96
98
  */
97
- async syncFromVersion(itemId, version, opts) {
98
- for (let attempt = 1;; attempt++) {
99
- const plan = await this.plan(itemId, version);
100
- if (plan.skills.length === 0 &&
101
- plan.agentTemplates.length === 0 &&
102
- plan.connectorTemplates.length === 0 &&
103
- plan.themes.length === 0) {
104
- await this.markSynced(itemId, version);
105
- return { skills: [], agentTemplates: [], connectorTemplates: [], themes: [] };
106
- }
107
- await this.writeFiles(plan);
108
- try {
109
- const r = await this.apply(plan);
110
- await this.markSynced(itemId, version);
111
- this.log.info("platform components synced", {
112
- itemId,
113
- version,
114
- initial: opts.initial,
115
- skills: r.skills.length,
116
- agentTemplates: r.agentTemplates.length,
117
- connectorTemplates: r.connectorTemplates.length,
118
- themes: r.themes.length,
119
- });
120
- return r;
121
- }
122
- catch (e) {
123
- if (!(e instanceof PlanStale) || attempt >= SYNC_ATTEMPTS)
124
- throw e;
125
- }
126
- }
99
+ async prepareSync(itemId, version, opts = {}) {
100
+ const plan = await this.planFrom(await this.source(itemId, version, opts.confirming === true));
101
+ await this.writeFiles(plan);
102
+ return { plan };
127
103
  }
128
104
  /**
129
- * The first phase of a sync inside a caller's transaction (the platform plugin update): plans the
130
- * version's components and copies their files, outside any transaction (no storage call holds a
131
- * row lock). {@link applySyncIn} writes the rows.
105
+ * {@link prepareSync} for an import whose transaction writes the catalog version (the item may
106
+ * not exist yet): plans from the staged content and copies the files, before that transaction.
132
107
  */
133
- async prepareSync(itemId, version) {
134
- const plan = await this.plan(itemId, version);
108
+ async prepareImport(source) {
109
+ const plan = await this.planFrom(source);
135
110
  await this.writeFiles(plan);
136
111
  return { plan };
137
112
  }
@@ -411,7 +386,7 @@ let PlatformComponents = class PlatformComponents {
411
386
  }
412
387
  /**
413
388
  * Records that the item's platform components are written from `version`
414
- * (`catalog_items.platform_synced_version`): the migration job syncs only items without it.
389
+ * (`catalog_items.platform_synced_version`, the version orgs install).
415
390
  */
416
391
  async markSynced(itemId, version) {
417
392
  await this.db
@@ -420,16 +395,18 @@ let PlatformComponents = class PlatformComponents {
420
395
  .where("id", "=", itemId)
421
396
  .execute();
422
397
  }
423
- /** Reads the version's components and the live platform rows; keeps only what changed. */
424
- async plan(itemId, version) {
398
+ /**
399
+ * The stored catalog version `version` of live item `itemId`. An org upload still waiting for the
400
+ * super admin has no platform components (P3-9) unless this is its `confirming`.
401
+ */
402
+ async source(itemId, version, confirming) {
425
403
  const item = await this.db
426
404
  .selectFrom("catalog_items")
427
405
  .select(["name", "awaiting_confirmation"])
428
406
  .where("id", "=", itemId)
429
407
  .where("deleted_at", "is", null)
430
408
  .executeTakeFirst();
431
- // An org upload still waiting for the super admin has no platform components (P3-9)
432
- if (item !== undefined)
409
+ if (item !== undefined && !confirming)
433
410
  assertNotAwaiting(item);
434
411
  const row = item
435
412
  ? await this.db
@@ -442,21 +419,36 @@ let PlatformComponents = class PlatformComponents {
442
419
  if (!item || !row) {
443
420
  throw new ApiError("catalog.item_not_found", `Catalog item ${itemId}@${version} not found`);
444
421
  }
445
- const plugin = item.name;
446
- const manifest = row.manifest;
447
- const v = row;
422
+ return {
423
+ itemId,
424
+ plugin: item.name,
425
+ version,
426
+ manifest: row.manifest,
427
+ objectPrefix: row.object_prefix,
428
+ files: row.files,
429
+ sourceFormat: row.source_format,
430
+ };
431
+ }
432
+ /** Reads the version's components and the live platform rows; keeps only what changed. */
433
+ async planFrom(src) {
434
+ const { itemId, plugin, version, manifest } = src;
435
+ const v = {
436
+ manifest,
437
+ object_prefix: src.objectPrefix,
438
+ files: src.files,
439
+ };
448
440
  const plan = {
449
441
  itemId,
450
442
  plugin,
451
443
  version,
452
- sourceFormat: row.source_format,
444
+ sourceFormat: src.sourceFormat,
453
445
  skills: [],
454
446
  agentTemplates: [],
455
447
  connectorTemplates: [],
456
448
  themes: [],
457
449
  };
458
450
  for (const s of manifest.skills ?? []) {
459
- const files = await readCatalogFiles(this.files, row.object_prefix, row.files, packagePath(s.path));
451
+ const files = await readCatalogFiles(this.files, v.object_prefix, v.files, packagePath(s.path));
460
452
  const pkg = { ...skillOf(files), files };
461
453
  const live = await this.db
462
454
  .selectFrom("platform_skills as p")
@@ -475,8 +467,7 @@ let PlatformComponents = class PlatformComponents {
475
467
  base: live && { id: live.id, version: live.current_version },
476
468
  id,
477
469
  to,
478
- // the catalog version in the prefix: two syncs of different versions never write one key
479
- prefix: syncVersionPrefix(platformSkillPrefix(id, to), version),
470
+ prefix: contentPrefix("skills", files),
480
471
  files,
481
472
  manifest: skillManifest(pkg),
482
473
  });
@@ -495,18 +486,19 @@ let PlatformComponents = class PlatformComponents {
495
486
  .executeTakeFirst();
496
487
  if (live && canonicalJson(live.definition) === canonicalJson(a.template))
497
488
  continue;
498
- const [file] = await readCatalogFiles(this.files, row.object_prefix, row.files.filter((f) => f.path === a.path));
489
+ const [file] = await readCatalogFiles(this.files, v.object_prefix, v.files.filter((f) => f.path === a.path));
499
490
  if (!file)
500
491
  throw new ApiError("internal", `Stored agent template ${a.path} is missing`);
501
492
  const id = live?.id ?? randomUUID();
502
493
  const to = (live?.current_version ?? 0) + 1;
494
+ const name = file.path.split("/").pop();
503
495
  plan.agentTemplates.push({
504
496
  name: a.template.name,
505
497
  base: live && { id: live.id, version: live.current_version },
506
498
  id,
507
499
  to,
508
- prefix: syncVersionPrefix(platformAgentTemplatePrefix(id, to), version),
509
- file: { ...file, path: file.path.split("/").pop() },
500
+ prefix: contentPrefix("agent-templates", [{ path: name, sha256: file.sha256 }]),
501
+ file: { ...file, path: name },
510
502
  template: a.template,
511
503
  });
512
504
  }
@@ -554,9 +546,7 @@ let PlatformComponents = class PlatformComponents {
554
546
  base: live && { id: live.id, version: live.current_version },
555
547
  id,
556
548
  to,
557
- prefix: t.assets.length > 0
558
- ? syncVersionPrefix(`${platformThemePrefix(id)}${to}/`, version)
559
- : null,
549
+ prefix: t.assets.length > 0 ? contentPrefix("themes", t.assets) : null,
560
550
  files: t.assets,
561
551
  theme: t.theme,
562
552
  });
@@ -0,0 +1,50 @@
1
+ import type { KernelLogger } from "../log.js";
2
+ import type { ActorOpts, CatalogItemView } from "./catalog.service.js";
3
+ import { PluginImport } from "./plugin-import.js";
4
+ import { PlatformPluginUpdater, type PlatformUpdatePreview, type PlatformUpdateResult } from "./plugin-upgrade.js";
5
+ /** `POST /api/v1/admin/catalog/imports/:stagingId/update`: the import and the update it applied. */
6
+ export interface PlatformImportUpdateResult {
7
+ item: CatalogItemView;
8
+ update: PlatformUpdateResult;
9
+ }
10
+ /**
11
+ * The platform's update of an installed plugin to a version staged for import (the one wizard of
12
+ * the admin plugin pages, maintainer decision 2026-11-13): the import review (prepared as any
13
+ * import, `PluginImport.prepare`) and the platform update preview of the staged version
14
+ * ({@link preview}: `PlatformPluginUpdater.previewStaged`, the target read from the staging) are
15
+ * confirmed together ({@link confirm} with the review's `reviewHash` and the preview's `diffHash`).
16
+ * Nothing is written before that confirm: cancelling the wizard leaves only the staging row, which
17
+ * expires like any staged import.
18
+ *
19
+ * The confirm holds the item's update lock (`PlatformPluginUpdater.withItemLock`, one per item
20
+ * across replicas: another update -> 409 `plugin.install_in_progress`), recomputes the preview
21
+ * (another `diffHash` -> 409 `plugin.upgrade_stale`, nothing written), commits the import without
22
+ * deploying its extension (the permission snapshot is written as the review approved it), then
23
+ * runs the platform update, which moves the extension with its own rollback and writes the
24
+ * components in one transaction. When that update fails, the platform stays on its version, the
25
+ * extension where it was and its previous approval is put back; the imported version stays in the
26
+ * catalog (its 版本 tab, and 更新到 retries the update with the plain update preview): 409
27
+ * `plugin.imported_not_updated` says so, with the cause in the details. No in-process state.
28
+ */
29
+ export declare class PlatformImportUpdate {
30
+ private readonly pluginImport;
31
+ private readonly updater;
32
+ private readonly log;
33
+ constructor(pluginImport: PluginImport, updater: PlatformPluginUpdater, log: KernelLogger);
34
+ /**
35
+ * The platform update the staged version would apply (writes nothing). The staging must be a
36
+ * platform staging (else 404 `plugin.staging_not_found`) of a new version of a live
37
+ * platform-owned plugin (else 409 `plugin.upgrade_target_invalid`, reason `not_installed`); the
38
+ * updater's refusals apply as for any update preview. `needsApproval` is false: the confirm
39
+ * approves the permissions the review shows.
40
+ */
41
+ preview(stagingId: string): Promise<PlatformUpdatePreview>;
42
+ /** Confirms the import and the update together (see the class comment). */
43
+ confirm(actor: string, stagingId: string, input: {
44
+ reviewHash: string;
45
+ diffHash: string;
46
+ }, opts?: ActorOpts): Promise<PlatformImportUpdateResult>;
47
+ /** The staged target, which must be a new version of a live platform-owned plugin. */
48
+ private target;
49
+ private previewOf;
50
+ }