@desplega.ai/agent-swarm 1.151.0 → 1.152.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 (104) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ex8hzjfc.js → acp-adapter-d05sg0q4.js} +1 -1
  3. package/dist/{actions-2bgpyhww.js → actions-4sc0v342.js} +13 -13
  4. package/dist/{app-1706zhr1.js → app-2d0v6kt6.js} +3 -3
  5. package/dist/{assistant-bavke5p7.js → assistant-zs6wdnrf.js} +14 -14
  6. package/dist/{boot-reembed-nafcmmmc.js → boot-reembed-3dwdnnsr.js} +3 -3
  7. package/dist/{boot-reembed-3cmrrmpa.js → boot-reembed-vhh33520.js} +4 -4
  8. package/dist/{boot-scrub-logs-cd6a2sq0.js → boot-scrub-logs-e1fnabcg.js} +2 -2
  9. package/dist/{claude-adapter-wfp2gzvz.js → claude-adapter-h58xqzzd.js} +3 -3
  10. package/dist/{claude-sdk-session-bht9jjak.js → claude-sdk-session-pbaczbgt.js} +3 -3
  11. package/dist/{cli-a1z3h107.js → cli-4fqn2vpg.js} +4 -4
  12. package/dist/{cli-g69fdc9g.js → cli-5bqt4gwa.js} +2 -2
  13. package/dist/{cli-gjyvhmmh.js → cli-5p007m2q.js} +5 -5
  14. package/dist/{cli-5jd2z7av.js → cli-6k2athpf.js} +6 -2
  15. package/dist/{cli-5tpgq60f.js → cli-72vksk1n.js} +152 -23
  16. package/dist/{cli-vwm416m6.js → cli-87hdfyde.js} +1 -1
  17. package/dist/{cli-3v9xhjcn.js → cli-8fy9dmpv.js} +2 -2
  18. package/dist/{cli-czjtgfys.js → cli-awb59f08.js} +2 -2
  19. package/dist/{cli-j9xczhaq.js → cli-cs9z1hw3.js} +1 -1
  20. package/dist/{cli-r2q6pevn.js → cli-cwvey7n1.js} +43 -21
  21. package/dist/{cli-ppm4975n.js → cli-evgy5w3y.js} +1 -1
  22. package/dist/{cli-frcta2w4.js → cli-f1f9n77e.js} +1 -1
  23. package/dist/{cli-9004vfdf.js → cli-fhdssm2v.js} +2 -2
  24. package/dist/{cli-s14agm5s.js → cli-gacq5hg8.js} +12 -3
  25. package/dist/{cli-zkxymas5.js → cli-jh9txj4n.js} +1 -1
  26. package/dist/{cli-q88st9aj.js → cli-nd5s3m4y.js} +2 -2
  27. package/dist/{cli-sjaae6ff.js → cli-p2hx1pxm.js} +3 -3
  28. package/dist/{cli-2tbvf1z1.js → cli-t1mykkng.js} +8 -8
  29. package/dist/{cli-7tgcstn2.js → cli-t6axtdcg.js} +2 -2
  30. package/dist/{cli-f1wky6zp.js → cli-wp7cejrg.js} +1 -1
  31. package/dist/{cli-0qb1z6s2.js → cli-zdcdh02m.js} +1 -1
  32. package/dist/{cli-gbfwcd3k.js → cli-zfzznn7c.js} +7 -6
  33. package/dist/cli.js +11 -11
  34. package/dist/{codex-adapter-jjjk8w4m.js → codex-adapter-v3cz462q.js} +2 -2
  35. package/dist/{codex-session-runner-nd6ayxkx.js → codex-session-runner-de1a5g5z.js} +2 -2
  36. package/dist/{commands-9v4psyq1.js → commands-wfqqpn95.js} +2 -2
  37. package/dist/{db-wnt58tpe.js → db-9zzv5y05.js} +2 -2
  38. package/dist/{dispatcher-05jh1aqk.js → dispatcher-hfm1jbgx.js} +12 -12
  39. package/dist/{handlers-tw90pkh5.js → handlers-wrrhsack.js} +15 -15
  40. package/dist/{hook-sxe3r349.js → hook-9skye8zd.js} +1 -1
  41. package/dist/{hook-123e2scb.js → hook-fgjv62k5.js} +2 -2
  42. package/dist/{http-ecsar8ez.js → http-7grttjfq.js} +37 -34
  43. package/dist/{index-nnrbpcjp.js → index-29gxx9ar.js} +12 -12
  44. package/dist/{index-hw26vj40.js → index-30pz2h9w.js} +12 -12
  45. package/dist/{index-zj518gf9.js → index-4ek1df87.js} +13 -13
  46. package/dist/{index-16js521z.js → index-myfwqqyq.js} +8 -8
  47. package/dist/{index-ymn7em0p.js → index-pfhzrh1d.js} +3 -3
  48. package/dist/{keepalive-asqtcm4y.js → keepalive-j75m2m7k.js} +4 -4
  49. package/dist/{lead-xbfr7fvt.js → lead-a1hpjt0a.js} +16 -16
  50. package/dist/{maintenance-qma55qvw.js → maintenance-tngjzqdq.js} +4 -4
  51. package/dist/{oauth-refresh-sweep-3s04c6qw.js → oauth-refresh-sweep-em1fn044.js} +3 -3
  52. package/dist/{onboard-drskd386.js → onboard-fv7ezvwx.js} +2 -2
  53. package/dist/{otel-impl-943c96er.js → otel-impl-6vbb568y.js} +1 -1
  54. package/dist/{pricing-refresh-mx51az05.js → pricing-refresh-nmm949an.js} +4 -4
  55. package/dist/{rbac-roles-wcmrg6sv.js → rbac-roles-0fz5qryx.js} +4 -4
  56. package/dist/{rbac-roles-78baecqd.js → rbac-roles-xtp05syf.js} +3 -3
  57. package/dist/{render-v2-8zjntgf5.js → render-v2-fpb8whme.js} +3 -3
  58. package/dist/{seed-pricing-jqjs6cws.js → seed-pricing-zwa8bs3t.js} +3 -3
  59. package/dist/{setup-4pks0vfk.js → setup-3ybwbdpd.js} +2 -2
  60. package/dist/{work-objects-wangt792.js → work-objects-rmayxcx7.js} +18 -17
  61. package/dist/{worker-p2mr422x.js → worker-rng4jhnh.js} +16 -16
  62. package/openapi.json +4 -4
  63. package/package.json +1 -1
  64. package/src/be/db.ts +1 -1
  65. package/src/be/scripts/typecheck.ts +4 -0
  66. package/src/be/swarm-config-guard.ts +7 -1
  67. package/src/extensions/lifecycle.ts +26 -4
  68. package/src/http/extensions.ts +8 -3
  69. package/src/rbac/legacy-policy.ts +13 -1
  70. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  71. package/src/scripts-runtime/types/stdlib.d.ts +4 -0
  72. package/src/scripts-runtime/types/swarm-sdk.d.ts +4 -0
  73. package/src/server.ts +12 -0
  74. package/src/slack/render-v2.ts +10 -4
  75. package/src/slack/responses.ts +7 -4
  76. package/src/slack/task-output.ts +21 -0
  77. package/src/slack/watcher.ts +3 -2
  78. package/src/slack/work-objects.ts +2 -1
  79. package/src/tests/extensions-example-mcp-install.test.ts +2 -2
  80. package/src/tests/extensions-http.test.ts +84 -3
  81. package/src/tests/extensions-lead-equivalence.test.ts +21 -0
  82. package/src/tests/extensions-mcp-tools.test.ts +111 -3
  83. package/src/tests/fixtures/store-progress-malformed-output.json +4 -0
  84. package/src/tests/rbac-admission-e2e.test.ts +35 -4
  85. package/src/tests/rbac-e2e-helpers.ts +18 -0
  86. package/src/tests/rbac-engine.test.ts +2 -2
  87. package/src/tests/rbac-mcp-admission-e2e.test.ts +22 -4
  88. package/src/tests/reload-config.test.ts +17 -0
  89. package/src/tests/scripts-only-gating.test.ts +4 -0
  90. package/src/tests/slack-render-v2.test.ts +24 -2
  91. package/src/tests/slack-task-output.test.ts +36 -0
  92. package/src/tests/store-progress-attachments-handler.test.ts +100 -1
  93. package/src/tests/swarm-config-reserved-keys.test.ts +6 -1
  94. package/src/tests/tool-annotations.test.ts +1 -1
  95. package/src/tools/extension-activate-version.ts +38 -0
  96. package/src/tools/extension-common.ts +2 -1
  97. package/src/tools/extension-delete.ts +29 -0
  98. package/src/tools/extension-disable.ts +36 -0
  99. package/src/tools/extension-enable.ts +36 -0
  100. package/src/tools/extension-install.ts +2 -2
  101. package/src/tools/store-progress.ts +30 -0
  102. package/src/tools/tool-config.ts +5 -1
  103. package/templates/skills/agent-browser/SKILL.md +84 -0
  104. package/templates/skills/agent-browser/content.md +21 -0
@@ -3,7 +3,7 @@ import {
3
3
  createDefaultMcpJson,
4
4
  createDefaultSettingsLocal,
5
5
  createHooksConfig
6
- } from "./cli-f1wky6zp.js";
6
+ } from "./cli-wp7cejrg.js";
7
7
  import {
8
8
  require_jsx_dev_runtime
9
9
  } from "./cli-s2qjdd6z.js";
@@ -13,7 +13,7 @@ import {
13
13
  import {
14
14
  init_package,
15
15
  package_default
16
- } from "./cli-zkxymas5.js";
16
+ } from "./cli-jh9txj4n.js";
17
17
  import {
18
18
  Box_default,
19
19
  Select,
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  init_package,
6
6
  package_default
7
- } from "./cli-zkxymas5.js";
7
+ } from "./cli-jh9txj4n.js";
8
8
  import {
9
9
  init_secret_scrubber,
10
10
  scrubSecrets
@@ -2,9 +2,9 @@ import {
2
2
  PRICING_REFRESH_INTERVAL_MS,
3
3
  refreshPricingFromModelsDev,
4
4
  startPricingRefreshLoop
5
- } from "./cli-g69fdc9g.js";
6
- import"./cli-0qb1z6s2.js";
7
- import"./cli-s14agm5s.js";
5
+ } from "./cli-5bqt4gwa.js";
6
+ import"./cli-zdcdh02m.js";
7
+ import"./cli-gacq5hg8.js";
8
8
  import"./cli-ht5rs63n.js";
9
9
  import"./cli-z61ykvam.js";
10
10
  import"./cli-dv6cdjs2.js";
@@ -12,7 +12,7 @@ import"./cli-c2mk1kgf.js";
12
12
  import"./cli-ej6gbxfb.js";
13
13
  import"./cli-sd0mxa3c.js";
14
14
  import"./cli-w5e1d1vv.js";
15
- import"./cli-zkxymas5.js";
15
+ import"./cli-jh9txj4n.js";
16
16
  import"./cli-r2ap2czm.js";
17
17
  import"./cli-zf8jjwex.js";
18
18
  import"./cli-bc05qbss.js";
@@ -7,9 +7,9 @@ import {
7
7
  getUserGrant,
8
8
  listUserRoles,
9
9
  runRbacCliCommand
10
- } from "./cli-7tgcstn2.js";
11
- import"./cli-gbfwcd3k.js";
12
- import"./cli-s14agm5s.js";
10
+ } from "./cli-t6axtdcg.js";
11
+ import"./cli-zfzznn7c.js";
12
+ import"./cli-gacq5hg8.js";
13
13
  import"./cli-ht5rs63n.js";
14
14
  import"./cli-z61ykvam.js";
15
15
  import"./cli-dv6cdjs2.js";
@@ -17,7 +17,7 @@ import"./cli-c2mk1kgf.js";
17
17
  import"./cli-ej6gbxfb.js";
18
18
  import"./cli-sd0mxa3c.js";
19
19
  import"./cli-w5e1d1vv.js";
20
- import"./cli-zkxymas5.js";
20
+ import"./cli-jh9txj4n.js";
21
21
  import"./cli-r2ap2czm.js";
22
22
  import"./cli-zf8jjwex.js";
23
23
  import"./cli-bc05qbss.js";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  PermissionVerbSchema
3
- } from "./cli-gbfwcd3k.js";
3
+ } from "./cli-zfzznn7c.js";
4
4
  import {
5
5
  getDb,
6
6
  getDbClient,
7
7
  init_db
8
- } from "./cli-s14agm5s.js";
8
+ } from "./cli-gacq5hg8.js";
9
9
  import"./cli-ht5rs63n.js";
10
10
  import"./cli-z61ykvam.js";
11
11
  import"./cli-dv6cdjs2.js";
@@ -16,7 +16,7 @@ import {
16
16
  } from "./cli-ej6gbxfb.js";
17
17
  import"./cli-sd0mxa3c.js";
18
18
  import"./cli-w5e1d1vv.js";
19
- import"./cli-zkxymas5.js";
19
+ import"./cli-jh9txj4n.js";
20
20
  import"./cli-r2ap2czm.js";
21
21
  import"./cli-zf8jjwex.js";
22
22
  import"./cli-bc05qbss.js";
@@ -9,11 +9,11 @@ import {
9
9
  processSlackRenderV2,
10
10
  renderThreadTree,
11
11
  streamOutcomeCard
12
- } from "./cli-r2q6pevn.js";
12
+ } from "./cli-cwvey7n1.js";
13
13
  import"./cli-q51yprfq.js";
14
14
  import"./cli-yatxqynm.js";
15
15
  import"./cli-2658f6at.js";
16
- import"./cli-s14agm5s.js";
16
+ import"./cli-gacq5hg8.js";
17
17
  import"./cli-ht5rs63n.js";
18
18
  import"./cli-z61ykvam.js";
19
19
  import"./cli-dv6cdjs2.js";
@@ -21,7 +21,7 @@ import"./cli-c2mk1kgf.js";
21
21
  import"./cli-ej6gbxfb.js";
22
22
  import"./cli-sd0mxa3c.js";
23
23
  import"./cli-w5e1d1vv.js";
24
- import"./cli-zkxymas5.js";
24
+ import"./cli-jh9txj4n.js";
25
25
  import"./cli-r2ap2czm.js";
26
26
  import"./cli-pzxba7gw.js";
27
27
  import"./cli-zf8jjwex.js";
@@ -2,8 +2,8 @@ import {
2
2
  buildModelsDevSeedRows,
3
3
  buildPricingSeedRows,
4
4
  seedPricingFromModelsDev
5
- } from "./cli-0qb1z6s2.js";
6
- import"./cli-s14agm5s.js";
5
+ } from "./cli-zdcdh02m.js";
6
+ import"./cli-gacq5hg8.js";
7
7
  import"./cli-ht5rs63n.js";
8
8
  import"./cli-z61ykvam.js";
9
9
  import"./cli-dv6cdjs2.js";
@@ -11,7 +11,7 @@ import"./cli-c2mk1kgf.js";
11
11
  import"./cli-ej6gbxfb.js";
12
12
  import"./cli-sd0mxa3c.js";
13
13
  import"./cli-w5e1d1vv.js";
14
- import"./cli-zkxymas5.js";
14
+ import"./cli-jh9txj4n.js";
15
15
  import"./cli-r2ap2czm.js";
16
16
  import"./cli-zf8jjwex.js";
17
17
  import"./cli-bc05qbss.js";
@@ -4,14 +4,14 @@ import {
4
4
  createDefaultMcpJson,
5
5
  createDefaultSettingsLocal,
6
6
  createHooksConfig
7
- } from "./cli-f1wky6zp.js";
7
+ } from "./cli-wp7cejrg.js";
8
8
  import {
9
9
  require_jsx_dev_runtime
10
10
  } from "./cli-s2qjdd6z.js";
11
11
  import {
12
12
  getApiKey
13
13
  } from "./cli-f14fvzag.js";
14
- import"./cli-zkxymas5.js";
14
+ import"./cli-jh9txj4n.js";
15
15
  import {
16
16
  Box_default,
17
17
  Spinner,
@@ -1,33 +1,34 @@
1
1
  import {
2
2
  isUserAllowed
3
- } from "./cli-gjyvhmmh.js";
4
- import"./cli-a1z3h107.js";
5
- import"./cli-czjtgfys.js";
6
- import"./cli-5tpgq60f.js";
3
+ } from "./cli-5p007m2q.js";
4
+ import"./cli-4fqn2vpg.js";
5
+ import"./cli-awb59f08.js";
6
+ import"./cli-72vksk1n.js";
7
7
  import"./cli-0z2v4nhw.js";
8
8
  import"./cli-4wppfkcm.js";
9
9
  import"./cli-e7d20cty.js";
10
10
  import"./cli-re8z5p8p.js";
11
11
  import"./cli-3dpj7atn.js";
12
- import"./cli-g69fdc9g.js";
13
- import"./cli-7tgcstn2.js";
14
- import"./cli-gbfwcd3k.js";
15
- import"./cli-sjaae6ff.js";
12
+ import"./cli-5bqt4gwa.js";
13
+ import"./cli-t6axtdcg.js";
14
+ import"./cli-zfzznn7c.js";
15
+ import"./cli-p2hx1pxm.js";
16
16
  import"./cli-epan13p1.js";
17
17
  import"./cli-y89t4nca.js";
18
18
  import"./cli-f14fvzag.js";
19
19
  import"./cli-fad8m16k.js";
20
- import"./cli-j9xczhaq.js";
21
- import"./cli-0qb1z6s2.js";
20
+ import"./cli-cs9z1hw3.js";
21
+ import"./cli-zdcdh02m.js";
22
22
  import"./cli-bsakbbkm.js";
23
- import"./cli-q88st9aj.js";
23
+ import"./cli-nd5s3m4y.js";
24
24
  import"./cli-51tf7ac3.js";
25
25
  import {
26
- getTaskUrl
27
- } from "./cli-r2q6pevn.js";
26
+ getTaskUrl,
27
+ slackTaskOutput
28
+ } from "./cli-cwvey7n1.js";
28
29
  import"./cli-q51yprfq.js";
29
30
  import"./cli-yatxqynm.js";
30
- import"./cli-ppm4975n.js";
31
+ import"./cli-evgy5w3y.js";
31
32
  import"./cli-fm4ytsdk.js";
32
33
  import"./cli-aehm1rbq.js";
33
34
  import"./cli-2658f6at.js";
@@ -36,7 +37,7 @@ import {
36
37
  getAgentById,
37
38
  getTaskById,
38
39
  init_db
39
- } from "./cli-s14agm5s.js";
40
+ } from "./cli-gacq5hg8.js";
40
41
  import"./cli-ht5rs63n.js";
41
42
  import"./cli-z61ykvam.js";
42
43
  import"./cli-dv6cdjs2.js";
@@ -47,7 +48,7 @@ import {
47
48
  } from "./cli-ej6gbxfb.js";
48
49
  import"./cli-sd0mxa3c.js";
49
50
  import"./cli-w5e1d1vv.js";
50
- import"./cli-zkxymas5.js";
51
+ import"./cli-jh9txj4n.js";
51
52
  import"./cli-r2ap2czm.js";
52
53
  import"./cli-pzxba7gw.js";
53
54
  import"./cli-f7kvq46p.js";
@@ -86,7 +87,7 @@ async function getDetails(event, client) {
86
87
  if (task.slackChannelId !== event.channel)
87
88
  return { error: { status: "restricted" } };
88
89
  const agent = task.agentId ? await getAgentById(task.agentId) : null;
89
- const result = task.output || task.failureReason || task.progress;
90
+ const result = slackTaskOutput(task) || task.failureReason || task.progress;
90
91
  return {
91
92
  metadata: {
92
93
  entity_type: "slack#/entities/task",
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  runAgent
3
- } from "./cli-2tbvf1z1.js";
3
+ } from "./cli-t1mykkng.js";
4
4
  import"./cli-pgj4a5fb.js";
5
5
  import"./cli-kj76p1ez.js";
6
6
  import"./cli-9b13ggd1.js";
7
7
  import"./cli-d3p82erb.js";
8
- import"./cli-3v9xhjcn.js";
9
- import"./cli-frcta2w4.js";
8
+ import"./cli-8fy9dmpv.js";
9
+ import"./cli-f1f9n77e.js";
10
10
  import"./cli-wbyk465z.js";
11
11
  import"./cli-tng3131n.js";
12
12
  import"./cli-5bfdm1ah.js";
13
- import"./cli-vwm416m6.js";
13
+ import"./cli-87hdfyde.js";
14
14
  import"./cli-hsxj0yar.js";
15
15
  import"./cli-r94z9p1z.js";
16
16
  import"./cli-b5b30yzk.js";
@@ -25,34 +25,34 @@ import"./cli-eree7rnv.js";
25
25
  import"./cli-4yc5d8fk.js";
26
26
  import {
27
27
  getEnabledCapabilities
28
- } from "./cli-5tpgq60f.js";
28
+ } from "./cli-72vksk1n.js";
29
29
  import"./cli-0z2v4nhw.js";
30
30
  import"./cli-4wppfkcm.js";
31
31
  import"./cli-e7d20cty.js";
32
32
  import"./cli-re8z5p8p.js";
33
33
  import"./cli-3dpj7atn.js";
34
- import"./cli-g69fdc9g.js";
35
- import"./cli-7tgcstn2.js";
36
- import"./cli-gbfwcd3k.js";
37
- import"./cli-sjaae6ff.js";
34
+ import"./cli-5bqt4gwa.js";
35
+ import"./cli-t6axtdcg.js";
36
+ import"./cli-zfzznn7c.js";
37
+ import"./cli-p2hx1pxm.js";
38
38
  import"./cli-epan13p1.js";
39
39
  import"./cli-y89t4nca.js";
40
40
  import"./cli-f14fvzag.js";
41
41
  import"./cli-fad8m16k.js";
42
- import"./cli-j9xczhaq.js";
43
- import"./cli-0qb1z6s2.js";
42
+ import"./cli-cs9z1hw3.js";
43
+ import"./cli-zdcdh02m.js";
44
44
  import"./cli-bsakbbkm.js";
45
- import"./cli-q88st9aj.js";
45
+ import"./cli-nd5s3m4y.js";
46
46
  import"./cli-51tf7ac3.js";
47
- import"./cli-r2q6pevn.js";
47
+ import"./cli-cwvey7n1.js";
48
48
  import"./cli-q51yprfq.js";
49
49
  import"./cli-yatxqynm.js";
50
- import"./cli-ppm4975n.js";
50
+ import"./cli-evgy5w3y.js";
51
51
  import"./cli-fm4ytsdk.js";
52
52
  import"./cli-aehm1rbq.js";
53
53
  import"./cli-2658f6at.js";
54
54
  import"./cli-jsp14b6c.js";
55
- import"./cli-s14agm5s.js";
55
+ import"./cli-gacq5hg8.js";
56
56
  import"./cli-ht5rs63n.js";
57
57
  import"./cli-z61ykvam.js";
58
58
  import"./cli-dv6cdjs2.js";
@@ -60,7 +60,7 @@ import"./cli-c2mk1kgf.js";
60
60
  import"./cli-ej6gbxfb.js";
61
61
  import"./cli-sd0mxa3c.js";
62
62
  import"./cli-w5e1d1vv.js";
63
- import"./cli-zkxymas5.js";
63
+ import"./cli-jh9txj4n.js";
64
64
  import"./cli-r2ap2czm.js";
65
65
  import"./cli-pzxba7gw.js";
66
66
  import"./cli-f7kvq46p.js";
package/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Agent Swarm API",
5
- "version": "1.151.0",
5
+ "version": "1.152.0",
6
6
  "description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
7
7
  },
8
8
  "servers": [
@@ -16466,7 +16466,7 @@
16466
16466
  "post": {
16467
16467
  "operationId": "extensions_enable",
16468
16468
  "summary": "Enable an extension",
16469
- "description": "Loads and enables an extension. This route is operator-only.",
16469
+ "description": "Loads and enables an extension. Available to leads, operators, and dashboard users.",
16470
16470
  "tags": [
16471
16471
  "Extensions"
16472
16472
  ],
@@ -16542,7 +16542,7 @@
16542
16542
  "post": {
16543
16543
  "operationId": "extensions_disable",
16544
16544
  "summary": "Disable an extension",
16545
- "description": "Unloads and disables an extension. This route is operator-only.",
16545
+ "description": "Unloads and disables an extension. Available to leads, operators, and dashboard users.",
16546
16546
  "tags": [
16547
16547
  "Extensions"
16548
16548
  ],
@@ -16608,7 +16608,7 @@
16608
16608
  "post": {
16609
16609
  "operationId": "extensions_activate_version",
16610
16610
  "summary": "Activate an extension version",
16611
- "description": "Activates a stored version. This route is operator-only.",
16611
+ "description": "Activates a stored version. Available to leads, operators, and dashboard users.",
16612
16612
  "tags": [
16613
16613
  "Extensions"
16614
16614
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/agent-swarm",
3
- "version": "1.151.0",
3
+ "version": "1.152.0",
4
4
  "description": "agent-swarm.dev — an open-source operating system for AI work: a lead agent breaks goals into tasks, routes them to specialized workers such as Claude Code or Codex, runs each worker in an isolated container, and preserves shared memory, tools, schedules, and review gates so delegated work compounds across sessions.",
5
5
  "keywords": [
6
6
  "agent-swarm.dev",
package/src/be/db.ts CHANGED
@@ -6154,7 +6154,7 @@ export async function getInjectableGlobalConfigs(): Promise<SwarmConfig[]> {
6154
6154
  const rows = await getDbClient().query<SwarmConfigRow>(
6155
6155
  `SELECT * FROM swarm_config
6156
6156
  WHERE scope = 'global'
6157
- AND UPPER(key) NOT IN ('API_KEY', 'SECRETS_ENCRYPTION_KEY', 'CORS_ALLOW_ANY_ORIGIN')
6157
+ AND UPPER(key) NOT IN ('API_KEY', 'SECRETS_ENCRYPTION_KEY', 'CORS_ALLOW_ANY_ORIGIN', 'EXTENSION_ALLOW_LEAD_ACTIVATION')
6158
6158
  ORDER BY key ASC`,
6159
6159
  );
6160
6160
  return rows.map(rowToSwarmConfig);
@@ -318,6 +318,10 @@ export interface SwarmSdk {
318
318
  // --- write: extensions ---
319
319
  extension_install(args: { manifest: Record<string, unknown>; files: Record<string, string>; priority?: number; config?: Record<string, unknown> }): Promise<unknown>;
320
320
  extension_list(args?: { enabledOnly?: boolean }): Promise<unknown>;
321
+ extension_delete(args: { id: string }): Promise<unknown>;
322
+ extension_enable(args: { id: string }): Promise<unknown>;
323
+ extension_disable(args: { id: string }): Promise<unknown>;
324
+ extension_activate_version(args: { id: string; version: number }): Promise<unknown>;
321
325
 
322
326
  // --- write: repos ---
323
327
  repo_update(args: Record<string, unknown>): Promise<unknown>;
@@ -18,7 +18,13 @@ import { parseTaskToolManifest } from "../utils/task-tool-manifest";
18
18
  * Matching is case-insensitive so `api_key`, `Api_Key`, etc. are all
19
19
  * rejected at every write path (DB helpers, HTTP routes, MCP tools).
20
20
  */
21
- const RESERVED_KEYS = new Set(["API_KEY", "SECRETS_ENCRYPTION_KEY", "CORS_ALLOW_ANY_ORIGIN"]);
21
+ // Lead activation is also deployment-only: leads can write ordinary global config.
22
+ const RESERVED_KEYS = new Set([
23
+ "API_KEY",
24
+ "SECRETS_ENCRYPTION_KEY",
25
+ "CORS_ALLOW_ANY_ORIGIN",
26
+ "EXTENSION_ALLOW_LEAD_ACTIVATION",
27
+ ]);
22
28
 
23
29
  export function isReservedConfigKey(key: string): boolean {
24
30
  return RESERVED_KEYS.has(key.toUpperCase());
@@ -3,6 +3,7 @@ import {
3
3
  getExtensionById,
4
4
  getExtensionFiles,
5
5
  getExtensionVersion,
6
+ insertExtensionRun,
6
7
  listExtensions,
7
8
  pruneExtensionRuns,
8
9
  setExtensionState,
@@ -95,14 +96,33 @@ async function removeRegistered(id: string): Promise<void> {
95
96
  if (previous) await previous.dispose();
96
97
  }
97
98
 
99
+ // Record the request before importing code, including attempts whose load fails.
100
+ async function recordLifecycleRequest(
101
+ record: Extension,
102
+ operation: string,
103
+ agentId: string | undefined,
104
+ version = record.activeVersion,
105
+ ): Promise<void> {
106
+ if (!agentId) return;
107
+ await insertExtensionRun({
108
+ extensionId: record.id,
109
+ version,
110
+ event: `lifecycle.${operation}.requested`,
111
+ action: "continue",
112
+ agentId,
113
+ subject: record.name,
114
+ });
115
+ }
116
+
98
117
  export async function enableExtension(
99
118
  id: string,
100
- opts: { by?: string | null } = {},
119
+ opts: { by?: string | null; agentId?: string } = {},
101
120
  ): Promise<Extension> {
102
121
  initExtensionPostBridge();
103
122
  let record = await getExtensionById(id);
104
123
  if (!record) throw new ExtensionLifecycleError("Extension not found", 404);
105
124
 
125
+ await recordLifecycleRequest(record, "enable", opts.agentId);
106
126
  const agentId = await ensureExtensionAgent(record.name);
107
127
  const identified = await setExtensionState(id, { agentId, updatedBy: opts.by });
108
128
  if (!identified) throw new ExtensionLifecycleError("Extension not found", 404);
@@ -133,10 +153,11 @@ export async function enableExtension(
133
153
 
134
154
  export async function disableExtension(
135
155
  id: string,
136
- opts: { by?: string | null } = {},
156
+ opts: { by?: string | null; agentId?: string } = {},
137
157
  ): Promise<Extension> {
138
158
  const record = await getExtensionById(id);
139
159
  if (!record) throw new ExtensionLifecycleError("Extension not found", 404);
160
+ await recordLifecycleRequest(record, "disable", opts.agentId);
140
161
  await removeRegistered(id);
141
162
  attemptedFingerprints.delete(id);
142
163
  await deactivateExtensionAgent(record.name);
@@ -152,7 +173,7 @@ export async function disableExtension(
152
173
  export async function activateVersion(
153
174
  id: string,
154
175
  version: number,
155
- opts: { by?: string | null } = {},
176
+ opts: { by?: string | null; agentId?: string } = {},
156
177
  ): Promise<Extension> {
157
178
  const current = await getExtensionById(id);
158
179
  if (!current) throw new ExtensionLifecycleError("Extension not found", 404);
@@ -160,6 +181,7 @@ export async function activateVersion(
160
181
  throw new ExtensionLifecycleError(`Extension version ${version} was not found`, 404);
161
182
  }
162
183
 
184
+ await recordLifecycleRequest(current, "activate-version", opts.agentId, version);
163
185
  const wasEnabled = current.enabled;
164
186
  if (wasEnabled) await disableExtension(id, opts);
165
187
  const activated = await activateExtensionVersionSnapshot(id, version, opts.by);
@@ -170,7 +192,7 @@ export async function activateVersion(
170
192
 
171
193
  export async function reloadExtension(
172
194
  id: string,
173
- opts: { by?: string | null } = {},
195
+ opts: { by?: string | null; agentId?: string } = {},
174
196
  ): Promise<Extension> {
175
197
  const record = await getExtensionById(id);
176
198
  if (!record) throw new ExtensionLifecycleError("Extension not found", 404);
@@ -197,7 +197,8 @@ const enableRoute = route({
197
197
  pattern: ["api", "extensions", null, "enable"],
198
198
  operationId: "extensions_enable",
199
199
  summary: "Enable an extension",
200
- description: "Loads and enables an extension. This route is operator-only.",
200
+ description:
201
+ "Loads and enables an extension. Available to leads, operators, and dashboard users.",
201
202
  tags: ["Extensions"],
202
203
  params: idParamsSchema,
203
204
  responses: {
@@ -215,7 +216,8 @@ const disableRoute = route({
215
216
  pattern: ["api", "extensions", null, "disable"],
216
217
  operationId: "extensions_disable",
217
218
  summary: "Disable an extension",
218
- description: "Unloads and disables an extension. This route is operator-only.",
219
+ description:
220
+ "Unloads and disables an extension. Available to leads, operators, and dashboard users.",
219
221
  tags: ["Extensions"],
220
222
  params: idParamsSchema,
221
223
  responses: {
@@ -232,7 +234,7 @@ const activateVersionRoute = route({
232
234
  pattern: ["api", "extensions", null, "activate-version"],
233
235
  operationId: "extensions_activate_version",
234
236
  summary: "Activate an extension version",
235
- description: "Activates a stored version. This route is operator-only.",
237
+ description: "Activates a stored version. Available to leads, operators, and dashboard users.",
236
238
  tags: ["Extensions"],
237
239
  params: idParamsSchema,
238
240
  body: z.object({ version: z.number().int().min(1) }).strict(),
@@ -501,6 +503,7 @@ export async function handleExtensions(
501
503
  try {
502
504
  const extension = await enableExtension(parsed.params.id, {
503
505
  by: await resolveHttpAuditUserId(req, writerAgentId),
506
+ agentId: writerAgentId,
504
507
  });
505
508
  enableRoute.respond(res, 200, { extension: redactExtension(extension) });
506
509
  } catch (error) {
@@ -518,6 +521,7 @@ export async function handleExtensions(
518
521
  try {
519
522
  const extension = await disableExtension(parsed.params.id, {
520
523
  by: await resolveHttpAuditUserId(req, writerAgentId),
524
+ agentId: writerAgentId,
521
525
  });
522
526
  disableRoute.respond(res, 200, { extension: redactExtension(extension) });
523
527
  } catch (error) {
@@ -535,6 +539,7 @@ export async function handleExtensions(
535
539
  try {
536
540
  const extension = await activateVersion(parsed.params.id, parsed.body.version, {
537
541
  by: await resolveHttpAuditUserId(req, writerAgentId),
542
+ agentId: writerAgentId,
538
543
  });
539
544
  activateVersionRoute.respond(res, 200, { extension: redactExtension(extension) });
540
545
  } catch (error) {
@@ -11,6 +11,7 @@
11
11
  * `PermissionVerb` (enforced via `satisfies`).
12
12
  */
13
13
 
14
+ import { isEnvFlagEnabled } from "../utils/env-flag";
14
15
  import { hasLeadEquivalence } from "./elevated-agents";
15
16
  import type { PermissionVerb } from "./permissions";
16
17
  import type { RbacPrincipal, RbacResource } from "./types";
@@ -55,6 +56,17 @@ const leadOrOperatorOrUser: LegacyRule = {
55
56
  principal.kind === "operator" || principal.kind === "user" || actsAsLead(principal),
56
57
  };
57
58
 
59
+ // Deployment-only: agents cannot reset this through swarm_config.
60
+ const extensionActivation: LegacyRule = {
61
+ name: "extension-activation",
62
+ denyReason:
63
+ "requires operator/user authentication, or a lead with EXTENSION_ALLOW_LEAD_ACTIVATION enabled",
64
+ evaluate: (principal) =>
65
+ principal.kind === "operator" ||
66
+ principal.kind === "user" ||
67
+ (actsAsLead(principal) && isEnvFlagEnabled("EXTENSION_ALLOW_LEAD_ACTIVATION", true)),
68
+ };
69
+
58
70
  const leadOrTaskCreator: LegacyRule = {
59
71
  name: "lead-or-task-creator",
60
72
  denyReason: "requires lead agent or task creator",
@@ -231,5 +243,5 @@ export const LEGACY_POLICY = {
231
243
  "script.api.rotate": leadOnly,
232
244
  "script.api.delete": leadOnly,
233
245
  "extension.write": leadOrOperatorOrUser,
234
- "extension.activate": operatorOrUser,
246
+ "extension.activate": extensionActivation,
235
247
  } as const satisfies Record<PermissionVerb, LegacyRule>;
@@ -57,6 +57,10 @@ export const SDK_TOOL_NAME_MAP = {
57
57
  script_listRuns: "list-script-runs",
58
58
 
59
59
  // ── extensions ──
60
+ extension_delete: "extension-delete",
61
+ extension_enable: "extension-enable",
62
+ extension_disable: "extension-disable",
63
+ extension_activate_version: "extension-activate-version",
60
64
  extension_install: "extension-install",
61
65
  extension_list: "extension-list",
62
66
 
@@ -525,6 +525,10 @@ declare module "swarm-sdk" {
525
525
  config?: Record<string, unknown>;
526
526
  }): Promise<unknown>;
527
527
  extension_list(args?: { enabledOnly?: boolean }): Promise<unknown>;
528
+ extension_delete(args: { id: string }): Promise<unknown>;
529
+ extension_enable(args: { id: string }): Promise<unknown>;
530
+ extension_disable(args: { id: string }): Promise<unknown>;
531
+ extension_activate_version(args: { id: string; version: number }): Promise<unknown>;
528
532
 
529
533
  // --- write: repos ---
530
534
  repo_update(args: Record<string, unknown>): Promise<unknown>;
@@ -507,6 +507,10 @@ declare module "swarm-sdk" {
507
507
  config?: Record<string, unknown>;
508
508
  }): Promise<unknown>;
509
509
  extension_list(args?: { enabledOnly?: boolean }): Promise<unknown>;
510
+ extension_delete(args: { id: string }): Promise<unknown>;
511
+ extension_enable(args: { id: string }): Promise<unknown>;
512
+ extension_disable(args: { id: string }): Promise<unknown>;
513
+ extension_activate_version(args: { id: string; version: number }): Promise<unknown>;
510
514
 
511
515
  // --- write: repos ---
512
516
  repo_update(args: Record<string, unknown>): Promise<unknown>;
package/src/server.ts CHANGED
@@ -30,6 +30,10 @@ import { registerDbQueryTool } from "./tools/db-query";
30
30
  import { registerDeferTaskTool } from "./tools/defer-task";
31
31
  import { registerDeleteChannelTool } from "./tools/delete-channel";
32
32
  import { registerDeletePageTool } from "./tools/delete-page";
33
+ import { registerExtensionActivateVersionTool } from "./tools/extension-activate-version";
34
+ import { registerExtensionDeleteTool } from "./tools/extension-delete";
35
+ import { registerExtensionDisableTool } from "./tools/extension-disable";
36
+ import { registerExtensionEnableTool } from "./tools/extension-enable";
33
37
  import { registerExtensionInstallTool } from "./tools/extension-install";
34
38
  import { registerExtensionListTool } from "./tools/extension-list";
35
39
  import { registerGetMetricsTool } from "./tools/get-metrics";
@@ -340,6 +344,10 @@ export async function createServer(
340
344
  registerScriptSearchTool(server);
341
345
  registerScriptRunTool(server);
342
346
  registerScriptUpsertTool(server);
347
+ registerExtensionDeleteTool(server);
348
+ registerExtensionEnableTool(server);
349
+ registerExtensionDisableTool(server);
350
+ registerExtensionActivateVersionTool(server);
343
351
  registerExtensionInstallTool(server);
344
352
  registerExtensionListTool(server);
345
353
  registerScriptDeleteTool(server);
@@ -402,6 +410,10 @@ export async function createServer(
402
410
  registerScriptApisTool(server);
403
411
  registerScriptRunTool(server);
404
412
  registerScriptUpsertTool(server);
413
+ registerExtensionDeleteTool(server);
414
+ registerExtensionEnableTool(server);
415
+ registerExtensionDisableTool(server);
416
+ registerExtensionActivateVersionTool(server);
405
417
  registerExtensionInstallTool(server);
406
418
  registerExtensionListTool(server);
407
419
  registerScriptDeleteTool(server);