@desplega.ai/agent-swarm 1.147.0 → 1.149.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 (185) hide show
  1. package/README.md +13 -1
  2. package/dist/{acp-adapter-9n319wqc.js → acp-adapter-4jncb126.js} +12 -5
  3. package/dist/{actions-2vxqvpr9.js → actions-31vp3ae7.js} +10 -9
  4. package/dist/{app-w066xfy0.js → app-1hh67x8w.js} +6 -6
  5. package/dist/{assistant-kt31dj2h.js → assistant-z66dmz6p.js} +13 -11
  6. package/dist/{boot-reembed-az5rassp.js → boot-reembed-fqzxxzjh.js} +7 -7
  7. package/dist/{boot-reembed-j3mm3rfz.js → boot-reembed-wxa8ya0s.js} +8 -8
  8. package/dist/{boot-scrub-logs-b6h54817.js → boot-scrub-logs-jnyndh79.js} +5 -5
  9. package/dist/{claude-adapter-w1z04ann.js → claude-adapter-3qpa9w0j.js} +9 -9
  10. package/dist/{claude-managed-adapter-sactwn31.js → claude-managed-adapter-qvsmh6mv.js} +2 -2
  11. package/dist/{claude-sdk-session-f0cc1kec.js → claude-sdk-session-2yxgjs5d.js} +9 -9
  12. package/dist/{cli-y6b6fb76.js → cli-08b07b4r.js} +1 -1
  13. package/dist/{cli-8fc8de14.js → cli-0z2v4nhw.js} +1 -1
  14. package/dist/{cli-de14znh8.js → cli-19f354qr.js} +2 -2
  15. package/dist/{cli-hbv0kq6w.js → cli-2qts1hys.js} +3 -3
  16. package/dist/{cli-kpv03zhj.js → cli-3apbzgyk.js} +27 -15
  17. package/dist/{cli-1th1728g.js → cli-3q5ejx9p.js} +2 -2
  18. package/dist/{cli-d8brzxjb.js → cli-4wtq5jjv.js} +2 -2
  19. package/dist/{cli-ct0et58h.js → cli-5my3bjsd.js} +1 -1
  20. package/dist/{cli-cn6mmc7f.js → cli-6664w7y4.js} +1 -1
  21. package/dist/{cli-yz3djrm0.js → cli-6pqcb4q0.js} +53 -13
  22. package/dist/{cli-719k9j2c.js → cli-7smrsr25.js} +3 -3
  23. package/dist/{cli-rw51bq3j.js → cli-9fy6nk6g.js} +1 -1
  24. package/dist/{cli-zhjmqxzh.js → cli-9hspd3dp.js} +2 -2
  25. package/dist/{cli-3tgwnf43.js → cli-aae6hz6a.js} +4 -4
  26. package/dist/{cli-89xfd7f9.js → cli-cr12paw2.js} +5 -5
  27. package/dist/{cli-b5bq9crk.js → cli-d8ftsp62.js} +8 -8
  28. package/dist/{cli-4nr988h6.js → cli-e95cx1eb.js} +3 -3
  29. package/dist/{cli-n8508nre.js → cli-gjhjfeeg.js} +1 -1
  30. package/dist/{cli-p1d5b073.js → cli-gv88e1vf.js} +1 -1
  31. package/dist/{cli-rvqz34y5.js → cli-jecc01cb.js} +1 -1
  32. package/dist/{cli-8v0g1yc8.js → cli-k0cr4kat.js} +1 -1
  33. package/dist/{cli-mmemxxdc.js → cli-kgz4np97.js} +4 -4
  34. package/dist/{cli-w9kb3bk1.js → cli-kjwt6hdf.js} +3 -1
  35. package/dist/{cli-f7dsy61y.js → cli-mnmsfd1w.js} +6 -2
  36. package/dist/{cli-54wwve05.js → cli-n3dz2942.js} +37 -26
  37. package/dist/{cli-12fz972k.js → cli-nye12xk5.js} +8 -5
  38. package/dist/{cli-tzvk9haz.js → cli-phsxnkp6.js} +20 -20
  39. package/dist/{cli-53s590z8.js → cli-q50ef8g0.js} +1 -1
  40. package/dist/{cli-f146mn5s.js → cli-qaacms9y.js} +7 -6
  41. package/dist/{cli-xqcq9y5e.js → cli-r2ap2czm.js} +1 -0
  42. package/dist/{cli-m8yrsg97.js → cli-sd5pv3b1.js} +3 -3
  43. package/dist/{cli-0b6y7kxm.js → cli-xm87hzbw.js} +1 -1
  44. package/dist/{cli-ftht3zzj.js → cli-yab68w40.js} +285 -11
  45. package/dist/{cli-atcve9y8.js → cli-yb9qhqam.js} +227 -59
  46. package/dist/{cli-smby5m17.js → cli-ygweqcn4.js} +133 -22
  47. package/dist/{cli-dttph1bw.js → cli-ykxrnd1q.js} +2 -2
  48. package/dist/{cli-m9sxbkhm.js → cli-zvz62chv.js} +3 -3
  49. package/dist/cli.js +16 -14
  50. package/dist/{codex-adapter-zw4dwsx7.js → codex-adapter-8meawydj.js} +4 -4
  51. package/dist/{codex-hook-bw8p5nh4.js → codex-hook-hfrt9shr.js} +2 -2
  52. package/dist/{codex-session-runner-k981s65v.js → codex-session-runner-gjgxyp5j.js} +4 -4
  53. package/dist/{commands-sykrxx7e.js → commands-hz3nb95f.js} +5 -5
  54. package/dist/{db-sfbsc8wt.js → db-ggz97zbm.js} +5 -5
  55. package/dist/{e2b-6hb103d8.js → e2b-p04vmtx0.js} +1 -1
  56. package/dist/{handlers-0aspcejm.js → handlers-nbzdzn9k.js} +14 -11
  57. package/dist/{hook-hxccs7m5.js → hook-bks2q1f6.js} +7 -7
  58. package/dist/{hook-4nvqj2sb.js → hook-kq9wp0ep.js} +8 -8
  59. package/dist/{http-y06z517d.js → http-hrf77v87.js} +96 -45
  60. package/dist/{index-tce1rss4.js → index-6nsbg88z.js} +443 -144
  61. package/dist/{index-x5j894zf.js → index-8hmeg8j1.js} +14 -14
  62. package/dist/{index-k8znfx0z.js → index-cqtebbhb.js} +13 -13
  63. package/dist/{index-hssww7kj.js → index-n28pw1zt.js} +15 -15
  64. package/dist/{keepalive-w733ax66.js → keepalive-dxc12gvg.js} +7 -7
  65. package/dist/{lead-75bjqa9d.js → lead-yckfn18d.js} +32 -32
  66. package/dist/{maintenance-w4f1zjck.js → maintenance-6kfb2m5e.js} +8 -8
  67. package/dist/{oauth-refresh-sweep-wdetky26.js → oauth-refresh-sweep-1x1ac722.js} +6 -6
  68. package/dist/{onboard-bb5net8s.js → onboard-dcyt1609.js} +4 -3
  69. package/dist/{opencode-adapter-fef1mrn2.js → opencode-adapter-dce4wskd.js} +2 -2
  70. package/dist/{otel-impl-0w7c14ap.js → otel-impl-tbk3e5dr.js} +2 -2
  71. package/dist/{pi-mono-adapter-2has4gnp.js → pi-mono-adapter-zvshk5cj.js} +2 -2
  72. package/dist/{pricing-refresh-9nzsrgcq.js → pricing-refresh-kaqg567e.js} +7 -7
  73. package/dist/{rbac-roles-z1jrffbt.js → rbac-roles-ammq6rd2.js} +5 -5
  74. package/dist/{rbac-roles-r3hqjp09.js → rbac-roles-cf97v1vd.js} +6 -6
  75. package/dist/{render-v2-vbr89fnb.js → render-v2-80w603vy.js} +6 -6
  76. package/dist/{seed-pricing-g62hy1pk.js → seed-pricing-zbrn83xv.js} +6 -6
  77. package/dist/{setup-gnfqnptp.js → setup-fe66kczs.js} +2 -2
  78. package/dist/{worker-kznxp4qm.js → worker-qmb2d1e2.js} +32 -32
  79. package/dist/{x-n2phr5vm.js → x-n3e0v3xa.js} +2 -2
  80. package/openapi.json +46 -4
  81. package/package.json +3 -1
  82. package/src/agentmail/handlers.ts +5 -0
  83. package/src/automation-preflight-alert.ts +41 -0
  84. package/src/be/automation-preflight.ts +3 -3
  85. package/src/be/budget-refusal-notify.ts +1 -0
  86. package/src/be/db/tasks/read.ts +5 -0
  87. package/src/be/db.ts +132 -2
  88. package/src/be/migrations/150_deferred_task_waits.sql +18 -0
  89. package/src/be/migrations/151_repair_scheduled_task_required_params.sql +39 -0
  90. package/src/be/migrations/152_routing_decisions.sql +44 -0
  91. package/src/be/scripts/typecheck.ts +33 -22
  92. package/src/be/seed-scripts/catalog/delegate.ts +5 -1
  93. package/src/be/seed-skills/bundled-files.generated.json +10 -0
  94. package/src/be/seed-skills/index.ts +3 -0
  95. package/src/be/steering.ts +1 -0
  96. package/src/be/swarm-config-guard.ts +11 -0
  97. package/src/commands/onboard/steps/post-task.tsx +1 -0
  98. package/src/github/handlers.ts +9 -0
  99. package/src/gitlab/handlers.ts +4 -0
  100. package/src/heartbeat/heartbeat.ts +8 -0
  101. package/src/http/approval-requests.ts +1 -0
  102. package/src/http/apps.ts +1 -0
  103. package/src/http/config.ts +15 -6
  104. package/src/http/mcp.ts +31 -4
  105. package/src/http/script-runs.ts +6 -0
  106. package/src/http/tasks.ts +52 -30
  107. package/src/integrations/kapso/inbound.ts +1 -0
  108. package/src/jira/sync.ts +2 -0
  109. package/src/linear/sync.ts +2 -0
  110. package/src/prompts/session-templates.ts +29 -15
  111. package/src/scheduler/deferred-task-waits.ts +123 -0
  112. package/src/scheduler/schedule-task.ts +42 -0
  113. package/src/scheduler/scheduler.ts +22 -31
  114. package/src/script-workflows/workflow-ctx.ts +2 -0
  115. package/src/scripts-runtime/types/stdlib.d.ts +38 -24
  116. package/src/scripts-runtime/types/swarm-sdk.d.ts +38 -24
  117. package/src/server.ts +10 -1
  118. package/src/slack/actions.ts +1 -0
  119. package/src/slack/assistant.ts +2 -0
  120. package/src/slack/handlers.ts +3 -0
  121. package/src/slack/thread-buffer.ts +2 -0
  122. package/src/tasks/worker-follow-up.ts +9 -0
  123. package/src/tests/acp-adapter.test.ts +35 -6
  124. package/src/tests/acp-session-token.test.ts +67 -0
  125. package/src/tests/asset-key-api.test.ts +15 -2
  126. package/src/tests/asset-key-mcp.test.ts +2 -0
  127. package/src/tests/automation-preflight-alert.test.ts +91 -0
  128. package/src/tests/claude-worker-parity.test.ts +3 -0
  129. package/src/tests/config-session-auth.test.ts +143 -0
  130. package/src/tests/defer-task.test.ts +117 -6
  131. package/src/tests/deferred-task-wake.test.ts +456 -0
  132. package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
  133. package/src/tests/http-api-integration.test.ts +33 -4
  134. package/src/tests/mcp-input-ergonomics.test.ts +386 -0
  135. package/src/tests/model-control.test.ts +18 -5
  136. package/src/tests/opencode-adapter.test.ts +2 -2
  137. package/src/tests/promote-draft-task-route.test.ts +4 -0
  138. package/src/tests/prompt-template-session.test.ts +13 -4
  139. package/src/tests/rbac-wire-e2e.test.ts +2 -2
  140. package/src/tests/routing-decision-persistence.test.ts +520 -0
  141. package/src/tests/routing-reason-contract.test.ts +89 -0
  142. package/src/tests/routing-reason-inventory.test.ts +55 -0
  143. package/src/tests/schedule-target-type.test.ts +48 -1
  144. package/src/tests/scheduled-task-required-params-migration.test.ts +182 -0
  145. package/src/tests/scheduled-tasks.test.ts +9 -5
  146. package/src/tests/script-connections.test.ts +4 -0
  147. package/src/tests/script-runs-http.test.ts +31 -0
  148. package/src/tests/scripts-typecheck.test.ts +11 -0
  149. package/src/tests/secret-scrubber.test.ts +12 -0
  150. package/src/tests/send-task-output-schema.test.ts +66 -1
  151. package/src/tests/send-task-requested-by.test.ts +1 -0
  152. package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
  153. package/src/tests/store-progress-blocked-waiting-gate.test.ts +151 -0
  154. package/src/tests/swarm-tool-result-gate.test.ts +24 -0
  155. package/src/tests/task-tool-manifest.test.ts +47 -0
  156. package/src/tests/task-tool-preload-mcp.test.ts +125 -0
  157. package/src/tests/task-tools-ctx.test.ts +2 -0
  158. package/src/tests/tool-output-agent-id.test.ts +1 -0
  159. package/src/tests/ui-followup-lead-delegation.test.ts +6 -1
  160. package/src/tests/workflow-agent-task.test.ts +24 -1
  161. package/src/tests/workflow-engine-v2.test.ts +58 -2
  162. package/src/tools/accept-steer.ts +0 -1
  163. package/src/tools/defer-task.ts +73 -21
  164. package/src/tools/memory-get.ts +10 -3
  165. package/src/tools/memory-rate.ts +19 -7
  166. package/src/tools/memory-search.ts +2 -1
  167. package/src/tools/memory-store.ts +25 -5
  168. package/src/tools/send-task.ts +40 -2
  169. package/src/tools/skills/skill-publish.ts +1 -0
  170. package/src/tools/store-progress.ts +78 -4
  171. package/src/tools/templates.ts +2 -1
  172. package/src/tools/utils.ts +33 -2
  173. package/src/types.ts +14 -1
  174. package/src/utils/acp-session-token.ts +14 -4
  175. package/src/utils/secret-scrubber.ts +2 -0
  176. package/src/utils/task-tool-manifest.ts +33 -0
  177. package/src/workflows/engine.ts +4 -1
  178. package/src/workflows/executors/agent-task.ts +7 -1
  179. package/templates/ai-toolbox.manifest.json +6 -1
  180. package/templates/skills/comms/config.json +18 -0
  181. package/templates/skills/comms/content.md +74 -0
  182. package/templates/skills/comms/files/references/ste-rules.md +73 -0
  183. package/templates/skills/comms/files/references/visual-shapes.md +112 -0
  184. package/templates/skills/swarm-scripts/SKILL.md +3 -2
  185. package/templates/skills/swarm-scripts/content.md +3 -2
@@ -1,25 +1,25 @@
1
1
  import {
2
2
  runAgent
3
- } from "./cli-tzvk9haz.js";
4
- import"./cli-0b6y7kxm.js";
5
- import"./cli-4nr988h6.js";
6
- import"./cli-cn6mmc7f.js";
3
+ } from "./cli-phsxnkp6.js";
4
+ import"./cli-xm87hzbw.js";
5
+ import"./cli-e95cx1eb.js";
6
+ import"./cli-6664w7y4.js";
7
7
  import"./cli-hsxj0yar.js";
8
8
  import"./cli-9b13ggd1.js";
9
- import"./cli-ct0et58h.js";
9
+ import"./cli-5my3bjsd.js";
10
10
  import"./cli-5bfdm1ah.js";
11
11
  import"./cli-r94z9p1z.js";
12
12
  import"./cli-2djtr51b.js";
13
13
  import {
14
14
  getEnabledCapabilities
15
- } from "./cli-atcve9y8.js";
16
- import"./cli-8fc8de14.js";
15
+ } from "./cli-yb9qhqam.js";
16
+ import"./cli-0z2v4nhw.js";
17
17
  import"./cli-j490egb5.js";
18
- import"./cli-719k9j2c.js";
19
- import"./cli-89xfd7f9.js";
20
- import"./cli-d8brzxjb.js";
18
+ import"./cli-7smrsr25.js";
19
+ import"./cli-cr12paw2.js";
20
+ import"./cli-4wtq5jjv.js";
21
21
  import"./cli-b5b30yzk.js";
22
- import"./cli-rvqz34y5.js";
22
+ import"./cli-jecc01cb.js";
23
23
  import"./cli-hp1n6zq3.js";
24
24
  import"./cli-tng3131n.js";
25
25
  import"./cli-zm7njwzd.js";
@@ -27,49 +27,49 @@ import"./cli-s25avqg9.js";
27
27
  import"./cli-eree7rnv.js";
28
28
  import"./cli-xvkmedgn.js";
29
29
  import"./cli-4yc5d8fk.js";
30
- import"./cli-smby5m17.js";
31
- import"./cli-m8yrsg97.js";
32
- import"./cli-rw51bq3j.js";
33
- import"./cli-8v0g1yc8.js";
30
+ import"./cli-ygweqcn4.js";
31
+ import"./cli-sd5pv3b1.js";
32
+ import"./cli-9fy6nk6g.js";
33
+ import"./cli-k0cr4kat.js";
34
34
  import"./cli-cmp8g3sw.js";
35
- import"./cli-de14znh8.js";
35
+ import"./cli-19f354qr.js";
36
36
  import"./cli-qgm2pfpq.js";
37
- import"./cli-f7dsy61y.js";
37
+ import"./cli-mnmsfd1w.js";
38
38
  import"./cli-07jd68a1.js";
39
- import"./cli-yz3djrm0.js";
39
+ import"./cli-6pqcb4q0.js";
40
40
  import"./cli-1ebpar1q.js";
41
41
  import"./cli-e7d20cty.js";
42
42
  import"./cli-3dpj7atn.js";
43
- import"./cli-3tgwnf43.js";
43
+ import"./cli-aae6hz6a.js";
44
44
  import"./cli-epan13p1.js";
45
- import"./cli-hbv0kq6w.js";
46
- import"./cli-1th1728g.js";
45
+ import"./cli-2qts1hys.js";
46
+ import"./cli-3q5ejx9p.js";
47
47
  import"./cli-y89t4nca.js";
48
48
  import"./cli-f14fvzag.js";
49
- import"./cli-m9sxbkhm.js";
50
- import"./cli-zhjmqxzh.js";
49
+ import"./cli-zvz62chv.js";
50
+ import"./cli-9hspd3dp.js";
51
51
  import"./cli-fad8m16k.js";
52
52
  import"./cli-aehm1rbq.js";
53
53
  import"./cli-bsakbbkm.js";
54
54
  import"./cli-51tf7ac3.js";
55
- import"./cli-mmemxxdc.js";
55
+ import"./cli-kgz4np97.js";
56
56
  import"./cli-jsp14b6c.js";
57
- import"./cli-p1d5b073.js";
58
- import"./cli-53s590z8.js";
59
- import"./cli-b5bq9crk.js";
57
+ import"./cli-gv88e1vf.js";
58
+ import"./cli-q50ef8g0.js";
59
+ import"./cli-d8ftsp62.js";
60
60
  import"./cli-q51yprfq.js";
61
61
  import"./cli-9d8ntetj.js";
62
62
  import"./cli-yatxqynm.js";
63
- import"./cli-ftht3zzj.js";
64
- import"./cli-y6b6fb76.js";
65
- import"./cli-kpv03zhj.js";
63
+ import"./cli-yab68w40.js";
64
+ import"./cli-08b07b4r.js";
65
+ import"./cli-3apbzgyk.js";
66
66
  import"./cli-e29gmdmw.js";
67
67
  import"./cli-c2mk1kgf.js";
68
68
  import"./cli-ej6gbxfb.js";
69
69
  import"./cli-sd0mxa3c.js";
70
70
  import"./cli-w5e1d1vv.js";
71
- import"./cli-w9kb3bk1.js";
72
- import"./cli-xqcq9y5e.js";
71
+ import"./cli-kjwt6hdf.js";
72
+ import"./cli-r2ap2czm.js";
73
73
  import"./cli-pzxba7gw.js";
74
74
  import"./cli-f7kvq46p.js";
75
75
  import"./cli-zf8jjwex.js";
@@ -3,11 +3,11 @@ import {
3
3
  executeComposioRequest,
4
4
  formatComposioResultForCli,
5
5
  parseComposioArgs
6
- } from "./cli-8fc8de14.js";
6
+ } from "./cli-0z2v4nhw.js";
7
7
  import {
8
8
  init_secret_scrubber,
9
9
  scrubSecrets
10
- } from "./cli-xqcq9y5e.js";
10
+ } from "./cli-r2ap2czm.js";
11
11
  import"./cli-bc05qbss.js";
12
12
 
13
13
  // src/commands/x.ts
package/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Swarm API",
5
- "version": "1.147.0",
5
+ "version": "1.149.0",
6
6
  "description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
7
7
  },
8
8
  "servers": [
@@ -174,6 +174,20 @@
174
174
  ],
175
175
  "default": "mcp"
176
176
  },
177
+ "routingReason": {
178
+ "type": "string",
179
+ "enum": [
180
+ "skill",
181
+ "continuity",
182
+ "overflow",
183
+ "human_pinned",
184
+ "reroute_fault"
185
+ ]
186
+ },
187
+ "routingNote": {
188
+ "type": "string",
189
+ "maxLength": 200
190
+ },
177
191
  "taskType": {
178
192
  "type": "string",
179
193
  "maxLength": 50
@@ -4065,7 +4079,7 @@
4065
4079
  "config": {
4066
4080
  "type": "object",
4067
4081
  "additionalProperties": {},
4068
- "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
4082
+ "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
4069
4083
  },
4070
4084
  "next": {
4071
4085
  "anyOf": [
@@ -4494,7 +4508,7 @@
4494
4508
  "config": {
4495
4509
  "type": "object",
4496
4510
  "additionalProperties": {},
4497
- "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
4511
+ "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
4498
4512
  },
4499
4513
  "next": {
4500
4514
  "anyOf": [
@@ -33207,6 +33221,20 @@
33207
33221
  "agentId": {
33208
33222
  "type": "string"
33209
33223
  },
33224
+ "routingReason": {
33225
+ "type": "string",
33226
+ "enum": [
33227
+ "skill",
33228
+ "continuity",
33229
+ "overflow",
33230
+ "human_pinned",
33231
+ "reroute_fault"
33232
+ ]
33233
+ },
33234
+ "routingNote": {
33235
+ "type": "string",
33236
+ "maxLength": 200
33237
+ },
33210
33238
  "tags": {
33211
33239
  "type": "array",
33212
33240
  "items": {
@@ -40188,6 +40216,20 @@
40188
40216
  "agentId": {
40189
40217
  "type": "string"
40190
40218
  },
40219
+ "routingReason": {
40220
+ "type": "string",
40221
+ "enum": [
40222
+ "skill",
40223
+ "continuity",
40224
+ "overflow",
40225
+ "human_pinned",
40226
+ "reroute_fault"
40227
+ ]
40228
+ },
40229
+ "routingNote": {
40230
+ "type": "string",
40231
+ "maxLength": 200
40232
+ },
40191
40233
  "taskType": {
40192
40234
  "type": "string"
40193
40235
  },
@@ -46726,7 +46768,7 @@
46726
46768
  "config": {
46727
46769
  "type": "object",
46728
46770
  "additionalProperties": {},
46729
- "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
46771
+ "description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
46730
46772
  },
46731
46773
  "next": {
46732
46774
  "anyOf": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/agent-swarm",
3
- "version": "1.147.0",
3
+ "version": "1.149.0",
4
4
  "description": "agent-swarm.dev — an open-source operating system for AI work: a lead agent breaks goals into tasks, routes them to specialized workers such as Claude Code or Codex, runs each worker in an isolated container, and preserves shared memory, tools, schedules, and review gates so delegated work compounds across sessions.",
5
5
  "keywords": [
6
6
  "agent-swarm.dev",
@@ -111,6 +111,8 @@
111
111
  "prepare-release": "bun scripts/prepare-release.ts",
112
112
  "refresh:vendored-openapi": "bun scripts/refresh-vendored-openapi.ts",
113
113
  "sync-chart-version": "bun scripts/sync-chart-version.ts",
114
+ "sync-plugin-versions": "bun scripts/sync-plugin-versions.ts",
115
+ "check:plugin-versions": "bun scripts/sync-plugin-versions.ts --check",
114
116
  "bump:agent-fs": "bun scripts/bump-agent-fs.ts",
115
117
  "check-chart-version": "bun scripts/sync-chart-version.ts --check-if-package-version-changed",
116
118
  "cli": "bun src/cli.tsx",
@@ -49,6 +49,7 @@ const agentmailBuffer = createIngressBuffer<BufferedAgentMailMessage>({
49
49
  if (followupResult.skipped) return;
50
50
  const task = await createTaskWithSiblingAwareness(followupResult.text, {
51
51
  agentId: first.agentId,
52
+ routingReason: "continuity",
52
53
  source: "agentmail",
53
54
  taskType: "agentmail-reply",
54
55
  agentmailInboxId: first.inboxId,
@@ -249,6 +250,7 @@ export async function handleMessageReceived(
249
250
 
250
251
  const task = await createTaskWithSiblingAwareness(followupResult.text, {
251
252
  agentId: existingTask.agentId,
253
+ routingReason: existingTask.agentId ? "continuity" : undefined,
252
254
  source: "agentmail",
253
255
  taskType: "agentmail-reply",
254
256
  agentmailInboxId: inbox_id,
@@ -288,6 +290,7 @@ export async function handleMessageReceived(
288
290
 
289
291
  const task = await createTaskWithSiblingAwareness(leadResult.text, {
290
292
  agentId: agent.id,
293
+ routingReason: "human_pinned",
291
294
  source: "agentmail",
292
295
  taskType: "agentmail-message",
293
296
  agentmailInboxId: inbox_id,
@@ -318,6 +321,7 @@ export async function handleMessageReceived(
318
321
 
319
322
  const task = await createTaskWithSiblingAwareness(workerResult.text, {
320
323
  agentId: agent.id,
324
+ routingReason: "human_pinned",
321
325
  source: "agentmail",
322
326
  taskType: "agentmail-message",
323
327
  agentmailInboxId: inbox_id,
@@ -352,6 +356,7 @@ export async function handleMessageReceived(
352
356
 
353
357
  const task = await createTaskWithSiblingAwareness(unmappedResult.text, {
354
358
  agentId: lead.id,
359
+ routingReason: "skill",
355
360
  source: "agentmail",
356
361
  taskType: "agentmail-message",
357
362
  agentmailInboxId: inbox_id,
@@ -0,0 +1,41 @@
1
+ import type { AutomationPreflightResult } from "./be/automation-preflight";
2
+ import { getAppUrl } from "./utils/constants";
3
+ import { scrubSecrets } from "./utils/secret-scrubber";
4
+
5
+ /** Best-effort alert; callers gate this on a newly recorded preflight refusal. */
6
+ export async function notifyAutomationPreflightFailure(
7
+ preflight: AutomationPreflightResult,
8
+ ): Promise<void> {
9
+ const channel = process.env.SLACK_ALERTS_CHANNEL?.trim();
10
+ if (!channel) {
11
+ console.warn("[Automation Preflight] SLACK_ALERTS_CHANNEL not set; skipping alert");
12
+ return;
13
+ }
14
+
15
+ try {
16
+ const { getSlackApp } = await import("./slack/app");
17
+ const app = getSlackApp();
18
+ if (!app) {
19
+ console.warn("[Automation Preflight] Slack not available, cannot send notification");
20
+ return;
21
+ }
22
+ await app.client.chat.postMessage({
23
+ channel,
24
+ text: scrubSecrets(
25
+ `⚠️ Automation needs setup\n` +
26
+ `Automation: ${preflight.kind} "${preflight.name}"\n` +
27
+ `Missing params: ${preflight.missing.params.join(", ") || "none"}\n` +
28
+ `Missing integrations: ${preflight.missing.integrations.join(", ") || "none"}\n` +
29
+ `Fire SKIPPED. It was not retried or queued.\n` +
30
+ `Fix setup: ${getAppUrl()}${preflight.fixUrl}`,
31
+ ),
32
+ unfurl_links: false,
33
+ unfurl_media: false,
34
+ });
35
+ } catch (error) {
36
+ console.error(
37
+ "[Automation Preflight] Failed to send Slack notification:",
38
+ scrubSecrets(error instanceof Error ? error.message : String(error)),
39
+ );
40
+ }
41
+ }
@@ -380,7 +380,7 @@ export async function recordWorkflowPreflightFailure(input: {
380
380
  failureReason: string;
381
381
  createdBy?: string;
382
382
  now?: Date;
383
- }): Promise<string> {
383
+ }): Promise<{ runId: string; recorded: boolean }> {
384
384
  const now = input.now ?? new Date();
385
385
  const bounds = utcDayBounds(now);
386
386
  return await getDbClient().transaction(async (tx) => {
@@ -392,7 +392,7 @@ export async function recordWorkflowPreflightFailure(input: {
392
392
  ORDER BY startedAt ASC LIMIT 1`,
393
393
  [input.workflowId, bounds.start, bounds.end],
394
394
  );
395
- if (existing) return existing.id;
395
+ if (existing) return { runId: existing.id, recorded: false };
396
396
 
397
397
  const runId = crypto.randomUUID();
398
398
  const timestamp = now.toISOString();
@@ -413,6 +413,6 @@ export async function recordWorkflowPreflightFailure(input: {
413
413
  timestamp,
414
414
  ],
415
415
  );
416
- return runId;
416
+ return { runId, recorded: true };
417
417
  });
418
418
  }
@@ -115,6 +115,7 @@ export async function emitBudgetRefusalSideEffects(
115
115
 
116
116
  const followUp = await createTaskExtended(resolved.text, {
117
117
  agentId: leadAgent.id,
118
+ routingReason: "skill",
118
119
  source: "system",
119
120
  taskType: "follow-up",
120
121
  parentTaskId: ctx.task.id,
@@ -9,6 +9,7 @@ import type {
9
9
  ProviderName,
10
10
  ReasoningEffort,
11
11
  RoutingAffinity,
12
+ RoutingReason,
12
13
  } from "../../../types";
13
14
  import {
14
15
  FollowUpConfigSchema,
@@ -45,6 +46,8 @@ export type AgentTaskRow = {
45
46
  title: string | null;
46
47
  status: AgentTaskStatus;
47
48
  source: AgentTaskSource;
49
+ routing_reason: RoutingReason | null;
50
+ routing_note: string | null;
48
51
  taskType: string | null;
49
52
  tags: string | null;
50
53
  priority: number;
@@ -165,6 +168,8 @@ export function rowToAgentTask(row: AgentTaskRow): AgentTask {
165
168
  title: row.title ?? undefined,
166
169
  status: row.status,
167
170
  source: row.source,
171
+ routingReason: row.routing_reason ?? undefined,
172
+ routingNote: row.routing_note ?? undefined,
168
173
  taskType: row.taskType ?? undefined,
169
174
  tags: row.tags ? JSON.parse(row.tags) : [],
170
175
  priority: row.priority ?? 50,
package/src/be/db.ts CHANGED
@@ -18,6 +18,7 @@ import type {
18
18
  AgentLogEventType,
19
19
  AgentMcpServer,
20
20
  AgentSkill,
21
+ AgentStatus,
21
22
  AgentTask,
22
23
  AgentTaskStatus,
23
24
  AgentTaskSummary,
@@ -2051,6 +2052,103 @@ export async function findRecentSimilarTasks(opts: {
2051
2052
  return rows.map(rowToAgentTask);
2052
2053
  }
2053
2054
 
2055
+ type RoutingDecisionWorkerStatus = {
2056
+ agentId: string;
2057
+ status: AgentStatus;
2058
+ activeTaskCount: number;
2059
+ openTaskCount: number;
2060
+ };
2061
+
2062
+ type RoutingDecisionCandidate = {
2063
+ taskId: string;
2064
+ agentId: string;
2065
+ };
2066
+
2067
+ type RoutingDecisionSnapshot = {
2068
+ capturedAt: string;
2069
+ workerStatuses: RoutingDecisionWorkerStatus[];
2070
+ continuityCandidates: {
2071
+ samePr: RoutingDecisionCandidate | null;
2072
+ sameThread: RoutingDecisionCandidate | null;
2073
+ sameRepo: RoutingDecisionCandidate | null;
2074
+ };
2075
+ };
2076
+
2077
+ const ROUTING_HOLDER_SQL = `CASE
2078
+ WHEN status IN ('draft', 'offered', 'reviewing') AND offeredTo IS NOT NULL THEN offeredTo
2079
+ ELSE COALESCE(agentId, offeredTo)
2080
+ END`;
2081
+
2082
+ async function findLatestRoutingCandidate(
2083
+ where: string,
2084
+ params: Array<string | number>,
2085
+ ): Promise<RoutingDecisionCandidate | null> {
2086
+ const row = await getDbClient().get<RoutingDecisionCandidate>(
2087
+ `SELECT id AS taskId, ${ROUTING_HOLDER_SQL} AS agentId
2088
+ FROM agent_tasks
2089
+ WHERE ${where}
2090
+ AND ${ROUTING_HOLDER_SQL} IN (SELECT id FROM agents WHERE isLead = 0)
2091
+ ORDER BY createdAt DESC, rowid DESC
2092
+ LIMIT 1`,
2093
+ params,
2094
+ );
2095
+ return row ?? null;
2096
+ }
2097
+
2098
+ async function captureRoutingDecisionSnapshot(
2099
+ options: CreateTaskOptions,
2100
+ ): Promise<RoutingDecisionSnapshot> {
2101
+ const workerStatuses = await getDbClient().query<RoutingDecisionWorkerStatus>(
2102
+ `SELECT agent.id AS agentId, agent.status,
2103
+ COUNT(task.id) AS openTaskCount,
2104
+ SUM(CASE WHEN task.status IN ('in_progress', 'reviewing') THEN 1 ELSE 0 END) AS activeTaskCount
2105
+ FROM agents agent
2106
+ LEFT JOIN agent_tasks task ON
2107
+ (task.agentId = agent.id OR task.offeredTo = agent.id)
2108
+ AND task.status NOT IN ('completed', 'failed', 'cancelled', 'superseded')
2109
+ WHERE agent.isLead = 0
2110
+ GROUP BY agent.id, agent.status
2111
+ ORDER BY agent.id`,
2112
+ );
2113
+
2114
+ const samePr =
2115
+ options.vcsRepo && options.vcsNumber != null
2116
+ ? await findLatestRoutingCandidate("vcsRepo = ? AND vcsNumber = ?", [
2117
+ options.vcsRepo,
2118
+ options.vcsNumber,
2119
+ ])
2120
+ : null;
2121
+
2122
+ let sameThread: RoutingDecisionCandidate | null = null;
2123
+ if (options.slackChannelId && options.slackThreadTs) {
2124
+ sameThread = await findLatestRoutingCandidate("slackChannelId = ? AND slackThreadTs = ?", [
2125
+ options.slackChannelId,
2126
+ options.slackThreadTs,
2127
+ ]);
2128
+ } else if (options.agentmailThreadId) {
2129
+ sameThread = await findLatestRoutingCandidate("agentmailThreadId = ?", [
2130
+ options.agentmailThreadId,
2131
+ ]);
2132
+ }
2133
+
2134
+ const sameRepo = options.vcsRepo
2135
+ ? await findLatestRoutingCandidate("vcsRepo = ?", [options.vcsRepo])
2136
+ : null;
2137
+
2138
+ return {
2139
+ capturedAt: new Date().toISOString(),
2140
+ workerStatuses,
2141
+ continuityCandidates: { samePr, sameThread, sameRepo },
2142
+ };
2143
+ }
2144
+
2145
+ function logRoutingDecisionFailure(taskId: string, stage: "capture" | "write", error: unknown) {
2146
+ console.warn(
2147
+ `[routing-decision] Failed to ${stage} snapshot for task ${taskId}:`,
2148
+ scrubSecrets(error instanceof Error ? error.message : String(error)),
2149
+ );
2150
+ }
2151
+
2054
2152
  export async function createTaskExtended(
2055
2153
  task: string,
2056
2154
  options?: CreateTaskOptions,
@@ -2417,9 +2515,16 @@ export async function createTaskExtended(
2417
2515
  : await findExistingLinearTrackerContextWork(options?.contextKey);
2418
2516
  if (existingTrackerWork) return { existing: existingTrackerWork };
2419
2517
 
2518
+ let routingDecisionSnapshot: RoutingDecisionSnapshot | null = null;
2519
+ try {
2520
+ routingDecisionSnapshot = await captureRoutingDecisionSnapshot(options);
2521
+ } catch (error) {
2522
+ logRoutingDecisionFailure(id, "capture", error);
2523
+ }
2524
+
2420
2525
  const inserted = await getDbClient().get<AgentTaskRow>(
2421
2526
  `INSERT INTO agent_tasks (
2422
- id, "key", agentId, creatorAgentId, task, status, source,
2527
+ id, "key", agentId, creatorAgentId, task, status, source, routing_reason, routing_note,
2423
2528
  taskType, tags, priority, dependsOn, offeredTo, offeredAt,
2424
2529
  slackChannelId, slackThreadTs, slackTriggerMessageTs, slackUserId,
2425
2530
  vcsProvider, vcsRepo, vcsEventType, vcsNumber, vcsCommentId, vcsAuthor, vcsUrl,
@@ -2427,7 +2532,7 @@ export async function createTaskExtended(
2427
2532
  agentmailInboxId, agentmailMessageId, agentmailThreadId,
2428
2533
  mentionMessageId, mentionChannelId, dir, parentTaskId, model, modelTier, effort, scheduleId,
2429
2534
  workflowRunId, workflowRunStepId, outputSchema, followUpConfig, requestedByUserId, requestedByUserIdInherited, contextKey, routingAffinity, swarmVersion, createdAt, lastUpdatedAt, created_by, updated_by
2430
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
2535
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
2431
2536
  [
2432
2537
  id,
2433
2538
  assetKey,
@@ -2436,6 +2541,8 @@ export async function createTaskExtended(
2436
2541
  task,
2437
2542
  status,
2438
2543
  options?.source ?? "mcp",
2544
+ options?.routingReason ?? null,
2545
+ options?.routingNote ?? null,
2439
2546
  options?.taskType ?? null,
2440
2547
  JSON.stringify(options?.tags ?? []),
2441
2548
  options?.priority ?? 50,
@@ -2482,6 +2589,28 @@ export async function createTaskExtended(
2482
2589
  ],
2483
2590
  );
2484
2591
  if (!inserted) throw new Error("Failed to create task");
2592
+
2593
+ if (routingDecisionSnapshot) {
2594
+ try {
2595
+ await getDbClient().run(
2596
+ `INSERT INTO routing_decisions (
2597
+ task_id, selected_agent_id, captured_at, worker_statuses,
2598
+ continuity_candidates, created_by, updated_by
2599
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)`,
2600
+ [
2601
+ id,
2602
+ options.offeredTo ?? options.agentId ?? null,
2603
+ routingDecisionSnapshot.capturedAt,
2604
+ JSON.stringify(routingDecisionSnapshot.workerStatuses),
2605
+ JSON.stringify(routingDecisionSnapshot.continuityCandidates),
2606
+ auditUserId,
2607
+ auditUserId,
2608
+ ],
2609
+ );
2610
+ } catch (error) {
2611
+ logRoutingDecisionFailure(id, "write", error);
2612
+ }
2613
+ }
2485
2614
  return { row: inserted };
2486
2615
  });
2487
2616
 
@@ -3520,6 +3649,7 @@ export async function postMessage(
3520
3649
 
3521
3650
  const task = await createTaskExtended(taskDescription, {
3522
3651
  agentId: mentionedAgentId, // Direct assignment
3652
+ routingReason: "human_pinned",
3523
3653
  creatorAgentId: agentId ?? undefined,
3524
3654
  source: "mcp",
3525
3655
  taskType: "task",
@@ -0,0 +1,18 @@
1
+ -- Task deferrals retain their one-time schedule as the deadline. This sibling
2
+ -- to workflow wait_states arbitrates event/deadline dispatch without inventing
3
+ -- a workflow run or step for an ordinary task.
4
+ CREATE TABLE IF NOT EXISTS deferred_task_waits (
5
+ scheduleId TEXT PRIMARY KEY REFERENCES scheduled_tasks(id) ON DELETE CASCADE,
6
+ taskId TEXT NOT NULL,
7
+ eventName TEXT NOT NULL CHECK (eventName IN ('task.completed', 'task.failed', 'settled')),
8
+ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'fired')),
9
+ firedBy TEXT,
10
+ childTaskId TEXT,
11
+ resolvedAt TEXT,
12
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
+ updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
14
+ created_by TEXT,
15
+ updated_by TEXT
16
+ );
17
+ CREATE INDEX IF NOT EXISTS idx_deferred_task_waits_pending
18
+ ON deferred_task_waits(taskId) WHERE status = 'pending';
@@ -0,0 +1,39 @@
1
+ -- Migration 141 added requirements by canonical name even when an existing
2
+ -- schedule already contained concrete values instead of template placeholders.
3
+ -- Restore its unbound timezone first so TIMEZONE is pruned in the same pass
4
+ -- unless the task body still references it. Keep operator-supplied bindings.
5
+ UPDATE scheduled_tasks
6
+ SET timezone = 'UTC'
7
+ WHERE name = 'weekly-dependabot-triage'
8
+ AND timezone = '{{TIMEZONE}}'
9
+ AND json_extract(params, '$.TIMEZONE') IS NULL;
10
+
11
+ -- Only remove requirements that the row does not consume. Scope this repair to
12
+ -- the names backfilled by 141; leave custom schedules and integration gates alone.
13
+ -- The EXISTS guard also leaves already-correct JSON byte-for-byte unchanged.
14
+ UPDATE scheduled_tasks
15
+ SET requiredParams = (
16
+ SELECT json_group_array(value)
17
+ FROM json_each(scheduled_tasks.requiredParams)
18
+ WHERE instr(COALESCE(scheduled_tasks.taskTemplate, ''), '{{' || value || '}}') > 0
19
+ OR instr(COALESCE(scheduled_tasks.timezone, ''), '{{' || value || '}}') > 0
20
+ )
21
+ WHERE name IN (
22
+ 'daily-blocker-digest',
23
+ 'daily-compounding-reflection',
24
+ 'daily-status-report',
25
+ 'daily-workflow-health-audit',
26
+ 'weekly-harness-upgrade-check',
27
+ 'weekly-dependabot-triage',
28
+ 'weekly-code-health-reports',
29
+ 'weekly-dora-metrics',
30
+ 'daily-hn-briefing',
31
+ 'gtm-weekly-review',
32
+ 'dream-daily'
33
+ )
34
+ AND EXISTS (
35
+ SELECT 1
36
+ FROM json_each(scheduled_tasks.requiredParams)
37
+ WHERE instr(COALESCE(scheduled_tasks.taskTemplate, ''), '{{' || value || '}}') = 0
38
+ AND instr(COALESCE(scheduled_tasks.timezone, ''), '{{' || value || '}}') = 0
39
+ );