@desplega.ai/agent-swarm 1.169.0 → 1.171.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 (349) hide show
  1. package/README.md +11 -2
  2. package/dist/{acp-adapter-m47zfx4a.js → acp-adapter-1z9p3fvx.js} +6 -6
  3. package/dist/{actions-ws7k3tvq.js → actions-rc2yjk8a.js} +31 -29
  4. package/dist/{amp-adapter-nvv8k8j5.js → amp-adapter-ypyf5s1x.js} +6 -6
  5. package/dist/{anthropic-messages-13yn502s.js → anthropic-messages-etkbxhhy.js} +11 -11
  6. package/dist/{app-80w6qspx.js → app-04ab2s0z.js} +9 -9
  7. package/dist/{artifact-fey7dvj9.js → artifact-eczsknc3.js} +6 -3
  8. package/dist/{assistant-jtq439kw.js → assistant-vhmjd8wf.js} +34 -32
  9. package/dist/{azure-openai-responses-9st34pfz.js → azure-openai-responses-xap57x4b.js} +7 -7
  10. package/dist/{boot-reembed-feda8wn8.js → boot-reembed-3p0m259x.js} +8 -8
  11. package/dist/{boot-reembed-3nc0aaed.js → boot-reembed-wew3gwk8.js} +8 -8
  12. package/dist/{boot-scrub-sweep-grsa2er0.js → boot-scrub-sweep-5ytwtq24.js} +9 -9
  13. package/dist/{boot-seeds-gcfgq44f.js → boot-seeds-s8p2xry8.js} +12 -12
  14. package/dist/{claude-adapter-pjv2q7t8.js → claude-adapter-akrzg6jh.js} +15 -15
  15. package/dist/{claude-managed-adapter-0wa8se82.js → claude-managed-adapter-kqqqhp2q.js} +2 -2
  16. package/dist/{claude-managed-setup-zxa9p9tx.js → claude-managed-setup-bnmjarjc.js} +11 -8
  17. package/dist/{claude-sdk-session-c9j6k9kx.js → claude-sdk-session-exq1jadx.js} +15 -15
  18. package/dist/{cli-a8vps458.js → cli-01qndrvw.js} +17274 -17242
  19. package/dist/{cli-rg1c8ccw.js → cli-0d2rqhvq.js} +497 -73
  20. package/dist/cli-0p3enk35.js +188 -0
  21. package/dist/cli-1srmzpr3.js +16 -0
  22. package/dist/{cli-zzev32jw.js → cli-231av4y6.js} +6 -6
  23. package/dist/{cli-kp3vfknv.js → cli-280gnz4v.js} +2 -2
  24. package/dist/{cli-mv2520nm.js → cli-2bw3w47j.js} +1 -1
  25. package/dist/{cli-km8559dm.js → cli-2qbs2tvf.js} +18 -10
  26. package/dist/{cli-efnd2kce.js → cli-2rbt7at8.js} +6 -1
  27. package/dist/{cli-xvc3q9br.js → cli-451ks6aw.js} +1 -1
  28. package/dist/{cli-jkfxpg1b.js → cli-4bm25xtw.js} +2 -2
  29. package/dist/{cli-zp38xvtm.js → cli-5rqrj7q0.js} +1 -1
  30. package/dist/{cli-km4x66j0.js → cli-5y67yrt6.js} +13 -13
  31. package/dist/{cli-qg2zhjfc.js → cli-62bwwc2q.js} +8 -8
  32. package/dist/{cli-s0k2j7q9.js → cli-6xxxb8qt.js} +10 -10
  33. package/dist/cli-6zx22mv6.js +0 -0
  34. package/dist/{cli-zp67qg5x.js → cli-7a0sde2x.js} +72 -1
  35. package/dist/{cli-v1w7pbd8.js → cli-7jykv7ef.js} +1 -1
  36. package/dist/{cli-rfphkzh5.js → cli-7pz3b7x5.js} +24 -4
  37. package/dist/{cli-mb75wpxf.js → cli-81r1wjyv.js} +1 -1
  38. package/dist/{cli-rbr91whd.js → cli-8mr695sb.js} +9 -5
  39. package/dist/{cli-f14fvzag.js → cli-a1b9b32n.js} +6 -1
  40. package/dist/cli-cd0hv9nh.js +32 -0
  41. package/dist/{cli-dv76vq5d.js → cli-ctret352.js} +685 -209
  42. package/dist/{cli-wt7ccy4r.js → cli-d161g69q.js} +9 -1
  43. package/dist/cli-db3m6zdt.js +362 -0
  44. package/dist/{cli-hf5s9pgf.js → cli-e3pmyt39.js} +1 -1
  45. package/dist/{cli-ysnkvdx6.js → cli-ec7hrgqp.js} +313 -91
  46. package/dist/{cli-m23r88re.js → cli-erbp6b4g.js} +3 -3
  47. package/dist/{cli-9k7mqz00.js → cli-ge593j7e.js} +30 -3
  48. package/dist/cli-h8w3fg83.js +17 -0
  49. package/dist/{cli-xvdgasgy.js → cli-hsem16hb.js} +114 -9
  50. package/dist/{cli-yvxfaem2.js → cli-hsk5gd15.js} +9 -5
  51. package/dist/{cli-7vz49g7h.js → cli-jxsgrnmq.js} +101 -4
  52. package/dist/{cli-b7y8113e.js → cli-k2v5x13t.js} +1 -1
  53. package/dist/{cli-bqrs5ycj.js → cli-m4csbs67.js} +2 -2
  54. package/dist/{cli-91r17hb1.js → cli-mzj3aqac.js} +3 -3
  55. package/dist/{cli-swrz3mj8.js → cli-n805bb98.js} +1 -1
  56. package/dist/{cli-sajr098b.js → cli-n8ybnv1k.js} +3 -3
  57. package/dist/{cli-e5qk3m2a.js → cli-nkjwe4z7.js} +19 -19
  58. package/dist/{cli-3ry5gx4f.js → cli-p2pjfq1r.js} +2 -2
  59. package/dist/{cli-61tbnjpf.js → cli-p8f7dqgt.js} +767 -541
  60. package/dist/{cli-r7eeddkq.js → cli-ph3145b7.js} +3 -3
  61. package/dist/cli-ppy4nnnh.js +168 -0
  62. package/dist/cli-r455yd58.js +832 -0
  63. package/dist/{cli-jv36y8wz.js → cli-rrbctenq.js} +1 -1
  64. package/dist/{cli-8xjst8q2.js → cli-s88my3br.js} +11 -11
  65. package/dist/{cli-vejds37t.js → cli-srmej5tp.js} +3 -3
  66. package/dist/{cli-eqfbsxsn.js → cli-tg8q0b5y.js} +14 -11
  67. package/dist/cli-w0zx9ya1.js +1351 -0
  68. package/dist/{cli-rh44xx46.js → cli-wfvedq5w.js} +15 -15
  69. package/dist/{cli-n4z21pt8.js → cli-x207g4w1.js} +1 -1
  70. package/dist/{cli-fyeft04q.js → cli-x3fy2tgp.js} +2 -2
  71. package/dist/{cli-7mhy3ths.js → cli-x61srfpp.js} +5 -5
  72. package/dist/{cli-w6xa5nf5.js → cli-y1j1ggbf.js} +8 -8
  73. package/dist/{cli-jvmtxqtc.js → cli-ywh2a87k.js} +7 -2
  74. package/dist/{cli-3qhyh31j.js → cli-ywm1azg9.js} +6 -0
  75. package/dist/{cli-z48ggfyq.js → cli-zxm9p3x4.js} +2 -2
  76. package/dist/cli.js +42 -24
  77. package/dist/{codex-adapter-0kpg09ca.js → codex-adapter-9ag75whm.js} +13 -13
  78. package/dist/{codex-hook-295jpbfa.js → codex-hook-7ba15hjd.js} +5 -3
  79. package/dist/{codex-login-g1cyt5zm.js → codex-login-841kv5fk.js} +7 -5
  80. package/dist/{codex-session-runner-8n672hxh.js → codex-session-runner-9fp7y4cf.js} +13 -13
  81. package/dist/{commands-mhmg5n0x.js → commands-d7eah0y9.js} +10 -10
  82. package/dist/controller-hq5ggpcp.js +193 -0
  83. package/dist/controllers-connect-8t0k65x2.js +265 -0
  84. package/dist/{cursor-adapter-wn8n5zzk.js → cursor-adapter-t4pr1m3c.js} +5 -5
  85. package/dist/db-2rmd23wq.js +71 -0
  86. package/dist/{db-wa6s1mwv.js → db-sp39qv72.js} +8 -8
  87. package/dist/{devin-adapter-bffjj5n4.js → devin-adapter-xgtj680j.js} +2 -2
  88. package/dist/{dispatcher-nhs2pkr8.js → dispatcher-g7fsybsd.js} +30 -28
  89. package/dist/docker-f503k9p0.js +201 -0
  90. package/dist/{dsh-adapter-5423p70m.js → dsh-adapter-2h8m4cab.js} +5 -5
  91. package/dist/e2b-66xra4az.js +202 -0
  92. package/dist/{e2b-nd50eccg.js → e2b-xwhyj8cw.js} +43 -527
  93. package/dist/{event-bus-vnfthafg.js → event-bus-vjtv82gm.js} +2 -2
  94. package/dist/{grok-adapter-28pkdt80.js → grok-adapter-1err1me7.js} +7 -7
  95. package/dist/{handlers-5rtf9nng.js → handlers-c7yggm37.js} +33 -31
  96. package/dist/heartbeat-dkm924fk.js +124 -0
  97. package/dist/{hook-qkm73zk6.js → hook-g8e7sfnf.js} +13 -13
  98. package/dist/{hook-krjfkpzy.js → hook-wgx4exw6.js} +20 -17
  99. package/dist/{http-a397xcn4.js → http-1d23k928.js} +1958 -205
  100. package/dist/{index-kqre45fr.js → index-gm10tmye.js} +30 -28
  101. package/dist/{index-rtxg15ah.js → index-q7cj9bn2.js} +39 -29
  102. package/dist/{index-vvsq7v45.js → index-va4zbvzp.js} +30 -28
  103. package/dist/{index-ac0v8v9d.js → index-vertaxs1.js} +8 -8
  104. package/dist/{index-ytdhtdry.js → index-y5vvczrs.js} +31 -22
  105. package/dist/{keepalive-psfh8ysx.js → keepalive-1jc5e7ct.js} +10 -10
  106. package/dist/{lead-m6rppjn7.js → lead-yxw2f1sg.js} +48 -46
  107. package/dist/{maintenance-41f837ke.js → maintenance-h7w2m10y.js} +8 -8
  108. package/dist/{node-8zkdq42h.js → node-c9we95xf.js} +9 -9
  109. package/dist/{oauth-refresh-sweep-6hr55hm8.js → oauth-refresh-sweep-wh9ypd1b.js} +9 -9
  110. package/dist/{onboard-ktrtd7cz.js → onboard-dfr9j762.js} +25 -15
  111. package/dist/{openai-codex-responses-jzxkta9b.js → openai-codex-responses-pgvtddvv.js} +3 -3
  112. package/dist/{openai-responses-m3g43rrt.js → openai-responses-9dyzwzkr.js} +9 -9
  113. package/dist/{opencode-adapter-yjyqynzf.js → opencode-adapter-f1zby94p.js} +3 -3
  114. package/dist/{otel-impl-dq4f2k3m.js → otel-impl-and31m5s.js} +5 -5
  115. package/dist/{pi-mono-adapter-e5v9w0hv.js → pi-mono-adapter-fx6k5wwh.js} +38 -27
  116. package/dist/{pricing-refresh-kmk7j1ra.js → pricing-refresh-23zr6j3w.js} +10 -10
  117. package/dist/{rbac-roles-9ykx9tc5.js → rbac-roles-nc7k9d0t.js} +10 -10
  118. package/dist/{rbac-roles-9w1dkkxd.js → rbac-roles-wnx35x4x.js} +11 -11
  119. package/dist/{render-v2-ycqm53np.js → render-v2-81cg1y52.js} +9 -9
  120. package/dist/{resume-cq2pkp8q.js → resume-d4b6j2n2.js} +16 -16
  121. package/dist/{setup-0dcmdvbn.js → setup-g68r1w28.js} +7 -5
  122. package/dist/static-t1gr2cr7.js +30 -0
  123. package/dist/{virtual-modules-1x9k4jcs.js → virtual-modules-rdjmcg7q.js} +3 -3
  124. package/dist/{work-objects-x01x2fh8.js → work-objects-0zzdnbt9.js} +35 -33
  125. package/dist/{worker-py1ssb1h.js → worker-p1g8qm6h.js} +48 -46
  126. package/dist/{x-ma4gnfgy.js → x-qfmygqqv.js} +2 -2
  127. package/openapi.json +3382 -167
  128. package/package.json +3 -3
  129. package/src/be/db/agents.ts +6 -0
  130. package/src/be/db/instance-signals.ts +30 -0
  131. package/src/be/db/tasks/read.ts +2 -0
  132. package/src/be/db/tasks/write.ts +39 -5
  133. package/src/be/db/workflow-runs.ts +22 -0
  134. package/src/be/db.ts +96 -40
  135. package/src/be/fleet-benchmark-stats.ts +39 -0
  136. package/src/be/migrations/205_favorites_per_dashboard_user.sql +29 -0
  137. package/src/be/migrations/206_runtime_pools.sql +62 -0
  138. package/src/be/migrations/207_runtime_session_tokens.sql +31 -0
  139. package/src/be/migrations/208_task_runtime_dispatch.sql +4 -0
  140. package/src/be/model-tier-resolution.ts +9 -2
  141. package/src/be/multi-runtime.ts +102 -13
  142. package/src/be/org-profile.ts +35 -0
  143. package/src/be/rbac-audit.ts +4 -0
  144. package/src/be/runtime-pools/controllers.ts +150 -0
  145. package/src/be/runtime-pools/db.ts +526 -0
  146. package/src/be/runtime-pools/demand.ts +65 -0
  147. package/src/be/runtime-pools/e2b-images.ts +109 -0
  148. package/src/be/runtime-pools/errors.ts +8 -0
  149. package/src/be/runtime-pools/lifecycle.ts +44 -0
  150. package/src/be/runtime-pools/reachability.ts +30 -0
  151. package/src/be/runtime-pools/recovery.ts +248 -0
  152. package/src/be/runtime-pools/remote-controller.ts +144 -0
  153. package/src/be/runtime-pools/routing.ts +304 -0
  154. package/src/be/runtime-pools/seed.ts +110 -0
  155. package/src/be/runtime-pools/supervisor.ts +981 -0
  156. package/src/be/runtime-pools/tokens.ts +57 -0
  157. package/src/be/scripts/typecheck.ts +48 -3
  158. package/src/be/secret-registry.ts +17 -1
  159. package/src/be/skill-usage.ts +467 -0
  160. package/src/be/swarm-config-guard.ts +59 -2
  161. package/src/be/telemetry-enable.ts +66 -0
  162. package/src/be/telemetry-ingest-anchor.ts +77 -0
  163. package/src/be/users.ts +173 -23
  164. package/src/be/worker-nudge-listener.ts +28 -0
  165. package/src/be/worker-nudges.ts +22 -0
  166. package/src/cli.tsx +22 -3
  167. package/src/commands/controller.ts +180 -0
  168. package/src/commands/onboard/non-interactive.ts +36 -12
  169. package/src/commands/onboard/types.ts +1 -1
  170. package/src/commands/onboard.tsx +3 -0
  171. package/src/commands/push-delivery.ts +230 -0
  172. package/src/commands/runner.ts +560 -276
  173. package/src/e2b/dispatch.ts +15 -1
  174. package/src/extensions/contract-types.generated.ts +1 -1
  175. package/src/fleet-benchmark.ts +157 -0
  176. package/src/heartbeat/heartbeat.ts +53 -135
  177. package/src/hooks/hook.ts +3 -2
  178. package/src/http/agents.ts +21 -0
  179. package/src/http/all-routes.ts +6 -0
  180. package/src/http/apps.ts +4 -2
  181. package/src/http/auth.ts +4 -7
  182. package/src/http/config.ts +58 -21
  183. package/src/http/controllers-connect.ts +206 -0
  184. package/src/http/core.ts +108 -14
  185. package/src/http/favorite-owner.ts +31 -1
  186. package/src/http/fleet-benchmark.ts +206 -0
  187. package/src/http/index.ts +38 -6
  188. package/src/http/mcp.ts +3 -8
  189. package/src/http/poll.ts +31 -2
  190. package/src/http/realtime.ts +1 -1
  191. package/src/http/request-principal.ts +2 -0
  192. package/src/http/runtime-pools.ts +527 -0
  193. package/src/http/session-data.ts +2 -0
  194. package/src/http/sessions.ts +100 -23
  195. package/src/http/skills.ts +173 -0
  196. package/src/http/status.ts +25 -1
  197. package/src/http/tasks.ts +14 -1
  198. package/src/http/telemetry-ui.ts +102 -0
  199. package/src/http/used-by.ts +140 -0
  200. package/src/http/utils.ts +7 -1
  201. package/src/http/workflows.ts +10 -2
  202. package/src/jira/app.ts +1 -2
  203. package/src/kv-reserved-namespaces.ts +1 -0
  204. package/src/linear/app.ts +1 -2
  205. package/src/providers/acp-target-catalog.ts +75 -1
  206. package/src/providers/acp-targets.ts +114 -0
  207. package/src/providers/amp-adapter.ts +1 -1
  208. package/src/providers/claude-adapter.ts +1 -1
  209. package/src/providers/codex-adapter.ts +5 -1
  210. package/src/providers/opencode-adapter.ts +2 -1
  211. package/src/providers/pi-mono-adapter.ts +41 -26
  212. package/src/providers/pricing-sources.md +2 -0
  213. package/src/providers/skill-invoke.ts +39 -3
  214. package/src/rbac/legacy-policy.ts +8 -0
  215. package/src/rbac/permissions.ts +16 -0
  216. package/src/rbac/types.ts +2 -0
  217. package/src/realtime/auth.ts +13 -0
  218. package/src/realtime/channels.ts +24 -0
  219. package/src/realtime/transport.ts +94 -15
  220. package/src/realtime/worker-client.ts +176 -0
  221. package/src/runtime-providers/controller-protocol.ts +97 -0
  222. package/src/runtime-providers/controller.ts +86 -0
  223. package/src/runtime-providers/docker.ts +235 -0
  224. package/src/runtime-providers/e2b.ts +217 -0
  225. package/src/runtime-providers/index.ts +37 -0
  226. package/src/runtime-providers/static.ts +26 -0
  227. package/src/runtime-providers/types.ts +92 -0
  228. package/src/runtime-providers/worker-api-url.ts +11 -0
  229. package/src/scripts-runtime/sdk-allowlist.ts +6 -0
  230. package/src/scripts-runtime/types/stdlib.d.ts +15 -0
  231. package/src/scripts-runtime/types/swarm-extension.d.ts +1 -0
  232. package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
  233. package/src/server.ts +12 -0
  234. package/src/slack/router.ts +7 -5
  235. package/src/tasks/worker-follow-up.ts +80 -52
  236. package/src/telemetry-context.ts +6 -0
  237. package/src/telemetry-contract/EVENTS.md +14 -1
  238. package/src/telemetry-contract/SOURCE.json +4 -4
  239. package/src/telemetry-contract/catalog.json +155 -0
  240. package/src/telemetry-contract/types.gen.ts +248 -4
  241. package/src/telemetry-ui-events.ts +130 -0
  242. package/src/telemetry.ts +43 -3
  243. package/src/tests/acp-adapter.test.ts +129 -0
  244. package/src/tests/claude-adapter.test.ts +6 -2
  245. package/src/tests/codex-adapter.test.ts +6 -2
  246. package/src/tests/config-internal-keys.test.ts +27 -0
  247. package/src/tests/config-session-auth.test.ts +19 -3
  248. package/src/tests/db-retention.test.ts +50 -10
  249. package/src/tests/docs-index-footprint.test.js +3 -3
  250. package/src/tests/e2b-dispatch.test.ts +28 -1
  251. package/src/tests/e2e-runtime-pools.test.ts +51 -0
  252. package/src/tests/entrypoint-acp-target-binary.test.ts +38 -1
  253. package/src/tests/favorites.test.ts +188 -0
  254. package/src/tests/fetch-resolved-env.test.ts +59 -1
  255. package/src/tests/fleet-benchmark.test.ts +453 -0
  256. package/src/tests/harness-model-support.test.ts +70 -2
  257. package/src/tests/heartbeat-orphan-resume.test.ts +24 -0
  258. package/src/tests/heartbeat-reboot-live.test.ts +31 -0
  259. package/src/tests/heartbeat-supersede-resume.test.ts +21 -0
  260. package/src/tests/hook-runtime-close.test.ts +64 -0
  261. package/src/tests/http-task-write-ownership.test.ts +8 -1
  262. package/src/tests/integration-disable-flags.test.ts +45 -0
  263. package/src/tests/migration-206-runtime-pools.test.ts +134 -0
  264. package/src/tests/migration-207-runtime-session-tokens.test.ts +45 -0
  265. package/src/tests/migration-208-task-runtime-dispatch.test.ts +30 -0
  266. package/src/tests/multi-runtime-registration.test.ts +219 -4
  267. package/src/tests/onboard-non-interactive.test.ts +104 -6
  268. package/src/tests/opencode-adapter.test.ts +6 -2
  269. package/src/tests/org-website.test.ts +115 -0
  270. package/src/tests/pi-mono-adapter.test.ts +74 -10
  271. package/src/tests/rbac-admission-e2e.test.ts +4 -4
  272. package/src/tests/rbac-engine.test.ts +8 -1
  273. package/src/tests/realtime-room-auth.test.ts +49 -0
  274. package/src/tests/repo-allow-merge-gate.test.ts +8 -1
  275. package/src/tests/runner-exit-after-tasks.test.ts +163 -0
  276. package/src/tests/runner-finish-retry.test.ts +466 -0
  277. package/src/tests/runner-harness-telemetry-env.test.ts +105 -0
  278. package/src/tests/runner-push-delivery.test.ts +670 -0
  279. package/src/tests/runner-slot-reconcile.test.ts +89 -1
  280. package/src/tests/runtime-child-token-cleanup.test.ts +172 -0
  281. package/src/tests/runtime-controller-token.test.ts +254 -0
  282. package/src/tests/runtime-demand.test.ts +119 -0
  283. package/src/tests/runtime-e2b-pools.test.ts +847 -0
  284. package/src/tests/runtime-pool-reachability.test.ts +328 -0
  285. package/src/tests/runtime-pool-routing.test.ts +817 -0
  286. package/src/tests/runtime-pools-db.test.ts +275 -0
  287. package/src/tests/runtime-pools-http.test.ts +506 -0
  288. package/src/tests/runtime-pools-ownership-guards.test.ts +235 -0
  289. package/src/tests/runtime-pools-seed.test.ts +203 -0
  290. package/src/tests/runtime-pools-test-utils.ts +128 -0
  291. package/src/tests/runtime-provider-registration.test.ts +133 -0
  292. package/src/tests/runtime-providers-docker.test.ts +400 -0
  293. package/src/tests/runtime-providers-e2b-transport.test.ts +50 -0
  294. package/src/tests/runtime-providers-e2b.test.ts +335 -0
  295. package/src/tests/runtime-recovery.test.ts +745 -0
  296. package/src/tests/runtime-remote-controller.test.ts +846 -0
  297. package/src/tests/runtime-supervisor-failures.test.ts +387 -0
  298. package/src/tests/runtime-supervisor.test.ts +1039 -0
  299. package/src/tests/runtime-token-auth.test.ts +897 -0
  300. package/src/tests/script-connections.test.ts +7 -0
  301. package/src/tests/secret-scrubber.test.ts +17 -2
  302. package/src/tests/session-costs-codex-recompute.test.ts +49 -0
  303. package/src/tests/session-tokens.test.ts +13 -3
  304. package/src/tests/skill-invoke.test.ts +142 -0
  305. package/src/tests/skill-usage-cohorts.test.ts +232 -0
  306. package/src/tests/skill-usage.test.ts +348 -0
  307. package/src/tests/slack-attachments-block.test.ts +23 -0
  308. package/src/tests/slack-render-v2.test.ts +6 -0
  309. package/src/tests/status-instance.test.ts +71 -0
  310. package/src/tests/task-supersede-resume.test.ts +87 -4
  311. package/src/tests/telemetry-enable.test.ts +113 -0
  312. package/src/tests/telemetry-ui-route.test.ts +195 -0
  313. package/src/tests/tool-annotations.test.ts +1 -1
  314. package/src/tests/used-by-route.test.ts +237 -0
  315. package/src/tests/worker-nudges.test.ts +653 -0
  316. package/src/tests/worker-realtime-client.test.ts +188 -0
  317. package/src/tests/workflow-sub-workflow.test.ts +22 -0
  318. package/src/tools/app-upsert.ts +1 -1
  319. package/src/tools/runtime-controller-list.ts +28 -0
  320. package/src/tools/runtime-pool-bind-agent.ts +29 -0
  321. package/src/tools/runtime-pool-common.ts +37 -0
  322. package/src/tools/runtime-pool-create-agent.ts +29 -0
  323. package/src/tools/runtime-pool-delete.ts +27 -0
  324. package/src/tools/runtime-pool-list.ts +27 -0
  325. package/src/tools/runtime-pool-upsert.ts +31 -0
  326. package/src/tools/script-common.ts +1 -1
  327. package/src/tools/send-task.ts +3 -2
  328. package/src/tools/tool-config.ts +6 -0
  329. package/src/types.ts +137 -2
  330. package/src/utils/config-secrets.ts +1 -0
  331. package/src/utils/lead-monitor-channels.ts +3 -0
  332. package/src/utils/org-website.ts +104 -0
  333. package/src/utils/request-auth-context.ts +10 -2
  334. package/src/utils/runtime-pools-flag.ts +11 -0
  335. package/src/utils/secret-scrubber.ts +9 -0
  336. package/src/utils/session-token-connections.ts +20 -0
  337. package/templates/skills/apps/content.md +1 -1
  338. package/templates/skills/code-quality/content.md +9 -1
  339. package/templates/skills/db-query-guidance/content.md +9 -0
  340. package/templates/skills/swarm-scripts/SKILL.md +1 -1
  341. package/templates/skills/swarm-scripts/content.md +1 -1
  342. package/templates/skills/work-on-task/SKILL.md +1 -1
  343. package/templates/skills/work-on-task/content.md +1 -1
  344. package/dist/{cli-qd97v6z2.js → cli-1qtgd1h1.js} +3 -3
  345. package/dist/{cli-cmxkbzzs.js → cli-j0w59p15.js} +6 -6
  346. package/dist/{google-generative-ai-b8zxrpax.js → google-generative-ai-pvhm0dq1.js} +1 -1
  347. package/dist/{google-vertex-nrdd697t.js → google-vertex-tek9sqe2.js} +4 -4
  348. package/dist/{mistral-conversations-059y51zt.js → mistral-conversations-rjxa9s1j.js} +3 -3
  349. package/dist/{openai-completions-663yncfq.js → openai-completions-44gb0zsk.js} +12 -12
package/src/types.ts CHANGED
@@ -6,6 +6,7 @@ import { normalizeAssetKey } from "./assets/key";
6
6
  import { isSafeBundlePath } from "./extensions/bundle-path";
7
7
  import { MAX_PROFILE_FILE_LENGTH } from "./utils/constants";
8
8
  import { z } from "./utils/zod-openapi";
9
+
9
10
  // ─── Asset namespaces ──────────────────────────────────────────────────────
10
11
 
11
12
  export const AssetKeySchema = z
@@ -594,6 +595,7 @@ export const AgentTaskSchema = z
594
595
  "Origin of the routing reason: declared by the caller or chosen by the engine. Absent for unknown historical provenance or no reason.",
595
596
  ),
596
597
  routingNote: z.string().max(200).optional(),
598
+ poolWakeAt: z.string().optional(),
597
599
 
598
600
  // Task metadata
599
601
  taskType: z.string().max(50).optional(), // e.g., "bug", "feature", "chore"
@@ -1158,6 +1160,9 @@ export const AgentSchema = z
1158
1160
  name: z.string().min(1),
1159
1161
  isLead: z.boolean().default(false),
1160
1162
  status: AgentStatusSchema,
1163
+ runtimePoolId: z.string().nullable().optional(),
1164
+ runtimeProvisionAttempts: z.number().int().min(0).optional(),
1165
+ runtimeProvisionRetryAt: z.string().nullable().optional(),
1161
1166
 
1162
1167
  // Profile fields
1163
1168
  description: z.string().optional(),
@@ -1321,7 +1326,7 @@ export type AcpSessionConfigOption = z.infer<typeof AcpSessionConfigOptionSchema
1321
1326
 
1322
1327
  export const AgentAcpStatusSchema = z
1323
1328
  .object({
1324
- target: z.enum(["opencode", "gemini", "copilot", "custom"]),
1329
+ target: z.enum(["opencode", "gemini", "copilot", "qwen", "kiro", "goose", "custom"]),
1325
1330
  configOptions: z.array(AcpSessionConfigOptionSchema),
1326
1331
  reportedAt: z.number(),
1327
1332
  })
@@ -1959,12 +1964,120 @@ export type ActiveSession = z.infer<typeof ActiveSessionSchema>;
1959
1964
  // Runtime Instance Types (multi-runtime worker tracking)
1960
1965
  // ============================================================================
1961
1966
 
1967
+ export const WorkerNudgeSchema = z.object({
1968
+ v: z.literal(1),
1969
+ kind: z.enum(["work", "cancel", "steer", "config"]),
1970
+ taskId: z.string().optional(),
1971
+ at: z.iso.datetime(),
1972
+ });
1973
+ export type WorkerNudge = z.infer<typeof WorkerNudgeSchema>;
1974
+
1962
1975
  /**
1963
1976
  * Lifecycle of a runtime instance. Zod is the source of truth for the allowed
1964
1977
  * values — the SQL column has no CHECK constraint (migration 132) so adding a
1965
1978
  * state doesn't require a table rebuild.
1966
1979
  */
1967
- export const RuntimeInstanceStatusSchema = z.enum(["active", "offline"]);
1980
+ export const RuntimeInstanceStatusSchema = z.enum(["active", "offline", "provisioning"]);
1981
+
1982
+ /**
1983
+ * Infrastructure kind a runtime pool provisions on. `k8s` is reserved: write
1984
+ * paths reject it until its adapter exists.
1985
+ */
1986
+ export const RuntimeProviderKindSchema = z.enum(["static", "docker", "e2b", "k8s"]);
1987
+ export type RuntimeProviderKind = z.infer<typeof RuntimeProviderKindSchema>;
1988
+
1989
+ export const DeliveryModeSchema = z.enum(["poll", "push"]);
1990
+ export type DeliveryMode = z.infer<typeof DeliveryModeSchema>;
1991
+ export const PoolLifecycleSchema = z.enum(["idle", "per-task"]);
1992
+ const RuntimeResourcesSchema = z
1993
+ .object({
1994
+ cpu: z.number().positive().optional(),
1995
+ memoryMb: z.number().int().positive().optional(),
1996
+ })
1997
+ .strict();
1998
+
1999
+ export const RuntimeControllerCreateSchema = z
2000
+ .object({
2001
+ name: z.string().min(1).max(200),
2002
+ kind: RuntimeProviderKindSchema,
2003
+ placement: z.enum(["builtin", "remote"]).default("remote"),
2004
+ config: z.record(z.string(), z.string()).default({}),
2005
+ secretConfig: z.record(z.string(), z.string().nullable()).optional(),
2006
+ })
2007
+ .strict();
2008
+ export const RuntimeControllerUpdateSchema = RuntimeControllerCreateSchema.partial().extend({
2009
+ placement: z.enum(["builtin", "remote"]).optional(),
2010
+ config: z.record(z.string(), z.string()).optional(),
2011
+ });
2012
+ export const RuntimeControllerSchema = RuntimeControllerCreateSchema.omit({ secretConfig: true })
2013
+ .extend({
2014
+ id: z.string(),
2015
+ secretConfigKeys: z.array(z.string()),
2016
+ secretConfigError: z.boolean().optional(),
2017
+ status: z.enum(["online", "offline", "unknown"]),
2018
+ lastSeenAt: z.string().nullable(),
2019
+ lastError: z.string().nullable(),
2020
+ lastErrorAt: z.string().nullable(),
2021
+ createdBy: z.string().nullable(),
2022
+ updatedBy: z.string().nullable(),
2023
+ createdAt: z.string(),
2024
+ updatedAt: z.string(),
2025
+ })
2026
+ .openapi("RuntimeController");
2027
+ export type RuntimeController = z.infer<typeof RuntimeControllerSchema>;
2028
+
2029
+ export const RuntimePoolCreateSchema = z
2030
+ .object({
2031
+ name: z.string().min(1).max(200),
2032
+ kind: RuntimeProviderKindSchema,
2033
+ placements: z.array(z.string().min(1)).length(1),
2034
+ image: z.string().min(1).nullable().optional(),
2035
+ lifecycle: PoolLifecycleSchema.default("idle"),
2036
+ idleMinutes: z.number().int().positive().nullable().default(null),
2037
+ slotsPerRuntime: z.number().int().min(1).default(1),
2038
+ maxRuntimes: z.number().int().min(0).nullable().default(null),
2039
+ minRuntimes: z.number().int().min(0).default(0),
2040
+ delivery: DeliveryModeSchema.nullable().default(null),
2041
+ env: z.record(z.string(), z.string()).default({}),
2042
+ resources: RuntimeResourcesSchema.nullable().default(null),
2043
+ ttlSec: z.number().int().positive().nullable().default(null),
2044
+ enabled: z.boolean().default(true),
2045
+ })
2046
+ .strict();
2047
+ export const RuntimePoolUpdateSchema = RuntimePoolCreateSchema.partial().extend({
2048
+ lifecycle: PoolLifecycleSchema.optional(),
2049
+ idleMinutes: z.number().int().positive().nullable().optional(),
2050
+ slotsPerRuntime: z.number().int().min(1).optional(),
2051
+ maxRuntimes: z.number().int().min(0).nullable().optional(),
2052
+ minRuntimes: z.number().int().min(0).optional(),
2053
+ delivery: DeliveryModeSchema.nullable().optional(),
2054
+ env: z.record(z.string(), z.string()).optional(),
2055
+ resources: RuntimeResourcesSchema.nullable().optional(),
2056
+ ttlSec: z.number().int().positive().nullable().optional(),
2057
+ enabled: z.boolean().optional(),
2058
+ });
2059
+ export const RuntimePoolSchema = RuntimePoolCreateSchema.extend({
2060
+ id: z.string(),
2061
+ resolvedImage: z.string().nullable(),
2062
+ consecutiveFailures: z.number().int(),
2063
+ circuitOpenUntil: z.string().nullable(),
2064
+ lastError: z.string().nullable(),
2065
+ lastErrorAt: z.string().nullable(),
2066
+ createdBy: z.string().nullable(),
2067
+ updatedBy: z.string().nullable(),
2068
+ createdAt: z.string(),
2069
+ updatedAt: z.string(),
2070
+ }).openapi("RuntimePool");
2071
+ export type RuntimePool = z.infer<typeof RuntimePoolSchema>;
2072
+ export const RuntimePoolCreateAgentSchema = z
2073
+ .object({
2074
+ name: z.string().min(1),
2075
+ isLead: z.boolean().optional(),
2076
+ harnessProvider: ProviderNameSchema.optional(),
2077
+ maxTasks: z.number().int().min(1).max(100).optional(),
2078
+ templateId: z.string().min(1).optional(),
2079
+ })
2080
+ .strict();
1968
2081
 
1969
2082
  /**
1970
2083
  * One worker process serving a logical agent. The `agents` row (AGENT_ID /
@@ -1979,6 +2092,16 @@ export const RuntimeInstanceSchema = z
1979
2092
  id: z.string(),
1980
2093
  agentId: z.string(),
1981
2094
  status: RuntimeInstanceStatusSchema,
2095
+ poolId: z.string().nullable().optional(),
2096
+ controllerId: z.string().nullable().optional(),
2097
+ externalHandle: z.record(z.string(), z.unknown()).nullable().optional(),
2098
+ provisionAttempts: z.number().int().optional(),
2099
+ provisionError: z.string().nullable().optional(),
2100
+ provisionRequestedAt: z.string().nullable().optional(),
2101
+ draining: z.boolean().optional(),
2102
+ idleSince: z.string().nullable().optional(),
2103
+ leaseExpiresAt: z.string().nullable().optional(),
2104
+ taskId: z.string().nullable().optional(),
1982
2105
  /** Runtime-local concurrent task capacity, self-reported at registration. */
1983
2106
  reportedSlots: z.number().int(),
1984
2107
  /** Process-local credential readiness; null when never reported. */
@@ -2710,8 +2833,20 @@ export const WorkflowRunSchema = z
2710
2833
  startedAt: z.string(),
2711
2834
  lastUpdatedAt: z.string(),
2712
2835
  finishedAt: z.string().optional(),
2836
+ /** The `sub-workflow` step that started this run. Unset on a top-level run. */
2837
+ parentStepId: z.string().optional(),
2713
2838
  })
2714
2839
  .openapi("WorkflowRun");
2840
+
2841
+ /** The run and `sub-workflow` step that started a child run. */
2842
+ export const WorkflowRunParentSchema = z
2843
+ .object({
2844
+ runId: z.string(),
2845
+ workflowId: z.string(),
2846
+ stepId: z.string(),
2847
+ nodeId: z.string(),
2848
+ })
2849
+ .openapi("WorkflowRunParent");
2715
2850
  export type WorkflowRun = z.infer<typeof WorkflowRunSchema>;
2716
2851
 
2717
2852
  /** List row of a run: no `context`, which `GET /api/workflow-runs/{id}` serves. */
@@ -0,0 +1 @@
1
+ export const MASKED_SECRET_VALUE = "********";
@@ -0,0 +1,3 @@
1
+ export function isLeadChannelMonitoringEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
2
+ return env.LEAD_MONITOR_CHANNELS === "true";
3
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The organization's website (`SWARM_ORG_WEBSITE`), shared by the API server
3
+ * and the dashboard. Pure: no DB, no network.
4
+ *
5
+ * Stored as a bare lowercase hostname. It feeds the telemetry `org_website`
6
+ * context field, the "used by" consent, and the org logo, which the telemetry
7
+ * proxy serves from logo.dev so the logo.dev key never leaves the proxy.
8
+ */
9
+
10
+ const LABEL = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
11
+ const IPV4 = /^\d{1,3}(\.\d{1,3}){3}$/;
12
+ const BLOCKED_SUFFIXES = [".local", ".internal", ".localhost", ".lan", ".home", ".test"];
13
+
14
+ /** Default telemetry proxy origin. */
15
+ export const TELEMETRY_PROXY_ORIGIN = "https://proxy.desplega.sh";
16
+
17
+ /**
18
+ * Normalize what someone typed as their company website to a bare hostname:
19
+ * lowercase, no scheme, `www.`, path, port, query or trailing dot. Null when it
20
+ * is not a public hostname: an IP literal, `localhost`, a single label, a
21
+ * `.local` / `.internal` style name, or anything over 253 characters.
22
+ */
23
+ export function normalizeOrgWebsite(raw: string | null | undefined): string | null {
24
+ let value = raw?.trim().toLowerCase();
25
+ if (!value) return null;
26
+ if (!/^[a-z][a-z0-9+.-]*:\/\//.test(value)) value = `https://${value}`;
27
+ let host: string;
28
+ try {
29
+ const url = new URL(value);
30
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
31
+ if (url.username || url.password) return null;
32
+ host = url.hostname;
33
+ } catch {
34
+ return null;
35
+ }
36
+ host = host.replace(/\.$/, "");
37
+ if (host.startsWith("www.")) host = host.slice(4);
38
+ if (!host || host.length > 253) return null;
39
+ if (host.startsWith("[") || IPV4.test(host)) return null;
40
+ const labels = host.split(".");
41
+ if (labels.length < 2) return null;
42
+ if (!labels.every((label) => label.length <= 63 && LABEL.test(label))) return null;
43
+ if (/^\d+$/.test(labels.at(-1) ?? "")) return null;
44
+ if (BLOCKED_SUFFIXES.some((suffix) => host.endsWith(suffix))) return null;
45
+ return host;
46
+ }
47
+
48
+ /** The proxy URL that serves the logo for `host`. */
49
+ export function orgLogoUrl(host: string, origin = TELEMETRY_PROXY_ORIGIN): string {
50
+ return `${origin.replace(/\/+$/, "")}/v1/logo?domain=${encodeURIComponent(host)}`;
51
+ }
52
+
53
+ /**
54
+ * Whether `url` has the shape of a logo URL `orgLogoUrl` builds for `origin`:
55
+ * the proxy origin itself, never just a matching path on another host.
56
+ */
57
+ export function isFilledOrgLogoUrl(
58
+ url: string | null | undefined,
59
+ origin = TELEMETRY_PROXY_ORIGIN,
60
+ ): boolean {
61
+ if (!url) return false;
62
+ try {
63
+ const parsed = new URL(url);
64
+ return (
65
+ parsed.origin === new URL(origin).origin &&
66
+ parsed.pathname === "/v1/logo" &&
67
+ parsed.searchParams.has("domain")
68
+ );
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ const FREE_MAIL_DOMAINS = new Set([
75
+ "gmail.com",
76
+ "googlemail.com",
77
+ "outlook.com",
78
+ "hotmail.com",
79
+ "live.com",
80
+ "msn.com",
81
+ "yahoo.com",
82
+ "icloud.com",
83
+ "me.com",
84
+ "mac.com",
85
+ "aol.com",
86
+ "proton.me",
87
+ "protonmail.com",
88
+ "gmx.com",
89
+ "gmx.de",
90
+ "yandex.com",
91
+ "yandex.ru",
92
+ "mail.com",
93
+ "zoho.com",
94
+ "qq.com",
95
+ "163.com",
96
+ "hey.com",
97
+ "fastmail.com",
98
+ ]);
99
+
100
+ /** The admin's email domain as a website suggestion, or null for free-mail domains. */
101
+ export function websiteSuggestion(orgDomain: string | null | undefined): string | null {
102
+ const host = normalizeOrgWebsite(orgDomain);
103
+ return host && !FREE_MAIL_DOMAINS.has(host) ? host : null;
104
+ }
@@ -7,8 +7,16 @@ export type HttpRequestAuth = (
7
7
  | { kind: "user"; userId: string; user: User }
8
8
  /** Password-page viewer with no user identity. Least privilege: every gate denies it. */
9
9
  | { kind: "guest" }
10
- /** Ephemeral session token minted by the ACP adapter per session (aseph_ prefix). */
11
- | { kind: "agent"; agentId: string; taskId: string }
10
+ | { kind: "controller"; controllerId: string; tokenId: string; expiresAt: string }
11
+ /** Ephemeral token bound to an ACP task or a worker runtime (aseph_ prefix). */
12
+ | {
13
+ kind: "agent";
14
+ agentId: string;
15
+ taskId: string | null;
16
+ runtimeId: string | null;
17
+ tokenId: string;
18
+ expiresAt: string;
19
+ }
12
20
  ) & {
13
21
  /** Verified page context for agent-scoped operations. This does not identify the viewer. */
14
22
  page?: { id: string; executionAgentId: string };
@@ -0,0 +1,11 @@
1
+ import { isEnvFlagEnabled } from "./env-flag";
2
+
3
+ /**
4
+ * `RUNTIME_POOLS_ENABLED` (default off) gates the whole push-workers feature:
5
+ * the runtime supervisor, pool routing, worker nudges, the pool/controller
6
+ * routes and tools, and the dashboard pages. Read it per call so a
7
+ * `swarm_config` reload takes effect.
8
+ */
9
+ export function isRuntimePoolsEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
10
+ return isEnvFlagEnabled("RUNTIME_POOLS_ENABLED", false, env);
11
+ }
@@ -1031,6 +1031,15 @@ export function registerVolatileSecret(value: string, name: string): void {
1031
1031
  }
1032
1032
  }
1033
1033
 
1034
+ /** Remove a short-lived secret and its encoded forms after credential revocation. */
1035
+ export function unregisterVolatileSecret(name: string): void {
1036
+ for (const [value, registeredName] of volatileSecrets) {
1037
+ if (registeredName !== name) continue;
1038
+ volatileSecrets.delete(value);
1039
+ volatileGeneration++;
1040
+ }
1041
+ }
1042
+
1034
1043
  /**
1035
1044
  * Mark a key name as sensitive at runtime (a swarm_config row with
1036
1045
  * isSecret=1 whose name matches no suffix rule). Its process.env value joins
@@ -0,0 +1,20 @@
1
+ const connections = new Map<string, Set<() => void>>();
2
+
3
+ export function registerSessionTokenConnection(tokenId: string, close: () => void): () => void {
4
+ let callbacks = connections.get(tokenId);
5
+ if (!callbacks) {
6
+ callbacks = new Set();
7
+ connections.set(tokenId, callbacks);
8
+ }
9
+ callbacks.add(close);
10
+ return () => {
11
+ callbacks.delete(close);
12
+ if (callbacks.size === 0) connections.delete(tokenId);
13
+ };
14
+ }
15
+
16
+ export function closeSessionTokenConnections(tokenIds: string[]): void {
17
+ for (const tokenId of tokenIds) {
18
+ for (const close of connections.get(tokenId) ?? []) close();
19
+ }
20
+ }
@@ -86,7 +86,7 @@ Use `{ "$state": "/user/<field>" }` on a page for the read-only current-user bin
86
86
 
87
87
  ### Theming
88
88
 
89
- 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`. 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.
89
+ 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.
90
90
 
91
91
  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.
92
92
 
@@ -71,7 +71,15 @@ The Repository Guidelines carry `allowMerge` and `mergeChecks`.
71
71
  A regression test must fail on the pre-fix code for the intended reason and pass after the repair. A regression test that never demonstrably failed does not prove the fix.
72
72
  6. Apply the "Review Guidance" entries from the Repository Guidelines.
73
73
  7. Read the diff for security (injection, secrets in code), logic (null handling, off-by-one, edge cases), performance (N+1, leaks), and code shape (naming, duplication, error handling). Run the test suite and the type check locally when you can.
74
- 8. Post the review with the verdict first. One finding per comment, with file and line, and what to change.
74
+ 8. Post the review with the verdict first. One finding per comment, with file and line, and what to change. When a finding is a pattern (a missing guard, a call shape, a test-only export), grep the whole PR diff for the same pattern and list every instance in that finding, so one fix round clears the class.
75
+
76
+ 9. Self-authored PR. GitHub refuses APPROVE and REQUEST_CHANGES when the reviewing account authored the PR. Compare `gh pr view <n> --json author --jq .author.login` with `gh api user --jq .login` before you submit. Same login: post one COMMENT whose first line is the verdict (`APPROVE` or `REQUEST_CHANGES`), then one line saying a formal review is blocked because this account authored the PR.
77
+ 10. Optimistic UI mutations (toggles, favorites, pins). Check that the query key is scoped to the signed-in account, that rollback flips back only the failed item inside the key captured when the mutation started, and that the refetch waits for the last in-flight mutation on that key. Ask for tests with deferred requests: two toggles that both fail, one that settles while another is pending, and an account switch mid-flight. Run them against the old head too: they must fail there.
78
+ 11. A resolved thread is not a fixed finding. Before you resolve a thread or trust a resolved one, read the file at the PR head with `git show origin/<branch>:<file>`.
79
+ 12. A bot acknowledgment carries no change request. Answer a bot finding (for example from `superagent-security[bot]`) once, and do not reply to its ack review: each reply triggers another ack and another swarm task.
80
+ 13. Human verdicts live in the reviews endpoint. `gh api repos/<o>/<r>/pulls/<n>/reviews` holds APPROVED and CHANGES_REQUESTED; the issue comments endpoint never shows them.
81
+ 14. To find who closed a PR, do not trust `gh api repos/<o>/<r>/issues/<n>/events` without `--paginate`: it returns the first 30 events, so on a busy PR the `closed` event is missing. Use GraphQL `timelineItems(itemTypes:[CLOSED_EVENT])`.
82
+ 15. Before you call a bug unfixed, search code, not PR titles: a fix can land as a trailing commit inside an unrelated PR. Use `git log origin/main -S'<symbol>'` and the open PRs' diffs.
75
83
 
76
84
  ## GitHub review-reply provenance
77
85
 
@@ -38,6 +38,15 @@ For these four tables:
38
38
  If you need a row total or a column type census, ask the lead. Do not derive
39
39
  it yourself by scanning the table.
40
40
 
41
+ ## Columns audits guess wrong
42
+
43
+ Run `SELECT name FROM pragma_table_info('<table>')` before you guess a column.
44
+
45
+ - `agent_tasks`: no cost column and no `metadata` column. Cost is `session_costs.totalCostUsd`, joined on `taskId`. Assignee `agentId`, creator `creatorAgentId`, model `model`, `resolvedModel`, `modelSource`. `parentTaskId` is the only SQL child finder, because `key` is unique per task.
46
+ - `scripts`: the owner is `createdByAgentId`; there is no `agentId`. `isScratch = 1` marks inline `script-run` bodies (`scratch-*` names), and they outnumber named scripts many times over. Add `isScratch = 0` to catalog audits. To find a script's callers, group by `isScratch` instead of dropping scratch rows: inline runs are often the negative tests.
47
+ - `script_runs`: `scriptName`, `agentId`, `status`, `startedAt`, `finishedAt`, `error`. There is no duration column: use `(julianday(finishedAt) - julianday(startedAt)) * 86400`.
48
+ - `session_costs`: `taskId`, `agentId`, `totalCostUsd`, `model`, the token columns, `createdAt`.
49
+
41
50
  ## Operator config knobs
42
51
 
43
52
  All are read dynamically (a `swarm_config` edit or env var change takes
@@ -69,7 +69,7 @@ export default async function (args: z.infer<typeof argsSchema>, ctx: ScriptCont
69
69
  - `agentId` is propagated through the `X-Agent-ID` header, so SDK calls run as you. `taskId` is not ambient: pass it in `args` when the script calls `task_storeProgress`.
70
70
  - A script invoked from a workflow node may run under a workflow identity.
71
71
  - Return compact structured data. Raw logs, full HTML, big JSON arrays, and file contents stay inside the script.
72
- - Limits: about 30 s wall clock (up to 5 minutes where the tool exposes it), 1 MB stdout. Never sleep or loop past about 25 s. Chain `wait-for-task` calls instead.
72
+ - Limits: about 30 s wall clock (up to 5 minutes where the tool exposes it), 1 MB stdout. Never sleep or loop past about 25 s. Chain `wait-for-task` calls instead. The cap also applies to a script called through `ctx.step.swarmScript`; the step's `timeoutMs` does not extend it. A long LLM call, such as a 2,000-word draft, goes in a `ctx.step.rawLlm` step inside `launch-script-run`, never in a called script.
73
73
 
74
74
  ### What `ctx` holds
75
75
 
@@ -64,7 +64,7 @@ export default async function (args: z.infer<typeof argsSchema>, ctx: ScriptCont
64
64
  - `agentId` is propagated through the `X-Agent-ID` header, so SDK calls run as you. `taskId` is not ambient: pass it in `args` when the script calls `task_storeProgress`.
65
65
  - A script invoked from a workflow node may run under a workflow identity.
66
66
  - Return compact structured data. Raw logs, full HTML, big JSON arrays, and file contents stay inside the script.
67
- - Limits: about 30 s wall clock (up to 5 minutes where the tool exposes it), 1 MB stdout. Never sleep or loop past about 25 s. Chain `wait-for-task` calls instead.
67
+ - Limits: about 30 s wall clock (up to 5 minutes where the tool exposes it), 1 MB stdout. Never sleep or loop past about 25 s. Chain `wait-for-task` calls instead. The cap also applies to a script called through `ctx.step.swarmScript`; the step's `timeoutMs` does not extend it. A long LLM call, such as a 2,000-word draft, goes in a `ctx.step.rawLlm` step inside `launch-script-run`, never in a called script.
68
68
 
69
69
  ### What `ctx` holds
70
70
 
@@ -13,7 +13,7 @@ When the task names a skill (`researching`, `planning`, `implementing`), use it.
13
13
 
14
14
  Finish the task with one of the four endings in your operating contract: `completed`, `defer-task`, `request-human-input`, or `failed`. Then stop.
15
15
 
16
- Resuming (a resume task, or work cut by a graceful shutdown): read the parent's last progress line, then re-read live state once (PR state and head SHA, branch, `git status`) before new work. Re-run controls only if the head moved. Never redo a pushed commit or open a second PR for the same branch. Store a progress line with branch, PR number and head SHA each time you push.
16
+ Resuming (a resume task, or work cut by a graceful shutdown): read the parent's last progress line, then re-read live state once (PR state and head SHA, branch, `git status`) before new work. Re-run controls only if the head moved. Never redo a pushed commit or open a second PR for the same branch. Store a progress line with branch, PR number and head SHA each time you push. A document task has no branch: its live state is the brief's agent-fs output path and the task attachments. Run `agent-fs ls` on that path, download any partial and extend it; never re-run collection steps that already produced artifacts. If your task's `model` differs from the parent's, say so in the output, because the result's provenance changed.
17
17
 
18
18
  Write times in replies, outputs and defer notes in the requester's timezone when the Requester Profile names one, never raw UTC.
19
19
 
@@ -8,7 +8,7 @@ When the task names a skill (`researching`, `planning`, `implementing`), use it.
8
8
 
9
9
  Finish the task with one of the four endings in your operating contract: `completed`, `defer-task`, `request-human-input`, or `failed`. Then stop.
10
10
 
11
- Resuming (a resume task, or work cut by a graceful shutdown): read the parent's last progress line, then re-read live state once (PR state and head SHA, branch, `git status`) before new work. Re-run controls only if the head moved. Never redo a pushed commit or open a second PR for the same branch. Store a progress line with branch, PR number and head SHA each time you push.
11
+ Resuming (a resume task, or work cut by a graceful shutdown): read the parent's last progress line, then re-read live state once (PR state and head SHA, branch, `git status`) before new work. Re-run controls only if the head moved. Never redo a pushed commit or open a second PR for the same branch. Store a progress line with branch, PR number and head SHA each time you push. A document task has no branch: its live state is the brief's agent-fs output path and the task attachments. Run `agent-fs ls` on that path, download any partial and extend it; never re-run collection steps that already produced artifacts. If your task's `model` differs from the parent's, say so in the output, because the result's provenance changed.
12
12
 
13
13
  Write times in replies, outputs and defer notes in the requester's timezone when the Requester Profile names one, never raw UTC.
14
14
 
@@ -12,6 +12,9 @@ import {
12
12
  import {
13
13
  sanitizeSurrogates
14
14
  } from "./cli-y2apkfe2.js";
15
+ import {
16
+ parseStreamingJson
17
+ } from "./cli-1m2e086m.js";
15
18
  import {
16
19
  calculateCost,
17
20
  getSystemMessageText,
@@ -19,9 +22,6 @@ import {
19
22
  resolveTranscript,
20
23
  resolveTranscriptTools
21
24
  } from "./cli-g7k7zbcz.js";
22
- import {
23
- parseStreamingJson
24
- } from "./cli-1m2e086m.js";
25
25
 
26
26
  // node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js
27
27
  function encodeTextSignatureV1(id, phase) {
@@ -39,6 +39,12 @@ import {
39
39
  import {
40
40
  providerHeadersToRecord
41
41
  } from "./cli-7kyk9jr3.js";
42
+ import {
43
+ getProviderEnvValue
44
+ } from "./cli-btbzvq95.js";
45
+ import {
46
+ parseStreamingJson
47
+ } from "./cli-1m2e086m.js";
42
48
  import {
43
49
  calculateCost,
44
50
  collapseSystemMessages,
@@ -47,12 +53,6 @@ import {
47
53
  getSystemMessageText,
48
54
  withoutInitialSystemMessage
49
55
  } from "./cli-g7k7zbcz.js";
50
- import {
51
- getProviderEnvValue
52
- } from "./cli-btbzvq95.js";
53
- import {
54
- parseStreamingJson
55
- } from "./cli-1m2e086m.js";
56
56
  import {
57
57
  AssistantMessageEventStream,
58
58
  appendAssistantMessageDiagnostic
@@ -14,10 +14,10 @@ import {
14
14
  toGoogleThinkingLevel,
15
15
  usesGoogleThinkingLevel
16
16
  } from "./cli-95zs84qw.js";
17
+ import"./cli-zy39d433.js";
17
18
  import {
18
19
  getPiUserAgent
19
20
  } from "./cli-et1bbwqf.js";
20
- import"./cli-zy39d433.js";
21
21
  import"./cli-yatxqynm.js";
22
22
  import {
23
23
  formatProviderError,
@@ -15,10 +15,10 @@ import {
15
15
  toGoogleThinkingLevel,
16
16
  usesGoogleThinkingLevel
17
17
  } from "./cli-95zs84qw.js";
18
+ import"./cli-zy39d433.js";
18
19
  import {
19
20
  getPiUserAgent
20
21
  } from "./cli-et1bbwqf.js";
21
- import"./cli-zy39d433.js";
22
22
  import"./cli-yatxqynm.js";
23
23
  import {
24
24
  formatProviderError,
@@ -33,6 +33,9 @@ import {
33
33
  import {
34
34
  providerHeadersToRecord
35
35
  } from "./cli-7kyk9jr3.js";
36
+ import {
37
+ getProviderEnvValue
38
+ } from "./cli-btbzvq95.js";
36
39
  import {
37
40
  calculateCost,
38
41
  clampThinkingLevel,
@@ -41,9 +44,6 @@ import {
41
44
  getInitialSystemMessage,
42
45
  getSystemMessageText
43
46
  } from "./cli-g7k7zbcz.js";
44
- import {
45
- getProviderEnvValue
46
- } from "./cli-btbzvq95.js";
47
47
  import {
48
48
  AssistantMessageEventStream
49
49
  } from "./cli-wnb9b2g3.js";
@@ -16,6 +16,9 @@ import {
16
16
  import {
17
17
  headersToRecord
18
18
  } from "./cli-7kyk9jr3.js";
19
+ import {
20
+ parseStreamingJson
21
+ } from "./cli-1m2e086m.js";
19
22
  import {
20
23
  calculateCost,
21
24
  clampThinkingLevel,
@@ -24,9 +27,6 @@ import {
24
27
  renderSystemMessageUpdate,
25
28
  resolveTranscript
26
29
  } from "./cli-g7k7zbcz.js";
27
- import {
28
- parseStreamingJson
29
- } from "./cli-1m2e086m.js";
30
30
  import {
31
31
  AssistantMessageEventStream
32
32
  } from "./cli-wnb9b2g3.js";
@@ -5,18 +5,18 @@ import {
5
5
  import {
6
6
  clampOpenAIPromptCacheKey
7
7
  } from "./cli-mrptpp86.js";
8
- import {
9
- shortHash
10
- } from "./cli-5m9j2spm.js";
11
8
  import {
12
9
  OpenAI
13
10
  } from "./cli-7cxw8b60.js";
14
- import {
15
- getPiUserAgent
16
- } from "./cli-et1bbwqf.js";
17
11
  import {
18
12
  retryProviderRequest
19
13
  } from "./cli-zy39d433.js";
14
+ import {
15
+ shortHash
16
+ } from "./cli-5m9j2spm.js";
17
+ import {
18
+ getPiUserAgent
19
+ } from "./cli-et1bbwqf.js";
20
20
  import {
21
21
  formatProviderError,
22
22
  normalizeProviderError
@@ -40,6 +40,12 @@ import {
40
40
  import {
41
41
  headersToRecord
42
42
  } from "./cli-7kyk9jr3.js";
43
+ import {
44
+ getProviderEnvValue
45
+ } from "./cli-btbzvq95.js";
46
+ import {
47
+ parseStreamingJson
48
+ } from "./cli-1m2e086m.js";
43
49
  import {
44
50
  calculateCost,
45
51
  clampThinkingLevel,
@@ -49,12 +55,6 @@ import {
49
55
  resolveTranscript,
50
56
  resolveTranscriptTools
51
57
  } from "./cli-g7k7zbcz.js";
52
- import {
53
- getProviderEnvValue
54
- } from "./cli-btbzvq95.js";
55
- import {
56
- parseStreamingJson
57
- } from "./cli-1m2e086m.js";
58
58
  import {
59
59
  AssistantMessageEventStream
60
60
  } from "./cli-wnb9b2g3.js";