@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
@@ -15,18 +15,17 @@ import { ApiError } from "../errors.js";
15
15
  import { ExtensionDisplayNames } from "../extensions/display-name.js";
16
16
  import { audit } from "../identity/audit.js";
17
17
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
18
- import { afterCommit } from "../infra/database/after-commit.js";
19
18
  import { KernelDb } from "../infra/database/kernel-db.js";
20
19
  import { TransactionHost } from "../infra/database/transaction-host.js";
21
20
  import { Transactional } from "../infra/database/transactional.decorator.js";
22
21
  import { LockService } from "../infra/lock/lock.service.js";
23
- import { KERNEL_LOGGER } from "../infra/tokens.js";
22
+ import { OutboxService } from "../infra/outbox/outbox.service.js";
24
23
  import { DevicePolicyService } from "../local-devices/device-policy.service.js";
25
24
  import { deviceLeaseKey } from "../local-devices/keys.js";
26
25
  import { MachinesService } from "../local-devices/machines.js";
27
26
  import { deviceFeaturesOf, localPolicyOf } from "../local-devices/policy-summary.js";
28
27
  import { readOrgSettings } from "../orgs/settings.service.js";
29
- import { SandboxJobs } from "../sandbox/jobs.js";
28
+ import { oweDeviceDestroy, SandboxJobs } from "../sandbox/jobs.js";
30
29
  import { isInternalProvider, LOCAL_PROVIDER, SandboxProviders } from "../sandbox/providers.js";
31
30
  import { deviceNotFound, SandboxService } from "../sandbox/sandbox.service.js";
32
31
  import { effectiveSandboxPolicy, readDeploymentSandboxPolicy, } from "../sandbox/tiers.js";
@@ -43,8 +42,8 @@ const nameTaken = () => new ApiError("device.name_taken", "You already have a de
43
42
  * Personal devices (spec 2026-11-07-environments-design §4.2 items 7, 12, 13; §6; §9):
44
43
  * cloud ones on the deployment's sandbox provider and `device` ones on a connected machine; a
45
44
  * person's devices in an org, visible and usable only by their owner (anyone else gets
46
- * `device.not_found`). Deleting one soft-deletes it and destroys its instance and files in a
47
- * `sandbox-destroy-for` job after the commit.
45
+ * `device.not_found`). Deleting one soft-deletes it and owes the destruction of its instance and
46
+ * files (a `sandbox-destroy-for` job) in the same transaction.
48
47
  */
49
48
  let DevicesService = class DevicesService {
50
49
  db;
@@ -53,13 +52,15 @@ let DevicesService = class DevicesService {
53
52
  providers;
54
53
  sandbox;
55
54
  sandboxJobs;
55
+ outbox;
56
56
  access;
57
57
  displayNames;
58
- log;
59
58
  locks;
60
59
  machines;
61
60
  policies;
62
- constructor(db, txHost, config, providers, sandbox, sandboxJobs, access, displayNames, log,
61
+ constructor(db, txHost, config, providers, sandbox, sandboxJobs,
62
+ /** Owes a deleted device's destruction in the delete's transaction. */
63
+ outbox, access, displayNames,
63
64
  /** Reads the device relay's lease (`online`). */
64
65
  locks, machines, policies) {
65
66
  this.db = db;
@@ -68,9 +69,9 @@ let DevicesService = class DevicesService {
68
69
  this.providers = providers;
69
70
  this.sandbox = sandbox;
70
71
  this.sandboxJobs = sandboxJobs;
72
+ this.outbox = outbox;
71
73
  this.access = access;
72
74
  this.displayNames = displayNames;
73
- this.log = log;
74
75
  this.locks = locks;
75
76
  this.machines = machines;
76
77
  this.policies = policies;
@@ -388,9 +389,9 @@ let DevicesService = class DevicesService {
388
389
  });
389
390
  }
390
391
  /**
391
- * Deletes one of the person's live devices: soft delete, its IM default row cleared, and
392
- * after the commit a `sandbox-destroy-for` job (the worker waits for running commands, then
393
- * destroys the instance and the files). Conversations bound to it keep pointing at it; their
392
+ * Deletes one of the person's live devices: soft delete, its IM default row cleared, and a
393
+ * `sandbox-destroy-for` job owed in the same transaction (`device-destroy-<deviceId>`; the
394
+ * worker waits for running commands, then destroys the instance and the files). Conversations bound to it keep pointing at it; their
394
395
  * sandbox tools then fail with `device.not_found`. A local device's machine is
395
396
  * revoked in the same transaction; after the commit it is told `stop { reason: "deleted" }`
396
397
  * (while connected) and its connection is closed.
@@ -417,15 +418,7 @@ let DevicesService = class DevicesService {
417
418
  target: id,
418
419
  detail: { name: before.name, isDefault: before.is_default, ...auditDetail },
419
420
  });
420
- afterCommit(async () => {
421
- try {
422
- await this.sandboxJobs.destroy([id]);
423
- }
424
- catch (err) {
425
- // the hourly destruction sweep destroys deleted devices too
426
- this.log.warn("cannot schedule device destruction", { deviceId: id, err });
427
- }
428
- });
421
+ await oweDeviceDestroy(this.outbox, id, orgId);
429
422
  }
430
423
  /**
431
424
  * Disconnects the machine of one of the person's own local devices (it must sign in
@@ -1021,9 +1014,9 @@ DevicesService = __decorate([
1021
1014
  __param(3, Inject(SandboxProviders)),
1022
1015
  __param(4, Inject(SandboxService)),
1023
1016
  __param(5, Inject(SandboxJobs)),
1024
- __param(6, Inject(DeviceAccess)),
1025
- __param(7, Inject(ExtensionDisplayNames)),
1026
- __param(8, Inject(KERNEL_LOGGER)),
1017
+ __param(6, Inject(OutboxService)),
1018
+ __param(7, Inject(DeviceAccess)),
1019
+ __param(8, Inject(ExtensionDisplayNames)),
1027
1020
  __param(9, Inject(LockService)),
1028
1021
  __param(10, Inject(MachinesService)),
1029
1022
  __param(11, Inject(DevicePolicyService))
@@ -1055,7 +1048,16 @@ const tierOrNull = (v) => v === "strict" || v === "dev" || v === "open" ? v : nu
1055
1048
  function sandboxChangeOf(action, at, d, by) {
1056
1049
  const hosts = (v) => Array.isArray(v) ? v.filter((h) => typeof h === "string") : [];
1057
1050
  const isolation = d.isolation === "sandbox" || d.isolation === "none" ? d.isolation : null;
1058
- const base = { at: at.toISOString(), add: [], remove: [], tier: null, isolation: null, by };
1051
+ const base = {
1052
+ at: at.toISOString(),
1053
+ add: [],
1054
+ remove: [],
1055
+ tier: null,
1056
+ isolation: null,
1057
+ localhost: null,
1058
+ remoteGrants: null,
1059
+ by,
1060
+ };
1059
1061
  if (action === "device.tier_changed") {
1060
1062
  return { ...base, kind: "tier", tier: { to: tierOrNull(d.to) }, via: "web", confirmed: true };
1061
1063
  }
@@ -1068,9 +1070,15 @@ function sandboxChangeOf(action, at, d, by) {
1068
1070
  add: hosts(d.add),
1069
1071
  remove: hosts(d.remove),
1070
1072
  // the key is there only when the change set the tier (null: follow the org's default)
1071
- tier: "tier" in d ? { to: tierOrNull(d.tier) } : null,
1073
+ tier: "tier" in d
1074
+ ? { ...("tierFrom" in d && { from: tierOrNull(d.tierFrom) }), to: tierOrNull(d.tier) }
1075
+ : null,
1072
1076
  isolation,
1073
- via: d.via === "im" ? "im" : "web",
1077
+ localhost: d.localhost === "on" || d.localhost === "off-proxy-detected" || d.localhost === "off"
1078
+ ? d.localhost
1079
+ : null,
1080
+ remoteGrants: d.remoteGrants === "owner" || d.remoteGrants === "off" ? d.remoteGrants : null,
1081
+ via: d.via === "im" ? "im" : d.via === "device" ? "device" : "web",
1074
1082
  confirmed: d.confirmed === true,
1075
1083
  };
1076
1084
  }
package/dist/errors.d.ts CHANGED
@@ -225,10 +225,17 @@ export declare const ERROR_CODES: {
225
225
  readonly "plugin.upgrade_stale": 409;
226
226
  readonly "plugin.upgrade_target_invalid": 409;
227
227
  readonly "plugin.upgrade_failed": 502;
228
+ /**
229
+ * The platform's import and update imported the version but the update failed: the platform
230
+ * stays on its version, the imported version is in the catalog (retry with the plain update).
231
+ */
232
+ readonly "plugin.imported_not_updated": 409;
228
233
  readonly "setup.already_completed": 409;
229
234
  readonly "setup.token_invalid": 403;
230
235
  /** The admin overview's seven-day usage aggregate ran past its statement timeout (spec §5.5). */
231
236
  readonly "admin.usage_unavailable": 503;
237
+ /** No dead outbox row has this id (delivered, discarded, retried, or never dead). */
238
+ readonly "outbox.not_found": 404;
232
239
  readonly "agent.not_found": 404;
233
240
  readonly "agent.version_conflict": 409;
234
241
  /** The profile was changed since the client read it (`expectedUpdatedAt` is stale). */
@@ -319,6 +326,10 @@ export declare const ERROR_CODES: {
319
326
  readonly "attachment.too_many_pending": 429;
320
327
  readonly "sandbox.unavailable": 503;
321
328
  readonly "sandbox.busy": 409;
329
+ /** A cloud sandbox provider refused the device's tier (its config refuses open egress). */
330
+ readonly "sandbox.tier_refused": 409;
331
+ /** A cloud sandbox provider failed to create a device's sandbox for another reason. */
332
+ readonly "sandbox.create_failed": 502;
322
333
  /** A sandbox file path the kernel reads is not absolute or not under the sandbox roots. */
323
334
  readonly "sandbox.file_invalid_path": 422;
324
335
  /** No file at the sandbox path the kernel reads. */
package/dist/errors.js CHANGED
@@ -225,10 +225,17 @@ export const ERROR_CODES = {
225
225
  "plugin.upgrade_stale": 409,
226
226
  "plugin.upgrade_target_invalid": 409,
227
227
  "plugin.upgrade_failed": 502,
228
+ /**
229
+ * The platform's import and update imported the version but the update failed: the platform
230
+ * stays on its version, the imported version is in the catalog (retry with the plain update).
231
+ */
232
+ "plugin.imported_not_updated": 409,
228
233
  "setup.already_completed": 409,
229
234
  "setup.token_invalid": 403,
230
235
  /** The admin overview's seven-day usage aggregate ran past its statement timeout (spec §5.5). */
231
236
  "admin.usage_unavailable": 503,
237
+ /** No dead outbox row has this id (delivered, discarded, retried, or never dead). */
238
+ "outbox.not_found": 404,
232
239
  "agent.not_found": 404,
233
240
  "agent.version_conflict": 409,
234
241
  /** The profile was changed since the client read it (`expectedUpdatedAt` is stale). */
@@ -319,6 +326,10 @@ export const ERROR_CODES = {
319
326
  "attachment.too_many_pending": 429,
320
327
  "sandbox.unavailable": 503,
321
328
  "sandbox.busy": 409,
329
+ /** A cloud sandbox provider refused the device's tier (its config refuses open egress). */
330
+ "sandbox.tier_refused": 409,
331
+ /** A cloud sandbox provider failed to create a device's sandbox for another reason. */
332
+ "sandbox.create_failed": 502,
322
333
  /** A sandbox file path the kernel reads is not absolute or not under the sandbox roots. */
323
334
  "sandbox.file_invalid_path": 422,
324
335
  /** No file at the sandbox path the kernel reads. */
@@ -1,4 +1,4 @@
1
- import { type ContentBlock, type Logger, type ModelUsage, type StopReason } from "@capybara-hq/plugin-sdk";
1
+ import { type ContentBlock, type ConversationSource, type Logger, type ModelUsage, type StopReason } from "@capybara-hq/plugin-sdk";
2
2
  import { type ModelRef } from "../agents/definition.js";
3
3
  import { EventLog } from "../conversations/event-log.js";
4
4
  import type { KernelSchemaDb } from "../db/kernel-schema.js";
@@ -98,6 +98,8 @@ export interface ReplaySeed {
98
98
  evalRunId: string;
99
99
  orgId: string;
100
100
  agentId: string;
101
+ /** The original conversation's source: the replay offers the tools of this source. */
102
+ source: ConversationSource;
101
103
  accountId: string;
102
104
  conversationId: string;
103
105
  runId: string;
@@ -121,11 +123,20 @@ export interface ReplaySeed {
121
123
  runContext: {
122
124
  payload: unknown;
123
125
  } | undefined;
126
+ /**
127
+ * The original run's `plugin_context` events (memory spec §6.1), in log order, copied as is:
128
+ * replays never call context providers.
129
+ */
130
+ pluginContexts: {
131
+ payload: {
132
+ plugin: string;
133
+ };
134
+ }[];
124
135
  }
125
136
  /**
126
137
  * The seed of a full-run replay (C6): the `kind = 'eval'` conversation with the events before the
127
138
  * original run at their original seqs, the run row and its `run_started` (and the original
128
- * `skills_catalog`), in one transaction of its own.
139
+ * `skills_catalog`, `run_context` and `plugin_context` events), in one transaction of its own.
129
140
  */
130
141
  export declare class EvalReplaySeeder {
131
142
  private readonly db;
@@ -18,7 +18,9 @@ import { ApiError } from "../errors.js";
18
18
  import { KernelDb } from "../infra/database/kernel-db.js";
19
19
  import { TransactionHost } from "../infra/database/transaction-host.js";
20
20
  import { Transactional } from "../infra/database/transactional.decorator.js";
21
+ import { pluginContextIdemKey } from "../runtime/context/plugin-context.js";
21
22
  import { estimateTokens } from "../runtime/context/tokens.js";
23
+ import { runDeadline, tightestLimit } from "../runtime/limits.js";
22
24
  import { RunError } from "../runtime/model-call.js";
23
25
  import { runContextIdemKey } from "../runtime/run-context.service.js";
24
26
  import { recordedSkillForks } from "../runtime/subagents/skill-fork.js";
@@ -35,7 +37,7 @@ export class ReplayClaimLost extends Error {
35
37
  /**
36
38
  * The seed of a full-run replay (C6): the `kind = 'eval'` conversation with the events before the
37
39
  * original run at their original seqs, the run row and its `run_started` (and the original
38
- * `skills_catalog`), in one transaction of its own.
40
+ * `skills_catalog`, `run_context` and `plugin_context` events), in one transaction of its own.
39
41
  */
40
42
  let EvalReplaySeeder = class EvalReplaySeeder {
41
43
  db;
@@ -73,6 +75,7 @@ let EvalReplaySeeder = class EvalReplaySeeder {
73
75
  consumed_seq: p.consumed,
74
76
  kind: "eval",
75
77
  eval_run_id: evalRunId,
78
+ source: p.source,
76
79
  })
77
80
  .execute();
78
81
  for (let i = 0; i < p.seeds.length; i += SEED_BATCH) {
@@ -132,6 +135,12 @@ let EvalReplaySeeder = class EvalReplaySeeder {
132
135
  },
133
136
  ]
134
137
  : []),
138
+ ...p.pluginContexts.map((c) => ({
139
+ type: "plugin_context",
140
+ runId,
141
+ idemKey: pluginContextIdemKey(runId, c.payload.plugin),
142
+ payload: c.payload,
143
+ })),
135
144
  ]);
136
145
  if (onSeeded && !(await onSeeded(conversationId)))
137
146
  throw new ReplayClaimLost();
@@ -332,6 +341,9 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
332
341
  const trigger = replayTrigger(start.payload, seeds, consumed);
333
342
  const catalog = s.events.find((e) => e.runId === s.runId && e.type === "skills_catalog" && e.seq > R);
334
343
  const runContext = s.events.find((e) => e.runId === s.runId && e.type === "run_context" && e.seq > R);
344
+ const pluginContexts = s.events
345
+ .filter((e) => e.runId === s.runId && e.type === "plugin_context" && e.seq > R)
346
+ .map((e) => ({ payload: e.payload }));
335
347
  // a sub-agent's case (spec §15.3) runs the effective definition frozen in its subagent_started
336
348
  // (the request renders that event's preamble and instructions; its tools come from it too), with
337
349
  // only the candidate's model and params, and the logged step limit
@@ -347,12 +359,16 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
347
359
  const forkRun = triggerEvent?.type === "user_message" &&
348
360
  triggerEvent.payload.skill !== undefined &&
349
361
  triggerEvent.payload.dispatch !== undefined;
362
+ // the original conversation's source (recorded in the case); a case taken before it was
363
+ // recorded replays as its run did by default: a web conversation, or a sub-agent's for a child
364
+ const source = s.source ?? (subagent === undefined ? "web" : "subagent");
350
365
  const conversationId = randomUUID();
351
366
  const runId = randomUUID();
352
367
  await d.seeder.seed({
353
368
  evalRunId,
354
369
  orgId: s.orgId,
355
370
  agentId: s.agentId,
371
+ source,
356
372
  accountId,
357
373
  conversationId,
358
374
  runId,
@@ -364,6 +380,7 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
364
380
  model: agent.model,
365
381
  catalog,
366
382
  runContext,
383
+ pluginContexts,
367
384
  }, d.onSeeded);
368
385
  await d.hooks?.afterRunSeeded?.(evalRunId, conversationId);
369
386
  // 停止:取消 / 越限 / 熔断 / 失去认领 / 截止时间 → 中止 loop(进行中的请求立即停下,loop 以 aborted 返回)
@@ -526,16 +543,28 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
526
543
  return out;
527
544
  };
528
545
  const runtime = d.config.get().runtime;
529
- const deadline = Date.now() + runtime.maxRunSeconds * 1000;
546
+ // 0 in the config or the logged child limit = no limit there
547
+ const maxSteps = tightestLimit(subagent?.maxSteps, runtime.maxSteps);
548
+ // `runtime.maxRunSeconds` 0: no deadline and no timer
549
+ const deadline = runDeadline(Date.now(), runtime.maxRunSeconds);
530
550
  let deadlineHit = false;
531
- const timer = setTimeout(() => {
532
- deadlineHit = true;
533
- stopper.abort();
534
- }, Math.max(0, deadline - Date.now()));
535
- timer.unref();
551
+ const timer = deadline === undefined
552
+ ? undefined
553
+ : setTimeout(() => {
554
+ deadlineHit = true;
555
+ stopper.abort();
556
+ }, Math.max(0, deadline - Date.now()));
557
+ timer?.unref();
536
558
  // a fork invocation's report is the recorded one: a replay never dispatches a sub-agent (A5)
537
559
  const skillForks = recordedSkillForks(eventLog, s.events.filter((e) => e.runId === s.runId));
538
560
  const loop = d.loop({ toolPipeline: pipeline, registry, skillForks, ...(media && { media }) });
561
+ // a replay never executes a tool, so the role only completes the context
562
+ const membership = await db
563
+ .selectFrom("memberships")
564
+ .select("role")
565
+ .where("org_id", "=", s.orgId)
566
+ .where("account_id", "=", accountId)
567
+ .executeTakeFirst();
539
568
  let outcome;
540
569
  try {
541
570
  outcome = await loop.run({
@@ -544,6 +573,10 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
544
573
  runId,
545
574
  agentId: s.agentId,
546
575
  triggerAccountId: accountId,
576
+ // the seeded conversation's source (the original's): its tools are the original's
577
+ source,
578
+ ownerAccountId: accountId,
579
+ role: membership?.role ?? "guest",
547
580
  agent,
548
581
  agentVersion: candidate.agentVersion,
549
582
  signal: loopSignal,
@@ -551,8 +584,8 @@ export async function replayRun(d, s, candidate, evalRunId, signal) {
551
584
  sink: () => { },
552
585
  pendingAbsorbable,
553
586
  limits: {
554
- maxSteps: subagent === undefined ? runtime.maxSteps : Math.min(subagent.maxSteps, runtime.maxSteps),
555
- deadline,
587
+ ...(maxSteps !== undefined && { maxSteps }),
588
+ ...(deadline !== undefined && { deadline }),
556
589
  },
557
590
  // replays never fire plugin hooks (the loop deps omit them too, P-18)
558
591
  conversationKind: "eval",
@@ -1,4 +1,4 @@
1
- import type { ToolSpec } from "@capybara-hq/plugin-sdk";
1
+ import type { ConversationSource, ToolSpec } from "@capybara-hq/plugin-sdk";
2
2
  import { type AgentDefinition } from "../agents/definition.js";
3
3
  import type { ConversationEvent, ConversationEventType } from "../conversations/events.js";
4
4
  import type { KernelSchemaDb } from "../db/kernel-schema.js";
@@ -21,6 +21,12 @@ export interface CaseSnapshot {
21
21
  runId: string;
22
22
  agentId: string;
23
23
  agentVersion: number;
24
+ /**
25
+ * The original conversation's source (memory plugin spec §6.2): a full-run replay offers the
26
+ * tools of this source. Cases taken before it was recorded have none (replayed as `web`, or as
27
+ * `subagent` for a child case).
28
+ */
29
+ source?: ConversationSource;
24
30
  /** seq ≤ 该运行终态事件的 seq,按 seq 升序。 */
25
31
  events: SnapshotEvent[];
26
32
  /** 事件里各次运行(`run_started`)与本运行引用的 agent 版本 → 定义。 */
@@ -17,7 +17,7 @@ const PAGE = 1000;
17
17
  export async function takeSnapshot(db, orgId, conversationId, runId, maxBytes) {
18
18
  const conv = await db
19
19
  .selectFrom("conversations")
20
- .select(["agent_id", "kind"])
20
+ .select(["agent_id", "kind", "source"])
21
21
  .where("id", "=", conversationId)
22
22
  .where("org_id", "=", orgId)
23
23
  .executeTakeFirst();
@@ -126,6 +126,7 @@ export async function takeSnapshot(db, orgId, conversationId, runId, maxBytes) {
126
126
  runId,
127
127
  agentId: conv.agent_id,
128
128
  agentVersion: run.agent_version,
129
+ source: conv.source,
129
130
  events,
130
131
  definitions,
131
132
  toolSpecs,
@@ -28,6 +28,7 @@ import { SingleProviderGuard } from "./single-provider.js";
28
28
  import { ReplicaStatusStore } from "./sources.js";
29
29
  import { ExtensionStateModule } from "./state.module.js";
30
30
  import { ExtensionAvailability } from "./unavailable.js";
31
+ import { UsageSubscribersModule } from "./usage-subscribers.js";
31
32
  /**
32
33
  * The extensions domain: the extension host (it builds each `ctx` from the injected kernel
33
34
  * services), the package store and install records (the desired state the host converges to, one
@@ -48,6 +49,8 @@ ExtensionsModule = __decorate([
48
49
  ExtensionStateModule,
49
50
  // ctx.models: the embeddings broker (models domain, below the host through ExtensionStateModule)
50
51
  ModelsModule,
52
+ // the lifecycle clears the `usage.report` subscriber cache on PLUGINS_CHANGED
53
+ UsageSubscribersModule,
51
54
  ],
52
55
  providers: [
53
56
  PluginInstallLock,
@@ -1,4 +1,4 @@
1
- import { type AvailableHook, type HookHandler, type HookOptions, type HookPayloads, type Logger, type PolicyHook } from "@capybara-hq/plugin-sdk";
1
+ import { type AvailableHook, type HookHandler, type HookOptions, type HookPayloads, type LIFECYCLE_HOOKS, type Logger, type PolicyHook } from "@capybara-hq/plugin-sdk";
2
2
  import type { KernelConfig } from "../config/schema.js";
3
3
  import type { LockService } from "../infra/lock/lock.service.js";
4
4
  import { type EffectiveConfig } from "./effective-config.js";
@@ -63,7 +63,16 @@ export interface HookSource {
63
63
  readonly name: string;
64
64
  readonly hooks: readonly RegisteredHook[];
65
65
  readonly inflight: InflightTracker;
66
+ /** The instance's platform deployment config (what lifecycle hooks are called with). */
67
+ readonly config?: unknown;
66
68
  }
69
+ /** A lifecycle mount: an observe-only notice that a member, an agent or an org was removed. */
70
+ export type LifecycleHook = (typeof LIFECYCLE_HOOKS)[number];
71
+ /**
72
+ * Mounts delivered by a queue (at least once, by plugin) instead of {@link HookRegistry.run}:
73
+ * `usage.report` and the lifecycle mounts.
74
+ */
75
+ export type QueuedHook = "usage.report" | LifecycleHook;
67
76
  /** Error text that never throws itself (a hostile `message` getter or `toString`). */
68
77
  export declare function errMsg(e: unknown): string;
69
78
  /**
@@ -166,8 +175,18 @@ export declare class HookRegistry {
166
175
  plugin: string;
167
176
  handler: HookHandler<"usage.report">;
168
177
  }[];
169
- /** Runs the hooks of a mount point (see the class comment). */
170
- run<K extends Exclude<AvailableHook, "usage.report">>(mount: K, payload: HookPayloads[K], signal: AbortSignal): Promise<HookOutcome>;
178
+ /**
179
+ * Lifecycle handlers by plugin name (delivered by the lifecycle queue, `lifecycle-hooks.ts`, not
180
+ * by {@link run}). Each call runs through the instance's `inflight.run` with the plugin's platform
181
+ * deployment config, never an org's copy: cleanup goes out whether or not the org's effective
182
+ * config is valid (or the org still exists).
183
+ */
184
+ lifecycleHandlers<K extends LifecycleHook>(mount: K): {
185
+ plugin: string;
186
+ handler: HookHandler<K>;
187
+ }[];
188
+ /** Runs the hooks of a mount point (see the class comment); queue-delivered mounts excluded. */
189
+ run<K extends Exclude<AvailableHook, QueuedHook>>(mount: K, payload: HookPayloads[K], signal: AbortSignal): Promise<HookOutcome>;
171
190
  /**
172
191
  * The M-1 denial: `missing` (sorted) are enabled policy plugins that are not loaded on this replica.
173
192
  * The model-visible reason is generic; the detail and a throttled warning name the plugin for the
@@ -189,7 +189,21 @@ export class HookRegistry {
189
189
  }),
190
190
  }));
191
191
  }
192
- /** Runs the hooks of a mount point (see the class comment). */
192
+ /**
193
+ * Lifecycle handlers by plugin name (delivered by the lifecycle queue, `lifecycle-hooks.ts`, not
194
+ * by {@link run}). Each call runs through the instance's `inflight.run` with the plugin's platform
195
+ * deployment config, never an org's copy: cleanup goes out whether or not the org's effective
196
+ * config is valid (or the org still exists).
197
+ */
198
+ lifecycleHandlers(mount) {
199
+ return this.entries(mount).map(({ src, hook }) => ({
200
+ plugin: src.name,
201
+ handler: (payload, signal) => src.inflight.run(signal, async (s) => {
202
+ await hook.handler(payload, s, { config: src.config });
203
+ }),
204
+ }));
205
+ }
206
+ /** Runs the hooks of a mount point (see the class comment); queue-delivered mounts excluded. */
193
207
  async run(mount, payload, signal) {
194
208
  if (signal.aborted)
195
209
  throw signal.reason;
@@ -0,0 +1,99 @@
1
+ import type { HookPayloads } from "@capybara-hq/plugin-sdk";
2
+ import { WorkerHost } from "@nestjs/bullmq";
3
+ import type { Job, Worker } from "bullmq";
4
+ import type { KernelSchemaDb } from "../db/kernel-schema.js";
5
+ import { KernelDb } from "../infra/database/kernel-db.js";
6
+ import { TransactionHost } from "../infra/database/transaction-host.js";
7
+ import { OutboxService } from "../infra/outbox/outbox.service.js";
8
+ import type { KernelLogger } from "../log.js";
9
+ import { type LifecycleHook } from "./hooks.js";
10
+ import { ExtensionHost } from "./host.js";
11
+ /** Queue of lifecycle hook deliveries (no `:` in the name). */
12
+ export declare const LIFECYCLE_QUEUE = "cap-kernel-lifecycle";
13
+ /** The job name of every delivery (registered in `infra/outbox/registry.ts`). */
14
+ export declare const LIFECYCLE_JOB = "lifecycle";
15
+ /** One handler call's time limit. */
16
+ export declare const LIFECYCLE_HOOK_TIMEOUT_MS = 5000;
17
+ /** Job data: one mount's payload for one subscribing plugin. */
18
+ export interface LifecycleJob<K extends LifecycleHook = LifecycleHook> {
19
+ mount: K;
20
+ plugin: string;
21
+ payload: HookPayloads[K];
22
+ }
23
+ /**
24
+ * The deterministic job id of one delivery: the mount, the plugin and the payload's ids (no `:`;
25
+ * kernel ids and plugin names carry none). Removing the same member, agent or org again while the
26
+ * first delivery is still owed is the same job.
27
+ */
28
+ export declare function lifecycleJobId<K extends LifecycleHook>(mount: K, plugin: string, payload: HookPayloads[K]): string;
29
+ /**
30
+ * Plugins that subscribe to a lifecycle mount according to deployment state: the approved
31
+ * permission snapshot declares the mount in `permissions.hooks`, and that approved version is the
32
+ * one the deployment runs: an enabled install of that version, or a replica status row (not
33
+ * `unloaded`) that loaded or still serves it (an upgrade pending approval keeps serving the
34
+ * approved version; a config-declared plugin has only replica rows). A snapshot approved for
35
+ * another version than the one installed or served does not count. Org enablement does not count
36
+ * either: cleanup concerns data the plugin already holds (memory plugin spec §6.3). Sorted by name.
37
+ */
38
+ export declare function queryLifecycleSubscribers(db: KernelSchemaDb, mount: LifecycleHook): Promise<string[]>;
39
+ /**
40
+ * Durable delivery of the lifecycle hooks `org.member_removed`, `agent.deleted` and `org.deleted`
41
+ * (memory plugin spec §6.3), so extensions reliably learn to delete the data they hold:
42
+ * - **Owe** ({@link recordIn}): in the transaction that removes the member, the agent or the org,
43
+ * one outbox job per subscribing plugin ({@link queryLifecycleSubscribers}) on
44
+ * {@link LIFECYCLE_QUEUE}, under {@link lifecycleJobId}, with no `org_id` (it is the deletion's
45
+ * own cleanup work, transactional outbox spec §9); a rollback owes nothing. The outbox delivers
46
+ * it to BullMQ after the commit (registry: attempts and backoff).
47
+ * - **Deliver** ({@link process}, worker role): the plugin's handlers loaded on this replica are
48
+ * called in turn (5 s each). Not loaded on this replica -> the job fails and is retried (another
49
+ * replica or a later attempt). Loaded without a handler -> dropped with a warning. Handlers get
50
+ * the plugin's platform deployment config (`call.config`), never an org's copy, so an org whose
51
+ * effective config is not valid still gets its cleanup. The last failed attempt logs an error.
52
+ * Handlers must be idempotent (a delivery may repeat when a replica dies after the call).
53
+ */
54
+ export declare class LifecycleHooks {
55
+ private readonly kdb;
56
+ readonly txHost: TransactionHost;
57
+ private readonly outbox;
58
+ /** The loaded plugins' handlers (`hooks.handlers`) and whether a plugin is active here. */
59
+ private readonly host;
60
+ private readonly log;
61
+ constructor(kdb: KernelDb, txHost: TransactionHost, outbox: Pick<OutboxService, "add">,
62
+ /** The loaded plugins' handlers (`hooks.handlers`) and whether a plugin is active here. */
63
+ host: Pick<ExtensionHost, "hooks" | "current">, log: KernelLogger);
64
+ /**
65
+ * Owes one delivery per subscribing plugin in the caller's transaction (`mandatory`); returns
66
+ * the plugins.
67
+ */
68
+ recordIn<K extends LifecycleHook>(mount: K, payload: HookPayloads[K]): Promise<string[]>;
69
+ /** One delivery job (the consumer {@link LifecycleHooksProcessor} calls it). */
70
+ process(data: LifecycleJob, stop: AbortSignal): Promise<void>;
71
+ /** One handler call, aborted after {@link LIFECYCLE_HOOK_TIMEOUT_MS} or when the replica stops. */
72
+ private call;
73
+ /** A job failed (the worker's `failed` event): a retry warns, the last attempt logs an error. */
74
+ onFailed(j: Job<LifecycleJob> | undefined, err: Error): void;
75
+ }
76
+ /**
77
+ * The consumer of {@link LIFECYCLE_QUEUE}: {@link LifecycleHooks.process}. Worker role only
78
+ * (`LifecycleHookWorkersModule`); built with `autorun: false`, started by the worker role after the
79
+ * extensions loaded.
80
+ */
81
+ export declare class LifecycleHooksProcessor extends WorkerHost<Worker<LifecycleJob>> {
82
+ private readonly hooks;
83
+ private readonly log;
84
+ private readonly stopping;
85
+ constructor(hooks: LifecycleHooks, log: Pick<KernelLogger, "error">);
86
+ process(job: Job<LifecycleJob>): Promise<void>;
87
+ /** Starts consuming (worker role, after the extensions loaded). */
88
+ start(): void;
89
+ /** Aborts the calls in flight and closes the worker. */
90
+ close(): Promise<void>;
91
+ failed(job: Job<LifecycleJob> | undefined, err: Error): void;
92
+ error(err: Error): void;
93
+ }
94
+ /** Lifecycle hook delivery: owing the jobs, and the queue the outbox adds them to, on every role. */
95
+ export declare class LifecycleHooksModule {
96
+ }
97
+ /** The lifecycle queue's consumer; imported only by the worker role (`WorkerModule`). */
98
+ export declare class LifecycleHookWorkersModule {
99
+ }