@desplega.ai/agent-swarm 1.159.0 → 1.161.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 (415) hide show
  1. package/README.md +2 -2
  2. package/dist/{acp-adapter-qhch0n2v.js → acp-adapter-xx489vvb.js} +286 -75
  3. package/dist/{actions-dtsh1mfb.js → actions-ykjkn0m9.js} +32 -30
  4. package/dist/{anthropic-messages-f2h06k64.js → anthropic-messages-5qx80j9k.js} +99 -14
  5. package/dist/{app-y1b9srva.js → app-0hdqa4k1.js} +13 -11
  6. package/dist/{assistant-31hwy5xj.js → assistant-am2g5g8a.js} +40 -32
  7. package/dist/{azure-openai-responses-0k1mfax5.js → azure-openai-responses-fszbkp0e.js} +3 -3
  8. package/dist/{boot-reembed-48d2qpkt.js → boot-reembed-gt5gjkt4.js} +14 -12
  9. package/dist/{boot-reembed-w0bryhkr.js → boot-reembed-xy9t7avg.js} +15 -13
  10. package/dist/{boot-scrub-logs-t65wbrn7.js → boot-scrub-logs-9x0985y5.js} +12 -10
  11. package/dist/boot-seeds-trv0d4vg.js +29 -0
  12. package/dist/{claude-adapter-1t6611ne.js → claude-adapter-jb6e1e54.js} +32 -26
  13. package/dist/{claude-managed-adapter-werp659j.js → claude-managed-adapter-yxkfxg8j.js} +7 -7
  14. package/dist/{claude-managed-setup-y6rdgbc1.js → claude-managed-setup-d1q9hv2b.js} +26 -27
  15. package/dist/{claude-sdk-session-zhkyk8yw.js → claude-sdk-session-zga700s2.js} +11737 -11256
  16. package/dist/{cli-79aq9cgb.js → cli-0383bp7f.js} +1222 -406
  17. package/dist/{cli-xgpf00sk.js → cli-0c7ata9h.js} +24 -23
  18. package/dist/{cli-qjxy52w7.js → cli-121ph74b.js} +2 -2
  19. package/dist/{cli-20035trh.js → cli-17xpf7cm.js} +14 -7
  20. package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
  21. package/dist/{cli-g9df2m37.js → cli-1cz0c18q.js} +249 -200
  22. package/dist/{cli-fjtp3463.js → cli-1er0rhz8.js} +13 -12
  23. package/dist/{cli-ca2w7zv7.js → cli-2hhfhfq5.js} +11 -6
  24. package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
  25. package/dist/{cli-rykfmgwg.js → cli-2x0e561b.js} +1 -1
  26. package/dist/{cli-503ya656.js → cli-35pj2yva.js} +20 -150
  27. package/dist/cli-3qhyh31j.js +166 -0
  28. package/dist/{cli-cygyqj3b.js → cli-3zc55ctx.js} +8 -6
  29. package/dist/{cli-96qd5psa.js → cli-58e8yr0d.js} +1 -1
  30. package/dist/{cli-4aj25szq.js → cli-5nbmpy8w.js} +2 -2
  31. package/dist/{cli-mg24hkt4.js → cli-5p3x4zna.js} +2 -2
  32. package/dist/{cli-vwbbaecp.js → cli-7119ja3w.js} +3 -3
  33. package/dist/{cli-mzkqpxee.js → cli-798vkbks.js} +2 -2
  34. package/dist/{cli-3gvrr8vj.js → cli-82c1pacn.js} +111 -54
  35. package/dist/{cli-hgqfttfc.js → cli-89s4ngw3.js} +1 -1
  36. package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
  37. package/dist/{cli-b6thtzac.js → cli-8g6mc14k.js} +7 -7
  38. package/dist/{cli-eg7cdg68.js → cli-9m03pzga.js} +5 -5
  39. package/dist/cli-9s68w752.js +303 -0
  40. package/dist/{cli-48527fpw.js → cli-a8c82p2t.js} +16 -15
  41. package/dist/{cli-5f2hq128.js → cli-ad4qxm6j.js} +12 -11
  42. package/dist/{cli-e4xnc0qp.js → cli-akfj32vj.js} +33 -7
  43. package/dist/{cli-ejpygnqz.js → cli-bh7jed3k.js} +212 -22
  44. package/dist/{cli-0z2v4nhw.js → cli-cat6h73s.js} +1 -1
  45. package/dist/{cli-e0ndxhtk.js → cli-cfkrztza.js} +190 -13
  46. package/dist/{cli-kc3dp84d.js → cli-d56tgd45.js} +216 -59
  47. package/dist/cli-dbmwby6a.js +9 -0
  48. package/dist/{cli-0n2e4x49.js → cli-ecfxwnyb.js} +15 -2
  49. package/dist/{cli-gzyh0j0g.js → cli-ee8bc46j.js} +66 -166
  50. package/dist/{cli-kdnehe0t.js → cli-et8m9xsv.js} +1 -1
  51. package/dist/cli-f9w1semm.js +413 -0
  52. package/dist/cli-gt4hxb8p.js +99 -0
  53. package/dist/{cli-qv4jv8bx.js → cli-hgmnf38m.js} +2 -2
  54. package/dist/{cli-10ym38qc.js → cli-hn04t9db.js} +3 -3
  55. package/dist/{cli-qvnnx4ct.js → cli-jpf7e1zq.js} +105 -243
  56. package/dist/cli-jyy6pm2f.js +333872 -0
  57. package/dist/{cli-dvjpkkjd.js → cli-kgd3p0bm.js} +7 -7
  58. package/dist/cli-ma3zvh39.js +10404 -0
  59. package/dist/{cli-r2ap2czm.js → cli-nexqx4ve.js} +6 -0
  60. package/dist/{cli-j9z8mfx3.js → cli-nsdxtcbg.js} +37 -20
  61. package/dist/{cli-wgjx0q33.js → cli-phfg8vy8.js} +392 -53
  62. package/dist/{cli-rgjprct3.js → cli-ptr8h7kp.js} +19 -1
  63. package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
  64. package/dist/{cli-bv0a38v9.js → cli-qwsnmjdd.js} +515 -229
  65. package/dist/{cli-68bmme5p.js → cli-r6fsxc76.js} +40018 -52654
  66. package/dist/{cli-rrqmqr1s.js → cli-rtx9dygp.js} +1 -1
  67. package/dist/{cli-rfezr056.js → cli-sqm3r5ps.js} +83 -15
  68. package/dist/{cli-zw65mab6.js → cli-t6v2ah3r.js} +67 -13
  69. package/dist/{cli-vn0qv9cj.js → cli-t845n9xk.js} +28 -14
  70. package/dist/cli-trc24wk2.js +143 -0
  71. package/dist/{cli-wd9hz40d.js → cli-tre4bdgq.js} +5 -5
  72. package/dist/{cli-9yg65c1j.js → cli-tsk3nz8a.js} +29 -1
  73. package/dist/{cli-phsaj4xq.js → cli-v0pvvhfq.js} +1 -1
  74. package/dist/{cli-hj65wsts.js → cli-vnnz5ncg.js} +4695 -4915
  75. package/dist/{cli-cpvsaqsw.js → cli-w0bwte75.js} +8 -5
  76. package/dist/{cli-z9x0sh1t.js → cli-we0q7t0e.js} +3 -3
  77. package/dist/{cli-r94z9p1z.js → cli-wgbezhw2.js} +3 -0
  78. package/dist/{cli-19jenss3.js → cli-xk79303e.js} +51 -17
  79. package/dist/{cli-31nkw3g3.js → cli-ybgv4kw2.js} +15 -8
  80. package/dist/{cli-ardpzhjm.js → cli-yrg7c73k.js} +13 -6
  81. package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
  82. package/dist/{cli-vhjwh6cz.js → cli-yy6dew39.js} +2 -2
  83. package/dist/{cli-bgv70kym.js → cli-zb6xbk61.js} +3 -2
  84. package/dist/{cli-4tvgz99m.js → cli-ze1d3wzv.js} +79 -27
  85. package/dist/cli.js +33 -32
  86. package/dist/{cloudflare-workers-ai-system-one-1sg586qv.js → cloudflare-workers-ai-system-one-k6fbxw9d.js} +2 -2
  87. package/dist/{codex-adapter-jqfqqa21.js → codex-adapter-04v97vep.js} +23 -20
  88. package/dist/{codex-hook-5eys3dya.js → codex-hook-20me6byw.js} +2 -2
  89. package/dist/{codex-login-he9vrn90.js → codex-login-cf7mzsgg.js} +48 -3
  90. package/dist/{codex-session-runner-zd341dsm.js → codex-session-runner-ax69mqq3.js} +21 -20
  91. package/dist/{commands-vfsysz4s.js → commands-18gy08n1.js} +12 -10
  92. package/dist/{db-s3znhvbn.js → db-d2pvjpyt.js} +22 -10
  93. package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
  94. package/dist/{dispatcher-5xn0c7rf.js → dispatcher-8wbwyzjg.js} +31 -29
  95. package/dist/{dsh-adapter-894mgfvs.js → dsh-adapter-ysqk9snv.js} +9 -4
  96. package/dist/{e2b-ez07znam.js → e2b-esmt1r16.js} +3 -1
  97. package/dist/{execute-71ysgv35.js → execute-cmagrbrz.js} +235 -52
  98. package/dist/{google-generative-ai-1nfcdphp.js → google-generative-ai-k6n5nbpp.js} +3 -3
  99. package/dist/{google-vertex-1tqcd7b1.js → google-vertex-44xxtcvp.js} +3 -3
  100. package/dist/{handlers-5w4jwycr.js → handlers-6b69m5kp.js} +34 -32
  101. package/dist/{hook-z0hbxj85.js → hook-k3mydf2n.js} +16 -14
  102. package/dist/{hook-853bxrr6.js → hook-srnkt0hb.js} +16 -14
  103. package/dist/{http-akc3wy3m.js → http-hrf80ca1.js} +836 -189
  104. package/dist/{index-ttpbhnjg.js → index-1asbaj62.js} +32 -30
  105. package/dist/{index-cd151qkq.js → index-45evq4ee.js} +31 -29
  106. package/dist/{index-k661dzzr.js → index-9rxdvj6w.js} +32 -30
  107. package/dist/index-k4nj18qs.js +31 -0
  108. package/dist/{index-5sz16ksh.js → index-xmevk2b9.js} +89 -61
  109. package/dist/{keepalive-8p9rpvz5.js → keepalive-sfdz6ksp.js} +14 -12
  110. package/dist/{lead-jp69z5h3.js → lead-ej91e9hw.js} +52 -50
  111. package/dist/{llama-cpp-classify-t2tccams.js → llama-cpp-classify-tgj35k8d.js} +1 -1
  112. package/dist/{maintenance-fwx4ev0k.js → maintenance-80dnd7ke.js} +15 -13
  113. package/dist/{mistral-conversations-bhvwqcnk.js → mistral-conversations-pc3ntnxt.js} +1 -1
  114. package/dist/node-f0ykebbv.js +2107 -0
  115. package/dist/node-wyamey5r.js +19 -0
  116. package/dist/{oauth-refresh-sweep-cwcq1ctx.js → oauth-refresh-sweep-m1etk2mx.js} +13 -11
  117. package/dist/{onboard-2b4q0t84.js → onboard-0q8sdfqc.js} +2 -2
  118. package/dist/{openai-codex-responses-nekthgks.js → openai-codex-responses-n7n683p2.js} +2 -2
  119. package/dist/{openai-completions-hxtzwj0s.js → openai-completions-jpaj5g2b.js} +2 -2
  120. package/dist/{openai-responses-w4r118w7.js → openai-responses-9a3nme9j.js} +3 -3
  121. package/dist/{opencode-adapter-zz7xvjj6.js → opencode-adapter-4wcgmvgf.js} +13 -11
  122. package/dist/{openrouter-images-b6sqqjgn.js → openrouter-images-8yx3487g.js} +1 -1
  123. package/dist/{otel-impl-g8rs4vwr.js → otel-impl-hnqm9mxq.js} +2 -2
  124. package/dist/pi-logo-animation-e9a0t68z.js +1003 -0
  125. package/dist/{pi-mono-adapter-n0me28wt.js → pi-mono-adapter-d6sqm9wr.js} +301 -78
  126. package/dist/{pricing-refresh-0v77385v.js → pricing-refresh-y60z64pm.js} +14 -13
  127. package/dist/quickjs-r1pq2107.wasm +0 -0
  128. package/dist/{rbac-roles-krjyazbj.js → rbac-roles-8pa0754b.js} +13 -11
  129. package/dist/{render-v2-3wjsp9aw.js → render-v2-418s1vj7.js} +13 -11
  130. package/dist/{runtime-ktjysacx.js → runtime-3pknc168.js} +5 -4
  131. package/dist/{setup-yeqryke6.js → setup-yghdkj4x.js} +2 -2
  132. package/dist/{typesafe-system-one-96960jxp.js → typesafe-system-one-2ef30pec.js} +2 -2
  133. package/dist/{virtual-modules-dzdeq1sf.js → virtual-modules-jcceevt5.js} +8 -6
  134. package/dist/{work-objects-3pakpkw0.js → work-objects-j1sz20v9.js} +34 -32
  135. package/dist/{worker-85testgj.js → worker-d4gcvkjt.js} +52 -50
  136. package/dist/{x-n3e0v3xa.js → x-f1gt1pz3.js} +2 -2
  137. package/openapi.json +587 -19
  138. package/package.json +16 -15
  139. package/src/azure-devops/api.ts +121 -0
  140. package/src/azure-devops/auth.ts +78 -0
  141. package/src/azure-devops/handlers.ts +413 -0
  142. package/src/azure-devops/index.ts +27 -0
  143. package/src/azure-devops/templates.ts +108 -0
  144. package/src/azure-devops/types.ts +90 -0
  145. package/src/be/db/api-keys.ts +70 -0
  146. package/src/be/db/tasks/read.ts +1 -1
  147. package/src/be/db/tasks/write.ts +16 -0
  148. package/src/be/db-client.ts +11 -2
  149. package/src/be/db-retention.ts +95 -32
  150. package/src/be/db.ts +187 -24
  151. package/src/be/memory/constants.ts +16 -0
  152. package/src/be/memory/graph-expansion.ts +8 -1
  153. package/src/be/memory/index-content.ts +20 -1
  154. package/src/be/memory/key-guard.ts +93 -0
  155. package/src/be/memory/key-paths.ts +103 -0
  156. package/src/be/memory/providers/sqlite-store.ts +203 -60
  157. package/src/be/memory/raters/llm-summarizer.ts +10 -4
  158. package/src/be/memory/raters/llm.ts +15 -5
  159. package/src/be/memory/raters/store.ts +6 -3
  160. package/src/be/memory/raters/types.ts +11 -0
  161. package/src/be/memory/reranker.ts +38 -7
  162. package/src/be/memory/types.ts +12 -1
  163. package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
  164. package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
  165. package/src/be/migrations/190_memory_rating_model.sql +7 -0
  166. package/src/be/migrations/191_context_versions_previous_index.sql +8 -0
  167. package/src/be/model-tier-keys.ts +16 -1
  168. package/src/be/model-tier-resolution.ts +63 -18
  169. package/src/be/model-validation.ts +86 -10
  170. package/src/be/pricing-normalize.ts +4 -2
  171. package/src/be/scripts/typecheck.ts +4 -3
  172. package/src/be/seed/runner.ts +18 -12
  173. package/src/be/seed/types.ts +1 -0
  174. package/src/be/seed-pricing.ts +16 -0
  175. package/src/be/seed-scripts/catalog/task-failure-audit.ts +26 -26
  176. package/src/be/swarm-config-guard.ts +13 -1
  177. package/src/commands/claude-managed-setup.ts +33 -31
  178. package/src/commands/codex-login.ts +67 -0
  179. package/src/commands/credential-outcome-report.ts +191 -0
  180. package/src/commands/provider-credentials.ts +28 -15
  181. package/src/commands/rate-limit-outcome.ts +34 -4
  182. package/src/commands/runner.ts +479 -228
  183. package/src/commands/seat-mismatch-report.ts +46 -0
  184. package/src/e2b/env.ts +2 -0
  185. package/src/extensions/apply-task-create.ts +27 -1
  186. package/src/extensions/catalog.generated.json +17 -0
  187. package/src/extensions/contract-types.generated.ts +1 -1
  188. package/src/github/handlers.ts +10 -74
  189. package/src/github/reactions.ts +119 -138
  190. package/src/github/task-reactions.ts +34 -11
  191. package/src/heartbeat/heartbeat.ts +15 -2
  192. package/src/hooks/hook.ts +1 -1
  193. package/src/http/agents.ts +15 -2
  194. package/src/http/api-keys.ts +140 -2
  195. package/src/http/codex-oauth-keep-warm.ts +3 -5
  196. package/src/http/core.ts +12 -0
  197. package/src/http/extensions.ts +51 -27
  198. package/src/http/index.ts +4 -0
  199. package/src/http/mcp-user.ts +8 -13
  200. package/src/http/mcp.ts +19 -12
  201. package/src/http/memory.ts +91 -18
  202. package/src/http/poll.ts +9 -1
  203. package/src/http/schedules.ts +17 -2
  204. package/src/http/script-runs.ts +12 -0
  205. package/src/http/session-data.ts +6 -4
  206. package/src/http/stats.ts +1 -0
  207. package/src/http/status.ts +15 -1
  208. package/src/http/tasks.ts +80 -8
  209. package/src/http/users.ts +1 -1
  210. package/src/http/webhooks.ts +120 -2
  211. package/src/http/workflows.ts +11 -0
  212. package/src/mcp-client/http-client.ts +5 -0
  213. package/src/memory/recall-query.ts +74 -0
  214. package/src/prompts/base-prompt.ts +15 -4
  215. package/src/prompts/session-templates.ts +22 -1
  216. package/src/providers/acp-adapter.ts +1 -0
  217. package/src/providers/claude-adapter.ts +98 -21
  218. package/src/providers/claude-managed-adapter.ts +30 -2
  219. package/src/providers/claude-sdk-session.ts +3 -1
  220. package/src/providers/codex-adapter.ts +11 -11
  221. package/src/providers/codex-skill-resolver.ts +6 -0
  222. package/src/providers/devin-adapter.ts +1 -0
  223. package/src/providers/dsh-adapter.ts +205 -7
  224. package/src/providers/harness-version.ts +83 -7
  225. package/src/providers/opencode-adapter.ts +77 -4
  226. package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
  227. package/src/providers/pi-codemode-runtime.ts +17 -0
  228. package/src/providers/pi-mono-adapter.ts +387 -83
  229. package/src/providers/pi-mono-extension.ts +17 -2
  230. package/src/providers/pricing-sources.md +5 -1
  231. package/src/providers/reasoning-effort.ts +10 -2
  232. package/src/providers/types.ts +9 -1
  233. package/src/rbac/legacy-policy.ts +20 -0
  234. package/src/rbac/permissions.ts +15 -0
  235. package/src/scripts-runtime/types/stdlib.d.ts +13 -5
  236. package/src/scripts-runtime/types/swarm-extension.d.ts +4 -2
  237. package/src/scripts-runtime/types/swarm-sdk.d.ts +13 -5
  238. package/src/slack/assistant.ts +13 -0
  239. package/src/slack/render-v2.ts +87 -37
  240. package/src/slack/session-status.ts +541 -0
  241. package/src/tasks/context-key.ts +38 -1
  242. package/src/tasks/sibling-awareness.ts +3 -2
  243. package/src/telemetry.ts +5 -4
  244. package/src/templates.d.ts +6 -0
  245. package/src/tests/api-key-auth-failure-route.test.ts +142 -0
  246. package/src/tests/api-key-tracking.test.ts +368 -1
  247. package/src/tests/azure-devops-auth.test.ts +100 -0
  248. package/src/tests/azure-devops-handlers.test.ts +324 -0
  249. package/src/tests/azure-devops-webhook-malformed.test.ts +96 -0
  250. package/src/tests/base-prompt.test.ts +40 -2
  251. package/src/tests/claude-adapter.test.ts +58 -0
  252. package/src/tests/claude-default-route.test.ts +260 -0
  253. package/src/tests/claude-managed-adapter.test.ts +47 -0
  254. package/src/tests/claude-managed-setup.test.ts +48 -0
  255. package/src/tests/claude-prompt-body-once.test.ts +117 -0
  256. package/src/tests/claude-routes-e2e.test.ts +316 -0
  257. package/src/tests/codex-auth-failure.test.ts +52 -0
  258. package/src/tests/codex-login.test.ts +116 -0
  259. package/src/tests/context-versions-retention.test.ts +314 -0
  260. package/src/tests/core-auth.test.ts +7 -0
  261. package/src/tests/credential-exhaustion-policy.test.ts +118 -3
  262. package/src/tests/credential-outcome-report.test.ts +171 -0
  263. package/src/tests/credential-status-api.test.ts +103 -2
  264. package/src/tests/db-retention.test.ts +14 -14
  265. package/src/tests/db-task-read-contract.test.ts +6 -0
  266. package/src/tests/db-task-write-contract.test.ts +533 -1
  267. package/src/tests/docs-index-footprint.test.js +3 -3
  268. package/src/tests/dokploy-deploy.test.ts +315 -0
  269. package/src/tests/dsh-adapter.test.ts +134 -2
  270. package/src/tests/dsh-usage.test.ts +153 -0
  271. package/src/tests/explicit-model-validation.test.ts +253 -2
  272. package/src/tests/extensions-catalog.test.ts +1 -0
  273. package/src/tests/extensions-example-deploy-awareness.test.ts +301 -0
  274. package/src/tests/extensions-http.test.ts +137 -10
  275. package/src/tests/extensions-mcp-tools.test.ts +28 -0
  276. package/src/tests/extensions-pre-task.test.ts +73 -0
  277. package/src/tests/fetch-resolved-env.test.ts +70 -0
  278. package/src/tests/fixtures/azure-devops/pull-request-commented.json +129 -0
  279. package/src/tests/fixtures/azure-devops/pull-request-created.json +88 -0
  280. package/src/tests/fixtures/fake-claude-routes.ts +229 -0
  281. package/src/tests/github-handlers-reactions.test.ts +486 -0
  282. package/src/tests/github-reactions.test.ts +280 -0
  283. package/src/tests/hang-watchdog-worker.ts +47 -0
  284. package/src/tests/hang-watchdog.test.ts +45 -0
  285. package/src/tests/hang-watchdog.ts +30 -0
  286. package/src/tests/harness-cli-version.test.ts +62 -0
  287. package/src/tests/harness-model-guard.test.ts +123 -0
  288. package/src/tests/harness-version.test.ts +70 -3
  289. package/src/tests/http-api-integration.test.ts +21 -0
  290. package/src/tests/http-task-write-ownership.test.ts +195 -0
  291. package/src/tests/internal-ai/complete-structured.test.ts +94 -0
  292. package/src/tests/internal-ai/credentials.test.ts +22 -0
  293. package/src/tests/internal-ai/models.test.ts +36 -2
  294. package/src/tests/internal-ai/schema-parity.test.ts +25 -1
  295. package/src/tests/internal-ai/summarize-session.test.ts +23 -7
  296. package/src/tests/mcp-user-route.test.ts +133 -0
  297. package/src/tests/memory-fts-populate.test.ts +139 -0
  298. package/src/tests/memory-http-recall-gating.test.ts +125 -1
  299. package/src/tests/memory-key-paths.test.ts +1055 -0
  300. package/src/tests/memory-rate-endpoint.test.ts +66 -0
  301. package/src/tests/memory-rater-llm-summarizer.test.ts +2 -1
  302. package/src/tests/memory-rater-llm.test.ts +73 -0
  303. package/src/tests/memory-rater-store.test.ts +31 -0
  304. package/src/tests/memory-reranker.test.ts +40 -0
  305. package/src/tests/model-rate-limit-windows.test.ts +19 -0
  306. package/src/tests/model-tier-resolution.test.ts +92 -0
  307. package/src/tests/opencode-adapter.test.ts +214 -2
  308. package/src/tests/opencode-plugin.test.ts +4 -0
  309. package/src/tests/pi-codemode.test.ts +324 -0
  310. package/src/tests/pi-mono-adapter.test.ts +3 -0
  311. package/src/tests/pi-native-mcp.test.ts +193 -0
  312. package/src/tests/pi-tool-exposure.test.ts +374 -0
  313. package/src/tests/preload.ts +9 -0
  314. package/src/tests/prompt-template-session.test.ts +5 -3
  315. package/src/tests/provider-registration.test.ts +0 -2
  316. package/src/tests/providers/pi-cost.test.ts +190 -4
  317. package/src/tests/rate-limit-event.test.ts +65 -0
  318. package/src/tests/rate-limit-outcome.test.ts +90 -0
  319. package/src/tests/rbac-engine.test.ts +41 -2
  320. package/src/tests/runner-key-completion-outcome.test.ts +112 -0
  321. package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
  322. package/src/tests/runner-registration-retry.test.ts +149 -0
  323. package/src/tests/runner-slot-reconcile.test.ts +199 -0
  324. package/src/tests/script-connections.test.ts +8 -0
  325. package/src/tests/seat-mismatch-report.test.ts +85 -0
  326. package/src/tests/seed-scripts.test.ts +49 -0
  327. package/src/tests/seed.test.ts +25 -0
  328. package/src/tests/session-costs-recompute-all-providers.test.ts +23 -0
  329. package/src/tests/slack-render-v2.test.ts +96 -0
  330. package/src/tests/slack-session-status.test.ts +626 -0
  331. package/src/tests/status.test.ts +29 -0
  332. package/src/tests/steering-promotion.test.ts +51 -0
  333. package/src/tests/store-progress-ownership.test.ts +136 -0
  334. package/src/tests/subscription-plans.test.ts +28 -0
  335. package/src/tests/task-citations.test.ts +3 -2
  336. package/src/tests/task-reactions.test.ts +29 -6
  337. package/src/tests/vcs-azure-devops.test.ts +73 -0
  338. package/src/tests/webhooks-task-blocked.test.ts +23 -0
  339. package/src/tests/workflow-agent-task.test.ts +30 -0
  340. package/src/tests/workflow-llm.test.ts +14 -0
  341. package/src/tests/workflow-triggers-v2.test.ts +320 -0
  342. package/src/tools/context-diff.ts +20 -0
  343. package/src/tools/extension-install.ts +27 -16
  344. package/src/tools/memory-edit.ts +47 -3
  345. package/src/tools/memory-search.ts +13 -1
  346. package/src/tools/memory-store.ts +55 -3
  347. package/src/tools/schedules/create-schedule.ts +1 -1
  348. package/src/tools/schedules/patch-schedule.ts +16 -3
  349. package/src/tools/schedules/update-schedule.ts +16 -3
  350. package/src/tools/send-task.ts +10 -7
  351. package/src/tools/store-progress.ts +49 -4
  352. package/src/tools/task-action.ts +2 -1
  353. package/src/tools/workflows/create-workflow.ts +8 -2
  354. package/src/tools/workflows/update-workflow.ts +8 -2
  355. package/src/types.ts +54 -7
  356. package/src/utils/codex-auth-failure.ts +34 -0
  357. package/src/utils/credentials.test.ts +31 -1
  358. package/src/utils/credentials.ts +92 -39
  359. package/src/utils/dsh-usage.ts +53 -0
  360. package/src/utils/error-tracker.ts +80 -0
  361. package/src/utils/harness-cli-version.ts +6 -4
  362. package/src/utils/internal-ai/complete-structured.ts +26 -3
  363. package/src/utils/internal-ai/credentials.ts +23 -9
  364. package/src/utils/internal-ai/index.ts +8 -1
  365. package/src/utils/internal-ai/models.ts +34 -8
  366. package/src/utils/internal-ai/summarize-session.ts +22 -8
  367. package/src/utils/model-rate-limit-windows.ts +12 -0
  368. package/src/utils/runtime-model-catalog.ts +15 -0
  369. package/src/utils/secret-scrubber.ts +8 -0
  370. package/src/utils/spawn-model-guard.ts +43 -0
  371. package/src/utils/subscription-plans.ts +22 -0
  372. package/src/vcs/azure-devops.ts +80 -0
  373. package/src/vcs/index.ts +5 -1
  374. package/src/vcs/types.ts +2 -2
  375. package/src/workflows/executors/agent-task.ts +7 -6
  376. package/src/workflows/model-validation.ts +45 -0
  377. package/src/workflows/patch-definition.ts +5 -0
  378. package/src/workflows/triggers.ts +85 -0
  379. package/templates/community/open-prompt-showreel/PLAYBOOK.md +336 -0
  380. package/templates/community/open-prompt-showreel/README.md +33 -0
  381. package/templates/community/open-prompt-showreel/example/tla-races/facts.ts +145 -0
  382. package/templates/community/open-prompt-showreel/example/tla-races/facts.v3.json +140 -0
  383. package/templates/community/open-prompt-showreel/example/tla-races/music.mist-city.json +8 -0
  384. package/templates/community/open-prompt-showreel/example/tla-races/reel.html +805 -0
  385. package/templates/community/open-prompt-showreel/example/tla-races/smoke.sh +48 -0
  386. package/templates/community/open-prompt-showreel/lead-prompt.md +89 -0
  387. package/templates/community/open-prompt-showreel/setup.sh +167 -0
  388. package/templates/community/open-prompt-showreel/skills/motion-design-replication/SKILL.md +85 -0
  389. package/templates/community/open-prompt-showreel/skills/motion-design-video-analysis/SKILL.md +115 -0
  390. package/templates/community/open-prompt-showreel/skills/open-prompt-showreel/SKILL.md +147 -0
  391. package/templates/community/open-prompt-showreel/skills/video-generation/SKILL.md +195 -0
  392. package/templates/community/open-prompt-showreel/tools/fetch-music.sh +65 -0
  393. package/templates/community/open-prompt-showreel/tools/music-analyze.py +69 -0
  394. package/templates/community/open-prompt-showreel/tools/music-current.sh +34 -0
  395. package/templates/community/open-prompt-showreel/tools/music-cut.sh +36 -0
  396. package/templates/community/open-prompt-showreel/tools/music-refine.py +39 -0
  397. package/templates/community/open-prompt-showreel/tools/render.mjs +157 -0
  398. package/templates/community/open-prompt-showreel/tools/sheet.sh +44 -0
  399. package/templates/community/open-prompt-showreel/tools/web-compress.sh +17 -0
  400. package/templates/community/open-prompt-showreel/tools/x-reencode.sh +21 -0
  401. package/templates/extensions/README.md +1 -0
  402. package/templates/extensions/deploy-awareness/README.md +28 -0
  403. package/templates/extensions/deploy-awareness/hooks.ts +152 -0
  404. package/templates/extensions/deploy-awareness/manifest.json +8 -0
  405. package/templates/skills/memory/config.json +2 -2
  406. package/templates/skills/memory/content.md +59 -5
  407. package/templates/skills/swarm-extensions/config.json +1 -1
  408. package/templates/skills/swarm-extensions/content.md +28 -5
  409. package/templates/skills/workflow-iterate/content.md +1 -0
  410. package/dist/boot-seeds-h7c32hvm.js +0 -27
  411. package/dist/cli-2djtr51b.js +0 -48
  412. package/dist/cli-7zttzetj.js +0 -324
  413. package/dist/cli-j490egb5.js +0 -5632
  414. package/dist/cli-m4excttz.js +0 -333481
  415. package/dist/index-bjmjh9h4.js +0 -29
@@ -2,33 +2,16 @@ import {
2
2
  COMPOSIO_HTTP_METHODS,
3
3
  composioArgsFromParts,
4
4
  executeComposioRequest
5
- } from "./cli-0z2v4nhw.js";
5
+ } from "./cli-cat6h73s.js";
6
6
  import {
7
7
  LlmRater,
8
8
  REFERENCES_SOURCE_MAX_LENGTH,
9
9
  getMemoryRaterNames,
10
10
  sanitizeReferencesSource
11
- } from "./cli-cpvsaqsw.js";
11
+ } from "./cli-w0bwte75.js";
12
12
  import {
13
13
  isMultiRuntimeEnabled
14
14
  } from "./cli-re8z5p8p.js";
15
- import {
16
- AgentFsProvider,
17
- getFileStorageProvider,
18
- providerPath
19
- } from "./cli-jsp14b6c.js";
20
- import {
21
- ensurePricingSeeded,
22
- ensureRbacSeeded,
23
- getUserGrant
24
- } from "./cli-z9x0sh1t.js";
25
- import {
26
- can,
27
- decideAdmission,
28
- grantLeadEquivalence,
29
- isRbacEnabled,
30
- revokeLeadEquivalence
31
- } from "./cli-9yg65c1j.js";
32
15
  import {
33
16
  buildCatalogEntries,
34
17
  getCatalogGeneration,
@@ -38,10 +21,7 @@ import {
38
21
  requestModelCatalogRefresh,
39
22
  startPricingRefreshLoop,
40
23
  upsertModelCatalogOverlay
41
- } from "./cli-cygyqj3b.js";
42
- import {
43
- loadModelsDevCache
44
- } from "./cli-0n2e4x49.js";
24
+ } from "./cli-3zc55ctx.js";
45
25
  import {
46
26
  AppDefinitionSchema,
47
27
  AppElementsSchema,
@@ -121,7 +101,7 @@ import {
121
101
  validateDefinition,
122
102
  validateScriptImports,
123
103
  writeBareImportShim
124
- } from "./cli-fjtp3463.js";
104
+ } from "./cli-1er0rhz8.js";
125
105
  import {
126
106
  detachedProcessGroup,
127
107
  registerProcessGroup,
@@ -130,9 +110,14 @@ import {
130
110
  import {
131
111
  getApiKey
132
112
  } from "./cli-f14fvzag.js";
113
+ import {
114
+ AgentFsProvider,
115
+ getFileStorageProvider,
116
+ providerPath
117
+ } from "./cli-jsp14b6c.js";
133
118
  import {
134
119
  embedScript
135
- } from "./cli-vwbbaecp.js";
120
+ } from "./cli-7119ja3w.js";
136
121
  import {
137
122
  buildAuthorizationUrl,
138
123
  createOAuthApp,
@@ -147,23 +132,48 @@ import {
147
132
  listAuthorizationsForApp,
148
133
  onAuthorizationRefreshed,
149
134
  upsertOAuthApp
150
- } from "./cli-qv4jv8bx.js";
135
+ } from "./cli-hgmnf38m.js";
136
+ import {
137
+ ensurePricingSeeded,
138
+ ensureRbacSeeded,
139
+ getUserGrant
140
+ } from "./cli-we0q7t0e.js";
141
+ import {
142
+ can,
143
+ decideAdmission,
144
+ grantLeadEquivalence,
145
+ isRbacEnabled,
146
+ revokeLeadEquivalence
147
+ } from "./cli-tsk3nz8a.js";
148
+ import {
149
+ loadModelsDevCache
150
+ } from "./cli-ecfxwnyb.js";
151
151
  import {
152
152
  ZodFirstPartyTypeKind,
153
153
  objectType
154
154
  } from "./cli-fad8m16k.js";
155
155
  import {
156
156
  CANDIDATE_SET_MULTIPLIER,
157
+ LONGTERM_ROOT,
158
+ MEMORY_KEY_MAX_LENGTH,
159
+ MEMORY_KEY_PATTERN,
160
+ MEMORY_KEY_PATTERN_MESSAGE,
157
161
  computeScore,
162
+ consolidatedKeyMessage,
158
163
  getEmbeddingProvider,
159
164
  getMemoryStore,
160
165
  init_constants as init_constants2,
166
+ init_key_paths,
161
167
  init_reranker,
162
168
  init_sqlite_store,
169
+ isConsolidatedKey,
163
170
  isGraphExpansionEnabled,
171
+ isLongtermKey,
172
+ longtermKeyError,
164
173
  rerank,
174
+ resolveStoreKey,
165
175
  rowToCandidate
166
- } from "./cli-kc3dp84d.js";
176
+ } from "./cli-d56tgd45.js";
167
177
  import {
168
178
  require_dist
169
179
  } from "./cli-51tf7ac3.js";
@@ -189,7 +199,7 @@ import {
189
199
  taskCitationWarnings,
190
200
  upsertTaskCitations,
191
201
  withSpan
192
- } from "./cli-wgjx0q33.js";
202
+ } from "./cli-phfg8vy8.js";
193
203
  import {
194
204
  init_task_attachment_links,
195
205
  taskAttachmentDisplayUrl,
@@ -204,6 +214,7 @@ import {
204
214
  acceptTask,
205
215
  agentContextKey,
206
216
  agentmailContextKey,
217
+ azureDevOpsContextKey,
207
218
  beginRequestAuthScope,
208
219
  buildJiraContextKey,
209
220
  buildRoutingAffinityFromAgent,
@@ -458,7 +469,7 @@ import {
458
469
  upsertSwarmConfig,
459
470
  validateConfigValue,
460
471
  workflowContextKey
461
- } from "./cli-g9df2m37.js";
472
+ } from "./cli-1cz0c18q.js";
462
473
  import {
463
474
  $OpenAPIRegistry,
464
475
  $OpenApiGeneratorV31,
@@ -505,6 +516,7 @@ import {
505
516
  WorkflowNodePatchSchema,
506
517
  WorkflowRunStatusSchema,
507
518
  canWriteAssetKey,
519
+ checkExtensionInstallSource,
508
520
  init_bundle_path,
509
521
  init_dist,
510
522
  init_key,
@@ -516,18 +528,13 @@ import {
516
528
  parseAssetKey,
517
529
  parseModelTier,
518
530
  splitLegacyModelAlias
519
- } from "./cli-e4xnc0qp.js";
531
+ } from "./cli-akfj32vj.js";
520
532
  import {
521
533
  generateDefaultClaudeMd,
522
534
  generateDefaultIdentityMd,
523
535
  generateDefaultSoulMd,
524
536
  init_defaults
525
- } from "./cli-ardpzhjm.js";
526
- import {
527
- getSlackConfiguration,
528
- init_config,
529
- isSlackConfigured
530
- } from "./cli-n7h1kqpf.js";
537
+ } from "./cli-yrg7c73k.js";
531
538
  import {
532
539
  deepInterpolate,
533
540
  findInterpolationTokens,
@@ -538,7 +545,12 @@ import {
538
545
  interpolate,
539
546
  registerTemplate,
540
547
  resolveTemplate
541
- } from "./cli-rgjprct3.js";
548
+ } from "./cli-ptr8h7kp.js";
549
+ import {
550
+ getSlackConfiguration,
551
+ init_config,
552
+ isSlackConfigured
553
+ } from "./cli-n7h1kqpf.js";
542
554
  import {
543
555
  MAX_PROFILE_FILE_LENGTH,
544
556
  getAppUrl,
@@ -556,12 +568,13 @@ import {
556
568
  claudeCatalogModelId,
557
569
  harnessCatalogSection,
558
570
  harnessModelIds,
571
+ harnessModelMismatch,
559
572
  init_src,
560
573
  isAlias,
561
574
  modelFamilyKey,
562
575
  parseAlias,
563
576
  resolveAlias
564
- } from "./cli-7zttzetj.js";
577
+ } from "./cli-jyy6pm2f.js";
565
578
  import {
566
579
  exports_zod,
567
580
  init_zod
@@ -610,7 +623,7 @@ import {
610
623
  import {
611
624
  init_package,
612
625
  package_default
613
- } from "./cli-48527fpw.js";
626
+ } from "./cli-a8c82p2t.js";
614
627
  import {
615
628
  init_secret_scrubber,
616
629
  isSensitiveKey,
@@ -618,7 +631,7 @@ import {
618
631
  registerVolatileSecret,
619
632
  scrubObject,
620
633
  scrubSecrets
621
- } from "./cli-r2ap2czm.js";
634
+ } from "./cli-nexqx4ve.js";
622
635
  import {
623
636
  init_event_bus,
624
637
  workflowEventBus
@@ -14349,7 +14362,7 @@ async function notifyAutomationPreflightFailure(preflight) {
14349
14362
  return;
14350
14363
  }
14351
14364
  try {
14352
- const { getSlackApp: getSlackApp2 } = await import("./app-y1b9srva.js");
14365
+ const { getSlackApp: getSlackApp2 } = await import("./app-0hdqa4k1.js");
14353
14366
  const app = getSlackApp2();
14354
14367
  if (!app) {
14355
14368
  console.warn("[Automation Preflight] Slack not available, cannot send notification");
@@ -17093,6 +17106,23 @@ async function verifyWebhookRequest(trigger, rawBody, headers) {
17093
17106
  }
17094
17107
  return;
17095
17108
  }
17109
+ if (verification.format === "standard-webhooks") {
17110
+ const key = decodeStandardWebhookSecret(secret);
17111
+ if (!key) {
17112
+ throw new WebhookError("Webhook trigger `standard-webhooks` secret must be base64 (optionally prefixed with `whsec_`)", 500);
17113
+ }
17114
+ const id = getHeader(headers, "webhook-id");
17115
+ const timestamp = getHeader(headers, "webhook-timestamp");
17116
+ const signature2 = getHeader(headers, "webhook-signature");
17117
+ if (!id || !timestamp || !signature2) {
17118
+ throw new WebhookError("Missing signature", 401);
17119
+ }
17120
+ const isValid2 = verifyStandardWebhookSignature(key, rawBody, { id, timestamp, signature: signature2 }, { toleranceSeconds: verification.toleranceSeconds });
17121
+ if (!isValid2) {
17122
+ throw new WebhookError("Invalid signature", 401);
17123
+ }
17124
+ return;
17125
+ }
17096
17126
  const header = verification.header || DEFAULT_HMAC_HEADER;
17097
17127
  const signature = getHeader(headers, header);
17098
17128
  if (!signature) {
@@ -17226,6 +17256,36 @@ function verifyTimestampedHmacSignature(secret, body, headerValue, opts = {}, no
17226
17256
  const expected = Buffer.from(expectedHex, "hex");
17227
17257
  return signatures.some((signature) => timingSafeEqualHex(signature, expected));
17228
17258
  }
17259
+ var STANDARD_WEBHOOK_SECRET_PREFIX = "whsec_";
17260
+ function decodeStandardWebhookSecret(secret) {
17261
+ const encoded = secret.startsWith(STANDARD_WEBHOOK_SECRET_PREFIX) ? secret.slice(STANDARD_WEBHOOK_SECRET_PREFIX.length) : secret;
17262
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(encoded) || encoded.length % 4 === 1) {
17263
+ return null;
17264
+ }
17265
+ const key = Buffer.from(encoded, "base64");
17266
+ return key.length > 0 ? key : null;
17267
+ }
17268
+ function verifyStandardWebhookSignature(key, body, headers, opts = {}, nowMs = Date.now()) {
17269
+ const toleranceSeconds = opts.toleranceSeconds ?? 300;
17270
+ if (!/^\d+$/.test(headers.timestamp)) {
17271
+ return false;
17272
+ }
17273
+ const timestampSeconds = Number(headers.timestamp);
17274
+ if (!Number.isSafeInteger(timestampSeconds)) {
17275
+ return false;
17276
+ }
17277
+ if (Math.abs(nowMs / 1000 - timestampSeconds) > toleranceSeconds) {
17278
+ return false;
17279
+ }
17280
+ const expected = Buffer.from(crypto2.createHmac("sha256", key).update(`${headers.id}.${headers.timestamp}.${body}`).digest("base64"));
17281
+ return headers.signature.split(" ").some((entry) => {
17282
+ const separatorIndex = entry.indexOf(",");
17283
+ if (separatorIndex <= 0 || entry.slice(0, separatorIndex) !== "v1")
17284
+ return false;
17285
+ const provided = Buffer.from(entry.slice(separatorIndex + 1));
17286
+ return provided.length === expected.length && crypto2.timingSafeEqual(provided, expected);
17287
+ });
17288
+ }
17229
17289
  function verifyTokenEquality(secret, providedToken) {
17230
17290
  const secretDigest = crypto2.createHash("sha256").update(secret).digest();
17231
17291
  const providedDigest = crypto2.createHash("sha256").update(providedToken).digest();
@@ -17601,22 +17661,45 @@ function taskModelCandidates(input) {
17601
17661
  }
17602
17662
  return candidates;
17603
17663
  }
17664
+ function harnessMismatchReason(model, harness) {
17665
+ return `[model-harness-mismatch] Model "${model}" does not run on the ${harness} harness of this worker. The task pinned a model from another harness family. Re-create the task with modelTier or with a ${harness} model.`;
17666
+ }
17604
17667
  async function resolveTaskModel(input) {
17668
+ const harness = input.harnessProvider ?? null;
17669
+ const judged = harness !== null && harnessCatalogSection(harness) !== null;
17670
+ const sections = judged ? (await loadResolutionCatalog()).catalog : {};
17605
17671
  for (const candidate of taskModelCandidates(input)) {
17672
+ let resolution = null;
17606
17673
  if (!isAlias(candidate.value)) {
17607
- return { resolvedModel: candidate.value, modelSource: candidate.source, modelAlias: null };
17608
- }
17609
- const resolved = await resolveLatestAlias(candidate.value, input.now, {
17610
- record: input.record
17611
- });
17612
- if (resolved) {
17613
- return {
17614
- resolvedModel: resolved,
17674
+ resolution = {
17675
+ resolvedModel: candidate.value,
17615
17676
  modelSource: candidate.source,
17616
- modelAlias: candidate.value.trim().toLowerCase()
17677
+ modelAlias: null
17617
17678
  };
17679
+ } else {
17680
+ const resolved = await resolveLatestAlias(candidate.value, input.now, {
17681
+ record: input.record
17682
+ });
17683
+ if (resolved) {
17684
+ resolution = {
17685
+ resolvedModel: resolved,
17686
+ modelSource: candidate.source,
17687
+ modelAlias: candidate.value.trim().toLowerCase()
17688
+ };
17689
+ }
17618
17690
  }
17619
- console.warn(`[model-tiers] ${candidate.source} alias ${candidate.value} resolved to nothing; trying next layer`);
17691
+ if (!resolution) {
17692
+ console.warn(`[model-tiers] ${candidate.source} alias ${candidate.value} resolved to nothing; trying next layer`);
17693
+ continue;
17694
+ }
17695
+ if (judged && harnessModelMismatch(resolution.resolvedModel, harness, sections)) {
17696
+ if (candidate.source === "model") {
17697
+ return { harnessMismatch: harnessMismatchReason(candidate.value, harness) };
17698
+ }
17699
+ console.warn(`[model-tiers] ${candidate.source} value ${candidate.value} does not run on ${harness}; trying next layer`);
17700
+ continue;
17701
+ }
17702
+ return resolution;
17620
17703
  }
17621
17704
  return null;
17622
17705
  }
@@ -17636,15 +17719,16 @@ async function previewModelTiers(opts = {}) {
17636
17719
  now: opts.now,
17637
17720
  record: false
17638
17721
  });
17722
+ const previewed = resolution && "harnessMismatch" in resolution ? null : resolution;
17639
17723
  rows.push({
17640
17724
  provider,
17641
17725
  tier,
17642
17726
  key,
17643
17727
  defaultValue: DEFAULT_MODEL_TIER_MAP[provider][tier],
17644
17728
  configured,
17645
- source: resolution?.modelSource === "tier-config" ? "tier-config" : "tier-default",
17646
- resolvedModel: resolution?.resolvedModel ?? null,
17647
- alias: resolution?.modelAlias ?? null
17729
+ source: previewed?.modelSource === "tier-config" ? "tier-config" : "tier-default",
17730
+ resolvedModel: previewed?.resolvedModel ?? null,
17731
+ alias: previewed?.modelAlias ?? null
17648
17732
  });
17649
17733
  }
17650
17734
  }
@@ -17678,6 +17762,8 @@ async function recordClaimModelResolution(task, agent) {
17678
17762
  });
17679
17763
  if (!resolved)
17680
17764
  return {};
17765
+ if ("harnessMismatch" in resolved)
17766
+ return { modelUnsupported: resolved.harnessMismatch };
17681
17767
  const checked = await applyCliSupport(resolved, harnessProvider, await getAgentHarnessCliVersion(agent.id));
17682
17768
  if ("unsupported" in checked) {
17683
17769
  return { modelUnsupported: checked.unsupported };
@@ -17716,12 +17802,31 @@ function isKnownCatalogModel(model, catalog) {
17716
17802
  const anthropic = catalog.anthropic?.models;
17717
17803
  return Object.hasOwn(buildClaudeShortnameMap(anthropic), id);
17718
17804
  }
17805
+ async function harnessModelErrorFor(model, harness) {
17806
+ const { providers } = await loadModelsCatalog();
17807
+ return harnessModelMismatch(model, harness, providers, {});
17808
+ }
17809
+ async function poolTaskRunsOnHarness(task, harness) {
17810
+ const model = task?.model?.trim();
17811
+ if (!model)
17812
+ return true;
17813
+ return await harnessModelErrorFor(model, harness) === null;
17814
+ }
17719
17815
  async function explicitModelError(check) {
17720
17816
  const model = check.model?.trim();
17721
- if (!model || check.allowCustomModel)
17817
+ if (!model)
17722
17818
  return null;
17723
17819
  if (check.harnessProvider && FREE_FORM_HARNESSES.has(check.harnessProvider))
17724
17820
  return null;
17821
+ const { providers } = await loadModelsCatalog();
17822
+ const catalog = providers;
17823
+ if (check.harnessProvider) {
17824
+ const mismatch = harnessModelMismatch(model, check.harnessProvider, catalog, { agentId: check.agentId, agentName: check.agentName });
17825
+ if (mismatch)
17826
+ return mismatch;
17827
+ }
17828
+ if (check.allowCustomModel)
17829
+ return null;
17725
17830
  if (isAlias(model)) {
17726
17831
  if (!parseAlias(model)) {
17727
17832
  return `Invalid model alias "${model}". Use latest:<provider>/<family>[@stable|@any], e.g. latest:anthropic/opus.`;
@@ -17729,8 +17834,6 @@ async function explicitModelError(check) {
17729
17834
  const resolved = await resolveLatestAlias(model, new Date, { record: false });
17730
17835
  return resolved ? null : `Model alias "${model}" matches no model in the catalog. Check the provider and family, or use a concrete model id.`;
17731
17836
  }
17732
- const { providers } = await loadModelsCatalog();
17733
- const catalog = providers;
17734
17837
  if (Object.keys(catalog).length === 0)
17735
17838
  return null;
17736
17839
  if (isKnownCatalogModel(model, catalog))
@@ -17738,10 +17841,40 @@ async function explicitModelError(check) {
17738
17841
  return `Unknown model "${model}": it is not in the model catalog. Use a catalog model id, a Claude CLI shortname (opus, sonnet, haiku, fable), a latest:<provider>/<family> alias, or modelTier. To run a custom model id anyway, set allowCustomModel: true (allow_custom_model on the agent runtime).`;
17739
17842
  }
17740
17843
  async function explicitModelErrorForAgent(check) {
17741
- if (!check.model?.trim() || check.allowCustomModel)
17844
+ const model = check.model?.trim();
17845
+ if (!model)
17742
17846
  return null;
17743
17847
  const agent = check.agentId ? await getAgentById(check.agentId) : null;
17744
- return explicitModelError({ ...check, harnessProvider: agent?.harnessProvider ?? null });
17848
+ if (agent) {
17849
+ return explicitModelError({
17850
+ ...check,
17851
+ agentId: agent.id,
17852
+ agentName: agent.name,
17853
+ harnessProvider: agent.harnessProvider ?? agent.provider ?? null
17854
+ });
17855
+ }
17856
+ if (!check.agentId && !isAlias(model)) {
17857
+ const poolError = await poolHarnessModelError(model);
17858
+ if (poolError)
17859
+ return poolError;
17860
+ }
17861
+ return explicitModelError({ ...check, harnessProvider: null });
17862
+ }
17863
+ async function poolHarnessModelError(model) {
17864
+ const agents = await getAllAgents({ slim: true });
17865
+ if (agents.length === 0)
17866
+ return null;
17867
+ const { providers } = await loadModelsCatalog();
17868
+ const sections = providers;
17869
+ const harnesses = new Set;
17870
+ for (const agent of agents) {
17871
+ const harness = agent.harnessProvider ?? agent.provider ?? null;
17872
+ if (!harnessModelMismatch(model, harness, sections))
17873
+ return null;
17874
+ if (harness)
17875
+ harnesses.add(harness);
17876
+ }
17877
+ return `Model "${model}" does not run on any registered agent harness (${[...harnesses].sort().join(", ")}). Use modelTier (smol, regular, smart, ultra) for portable intent, or omit model and let the claiming agent resolve it.`;
17745
17878
  }
17746
17879
 
17747
17880
  // src/extensions/apply-task-create.ts
@@ -17969,7 +18102,8 @@ async function prepareTaskWithSiblingAwareness(description, options, args = {})
17969
18102
  const preCreate = await applyPreTaskCreate({
17970
18103
  description,
17971
18104
  options,
17972
- origin: args.origin ?? "rest"
18105
+ origin: args.origin ?? "rest",
18106
+ allowCustomModel: args.allowCustomModel
17973
18107
  });
17974
18108
  if (preCreate.kind === "blocked") {
17975
18109
  throw new TaskCreationBlockedError(preCreate.reason, preCreate.extension);
@@ -24030,6 +24164,10 @@ init_steering();
24030
24164
 
24031
24165
  // src/github/task-reactions.ts
24032
24166
  init_task_lifecycle_events();
24167
+ init_secret_scrubber();
24168
+
24169
+ // src/github/reactions.ts
24170
+ init_secret_scrubber();
24033
24171
 
24034
24172
  // src/github/app.ts
24035
24173
  var initialized = false;
@@ -24181,18 +24319,25 @@ async function getInstallationToken(installationId) {
24181
24319
  }
24182
24320
 
24183
24321
  // src/github/reactions.ts
24184
- async function addReaction(repo, commentId, reaction, installationId) {
24185
- if (!isReactionsEnabled()) {
24186
- console.log("[GitHub] Reactions not enabled, skipping");
24187
- return false;
24188
- }
24189
- const token = await getInstallationToken(installationId);
24190
- if (!token) {
24191
- console.log("[GitHub] No installation token, skipping reaction");
24322
+ async function resolveReactionToken(installationId) {
24323
+ if (installationId && isReactionsEnabled()) {
24324
+ const appToken = await getInstallationToken(installationId);
24325
+ if (appToken)
24326
+ return appToken;
24327
+ console.log("[GitHub] No installation token, trying GITHUB_TOKEN for reaction");
24328
+ }
24329
+ const pat = process.env.GITHUB_TOKEN?.trim();
24330
+ if (pat)
24331
+ return pat;
24332
+ console.log("[GitHub] No App installation and no GITHUB_TOKEN, skipping reaction");
24333
+ return null;
24334
+ }
24335
+ async function postRestReaction(repo, target, reaction, installationId, label) {
24336
+ const token = await resolveReactionToken(installationId);
24337
+ if (!token)
24192
24338
  return false;
24193
- }
24194
24339
  try {
24195
- const response = await fetch(`https://api.github.com/repos/${repo}/issues/comments/${commentId}/reactions`, {
24340
+ const response = await fetch(`https://api.github.com/repos/${repo}/${target}/reactions`, {
24196
24341
  method: "POST",
24197
24342
  headers: {
24198
24343
  Accept: "application/vnd.github+json",
@@ -24204,92 +24349,29 @@ async function addReaction(repo, commentId, reaction, installationId) {
24204
24349
  });
24205
24350
  if (!response.ok) {
24206
24351
  const errorText2 = await response.text();
24207
- console.error(`[GitHub] Failed to add reaction: ${response.status} ${errorText2}`);
24352
+ console.error(`[GitHub] Failed to add ${label} reaction: ${response.status} ${scrubSecrets(errorText2)}`);
24208
24353
  return false;
24209
24354
  }
24210
- console.log(`[GitHub] Added ${reaction} reaction to comment ${commentId}`);
24355
+ console.log(`[GitHub] Added ${reaction} reaction to ${label}`);
24211
24356
  return true;
24212
24357
  } catch (error) {
24213
- console.error("[GitHub] Error adding reaction:", error);
24358
+ console.error(`[GitHub] Error adding ${label} reaction:`, scrubSecrets(error instanceof Error ? error.message : String(error)));
24214
24359
  return false;
24215
24360
  }
24216
24361
  }
24362
+ async function addReaction(repo, commentId, reaction, installationId) {
24363
+ return postRestReaction(repo, `issues/comments/${commentId}`, reaction, installationId, `comment ${commentId}`);
24364
+ }
24217
24365
  async function addIssueReaction(repo, issueNumber, reaction, installationId) {
24218
- if (!isReactionsEnabled()) {
24219
- console.log("[GitHub] Reactions not enabled, skipping");
24220
- return false;
24221
- }
24222
- const token = await getInstallationToken(installationId);
24223
- if (!token) {
24224
- console.log("[GitHub] No installation token, skipping reaction");
24225
- return false;
24226
- }
24227
- try {
24228
- const response = await fetch(`https://api.github.com/repos/${repo}/issues/${issueNumber}/reactions`, {
24229
- method: "POST",
24230
- headers: {
24231
- Accept: "application/vnd.github+json",
24232
- Authorization: `Bearer ${token}`,
24233
- "X-GitHub-Api-Version": "2022-11-28",
24234
- "Content-Type": "application/json"
24235
- },
24236
- body: JSON.stringify({ content: reaction })
24237
- });
24238
- if (!response.ok) {
24239
- const errorText2 = await response.text();
24240
- console.error(`[GitHub] Failed to add issue reaction: ${response.status} ${errorText2}`);
24241
- return false;
24242
- }
24243
- console.log(`[GitHub] Added ${reaction} reaction to issue/PR #${issueNumber}`);
24244
- return true;
24245
- } catch (error) {
24246
- console.error("[GitHub] Error adding issue reaction:", error);
24247
- return false;
24248
- }
24366
+ return postRestReaction(repo, `issues/${issueNumber}`, reaction, installationId, `issue/PR #${issueNumber}`);
24249
24367
  }
24250
24368
  async function addPullReviewCommentReaction(repo, commentId, reaction, installationId) {
24251
- if (!isReactionsEnabled()) {
24252
- console.log("[GitHub] Reactions not enabled, skipping");
24253
- return false;
24254
- }
24255
- const token = await getInstallationToken(installationId);
24256
- if (!token) {
24257
- console.log("[GitHub] No installation token, skipping reaction");
24258
- return false;
24259
- }
24260
- try {
24261
- const response = await fetch(`https://api.github.com/repos/${repo}/pulls/comments/${commentId}/reactions`, {
24262
- method: "POST",
24263
- headers: {
24264
- Accept: "application/vnd.github+json",
24265
- Authorization: `Bearer ${token}`,
24266
- "X-GitHub-Api-Version": "2022-11-28",
24267
- "Content-Type": "application/json"
24268
- },
24269
- body: JSON.stringify({ content: reaction })
24270
- });
24271
- if (!response.ok) {
24272
- const errorText2 = await response.text();
24273
- console.error(`[GitHub] Failed to add PR review comment reaction: ${response.status} ${errorText2}`);
24274
- return false;
24275
- }
24276
- console.log(`[GitHub] Added ${reaction} reaction to PR review comment ${commentId}`);
24277
- return true;
24278
- } catch (error) {
24279
- console.error("[GitHub] Error adding PR review comment reaction:", error);
24280
- return false;
24281
- }
24369
+ return postRestReaction(repo, `pulls/comments/${commentId}`, reaction, installationId, `PR review comment ${commentId}`);
24282
24370
  }
24283
24371
  async function addGraphQLReaction(nodeId, reaction, installationId) {
24284
- if (!isReactionsEnabled()) {
24285
- console.log("[GitHub] Reactions not enabled, skipping");
24286
- return false;
24287
- }
24288
- const token = await getInstallationToken(installationId);
24289
- if (!token) {
24290
- console.log("[GitHub] No installation token, skipping GraphQL reaction");
24372
+ const token = await resolveReactionToken(installationId);
24373
+ if (!token)
24291
24374
  return false;
24292
- }
24293
24375
  try {
24294
24376
  const response = await fetch("https://api.github.com/graphql", {
24295
24377
  method: "POST",
@@ -24310,28 +24392,26 @@ async function addGraphQLReaction(nodeId, reaction, installationId) {
24310
24392
  });
24311
24393
  if (!response.ok) {
24312
24394
  const errorText2 = await response.text();
24313
- console.error(`[GitHub] GraphQL reaction failed: ${response.status} ${errorText2}`);
24395
+ console.error(`[GitHub] GraphQL reaction failed: ${response.status} ${scrubSecrets(errorText2)}`);
24314
24396
  return false;
24315
24397
  }
24316
24398
  const data = await response.json();
24317
24399
  if (data.errors?.length) {
24318
- console.error(`[GitHub] GraphQL reaction errors: ${JSON.stringify(data.errors)}`);
24400
+ console.error(`[GitHub] GraphQL reaction errors: ${scrubSecrets(JSON.stringify(data.errors))}`);
24319
24401
  return false;
24320
24402
  }
24321
24403
  console.log(`[GitHub] Added ${reaction} GraphQL reaction to node ${nodeId}`);
24322
24404
  return true;
24323
24405
  } catch (error) {
24324
- console.error("[GitHub] Error adding GraphQL reaction:", error);
24406
+ console.error("[GitHub] Error adding GraphQL reaction:", scrubSecrets(error instanceof Error ? error.message : String(error)));
24325
24407
  return false;
24326
24408
  }
24327
24409
  }
24328
24410
 
24329
24411
  // src/github/task-reactions.ts
24330
- async function addEyesReactionOnTaskStart(task) {
24412
+ async function addEyesReactionToTaskSource(task) {
24331
24413
  if (task.source !== "github" || task.vcsProvider !== "github")
24332
24414
  return;
24333
- if (!task.vcsInstallationId)
24334
- return;
24335
24415
  const installationId = task.vcsInstallationId;
24336
24416
  const repo = task.vcsRepo;
24337
24417
  if (!repo)
@@ -24353,6 +24433,8 @@ async function addEyesReactionOnTaskStart(task) {
24353
24433
  case "pull_request_review": {
24354
24434
  if (task.vcsNodeId) {
24355
24435
  await addGraphQLReaction(task.vcsNodeId, "EYES", installationId);
24436
+ } else if (task.vcsNumber) {
24437
+ await addIssueReaction(repo, task.vcsNumber, "eyes", installationId);
24356
24438
  }
24357
24439
  break;
24358
24440
  }
@@ -24365,9 +24447,12 @@ async function addEyesReactionOnTaskStart(task) {
24365
24447
  }
24366
24448
  }
24367
24449
  } catch (error) {
24368
- console.error("[GitHub] Failed to add eyes reaction on task start:", error);
24450
+ console.error("[GitHub] Failed to add eyes reaction:", scrubSecrets(error instanceof Error ? error.message : String(error)));
24369
24451
  }
24370
24452
  }
24453
+ async function addEyesReactionOnTaskStart(task) {
24454
+ await addEyesReactionToTaskSource(task);
24455
+ }
24371
24456
  var registered = false;
24372
24457
  function registerGithubTaskReactions() {
24373
24458
  if (registered)
@@ -25230,6 +25315,510 @@ async function handleMessageReceived(payload) {
25230
25315
  console.log(`[AgentMail] Created unassigned task ${task.id} (no lead or mapping available)`);
25231
25316
  return { created: true, taskId: task.id };
25232
25317
  }
25318
+ // src/azure-devops/auth.ts
25319
+ init_env_flag();
25320
+ var initialized3 = false;
25321
+ var webhookSecret3 = null;
25322
+ var apiToken = null;
25323
+ var orgUrl = null;
25324
+ function isAzureDevOpsEnabled() {
25325
+ return !!process.env.AZURE_DEVOPS_WEBHOOK_SECRET && !isEnvFlagEnabled("AZURE_DEVOPS_DISABLE", false);
25326
+ }
25327
+ function initAzureDevOps() {
25328
+ if (initialized3)
25329
+ return;
25330
+ if (!isAzureDevOpsEnabled()) {
25331
+ console.log("[AzureDevOps] Integration disabled (AZURE_DEVOPS_WEBHOOK_SECRET not set)");
25332
+ return;
25333
+ }
25334
+ webhookSecret3 = process.env.AZURE_DEVOPS_WEBHOOK_SECRET;
25335
+ apiToken = process.env.AZURE_DEVOPS_TOKEN ?? null;
25336
+ orgUrl = normalizeOrgUrl(process.env.AZURE_DEVOPS_ORG_URL);
25337
+ initialized3 = true;
25338
+ console.log(`[AzureDevOps] Integration initialized (org: ${orgUrl ?? "from payload"})`);
25339
+ }
25340
+ function verifyAzureDevOpsWebhook(authorizationHeader) {
25341
+ if (!webhookSecret3)
25342
+ return false;
25343
+ if (!authorizationHeader?.startsWith("Basic "))
25344
+ return false;
25345
+ const decoded = Buffer.from(authorizationHeader.slice("Basic ".length), "base64").toString();
25346
+ const separator = decoded.indexOf(":");
25347
+ if (separator === -1)
25348
+ return false;
25349
+ const password = decoded.slice(separator + 1);
25350
+ if (password.length !== webhookSecret3.length)
25351
+ return false;
25352
+ return crypto.timingSafeEqual(Buffer.from(password), Buffer.from(webhookSecret3));
25353
+ }
25354
+ function getAzureDevOpsToken() {
25355
+ return apiToken;
25356
+ }
25357
+ function getAzureDevOpsOrgUrl() {
25358
+ return orgUrl;
25359
+ }
25360
+ function normalizeOrgUrl(url) {
25361
+ const trimmed = url?.trim().replace(/\/+$/, "");
25362
+ return trimmed ? trimmed : null;
25363
+ }
25364
+ var AZURE_DEVOPS_BOT_NAME = process.env.AZURE_DEVOPS_BOT_NAME ?? "agent-swarm-bot";
25365
+ function resetAzureDevOps() {
25366
+ initialized3 = false;
25367
+ webhookSecret3 = null;
25368
+ apiToken = null;
25369
+ orgUrl = null;
25370
+ }
25371
+
25372
+ // src/azure-devops/api.ts
25373
+ var API_VERSION = "7.1";
25374
+ function headers() {
25375
+ const token = getAzureDevOpsToken();
25376
+ if (!token)
25377
+ throw new Error("[AzureDevOps] No API token configured");
25378
+ return {
25379
+ Authorization: `Basic ${Buffer.from(`:${token}`).toString("base64")}`,
25380
+ "Content-Type": "application/json",
25381
+ Accept: "application/json"
25382
+ };
25383
+ }
25384
+ function pullRequestBase(ref) {
25385
+ return `${ref.orgUrl}/${encodeURIComponent(ref.projectId)}/_apis/git/repositories/` + `${encodeURIComponent(ref.repositoryId)}/pullRequests/${ref.pullRequestId}`;
25386
+ }
25387
+ var cachedBotId = null;
25388
+ async function resolveAzureDevOpsBotId(orgBaseUrl) {
25389
+ const fromEnv = process.env.AZURE_DEVOPS_BOT_ID?.trim();
25390
+ if (fromEnv)
25391
+ return fromEnv;
25392
+ const orgUrl2 = normalizeOrgUrl(orgBaseUrl) ?? getAzureDevOpsOrgUrl();
25393
+ if (!orgUrl2 || !getAzureDevOpsToken())
25394
+ return null;
25395
+ if (cachedBotId?.orgUrl === orgUrl2)
25396
+ return cachedBotId.id;
25397
+ try {
25398
+ const resp = await fetch(`${orgUrl2}/_apis/connectionData`, { headers: headers() });
25399
+ if (!resp.ok) {
25400
+ console.error(`[AzureDevOps] Failed to resolve bot identity: ${resp.status}`);
25401
+ return null;
25402
+ }
25403
+ const data = await resp.json();
25404
+ const id = data.authenticatedUser?.id;
25405
+ if (!id)
25406
+ return null;
25407
+ cachedBotId = { orgUrl: orgUrl2, id };
25408
+ return id;
25409
+ } catch (err) {
25410
+ console.error(`[AzureDevOps] Error resolving bot identity:`, err);
25411
+ return null;
25412
+ }
25413
+ }
25414
+ function resetAzureDevOpsBotIdCache() {
25415
+ cachedBotId = null;
25416
+ }
25417
+ async function likeAzureDevOpsComment(ref, threadId, commentId) {
25418
+ const url = `${pullRequestBase(ref)}/threads/${threadId}/comments/${commentId}/likes?api-version=${API_VERSION}`;
25419
+ try {
25420
+ const resp = await fetch(url, { method: "POST", headers: headers() });
25421
+ if (!resp.ok) {
25422
+ console.error(`[AzureDevOps] Failed to like comment: ${resp.status} ${await resp.text()}`);
25423
+ }
25424
+ } catch (err) {
25425
+ console.error(`[AzureDevOps] Error liking comment:`, err);
25426
+ }
25427
+ }
25428
+ // src/azure-devops/handlers.ts
25429
+ init_db();
25430
+ init_resolver();
25431
+ init_context_key();
25432
+
25433
+ // src/vcs/azure-devops.ts
25434
+ function isAzureDevOpsUrl(url) {
25435
+ return /(^|[/@.])dev\.azure\.com[/:]|\.visualstudio\.com[/:]/i.test(url);
25436
+ }
25437
+ function canonicalAzureDevOpsRepoUrl(url) {
25438
+ const trimmed = url.trim();
25439
+ const ssh = trimmed.match(/^(?:ssh:\/\/)?[^@]+@ssh\.dev\.azure\.com[:/]v3\/([^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
25440
+ if (ssh)
25441
+ return `https://dev.azure.com/${ssh[1]}/${ssh[2]}/_git/${ssh[3]}`;
25442
+ let parsed;
25443
+ try {
25444
+ parsed = new URL(trimmed);
25445
+ } catch {
25446
+ return trimmed;
25447
+ }
25448
+ parsed.username = "";
25449
+ parsed.password = "";
25450
+ parsed.search = "";
25451
+ parsed.hash = "";
25452
+ const parts = parsed.pathname.replace(/\.git\/?$/, "").split("/").filter(Boolean);
25453
+ if (parsed.hostname === "dev.azure.com" && parts.length === 3 && parts[1] === "_git") {
25454
+ parts.splice(1, 0, parts[2]);
25455
+ }
25456
+ parsed.pathname = `/${parts.join("/")}`;
25457
+ return parsed.toString().replace(/\/+$/, "");
25458
+ }
25459
+ function parseAzureDevOpsRepoUrl(url) {
25460
+ const canonical = canonicalAzureDevOpsRepoUrl(url);
25461
+ let parsed;
25462
+ try {
25463
+ parsed = new URL(canonical);
25464
+ } catch {
25465
+ return null;
25466
+ }
25467
+ const parts = parsed.pathname.split("/").filter(Boolean);
25468
+ const gitIndex = parts.indexOf("_git");
25469
+ const repository = parts[gitIndex + 1];
25470
+ if (gitIndex < 1 || !repository) {
25471
+ if (gitIndex === 0 && repository) {
25472
+ return { orgUrl: parsed.origin, project: repository, repository };
25473
+ }
25474
+ return null;
25475
+ }
25476
+ const collectionOnly = parts[gitIndex - 1]?.toLowerCase() === "defaultcollection";
25477
+ const project = collectionOnly ? repository : parts[gitIndex - 1];
25478
+ const orgPath = parts.slice(0, collectionOnly ? gitIndex : gitIndex - 1).join("/");
25479
+ return {
25480
+ orgUrl: orgPath ? `${parsed.origin}/${orgPath}` : parsed.origin,
25481
+ project: decodeURIComponent(project),
25482
+ repository: decodeURIComponent(repository)
25483
+ };
25484
+ }
25485
+
25486
+ // src/azure-devops/templates.ts
25487
+ init_registry();
25488
+ registerTemplate({
25489
+ eventType: "common.delegation_instruction.azure_devops",
25490
+ header: "",
25491
+ defaultBody: "\n\n**Delegation instruction:** As the lead agent, analyze this and decide whether to handle it yourself or delegate to a worker agent. Use `send-task` to delegate with clear instructions.",
25492
+ variables: [],
25493
+ category: "common"
25494
+ });
25495
+ registerTemplate({
25496
+ eventType: "common.command_suggestions.azure_devops_pr",
25497
+ header: "",
25498
+ defaultBody: 'Workers have the `az` CLI with the azure-devops extension, authenticated with the swarm PAT. Inspect the PR with `az repos pr show --id {{pr_id}}`. To reply on the PR, write `{"comments":[{"content":"<reply>"}],"status":1}` to a JSON file and run `az devops invoke --area git --resource pullRequestThreads --route-parameters project={{project}} repositoryId={{repository}} pullRequestId={{pr_id}} --http-method POST --in-file <file> --api-version 7.1`.',
25499
+ variables: [
25500
+ { name: "pr_id", description: "Pull request ID" },
25501
+ { name: "project", description: "Azure DevOps project name" },
25502
+ { name: "repository", description: "Azure Repos repository name" }
25503
+ ],
25504
+ category: "common"
25505
+ });
25506
+ var SHARED_VARIABLES = [
25507
+ { name: "pr_id", description: "Pull request ID" },
25508
+ { name: "pr_title", description: "Pull request title" },
25509
+ {
25510
+ name: "repo",
25511
+ description: "Repository clone URL (https://dev.azure.com/<org>/<project>/_git/<repo>)"
25512
+ },
25513
+ { name: "project", description: "Azure DevOps project name" },
25514
+ { name: "repository", description: "Azure Repos repository name" },
25515
+ { name: "pr_url", description: "Pull request web URL" }
25516
+ ];
25517
+ registerTemplate({
25518
+ eventType: "azure-devops.pull_request.opened",
25519
+ header: "[Azure DevOps PR #{{pr_id}}] {{pr_title}}",
25520
+ defaultBody: `Repo: {{repo}}
25521
+ Author: {{username}}
25522
+ Branch: {{source_branch}} → {{target_branch}}
25523
+ URL: {{pr_url}}
25524
+
25525
+ {{context_section}}{{@template[common.command_suggestions.azure_devops_pr]}}{{@template[common.delegation_instruction.azure_devops]}}`,
25526
+ variables: [
25527
+ ...SHARED_VARIABLES,
25528
+ {
25529
+ name: "username",
25530
+ description: "Author identity — resolved canonical name (e.g. 'Luis (azure-devops:luis@example.com)') or the UNKNOWN sentinel"
25531
+ },
25532
+ { name: "source_branch", description: "Source branch name" },
25533
+ { name: "target_branch", description: "Target branch name" },
25534
+ { name: "context_section", description: "Context section with description or empty string" }
25535
+ ],
25536
+ category: "event"
25537
+ });
25538
+ registerTemplate({
25539
+ eventType: "azure-devops.comment.mentioned",
25540
+ header: "[Azure DevOps Comment on PR #{{pr_id}}] {{username}} mentioned bot",
25541
+ defaultBody: `Repo: {{repo}}
25542
+ PR: {{pr_title}}
25543
+ URL: {{pr_url}}
25544
+
25545
+ Comment:
25546
+ {{context}}{{existing_task_note}}
25547
+
25548
+ {{@template[common.command_suggestions.azure_devops_pr]}}{{@template[common.delegation_instruction.azure_devops]}}`,
25549
+ variables: [
25550
+ ...SHARED_VARIABLES,
25551
+ {
25552
+ name: "username",
25553
+ description: "Comment author identity — resolved canonical name (e.g. 'Luis (azure-devops:luis@example.com)') or the UNKNOWN sentinel"
25554
+ },
25555
+ { name: "context", description: "Extracted mention context from comment" },
25556
+ {
25557
+ name: "existing_task_note",
25558
+ description: "Note about existing active task, or empty string"
25559
+ }
25560
+ ],
25561
+ category: "event"
25562
+ });
25563
+
25564
+ // src/azure-devops/handlers.ts
25565
+ var processedEvents2 = new Map;
25566
+ var DEDUP_TTL_MS = 60000;
25567
+ function isDuplicate2(key) {
25568
+ const now = Date.now();
25569
+ for (const [k, ts] of processedEvents2) {
25570
+ if (now - ts > DEDUP_TTL_MS)
25571
+ processedEvents2.delete(k);
25572
+ }
25573
+ if (processedEvents2.has(key))
25574
+ return true;
25575
+ processedEvents2.set(key, now);
25576
+ return false;
25577
+ }
25578
+ function escapeRegExp(value) {
25579
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
25580
+ }
25581
+ function mentionPatterns(botId) {
25582
+ const patterns = [new RegExp(`@${escapeRegExp(AZURE_DEVOPS_BOT_NAME)}\\b`, "gi")];
25583
+ if (botId)
25584
+ patterns.push(new RegExp(`@<${escapeRegExp(botId)}>`, "gi"));
25585
+ return patterns;
25586
+ }
25587
+ function detectMention(text, botId) {
25588
+ if (!text)
25589
+ return false;
25590
+ return mentionPatterns(botId).some((re) => {
25591
+ re.lastIndex = 0;
25592
+ return re.test(text);
25593
+ });
25594
+ }
25595
+ function extractMentionContext(text, botId) {
25596
+ return mentionPatterns(botId).reduce((acc, re) => acc.replace(re, ""), text).trim();
25597
+ }
25598
+ function isBot(identity, botId) {
25599
+ return !!botId && identity.id.toLowerCase() === botId.toLowerCase();
25600
+ }
25601
+ function pullRequestWebUrl(pr) {
25602
+ const web = pr._links?.web?.href;
25603
+ if (web)
25604
+ return web.split("#")[0];
25605
+ return `${canonicalAzureDevOpsRepoUrl(pr.repository.remoteUrl)}/pullrequest/${pr.pullRequestId}`;
25606
+ }
25607
+ function branchName(refName) {
25608
+ return refName.replace(/^refs\/heads\//, "");
25609
+ }
25610
+ function orgUrlFor(event) {
25611
+ const containers = event.resourceContainers;
25612
+ return normalizeOrgUrl(containers?.account?.baseUrl ?? containers?.collection?.baseUrl) ?? getAzureDevOpsOrgUrl();
25613
+ }
25614
+ function threadIdOf(links) {
25615
+ const href = links?.threads?.href ?? links?.self?.href ?? "";
25616
+ const match = href.match(/\/threads\/(\d+)/);
25617
+ return match ? Number(match[1]) : null;
25618
+ }
25619
+ function isPullRequest(value) {
25620
+ const pr = value;
25621
+ return typeof pr?.pullRequestId === "number" && typeof pr.repository?.id === "string" && typeof pr.repository.remoteUrl === "string" && !!pr.repository.project && !!pr.createdBy;
25622
+ }
25623
+ function createdPullRequestOf(event) {
25624
+ return isPullRequest(event?.resource) ? event.resource : null;
25625
+ }
25626
+ function commentedPayloadOf(event) {
25627
+ const resource = event?.resource;
25628
+ const comment = resource?.comment;
25629
+ const pullRequest = resource?.pullRequest;
25630
+ if (!isPullRequest(pullRequest) || typeof comment?.id !== "number" || !comment.author) {
25631
+ return null;
25632
+ }
25633
+ return { comment, pullRequest };
25634
+ }
25635
+ function warnMalformed(event) {
25636
+ console.warn(`[AzureDevOps] Ignoring ${event?.eventType} event with resourceVersion ${event?.resourceVersion ?? "unknown"}: required resource fields are missing`);
25637
+ }
25638
+ async function findLeadAgent2() {
25639
+ const agents = await getAllAgents();
25640
+ return agents.find((a) => a.role === "lead" && a.status === "idle") ?? agents.find((a) => a.role === "lead") ?? null;
25641
+ }
25642
+ var UNMAPPED_NAMESPACE = "integration:unmapped:azure-devops";
25643
+ var UNMAPPED_TTL_MS = 30 * 24 * 60 * 60 * 1000;
25644
+ var AZURE_DEVOPS_WEBHOOK_ACTOR = { kind: "system", id: "webhook:azure-devops" };
25645
+ function externalIdOf(identity) {
25646
+ return identity.uniqueName?.trim() || identity.id;
25647
+ }
25648
+ async function resolveAzureDevOpsSender(identity, sampleEventType, sampleContext) {
25649
+ const externalId = externalIdOf(identity);
25650
+ const existing = await findUserByExternalId("azure-devops", externalId);
25651
+ if (existing)
25652
+ return existing.id;
25653
+ if (externalId.includes("@")) {
25654
+ const { user: linked } = await findOrCreateUserByEmail(externalId, { name: identity.displayName }, AZURE_DEVOPS_WEBHOOK_ACTOR);
25655
+ await linkIdentity(linked.id, "azure-devops", externalId, AZURE_DEVOPS_WEBHOOK_ACTOR);
25656
+ return linked.id;
25657
+ }
25658
+ await upsertKv({
25659
+ namespace: UNMAPPED_NAMESPACE,
25660
+ key: `${externalId}:meta`,
25661
+ value: {
25662
+ lastSeenAt: new Date().toISOString(),
25663
+ sampleEventType,
25664
+ sampleContext: sampleContext.slice(0, 100)
25665
+ },
25666
+ valueType: "json",
25667
+ expiresAt: Date.now() + UNMAPPED_TTL_MS
25668
+ });
25669
+ await incrKv(UNMAPPED_NAMESPACE, `${externalId}:count`, 1);
25670
+ return;
25671
+ }
25672
+ async function renderAzureDevOpsIdentity(identity) {
25673
+ return renderIdentity(await resolveIdentity("azure-devops", externalIdOf(identity)));
25674
+ }
25675
+ async function handlePullRequestCreated(event) {
25676
+ const pr = createdPullRequestOf(event);
25677
+ if (!pr) {
25678
+ warnMalformed(event);
25679
+ return { created: false };
25680
+ }
25681
+ const repo = canonicalAzureDevOpsRepoUrl(pr.repository.remoteUrl);
25682
+ console.log(`[AzureDevOps] PR #${pr.pullRequestId} created by ${pr.createdBy.displayName} in ${repo}`);
25683
+ const orgUrl2 = orgUrlFor(event);
25684
+ const botId = await resolveAzureDevOpsBotId(orgUrl2);
25685
+ if (isBot(pr.createdBy, botId)) {
25686
+ console.log(`[AzureDevOps] PR opened by the bot itself, skipping`);
25687
+ return { created: false };
25688
+ }
25689
+ if (!detectMention(pr.description, botId)) {
25690
+ console.log(`[AzureDevOps] PR opened without bot mention, skipping`);
25691
+ return { created: false };
25692
+ }
25693
+ const dedupKey = `azure-devops-pr-${pr.repository.id}-${pr.pullRequestId}-created`;
25694
+ if (isDuplicate2(dedupKey)) {
25695
+ console.log(`[AzureDevOps] Skipping duplicate PR event`);
25696
+ return { created: false };
25697
+ }
25698
+ const requestedByUserId = await resolveAzureDevOpsSender(pr.createdBy, "pull_request", `PR !${pr.pullRequestId}: ${pr.title}`);
25699
+ const context = pr.description ? extractMentionContext(pr.description, botId) : "";
25700
+ const prUrl = pullRequestWebUrl(pr);
25701
+ const result = resolveTemplate("azure-devops.pull_request.opened", {
25702
+ pr_id: pr.pullRequestId,
25703
+ pr_title: pr.title,
25704
+ repo,
25705
+ project: pr.repository.project.name,
25706
+ repository: pr.repository.name,
25707
+ username: await renderAzureDevOpsIdentity(pr.createdBy),
25708
+ source_branch: branchName(pr.sourceRefName),
25709
+ target_branch: branchName(pr.targetRefName),
25710
+ pr_url: prUrl,
25711
+ context_section: context ? `Context: ${context}
25712
+
25713
+ ` : ""
25714
+ });
25715
+ if (result.skipped) {
25716
+ return { created: false };
25717
+ }
25718
+ const lead = await findLeadAgent2();
25719
+ const task = await createTaskWithSiblingAwareness(result.text, {
25720
+ agentId: lead?.id ?? null,
25721
+ routingReason: lead ? "skill" : undefined,
25722
+ routingSource: lead ? "engine_default" : undefined,
25723
+ source: "azure-devops",
25724
+ vcsProvider: "azure-devops",
25725
+ taskType: "azure-devops-pr",
25726
+ vcsRepo: repo,
25727
+ vcsEventType: "pull_request",
25728
+ vcsNumber: pr.pullRequestId,
25729
+ vcsAuthor: externalIdOf(pr.createdBy),
25730
+ requestedByUserId,
25731
+ vcsUrl: prUrl,
25732
+ contextKey: azureDevOpsContextKey({
25733
+ repositoryId: pr.repository.id,
25734
+ pullRequestId: pr.pullRequestId
25735
+ })
25736
+ }, { origin: "webhook" });
25737
+ return { created: true, taskId: task.id };
25738
+ }
25739
+ async function handlePullRequestCommented(event) {
25740
+ const payload = commentedPayloadOf(event);
25741
+ if (!payload) {
25742
+ warnMalformed(event);
25743
+ return { created: false };
25744
+ }
25745
+ const { comment, pullRequest: pr } = payload;
25746
+ const repo = canonicalAzureDevOpsRepoUrl(pr.repository.remoteUrl);
25747
+ if (comment.commentType === "system") {
25748
+ return { created: false };
25749
+ }
25750
+ if (comment.lastContentUpdatedDate && comment.lastContentUpdatedDate !== comment.publishedDate) {
25751
+ console.log(`[AzureDevOps] Ignoring edited comment ${comment.id} on PR #${pr.pullRequestId}`);
25752
+ return { created: false };
25753
+ }
25754
+ const orgUrl2 = orgUrlFor(event);
25755
+ const botId = await resolveAzureDevOpsBotId(orgUrl2);
25756
+ if (isBot(comment.author, botId)) {
25757
+ return { created: false };
25758
+ }
25759
+ if (!detectMention(comment.content, botId)) {
25760
+ return { created: false };
25761
+ }
25762
+ console.log(`[AzureDevOps] Comment by ${comment.author.displayName} on PR #${pr.pullRequestId} in ${repo}`);
25763
+ const threadId = threadIdOf(comment._links);
25764
+ const dedupKey = `azure-devops-comment-${pr.repository.id}-${pr.pullRequestId}-${threadId}-${comment.id}`;
25765
+ if (isDuplicate2(dedupKey)) {
25766
+ return { created: false };
25767
+ }
25768
+ const requestedByUserId = await resolveAzureDevOpsSender(comment.author, "pull_request_comment", comment.content);
25769
+ const existingTask = await findTaskByVcs(repo, pr.pullRequestId);
25770
+ const existingTaskNote = existingTask ? `
25771
+
25772
+ _Note: There's an active task (${existingTask.id}) for this PR #${pr.pullRequestId}._` : "";
25773
+ const prUrl = pullRequestWebUrl(pr);
25774
+ const result = resolveTemplate("azure-devops.comment.mentioned", {
25775
+ pr_id: pr.pullRequestId,
25776
+ pr_title: pr.title,
25777
+ username: await renderAzureDevOpsIdentity(comment.author),
25778
+ repo,
25779
+ project: pr.repository.project.name,
25780
+ repository: pr.repository.name,
25781
+ pr_url: prUrl,
25782
+ context: extractMentionContext(comment.content, botId),
25783
+ existing_task_note: existingTaskNote
25784
+ });
25785
+ if (result.skipped) {
25786
+ return { created: false };
25787
+ }
25788
+ const lead = await findLeadAgent2();
25789
+ const task = await createTaskWithSiblingAwareness(result.text, {
25790
+ agentId: lead?.id ?? null,
25791
+ routingReason: lead ? "skill" : undefined,
25792
+ routingSource: lead ? "engine_default" : undefined,
25793
+ source: "azure-devops",
25794
+ vcsProvider: "azure-devops",
25795
+ taskType: "azure-devops-comment",
25796
+ vcsRepo: repo,
25797
+ vcsEventType: "pull_request_comment",
25798
+ vcsNumber: pr.pullRequestId,
25799
+ vcsCommentId: comment.id,
25800
+ vcsAuthor: externalIdOf(comment.author),
25801
+ requestedByUserId,
25802
+ vcsUrl: prUrl,
25803
+ parentTaskId: existingTask?.id,
25804
+ contextKey: azureDevOpsContextKey({
25805
+ repositoryId: pr.repository.id,
25806
+ pullRequestId: pr.pullRequestId
25807
+ })
25808
+ }, { origin: "webhook" });
25809
+ if (orgUrl2 && threadId !== null) {
25810
+ const ref = {
25811
+ orgUrl: orgUrl2,
25812
+ projectId: pr.repository.project.id,
25813
+ repositoryId: pr.repository.id,
25814
+ pullRequestId: pr.pullRequestId
25815
+ };
25816
+ try {
25817
+ await likeAzureDevOpsComment(ref, threadId, comment.id);
25818
+ } catch {}
25819
+ }
25820
+ return { created: true, taskId: task.id };
25821
+ }
25233
25822
  // src/http/core.ts
25234
25823
  init_db();
25235
25824
 
@@ -25601,7 +26190,6 @@ function stopAuditGc() {
25601
26190
  init_db();
25602
26191
  init_resolver();
25603
26192
  init_context_key();
25604
- init_secret_scrubber();
25605
26193
 
25606
26194
  // src/github/mentions.ts
25607
26195
  var GITHUB_BOT_NAME = process.env.GITHUB_BOT_NAME || "agent-swarm-bot";
@@ -25620,12 +26208,12 @@ function computeMentionPattern(names) {
25620
26208
  }
25621
26209
  var BOT_NAMES = computeBotNames();
25622
26210
  var MENTION_PATTERN = computeMentionPattern(BOT_NAMES);
25623
- function detectMention(text) {
26211
+ function detectMention2(text) {
25624
26212
  if (!text)
25625
26213
  return false;
25626
26214
  return MENTION_PATTERN.test(text);
25627
26215
  }
25628
- function extractMentionContext(text) {
26216
+ function extractMentionContext2(text) {
25629
26217
  if (!text)
25630
26218
  return "";
25631
26219
  return text.replace(MENTION_PATTERN, "").trim();
@@ -26068,7 +26656,7 @@ Related task: {{related_task_id}}
26068
26656
  });
26069
26657
 
26070
26658
  // src/github/handlers.ts
26071
- var processedEvents2 = new Map;
26659
+ var processedEvents3 = new Map;
26072
26660
  var EVENT_TTL2 = 60000;
26073
26661
  function buildGithubContextKey(fullName, kind, number3) {
26074
26662
  const [owner, repo] = fullName.split("/");
@@ -26112,34 +26700,34 @@ function getCommandSuggestions(taskType, targetType) {
26112
26700
  return "";
26113
26701
  }
26114
26702
  }
26115
- function isDuplicate2(eventKey) {
26703
+ function isDuplicate3(eventKey) {
26116
26704
  const now = Date.now();
26117
- for (const [key, timestamp] of processedEvents2) {
26705
+ for (const [key, timestamp] of processedEvents3) {
26118
26706
  if (now - timestamp > EVENT_TTL2) {
26119
- processedEvents2.delete(key);
26707
+ processedEvents3.delete(key);
26120
26708
  }
26121
26709
  }
26122
- if (processedEvents2.has(eventKey)) {
26710
+ if (processedEvents3.has(eventKey)) {
26123
26711
  return true;
26124
26712
  }
26125
- processedEvents2.set(eventKey, now);
26713
+ processedEvents3.set(eventKey, now);
26126
26714
  return false;
26127
26715
  }
26128
- async function findLeadAgent2() {
26716
+ async function findLeadAgent3() {
26129
26717
  const agents = await getAllAgents();
26130
26718
  const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
26131
26719
  if (onlineLead)
26132
26720
  return onlineLead;
26133
26721
  return agents.find((a) => a.isLead) ?? null;
26134
26722
  }
26135
- var UNMAPPED_NAMESPACE = "integration:unmapped:github";
26136
- var UNMAPPED_TTL_MS = 30 * 24 * 60 * 60 * 1000;
26723
+ var UNMAPPED_NAMESPACE2 = "integration:unmapped:github";
26724
+ var UNMAPPED_TTL_MS2 = 30 * 24 * 60 * 60 * 1000;
26137
26725
  async function resolveGitHubSender(login, sampleEventType, sampleContext) {
26138
26726
  const existing = await findUserByExternalId("github", login);
26139
26727
  if (existing)
26140
26728
  return existing.id;
26141
26729
  await upsertKv({
26142
- namespace: UNMAPPED_NAMESPACE,
26730
+ namespace: UNMAPPED_NAMESPACE2,
26143
26731
  key: `${login}:meta`,
26144
26732
  value: {
26145
26733
  lastSeenAt: new Date().toISOString(),
@@ -26147,9 +26735,9 @@ async function resolveGitHubSender(login, sampleEventType, sampleContext) {
26147
26735
  sampleContext: sampleContext.slice(0, 100)
26148
26736
  },
26149
26737
  valueType: "json",
26150
- expiresAt: Date.now() + UNMAPPED_TTL_MS
26738
+ expiresAt: Date.now() + UNMAPPED_TTL_MS2
26151
26739
  });
26152
- await incrKv(UNMAPPED_NAMESPACE, `${login}:count`, 1);
26740
+ await incrKv(UNMAPPED_NAMESPACE2, `${login}:count`, 1);
26153
26741
  return;
26154
26742
  }
26155
26743
  async function handlePullRequest(event) {
@@ -26168,10 +26756,10 @@ async function handlePullRequest(event) {
26168
26756
  return { created: false };
26169
26757
  }
26170
26758
  const eventKey2 = `pr-assigned:${repository.full_name}:${pr.number}`;
26171
- if (isDuplicate2(eventKey2)) {
26759
+ if (isDuplicate3(eventKey2)) {
26172
26760
  return { created: false };
26173
26761
  }
26174
- const lead2 = await findLeadAgent2();
26762
+ const lead2 = await findLeadAgent3();
26175
26763
  const result2 = resolveTemplate("github.pull_request.assigned", {
26176
26764
  pr_number: pr.number,
26177
26765
  pr_title: pr.title,
@@ -26207,9 +26795,7 @@ async function handlePullRequest(event) {
26207
26795
  } else {
26208
26796
  console.log(`[GitHub] Created unassigned task ${task2.id} for PR #${pr.number} (assigned, no lead available)`);
26209
26797
  }
26210
- if (installation?.id) {
26211
- addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26212
- }
26798
+ addEyesReactionToTaskSource(task2).catch(() => {});
26213
26799
  return { created: true, taskId: task2.id };
26214
26800
  }
26215
26801
  if (action === "unassigned") {
@@ -26237,7 +26823,7 @@ async function handlePullRequest(event) {
26237
26823
  return { created: false };
26238
26824
  }
26239
26825
  const eventKey2 = `pr-review-requested:${repository.full_name}:${pr.number}`;
26240
- if (isDuplicate2(eventKey2)) {
26826
+ if (isDuplicate3(eventKey2)) {
26241
26827
  return { created: false };
26242
26828
  }
26243
26829
  const existingTask = await findTaskByVcs(repository.full_name, pr.number);
@@ -26245,7 +26831,7 @@ async function handlePullRequest(event) {
26245
26831
  console.log(`[GitHub] Skipping review task for PR #${pr.number} — active task ${existingTask.id} already exists`);
26246
26832
  return { created: false };
26247
26833
  }
26248
- const lead2 = await findLeadAgent2();
26834
+ const lead2 = await findLeadAgent3();
26249
26835
  const result2 = resolveTemplate("github.pull_request.review_requested", {
26250
26836
  pr_number: pr.number,
26251
26837
  pr_title: pr.title,
@@ -26281,9 +26867,7 @@ async function handlePullRequest(event) {
26281
26867
  } else {
26282
26868
  console.log(`[GitHub] Created unassigned task ${task2.id} for PR #${pr.number} (review requested, no lead available)`);
26283
26869
  }
26284
- if (installation?.id) {
26285
- addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26286
- }
26870
+ addEyesReactionToTaskSource(task2).catch(() => {});
26287
26871
  return { created: true, taskId: task2.id };
26288
26872
  }
26289
26873
  if (action === "review_request_removed") {
@@ -26312,10 +26896,10 @@ async function handlePullRequest(event) {
26312
26896
  return { created: false };
26313
26897
  }
26314
26898
  const eventKey2 = `pr-labeled:${repository.full_name}:${pr.number}:${labelName}`;
26315
- if (isDuplicate2(eventKey2)) {
26899
+ if (isDuplicate3(eventKey2)) {
26316
26900
  return { created: false };
26317
26901
  }
26318
- const lead2 = await findLeadAgent2();
26902
+ const lead2 = await findLeadAgent3();
26319
26903
  const result2 = resolveTemplate("github.pull_request.labeled", {
26320
26904
  pr_number: pr.number,
26321
26905
  pr_title: pr.title,
@@ -26351,9 +26935,7 @@ async function handlePullRequest(event) {
26351
26935
  } else {
26352
26936
  console.log(`[GitHub] Created unassigned task ${task2.id} for PR #${pr.number} (labeled: ${labelName}, no lead available)`);
26353
26937
  }
26354
- if (installation?.id) {
26355
- addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26356
- }
26938
+ addEyesReactionToTaskSource(task2).catch(() => {});
26357
26939
  return { created: true, taskId: task2.id };
26358
26940
  }
26359
26941
  if (action === "closed") {
@@ -26367,16 +26949,16 @@ async function handlePullRequest(event) {
26367
26949
  if (action !== "opened" && action !== "edited") {
26368
26950
  return { created: false };
26369
26951
  }
26370
- const hasMention = detectMention(pr.title) || detectMention(pr.body);
26952
+ const hasMention = detectMention2(pr.title) || detectMention2(pr.body);
26371
26953
  if (!hasMention) {
26372
26954
  return { created: false };
26373
26955
  }
26374
26956
  const eventKey = `pr:${repository.full_name}:${pr.number}:${action}`;
26375
- if (isDuplicate2(eventKey)) {
26957
+ if (isDuplicate3(eventKey)) {
26376
26958
  return { created: false };
26377
26959
  }
26378
- const lead = await findLeadAgent2();
26379
- const context = extractMentionContext(pr.body) || pr.title;
26960
+ const lead = await findLeadAgent3();
26961
+ const context = extractMentionContext2(pr.body) || pr.title;
26380
26962
  const result = resolveTemplate("github.pull_request.mentioned", {
26381
26963
  pr_number: pr.number,
26382
26964
  pr_title: pr.title,
@@ -26411,9 +26993,7 @@ async function handlePullRequest(event) {
26411
26993
  } else {
26412
26994
  console.log(`[GitHub] Created unassigned task ${task.id} for PR #${pr.number} (no lead available)`);
26413
26995
  }
26414
- if (installation?.id) {
26415
- addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26416
- }
26996
+ addEyesReactionToTaskSource(task).catch(() => {});
26417
26997
  return { created: true, taskId: task.id };
26418
26998
  }
26419
26999
  async function handleIssue(event) {
@@ -26424,10 +27004,10 @@ async function handleIssue(event) {
26424
27004
  return { created: false };
26425
27005
  }
26426
27006
  const eventKey2 = `issue-assigned:${repository.full_name}:${issue.number}`;
26427
- if (isDuplicate2(eventKey2)) {
27007
+ if (isDuplicate3(eventKey2)) {
26428
27008
  return { created: false };
26429
27009
  }
26430
- const lead2 = await findLeadAgent2();
27010
+ const lead2 = await findLeadAgent3();
26431
27011
  const result2 = resolveTemplate("github.issue.assigned", {
26432
27012
  issue_number: issue.number,
26433
27013
  issue_title: issue.title,
@@ -26461,9 +27041,7 @@ async function handleIssue(event) {
26461
27041
  } else {
26462
27042
  console.log(`[GitHub] Created unassigned task ${task2.id} for issue #${issue.number} (assigned, no lead available)`);
26463
27043
  }
26464
- if (installation?.id) {
26465
- addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26466
- }
27044
+ addEyesReactionToTaskSource(task2).catch(() => {});
26467
27045
  return { created: true, taskId: task2.id };
26468
27046
  }
26469
27047
  if (action === "unassigned") {
@@ -26492,10 +27070,10 @@ async function handleIssue(event) {
26492
27070
  return { created: false };
26493
27071
  }
26494
27072
  const eventKey2 = `issue-labeled:${repository.full_name}:${issue.number}:${labelName}`;
26495
- if (isDuplicate2(eventKey2)) {
27073
+ if (isDuplicate3(eventKey2)) {
26496
27074
  return { created: false };
26497
27075
  }
26498
- const lead2 = await findLeadAgent2();
27076
+ const lead2 = await findLeadAgent3();
26499
27077
  const result2 = resolveTemplate("github.issue.labeled", {
26500
27078
  issue_number: issue.number,
26501
27079
  issue_title: issue.title,
@@ -26529,24 +27107,22 @@ async function handleIssue(event) {
26529
27107
  } else {
26530
27108
  console.log(`[GitHub] Created unassigned task ${task2.id} for issue #${issue.number} (labeled: ${labelName}, no lead available)`);
26531
27109
  }
26532
- if (installation?.id) {
26533
- addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26534
- }
27110
+ addEyesReactionToTaskSource(task2).catch(() => {});
26535
27111
  return { created: true, taskId: task2.id };
26536
27112
  }
26537
27113
  if (action !== "opened" && action !== "edited") {
26538
27114
  return { created: false };
26539
27115
  }
26540
- const hasMention = detectMention(issue.title) || detectMention(issue.body);
27116
+ const hasMention = detectMention2(issue.title) || detectMention2(issue.body);
26541
27117
  if (!hasMention) {
26542
27118
  return { created: false };
26543
27119
  }
26544
27120
  const eventKey = `issue:${repository.full_name}:${issue.number}:${action}`;
26545
- if (isDuplicate2(eventKey)) {
27121
+ if (isDuplicate3(eventKey)) {
26546
27122
  return { created: false };
26547
27123
  }
26548
- const lead = await findLeadAgent2();
26549
- const context = extractMentionContext(issue.body) || issue.title;
27124
+ const lead = await findLeadAgent3();
27125
+ const context = extractMentionContext2(issue.body) || issue.title;
26550
27126
  const result = resolveTemplate("github.issue.mentioned", {
26551
27127
  issue_number: issue.number,
26552
27128
  issue_title: issue.title,
@@ -26579,9 +27155,7 @@ async function handleIssue(event) {
26579
27155
  } else {
26580
27156
  console.log(`[GitHub] Created unassigned task ${task.id} for issue #${issue.number} (no lead available)`);
26581
27157
  }
26582
- if (installation?.id) {
26583
- addIssueReaction(repository.full_name, issue.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26584
- }
27158
+ addEyesReactionToTaskSource(task).catch(() => {});
26585
27159
  return { created: true, taskId: task.id };
26586
27160
  }
26587
27161
  async function handleComment(event, eventType) {
@@ -26590,21 +27164,21 @@ async function handleComment(event, eventType) {
26590
27164
  if (action !== "created") {
26591
27165
  return { created: false };
26592
27166
  }
26593
- if (!detectMention(comment.body)) {
27167
+ if (!detectMention2(comment.body)) {
26594
27168
  return { created: false };
26595
27169
  }
26596
27170
  const eventKey = `comment:${repository.full_name}:${comment.id}`;
26597
- if (isDuplicate2(eventKey)) {
27171
+ if (isDuplicate3(eventKey)) {
26598
27172
  return { created: false };
26599
27173
  }
26600
- const lead = await findLeadAgent2();
27174
+ const lead = await findLeadAgent3();
26601
27175
  const target = pull_request || issue;
26602
27176
  const targetType = pull_request ? "PR" : "Issue";
26603
27177
  const targetNumber = target?.number ?? 0;
26604
27178
  const targetTitle = target?.title ?? "Unknown";
26605
27179
  const targetUrl = target?.html_url ?? comment.html_url;
26606
27180
  const existingTask = targetNumber ? await findTaskByVcs(repository.full_name, targetNumber) : null;
26607
- const context = extractMentionContext(comment.body);
27181
+ const context = extractMentionContext2(comment.body);
26608
27182
  const suggestions = getCommandSuggestions("github-comment", targetType);
26609
27183
  const relatedTaskSection = existingTask ? `Related task: ${existingTask.id}
26610
27184
  \uD83D\uDD00 Consider routing to the same agent working on the related task.
@@ -26646,9 +27220,7 @@ async function handleComment(event, eventType) {
26646
27220
  } else {
26647
27221
  console.log(`[GitHub] Created unassigned task ${task.id} for comment on #${targetNumber} (no lead available)`);
26648
27222
  }
26649
- if (installation?.id) {
26650
- addReaction(repository.full_name, comment.id, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add comment reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26651
- }
27223
+ addEyesReactionToTaskSource(task).catch(() => {});
26652
27224
  return { created: true, taskId: task.id };
26653
27225
  }
26654
27226
  function parseNextPageLink(linkHeader) {
@@ -26667,12 +27239,12 @@ function buildReviewCommentsHeaders(token) {
26667
27239
  "X-GitHub-Api-Version": "2022-11-28"
26668
27240
  };
26669
27241
  }
26670
- async function fetchPaginatedReviewComments(initialUrl, headers) {
27242
+ async function fetchPaginatedReviewComments(initialUrl, headers2) {
26671
27243
  const allComments = [];
26672
27244
  let url = initialUrl;
26673
27245
  try {
26674
27246
  while (url) {
26675
- const response = await fetch(url, { headers });
27247
+ const response = await fetch(url, { headers: headers2 });
26676
27248
  if (!response.ok) {
26677
27249
  console.error(`[GitHub] Failed to fetch review inline comments: ${response.status}`);
26678
27250
  return { comments: allComments, degraded: true };
@@ -26689,24 +27261,24 @@ async function fetchPaginatedReviewComments(initialUrl, headers) {
26689
27261
  return { comments: allComments, degraded: true };
26690
27262
  }
26691
27263
  }
26692
- async function fetchReviewScopedComments(repo, prNumber, reviewId, headers) {
27264
+ async function fetchReviewScopedComments(repo, prNumber, reviewId, headers2) {
26693
27265
  const url = `https://api.github.com/repos/${repo}/pulls/${prNumber}/reviews/${reviewId}/comments?per_page=100`;
26694
- let result = await fetchPaginatedReviewComments(url, headers);
27266
+ let result = await fetchPaginatedReviewComments(url, headers2);
26695
27267
  if (result.degraded || result.comments.length > 0) {
26696
27268
  return result;
26697
27269
  }
26698
27270
  for (const delayMs of REVIEW_COMMENTS_EMPTY_RETRY_DELAYS_MS) {
26699
27271
  await reviewCommentsRetryDelay(delayMs);
26700
- result = await fetchPaginatedReviewComments(url, headers);
27272
+ result = await fetchPaginatedReviewComments(url, headers2);
26701
27273
  if (result.degraded || result.comments.length > 0) {
26702
27274
  return result;
26703
27275
  }
26704
27276
  }
26705
27277
  return result;
26706
27278
  }
26707
- async function fetchPrLevelReviewComments(repo, prNumber, reviewId, headers) {
27279
+ async function fetchPrLevelReviewComments(repo, prNumber, reviewId, headers2) {
26708
27280
  const url = `https://api.github.com/repos/${repo}/pulls/${prNumber}/comments?per_page=100`;
26709
- const result = await fetchPaginatedReviewComments(url, headers);
27281
+ const result = await fetchPaginatedReviewComments(url, headers2);
26710
27282
  return {
26711
27283
  comments: result.comments.filter((comment) => comment.pull_request_review_id === reviewId),
26712
27284
  degraded: result.degraded
@@ -26726,12 +27298,12 @@ async function fetchReviewComments(repo, prNumber, reviewId, installationId) {
26726
27298
  if (!token) {
26727
27299
  return { comments: [], degraded: true };
26728
27300
  }
26729
- const headers = buildReviewCommentsHeaders(token);
26730
- const scopedResult = await fetchReviewScopedComments(repo, prNumber, reviewId, headers);
27301
+ const headers2 = buildReviewCommentsHeaders(token);
27302
+ const scopedResult = await fetchReviewScopedComments(repo, prNumber, reviewId, headers2);
26731
27303
  if (!scopedResult.degraded && scopedResult.comments.length > 0) {
26732
27304
  return scopedResult;
26733
27305
  }
26734
- const fallbackResult = await fetchPrLevelReviewComments(repo, prNumber, reviewId, headers);
27306
+ const fallbackResult = await fetchPrLevelReviewComments(repo, prNumber, reviewId, headers2);
26735
27307
  const mergedComments = dedupeReviewComments([
26736
27308
  ...scopedResult.comments,
26737
27309
  ...fallbackResult.comments
@@ -26782,7 +27354,7 @@ async function handlePullRequestReview(event) {
26782
27354
  return { created: false };
26783
27355
  }
26784
27356
  const eventKey = `pr-review:${repository.full_name}:${pr.number}:${review.id}`;
26785
- if (isDuplicate2(eventKey)) {
27357
+ if (isDuplicate3(eventKey)) {
26786
27358
  return { created: false };
26787
27359
  }
26788
27360
  const { comments: inlineComments, degraded } = installation?.id ? await fetchReviewComments(repository.full_name, pr.number, review.id, installation.id) : { comments: [], degraded: true };
@@ -26794,7 +27366,7 @@ async function handlePullRequestReview(event) {
26794
27366
  if (!isBotCreator && !existingTask) {
26795
27367
  return { created: false };
26796
27368
  }
26797
- const lead = await findLeadAgent2();
27369
+ const lead = await findLeadAgent3();
26798
27370
  const { emoji, label } = getReviewStateInfo(review.state);
26799
27371
  const reviewBodySection = review.body ? `
26800
27372
 
@@ -26846,9 +27418,7 @@ ${review.body}` : "";
26846
27418
  } else {
26847
27419
  console.log(`[GitHub] Created unassigned task ${task.id} for PR #${pr.number} review (${review.state}, no lead available)`);
26848
27420
  }
26849
- if (installation?.id) {
26850
- addIssueReaction(repository.full_name, pr.number, "eyes", installation.id).catch((err) => console.error("[GitHub] failed to add issue reaction:", scrubSecrets(err instanceof Error ? err.message : String(err))));
26851
- }
27421
+ addEyesReactionToTaskSource(task).catch(() => {});
26852
27422
  return { created: true, taskId: task.id };
26853
27423
  }
26854
27424
  async function handleCheckRun(event) {
@@ -26871,46 +27441,46 @@ async function handleWorkflowRun(event) {
26871
27441
  }
26872
27442
  // src/gitlab/auth.ts
26873
27443
  init_env_flag();
26874
- var initialized3 = false;
26875
- var webhookSecret3 = null;
26876
- var apiToken = null;
27444
+ var initialized4 = false;
27445
+ var webhookSecret4 = null;
27446
+ var apiToken2 = null;
26877
27447
  var gitlabUrl = "https://gitlab.com";
26878
27448
  function isGitLabEnabled() {
26879
27449
  return !!process.env.GITLAB_WEBHOOK_SECRET && !isEnvFlagEnabled("GITLAB_DISABLE", false);
26880
27450
  }
26881
27451
  function initGitLab() {
26882
- if (initialized3)
27452
+ if (initialized4)
26883
27453
  return;
26884
27454
  if (!isGitLabEnabled()) {
26885
27455
  console.log("[GitLab] Integration disabled (GITLAB_WEBHOOK_SECRET not set)");
26886
27456
  return;
26887
27457
  }
26888
- webhookSecret3 = process.env.GITLAB_WEBHOOK_SECRET;
26889
- apiToken = process.env.GITLAB_TOKEN ?? null;
27458
+ webhookSecret4 = process.env.GITLAB_WEBHOOK_SECRET;
27459
+ apiToken2 = process.env.GITLAB_TOKEN ?? null;
26890
27460
  gitlabUrl = process.env.GITLAB_URL ?? "https://gitlab.com";
26891
- initialized3 = true;
27461
+ initialized4 = true;
26892
27462
  console.log(`[GitLab] Integration initialized (url: ${gitlabUrl})`);
26893
27463
  }
26894
27464
  function verifyGitLabWebhook(tokenHeader) {
26895
- if (!webhookSecret3)
27465
+ if (!webhookSecret4)
26896
27466
  return false;
26897
27467
  if (!tokenHeader)
26898
27468
  return false;
26899
- if (tokenHeader.length !== webhookSecret3.length)
27469
+ if (tokenHeader.length !== webhookSecret4.length)
26900
27470
  return false;
26901
- return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(webhookSecret3));
27471
+ return crypto.timingSafeEqual(Buffer.from(tokenHeader), Buffer.from(webhookSecret4));
26902
27472
  }
26903
27473
  function getGitLabToken() {
26904
- return apiToken;
27474
+ return apiToken2;
26905
27475
  }
26906
27476
  function getGitLabUrl() {
26907
27477
  return gitlabUrl;
26908
27478
  }
26909
27479
  var GITLAB_BOT_NAME = process.env.GITLAB_BOT_NAME ?? "agent-swarm-bot";
26910
27480
  function resetGitLab() {
26911
- initialized3 = false;
26912
- webhookSecret3 = null;
26913
- apiToken = null;
27481
+ initialized4 = false;
27482
+ webhookSecret4 = null;
27483
+ apiToken2 = null;
26914
27484
  gitlabUrl = "https://gitlab.com";
26915
27485
  }
26916
27486
  // src/gitlab/handlers.ts
@@ -26919,7 +27489,7 @@ init_resolver();
26919
27489
  init_context_key();
26920
27490
 
26921
27491
  // src/gitlab/reactions.ts
26922
- function headers() {
27492
+ function headers2() {
26923
27493
  const token = getGitLabToken();
26924
27494
  if (!token)
26925
27495
  throw new Error("[GitLab] No API token configured");
@@ -26940,7 +27510,7 @@ async function addGitLabReaction(project, entityType, iid, emojiName) {
26940
27510
  try {
26941
27511
  const resp = await fetch(url, {
26942
27512
  method: "POST",
26943
- headers: headers(),
27513
+ headers: headers2(),
26944
27514
  body: JSON.stringify({ name: emojiName })
26945
27515
  });
26946
27516
  if (!resp.ok) {
@@ -26956,7 +27526,7 @@ async function addGitLabNoteReaction(project, entityType, iid, noteId, emojiName
26956
27526
  try {
26957
27527
  const resp = await fetch(url, {
26958
27528
  method: "POST",
26959
- headers: headers(),
27529
+ headers: headers2(),
26960
27530
  body: JSON.stringify({ name: emojiName })
26961
27531
  });
26962
27532
  if (!resp.ok) {
@@ -27080,33 +27650,33 @@ The CI pipeline has failed. Please investigate and fix the issues.{{@template[co
27080
27650
  });
27081
27651
 
27082
27652
  // src/gitlab/handlers.ts
27083
- var processedEvents3 = new Map;
27084
- var DEDUP_TTL_MS = 60000;
27085
- function isDuplicate3(key) {
27653
+ var processedEvents4 = new Map;
27654
+ var DEDUP_TTL_MS2 = 60000;
27655
+ function isDuplicate4(key) {
27086
27656
  const now = Date.now();
27087
- for (const [k, ts] of processedEvents3) {
27088
- if (now - ts > DEDUP_TTL_MS)
27089
- processedEvents3.delete(k);
27657
+ for (const [k, ts] of processedEvents4) {
27658
+ if (now - ts > DEDUP_TTL_MS2)
27659
+ processedEvents4.delete(k);
27090
27660
  }
27091
- if (processedEvents3.has(key))
27661
+ if (processedEvents4.has(key))
27092
27662
  return true;
27093
- processedEvents3.set(key, now);
27663
+ processedEvents4.set(key, now);
27094
27664
  return false;
27095
27665
  }
27096
- function detectMention2(text) {
27666
+ function detectMention3(text) {
27097
27667
  if (!text)
27098
27668
  return false;
27099
27669
  return new RegExp(`@${GITLAB_BOT_NAME}\\b`, "i").test(text);
27100
27670
  }
27101
- function extractMentionContext2(text) {
27671
+ function extractMentionContext3(text) {
27102
27672
  return text.replace(new RegExp(`@${GITLAB_BOT_NAME}\\b`, "gi"), "").trim();
27103
27673
  }
27104
- async function findLeadAgent3() {
27674
+ async function findLeadAgent4() {
27105
27675
  const agents = await getAllAgents();
27106
27676
  return agents.find((a) => a.role === "lead" && a.status === "idle") ?? agents.find((a) => a.role === "lead") ?? null;
27107
27677
  }
27108
- var UNMAPPED_NAMESPACE2 = "integration:unmapped:gitlab";
27109
- var UNMAPPED_TTL_MS2 = 30 * 24 * 60 * 60 * 1000;
27678
+ var UNMAPPED_NAMESPACE3 = "integration:unmapped:gitlab";
27679
+ var UNMAPPED_TTL_MS3 = 30 * 24 * 60 * 60 * 1000;
27110
27680
  var GITLAB_WEBHOOK_ACTOR = { kind: "system", id: "webhook:gitlab" };
27111
27681
  async function resolveGitLabSender(user, sampleEventType, sampleContext) {
27112
27682
  const existing = await findUserByExternalId("gitlab", user.username);
@@ -27119,7 +27689,7 @@ async function resolveGitLabSender(user, sampleEventType, sampleContext) {
27119
27689
  return linked.id;
27120
27690
  }
27121
27691
  await upsertKv({
27122
- namespace: UNMAPPED_NAMESPACE2,
27692
+ namespace: UNMAPPED_NAMESPACE3,
27123
27693
  key: `${user.username}:meta`,
27124
27694
  value: {
27125
27695
  lastSeenAt: new Date().toISOString(),
@@ -27127,9 +27697,9 @@ async function resolveGitLabSender(user, sampleEventType, sampleContext) {
27127
27697
  sampleContext: sampleContext.slice(0, 100)
27128
27698
  },
27129
27699
  valueType: "json",
27130
- expiresAt: Date.now() + UNMAPPED_TTL_MS2
27700
+ expiresAt: Date.now() + UNMAPPED_TTL_MS3
27131
27701
  });
27132
- await incrKv(UNMAPPED_NAMESPACE2, `${user.username}:count`, 1);
27702
+ await incrKv(UNMAPPED_NAMESPACE3, `${user.username}:count`, 1);
27133
27703
  return;
27134
27704
  }
27135
27705
  async function renderGitLabIdentity(username) {
@@ -27142,19 +27712,19 @@ async function handleMergeRequest(event) {
27142
27712
  const requestedByUserId = await resolveGitLabSender(user, "merge_request", `MR !${mr.iid}: ${mr.title}`);
27143
27713
  console.log(`[GitLab] MR #${mr.iid} ${action} by ${user.username} in ${repo}`);
27144
27714
  const dedupKey = `gitlab-mr-${repo}-${mr.iid}-${action}-${user.username}`;
27145
- if (isDuplicate3(dedupKey)) {
27715
+ if (isDuplicate4(dedupKey)) {
27146
27716
  console.log(`[GitLab] Skipping duplicate MR event`);
27147
27717
  return { created: false };
27148
27718
  }
27149
- const lead = await findLeadAgent3();
27719
+ const lead = await findLeadAgent4();
27150
27720
  switch (action) {
27151
27721
  case "open": {
27152
- const hasMention = detectMention2(mr.description);
27722
+ const hasMention = detectMention3(mr.description);
27153
27723
  if (!hasMention) {
27154
27724
  console.log(`[GitLab] MR opened without bot mention, skipping`);
27155
27725
  return { created: false };
27156
27726
  }
27157
- const context = mr.description ? extractMentionContext2(mr.description) : "";
27727
+ const context = mr.description ? extractMentionContext3(mr.description) : "";
27158
27728
  const contextSection = context ? `Context: ${context}
27159
27729
 
27160
27730
  ` : "";
@@ -27226,13 +27796,13 @@ async function handleIssue2(event) {
27226
27796
  const requestedByUserId = await resolveGitLabSender(user, "issue", `Issue #${issue.iid}: ${issue.title}`);
27227
27797
  console.log(`[GitLab] Issue #${issue.iid} ${action} by ${user.username} in ${repo}`);
27228
27798
  const dedupKey = `gitlab-issue-${repo}-${issue.iid}-${action}-${user.username}`;
27229
- if (isDuplicate3(dedupKey)) {
27799
+ if (isDuplicate4(dedupKey)) {
27230
27800
  return { created: false };
27231
27801
  }
27232
- const lead = await findLeadAgent3();
27802
+ const lead = await findLeadAgent4();
27233
27803
  switch (action) {
27234
27804
  case "open": {
27235
- const hasMention = detectMention2(issue.description);
27805
+ const hasMention = detectMention3(issue.description);
27236
27806
  if (!hasMention) {
27237
27807
  const isBotAssigned = event.assignees?.some((a) => a.username.toLowerCase() === GITLAB_BOT_NAME.toLowerCase());
27238
27808
  if (!isBotAssigned) {
@@ -27240,7 +27810,7 @@ async function handleIssue2(event) {
27240
27810
  return { created: false };
27241
27811
  }
27242
27812
  }
27243
- const context = issue.description ? extractMentionContext2(issue.description) : "";
27813
+ const context = issue.description ? extractMentionContext3(issue.description) : "";
27244
27814
  const contextSection = context ? `Context: ${context}
27245
27815
 
27246
27816
  ` : "";
@@ -27296,16 +27866,16 @@ async function handleNote(event) {
27296
27866
  const { user, project, object_attributes: note } = event;
27297
27867
  const repo = project.path_with_namespace;
27298
27868
  const requestedByUserId = await resolveGitLabSender(user, "note", note.note);
27299
- if (!detectMention2(note.note)) {
27869
+ if (!detectMention3(note.note)) {
27300
27870
  return { created: false };
27301
27871
  }
27302
27872
  console.log(`[GitLab] Note by ${user.username} in ${repo} (${note.noteable_type})`);
27303
27873
  const dedupKey = `gitlab-note-${note.id}`;
27304
- if (isDuplicate3(dedupKey)) {
27874
+ if (isDuplicate4(dedupKey)) {
27305
27875
  return { created: false };
27306
27876
  }
27307
- const lead = await findLeadAgent3();
27308
- const context = extractMentionContext2(note.note);
27877
+ const lead = await findLeadAgent4();
27878
+ const context = extractMentionContext3(note.note);
27309
27879
  let targetNumber;
27310
27880
  let targetUrl;
27311
27881
  let eventType;
@@ -27379,14 +27949,14 @@ async function handlePipeline(event) {
27379
27949
  }
27380
27950
  const mrIid = event.merge_request.iid;
27381
27951
  const dedupKey = `gitlab-pipeline-${pipeline2.id}`;
27382
- if (isDuplicate3(dedupKey)) {
27952
+ if (isDuplicate4(dedupKey)) {
27383
27953
  return { created: false };
27384
27954
  }
27385
27955
  const existingTask = await findTaskByVcs(repo, mrIid);
27386
27956
  if (!existingTask) {
27387
27957
  return { created: false };
27388
27958
  }
27389
- const lead = await findLeadAgent3();
27959
+ const lead = await findLeadAgent4();
27390
27960
  const pipelineResult = resolveTemplate("gitlab.pipeline.failed", {
27391
27961
  pipeline_id: pipeline2.id,
27392
27962
  mr_iid: mrIid,
@@ -27748,14 +28318,14 @@ async function jiraFetch(path, init) {
27748
28318
  const send = async (token2) => {
27749
28319
  const cloudId = await getJiraCloudId();
27750
28320
  const url = `https://api.atlassian.com/ex/jira/${cloudId}${path}`;
27751
- const headers2 = new Headers(init?.headers);
27752
- headers2.set("Authorization", `Bearer ${token2}`);
27753
- if (!headers2.has("Accept"))
27754
- headers2.set("Accept", "application/json");
27755
- if (init?.body && !headers2.has("Content-Type")) {
27756
- headers2.set("Content-Type", "application/json");
27757
- }
27758
- return fetch(url, { ...init, headers: headers2 });
28321
+ const headers3 = new Headers(init?.headers);
28322
+ headers3.set("Authorization", `Bearer ${token2}`);
28323
+ if (!headers3.has("Accept"))
28324
+ headers3.set("Accept", "application/json");
28325
+ if (init?.body && !headers3.has("Content-Type")) {
28326
+ headers3.set("Content-Type", "application/json");
28327
+ }
28328
+ return fetch(url, { ...init, headers: headers3 });
27759
28329
  };
27760
28330
  let token = await getJiraAccessToken();
27761
28331
  let response = await send(token);
@@ -28079,7 +28649,7 @@ async function resolveBotAccountId() {
28079
28649
  function resetBotAccountIdCache() {
28080
28650
  setCachedBotAccountId(null);
28081
28651
  }
28082
- async function findLeadAgent4() {
28652
+ async function findLeadAgent5() {
28083
28653
  const agents = await getAllAgents();
28084
28654
  const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
28085
28655
  if (onlineLead)
@@ -28283,7 +28853,7 @@ async function handleIssueDeleteEvent(event) {
28283
28853
  }
28284
28854
  }
28285
28855
  async function createInitialJiraTask(input) {
28286
- const lead = await findLeadAgent4();
28856
+ const lead = await findLeadAgent5();
28287
28857
  const descriptionSection = input.descriptionText ? `
28288
28858
  Description:
28289
28859
  ${input.descriptionText}
@@ -28321,7 +28891,7 @@ ${input.descriptionText}
28321
28891
  console.log(`[Jira Sync] Created ${action} task ${task.id} for ${input.issueKey} -> ${lead?.name ?? "unassigned"}`);
28322
28892
  }
28323
28893
  async function createCommentMentionTask(input) {
28324
- const lead = await findLeadAgent4();
28894
+ const lead = await findLeadAgent5();
28325
28895
  const descriptionSection = input.descriptionText ? `
28326
28896
  Description:
28327
28897
  ${input.descriptionText}
@@ -28381,7 +28951,7 @@ async function notifySlack(text) {
28381
28951
  return;
28382
28952
  }
28383
28953
  try {
28384
- const { getSlackApp: getSlackApp2 } = await import("./app-y1b9srva.js");
28954
+ const { getSlackApp: getSlackApp2 } = await import("./app-0hdqa4k1.js");
28385
28955
  const app = getSlackApp2();
28386
28956
  if (!app) {
28387
28957
  console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
@@ -28452,7 +29022,7 @@ async function deleteJiraWebhook(webhookId) {
28452
29022
  console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
28453
29023
  }
28454
29024
  async function overwriteWebhookIds(next) {
28455
- const { getDbClient: getDbClient2 } = await import("./db-s3znhvbn.js");
29025
+ const { getDbClient: getDbClient2 } = await import("./db-d2pvjpyt.js");
28456
29026
  await getDbClient2().transaction(async (tx) => {
28457
29027
  const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
28458
29028
  if (!row) {
@@ -28559,7 +29129,7 @@ function stopJiraWebhookKeepalive() {
28559
29129
  }
28560
29130
 
28561
29131
  // src/jira/app.ts
28562
- var initialized4 = false;
29132
+ var initialized5 = false;
28563
29133
  function isJiraEnabled() {
28564
29134
  const disabled = process.env.JIRA_DISABLE;
28565
29135
  if (disabled === "true" || disabled === "1")
@@ -28573,12 +29143,12 @@ function resetJira() {
28573
29143
  resetBotAccountIdCache();
28574
29144
  teardownJiraOutboundSync();
28575
29145
  stopJiraWebhookKeepalive();
28576
- initialized4 = false;
29146
+ initialized5 = false;
28577
29147
  }
28578
29148
  async function initJira() {
28579
- if (initialized4)
29149
+ if (initialized5)
28580
29150
  return isJiraEnabled();
28581
- initialized4 = true;
29151
+ initialized5 = true;
28582
29152
  if (!isJiraEnabled()) {
28583
29153
  console.log("[Jira] Integration disabled or JIRA_CLIENT_ID not set");
28584
29154
  return false;
@@ -28799,14 +29369,14 @@ var InvalidInputLinearError = class extends LinearError {
28799
29369
  var RatelimitedLinearError = class extends LinearError {
28800
29370
  constructor(error, errors) {
28801
29371
  super(error, errors, LinearErrorType.Ratelimited);
28802
- const headers2 = error?.response?.headers;
28803
- this.retryAfter = this.parseNumber(headers2?.get("retry-after"));
28804
- this.requestsLimit = this.parseNumber(headers2?.get("x-ratelimit-requests-limit"));
28805
- this.requestsRemaining = this.parseNumber(headers2?.get("x-ratelimit-requests-remaining"));
28806
- this.requestsResetAt = this.parseNumber(headers2?.get("x-ratelimit-requests-reset"));
28807
- this.complexityLimit = this.parseNumber(headers2?.get("x-ratelimit-complexity-limit"));
28808
- this.complexityRemaining = this.parseNumber(headers2?.get("x-ratelimit-complexity-remaining"));
28809
- this.complexityResetAt = this.parseNumber(headers2?.get("x-ratelimit-complexity-reset"));
29372
+ const headers3 = error?.response?.headers;
29373
+ this.retryAfter = this.parseNumber(headers3?.get("retry-after"));
29374
+ this.requestsLimit = this.parseNumber(headers3?.get("x-ratelimit-requests-limit"));
29375
+ this.requestsRemaining = this.parseNumber(headers3?.get("x-ratelimit-requests-remaining"));
29376
+ this.requestsResetAt = this.parseNumber(headers3?.get("x-ratelimit-requests-reset"));
29377
+ this.complexityLimit = this.parseNumber(headers3?.get("x-ratelimit-complexity-limit"));
29378
+ this.complexityRemaining = this.parseNumber(headers3?.get("x-ratelimit-complexity-remaining"));
29379
+ this.complexityResetAt = this.parseNumber(headers3?.get("x-ratelimit-complexity-reset"));
28810
29380
  }
28811
29381
  retryAfter;
28812
29382
  requestsLimit;
@@ -29829,7 +30399,7 @@ var LinearGraphQLClient = class {
29829
30399
  this.options = options || {};
29830
30400
  }
29831
30401
  async rawRequest(query, variables, requestHeaders) {
29832
- const { headers: headers2, ...others } = this.options;
30402
+ const { headers: headers3, ...others } = this.options;
29833
30403
  const body = JSON.stringify({
29834
30404
  query,
29835
30405
  variables
@@ -29839,7 +30409,7 @@ var LinearGraphQLClient = class {
29839
30409
  method: "POST",
29840
30410
  headers: {
29841
30411
  ...typeof body === "string" ? { "Content-Type": "application/json" } : {},
29842
- ...resolveHeaders(headers2),
30412
+ ...resolveHeaders(headers3),
29843
30413
  ...resolveHeaders(requestHeaders)
29844
30414
  },
29845
30415
  body,
@@ -29863,7 +30433,7 @@ var LinearGraphQLClient = class {
29863
30433
  }));
29864
30434
  }
29865
30435
  async request(document2, variables, requestHeaders) {
29866
- const { headers: headers2, ...others } = this.options;
30436
+ const { headers: headers3, ...others } = this.options;
29867
30437
  const query = typeof document2 === "string" ? document2 : (0, import_printer.print)(document2);
29868
30438
  const body = JSON.stringify({
29869
30439
  query,
@@ -29873,7 +30443,7 @@ var LinearGraphQLClient = class {
29873
30443
  method: "POST",
29874
30444
  headers: {
29875
30445
  ...typeof body === "string" ? { "Content-Type": "application/json" } : {},
29876
- ...resolveHeaders(headers2),
30446
+ ...resolveHeaders(headers3),
29877
30447
  ...resolveHeaders(requestHeaders)
29878
30448
  },
29879
30449
  body,
@@ -29892,14 +30462,14 @@ var LinearGraphQLClient = class {
29892
30462
  variables
29893
30463
  });
29894
30464
  }
29895
- setHeaders(headers2) {
29896
- this.options.headers = headers2;
30465
+ setHeaders(headers3) {
30466
+ this.options.headers = headers3;
29897
30467
  return this;
29898
30468
  }
29899
30469
  setHeader(key, value) {
29900
- const { headers: headers2 } = this.options;
29901
- if (headers2)
29902
- headers2[key] = value;
30470
+ const { headers: headers3 } = this.options;
30471
+ if (headers3)
30472
+ headers3[key] = value;
29903
30473
  else
29904
30474
  this.options.headers = { [key]: value };
29905
30475
  return this;
@@ -29912,22 +30482,22 @@ function getResult(response) {
29912
30482
  else
29913
30483
  return response.text();
29914
30484
  }
29915
- function resolveHeaders(headers2) {
30485
+ function resolveHeaders(headers3) {
29916
30486
  let oHeaders = {};
29917
- if (headers2)
29918
- if (typeof Headers !== "undefined" && headers2 instanceof Headers)
29919
- oHeaders = headersToObject(headers2);
29920
- else if (Array.isArray(headers2))
29921
- headers2.forEach(([name, value]) => {
30487
+ if (headers3)
30488
+ if (typeof Headers !== "undefined" && headers3 instanceof Headers)
30489
+ oHeaders = headersToObject(headers3);
30490
+ else if (Array.isArray(headers3))
30491
+ headers3.forEach(([name, value]) => {
29922
30492
  oHeaders[name] = value;
29923
30493
  });
29924
30494
  else
29925
- oHeaders = headers2;
30495
+ oHeaders = headers3;
29926
30496
  return oHeaders;
29927
30497
  }
29928
- function headersToObject(headers2) {
30498
+ function headersToObject(headers3) {
29929
30499
  const o = {};
29930
- headers2.forEach((v, k) => {
30500
+ headers3.forEach((v, k) => {
29931
30501
  o[k] = v;
29932
30502
  });
29933
30503
  return o;
@@ -93790,8 +94360,8 @@ var IssueVcsBranchSearchQuery = class extends Request2 {
93790
94360
  constructor(request) {
93791
94361
  super(request);
93792
94362
  }
93793
- async fetch(branchName) {
93794
- const data = (await this._request(IssueVcsBranchSearchDocument.toString(), { branchName })).issueVcsBranchSearch;
94363
+ async fetch(branchName2) {
94364
+ const data = (await this._request(IssueVcsBranchSearchDocument.toString(), { branchName: branchName2 })).issueVcsBranchSearch;
93795
94365
  return data ? new Issue(this._request, data) : undefined;
93796
94366
  }
93797
94367
  };
@@ -99124,8 +99694,8 @@ var LinearSdk = class extends Request2 {
99124
99694
  issueTitleSuggestionFromCustomerRequest(request) {
99125
99695
  return new IssueTitleSuggestionFromCustomerRequestQuery(this._request).fetch(request);
99126
99696
  }
99127
- issueVcsBranchSearch(branchName) {
99128
- return new IssueVcsBranchSearchQuery(this._request).fetch(branchName);
99697
+ issueVcsBranchSearch(branchName2) {
99698
+ return new IssueVcsBranchSearchQuery(this._request).fetch(branchName2);
99129
99699
  }
99130
99700
  issues(variables) {
99131
99701
  return new IssuesQuery(this._request).fetch(variables);
@@ -100142,13 +100712,13 @@ var LinearSdk = class extends Request2 {
100142
100712
  return new UpdateWorkflowStateMutation(this._request).fetch(id, input);
100143
100713
  }
100144
100714
  };
100145
- function parseClientOptions({ apiKey, accessToken, apiUrl, headers: headers2, ...opts }) {
100715
+ function parseClientOptions({ apiKey, accessToken, apiUrl, headers: headers3, ...opts }) {
100146
100716
  if (!accessToken && !apiKey)
100147
100717
  throw new Error("No accessToken or apiKey provided to the LinearClient - create one here: https://linear.app/settings/account/security");
100148
100718
  return {
100149
100719
  headers: {
100150
100720
  Authorization: accessToken ? accessToken.startsWith("Bearer ") ? accessToken : `Bearer ${accessToken}` : apiKey ?? "",
100151
- ...headers2,
100721
+ ...headers3,
100152
100722
  "User-Agent": serializeUserAgent({ [process.env.npm_package_name ?? "@linear/sdk"]: process.env.npm_package_version ?? "unknown" })
100153
100723
  },
100154
100724
  apiUrl: apiUrl ?? "https://api.linear.app/graphql",
@@ -100464,15 +101034,15 @@ async function _fetchIssueGatingInfo(issueId) {
100464
101034
  const labelNames = (json.data?.issue?.labels?.nodes ?? []).map((n) => n?.name ?? "").filter((n) => n.length > 0);
100465
101035
  return { stateType, labelNames };
100466
101036
  }
100467
- async function findLeadAgent5() {
101037
+ async function findLeadAgent6() {
100468
101038
  const agents = await getAllAgents();
100469
101039
  const onlineLead = agents.find((a) => a.isLead && a.status !== "offline");
100470
101040
  if (onlineLead)
100471
101041
  return onlineLead;
100472
101042
  return agents.find((a) => a.isLead) ?? null;
100473
101043
  }
100474
- var UNMAPPED_NAMESPACE3 = "integration:unmapped:linear";
100475
- var UNMAPPED_TTL_MS3 = 30 * 24 * 60 * 60 * 1000;
101044
+ var UNMAPPED_NAMESPACE4 = "integration:unmapped:linear";
101045
+ var UNMAPPED_TTL_MS4 = 30 * 24 * 60 * 60 * 1000;
100476
101046
  var LINEAR_WEBHOOK_ACTOR = { kind: "system", id: "webhook:linear" };
100477
101047
  var APP_USER_ID_NAMESPACE = "integration:linear:bot-app-user-id";
100478
101048
  async function getStoredAppUserId(workspaceId) {
@@ -100503,7 +101073,7 @@ async function resolveLinearActor(linearUserId, email, name, workspaceId, sample
100503
101073
  return linked.id;
100504
101074
  }
100505
101075
  await upsertKv({
100506
- namespace: UNMAPPED_NAMESPACE3,
101076
+ namespace: UNMAPPED_NAMESPACE4,
100507
101077
  key: `${linearUserId}:meta`,
100508
101078
  value: {
100509
101079
  lastSeenAt: new Date().toISOString(),
@@ -100511,9 +101081,9 @@ async function resolveLinearActor(linearUserId, email, name, workspaceId, sample
100511
101081
  sampleContext: sampleContext ? sampleContext.slice(0, 100) : null
100512
101082
  },
100513
101083
  valueType: "json",
100514
- expiresAt: Date.now() + UNMAPPED_TTL_MS3
101084
+ expiresAt: Date.now() + UNMAPPED_TTL_MS4
100515
101085
  });
100516
- await incrKv(UNMAPPED_NAMESPACE3, `${linearUserId}:count`, 1);
101086
+ await incrKv(UNMAPPED_NAMESPACE4, `${linearUserId}:count`, 1);
100517
101087
  return;
100518
101088
  }
100519
101089
  async function handleAgentSessionEvent(event) {
@@ -100584,7 +101154,7 @@ async function handleAgentSessionEvent(event) {
100584
101154
  }
100585
101155
  return;
100586
101156
  }
100587
- const lead = await findLeadAgent5();
101157
+ const lead = await findLeadAgent6();
100588
101158
  const sessionSection = sessionUrl ? `
100589
101159
  Session: ${sessionUrl}` : "";
100590
101160
  const descriptionSection = issueDescription ? `
@@ -100785,7 +101355,7 @@ async function handleAgentSessionPrompted(event) {
100785
101355
  return;
100786
101356
  }
100787
101357
  }
100788
- const lead = await findLeadAgent5();
101358
+ const lead = await findLeadAgent6();
100789
101359
  const activity = event.agentActivity;
100790
101360
  const promptUser = activity?.user;
100791
101361
  const promptedActorLinearId = promptUser ? String(promptUser.id ?? "") : "";
@@ -101067,7 +101637,7 @@ function shouldSkipForLoopPrevention2(sync) {
101067
101637
  }
101068
101638
 
101069
101639
  // src/linear/app.ts
101070
- var initialized5 = false;
101640
+ var initialized6 = false;
101071
101641
  var unsubscribeRefresh = null;
101072
101642
  function isLinearEnabled() {
101073
101643
  const disabled = process.env.LINEAR_DISABLE;
@@ -101084,12 +101654,12 @@ function resetLinear() {
101084
101654
  unsubscribeRefresh();
101085
101655
  unsubscribeRefresh = null;
101086
101656
  }
101087
- initialized5 = false;
101657
+ initialized6 = false;
101088
101658
  }
101089
101659
  async function initLinear() {
101090
- if (initialized5)
101660
+ if (initialized6)
101091
101661
  return isLinearEnabled();
101092
- initialized5 = true;
101662
+ initialized6 = true;
101093
101663
  if (!isLinearEnabled()) {
101094
101664
  console.log("[Linear] Integration disabled or LINEAR_CLIENT_ID not set");
101095
101665
  return false;
@@ -102184,7 +102754,7 @@ async function reloadGlobalConfigsAndIntegrations() {
102184
102754
  return runWithoutRequestAuth(() => reloadGlobalConfigsAndIntegrationsInner());
102185
102755
  }
102186
102756
  async function reloadGlobalConfigsAndIntegrationsInner() {
102187
- const { getEmbeddingProvider: getEmbeddingProvider2, resetEmbeddingProvider } = await import("./index-bjmjh9h4.js");
102757
+ const { getEmbeddingProvider: getEmbeddingProvider2, resetEmbeddingProvider } = await import("./index-k4nj18qs.js");
102188
102758
  const wasEmbeddingsConfigured = getEmbeddingProvider2().isConfigured();
102189
102759
  const updated = await loadGlobalConfigsIntoEnv(true);
102190
102760
  await stopSlackApp();
@@ -102197,10 +102767,10 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
102197
102767
  integrations.push("embeddings");
102198
102768
  }
102199
102769
  if (!wasEmbeddingsConfigured && isEmbeddingsConfigured) {
102200
- import("./boot-reembed-48d2qpkt.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
102770
+ import("./boot-reembed-gt5gjkt4.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
102201
102771
  console.error("[config-reload] memory backfill failed (non-fatal):", err);
102202
102772
  });
102203
- import("./boot-reembed-w0bryhkr.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
102773
+ import("./boot-reembed-xy9t7avg.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
102204
102774
  console.error("[config-reload] script backfill failed (non-fatal):", err);
102205
102775
  });
102206
102776
  }
@@ -102214,6 +102784,11 @@ async function reloadGlobalConfigsAndIntegrationsInner() {
102214
102784
  initGitLab();
102215
102785
  if (isGitLabEnabled())
102216
102786
  integrations.push("gitlab");
102787
+ resetAzureDevOps();
102788
+ resetAzureDevOpsBotIdCache();
102789
+ initAzureDevOps();
102790
+ if (isAzureDevOpsEnabled())
102791
+ integrations.push("azure-devops");
102217
102792
  resetLinear();
102218
102793
  if (await initLinear())
102219
102794
  integrations.push("linear");
@@ -103013,7 +103588,7 @@ function setPreloadedTools(server, names) {
103013
103588
  async function applyPreToolCall(name, args, requestInfo, inputSchema) {
103014
103589
  if (requestInfo.callOrigin !== "mcp")
103015
103590
  return { args };
103016
- const dispatcher = await import("./dispatcher-5xn0c7rf.js");
103591
+ const dispatcher = await import("./dispatcher-8wbwyzjg.js");
103017
103592
  const result = await dispatcher.dispatchPre("pre.tool.call", { tool: name, args, requestInfo }, inputSchema ? {
103018
103593
  validateModify: async (data) => {
103019
103594
  const schema = normalizeObjectSchema(inputSchema) ?? inputSchema;
@@ -105065,6 +105640,7 @@ var registerContextDiffTool = (server) => {
105065
105640
  fromVersion: number().optional(),
105066
105641
  toVersion: number().optional(),
105067
105642
  diff: string().optional(),
105643
+ predecessorPruned: boolean().optional(),
105068
105644
  changeSource: string().optional(),
105069
105645
  createdAt: string().optional()
105070
105646
  })
@@ -105112,6 +105688,20 @@ var registerContextDiffTool = (server) => {
105112
105688
  } else if (version.previousVersionId) {
105113
105689
  compareVersion = await getContextVersion(version.previousVersionId);
105114
105690
  }
105691
+ if (!compareToVersionId && !compareVersion && version.version > 1) {
105692
+ const message = `No predecessor for ${version.field} v${version.version}: v${version.version - 1} was removed by context version retention. Pass compareToVersionId with a surviving version from context-history.`;
105693
+ return toolOk(message, {
105694
+ details: message,
105695
+ data: {
105696
+ yourAgentId: requestInfo.agentId,
105697
+ field: version.field,
105698
+ toVersion: version.version,
105699
+ predecessorPruned: true,
105700
+ changeSource: version.changeSource,
105701
+ createdAt: version.createdAt
105702
+ }
105703
+ });
105704
+ }
105115
105705
  const oldContent = compareVersion?.content ?? "";
105116
105706
  const diff = await computeDiff(oldContent, version.content);
105117
105707
  const fromVersion = compareVersion?.version ?? 0;
@@ -109426,8 +110016,8 @@ async function applyRating(events, ctx = {}) {
109426
110016
  const UPDATE_MEMORY_SQL = "UPDATE agent_memory SET alpha = alpha + ?, beta = beta + ? WHERE id = ?";
109427
110017
  const CHECK_EXISTS_SQL = "SELECT id FROM agent_memory WHERE id = ?";
109428
110018
  const INSERT_RATING_SQL = `INSERT INTO memory_rating
109429
- (id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey)
109430
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
110019
+ (id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey, model)
110020
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
109431
110021
  const UPSERT_EDGE_SQL = `INSERT INTO agent_memory_edge (from_id, to_id, type, alpha, beta, createdAt)
109432
110022
  VALUES (?, ?, 'references-source', ?, ?, ?)
109433
110023
  ON CONFLICT(from_id, to_id, type) DO UPDATE SET
@@ -109456,7 +110046,8 @@ async function applyRating(events, ctx = {}) {
109456
110046
  event.weight,
109457
110047
  event.reasoning ?? null,
109458
110048
  new Date().toISOString(),
109459
- ctx.contextKey ?? null
110049
+ ctx.contextKey ?? null,
110050
+ event.source === "llm" ? event.model ?? null : null
109460
110051
  ]);
109461
110052
  } catch (err) {
109462
110053
  if (isUniqueConstraintError(err)) {
@@ -110660,20 +111251,20 @@ async function proxySwarmApi(args) {
110660
111251
  if (!args.requestInfo.agentId)
110661
111252
  return toolErr(args.transportError);
110662
111253
  const apiKey = getApiKey();
110663
- const headers2 = {
111254
+ const headers3 = {
110664
111255
  Authorization: `Bearer ${apiKey}`,
110665
111256
  "X-Agent-ID": args.requestInfo.agentId,
110666
111257
  "Content-Type": "application/json"
110667
111258
  };
110668
111259
  if (args.requestInfo.sourceTaskId) {
110669
- headers2["X-Source-Task-Id"] = args.requestInfo.sourceTaskId;
111260
+ headers3["X-Source-Task-Id"] = args.requestInfo.sourceTaskId;
110670
111261
  }
110671
111262
  if (args.requestInfo.runtimeInstanceId) {
110672
- headers2["X-Runtime-Instance-ID"] = args.requestInfo.runtimeInstanceId;
111263
+ headers3["X-Runtime-Instance-ID"] = args.requestInfo.runtimeInstanceId;
110673
111264
  }
110674
111265
  const res = await fetch(`${apiBaseUrl()}${args.path}`, {
110675
111266
  method: args.method,
110676
- headers: headers2,
111267
+ headers: headers3,
110677
111268
  body: args.body === undefined ? undefined : JSON.stringify(args.body)
110678
111269
  });
110679
111270
  const text = await res.text();
@@ -110908,7 +111499,15 @@ var registerExtensionEnableTool = (server) => {
110908
111499
 
110909
111500
  // src/tools/extension-install.ts
110910
111501
  init_zod();
110911
- var EXTENSION_INSTALL_DESCRIPTION = "Install a predefined extension by name. Only extensions in the catalog (extension-catalog, GET /api/extensions/catalog) can be installed; inline bundles are rejected. Install creates the extension, its ext:<name> agent and every asset it declares (scripts, and disabled schedules). Any authenticated agent may install; the installing agent is recorded as createdByAgentId. Workers may install subsequent versions only for their own extensions; those versions remain inactive. A new extension remains disabled until a lead, operator, or dashboard user enables it with extension-enable.";
111502
+ init_types();
111503
+ var EXTENSION_INSTALL_DESCRIPTION = "Install an extension from the catalog by `template` name (extension-catalog, GET /api/extensions/catalog), or from an inline bundle: `manifest` plus a `files` map keyed by bundle path. `template` and `manifest`/`files` are mutually exclusive. Inline bundles are accepted only when the deployment sets EXTENSION_ALLOW_INLINE_INSTALL=true, and only from lead, operator and dashboard-user callers. Workers are denied (403) and stay catalog-only; with the flag off the call fails with inline_install_disabled. Before writing an inline bundle, fetch the hook contract: GET /api/extensions/type-defs returns swarm-extension.d.ts. Install creates the extension, its ext:<name> agent and every asset it declares (scripts, and disabled schedules, workflows and skills). Any authenticated agent may install from the catalog; the installing agent is recorded as createdByAgentId. Workers may install subsequent versions only for their own extensions; those versions remain inactive. A new extension remains disabled until a lead, operator, or dashboard user enables it with extension-enable.";
111504
+ var extensionInstallInputSchema = object({
111505
+ template: string().min(1).optional().describe("Name of a predefined extension from extension-catalog. Mutually exclusive with manifest and files."),
111506
+ manifest: ExtensionManifestSchema.optional().describe("Inline bundle manifest. Requires files. Needs EXTENSION_ALLOW_INLINE_INSTALL and a lead, operator, or dashboard-user caller."),
111507
+ files: record(string(), string()).optional().describe("Inline bundle files keyed by relative path. Requires manifest."),
111508
+ priority: number().int().optional().describe("Handler priority. Lower values run first."),
111509
+ config: record(string(), unknown()).optional().describe("Extension configuration.")
111510
+ }).strict().superRefine(checkExtensionInstallSource);
110912
111511
  function extensionInstallResult(data, fallbackName) {
110913
111512
  const body = data;
110914
111513
  const extension = coerceExtensionSummary(body.extension);
@@ -110929,18 +111528,14 @@ var registerExtensionInstallTool = (server) => {
110929
111528
  title: "Extension Install",
110930
111529
  description: EXTENSION_INSTALL_DESCRIPTION,
110931
111530
  annotations: { openWorldHint: false },
110932
- inputSchema: object({
110933
- template: string().min(1).describe("Name of a predefined extension from extension-catalog."),
110934
- priority: number().int().optional().describe("Handler priority. Lower values run first."),
110935
- config: record(string(), unknown()).optional().describe("Extension configuration.")
110936
- }).strict(),
111531
+ inputSchema: extensionInstallInputSchema,
110937
111532
  outputSchema: extensionToolOutputSchema
110938
111533
  }, async (args, requestInfo) => proxyExtensionsApi({
110939
111534
  method: "POST",
110940
111535
  path: "/api/extensions/install",
110941
111536
  body: args,
110942
111537
  requestInfo,
110943
- success: (data) => extensionInstallResult(data, args.template)
111538
+ success: (data) => extensionInstallResult(data, args.template ?? args.manifest?.name ?? "extension")
110944
111539
  }));
110945
111540
  };
110946
111541
 
@@ -112591,6 +113186,52 @@ var registerMemoryDeleteTool = (server) => {
112591
113186
  init_zod();
112592
113187
  init_db();
112593
113188
 
113189
+ // src/be/memory/key-guard.ts
113190
+ init_key_paths();
113191
+
113192
+ class MemoryKeyError extends Error {
113193
+ reason;
113194
+ constructor(message, reason) {
113195
+ super(message);
113196
+ this.reason = reason;
113197
+ this.name = "MemoryKeyError";
113198
+ }
113199
+ }
113200
+ var NO_AUTHORITY = {
113201
+ principal: { kind: "agent", agentId: "", isLead: false },
113202
+ source: "http"
113203
+ };
113204
+ function shapeError(key, origin) {
113205
+ if (key.length <= MEMORY_KEY_MAX_LENGTH && MEMORY_KEY_PATTERN.test(key))
113206
+ return null;
113207
+ const subject = origin === "sourcePath" ? `sourcePath "${key}" starts with ${LONGTERM_ROOT}, so it is used as the key, but it is not a valid key.` : `Key "${key}" is not a valid key.`;
113208
+ return `${subject} ${MEMORY_KEY_PATTERN_MESSAGE}`;
113209
+ }
113210
+ function assertKeyWritable(key, origin, writer) {
113211
+ if (origin === "sourcePath" && !isLongtermKey(key))
113212
+ return;
113213
+ const shape = shapeError(key, origin);
113214
+ if (shape)
113215
+ throw new MemoryKeyError(shape, "invalid");
113216
+ const pathError = longtermKeyError(key);
113217
+ if (pathError)
113218
+ throw new MemoryKeyError(pathError, "invalid");
113219
+ if (!isConsolidatedKey(key))
113220
+ return;
113221
+ const { principal, source } = writer ?? NO_AUTHORITY;
113222
+ const decision = can({
113223
+ principal,
113224
+ verb: "memory.write.consolidated",
113225
+ resource: { kind: "none" },
113226
+ source
113227
+ });
113228
+ if (!decision.allow)
113229
+ throw new MemoryKeyError(consolidatedKeyMessage(key), "forbidden");
113230
+ }
113231
+
113232
+ // src/tools/memory-edit.ts
113233
+ init_key_paths();
113234
+
112594
113235
  // src/be/memory/link-resolver.ts
112595
113236
  init_db();
112596
113237
  var WIKILINK_RE = /\[\[([^\]]+)\]\]/g;
@@ -112805,7 +113446,7 @@ var agentMemoryOutputSchema = looseObject({
112805
113446
  var registerMemoryEditTool = (server) => {
112806
113447
  createToolRegistrar(server)("memory-edit", {
112807
113448
  title: "Edit a memory",
112808
- description: "Edit a single memory in place while preserving its ID, usefulness posterior, and audit history. Two modes: 'replace' overwrites the entire content (requires `content`); 'exact' performs a surgical find-and-replace of `oldString` with `newString` within the existing content (fails if `oldString` is missing or ambiguous). Use 'replace' for full rewrites, 'exact' for targeted edits. Agents can edit their own memories; lead agents can edit any scope.",
113449
+ description: "Edit a single memory in place while preserving its ID, usefulness posterior, and audit history. Two modes: 'replace' overwrites the entire content (requires `content`); 'exact' performs a surgical find-and-replace of `oldString` with `newString` within the existing content (fails if `oldString` is missing or ambiguous). Use 'replace' for full rewrites, 'exact' for targeted edits. Pass `newKey` alone to move the memory to another logical path (every chunk, same ID, posterior, access counts and author). A move into /longterm also clears the expiry. Agents can edit their own memories; lead agents can edit any scope.",
112809
113450
  annotations: { destructiveHint: true },
112810
113451
  inputSchema: object({
112811
113452
  memoryId: uuid().optional().describe("The memory ID to edit."),
@@ -112816,7 +113457,8 @@ var registerMemoryEditTool = (server) => {
112816
113457
  oldString: string().min(1).optional().describe("Substring to find in existing content. Required for 'exact' mode. Must appear exactly once."),
112817
113458
  newString: string().optional().describe("Replacement for oldString. Required for 'exact' mode. Can be empty to delete."),
112818
113459
  intent: string().min(1).describe("Why you are editing this memory."),
112819
- expectedVersion: number().int().min(1).optional()
113460
+ expectedVersion: number().int().min(1).optional(),
113461
+ newKey: string().max(MEMORY_KEY_MAX_LENGTH).regex(MEMORY_KEY_PATTERN, MEMORY_KEY_PATTERN_MESSAGE).optional().describe("Move the memory to this logical path, for example '/longterm/facts/swarm-runtime/slug'. Alone it is a pure move: omit content/oldString/newString. Fails when the key is already used in this scope by the same owner. Moving into /longterm marks the memory as curated on every chunk: it stops expiring and is protected from cleanup, and moving it out later does not bring the expiry back. A key under /longterm must start with /longterm/company-story, /longterm/entities/people, /longterm/entities/customers, /longterm/facts, /longterm/decisions, /longterm/workstreams or /longterm/timeline. Paths under /longterm/company-story, /longterm/entities and /longterm/timeline are lead-only.")
112820
113462
  }),
112821
113463
  outputSchema: swarmToolOutputSchema({
112822
113464
  yourAgentId: string().optional(),
@@ -112825,7 +113467,18 @@ var registerMemoryEditTool = (server) => {
112825
113467
  previousVersion: number().int().optional(),
112826
113468
  version: number().int().optional()
112827
113469
  })
112828
- }, async ({ memoryId, key, scope, mode, content, oldString, newString, intent, expectedVersion }, requestInfo, _meta) => {
113470
+ }, async ({
113471
+ memoryId,
113472
+ key,
113473
+ scope,
113474
+ mode,
113475
+ content,
113476
+ oldString,
113477
+ newString,
113478
+ intent,
113479
+ expectedVersion,
113480
+ newKey
113481
+ }, requestInfo, _meta) => {
112829
113482
  if (!requestInfo.agentId) {
112830
113483
  return toolErr("Agent ID required. Are you registered in the swarm?");
112831
113484
  }
@@ -112835,6 +113488,17 @@ var registerMemoryEditTool = (server) => {
112835
113488
  });
112836
113489
  }
112837
113490
  try {
113491
+ if (newKey) {
113492
+ const agent = await getAgentById(requestInfo.agentId);
113493
+ assertKeyWritable(newKey, "key", {
113494
+ principal: {
113495
+ kind: "agent",
113496
+ agentId: requestInfo.agentId,
113497
+ isLead: agent?.isLead ?? false
113498
+ },
113499
+ source: "mcp"
113500
+ });
113501
+ }
112838
113502
  const store = getMemoryStore();
112839
113503
  if (memoryId) {
112840
113504
  const memory = await store.peek(memoryId);
@@ -112871,9 +113535,11 @@ var registerMemoryEditTool = (server) => {
112871
113535
  newString,
112872
113536
  intent,
112873
113537
  expectedVersion,
112874
- changedByAgentId: requestInfo.agentId
113538
+ changedByAgentId: requestInfo.agentId,
113539
+ newKey
112875
113540
  });
112876
- if (result.changed) {
113541
+ const contentEdited = content !== undefined || oldString !== undefined || newString !== undefined;
113542
+ if (result.changed && (newKey === undefined || contentEdited)) {
112877
113543
  const provider = getEmbeddingProvider();
112878
113544
  const embedding = await provider.embed(result.memory.content);
112879
113545
  if (embedding)
@@ -112894,6 +113560,9 @@ var registerMemoryEditTool = (server) => {
112894
113560
  }
112895
113561
  });
112896
113562
  } catch (err) {
113563
+ if (err instanceof MemoryKeyError) {
113564
+ return toolErr(err.message, { data: { yourAgentId: requestInfo.agentId } });
113565
+ }
112897
113566
  return toolErr(`Memory edit failed: ${err.message}`, {
112898
113567
  data: { yourAgentId: requestInfo.agentId }
112899
113568
  });
@@ -113231,7 +113900,7 @@ function addNeighborScopeConditions(conditions, params, agentId, scope, isLead)
113231
113900
  async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
113232
113901
  if (!isGraphExpansionEnabled())
113233
113902
  return candidates;
113234
- const { cap = 5, damping = 0.7, scope = "all", source, isLead = false } = options;
113903
+ const { cap = 5, damping = 0.7, scope = "all", source, keyPrefix, isLead = false } = options;
113235
113904
  if (candidates.length === 0 || cap <= 0)
113236
113905
  return candidates;
113237
113906
  const parentById = new Map(candidates.map((c) => [c.id, c]));
@@ -113247,6 +113916,10 @@ async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
113247
113916
  conditions.push("m.source = ?");
113248
113917
  params.push(source);
113249
113918
  }
113919
+ if (keyPrefix) {
113920
+ conditions.push("substr(m.key, 1, length(?)) = ?");
113921
+ params.push(keyPrefix, keyPrefix);
113922
+ }
113250
113923
  let rows;
113251
113924
  try {
113252
113925
  rows = await getDbClient().query(`SELECT m.*, ml.from_memory_id AS fromMemoryId, ml.strength AS linkStrength
@@ -113303,6 +113976,7 @@ async function expandCandidatesWithGraph(candidates, agentId, options = {}) {
113303
113976
  }
113304
113977
 
113305
113978
  // src/tools/memory-search.ts
113979
+ init_key_paths();
113306
113980
  init_reranker();
113307
113981
  init_types();
113308
113982
  var NUDGE_ELIGIBLE_SOURCES2 = new Set(["manual", "file_index"]);
@@ -113345,10 +114019,11 @@ var registerMemorySearchTool = (server) => {
113345
114019
  intent: string().min(1).optional().describe("Optional reason for searching for this memory. E.g. 'looking for auth pattern to fix login bug'."),
113346
114020
  scope: _enum(["all", "agent", "swarm"]).default("all").describe("Search scope: 'all' (own + swarm), 'agent' (own only), 'swarm' (shared only)."),
113347
114021
  limit: number().int().min(1).max(50).default(10).describe("Max results to return."),
113348
- source: AgentMemorySourceSchema.optional().describe("Filter by memory source type.")
114022
+ source: AgentMemorySourceSchema.optional().describe("Filter by memory source type."),
114023
+ keyPrefix: string().min(1).max(MEMORY_KEY_MAX_LENGTH).optional().describe("Only return memories whose key starts with this text, for example '/longterm/facts/' or '/longterm/entities/people/'. Matched literally, case-sensitive. Include the trailing '/' to stay inside one folder.")
113349
114024
  }),
113350
114025
  outputSchema: memorySearchOutputSchema
113351
- }, async ({ query, intent, scope, limit, source }, requestInfo, _meta) => {
114026
+ }, async ({ query, intent, scope, limit, source, keyPrefix }, requestInfo, _meta) => {
113352
114027
  if (!requestInfo.agentId) {
113353
114028
  return toolErr("Agent ID required. Are you registered in the swarm?");
113354
114029
  }
@@ -113363,11 +114038,13 @@ var registerMemorySearchTool = (server) => {
113363
114038
  limit: candidateLimit,
113364
114039
  source,
113365
114040
  isLead,
113366
- queryText: query
114041
+ queryText: query,
114042
+ keyPrefix
113367
114043
  });
113368
114044
  const expanded = await expandCandidatesWithGraph(candidates, requestInfo.agentId, {
113369
114045
  scope,
113370
114046
  source,
114047
+ keyPrefix,
113371
114048
  isLead
113372
114049
  });
113373
114050
  if (expanded.length > 0) {
@@ -113414,7 +114091,8 @@ var registerMemorySearchTool = (server) => {
113414
114091
  scope,
113415
114092
  limit,
113416
114093
  isLead,
113417
- source
114094
+ source,
114095
+ keyPrefix
113418
114096
  });
113419
114097
  const consumedIds = dedupeMemoryDocumentIds(recent);
113420
114098
  try {
@@ -113442,6 +114120,7 @@ var registerMemorySearchTool = (server) => {
113442
114120
 
113443
114121
  // src/tools/memory-store.ts
113444
114122
  init_zod();
114123
+ init_db();
113445
114124
 
113446
114125
  // src/be/chunking.ts
113447
114126
  var MAX_CHUNK_SIZE = 2000;
@@ -113594,6 +114273,9 @@ function addOverlap(chunks, _originalText) {
113594
114273
  init_secret_scrubber();
113595
114274
  async function indexMemoryContent(params) {
113596
114275
  const { agentId, content, name, scope, source, sourceTaskId, sourcePath, tags } = params;
114276
+ const rowKey2 = params.key ?? (sourcePath || null);
114277
+ if (rowKey2)
114278
+ assertKeyWritable(rowKey2, params.key != null ? "key" : "sourcePath", params.writer);
113597
114279
  const contentChunks = chunkContent(content);
113598
114280
  if (contentChunks.length === 0) {
113599
114281
  contentChunks.push({
@@ -113647,7 +114329,7 @@ async function indexMemoryContent(params) {
113647
114329
  tags: tags || [],
113648
114330
  contextKey: params.contextKey ?? null,
113649
114331
  intent: params.intent ?? "index memory content",
113650
- key: sourcePath || null
114332
+ key: rowKey2
113651
114333
  })));
113652
114334
  if (agentId) {
113653
114335
  for (const memory of memories) {
@@ -113674,6 +114356,7 @@ async function indexMemoryContent(params) {
113674
114356
  }
113675
114357
 
113676
114358
  // src/tools/memory-store.ts
114359
+ init_key_paths();
113677
114360
  init_types();
113678
114361
  var registerMemoryStoreTool = (server) => {
113679
114362
  createToolRegistrar(server)("memory-store", {
@@ -113682,11 +114365,12 @@ var registerMemoryStoreTool = (server) => {
113682
114365
  annotations: { destructiveHint: false },
113683
114366
  inputSchema: object({
113684
114367
  content: string().min(1).describe("The memory body. Markdown is fine. State the fact, the context it applies to, and the evidence."),
113685
- name: string().min(1).max(200).optional().describe("Short title used in search results and the UI. Defaults to the first non-empty content line (up to 200 characters)."),
114368
+ name: string().min(1).max(200).optional().describe("Short title used in search results and the UI. Defaults to the first non-empty content line (up to 200 characters). A name that starts with /longterm/ is also used as the key when no key is given."),
113686
114369
  scope: AgentMemoryScopeSchema.default("agent").describe("'agent' (default): only you can recall it. 'swarm': every agent can recall it."),
113687
114370
  tags: union([array(string()), string()]).optional().describe("Free-form tags as an array or a comma-separated string, for example a repo name or a topic."),
113688
114371
  taskId: uuid().optional().describe("The task this learning came from, when there is one."),
113689
- intent: string().min(1).optional().describe("Why this is worth remembering. Kept in the audit trail.")
114372
+ intent: string().min(1).optional().describe("Why this is worth remembering. Kept in the audit trail."),
114373
+ key: string().max(MEMORY_KEY_MAX_LENGTH).regex(MEMORY_KEY_PATTERN, MEMORY_KEY_PATTERN_MESSAGE).optional().describe("Optional logical path for this memory, for example '/longterm/facts/swarm-runtime/sqlite-busy-retry'. Lowercase segments joined by '/', starting with '/'. Search it with memory-search keyPrefix and move it with memory-edit newKey. Fails when you already have a memory with this key in this scope. A key under /longterm marks the memory as curated: it never expires and is protected from cleanup. It must start with /longterm/company-story, /longterm/entities/people, /longterm/entities/customers, /longterm/facts, /longterm/decisions, /longterm/workstreams or /longterm/timeline. Paths under /longterm/company-story, /longterm/entities and /longterm/timeline are lead-only. Defaults to an auto key, which makes the memory inbox material.")
113690
114374
  }),
113691
114375
  outputSchema: swarmToolOutputSchema({
113692
114376
  yourAgentId: string().optional(),
@@ -113694,13 +114378,18 @@ var registerMemoryStoreTool = (server) => {
113694
114378
  chunks: number().int().optional(),
113695
114379
  queued: boolean().optional()
113696
114380
  })
113697
- }, async ({ content, name: requestedName, scope, tags, taskId, intent }, requestInfo, _meta) => {
114381
+ }, async ({ content, name: requestedName, scope, tags, taskId, intent, key }, requestInfo, _meta) => {
113698
114382
  const name = requestedName ?? content.split(/\r?\n/).find((line) => line.trim())?.trim().slice(0, 200) ?? "Untitled memory";
113699
114383
  const normalizedTags = typeof tags === "string" ? tags.split(",").map((tag) => tag.trim()).filter(Boolean) : tags;
113700
114384
  if (!requestInfo.agentId) {
113701
114385
  return toolErr("Agent ID required. Are you registered in the swarm?");
113702
114386
  }
114387
+ const storeKey = resolveStoreKey(key, requestedName);
114388
+ if (storeKey && !key && !MEMORY_KEY_PATTERN.test(storeKey)) {
114389
+ return toolErr(`Name "${storeKey}" starts with /longterm/, so it is used as the key, but it is not a valid key. ${MEMORY_KEY_PATTERN_MESSAGE}`, { data: { yourAgentId: requestInfo.agentId } });
114390
+ }
113703
114391
  try {
114392
+ const agent = storeKey ? await getAgentById(requestInfo.agentId) : undefined;
113704
114393
  const result = await indexMemoryContent({
113705
114394
  agentId: requestInfo.agentId,
113706
114395
  content,
@@ -113709,7 +114398,16 @@ var registerMemoryStoreTool = (server) => {
113709
114398
  source: "manual",
113710
114399
  sourceTaskId: taskId ?? null,
113711
114400
  tags: normalizedTags,
113712
- intent
114401
+ intent,
114402
+ key: storeKey,
114403
+ writer: {
114404
+ principal: {
114405
+ kind: "agent",
114406
+ agentId: requestInfo.agentId,
114407
+ isLead: agent?.isLead ?? false
114408
+ },
114409
+ source: "mcp"
114410
+ }
113713
114411
  });
113714
114412
  return toolOk(`Memory "${name}" stored as ${result.chunks} chunk(s) in ${scope} scope. Embedding runs in the background.`, {
113715
114413
  data: {
@@ -113720,7 +114418,14 @@ var registerMemoryStoreTool = (server) => {
113720
114418
  }
113721
114419
  });
113722
114420
  } catch (err) {
113723
- return toolErr(`Memory store failed: ${err.message}`, {
114421
+ if (err instanceof MemoryKeyError) {
114422
+ return toolErr(err.message, { data: { yourAgentId: requestInfo.agentId } });
114423
+ }
114424
+ const message = err.message;
114425
+ if (storeKey && /UNIQUE constraint failed/i.test(message)) {
114426
+ return toolErr(`Memory store failed: key "${storeKey}" is already used in ${scope} scope. Edit that memory with memory-edit, or pick another key.`, { data: { yourAgentId: requestInfo.agentId } });
114427
+ }
114428
+ return toolErr(`Memory store failed: ${message}`, {
113724
114429
  data: { yourAgentId: requestInfo.agentId }
113725
114430
  });
113726
114431
  }
@@ -121843,7 +122548,7 @@ var createScheduleInputSchema = object({
121843
122548
  targetAgentId: string().optional().describe("Agent to assign tasks to (omit for task pool)"),
121844
122549
  timezone: string().default("UTC").optional().describe("Timezone for cron schedules"),
121845
122550
  enabled: boolean().default(true).optional().describe("Whether the schedule is enabled (default: true)"),
121846
- model: string().trim().min(1).optional().describe("Concrete model override for tasks created by this schedule. Interpreted by each assignee's harness/provider and does not switch providers. Prefer modelTier for portable intent."),
122551
+ model: string().trim().min(1).optional().describe("Concrete model override for tasks created by this schedule. Interpreted by each assignee's harness/provider and does not switch providers. Prefer modelTier for portable intent. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
121847
122552
  modelTier: ModelTierSchema.optional().describe("Portable model tier for tasks created by this schedule: 'smol', 'regular', 'smart', or 'ultra'. Resolved by each assignee's harness/provider at run time."),
121848
122553
  allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet.")
121849
122554
  });
@@ -122427,7 +123132,7 @@ var patchScheduleInputSchema = object({
122427
123132
  targetAgentId: string().nullable().optional().describe("New target agent ID"),
122428
123133
  timezone: string().optional().describe("New timezone"),
122429
123134
  enabled: boolean().optional().describe("Enable or disable the schedule"),
122430
- model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear."),
123135
+ model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
122431
123136
  modelTier: ModelTierSchema.nullable().optional().describe("Portable model tier for tasks created by this schedule. Set to null to clear."),
122432
123137
  allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet.")
122433
123138
  });
@@ -122586,12 +123291,13 @@ var registerPatchScheduleTool = (server) => {
122586
123291
  updateData.timezone = timezone;
122587
123292
  if (enabled2 !== undefined)
122588
123293
  updateData.enabled = enabled2;
123294
+ const agentChanged = targetAgentId !== undefined && targetAgentId !== schedule.targetAgentId;
122589
123295
  if (model !== undefined || modelTier !== undefined) {
122590
123296
  const normalizedModel = splitLegacyModelAlias({ model, modelTier });
122591
- if (normalizedModel.model !== schedule.model) {
123297
+ if (normalizedModel.model !== schedule.model || agentChanged) {
122592
123298
  const modelError = await explicitModelErrorForAgent({
122593
123299
  model: normalizedModel.model,
122594
- allowCustomModel,
123300
+ allowCustomModel: allowCustomModel || normalizedModel.model === schedule.model,
122595
123301
  agentId: targetAgentId ?? schedule.targetAgentId
122596
123302
  });
122597
123303
  if (modelError)
@@ -122602,6 +123308,14 @@ var registerPatchScheduleTool = (server) => {
122602
123308
  if (modelTier !== undefined || normalizedModel.modelTier) {
122603
123309
  updateData.modelTier = normalizedModel.modelTier ?? null;
122604
123310
  }
123311
+ } else if (agentChanged && schedule.model) {
123312
+ const modelError = await explicitModelErrorForAgent({
123313
+ model: schedule.model,
123314
+ allowCustomModel: true,
123315
+ agentId: targetAgentId ?? schedule.targetAgentId
123316
+ });
123317
+ if (modelError)
123318
+ return toolErr(modelError);
122605
123319
  }
122606
123320
  if (schedule.scheduleType === "one_time") {
122607
123321
  if (enabled2 === false) {
@@ -122728,7 +123442,7 @@ var updateScheduleInputSchema = object({
122728
123442
  targetAgentId: string().nullable().optional().describe("New target agent ID"),
122729
123443
  timezone: string().optional().describe("New timezone"),
122730
123444
  enabled: boolean().optional().describe("Enable or disable the schedule"),
122731
- model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear."),
123445
+ model: string().trim().min(1).nullable().optional().describe("Concrete model override for tasks created by this schedule. Set to null to clear. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
122732
123446
  modelTier: ModelTierSchema.nullable().optional().describe("Portable model tier for tasks created by this schedule. Set to null to clear."),
122733
123447
  allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet.")
122734
123448
  });
@@ -122887,12 +123601,13 @@ var registerUpdateScheduleTool = (server) => {
122887
123601
  updateData.timezone = timezone;
122888
123602
  if (enabled2 !== undefined)
122889
123603
  updateData.enabled = enabled2;
123604
+ const agentChanged = targetAgentId !== undefined && targetAgentId !== schedule.targetAgentId;
122890
123605
  if (model !== undefined || modelTier !== undefined) {
122891
123606
  const normalizedModel = splitLegacyModelAlias({ model, modelTier });
122892
- if (normalizedModel.model !== schedule.model) {
123607
+ if (normalizedModel.model !== schedule.model || agentChanged) {
122893
123608
  const modelError = await explicitModelErrorForAgent({
122894
123609
  model: normalizedModel.model,
122895
- allowCustomModel,
123610
+ allowCustomModel: allowCustomModel || normalizedModel.model === schedule.model,
122896
123611
  agentId: targetAgentId ?? schedule.targetAgentId
122897
123612
  });
122898
123613
  if (modelError)
@@ -122903,6 +123618,14 @@ var registerUpdateScheduleTool = (server) => {
122903
123618
  if (modelTier !== undefined || normalizedModel.modelTier) {
122904
123619
  updateData.modelTier = normalizedModel.modelTier ?? null;
122905
123620
  }
123621
+ } else if (agentChanged && schedule.model) {
123622
+ const modelError = await explicitModelErrorForAgent({
123623
+ model: schedule.model,
123624
+ allowCustomModel: true,
123625
+ agentId: targetAgentId ?? schedule.targetAgentId
123626
+ });
123627
+ if (modelError)
123628
+ return toolErr(modelError);
122906
123629
  }
122907
123630
  if (schedule.scheduleType === "one_time") {
122908
123631
  if (enabled2 === false) {
@@ -123773,7 +124496,7 @@ var sendTaskInputSchema = object({
123773
124496
  parentTaskId: uuid().optional().describe("Parent task ID for session continuity. Child task will resume the parent's Claude session. Auto-routes to the same worker unless agentId is explicitly provided."),
123774
124497
  dir: string().min(1).startsWith("/").optional().describe("Working directory (absolute path) for the agent to start in. If the directory doesn't exist, falls back to the default working directory."),
123775
124498
  vcsRepo: string().optional().describe("VCS repo identifier (e.g., 'desplega-ai/agent-swarm' for GitHub or 'group/project' for GitLab). Links the task to a registered repo for workspace context."),
123776
- model: string().trim().min(1).optional().describe("Concrete model override for this task, interpreted by the assignee's harness/provider. This does not switch providers. Prefer modelTier for portable intent."),
124499
+ model: string().trim().min(1).optional().describe("Concrete model override for this task, interpreted by the assignee's harness/provider. This does not switch providers. Prefer modelTier for portable intent. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
123777
124500
  modelTier: ModelTierSchema.optional().describe("Portable model tier for this task: 'smol', 'regular', 'smart', or 'ultra'. Resolved at claim/run time using the assignee's harness/provider. Legacy model shortnames map as haiku→smol, sonnet→regular, opus→smart, fable→ultra."),
123778
124501
  allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only for ids the catalog cannot know yet (a fresh launch, a private deployment)."),
123779
124502
  effort: ReasoningEffortSchema.optional().describe("Reasoning effort for this task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. If omitted, the assignee's REASONING_EFFORT_OVERRIDE/default applies."),
@@ -123887,13 +124610,6 @@ async function sendTaskHandler(ctx, {
123887
124610
  }
123888
124611
  const effectiveVcsRepo = vcsRepo;
123889
124612
  const normalizedModel = splitLegacyModelAlias({ model, modelTier });
123890
- const modelError = await explicitModelErrorForAgent({
123891
- model: normalizedModel.model,
123892
- allowCustomModel,
123893
- agentId
123894
- });
123895
- if (modelError)
123896
- return toolErr(modelError, { data: { yourAgentId: creatorAgentId } });
123897
124613
  const effectiveParentTaskId = parentTaskId ?? sourceTaskId;
123898
124614
  const effectiveParentTask = effectiveParentTaskId ? await getTaskById(effectiveParentTaskId) : null;
123899
124615
  if (effectiveParentTask?.routingAffinityInvalid) {
@@ -123931,6 +124647,13 @@ async function sendTaskHandler(ctx, {
123931
124647
  effectiveAgentId = effectiveParentTask.agentId;
123932
124648
  }
123933
124649
  }
124650
+ const modelError = await explicitModelErrorForAgent({
124651
+ model: normalizedModel.model,
124652
+ allowCustomModel,
124653
+ agentId: effectiveAgentId
124654
+ });
124655
+ if (modelError)
124656
+ return toolErr(modelError, { data: { yourAgentId: creatorAgentId } });
123934
124657
  const effectiveRoutingReason = agentId !== undefined ? routingReason : effectiveAgentId ? "continuity" : undefined;
123935
124658
  const effectiveRoutingNote = effectiveRoutingReason ? routingNote : undefined;
123936
124659
  const effectiveRoutingSource = agentId !== undefined ? "declared" : effectiveAgentId ? "engine_default" : undefined;
@@ -123968,7 +124691,8 @@ async function sendTaskHandler(ctx, {
123968
124691
  description: task,
123969
124692
  options: requestedTaskOptions,
123970
124693
  origin: "mcp",
123971
- requestInfo: ctx.kind === "owner" ? ctx.requestInfo : undefined
124694
+ requestInfo: ctx.kind === "owner" ? ctx.requestInfo : undefined,
124695
+ allowCustomModel
123972
124696
  });
123973
124697
  if (preCreate.kind === "blocked") {
123974
124698
  return toolErr(preCreate.reason, {
@@ -126167,9 +126891,9 @@ var registerSlackReadTool = (server) => {
126167
126891
  const extractedText = extractSlackMessageText(m);
126168
126892
  if (!extractedText && (!m.files || m.files.length === 0))
126169
126893
  continue;
126170
- const isBot = m.user === botUserId || m.bot_id !== undefined || m.subtype === "bot_message";
126894
+ const isBot2 = m.user === botUserId || m.bot_id !== undefined || m.subtype === "bot_message";
126171
126895
  let username;
126172
- if (isBot) {
126896
+ if (isBot2) {
126173
126897
  username = m.username || "Agent";
126174
126898
  } else if (m.user) {
126175
126899
  username = await getUserDisplayName(m.user);
@@ -126207,7 +126931,7 @@ var registerSlackReadTool = (server) => {
126207
126931
  messages.push({
126208
126932
  user: m.user,
126209
126933
  username,
126210
- isBot,
126934
+ isBot: isBot2,
126211
126935
  text: extractedText,
126212
126936
  ts: m.ts,
126213
126937
  files
@@ -126867,6 +127591,20 @@ init_types();
126867
127591
  init_secret_scrubber();
126868
127592
  var BLOCKED_WAITING_PATTERN = /\b(waiting (for|on)|blocked (on|until|by)|still waiting|awaiting)\b/i;
126869
127593
  var BLOCKED_WAITING_MIN_ELAPSED_MS = 3 * 60 * 1000;
127594
+ async function foreignTaskWriteError(caller, task, sourceTaskId) {
127595
+ const decision = can({
127596
+ principal: { kind: "agent", agentId: caller.id, isLead: caller.isLead === true },
127597
+ verb: "task.progress.write",
127598
+ resource: { kind: "task", taskId: task.id, agentId: task.agentId },
127599
+ source: "mcp"
127600
+ });
127601
+ if (decision.allow)
127602
+ return;
127603
+ const sourceTask = sourceTaskId ? await getTaskById(sourceTaskId) : null;
127604
+ const ownTask = sourceTask?.agentId === caller.id ? sourceTask : await getAgentCurrentTask(caller.id);
127605
+ const retry = ownTask ? ` Your own task is "${ownTask.id}"; call store-progress with that taskId.` : " You have no in-progress task.";
127606
+ return `Task "${task.id}" is assigned to another agent; only its assignee may store progress on it. Nothing was written.${retry}`;
127607
+ }
126870
127608
  var storeProgressOutputSchema = swarmToolOutputSchema({
126871
127609
  task: looseObject({
126872
127610
  id: string(),
@@ -126940,12 +127678,17 @@ var registerStoreProgressTool = (server) => {
126940
127678
  const agentFsScopes = new Map;
126941
127679
  const agentFsAttachments = attachments?.filter((a) => a.kind === "agent-fs") ?? [];
126942
127680
  if (agentFsAttachments.length > 0) {
126943
- if (!await getAgentById(requestInfo.agentId)) {
127681
+ const caller = await getAgentById(requestInfo.agentId);
127682
+ if (!caller) {
126944
127683
  return toolErr(`Agent with ID "${requestInfo.agentId}" not found in the swarm, register before storing task progress.`);
126945
127684
  }
126946
- if (!await getTaskById(taskId)) {
127685
+ const target = await getTaskById(taskId);
127686
+ if (!target) {
126947
127687
  return toolErr(`Task with ID "${taskId}" not found.`);
126948
127688
  }
127689
+ const foreignError = await foreignTaskWriteError(caller, target, requestInfo.sourceTaskId);
127690
+ if (foreignError)
127691
+ return toolErr(foreignError);
126949
127692
  const configs = await getResolvedConfig(requestInfo.agentId ?? undefined);
126950
127693
  const configValue = (key) => configs.find((c) => c.key === key)?.value?.trim();
126951
127694
  const defaultOrgId = configValue("AGENT_FS_DEFAULT_ORG_ID");
@@ -127006,6 +127749,10 @@ var registerStoreProgressTool = (server) => {
127006
127749
  message: `Task with ID "${taskId}" not found.`
127007
127750
  };
127008
127751
  }
127752
+ const foreignError = await foreignTaskWriteError(agent, existingTask, requestInfo.sourceTaskId);
127753
+ if (foreignError) {
127754
+ return { success: false, message: foreignError };
127755
+ }
127009
127756
  let updatedTask = existingTask;
127010
127757
  const isTerminal2 = isTerminalTaskStatus(existingTask.status);
127011
127758
  const goingTerminal = status !== undefined && isTerminalTaskStatus(status);
@@ -127063,8 +127810,8 @@ var registerStoreProgressTool = (server) => {
127063
127810
  return terminalResultGuard;
127064
127811
  }
127065
127812
  if (progress && !isTerminal2) {
127066
- const isDuplicate4 = existingTask.progress === progress && existingTask.lastUpdatedAt && Date.now() - new Date(existingTask.lastUpdatedAt).getTime() < 5 * 60 * 1000;
127067
- if (!isDuplicate4) {
127813
+ const isDuplicate5 = existingTask.progress === progress && existingTask.lastUpdatedAt && Date.now() - new Date(existingTask.lastUpdatedAt).getTime() < 5 * 60 * 1000;
127814
+ if (!isDuplicate5) {
127068
127815
  const result2 = await updateTaskProgress(taskId, progress);
127069
127816
  if (result2)
127070
127817
  updatedTask = result2;
@@ -127780,7 +128527,7 @@ var taskActionInputSchema = object({
127780
128527
  taskId: uuid().optional().describe("Task ID (required for claim/release/accept/reject)."),
127781
128528
  reason: string().optional().describe("Reason for rejection (optional for 'reject')."),
127782
128529
  dir: string().min(1).startsWith("/").optional().describe("Working directory (absolute path) for the agent to start in. Only used with 'create' action."),
127783
- model: string().trim().min(1).optional().describe("Concrete model override for the created task, interpreted by the claiming worker's harness/provider. This does not switch providers. Only used with 'create' action."),
128530
+ model: string().trim().min(1).optional().describe("Concrete model override for the created task, interpreted by the claiming worker's harness/provider. This does not switch providers. Only used with 'create' action. The model must run on the assignee's harness (an Anthropic model on a Claude agent, an OpenAI model on a Codex agent); a mismatch is rejected."),
127784
128531
  modelTier: ModelTierSchema.optional().describe("Portable model tier for the created task: 'smol', 'regular', 'smart', or 'ultra'. Resolved when a worker claims/runs the task. Only used with 'create' action."),
127785
128532
  allowCustomModel: boolean().optional().describe("Accept a `model` the model catalog does not list. Without it an unknown model id is rejected. Only used with 'create' action."),
127786
128533
  effort: ReasoningEffortSchema.optional().describe("Reasoning effort for the created task: 'off', 'low', 'medium', 'high', 'xhigh', or 'max'. Only used with 'create' action."),
@@ -127928,7 +128675,8 @@ async function taskActionHandler(ctx, input) {
127928
128675
  routingAffinity: leadOnly || requiredCapabilities?.length ? { leadOnly, capabilities: requiredCapabilities ?? [] } : undefined
127929
128676
  },
127930
128677
  origin: "mcp",
127931
- requestInfo: ctx.requestInfo
128678
+ requestInfo: ctx.requestInfo,
128679
+ allowCustomModel: input.allowCustomModel
127932
128680
  });
127933
128681
  if (preCreate.kind === "blocked") {
127934
128682
  return taskActionResult({ success: false, message: preCreate.reason }, agentId);
@@ -128849,6 +129597,43 @@ var registerCancelWorkflowRunTool = (server) => {
128849
129597
  init_zod();
128850
129598
  init_db();
128851
129599
  init_types();
129600
+
129601
+ // src/workflows/model-validation.ts
129602
+ init_types();
129603
+ function asConfig(value) {
129604
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
129605
+ }
129606
+ function isStatic(value) {
129607
+ return typeof value === "string" && value.trim() !== "" && !value.includes("{{");
129608
+ }
129609
+ async function workflowModelErrors(def) {
129610
+ const errors = [];
129611
+ for (const node of def.nodes) {
129612
+ const targets = [];
129613
+ if (node.type === "agent-task")
129614
+ targets.push({ config: node.config, path: "config" });
129615
+ if (node.type === "foreach") {
129616
+ const body = asConfig(asConfig(node.config.body)?.config);
129617
+ if (body)
129618
+ targets.push({ config: body, path: "config.body.config" });
129619
+ }
129620
+ for (const { config, path: path3 } of targets) {
129621
+ if (!isStatic(config.model) || !isStatic(config.agentId))
129622
+ continue;
129623
+ const modelTier = typeof config.modelTier === "string" ? config.modelTier : undefined;
129624
+ const error = await explicitModelErrorForAgent({
129625
+ model: splitLegacyModelAlias({ model: config.model, modelTier }).model,
129626
+ allowCustomModel: config.allowCustomModel === true,
129627
+ agentId: config.agentId
129628
+ });
129629
+ if (error)
129630
+ errors.push(`Node "${node.id}" ${path3}.model: ${error}`);
129631
+ }
129632
+ }
129633
+ return errors;
129634
+ }
129635
+
129636
+ // src/tools/workflows/create-workflow.ts
128852
129637
  var registerCreateWorkflowTool = (server) => {
128853
129638
  createToolRegistrar(server)("create-workflow", {
128854
129639
  title: "Create Workflow",
@@ -128860,14 +129645,14 @@ var registerCreateWorkflowTool = (server) => {
128860
129645
  ` + `- Agent-task config: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }.
128861
129646
  ` + "- FOREACH NODE: type 'foreach' fans out one agent-task per item. Config: " + "{ over: <array or exact {{input}} token>, itemKey: <property name>, body: { type: 'agent-task', config: {...} } }. " + "The body config is interpolated once per item with {{item.*}} and {{index}}. Child steps use synthetic IDs " + "'<foreachNodeId>#<itemKey>'; the parent waits for every child and exposes one aggregate result to successors. " + `concurrency is not supported in v1; use definition-level onNodeFailure: 'continue' to aggregate failed children.
128862
129647
  ` + "- TRIGGER SCHEMA: Optional 'triggerSchema' is a JSON-Schema object that validates incoming trigger payloads. " + "Supported keywords: type, required, properties, enum, const, items (recursive into arrays). " + `Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored.
128863
- ` + "- WEBHOOK VERIFICATION: Webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "or { format: 'token-equality', header }. Example: { type: 'webhook', hmacSecret: 'secret.SUPERAGENT_WEBHOOK_SECRET', " + `verification: { format: 'timestamped-hmac-sha256', header: 'X-Superagent-Signature', toleranceSeconds: 300 } }.
129648
+ ` + "- WEBHOOK VERIFICATION: Webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "{ format: 'token-equality', header }, or { format: 'standard-webhooks', toleranceSeconds? } " + "(standardwebhooks.com: webhook-id/webhook-timestamp/webhook-signature headers, hmacSecret is the whsec_ signing secret). Example: { type: 'webhook', hmacSecret: 'secret.SUPERAGENT_WEBHOOK_SECRET', " + `verification: { format: 'timestamped-hmac-sha256', header: 'X-Superagent-Signature', toleranceSeconds: 300 } }.
128864
129649
  ` + "- WAIT NODE: type 'wait' pauses a workflow for a duration or until a named workflowEventBus event arrives. " + "See runbooks/workflows.md#wait-nodes for config shapes, ordering caveats, and built-in event names.",
128865
129650
  inputSchema: exports_external.object({
128866
129651
  name: exports_external.string().describe("Unique name for the workflow"),
128867
129652
  key: AssetKeySchema.optional().describe("Logical namespace. Defaults to a shared/workflow:<id>/ resource key."),
128868
129653
  description: exports_external.string().optional().describe("Description of what this workflow does"),
128869
129654
  definition: WorkflowDefinitionSchema.describe("The workflow definition with nodes (each node has id, type, config, and optional next/retry/validation)"),
128870
- triggers: exports_external.array(TriggerConfigSchema).optional().describe("Optional trigger configurations (webhook, schedule, event). Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality."),
129655
+ triggers: exports_external.array(TriggerConfigSchema).optional().describe("Optional trigger configurations (webhook, schedule, event). Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality, standard-webhooks."),
128871
129656
  cooldown: CooldownConfigSchema.optional().describe("Optional cooldown configuration to prevent re-triggering too frequently"),
128872
129657
  input: exports_external.record(exports_external.string(), InputValueSchema).optional().describe("Optional input values resolved at execution time (env vars like VAR_NAME, secrets secret.NAME, or literals)"),
128873
129658
  dir: exports_external.string().min(1).startsWith("/").optional().describe("Default working directory for all agent-task nodes (absolute path, e.g. /tmp/workspace)"),
@@ -128899,6 +129684,10 @@ var registerCreateWorkflowTool = (server) => {
128899
129684
  if (!validation.valid) {
128900
129685
  return toolErr(`Invalid definition: ${validation.errors.join("; ")}`);
128901
129686
  }
129687
+ const modelErrors = await workflowModelErrors(definition);
129688
+ if (modelErrors.length > 0) {
129689
+ return toolErr(`Invalid definition: ${modelErrors.join("; ")}`);
129690
+ }
128902
129691
  const createdBy = await resolveTaskAuditUserId(requestInfo.sourceTaskId, requestInfo.agentId) ?? undefined;
128903
129692
  const assetKey = key ? await authorizeAssetKeyWrite(key, createdBy) : undefined;
128904
129693
  const workflow = await createWorkflow({
@@ -129178,6 +129967,10 @@ async function patchWorkflowDefinition(options) {
129178
129967
  if (!validation.valid) {
129179
129968
  return { ok: false, reason: "invalid", errors: validation.errors };
129180
129969
  }
129970
+ const modelErrors = await workflowModelErrors(patchResult.definition);
129971
+ if (modelErrors.length > 0) {
129972
+ return { ok: false, reason: "invalid", errors: modelErrors };
129973
+ }
129181
129974
  let version = null;
129182
129975
  if (snapshotOptional) {
129183
129976
  try {
@@ -129438,14 +130231,14 @@ var registerUpdateWorkflowTool = (server) => {
129438
130231
  createToolRegistrar(server)("update-workflow", {
129439
130232
  title: "Update Workflow",
129440
130233
  annotations: { destructiveHint: false },
129441
- description: "Update an existing workflow's name, description, definition, triggers, cooldown, input, triggerSchema, or enabled state. " + "Creates a version snapshot before applying changes. " + "TRIGGER SCHEMA: pass 'triggerSchema' as a JSON-Schema object to set/replace, or 'null' to clear. " + "Supported JSON-Schema keywords: type, required, properties, enum, const, items (recursive into arrays). " + "Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored. " + "WEBHOOK VERIFICATION: webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "or { format: 'token-equality', header }.",
130234
+ description: "Update an existing workflow's name, description, definition, triggers, cooldown, input, triggerSchema, or enabled state. " + "Creates a version snapshot before applying changes. " + "TRIGGER SCHEMA: pass 'triggerSchema' as a JSON-Schema object to set/replace, or 'null' to clear. " + "Supported JSON-Schema keywords: type, required, properties, enum, const, items (recursive into arrays). " + "Other JSON-Schema keywords (oneOf/anyOf/$ref/pattern/format/additionalProperties) are silently ignored. " + "WEBHOOK VERIFICATION: webhook triggers use hmacSecret for all verification formats. " + "Omit verification for legacy HMAC-SHA256 over the raw body with fallback header scanning; " + "or set verification to { format: 'hmac-sha256', header }, { format: 'timestamped-hmac-sha256', header, toleranceSeconds? }, " + "{ format: 'token-equality', header }, or { format: 'standard-webhooks', toleranceSeconds? } " + "(standardwebhooks.com: webhook-id/webhook-timestamp/webhook-signature headers, hmacSecret is the whsec_ signing secret).",
129442
130235
  inputSchema: exports_external.object({
129443
130236
  id: exports_external.string().uuid().describe("Workflow ID to update"),
129444
130237
  key: AssetKeySchema.optional().describe("Move to a logical namespace."),
129445
130238
  name: exports_external.string().optional().describe("New name for the workflow"),
129446
130239
  description: exports_external.string().optional().describe("New description"),
129447
130240
  definition: WorkflowDefinitionSchema.optional().describe("New workflow definition"),
129448
- triggers: exports_external.array(TriggerConfigSchema).optional().describe("New trigger configurations. Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality."),
130241
+ triggers: exports_external.array(TriggerConfigSchema).optional().describe("New trigger configurations. Webhook verification formats: legacy omitted verification, hmac-sha256, timestamped-hmac-sha256, token-equality, standard-webhooks."),
129449
130242
  cooldown: CooldownConfigSchema.optional().nullable().describe("New cooldown configuration (null to remove)"),
129450
130243
  input: exports_external.record(exports_external.string(), InputValueSchema).optional().nullable().describe("New input values (null to remove)"),
129451
130244
  dir: exports_external.string().min(1).startsWith("/").optional().nullable().describe("Default working directory for all agent-task nodes (null to remove)"),
@@ -129484,6 +130277,10 @@ var registerUpdateWorkflowTool = (server) => {
129484
130277
  if (!validation.valid) {
129485
130278
  return toolErr(`Invalid definition: ${validation.errors.join("; ")}`);
129486
130279
  }
130280
+ const modelErrors = await workflowModelErrors(definition);
130281
+ if (modelErrors.length > 0) {
130282
+ return toolErr(`Invalid definition: ${modelErrors.join("; ")}`);
130283
+ }
129487
130284
  }
129488
130285
  const updatedBy = await resolveTaskAuditUserId(requestInfo.sourceTaskId, requestInfo.agentId) ?? undefined;
129489
130286
  const assetKey = key === undefined ? undefined : await authorizeAssetKeyWrite(key, updatedBy);
@@ -130205,7 +131002,7 @@ async function readScriptSdkJsonResponse(response, operation, limitBytes = SCRIP
130205
131002
  }
130206
131003
 
130207
131004
  // src/scripts-runtime/swarm-sdk.ts
130208
- function headers2(config) {
131005
+ function headers3(config) {
130209
131006
  return {
130210
131007
  Authorization: `Bearer ${Redacted.value(config.apiKey)}`,
130211
131008
  "X-Agent-ID": Redacted.value(config.agentId),
@@ -130638,7 +131435,7 @@ async function callBridgeApi(name, args2, config, options = {}) {
130638
131435
  const mcpToolName = mcpToolNameForSdkMethod(name);
130639
131436
  const res2 = await fetch(`${baseUrl}/api/mcp-bridge`, {
130640
131437
  method: "POST",
130641
- headers: headers2(config),
131438
+ headers: headers3(config),
130642
131439
  body: JSON.stringify({ tool: mcpToolName, args: args2 ?? {} })
130643
131440
  });
130644
131441
  const data2 = await readScriptSdkJsonResponse(res2, `ctx.swarm.${name}`);
@@ -130650,7 +131447,7 @@ async function callBridgeApi(name, args2, config, options = {}) {
130650
131447
  }
130651
131448
  const res = await fetch(`${baseUrl}${request.path}`, {
130652
131449
  method: request.method,
130653
- headers: headers2(config),
131450
+ headers: headers3(config),
130654
131451
  body: request.body === undefined ? undefined : JSON.stringify(request.body)
130655
131452
  });
130656
131453
  const data = await readScriptSdkJsonResponse(res, `ctx.swarm.${name}`);
@@ -131777,6 +132574,7 @@ async function applyPreTaskCreate(args2) {
131777
132574
  const creatingExtensionId = extensionIdForAgent(args2.requestInfo?.agentId);
131778
132575
  const creatingExtension = creatingExtensionId ? listRegistered().find((loaded) => loaded.record.id === creatingExtensionId) : undefined;
131779
132576
  const origin = creatingExtension ? `extension:${creatingExtension.record.name}` : args2.origin;
132577
+ let modelEditor;
131780
132578
  const result = await dispatchPre("pre.task.create", {
131781
132579
  description: args2.description,
131782
132580
  options: args2.options,
@@ -131803,6 +132601,9 @@ async function applyPreTaskCreate(args2) {
131803
132601
  }
131804
132602
  const { description: _description, ...optionChanges2 } = filtered;
131805
132603
  CreateTaskOptionsSchema.parse({ ...currentOptions, ...optionChanges2 });
132604
+ if ("model" in optionChanges2 || "agentId" in optionChanges2) {
132605
+ modelEditor = { id: extension.id, name: extension.name };
132606
+ }
131806
132607
  return filtered;
131807
132608
  }
131808
132609
  });
@@ -131817,10 +132618,25 @@ async function applyPreTaskCreate(args2) {
131817
132618
  return { kind: "proceed", description: args2.description, options: args2.options };
131818
132619
  }
131819
132620
  const { description, ...optionChanges } = result.data;
132621
+ const options = CreateTaskOptionsSchema.parse({ ...args2.options, ...optionChanges });
132622
+ if (modelEditor) {
132623
+ const modelError = await explicitModelErrorForAgent({
132624
+ model: options.model,
132625
+ allowCustomModel: args2.allowCustomModel || options.model === args2.options.model,
132626
+ agentId: options.agentId
132627
+ });
132628
+ if (modelError) {
132629
+ return {
132630
+ kind: "blocked",
132631
+ reason: `pre.task.create rewrite from extension "${modelEditor.name}" is invalid: ${modelError}`,
132632
+ extension: modelEditor
132633
+ };
132634
+ }
132635
+ }
131820
132636
  return {
131821
132637
  kind: "proceed",
131822
132638
  description: description ?? args2.description,
131823
- options: CreateTaskOptionsSchema.parse({ ...args2.options, ...optionChanges })
132639
+ options
131824
132640
  };
131825
132641
  }
131826
132642
 
@@ -131920,13 +132736,13 @@ class AgentTaskExecutor extends BaseExecutor {
131920
132736
  followUpConfig: config.followUpConfig,
131921
132737
  contextKey: workflowContextKey({ workflowRunId: meta2.runId })
131922
132738
  },
131923
- origin: "workflow"
132739
+ origin: "workflow",
132740
+ allowCustomModel: config.allowCustomModel
131924
132741
  });
131925
132742
  if (preCreate.kind === "blocked") {
131926
132743
  throw new TaskCreationBlockedError(preCreate.reason, preCreate.extension);
131927
132744
  }
131928
- const { description: taskDescription, options: taskOptions } = await withSiblingAwareness(preCreate.description, preCreate.options);
131929
- const task = await db.createTaskExtended(taskDescription, taskOptions);
132745
+ const task = await db.createTaskExtended(preCreate.description, preCreate.options);
131930
132746
  return {
131931
132747
  status: "success",
131932
132748
  async: true,
@@ -132187,7 +133003,7 @@ class NotifyExecutor extends BaseExecutor {
132187
133003
  }
132188
133004
  }
132189
133005
  case "slack": {
132190
- const { getSlackApp: getSlackApp2 } = await import("./app-y1b9srva.js");
133006
+ const { getSlackApp: getSlackApp2 } = await import("./app-0hdqa4k1.js");
132191
133007
  const app = getSlackApp2();
132192
133008
  if (!app) {
132193
133009
  return {
@@ -132992,4 +133808,4 @@ async function initWorkflows() {
132992
133808
  logOpenWebhookTriggers();
132993
133809
  }
132994
133810
 
132995
- export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, findUserById, findUserByExternalId, getUserIdentities, listUserEvents, listUserTokens, recordIdentityEvent, findOrCreateUserByEmail, linkIdentity, unlinkIdentity, mintToken, revokeToken, resolveUserByToken, mintSessionToken, revokeSessionToken, fingerprintApiKey, resolveIdentity, renderIdentity, createAdditiveBuffer, referencedBundlePaths, skillDirs, TaskCreationBlockedError, recordUnmappedIdentity, MAX_TASK_ATTACHMENT_BYTES, recordTaskAttachmentUpload, buildEffectiveText, bufferedFileFailures, fetchSlackFiles, createSlackTaskWithFiles, notifySlackFileFailures, hasOtherUserMention, broadcastMatches, routeMessage, extractTaskFromMessage, extractSlackMessageText, automationIntegrationFixUrl, preflightAutomation, getAutomationSetupStates, listEnabledAutomationPreflightInputs, validateJsonSchema, workflowSaveWarnings, TriggerSchemaError, startWorkflowExecution, setupWorkflowResumeListener, retryFailedRun, cancelWorkflowRun, resumeWaitState, initWaitBusSubscriptions, subscribeWaitToBus, recoverIncompleteRuns, startRetryPoller, stopRetryPoller, validateTemplateVariables, instantiateTemplate, handleWebhookTrigger, logOpenWebhookTriggers, handleEventTrigger, handleScheduleTrigger, verifyHmacSignature, WebhookError, snapshotWorkflow, snapshotAndUpdateWorkflow, startWaitPoller, stopWaitPoller, listHarnessModelSupport, recordHarnessModelSupport, agentRanModel, getAgentHarnessCliVersion, setAgentHarnessCliVersion, sanitizeModelTierOverrides, parseModelTierOverridesHeader, setAgentModelTierOverrides, previewModelTiers, recordClaimModelResolution, explicitModelError, explicitModelErrorForAgent, RawLlmConfigSchema, RawLlmOutputSchema, executeRawLlm, getExecutorRegistry, initWorkflows, dispatchScheduleTarget, calculateNextRun, startScheduler, stopScheduler, runScheduleNow, parseSkillContent, ExtensionAssetConflictError, ExtensionOwnershipError, getExtensionFiles, getExtensionById, getExtensionByName, listExtensions, listExtensionVersions, updateExtensionMeta, listExtensionRuns, SDK_ALLOWLIST, mcpToolNameForSdkMethod, mcpOverflowAuthError, toolErr, createToolRegistrar, warnIfCorsAllowsAnyOrigin, isOriginAllowedForCredentials, allowedCredentialRedirect, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, runtimeInstanceHeader, describeRequestRoute, route, handleMcpBridge, Redacted, SCRIPT_SDK_RESPONSE_LIMIT_BYTES, readScriptSdkJsonResponse, ExtensionConfigError, ExtensionLifecycleError, setExtensionLoopbackBaseUrl, enableExtension, disableExtension, activateVersion, ExtensionAssetsInvalidError, installExtensionWithAssets, uninstallExtension, reloadExtension, loadEnabledExtensions, stopExtensionRuntime, ExtensionAbortedError, isRegistered, isExtensionAgentId, getExtensionBridgeToken, resolveBridgeCallOrigin, extensionIdForAgent, runContext, registerLoaded, unregister, listRegistered, dispatchPre, dispatchPost, createTaskWithSiblingAwareness, isInboxAllowed, isSenderAllowed, handleMessageReceived, AGENT_MAX_TASKS_CONFIG_KEY, reconcileAgentMaxTasksPolicy, resetAgentMaxTasksMirror, upsertSwarmConfigWithPolicyMirror, runtimeStaleThresholdMinutes, upsertRuntimeInstance, getRuntimeInstanceById, touchRuntimeInstance, countActiveRuntimeInstancesForAgent, listRuntimeInstancesForAgent, setRuntimeCredentialReady, reconcileAgentStatusFromRuntimes, agentsWithLiveRuntime, expireStaleRuntimeInstances, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2 as handleIssue1, handleNote, handlePipeline, repointTrackerSyncBySwarmId, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, userCtx, resolveTaskAuditUserId, resolveHttpAuditUserId, resolveHttpFavoriteOwner, handleApps, cancelApprovalRequest, cancelApprovalRequestAndRun, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, dedupeMemoryDocumentIds, recordMemoryAccesses, recordRetrievals, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, REBOOT_RETRY_PIN_TAG, getPinCandidateAgent, resolveLeadOnlyRecoveryAssignment, getResumeGeneration, getNextResumeGeneration, createWorkerTaskFollowUp, createResumeFollowUp, createRerouteDecisionTask, createPoolStarvationDecisionTask, guardTerminalTaskResultWrite, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, refreshLinks, canReadMemory, getLinksForMemory, expandCandidatesWithGraph, indexMemoryContent, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, resolveRoomNamespace, roomRequestInfo, authorizeRoomNamespace, RoomOperationSchema, removeAwarenessStates, roomTopic, decodeRoomSnapshot, roomView, getRoom, changeRoom, applyRoomUpdate, resetRoom, sweepRooms, closeRooms, removeNamespaceRooms, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, checkOutputSchemaShape, sendTaskOutputSchema, sendTaskHandler, steerTaskUserInputSchema, steerTaskOutputSchema, steerTaskHandler, canClaim, emitBudgetRefusalSideEffects, taskActionInputSchema, taskActionOutputSchema, taskActionHandler, patchWorkflowDefinition, resolveScriptsOnlyMode, ALL_CAPABILITIES, hasCapability, getEnabledCapabilities, createServer };
133811
+ export { DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, findUserById, findUserByExternalId, getUserIdentities, listUserEvents, listUserTokens, recordIdentityEvent, findOrCreateUserByEmail, linkIdentity, unlinkIdentity, mintToken, revokeToken, resolveUserByToken, mintSessionToken, revokeSessionToken, fingerprintApiKey, resolveIdentity, renderIdentity, createAdditiveBuffer, listHarnessModelSupport, recordHarnessModelSupport, agentRanModel, getAgentHarnessCliVersion, setAgentHarnessCliVersion, sanitizeModelTierOverrides, parseModelTierOverridesHeader, setAgentModelTierOverrides, previewModelTiers, recordClaimModelResolution, harnessModelErrorFor, poolTaskRunsOnHarness, explicitModelError, explicitModelErrorForAgent, referencedBundlePaths, skillDirs, TaskCreationBlockedError, recordUnmappedIdentity, MAX_TASK_ATTACHMENT_BYTES, recordTaskAttachmentUpload, buildEffectiveText, bufferedFileFailures, fetchSlackFiles, createSlackTaskWithFiles, notifySlackFileFailures, hasOtherUserMention, broadcastMatches, routeMessage, extractTaskFromMessage, extractSlackMessageText, automationIntegrationFixUrl, preflightAutomation, getAutomationSetupStates, listEnabledAutomationPreflightInputs, validateJsonSchema, workflowSaveWarnings, TriggerSchemaError, startWorkflowExecution, setupWorkflowResumeListener, retryFailedRun, cancelWorkflowRun, resumeWaitState, initWaitBusSubscriptions, subscribeWaitToBus, recoverIncompleteRuns, startRetryPoller, stopRetryPoller, validateTemplateVariables, instantiateTemplate, handleWebhookTrigger, logOpenWebhookTriggers, handleEventTrigger, handleScheduleTrigger, verifyHmacSignature, WebhookError, snapshotWorkflow, snapshotAndUpdateWorkflow, startWaitPoller, stopWaitPoller, RawLlmConfigSchema, RawLlmOutputSchema, executeRawLlm, getExecutorRegistry, initWorkflows, dispatchScheduleTarget, calculateNextRun, startScheduler, stopScheduler, runScheduleNow, parseSkillContent, ExtensionAssetConflictError, ExtensionOwnershipError, getExtensionFiles, getExtensionById, getExtensionByName, listExtensions, listExtensionVersions, updateExtensionMeta, listExtensionRuns, SDK_ALLOWLIST, mcpToolNameForSdkMethod, mcpOverflowAuthError, toolErr, createToolRegistrar, warnIfCorsAllowsAnyOrigin, isOriginAllowedForCredentials, allowedCredentialRedirect, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, runtimeInstanceHeader, describeRequestRoute, route, handleMcpBridge, Redacted, SCRIPT_SDK_RESPONSE_LIMIT_BYTES, readScriptSdkJsonResponse, ExtensionConfigError, ExtensionLifecycleError, setExtensionLoopbackBaseUrl, enableExtension, disableExtension, activateVersion, ExtensionAssetsInvalidError, installExtensionWithAssets, uninstallExtension, reloadExtension, loadEnabledExtensions, stopExtensionRuntime, ExtensionAbortedError, isRegistered, isExtensionAgentId, getExtensionBridgeToken, resolveBridgeCallOrigin, extensionIdForAgent, runContext, registerLoaded, unregister, listRegistered, dispatchPre, dispatchPost, stripSiblingBlock, createTaskWithSiblingAwareness, isInboxAllowed, isSenderAllowed, handleMessageReceived, isAzureDevOpsEnabled, initAzureDevOps, verifyAzureDevOpsWebhook, isAzureDevOpsUrl, canonicalAzureDevOpsRepoUrl, parseAzureDevOpsRepoUrl, createdPullRequestOf, commentedPayloadOf, handlePullRequestCreated, handlePullRequestCommented, AGENT_MAX_TASKS_CONFIG_KEY, reconcileAgentMaxTasksPolicy, resetAgentMaxTasksMirror, upsertSwarmConfigWithPolicyMirror, runtimeStaleThresholdMinutes, upsertRuntimeInstance, getRuntimeInstanceById, touchRuntimeInstance, countActiveRuntimeInstancesForAgent, listRuntimeInstancesForAgent, setRuntimeCredentialReady, reconcileAgentStatusFromRuntimes, agentsWithLiveRuntime, expireStaleRuntimeInstances, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2 as handleIssue1, handleNote, handlePipeline, repointTrackerSyncBySwarmId, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, userCtx, resolveTaskAuditUserId, resolveHttpAuditUserId, resolveHttpFavoriteOwner, handleApps, cancelApprovalRequest, cancelApprovalRequestAndRun, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, dedupeMemoryDocumentIds, recordMemoryAccesses, recordRetrievals, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, REBOOT_RETRY_PIN_TAG, getPinCandidateAgent, resolveLeadOnlyRecoveryAssignment, getResumeGeneration, getNextResumeGeneration, createWorkerTaskFollowUp, createResumeFollowUp, createRerouteDecisionTask, createPoolStarvationDecisionTask, guardTerminalTaskResultWrite, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, MemoryKeyError, refreshLinks, canReadMemory, getLinksForMemory, expandCandidatesWithGraph, indexMemoryContent, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, resolveRoomNamespace, roomRequestInfo, authorizeRoomNamespace, RoomOperationSchema, removeAwarenessStates, roomTopic, decodeRoomSnapshot, roomView, getRoom, changeRoom, applyRoomUpdate, resetRoom, sweepRooms, closeRooms, removeNamespaceRooms, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, checkOutputSchemaShape, sendTaskOutputSchema, sendTaskHandler, steerTaskUserInputSchema, steerTaskOutputSchema, steerTaskHandler, canClaim, emitBudgetRefusalSideEffects, taskActionInputSchema, taskActionOutputSchema, taskActionHandler, workflowModelErrors, patchWorkflowDefinition, resolveScriptsOnlyMode, ALL_CAPABILITIES, hasCapability, getEnabledCapabilities, createServer };