@desplega.ai/agent-swarm 1.150.0 → 1.151.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 (293) hide show
  1. package/README.md +11 -0
  2. package/dist/{acp-adapter-d5mzggyk.js → acp-adapter-ex8hzjfc.js} +5 -5
  3. package/dist/{actions-wn6ew0p7.js → actions-2bgpyhww.js} +38 -11
  4. package/dist/{anthropic-messages-ec35ktvx.js → anthropic-messages-2y8nktar.js} +16 -16
  5. package/dist/{app-dty7p9hg.js → app-1706zhr1.js} +7 -7
  6. package/dist/{assistant-q4vhgjtx.js → assistant-bavke5p7.js} +41 -16
  7. package/dist/{azure-openai-responses-g85jv7m8.js → azure-openai-responses-f38x2avq.js} +13 -13
  8. package/dist/{boot-reembed-92292pgf.js → boot-reembed-3cmrrmpa.js} +8 -8
  9. package/dist/{boot-reembed-n15q6s9x.js → boot-reembed-nafcmmmc.js} +13 -15
  10. package/dist/{boot-scrub-logs-44pc955m.js → boot-scrub-logs-cd6a2sq0.js} +5 -5
  11. package/dist/{claude-adapter-cjegjbje.js → claude-adapter-wfp2gzvz.js} +12 -13
  12. package/dist/{claude-managed-adapter-p3ts5m9m.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
  13. package/dist/{claude-sdk-session-7ywbn12v.js → claude-sdk-session-bht9jjak.js} +12 -13
  14. package/dist/{cli-ceb5y160.js → cli-0qb1z6s2.js} +1 -1
  15. package/dist/{cli-ryz8q8p1.js → cli-2tbvf1z1.js} +40 -40
  16. package/dist/{cli-zthatyrx.js → cli-3v9xhjcn.js} +5 -5
  17. package/dist/{cli-mzb0n642.js → cli-4wppfkcm.js} +350 -20
  18. package/dist/{cli-3ckzxdt1.js → cli-5jd2z7av.js} +90 -81
  19. package/dist/{cli-3mh119qv.js → cli-5tpgq60f.js} +9726 -693
  20. package/dist/{cli-ck1vqzdj.js → cli-7tgcstn2.js} +9 -4
  21. package/dist/{cli-ttje5a4z.js → cli-9004vfdf.js} +105 -56
  22. package/dist/{cli-asvrh7kj.js → cli-9xvdm3bx.js} +1 -1
  23. package/dist/{cli-9gqddmxs.js → cli-a1z3h107.js} +8 -8
  24. package/dist/{cli-72xdszyx.js → cli-czjtgfys.js} +2 -2
  25. package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
  26. package/dist/{cli-kyysm7m3.js → cli-f1wky6zp.js} +1 -1
  27. package/dist/{cli-a45d5v9b.js → cli-fm4ytsdk.js} +2 -2
  28. package/dist/{cli-111ey3ra.js → cli-frcta2w4.js} +5 -5
  29. package/dist/{cli-h505yhex.js → cli-g69fdc9g.js} +2 -2
  30. package/dist/{cli-cmp8g3sw.js → cli-gbfwcd3k.js} +44 -9
  31. package/dist/{cli-hbagregr.js → cli-gjyvhmmh.js} +88 -13
  32. package/dist/{cli-hmyynq9b.js → cli-ht5rs63n.js} +1 -1
  33. package/dist/{cli-dyx0237s.js → cli-j4nv2wqy.js} +2 -4
  34. package/dist/{cli-vr6qj104.js → cli-j9xczhaq.js} +1 -1
  35. package/dist/cli-pf9q3696.js +172 -0
  36. package/dist/{cli-7fesa1ky.js → cli-pgj4a5fb.js} +1 -1
  37. package/dist/{cli-7kwmt3r5.js → cli-ppm4975n.js} +9 -3
  38. package/dist/{cli-8chp8xab.js → cli-q88st9aj.js} +2 -2
  39. package/dist/{cli-kt7wevqh.js → cli-r2q6pevn.js} +132 -46
  40. package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
  41. package/dist/{cli-qp69dd5d.js → cli-s14agm5s.js} +105 -12
  42. package/dist/{cli-zd21jrrc.js → cli-sjaae6ff.js} +9872 -424
  43. package/dist/{cli-taym3dmg.js → cli-vwm416m6.js} +13 -13
  44. package/dist/{cli-1mx65de9.js → cli-wbyk465z.js} +1 -1
  45. package/dist/{cli-n75jt793.js → cli-z61ykvam.js} +6 -5
  46. package/dist/{cli-gm0fhz13.js → cli-zkxymas5.js} +2 -1
  47. package/dist/cli.js +22 -21
  48. package/dist/{codex-adapter-rn3aq7jm.js → codex-adapter-jjjk8w4m.js} +8 -9
  49. package/dist/{codex-hook-gthcmm0g.js → codex-hook-8jexc34x.js} +2 -2
  50. package/dist/{codex-session-runner-bge0cbsw.js → codex-session-runner-nd6ayxkx.js} +8 -9
  51. package/dist/{commands-26phw0pc.js → commands-9v4psyq1.js} +5 -5
  52. package/dist/{db-jxjx6s1b.js → db-wnt58tpe.js} +5 -5
  53. package/dist/dispatcher-05jh1aqk.js +74 -0
  54. package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
  55. package/dist/{google-vertex-pkhpkbq9.js → google-vertex-fr665tqs.js} +10 -10
  56. package/dist/handlers-tw90pkh5.js +65 -0
  57. package/dist/{hook-t6fqsggw.js → hook-123e2scb.js} +9 -10
  58. package/dist/{hook-jw0ztn96.js → hook-sxe3r349.js} +9 -10
  59. package/dist/{http-hyc7s57s.js → http-ecsar8ez.js} +1431 -579
  60. package/dist/{index-sfhaq59d.js → index-16js521z.js} +119 -101
  61. package/dist/{index-wtwpthe1.js → index-hw26vj40.js} +25 -19
  62. package/dist/{index-bcyx5djw.js → index-nnrbpcjp.js} +25 -17
  63. package/dist/index-ymn7em0p.js +25 -0
  64. package/dist/{index-1d9r6a74.js → index-zj518gf9.js} +26 -20
  65. package/dist/{keepalive-fbsak4ya.js → keepalive-asqtcm4y.js} +7 -7
  66. package/dist/{lead-rdzdm627.js → lead-xbfr7fvt.js} +41 -49
  67. package/dist/{maintenance-25z1c1vf.js → maintenance-qma55qvw.js} +8 -8
  68. package/dist/{node-209sxmg3.js → node-x1g4v0pq.js} +9 -9
  69. package/dist/{oauth-refresh-sweep-j3d7gtse.js → oauth-refresh-sweep-3s04c6qw.js} +6 -6
  70. package/dist/{onboard-dkcwrc75.js → onboard-drskd386.js} +13 -4
  71. package/dist/{openai-codex-responses-pm5gnyfa.js → openai-codex-responses-wy6a43wd.js} +11 -11
  72. package/dist/{openai-responses-vwvk1taj.js → openai-responses-6xwf7bzg.js} +13 -13
  73. package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
  74. package/dist/{otel-impl-8rgyy3j8.js → otel-impl-943c96er.js} +1 -1
  75. package/dist/{pi-mono-adapter-4s2bbkgq.js → pi-mono-adapter-jcqt71cg.js} +14 -16
  76. package/dist/{pricing-refresh-9cek71nq.js → pricing-refresh-mx51az05.js} +7 -7
  77. package/dist/{rbac-roles-z98s2ypy.js → rbac-roles-78baecqd.js} +13 -9
  78. package/dist/{rbac-roles-vk8mqp9v.js → rbac-roles-wcmrg6sv.js} +7 -7
  79. package/dist/{render-v2-3j26g0qh.js → render-v2-8zjntgf5.js} +7 -7
  80. package/dist/{seed-pricing-7rxhcnzm.js → seed-pricing-jqjs6cws.js} +6 -6
  81. package/dist/{setup-e2t7vz0c.js → setup-4pks0vfk.js} +2 -2
  82. package/dist/{work-objects-8d3nd3x2.js → work-objects-wangt792.js} +38 -14
  83. package/dist/{worker-0x9fn7nq.js → worker-p2mr422x.js} +41 -49
  84. package/openapi.json +1351 -265
  85. package/package.json +2 -1
  86. package/src/agentmail/handlers.ts +95 -71
  87. package/src/be/db-client.ts +5 -0
  88. package/src/be/db.ts +11 -3
  89. package/src/be/extensions/db.ts +461 -0
  90. package/src/be/extensions/validate.ts +107 -0
  91. package/src/be/memory/boot-reembed.ts +17 -12
  92. package/src/be/memory/index.ts +12 -0
  93. package/src/be/memory/providers/openai-embedding.ts +4 -0
  94. package/src/be/memory/types.ts +2 -0
  95. package/src/be/migrations/155_extensions.sql +66 -0
  96. package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
  97. package/src/be/rbac-roles.ts +3 -2
  98. package/src/be/scripts/typecheck.ts +52 -38
  99. package/src/be/seed-skills/index.ts +7 -0
  100. package/src/be/swarm-config-guard.ts +3 -1
  101. package/src/commands/onboard/compose-generator.ts +14 -2
  102. package/src/commands/onboard/env-generator.ts +7 -0
  103. package/src/commands/runner.ts +1 -1
  104. package/src/extensions/apply-task-create.ts +135 -0
  105. package/src/extensions/bundle-path.ts +10 -0
  106. package/src/extensions/contract-runtime.ts +7 -0
  107. package/src/extensions/contract-types.generated.ts +4 -0
  108. package/src/extensions/contract.ts +270 -0
  109. package/src/extensions/ctx.ts +186 -0
  110. package/src/extensions/dispatcher.ts +479 -0
  111. package/src/extensions/identity.ts +44 -0
  112. package/src/extensions/lifecycle.ts +281 -0
  113. package/src/extensions/loader.ts +207 -0
  114. package/src/extensions/post-bridge.ts +161 -0
  115. package/src/github/handlers.ts +185 -149
  116. package/src/gitlab/handlers.ts +97 -81
  117. package/src/heartbeat/heartbeat.ts +152 -83
  118. package/src/http/agents.ts +1 -1
  119. package/src/http/all-routes.ts +1 -0
  120. package/src/http/apps.ts +14 -10
  121. package/src/http/core.ts +34 -0
  122. package/src/http/extensions.ts +547 -0
  123. package/src/http/inbox-state.ts +2 -0
  124. package/src/http/index.ts +25 -0
  125. package/src/http/mcp-bridge.ts +96 -62
  126. package/src/http/mcp.ts +1 -1
  127. package/src/http/status.ts +6 -4
  128. package/src/http/tasks.ts +51 -35
  129. package/src/integrations/kapso/inbound.ts +15 -11
  130. package/src/jira/sync.ts +26 -18
  131. package/src/linear/sync.ts +26 -18
  132. package/src/prompts/session-templates.ts +5 -4
  133. package/src/rbac/admission.ts +1 -1
  134. package/src/rbac/elevated-agents.ts +24 -0
  135. package/src/rbac/legacy-policy.ts +35 -6
  136. package/src/rbac/permissions.ts +8 -0
  137. package/src/scheduler/deferred-task-waits.ts +133 -51
  138. package/src/scheduler/schedule-task.ts +50 -24
  139. package/src/scheduler/scheduler.ts +4 -2
  140. package/src/scripts-runtime/executors/native.ts +5 -1
  141. package/src/scripts-runtime/executors/types.ts +5 -0
  142. package/src/scripts-runtime/import-allowlist.ts +79 -19
  143. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  144. package/src/scripts-runtime/swarm-config.ts +8 -0
  145. package/src/scripts-runtime/swarm-sdk.ts +3 -0
  146. package/src/scripts-runtime/types/stdlib.d.ts +9 -0
  147. package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
  148. package/src/scripts-runtime/types/swarm-sdk.d.ts +9 -0
  149. package/src/server.ts +6 -0
  150. package/src/slack/HEURISTICS.md +1 -1
  151. package/src/slack/actions.ts +21 -17
  152. package/src/slack/blocks.ts +1 -1
  153. package/src/slack/handlers.ts +98 -5
  154. package/src/slack/inbound-files.ts +6 -2
  155. package/src/slack/render-v2.ts +171 -35
  156. package/src/slack/router.ts +13 -3
  157. package/src/slack/steering.ts +3 -3
  158. package/src/tasks/errors.ts +9 -0
  159. package/src/tasks/sibling-awareness.ts +35 -1
  160. package/src/tasks/worker-follow-up.ts +64 -12
  161. package/src/tests/base-prompt.test.ts +1 -0
  162. package/src/tests/deferred-task-wake.test.ts +161 -9
  163. package/src/tests/docs-index-footprint.test.js +3 -3
  164. package/src/tests/env-flag.test.ts +1 -0
  165. package/src/tests/extensions-db.test.ts +216 -0
  166. package/src/tests/extensions-dispatcher.test.ts +275 -0
  167. package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
  168. package/src/tests/extensions-example-mcp-install.test.ts +63 -0
  169. package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
  170. package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
  171. package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
  172. package/src/tests/extensions-heartbeat.test.ts +291 -0
  173. package/src/tests/extensions-http.test.ts +431 -0
  174. package/src/tests/extensions-lead-equivalence.test.ts +49 -0
  175. package/src/tests/extensions-lifecycle.test.ts +209 -0
  176. package/src/tests/extensions-loader.test.ts +95 -0
  177. package/src/tests/extensions-mcp-tools.test.ts +245 -0
  178. package/src/tests/extensions-pre-task.test.ts +487 -0
  179. package/src/tests/extensions-run-context.test.ts +41 -0
  180. package/src/tests/extensions-tool-call.test.ts +288 -0
  181. package/src/tests/extensions-validate.test.ts +196 -0
  182. package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
  183. package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
  184. package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
  185. package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
  186. package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
  187. package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
  188. package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
  189. package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
  190. package/src/tests/fixtures/extensions/load.ts +10 -0
  191. package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
  192. package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
  193. package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
  194. package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
  195. package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
  196. package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
  197. package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
  198. package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
  199. package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
  200. package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
  201. package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
  202. package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
  203. package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
  204. package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
  205. package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
  206. package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
  207. package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
  208. package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
  209. package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
  210. package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
  211. package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
  212. package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
  213. package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
  214. package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
  215. package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
  216. package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
  217. package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
  218. package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
  219. package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
  220. package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
  221. package/src/tests/memory-edit-authorization.test.ts +32 -0
  222. package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
  223. package/src/tests/multi-runtime-registration.test.ts +14 -14
  224. package/src/tests/onboard-compose.test.ts +44 -0
  225. package/src/tests/preload.ts +5 -0
  226. package/src/tests/rbac-admission.test.ts +18 -3
  227. package/src/tests/rbac-engine.test.ts +39 -0
  228. package/src/tests/realtime-room-auth.test.ts +1 -1
  229. package/src/tests/reload-config.test.ts +44 -0
  230. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  231. package/src/tests/script-connections.test.ts +2 -0
  232. package/src/tests/scripts-boot-reembed.test.ts +4 -0
  233. package/src/tests/scripts-embeddings.test.ts +4 -0
  234. package/src/tests/scripts-import-allowlist.test.ts +44 -1
  235. package/src/tests/scripts-mcp-e2e.test.ts +80 -0
  236. package/src/tests/scripts-only-gating.test.ts +2 -0
  237. package/src/tests/scripts-runtime-identity.test.ts +1 -1
  238. package/src/tests/slack-blocks.test.ts +12 -1
  239. package/src/tests/slack-render-v2.test.ts +76 -3
  240. package/src/tests/slack-router.test.ts +17 -2
  241. package/src/tests/slack-steering.test.ts +19 -0
  242. package/src/tests/status.test.ts +12 -0
  243. package/src/tests/steering-enabled.test.ts +6 -8
  244. package/src/tests/task-tool-preload-mcp.test.ts +4 -1
  245. package/src/tests/tool-annotations.test.ts +1 -1
  246. package/src/tests/tool-registrar-no-input.test.ts +42 -1
  247. package/src/tools/defer-task.ts +1 -1
  248. package/src/tools/extension-common.ts +84 -0
  249. package/src/tools/extension-install.ts +65 -0
  250. package/src/tools/extension-list.ts +66 -0
  251. package/src/tools/script-common.ts +43 -18
  252. package/src/tools/send-task.ts +69 -107
  253. package/src/tools/task-action.ts +43 -22
  254. package/src/tools/task-tool-ctx.ts +2 -0
  255. package/src/tools/tool-config.ts +3 -1
  256. package/src/tools/utils.ts +140 -16
  257. package/src/types.ts +133 -0
  258. package/src/utils/multi-runtime.ts +2 -2
  259. package/src/utils/steering-enabled.ts +4 -4
  260. package/src/workflows/executors/agent-task.ts +13 -3
  261. package/templates/extensions/README.md +17 -0
  262. package/templates/extensions/notify-on-complete/README.md +11 -0
  263. package/templates/extensions/notify-on-complete/hooks.ts +61 -0
  264. package/templates/extensions/notify-on-complete/manifest.json +7 -0
  265. package/templates/extensions/require-ticket-ref/README.md +11 -0
  266. package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
  267. package/templates/extensions/require-ticket-ref/manifest.json +7 -0
  268. package/templates/extensions/require-verification-note/README.md +11 -0
  269. package/templates/extensions/require-verification-note/hooks.ts +32 -0
  270. package/templates/extensions/require-verification-note/manifest.json +7 -0
  271. package/templates/skills/scheduling/content.md +2 -0
  272. package/templates/skills/swarm-extensions/config.json +14 -0
  273. package/templates/skills/swarm-extensions/content.md +120 -0
  274. package/dist/cli-b8x19vbh.js +0 -823
  275. package/dist/cli-n1yj5fd5.js +0 -164
  276. package/dist/cli-q04q68be.js +0 -3066
  277. package/dist/cli-qgm2pfpq.js +0 -6377
  278. package/dist/cli-rnsr8asm.js +0 -4323
  279. package/dist/cli-rwp3ksm7.js +0 -545
  280. package/dist/cli-xjb9wghj.js +0 -668
  281. package/dist/cli-xvkmedgn.js +0 -332
  282. package/dist/cli-ydk0wjj8.js +0 -338
  283. package/dist/handlers-vr1djg4n.js +0 -41
  284. package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
  285. package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
  286. package/dist/{cli-wk0gjrn3.js → cli-kj76p1ez.js} +6 -6
  287. package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
  288. package/dist/{cli-8qx7jnrk.js → cli-y6x0gqtg.js} +16 -16
  289. package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
  290. package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
  291. package/dist/{openai-completions-qdcmkfnr.js → openai-completions-32rdwmze.js} +17 -17
  292. package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
  293. package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
@@ -1,13 +1,18 @@
1
1
  import {
2
2
  PermissionVerbSchema
3
- } from "./cli-cmp8g3sw.js";
3
+ } from "./cli-gbfwcd3k.js";
4
4
  import {
5
5
  getDb,
6
6
  getDbClient,
7
7
  init_db
8
- } from "./cli-qp69dd5d.js";
8
+ } from "./cli-s14agm5s.js";
9
+ import {
10
+ init_env_flag,
11
+ isEnvFlagEnabled
12
+ } from "./cli-ej6gbxfb.js";
9
13
 
10
14
  // src/be/rbac-roles.ts
15
+ init_env_flag();
11
16
  init_db();
12
17
  var DEFAULT_ROLE_ID = "rbac-role-admin";
13
18
  var BUILTIN_ROLES = [
@@ -217,8 +222,8 @@ function ensureRbacSeedsSynced(opts) {
217
222
  function describeRbacFlag() {
218
223
  const raw = process.env.RBAC_ENABLED;
219
224
  if (raw === undefined)
220
- return "unset (off)";
221
- return `${raw} (${raw === "true" ? "on" : "off"})`;
225
+ return "unset (on)";
226
+ return `${raw} (${isEnvFlagEnabled("RBAC_ENABLED", true) ? "on" : "off"})`;
222
227
  }
223
228
  function printRolesTable(rows) {
224
229
  const tableRows = rows.map((row) => [
@@ -5,20 +5,20 @@ import {
5
5
  createPoolStarvationDecisionTask,
6
6
  createRerouteDecisionTask,
7
7
  createResumeFollowUp,
8
+ dispatchPre,
8
9
  expireStaleRuntimeInstances,
10
+ extensionIdForAgent,
11
+ getExecutorRegistry,
9
12
  getNextResumeGeneration,
10
13
  getPinCandidateAgent,
11
14
  getResumeGeneration,
15
+ recoverIncompleteRuns,
12
16
  repointTrackerSyncBySwarmId,
13
17
  resolveLeadOnlyRecoveryAssignment
14
- } from "./cli-xjb9wghj.js";
18
+ } from "./cli-5tpgq60f.js";
15
19
  import {
16
20
  isMultiRuntimeEnabled
17
- } from "./cli-07jd68a1.js";
18
- import {
19
- getExecutorRegistry,
20
- recoverIncompleteRuns
21
- } from "./cli-rnsr8asm.js";
21
+ } from "./cli-re8z5p8p.js";
22
22
  import {
23
23
  MAX_EMPTY_POLLS,
24
24
  assignUnassignedTaskPending,
@@ -61,13 +61,13 @@ import {
61
61
  releaseStaleReviewingTasks,
62
62
  supersedeTask,
63
63
  updateAgentStatus
64
- } from "./cli-qp69dd5d.js";
64
+ } from "./cli-s14agm5s.js";
65
65
  import {
66
66
  init_registry,
67
67
  init_resolver,
68
68
  registerTemplate,
69
69
  resolveTemplate
70
- } from "./cli-n75jt793.js";
70
+ } from "./cli-z61ykvam.js";
71
71
  import {
72
72
  init_secret_scrubber,
73
73
  scrubSecrets
@@ -206,6 +206,7 @@ function maxResumeGenerations() {
206
206
  return Number(process.env.HEARTBEAT_MAX_RESUME_GENERATIONS) || 3;
207
207
  }
208
208
  var RESUME_BUDGET_EXHAUSTED_REASON = "resume_budget_exhausted";
209
+ var REMEDIATION_ACTIONS = new Set(["supersede-resume", "fail", "record"]);
209
210
  var HEARTBEAT_RESUME_PIN_GRACE_MIN = (() => {
210
211
  const raw = process.env.HEARTBEAT_RESUME_PIN_GRACE_MIN;
211
212
  if (raw === undefined)
@@ -244,6 +245,7 @@ async function preflightGate() {
244
245
  async function codeLevelTriage() {
245
246
  const findings = {
246
247
  stalledTasks: [],
248
+ extensionSkipped: [],
247
249
  autoFailedTasks: [],
248
250
  autoResumedTasks: [],
249
251
  pinnedResumes: [],
@@ -283,85 +285,128 @@ async function detectAndRemediateStalledTasks(findings) {
283
285
  if (newestPendingSteeringAt > 0 && pendingSteeringAgeMs < STEERING_STALL_GRACE_MIN * 60 * 1000) {
284
286
  continue;
285
287
  }
288
+ let classification;
289
+ let remediationOpts;
290
+ let proposed;
286
291
  if (!session) {
287
292
  if (taskAgeMs >= stallThresholdNoSessionMin() * 60 * 1000) {
288
- await remediateCrashedWorkerTask(findings, task, {
293
+ classification = "no-session";
294
+ remediationOpts = {
289
295
  supersedeReason: "Auto-superseded by heartbeat: worker session not found (no active session for task)",
290
296
  legacyFailReason: "Auto-failed by heartbeat: worker session not found (no active session for task)",
291
297
  shortLabel: "no active session"
292
- });
298
+ };
299
+ proposed = await defaultRemediationDecision(task, remediationOpts);
293
300
  }
294
301
  } else {
295
302
  const isStaleHeartbeat = sessionHeartbeatAgeMs >= stallThresholdStaleHeartbeatMin() * 60 * 1000;
296
303
  if (isStaleHeartbeat) {
297
304
  if (taskAgeMs >= stallThresholdStaleHeartbeatMin() * 60 * 1000) {
298
- await remediateCrashedWorkerTask(findings, task, {
305
+ classification = "stale-session";
306
+ remediationOpts = {
299
307
  supersedeReason: "Auto-superseded by heartbeat: worker session heartbeat is stale (likely crashed)",
300
308
  legacyFailReason: "Auto-failed by heartbeat: worker session heartbeat is stale (likely crashed)",
301
309
  shortLabel: "stale session heartbeat",
302
310
  cleanupActiveSession: true
303
- });
311
+ };
312
+ proposed = await defaultRemediationDecision(task, remediationOpts);
304
313
  }
305
314
  } else {
306
315
  if (taskAgeMs >= stallThresholdMinutes() * 60 * 1000) {
307
- findings.stalledTasks.push(task);
316
+ classification = "fresh-stalled";
317
+ remediationOpts = {
318
+ supersedeReason: "Auto-superseded by heartbeat: task stalled despite a fresh session heartbeat",
319
+ legacyFailReason: "Auto-failed by heartbeat: task stalled despite a fresh session heartbeat",
320
+ shortLabel: "fresh session heartbeat"
321
+ };
322
+ proposed = {
323
+ action: "record",
324
+ reason: "Task stalled despite a fresh session heartbeat"
325
+ };
308
326
  }
309
327
  }
310
328
  }
329
+ if (!classification || !remediationOpts || !proposed)
330
+ continue;
331
+ const dispatched = await dispatchPre("pre.heartbeat.remediate", {
332
+ task,
333
+ ...session ? { session } : {},
334
+ classification,
335
+ proposedAction: proposed.action,
336
+ reason: proposed.reason,
337
+ taskAgeMs,
338
+ ...sessionHeartbeatAgeMs === null ? {} : { sessionHeartbeatAgeMs }
339
+ }, { skipExtensionId: extensionIdForAgent(task.creatorAgentId) });
340
+ if (dispatched.action === "block") {
341
+ findings.stalledTasks.push(task);
342
+ findings.extensionSkipped.push({
343
+ taskId: task.id,
344
+ extension: dispatched.extension,
345
+ reason: dispatched.reason
346
+ });
347
+ continue;
348
+ }
349
+ if (dispatched.action === "modify") {
350
+ const action = dispatched.data.proposedAction;
351
+ if (isRemediationAction(action)) {
352
+ proposed = { ...proposed, action };
353
+ } else {
354
+ console.warn("[Heartbeat] Extension returned an invalid remediation action:", scrubSecrets(String(action)));
355
+ }
356
+ }
357
+ if (proposed.action === "record") {
358
+ findings.stalledTasks.push(task);
359
+ continue;
360
+ }
361
+ await remediateCrashedWorkerTask(findings, task, remediationOpts, proposed);
311
362
  }
312
363
  }
313
- async function remediateCrashedWorkerTask(findings, task, opts) {
314
- if (!task.agentId)
315
- return;
364
+ function isRemediationAction(value) {
365
+ return typeof value === "string" && REMEDIATION_ACTIONS.has(value);
366
+ }
367
+ function decideRemediation(task, facts) {
368
+ if (task.workflowRunStepId != null) {
369
+ return { action: "fail", reason: "superseded_workflow_task" };
370
+ }
371
+ if (facts.skipAutoResume || facts.alreadyResumed) {
372
+ return { action: "fail", reason: facts.legacyFailReason };
373
+ }
374
+ if (facts.resumeBudgetExhausted) {
375
+ return { action: "fail", reason: RESUME_BUDGET_EXHAUSTED_REASON };
376
+ }
377
+ return { action: "supersede-resume", reason: facts.supersedeReason };
378
+ }
379
+ async function defaultRemediationDecision(task, opts) {
316
380
  const skipAutoResume = SKIP_AUTO_RESUME_TYPES.has(task.taskType ?? "");
317
381
  const isWorkflowStep = task.workflowRunStepId != null;
318
382
  const alreadyResumed = !skipAutoResume && !isWorkflowStep && await hasNonTerminalResumeChild(task.id);
319
- if (isWorkflowStep) {
320
- const failed = await failTask(task.id, "superseded_workflow_task");
321
- if (failed) {
322
- findings.autoFailedTasks.push({
323
- taskId: task.id,
324
- agentId: task.agentId,
325
- reason: "superseded_workflow_task"
326
- });
327
- if (opts.cleanupActiveSession)
328
- await deleteActiveSession(task.id);
329
- console.log(`[Heartbeat] Workflow-step task ${task.id.slice(0, 8)} failed — engine will handle retry (${opts.shortLabel})`);
330
- const remaining2 = await getActiveTaskCount(task.agentId);
331
- if (remaining2 === 0)
332
- await restoreAgentIdleAfterRemediation(task.agentId);
333
- }
334
- return;
335
- }
336
- if (skipAutoResume || alreadyResumed) {
337
- const failed = await failTask(task.id, opts.legacyFailReason);
338
- if (failed) {
339
- findings.autoFailedTasks.push({
340
- taskId: task.id,
341
- agentId: task.agentId,
342
- reason: opts.legacyFailReason
343
- });
344
- if (opts.cleanupActiveSession)
345
- await deleteActiveSession(task.id);
346
- console.log(`[Heartbeat] Auto-failed task ${task.id.slice(0, 8)} — ${opts.shortLabel} (${skipAutoResume ? "skipRetry taskType" : "resume already exists"})`);
347
- const remaining2 = await getActiveTaskCount(task.agentId);
348
- if (remaining2 === 0)
349
- await restoreAgentIdleAfterRemediation(task.agentId);
350
- }
383
+ const resumeBudgetExhausted = getNextResumeGeneration(task) > maxResumeGenerations();
384
+ return decideRemediation(task, {
385
+ skipAutoResume,
386
+ alreadyResumed,
387
+ resumeBudgetExhausted,
388
+ supersedeReason: opts.supersedeReason,
389
+ legacyFailReason: opts.legacyFailReason
390
+ });
391
+ }
392
+ async function remediateCrashedWorkerTask(findings, task, opts, decision) {
393
+ if (!task.agentId)
351
394
  return;
352
- }
353
- const nextResumeGeneration = getNextResumeGeneration(task);
354
- if (nextResumeGeneration > maxResumeGenerations()) {
355
- const failed = await failTask(task.id, RESUME_BUDGET_EXHAUSTED_REASON);
395
+ if (decision.action === "fail") {
396
+ const failed = await failTask(task.id, decision.reason);
356
397
  if (failed) {
357
398
  findings.autoFailedTasks.push({
358
399
  taskId: task.id,
359
400
  agentId: task.agentId,
360
- reason: RESUME_BUDGET_EXHAUSTED_REASON
401
+ reason: decision.reason
361
402
  });
362
403
  if (opts.cleanupActiveSession)
363
404
  await deleteActiveSession(task.id);
364
- console.warn(`[Heartbeat] Auto-failed task ${task.id.slice(0, 8)} — ${RESUME_BUDGET_EXHAUSTED_REASON} (${opts.shortLabel})`);
405
+ const message = `[Heartbeat] Auto-failed task ${task.id.slice(0, 8)}: ${decision.reason} (${opts.shortLabel})`;
406
+ if (decision.reason === RESUME_BUDGET_EXHAUSTED_REASON)
407
+ console.warn(message);
408
+ else
409
+ console.log(message);
365
410
  const remaining2 = await getActiveTaskCount(task.agentId);
366
411
  if (remaining2 === 0)
367
412
  await restoreAgentIdleAfterRemediation(task.agentId);
@@ -370,7 +415,7 @@ async function remediateCrashedWorkerTask(findings, task, opts) {
370
415
  }
371
416
  await beforeHeartbeatSupersedeForTests?.(task);
372
417
  const superseded = await supersedeTask(task.id, {
373
- reason: opts.supersedeReason,
418
+ reason: decision.reason,
374
419
  resumeTaskId: null
375
420
  });
376
421
  if (!superseded) {
@@ -388,7 +433,7 @@ async function remediateCrashedWorkerTask(findings, task, opts) {
388
433
  taskId: task.id,
389
434
  resumeTaskId: resume.task.id,
390
435
  agentId: task.agentId,
391
- reason: opts.supersedeReason
436
+ reason: decision.reason
392
437
  });
393
438
  if (resume.task.agentId === task.agentId) {
394
439
  findings.pinnedResumes.push({ taskId: resume.task.id, agentId: task.agentId });
@@ -910,6 +955,7 @@ async function runHeartbeatSweep() {
910
955
  if (!await preflightGate()) {
911
956
  const cleanupOnlyFindings = {
912
957
  stalledTasks: [],
958
+ extensionSkipped: [],
913
959
  autoFailedTasks: [],
914
960
  autoResumedTasks: [],
915
961
  pinnedResumes: [],
@@ -956,6 +1002,9 @@ function logFindings(findings) {
956
1002
  if (findings.stalledTasks.length > 0) {
957
1003
  parts.push(`stalled=${findings.stalledTasks.length}`);
958
1004
  }
1005
+ if (findings.extensionSkipped.length > 0) {
1006
+ parts.push(`extension_skipped=${findings.extensionSkipped.length}`);
1007
+ }
959
1008
  if (findings.workerHealthFixes.length > 0) {
960
1009
  parts.push(`health_fixes=${findings.workerHealthFixes.length}`);
961
1010
  }
@@ -3966,7 +3966,7 @@ _EnvironmentWorker_signal = new WeakMap, _EnvironmentWorker_instances = new Weak
3966
3966
  const ctrl = new AbortController;
3967
3967
  const detachExternal = linkAbort(externalSignal, ctrl);
3968
3968
  const lease = new Lease(ctrl);
3969
- const agentToolset = await import("./node-209sxmg3.js");
3969
+ const agentToolset = await import("./node-x1g4v0pq.js");
3970
3970
  let leaseTtlMs;
3971
3971
  let runner;
3972
3972
  const heartbeatPromise = heartbeatLoop(sessionClient, work, lease, log2, this.requestOptions, (ttlMs) => {
@@ -1,3 +1,6 @@
1
+ import {
2
+ rewriteSlackMentions
3
+ } from "./cli-czjtgfys.js";
1
4
  import {
2
5
  bufferedFileFailures,
3
6
  buildEffectiveText,
@@ -6,10 +9,7 @@ import {
6
9
  extractSlackMessageText,
7
10
  fetchSlackFiles,
8
11
  notifySlackFileFailures
9
- } from "./cli-b8x19vbh.js";
10
- import {
11
- rewriteSlackMentions
12
- } from "./cli-72xdszyx.js";
12
+ } from "./cli-5tpgq60f.js";
13
13
  import {
14
14
  buildBufferFlushBlocks,
15
15
  ensureSlackThreadTree,
@@ -18,7 +18,7 @@ import {
18
18
  getSlackApp,
19
19
  isSlackRenderV2Enabled,
20
20
  registerTreeMessage
21
- } from "./cli-kt7wevqh.js";
21
+ } from "./cli-r2q6pevn.js";
22
22
  import {
23
23
  createLogEntry,
24
24
  getAgentById,
@@ -31,11 +31,11 @@ import {
31
31
  init_steering,
32
32
  requestSteering,
33
33
  slackContextKey
34
- } from "./cli-qp69dd5d.js";
34
+ } from "./cli-s14agm5s.js";
35
35
  import {
36
36
  init_steering_enabled,
37
37
  isSteeringEnabled
38
- } from "./cli-n75jt793.js";
38
+ } from "./cli-z61ykvam.js";
39
39
  import {
40
40
  __callDispose,
41
41
  __using
@@ -89,7 +89,7 @@ init_db();
89
89
  init_steering();
90
90
  init_steering_enabled();
91
91
  async function configuredSteeringTarget(channelId, threadTs) {
92
- switch (process.env.SLACK_THREAD_STEERING) {
92
+ switch (process.env.SLACK_THREAD_STEERING ?? "lead") {
93
93
  case "lead":
94
94
  return getLatestLeadTaskInThread(channelId, threadTs);
95
95
  case "all":
@@ -4,12 +4,12 @@ import {
4
4
  linkIdentity,
5
5
  recordUnmappedIdentity,
6
6
  resolveIdentity
7
- } from "./cli-ydk0wjj8.js";
7
+ } from "./cli-5tpgq60f.js";
8
8
  import {
9
9
  getKv,
10
10
  init_db,
11
11
  upsertKv
12
- } from "./cli-qp69dd5d.js";
12
+ } from "./cli-s14agm5s.js";
13
13
 
14
14
  // src/slack/enrich.ts
15
15
  init_db();
@@ -1,15 +1,12 @@
1
+ import {
2
+ fetchInstalledMcpServers
3
+ } from "./cli-tng3131n.js";
1
4
  import {
2
5
  require_cross_spawn
3
6
  } from "./cli-5bfdm1ah.js";
4
7
  import {
5
8
  resolveSlashSkillPrompt
6
9
  } from "./cli-r94z9p1z.js";
7
- import {
8
- readPkgVersion
9
- } from "./cli-2djtr51b.js";
10
- import {
11
- fetchInstalledMcpServers
12
- } from "./cli-tng3131n.js";
13
10
  import {
14
11
  CTX_MODE_NUDGE_EVERY
15
12
  } from "./cli-zm7njwzd.js";
@@ -18,12 +15,15 @@ import {
18
15
  clampContextPercent,
19
16
  getContextWindowSize
20
17
  } from "./cli-s25avqg9.js";
18
+ import {
19
+ readPkgVersion
20
+ } from "./cli-2djtr51b.js";
21
21
  import {
22
22
  applyReasoningEffort
23
23
  } from "./cli-4yc5d8fk.js";
24
24
  import {
25
25
  swarmRuntimeInstanceId
26
- } from "./cli-07jd68a1.js";
26
+ } from "./cli-re8z5p8p.js";
27
27
  import {
28
28
  DEFAULT_OPENROUTER_BASE_URL,
29
29
  getOpenRouterBaseUrl
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  init_package,
3
3
  package_default
4
- } from "./cli-gm0fhz13.js";
4
+ } from "./cli-zkxymas5.js";
5
5
 
6
6
  // src/commands/shared/client-config.ts
7
7
  init_package();
@@ -6,13 +6,13 @@ import {
6
6
  IDENTITY_FIELD_BUDGETS,
7
7
  init_identity_field_budget,
8
8
  init_templates
9
- } from "./cli-hmyynq9b.js";
9
+ } from "./cli-ht5rs63n.js";
10
10
  import {
11
11
  init_resolver,
12
12
  init_steering_enabled,
13
13
  isSteeringEnabled,
14
14
  resolveTemplateAsync
15
- } from "./cli-n75jt793.js";
15
+ } from "./cli-z61ykvam.js";
16
16
  import {
17
17
  MAX_PROFILE_FILE_LENGTH,
18
18
  init_constants
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  materializeClaudeMd,
3
3
  stopClaudeMd
4
- } from "./cli-1mx65de9.js";
4
+ } from "./cli-wbyk465z.js";
5
5
  import {
6
6
  summarizeSession
7
- } from "./cli-dyx0237s.js";
7
+ } from "./cli-j4nv2wqy.js";
8
8
  import {
9
9
  checkToolLoop,
10
10
  clearToolHistory
@@ -15,7 +15,7 @@ import {
15
15
  fetchRetrievalsForTask,
16
16
  isLlmRaterEnabled,
17
17
  postRatings
18
- } from "./cli-xvkmedgn.js";
18
+ } from "./cli-4wppfkcm.js";
19
19
  import {
20
20
  getApiKey
21
21
  } from "./cli-f14fvzag.js";
@@ -26,7 +26,7 @@ import {
26
26
  init_profile_sync,
27
27
  readIdentityBaselines,
28
28
  warnProfileFileTooLarge
29
- } from "./cli-a45d5v9b.js";
29
+ } from "./cli-fm4ytsdk.js";
30
30
  import {
31
31
  MAX_PROFILE_FILE_LENGTH,
32
32
  getMcpBaseUrl,
@@ -35,7 +35,7 @@ import {
35
35
  import {
36
36
  init_package,
37
37
  package_default
38
- } from "./cli-gm0fhz13.js";
38
+ } from "./cli-zkxymas5.js";
39
39
  import {
40
40
  init_secret_scrubber,
41
41
  scrubSecrets
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  buildModelsDevSeedRows,
3
3
  loadModelsDevCache
4
- } from "./cli-ceb5y160.js";
4
+ } from "./cli-0qb1z6s2.js";
5
5
  import {
6
6
  createLogEntry,
7
7
  getActivePricingRow,
8
8
  getDbClient,
9
9
  init_db,
10
10
  insertPricingRow
11
- } from "./cli-qp69dd5d.js";
11
+ } from "./cli-s14agm5s.js";
12
12
  import {
13
13
  init_secret_scrubber,
14
14
  scrubSecrets
@@ -9,6 +9,18 @@ import {
9
9
  _enum
10
10
  } from "./cli-w5e1d1vv.js";
11
11
 
12
+ // src/rbac/elevated-agents.ts
13
+ var leadEquivalentAgentIds = new Set;
14
+ function grantLeadEquivalence(agentId) {
15
+ leadEquivalentAgentIds.add(agentId);
16
+ }
17
+ function revokeLeadEquivalence(agentId) {
18
+ leadEquivalentAgentIds.delete(agentId);
19
+ }
20
+ function hasLeadEquivalence(agentId) {
21
+ return !!agentId && leadEquivalentAgentIds.has(agentId);
22
+ }
23
+
12
24
  // src/rbac/permissions.ts
13
25
  init_zod();
14
26
  var PERMISSIONS = {
@@ -251,6 +263,14 @@ var PERMISSIONS = {
251
263
  "script.api.delete": {
252
264
  description: "Delete an external script API endpoint.",
253
265
  namespace: "script"
266
+ },
267
+ "extension.write": {
268
+ description: "Install, update, or uninstall a swarm extension.",
269
+ namespace: "extension"
270
+ },
271
+ "extension.activate": {
272
+ description: "Enable, disable, or activate a version of a swarm extension.",
273
+ namespace: "extension"
254
274
  }
255
275
  };
256
276
  var PERMISSION_VERBS = Object.keys(PERMISSIONS);
@@ -259,7 +279,7 @@ var PermissionVerbSchema = _enum(PERMISSION_VERBS);
259
279
  // src/rbac/admission.ts
260
280
  init_env_flag();
261
281
  function isRbacEnabled() {
262
- return isEnvFlagEnabled("RBAC_ENABLED", false);
282
+ return isEnvFlagEnabled("RBAC_ENABLED", true);
263
283
  }
264
284
  function decideAdmission(input) {
265
285
  if (input.grant.grantsAll) {
@@ -295,10 +315,23 @@ function decideToolAdmission(input) {
295
315
  return { allow: false, reason: "admission: tool has no permission verb (operator-only)" };
296
316
  }
297
317
  // src/rbac/legacy-policy.ts
318
+ function actsAsLead(principal) {
319
+ return principal.kind === "agent" && (principal.isLead || hasLeadEquivalence(principal.agentId));
320
+ }
298
321
  var leadOnly = {
299
322
  name: "lead-only",
300
323
  denyReason: "requires lead agent",
301
- evaluate: (principal) => principal.kind === "agent" && principal.isLead
324
+ evaluate: (principal) => actsAsLead(principal)
325
+ };
326
+ var operatorOrUser = {
327
+ name: "operator-or-user",
328
+ denyReason: "requires operator or user authentication",
329
+ evaluate: (principal) => principal.kind === "operator" || principal.kind === "user"
330
+ };
331
+ var leadOrOperatorOrUser = {
332
+ name: "lead-or-operator-or-user",
333
+ denyReason: "requires lead agent, operator, or user authentication",
334
+ evaluate: (principal) => principal.kind === "operator" || principal.kind === "user" || actsAsLead(principal)
302
335
  };
303
336
  var leadOrTaskCreator = {
304
337
  name: "lead-or-task-creator",
@@ -306,7 +339,7 @@ var leadOrTaskCreator = {
306
339
  evaluate: (principal, resource) => {
307
340
  if (principal.kind !== "agent")
308
341
  return false;
309
- if (principal.isLead)
342
+ if (actsAsLead(principal))
310
343
  return true;
311
344
  return resource?.kind === "task" && resource.creatorAgentId != null && resource.creatorAgentId === principal.agentId;
312
345
  }
@@ -317,7 +350,7 @@ var leadOrResourceOwner = {
317
350
  evaluate: (principal, resource) => {
318
351
  if (principal.kind !== "agent")
319
352
  return false;
320
- if (principal.isLead)
353
+ if (actsAsLead(principal))
321
354
  return true;
322
355
  return resource?.kind === "owned" && resource.ownerAgentId != null && resource.ownerAgentId === principal.agentId;
323
356
  }
@@ -328,7 +361,7 @@ var leadOrOwnNamespace = {
328
361
  evaluate: (principal, resource) => {
329
362
  if (principal.kind !== "agent")
330
363
  return false;
331
- if (principal.isLead)
364
+ if (actsAsLead(principal))
332
365
  return true;
333
366
  return principal.agentId !== "" && resource?.kind === "kv-namespace" && resource.namespace === `task:agent:${principal.agentId}`;
334
367
  }
@@ -355,7 +388,7 @@ var memoryOwnerOrLeadSwarm = {
355
388
  return false;
356
389
  if (resource.ownerAgentId != null && resource.ownerAgentId === principal.agentId)
357
390
  return true;
358
- return principal.isLead && resource.scope === "swarm";
391
+ return actsAsLead(principal) && resource.scope === "swarm";
359
392
  }
360
393
  };
361
394
  var taskFsMutate = {
@@ -364,7 +397,7 @@ var taskFsMutate = {
364
397
  evaluate: (principal, resource) => {
365
398
  if (principal.kind === "operator" || principal.kind === "user")
366
399
  return true;
367
- if (principal.isLead)
400
+ if (actsAsLead(principal))
368
401
  return true;
369
402
  if (resource?.kind !== "task")
370
403
  return false;
@@ -431,7 +464,9 @@ var LEGACY_POLICY = {
431
464
  "script.api.create": leadOnly,
432
465
  "script.api.update": leadOnly,
433
466
  "script.api.rotate": leadOnly,
434
- "script.api.delete": leadOnly
467
+ "script.api.delete": leadOnly,
468
+ "extension.write": leadOrOperatorOrUser,
469
+ "extension.activate": operatorOrUser
435
470
  };
436
471
 
437
472
  // src/rbac/can.ts
@@ -452,4 +487,4 @@ function can(check) {
452
487
  }
453
488
  return decision;
454
489
  }
455
- export { isRbacEnabled, decideAdmission, decideToolAdmission, setAuditSink, clearAuditSink, can, PermissionVerbSchema };
490
+ export { isRbacEnabled, decideAdmission, decideToolAdmission, grantLeadEquivalence, revokeLeadEquivalence, setAuditSink, clearAuditSink, can, PermissionVerbSchema };