@desplega.ai/agent-swarm 2.7.0 → 2.7.1

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 (236) hide show
  1. package/dist/{acp-adapter-ma1js5n7.js → acp-adapter-8dn5tq56.js} +6 -6
  2. package/dist/{actions-1vhmtvg9.js → actions-3r6gw7dy.js} +18 -18
  3. package/dist/{amp-adapter-sxqqvmdk.js → amp-adapter-wjtq413p.js} +3 -3
  4. package/dist/{anthropic-messages-txs190dd.js → anthropic-messages-n4cby1rz.js} +4 -4
  5. package/dist/{app-mwx1d5a9.js → app-d53yhykk.js} +3 -3
  6. package/dist/{assistant-yx1p6g82.js → assistant-ksrawj3k.js} +20 -20
  7. package/dist/{boot-reembed-7h78vmvv.js → boot-reembed-fxfw17m2.js} +10 -3
  8. package/dist/{boot-reembed-5h37a2c2.js → boot-reembed-k5y5xbj0.js} +15 -8
  9. package/dist/{boot-scrub-sweep-8mawd4gw.js → boot-scrub-sweep-se41j9fd.js} +3 -3
  10. package/dist/{boot-seeds-ca84dhnn.js → boot-seeds-r3kwwv8b.js} +4 -4
  11. package/dist/{claude-adapter-wqt4hfkq.js → claude-adapter-ahmyf231.js} +7 -7
  12. package/dist/{claude-managed-adapter-6fjqtr2z.js → claude-managed-adapter-5knamegc.js} +3 -3
  13. package/dist/{claude-managed-setup-rqv98sea.js → claude-managed-setup-mdc7dy6b.js} +2 -2
  14. package/dist/{claude-sdk-session-f29f3b2x.js → claude-sdk-session-n5wen9zk.js} +8728 -8599
  15. package/dist/{cli-m5e802r7.js → cli-0dqtv2jg.js} +2 -2
  16. package/dist/{cli-e1595bgx.js → cli-0tww7dnz.js} +2 -2
  17. package/dist/{cli-2y7v133v.js → cli-0w4e4v58.js} +7 -7
  18. package/dist/{cli-d20qvpr2.js → cli-2sjm3t4r.js} +1 -1
  19. package/dist/{cli-gf2850q7.js → cli-3cywb44q.js} +18 -1
  20. package/dist/{cli-8wkb09q5.js → cli-3k9jej0c.js} +2 -2
  21. package/dist/{cli-twctnkng.js → cli-3v2cyqb8.js} +3 -3
  22. package/dist/{cli-he9gbdx0.js → cli-5qt9vzmq.js} +39 -20
  23. package/dist/{cli-a6ds2epe.js → cli-5rp1w4cr.js} +1 -1
  24. package/dist/{cli-6srv653c.js → cli-6vwjsetx.js} +4 -4
  25. package/dist/{cli-1hhbzkbb.js → cli-6w2yrrc0.js} +8 -8
  26. package/dist/{cli-f12mr20z.js → cli-75tdydgv.js} +1 -1
  27. package/dist/{cli-j3y0x2n4.js → cli-8feswf2v.js} +43 -33
  28. package/dist/{cli-07q03xm2.js → cli-8wd3mbyj.js} +1 -1
  29. package/dist/{cli-ymjpkxgn.js → cli-9csfthbw.js} +8 -6
  30. package/dist/{cli-f1e0ptjj.js → cli-b41p764a.js} +21 -2
  31. package/dist/{cli-kv7sbc2c.js → cli-c1t533hh.js} +3 -3
  32. package/dist/{cli-54sj64fc.js → cli-c28jxpcv.js} +1 -1
  33. package/dist/{cli-8mbc9za9.js → cli-cb50g9cd.js} +1 -1
  34. package/dist/{cli-c668vvcf.js → cli-d8gaphtr.js} +1 -1
  35. package/dist/{cli-86ehn4s5.js → cli-dgtfysne.js} +2 -2
  36. package/dist/{cli-sjctjr48.js → cli-dscnhn18.js} +1 -1
  37. package/dist/{cli-j0ppywdr.js → cli-dv11pgpv.js} +12 -12
  38. package/dist/{cli-1m9x8dr5.js → cli-ekptgk2m.js} +5 -5
  39. package/dist/{cli-9gsm2rzp.js → cli-f3mzy662.js} +17 -17
  40. package/dist/{cli-s0mgx214.js → cli-fk7k8s9x.js} +2 -2
  41. package/dist/{cli-vbhgkw9h.js → cli-h3e7bhvn.js} +3 -3
  42. package/dist/{cli-yd2nreqw.js → cli-hkxqdmnb.js} +2 -2
  43. package/dist/{cli-8wmj18cz.js → cli-hpkvgdad.js} +7 -4
  44. package/dist/{cli-wqr7cea4.js → cli-hq2v4rr5.js} +37 -9
  45. package/dist/{cli-sgqm2582.js → cli-k1zb7raw.js} +5 -5
  46. package/dist/{cli-4rvr7zfx.js → cli-k4awgvzm.js} +5 -0
  47. package/dist/{cli-ay40dnj3.js → cli-k7d3hvya.js} +2 -2
  48. package/dist/{cli-j9bpmykh.js → cli-kbtdftbw.js} +5 -5
  49. package/dist/{cli-x37r7qwf.js → cli-kj69b9tw.js} +25 -5
  50. package/dist/{cli-gsfk58nw.js → cli-kk9jy4nm.js} +1 -1
  51. package/dist/{cli-39aet655.js → cli-m52t4cta.js} +1 -1
  52. package/dist/{cli-h5jeg46p.js → cli-mdadewqp.js} +5 -5
  53. package/dist/{cli-a89zdqz9.js → cli-nf6k60sn.js} +1 -1
  54. package/dist/{cli-v6shg7na.js → cli-nzdf09js.js} +1 -1
  55. package/dist/{cli-rr7zx19j.js → cli-prcyzecg.js} +12 -12
  56. package/dist/{cli-6a9qfa8b.js → cli-pzafyqtk.js} +118 -48
  57. package/dist/{cli-48gxjmcz.js → cli-qvaa1gjp.js} +87 -24
  58. package/dist/{cli-qj442fws.js → cli-rg4b2g6j.js} +1 -1
  59. package/dist/{cli-aypd09nf.js → cli-rm66vqdz.js} +1 -1
  60. package/dist/{cli-9pshx6rd.js → cli-s504c3w7.js} +1 -1
  61. package/dist/{cli-ptfq202x.js → cli-swkx9jm2.js} +3 -3
  62. package/dist/{cli-m30k9777.js → cli-thsaq4pd.js} +16 -16
  63. package/dist/{cli-60sty27p.js → cli-twjnyvs8.js} +2 -2
  64. package/dist/{cli-rd5m70gj.js → cli-typdpe8g.js} +4 -4
  65. package/dist/{cli-yxbsmx56.js → cli-vg8pwmsd.js} +6 -6
  66. package/dist/{cli-s09j9vp5.js → cli-vhpckzvp.js} +1 -1
  67. package/dist/{cli-dv97kdzv.js → cli-wdxgsdz5.js} +2 -2
  68. package/dist/{cli-7a6p4e65.js → cli-wtjg6je3.js} +1 -1
  69. package/dist/{cli-b3yzyc57.js → cli-x3cngb1h.js} +44 -12
  70. package/dist/{cli-6mgdba42.js → cli-xbz6mcg4.js} +2 -2
  71. package/dist/{cli-2pvzmas1.js → cli-y4tdxsqb.js} +3 -3
  72. package/dist/{cli-f4dbh7a5.js → cli-yqrsp3ny.js} +7 -7
  73. package/dist/cli.js +27 -19
  74. package/dist/{codex-adapter-zk59x2zh.js → codex-adapter-7wepzq15.js} +5 -5
  75. package/dist/{codex-hook-xyjhvxwd.js → codex-hook-pbdh4xhx.js} +2 -2
  76. package/dist/{codex-session-runner-kh6s4j3n.js → codex-session-runner-02sb49e4.js} +5 -5
  77. package/dist/{commands-68et1qv2.js → commands-3rcspxct.js} +2 -2
  78. package/dist/{controller-fyrbnzg4.js → controller-8ar4avd6.js} +3 -3
  79. package/dist/{controllers-connect-nep9h2xv.js → controllers-connect-ajvh9h0v.js} +19 -19
  80. package/dist/{cursor-adapter-yss3pg7t.js → cursor-adapter-gd0sa7bh.js} +1 -1
  81. package/dist/{db-28gjyvxj.js → db-dv9j7ts5.js} +2 -2
  82. package/dist/{db-8ftwvzba.js → db-z26vgdvj.js} +3 -3
  83. package/dist/{dispatcher-hayexmkr.js → dispatcher-8m0htjq8.js} +17 -17
  84. package/dist/{dsh-adapter-46wawff9.js → dsh-adapter-y8gyk130.js} +1 -1
  85. package/dist/{e2b-fn3zacvt.js → e2b-74vg9b7e.js} +1 -1
  86. package/dist/{e2b-222hsajc.js → e2b-jyay8wzn.js} +1 -1
  87. package/dist/{easter-egg-3d-8d1e0h4m.js → easter-egg-3d-28f880xx.js} +1 -1
  88. package/dist/{execute-cjrfxfnm.js → execute-9seb79vh.js} +1 -1
  89. package/dist/{external-channel-xbmxcg09.js → external-channel-smz7jyth.js} +2 -2
  90. package/dist/{getMachineId-bsd-brn0xym3.js → getMachineId-bsd-whfre6gr.js} +3 -3
  91. package/dist/{getMachineId-darwin-t339sfxm.js → getMachineId-darwin-5zjynb19.js} +3 -3
  92. package/dist/{getMachineId-linux-5eq95d8b.js → getMachineId-linux-8mksrrsq.js} +3 -3
  93. package/dist/{getMachineId-unsupported-qavrtc7j.js → getMachineId-unsupported-fxtqsdt2.js} +3 -3
  94. package/dist/{getMachineId-win-q7fe1wx7.js → getMachineId-win-nzfmz857.js} +3 -3
  95. package/dist/{grok-adapter-ag4wks2a.js → grok-adapter-z0nnvtbn.js} +7 -7
  96. package/dist/handlers-pspryh6g.js +41 -0
  97. package/dist/{heartbeat-psfvcgwp.js → heartbeat-f928aqyp.js} +20 -20
  98. package/dist/{hook-cyq4mryn.js → hook-d7c605r4.js} +7 -7
  99. package/dist/{hook-8pz04697.js → hook-q9hv5xf9.js} +5 -5
  100. package/dist/{http-haj1nd6k.js → http-q6j4k989.js} +934 -180
  101. package/dist/{index-z5h22pes.js → index-5nb266jr.js} +17 -17
  102. package/dist/{index-ysd45kgc.js → index-8fxt5eah.js} +10 -10
  103. package/dist/{index-zgvqzjsw.js → index-cekzwhez.js} +5 -5
  104. package/dist/{index-zyq8ct52.js → index-ch0c1xff.js} +17 -17
  105. package/dist/{index-syvhnvtw.js → index-ebnjhxh1.js} +1 -1
  106. package/dist/{index-y1ajx04a.js → index-ed8dy8rn.js} +20 -20
  107. package/dist/{index-jwt2bj6f.js → index-ejqdkkqx.js} +11 -10
  108. package/dist/{index-dr94zbnh.js → index-farm1zsn.js} +32661 -29443
  109. package/dist/{index-q52f47pe.js → index-yn1yxg85.js} +1 -1
  110. package/dist/{keepalive-xdvsamvj.js → keepalive-zzc3hks1.js} +3 -3
  111. package/dist/{lead-hqg57kdp.js → lead-c0pjcaw4.js} +36 -36
  112. package/dist/{maintenance-4y2xzh3a.js → maintenance-kqsxzpzx.js} +1 -1
  113. package/dist/{oauth-refresh-sweep-jd4r7zbs.js → oauth-refresh-sweep-7qt0g55z.js} +2 -2
  114. package/dist/{onboard-18447q9q.js → onboard-k7x13fqg.js} +118 -5
  115. package/dist/{opencode-adapter-26b2frdf.js → opencode-adapter-tqvrtter.js} +5 -5
  116. package/dist/{otel-impl-f9tgr8yw.js → otel-impl-sqkf6k3b.js} +97 -97
  117. package/dist/{pi-mono-adapter-qn6qbga1.js → pi-mono-adapter-m2qnafxm.js} +63 -9
  118. package/dist/{pricing-refresh-dw2tgb53.js → pricing-refresh-wkpwhgvs.js} +3 -3
  119. package/dist/{rbac-roles-s4nwj2m3.js → rbac-roles-dpn0c0wj.js} +7 -4
  120. package/dist/{rbac-roles-aygm2760.js → rbac-roles-wk7xd6a6.js} +2 -2
  121. package/dist/{render-v2-yfvdfr0x.js → render-v2-ex2m4g2k.js} +3 -3
  122. package/dist/{resume-1bmvjbf3.js → resume-725g9b0b.js} +7 -7
  123. package/dist/{runtime-f7tpzedy.js → runtime-kajas15g.js} +1 -1
  124. package/dist/{session-access-r5garej6.js → session-access-0j2ezjje.js} +8 -4
  125. package/dist/{session-source-backfill-424wzv0r.js → session-source-backfill-62202awe.js} +2 -2
  126. package/dist/{setup-8tygvxkq.js → setup-9sj11ax6.js} +1 -1
  127. package/dist/{virtual-modules-xsw323b3.js → virtual-modules-c6fcq6zr.js} +2 -2
  128. package/dist/{work-objects-ggnghpgf.js → work-objects-0y07495y.js} +20 -20
  129. package/dist/{worker-sqjd1nqf.js → worker-d4q9sqbc.js} +36 -36
  130. package/openapi.json +1070 -9
  131. package/package.json +3 -3
  132. package/src/be/connector-codes.ts +65 -22
  133. package/src/be/memory/boot-reembed.ts +4 -1
  134. package/src/be/memory/constants.ts +6 -0
  135. package/src/be/memory/embedding-recovery.ts +48 -0
  136. package/src/be/memory/index-content.ts +5 -2
  137. package/src/be/memory/providers/openai-embedding.ts +65 -14
  138. package/src/be/memory/task-learning.ts +110 -8
  139. package/src/be/memory/types.ts +13 -2
  140. package/src/be/migrations/246_connector_code_kind.sql +11 -0
  141. package/src/be/onboarding.ts +125 -15
  142. package/src/be/rbac-roles.ts +4 -1
  143. package/src/be/scripts/embeddings.ts +2 -2
  144. package/src/be/seed/agent-fs-provision.ts +75 -14
  145. package/src/be/swarm-config-guard.ts +3 -0
  146. package/src/cli.tsx +9 -0
  147. package/src/comb/config.ts +6 -1
  148. package/src/commands/onboard/agent-fs-version.ts +5 -0
  149. package/src/commands/onboard/compose-generator.ts +112 -1
  150. package/src/commands/onboard/env-generator.ts +9 -0
  151. package/src/commands/onboard/tei-image.ts +12 -0
  152. package/src/commands/onboard/types.ts +7 -0
  153. package/src/commands/onboard.tsx +11 -1
  154. package/src/commands/runner.ts +14 -1
  155. package/src/http/agentfs-proxy.ts +369 -0
  156. package/src/http/all-routes.ts +1 -0
  157. package/src/http/codex-oauth-device.ts +8 -1
  158. package/src/http/fs.ts +64 -10
  159. package/src/http/inbox-state.ts +27 -1
  160. package/src/http/index.ts +4 -1
  161. package/src/http/memory.ts +7 -4
  162. package/src/http/onboarding.ts +139 -11
  163. package/src/http/session-access.ts +24 -0
  164. package/src/http/sessions.ts +10 -6
  165. package/src/http/tasks.ts +85 -11
  166. package/src/http/telemetry-ui.ts +1 -1
  167. package/src/http/user-roles.ts +4 -1
  168. package/src/http/users.ts +272 -3
  169. package/src/http/utils.ts +22 -3
  170. package/src/prompts/base-prompt.ts +24 -9
  171. package/src/prompts/session-templates.ts +26 -2
  172. package/src/providers/amp-adapter.ts +1 -1
  173. package/src/providers/codex-adapter.ts +6 -1
  174. package/src/providers/cursor-adapter.ts +1 -1
  175. package/src/providers/pi-mono-adapter.ts +58 -3
  176. package/src/rbac/legacy-policy.ts +1 -0
  177. package/src/rbac/permissions.ts +4 -0
  178. package/src/tests/agent-fs-provision-seeder.test.ts +261 -92
  179. package/src/tests/agentfs-proxy.test.ts +1106 -0
  180. package/src/tests/base-prompt.test.ts +69 -2
  181. package/src/tests/codex-adapter.test.ts +46 -8
  182. package/src/tests/codex-oauth-device.test.ts +12 -1
  183. package/src/tests/comb-config-guard.test.ts +20 -0
  184. package/src/tests/comb-links.test.ts +79 -1
  185. package/src/tests/comb-status.test.ts +44 -0
  186. package/src/tests/docs-index-footprint.test.js +3 -3
  187. package/src/tests/fixtures/onboard/baseline-states.ts +68 -0
  188. package/src/tests/fixtures/onboard/content.compose.yml.txt +190 -0
  189. package/src/tests/fixtures/onboard/content.env.txt +29 -0
  190. package/src/tests/fixtures/onboard/dev.compose.yml.txt +155 -0
  191. package/src/tests/fixtures/onboard/dev.env.txt +28 -0
  192. package/src/tests/fixtures/onboard/full-all.compose.yml.txt +582 -0
  193. package/src/tests/fixtures/onboard/full-all.env.txt +59 -0
  194. package/src/tests/fixtures/onboard/full.compose.yml.txt +435 -0
  195. package/src/tests/fixtures/onboard/full.env.txt +36 -0
  196. package/src/tests/fixtures/onboard/research.compose.yml.txt +155 -0
  197. package/src/tests/fixtures/onboard/research.env.txt +28 -0
  198. package/src/tests/fixtures/onboard/solo.compose.yml.txt +85 -0
  199. package/src/tests/fixtures/onboard/solo.env.txt +26 -0
  200. package/src/tests/http-log-scrubbing.test.ts +34 -1
  201. package/src/tests/http-task-write-ownership.test.ts +5 -1
  202. package/src/tests/invites-http.test.ts +464 -0
  203. package/src/tests/memory-embedding-input-cap.test.ts +122 -1
  204. package/src/tests/memory-embedding-recovery.test.ts +137 -0
  205. package/src/tests/onboard-compose.test.ts +142 -0
  206. package/src/tests/onboard-env.test.ts +24 -0
  207. package/src/tests/onboard-non-interactive.test.ts +29 -0
  208. package/src/tests/onboard-tei-image.test.ts +36 -0
  209. package/src/tests/onboarding.test.ts +451 -4
  210. package/src/tests/openai-embedding-provider.test.ts +105 -2
  211. package/src/tests/pi-mono-session-cost-on-abort.test.ts +270 -0
  212. package/src/tests/preload-env.test.ts +4 -0
  213. package/src/tests/preload.ts +4 -0
  214. package/src/tests/prompt-template-session.test.ts +19 -3
  215. package/src/tests/rbac-admission-e2e.test.ts +22 -6
  216. package/src/tests/rbac-admission.test.ts +342 -4
  217. package/src/tests/rbac-engine.test.ts +1 -0
  218. package/src/tests/rbac-roles.test.ts +9 -1
  219. package/src/tests/send-task-requester-gate.test.ts +64 -3
  220. package/src/tests/sessions-move.test.ts +39 -1
  221. package/src/tests/store-progress-learning.test.ts +95 -2
  222. package/src/tests/whoami-route.test.ts +41 -0
  223. package/src/tools/inject-learning.ts +1 -1
  224. package/src/tools/memory-edit.ts +1 -1
  225. package/src/tools/memory-search.ts +1 -1
  226. package/src/tools/store-progress.ts +5 -1
  227. package/src/tools/utils.ts +12 -1
  228. package/src/utils/constants.ts +39 -0
  229. package/src/utils/task-attachment-links.ts +15 -3
  230. package/templates/skills/swarm-docs/content.md +1 -1
  231. package/dist/handlers-tzmevqb5.js +0 -41
  232. package/dist/{azure-openai-responses-9kfwhmn7.js → azure-openai-responses-43asa23s.js} +0 -0
  233. package/dist/{node-vxx896fa.js → node-t28cc56b.js} +0 -0
  234. package/dist/{openai-codex-responses-79s8xnbh.js → openai-codex-responses-jhr3sjtm.js} +3 -3
  235. package/dist/{openai-completions-tdbyts0x.js → openai-completions-gs6yn37k.js} +3 -3
  236. /package/dist/{openai-responses-dm3t5vqp.js → openai-responses-jqm9vwwk.js} +0 -0
@@ -296,7 +296,7 @@ import {
296
296
  hasCapability,
297
297
  getEnabledCapabilities,
298
298
  createServer
299
- } from "./cli-6a9qfa8b.js";
299
+ } from "./cli-pzafyqtk.js";
300
300
  import {
301
301
  chatThreadOfContextKey,
302
302
  agentContextKey,
@@ -338,7 +338,9 @@ import {
338
338
  init_asset_key_audit,
339
339
  CredentialBindingSchema,
340
340
  placeholderForConfigKey,
341
+ isPrivateAddress,
341
342
  assertUrlSafe,
343
+ init_egress_guard,
342
344
  init_credential_broker,
343
345
  encryptSecret,
344
346
  decryptSecret,
@@ -406,6 +408,7 @@ import {
406
408
  getAllTasks2,
407
409
  getTasksCount2,
408
410
  getTaskStats2,
411
+ getInProgressTasksByContextKey2,
409
412
  getLatestScriptRunStepTaskByContextKey2,
410
413
  init_read,
411
414
  MODEL_PROFILE_CONFIG_KEY,
@@ -523,6 +526,7 @@ import {
523
526
  searchMemoryCandidates,
524
527
  init_search_candidates,
525
528
  getEmbeddingProvider2,
529
+ resetEmbeddingProvider2,
526
530
  getMemoryStore2,
527
531
  init_memory,
528
532
  searchScripts,
@@ -765,7 +769,7 @@ import {
765
769
  countScriptRunJournalSteps2,
766
770
  countScriptRunJournalAgentTaskSteps2,
767
771
  init_db3
768
- } from "./cli-48gxjmcz.js";
772
+ } from "./cli-qvaa1gjp.js";
769
773
  import {
770
774
  PRIMARY_ROLE_NAMES2,
771
775
  getUserGrant2,
@@ -776,22 +780,22 @@ import {
776
780
  assertNotLastAdmin2,
777
781
  setUserRoles2,
778
782
  init_rbac_roles
779
- } from "./cli-8wmj18cz.js";
780
- import"./cli-rd5m70gj.js";
783
+ } from "./cli-hpkvgdad.js";
784
+ import"./cli-typdpe8g.js";
781
785
  import {
782
786
  normalizeModelKey
783
- } from "./cli-d20qvpr2.js";
787
+ } from "./cli-2sjm3t4r.js";
784
788
  import {
785
789
  upsertModelCatalogOverlay,
786
790
  deleteModelCatalogOverlay,
787
791
  loadModelsCatalog,
788
792
  requestModelCatalogRefresh2
789
- } from "./cli-60sty27p.js";
793
+ } from "./cli-twjnyvs8.js";
790
794
  import {
791
795
  AMP_ESTIMATE_MODELS,
792
796
  ampBillsCacheWrites,
793
797
  resolveAmpModel
794
- } from "./cli-8mbc9za9.js";
798
+ } from "./cli-cb50g9cd.js";
795
799
  import {
796
800
  workflowEventBus2,
797
801
  init_event_bus
@@ -831,7 +835,7 @@ import {
831
835
  generateEdges,
832
836
  definitionNodeIds,
833
837
  validateDefinition
834
- } from "./cli-j0ppywdr.js";
838
+ } from "./cli-dv11pgpv.js";
835
839
  import {
836
840
  require_dist2,
837
841
  isInvalidClientError,
@@ -913,14 +917,14 @@ import {
913
917
  typecheckWithAmbient,
914
918
  typecheckScript,
915
919
  parseSkillContent
916
- } from "./cli-j9bpmykh.js";
920
+ } from "./cli-kbtdftbw.js";
917
921
  import {
918
922
  buildAuthorizationUrl,
919
923
  exchangeAuthorizationCode,
920
924
  oauthAppRowToProviderConfig,
921
925
  forceRefreshAuthorizationOrThrow,
922
926
  forceRefreshTokenOrThrow
923
- } from "./cli-aypd09nf.js";
927
+ } from "./cli-rm66vqdz.js";
924
928
  import {
925
929
  signalProcessGroup,
926
930
  detachedProcessGroup,
@@ -953,9 +957,9 @@ import {
953
957
  getSlackApp2,
954
958
  startSlackApp2,
955
959
  stopSlackApp2
956
- } from "./cli-m30k9777.js";
957
- import"./cli-s09j9vp5.js";
958
- import"./cli-1m9x8dr5.js";
960
+ } from "./cli-thsaq4pd.js";
961
+ import"./cli-vhpckzvp.js";
962
+ import"./cli-ekptgk2m.js";
959
963
  import {
960
964
  _fetchHolder,
961
965
  CLIENT_ID,
@@ -972,7 +976,7 @@ import {
972
976
  import {
973
977
  retryFailedRun2,
974
978
  cancelWorkflowRun2
975
- } from "./cli-twctnkng.js";
979
+ } from "./cli-3v2cyqb8.js";
976
980
  import {
977
981
  duplicateGuardedQueryKey,
978
982
  warnIfCorsAllowsAnyOrigin,
@@ -982,6 +986,7 @@ import {
982
986
  parseQueryParams,
983
987
  getPathSegments,
984
988
  wireHttpSpanLifecycle,
989
+ redactShareTokenInPath,
985
990
  safeRequestUrlForLog,
986
991
  agentWithCapacity,
987
992
  RequestBodyTooLargeError,
@@ -1011,13 +1016,15 @@ import {
1011
1016
  readableByFor2,
1012
1017
  SESSION_WRITE_DENIED2,
1013
1018
  hasSessionWrite2,
1019
+ NOT_YOUR_TASK_DENIED2,
1020
+ deniesNonOwnerTaskWrite2,
1014
1021
  denyParentAttach2,
1015
1022
  runtimeInstanceHeader,
1016
1023
  bodyTask,
1017
1024
  bodyListTask,
1018
1025
  describeRequestRoute,
1019
1026
  route
1020
- } from "./cli-wqr7cea4.js";
1027
+ } from "./cli-hq2v4rr5.js";
1021
1028
  import {
1022
1029
  FilesError,
1023
1030
  normalizeFilesError,
@@ -1045,7 +1052,7 @@ import {
1045
1052
  resolvePoolDelivery2,
1046
1053
  createPoolAgent2,
1047
1054
  init_db
1048
- } from "./cli-6srv653c.js";
1055
+ } from "./cli-6vwjsetx.js";
1049
1056
  import {
1050
1057
  RATING_MODEL_MAX_LENGTH,
1051
1058
  REFERENCES_SOURCE_MAX_LENGTH,
@@ -1055,14 +1062,17 @@ import"./cli-737pyqxr.js";
1055
1062
  import {
1056
1063
  startPoolRouting,
1057
1064
  stopPoolRouting,
1065
+ INVITE_CODE_TTL_MS,
1058
1066
  DEFAULT_CONNECTOR_CODE_LABEL,
1067
+ DEFAULT_INVITE_CODE_LABEL,
1059
1068
  createConnectorCode,
1060
1069
  exchangeConnectorCode,
1070
+ deleteUnusedInviteCodes,
1061
1071
  checkHeartbeatChecklist2,
1062
1072
  runHeartbeatSweep2,
1063
1073
  stopHeartbeat2
1064
- } from "./cli-he9gbdx0.js";
1065
- import"./cli-qj442fws.js";
1074
+ } from "./cli-5qt9vzmq.js";
1075
+ import"./cli-rg4b2g6j.js";
1066
1076
  import {
1067
1077
  import_websocket,
1068
1078
  import_websocket_server
@@ -1071,7 +1081,7 @@ import {
1071
1081
  runtimeSupervisorStatus,
1072
1082
  startRuntimeSupervisor,
1073
1083
  stopRuntimeSupervisor
1074
- } from "./cli-9gsm2rzp.js";
1084
+ } from "./cli-f3mzy662.js";
1075
1085
  import"./cli-ns59dc6r.js";
1076
1086
  import {
1077
1087
  ACP_TARGET_IDS
@@ -1092,14 +1102,14 @@ import {
1092
1102
  isUnknownModelError,
1093
1103
  checkProviderPoolKey,
1094
1104
  writeSkillsToFilesystem
1095
- } from "./cli-6mgdba42.js";
1105
+ } from "./cli-xbz6mcg4.js";
1096
1106
  import {
1097
1107
  inviteEmailToSharedOrg,
1098
1108
  ensureAgentFsCredentialsForAgent
1099
- } from "./cli-b3yzyc57.js";
1109
+ } from "./cli-x3cngb1h.js";
1100
1110
  import {
1101
1111
  Anthropic
1102
- } from "./cli-rr7zx19j.js";
1112
+ } from "./cli-prcyzecg.js";
1103
1113
  import {
1104
1114
  isCodexOAuthConfigKey
1105
1115
  } from "./cli-j4bwnpkm.js";
@@ -1116,6 +1126,7 @@ import {
1116
1126
  registerSessionTokenConnection,
1117
1127
  init_session_token_connections,
1118
1128
  findUserById,
1129
+ findUserByEmail,
1119
1130
  getUserIdentities,
1120
1131
  listUserEvents,
1121
1132
  listUserTokens,
@@ -1136,7 +1147,7 @@ import {
1136
1147
  revokeAgentTokens,
1137
1148
  fingerprintApiKey,
1138
1149
  init_users
1139
- } from "./cli-a89zdqz9.js";
1150
+ } from "./cli-nf6k60sn.js";
1140
1151
  import"./cli-v41kn3cd.js";
1141
1152
  import"./cli-wgtk7xxr.js";
1142
1153
  import"./cli-1f0gp9vz.js";
@@ -1151,7 +1162,7 @@ import {
1151
1162
  clearAuditSink,
1152
1163
  can,
1153
1164
  init_rbac
1154
- } from "./cli-4rvr7zfx.js";
1165
+ } from "./cli-k4awgvzm.js";
1155
1166
  import {
1156
1167
  ASSET_KEY_MAX_LENGTH,
1157
1168
  normalizeAssetKey,
@@ -1302,12 +1313,12 @@ import {
1302
1313
  KvKeySchema,
1303
1314
  KvEntrySchema,
1304
1315
  init_types
1305
- } from "./cli-9pshx6rd.js";
1316
+ } from "./cli-s504c3w7.js";
1306
1317
  import {
1307
1318
  IDENTITY_FIELD_BUDGETS,
1308
1319
  IdentityFieldBudgetError,
1309
1320
  init_identity_field_budget
1310
- } from "./cli-x37r7qwf.js";
1321
+ } from "./cli-kj69b9tw.js";
1311
1322
  import {
1312
1323
  isSteeringEnabled2,
1313
1324
  init_steering_enabled
@@ -1344,7 +1355,7 @@ import {
1344
1355
  resolveTemplate,
1345
1356
  init_resolver,
1346
1357
  init_session_templates
1347
- } from "./cli-f1e0ptjj.js";
1358
+ } from "./cli-b41p764a.js";
1348
1359
  import {
1349
1360
  init_zod
1350
1361
  } from "./cli-4chz1hye.js";
@@ -1379,25 +1390,28 @@ import {
1379
1390
  import {
1380
1391
  init_package,
1381
1392
  package_default
1382
- } from "./cli-ptfq202x.js";
1383
- import {
1384
- realtimeBus,
1385
- init_bus
1386
- } from "./cli-syfdvhkc.js";
1393
+ } from "./cli-swkx9jm2.js";
1387
1394
  import {
1388
1395
  MAX_PROFILE_FILE_LENGTH,
1396
+ DEFAULT_APP_URL,
1389
1397
  getConfiguredAppUrls,
1390
1398
  getAppUrl,
1391
1399
  getMcpBaseUrl,
1392
1400
  getPublicMcpBaseUrl,
1393
1401
  agentFsFileRoute,
1402
+ isCombEnabled,
1403
+ isAgentFsProxyEnabled,
1394
1404
  init_constants2
1395
- } from "./cli-gf2850q7.js";
1405
+ } from "./cli-3cywb44q.js";
1396
1406
  import {
1397
1407
  parseEnvFlag,
1398
1408
  isEnvFlagEnabled,
1399
1409
  init_env_flag
1400
1410
  } from "./cli-cebvbc9t.js";
1411
+ import {
1412
+ realtimeBus,
1413
+ init_bus
1414
+ } from "./cli-syfdvhkc.js";
1401
1415
  import {
1402
1416
  getApiKey,
1403
1417
  init_api_key
@@ -4283,6 +4297,353 @@ async function handleActiveSessions(req, res, pathSegments, queryParams, myAgent
4283
4297
  return false;
4284
4298
  }
4285
4299
 
4300
+ // src/http/agentfs-proxy.ts
4301
+ init_api_key();
4302
+ init_constants2();
4303
+ import { Readable } from "node:stream";
4304
+
4305
+ // src/http/ip-rate-limit.ts
4306
+ var PRUNE_THRESHOLD = 1e4;
4307
+ var PRUNE_INTERVAL_MS = 60000;
4308
+ var MAX_BUCKETS = 50000;
4309
+ function isPrivateAddress2(address) {
4310
+ const ip = address.startsWith("::ffff:") ? address.slice(7) : address;
4311
+ if (ip === "::1" || ip.startsWith("127.") || ip.startsWith("10."))
4312
+ return true;
4313
+ if (ip.startsWith("192.168.") || ip.startsWith("169.254."))
4314
+ return true;
4315
+ const match = /^172\.(\d+)\./.exec(ip);
4316
+ if (match && Number(match[1]) >= 16 && Number(match[1]) <= 31)
4317
+ return true;
4318
+ const lower = ip.toLowerCase();
4319
+ return lower.startsWith("fc") || lower.startsWith("fd") || lower.startsWith("fe80:");
4320
+ }
4321
+ function clientIp(req) {
4322
+ const peer = req.socket.remoteAddress ?? "unknown";
4323
+ if (!isPrivateAddress2(peer))
4324
+ return peer;
4325
+ const raw = req.headers["x-forwarded-for"];
4326
+ const header = Array.isArray(raw) ? raw[raw.length - 1] : raw;
4327
+ const hop = header?.split(",").pop()?.trim();
4328
+ return hop || peer;
4329
+ }
4330
+ function createIpRateLimiter(options) {
4331
+ const buckets = new Map;
4332
+ let lastPruneAt = 0;
4333
+ function refill(bucket, now) {
4334
+ const elapsed = now - bucket.updatedAt;
4335
+ bucket.tokens = Math.min(options.capacity, bucket.tokens + elapsed * options.refillPerMs);
4336
+ bucket.updatedAt = now;
4337
+ }
4338
+ return {
4339
+ take(ip, now = Date.now()) {
4340
+ if (buckets.size > PRUNE_THRESHOLD && now - lastPruneAt >= PRUNE_INTERVAL_MS) {
4341
+ lastPruneAt = now;
4342
+ for (const [key, bucket] of buckets) {
4343
+ refill(bucket, now);
4344
+ if (bucket.tokens >= options.capacity)
4345
+ buckets.delete(key);
4346
+ }
4347
+ }
4348
+ let bucket = buckets.get(ip);
4349
+ if (!bucket) {
4350
+ if (buckets.size >= MAX_BUCKETS) {
4351
+ const oldest = buckets.keys().next().value;
4352
+ if (oldest !== undefined)
4353
+ buckets.delete(oldest);
4354
+ }
4355
+ bucket = { tokens: options.capacity, updatedAt: now };
4356
+ buckets.set(ip, bucket);
4357
+ }
4358
+ refill(bucket, now);
4359
+ if (bucket.tokens < 1)
4360
+ return false;
4361
+ bucket.tokens -= 1;
4362
+ return true;
4363
+ },
4364
+ reset() {
4365
+ buckets.clear();
4366
+ lastPruneAt = 0;
4367
+ }
4368
+ };
4369
+ }
4370
+
4371
+ // src/http/agentfs-proxy.ts
4372
+ var API_PREFIX = "/agentfs";
4373
+ var PUBLIC_PREFIXES = ["/share/", "/site/"];
4374
+ function upstreamBase() {
4375
+ const v = process.env.AGENT_FS_API_URL?.trim().replace(/\/+$/, "");
4376
+ return v || null;
4377
+ }
4378
+ var REQUEST_HEADER_ALLOWLIST = [
4379
+ "content-type",
4380
+ "content-length",
4381
+ "accept",
4382
+ "if-match",
4383
+ "if-none-match",
4384
+ "range",
4385
+ "x-agent-fs-message",
4386
+ "x-agent-fs-message-encoding"
4387
+ ];
4388
+ var AGENT_FS_BEARER = /^Bearer\s+af_\S+$/i;
4389
+ var RESPONSE_HEADER_ALLOWLIST = new Set([
4390
+ "content-type",
4391
+ "content-length",
4392
+ "content-disposition",
4393
+ "content-range",
4394
+ "accept-ranges",
4395
+ "etag",
4396
+ "last-modified",
4397
+ "cache-control",
4398
+ "location",
4399
+ "retry-after",
4400
+ "content-security-policy",
4401
+ "x-content-type-options",
4402
+ "x-frame-options",
4403
+ "referrer-policy",
4404
+ "x-robots-tag",
4405
+ "cross-origin-resource-policy"
4406
+ ]);
4407
+ var EXPOSED_HEADERS = ["X-Agent-FS-Version", "X-Agent-FS-Content-Hash", "Content-Disposition"];
4408
+ var UNGATED = "agent-fs enforces its own af_ auth; register needs a swarm credential; swarm credentials are never forwarded";
4409
+ var OK_200 = {
4410
+ description: "Upstream agent-fs response, streamed verbatim",
4411
+ unstructured: "Body is streamed from agent-fs; shape and content-type vary per upstream route"
4412
+ };
4413
+ for (const method of ["get", "post", "put", "delete", "patch"]) {
4414
+ route({
4415
+ method,
4416
+ path: "/agentfs/{path}",
4417
+ pattern: ["agentfs", null],
4418
+ exact: false,
4419
+ summary: "Streaming pass-through proxy to agent-fs (enabled by AGENT_FS_PROXY)",
4420
+ tags: ["Comb"],
4421
+ responses: {
4422
+ 200: OK_200,
4423
+ 401: {
4424
+ description: "Returned by agent-fs when credentials are missing or invalid, or by the swarm when POST /agentfs/auth/register has no swarm credential"
4425
+ },
4426
+ 403: {
4427
+ description: "POST /agentfs/auth/register with a user token for an email that is not the user's"
4428
+ },
4429
+ 413: { description: "POST /agentfs/auth/register body over 16 KB" },
4430
+ 429: { description: "Too many registrations from this IP (POST /agentfs/auth/register)" },
4431
+ 502: { description: "agent-fs is unreachable" }
4432
+ },
4433
+ auth: { apiKey: false },
4434
+ ...method === "get" ? {} : { rbac: { ungated: UNGATED } }
4435
+ });
4436
+ }
4437
+ for (const prefix of ["share", "site"]) {
4438
+ route({
4439
+ method: "get",
4440
+ path: `/${prefix}/{path}`,
4441
+ pattern: [prefix, null],
4442
+ exact: false,
4443
+ summary: `Public agent-fs ${prefix} page, served through the API (enabled by AGENT_FS_PROXY)`,
4444
+ tags: ["Comb"],
4445
+ responses: {
4446
+ 200: {
4447
+ description: `agent-fs /${prefix} response, streamed verbatim`,
4448
+ unstructured: "HTML page or raw file streamed from agent-fs; content-type varies"
4449
+ },
4450
+ 404: { description: "Unknown or expired link (from agent-fs), or the proxy is off" },
4451
+ 502: { description: "agent-fs is unreachable" }
4452
+ },
4453
+ auth: { apiKey: false }
4454
+ });
4455
+ }
4456
+ var registerRateLimiter = createIpRateLimiter({ capacity: 5, refillPerMs: 5 / 60000 });
4457
+ var REGISTER_BODY_MAX_BYTES = 16 * 1024;
4458
+ async function checkRegister(req, res) {
4459
+ const auth = await resolveHttpRequestAuth(req, getApiKey());
4460
+ if (!auth || auth.page || auth.kind !== "operator" && auth.kind !== "user") {
4461
+ jsonError(res, "Creating an agent-fs account here needs a swarm API key or user token", 401);
4462
+ return null;
4463
+ }
4464
+ let body;
4465
+ try {
4466
+ body = await parseBody(req, REGISTER_BODY_MAX_BYTES);
4467
+ } catch (err) {
4468
+ if (err instanceof RequestBodyTooLargeError)
4469
+ jsonError(res, "Request body too large", 413);
4470
+ else
4471
+ jsonError(res, "Invalid JSON body", 400);
4472
+ return null;
4473
+ }
4474
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
4475
+ jsonError(res, "Invalid JSON body", 400);
4476
+ return null;
4477
+ }
4478
+ if (auth.kind === "user") {
4479
+ const email = body.email;
4480
+ const own = [auth.user.email, ...auth.user.emailAliases].filter((e) => typeof e === "string").map((e) => e.trim().toLowerCase());
4481
+ if (typeof email !== "string" || !own.includes(email.trim().toLowerCase())) {
4482
+ jsonError(res, "You can create an agent-fs account only for your own email", 403);
4483
+ return null;
4484
+ }
4485
+ }
4486
+ return JSON.stringify(body);
4487
+ }
4488
+ function routedPath(pathOnly) {
4489
+ let decoded = pathOnly;
4490
+ try {
4491
+ decoded = decodeURIComponent(pathOnly);
4492
+ } catch {}
4493
+ return decoded.replace(/\/{2,}/g, "/").replace(/\/+$/, "");
4494
+ }
4495
+ function isNonCanonical(pathOnly) {
4496
+ let decoded = pathOnly;
4497
+ try {
4498
+ decoded = decodeURIComponent(pathOnly);
4499
+ } catch {}
4500
+ for (const p of [pathOnly, decoded]) {
4501
+ if (p.includes("\\"))
4502
+ return true;
4503
+ if (p.split("/").some((s) => s === "." || s === ".."))
4504
+ return true;
4505
+ }
4506
+ return pathOnly.split("/").some((s) => /^(\.|%2e){1,2}$/i.test(s));
4507
+ }
4508
+ async function handleAgentFsProxy(req, res) {
4509
+ const url = req.url ?? "";
4510
+ const isApi = url.startsWith(`${API_PREFIX}/`);
4511
+ const isPublicPage = !isApi && PUBLIC_PREFIXES.some((p) => url.startsWith(p));
4512
+ if (!isApi && !isPublicPage)
4513
+ return false;
4514
+ const base = upstreamBase();
4515
+ if (!base || !isAgentFsProxyEnabled())
4516
+ return false;
4517
+ const method = req.method ?? "GET";
4518
+ const allowed = isApi ? ["GET", "POST", "PUT", "DELETE", "PATCH"] : ["GET"];
4519
+ if (!allowed.includes(method))
4520
+ return false;
4521
+ const upstreamPath = isApi ? url.slice(API_PREFIX.length) : url;
4522
+ const queryStart = upstreamPath.indexOf("?");
4523
+ const pathOnly = queryStart === -1 ? upstreamPath : upstreamPath.slice(0, queryStart);
4524
+ if (isNonCanonical(pathOnly)) {
4525
+ jsonError(res, "Invalid path", 400);
4526
+ return true;
4527
+ }
4528
+ const upstreamUrl = `${base}${upstreamPath}`;
4529
+ let sentPath;
4530
+ try {
4531
+ const basePath = new URL(base).pathname.replace(/\/+$/, "");
4532
+ sentPath = new URL(upstreamUrl).pathname.slice(basePath.length);
4533
+ } catch {
4534
+ jsonError(res, "Invalid path", 400);
4535
+ return true;
4536
+ }
4537
+ const isRegister = isApi && method === "POST" && routedPath(sentPath) === "/auth/register";
4538
+ if (isRegister && !registerRateLimiter.take(clientIp(req))) {
4539
+ res.setHeader("Retry-After", "12");
4540
+ jsonError(res, "rate_limited", 429);
4541
+ return true;
4542
+ }
4543
+ const registerBody = isRegister ? await checkRegister(req, res) : null;
4544
+ if (isRegister && registerBody === null)
4545
+ return true;
4546
+ const headers = new Headers;
4547
+ const authorization = req.headers.authorization?.trim();
4548
+ if (registerBody === null && authorization && AGENT_FS_BEARER.test(authorization) && authorization.replace(/^bearer\s+/i, "") !== getApiKey()) {
4549
+ headers.set("authorization", authorization);
4550
+ }
4551
+ for (const name of REQUEST_HEADER_ALLOWLIST) {
4552
+ const v = req.headers[name];
4553
+ if (typeof v === "string")
4554
+ headers.set(name, v);
4555
+ }
4556
+ if (registerBody !== null) {
4557
+ headers.delete("content-length");
4558
+ headers.set("content-type", "application/json");
4559
+ }
4560
+ const ac = new AbortController;
4561
+ res.on("close", () => {
4562
+ if (!res.writableEnded)
4563
+ ac.abort();
4564
+ });
4565
+ const hasBody = method !== "GET" && method !== "DELETE";
4566
+ let upstream;
4567
+ try {
4568
+ const init = {
4569
+ method,
4570
+ headers,
4571
+ redirect: "manual",
4572
+ signal: ac.signal
4573
+ };
4574
+ if (registerBody !== null) {
4575
+ init.body = registerBody;
4576
+ } else if (hasBody) {
4577
+ init.body = Readable.toWeb(req);
4578
+ init.duplex = "half";
4579
+ }
4580
+ upstream = await fetch(upstreamUrl, init);
4581
+ } catch {
4582
+ if (!res.headersSent && !res.destroyed)
4583
+ jsonError(res, "agent-fs upstream unavailable", 502);
4584
+ else
4585
+ res.destroy();
4586
+ return true;
4587
+ }
4588
+ if (isPublicPage) {
4589
+ for (const name of res.getHeaderNames()) {
4590
+ if (name.startsWith("access-control-"))
4591
+ res.removeHeader(name);
4592
+ }
4593
+ }
4594
+ const encoded = upstream.headers.has("content-encoding");
4595
+ upstream.headers.forEach((value, name) => {
4596
+ const n = name.toLowerCase();
4597
+ const keep = RESPONSE_HEADER_ALLOWLIST.has(n) || n.startsWith("x-agent-fs-") || isPublicPage && n.startsWith("access-control-");
4598
+ if (!keep)
4599
+ return;
4600
+ if (encoded && n === "content-length")
4601
+ return;
4602
+ res.setHeader(name, value);
4603
+ });
4604
+ if (isApi) {
4605
+ const expose = res.getHeader("Access-Control-Expose-Headers");
4606
+ if (typeof expose === "string" && expose !== "*") {
4607
+ res.setHeader("Access-Control-Expose-Headers", `${expose}, ${EXPOSED_HEADERS.join(", ")}`);
4608
+ }
4609
+ }
4610
+ res.writeHead(upstream.status);
4611
+ if (!upstream.body) {
4612
+ res.end();
4613
+ return true;
4614
+ }
4615
+ await pump(upstream.body, res);
4616
+ return true;
4617
+ }
4618
+ async function pump(body, res) {
4619
+ const reader = body.getReader();
4620
+ const closed = new Promise((resolve) => {
4621
+ if (res.destroyed)
4622
+ resolve();
4623
+ else
4624
+ res.once("close", () => resolve());
4625
+ });
4626
+ try {
4627
+ for (;; ) {
4628
+ if (res.destroyed)
4629
+ break;
4630
+ const { done, value } = await reader.read();
4631
+ if (done) {
4632
+ res.end();
4633
+ break;
4634
+ }
4635
+ if (!res.write(value)) {
4636
+ await Promise.race([new Promise((resolve) => res.once("drain", resolve)), closed]);
4637
+ }
4638
+ }
4639
+ } catch {
4640
+ res.destroy();
4641
+ } finally {
4642
+ reader.cancel().catch(() => {});
4643
+ }
4644
+ await closed;
4645
+ }
4646
+
4286
4647
  // src/http/agents.ts
4287
4648
  init_src2();
4288
4649
  init_zod();
@@ -8383,6 +8744,7 @@ var OnboardingStepIdSchema = _enum2([
8383
8744
  "agents",
8384
8745
  "memory",
8385
8746
  "integrations",
8747
+ "files",
8386
8748
  "first_task"
8387
8749
  ]);
8388
8750
  var OnboardingErrorClassSchema = _enum2([
@@ -8418,6 +8780,14 @@ var OnboardingMemoryPresetSchema = _enum2([
8418
8780
  "custom",
8419
8781
  "existing"
8420
8782
  ]);
8783
+ var OnboardingMemoryProviderSchema = _enum2([
8784
+ "local",
8785
+ "openai",
8786
+ "openrouter",
8787
+ "vercel",
8788
+ "azure",
8789
+ "custom"
8790
+ ]);
8421
8791
  var OnboardingIntegrationMethodSchema = _enum2([
8422
8792
  "slack",
8423
8793
  "github",
@@ -8426,6 +8796,7 @@ var OnboardingIntegrationMethodSchema = _enum2([
8426
8796
  "linear_oauth",
8427
8797
  "jira_oauth"
8428
8798
  ]);
8799
+ var OnboardingFilesMethodSchema = _enum2(["created", "connected"]);
8429
8800
  var OnboardingFirstTaskMethodSchema = _enum2(["suggestion", "free_form"]);
8430
8801
  var OnboardingStepMethodSchema = union2([
8431
8802
  OnboardingConnectMethodSchema,
@@ -8434,6 +8805,7 @@ var OnboardingStepMethodSchema = union2([
8434
8805
  OnboardingAgentsMethodSchema,
8435
8806
  OnboardingMemoryPresetSchema,
8436
8807
  OnboardingIntegrationMethodSchema,
8808
+ OnboardingFilesMethodSchema,
8437
8809
  OnboardingFirstTaskMethodSchema
8438
8810
  ]);
8439
8811
  function onboardingStepStateSchema(method) {
@@ -8455,6 +8827,7 @@ var OnboardingAiStepStateSchema = onboardingStepStateSchema(OnboardingAiMethodSc
8455
8827
  var OnboardingAgentsStepStateSchema = onboardingStepStateSchema(OnboardingAgentsMethodSchema);
8456
8828
  var OnboardingMemoryStepStateSchema = onboardingStepStateSchema(OnboardingMemoryPresetSchema);
8457
8829
  var OnboardingIntegrationStepStateSchema = onboardingStepStateSchema(OnboardingIntegrationMethodSchema);
8830
+ var OnboardingFilesStepStateSchema = onboardingStepStateSchema(OnboardingFilesMethodSchema);
8458
8831
  var OnboardingFirstTaskStepStateSchema = onboardingStepStateSchema(OnboardingFirstTaskMethodSchema);
8459
8832
  var OnboardingStateSchema = object2({
8460
8833
  version: literal2(1),
@@ -8472,6 +8845,7 @@ var OnboardingStateSchema = object2({
8472
8845
  agents: OnboardingAgentsStepStateSchema,
8473
8846
  memory: OnboardingMemoryStepStateSchema,
8474
8847
  integrations: OnboardingIntegrationStepStateSchema,
8848
+ files: OnboardingFilesStepStateSchema,
8475
8849
  first_task: OnboardingFirstTaskStepStateSchema
8476
8850
  })
8477
8851
  });
@@ -8486,7 +8860,11 @@ var OnboardingSignalsSchema = object2({
8486
8860
  })),
8487
8861
  embeddings: object2({
8488
8862
  configured: boolean(),
8489
- dimensions: number2().int().positive()
8863
+ dimensions: number2().int().positive(),
8864
+ model: string2().nullable(),
8865
+ local: boolean(),
8866
+ provider: OnboardingMemoryProviderSchema.nullable(),
8867
+ localDefault: object2({ model: string2() }).nullable()
8490
8868
  }),
8491
8869
  integrations: object2({
8492
8870
  slack: boolean(),
@@ -8500,7 +8878,8 @@ var OnboardingSignalsSchema = object2({
8500
8878
  leadsOnline: number2().int().nonnegative(),
8501
8879
  workersOnline: number2().int().nonnegative()
8502
8880
  }),
8503
- firstTask: object2({ id: string2(), status: string2() }).nullable()
8881
+ firstTask: object2({ id: string2(), status: string2() }).nullable(),
8882
+ files: object2({ enabled: boolean() })
8504
8883
  });
8505
8884
  var OnboardingResponseSchema = object2({
8506
8885
  state: OnboardingStateSchema,
@@ -8533,9 +8912,14 @@ var OnboardingActionSchema = union2([
8533
8912
  step: literal2("integrations"),
8534
8913
  method: OnboardingIntegrationMethodSchema
8535
8914
  }).strict(),
8915
+ object2({
8916
+ action: literal2("complete"),
8917
+ step: literal2("files"),
8918
+ method: OnboardingFilesMethodSchema
8919
+ }).strict(),
8536
8920
  object2({
8537
8921
  action: literal2("skip"),
8538
- step: _enum2(["name", "ai", "agents", "memory", "integrations", "first_task"])
8922
+ step: _enum2(["name", "ai", "agents", "memory", "integrations", "files", "first_task"])
8539
8923
  }).strict(),
8540
8924
  object2({
8541
8925
  action: literal2("fail"),
@@ -8564,8 +8948,12 @@ var OnboardingMemoryRequestSchema = object2({
8564
8948
  baseUrl: OnboardingHttpUrlSchema.optional(),
8565
8949
  model: string2().trim().min(1).optional(),
8566
8950
  apiKey: string2().min(1).optional(),
8567
- reuseKey: _enum2(["OPENAI_API_KEY", "OPENROUTER_API_KEY"]).optional()
8568
- }).strict();
8951
+ reuseKey: _enum2(["OPENAI_API_KEY", "OPENROUTER_API_KEY"]).optional(),
8952
+ restoreDefault: boolean().optional()
8953
+ }).strict().refine((body) => !body.restoreDefault || body.preset === "existing", {
8954
+ message: "restoreDefault needs preset existing",
8955
+ path: ["restoreDefault"]
8956
+ });
8569
8957
  var OnboardingMemoryResponseSchema = object2({
8570
8958
  ok: boolean(),
8571
8959
  dimensions: number2().int().positive().optional(),
@@ -8593,6 +8981,7 @@ function freshState(now, autoCompleted) {
8593
8981
  agents: emptyStep(),
8594
8982
  memory: emptyStep(),
8595
8983
  integrations: emptyStep(),
8984
+ files: emptyStep(),
8596
8985
  first_task: emptyStep()
8597
8986
  }
8598
8987
  };
@@ -8751,6 +9140,14 @@ function deriveState(state, signals, funnelEvents) {
8751
9140
  }
8752
9141
  return changed;
8753
9142
  }
9143
+ function presentState(state, signals) {
9144
+ if (signals.files.enabled || state.steps.files.status !== "todo")
9145
+ return state;
9146
+ return {
9147
+ ...state,
9148
+ steps: { ...state.steps, files: { ...state.steps.files, status: "skipped" } }
9149
+ };
9150
+ }
8754
9151
 
8755
9152
  class OnboardingTaskNotFoundError extends Error {
8756
9153
  }
@@ -8820,7 +9217,7 @@ async function readOrUpdateOnboarding(loadSignals, action) {
8820
9217
  readOnly: true
8821
9218
  });
8822
9219
  if (!read.dirty)
8823
- return { state: read.state, signals: read.signals };
9220
+ return { state: presentState(read.state, read.signals), signals: read.signals };
8824
9221
  }
8825
9222
  return await client.transaction(async () => {
8826
9223
  const events = [];
@@ -8835,20 +9232,30 @@ async function readOrUpdateOnboarding(loadSignals, action) {
8835
9232
  if (dirty)
8836
9233
  await persistState(state);
8837
9234
  queueTelemetry(events);
8838
- return { state, signals };
9235
+ return { state: presentState(state, signals), signals };
8839
9236
  });
8840
9237
  }
8841
- async function updateOnboardingMemory(preset, result, saveConfig) {
9238
+ var EMBEDDING_PREFIX_KEYS = [
9239
+ "EMBEDDING_QUERY_PREFIX",
9240
+ "EMBEDDING_DOCUMENT_PREFIX"
9241
+ ];
9242
+ var EMBEDDING_CONFIG_KEYS = [
9243
+ "EMBEDDING_API_BASE_URL",
9244
+ "EMBEDDING_MODEL",
9245
+ "EMBEDDING_API_KEY",
9246
+ ...EMBEDDING_PREFIX_KEYS
9247
+ ];
9248
+ async function updateOnboardingMemory(preset, result, change) {
8842
9249
  return await getDbClient2().transaction(async () => {
8843
9250
  const events = [];
8844
9251
  const loaded = await loadState(events);
8845
9252
  let dirty = loaded.dirty;
8846
9253
  const eventsForState = loaded.state.autoCompleted ? [] : events;
8847
- if (saveConfig) {
9254
+ if (change?.kind === "save") {
8848
9255
  const configValues = [
8849
- ["EMBEDDING_API_BASE_URL", saveConfig.baseUrl],
8850
- ["EMBEDDING_MODEL", saveConfig.model],
8851
- ...saveConfig.apiKey ? [["EMBEDDING_API_KEY", saveConfig.apiKey]] : []
9256
+ ["EMBEDDING_API_BASE_URL", change.baseUrl],
9257
+ ["EMBEDDING_MODEL", change.model],
9258
+ ...change.apiKey ? [["EMBEDDING_API_KEY", change.apiKey]] : []
8852
9259
  ];
8853
9260
  for (const [key, value] of configValues) {
8854
9261
  const validationError = validateConfigValue(key, value);
@@ -8858,17 +9265,26 @@ async function updateOnboardingMemory(preset, result, saveConfig) {
8858
9265
  await upsertSwarmConfig2({
8859
9266
  scope: "global",
8860
9267
  key: "EMBEDDING_API_BASE_URL",
8861
- value: saveConfig.baseUrl
9268
+ value: change.baseUrl
8862
9269
  });
8863
- await upsertSwarmConfig2({ scope: "global", key: "EMBEDDING_MODEL", value: saveConfig.model });
8864
- if (saveConfig.apiKey) {
9270
+ await upsertSwarmConfig2({ scope: "global", key: "EMBEDDING_MODEL", value: change.model });
9271
+ if (change.apiKey) {
8865
9272
  await upsertSwarmConfig2({
8866
9273
  scope: "global",
8867
9274
  key: "EMBEDDING_API_KEY",
8868
- value: saveConfig.apiKey,
9275
+ value: change.apiKey,
8869
9276
  isSecret: true
8870
9277
  });
8871
9278
  }
9279
+ for (const { key, value } of change.prefixes) {
9280
+ if (value === null)
9281
+ await deleteSwarmConfigByKey2("global", null, key);
9282
+ else
9283
+ await upsertSwarmConfig2({ scope: "global", key, value });
9284
+ }
9285
+ } else if (change?.kind === "restore") {
9286
+ for (const key of EMBEDDING_CONFIG_KEYS)
9287
+ await deleteSwarmConfigByKey2("global", null, key);
8872
9288
  }
8873
9289
  if (result.ok) {
8874
9290
  dirty = completeStep(loaded.state, "memory", preset, false, eventsForState) || dirty;
@@ -8878,7 +9294,7 @@ async function updateOnboardingMemory(preset, result, saveConfig) {
8878
9294
  if (dirty)
8879
9295
  await persistState(loaded.state);
8880
9296
  queueTelemetry(events);
8881
- return saveConfig !== undefined;
9297
+ return change !== undefined;
8882
9298
  });
8883
9299
  }
8884
9300
  async function updateOnboardingAiFromCodexDevice(result) {
@@ -9152,6 +9568,9 @@ async function completeFlow(flowId, credentials) {
9152
9568
  isSecret: true,
9153
9569
  description: `Codex ChatGPT OAuth credentials slot ${slot} (stored by dashboard device login)`
9154
9570
  });
9571
+ const keySuffix = deriveCodexKeySuffix(credentials.access, credentials.accountId);
9572
+ const checked = [{ keyIndex: slot, keySuffix, ok: true }];
9573
+ await recordKeyValidation2("CODEX_OAUTH", checked, "global", null, { retireAbsent: false });
9155
9574
  await updateOnboardingAiFromCodexDevice({ status: "complete" });
9156
9575
  state.status = "complete";
9157
9576
  state.slot = slot;
@@ -14040,6 +14459,7 @@ ${block}`, new Date().toISOString(), taskId]);
14040
14459
  }
14041
14460
 
14042
14461
  // src/http/fs.ts
14462
+ init_rbac_roles();
14043
14463
  init_rbac();
14044
14464
  init_types();
14045
14465
 
@@ -14085,7 +14505,11 @@ var agentFsCredentialStateSchema = object2({
14085
14505
  });
14086
14506
  var agentFsInviteStateSchema = object2({
14087
14507
  orgId: string2(),
14088
- invited: boolean()
14508
+ invited: boolean().describe("False only when the email already holds the requested role."),
14509
+ status: _enum2(["already_member", "added", "pending"]).describe("already_member: no change. added: an existing agent-fs account joined the org. pending: the email has no account, so agent-fs created an invite the person must accept."),
14510
+ inviteId: string2().optional().describe("Pending invite id (status pending)."),
14511
+ expiresAt: string2().optional().describe("ISO time the accept link expires (status pending)."),
14512
+ acceptUrl: string2().optional().describe("Link the invitee opens to accept (status pending). agent-fs sends no email, so hand it to the person. Absent when agent-fs has no app URL configured.")
14089
14513
  });
14090
14514
  var signedUrlResponseSchema = object2({
14091
14515
  url: string2(),
@@ -14125,21 +14549,23 @@ var inviteMemberRoute = route({
14125
14549
  path: "/api/fs/members/invite",
14126
14550
  pattern: ["api", "fs", "members", "invite"],
14127
14551
  summary: "Invite an external member into the agent-fs shared org",
14128
- description: "The API server performs the invite with its own bootstrap credentials (which are API-only and never served over HTTP), provisioning the shared org/drive first when needed. Intended for the cloud control plane's Connect-to-Drive flow. No keys are returned; the invitee obtains their own key via agent-fs registration.",
14552
+ description: "The API server performs the invite with its own bootstrap credentials (which are API-only and never served over HTTP), provisioning the shared org/drive first when needed. Intended for the cloud control plane's Connect-to-Drive flow. An email with an agent-fs account is added directly (status added). An email without one gets a pending invite (status pending) with an acceptUrl when agent-fs returns one; agent-fs sends no email, so the caller must hand the link to the invitee. No keys are returned; the invitee obtains their own key via agent-fs registration.",
14129
14553
  tags: ["FS"],
14130
14554
  body: object2({
14131
14555
  email: email(),
14132
14556
  role: _enum2(["viewer", "editor", "admin"]).default("editor")
14133
14557
  }),
14134
14558
  responses: {
14135
- 200: { description: "Invite state ({ orgId, invited })", schema: agentFsInviteStateSchema },
14559
+ 200: {
14560
+ description: "Invite state ({ orgId, invited, status, acceptUrl? })",
14561
+ schema: agentFsInviteStateSchema
14562
+ },
14136
14563
  400: { description: "Invalid body" },
14564
+ 403: { description: "A non-admin user token named an email other than its own" },
14137
14565
  500: { description: "Provisioning or invite failed" }
14138
14566
  },
14139
14567
  auth: { apiKey: true },
14140
- rbac: {
14141
- ungated: "Tenant API key is the org-owner credential; the invite runs under the API server's own bootstrap identity, no per-agent principal applies."
14142
- }
14568
+ rbac: { permission: "fs.join.own" }
14143
14569
  });
14144
14570
  var listTaskFilesRoute = route({
14145
14571
  method: "get",
@@ -14238,6 +14664,27 @@ var deleteTaskFileRoute = route({
14238
14664
  auth: { apiKey: true, agentId: true },
14239
14665
  rbac: { permission: "task.fs.mutate" }
14240
14666
  });
14667
+ async function resolveInvite(req, body) {
14668
+ const auth = getRequestAuth(req);
14669
+ if (auth?.kind !== "user" || !isRbacEnabled())
14670
+ return body;
14671
+ const grant = await getUserGrant2(auth.userId);
14672
+ if (grant.grantsAll)
14673
+ return body;
14674
+ const decision = can({
14675
+ principal: { kind: "user", userId: auth.userId },
14676
+ verb: "fs.join.own",
14677
+ resource: { kind: "none" },
14678
+ source: "http"
14679
+ });
14680
+ if (!decision.allow)
14681
+ return { denied: decision.reason };
14682
+ const ownEmail = auth.user.email?.trim();
14683
+ if (!ownEmail || ownEmail.toLowerCase() !== body.email.trim().toLowerCase()) {
14684
+ return { denied: "You can only join the shared drive with your own account email" };
14685
+ }
14686
+ return { email: ownEmail, role: grant.verbs.has("task.fs.mutate") ? "editor" : "viewer" };
14687
+ }
14241
14688
  async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
14242
14689
  if (ensureAgentCredentialsRoute.match(req.method, pathSegments)) {
14243
14690
  const parsed = await ensureAgentCredentialsRoute.parse(req, res, pathSegments, queryParams);
@@ -14262,8 +14709,13 @@ async function handleFs(req, res, pathSegments, queryParams, myAgentId) {
14262
14709
  const parsed = await inviteMemberRoute.parse(req, res, pathSegments, queryParams);
14263
14710
  if (!parsed)
14264
14711
  return true;
14712
+ const invite = await resolveInvite(req, parsed.body);
14713
+ if ("denied" in invite) {
14714
+ jsonError(res, invite.denied, 403);
14715
+ return true;
14716
+ }
14265
14717
  try {
14266
- const result = await inviteEmailToSharedOrg(parsed.body.email, parsed.body.role);
14718
+ const result = await inviteEmailToSharedOrg(invite.email, invite.role);
14267
14719
  inviteMemberRoute.respond(res, 200, result);
14268
14720
  } catch (error) {
14269
14721
  const message = scrubSecrets(error instanceof Error ? error.message : String(error));
@@ -14600,7 +15052,10 @@ async function handleHeartbeat(req, res, pathSegments) {
14600
15052
  // src/http/inbox-state.ts
14601
15053
  init_zod();
14602
15054
  init_db3();
15055
+ init_rbac_roles();
15056
+ init_rbac();
14603
15057
  init_types();
15058
+ init_request_auth_context();
14604
15059
  var listState = route({
14605
15060
  method: "get",
14606
15061
  path: "/api/inbox-state",
@@ -14643,9 +15098,11 @@ var upsertState = route({
14643
15098
  schema: object2({ item: InboxItemStateSchema })
14644
15099
  },
14645
15100
  400: { description: "Validation error" },
14646
- 401: { description: "Unauthorized" }
15101
+ 401: { description: "Unauthorized" },
15102
+ 403: { description: "A non-admin user token wrote another user's state" }
14647
15103
  },
14648
- auth: { apiKey: true }
15104
+ auth: { apiKey: true },
15105
+ rbac: { permission: "favorite.write.own" }
14649
15106
  });
14650
15107
  var bulkUpsertState = route({
14651
15108
  method: "patch",
@@ -14663,11 +15120,19 @@ var bulkUpsertState = route({
14663
15120
  schema: object2({ items: array2(InboxItemStateSchema) })
14664
15121
  },
14665
15122
  400: { description: "Validation error" },
14666
- 401: { description: "Unauthorized" }
15123
+ 401: { description: "Unauthorized" },
15124
+ 403: { description: "A non-admin user token wrote another user's state" }
14667
15125
  },
14668
15126
  auth: { apiKey: true },
14669
- rbac: { ungated: "per-user inbox UI state, same posture as PATCH /api/inbox-state" }
15127
+ rbac: { permission: "favorite.write.own" }
14670
15128
  });
15129
+ var OTHER_USER_STATE_DENIED = "You can only change your own inbox state";
15130
+ async function writesOtherUsersState(req, userId) {
15131
+ const auth = getRequestAuth(req);
15132
+ if (auth?.kind !== "user" || auth.userId === userId || !isRbacEnabled())
15133
+ return false;
15134
+ return !(await getUserGrant2(auth.userId)).grantsAll;
15135
+ }
14671
15136
  async function handleInboxState(req, res, pathSegments, queryParams) {
14672
15137
  if (listState.match(req.method, pathSegments)) {
14673
15138
  const parsed = await listState.parse(req, res, pathSegments, queryParams);
@@ -14685,6 +15150,10 @@ async function handleInboxState(req, res, pathSegments, queryParams) {
14685
15150
  const parsed = await bulkUpsertState.parse(req, res, pathSegments, queryParams);
14686
15151
  if (!parsed)
14687
15152
  return true;
15153
+ if (await writesOtherUsersState(req, parsed.body.userId)) {
15154
+ jsonError(res, OTHER_USER_STATE_DENIED, 403);
15155
+ return true;
15156
+ }
14688
15157
  try {
14689
15158
  const items = await getDbClient2().transaction(async () => {
14690
15159
  const rows = [];
@@ -14703,6 +15172,10 @@ async function handleInboxState(req, res, pathSegments, queryParams) {
14703
15172
  const parsed = await upsertState.parse(req, res, pathSegments, queryParams);
14704
15173
  if (!parsed)
14705
15174
  return true;
15175
+ if (await writesOtherUsersState(req, parsed.body.userId)) {
15176
+ jsonError(res, OTHER_USER_STATE_DENIED, 403);
15177
+ return true;
15178
+ }
14706
15179
  try {
14707
15180
  const item = await upsertInboxState2({
14708
15181
  userId: parsed.body.userId,
@@ -15824,7 +16297,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
15824
16297
  // node_modules/@hono/node-server/dist/index.mjs
15825
16298
  import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "http2";
15826
16299
  import { Http2ServerRequest } from "http2";
15827
- import { Readable } from "stream";
16300
+ import { Readable as Readable2 } from "stream";
15828
16301
  import crypto2 from "crypto";
15829
16302
  var RequestError = class extends Error {
15830
16303
  constructor(message, options) {
@@ -15891,7 +16364,7 @@ var newRequestFromIncoming = (method, url, headers, incoming, abortController) =
15891
16364
  init.body = new ReadableStream({
15892
16365
  async pull(controller) {
15893
16366
  try {
15894
- reader ||= Readable.toWeb(incoming).getReader();
16367
+ reader ||= Readable2.toWeb(incoming).getReader();
15895
16368
  const { done, value } = await reader.read();
15896
16369
  if (done) {
15897
16370
  controller.close();
@@ -15904,7 +16377,7 @@ var newRequestFromIncoming = (method, url, headers, incoming, abortController) =
15904
16377
  }
15905
16378
  });
15906
16379
  } else {
15907
- init.body = Readable.toWeb(incoming);
16380
+ init.body = Readable2.toWeb(incoming);
15908
16381
  }
15909
16382
  }
15910
16383
  return new Request2(url, init);
@@ -19804,7 +20277,7 @@ async function handleMemory(req, res, pathSegments, callerAgentId) {
19804
20277
  try {
19805
20278
  const provider = getEmbeddingProvider2();
19806
20279
  const store = getMemoryStore2();
19807
- const queryEmbedding = await provider.embed(query);
20280
+ const queryEmbedding = await provider.embed(query, { kind: "query" });
19808
20281
  const candidateLimit = Math.min(limit, 20) * CANDIDATE_SET_MULTIPLIER;
19809
20282
  const candidates = await searchMemoryCandidates(store, queryEmbedding ?? new Float32Array(0), myAgentId, {
19810
20283
  scope,
@@ -19885,7 +20358,7 @@ async function handleMemory(req, res, pathSegments, callerAgentId) {
19885
20358
  try {
19886
20359
  if (query && query.trim().length > 0) {
19887
20360
  const provider = getEmbeddingProvider2();
19888
- const queryEmbedding = await provider.embed(query.trim());
20361
+ const queryEmbedding = await provider.embed(query.trim(), { kind: "query" });
19889
20362
  const candidateLimit = Math.min(4096, Math.max(offset + pageLimit, pageLimit) * CANDIDATE_SET_MULTIPLIER);
19890
20363
  let candidates = await searchMemoryCandidates(store, queryEmbedding ?? new Float32Array(0), viewer.agentId, {
19891
20364
  scope,
@@ -20100,7 +20573,7 @@ async function handleMemory(req, res, pathSegments, callerAgentId) {
20100
20573
  });
20101
20574
  if (result.changed) {
20102
20575
  const provider = getEmbeddingProvider2();
20103
- const embedding = await provider.embed(result.memory.content);
20576
+ const embedding = await provider.embed(result.memory.content, { kind: "document" });
20104
20577
  if (embedding)
20105
20578
  await store.updateEmbedding(result.memory.id, embedding, provider.name);
20106
20579
  try {
@@ -20178,7 +20651,7 @@ async function handleMemory(req, res, pathSegments, callerAgentId) {
20178
20651
  for (let i = 0;i < memories.length; i += batchSize) {
20179
20652
  const batch = memories.slice(i, i + batchSize);
20180
20653
  try {
20181
- const embeddings = await provider.embedBatch(batch.map((m) => m.content));
20654
+ const embeddings = await provider.embedBatch(batch.map((m) => m.content), { kind: "document" });
20182
20655
  for (let j = 0;j < embeddings.length; j++) {
20183
20656
  if (embeddings[j]) {
20184
20657
  await store.updateEmbedding(batch[j].id, embeddings[j], provider.name);
@@ -21909,7 +22382,9 @@ init_db3();
21909
22382
  init_memory();
21910
22383
  init_constants();
21911
22384
  init_types();
22385
+ init_constants2();
21912
22386
  init_credentials();
22387
+ init_egress_guard();
21913
22388
  init_openrouter_base_url();
21914
22389
 
21915
22390
  // src/http/status.ts
@@ -22501,6 +22976,58 @@ async function handleStatus(req, res, pathSegments, queryParams) {
22501
22976
  }
22502
22977
 
22503
22978
  // src/http/onboarding.ts
22979
+ function isLocalEndpoint(baseUrl) {
22980
+ if (!baseUrl?.trim())
22981
+ return false;
22982
+ let host;
22983
+ try {
22984
+ host = new URL(baseUrl.trim()).hostname.toLowerCase().replace(/\.$/, "");
22985
+ } catch {
22986
+ return false;
22987
+ }
22988
+ if (!host)
22989
+ return false;
22990
+ if (host === "localhost" || host.endsWith(".localhost"))
22991
+ return true;
22992
+ if (isPrivateAddress(host))
22993
+ return true;
22994
+ return !host.includes(".") && !host.includes(":");
22995
+ }
22996
+ var PRESET_HOSTS = [
22997
+ ["openai", (host) => host === "api.openai.com"],
22998
+ ["openrouter", (host) => host === "openrouter.ai"],
22999
+ ["vercel", (host) => host === "ai-gateway.vercel.sh"],
23000
+ [
23001
+ "azure",
23002
+ (host) => [".services.ai.azure.com", ".openai.azure.com", ".cognitiveservices.azure.com"].some((suffix) => host.endsWith(suffix))
23003
+ ]
23004
+ ];
23005
+ function embeddingsProvider(baseUrl) {
23006
+ if (isLocalEndpoint(baseUrl))
23007
+ return "local";
23008
+ if (!baseUrl?.trim())
23009
+ return "openai";
23010
+ let host;
23011
+ try {
23012
+ host = new URL(baseUrl.trim()).hostname.toLowerCase().replace(/\.$/, "");
23013
+ } catch {
23014
+ return "custom";
23015
+ }
23016
+ return PRESET_HOSTS.find(([, matches]) => matches(host))?.[0] ?? "custom";
23017
+ }
23018
+ function deploymentEmbeddings() {
23019
+ return {
23020
+ baseUrl: getDeploymentEnvValue("EMBEDDING_API_BASE_URL"),
23021
+ model: getDeploymentEnvValue("EMBEDDING_MODEL") ?? "text-embedding-3-small",
23022
+ apiKey: getDeploymentEnvValue("EMBEDDING_API_KEY") ?? process.env.OPENAI_API_KEY
23023
+ };
23024
+ }
23025
+ function localDefault() {
23026
+ const deployment = deploymentEmbeddings();
23027
+ if (!isLocalEndpoint(deployment.baseUrl) || !deployment.apiKey)
23028
+ return null;
23029
+ return { model: deployment.model };
23030
+ }
22504
23031
  async function buildSignals(state) {
22505
23032
  const providers = [];
22506
23033
  for (const entry of await getAgentHarnessProviders2()) {
@@ -22521,11 +23048,16 @@ async function buildSignals(state) {
22521
23048
  const integrations = await getAutomationSetupStates();
22522
23049
  const agentCounts = await getReadyAgentCounts2();
22523
23050
  const firstTask = state.firstTaskId ? await getTaskById2(state.firstTaskId) : null;
23051
+ const embeddingsOn = getEmbeddingProvider2().isConfigured();
22524
23052
  return {
22525
23053
  providers,
22526
23054
  embeddings: {
22527
- configured: getEmbeddingProvider2().isConfigured(),
22528
- dimensions: EMBEDDING_DIMENSIONS
23055
+ configured: embeddingsOn,
23056
+ dimensions: EMBEDDING_DIMENSIONS,
23057
+ model: embeddingsOn ? process.env.EMBEDDING_MODEL ?? "text-embedding-3-small" : null,
23058
+ local: embeddingsOn && isLocalEndpoint(process.env.EMBEDDING_API_BASE_URL),
23059
+ provider: embeddingsOn ? embeddingsProvider(process.env.EMBEDDING_API_BASE_URL) : null,
23060
+ localDefault: localDefault()
22529
23061
  },
22530
23062
  integrations: {
22531
23063
  slack: integrations.slack === "configured",
@@ -22539,7 +23071,8 @@ async function buildSignals(state) {
22539
23071
  leadsOnline: agentCounts.leads,
22540
23072
  workersOnline: agentCounts.workers
22541
23073
  },
22542
- firstTask: firstTask ? { id: firstTask.id, status: firstTask.status } : null
23074
+ firstTask: firstTask ? { id: firstTask.id, status: firstTask.status } : null,
23075
+ files: { enabled: isCombEnabled() }
22543
23076
  };
22544
23077
  }
22545
23078
  var getOnboarding = route({
@@ -22636,19 +23169,34 @@ function memoryErrorMessage(errorClass, status) {
22636
23169
  return `The endpoint returned an error${statusSuffix}.`;
22637
23170
  }
22638
23171
  }
22639
- async function updateMemoryState(preset, result, saveConfig) {
22640
- const configSaved = await updateOnboardingMemory(preset, result, saveConfig);
22641
- if (configSaved)
22642
- scheduleIntegrationsReload();
23172
+ async function updateMemoryState(preset, result, change) {
23173
+ const configChanged = await updateOnboardingMemory(preset, result, change);
23174
+ if (!configChanged)
23175
+ return;
23176
+ if (change?.kind === "restore") {
23177
+ await loadGlobalConfigsIntoEnv(true);
23178
+ resetEmbeddingProvider2();
23179
+ }
23180
+ scheduleIntegrationsReload();
23181
+ }
23182
+ function prefixChanges(model) {
23183
+ const sameModel = model === getDeploymentEnvValue("EMBEDDING_MODEL");
23184
+ return EMBEDDING_PREFIX_KEYS.filter((key) => getDeploymentEnvValue(key)).map((key) => ({
23185
+ key,
23186
+ value: sameModel ? null : ""
23187
+ }));
22643
23188
  }
22644
23189
  async function handleMemoryProbe(body) {
22645
23190
  const explicitKey = body.apiKey;
22646
23191
  const preset = body.preset === "openai" || body.preset === "openrouter" || body.preset === "vercel" ? MEMORY_PRESETS[body.preset] : undefined;
22647
- const baseUrl = body.preset === "existing" ? process.env.EMBEDDING_API_BASE_URL : body.baseUrl ?? preset?.baseUrl ?? process.env.EMBEDDING_API_BASE_URL ?? "https://api.openai.com/v1";
22648
- const model = body.preset === "existing" ? process.env.EMBEDDING_MODEL ?? "text-embedding-3-small" : body.model ?? preset?.model ?? process.env.EMBEDDING_MODEL ?? "text-embedding-3-small";
23192
+ const restore = body.preset === "existing" && body.restoreDefault === true;
23193
+ const deployment = restore ? deploymentEmbeddings() : null;
23194
+ const baseUrl = body.preset === "existing" ? deployment ? deployment.baseUrl : process.env.EMBEDDING_API_BASE_URL : body.baseUrl ?? preset?.baseUrl ?? process.env.EMBEDDING_API_BASE_URL ?? "https://api.openai.com/v1";
23195
+ const model = body.preset === "existing" ? deployment?.model ?? process.env.EMBEDDING_MODEL ?? "text-embedding-3-small" : body.model ?? preset?.model ?? process.env.EMBEDDING_MODEL ?? "text-embedding-3-small";
23196
+ const configuredEndpoint = body.preset === "existing" && !!baseUrl && baseUrl === getDeploymentEnvValue("EMBEDDING_API_BASE_URL");
22649
23197
  let endpoint;
22650
23198
  try {
22651
- endpoint = assertUrlSafe(baseUrl ?? "", publicEndpointSsrfOptions());
23199
+ endpoint = configuredEndpoint ? new URL(baseUrl ?? "") : assertUrlSafe(baseUrl ?? "", publicEndpointSsrfOptions());
22652
23200
  } catch {
22653
23201
  return {
22654
23202
  ok: false,
@@ -22660,7 +23208,7 @@ async function handleMemoryProbe(body) {
22660
23208
  const reuseHost = body.reuseKey === "OPENAI_API_KEY" ? "api.openai.com" : body.reuseKey === "OPENROUTER_API_KEY" ? "openrouter.ai" : undefined;
22661
23209
  const canReuseKey = reuseHost === undefined || endpoint.hostname === reuseHost;
22662
23210
  const reusedKey = !explicitKey && body.reuseKey && canReuseKey ? process.env[body.reuseKey] : undefined;
22663
- const implicitKey = body.preset === "existing" ? process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY : undefined;
23211
+ const implicitKey = body.preset === "existing" ? deployment ? deployment.apiKey : process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY : undefined;
22664
23212
  const apiKey = splitCredentialPool(explicitKey ?? reusedKey ?? implicitKey ?? "")[0];
22665
23213
  if (!apiKey) {
22666
23214
  return {
@@ -22698,10 +23246,12 @@ async function handleMemoryProbe(body) {
22698
23246
  };
22699
23247
  }
22700
23248
  const keyToSave = explicitKey || reusedKey ? apiKey : undefined;
22701
- await updateMemoryState(body.preset, { ok: true }, body.preset === "existing" ? undefined : {
23249
+ await updateMemoryState(body.preset, { ok: true }, body.preset === "existing" ? restore ? { kind: "restore" } : undefined : {
23250
+ kind: "save",
22702
23251
  baseUrl: baseUrl ?? "https://api.openai.com/v1",
22703
23252
  model,
22704
- apiKey: keyToSave
23253
+ apiKey: keyToSave,
23254
+ prefixes: prefixChanges(model)
22705
23255
  });
22706
23256
  return { ok: true, dimensions, latencyMs };
22707
23257
  } catch (error) {
@@ -22980,6 +23530,7 @@ init_request_auth_context();
22980
23530
  init_zod();
22981
23531
  init_db3();
22982
23532
  init_model_profiles();
23533
+ init_rbac_roles();
22983
23534
  init_steering();
22984
23535
  init_users();
22985
23536
  init_rbac();
@@ -23156,6 +23707,7 @@ var createTask = route({
23156
23707
  path: "/api/tasks",
23157
23708
  pattern: ["api", "tasks"],
23158
23709
  session: bodyTask("parentTaskId"),
23710
+ rbac: { permission: "task.create.own" },
23159
23711
  summary: "Create a new task",
23160
23712
  tags: ["Tasks"],
23161
23713
  body: object2({
@@ -23262,6 +23814,7 @@ var cancelTaskRoute = route({
23262
23814
  path: "/api/tasks/{id}/cancel",
23263
23815
  pattern: ["api", "tasks", null, "cancel"],
23264
23816
  session: { taskParam: "id" },
23817
+ rbac: { permission: "task.cancel.own" },
23265
23818
  summary: "Cancel a pending or in-progress task",
23266
23819
  tags: ["Tasks"],
23267
23820
  params: object2({ id: string2() }),
@@ -23512,6 +24065,7 @@ var pauseTaskRoute = route({
23512
24065
  path: "/api/tasks/{id}/pause",
23513
24066
  pattern: ["api", "tasks", null, "pause"],
23514
24067
  session: { taskParam: "id" },
24068
+ rbac: { permission: "task.action.own" },
23515
24069
  summary: "Pause an in-progress task",
23516
24070
  tags: ["Tasks"],
23517
24071
  params: object2({ id: string2() }),
@@ -23527,6 +24081,7 @@ var resumeTaskRoute = route({
23527
24081
  path: "/api/tasks/{id}/resume",
23528
24082
  pattern: ["api", "tasks", null, "resume"],
23529
24083
  session: { taskParam: "id" },
24084
+ rbac: { permission: "task.action.own" },
23530
24085
  summary: "Resume a paused task",
23531
24086
  tags: ["Tasks"],
23532
24087
  params: object2({ id: string2() }),
@@ -23596,9 +24151,7 @@ var updateTaskTitleRoute = route({
23596
24151
  404: { description: "Task not found" }
23597
24152
  },
23598
24153
  auth: { apiKey: true },
23599
- rbac: {
23600
- ungated: "mirrors the pre-RBAC PATCH /api/tasks/{id}/vcs sibling route: bearer auth only"
23601
- }
24154
+ rbac: { permission: "task.action.own" }
23602
24155
  });
23603
24156
  async function canSteerTask(req, myAgentId, task, sessionAccess = "none") {
23604
24157
  const auth = getRequestAuth(req);
@@ -23668,6 +24221,34 @@ async function resolveTaskWritePrincipal(req, myAgentId) {
23668
24221
  const agent = await getAgentById2(agentId);
23669
24222
  return { kind: "agent", agentId, isLead: agent?.isLead === true };
23670
24223
  }
24224
+ async function mayBindChatThread(principal) {
24225
+ if (principal.kind === "operator")
24226
+ return true;
24227
+ if (principal.kind === "user") {
24228
+ if (!isRbacEnabled())
24229
+ return true;
24230
+ const grant = await getUserGrant2(principal.userId);
24231
+ return grant.grantsAll || grant.verbs.has("integration.chat.post");
24232
+ }
24233
+ return can({
24234
+ principal,
24235
+ verb: "integration.chat.post",
24236
+ resource: { kind: "none" },
24237
+ source: "http"
24238
+ }).allow;
24239
+ }
24240
+ async function deniesForeignContext(req, contextKey) {
24241
+ const auth = getRequestAuth(req);
24242
+ if (auth?.kind !== "user" || !isRbacEnabled())
24243
+ return false;
24244
+ if ((await getUserGrant2(auth.userId)).grantsAll)
24245
+ return false;
24246
+ for (const task of await getInProgressTasksByContextKey2(contextKey)) {
24247
+ if (await deniesNonOwnerTaskWrite2(req, task))
24248
+ return true;
24249
+ }
24250
+ return false;
24251
+ }
23671
24252
  async function resolveTaskRequester(req, myAgentId, bodyUserId, trustedUserId) {
23672
24253
  const trusted = trustedUserId === undefined ? await resolveHttpAuditUserId(req, myAgentId) : trustedUserId;
23673
24254
  if (trusted)
@@ -23783,8 +24364,12 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
23783
24364
  if (parentTask && await denyParentAttach2(req, res, myAgentId, parentTask, principal)) {
23784
24365
  return true;
23785
24366
  }
23786
- 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) {
23787
- jsonError(res, "Permission denied: only a lead can bind a task to a chat thread.", 403);
24367
+ if (parsed.body.contextKey && parsed.body.contextKey !== parentTask?.contextKey && chatThreadOfContextKey(parsed.body.contextKey) && !await mayBindChatThread(principal)) {
24368
+ jsonError(res, "Permission denied: only a lead or an admin can bind a task to a chat thread.", 403);
24369
+ return true;
24370
+ }
24371
+ if (parsed.body.contextKey && parsed.body.contextKey !== parentTask?.contextKey && await deniesForeignContext(req, parsed.body.contextKey)) {
24372
+ jsonError(res, "You don't have access to the tasks in this context.", 403);
23788
24373
  return true;
23789
24374
  }
23790
24375
  let assetKey;
@@ -23904,6 +24489,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
23904
24489
  jsonError(res, "Task not found", 404);
23905
24490
  return true;
23906
24491
  }
24492
+ if (await deniesNonOwnerTaskWrite2(req, task)) {
24493
+ jsonError(res, NOT_YOUR_TASK_DENIED2, 403);
24494
+ return true;
24495
+ }
23907
24496
  const principal = await resolveTaskWritePrincipal(req, myAgentId);
23908
24497
  if (principal.kind === "agent" && !can({
23909
24498
  principal,
@@ -24395,6 +24984,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
24395
24984
  jsonError(res, "Task not found", 404);
24396
24985
  return true;
24397
24986
  }
24987
+ if (await deniesNonOwnerTaskWrite2(req, task)) {
24988
+ jsonError(res, NOT_YOUR_TASK_DENIED2, 403);
24989
+ return true;
24990
+ }
24398
24991
  if (myAgentId && task.agentId !== myAgentId) {
24399
24992
  jsonError(res, "Task belongs to another agent", 403);
24400
24993
  return true;
@@ -24455,6 +25048,15 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
24455
25048
  const parsed = await updateTaskTitleRoute.parse(req, res, pathSegments, queryParams);
24456
25049
  if (!parsed)
24457
25050
  return true;
25051
+ const existing = await getTaskById2(parsed.params.id);
25052
+ if (!existing) {
25053
+ jsonError(res, "Task not found", 404);
25054
+ return true;
25055
+ }
25056
+ if (await deniesNonOwnerTaskWrite2(req, existing)) {
25057
+ jsonError(res, NOT_YOUR_TASK_DENIED2, 403);
25058
+ return true;
25059
+ }
24458
25060
  const task = await updateTaskTitle2(parsed.params.id, parsed.body.title);
24459
25061
  if (!task) {
24460
25062
  jsonError(res, "Task not found", 404);
@@ -24472,6 +25074,10 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
24472
25074
  jsonError(res, "Task not found", 404);
24473
25075
  return true;
24474
25076
  }
25077
+ if (await deniesNonOwnerTaskWrite2(req, task)) {
25078
+ jsonError(res, NOT_YOUR_TASK_DENIED2, 403);
25079
+ return true;
25080
+ }
24475
25081
  if (myAgentId && task.agentId !== myAgentId) {
24476
25082
  jsonError(res, "Task belongs to another agent", 403);
24477
25083
  return true;
@@ -34819,7 +35425,7 @@ var triageSessionListRoute = route({
34819
35425
  401: { description: "Unauthorized" }
34820
35426
  },
34821
35427
  auth: { apiKey: true },
34822
- rbac: { ungated: "per-user inbox UI state, same posture as PATCH /api/inbox-state" }
35428
+ rbac: { permission: "favorite.write.own" }
34823
35429
  });
34824
35430
  var SESSION_MOVE_LIMIT = 200;
34825
35431
  var SESSION_MOVE_OWNER_ONLY = "Only the session owner can move this group";
@@ -34828,9 +35434,7 @@ var SessionMoveResultSchema = object2({
34828
35434
  moved: array2(string2()),
34829
35435
  skipped: array2(object2({ rootTaskId: string2(), reason: string2() }))
34830
35436
  });
34831
- var sessionMoveRbac = {
34832
- ungated: "per-session access, per-task task.fs.mutate, and asset-key write checks in the handler, as PATCH /api/assets/task/{id}/key"
34833
- };
35437
+ var sessionMoveRbac = { permission: "task.fs.mutate" };
34834
35438
  var sessionMoveResponses = {
34835
35439
  400: { description: "Invalid namespace or request" },
34836
35440
  403: { description: "Personal destination not authorized" },
@@ -34902,6 +35506,8 @@ async function checkSessionMove(rootTaskId, actor, req, myAgentId, options = {})
34902
35506
  return { reason: SESSION_MOVE_UNAVAILABLE };
34903
35507
  if (!hasSessionAccess(access, "write"))
34904
35508
  return { reason: "Session write access required" };
35509
+ if (await deniesNonOwnerTaskWrite2(req, root))
35510
+ return { reason: NOT_YOUR_TASK_DENIED2 };
34905
35511
  }
34906
35512
  if (root.parentTaskId)
34907
35513
  return { reason: "Task is not a session root" };
@@ -36989,7 +37595,7 @@ var uiEvent = route({
36989
37595
  401: { description: "Unauthorized" },
36990
37596
  403: { description: "Guest page sessions cannot send events" }
36991
37597
  },
36992
- rbac: { ungated: "any authenticated dashboard user; event name allowlisted" }
37598
+ rbac: { permission: "favorite.write.own" }
36993
37599
  });
36994
37600
  var enableTelemetry = route({
36995
37601
  method: "post",
@@ -37913,76 +38519,11 @@ init_zod();
37913
38519
  init_db3();
37914
38520
  init_rbac_roles();
37915
38521
  init_users();
38522
+ init_rbac();
37916
38523
  init_types();
38524
+ init_constants2();
38525
+ init_egress_guard();
37917
38526
  init_request_auth_context();
37918
-
37919
- // src/http/ip-rate-limit.ts
37920
- var PRUNE_THRESHOLD = 1e4;
37921
- var PRUNE_INTERVAL_MS = 60000;
37922
- var MAX_BUCKETS = 50000;
37923
- function isPrivateAddress(address) {
37924
- const ip = address.startsWith("::ffff:") ? address.slice(7) : address;
37925
- if (ip === "::1" || ip.startsWith("127.") || ip.startsWith("10."))
37926
- return true;
37927
- if (ip.startsWith("192.168.") || ip.startsWith("169.254."))
37928
- return true;
37929
- const match = /^172\.(\d+)\./.exec(ip);
37930
- if (match && Number(match[1]) >= 16 && Number(match[1]) <= 31)
37931
- return true;
37932
- const lower = ip.toLowerCase();
37933
- return lower.startsWith("fc") || lower.startsWith("fd") || lower.startsWith("fe80:");
37934
- }
37935
- function clientIp(req) {
37936
- const peer = req.socket.remoteAddress ?? "unknown";
37937
- if (!isPrivateAddress(peer))
37938
- return peer;
37939
- const raw = req.headers["x-forwarded-for"];
37940
- const header = Array.isArray(raw) ? raw[raw.length - 1] : raw;
37941
- const hop = header?.split(",").pop()?.trim();
37942
- return hop || peer;
37943
- }
37944
- function createIpRateLimiter(options) {
37945
- const buckets = new Map;
37946
- let lastPruneAt = 0;
37947
- function refill(bucket, now) {
37948
- const elapsed = now - bucket.updatedAt;
37949
- bucket.tokens = Math.min(options.capacity, bucket.tokens + elapsed * options.refillPerMs);
37950
- bucket.updatedAt = now;
37951
- }
37952
- return {
37953
- take(ip, now = Date.now()) {
37954
- if (buckets.size > PRUNE_THRESHOLD && now - lastPruneAt >= PRUNE_INTERVAL_MS) {
37955
- lastPruneAt = now;
37956
- for (const [key, bucket] of buckets) {
37957
- refill(bucket, now);
37958
- if (bucket.tokens >= options.capacity)
37959
- buckets.delete(key);
37960
- }
37961
- }
37962
- let bucket = buckets.get(ip);
37963
- if (!bucket) {
37964
- if (buckets.size >= MAX_BUCKETS) {
37965
- const oldest = buckets.keys().next().value;
37966
- if (oldest !== undefined)
37967
- buckets.delete(oldest);
37968
- }
37969
- bucket = { tokens: options.capacity, updatedAt: now };
37970
- buckets.set(ip, bucket);
37971
- }
37972
- refill(bucket, now);
37973
- if (bucket.tokens < 1)
37974
- return false;
37975
- bucket.tokens -= 1;
37976
- return true;
37977
- },
37978
- reset() {
37979
- buckets.clear();
37980
- lastPruneAt = 0;
37981
- }
37982
- };
37983
- }
37984
-
37985
- // src/http/users.ts
37986
38527
  async function composeUser(userId, recentEventLimit = 5) {
37987
38528
  const user = await getUserById2(userId);
37988
38529
  if (!user)
@@ -38054,7 +38595,12 @@ var whoamiRoute = route({
38054
38595
  description: "Authenticated principal",
38055
38596
  schema: object2({
38056
38597
  kind: _enum2(["operator", "user"]),
38057
- user: union2([UserSchema, _null()])
38598
+ user: union2([UserSchema, _null()]),
38599
+ grants: object2({
38600
+ grantsAll: boolean(),
38601
+ verbs: array2(string2()),
38602
+ roles: array2(string2())
38603
+ }).optional()
38058
38604
  })
38059
38605
  },
38060
38606
  401: { description: "Unauthorized" }
@@ -38303,6 +38849,72 @@ var exchangeConnectorCodeRoute = route({
38303
38849
  ungated: "the single-use code is the credential; the minted token carries the user's own grant and is admitted on use"
38304
38850
  }
38305
38851
  });
38852
+ var INVITE_ROLES = ["requester", "viewer", "admin"];
38853
+ var createInviteRoute = route({
38854
+ method: "post",
38855
+ path: "/api/invites",
38856
+ pattern: ["api", "invites"],
38857
+ summary: "Invite a teammate with a one-time API link",
38858
+ description: "Creates an invited user with the given role (requester by default) and returns a 7-day single-use API link. The API redirects to the current APP_URL dashboard with the code in the URL fragment. The browser exchanges the code at POST /api/invites/exchange for a personal MCP token. Re-inviting an invited user replaces the role and link. Active or suspended users return 409 user_exists. No email is sent.",
38859
+ tags: ["Users"],
38860
+ body: object2({
38861
+ email: email(),
38862
+ name: string2().trim().min(1).max(200).optional(),
38863
+ role: _enum2(INVITE_ROLES).default("requester")
38864
+ }),
38865
+ responses: {
38866
+ 201: {
38867
+ description: "The invited user, API link, dashboard URL, expiry and API reachability",
38868
+ schema: object2({
38869
+ user: ComposedUserSchema.nullable(),
38870
+ inviteUrl: string2(),
38871
+ appUrl: string2(),
38872
+ expiresAt: string2(),
38873
+ apiReachable: _enum2(["public", "local"])
38874
+ })
38875
+ },
38876
+ 401: { description: "Unauthorized" },
38877
+ 403: { description: "Not allowed to manage roles" },
38878
+ 409: { description: "The email belongs to an active or suspended user" }
38879
+ },
38880
+ auth: { apiKey: true },
38881
+ rbac: { permission: "user.role.manage" }
38882
+ });
38883
+ var openInviteRoute = route({
38884
+ method: "get",
38885
+ path: "/invite/{code}",
38886
+ pattern: ["invite", null],
38887
+ summary: "Open an invite in the configured dashboard",
38888
+ description: "Redirects to the current APP_URL dashboard with the code in the URL fragment. Does not validate or consume the invite.",
38889
+ tags: ["Users"],
38890
+ params: object2({ code: string2() }),
38891
+ responses: {
38892
+ 302: { description: "Redirect to the dashboard", unstructured: "Dashboard redirect" },
38893
+ 404: { description: "Malformed code (code_invalid)" }
38894
+ },
38895
+ auth: { apiKey: false }
38896
+ });
38897
+ var exchangeInviteCodeRoute = route({
38898
+ method: "post",
38899
+ path: "/api/invites/exchange",
38900
+ pattern: ["api", "invites", "exchange"],
38901
+ summary: "Exchange an invite code for the invited user's MCP token",
38902
+ description: "Unauthenticated: the single-use invite code is the credential. Rate limited per IP. Activates the invited user. Unknown, expired, used and connector codes, and codes for users who are no longer invited, all return 404 code_invalid.",
38903
+ tags: ["Users"],
38904
+ body: object2({ code: string2().min(1).max(256) }),
38905
+ maxBodyBytes: 1024,
38906
+ responses: {
38907
+ 200: {
38908
+ description: "Minted MCP token for the invited user",
38909
+ schema: object2({ token: string2(), userId: string2() })
38910
+ },
38911
+ 404: { description: "Code unknown, malformed, expired, already used or not an invite" },
38912
+ 413: { description: "Request body too large" },
38913
+ 429: { description: "Rate limited" }
38914
+ },
38915
+ auth: { apiKey: false },
38916
+ rbac: { ungated: "the one-time invite code is the credential" }
38917
+ });
38306
38918
  var connectorDiscoveryRoute = route({
38307
38919
  method: "get",
38308
38920
  path: "/api/connector/discovery",
@@ -38483,6 +39095,26 @@ var connectorExchangeRateLimiter = createIpRateLimiter({
38483
39095
  capacity: 10,
38484
39096
  refillPerMs: 10 / 60000
38485
39097
  });
39098
+ var inviteExchangeRateLimiter = createIpRateLimiter({
39099
+ capacity: 10,
39100
+ refillPerMs: 10 / 60000
39101
+ });
39102
+ function apiReachability(apiUrl) {
39103
+ let host;
39104
+ try {
39105
+ host = assertUrlSafe(apiUrl, { allowInsecure: true }).hostname.toLowerCase();
39106
+ } catch {
39107
+ return "local";
39108
+ }
39109
+ if (!host.includes(".") && !host.includes(":"))
39110
+ return "local";
39111
+ if (/\.(local|internal|lan|home\.arpa)\.?$/.test(host))
39112
+ return "local";
39113
+ return "public";
39114
+ }
39115
+
39116
+ class InviteUserExistsError extends Error {
39117
+ }
38486
39118
  async function handleUsers(req, res, pathSegments, queryParams) {
38487
39119
  if (whoamiRoute.match(req.method, pathSegments)) {
38488
39120
  const parsed = await whoamiRoute.parse(req, res, pathSegments, queryParams);
@@ -38490,9 +39122,26 @@ async function handleUsers(req, res, pathSegments, queryParams) {
38490
39122
  return true;
38491
39123
  const auth = getRequestAuth(req);
38492
39124
  if (auth?.kind === "user") {
38493
- whoamiRoute.respond(res, 200, { kind: "user", user: auth.user });
39125
+ const [grant, roles] = await Promise.all([
39126
+ getUserGrant2(auth.user.id),
39127
+ listUserRoles2(auth.user.id)
39128
+ ]);
39129
+ const grantsAll = !isRbacEnabled() || grant.grantsAll;
39130
+ whoamiRoute.respond(res, 200, {
39131
+ kind: "user",
39132
+ user: auth.user,
39133
+ grants: {
39134
+ grantsAll,
39135
+ verbs: grantsAll ? [] : [...grant.verbs].sort(),
39136
+ roles: roles.map((role) => role.name)
39137
+ }
39138
+ });
38494
39139
  } else {
38495
- whoamiRoute.respond(res, 200, { kind: "operator", user: null });
39140
+ whoamiRoute.respond(res, 200, {
39141
+ kind: "operator",
39142
+ user: null,
39143
+ grants: { grantsAll: true, verbs: [], roles: [] }
39144
+ });
38496
39145
  }
38497
39146
  return true;
38498
39147
  }
@@ -38696,6 +39345,110 @@ async function handleUsers(req, res, pathSegments, queryParams) {
38696
39345
  }
38697
39346
  return true;
38698
39347
  }
39348
+ if (createInviteRoute.match(req.method, pathSegments)) {
39349
+ const parsed = await createInviteRoute.parse(req, res, pathSegments, queryParams);
39350
+ if (!parsed)
39351
+ return true;
39352
+ if (!await ensureRoleManager(req, res))
39353
+ return true;
39354
+ const actor = getOperatorActor(req, res);
39355
+ if (!actor)
39356
+ return true;
39357
+ const { email: email2, name, role } = parsed.body;
39358
+ const actorUserId = actor.kind === "user" ? actor.id : null;
39359
+ let invited;
39360
+ try {
39361
+ invited = await getDbClient2().transaction(async () => {
39362
+ const existing = await findUserByEmail(email2);
39363
+ if (existing && existing.status !== "invited")
39364
+ throw new InviteUserExistsError;
39365
+ let userId;
39366
+ if (existing) {
39367
+ userId = existing.id;
39368
+ await deleteUnusedInviteCodes(userId);
39369
+ } else {
39370
+ const user = await createUser2({
39371
+ name: name ?? (email2.split("@")[0] || email2),
39372
+ email: email2,
39373
+ status: "invited"
39374
+ });
39375
+ userId = user.id;
39376
+ await recordIdentityEvent(userId, "identity_added", actor, null, {
39377
+ email: email2,
39378
+ source: "invite"
39379
+ });
39380
+ }
39381
+ const { before, after } = await setUserRoles2(userId, [role], actorUserId);
39382
+ if (before.join(",") !== after.join(",")) {
39383
+ await recordIdentityEvent(userId, "profile_changed", actor, { rbacRoles: before }, { rbacRoles: after });
39384
+ }
39385
+ const { code, expiresAt } = await createConnectorCode(userId, DEFAULT_INVITE_CODE_LABEL, actor, new Date, { kind: "invite", ttlMs: INVITE_CODE_TTL_MS });
39386
+ return { userId, code, expiresAt };
39387
+ });
39388
+ } catch (err) {
39389
+ if (err instanceof InviteUserExistsError) {
39390
+ jsonError(res, "user_exists", 409);
39391
+ return true;
39392
+ }
39393
+ jsonError(res, "Failed to create invite", 500);
39394
+ return true;
39395
+ }
39396
+ const apiUrl = await resolveMcpBaseUrl();
39397
+ const appUrl = await resolveAppUrl() ?? DEFAULT_APP_URL;
39398
+ const inviteUrl = `${apiUrl}/invite/${invited.code}`;
39399
+ createInviteRoute.respond(res, 201, {
39400
+ user: await composeUser(invited.userId),
39401
+ inviteUrl,
39402
+ appUrl,
39403
+ expiresAt: invited.expiresAt,
39404
+ apiReachable: apiReachability(apiUrl)
39405
+ });
39406
+ return true;
39407
+ }
39408
+ if (openInviteRoute.match(req.method, pathSegments)) {
39409
+ const parsed = await openInviteRoute.parse(req, res, pathSegments, queryParams);
39410
+ if (!parsed)
39411
+ return true;
39412
+ const { code } = parsed.params;
39413
+ if (!/^[A-Za-z0-9_-]{16,256}$/.test(code)) {
39414
+ jsonError(res, "code_invalid", 404);
39415
+ return true;
39416
+ }
39417
+ const apiUrl = await resolveMcpBaseUrl();
39418
+ const appUrl = await resolveAppUrl() ?? DEFAULT_APP_URL;
39419
+ res.writeHead(302, {
39420
+ Location: `${appUrl}/join?swarm=${encodeURIComponent(apiUrl)}#code=${code}`,
39421
+ "Cache-Control": "no-store",
39422
+ "Referrer-Policy": "no-referrer"
39423
+ });
39424
+ res.end();
39425
+ return true;
39426
+ }
39427
+ if (exchangeInviteCodeRoute.match(req.method, pathSegments)) {
39428
+ if (!inviteExchangeRateLimiter.take(clientIp(req))) {
39429
+ res.setHeader("Retry-After", "6");
39430
+ jsonError(res, "rate_limited", 429);
39431
+ return true;
39432
+ }
39433
+ const parsed = await exchangeInviteCodeRoute.parse(req, res, pathSegments, queryParams);
39434
+ if (!parsed)
39435
+ return true;
39436
+ if (!CONNECTOR_CODE_PATTERN.test(parsed.body.code)) {
39437
+ jsonError(res, "code_invalid", 404);
39438
+ return true;
39439
+ }
39440
+ try {
39441
+ const result = await exchangeConnectorCode(parsed.body.code, { kind: "invite" });
39442
+ if (!result) {
39443
+ jsonError(res, "code_invalid", 404);
39444
+ return true;
39445
+ }
39446
+ exchangeInviteCodeRoute.respond(res, 200, result);
39447
+ } catch {
39448
+ jsonError(res, "Failed to exchange code", 500);
39449
+ }
39450
+ return true;
39451
+ }
38699
39452
  if (revokeUserMcpTokenRoute.match(req.method, pathSegments)) {
38700
39453
  const parsed = await revokeUserMcpTokenRoute.parse(req, res, pathSegments, queryParams);
38701
39454
  if (!parsed)
@@ -41250,7 +42003,7 @@ var httpServer = createHttpServer(async (req, res) => {
41250
42003
  const semconv = httpServerSemconvAttributes(req);
41251
42004
  const span = skipSpan ? null : startSpan2(spanName, {
41252
42005
  "http.request.method": req.method ?? "",
41253
- "url.path": reqPath,
42006
+ "url.path": redactShareTokenInPath(reqPath),
41254
42007
  "url.scheme": semconv["url.scheme"],
41255
42008
  "http.route": httpRoute,
41256
42009
  "server.address": semconv["server.address"],
@@ -41294,6 +42047,7 @@ var httpServer = createHttpServer(async (req, res) => {
41294
42047
  () => handlePoolKeys(req, res, pathSegments, queryParams),
41295
42048
  () => handleConfig(req, res, pathSegments, queryParams),
41296
42049
  () => handleFs(req, res, pathSegments, queryParams, myAgentId),
42050
+ () => handleAgentFsProxy(req, res),
41297
42051
  () => handleComb(req, res, pathSegments, queryParams, myAgentId),
41298
42052
  () => handleKv(req, res, pathSegments, queryParams),
41299
42053
  () => handleRooms(req, res, pathSegments, queryParams),
@@ -41368,7 +42122,7 @@ var httpServer = createHttpServer(async (req, res) => {
41368
42122
  });
41369
42123
  });
41370
42124
  var detachRealtime = attachRealtimeTransport(httpServer);
41371
- var { attachControllerTransport } = await import("./controllers-connect-nep9h2xv.js");
42125
+ var { attachControllerTransport } = await import("./controllers-connect-ajvh9h0v.js");
41372
42126
  var detachControllers = attachControllerTransport(httpServer);
41373
42127
  var stopWorkerNudges = startWorkerNudgeListener();
41374
42128
  var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
@@ -41397,7 +42151,7 @@ async function shutdown() {
41397
42151
  sessionsProcessed: getServerSessionsProcessed()
41398
42152
  });
41399
42153
  if (hasCapability("scheduling")) {
41400
- const { stopScheduler } = await import("./index-zyq8ct52.js");
42154
+ const { stopScheduler } = await import("./index-ch0c1xff.js");
41401
42155
  stopScheduler();
41402
42156
  }
41403
42157
  stopHeartbeat2();
@@ -41409,7 +42163,7 @@ async function shutdown() {
41409
42163
  await stopSlackApp2();
41410
42164
  await stopChatSdk();
41411
42165
  if (!isEnvFlagEnabled("OAUTH_KEEPALIVE_DISABLE", false)) {
41412
- const { stopOAuthKeepalive } = await import("./keepalive-xdvsamvj.js");
42166
+ const { stopOAuthKeepalive } = await import("./keepalive-zzc3hks1.js");
41413
42167
  await stopOAuthKeepalive();
41414
42168
  }
41415
42169
  stopOAuthPendingGc();
@@ -41489,21 +42243,21 @@ try {
41489
42243
  console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
41490
42244
  }
41491
42245
  try {
41492
- const { ensurePricingSeeded } = await import("./boot-seeds-ca84dhnn.js");
42246
+ const { ensurePricingSeeded } = await import("./boot-seeds-r3kwwv8b.js");
41493
42247
  ensurePricingSeeded();
41494
- const { startPricingRefreshLoop } = await import("./pricing-refresh-dw2tgb53.js");
42248
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-wkpwhgvs.js");
41495
42249
  startPricingRefreshLoop();
41496
42250
  } catch (err) {
41497
42251
  console.error("[startup] Failed to seed pricing rows:", err);
41498
42252
  }
41499
42253
  try {
41500
- const { ensureModelProfilesSeeded } = await import("./boot-seeds-ca84dhnn.js");
42254
+ const { ensureModelProfilesSeeded } = await import("./boot-seeds-r3kwwv8b.js");
41501
42255
  await ensureModelProfilesSeeded();
41502
42256
  } catch (err) {
41503
42257
  console.error("[startup] Failed to seed model profiles:", err);
41504
42258
  }
41505
42259
  try {
41506
- const { ensureRbacSeeded } = await import("./boot-seeds-ca84dhnn.js");
42260
+ const { ensureRbacSeeded } = await import("./boot-seeds-r3kwwv8b.js");
41507
42261
  ensureRbacSeeded();
41508
42262
  } catch (err) {
41509
42263
  console.error("[startup] Failed to sync RBAC seed rows:", err);
@@ -41511,7 +42265,7 @@ try {
41511
42265
  throw err;
41512
42266
  }
41513
42267
  try {
41514
- const { runAllSeeders } = await import("./index-jwt2bj6f.js");
42268
+ const { runAllSeeders } = await import("./index-ejqdkkqx.js");
41515
42269
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
41516
42270
  } catch (err) {
41517
42271
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -41574,42 +42328,42 @@ httpServer.listen(port, async () => {
41574
42328
  await initWorkflows2();
41575
42329
  await startScriptRunSupervisor(getMcpBaseUrl());
41576
42330
  if (hasCapability("scheduling")) {
41577
- const { startScheduler } = await import("./index-zyq8ct52.js");
41578
- const { getExecutorRegistry } = await import("./index-z5h22pes.js");
42331
+ const { startScheduler } = await import("./index-ch0c1xff.js");
42332
+ const { getExecutorRegistry } = await import("./index-5nb266jr.js");
41579
42333
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
41580
42334
  startScheduler(getExecutorRegistry(), intervalMs, {
41581
42335
  runId: globalState.__runId
41582
42336
  });
41583
42337
  }
41584
42338
  if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
41585
- const { startHeartbeat } = await import("./index-y1ajx04a.js");
42339
+ const { startHeartbeat } = await import("./index-ed8dy8rn.js");
41586
42340
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
41587
42341
  startHeartbeat(heartbeatMs);
41588
42342
  }
41589
42343
  startPoolRouting();
41590
42344
  startRuntimeSupervisor();
41591
42345
  if (!isEnvFlagEnabled("OAUTH_KEEPALIVE_DISABLE", false)) {
41592
- const { startOAuthKeepalive } = await import("./keepalive-xdvsamvj.js");
42346
+ const { startOAuthKeepalive } = await import("./keepalive-zzc3hks1.js");
41593
42347
  startOAuthKeepalive();
41594
42348
  }
41595
42349
  if (!isEnvFlagEnabled("OAUTH_REFRESH_SWEEP_DISABLE", false)) {
41596
- const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-jd4r7zbs.js");
42350
+ const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-7qt0g55z.js");
41597
42351
  startOAuthRefreshSweep();
41598
42352
  }
41599
42353
  startOAuthPendingGc();
41600
42354
  await startMemoryGc();
41601
42355
  await startDbRetention();
41602
42356
  startHumanFreeDrain();
41603
- import("./boot-reembed-5h37a2c2.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
42357
+ import("./boot-reembed-k5y5xbj0.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
41604
42358
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
41605
42359
  });
41606
- import("./boot-reembed-7h78vmvv.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
42360
+ import("./boot-reembed-fxfw17m2.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
41607
42361
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
41608
42362
  });
41609
- import("./boot-scrub-sweep-8mawd4gw.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
42363
+ import("./boot-scrub-sweep-se41j9fd.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
41610
42364
  console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
41611
42365
  });
41612
- import("./session-source-backfill-424wzv0r.js").then(({ runSessionSourceBackfill }) => runSessionSourceBackfill()).catch((err) => {
42366
+ import("./session-source-backfill-62202awe.js").then(({ runSessionSourceBackfill }) => runSessionSourceBackfill()).catch((err) => {
41613
42367
  console.error("[session-source-backfill] startup run failed (non-fatal):", err);
41614
42368
  });
41615
42369
  }).on("error", (err) => {