@desplega.ai/agent-swarm 2.7.5 → 2.7.7

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 (319) hide show
  1. package/dist/{acp-adapter-g3ads55s.js → acp-adapter-7b4vk3h5.js} +5 -4
  2. package/dist/{actions-zwfykqqk.js → actions-3tt153af.js} +18 -17
  3. package/dist/{amp-adapter-z3s0ssdt.js → amp-adapter-njpts0yr.js} +1 -1
  4. package/dist/{anthropic-messages-x4q6rfq5.js → anthropic-messages-xey2skwx.js} +7 -7
  5. package/dist/{app-vmp4fgep.js → app-nky4378f.js} +3 -3
  6. package/dist/{assistant-vwde653f.js → assistant-jnb669pa.js} +24 -22
  7. package/dist/{azure-openai-responses-s1w5n70z.js → azure-openai-responses-26t7j9ra.js} +5 -5
  8. package/dist/{boot-reembed-375t7tbk.js → boot-reembed-9mgvaztt.js} +1 -1
  9. package/dist/{boot-reembed-gq9rcpnj.js → boot-reembed-qs2djdej.js} +1 -1
  10. package/dist/{boot-scrub-sweep-nd938kyf.js → boot-scrub-sweep-yjpdj7s1.js} +3 -3
  11. package/dist/{boot-seeds-aykx51v3.js → boot-seeds-5cm6ambd.js} +4 -4
  12. package/dist/{boxd-k1j26g3h.js → boxd-nv507va8.js} +5 -5
  13. package/dist/{claude-adapter-8j4hm099.js → claude-adapter-fn287zmm.js} +5 -4
  14. package/dist/{claude-managed-setup-0wyynpn1.js → claude-managed-setup-wtdz2mj2.js} +1 -1
  15. package/dist/{claude-sdk-session-q6wj5hmy.js → claude-sdk-session-x91kqyhm.js} +9677 -9514
  16. package/dist/{cli-j3jvnpe8.js → cli-08bmz9z9.js} +1 -1
  17. package/dist/{cli-gjr2y2xk.js → cli-0agcv1v5.js} +4 -1
  18. package/dist/{cli-y24sc29k.js → cli-1c6tzt8g.js} +30 -8
  19. package/dist/{cli-mjzynrse.js → cli-35rsp8ye.js} +1 -1
  20. package/dist/{cli-rpm2sgv0.js → cli-3fg0bdcv.js} +19 -2
  21. package/dist/{cli-nn4d8dne.js → cli-5b456bpf.js} +2 -2
  22. package/dist/{cli-bhjt02p8.js → cli-5jnhv72d.js} +1 -1
  23. package/dist/{cli-fqzx7gwa.js → cli-5zx699j9.js} +2 -2
  24. package/dist/{cli-hf6zt5m6.js → cli-69szn7w7.js} +17 -1
  25. package/dist/{cli-vqypxzh4.js → cli-6g0hb4cp.js} +8 -8
  26. package/dist/{cli-tqgg40ek.js → cli-6pfd54vx.js} +9 -8
  27. package/dist/{cli-bsn8nhrq.js → cli-6vcp76qk.js} +3 -3
  28. package/dist/{cli-zppwg9p9.js → cli-72v799xn.js} +1 -1
  29. package/dist/cli-82j36f2m.js +45 -0
  30. package/dist/{cli-hn9hxmz9.js → cli-8305gbq0.js} +29 -16
  31. package/dist/{cli-z8eh3ex8.js → cli-8sckt74b.js} +8 -8
  32. package/dist/{cli-bnz7a7qf.js → cli-95jzxcp3.js} +1 -1
  33. package/dist/{cli-0bxqnvq9.js → cli-adeegh7d.js} +29 -7
  34. package/dist/{cli-g61qxmge.js → cli-afkqkrtw.js} +3 -3
  35. package/dist/{cli-7a42nfy0.js → cli-ayayvfg4.js} +24 -4
  36. package/dist/{cli-bqt1mptt.js → cli-az48n0nr.js} +4 -4
  37. package/dist/{cli-z6jkx23q.js → cli-bfv7vdg6.js} +9 -9
  38. package/dist/{cli-pywf3eh5.js → cli-caj33vcq.js} +5 -5
  39. package/dist/{cli-5pag6rmn.js → cli-cb2a8pna.js} +1 -1
  40. package/dist/{cli-wvaawacd.js → cli-cppkf404.js} +5236 -72
  41. package/dist/{cli-mry0qzym.js → cli-ddaanqkd.js} +123 -10
  42. package/dist/{cli-0gey5fzy.js → cli-e0kmphd6.js} +2 -2
  43. package/dist/{cli-zh3fp8v2.js → cli-e46hg0xw.js} +1 -1
  44. package/dist/{cli-jm2vfpfd.js → cli-e5bzrn01.js} +1 -1
  45. package/dist/{cli-qxnf8z2z.js → cli-excnnjg2.js} +165 -153
  46. package/dist/{cli-71ptav7x.js → cli-ferkkrg9.js} +1 -1
  47. package/dist/{cli-vpf89f34.js → cli-fmjd0t1y.js} +3 -3
  48. package/dist/{cli-rm6hqj3z.js → cli-fyt2g4wd.js} +33 -139
  49. package/dist/cli-g08zdaec.js +55 -0
  50. package/dist/{cli-ehq736cn.js → cli-g7s47cc5.js} +4 -4
  51. package/dist/{cli-82ae98pz.js → cli-gz6q4eve.js} +3 -3
  52. package/dist/{cli-82jg7fp9.js → cli-he5nxaa8.js} +1 -1
  53. package/dist/{cli-rqkxrmgw.js → cli-je518txm.js} +39 -14
  54. package/dist/{cli-8hs41zy2.js → cli-jtjtabxe.js} +1 -1
  55. package/dist/{cli-611a1294.js → cli-k0wwfqbg.js} +18 -1
  56. package/dist/{cli-nzxr556s.js → cli-k1nje3v3.js} +38 -43
  57. package/dist/{cli-3h4nhjn8.js → cli-k8196sh2.js} +9 -7
  58. package/dist/{cli-afrrppsw.js → cli-k899ehvh.js} +2 -2
  59. package/dist/{cli-0731hvbw.js → cli-m0da8j35.js} +23 -9
  60. package/dist/cli-m2z8jagn.js +12078 -0
  61. package/dist/{cli-8veytvbh.js → cli-mkk9rnzz.js} +5 -5
  62. package/dist/{cli-7wspm5gm.js → cli-n6bv12jn.js} +528 -6
  63. package/dist/{cli-spknvxbq.js → cli-nmzhp1b5.js} +14 -12
  64. package/dist/{cli-p599f1qm.js → cli-p82cnnjq.js} +1 -1
  65. package/dist/{cli-xtjhfmpc.js → cli-pc6n7fre.js} +1 -1
  66. package/dist/{cli-vbyfwh92.js → cli-pjctyea3.js} +2 -2
  67. package/dist/{cli-nmbmy64z.js → cli-pq73h5mz.js} +3 -3
  68. package/dist/{cli-aa6yxc7m.js → cli-pz4rk021.js} +1 -1
  69. package/dist/{cli-7wcyk2s5.js → cli-q3tkegby.js} +1 -1
  70. package/dist/cli-qghe0h66.js +67 -0
  71. package/dist/{cli-6s7vdcta.js → cli-qh4d4tvk.js} +4 -4
  72. package/dist/{cli-mmwm7zbf.js → cli-rtt8g4v9.js} +1 -1
  73. package/dist/{cli-kg8hchyg.js → cli-sa02jsqt.js} +1 -1
  74. package/dist/{cli-1h3wcpbw.js → cli-snpj5zbj.js} +2 -2
  75. package/dist/{cli-a7v854rf.js → cli-tgrv9cjx.js} +263 -12
  76. package/dist/{cli-a47xy8eq.js → cli-vz22fyqv.js} +186 -54
  77. package/dist/{cli-1ayk1eas.js → cli-wk5yrfwd.js} +285 -42
  78. package/dist/{cli-1338796d.js → cli-ws19768n.js} +1755 -119
  79. package/dist/{cli-70r77n04.js → cli-xae4g51r.js} +1 -1
  80. package/dist/{cli-gf5hbmdr.js → cli-yjdgea32.js} +3 -3
  81. package/dist/{cli-xbkdm710.js → cli-yndmfxb3.js} +3 -3
  82. package/dist/{cli-rhw40jgb.js → cli-yyj3j5m4.js} +2 -2
  83. package/dist/cli.js +26 -25
  84. package/dist/{cloudflare-workers-ai-system-one-bm60fjm0.js → cloudflare-workers-ai-system-one-ef2a980q.js} +2 -2
  85. package/dist/{codex-adapter-q6k3gnyg.js → codex-adapter-cf2yxe9m.js} +3 -2
  86. package/dist/{codex-hook-9efm2x1m.js → codex-hook-a0c6g6t6.js} +1 -1
  87. package/dist/{codex-session-runner-3mwmk3d9.js → codex-session-runner-6vfzdgbd.js} +3 -2
  88. package/dist/{commands-evrenjn9.js → commands-t3mfy7vn.js} +9 -3
  89. package/dist/{controller-xjp8vswh.js → controller-q7xrbaz0.js} +8 -3
  90. package/dist/{controllers-connect-pp5jnxvc.js → controllers-connect-c6nm70kg.js} +20 -19
  91. package/dist/{cursor-adapter-yf47w4t0.js → cursor-adapter-ftd81ga8.js} +1 -1
  92. package/dist/{db-zxpw6aht.js → db-dk572x25.js} +3 -3
  93. package/dist/{db-rgfsh91f.js → db-vemtpmcc.js} +14 -4
  94. package/dist/{devtools-82fzqra8.js → devtools-qxfgbsqz.js} +1 -1
  95. package/dist/{dispatcher-smasgws7.js → dispatcher-kh7ecxh9.js} +17 -16
  96. package/dist/{docker-rrjhaqt9.js → docker-c1a3gqmf.js} +89 -22
  97. package/dist/{dsh-adapter-ftyy8dnp.js → dsh-adapter-v8628r89.js} +1 -1
  98. package/dist/{e2b-w1p0bnpm.js → e2b-fr12yccx.js} +5 -5
  99. package/dist/{e2b-qcaj675y.js → e2b-x6ywzak3.js} +3 -3
  100. package/dist/{easter-egg-3d-yyts7p16.js → easter-egg-3d-nenw4x63.js} +1 -1
  101. package/dist/{embedding-space-1z0mbg95.js → embedding-space-0jepb239.js} +6 -6
  102. package/dist/{embeddings-ygeg7tm7.js → embeddings-xxt49yxg.js} +1 -1
  103. package/dist/{execute-14qhqp4d.js → execute-1mhw6e4x.js} +1 -1
  104. package/dist/{external-channel-ttgrs3sx.js → external-channel-55v12e60.js} +2 -2
  105. package/dist/{fx-adapter-gt6pncj2.js → fx-adapter-bs8wqrk5.js} +6 -5
  106. package/dist/{google-generative-ai-yvmdxyxa.js → google-generative-ai-v94hr7h0.js} +5 -5
  107. package/dist/{google-vertex-jrtdh9gs.js → google-vertex-g7vr6cf8.js} +5 -5
  108. package/dist/{grok-adapter-sm4m5k4g.js → grok-adapter-gpjqmkcq.js} +6 -5
  109. package/dist/handlers-zxmp1ta4.js +32 -0
  110. package/dist/{heartbeat-qahz4p62.js → heartbeat-k42svnr0.js} +20 -19
  111. package/dist/{hook-4fd5wq5w.js → hook-114m7hap.js} +4 -3
  112. package/dist/{hook-kj3d398m.js → hook-6nphweh0.js} +24 -9
  113. package/dist/{http-1ted0j1k.js → http-r8cc4wz7.js} +1196 -211
  114. package/dist/index-a8phxqnk.js +37 -0
  115. package/dist/{index-q4b917zs.js → index-e3s8wmxy.js} +1 -1
  116. package/dist/{index-6rq3r5zb.js → index-fpk4bcd9.js} +1 -1
  117. package/dist/{index-5rk6rfzr.js → index-fvzke5kx.js} +1 -1
  118. package/dist/index-k6h00t4c.js +30 -0
  119. package/dist/{index-7v51awbn.js → index-nh3wyqdt.js} +1027 -577
  120. package/dist/{index-yqhz88yy.js → index-pxn30mse.js} +8 -8
  121. package/dist/index-xrz7te8h.js +33 -0
  122. package/dist/{keepalive-6cf311t5.js → keepalive-x060nt9p.js} +3 -3
  123. package/dist/lead-956sd2yc.js +71 -0
  124. package/dist/{maintenance-a4bm1bmt.js → maintenance-2xxfexhf.js} +1 -1
  125. package/dist/{mistral-conversations-4pmwj1c0.js → mistral-conversations-3gjpdb4b.js} +4 -4
  126. package/dist/{oauth-refresh-sweep-3h0dfw1k.js → oauth-refresh-sweep-fckc4ar5.js} +2 -2
  127. package/dist/{onboard-myn5hraa.js → onboard-zc48j237.js} +5 -5
  128. package/dist/{openai-codex-responses-44j573nm.js → openai-codex-responses-8pbxq9h5.js} +5 -5
  129. package/dist/{openai-completions-a4gee2a8.js → openai-completions-rm00s912.js} +4 -4
  130. package/dist/{openai-decisions-w4qkrcar.js → openai-decisions-8v957r2r.js} +1 -1
  131. package/dist/{openai-responses-rbp6h5kr.js → openai-responses-agxpf96k.js} +5 -5
  132. package/dist/{opencode-adapter-p2nkb5am.js → opencode-adapter-r690h1cr.js} +4 -3
  133. package/dist/{otel-impl-a1a0ef6b.js → otel-impl-r5xbh81q.js} +4 -4
  134. package/dist/{pi-mono-adapter-rzmpb72a.js → pi-mono-adapter-c7v8sdec.js} +7 -6
  135. package/dist/{pricing-refresh-83drrnxj.js → pricing-refresh-3pmre11v.js} +3 -3
  136. package/dist/{rbac-roles-s8y6ecb5.js → rbac-roles-3vbshwsb.js} +1 -1
  137. package/dist/{rbac-roles-0fb6e7pj.js → rbac-roles-910mmkgz.js} +2 -2
  138. package/dist/{render-v2-twmbgrz4.js → render-v2-pxykkbab.js} +3 -3
  139. package/dist/{resume-zfqc36xj.js → resume-adda0bwy.js} +6 -6
  140. package/dist/{runtime-qwggdpqr.js → runtime-fnbm7stk.js} +1 -1
  141. package/dist/{session-access-sc9pn9da.js → session-access-2fvamrdc.js} +4 -4
  142. package/dist/{session-source-backfill-qh07xr8g.js → session-source-backfill-08xvv0sm.js} +2 -2
  143. package/dist/{setup-4fr0m7a1.js → setup-1aqmvmh1.js} +3 -3
  144. package/dist/{typesafe-system-one-5mavm259.js → typesafe-system-one-0bmqcxfg.js} +2 -2
  145. package/dist/{virtual-modules-fh4ha15b.js → virtual-modules-d2pjk9j1.js} +5 -5
  146. package/dist/{work-objects-0wr8zxct.js → work-objects-9s0yrm5j.js} +20 -19
  147. package/dist/{worker-follow-up-ktyyazyp.js → worker-follow-up-3q78fqmr.js} +17 -16
  148. package/dist/worker-y15hy08h.js +71 -0
  149. package/openapi.json +289 -4
  150. package/package.json +9 -8
  151. package/src/apps/definition.ts +6 -5
  152. package/src/be/db/page-theme-tokens.ts +12 -0
  153. package/src/be/db/script-runs.ts +23 -0
  154. package/src/be/db/tasks/read.ts +131 -4
  155. package/src/be/db/tasks/write.ts +19 -0
  156. package/src/be/db-client.ts +114 -11
  157. package/src/be/db.ts +49 -6
  158. package/src/be/memory/providers/sqlite-store.ts +49 -12
  159. package/src/be/migrations/260_runtime_pool_cache.sql +20 -0
  160. package/src/be/migrations/262_session_visibility_indexes.sql +18 -0
  161. package/src/be/migrations/263_task_list_filter_index.sql +11 -0
  162. package/src/be/migrations/264_slack_thread_cover_index.sql +9 -0
  163. package/src/be/migrations/266_script_runs_source_task.sql +11 -0
  164. package/src/be/migrations/269_pages_design_system.sql +23 -0
  165. package/src/be/runtime-pools/cache-cleanup.ts +109 -0
  166. package/src/be/runtime-pools/db.ts +65 -6
  167. package/src/be/runtime-pools/remote-controller.ts +5 -0
  168. package/src/be/runtime-pools/supervisor.ts +33 -2
  169. package/src/be/scripts/typecheck.ts +22 -0
  170. package/src/be/seed/schedules-seeder.ts +0 -10
  171. package/src/be/seed-scripts/catalog/catalog-report.inline.ts +2 -0
  172. package/src/be/seed-scripts/catalog/catalog-report.ts +2 -0
  173. package/src/be/seed-scripts/catalog/memory-eval.ts +2 -0
  174. package/src/be/seed-scripts/catalog/swarm-update-check.ts +150 -0
  175. package/src/be/seed-scripts/catalog/task-failure-audit.ts +5 -1
  176. package/src/be/seed-scripts/index.ts +9 -0
  177. package/src/be/seed-skills/bundled-files.generated.json +3 -3
  178. package/src/be/swarm-config-guard.ts +32 -0
  179. package/src/be/task-auto-title-listener.ts +127 -0
  180. package/src/commands/controller.ts +4 -0
  181. package/src/commands/entrypoint-api-readiness.ts +74 -0
  182. package/src/commands/onboard/agent-fs-version.ts +1 -1
  183. package/src/commands/profile-sync.ts +151 -16
  184. package/src/commands/runner.ts +15 -7
  185. package/src/hooks/hook.ts +20 -9
  186. package/src/http/index.ts +4 -1
  187. package/src/http/list-total-cache.ts +14 -7
  188. package/src/http/memory.ts +38 -9
  189. package/src/http/pages-public.ts +93 -129
  190. package/src/http/pages.ts +94 -21
  191. package/src/http/script-runs.ts +174 -5
  192. package/src/http/status.ts +10 -2
  193. package/src/http/tasks.ts +4 -2
  194. package/src/pages/browser-sdk.ts +48 -21
  195. package/src/pages/color-literals.ts +115 -0
  196. package/src/pages/page-head.ts +766 -0
  197. package/src/pages/version.ts +3 -0
  198. package/src/providers/amp-adapter.ts +1 -1
  199. package/src/providers/codex-adapter.ts +1 -0
  200. package/src/providers/codex-app-server.ts +27 -1
  201. package/src/providers/fx-adapter.ts +1 -1
  202. package/src/providers/pi-mono-extension.ts +30 -15
  203. package/src/runtime-providers/controller-protocol.ts +14 -1
  204. package/src/runtime-providers/controller.ts +5 -0
  205. package/src/runtime-providers/docker.ts +108 -23
  206. package/src/runtime-providers/types.ts +16 -0
  207. package/src/script-workflows/workflow-ctx.ts +8 -0
  208. package/src/scripts-runtime/types/stdlib.d.ts +22 -0
  209. package/src/scripts-runtime/types/swarm-sdk.d.ts +22 -0
  210. package/src/server-user.ts +1 -0
  211. package/src/slack/commands.ts +5 -1
  212. package/src/slack/handlers.ts +37 -2
  213. package/src/slack/left-threads.ts +27 -4
  214. package/src/tasks/follow-up-gate.ts +318 -0
  215. package/src/tasks/follow-up-redelegation-guard.ts +155 -0
  216. package/src/tasks/worker-follow-up.ts +21 -1
  217. package/src/tests/claude-artifacts-read-script.test.ts +209 -0
  218. package/src/tests/codex-app-server.test.ts +59 -0
  219. package/src/tests/codex-gateway-route.test.ts +50 -1
  220. package/src/tests/create-page-tool.test.ts +501 -0
  221. package/src/tests/db-client-busy-retry.test.ts +81 -0
  222. package/src/tests/db-client.test.ts +21 -0
  223. package/src/tests/db-task-read-contract.test.ts +9 -2
  224. package/src/tests/db-task-write-contract.test.ts +7 -1
  225. package/src/tests/db-tasks-read.test.ts +21 -0
  226. package/src/tests/entrypoint-api-readiness.test.ts +416 -210
  227. package/src/tests/explicit-model-validation.test.ts +14 -8
  228. package/src/tests/fixtures/pages/head-v1.html +56 -0
  229. package/src/tests/follow-up-gate-shadow.test.ts +513 -0
  230. package/src/tests/follow-up-redelivery-guard.test.ts +432 -202
  231. package/src/tests/identity-field-budget.test.ts +1 -1
  232. package/src/tests/internal-ai/credentials.test.ts +62 -0
  233. package/src/tests/internal-ai/task-title.test.ts +283 -0
  234. package/src/tests/list-total-cache.test.ts +27 -2
  235. package/src/tests/memory-fts-populate.test.ts +11 -9
  236. package/src/tests/memory-retrieval-purge.test.ts +80 -0
  237. package/src/tests/merge-gate-detect-changes.test.ts +145 -0
  238. package/src/tests/migration-260-runtime-pool-cache.test.ts +118 -0
  239. package/src/tests/page-proxy.test.ts +1 -1
  240. package/src/tests/page-session-dev-cookie.test.ts +188 -0
  241. package/src/tests/pages-frame-ancestors.test.ts +28 -1
  242. package/src/tests/pages-head-v2.test.ts +534 -0
  243. package/src/tests/pages-http.test.ts +330 -0
  244. package/src/tests/pages-public-html.test.ts +43 -0
  245. package/src/tests/pages-storage.test.ts +182 -0
  246. package/src/tests/pages-versioning.test.ts +72 -0
  247. package/src/tests/profile-sync-stale-writeback.test.ts +334 -0
  248. package/src/tests/profile-sync.test.ts +11 -15
  249. package/src/tests/query-audit-plans.test.ts +27 -0
  250. package/src/tests/runtime-cache-cleanup.test.ts +367 -0
  251. package/src/tests/runtime-e2b-pools.test.ts +41 -0
  252. package/src/tests/runtime-pools-db.test.ts +98 -0
  253. package/src/tests/runtime-pools-http.test.ts +29 -0
  254. package/src/tests/runtime-providers-docker.test.ts +253 -0
  255. package/src/tests/runtime-remote-controller.test.ts +66 -2
  256. package/src/tests/runtime-supervisor.test.ts +66 -2
  257. package/src/tests/scheduled-task-required-params-migration.test.ts +3 -1
  258. package/src/tests/script-connections.test.ts +13 -0
  259. package/src/tests/script-runs-http.test.ts +684 -2
  260. package/src/tests/seed-registry.test.ts +28 -6
  261. package/src/tests/seed-schedules.test.ts +61 -8
  262. package/src/tests/seed-scripts.test.ts +168 -2
  263. package/src/tests/slack-leave-thread.test.ts +145 -5
  264. package/src/tests/slack-render-v2-query-plans.test.ts +24 -2
  265. package/src/tests/status.test.ts +11 -0
  266. package/src/tests/swarm-diff.test.ts +121 -2
  267. package/src/tests/task-auto-title-config-guard.test.ts +37 -0
  268. package/src/tests/task-auto-title-listener.test.ts +165 -0
  269. package/src/tests/tasks-readable-row.test.ts +155 -0
  270. package/src/tests/theme-import.test.ts +758 -0
  271. package/src/tests/themes-page-theme.test.ts +155 -0
  272. package/src/tests/themes-presets.test.ts +172 -0
  273. package/src/tests/workflow-script-principal.test.ts +2 -1
  274. package/src/themes/classics.ts +949 -0
  275. package/src/themes/import.ts +420 -0
  276. package/src/themes/page-fields.ts +40 -0
  277. package/src/themes/page-theme.ts +102 -0
  278. package/src/themes/presets.ts +561 -0
  279. package/src/themes/tokens.ts +218 -0
  280. package/src/tools/app-upsert.ts +1 -1
  281. package/src/tools/create-page.ts +118 -12
  282. package/src/tools/send-task.ts +35 -47
  283. package/src/tools/slack-leave-thread.ts +1 -1
  284. package/src/tools/task-dedup.ts +45 -21
  285. package/src/tools/utils.ts +33 -0
  286. package/src/types.ts +83 -3
  287. package/src/utils/constants.ts +19 -0
  288. package/src/utils/follow-up-gate-schedule-ids.ts +13 -0
  289. package/src/utils/internal-ai/credentials.ts +146 -93
  290. package/src/utils/internal-ai/index.ts +10 -0
  291. package/src/utils/internal-ai/models.ts +18 -0
  292. package/src/utils/internal-ai/task-title.ts +282 -0
  293. package/src/utils/page-session.ts +37 -0
  294. package/templates/schedules/daily-status-report/content.md +88 -2
  295. package/templates/schedules/daily-swarm-update-check/content.md +16 -40
  296. package/templates/skills/apps/SKILL.md +1 -1
  297. package/templates/skills/apps/content.md +1 -1
  298. package/templates/skills/composio-google-docs/content.md +10 -0
  299. package/templates/skills/heartbeat-runbook/content.md +1 -1
  300. package/templates/skills/pages/config.json +1 -1
  301. package/templates/skills/pages/content.md +539 -86
  302. package/templates/skills/pages/files/examples/annotated-pr.html +21 -12
  303. package/templates/skills/pages/files/examples/multiplayer-board.html +41 -41
  304. package/templates/skills/pages/files/examples/report-page.html +125 -124
  305. package/templates/skills/script-workflows/content.md +19 -1
  306. package/templates/skills/swarm-docs/content.md +1 -0
  307. package/templates/skills/swarm-scripts/SKILL.md +2 -0
  308. package/templates/skills/swarm-scripts/content.md +2 -0
  309. package/dist/cli-2pnswgh8.js +0 -189
  310. package/dist/cli-dznrgaep.js +0 -30
  311. package/dist/cli-w3hcrxht.js +0 -6985
  312. package/dist/handlers-vwmba1m2.js +0 -31
  313. package/dist/index-5r71rf98.js +0 -32
  314. package/dist/index-anmwxs87.js +0 -29
  315. package/dist/index-spp0ra5c.js +0 -36
  316. package/dist/lead-fjy418cw.js +0 -69
  317. package/dist/worker-0c5tyzqe.js +0 -69
  318. package/templates/schedules/daily-workflow-health-audit/config.json +0 -19
  319. package/templates/schedules/daily-workflow-health-audit/content.md +0 -191
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Task title generation: a short display title for a task prompt.
3
+ *
4
+ * Consumer of `completeStructuredWithModel`. Walks `TASK_TITLE_MODEL_CANDIDATES`
5
+ * (provider order, then model order) and returns the first title a configured
6
+ * credential produces. Every candidate is a cheap, fast model: one title costs
7
+ * well under a tenth of a cent, so thousands of weekly tasks stay in cents.
8
+ *
9
+ * Worker-safe: no bun:sqlite import. The API server wires it to task creation
10
+ * in `src/be/task-auto-title-listener.ts`.
11
+ */
12
+
13
+ import { Type } from "typebox";
14
+ import { z } from "zod";
15
+ import { scrubSecrets } from "../secret-scrubber.js";
16
+ import { completeStructuredWithModel } from "./complete-structured.js";
17
+ import { type CredentialKind, type ResolvedCredential, resolveCredentials } from "./credentials.js";
18
+ import { kindForModelString } from "./models.js";
19
+
20
+ /** Longest generated title. The PATCH /api/tasks/{id}/title route allows 120. */
21
+ export const TASK_TITLE_MAX_CHARS = 100;
22
+ /** Prompts shorter than this keep the prompt itself as the display title. */
23
+ export const TASK_TITLE_MIN_TASK_CHARS = 48;
24
+ /** Prompt text sent to the model is cut here. Keeps every call small. */
25
+ export const TASK_TITLE_MAX_TASK_CHARS = 2000;
26
+ /** Whole generation, across every candidate. */
27
+ export const TASK_TITLE_TIMEOUT_MS = 20_000;
28
+
29
+ /** Env var that pins one model (`provider/model-id`, or a `claude -p` alias). */
30
+ export const TASK_TITLE_MODEL_ENV = "TASK_AUTO_TITLE_MODEL";
31
+
32
+ export interface TaskTitleCandidateGroup {
33
+ kind: CredentialKind;
34
+ /** Full model strings for this credential kind, best first. */
35
+ models: readonly string[];
36
+ }
37
+
38
+ /**
39
+ * Provider order, then model order within a provider. Cheapest and fastest
40
+ * first: pay-per-token API keys before subscription OAuth, and the `claude -p`
41
+ * shellout last (it spawns a full CLI process per call).
42
+ *
43
+ * Model prices (input / output, USD per million tokens, models.dev snapshot):
44
+ * deepseek-v4.1-flash 0.034 / 0.137 · claude-haiku-5.5 0.10 / 0.50 ·
45
+ * gpt-6-luna 0.10 / 0.50 · gpt-5-nano 0.05 / 0.40
46
+ */
47
+ export const TASK_TITLE_MODEL_CANDIDATES: readonly TaskTitleCandidateGroup[] = [
48
+ {
49
+ kind: "openrouter",
50
+ models: [
51
+ "openrouter/deepseek/deepseek-v4.1-flash",
52
+ "openrouter/anthropic/claude-haiku-5.5",
53
+ "openrouter/openai/gpt-6-luna",
54
+ ],
55
+ },
56
+ { kind: "anthropic", models: ["anthropic/claude-haiku-5-5"] },
57
+ { kind: "openai", models: ["openai/gpt-6-luna", "openai/gpt-5-nano"] },
58
+ { kind: "openai-codex", models: ["openai-codex/gpt-6-luna"] },
59
+ { kind: "claude-cli", models: ["haiku"] },
60
+ ];
61
+
62
+ export { kindForModelString };
63
+
64
+ /**
65
+ * The candidate list for one environment. `TASK_AUTO_TITLE_MODEL` moves its
66
+ * provider to the front and puts the pinned model first inside it; the rest of
67
+ * the list stays as fallback. An unknown provider is ignored with a warning.
68
+ */
69
+ export function buildTaskTitlePlan(
70
+ env: Record<string, string | undefined> = process.env,
71
+ ): readonly TaskTitleCandidateGroup[] {
72
+ const pinned = env[TASK_TITLE_MODEL_ENV]?.trim();
73
+ if (!pinned) return TASK_TITLE_MODEL_CANDIDATES;
74
+ const kind = kindForModelString(pinned);
75
+ if (!kind) {
76
+ console.warn(
77
+ `[task-title] ${TASK_TITLE_MODEL_ENV}=${pinned} names an unsupported provider; ignored`,
78
+ );
79
+ return TASK_TITLE_MODEL_CANDIDATES;
80
+ }
81
+ const own = TASK_TITLE_MODEL_CANDIDATES.find((group) => group.kind === kind);
82
+ const rest = TASK_TITLE_MODEL_CANDIDATES.filter((group) => group.kind !== kind);
83
+ const models = [pinned, ...(own?.models ?? []).filter((model) => model !== pinned)];
84
+ return [{ kind, models }, ...rest];
85
+ }
86
+
87
+ const SIBLING_OPEN = "<sibling_tasks_in_progress>";
88
+ const SIBLING_CLOSE = "</sibling_tasks_in_progress>";
89
+
90
+ /**
91
+ * Task text as the model should see it: without the sibling-awareness block
92
+ * the API prepends to child tasks, with runs of blank lines collapsed, and cut
93
+ * to `TASK_TITLE_MAX_TASK_CHARS`.
94
+ */
95
+ export function prepareTaskTextForTitle(task: string): string {
96
+ let text = task;
97
+ if (text.startsWith(SIBLING_OPEN)) {
98
+ const close = text.indexOf(SIBLING_CLOSE);
99
+ if (close !== -1) text = text.slice(close + SIBLING_CLOSE.length);
100
+ }
101
+ text = text
102
+ .replace(/\r\n?/g, "\n")
103
+ .replace(/\n{3,}/g, "\n\n")
104
+ .trim();
105
+ if (text.length > TASK_TITLE_MAX_TASK_CHARS) {
106
+ text = `${text.slice(0, TASK_TITLE_MAX_TASK_CHARS).trimEnd()} …`;
107
+ }
108
+ return text;
109
+ }
110
+
111
+ const WRAPPING_QUOTES: ReadonlyArray<[string, string]> = [
112
+ ['"', '"'],
113
+ ["'", "'"],
114
+ ["“", "”"],
115
+ ["‘", "’"],
116
+ ["`", "`"],
117
+ ["«", "»"],
118
+ ];
119
+
120
+ /**
121
+ * Clean a model-produced title: one line, no wrapping quotes or `Title:`
122
+ * prefix, no markdown emphasis, no trailing sentence punctuation, at most
123
+ * `TASK_TITLE_MAX_CHARS` (cut at a word boundary). Empty string when nothing
124
+ * usable remains.
125
+ */
126
+ export function normalizeTaskTitle(raw: string): string {
127
+ let title = raw.replace(/\s+/g, " ").trim();
128
+ title = title.replace(/^title\s*:\s*/i, "");
129
+ title = title.replace(/\*\*|__|^#+\s*/g, "");
130
+ const stripTrailingPunctuation = () => {
131
+ title = title.replace(/[.!…]+$/u, "").trim();
132
+ };
133
+ // Quotes can sit inside or outside the trailing punctuation: `"Title".` and `"Title…"`.
134
+ stripTrailingPunctuation();
135
+ for (const [open, close] of WRAPPING_QUOTES) {
136
+ if (title.length >= 2 && title.startsWith(open) && title.endsWith(close)) {
137
+ title = title.slice(open.length, title.length - close.length).trim();
138
+ }
139
+ }
140
+ stripTrailingPunctuation();
141
+ if (title.length > TASK_TITLE_MAX_CHARS) {
142
+ const cut = title.slice(0, TASK_TITLE_MAX_CHARS);
143
+ const lastSpace = cut.lastIndexOf(" ");
144
+ title = (lastSpace >= TASK_TITLE_MAX_CHARS / 2 ? cut.slice(0, lastSpace) : cut).trimEnd();
145
+ title = title.replace(/[,;:\-–—]+$/u, "").trimEnd();
146
+ }
147
+ return title;
148
+ }
149
+
150
+ export const TASK_TITLE_SYSTEM_PROMPT = [
151
+ "You write titles for tasks on a software team's dashboard.",
152
+ "Rules:",
153
+ "- 3 to 8 words, at most 80 characters.",
154
+ "- Sentence case. No trailing period. No quotes, markdown, emoji, or task ids.",
155
+ "- Name the concrete subject (feature, bug, repo, file, system, person), not a generic verb alone.",
156
+ "- Keep the language of the request.",
157
+ "- Ignore pasted logs, code, and context blocks; title the request itself.",
158
+ "Call the set_title tool with the title.",
159
+ ].join("\n");
160
+
161
+ export const TASK_TITLE_TOOL_NAME = "set_title";
162
+
163
+ const TaskTitleZodSchema = z.object({ title: z.string().trim().min(1).max(200) });
164
+ const TaskTitleToolSchema = Type.Object({
165
+ title: Type.String({ minLength: 1, maxLength: 200, description: "The task title." }),
166
+ });
167
+
168
+ export interface GenerateTaskTitleOptions {
169
+ /** Full task prompt as stored on the task. */
170
+ task: string;
171
+ /** Credential lookup env. Defaults to `process.env`. */
172
+ env?: Record<string, string | undefined>;
173
+ /** Optional loopback context for the codex OAuth probe (see `resolveCredentials`). */
174
+ apiUrl?: string;
175
+ apiKey?: string;
176
+ signal?: AbortSignal;
177
+ /** Diagnostic tag forwarded to `completeStructured` logs. */
178
+ callerTag?: string;
179
+ // Test injection points:
180
+ _resolveCredentials?: typeof resolveCredentials;
181
+ _completeStructured?: typeof completeStructuredWithModel;
182
+ }
183
+
184
+ export type GenerateTaskTitleResult =
185
+ | { ok: true; title: string; model: string; kind: CredentialKind }
186
+ | { ok: false; reason: "short-task" | "no-credentials" | "all-models-failed" };
187
+
188
+ /**
189
+ * Generate a title for `task`. Never throws: a provider error moves on to the
190
+ * next candidate, and exhausting the list returns `{ ok: false }`.
191
+ */
192
+ export async function generateTaskTitle(
193
+ opts: GenerateTaskTitleOptions,
194
+ ): Promise<GenerateTaskTitleResult> {
195
+ const text = prepareTaskTextForTitle(opts.task);
196
+ if (text.length < TASK_TITLE_MIN_TASK_CHARS) return { ok: false, reason: "short-task" };
197
+
198
+ const env = opts.env ?? process.env;
199
+ const resolve = opts._resolveCredentials ?? resolveCredentials;
200
+ const complete = opts._completeStructured ?? completeStructuredWithModel;
201
+ const callerTag = opts.callerTag ?? "task-title";
202
+ const plan = buildTaskTitlePlan(env);
203
+
204
+ // One lookup per kind, on demand, so the codex OAuth probe (an HTTP call
205
+ // that can rotate a refresh token) runs only when its turn comes.
206
+ const credentialCache = new Map<CredentialKind, ResolvedCredential | null>();
207
+ const credentialFor = async (kind: CredentialKind): Promise<ResolvedCredential | null> => {
208
+ const cached = credentialCache.get(kind);
209
+ if (cached !== undefined) return cached;
210
+ const [cred] = await resolve({
211
+ env,
212
+ apiUrl: opts.apiUrl,
213
+ apiKey: opts.apiKey,
214
+ callerTag,
215
+ kinds: [kind],
216
+ limit: 1,
217
+ });
218
+ credentialCache.set(kind, cred ?? null);
219
+ return cred ?? null;
220
+ };
221
+
222
+ let sawCredential = false;
223
+ for (const group of plan) {
224
+ if (opts.signal?.aborted) break;
225
+ const cred = await credentialFor(group.kind);
226
+ if (!cred) continue;
227
+ sawCredential = true;
228
+ for (const model of group.models) {
229
+ if (opts.signal?.aborted) break;
230
+ const title = await attemptTitle(complete, {
231
+ cred,
232
+ model,
233
+ text,
234
+ env,
235
+ callerTag,
236
+ signal: opts.signal,
237
+ });
238
+ if (title) return { ok: true, title, model, kind: cred.kind };
239
+ }
240
+ }
241
+ return { ok: false, reason: sawCredential ? "all-models-failed" : "no-credentials" };
242
+ }
243
+
244
+ interface TitleAttempt {
245
+ cred: ResolvedCredential;
246
+ model: string;
247
+ text: string;
248
+ env: Record<string, string | undefined>;
249
+ callerTag: string;
250
+ signal?: AbortSignal;
251
+ }
252
+
253
+ /** One model call. `completeStructuredWithModel` swallows provider errors; a throw here is still just a miss. */
254
+ async function attemptTitle(
255
+ complete: typeof completeStructuredWithModel,
256
+ attempt: TitleAttempt,
257
+ ): Promise<string> {
258
+ try {
259
+ const result = await complete({
260
+ zodSchema: TaskTitleZodSchema,
261
+ toolSchema: TaskTitleToolSchema,
262
+ toolName: TASK_TITLE_TOOL_NAME,
263
+ toolDescription: "Record the title for this task.",
264
+ systemPrompt: TASK_TITLE_SYSTEM_PROMPT,
265
+ userPrompt: `Task request:\n\n${attempt.text}`,
266
+ env: attempt.env,
267
+ retries: 1,
268
+ signal: attempt.signal,
269
+ callerTag: `${attempt.callerTag}:${attempt.model}`,
270
+ _credentialOverride: { ...attempt.cred, modelDefault: attempt.model },
271
+ });
272
+ return result ? normalizeTaskTitle(result.data.title) : "";
273
+ } catch (error) {
274
+ // Provider errors can echo request fragments; scrub before logging.
275
+ console.error(
276
+ scrubSecrets(
277
+ `[task-title] ${attempt.model} threw: ${error instanceof Error ? error.message : String(error)}`,
278
+ ),
279
+ );
280
+ return "";
281
+ }
282
+ }
@@ -27,7 +27,9 @@
27
27
  */
28
28
  import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
29
29
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
30
+ import type { IncomingHttpHeaders } from "node:http";
30
31
  import path from "node:path";
32
+ import { isDevOrTestNodeEnv } from "./node-env";
31
33
 
32
34
  const ENV_SECRET = "PAGE_SESSION_SECRET";
33
35
  const ENV_SECRET_FILE = "PAGE_SESSION_SECRET_FILE";
@@ -336,6 +338,41 @@ export async function extractAndVerifyCookie(
336
338
  */
337
339
  const PAGE_SESSION_TTL_SECONDS = 3600;
338
340
 
341
+ const LOCAL_DEV_HOSTNAMES = new Set(["localhost", "127.0.0.1"]);
342
+
343
+ /** True only for a parsed `http:` URL whose hostname is exactly a loopback dev name. */
344
+ function isLocalHttpUrl(value: string): boolean {
345
+ try {
346
+ const url = new URL(value);
347
+ return url.protocol === "http:" && LOCAL_DEV_HOSTNAMES.has(url.hostname);
348
+ } catch {
349
+ return false;
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Decide the `dev` flag for `issuePageSessionCookie`. Shared by the launch
355
+ * endpoint (`src/http/pages.ts`) and the password flow on `/p/:id`
356
+ * (`src/http/pages-public.ts`) so both issue the same cookie.
357
+ *
358
+ * Fails closed: only an explicit development or test NODE_ENV can soften the
359
+ * cookie. Deployed images leave NODE_ENV unset and get `SameSite=None; Secure`.
360
+ * In dev, the request must come from `http://localhost` or `http://127.0.0.1`
361
+ * (parsed, so `http://localhost.evil.example` does not match). Without an
362
+ * Origin, the Host header decides; a missing Host counts as local.
363
+ * Anything else, including portless `https://*.localhost`, keeps
364
+ * `SameSite=None; Secure` so the cookie travels on cross-site fetches.
365
+ * Chrome treats localhost as a secure context, so Secure also works over http.
366
+ */
367
+ export function isLocalDevPageRequest(req: { headers: IncomingHttpHeaders }): boolean {
368
+ if (!isDevOrTestNodeEnv()) return false;
369
+ const origin = req.headers.origin ?? "";
370
+ if (origin !== "") return isLocalHttpUrl(origin);
371
+ const host = req.headers.host;
372
+ if (!host) return true;
373
+ return isLocalHttpUrl(`http://${host}`);
374
+ }
375
+
339
376
  /**
340
377
  * Mint a signed page-session token + build the `Set-Cookie` header value for
341
378
  * `pageId`. Shared by the bearer-authed launch endpoint (`src/http/pages.ts`)
@@ -27,7 +27,93 @@ You are Lead. Produce one digest covering workflows, schedule runs, agents, task
27
27
  Call `GET $MCP_BASE_URL/status` and read `status.automations`. List every automation whose state is `needs_setup`, its missing parameters/integrations, and its `fixUrl`. This is the first digest section and the first failure classification; it is setup work, not an automation failure.
28
28
 
29
29
  ### 1B. Workflows and schedules
30
- Run the same six-query set as `daily-workflow-health-audit` Phase 1 (hard-failed workflow runs, hard-failed schedule-spawned tasks, halted >24h runs, silent-empty-output completions, cron-didn't-fire, schedules with ≥3 consecutive errors — all against `workflow_runs` / `agent_tasks` / `scheduled_tasks` via `db-query`), plus:
30
+ Run these six failure-mode queries with `db-query`:
31
+
32
+ **1.** Hard-failed workflow runs (last 24h)
33
+
34
+ ```sql
35
+ SELECT wr.id, w.name AS workflowName, wr.status,
36
+ wr.finishedAt, wr.lastUpdatedAt,
37
+ SUBSTR(COALESCE(wr.error, ''), 1, 220) AS errSnippet
38
+ FROM workflow_runs wr
39
+ JOIN workflows w ON w.id = wr.workflowId
40
+ WHERE wr.status = 'failed'
41
+ AND datetime(COALESCE(wr.finishedAt, wr.lastUpdatedAt, wr.startedAt)) > datetime('now', '-24 hours')
42
+ ORDER BY wr.lastUpdatedAt DESC;
43
+ ```
44
+
45
+ **2.** Hard-failed schedule-spawned tasks (last 24h)
46
+
47
+ ```sql
48
+ SELECT t.id, s.name AS scheduleName, t.status,
49
+ SUBSTR(COALESCE(t.failureReason, ''), 1, 220) AS reasonSnippet,
50
+ SUBSTR(COALESCE(t.output, ''), 1, 220) AS outSnippet,
51
+ t.lastUpdatedAt
52
+ FROM agent_tasks t
53
+ LEFT JOIN scheduled_tasks s ON s.id = t.scheduleId
54
+ WHERE t.status = 'failed'
55
+ AND t.scheduleId IS NOT NULL
56
+ AND datetime(t.lastUpdatedAt) > datetime('now', '-24 hours')
57
+ ORDER BY t.lastUpdatedAt DESC;
58
+ ```
59
+
60
+ **3.** Halted >24h workflow runs (silent stuck)
61
+
62
+ ```sql
63
+ SELECT wr.id, w.name AS workflowName, wr.status, wr.lastUpdatedAt
64
+ FROM workflow_runs wr
65
+ JOIN workflows w ON w.id = wr.workflowId
66
+ WHERE wr.status IN ('running', 'waiting')
67
+ AND datetime(wr.lastUpdatedAt) < datetime('now', '-24 hours')
68
+ ORDER BY wr.lastUpdatedAt ASC;
69
+ ```
70
+
71
+ **4.** Silent: schedule-spawned task completed with empty/sentinel output
72
+
73
+ ```sql
74
+ SELECT t.id, s.name AS scheduleName, t.status,
75
+ SUBSTR(COALESCE(t.output, ''), 1, 220) AS outSnippet,
76
+ LENGTH(TRIM(COALESCE(t.output, ''))) AS outLen,
77
+ t.lastUpdatedAt
78
+ FROM agent_tasks t
79
+ LEFT JOIN scheduled_tasks s ON s.id = t.scheduleId
80
+ WHERE t.status = 'completed'
81
+ AND t.scheduleId IS NOT NULL
82
+ AND datetime(t.lastUpdatedAt) > datetime('now', '-24 hours')
83
+ AND (
84
+ t.output IS NULL
85
+ OR TRIM(t.output) = ''
86
+ OR TRIM(t.output) = '⚡ Running shell command'
87
+ OR LENGTH(TRIM(t.output)) < 10
88
+ )
89
+ ORDER BY t.lastUpdatedAt DESC;
90
+ ```
91
+
92
+ **5.** Cron didn't fire (nextRunAt in the past)
93
+
94
+ ```sql
95
+ SELECT s.id, s.name, s.cronExpression, s.lastRunAt, s.nextRunAt, s.consecutiveErrors,
96
+ SUBSTR(COALESCE(s.lastErrorMessage, ''), 1, 220) AS lastErrSnippet
97
+ FROM scheduled_tasks s
98
+ WHERE s.enabled = 1
99
+ AND s.scheduleType = 'recurring'
100
+ AND s.nextRunAt IS NOT NULL
101
+ AND datetime(s.nextRunAt) < datetime('now', '-1 hour')
102
+ ORDER BY s.nextRunAt ASC;
103
+ ```
104
+
105
+ **6.** Schedules with consecutive errors (defensive)
106
+
107
+ ```sql
108
+ SELECT s.id, s.name, s.cronExpression, s.consecutiveErrors, s.lastErrorAt,
109
+ SUBSTR(COALESCE(s.lastErrorMessage, ''), 1, 220) AS lastErrSnippet
110
+ FROM scheduled_tasks s
111
+ WHERE s.enabled = 1
112
+ AND s.consecutiveErrors >= 3
113
+ ORDER BY s.consecutiveErrors DESC;
114
+ ```
115
+
116
+ Plus:
31
117
  - Enabled/disabled counts: `SELECT enabled, COUNT(*) FROM scheduled_tasks GROUP BY enabled` and the workflow equivalent.
32
118
  - 7-day rollup, not just 24h: repeat the hard-failure and cron-didn't-fire queries with a `-7 days` window for a weekly trend line.
33
119
 
@@ -87,7 +173,7 @@ More than 3 qualify ⇒ post the 3 that matter and put the rest in the task outp
87
173
  `store-progress` with `status: "completed"`. **This is where the detail goes** — every count from Phase 1, the per-class failure breakdown, and the Slack message ts. The Slack post is the headline; the task output is the record. Cutting the post does not mean cutting the work.
88
174
 
89
175
  ## Anti-patterns
90
- - ❌ Modifying anything — this schedule reports, it doesn't fix (that's `daily-workflow-health-audit` for plumbing and `daily-compounding-reflection` for agent/skill/memory evolution).
176
+ - ❌ Modifying anything — this schedule reports, it doesn't fix (that's `daily-compounding-reflection` for agent/skill/memory evolution).
91
177
  - ❌ Folding the unclassified-failure bucket into "real defect" to make the number look more actionable than it is.
92
178
  - ❌ Narrating a zero. The all-clear line already covers `needs_setup` and integrations; only a non-verified integration or a real `needs_setup` automation earns its own line.
93
179
  - ❌ Exceeding 600 characters, or posting more than one message.
@@ -2,48 +2,24 @@
2
2
 
3
3
  Zero-config auto-update watchdog: compares the swarm's own running version against the latest published GitHub release of `desplega-ai/agent-swarm`, and flags the operator when an upgrade is available. No placeholders and no integration required — every install gets this by default.
4
4
 
5
- ## Schedule
6
-
7
- ```json
8
- {"cron":"0 9 * * *","timezone":"UTC","agentRole":"lead","enabled":true}
9
- ```
10
-
11
- ## Scheduled Task
12
-
13
- This schedule runs by default. It needs no repository clone and no integration — it only reads its own task metadata and calls the public GitHub API.
14
-
15
- Task Type: Daily Agent-Swarm Update Check
16
-
17
- You are Lead. Determine whether a newer `desplega-ai/agent-swarm` release is published than the version currently running on this install, and tell the operator if so.
18
-
19
- ## Phase 1 — Determine the running version
5
+ This is a script schedule: each fire runs the global `swarm-update-check` script directly, with no agent task in between. The script:
20
6
 
21
- Call `get-task-details` for THIS task's own id and read `task.swarmVersion` — the API server stamps every task with the `package.json` version it was running at task-creation time, so this is the version currently deployed on this install.
7
+ 1. Reads the running version from the API server's own `/health` route.
8
+ 2. Fetches `https://api.github.com/repos/desplega-ai/agent-swarm/releases/latest` once and reads `tag_name` and `html_url`.
9
+ 3. Compares the two as numeric `major.minor.patch`, never as strings (`"1.9.0" < "1.10.0"` is false as strings).
10
+ 4. Only when the latest release is newer, sends the lead one task to post the notice to its configured admin delivery channel (the in-app fallback if none is configured).
22
11
 
23
- If `swarmVersion` is missing or empty (an older install, or the field predates this schedule), complete with `output`: `"Unable to determine running version — swarmVersion not set on this task."` and stop. Do not guess a version.
12
+ Up to date, a missing running version (reported as `unknown`, never as up to date) and an unreachable GitHub API all end the run without any agent task. A failed GitHub call is reported once and never retried in a loop. The check never attempts the upgrade; `weekly-harness-upgrade-check` is the separate routine that bumps pinned harness versions inside the repo.
24
13
 
25
- ## Phase 2 — Fetch the latest published release
14
+ ## Schedule
26
15
 
27
- ```bash
28
- curl -fsSL https://api.github.com/repos/desplega-ai/agent-swarm/releases/latest
16
+ ```json
17
+ {
18
+ "cron": "0 9 * * *",
19
+ "timezone": "UTC",
20
+ "enabled": true,
21
+ "targetType": "script",
22
+ "scriptName": "swarm-update-check",
23
+ "scriptArgs": {}
24
+ }
29
25
  ```
30
-
31
- Read `.tag_name` (strip a leading `v` if present) and `.html_url`. If the request fails (network, rate limit, non-200), complete with `output`: `"Could not reach GitHub releases API: <error>"` and stop — do not retry in a loop.
32
-
33
- ## Phase 3 — Compare and act
34
-
35
- Compare the two versions as dotted numeric triples (major.minor.patch) — never as plain strings (`"1.9.0" < "1.10.0"` is false as strings).
36
-
37
- - **Latest <= running:** complete with `output`: `"Up to date: running <running>, latest published <latest>."` No further action.
38
- - **Latest > running:** raise it for the operator:
39
- 1. Post a short message to your configured admin delivery channel (or the in-app fallback if none is configured) naming the running version, the new version, and the release URL.
40
- 2. Complete `store-progress` with `status: "completed"` and `output`: `"Update available: running <running>, latest <latest> — <releaseUrl>"`.
41
-
42
- Do not attempt the upgrade yourself — this schedule only detects and reports. `weekly-harness-upgrade-check` is the separate routine that bumps pinned harness versions inside the repo; this schedule is about the agent-swarm release itself.
43
-
44
- ## Anti-patterns
45
-
46
- - ❌ Cloning the repo or reading `package.json` from disk — this schedule must work on any install, including ones where the API pod has no repo checkout.
47
- - ❌ String-comparing versions.
48
- - ❌ Treating a missing `swarmVersion` as "no update available" — it's "unknown", say so explicitly.
49
- - ❌ Retrying a failed GitHub API call in a loop.
@@ -133,7 +133,7 @@ Use `{ "$state": "/user/<field>" }` on a page for the read-only current-user bin
133
133
 
134
134
  ### Theming
135
135
 
136
- An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas — a lowercase slug validated by shape only. The preset catalog ships with the dashboard (`apps/ui/src/lib/themes.ts` + `theme-classics.ts` — update this list and the `app-upsert` tool description when it changes); current ids: `hive` (the stock look), the accent/field presets `meadow`, `iris`, `rose`, `cobalt`, `ember`, `carbon`, and the classic editor/platform presets `github`, `vscode`, `material`, `solarized`, `tokyo`, `monokai`, `gruvbox`, `catppuccin`. Action and destructive tones are never themed; status tones are themed ONLY by the classic presets (their identity includes a status palette — hue semantics stay fixed, success reads green and error reads red everywhere). An id the viewer's dashboard build does not know degrades to the dashboard's own theme, so unknown slugs are safe but pointless. Omit `theme` to inherit whatever theme the viewer runs; `"hive"` is an explicit reset to the stock look even inside a themed dashboard.
136
+ An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas: a lowercase slug validated by shape only. The preset catalog ships with the dashboard and lives in `src/themes/presets.ts` and `src/themes/classics.ts`. Update this list and the `app-upsert` tool description when it changes. Current ids: `hive` (the stock look), the accent/field presets `meadow`, `iris`, `rose`, `cobalt`, `ember`, `carbon`, `paper` (the warm editorial paper look), and the classic editor/platform presets `github`, `vscode`, `material`, `solarized`, `tokyo`, `monokai`, `gruvbox`, `catppuccin`. Action and destructive tones are never themed; status tones are themed ONLY by the classic presets (their identity includes a status palette: hue semantics stay fixed, success reads green and error reads red everywhere). An id the viewer's dashboard build does not know degrades to the dashboard's own theme, so unknown slugs are safe but pointless. Omit `theme` to inherit whatever theme the viewer runs; `"hive"` is an explicit reset to the stock look even inside a themed dashboard.
137
137
 
138
138
  Viewers can override the preset per app from the app's settings drawer; the override rides the reserved `$theme` key of the user-config values (accepted on every app, even without a declared `userConfig` schema, and never visible at `/user/...`). A present override always beats the definition's `theme` — even an unrecognized one, which degrades to the dashboard theme — so treat `theme` as the app's default styling, not a guarantee.
139
139
 
@@ -128,7 +128,7 @@ Use `{ "$state": "/user/<field>" }` on a page for the read-only current-user bin
128
128
 
129
129
  ### Theming
130
130
 
131
- An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas — a lowercase slug validated by shape only. The preset catalog ships with the dashboard (`apps/ui/src/lib/themes.ts` + `theme-classics.ts` — update this list and the `app-upsert` tool description when it changes); current ids: `hive` (the stock look), the accent/field presets `meadow`, `iris`, `rose`, `cobalt`, `ember`, `carbon`, and the classic editor/platform presets `github`, `vscode`, `material`, `solarized`, `tokyo`, `monokai`, `gruvbox`, `catppuccin`. Action and destructive tones are never themed; status tones are themed ONLY by the classic presets (their identity includes a status palette — hue semantics stay fixed, success reads green and error reads red everywhere). An id the viewer's dashboard build does not know degrades to the dashboard's own theme, so unknown slugs are safe but pointless. Omit `theme` to inherit whatever theme the viewer runs; `"hive"` is an explicit reset to the stock look even inside a themed dashboard.
131
+ An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas: a lowercase slug validated by shape only. The preset catalog ships with the dashboard and lives in `src/themes/presets.ts` and `src/themes/classics.ts`. Update this list and the `app-upsert` tool description when it changes. Current ids: `hive` (the stock look), the accent/field presets `meadow`, `iris`, `rose`, `cobalt`, `ember`, `carbon`, `paper` (the warm editorial paper look), and the classic editor/platform presets `github`, `vscode`, `material`, `solarized`, `tokyo`, `monokai`, `gruvbox`, `catppuccin`. Action and destructive tones are never themed; status tones are themed ONLY by the classic presets (their identity includes a status palette: hue semantics stay fixed, success reads green and error reads red everywhere). An id the viewer's dashboard build does not know degrades to the dashboard's own theme, so unknown slugs are safe but pointless. Omit `theme` to inherit whatever theme the viewer runs; `"hive"` is an explicit reset to the stock look even inside a themed dashboard.
132
132
 
133
133
  Viewers can override the preset per app from the app's settings drawer; the override rides the reserved `$theme` key of the user-config values (accepted on every app, even without a declared `userConfig` schema, and never visible at `/user/...`). A present override always beats the definition's `theme` — even an unrecognized one, which degrades to the dashboard theme — so treat `theme` as the app's default styling, not a guarantee.
134
134
 
@@ -80,6 +80,16 @@ Google Drive export, then preserve or reconstruct the structure explicitly.
80
80
  There is no `GET_DOCUMENT_MARKDOWN` tool; markdown exists on create/update, not
81
81
  on read.
82
82
 
83
+ ## Comments
84
+
85
+ Doc comments are a Drive feature, not a Docs one: there is no `GOOGLEDOCS_*`
86
+ comment slug. List them with `GOOGLEDRIVE_LIST_COMMENTS` (replies:
87
+ `GOOGLEDRIVE_LIST_REPLIES`) from the `googledrive` toolkit, so resolve the
88
+ user's `googledrive` connected account instead of their `googledocs` one.
89
+ Listing only works when the Drive read scopes are authorized on that account.
90
+ `GOOGLEDRIVE_CREATE_COMMENT` and the update/delete tools are write actions,
91
+ only on explicit request.
92
+
83
93
  ## Gotchas
84
94
 
85
95
  - Search returns Drive metadata, not document content — do a second
@@ -35,7 +35,7 @@ Two kinds of sections:
35
35
 
36
36
  0. Quiet check. Take the fast path when three things hold: every failed, stalled or reboot-interrupted task in the system status was already named in the previous heartbeat-checklist task's output (newest completed one via `get-tasks`); no mention has gone unanswered since the last heartbeat; and no tracked item in the task's runbook snapshot is at or past its date. On the fast path, run the two step 3 scripts. If they report nothing the previous heartbeat had not already triaged, complete with exactly one line, `Quiet. Same as <previousTaskId>: <N> failures (triaged), schedule-health <M>/<total>, controls ok.`, and skip steps 1, 2 and 4-7. A longer quiet output is a defect: no failure-set recap, no per-script bullets. Anything new means continue at step 1.
37
37
  1. Read the latest runbook. The snapshot in the task may be stale.
38
- 2. Prune first. Check every tracked item against its lift trigger. Remove resolved, stale, and past-date items. A trigger tied to a pull request ("lift when #N merges") fires silently: read the state of every PR a trigger names. Merged means the lift fired, so act on it now. Closed without merge means the item is dead, so drop it.
38
+ 2. Prune first. Check every tracked item against its lift trigger. Remove resolved, stale, and past-date items. A trigger tied to a pull request ("lift when #N merges") fires silently: read the state of every PR a trigger names. Merged means the lift fired, so act on it now. Closed without merge means the item is dead, so drop it. A PR's `mergeable` field reads `null` while the host is still computing it: `null` is unknown, never clean, so re-read until a value comes back and never treat it as a cleared blocker or as ready to merge.
39
39
  3. Run the seeded scripts: `script-run` with name `schedule-health`, then `task-failure-audit`, both with `args: { days: 1, publishPage: false }`. They report failing schedules and failure clusters. Check any other standing order in the runbook yourself.
40
40
  4. Read the system status and the script results for stalled tasks, idle workers next to open work, and anomalies.
41
41
  5. Reboot-interrupted failures: the failure reason "Auto-failed by reboot sweep: worker session not found after server restart" means a restart cut the task off. For each one: `get-task-details` on the task, confirm a retry task tagged `reboot-retry` exists and moves, recreate the task when no retry exists and the work is still needed. Heartbeat and triage tasks get no retry. A worker crash outside a restart ("worker session not found" or "worker session heartbeat is stale" from the stall sweep) normally leaves a `superseded` task with a `resume` child instead; check that the child moves. None of these are "expected cleanup".
@@ -4,7 +4,7 @@
4
4
  "displayName": "Pages",
5
5
  "slug": "pages",
6
6
  "title": "Pages",
7
- "description": "Publish human-readable task outputs as DB-backed shareable pages (HTML or JSON) via `create_page` — no server, no tunnel. Covers auth modes, share URLs, versioning, the injected browser SDK, the `<swarm-diff>` primitive, print/PDF export, limits, and the minimalist taste baseline plus report-density layer every page should follow.",
7
+ "description": "Publish human-readable task outputs as DB-backed shareable pages (HTML or JSON) via `create_page`, with no server and no tunnel. Covers auth modes, share URLs, versioning, the injected browser SDK, the `<swarm-diff>` web component, print/PDF export, and limits. Also covers the swarm design system every page should use: theme tokens, `swarm-*` primitives, Tailwind v4 utilities, theme presets, dark mode, and the minimalist taste and report-density rules.",
8
8
  "version": "2.0.0",
9
9
  "category": "skills",
10
10
  "placeholders": [],