@capybara-hq/kernel 0.1.0-rc.21 → 0.1.0-rc.22

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 (242) hide show
  1. package/dist/agents/admin-agents.d.ts +16 -3
  2. package/dist/agents/admin-agents.js +65 -7
  3. package/dist/agents/agents.schemas.d.ts +24 -6
  4. package/dist/agents/agents.service.d.ts +4 -3
  5. package/dist/agents/agents.service.js +39 -26
  6. package/dist/agents/definition.d.ts +44 -6
  7. package/dist/agents/definition.js +86 -18
  8. package/dist/agents/from-template.d.ts +6 -3
  9. package/dist/agents/from-template.js +57 -44
  10. package/dist/agents/org-templates.js +97 -41
  11. package/dist/agents/templates.d.ts +6 -0
  12. package/dist/agents/templates.js +15 -1
  13. package/dist/catalog/admin-catalog.controller.d.ts +2 -4
  14. package/dist/catalog/admin-catalog.controller.js +2 -6
  15. package/dist/catalog/catalog.module.js +3 -0
  16. package/dist/catalog/claude/report.d.ts +9 -2
  17. package/dist/catalog/claude/report.js +1 -0
  18. package/dist/catalog/claude/translate.js +1 -1
  19. package/dist/catalog/component-promotion.js +1 -2
  20. package/dist/catalog/component-state.d.ts +13 -1
  21. package/dist/catalog/component-state.js +14 -5
  22. package/dist/catalog/marketplaces.service.d.ts +1 -1
  23. package/dist/catalog/marketplaces.service.js +2 -1
  24. package/dist/catalog/org-catalog.controller.d.ts +13 -3
  25. package/dist/catalog/org-catalog.controller.js +26 -4
  26. package/dist/catalog/org-catalog.schemas.d.ts +13 -0
  27. package/dist/catalog/org-catalog.schemas.js +34 -0
  28. package/dist/catalog/org-plugin-uploads.controller.js +0 -1
  29. package/dist/catalog/org-plugin-uploads.d.ts +0 -1
  30. package/dist/catalog/org-plugin-uploads.js +0 -3
  31. package/dist/catalog/org-plugin-uploads.schemas.d.ts +0 -1
  32. package/dist/catalog/org-plugin-uploads.schemas.js +0 -2
  33. package/dist/catalog/platform-components.d.ts +0 -1
  34. package/dist/catalog/platform-components.js +3 -8
  35. package/dist/catalog/plugin-import.d.ts +0 -8
  36. package/dist/catalog/plugin-import.js +4 -35
  37. package/dist/catalog/plugin-install.d.ts +2 -2
  38. package/dist/catalog/plugin-install.js +2 -2
  39. package/dist/catalog/plugin-package.d.ts +7 -0
  40. package/dist/catalog/plugin-package.js +27 -1
  41. package/dist/catalog/plugin-upgrade.d.ts +5 -6
  42. package/dist/catalog/plugin-upgrade.js +5 -23
  43. package/dist/catalog/requests.service.d.ts +66 -10
  44. package/dist/catalog/requests.service.js +196 -15
  45. package/dist/channels/actions.d.ts +2 -0
  46. package/dist/channels/actions.js +19 -4
  47. package/dist/channels/cards.d.ts +16 -2
  48. package/dist/channels/cards.js +40 -7
  49. package/dist/channels/channels.module.js +3 -0
  50. package/dist/channels/outbound.d.ts +22 -1
  51. package/dist/channels/outbound.js +116 -7
  52. package/dist/channels/phrases.d.ts +25 -0
  53. package/dist/channels/phrases.js +19 -0
  54. package/dist/channels/threads.d.ts +12 -0
  55. package/dist/channels/threads.js +34 -0
  56. package/dist/config/schema.d.ts +23 -1
  57. package/dist/config/schema.js +105 -5
  58. package/dist/conversations/conversations.service.d.ts +42 -9
  59. package/dist/conversations/conversations.service.js +57 -25
  60. package/dist/conversations/events.d.ts +106 -11
  61. package/dist/conversations/events.js +121 -18
  62. package/dist/conversations/message-context.d.ts +6 -3
  63. package/dist/conversations/message-context.js +14 -10
  64. package/dist/conversations/queue.d.ts +15 -2
  65. package/dist/conversations/queue.js +22 -3
  66. package/dist/conversations/queue.service.d.ts +12 -6
  67. package/dist/conversations/queue.service.js +36 -13
  68. package/dist/db/kernel-schema.d.ts +105 -3
  69. package/dist/devices/conversation-devices.d.ts +8 -1
  70. package/dist/devices/conversation-devices.js +8 -0
  71. package/dist/devices/devices.controller.d.ts +21 -4
  72. package/dist/devices/devices.controller.js +46 -8
  73. package/dist/devices/devices.schemas.d.ts +9 -1
  74. package/dist/devices/devices.schemas.js +11 -3
  75. package/dist/devices/devices.service.d.ts +176 -4
  76. package/dist/devices/devices.service.js +341 -6
  77. package/dist/devices/dto.d.ts +56 -3
  78. package/dist/devices/dto.js +51 -1
  79. package/dist/devices/public-suffix.d.ts +6 -0
  80. package/dist/devices/public-suffix.js +79 -0
  81. package/dist/errors.d.ts +46 -5
  82. package/dist/errors.js +46 -5
  83. package/dist/evals/reconstruct.d.ts +18 -13
  84. package/dist/evals/reconstruct.js +50 -36
  85. package/dist/evals/recorded-tools.d.ts +7 -7
  86. package/dist/evals/recorded-tools.js +4 -3
  87. package/dist/evals/trajectory.d.ts +6 -1
  88. package/dist/evals/trajectory.js +7 -0
  89. package/dist/extensions/package.js +2 -2
  90. package/dist/http/api.module.js +5 -0
  91. package/dist/inbox/inbox.module.js +2 -1
  92. package/dist/inbox/inbox.service.d.ts +19 -4
  93. package/dist/inbox/inbox.service.js +14 -3
  94. package/dist/infra/config/kernel-config.service.js +11 -0
  95. package/dist/infra/events/kernel-events.d.ts +2 -1
  96. package/dist/local-devices/device-policy.service.d.ts +65 -0
  97. package/dist/local-devices/device-policy.service.js +217 -0
  98. package/dist/local-devices/local-device-gateway.js +4 -1
  99. package/dist/local-devices/local-device-provider.d.ts +40 -3
  100. package/dist/local-devices/local-device-provider.js +109 -7
  101. package/dist/local-devices/local-devices.module.d.ts +2 -1
  102. package/dist/local-devices/local-devices.module.js +19 -3
  103. package/dist/local-devices/machines.d.ts +14 -3
  104. package/dist/local-devices/machines.js +41 -3
  105. package/dist/local-devices/network-grants.d.ts +104 -0
  106. package/dist/local-devices/network-grants.js +288 -0
  107. package/dist/local-devices/policy-summary.d.ts +20 -0
  108. package/dist/local-devices/policy-summary.js +63 -0
  109. package/dist/orgs/orgs.module.js +4 -10
  110. package/dist/orgs/roles.d.ts +1 -1
  111. package/dist/orgs/roles.js +4 -0
  112. package/dist/orgs/settings.controller.js +2 -1
  113. package/dist/orgs/settings.service.d.ts +164 -12
  114. package/dist/orgs/settings.service.js +212 -24
  115. package/dist/platform/exclusions.js +11 -1
  116. package/dist/platform/operation.js +4 -0
  117. package/dist/platform/ops/admin-items.ops.js +1 -1
  118. package/dist/platform/ops/agent-skills.ops.js +2 -2
  119. package/dist/platform/ops/agent-templates.ops.js +2 -2
  120. package/dist/platform/ops/agents.ops.js +11 -15
  121. package/dist/platform/ops/devices.ops.js +3 -1
  122. package/dist/platform/ops/inbox.ops.js +19 -0
  123. package/dist/platform/ops/org-settings.ops.js +14 -5
  124. package/dist/platform/ops/platform.ops.d.ts +9 -1
  125. package/dist/platform/ops/platform.ops.js +34 -12
  126. package/dist/platform/ops/requests.ops.js +3 -2
  127. package/dist/platform/ops/schedules.ops.d.ts +21 -0
  128. package/dist/platform/ops/schedules.ops.js +470 -0
  129. package/dist/platform/ops/skills.ops.js +3 -3
  130. package/dist/platform/platform-ops.module.d.ts +2 -1
  131. package/dist/platform/platform-ops.module.js +5 -0
  132. package/dist/platform/route-schemas.js +3 -0
  133. package/dist/roles/worker.module.js +3 -0
  134. package/dist/runtime/context/build.js +13 -4
  135. package/dist/runtime/context/compaction.js +6 -3
  136. package/dist/runtime/context/device-paths.d.ts +43 -21
  137. package/dist/runtime/context/device-paths.js +104 -21
  138. package/dist/runtime/context/run-context.d.ts +9 -0
  139. package/dist/runtime/context/run-context.js +8 -0
  140. package/dist/runtime/context/skills.d.ts +14 -1
  141. package/dist/runtime/context/skills.js +36 -5
  142. package/dist/runtime/maintenance.d.ts +4 -2
  143. package/dist/runtime/maintenance.js +16 -5
  144. package/dist/runtime/run-finish.d.ts +6 -1
  145. package/dist/runtime/run-finish.js +16 -2
  146. package/dist/runtime/run-queue.js +21 -2
  147. package/dist/runtime/run-worker.js +14 -33
  148. package/dist/runtime/runtime.module.js +3 -0
  149. package/dist/runtime/subagents/definition.d.ts +32 -14
  150. package/dist/runtime/subagents/definition.js +106 -109
  151. package/dist/runtime/subagents/dispatch.js +4 -3
  152. package/dist/runtime/subagents/preamble.d.ts +2 -1
  153. package/dist/runtime/subagents/preamble.js +2 -1
  154. package/dist/runtime/waits.js +14 -4
  155. package/dist/sandbox/sandbox.service.d.ts +120 -10
  156. package/dist/sandbox/sandbox.service.js +335 -28
  157. package/dist/sandbox/tiers.d.ts +86 -0
  158. package/dist/sandbox/tiers.js +96 -0
  159. package/dist/schedules/effective-settings.d.ts +16 -0
  160. package/dist/schedules/effective-settings.js +17 -0
  161. package/dist/schedules/errors.d.ts +8 -0
  162. package/dist/schedules/errors.js +8 -0
  163. package/dist/schedules/fire.d.ts +118 -0
  164. package/dist/schedules/fire.js +625 -0
  165. package/dist/schedules/grant-rules.d.ts +94 -0
  166. package/dist/schedules/grant-rules.js +126 -0
  167. package/dist/schedules/job-ids.d.ts +32 -0
  168. package/dist/schedules/job-ids.js +27 -0
  169. package/dist/schedules/pause.d.ts +9 -0
  170. package/dist/schedules/pause.js +33 -0
  171. package/dist/schedules/run-tracker.d.ts +81 -0
  172. package/dist/schedules/run-tracker.js +333 -0
  173. package/dist/schedules/scan.job.d.ts +64 -0
  174. package/dist/schedules/scan.job.js +303 -0
  175. package/dist/schedules/schedule-math.d.ts +31 -0
  176. package/dist/schedules/schedule-math.js +223 -0
  177. package/dist/schedules/scheduled-tasks.service.d.ts +351 -0
  178. package/dist/schedules/scheduled-tasks.service.js +1193 -0
  179. package/dist/schedules/schedules.controller.d.ts +68 -0
  180. package/dist/schedules/schedules.controller.js +242 -0
  181. package/dist/schedules/schedules.module.d.ts +16 -0
  182. package/dist/schedules/schedules.module.js +65 -0
  183. package/dist/schedules/schedules.schemas.d.ts +316 -0
  184. package/dist/schedules/schedules.schemas.js +186 -0
  185. package/dist/schedules/store.d.ts +81 -0
  186. package/dist/schedules/store.js +390 -0
  187. package/dist/schedules/store.module.d.ts +6 -0
  188. package/dist/schedules/store.module.js +21 -0
  189. package/dist/schedules/types.d.ts +108 -0
  190. package/dist/schedules/types.js +1 -0
  191. package/dist/schedules/unattended.d.ts +117 -0
  192. package/dist/schedules/unattended.js +228 -0
  193. package/dist/setup/oauth-token-probe.js +8 -4
  194. package/dist/skills/agent-skills.service.d.ts +4 -8
  195. package/dist/skills/agent-skills.service.js +18 -53
  196. package/dist/skills/catalog.d.ts +65 -62
  197. package/dist/skills/catalog.js +109 -206
  198. package/dist/skills/conversation-catalog.d.ts +3 -3
  199. package/dist/skills/conversation-catalog.js +5 -12
  200. package/dist/skills/invoke.d.ts +2 -2
  201. package/dist/skills/skills.controller.d.ts +3 -1
  202. package/dist/skills/skills.service.d.ts +38 -37
  203. package/dist/skills/skills.service.js +168 -107
  204. package/dist/skills/usable.d.ts +57 -8
  205. package/dist/skills/usable.js +172 -38
  206. package/dist/tools/approvals.controller.d.ts +4 -2
  207. package/dist/tools/approvals.controller.js +17 -2
  208. package/dist/tools/approvals.schemas.d.ts +1 -0
  209. package/dist/tools/approvals.schemas.js +3 -1
  210. package/dist/tools/approvals.service.d.ts +182 -7
  211. package/dist/tools/approvals.service.js +597 -13
  212. package/dist/tools/builtin-names.d.ts +25 -4
  213. package/dist/tools/builtin-names.js +45 -4
  214. package/dist/tools/builtins/builtin-tools.d.ts +8 -0
  215. package/dist/tools/builtins/builtin-tools.js +23 -2
  216. package/dist/tools/builtins/sandbox/bash.js +16 -7
  217. package/dist/tools/builtins/sandbox/common.d.ts +1 -1
  218. package/dist/tools/builtins/sandbox/common.js +33 -10
  219. package/dist/tools/builtins/sandbox/edit.js +7 -3
  220. package/dist/tools/builtins/sandbox/file-state.d.ts +31 -1
  221. package/dist/tools/builtins/sandbox/file-state.js +33 -3
  222. package/dist/tools/builtins/sandbox/write.js +8 -4
  223. package/dist/tools/builtins/schedules.d.ts +107 -0
  224. package/dist/tools/builtins/schedules.js +789 -0
  225. package/dist/tools/elicitation.d.ts +2 -0
  226. package/dist/tools/elicitation.js +1 -1
  227. package/dist/tools/fixed-ask.d.ts +7 -0
  228. package/dist/tools/fixed-ask.js +9 -0
  229. package/dist/tools/network-asks.d.ts +109 -0
  230. package/dist/tools/network-asks.js +221 -0
  231. package/dist/tools/pipeline.d.ts +53 -6
  232. package/dist/tools/pipeline.js +202 -13
  233. package/dist/tools/policy.d.ts +21 -8
  234. package/dist/tools/policy.js +63 -9
  235. package/dist/tools/registry.d.ts +10 -1
  236. package/dist/tools/tools.module.js +12 -0
  237. package/package.json +2 -2
  238. package/src/migrations/0113_scheduled_tasks.sql +108 -0
  239. package/src/migrations/0114_network_asks.sql +23 -0
  240. package/src/migrations/0115_network_requests.sql +28 -0
  241. package/src/migrations/0116_skills_default_on.sql +37 -0
  242. package/src/migrations/0117_sandbox_tiers.sql +11 -0
@@ -0,0 +1,94 @@
1
+ import { type DeviceLocalPolicySummary, type SandboxLimits, type SandboxTier } from "@capybara-hq/plugin-sdk";
2
+ import { type OrgRole } from "../orgs/roles.js";
3
+ import type { ResolvedTool } from "../tools/registry.js";
4
+ import { TIER_GRANT_SPEC_HASH, TIER_OPEN_GRANT_KEY } from "./unattended.js";
5
+ export { TIER_GRANT_SPEC_HASH, TIER_OPEN_GRANT_KEY };
6
+ /**
7
+ * The one rule for what can be a scheduled task's grant (spec §7): the task form and
8
+ * `addGrants`, a trial run's kept approvals and the unattended policy's `missing_grants` all ask
9
+ * it. A plain module (no provider): the tool policy imports it.
10
+ */
11
+ /** Who asks for a grant and where: the inputs of {@link grantRefusalOf}. */
12
+ export interface GrantContext {
13
+ role: OrgRole;
14
+ forbiddenTools: readonly string[];
15
+ }
16
+ /**
17
+ * Why a tool can't be a task's grant, as a code the UI words: `forbidden` (the org's
18
+ * `forbiddenTools`), `not_grantable` (by design: a Platform call that changes the agent's
19
+ * skills, or any other per-call key such as `Platform:<operation>`), `not_available` (not one of the agent's tools now), `needs_role` (a
20
+ * `requiredRole` above the creator's), `fixed_ask` (always asks a person). A network grant
21
+ * (`network:<host>`, {@link networkGrantRefusal}) adds `needs_admin` (outside the org's network
22
+ * allowlist: only an org admin can add the host) and `device_refuses` (the task's device takes no
23
+ * network grants from the deployment: `remoteGrants` off); an invalid or wildcard host is
24
+ * `not_grantable`.
25
+ */
26
+ export type GrantRefusalCode = "forbidden" | "not_grantable" | "not_available" | "needs_role" | "fixed_ask" | "needs_admin" | "device_refuses";
27
+ /**
28
+ * Why `toolKey` cannot be one of a task's grants, or null when it can: the creator could approve
29
+ * it with scope `always` themselves (no `requiredRole` above their role, not a fixed ask), it is
30
+ * the tool's own key (a per-call key such as `Platform:<operation>` is decided per call and never
31
+ * a task grant), it changes none of the agent's skills (an unattended run never does) and
32
+ * the org forbids neither the key nor the tool. `tool`: the agent's tool `toolKey` belongs to,
33
+ * undefined when the agent does not have it now.
34
+ */
35
+ export declare function grantRefusalOf(toolKey: string, tool: ResolvedTool | undefined, ctx: GrantContext): {
36
+ code: GrantRefusalCode;
37
+ message: string;
38
+ } | null;
39
+ /** {@link grantRefusalOf}'s message alone; null when the tool can be granted. */
40
+ export declare function grantRefusal(toolKey: string, tool: ResolvedTool | undefined, ctx: GrantContext): string | null;
41
+ /** The prefix of a network grant's key (network ask-to-allow spec §8.1). */
42
+ export declare const NETWORK_GRANT_PREFIX = "network:";
43
+ /** The `spec_hash` a network grant is stored with (no tool definition behind it; plan P-D7). */
44
+ export declare const NETWORK_GRANT_SPEC_HASH = "network";
45
+ /** Whether a grant key is a network grant (`network:<host>`). */
46
+ export declare const isNetworkGrantKey: (key: string) => boolean;
47
+ /** The host of a network grant key (`network:<host>`). */
48
+ export declare const networkGrantHost: (key: string) => string;
49
+ /** What {@link networkGrantRefusal} checks a host against. */
50
+ export interface NetworkGrantContext {
51
+ /**
52
+ * The network of the org's sandbox ceiling now (`SandboxService.ceilingLimits`): the most a
53
+ * device's command may reach.
54
+ */
55
+ limits: Pick<SandboxLimits, "egress" | "allowHosts">;
56
+ /**
57
+ * The local policy summary of the task's device (its active machine); null or undefined when
58
+ * the task has no device that can be determined or its machine is not connected: the device
59
+ * rule is then skipped (the device still refuses at the command, and the run notes it).
60
+ */
61
+ deviceSummary?: DeviceLocalPolicySummary | null;
62
+ }
63
+ /**
64
+ * Why `host` cannot be one of a task's network grants (network ask-to-allow spec §8.1), or null
65
+ * when it can: `not_grantable` (not an exact, valid host name: no wildcard, no address),
66
+ * `needs_admin` (the org's effective egress does not admit it: only an org admin can add it),
67
+ * `device_refuses` (the task's device reports `remoteGrants: "off"`). The host is compared as given
68
+ * (callers lower-case it first).
69
+ */
70
+ export declare function networkGrantRefusal(host: string, ctx: NetworkGrantContext): {
71
+ code: GrantRefusalCode;
72
+ message: string;
73
+ } | null;
74
+ /** The prefix of a sandbox tier grant's key (sandbox dev tiers spec §11.4): only `tier:open` exists. */
75
+ export declare const TIER_GRANT_PREFIX = "tier:";
76
+ /** Whether a grant key is a sandbox tier grant (`tier:<tier>`). */
77
+ export declare const isTierGrantKey: (key: string) => boolean;
78
+ /** Whether a grant key names no tool: a network grant or a sandbox tier grant. */
79
+ export declare const isPolicyGrantKey: (key: string) => boolean;
80
+ /**
81
+ * Why `key` cannot be a task's sandbox tier grant (sandbox dev tiers spec §11.4), or null when it
82
+ * can: only `tier:open` is one (`not_grantable` otherwise), and only while the org's ceiling
83
+ * (`ceiling`: its highest tier, cut to the platform's) is `open` (`needs_admin`: only an org admin
84
+ * can raise it, within the platform's), and only while the task's device can reach it
85
+ * (`deviceReachesOpen: false`, `device_refuses`: a local device whose program applies no tiers
86
+ * runs every command in `strict`).
87
+ */
88
+ export declare function tierGrantRefusal(key: string, ctx: {
89
+ ceiling: SandboxTier;
90
+ deviceReachesOpen?: boolean;
91
+ }): {
92
+ code: GrantRefusalCode;
93
+ message: string;
94
+ } | null;
@@ -0,0 +1,126 @@
1
+ import { validateAllowHost, } from "@capybara-hq/plugin-sdk";
2
+ import { orgAllows } from "../local-devices/network-grants.js";
3
+ import { roleAtLeast } from "../orgs/roles.js";
4
+ import { isFixedAsk } from "../tools/fixed-ask.js";
5
+ import { changesAgentSkills, TIER_GRANT_SPEC_HASH, TIER_OPEN_GRANT_KEY } from "./unattended.js";
6
+ export { TIER_GRANT_SPEC_HASH, TIER_OPEN_GRANT_KEY };
7
+ /**
8
+ * Why `toolKey` cannot be one of a task's grants, or null when it can: the creator could approve
9
+ * it with scope `always` themselves (no `requiredRole` above their role, not a fixed ask), it is
10
+ * the tool's own key (a per-call key such as `Platform:<operation>` is decided per call and never
11
+ * a task grant), it changes none of the agent's skills (an unattended run never does) and
12
+ * the org forbids neither the key nor the tool. `tool`: the agent's tool `toolKey` belongs to,
13
+ * undefined when the agent does not have it now.
14
+ */
15
+ export function grantRefusalOf(toolKey, tool, ctx) {
16
+ if (ctx.forbiddenTools.includes(toolKey) ||
17
+ (tool !== undefined && ctx.forbiddenTools.includes(tool.key))) {
18
+ return {
19
+ code: "forbidden",
20
+ message: `The organization does not allow ${toolKey} in scheduled runs`,
21
+ };
22
+ }
23
+ if (changesAgentSkills(toolKey)) {
24
+ return {
25
+ code: "not_grantable",
26
+ message: `${toolKey} cannot be approved for a scheduled task: an unattended run never changes the agent's skills`,
27
+ };
28
+ }
29
+ if (!tool) {
30
+ return { code: "not_available", message: `${toolKey} is not one of the agent's tools now` };
31
+ }
32
+ if (toolKey !== tool.key) {
33
+ return {
34
+ code: "not_grantable",
35
+ message: `${toolKey} is decided per call and cannot be approved in advance for a scheduled task`,
36
+ };
37
+ }
38
+ if (tool.requiredRole !== undefined && !roleAtLeast(ctx.role, tool.requiredRole)) {
39
+ return {
40
+ code: "needs_role",
41
+ message: `${toolKey} needs the ${tool.requiredRole} role to approve; you cannot approve it for the task`,
42
+ };
43
+ }
44
+ if (isFixedAsk(tool)) {
45
+ return {
46
+ code: "fixed_ask",
47
+ message: `${toolKey} always asks a person and cannot be approved in advance`,
48
+ };
49
+ }
50
+ return null;
51
+ }
52
+ /** {@link grantRefusalOf}'s message alone; null when the tool can be granted. */
53
+ export function grantRefusal(toolKey, tool, ctx) {
54
+ return grantRefusalOf(toolKey, tool, ctx)?.message ?? null;
55
+ }
56
+ /** The prefix of a network grant's key (network ask-to-allow spec §8.1). */
57
+ export const NETWORK_GRANT_PREFIX = "network:";
58
+ /** The `spec_hash` a network grant is stored with (no tool definition behind it; plan P-D7). */
59
+ export const NETWORK_GRANT_SPEC_HASH = "network";
60
+ /** Whether a grant key is a network grant (`network:<host>`). */
61
+ export const isNetworkGrantKey = (key) => key.startsWith(NETWORK_GRANT_PREFIX);
62
+ /** The host of a network grant key (`network:<host>`). */
63
+ export const networkGrantHost = (key) => key.slice(NETWORK_GRANT_PREFIX.length);
64
+ /**
65
+ * Why `host` cannot be one of a task's network grants (network ask-to-allow spec §8.1), or null
66
+ * when it can: `not_grantable` (not an exact, valid host name: no wildcard, no address),
67
+ * `needs_admin` (the org's effective egress does not admit it: only an org admin can add it),
68
+ * `device_refuses` (the task's device reports `remoteGrants: "off"`). The host is compared as given
69
+ * (callers lower-case it first).
70
+ */
71
+ export function networkGrantRefusal(host, ctx) {
72
+ if (host.startsWith("*.") || validateAllowHost(host).length > 0) {
73
+ return {
74
+ code: "not_grantable",
75
+ message: `${host} cannot be approved for a scheduled task: give one exact domain name (no wildcard, no IP address or local name)`,
76
+ };
77
+ }
78
+ if (!orgAllows(host, ctx.limits)) {
79
+ return {
80
+ code: "needs_admin",
81
+ message: `${host} is not in the organization's network allowlist; only an organization admin can add it`,
82
+ };
83
+ }
84
+ if (ctx.deviceSummary?.remoteGrants === "off") {
85
+ return {
86
+ code: "device_refuses",
87
+ message: `The task's device does not accept network grants from the deployment; its owner can allow ${host} locally: capybara-device policy add allowedDomains ${host}`,
88
+ };
89
+ }
90
+ return null;
91
+ }
92
+ /** The prefix of a sandbox tier grant's key (sandbox dev tiers spec §11.4): only `tier:open` exists. */
93
+ export const TIER_GRANT_PREFIX = "tier:";
94
+ /** Whether a grant key is a sandbox tier grant (`tier:<tier>`). */
95
+ export const isTierGrantKey = (key) => key.startsWith(TIER_GRANT_PREFIX);
96
+ /** Whether a grant key names no tool: a network grant or a sandbox tier grant. */
97
+ export const isPolicyGrantKey = (key) => isNetworkGrantKey(key) || isTierGrantKey(key);
98
+ /**
99
+ * Why `key` cannot be a task's sandbox tier grant (sandbox dev tiers spec §11.4), or null when it
100
+ * can: only `tier:open` is one (`not_grantable` otherwise), and only while the org's ceiling
101
+ * (`ceiling`: its highest tier, cut to the platform's) is `open` (`needs_admin`: only an org admin
102
+ * can raise it, within the platform's), and only while the task's device can reach it
103
+ * (`deviceReachesOpen: false`, `device_refuses`: a local device whose program applies no tiers
104
+ * runs every command in `strict`).
105
+ */
106
+ export function tierGrantRefusal(key, ctx) {
107
+ if (key !== TIER_OPEN_GRANT_KEY) {
108
+ return {
109
+ code: "not_grantable",
110
+ message: `${key} cannot be approved for a scheduled task; the only sandbox level a task can allow is ${TIER_OPEN_GRANT_KEY}`,
111
+ };
112
+ }
113
+ if (ctx.ceiling !== "open") {
114
+ return {
115
+ code: "needs_admin",
116
+ message: `The organization's highest sandbox level is ${ctx.ceiling}, so a scheduled task cannot allow the open level; only an organization admin can raise it`,
117
+ };
118
+ }
119
+ if (ctx.deviceReachesOpen === false) {
120
+ return {
121
+ code: "device_refuses",
122
+ message: "The task's device runs a capybara-device program without sandbox levels, so its commands always run at the strict level; update the program on the device, then allow the open level",
123
+ };
124
+ }
125
+ return null;
126
+ }
@@ -0,0 +1,32 @@
1
+ /** The scheduled tasks' jobs (a leaf module: no imports). */
2
+ /**
3
+ * The once-a-minute `@LockedCron` that turns due tasks into task runs (spec §6); its name enqueued
4
+ * on the maintenance queue runs one scan (`ScheduledRuns.runNow`).
5
+ */
6
+ export declare const SCHED_SCAN_JOB = "scheduled-task-scan";
7
+ /** The one-off job that checks and starts one task run, on `cap-kernel-maintenance`. */
8
+ export declare const SCHED_FIRE_JOB = "sched-fire";
9
+ /** The data of a {@link SCHED_FIRE_JOB}. */
10
+ export interface SchedFireJobData {
11
+ taskRunId: string;
12
+ }
13
+ /** The fire job's id: `sched-fire-<taskRunId>` (no `:`, task run ids are UUIDs). */
14
+ export declare const schedFireJobId: (taskRunId: string) => string;
15
+ /**
16
+ * The fire job of one task run. Removed when done, so the scanner's repair can enqueue it again
17
+ * after a lost job; the fire is idempotent on the task run's status, so retries are safe.
18
+ */
19
+ export declare function schedFireJob(taskRunId: string): {
20
+ name: string;
21
+ data: SchedFireJobData;
22
+ opts: {
23
+ jobId: string;
24
+ attempts: number;
25
+ backoff: {
26
+ type: "exponential";
27
+ delay: number;
28
+ };
29
+ removeOnComplete: true;
30
+ removeOnFail: true;
31
+ };
32
+ };
@@ -0,0 +1,27 @@
1
+ /** The scheduled tasks' jobs (a leaf module: no imports). */
2
+ /**
3
+ * The once-a-minute `@LockedCron` that turns due tasks into task runs (spec §6); its name enqueued
4
+ * on the maintenance queue runs one scan (`ScheduledRuns.runNow`).
5
+ */
6
+ export const SCHED_SCAN_JOB = "scheduled-task-scan";
7
+ /** The one-off job that checks and starts one task run, on `cap-kernel-maintenance`. */
8
+ export const SCHED_FIRE_JOB = "sched-fire";
9
+ /** The fire job's id: `sched-fire-<taskRunId>` (no `:`, task run ids are UUIDs). */
10
+ export const schedFireJobId = (taskRunId) => `${SCHED_FIRE_JOB}-${taskRunId}`;
11
+ /**
12
+ * The fire job of one task run. Removed when done, so the scanner's repair can enqueue it again
13
+ * after a lost job; the fire is idempotent on the task run's status, so retries are safe.
14
+ */
15
+ export function schedFireJob(taskRunId) {
16
+ return {
17
+ name: SCHED_FIRE_JOB,
18
+ data: { taskRunId },
19
+ opts: {
20
+ jobId: schedFireJobId(taskRunId),
21
+ attempts: 3,
22
+ backoff: { type: "exponential", delay: 2_000 },
23
+ removeOnComplete: true,
24
+ removeOnFail: true,
25
+ },
26
+ };
27
+ }
@@ -0,0 +1,9 @@
1
+ import type { KernelSchemaDb } from "../db/kernel-schema.js";
2
+ import type { SchedulePauseReason } from "./types.js";
3
+ /**
4
+ * Pauses an active live task for `reason` in the caller's transaction `t` (the fire job, the run
5
+ * tracker, the delivery path); `by` is the account that caused it, null for the kernel. A task
6
+ * already paused or ended keeps its state and reason. A plain function so the run tracker, which
7
+ * the runtime imports, needs no service of the schedules domain.
8
+ */
9
+ export declare function pauseTaskIn(t: KernelSchemaDb, taskId: string, reason: SchedulePauseReason, by: string | null): Promise<void>;
@@ -0,0 +1,33 @@
1
+ import { sql } from "kysely";
2
+ import { audit } from "../identity/audit.js";
3
+ /**
4
+ * Pauses an active live task for `reason` in the caller's transaction `t` (the fire job, the run
5
+ * tracker, the delivery path); `by` is the account that caused it, null for the kernel. A task
6
+ * already paused or ended keeps its state and reason. A plain function so the run tracker, which
7
+ * the runtime imports, needs no service of the schedules domain.
8
+ */
9
+ export async function pauseTaskIn(t, taskId, reason, by) {
10
+ const row = await t
11
+ .updateTable("scheduled_tasks")
12
+ .set({
13
+ status: "paused",
14
+ pause_reason: reason,
15
+ paused_by: by,
16
+ next_run_at: null,
17
+ updated_at: sql `now()`,
18
+ })
19
+ .where("id", "=", taskId)
20
+ .where("status", "=", "active")
21
+ .where("deleted_at", "is", null)
22
+ .returning(["org_id", "account_id"])
23
+ .executeTakeFirst();
24
+ if (!row)
25
+ return;
26
+ await audit(t, {
27
+ actorAccountId: by,
28
+ orgId: row.org_id,
29
+ action: "schedule.paused",
30
+ target: taskId,
31
+ detail: { reason, creator: row.account_id },
32
+ });
33
+ }
@@ -0,0 +1,81 @@
1
+ import type { KernelSchemaDb } from "../db/kernel-schema.js";
2
+ import { KernelConfigService } from "../infra/config/kernel-config.service.js";
3
+ import { KernelDb } from "../infra/database/kernel-db.js";
4
+ import { TransactionHost } from "../infra/database/transaction-host.js";
5
+ import type { TaskRun } from "./types.js";
6
+ /** How a kernel run ended (`runs.status` once terminal). */
7
+ export type RunOutcome = "completed" | "failed" | "aborted";
8
+ /**
9
+ * How long a task run that was started (its message created or queued) may show no trace of its
10
+ * message before the overlap check releases it: the fire job writes `fired_at` before it creates
11
+ * the conversation or queues the item, in a transaction of its own.
12
+ */
13
+ export declare const START_GRACE_MS: number;
14
+ /**
15
+ * Follows a task run's kernel run to its end (scheduled tasks spec §6). {@link onRunFinished} runs
16
+ * in the transaction that writes a run's terminal state (`RunFinish.finishIn`, the one writer of
17
+ * terminal states), so a task run never misses its run's end: a run aborted by a person counts as
18
+ * completed; a failed one counts against the task (`consecutive_failures`, paused at the org's
19
+ * `pauseAfterFailures`), a completed one resets the count. Trial runs do not count.
20
+ * {@link inFlightIn} is the overlap check's view of the task's previous run: it settles a run whose
21
+ * end was missed and releases one whose queued message is gone.
22
+ */
23
+ export declare class ScheduledTaskRunTracker {
24
+ private readonly kdb;
25
+ readonly txHost: TransactionHost;
26
+ private readonly config;
27
+ constructor(kdb: KernelDb, txHost: TransactionHost, config: Pick<KernelConfigService, "get">);
28
+ private get db();
29
+ /**
30
+ * The kernel run `runId` ended with `outcome`: the task run it was started for (the run its
31
+ * message triggered, `scheduled_task_runs.run_id`) takes the outcome. A sub-agent or wake run
32
+ * that inherited the marker is not the task run's own and changes nothing.
33
+ */
34
+ onRunFinished(runId: string, outcome: RunOutcome, error?: string): Promise<void>;
35
+ /**
36
+ * Whether `prev`, a run of the task still `pending` or `running`, is really in flight (the
37
+ * overlap check, inside the fire's transaction). Settled on the way: a running one whose kernel
38
+ * run already ended takes its outcome; a started one linked to its run now when the run exists;
39
+ * a started one whose message another run consumed (`consumed_seq`, no run of its own) ends
40
+ * `completed`; a started one with no queued item, no message and no run after {@link START_GRACE_MS} (its
41
+ * queued item was removed or the queue cleared without the queue's own hook) becomes `skipped`
42
+ * (`removed`). The marker alone decides what is the task's message, never a client message id.
43
+ */
44
+ inFlightIn(prev: TaskRun, now?: Date): Promise<boolean>;
45
+ /**
46
+ * A pending task run whose start was refused (the fire job could not create or queue its
47
+ * message, for a reason that is not a lasting skip): it fails and counts against the task like
48
+ * a failed run (`consecutive_failures`, paused at the org's `pauseAfterFailures`), a trial run
49
+ * excepted. In the caller's transaction, which holds the task row.
50
+ */
51
+ failStartIn(taskRunId: string, error: string): Promise<void>;
52
+ /** Writes the task run's end and the task's failure count (non-trial runs). */
53
+ private settle;
54
+ }
55
+ /**
56
+ * A kernel run was created for task run `taskRunId` (its message is the run's trigger, or it
57
+ * inherited the marker): a task run still `pending` takes the run (`running`), in the caller's
58
+ * transaction (`RunQueue.ensureRunIn`, which inserts the run). A task run already linked (a
59
+ * sub-agent or wake run inheriting the marker) is left alone.
60
+ */
61
+ export declare function linkStartedRunIn(t: KernelSchemaDb, taskRunId: string, runId: string, conversationId: string): Promise<void>;
62
+ /**
63
+ * A queued run row was taken back before it ran (`RunQueue.deleteQueued`: its job could not be
64
+ * enqueued): the task run it had taken waits for the next run of its message again.
65
+ */
66
+ export declare function unlinkRunIn(t: KernelSchemaDb, taskRunId: string, runId: string): Promise<void>;
67
+ /**
68
+ * A person removed, edited or sent the queued item that carried `schedule` (the item's stored
69
+ * marker, or null): its task run will never run as the task's, so it becomes `skipped`
70
+ * (`removed`) in the caller's transaction, and the next tick is not held by the overlap check.
71
+ */
72
+ export declare function releaseQueuedTaskRunIn(t: KernelSchemaDb, schedule: unknown): Promise<void>;
73
+ /**
74
+ * Locks a task's row (deleted or not) in the caller's transaction. Every path that locks a task
75
+ * run and the task takes the task row first: the fire job's claim, the run tracker, the scan's
76
+ * repair (a run finishing while the next tick's claim checks overlap must not deadlock).
77
+ */
78
+ export declare function lockTaskRow(t: KernelSchemaDb, taskId: string): Promise<void>;
79
+ /** The run tracker alone: the runtime (`RunFinish`) imports it without the schedules service. */
80
+ export declare class ScheduledTaskTrackerModule {
81
+ }