@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,334 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import {
5
+ advanceIdentityBaselines,
6
+ bootIdentityBaselines,
7
+ CLAUDE_MD_LINEAGE_PATH,
8
+ CLAUDE_MD_PATH,
9
+ collectProfilePayloads,
10
+ contentSha256,
11
+ type FileReader,
12
+ HEARTBEAT_MD_PATH,
13
+ IDENTITY_BASELINES_PATH,
14
+ IDENTITY_MD_PATH,
15
+ type ProfileFileIO,
16
+ SETUP_SCRIPT_PATH,
17
+ SOUL_MD_PATH,
18
+ syncProfileFilesToServer,
19
+ TOOLS_MD_PATH,
20
+ WORKSPACE_CLAUDE_MD_PATH,
21
+ } from "../commands/profile-sync";
22
+ import {
23
+ type SwarmHooksConfig,
24
+ syncIdentityFilesToServer,
25
+ syncSetupScriptToServer,
26
+ } from "../providers/pi-mono-extension";
27
+
28
+ // A file the agent never touched still holds the copy written at boot. A sync
29
+ // that sends it anyway writes that stale copy over any DB-side edit made since
30
+ // (Lead's update-profile, a nightly profile edit). These tests hold the DB
31
+ // edit in a fake profile API and check that it survives the agent's sync.
32
+
33
+ const BOOT_IDENTITY = `# Identity\n\n${"boot ".repeat(120)}\n\n## Self-Evolution\n\nold section\n`;
34
+ const EDITED_IDENTITY = `# Identity\n\n${"boot ".repeat(120)}\n`;
35
+
36
+ /** In-memory stand-in for the worker's workspace and /tmp baselines. */
37
+ function memoryIO(files: Record<string, string>): ProfileFileIO & {
38
+ files: Record<string, string>;
39
+ } {
40
+ return {
41
+ files,
42
+ readFile: async (path) => files[path],
43
+ writeFile: async (path, content) => {
44
+ files[path] = content;
45
+ },
46
+ baselinesLockPath: join(tmpdir(), `identity-baselines-${crypto.randomUUID()}.lock`),
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Holds each read of the baselines file until a second read arrives (or a
52
+ * short timeout), after both have captured the file as it was: the
53
+ * interleaving in which two unserialized updates drop one another's hashes.
54
+ */
55
+ function pairBaselineReads(io: ReturnType<typeof memoryIO>): typeof io {
56
+ let waiting: (() => void) | null = null;
57
+ return {
58
+ ...io,
59
+ readFile: async (path) => {
60
+ const content = io.files[path];
61
+ if (path !== IDENTITY_BASELINES_PATH) return content;
62
+ if (waiting) {
63
+ const partner = waiting;
64
+ waiting = null;
65
+ partner();
66
+ return content;
67
+ }
68
+ await new Promise<void>((resolve) => {
69
+ waiting = resolve;
70
+ setTimeout(() => {
71
+ if (waiting === resolve) waiting = null;
72
+ resolve();
73
+ }, 300);
74
+ });
75
+ return content;
76
+ },
77
+ };
78
+ }
79
+
80
+ function baselinesOf(io: ReturnType<typeof memoryIO>): Record<string, string> {
81
+ return JSON.parse(io.files[IDENTITY_BASELINES_PATH] ?? "{}");
82
+ }
83
+
84
+ /** The workspace right after runner boot: files and baselines from the DB. */
85
+ function bootedWorkspace(profile: Record<string, string>) {
86
+ const baselines: Record<string, string> = {};
87
+ for (const [field, content] of Object.entries(profile)) {
88
+ baselines[field] = contentSha256(content);
89
+ }
90
+ return memoryIO({
91
+ [IDENTITY_MD_PATH]: profile.identityMd ?? "",
92
+ [IDENTITY_BASELINES_PATH]: JSON.stringify(baselines),
93
+ });
94
+ }
95
+
96
+ describe("profile sync never writes an untouched file over a DB edit", () => {
97
+ let db: Record<string, string> = {};
98
+ let server: ReturnType<typeof Bun.serve>;
99
+ let config: SwarmHooksConfig;
100
+
101
+ beforeAll(() => {
102
+ server = Bun.serve({
103
+ port: 0,
104
+ async fetch(req) {
105
+ if (req.method !== "PUT") return new Response("not found", { status: 404 });
106
+ const body = (await req.json()) as Record<string, string>;
107
+ for (const [field, value] of Object.entries(body)) {
108
+ if (field !== "changeSource") db[field] = value;
109
+ }
110
+ return Response.json({ ok: true });
111
+ },
112
+ });
113
+ config = {
114
+ apiUrl: `http://localhost:${server.port}`,
115
+ apiKey: "test-key",
116
+ agentId: "agent-1",
117
+ taskId: "task-1",
118
+ isLead: false,
119
+ };
120
+ });
121
+
122
+ afterAll(() => {
123
+ server.stop(true);
124
+ });
125
+
126
+ test("opencode/pi session end keeps a DB edit made during the session when IDENTITY.md is untouched", async () => {
127
+ db = { identityMd: BOOT_IDENTITY };
128
+ const io = bootedWorkspace({ identityMd: BOOT_IDENTITY });
129
+
130
+ // Mid-session DB edit; the agent never touches /workspace/IDENTITY.md.
131
+ db.identityMd = EDITED_IDENTITY;
132
+
133
+ await syncIdentityFilesToServer(config, "session_sync", undefined, io);
134
+
135
+ expect(db.identityMd).toBe(EDITED_IDENTITY);
136
+ });
137
+
138
+ test("a synced local edit advances the baseline, so a later DB edit survives the next session end", async () => {
139
+ db = { identityMd: BOOT_IDENTITY };
140
+ const io = bootedWorkspace({ identityMd: BOOT_IDENTITY });
141
+ const agentEdit = `${BOOT_IDENTITY}\n## Learned\n\nagent edit\n`;
142
+
143
+ io.files[IDENTITY_MD_PATH] = agentEdit;
144
+ await syncIdentityFilesToServer(config, "self_edit", undefined, io);
145
+ expect(db.identityMd).toBe(agentEdit);
146
+
147
+ db.identityMd = EDITED_IDENTITY;
148
+ await syncIdentityFilesToServer(config, "session_sync", undefined, io);
149
+
150
+ expect(db.identityMd).toBe(EDITED_IDENTITY);
151
+ });
152
+
153
+ test("a real local edit still syncs", async () => {
154
+ db = { identityMd: BOOT_IDENTITY };
155
+ const io = bootedWorkspace({ identityMd: BOOT_IDENTITY });
156
+ io.files[IDENTITY_MD_PATH] = EDITED_IDENTITY;
157
+
158
+ await syncIdentityFilesToServer(config, "session_sync", undefined, io);
159
+
160
+ expect(db.identityMd).toBe(EDITED_IDENTITY);
161
+ });
162
+
163
+ test("an untouched start-up.sh does not overwrite a DB setupScript edit", async () => {
164
+ db = { setupScript: "echo boot" };
165
+ const io = memoryIO({
166
+ [SETUP_SCRIPT_PATH]: "#!/bin/bash\necho boot\n",
167
+ [IDENTITY_BASELINES_PATH]: JSON.stringify({ setupScript: contentSha256("echo boot") }),
168
+ });
169
+ db.setupScript = "echo edited";
170
+
171
+ await syncSetupScriptToServer(config, "session_sync", io);
172
+
173
+ expect(db.setupScript).toBe("echo edited");
174
+ });
175
+
176
+ const runnerSync = (
177
+ io: ProfileFileIO,
178
+ opts: Partial<Parameters<typeof syncProfileFilesToServer>[0]>,
179
+ ) =>
180
+ syncProfileFilesToServer({
181
+ agentId: config.agentId,
182
+ apiUrl: config.apiUrl,
183
+ apiKey: config.apiKey,
184
+ changeSource: "session_sync",
185
+ io,
186
+ ...opts,
187
+ });
188
+
189
+ test("an accepted workspace CLAUDE.md edit advances its baseline, so a later DB edit survives the next session end", async () => {
190
+ const boot = "# CLAUDE.md\n\nboot rules\n";
191
+ db = { claudeMd: boot };
192
+ const io = memoryIO({
193
+ [WORKSPACE_CLAUDE_MD_PATH]: boot,
194
+ [IDENTITY_BASELINES_PATH]: JSON.stringify({ claudeMd: contentSha256(boot) }),
195
+ });
196
+ const sync = () =>
197
+ runnerSync(io, { fields: ["claude"], claudeMdPath: WORKSPACE_CLAUDE_MD_PATH });
198
+
199
+ // Session 1: a codex/opencode agent edits /workspace/CLAUDE.md.
200
+ const agentEdit = `${boot}\n## Learned\n\nagent rule\n`;
201
+ io.files[WORKSPACE_CLAUDE_MD_PATH] = agentEdit;
202
+ await sync();
203
+ expect(db.claudeMd).toBe(agentEdit);
204
+
205
+ // Lead edits the DB; session 2 never touches the file.
206
+ db.claudeMd = "# CLAUDE.md\n\nlead rules\n";
207
+ await sync();
208
+
209
+ expect(db.claudeMd).toBe("# CLAUDE.md\n\nlead rules\n");
210
+ });
211
+
212
+ test("an accepted personal CLAUDE.md sync keeps the hook's lineage and the boot baseline", async () => {
213
+ const boot = "# CLAUDE.md\n\nboot rules\n";
214
+ const lineage = JSON.stringify({ written: contentSha256(boot), base: contentSha256(boot) });
215
+ const bootBaselines = JSON.stringify({ claudeMd: contentSha256(boot) });
216
+ db = { claudeMd: boot };
217
+ const io = memoryIO({
218
+ [CLAUDE_MD_PATH]: `${boot}\nagent rule\n`,
219
+ [CLAUDE_MD_LINEAGE_PATH]: lineage,
220
+ [IDENTITY_BASELINES_PATH]: bootBaselines,
221
+ });
222
+
223
+ await runnerSync(io, {
224
+ fields: ["claude"],
225
+ claudeMdPath: CLAUDE_MD_PATH,
226
+ claudeMdLock: { path: join(tmpdir(), `claude-md-${crypto.randomUUID()}.lock`) },
227
+ });
228
+
229
+ expect(db.claudeMd).toBe(`${boot}\nagent rule\n`);
230
+ expect(db.expectedHashes).toEqual({ claudeMd: contentSha256(boot) });
231
+ expect(io.files[CLAUDE_MD_LINEAGE_PATH]).toBe(lineage);
232
+ expect(io.files[IDENTITY_BASELINES_PATH]).toBe(bootBaselines);
233
+ });
234
+
235
+ test("two concurrent baseline updates both persist their hashes", async () => {
236
+ const io = memoryIO({
237
+ [IDENTITY_BASELINES_PATH]: JSON.stringify({ soulMd: contentSha256("soul") }),
238
+ });
239
+ const paired = pairBaselineReads(io);
240
+
241
+ await Promise.all([
242
+ advanceIdentityBaselines({ identityMd: "identity, edited" }, paired),
243
+ advanceIdentityBaselines({ setupScript: "echo edited" }, paired),
244
+ ]);
245
+
246
+ expect(baselinesOf(io)).toEqual({
247
+ soulMd: contentSha256("soul"),
248
+ identityMd: contentSha256("identity, edited"),
249
+ setupScript: contentSha256("echo edited"),
250
+ });
251
+ });
252
+
253
+ test("concurrent runner and pi syncs both advance their baselines, so neither file is re-sent over a later DB edit", async () => {
254
+ db = { identityMd: BOOT_IDENTITY, setupScript: "echo boot" };
255
+ const io = bootedWorkspace({ identityMd: BOOT_IDENTITY });
256
+ io.files[IDENTITY_BASELINES_PATH] = JSON.stringify({
257
+ identityMd: contentSha256(BOOT_IDENTITY),
258
+ setupScript: contentSha256("echo boot"),
259
+ });
260
+ io.files[IDENTITY_MD_PATH] = EDITED_IDENTITY;
261
+ io.files[SETUP_SCRIPT_PATH] = "#!/bin/bash\necho edited\n";
262
+ const paired = pairBaselineReads(io);
263
+
264
+ // The runner's session-end sync races the pi extension's on-edit sync.
265
+ await Promise.all([
266
+ runnerSync(paired, { fields: ["identity"] }),
267
+ syncSetupScriptToServer(config, "self_edit", paired),
268
+ ]);
269
+ expect(db).toEqual({ identityMd: EDITED_IDENTITY, setupScript: "echo edited" });
270
+
271
+ db = { identityMd: "lead identity", setupScript: "echo lead" };
272
+ await runnerSync(io, { fields: ["identity", "setup"] });
273
+ await syncIdentityFilesToServer(config, "session_sync", undefined, io);
274
+ await syncSetupScriptToServer(config, "session_sync", io);
275
+
276
+ expect(db).toEqual({ identityMd: "lead identity", setupScript: "echo lead" });
277
+ });
278
+
279
+ test("an empty HEARTBEAT.md that survives a restart is not sent over a later DB edit", async () => {
280
+ // Boot after a restart: the DB value is empty, so the runner leaves the
281
+ // surviving empty file in place and records the boot baselines.
282
+ db = { heartbeatMd: "" };
283
+ const io = memoryIO({ [HEARTBEAT_MD_PATH]: "" });
284
+ io.files[IDENTITY_BASELINES_PATH] = JSON.stringify(
285
+ bootIdentityBaselines({ heartbeatMd: db.heartbeatMd }, undefined),
286
+ );
287
+
288
+ db.heartbeatMd = "- check the queue";
289
+ await runnerSync(io, { fields: ["identity"] });
290
+ expect(db.heartbeatMd).toBe("- check the queue");
291
+
292
+ // A real edit of the empty file still syncs.
293
+ io.files[HEARTBEAT_MD_PATH] = "- agent checklist";
294
+ await runnerSync(io, { fields: ["identity"] });
295
+ expect(db.heartbeatMd).toBe("- agent checklist");
296
+ });
297
+ });
298
+
299
+ describe("collectProfilePayloads (claude hook + runner)", () => {
300
+ const reader =
301
+ (files: Record<string, string>): FileReader =>
302
+ async (path) =>
303
+ files[path];
304
+
305
+ test("Lead's self_edit of HEARTBEAT.md does not resend a stale IDENTITY.md", async () => {
306
+ const files = reader({
307
+ [SOUL_MD_PATH]: BOOT_IDENTITY,
308
+ [IDENTITY_MD_PATH]: BOOT_IDENTITY,
309
+ [TOOLS_MD_PATH]: "tools",
310
+ [HEARTBEAT_MD_PATH]: "heartbeat, edited",
311
+ [IDENTITY_BASELINES_PATH]: JSON.stringify({
312
+ soulMd: contentSha256(BOOT_IDENTITY),
313
+ identityMd: contentSha256(BOOT_IDENTITY),
314
+ toolsMd: contentSha256("tools"),
315
+ heartbeatMd: contentSha256("heartbeat"),
316
+ }),
317
+ });
318
+
319
+ const payloads = await collectProfilePayloads(["identity"], "self_edit", files);
320
+
321
+ expect(payloads.map((payload) => payload.body)).toEqual([
322
+ { heartbeatMd: "heartbeat, edited", changeSource: "self_edit" },
323
+ ]);
324
+ });
325
+
326
+ test("session_sync skips an untouched start-up.sh", async () => {
327
+ const files = reader({
328
+ [SETUP_SCRIPT_PATH]: "#!/bin/bash\necho boot\n",
329
+ [IDENTITY_BASELINES_PATH]: JSON.stringify({ setupScript: contentSha256("echo boot") }),
330
+ });
331
+
332
+ expect(await collectProfilePayloads(["setup"], "session_sync", files)).toEqual([]);
333
+ });
334
+ });
@@ -439,7 +439,7 @@ describe("postProfileUpdate (non-2xx is surfaced, not swallowed)", () => {
439
439
  new Response("boom", { status: 500, statusText: "Server Error" })) as typeof fetch;
440
440
  try {
441
441
  // Must resolve (non-fatal), not reject.
442
- await expect(postProfileUpdate({ ...opts, fetchImpl }, payload)).resolves.toBeUndefined();
442
+ await expect(postProfileUpdate({ ...opts, fetchImpl }, payload)).resolves.toBe(false);
443
443
  expect(warnSpy).toHaveBeenCalledTimes(1);
444
444
  const msg = String(warnSpy.mock.calls[0]?.[0]);
445
445
  expect(msg).toContain("setup sync failed");
@@ -455,7 +455,7 @@ describe("postProfileUpdate (non-2xx is surfaced, not swallowed)", () => {
455
455
  throw new Error("network down");
456
456
  }) as typeof fetch;
457
457
  try {
458
- await expect(postProfileUpdate({ ...opts, fetchImpl }, payload)).resolves.toBeUndefined();
458
+ await expect(postProfileUpdate({ ...opts, fetchImpl }, payload)).resolves.toBe(false);
459
459
  expect(warnSpy).toHaveBeenCalledTimes(1);
460
460
  expect(String(warnSpy.mock.calls[0]?.[0])).toContain("setup sync errored");
461
461
  } finally {
@@ -634,27 +634,23 @@ describe("collectProfilePayloads (baseline integration)", () => {
634
634
  expect(payloads[0]?.body.identityMd).toBeUndefined();
635
635
  });
636
636
 
637
- test("self_edit bypasses baselines (agent explicitly changed the file)", async () => {
638
- const identityContent = LONG;
639
-
637
+ test("self_edit skips the identity files the agent did not edit", async () => {
638
+ // An edit to one file triggers a sync of all of them; the untouched ones
639
+ // still hold the boot-time copy, which may predate a DB-side edit.
640
640
  const files = reader({
641
- [SOUL_MD_PATH]: identityContent,
642
- [IDENTITY_MD_PATH]: identityContent,
643
- [TOOLS_MD_PATH]: "tools",
641
+ [SOUL_MD_PATH]: LONG,
642
+ [IDENTITY_MD_PATH]: LONG,
643
+ [TOOLS_MD_PATH]: "edited tools",
644
644
  [IDENTITY_BASELINES_PATH]: JSON.stringify({
645
- soulMd: contentSha256(identityContent),
646
- identityMd: contentSha256(identityContent),
645
+ soulMd: contentSha256(LONG),
646
+ identityMd: contentSha256(LONG),
647
647
  toolsMd: contentSha256("tools"),
648
648
  }),
649
649
  });
650
650
 
651
651
  const payloads = await collectProfilePayloads(["identity"], "self_edit", files);
652
- expect(payloads).toHaveLength(3);
653
- // self_edit should include ALL files regardless of baselines, independently.
654
652
  expect(payloads.map((payload) => payload.body)).toEqual([
655
- { soulMd: identityContent, changeSource: "self_edit" },
656
- { identityMd: identityContent, changeSource: "self_edit" },
657
- { toolsMd: "tools", changeSource: "self_edit" },
653
+ { toolsMd: "edited tools", changeSource: "self_edit" },
658
654
  ]);
659
655
  });
660
656
 
@@ -156,6 +156,22 @@ const CASES: Array<{
156
156
  uses: ["COVERING INDEX idx_session_summaries_source (source=?)"],
157
157
  revert: { dropIndex: "idx_session_summaries_source" },
158
158
  },
159
+ {
160
+ // A user's task count hides other users' sessions. Both steps of that
161
+ // walk stay in an index (migration 262) instead of reading task rows.
162
+ name: "getTasksCount readableBy, root step",
163
+ match: /COUNT/,
164
+ run: () => getTasksCount({ status: "in_progress", readableBy: { userId: "viewer-1" } }),
165
+ uses: ["SEARCH r USING COVERING INDEX idx_agent_tasks_session_owner (scheduleId=?)"],
166
+ revert: { dropIndex: "idx_agent_tasks_session_owner" },
167
+ },
168
+ {
169
+ name: "getTasksCount readableBy, recursive step",
170
+ match: /COUNT/,
171
+ run: () => getTasksCount({ status: "in_progress", readableBy: { userId: "viewer-1" } }),
172
+ uses: ["SEARCH c USING COVERING INDEX idx_agent_tasks_parentTaskId_id (parentTaskId=?)"],
173
+ revert: { dropIndex: "idx_agent_tasks_parentTaskId_id" },
174
+ },
159
175
  {
160
176
  // Few hits: the page reads the agent_tasks_fts candidates by rowid. The
161
177
  // control is the old `task LIKE '%q%'`, which scans every task body.
@@ -221,6 +237,17 @@ describe("query audit plans without sqlite_stat1", () => {
221
237
  });
222
238
  }
223
239
 
240
+ test("the default task count scans the filter index, not the task rows", async () => {
241
+ // The heartbeat filter is a NOT IN and a NOT LIKE, so the count scans.
242
+ // Migration 263 lets it scan the narrow index instead of every task body.
243
+ const count = await capturedSql(/COUNT/, () =>
244
+ getTasksCount({ readableBy: { userId: "viewer-1" } }),
245
+ );
246
+ const uses = ["SCAN agent_tasks USING COVERING INDEX idx_agent_tasks_list_filter"];
247
+ expect(missing(plan(count), uses)).toEqual([]);
248
+ expect(missing(planWithoutIndex(count, "idx_agent_tasks_list_filter"), uses)).not.toEqual([]);
249
+ });
250
+
224
251
  test("task search with many hits pages by lastUpdatedAt and counts from the index", async () => {
225
252
  await getDbClient().transaction(async (tx) => {
226
253
  for (let i = 0; i < 501; i++) {