@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,5 +1,6 @@
1
1
  import type { Job, Queue } from "bullmq";
2
2
  import { LockService } from "../infra/lock/lock.service.js";
3
+ import type { OutboxService } from "../infra/outbox/outbox.service.js";
3
4
  import type { KernelLogger } from "../log.js";
4
5
  import { SandboxService } from "./sandbox.service.js";
5
6
  /** The idle suspension sweep (every minute, once per tick across replicas). */
@@ -7,10 +8,25 @@ export declare const SANDBOX_SUSPEND_JOB = "sandbox-suspend-idle";
7
8
  /** The inactivity destruction sweep (hourly, once per tick across replicas). */
8
9
  export declare const SANDBOX_DESTROY_JOB = "sandbox-destroy-inactive";
9
10
  /**
10
- * One-off job: destroy a batch of devices now, instance and file system (device
11
- * deletion, offboarding; data `{ deviceIds }`).
11
+ * One-off job: destroy devices now, instance and file system (data `{ deviceIds }`). Owed through
12
+ * the outbox by the transaction that soft-deletes the device (a device's deletion, offboarding),
13
+ * one device per job under {@link deviceDestroyJobId} ({@link oweDeviceDestroy}).
12
14
  */
13
15
  export declare const SANDBOX_DESTROY_FOR_JOB = "sandbox-destroy-for";
16
+ /** The data of a {@link SANDBOX_DESTROY_FOR_JOB} job. */
17
+ export interface SandboxDestroyForData {
18
+ deviceIds: string[];
19
+ }
20
+ /**
21
+ * The deterministic id of a deleted device's destroy job (no `:`): a device is deleted once, so
22
+ * its destruction is owed once.
23
+ */
24
+ export declare const deviceDestroyJobId: (deviceId: string) => string;
25
+ /**
26
+ * Owes the destruction of a device in the caller's transaction, the one that soft-deleted it
27
+ * (transactional outbox spec §8.1; throws outside a transaction).
28
+ */
29
+ export declare function oweDeviceDestroy(outbox: Pick<OutboxService, "add">, deviceId: string, orgId: string): Promise<boolean>;
14
30
  /**
15
31
  * One-off job: start a device over with empty files (`resetFileSystem`; data
16
32
  * `{ deviceId }`, job id {@link resetFilesJobId}).
@@ -22,18 +38,12 @@ export declare const SANDBOX_RESET_FILES_JOB = "sandbox-reset-files";
22
38
  */
23
39
  export declare const resetFilesJobId: (deviceId: string) => string;
24
40
  /**
25
- * The producer of the sandbox maintenance jobs: {@link SANDBOX_DESTROY_FOR_JOB} (BullMQ's own job
26
- * ids, as before: every enqueue is a new job, also after a batch failed all its attempts) and
27
- * {@link SANDBOX_RESET_FILES_JOB}; `MaintenanceProcessor` consumes them.
41
+ * The producer of {@link SANDBOX_RESET_FILES_JOB} (destroys are owed through the outbox,
42
+ * {@link oweDeviceDestroy}); `MaintenanceProcessor` consumes both.
28
43
  */
29
44
  export declare class SandboxJobs {
30
45
  private readonly queue;
31
46
  constructor(queue: Pick<Queue, "add">);
32
- /**
33
- * Enqueues the destruction of these devices: a failed batch is retried whole (destroying
34
- * one already destroyed does nothing).
35
- */
36
- destroy(deviceIds: string[]): Promise<void>;
37
47
  /**
38
48
  * Enqueues the reset of a device's files (see {@link resetFilesJobId}): retried on failure
39
49
  * (the exclusive lease not obtained in time, the provider failing); a job that failed all its
@@ -19,10 +19,29 @@ export const SANDBOX_SUSPEND_JOB = "sandbox-suspend-idle";
19
19
  /** The inactivity destruction sweep (hourly, once per tick across replicas). */
20
20
  export const SANDBOX_DESTROY_JOB = "sandbox-destroy-inactive";
21
21
  /**
22
- * One-off job: destroy a batch of devices now, instance and file system (device
23
- * deletion, offboarding; data `{ deviceIds }`).
22
+ * One-off job: destroy devices now, instance and file system (data `{ deviceIds }`). Owed through
23
+ * the outbox by the transaction that soft-deletes the device (a device's deletion, offboarding),
24
+ * one device per job under {@link deviceDestroyJobId} ({@link oweDeviceDestroy}).
24
25
  */
25
26
  export const SANDBOX_DESTROY_FOR_JOB = "sandbox-destroy-for";
27
+ /**
28
+ * The deterministic id of a deleted device's destroy job (no `:`): a device is deleted once, so
29
+ * its destruction is owed once.
30
+ */
31
+ export const deviceDestroyJobId = (deviceId) => `device-destroy-${deviceId}`;
32
+ /**
33
+ * Owes the destruction of a device in the caller's transaction, the one that soft-deleted it
34
+ * (transactional outbox spec §8.1; throws outside a transaction).
35
+ */
36
+ export function oweDeviceDestroy(outbox, deviceId, orgId) {
37
+ return outbox.add({
38
+ queue: MAINTENANCE_QUEUE_NAME,
39
+ name: SANDBOX_DESTROY_FOR_JOB,
40
+ jobId: deviceDestroyJobId(deviceId),
41
+ data: { deviceIds: [deviceId] },
42
+ orgId,
43
+ });
44
+ }
26
45
  /**
27
46
  * One-off job: start a device over with empty files (`resetFileSystem`; data
28
47
  * `{ deviceId }`, job id {@link resetFilesJobId}).
@@ -34,27 +53,14 @@ export const SANDBOX_RESET_FILES_JOB = "sandbox-reset-files";
34
53
  */
35
54
  export const resetFilesJobId = (deviceId) => `${SANDBOX_RESET_FILES_JOB}-${deviceId}`;
36
55
  /**
37
- * The producer of the sandbox maintenance jobs: {@link SANDBOX_DESTROY_FOR_JOB} (BullMQ's own job
38
- * ids, as before: every enqueue is a new job, also after a batch failed all its attempts) and
39
- * {@link SANDBOX_RESET_FILES_JOB}; `MaintenanceProcessor` consumes them.
56
+ * The producer of {@link SANDBOX_RESET_FILES_JOB} (destroys are owed through the outbox,
57
+ * {@link oweDeviceDestroy}); `MaintenanceProcessor` consumes both.
40
58
  */
41
59
  let SandboxJobs = class SandboxJobs {
42
60
  queue;
43
61
  constructor(queue) {
44
62
  this.queue = queue;
45
63
  }
46
- /**
47
- * Enqueues the destruction of these devices: a failed batch is retried whole (destroying
48
- * one already destroyed does nothing).
49
- */
50
- async destroy(deviceIds) {
51
- await this.queue.add(SANDBOX_DESTROY_FOR_JOB, { deviceIds }, {
52
- attempts: 5,
53
- backoff: { type: "exponential", delay: 30_000 },
54
- removeOnComplete: true,
55
- removeOnFail: 100,
56
- });
57
- }
58
64
  /**
59
65
  * Enqueues the reset of a device's files (see {@link resetFilesJobId}): retried on failure
60
66
  * (the exclusive lease not obtained in time, the provider failing); a job that failed all its
@@ -2,7 +2,7 @@ import { type ExecResult, type SandboxActor, type SandboxHandle, type SandboxLim
2
2
  import type { Redis } from "ioredis";
3
3
  import { type Selectable } from "kysely";
4
4
  import { BackgroundTaskStore } from "../background/store.js";
5
- import { type KernelConfig } from "../config/schema.js";
5
+ import type { KernelConfig } from "../config/schema.js";
6
6
  import type { DeviceInstancesTable } from "../db/kernel-schema.js";
7
7
  import { ApiError } from "../errors.js";
8
8
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
@@ -106,6 +106,19 @@ export declare const deviceNotFound: () => ApiError;
106
106
  * owner's: `capybara-device logout`, then `login` into the device, recreates it (ruling R24).
107
107
  */
108
108
  export declare const deviceFilesLost: (local?: boolean) => ApiError;
109
+ /**
110
+ * A cloud sandbox provider refused to make (or move) an instance with open egress, the open tier
111
+ * (409; sandbox dev tiers spec §5.3): above all a provider set to refuse it (sandbox-docker /
112
+ * sandbox-e2b `openEgress: "off"`). Details `[{ tier }]`. The provider's own error goes only to
113
+ * the log: it may name the provider's settings.
114
+ */
115
+ export declare const sandboxTierRefused: (tier: SandboxTier) => ApiError;
116
+ /**
117
+ * A cloud sandbox provider failed to make a device's file system or instance for another reason
118
+ * (502): often its deployment config (image, runtime, network), sometimes a passing fault. The
119
+ * provider's own error goes only to the log.
120
+ */
121
+ export declare const sandboxCreateFailed: () => ApiError;
109
122
  /**
110
123
  * The row still records the instance `gone` (same handle and same `created_at`). Handles compare
111
124
  * canonically: a jsonb round trip reorders a multi-key handle's keys (final review m9).
@@ -117,11 +130,11 @@ export declare const isInstance: (row: Pick<Row, "handle" | "created_at">, gone:
117
130
  * run time limit (Ruling M20);
118
131
  * - `sandbox.tiers.max` is open but the current provider plugin sets `openEgress: "off"`: every
119
132
  * creation of an open-tier instance is refused.
120
- * With both time limits at their defaults (900 < 7200, a known trade-off) it is only info; warn
121
- * when an operator changed one and they still disagree.
133
+ * No run duration limit (`runtime.maxRunSeconds` 0, the default) cuts no command, so there is
134
+ * nothing to tell.
122
135
  */
123
136
  export declare function sandboxConfigWarnings(cfg: Pick<KernelConfig, "runtime" | "sandbox" | "extensionConfig">, providerPlugin?: string): {
124
- level: "info" | "warn";
137
+ level: "warn";
125
138
  message: string;
126
139
  }[];
127
140
  /** No sandbox provider (503). */
@@ -13,7 +13,6 @@ import { Inject, Injectable } from "@nestjs/common";
13
13
  import { sql, } from "kysely";
14
14
  import { SESSION_MODE_SCRIPT } from "../background/launch.js";
15
15
  import { BackgroundTaskStore } from "../background/store.js";
16
- import { DEFAULT_MAX_COMMAND_SECONDS, DEFAULT_MAX_RUN_SECONDS, } from "../config/schema.js";
17
16
  import { ApiError } from "../errors.js";
18
17
  import { readSandboxLimitOverride } from "../identity/settings.js";
19
18
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
@@ -23,8 +22,9 @@ import { effectiveSandboxLimits, readOrgSettings } from "../orgs/settings.servic
23
22
  import { appendMissingGrant, TIER_OPEN_GRANT_KEY, UNATTENDED_OPEN_TIER_ERROR, unattendedTierOf, } from "../schedules/unattended.js";
24
23
  import { canonicalJson } from "../tools/canonical-json.js";
25
24
  import { SandboxLeases, SandboxLockLostError, sandboxBusy, } from "./leases.js";
26
- import { LOCAL_PROVIDER, providerForDevice, SandboxProviders, } from "./providers.js";
25
+ import { isInternalProvider, LOCAL_PROVIDER, providerForDevice, SandboxProviders, } from "./providers.js";
27
26
  import { appliedOf, effectiveSandboxPolicy, instanceLimitsJson, limitsForTier, readDeploymentSandboxPolicy, readInstanceLimits, sameApplied, } from "./tiers.js";
27
+ import { SandboxProviderUnreachableError } from "./unreachable.js";
28
28
  // Moved to leases.ts (phase C); re-exported for existing importers
29
29
  export { SANDBOX_LOCK_PREFIX, SANDBOX_LOCK_TTL_MS, SandboxLockLostError, sandboxBusy, } from "./leases.js";
30
30
  /** Margin (ms) of a holder record's TTL beyond the longest command: by then the in-sandbox limit has ended its commands. */
@@ -58,6 +58,46 @@ export const deviceNotFound = () => new ApiError("device.not_found", "This devic
58
58
  export const deviceFilesLost = (local = false) => local
59
59
  ? new ApiError("device.files_lost", "The local device's directory is gone from its machine; run capybara-device logout, then capybara-device login into this device, on that machine to recreate it.", [{ source: "local" }])
60
60
  : new ApiError("device.files_lost", "The device's files are gone; reset its files from the devices page to start with an empty workspace.");
61
+ /**
62
+ * A cloud sandbox provider refused to make (or move) an instance with open egress, the open tier
63
+ * (409; sandbox dev tiers spec §5.3): above all a provider set to refuse it (sandbox-docker /
64
+ * sandbox-e2b `openEgress: "off"`). Details `[{ tier }]`. The provider's own error goes only to
65
+ * the log: it may name the provider's settings.
66
+ */
67
+ export const sandboxTierRefused = (tier) => new ApiError("sandbox.tier_refused", `The cloud sandbox can't run this device at the ${tier} tier: the sandbox provider refused to create it there. An org admin can lower the tier on the device page or in the org's sandbox settings, or a super admin can allow it in the sandbox extension's settings.`, [{ tier }]);
68
+ /**
69
+ * A cloud sandbox provider failed to make a device's file system or instance for another reason
70
+ * (502): often its deployment config (image, runtime, network), sometimes a passing fault. The
71
+ * provider's own error goes only to the log.
72
+ */
73
+ export const sandboxCreateFailed = () => new ApiError("sandbox.create_failed", "The cloud sandbox provider could not create this device's sandbox. Retry; if it keeps failing, a super admin should check the sandbox extension's settings.");
74
+ /**
75
+ * What a failed `createFileSystem` / `create` / `update` of a cloud provider becomes: an abort,
76
+ * a gone error, an unreachable provider and a kernel error stay as they are (their callers and the
77
+ * tools handle them); any other error is logged (warn, redacted) and replaced by
78
+ * {@link sandboxTierRefused} when `limits` ask for open egress (the only egress a provider's
79
+ * config refuses), else (a create) by {@link sandboxCreateFailed}; a failed `update` below open
80
+ * stays as it is. A kernel-internal provider (`@local`) keeps its own errors.
81
+ */
82
+ function providerRefusal(log, err, facts, limits, signal) {
83
+ if (signal.aborted ||
84
+ isInternalProvider(facts.provider) ||
85
+ isSandboxGoneError(err) ||
86
+ isFileSystemGoneError(err) ||
87
+ err instanceof SandboxProviderUnreachableError ||
88
+ err instanceof ApiError) {
89
+ return err;
90
+ }
91
+ if (limits.egress === "open") {
92
+ // spec §5.3: a provider set to refuse open egress (`openEgress: "off"`) fails here
93
+ log.warn("the sandbox provider refused an instance in the open tier; check its openEgress setting or lower sandbox.tiers.max", { ...facts, tier: limits.tier, err });
94
+ return sandboxTierRefused(limits.tier);
95
+ }
96
+ if (facts.op === "update")
97
+ return err;
98
+ log.warn("the sandbox provider failed to create a device's sandbox", { ...facts, err });
99
+ return sandboxCreateFailed();
100
+ }
61
101
  /**
62
102
  * The row still records the instance `gone` (same handle and same `created_at`). Handles compare
63
103
  * canonically: a jsonb round trip reorders a multi-key handle's keys (final review m9).
@@ -87,8 +127,8 @@ function tagged(impl, tag, actor, before) {
87
127
  * run time limit (Ruling M20);
88
128
  * - `sandbox.tiers.max` is open but the current provider plugin sets `openEgress: "off"`: every
89
129
  * creation of an open-tier instance is refused.
90
- * With both time limits at their defaults (900 < 7200, a known trade-off) it is only info; warn
91
- * when an operator changed one and they still disagree.
130
+ * No run duration limit (`runtime.maxRunSeconds` 0, the default) cuts no command, so there is
131
+ * nothing to tell.
92
132
  */
93
133
  export function sandboxConfigWarnings(cfg, providerPlugin) {
94
134
  const out = [];
@@ -104,10 +144,9 @@ export function sandboxConfigWarnings(cfg, providerPlugin) {
104
144
  }
105
145
  const run = cfg.runtime.maxRunSeconds;
106
146
  const cmd = cfg.sandbox.limits.maxCommandSeconds;
107
- if (run < cmd) {
108
- const defaults = run === DEFAULT_MAX_RUN_SECONDS && cmd === DEFAULT_MAX_COMMAND_SECONDS;
147
+ if (run > 0 && run < cmd) {
109
148
  out.push({
110
- level: defaults ? "info" : "warn",
149
+ level: "warn",
111
150
  message: `runtime.maxRunSeconds (${run}) is less than sandbox.limits.maxCommandSeconds (${cmd}): sandbox commands are limited to the time left in the run, so commands longer than about ${run} seconds cannot finish; raise runtime.maxRunSeconds to at least ${cmd} if agents need long commands`,
112
151
  });
113
152
  }
@@ -1380,7 +1419,12 @@ let SandboxService = class SandboxService {
1380
1419
  ? row.fs_handle
1381
1420
  : null;
1382
1421
  if (fs === null) {
1383
- fs = await p.impl.createFileSystem({ name, limits, signal });
1422
+ try {
1423
+ fs = await p.impl.createFileSystem({ name, limits, signal });
1424
+ }
1425
+ catch (err) {
1426
+ throw providerRefusal(this.log, err, { deviceId: id, provider: p.plugin, op: "createFileSystem" }, limits, signal);
1427
+ }
1384
1428
  // A lost lease fails this write and leaves the file system alone: createFileSystem returns
1385
1429
  // the existing one for a name, so the new holder may already use it, files and all.
1386
1430
  await this.fenced(held, id, fence, {
@@ -1403,11 +1447,7 @@ let SandboxService = class SandboxService {
1403
1447
  }
1404
1448
  catch (err) {
1405
1449
  if (!isFileSystemGoneError(err)) {
1406
- if (limits.egress === "open" && !signal.aborted) {
1407
- // spec §5.3: a provider set to refuse open egress (`openEgress: "off"`) fails here
1408
- this.log.warn("the sandbox provider did not create an instance in the open tier; check its openEgress setting or lower sandbox.tiers.max", { deviceId: id, provider: p.plugin, err });
1409
- }
1410
- throw err;
1450
+ throw providerRefusal(this.log, err, { deviceId: id, provider: p.plugin, op: "create" }, limits, signal);
1411
1451
  }
1412
1452
  this.log.warn("device file system is gone at the provider; its files are lost", {
1413
1453
  deviceId: id,
@@ -1479,7 +1519,8 @@ let SandboxService = class SandboxService {
1479
1519
  // the instance may run with half-applied limits and cannot be recreated here: stop it,
1480
1520
  // so the next use resumes it and applies them again
1481
1521
  await this.quarantine(held, id, handle, p, fence);
1482
- throw err;
1522
+ // a provider bound to its file system that refuses the new tier (E2B, `openEgress: "off"`)
1523
+ throw providerRefusal(this.log, err, { deviceId: id, provider: p.plugin, op: "update" }, want, signal);
1483
1524
  }
1484
1525
  else {
1485
1526
  // a new instance gets the limits at create: recreate rather than trust a failed update
@@ -0,0 +1,134 @@
1
+ import type { ScheduledTask, ScheduleMode, SchedulePauseReason, ScheduleStatus, ScheduleTrigger, TaskRun, TaskRunSkipReason, TaskRunStatus } from "./types.js";
2
+ /** Planned occurrences reach this far ahead of now (spec §5.2, "about six weeks"). */
3
+ export declare const CALENDAR_HORIZON_DAYS = 42;
4
+ /** The longest range one request may ask for: a 6-week month grid plus a DST hour (§5.1). */
5
+ export declare const CALENDAR_RANGE_DAYS = 43;
6
+ /** The longest range with `taskId` (the panel's one-day list, §5.4). */
7
+ export declare const CALENDAR_TASK_RANGE_DAYS = 2;
8
+ /** A task-day with more items than this is collapsed into one summary (§5.4). */
9
+ export declare const CALENDAR_COLLAPSE_OVER = 6;
10
+ /**
11
+ * Ticks taken per request after the first local day, across all tasks (§5.5). One tick costs
12
+ * about 150-340 µs (cron's `getNextDateFrom`, measured 2026-11-12 with a ticker built once per
13
+ * task), so 3,000 keeps a worst-case request near one second.
14
+ */
15
+ export declare const CALENDAR_TICK_BUDGET = 3000;
16
+ /** Entries (`items` + `collapsed`) per request after the first local day (§5.5). */
17
+ export declare const CALENDAR_ITEM_CAP = 3000;
18
+ /** Run rows read per request after the first local day (§5.5). */
19
+ export declare const CALENDAR_RUN_ROW_CAP = 20000;
20
+ /**
21
+ * The first requested local day is always returned whole, outside the limits above; only these
22
+ * safety caps stop it (then nothing is returned, `truncated`, `horizon` = `from`).
23
+ */
24
+ export declare const CALENDAR_FIRST_DAY_TICK_CAP = 10000;
25
+ export declare const CALENDAR_FIRST_DAY_RUN_CAP = 20000;
26
+ /** The limits of one assembly; tests lower them. */
27
+ export interface CalendarLimits {
28
+ horizonDays: number;
29
+ collapseOver: number;
30
+ /**
31
+ * Ticks taken (planned ticks in the range, the due tick included), after the first day. Not
32
+ * counted: each stream's one lookahead evaluation past its `until` and the doubling search of
33
+ * `scanStep` for a task already due, at most about 2 × tasks evaluations more.
34
+ */
35
+ tickBudget: number;
36
+ itemCap: number;
37
+ runRowCap: number;
38
+ firstDayTickCap: number;
39
+ firstDayRunCap: number;
40
+ }
41
+ export declare const CALENDAR_LIMITS: CalendarLimits;
42
+ /** How many run rows the service reads: enough to tell where either run cap cuts. */
43
+ export declare const calendarRunReadLimit: (limits: CalendarLimits) => number;
44
+ /** A task an entry of the answer names. */
45
+ export interface CalendarTask {
46
+ id: string;
47
+ name: string;
48
+ agentId: string;
49
+ accountId: string;
50
+ status: ScheduleStatus;
51
+ pauseReason: SchedulePauseReason | null;
52
+ trigger: ScheduleTrigger;
53
+ mode: ScheduleMode;
54
+ jitterSeconds: number;
55
+ nextRunAt: string | null;
56
+ }
57
+ export type CalendarItem = {
58
+ kind: "run";
59
+ taskId: string;
60
+ /** The task run's id. */
61
+ id: string;
62
+ scheduledFor: string;
63
+ firedAt: string | null;
64
+ status: TaskRunStatus;
65
+ skipReason: TaskRunSkipReason | null;
66
+ trial: boolean;
67
+ manual: boolean;
68
+ /** Null for another member's run (admin `all`, spec §15 Q3), as `error` and `missingGrants`. */
69
+ conversationId: string | null;
70
+ error: string | null;
71
+ missingGrants: number | null;
72
+ } | {
73
+ kind: "occurrence";
74
+ taskId: string;
75
+ /** The tick, before jitter. */
76
+ scheduledFor: string;
77
+ /** When it fires: the tick plus the task's jitter. */
78
+ at: string;
79
+ };
80
+ /** A task's items of one local day, summarized (§5.4). */
81
+ export interface CalendarCollapsed {
82
+ taskId: string;
83
+ /** YYYY-MM-DD in the request's `timeZone`. */
84
+ day: string;
85
+ count: number;
86
+ upcoming: number;
87
+ running: number;
88
+ completed: number;
89
+ failed: number;
90
+ skipped: number;
91
+ /** The earliest and latest `scheduledFor` of the day's items. */
92
+ first: string;
93
+ last: string;
94
+ }
95
+ export interface CalendarAnswer {
96
+ tasks: CalendarTask[];
97
+ items: CalendarItem[];
98
+ collapsed: CalendarCollapsed[];
99
+ /** Nothing is returned after it: 42 days ahead, or the cut. */
100
+ horizon: string;
101
+ /** A limit cut the range at a whole local day. */
102
+ truncated: boolean;
103
+ }
104
+ export interface CalendarInput {
105
+ /** The live tasks the viewer may see in this request. */
106
+ tasks: readonly ScheduledTask[];
107
+ /**
108
+ * Their runs with `scheduledFor` in `[from, to)`, trial included, ordered by `scheduledFor`, at
109
+ * most {@link calendarRunReadLimit} (rows past it are not read; the range is cut before them).
110
+ */
111
+ runs: readonly TaskRun[];
112
+ /** The viewer: another creator's runs lose `conversationId`, `error` and `missingGrants`. */
113
+ viewerAccountId: string;
114
+ from: Date;
115
+ to: Date;
116
+ /** The viewer's zone: local days for the collapse and the cut. */
117
+ timeZone: string;
118
+ now: Date;
119
+ /** False when the org turned scheduled tasks off: nothing would fire, so nothing is planned. */
120
+ plan: boolean;
121
+ /** The org's catch-up window, as the scanner reads it. */
122
+ catchUpWindowMinutes: number;
123
+ /** False for a `taskId` read: every item, never collapsed. */
124
+ collapse: boolean;
125
+ }
126
+ /** The calendar answer from the rows (spec §5.2–§5.5). */
127
+ export declare function assembleCalendar(input: CalendarInput, limits?: CalendarLimits): CalendarAnswer;
128
+ /** YYYY-MM-DD of the instant (epoch ms) in `timeZone`. */
129
+ export declare function dayKey(ms: number, timeZone: string): string;
130
+ /**
131
+ * The first instant (epoch ms) of the local day of `ms` in `timeZone`: midnight, or the end of a
132
+ * DST gap that swallows it. A day is at most 25 hours long, so 27 hours back is an earlier day.
133
+ */
134
+ export declare function startOfLocalDay(ms: number, timeZone: string): number;