@capybara-hq/kernel 0.1.0-rc.23 → 0.1.0-rc.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/bootstrap.json +25 -25
  2. package/dist/admin/admin.module.d.ts +2 -1
  3. package/dist/admin/admin.module.js +9 -3
  4. package/dist/admin/health.service.d.ts +2 -2
  5. package/dist/admin/health.service.js +6 -2
  6. package/dist/admin/outbox-dead.controller.d.ts +23 -0
  7. package/dist/admin/outbox-dead.controller.js +62 -0
  8. package/dist/admin/outbox-dead.schemas.d.ts +8 -0
  9. package/dist/admin/outbox-dead.schemas.js +18 -0
  10. package/dist/admin/outbox-dead.service.d.ts +66 -0
  11. package/dist/admin/outbox-dead.service.js +179 -0
  12. package/dist/admin/overview.service.d.ts +40 -5
  13. package/dist/admin/overview.service.js +41 -7
  14. package/dist/agents/agents.module.js +3 -0
  15. package/dist/agents/agents.service.d.ts +6 -1
  16. package/dist/agents/agents.service.js +11 -2
  17. package/dist/agents/from-template.js +1 -1
  18. package/dist/background/finish.d.ts +5 -2
  19. package/dist/background/finish.js +14 -3
  20. package/dist/background/launch.d.ts +2 -1
  21. package/dist/background/launch.js +5 -2
  22. package/dist/background/store.d.ts +8 -0
  23. package/dist/background/store.js +24 -0
  24. package/dist/catalog/admin-catalog.controller.d.ts +21 -2
  25. package/dist/catalog/admin-catalog.controller.js +45 -6
  26. package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
  27. package/dist/catalog/admin-catalog.schemas.js +8 -0
  28. package/dist/catalog/catalog-import.module.js +0 -4
  29. package/dist/catalog/catalog-scope.service.d.ts +63 -26
  30. package/dist/catalog/catalog-scope.service.js +146 -71
  31. package/dist/catalog/catalog.module.d.ts +2 -1
  32. package/dist/catalog/catalog.module.js +9 -4
  33. package/dist/catalog/catalog.service.d.ts +11 -4
  34. package/dist/catalog/catalog.service.js +21 -5
  35. package/dist/catalog/cli.d.ts +4 -3
  36. package/dist/catalog/cli.js +8 -13
  37. package/dist/catalog/job-ids.d.ts +8 -20
  38. package/dist/catalog/job-ids.js +11 -16
  39. package/dist/catalog/marketplaces.service.d.ts +1 -1
  40. package/dist/catalog/org-plugin-uploads.d.ts +11 -4
  41. package/dist/catalog/org-plugin-uploads.js +21 -6
  42. package/dist/catalog/owned-items.d.ts +6 -13
  43. package/dist/catalog/owned-items.js +11 -29
  44. package/dist/catalog/owned-plugin-cleanup.d.ts +8 -17
  45. package/dist/catalog/owned-plugin-cleanup.js +12 -66
  46. package/dist/catalog/platform-components.d.ts +56 -34
  47. package/dist/catalog/platform-components.js +68 -78
  48. package/dist/catalog/platform-import-update.d.ts +50 -0
  49. package/dist/catalog/platform-import-update.js +116 -0
  50. package/dist/catalog/plugin-import.d.ts +64 -26
  51. package/dist/catalog/plugin-import.js +113 -77
  52. package/dist/catalog/plugin-upgrade.d.ts +22 -4
  53. package/dist/catalog/plugin-upgrade.js +26 -19
  54. package/dist/catalog/scope-jobs.d.ts +59 -0
  55. package/dist/catalog/scope-jobs.js +65 -0
  56. package/dist/catalog/scope-sync-workers.d.ts +22 -0
  57. package/dist/catalog/scope-sync-workers.js +58 -2
  58. package/dist/catalog/scope-sync.d.ts +40 -65
  59. package/dist/catalog/scope-sync.js +114 -122
  60. package/dist/channels/channels.module.d.ts +5 -2
  61. package/dist/channels/channels.module.js +9 -2
  62. package/dist/channels/deliver-job.d.ts +25 -0
  63. package/dist/channels/deliver-job.js +25 -0
  64. package/dist/channels/inbound.d.ts +1 -1
  65. package/dist/channels/inbound.js +4 -17
  66. package/dist/channels/jobs.d.ts +28 -18
  67. package/dist/channels/jobs.js +63 -26
  68. package/dist/channels/threads.d.ts +4 -3
  69. package/dist/channels/threads.js +4 -3
  70. package/dist/config/schema.d.ts +0 -3
  71. package/dist/config/schema.js +11 -20
  72. package/dist/conversations/agent-tree.d.ts +16 -0
  73. package/dist/conversations/agent-tree.js +36 -0
  74. package/dist/conversations/conversations.controller.js +4 -2
  75. package/dist/conversations/conversations.service.d.ts +61 -19
  76. package/dist/conversations/conversations.service.js +69 -43
  77. package/dist/conversations/event-log.d.ts +7 -10
  78. package/dist/conversations/event-log.js +24 -15
  79. package/dist/conversations/events.d.ts +21 -0
  80. package/dist/conversations/events.js +26 -2
  81. package/dist/conversations/queue.service.d.ts +8 -3
  82. package/dist/conversations/queue.service.js +37 -13
  83. package/dist/conversations/source.d.ts +10 -0
  84. package/dist/conversations/source.js +17 -0
  85. package/dist/conversations/titles.d.ts +21 -8
  86. package/dist/conversations/titles.js +42 -15
  87. package/dist/conversations/tree.d.ts +10 -0
  88. package/dist/conversations/tree.js +35 -0
  89. package/dist/db/kernel-schema.d.ts +35 -22
  90. package/dist/devices/devices.service.d.ts +23 -11
  91. package/dist/devices/devices.service.js +34 -26
  92. package/dist/errors.d.ts +11 -0
  93. package/dist/errors.js +11 -0
  94. package/dist/evals/run-replay.d.ts +13 -2
  95. package/dist/evals/run-replay.js +42 -9
  96. package/dist/evals/snapshot.d.ts +7 -1
  97. package/dist/evals/snapshot.js +2 -1
  98. package/dist/extensions/extensions.module.js +3 -0
  99. package/dist/extensions/hooks.d.ts +22 -3
  100. package/dist/extensions/hooks.js +15 -1
  101. package/dist/extensions/lifecycle-hooks.d.ts +99 -0
  102. package/dist/extensions/lifecycle-hooks.js +273 -0
  103. package/dist/extensions/lifecycle.d.ts +6 -1
  104. package/dist/extensions/lifecycle.js +9 -2
  105. package/dist/extensions/org-config.d.ts +13 -1
  106. package/dist/extensions/org-config.js +19 -2
  107. package/dist/extensions/permission-view.d.ts +9 -5
  108. package/dist/extensions/permission-view.js +9 -4
  109. package/dist/extensions/point-defaults.d.ts +28 -1
  110. package/dist/extensions/point-defaults.js +44 -13
  111. package/dist/extensions/usage-subscribers.d.ts +43 -0
  112. package/dist/extensions/usage-subscribers.js +108 -0
  113. package/dist/http/api.module.js +2 -0
  114. package/dist/inbox/inbox.service.d.ts +6 -20
  115. package/dist/inbox/inbox.service.js +0 -3
  116. package/dist/inbox/org-notices.d.ts +1 -1
  117. package/dist/inbox/platform-inbox.service.d.ts +3 -32
  118. package/dist/inbox/platform-inbox.service.js +5 -54
  119. package/dist/index.d.ts +1 -0
  120. package/dist/index.js +1 -0
  121. package/dist/infra/cli/kernel-cli.module.js +5 -0
  122. package/dist/infra/events/kernel-events.d.ts +9 -35
  123. package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
  124. package/dist/infra/outbox/outbox-relay.module.js +18 -0
  125. package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
  126. package/dist/infra/outbox/outbox.dispatcher.js +310 -0
  127. package/dist/infra/outbox/outbox.module.d.ts +24 -0
  128. package/dist/infra/outbox/outbox.module.js +50 -0
  129. package/dist/infra/outbox/outbox.relay.d.ts +31 -0
  130. package/dist/infra/outbox/outbox.relay.js +76 -0
  131. package/dist/infra/outbox/outbox.service.d.ts +51 -0
  132. package/dist/infra/outbox/outbox.service.js +131 -0
  133. package/dist/infra/outbox/registry.d.ts +244 -0
  134. package/dist/infra/outbox/registry.js +234 -0
  135. package/dist/infra/queue/queue-names.d.ts +8 -0
  136. package/dist/infra/queue/queue-names.js +17 -0
  137. package/dist/kernel.module.js +3 -0
  138. package/dist/local-devices/device-policy.service.d.ts +4 -0
  139. package/dist/local-devices/device-policy.service.js +61 -3
  140. package/dist/local-devices/machines.d.ts +13 -5
  141. package/dist/local-devices/machines.js +45 -7
  142. package/dist/local-devices/policy-summary.d.ts +44 -1
  143. package/dist/local-devices/policy-summary.js +69 -0
  144. package/dist/models/embeddings.d.ts +9 -9
  145. package/dist/models/embeddings.js +11 -18
  146. package/dist/models/models.module.js +3 -0
  147. package/dist/orgs/directory-sync.js +1 -1
  148. package/dist/orgs/members.service.js +1 -1
  149. package/dist/orgs/offboarding.d.ts +50 -57
  150. package/dist/orgs/offboarding.js +117 -162
  151. package/dist/orgs/orgs.module.js +3 -0
  152. package/dist/orgs/orgs.service.d.ts +11 -5
  153. package/dist/orgs/orgs.service.js +22 -6
  154. package/dist/overrides.d.ts +23 -3
  155. package/dist/overrides.js +12 -2
  156. package/dist/platform/exclusions.js +5 -0
  157. package/dist/platform/ops/admin.ops.js +18 -2
  158. package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
  159. package/dist/platform/ops/catalog-admin.ops.js +32 -4
  160. package/dist/platform/ops/inbox.ops.js +4 -20
  161. package/dist/platform/ops/outbox.ops.d.ts +21 -0
  162. package/dist/platform/ops/outbox.ops.js +125 -0
  163. package/dist/platform/ops/platform.ops.d.ts +1 -0
  164. package/dist/platform/ops/platform.ops.js +6 -3
  165. package/dist/platform/ops/schedules.ops.js +40 -1
  166. package/dist/platform/platform-ops.module.d.ts +2 -1
  167. package/dist/platform/platform-ops.module.js +3 -0
  168. package/dist/platform/route-schemas.js +3 -0
  169. package/dist/roles/worker-role.d.ts +10 -5
  170. package/dist/roles/worker-role.js +19 -9
  171. package/dist/roles/worker.module.js +11 -8
  172. package/dist/runtime/context/build.d.ts +3 -0
  173. package/dist/runtime/context/build.js +15 -0
  174. package/dist/runtime/context/plugin-context.d.ts +20 -0
  175. package/dist/runtime/context/plugin-context.js +30 -0
  176. package/dist/runtime/langgraph-loop.js +17 -5
  177. package/dist/runtime/limits.d.ts +15 -0
  178. package/dist/runtime/limits.js +25 -0
  179. package/dist/runtime/loop.d.ts +16 -3
  180. package/dist/runtime/loop.js +2 -1
  181. package/dist/runtime/maintenance.d.ts +7 -3
  182. package/dist/runtime/maintenance.js +52 -12
  183. package/dist/runtime/model-call.d.ts +20 -17
  184. package/dist/runtime/model-call.js +15 -24
  185. package/dist/runtime/plugin-context.service.d.ts +69 -0
  186. package/dist/runtime/plugin-context.service.js +208 -0
  187. package/dist/runtime/queue-lost-jobs.d.ts +24 -0
  188. package/dist/runtime/queue-lost-jobs.js +51 -0
  189. package/dist/runtime/run-control.d.ts +47 -5
  190. package/dist/runtime/run-control.js +79 -12
  191. package/dist/runtime/run-finish.d.ts +39 -12
  192. package/dist/runtime/run-finish.js +97 -14
  193. package/dist/runtime/run-jobs.d.ts +95 -13
  194. package/dist/runtime/run-jobs.js +199 -28
  195. package/dist/runtime/run-orphan-check.job.d.ts +142 -0
  196. package/dist/runtime/run-orphan-check.job.js +339 -0
  197. package/dist/runtime/run-processors.d.ts +16 -9
  198. package/dist/runtime/run-processors.js +1 -1
  199. package/dist/runtime/run-queue.d.ts +75 -53
  200. package/dist/runtime/run-queue.js +189 -263
  201. package/dist/runtime/run-steps.d.ts +1 -2
  202. package/dist/runtime/run-steps.js +8 -11
  203. package/dist/runtime/run-worker.d.ts +26 -16
  204. package/dist/runtime/run-worker.js +132 -37
  205. package/dist/runtime/runtime.module.d.ts +2 -3
  206. package/dist/runtime/runtime.module.js +7 -6
  207. package/dist/runtime/step-log.d.ts +16 -4
  208. package/dist/runtime/step-log.js +26 -6
  209. package/dist/runtime/stream.controller.d.ts +2 -4
  210. package/dist/runtime/stream.controller.js +5 -11
  211. package/dist/runtime/subagents/child.js +1 -1
  212. package/dist/runtime/subagents/definition.d.ts +2 -1
  213. package/dist/runtime/subagents/definition.js +4 -2
  214. package/dist/runtime/subagents/deliveries.d.ts +6 -3
  215. package/dist/runtime/subagents/deliveries.js +16 -7
  216. package/dist/runtime/subagents/dispatch.d.ts +12 -12
  217. package/dist/runtime/subagents/dispatch.js +14 -38
  218. package/dist/runtime/subagents/messages.d.ts +5 -1
  219. package/dist/runtime/subagents/messages.js +11 -3
  220. package/dist/runtime/subagents/skill-fork.d.ts +3 -3
  221. package/dist/runtime/subagents/skill-fork.js +8 -5
  222. package/dist/runtime/subagents/subagents.service.js +1 -1
  223. package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
  224. package/dist/runtime/subagents/tree-jobs.js +86 -0
  225. package/dist/runtime/usage-report-jobs.d.ts +23 -48
  226. package/dist/runtime/usage-report-jobs.js +67 -119
  227. package/dist/runtime/usage-report.d.ts +28 -77
  228. package/dist/runtime/usage-report.js +35 -213
  229. package/dist/runtime/waits.d.ts +48 -198
  230. package/dist/runtime/waits.js +103 -805
  231. package/dist/sandbox/jobs.d.ts +20 -10
  232. package/dist/sandbox/jobs.js +23 -17
  233. package/dist/sandbox/sandbox.service.d.ts +17 -4
  234. package/dist/sandbox/sandbox.service.js +55 -14
  235. package/dist/schedules/calendar.d.ts +134 -0
  236. package/dist/schedules/calendar.js +410 -0
  237. package/dist/schedules/fire.d.ts +26 -7
  238. package/dist/schedules/fire.js +91 -22
  239. package/dist/schedules/job-ids.d.ts +66 -17
  240. package/dist/schedules/job-ids.js +81 -13
  241. package/dist/schedules/run-tracker.d.ts +0 -5
  242. package/dist/schedules/run-tracker.js +2 -14
  243. package/dist/schedules/scan.job.d.ts +13 -32
  244. package/dist/schedules/scan.job.js +50 -164
  245. package/dist/schedules/schedule-math.d.ts +42 -0
  246. package/dist/schedules/schedule-math.js +52 -0
  247. package/dist/schedules/scheduled-tasks.service.d.ts +22 -6
  248. package/dist/schedules/scheduled-tasks.service.js +70 -14
  249. package/dist/schedules/schedules.controller.d.ts +5 -1
  250. package/dist/schedules/schedules.controller.js +15 -1
  251. package/dist/schedules/schedules.module.js +0 -4
  252. package/dist/schedules/schedules.schemas.d.ts +35 -0
  253. package/dist/schedules/schedules.schemas.js +27 -0
  254. package/dist/schedules/store.d.ts +5 -0
  255. package/dist/schedules/store.js +20 -0
  256. package/dist/skills/changes.controller.d.ts +1 -1
  257. package/dist/skills/changes.controller.js +1 -1
  258. package/dist/tools/approvals.service.d.ts +41 -11
  259. package/dist/tools/approvals.service.js +108 -14
  260. package/dist/tools/builtin-names.d.ts +5 -3
  261. package/dist/tools/builtin-names.js +12 -4
  262. package/dist/tools/builtins/builtin-tools.d.ts +1 -2
  263. package/dist/tools/builtins/builtin-tools.js +21 -17
  264. package/dist/tools/builtins/sandbox/bash.js +9 -3
  265. package/dist/tools/builtins/sandbox/common.d.ts +18 -1
  266. package/dist/tools/builtins/sandbox/common.js +14 -1
  267. package/dist/tools/builtins/sandbox/index.d.ts +2 -1
  268. package/dist/tools/builtins/sandbox/index.js +4 -1
  269. package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
  270. package/dist/tools/builtins/sandbox/task-list.js +130 -0
  271. package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
  272. package/dist/tools/builtins/sandbox/task-output.js +21 -3
  273. package/dist/tools/builtins/web/extract.d.ts +2 -4
  274. package/dist/tools/builtins/web/extract.js +2 -5
  275. package/dist/tools/pipeline.d.ts +12 -3
  276. package/dist/tools/pipeline.js +6 -1
  277. package/dist/tools/questions.service.d.ts +30 -10
  278. package/dist/tools/questions.service.js +41 -27
  279. package/dist/tools/registry.d.ts +12 -3
  280. package/dist/tools/registry.js +13 -3
  281. package/dist/tools/tools.module.js +4 -3
  282. package/package.json +3 -3
  283. package/src/migrations/0118_device_policy_ops.sql +6 -0
  284. package/src/migrations/0119_outbox.sql +22 -0
  285. package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
  286. package/src/migrations/0121_drop_platform_migration_runs.sql +12 -0
  287. package/src/migrations/0122_drop_scheduled_task_runs_rechecked_at.sql +5 -0
  288. package/src/migrations/0123_pgvector.sql +27 -0
  289. package/src/migrations/0124_conversation_source.sql +36 -0
  290. package/dist/catalog/platform-migration.d.ts +0 -115
  291. package/dist/catalog/platform-migration.js +0 -583
  292. package/dist/infra/queue/add-job-once.d.ts +0 -14
  293. package/dist/infra/queue/add-job-once.js +0 -16
@@ -9,6 +9,8 @@ import { AccountsService } from "../identity/accounts.js";
9
9
  import { PlatformInboxService } from "../inbox/platform-inbox.service.js";
10
10
  import { OrgsService } from "../orgs/orgs.service.js";
11
11
  import { ProviderRegistry, type ProviderStatus } from "../runtime/providers.js";
12
+ import { QueueLostJobs } from "../runtime/queue-lost-jobs.js";
13
+ import { OutboxDeadService } from "./outbox-dead.service.js";
12
14
  /** The most rows each attention list returns; the rest are counted in `more`. */
13
15
  export declare const ATTENTION_LIST_MAX = 20;
14
16
  /** The admin overview's numbers (`GET /api/v1/admin/overview`): counts only. */
@@ -17,7 +19,8 @@ export interface AdminOverviewStats {
17
19
  accounts: number;
18
20
  /**
19
21
  * What waits for a super admin: the platform inbox total plus the extensions, plugin updates and
20
- * model providers of {@link AdminAttention} (each counted in full, not capped).
22
+ * model providers of {@link AdminAttention} (each counted in full, not capped), every dead
23
+ * outbox row and the run queue's lost-jobs item.
21
24
  */
22
25
  attentionTotal: number;
23
26
  /** An attention source could not be read: `attentionTotal` leaves its items out. */
@@ -33,7 +36,7 @@ export type AttentionExtensionReason = "config" | "load_failed" | "approval" | "
33
36
  /** What is wrong with a model provider: its model list failed, or it lists no usable chat model. */
34
37
  export type AttentionProviderProblem = "list_failed" | "no_chat_model";
35
38
  /** An attention list a source failed to read (it is then empty, the others intact). */
36
- export type AttentionSource = "extensions" | "updates" | "providers";
39
+ export type AttentionSource = "extensions" | "updates" | "providers" | "outbox" | "queue";
37
40
  export interface AttentionExtension {
38
41
  name: string;
39
42
  displayName: LocalizedName | null;
@@ -61,6 +64,27 @@ export interface AttentionProvider {
61
64
  icon: string | null;
62
65
  problem: AttentionProviderProblem;
63
66
  }
67
+ /**
68
+ * Background work the kernel could not queue (transactional outbox spec §3.4): how many outbox
69
+ * rows are dead and the oldest one's `dead_at`. One item for all of them; the rows themselves are
70
+ * `GET /api/v1/admin/outbox/dead`.
71
+ */
72
+ export interface AttentionOutboxDead {
73
+ kind: "outbox_dead";
74
+ count: number;
75
+ oldestAt: string;
76
+ }
77
+ /**
78
+ * The run queue lost background jobs (transactional outbox spec §8.3): the `run-orphan-check`
79
+ * found queued runs whose job was neither in the queue nor owed, which only Redis losing data
80
+ * explains. Their jobs were added again; the item says Redis durability needs a look, how many
81
+ * jobs were lost and when last (it stays a week after the last loss).
82
+ */
83
+ export interface AttentionQueueLostJobs {
84
+ kind: "queue_lost_jobs";
85
+ count: number;
86
+ lastAt: string;
87
+ }
64
88
  /**
65
89
  * `GET /api/v1/admin/overview/attention` (spec §5.2, §9): what needs a super admin besides the
66
90
  * inbox, each list at most {@link ATTENTION_LIST_MAX} rows with the rest counted in `more`, and
@@ -71,6 +95,10 @@ export interface AdminAttention {
71
95
  extensions: AttentionExtension[];
72
96
  updates: AttentionUpdate[];
73
97
  providers: AttentionProvider[];
98
+ /** System items: at most one, `outbox_dead`, when some outbox rows are dead. */
99
+ outbox: AttentionOutboxDead[];
100
+ /** System items: at most one, `queue_lost_jobs`, when the run queue lost jobs this week. */
101
+ queue: AttentionQueueLostJobs[];
74
102
  more: Record<AttentionSource, number>;
75
103
  unavailable: AttentionSource[];
76
104
  }
@@ -81,8 +109,9 @@ export declare function providerProblem(p: ProviderStatus): AttentionProviderPro
81
109
  /**
82
110
  * The admin overview (spec §4.1, §5.2): its numbers and the 待处理 lists, read live from the
83
111
  * sources the admin pages read (`ExtensionAdmin`, the catalog, the provider registry's cached
84
- * lists). Each source is read on its own: a failing one is reported in `unavailable`. Reads are not
85
- * audited (decision D5) and not cached further (every source is PG or already Redis-cached).
112
+ * lists, the dead outbox rows, the run queue's lost-jobs canary). Each source is read on its own: a failing one is reported in
113
+ * `unavailable`. Reads are not audited (decision D5) and not cached further (every source is PG
114
+ * or already Redis-cached).
86
115
  */
87
116
  export declare class AdminOverviewService {
88
117
  private readonly extensions;
@@ -94,10 +123,16 @@ export declare class AdminOverviewService {
94
123
  private readonly orgs;
95
124
  private readonly accounts;
96
125
  private readonly marketplaces;
126
+ private readonly outboxDead;
127
+ private readonly lostJobs;
97
128
  private readonly log;
98
- constructor(extensions: ExtensionAdmin, catalog: CatalogService, registry: ProviderRegistry, displayNames: ExtensionDisplayNames, icons: PluginIcons, inbox: PlatformInboxService, orgs: OrgsService, accounts: AccountsService, marketplaces: MarketplacesService, log: Logger);
129
+ constructor(extensions: ExtensionAdmin, catalog: CatalogService, registry: ProviderRegistry, displayNames: ExtensionDisplayNames, icons: PluginIcons, inbox: PlatformInboxService, orgs: OrgsService, accounts: AccountsService, marketplaces: MarketplacesService, outboxDead: OutboxDeadService, lostJobs: Pick<QueueLostJobs, "summary">, log: Logger);
99
130
  stats(): Promise<AdminOverviewStats>;
100
131
  attention(): Promise<AdminAttention>;
132
+ /** The `queue_lost_jobs` item when the run queue lost jobs this week, else none. */
133
+ private queueRows;
134
+ /** The `outbox_dead` item when some outbox rows are dead, else none. */
135
+ private outboxRows;
101
136
  /**
102
137
  * The extensions needing a look, but not one pending approval whose plugin waits in the platform
103
138
  * inbox (a permission confirmation or an org upload: the inbox already lists and counts it). A
@@ -18,6 +18,8 @@ import { PlatformInboxService } from "../inbox/platform-inbox.service.js";
18
18
  import { KERNEL_LOGGER } from "../infra/tokens.js";
19
19
  import { OrgsService } from "../orgs/orgs.service.js";
20
20
  import { ProviderRegistry } from "../runtime/providers.js";
21
+ import { QueueLostJobs } from "../runtime/queue-lost-jobs.js";
22
+ import { OutboxDeadService } from "./outbox-dead.service.js";
21
23
  /** The most rows each attention list returns; the rest are counted in `more`. */
22
24
  export const ATTENTION_LIST_MAX = 20;
23
25
  /** The reason an extension is listed, or null when it needs nothing. */
@@ -53,8 +55,9 @@ export function providerProblem(p) {
53
55
  /**
54
56
  * The admin overview (spec §4.1, §5.2): its numbers and the 待处理 lists, read live from the
55
57
  * sources the admin pages read (`ExtensionAdmin`, the catalog, the provider registry's cached
56
- * lists). Each source is read on its own: a failing one is reported in `unavailable`. Reads are not
57
- * audited (decision D5) and not cached further (every source is PG or already Redis-cached).
58
+ * lists, the dead outbox rows, the run queue's lost-jobs canary). Each source is read on its own: a failing one is reported in
59
+ * `unavailable`. Reads are not audited (decision D5) and not cached further (every source is PG
60
+ * or already Redis-cached).
58
61
  */
59
62
  let AdminOverviewService = class AdminOverviewService {
60
63
  extensions;
@@ -66,8 +69,10 @@ let AdminOverviewService = class AdminOverviewService {
66
69
  orgs;
67
70
  accounts;
68
71
  marketplaces;
72
+ outboxDead;
73
+ lostJobs;
69
74
  log;
70
- constructor(extensions, catalog, registry, displayNames, icons, inbox, orgs, accounts, marketplaces, log) {
75
+ constructor(extensions, catalog, registry, displayNames, icons, inbox, orgs, accounts, marketplaces, outboxDead, lostJobs, log) {
71
76
  this.extensions = extensions;
72
77
  this.catalog = catalog;
73
78
  this.registry = registry;
@@ -77,6 +82,8 @@ let AdminOverviewService = class AdminOverviewService {
77
82
  this.orgs = orgs;
78
83
  this.accounts = accounts;
79
84
  this.marketplaces = marketplaces;
85
+ this.outboxDead = outboxDead;
86
+ this.lostJobs = lostJobs;
80
87
  this.log = log;
81
88
  }
82
89
  async stats() {
@@ -87,10 +94,17 @@ let AdminOverviewService = class AdminOverviewService {
87
94
  this.attention(),
88
95
  ]);
89
96
  const listed = (s) => attention[s].length + attention.more[s];
97
+ // each dead row waits for a super admin, not the one item that counts them
98
+ const dead = attention.outbox.reduce((n, o) => n + o.count, 0);
90
99
  return {
91
100
  orgs: orgs.length,
92
101
  accounts,
93
- attentionTotal: inbox + listed("extensions") + listed("updates") + listed("providers"),
102
+ attentionTotal: inbox +
103
+ listed("extensions") +
104
+ listed("updates") +
105
+ listed("providers") +
106
+ dead +
107
+ attention.queue.length,
94
108
  partial: attention.unavailable.length > 0,
95
109
  };
96
110
  }
@@ -98,16 +112,20 @@ let AdminOverviewService = class AdminOverviewService {
98
112
  // the catalog is read once: the update rows, and the plugins the inbox already lists
99
113
  const items = this.catalogItems();
100
114
  items.catch(() => { }); // awaited (and reported) by updateRows
101
- const [extensions, updates, providers] = await Promise.allSettled([
115
+ const [extensions, updates, providers, outbox, queue] = await Promise.allSettled([
102
116
  this.extensionRows(items),
103
117
  this.updateRows(items),
104
118
  this.providerRows(),
119
+ this.outboxRows(),
120
+ this.queueRows(),
105
121
  ]);
106
122
  const out = {
107
123
  extensions: [],
108
124
  updates: [],
109
125
  providers: [],
110
- more: { extensions: 0, updates: 0, providers: 0 },
126
+ outbox: [],
127
+ queue: [],
128
+ more: { extensions: 0, updates: 0, providers: 0, outbox: 0, queue: 0 },
111
129
  unavailable: [],
112
130
  };
113
131
  /** The rows of a source that answered (capped), or none and its name in `unavailable`. */
@@ -127,8 +145,22 @@ let AdminOverviewService = class AdminOverviewService {
127
145
  out.extensions = take("extensions", extensions);
128
146
  out.updates = take("updates", updates);
129
147
  out.providers = take("providers", providers);
148
+ out.outbox = take("outbox", outbox);
149
+ out.queue = take("queue", queue);
130
150
  return out;
131
151
  }
152
+ /** The `queue_lost_jobs` item when the run queue lost jobs this week, else none. */
153
+ async queueRows() {
154
+ const lost = await this.lostJobs.summary();
155
+ return lost === null ? [] : [{ kind: "queue_lost_jobs", ...lost }];
156
+ }
157
+ /** The `outbox_dead` item when some outbox rows are dead, else none. */
158
+ async outboxRows() {
159
+ const { count, oldestAt } = await this.outboxDead.summary();
160
+ if (count === 0 || oldestAt === null)
161
+ return [];
162
+ return [{ kind: "outbox_dead", count, oldestAt: oldestAt.toISOString() }];
163
+ }
132
164
  /**
133
165
  * The extensions needing a look, but not one pending approval whose plugin waits in the platform
134
166
  * inbox (a permission confirmation or an org upload: the inbox already lists and counts it). A
@@ -218,6 +250,8 @@ AdminOverviewService = __decorate([
218
250
  __param(6, Inject(OrgsService)),
219
251
  __param(7, Inject(AccountsService)),
220
252
  __param(8, Inject(MarketplacesService)),
221
- __param(9, Inject(KERNEL_LOGGER))
253
+ __param(9, Inject(OutboxDeadService)),
254
+ __param(10, Inject(QueueLostJobs)),
255
+ __param(11, Inject(KERNEL_LOGGER))
222
256
  ], AdminOverviewService);
223
257
  export { AdminOverviewService };
@@ -8,6 +8,7 @@ import { Module } from "@nestjs/common";
8
8
  import { AttachmentsModule } from "../conversations/attachments.module.js";
9
9
  import { EvalBudgetModule } from "../evals/budget.js";
10
10
  import { ExtensionsModule } from "../extensions/extensions.module.js";
11
+ import { LifecycleHooksModule } from "../extensions/lifecycle-hooks.js";
11
12
  import { ModelsModule } from "../models/models.module.js";
12
13
  import { OrgLockModule } from "../orgs/org-lock.js";
13
14
  import { ProvidersModule } from "../runtime/providers.js";
@@ -48,6 +49,8 @@ AgentsModule = __decorate([
48
49
  // creating from a template: the extension tools and the tier purposes (rulings P4-4, P4-5)
49
50
  ExtensionsModule,
50
51
  ModelsModule,
52
+ // the agent delete records `agent.deleted` deliveries
53
+ LifecycleHooksModule,
51
54
  ],
52
55
  providers: [
53
56
  AgentsService,
@@ -1,5 +1,6 @@
1
1
  import type { KernelSchemaDb } from "../db/kernel-schema.js";
2
2
  import { EvalBudget } from "../evals/budget.js";
3
+ import { LifecycleHooks } from "../extensions/lifecycle-hooks.js";
3
4
  import type { WriteActor } from "../identity/write-actor.js";
4
5
  import { KernelDb } from "../infra/database/kernel-db.js";
5
6
  import { TransactionHost } from "../infra/database/transaction-host.js";
@@ -92,6 +93,8 @@ export declare class AgentsService {
92
93
  private readonly evalBudget;
93
94
  /** Settles the agent's connector setup request when its pending connectors change (P4-7). */
94
95
  private readonly setupRequests;
96
+ /** Records `agent.deleted` for the subscribing plugins in the delete's transaction. */
97
+ private readonly lifecycle;
95
98
  constructor(db: KernelDb, lookup: AgentLookup, tools: Pick<ToolRegistry, "checkDisabled">,
96
99
  /**
97
100
  * Cancels the agent's pending skill requests: all of them when it is deleted, share requests
@@ -105,7 +108,9 @@ export declare class AgentsService {
105
108
  /** Cancels the deleted agent's running eval runs (in the delete's transaction). */
106
109
  evalBudget: Pick<EvalBudget, "cancelRuns">,
107
110
  /** Settles the agent's connector setup request when its pending connectors change (P4-7). */
108
- setupRequests: Pick<PendingConnectorRequests, "settleIn" | "retargetIn">);
111
+ setupRequests: Pick<PendingConnectorRequests, "settleIn" | "retargetIn">,
112
+ /** Records `agent.deleted` for the subscribing plugins in the delete's transaction. */
113
+ lifecycle: Pick<LifecycleHooks, "recordIn">);
109
114
  /**
110
115
  * Checks the turned-off tools and the policies (tools default-on spec §2): `disabledTools` must
111
116
  * name existing builtins, extensions and connectors (`ToolRegistry.checkDisabled`); `toolPolicies`
@@ -13,7 +13,9 @@ import { Inject, Injectable } from "@nestjs/common";
13
13
  import { sql } from "kysely";
14
14
  import { ApiError } from "../errors.js";
15
15
  import { EvalBudget } from "../evals/budget.js";
16
+ import { LifecycleHooks } from "../extensions/lifecycle-hooks.js";
16
17
  import { audit } from "../identity/audit.js";
18
+ import { afterCommit } from "../infra/database/after-commit.js";
17
19
  import { KernelDb } from "../infra/database/kernel-db.js";
18
20
  import { TransactionHost } from "../infra/database/transaction-host.js";
19
21
  import { Transactional } from "../infra/database/transactional.decorator.js";
@@ -279,6 +281,7 @@ let AgentsService = class AgentsService {
279
281
  txHost;
280
282
  evalBudget;
281
283
  setupRequests;
284
+ lifecycle;
282
285
  constructor(db, lookup, tools,
283
286
  /**
284
287
  * Cancels the agent's pending skill requests: all of them when it is deleted, share requests
@@ -292,7 +295,9 @@ let AgentsService = class AgentsService {
292
295
  /** Cancels the deleted agent's running eval runs (in the delete's transaction). */
293
296
  evalBudget,
294
297
  /** Settles the agent's connector setup request when its pending connectors change (P4-7). */
295
- setupRequests) {
298
+ setupRequests,
299
+ /** Records `agent.deleted` for the subscribing plugins in the delete's transaction. */
300
+ lifecycle) {
296
301
  this.db = db;
297
302
  this.lookup = lookup;
298
303
  this.tools = tools;
@@ -302,6 +307,7 @@ let AgentsService = class AgentsService {
302
307
  this.txHost = txHost;
303
308
  this.evalBudget = evalBudget;
304
309
  this.setupRequests = setupRequests;
310
+ this.lifecycle = lifecycle;
305
311
  }
306
312
  /**
307
313
  * Checks the turned-off tools and the policies (tools default-on spec §2): `disabledTools` must
@@ -746,6 +752,8 @@ let AgentsService = class AgentsService {
746
752
  });
747
753
  // 评测集的 agent 删除后其评测运行不再花钱:显式取消(审计带原因)
748
754
  await this.evalBudget.cancelRuns({ orgId, agentId }, { accountId: actorAccountId, ...(actorTokenId !== undefined && { tokenId: actorTokenId }) }, "agent_deleted");
755
+ // plugins learn of the delete durably: owed here, delivered by the outbox after the commit
756
+ await this.lifecycle.recordIn("agent.deleted", { orgId, agentId });
749
757
  // joins this transaction (mandatory: it relies on the agent row lock taken above)
750
758
  return this.skillChanges.cancelPendingForAgent(orgId, agentId, actorAccountId, "agent_deleted", actorTokenId);
751
759
  }
@@ -907,6 +915,7 @@ AgentsService = __decorate([
907
915
  __param(5, Inject(ProviderRegistry)),
908
916
  __param(6, Inject(TransactionHost)),
909
917
  __param(7, Inject(EvalBudget)),
910
- __param(8, Inject(PendingConnectorRequests))
918
+ __param(8, Inject(PendingConnectorRequests)),
919
+ __param(9, Inject(LifecycleHooks))
911
920
  ], AgentsService);
912
921
  export { AgentsService };
@@ -329,7 +329,7 @@ export async function planFromTemplate(db, orgId, row, opts) {
329
329
  }
330
330
  if (describesSubagents)
331
331
  listed.add(AGENT_TOOL);
332
- // `TaskOutput` / `TaskStop` follow `Bash`
332
+ // `TaskOutput` / `TaskStop` / `TaskList` follow `Bash`
333
333
  for (const name of AGENT_BUILTIN_NAMES)
334
334
  if (!listed.has(name))
335
335
  offBuiltin(name);
@@ -1,6 +1,7 @@
1
1
  import { EventLog } from "../conversations/event-log.js";
2
2
  import { TransactionHost } from "../infra/database/transaction-host.js";
3
3
  import { KernelEvents } from "../infra/events/kernel-events.js";
4
+ import { OutboxService } from "../infra/outbox/outbox.service.js";
4
5
  import { type BackgroundTaskRow, BackgroundTaskStore } from "./store.js";
5
6
  /** Where a task ends (as {@link BackgroundTaskStore.finish} takes it). */
6
7
  export type BackgroundFinish = Parameters<BackgroundTaskStore["finish"]>[1];
@@ -19,7 +20,8 @@ export declare const finishedEventKey: (taskId: string) => string;
19
20
  * task (two pollers, a poll and a stop) exactly one writes it. After the commit: the log's notify,
20
21
  * the `changed: "background"` frame (to the owner and, for a sub-agent's task, the conversation
21
22
  * that owns the sandbox, whose panel lists it too) and the `background_task.finished` domain event
22
- * (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module).
23
+ * (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module). A
24
+ * finish that may wake the conversation also owes the ensure-run backstop in the transaction.
23
25
  *
24
26
  * Holds no lock and runs no sandbox command: the caller reads `lastLines` before.
25
27
  */
@@ -28,7 +30,8 @@ export declare class BackgroundTaskFinisher {
28
30
  private readonly eventLog;
29
31
  private readonly events;
30
32
  readonly txHost: TransactionHost;
31
- constructor(store: Pick<BackgroundTaskStore, "finish">, eventLog: EventLog, events: KernelEvents, txHost: TransactionHost);
33
+ private readonly outbox;
34
+ constructor(store: Pick<BackgroundTaskStore, "finish">, eventLog: EventLog, events: KernelEvents, txHost: TransactionHost, outbox: Pick<OutboxService, "add">);
32
35
  /**
33
36
  * Finishes `task` as `to` with its last output lines (cut to their last 4 000 characters);
34
37
  * `reported` when a tool call already told the model in its run. False (nothing written) when the
@@ -13,6 +13,8 @@ import { afterCommit } from "../infra/database/after-commit.js";
13
13
  import { TransactionHost } from "../infra/database/transaction-host.js";
14
14
  import { Transactional } from "../infra/database/transactional.decorator.js";
15
15
  import { KernelEvents } from "../infra/events/kernel-events.js";
16
+ import { OutboxService } from "../infra/outbox/outbox.service.js";
17
+ import { oweEnsureRun } from "../runtime/run-jobs.js";
16
18
  import { taskOutputFile } from "./launch.js";
17
19
  import { LAST_LINES_MAX_CHARS } from "./session.js";
18
20
  import { BackgroundTaskStore } from "./store.js";
@@ -25,7 +27,8 @@ export const finishedEventKey = (taskId) => `background_task_finished:${taskId}`
25
27
  * task (two pollers, a poll and a stop) exactly one writes it. After the commit: the log's notify,
26
28
  * the `changed: "background"` frame (to the owner and, for a sub-agent's task, the conversation
27
29
  * that owns the sandbox, whose panel lists it too) and the `background_task.finished` domain event
28
- * (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module).
30
+ * (`BackgroundWake` wakes an idle conversation; it lives in the runtime, above this module). A
31
+ * finish that may wake the conversation also owes the ensure-run backstop in the transaction.
29
32
  *
30
33
  * Holds no lock and runs no sandbox command: the caller reads `lastLines` before.
31
34
  */
@@ -34,11 +37,13 @@ let BackgroundTaskFinisher = class BackgroundTaskFinisher {
34
37
  eventLog;
35
38
  events;
36
39
  txHost;
37
- constructor(store, eventLog, events, txHost) {
40
+ outbox;
41
+ constructor(store, eventLog, events, txHost, outbox) {
38
42
  this.store = store;
39
43
  this.eventLog = eventLog;
40
44
  this.events = events;
41
45
  this.txHost = txHost;
46
+ this.outbox = outbox;
42
47
  }
43
48
  /**
44
49
  * Finishes `task` as `to` with its last output lines (cut to their last 4 000 characters);
@@ -71,6 +76,11 @@ let BackgroundTaskFinisher = class BackgroundTaskFinisher {
71
76
  },
72
77
  },
73
78
  ]);
79
+ // a finish that may wake the conversation owes the ensure-run backstop with its event: the
80
+ // wake after the commit (`BackgroundWake`) may never happen (transactional outbox spec §6)
81
+ if (event && !reported && opts.stoppedBy === undefined) {
82
+ await oweEnsureRun(this.outbox, task.conversationId, event.seq, task.orgId);
83
+ }
74
84
  const conversations = [...new Set([task.conversationId, task.sandboxConversationId])];
75
85
  afterCommit(async () => {
76
86
  if (event)
@@ -90,6 +100,7 @@ BackgroundTaskFinisher = __decorate([
90
100
  __param(0, Inject(BackgroundTaskStore)),
91
101
  __param(1, Inject(EventLog)),
92
102
  __param(2, Inject(KernelEvents)),
93
- __param(3, Inject(TransactionHost))
103
+ __param(3, Inject(TransactionHost)),
104
+ __param(4, Inject(OutboxService))
94
105
  ], BackgroundTaskFinisher);
95
106
  export { BackgroundTaskFinisher };
@@ -70,7 +70,8 @@ export declare const GROUP_LAUNCHER: string;
70
70
  * `setsid nohup sh -c 'timeout -s KILL <seconds> …'` and the sid is `$!`, the pid `setsid` started;
71
71
  * elsewhere (macOS: no `setsid`, no `timeout`, no `pgrep -s`) {@link GROUP_LAUNCHER} runs it in a
72
72
  * process group of its own, watched by the launcher, and writes the sid (the group id) itself,
73
- * which the launch waits for (up to 10 s). An
73
+ * which the launch waits for (up to 10 s). The script starts with `BACKGROUND_LAUNCH_LINE`, so a
74
+ * local device, which kills what any other exec leaves running, leaves the task alone. An
74
75
  * environment without one of the needed programs fails with a readable error on stderr and exit
75
76
  * code 127, before anything starts. `id` must be a task id and `seconds` a positive integer (both
76
77
  * go into the script unquoted).
@@ -1,5 +1,5 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { DEFAULT_SANDBOX_ROOTS } from "@capybara-hq/plugin-sdk";
2
+ import { BACKGROUND_LAUNCH_LINE, DEFAULT_SANDBOX_ROOTS } from "@capybara-hq/plugin-sdk";
3
3
  /**
4
4
  * Launching a background Bash task (spec 2026-11-05-background-bash-design §4.2): the task id, the
5
5
  * one short exec that starts the command detached from the exec, and the model-visible result.
@@ -112,7 +112,8 @@ export const GROUP_LAUNCHER = [
112
112
  * `setsid nohup sh -c 'timeout -s KILL <seconds> …'` and the sid is `$!`, the pid `setsid` started;
113
113
  * elsewhere (macOS: no `setsid`, no `timeout`, no `pgrep -s`) {@link GROUP_LAUNCHER} runs it in a
114
114
  * process group of its own, watched by the launcher, and writes the sid (the group id) itself,
115
- * which the launch waits for (up to 10 s). An
115
+ * which the launch waits for (up to 10 s). The script starts with `BACKGROUND_LAUNCH_LINE`, so a
116
+ * local device, which kills what any other exec leaves running, leaves the task alone. An
116
117
  * environment without one of the needed programs fails with a readable error on stderr and exit
117
118
  * code 127, before anything starts. `id` must be a task id and `seconds` a positive integer (both
118
119
  * go into the script unquoted).
@@ -127,6 +128,8 @@ export function launchScript(id, command, seconds) {
127
128
  const t = `${TASKS_DIR}/${id}`;
128
129
  const need = (list) => `for c in ${list.join(" ")}; do command -v "$c" >/dev/null 2>&1 || { echo "Background tasks need ${list.join(", ")} in this environment; $c is missing." >&2; exit 127; }; done`;
129
130
  return [
131
+ // first: a local device kills what an exec leaves running, except a launch's detached task
132
+ BACKGROUND_LAUNCH_LINE,
130
133
  "set -e",
131
134
  SESSION_MODE_SCRIPT,
132
135
  `if [ "$pg" = -s ]; then ${need(REQUIRED_SESSION)}; else ${need(REQUIRED_GROUP)}; fi`,
@@ -137,6 +137,14 @@ export declare class BackgroundTaskStore {
137
137
  runningStarted(): Promise<BackgroundTaskRow[]>;
138
138
  /** The running tasks one conversation owns (not those of its sub-agents), oldest first. */
139
139
  runningOwnedBy(conversationId: string): Promise<BackgroundTaskRow[]>;
140
+ /**
141
+ * The finished tasks one conversation owns (not those of its sub-agents), the most recently
142
+ * finished first, at most `limit` of them, with how many it owns in all (`TaskList`).
143
+ */
144
+ finishedOwnedBy(conversationId: string, limit: number): Promise<{
145
+ rows: BackgroundTaskRow[];
146
+ total: number;
147
+ }>;
140
148
  /** The running tasks of one root conversation's tree (what `maxTasks` limits). */
141
149
  countRunning(sandboxConversationId: string): Promise<number>;
142
150
  /** The tasks owned by any of the conversations, newest first. */
@@ -258,6 +258,30 @@ let BackgroundTaskStore = class BackgroundTaskStore {
258
258
  .execute();
259
259
  return rows.map(toRow);
260
260
  }
261
+ /**
262
+ * The finished tasks one conversation owns (not those of its sub-agents), the most recently
263
+ * finished first, at most `limit` of them, with how many it owns in all (`TaskList`).
264
+ */
265
+ async finishedOwnedBy(conversationId, limit) {
266
+ const [rows, count] = await Promise.all([
267
+ this.db
268
+ .selectFrom("background_tasks")
269
+ .selectAll()
270
+ .where("conversation_id", "=", conversationId)
271
+ .where("status", "<>", "running")
272
+ .orderBy("finished_at", "desc")
273
+ .orderBy("id", "desc")
274
+ .limit(limit)
275
+ .execute(),
276
+ this.db
277
+ .selectFrom("background_tasks")
278
+ .select((eb) => eb.fn.countAll().as("n"))
279
+ .where("conversation_id", "=", conversationId)
280
+ .where("status", "<>", "running")
281
+ .executeTakeFirstOrThrow(),
282
+ ]);
283
+ return { rows: rows.map(toRow), total: Number(count.n) };
284
+ }
261
285
  /** The running tasks of one root conversation's tree (what `maxTasks` limits). */
262
286
  async countRunning(sandboxConversationId) {
263
287
  const r = await this.db
@@ -5,12 +5,13 @@ import { type ClientBuildSummary, ClientBuilds } from "../client/client-builds.s
5
5
  import { PluginGuides, type RenderedSetupGuide } from "../extensions/plugin-guides.js";
6
6
  import { PluginIcons } from "../extensions/plugin-icons.js";
7
7
  import { type Principal } from "../identity/principal.js";
8
- import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
8
+ import { AdminCatalogGuideQuery, CatalogImportUpdateBody, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
9
9
  import { AppearanceApplyBody } from "./appearance.schemas.js";
10
10
  import { type AppearanceResult, AppearanceService } from "./appearance.service.js";
11
11
  import { type CatalogItemDetail, type CatalogItemView, CatalogService, type PermissionsMismatch } from "./catalog.service.js";
12
12
  import { CatalogScopeService, type ScopePreview } from "./catalog-scope.service.js";
13
13
  import { OrgCatalogService } from "./org-catalog.service.js";
14
+ import { PlatformImportUpdate, type PlatformImportUpdateResult } from "./platform-import-update.js";
14
15
  import { type PluginConfirmResult, PluginImport, type PluginReview } from "./plugin-import.js";
15
16
  import { PlatformPluginUpdater, type PlatformUpdatePreview, type PlatformUpdateResult } from "./plugin-upgrade.js";
16
17
  declare const ConfirmBody: z.ZodObject<{
@@ -41,11 +42,12 @@ export declare class AdminCatalogController {
41
42
  private readonly orgCatalog;
42
43
  private readonly scope;
43
44
  private readonly updater;
45
+ private readonly importUpdate;
44
46
  private readonly icons;
45
47
  private readonly appearance;
46
48
  private readonly clientBuilds;
47
49
  private readonly guides;
48
- constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, icons: PluginIcons, appearance: AppearanceService, clientBuilds: ClientBuilds, guides: PluginGuides);
50
+ constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, importUpdate: PlatformImportUpdate, icons: PluginIcons, appearance: AppearanceService, clientBuilds: ClientBuilds, guides: PluginGuides);
49
51
  /**
50
52
  * Prepares the import of an uploaded plugin (an npm-pack tgz as the raw body,
51
53
  * `application/octet-stream`, at most `packages.maxBytes`): reads and checks the whole plugin
@@ -108,6 +110,23 @@ export declare class AdminCatalogController {
108
110
  * is an unknown field (400 `validation_failed`).
109
111
  */
110
112
  confirm(principal: Principal, stagingId: string, body: z.infer<typeof ConfirmBody>): Promise<PluginConfirmResult>;
113
+ /**
114
+ * What confirming a staged new version of an installed platform plugin would do as the platform
115
+ * update (`PlatformImportUpdate`, the one 更新到 wizard): the update preview of the staged
116
+ * version, nothing written (cancelling the wizard leaves only the staging row). Not a platform
117
+ * plugin yet -> 409 `plugin.upgrade_target_invalid` (reason `not_installed`); staging missing ->
118
+ * 404 `plugin.staging_not_found`; otherwise as `items/:id/update/preview`.
119
+ */
120
+ importUpdatePreview(stagingId: string): Promise<PlatformUpdatePreview>;
121
+ /**
122
+ * Imports the staged version and updates the platform plugin to it, confirmed with the import
123
+ * review's `reviewHash` and the update preview's `diffHash` (201 `{ item, update }`). Stale review
124
+ * -> 409 `plugin.review_stale`, stale preview -> 409 `plugin.upgrade_stale`, another update
125
+ * running -> 409 `plugin.install_in_progress`: nothing written. The update failing after the
126
+ * import -> 409 `plugin.imported_not_updated` (the version stays in the catalog, the platform on
127
+ * its version, the extension's approval put back; details name the cause).
128
+ */
129
+ importAndUpdate(principal: Principal, stagingId: string, body: z.infer<typeof CatalogImportUpdateBody>): Promise<PlatformImportUpdateResult>;
111
130
  /**
112
131
  * The item list (`includeDeleted=true` includes deleted items). Paging: `limit` (default 200, at
113
132
  * most 1000) and `offset`; `nextOffset` is the next page's offset, null when there is none.
@@ -16,13 +16,14 @@ import { PluginIcons } from "../extensions/plugin-icons.js";
16
16
  import { CurrentPrincipal, patTokenId, requireUser, SuperAdmin, } from "../identity/principal.js";
17
17
  import { createZodDto } from "../infra/validation/create-zod-dto.js";
18
18
  import { ZBody, ZQuery } from "../infra/validation/zod-params.js";
19
- import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
19
+ import { AdminCatalogGuideQuery, CatalogImportUpdateBody, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
20
20
  import { AppearanceApplyBody } from "./appearance.schemas.js";
21
21
  import { AppearanceService, suggestedAppearanceOf, } from "./appearance.service.js";
22
22
  import { CatalogService, } from "./catalog.service.js";
23
23
  import { CatalogScopeService } from "./catalog-scope.service.js";
24
24
  import { sendCatalogIcon } from "./org-catalog.controller.js";
25
25
  import { OrgCatalogService } from "./org-catalog.service.js";
26
+ import { PlatformImportUpdate } from "./platform-import-update.js";
26
27
  import { PluginImport } from "./plugin-import.js";
27
28
  import { PlatformPluginUpdater, } from "./plugin-upgrade.js";
28
29
  const ConfirmBody = z
@@ -66,6 +67,8 @@ class CatalogUpdatePreviewBodyDto extends createZodDto(CatalogUpdatePreviewBody,
66
67
  }
67
68
  class CatalogUpdateBodyDto extends createZodDto(CatalogUpdateBody, "CatalogUpdateBody") {
68
69
  }
70
+ class CatalogImportUpdateBodyDto extends createZodDto(CatalogImportUpdateBody, "CatalogImportUpdateBody") {
71
+ }
69
72
  class AppearanceApplyBodyDto extends createZodDto(AppearanceApplyBody, "AppearanceApplyBody") {
70
73
  }
71
74
  /**
@@ -80,16 +83,18 @@ let AdminCatalogController = class AdminCatalogController {
80
83
  orgCatalog;
81
84
  scope;
82
85
  updater;
86
+ importUpdate;
83
87
  icons;
84
88
  appearance;
85
89
  clientBuilds;
86
90
  guides;
87
- constructor(catalog, pluginImport, orgCatalog, scope, updater, icons, appearance, clientBuilds, guides) {
91
+ constructor(catalog, pluginImport, orgCatalog, scope, updater, importUpdate, icons, appearance, clientBuilds, guides) {
88
92
  this.catalog = catalog;
89
93
  this.pluginImport = pluginImport;
90
94
  this.orgCatalog = orgCatalog;
91
95
  this.scope = scope;
92
96
  this.updater = updater;
97
+ this.importUpdate = importUpdate;
93
98
  this.icons = icons;
94
99
  this.appearance = appearance;
95
100
  this.clientBuilds = clientBuilds;
@@ -169,6 +174,28 @@ let AdminCatalogController = class AdminCatalogController {
169
174
  ...(body.orgs !== undefined && { orgs: body.orgs }),
170
175
  }, actorOpts(actor));
171
176
  }
177
+ /**
178
+ * What confirming a staged new version of an installed platform plugin would do as the platform
179
+ * update (`PlatformImportUpdate`, the one 更新到 wizard): the update preview of the staged
180
+ * version, nothing written (cancelling the wizard leaves only the staging row). Not a platform
181
+ * plugin yet -> 409 `plugin.upgrade_target_invalid` (reason `not_installed`); staging missing ->
182
+ * 404 `plugin.staging_not_found`; otherwise as `items/:id/update/preview`.
183
+ */
184
+ importUpdatePreview(stagingId) {
185
+ return this.importUpdate.preview(stagingId);
186
+ }
187
+ /**
188
+ * Imports the staged version and updates the platform plugin to it, confirmed with the import
189
+ * review's `reviewHash` and the update preview's `diffHash` (201 `{ item, update }`). Stale review
190
+ * -> 409 `plugin.review_stale`, stale preview -> 409 `plugin.upgrade_stale`, another update
191
+ * running -> 409 `plugin.install_in_progress`: nothing written. The update failing after the
192
+ * import -> 409 `plugin.imported_not_updated` (the version stays in the catalog, the platform on
193
+ * its version, the extension's approval put back; details name the cause).
194
+ */
195
+ importAndUpdate(principal, stagingId, body) {
196
+ const actor = requireUser(principal);
197
+ return this.importUpdate.confirm(actor.account.id, stagingId, body, actorOpts(actor));
198
+ }
172
199
  /**
173
200
  * The item list (`includeDeleted=true` includes deleted items). Paging: `limit` (default 200, at
174
201
  * most 1000) and `offset`; `nextOffset` is the next page's offset, null when there is none.
@@ -367,6 +394,17 @@ __decorate([
367
394
  __param(1, Param("stagingId")),
368
395
  __param(2, ZBody(CatalogImportConfirmBody))
369
396
  ], AdminCatalogController.prototype, "confirm", null);
397
+ __decorate([
398
+ Get("imports/:stagingId/update-preview"),
399
+ __param(0, Param("stagingId"))
400
+ ], AdminCatalogController.prototype, "importUpdatePreview", null);
401
+ __decorate([
402
+ Post("imports/:stagingId/update"),
403
+ HttpCode(201),
404
+ __param(0, CurrentPrincipal()),
405
+ __param(1, Param("stagingId")),
406
+ __param(2, ZBody(CatalogImportUpdateBodyDto))
407
+ ], AdminCatalogController.prototype, "importAndUpdate", null);
370
408
  __decorate([
371
409
  Get("items"),
372
410
  __param(0, ZQuery(CatalogItemsQueryDto))
@@ -457,9 +495,10 @@ AdminCatalogController = __decorate([
457
495
  __param(2, Inject(OrgCatalogService)),
458
496
  __param(3, Inject(CatalogScopeService)),
459
497
  __param(4, Inject(PlatformPluginUpdater)),
460
- __param(5, Inject(PluginIcons)),
461
- __param(6, Inject(AppearanceService)),
462
- __param(7, Inject(ClientBuilds)),
463
- __param(8, Inject(PluginGuides))
498
+ __param(5, Inject(PlatformImportUpdate)),
499
+ __param(6, Inject(PluginIcons)),
500
+ __param(7, Inject(AppearanceService)),
501
+ __param(8, Inject(ClientBuilds)),
502
+ __param(9, Inject(PluginGuides))
464
503
  ], AdminCatalogController);
465
504
  export { AdminCatalogController };