@capybara-hq/kernel 0.1.0-rc.20 → 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 (247) hide show
  1. package/bootstrap.json +10 -1
  2. package/dist/agents/admin-agents.d.ts +16 -3
  3. package/dist/agents/admin-agents.js +65 -7
  4. package/dist/agents/agents.schemas.d.ts +24 -6
  5. package/dist/agents/agents.service.d.ts +4 -3
  6. package/dist/agents/agents.service.js +39 -26
  7. package/dist/agents/definition.d.ts +44 -6
  8. package/dist/agents/definition.js +86 -18
  9. package/dist/agents/from-template.d.ts +6 -3
  10. package/dist/agents/from-template.js +57 -44
  11. package/dist/agents/org-templates.js +97 -41
  12. package/dist/agents/templates.d.ts +6 -0
  13. package/dist/agents/templates.js +15 -1
  14. package/dist/catalog/admin-catalog.controller.d.ts +2 -4
  15. package/dist/catalog/admin-catalog.controller.js +2 -6
  16. package/dist/catalog/catalog.module.js +3 -0
  17. package/dist/catalog/claude/report.d.ts +9 -2
  18. package/dist/catalog/claude/report.js +1 -0
  19. package/dist/catalog/claude/translate.js +1 -1
  20. package/dist/catalog/component-promotion.js +1 -2
  21. package/dist/catalog/component-state.d.ts +13 -1
  22. package/dist/catalog/component-state.js +14 -5
  23. package/dist/catalog/marketplaces.service.d.ts +1 -1
  24. package/dist/catalog/marketplaces.service.js +2 -1
  25. package/dist/catalog/org-catalog.controller.d.ts +13 -3
  26. package/dist/catalog/org-catalog.controller.js +26 -4
  27. package/dist/catalog/org-catalog.schemas.d.ts +13 -0
  28. package/dist/catalog/org-catalog.schemas.js +34 -0
  29. package/dist/catalog/org-plugin-uploads.controller.js +0 -1
  30. package/dist/catalog/org-plugin-uploads.d.ts +0 -1
  31. package/dist/catalog/org-plugin-uploads.js +0 -3
  32. package/dist/catalog/org-plugin-uploads.schemas.d.ts +0 -1
  33. package/dist/catalog/org-plugin-uploads.schemas.js +0 -2
  34. package/dist/catalog/platform-components.d.ts +0 -1
  35. package/dist/catalog/platform-components.js +3 -8
  36. package/dist/catalog/plugin-import.d.ts +0 -8
  37. package/dist/catalog/plugin-import.js +4 -35
  38. package/dist/catalog/plugin-install.d.ts +2 -2
  39. package/dist/catalog/plugin-install.js +2 -2
  40. package/dist/catalog/plugin-package.d.ts +7 -0
  41. package/dist/catalog/plugin-package.js +27 -1
  42. package/dist/catalog/plugin-upgrade.d.ts +5 -6
  43. package/dist/catalog/plugin-upgrade.js +5 -23
  44. package/dist/catalog/requests.service.d.ts +66 -10
  45. package/dist/catalog/requests.service.js +196 -15
  46. package/dist/channels/actions.d.ts +2 -0
  47. package/dist/channels/actions.js +19 -4
  48. package/dist/channels/cards.d.ts +16 -2
  49. package/dist/channels/cards.js +40 -7
  50. package/dist/channels/channels.module.js +3 -0
  51. package/dist/channels/outbound.d.ts +22 -1
  52. package/dist/channels/outbound.js +116 -7
  53. package/dist/channels/phrases.d.ts +25 -0
  54. package/dist/channels/phrases.js +19 -0
  55. package/dist/channels/threads.d.ts +12 -0
  56. package/dist/channels/threads.js +34 -0
  57. package/dist/config/schema.d.ts +23 -1
  58. package/dist/config/schema.js +105 -5
  59. package/dist/conversations/conversations.service.d.ts +42 -9
  60. package/dist/conversations/conversations.service.js +57 -25
  61. package/dist/conversations/events.d.ts +106 -11
  62. package/dist/conversations/events.js +121 -18
  63. package/dist/conversations/message-context.d.ts +6 -3
  64. package/dist/conversations/message-context.js +14 -10
  65. package/dist/conversations/queue.d.ts +15 -2
  66. package/dist/conversations/queue.js +22 -3
  67. package/dist/conversations/queue.service.d.ts +12 -6
  68. package/dist/conversations/queue.service.js +36 -13
  69. package/dist/db/kernel-schema.d.ts +105 -3
  70. package/dist/devices/conversation-devices.d.ts +8 -1
  71. package/dist/devices/conversation-devices.js +8 -0
  72. package/dist/devices/devices.controller.d.ts +21 -4
  73. package/dist/devices/devices.controller.js +46 -8
  74. package/dist/devices/devices.schemas.d.ts +9 -1
  75. package/dist/devices/devices.schemas.js +11 -3
  76. package/dist/devices/devices.service.d.ts +176 -4
  77. package/dist/devices/devices.service.js +341 -6
  78. package/dist/devices/dto.d.ts +56 -3
  79. package/dist/devices/dto.js +51 -1
  80. package/dist/devices/public-suffix.d.ts +6 -0
  81. package/dist/devices/public-suffix.js +79 -0
  82. package/dist/errors.d.ts +46 -5
  83. package/dist/errors.js +46 -5
  84. package/dist/evals/reconstruct.d.ts +18 -13
  85. package/dist/evals/reconstruct.js +50 -36
  86. package/dist/evals/recorded-tools.d.ts +7 -7
  87. package/dist/evals/recorded-tools.js +4 -3
  88. package/dist/evals/trajectory.d.ts +6 -1
  89. package/dist/evals/trajectory.js +7 -0
  90. package/dist/extensions/bootstrap.d.ts +49 -10
  91. package/dist/extensions/bootstrap.js +104 -27
  92. package/dist/extensions/package.js +2 -2
  93. package/dist/http/api.module.js +5 -0
  94. package/dist/inbox/inbox.module.js +2 -1
  95. package/dist/inbox/inbox.service.d.ts +19 -4
  96. package/dist/inbox/inbox.service.js +14 -3
  97. package/dist/infra/config/kernel-config.service.js +11 -0
  98. package/dist/infra/events/kernel-events.d.ts +2 -1
  99. package/dist/lifecycle/kernel-lifecycle.d.ts +5 -1
  100. package/dist/lifecycle/kernel-lifecycle.js +16 -4
  101. package/dist/local-devices/device-policy.service.d.ts +65 -0
  102. package/dist/local-devices/device-policy.service.js +217 -0
  103. package/dist/local-devices/local-device-gateway.js +4 -1
  104. package/dist/local-devices/local-device-provider.d.ts +40 -3
  105. package/dist/local-devices/local-device-provider.js +109 -7
  106. package/dist/local-devices/local-devices.module.d.ts +2 -1
  107. package/dist/local-devices/local-devices.module.js +19 -3
  108. package/dist/local-devices/machines.d.ts +14 -3
  109. package/dist/local-devices/machines.js +41 -3
  110. package/dist/local-devices/network-grants.d.ts +104 -0
  111. package/dist/local-devices/network-grants.js +288 -0
  112. package/dist/local-devices/policy-summary.d.ts +20 -0
  113. package/dist/local-devices/policy-summary.js +63 -0
  114. package/dist/orgs/orgs.module.js +4 -10
  115. package/dist/orgs/roles.d.ts +1 -1
  116. package/dist/orgs/roles.js +4 -0
  117. package/dist/orgs/settings.controller.js +2 -1
  118. package/dist/orgs/settings.service.d.ts +164 -12
  119. package/dist/orgs/settings.service.js +212 -24
  120. package/dist/platform/exclusions.js +11 -1
  121. package/dist/platform/operation.js +4 -0
  122. package/dist/platform/ops/admin-items.ops.js +1 -1
  123. package/dist/platform/ops/agent-skills.ops.js +2 -2
  124. package/dist/platform/ops/agent-templates.ops.js +2 -2
  125. package/dist/platform/ops/agents.ops.js +11 -15
  126. package/dist/platform/ops/devices.ops.js +3 -1
  127. package/dist/platform/ops/inbox.ops.js +19 -0
  128. package/dist/platform/ops/org-settings.ops.js +14 -5
  129. package/dist/platform/ops/platform.ops.d.ts +9 -1
  130. package/dist/platform/ops/platform.ops.js +34 -12
  131. package/dist/platform/ops/requests.ops.js +3 -2
  132. package/dist/platform/ops/schedules.ops.d.ts +21 -0
  133. package/dist/platform/ops/schedules.ops.js +470 -0
  134. package/dist/platform/ops/skills.ops.js +3 -3
  135. package/dist/platform/platform-ops.module.d.ts +2 -1
  136. package/dist/platform/platform-ops.module.js +5 -0
  137. package/dist/platform/route-schemas.js +3 -0
  138. package/dist/roles/worker.module.js +3 -0
  139. package/dist/runtime/context/build.js +13 -4
  140. package/dist/runtime/context/compaction.js +6 -3
  141. package/dist/runtime/context/device-paths.d.ts +43 -21
  142. package/dist/runtime/context/device-paths.js +104 -21
  143. package/dist/runtime/context/run-context.d.ts +9 -0
  144. package/dist/runtime/context/run-context.js +8 -0
  145. package/dist/runtime/context/skills.d.ts +14 -1
  146. package/dist/runtime/context/skills.js +36 -5
  147. package/dist/runtime/maintenance.d.ts +4 -2
  148. package/dist/runtime/maintenance.js +16 -5
  149. package/dist/runtime/run-finish.d.ts +6 -1
  150. package/dist/runtime/run-finish.js +16 -2
  151. package/dist/runtime/run-queue.js +21 -2
  152. package/dist/runtime/run-worker.js +14 -33
  153. package/dist/runtime/runtime.module.js +3 -0
  154. package/dist/runtime/subagents/definition.d.ts +32 -14
  155. package/dist/runtime/subagents/definition.js +106 -109
  156. package/dist/runtime/subagents/dispatch.js +4 -3
  157. package/dist/runtime/subagents/preamble.d.ts +2 -1
  158. package/dist/runtime/subagents/preamble.js +2 -1
  159. package/dist/runtime/waits.js +14 -4
  160. package/dist/sandbox/sandbox.service.d.ts +120 -10
  161. package/dist/sandbox/sandbox.service.js +335 -28
  162. package/dist/sandbox/tiers.d.ts +86 -0
  163. package/dist/sandbox/tiers.js +96 -0
  164. package/dist/schedules/effective-settings.d.ts +16 -0
  165. package/dist/schedules/effective-settings.js +17 -0
  166. package/dist/schedules/errors.d.ts +8 -0
  167. package/dist/schedules/errors.js +8 -0
  168. package/dist/schedules/fire.d.ts +118 -0
  169. package/dist/schedules/fire.js +625 -0
  170. package/dist/schedules/grant-rules.d.ts +94 -0
  171. package/dist/schedules/grant-rules.js +126 -0
  172. package/dist/schedules/job-ids.d.ts +32 -0
  173. package/dist/schedules/job-ids.js +27 -0
  174. package/dist/schedules/pause.d.ts +9 -0
  175. package/dist/schedules/pause.js +33 -0
  176. package/dist/schedules/run-tracker.d.ts +81 -0
  177. package/dist/schedules/run-tracker.js +333 -0
  178. package/dist/schedules/scan.job.d.ts +64 -0
  179. package/dist/schedules/scan.job.js +303 -0
  180. package/dist/schedules/schedule-math.d.ts +31 -0
  181. package/dist/schedules/schedule-math.js +223 -0
  182. package/dist/schedules/scheduled-tasks.service.d.ts +351 -0
  183. package/dist/schedules/scheduled-tasks.service.js +1193 -0
  184. package/dist/schedules/schedules.controller.d.ts +68 -0
  185. package/dist/schedules/schedules.controller.js +242 -0
  186. package/dist/schedules/schedules.module.d.ts +16 -0
  187. package/dist/schedules/schedules.module.js +65 -0
  188. package/dist/schedules/schedules.schemas.d.ts +316 -0
  189. package/dist/schedules/schedules.schemas.js +186 -0
  190. package/dist/schedules/store.d.ts +81 -0
  191. package/dist/schedules/store.js +390 -0
  192. package/dist/schedules/store.module.d.ts +6 -0
  193. package/dist/schedules/store.module.js +21 -0
  194. package/dist/schedules/types.d.ts +108 -0
  195. package/dist/schedules/types.js +1 -0
  196. package/dist/schedules/unattended.d.ts +117 -0
  197. package/dist/schedules/unattended.js +228 -0
  198. package/dist/setup/oauth-token-probe.js +8 -4
  199. package/dist/skills/agent-skills.service.d.ts +4 -8
  200. package/dist/skills/agent-skills.service.js +18 -53
  201. package/dist/skills/catalog.d.ts +65 -62
  202. package/dist/skills/catalog.js +109 -206
  203. package/dist/skills/conversation-catalog.d.ts +3 -3
  204. package/dist/skills/conversation-catalog.js +5 -12
  205. package/dist/skills/invoke.d.ts +2 -2
  206. package/dist/skills/skills.controller.d.ts +3 -1
  207. package/dist/skills/skills.service.d.ts +38 -37
  208. package/dist/skills/skills.service.js +168 -107
  209. package/dist/skills/usable.d.ts +57 -8
  210. package/dist/skills/usable.js +172 -38
  211. package/dist/tools/approvals.controller.d.ts +4 -2
  212. package/dist/tools/approvals.controller.js +17 -2
  213. package/dist/tools/approvals.schemas.d.ts +1 -0
  214. package/dist/tools/approvals.schemas.js +3 -1
  215. package/dist/tools/approvals.service.d.ts +182 -7
  216. package/dist/tools/approvals.service.js +597 -13
  217. package/dist/tools/builtin-names.d.ts +25 -4
  218. package/dist/tools/builtin-names.js +45 -4
  219. package/dist/tools/builtins/builtin-tools.d.ts +8 -0
  220. package/dist/tools/builtins/builtin-tools.js +23 -2
  221. package/dist/tools/builtins/sandbox/bash.js +16 -7
  222. package/dist/tools/builtins/sandbox/common.d.ts +1 -1
  223. package/dist/tools/builtins/sandbox/common.js +33 -10
  224. package/dist/tools/builtins/sandbox/edit.js +7 -3
  225. package/dist/tools/builtins/sandbox/file-state.d.ts +31 -1
  226. package/dist/tools/builtins/sandbox/file-state.js +33 -3
  227. package/dist/tools/builtins/sandbox/write.js +8 -4
  228. package/dist/tools/builtins/schedules.d.ts +107 -0
  229. package/dist/tools/builtins/schedules.js +789 -0
  230. package/dist/tools/elicitation.d.ts +2 -0
  231. package/dist/tools/elicitation.js +1 -1
  232. package/dist/tools/fixed-ask.d.ts +7 -0
  233. package/dist/tools/fixed-ask.js +9 -0
  234. package/dist/tools/network-asks.d.ts +109 -0
  235. package/dist/tools/network-asks.js +221 -0
  236. package/dist/tools/pipeline.d.ts +53 -6
  237. package/dist/tools/pipeline.js +202 -13
  238. package/dist/tools/policy.d.ts +21 -8
  239. package/dist/tools/policy.js +63 -9
  240. package/dist/tools/registry.d.ts +10 -1
  241. package/dist/tools/tools.module.js +12 -0
  242. package/package.json +2 -2
  243. package/src/migrations/0113_scheduled_tasks.sql +108 -0
  244. package/src/migrations/0114_network_asks.sql +23 -0
  245. package/src/migrations/0115_network_requests.sql +28 -0
  246. package/src/migrations/0116_skills_default_on.sql +37 -0
  247. package/src/migrations/0117_sandbox_tiers.sql +11 -0
@@ -1,6 +1,7 @@
1
- import { type BootstrapManifest, type Logger } from "@capybara-hq/plugin-sdk";
1
+ import { type BootstrapEntry, type BootstrapManifest, type Logger } from "@capybara-hq/plugin-sdk";
2
2
  import { type PluginImport } from "../catalog/plugin-import.js";
3
3
  import type { KernelConfig } from "../config/schema.js";
4
+ import { ApiError } from "../errors.js";
4
5
  import { KernelConfigService } from "../infra/config/kernel-config.service.js";
5
6
  import { KernelDb } from "../infra/database/kernel-db.js";
6
7
  import { TransactionHost } from "../infra/database/transaction-host.js";
@@ -35,9 +36,15 @@ import type { SingleProviderNote } from "./single-provider.js";
35
36
  * until expiry) aborts the run at its next step. "Done" is a `bootstrap_runs` row for the
36
37
  * manifest's sha256 (written with the audit `bootstrap.completed` only when every entry
37
38
  * succeeded; otherwise the next start runs it again, which is idempotent).
39
+ * - Two passes per start: the first runs before the extensions load (no object store yet), the
40
+ * second after them. A `builtin` entry (not required, but builtin in the catalog) is deferred by
41
+ * the first pass (`deferBuiltin`: skipped, not a failure; the run is then not recorded and the
42
+ * start runs the second pass), so it may ship skills and templates. A required entry is imported
43
+ * by the first pass and must succeed; a builtin one that fails is logged like an optional one.
38
44
  * - Only entries new to the manifest are installed (Ruling 5): an optional entry that the last
39
45
  * completed run already handled and that is not installed now (a super admin uninstalled
40
- * it) stays uninstalled -> `kept`. A required entry is always installed.
46
+ * it) stays uninstalled -> `kept`. A required or builtin entry is always installed (a
47
+ * declarative one imported again when its catalog item is gone).
41
48
  * - Per entry, by the installed state of its extension:
42
49
  * - not installed (and new, or required): imported into the catalog (source `bootstrap`, ref
43
50
  * `bootstrap:<name>@<version>`, like a marketplace import), installed, approved (snapshot
@@ -65,7 +72,8 @@ import type { SingleProviderNote } from "./single-provider.js";
65
72
  * never needed again. A plugin's icons and setup guide files are kept in PG too (`catalog_files`),
66
73
  * so they never need it either; its skills, connector templates and agent templates do (an entry
67
74
  * shipping them fails while no object store runs; an optional one is retried after the extensions
68
- * loaded).
75
+ * loaded, and a plugin that must be builtin and ships them is a `builtin` entry, which only the
76
+ * pass after the extensions load imports).
69
77
  */
70
78
  /** The bootstrap manifest that ships with the kernel package. */
71
79
  export declare const BOOTSTRAP_MANIFEST_FILE: string;
@@ -93,15 +101,23 @@ export interface BootstrapFailure {
93
101
  code: string;
94
102
  message: string;
95
103
  }
96
- /** Some entries failed (the others were done); the run is not recorded as done. */
104
+ /**
105
+ * Some entries failed or were deferred (the others were done); the run is not recorded as done.
106
+ */
97
107
  export declare class BootstrapFailedError extends Error {
98
108
  readonly failures: BootstrapFailure[];
99
109
  readonly results: BootstrapEntryResult[];
110
+ readonly deferred: string[];
111
+ readonly packages: ReadonlyMap<string, Uint8Array>;
100
112
  /**
101
113
  * @param results what the entries that did not fail did (pass them as `carry` to a later run in
102
114
  * the same start, so its record keeps `installed` instead of `kept`).
115
+ * @param deferred the builtin entries a first pass skipped (`deferBuiltin`): not failures, the
116
+ * later pass of the same start imports them.
117
+ * @param packages the packages this run obtained, by entry name (pass them as `packages` to the
118
+ * later pass of the same start, so nothing is downloaded twice).
103
119
  */
104
- constructor(failures: BootstrapFailure[], results?: BootstrapEntryResult[]);
120
+ constructor(failures: BootstrapFailure[], results?: BootstrapEntryResult[], deferred?: string[], packages?: ReadonlyMap<string, Uint8Array>);
105
121
  /** A required entry failed: the kernel must not serve without it. */
106
122
  get requiredFailed(): boolean;
107
123
  }
@@ -121,13 +137,21 @@ export interface BootstrapResolveOptions {
121
137
  log?: Pick<Logger, "warn">;
122
138
  /** The npm download (default {@link fetchNpmPackage}; tests replace it). */
123
139
  fetch?: typeof fetchNpmPackage;
140
+ /**
141
+ * Entries whose package failing to be obtained is that entry's failure only: the error goes into
142
+ * `failed` (by entry name) and the other entries are still obtained. Every other entry's failure
143
+ * throws, so nothing is written.
144
+ */
145
+ soft?: (e: BootstrapEntry) => boolean;
146
+ failed?: Map<string, ApiError>;
124
147
  }
125
148
  /**
126
149
  * Obtains every entry's tgz, checked against its pinned sha512: from the offline directory when a
127
150
  * file there has that sha512, else (a `source: "npm"` entry) downloaded from the npm registry and
128
151
  * verified against the pin (the packument's `dist.integrity` is not consulted). Throws an
129
152
  * {@link ApiError} naming the plugin for the first entry it cannot obtain
130
- * (`bootstrap.missing_file`, `bootstrap.download_failed`, `bootstrap.integrity_mismatch`).
153
+ * (`bootstrap.missing_file`, `bootstrap.download_failed`, `bootstrap.integrity_mismatch`), except
154
+ * for the `soft` entries (recorded in `failed`, left out of the result).
131
155
  */
132
156
  export declare function resolveBootstrapPackages(manifest: BootstrapManifest, o: BootstrapResolveOptions): Promise<Map<string, Uint8Array>>;
133
157
  /** The lock around a whole run (`lock:bootstrap`). */
@@ -181,6 +205,17 @@ export declare class BootstrapService {
181
205
  dir?: string;
182
206
  signal?: AbortSignal;
183
207
  carry?: readonly BootstrapEntryResult[];
208
+ /**
209
+ * The first pass of a start (before the extensions load, so no object store): builtin entries
210
+ * are skipped, and the run throws {@link BootstrapFailedError} with them as `deferred` instead
211
+ * of being recorded as done.
212
+ */
213
+ deferBuiltin?: boolean;
214
+ /**
215
+ * Packages an earlier pass of the same start obtained ({@link BootstrapFailedError.packages});
216
+ * one whose sha512 still equals its entry's pin is used instead of obtaining it again.
217
+ */
218
+ packages?: ReadonlyMap<string, Uint8Array>;
184
219
  /** The plugin import a declarative entry (or an entry's catalog version) goes through. */
185
220
  imports: BootstrapImports;
186
221
  }): Promise<BootstrapResult>;
@@ -201,11 +236,15 @@ export declare class BootstrapService {
201
236
  /** The entry names the last completed run handled (undefined before any run completed). */
202
237
  private lastRunNames;
203
238
  private entry;
239
+ /** Whether a live (not deleted) platform catalog item has this name. */
240
+ private hasLiveItem;
204
241
  /**
205
- * The catalog item of a bootstrap entry follows `required`: a required entry is builtin, offered
206
- * to every org (scope `all`) and not disabled (migration 0075 could leave a required plugin
207
- * disabled); an entry that stops being required is no longer builtin and keeps scope `all` (the
208
- * admin may change it from then on).
242
+ * The catalog item of a bootstrap entry follows `required` / `builtin`: such an entry is builtin,
243
+ * offered to every org (scope `all`, which an org admin cannot switch off) and not disabled
244
+ * (migration 0075 could leave a required plugin disabled); an entry that stops being required or
245
+ * builtin is no longer builtin and keeps scope `all` (the admin may change it from then on).
246
+ * Only the platform item: an org-owned item of the same name (the entry then fails with
247
+ * `plugin.name_taken`) is never touched.
209
248
  */
210
249
  private markBuiltin;
211
250
  /** A declarative plugin: catalog only. Returns false when that version is already imported. */
@@ -57,9 +57,15 @@ import { ExtensionRegistry } from "./registry.js";
57
57
  * until expiry) aborts the run at its next step. "Done" is a `bootstrap_runs` row for the
58
58
  * manifest's sha256 (written with the audit `bootstrap.completed` only when every entry
59
59
  * succeeded; otherwise the next start runs it again, which is idempotent).
60
+ * - Two passes per start: the first runs before the extensions load (no object store yet), the
61
+ * second after them. A `builtin` entry (not required, but builtin in the catalog) is deferred by
62
+ * the first pass (`deferBuiltin`: skipped, not a failure; the run is then not recorded and the
63
+ * start runs the second pass), so it may ship skills and templates. A required entry is imported
64
+ * by the first pass and must succeed; a builtin one that fails is logged like an optional one.
60
65
  * - Only entries new to the manifest are installed (Ruling 5): an optional entry that the last
61
66
  * completed run already handled and that is not installed now (a super admin uninstalled
62
- * it) stays uninstalled -> `kept`. A required entry is always installed.
67
+ * it) stays uninstalled -> `kept`. A required or builtin entry is always installed (a
68
+ * declarative one imported again when its catalog item is gone).
63
69
  * - Per entry, by the installed state of its extension:
64
70
  * - not installed (and new, or required): imported into the catalog (source `bootstrap`, ref
65
71
  * `bootstrap:<name>@<version>`, like a marketplace import), installed, approved (snapshot
@@ -87,22 +93,35 @@ import { ExtensionRegistry } from "./registry.js";
87
93
  * never needed again. A plugin's icons and setup guide files are kept in PG too (`catalog_files`),
88
94
  * so they never need it either; its skills, connector templates and agent templates do (an entry
89
95
  * shipping them fails while no object store runs; an optional one is retried after the extensions
90
- * loaded).
96
+ * loaded, and a plugin that must be builtin and ships them is a `builtin` entry, which only the
97
+ * pass after the extensions load imports).
91
98
  */
92
99
  /** The bootstrap manifest that ships with the kernel package. */
93
100
  export const BOOTSTRAP_MANIFEST_FILE = fileURLToPath(new URL("../../bootstrap.json", import.meta.url));
94
- /** Some entries failed (the others were done); the run is not recorded as done. */
101
+ /**
102
+ * Some entries failed or were deferred (the others were done); the run is not recorded as done.
103
+ */
95
104
  export class BootstrapFailedError extends Error {
96
105
  failures;
97
106
  results;
107
+ deferred;
108
+ packages;
98
109
  /**
99
110
  * @param results what the entries that did not fail did (pass them as `carry` to a later run in
100
111
  * the same start, so its record keeps `installed` instead of `kept`).
112
+ * @param deferred the builtin entries a first pass skipped (`deferBuiltin`): not failures, the
113
+ * later pass of the same start imports them.
114
+ * @param packages the packages this run obtained, by entry name (pass them as `packages` to the
115
+ * later pass of the same start, so nothing is downloaded twice).
101
116
  */
102
- constructor(failures, results = []) {
103
- super(`bootstrap failed for ${failures.map((f) => `${f.name}${f.required ? " (required)" : ""}: ${f.message}`).join("; ")}`);
117
+ constructor(failures, results = [], deferred = [], packages = new Map()) {
118
+ super(failures.length > 0
119
+ ? `bootstrap failed for ${failures.map((f) => `${f.name}${f.required ? " (required)" : ""}: ${f.message}`).join("; ")}`
120
+ : `bootstrap deferred the builtin plugins ${deferred.join(", ")} to the pass after the extensions load`);
104
121
  this.failures = failures;
105
122
  this.results = results;
123
+ this.deferred = deferred;
124
+ this.packages = packages;
106
125
  this.name = "BootstrapFailedError";
107
126
  }
108
127
  /** A required entry failed: the kernel must not serve without it. */
@@ -128,7 +147,8 @@ const integrityOf = (bytes) => `sha512-${createHash("sha512").update(bytes).dige
128
147
  * file there has that sha512, else (a `source: "npm"` entry) downloaded from the npm registry and
129
148
  * verified against the pin (the packument's `dist.integrity` is not consulted). Throws an
130
149
  * {@link ApiError} naming the plugin for the first entry it cannot obtain
131
- * (`bootstrap.missing_file`, `bootstrap.download_failed`, `bootstrap.integrity_mismatch`).
150
+ * (`bootstrap.missing_file`, `bootstrap.download_failed`, `bootstrap.integrity_mismatch`), except
151
+ * for the `soft` entries (recorded in `failed`, left out of the result).
132
152
  */
133
153
  export async function resolveBootstrapPackages(manifest, o) {
134
154
  const out = new Map();
@@ -141,11 +161,20 @@ export async function resolveBootstrapPackages(manifest, o) {
141
161
  const where = o.dir !== undefined ? o.dir : "the bootstrap directory (config bootstrap.dir)";
142
162
  for (const e of manifest.plugins) {
143
163
  signal.throwIfAborted();
144
- const found = offline.get(e.integrity);
145
- if (found !== undefined) {
146
- out.set(e.name, found);
147
- continue;
164
+ try {
165
+ out.set(e.name, await obtain(e));
148
166
  }
167
+ catch (err) {
168
+ if (signal.aborted || !(err instanceof ApiError) || o.soft?.(e) !== true)
169
+ throw err;
170
+ o.failed?.set(e.name, err);
171
+ }
172
+ }
173
+ return out;
174
+ async function obtain(e) {
175
+ const found = offline.get(e.integrity);
176
+ if (found !== undefined)
177
+ return found;
149
178
  if (e.source === "workspace") {
150
179
  throw new ApiError("bootstrap.missing_file", `Bootstrap plugin ${e.name} ${e.version}: no file in ${where} has its pinned sha512 (${e.integrity.slice(0, 19)}…), and a workspace entry cannot be downloaded; put its package tgz (pnpm pack-plugin ${e.path}) in that directory`);
151
180
  }
@@ -153,7 +182,7 @@ export async function resolveBootstrapPackages(manifest, o) {
153
182
  const offlineHint = `to install offline, put the package tgz (npm pack ${e.npm}@${e.version}, any file name) in ${where}`;
154
183
  try {
155
184
  const r = await fetchPackage({ registry: npmRegistry, ...(npmToken !== undefined && { token: npmToken }), maxBytes }, e.npm, e.version, signal, { expectedIntegrity: e.integrity });
156
- out.set(e.name, r.bytes);
185
+ return r.bytes;
157
186
  }
158
187
  catch (err) {
159
188
  if (signal.aborted)
@@ -169,7 +198,6 @@ export async function resolveBootstrapPackages(manifest, o) {
169
198
  throw new ApiError("bootstrap.download_failed", `Bootstrap plugin ${e.name} ${e.version}: cannot download ${e.npm}@${e.version} from ${registry} (${reason}); ${offlineHint}, or set packages.npmRegistry to a reachable mirror`);
170
199
  }
171
200
  }
172
- return out;
173
201
  }
174
202
  /** The registry's origin, for messages (never its credentials or path). */
175
203
  function registryOrigin(registry) {
@@ -298,20 +326,47 @@ let BootstrapService = class BootstrapService {
298
326
  const done = await recorded();
299
327
  if (done)
300
328
  return done;
301
- // Every package is obtained and checked before the first write
302
- const files = await resolveBootstrapPackages(o.manifest, {
329
+ const deferBuiltin = o.deferBuiltin === true;
330
+ const isDeferred = (e) => deferBuiltin && e.builtin === true;
331
+ // Every package is obtained and checked before the first write (a deferred entry's by the
332
+ // later pass). The first pass refuses to write anything when one is missing or tampered;
333
+ // the later pass only fails that entry unless it is required.
334
+ const files = new Map();
335
+ const fetchFailed = new Map();
336
+ const toObtain = [];
337
+ for (const e of o.manifest.plugins) {
338
+ if (isDeferred(e))
339
+ continue;
340
+ const kept = o.packages?.get(e.name);
341
+ if (kept !== undefined && integrityOf(kept) === e.integrity)
342
+ files.set(e.name, kept);
343
+ else
344
+ toObtain.push(e);
345
+ }
346
+ const obtained = await resolveBootstrapPackages({ ...o.manifest, plugins: toObtain }, {
303
347
  ...(o.dir !== undefined && { dir: o.dir }),
304
348
  config: this.config(),
305
349
  signal,
306
350
  log: this.log,
351
+ ...(!deferBuiltin && { soft: (e) => !e.required, failed: fetchFailed }),
307
352
  });
353
+ for (const [name, bytes] of obtained)
354
+ files.set(name, bytes);
308
355
  const handled = await this.lastRunNames();
309
356
  const results = [];
310
357
  const failures = [];
358
+ const deferred = [];
311
359
  for (const e of o.manifest.plugins) {
312
360
  signal.throwIfAborted();
361
+ if (isDeferred(e)) {
362
+ deferred.push(e.name);
363
+ continue;
364
+ }
313
365
  await this.warnIfHeld(e);
314
366
  try {
367
+ const fetchErr = fetchFailed.get(e.name);
368
+ if (fetchErr !== undefined)
369
+ throw fetchErr;
315
370
  const r = await this.entry(e, files.get(e.name), handled, o.imports);
316
371
  results.push(carried(r, o.carry));
317
372
  }
@@ -320,6 +375,7 @@ let BootstrapService = class BootstrapService {
320
375
  plugin: e.name,
321
376
  version: e.version,
322
377
  required: e.required,
378
+ ...(e.builtin === true && { builtin: true }),
323
379
  err,
324
380
  });
325
381
  failures.push({
@@ -331,8 +387,9 @@ let BootstrapService = class BootstrapService {
331
387
  }
332
388
  }
333
389
  results.push(...(await this.clearRemoved(o.manifest)));
334
- if (failures.length > 0)
335
- throw new BootstrapFailedError(failures, results);
390
+ if (failures.length > 0 || deferred.length > 0) {
391
+ throw new BootstrapFailedError(failures, results, deferred, files);
392
+ }
336
393
  signal.throwIfAborted();
337
394
  await this.recordDone(manifestSha256, results);
338
395
  this.log.info("bootstrap completed", { manifestSha256, results });
@@ -421,12 +478,15 @@ let BootstrapService = class BootstrapService {
421
478
  const ref = `bootstrap:${e.name}@${e.version}`;
422
479
  // Not new to the manifest: an optional entry left out on purpose stays out (Ruling 5)
423
480
  const isNew = handled === undefined || !handled.has(e.name);
481
+ // Required and builtin entries are builtin in the catalog and put back when missing
482
+ const builtin = e.required || e.builtin === true;
424
483
  if (!pkg.manifest.extension) {
425
- await this.markBuiltin(e.name, e.required);
426
- if (!isNew)
484
+ await this.markBuiltin(e.name, builtin);
485
+ if (!isNew && !(builtin && !(await this.hasLiveItem(e.name)))) {
427
486
  return { name: e.name, action: "kept", version: e.version };
487
+ }
428
488
  const imported = await this.importOnly(e, bytes, ref, imports);
429
- await this.markBuiltin(e.name, e.required);
489
+ await this.markBuiltin(e.name, builtin);
430
490
  return { name: e.name, action: imported ? "imported" : "kept", version: e.version };
431
491
  }
432
492
  if (this.registry.declared().has(e.name)) {
@@ -438,7 +498,7 @@ let BootstrapService = class BootstrapService {
438
498
  .select(["version", "source", "required", "desired_state", "sha256"])
439
499
  .where("name", "=", e.name)
440
500
  .executeTakeFirst();
441
- if (!row && !isNew && !e.required) {
501
+ if (!row && !isNew && !builtin) {
442
502
  this.log.info("bootstrap: an optional plugin that is not installed stays uninstalled", {
443
503
  plugin: e.name,
444
504
  });
@@ -476,18 +536,31 @@ let BootstrapService = class BootstrapService {
476
536
  if (e.required && row?.desired_state === "disabled") {
477
537
  leftDisabled = await this.enableOrWarn(e);
478
538
  }
479
- await this.markBuiltin(e.name, e.required);
539
+ await this.markBuiltin(e.name, builtin);
480
540
  return leftDisabled === undefined ? result : { ...result, leftDisabled };
481
541
  }
542
+ /** Whether a live (not deleted) platform catalog item has this name. */
543
+ async hasLiveItem(name) {
544
+ const row = await this.db
545
+ .selectFrom("catalog_items")
546
+ .select("id")
547
+ .where("name", "=", name)
548
+ .where("owner_org_id", "is", null)
549
+ .where("deleted_at", "is", null)
550
+ .executeTakeFirst();
551
+ return row !== undefined;
552
+ }
482
553
  /**
483
- * The catalog item of a bootstrap entry follows `required`: a required entry is builtin, offered
484
- * to every org (scope `all`) and not disabled (migration 0075 could leave a required plugin
485
- * disabled); an entry that stops being required is no longer builtin and keeps scope `all` (the
486
- * admin may change it from then on).
554
+ * The catalog item of a bootstrap entry follows `required` / `builtin`: such an entry is builtin,
555
+ * offered to every org (scope `all`, which an org admin cannot switch off) and not disabled
556
+ * (migration 0075 could leave a required plugin disabled); an entry that stops being required or
557
+ * builtin is no longer builtin and keeps scope `all` (the admin may change it from then on).
558
+ * Only the platform item: an org-owned item of the same name (the entry then fails with
559
+ * `plugin.name_taken`) is never touched.
487
560
  */
488
- async markBuiltin(name, required) {
561
+ async markBuiltin(name, builtin) {
489
562
  const touch = { updated_at: sql `now()` };
490
- if (required) {
563
+ if (builtin) {
491
564
  await this.db
492
565
  .updateTable("catalog_items")
493
566
  .set({
@@ -498,6 +571,7 @@ let BootstrapService = class BootstrapService {
498
571
  ...touch,
499
572
  })
500
573
  .where("name", "=", name)
574
+ .where("owner_org_id", "is", null)
501
575
  .where("deleted_at", "is", null)
502
576
  .where((eb) => eb.or([eb("builtin", "=", false), eb("scope", "<>", "all"), eb("disabled", "=", true)]))
503
577
  .execute();
@@ -507,6 +581,7 @@ let BootstrapService = class BootstrapService {
507
581
  .updateTable("catalog_items")
508
582
  .set({ builtin: false, ...touch })
509
583
  .where("name", "=", name)
584
+ .where("owner_org_id", "is", null)
510
585
  .where("deleted_at", "is", null)
511
586
  .where("builtin", "=", true)
512
587
  .execute();
@@ -582,6 +657,7 @@ let BootstrapService = class BootstrapService {
582
657
  .selectFrom("catalog_items")
583
658
  .select("id")
584
659
  .where("name", "=", e.name)
660
+ .where("owner_org_id", "is", null)
585
661
  .where("deleted_at", "is", null)
586
662
  .executeTakeFirst();
587
663
  const installed = await this.ops.install(e.name, review.sha256, null, undefined, item ? { catalogItemId: item.id } : {});
@@ -650,6 +726,7 @@ let BootstrapService = class BootstrapService {
650
726
  .updateTable("catalog_items")
651
727
  .set({ builtin: false, updated_at: sql `now()` })
652
728
  .where("builtin", "=", true)
729
+ .where("owner_org_id", "is", null)
653
730
  .where("deleted_at", "is", null);
654
731
  if (names.length > 0)
655
732
  items = items.where("name", "not in", names);
@@ -2,7 +2,7 @@ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { dirname, join, posix, relative, resolve as resolvePath } from "node:path";
3
3
  import { checkEntryImports, isSafePackagePath, PLUGIN_MANIFEST_FILE, parsePluginManifest, } from "@capybara-hq/plugin-sdk";
4
4
  import { init as lexerInit, parse as lexerParse } from "es-module-lexer";
5
- import { PluginPackageError, readPluginPackage } from "../catalog/plugin-package.js";
5
+ import { PluginPackageError, readPluginPackage, withoutRemovedManifestFields, } from "../catalog/plugin-package.js";
6
6
  import { pluginSchemaName } from "../ctx/create-ctx.js";
7
7
  import { MIGRATION_FILE_RE } from "../db/migrator.js";
8
8
  import { ApiError } from "../errors.js";
@@ -252,7 +252,7 @@ export async function declaredDisplayName(dir, name) {
252
252
  const named = json?.name;
253
253
  if (typeof named === "string" && named !== name)
254
254
  return {};
255
- const m = parsePluginManifest(json);
255
+ const m = parsePluginManifest(withoutRemovedManifestFields(text));
256
256
  if ("errors" in m)
257
257
  return { problem: m.errors.slice(0, 3).join("; ") };
258
258
  if (m.name !== name)
@@ -68,6 +68,8 @@ import { OrgsModule } from "../orgs/orgs.module.js";
68
68
  import { OrgSettingsController } from "../orgs/settings.controller.js";
69
69
  import { RuntimeModule } from "../runtime/runtime.module.js";
70
70
  import { ConversationStreamController } from "../runtime/stream.controller.js";
71
+ import { SchedulesController } from "../schedules/schedules.controller.js";
72
+ import { SchedulesModule } from "../schedules/schedules.module.js";
71
73
  import { SetupModule } from "../setup/setup.module.js";
72
74
  import { SetupChecksController } from "../setup/setup-checks.controller.js";
73
75
  import { SetupGuidesController } from "../setup/setup-guides.controller.js";
@@ -123,6 +125,7 @@ const CONTROLLERS = [
123
125
  ConversationsController,
124
126
  BackgroundController,
125
127
  DevicesController,
128
+ SchedulesController,
126
129
  AttachmentsController,
127
130
  SkillsController,
128
131
  SkillChangesController,
@@ -204,6 +207,8 @@ ApiModule = __decorate([
204
207
  ThemesModule,
205
208
  ClientModule,
206
209
  SetupModule,
210
+ // scheduled tasks (the controller comes with the HTTP routes)
211
+ SchedulesModule,
207
212
  ],
208
213
  controllers: CONTROLLERS,
209
214
  providers: [{ provide: APP_GUARD, useClass: AuthGuard }],
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { Module } from "@nestjs/common";
8
8
  import { CatalogModule } from "../catalog/catalog.module.js";
9
+ import { SchedulesModule } from "../schedules/schedules.module.js";
9
10
  import { SkillsModule } from "../skills/skills.module.js";
10
11
  import { ToolsModule } from "../tools/tools.module.js";
11
12
  import { InboxService } from "./inbox.service.js";
@@ -18,7 +19,7 @@ let InboxModule = class InboxModule {
18
19
  };
19
20
  InboxModule = __decorate([
20
21
  Module({
21
- imports: [ToolsModule, SkillsModule, CatalogModule],
22
+ imports: [ToolsModule, SkillsModule, CatalogModule, SchedulesModule],
22
23
  providers: [InboxService, PlatformInboxService],
23
24
  exports: [InboxService, PlatformInboxService],
24
25
  })
@@ -1,5 +1,6 @@
1
1
  import { CatalogRequestsService, type CatalogRequestView } from "../catalog/requests.service.js";
2
2
  import { KernelDb } from "../infra/database/kernel-db.js";
3
+ import { type ScheduleAttention, ScheduledTasksService } from "../schedules/scheduled-tasks.service.js";
3
4
  import { SkillChangesService, type SkillChangeView } from "../skills/changes.service.js";
4
5
  import { ApprovalsService, type ApprovalView } from "../tools/approvals.service.js";
5
6
  import type { OrgNoticeDetails } from "./org-notices.js";
@@ -40,11 +41,16 @@ export declare const INBOX_MAX_ITEMS = 100;
40
41
  * - `tool_approval`:当前用户能处理的待处理工具调用审批(与 `GET /approvals?status=pending` 同一视图);
41
42
  * - `skill_change`: pending skill share requests and proposed versions of shared skills, when the
42
43
  * current user is an org admin (`skillChange.kind`; spec §5.4, §5.5);
43
- * - `catalog_request`: pending `enable` requests from members and pending `connector_setup`
44
- * requests (`request.kind`; `request.agent` and `request.connectors` set, `item` null; ruling
45
- * P4-T6-5), when the current user is an org admin (M6 T26, C22; plugin scope spec §5.1);
44
+ * - `catalog_request`: pending `enable` and `network_allowlist` requests from members and pending
45
+ * `connector_setup` requests (`request.kind`; for `connector_setup` `request.agent` and
46
+ * `request.connectors` set, `item` null, ruling P4-T6-5; for `network_allowlist`
47
+ * `request.network` set, network ask-to-allow spec §5.3), when the current user is an org admin
48
+ * (M6 T26, C22; plugin scope spec §5.1);
46
49
  * - `catalog_request_decided`: the current user's own requests in this org that were approved or
47
50
  * rejected (with the reason), until dismissed (`POST catalog-requests/:id/dismiss`);
51
+ * - `schedule_attention`: the current user's own scheduled task that needs them (spec §8): paused
52
+ * for any reason but their own pause, its latest run failed, or its latest run was refused tools
53
+ * or connections; derived live, gone once the task is resumed or runs clean;
48
54
  * - the org notices (`skill_renamed`, `item_shared`, `shared_item_updated`, `upload_confirmed`,
49
55
  * `upload_rejected`; `type` = the notice's kind): for org admins, until one dismisses it
50
56
  * (`POST inbox/notices/:id/dismiss`).
@@ -70,12 +76,20 @@ export type InboxItem = {
70
76
  /** When it was decided. */
71
77
  createdAt: string;
72
78
  request: CatalogRequestView;
79
+ } | {
80
+ type: "schedule_attention";
81
+ /** `<taskId>:paused`, `<taskId>:failed` or `<taskId>:grants`. */
82
+ id: string;
83
+ createdAt: string;
84
+ attention: ScheduleAttentionView;
73
85
  } | {
74
86
  type: OrgNoticeView["kind"];
75
87
  id: string;
76
88
  createdAt: string;
77
89
  notice: OrgNoticeView;
78
90
  };
91
+ /** A scheduled task that needs its creator ({@link ScheduleAttention}, dates as ISO strings). */
92
+ export type ScheduleAttentionView = Omit<ScheduleAttention, "at">;
79
93
  /** `GET /inbox` 的结果:新的在前,最多 {@link INBOX_MAX_ITEMS} 项;`truncated` 为 true 表示还有更多。 */
80
94
  export interface InboxView {
81
95
  items: InboxItem[];
@@ -87,7 +101,8 @@ export declare class InboxService {
87
101
  private readonly skillChanges;
88
102
  private readonly kdb;
89
103
  private readonly catalogRequests;
90
- constructor(approvals: Pick<ApprovalsService, "list">, skillChanges: Pick<SkillChangesService, "listPending">, kdb: KernelDb, catalogRequests: Pick<CatalogRequestsService, "listForOrgAdmin" | "listDecidedForRequester">);
104
+ private readonly schedules;
105
+ constructor(approvals: Pick<ApprovalsService, "list">, skillChanges: Pick<SkillChangesService, "listPending">, kdb: KernelDb, catalogRequests: Pick<CatalogRequestsService, "listForOrgAdmin" | "listDecidedForRequester">, schedules: Pick<ScheduledTasksService, "attentionFor">);
91
106
  list(orgId: string, accountId: string): Promise<InboxView>;
92
107
  /** The org's open notices when the account is an org admin (else none), newest first. */
93
108
  private notices;
@@ -13,6 +13,7 @@ import { CATALOG_REQUESTS_LIST_MAX, CatalogRequestsService, } from "../catalog/r
13
13
  import { ApiError } from "../errors.js";
14
14
  import { KernelDb } from "../infra/database/kernel-db.js";
15
15
  import { roleAtLeast } from "../orgs/roles.js";
16
+ import { ScheduledTasksService, } from "../schedules/scheduled-tasks.service.js";
16
17
  import { SKILL_CHANGES_LIST_MAX, SkillChangesService, } from "../skills/changes.service.js";
17
18
  import { APPROVALS_LIST_MAX, ApprovalsService, } from "../tools/approvals.service.js";
18
19
  /** The most open org notices one inbox read returns. */
@@ -25,19 +26,22 @@ let InboxService = class InboxService {
25
26
  skillChanges;
26
27
  kdb;
27
28
  catalogRequests;
28
- constructor(approvals, skillChanges, kdb, catalogRequests) {
29
+ schedules;
30
+ constructor(approvals, skillChanges, kdb, catalogRequests, schedules) {
29
31
  this.approvals = approvals;
30
32
  this.skillChanges = skillChanges;
31
33
  this.kdb = kdb;
32
34
  this.catalogRequests = catalogRequests;
35
+ this.schedules = schedules;
33
36
  }
34
37
  async list(orgId, accountId) {
35
- const [approvals, changes, requests, decided, notices] = await Promise.all([
38
+ const [approvals, changes, requests, decided, notices, attention] = await Promise.all([
36
39
  this.approvals.list(orgId, accountId, "pending"),
37
40
  this.skillChanges.listPending(orgId, accountId),
38
41
  this.catalogRequests.listForOrgAdmin(orgId, accountId),
39
42
  this.catalogRequests.listDecidedForRequester(orgId, accountId),
40
43
  this.notices(orgId, accountId),
44
+ this.schedules.attentionFor(orgId, accountId),
41
45
  ]);
42
46
  const all = [
43
47
  ...approvals.map((a) => ({
@@ -64,6 +68,12 @@ let InboxService = class InboxService {
64
68
  createdAt: r.decidedAt ?? r.createdAt,
65
69
  request: r,
66
70
  })),
71
+ ...attention.map(({ at, ...view }) => ({
72
+ type: "schedule_attention",
73
+ id: `${view.taskId}:${view.reason === "missing_grants" ? "grants" : view.reason === "failed" ? "failed" : "paused"}`,
74
+ createdAt: at.toISOString(),
75
+ attention: view,
76
+ })),
67
77
  ...notices.map((n) => ({ type: n.kind, id: n.id, createdAt: n.createdAt, notice: n })),
68
78
  ];
69
79
  // 新的在前;同一时刻按 id 定序(结果稳定)
@@ -142,7 +152,8 @@ InboxService = __decorate([
142
152
  __param(0, Inject(ApprovalsService)),
143
153
  __param(1, Inject(SkillChangesService)),
144
154
  __param(2, Inject(KernelDb)),
145
- __param(3, Inject(CatalogRequestsService))
155
+ __param(3, Inject(CatalogRequestsService)),
156
+ __param(4, Inject(ScheduledTasksService))
146
157
  ], InboxService);
147
158
  export { InboxService };
148
159
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -33,6 +33,10 @@ const HOT_APPLIERS = {
33
33
  "models.embedTimeoutMs": () => { },
34
34
  // SandboxService reads the shared-lease cap at every acquisition.
35
35
  "sandbox.maxConcurrentCommands": () => { },
36
+ // Sandbox tiers are read at every device use, org settings read and Platform call.
37
+ "sandbox.tiers.max": () => { },
38
+ "sandbox.tiers.default": () => { },
39
+ "sandbox.tiers.allowUnsandboxed": () => { },
36
40
  // The devices service reads the personal limit at every create.
37
41
  "devices.maxPersonal": () => { },
38
42
  // The local device relay reads the reconnect grace at every disconnect and token response.
@@ -48,6 +52,13 @@ const HOT_APPLIERS = {
48
52
  "web.fetch.maxAnswerTokens": () => { },
49
53
  "web.fetch.cacheSeconds": () => { },
50
54
  "web.fetch.timeoutMs": () => { },
55
+ // Scheduled-task settings are clamped to these bounds on every read.
56
+ "schedules.minIntervalFloorMinutes": () => { },
57
+ "schedules.maxTasksPerMemberCap": () => { },
58
+ "schedules.maxTasksPerOrgCap": () => { },
59
+ "schedules.maxRunsPerHourCap": () => { },
60
+ // Run start reads the skills catalog budget when it records a snapshot.
61
+ "skills.catalogBudgetChars": () => { },
51
62
  };
52
63
  /**
53
64
  * Environment variables of renamed config keys, with their replacements: warned about once when
@@ -31,7 +31,8 @@ export interface KernelEventMap {
31
31
  orgId: string;
32
32
  conversationId: string;
33
33
  runId: string;
34
- status: "approved" | "denied";
34
+ /** `skipped`: a network ask closed by the run's starter's message (network ask-to-allow §6.7). */
35
+ status: "approved" | "denied" | "skipped";
35
36
  };
36
37
  /**
37
38
  * A person answered a tool call's input request, or skipped it with a message (after the commit,
@@ -99,6 +99,8 @@ export declare class KernelLifecycle implements OnApplicationBootstrap, BeforeAp
99
99
  private unwatchConfig;
100
100
  /** What the first bootstrap pass did, carried into the second one. */
101
101
  private bootstrapCarry;
102
+ /** The packages the first bootstrap pass obtained, so the second downloads nothing again. */
103
+ private bootstrapPackages;
102
104
  constructor(accounts: AccountsService, configService: KernelConfigService, log: KernelLogger, options: KernelAppOptions, pool: Kysely<any>, redis: Redis, kdb: KernelDb, shutdown: GracefulShutdown, host: ExtensionHost, registry: ExtensionRegistry, installs: ExtensionInstalls, blobs: ExtensionBlobs, extensionLifecycle: ExtensionLifecycle, replicaStatus: ReplicaStatusStore, bootstrap: BootstrapService, marketplaces: MarketplacesService, pluginImport: PluginImport, bus: Pick<ExtensionContext["bus"], "publish" | "subscribe">, usageReport: UsageReporter, titles: TitleQueue, channelJobs: ChannelJobs, channelOutbound: ChannelOutbound, presence: ReplicaPresence, worker?: WorkerRole | undefined, gateway?: GatewayRole | undefined);
103
105
  /** The kernel HTTP application (set up by `buildKernelApp` before `init()`). */
104
106
  get http(): KernelHttpApp;
@@ -122,7 +124,9 @@ export declare class KernelLifecycle implements OnApplicationBootstrap, BeforeAp
122
124
  * kernel never serves without a required plugin. A failed optional entry is logged and returns
123
125
  * true: the start runs the step once more after the extensions loaded (a declarative entry's
124
126
  * catalog files need the object store, which on a fresh deployment is itself a bootstrap plugin),
125
- * and the next start tries again while it stays incomplete.
127
+ * and the next start tries again while it stays incomplete. The first pass skips the `builtin`
128
+ * entries (they may ship skills and templates, which need the object store) and returns true for
129
+ * them too; the final pass imports them, and one that fails is logged like an optional entry.
126
130
  */
127
131
  private runBootstrap;
128
132
  /** 部署尚无活跃超级管理员时提示去初始化;查询失败只记日志,不影响启动。 */