@desplega.ai/agent-swarm 1.149.1 → 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 (538) hide show
  1. package/README.md +18 -3
  2. package/dist/{acp-adapter-vhkzfpjg.js → acp-adapter-ex8hzjfc.js} +5 -5
  3. package/dist/{actions-9d2694yk.js → actions-2bgpyhww.js} +39 -11
  4. package/dist/{app-fq2ggynt.js → app-1706zhr1.js} +7 -7
  5. package/dist/{artifact-gj9arwrr.js → artifact-td4q4dch.js} +1 -1
  6. package/dist/{assistant-edb6n9nn.js → assistant-bavke5p7.js} +44 -20
  7. package/dist/{azure-openai-responses-cqar64rc.js → azure-openai-responses-f38x2avq.js} +13 -13
  8. package/dist/{boot-reembed-msweabbp.js → boot-reembed-3cmrrmpa.js} +9 -9
  9. package/dist/{boot-reembed-q5wd3tha.js → boot-reembed-nafcmmmc.js} +14 -16
  10. package/dist/{boot-scrub-logs-3g1az933.js → boot-scrub-logs-cd6a2sq0.js} +5 -5
  11. package/dist/{claude-adapter-v3rnzsdc.js → claude-adapter-wfp2gzvz.js} +15 -16
  12. package/dist/{claude-managed-adapter-qvsmh6mv.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
  13. package/dist/{claude-sdk-session-qxrpsna1.js → claude-sdk-session-bht9jjak.js} +15 -16
  14. package/dist/{cli-5m0qmvdp.js → cli-0qb1z6s2.js} +1 -1
  15. package/dist/{cli-9d8ntetj.js → cli-2658f6at.js} +1 -1
  16. package/dist/{cli-7evafqvy.js → cli-2tbvf1z1.js} +85 -69
  17. package/dist/{cli-k351hv5k.js → cli-3v9xhjcn.js} +24 -12
  18. package/dist/{cli-1ebpar1q.js → cli-4wppfkcm.js} +350 -20
  19. package/dist/{cli-4260r1tg.js → cli-5jd2z7av.js} +97 -84
  20. package/dist/{cli-cv7s5zdq.js → cli-5tpgq60f.js} +9865 -715
  21. package/dist/{cli-6skz3rk8.js → cli-7tgcstn2.js} +9 -4
  22. package/dist/{cli-01g3x1ca.js → cli-9004vfdf.js} +108 -56
  23. package/dist/{cli-1c94wvcw.js → cli-a1z3h107.js} +124 -99
  24. package/dist/{cli-9br8ypfv.js → cli-czjtgfys.js} +2 -2
  25. package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
  26. package/dist/{cli-e29gmdmw.js → cli-dv6cdjs2.js} +2 -1
  27. package/dist/{cli-wby1xnnb.js → cli-f1wky6zp.js} +1 -1
  28. package/dist/{cli-zvz62chv.js → cli-fm4ytsdk.js} +4 -4
  29. package/dist/{cli-tg8qj8ee.js → cli-frcta2w4.js} +6 -6
  30. package/dist/{cli-7xx10h0a.js → cli-g69fdc9g.js} +2 -2
  31. package/dist/{cli-cmp8g3sw.js → cli-gbfwcd3k.js} +44 -9
  32. package/dist/{handlers-nsg0bcye.js → cli-gjyvhmmh.js} +97 -45
  33. package/dist/{cli-08b07b4r.js → cli-ht5rs63n.js} +1 -1
  34. package/dist/{cli-jecc01cb.js → cli-j4nv2wqy.js} +2 -4
  35. package/dist/{cli-cd60fv6j.js → cli-j9xczhaq.js} +1 -1
  36. package/dist/cli-pf9q3696.js +172 -0
  37. package/dist/{cli-xm87hzbw.js → cli-pgj4a5fb.js} +1 -1
  38. package/dist/{cli-jezx9b9c.js → cli-ppm4975n.js} +9 -3
  39. package/dist/{cli-3z634pqe.js → cli-q88st9aj.js} +2 -2
  40. package/dist/{cli-3sysyjve.js → cli-r2q6pevn.js} +142 -49
  41. package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
  42. package/dist/{cli-qgd4sqz5.js → cli-s14agm5s.js} +121 -14
  43. package/dist/{cli-svbrpf5q.js → cli-sjaae6ff.js} +9872 -424
  44. package/dist/{cli-73gq0zxn.js → cli-vwm416m6.js} +13 -13
  45. package/dist/{cli-4wtq5jjv.js → cli-wbyk465z.js} +1 -1
  46. package/dist/{cli-3apbzgyk.js → cli-z61ykvam.js} +19 -14
  47. package/dist/{cli-e06a8a7y.js → cli-zkxymas5.js} +4 -3
  48. package/dist/cli.js +26 -25
  49. package/dist/{codex-adapter-jyw7a91z.js → codex-adapter-jjjk8w4m.js} +8 -9
  50. package/dist/{codex-hook-hfrt9shr.js → codex-hook-8jexc34x.js} +3 -3
  51. package/dist/{codex-session-runner-bmngj0s5.js → codex-session-runner-nd6ayxkx.js} +8 -9
  52. package/dist/{commands-n755g391.js → commands-9v4psyq1.js} +5 -5
  53. package/dist/{db-s1cgh5gv.js → db-wnt58tpe.js} +5 -5
  54. package/dist/dispatcher-05jh1aqk.js +74 -0
  55. package/dist/{e2b-p04vmtx0.js → e2b-413b8t4v.js} +1 -1
  56. package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
  57. package/dist/{google-vertex-ppw8ydpa.js → google-vertex-fr665tqs.js} +10 -10
  58. package/dist/handlers-tw90pkh5.js +65 -0
  59. package/dist/{hook-jf0xe8zh.js → hook-123e2scb.js} +11 -12
  60. package/dist/{hook-h9cqrm8q.js → hook-sxe3r349.js} +11 -12
  61. package/dist/{http-nc6pydw5.js → http-ecsar8ez.js} +1442 -581
  62. package/dist/{index-ezxkds2n.js → index-16js521z.js} +335 -107
  63. package/dist/{index-769nc012.js → index-hw26vj40.js} +25 -19
  64. package/dist/{index-0wdy6gwc.js → index-nnrbpcjp.js} +25 -17
  65. package/dist/index-ymn7em0p.js +25 -0
  66. package/dist/{index-x1zcj09z.js → index-zj518gf9.js} +26 -20
  67. package/dist/{keepalive-nesm3xb6.js → keepalive-asqtcm4y.js} +7 -7
  68. package/dist/{lead-bwy6t2za.js → lead-xbfr7fvt.js} +40 -48
  69. package/dist/{maintenance-8w393zf0.js → maintenance-qma55qvw.js} +9 -9
  70. package/dist/{oauth-refresh-sweep-sh8xjy08.js → oauth-refresh-sweep-3s04c6qw.js} +6 -6
  71. package/dist/{onboard-25ps29h1.js → onboard-drskd386.js} +13 -4
  72. package/dist/{openai-codex-responses-g7w48y30.js → openai-codex-responses-wy6a43wd.js} +13 -13
  73. package/dist/{openai-responses-nmeyptke.js → openai-responses-6xwf7bzg.js} +19 -19
  74. package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
  75. package/dist/{otel-impl-b93gxnz5.js → otel-impl-943c96er.js} +1 -1
  76. package/dist/{pi-mono-adapter-zvshk5cj.js → pi-mono-adapter-jcqt71cg.js} +17 -19
  77. package/dist/{pricing-refresh-5v56x7gb.js → pricing-refresh-mx51az05.js} +7 -7
  78. package/dist/{rbac-roles-x55cnezn.js → rbac-roles-78baecqd.js} +13 -9
  79. package/dist/{rbac-roles-0p0s6pbj.js → rbac-roles-wcmrg6sv.js} +7 -7
  80. package/dist/{render-v2-hyd45w8b.js → render-v2-8zjntgf5.js} +7 -7
  81. package/dist/{seed-pricing-49gbgn96.js → seed-pricing-jqjs6cws.js} +6 -6
  82. package/dist/{setup-qvq64vzq.js → setup-4pks0vfk.js} +2 -2
  83. package/dist/work-objects-wangt792.js +165 -0
  84. package/dist/{worker-scj60cxg.js → worker-p2mr422x.js} +40 -48
  85. package/openapi.json +1365 -268
  86. package/package.json +4 -3
  87. package/src/agentmail/handlers.ts +95 -66
  88. package/src/be/budget-refusal-notify.ts +1 -0
  89. package/src/be/db/tasks/read.ts +3 -0
  90. package/src/be/db/tasks/write.ts +13 -1
  91. package/src/be/db-client.ts +5 -0
  92. package/src/be/db.ts +15 -5
  93. package/src/be/extensions/db.ts +461 -0
  94. package/src/be/extensions/validate.ts +107 -0
  95. package/src/be/memory/boot-reembed.ts +17 -12
  96. package/src/be/memory/index.ts +12 -0
  97. package/src/be/memory/providers/openai-embedding.ts +4 -0
  98. package/src/be/memory/types.ts +2 -0
  99. package/src/be/migrations/153_deferred_task_wait_members.sql +25 -0
  100. package/src/be/migrations/154_routing_source.sql +3 -0
  101. package/src/be/migrations/155_extensions.sql +66 -0
  102. package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
  103. package/src/be/rbac-roles.ts +3 -2
  104. package/src/be/scripts/typecheck.ts +59 -41
  105. package/src/be/seed/schedules-seeder.ts +25 -2
  106. package/src/be/seed/workflows-seeder.ts +17 -0
  107. package/src/be/seed-scripts/catalog/delegate.ts +3 -1
  108. package/src/be/seed-skills/bundled-files.generated.json +1 -1
  109. package/src/be/seed-skills/index.ts +7 -0
  110. package/src/be/steering.ts +1 -0
  111. package/src/be/swarm-config-guard.ts +3 -1
  112. package/src/commands/credential-refresh.ts +70 -0
  113. package/src/commands/onboard/compose-generator.ts +14 -2
  114. package/src/commands/onboard/env-generator.ts +7 -0
  115. package/src/commands/provider-credentials.ts +2 -25
  116. package/src/commands/runner.ts +24 -57
  117. package/src/extensions/apply-task-create.ts +135 -0
  118. package/src/extensions/bundle-path.ts +10 -0
  119. package/src/extensions/contract-runtime.ts +7 -0
  120. package/src/extensions/contract-types.generated.ts +4 -0
  121. package/src/extensions/contract.ts +270 -0
  122. package/src/extensions/ctx.ts +186 -0
  123. package/src/extensions/dispatcher.ts +479 -0
  124. package/src/extensions/identity.ts +44 -0
  125. package/src/extensions/lifecycle.ts +281 -0
  126. package/src/extensions/loader.ts +207 -0
  127. package/src/extensions/post-bridge.ts +161 -0
  128. package/src/github/handlers.ts +185 -140
  129. package/src/gitlab/handlers.ts +97 -77
  130. package/src/heartbeat/heartbeat.ts +155 -83
  131. package/src/http/agents.ts +1 -1
  132. package/src/http/all-routes.ts +1 -0
  133. package/src/http/approval-requests.ts +1 -0
  134. package/src/http/apps.ts +14 -9
  135. package/src/http/config.ts +4 -1
  136. package/src/http/core.ts +38 -2
  137. package/src/http/extensions.ts +547 -0
  138. package/src/http/inbox-state.ts +2 -0
  139. package/src/http/index.ts +41 -3
  140. package/src/http/mcp-bridge.ts +96 -62
  141. package/src/http/mcp.ts +1 -1
  142. package/src/http/script-runs.ts +5 -0
  143. package/src/http/status.ts +6 -4
  144. package/src/http/tasks.ts +51 -30
  145. package/src/integrations/kapso/inbound.ts +15 -10
  146. package/src/jira/sync.ts +26 -16
  147. package/src/linear/sync.ts +26 -16
  148. package/src/prompts/session-templates.ts +18 -13
  149. package/src/providers/claude-adapter.ts +21 -8
  150. package/src/rbac/admission.ts +1 -1
  151. package/src/rbac/elevated-agents.ts +24 -0
  152. package/src/rbac/legacy-policy.ts +35 -6
  153. package/src/rbac/permissions.ts +8 -0
  154. package/src/scheduler/deferred-task-waits.ts +138 -27
  155. package/src/scheduler/schedule-task.ts +54 -24
  156. package/src/scheduler/scheduler.ts +108 -125
  157. package/src/scripts-runtime/executors/native.ts +5 -1
  158. package/src/scripts-runtime/executors/types.ts +5 -0
  159. package/src/scripts-runtime/import-allowlist.ts +79 -19
  160. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  161. package/src/scripts-runtime/swarm-config.ts +8 -0
  162. package/src/scripts-runtime/swarm-sdk.ts +3 -0
  163. package/src/scripts-runtime/types/stdlib.d.ts +16 -3
  164. package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
  165. package/src/scripts-runtime/types/swarm-sdk.d.ts +16 -3
  166. package/src/server.ts +6 -0
  167. package/src/slack/HEURISTICS.md +3 -1
  168. package/src/slack/actions.ts +21 -16
  169. package/src/slack/app.ts +2 -0
  170. package/src/slack/assistant.ts +4 -12
  171. package/src/slack/blocks.ts +1 -1
  172. package/src/slack/handlers.ts +107 -19
  173. package/src/slack/inbound-files.ts +9 -5
  174. package/src/slack/render-v2.ts +188 -38
  175. package/src/slack/router.ts +13 -3
  176. package/src/slack/steering.ts +3 -3
  177. package/src/slack/thread-buffer.ts +66 -23
  178. package/src/slack/work-objects.test.ts +252 -0
  179. package/src/slack/work-objects.ts +118 -0
  180. package/src/tasks/errors.ts +9 -0
  181. package/src/tasks/sibling-awareness.ts +35 -1
  182. package/src/tasks/worker-follow-up.ts +67 -11
  183. package/src/tests/acp-adapter.test.ts +10 -10
  184. package/src/tests/agent-fs-live-url.test.ts +40 -0
  185. package/src/tests/agent-fs-provision-seeder.test.ts +12 -12
  186. package/src/tests/api-key-tracking.test.ts +18 -18
  187. package/src/tests/api-key.test.ts +4 -2
  188. package/src/tests/apps-rbac.test.ts +1 -1
  189. package/src/tests/apps-spike5.test.ts +1 -1
  190. package/src/tests/apps-sync-engine.test.ts +8 -8
  191. package/src/tests/apps-user-config.test.ts +1 -1
  192. package/src/tests/artifact-sdk.test.ts +8 -8
  193. package/src/tests/asset-key-mcp.test.ts +2 -0
  194. package/src/tests/automation-preflight-alert.test.ts +1 -1
  195. package/src/tests/base-prompt.test.ts +7 -6
  196. package/src/tests/budget-user-scope.test.ts +1 -1
  197. package/src/tests/budgets-routes.test.ts +1 -1
  198. package/src/tests/claude-adapter-binary.test.ts +22 -40
  199. package/src/tests/claude-adapter-otel.test.ts +13 -7
  200. package/src/tests/claude-adapter.test.ts +8 -6
  201. package/src/tests/claude-hook-credentials.test.ts +3 -3
  202. package/src/tests/claude-managed-adapter.test.ts +4 -4
  203. package/src/tests/claude-managed-setup.test.ts +3 -3
  204. package/src/tests/claude-sdk-lifecycle.test.ts +1 -1
  205. package/src/tests/claude-sdk-transport.test.ts +6 -6
  206. package/src/tests/claude-stop-hook.test.ts +8 -8
  207. package/src/tests/claude-worker-parity.test.ts +3 -3
  208. package/src/tests/codex-adapter-pool-auth-revalidate.test.ts +5 -5
  209. package/src/tests/codex-adapter.test.ts +7 -5
  210. package/src/tests/codex-app-server.test.ts +2 -2
  211. package/src/tests/codex-login.test.ts +15 -15
  212. package/src/tests/codex-oauth-credential-info.test.ts +4 -4
  213. package/src/tests/codex-oauth-keep-warm.test.ts +4 -4
  214. package/src/tests/codex-oauth-refresh-lock.test.ts +1 -1
  215. package/src/tests/codex-oauth-storage.test.ts +7 -7
  216. package/src/tests/codex-pool.test.ts +1 -1
  217. package/src/tests/codex-steering-hook.test.ts +1 -1
  218. package/src/tests/codex-swarm-events.test.ts +1 -1
  219. package/src/tests/config-api-only-keys.test.ts +1 -1
  220. package/src/tests/config-session-auth.test.ts +2 -2
  221. package/src/tests/connection-embedded-auth.test.ts +20 -18
  222. package/src/tests/core-auth.test.ts +1 -1
  223. package/src/tests/create-page-tool.test.ts +3 -3
  224. package/src/tests/credential-refresh.test.ts +115 -0
  225. package/src/tests/credential-wait.test.ts +2 -2
  226. package/src/tests/credentials.test.ts +6 -4
  227. package/src/tests/db-queries-oauth.test.ts +40 -40
  228. package/src/tests/defer-task.test.ts +73 -8
  229. package/src/tests/deferred-task-wait-migration.test.ts +64 -0
  230. package/src/tests/deferred-task-wake.test.ts +349 -8
  231. package/src/tests/devin-adapter.test.ts +1 -1
  232. package/src/tests/devin-api.test.ts +1 -1
  233. package/src/tests/docs-index-footprint.test.js +3 -3
  234. package/src/tests/e2b-dispatch.test.ts +21 -19
  235. package/src/tests/e2e-claude-transport.test.ts +3 -3
  236. package/src/tests/e2e-redact.test.ts +6 -6
  237. package/src/tests/ensure-token.test.ts +68 -68
  238. package/src/tests/entrypoint-api-readiness.test.ts +1 -1
  239. package/src/tests/entrypoint-codex-oauth-seed.test.ts +13 -13
  240. package/src/tests/env-flag.test.ts +1 -0
  241. package/src/tests/events-http.test.ts +1 -1
  242. package/src/tests/extensions-db.test.ts +216 -0
  243. package/src/tests/extensions-dispatcher.test.ts +275 -0
  244. package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
  245. package/src/tests/extensions-example-mcp-install.test.ts +63 -0
  246. package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
  247. package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
  248. package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
  249. package/src/tests/extensions-heartbeat.test.ts +291 -0
  250. package/src/tests/extensions-http.test.ts +431 -0
  251. package/src/tests/extensions-lead-equivalence.test.ts +49 -0
  252. package/src/tests/extensions-lifecycle.test.ts +209 -0
  253. package/src/tests/extensions-loader.test.ts +95 -0
  254. package/src/tests/extensions-mcp-tools.test.ts +245 -0
  255. package/src/tests/extensions-pre-task.test.ts +487 -0
  256. package/src/tests/extensions-run-context.test.ts +41 -0
  257. package/src/tests/extensions-tool-call.test.ts +288 -0
  258. package/src/tests/extensions-validate.test.ts +196 -0
  259. package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
  260. package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
  261. package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
  262. package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
  263. package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
  264. package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
  265. package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
  266. package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
  267. package/src/tests/fixtures/extensions/load.ts +10 -0
  268. package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
  269. package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
  270. package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
  271. package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
  272. package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
  273. package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
  274. package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
  275. package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
  276. package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
  277. package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
  278. package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
  279. package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
  280. package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
  281. package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
  282. package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
  283. package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
  284. package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
  285. package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
  286. package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
  287. package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
  288. package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
  289. package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
  290. package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
  291. package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
  292. package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
  293. package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
  294. package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
  295. package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
  296. package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
  297. package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
  298. package/src/tests/fs-routes.test.ts +1 -1
  299. package/src/tests/gitlab-auth.test.ts +10 -10
  300. package/src/tests/harness-provider-resolution.test.ts +8 -5
  301. package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
  302. package/src/tests/helper-credentials.test.ts +137 -0
  303. package/src/tests/http/context-routes.test.ts +2 -2
  304. package/src/tests/http-api-integration.test.ts +5 -2
  305. package/src/tests/http-users.test.ts +1 -1
  306. package/src/tests/identity-refresh.test.ts +2 -2
  307. package/src/tests/internal-ai/complete-structured.test.ts +2 -2
  308. package/src/tests/internal-ai/credentials.test.ts +19 -17
  309. package/src/tests/jira-metadata.test.ts +1 -1
  310. package/src/tests/jira-oauth.test.ts +5 -5
  311. package/src/tests/jira-sync.test.ts +1 -1
  312. package/src/tests/jira-webhook-lifecycle.test.ts +3 -3
  313. package/src/tests/jira-webhook.test.ts +2 -2
  314. package/src/tests/kapso-inbound.test.ts +2 -2
  315. package/src/tests/kv-http.test.ts +1 -1
  316. package/src/tests/kv-namespace-resolution.test.ts +1 -1
  317. package/src/tests/kv-page-proxy.test.ts +2 -2
  318. package/src/tests/launch-password-rejection.test.ts +2 -2
  319. package/src/tests/linear-webhook.test.ts +1 -1
  320. package/src/tests/mcp-oauth-dcr-reuse.test.ts +6 -6
  321. package/src/tests/mcp-oauth-ensure-token.test.ts +28 -22
  322. package/src/tests/mcp-oauth-manual-client.test.ts +16 -12
  323. package/src/tests/mcp-oauth-queries.test.ts +35 -32
  324. package/src/tests/mcp-oauth-resolve-secrets.test.ts +8 -8
  325. package/src/tests/mcp-oauth-wrapper.test.ts +20 -20
  326. package/src/tests/mcp-user-route.test.ts +1 -1
  327. package/src/tests/memory-edges.test.ts +1 -1
  328. package/src/tests/memory-edit-authorization.test.ts +32 -0
  329. package/src/tests/memory-rate-endpoint.test.ts +1 -1
  330. package/src/tests/memory-rate-tool.test.ts +2 -2
  331. package/src/tests/memory-rater-e2e.test.ts +1 -1
  332. package/src/tests/memory-rater-llm-summarizer.test.ts +3 -3
  333. package/src/tests/memory-rater-llm.test.ts +1 -1
  334. package/src/tests/model-control.test.ts +3 -0
  335. package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
  336. package/src/tests/multi-runtime-registration.test.ts +111 -17
  337. package/src/tests/oauth-access-token-tool.test.ts +18 -18
  338. package/src/tests/oauth-callback-flow.test.ts +8 -8
  339. package/src/tests/oauth-credential-bindings.test.ts +29 -27
  340. package/src/tests/oauth-keepalive.test.ts +10 -10
  341. package/src/tests/oauth-presets.test.ts +13 -5
  342. package/src/tests/oauth-refresh-failure.test.ts +9 -9
  343. package/src/tests/oauth-refresh-sweep.test.ts +20 -13
  344. package/src/tests/oauth-wrapper.test.ts +1 -1
  345. package/src/tests/onboard-compose.test.ts +47 -3
  346. package/src/tests/onboard-env.test.ts +26 -26
  347. package/src/tests/onboard-non-interactive.test.ts +4 -4
  348. package/src/tests/opencode-adapter.test.ts +1 -1
  349. package/src/tests/opencode-plugin.test.ts +2 -2
  350. package/src/tests/otel-session-cost-metrics.test.ts +1 -1
  351. package/src/tests/page-proxy-authed.test.ts +2 -2
  352. package/src/tests/page-proxy.test.ts +2 -2
  353. package/src/tests/page-session.test.ts +7 -7
  354. package/src/tests/page-viewer-auth.test.ts +2 -2
  355. package/src/tests/pages-authed-mode.test.ts +1 -1
  356. package/src/tests/pages-http.test.ts +1 -1
  357. package/src/tests/pages-password-mode.test.ts +1 -1
  358. package/src/tests/pages-public-authed-401.test.ts +1 -1
  359. package/src/tests/pages-public-html.test.ts +2 -2
  360. package/src/tests/pages-view-count.test.ts +1 -1
  361. package/src/tests/pi-mono-adapter.test.ts +10 -10
  362. package/src/tests/pi-mono-extension.test.ts +2 -2
  363. package/src/tests/preload.ts +5 -0
  364. package/src/tests/pricing-routes.test.ts +1 -1
  365. package/src/tests/profile-sync-warning.test.ts +8 -8
  366. package/src/tests/profile-sync.test.ts +8 -8
  367. package/src/tests/prompt-template-session.test.ts +36 -5
  368. package/src/tests/provider-process-group.test.ts +95 -4
  369. package/src/tests/providers/pi-cost.test.ts +1 -1
  370. package/src/tests/queue-stall-alarm.test.ts +1 -1
  371. package/src/tests/rbac-admission.test.ts +19 -4
  372. package/src/tests/rbac-charact-http.test.ts +1 -1
  373. package/src/tests/rbac-e2e-helpers.ts +1 -1
  374. package/src/tests/rbac-engine.test.ts +39 -0
  375. package/src/tests/realtime-room-auth.test.ts +1 -1
  376. package/src/tests/realtime-room-surfaces.test.ts +1 -1
  377. package/src/tests/reload-config.test.ts +45 -1
  378. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  379. package/src/tests/routing-reason-contract.test.ts +76 -3
  380. package/src/tests/routing-reason-inventory.test.ts +11 -6
  381. package/src/tests/routing-source.test.ts +53 -0
  382. package/src/tests/runner-agent-fs-provision-retry.test.ts +1 -1
  383. package/src/tests/runner-context-preamble.test.ts +1 -1
  384. package/src/tests/runner-deployment-resume.test.ts +1 -1
  385. package/src/tests/runner-fallback-output.test.ts +1 -1
  386. package/src/tests/runner-identity-refresh.test.ts +1 -1
  387. package/src/tests/runner-skills-refresh.test.ts +1 -1
  388. package/src/tests/schedule-target-type.test.ts +3 -3
  389. package/src/tests/scheduled-tasks.test.ts +14 -5
  390. package/src/tests/scheduler-occurrence.test.ts +347 -0
  391. package/src/tests/script-apis-mcp.test.ts +1 -1
  392. package/src/tests/script-connections-http.test.ts +61 -58
  393. package/src/tests/script-connections-mcp.test.ts +1 -1
  394. package/src/tests/script-connections.test.ts +3 -1
  395. package/src/tests/script-runs-http.test.ts +15 -7
  396. package/src/tests/script-workflows-runtime-e2e.test.ts +1 -1
  397. package/src/tests/scripts-boot-reembed.test.ts +4 -0
  398. package/src/tests/scripts-embeddings.test.ts +4 -0
  399. package/src/tests/scripts-external-api.test.ts +1 -1
  400. package/src/tests/scripts-http.test.ts +1 -1
  401. package/src/tests/scripts-import-allowlist.test.ts +44 -1
  402. package/src/tests/scripts-mcp-e2e.test.ts +81 -1
  403. package/src/tests/scripts-only-gating.test.ts +4 -2
  404. package/src/tests/scripts-retention.test.ts +1 -1
  405. package/src/tests/scripts-runtime-identity.test.ts +2 -2
  406. package/src/tests/scripts-runtime-secret-egress.test.ts +1 -1
  407. package/src/tests/scripts-runtime.test.ts +6 -4
  408. package/src/tests/scripts-typecheck.test.ts +21 -0
  409. package/src/tests/sdk-allowlist.test.ts +1 -1
  410. package/src/tests/secret-scrubber.test.ts +38 -31
  411. package/src/tests/seed-registry.test.ts +46 -8
  412. package/src/tests/seed-schedules.test.ts +44 -9
  413. package/src/tests/seed-workflows.test.ts +21 -9
  414. package/src/tests/send-task-output-schema.test.ts +9 -1
  415. package/src/tests/send-task-requested-by.test.ts +1 -0
  416. package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
  417. package/src/tests/session-costs-codex-recompute.test.ts +1 -1
  418. package/src/tests/session-costs-golden.test.ts +2 -2
  419. package/src/tests/session-costs-model-key-normalize.test.ts +2 -2
  420. package/src/tests/session-costs-recompute-all-providers.test.ts +1 -1
  421. package/src/tests/session-tokens.test.ts +1 -1
  422. package/src/tests/shutdown-error-scrubbing.test.ts +1 -1
  423. package/src/tests/slack-blocks.test.ts +12 -1
  424. package/src/tests/slack-file-tools-attachments.test.ts +1 -1
  425. package/src/tests/slack-inbound-files.test.ts +222 -86
  426. package/src/tests/slack-reaction-config.test.ts +5 -4
  427. package/src/tests/slack-read-boundaries.test.ts +1 -1
  428. package/src/tests/slack-render-v2.test.ts +196 -4
  429. package/src/tests/slack-router.test.ts +17 -2
  430. package/src/tests/slack-steering.test.ts +19 -0
  431. package/src/tests/status.test.ts +19 -7
  432. package/src/tests/steering-core.test.ts +1 -1
  433. package/src/tests/steering-enabled.test.ts +6 -8
  434. package/src/tests/steering-transport.test.ts +4 -4
  435. package/src/tests/store-progress-output-guidance.test.ts +34 -0
  436. package/src/tests/swarm-tool-result-gate.test.ts +11 -11
  437. package/src/tests/swarm-x-tool.test.ts +7 -5
  438. package/src/tests/sync-ai-toolbox-skills.test.ts +19 -0
  439. package/src/tests/task-supersede-resume.test.ts +1 -1
  440. package/src/tests/task-tool-preload-mcp.test.ts +4 -1
  441. package/src/tests/task-tools-ctx.test.ts +2 -0
  442. package/src/tests/tasks-requested-by-filter.test.ts +2 -2
  443. package/src/tests/telemetry-init.test.ts +11 -3
  444. package/src/tests/tool-annotations.test.ts +1 -1
  445. package/src/tests/tool-output-agent-id.test.ts +1 -0
  446. package/src/tests/tool-registrar-no-input.test.ts +42 -1
  447. package/src/tests/tracker-fold.test.ts +7 -7
  448. package/src/tests/tracker-tools.test.ts +3 -3
  449. package/src/tests/ui-followup-lead-delegation.test.ts +1 -0
  450. package/src/tests/unified-oauth-migration.test.ts +5 -5
  451. package/src/tests/user-token-rest-auth.test.ts +1 -1
  452. package/src/tests/user-token-routes.test.ts +1 -1
  453. package/src/tests/whoami-route.test.ts +1 -1
  454. package/src/tests/workflow-agent-task.test.ts +15 -13
  455. package/src/tests/workflow-ctx.test.ts +1 -1
  456. package/src/tests/workflow-e2e.test.ts +1 -1
  457. package/src/tests/workflow-engine-v2.test.ts +3 -1
  458. package/src/tests/workflow-executors.test.ts +2 -2
  459. package/src/tests/workflow-http-v2.test.ts +8 -6
  460. package/src/tests/workflow-input-redaction.test.ts +7 -5
  461. package/src/tests/workflow-integration-io.test.ts +2 -2
  462. package/src/tests/workflow-llm.test.ts +5 -5
  463. package/src/tests/workflow-registry.test.ts +1 -1
  464. package/src/tests/workflow-swarm-script.test.ts +1 -1
  465. package/src/tests/workflow-triggers-v2.test.ts +23 -21
  466. package/src/tests/x-composio.test.ts +9 -7
  467. package/src/tests/x402-client.test.ts +1 -1
  468. package/src/tests/x402-config.test.ts +28 -41
  469. package/src/tools/defer-task.ts +156 -24
  470. package/src/tools/extension-common.ts +84 -0
  471. package/src/tools/extension-install.ts +65 -0
  472. package/src/tools/extension-list.ts +66 -0
  473. package/src/tools/script-common.ts +43 -18
  474. package/src/tools/send-task.ts +87 -105
  475. package/src/tools/skills/skill-publish.ts +1 -0
  476. package/src/tools/store-progress.ts +1 -1
  477. package/src/tools/task-action.ts +43 -22
  478. package/src/tools/task-tool-ctx.ts +2 -0
  479. package/src/tools/templates.ts +2 -1
  480. package/src/tools/tool-config.ts +3 -1
  481. package/src/tools/utils.ts +140 -16
  482. package/src/types.ts +144 -0
  483. package/src/utils/constants.ts +7 -1
  484. package/src/utils/credentials.test.ts +16 -16
  485. package/src/utils/multi-runtime.ts +2 -2
  486. package/src/utils/steering-enabled.ts +4 -4
  487. package/src/workflows/executors/agent-task.ts +18 -3
  488. package/templates/ai-toolbox.manifest.json +7 -1
  489. package/templates/extensions/README.md +17 -0
  490. package/templates/extensions/notify-on-complete/README.md +11 -0
  491. package/templates/extensions/notify-on-complete/hooks.ts +61 -0
  492. package/templates/extensions/notify-on-complete/manifest.json +7 -0
  493. package/templates/extensions/require-ticket-ref/README.md +11 -0
  494. package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
  495. package/templates/extensions/require-ticket-ref/manifest.json +7 -0
  496. package/templates/extensions/require-verification-note/README.md +11 -0
  497. package/templates/extensions/require-verification-note/hooks.ts +32 -0
  498. package/templates/extensions/require-verification-note/manifest.json +7 -0
  499. package/templates/schedules/daily-hn-briefing/config.json +1 -1
  500. package/templates/schedules/gtm-weekly-review/config.json +1 -1
  501. package/templates/schedules/weekly-code-health-reports/config.json +1 -1
  502. package/templates/schedules/weekly-dependabot-triage/config.json +1 -1
  503. package/templates/schedules/weekly-dora-metrics/config.json +1 -1
  504. package/templates/schedules/weekly-harness-upgrade-check/config.json +1 -1
  505. package/templates/skills/delegate-work/files/scripts/codex-exec.sh +1 -1
  506. package/templates/skills/scheduling/content.md +2 -0
  507. package/templates/skills/serply-search/SKILL.md +95 -0
  508. package/templates/skills/serply-search/config.json +13 -0
  509. package/templates/skills/serply-search/content.md +90 -0
  510. package/templates/skills/swarm-extensions/config.json +14 -0
  511. package/templates/skills/swarm-extensions/content.md +120 -0
  512. package/templates/skills/swarm-scripts/SKILL.md +2 -2
  513. package/templates/skills/swarm-scripts/content.md +2 -2
  514. package/templates/workflows/claude-code-changelog-watch/config.json +1 -1
  515. package/templates/workflows/gsc-topic-miner/config.json +1 -1
  516. package/templates/workflows/linear-drain-loop/config.json +1 -1
  517. package/templates/workflows/llm-safe-release-context/config.json +1 -1
  518. package/templates/workflows/ralph-loop/config.json +1 -1
  519. package/dist/cli-7fehefdf.js +0 -562
  520. package/dist/cli-ayvy5kde.js +0 -164
  521. package/dist/cli-ddfw1mc4.js +0 -4322
  522. package/dist/cli-hzqmgcm2.js +0 -3066
  523. package/dist/cli-j4d4f6hv.js +0 -338
  524. package/dist/cli-qgm2pfpq.js +0 -6377
  525. package/dist/cli-sdzq01t9.js +0 -823
  526. package/dist/cli-xvkmedgn.js +0 -332
  527. package/dist/cli-y3pq4v9g.js +0 -664
  528. package/dist/{anthropic-messages-vs2rabzp.js → anthropic-messages-2y8nktar.js} +19 -19
  529. package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
  530. package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
  531. package/dist/{cli-6664w7y4.js → cli-kj76p1ez.js} +8 -8
  532. package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
  533. package/dist/{cli-4xz3pmrq.js → cli-y6x0gqtg.js} +16 -16
  534. package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
  535. package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
  536. package/dist/{openai-completions-0bqmsajw.js → openai-completions-32rdwmze.js} +19 -19
  537. package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
  538. package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
@@ -8,8 +8,13 @@ import {
8
8
  } from "@modelcontextprotocol/sdk/server/zod-compat.js";
9
9
  import { z } from "zod";
10
10
  import { createServer } from "@/server";
11
+ import { resolveBridgeCallOrigin } from "../extensions/dispatcher";
11
12
  import { isMcpToolAllowedForScripts } from "../scripts-runtime/sdk-allowlist";
12
- import { markScriptSdkRequestOrigin } from "../tools/utils";
13
+ import {
14
+ markExtensionRequestOrigin,
15
+ markScriptSdkRequestOrigin,
16
+ type RequestInfo,
17
+ } from "../tools/utils";
13
18
  import { route, runtimeInstanceHeader } from "./route-def";
14
19
  import { json, jsonError } from "./utils";
15
20
 
@@ -35,6 +40,78 @@ type RegisteredTool = {
35
40
 
36
41
  type ToolRegistry = Record<string, RegisteredTool>;
37
42
 
43
+ export class InProcessToolInvocationError extends Error {
44
+ constructor(
45
+ message: string,
46
+ readonly status: number,
47
+ ) {
48
+ super(message);
49
+ this.name = "InProcessToolInvocationError";
50
+ }
51
+ }
52
+
53
+ export async function invokeToolInProcess(args: {
54
+ toolName: string;
55
+ args?: unknown;
56
+ agentId?: string;
57
+ sourceTaskId?: string;
58
+ runtimeInstanceId?: string;
59
+ callOrigin: Extract<RequestInfo["callOrigin"], "script-sdk" | "extension">;
60
+ }): Promise<unknown> {
61
+ if (!isMcpToolAllowedForScripts(args.toolName)) {
62
+ throw new InProcessToolInvocationError(
63
+ `Tool '${args.toolName}' is not in the SDK allowlist`,
64
+ 403,
65
+ );
66
+ }
67
+
68
+ const server = await getBridgeServer();
69
+ const tools = (server as unknown as { _registeredTools: ToolRegistry })._registeredTools;
70
+ const tool = tools[args.toolName];
71
+ if (!tool) {
72
+ throw new InProcessToolInvocationError(
73
+ `Tool '${args.toolName}' not found in the MCP registry`,
74
+ 404,
75
+ );
76
+ }
77
+ if (tool.enabled === false) {
78
+ throw new InProcessToolInvocationError(`Tool '${args.toolName}' is disabled`, 400);
79
+ }
80
+
81
+ const baseExtra = {
82
+ sessionId: args.callOrigin === "extension" ? "extension" : "mcp-bridge",
83
+ requestInfo: {
84
+ headers: {
85
+ "x-agent-id": args.agentId ?? "",
86
+ ...(args.sourceTaskId ? { "x-source-task-id": args.sourceTaskId } : {}),
87
+ ...(args.runtimeInstanceId ? { "x-runtime-instance-id": args.runtimeInstanceId } : {}),
88
+ },
89
+ },
90
+ };
91
+ const extra =
92
+ args.callOrigin === "extension"
93
+ ? markExtensionRequestOrigin(baseExtra)
94
+ : markScriptSdkRequestOrigin(baseExtra);
95
+
96
+ let handlerArgs: unknown = args.args ?? {};
97
+ if (tool.inputSchema) {
98
+ const inputObj = normalizeObjectSchema(tool.inputSchema);
99
+ const parseResult = await safeParseAsync(inputObj ?? tool.inputSchema, handlerArgs);
100
+ if (!parseResult.success) {
101
+ const parseError = "error" in parseResult ? parseResult.error : "Unknown error";
102
+ throw new InProcessToolInvocationError(
103
+ `Invalid arguments for tool '${args.toolName}': ${getParseErrorMessage(parseError)}`,
104
+ 400,
105
+ );
106
+ }
107
+ handlerArgs = parseResult.data;
108
+ }
109
+
110
+ return tool.inputSchema
111
+ ? await Promise.resolve(tool.handler(handlerArgs, extra))
112
+ : await Promise.resolve(tool.handler(extra));
113
+ }
114
+
38
115
  const mcpBridgeRoute = route({
39
116
  method: "post",
40
117
  path: "/api/mcp-bridge",
@@ -58,6 +135,11 @@ const mcpBridgeRoute = route({
58
135
  },
59
136
  });
60
137
 
138
+ function headerValue(req: IncomingMessage, name: string): string | undefined {
139
+ const value = req.headers[name];
140
+ return Array.isArray(value) ? value[0] : value;
141
+ }
142
+
61
143
  export async function handleMcpBridge(
62
144
  req: IncomingMessage,
63
145
  res: ServerResponse,
@@ -72,70 +154,22 @@ export async function handleMcpBridge(
72
154
 
73
155
  const { tool: toolName, args } = parsed.body;
74
156
 
75
- if (!isMcpToolAllowedForScripts(toolName)) {
76
- jsonError(res, `Tool '${toolName}' is not in the SDK allowlist`, 403);
77
- return true;
78
- }
79
-
80
- const server = await getBridgeServer();
81
- const tools = (server as unknown as { _registeredTools: ToolRegistry })._registeredTools;
82
-
83
- const tool = tools[toolName];
84
- if (!tool) {
85
- jsonError(res, `Tool '${toolName}' not found in the MCP registry`, 404);
86
- return true;
87
- }
88
-
89
- if (tool.enabled === false) {
90
- jsonError(res, `Tool '${toolName}' is disabled`, 400);
91
- return true;
92
- }
93
-
94
- const sourceTaskId = Array.isArray(req.headers["x-source-task-id"])
95
- ? req.headers["x-source-task-id"][0]
96
- : (req.headers["x-source-task-id"] as string | undefined);
157
+ const sourceTaskId = headerValue(req, "x-source-task-id");
97
158
  // Runtime identity rides the bridge like the agent identity so the
98
159
  // work-acquisition gates in bridged tools see the invoking worker process.
99
- const runtimeInstanceId = Array.isArray(req.headers["x-runtime-instance-id"])
100
- ? req.headers["x-runtime-instance-id"][0]
101
- : (req.headers["x-runtime-instance-id"] as string | undefined);
102
-
103
- const extra = markScriptSdkRequestOrigin({
104
- sessionId: "mcp-bridge",
105
- requestInfo: {
106
- headers: {
107
- "x-agent-id": myAgentId ?? "",
108
- ...(sourceTaskId ? { "x-source-task-id": sourceTaskId } : {}),
109
- ...(runtimeInstanceId ? { "x-runtime-instance-id": runtimeInstanceId } : {}),
110
- },
111
- },
112
- });
113
-
114
- // Mirror the SDK's own tools/call validation (`validateToolInput` in
115
- // @modelcontextprotocol/sdk server/mcp.js). The bridge bypasses the MCP
116
- // transport, so without this parse raw script args reach handlers
117
- // unchecked (2026-08-18 priority='high' incident) and the schema's
118
- // `.default()`/`.transform()` never apply.
119
- let handlerArgs: unknown = args;
120
- if (tool.inputSchema) {
121
- const inputObj = normalizeObjectSchema(tool.inputSchema);
122
- const parseResult = await safeParseAsync(inputObj ?? tool.inputSchema, args);
123
- if (!parseResult.success) {
124
- const parseError = "error" in parseResult ? parseResult.error : "Unknown error";
125
- jsonError(
126
- res,
127
- `Invalid arguments for tool '${toolName}': ${getParseErrorMessage(parseError)}`,
128
- 400,
129
- );
130
- return true;
131
- }
132
- handlerArgs = parseResult.data;
133
- }
160
+ const runtimeInstanceId = headerValue(req, "x-runtime-instance-id");
134
161
 
135
162
  try {
136
- const result = tool.inputSchema
137
- ? await Promise.resolve(tool.handler(handlerArgs, extra))
138
- : await Promise.resolve(tool.handler(extra));
163
+ const result = await invokeToolInProcess({
164
+ toolName,
165
+ args,
166
+ agentId: myAgentId,
167
+ sourceTaskId,
168
+ runtimeInstanceId,
169
+ // The agent header is caller-controlled; the extension origin also needs the
170
+ // per-process token that only the in-process extension SDK holds.
171
+ callOrigin: resolveBridgeCallOrigin(myAgentId, headerValue(req, "x-extension-token")),
172
+ });
139
173
 
140
174
  if (result && typeof result === "object" && "structuredContent" in result) {
141
175
  json(res, result.structuredContent);
@@ -155,7 +189,7 @@ export async function handleMcpBridge(
155
189
  }
156
190
  } catch (err) {
157
191
  const message = err instanceof Error ? err.message : String(err);
158
- jsonError(res, message, 500);
192
+ jsonError(res, message, err instanceof InProcessToolInvocationError ? err.status : 500);
159
193
  }
160
194
  return true;
161
195
  }
package/src/http/mcp.ts CHANGED
@@ -203,7 +203,7 @@ export async function handleMcp(
203
203
  const preloadEnabled = parseEnvFlag(
204
204
  configs.find((config) => config.key === "TASK_TOOL_PRELOAD_ENABLED")?.value ??
205
205
  process.env.TASK_TOOL_PRELOAD_ENABLED,
206
- false,
206
+ true,
207
207
  );
208
208
  let preloadedTools: string[] = [];
209
209
  if (preloadEnabled) {
@@ -625,6 +625,11 @@ export async function handleScriptRuns(
625
625
  routingReason:
626
626
  parsed.body.routingReason ?? (parsed.body.agentId ? "human_pinned" : undefined),
627
627
  routingNote: parsed.body.routingNote,
628
+ routingSource: parsed.body.routingReason
629
+ ? "declared"
630
+ : parsed.body.agentId
631
+ ? "engine_default"
632
+ : undefined,
628
633
  tags: parsed.body.tags,
629
634
  priority: parsed.body.priority,
630
635
  offeredTo: parsed.body.offerMode ? parsed.body.agentId : undefined,
@@ -32,6 +32,7 @@ import {
32
32
  hasFirstCompletedTask,
33
33
  listAgentsWithCredStatusByProvider,
34
34
  } from "../be/db";
35
+ import { getEmbeddingProvider } from "../be/memory";
35
36
  import { getFileStorageProvider } from "../fs/registry";
36
37
  import { type AgentCredStatus, AutomationIntegrationIdSchema, ProviderNameSchema } from "../types";
37
38
  import { route } from "./route-def";
@@ -385,10 +386,11 @@ async function harnessMilestone(): Promise<SetupMilestone> {
385
386
  }
386
387
 
387
388
  function embeddingsMilestone(): SetupMilestone {
388
- // Keep this precedence identical to OpenAIEmbeddingProvider: an explicitly
389
- // empty EMBEDDING_API_KEY disables the OPENAI_API_KEY fallback.
390
- const embeddingKey = process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY;
391
- if (embeddingKey) {
389
+ // Ask the live provider rather than re-deriving key precedence here — it
390
+ // reflects whatever the last config reload (or boot) resolved, including
391
+ // an explicitly empty EMBEDDING_API_KEY disabling the OPENAI_API_KEY
392
+ // fallback. See OpenAIEmbeddingProvider.isConfigured().
393
+ if (getEmbeddingProvider().isConfigured()) {
392
394
  return {
393
395
  id: "embeddings",
394
396
  label: "Memory search",
package/src/http/tasks.ts CHANGED
@@ -41,6 +41,7 @@ import {
41
41
  } from "../be/steering";
42
42
  import { findUserById } from "../be/users";
43
43
  import { can, type RbacPrincipal, type RbacResource } from "../rbac";
44
+ import { TaskCreationBlockedError } from "../tasks/errors";
44
45
  import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
45
46
  import { guardTerminalTaskResultWrite } from "../tasks/terminal-result-guard";
46
47
  import { createResumeFollowUp, createWorkerTaskFollowUp } from "../tasks/worker-follow-up";
@@ -259,6 +260,13 @@ const createTask = route({
259
260
  responses: {
260
261
  201: { description: "Task created", schema: AgentTaskSchema },
261
262
  400: { description: "Validation error" },
263
+ 422: {
264
+ description: "Task creation blocked by an extension",
265
+ schema: z.object({
266
+ error: z.string(),
267
+ extension: z.object({ id: z.string(), name: z.string() }),
268
+ }),
269
+ },
262
270
  },
263
271
  });
264
272
 
@@ -836,36 +844,45 @@ export async function handleTasks(
836
844
  }
837
845
 
838
846
  try {
839
- const task = await createTaskWithSiblingAwareness(parsed.body.task, {
840
- key: assetKey,
841
- agentId: defaultAgentId,
842
- routingReason:
843
- parsed.body.routingReason ??
844
- (defaultAgentId
845
- ? parentTask?.agentId === defaultAgentId
846
- ? "continuity"
847
- : "skill"
848
- : undefined),
849
- routingNote: parsed.body.routingNote,
850
- creatorAgentId: myAgentId || undefined,
851
- taskType: parsed.body.taskType || undefined,
852
- tags: parsed.body.tags || undefined,
853
- priority: parsed.body.priority,
854
- dependsOn: parsed.body.dependsOn || undefined,
855
- offeredTo: parsed.body.offeredTo || undefined,
856
- dir: parsed.body.dir || undefined,
857
- parentTaskId: parsed.body.parentTaskId || undefined,
858
- source: parsed.body.source || "api",
859
- outputSchema: parsed.body.outputSchema || undefined,
860
- contextKey: parsed.body.contextKey || undefined,
861
- requestedByUserId,
862
- status: parsed.body.draft ? "draft" : undefined,
863
- ...splitLegacyModelAlias({
864
- model: parsed.body.model,
865
- modelTier: parsed.body.modelTier,
866
- }),
867
- effort: parsed.body.effort,
868
- });
847
+ const task = await createTaskWithSiblingAwareness(
848
+ parsed.body.task,
849
+ {
850
+ key: assetKey,
851
+ agentId: defaultAgentId,
852
+ routingReason:
853
+ parsed.body.routingReason ??
854
+ (defaultAgentId
855
+ ? parentTask?.agentId === defaultAgentId
856
+ ? "continuity"
857
+ : "skill"
858
+ : undefined),
859
+ routingSource: parsed.body.routingReason
860
+ ? "declared"
861
+ : defaultAgentId
862
+ ? "engine_default"
863
+ : undefined,
864
+ routingNote: parsed.body.routingNote,
865
+ creatorAgentId: myAgentId || undefined,
866
+ taskType: parsed.body.taskType || undefined,
867
+ tags: parsed.body.tags || undefined,
868
+ priority: parsed.body.priority,
869
+ dependsOn: parsed.body.dependsOn || undefined,
870
+ offeredTo: parsed.body.offeredTo || undefined,
871
+ dir: parsed.body.dir || undefined,
872
+ parentTaskId: parsed.body.parentTaskId || undefined,
873
+ source: parsed.body.source || "api",
874
+ outputSchema: parsed.body.outputSchema || undefined,
875
+ contextKey: parsed.body.contextKey || undefined,
876
+ requestedByUserId,
877
+ status: parsed.body.draft ? "draft" : undefined,
878
+ ...splitLegacyModelAlias({
879
+ model: parsed.body.model,
880
+ modelTier: parsed.body.modelTier,
881
+ }),
882
+ effort: parsed.body.effort,
883
+ },
884
+ { origin: "rest" },
885
+ );
869
886
 
870
887
  ensure({
871
888
  id: "created",
@@ -885,6 +902,10 @@ export async function handleTasks(
885
902
 
886
903
  createTask.respond(res, 201, task);
887
904
  } catch (error) {
905
+ if (error instanceof TaskCreationBlockedError) {
906
+ createTask.respond(res, 422, { error: error.reason, extension: error.extension });
907
+ return true;
908
+ }
888
909
  console.error("[HTTP] Failed to create task:", error);
889
910
  jsonError(res, "Failed to create task", 500);
890
911
  }
@@ -152,16 +152,21 @@ export async function routeKapsoInbound(payload: KapsoWebhookPayload): Promise<K
152
152
  return { kind: "workflow", workflowId: mapping.workflowId };
153
153
  }
154
154
 
155
- const task = await createTaskWithSiblingAwareness(await buildTaskDescription(payload), {
156
- agentId: mapping.agentId ?? null,
157
- routingReason: mapping.agentId ? "human_pinned" : undefined,
158
- source: "system",
159
- taskType: "kapso-inbound",
160
- tags: ["kapso-whatsapp", "inbound"],
161
- priority: 70,
162
- requestedByUserId: await resolveKapsoRequestedByUserId(payload),
163
- contextKey: `kapso:conversation:${payload.conversation?.id ?? messageId}`,
164
- });
155
+ const task = await createTaskWithSiblingAwareness(
156
+ await buildTaskDescription(payload),
157
+ {
158
+ agentId: mapping.agentId ?? null,
159
+ routingReason: mapping.agentId ? "human_pinned" : undefined,
160
+ routingSource: mapping.agentId ? "engine_default" : undefined,
161
+ source: "system",
162
+ taskType: "kapso-inbound",
163
+ tags: ["kapso-whatsapp", "inbound"],
164
+ priority: 70,
165
+ requestedByUserId: await resolveKapsoRequestedByUserId(payload),
166
+ contextKey: `kapso:conversation:${payload.conversation?.id ?? messageId}`,
167
+ },
168
+ { origin: "webhook" },
169
+ );
165
170
 
166
171
  return { kind: "task", taskId: task.id };
167
172
  }
package/src/jira/sync.ts CHANGED
@@ -580,14 +580,19 @@ async function createInitialJiraTask(input: {
580
580
  return;
581
581
  }
582
582
 
583
- const task = await createTaskWithSiblingAwareness(result.text, {
584
- agentId: lead?.id ?? "",
585
- routingReason: lead ? "skill" : undefined,
586
- source: "jira",
587
- taskType: "jira-issue",
588
- requestedByUserId: input.requestedByUserId,
589
- contextKey: buildJiraContextKey(input.issueKey),
590
- });
583
+ const task = await createTaskWithSiblingAwareness(
584
+ result.text,
585
+ {
586
+ agentId: lead?.id ?? "",
587
+ routingReason: lead ? "skill" : undefined,
588
+ routingSource: lead ? "engine_default" : undefined,
589
+ source: "jira",
590
+ taskType: "jira-issue",
591
+ requestedByUserId: input.requestedByUserId,
592
+ contextKey: buildJiraContextKey(input.issueKey),
593
+ },
594
+ { origin: "webhook" },
595
+ );
591
596
 
592
597
  await updateTrackerSyncSwarmId(input.syncRowId, task.id);
593
598
 
@@ -626,14 +631,19 @@ async function createCommentMentionTask(input: {
626
631
  return;
627
632
  }
628
633
 
629
- const task = await createTaskWithSiblingAwareness(result.text, {
630
- agentId: lead?.id ?? "",
631
- routingReason: lead ? "skill" : undefined,
632
- source: "jira",
633
- taskType: "jira-issue",
634
- requestedByUserId: input.requestedByUserId,
635
- contextKey: buildJiraContextKey(input.issueKey),
636
- });
634
+ const task = await createTaskWithSiblingAwareness(
635
+ result.text,
636
+ {
637
+ agentId: lead?.id ?? "",
638
+ routingReason: lead ? "skill" : undefined,
639
+ routingSource: lead ? "engine_default" : undefined,
640
+ source: "jira",
641
+ taskType: "jira-issue",
642
+ requestedByUserId: input.requestedByUserId,
643
+ contextKey: buildJiraContextKey(input.issueKey),
644
+ },
645
+ { origin: "webhook" },
646
+ );
637
647
 
638
648
  await updateTrackerSyncSwarmId(input.syncRowId, task.id);
639
649
 
@@ -612,14 +612,19 @@ export async function handleAgentSessionEvent(event: Record<string, unknown>): P
612
612
  return;
613
613
  }
614
614
 
615
- const task = await createTaskWithSiblingAwareness(templateResult.text, {
616
- agentId: lead?.id ?? "",
617
- routingReason: lead ? "skill" : undefined,
618
- source: "linear",
619
- taskType: "linear-issue",
620
- requestedByUserId,
621
- contextKey,
622
- });
615
+ const task = await createTaskWithSiblingAwareness(
616
+ templateResult.text,
617
+ {
618
+ agentId: lead?.id ?? "",
619
+ routingReason: lead ? "skill" : undefined,
620
+ routingSource: lead ? "engine_default" : undefined,
621
+ source: "linear",
622
+ taskType: "linear-issue",
623
+ requestedByUserId,
624
+ contextKey,
625
+ },
626
+ { origin: "webhook" },
627
+ );
623
628
 
624
629
  // Delete old tracker_sync before creating new one (UNIQUE constraint)
625
630
  if (existing) {
@@ -896,14 +901,19 @@ export async function handleAgentSessionPrompted(event: Record<string, unknown>)
896
901
  return;
897
902
  }
898
903
 
899
- const task = await createTaskWithSiblingAwareness(followupResult.text, {
900
- agentId: lead?.id ?? "",
901
- routingReason: lead ? "skill" : undefined,
902
- source: "linear",
903
- taskType: "linear-issue",
904
- requestedByUserId: promptedRequestedByUserId,
905
- contextKey,
906
- });
904
+ const task = await createTaskWithSiblingAwareness(
905
+ followupResult.text,
906
+ {
907
+ agentId: lead?.id ?? "",
908
+ routingReason: lead ? "skill" : undefined,
909
+ routingSource: lead ? "engine_default" : undefined,
910
+ source: "linear",
911
+ taskType: "linear-issue",
912
+ requestedByUserId: promptedRequestedByUserId,
913
+ contextKey,
914
+ },
915
+ { origin: "webhook" },
916
+ );
907
917
 
908
918
  // Repoint the existing tracker_sync to the new follow-up task (can't create a
909
919
  // duplicate due to UNIQUE(provider, entityType, externalId) constraint)
@@ -72,10 +72,12 @@ Choose the path by the shape of the work:
72
72
  - Everything else: tools, directly.
73
73
 
74
74
  Store progress with \`store-progress\` at each milestone. A milestone is a result the lead could act on.
75
- The task is done when \`store-progress\` carries status \`completed\` and an \`output\` that names the result and every artifact link. On failure, status \`failed\` and a \`failureReason\` that names what you tried.
76
- When the task carries an \`outputSchema\`, \`output\` is JSON that matches it.
75
+ Complete with \`store-progress\`: status \`completed\`, and \`output\` naming the result and every artifact link. On failure: status \`failed\`, with \`failureReason\` naming what you tried.
76
+ Free-text \`output\`: under 120 words by default, with the exceptions in How you write. Link documents instead of inlining them; omit process narration.
77
+ For a task with \`outputSchema\`, return matching JSON in \`output\`.
77
78
  When you are blocked after real effort, store the blocker with \`store-progress\` and keep working on what you can.
78
- The task has four endings. When you are done: \`completed\`. When the answer needs time (a build, a deploy, a reply): \`defer-task\` with a summary of what you did, when to wake up, and what to check. It completes the task now; the wake-up task continues it. When a person must decide: \`request-human-input\`. When nothing else is possible: \`failed\` with the blocker.
79
+ The task has four endings. When you are done: \`completed\`. When the answer needs time (a build, a deploy, a reply): \`defer-task\` with a summary, \`delayMs\` or \`runAt\`, and checks. It completes the task now; the wake-up task continues it. When a person must decide: \`request-human-input\`. When nothing else is possible: \`failed\` with the blocker.
80
+ For task waits, add \`wakeOn:{event:"settled",taskIds:["<id>"],mode:"all"}\`; the displayed time is a ceiling, not a fixed wake-up.
79
81
  `,
80
82
  variables: [],
81
83
  category: "system",
@@ -90,15 +92,15 @@ registerTemplate({
90
92
  Your output is delegation and review. Workers implement, research, analyze, and write. Data gathering, even a quick query, goes to a worker. You answer simple factual questions yourself.
91
93
 
92
94
  \`get-swarm\` is the roster. Route by capability and load.
93
- \`send-task\`: include \`routingReason\` with \`agentId\`. Read results via \`get-task-details\`.
95
+ \`send-task\`: include \`routingReason\` and \`routingNote\` (at least 10 characters after trim, maximum 200) with \`agentId\`. Read results via \`get-task-details\`.
94
96
  A task states the goal, the repo URL when there is one, and the constraints. Workers know git, the skills, and \`store-progress\`.
95
97
  Delegate by the shape of the work: a workflow for multi-step or fan-out work, a schedule for recurring work, a script for bulk data, an inline \`script-run\` for a one-off bulk job you can run yourself. The \`workflow-iterate\`, \`scheduling\`, and \`swarm-scripts\` skills build them.
96
98
  Research or exploration: tell the worker to use the \`researching\` skill. A large feature: a task for the \`planning\` skill first, then a task for the \`implementing\` skill with \`parentTaskId\`. A small fix: direct implementation.
97
99
  A follow-up that continues earlier work carries \`parentTaskId\`. The worker receives the prior context.
98
100
 
99
- Worker completion/failure triggers a follow-up by default. For longer work, \`defer-task\` with a wake-up or complete this task. Review the worker's answer and complete the follow-up. Escalate only failures needing a person.
101
+ Worker completion/failure triggers a follow-up by default; review the result and complete it. Escalate only failures needing a person. For longer task waits, complete this task or \`defer-task\` with \`wakeOn:{event:"settled",taskIds:["<id>"],mode:"all"}\` alongside \`delayMs\` or \`runAt\`. The displayed time is a ceiling, not a fixed wake-up.
100
102
 
101
- Wait inline via \`wait-for-task\` only for an essential result expected within ~1 minute. Set \`send-task.followUpConfig.disabled=true\`; cap all waits at ~1 minute total. If still running, \`defer-task\` with a wake-up.
103
+ For an essential result expected within ~1 minute, set \`send-task.followUpConfig.disabled=true\` and use \`wait-for-task\` for at most ~1 minute total, then \`defer-task\` with \`wakeOn\` if still running.
102
104
 
103
105
  A task from an unknown user: register them with \`manage-user\`, then continue.
104
106
  Your heartbeat runbook is the \`heartbeatMd\` profile field. Edit it with \`update-profile\`. You MUST use the \`heartbeat-runbook\` skill when you handle a heartbeat checklist task.
@@ -118,6 +120,7 @@ registerTemplate({
118
120
  The lead assigns your tasks and reviews your output. Your task is in your first message, with memories from past sessions.
119
121
 
120
122
  Your final message is the task output. It names the result, every link (a PR, a file, a page), and, on failure, what you tried and what blocked you.
123
+ Free-text task output: under 120 words by default, with the exceptions in How you write. Link documents instead of inlining them; omit process narration.
121
124
  `,
122
125
  variables: [],
123
126
  category: "system",
@@ -230,14 +233,14 @@ registerTemplate({
230
233
  defaultBody: `
231
234
  ## How you write
232
235
 
233
- For human-facing replies and artifacts: lead with the result. Use plain words, active voice, one idea per sentence, and sentence case headings.
236
+ For replies, task output (\`output\` or a remote final message), and artifacts: lead with the result. Use plain words, active voice, one idea per sentence, and sentence case headings.
234
237
  State blockers and reasons. Preserve meaningful uncertainty.
235
238
  Omit em dashes, filler, sign-offs, praise, repetition, step narration, and generic offers to elaborate.
236
239
 
237
- Simple replies: one to three sentences. Routine replies: under 120 words, using short paragraphs or up to three bullets.
238
- Use more detail for requested depth or essential evidence, caveats, or instructions.
239
- Include context only when it changes understanding or action. Link extensive supporting material when useful, but make the reply self-contained.
240
- Do not shorten investigation, required artifacts, or schema-defined output to meet reply limits.
240
+ Simple replies: one to three sentences. Routine replies and free-text task output: under 120 words by default, in short paragraphs or up to three bullets.
241
+ Exceed for requested depth, enumerated results, essential evidence, caveats, instructions, or longer output required by the task's \`outputSchema\`.
242
+ Keep replies and task output self-contained; link documents instead of inlining them.
243
+ Preserve investigation and required artifacts. Schema exemptions apply to \`outputSchema\`-constrained completions; free-text \`output\` follows the target.
241
244
 
242
245
  Follow the current request and Requester Profile for language, tone, depth, and format. Correctness wins over style.
243
246
  Use the \`comms\` skill when available for requested simplification or clarity rewrites. Ordinary replies need no skill invocation.
@@ -278,6 +281,7 @@ registerTemplate({
278
281
  ## Slack
279
282
 
280
283
  The engine posts the thread tree and the outcome card. You post at most one message per task, and only when you have something the card will not carry. Progress, receipts, and relayed worker output stay out of Slack.
284
+ The outcome card publishes your \`output\` verbatim. Keep free-text \`output\` under 120 words by default, with the exceptions in How you write.
281
285
  A Slack task from an unknown user: register them with \`manage-user\` first.
282
286
  You MUST use the \`slack-interaction\` skill before you post to Slack.
283
287
  `,
@@ -400,8 +404,8 @@ This swarm runs in **scripts-only mode**. The ONLY swarm MCP tools available are
400
404
  The script authoring contract in the \`swarm-scripts\` skill (entry signature, \`ctx\` shape, secret handling) applies here unchanged. The full SDK is \`ctx.swarm.*\`: task lifecycle (\`task_get\`, \`task_send\`, \`task_storeProgress\`, \`task_action\`, \`task_list\`), Slack (\`slack_reply\`, \`slack_post\`, \`slack_read\`), memory, kv, swarm info (\`swarm_get\`, \`agent_info\`), and more. Responses are usually wrapped; prefer \`res?.data ?? res\`.
401
405
 
402
406
  **Built-in coordination scripts, USE THESE FIRST (\`script-run\` with \`name\` + \`args\`):**
403
- - \`delegate\` {agentName, task, routingReason, parentTaskId?} → subtask for an agent by name; returns {taskId}
404
- - \`wait-for-task\` {taskId} → waits up to ~25s for a terminal state; returns {done, status, output}; only for a child expected to finish within about a minute whose result the answer requires. Bound all calls to about a minute total; if still done=false, use \`defer-task\` with a wake-up to collect the result.
407
+ - \`delegate\` {agentName, task, routingReason, routingNote, parentTaskId?} → subtask for an agent by name; returns {taskId}
408
+ - \`wait-for-task\` {taskId} → waits up to ~25s for a terminal state; returns {done, status, output}; only for a child expected to finish within about a minute whose result the answer requires. Bound all calls to about a minute total; if still done=false, use \`defer-task\` with \`wakeOn:{event:"settled",taskIds:["<id>"],mode:"all"}\` alongside \`delayMs\` or \`runAt\`. The displayed time is a ceiling; matching task outcomes wake you sooner.
405
409
  - \`get-child-outputs\` {parentTaskId} → all children with status+output
406
410
  - \`complete-task\` {taskId, output} → THE way to finish your assigned task
407
411
  - \`report-progress\` {taskId, note} → progress update
@@ -426,6 +430,7 @@ registerTemplate({
426
430
  ## Slack (scripts-only)
427
431
 
428
432
  This task originated from Slack (channel: \`{{slackChannelId}}\`). The engine maintains the thread tree and publishes the top-level outcome card. Post at most one distinct agent-authored message per task, concrete, sized to what the user asked for. Progress, start, completion, failure, acknowledgment messages, and relayed raw task output stay out of Slack. Named Slack tools are not exposed in scripts-only mode, so use \`script-run\` with inline source calling \`ctx.swarm.slack_reply({ taskId, message })\` (your taskId carries the thread context).
433
+ The outcome card publishes your \`output\` verbatim. Keep free-text \`output\` under 120 words by default, with the exceptions in How you write.
429
434
  `,
430
435
  variables: [
431
436
  { name: "slackChannelId", description: "The Slack channel ID for the originating thread" },
@@ -96,6 +96,8 @@ export function parseClaudeBinary(raw: string | undefined): string[] {
96
96
  }
97
97
 
98
98
  const MIN_CLAUDE_QUEUE_STEERING_VERSION = [2, 1, 205] as const;
99
+ const CLAUDE_VERSION_PROBE_TIMEOUT_MS = 1_000;
100
+ const CLAUDE_VERSION_PROBE_MAX_BUFFER_BYTES = 64 * 1024;
99
101
 
100
102
  /**
101
103
  * Operator kill-switch for the stream-json invocation path.
@@ -1157,14 +1159,25 @@ export class ClaudeAdapter implements ProviderAdapter {
1157
1159
  const queueSteeringOverride = resolveClaudeQueueSteeringOverride(sourceEnv);
1158
1160
  let harnessVersion: string | undefined;
1159
1161
  try {
1160
- const result = Bun.spawnSync([...effectiveClaudeBinaryArgv, "--version"], {
1161
- env: sourceEnv,
1162
- stdout: "pipe",
1163
- stderr: "pipe",
1164
- });
1165
- if (result.success) {
1166
- const trimmed =
1167
- `${result.stdout?.toString() ?? ""}\n${result.stderr?.toString() ?? ""}`.trim();
1162
+ const probe = registerProcessGroup(
1163
+ Bun.spawn([...effectiveClaudeBinaryArgv, "--version"], {
1164
+ detached: detachedProcessGroup,
1165
+ env: sourceEnv,
1166
+ stdin: "ignore",
1167
+ stdout: "pipe",
1168
+ stderr: "pipe",
1169
+ timeout: CLAUDE_VERSION_PROBE_TIMEOUT_MS,
1170
+ killSignal: "SIGKILL",
1171
+ maxBuffer: CLAUDE_VERSION_PROBE_MAX_BUFFER_BYTES,
1172
+ }),
1173
+ );
1174
+ const exitCode = await probe.exited.finally(() => terminateProcessGroup(probe.pid));
1175
+ const [stdout, stderr] = await Promise.all([
1176
+ new Response(probe.stdout).text(),
1177
+ new Response(probe.stderr).text(),
1178
+ ]);
1179
+ if (exitCode === 0) {
1180
+ const trimmed = `${stdout}\n${stderr}`.trim();
1168
1181
  if (trimmed) {
1169
1182
  harnessVersion = trimmed;
1170
1183
  harnessVariantMeta = { version: trimmed };
@@ -15,7 +15,7 @@ export type AdmissionDecision =
15
15
  | { allow: false; reason: string; verb?: PermissionVerb };
16
16
 
17
17
  export function isRbacEnabled(): boolean {
18
- return isEnvFlagEnabled("RBAC_ENABLED", false);
18
+ return isEnvFlagEnabled("RBAC_ENABLED", true);
19
19
  }
20
20
 
21
21
  export function decideAdmission(input: {