@desplega.ai/agent-swarm 1.173.0 → 2.1.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 (511) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-kr4abrsk.js} +17 -16
  3. package/dist/{actions-sgeyv08k.js → actions-eh4g6w2r.js} +39 -34
  4. package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-7h7wdt8q.js} +8 -7
  5. package/dist/{app-km9qnv2f.js → app-7k8s9w5p.js} +18 -14
  6. package/dist/{assistant-5r8tcvvd.js → assistant-wswt2y7p.js} +40 -35
  7. package/dist/{boot-reembed-16rv9843.js → boot-reembed-9apm9qw6.js} +10 -9
  8. package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-whzbdthj.js} +10 -9
  9. package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-ndzmvmgt.js} +11 -10
  10. package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-e9sta0yt.js} +16 -13
  11. package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-4mqd3r6r.js} +19 -18
  12. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-9wswb52m.js} +7 -5
  13. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-tpe1effx.js} +6 -4
  14. package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-q49ghmh9.js} +12402 -11850
  15. package/dist/{cli-ne7smj1b.js → cli-01xvj1rq.js} +10 -10
  16. package/dist/{cli-nwrdx840.js → cli-035vekcw.js} +3 -3
  17. package/dist/{cli-9xf7fdtp.js → cli-0pd8hzhc.js} +29 -6
  18. package/dist/{cli-tmhsxhb8.js → cli-0veb92a3.js} +28 -6
  19. package/dist/{cli-c3rk1v0x.js → cli-10jesr25.js} +3 -3
  20. package/dist/{cli-6thk4jz3.js → cli-1y7yywmj.js} +6 -6
  21. package/dist/{cli-6r2f7edk.js → cli-20krdhz5.js} +47 -19
  22. package/dist/{cli-rfs4vddv.js → cli-29rja109.js} +39 -20
  23. package/dist/cli-2m1ktfzz.js +17795 -0
  24. package/dist/{cli-na2pxe4f.js → cli-2pwa0q4d.js} +15 -4
  25. package/dist/{cli-7a93cv8c.js → cli-4mengw46.js} +441 -43
  26. package/dist/{cli-94b48jhk.js → cli-5twdke5x.js} +16 -14
  27. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  28. package/dist/cli-6cvfxs8r.js +47 -0
  29. package/dist/{cli-w1apjecb.js → cli-711vwbxn.js} +2 -2
  30. package/dist/{cli-r4fqfpwf.js → cli-78vv7446.js} +50 -27
  31. package/dist/{cli-srqq3gc5.js → cli-7n6s5man.js} +5 -5
  32. package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
  33. package/dist/{cli-2bw3w47j.js → cli-8wwxw8a3.js} +1 -1
  34. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  35. package/dist/{cli-ywm1azg9.js → cli-9jzdj90z.js} +8 -4
  36. package/dist/cli-9traj3dn.js +638 -0
  37. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  38. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  39. package/dist/cli-cvv9k0hh.js +10143 -0
  40. package/dist/{cli-anzdk0z4.js → cli-d9286m9h.js} +2 -2
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/cli-f527ce74.js +781 -0
  43. package/dist/{cli-gmdajfw5.js → cli-gxzkg1de.js} +5020 -1729
  44. package/dist/{cli-451ks6aw.js → cli-h1arqn31.js} +1 -1
  45. package/dist/cli-hjwmhcg1.js +10622 -0
  46. package/dist/{cli-jpc4r224.js → cli-hqr88ew6.js} +19 -3
  47. package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
  48. package/dist/{cli-cd0hv9nh.js → cli-j67mh2vg.js} +2 -2
  49. package/dist/cli-jta2eyzc.js +619 -0
  50. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  51. package/dist/cli-kceah1eh.js +92 -0
  52. package/dist/{cli-d603qf86.js → cli-ksphgh48.js} +10 -8
  53. package/dist/{cli-3nxdmjrc.js → cli-mgz4nbgg.js} +4 -4
  54. package/dist/{cli-saqyage0.js → cli-mz5as5ha.js} +179 -27
  55. package/dist/cli-n2wq4j7m.js +6985 -0
  56. package/dist/{cli-ppy4nnnh.js → cli-n8ndw8j7.js} +2 -2
  57. package/dist/{cli-1w0vj3gw.js → cli-naqzr17j.js} +7 -7
  58. package/dist/{cli-0a7mm3zp.js → cli-nm1p8jfr.js} +25 -21
  59. package/dist/{cli-wrh08zjd.js → cli-p3zbc1rw.js} +5 -18
  60. package/dist/{cli-hsem16hb.js → cli-pe05f8yk.js} +29 -6
  61. package/dist/{cli-5wpw4rab.js → cli-qmzsbkvy.js} +5 -5
  62. package/dist/{cli-bv2etw2y.js → cli-qnm4e9e4.js} +99 -590
  63. package/dist/{cli-1x7da0de.js → cli-qqy4q48b.js} +8 -8
  64. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  65. package/dist/{cli-5er5gjbm.js → cli-r35rw5de.js} +15 -15
  66. package/dist/{cli-v3zhnxsb.js → cli-r610p9bs.js} +2 -2
  67. package/dist/{cli-7jykv7ef.js → cli-rc6pf5kv.js} +1 -1
  68. package/dist/{cli-x119kdba.js → cli-rdxm77k3.js} +1 -1
  69. package/dist/cli-rhs9pz33.js +294 -0
  70. package/dist/{cli-0p3enk35.js → cli-s69nfyeh.js} +9 -1
  71. package/dist/{cli-0kxf81jj.js → cli-sawv63e8.js} +2 -2
  72. package/dist/{cli-e3pmyt39.js → cli-sg19gbf0.js} +1 -1
  73. package/dist/{cli-d161g69q.js → cli-shk7r5cs.js} +57 -6
  74. package/dist/{cli-7pz3b7x5.js → cli-sksetb2q.js} +36 -1
  75. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  76. package/dist/{cli-db3m6zdt.js → cli-t02z59f2.js} +1 -1
  77. package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
  78. package/dist/{cli-s8z6x4b4.js → cli-v7g551te.js} +225 -113
  79. package/dist/{cli-rfz2ve55.js → cli-vgqzp4em.js} +3341 -955
  80. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  81. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  82. package/dist/cli-wfnemr1t.js +86 -0
  83. package/dist/cli-wmgrkscj.js +23254 -0
  84. package/dist/{cli-qm1448f9.js → cli-wms6x9db.js} +8 -8
  85. package/dist/{cli-tadfgd0t.js → cli-x1r545x8.js} +33 -4
  86. package/dist/{cli-xc7p7s3g.js → cli-xczsgshn.js} +6 -6
  87. package/dist/{cli-fmhj1ehj.js → cli-y3167wt1.js} +882 -271
  88. package/dist/{cli-r0byd61h.js → cli-yjmqpxt3.js} +17 -16
  89. package/dist/{cli-81r1wjyv.js → cli-z780ec7c.js} +1 -1
  90. package/dist/{cli-phcqp1b9.js → cli-zm9t2vde.js} +2 -2
  91. package/dist/cli.js +34 -49
  92. package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-4z16v9n0.js} +15 -14
  93. package/dist/{codex-login-841kv5fk.js → codex-login-pkepy2j1.js} +3 -2
  94. package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-rvms9y2x.js} +15 -14
  95. package/dist/{commands-z8fq9qna.js → commands-2a9rtyat.js} +11 -10
  96. package/dist/{controller-hq5ggpcp.js → controller-3k3madbn.js} +5 -4
  97. package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-v9yn8zb9.js} +42 -37
  98. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-98gbhyzn.js} +7 -6
  99. package/dist/{db-qfpq4bt7.js → db-eywwsnjw.js} +30 -9
  100. package/dist/{db-yyhqqrbf.js → db-ncypk9np.js} +12 -11
  101. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-zeq8b9gz.js} +3 -2
  102. package/dist/{dispatcher-x0x7qfcq.js → dispatcher-w94kc575.js} +38 -33
  103. package/dist/{docker-f503k9p0.js → docker-b1e4cqab.js} +3 -2
  104. package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-47ztej36.js} +7 -6
  105. package/dist/{e2b-66xra4az.js → e2b-bbt8ey45.js} +4 -3
  106. package/dist/{e2b-xwhyj8cw.js → e2b-dp804sen.js} +4 -3
  107. package/dist/{event-bus-vjtv82gm.js → event-bus-j2jdg3qb.js} +3 -2
  108. package/dist/{external-channel-h1fjecwe.js → external-channel-zrkg8ar9.js} +11 -10
  109. package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
  110. package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
  111. package/dist/{grok-adapter-e7mr287e.js → grok-adapter-s9ncp9vy.js} +18 -17
  112. package/dist/{handlers-znb9n7d4.js → handlers-kqftvjgw.js} +41 -36
  113. package/dist/{heartbeat-bm4qkn8d.js → heartbeat-9q96p8v9.js} +43 -38
  114. package/dist/{hook-254r4mza.js → hook-56qe10dp.js} +11 -23
  115. package/dist/{hook-xaa3q80s.js → hook-yy6rw42k.js} +12 -11
  116. package/dist/{http-3dgrgp8y.js → http-r2dnb8f8.js} +2411 -275
  117. package/dist/{index-fx3jqq1e.js → index-3gtmkhc6.js} +38 -33
  118. package/dist/{index-bdsqa799.js → index-3k5hkz7r.js} +43 -38
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-g2byveez.js → index-5e101240.js} +38 -33
  121. package/dist/{index-2ybk7khy.js → index-5wyfjc2c.js} +845 -683
  122. package/dist/index-9gw58n4k.js +193 -0
  123. package/dist/index-9j87mcm8.js +56305 -0
  124. package/dist/index-bsmcresk.js +79424 -0
  125. package/dist/index-mh85qhec.js +475 -0
  126. package/dist/{index-jd7sejm2.js → index-vxvhxxbn.js} +10 -9
  127. package/dist/index-we27kd31.js +12810 -0
  128. package/dist/{keepalive-6ywhpja1.js → keepalive-psj6j54c.js} +12 -11
  129. package/dist/{lead-cw45n21s.js → lead-hajz4688.js} +61 -56
  130. package/dist/{maintenance-ss1a1ge9.js → maintenance-ps02sb5m.js} +10 -9
  131. package/dist/{node-fkajaq96.js → node-mwb5r697.js} +2 -1
  132. package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-0284h93b.js} +11 -10
  133. package/dist/{onboard-8hzdhc1k.js → onboard-rbf6bg01.js} +11 -3
  134. package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-13dcatgq.js} +18 -13
  135. package/dist/{otel-impl-e6mnvc4v.js → otel-impl-zvqcbhp7.js} +242 -868
  136. package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-xxy47q4v.js} +244 -106
  137. package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-kefx9v3t.js} +12 -11
  138. package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-3m36rxm2.js} +11 -10
  139. package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-z76xv0hq.js} +12 -11
  140. package/dist/{render-v2-907cy6sa.js → render-v2-wz73bs25.js} +18 -14
  141. package/dist/{resume-42stcaz0.js → resume-k4wzge8w.js} +25 -21
  142. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  143. package/dist/{setup-adbc1c10.js → setup-2fp2pypp.js} +2 -2
  144. package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
  145. package/dist/{work-objects-wpj8ck95.js → work-objects-6k0ywz3m.js} +41 -36
  146. package/dist/{worker-bzdra9rf.js → worker-5v3rxsdh.js} +61 -56
  147. package/dist/{x-qfmygqqv.js → x-4mtdeym1.js} +3 -2
  148. package/openapi.json +1279 -329
  149. package/package.json +15 -15
  150. package/src/agentmail/handlers.ts +21 -11
  151. package/src/apps/definition.ts +16 -0
  152. package/src/azure-devops/api.ts +52 -2
  153. package/src/azure-devops/boards-sync.ts +50 -20
  154. package/src/azure-devops/index.ts +1 -0
  155. package/src/azure-devops/outbound.ts +95 -0
  156. package/src/be/boot-seeds.ts +11 -0
  157. package/src/be/config-refs.ts +60 -0
  158. package/src/be/db/model-profiles.ts +315 -0
  159. package/src/be/db/page-versions.ts +15 -0
  160. package/src/be/db/runtime.ts +35 -8
  161. package/src/be/db/skill-name-resolution.ts +36 -0
  162. package/src/be/db/tasks/read.ts +237 -0
  163. package/src/be/db/tasks/write.ts +7 -0
  164. package/src/be/db.ts +87 -36
  165. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  166. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  167. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  168. package/src/be/migrations/219_relabel_pi_context_compactions.sql +22 -0
  169. package/src/be/migrations/220_model_profiles.sql +137 -0
  170. package/src/be/model-catalog-store.ts +5 -1
  171. package/src/be/model-tier-resolution.ts +155 -10
  172. package/src/be/model-validation.ts +12 -2
  173. package/src/be/models-catalog.ts +26 -1
  174. package/src/be/modelsdev-cache.json +198 -63
  175. package/src/be/modelsdev-cache.ts +9 -1
  176. package/src/be/script-credential-broker.ts +39 -2
  177. package/src/be/scripts/run-saved.ts +1 -0
  178. package/src/be/scripts/typecheck.ts +22 -8
  179. package/src/be/secret-registry.ts +6 -2
  180. package/src/be/seed/runner.ts +13 -1
  181. package/src/be/seed/state-db.ts +5 -0
  182. package/src/be/seed/types.ts +6 -0
  183. package/src/be/seed-model-profiles.ts +41 -0
  184. package/src/be/seed-pricing.ts +19 -2
  185. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
  186. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  187. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  188. package/src/be/seed-scripts/index.ts +9 -0
  189. package/src/be/seed-skills/bundled-files.generated.json +0 -18
  190. package/src/be/seed-skills/index.ts +104 -3
  191. package/src/be/swarm-config-guard.ts +53 -0
  192. package/src/cli.tsx +0 -16
  193. package/src/commands/onboard/non-interactive.ts +4 -2
  194. package/src/commands/provider-credentials.ts +52 -6
  195. package/src/commands/runner.ts +193 -71
  196. package/src/e2b/env.ts +5 -0
  197. package/src/extensions/catalog.generated.json +17 -0
  198. package/src/extensions/contract-types.generated.ts +1 -1
  199. package/src/extensions/contract.ts +45 -0
  200. package/src/extensions/dispatcher.ts +7 -0
  201. package/src/extensions/loader.ts +10 -5
  202. package/src/extensions/post-bridge.ts +40 -0
  203. package/src/github/handlers.ts +11 -4
  204. package/src/heartbeat/heartbeat.ts +2 -1
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/agents.ts +49 -2
  208. package/src/http/all-routes.ts +1 -1
  209. package/src/http/apps.ts +30 -3
  210. package/src/http/config.ts +62 -19
  211. package/src/http/core.ts +8 -0
  212. package/src/http/index.ts +25 -3
  213. package/src/http/integrations.ts +88 -1
  214. package/src/http/mcp.ts +15 -5
  215. package/src/http/model-profiles.ts +303 -0
  216. package/src/http/page-proxy.ts +2 -4
  217. package/src/http/pages-public.ts +13 -7
  218. package/src/http/pages.ts +3 -13
  219. package/src/http/poll.ts +42 -71
  220. package/src/http/requested-by.ts +54 -0
  221. package/src/http/script-runs.ts +1 -1
  222. package/src/http/scripts.ts +26 -2
  223. package/src/http/stats.ts +1 -30
  224. package/src/http/tasks.ts +79 -5
  225. package/src/http/utils.ts +14 -0
  226. package/src/http/webhooks.ts +160 -3
  227. package/src/http/x.ts +1 -0
  228. package/src/integrations/chat-sdk/adapters.ts +129 -0
  229. package/src/integrations/chat-sdk/attachments.ts +232 -0
  230. package/src/integrations/chat-sdk/background.ts +36 -0
  231. package/src/integrations/chat-sdk/commands.ts +194 -0
  232. package/src/integrations/chat-sdk/config.ts +198 -0
  233. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  234. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  235. package/src/integrations/chat-sdk/handlers.ts +28 -0
  236. package/src/integrations/chat-sdk/inbound.ts +426 -0
  237. package/src/integrations/chat-sdk/limits.ts +48 -0
  238. package/src/integrations/chat-sdk/logger.ts +81 -0
  239. package/src/integrations/chat-sdk/outbound.ts +123 -0
  240. package/src/integrations/chat-sdk/relay.ts +172 -0
  241. package/src/integrations/chat-sdk/router.ts +169 -0
  242. package/src/integrations/chat-sdk/runtime.ts +351 -0
  243. package/src/integrations/chat-sdk/schema.ts +245 -0
  244. package/src/integrations/chat-sdk/state.ts +243 -0
  245. package/src/integrations/chat-sdk/status.ts +244 -0
  246. package/src/integrations/chat-sdk/steering.ts +58 -0
  247. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  248. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  249. package/src/integrations/chat-sdk/templates.ts +16 -0
  250. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  251. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  252. package/src/integrations/chat-sdk/typing.ts +65 -0
  253. package/src/{artifact-sdk → pages}/feedback-overlay.ts +65 -6
  254. package/src/pages/version.ts +4 -5
  255. package/src/prompts/base-prompt.ts +111 -45
  256. package/src/providers/acp-target-catalog.ts +6 -0
  257. package/src/providers/acp-targets.ts +56 -3
  258. package/src/providers/amp-adapter.ts +1 -1
  259. package/src/providers/claude-adapter.ts +1 -1
  260. package/src/providers/claude-flag-settings.ts +17 -5
  261. package/src/providers/claude-managed-adapter.ts +1 -1
  262. package/src/providers/claude-session-events.ts +6 -1
  263. package/src/providers/dsh-adapter.ts +1 -1
  264. package/src/providers/opencode-adapter.ts +243 -26
  265. package/src/providers/opencode-swarm-plugin.ts +31 -0
  266. package/src/providers/pi-mono-adapter.ts +398 -153
  267. package/src/providers/pi-mono-extension.ts +17 -3
  268. package/src/providers/pricing-sources.md +33 -2
  269. package/src/providers/reasoning-effort.ts +37 -0
  270. package/src/providers/types.ts +6 -2
  271. package/src/rbac/legacy-policy.ts +16 -2
  272. package/src/rbac/permissions.ts +26 -0
  273. package/src/scheduler/deferred-task-waits.ts +18 -5
  274. package/src/scheduler/scheduler.ts +11 -3
  275. package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
  276. package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
  277. package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
  278. package/src/scripts-runtime/extract-args-schema.ts +9 -8
  279. package/src/scripts-runtime/loader.ts +19 -7
  280. package/src/scripts-runtime/quickjs-compat.ts +464 -0
  281. package/src/scripts-runtime/sdk-allowlist.ts +12 -6
  282. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  283. package/src/scripts-runtime/types/stdlib.d.ts +39 -15
  284. package/src/scripts-runtime/types/swarm-extension.d.ts +66 -1
  285. package/src/scripts-runtime/types/swarm-sdk.d.ts +39 -15
  286. package/src/server.ts +62 -19
  287. package/src/slack/blocks.ts +4 -2
  288. package/src/slack/event-dedup.ts +1 -1
  289. package/src/slack/reaction-shortcode.ts +14 -0
  290. package/src/slack/render-v2.ts +12 -7
  291. package/src/slack/responses.ts +5 -4
  292. package/src/slack/thread-buffer.ts +41 -22
  293. package/src/tasks/additive-buffer.ts +4 -2
  294. package/src/tasks/context-key.ts +60 -1
  295. package/src/tasks/model-pin.ts +67 -0
  296. package/src/tasks/worker-follow-up.ts +15 -33
  297. package/src/tests/acp-adapter.test.ts +42 -0
  298. package/src/tests/agentmail-filters.test.ts +47 -0
  299. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  300. package/src/tests/apps-spike2.test.ts +35 -0
  301. package/src/tests/azure-devops-outbound.test.ts +420 -0
  302. package/src/tests/base-prompt.test.ts +58 -54
  303. package/src/tests/chat-sdk-commands.test.ts +191 -0
  304. package/src/tests/chat-sdk-config.test.ts +334 -0
  305. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  306. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  307. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  308. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  309. package/src/tests/chat-sdk-harness.ts +146 -0
  310. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  311. package/src/tests/chat-sdk-relay.test.ts +470 -0
  312. package/src/tests/chat-sdk-reload.test.ts +128 -0
  313. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  314. package/src/tests/chat-sdk-slack.test.ts +268 -0
  315. package/src/tests/chat-sdk-state.test.ts +163 -0
  316. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  317. package/src/tests/chat-sdk-teams.test.ts +277 -0
  318. package/src/tests/chat-sdk-tools.test.ts +520 -0
  319. package/src/tests/chat-sdk-typing.test.ts +120 -0
  320. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  321. package/src/tests/claude-adapter-binary.test.ts +9 -4
  322. package/src/tests/claude-flag-settings.test.ts +11 -3
  323. package/src/tests/claude-managed-adapter.test.ts +1 -1
  324. package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
  325. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  326. package/src/tests/claude-worker-parity.test.ts +2 -7
  327. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  328. package/src/tests/config-refs.test.ts +66 -0
  329. package/src/tests/context-key.test.ts +19 -0
  330. package/src/tests/cors-allowlist.test.ts +25 -0
  331. package/src/tests/create-page-tool.test.ts +18 -0
  332. package/src/tests/credential-check.test.ts +139 -0
  333. package/src/tests/credentials.test.ts +21 -0
  334. package/src/tests/db-runtime.test.ts +61 -0
  335. package/src/tests/db-task-read-contract.test.ts +22 -0
  336. package/src/tests/db-task-write-contract.test.ts +11 -0
  337. package/src/tests/deferred-task-wake.test.ts +78 -1
  338. package/src/tests/docs-index-footprint.test.js +3 -3
  339. package/src/tests/dsh-adapter.test.ts +1 -1
  340. package/src/tests/enabled-capabilities.test.ts +20 -0
  341. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  342. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  343. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  344. package/src/tests/env-flag.test.ts +1 -0
  345. package/src/tests/explicit-model-validation.test.ts +105 -1
  346. package/src/tests/extensions-catalog.test.ts +1 -0
  347. package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
  348. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  349. package/src/tests/extensions-loader.test.ts +15 -0
  350. package/src/tests/extensions-post-bridge.test.ts +51 -0
  351. package/src/tests/fetch-resolved-env.test.ts +128 -0
  352. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  353. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  354. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  355. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  356. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  357. package/src/tests/github-handlers.test.ts +35 -0
  358. package/src/tests/harness-provider-resolution.test.ts +12 -0
  359. package/src/tests/heartbeat-checklist.test.ts +3 -2
  360. package/src/tests/heartbeat-jev-gate-credentials.test.ts +168 -0
  361. package/src/tests/heartbeat-jev-gate.test.ts +385 -0
  362. package/src/tests/hook-runtime-close.test.ts +0 -2
  363. package/src/tests/http-api-integration.test.ts +0 -25
  364. package/src/tests/migration-046-budgets.test.ts +17 -16
  365. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  366. package/src/tests/model-profile-backcompat.test.ts +327 -0
  367. package/src/tests/model-profile-providers.test.ts +302 -0
  368. package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
  369. package/src/tests/model-profiles-api.test.ts +614 -0
  370. package/src/tests/model-tier-resolution.test.ts +93 -0
  371. package/src/tests/models-catalog.test.ts +42 -1
  372. package/src/tests/openai-compatible-providers.test.ts +134 -0
  373. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  374. package/src/tests/opencode-adapter.test.ts +216 -2
  375. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  376. package/src/tests/opencode-shell-env.test.ts +145 -0
  377. package/src/tests/openrouter-base-url.test.ts +101 -151
  378. package/src/tests/page-proxy.test.ts +1 -1
  379. package/src/tests/pages-browser-sdk.test.ts +76 -0
  380. package/src/tests/pages-feedback-keys.test.ts +121 -0
  381. package/src/tests/pages-feedback.test.ts +4 -1
  382. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  383. package/src/tests/pi-context-compaction.test.ts +193 -0
  384. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  385. package/src/tests/pi-mono-adapter.test.ts +385 -5
  386. package/src/tests/pi-shell-env.test.ts +170 -0
  387. package/src/tests/profile-claim.test.ts +269 -0
  388. package/src/tests/prompt-template-remaining.test.ts +35 -0
  389. package/src/tests/quickjs-compat.test.ts +213 -0
  390. package/src/tests/rbac-engine.test.ts +32 -3
  391. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  392. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  393. package/src/tests/script-connections.test.ts +6 -0
  394. package/src/tests/script-executor-conformance.test.ts +252 -1
  395. package/src/tests/script-executor-quickjs.test.ts +96 -0
  396. package/src/tests/script-runs-http.test.ts +89 -0
  397. package/src/tests/scripts-http.test.ts +217 -1
  398. package/src/tests/scripts-only-gating.test.ts +2 -3
  399. package/src/tests/scripts-runtime.test.ts +58 -40
  400. package/src/tests/secret-scrubber.test.ts +96 -0
  401. package/src/tests/seed-model-profiles.test.ts +174 -0
  402. package/src/tests/seed-scripts.test.ts +2 -2
  403. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  404. package/src/tests/seed-skills-retire.test.ts +182 -0
  405. package/src/tests/send-task-requester-gate.test.ts +58 -0
  406. package/src/tests/session-cost-recompute-unit.test.ts +46 -0
  407. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  408. package/src/tests/skill-invocations.test.ts +4 -2
  409. package/src/tests/slack-blocks.test.ts +36 -0
  410. package/src/tests/slack-inline-output.test.ts +14 -0
  411. package/src/tests/slack-reaction-config.test.ts +20 -0
  412. package/src/tests/slack-render-v2.test.ts +37 -0
  413. package/src/tests/slack-thread-buffer.test.ts +98 -1
  414. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  415. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  416. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  417. package/src/tests/swarm-diff.test.ts +1 -1
  418. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  419. package/src/tests/task-session-prompts.test.ts +132 -0
  420. package/src/tests/task-tool-manifest.test.ts +14 -0
  421. package/src/tests/task-tools-ctx.test.ts +2 -0
  422. package/src/tests/tool-annotations.test.ts +6 -6
  423. package/src/tests/ui-logs-parser.test.ts +43 -0
  424. package/src/tests/used-by-route.test.ts +6 -0
  425. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  426. package/src/tests/workflow-llm.test.ts +61 -0
  427. package/src/tests/workflow-swarm-script.test.ts +38 -0
  428. package/src/tests/workflow-wait-filter.test.ts +5 -3
  429. package/src/tools/chat-access.ts +41 -0
  430. package/src/tools/chat-open-dm.ts +59 -0
  431. package/src/tools/chat-post.ts +74 -0
  432. package/src/tools/chat-read-thread.ts +100 -0
  433. package/src/tools/chat-reply.ts +75 -0
  434. package/src/tools/create-page.ts +3 -13
  435. package/src/tools/model-catalog/index.ts +2 -1
  436. package/src/tools/model-profiles/list-model-profiles.ts +54 -0
  437. package/src/tools/register-chat-channel.ts +139 -0
  438. package/src/tools/request-human-input.ts +11 -3
  439. package/src/tools/script-apis.ts +5 -1
  440. package/src/tools/script-upsert.ts +4 -1
  441. package/src/tools/send-task.ts +48 -1
  442. package/src/tools/skills/skill-get.ts +17 -9
  443. package/src/tools/swarm-config/get-config.ts +2 -1
  444. package/src/tools/swarm-config/list-config.ts +2 -1
  445. package/src/tools/swarm-config/set-config.ts +16 -3
  446. package/src/tools/system-one-decide.ts +104 -0
  447. package/src/tools/task-action.ts +22 -1
  448. package/src/tools/tool-config.ts +14 -6
  449. package/src/types.ts +48 -3
  450. package/src/utils/config-env-export.ts +74 -0
  451. package/src/utils/credentials.test.ts +92 -0
  452. package/src/utils/credentials.ts +52 -4
  453. package/src/utils/harness-provider.ts +15 -6
  454. package/src/utils/runtime-model-catalog.ts +11 -1
  455. package/src/utils/secret-scrubber.ts +86 -10
  456. package/src/utils/task-tool-manifest.ts +19 -2
  457. package/src/utils/vcs-repo-match.ts +29 -0
  458. package/src/workflows/executors/raw-llm.ts +8 -3
  459. package/src/workflows/executors/swarm-script.ts +1 -0
  460. package/src/workflows/executors/system-one-decision.ts +21 -11
  461. package/src/workflows/executors/workflow-llm.ts +22 -0
  462. package/src/workflows/index.ts +21 -12
  463. package/templates/extensions/README.md +1 -0
  464. package/templates/extensions/comms-adherence-gate/README.md +88 -0
  465. package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
  466. package/templates/extensions/comms-adherence-gate/manifest.json +8 -0
  467. package/templates/skills/agent-browser/SKILL.md +1 -1
  468. package/templates/skills/agent-browser/content.md +1 -1
  469. package/templates/skills/apps/SKILL.md +8 -1
  470. package/templates/skills/apps/content.md +8 -1
  471. package/templates/skills/chat-sdk/config.json +14 -0
  472. package/templates/skills/chat-sdk/content.md +84 -0
  473. package/templates/skills/composio-gmail/content.md +7 -0
  474. package/templates/skills/composio-google-docs/content.md +1 -1
  475. package/templates/skills/email-domain-health/config.json +14 -0
  476. package/templates/skills/email-domain-health/content.md +131 -0
  477. package/templates/skills/kv-storage/content.md +2 -2
  478. package/templates/skills/pages/content.md +8 -10
  479. package/templates/skills/swarm-extensions/content.md +2 -0
  480. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  481. package/templates/skills/swarm-scripts/config.json +1 -1
  482. package/templates/skills/swarm-scripts/content.md +4 -2
  483. package/templates/skills/workflow-iterate/content.md +38 -0
  484. package/dist/artifact-eczsknc3.js +0 -3843
  485. package/dist/cli-42qhyvwx.js +0 -33
  486. package/dist/cli-bd957dgb.js +0 -153
  487. package/dist/cli-q51yprfq.js +0 -1104
  488. package/dist/cli-t1ze64h3.js +0 -811
  489. package/dist/cli-tcc4wd5d.js +0 -56471
  490. package/dist/index-9ch1n761.js +0 -1102
  491. package/src/artifact-sdk/index.ts +0 -2
  492. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  493. package/src/artifact-sdk/port.ts +0 -12
  494. package/src/artifact-sdk/server.ts +0 -183
  495. package/src/artifact-sdk/tunnel.ts +0 -19
  496. package/src/commands/artifact.ts +0 -249
  497. package/src/http/ecosystem.ts +0 -77
  498. package/src/tests/artifact-commands.test.ts +0 -92
  499. package/src/tests/artifact-sdk.test.ts +0 -793
  500. package/src/tests/register-service-security.test.ts +0 -194
  501. package/src/tools/list-services.ts +0 -107
  502. package/src/tools/register-service.ts +0 -177
  503. package/src/tools/unregister-service.ts +0 -73
  504. package/src/tools/update-service-status.ts +0 -96
  505. package/templates/skills/artifacts/config.json +0 -14
  506. package/templates/skills/artifacts/content.md +0 -344
  507. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  508. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  509. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  510. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  511. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
@@ -0,0 +1,76 @@
1
+ import { describe, expect, mock, test } from "bun:test";
2
+ import { BROWSER_SDK_JS } from "../pages/browser-sdk";
3
+
4
+ // ─── Browser SDK tests ─────────────────────────────────────────────────
5
+
6
+ describe("BROWSER_SDK_JS", () => {
7
+ test("is a non-empty string", () => {
8
+ expect(typeof BROWSER_SDK_JS).toBe("string");
9
+ expect(BROWSER_SDK_JS.length).toBeGreaterThan(100);
10
+ });
11
+
12
+ test("contains SwarmSDK class", () => {
13
+ expect(BROWSER_SDK_JS).toContain("class SwarmSDK");
14
+ });
15
+
16
+ test("is syntactically valid JavaScript", () => {
17
+ expect(() => new Function(BROWSER_SDK_JS)).not.toThrow();
18
+ });
19
+
20
+ test("exposes the eight canonical domains", () => {
21
+ const expectedDomains = [
22
+ "this.tasks",
23
+ "this.agents",
24
+ "this.events",
25
+ "this.memory",
26
+ "this.repos",
27
+ "this.schedules",
28
+ "this.approvalRequests",
29
+ "this.assets",
30
+ ];
31
+ for (const domain of expectedDomains) {
32
+ expect(BROWSER_SDK_JS).toContain(domain);
33
+ }
34
+ });
35
+
36
+ test("removed domains are NOT exposed (messages, services, slack)", () => {
37
+ const removed = ["this.messages", "this.services", "this.slack", "postMessage", "readMessages"];
38
+ for (const r of removed) {
39
+ expect(BROWSER_SDK_JS).not.toContain(r);
40
+ }
41
+ });
42
+
43
+ test("assigns SwarmSDK class + swarmSdk singleton to window", () => {
44
+ expect(BROWSER_SDK_JS).toContain("window.SwarmSDK = SwarmSDK");
45
+ expect(BROWSER_SDK_JS).toContain("window.swarmSdk = new SwarmSDK()");
46
+ });
47
+
48
+ test("routes calls through the /@swarm/api/* proxy", () => {
49
+ expect(BROWSER_SDK_JS).toContain("const base = '/@swarm/api'");
50
+ // Sentinel endpoints — one per domain.
51
+ expect(BROWSER_SDK_JS).toContain("'/tasks'");
52
+ expect(BROWSER_SDK_JS).toContain("'/agents'");
53
+ expect(BROWSER_SDK_JS).toContain("'/events'");
54
+ expect(BROWSER_SDK_JS).toContain("'/memory/search'");
55
+ expect(BROWSER_SDK_JS).toContain("'/repos'");
56
+ expect(BROWSER_SDK_JS).toContain("'/schedules'");
57
+ expect(BROWSER_SDK_JS).toContain("'/approval-requests'");
58
+ expect(BROWSER_SDK_JS).toContain("'/assets'");
59
+ expect(BROWSER_SDK_JS).toContain("'/assets/key-audit'");
60
+ expect(BROWSER_SDK_JS).toContain("'/assets/mappings'");
61
+ });
62
+
63
+ test("does not fetch on SDK load or construction", () => {
64
+ const fetchMock = mock(() => Promise.resolve(Response.json({})));
65
+ const window = {};
66
+ const loadSdk = new Function("window", "fetch", `${BROWSER_SDK_JS}\nreturn window.SwarmSDK;`);
67
+
68
+ const SwarmSDK = loadSdk(window, fetchMock);
69
+ expect(window).toHaveProperty("swarmSdk");
70
+ expect(fetchMock).not.toHaveBeenCalled();
71
+
72
+ new SwarmSDK();
73
+ new SwarmSDK();
74
+ expect(fetchMock).not.toHaveBeenCalled();
75
+ });
76
+ });
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Typing in the page feedback overlay must not reach the page's own key
3
+ * handlers. The overlay lives in a shadow root, so outside it the event target
4
+ * is the shadow host and a page's "ignore keys from a textarea" guard misses:
5
+ * Space and arrows typed into a comment used to change slides in a deck page.
6
+ * Page capture listeners on window/document run before anything the overlay
7
+ * registers later, so a key guard is served first in <head>.
8
+ */
9
+ import { describe, expect, test } from "bun:test";
10
+ import { Window } from "happy-dom";
11
+ import { feedbackKeyGuardScript, feedbackOverlayScripts } from "../pages/feedback-overlay";
12
+
13
+ type Target = { dispatchEvent(e: unknown): boolean };
14
+
15
+ function scriptSources(html: string): string[] {
16
+ return [...html.matchAll(/<script>([\s\S]*?)<\/script>/g)].map((m) => m[1]!);
17
+ }
18
+
19
+ // Served order: key guard (top of <head>), page scripts, overlay (end of body).
20
+ function overlayPage() {
21
+ const window = new Window({ url: "https://api.example.test/p/abc" });
22
+ const document = window.document;
23
+ document.body.innerHTML = "<h2>Slide title</h2>";
24
+ for (const source of scriptSources(feedbackKeyGuardScript())) window.eval(source);
25
+ // A page's key handlers (e.g. a deck's slide navigation), registered before
26
+ // the overlay, in every phase. They record every key event they see.
27
+ const pageKeys: string[] = [];
28
+ for (const type of ["keydown", "keyup", "keypress"]) {
29
+ const record = (where: string) => (e: Event) =>
30
+ pageKeys.push(`${where}:${type}:${(e as unknown as KeyboardEvent).key}`);
31
+ window.addEventListener(type, record("window-capture"), true);
32
+ document.addEventListener(type, record("document-capture"), true);
33
+ window.addEventListener(type, record("window-bubble"));
34
+ }
35
+ for (const source of scriptSources(feedbackOverlayScripts("abc"))) window.eval(source);
36
+ const root = document.querySelector("swarm-feedback-root")!.shadowRoot!;
37
+ return { window, document, root, pageKeys };
38
+ }
39
+
40
+ function key(window: Window, target: Target, type: string, key: string, init = {}) {
41
+ target.dispatchEvent(
42
+ new window.KeyboardEvent(type, { key, bubbles: true, composed: true, ...init }),
43
+ );
44
+ }
45
+
46
+ function press(window: Window, target: Target, k: string) {
47
+ key(window, target, "keydown", k);
48
+ key(window, target, "keypress", k);
49
+ key(window, target, "keyup", k);
50
+ }
51
+
52
+ function openComposer(window: Window, document: Window["document"], root: ShadowRoot) {
53
+ // Select mode stays on after a comment, so the button is only there the first time.
54
+ const select = [...root.querySelectorAll("button")].find(
55
+ (b) => b.textContent === "Select an element",
56
+ );
57
+ select?.click();
58
+ document.querySelector("h2")!.dispatchEvent(new window.MouseEvent("click", { bubbles: true }));
59
+ const comment = root.querySelector("textarea") as unknown as HTMLTextAreaElement | null;
60
+ expect(comment).not.toBeNull();
61
+ return comment!;
62
+ }
63
+
64
+ function savedComments(window: Window): unknown[] {
65
+ return JSON.parse(window.sessionStorage.getItem("swarm-feedback:abc") || "[]");
66
+ }
67
+
68
+ describe("page feedback overlay keys", () => {
69
+ test("keys typed in a comment box never reach page capture or bubble handlers", () => {
70
+ const { window, document, root, pageKeys } = overlayPage();
71
+ const comment = openComposer(window, document, root);
72
+
73
+ for (const k of [" ", "ArrowRight", "ArrowLeft", "ArrowUp", "ArrowDown", "Enter", "PageDown"]) {
74
+ press(window, comment, k);
75
+ }
76
+ expect(pageKeys).toEqual([]);
77
+ // Escape still closes the composer, and the page never sees it.
78
+ key(window, comment, "keydown", "Escape");
79
+ expect(comment.isConnected).toBe(false);
80
+ expect(pageKeys).toEqual([]);
81
+ });
82
+
83
+ test("the release of an overlay key stays in the overlay after the composer closes", () => {
84
+ const { window, document, root, pageKeys } = overlayPage();
85
+
86
+ // Escape: keydown closes the composer, keyup lands on the page body.
87
+ let comment = openComposer(window, document, root);
88
+ key(window, comment, "keydown", "Escape");
89
+ expect(comment.isConnected).toBe(false);
90
+ key(window, document.body, "keyup", "Escape");
91
+
92
+ // Ctrl+Enter: keydown commits and removes the textarea, both keyups land on the body.
93
+ comment = openComposer(window, document, root);
94
+ comment.value = "Bigger title";
95
+ key(window, comment, "keydown", "Control", { ctrlKey: true });
96
+ key(window, comment, "keydown", "Enter", { ctrlKey: true });
97
+ expect(comment.isConnected).toBe(false);
98
+ expect(savedComments(window)).toHaveLength(1);
99
+ key(window, document.body, "keyup", "Enter", { ctrlKey: true });
100
+ key(window, document.body, "keyup", "Control");
101
+ expect(pageKeys).toEqual([]);
102
+
103
+ // The next press that starts on the page is the page's again.
104
+ key(window, document.body, "keydown", "Escape");
105
+ key(window, document.body, "keyup", "Escape");
106
+ expect(pageKeys).toContain("window-bubble:keydown:Escape");
107
+ expect(pageKeys).toContain("window-bubble:keyup:Escape");
108
+ });
109
+
110
+ test("keys outside the overlay still reach the page", () => {
111
+ const { window, document, pageKeys } = overlayPage();
112
+ press(window, document.body, "ArrowRight");
113
+ expect(pageKeys).toEqual(
114
+ ["keydown", "keypress", "keyup"].flatMap((type) => [
115
+ `window-capture:${type}:ArrowRight`,
116
+ `document-capture:${type}:ArrowRight`,
117
+ `window-bubble:${type}:ArrowRight`,
118
+ ]),
119
+ );
120
+ });
121
+ });
@@ -12,11 +12,11 @@ import {
12
12
  type Server,
13
13
  type ServerResponse,
14
14
  } from "node:http";
15
- import { feedbackOverlayScripts, isPageFeedbackRequested } from "../artifact-sdk/feedback-overlay";
16
15
  import { closeDb, createAgent, getTaskById, initDb } from "../be/db";
17
16
  import { handlePages } from "../http/pages";
18
17
  import { handlePagesPublic } from "../http/pages-public";
19
18
  import { getPathSegments, parseQueryParams } from "../http/utils";
19
+ import { feedbackOverlayScripts, isPageFeedbackRequested } from "../pages/feedback-overlay";
20
20
  import { listenOnFreePort } from "./test-net";
21
21
 
22
22
  const TEST_DB_PATH = "./test-pages-feedback.sqlite";
@@ -127,6 +127,9 @@ describe("page feedback", () => {
127
127
  const html = await res.text();
128
128
  expect(html).toContain(`window.__swarmFeedback = {"pageId":"${pageId}"};`);
129
129
  expect(html).toContain("swarm-feedback-root");
130
+ // The key guard is served before the page's own markup and scripts.
131
+ expect(html.indexOf("__swarmFeedbackKeys")).toBeGreaterThan(-1);
132
+ expect(html.indexOf("__swarmFeedbackKeys")).toBeLessThan(html.indexOf("<h1>Hello</h1>"));
130
133
  // The agent-authored body and the SDK are still served.
131
134
  expect(html).toContain("<h1>Hello</h1>");
132
135
  expect(html).toContain("class SwarmSDK");
@@ -0,0 +1,102 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import {
4
+ closeDb,
5
+ createAgent,
6
+ createTaskExtended,
7
+ createUser,
8
+ initDb,
9
+ pauseTask,
10
+ startTask,
11
+ } from "../be/db";
12
+ import { handleTasks } from "../http/tasks";
13
+
14
+ const TEST_DB_PATH = "./test-paused-tasks-requested-by.sqlite";
15
+ const AGENT_ID = "50000000-0000-4000-8000-000000000001";
16
+
17
+ async function removeDbFiles(path: string): Promise<void> {
18
+ for (const suffix of ["", "-wal", "-shm"]) {
19
+ try {
20
+ await unlink(path + suffix);
21
+ } catch (error) {
22
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
23
+ }
24
+ }
25
+ }
26
+
27
+ async function getPausedTasks(): Promise<{
28
+ status: number;
29
+ body: { tasks: Array<{ id: string; requestedBy?: Record<string, unknown> }> };
30
+ }> {
31
+ let status = 200;
32
+ let bodyStr = "";
33
+ const req = {
34
+ method: "GET",
35
+ url: "/api/paused-tasks",
36
+ headers: { "x-agent-id": AGENT_ID },
37
+ } as unknown as Parameters<typeof handleTasks>[0];
38
+ const res = {
39
+ setHeader() {},
40
+ writeHead(code: number) {
41
+ status = code;
42
+ },
43
+ end(body?: string) {
44
+ bodyStr = body ?? "";
45
+ },
46
+ } as unknown as Parameters<typeof handleTasks>[1];
47
+ const handled = await handleTasks(
48
+ req,
49
+ res,
50
+ ["api", "paused-tasks"],
51
+ new URLSearchParams(),
52
+ AGENT_ID,
53
+ );
54
+ if (!handled) throw new Error("handleTasks did not handle the request");
55
+ return { status, body: JSON.parse(bodyStr) };
56
+ }
57
+
58
+ beforeAll(async () => {
59
+ await removeDbFiles(TEST_DB_PATH);
60
+ initDb(TEST_DB_PATH);
61
+ await createAgent({ id: AGENT_ID, name: "Paused Worker", isLead: false, status: "idle" });
62
+ });
63
+
64
+ afterAll(async () => {
65
+ closeDb();
66
+ await removeDbFiles(TEST_DB_PATH);
67
+ });
68
+
69
+ describe("GET /api/paused-tasks requester projection", () => {
70
+ test("carries the same requestedBy a task_assigned trigger carries", async () => {
71
+ const user = await createUser({
72
+ name: "Paused Requester",
73
+ email: "paused@example.com",
74
+ role: "CTO",
75
+ notes: "Paused requester notes",
76
+ });
77
+ const withUser = await createTaskExtended("Paused task with requester", {
78
+ agentId: AGENT_ID,
79
+ requestedByUserId: user.id,
80
+ });
81
+ const withoutUser = await createTaskExtended("Paused task without requester", {
82
+ agentId: AGENT_ID,
83
+ });
84
+ for (const task of [withUser, withoutUser]) {
85
+ await startTask(task.id);
86
+ expect(await pauseTask(task.id)).not.toBeNull();
87
+ }
88
+
89
+ const { status, body } = await getPausedTasks();
90
+ expect(status).toBe(200);
91
+ const byId = new Map(body.tasks.map((task) => [task.id, task]));
92
+ expect(byId.get(withUser.id)?.requestedBy).toMatchObject({
93
+ id: user.id,
94
+ name: "Paused Requester",
95
+ email: "paused@example.com",
96
+ role: "CTO",
97
+ notes: "Paused requester notes",
98
+ });
99
+ expect(byId.get(withoutUser.id)).toBeDefined();
100
+ expect(byId.get(withoutUser.id)?.requestedBy).toBeUndefined();
101
+ });
102
+ });
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Pi's `context` hook fires before every LLM call. It must report usage as a
3
+ * `progress` snapshot; only `session_compact` reports a compaction. Migration
4
+ * 219 relabels the trigger-less pi compaction rows written before the fix.
5
+ */
6
+
7
+ import type { Database } from "bun:sqlite";
8
+ import { afterAll, afterEach, beforeAll, describe, expect, test } from "bun:test";
9
+ import { unlink } from "node:fs/promises";
10
+ import type {
11
+ ContextEvent,
12
+ ExtensionFactory,
13
+ SessionCompactEvent,
14
+ } from "@earendil-works/pi-coding-agent";
15
+ import type { CreateContextSnapshotInput } from "../be/db";
16
+ import {
17
+ closeDb,
18
+ createAgent,
19
+ createContextSnapshot,
20
+ createTaskExtended,
21
+ getContextSnapshotsByTaskId,
22
+ getContextSummaryByTaskId,
23
+ initDb,
24
+ } from "../be/db";
25
+ import { createSwarmHooksExtension } from "../providers/pi-mono-extension";
26
+
27
+ const TEST_DB_PATH = "./test-pi-context-compaction.sqlite";
28
+ const agentId = "aaaa0000-0000-4000-8000-0000000000a1";
29
+
30
+ type Handler = (event: unknown, ctx: unknown) => Promise<unknown> | unknown;
31
+
32
+ let db: Database;
33
+ const origFetch = globalThis.fetch;
34
+
35
+ async function removeDbFiles() {
36
+ for (const suffix of ["", "-wal", "-shm"]) {
37
+ try {
38
+ await unlink(TEST_DB_PATH + suffix);
39
+ } catch {
40
+ // File doesn't exist
41
+ }
42
+ }
43
+ }
44
+
45
+ beforeAll(async () => {
46
+ await removeDbFiles();
47
+ db = initDb(TEST_DB_PATH);
48
+ await createAgent({ id: agentId, name: "Pi Worker", isLead: false, status: "idle" });
49
+ });
50
+
51
+ afterEach(() => {
52
+ globalThis.fetch = origFetch;
53
+ });
54
+
55
+ afterAll(async () => {
56
+ closeDb();
57
+ await removeDbFiles();
58
+ });
59
+
60
+ async function createTask(provider: string): Promise<string> {
61
+ const task = await createTaskExtended(`context compaction ${provider}`, {
62
+ agentId,
63
+ source: "mcp",
64
+ });
65
+ db.run("UPDATE agent_tasks SET provider = ? WHERE id = ?", [provider, task.id]);
66
+ return task.id;
67
+ }
68
+
69
+ /**
70
+ * Load the extension and route its `/context` POSTs into the real snapshot
71
+ * writer, the same path `POST /api/tasks/:id/context` takes.
72
+ */
73
+ function loadExtension(taskId: string) {
74
+ const handlers = new Map<string, Handler>();
75
+ const pending: Promise<unknown>[] = [];
76
+ globalThis.fetch = (async (url: string | URL | Request, init?: RequestInit) => {
77
+ const urlStr = typeof url === "string" ? url : url.toString();
78
+ if (urlStr.endsWith(`/api/tasks/${taskId}/context`) && init?.method === "POST") {
79
+ const body = JSON.parse(String(init.body)) as Omit<
80
+ CreateContextSnapshotInput,
81
+ "taskId" | "agentId"
82
+ >;
83
+ const write = createContextSnapshot({ ...body, taskId, agentId });
84
+ pending.push(write);
85
+ await write;
86
+ }
87
+ return new Response("{}", { status: 200 });
88
+ }) as typeof fetch;
89
+
90
+ const pi = {
91
+ on: (event: string, handler: Handler) => {
92
+ handlers.set(event, handler);
93
+ },
94
+ sendMessage: () => {},
95
+ registerMcpServer: () => {},
96
+ };
97
+ createSwarmHooksExtension({
98
+ apiUrl: "http://localhost:3013",
99
+ apiKey: "example-test-key",
100
+ agentId,
101
+ taskId,
102
+ isLead: false,
103
+ })(pi as unknown as Parameters<ExtensionFactory>[0]);
104
+
105
+ let tokens = 0;
106
+ const ctx = {
107
+ getContextUsage: () => ({ tokens, contextWindow: 1_000_000, percent: tokens / 10_000 }),
108
+ };
109
+ const fire = async (event: ContextEvent | SessionCompactEvent, usedTokens: number) => {
110
+ tokens = usedTokens;
111
+ await handlers.get(event.type)?.(event, ctx);
112
+ await Promise.all(pending);
113
+ };
114
+ return { fire };
115
+ }
116
+
117
+ describe("pi context hook", () => {
118
+ test("per-call context usage is progress; only session_compact counts", async () => {
119
+ const taskId = await createTask("pi");
120
+ const { fire } = loadExtension(taskId);
121
+
122
+ for (const used of [82_000, 94_000, 94_400]) {
123
+ await fire({ type: "context", messages: [] }, used);
124
+ }
125
+
126
+ let snapshots = await getContextSnapshotsByTaskId(taskId);
127
+ expect(snapshots.length).toBe(3);
128
+ expect(snapshots.filter((s) => s.eventType === "compaction")).toEqual([]);
129
+ let summary = await getContextSummaryByTaskId(taskId);
130
+ expect(summary.compactionCount).toBe(0);
131
+ expect(summary.peakContextTokens).toBe(94_400);
132
+
133
+ await fire(
134
+ {
135
+ type: "session_compact",
136
+ reason: "threshold",
137
+ willRetry: false,
138
+ fromExtension: false,
139
+ compactionEntry: {
140
+ type: "compaction",
141
+ id: "c1",
142
+ parentId: null,
143
+ timestamp: new Date().toISOString(),
144
+ summary: "s",
145
+ firstKeptEntryId: "e1",
146
+ tokensBefore: 120_000,
147
+ },
148
+ },
149
+ 30_000,
150
+ );
151
+
152
+ snapshots = await getContextSnapshotsByTaskId(taskId);
153
+ const compactions = snapshots.filter((s) => s.eventType === "compaction");
154
+ expect(compactions.length).toBe(1);
155
+ expect(compactions[0]?.compactTrigger).toBe("auto");
156
+ expect(compactions[0]?.preCompactTokens).toBe(120_000);
157
+ summary = await getContextSummaryByTaskId(taskId);
158
+ expect(summary.compactionCount).toBe(1);
159
+ });
160
+ });
161
+
162
+ describe("migration 219", () => {
163
+ test("relabels trigger-less pi compactions and leaves other rows alone", async () => {
164
+ const piTask = await createTask("pi");
165
+ const claudeTask = await createTask("claude");
166
+ const snapshot = (taskId: string, sessionId: string, extra = {}) =>
167
+ createContextSnapshot({
168
+ taskId,
169
+ agentId,
170
+ sessionId,
171
+ eventType: "compaction",
172
+ contextPercent: 9,
173
+ ...extra,
174
+ });
175
+
176
+ await snapshot(piTask, `pi-${piTask}`);
177
+ await snapshot(piTask, `pi-${piTask}`);
178
+ await snapshot(piTask, `pi-${piTask}`, { compactTrigger: "auto", preCompactTokens: 150_000 });
179
+ await snapshot(claudeTask, "claude-session");
180
+ expect((await getContextSummaryByTaskId(piTask)).compactionCount).toBe(3);
181
+
182
+ db.exec(await Bun.file("src/be/migrations/219_relabel_pi_context_compactions.sql").text());
183
+
184
+ const piRows = await getContextSnapshotsByTaskId(piTask);
185
+ expect(piRows.map((s) => s.eventType).sort()).toEqual(["compaction", "progress", "progress"]);
186
+ expect(piRows.find((s) => s.eventType === "compaction")?.preCompactTokens).toBe(150_000);
187
+ expect((await getContextSummaryByTaskId(piTask)).compactionCount).toBe(1);
188
+
189
+ const claudeRows = await getContextSnapshotsByTaskId(claudeTask);
190
+ expect(claudeRows.map((s) => s.eventType)).toEqual(["compaction"]);
191
+ expect((await getContextSummaryByTaskId(claudeTask)).compactionCount).toBe(1);
192
+ });
193
+ });