@capybara-hq/kernel 0.1.0-rc.24 → 0.1.0-rc.26

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 (198) hide show
  1. package/dist/admin/admin.module.js +2 -0
  2. package/dist/admin/health.service.d.ts +2 -2
  3. package/dist/admin/health.service.js +6 -2
  4. package/dist/admin/outbox-dead.service.d.ts +7 -3
  5. package/dist/admin/outbox-dead.service.js +17 -6
  6. package/dist/admin/overview.service.d.ts +6 -6
  7. package/dist/admin/overview.service.js +7 -7
  8. package/dist/agents/agents.module.js +3 -0
  9. package/dist/agents/agents.service.d.ts +6 -1
  10. package/dist/agents/agents.service.js +11 -2
  11. package/dist/background/wake-rules.d.ts +5 -0
  12. package/dist/background/wake-rules.js +16 -5
  13. package/dist/catalog/catalog-import.module.js +0 -4
  14. package/dist/catalog/catalog-scope.service.d.ts +63 -26
  15. package/dist/catalog/catalog-scope.service.js +146 -71
  16. package/dist/catalog/catalog.module.js +4 -3
  17. package/dist/catalog/catalog.service.d.ts +11 -4
  18. package/dist/catalog/catalog.service.js +21 -5
  19. package/dist/catalog/cli.d.ts +4 -3
  20. package/dist/catalog/cli.js +8 -13
  21. package/dist/catalog/job-ids.d.ts +8 -20
  22. package/dist/catalog/job-ids.js +11 -16
  23. package/dist/catalog/marketplaces.service.d.ts +1 -1
  24. package/dist/catalog/org-plugin-uploads.d.ts +11 -4
  25. package/dist/catalog/org-plugin-uploads.js +21 -6
  26. package/dist/catalog/owned-items.d.ts +6 -13
  27. package/dist/catalog/owned-items.js +11 -29
  28. package/dist/catalog/owned-plugin-cleanup.d.ts +8 -17
  29. package/dist/catalog/owned-plugin-cleanup.js +12 -66
  30. package/dist/catalog/platform-components.d.ts +56 -34
  31. package/dist/catalog/platform-components.js +68 -78
  32. package/dist/catalog/plugin-import.d.ts +28 -25
  33. package/dist/catalog/plugin-import.js +90 -76
  34. package/dist/catalog/plugin-upgrade.d.ts +4 -4
  35. package/dist/catalog/plugin-upgrade.js +7 -19
  36. package/dist/catalog/scope-jobs.d.ts +59 -0
  37. package/dist/catalog/scope-jobs.js +65 -0
  38. package/dist/catalog/scope-sync-workers.d.ts +22 -0
  39. package/dist/catalog/scope-sync-workers.js +58 -2
  40. package/dist/catalog/scope-sync.d.ts +40 -65
  41. package/dist/catalog/scope-sync.js +114 -122
  42. package/dist/channels/channels.module.d.ts +9 -8
  43. package/dist/channels/channels.module.js +11 -10
  44. package/dist/channels/connections.service.d.ts +3 -3
  45. package/dist/channels/connections.service.js +6 -6
  46. package/dist/channels/deliver-job.d.ts +10 -3
  47. package/dist/channels/deliver-job.js +7 -3
  48. package/dist/channels/inbound.js +2 -2
  49. package/dist/channels/jobs.d.ts +11 -4
  50. package/dist/channels/jobs.js +18 -3
  51. package/dist/channels/outbound.d.ts +5 -2
  52. package/dist/channels/outbound.js +9 -2
  53. package/dist/channels/threads.d.ts +4 -3
  54. package/dist/channels/threads.js +4 -3
  55. package/dist/conversations/conversations.controller.d.ts +4 -2
  56. package/dist/conversations/conversations.controller.js +8 -4
  57. package/dist/conversations/conversations.service.d.ts +54 -9
  58. package/dist/conversations/conversations.service.js +94 -25
  59. package/dist/conversations/events.d.ts +27 -0
  60. package/dist/conversations/events.js +30 -1
  61. package/dist/conversations/source.d.ts +10 -0
  62. package/dist/conversations/source.js +17 -0
  63. package/dist/conversations/tree.d.ts +10 -0
  64. package/dist/conversations/tree.js +35 -0
  65. package/dist/db/kernel-schema.d.ts +19 -15
  66. package/dist/devices/devices.service.d.ts +25 -14
  67. package/dist/devices/devices.service.js +36 -30
  68. package/dist/evals/evals.module.js +5 -1
  69. package/dist/evals/jobs.d.ts +14 -6
  70. package/dist/evals/jobs.js +21 -19
  71. package/dist/evals/run-replay.d.ts +13 -2
  72. package/dist/evals/run-replay.js +28 -1
  73. package/dist/evals/runs.service.d.ts +5 -6
  74. package/dist/evals/runs.service.js +11 -33
  75. package/dist/evals/snapshot.d.ts +7 -1
  76. package/dist/evals/snapshot.js +2 -1
  77. package/dist/extensions/hooks.d.ts +22 -3
  78. package/dist/extensions/hooks.js +15 -1
  79. package/dist/extensions/lifecycle-hooks.d.ts +99 -0
  80. package/dist/extensions/lifecycle-hooks.js +273 -0
  81. package/dist/extensions/org-config.d.ts +13 -1
  82. package/dist/extensions/org-config.js +19 -2
  83. package/dist/extensions/permission-view.d.ts +9 -5
  84. package/dist/extensions/permission-view.js +9 -4
  85. package/dist/extensions/point-defaults.d.ts +28 -1
  86. package/dist/extensions/point-defaults.js +44 -13
  87. package/dist/inbox/inbox.service.d.ts +6 -20
  88. package/dist/inbox/inbox.service.js +0 -3
  89. package/dist/inbox/org-notices.d.ts +1 -1
  90. package/dist/inbox/platform-inbox.service.d.ts +3 -32
  91. package/dist/inbox/platform-inbox.service.js +5 -54
  92. package/dist/infra/outbox/outbox.service.d.ts +6 -0
  93. package/dist/infra/outbox/outbox.service.js +51 -17
  94. package/dist/infra/outbox/registry.d.ts +176 -0
  95. package/dist/infra/outbox/registry.js +183 -0
  96. package/dist/infra/queue/queue-names.d.ts +1 -1
  97. package/dist/infra/queue/queue-names.js +1 -0
  98. package/dist/local-devices/device-policy.service.d.ts +131 -26
  99. package/dist/local-devices/device-policy.service.js +341 -145
  100. package/dist/local-devices/machines.d.ts +17 -2
  101. package/dist/local-devices/machines.js +66 -5
  102. package/dist/local-devices/policy-op-jobs.d.ts +15 -0
  103. package/dist/local-devices/policy-op-jobs.js +12 -0
  104. package/dist/local-devices/policy-summary.d.ts +36 -3
  105. package/dist/local-devices/policy-summary.js +47 -1
  106. package/dist/orgs/directory-sync.js +1 -1
  107. package/dist/orgs/members.service.js +1 -1
  108. package/dist/orgs/offboarding.d.ts +50 -57
  109. package/dist/orgs/offboarding.js +117 -162
  110. package/dist/orgs/orgs.module.js +3 -0
  111. package/dist/orgs/orgs.service.d.ts +11 -5
  112. package/dist/orgs/orgs.service.js +19 -7
  113. package/dist/overrides.d.ts +7 -0
  114. package/dist/overrides.js +4 -0
  115. package/dist/platform/ops/conversations.ops.js +1 -1
  116. package/dist/platform/ops/inbox.ops.js +4 -20
  117. package/dist/platform/ops/platform.ops.d.ts +1 -0
  118. package/dist/platform/ops/platform.ops.js +6 -3
  119. package/dist/roles/worker-role.d.ts +10 -5
  120. package/dist/roles/worker-role.js +19 -9
  121. package/dist/roles/worker.module.js +2 -4
  122. package/dist/runtime/context/build.d.ts +3 -0
  123. package/dist/runtime/context/build.js +15 -0
  124. package/dist/runtime/context/plugin-context.d.ts +20 -0
  125. package/dist/runtime/context/plugin-context.js +30 -0
  126. package/dist/runtime/langgraph-loop.js +4 -0
  127. package/dist/runtime/loop.d.ts +8 -0
  128. package/dist/runtime/maintenance.d.ts +9 -4
  129. package/dist/runtime/maintenance.js +52 -13
  130. package/dist/runtime/model-call.d.ts +6 -1
  131. package/dist/runtime/model-call.js +1 -0
  132. package/dist/runtime/plugin-context.service.d.ts +75 -0
  133. package/dist/runtime/plugin-context.service.js +220 -0
  134. package/dist/runtime/run-context.service.d.ts +7 -3
  135. package/dist/runtime/run-context.service.js +12 -2
  136. package/dist/runtime/run-control.d.ts +6 -1
  137. package/dist/runtime/run-control.js +13 -0
  138. package/dist/runtime/run-finish.d.ts +2 -2
  139. package/dist/runtime/run-finish.js +11 -6
  140. package/dist/runtime/run-jobs.d.ts +21 -4
  141. package/dist/runtime/run-jobs.js +29 -6
  142. package/dist/runtime/run-orphan-check.job.d.ts +14 -11
  143. package/dist/runtime/run-orphan-check.job.js +16 -11
  144. package/dist/runtime/run-queue.d.ts +29 -24
  145. package/dist/runtime/run-queue.js +118 -57
  146. package/dist/runtime/run-status.d.ts +12 -0
  147. package/dist/runtime/run-status.js +21 -0
  148. package/dist/runtime/run-worker.d.ts +32 -3
  149. package/dist/runtime/run-worker.js +143 -21
  150. package/dist/runtime/runtime.module.js +2 -0
  151. package/dist/runtime/step-log.d.ts +6 -5
  152. package/dist/runtime/step-log.js +6 -5
  153. package/dist/runtime/subagents/dispatch.js +1 -0
  154. package/dist/runtime/subagents/skill-fork.js +3 -0
  155. package/dist/runtime/usage-report.d.ts +3 -1
  156. package/dist/runtime/usage-report.js +4 -2
  157. package/dist/runtime/waits.d.ts +16 -6
  158. package/dist/runtime/waits.js +37 -15
  159. package/dist/sandbox/jobs.d.ts +20 -10
  160. package/dist/sandbox/jobs.js +23 -17
  161. package/dist/schedules/fire.d.ts +25 -4
  162. package/dist/schedules/fire.js +87 -13
  163. package/dist/schedules/job-ids.d.ts +66 -17
  164. package/dist/schedules/job-ids.js +81 -13
  165. package/dist/schedules/run-tracker.js +2 -1
  166. package/dist/schedules/scan.job.d.ts +16 -35
  167. package/dist/schedules/scan.job.js +38 -147
  168. package/dist/schedules/scheduled-tasks.service.d.ts +6 -6
  169. package/dist/schedules/scheduled-tasks.service.js +17 -14
  170. package/dist/schedules/schedules.module.js +0 -4
  171. package/dist/skills/catalog.d.ts +7 -3
  172. package/dist/skills/catalog.js +12 -2
  173. package/dist/skills/changes.controller.d.ts +1 -1
  174. package/dist/skills/changes.controller.js +1 -1
  175. package/dist/tools/approvals.service.d.ts +111 -23
  176. package/dist/tools/approvals.service.js +326 -77
  177. package/dist/tools/builtins/sandbox/task-output.js +21 -6
  178. package/dist/tools/device-op-resolver.d.ts +40 -0
  179. package/dist/tools/device-op-resolver.js +121 -0
  180. package/dist/tools/network-asks.d.ts +1 -1
  181. package/dist/tools/network-asks.js +4 -3
  182. package/dist/tools/pipeline.d.ts +11 -2
  183. package/dist/tools/pipeline.js +5 -0
  184. package/dist/tools/questions.service.d.ts +15 -4
  185. package/dist/tools/questions.service.js +21 -19
  186. package/dist/tools/registry.d.ts +8 -1
  187. package/dist/tools/registry.js +9 -0
  188. package/dist/tools/tools.module.js +4 -0
  189. package/package.json +3 -3
  190. package/src/migrations/0121_drop_platform_migration_runs.sql +12 -0
  191. package/src/migrations/0122_drop_scheduled_task_runs_rechecked_at.sql +5 -0
  192. package/src/migrations/0123_pgvector.sql +27 -0
  193. package/src/migrations/0124_conversation_source.sql +36 -0
  194. package/src/migrations/0125_conversation_tree_stopped_at.sql +5 -0
  195. package/dist/catalog/platform-migration.d.ts +0 -115
  196. package/dist/catalog/platform-migration.js +0 -583
  197. package/dist/infra/queue/add-job-once.d.ts +0 -14
  198. package/dist/infra/queue/add-job-once.js +0 -16
@@ -8,11 +8,6 @@ import type { PlatformNoticeDetails } from "./platform-notices.js";
8
8
  export declare const PLATFORM_INBOX_MAX_ITEMS = 100;
9
9
  /** The most open scope sync failures one read takes. */
10
10
  export declare const SCOPE_SYNC_FAILURES_LIST_MAX = 200;
11
- /**
12
- * A platform components migration run unfinished this long after its start is stuck (its worker
13
- * stopped mid-run; a run takes seconds, and the next one starts at the next worker start or day).
14
- */
15
- export declare const MIGRATION_RUN_STUCK_MS: number;
16
11
  /**
17
12
  * An open failure of the plugin scope sync: its last attempt to install the plugin in the org, to
18
13
  * uninstall it, or to install the dependencies a platform update added (`dependencies`) failed,
@@ -34,18 +29,6 @@ export interface ScopeSyncFailureView {
34
29
  message: string;
35
30
  failedAt: string;
36
31
  }
37
- /**
38
- * The latest platform components migration run (`platform_migration_runs`) when it needs a look:
39
- * finished with catalog items whose components could not be written (`itemsFailed`,
40
- * `<name>@<version>`), or `stuck` (unfinished {@link MIGRATION_RUN_STUCK_MS} after its start).
41
- */
42
- export interface MigrationRunView {
43
- id: string;
44
- startedAt: string;
45
- finishedAt: string | null;
46
- stuck: boolean;
47
- itemsFailed: string[];
48
- }
49
32
  /**
50
33
  * One item of the super admin's inbox (by `type`). Nothing is decided in the inbox: each item is
51
34
  * acted on where it lives (the web links to it).
@@ -56,7 +39,6 @@ export interface MigrationRunView {
56
39
  * - `org_upload_pending`: an org-owned plugin whose uploaded version (with an extension) waits for
57
40
  * the super admin in 待确认 (ruling P3-22; confirmed or rejected there), `id` = the item's;
58
41
  * - `scope_sync_failed`: an open scope sync failure, `id` = `<itemId>/<orgId>`;
59
- * - `platform_migration`: the latest migration run, failed items or stuck, `id` = the run's;
60
42
  * - `ownership_transferred`: a deleted org's shared item now belongs to the platform, until a
61
43
  * super admin dismisses it (`POST admin/inbox/notices/:id/dismiss`).
62
44
  */
@@ -80,11 +62,6 @@ export type PlatformInboxItem = {
80
62
  id: string;
81
63
  createdAt: string;
82
64
  failure: ScopeSyncFailureView;
83
- } | {
84
- type: "platform_migration";
85
- id: string;
86
- createdAt: string;
87
- run: MigrationRunView;
88
65
  } | {
89
66
  type: "ownership_transferred";
90
67
  id: string;
@@ -92,7 +69,7 @@ export type PlatformInboxItem = {
92
69
  notice: PlatformNoticeView;
93
70
  };
94
71
  /** Every {@link PlatformInboxItem} type, in the order the admin overview lists them. */
95
- export declare const PLATFORM_INBOX_TYPES: readonly ["catalog_request", "permission_confirmation", "org_upload_pending", "scope_sync_failed", "platform_migration", "ownership_transferred"];
72
+ export declare const PLATFORM_INBOX_TYPES: readonly ["catalog_request", "permission_confirmation", "org_upload_pending", "scope_sync_failed", "ownership_transferred"];
96
73
  /** How many items of each type wait: every type, zeros included. */
97
74
  export type PlatformInboxCounts = Record<PlatformInboxItem["type"], number>;
98
75
  /** An open platform notice (`platform_notices`, kind `ownership_transferred`). */
@@ -116,8 +93,8 @@ export interface PlatformInboxView {
116
93
  /**
117
94
  * The super admin's inbox (plugin scope spec §5.1 rule 5, §13.5): what waits on the platform,
118
95
  * gathered from the sources the admin pages read (the 待确认 tab's requests and permission
119
- * confirmations), plus the scope sync's open failures and the platform components migration's
120
- * latest run. Stateless, read live from PG.
96
+ * confirmations), plus the scope sync's open failures and the platform notices. Stateless, read
97
+ * live from PG.
121
98
  */
122
99
  export declare class PlatformInboxService {
123
100
  private readonly requests;
@@ -148,10 +125,4 @@ export declare class PlatformInboxService {
148
125
  private countScopeSyncFailures;
149
126
  /** The open scope sync failures ({@link failureRows}), newest first. */
150
127
  private scopeSyncFailures;
151
- /**
152
- * The latest migration run when it needs a look (see {@link MigrationRunView}); null when it
153
- * finished without failed items, is still running, or there was none. An earlier run's failure
154
- * is not shown: each run tries every unwritten item again.
155
- */
156
- private migrationRun;
157
128
  }
@@ -17,11 +17,6 @@ import { KernelDb } from "../infra/database/kernel-db.js";
17
17
  export const PLATFORM_INBOX_MAX_ITEMS = 100;
18
18
  /** The most open scope sync failures one read takes. */
19
19
  export const SCOPE_SYNC_FAILURES_LIST_MAX = 200;
20
- /**
21
- * A platform components migration run unfinished this long after its start is stuck (its worker
22
- * stopped mid-run; a run takes seconds, and the next one starts at the next worker start or day).
23
- */
24
- export const MIGRATION_RUN_STUCK_MS = 60 * 60_000;
25
20
  /** Plugin install statuses of a plugin that is on in the org. */
26
21
  const LIVE_INSTALL = ["installing", "installed", "upgrading"];
27
22
  /** Every {@link PlatformInboxItem} type, in the order the admin overview lists them. */
@@ -30,14 +25,13 @@ export const PLATFORM_INBOX_TYPES = [
30
25
  "permission_confirmation",
31
26
  "org_upload_pending",
32
27
  "scope_sync_failed",
33
- "platform_migration",
34
28
  "ownership_transferred",
35
29
  ];
36
30
  /**
37
31
  * The super admin's inbox (plugin scope spec §5.1 rule 5, §13.5): what waits on the platform,
38
32
  * gathered from the sources the admin pages read (the 待确认 tab's requests and permission
39
- * confirmations), plus the scope sync's open failures and the platform components migration's
40
- * latest run. Stateless, read live from PG.
33
+ * confirmations), plus the scope sync's open failures and the platform notices. Stateless, read
34
+ * live from PG.
41
35
  */
42
36
  let PlatformInboxService = class PlatformInboxService {
43
37
  requests;
@@ -49,13 +43,12 @@ let PlatformInboxService = class PlatformInboxService {
49
43
  this.kdb = kdb;
50
44
  }
51
45
  async list() {
52
- const [requests, requestCount, pending, failures, failureCount, run, notices, noticeCount] = await Promise.all([
46
+ const [requests, requestCount, pending, failures, failureCount, notices, noticeCount] = await Promise.all([
53
47
  this.requests.listDeployment(),
54
48
  this.requests.countPendingDeployment(),
55
49
  this.catalog.list({ pending: true }),
56
50
  this.scopeSyncFailures(),
57
51
  this.countScopeSyncFailures(),
58
- this.migrationRun(),
59
52
  this.notices(),
60
53
  this.countNotices(),
61
54
  ]);
@@ -84,16 +77,6 @@ let PlatformInboxService = class PlatformInboxService {
84
77
  createdAt: n.createdAt,
85
78
  notice: n,
86
79
  })),
87
- ...(run === null
88
- ? []
89
- : [
90
- {
91
- type: "platform_migration",
92
- id: run.id,
93
- createdAt: run.finishedAt ?? run.startedAt,
94
- run,
95
- },
96
- ]),
97
80
  ];
98
81
  // newest first; equal times by id (a stable order)
99
82
  all.sort((a, b) => a.createdAt !== b.createdAt
@@ -111,7 +94,6 @@ let PlatformInboxService = class PlatformInboxService {
111
94
  permission_confirmation: pending.length - orgUploads,
112
95
  org_upload_pending: orgUploads,
113
96
  scope_sync_failed: failureCount,
114
- platform_migration: run === null ? 0 : 1,
115
97
  ownership_transferred: noticeCount,
116
98
  };
117
99
  const total = Object.values(byType).reduce((a, b) => a + b, 0);
@@ -123,14 +105,13 @@ let PlatformInboxService = class PlatformInboxService {
123
105
  * requests and the failures; the permission confirmations are the catalog's pending list).
124
106
  */
125
107
  async count() {
126
- const [requests, pending, failures, run, notices] = await Promise.all([
108
+ const [requests, pending, failures, notices] = await Promise.all([
127
109
  this.requests.countPendingDeployment(),
128
110
  this.catalog.list({ pending: true }),
129
111
  this.countScopeSyncFailures(),
130
- this.migrationRun(),
131
112
  this.countNotices(),
132
113
  ]);
133
- return requests + pending.length + failures + (run === null ? 0 : 1) + notices;
114
+ return requests + pending.length + failures + notices;
134
115
  }
135
116
  async countNotices() {
136
117
  const r = await this.kdb.db
@@ -240,36 +221,6 @@ let PlatformInboxService = class PlatformInboxService {
240
221
  failedAt: r.failed_at.toISOString(),
241
222
  }));
242
223
  }
243
- /**
244
- * The latest migration run when it needs a look (see {@link MigrationRunView}); null when it
245
- * finished without failed items, is still running, or there was none. An earlier run's failure
246
- * is not shown: each run tries every unwritten item again.
247
- */
248
- async migrationRun() {
249
- const run = await this.kdb.db
250
- .selectFrom("platform_migration_runs")
251
- .select(["id", "started_at", "finished_at", "stats"])
252
- .orderBy("started_at", "desc")
253
- .orderBy("id", "desc")
254
- .limit(1)
255
- .executeTakeFirst();
256
- if (run === undefined)
257
- return null;
258
- const failed = run.stats.itemsFailed;
259
- const itemsFailed = Array.isArray(failed)
260
- ? failed.filter((x) => typeof x === "string")
261
- : [];
262
- const stuck = run.finished_at === null && run.started_at.getTime() < Date.now() - MIGRATION_RUN_STUCK_MS;
263
- if (!stuck && (run.finished_at === null || itemsFailed.length === 0))
264
- return null;
265
- return {
266
- id: run.id,
267
- startedAt: run.started_at.toISOString(),
268
- finishedAt: run.finished_at?.toISOString() ?? null,
269
- stuck,
270
- itemsFailed,
271
- };
272
- }
273
224
  };
274
225
  PlatformInboxService = __decorate([
275
226
  Injectable(),
@@ -46,6 +46,12 @@ export declare class OutboxService {
46
46
  * conflicts, else logs an error. Undefined data is stored as JSON null.
47
47
  */
48
48
  add<T>(job: OutboxJob<T>): Promise<boolean>;
49
+ /**
50
+ * {@link add} for many jobs in one multi-row insert per {@link ADD_MANY_CHUNK} jobs (an eval
51
+ * run's cases). A job whose (queue, jobId) is already owed is skipped without comparing its data.
52
+ * Returns how many rows it inserted.
53
+ */
54
+ addMany<T>(jobs: readonly OutboxJob<T>[]): Promise<number>;
49
55
  /** Collects `id` for its transaction; the first id registers the transaction's one hint. */
50
56
  private deliverAfterCommit;
51
57
  }
@@ -21,6 +21,29 @@ export const OUTBOX_FAST_PATH = Symbol("OUTBOX_FAST_PATH");
21
21
  * logging an error (spec §4, designer's call: "throws in tests, logs in production").
22
22
  */
23
23
  export const OUTBOX_STRICT_CONFLICTS = Symbol("OUTBOX_STRICT_CONFLICTS");
24
+ /** Jobs per insert statement of {@link OutboxService.addMany} (6 parameters each). */
25
+ const ADD_MANY_CHUNK = 1000;
26
+ /** The row of `job` (throws on a job id with `:`). */
27
+ function rowOf(job) {
28
+ if (job.jobId.includes(":")) {
29
+ throw new Error(`outbox job id "${job.jobId}" must not contain ":" (BullMQ uses it as its key separator); ` +
30
+ 'join the id\'s parts with "-" instead');
31
+ }
32
+ return {
33
+ queue: job.queue,
34
+ job_name: job.name,
35
+ job_id: job.jobId,
36
+ data: JSON.stringify(job.data ?? null),
37
+ run_at: job.runAt ?? null,
38
+ org_id: job.orgId ?? null,
39
+ };
40
+ }
41
+ /**
42
+ * Only a job due now goes through the fast path (ruling R20): a delayed one (a backstop, a
43
+ * timeout) is claimed by the relay within its next tick and added with its remaining delay, so the
44
+ * commit's caller spends no claim transaction on work due in seconds or hours.
45
+ */
46
+ const dueNow = (job) => job.runAt === undefined || job.runAt.getTime() <= Date.now();
24
47
  /**
25
48
  * The ids each open transaction inserted, keyed by its transaction store: lives only as long as
26
49
  * that transaction (a WeakMap entry, no state shared across requests).
@@ -51,31 +74,16 @@ let OutboxService = class OutboxService {
51
74
  * conflicts, else logs an error. Undefined data is stored as JSON null.
52
75
  */
53
76
  async add(job) {
54
- if (job.jobId.includes(":")) {
55
- throw new Error(`outbox job id "${job.jobId}" must not contain ":" (BullMQ uses it as its key separator); ` +
56
- 'join the id\'s parts with "-" instead');
57
- }
58
77
  const json = JSON.stringify(job.data ?? null);
59
78
  const row = await this.db
60
79
  .insertInto("outbox")
61
- .values({
62
- queue: job.queue,
63
- job_name: job.name,
64
- job_id: job.jobId,
65
- data: json,
66
- run_at: job.runAt ?? null,
67
- org_id: job.orgId ?? null,
68
- })
80
+ .values(rowOf(job))
69
81
  .onConflict((oc) => oc.columns(["queue", "job_id"]).where("dead_at", "is", null).doNothing())
70
82
  .returning("id")
71
83
  .executeTakeFirst();
72
84
  if (row) {
73
- // only a job due now goes through the fast path (ruling R20): a delayed one (a backstop, a
74
- // timeout) is claimed by the relay within its next tick and added with its remaining delay,
75
- // so the commit's caller spends no claim transaction on work due in seconds or hours
76
- if (job.runAt === undefined || job.runAt.getTime() <= Date.now()) {
85
+ if (dueNow(job))
77
86
  this.deliverAfterCommit(row.id);
78
- }
79
87
  return true;
80
88
  }
81
89
  const stored = await this.db
@@ -100,6 +108,29 @@ let OutboxService = class OutboxService {
100
108
  }
101
109
  return false;
102
110
  }
111
+ /**
112
+ * {@link add} for many jobs in one multi-row insert per {@link ADD_MANY_CHUNK} jobs (an eval
113
+ * run's cases). A job whose (queue, jobId) is already owed is skipped without comparing its data.
114
+ * Returns how many rows it inserted.
115
+ */
116
+ async addMany(jobs) {
117
+ let inserted = 0;
118
+ for (let i = 0; i < jobs.length; i += ADD_MANY_CHUNK) {
119
+ const chunk = jobs.slice(i, i + ADD_MANY_CHUNK);
120
+ const rows = await this.db
121
+ .insertInto("outbox")
122
+ .values(chunk.map(rowOf))
123
+ .onConflict((oc) => oc.columns(["queue", "job_id"]).where("dead_at", "is", null).doNothing())
124
+ .returning(["id", "run_at"])
125
+ .execute();
126
+ for (const r of rows) {
127
+ if (dueNow({ runAt: r.run_at ?? undefined }))
128
+ this.deliverAfterCommit(r.id);
129
+ }
130
+ inserted += rows.length;
131
+ }
132
+ return inserted;
133
+ }
103
134
  /** Collects `id` for its transaction; the first id registers the transaction's one hint. */
104
135
  deliverAfterCommit(id) {
105
136
  // `mandatory` guarantees a live store here
@@ -119,6 +150,9 @@ let OutboxService = class OutboxService {
119
150
  __decorate([
120
151
  Transactional({ propagation: "mandatory" })
121
152
  ], OutboxService.prototype, "add", null);
153
+ __decorate([
154
+ Transactional({ propagation: "mandatory" })
155
+ ], OutboxService.prototype, "addMany", null);
122
156
  OutboxService = __decorate([
123
157
  Injectable(),
124
158
  __param(0, Inject(TransactionHost)),
@@ -66,6 +66,37 @@ export declare const OUTBOX_JOBS: {
66
66
  readonly removeOnFail: true;
67
67
  };
68
68
  };
69
+ readonly "run-stop": {
70
+ readonly queue: "cap-kernel-maintenance";
71
+ readonly idempotent: "stopping a finished run is a no-op";
72
+ readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
73
+ readonly opts: {
74
+ readonly attempts: 5;
75
+ readonly backoff: {
76
+ readonly type: "exponential";
77
+ readonly delay: 5000;
78
+ };
79
+ readonly removeOnComplete: true;
80
+ readonly removeOnFail: {
81
+ readonly age: number;
82
+ readonly count: 1000;
83
+ };
84
+ };
85
+ };
86
+ readonly "sandbox-destroy-for": {
87
+ readonly queue: "cap-kernel-maintenance";
88
+ readonly idempotent: "destroying a destroyed device is a no-op";
89
+ readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
90
+ readonly opts: {
91
+ readonly attempts: 5;
92
+ readonly backoff: {
93
+ readonly type: "exponential";
94
+ readonly delay: 30000;
95
+ };
96
+ readonly removeOnComplete: true;
97
+ readonly removeOnFail: 100;
98
+ };
99
+ };
69
100
  readonly "deliver-to-parent": {
70
101
  readonly queue: "cap-kernel-maintenance";
71
102
  readonly idempotent: "the delivery's idempotency key is the child run id";
@@ -114,6 +145,151 @@ export declare const OUTBOX_JOBS: {
114
145
  readonly removeOnFail: true;
115
146
  };
116
147
  };
148
+ readonly "channel-resume": {
149
+ readonly queue: "cap-kernel-channels";
150
+ readonly idempotent: "the catch-up re-reads which of the connection's conversations lag their log and adds their delivery jobs, and a delivery resumes from the delivered seq under a per-conversation lock, so a second catch-up sends nothing twice";
151
+ readonly processedIn: "packages/kernel/src/channels/channels.module.ts";
152
+ readonly opts: {
153
+ readonly attempts: 5;
154
+ readonly backoff: {
155
+ readonly type: "exponential";
156
+ readonly delay: 5000;
157
+ };
158
+ readonly priority: 10;
159
+ readonly removeOnComplete: true;
160
+ readonly removeOnFail: true;
161
+ };
162
+ };
163
+ readonly "scope-item": {
164
+ readonly queue: "cap-kernel-plugin-scope";
165
+ readonly idempotent: "the sync converges each (item, org) from the scope, switches and installs it reads under the org's lock, and the installer re-checks under the org row lock, so a second run changes nothing";
166
+ readonly processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts";
167
+ readonly opts: {
168
+ readonly attempts: 1;
169
+ readonly removeOnComplete: true;
170
+ readonly removeOnFail: true;
171
+ };
172
+ };
173
+ readonly "scope-item-backstop": {
174
+ readonly queue: "cap-kernel-plugin-scope";
175
+ readonly idempotent: "the sync converges each (item, org) from what it reads, as a scope-item job does, so a run after the immediate job changes nothing";
176
+ readonly processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts";
177
+ readonly opts: {
178
+ readonly attempts: 5;
179
+ readonly backoff: {
180
+ readonly type: "exponential";
181
+ readonly delay: 60000;
182
+ };
183
+ readonly removeOnComplete: true;
184
+ readonly removeOnFail: true;
185
+ };
186
+ };
187
+ readonly "scope-org": {
188
+ readonly queue: "cap-kernel-plugin-scope";
189
+ readonly idempotent: "the sync converges each (item, org) of the org from what it reads, so a second run changes nothing";
190
+ readonly processedIn: "packages/kernel/src/catalog/scope-sync-workers.ts";
191
+ readonly opts: {
192
+ readonly attempts: 1;
193
+ readonly removeOnComplete: true;
194
+ readonly removeOnFail: true;
195
+ };
196
+ };
197
+ readonly "owned-plugin-cleanup": {
198
+ readonly queue: "cap-kernel-maintenance";
199
+ readonly idempotent: "the cleanup takes the extension out only while no live item uses it, and a missing install or a released claim changes nothing";
200
+ readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
201
+ readonly opts: {
202
+ readonly attempts: 3;
203
+ readonly backoff: {
204
+ readonly type: "exponential";
205
+ readonly delay: 5000;
206
+ };
207
+ readonly removeOnComplete: true;
208
+ readonly removeOnFail: true;
209
+ };
210
+ };
211
+ readonly "sched-fire": {
212
+ readonly queue: "cap-kernel-maintenance";
213
+ readonly idempotent: "a fire acts only on a pending task run, under its row lock; a retried start reuses what the first one made";
214
+ readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
215
+ readonly opts: {
216
+ readonly attempts: 3;
217
+ readonly backoff: {
218
+ readonly type: "exponential";
219
+ readonly delay: 2000;
220
+ };
221
+ readonly removeOnComplete: true;
222
+ readonly removeOnFail: true;
223
+ };
224
+ };
225
+ readonly "sched-settle": {
226
+ readonly queue: "cap-kernel-maintenance";
227
+ readonly idempotent: "a check acts only on a task run still pending (claimed for the claimed check, unclaimed for the unfired one), under the task and run row locks, so a run claimed, started, ended or skipped since is left as it is";
228
+ readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
229
+ readonly opts: {
230
+ readonly attempts: 5;
231
+ readonly backoff: {
232
+ readonly type: "exponential";
233
+ readonly delay: 5000;
234
+ };
235
+ readonly removeOnComplete: true;
236
+ readonly removeOnFail: true;
237
+ };
238
+ };
239
+ readonly "device-op-resolve": {
240
+ readonly queue: "cap-kernel-maintenance";
241
+ readonly idempotent: "resolving an op whose entry is gone is a no-op (the entry is read under the machine row's lock, and under the network ask's lock for an op that answers one, so the ask is decided at most once); the resolver only reads the device, never sends a change";
242
+ readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
243
+ readonly opts: {
244
+ readonly attempts: 5;
245
+ readonly backoff: {
246
+ readonly type: "exponential";
247
+ readonly delay: 5000;
248
+ };
249
+ readonly removeOnComplete: true;
250
+ readonly removeOnFail: true;
251
+ };
252
+ };
253
+ readonly "bg-wake": {
254
+ readonly queue: "cap-kernel-maintenance";
255
+ readonly idempotent: "the wake only calls ensureRun, which decides from the conversation's state under its row lock, so a wake with nothing unconsumed or an active run starts nothing";
256
+ readonly processedIn: "packages/kernel/src/runtime/maintenance.ts";
257
+ readonly opts: {
258
+ readonly removeOnComplete: true;
259
+ readonly removeOnFail: true;
260
+ };
261
+ };
262
+ readonly "eval-case": {
263
+ readonly queue: "cap-kernel-evals";
264
+ readonly idempotent: "a case job replays only the case's unfinished results (and pending judgements) of a still-active run, each under a fresh claim, so a second job writes no result twice";
265
+ readonly processedIn: "packages/kernel/src/evals/evals.module.ts";
266
+ readonly opts: {
267
+ readonly attempts: 3;
268
+ readonly backoff: {
269
+ readonly type: "exponential";
270
+ readonly delay: 1000;
271
+ };
272
+ readonly removeOnComplete: true;
273
+ readonly removeOnFail: 1000;
274
+ };
275
+ };
276
+ readonly lifecycle: {
277
+ readonly queue: "cap-kernel-lifecycle";
278
+ readonly idempotent: "lifecycle handlers must be idempotent (the SDK contract): they delete what the plugin holds for the removed member, agent or org, and deleting it again is a no-op";
279
+ readonly processedIn: "packages/kernel/src/extensions/lifecycle-hooks.ts";
280
+ readonly opts: {
281
+ readonly attempts: 15;
282
+ readonly backoff: {
283
+ readonly type: "exponential";
284
+ readonly delay: 2000;
285
+ };
286
+ readonly removeOnComplete: true;
287
+ readonly removeOnFail: {
288
+ readonly age: number;
289
+ readonly count: 1000;
290
+ };
291
+ };
292
+ };
117
293
  };
118
294
  export type OutboxJobName = keyof typeof OUTBOX_JOBS;
119
295
  /** The registry's BullMQ options of a job name (none for a name it does not list). */