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

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 (206) 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 +7 -3
  4. package/dist/admin/outbox-dead.controller.d.ts +23 -0
  5. package/dist/admin/outbox-dead.controller.js +62 -0
  6. package/dist/admin/outbox-dead.schemas.d.ts +8 -0
  7. package/dist/admin/outbox-dead.schemas.js +18 -0
  8. package/dist/admin/outbox-dead.service.d.ts +66 -0
  9. package/dist/admin/outbox-dead.service.js +179 -0
  10. package/dist/admin/overview.service.d.ts +40 -5
  11. package/dist/admin/overview.service.js +41 -7
  12. package/dist/agents/from-template.js +1 -1
  13. package/dist/background/finish.d.ts +5 -2
  14. package/dist/background/finish.js +14 -3
  15. package/dist/background/launch.d.ts +2 -1
  16. package/dist/background/launch.js +5 -2
  17. package/dist/background/store.d.ts +8 -0
  18. package/dist/background/store.js +24 -0
  19. package/dist/catalog/admin-catalog.controller.d.ts +21 -2
  20. package/dist/catalog/admin-catalog.controller.js +45 -6
  21. package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
  22. package/dist/catalog/admin-catalog.schemas.js +8 -0
  23. package/dist/catalog/catalog.module.d.ts +2 -1
  24. package/dist/catalog/catalog.module.js +5 -1
  25. package/dist/catalog/marketplaces.service.d.ts +1 -1
  26. package/dist/catalog/platform-import-update.d.ts +50 -0
  27. package/dist/catalog/platform-import-update.js +116 -0
  28. package/dist/catalog/plugin-import.d.ts +36 -1
  29. package/dist/catalog/plugin-import.js +23 -1
  30. package/dist/catalog/plugin-upgrade.d.ts +18 -0
  31. package/dist/catalog/plugin-upgrade.js +19 -0
  32. package/dist/channels/channels.module.d.ts +5 -2
  33. package/dist/channels/channels.module.js +9 -2
  34. package/dist/channels/deliver-job.d.ts +25 -0
  35. package/dist/channels/deliver-job.js +25 -0
  36. package/dist/channels/inbound.d.ts +1 -1
  37. package/dist/channels/inbound.js +2 -15
  38. package/dist/channels/jobs.d.ts +28 -18
  39. package/dist/channels/jobs.js +63 -26
  40. package/dist/config/schema.d.ts +0 -3
  41. package/dist/config/schema.js +11 -20
  42. package/dist/conversations/agent-tree.d.ts +16 -0
  43. package/dist/conversations/agent-tree.js +36 -0
  44. package/dist/conversations/conversations.service.d.ts +44 -14
  45. package/dist/conversations/conversations.service.js +52 -38
  46. package/dist/conversations/event-log.d.ts +7 -10
  47. package/dist/conversations/event-log.js +24 -15
  48. package/dist/conversations/events.js +2 -1
  49. package/dist/conversations/queue.service.d.ts +8 -3
  50. package/dist/conversations/queue.service.js +37 -13
  51. package/dist/conversations/titles.d.ts +21 -8
  52. package/dist/conversations/titles.js +42 -15
  53. package/dist/db/kernel-schema.d.ts +26 -8
  54. package/dist/devices/devices.service.d.ts +12 -3
  55. package/dist/devices/devices.service.js +18 -3
  56. package/dist/errors.d.ts +11 -0
  57. package/dist/errors.js +11 -0
  58. package/dist/evals/run-replay.js +14 -8
  59. package/dist/extensions/extensions.module.js +3 -0
  60. package/dist/extensions/lifecycle.d.ts +6 -1
  61. package/dist/extensions/lifecycle.js +9 -2
  62. package/dist/extensions/usage-subscribers.d.ts +43 -0
  63. package/dist/extensions/usage-subscribers.js +108 -0
  64. package/dist/http/api.module.js +2 -0
  65. package/dist/index.d.ts +1 -0
  66. package/dist/index.js +1 -0
  67. package/dist/infra/cli/kernel-cli.module.js +5 -0
  68. package/dist/infra/events/kernel-events.d.ts +9 -35
  69. package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
  70. package/dist/infra/outbox/outbox-relay.module.js +18 -0
  71. package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
  72. package/dist/infra/outbox/outbox.dispatcher.js +310 -0
  73. package/dist/infra/outbox/outbox.module.d.ts +24 -0
  74. package/dist/infra/outbox/outbox.module.js +50 -0
  75. package/dist/infra/outbox/outbox.relay.d.ts +31 -0
  76. package/dist/infra/outbox/outbox.relay.js +76 -0
  77. package/dist/infra/outbox/outbox.service.d.ts +51 -0
  78. package/dist/infra/outbox/outbox.service.js +131 -0
  79. package/dist/infra/outbox/registry.d.ts +120 -0
  80. package/dist/infra/outbox/registry.js +108 -0
  81. package/dist/infra/queue/queue-names.d.ts +8 -0
  82. package/dist/infra/queue/queue-names.js +16 -0
  83. package/dist/kernel.module.js +3 -0
  84. package/dist/local-devices/device-policy.service.d.ts +4 -0
  85. package/dist/local-devices/device-policy.service.js +61 -3
  86. package/dist/local-devices/machines.d.ts +13 -5
  87. package/dist/local-devices/machines.js +45 -7
  88. package/dist/local-devices/policy-summary.d.ts +44 -1
  89. package/dist/local-devices/policy-summary.js +69 -0
  90. package/dist/models/embeddings.d.ts +9 -9
  91. package/dist/models/embeddings.js +11 -18
  92. package/dist/models/models.module.js +3 -0
  93. package/dist/orgs/orgs.service.js +7 -0
  94. package/dist/overrides.d.ts +20 -3
  95. package/dist/overrides.js +10 -2
  96. package/dist/platform/exclusions.js +5 -0
  97. package/dist/platform/ops/admin.ops.js +18 -2
  98. package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
  99. package/dist/platform/ops/catalog-admin.ops.js +32 -4
  100. package/dist/platform/ops/outbox.ops.d.ts +21 -0
  101. package/dist/platform/ops/outbox.ops.js +125 -0
  102. package/dist/platform/ops/schedules.ops.js +40 -1
  103. package/dist/platform/platform-ops.module.d.ts +2 -1
  104. package/dist/platform/platform-ops.module.js +3 -0
  105. package/dist/platform/route-schemas.js +3 -0
  106. package/dist/roles/worker.module.js +9 -4
  107. package/dist/runtime/langgraph-loop.js +13 -5
  108. package/dist/runtime/limits.d.ts +15 -0
  109. package/dist/runtime/limits.js +25 -0
  110. package/dist/runtime/loop.d.ts +8 -3
  111. package/dist/runtime/loop.js +2 -1
  112. package/dist/runtime/maintenance.d.ts +4 -2
  113. package/dist/runtime/maintenance.js +17 -2
  114. package/dist/runtime/model-call.d.ts +14 -16
  115. package/dist/runtime/model-call.js +14 -24
  116. package/dist/runtime/queue-lost-jobs.d.ts +24 -0
  117. package/dist/runtime/queue-lost-jobs.js +51 -0
  118. package/dist/runtime/run-control.d.ts +42 -5
  119. package/dist/runtime/run-control.js +66 -12
  120. package/dist/runtime/run-finish.d.ts +39 -12
  121. package/dist/runtime/run-finish.js +97 -14
  122. package/dist/runtime/run-jobs.d.ts +95 -13
  123. package/dist/runtime/run-jobs.js +199 -28
  124. package/dist/runtime/run-orphan-check.job.d.ts +142 -0
  125. package/dist/runtime/run-orphan-check.job.js +339 -0
  126. package/dist/runtime/run-processors.d.ts +16 -9
  127. package/dist/runtime/run-processors.js +1 -1
  128. package/dist/runtime/run-queue.d.ts +64 -55
  129. package/dist/runtime/run-queue.js +147 -284
  130. package/dist/runtime/run-steps.d.ts +1 -2
  131. package/dist/runtime/run-steps.js +8 -11
  132. package/dist/runtime/run-worker.d.ts +6 -17
  133. package/dist/runtime/run-worker.js +32 -34
  134. package/dist/runtime/runtime.module.d.ts +2 -3
  135. package/dist/runtime/runtime.module.js +5 -6
  136. package/dist/runtime/step-log.d.ts +16 -4
  137. package/dist/runtime/step-log.js +26 -6
  138. package/dist/runtime/stream.controller.d.ts +2 -4
  139. package/dist/runtime/stream.controller.js +5 -11
  140. package/dist/runtime/subagents/child.js +1 -1
  141. package/dist/runtime/subagents/definition.d.ts +2 -1
  142. package/dist/runtime/subagents/definition.js +4 -2
  143. package/dist/runtime/subagents/deliveries.d.ts +6 -3
  144. package/dist/runtime/subagents/deliveries.js +16 -7
  145. package/dist/runtime/subagents/dispatch.d.ts +12 -12
  146. package/dist/runtime/subagents/dispatch.js +13 -38
  147. package/dist/runtime/subagents/messages.d.ts +5 -1
  148. package/dist/runtime/subagents/messages.js +11 -3
  149. package/dist/runtime/subagents/skill-fork.d.ts +3 -3
  150. package/dist/runtime/subagents/skill-fork.js +5 -5
  151. package/dist/runtime/subagents/subagents.service.js +1 -1
  152. package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
  153. package/dist/runtime/subagents/tree-jobs.js +86 -0
  154. package/dist/runtime/usage-report-jobs.d.ts +23 -48
  155. package/dist/runtime/usage-report-jobs.js +67 -119
  156. package/dist/runtime/usage-report.d.ts +28 -77
  157. package/dist/runtime/usage-report.js +35 -213
  158. package/dist/runtime/waits.d.ts +48 -198
  159. package/dist/runtime/waits.js +103 -805
  160. package/dist/sandbox/sandbox.service.d.ts +17 -4
  161. package/dist/sandbox/sandbox.service.js +55 -14
  162. package/dist/schedules/calendar.d.ts +134 -0
  163. package/dist/schedules/calendar.js +410 -0
  164. package/dist/schedules/fire.d.ts +1 -3
  165. package/dist/schedules/fire.js +5 -10
  166. package/dist/schedules/run-tracker.d.ts +0 -5
  167. package/dist/schedules/run-tracker.js +0 -13
  168. package/dist/schedules/scan.job.js +15 -20
  169. package/dist/schedules/schedule-math.d.ts +42 -0
  170. package/dist/schedules/schedule-math.js +52 -0
  171. package/dist/schedules/scheduled-tasks.service.d.ts +16 -0
  172. package/dist/schedules/scheduled-tasks.service.js +53 -0
  173. package/dist/schedules/schedules.controller.d.ts +5 -1
  174. package/dist/schedules/schedules.controller.js +15 -1
  175. package/dist/schedules/schedules.schemas.d.ts +35 -0
  176. package/dist/schedules/schedules.schemas.js +27 -0
  177. package/dist/schedules/store.d.ts +5 -0
  178. package/dist/schedules/store.js +20 -0
  179. package/dist/tools/approvals.service.d.ts +26 -7
  180. package/dist/tools/approvals.service.js +88 -10
  181. package/dist/tools/builtin-names.d.ts +5 -3
  182. package/dist/tools/builtin-names.js +12 -4
  183. package/dist/tools/builtins/builtin-tools.d.ts +1 -2
  184. package/dist/tools/builtins/builtin-tools.js +21 -17
  185. package/dist/tools/builtins/sandbox/bash.js +9 -3
  186. package/dist/tools/builtins/sandbox/common.d.ts +18 -1
  187. package/dist/tools/builtins/sandbox/common.js +14 -1
  188. package/dist/tools/builtins/sandbox/index.d.ts +2 -1
  189. package/dist/tools/builtins/sandbox/index.js +4 -1
  190. package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
  191. package/dist/tools/builtins/sandbox/task-list.js +130 -0
  192. package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
  193. package/dist/tools/builtins/sandbox/task-output.js +21 -3
  194. package/dist/tools/builtins/web/extract.d.ts +2 -4
  195. package/dist/tools/builtins/web/extract.js +2 -5
  196. package/dist/tools/pipeline.d.ts +1 -1
  197. package/dist/tools/pipeline.js +1 -1
  198. package/dist/tools/questions.service.d.ts +15 -6
  199. package/dist/tools/questions.service.js +20 -8
  200. package/dist/tools/registry.d.ts +4 -2
  201. package/dist/tools/registry.js +4 -3
  202. package/dist/tools/tools.module.js +4 -3
  203. package/package.json +3 -3
  204. package/src/migrations/0118_device_policy_ops.sql +6 -0
  205. package/src/migrations/0119_outbox.sql +22 -0
  206. package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
@@ -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;