@desplega.ai/agent-swarm 1.172.0 → 2.0.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 (525) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
  3. package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
  4. package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
  5. package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
  6. package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
  7. package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
  8. package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
  9. package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
  10. package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
  11. package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
  12. package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
  13. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
  14. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
  15. package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
  16. package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
  17. package/dist/{cli-kb4ehzx5.js → cli-1e4b6bzh.js} +7 -7
  18. package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
  19. package/dist/cli-2m1ktfzz.js +17795 -0
  20. package/dist/{cli-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
  21. package/dist/{cli-zxm9p3x4.js → cli-3fbmmawm.js} +5 -5
  22. package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
  23. package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
  24. package/dist/{cli-6jb2rf77.js → cli-5t4f29ez.js} +3 -3
  25. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  26. package/dist/cli-6cvfxs8r.js +47 -0
  27. package/dist/{cli-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
  28. package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
  29. package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
  30. package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
  31. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  32. package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
  33. package/dist/cli-9traj3dn.js +638 -0
  34. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  35. package/dist/{cli-bf7485pm.js → cli-apx87jne.js} +2 -2
  36. package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
  37. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  38. package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
  39. package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
  40. package/dist/{cli-1hgat6pa.js → cli-d5f9ed5c.js} +5 -5
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
  43. package/dist/{cli-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
  44. package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
  45. package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
  46. package/dist/cli-f527ce74.js +781 -0
  47. package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
  48. package/dist/cli-hjwmhcg1.js +10622 -0
  49. package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
  50. package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
  51. package/dist/{cli-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
  52. package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
  53. package/dist/cli-jta2eyzc.js +619 -0
  54. package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
  55. package/dist/cli-k3dp5tpf.js +263 -0
  56. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  57. package/dist/cli-kceah1eh.js +92 -0
  58. package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
  59. package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
  60. package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
  61. package/dist/cli-n2wq4j7m.js +6985 -0
  62. package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
  63. package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
  64. package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
  65. package/dist/cli-p0sg24zp.js +16 -0
  66. package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
  67. package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
  68. package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
  69. package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
  70. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  71. package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
  72. package/dist/{cli-r8smj8b8.js → cli-r62a35ea.js} +19 -3
  73. package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
  74. package/dist/cli-rhs9pz33.js +294 -0
  75. package/dist/{cli-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
  76. package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
  77. package/dist/{cli-xczpdp9e.js → cli-se8w6wny.js} +6 -6
  78. package/dist/cli-skxvvpap.js +10140 -0
  79. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  80. package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
  81. package/dist/{cli-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
  82. package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
  83. package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
  84. package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
  85. package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
  86. package/dist/{cli-04emfe2q.js → cli-vdach5a9.js} +5 -5
  87. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  88. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  89. package/dist/{cli-hwwvy36w.js → cli-wayw93nt.js} +3 -3
  90. package/dist/cli-wmgrkscj.js +23254 -0
  91. package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
  92. package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
  93. package/dist/cli.js +32 -48
  94. package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
  95. package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
  96. package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
  97. package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
  98. package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
  99. package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
  100. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
  101. package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
  102. package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
  103. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
  104. package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
  105. package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
  106. package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-3epjm3af.js} +7 -6
  107. package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
  108. package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
  109. package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
  110. package/dist/external-channel-h3359cwn.js +52 -0
  111. package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
  112. package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
  113. package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
  114. package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
  115. package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
  116. package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
  117. package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
  118. package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
  121. package/dist/index-9gw58n4k.js +193 -0
  122. package/dist/index-9j87mcm8.js +56305 -0
  123. package/dist/index-bsmcresk.js +79424 -0
  124. package/dist/index-mh85qhec.js +475 -0
  125. package/dist/{index-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
  126. package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
  127. package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
  128. package/dist/index-we27kd31.js +12810 -0
  129. package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
  130. package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
  131. package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
  132. package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
  133. package/dist/node-c9we95xf.js +1 -1
  134. package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
  135. package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
  136. package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
  137. package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
  138. package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
  139. package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
  140. package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
  141. package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
  142. package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
  143. package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
  144. package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
  145. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  146. package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
  147. package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
  148. package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
  149. package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
  150. package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
  151. package/openapi.json +951 -356
  152. package/package.json +12 -13
  153. package/src/apps/catalog.generated.json +1309 -53
  154. package/src/apps/page-validator.ts +93 -31
  155. package/src/azure-devops/api.ts +94 -18
  156. package/src/azure-devops/auth.ts +32 -0
  157. package/src/azure-devops/boards-sync.ts +708 -0
  158. package/src/azure-devops/handlers.ts +52 -8
  159. package/src/azure-devops/html.ts +26 -0
  160. package/src/azure-devops/index.ts +15 -0
  161. package/src/azure-devops/templates.ts +86 -0
  162. package/src/azure-devops/types.ts +65 -1
  163. package/src/be/config-refs.ts +60 -0
  164. package/src/be/db/page-versions.ts +15 -0
  165. package/src/be/db/runtime.ts +35 -8
  166. package/src/be/db/skill-name-resolution.ts +36 -0
  167. package/src/be/db/tasks/read.ts +230 -0
  168. package/src/be/db/tasks/write.ts +7 -0
  169. package/src/be/db.ts +74 -13
  170. package/src/be/migrations/213_script_connections_sql.sql +79 -0
  171. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  172. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  173. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  174. package/src/be/model-catalog-store.ts +5 -1
  175. package/src/be/model-tier-resolution.ts +12 -1
  176. package/src/be/model-validation.ts +5 -2
  177. package/src/be/models-catalog.ts +26 -1
  178. package/src/be/modelsdev-cache.json +198 -63
  179. package/src/be/modelsdev-cache.ts +9 -1
  180. package/src/be/script-connections.ts +47 -8
  181. package/src/be/script-credential-broker.ts +39 -2
  182. package/src/be/scripts/run-saved.ts +1 -0
  183. package/src/be/scripts/typecheck.ts +10 -8
  184. package/src/be/seed/runner.ts +13 -1
  185. package/src/be/seed/state-db.ts +5 -0
  186. package/src/be/seed/types.ts +6 -0
  187. package/src/be/seed-pricing.ts +19 -2
  188. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  189. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  190. package/src/be/seed-skills/bundled-files.generated.json +10 -18
  191. package/src/be/seed-skills/index.ts +107 -3
  192. package/src/be/sql-connections.ts +118 -0
  193. package/src/be/swarm-config-guard.ts +53 -0
  194. package/src/cli.tsx +0 -16
  195. package/src/commands/onboard/non-interactive.ts +4 -2
  196. package/src/commands/profile-sync.ts +5 -3
  197. package/src/commands/provider-credentials.ts +52 -6
  198. package/src/commands/runner.ts +196 -56
  199. package/src/e2b/env.ts +5 -0
  200. package/src/extensions/contract-types.generated.ts +1 -1
  201. package/src/extensions/contract.ts +45 -0
  202. package/src/extensions/dispatcher.ts +7 -0
  203. package/src/extensions/post-bridge.ts +40 -0
  204. package/src/github/handlers.ts +11 -4
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/all-routes.ts +0 -1
  208. package/src/http/config.ts +36 -17
  209. package/src/http/core.ts +4 -0
  210. package/src/http/index.ts +14 -2
  211. package/src/http/integrations.ts +88 -1
  212. package/src/http/mcp-oauth.ts +6 -13
  213. package/src/http/mcp.ts +15 -5
  214. package/src/http/page-proxy.ts +2 -4
  215. package/src/http/pages-public.ts +6 -5
  216. package/src/http/pages.ts +5 -14
  217. package/src/http/poll.ts +28 -68
  218. package/src/http/requested-by.ts +54 -0
  219. package/src/http/route-def.ts +7 -6
  220. package/src/http/script-connection-proxy.ts +51 -4
  221. package/src/http/script-connections.ts +5 -2
  222. package/src/http/scripts.ts +1 -0
  223. package/src/http/session-cost-recompute.ts +12 -2
  224. package/src/http/session-data.ts +4 -0
  225. package/src/http/stats.ts +1 -30
  226. package/src/http/tasks.ts +61 -5
  227. package/src/http/utils.ts +14 -0
  228. package/src/http/webhooks.ts +183 -2
  229. package/src/http/x.ts +1 -0
  230. package/src/integrations/chat-sdk/adapters.ts +129 -0
  231. package/src/integrations/chat-sdk/attachments.ts +232 -0
  232. package/src/integrations/chat-sdk/background.ts +36 -0
  233. package/src/integrations/chat-sdk/commands.ts +194 -0
  234. package/src/integrations/chat-sdk/config.ts +198 -0
  235. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  236. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  237. package/src/integrations/chat-sdk/handlers.ts +28 -0
  238. package/src/integrations/chat-sdk/inbound.ts +426 -0
  239. package/src/integrations/chat-sdk/limits.ts +48 -0
  240. package/src/integrations/chat-sdk/logger.ts +81 -0
  241. package/src/integrations/chat-sdk/outbound.ts +123 -0
  242. package/src/integrations/chat-sdk/relay.ts +172 -0
  243. package/src/integrations/chat-sdk/router.ts +169 -0
  244. package/src/integrations/chat-sdk/runtime.ts +351 -0
  245. package/src/integrations/chat-sdk/schema.ts +245 -0
  246. package/src/integrations/chat-sdk/state.ts +243 -0
  247. package/src/integrations/chat-sdk/status.ts +244 -0
  248. package/src/integrations/chat-sdk/steering.ts +58 -0
  249. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  250. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  251. package/src/integrations/chat-sdk/templates.ts +16 -0
  252. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  253. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  254. package/src/integrations/chat-sdk/typing.ts +65 -0
  255. package/src/jira/adf.ts +3 -1
  256. package/src/kv-reserved-namespaces.ts +2 -0
  257. package/src/oauth/mcp-wrapper.ts +10 -6
  258. package/src/otel-impl.ts +2 -1
  259. package/src/pages/version.ts +4 -5
  260. package/src/prompts/base-prompt.ts +111 -45
  261. package/src/providers/acp-target-catalog.ts +6 -0
  262. package/src/providers/acp-targets.ts +56 -3
  263. package/src/providers/amp-adapter.ts +1 -1
  264. package/src/providers/claude-adapter.ts +27 -2
  265. package/src/providers/claude-flag-settings.ts +133 -0
  266. package/src/providers/claude-managed-adapter.ts +1 -1
  267. package/src/providers/claude-sdk-session.ts +7 -0
  268. package/src/providers/claude-session-events.ts +6 -1
  269. package/src/providers/dsh-adapter.ts +1 -1
  270. package/src/providers/opencode-adapter.ts +268 -37
  271. package/src/providers/opencode-billing.ts +86 -0
  272. package/src/providers/opencode-swarm-plugin.ts +51 -0
  273. package/src/providers/pi-mono-adapter.ts +398 -153
  274. package/src/providers/pricing-sources.md +37 -3
  275. package/src/providers/reasoning-effort.ts +27 -0
  276. package/src/providers/types.ts +11 -2
  277. package/src/rbac/legacy-policy.ts +8 -2
  278. package/src/rbac/permissions.ts +21 -0
  279. package/src/scheduler/scheduler.ts +4 -2
  280. package/src/scripts-runtime/api-client.ts +15 -1
  281. package/src/scripts-runtime/api-types.ts +9 -1
  282. package/src/scripts-runtime/ctx.ts +1 -1
  283. package/src/scripts-runtime/loader.ts +19 -7
  284. package/src/scripts-runtime/mcp-client.ts +30 -19
  285. package/src/scripts-runtime/sdk-allowlist.ts +8 -6
  286. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  287. package/src/scripts-runtime/types/stdlib.d.ts +27 -15
  288. package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
  289. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
  290. package/src/server.ts +52 -18
  291. package/src/slack/actions.ts +29 -1
  292. package/src/slack/app.ts +14 -2
  293. package/src/slack/assistant.ts +36 -2
  294. package/src/slack/channel-join.ts +3 -16
  295. package/src/slack/commands.ts +9 -1
  296. package/src/slack/event-dedup.ts +1 -1
  297. package/src/slack/external-channel-egress.ts +113 -0
  298. package/src/slack/external-channel.ts +309 -0
  299. package/src/slack/handlers.ts +61 -0
  300. package/src/slack/render-v2.ts +40 -47
  301. package/src/slack/work-objects.ts +5 -0
  302. package/src/tasks/additive-buffer.ts +4 -2
  303. package/src/tasks/context-key.ts +94 -2
  304. package/src/tasks/model-pin.ts +67 -0
  305. package/src/tasks/worker-follow-up.ts +4 -31
  306. package/src/telemetry.ts +2 -1
  307. package/src/tests/acp-adapter.test.ts +42 -0
  308. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  309. package/src/tests/apps-catalog-feedback.test.ts +310 -0
  310. package/src/tests/apps-catalog-inputs.test.ts +70 -0
  311. package/src/tests/apps-catalog-table.test.ts +113 -0
  312. package/src/tests/azure-devops-boards-sync.test.ts +584 -0
  313. package/src/tests/azure-devops-html.test.ts +13 -0
  314. package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
  315. package/src/tests/base-prompt.test.ts +58 -54
  316. package/src/tests/chat-sdk-commands.test.ts +191 -0
  317. package/src/tests/chat-sdk-config.test.ts +334 -0
  318. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  319. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  320. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  321. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  322. package/src/tests/chat-sdk-harness.ts +146 -0
  323. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  324. package/src/tests/chat-sdk-relay.test.ts +470 -0
  325. package/src/tests/chat-sdk-reload.test.ts +128 -0
  326. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  327. package/src/tests/chat-sdk-slack.test.ts +268 -0
  328. package/src/tests/chat-sdk-state.test.ts +163 -0
  329. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  330. package/src/tests/chat-sdk-teams.test.ts +277 -0
  331. package/src/tests/chat-sdk-tools.test.ts +520 -0
  332. package/src/tests/chat-sdk-typing.test.ts +120 -0
  333. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  334. package/src/tests/claude-adapter-binary.test.ts +144 -0
  335. package/src/tests/claude-flag-settings.test.ts +114 -0
  336. package/src/tests/claude-managed-adapter.test.ts +1 -1
  337. package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
  338. package/src/tests/claude-sdk-process.fixture.ts +7 -0
  339. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  340. package/src/tests/claude-worker-parity.test.ts +2 -7
  341. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  342. package/src/tests/config-refs.test.ts +66 -0
  343. package/src/tests/context-key.test.ts +51 -0
  344. package/src/tests/cors-allowlist.test.ts +25 -0
  345. package/src/tests/create-page-tool.test.ts +18 -0
  346. package/src/tests/credential-check.test.ts +139 -0
  347. package/src/tests/credentials.test.ts +21 -0
  348. package/src/tests/db-runtime.test.ts +61 -0
  349. package/src/tests/db-task-read-contract.test.ts +20 -0
  350. package/src/tests/db-task-write-contract.test.ts +10 -0
  351. package/src/tests/deferred-task-wake.test.ts +52 -4
  352. package/src/tests/docs-index-footprint.test.js +3 -3
  353. package/src/tests/dsh-adapter.test.ts +1 -1
  354. package/src/tests/enabled-capabilities.test.ts +20 -0
  355. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  356. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  357. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  358. package/src/tests/explicit-model-validation.test.ts +105 -1
  359. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  360. package/src/tests/extensions-post-bridge.test.ts +51 -0
  361. package/src/tests/fetch-resolved-env.test.ts +128 -0
  362. package/src/tests/fixtures/azure-boards/workitem.commented.json +89 -0
  363. package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
  364. package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
  365. package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
  366. package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
  367. package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
  368. package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
  369. package/src/tests/fixtures/catalog-table-definition.json.txt +468 -0
  370. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  371. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  372. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  373. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  374. package/src/tests/fixtures/runner-identity-refresh.ts +3 -0
  375. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  376. package/src/tests/github-handlers.test.ts +35 -0
  377. package/src/tests/harness-provider-resolution.test.ts +12 -0
  378. package/src/tests/heartbeat-checklist.test.ts +3 -2
  379. package/src/tests/hook-runtime-close.test.ts +0 -2
  380. package/src/tests/http-api-integration.test.ts +0 -25
  381. package/src/tests/migration-046-budgets.test.ts +17 -16
  382. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  383. package/src/tests/model-tier-resolution.test.ts +93 -0
  384. package/src/tests/models-catalog.test.ts +42 -1
  385. package/src/tests/node-env-runtime.test.ts +98 -0
  386. package/src/tests/openai-compatible-providers.test.ts +134 -0
  387. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  388. package/src/tests/opencode-adapter.test.ts +348 -3
  389. package/src/tests/opencode-billing.test.ts +28 -0
  390. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  391. package/src/tests/opencode-shell-env.test.ts +145 -0
  392. package/src/tests/openrouter-base-url.test.ts +101 -151
  393. package/src/tests/page-proxy.test.ts +1 -1
  394. package/src/tests/pages-browser-sdk.test.ts +76 -0
  395. package/src/tests/pages-feedback.test.ts +1 -1
  396. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  397. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  398. package/src/tests/pi-mono-adapter.test.ts +385 -5
  399. package/src/tests/pi-shell-env.test.ts +170 -0
  400. package/src/tests/prompt-template-remaining.test.ts +35 -0
  401. package/src/tests/rbac-engine.test.ts +11 -3
  402. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  403. package/src/tests/runner-identity-refresh.test.ts +3 -0
  404. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  405. package/src/tests/script-connections-sql.test.ts +675 -0
  406. package/src/tests/script-connections.test.ts +7 -1
  407. package/src/tests/scripts-http.test.ts +201 -1
  408. package/src/tests/scripts-only-gating.test.ts +2 -3
  409. package/src/tests/scripts-runtime.test.ts +58 -40
  410. package/src/tests/secret-scrubber.test.ts +86 -0
  411. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  412. package/src/tests/seed-skills-retire.test.ts +182 -0
  413. package/src/tests/send-task-requester-gate.test.ts +58 -0
  414. package/src/tests/session-cost-recompute-unit.test.ts +94 -0
  415. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  416. package/src/tests/slack-channel-join.test.ts +4 -1
  417. package/src/tests/slack-external-channel-config.test.ts +65 -0
  418. package/src/tests/slack-external-channel-egress.test.ts +237 -0
  419. package/src/tests/slack-external-channel-guard.test.ts +280 -0
  420. package/src/tests/slack-external-channel-tools.test.ts +173 -0
  421. package/src/tests/slack-external-channel.test.ts +370 -0
  422. package/src/tests/slack-render-v2.test.ts +86 -10
  423. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  424. package/src/tests/spec-base-url.test.ts +16 -1
  425. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  426. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  427. package/src/tests/swarm-diff.test.ts +1 -1
  428. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  429. package/src/tests/task-session-prompts.test.ts +132 -0
  430. package/src/tests/task-tool-manifest.test.ts +14 -0
  431. package/src/tests/task-tools-ctx.test.ts +2 -0
  432. package/src/tests/tool-annotations.test.ts +6 -6
  433. package/src/tests/ui-logs-parser.test.ts +43 -0
  434. package/src/tests/used-by-route.test.ts +6 -0
  435. package/src/tests/vendored-openapi.test.ts +16 -1
  436. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  437. package/src/tests/workflow-swarm-script.test.ts +38 -0
  438. package/src/tests/workflow-wait-filter.test.ts +5 -3
  439. package/src/tools/chat-access.ts +41 -0
  440. package/src/tools/chat-open-dm.ts +59 -0
  441. package/src/tools/chat-post.ts +74 -0
  442. package/src/tools/chat-read-thread.ts +100 -0
  443. package/src/tools/chat-reply.ts +75 -0
  444. package/src/tools/create-page.ts +3 -13
  445. package/src/tools/defer-task.ts +17 -0
  446. package/src/tools/model-catalog/index.ts +2 -1
  447. package/src/tools/register-chat-channel.ts +139 -0
  448. package/src/tools/send-task.ts +24 -0
  449. package/src/tools/skills/skill-get.ts +17 -9
  450. package/src/tools/slack-post.ts +6 -0
  451. package/src/tools/slack-read.ts +8 -0
  452. package/src/tools/slack-reply.ts +6 -0
  453. package/src/tools/slack-start-thread.ts +6 -0
  454. package/src/tools/slack-update.ts +6 -0
  455. package/src/tools/slack-upload-file.ts +6 -0
  456. package/src/tools/swarm-config/get-config.ts +2 -1
  457. package/src/tools/swarm-config/list-config.ts +2 -1
  458. package/src/tools/swarm-config/set-config.ts +16 -3
  459. package/src/tools/tool-config.ts +8 -6
  460. package/src/types.ts +12 -2
  461. package/src/utils/config-env-export.ts +74 -0
  462. package/src/utils/credentials.test.ts +92 -0
  463. package/src/utils/credentials.ts +52 -4
  464. package/src/utils/harness-provider.ts +15 -6
  465. package/src/utils/node-env.ts +24 -0
  466. package/src/utils/runtime-model-catalog.ts +11 -1
  467. package/src/utils/secret-scrubber.ts +71 -2
  468. package/src/utils/task-tool-manifest.ts +19 -2
  469. package/src/workflows/executors/swarm-script.ts +1 -0
  470. package/templates/skills/agent-browser/SKILL.md +1 -1
  471. package/templates/skills/agent-browser/content.md +1 -1
  472. package/templates/skills/apps/SKILL.md +749 -0
  473. package/templates/skills/apps/content.md +60 -22
  474. package/templates/skills/chat-sdk/config.json +14 -0
  475. package/templates/skills/chat-sdk/content.md +84 -0
  476. package/templates/skills/composio-gmail/content.md +7 -0
  477. package/templates/skills/composio-google-docs/content.md +1 -1
  478. package/templates/skills/email-domain-health/config.json +14 -0
  479. package/templates/skills/email-domain-health/content.md +131 -0
  480. package/templates/skills/kv-storage/content.md +2 -2
  481. package/templates/skills/pages/content.md +8 -10
  482. package/templates/skills/qa-loom/config.json +14 -0
  483. package/templates/skills/qa-loom/content.md +187 -0
  484. package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
  485. package/templates/skills/qa-loom/files/run-qa.sh +57 -0
  486. package/templates/skills/slack-interaction/content.md +4 -0
  487. package/templates/skills/swarm-extensions/content.md +2 -0
  488. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  489. package/templates/skills/swarm-scripts/config.json +1 -1
  490. package/templates/skills/swarm-scripts/content.md +4 -2
  491. package/templates/skills/workflow-iterate/content.md +38 -0
  492. package/dist/artifact-eczsknc3.js +0 -3843
  493. package/dist/cli-9xsmdpdt.js +0 -56377
  494. package/dist/cli-bd957dgb.js +0 -153
  495. package/dist/cli-q51yprfq.js +0 -1104
  496. package/dist/cli-t1ze64h3.js +0 -811
  497. package/dist/index-9ch1n761.js +0 -1102
  498. package/src/artifact-sdk/index.ts +0 -2
  499. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  500. package/src/artifact-sdk/port.ts +0 -12
  501. package/src/artifact-sdk/server.ts +0 -183
  502. package/src/artifact-sdk/tunnel.ts +0 -19
  503. package/src/commands/artifact.ts +0 -249
  504. package/src/http/ecosystem.ts +0 -77
  505. package/src/tests/artifact-commands.test.ts +0 -92
  506. package/src/tests/artifact-sdk.test.ts +0 -793
  507. package/src/tests/register-service-security.test.ts +0 -194
  508. package/src/tools/list-services.ts +0 -107
  509. package/src/tools/register-service.ts +0 -177
  510. package/src/tools/unregister-service.ts +0 -73
  511. package/src/tools/update-service-status.ts +0 -96
  512. package/templates/skills/artifacts/config.json +0 -14
  513. package/templates/skills/artifacts/content.md +0 -344
  514. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  515. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  516. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  517. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  518. package/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
  519. package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
  520. package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
  521. package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
  522. package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
  523. package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
  524. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
  525. /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
@@ -12,7 +12,7 @@ import {
12
12
  generateRandomCodeVerifier,
13
13
  generateRandomState,
14
14
  oauthAppRowToProviderConfig
15
- } from "./cli-388egyf6.js";
15
+ } from "./cli-6razj6t4.js";
16
16
  import {
17
17
  CredentialBroker,
18
18
  DEFAULT_CREDENTIAL_BINDINGS,
@@ -36,6 +36,9 @@ import {
36
36
  init_oauth,
37
37
  init_quickjs_pool_config,
38
38
  init_secret_registry,
39
+ init_swarm_config_guard,
40
+ isApiOnlyConfigKey,
41
+ isInternalConfigKey,
39
42
  normalizeDateRequired,
40
43
  oauthSecretName,
41
44
  placeholderForConfigKey,
@@ -46,11 +49,11 @@ import {
46
49
  updateAuthorizationTokens,
47
50
  upsertAuthorization,
48
51
  upsertSwarmConfig
49
- } from "./cli-tgpfnm6r.js";
52
+ } from "./cli-ef1hg1wv.js";
50
53
  import {
51
54
  defaultAssetKey,
52
55
  init_key
53
- } from "./cli-hsem16hb.js";
56
+ } from "./cli-cgtksawx.js";
54
57
  import {
55
58
  init_zod
56
59
  } from "./cli-sd0mxa3c.js";
@@ -69,6 +72,14 @@ import {
69
72
  union,
70
73
  unknown
71
74
  } from "./cli-w5e1d1vv.js";
75
+ import {
76
+ init_node_env,
77
+ isDevOrTestNodeEnv
78
+ } from "./cli-p0sg24zp.js";
79
+ import {
80
+ getMcpBaseUrl,
81
+ init_constants
82
+ } from "./cli-gd4favx9.js";
72
83
  import {
73
84
  init_env_flag,
74
85
  isEnvFlagEnabled
@@ -78,12 +89,13 @@ import {
78
89
  init_api_key
79
90
  } from "./cli-a1b9b32n.js";
80
91
  import {
92
+ createValueScrubber,
81
93
  init_secret_scrubber,
82
94
  refreshSecretScrubberCache,
83
95
  registerVolatileSecret,
84
96
  scrubObject,
85
97
  scrubSecrets
86
- } from "./cli-d161g69q.js";
98
+ } from "./cli-p1x85d2t.js";
87
99
  import {
88
100
  __commonJS,
89
101
  __require,
@@ -175184,6 +175196,7 @@ var require_dist = __commonJS(function(exports) {
175184
175196
 
175185
175197
  // src/scripts-runtime/loader.ts
175186
175198
  init_api_key();
175199
+ init_constants();
175187
175200
  init_secret_scrubber();
175188
175201
 
175189
175202
  // src/scripts-runtime/egress-secrets.ts
@@ -175780,7 +175793,7 @@ async function buildConfigPayload(input) {
175780
175793
  apiKey: { value: apiKey, isSecret: true },
175781
175794
  agentId: { value: input.agentId, isSecret: false },
175782
175795
  mcpBaseUrl: {
175783
- value: input.mcpBaseUrl ?? process.env.MCP_BASE_URL ?? "http://localhost:3013",
175796
+ value: input.mcpBaseUrl ?? getMcpBaseUrl(),
175784
175797
  isSecret: false
175785
175798
  },
175786
175799
  ...input.runtimeInstanceId ? { runtimeInstanceId: { value: input.runtimeInstanceId, isSecret: false } } : {}
@@ -175804,12 +175817,13 @@ async function runScript(input) {
175804
175817
  error: "executor_error"
175805
175818
  };
175806
175819
  }
175820
+ const runSecrets = createValueScrubber(Object.entries(input.userConfig ?? {}).filter(([, entry]) => entry.isSecret).map(([key, entry]) => ({ value: entry.value, name: `config:${key}` })));
175807
175821
  const imports = validateScriptImports(input.source);
175808
175822
  if (!imports.ok) {
175809
175823
  return {
175810
175824
  result: undefined,
175811
175825
  stdout: "",
175812
- stderr: imports.diagnostic,
175826
+ stderr: scrubSecrets(runSecrets.text(imports.diagnostic)),
175813
175827
  truncated: { stdout: false, stderr: false },
175814
175828
  durationMs: 0,
175815
175829
  exitCode: 1,
@@ -175840,10 +175854,10 @@ async function runScript(input) {
175840
175854
  }
175841
175855
  return {
175842
175856
  ...output,
175843
- result: scrubObject(output.result),
175844
- stdout: scrubSecrets(output.stdout),
175845
- stderr: scrubSecrets(output.stderr),
175846
- ...output.runtimeError ? { runtimeError: scrubObject(output.runtimeError) } : {}
175857
+ result: scrubObject(runSecrets.object(output.result)),
175858
+ stdout: scrubSecrets(runSecrets.text(output.stdout)),
175859
+ stderr: scrubSecrets(runSecrets.text(output.stderr)),
175860
+ ...output.runtimeError ? { runtimeError: scrubObject(runSecrets.object(output.runtimeError)) } : {}
175847
175861
  };
175848
175862
  }
175849
175863
 
@@ -175854,6 +175868,7 @@ init_oauth();
175854
175868
 
175855
175869
  // src/oauth/mcp-wrapper.ts
175856
175870
  init_env_flag();
175871
+ init_node_env();
175857
175872
  init_secret_scrubber();
175858
175873
  var PRIVATE_IPV4_BLOCKS = [
175859
175874
  { prefix: "10.", mask: 8 },
@@ -175932,22 +175947,21 @@ function assertUrlSafe(rawUrl, opts = {}) {
175932
175947
  return parsed;
175933
175948
  }
175934
175949
  function publicEndpointSsrfOptions() {
175935
- const env = "development";
175936
- const dev = env === "development" || env === "test" || process.env.ALLOW_PRIVATE_NETWORK_URLS === "true";
175950
+ const dev = isDevOrTestNodeEnv() || process.env.ALLOW_PRIVATE_NETWORK_URLS === "true";
175937
175951
  return {
175938
175952
  allowPrivateHosts: dev,
175939
175953
  allowInsecure: dev
175940
175954
  };
175941
175955
  }
175942
- function defaultSsrfOptions() {
175956
+ function mcpOAuthSsrfOptions() {
175943
175957
  return {
175944
175958
  allowPrivateHosts: isEnvFlagEnabled("MCP_OAUTH_ALLOW_PRIVATE_HOSTS", false),
175945
- allowInsecure: true
175959
+ allowInsecure: isDevOrTestNodeEnv()
175946
175960
  };
175947
175961
  }
175948
175962
  var DEFAULT_FETCH_TIMEOUT_MS = 15000;
175949
175963
  async function safeFetch(url, init, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
175950
- assertUrlSafe(url, defaultSsrfOptions());
175964
+ assertUrlSafe(url, mcpOAuthSsrfOptions());
175951
175965
  return fetch(url, { ...init, signal: init?.signal ?? AbortSignal.timeout(timeoutMs) });
175952
175966
  }
175953
175967
  async function discoverProtectedResourceMetadata(resourceUrl) {
@@ -176801,6 +176815,82 @@ async function callMcpServerTool(serverId, tool, args, context = {}) {
176801
176815
  return client.callToolRaw(tool, args);
176802
176816
  }
176803
176817
 
176818
+ // src/be/sql-connections.ts
176819
+ init_db2();
176820
+ init_secret_scrubber();
176821
+ var SQL_MAX_ROWS = 1000;
176822
+ var SQL_MAX_BYTES = 5 * 1024 * 1024;
176823
+ var SQL_FETCH_BATCH = 100;
176824
+ function assertPostgresDsn(dsn) {
176825
+ if (!URL.canParse(dsn) || !["postgres:", "postgresql:"].includes(new URL(dsn).protocol)) {
176826
+ throw new Error("SQL connection DSN must be a postgres:// or postgresql:// URL.");
176827
+ }
176828
+ }
176829
+ async function resolveSqlDsn(connection, agentId) {
176830
+ const key = connection.authConfigKey;
176831
+ if (!key)
176832
+ throw new Error("SQL connection has no DSN config key.");
176833
+ const repoId = connection.scope === "repo" ? connection.scopeId ?? undefined : undefined;
176834
+ const dsn = (await getResolvedConfig(agentId, repoId)).find((c) => c.key === key)?.value;
176835
+ if (!dsn)
176836
+ throw new Error(`SQL connection DSN '${key}' is not set.`);
176837
+ registerVolatileSecret(dsn, key);
176838
+ if (URL.canParse(dsn))
176839
+ registerVolatileSecret(decodeURIComponent(new URL(dsn).password), key);
176840
+ assertPostgresDsn(dsn);
176841
+ return dsn;
176842
+ }
176843
+ var asTemplate = (text) => Object.assign([text], { raw: [text] });
176844
+ var defaultExecutor = async (dsn, query, params, take) => {
176845
+ const sql = new Bun.SQL({
176846
+ adapter: "postgres",
176847
+ url: dsn,
176848
+ max: 1,
176849
+ connectionTimeout: 10,
176850
+ connection: { default_transaction_read_only: "on", statement_timeout: 30000 }
176851
+ });
176852
+ try {
176853
+ await sql.begin("read only", async (tx) => {
176854
+ const declare = `declare swarm_sql_cursor no scroll cursor for ${query}`;
176855
+ await (params.length > 0 ? tx.unsafe(declare, params) : tx(asTemplate(declare)));
176856
+ const fetchNext = asTemplate(`fetch ${SQL_FETCH_BATCH} from swarm_sql_cursor`);
176857
+ for (;; ) {
176858
+ const batch = [...await tx(fetchNext)];
176859
+ if (!take(batch) || batch.length < SQL_FETCH_BATCH)
176860
+ return;
176861
+ }
176862
+ });
176863
+ } finally {
176864
+ await sql.close();
176865
+ }
176866
+ };
176867
+ var sqlExecutorForTesting = null;
176868
+ async function runReadOnlyQuery(dsn, query, params = []) {
176869
+ const rows = [];
176870
+ let bytes = 0;
176871
+ let truncated = false;
176872
+ const take = (batch) => {
176873
+ for (const row of batch) {
176874
+ const size = Buffer.byteLength(JSON.stringify(row, (_, v) => typeof v === "bigint" ? v.toString() : v));
176875
+ if (rows.length >= SQL_MAX_ROWS || bytes + size > SQL_MAX_BYTES) {
176876
+ truncated = true;
176877
+ return false;
176878
+ }
176879
+ bytes += size;
176880
+ rows.push(row);
176881
+ }
176882
+ return true;
176883
+ };
176884
+ try {
176885
+ await (sqlExecutorForTesting ?? defaultExecutor)(dsn, query, params, take);
176886
+ return { rows, rowCount: rows.length, truncated };
176887
+ } catch (err) {
176888
+ const code = err.errno;
176889
+ const message = err instanceof Error ? err.message : String(err);
176890
+ throw new Error(scrubSecrets(typeof code === "string" ? `${message} (SQLSTATE ${code})` : message));
176891
+ }
176892
+ }
176893
+
176804
176894
  // src/be/vendored-openapi.ts
176805
176895
  import { readFileSync } from "node:fs";
176806
176896
  import path from "node:path";
@@ -176899,6 +176989,9 @@ var ConnectionAuthInputSchema = exports_external.discriminatedUnion("type", [
176899
176989
  hosts: authHostsSchema
176900
176990
  })
176901
176991
  ]);
176992
+ var SqlDsnInputSchema = exports_external.object({ secret: authSecretSchema, configKey: authConfigKeySchema }).refine((dsn) => dsn.secret === undefined !== (dsn.configKey === undefined), {
176993
+ message: "Provide exactly one of `secret` or `configKey` for the SQL DSN."
176994
+ });
176902
176995
  function parseJsonArray(value) {
176903
176996
  try {
176904
176997
  const parsed = JSON.parse(value);
@@ -177620,7 +177713,9 @@ function assertConfigKeyNotReserved(auth) {
177620
177713
  function derivedInlineSecretKey(connection) {
177621
177714
  if (!connection)
177622
177715
  return null;
177623
- if (connection.authType === "none" || connection.authType === "oauth")
177716
+ if (connection.authType === "oauth")
177717
+ return null;
177718
+ if (connection.authType === "none" && connection.kind !== "sql")
177624
177719
  return null;
177625
177720
  const key = connection.authConfigKey;
177626
177721
  return key && DERIVED_INLINE_SECRET_KEY.test(key) ? key : null;
@@ -177781,6 +177876,9 @@ async function upsertScriptConnection(data) {
177781
177876
  if (data.kind === "mcp" && data.auth && data.auth.type !== "none") {
177782
177877
  throw new Error("MCP connections resolve auth through their MCP server; `auth` is not supported.");
177783
177878
  }
177879
+ if (data.kind === "sql" && data.auth && data.auth.type !== "none") {
177880
+ throw new Error("SQL connections authenticate through their DSN; `auth` is not supported.");
177881
+ }
177784
177882
  assertConfigKeyNotReserved(data.auth);
177785
177883
  if (data.kind === "openapi" && existingConnection?.openapiSpecJson && data.openapiSpecJson == null && data.openapiSpecUrl == null && data.openapiSpecSource == null) {
177786
177884
  openapiSpecJson = existingConnection.openapiSpecJson;
@@ -177790,7 +177888,7 @@ async function upsertScriptConnection(data) {
177790
177888
  openapiSpecFetchedAt = existingConnection.openapiSpecFetchedAt;
177791
177889
  }
177792
177890
  const explicitLegacyBinding = data.auth === undefined && data.credentialBindingId !== undefined;
177793
- const authIntent = data.kind === "mcp" || explicitLegacyBinding ? { type: "none" } : data.auth ?? reconstructAuthFromConnection(existingConnection);
177891
+ const authIntent = data.kind === "mcp" || data.kind === "sql" || explicitLegacyBinding ? { type: "none" } : data.auth ?? reconstructAuthFromConnection(existingConnection);
177794
177892
  let derived = null;
177795
177893
  const explicitBinding = explicitLegacyBinding && data.credentialBindingId ? await getCredentialBindingById(data.credentialBindingId) : null;
177796
177894
  const explicitBindingCredential = explicitBinding ? {
@@ -177913,17 +178011,41 @@ async function upsertScriptConnection(data) {
177913
178011
  generatedRuntimeJson = artifacts.generatedRuntimeJson;
177914
178012
  generatedAt = now;
177915
178013
  }
178014
+ let sqlDsnKey = null;
178015
+ let sqlSecretWrite = null;
178016
+ if (data.kind === "sql") {
178017
+ if (data.sqlDsn?.secret !== undefined) {
178018
+ assertPostgresDsn(data.sqlDsn.secret);
178019
+ sqlDsnKey = `connection.${normalizedSlug}.secret`;
178020
+ sqlSecretWrite = { scope, scopeId, key: sqlDsnKey, value: data.sqlDsn.secret };
178021
+ } else if (data.sqlDsn?.configKey) {
178022
+ assertConfigKeyNotReserved({ type: "bearer", configKey: data.sqlDsn.configKey });
178023
+ sqlDsnKey = data.sqlDsn.configKey;
178024
+ } else {
178025
+ sqlDsnKey = existingConnection?.kind === "sql" ? existingConnection.authConfigKey : null;
178026
+ }
178027
+ if (!sqlDsnKey)
178028
+ throw new Error("SQL connections require `dsn.secret` or `dsn.configKey`.");
178029
+ generatedRuntimeJson = JSON.stringify({ slug: normalizedSlug, kind: "sql", connectionId });
178030
+ generatedTypes = `export interface ${pascal(normalizedSlug)}Api {
178031
+ /** One read-only statement; pass values via params ($1, $2, ...). */
178032
+ query<T = Record<string, JsonValue>>(sql: string, params?: JsonValue[]): Promise<{ rows: T[]; rowCount: number; truncated: boolean }>;
178033
+ }`;
178034
+ generatedAt = now;
178035
+ }
177916
178036
  if (data.kind !== "graphql") {
177917
178037
  allowedHosts = data.allowedHosts ?? (effectiveBaseUrl ? [new URL(effectiveBaseUrl).hostname] : []);
177918
178038
  }
177919
178039
  const oldDerivedSecretKey = derivedInlineSecretKey(existingConnection);
177920
- const newReferencedConfigKey = derived?.configKey ?? explicitBinding?.configKey ?? null;
178040
+ const newReferencedConfigKey = derived?.configKey ?? explicitBinding?.configKey ?? sqlDsnKey ?? null;
177921
178041
  let supersededSecretDeleted = false;
177922
178042
  const writeConnectionAndBinding = () => getDbClient().transaction(async (tx) => {
177923
178043
  await tx.run("PRAGMA defer_foreign_keys = ON");
177924
178044
  if (derived?.secretWrite) {
177925
178045
  await upsertSwarmConfig({ ...derived.secretWrite, isSecret: true });
177926
178046
  }
178047
+ if (sqlSecretWrite)
178048
+ await upsertSwarmConfig({ ...sqlSecretWrite, isSecret: true });
177927
178049
  if (oldDerivedSecretKey && oldDerivedSecretKey !== newReferencedConfigKey) {
177928
178050
  await deleteManagedConnectionSecret({
177929
178051
  scope: existingConnection?.scope ?? scope,
@@ -177964,6 +178086,8 @@ async function upsertScriptConnection(data) {
177964
178086
  credentialBindingId = existingConnection && existingManaged && existingConnection.credentialBindingId === existingManaged.id ? null : existingConnection?.credentialBindingId ?? null;
177965
178087
  authCols = NONE_AUTH_COLUMNS;
177966
178088
  }
178089
+ if (sqlDsnKey)
178090
+ authCols = { ...NONE_AUTH_COLUMNS, authConfigKey: sqlDsnKey };
177967
178091
  const params = [
177968
178092
  normalizedSlug,
177969
178093
  data.displayName ?? null,
@@ -178027,8 +178151,9 @@ async function upsertScriptConnection(data) {
178027
178151
  return row2;
178028
178152
  });
178029
178153
  const row = await writeConnectionAndBinding();
178030
- if (derived?.secretWrite || supersededSecretDeleted)
178154
+ if (derived?.secretWrite || sqlSecretWrite || supersededSecretDeleted) {
178031
178155
  refreshSecretScrubberCache();
178156
+ }
178032
178157
  return connectionFromRow(row);
178033
178158
  }
178034
178159
  async function refreshScriptConnection(id, userId, callerAgentId) {
@@ -178143,7 +178268,7 @@ async function deleteScriptConnection(id) {
178143
178268
  return deleted;
178144
178269
  }
178145
178270
  function getScriptApiConnectionDescriptors(context = {}) {
178146
- return listScriptConnections(context).filter((connection) => connection.kind === "openapi" || connection.kind === "graphql").map((connection) => {
178271
+ return listScriptConnections(context).filter((connection) => ["openapi", "graphql", "sql"].includes(connection.kind)).map((connection) => {
178147
178272
  if (!connection.generatedRuntimeJson)
178148
178273
  return null;
178149
178274
  try {
@@ -178165,7 +178290,7 @@ function getScriptMcpConnectionDescriptors(context = {}) {
178165
178290
  }).filter((descriptor) => Boolean(descriptor));
178166
178291
  }
178167
178292
  function getScriptApiTypes(context = {}) {
178168
- const connections = listScriptConnections(context).filter((connection) => connection.kind === "openapi" || connection.kind === "graphql");
178293
+ const connections = listScriptConnections(context).filter((connection) => ["openapi", "graphql", "sql"].includes(connection.kind));
178169
178294
  const blocks = connections.filter((connection) => connection.generatedTypes).map((connection) => connection.generatedTypes);
178170
178295
  if (blocks.length === 0)
178171
178296
  return `export interface ScriptApiRegistry {}
@@ -178246,13 +178371,25 @@ async function resolveOAuthBindingToken(oauthAuthorizationId) {
178246
178371
  }
178247
178372
 
178248
178373
  // src/be/script-credential-broker.ts
178374
+ init_swarm_config_guard();
178375
+
178249
178376
  class RelationalCredentialBindingStore {
178250
178377
  listActiveBindings(context) {
178251
178378
  return listRelationalCredentialBindings(context);
178252
178379
  }
178253
178380
  }
178381
+ function toScriptUserConfig(configs) {
178382
+ const exposed = configs.filter((config) => !isApiOnlyConfigKey(config.key) && !isInternalConfigKey(config.key));
178383
+ for (const config of exposed) {
178384
+ if (config.isSecret && config.value) {
178385
+ registerVolatileSecret(config.value, `config:${config.key}`);
178386
+ }
178387
+ }
178388
+ return Object.fromEntries(exposed.map((config) => [config.key, { value: config.value, isSecret: config.isSecret }]));
178389
+ }
178254
178390
  async function buildScriptCredentialBindingsWithFailures(input) {
178255
178391
  const resolvedConfigs = await getResolvedConfig(input.agentId, input.repoId);
178392
+ const userConfig = toScriptUserConfig(resolvedConfigs);
178256
178393
  const configMap = new Map(resolvedConfigs.map((config) => [config.key, config.value]));
178257
178394
  const broker = new CredentialBroker(new RelationalCredentialBindingStore, (configKey) => configMap.get(configKey) ?? process.env[configKey], DEFAULT_CREDENTIAL_BINDINGS, (oauthAuthorizationId) => resolveOAuthBindingToken(oauthAuthorizationId));
178258
178395
  const { resolved, failed } = await broker.resolveBindingsWithFailures({
@@ -178262,10 +178399,11 @@ async function buildScriptCredentialBindingsWithFailures(input) {
178262
178399
  for (const binding of resolved) {
178263
178400
  registerVolatileSecret(binding.value, binding.configKey);
178264
178401
  }
178265
- return { egressSecrets: resolved, failedBindings: failed };
178266
- }
178267
- async function buildScriptCredentialBindings(input) {
178268
- return (await buildScriptCredentialBindingsWithFailures(input)).egressSecrets;
178402
+ return {
178403
+ egressSecrets: resolved,
178404
+ failedBindings: failed,
178405
+ userConfig
178406
+ };
178269
178407
  }
178270
178408
 
178271
178409
  // src/be/scripts/run-saved.ts
@@ -178292,6 +178430,7 @@ async function runSavedScriptAsAgent(args, deps = {}) {
178292
178430
  agentId: args.agentId,
178293
178431
  egressSecrets: credentials.egressSecrets,
178294
178432
  failedBindings: credentials.failedBindings,
178433
+ userConfig: credentials.userConfig,
178295
178434
  apiConnections: getScriptApiConnectionDescriptors({ agentId: args.agentId }),
178296
178435
  mcpConnections: getScriptMcpConnectionDescriptors({ agentId: args.agentId }),
178297
178436
  ...args.timeoutMs ? { timeoutMs: args.timeoutMs } : {},
@@ -178436,6 +178575,16 @@ var catalog_generated_default = {
178436
178575
  "Metric",
178437
178576
  "Alert",
178438
178577
  "Badge",
178578
+ "Icon",
178579
+ "Progress",
178580
+ "EmptyState",
178581
+ "CopyButton",
178582
+ "Kbd",
178583
+ "Skeleton",
178584
+ "Spinner",
178585
+ "AvatarStack",
178586
+ "Section",
178587
+ "Chips",
178439
178588
  "Table",
178440
178589
  "Form",
178441
178590
  "Drawer",
@@ -178449,6 +178598,7 @@ var catalog_generated_default = {
178449
178598
  actionTypes: [
178450
178599
  "swarm.sdk",
178451
178600
  "swarm.call",
178601
+ "ui.toast",
178452
178602
  "app.mutate",
178453
178603
  "app.refresh",
178454
178604
  "app.action",
@@ -178456,7 +178606,7 @@ var catalog_generated_default = {
178456
178606
  ],
178457
178607
  components: {
178458
178608
  Stack: {
178459
- description: "THE primary layout primitive — a flex column (default) or row of its children. `gap`/`padding` use the shared spacing scale (none|xs|sm|md|lg|xl, default gap md); `align` is the cross axis, `justify` the main axis, `wrap` lets a row reflow. For rows, set `collapseBelow` (sm|md|lg) so the row stacks vertically on narrow viewports — filter bars should always set it. Use this as the page root and for every section; `Container` is the legacy 2-prop alias kept for older pages.",
178609
+ description: "THE primary layout primitive — a flex column (default) or row of its children. `gap`/`padding` use the shared spacing scale (none|xs|sm|md|lg|xl, default gap md); `align` is the cross axis, `justify` the main axis, `wrap` lets a row reflow. For rows, set `collapseBelow` (sm|md|lg) so the row stacks vertically on narrow viewports — filter bars should always set it. `motion` (rise|fade|none, default rise) is the entrance of the direct children on first paint: a 200ms fade plus a 4px rise, staggered 30ms; it never replays on data polls, nested Stacks inherit the parent's entrance, and reduced-motion viewers get a short fade. Use this as the page root and for every section; `Container` is the legacy 2-prop alias kept for older pages.",
178460
178610
  slots: ["default"],
178461
178611
  props: {
178462
178612
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -178488,6 +178638,10 @@ var catalog_generated_default = {
178488
178638
  collapseBelow: {
178489
178639
  type: "string",
178490
178640
  enum: ["sm", "md", "lg"]
178641
+ },
178642
+ motion: {
178643
+ type: "string",
178644
+ enum: ["rise", "fade", "none"]
178491
178645
  }
178492
178646
  },
178493
178647
  additionalProperties: false
@@ -178591,7 +178745,7 @@ var catalog_generated_default = {
178591
178745
  }
178592
178746
  },
178593
178747
  Tabs: {
178594
- description: 'Tabbed sections. POSITIONAL children: children[i] is the body of tabs[i], so declare exactly as many children as tabs, in the same order. Only the active tab is visible but every child stays mounted, so polled Tables in background tabs keep their data warm. The active key is mirrored into state at `/ui/<id>/tab`, so other components can bind `{ "$state": "/ui/<id>/tab" }`. `defaultTab` picks the initial key (defaults to the first tab).',
178748
+ description: 'Tabbed sections. POSITIONAL children: children[i] is the body of tabs[i], so declare exactly as many children as tabs, in the same order. Only the active tab is visible but every child stays mounted, so polled Tables in background tabs keep their data warm. The active key is mirrored into state at `/ui/<id>/tab`, so other components can bind `{ "$state": "/ui/<id>/tab" }`. `defaultTab` picks the initial key (defaults to the first tab). Tab entries take an optional `icon` and `count` (a small count pill; a literal or a bound number). `variant: "segmented"` renders a compact segmented control instead of the tab strip (same state and warm panels).',
178595
178749
  slots: ["default"],
178596
178750
  props: {
178597
178751
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -178611,6 +178765,54 @@ var catalog_generated_default = {
178611
178765
  },
178612
178766
  label: {
178613
178767
  type: "string"
178768
+ },
178769
+ icon: {
178770
+ type: "string",
178771
+ enum: [
178772
+ "plus",
178773
+ "refresh-cw",
178774
+ "search",
178775
+ "filter",
178776
+ "download",
178777
+ "upload",
178778
+ "external-link",
178779
+ "copy",
178780
+ "check",
178781
+ "x",
178782
+ "trash-2",
178783
+ "pencil",
178784
+ "eye",
178785
+ "calendar",
178786
+ "clock",
178787
+ "user",
178788
+ "users",
178789
+ "bot",
178790
+ "git-pull-request",
178791
+ "git-branch",
178792
+ "github",
178793
+ "slack",
178794
+ "mail",
178795
+ "link",
178796
+ "file-text",
178797
+ "folder",
178798
+ "database",
178799
+ "zap",
178800
+ "sparkles",
178801
+ "flag",
178802
+ "star",
178803
+ "tag",
178804
+ "alert-triangle",
178805
+ "info",
178806
+ "circle-check",
178807
+ "trending-up",
178808
+ "trending-down",
178809
+ "dollar-sign",
178810
+ "activity",
178811
+ "rocket"
178812
+ ]
178813
+ },
178814
+ count: {
178815
+ type: "number"
178614
178816
  }
178615
178817
  },
178616
178818
  required: ["key"],
@@ -178619,6 +178821,10 @@ var catalog_generated_default = {
178619
178821
  },
178620
178822
  defaultTab: {
178621
178823
  type: "string"
178824
+ },
178825
+ variant: {
178826
+ type: "string",
178827
+ enum: ["line", "segmented"]
178622
178828
  }
178623
178829
  },
178624
178830
  required: ["id", "tabs"],
@@ -178712,7 +178918,7 @@ var catalog_generated_default = {
178712
178918
  }
178713
178919
  },
178714
178920
  SearchInput: {
178715
- description: 'Free-text search box. Writes the debounced (~200ms) query into state at `/ui/<id>/value`; bind it into a Table with `"search": { "$state": "/ui/<id>/value" }`. Purely client-side — it filters rows the page already polled, it does not re-run the query.',
178921
+ description: 'Free-text search box. Writes the debounced (~200ms) query into state at `/ui/<id>/value`; bind it into a Table with `"search": { "$state": "/ui/<id>/value" }`. Purely client-side — it filters rows the page already polled, it does not re-run the query. `shortcut` (usually `"/"`) shows a keycap hint and focuses the field when pressed outside a text field.',
178716
178922
  props: {
178717
178923
  $schema: "http://json-schema.org/draft-07/schema#",
178718
178924
  type: "object",
@@ -178725,6 +178931,11 @@ var catalog_generated_default = {
178725
178931
  },
178726
178932
  label: {
178727
178933
  type: "string"
178934
+ },
178935
+ shortcut: {
178936
+ type: "string",
178937
+ minLength: 1,
178938
+ maxLength: 12
178728
178939
  }
178729
178940
  },
178730
178941
  required: ["id"],
@@ -178732,7 +178943,7 @@ var catalog_generated_default = {
178732
178943
  }
178733
178944
  },
178734
178945
  Select: {
178735
- description: 'Dropdown filter/picker. `options` are plain strings or `{ value, label }` objects. Writes the chosen value into state at `/ui/<id>/value` (clearing writes `null`); bind it into a Table with `"filters": { "<column>": { "$state": "/ui/<id>/value" } }`. `clearable` (default true) shows a clear button.',
178946
+ description: 'Dropdown filter/picker. `options` are plain strings or `{ value, label?, icon?, hint? }` objects. Writes the chosen value into state at `/ui/<id>/value` (clearing writes `null`); bind it into a Table with `"filters": { "<column>": { "$state": "/ui/<id>/value" } }`. `clearable` (default true) shows a clear button. `searchable` adds a type-to-filter field (on by default past 8 options; `searchPlaceholder` sets its hint). `multiple` picks several: the value is a string array (empty = nothing picked), which a Table filter reads as "cell is one of".',
178736
178947
  props: {
178737
178948
  $schema: "http://json-schema.org/draft-07/schema#",
178738
178949
  type: "object",
@@ -178756,6 +178967,54 @@ var catalog_generated_default = {
178756
178967
  },
178757
178968
  label: {
178758
178969
  type: "string"
178970
+ },
178971
+ icon: {
178972
+ type: "string",
178973
+ enum: [
178974
+ "plus",
178975
+ "refresh-cw",
178976
+ "search",
178977
+ "filter",
178978
+ "download",
178979
+ "upload",
178980
+ "external-link",
178981
+ "copy",
178982
+ "check",
178983
+ "x",
178984
+ "trash-2",
178985
+ "pencil",
178986
+ "eye",
178987
+ "calendar",
178988
+ "clock",
178989
+ "user",
178990
+ "users",
178991
+ "bot",
178992
+ "git-pull-request",
178993
+ "git-branch",
178994
+ "github",
178995
+ "slack",
178996
+ "mail",
178997
+ "link",
178998
+ "file-text",
178999
+ "folder",
179000
+ "database",
179001
+ "zap",
179002
+ "sparkles",
179003
+ "flag",
179004
+ "star",
179005
+ "tag",
179006
+ "alert-triangle",
179007
+ "info",
179008
+ "circle-check",
179009
+ "trending-up",
179010
+ "trending-down",
179011
+ "dollar-sign",
179012
+ "activity",
179013
+ "rocket"
179014
+ ]
179015
+ },
179016
+ hint: {
179017
+ type: "string"
178759
179018
  }
178760
179019
  },
178761
179020
  required: ["value"],
@@ -178772,6 +179031,15 @@ var catalog_generated_default = {
178772
179031
  },
178773
179032
  clearable: {
178774
179033
  type: "boolean"
179034
+ },
179035
+ searchable: {
179036
+ type: "boolean"
179037
+ },
179038
+ multiple: {
179039
+ type: "boolean"
179040
+ },
179041
+ searchPlaceholder: {
179042
+ type: "string"
178775
179043
  }
178776
179044
  },
178777
179045
  required: ["id", "options"],
@@ -178779,7 +179047,7 @@ var catalog_generated_default = {
178779
179047
  }
178780
179048
  },
178781
179049
  Button: {
178782
- description: 'Interactive button. Wire to actions via `on.press`. `variant: "destructive-outline"` is the canonical red-outlined destructive look (standalone deletes should use it, not solid red). `disabled` accepts a constant or a bound boolean; `busyWith: "<actionName>"` disables the button and shows a spinner while that custom action is running.',
179050
+ description: 'Interactive button. Wire to actions via `on.press`. `variant: "destructive-outline"` is the canonical red-outlined destructive look (standalone deletes should use it, not solid red). `disabled` accepts a constant or a bound boolean; `busyWith: "<actionName>"` swaps the label for a spinner (presses ignored) while that custom action is running, then shows a check plus `successLabel` for ~1.5s when it finishes ok. `icon` + `iconPosition` (start|end) add an icon from the curated set; `size` sm|default|lg. `shortcut` (one key, e.g. `"n"`) shows a keycap inside the button and presses it from anywhere on the page (not while typing in a field, not with Ctrl/Cmd/Alt). `hint` is a hover tooltip.',
178783
179051
  props: {
178784
179052
  $schema: "http://json-schema.org/draft-07/schema#",
178785
179053
  type: "object",
@@ -178803,6 +179071,70 @@ var catalog_generated_default = {
178803
179071
  },
178804
179072
  busyWith: {
178805
179073
  type: "string"
179074
+ },
179075
+ icon: {
179076
+ type: "string",
179077
+ enum: [
179078
+ "plus",
179079
+ "refresh-cw",
179080
+ "search",
179081
+ "filter",
179082
+ "download",
179083
+ "upload",
179084
+ "external-link",
179085
+ "copy",
179086
+ "check",
179087
+ "x",
179088
+ "trash-2",
179089
+ "pencil",
179090
+ "eye",
179091
+ "calendar",
179092
+ "clock",
179093
+ "user",
179094
+ "users",
179095
+ "bot",
179096
+ "git-pull-request",
179097
+ "git-branch",
179098
+ "github",
179099
+ "slack",
179100
+ "mail",
179101
+ "link",
179102
+ "file-text",
179103
+ "folder",
179104
+ "database",
179105
+ "zap",
179106
+ "sparkles",
179107
+ "flag",
179108
+ "star",
179109
+ "tag",
179110
+ "alert-triangle",
179111
+ "info",
179112
+ "circle-check",
179113
+ "trending-up",
179114
+ "trending-down",
179115
+ "dollar-sign",
179116
+ "activity",
179117
+ "rocket"
179118
+ ]
179119
+ },
179120
+ iconPosition: {
179121
+ type: "string",
179122
+ enum: ["start", "end"]
179123
+ },
179124
+ successLabel: {
179125
+ type: "string"
179126
+ },
179127
+ size: {
179128
+ type: "string",
179129
+ enum: ["sm", "default", "lg"]
179130
+ },
179131
+ shortcut: {
179132
+ type: "string",
179133
+ minLength: 1,
179134
+ maxLength: 12
179135
+ },
179136
+ hint: {
179137
+ type: "string"
178806
179138
  }
178807
179139
  },
178808
179140
  required: ["label"],
@@ -178810,7 +179142,7 @@ var catalog_generated_default = {
178810
179142
  }
178811
179143
  },
178812
179144
  Metric: {
178813
- description: 'Single label/value tile for status pages. Bind `loading` to the backing query (`{ "$state": "/queries/<name>/loading" }`) to show a skeleton instead of a blank value while it loads.',
179145
+ description: 'Stat tile (the dashboard `StatPanel`): label, value, optional `detail` line and `trend: { direction: "up"|"down"|"flat", label }` (arrow plus success/error/muted text). `icon` adds a tile tinted by `tone` (neutral|success|active|error|info|pending|warning|paused); `info` is a one-sentence explanation in a tooltip next to the label. Bind `loading` to the backing query (`{ "$state": "/queries/<name>/loading" }`) to show a skeleton instead of a blank value while it loads; an empty value renders an em dash.',
178814
179146
  props: {
178815
179147
  $schema: "http://json-schema.org/draft-07/schema#",
178816
179148
  type: "object",
@@ -178830,6 +179162,84 @@ var catalog_generated_default = {
178830
179162
  },
178831
179163
  loading: {
178832
179164
  type: "boolean"
179165
+ },
179166
+ icon: {
179167
+ type: "string",
179168
+ enum: [
179169
+ "plus",
179170
+ "refresh-cw",
179171
+ "search",
179172
+ "filter",
179173
+ "download",
179174
+ "upload",
179175
+ "external-link",
179176
+ "copy",
179177
+ "check",
179178
+ "x",
179179
+ "trash-2",
179180
+ "pencil",
179181
+ "eye",
179182
+ "calendar",
179183
+ "clock",
179184
+ "user",
179185
+ "users",
179186
+ "bot",
179187
+ "git-pull-request",
179188
+ "git-branch",
179189
+ "github",
179190
+ "slack",
179191
+ "mail",
179192
+ "link",
179193
+ "file-text",
179194
+ "folder",
179195
+ "database",
179196
+ "zap",
179197
+ "sparkles",
179198
+ "flag",
179199
+ "star",
179200
+ "tag",
179201
+ "alert-triangle",
179202
+ "info",
179203
+ "circle-check",
179204
+ "trending-up",
179205
+ "trending-down",
179206
+ "dollar-sign",
179207
+ "activity",
179208
+ "rocket"
179209
+ ]
179210
+ },
179211
+ tone: {
179212
+ type: "string",
179213
+ enum: [
179214
+ "neutral",
179215
+ "success",
179216
+ "active",
179217
+ "error",
179218
+ "info",
179219
+ "pending",
179220
+ "warning",
179221
+ "paused"
179222
+ ]
179223
+ },
179224
+ detail: {
179225
+ type: "string"
179226
+ },
179227
+ info: {
179228
+ type: "string"
179229
+ },
179230
+ trend: {
179231
+ type: "object",
179232
+ properties: {
179233
+ direction: {
179234
+ type: "string",
179235
+ enum: ["up", "down", "flat"]
179236
+ },
179237
+ label: {
179238
+ type: "string"
179239
+ }
179240
+ },
179241
+ required: ["direction", "label"],
179242
+ additionalProperties: false
178833
179243
  }
178834
179244
  },
178835
179245
  required: ["label", "value"],
@@ -178837,7 +179247,7 @@ var catalog_generated_default = {
178837
179247
  }
178838
179248
  },
178839
179249
  Alert: {
178840
- description: "Status-toned inline alert.",
179250
+ description: "Status-toned inline alert. `icon` overrides the tone's default icon. `actionLabel` adds a button inside the callout that emits the element's `press` event (wire it with `on.press`).",
178841
179251
  props: {
178842
179252
  $schema: "http://json-schema.org/draft-07/schema#",
178843
179253
  type: "object",
@@ -178851,6 +179261,54 @@ var catalog_generated_default = {
178851
179261
  },
178852
179262
  title: {
178853
179263
  type: "string"
179264
+ },
179265
+ icon: {
179266
+ type: "string",
179267
+ enum: [
179268
+ "plus",
179269
+ "refresh-cw",
179270
+ "search",
179271
+ "filter",
179272
+ "download",
179273
+ "upload",
179274
+ "external-link",
179275
+ "copy",
179276
+ "check",
179277
+ "x",
179278
+ "trash-2",
179279
+ "pencil",
179280
+ "eye",
179281
+ "calendar",
179282
+ "clock",
179283
+ "user",
179284
+ "users",
179285
+ "bot",
179286
+ "git-pull-request",
179287
+ "git-branch",
179288
+ "github",
179289
+ "slack",
179290
+ "mail",
179291
+ "link",
179292
+ "file-text",
179293
+ "folder",
179294
+ "database",
179295
+ "zap",
179296
+ "sparkles",
179297
+ "flag",
179298
+ "star",
179299
+ "tag",
179300
+ "alert-triangle",
179301
+ "info",
179302
+ "circle-check",
179303
+ "trending-up",
179304
+ "trending-down",
179305
+ "dollar-sign",
179306
+ "activity",
179307
+ "rocket"
179308
+ ]
179309
+ },
179310
+ actionLabel: {
179311
+ type: "string"
178854
179312
  }
178855
179313
  },
178856
179314
  required: ["message"],
@@ -178858,7 +179316,7 @@ var catalog_generated_default = {
178858
179316
  }
178859
179317
  },
178860
179318
  Badge: {
178861
- description: "Status pill (uppercase tag chip) with a semantic tone.",
179319
+ description: "Small chip. `variant`: `tag` (default, the uppercase status chip with a tone dot), `status` (11px sentence-case pill with a dot or icon), `count` (compact rounded numeric pill), `beta` (the BETA tag; `hint` is its tooltip). `tone` is neutral|success|active|error|info|pending|warning|paused; `icon` replaces the dot. `status` takes a lifecycle value (pending, in_progress, completed, failed, cancelled, paused, ...) and renders the dashboard status chip with its icon and label — any other value falls back to a toned pill showing `text`. `hint` adds a hover tooltip.",
178862
179320
  props: {
178863
179321
  $schema: "http://json-schema.org/draft-07/schema#",
178864
179322
  type: "object",
@@ -178885,14 +179343,465 @@ var catalog_generated_default = {
178885
179343
  "warning",
178886
179344
  "paused"
178887
179345
  ]
179346
+ },
179347
+ icon: {
179348
+ type: "string",
179349
+ enum: [
179350
+ "plus",
179351
+ "refresh-cw",
179352
+ "search",
179353
+ "filter",
179354
+ "download",
179355
+ "upload",
179356
+ "external-link",
179357
+ "copy",
179358
+ "check",
179359
+ "x",
179360
+ "trash-2",
179361
+ "pencil",
179362
+ "eye",
179363
+ "calendar",
179364
+ "clock",
179365
+ "user",
179366
+ "users",
179367
+ "bot",
179368
+ "git-pull-request",
179369
+ "git-branch",
179370
+ "github",
179371
+ "slack",
179372
+ "mail",
179373
+ "link",
179374
+ "file-text",
179375
+ "folder",
179376
+ "database",
179377
+ "zap",
179378
+ "sparkles",
179379
+ "flag",
179380
+ "star",
179381
+ "tag",
179382
+ "alert-triangle",
179383
+ "info",
179384
+ "circle-check",
179385
+ "trending-up",
179386
+ "trending-down",
179387
+ "dollar-sign",
179388
+ "activity",
179389
+ "rocket"
179390
+ ]
179391
+ },
179392
+ status: {
179393
+ type: "string"
179394
+ },
179395
+ variant: {
179396
+ type: "string",
179397
+ enum: ["tag", "status", "count", "beta"]
179398
+ },
179399
+ hint: {
179400
+ type: "string"
178888
179401
  }
178889
179402
  },
178890
179403
  required: ["text"],
178891
179404
  additionalProperties: false
178892
179405
  }
178893
179406
  },
179407
+ Icon: {
179408
+ description: "One icon from the curated lucide set (`plus`, `refresh-cw`, `search`, `filter`, `download`, `upload`, `external-link`, `copy`, `check`, `x`, `trash-2`, `pencil`, `eye`, `calendar`, `clock`, `user`, `users`, `bot`, `git-pull-request`, `git-branch`, `github`, `slack`, `mail`, `link`, `file-text`, `folder`, `database`, `zap`, `sparkles`, `flag`, `star`, `tag`, `alert-triangle`, `info`, `circle-check`, `trending-up`, `trending-down`, `dollar-sign`, `activity`, `rocket`). The same names work on every `icon` prop (Button, Badge, Metric, Alert, Tabs entries, Chips options, EmptyState, Table columns, row actions and Drawer actions). Decorative unless `label` is set. `size` sm|md|lg, `tone` default|muted|success|warning|error|info.",
179409
+ props: {
179410
+ $schema: "http://json-schema.org/draft-07/schema#",
179411
+ type: "object",
179412
+ properties: {
179413
+ name: {
179414
+ type: "string",
179415
+ enum: [
179416
+ "plus",
179417
+ "refresh-cw",
179418
+ "search",
179419
+ "filter",
179420
+ "download",
179421
+ "upload",
179422
+ "external-link",
179423
+ "copy",
179424
+ "check",
179425
+ "x",
179426
+ "trash-2",
179427
+ "pencil",
179428
+ "eye",
179429
+ "calendar",
179430
+ "clock",
179431
+ "user",
179432
+ "users",
179433
+ "bot",
179434
+ "git-pull-request",
179435
+ "git-branch",
179436
+ "github",
179437
+ "slack",
179438
+ "mail",
179439
+ "link",
179440
+ "file-text",
179441
+ "folder",
179442
+ "database",
179443
+ "zap",
179444
+ "sparkles",
179445
+ "flag",
179446
+ "star",
179447
+ "tag",
179448
+ "alert-triangle",
179449
+ "info",
179450
+ "circle-check",
179451
+ "trending-up",
179452
+ "trending-down",
179453
+ "dollar-sign",
179454
+ "activity",
179455
+ "rocket"
179456
+ ]
179457
+ },
179458
+ size: {
179459
+ type: "string",
179460
+ enum: ["sm", "md", "lg"]
179461
+ },
179462
+ tone: {
179463
+ type: "string",
179464
+ enum: ["default", "muted", "success", "warning", "error", "info"]
179465
+ },
179466
+ label: {
179467
+ type: "string"
179468
+ }
179469
+ },
179470
+ required: ["name"],
179471
+ additionalProperties: false
179472
+ }
179473
+ },
179474
+ Progress: {
179475
+ description: 'Progress readout. `value` against `max` (default 100), usually bound to state. `variant: "bar"` (default) is a toned bar (`tone` neutral|success|active|error|info|pending|warning|paused) with an optional `label` above it; `"ring"` is the dashboard progress ring (done arc). `showValue` (default true) prints the percent (bar) or `value / max` (ring).',
179476
+ props: {
179477
+ $schema: "http://json-schema.org/draft-07/schema#",
179478
+ type: "object",
179479
+ properties: {
179480
+ value: {
179481
+ type: "number"
179482
+ },
179483
+ max: {
179484
+ type: "number",
179485
+ exclusiveMinimum: 0
179486
+ },
179487
+ tone: {
179488
+ type: "string",
179489
+ enum: [
179490
+ "neutral",
179491
+ "success",
179492
+ "active",
179493
+ "error",
179494
+ "info",
179495
+ "pending",
179496
+ "warning",
179497
+ "paused"
179498
+ ]
179499
+ },
179500
+ label: {
179501
+ type: "string"
179502
+ },
179503
+ variant: {
179504
+ type: "string",
179505
+ enum: ["bar", "ring"]
179506
+ },
179507
+ showValue: {
179508
+ type: "boolean"
179509
+ }
179510
+ },
179511
+ required: ["value"],
179512
+ additionalProperties: false
179513
+ }
179514
+ },
179515
+ EmptyState: {
179516
+ description: "Centered empty state: `icon` (curated set, default inbox), `title`, optional `body`. `actionLabel` adds a button that emits the element's `press` event — wire it with `on.press` like a Button.",
179517
+ props: {
179518
+ $schema: "http://json-schema.org/draft-07/schema#",
179519
+ type: "object",
179520
+ properties: {
179521
+ icon: {
179522
+ type: "string",
179523
+ enum: [
179524
+ "plus",
179525
+ "refresh-cw",
179526
+ "search",
179527
+ "filter",
179528
+ "download",
179529
+ "upload",
179530
+ "external-link",
179531
+ "copy",
179532
+ "check",
179533
+ "x",
179534
+ "trash-2",
179535
+ "pencil",
179536
+ "eye",
179537
+ "calendar",
179538
+ "clock",
179539
+ "user",
179540
+ "users",
179541
+ "bot",
179542
+ "git-pull-request",
179543
+ "git-branch",
179544
+ "github",
179545
+ "slack",
179546
+ "mail",
179547
+ "link",
179548
+ "file-text",
179549
+ "folder",
179550
+ "database",
179551
+ "zap",
179552
+ "sparkles",
179553
+ "flag",
179554
+ "star",
179555
+ "tag",
179556
+ "alert-triangle",
179557
+ "info",
179558
+ "circle-check",
179559
+ "trending-up",
179560
+ "trending-down",
179561
+ "dollar-sign",
179562
+ "activity",
179563
+ "rocket"
179564
+ ]
179565
+ },
179566
+ title: {
179567
+ type: "string"
179568
+ },
179569
+ body: {
179570
+ type: "string"
179571
+ },
179572
+ actionLabel: {
179573
+ type: "string"
179574
+ }
179575
+ },
179576
+ required: ["title"],
179577
+ additionalProperties: false
179578
+ }
179579
+ },
179580
+ CopyButton: {
179581
+ description: "Copies `value` to the clipboard; the icon swaps to a check on copy. `label` is the visible text; without it the button is icon-only.",
179582
+ props: {
179583
+ $schema: "http://json-schema.org/draft-07/schema#",
179584
+ type: "object",
179585
+ properties: {
179586
+ value: {
179587
+ anyOf: [
179588
+ {
179589
+ type: "string"
179590
+ },
179591
+ {
179592
+ type: "number"
179593
+ }
179594
+ ]
179595
+ },
179596
+ label: {
179597
+ type: "string"
179598
+ }
179599
+ },
179600
+ required: ["value"],
179601
+ additionalProperties: false
179602
+ }
179603
+ },
179604
+ Kbd: {
179605
+ description: 'Keycaps for a keyboard shortcut, one per entry in `keys` (e.g. `["⌘", "K"]`). Display only.',
179606
+ props: {
179607
+ $schema: "http://json-schema.org/draft-07/schema#",
179608
+ type: "object",
179609
+ properties: {
179610
+ keys: {
179611
+ minItems: 1,
179612
+ type: "array",
179613
+ items: {
179614
+ type: "string"
179615
+ }
179616
+ }
179617
+ },
179618
+ required: ["keys"],
179619
+ additionalProperties: false
179620
+ }
179621
+ },
179622
+ Skeleton: {
179623
+ description: "Loading placeholder. `shape`: `line` (text lines), `block` (one box, `height` in px, default 128), `rows` (table-like rows), `metric` (stat tiles), `card` (a card sketch). `count` repeats lines, rows or tiles. Pair with `visible` on a query's `loading` state.",
179624
+ props: {
179625
+ $schema: "http://json-schema.org/draft-07/schema#",
179626
+ type: "object",
179627
+ properties: {
179628
+ shape: {
179629
+ type: "string",
179630
+ enum: ["line", "block", "rows", "metric", "card"]
179631
+ },
179632
+ count: {
179633
+ type: "integer",
179634
+ minimum: 1,
179635
+ maximum: 20
179636
+ },
179637
+ height: {
179638
+ type: "integer",
179639
+ minimum: 8,
179640
+ maximum: 800
179641
+ }
179642
+ },
179643
+ required: ["shape"],
179644
+ additionalProperties: false
179645
+ }
179646
+ },
179647
+ Spinner: {
179648
+ description: 'Inline busy indicator with `role=status`. `variant` ring|ellipsis|bars (default: the dashboard spinner), `size` sm|md, `label` shown next to it (and its accessible name; defaults to an sr-only "Loading").',
179649
+ props: {
179650
+ $schema: "http://json-schema.org/draft-07/schema#",
179651
+ type: "object",
179652
+ properties: {
179653
+ variant: {
179654
+ type: "string",
179655
+ enum: ["ring", "ellipsis", "bars"]
179656
+ },
179657
+ size: {
179658
+ type: "string",
179659
+ enum: ["sm", "md"]
179660
+ },
179661
+ label: {
179662
+ type: "string"
179663
+ }
179664
+ },
179665
+ additionalProperties: false
179666
+ }
179667
+ },
179668
+ AvatarStack: {
179669
+ description: "Overlapping initials avatars for `users` (display names), up to `max` (default 4) then a `+N` count; hover lists every name.",
179670
+ props: {
179671
+ $schema: "http://json-schema.org/draft-07/schema#",
179672
+ type: "object",
179673
+ properties: {
179674
+ users: {
179675
+ type: "array",
179676
+ items: {
179677
+ type: "string"
179678
+ }
179679
+ },
179680
+ max: {
179681
+ type: "integer",
179682
+ minimum: 1,
179683
+ maximum: 20
179684
+ }
179685
+ },
179686
+ required: ["users"],
179687
+ additionalProperties: false
179688
+ }
179689
+ },
179690
+ Section: {
179691
+ description: "Titled section around its children: `title`, optional `description`. `collapsible` folds the body under a toggle header (`defaultOpen`, default true).",
179692
+ slots: ["default"],
179693
+ props: {
179694
+ $schema: "http://json-schema.org/draft-07/schema#",
179695
+ type: "object",
179696
+ properties: {
179697
+ title: {
179698
+ type: "string"
179699
+ },
179700
+ description: {
179701
+ type: "string"
179702
+ },
179703
+ collapsible: {
179704
+ type: "boolean"
179705
+ },
179706
+ defaultOpen: {
179707
+ type: "boolean"
179708
+ }
179709
+ },
179710
+ required: ["title"],
179711
+ additionalProperties: false
179712
+ }
179713
+ },
179714
+ Chips: {
179715
+ description: 'Toggle chips for quick filters. `options` are strings or `{ value, label?, icon? }`. Writes the selection to `/ui/<id>/value`: one string or `null` (pressing the selected chip clears it), or with `multiple` a string array (empty = nothing picked). Bind it into a Table with `"filters": { "<column>": { "$state": "/ui/<id>/value" } }` — an array filter matches rows whose cell is one of the values. `label` names the group for screen readers.',
179716
+ props: {
179717
+ $schema: "http://json-schema.org/draft-07/schema#",
179718
+ type: "object",
179719
+ properties: {
179720
+ id: {
179721
+ type: "string"
179722
+ },
179723
+ options: {
179724
+ minItems: 1,
179725
+ type: "array",
179726
+ items: {
179727
+ anyOf: [
179728
+ {
179729
+ type: "string"
179730
+ },
179731
+ {
179732
+ type: "object",
179733
+ properties: {
179734
+ value: {
179735
+ type: "string"
179736
+ },
179737
+ label: {
179738
+ type: "string"
179739
+ },
179740
+ icon: {
179741
+ type: "string",
179742
+ enum: [
179743
+ "plus",
179744
+ "refresh-cw",
179745
+ "search",
179746
+ "filter",
179747
+ "download",
179748
+ "upload",
179749
+ "external-link",
179750
+ "copy",
179751
+ "check",
179752
+ "x",
179753
+ "trash-2",
179754
+ "pencil",
179755
+ "eye",
179756
+ "calendar",
179757
+ "clock",
179758
+ "user",
179759
+ "users",
179760
+ "bot",
179761
+ "git-pull-request",
179762
+ "git-branch",
179763
+ "github",
179764
+ "slack",
179765
+ "mail",
179766
+ "link",
179767
+ "file-text",
179768
+ "folder",
179769
+ "database",
179770
+ "zap",
179771
+ "sparkles",
179772
+ "flag",
179773
+ "star",
179774
+ "tag",
179775
+ "alert-triangle",
179776
+ "info",
179777
+ "circle-check",
179778
+ "trending-up",
179779
+ "trending-down",
179780
+ "dollar-sign",
179781
+ "activity",
179782
+ "rocket"
179783
+ ]
179784
+ }
179785
+ },
179786
+ required: ["value"],
179787
+ additionalProperties: false
179788
+ }
179789
+ ]
179790
+ }
179791
+ },
179792
+ multiple: {
179793
+ type: "boolean"
179794
+ },
179795
+ label: {
179796
+ type: "string"
179797
+ }
179798
+ },
179799
+ required: ["id", "options"],
179800
+ additionalProperties: false
179801
+ }
179802
+ },
178894
179803
  Table: {
178895
- description: 'Data table. Bind `data`/`loading`/`error` to a named query (`/queries/<name>/...`). `rowActions` chains receive `{ "$row": "<col>" }` (or `{ "$row": "" }` for the whole row) and `{ "$rowIndex": true }`. Destructive row actions always confirm via a dialog; override the copy with `confirm: { title, description, confirmLabel }`. `search` (case-insensitive substring across every listed column) and `filters` (per-column equality, `null`/`""` disables one) narrow the polled rows client-side — bind them to a `SearchInput` / `Select` via `/ui/<id>/value`, or pin a constant (e.g. `"filters": { "pinned": true }`). Columns take `pinned: "left"|"right"` to survive horizontal scroll; `pagination` pages large row sets (auto past 200 rows); `density: "compact"` tightens row height.',
179804
+ description: 'Data table. Bind `data`/`loading`/`error` to a named query (`/queries/<name>/...`). `rowActions` chains receive `{ "$row": "<col>" }` (or `{ "$row": "" }` for the whole row) and `{ "$rowIndex": true }`. Destructive row actions always confirm via a dialog; override the copy with `confirm: { title, description, confirmLabel }`. `search` (case-insensitive substring across every listed column) and `filters` (per-column equality, `null`/`""` disables one; an array means "one of", which is what a multiple `Chips` writes, and an empty array disables it) narrow the polled rows client-side — bind them to a `SearchInput` / `Select` via `/ui/<id>/value`, or pin a constant (e.g. `"filters": { "pinned": true }`). Columns take `pinned: "left"|"right"` to survive horizontal scroll; `pagination` pages large row sets (auto past 200 rows); `density: "compact"` tightens row height. Column kinds: `status` (lifecycle values like pending/in_progress/completed/failed get the dashboard status icon, anything else a `tones` pill), `user` / `agent` (avatar + name), `relative` (smart time with the exact time on hover), `duration` (ms → 1m 23s), `progress` (bar, `max` default 100), `copy` (value + copy button), `switch` (runs the column\'s `onChange` chain with `$row` set to the new value; read-only without it), `link` (http(s) URL, opens in a new tab). Columns also take `align`, `truncate: "middle"` (ids, paths), a header `icon` and `tooltip` (a row field shown on hover). `onRowClick` runs a chain with `$row` when a row is clicked — pair it with `app.navigate` + a Drawer and bind `selectedId` to the drawer param to highlight the open row. `rowId` names the id field (default `id`). Below 768px the table renders as a phone list (`mobile: "list"`, fields picked by `mobileFields: { title, subtitle?, meta?, status? }`); `mobile: "scroll"` keeps the grid. `emptyState: { icon?, title, body? }` replaces the empty message. Row actions take `icon` and `placement: "menu"` (collected into a More menu).',
178896
179805
  props: {
178897
179806
  $schema: "http://json-schema.org/draft-07/schema#",
178898
179807
  type: "object",
@@ -178920,7 +179829,24 @@ var catalog_generated_default = {
178920
179829
  },
178921
179830
  kind: {
178922
179831
  type: "string",
178923
- enum: ["text", "string", "number", "boolean", "date", "badge", "enum"]
179832
+ enum: [
179833
+ "text",
179834
+ "string",
179835
+ "number",
179836
+ "boolean",
179837
+ "date",
179838
+ "badge",
179839
+ "enum",
179840
+ "status",
179841
+ "user",
179842
+ "agent",
179843
+ "relative",
179844
+ "duration",
179845
+ "progress",
179846
+ "copy",
179847
+ "switch",
179848
+ "link"
179849
+ ]
178924
179850
  },
178925
179851
  tones: {
178926
179852
  type: "object",
@@ -178947,6 +179873,86 @@ var catalog_generated_default = {
178947
179873
  pinned: {
178948
179874
  type: "string",
178949
179875
  enum: ["left", "right"]
179876
+ },
179877
+ align: {
179878
+ type: "string",
179879
+ enum: ["start", "end"]
179880
+ },
179881
+ truncate: {
179882
+ type: "string",
179883
+ enum: ["end", "middle"]
179884
+ },
179885
+ icon: {
179886
+ type: "string",
179887
+ enum: [
179888
+ "plus",
179889
+ "refresh-cw",
179890
+ "search",
179891
+ "filter",
179892
+ "download",
179893
+ "upload",
179894
+ "external-link",
179895
+ "copy",
179896
+ "check",
179897
+ "x",
179898
+ "trash-2",
179899
+ "pencil",
179900
+ "eye",
179901
+ "calendar",
179902
+ "clock",
179903
+ "user",
179904
+ "users",
179905
+ "bot",
179906
+ "git-pull-request",
179907
+ "git-branch",
179908
+ "github",
179909
+ "slack",
179910
+ "mail",
179911
+ "link",
179912
+ "file-text",
179913
+ "folder",
179914
+ "database",
179915
+ "zap",
179916
+ "sparkles",
179917
+ "flag",
179918
+ "star",
179919
+ "tag",
179920
+ "alert-triangle",
179921
+ "info",
179922
+ "circle-check",
179923
+ "trending-up",
179924
+ "trending-down",
179925
+ "dollar-sign",
179926
+ "activity",
179927
+ "rocket"
179928
+ ]
179929
+ },
179930
+ tooltip: {
179931
+ type: "string"
179932
+ },
179933
+ max: {
179934
+ type: "number",
179935
+ exclusiveMinimum: 0
179936
+ },
179937
+ onChange: {
179938
+ type: "array",
179939
+ items: {
179940
+ type: "object",
179941
+ properties: {
179942
+ action: {
179943
+ type: "string"
179944
+ },
179945
+ params: {
179946
+ type: "object",
179947
+ propertyNames: {
179948
+ type: "string"
179949
+ },
179950
+ additionalProperties: {}
179951
+ }
179952
+ },
179953
+ required: ["action"],
179954
+ additionalProperties: false
179955
+ }
178950
179956
  }
178951
179957
  },
178952
179958
  required: ["key"],
@@ -179016,6 +180022,55 @@ var catalog_generated_default = {
179016
180022
  required: ["action"],
179017
180023
  additionalProperties: false
179018
180024
  }
180025
+ },
180026
+ icon: {
180027
+ type: "string",
180028
+ enum: [
180029
+ "plus",
180030
+ "refresh-cw",
180031
+ "search",
180032
+ "filter",
180033
+ "download",
180034
+ "upload",
180035
+ "external-link",
180036
+ "copy",
180037
+ "check",
180038
+ "x",
180039
+ "trash-2",
180040
+ "pencil",
180041
+ "eye",
180042
+ "calendar",
180043
+ "clock",
180044
+ "user",
180045
+ "users",
180046
+ "bot",
180047
+ "git-pull-request",
180048
+ "git-branch",
180049
+ "github",
180050
+ "slack",
180051
+ "mail",
180052
+ "link",
180053
+ "file-text",
180054
+ "folder",
180055
+ "database",
180056
+ "zap",
180057
+ "sparkles",
180058
+ "flag",
180059
+ "star",
180060
+ "tag",
180061
+ "alert-triangle",
180062
+ "info",
180063
+ "circle-check",
180064
+ "trending-up",
180065
+ "trending-down",
180066
+ "dollar-sign",
180067
+ "activity",
180068
+ "rocket"
180069
+ ]
180070
+ },
180071
+ placement: {
180072
+ type: "string",
180073
+ enum: ["inline", "menu"]
179019
180074
  }
179020
180075
  },
179021
180076
  required: ["label", "actions"],
@@ -179058,6 +180113,22 @@ var catalog_generated_default = {
179058
180113
  },
179059
180114
  {
179060
180115
  type: "boolean"
180116
+ },
180117
+ {
180118
+ type: "array",
180119
+ items: {
180120
+ anyOf: [
180121
+ {
180122
+ type: "string"
180123
+ },
180124
+ {
180125
+ type: "number"
180126
+ },
180127
+ {
180128
+ type: "boolean"
180129
+ }
180130
+ ]
180131
+ }
179061
180132
  }
179062
180133
  ]
179063
180134
  },
@@ -179073,6 +180144,137 @@ var catalog_generated_default = {
179073
180144
  density: {
179074
180145
  type: "string",
179075
180146
  enum: ["comfortable", "compact"]
180147
+ },
180148
+ rowId: {
180149
+ type: "string"
180150
+ },
180151
+ onRowClick: {
180152
+ type: "array",
180153
+ items: {
180154
+ type: "object",
180155
+ properties: {
180156
+ action: {
180157
+ type: "string"
180158
+ },
180159
+ params: {
180160
+ type: "object",
180161
+ propertyNames: {
180162
+ type: "string"
180163
+ },
180164
+ additionalProperties: {}
180165
+ }
180166
+ },
180167
+ required: ["action"],
180168
+ additionalProperties: false
180169
+ }
180170
+ },
180171
+ selectedId: {
180172
+ anyOf: [
180173
+ {
180174
+ anyOf: [
180175
+ {
180176
+ type: "string"
180177
+ },
180178
+ {
180179
+ type: "number"
180180
+ }
180181
+ ]
180182
+ },
180183
+ {
180184
+ type: "null"
180185
+ }
180186
+ ]
180187
+ },
180188
+ mobile: {
180189
+ type: "string",
180190
+ enum: ["list", "scroll"]
180191
+ },
180192
+ mobileFields: {
180193
+ type: "object",
180194
+ properties: {
180195
+ title: {
180196
+ type: "string"
180197
+ },
180198
+ subtitle: {
180199
+ type: "string"
180200
+ },
180201
+ meta: {
180202
+ anyOf: [
180203
+ {
180204
+ type: "string"
180205
+ },
180206
+ {
180207
+ type: "array",
180208
+ items: {
180209
+ type: "string"
180210
+ }
180211
+ }
180212
+ ]
180213
+ },
180214
+ status: {
180215
+ type: "string"
180216
+ }
180217
+ },
180218
+ required: ["title"],
180219
+ additionalProperties: false
180220
+ },
180221
+ emptyState: {
180222
+ type: "object",
180223
+ properties: {
180224
+ icon: {
180225
+ type: "string",
180226
+ enum: [
180227
+ "plus",
180228
+ "refresh-cw",
180229
+ "search",
180230
+ "filter",
180231
+ "download",
180232
+ "upload",
180233
+ "external-link",
180234
+ "copy",
180235
+ "check",
180236
+ "x",
180237
+ "trash-2",
180238
+ "pencil",
180239
+ "eye",
180240
+ "calendar",
180241
+ "clock",
180242
+ "user",
180243
+ "users",
180244
+ "bot",
180245
+ "git-pull-request",
180246
+ "git-branch",
180247
+ "github",
180248
+ "slack",
180249
+ "mail",
180250
+ "link",
180251
+ "file-text",
180252
+ "folder",
180253
+ "database",
180254
+ "zap",
180255
+ "sparkles",
180256
+ "flag",
180257
+ "star",
180258
+ "tag",
180259
+ "alert-triangle",
180260
+ "info",
180261
+ "circle-check",
180262
+ "trending-up",
180263
+ "trending-down",
180264
+ "dollar-sign",
180265
+ "activity",
180266
+ "rocket"
180267
+ ]
180268
+ },
180269
+ title: {
180270
+ type: "string"
180271
+ },
180272
+ body: {
180273
+ type: "string"
180274
+ }
180275
+ },
180276
+ required: ["title"],
180277
+ additionalProperties: false
179076
180278
  }
179077
180279
  },
179078
180280
  required: ["columns"],
@@ -179153,7 +180355,7 @@ var catalog_generated_default = {
179153
180355
  }
179154
180356
  },
179155
180357
  Drawer: {
179156
- description: 'Route-driven slide-in side panel (sheet). Open exactly when the route param named by `param` is set — open it with `app.navigate` (e.g. a rowAction setting `{ "panel": { "$row": "id" } }`), and the URL stays shareable: a deep link with the param renders the drawer open, and closing it clears the param. Children mount only while open (a Table inside does NOT stay warm when closed — unlike Tabs). `side` right (default) or left; `size` sm|md|lg|xl width.',
180358
+ description: 'Route-driven slide-in side panel (sheet). Open exactly when the route param named by `param` is set — open it with `app.navigate` (e.g. a rowAction setting `{ "panel": { "$row": "id" } }`), and the URL stays shareable: a deep link with the param renders the drawer open, and closing it clears the param. Children mount only while open (a Table inside does NOT stay warm when closed — unlike Tabs). `side` right (default) or left; `size` sm|md|lg|xl width. `actions: [{ label, icon?, variant?, confirm?, actions }]` render in a sticky footer with the Table rowActions confirm rules (destructive variants confirm, an `app.mutate` delete always confirms); chains have no `$row`, so read the open record id with `{ "$state": "/route/params/<param>" }`.',
179157
180359
  slots: ["default"],
179158
180360
  props: {
179159
180361
  $schema: "http://json-schema.org/draft-07/schema#",
@@ -179175,6 +180377,120 @@ var catalog_generated_default = {
179175
180377
  size: {
179176
180378
  type: "string",
179177
180379
  enum: ["sm", "md", "lg", "xl"]
180380
+ },
180381
+ actions: {
180382
+ type: "array",
180383
+ items: {
180384
+ type: "object",
180385
+ properties: {
180386
+ label: {
180387
+ type: "string"
180388
+ },
180389
+ variant: {
180390
+ type: "string",
180391
+ enum: [
180392
+ "default",
180393
+ "secondary",
180394
+ "outline",
180395
+ "ghost",
180396
+ "destructive",
180397
+ "destructive-outline"
180398
+ ]
180399
+ },
180400
+ confirm: {
180401
+ anyOf: [
180402
+ {
180403
+ type: "boolean"
180404
+ },
180405
+ {
180406
+ type: "object",
180407
+ properties: {
180408
+ title: {
180409
+ type: "string"
180410
+ },
180411
+ description: {
180412
+ type: "string"
180413
+ },
180414
+ confirmLabel: {
180415
+ type: "string"
180416
+ }
180417
+ },
180418
+ additionalProperties: false
180419
+ },
180420
+ {
180421
+ type: "string"
180422
+ }
180423
+ ]
180424
+ },
180425
+ actions: {
180426
+ type: "array",
180427
+ items: {
180428
+ type: "object",
180429
+ properties: {
180430
+ action: {
180431
+ type: "string"
180432
+ },
180433
+ params: {
180434
+ type: "object",
180435
+ propertyNames: {
180436
+ type: "string"
180437
+ },
180438
+ additionalProperties: {}
180439
+ }
180440
+ },
180441
+ required: ["action"],
180442
+ additionalProperties: false
180443
+ }
180444
+ },
180445
+ icon: {
180446
+ type: "string",
180447
+ enum: [
180448
+ "plus",
180449
+ "refresh-cw",
180450
+ "search",
180451
+ "filter",
180452
+ "download",
180453
+ "upload",
180454
+ "external-link",
180455
+ "copy",
180456
+ "check",
180457
+ "x",
180458
+ "trash-2",
180459
+ "pencil",
180460
+ "eye",
180461
+ "calendar",
180462
+ "clock",
180463
+ "user",
180464
+ "users",
180465
+ "bot",
180466
+ "git-pull-request",
180467
+ "git-branch",
180468
+ "github",
180469
+ "slack",
180470
+ "mail",
180471
+ "link",
180472
+ "file-text",
180473
+ "folder",
180474
+ "database",
180475
+ "zap",
180476
+ "sparkles",
180477
+ "flag",
180478
+ "star",
180479
+ "tag",
180480
+ "alert-triangle",
180481
+ "info",
180482
+ "circle-check",
180483
+ "trending-up",
180484
+ "trending-down",
180485
+ "dollar-sign",
180486
+ "activity",
180487
+ "rocket"
180488
+ ]
180489
+ }
180490
+ },
180491
+ required: ["label", "actions"],
180492
+ additionalProperties: false
180493
+ }
179178
180494
  }
179179
180495
  },
179180
180496
  required: ["param"],
@@ -179182,7 +180498,7 @@ var catalog_generated_default = {
179182
180498
  }
179183
180499
  },
179184
180500
  DetailList: {
179185
- description: 'Read-only label/value detail view for ONE record. Bind `data` to a single row — usually `{ "$state": "/queries/<name>/data/0" }` with a `$param`-filtered query. `fields` pick and format properties with the same kinds as Table columns (badge tones, relative dates) plus `code` for raw/JSON values. Bind `loading` to the query (`/queries/<name>/loading`) for skeleton fields while it loads; `emptyMessage` shows when the record is genuinely missing.',
180501
+ description: 'Read-only label/value detail view for ONE record. Bind `data` to a single row — usually `{ "$state": "/queries/<name>/data/0" }` with a `$param`-filtered query. `fields` pick and format properties with the same kinds as Table columns (badge tones, relative dates) plus `status` (lifecycle chip), `user` (avatar + name), `relative` (smart time, exact on hover), `copy` (value + copy button), `code` (monospace block) and `json` (collapsible JSON tree). Bind `loading` to the query (`/queries/<name>/loading`) for skeleton fields while it loads; `emptyMessage` shows when the record is genuinely missing.',
179186
180502
  props: {
179187
180503
  $schema: "http://json-schema.org/draft-07/schema#",
179188
180504
  type: "object",
@@ -179215,7 +180531,21 @@ var catalog_generated_default = {
179215
180531
  },
179216
180532
  kind: {
179217
180533
  type: "string",
179218
- enum: ["text", "string", "number", "boolean", "date", "badge", "enum", "code"]
180534
+ enum: [
180535
+ "text",
180536
+ "string",
180537
+ "number",
180538
+ "boolean",
180539
+ "date",
180540
+ "badge",
180541
+ "enum",
180542
+ "code",
180543
+ "status",
180544
+ "user",
180545
+ "relative",
180546
+ "copy",
180547
+ "json"
180548
+ ]
179219
180549
  },
179220
180550
  tones: {
179221
180551
  type: "object",
@@ -179265,7 +180595,7 @@ var catalog_generated_default = {
179265
180595
  }
179266
180596
  },
179267
180597
  Kanban: {
179268
- description: 'Kanban board: one card per row, grouped into `columns` by the row\'s `columnField`. Bind `data`/`loading` to a named query. `titleField` is the card title; `cardFields` add label/value lines with Table column kinds (badge tones, relative dates). Dragging a card to another column runs `onMove` with `$row` = the moved row, `columnField` already set to the new column — typically `[{ "action": "app.mutate", "params": { "model": "<m>", "op": "update", "rowId": { "$row": "id" }, "values": { "<columnField>": { "$row": "<columnField>" } } } }]`. Without `onMove` the board is read-only. `onCardClick` runs with `$row` (e.g. an `app.navigate` that opens a Drawer).',
180598
+ description: 'Kanban board: one card per row, grouped into `columns` by the row\'s `columnField`. Bind `data`/`loading` to a named query. `titleField` is the card title; `cardFields` add label/value lines with the DetailList field kinds (badge tones, status, user, relative, copy, ...). Dragging a card to another column runs `onMove` with `$row` = the moved row, `columnField` already set to the new column — typically `[{ "action": "app.mutate", "params": { "model": "<m>", "op": "update", "rowId": { "$row": "id" }, "values": { "<columnField>": { "$row": "<columnField>" } } } }]`. Without `onMove` the board is read-only. `onCardClick` runs with `$row` (e.g. an `app.navigate` that opens a Drawer).',
179269
180599
  props: {
179270
180600
  $schema: "http://json-schema.org/draft-07/schema#",
179271
180601
  type: "object",
@@ -179326,7 +180656,21 @@ var catalog_generated_default = {
179326
180656
  },
179327
180657
  kind: {
179328
180658
  type: "string",
179329
- enum: ["text", "string", "number", "boolean", "date", "badge", "enum", "code"]
180659
+ enum: [
180660
+ "text",
180661
+ "string",
180662
+ "number",
180663
+ "boolean",
180664
+ "date",
180665
+ "badge",
180666
+ "enum",
180667
+ "code",
180668
+ "status",
180669
+ "user",
180670
+ "relative",
180671
+ "copy",
180672
+ "json"
180673
+ ]
179330
180674
  },
179331
180675
  tones: {
179332
180676
  type: "object",
@@ -179610,6 +180954,57 @@ var catalog_generated_default = {
179610
180954
  additionalProperties: false
179611
180955
  }
179612
180956
  },
180957
+ "ui.toast": {
180958
+ description: 'Show a toast: `message`, optional `description`, `tone` success|error|info|warning (default info). `undo: { label?, actions }` adds an Undo button (label defaults to "Undo") that runs `actions` as a chain — e.g. an `app.mutate` that restores the row a delete just removed.',
180959
+ params: {
180960
+ $schema: "http://json-schema.org/draft-07/schema#",
180961
+ type: "object",
180962
+ properties: {
180963
+ message: {
180964
+ type: "string"
180965
+ },
180966
+ description: {
180967
+ type: "string"
180968
+ },
180969
+ tone: {
180970
+ type: "string",
180971
+ enum: ["success", "error", "info", "warning"]
180972
+ },
180973
+ undo: {
180974
+ type: "object",
180975
+ properties: {
180976
+ label: {
180977
+ type: "string"
180978
+ },
180979
+ actions: {
180980
+ type: "array",
180981
+ items: {
180982
+ type: "object",
180983
+ properties: {
180984
+ action: {
180985
+ type: "string"
180986
+ },
180987
+ params: {
180988
+ type: "object",
180989
+ propertyNames: {
180990
+ type: "string"
180991
+ },
180992
+ additionalProperties: {}
180993
+ }
180994
+ },
180995
+ required: ["action"],
180996
+ additionalProperties: false
180997
+ }
180998
+ }
180999
+ },
181000
+ required: ["actions"],
181001
+ additionalProperties: false
181002
+ }
181003
+ },
181004
+ required: ["message"],
181005
+ additionalProperties: false
181006
+ }
181007
+ },
179613
181008
  "app.mutate": {
179614
181009
  description: "Create / update / delete a swarm-app row, then refetch every named query on the same model.",
179615
181010
  params: {
@@ -179721,12 +181116,37 @@ var ELEMENT_KEYS = new Set([
179721
181116
  "repeat",
179722
181117
  "watch"
179723
181118
  ]);
179724
- var UI_STATE_COMPONENTS = new Set(["SearchInput", "Select", "Tabs"]);
181119
+ var UI_STATE_COMPONENTS = new Set(["SearchInput", "Select", "Tabs", "Chips"]);
179725
181120
  var PROP_ACTION_CHAINS = {
181121
+ Table: ["onRowClick"],
179726
181122
  Form: ["onSubmit"],
179727
181123
  Kanban: ["onMove", "onCardClick"],
179728
181124
  Calendar: ["onSelect"]
179729
181125
  };
181126
+ var ITEM_ACTION_CHAINS = {
181127
+ Table: [
181128
+ ["rowActions", "actions"],
181129
+ ["columns", "onChange"]
181130
+ ],
181131
+ Drawer: [["actions", "actions"]]
181132
+ };
181133
+ function itemActionChains(type, props, propsPath) {
181134
+ const chains = [];
181135
+ for (const [arrayProp, chainKey] of ITEM_ACTION_CHAINS[String(type)] ?? []) {
181136
+ const items = props[arrayProp];
181137
+ if (!Array.isArray(items))
181138
+ continue;
181139
+ for (const [index, item] of items.entries()) {
181140
+ if (!isPlainObject(item) || !Object.hasOwn(item, chainKey))
181141
+ continue;
181142
+ chains.push({
181143
+ path: `${propsPath}.${arrayProp}.${index}.${chainKey}`,
181144
+ chain: item[chainKey]
181145
+ });
181146
+ }
181147
+ }
181148
+ return chains;
181149
+ }
179730
181150
  var DATA_FIELD_PROPS = {
179731
181151
  Kanban: ["columnField", "titleField", "idField"],
179732
181152
  Calendar: ["startField", "endField", "titleField", "idField"],
@@ -179965,9 +181385,9 @@ function actionParams(step, path2, definition, catalog, validateNavigation = fal
179965
181385
  }
179966
181386
  if (op === "update" || op === "delete") {
179967
181387
  const rowId = params.rowId;
179968
- const validRowId = typeof rowId === "string" || isPlainObject(rowId) && typeof rowId.$row === "string" && Object.keys(rowId).length === 1;
181388
+ const validRowId = typeof rowId === "string" || isStateBinding(rowId) || isPlainObject(rowId) && typeof rowId.$row === "string" && Object.keys(rowId).length === 1;
179969
181389
  if (!validRowId) {
179970
- result.issues.push(issue(appendPath(paramsPath, "rowId"), "is required for update and delete and must be a string or $row binding"));
181390
+ result.issues.push(issue(appendPath(paramsPath, "rowId"), "is required for update and delete and must be a string, $row, or $state binding"));
179971
181391
  }
179972
181392
  }
179973
181393
  if (isPlainObject(params.values) && !isActionSentinel(params.values) && !isStateBinding(params.values)) {
@@ -179986,6 +181406,13 @@ function actionParams(step, path2, definition, catalog, validateNavigation = fal
179986
181406
  if (typeof params.name !== "string" || !Object.hasOwn(definition.actions ?? {}, params.name)) {
179987
181407
  result.issues.push(issue(appendPath(paramsPath, "name"), `unknown app action "${String(params.name)}"`));
179988
181408
  }
181409
+ } else if (step.action === "ui.toast") {
181410
+ const undo = toastUndoChain(step);
181411
+ if (Array.isArray(undo)) {
181412
+ const undoResult = validateActionChain(undo, appendPath(appendPath(paramsPath, "undo"), "actions"), definition, catalog);
181413
+ result.issues.push(...undoResult.issues);
181414
+ result.stateRefs.push(...undoResult.stateRefs);
181415
+ }
179989
181416
  }
179990
181417
  return result;
179991
181418
  }
@@ -180170,10 +181597,21 @@ function visitActionChain(chain, path2, visit, allowSingle) {
180170
181597
  if (!Array.isArray(normalized))
180171
181598
  return;
180172
181599
  for (const [index, step] of normalized.entries()) {
180173
- if (isPlainObject(step))
180174
- visit(step, appendPath(path2, index));
181600
+ if (!isPlainObject(step))
181601
+ continue;
181602
+ const stepPath = appendPath(path2, index);
181603
+ visit(step, stepPath);
181604
+ const undo = toastUndoChain(step);
181605
+ if (undo !== undefined)
181606
+ visitActionChain(undo, `${stepPath}.params.undo.actions`, visit, false);
180175
181607
  }
180176
181608
  }
181609
+ function toastUndoChain(step) {
181610
+ if (step.action !== "ui.toast" || !isPlainObject(step.params))
181611
+ return;
181612
+ const undo = step.params.undo;
181613
+ return isPlainObject(undo) && Object.hasOwn(undo, "actions") ? undo.actions : undefined;
181614
+ }
180177
181615
  function visitPageActionSteps(page, pagePath, visit) {
180178
181616
  if (!isPlainObject(page.elements))
180179
181617
  return;
@@ -180191,12 +181629,8 @@ function visitPageActionSteps(page, pagePath, visit) {
180191
181629
  }
180192
181630
  if (!isPlainObject(rawElement.props))
180193
181631
  continue;
180194
- if (rawElement.type === "Table" && Array.isArray(rawElement.props.rowActions)) {
180195
- for (const [index, rowAction] of rawElement.props.rowActions.entries()) {
180196
- if (!isPlainObject(rowAction))
180197
- continue;
180198
- visitActionChain(rowAction.actions, `${elementPath}.props.rowActions.${index}.actions`, visit, false);
180199
- }
181632
+ for (const { path: path2, chain } of itemActionChains(rawElement.type, rawElement.props, `${elementPath}.props`)) {
181633
+ visitActionChain(chain, path2, visit, false);
180200
181634
  }
180201
181635
  for (const prop of PROP_ACTION_CHAINS[String(rawElement.type)] ?? []) {
180202
181636
  visitActionChain(rawElement.props[prop], `${elementPath}.props.${prop}`, visit, false);
@@ -180526,7 +181960,8 @@ function validatePage(definition, catalog, target) {
180526
181960
  }
180527
181961
  if (component) {
180528
181962
  const propsPath = appendPath(elementPath, "props");
180529
- const actionChainPath = (path2) => (PROP_ACTION_CHAINS[String(type)] ?? []).some((prop) => path2 === `${propsPath}.${prop}`) || type === "Table" && /^.+\.rowActions\.\d+\.actions$/.test(path2);
181963
+ const itemChainPaths = new Set(isPlainObject(rawElement.props) ? itemActionChains(type, rawElement.props, propsPath).map(({ path: path2 }) => path2) : []);
181964
+ const actionChainPath = (path2) => (PROP_ACTION_CHAINS[String(type)] ?? []).some((prop) => path2 === `${propsPath}.${prop}`) || itemChainPaths.has(path2);
180530
181965
  const propsResult = validateSchema(Object.hasOwn(rawElement, "props") ? rawElement.props : {}, component.props, propsPath, false, actionChainPath);
180531
181966
  issues.push(...propsResult.issues);
180532
181967
  stateRefs.push(...propsResult.stateRefs);
@@ -180563,6 +181998,9 @@ function validatePage(definition, catalog, target) {
180563
181998
  }
180564
181999
  }
180565
182000
  collectRowFieldIssues(rawElement.props.rowActions, `${elementPath}.props.rowActions`, queryModel.modelName, queryModel.model, issues);
182001
+ for (const prop of ["onRowClick", "columns"]) {
182002
+ collectRowFieldIssues(rawElement.props[prop], `${elementPath}.props.${prop}`, queryModel.modelName, queryModel.model, issues);
182003
+ }
180566
182004
  }
180567
182005
  } else if (type === "DetailList") {
180568
182006
  const queryModel = queryModelFromDataBinding(definition, rawElement.props.data);
@@ -180659,16 +182097,12 @@ function validatePage(definition, catalog, target) {
180659
182097
  issues.push(...visibleConditionIssues(rawElement[key], bindingPath));
180660
182098
  }
180661
182099
  }
180662
- if (type === "Table" && isPlainObject(rawElement.props) && Array.isArray(rawElement.props.rowActions)) {
180663
- for (const [rowActionIndex, rowAction] of rawElement.props.rowActions.entries()) {
180664
- if (!isPlainObject(rowAction) || !Object.hasOwn(rowAction, "actions"))
180665
- continue;
180666
- const chainResult = validateActionChain(rowAction.actions, `${elementPath}.props.rowActions.${rowActionIndex}.actions`, definition, catalog);
182100
+ if (isPlainObject(rawElement.props)) {
182101
+ for (const { path: path2, chain } of itemActionChains(type, rawElement.props, `${elementPath}.props`)) {
182102
+ const chainResult = validateActionChain(chain, path2, definition, catalog);
180667
182103
  issues.push(...chainResult.issues);
180668
182104
  stateRefs.push(...chainResult.stateRefs);
180669
182105
  }
180670
- }
180671
- if (isPlainObject(rawElement.props)) {
180672
182106
  for (const prop of PROP_ACTION_CHAINS[String(type)] ?? []) {
180673
182107
  if (!Object.hasOwn(rawElement.props, prop))
180674
182108
  continue;
@@ -182107,10 +183541,10 @@ export interface SwarmSdk {
182107
183541
  // --- slack ---
182108
183542
  slack_read(args?: { inboxMessageId?: string; taskId?: string; channelId?: string; threadTs?: string; limit?: number; includeFiles?: boolean }): Promise<unknown>;
182109
183543
  slack_listChannels(args?: { types?: Array<"public" | "private" | "dm" | "mpim">; limit?: number }): Promise<unknown>;
183544
+ // --- chat sdk ---
183545
+ chat_readThread(args: { threadId: string; limit?: number }): Promise<unknown>;
182110
183546
  // --- messaging ---
182111
183547
  message_read(args?: { channel?: string; limit?: number; since?: string; unreadOnly?: boolean; mentionsOnly?: boolean; markAsRead?: boolean }): Promise<unknown>;
182112
- // --- services ---
182113
- service_list(args?: { agentId?: string; name?: string; status?: "starting" | "healthy" | "unhealthy" | "stopped"; includeOwn?: boolean }): Promise<unknown>;
182114
183548
  // --- context / profiles ---
182115
183549
  context_history(args?: { agentId?: string; field?: "soulMd" | "identityMd" | "toolsMd" | "claudeMd" | "setupScript"; limit?: number }): Promise<unknown>;
182116
183550
  context_diff(args: { versionId: string; compareToVersionId?: string }): Promise<unknown>;
@@ -182153,7 +183587,7 @@ export interface SwarmSdk {
182153
183587
  task_action(args: Record<string, unknown>): Promise<unknown>;
182154
183588
 
182155
183589
  // --- write: config ---
182156
- config_set(args: { key: string; value: unknown; scope?: "global" | "agent" | "repo"; scopeId?: string; isSecret?: boolean }): Promise<unknown>;
183590
+ config_set(args: { key: string; value: unknown; scope?: "global" | "agent" | "repo"; scopeId?: string; isSecret?: boolean; exportToEnv?: boolean }): Promise<unknown>;
182157
183591
  config_delete(args: { id: string }): Promise<unknown>;
182158
183592
 
182159
183593
  // --- write: model catalog ---
@@ -182183,17 +183617,19 @@ export interface SwarmSdk {
182183
183617
  slack_delete(args: { channelId: string; messageTs: string }): Promise<unknown>;
182184
183618
  slack_update(args: { channelId: string; messageTs: string; message: string }): Promise<unknown>;
182185
183619
 
183620
+ // --- write: chat sdk ---
183621
+ chat_reply(args: { text: string }): Promise<unknown>;
183622
+ chat_post(args: { adapter: "telegram" | "slack" | "discord" | "teams"; threadId?: string; channelId?: string; text: string }): Promise<unknown>;
183623
+ chat_openDm(args: { adapter: "telegram" | "slack" | "discord" | "teams"; userId: string }): Promise<unknown>;
183624
+ chat_registerChannel(args: { adapter: "telegram" | "slack" | "discord" | "teams"; channelId: string; agentId?: string; workflowId?: string; name?: string }): Promise<unknown>;
183625
+ chat_unregisterChannel(args: { adapter: "telegram" | "slack" | "discord" | "teams"; channelId: string }): Promise<unknown>;
183626
+
182186
183627
  // --- write: messaging (internal) ---
182187
183628
  message_post(args: { channel?: string; content: string; to?: string }): Promise<unknown>;
182188
183629
 
182189
183630
  // --- write: profiles ---
182190
183631
  profile_update(args: Record<string, unknown>): Promise<unknown>;
182191
183632
 
182192
- // --- write: services ---
182193
- service_register(args: Record<string, unknown>): Promise<unknown>;
182194
- service_unregister(args: { name: string }): Promise<unknown>;
182195
- service_updateStatus(args: { name: string; status: "starting" | "healthy" | "unhealthy" | "stopped" }): Promise<unknown>;
182196
-
182197
183633
  // --- write: schedules ---
182198
183634
  schedule_create(args: Record<string, unknown>): Promise<unknown>;
182199
183635
  schedule_update(args: Record<string, unknown>): Promise<unknown>;
@@ -182939,4 +184375,53 @@ void _scriptMain;
182939
184375
  });
182940
184376
  }
182941
184377
 
182942
- export { require_dist, isInvalidClientError, assertUrlSafe, publicEndpointSsrfOptions, discoverProtectedResourceMetadata, discoverAuthorizationServerMetadata, normalizeTokenEndpointAuthMethod, resolveAdvertisedTokenEndpointAuthMethod, authMethodForStoredClient, selectDcrTokenEndpointAuthMethod, registerClient, buildAuthorizeUrl, exchangeCodeForTokens, refreshMcpToken, revokeMcpToken, computeExpiresAt, getMcpOAuthToken, findReusableMcpOAuthClient, invalidateMcpOAuthClient, upsertMcpOAuthToken, applyMcpOAuthRefresh, markMcpOAuthTokenStatus, deleteMcpOAuthToken, insertMcpOAuthPending, consumeMcpOAuthPending, gcMcpOAuthPending, setMcpServerAuthMethod, ensureMcpToken, callMcpServerTool, listVendoredOpenapiEntries, ConnectionAuthInputSchema, connectionAuthSummary, listRelationalCredentialBindings, getCredentialBindingById, findCredentialBindingByIdentity, upsertCredentialBinding, disableCredentialBinding, listScriptConnections, listScriptConnectionsAsync, getScriptConnectionById, ScriptConnectionConflictError, connectionAuthInputFromFlat, upsertScriptConnection, refreshScriptConnection, setScriptConnectionEnabled, deleteScriptConnection, getScriptApiConnectionDescriptors, getScriptMcpConnectionDescriptors, getScriptApiTypes, getScriptMcpTypes, oauthAppToProviderConfig, getOAuthProviderConfig, getOAuthBindingTokenStatus, buildScriptCredentialBindingsWithFailures, buildScriptCredentialBindings, buildSandboxedCommand, sandboxSpawnEnv, createCappedStreamState, snapshotCapped, readStreamCapped, writeBareImportShim, MIN_SCRIPT_WALL_CLOCK_MS, SCRIPT_LONG_TIMEOUT_HINT_MS, MAX_SCRIPT_WALL_CLOCK_MS, DEFAULT_SCRIPT_RESOURCES, require_typescript, checkImportAllowlist, validateScriptImports, runScript, extractScriptSignature, extractArgsJsonSchema, getSavedScriptOwnerAgentId, runSavedScriptAsAgent, resolveSyncRunAs, AppNameSchema, ColumnKindSchema, isIso8601Date, SYSTEM_COLUMN_KINDS, SORTABLE_SYSTEM_DATE_COLUMNS, AppElementsSchema, AppDefinitionSchema, collectScriptReferences, parseAppDefinition, applyAppDefinitionPatch, upgradeAppDefinition, decodeAppDefinition, appDefinitionNeedsRepair, createApp, getApp, listApps, listAppRecords, updateApp, deleteApp, getScriptAppTypes, SCRIPT_SDK_TYPES, scriptSdkTypesWithGeneratedApis, SCRIPT_STDLIB_MODULE_TYPES, scriptStdlibTypesWithGeneratedApis, typecheckWithAmbient, typecheckScript };
184378
+ // src/be/skill-parser.ts
184379
+ function parseSkillContent(content) {
184380
+ const trimmed = content.trim();
184381
+ if (!trimmed.startsWith("---")) {
184382
+ throw new Error("Skill content must start with YAML frontmatter (---). No frontmatter found.");
184383
+ }
184384
+ const secondDelimiter = trimmed.indexOf("---", 3);
184385
+ if (secondDelimiter === -1) {
184386
+ throw new Error("Skill content has unterminated frontmatter. Missing closing ---.");
184387
+ }
184388
+ const frontmatterRaw = trimmed.slice(3, secondDelimiter).trim();
184389
+ const body = trimmed.slice(secondDelimiter + 3).trim();
184390
+ const metadata = {};
184391
+ for (const line of frontmatterRaw.split(`
184392
+ `)) {
184393
+ const colonIdx = line.indexOf(":");
184394
+ if (colonIdx === -1)
184395
+ continue;
184396
+ const key = line.slice(0, colonIdx).trim();
184397
+ let value = line.slice(colonIdx + 1).trim();
184398
+ if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
184399
+ try {
184400
+ value = JSON.parse(value);
184401
+ } catch {}
184402
+ }
184403
+ if (key && value) {
184404
+ metadata[key] = value;
184405
+ }
184406
+ }
184407
+ if (!metadata.name) {
184408
+ throw new Error('Skill frontmatter is missing required field: "name"');
184409
+ }
184410
+ if (!metadata.description) {
184411
+ throw new Error('Skill frontmatter is missing required field: "description"');
184412
+ }
184413
+ return {
184414
+ name: metadata.name,
184415
+ description: metadata.description,
184416
+ allowedTools: metadata["allowed-tools"] || undefined,
184417
+ model: metadata.model || undefined,
184418
+ effort: metadata.effort || undefined,
184419
+ context: metadata.context || undefined,
184420
+ agent: metadata.agent || undefined,
184421
+ disableModelInvocation: metadata["disable-model-invocation"] === "true" ? true : undefined,
184422
+ userInvocable: metadata["user-invocable"] !== undefined ? metadata["user-invocable"] !== "false" : undefined,
184423
+ body
184424
+ };
184425
+ }
184426
+
184427
+ export { require_dist, isInvalidClientError, assertUrlSafe, publicEndpointSsrfOptions, mcpOAuthSsrfOptions, discoverProtectedResourceMetadata, discoverAuthorizationServerMetadata, normalizeTokenEndpointAuthMethod, resolveAdvertisedTokenEndpointAuthMethod, authMethodForStoredClient, selectDcrTokenEndpointAuthMethod, registerClient, buildAuthorizeUrl, exchangeCodeForTokens, refreshMcpToken, revokeMcpToken, computeExpiresAt, getMcpOAuthToken, findReusableMcpOAuthClient, invalidateMcpOAuthClient, upsertMcpOAuthToken, applyMcpOAuthRefresh, markMcpOAuthTokenStatus, deleteMcpOAuthToken, insertMcpOAuthPending, consumeMcpOAuthPending, gcMcpOAuthPending, setMcpServerAuthMethod, ensureMcpToken, callMcpServerTool, resolveSqlDsn, runReadOnlyQuery, listVendoredOpenapiEntries, ConnectionAuthInputSchema, SqlDsnInputSchema, connectionAuthSummary, listRelationalCredentialBindings, getCredentialBindingById, findCredentialBindingByIdentity, upsertCredentialBinding, disableCredentialBinding, listScriptConnections, listScriptConnectionsAsync, getScriptConnectionById, ScriptConnectionConflictError, connectionAuthInputFromFlat, upsertScriptConnection, refreshScriptConnection, setScriptConnectionEnabled, deleteScriptConnection, getScriptApiConnectionDescriptors, getScriptMcpConnectionDescriptors, getScriptApiTypes, getScriptMcpTypes, oauthAppToProviderConfig, getOAuthProviderConfig, getOAuthBindingTokenStatus, buildScriptCredentialBindingsWithFailures, buildSandboxedCommand, sandboxSpawnEnv, createCappedStreamState, snapshotCapped, readStreamCapped, writeBareImportShim, MIN_SCRIPT_WALL_CLOCK_MS, SCRIPT_LONG_TIMEOUT_HINT_MS, MAX_SCRIPT_WALL_CLOCK_MS, DEFAULT_SCRIPT_RESOURCES, require_typescript, checkImportAllowlist, validateScriptImports, runScript, extractScriptSignature, extractArgsJsonSchema, getSavedScriptOwnerAgentId, runSavedScriptAsAgent, resolveSyncRunAs, AppNameSchema, ColumnKindSchema, isIso8601Date, SYSTEM_COLUMN_KINDS, SORTABLE_SYSTEM_DATE_COLUMNS, AppElementsSchema, AppDefinitionSchema, collectScriptReferences, parseAppDefinition, applyAppDefinitionPatch, upgradeAppDefinition, decodeAppDefinition, appDefinitionNeedsRepair, createApp, getApp, listApps, listAppRecords, updateApp, deleteApp, getScriptAppTypes, SCRIPT_SDK_TYPES, scriptSdkTypesWithGeneratedApis, SCRIPT_STDLIB_MODULE_TYPES, scriptStdlibTypesWithGeneratedApis, typecheckWithAmbient, typecheckScript, parseSkillContent };