@desplega.ai/agent-swarm 1.164.1 → 1.166.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 (328) hide show
  1. package/README.md +1 -1
  2. package/dist/acp-adapter-yzfxn8vj.js +23 -0
  3. package/dist/{actions-hp2h32dx.js → actions-qz3m692w.js} +24 -28
  4. package/dist/{amp-adapter-zfd7djyx.js → amp-adapter-j1xbmsqz.js} +7 -7
  5. package/dist/{app-w2d26h4f.js → app-43vrdmv8.js} +9 -10
  6. package/dist/{assistant-45pc4en7.js → assistant-ertffmka.js} +25 -29
  7. package/dist/{boot-reembed-k1q2s4fc.js → boot-reembed-998jtpdg.js} +12 -15
  8. package/dist/{boot-reembed-6rhcpsjf.js → boot-reembed-s7k7c6v2.js} +13 -15
  9. package/dist/boot-scrub-sweep-nepsk4t1.js +211 -0
  10. package/dist/{boot-seeds-ex93edx7.js → boot-seeds-vvzs1zhk.js} +12 -12
  11. package/dist/{claude-adapter-hcxd0szm.js → claude-adapter-2zvmekrp.js} +15 -17
  12. package/dist/{claude-managed-adapter-fz7xps2r.js → claude-managed-adapter-s49wbk8t.js} +5 -5
  13. package/dist/{claude-managed-setup-xx6f15h9.js → claude-managed-setup-cvhqq8qn.js} +4 -4
  14. package/dist/{claude-sdk-session-6nb9raem.js → claude-sdk-session-kkbxtw5q.js} +2624 -2606
  15. package/dist/{cli-etbrt8x1.js → cli-0nhdwxd5.js} +4 -4
  16. package/dist/{cli-jeefgppq.js → cli-0qjcsxgz.js} +7 -7
  17. package/dist/{cli-6behs2bt.js → cli-32bca7nr.js} +1 -1
  18. package/dist/{cli-gt8v96qx.js → cli-3ddybbbx.js} +4 -4
  19. package/dist/{acp-adapter-rxvek4ym.js → cli-3qn4r334.js} +317 -35
  20. package/dist/{cli-1d3w4xm3.js → cli-4r1sjfc4.js} +14 -6
  21. package/dist/{cli-691f2rxm.js → cli-66zh26sp.js} +68 -16
  22. package/dist/{cli-et8wdyqh.js → cli-68r1j4sg.js} +9 -9
  23. package/dist/{cli-xb7kyanp.js → cli-8kgvmkak.js} +3 -3
  24. package/dist/{cli-fdpkw8vk.js → cli-8t229cmr.js} +8 -8
  25. package/dist/{cli-gc54qc0p.js → cli-aqcey741.js} +1 -1
  26. package/dist/{cli-4q4cmr4t.js → cli-cpfmqz3n.js} +8 -8
  27. package/dist/{cli-a9bw0xxt.js → cli-df56tqdw.js} +997 -408
  28. package/dist/{cli-n7h1kqpf.js → cli-dmtrxqhg.js} +6 -1
  29. package/dist/{cli-xfb7333f.js → cli-dw2q9f7g.js} +5 -5
  30. package/dist/{cli-4drstbb9.js → cli-ecknp7p1.js} +81 -23
  31. package/dist/{cli-v0pvvhfq.js → cli-efnd2kce.js} +36 -1
  32. package/dist/{cli-1wetf34q.js → cli-f2n17zhp.js} +1 -1
  33. package/dist/{cli-2c8eky5y.js → cli-feh3dkah.js} +1 -1
  34. package/dist/cli-fn697bnt.js +126 -0
  35. package/dist/{cli-v5pr2fgt.js → cli-gt8azyet.js} +3 -3
  36. package/dist/{cli-dbszf3rw.js → cli-h3x613ze.js} +4 -4
  37. package/dist/{cli-nwhb8y2e.js → cli-hf5s9pgf.js} +1 -1
  38. package/dist/cli-j2jbr8af.js +516 -0
  39. package/dist/{cli-agjzafns.js → cli-jhm6hzjn.js} +593 -10
  40. package/dist/{cli-j0tmc908.js → cli-jvj6a0cv.js} +484 -477
  41. package/dist/{cli-xxz89c2n.js → cli-mb75wpxf.js} +1 -1
  42. package/dist/{cli-07s39g1n.js → cli-mv2520nm.js} +1 -1
  43. package/dist/{cli-v90vfwyb.js → cli-mwegs4af.js} +5 -5
  44. package/dist/{cli-bz1gbac9.js → cli-p4ztb80h.js} +2 -2
  45. package/dist/{cli-1wd1n2ya.js → cli-rfphkzh5.js} +1 -1
  46. package/dist/{cli-976r1zqx.js → cli-rggdq8wq.js} +5 -5
  47. package/dist/{cli-3ajw5v5v.js → cli-rsy933yz.js} +6 -6
  48. package/dist/{cli-yj790e19.js → cli-tadfgd0t.js} +8 -1
  49. package/dist/{cli-cn53e7vc.js → cli-ttbsse3f.js} +6 -1
  50. package/dist/{cli-dyqsrqcf.js → cli-v2a8x45d.js} +4 -4
  51. package/dist/{cli-wbvnn6tk.js → cli-v6vv7dy8.js} +91 -9
  52. package/dist/{cli-z2ap2c0c.js → cli-vzc73wet.js} +90 -55
  53. package/dist/cli-wt7ccy4r.js +2654 -0
  54. package/dist/{cli-4cn19jvn.js → cli-x7kpr72a.js} +3 -3
  55. package/dist/{cli-003785v9.js → cli-xvc3q9br.js} +1 -1
  56. package/dist/{cli-v0e7jpr5.js → cli-xvdgasgy.js} +13 -4
  57. package/dist/{cli-asqeg4ve.js → cli-y59h2pk9.js} +2 -2
  58. package/dist/{cli-0wn3ypqv.js → cli-yshaazs1.js} +14121 -3478
  59. package/dist/{cli-wg8yjqtw.js → cli-ysnyhws9.js} +16 -3
  60. package/dist/cli-zp67qg5x.js +92 -0
  61. package/dist/{cli-g3qgrzck.js → cli-zsh093hk.js} +71 -3
  62. package/dist/{cli-ma3zvh39.js → cli-zy7vwsne.js} +6066 -5829
  63. package/dist/cli.js +79 -26
  64. package/dist/{codex-adapter-pcxdn10v.js → codex-adapter-dw1wxqt8.js} +10 -10
  65. package/dist/{codex-hook-b1fb7c2k.js → codex-hook-d2rkvf39.js} +1 -1
  66. package/dist/{codex-login-059nm145.js → codex-login-terbdsqq.js} +2 -2
  67. package/dist/{codex-session-runner-xzwwddp8.js → codex-session-runner-3cgb8y1g.js} +10 -10
  68. package/dist/{commands-98at8mkn.js → commands-mhxam6z2.js} +9 -9
  69. package/dist/{cursor-adapter-dkg6qnkp.js → cursor-adapter-2qda3st7.js} +6 -6
  70. package/dist/{db-01g8wtvw.js → db-sjks418k.js} +11 -9
  71. package/dist/{devin-adapter-qmttt2fz.js → devin-adapter-bffjj5n4.js} +2 -2
  72. package/dist/{dispatcher-nn2k1wxd.js → dispatcher-1es759rn.js} +22 -26
  73. package/dist/{dsh-adapter-w4d4vwdq.js → dsh-adapter-bek4cyw9.js} +6 -6
  74. package/dist/{e2b-9e4g2hvt.js → e2b-nd50eccg.js} +1 -1
  75. package/dist/{event-bus-z7v2t26e.js → event-bus-vnfthafg.js} +2 -2
  76. package/dist/grok-adapter-ar9cw9jg.js +29 -0
  77. package/dist/{handlers-b0kqsbg8.js → handlers-1gkbhktr.js} +25 -29
  78. package/dist/{hook-sap7v1aj.js → hook-ds2zxq9v.js} +16 -18
  79. package/dist/{hook-pz50gqep.js → hook-vxa3tcsy.js} +10 -12
  80. package/dist/{http-ncr8rmd0.js → http-3h21z9md.js} +679 -227
  81. package/dist/{index-c4aqcyz1.js → index-9b65j1m5.js} +11 -11
  82. package/dist/{index-r46s01nq.js → index-bn6cy8ps.js} +22 -26
  83. package/dist/{index-38kqdt3e.js → index-dkfxpkmm.js} +23 -27
  84. package/dist/{index-630kj5vd.js → index-f8xnqrye.js} +55 -43
  85. package/dist/{index-fdk1t4d6.js → index-n0rxa4ca.js} +11962 -9900
  86. package/dist/{index-9nrj7797.js → index-n99fycq7.js} +22 -26
  87. package/dist/{keepalive-31613r2h.js → keepalive-3xspa9jw.js} +14 -11
  88. package/dist/{lead-mx59tr5s.js → lead-6qphc124.js} +43 -43
  89. package/dist/{maintenance-55ff39ca.js → maintenance-0teem1bb.js} +10 -12
  90. package/dist/{node-f0ykebbv.js → node-9sg7ajby.js} +25 -7
  91. package/dist/{oauth-refresh-sweep-anma954w.js → oauth-refresh-sweep-sh9q25xp.js} +13 -10
  92. package/dist/{onboard-b2fy8ftb.js → onboard-54qmnqxe.js} +4 -3
  93. package/dist/{opencode-adapter-p1s92tmy.js → opencode-adapter-wjfa2wvd.js} +6 -6
  94. package/dist/{otel-impl-9brvt7xv.js → otel-impl-ycqzp2a1.js} +2 -2
  95. package/dist/{pi-mono-adapter-kz4rrwvd.js → pi-mono-adapter-e77e9zst.js} +6 -6
  96. package/dist/{pricing-refresh-7w8mbmva.js → pricing-refresh-atnkngqs.js} +10 -10
  97. package/dist/{rbac-roles-ejp7qwvb.js → rbac-roles-9pjphh9q.js} +10 -10
  98. package/dist/{rbac-roles-nhk4r7bc.js → rbac-roles-j78wdksm.js} +10 -10
  99. package/dist/{render-v2-2gzt8skq.js → render-v2-pxjs49fx.js} +9 -10
  100. package/dist/{setup-5et8t412.js → setup-ymej0xtx.js} +2 -2
  101. package/dist/{work-objects-tb0er7qa.js → work-objects-3nh4ymzb.js} +26 -30
  102. package/dist/{worker-62cv075d.js → worker-qa9fkz5s.js} +43 -43
  103. package/dist/{x-vbxb31jr.js → x-ma4gnfgy.js} +2 -2
  104. package/openapi.json +457 -31
  105. package/package.json +14 -6
  106. package/plugin/commands/create-pr.md +7 -1
  107. package/plugin/pi-skills/create-pr/SKILL.md +7 -1
  108. package/src/agentmail/app.ts +5 -4
  109. package/src/be/automation-preflight.ts +11 -9
  110. package/src/be/boot-scrub-sweep.ts +302 -0
  111. package/src/be/connector-codes.ts +81 -0
  112. package/src/be/crypto/key-bootstrap.ts +1 -1
  113. package/src/be/db/approvals.ts +15 -1
  114. package/src/be/db/codex-oauth-device-flows.ts +40 -0
  115. package/src/be/db/config-secrets.ts +31 -0
  116. package/src/be/db/runtime.ts +4 -0
  117. package/src/be/db/script-runs.ts +15 -0
  118. package/src/be/db/tasks/write.ts +1 -1
  119. package/src/be/db-queries/mcp-oauth.ts +5 -0
  120. package/src/be/db-queries/oauth.ts +77 -0
  121. package/src/be/db.ts +162 -59
  122. package/src/be/events.ts +17 -1
  123. package/src/be/memory/index-content.ts +2 -2
  124. package/src/be/memory/providers/sqlite-store.ts +63 -11
  125. package/src/be/memory/types.ts +14 -0
  126. package/src/be/migrations/197_connector_codes.sql +23 -0
  127. package/src/be/migrations/198_permission_audit_guest.sql +33 -0
  128. package/src/be/migrations/200_backfill_auto_memory_expiry.sql +20 -0
  129. package/src/be/migrations/201_workflow_replay_columns.sql +10 -0
  130. package/src/be/migrations/202_codex_oauth_device_flows.sql +24 -0
  131. package/src/be/model-tier-resolution.ts +2 -1
  132. package/src/be/model-validation.ts +1 -1
  133. package/src/be/pricing-normalize.ts +3 -0
  134. package/src/be/rbac-audit.ts +2 -1
  135. package/src/be/scripts/db.ts +28 -4
  136. package/src/be/scripts/source-secrets.ts +37 -0
  137. package/src/be/scripts/typecheck.ts +23 -2
  138. package/src/be/scrub-json.ts +32 -0
  139. package/src/be/sealed-json.ts +59 -0
  140. package/src/be/secret-registry.ts +131 -0
  141. package/src/be/seed-pricing.ts +14 -0
  142. package/src/be/users.ts +7 -1
  143. package/src/be/workflow-replay.ts +77 -0
  144. package/src/cli.tsx +7 -0
  145. package/src/commands/provider-credentials.ts +46 -8
  146. package/src/commands/runner.ts +2 -10
  147. package/src/extensions/contract-types.generated.ts +1 -1
  148. package/src/github/app.ts +4 -4
  149. package/src/heartbeat/heartbeat.ts +20 -8
  150. package/src/hooks/pr-body-guard.ts +1 -1
  151. package/src/http/agents.ts +1 -0
  152. package/src/http/approval-requests.ts +1 -0
  153. package/src/http/apps.ts +3 -0
  154. package/src/http/auth.ts +4 -1
  155. package/src/http/codex-oauth-device.ts +8 -10
  156. package/src/http/codex-oauth-keep-warm.ts +2 -2
  157. package/src/http/config-values.ts +59 -0
  158. package/src/http/config.ts +5 -0
  159. package/src/http/db-query-bounded.ts +3 -0
  160. package/src/http/db-query-shared.ts +107 -15
  161. package/src/http/db-query.ts +10 -2
  162. package/src/http/extensions.ts +1 -0
  163. package/src/http/index.ts +23 -6
  164. package/src/http/integrations.ts +1 -38
  165. package/src/http/ip-rate-limit.ts +82 -0
  166. package/src/http/kv.ts +38 -4
  167. package/src/http/mcp-servers.ts +1 -0
  168. package/src/http/memory.ts +9 -0
  169. package/src/http/models-catalog.ts +2 -0
  170. package/src/http/operator-actor.ts +4 -0
  171. package/src/http/page-proxy.ts +22 -0
  172. package/src/http/pages.ts +4 -2
  173. package/src/http/realtime.ts +1 -1
  174. package/src/http/request-principal.ts +14 -1
  175. package/src/http/script-connections.ts +8 -0
  176. package/src/http/script-runs.ts +12 -4
  177. package/src/http/scripts.ts +15 -0
  178. package/src/http/session-cost-recompute.ts +3 -2
  179. package/src/http/tasks.ts +9 -0
  180. package/src/http/users.ts +226 -0
  181. package/src/http/workflows.ts +3 -2
  182. package/src/http.ts +1 -0
  183. package/src/integrations/kapso/client.ts +3 -1
  184. package/src/jira/app.ts +2 -2
  185. package/src/kv-view.ts +324 -0
  186. package/src/linear/app.ts +2 -2
  187. package/src/oauth/mcp-wrapper.ts +1 -1
  188. package/src/prompts/memories.ts +42 -1
  189. package/src/providers/acp-adapter.ts +85 -24
  190. package/src/providers/acp-target-catalog.ts +54 -1
  191. package/src/providers/acp-targets.ts +358 -4
  192. package/src/providers/amp-adapter.ts +1 -1
  193. package/src/providers/cursor-adapter.ts +1 -1
  194. package/src/providers/grok-adapter.ts +186 -0
  195. package/src/providers/index.ts +5 -1
  196. package/src/providers/pricing-sources.md +6 -0
  197. package/src/providers/reasoning-effort.ts +17 -1
  198. package/src/providers/types.ts +2 -1
  199. package/src/rbac/can.ts +4 -3
  200. package/src/rbac/legacy-policy.ts +3 -3
  201. package/src/rbac/types.ts +6 -0
  202. package/src/script-workflows/supervisor.ts +11 -2
  203. package/src/scripts-runtime/eval-harness.ts +2 -12
  204. package/src/scripts-runtime/executors/quickjs-bundle.ts +152 -0
  205. package/src/scripts-runtime/executors/quickjs-prelude.ts +285 -0
  206. package/src/scripts-runtime/executors/quickjs-runner.ts +580 -0
  207. package/src/scripts-runtime/executors/quickjs-worker.ts +81 -0
  208. package/src/scripts-runtime/executors/quickjs.ts +196 -0
  209. package/src/scripts-runtime/executors/registry.ts +2 -0
  210. package/src/scripts-runtime/executors/sourcemap.ts +79 -0
  211. package/src/scripts-runtime/script-error-hints.ts +14 -0
  212. package/src/scripts-runtime/swarm-sdk.ts +9 -2
  213. package/src/scripts-runtime/types/stdlib.d.ts +27 -8
  214. package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
  215. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -8
  216. package/src/server-user.ts +2 -20
  217. package/src/server.ts +3 -1
  218. package/src/slack/app.ts +4 -0
  219. package/src/slack/config.ts +3 -1
  220. package/src/slack/egress-scrub.ts +87 -0
  221. package/src/tests/acp-adapter.test.ts +191 -2
  222. package/src/tests/boot-scrub-sweep.test.ts +390 -0
  223. package/src/tests/budget-user-scope.test.ts +7 -21
  224. package/src/tests/check-pr-body.test.ts +149 -6
  225. package/src/tests/check-text-columns.test.ts +145 -0
  226. package/src/tests/claude-adapter-binary.test.ts +1 -1
  227. package/src/tests/claude-sdk-process.fixture.ts +13 -2
  228. package/src/tests/codex-oauth-device.test.ts +23 -37
  229. package/src/tests/codex-oauth-keep-warm.test.ts +29 -0
  230. package/src/tests/console-scrub.test.ts +141 -0
  231. package/src/tests/credential-check.test.ts +90 -0
  232. package/src/tests/db-query-denylist.test.ts +202 -0
  233. package/src/tests/db-task-read-contract.test.ts +1 -0
  234. package/src/tests/db-task-write-contract.test.ts +1 -0
  235. package/src/tests/docs-index-footprint.test.js +3 -3
  236. package/src/tests/entrypoint-acp-target-binary.test.ts +44 -1
  237. package/src/tests/events-scrub.test.ts +88 -0
  238. package/src/tests/explicit-model-validation.test.ts +81 -0
  239. package/src/tests/extensions-pre-task.test.ts +33 -1
  240. package/src/tests/fixtures/grok/acp-updates-recorded.jsonl +53 -0
  241. package/src/tests/fixtures/grok/prompt-response-meta.json +36 -0
  242. package/src/tests/fixtures/secret-corpus.ts +320 -0
  243. package/src/tests/grok-adapter.test.ts +647 -0
  244. package/src/tests/heartbeat-checklist.test.ts +44 -0
  245. package/src/tests/integration-disable-flags.test.ts +156 -0
  246. package/src/tests/kv-http.test.ts +34 -0
  247. package/src/tests/kv-tool.test.ts +274 -1
  248. package/src/tests/kv-view.test.ts +147 -0
  249. package/src/tests/mcp-user-route.test.ts +257 -15
  250. package/src/tests/memory-injection-outcome.test.ts +143 -0
  251. package/src/tests/model-tier-resolution.test.ts +76 -3
  252. package/src/tests/page-guest-session.test.ts +424 -0
  253. package/src/tests/page-proxy.test.ts +1 -1
  254. package/src/tests/page-viewer-auth.test.ts +22 -1
  255. package/src/tests/pr-body-leaks.test.ts +157 -2
  256. package/src/tests/preload.ts +10 -0
  257. package/src/tests/provider-registration.test.ts +3 -1
  258. package/src/tests/rbac-audit.test.ts +32 -0
  259. package/src/tests/rbac-mcp-admission-e2e.test.ts +4 -62
  260. package/src/tests/script-connections.test.ts +9 -0
  261. package/src/tests/script-executor-conformance.test.ts +3 -0
  262. package/src/tests/script-executor-quickjs.test.ts +442 -0
  263. package/src/tests/script-executor-registry.test.ts +6 -1
  264. package/src/tests/script-runs-http.test.ts +126 -1
  265. package/src/tests/script-runs-scrub.test.ts +275 -0
  266. package/src/tests/scripts-http.test.ts +82 -1
  267. package/src/tests/scripts-mcp-e2e.test.ts +42 -6
  268. package/src/tests/scripts-runtime.test.ts +37 -0
  269. package/src/tests/scrubbed-text-12e.test.ts +289 -0
  270. package/src/tests/sealed-key-guard.test.ts +166 -0
  271. package/src/tests/secret-canary-sweep.test.ts +958 -0
  272. package/src/tests/secret-registry.test.ts +355 -0
  273. package/src/tests/secret-rules.test.ts +230 -0
  274. package/src/tests/secret-scrubber.test.ts +317 -1
  275. package/src/tests/session-costs-golden.test.ts +17 -0
  276. package/src/tests/slack-egress-scrub.test.ts +216 -0
  277. package/src/tests/swarm-tool-result-gate.test.ts +143 -30
  278. package/src/tests/task-tools-ctx.test.ts +3 -0
  279. package/src/tests/user-token-routes.test.ts +342 -3
  280. package/src/tests/workflow-replay.test.ts +518 -0
  281. package/src/tests/workflow-scrub.test.ts +242 -0
  282. package/src/tests/workflow-system-one-decision-providers.test.ts +737 -0
  283. package/src/tools/db-query.ts +1 -1
  284. package/src/tools/inject-learning.ts +1 -1
  285. package/src/tools/kv/kv-get.ts +136 -6
  286. package/src/tools/send-task.ts +61 -17
  287. package/src/tools/utils.ts +186 -43
  288. package/src/tools/workflows/get-workflow-run.ts +3 -2
  289. package/src/types.ts +16 -1
  290. package/src/utils/console-scrub-install.ts +5 -0
  291. package/src/utils/console-scrub.ts +57 -0
  292. package/src/utils/credentials.ts +8 -0
  293. package/src/utils/page-session.ts +6 -2
  294. package/src/utils/pr-body-leaks.ts +149 -10
  295. package/src/utils/request-auth-context.ts +2 -0
  296. package/src/utils/secret-rules.generated.ts +2055 -0
  297. package/src/utils/secret-scrubber.ts +662 -36
  298. package/src/workflows/engine.ts +39 -4
  299. package/src/workflows/executors/notify.ts +6 -1
  300. package/src/workflows/executors/system-one-decision.ts +31 -12
  301. package/src/workflows/executors/system-one-openai-wire.ts +168 -0
  302. package/src/workflows/executors/system-one-providers.ts +112 -11
  303. package/src/workflows/executors/system-one-wire.ts +79 -0
  304. package/src/workflows/recovery.ts +10 -1
  305. package/src/workflows/resume.ts +62 -3
  306. package/src/workflows/retry-poller.ts +3 -0
  307. package/templates/ai-toolbox.manifest.json +2 -2
  308. package/templates/skills/agent-browser/SKILL.md +5 -5
  309. package/templates/skills/agent-browser/config.json +1 -1
  310. package/templates/skills/agent-browser/content.md +4 -4
  311. package/templates/skills/artifacts/content.md +17 -7
  312. package/templates/skills/jira-interaction/config.json +1 -1
  313. package/templates/skills/jira-interaction/content.md +56 -205
  314. package/templates/skills/linear-interaction/config.json +1 -1
  315. package/templates/skills/linear-interaction/content.md +31 -50
  316. package/templates/skills/pages/content.md +8 -4
  317. package/templates/skills/qa/content.md +2 -2
  318. package/templates/skills/workflow-iterate/content.md +4 -4
  319. package/tsconfig.json +3 -3
  320. package/dist/boot-scrub-logs-t8xg7wd7.js +0 -99
  321. package/dist/cli-0a7r5331.js +0 -168
  322. package/dist/cli-93rxw9yd.js +0 -951
  323. package/dist/cli-cvk6yzw5.js +0 -40
  324. package/dist/cli-dgnj0zcc.js +0 -40
  325. package/dist/cli-qt5wzq6v.js +0 -256
  326. package/dist/cli-v7fqehqd.js +0 -9281
  327. package/dist/cli-vbr859rz.js +0 -572
  328. package/src/be/boot-scrub-logs.ts +0 -132
@@ -26,7 +26,7 @@ export const registerDbQueryTool = (server: McpServer) => {
26
26
  {
27
27
  title: "Execute database query",
28
28
  description:
29
- "Execute a read-only SQL query against the swarm database (SQLite). Available to all authenticated agents — be aware results may include secrets (oauth_tokens, configs). Runs in a short-lived child process with a wall-clock budget by default (fails gracefully with a timeout or a 429-style concurrency error rather than freezing); results capped at a default row count (operator-configurable via `DB_QUERY_MCP_MAX_ROWS`) regardless of how many the query matched. See the sql parameter's description for which tables are unsafe to read whole, and the db-query-guidance skill for config knobs.",
29
+ "Execute a read-only SQL query against the swarm database (SQLite). Available to all authenticated agents. Queries that read credential tables (OAuth authorizations, apps and pending flows, user and session tokens, script API bearers, Codex device-login state) are rejected, and secret-shaped values in results are redacted. Runs in a short-lived child process with a wall-clock budget by default (fails gracefully with a timeout or a 429-style concurrency error rather than freezing); results capped at a default row count (operator-configurable via `DB_QUERY_MCP_MAX_ROWS`) regardless of how many the query matched. See the sql parameter's description for which tables are unsafe to read whole, and the db-query-guidance skill for config knobs.",
30
30
  annotations: { readOnlyHint: true },
31
31
  inputSchema: DbQueryToolInputSchema,
32
32
  outputSchema: swarmToolOutputSchema({
@@ -73,7 +73,7 @@ export const registerInjectLearningTool = (server: McpServer) => {
73
73
  // Generate and store embedding (async, best-effort)
74
74
  try {
75
75
  const provider = getEmbeddingProvider();
76
- const embedding = await provider.embed(content);
76
+ const embedding = await provider.embed(memory.content);
77
77
  if (embedding) {
78
78
  await store.updateEmbedding(memory.id, embedding, provider.name);
79
79
  }
@@ -1,8 +1,25 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import * as z from "zod";
3
3
  import { getKv } from "@/be/db";
4
- import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
5
- import { KvKeySchema, KvNamespaceSchema, KvValueTypeSchema } from "@/types";
4
+ import {
5
+ hasKvViewArgs,
6
+ joinKvPath,
7
+ KV_PATH_MAX_CHARS,
8
+ type KvView,
9
+ resolveKvTarget,
10
+ resolveKvView,
11
+ sliceKvTarget,
12
+ } from "@/kv-view";
13
+ import {
14
+ createToolRegistrar,
15
+ MCP_RESULT_WIRE_LIMIT_BYTES,
16
+ type SwarmToolResult,
17
+ swarmToolOutputSchema,
18
+ swarmToolResultBytes,
19
+ toolErr,
20
+ toolOk,
21
+ } from "@/tools/utils";
22
+ import { type KvEntry, KvKeySchema, KvNamespaceSchema, KvValueTypeSchema } from "@/types";
6
23
  import { kvReadAuthError } from "./kv-read-auth";
7
24
  import { resolveNamespace } from "./resolve-namespace";
8
25
 
@@ -28,13 +45,102 @@ function renderKvEntry(entry: {
28
45
  return `value (${entry.valueType}): ${valueText}${expiry}`;
29
46
  }
30
47
 
48
+ const kvViewOutputSchema = z.looseObject({
49
+ path: z.string().optional(),
50
+ type: z.string().optional(),
51
+ total: z.number().optional(),
52
+ offset: z.number().optional(),
53
+ returned: z.number().optional(),
54
+ nextOffset: z.number().nullable().optional(),
55
+ });
56
+
57
+ function describeView(view: KvView): string {
58
+ const target = view.path ? `"${view.path}"` : "the value";
59
+ if (view.total === undefined) return `${target} (${view.type})`;
60
+ const unit =
61
+ view.type === "array" ? "items" : view.type === "object" ? "keys" : "chars (JSON-encoded)";
62
+ const offset = view.offset ?? 0;
63
+ return `${target} ${unit} ${offset}..${offset + (view.returned ?? 0)} of ${view.total}`;
64
+ }
65
+
66
+ /**
67
+ * A targeted read shrunk to the per-channel MCP budget. kv-get is spill-exempt,
68
+ * so the tool bounds its own views: the page shrinks (binary search on items,
69
+ * keys, or chars) and `view.nextOffset` says where to resume.
70
+ */
71
+ function boundedView(
72
+ entry: KvEntry,
73
+ agentId: string | undefined,
74
+ args: { path?: string; offset?: number; limit?: number },
75
+ ): SwarmToolResult {
76
+ const { namespace, key } = entry;
77
+ const failed = (error: string) => toolErr(error, { data: { yourAgentId: agentId, namespace } });
78
+ // Validates path and offset/limit applicability; the page itself is sized below.
79
+ const checked = resolveKvView(entry.value, args);
80
+ if (!checked.ok) return failed(checked.error);
81
+ const target = resolveKvTarget(entry.value, args.path ?? "");
82
+ if (!target.ok) return failed(target.error);
83
+
84
+ const { value: _value, ...meta } = entry;
85
+ // Strings go out JSON-encoded too: the wire composer trims `details`, which
86
+ // would drop a slice's edge whitespace and erase a whitespace-only slice.
87
+ const render = (value: unknown, view: KvView) =>
88
+ toolOk(`Read ${describeView(view)} from "${key}" in "${namespace}".`, {
89
+ details: JSON.stringify(value),
90
+ data: { yourAgentId: agentId, namespace, entry: meta, view },
91
+ });
92
+ const baseView = checked.view;
93
+ if (baseView.total === undefined) return render(checked.value, baseView);
94
+
95
+ const offset = baseView.offset ?? 0;
96
+ const wanted = Math.min(args.limit ?? baseView.total, Math.max(0, baseView.total - offset));
97
+ const firstKey =
98
+ baseView.type === "array"
99
+ ? String(offset)
100
+ : baseView.type === "object"
101
+ ? Object.keys(target.value as object)[offset]
102
+ : undefined;
103
+ // An empty key or an over-long path cannot be passed back as `path`.
104
+ const firstPath =
105
+ firstKey === undefined || firstKey === ""
106
+ ? undefined
107
+ : `${baseView.path ? `${baseView.path}.` : ""}${joinKvPath([firstKey])}`;
108
+ const narrowTo = firstPath !== undefined && firstPath.length <= KV_PATH_MAX_CHARS;
109
+ // A shrunk page carries its note, so the note is part of what gets sized.
110
+ const page = (count: number) => {
111
+ const sliced = sliceKvTarget(target.value, offset, count);
112
+ const result = render(sliced?.value, {
113
+ ...baseView,
114
+ returned: sliced?.returned ?? 0,
115
+ nextOffset: sliced?.nextOffset ?? null,
116
+ });
117
+ if (count >= wanted) return result;
118
+ const note =
119
+ count === 0 && narrowTo
120
+ ? ` The entry at offset ${offset} alone exceeds the ${MCP_RESULT_WIRE_LIMIT_BYTES}-byte cap; narrow the path to "${firstPath}".`
121
+ : ` Page shrunk to fit the ${MCP_RESULT_WIRE_LIMIT_BYTES}-byte cap; continue at view.nextOffset.`;
122
+ return { ...result, message: `${result.message}${note}` };
123
+ };
124
+ const fits = (count: number) => swarmToolResultBytes(page(count)) <= MCP_RESULT_WIRE_LIMIT_BYTES;
125
+ if (fits(wanted)) return page(wanted);
126
+
127
+ let low = 0;
128
+ let high = wanted;
129
+ while (low < high) {
130
+ const mid = Math.ceil((low + high) / 2);
131
+ if (fits(mid)) low = mid;
132
+ else high = mid - 1;
133
+ }
134
+ return page(low);
135
+ }
136
+
31
137
  export const registerKvGetTool = (server: McpServer) => {
32
138
  createToolRegistrar(server)(
33
139
  "kv-get",
34
140
  {
35
141
  title: "KV Get",
36
142
  description:
37
- "Read a key from the swarm KV store. Returns the entry or null if missing/expired. Namespace defaults to your current context (Slack thread / PR / Linear issue when invoked from a task; otherwise your agent scratchpad).",
143
+ "Read a key from the swarm KV store. Returns the entry or null if missing/expired. Namespace defaults to your current context (Slack thread / PR / Linear issue when invoked from a task; otherwise your agent scratchpad). Without path/offset/limit the whole value comes back unbounded. With any of them you get a bounded view (≤10KB per channel): `path` is a dot path into a JSON value (string entries holding JSON, such as spilled tool results, count as JSON; numeric segments index arrays, e.g. `outcome.data.rows` or `rows.3`; escape a dot inside a key as `\\.`), and `offset`/`limit` page the array items, object keys, or string characters found there. The result's `view.nextOffset` says where the next page starts.",
38
144
  annotations: { readOnlyHint: true },
39
145
 
40
146
  inputSchema: z.object({
@@ -42,14 +148,34 @@ export const registerKvGetTool = (server: McpServer) => {
42
148
  namespace: KvNamespaceSchema.optional().describe(
43
149
  "Optional explicit namespace. Defaults to the caller's contextKey.",
44
150
  ),
151
+ path: z
152
+ .string()
153
+ .max(KV_PATH_MAX_CHARS)
154
+ .optional()
155
+ .describe(
156
+ 'Dot path into the JSON value, e.g. "outcome.data.rows" or "rows.3". "" is the whole value. A dot inside a key is escaped as "\\.".',
157
+ ),
158
+ offset: z
159
+ .number()
160
+ .int()
161
+ .nonnegative()
162
+ .optional()
163
+ .describe("First array item / object key / string char to return. Default 0."),
164
+ limit: z
165
+ .number()
166
+ .int()
167
+ .positive()
168
+ .optional()
169
+ .describe("Max items / keys / chars to return; the page also shrinks to fit the cap."),
45
170
  }),
46
171
  outputSchema: swarmToolOutputSchema({
47
172
  yourAgentId: z.string().optional(),
48
173
  namespace: z.string().optional(),
49
174
  entry: kvEntryOutputSchema.nullable().optional(),
175
+ view: kvViewOutputSchema.optional(),
50
176
  }),
51
177
  },
52
- async ({ key, namespace }, requestInfo) => {
178
+ async ({ key, namespace, path, offset, limit }, requestInfo) => {
53
179
  const resolved = await resolveNamespace(namespace, requestInfo);
54
180
  if ("error" in resolved) {
55
181
  return toolErr(resolved.error, { data: { yourAgentId: requestInfo.agentId } });
@@ -62,9 +188,13 @@ export const registerKvGetTool = (server: McpServer) => {
62
188
  }
63
189
 
64
190
  // kv-get is exempt from the ctx-control spill (see CTX_CONTROL_EXEMPT_TOOLS):
65
- // it is the retrieval path for spilled values, so oversized entries go out
66
- // whole and the harness applies its own truncation.
191
+ // it is the retrieval path for spilled values. Without view args oversized
192
+ // entries go out whole and the harness applies its own truncation; with
193
+ // path/offset/limit the tool bounds the page itself.
67
194
  const entry = await getKv(resolved.namespace, key);
195
+ if (entry && hasKvViewArgs({ path, offset, limit })) {
196
+ return boundedView(entry, requestInfo.agentId, { path, offset, limit });
197
+ }
68
198
  return toolOk(
69
199
  entry
70
200
  ? `Found "${key}" in "${resolved.namespace}".`
@@ -11,6 +11,7 @@ import {
11
11
  getActiveTaskCount,
12
12
  getAgentById,
13
13
  getDbClient,
14
+ getLeadAgent,
14
15
  getTaskById,
15
16
  getUserById,
16
17
  hasCapacity,
@@ -289,11 +290,28 @@ export async function sendTaskHandler(
289
290
  outputSchema,
290
291
  }: SendTaskArgs,
291
292
  ): Promise<SwarmToolResult> {
293
+ const userLead = ctx.kind === "user" ? await getLeadAgent() : null;
294
+ if (ctx.kind === "user" && (!userLead || userLead.status === "offline")) {
295
+ return toolErr("No online Lead is available. Start or register a Lead before sending a task.");
296
+ }
297
+
298
+ const requestedAgentId = ctx.kind === "user" ? userLead!.id : agentId;
299
+ const requestedRoutingReason = ctx.kind === "user" ? "skill" : routingReason;
300
+ const requestedRoutingNote =
301
+ ctx.kind === "user"
302
+ ? "User MCP ingress assigns new work to the Lead for delegation."
303
+ : routingNote;
304
+ const requestedOfferMode = ctx.kind === "user" ? false : offerMode;
305
+ const requestedLeadOnly = ctx.kind === "user" ? false : leadOnly;
306
+ const requestedCapabilities = ctx.kind === "user" ? undefined : requiredCapabilities;
307
+ const requestedAllowDuplicate = ctx.kind === "user" ? false : allowDuplicate;
308
+ const requestedOverrideSlackContext = ctx.kind === "user" ? false : overrideSlackContext;
309
+
292
310
  // Defense in depth for direct TypeScript callers that bypass MCP schema parsing.
293
- if (agentId !== undefined && routingReason === undefined) {
311
+ if (requestedAgentId !== undefined && requestedRoutingReason === undefined) {
294
312
  return toolErr("routingReason is required when agentId is supplied.");
295
313
  }
296
- if (agentId !== undefined && (routingNote?.trim().length ?? 0) < 10) {
314
+ if (requestedAgentId !== undefined && (requestedRoutingNote?.trim().length ?? 0) < 10) {
297
315
  return toolErr(
298
316
  "routingNote is required when agentId is supplied (at least 10 characters after trim).",
299
317
  );
@@ -337,7 +355,7 @@ export async function sendTaskHandler(
337
355
  });
338
356
  }
339
357
 
340
- if (ctx.kind === "owner" && agentId === ctx.agentId) {
358
+ if (ctx.kind === "owner" && requestedAgentId === ctx.agentId) {
341
359
  return toolErr("Cannot send a task to yourself, are you drunk?", {
342
360
  data: { yourAgentId: ctx.agentId },
343
361
  });
@@ -358,7 +376,10 @@ export async function sendTaskHandler(
358
376
  }
359
377
  // A public continuation cannot accidentally declassify its parent before
360
378
  // createTaskExtended performs the authoritative merge.
361
- const effectiveLeadOnly = leadOnly || effectiveParentTask?.routingAffinity?.leadOnly === true;
379
+ const effectiveLeadOnly =
380
+ ctx.kind === "user"
381
+ ? false
382
+ : requestedLeadOnly || effectiveParentTask?.routingAffinity?.leadOnly === true;
362
383
 
363
384
  // Slack-routing coherence guard: reject a hand-typed slackChannelId/slackThreadTs
364
385
  // that disagrees with the parent task or the contextKey this child will inherit.
@@ -367,7 +388,7 @@ export async function sendTaskHandler(
367
388
  // dispatch-slack-channel-must-match-parent-context-2026-07-10). Omitting the
368
389
  // three Slack fields lets inheritance do the right thing; overrideSlackContext
369
390
  // opts into a deliberate cross-channel dispatch.
370
- if (!overrideSlackContext) {
391
+ if (!requestedOverrideSlackContext) {
371
392
  // send-task never passes contextKey explicitly, so the child inherits the
372
393
  // parent's contextKey verbatim (createTaskExtended, src/be/db.ts:3556-3558).
373
394
  const inheritedContextKey = effectiveParentTask?.contextKey;
@@ -406,8 +427,8 @@ export async function sendTaskHandler(
406
427
  }
407
428
 
408
429
  // Auto-route to parent's worker if parentTaskId is set and no explicit agentId
409
- let effectiveAgentId = agentId;
410
- if (effectiveParentTaskId && !agentId) {
430
+ let effectiveAgentId = requestedAgentId;
431
+ if (effectiveParentTaskId && !requestedAgentId) {
411
432
  if (effectiveParentTask?.agentId) {
412
433
  effectiveAgentId = effectiveParentTask.agentId;
413
434
  }
@@ -421,15 +442,25 @@ export async function sendTaskHandler(
421
442
  });
422
443
  if (modelError) return toolErr(modelError, { data: { yourAgentId: creatorAgentId } });
423
444
  const effectiveRoutingReason =
424
- agentId !== undefined ? routingReason : effectiveAgentId ? "continuity" : undefined;
425
- const effectiveRoutingNote = effectiveRoutingReason ? routingNote : undefined;
445
+ requestedAgentId !== undefined
446
+ ? requestedRoutingReason
447
+ : effectiveAgentId
448
+ ? "continuity"
449
+ : undefined;
450
+ const effectiveRoutingNote = effectiveRoutingReason ? requestedRoutingNote : undefined;
426
451
  const effectiveRoutingSource =
427
- agentId !== undefined ? "declared" : effectiveAgentId ? "engine_default" : undefined;
452
+ ctx.kind === "user"
453
+ ? "engine_default"
454
+ : requestedAgentId !== undefined
455
+ ? "declared"
456
+ : effectiveAgentId
457
+ ? "engine_default"
458
+ : undefined;
428
459
 
429
460
  const requestedTaskOptions: CreateTaskOptions = {
430
461
  key: assetKey,
431
- agentId: offerMode ? undefined : effectiveAgentId,
432
- offeredTo: offerMode ? effectiveAgentId : undefined,
462
+ agentId: requestedOfferMode ? undefined : effectiveAgentId,
463
+ offeredTo: requestedOfferMode ? effectiveAgentId : undefined,
433
464
  creatorAgentId,
434
465
  requestedByUserId,
435
466
  source: "mcp",
@@ -447,7 +478,7 @@ export async function sendTaskHandler(
447
478
  slackChannelId,
448
479
  slackThreadTs,
449
480
  slackUserId,
450
- overrideSlackContext,
481
+ overrideSlackContext: requestedOverrideSlackContext,
451
482
  followUpConfig,
452
483
  // A delegation with parentTaskId is new work and starts without the
453
484
  // parent's followUpConfig. A `resume` re-delegation (the reroute-decision
@@ -458,8 +489,8 @@ export async function sendTaskHandler(
458
489
  routingSource: effectiveRoutingSource,
459
490
  routingNote: effectiveRoutingNote,
460
491
  routingAffinity:
461
- effectiveLeadOnly || requiredCapabilities?.length
462
- ? { leadOnly: effectiveLeadOnly, capabilities: requiredCapabilities ?? [] }
492
+ effectiveLeadOnly || requestedCapabilities?.length
493
+ ? { leadOnly: effectiveLeadOnly, capabilities: requestedCapabilities ?? [] }
463
494
  : undefined,
464
495
  };
465
496
  const preCreate = await applyPreTaskCreate({
@@ -477,6 +508,12 @@ export async function sendTaskHandler(
477
508
  }
478
509
  const taskDescription = preCreate.description;
479
510
  const taskOptions = preCreate.options;
511
+ if (
512
+ ctx.kind === "user" &&
513
+ (taskOptions.agentId !== userLead!.id || taskOptions.offeredTo !== undefined)
514
+ ) {
515
+ return toolErr("A pre.task.create extension cannot change the user task's Lead assignment.");
516
+ }
480
517
 
481
518
  // The three dedup guards are pure reads, so they run twice: once here as a
482
519
  // fast path (keeping this tool's existing early-exit responses), and once
@@ -500,7 +537,7 @@ export async function sendTaskHandler(
500
537
  }
501
538
 
502
539
  // Dedup guard: check for similar recent tasks
503
- if (!allowDuplicate && creatorAgentId) {
540
+ if (!requestedAllowDuplicate && creatorAgentId) {
504
541
  const duplicate = await findDuplicateTask({
505
542
  taskDescription,
506
543
  creatorAgentId: taskOptions.creatorAgentId ?? creatorAgentId,
@@ -616,6 +653,13 @@ export async function sendTaskHandler(
616
653
  };
617
654
  }
618
655
 
656
+ if (ctx.kind === "user" && (!agent.isLead || agent.status === "offline")) {
657
+ return {
658
+ success: false,
659
+ message: "The Lead is no longer online. No task was created.",
660
+ };
661
+ }
662
+
619
663
  if (isExtensionAgent(agent)) {
620
664
  return { success: false, message: extensionAgentAssignmentError(agent) };
621
665
  }
@@ -628,7 +672,7 @@ export async function sendTaskHandler(
628
672
  }
629
673
 
630
674
  // For direct assignment (not offer), check if agent has capacity
631
- if (!taskOptions.offeredTo && !(await hasCapacity(targetAgentId))) {
675
+ if (ctx.kind !== "user" && !taskOptions.offeredTo && !(await hasCapacity(targetAgentId))) {
632
676
  const activeCount = await getActiveTaskCount(targetAgentId);
633
677
  return {
634
678
  success: false,