@desplega.ai/agent-swarm 2.3.0 → 2.4.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 (247) hide show
  1. package/README.md +1 -0
  2. package/dist/{acp-adapter-v85a2bqy.js → acp-adapter-kedstxx6.js} +6 -6
  3. package/dist/{actions-zgcxfspj.js → actions-vget6r1k.js} +18 -16
  4. package/dist/{amp-adapter-jw9xfz42.js → amp-adapter-xeb5mktv.js} +2 -2
  5. package/dist/{app-4e1s4675.js → app-mqap8t8m.js} +3 -3
  6. package/dist/{assistant-v238n9dk.js → assistant-h0gv97mv.js} +20 -18
  7. package/dist/{boot-reembed-p666cw5n.js → boot-reembed-qr8a894z.js} +1 -1
  8. package/dist/{boot-reembed-w6pm64j4.js → boot-reembed-rj85jjhw.js} +1 -1
  9. package/dist/{boot-scrub-sweep-jcyjagn3.js → boot-scrub-sweep-eyfvn6v9.js} +3 -3
  10. package/dist/{boot-seeds-gbedmamp.js → boot-seeds-xs9a8dx1.js} +4 -4
  11. package/dist/{claude-adapter-q7wspzt8.js → claude-adapter-bm23cye7.js} +5 -5
  12. package/dist/{claude-managed-adapter-n7ahjyx6.js → claude-managed-adapter-1mwrsm9d.js} +2 -2
  13. package/dist/{claude-managed-setup-wza784fb.js → claude-managed-setup-gkfgks4j.js} +1 -1
  14. package/dist/{claude-sdk-session-yf400ptr.js → claude-sdk-session-apb4ypz3.js} +5 -5
  15. package/dist/cli-02vhhssk.js +848 -0
  16. package/dist/{cli-4ync7m60.js → cli-0ebey9hg.js} +1 -1
  17. package/dist/{cli-665j3feb.js → cli-0xk505e8.js} +1 -1
  18. package/dist/{cli-30m5q8mc.js → cli-1cevz46c.js} +5 -5
  19. package/dist/{cli-gzvb3d4a.js → cli-1jx0srjt.js} +3 -3
  20. package/dist/{cli-zj4d6afs.js → cli-1pa3rz69.js} +21 -6
  21. package/dist/{cli-fhvqt2fp.js → cli-2rwet3r7.js} +1 -1
  22. package/dist/{cli-azs9bhc5.js → cli-3wjs22x3.js} +2 -2
  23. package/dist/{cli-dxwh4j32.js → cli-4fhyq711.js} +45 -36
  24. package/dist/{cli-yv3n83x8.js → cli-5ff2sjyt.js} +1 -1
  25. package/dist/{cli-6vcyw6v7.js → cli-5s5hx57y.js} +5 -3
  26. package/dist/{cli-hz64bcnj.js → cli-6ftrrwm1.js} +9 -371
  27. package/dist/{cli-zes4tsbb.js → cli-8b9wvjps.js} +1 -1
  28. package/dist/cli-8cxkw1f5.js +382 -0
  29. package/dist/{cli-4s1kqrqg.js → cli-8rwvksbc.js} +2 -2
  30. package/dist/{cli-e09hj50q.js → cli-8wkb09q5.js} +11 -11
  31. package/dist/{cli-yv0vgscc.js → cli-a1esmmee.js} +13 -2
  32. package/dist/{cli-4hmaheb6.js → cli-avmqhatn.js} +7 -7
  33. package/dist/{cli-g6p7c2my.js → cli-b80a1100.js} +1 -1
  34. package/dist/{cli-tr24eeny.js → cli-bfc3k1x5.js} +3 -3
  35. package/dist/{cli-ka01m5rb.js → cli-bhwa8rzc.js} +13 -11
  36. package/dist/{cli-8cvvytad.js → cli-bn26xbcs.js} +2 -2
  37. package/dist/{cli-k28p6xh7.js → cli-c8fwpgqb.js} +1 -1
  38. package/dist/{cli-rc3r0bnh.js → cli-ccn0eybf.js} +1 -1
  39. package/dist/{cli-9td5ss65.js → cli-dsgj3e7a.js} +2 -2
  40. package/dist/{cli-a17tzmn0.js → cli-ecshf504.js} +2 -2
  41. package/dist/{cli-d43xqzbe.js → cli-eqgfs202.js} +1 -1
  42. package/dist/{cli-ppapy34w.js → cli-f3nx1h8z.js} +2 -2
  43. package/dist/{cli-ea7chd26.js → cli-ffbrkh1r.js} +74 -35
  44. package/dist/{cli-xgn4rwyv.js → cli-kk2r80n5.js} +4 -4
  45. package/dist/{cli-hn3pftj2.js → cli-kz116kvw.js} +3 -3
  46. package/dist/{cli-1v8w782f.js → cli-mvg2hf8p.js} +4 -4
  47. package/dist/{cli-5d1m1qca.js → cli-mz1ezzzh.js} +1 -1
  48. package/dist/{cli-jhmjwqcg.js → cli-nme7wery.js} +6 -6
  49. package/dist/{cli-65q70v2v.js → cli-nrrg0fvy.js} +18 -4
  50. package/dist/{cli-8jtrekpy.js → cli-p1m2b6gc.js} +7 -7
  51. package/dist/{cli-re4wkbzx.js → cli-rg7ntypm.js} +328 -47
  52. package/dist/{cli-fp4xbw07.js → cli-rsd7ga7v.js} +10 -8
  53. package/dist/{cli-etvn5ej2.js → cli-sppc0cmw.js} +1 -1
  54. package/dist/{cli-qrwp40st.js → cli-tg9ksbn8.js} +1 -1
  55. package/dist/{cli-6p7ddg72.js → cli-tgvpmnwz.js} +2 -2
  56. package/dist/{cli-q1812jbw.js → cli-tj4j2ts4.js} +6 -6
  57. package/dist/{cli-kqypty34.js → cli-ttaz6c7m.js} +2 -2
  58. package/dist/{cli-w7z94e6c.js → cli-tx00c0h6.js} +4 -2
  59. package/dist/{cli-4g629sgr.js → cli-wrv09v7q.js} +20 -1
  60. package/dist/{cli-cby329ny.js → cli-wyrr38xm.js} +2 -2
  61. package/dist/{cli-y3dvz6ge.js → cli-x1p5dhq2.js} +3 -3
  62. package/dist/{cli-8qsx817b.js → cli-x719j3vs.js} +219 -629
  63. package/dist/{cli-9e9kjqsj.js → cli-xfe63zx3.js} +1 -1
  64. package/dist/{cli-wtg6edvd.js → cli-ywyrffff.js} +1 -1
  65. package/dist/{cli-0rh20bp3.js → cli-zvze9rbm.js} +1 -1
  66. package/dist/cli.js +14 -14
  67. package/dist/{codex-adapter-nhjj2veb.js → codex-adapter-pp2gq8gr.js} +3 -3
  68. package/dist/{codex-hook-x6tm6y5m.js → codex-hook-qwzccd64.js} +1 -1
  69. package/dist/{codex-session-runner-6hggrjbx.js → codex-session-runner-0vzn09t8.js} +3 -3
  70. package/dist/{commands-mrw1ph2w.js → commands-psqhkttb.js} +2 -2
  71. package/dist/{controller-pt1zam5w.js → controller-t20vz2k8.js} +2 -2
  72. package/dist/{controllers-connect-ymw5541d.js → controllers-connect-gkxmqw9d.js} +24 -20
  73. package/dist/{cursor-adapter-cf4zh5x0.js → cursor-adapter-3v542qe5.js} +1 -1
  74. package/dist/{db-hy80219q.js → db-2xbyenjr.js} +2 -2
  75. package/dist/{db-hhpy6m4x.js → db-nc1rd869.js} +3 -2
  76. package/dist/{dispatcher-6pdjtkr1.js → dispatcher-ewceb8ts.js} +17 -15
  77. package/dist/{dsh-adapter-fbx06re2.js → dsh-adapter-75xwh78t.js} +1 -1
  78. package/dist/{easter-egg-3d-6hg2r942.js → easter-egg-3d-xsc47jwf.js} +1 -1
  79. package/dist/{execute-bcqc69a5.js → execute-gzmw1mnw.js} +1 -1
  80. package/dist/{external-channel-j6vb6ya1.js → external-channel-a5dsmxn4.js} +2 -2
  81. package/dist/{google-generative-ai-phpmwxvg.js → google-generative-ai-bmq8gkf3.js} +1 -1
  82. package/dist/{google-vertex-es9ybgdy.js → google-vertex-b1rvp52s.js} +1 -1
  83. package/dist/{grok-adapter-1193sprp.js → grok-adapter-vj88xr23.js} +7 -7
  84. package/dist/handlers-zbs90bny.js +39 -0
  85. package/dist/{heartbeat-h1w1ktce.js → heartbeat-t2m9r3wa.js} +20 -18
  86. package/dist/{hook-skrbja18.js → hook-8femx1bg.js} +4 -4
  87. package/dist/{hook-ejja4bpe.js → hook-xa677f8r.js} +5 -5
  88. package/dist/{http-mzh41mfj.js → http-xpmmq028.js} +868 -253
  89. package/dist/{index-vjn3wbzf.js → index-8pwc1jc8.js} +17 -15
  90. package/dist/{index-epr2gnbw.js → index-cdzyfrsp.js} +1 -1
  91. package/dist/{index-xmmkyx82.js → index-dg2tmj99.js} +17 -15
  92. package/dist/index-nxa6me0q.js +41 -0
  93. package/dist/{index-6rmnn89d.js → index-s7ckdajq.js} +9 -9
  94. package/dist/{index-wgsw9xcz.js → index-syztqdt6.js} +1 -1
  95. package/dist/{index-x0q2a4f9.js → index-ysd45kgc.js} +1 -1
  96. package/dist/{index-g909y089.js → index-zgvqzjsw.js} +8 -8
  97. package/dist/{keepalive-4djvbm2j.js → keepalive-3nr4st3r.js} +3 -3
  98. package/dist/{lead-61kqp604.js → lead-td8h2sfn.js} +33 -31
  99. package/dist/{maintenance-f3xhnjsm.js → maintenance-verwpe2c.js} +1 -1
  100. package/dist/{oauth-refresh-sweep-fpd6x6rw.js → oauth-refresh-sweep-9q2t0y3q.js} +2 -2
  101. package/dist/{onboard-196tjgyn.js → onboard-aytqedmq.js} +2 -2
  102. package/dist/{opencode-adapter-eeesgfqk.js → opencode-adapter-f4hryjny.js} +4 -4
  103. package/dist/{otel-impl-g8fh4c21.js → otel-impl-hckw4wt1.js} +1 -1
  104. package/dist/{pi-mono-adapter-zasp3ze3.js → pi-mono-adapter-hxby0ce1.js} +6 -6
  105. package/dist/{pricing-refresh-sdcf5yaz.js → pricing-refresh-5nvme3sm.js} +3 -3
  106. package/dist/{rbac-roles-bsp5657v.js → rbac-roles-pd8c26m1.js} +5 -3
  107. package/dist/{rbac-roles-2x4g1wb5.js → rbac-roles-vbpy21mg.js} +2 -2
  108. package/dist/{render-v2-0pyb39bb.js → render-v2-7nqgvk2q.js} +3 -3
  109. package/dist/{resume-a86tkj6r.js → resume-b6djcj3c.js} +6 -6
  110. package/dist/{runtime-ar8310ba.js → runtime-txrxc9za.js} +1 -1
  111. package/dist/session-access-fc3f9y12.js +25 -0
  112. package/dist/{setup-ypbzcapd.js → setup-n39szm6b.js} +1 -1
  113. package/dist/{virtual-modules-wzk6jf3a.js → virtual-modules-wyp2k6z3.js} +2 -2
  114. package/dist/{work-objects-yjp8de12.js → work-objects-jem2fre0.js} +20 -18
  115. package/dist/{worker-4ptnn1ge.js → worker-wr6xgfr2.js} +33 -31
  116. package/openapi.json +844 -110
  117. package/package.json +1 -1
  118. package/src/apps/action-caller.ts +6 -0
  119. package/src/apps/script-types.ts +16 -3
  120. package/src/be/db/active-sessions.ts +5 -0
  121. package/src/be/db/session-visibility.ts +29 -0
  122. package/src/be/db/tasks/read.ts +61 -3
  123. package/src/be/db/tasks/write.ts +15 -6
  124. package/src/be/db.ts +92 -33
  125. package/src/be/events.ts +11 -0
  126. package/src/be/migrations/230_session_shares.sql +23 -0
  127. package/src/be/rbac-roles.ts +2 -0
  128. package/src/be/session-shares.ts +244 -0
  129. package/src/be/swarm-config-guard.ts +23 -2
  130. package/src/commands/runner.ts +11 -0
  131. package/src/http/active-sessions.ts +13 -2
  132. package/src/http/agents.ts +10 -3
  133. package/src/http/all-routes.ts +1 -0
  134. package/src/http/api-keys.ts +3 -1
  135. package/src/http/approval-requests.ts +2 -1
  136. package/src/http/apps.ts +36 -11
  137. package/src/http/config.ts +3 -0
  138. package/src/http/context.ts +2 -0
  139. package/src/http/core.ts +39 -2
  140. package/src/http/events.ts +6 -2
  141. package/src/http/favorite-owner.ts +1 -1
  142. package/src/http/fs.ts +38 -3
  143. package/src/http/index.ts +3 -1
  144. package/src/http/memory.ts +3 -1
  145. package/src/http/ranking.ts +367 -0
  146. package/src/http/realtime.ts +26 -21
  147. package/src/http/route-def.ts +77 -11
  148. package/src/http/script-runs.ts +2 -1
  149. package/src/http/scripts.ts +8 -0
  150. package/src/http/session-access.ts +179 -0
  151. package/src/http/session-data.ts +10 -2
  152. package/src/http/sessions.ts +212 -12
  153. package/src/http/stats.ts +7 -3
  154. package/src/http/tasks.ts +83 -7
  155. package/src/http/used-by.ts +11 -3
  156. package/src/prompts/session-templates.ts +3 -1
  157. package/src/providers/amp-adapter.ts +1 -1
  158. package/src/ranking/telemetry-ranking.ts +147 -0
  159. package/src/ranking/usage.ts +57 -0
  160. package/src/rbac/admission.ts +22 -7
  161. package/src/rbac/legacy-policy.ts +2 -0
  162. package/src/rbac/permissions.ts +9 -0
  163. package/src/realtime/auth.ts +69 -0
  164. package/src/realtime/tickets.ts +4 -1
  165. package/src/realtime/transport.ts +77 -9
  166. package/src/slack/blocks.ts +18 -0
  167. package/src/slack/dm.ts +29 -0
  168. package/src/telemetry-contract/EVENTS.md +3 -0
  169. package/src/telemetry-contract/SOURCE.json +37 -4
  170. package/src/telemetry-contract/catalog.json +69 -0
  171. package/src/telemetry-contract/ranking/fixtures/expected.json +30 -0
  172. package/src/telemetry-contract/ranking/fixtures/invalid/bad-category.json +11 -0
  173. package/src/telemetry-contract/ranking/fixtures/invalid/bad-claim.json +11 -0
  174. package/src/telemetry-contract/ranking/fixtures/invalid/blank-description.json +11 -0
  175. package/src/telemetry-contract/ranking/fixtures/invalid/blank-name.json +11 -0
  176. package/src/telemetry-contract/ranking/fixtures/invalid/description-too-long.json +11 -0
  177. package/src/telemetry-contract/ranking/fixtures/invalid/domain-uppercase.json +11 -0
  178. package/src/telemetry-contract/ranking/fixtures/invalid/domain-with-scheme.json +11 -0
  179. package/src/telemetry-contract/ranking/fixtures/invalid/domain-with-www.json +11 -0
  180. package/src/telemetry-contract/ranking/fixtures/invalid/http-source-url.json +11 -0
  181. package/src/telemetry-contract/ranking/fixtures/invalid/missing-description.json +10 -0
  182. package/src/telemetry-contract/ranking/fixtures/invalid/missing-version.json +10 -0
  183. package/src/telemetry-contract/ranking/fixtures/invalid/name-not-string.json +11 -0
  184. package/src/telemetry-contract/ranking/fixtures/invalid/name-too-long.json +11 -0
  185. package/src/telemetry-contract/ranking/fixtures/invalid/not-object.json +1 -0
  186. package/src/telemetry-contract/ranking/fixtures/invalid/null.json +1 -0
  187. package/src/telemetry-contract/ranking/fixtures/invalid/other-with-subcategory.json +11 -0
  188. package/src/telemetry-contract/ranking/fixtures/invalid/oversize.json +1 -0
  189. package/src/telemetry-contract/ranking/fixtures/invalid/short-claim.json +11 -0
  190. package/src/telemetry-contract/ranking/fixtures/invalid/subcategory-other-category.json +11 -0
  191. package/src/telemetry-contract/ranking/fixtures/invalid/trailing-data.json +1 -0
  192. package/src/telemetry-contract/ranking/fixtures/invalid/unknown-field.json +12 -0
  193. package/src/telemetry-contract/ranking/fixtures/invalid/unsupported-version.json +11 -0
  194. package/src/telemetry-contract/ranking/fixtures/invalid/updated-at-not-date.json +11 -0
  195. package/src/telemetry-contract/ranking/fixtures/invalid/updated-at-offset.json +11 -0
  196. package/src/telemetry-contract/ranking/fixtures/invalid/wrong-case-field.json +11 -0
  197. package/src/telemetry-contract/ranking/fixtures/valid/category-without-subcategory.json +11 -0
  198. package/src/telemetry-contract/ranking/fixtures/valid/full.json +11 -0
  199. package/src/telemetry-contract/ranking/fixtures/valid/minimal.json +11 -0
  200. package/src/telemetry-contract/ranking/fixtures/valid/padded-text.json +11 -0
  201. package/src/telemetry-contract/ranking/fixtures/valid/unicode-name.json +11 -0
  202. package/src/telemetry-contract/ranking/listing.v1.schema.json +61 -0
  203. package/src/telemetry-contract/ranking/taxonomy.json +8 -0
  204. package/src/telemetry-contract/ranking-taxonomy.gen.ts +11 -0
  205. package/src/telemetry-contract/types.gen.ts +708 -1
  206. package/src/telemetry.ts +26 -2
  207. package/src/tests/apps-rbac.test.ts +189 -2
  208. package/src/tests/apps-script-types.test.ts +16 -3
  209. package/src/tests/check-pr-body.test.ts +23 -0
  210. package/src/tests/check-ranking-entry.test.ts +146 -0
  211. package/src/tests/db-extraction-contract.test.ts +1 -0
  212. package/src/tests/db-task-read-contract.test.ts +1 -0
  213. package/src/tests/docs-index-footprint.test.js +2 -2
  214. package/src/tests/org-identity.test.ts +44 -0
  215. package/src/tests/ranking-listing.test.ts +112 -0
  216. package/src/tests/ranking-route.test.ts +319 -0
  217. package/src/tests/ranking-usage.test.ts +50 -0
  218. package/src/tests/rbac-admission-e2e.test.ts +8 -0
  219. package/src/tests/rbac-admission.test.ts +38 -0
  220. package/src/tests/rbac-charact-http.test.ts +4 -3
  221. package/src/tests/rbac-engine.test.ts +2 -0
  222. package/src/tests/rbac-roles.test.ts +2 -0
  223. package/src/tests/realtime-room-surfaces.test.ts +3 -1
  224. package/src/tests/realtime-session-join-race.test.ts +142 -0
  225. package/src/tests/realtime-tickets.test.ts +24 -17
  226. package/src/tests/realtime-transport.test.ts +91 -0
  227. package/src/tests/session-route-posture.test.ts +639 -0
  228. package/src/tests/session-sharing-routes.test.ts +282 -0
  229. package/src/tests/session-sharing.test.ts +526 -0
  230. package/src/tests/sessions-detail-batch.test.ts +7 -1
  231. package/src/tests/slack-tool-blocks.test.ts +101 -0
  232. package/src/tests/slack-update.test.ts +55 -0
  233. package/src/tests/slack-user-dm.test.ts +177 -0
  234. package/src/tests/used-by-route.test.ts +10 -0
  235. package/src/tools/slack-post.ts +18 -12
  236. package/src/tools/slack-read.ts +13 -1
  237. package/src/tools/slack-reply.ts +7 -10
  238. package/src/tools/slack-start-thread.ts +18 -11
  239. package/src/tools/slack-update.ts +2 -9
  240. package/src/types.ts +35 -0
  241. package/src/utils/org-identity.ts +33 -0
  242. package/templates/skills/apps/SKILL.md +17 -0
  243. package/templates/skills/apps/content.md +17 -0
  244. package/dist/handlers-tb3xgjnm.js +0 -37
  245. package/dist/index-nyfcdpky.js +0 -39
  246. package/dist/{cli-n5mrsg0f.js → cli-60cgh1rv.js} +3 -3
  247. /package/dist/{cli-j0v75y13.js → cli-y83zk5sb.js} +0 -0
@@ -69,28 +69,6 @@ import {
69
69
  resolveKvView,
70
70
  toolErr,
71
71
  createToolRegistrar,
72
- duplicateGuardedQueryKey,
73
- warnIfCorsAllowsAnyOrigin,
74
- isOriginAllowedForCredentials,
75
- allowedCredentialRedirect,
76
- setCorsHeaders,
77
- parseQueryParams,
78
- getPathSegments,
79
- wireHttpSpanLifecycle,
80
- safeRequestUrlForLog,
81
- agentWithCapacity,
82
- parseBody,
83
- BODY_TOO_LARGE,
84
- enforceContentLengthCap,
85
- json,
86
- jsonError,
87
- writeUnhandledError,
88
- triggerSchemaErrorResponse,
89
- deriveApiBaseUrl,
90
- httpServerSemconvAttributes,
91
- runtimeInstanceHeader,
92
- describeRequestRoute,
93
- route,
94
72
  handleMcpBridge,
95
73
  Redacted,
96
74
  SCRIPT_SDK_RESPONSE_LIMIT_BYTES,
@@ -199,9 +177,6 @@ import {
199
177
  scheduleIntegrationsReload,
200
178
  handleCore,
201
179
  userCtx,
202
- resolveTaskAuditUserId,
203
- resolveHttpAuditUserId,
204
- resolveHttpFavoriteOwner,
205
180
  handleApps,
206
181
  cancelApprovalRequest,
207
182
  getUserCommsPrefs,
@@ -262,6 +237,8 @@ import {
262
237
  resolveRoomNamespace,
263
238
  roomRequestInfo,
264
239
  authorizeRoomNamespace,
240
+ sessionAccessTopic,
241
+ sessionPresenceRoot,
265
242
  RoomOperationSchema,
266
243
  removeAwarenessStates,
267
244
  roomTopic,
@@ -303,7 +280,7 @@ import {
303
280
  hasCapability,
304
281
  getEnabledCapabilities,
305
282
  createServer
306
- } from "./cli-8qsx817b.js";
283
+ } from "./cli-x719j3vs.js";
307
284
  import {
308
285
  chatThreadOfContextKey,
309
286
  agentContextKey,
@@ -440,6 +417,17 @@ import {
440
417
  CHAT_SDK_ADAPTER_NAMES,
441
418
  isAdapterEntryEnabled,
442
419
  init_schema,
420
+ TELEMETRY_RANKING_KEY,
421
+ PUBLIC_RANKING_ENABLED_KEY,
422
+ RANKING_CATEGORIES,
423
+ readTelemetryRanking,
424
+ rankingFormSchema,
425
+ mintRankingClaim,
426
+ buildListing,
427
+ rankingEntryFile,
428
+ rankingPrUrl,
429
+ rankingLeaveUrl,
430
+ init_telemetry_ranking,
443
431
  API_DRAINING_HEADER,
444
432
  init_api_drain,
445
433
  parseTaskToolManifest,
@@ -724,26 +712,26 @@ import {
724
712
  countScriptRunJournalSteps2,
725
713
  countScriptRunJournalAgentTaskSteps2,
726
714
  init_db3
727
- } from "./cli-re4wkbzx.js";
715
+ } from "./cli-rg7ntypm.js";
728
716
  import {
729
717
  getUserGrant2,
730
718
  init_rbac_roles
731
- } from "./cli-6vcyw6v7.js";
732
- import"./cli-xgn4rwyv.js";
719
+ } from "./cli-5s5hx57y.js";
720
+ import"./cli-kk2r80n5.js";
733
721
  import {
734
722
  normalizeModelKey
735
- } from "./cli-qrwp40st.js";
723
+ } from "./cli-tg9ksbn8.js";
736
724
  import {
737
725
  upsertModelCatalogOverlay,
738
726
  deleteModelCatalogOverlay,
739
727
  loadModelsCatalog,
740
728
  requestModelCatalogRefresh2
741
- } from "./cli-kqypty34.js";
729
+ } from "./cli-ttaz6c7m.js";
742
730
  import {
743
731
  AMP_ESTIMATE_MODELS,
744
732
  ampBillsCacheWrites,
745
733
  resolveAmpModel
746
- } from "./cli-fhvqt2fp.js";
734
+ } from "./cli-2rwet3r7.js";
747
735
  import {
748
736
  automationIntegrationFixUrl,
749
737
  preflightAutomation,
@@ -755,7 +743,7 @@ import {
755
743
  cancelWorkflowRun2,
756
744
  TriggerSchemaError,
757
745
  startWorkflowExecution2
758
- } from "./cli-jhmjwqcg.js";
746
+ } from "./cli-nme7wery.js";
759
747
  import {
760
748
  require_dist2,
761
749
  isInvalidClientError,
@@ -835,14 +823,14 @@ import {
835
823
  typecheckWithAmbient,
836
824
  typecheckScript,
837
825
  parseSkillContent
838
- } from "./cli-65q70v2v.js";
826
+ } from "./cli-nrrg0fvy.js";
839
827
  import {
840
828
  buildAuthorizationUrl,
841
829
  exchangeAuthorizationCode,
842
830
  oauthAppRowToProviderConfig,
843
831
  forceRefreshAuthorizationOrThrow,
844
832
  forceRefreshTokenOrThrow
845
- } from "./cli-g6p7c2my.js";
833
+ } from "./cli-b80a1100.js";
846
834
  import {
847
835
  signalProcessGroup,
848
836
  detachedProcessGroup,
@@ -870,15 +858,15 @@ import {
870
858
  getSlackApp2,
871
859
  startSlackApp2,
872
860
  stopSlackApp2
873
- } from "./cli-dxwh4j32.js";
874
- import"./cli-9e9kjqsj.js";
861
+ } from "./cli-4fhyq711.js";
862
+ import"./cli-xfe63zx3.js";
875
863
  import {
876
864
  createApprovalFollowUpTask,
877
865
  generateEdges,
878
866
  definitionNodeIds,
879
867
  validateDefinition
880
- } from "./cli-q1812jbw.js";
881
- import"./cli-8cvvytad.js";
868
+ } from "./cli-tj4j2ts4.js";
869
+ import"./cli-bn26xbcs.js";
882
870
  import {
883
871
  _fetchHolder,
884
872
  CLIENT_ID,
@@ -894,6 +882,48 @@ import {
894
882
  workflowEventBus2,
895
883
  init_event_bus
896
884
  } from "./cli-ptkpaqfy.js";
885
+ import {
886
+ duplicateGuardedQueryKey,
887
+ warnIfCorsAllowsAnyOrigin,
888
+ isOriginAllowedForCredentials,
889
+ allowedCredentialRedirect,
890
+ setCorsHeaders,
891
+ parseQueryParams,
892
+ getPathSegments,
893
+ wireHttpSpanLifecycle,
894
+ safeRequestUrlForLog,
895
+ agentWithCapacity,
896
+ parseBody,
897
+ BODY_TOO_LARGE,
898
+ enforceContentLengthCap,
899
+ json,
900
+ jsonError,
901
+ writeUnhandledError,
902
+ triggerSchemaErrorResponse,
903
+ deriveApiBaseUrl,
904
+ httpServerSemconvAttributes,
905
+ hasSessionAccess,
906
+ getSessionRoot,
907
+ sessionAccessForRoot,
908
+ listActiveSessionShares,
909
+ toSessionSharesState,
910
+ setSessionShares,
911
+ resolveTaskAuditUserId,
912
+ resolveHttpAuditUserId,
913
+ dashboardUserIdHeader,
914
+ resolveHttpFavoriteOwner,
915
+ resolveSessionActor2,
916
+ sessionAccessFor2,
917
+ SESSION_READ_DENIED2,
918
+ canReadSession2,
919
+ readableByFor2,
920
+ SESSION_WRITE_DENIED2,
921
+ runtimeInstanceHeader,
922
+ bodyTask,
923
+ bodyListTask,
924
+ describeRequestRoute,
925
+ route
926
+ } from "./cli-02vhhssk.js";
897
927
  import {
898
928
  isMultiRuntimeEnabled
899
929
  } from "./cli-7a91w22y.js";
@@ -906,24 +936,6 @@ import {
906
936
  } from "./cli-qje9k2nh.js";
907
937
  import {
908
938
  RuntimePoolError2,
909
- registerSessionTokenConnection,
910
- init_session_token_connections,
911
- findUserById,
912
- getUserIdentities,
913
- listUserEvents,
914
- listUserTokens,
915
- recordIdentityEvent,
916
- linkIdentity,
917
- unlinkIdentity,
918
- mintToken,
919
- revokeToken,
920
- resolveUserByToken,
921
- InvalidRuntimeTokenError,
922
- mintSessionToken,
923
- mintRuntimeToken,
924
- revokeSessionToken,
925
- fingerprintApiKey,
926
- init_users,
927
939
  mintControllerToken,
928
940
  init_tokens,
929
941
  listRuntimeControllers2,
@@ -942,7 +954,7 @@ import {
942
954
  resolvePoolDelivery2,
943
955
  createPoolAgent2,
944
956
  init_db
945
- } from "./cli-hz64bcnj.js";
957
+ } from "./cli-6ftrrwm1.js";
946
958
  import {
947
959
  RATING_MODEL_MAX_LENGTH,
948
960
  REFERENCES_SOURCE_MAX_LENGTH,
@@ -958,8 +970,8 @@ import {
958
970
  checkHeartbeatChecklist2,
959
971
  runHeartbeatSweep2,
960
972
  stopHeartbeat2
961
- } from "./cli-ka01m5rb.js";
962
- import"./cli-d43xqzbe.js";
973
+ } from "./cli-bhwa8rzc.js";
974
+ import"./cli-eqgfs202.js";
963
975
  import {
964
976
  import_websocket,
965
977
  import_websocket_server
@@ -968,7 +980,7 @@ import {
968
980
  runtimeSupervisorStatus,
969
981
  startRuntimeSupervisor,
970
982
  stopRuntimeSupervisor
971
- } from "./cli-fp4xbw07.js";
983
+ } from "./cli-rsd7ga7v.js";
972
984
  import"./cli-ns59dc6r.js";
973
985
  import {
974
986
  ACP_TARGET_IDS
@@ -980,20 +992,22 @@ import {
980
992
  import {
981
993
  MAX_RATE_LIMIT_RESET_MS
982
994
  } from "./cli-gx4rm0qx.js";
983
- import {
984
- inviteEmailToSharedOrg,
985
- ensureAgentFsCredentialsForAgent
986
- } from "./cli-yv3n83x8.js";
987
- import {
988
- Anthropic
989
- } from "./cli-er83cjbn.js";
990
995
  import {
991
996
  isLeadChannelMonitoringEnabled,
997
+ ORG_IDENTITY_KEYS,
998
+ orgIdentityStatus,
992
999
  SIMILARITY_THRESHOLD,
993
1000
  memoryRelevance,
994
1001
  isUnknownModelError,
995
1002
  writeSkillsToFilesystem
996
- } from "./cli-4g629sgr.js";
1003
+ } from "./cli-wrv09v7q.js";
1004
+ import {
1005
+ inviteEmailToSharedOrg,
1006
+ ensureAgentFsCredentialsForAgent
1007
+ } from "./cli-5ff2sjyt.js";
1008
+ import {
1009
+ Anthropic
1010
+ } from "./cli-er83cjbn.js";
997
1011
  import {
998
1012
  isCodexOAuthConfigKey
999
1013
  } from "./cli-j4bwnpkm.js";
@@ -1005,7 +1019,27 @@ import"./cli-13p25grh.js";
1005
1019
  import"./cli-0adyhvq2.js";
1006
1020
  import {
1007
1021
  require_content_type
1008
- } from "./cli-gzvb3d4a.js";
1022
+ } from "./cli-1jx0srjt.js";
1023
+ import {
1024
+ registerSessionTokenConnection,
1025
+ init_session_token_connections,
1026
+ findUserById,
1027
+ getUserIdentities,
1028
+ listUserEvents,
1029
+ listUserTokens,
1030
+ recordIdentityEvent,
1031
+ linkIdentity,
1032
+ unlinkIdentity,
1033
+ mintToken,
1034
+ revokeToken,
1035
+ resolveUserByToken,
1036
+ InvalidRuntimeTokenError,
1037
+ mintSessionToken,
1038
+ mintRuntimeToken,
1039
+ revokeSessionToken,
1040
+ fingerprintApiKey,
1041
+ init_users
1042
+ } from "./cli-8cxkw1f5.js";
1009
1043
  import"./cli-v41kn3cd.js";
1010
1044
  import"./cli-wgtk7xxr.js";
1011
1045
  import {
@@ -1019,7 +1053,7 @@ import {
1019
1053
  clearAuditSink,
1020
1054
  can,
1021
1055
  init_rbac
1022
- } from "./cli-zj4d6afs.js";
1056
+ } from "./cli-1pa3rz69.js";
1023
1057
  import {
1024
1058
  isSafeBundlePath,
1025
1059
  init_bundle_path,
@@ -1039,6 +1073,10 @@ import {
1039
1073
  ProviderNameSchema,
1040
1074
  ModelProfileNameSchema,
1041
1075
  ModelProfileSchema,
1076
+ SessionAccessSchema,
1077
+ SessionOwnerSchema,
1078
+ SessionSharesSchema,
1079
+ SessionSharesUpdateSchema,
1042
1080
  SteerModeSchema,
1043
1081
  SteeringSourceSchema,
1044
1082
  SteeringMessageSchema,
@@ -1156,12 +1194,12 @@ import {
1156
1194
  KvKeySchema,
1157
1195
  KvEntrySchema,
1158
1196
  init_types
1159
- } from "./cli-yv0vgscc.js";
1197
+ } from "./cli-a1esmmee.js";
1160
1198
  import {
1161
1199
  IDENTITY_FIELD_BUDGETS,
1162
1200
  IdentityFieldBudgetError,
1163
1201
  init_identity_field_budget
1164
- } from "./cli-cby329ny.js";
1202
+ } from "./cli-wyrr38xm.js";
1165
1203
  import {
1166
1204
  getSlackConfiguration,
1167
1205
  init_config
@@ -1179,7 +1217,7 @@ import {
1179
1217
  resolveTemplate,
1180
1218
  init_resolver,
1181
1219
  init_session_templates
1182
- } from "./cli-w7z94e6c.js";
1220
+ } from "./cli-tx00c0h6.js";
1183
1221
  import {
1184
1222
  MODEL_SCOPED_WINDOWS,
1185
1223
  activeModelBlocks,
@@ -1201,6 +1239,7 @@ import {
1201
1239
  import {
1202
1240
  NEVER,
1203
1241
  toJSONSchema,
1242
+ ZodError,
1204
1243
  string2,
1205
1244
  email,
1206
1245
  uuid,
@@ -1228,7 +1267,7 @@ import {
1228
1267
  import {
1229
1268
  init_package,
1230
1269
  package_default
1231
- } from "./cli-5d1m1qca.js";
1270
+ } from "./cli-mz1ezzzh.js";
1232
1271
  import {
1233
1272
  realtimeBus,
1234
1273
  init_bus
@@ -2367,7 +2406,8 @@ function identityFromHttpAuth(req, auth) {
2367
2406
  agentId,
2368
2407
  sourceTaskId: auth.kind === "agent" ? auth.taskId ?? undefined : header(req, "x-source-task-id"),
2369
2408
  userId: auth.kind === "user" ? auth.userId : undefined,
2370
- isOperator: auth.kind === "operator"
2409
+ isOperator: auth.kind === "operator",
2410
+ dashboardUserId: auth.kind === "operator" ? auth.dashboardUserId : undefined
2371
2411
  },
2372
2412
  me: {
2373
2413
  userId: auth.kind === "user" ? auth.userId : agentId ?? guestId,
@@ -2560,6 +2600,9 @@ function connect(ws, auth, runtimeId) {
2560
2600
  if (namespace.startsWith("presence:comb:") && msg.name !== "default") {
2561
2601
  throw new Error("Comb presence uses the default room");
2562
2602
  }
2603
+ if (namespace.startsWith("presence:session:") && msg.name !== "default") {
2604
+ throw new Error("Session presence uses the default room");
2605
+ }
2563
2606
  const denied = await authorizeRoomNamespace(namespace, auth.identity, msg.op, msg.name);
2564
2607
  if (denied)
2565
2608
  throw new Error(typeof denied === "string" ? denied : "Forbidden");
@@ -2600,7 +2643,7 @@ function connect(ws, auth, runtimeId) {
2600
2643
  } catch (error) {
2601
2644
  if (!(error instanceof Error) || error.message !== "room does not exist")
2602
2645
  throw error;
2603
- const creationDenied = await authorizeRoomNamespace(namespace, auth.identity, namespace.startsWith("presence:comb:") ? "join" : true);
2646
+ const creationDenied = await authorizeRoomNamespace(namespace, auth.identity, namespace.startsWith("presence:comb:") || namespace.startsWith("presence:session:") ? "join" : true);
2604
2647
  if (creationDenied)
2605
2648
  throw new Error(creationDenied);
2606
2649
  if (closed)
@@ -2610,6 +2653,8 @@ function connect(ws, auth, runtimeId) {
2610
2653
  if (closed)
2611
2654
  return;
2612
2655
  const stopRoom = realtimeBus.subscribe(key, (event) => {
2656
+ if (rooms.get(key)?.suspended)
2657
+ return;
2613
2658
  const view = event;
2614
2659
  const type = view.type;
2615
2660
  if (type === "deleted") {
@@ -2631,15 +2676,62 @@ function connect(ws, auth, runtimeId) {
2631
2676
  }).catch(() => ws.close(1011, "Room reset failed"));
2632
2677
  }
2633
2678
  });
2634
- const stopPresence = realtimeBus.subscribe(`presence:${key}`, (peers) => send({ type: "presence", name: msg.name, namespace, peers }));
2679
+ const stopPresence = realtimeBus.subscribe(`presence:${key}`, (peers) => {
2680
+ if (rooms.get(key)?.suspended)
2681
+ return;
2682
+ send({ type: "presence", name: msg.name, namespace, peers });
2683
+ });
2684
+ const sessionRoot = sessionPresenceRoot(namespace);
2685
+ let accessCheck = 0;
2686
+ const stopAccess = sessionRoot ? realtimeBus.subscribe(sessionAccessTopic(sessionRoot), () => {
2687
+ const joined = rooms.get(key);
2688
+ if (!joined)
2689
+ return;
2690
+ joined.suspended = true;
2691
+ const check = ++accessCheck;
2692
+ authorizeRoomNamespace(namespace, auth.identity, "join").catch(() => "Session access check failed").then((denied) => {
2693
+ const current = rooms.get(key);
2694
+ if (closed || !current || check !== accessCheck)
2695
+ return;
2696
+ if (denied) {
2697
+ leave(key);
2698
+ send({ type: "error", name: msg.name, namespace, error: denied });
2699
+ return;
2700
+ }
2701
+ current.suspended = false;
2702
+ send({
2703
+ type: "presence",
2704
+ name: msg.name,
2705
+ namespace,
2706
+ peers: [...current.room.awareness.getStates().values()]
2707
+ });
2708
+ });
2709
+ }) : undefined;
2635
2710
  rooms.set(key, {
2636
2711
  room,
2637
2712
  version: msg.schemaVersion,
2638
2713
  stop: () => {
2639
2714
  stopRoom();
2640
2715
  stopPresence();
2641
- }
2716
+ stopAccess?.();
2717
+ },
2718
+ suspended: sessionRoot !== undefined
2642
2719
  });
2720
+ if (sessionRoot) {
2721
+ const check = ++accessCheck;
2722
+ const denied = await authorizeRoomNamespace(namespace, auth.identity, "join").catch(() => "Session access check failed");
2723
+ if (closed)
2724
+ return;
2725
+ if (denied) {
2726
+ leave(key);
2727
+ throw new Error(denied);
2728
+ }
2729
+ const current = rooms.get(key);
2730
+ if (!current)
2731
+ throw new Error("You don't have access to this session");
2732
+ if (check === accessCheck)
2733
+ current.suspended = false;
2734
+ }
2643
2735
  room.awareness.states.set(clientId, { ...auth.me, data: {} });
2644
2736
  room.awareness.meta.set(clientId, { clock: 1, lastUpdated: Date.now() });
2645
2737
  publishPresence(room);
@@ -3863,6 +3955,7 @@ var createActiveSession = route({
3863
3955
  method: "post",
3864
3956
  path: "/api/active-sessions",
3865
3957
  pattern: ["api", "active-sessions"],
3958
+ session: bodyTask("taskId"),
3866
3959
  summary: "Create a new active session",
3867
3960
  tags: ["Active Sessions"],
3868
3961
  body: object2({
@@ -3883,6 +3976,7 @@ var deleteSessionByTask = route({
3883
3976
  method: "delete",
3884
3977
  path: "/api/active-sessions/by-task/{taskId}",
3885
3978
  pattern: ["api", "active-sessions", "by-task", null],
3979
+ session: { taskParam: "taskId" },
3886
3980
  summary: "Delete active session by task ID",
3887
3981
  tags: ["Active Sessions"],
3888
3982
  params: object2({ taskId: string2() }),
@@ -3894,6 +3988,7 @@ var deleteSessionById = route({
3894
3988
  method: "delete",
3895
3989
  path: "/api/active-sessions/{id}",
3896
3990
  pattern: ["api", "active-sessions", null],
3991
+ session: { activeSessionParam: "id" },
3897
3992
  summary: "Delete active session by ID",
3898
3993
  tags: ["Active Sessions"],
3899
3994
  params: object2({ id: string2() }),
@@ -3905,6 +4000,7 @@ var heartbeatSession = route({
3905
4000
  method: "put",
3906
4001
  path: "/api/active-sessions/heartbeat/{taskId}",
3907
4002
  pattern: ["api", "active-sessions", "heartbeat", null],
4003
+ session: { taskParam: "taskId" },
3908
4004
  summary: "Update heartbeat for an active session",
3909
4005
  tags: ["Active Sessions"],
3910
4006
  params: object2({ taskId: string2() }),
@@ -3916,6 +4012,7 @@ var updateProviderSession = route({
3916
4012
  method: "put",
3917
4013
  path: "/api/active-sessions/provider-session/{taskId}",
3918
4014
  pattern: ["api", "active-sessions", "provider-session", null],
4015
+ session: { taskParam: "taskId" },
3919
4016
  summary: "Update provider session ID on an active session",
3920
4017
  tags: ["Active Sessions"],
3921
4018
  params: object2({ taskId: string2() }),
@@ -3928,6 +4025,7 @@ var cleanupSessions = route({
3928
4025
  method: "post",
3929
4026
  path: "/api/active-sessions/cleanup",
3930
4027
  pattern: ["api", "active-sessions", "cleanup"],
4028
+ session: { agentWide: "Deletes every session of an agent, or every stale session." },
3931
4029
  summary: "Clean up stale sessions",
3932
4030
  tags: ["Active Sessions"],
3933
4031
  body: object2({
@@ -3942,6 +4040,7 @@ var recoverOrphanedTasks = route({
3942
4040
  method: "post",
3943
4041
  path: "/api/active-sessions/recover-orphaned-tasks",
3944
4042
  pattern: ["api", "active-sessions", "recover-orphaned-tasks"],
4043
+ session: { none: "Its handler admits only the calling agent, never a user." },
3945
4044
  summary: "Recover orphaned in-progress tasks for an agent",
3946
4045
  tags: ["Active Sessions"],
3947
4046
  body: object2({
@@ -3961,7 +4060,7 @@ async function handleActiveSessions(req, res, pathSegments, queryParams, myAgent
3961
4060
  const parsed = await listActiveSessions.parse(req, res, pathSegments, queryParams);
3962
4061
  if (!parsed)
3963
4062
  return true;
3964
- const sessions = await getActiveSessions2(parsed.query.agentId || undefined);
4063
+ const sessions = await getActiveSessions2(parsed.query.agentId || undefined, readableByFor2(await resolveSessionActor2(req, myAgentId)));
3965
4064
  listActiveSessions.respond(res, 200, { sessions });
3966
4065
  return true;
3967
4066
  }
@@ -4610,14 +4709,17 @@ async function handleAgentRegister(req, res, pathSegments, myAgentId) {
4610
4709
  }
4611
4710
  return false;
4612
4711
  }
4613
- async function handleAgentsRest(req, res, pathSegments, queryParams, _myAgentId) {
4712
+ async function handleAgentsRest(req, res, pathSegments, queryParams, myAgentId) {
4614
4713
  if (listAgents.match(req.method, pathSegments)) {
4615
4714
  const parsed = await listAgents.parse(req, res, pathSegments, queryParams);
4616
4715
  if (!parsed)
4617
4716
  return true;
4618
4717
  const includeTasks = parsed.query.include === "tasks";
4619
4718
  const slim = parsed.query.fields !== "full";
4620
- const agents = includeTasks ? await getAllAgentsWithTasks2({ slim }) : await getAllAgents2({ slim });
4719
+ const agents = includeTasks ? await getAllAgentsWithTasks2({
4720
+ slim,
4721
+ readableBy: readableByFor2(await resolveSessionActor2(req, myAgentId))
4722
+ }) : await getAllAgents2({ slim });
4621
4723
  const [agentsWithCapacity, transports] = await Promise.all([
4622
4724
  Promise.all(agents.map(agentWithCapacity)),
4623
4725
  resolveListClaudeTransports(agents)
@@ -5155,7 +5257,7 @@ async function handleAgentsRest(req, res, pathSegments, queryParams, _myAgentId)
5155
5257
  if (!parsed)
5156
5258
  return true;
5157
5259
  const includeTasks = parsed.query.include === "tasks";
5158
- const agent = includeTasks ? await getAgentWithTasks2(parsed.params.id) : await getAgentById2(parsed.params.id);
5260
+ const agent = includeTasks ? await getAgentWithTasks2(parsed.params.id, readableByFor2(await resolveSessionActor2(req, myAgentId))) : await getAgentById2(parsed.params.id);
5159
5261
  if (!agent) {
5160
5262
  jsonError(res, "Agent not found", 404);
5161
5263
  return true;
@@ -5234,6 +5336,7 @@ var reportUsage = route({
5234
5336
  method: "post",
5235
5337
  path: "/api/keys/report-usage",
5236
5338
  pattern: ["api", "keys", "report-usage"],
5339
+ session: bodyTask("taskId"),
5237
5340
  summary: "Record which API key was used for a task",
5238
5341
  tags: ["API Keys"],
5239
5342
  body: object2({
@@ -5277,6 +5380,7 @@ var reportAuthFailure = route({
5277
5380
  method: "post",
5278
5381
  path: "/api/keys/report-auth-failure",
5279
5382
  pattern: ["api", "keys", "report-auth-failure"],
5383
+ session: bodyTask("taskId"),
5280
5384
  summary: "Record an auth failure for a pooled key; bench it after 2 in a row",
5281
5385
  tags: ["API Keys"],
5282
5386
  body: object2({
@@ -5974,6 +6078,7 @@ var createRoute = route({
5974
6078
  method: "post",
5975
6079
  path: "/api/approval-requests",
5976
6080
  pattern: ["api", "approval-requests"],
6081
+ session: bodyTask("sourceTaskId"),
5977
6082
  summary: "Create a new approval request",
5978
6083
  tags: ["ApprovalRequests"],
5979
6084
  body: object2({
@@ -7590,6 +7695,396 @@ init_rbac();
7590
7695
  init_types();
7591
7696
  init_request_auth_context();
7592
7697
  init_secret_scrubber();
7698
+
7699
+ // src/http/ranking.ts
7700
+ init_zod();
7701
+ init_db3();
7702
+ init_telemetry_ranking();
7703
+ init_telemetry();
7704
+ init_env_flag();
7705
+
7706
+ // src/http/used-by.ts
7707
+ init_zod();
7708
+ init_db3();
7709
+ init_telemetry();
7710
+ init_org_website();
7711
+ var CONSENT_KEY = "SWARM_USED_BY_CONSENT";
7712
+ var CONSENT_AT_KEY = "SWARM_USED_BY_CONSENT_AT";
7713
+ var GRANTED_NAME_KEY = "SWARM_USED_BY_ORG_NAME";
7714
+ var GRANTED_WEBSITE_KEY = "SWARM_USED_BY_ORG_WEBSITE";
7715
+ var TIMEOUT_MS = 1e4;
7716
+ var usedBy = route({
7717
+ method: "post",
7718
+ path: "/api/used-by",
7719
+ pattern: ["api", "used-by"],
7720
+ summary: "Grant or revoke the 'used by' logo consent",
7721
+ description: "Records whether agent-swarm.dev may show this organization's logo as a company that uses Agent Swarm. Sends the organization name and website to the telemetry proxy, where a person approves each logo by hand. An explicit admin action, so it is not gated by the telemetry opt-out.",
7722
+ tags: ["Telemetry"],
7723
+ body: object2({ granted: boolean() }),
7724
+ responses: {
7725
+ 200: {
7726
+ description: "Consent recorded",
7727
+ schema: object2({ granted: boolean(), changedAt: string2() })
7728
+ },
7729
+ 400: {
7730
+ description: "Organization name or website is not set (a revoke falls back to the identity of the last grant)"
7731
+ },
7732
+ 401: { description: "Unauthorized" },
7733
+ 403: { description: "Only a config admin can change the consent" },
7734
+ 502: { description: "The telemetry proxy did not accept the consent" }
7735
+ },
7736
+ rbac: { permission: "config.write.any" }
7737
+ });
7738
+ async function globalConfig(key) {
7739
+ const stored = (await getSwarmConfigs2({ scope: "global", key }))?.[0]?.value?.trim();
7740
+ return stored || process.env[key]?.trim() || undefined;
7741
+ }
7742
+ async function telemetryProxyEndpoint(path) {
7743
+ const feedback = await globalConfig("feedback_endpoint");
7744
+ if (feedback && /^https?:\/\/[^/]+\/v1\/feedback\/?$/.test(feedback)) {
7745
+ return feedback.replace(/\/v1\/feedback\/?$/, path);
7746
+ }
7747
+ return `${TELEMETRY_PROXY_ORIGIN}${path}`;
7748
+ }
7749
+ function usedByEndpoint() {
7750
+ return telemetryProxyEndpoint("/v1/used-by");
7751
+ }
7752
+ async function handleUsedBy(req, res, pathSegments, queryParams, myAgentId) {
7753
+ if (!usedBy.match(req.method, pathSegments))
7754
+ return false;
7755
+ const parsed = await usedBy.parse(req, res, pathSegments, queryParams);
7756
+ if (!parsed)
7757
+ return true;
7758
+ if (!await ensureConfigAdmin(req, res, "config.write.any"))
7759
+ return true;
7760
+ const { granted } = parsed.body;
7761
+ const current = orgIdentityStatus({
7762
+ SWARM_ORG_NAME: await globalConfig("SWARM_ORG_NAME"),
7763
+ SWARM_ORG_WEBSITE: await globalConfig("SWARM_ORG_WEBSITE")
7764
+ });
7765
+ const currentName = current.name ?? undefined;
7766
+ const currentWebsite = current.website;
7767
+ const grantedName = granted ? undefined : await globalConfig(GRANTED_NAME_KEY);
7768
+ const grantedWebsite = granted ? null : normalizeOrgWebsite(await globalConfig(GRANTED_WEBSITE_KEY));
7769
+ const [orgName, orgWebsite] = grantedName && grantedWebsite ? [grantedName, grantedWebsite] : [currentName, currentWebsite];
7770
+ if (!orgName || !orgWebsite) {
7771
+ jsonError(res, "Set the organization name and website first", 400);
7772
+ return true;
7773
+ }
7774
+ const installId = isTelemetryEnabled() ? await globalConfig("telemetry_installation_id") : undefined;
7775
+ const orgDomain = await globalConfig("telemetry_org_domain");
7776
+ const changedAt = new Date().toISOString();
7777
+ try {
7778
+ const response = await fetch(await usedByEndpoint(), {
7779
+ method: "POST",
7780
+ headers: { "Content-Type": "application/json" },
7781
+ body: JSON.stringify({
7782
+ ...installId ? { install_id: installId } : {},
7783
+ org_name: orgName,
7784
+ org_website: orgWebsite,
7785
+ ...orgDomain ? { org_domain: orgDomain } : {},
7786
+ granted,
7787
+ changed_at: changedAt
7788
+ }),
7789
+ signal: AbortSignal.timeout(TIMEOUT_MS)
7790
+ });
7791
+ if (!response.ok) {
7792
+ jsonError(res, `The telemetry proxy answered ${response.status}`, 502);
7793
+ return true;
7794
+ }
7795
+ } catch {
7796
+ jsonError(res, "Could not reach the telemetry proxy", 502);
7797
+ return true;
7798
+ }
7799
+ await upsertSwarmConfig2({ scope: "global", key: CONSENT_KEY, value: String(granted) });
7800
+ await upsertSwarmConfig2({ scope: "global", key: CONSENT_AT_KEY, value: changedAt });
7801
+ if (granted) {
7802
+ await upsertSwarmConfig2({ scope: "global", key: GRANTED_NAME_KEY, value: orgName });
7803
+ await upsertSwarmConfig2({ scope: "global", key: GRANTED_WEBSITE_KEY, value: orgWebsite });
7804
+ }
7805
+ scheduleIntegrationsReload();
7806
+ const owner = await resolveHttpFavoriteOwner(req, myAgentId);
7807
+ trackRelayed("used_by.consent_changed", { granted }, { actor: owner?.userId ? { userId: owner.userId } : undefined, emitter: "ui" });
7808
+ usedBy.respond(res, 200, { granted, changedAt });
7809
+ return true;
7810
+ }
7811
+
7812
+ // src/http/ranking.ts
7813
+ var ListingSchema = object2({
7814
+ v: literal2(1),
7815
+ claim: string2(),
7816
+ name: string2(),
7817
+ domain: string2(),
7818
+ category: _enum2(RANKING_CATEGORIES),
7819
+ subcategory: string2().nullable(),
7820
+ description: string2().nullable(),
7821
+ sourceCodeUrl: string2().nullable(),
7822
+ updatedAt: string2()
7823
+ });
7824
+ var RankingStateSchema = object2({
7825
+ eligible: boolean(),
7826
+ missing: array2(_enum2(ORG_IDENTITY_KEYS)),
7827
+ telemetryOn: boolean(),
7828
+ enabled: boolean(),
7829
+ name: string2().nullable(),
7830
+ domain: string2().nullable(),
7831
+ listing: ListingSchema.nullable(),
7832
+ listingMatchesDomain: boolean(),
7833
+ fileJson: string2().nullable(),
7834
+ prUrl: string2().nullable(),
7835
+ verifyUrl: string2().nullable()
7836
+ });
7837
+ var OptInResponseSchema = object2({
7838
+ domain: string2(),
7839
+ claim: string2(),
7840
+ listing: ListingSchema,
7841
+ fileJson: string2(),
7842
+ prUrl: string2(),
7843
+ verifyUrl: string2()
7844
+ });
7845
+ var OptOutResponseSchema = object2({
7846
+ enabled: literal2(false),
7847
+ leaveUrl: string2().nullable()
7848
+ });
7849
+ var getRanking = route({
7850
+ method: "get",
7851
+ path: "/api/ranking",
7852
+ pattern: ["api", "ranking"],
7853
+ summary: "Public ranking state",
7854
+ description: "Whether this install can join the public agent-swarm.dev ranking (telemetry on, organization name and website set), whether it is opted in, and its stored listing. The listing carries the private ranking claim, so only a config admin can read it.",
7855
+ tags: ["Telemetry"],
7856
+ responses: {
7857
+ 200: { description: "Ranking state", schema: RankingStateSchema },
7858
+ 401: { description: "Unauthorized" },
7859
+ 403: { description: "Only a config admin can read the ranking state" }
7860
+ },
7861
+ rbac: { permission: "config.write.any" }
7862
+ });
7863
+ var optIn = route({
7864
+ method: "post",
7865
+ path: "/api/ranking/opt-in",
7866
+ pattern: ["api", "ranking", "opt-in"],
7867
+ summary: "Opt this install into the public ranking",
7868
+ description: "Builds the telemetry_ranking listing from the organization name and website plus the chosen category, stores it, turns PUBLIC_RANKING_ENABLED on and sends ranking.opted_in. The install is ranked only after a ranking PR with the returned file is merged into desplega-ai/agent-swarm.",
7869
+ tags: ["Telemetry"],
7870
+ body: rankingFormSchema,
7871
+ responses: {
7872
+ 200: { description: "Opted in", schema: OptInResponseSchema },
7873
+ 400: { description: "A listing field is invalid" },
7874
+ 401: { description: "Unauthorized" },
7875
+ 403: { description: "Only a config admin can opt in" },
7876
+ 409: {
7877
+ description: "telemetry_off: telemetry is off or the install has no ID. org_identity_missing: the organization name or website is not set (`missing` lists which)."
7878
+ }
7879
+ },
7880
+ rbac: { permission: "config.write.any" }
7881
+ });
7882
+ var optOut = route({
7883
+ method: "post",
7884
+ path: "/api/ranking/opt-out",
7885
+ pattern: ["api", "ranking", "opt-out"],
7886
+ summary: "Leave the public ranking",
7887
+ description: "Turns PUBLIC_RANKING_ENABLED off and sends ranking.opted_out, so workers stop sending ranking.usage. Returns the GitHub page that deletes the ranking entry.",
7888
+ tags: ["Telemetry"],
7889
+ responses: {
7890
+ 200: { description: "Opted out", schema: OptOutResponseSchema },
7891
+ 401: { description: "Unauthorized" },
7892
+ 403: { description: "Only a config admin can opt out" }
7893
+ },
7894
+ rbac: { permission: "config.write.any" }
7895
+ });
7896
+ var RANKING_CONFIG_KEYS = new Set([...ORG_IDENTITY_KEYS, PUBLIC_RANKING_ENABLED_KEY]);
7897
+ async function currentIdentity(changed) {
7898
+ const read = async (key) => changed?.key === key ? changed.value : await globalConfig(key);
7899
+ return orgIdentityStatus({
7900
+ SWARM_ORG_NAME: await read("SWARM_ORG_NAME"),
7901
+ SWARM_ORG_WEBSITE: await read("SWARM_ORG_WEBSITE")
7902
+ });
7903
+ }
7904
+ async function storedListing() {
7905
+ return readTelemetryRanking(await globalConfig(TELEMETRY_RANKING_KEY));
7906
+ }
7907
+ async function rankingEnabled() {
7908
+ const raw = await globalConfig(PUBLIC_RANKING_ENABLED_KEY);
7909
+ return isEnvFlagEnabled(PUBLIC_RANKING_ENABLED_KEY, false, {
7910
+ [PUBLIC_RANKING_ENABLED_KEY]: raw
7911
+ });
7912
+ }
7913
+ async function telemetryReady() {
7914
+ return isTelemetryEnabled() && Boolean(await globalConfig("telemetry_installation_id"));
7915
+ }
7916
+ async function verifyUrl(listing) {
7917
+ const params = new URLSearchParams({ domain: listing.domain, claim: listing.claim });
7918
+ return `${await telemetryProxyEndpoint("/v1/ranking/verify")}?${params.toString()}`;
7919
+ }
7920
+ async function setEnabled(enabled) {
7921
+ await upsertSwarmConfig2({
7922
+ scope: "global",
7923
+ key: PUBLIC_RANKING_ENABLED_KEY,
7924
+ value: String(enabled)
7925
+ });
7926
+ }
7927
+ function emitOptedIn(listing) {
7928
+ telemetry.ranking("opted_in", { listing: JSON.stringify(listing) }, { orgName: listing.name, orgWebsite: listing.domain });
7929
+ }
7930
+ function emitOptedOut(domain) {
7931
+ telemetry.ranking("opted_out", { domain });
7932
+ }
7933
+ async function buildRankingState() {
7934
+ const [identity, listing, enabled, telemetryOn] = await Promise.all([
7935
+ currentIdentity(),
7936
+ storedListing(),
7937
+ rankingEnabled(),
7938
+ telemetryReady()
7939
+ ]);
7940
+ const listingMatchesDomain = Boolean(listing && listing.domain === identity.website);
7941
+ const current = listingMatchesDomain ? listing : null;
7942
+ return {
7943
+ eligible: telemetryOn && identity.ok,
7944
+ missing: identity.missing,
7945
+ telemetryOn,
7946
+ enabled: enabled && listingMatchesDomain,
7947
+ name: identity.name,
7948
+ domain: identity.website,
7949
+ listing,
7950
+ listingMatchesDomain,
7951
+ fileJson: current ? rankingEntryFile(current) : null,
7952
+ prUrl: current ? rankingPrUrl(current) : null,
7953
+ verifyUrl: current ? await verifyUrl(current) : null
7954
+ };
7955
+ }
7956
+ async function syncRankingAfterConfigChange(key, value) {
7957
+ if (!RANKING_CONFIG_KEYS.has(key))
7958
+ return;
7959
+ const listing = await storedListing();
7960
+ if (!listing)
7961
+ return;
7962
+ if (key === PUBLIC_RANKING_ENABLED_KEY) {
7963
+ if (!isEnvFlagEnabled(key, false, { [key]: value ?? undefined })) {
7964
+ emitOptedOut(listing.domain);
7965
+ }
7966
+ return;
7967
+ }
7968
+ if (!await rankingEnabled())
7969
+ return;
7970
+ const identity = await currentIdentity({ key, value });
7971
+ let rebuilt = null;
7972
+ if (identity.ok && identity.website === listing.domain) {
7973
+ if (identity.name === listing.name)
7974
+ return;
7975
+ try {
7976
+ rebuilt = buildListing(identity, listing, listing.claim);
7977
+ } catch {}
7978
+ }
7979
+ if (!rebuilt) {
7980
+ await setEnabled(false);
7981
+ emitOptedOut(listing.domain);
7982
+ return;
7983
+ }
7984
+ await upsertSwarmConfig2({
7985
+ scope: "global",
7986
+ key: TELEMETRY_RANKING_KEY,
7987
+ value: JSON.stringify(rebuilt)
7988
+ });
7989
+ emitOptedIn(rebuilt);
7990
+ }
7991
+ function conflict(res, body) {
7992
+ res.writeHead(409, { "Content-Type": "application/json" });
7993
+ res.end(JSON.stringify(body));
7994
+ }
7995
+ async function handleRanking(req, res, pathSegments, queryParams) {
7996
+ if (getRanking.match(req.method, pathSegments)) {
7997
+ const parsed = await getRanking.parse(req, res, pathSegments, queryParams);
7998
+ if (!parsed)
7999
+ return true;
8000
+ if (!await ensureConfigAdmin(req, res, "config.write.any"))
8001
+ return true;
8002
+ getRanking.respond(res, 200, await buildRankingState());
8003
+ return true;
8004
+ }
8005
+ if (optIn.match(req.method, pathSegments)) {
8006
+ const parsed = await optIn.parse(req, res, pathSegments, queryParams);
8007
+ if (!parsed)
8008
+ return true;
8009
+ if (!await ensureConfigAdmin(req, res, "config.write.any"))
8010
+ return true;
8011
+ if (!await telemetryReady()) {
8012
+ conflict(res, {
8013
+ error: "telemetry_off",
8014
+ message: "Turn telemetry on first: the ranking counts tokens from telemetry."
8015
+ });
8016
+ return true;
8017
+ }
8018
+ const identity = await currentIdentity();
8019
+ if (!identity.ok || !identity.website) {
8020
+ conflict(res, {
8021
+ error: "org_identity_missing",
8022
+ message: "Set the organization name and website first",
8023
+ missing: identity.missing
8024
+ });
8025
+ return true;
8026
+ }
8027
+ const website = identity.website;
8028
+ const db = getDbClient2();
8029
+ const built = await db.transaction(async () => {
8030
+ const stored = await storedListing();
8031
+ const claim = stored?.domain === website ? stored.claim : mintRankingClaim();
8032
+ let listing;
8033
+ try {
8034
+ listing = buildListing(identity, parsed.body, claim);
8035
+ } catch (error) {
8036
+ return { ok: false, error };
8037
+ }
8038
+ await upsertSwarmConfig2({
8039
+ scope: "global",
8040
+ key: TELEMETRY_RANKING_KEY,
8041
+ value: JSON.stringify(listing)
8042
+ });
8043
+ await setEnabled(true);
8044
+ db.afterCommit(() => emitOptedIn(listing));
8045
+ return { ok: true, listing };
8046
+ });
8047
+ if (!built.ok) {
8048
+ const issue = built.error instanceof ZodError ? built.error.issues[0] : undefined;
8049
+ res.writeHead(400, { "Content-Type": "application/json" });
8050
+ res.end(JSON.stringify({
8051
+ error: issue ? `Invalid ${issue.path.join(".") || "listing"}: ${issue.message}` : "Invalid listing"
8052
+ }));
8053
+ return true;
8054
+ }
8055
+ const { listing } = built;
8056
+ scheduleIntegrationsReload();
8057
+ optIn.respond(res, 200, {
8058
+ domain: listing.domain,
8059
+ claim: listing.claim,
8060
+ listing,
8061
+ fileJson: rankingEntryFile(listing),
8062
+ prUrl: rankingPrUrl(listing),
8063
+ verifyUrl: await verifyUrl(listing)
8064
+ });
8065
+ return true;
8066
+ }
8067
+ if (optOut.match(req.method, pathSegments)) {
8068
+ const parsed = await optOut.parse(req, res, pathSegments, queryParams);
8069
+ if (!parsed)
8070
+ return true;
8071
+ if (!await ensureConfigAdmin(req, res, "config.write.any"))
8072
+ return true;
8073
+ const listing = await storedListing();
8074
+ await setEnabled(false);
8075
+ if (listing)
8076
+ emitOptedOut(listing.domain);
8077
+ scheduleIntegrationsReload();
8078
+ optOut.respond(res, 200, {
8079
+ enabled: false,
8080
+ leaveUrl: listing ? rankingLeaveUrl(listing.domain) : null
8081
+ });
8082
+ return true;
8083
+ }
8084
+ return false;
8085
+ }
8086
+
8087
+ // src/http/config.ts
7593
8088
  var MAX_ENV_PRESENCE_KEYS = 200;
7594
8089
  var SECRETS_FORCE_MASK_NOTE = " (secret values masked: this token cannot read secrets in this scope)";
7595
8090
  function stripApiOnlyKeys(configs) {
@@ -7959,6 +8454,8 @@ async function handleConfig(req, res, pathSegments, queryParams) {
7959
8454
  if (scope === "global" && key === "SWARM_ORG_WEBSITE") {
7960
8455
  await fillOrgLogoFromWebsite(String(value));
7961
8456
  }
8457
+ if (scope === "global")
8458
+ await syncRankingAfterConfigChange(key, String(value));
7962
8459
  if (scope === "global") {
7963
8460
  scheduleIntegrationsReload();
7964
8461
  }
@@ -7994,6 +8491,7 @@ async function handleConfig(req, res, pathSegments, queryParams) {
7994
8491
  return true;
7995
8492
  }
7996
8493
  if (existing.scope === "global") {
8494
+ await syncRankingAfterConfigChange(existing.key, null);
7997
8495
  scheduleIntegrationsReload();
7998
8496
  }
7999
8497
  if (existing.scope === "agent" && existing.scopeId && existing.key === AGENT_MAX_TASKS_CONFIG_KEY) {
@@ -8830,6 +9328,7 @@ var postContext = route({
8830
9328
  method: "post",
8831
9329
  path: "/api/tasks/{id}/context",
8832
9330
  pattern: ["api", "tasks", null, "context"],
9331
+ session: { taskParam: "id" },
8833
9332
  summary: "Record a context usage snapshot for a task",
8834
9333
  tags: ["Tasks"],
8835
9334
  params: object2({ id: string2() }),
@@ -8856,6 +9355,7 @@ var getContext = route({
8856
9355
  method: "get",
8857
9356
  path: "/api/tasks/{id}/context",
8858
9357
  pattern: ["api", "tasks", null, "context"],
9358
+ session: { taskParam: "id" },
8859
9359
  summary: "Get context usage history for a task",
8860
9360
  tags: ["Tasks"],
8861
9361
  params: object2({ id: string2() }),
@@ -8936,6 +9436,7 @@ var createEventRoute = route({
8936
9436
  method: "post",
8937
9437
  path: "/api/events",
8938
9438
  pattern: ["api", "events"],
9439
+ session: bodyTask("taskId"),
8939
9440
  summary: "Store a single event",
8940
9441
  tags: ["Events"],
8941
9442
  body: eventBodySchema,
@@ -8952,6 +9453,7 @@ var createEventsBatchRoute = route({
8952
9453
  method: "post",
8953
9454
  path: "/api/events/batch",
8954
9455
  pattern: ["api", "events", "batch"],
9456
+ session: bodyListTask("events", "taskId"),
8955
9457
  summary: "Store multiple events in a batch",
8956
9458
  tags: ["Events"],
8957
9459
  body: object2({
@@ -9026,7 +9528,7 @@ var getEventCountsRoute = route({
9026
9528
  auth: { apiKey: true }
9027
9529
  });
9028
9530
  var MAX_LATEST_PAIRS = 50;
9029
- async function handleEvents(req, res, pathSegments, queryParams, _myAgentId) {
9531
+ async function handleEvents(req, res, pathSegments, queryParams, myAgentId) {
9030
9532
  if (createEventsBatchRoute.match(req.method, pathSegments)) {
9031
9533
  const parsed = await createEventsBatchRoute.parse(req, res, pathSegments, queryParams);
9032
9534
  if (!parsed)
@@ -9100,7 +9602,8 @@ async function handleEvents(req, res, pathSegments, queryParams, _myAgentId) {
9100
9602
  until: parsed.query.until || undefined,
9101
9603
  limit: parsed.query.limit ?? 100,
9102
9604
  events: eventFilter,
9103
- latestPerDataField: latestPerDataField ? { events: latestEvents, dataFields } : undefined
9605
+ latestPerDataField: latestPerDataField ? { events: latestEvents, dataFields } : undefined,
9606
+ readableBy: readableByFor2(await resolveSessionActor2(req, myAgentId))
9104
9607
  });
9105
9608
  getEventsRoute.respond(res, 200, latestPerDataField ? { events, latestPerDataField: true } : { events });
9106
9609
  return true;
@@ -12524,110 +13027,6 @@ async function getLocalFleetStats(now = new Date) {
12524
13027
 
12525
13028
  // src/http/fleet-benchmark.ts
12526
13029
  init_telemetry();
12527
-
12528
- // src/http/used-by.ts
12529
- init_zod();
12530
- init_db3();
12531
- init_telemetry();
12532
- init_org_website();
12533
- var CONSENT_KEY = "SWARM_USED_BY_CONSENT";
12534
- var CONSENT_AT_KEY = "SWARM_USED_BY_CONSENT_AT";
12535
- var GRANTED_NAME_KEY = "SWARM_USED_BY_ORG_NAME";
12536
- var GRANTED_WEBSITE_KEY = "SWARM_USED_BY_ORG_WEBSITE";
12537
- var TIMEOUT_MS = 1e4;
12538
- var usedBy = route({
12539
- method: "post",
12540
- path: "/api/used-by",
12541
- pattern: ["api", "used-by"],
12542
- summary: "Grant or revoke the 'used by' logo consent",
12543
- description: "Records whether agent-swarm.dev may show this organization's logo as a company that uses Agent Swarm. Sends the organization name and website to the telemetry proxy, where a person approves each logo by hand. An explicit admin action, so it is not gated by the telemetry opt-out.",
12544
- tags: ["Telemetry"],
12545
- body: object2({ granted: boolean() }),
12546
- responses: {
12547
- 200: {
12548
- description: "Consent recorded",
12549
- schema: object2({ granted: boolean(), changedAt: string2() })
12550
- },
12551
- 400: {
12552
- description: "Organization name or website is not set (a revoke falls back to the identity of the last grant)"
12553
- },
12554
- 401: { description: "Unauthorized" },
12555
- 403: { description: "Only a config admin can change the consent" },
12556
- 502: { description: "The telemetry proxy did not accept the consent" }
12557
- },
12558
- rbac: { permission: "config.write.any" }
12559
- });
12560
- async function globalConfig(key) {
12561
- const stored = (await getSwarmConfigs2({ scope: "global", key }))?.[0]?.value?.trim();
12562
- return stored || process.env[key]?.trim() || undefined;
12563
- }
12564
- async function telemetryProxyEndpoint(path) {
12565
- const feedback = await globalConfig("feedback_endpoint");
12566
- if (feedback && /^https?:\/\/[^/]+\/v1\/feedback\/?$/.test(feedback)) {
12567
- return feedback.replace(/\/v1\/feedback\/?$/, path);
12568
- }
12569
- return `${TELEMETRY_PROXY_ORIGIN}${path}`;
12570
- }
12571
- function usedByEndpoint() {
12572
- return telemetryProxyEndpoint("/v1/used-by");
12573
- }
12574
- async function handleUsedBy(req, res, pathSegments, queryParams, myAgentId) {
12575
- if (!usedBy.match(req.method, pathSegments))
12576
- return false;
12577
- const parsed = await usedBy.parse(req, res, pathSegments, queryParams);
12578
- if (!parsed)
12579
- return true;
12580
- if (!await ensureConfigAdmin(req, res, "config.write.any"))
12581
- return true;
12582
- const { granted } = parsed.body;
12583
- const currentName = await globalConfig("SWARM_ORG_NAME");
12584
- const currentWebsite = normalizeOrgWebsite(await globalConfig("SWARM_ORG_WEBSITE"));
12585
- const grantedName = granted ? undefined : await globalConfig(GRANTED_NAME_KEY);
12586
- const grantedWebsite = granted ? null : normalizeOrgWebsite(await globalConfig(GRANTED_WEBSITE_KEY));
12587
- const [orgName, orgWebsite] = grantedName && grantedWebsite ? [grantedName, grantedWebsite] : [currentName, currentWebsite];
12588
- if (!orgName || !orgWebsite) {
12589
- jsonError(res, "Set the organization name and website first", 400);
12590
- return true;
12591
- }
12592
- const installId = isTelemetryEnabled() ? await globalConfig("telemetry_installation_id") : undefined;
12593
- const orgDomain = await globalConfig("telemetry_org_domain");
12594
- const changedAt = new Date().toISOString();
12595
- try {
12596
- const response = await fetch(await usedByEndpoint(), {
12597
- method: "POST",
12598
- headers: { "Content-Type": "application/json" },
12599
- body: JSON.stringify({
12600
- ...installId ? { install_id: installId } : {},
12601
- org_name: orgName,
12602
- org_website: orgWebsite,
12603
- ...orgDomain ? { org_domain: orgDomain } : {},
12604
- granted,
12605
- changed_at: changedAt
12606
- }),
12607
- signal: AbortSignal.timeout(TIMEOUT_MS)
12608
- });
12609
- if (!response.ok) {
12610
- jsonError(res, `The telemetry proxy answered ${response.status}`, 502);
12611
- return true;
12612
- }
12613
- } catch {
12614
- jsonError(res, "Could not reach the telemetry proxy", 502);
12615
- return true;
12616
- }
12617
- await upsertSwarmConfig2({ scope: "global", key: CONSENT_KEY, value: String(granted) });
12618
- await upsertSwarmConfig2({ scope: "global", key: CONSENT_AT_KEY, value: changedAt });
12619
- if (granted) {
12620
- await upsertSwarmConfig2({ scope: "global", key: GRANTED_NAME_KEY, value: orgName });
12621
- await upsertSwarmConfig2({ scope: "global", key: GRANTED_WEBSITE_KEY, value: orgWebsite });
12622
- }
12623
- scheduleIntegrationsReload();
12624
- const owner = await resolveHttpFavoriteOwner(req, myAgentId);
12625
- trackRelayed("used_by.consent_changed", { granted }, { actor: owner?.userId ? { userId: owner.userId } : undefined, emitter: "ui" });
12626
- usedBy.respond(res, 200, { granted, changedAt });
12627
- return true;
12628
- }
12629
-
12630
- // src/http/fleet-benchmark.ts
12631
13030
  var FLEET_TTL_MS = 24 * 60 * 60 * 1000;
12632
13031
  var FLEET_FAILURE_TTL_MS = 60 * 60 * 1000;
12633
13032
  var LOCAL_TTL_MS = 10 * 60 * 1000;
@@ -12886,6 +13285,7 @@ var listTaskFilesRoute = route({
12886
13285
  method: "get",
12887
13286
  path: "/api/fs/tasks/{taskId}/files",
12888
13287
  pattern: ["api", "fs", "tasks", null, "files"],
13288
+ session: { taskParam: "taskId" },
12889
13289
  summary: "List task file attachments",
12890
13290
  tags: ["FS"],
12891
13291
  params: taskParams,
@@ -12901,6 +13301,7 @@ var uploadTaskFileRoute = route({
12901
13301
  method: "post",
12902
13302
  path: "/api/fs/tasks/{taskId}/files",
12903
13303
  pattern: ["api", "fs", "tasks", null, "files"],
13304
+ session: { taskParam: "taskId" },
12904
13305
  summary: "Upload a binary task file attachment",
12905
13306
  description: "Accepts a raw binary request body. Pass the display/path name as the `name` query parameter.",
12906
13307
  tags: ["FS"],
@@ -12920,6 +13321,7 @@ var getTaskFileRoute = route({
12920
13321
  method: "get",
12921
13322
  path: "/api/fs/tasks/{taskId}/files/{attachmentId}",
12922
13323
  pattern: ["api", "fs", "tasks", null, "files", null],
13324
+ session: { taskParam: "taskId" },
12923
13325
  summary: "Get task file attachment metadata",
12924
13326
  tags: ["FS"],
12925
13327
  params: attachmentParams,
@@ -12932,6 +13334,7 @@ var downloadTaskFileRoute = route({
12932
13334
  method: "get",
12933
13335
  path: "/api/fs/tasks/{taskId}/files/{attachmentId}/raw",
12934
13336
  pattern: ["api", "fs", "tasks", null, "files", null, "raw"],
13337
+ session: { taskParam: "taskId" },
12935
13338
  summary: "Download raw task file bytes",
12936
13339
  description: "Streams raw bytes. File content is not secret-scrubbed.",
12937
13340
  tags: ["FS"],
@@ -12948,6 +13351,7 @@ var signedUrlTaskFileRoute = route({
12948
13351
  method: "get",
12949
13352
  path: "/api/fs/tasks/{taskId}/files/{attachmentId}/signed-url",
12950
13353
  pattern: ["api", "fs", "tasks", null, "files", null, "signed-url"],
13354
+ session: { taskParam: "taskId" },
12951
13355
  summary: "Create a provider signed GET URL for a task file",
12952
13356
  tags: ["FS"],
12953
13357
  params: attachmentParams,
@@ -12962,6 +13366,7 @@ var deleteTaskFileRoute = route({
12962
13366
  method: "delete",
12963
13367
  path: "/api/fs/tasks/{taskId}/files/{attachmentId}",
12964
13368
  pattern: ["api", "fs", "tasks", null, "files", null],
13369
+ session: { taskParam: "taskId" },
12965
13370
  summary: "Delete a task file attachment",
12966
13371
  tags: ["FS"],
12967
13372
  params: attachmentParams,
@@ -13010,7 +13415,7 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
13010
13415
  const parsed = await downloadTaskFileRoute.parse(req, res, pathSegments, queryParams);
13011
13416
  if (!parsed)
13012
13417
  return true;
13013
- const attachment = await findAttachment(parsed.params.taskId, parsed.params.attachmentId, res);
13418
+ const attachment = await findAttachment(req, myAgentId, parsed.params.taskId, parsed.params.attachmentId, res);
13014
13419
  if (!attachment)
13015
13420
  return true;
13016
13421
  return sendDownload(res, attachment);
@@ -13019,7 +13424,7 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
13019
13424
  const parsed = await signedUrlTaskFileRoute.parse(req, res, pathSegments, queryParams);
13020
13425
  if (!parsed)
13021
13426
  return true;
13022
- const attachment = await findAttachment(parsed.params.taskId, parsed.params.attachmentId, res);
13427
+ const attachment = await findAttachment(req, myAgentId, parsed.params.taskId, parsed.params.attachmentId, res);
13023
13428
  if (!attachment)
13024
13429
  return true;
13025
13430
  return sendSignedUrl(res, attachment, parsed.query.expiresIn);
@@ -13028,7 +13433,7 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
13028
13433
  const parsed = await getTaskFileRoute.parse(req, res, pathSegments, queryParams);
13029
13434
  if (!parsed)
13030
13435
  return true;
13031
- const attachment = await findAttachment(parsed.params.taskId, parsed.params.attachmentId, res);
13436
+ const attachment = await findAttachment(req, myAgentId, parsed.params.taskId, parsed.params.attachmentId, res);
13032
13437
  if (!attachment)
13033
13438
  return true;
13034
13439
  getTaskFileRoute.respond(res, 200, attachment);
@@ -13067,6 +13472,10 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
13067
13472
  return true;
13068
13473
  if (!await getTaskById2(parsed.params.taskId))
13069
13474
  return notFound(res, "Task not found");
13475
+ if (!await canReadSession2(req, myAgentId, parsed.params.taskId)) {
13476
+ jsonError(res, SESSION_READ_DENIED2, 403);
13477
+ return true;
13478
+ }
13070
13479
  listTaskFilesRoute.respond(res, 200, {
13071
13480
  attachments: await getTaskAttachments2(parsed.params.taskId)
13072
13481
  });
@@ -13202,11 +13611,15 @@ function backingProviderId(attachment) {
13202
13611
  return "local-fs";
13203
13612
  return null;
13204
13613
  }
13205
- async function findAttachment(taskId, attachmentId, res) {
13614
+ async function findAttachment(req, myAgentId, taskId, attachmentId, res) {
13206
13615
  if (!await getTaskById2(taskId)) {
13207
13616
  notFound(res, "Task not found");
13208
13617
  return null;
13209
13618
  }
13619
+ if (!await canReadSession2(req, myAgentId, taskId)) {
13620
+ jsonError(res, SESSION_READ_DENIED2, 403);
13621
+ return null;
13622
+ }
13210
13623
  const attachment = (await getTaskAttachments2(taskId)).find((item) => item.id === attachmentId);
13211
13624
  if (!attachment) {
13212
13625
  notFound(res, "Attachment not found");
@@ -17846,6 +18259,7 @@ var indexMemory = route({
17846
18259
  method: "post",
17847
18260
  path: "/api/memory/index",
17848
18261
  pattern: ["api", "memory", "index"],
18262
+ session: bodyTask("sourceTaskId"),
17849
18263
  summary: "Ingest content into memory system (async embedding)",
17850
18264
  tags: ["Memory"],
17851
18265
  rbac: { permission: "memory.write.consolidated" },
@@ -18323,6 +18737,7 @@ var rateMemory = route({
18323
18737
  method: "post",
18324
18738
  path: "/api/memory/rate",
18325
18739
  pattern: ["api", "memory", "rate"],
18740
+ session: { none: "worker-only: it needs X-Agent-ID, which a user token cannot send" },
18326
18741
  summary: "Submit RatingEvents to update memory usefulness posteriors",
18327
18742
  tags: ["Memory"],
18328
18743
  auth: { apiKey: true, agentId: true },
@@ -21770,7 +22185,7 @@ var listTasks = route({
21770
22185
  path: "/api/tasks",
21771
22186
  pattern: ["api", "tasks"],
21772
22187
  summary: "List tasks with filters",
21773
- description: "Returns tasks with the full `task` text replaced by a bounded `taskPreview` and completion/integration blobs dropped by default — list views only need the preview. Pass `fields=full` to restore the full `AgentTask`, or `fields=timeline` for the narrow shape the dashboard timeline draws. Fetch a single task in full via `GET /api/tasks/{id}`. `total` (the filtered row count, ignoring limit/offset) is computed only with `includeTotal=true`.",
22188
+ description: "Returns tasks with the full `task` text replaced by a bounded `taskPreview` and completion/integration blobs dropped by default — list views only need the preview. Pass `fields=full` to restore the full `AgentTask`, or `fields=timeline` for the narrow shape the dashboard timeline draws. Every shape gives a user caller only tasks of sessions they can read. Fetch a single task in full via `GET /api/tasks/{id}`. `total` (the filtered row count, ignoring limit/offset) is computed only with `includeTotal=true`.",
21774
22189
  tags: ["Tasks"],
21775
22190
  query: object2({
21776
22191
  status: string2().optional(),
@@ -21809,6 +22224,7 @@ var createTask = route({
21809
22224
  method: "post",
21810
22225
  path: "/api/tasks",
21811
22226
  pattern: ["api", "tasks"],
22227
+ session: bodyTask("parentTaskId"),
21812
22228
  summary: "Create a new task",
21813
22229
  tags: ["Tasks"],
21814
22230
  body: object2({
@@ -21864,6 +22280,7 @@ var promoteDraftTaskRoute = route({
21864
22280
  method: "post",
21865
22281
  path: "/api/tasks/{id}/promote-draft",
21866
22282
  pattern: ["api", "tasks", null, "promote-draft"],
22283
+ session: { taskParam: "id" },
21867
22284
  summary: "Promote a draft task out of the pre-dispatch draft state",
21868
22285
  description: "Transitions a `draft` task (#1240 — created with attachments still uploading) to its normal dispatch-eligible status: `offered` if it was offered to an agent, `pending` if it has an owning agent (the common case — UI-composer tasks default to Lead), otherwise `unassigned`. Called by the UI composer once its attachment upload batch settles, whether every file uploaded, some failed, or all failed — a draft must never be stranded by an upload error. Idempotent: calling it on a task that already left `draft` returns the current task unchanged rather than erroring, so a retried request is safe.",
21869
22286
  tags: ["Tasks"],
@@ -21879,6 +22296,7 @@ var updateSession = route({
21879
22296
  method: "put",
21880
22297
  path: "/api/tasks/{id}/session",
21881
22298
  pattern: ["api", "tasks", null, "session"],
22299
+ session: { taskParam: "id" },
21882
22300
  summary: "Update provider session ID and harness metadata for a task",
21883
22301
  tags: ["Tasks"],
21884
22302
  params: object2({ id: string2() }),
@@ -21912,6 +22330,7 @@ var cancelTaskRoute = route({
21912
22330
  method: "post",
21913
22331
  path: "/api/tasks/{id}/cancel",
21914
22332
  pattern: ["api", "tasks", null, "cancel"],
22333
+ session: { taskParam: "id" },
21915
22334
  summary: "Cancel a pending or in-progress task",
21916
22335
  tags: ["Tasks"],
21917
22336
  params: object2({ id: string2() }),
@@ -21926,6 +22345,7 @@ var steerTaskRoute = route({
21926
22345
  method: "post",
21927
22346
  path: "/api/tasks/{id}/steer",
21928
22347
  pattern: ["api", "tasks", null, "steer"],
22348
+ session: { taskParam: "id" },
21929
22349
  summary: "Deliver a steering message to a running task",
21930
22350
  tags: ["Tasks"],
21931
22351
  params: object2({ id: string2() }),
@@ -21954,6 +22374,7 @@ var getTaskSteeringMessagesRoute = route({
21954
22374
  method: "get",
21955
22375
  path: "/api/tasks/{id}/steering-messages",
21956
22376
  pattern: ["api", "tasks", null, "steering-messages"],
22377
+ session: { taskParam: "id" },
21957
22378
  summary: "List steering messages for a task",
21958
22379
  tags: ["Tasks"],
21959
22380
  params: object2({ id: string2() }),
@@ -21980,6 +22401,7 @@ var markSteeringDeliveredRoute = route({
21980
22401
  method: "post",
21981
22402
  path: "/api/steering-messages/{id}/delivered",
21982
22403
  pattern: ["api", "steering-messages", null, "delivered"],
22404
+ session: { steeringParam: "id" },
21983
22405
  summary: "Mark a steering message delivered",
21984
22406
  tags: ["Tasks"],
21985
22407
  params: object2({ id: string2() }),
@@ -22003,6 +22425,7 @@ var markSteeringHandledRoute = route({
22003
22425
  method: "post",
22004
22426
  path: "/api/steering-messages/{id}/handled",
22005
22427
  pattern: ["api", "steering-messages", null, "handled"],
22428
+ session: { steeringParam: "id" },
22006
22429
  summary: "Mark a steering message handled",
22007
22430
  description: "Optionally accepts a JSON body `{ note?: string }` — a short acceptance note describing how the steering was incorporated, persisted as `handledNote`.",
22008
22431
  tags: ["Tasks"],
@@ -22025,6 +22448,7 @@ var markSteeringUndeliverableRoute = route({
22025
22448
  method: "post",
22026
22449
  path: "/api/steering-messages/{id}/undeliverable",
22027
22450
  pattern: ["api", "steering-messages", null, "undeliverable"],
22451
+ session: { steeringParam: "id" },
22028
22452
  summary: "Promote an undeliverable steering message",
22029
22453
  tags: ["Tasks"],
22030
22454
  params: object2({ id: string2() }),
@@ -22048,6 +22472,7 @@ var getTask = route({
22048
22472
  method: "get",
22049
22473
  path: "/api/tasks/{id}",
22050
22474
  pattern: ["api", "tasks", null],
22475
+ session: { taskParam: "id" },
22051
22476
  summary: "Get task details with logs and attachments",
22052
22477
  description: "Returns the full `AgentTask` row decorated with `logs` (capped by `logsLimit`) and `attachments` (pointer-based artifacts stored on the task, ordered by `created_at`).",
22053
22478
  tags: ["Tasks"],
@@ -22057,6 +22482,7 @@ var getTask = route({
22057
22482
  }),
22058
22483
  responses: {
22059
22484
  200: { description: "Task with logs and attachments", schema: GetTaskResponseSchema },
22485
+ 403: { description: "A user caller cannot read the task's session" },
22060
22486
  404: { description: "Task not found" }
22061
22487
  }
22062
22488
  });
@@ -22064,6 +22490,7 @@ var updateTaskProgressRoute = route({
22064
22490
  method: "post",
22065
22491
  path: "/api/tasks/{id}/progress",
22066
22492
  pattern: ["api", "tasks", null, "progress"],
22493
+ session: { taskParam: "id" },
22067
22494
  summary: "Update task progress text",
22068
22495
  tags: ["Tasks"],
22069
22496
  params: object2({ id: string2() }),
@@ -22081,6 +22508,7 @@ var finishTask = route({
22081
22508
  method: "post",
22082
22509
  path: "/api/tasks/{id}/finish",
22083
22510
  pattern: ["api", "tasks", null, "finish"],
22511
+ session: { taskParam: "id" },
22084
22512
  summary: "Mark task as completed or failed (runner endpoint)",
22085
22513
  tags: ["Tasks"],
22086
22514
  params: object2({ id: string2() }),
@@ -22126,6 +22554,7 @@ var pauseTaskRoute = route({
22126
22554
  method: "post",
22127
22555
  path: "/api/tasks/{id}/pause",
22128
22556
  pattern: ["api", "tasks", null, "pause"],
22557
+ session: { taskParam: "id" },
22129
22558
  summary: "Pause an in-progress task",
22130
22559
  tags: ["Tasks"],
22131
22560
  params: object2({ id: string2() }),
@@ -22140,6 +22569,7 @@ var resumeTaskRoute = route({
22140
22569
  method: "post",
22141
22570
  path: "/api/tasks/{id}/resume",
22142
22571
  pattern: ["api", "tasks", null, "resume"],
22572
+ session: { taskParam: "id" },
22143
22573
  summary: "Resume a paused task",
22144
22574
  tags: ["Tasks"],
22145
22575
  params: object2({ id: string2() }),
@@ -22154,6 +22584,7 @@ var supersedeTaskRoute = route({
22154
22584
  method: "post",
22155
22585
  path: "/api/tasks/{id}/supersede",
22156
22586
  pattern: ["api", "tasks", null, "supersede"],
22587
+ session: { taskParam: "id" },
22157
22588
  summary: "Supersede an in-progress task (terminate + spawn resume follow-up)",
22158
22589
  description: 'Marks the original task `superseded` (terminal) and creates a fresh `taskType="resume"` follow-up so a worker can pick up the work in a new provider session. Workflow-step tasks (those with `workflowRunStepId`) are carved out: the original is marked `failed` with reason `superseded_workflow_task` and no follow-up is created — the workflow engine\'s retry/failure policy applies.',
22159
22590
  tags: ["Tasks"],
@@ -22174,6 +22605,7 @@ var updateTaskVcsRoute = route({
22174
22605
  method: "patch",
22175
22606
  path: "/api/tasks/{id}/vcs",
22176
22607
  pattern: ["api", "tasks", null, "vcs"],
22608
+ session: { taskParam: "id" },
22177
22609
  summary: "Update VCS (PR/MR) info for a task",
22178
22610
  tags: ["Tasks"],
22179
22611
  params: object2({ id: string2() }),
@@ -22194,6 +22626,7 @@ var updateTaskTitleRoute = route({
22194
22626
  method: "patch",
22195
22627
  path: "/api/tasks/{id}/title",
22196
22628
  pattern: ["api", "tasks", null, "title"],
22629
+ session: { taskParam: "id" },
22197
22630
  summary: "Set or clear a task's display title (session rename)",
22198
22631
  description: "Sets a human-facing display title override on a task. The sessions UI only reads this from root tasks (session list items), but titles on child tasks are harmless. Pass `title: null` (or an empty string) to clear the override and fall back to the task prompt.",
22199
22632
  tags: ["Tasks"],
@@ -22210,17 +22643,21 @@ var updateTaskTitleRoute = route({
22210
22643
  ungated: "mirrors the pre-RBAC PATCH /api/tasks/{id}/vcs sibling route: bearer auth only"
22211
22644
  }
22212
22645
  });
22213
- async function canSteerTask(req, myAgentId, task) {
22646
+ async function hasSessionWrite(req, myAgentId, taskId) {
22647
+ const access = await sessionAccessFor2(await resolveSessionActor2(req, myAgentId), taskId);
22648
+ return hasSessionAccess(access, "write");
22649
+ }
22650
+ async function canSteerTask(req, myAgentId, task, sessionAccess = "none") {
22651
+ const auth = getRequestAuth(req);
22214
22652
  const resource = {
22215
22653
  kind: "task",
22216
22654
  taskId: task.id,
22217
- requestedByUserId: task.requestedByUserId,
22655
+ requestedByUserId: auth?.kind === "user" && sessionAccess === "write" ? auth.userId : task.requestedByUserId,
22218
22656
  creatorAgentId: task.creatorAgentId,
22219
22657
  agentId: task.agentId
22220
22658
  };
22221
22659
  let principal;
22222
22660
  let verb;
22223
- const auth = getRequestAuth(req);
22224
22661
  if (auth?.kind === "operator") {
22225
22662
  principal = { kind: "operator" };
22226
22663
  verb = "task.steer.own";
@@ -22329,6 +22766,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22329
22766
  if (validated.length > 0)
22330
22767
  source = validated;
22331
22768
  }
22769
+ const actor = await resolveSessionActor2(req, myAgentId);
22332
22770
  const filters = {
22333
22771
  status,
22334
22772
  agentId: parsed.query.agentId || undefined,
@@ -22344,7 +22782,8 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22344
22782
  requestedByUserIdIsNull: parsed.query.requestedByUserId === "none" || undefined,
22345
22783
  orderBy: parsed.query.orderBy,
22346
22784
  limit: parsed.query.limit,
22347
- offset: parsed.query.offset
22785
+ offset: parsed.query.offset,
22786
+ readableBy: actor.kind === "user" ? { userId: actor.userId } : undefined
22348
22787
  };
22349
22788
  const tasks = parsed.query.fields === "full" ? await getAllTasks2(filters) : parsed.query.fields === "timeline" ? await getAllTasks2(filters, { fields: "timeline" }) : await getAllTasks2(filters, { slim: true });
22350
22789
  if (parsed.query.includeTotal === "true") {
@@ -22402,6 +22841,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22402
22841
  jsonError(res, `You don't have context for parent task ${parentTask.id}.`, 403);
22403
22842
  return true;
22404
22843
  }
22844
+ if (parentTask && !await hasSessionWrite(req, myAgentId, parentTask.id)) {
22845
+ jsonError(res, SESSION_WRITE_DENIED2, 403);
22846
+ return true;
22847
+ }
22405
22848
  if (principal.kind === "agent" && parsed.body.contextKey && parsed.body.contextKey !== parentTask?.contextKey && chatThreadOfContextKey(parsed.body.contextKey) && !can({ principal, verb: "integration.chat.post", resource: { kind: "none" }, source: "http" }).allow) {
22406
22849
  jsonError(res, "Permission denied: only a lead can bind a task to a chat thread.", 403);
22407
22850
  return true;
@@ -22601,7 +23044,13 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22601
23044
  jsonError(res, "Task not found", 404);
22602
23045
  return true;
22603
23046
  }
22604
- if (!await canSteerTask(req, myAgentId, task)) {
23047
+ const sessionActor = await resolveSessionActor2(req, myAgentId);
23048
+ const steerAccess = await sessionAccessFor2(sessionActor, task.id);
23049
+ if (!hasSessionAccess(steerAccess, "write")) {
23050
+ jsonError(res, SESSION_WRITE_DENIED2, 403);
23051
+ return true;
23052
+ }
23053
+ if (!await canSteerTask(req, myAgentId, task, steerAccess)) {
22605
23054
  jsonError(res, "Forbidden: caller cannot steer this task", 403);
22606
23055
  return true;
22607
23056
  }
@@ -22641,6 +23090,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22641
23090
  jsonError(res, "Task not found", 404);
22642
23091
  return true;
22643
23092
  }
23093
+ if (!await canReadSession2(req, myAgentId, parsed.params.id)) {
23094
+ jsonError(res, SESSION_READ_DENIED2, 403);
23095
+ return true;
23096
+ }
22644
23097
  getTaskSteeringMessagesRoute.respond(res, 200, {
22645
23098
  messages: await getSteeringMessagesForTask2(parsed.params.id)
22646
23099
  });
@@ -22659,13 +23112,18 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22659
23112
  return true;
22660
23113
  }
22661
23114
  if (parsed.query.taskId) {
23115
+ if (!await canReadSession2(req, myAgentId, parsed.query.taskId)) {
23116
+ jsonError(res, SESSION_READ_DENIED2, 403);
23117
+ return true;
23118
+ }
22662
23119
  const task = await getTaskById2(parsed.query.taskId);
22663
23120
  const messages = task?.agentId === myAgentId ? await getPendingSteeringForTask2(parsed.query.taskId) : [];
22664
23121
  getPendingSteeringMessagesRoute.respond(res, 200, { messages });
22665
23122
  return true;
22666
23123
  }
23124
+ const actor = await resolveSessionActor2(req, myAgentId);
22667
23125
  getPendingSteeringMessagesRoute.respond(res, 200, {
22668
- messages: await getPendingSteeringForAgent2(myAgentId)
23126
+ messages: await getPendingSteeringForAgent2(myAgentId, readableByFor2(actor))
22669
23127
  });
22670
23128
  return true;
22671
23129
  }
@@ -22806,6 +23264,11 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22806
23264
  jsonError(res, "Task not found", 404);
22807
23265
  return true;
22808
23266
  }
23267
+ const readAccess = await sessionAccessFor2(await resolveSessionActor2(req, myAgentId), task.id);
23268
+ if (!hasSessionAccess(readAccess, "read")) {
23269
+ jsonError(res, "You don't have access to this session. Ask the owner to share it.", 403);
23270
+ return true;
23271
+ }
22809
23272
  const logs = await getLogsByTaskId2(parsed.params.id, parsed.query.logsLimit ?? 200);
22810
23273
  const attachments = await getTaskAttachments2(parsed.params.id);
22811
23274
  getTask.respond(res, 200, {
@@ -22957,7 +23420,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
22957
23420
  jsonError(res, "Missing X-Agent-ID header", 400);
22958
23421
  return true;
22959
23422
  }
22960
- const pausedTasks = await getPausedTasksForAgent2(myAgentId);
23423
+ const pausedTasks = await getPausedTasksForAgent2(myAgentId, readableByFor2(await resolveSessionActor2(req, myAgentId)));
22961
23424
  const tasks = await Promise.all(pausedTasks.map(async (task) => {
22962
23425
  const requestedBy = await buildTaskRequestedBy(task);
22963
23426
  return {
@@ -26820,6 +27283,7 @@ ${templateBody}` : templateBody;
26820
27283
 
26821
27284
  // src/http/realtime.ts
26822
27285
  init_zod();
27286
+ init_users();
26823
27287
  init_rbac();
26824
27288
 
26825
27289
  // src/realtime/browser.generated.txt
@@ -26833,14 +27297,14 @@ var realtimeTicketRoute = route({
26833
27297
  pattern: ["api", "realtime", "ticket"],
26834
27298
  summary: "Issue a one-shot dashboard realtime ticket",
26835
27299
  tags: ["Rooms"],
26836
- rbac: { permission: "comb.presence" },
27300
+ description: "The ticket authorizes one dashboard socket for presence rooms: Comb drives (`comb.presence`) and sessions (`session.presence`). An operator-key tab's picked user (`X-Swarm-User-Id`) rides on the ticket so session presence can check that user's access.",
27301
+ rbac: { permission: "session.presence", alsoAdmits: ["comb.presence"] },
26837
27302
  responses: {
26838
27303
  200: {
26839
27304
  description: "One-shot realtime ticket",
26840
27305
  schema: object2({ ticket: string2(), expiresAt: number2().int() })
26841
27306
  },
26842
- 403: { description: "Comb presence is not allowed" },
26843
- 404: { description: "Comb is not enabled" }
27307
+ 403: { description: "Presence is not allowed" }
26844
27308
  }
26845
27309
  });
26846
27310
  route({
@@ -26857,29 +27321,28 @@ route({
26857
27321
  async function handleRealtimeTicket(req, res, pathSegments, queryParams) {
26858
27322
  if (!realtimeTicketRoute.match(req.method, pathSegments))
26859
27323
  return false;
26860
- if (!getCombConfig().enabled) {
26861
- jsonError(res, "Comb is not enabled", 404);
26862
- return true;
26863
- }
26864
27324
  const parsed = await realtimeTicketRoute.parse(req, res, pathSegments, queryParams);
26865
27325
  if (!parsed)
26866
27326
  return true;
26867
27327
  const auth = getRequestAuth(req);
26868
27328
  if (!auth || auth.kind === "agent" || auth.kind === "guest" || auth.kind === "controller") {
26869
- jsonError(res, "Comb presence requires dashboard authentication", 403);
27329
+ jsonError(res, "Presence requires dashboard authentication", 403);
26870
27330
  return true;
26871
27331
  }
26872
27332
  const principal = auth.kind === "operator" ? { kind: "operator" } : { kind: "user", userId: auth.userId };
26873
- if (!can({
26874
- principal,
26875
- verb: "comb.presence",
26876
- resource: { kind: "none" },
26877
- source: "http"
26878
- }).allow) {
26879
- jsonError(res, "Comb presence requires the comb.presence permission", 403);
27333
+ const allowed = (verb) => can({ principal, verb, resource: { kind: "none" }, source: "http" }).allow;
27334
+ if (!allowed("comb.presence") && !allowed("session.presence")) {
27335
+ jsonError(res, "Presence requires the comb.presence or session.presence permission", 403);
26880
27336
  return true;
26881
27337
  }
26882
- realtimeTicketRoute.respond(res, 200, issueRealtimeTicket(auth));
27338
+ let dashboardUserId;
27339
+ if (auth.kind === "operator" && !auth.page) {
27340
+ const picked = dashboardUserIdHeader(req);
27341
+ const user = picked ? await findUserById(picked) : null;
27342
+ if (user?.status === "active")
27343
+ dashboardUserId = user.id;
27344
+ }
27345
+ realtimeTicketRoute.respond(res, 200, issueRealtimeTicket(dashboardUserId ? { ...auth, dashboardUserId } : auth));
26883
27346
  return true;
26884
27347
  }
26885
27348
  async function handleRealtimeAsset(req, res) {
@@ -30768,6 +31231,7 @@ var agentTaskRoute = route({
30768
31231
  method: "post",
30769
31232
  path: "/api/internal/script-runs/{runId}/agent-task",
30770
31233
  pattern: ["api", "internal", "script-runs", null, "agent-task"],
31234
+ session: bodyTask("parentTaskId"),
30771
31235
  operationId: "script_runs_internal_agent_task",
30772
31236
  summary: "Create or wait for a script workflow agent task step",
30773
31237
  tags: ["Script Runs"],
@@ -31247,6 +31711,9 @@ var upsertRoute2 = route({
31247
31711
  method: "post",
31248
31712
  path: "/api/scripts/upsert",
31249
31713
  pattern: ["api", "scripts", "upsert"],
31714
+ auth: {
31715
+ userNamesAgent: "dashboard script playground: a user runs or saves a script in a chosen agent's scope"
31716
+ },
31250
31717
  operationId: "scripts_upsert",
31251
31718
  summary: "Create or update a reusable script",
31252
31719
  description: "Explicit script upserts run a TypeScript typecheck before writing.",
@@ -31271,6 +31738,9 @@ var runRoute = route({
31271
31738
  method: "post",
31272
31739
  path: "/api/scripts/run",
31273
31740
  pattern: ["api", "scripts", "run"],
31741
+ auth: {
31742
+ userNamesAgent: "dashboard script playground: a user runs or saves a script in a chosen agent's scope"
31743
+ },
31274
31744
  operationId: "scripts_run",
31275
31745
  summary: "Run a reusable or inline script",
31276
31746
  description: "Inline source skips typecheck and is auto-saved as a scratch script only on success.",
@@ -32241,6 +32711,7 @@ var createSessionLogsRoute = route({
32241
32711
  method: "post",
32242
32712
  path: "/api/session-logs",
32243
32713
  pattern: ["api", "session-logs"],
32714
+ session: bodyTask("taskId"),
32244
32715
  summary: "Store session logs",
32245
32716
  tags: ["Session Data"],
32246
32717
  body: object2({
@@ -32262,6 +32733,7 @@ var getSessionLogsByTask = route({
32262
32733
  method: "get",
32263
32734
  path: "/api/tasks/{taskId}/session-logs",
32264
32735
  pattern: ["api", "tasks", null, "session-logs"],
32736
+ session: { taskParam: "taskId" },
32265
32737
  summary: "Get session logs for a task",
32266
32738
  tags: ["Session Data"],
32267
32739
  params: object2({ taskId: string2() }),
@@ -32280,6 +32752,7 @@ var createSessionCostRoute = route({
32280
32752
  method: "post",
32281
32753
  path: "/api/session-costs",
32282
32754
  pattern: ["api", "session-costs"],
32755
+ session: bodyTask("taskId"),
32283
32756
  summary: "Store session cost record",
32284
32757
  tags: ["Session Data"],
32285
32758
  body: object2({
@@ -32378,7 +32851,7 @@ var listSessionCosts = route({
32378
32851
  }
32379
32852
  }
32380
32853
  });
32381
- async function handleSessionData(req, res, pathSegments, queryParams, _myAgentId) {
32854
+ async function handleSessionData(req, res, pathSegments, queryParams, myAgentId) {
32382
32855
  if (createSessionLogsRoute.match(req.method, pathSegments)) {
32383
32856
  const parsed = await createSessionLogsRoute.parse(req, res, pathSegments, queryParams);
32384
32857
  if (!parsed)
@@ -32417,6 +32890,10 @@ async function handleSessionData(req, res, pathSegments, queryParams, _myAgentId
32417
32890
  jsonError(res, "Task not found", 404);
32418
32891
  return true;
32419
32892
  }
32893
+ if (!await canReadSession2(req, myAgentId, task.id)) {
32894
+ jsonError(res, SESSION_READ_DENIED2, 403);
32895
+ return true;
32896
+ }
32420
32897
  const logs = await getSessionLogsByTaskId2(parsed.params.taskId, parsed.query?.limit);
32421
32898
  getSessionLogsByTask.respond(res, 200, { logs });
32422
32899
  return true;
@@ -32563,6 +33040,8 @@ init_zod();
32563
33040
  init_db3();
32564
33041
  init_steering();
32565
33042
  init_users();
33043
+ init_rbac();
33044
+ init_bus();
32566
33045
  init_types();
32567
33046
  init_request_auth_context();
32568
33047
  init_runtime_pools_flag();
@@ -32611,6 +33090,9 @@ var mintSessionTokenRoute = route({
32611
33090
  method: "post",
32612
33091
  path: "/api/sessions/tokens",
32613
33092
  pattern: ["api", "sessions", "tokens"],
33093
+ session: {
33094
+ none: "user tokens cannot mint: the handler admits only the operator key or the task's own runtime"
33095
+ },
32614
33096
  summary: "Mint an ephemeral task or runtime token",
32615
33097
  description: "Operators can mint task or runtime tokens. Runtime tokens can mint task tokens for their own assigned tasks. Child tokens expire with their parent runtime.",
32616
33098
  tags: ["Sessions"],
@@ -32673,7 +33155,8 @@ var listSessions = route({
32673
33155
  q: string2().optional(),
32674
33156
  requestedByUserId: string2().min(1).optional(),
32675
33157
  contextKeyPrefix: string2().min(1).optional(),
32676
- fields: _enum2(["full", "slim"]).optional()
33158
+ fields: _enum2(["full", "slim"]).optional(),
33159
+ scope: _enum2(["mine", "shared"]).optional()
32677
33160
  }),
32678
33161
  responses: {
32679
33162
  200: {
@@ -32693,23 +33176,68 @@ var getSession = route({
32693
33176
  method: "get",
32694
33177
  path: "/api/sessions/{rootTaskId}",
32695
33178
  pattern: ["api", "sessions", null],
33179
+ session: { taskParam: "rootTaskId" },
32696
33180
  summary: "Get a session — root task + the entire descendant chain",
32697
33181
  tags: ["Sessions"],
32698
33182
  params: object2({ rootTaskId: string2() }),
32699
33183
  responses: {
32700
33184
  200: {
32701
- description: "Root task + chain (ordered by createdAt)",
33185
+ description: "Root task + chain (ordered by createdAt), plus the caller's `access` and the session `owner`",
32702
33186
  schema: object2({
32703
33187
  root: TaskWithSteeringSchema,
32704
- chain: array2(TaskWithSteeringSchema)
33188
+ chain: array2(TaskWithSteeringSchema),
33189
+ access: SessionAccessSchema,
33190
+ owner: SessionOwnerSchema.nullable()
32705
33191
  })
32706
33192
  },
32707
33193
  401: { description: "Unauthorized" },
33194
+ 403: { description: "The caller has no access to this session" },
32708
33195
  404: { description: "Root task not found" }
32709
33196
  },
32710
33197
  auth: { apiKey: true }
32711
33198
  });
32712
- async function handleSessions(req, res, pathSegments, queryParams) {
33199
+ var getSessionShares = route({
33200
+ method: "get",
33201
+ path: "/api/sessions/{rootTaskId}/shares",
33202
+ pattern: ["api", "sessions", null, "shares"],
33203
+ session: { taskParam: "rootTaskId" },
33204
+ summary: "List a session's active shares",
33205
+ description: "Active shares only. `everyone` is the access every user has; `users` are per-person shares. A session with no shares is private to its owner.",
33206
+ tags: ["Sessions"],
33207
+ params: object2({ rootTaskId: string2() }),
33208
+ responses: {
33209
+ 200: { description: "Active shares", schema: SessionSharesSchema },
33210
+ 401: { description: "Unauthorized" },
33211
+ 403: { description: "The caller has no access to this session" },
33212
+ 404: { description: "Root task not found" }
33213
+ },
33214
+ auth: { apiKey: true }
33215
+ });
33216
+ var putSessionShares = route({
33217
+ method: "put",
33218
+ path: "/api/sessions/{rootTaskId}/shares",
33219
+ pattern: ["api", "sessions", null, "shares"],
33220
+ session: { taskParam: "rootTaskId" },
33221
+ summary: "Set who can view or edit a session",
33222
+ description: "Owner only. The body is the full desired state: users left out lose access. Changed targets have their active share revoked and a new one inserted in one transaction; shares are never deleted.",
33223
+ tags: ["Sessions"],
33224
+ params: object2({ rootTaskId: string2() }),
33225
+ body: SessionSharesUpdateSchema,
33226
+ responses: {
33227
+ 200: { description: "Active shares after the change", schema: SessionSharesSchema },
33228
+ 400: { description: "Validation error or unknown user" },
33229
+ 401: { description: "Unauthorized" },
33230
+ 403: { description: "Only the session owner can share it" },
33231
+ 404: { description: "Root task not found" },
33232
+ 409: { description: "The session has no owner, so it is already open to everyone" }
33233
+ },
33234
+ auth: { apiKey: true },
33235
+ rbac: { permission: "session.share" }
33236
+ });
33237
+ async function accessForRoot(actor, root) {
33238
+ return actor.kind === "bypass" ? "owner" : sessionAccessForRoot(actor.userId, root);
33239
+ }
33240
+ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
32713
33241
  if (mintSessionTokenRoute.match(req.method, pathSegments)) {
32714
33242
  const auth = getRequestAuth(req);
32715
33243
  if (auth?.kind !== "operator" && !(auth?.kind === "agent" && auth.runtimeId)) {
@@ -32786,21 +33314,30 @@ async function handleSessions(req, res, pathSegments, queryParams) {
32786
33314
  if (!parsed)
32787
33315
  return true;
32788
33316
  const sources = parsed.query.source ? parsed.query.source.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
32789
- const baseOpts = {
32790
- limit: parsed.query.limit,
32791
- offset: parsed.query.offset,
33317
+ const actor = await resolveSessionActor2(req, myAgentId);
33318
+ if (actor.kind === "bypass" && parsed.query.scope) {
33319
+ listSessions.respond(res, 200, {
33320
+ sessions: [],
33321
+ total: 0,
33322
+ limit: parsed.query.limit ?? 25,
33323
+ offset: parsed.query.offset ?? 0
33324
+ });
33325
+ return true;
33326
+ }
33327
+ const filterOpts = {
32792
33328
  source: sources,
32793
33329
  q: parsed.query.q,
32794
33330
  requestedByUserId: parsed.query.requestedByUserId,
32795
- contextKeyPrefix: parsed.query.contextKeyPrefix
33331
+ contextKeyPrefix: parsed.query.contextKeyPrefix,
33332
+ ...actor.kind === "user" ? { viewer: { userId: actor.userId, scope: parsed.query.scope ?? "all" } } : {}
33333
+ };
33334
+ const baseOpts = {
33335
+ ...filterOpts,
33336
+ limit: parsed.query.limit,
33337
+ offset: parsed.query.offset
32796
33338
  };
32797
33339
  const sessions = parsed.query.fields === "full" ? await listRecentSessions2(baseOpts) : await listRecentSessions2({ ...baseOpts, slim: true });
32798
- const total = await countSessions2({
32799
- source: sources,
32800
- q: parsed.query.q,
32801
- requestedByUserId: parsed.query.requestedByUserId,
32802
- contextKeyPrefix: parsed.query.contextKeyPrefix
32803
- });
33340
+ const total = await countSessions2(filterOpts);
32804
33341
  listSessions.respond(res, 200, {
32805
33342
  sessions,
32806
33343
  total,
@@ -32818,6 +33355,20 @@ async function handleSessions(req, res, pathSegments, queryParams) {
32818
33355
  jsonError(res, "Root task not found", 404);
32819
33356
  return true;
32820
33357
  }
33358
+ const sessionRoot = await getSessionRoot(root.id) ?? {
33359
+ id: root.id,
33360
+ requestedByUserId: root.requestedByUserId ?? null
33361
+ };
33362
+ const access = await accessForRoot(await resolveSessionActor2(req, myAgentId), sessionRoot);
33363
+ if (access === "none") {
33364
+ jsonError(res, "You don't have access to this session. Ask the owner to share it.", 403);
33365
+ return true;
33366
+ }
33367
+ const ownerUser = sessionRoot.requestedByUserId ? await findUserById(sessionRoot.requestedByUserId) : null;
33368
+ const owner = sessionRoot.requestedByUserId ? {
33369
+ id: sessionRoot.requestedByUserId,
33370
+ name: ownerUser?.name ?? sessionRoot.requestedByUserId
33371
+ } : null;
32821
33372
  const chain = await getRootTaskChain2(parsed.params.rootTaskId);
32822
33373
  const tasks = [root, ...chain];
32823
33374
  const [steering, citations] = await Promise.all([
@@ -32829,7 +33380,69 @@ async function handleSessions(req, res, pathSegments, queryParams) {
32829
33380
  ...steering.get(task.id),
32830
33381
  citations: citations.get(task.id)
32831
33382
  });
32832
- getSession.respond(res, 200, { root: decorate(root), chain: chain.map(decorate) });
33383
+ getSession.respond(res, 200, {
33384
+ root: decorate(root),
33385
+ chain: chain.map(decorate),
33386
+ access,
33387
+ owner
33388
+ });
33389
+ return true;
33390
+ }
33391
+ if (getSessionShares.match(req.method, pathSegments)) {
33392
+ const parsed = await getSessionShares.parse(req, res, pathSegments, queryParams);
33393
+ if (!parsed)
33394
+ return true;
33395
+ const root = await getSessionRoot(parsed.params.rootTaskId);
33396
+ if (!root) {
33397
+ jsonError(res, "Root task not found", 404);
33398
+ return true;
33399
+ }
33400
+ const access = await accessForRoot(await resolveSessionActor2(req, myAgentId), root);
33401
+ if (access === "none") {
33402
+ jsonError(res, "You don't have access to this session. Ask the owner to share it.", 403);
33403
+ return true;
33404
+ }
33405
+ getSessionShares.respond(res, 200, toSessionSharesState(await listActiveSessionShares(root.id)));
33406
+ return true;
33407
+ }
33408
+ if (putSessionShares.match(req.method, pathSegments)) {
33409
+ const parsed = await putSessionShares.parse(req, res, pathSegments, queryParams);
33410
+ if (!parsed)
33411
+ return true;
33412
+ const auth = getRequestAuth(req);
33413
+ const actor = await resolveSessionActor2(req, myAgentId);
33414
+ const principal = auth?.kind === "user" ? { kind: "user", userId: auth.userId } : auth?.kind === "operator" && !myAgentId ? { kind: "operator" } : null;
33415
+ if (!principal || !can({ principal, verb: "session.share", resource: { kind: "none" }, source: "http" }).allow) {
33416
+ jsonError(res, "Only the session owner can share it", 403);
33417
+ return true;
33418
+ }
33419
+ const root = await getSessionRoot(parsed.params.rootTaskId);
33420
+ if (!root) {
33421
+ jsonError(res, "Root task not found", 404);
33422
+ return true;
33423
+ }
33424
+ if (!root.requestedByUserId) {
33425
+ jsonError(res, "This session has no owner, so it is already open to everyone", 409);
33426
+ return true;
33427
+ }
33428
+ if (actor.kind === "user" && actor.userId !== root.requestedByUserId) {
33429
+ jsonError(res, "Only the session owner can share it", 403);
33430
+ return true;
33431
+ }
33432
+ const userIds = [...new Set(parsed.body.users.map((user) => user.userId))];
33433
+ if (userIds.length !== parsed.body.users.length) {
33434
+ jsonError(res, "Each user may appear only once", 400);
33435
+ return true;
33436
+ }
33437
+ for (const userId of userIds) {
33438
+ if (!await findUserById(userId)) {
33439
+ jsonError(res, `Unknown user ${userId}`, 400);
33440
+ return true;
33441
+ }
33442
+ }
33443
+ const state = await setSessionShares(root, parsed.body, actor.kind === "user" ? actor.userId : null);
33444
+ realtimeBus.publish(sessionAccessTopic(root.id), null);
33445
+ putSessionShares.respond(res, 200, state);
32833
33446
  return true;
32834
33447
  }
32835
33448
  return false;
@@ -34231,11 +34844,12 @@ async function handleStats(req, res, pathSegments, queryParams, myAgentId) {
34231
34844
  return true;
34232
34845
  const limit = parsed.query.limit ?? 100;
34233
34846
  const agentId = parsed.query.agentId;
34847
+ const readableBy = readableByFor2(await resolveSessionActor2(req, myAgentId));
34234
34848
  let logs = [];
34235
34849
  if (agentId) {
34236
- logs = (await getLogsByAgentId2(agentId)).slice(0, limit);
34850
+ logs = (await getLogsByAgentId2(agentId, readableBy)).slice(0, limit);
34237
34851
  } else {
34238
- logs = await getAllLogs2(limit);
34852
+ logs = await getAllLogs2(limit, readableBy);
34239
34853
  }
34240
34854
  listLogs.respond(res, 200, { logs });
34241
34855
  return true;
@@ -34291,7 +34905,7 @@ async function handleStats(req, res, pathSegments, queryParams, myAgentId) {
34291
34905
  return true;
34292
34906
  }
34293
34907
  if (getConcurrentContextRoute.match(req.method, pathSegments)) {
34294
- const context = await getConcurrentContext2();
34908
+ const context = await getConcurrentContext2(readableByFor2(await resolveSessionActor2(req, myAgentId)));
34295
34909
  getConcurrentContextRoute.respond(res, 200, context);
34296
34910
  return true;
34297
34911
  }
@@ -38362,10 +38976,11 @@ var httpServer = createHttpServer(async (req, res) => {
38362
38976
  () => handleExtensions(req, res, pathSegments, queryParams, myAgentId),
38363
38977
  () => handleFavorites(req, res, pathSegments, queryParams, myAgentId),
38364
38978
  () => handleUsers(req, res, pathSegments, queryParams),
38365
- () => handleSessions(req, res, pathSegments, queryParams),
38979
+ () => handleSessions(req, res, pathSegments, queryParams, myAgentId),
38366
38980
  () => handleInboxState(req, res, pathSegments, queryParams),
38367
38981
  () => handleTelemetryUi(req, res, pathSegments, queryParams, myAgentId),
38368
38982
  () => handleUsedBy(req, res, pathSegments, queryParams, myAgentId),
38983
+ () => handleRanking(req, res, pathSegments, queryParams),
38369
38984
  () => handleFleetBenchmark(req, res, pathSegments, queryParams),
38370
38985
  () => handleTaskTemplates(req, res, pathSegments, queryParams),
38371
38986
  () => handleMcp(req, res, transports, transportActivity, mcpSessionAgents),
@@ -38397,7 +39012,7 @@ var httpServer = createHttpServer(async (req, res) => {
38397
39012
  });
38398
39013
  });
38399
39014
  var detachRealtime = attachRealtimeTransport(httpServer);
38400
- var { attachControllerTransport } = await import("./controllers-connect-ymw5541d.js");
39015
+ var { attachControllerTransport } = await import("./controllers-connect-gkxmqw9d.js");
38401
39016
  var detachControllers = attachControllerTransport(httpServer);
38402
39017
  var stopWorkerNudges = startWorkerNudgeListener();
38403
39018
  var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
@@ -38426,7 +39041,7 @@ async function shutdown() {
38426
39041
  sessionsProcessed: getServerSessionsProcessed()
38427
39042
  });
38428
39043
  if (hasCapability("scheduling")) {
38429
- const { stopScheduler } = await import("./index-vjn3wbzf.js");
39044
+ const { stopScheduler } = await import("./index-8pwc1jc8.js");
38430
39045
  stopScheduler();
38431
39046
  }
38432
39047
  stopHeartbeat2();
@@ -38438,7 +39053,7 @@ async function shutdown() {
38438
39053
  await stopSlackApp2();
38439
39054
  await stopChatSdk();
38440
39055
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
38441
- const { stopOAuthKeepalive } = await import("./keepalive-4djvbm2j.js");
39056
+ const { stopOAuthKeepalive } = await import("./keepalive-3nr4st3r.js");
38442
39057
  await stopOAuthKeepalive();
38443
39058
  }
38444
39059
  stopOAuthPendingGc();
@@ -38518,21 +39133,21 @@ try {
38518
39133
  console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
38519
39134
  }
38520
39135
  try {
38521
- const { ensurePricingSeeded } = await import("./boot-seeds-gbedmamp.js");
39136
+ const { ensurePricingSeeded } = await import("./boot-seeds-xs9a8dx1.js");
38522
39137
  ensurePricingSeeded();
38523
- const { startPricingRefreshLoop } = await import("./pricing-refresh-sdcf5yaz.js");
39138
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-5nvme3sm.js");
38524
39139
  startPricingRefreshLoop();
38525
39140
  } catch (err) {
38526
39141
  console.error("[startup] Failed to seed pricing rows:", err);
38527
39142
  }
38528
39143
  try {
38529
- const { ensureModelProfilesSeeded } = await import("./boot-seeds-gbedmamp.js");
39144
+ const { ensureModelProfilesSeeded } = await import("./boot-seeds-xs9a8dx1.js");
38530
39145
  await ensureModelProfilesSeeded();
38531
39146
  } catch (err) {
38532
39147
  console.error("[startup] Failed to seed model profiles:", err);
38533
39148
  }
38534
39149
  try {
38535
- const { ensureRbacSeeded } = await import("./boot-seeds-gbedmamp.js");
39150
+ const { ensureRbacSeeded } = await import("./boot-seeds-xs9a8dx1.js");
38536
39151
  ensureRbacSeeded();
38537
39152
  } catch (err) {
38538
39153
  console.error("[startup] Failed to sync RBAC seed rows:", err);
@@ -38540,7 +39155,7 @@ try {
38540
39155
  throw err;
38541
39156
  }
38542
39157
  try {
38543
- const { runAllSeeders } = await import("./index-6rmnn89d.js");
39158
+ const { runAllSeeders } = await import("./index-s7ckdajq.js");
38544
39159
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
38545
39160
  } catch (err) {
38546
39161
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -38602,39 +39217,39 @@ httpServer.listen(port, async () => {
38602
39217
  await initWorkflows2();
38603
39218
  await startScriptRunSupervisor(getMcpBaseUrl());
38604
39219
  if (hasCapability("scheduling")) {
38605
- const { startScheduler } = await import("./index-vjn3wbzf.js");
38606
- const { getExecutorRegistry } = await import("./index-xmmkyx82.js");
39220
+ const { startScheduler } = await import("./index-8pwc1jc8.js");
39221
+ const { getExecutorRegistry } = await import("./index-dg2tmj99.js");
38607
39222
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
38608
39223
  startScheduler(getExecutorRegistry(), intervalMs, {
38609
39224
  runId: globalState.__runId
38610
39225
  });
38611
39226
  }
38612
39227
  if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
38613
- const { startHeartbeat } = await import("./index-nyfcdpky.js");
39228
+ const { startHeartbeat } = await import("./index-nxa6me0q.js");
38614
39229
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
38615
39230
  startHeartbeat(heartbeatMs);
38616
39231
  }
38617
39232
  startPoolRouting();
38618
39233
  startRuntimeSupervisor();
38619
39234
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
38620
- const { startOAuthKeepalive } = await import("./keepalive-4djvbm2j.js");
39235
+ const { startOAuthKeepalive } = await import("./keepalive-3nr4st3r.js");
38621
39236
  startOAuthKeepalive();
38622
39237
  }
38623
39238
  if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
38624
- const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-fpd6x6rw.js");
39239
+ const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-9q2t0y3q.js");
38625
39240
  startOAuthRefreshSweep();
38626
39241
  }
38627
39242
  startOAuthPendingGc();
38628
39243
  await startMemoryGc();
38629
39244
  await startDbRetention();
38630
39245
  startHumanFreeDrain();
38631
- import("./boot-reembed-p666cw5n.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
39246
+ import("./boot-reembed-qr8a894z.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
38632
39247
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
38633
39248
  });
38634
- import("./boot-reembed-w6pm64j4.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
39249
+ import("./boot-reembed-rj85jjhw.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
38635
39250
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
38636
39251
  });
38637
- import("./boot-scrub-sweep-jcyjagn3.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
39252
+ import("./boot-scrub-sweep-eyfvn6v9.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
38638
39253
  console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
38639
39254
  });
38640
39255
  }).on("error", (err) => {