@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
@@ -1,6 +1,7 @@
1
1
  import { OwnedItems } from "../catalog/owned-items.js";
2
2
  import { PluginScopeSync } from "../catalog/scope-sync.js";
3
3
  import { EvalBudget } from "../evals/budget.js";
4
+ import { LifecycleHooks } from "../extensions/lifecycle-hooks.js";
4
5
  import type { Account } from "../identity/accounts.js";
5
6
  import { ApiTokenService } from "../identity/api-tokens.js";
6
7
  import { SettingsService } from "../identity/settings.js";
@@ -32,17 +33,21 @@ export declare class OrgsService {
32
33
  private readonly events;
33
34
  /** Cancels the deleted org's running eval runs (in the delete's transaction). */
34
35
  private readonly evalBudget;
35
- /** A new org gets the plugins its scope offers it (the scope sync, after the commit). */
36
+ /** A new org gets the plugins its scope offers it (the scope sync, owed with the org). */
36
37
  private readonly scopeSync;
37
38
  /** What the deleted org owns is transferred or removed in the delete's transaction (P3-20). */
38
39
  private readonly ownedItems;
40
+ /** Records `org.deleted` for the subscribing plugins in the delete's transaction. */
41
+ private readonly lifecycle;
39
42
  constructor(db: KernelDb, txHost: TransactionHost, settings: SettingsService, apiTokens: ApiTokenService, orgLock: OrgLock, events: KernelEvents,
40
43
  /** Cancels the deleted org's running eval runs (in the delete's transaction). */
41
44
  evalBudget: Pick<EvalBudget, "cancelRuns">,
42
- /** A new org gets the plugins its scope offers it (the scope sync, after the commit). */
45
+ /** A new org gets the plugins its scope offers it (the scope sync, owed with the org). */
43
46
  scopeSync: Pick<PluginScopeSync, "enqueueOrg">,
44
47
  /** What the deleted org owns is transferred or removed in the delete's transaction (P3-20). */
45
- ownedItems: Pick<OwnedItems, "onOrgDeleted">);
48
+ ownedItems: Pick<OwnedItems, "onOrgDeleted">,
49
+ /** Records `org.deleted` for the subscribing plugins in the delete's transaction. */
50
+ lifecycle: Pick<LifecycleHooks, "recordIn">);
46
51
  /**
47
52
  * Creates an org with the actor as owner, in the caller's transaction when there is one (the
48
53
  * setup wizard creates it with the account); a slug conflict is `org.slug_taken` either way, but
@@ -79,8 +84,9 @@ export declare class OrgsService {
79
84
  * sessions' current org pointing at it, and transfers or removes the plugins and promoted
80
85
  * components it owns ({@link OwnedItems.onOrgDeleted}, P3-20: shared ones become the platform's,
81
86
  * the others are removed, a removed plugin's extension taken out by its cleanup job after the
82
- * commit); after the commit emits `org.deleted` (channel connections go with the org: the
83
- * runtime's connection reads filter deleted orgs).
87
+ * commit) and owes the `org.deleted` lifecycle hook deliveries (outbox jobs); after the commit
88
+ * emits `org.deleted` (channel connections go with the org: the runtime's connection reads filter
89
+ * deleted orgs).
84
90
  */
85
91
  softDelete(orgId: string, actor: Account, actorTokenId?: string): Promise<void>;
86
92
  private softDeleteIn;
@@ -15,6 +15,7 @@ import { cancelPendingRequests } from "../catalog/request-rules.js";
15
15
  import { PluginScopeSync } from "../catalog/scope-sync.js";
16
16
  import { ApiError } from "../errors.js";
17
17
  import { EvalBudget } from "../evals/budget.js";
18
+ import { LifecycleHooks } from "../extensions/lifecycle-hooks.js";
18
19
  import { ApiTokenService } from "../identity/api-tokens.js";
19
20
  import { audit } from "../identity/audit.js";
20
21
  import { SettingsService } from "../identity/settings.js";
@@ -85,13 +86,16 @@ let OrgsService = class OrgsService {
85
86
  evalBudget;
86
87
  scopeSync;
87
88
  ownedItems;
89
+ lifecycle;
88
90
  constructor(db, txHost, settings, apiTokens, orgLock, events,
89
91
  /** Cancels the deleted org's running eval runs (in the delete's transaction). */
90
92
  evalBudget,
91
- /** A new org gets the plugins its scope offers it (the scope sync, after the commit). */
93
+ /** A new org gets the plugins its scope offers it (the scope sync, owed with the org). */
92
94
  scopeSync,
93
95
  /** What the deleted org owns is transferred or removed in the delete's transaction (P3-20). */
94
- ownedItems) {
96
+ ownedItems,
97
+ /** Records `org.deleted` for the subscribing plugins in the delete's transaction. */
98
+ lifecycle) {
95
99
  this.db = db;
96
100
  this.txHost = txHost;
97
101
  this.settings = settings;
@@ -101,6 +105,7 @@ let OrgsService = class OrgsService {
101
105
  this.evalBudget = evalBudget;
102
106
  this.scopeSync = scopeSync;
103
107
  this.ownedItems = ownedItems;
108
+ this.lifecycle = lifecycle;
104
109
  }
105
110
  /**
106
111
  * Creates an org with the actor as owner, in the caller's transaction when there is one (the
@@ -137,7 +142,7 @@ let OrgsService = class OrgsService {
137
142
  target: row.id,
138
143
  detail: { slug, name },
139
144
  });
140
- afterCommit(() => this.scopeSync.enqueueOrg(row.id));
145
+ await this.scopeSync.enqueueOrg(row.id);
141
146
  return toOrg(row);
142
147
  }
143
148
  /** 账号所属的(未软删除的)组织及其角色,按创建时间升序。 */
@@ -222,8 +227,9 @@ let OrgsService = class OrgsService {
222
227
  * sessions' current org pointing at it, and transfers or removes the plugins and promoted
223
228
  * components it owns ({@link OwnedItems.onOrgDeleted}, P3-20: shared ones become the platform's,
224
229
  * the others are removed, a removed plugin's extension taken out by its cleanup job after the
225
- * commit); after the commit emits `org.deleted` (channel connections go with the org: the
226
- * runtime's connection reads filter deleted orgs).
230
+ * commit) and owes the `org.deleted` lifecycle hook deliveries (outbox jobs); after the commit
231
+ * emits `org.deleted` (channel connections go with the org: the runtime's connection reads filter
232
+ * deleted orgs).
227
233
  */
228
234
  async softDelete(orgId, actor, actorTokenId) {
229
235
  await this.softDeleteIn(orgId, actor, actorTokenId);
@@ -235,6 +241,13 @@ let OrgsService = class OrgsService {
235
241
  .set({ deleted_at: sql `now()` })
236
242
  .where("id", "=", orgId)
237
243
  .execute();
244
+ // the org's owed jobs go with it; dead letters stay for the overview, and the deletion's own
245
+ // cleanup work carries no org_id (transactional outbox spec §9)
246
+ await this.db
247
+ .deleteFrom("outbox")
248
+ .where("org_id", "=", orgId)
249
+ .where("dead_at", "is", null)
250
+ .execute();
238
251
  // after the org is marked deleted, so it counts as no user of what it shared (P3-18)
239
252
  await this.ownedItems.onOrgDeleted(orgId, actor.id, {
240
253
  ...(actorTokenId !== undefined && { actorTokenId }),
@@ -256,6 +269,8 @@ let OrgsService = class OrgsService {
256
269
  action: "org.deleted",
257
270
  target: orgId,
258
271
  });
272
+ // owed with the delete, carrying no org id, so the org's own outbox cleanup keeps them
273
+ await this.lifecycle.recordIn("org.deleted", { orgId });
259
274
  // channel connections follow the org after the root commit (none after a rollback)
260
275
  afterCommit(() => this.events.emit("org.deleted", { orgId }));
261
276
  }
@@ -279,6 +294,7 @@ OrgsService = __decorate([
279
294
  __param(5, Inject(KernelEvents)),
280
295
  __param(6, Inject(EvalBudget)),
281
296
  __param(7, Inject(PluginScopeSync)),
282
- __param(8, Inject(OwnedItems))
297
+ __param(8, Inject(OwnedItems)),
298
+ __param(9, Inject(LifecycleHooks))
283
299
  ], OrgsService);
284
300
  export { OrgsService };
@@ -1,18 +1,24 @@
1
1
  import type { NestInterceptor } from "@nestjs/common";
2
2
  import { APP_INTERCEPTOR } from "@nestjs/core";
3
3
  import { ADMIN_USAGE_TIMINGS, type AdminUsageTimings } from "./admin/usage.service.js";
4
+ import { SCOPE_BACKSTOP_DELAY } from "./catalog/scope-jobs.js";
4
5
  import { CHANNEL_WEBHOOK_TIMINGS, type ChannelWebhookTimings } from "./channels/webhook.js";
5
6
  import type { EvalReplayHooks } from "./evals/run-replay.js";
6
7
  import { EVAL_REPLAY_HOOKS } from "./evals/worker.js";
7
8
  import { BOOTSTRAP_LOCK_TTL } from "./extensions/bootstrap.js";
9
+ import { USAGE_SUBSCRIBERS_CLOCK } from "./extensions/usage-subscribers.js";
8
10
  import { FILE_PREVIEW_TIMEOUT } from "./files/previewers.js";
11
+ import { OUTBOX_DISPATCH_FAILS } from "./infra/outbox/outbox.dispatcher.js";
12
+ import { OUTBOX_FAST_PATH_SETTLED } from "./infra/outbox/outbox.module.js";
13
+ import { OUTBOX_STRICT_CONFLICTS } from "./infra/outbox/outbox.service.js";
9
14
  import { PRESENCE_INTERVAL_MS } from "./infra/presence/replica-presence.js";
15
+ import type { KernelQueueName } from "./infra/queue/queue-names.js";
10
16
  import { LIST_MODELS_TIMEOUT } from "./runtime/providers.js";
11
17
  import { RUN_CONTEXT_CLOCK } from "./runtime/run-context.service.js";
18
+ import { ENSURE_RUN_FAILS } from "./runtime/run-queue.js";
12
19
  import { AGENT_LOOP_FACTORY, type AgentLoopFactory } from "./runtime/run-steps.js";
13
20
  import { RUN_HOOKS, type RunHooks } from "./runtime/run-worker.js";
14
21
  import { SUBAGENT_MESSAGES_HOOKS, type SubagentMessagesHooks } from "./runtime/subagents/messages.js";
15
- import { USAGE_REPORT_RETRY, type UsageReportRetry } from "./runtime/usage-report.js";
16
22
  import { SANDBOX_LEASE_TIMINGS, type SandboxLeaseTimings } from "./sandbox/leases.js";
17
23
  import { SETUP_CHECK_TIMEOUT } from "./setup/setup-checks.service.js";
18
24
  import { TOOL_PIPELINE_HOOKS, type ToolPipelineHooks } from "./tools/pipeline.js";
@@ -26,13 +32,22 @@ import { EMBED_TOKEN_CLOCK } from "./ui/embed-token.js";
26
32
  * - `EVAL_REPLAY_HOOKS`: the hooks of the eval full-run replay and the judge;
27
33
  * - `TOOL_PIPELINE_HOOKS`: the tool pipeline's hooks and policy decision;
28
34
  * - `SUBAGENT_MESSAGES_HOOKS`: the sub-agent message tools' hooks (a send raced by a run's end);
29
- * - `BOOTSTRAP_LOCK_TTL`, `FILE_PREVIEW_TIMEOUT`, `LIST_MODELS_TIMEOUT`, `USAGE_REPORT_RETRY`,
35
+ * - `BOOTSTRAP_LOCK_TTL`, `FILE_PREVIEW_TIMEOUT`, `LIST_MODELS_TIMEOUT`,
30
36
  * `SANDBOX_LEASE_TIMINGS`, `CHANNEL_WEBHOOK_TIMINGS`, `SETUP_CHECK_TIMEOUT`,
31
37
  * `PRESENCE_INTERVAL_MS`: shorter timings;
32
38
  * - `ADMIN_USAGE_TIMINGS`: the usage aggregate's statement timeout and clock;
33
39
  * - `EMBED_TOKEN_CLOCK`: the clock embed tokens are issued and checked with;
34
40
  * - `RUN_CONTEXT_CLOCK`: the clock run start reads the run context's date from, and the
35
41
  * `CurrentTime` builtin the time;
42
+ * - `OUTBOX_STRICT_CONFLICTS`: a reused outbox job id with different data throws (tests) instead
43
+ * of logging an error;
44
+ * - `OUTBOX_DISPATCH_FAILS`: returns true to make the outbox dispatcher's adds to the given queue
45
+ * fail (a Redis outage);
46
+ * - `USAGE_SUBSCRIBERS_CLOCK`: the clock the `usage.report` subscriber cache ages with;
47
+ * - `OUTBOX_FAST_PATH_SETTLED`: receives each detached outbox fast-path pass (a test awaits them);
48
+ * - `ENSURE_RUN_FAILS`: returns true to make `RunQueue.ensureRun` throw (Redis unreachable, or the
49
+ * direct call after a commit skipped by a crash);
50
+ * - `SCOPE_BACKSTOP_DELAY`: the delay of a confirmation's scope sync backstop (ruling R24);
36
51
  * - `APP_INTERCEPTOR`: one more global interceptor (a probe of the matched routes).
37
52
  */
38
53
  interface KernelSeams {
@@ -44,7 +59,6 @@ interface KernelSeams {
44
59
  [BOOTSTRAP_LOCK_TTL]: number;
45
60
  [FILE_PREVIEW_TIMEOUT]: number;
46
61
  [LIST_MODELS_TIMEOUT]: number;
47
- [USAGE_REPORT_RETRY]: UsageReportRetry;
48
62
  [SANDBOX_LEASE_TIMINGS]: Partial<SandboxLeaseTimings>;
49
63
  [CHANNEL_WEBHOOK_TIMINGS]: Partial<ChannelWebhookTimings>;
50
64
  [SETUP_CHECK_TIMEOUT]: number;
@@ -52,6 +66,12 @@ interface KernelSeams {
52
66
  [ADMIN_USAGE_TIMINGS]: Partial<AdminUsageTimings>;
53
67
  [EMBED_TOKEN_CLOCK]: () => number;
54
68
  [RUN_CONTEXT_CLOCK]: () => number;
69
+ [OUTBOX_STRICT_CONFLICTS]: boolean;
70
+ [OUTBOX_DISPATCH_FAILS]: (queue: KernelQueueName) => boolean;
71
+ [USAGE_SUBSCRIBERS_CLOCK]: () => number;
72
+ [OUTBOX_FAST_PATH_SETTLED]: (pass: Promise<void>) => void;
73
+ [ENSURE_RUN_FAILS]: () => boolean;
74
+ [SCOPE_BACKSTOP_DELAY]: number;
55
75
  [APP_INTERCEPTOR]: NestInterceptor;
56
76
  }
57
77
  /**
package/dist/overrides.js CHANGED
@@ -1,16 +1,21 @@
1
1
  import { APP_INTERCEPTOR } from "@nestjs/core";
2
2
  import { ADMIN_USAGE_TIMINGS } from "./admin/usage.service.js";
3
+ import { SCOPE_BACKSTOP_DELAY } from "./catalog/scope-jobs.js";
3
4
  import { CHANNEL_WEBHOOK_TIMINGS } from "./channels/webhook.js";
4
5
  import { EVAL_REPLAY_HOOKS } from "./evals/worker.js";
5
6
  import { BOOTSTRAP_LOCK_TTL } from "./extensions/bootstrap.js";
7
+ import { USAGE_SUBSCRIBERS_CLOCK } from "./extensions/usage-subscribers.js";
6
8
  import { FILE_PREVIEW_TIMEOUT } from "./files/previewers.js";
9
+ import { OUTBOX_DISPATCH_FAILS } from "./infra/outbox/outbox.dispatcher.js";
10
+ import { OUTBOX_FAST_PATH_SETTLED } from "./infra/outbox/outbox.module.js";
11
+ import { OUTBOX_STRICT_CONFLICTS } from "./infra/outbox/outbox.service.js";
7
12
  import { PRESENCE_INTERVAL_MS } from "./infra/presence/replica-presence.js";
8
13
  import { LIST_MODELS_TIMEOUT } from "./runtime/providers.js";
9
14
  import { RUN_CONTEXT_CLOCK } from "./runtime/run-context.service.js";
15
+ import { ENSURE_RUN_FAILS } from "./runtime/run-queue.js";
10
16
  import { AGENT_LOOP_FACTORY } from "./runtime/run-steps.js";
11
17
  import { RUN_HOOKS } from "./runtime/run-worker.js";
12
18
  import { SUBAGENT_MESSAGES_HOOKS, } from "./runtime/subagents/messages.js";
13
- import { USAGE_REPORT_RETRY } from "./runtime/usage-report.js";
14
19
  import { SANDBOX_LEASE_TIMINGS } from "./sandbox/leases.js";
15
20
  import { SETUP_CHECK_TIMEOUT } from "./setup/setup-checks.service.js";
16
21
  import { TOOL_PIPELINE_HOOKS } from "./tools/pipeline.js";
@@ -24,7 +29,7 @@ const SEAM_TOKENS = [
24
29
  BOOTSTRAP_LOCK_TTL,
25
30
  FILE_PREVIEW_TIMEOUT,
26
31
  LIST_MODELS_TIMEOUT,
27
- USAGE_REPORT_RETRY,
32
+ USAGE_SUBSCRIBERS_CLOCK,
28
33
  SANDBOX_LEASE_TIMINGS,
29
34
  CHANNEL_WEBHOOK_TIMINGS,
30
35
  SETUP_CHECK_TIMEOUT,
@@ -32,6 +37,11 @@ const SEAM_TOKENS = [
32
37
  ADMIN_USAGE_TIMINGS,
33
38
  EMBED_TOKEN_CLOCK,
34
39
  RUN_CONTEXT_CLOCK,
40
+ OUTBOX_STRICT_CONFLICTS,
41
+ OUTBOX_DISPATCH_FAILS,
42
+ OUTBOX_FAST_PATH_SETTLED,
43
+ ENSURE_RUN_FAILS,
44
+ SCOPE_BACKSTOP_DELAY,
35
45
  APP_INTERCEPTOR,
36
46
  ];
37
47
  const allSeamsListed = true;
@@ -95,6 +95,11 @@ export const PLATFORM_EXCLUSIONS = [
95
95
  category: "human-only",
96
96
  reason: "Confirms an import review, an approval decision by the super admin",
97
97
  },
98
+ {
99
+ route: "POST /api/v1/admin/catalog/imports/:stagingId/update",
100
+ category: "human-only",
101
+ reason: "Confirms an import review together with the platform update it applies, an approval decision by the super admin",
102
+ },
98
103
  {
99
104
  route: "GET /api/v1/admin/catalog/items/:id/icon",
100
105
  category: "transport",
@@ -78,6 +78,22 @@ function attentionRows(a) {
78
78
  ? `Check the provider's deployment config and connection on its extension page (/admin/extensions/${p.plugin}); the models page (/admin/models) shows the list.`
79
79
  : "The provider lists no chat model that is switched on: switch one on in the admin console (/admin/models) or check the provider's config.",
80
80
  })),
81
+ ...a.outbox.map((o) => ({
82
+ kind: "outbox",
83
+ id: o.kind,
84
+ name: "Background work that could not be queued",
85
+ state: "dead",
86
+ reason: `${o.count} dead outbox row(s), the oldest dead since ${o.oldestAt}`,
87
+ next: "List them with admin.outbox-list-dead, then retry each with admin.outbox-retry or drop it with admin.outbox-discard.",
88
+ })),
89
+ ...a.queue.map((q) => ({
90
+ kind: "queue",
91
+ id: q.kind,
92
+ name: "The queue lost background jobs",
93
+ state: "lost_jobs",
94
+ reason: `${q.count} queued run job(s) were missing from the queue, the last at ${q.lastAt}; they were queued again`,
95
+ next: "Redis lost data: check its persistence (AOF or snapshots) and whether it restarted or evicted keys. Nothing to do per run; the item clears a week after the last loss.",
96
+ })),
81
97
  ],
82
98
  more: a.more,
83
99
  unavailable: a.unavailable,
@@ -127,7 +143,7 @@ let AdminOperations = class AdminOperations {
127
143
  this.registry.register([
128
144
  defineOperation({
129
145
  id: "admin.overview",
130
- description: "The admin console's dashboard numbers (super admin): orgs, accounts and attentionTotal, everything waiting for a super admin (the platform inbox total plus the extensions, plugin updates and model providers admin.attention lists); partial is true when one of those lists could not be read right now (attentionTotal then leaves it out).",
146
+ description: "The admin console's dashboard numbers (super admin): orgs, accounts and attentionTotal, everything waiting for a super admin (the platform inbox total plus the extensions, plugin updates and model providers admin.attention lists, every dead outbox row and the lost-jobs item of the run queue); partial is true when one of those lists could not be read right now (attentionTotal then leaves it out).",
131
147
  input: z.object({}).strict(),
132
148
  example: {},
133
149
  authz: { superAdmin: true },
@@ -137,7 +153,7 @@ let AdminOperations = class AdminOperations {
137
153
  }),
138
154
  defineOperation({
139
155
  id: "admin.attention",
140
- description: "What needs the super admin besides the platform inbox (super admin), one compact row each (kind, id, name, state, reason, next step): extensions (reason config, load_failed, approval, dependency, conflict, converging or legacy_format), platform plugins with a newer marketplace version (reason names both versions) and model providers (reason list_failed or no_chat_model). Each kind lists at most 20 rows; more counts the rest per kind. unavailable names a kind that could not be read right now (try again later). The platform inbox itself is inbox.platform-list.",
156
+ description: "What needs the super admin besides the platform inbox (super admin), one compact row each (kind, id, name, state, reason, next step): extensions (reason config, load_failed, approval, dependency, conflict, converging or legacy_format), platform plugins with a newer marketplace version (reason names both versions) model providers (reason list_failed or no_chat_model) background work the kernel could not queue (kind outbox: how many outbox rows are dead and since when) and run jobs the queue lost (kind queue: Redis lost data; the runs were queued again). Each kind lists at most 20 rows; more counts the rest per kind. unavailable names a kind that could not be read right now (try again later). The platform inbox itself is inbox.platform-list.",
141
157
  input: z.object({}).strict(),
142
158
  example: {},
143
159
  authz: { superAdmin: true },
@@ -2,6 +2,7 @@ import { type OnModuleInit } from "@nestjs/common";
2
2
  import { type AppearanceResult, AppearanceService } from "../../catalog/appearance.service.js";
3
3
  import { CatalogService } from "../../catalog/catalog.service.js";
4
4
  import { CatalogScopeService } from "../../catalog/catalog-scope.service.js";
5
+ import { PlatformImportUpdate } from "../../catalog/platform-import-update.js";
5
6
  import { PluginImport, type PluginReview } from "../../catalog/plugin-import.js";
6
7
  import { KernelDb } from "../../infra/database/kernel-db.js";
7
8
  import { ThemesService } from "../../themes/themes.service.js";
@@ -70,10 +71,11 @@ export declare class CatalogAdminOperations implements OnModuleInit {
70
71
  private readonly catalog;
71
72
  private readonly scope;
72
73
  private readonly pluginImport;
74
+ private readonly importUpdate;
73
75
  private readonly kdb;
74
76
  private readonly appearance;
75
77
  private readonly themes;
76
- constructor(registry: PlatformOperations, catalog: CatalogService, scope: CatalogScopeService, pluginImport: PluginImport, kdb: KernelDb, appearance: AppearanceService, themes: ThemesService);
78
+ constructor(registry: PlatformOperations, catalog: CatalogService, scope: CatalogScopeService, pluginImport: PluginImport, importUpdate: PlatformImportUpdate, kdb: KernelDb, appearance: AppearanceService, themes: ThemesService);
77
79
  /** The precheck refusal of another org's private plugin (the phase-1 rule), else null. */
78
80
  private otherOrgs;
79
81
  /** Whether an org owns the item (its owner org manages it, not the super admin's agent). */
@@ -14,6 +14,7 @@ import { CatalogDisabledBody, CatalogGitImportBody, CatalogIdPathParams, Catalog
14
14
  import { AppearanceService } from "../../catalog/appearance.service.js";
15
15
  import { CatalogService } from "../../catalog/catalog.service.js";
16
16
  import { CatalogScopeService } from "../../catalog/catalog-scope.service.js";
17
+ import { PlatformImportUpdate } from "../../catalog/platform-import-update.js";
17
18
  import { PluginImport } from "../../catalog/plugin-import.js";
18
19
  import { ApiError } from "../../errors.js";
19
20
  import { KernelDb } from "../../infra/database/kernel-db.js";
@@ -125,14 +126,16 @@ let CatalogAdminOperations = class CatalogAdminOperations {
125
126
  catalog;
126
127
  scope;
127
128
  pluginImport;
129
+ importUpdate;
128
130
  kdb;
129
131
  appearance;
130
132
  themes;
131
- constructor(registry, catalog, scope, pluginImport, kdb, appearance, themes) {
133
+ constructor(registry, catalog, scope, pluginImport, importUpdate, kdb, appearance, themes) {
132
134
  this.registry = registry;
133
135
  this.catalog = catalog;
134
136
  this.scope = scope;
135
137
  this.pluginImport = pluginImport;
138
+ this.importUpdate = importUpdate;
136
139
  this.kdb = kdb;
137
140
  this.appearance = appearance;
138
141
  this.themes = themes;
@@ -313,6 +316,30 @@ let CatalogAdminOperations = class CatalogAdminOperations {
313
316
  };
314
317
  },
315
318
  }),
319
+ defineOperation({
320
+ id: "plugins.import-update-preview",
321
+ description: "Preview what a staged new version of an installed platform plugin does as the platform update (super admin): every component's change, the extension step and the org connectors it touches. Nothing is imported or changed; the person confirms the review and the update together on the web (reviewUrl).",
322
+ input: z.object({ stagingId: StagingId }).strict(),
323
+ example: { stagingId: "3f1c2a9e-5b7d-4e21-9c0a-1d2e3f4a5b6c" },
324
+ authz: { superAdmin: true },
325
+ mirrors: ["GET /api/v1/admin/catalog/imports/:stagingId/update-preview"],
326
+ confirm: "read",
327
+ errors: [
328
+ {
329
+ code: "plugin.staging_not_found",
330
+ next: "The staged import expired (24 hours) or was confirmed already: prepare it again with plugins.import-npm or plugins.import-git.",
331
+ },
332
+ {
333
+ code: "plugin.upgrade_target_invalid",
334
+ next: "The plugin is not installed on the platform yet (reason not_installed: the review installs it), or the platform cannot move to this version (the details say why).",
335
+ },
336
+ ],
337
+ run: async (input) => ({
338
+ preview: await this.importUpdate.preview(input.stagingId),
339
+ reviewUrl: reviewUrl(input.stagingId),
340
+ next: CONFIRM_ON_WEB,
341
+ }),
342
+ }),
316
343
  defineOperation({
317
344
  id: "plugins.scope-preview",
318
345
  description: "Preview changing where a platform plugin is on (super admin): a scope (all: every org; optional: orgs switch it on; named: only the orgs listed, with orgs) or disabled: true (off everywhere). Returns the orgs that lose it (with the agents there), the components it takes back, name conflicts, and the scopeHash plugins.set-scope or plugins.set-disabled needs. Nothing is written; show the preview to the person first.",
@@ -675,8 +702,9 @@ CatalogAdminOperations = __decorate([
675
702
  __param(1, Inject(CatalogService)),
676
703
  __param(2, Inject(CatalogScopeService)),
677
704
  __param(3, Inject(PluginImport)),
678
- __param(4, Inject(KernelDb)),
679
- __param(5, Inject(AppearanceService)),
680
- __param(6, Inject(ThemesService))
705
+ __param(4, Inject(PlatformImportUpdate)),
706
+ __param(5, Inject(KernelDb)),
707
+ __param(6, Inject(AppearanceService)),
708
+ __param(7, Inject(ThemesService))
681
709
  ], CatalogAdminOperations);
682
710
  export { CatalogAdminOperations };
@@ -34,12 +34,10 @@ const ADMIN_CONSOLE_PENDING = "Review it in the admin console (plugins, pending
34
34
  const requestName = (r) => r.item?.name ?? r.entry?.name ?? r.agent?.name ?? r.kind;
35
35
  const requester = (r) => r.requestedByName ?? "a deleted account";
36
36
  /** The name an org notice is about. */
37
- const orgNoticeName = (n) => n.kind === "skill_renamed" ? n.skillRenamed.to : n.detail.name;
37
+ const orgNoticeName = (n) => n.detail.name;
38
38
  /** An org notice in one English sentence, as the inbox tells it. */
39
39
  function orgNoticeSummary(n) {
40
40
  switch (n.kind) {
41
- case "skill_renamed":
42
- return `Skill "${n.skillRenamed.from}" was renamed to "${n.skillRenamed.to}": a platform skill on in this org has its name; agents keep it.`;
43
41
  case "item_shared": {
44
42
  const d = n.detail;
45
43
  return `${d.ref.kind} ${d.name} was shared with ${d.org === "all_orgs" ? "every org" : d.org.name}.`;
@@ -182,18 +180,6 @@ function platformRow(i) {
182
180
  next: "Open the plugin in the admin console to see the error and retry.",
183
181
  };
184
182
  }
185
- case "platform_migration": {
186
- const r = i.run;
187
- const failed = r.itemsFailed.slice(0, 5).join(", ");
188
- return {
189
- ...base,
190
- name: "platform components migration",
191
- state: r.stuck ? "stuck" : "failed",
192
- summary: r.stuck
193
- ? "The platform components migration run has not finished for over an hour; its worker stopped. The next run starts at the next worker start or day."
194
- : `The platform components migration could not write ${r.itemsFailed.length} catalog item(s): ${failed}${r.itemsFailed.length > 5 ? ", …" : ""}. The next run tries them again.`,
195
- };
196
- }
197
183
  case "ownership_transferred":
198
184
  return {
199
185
  ...base,
@@ -243,9 +229,7 @@ let InboxOperations = class InboxOperations {
243
229
  if (row === undefined)
244
230
  return null;
245
231
  const base = { id: row.id, createdAt: row.created_at.toISOString() };
246
- return (row.kind === "skill_renamed"
247
- ? { ...base, kind: row.kind, skillRenamed: row.detail }
248
- : { ...base, kind: row.kind, detail: row.detail });
232
+ return { ...base, kind: row.kind, detail: row.detail };
249
233
  }
250
234
  /** A platform notice by id (dismissed or not), or null. */
251
235
  async platformNotice(id) {
@@ -292,7 +276,7 @@ let InboxOperations = class InboxOperations {
292
276
  }),
293
277
  defineOperation({
294
278
  id: "inbox.dismiss-notice",
295
- description: "Dismiss an org notice from the inbox for every org admin (org admins): the id of a notice row from inbox.list (types skill_renamed, item_shared, shared_item_updated, upload_confirmed, upload_rejected). Approvals and requests are not dismissed here: they are decided on the web.",
279
+ description: "Dismiss an org notice from the inbox for every org admin (org admins): the id of a notice row from inbox.list (types item_shared, shared_item_updated, upload_confirmed, upload_rejected). Approvals and requests are not dismissed here: they are decided on the web.",
296
280
  input: NoticeInput,
297
281
  example: NOTICE_EXAMPLE,
298
282
  authz: { orgAction: "catalog.decide" },
@@ -323,7 +307,7 @@ let InboxOperations = class InboxOperations {
323
307
  }),
324
308
  defineOperation({
325
309
  id: "inbox.platform-list",
326
- description: "List the platform inbox (super admin), newest first, one compact row each (type, what, state, summary, next step): orgs' requests to the platform, plugins waiting for a permission confirmation, this org's uploads waiting for you, failed scope syncs, a failed or stuck components migration and ownership notices. Only the newest 100 items are read (truncated: more wait); listed is how many of them are shown, otherOrgItems how many are items of plugins other orgs own (only counted). total counts everything waiting on the platform, other orgs' items included, as the admin console does; byType splits total by type (everything waiting, not the listed page). Nothing is decided here: requests and confirmations are done in the admin console. Pages by 50: pass the returned next as params.cursor.",
310
+ description: "List the platform inbox (super admin), newest first, one compact row each (type, what, state, summary, next step): orgs' requests to the platform, plugins waiting for a permission confirmation, this org's uploads waiting for you, failed scope syncs and ownership notices. Only the newest 100 items are read (truncated: more wait); listed is how many of them are shown, otherOrgItems how many are items of plugins other orgs own (only counted). total counts everything waiting on the platform, other orgs' items included, as the admin console does; byType splits total by type (everything waiting, not the listed page). Nothing is decided here: requests and confirmations are done in the admin console. Pages by 50: pass the returned next as params.cursor.",
327
311
  input: z.object({ cursor: Cursor.optional() }).strict(),
328
312
  example: {},
329
313
  authz: { superAdmin: true },
@@ -0,0 +1,21 @@
1
+ import { type OnModuleInit } from "@nestjs/common";
2
+ import { OutboxDeadService } from "../../admin/outbox-dead.service.js";
3
+ import { KernelDb } from "../../infra/database/kernel-db.js";
4
+ import { PlatformOperations } from "../registry.js";
5
+ /**
6
+ * The super admin's dead outbox rows through the `Platform` tool (transactional outbox spec
7
+ * §3.4): the list, retry and discard of `/api/v1/admin/outbox/dead*`, run through the same
8
+ * service. Dead rows are the deployment's, not an org's: the operations act on all of them.
9
+ */
10
+ export declare class OutboxOperations implements OnModuleInit {
11
+ private readonly registry;
12
+ private readonly dead;
13
+ private readonly kdb;
14
+ constructor(registry: PlatformOperations, dead: OutboxDeadService, kdb: KernelDb);
15
+ /** The dead row's job (queue and name) for a card, or null when no dead row has the id. */
16
+ private jobOf;
17
+ private precheck;
18
+ /** "job-name on queue" for a card, or the bare id when the row is gone. */
19
+ private label;
20
+ onModuleInit(): void;
21
+ }
@@ -0,0 +1,125 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
8
+ return function (target, key) { decorator(target, key, paramIndex); }
9
+ };
10
+ import { Inject, Injectable } from "@nestjs/common";
11
+ import { z } from "zod";
12
+ import { OutboxDeadParams } from "../../admin/outbox-dead.schemas.js";
13
+ import { OutboxDeadService } from "../../admin/outbox-dead.service.js";
14
+ import { KernelDb } from "../../infra/database/kernel-db.js";
15
+ import { defineOperation } from "../operation.js";
16
+ import { PlatformOperations } from "../registry.js";
17
+ import { viaAgent } from "./errors.js";
18
+ const DeadIdInput = OutboxDeadParams.strict();
19
+ /**
20
+ * The super admin's dead outbox rows through the `Platform` tool (transactional outbox spec
21
+ * §3.4): the list, retry and discard of `/api/v1/admin/outbox/dead*`, run through the same
22
+ * service. Dead rows are the deployment's, not an org's: the operations act on all of them.
23
+ */
24
+ let OutboxOperations = class OutboxOperations {
25
+ registry;
26
+ dead;
27
+ kdb;
28
+ constructor(registry, dead, kdb) {
29
+ this.registry = registry;
30
+ this.dead = dead;
31
+ this.kdb = kdb;
32
+ }
33
+ /** The dead row's job (queue and name) for a card, or null when no dead row has the id. */
34
+ async jobOf(id) {
35
+ const row = await this.kdb.db
36
+ .selectFrom("outbox")
37
+ .select(["queue", "job_name"])
38
+ .where("id", "=", id)
39
+ .where("dead_at", "is not", null)
40
+ .executeTakeFirst();
41
+ return row ?? null;
42
+ }
43
+ async precheck(id) {
44
+ return (await this.jobOf(id)) === null
45
+ ? { ok: false, code: "outbox.not_found", message: `No dead outbox row ${id}.` }
46
+ : { ok: true };
47
+ }
48
+ /** "job-name on queue" for a card, or the bare id when the row is gone. */
49
+ async label(id) {
50
+ const job = await this.jobOf(id);
51
+ return job === null ? `#${id}` : `${job.job_name} (${job.queue}, #${id})`;
52
+ }
53
+ onModuleInit() {
54
+ this.registry.register([
55
+ defineOperation({
56
+ id: "admin.outbox-list-dead",
57
+ description: "List background work the kernel could not queue (super admin): outbox rows dead after their last delivery attempt, oldest first (at most 200), each with its id, queue, job name, job id, org (null for platform work), attempts, last error and when it died. Retry one with admin.outbox-retry or drop it with admin.outbox-discard.",
58
+ input: z.object({}).strict(),
59
+ example: {},
60
+ authz: { superAdmin: true },
61
+ mirrors: ["GET /api/v1/admin/outbox/dead"],
62
+ confirm: "read",
63
+ run: () => this.dead.list(),
64
+ }),
65
+ defineOperation({
66
+ id: "admin.outbox-retry",
67
+ description: "Queue a dead outbox row again (super admin): it gets fresh attempts and is delivered right away. When the same job is already owed by a pending row, the dead copy is discarded instead; outcome says which (retried or already_owed). A job whose subject is gone since is harmless: it finds nothing to do. The platform audit log records it.",
68
+ input: DeadIdInput,
69
+ example: { id: "42" },
70
+ authz: { superAdmin: true },
71
+ mirrors: ["POST /api/v1/admin/outbox/dead/:id/retry"],
72
+ confirm: "platform",
73
+ errors: [
74
+ {
75
+ code: "outbox.not_found",
76
+ next: "The row is no longer dead (retried, discarded or delivered): list the dead rows again with admin.outbox-list-dead.",
77
+ },
78
+ ],
79
+ precheck: (i) => this.precheck(i.id),
80
+ summary: async (i) => {
81
+ const job = await this.label(i.id);
82
+ return {
83
+ zh: `重新排入无法排入队列的后台任务 ${job}`,
84
+ en: `Queue background work that could not be queued again: ${job}`,
85
+ };
86
+ },
87
+ run: (input, ctx) => this.dead.retry(input.id, { accountId: ctx.actorAccountId }, viaAgent("admin.outbox-retry", ctx)),
88
+ }),
89
+ defineOperation({
90
+ id: "admin.outbox-discard",
91
+ description: "Discard a dead outbox row (super admin): its job is never run. Use it only when the work is no longer wanted; to run it, use admin.outbox-retry. The platform audit log records it.",
92
+ input: DeadIdInput,
93
+ example: { id: "42" },
94
+ authz: { superAdmin: true },
95
+ mirrors: ["DELETE /api/v1/admin/outbox/dead/:id"],
96
+ confirm: "platform",
97
+ errors: [
98
+ {
99
+ code: "outbox.not_found",
100
+ next: "The row is no longer dead (retried, discarded or delivered): list the dead rows again with admin.outbox-list-dead.",
101
+ },
102
+ ],
103
+ precheck: (i) => this.precheck(i.id),
104
+ summary: async (i) => {
105
+ const job = await this.label(i.id);
106
+ return {
107
+ zh: `丢弃无法排入队列的后台任务 ${job},它不会再运行`,
108
+ en: `Discard background work that could not be queued: ${job}; it will never run`,
109
+ };
110
+ },
111
+ run: async (input, ctx) => {
112
+ await this.dead.discard(input.id, { accountId: ctx.actorAccountId }, viaAgent("admin.outbox-discard", ctx));
113
+ return { id: input.id, discarded: true };
114
+ },
115
+ }),
116
+ ]);
117
+ }
118
+ };
119
+ OutboxOperations = __decorate([
120
+ Injectable(),
121
+ __param(0, Inject(PlatformOperations)),
122
+ __param(1, Inject(OutboxDeadService)),
123
+ __param(2, Inject(KernelDb))
124
+ ], OutboxOperations);
125
+ export { OutboxOperations };
@@ -32,6 +32,7 @@ export declare class PlatformOperationsProvider implements OnModuleInit {
32
32
  * default-on spec §8): every tool the org offers that the definition does not turn off, builtins
33
33
  * by name, extension tools as `plugin__<plugin>__<tool>`, connector tools as
34
34
  * `mcp__<slug>__<tool>`; the ones that cannot load now are listed with the registry's reason.
35
+ * Listed for the source of the conversation the operation runs in (memory plugin spec §6.2).
35
36
  */
36
37
  private toolKeys;
37
38
  onModuleInit(): void;