@desplega.ai/agent-swarm 2.3.0 → 2.4.1

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 (332) hide show
  1. package/README.md +1 -0
  2. package/dist/{acp-adapter-v85a2bqy.js → acp-adapter-zvzr538d.js} +9 -9
  3. package/dist/{actions-zgcxfspj.js → actions-jhtqdw69.js} +21 -19
  4. package/dist/{amp-adapter-jw9xfz42.js → amp-adapter-bd84rhs2.js} +4 -4
  5. package/dist/{app-4e1s4675.js → app-kreq1gwg.js} +3 -3
  6. package/dist/{assistant-v238n9dk.js → assistant-3k22sbsq.js} +23 -21
  7. package/dist/{boot-reembed-p666cw5n.js → boot-reembed-e53x6b9v.js} +1 -1
  8. package/dist/{boot-reembed-w6pm64j4.js → boot-reembed-f6z923ny.js} +1 -1
  9. package/dist/{boot-scrub-sweep-jcyjagn3.js → boot-scrub-sweep-0538vsb7.js} +4 -4
  10. package/dist/{boot-seeds-gbedmamp.js → boot-seeds-6wxqkfk2.js} +4 -4
  11. package/dist/{claude-adapter-q7wspzt8.js → claude-adapter-gfts5044.js} +9 -9
  12. package/dist/{claude-managed-adapter-n7ahjyx6.js → claude-managed-adapter-h2y889ge.js} +3 -3
  13. package/dist/{claude-managed-setup-wza784fb.js → claude-managed-setup-h00hsgtz.js} +2 -2
  14. package/dist/{claude-sdk-session-yf400ptr.js → claude-sdk-session-56besmfz.js} +13 -13
  15. package/dist/{cli-65q70v2v.js → cli-0bh477zn.js} +33 -6
  16. package/dist/{cli-4ync7m60.js → cli-0ebey9hg.js} +1 -1
  17. package/dist/{cli-665j3feb.js → cli-0xk505e8.js} +1 -1
  18. package/dist/{cli-7gh7020n.js → cli-1dmcq2eh.js} +1 -1
  19. package/dist/{cli-gzvb3d4a.js → cli-1jx0srjt.js} +3 -3
  20. package/dist/{cli-zj4d6afs.js → cli-1pa3rz69.js} +21 -6
  21. package/dist/{cli-7ayprxp7.js → cli-2dfbv8qr.js} +8 -0
  22. package/dist/{cli-30m5q8mc.js → cli-3kh4kpqy.js} +6 -6
  23. package/dist/{cli-qrwp40st.js → cli-3p8fqcnh.js} +2 -2
  24. package/dist/{cli-y3dvz6ge.js → cli-3r448dqn.js} +3 -3
  25. package/dist/{cli-a17tzmn0.js → cli-3tnpj2bh.js} +7 -7
  26. package/dist/{cli-ea7chd26.js → cli-471qk6s2.js} +93 -46
  27. package/dist/{cli-a49vpbf3.js → cli-5kqnemen.js} +1 -1
  28. package/dist/{cli-0rh20bp3.js → cli-6ncjvx55.js} +3 -3
  29. package/dist/{cli-fb6t92v8.js → cli-6x9ma5w5.js} +1 -1
  30. package/dist/{cli-k28p6xh7.js → cli-7225gwj7.js} +2 -2
  31. package/dist/{cli-8cvvytad.js → cli-8nyhf7za.js} +3 -3
  32. package/dist/{cli-e09hj50q.js → cli-8wkb09q5.js} +11 -11
  33. package/dist/{cli-j0v75y13.js → cli-a0kcty51.js} +4 -4
  34. package/dist/{cli-zes4tsbb.js → cli-a4gvwttf.js} +4 -4
  35. package/dist/{cli-jhp7w1fy.js → cli-a5ebc95n.js} +2 -2
  36. package/dist/{cli-5d1m1qca.js → cli-ash6xxk7.js} +2 -2
  37. package/dist/{cli-fp4xbw07.js → cli-axh29tyr.js} +14 -12
  38. package/dist/{cli-p22zdvnt.js → cli-bn0rewsy.js} +3 -3
  39. package/dist/{cli-hz64bcnj.js → cli-bn5kevnf.js} +11 -373
  40. package/dist/{cli-8jtrekpy.js → cli-d2mb5s8a.js} +7 -7
  41. package/dist/{cli-c5sbmw1v.js → cli-d82btycs.js} +94 -15
  42. package/dist/{cli-vjfpshn3.js → cli-ejs3m1sx.js} +1 -1
  43. package/dist/{cli-yv0vgscc.js → cli-fpmsqq59.js} +18 -2
  44. package/dist/cli-fz9kewbh.js +382 -0
  45. package/dist/{cli-4s1kqrqg.js → cli-g0hgtz4p.js} +6 -6
  46. package/dist/{cli-hn3pftj2.js → cli-gf0kfg81.js} +7 -7
  47. package/dist/{cli-d43xqzbe.js → cli-hqhzg1qq.js} +2 -2
  48. package/dist/{cli-azs9bhc5.js → cli-j4rqdf2n.js} +2 -2
  49. package/dist/{cli-wtg6edvd.js → cli-jh0qcrga.js} +1 -1
  50. package/dist/{cli-kqypty34.js → cli-k9z4zd4p.js} +6 -5
  51. package/dist/{cli-jhmjwqcg.js → cli-kmqgmcnb.js} +47 -14
  52. package/dist/{cli-8qsx817b.js → cli-kr2pmfqx.js} +583 -769
  53. package/dist/{cli-4g629sgr.js → cli-m2qgh5sv.js} +20 -1
  54. package/dist/{cli-9e9kjqsj.js → cli-mfe7f7b5.js} +2 -2
  55. package/dist/{cli-x3en6ct3.js → cli-nwyw3zhg.js} +1 -1
  56. package/dist/{cli-6vcyw6v7.js → cli-nx462e4v.js} +5 -3
  57. package/dist/{cli-tr24eeny.js → cli-p0rakbrk.js} +9 -9
  58. package/dist/{cli-4hmaheb6.js → cli-p6argxh9.js} +9 -9
  59. package/dist/{cli-3avfh5az.js → cli-pemywhfq.js} +2 -2
  60. package/dist/{cli-etvn5ej2.js → cli-pnp2j5zg.js} +2 -2
  61. package/dist/{cli-wk8ccrz6.js → cli-pw7v69vp.js} +2 -2
  62. package/dist/{cli-ka01m5rb.js → cli-rdq7tzwm.js} +17 -14
  63. package/dist/{cli-re4wkbzx.js → cli-rqqsfz30.js} +677 -104
  64. package/dist/{cli-xgn4rwyv.js → cli-s48yvzb8.js} +4 -4
  65. package/dist/{cli-zv4vy2b0.js → cli-s95dknxh.js} +1 -1
  66. package/dist/{cli-g6p7c2my.js → cli-sjyetj21.js} +2 -2
  67. package/dist/{cli-rdr166ht.js → cli-smvcw9z5.js} +1 -1
  68. package/dist/{cli-fhvqt2fp.js → cli-sv5gb0yb.js} +1 -1
  69. package/dist/{cli-yv3n83x8.js → cli-syhq378v.js} +2 -2
  70. package/dist/{cli-q1812jbw.js → cli-tbhwrxpt.js} +9 -9
  71. package/dist/{cli-w7z94e6c.js → cli-tx00c0h6.js} +4 -2
  72. package/dist/{cli-dxwh4j32.js → cli-vy0fay6k.js} +46 -37
  73. package/dist/{cli-ptkpaqfy.js → cli-wt645v7q.js} +1 -1
  74. package/dist/{cli-ppapy34w.js → cli-wxbn3yfx.js} +2 -2
  75. package/dist/{cli-cby329ny.js → cli-x5mq1fyq.js} +3 -3
  76. package/dist/{cli-rc3r0bnh.js → cli-xbzvet96.js} +6 -6
  77. package/dist/{cli-4mkvwgzr.js → cli-xf234ws8.js} +1 -1
  78. package/dist/{cli-6p7ddg72.js → cli-xftrvxag.js} +5 -5
  79. package/dist/cli-z071fb95.js +848 -0
  80. package/dist/{cli-1v8w782f.js → cli-z1ew8vbq.js} +14 -7
  81. package/dist/{cli-9td5ss65.js → cli-zfg9enh9.js} +3 -3
  82. package/dist/{cli-yxqag76b.js → cli-zw88zjba.js} +1 -1
  83. package/dist/cli.js +19 -19
  84. package/dist/{codex-adapter-nhjj2veb.js → codex-adapter-p6rmm7vv.js} +6 -6
  85. package/dist/{codex-hook-x6tm6y5m.js → codex-hook-x7nejyrr.js} +8 -5
  86. package/dist/{codex-login-35p4sk85.js → codex-login-m819c41r.js} +1 -1
  87. package/dist/{codex-session-runner-6hggrjbx.js → codex-session-runner-8vd5t9t0.js} +7 -7
  88. package/dist/{commands-mrw1ph2w.js → commands-7ems2p13.js} +2 -2
  89. package/dist/{controller-pt1zam5w.js → controller-m263fg43.js} +4 -4
  90. package/dist/{controllers-connect-ymw5541d.js → controllers-connect-bg33ae53.js} +28 -24
  91. package/dist/{cursor-adapter-cf4zh5x0.js → cursor-adapter-cz6nm6mj.js} +3 -3
  92. package/dist/{db-hy80219q.js → db-w505dwa8.js} +2 -2
  93. package/dist/{db-hhpy6m4x.js → db-ys2rbdft.js} +3 -2
  94. package/dist/{devin-adapter-7egzmt0k.js → devin-adapter-zgqadvnm.js} +1 -1
  95. package/dist/{dispatcher-6pdjtkr1.js → dispatcher-0s0mckqr.js} +20 -18
  96. package/dist/{docker-njavd3fb.js → docker-fkgtr75t.js} +2 -2
  97. package/dist/{dsh-adapter-fbx06re2.js → dsh-adapter-3n3net33.js} +3 -3
  98. package/dist/{e2b-5r6a5jeb.js → e2b-7am6tmq6.js} +2 -2
  99. package/dist/{e2b-pw1nvtmh.js → e2b-thdcxtjd.js} +2 -2
  100. package/dist/{easter-egg-3d-6hg2r942.js → easter-egg-3d-5cgynaja.js} +1 -1
  101. package/dist/{event-bus-101fenkh.js → event-bus-9vpk8gmq.js} +1 -1
  102. package/dist/{execute-bcqc69a5.js → execute-t4e6m3rw.js} +1 -1
  103. package/dist/{external-channel-j6vb6ya1.js → external-channel-5b23fv8z.js} +2 -2
  104. package/dist/{google-generative-ai-phpmwxvg.js → google-generative-ai-bmq8gkf3.js} +1 -1
  105. package/dist/{google-vertex-es9ybgdy.js → google-vertex-b1rvp52s.js} +1 -1
  106. package/dist/{grok-adapter-1193sprp.js → grok-adapter-q9fghe5q.js} +10 -10
  107. package/dist/handlers-mqrym347.js +39 -0
  108. package/dist/{heartbeat-h1w1ktce.js → heartbeat-tww6yx1w.js} +23 -21
  109. package/dist/{hook-ejja4bpe.js → hook-dx0pkvar.js} +16 -9
  110. package/dist/{hook-skrbja18.js → hook-pvmh9b6m.js} +6 -6
  111. package/dist/{http-mzh41mfj.js → http-k2ejbt05.js} +975 -292
  112. package/dist/{index-6rmnn89d.js → index-2z710v4x.js} +10 -10
  113. package/dist/{index-xmmkyx82.js → index-dgz61nff.js} +20 -18
  114. package/dist/{index-wgsw9xcz.js → index-g6tbb6ve.js} +1 -1
  115. package/dist/index-h2ek08d6.js +40 -0
  116. package/dist/index-pqfwh9nn.js +41 -0
  117. package/dist/{index-epr2gnbw.js → index-x5aktmp8.js} +1 -1
  118. package/dist/{index-x0q2a4f9.js → index-ysd45kgc.js} +1 -1
  119. package/dist/{index-g909y089.js → index-zgvqzjsw.js} +8 -8
  120. package/dist/{keepalive-4djvbm2j.js → keepalive-nhvpw10z.js} +4 -4
  121. package/dist/lead-jb6sf69z.js +78 -0
  122. package/dist/{maintenance-f3xhnjsm.js → maintenance-agakc519.js} +1 -1
  123. package/dist/{oauth-refresh-sweep-fpd6x6rw.js → oauth-refresh-sweep-4dcbhtn0.js} +3 -3
  124. package/dist/{onboard-196tjgyn.js → onboard-4n2kwa4v.js} +3 -3
  125. package/dist/{opencode-adapter-eeesgfqk.js → opencode-adapter-3s7ax02e.js} +7 -7
  126. package/dist/{otel-impl-g8fh4c21.js → otel-impl-tfa12080.js} +2 -2
  127. package/dist/{pi-mono-adapter-zasp3ze3.js → pi-mono-adapter-ytp7gz8b.js} +24 -13
  128. package/dist/{pricing-refresh-sdcf5yaz.js → pricing-refresh-3cqx3f3x.js} +3 -3
  129. package/dist/{rbac-roles-bsp5657v.js → rbac-roles-9fae5rnv.js} +5 -3
  130. package/dist/{rbac-roles-2x4g1wb5.js → rbac-roles-y6zbfzve.js} +2 -2
  131. package/dist/{render-v2-0pyb39bb.js → render-v2-emawjvc4.js} +3 -3
  132. package/dist/{resume-a86tkj6r.js → resume-zhgts7h7.js} +10 -8
  133. package/dist/{runtime-ar8310ba.js → runtime-xe3aqy4x.js} +1 -1
  134. package/dist/session-access-cm823e06.js +25 -0
  135. package/dist/{setup-ypbzcapd.js → setup-tkp99w1e.js} +1 -1
  136. package/dist/{virtual-modules-wzk6jf3a.js → virtual-modules-4r3zkc20.js} +2 -2
  137. package/dist/{work-objects-yjp8de12.js → work-objects-f722h263.js} +23 -21
  138. package/dist/worker-p7f336rq.js +78 -0
  139. package/dist/{x-8ewt8gxn.js → x-y45mthwn.js} +2 -2
  140. package/openapi.json +1086 -305
  141. package/package.json +2 -2
  142. package/src/apps/action-caller.ts +6 -0
  143. package/src/apps/action-runner.ts +146 -0
  144. package/src/apps/row-store.ts +4 -2
  145. package/src/apps/script-types.ts +17 -4
  146. package/src/be/db/active-sessions.ts +5 -0
  147. package/src/be/db/session-visibility.ts +29 -0
  148. package/src/be/db/tasks/read.ts +61 -3
  149. package/src/be/db/tasks/write.ts +15 -6
  150. package/src/be/db.ts +106 -37
  151. package/src/be/events.ts +11 -0
  152. package/src/be/fleet-benchmark-stats.ts +10 -5
  153. package/src/be/migrations/230_session_shares.sql +23 -0
  154. package/src/be/models-catalog.ts +4 -0
  155. package/src/be/onboarding.ts +6 -0
  156. package/src/be/rbac-roles.ts +2 -0
  157. package/src/be/scripts/typecheck.ts +13 -0
  158. package/src/be/session-shares.ts +244 -0
  159. package/src/be/swarm-config-guard.ts +33 -3
  160. package/src/be/telemetry-enable.ts +1 -1
  161. package/src/commands/provider-credentials.ts +12 -2
  162. package/src/commands/runner.ts +14 -0
  163. package/src/heartbeat/heartbeat.ts +2 -2
  164. package/src/hooks/codex-hook.ts +6 -2
  165. package/src/hooks/hook.ts +7 -0
  166. package/src/hooks/pr-body-guard.ts +38 -11
  167. package/src/hooks/pr-room-guard.ts +88 -0
  168. package/src/http/active-sessions.ts +13 -2
  169. package/src/http/agents.ts +11 -3
  170. package/src/http/all-routes.ts +1 -0
  171. package/src/http/api-keys.ts +3 -1
  172. package/src/http/approval-requests.ts +2 -1
  173. package/src/http/apps.ts +118 -190
  174. package/src/http/config.ts +3 -0
  175. package/src/http/context.ts +2 -0
  176. package/src/http/core.ts +39 -2
  177. package/src/http/events.ts +6 -2
  178. package/src/http/favorite-owner.ts +1 -1
  179. package/src/http/fleet-benchmark.ts +79 -30
  180. package/src/http/fs.ts +38 -3
  181. package/src/http/global-config.ts +7 -0
  182. package/src/http/index.ts +3 -1
  183. package/src/http/memory.ts +3 -1
  184. package/src/http/ranking.ts +351 -0
  185. package/src/http/realtime.ts +26 -21
  186. package/src/http/route-def.ts +77 -11
  187. package/src/http/script-runs.ts +2 -1
  188. package/src/http/scripts.ts +8 -0
  189. package/src/http/session-access.ts +179 -0
  190. package/src/http/session-data.ts +10 -2
  191. package/src/http/sessions.ts +212 -12
  192. package/src/http/stats.ts +7 -3
  193. package/src/http/tasks.ts +85 -8
  194. package/src/http/telemetry-ui.ts +1 -1
  195. package/src/http/used-by.ts +64 -20
  196. package/src/http/users.ts +2 -2
  197. package/src/prompts/session-templates.ts +3 -1
  198. package/src/providers/amp-adapter.ts +1 -1
  199. package/src/providers/pi-mono-adapter.ts +15 -0
  200. package/src/providers/reasoning-effort.ts +2 -1
  201. package/src/providers/types.ts +2 -0
  202. package/src/ranking/telemetry-ranking.ts +119 -0
  203. package/src/ranking/usage.ts +57 -0
  204. package/src/rbac/admission.ts +22 -7
  205. package/src/rbac/legacy-policy.ts +2 -0
  206. package/src/rbac/permissions.ts +9 -0
  207. package/src/realtime/auth.ts +69 -0
  208. package/src/realtime/tickets.ts +4 -1
  209. package/src/realtime/transport.ts +77 -9
  210. package/src/scripts-runtime/sdk-allowlist.ts +7 -0
  211. package/src/scripts-runtime/types/stdlib.d.ts +31 -0
  212. package/src/scripts-runtime/types/swarm-sdk.d.ts +31 -0
  213. package/src/server.ts +4 -0
  214. package/src/slack/blocks.ts +18 -0
  215. package/src/slack/dm.ts +29 -0
  216. package/src/telemetry-context.ts +19 -1
  217. package/src/telemetry-contract/EVENTS.md +45 -8
  218. package/src/telemetry-contract/SOURCE.json +38 -4
  219. package/src/telemetry-contract/catalog.json +294 -5
  220. package/src/telemetry-contract/ranking/fixtures/expected.json +30 -0
  221. package/src/telemetry-contract/ranking/fixtures/invalid/bad-category.json +11 -0
  222. package/src/telemetry-contract/ranking/fixtures/invalid/bad-claim.json +11 -0
  223. package/src/telemetry-contract/ranking/fixtures/invalid/blank-description.json +11 -0
  224. package/src/telemetry-contract/ranking/fixtures/invalid/blank-name.json +11 -0
  225. package/src/telemetry-contract/ranking/fixtures/invalid/description-too-long.json +11 -0
  226. package/src/telemetry-contract/ranking/fixtures/invalid/domain-uppercase.json +11 -0
  227. package/src/telemetry-contract/ranking/fixtures/invalid/domain-with-scheme.json +11 -0
  228. package/src/telemetry-contract/ranking/fixtures/invalid/domain-with-www.json +11 -0
  229. package/src/telemetry-contract/ranking/fixtures/invalid/http-source-url.json +11 -0
  230. package/src/telemetry-contract/ranking/fixtures/invalid/missing-description.json +10 -0
  231. package/src/telemetry-contract/ranking/fixtures/invalid/missing-version.json +10 -0
  232. package/src/telemetry-contract/ranking/fixtures/invalid/name-not-string.json +11 -0
  233. package/src/telemetry-contract/ranking/fixtures/invalid/name-too-long.json +11 -0
  234. package/src/telemetry-contract/ranking/fixtures/invalid/not-object.json +1 -0
  235. package/src/telemetry-contract/ranking/fixtures/invalid/null.json +1 -0
  236. package/src/telemetry-contract/ranking/fixtures/invalid/other-with-subcategory.json +11 -0
  237. package/src/telemetry-contract/ranking/fixtures/invalid/oversize.json +1 -0
  238. package/src/telemetry-contract/ranking/fixtures/invalid/short-claim.json +11 -0
  239. package/src/telemetry-contract/ranking/fixtures/invalid/subcategory-other-category.json +11 -0
  240. package/src/telemetry-contract/ranking/fixtures/invalid/trailing-data.json +1 -0
  241. package/src/telemetry-contract/ranking/fixtures/invalid/unknown-field.json +12 -0
  242. package/src/telemetry-contract/ranking/fixtures/invalid/unsupported-version.json +11 -0
  243. package/src/telemetry-contract/ranking/fixtures/invalid/updated-at-not-date.json +11 -0
  244. package/src/telemetry-contract/ranking/fixtures/invalid/updated-at-offset.json +11 -0
  245. package/src/telemetry-contract/ranking/fixtures/invalid/wrong-case-field.json +11 -0
  246. package/src/telemetry-contract/ranking/fixtures/valid/category-without-subcategory.json +11 -0
  247. package/src/telemetry-contract/ranking/fixtures/valid/full.json +11 -0
  248. package/src/telemetry-contract/ranking/fixtures/valid/minimal.json +11 -0
  249. package/src/telemetry-contract/ranking/fixtures/valid/no-claim.json +10 -0
  250. package/src/telemetry-contract/ranking/fixtures/valid/padded-text.json +11 -0
  251. package/src/telemetry-contract/ranking/fixtures/valid/unicode-name.json +11 -0
  252. package/src/telemetry-contract/ranking/listing.v1.schema.json +61 -0
  253. package/src/telemetry-contract/ranking/taxonomy.json +8 -0
  254. package/src/telemetry-contract/ranking-taxonomy.gen.ts +11 -0
  255. package/src/telemetry-contract/types.gen.ts +963 -58
  256. package/src/telemetry-identity.ts +47 -9
  257. package/src/telemetry-snapshot.ts +9 -1
  258. package/src/telemetry-ui-events.ts +9 -2
  259. package/src/telemetry.ts +40 -5
  260. package/src/tests/app-action-run-tool.test.ts +178 -0
  261. package/src/tests/app-row-tools.test.ts +360 -0
  262. package/src/tests/apps-rbac.test.ts +189 -2
  263. package/src/tests/apps-script-types.test.ts +16 -3
  264. package/src/tests/credential-check.test.ts +38 -0
  265. package/src/tests/db-extraction-contract.test.ts +1 -0
  266. package/src/tests/db-task-read-contract.test.ts +1 -0
  267. package/src/tests/docs-index-footprint.test.js +2 -2
  268. package/src/tests/fleet-benchmark.test.ts +122 -2
  269. package/src/tests/http-users.test.ts +62 -1
  270. package/src/tests/model-catalog-table.test.ts +63 -0
  271. package/src/tests/model-profiles-api.test.ts +19 -7
  272. package/src/tests/models-catalog.test.ts +50 -0
  273. package/src/tests/onboarding.test.ts +21 -0
  274. package/src/tests/org-identity.test.ts +44 -0
  275. package/src/tests/org-website.test.ts +62 -0
  276. package/src/tests/pi-mono-adapter.test.ts +23 -0
  277. package/src/tests/pr-body-leaks.test.ts +4 -0
  278. package/src/tests/pr-room-guard.test.ts +242 -0
  279. package/src/tests/ranking-listing.test.ts +97 -0
  280. package/src/tests/ranking-route.test.ts +321 -0
  281. package/src/tests/ranking-usage.test.ts +50 -0
  282. package/src/tests/rbac-admission-e2e.test.ts +8 -0
  283. package/src/tests/rbac-admission.test.ts +38 -0
  284. package/src/tests/rbac-charact-http.test.ts +4 -3
  285. package/src/tests/rbac-engine.test.ts +2 -0
  286. package/src/tests/rbac-roles.test.ts +2 -0
  287. package/src/tests/realtime-room-surfaces.test.ts +3 -1
  288. package/src/tests/realtime-session-join-race.test.ts +142 -0
  289. package/src/tests/realtime-tickets.test.ts +24 -17
  290. package/src/tests/realtime-transport.test.ts +91 -0
  291. package/src/tests/reasoning-effort.test.ts +39 -3
  292. package/src/tests/runner-harness-telemetry-env.test.ts +56 -1
  293. package/src/tests/session-route-posture.test.ts +639 -0
  294. package/src/tests/session-sharing-routes.test.ts +282 -0
  295. package/src/tests/session-sharing.test.ts +526 -0
  296. package/src/tests/sessions-detail-batch.test.ts +7 -1
  297. package/src/tests/slack-tool-blocks.test.ts +101 -0
  298. package/src/tests/slack-update.test.ts +55 -0
  299. package/src/tests/slack-user-dm.test.ts +177 -0
  300. package/src/tests/swarm-tool-result-gate.test.ts +2 -4
  301. package/src/tests/telemetry-context.test.ts +128 -2
  302. package/src/tests/telemetry-ui-route.test.ts +123 -0
  303. package/src/tests/tool-annotations.test.ts +3 -2
  304. package/src/tests/used-by-route.test.ts +153 -9
  305. package/src/tests/workflow-agent-task-retry.test.ts +130 -4
  306. package/src/tests/workflow-wait-recovery.test.ts +116 -4
  307. package/src/tools/app-action-run.ts +63 -0
  308. package/src/tools/app-rows.ts +234 -0
  309. package/src/tools/model-catalog/index.ts +1 -1
  310. package/src/tools/slack-post.ts +18 -12
  311. package/src/tools/slack-read.ts +13 -1
  312. package/src/tools/slack-reply.ts +7 -10
  313. package/src/tools/slack-start-thread.ts +18 -11
  314. package/src/tools/slack-update.ts +2 -9
  315. package/src/tools/tool-config.ts +8 -0
  316. package/src/tools/utils.ts +1 -1
  317. package/src/tools/workflows/retry-workflow-run.ts +1 -1
  318. package/src/types.ts +52 -0
  319. package/src/utils/company-profile.ts +24 -0
  320. package/src/utils/org-identity.ts +33 -0
  321. package/src/utils/org-website.ts +58 -21
  322. package/src/workflows/recovery.ts +10 -22
  323. package/src/workflows/resume.ts +16 -0
  324. package/src/workflows/task-step-routing.ts +47 -7
  325. package/templates/skills/apps/SKILL.md +58 -2
  326. package/templates/skills/apps/content.md +58 -2
  327. package/dist/handlers-tb3xgjnm.js +0 -37
  328. package/dist/index-nyfcdpky.js +0 -39
  329. package/dist/index-vjn3wbzf.js +0 -38
  330. package/dist/lead-61kqp604.js +0 -76
  331. package/dist/worker-4ptnn1ge.js +0 -76
  332. package/dist/{cli-n5mrsg0f.js → cli-60cgh1rv.js} +3 -3
@@ -0,0 +1,234 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import * as z from "zod";
3
+ import { AppNameSchema, type ModelDef, SYSTEM_COLUMN_KINDS } from "../apps/definition";
4
+ import {
5
+ type AppRow,
6
+ AppRowAppNotFoundError,
7
+ AppRowValidationError,
8
+ createAppRow,
9
+ createAppRows,
10
+ deleteAppRow,
11
+ getAppRow,
12
+ patchAppRow,
13
+ validValue,
14
+ } from "../apps/row-store";
15
+ import { appDefinitionNeedsRepair, getApp } from "../apps/store";
16
+ import { getAgentById } from "../be/db";
17
+ import {
18
+ MAX_APP_BULK_ROWS_BODY_BYTES,
19
+ MAX_APP_ROW_BODY_BYTES,
20
+ rowMatchesFilters,
21
+ selectAppRows,
22
+ } from "../http/apps";
23
+ import { can } from "../rbac";
24
+ import {
25
+ createToolRegistrar,
26
+ type SwarmToolResult,
27
+ swarmToolOutputSchema,
28
+ toolErr,
29
+ toolOk,
30
+ } from "./utils";
31
+
32
+ const base = { appId: z.string().min(1), model: AppNameSchema };
33
+ const rowId = z.string().min(1);
34
+ const values = z.record(z.string(), z.unknown());
35
+ const equals = z.record(z.string(), z.union([z.string(), z.number(), z.boolean()]));
36
+ const limit = z.number().int().min(1).max(1000);
37
+ const rowOutput = { row: z.looseObject({}).optional() };
38
+ const rowsOutput = { rows: z.array(z.looseObject({})).optional() };
39
+
40
+ function checkSize(value: unknown, max: number): void {
41
+ if (Buffer.byteLength(JSON.stringify(value), "utf8") > max) {
42
+ throw new AppRowValidationError([
43
+ { path: "values", message: `Row input exceeds ${max} bytes.` },
44
+ ]);
45
+ }
46
+ }
47
+
48
+ function rowFilters(model: ModelDef, equals: Record<string, string | number | boolean> = {}) {
49
+ return Object.entries(equals).map(([column, value]) => {
50
+ const declared = Object.hasOwn(model.columns, column) ? model.columns[column] : undefined;
51
+ if ((!declared && !Object.hasOwn(SYSTEM_COLUMN_KINDS, column)) || declared?.hidden) {
52
+ throw new AppRowValidationError([
53
+ { path: `equals.${column}`, message: "Unknown or hidden column." },
54
+ ]);
55
+ }
56
+ if (!validValue(declared ?? { kind: SYSTEM_COLUMN_KINDS[column]! }, value)) {
57
+ throw new AppRowValidationError([
58
+ { path: `equals.${column}`, message: "Filter value must match the column kind." },
59
+ ]);
60
+ }
61
+ return { column, value };
62
+ });
63
+ }
64
+
65
+ export function registerAppRowTools(server: McpServer) {
66
+ function register<Shape extends z.ZodRawShape>(
67
+ name: string,
68
+ description: string,
69
+ shape: Shape,
70
+ output: z.ZodRawShape,
71
+ operation: (
72
+ args: z.infer<z.ZodObject<typeof base & Shape>>,
73
+ model: ModelDef,
74
+ actor: string,
75
+ ) => Promise<SwarmToolResult>,
76
+ readOnly = false,
77
+ ) {
78
+ createToolRegistrar(server)(
79
+ name,
80
+ {
81
+ title: description,
82
+ description,
83
+ annotations: { readOnlyHint: readOnly },
84
+ rbac: { permission: "app.use" },
85
+ inputSchema: z.object({ ...base, ...shape }),
86
+ outputSchema: swarmToolOutputSchema(output),
87
+ },
88
+ async (args, info) => {
89
+ if (!info.agentId) return toolErr('Agent ID not found. Set the "X-Agent-ID" header.');
90
+ const { appId, model: modelName } = z.object(base).parse(args);
91
+ const agent = await getAgentById(info.agentId);
92
+ const decision = can({
93
+ principal: { kind: "agent", agentId: info.agentId, isLead: agent?.isLead ?? false },
94
+ verb: "app.use",
95
+ resource: { kind: "app", appId },
96
+ source: "mcp",
97
+ });
98
+ if (!decision.allow) return toolErr(decision.reason);
99
+ const app = await getApp(appId);
100
+ if (!app) return toolErr("App not found.");
101
+ if (appDefinitionNeedsRepair(app))
102
+ return toolErr("App definition needs repair.", { data: { issues: app.definitionError } });
103
+ if (!Object.hasOwn(app.definition.models, modelName)) return toolErr("Model not found.");
104
+ try {
105
+ return await operation(args, app.definition.models[modelName]!, `agent:${info.agentId}`);
106
+ } catch (error) {
107
+ if (error instanceof AppRowValidationError)
108
+ return toolErr(error.message, { data: { issues: error.issues } });
109
+ if (error instanceof AppRowAppNotFoundError) return toolErr(error.message);
110
+ throw error;
111
+ }
112
+ },
113
+ );
114
+ }
115
+
116
+ register(
117
+ "app-rows-list",
118
+ "List app rows with equality filters, sorting, and a limit.",
119
+ {
120
+ equals: equals.optional(),
121
+ sort: z.string().optional(),
122
+ limit: limit.optional(),
123
+ },
124
+ { ...rowsOutput, total: z.number().optional() },
125
+ async (args, model) => {
126
+ const data = await selectAppRows(
127
+ args.appId,
128
+ args.model,
129
+ model,
130
+ rowFilters(model, args.equals),
131
+ args.sort,
132
+ args.limit,
133
+ true,
134
+ );
135
+ return toolOk(`Found ${data.total} row(s).`, { data });
136
+ },
137
+ true,
138
+ );
139
+
140
+ register(
141
+ "app-row-get",
142
+ "Get an app row.",
143
+ { rowId },
144
+ rowOutput,
145
+ async (args) => {
146
+ const row = await getAppRow(args.appId, args.model, args.rowId);
147
+ return row ? toolOk("Row retrieved.", { data: { row } }) : toolErr("Row not found.");
148
+ },
149
+ true,
150
+ );
151
+
152
+ register(
153
+ "app-row-create",
154
+ "Create an app row.",
155
+ { values },
156
+ rowOutput,
157
+ async (args, model, actor) => {
158
+ checkSize({ values: args.values }, MAX_APP_ROW_BODY_BYTES);
159
+ const row = await createAppRow(args.appId, args.model, model, args.values, { actor });
160
+ return toolOk("Row created.", { data: { row } });
161
+ },
162
+ );
163
+
164
+ register(
165
+ "app-rows-create",
166
+ "Create up to 500 app rows within 10 MiB.",
167
+ {
168
+ rows: z.array(values).min(1).max(500),
169
+ },
170
+ rowsOutput,
171
+ async (args, model, actor) => {
172
+ checkSize({ rows: args.rows }, MAX_APP_BULK_ROWS_BODY_BYTES);
173
+ for (const values of args.rows) checkSize({ values }, MAX_APP_ROW_BODY_BYTES);
174
+ const rows = await createAppRows(args.appId, args.model, model, args.rows, { actor });
175
+ return toolOk(`Created ${rows.length} row(s).`, { data: { rows } });
176
+ },
177
+ );
178
+
179
+ register(
180
+ "app-row-patch",
181
+ "Patch an app row.",
182
+ { rowId, values },
183
+ rowOutput,
184
+ async (args, model, actor) => {
185
+ checkSize({ values: args.values }, MAX_APP_ROW_BODY_BYTES);
186
+ const row = await patchAppRow(args.appId, args.model, model, args.rowId, args.values, {
187
+ actor,
188
+ });
189
+ return row ? toolOk("Row updated.", { data: { row } }) : toolErr("Row not found.");
190
+ },
191
+ );
192
+
193
+ register(
194
+ "app-row-delete",
195
+ "Delete an app row.",
196
+ { rowId },
197
+ { ok: z.boolean().optional() },
198
+ async (args, model) => {
199
+ const deleted = await deleteAppRow(args.appId, args.model, model, args.rowId);
200
+ return deleted ? toolOk("Row deleted.", { data: { ok: true } }) : toolErr("Row not found.");
201
+ },
202
+ );
203
+
204
+ register(
205
+ "app-rows-delete",
206
+ "Delete matching app rows. Supply at least one equality filter.",
207
+ {
208
+ equals: equals.refine(
209
+ (value) => Object.keys(value).length > 0,
210
+ "Supply at least one equality filter.",
211
+ ),
212
+ limit: limit.optional(),
213
+ },
214
+ { deleted: z.number().optional() },
215
+ async (args, model) => {
216
+ const filters = rowFilters(model, args.equals);
217
+ const { rows } = await selectAppRows(
218
+ args.appId,
219
+ args.model,
220
+ model,
221
+ filters,
222
+ undefined,
223
+ args.limit ?? 1000,
224
+ true,
225
+ );
226
+ // Re-check under the row lock: a row patched out of the filter since the select is kept.
227
+ const matches = (row: AppRow) => rowMatchesFilters(row, filters);
228
+ let deleted = 0;
229
+ for (const row of rows)
230
+ if (await deleteAppRow(args.appId, args.model, model, row.id, matches)) deleted++;
231
+ return toolOk(`Deleted ${deleted} row(s).`, { data: { deleted } });
232
+ },
233
+ );
234
+ }
@@ -87,7 +87,7 @@ export const registerModelCatalogOverlayUpsertTool = (server: McpServer) => {
87
87
  .string()
88
88
  .min(1)
89
89
  .describe(
90
- `models.dev provider id: anthropic, openai, openrouter, amazon-bedrock, opencode, ${openAICompatibleProviderIds().join(", ")}.`,
90
+ `models.dev provider id: anthropic, openai, openrouter, amazon-bedrock, opencode, opencode-go, ${openAICompatibleProviderIds().join(", ")}.`,
91
91
  ),
92
92
  modelId: z
93
93
  .string()
@@ -8,8 +8,9 @@ import {
8
8
  } from "@/be/db";
9
9
  import { can } from "@/rbac";
10
10
  import { getSlackApp } from "@/slack/app";
11
- import { getTaskLink } from "@/slack/blocks";
11
+ import { buildMrkdwnSectionBlocks, getTaskLink } from "@/slack/blocks";
12
12
  import { withAutoJoin } from "@/slack/channel-join";
13
+ import { resolveSlackConversationId } from "@/slack/dm";
13
14
  import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
14
15
  import { getAgentDisplayName, getAgentEmoji, markdownToSlack } from "@/slack/responses";
15
16
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
@@ -24,7 +25,12 @@ export const registerSlackPostTool = (server: McpServer) => {
24
25
  annotations: { openWorldHint: true },
25
26
 
26
27
  inputSchema: z.object({
27
- channelId: z.string().min(1).describe("The Slack channel ID to post to."),
28
+ channelId: z
29
+ .string()
30
+ .min(1)
31
+ .describe(
32
+ "The Slack channel ID to post to. A user ID (U…/W…) posts in the bot's DM with that user.",
33
+ ),
28
34
  message: z.string().min(1).max(4000).describe("The message content to post."),
29
35
  blocks: z
30
36
  .array(z.record(z.string(), z.unknown()))
@@ -42,7 +48,7 @@ export const registerSlackPostTool = (server: McpServer) => {
42
48
  messageTs: z.string().optional(),
43
49
  }),
44
50
  },
45
- async ({ channelId, message, threadTs, blocks }, requestInfo, _meta) => {
51
+ async ({ channelId: requestedChannelId, message, threadTs, blocks }, requestInfo, _meta) => {
46
52
  if (!requestInfo.agentId) {
47
53
  return toolErr("Agent ID not found.");
48
54
  }
@@ -68,6 +74,14 @@ export const registerSlackPostTool = (server: McpServer) => {
68
74
  return toolErr("Slack not configured.");
69
75
  }
70
76
 
77
+ let channelId: string;
78
+ try {
79
+ channelId = await resolveSlackConversationId(app.client, requestedChannelId);
80
+ } catch (error) {
81
+ const errorMsg = error instanceof Error ? error.message : String(error);
82
+ return toolErr(`Failed to open a DM with ${requestedChannelId}: ${errorMsg}`);
83
+ }
84
+
71
85
  const blockReason = await getChannelBlockReason(app.client, channelId);
72
86
  if (blockReason) {
73
87
  return toolErr(externalChannelToolError(channelId, blockReason));
@@ -82,15 +96,7 @@ export const registerSlackPostTool = (server: McpServer) => {
82
96
  const contextKey = sourceTask?.contextKey;
83
97
  const tree = threadTs ? await getSlackTreeMessageByThread(channelId, threadTs) : null;
84
98
  const messageBlocks: Record<string, unknown>[] = [
85
- ...(blocks ?? [
86
- {
87
- type: "section",
88
- text: {
89
- type: "mrkdwn",
90
- text: slackMessage,
91
- },
92
- },
93
- ]),
99
+ ...(blocks ?? buildMrkdwnSectionBlocks(slackMessage)),
94
100
  ];
95
101
  if (sourceTask && tree) {
96
102
  if (messageBlocks.length >= 50) {
@@ -4,6 +4,7 @@ import { getAgentById, getInboxMessageById, getTaskById } from "@/be/db";
4
4
  import { can } from "@/rbac";
5
5
  import { getSlackApp } from "@/slack/app";
6
6
  import { withAutoJoin } from "@/slack/channel-join";
7
+ import { resolveSlackConversationId } from "@/slack/dm";
7
8
  import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
8
9
  import { downloadFile, type SlackFile } from "@/slack/files";
9
10
  import { attachableTask, attachSlackFilesForAgent } from "@/slack/inbound-files";
@@ -59,7 +60,9 @@ export const registerSlackReadTool = (server: McpServer) => {
59
60
  channelId: z
60
61
  .string()
61
62
  .optional()
62
- .describe("Slack channel ID to read from (requires lead privileges)."),
63
+ .describe(
64
+ "Slack channel ID to read from (requires lead privileges). A user ID (U…/W…) reads the bot's DM with that user.",
65
+ ),
63
66
  threadTs: z
64
67
  .string()
65
68
  .optional()
@@ -155,6 +158,15 @@ export const registerSlackReadTool = (server: McpServer) => {
155
158
  return toolErr("Slack not configured.", { data: { messages: [] } });
156
159
  }
157
160
 
161
+ try {
162
+ slackChannelId = await resolveSlackConversationId(app.client, slackChannelId);
163
+ } catch (error) {
164
+ const errorMsg = error instanceof Error ? error.message : String(error);
165
+ return toolErr(`Failed to open a DM with ${slackChannelId}: ${errorMsg}`, {
166
+ data: { messages: [] },
167
+ });
168
+ }
169
+
158
170
  const blockReason = await getChannelBlockReason(app.client, slackChannelId);
159
171
  if (blockReason) {
160
172
  return toolErr(externalChannelToolError(slackChannelId, blockReason), {
@@ -11,7 +11,12 @@ import {
11
11
  } from "@/be/db";
12
12
  import { getTaskCitations } from "@/be/task-citations";
13
13
  import { getSlackApp } from "@/slack/app";
14
- import { buildCaptionBlock, getTaskLink, getTaskUrl } from "@/slack/blocks";
14
+ import {
15
+ buildCaptionBlock,
16
+ buildMrkdwnSectionBlocks,
17
+ getTaskLink,
18
+ getTaskUrl,
19
+ } from "@/slack/blocks";
15
20
  import { withAutoJoin } from "@/slack/channel-join";
16
21
  import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
17
22
  import { getAgentDisplayName, getAgentEmoji, markdownToSlack } from "@/slack/responses";
@@ -140,15 +145,7 @@ export const registerSlackReplyTool = (server: McpServer) => {
140
145
 
141
146
  const tree = await getSlackTreeMessageByThread(slackChannelId, slackThreadTs);
142
147
  const messageBlocks: Record<string, unknown>[] = [
143
- ...(renderedBlocks ?? [
144
- {
145
- type: "section",
146
- text: {
147
- type: "mrkdwn",
148
- text: slackMessage,
149
- },
150
- },
151
- ]),
148
+ ...(renderedBlocks ?? buildMrkdwnSectionBlocks(slackMessage)),
152
149
  ];
153
150
  for (const group of taskCitationSourceGroups(
154
151
  blocks ? JSON.stringify(blocks) : message,
@@ -3,7 +3,9 @@ import * as z from "zod";
3
3
  import { getAgentById, getTaskById, recordSlackMessage } from "@/be/db";
4
4
  import { can } from "@/rbac";
5
5
  import { getSlackApp } from "@/slack/app";
6
+ import { buildMrkdwnSectionBlocks } from "@/slack/blocks";
6
7
  import { withAutoJoin } from "@/slack/channel-join";
8
+ import { resolveSlackConversationId } from "@/slack/dm";
7
9
  import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
8
10
  import { getAgentDisplayName, getAgentEmoji, markdownToSlack } from "@/slack/responses";
9
11
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
@@ -18,7 +20,12 @@ export const registerSlackStartThreadTool = (server: McpServer) => {
18
20
  annotations: { openWorldHint: true },
19
21
 
20
22
  inputSchema: z.object({
21
- channelId: z.string().min(1).describe("The Slack channel ID to post to."),
23
+ channelId: z
24
+ .string()
25
+ .min(1)
26
+ .describe(
27
+ "The Slack channel ID to post to. A user ID (U…/W…) opens the bot's DM with that user; use the returned channelId afterwards.",
28
+ ),
22
29
  message: z.string().min(1).max(4000).describe("The message content to post."),
23
30
  blocks: z
24
31
  .array(z.record(z.string(), z.unknown()))
@@ -32,7 +39,7 @@ export const registerSlackStartThreadTool = (server: McpServer) => {
32
39
  messageTs: z.string().optional(),
33
40
  }),
34
41
  },
35
- async ({ channelId, message, blocks }, requestInfo, _meta) => {
42
+ async ({ channelId: requestedChannelId, message, blocks }, requestInfo, _meta) => {
36
43
  if (!requestInfo.agentId) {
37
44
  return toolErr("Agent ID not found.");
38
45
  }
@@ -57,6 +64,14 @@ export const registerSlackStartThreadTool = (server: McpServer) => {
57
64
  return toolErr("Slack not configured.");
58
65
  }
59
66
 
67
+ let channelId: string;
68
+ try {
69
+ channelId = await resolveSlackConversationId(app.client, requestedChannelId);
70
+ } catch (error) {
71
+ const errorMsg = error instanceof Error ? error.message : String(error);
72
+ return toolErr(`Failed to open a DM with ${requestedChannelId}: ${errorMsg}`);
73
+ }
74
+
60
75
  const blockReason = await getChannelBlockReason(app.client, channelId);
61
76
  if (blockReason) {
62
77
  return toolErr(externalChannelToolError(channelId, blockReason));
@@ -64,15 +79,7 @@ export const registerSlackStartThreadTool = (server: McpServer) => {
64
79
 
65
80
  try {
66
81
  const slackMessage = markdownToSlack(message);
67
- const messageBlocks = blocks ?? [
68
- {
69
- type: "section",
70
- text: {
71
- type: "mrkdwn",
72
- text: slackMessage,
73
- },
74
- },
75
- ];
82
+ const messageBlocks = blocks ?? buildMrkdwnSectionBlocks(slackMessage);
76
83
 
77
84
  const result = await withAutoJoin(app.client, channelId, () =>
78
85
  app.client.chat.postMessage({
@@ -4,6 +4,7 @@ import * as z from "zod";
4
4
  import { getAgentById } from "@/be/db";
5
5
  import { can } from "@/rbac";
6
6
  import { getSlackApp } from "@/slack/app";
7
+ import { buildMrkdwnSectionBlocks } from "@/slack/blocks";
7
8
  import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
8
9
  import { parseSlackTs } from "@/slack/message-text";
9
10
  import { markdownToSlack } from "@/slack/responses";
@@ -77,15 +78,7 @@ export const registerSlackUpdateTool = (server: McpServer) => {
77
78
  text: slackMessage,
78
79
  unfurl_links: false,
79
80
  unfurl_media: false,
80
- blocks: [
81
- {
82
- type: "section",
83
- text: {
84
- type: "mrkdwn",
85
- text: slackMessage,
86
- },
87
- },
88
- ],
81
+ blocks: buildMrkdwnSectionBlocks(slackMessage),
89
82
  } satisfies ChatUpdatePayload;
90
83
  const result = await app.client.chat.update(updatePayload);
91
84
 
@@ -189,6 +189,14 @@ export const DEFERRED_TOOLS = new Set([
189
189
  "app-list",
190
190
  "app-patch",
191
191
  "app-query",
192
+ "app-rows-list",
193
+ "app-row-get",
194
+ "app-row-create",
195
+ "app-rows-create",
196
+ "app-row-patch",
197
+ "app-row-delete",
198
+ "app-rows-delete",
199
+ "app-action-run",
192
200
  "app-sync",
193
201
  "app-upsert",
194
202
  "app-history",
@@ -347,7 +347,7 @@ export const NUDGES: Record<string, (result: SwarmToolResult) => string | undefi
347
347
  const hasQueries = Object.keys(definition?.queries ?? {}).length > 0;
348
348
  const hasActions = Object.keys(definition?.actions ?? {}).length > 0;
349
349
  return hasQueries || hasActions
350
- ? "This app's callable surface is `definition.queries` (run with `app-query`, passing any `$param` values) and `definition.actions` (invoke with `POST /api/apps/<id>/actions/<name>`; `sync` actions refresh sources)."
350
+ ? "Run `definition.queries` with `app-query` and supply each `$param` value. Invoke `definition.actions` with `app-action-run` through MCP or `POST /api/apps/<id>/actions/<name>` through REST. Sync actions refresh sources."
351
351
  : undefined;
352
352
  },
353
353
  // kv-get is spill-exempt (retrieval path), so oversized values reach the
@@ -10,7 +10,7 @@ export const registerRetryWorkflowRunTool = (server: McpServer) => {
10
10
  title: "Retry Workflow Run",
11
11
  annotations: { destructiveHint: false },
12
12
  description:
13
- "Retry a failed workflow run from the beginning. The run must be in 'failed' status.",
13
+ "Resume the same failed workflow run from its failed step(s); completed steps are not re-run. Retrying re-creates the failed node's side effects (e.g. an agent task), so check the target state first if that work was already done manually.",
14
14
  inputSchema: z.object({
15
15
  runId: z.string().uuid().describe("Workflow run ID to retry"),
16
16
  }),
package/src/types.ts CHANGED
@@ -453,6 +453,41 @@ export const ModelProfileSchema = z.object({
453
453
  });
454
454
  export type ModelProfile = z.infer<typeof ModelProfileSchema>;
455
455
 
456
+ // ============================================================================
457
+ // Session sharing
458
+ // ============================================================================
459
+ //
460
+ // `SessionShareAccessSchema` MUST stay in sync with the SQL CHECK constraint
461
+ // on session_shares.access (migration 230).
462
+
463
+ export const SessionShareAccessSchema = z.enum(["read", "write"]);
464
+ export type SessionShareAccess = z.infer<typeof SessionShareAccessSchema>;
465
+
466
+ /** The caller's access to a session. `none` is never returned; it is a 403. */
467
+ export const SessionAccessSchema = z.enum(["owner", "write", "read"]);
468
+
469
+ export const SessionOwnerSchema = z
470
+ .object({ id: z.string(), name: z.string() })
471
+ .openapi("SessionOwner");
472
+
473
+ export const SessionSharesSchema = z
474
+ .object({
475
+ /** What every user may do. `none` = private (owner and named users only). */
476
+ everyone: z.enum(["none", "read", "write"]),
477
+ users: z.array(
478
+ z.object({ userId: z.string(), access: SessionShareAccessSchema, createdAt: z.string() }),
479
+ ),
480
+ })
481
+ .openapi("SessionShares");
482
+ export type SessionShares = z.infer<typeof SessionSharesSchema>;
483
+
484
+ export const SessionSharesUpdateSchema = z.object({
485
+ everyone: z.enum(["none", "read", "write"]),
486
+ users: z
487
+ .array(z.object({ userId: z.string().min(1), access: SessionShareAccessSchema }))
488
+ .max(500),
489
+ });
490
+
456
491
  // ============================================================================
457
492
  // Task Steering Messages
458
493
  // ============================================================================
@@ -1327,6 +1362,14 @@ export const AgentBedrockStatusSchema = z
1327
1362
  .openapi("AgentBedrockStatus");
1328
1363
  export type AgentBedrockStatus = z.infer<typeof AgentBedrockStatusSchema>;
1329
1364
 
1365
+ export const AgentOpencodeGoStatusSchema = z
1366
+ .object({
1367
+ probedAt: z.number(), // unix ms
1368
+ models: z.array(z.string()).default([]),
1369
+ })
1370
+ .openapi("AgentOpencodeGoStatus");
1371
+ export type AgentOpencodeGoStatus = z.infer<typeof AgentOpencodeGoStatusSchema>;
1372
+
1330
1373
  const AcpSessionConfigSelectValueSchema = z.object({
1331
1374
  value: z.string(),
1332
1375
  name: z.string(),
@@ -1386,6 +1429,8 @@ export const AgentCredStatusSchema = z
1386
1429
  reportKind: z.enum(["boot", "post_task"]).default("boot"),
1387
1430
  /** Pi-mono Bedrock enumeration block — null when not in Bedrock mode. */
1388
1431
  bedrock: AgentBedrockStatusSchema.nullable().default(null),
1432
+ /** Pi-mono only: the `opencode-go` model ids the worker's pi-ai resolves. */
1433
+ opencodeGo: AgentOpencodeGoStatusSchema.nullable().default(null),
1389
1434
  /** ACP options advertised by the most recently created session. */
1390
1435
  acp: AgentAcpStatusSchema.nullable().default(null),
1391
1436
  })
@@ -2175,6 +2220,13 @@ export const RetryPolicySchema = z
2175
2220
  .openapi("RetryPolicy");
2176
2221
  export type RetryPolicy = z.infer<typeof RetryPolicySchema>;
2177
2222
 
2223
+ /**
2224
+ * `failureReason` of a workflow-step task cut by a supersede (deploy drain,
2225
+ * heartbeat remediation). The workflow engine re-dispatches it once even
2226
+ * when the node declares no `retry` (see `scheduleTaskStepRetry`).
2227
+ */
2228
+ export const SUPERSEDED_WORKFLOW_TASK_REASON = "superseded_workflow_task";
2229
+
2178
2230
  // --- Executor Metadata ---
2179
2231
 
2180
2232
  export const ExecutorMetaSchema = z
@@ -0,0 +1,24 @@
1
+ export const COMPANY_TEAM_SIZES = ["1", "2-10", "11-50", "51+"] as const;
2
+
3
+ export const COMPANY_USE_CASES = ["features", "bugs", "review", "ops", "docs", "data"] as const;
4
+
5
+ export const COMPANY_ACQUISITION_SOURCES = [
6
+ "search",
7
+ "github",
8
+ "social",
9
+ "colleague",
10
+ "newsletter",
11
+ "event",
12
+ "ai_assistant",
13
+ "hacker_news",
14
+ "other",
15
+ ] as const;
16
+
17
+ export const USER_FUNCTIONS = [
18
+ "engineer",
19
+ "eng_lead",
20
+ "founder",
21
+ "product",
22
+ "ops",
23
+ "other",
24
+ ] as const;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The "is the org identity set" rule, shared by every feature that needs a real
3
+ * organization name and website (the public ranking, the "used by" grant).
4
+ * Pure: the API passes global config values, workers pass `process.env`.
5
+ */
6
+ import { normalizeOrgWebsite } from "./org-website";
7
+
8
+ export const ORG_IDENTITY_KEYS = ["SWARM_ORG_NAME", "SWARM_ORG_WEBSITE"] as const;
9
+ export type OrgIdentityKey = (typeof ORG_IDENTITY_KEYS)[number];
10
+
11
+ /** Names the product falls back to when none is set; they are not an org name. */
12
+ const PLACEHOLDER_NAMES = new Set(["swarm", "your swarm"]);
13
+
14
+ export interface OrgIdentityStatus {
15
+ /** The trimmed name, or null when blank. A placeholder is returned but listed as missing. */
16
+ name: string | null;
17
+ /** The website as a bare hostname, or null when blank or not a public hostname. */
18
+ website: string | null;
19
+ missing: OrgIdentityKey[];
20
+ ok: boolean;
21
+ }
22
+
23
+ export function orgIdentityStatus(src: {
24
+ SWARM_ORG_NAME?: string | null;
25
+ SWARM_ORG_WEBSITE?: string | null;
26
+ }): OrgIdentityStatus {
27
+ const name = src.SWARM_ORG_NAME?.trim() || null;
28
+ const website = normalizeOrgWebsite(src.SWARM_ORG_WEBSITE) || null;
29
+ const missing: OrgIdentityKey[] = [];
30
+ if (!name || PLACEHOLDER_NAMES.has(name.toLowerCase())) missing.push("SWARM_ORG_NAME");
31
+ if (!website) missing.push("SWARM_ORG_WEBSITE");
32
+ return { name, website, missing, ok: missing.length === 0 };
33
+ }