@desplega.ai/agent-swarm 1.112.0 → 1.114.0

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 (276) hide show
  1. package/README.md +2 -2
  2. package/dist/{actions-eckb4g8r.js → actions-bm8vdxys.js} +7 -8
  3. package/dist/{app-b05sgm02.js → app-bhwdxmvp.js} +5 -5
  4. package/dist/{assistant-7255sbyw.js → assistant-15mp2apr.js} +18 -17
  5. package/dist/{boot-reembed-y1bt3ttn.js → boot-reembed-awr2179r.js} +6 -6
  6. package/dist/{boot-reembed-yv7awg4y.js → boot-reembed-b9sbk87z.js} +5 -5
  7. package/dist/{boot-scrub-logs-ddyaeqar.js → boot-scrub-logs-c1zsaw9m.js} +4 -4
  8. package/dist/{claude-adapter-mma9a1yr.js → claude-adapter-2k45y7p7.js} +2 -2
  9. package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-kysmkz89.js} +2 -2
  10. package/dist/cli-0kgcv878.js +344 -0
  11. package/dist/cli-0pygq9r1.js +429 -0
  12. package/dist/{cli-7xkwgkrs.js → cli-113wmegp.js} +90 -3
  13. package/dist/{cli-7ga43spr.js → cli-1yjrbg1f.js} +1 -1
  14. package/dist/{cli-56s4ehzw.js → cli-2t4e4ayk.js} +1 -1
  15. package/dist/{cli-0c3n0eba.js → cli-312v3c41.js} +1 -1
  16. package/dist/{cli-ceewqajw.js → cli-46b6kc7f.js} +5 -5
  17. package/dist/cli-49j095n9.js +393 -0
  18. package/dist/{cli-h9jx5mag.js → cli-5afkmcfj.js} +10 -7
  19. package/dist/{cli-76d1vtvq.js → cli-5ktc9fd4.js} +1 -1
  20. package/dist/cli-7rgh0w0k.js +262 -0
  21. package/dist/{cli-9cy6nc5m.js → cli-8fjwym53.js} +1 -1
  22. package/dist/{cli-tg0f2wmz.js → cli-a6tzw6vq.js} +175 -28
  23. package/dist/{cli-q21d49ac.js → cli-bw80ck94.js} +1 -1
  24. package/dist/{cli-709t753c.js → cli-byjcad11.js} +2 -2
  25. package/dist/{cli-15598a4k.js → cli-e2xbxmhd.js} +1808 -302
  26. package/dist/{cli-6wscj9z0.js → cli-e7306swv.js} +14 -14
  27. package/dist/{cli-8f0dwca2.js → cli-f5pzfvwb.js} +6 -5
  28. package/dist/{cli-s9pj3c7z.js → cli-f9n2jg31.js} +2 -2
  29. package/dist/{cli-dcfyyh3t.js → cli-ftyf58xj.js} +2 -2
  30. package/dist/{cli-hm27prrc.js → cli-hq39e630.js} +5 -5
  31. package/dist/{cli-a5e8n5hg.js → cli-hvg05qwm.js} +1 -1
  32. package/dist/cli-jkhwmmgg.js +136 -0
  33. package/dist/{cli-951w7c79.js → cli-jzwtn8rm.js} +136 -21
  34. package/dist/{cli-rp8pca98.js → cli-k6h2zkw3.js} +1 -1
  35. package/dist/{cli-3r5y6ayj.js → cli-pnfyyp6h.js} +1240 -335
  36. package/dist/{cli-94vzr3nq.js → cli-q1z5d5ss.js} +13 -7
  37. package/dist/{cli-pt7c7qxz.js → cli-q4e2x252.js} +3 -3
  38. package/dist/{cli-tch0ypp6.js → cli-r3mtrrzp.js} +16 -16
  39. package/dist/{cli-ywez6yps.js → cli-sq7f72d6.js} +1 -1
  40. package/dist/{cli-r1btc895.js → cli-w3nq88yc.js} +2 -2
  41. package/dist/{cli-30d2ct3k.js → cli-w4wk3kx6.js} +12 -7
  42. package/dist/{cli-anrj584m.js → cli-xz9aq0rf.js} +1 -1
  43. package/dist/{cli-tp7e60s3.js → cli-zmmp2r79.js} +22 -9
  44. package/dist/cli.js +35 -17
  45. package/dist/{codex-adapter-5cmy858w.js → codex-adapter-4z8m9mb5.js} +9 -9
  46. package/dist/{codex-session-runner-46q8mrba.js → codex-session-runner-rbct46dg.js} +9 -9
  47. package/dist/{commands-14g7taf4.js → commands-zk4d6esf.js} +4 -4
  48. package/dist/{db-3tge4jrn.js → db-stn16jp2.js} +4 -4
  49. package/dist/{handlers-sy64egg6.js → handlers-gshprvpf.js} +16 -30
  50. package/dist/{hook-rnkzw8vp.js → hook-amzx9tap.js} +7 -7
  51. package/dist/{http-xx9xptcs.js → http-6g0hfzax.js} +1977 -786
  52. package/dist/{index-wz1ea15p.js → index-2dgfj9av.js} +3 -3
  53. package/dist/{index-ha8e9xn2.js → index-df8fmphk.js} +55 -17
  54. package/dist/{index-zfx5p959.js → index-f03rnnrs.js} +13 -10
  55. package/dist/{index-3wr6v2mm.js → index-jbm7qcqk.js} +12 -9
  56. package/dist/{index-ykvs43z4.js → index-t2snazez.js} +4 -4
  57. package/dist/{index-brma88d4.js → index-ty42rxw9.js} +14 -11
  58. package/dist/{keepalive-rbz05zad.js → keepalive-pm6g2wpw.js} +7 -6
  59. package/dist/{lead-s790v7r0.js → lead-h79fzpzw.js} +33 -29
  60. package/dist/{maintenance-420rmadb.js → maintenance-433zndy1.js} +6 -6
  61. package/dist/{mistral-conversations-26yrnbf1.js → mistral-conversations-7gqnz2wt.js} +7 -7
  62. package/dist/oauth-refresh-sweep-mjsbmsk2.js +114 -0
  63. package/dist/{onboard-jgqamqnw.js → onboard-vdr9hc3f.js} +2 -2
  64. package/dist/{otel-zjd9zaxs.js → otel-g299k41b.js} +2 -2
  65. package/dist/{otel-impl-ch3n3783.js → otel-impl-yswd0fty.js} +1 -1
  66. package/dist/{pi-mono-adapter-kxjxpfgy.js → pi-mono-adapter-vbrvg1p8.js} +16 -108
  67. package/dist/{pricing-refresh-rmtrby6h.js → pricing-refresh-2kk2ap9b.js} +6 -6
  68. package/dist/rbac-roles-2wgh9b5t.js +276 -0
  69. package/dist/rbac-roles-xdc5208b.js +28 -0
  70. package/dist/{seed-pricing-1szjzfj1.js → seed-pricing-m9h69d2t.js} +5 -5
  71. package/dist/{setup-8jfzkyzv.js → setup-eynkvafa.js} +2 -2
  72. package/dist/{worker-40vq0pm8.js → worker-136q8dc2.js} +33 -29
  73. package/openapi.json +1634 -20
  74. package/package.json +6 -5
  75. package/src/agentmail/handlers.ts +16 -6
  76. package/src/agentmail/templates.ts +25 -5
  77. package/src/be/audit-user.ts +28 -4
  78. package/src/be/db-queries/oauth.ts +42 -0
  79. package/src/be/db.ts +104 -11
  80. package/src/be/identity.ts +79 -0
  81. package/src/be/mcp-proxy.ts +132 -0
  82. package/src/be/memory/providers/sqlite-store.ts +5 -1
  83. package/src/be/migrations/108_rbac_permission_audit.sql +26 -0
  84. package/src/be/migrations/109_rbac_roles.sql +79 -0
  85. package/src/be/migrations/111_oauth_credential_bindings.sql +6 -0
  86. package/src/be/migrations/112_script_connections_graphql.sql +96 -0
  87. package/src/be/oauth-credential-bindings.ts +35 -0
  88. package/src/be/oauth-refresh-sweep.ts +159 -0
  89. package/src/be/rbac-audit.ts +246 -0
  90. package/src/be/rbac-roles.ts +417 -0
  91. package/src/be/script-connections.ts +456 -37
  92. package/src/be/script-credential-broker.ts +29 -3
  93. package/src/be/scripts/typecheck.ts +40 -7
  94. package/src/be/users.ts +24 -0
  95. package/src/cli.tsx +17 -0
  96. package/src/github/handlers.ts +10 -9
  97. package/src/github/templates.ts +45 -9
  98. package/src/gitlab/handlers.ts +20 -8
  99. package/src/gitlab/templates.ts +18 -6
  100. package/src/http/all-routes.ts +61 -0
  101. package/src/http/approval-requests.ts +12 -0
  102. package/src/http/config.ts +98 -9
  103. package/src/http/core.ts +30 -3
  104. package/src/http/favorites.ts +5 -0
  105. package/src/http/fs.ts +27 -7
  106. package/src/http/index.ts +50 -0
  107. package/src/http/kv.ts +21 -4
  108. package/src/http/mcp-oauth.ts +2 -0
  109. package/src/http/mcp-servers.ts +6 -3
  110. package/src/http/oauth-generic.ts +105 -0
  111. package/src/http/poll.ts +13 -1
  112. package/src/http/route-def.ts +9 -0
  113. package/src/http/schedules.ts +56 -22
  114. package/src/http/script-connection-proxy.ts +116 -0
  115. package/src/http/script-connections.ts +1657 -0
  116. package/src/http/scripts.ts +54 -7
  117. package/src/http/tasks.ts +16 -14
  118. package/src/http/workflows.ts +13 -2
  119. package/src/http/x.ts +6 -2
  120. package/src/integrations/kapso/inbound.ts +23 -6
  121. package/src/jira/sync.ts +111 -17
  122. package/src/jira/templates.ts +10 -2
  123. package/src/mcp-client/http-client.ts +194 -0
  124. package/src/oauth/app-validation.ts +16 -0
  125. package/src/oauth/ensure-token.ts +69 -14
  126. package/src/oauth/mcp-wrapper.ts +15 -0
  127. package/src/oauth/wrapper.ts +48 -20
  128. package/src/prompts/base-prompt.ts +7 -6
  129. package/src/prompts/session-templates.ts +38 -11
  130. package/src/providers/pi-mono-mcp-client.ts +2 -133
  131. package/src/rbac/admission.ts +44 -0
  132. package/src/rbac/can.ts +44 -0
  133. package/src/rbac/index.ts +15 -0
  134. package/src/rbac/legacy-policy.ts +188 -0
  135. package/src/rbac/permissions.ts +194 -0
  136. package/src/rbac/types.ts +45 -0
  137. package/src/scheduler/scheduler.ts +9 -1
  138. package/src/scripts-runtime/api-client.ts +70 -14
  139. package/src/scripts-runtime/api-types.ts +38 -6
  140. package/src/scripts-runtime/credential-broker/default-bindings.ts +1 -0
  141. package/src/scripts-runtime/credential-broker/types.ts +8 -0
  142. package/src/scripts-runtime/ctx.ts +11 -1
  143. package/src/scripts-runtime/eval-harness.ts +5 -1
  144. package/src/scripts-runtime/executors/types.ts +2 -1
  145. package/src/scripts-runtime/loader.ts +3 -1
  146. package/src/scripts-runtime/mcp-client.ts +87 -0
  147. package/src/scripts-runtime/sdk-allowlist.ts +2 -0
  148. package/src/scripts-runtime/swarm-sdk.ts +81 -0
  149. package/src/scripts-runtime/types/stdlib.d.ts +24 -2
  150. package/src/scripts-runtime/types/swarm-sdk.d.ts +26 -2
  151. package/src/server.ts +14 -0
  152. package/src/slack/assistant.ts +14 -6
  153. package/src/slack/enrich.ts +17 -0
  154. package/src/slack/handlers.ts +8 -22
  155. package/src/slack/thread-buffer.ts +6 -3
  156. package/src/stdio.ts +43 -0
  157. package/src/tests/agentmail-handlers.test.ts +32 -3
  158. package/src/tests/approval-requests.test.ts +61 -0
  159. package/src/tests/audit-user.test.ts +47 -1
  160. package/src/tests/base-prompt.test.ts +7 -4
  161. package/src/tests/credential-broker.test.ts +5 -2
  162. package/src/tests/delete-page-tool.test.ts +197 -0
  163. package/src/tests/github-handlers.test.ts +28 -2
  164. package/src/tests/gitlab-handlers.test.ts +125 -0
  165. package/src/tests/harness-provider-resolution.test.ts +5 -0
  166. package/src/tests/http-api-integration.test.ts +8 -1
  167. package/src/tests/identity.test.ts +117 -0
  168. package/src/tests/jira-sync.test.ts +99 -1
  169. package/src/tests/kapso-inbound.test.ts +7 -0
  170. package/src/tests/mcp-tools-user.test.ts +60 -6
  171. package/src/tests/oauth-credential-bindings.test.ts +490 -0
  172. package/src/tests/oauth-refresh-sweep.test.ts +160 -0
  173. package/src/tests/prompt-template-remaining.test.ts +2 -2
  174. package/src/tests/prompt-template-session.test.ts +21 -8
  175. package/src/tests/rbac-admission-e2e.test.ts +241 -0
  176. package/src/tests/rbac-admission.test.ts +433 -0
  177. package/src/tests/rbac-audit.test.ts +345 -0
  178. package/src/tests/rbac-charact-http.test.ts +272 -0
  179. package/src/tests/rbac-charact-misc-tools.test.ts +428 -0
  180. package/src/tests/rbac-charact-skills.test.ts +492 -0
  181. package/src/tests/rbac-charact-slack.test.ts +283 -0
  182. package/src/tests/rbac-e2e-helpers.ts +308 -0
  183. package/src/tests/rbac-engine.test.ts +474 -0
  184. package/src/tests/rbac-lifecycle-e2e.test.ts +262 -0
  185. package/src/tests/rbac-roles.test.ts +326 -0
  186. package/src/tests/rbac-wire-e2e.test.ts +574 -0
  187. package/src/tests/schedule-http-triage-tools.test.ts +121 -0
  188. package/src/tests/schedule-target-type.test.ts +50 -0
  189. package/src/tests/scheduled-tasks.test.ts +74 -0
  190. package/src/tests/script-connections-http.test.ts +1158 -0
  191. package/src/tests/script-connections-mcp.test.ts +894 -0
  192. package/src/tests/script-connections.test.ts +727 -5
  193. package/src/tests/scripts-external-api.test.ts +49 -1
  194. package/src/tests/scripts-http.test.ts +56 -7
  195. package/src/tests/scripts-runtime-secret-egress.test.ts +1 -0
  196. package/src/tests/scripts-runtime.test.ts +104 -0
  197. package/src/tests/slack-identity-resolution.test.ts +37 -3
  198. package/src/tests/slack-thread-buffer.test.ts +28 -0
  199. package/src/tests/swarm-config-reserved-keys.test.ts +17 -0
  200. package/src/tests/tool-annotations.test.ts +2 -0
  201. package/src/tests/update-schedule-mcp-tool.test.ts +57 -0
  202. package/src/tests/user-token-rest-auth.test.ts +30 -1
  203. package/src/tests/workflow-http-v2.test.ts +80 -0
  204. package/src/tests/workflow-swarm-script.test.ts +44 -0
  205. package/src/tests/workflow-triggers-v2.test.ts +300 -1
  206. package/src/tools/cancel-task.ts +13 -3
  207. package/src/tools/context-diff.ts +12 -1
  208. package/src/tools/context-history.ts +12 -1
  209. package/src/tools/credential-bindings/tool.ts +289 -19
  210. package/src/tools/delete-channel.ts +12 -1
  211. package/src/tools/delete-page.ts +145 -0
  212. package/src/tools/get-task-details.ts +1 -1
  213. package/src/tools/inject-learning.ts +12 -1
  214. package/src/tools/kv/kv-delete.ts +3 -18
  215. package/src/tools/kv/kv-incr.ts +3 -18
  216. package/src/tools/kv/kv-set.ts +3 -20
  217. package/src/tools/kv/kv-write-auth.ts +40 -0
  218. package/src/tools/manage-user.ts +12 -1
  219. package/src/tools/mcp-servers/mcp-server-create.ts +12 -1
  220. package/src/tools/mcp-servers/mcp-server-delete.ts +19 -5
  221. package/src/tools/mcp-servers/mcp-server-install.ts +12 -1
  222. package/src/tools/mcp-servers/mcp-server-uninstall.ts +12 -1
  223. package/src/tools/mcp-servers/mcp-server-update.ts +12 -1
  224. package/src/tools/memory-delete.ts +12 -4
  225. package/src/tools/register-kapso-number.ts +23 -2
  226. package/src/tools/request-human-input.ts +2 -0
  227. package/src/tools/resolve-user.ts +77 -27
  228. package/src/tools/schedules/create-schedule.ts +4 -3
  229. package/src/tools/schedules/index.ts +1 -0
  230. package/src/tools/schedules/list-schedules.ts +36 -2
  231. package/src/tools/schedules/patch-schedule.ts +405 -0
  232. package/src/tools/schedules/update-schedule.ts +2 -2
  233. package/src/tools/script-connections/tool.ts +287 -32
  234. package/src/tools/skills/skill-create.ts +12 -1
  235. package/src/tools/skills/skill-delete.ts +12 -1
  236. package/src/tools/skills/skill-install-remote.ts +12 -1
  237. package/src/tools/skills/skill-install.ts +12 -1
  238. package/src/tools/skills/skill-uninstall.ts +12 -1
  239. package/src/tools/skills/skill-update.ts +25 -2
  240. package/src/tools/slack-delete.ts +8 -1
  241. package/src/tools/slack-post.ts +8 -1
  242. package/src/tools/slack-read.ts +8 -1
  243. package/src/tools/slack-start-thread.ts +8 -1
  244. package/src/tools/slack-update.ts +8 -1
  245. package/src/tools/slack-upload-file.ts +8 -1
  246. package/src/tools/swarm-config/delete-config.ts +28 -1
  247. package/src/tools/swarm-config/get-config.ts +32 -5
  248. package/src/tools/swarm-config/list-config.ts +31 -5
  249. package/src/tools/swarm-config/set-config.ts +38 -1
  250. package/src/tools/task-action.ts +1 -1
  251. package/src/tools/task-tool-ctx.ts +19 -3
  252. package/src/tools/templates.ts +5 -1
  253. package/src/tools/tool-config.ts +4 -2
  254. package/src/tools/update-profile.ts +8 -1
  255. package/src/tools/workflows/create-workflow.ts +8 -1
  256. package/src/tools/workflows/list-workflows.ts +14 -2
  257. package/src/tools/workflows/update-workflow.ts +11 -2
  258. package/src/types.ts +63 -6
  259. package/src/utils/scoped-resource.ts +25 -0
  260. package/src/workflows/executors/human-in-the-loop.ts +1 -0
  261. package/src/workflows/executors/swarm-script.ts +7 -1
  262. package/src/workflows/triggers.ts +146 -18
  263. package/templates/skills/swarm-scripts/SKILL.md +4 -9
  264. package/templates/skills/swarm-scripts/content.md +45 -9
  265. package/dist/cli-52tbq17n.js +0 -771
  266. package/dist/cli-9p0qhead.js +0 -43
  267. package/dist/{anthropic-messages-8nc6r2dw.js → anthropic-messages-kq3pjhbp.js} +6 -6
  268. package/dist/{azure-openai-responses-6yfzw3qw.js → azure-openai-responses-gm1ejtmn.js} +7 -7
  269. package/dist/{cli-vbraamxr.js → cli-6b4wwmm8.js} +9 -9
  270. package/dist/{cli-2fc97xm5.js → cli-ggy8c7tk.js} +3 -3
  271. package/dist/{cli-2r7s8jhp.js → cli-sznberje.js} +3 -3
  272. package/dist/{google-generative-ai-vfq6ymz9.js → google-generative-ai-hyrra2jm.js} +3 -3
  273. package/dist/{google-vertex-mj5y5rfj.js → google-vertex-8bs2pzgn.js} +3 -3
  274. package/dist/{openai-codex-responses-8h6kvfv8.js → openai-codex-responses-3nkvje79.js} +4 -4
  275. package/dist/{openai-completions-x6kjnqjd.js → openai-completions-0asftkwg.js} +11 -11
  276. package/dist/{openai-responses-7jwyz3ds.js → openai-responses-pmatek45.js} +10 -10
@@ -288,6 +288,56 @@ describe("dispatchScheduleTarget — script target", () => {
288
288
  expect(result.task).toBeUndefined();
289
289
  }, 15_000);
290
290
 
291
+ test("scheduled script runs receive ctx.api and ctx.mcp connections", async () => {
292
+ const { upsertScriptConnection } = await import("../be/script-connections");
293
+ await upsertScriptConnection({
294
+ slug: "schedgql",
295
+ kind: "graphql",
296
+ scope: "global",
297
+ baseUrl: "https://gql.vendor.test/graphql",
298
+ allowedHosts: ["gql.vendor.test"],
299
+ agentId,
300
+ });
301
+ const mcpRow = {
302
+ id: crypto.randomUUID(),
303
+ serverId: crypto.randomUUID(),
304
+ runtime: { slug: "schedmcp", kind: "mcp", connectionId: "", tools: [{ name: "ping" }] },
305
+ };
306
+ mcpRow.runtime.connectionId = mcpRow.id;
307
+ getDb()
308
+ .prepare(
309
+ `INSERT INTO mcp_servers (id, name, transport, scope, url, createdAt, lastUpdatedAt)
310
+ VALUES (?, ?, 'http', 'global', 'http://mcp.invalid.test/mcp', datetime('now'), datetime('now'))`,
311
+ )
312
+ .run(mcpRow.serverId, `sched-mcp-${mcpRow.serverId.slice(0, 8)}`);
313
+ getDb()
314
+ .prepare(
315
+ `INSERT INTO script_connections
316
+ (id, slug, kind, scope, allowed_hosts_json, mcp_server_id, generated_runtime_json)
317
+ VALUES (?, 'schedmcp', 'mcp', 'global', '[]', ?, ?)`,
318
+ )
319
+ .run(mcpRow.id, mcpRow.serverId, JSON.stringify(mcpRow.runtime));
320
+
321
+ await saveGlobalScript(
322
+ "schedule-target-type-ctx-connections",
323
+ `export default async (args, ctx) => {
324
+ if (!ctx.api || !("schedgql" in ctx.api)) throw new Error("ctx.api missing schedgql");
325
+ if (!ctx.mcp || !("schedmcp" in ctx.mcp)) throw new Error("ctx.mcp missing schedmcp");
326
+ return { ok: true };
327
+ };`,
328
+ );
329
+ const schedule = createScheduledTask({
330
+ name: `dispatch-script-ctx-${crypto.randomUUID()}`,
331
+ intervalMs: 60_000,
332
+ targetType: "script",
333
+ scriptName: "schedule-target-type-ctx-connections",
334
+ createdByAgentId: agentId,
335
+ });
336
+
337
+ const result = await dispatchScheduleTarget(schedule);
338
+ expect(result.triggeredWorkflows).toBe(false);
339
+ }, 15_000);
340
+
291
341
  test("throws a clear error when the script does not exist", async () => {
292
342
  const schedule = createScheduledTask({
293
343
  name: `dispatch-script-missing-${crypto.randomUUID()}`,
@@ -4,11 +4,13 @@ import {
4
4
  closeDb,
5
5
  createAgent,
6
6
  createScheduledTask,
7
+ createUser,
7
8
  deleteScheduledTask,
8
9
  getDb,
9
10
  getScheduledTaskById,
10
11
  getScheduledTaskByName,
11
12
  getScheduledTasks,
13
+ getTaskById,
12
14
  initDb,
13
15
  updateScheduledTask,
14
16
  } from "../be/db";
@@ -195,6 +197,40 @@ describe("Scheduled Tasks Integration", () => {
195
197
  expect(disabledOnly.every((s) => !s.enabled)).toBe(true);
196
198
  });
197
199
 
200
+ test("should filter scheduled tasks by triage error fields", () => {
201
+ const ok = createScheduledTask({
202
+ name: "test-filter-last-run-ok",
203
+ intervalMs: 60000,
204
+ taskTemplate: "Healthy task",
205
+ });
206
+ const failing = createScheduledTask({
207
+ name: "test-filter-last-run-failed",
208
+ intervalMs: 60000,
209
+ taskTemplate: "Failing task",
210
+ });
211
+ updateScheduledTask(ok.id, {
212
+ lastRunAt: new Date(Date.now() - 120000).toISOString(),
213
+ consecutiveErrors: 0,
214
+ });
215
+ updateScheduledTask(failing.id, {
216
+ lastRunAt: new Date(Date.now() - 60000).toISOString(),
217
+ consecutiveErrors: 3,
218
+ lastErrorAt: new Date().toISOString(),
219
+ lastErrorMessage: "boom",
220
+ });
221
+
222
+ const failingOnly = getScheduledTasks({
223
+ lastRunStatus: "failed",
224
+ consecutiveErrorsMin: 2,
225
+ });
226
+ const succeededOnly = getScheduledTasks({ lastRunStatus: "succeeded" });
227
+
228
+ expect(failingOnly.some((s) => s.id === failing.id)).toBe(true);
229
+ expect(failingOnly.some((s) => s.id === ok.id)).toBe(false);
230
+ expect(succeededOnly.some((s) => s.id === ok.id)).toBe(true);
231
+ expect(succeededOnly.some((s) => s.id === failing.id)).toBe(false);
232
+ });
233
+
198
234
  test("should filter scheduled tasks by name", () => {
199
235
  createScheduledTask({
200
236
  name: "unique-name-xyz-123",
@@ -281,6 +317,44 @@ describe("Scheduled Tasks Integration", () => {
281
317
  expect(afterRun?.lastRunAt).toBeDefined();
282
318
  });
283
319
 
320
+ test("fired task inherits the schedule's createdBy as requestedByUserId", async () => {
321
+ const requester = createUser({ name: "Schedule Requester", email: "sched-req@example.com" });
322
+ const schedule = createScheduledTask({
323
+ name: "test-manual-run-createdby",
324
+ cronExpression: "0 9 * * *",
325
+ taskTemplate: "Task carrying schedule provenance",
326
+ createdByAgentId: testAgent.id,
327
+ createdBy: requester.id,
328
+ enabled: true,
329
+ });
330
+
331
+ await runScheduleNow(schedule.id);
332
+
333
+ const createdTask = getDb()
334
+ .query("SELECT id FROM agent_tasks WHERE task = ? ORDER BY createdAt DESC LIMIT 1")
335
+ .get(schedule.taskTemplate) as { id: string };
336
+ const task = getTaskById(createdTask.id);
337
+ expect(task?.requestedByUserId).toBe(requester.id);
338
+ });
339
+
340
+ test("fired task has no requestedByUserId when the schedule's createdBy is unset (first-ever schedules)", async () => {
341
+ const schedule = createScheduledTask({
342
+ name: "test-manual-run-no-createdby",
343
+ cronExpression: "0 9 * * *",
344
+ taskTemplate: "Task with no schedule provenance",
345
+ createdByAgentId: testAgent.id,
346
+ enabled: true,
347
+ });
348
+
349
+ await runScheduleNow(schedule.id);
350
+
351
+ const createdTask = getDb()
352
+ .query("SELECT id FROM agent_tasks WHERE task = ? ORDER BY createdAt DESC LIMIT 1")
353
+ .get(schedule.taskTemplate) as { id: string };
354
+ const task = getTaskById(createdTask.id);
355
+ expect(task?.requestedByUserId ?? null).toBeNull();
356
+ });
357
+
284
358
  test("should throw error for non-existent schedule", async () => {
285
359
  await expect(runScheduleNow("non-existent-schedule-id")).rejects.toThrow(
286
360
  "Schedule not found",