@cursor/bdk 0.2.8 → 0.2.10

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 (581) hide show
  1. package/dist/artifacts.js +3 -5
  2. package/dist/bin/agent-serve.d.ts +1 -0
  3. package/dist/bin/agent-serve.d.ts.map +1 -1
  4. package/dist/bin/agent-serve.js +820 -807
  5. package/dist/channels/bitbucket/api.js +305 -321
  6. package/dist/channels/bitbucket/binding.js +97 -61
  7. package/dist/channels/bitbucket/bitbucket-channel.d.ts +15 -1
  8. package/dist/channels/bitbucket/bitbucket-channel.d.ts.map +1 -1
  9. package/dist/channels/bitbucket/bitbucket-channel.js +95 -42
  10. package/dist/channels/bitbucket/bitbucket-webhook.d.ts +11 -0
  11. package/dist/channels/bitbucket/bitbucket-webhook.d.ts.map +1 -1
  12. package/dist/channels/bitbucket/bitbucket-webhook.js +214 -204
  13. package/dist/channels/bitbucket/checks.js +9 -21
  14. package/dist/channels/bitbucket/cursor-account.js +1 -1
  15. package/dist/channels/bitbucket/defaults.js +14 -4
  16. package/dist/channels/bitbucket/events.js +1 -2
  17. package/dist/channels/bitbucket/index.d.ts +6 -2
  18. package/dist/channels/bitbucket/index.d.ts.map +1 -1
  19. package/dist/channels/bitbucket/index.js +6 -2
  20. package/dist/channels/bitbucket/replay.js +80 -56
  21. package/dist/channels/bitbucket/state.js +16 -7
  22. package/dist/channels/bitbucket/types.d.ts +11 -2
  23. package/dist/channels/bitbucket/types.d.ts.map +1 -1
  24. package/dist/channels/checks.js +18 -28
  25. package/dist/channels/deployments/deployments-channel.js +26 -34
  26. package/dist/channels/github/api.js +216 -210
  27. package/dist/channels/github/auth.d.ts +5 -1
  28. package/dist/channels/github/auth.d.ts.map +1 -1
  29. package/dist/channels/github/auth.js +157 -174
  30. package/dist/channels/github/binding.js +48 -39
  31. package/dist/channels/github/checks.js +9 -14
  32. package/dist/channels/github/cursor-account.js +6 -11
  33. package/dist/channels/github/defaults.js +105 -130
  34. package/dist/channels/github/forward.js +13 -17
  35. package/dist/channels/github/github-channel.d.ts +43 -2
  36. package/dist/channels/github/github-channel.d.ts.map +1 -1
  37. package/dist/channels/github/github-channel.js +1228 -958
  38. package/dist/channels/github/progress.js +145 -146
  39. package/dist/channels/github/replay.js +30 -39
  40. package/dist/channels/github/state.js +40 -16
  41. package/dist/channels/github/types.d.ts +30 -6
  42. package/dist/channels/github/types.d.ts.map +1 -1
  43. package/dist/channels/gitlab/api.js +100 -114
  44. package/dist/channels/gitlab/binding.js +52 -33
  45. package/dist/channels/gitlab/checks.js +28 -29
  46. package/dist/channels/gitlab/cursor-account.js +1 -1
  47. package/dist/channels/gitlab/defaults.js +9 -3
  48. package/dist/channels/gitlab/gitlab-channel.d.ts +16 -1
  49. package/dist/channels/gitlab/gitlab-channel.d.ts.map +1 -1
  50. package/dist/channels/gitlab/gitlab-channel.js +95 -42
  51. package/dist/channels/gitlab/gitlab-webhook.d.ts +10 -1
  52. package/dist/channels/gitlab/gitlab-webhook.d.ts.map +1 -1
  53. package/dist/channels/gitlab/gitlab-webhook.js +282 -249
  54. package/dist/channels/gitlab/index.d.ts +6 -2
  55. package/dist/channels/gitlab/index.d.ts.map +1 -1
  56. package/dist/channels/gitlab/index.js +6 -2
  57. package/dist/channels/gitlab/replay.js +50 -27
  58. package/dist/channels/gitlab/state.js +14 -6
  59. package/dist/channels/gitlab/types.d.ts +13 -2
  60. package/dist/channels/gitlab/types.d.ts.map +1 -1
  61. package/dist/channels/origin/api.js +100 -116
  62. package/dist/channels/origin/binding.js +15 -16
  63. package/dist/channels/origin/checks.js +30 -28
  64. package/dist/channels/origin/defaults.js +50 -65
  65. package/dist/channels/origin/origin-channel.js +266 -272
  66. package/dist/channels/origin/origin-webhook.js +70 -88
  67. package/dist/channels/origin/reactions.js +9 -21
  68. package/dist/channels/origin/state.js +13 -5
  69. package/dist/channels/slack/agentic-delivery.js +426 -478
  70. package/dist/channels/slack/agentic-posted.js +9 -10
  71. package/dist/channels/slack/agentic-signals.js +2 -3
  72. package/dist/channels/slack/api.js +417 -427
  73. package/dist/channels/slack/approvals.js +1 -1
  74. package/dist/channels/slack/assistant.js +37 -47
  75. package/dist/channels/slack/attachments.js +188 -206
  76. package/dist/channels/slack/auth.js +8 -6
  77. package/dist/channels/slack/bot-mentions.js +31 -45
  78. package/dist/channels/slack/channel-watch.js +42 -48
  79. package/dist/channels/slack/cli-project.js +112 -137
  80. package/dist/channels/slack/code-fences.js +3 -5
  81. package/dist/channels/slack/constants.js +2 -2
  82. package/dist/channels/slack/credentials.js +23 -38
  83. package/dist/channels/slack/defaults.js +292 -331
  84. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  85. package/dist/channels/slack/dispatch.js +533 -460
  86. package/dist/channels/slack/doctor.js +200 -214
  87. package/dist/channels/slack/eval-directive.js +79 -96
  88. package/dist/channels/slack/event-id-dedupe.js +1 -1
  89. package/dist/channels/slack/external-policy.js +26 -39
  90. package/dist/channels/slack/footer.js +28 -41
  91. package/dist/channels/slack/inbound.d.ts +1 -0
  92. package/dist/channels/slack/inbound.d.ts.map +1 -1
  93. package/dist/channels/slack/inbound.js +50 -31
  94. package/dist/channels/slack/init.d.ts +1 -5
  95. package/dist/channels/slack/init.d.ts.map +1 -1
  96. package/dist/channels/slack/init.js +42 -59
  97. package/dist/channels/slack/interactive.d.ts +9 -3
  98. package/dist/channels/slack/interactive.d.ts.map +1 -1
  99. package/dist/channels/slack/interactive.js +160 -162
  100. package/dist/channels/slack/links.js +1 -2
  101. package/dist/channels/slack/live-delivery.js +172 -190
  102. package/dist/channels/slack/manifest.d.ts.map +1 -1
  103. package/dist/channels/slack/manifest.js +44 -23
  104. package/dist/channels/slack/message-body.js +2 -2
  105. package/dist/channels/slack/nudge-carrier.js +30 -42
  106. package/dist/channels/slack/nudge-store.js +164 -191
  107. package/dist/channels/slack/paint-start.js +66 -81
  108. package/dist/channels/slack/placeholder.js +123 -152
  109. package/dist/channels/slack/pr-ref.js +1 -1
  110. package/dist/channels/slack/progress-delivery.js +65 -78
  111. package/dist/channels/slack/reasoning-card.js +36 -49
  112. package/dist/channels/slack/recording-sink.js +12 -24
  113. package/dist/channels/slack/reply-options.js +7 -12
  114. package/dist/channels/slack/self-identity.js +27 -35
  115. package/dist/channels/slack/sender-name.d.ts +12 -3
  116. package/dist/channels/slack/sender-name.d.ts.map +1 -1
  117. package/dist/channels/slack/sender-name.js +57 -61
  118. package/dist/channels/slack/setup.js +2 -4
  119. package/dist/channels/slack/slack-channel.d.ts +6 -4
  120. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  121. package/dist/channels/slack/slack-channel.js +441 -308
  122. package/dist/channels/slack/socket-mode.js +38 -52
  123. package/dist/channels/slack/thread-context.js +143 -160
  124. package/dist/channels/slack/tool-approval-events.js +149 -166
  125. package/dist/channels/slack/tool-cards.js +6 -11
  126. package/dist/channels/slack/tool-chip.js +1 -2
  127. package/dist/channels/slack/types.d.ts +15 -17
  128. package/dist/channels/slack/types.d.ts.map +1 -1
  129. package/dist/channels/slack/upload.js +84 -97
  130. package/dist/channels/slack/user-info.js +27 -41
  131. package/dist/channels.js +9 -20
  132. package/dist/dashboard-session-url.js +3 -4
  133. package/dist/docs/404.html +2 -2
  134. package/dist/docs/assets/{app.oyjtOr3W.js → app.DXI7bwox.js} +4 -4
  135. package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.js → building-with-agents.md.Df87rAe1.js} +1 -1
  136. package/dist/docs/assets/chunks/@localSearchIndexroot.CtLtpWcx.js +1 -0
  137. package/dist/docs/assets/chunks/{VPLocalSearchBox.D0P6J_UJ.js → VPLocalSearchBox.BrbO5mEe.js} +1 -1
  138. package/dist/docs/assets/chunks/{arc.B0LY1J1h.js → arc.BOG1yms8.js} +1 -1
  139. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.dPduLUxY.js → architectureDiagram-Q4EWVU46.C0hsMZnZ.js} +1 -1
  140. package/dist/docs/assets/chunks/{baseUniq.B_Ohm21h.js → baseUniq.H044KjKs.js} +1 -1
  141. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.B4zcanaJ.js → blockDiagram-DXYQGD6D.BsRW6GoB.js} +1 -1
  142. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.D9Iw21nx.js → c4Diagram-AHTNJAMY.B9HV5PFR.js} +1 -1
  143. package/dist/docs/assets/chunks/channel.CBwrU9rP.js +1 -0
  144. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.DDVwRShI.js → chunk-4BX2VUAB.CPoT_ajl.js} +1 -1
  145. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.DsYcdn1i.js → chunk-4TB4RGXK.DZBwWuCL.js} +1 -1
  146. package/dist/docs/assets/chunks/{chunk-55IACEB6.BzzQvcYp.js → chunk-55IACEB6.CZ3yTiyq.js} +1 -1
  147. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.BMiXZ7FX.js → chunk-EDXVE4YY.6DfvHSd8.js} +1 -1
  148. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.D_mBcLoc.js → chunk-FMBD7UC4.CpBj8HfK.js} +1 -1
  149. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CMVjWVMx.js → chunk-OYMX7WX6.BdKo8YqS.js} +1 -1
  150. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BG-FrPv9.js → chunk-QZHKN3VN.BnXNyxJx.js} +1 -1
  151. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.CkFE1ap3.js → chunk-YZCP3GAM.Cg1OcF8G.js} +1 -1
  152. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CbC_mrvB.js +1 -0
  153. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CbC_mrvB.js +1 -0
  154. package/dist/docs/assets/chunks/clone.BTvFyY1a.js +1 -0
  155. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.BVNnCTvY.js → cose-bilkent-S5V4N54A.1SP8al9c.js} +1 -1
  156. package/dist/docs/assets/chunks/{dagre-KV5264BT.CDN5PR9l.js → dagre-KV5264BT.DS1L6hJt.js} +1 -1
  157. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.DQRUlT-i.js → diagram-5BDNPKRD.ChsausbG.js} +1 -1
  158. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.CoeblYQT.js → diagram-G4DWMVQ6.3XsptNWj.js} +1 -1
  159. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.DW3ymjl0.js → diagram-MMDJMWI5.DPA9Dk_P.js} +1 -1
  160. package/dist/docs/assets/chunks/{diagram-TYMM5635.BP0uN4Jw.js → diagram-TYMM5635.BVswXWrB.js} +1 -1
  161. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.DVFUWEn4.js → erDiagram-SMLLAGMA.BSak5OSP.js} +1 -1
  162. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.HU-eHspv.js → flowDiagram-DWJPFMVM.CQgN4TTz.js} +1 -1
  163. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.DHNhXijY.js → ganttDiagram-T4ZO3ILL.GrT0kA4a.js} +1 -1
  164. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.DkISXcO3.js → gitGraphDiagram-UUTBAWPF.CdS7Ucll.js} +1 -1
  165. package/dist/docs/assets/chunks/{graph.CCV0fuRR.js → graph.BVqKRmRo.js} +1 -1
  166. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.bgILzOoc.js → infoDiagram-42DDH7IO.C3C9FRto.js} +1 -1
  167. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.CuryXC0F.js → ishikawaDiagram-UXIWVN3A.2FuAh_Zj.js} +1 -1
  168. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.BL1Pr-wu.js → journeyDiagram-VCZTEJTY.CaHMfK4b.js} +1 -1
  169. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.BbGjvk4l.js → kanban-definition-6JOO6SKY.CjhIUwcA.js} +1 -1
  170. package/dist/docs/assets/chunks/{layout.C4PfdldS.js → layout.CGU3gfSf.js} +1 -1
  171. package/dist/docs/assets/chunks/{linear.C3xD1T6X.js → linear.DaihpW_n.js} +1 -1
  172. package/dist/docs/assets/chunks/{min.CzgRAQ9c.js → min.BS-j8kHQ.js} +1 -1
  173. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CA9rSWum.js → mindmap-definition-QFDTVHPH.BVJ1Bbnk.js} +1 -1
  174. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.B8MprgJu.js → pieDiagram-DEJITSTG.Cz1WIv9r.js} +1 -1
  175. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.DndDwbKT.js → quadrantDiagram-34T5L4WZ.DKLFxcjy.js} +1 -1
  176. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.Zhfgwlnn.js → requirementDiagram-MS252O5E.BHegiK7x.js} +1 -1
  177. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.B6RRm6N5.js → sankeyDiagram-XADWPNL6.DYkY6yPc.js} +1 -1
  178. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.Bfmz-1PN.js → sequenceDiagram-FGHM5R23.DYQ1QUrI.js} +1 -1
  179. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.gbrdNqgj.js → stateDiagram-FHFEXIEX.Iru8BsFo.js} +1 -1
  180. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.BYXl4LW6.js +1 -0
  181. package/dist/docs/assets/chunks/{theme.gpWjytMh.js → theme.DaplWQhQ.js} +2 -2
  182. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.Bl1l7M1f.js → timeline-definition-GMOUNBTQ.BwFA8hiX.js} +1 -1
  183. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.Dfle4U0d.js → vennDiagram-DHZGUBPP.CZ60W1C_.js} +1 -1
  184. package/dist/docs/assets/chunks/wardley-RL74JXVD.iXazD3Z7.js +162 -0
  185. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.CM_4lmvZ.js → wardleyDiagram-NUSXRM2D.B69D2r8-.js} +1 -1
  186. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.CHT5X28R.js → xychartDiagram-5P7HB3ND.CLPZEIU9.js} +1 -1
  187. package/dist/docs/assets/{deployment.md.BdqTiGdc.js → deployment.md.BYuEcDBv.js} +2 -2
  188. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.js → guides_bitbucket.md.CKUayYtD.js} +3 -3
  189. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.lean.js → guides_bitbucket.md.CKUayYtD.lean.js} +1 -1
  190. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.js → guides_github.md.TuNiZAOQ.js} +4 -4
  191. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.lean.js → guides_github.md.TuNiZAOQ.lean.js} +1 -1
  192. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.js → guides_gitlab.md.CtNI4fSH.js} +4 -4
  193. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.lean.js → guides_gitlab.md.CtNI4fSH.lean.js} +1 -1
  194. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.js +7 -0
  195. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.lean.js +1 -0
  196. package/dist/docs/assets/{reference_cli.md.GwugN3n-.js → reference_cli.md.dYCAL2lB.js} +4 -3
  197. package/dist/docs/assets/reference_cli.md.dYCAL2lB.lean.js +1 -0
  198. package/dist/docs/assets/{reference_skills.md.ClkMoQsV.js → reference_skills.md.C0guGcH0.js} +3 -3
  199. package/dist/docs/assets/troubleshooting.md.x-GBa7wN.js +1 -0
  200. package/dist/docs/assets/{troubleshooting.md.Bscj6ODe.lean.js → troubleshooting.md.x-GBa7wN.lean.js} +1 -1
  201. package/dist/docs/building-with-agents.html +37 -37
  202. package/dist/docs/building-with-agents.md +2 -0
  203. package/dist/docs/deployment.html +38 -38
  204. package/dist/docs/deployment.md +7 -0
  205. package/dist/docs/evals.html +36 -36
  206. package/dist/docs/guides/agent-to-agent.html +35 -35
  207. package/dist/docs/guides/bitbucket.html +38 -38
  208. package/dist/docs/guides/bitbucket.md +9 -1
  209. package/dist/docs/guides/cloud-agents.html +35 -35
  210. package/dist/docs/guides/convert-automation.html +35 -35
  211. package/dist/docs/guides/github.html +39 -39
  212. package/dist/docs/guides/github.md +20 -4
  213. package/dist/docs/guides/gitlab.html +38 -38
  214. package/dist/docs/guides/gitlab.md +9 -1
  215. package/dist/docs/guides/grokbot-agents.html +35 -35
  216. package/dist/docs/guides/hooks.html +35 -35
  217. package/dist/docs/guides/improve.html +35 -35
  218. package/dist/docs/guides/jev.html +35 -35
  219. package/dist/docs/guides/mcp-oauth.html +35 -35
  220. package/dist/docs/guides/migrate.html +66 -0
  221. package/dist/docs/guides/migrate.md +122 -0
  222. package/dist/docs/guides/opentelemetry.html +35 -35
  223. package/dist/docs/guides/slack.html +35 -35
  224. package/dist/docs/guides/webhooks.html +35 -35
  225. package/dist/docs/hashmap.json +1 -1
  226. package/dist/docs/hillclimbing.html +35 -35
  227. package/dist/docs/index.html +35 -35
  228. package/dist/docs/llms-full.txt +214 -6
  229. package/dist/docs/llms.txt +1 -0
  230. package/dist/docs/quickstart.html +35 -35
  231. package/dist/docs/reference/agent-config.html +35 -35
  232. package/dist/docs/reference/artifacts.html +35 -35
  233. package/dist/docs/reference/channels.html +35 -35
  234. package/dist/docs/reference/cli.html +39 -38
  235. package/dist/docs/reference/cli.md +39 -0
  236. package/dist/docs/reference/connections.html +35 -35
  237. package/dist/docs/reference/evals.html +35 -35
  238. package/dist/docs/reference/extensions.html +35 -35
  239. package/dist/docs/reference/hooks.html +35 -35
  240. package/dist/docs/reference/http-api.html +35 -35
  241. package/dist/docs/reference/instructions.html +35 -35
  242. package/dist/docs/reference/playground.html +35 -35
  243. package/dist/docs/reference/project-layout.html +35 -35
  244. package/dist/docs/reference/prompt.html +35 -35
  245. package/dist/docs/reference/schedules.html +35 -35
  246. package/dist/docs/reference/sessions.html +35 -35
  247. package/dist/docs/reference/skills.html +38 -38
  248. package/dist/docs/reference/subagents.html +35 -35
  249. package/dist/docs/reference/tools.html +35 -35
  250. package/dist/docs/templates/agentic-owners.html +35 -35
  251. package/dist/docs/templates/grokbot-agents.html +35 -35
  252. package/dist/docs/templates/security-reviewer.html +35 -35
  253. package/dist/docs/templates/thermo-quality-review.html +35 -35
  254. package/dist/docs/templates/thermo-review.html +35 -35
  255. package/dist/docs/templates/triage.html +35 -35
  256. package/dist/docs/troubleshooting.html +36 -36
  257. package/dist/docs/troubleshooting.md +1 -0
  258. package/dist/evals/assertions.js +20 -34
  259. package/dist/evals/expect.js +3 -6
  260. package/dist/evals/judge.js +5 -8
  261. package/dist/evals/loaders.js +45 -62
  262. package/dist/evals/matchers.js +2 -3
  263. package/dist/evals/reporters.js +43 -67
  264. package/dist/evals/results.js +1 -1
  265. package/dist/evals/run-facts.js +5 -6
  266. package/dist/evals.js +27 -15
  267. package/dist/extensions/cursor-cloud-agents/extension.js +4 -1
  268. package/dist/extensions/cursor-cloud-agents/lib/backend.d.ts +0 -1
  269. package/dist/extensions/cursor-cloud-agents/lib/backend.d.ts.map +1 -1
  270. package/dist/extensions/cursor-cloud-agents/lib/backend.js +101 -130
  271. package/dist/extensions/cursor-cloud-agents/lib/fleet.js +22 -38
  272. package/dist/extensions/cursor-cloud-agents/lib/repos.js +8 -10
  273. package/dist/extensions/cursor-cloud-agents/lib/transcript.js +2 -3
  274. package/dist/extensions/cursor-cloud-agents/lib/watch.js +52 -66
  275. package/dist/extensions/cursor-cloud-agents/reminders/cloud-agent-stop-watch.js +29 -40
  276. package/dist/extensions/cursor-cloud-agents/tools/cancel.js +6 -17
  277. package/dist/extensions/cursor-cloud-agents/tools/dump.js +25 -36
  278. package/dist/extensions/cursor-cloud-agents/tools/get.js +3 -14
  279. package/dist/extensions/cursor-cloud-agents/tools/launch.js +13 -21
  280. package/dist/extensions/cursor-cloud-agents/tools/list.d.ts.map +1 -1
  281. package/dist/extensions/cursor-cloud-agents/tools/list.js +9 -20
  282. package/dist/extensions/cursor-cloud-agents/tools/reply.js +5 -16
  283. package/dist/extensions/cursor-grokbot-agents/extension.js +4 -1
  284. package/dist/extensions/cursor-grokbot-agents/lib/agents.js +3 -3
  285. package/dist/extensions/cursor-grokbot-agents/lib/backend.js +53 -73
  286. package/dist/extensions/cursor-grokbot-agents/lib/contacts.js +10 -23
  287. package/dist/extensions/cursor-grokbot-agents/lib/conversation.js +112 -132
  288. package/dist/extensions/cursor-grokbot-agents/lib/lock.js +1 -2
  289. package/dist/extensions/cursor-grokbot-agents/tools/ask.js +5 -16
  290. package/dist/extensions/cursor-grokbot-agents/tools/check.js +4 -15
  291. package/dist/extensions/cursor-grokbot-agents/tools/interrupt.js +2 -13
  292. package/dist/extensions/cursor-grokbot-agents/tools/list.js +11 -23
  293. package/dist/extensions/jev/extension.js +3 -3
  294. package/dist/extensions/jev/lib/evaluate.js +43 -60
  295. package/dist/extensions/jev/tools/evaluate.js +6 -17
  296. package/dist/extensions/slack-communication/tools/post-file.js +1 -1
  297. package/dist/extensions.js +3 -5
  298. package/dist/files-backends/cursor-hosted.js +504 -523
  299. package/dist/files-backends/local-fs.js +72 -134
  300. package/dist/files.js +3 -3
  301. package/dist/filesystem.js +562 -861
  302. package/dist/index.js +16 -35
  303. package/dist/internal/advertise-tools.js +74 -86
  304. package/dist/internal/artifacts-store.js +298 -361
  305. package/dist/internal/as-of.js +2 -4
  306. package/dist/internal/authored-alias-hooks.js +6 -4
  307. package/dist/internal/authored-loaders.js +37 -52
  308. package/dist/internal/bounded-int.js +1 -2
  309. package/dist/internal/bounded.js +13 -24
  310. package/dist/internal/brand.js +1 -1
  311. package/dist/internal/browser-origin-guard.js +4 -4
  312. package/dist/internal/builtin-tools/artifacts.js +15 -27
  313. package/dist/internal/builtin-tools/index.js +2 -3
  314. package/dist/internal/builtin-tools/reminders.js +33 -52
  315. package/dist/internal/channel-architecture.d.ts +21 -0
  316. package/dist/internal/channel-architecture.d.ts.map +1 -0
  317. package/dist/internal/channel-architecture.js +41 -0
  318. package/dist/internal/channel-dispatch.js +3 -4
  319. package/dist/internal/channel-route-dispatch.js +40 -51
  320. package/dist/internal/channel-state.js +1 -1
  321. package/dist/internal/chat-client.js +319 -340
  322. package/dist/internal/cli-ax.js +1262 -1294
  323. package/dist/internal/cli-bitbucket.js +244 -272
  324. package/dist/internal/cli-convert-automation.js +137 -151
  325. package/dist/internal/cli-cursor.js +126 -147
  326. package/dist/internal/cli-deploy.d.ts.map +1 -1
  327. package/dist/internal/cli-deploy.js +1457 -1507
  328. package/dist/internal/cli-docs.js +130 -147
  329. package/dist/internal/cli-github.js +437 -476
  330. package/dist/internal/cli-gitlab.js +259 -288
  331. package/dist/internal/cli-images.js +266 -334
  332. package/dist/internal/cli-manifest.js +25 -37
  333. package/dist/internal/cli-mcp-oauth.js +228 -247
  334. package/dist/internal/cli-mcp.js +358 -383
  335. package/dist/internal/cli-migrate.d.ts +18 -0
  336. package/dist/internal/cli-migrate.d.ts.map +1 -0
  337. package/dist/internal/cli-migrate.js +136 -0
  338. package/dist/internal/cli-skills.js +35 -47
  339. package/dist/internal/cli-slack-manual.d.ts +0 -1
  340. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  341. package/dist/internal/cli-slack-manual.js +175 -204
  342. package/dist/internal/cli-slack.d.ts +1 -1
  343. package/dist/internal/cli-slack.d.ts.map +1 -1
  344. package/dist/internal/cli-slack.js +416 -456
  345. package/dist/internal/cloud-merge.js +7 -3
  346. package/dist/internal/cloud-turn-cost.js +8 -1
  347. package/dist/internal/connection-env.js +5 -6
  348. package/dist/internal/continuation-channel.js +10 -7
  349. package/dist/internal/continuation-identity.js +85 -67
  350. package/dist/internal/conversation-mirror.js +112 -131
  351. package/dist/internal/convert-automation/convert-workflow.js +21 -31
  352. package/dist/internal/cron.js +3 -3
  353. package/dist/internal/cursor/account-mcp.js +147 -146
  354. package/dist/internal/cursor/backend-client.js +290 -320
  355. package/dist/internal/cursor/bound-secret-file.js +3 -3
  356. package/dist/internal/cursor/credentials.d.ts +1 -0
  357. package/dist/internal/cursor/credentials.d.ts.map +1 -1
  358. package/dist/internal/cursor/credentials.js +130 -142
  359. package/dist/internal/cursor/cursor-api-transport.js +4 -8
  360. package/dist/internal/cursor/github-credentials.js +91 -108
  361. package/dist/internal/cursor/hosted-bound-secrets.js +3 -4
  362. package/dist/internal/cursor/hosted-deployment-secrets.js +1 -1
  363. package/dist/internal/cursor/hosted-store-secrets.js +5 -9
  364. package/dist/internal/cursor/session-token.js +36 -48
  365. package/dist/internal/cursor/store-api-client.js +77 -92
  366. package/dist/internal/cursor-account-mcp-auth.js +132 -149
  367. package/dist/internal/cursor-agent-template.js +1 -1
  368. package/dist/internal/cursor-deployment-relay.js +33 -54
  369. package/dist/internal/cursor-event-relay.js +65 -59
  370. package/dist/internal/cursor-relay-core.js +258 -286
  371. package/dist/internal/deferred-channel-session.js +3 -12
  372. package/dist/internal/deploy-client.js +410 -475
  373. package/dist/internal/deploy-manifest.d.ts +17 -0
  374. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  375. package/dist/internal/deploy-manifest.js +71 -21
  376. package/dist/internal/deploy-source.js +31 -43
  377. package/dist/internal/discovery/agent-config.js +45 -59
  378. package/dist/internal/discovery/agent.js +276 -280
  379. package/dist/internal/discovery/channels.js +67 -80
  380. package/dist/internal/discovery/connections.js +286 -296
  381. package/dist/internal/discovery/context.js +2 -13
  382. package/dist/internal/discovery/cursor-plugin.js +223 -259
  383. package/dist/internal/discovery/extension-overlay.js +104 -131
  384. package/dist/internal/discovery/extensions.js +276 -281
  385. package/dist/internal/discovery/fs.js +56 -79
  386. package/dist/internal/discovery/hooks.js +39 -50
  387. package/dist/internal/discovery/info.js +17 -19
  388. package/dist/internal/discovery/instructions.js +58 -71
  389. package/dist/internal/discovery/modules.js +45 -58
  390. package/dist/internal/discovery/project.d.ts.map +1 -1
  391. package/dist/internal/discovery/project.js +192 -215
  392. package/dist/internal/discovery/reminders.js +41 -52
  393. package/dist/internal/discovery/runtime.js +1 -1
  394. package/dist/internal/discovery/schedules.js +71 -82
  395. package/dist/internal/discovery/seed-files.js +21 -32
  396. package/dist/internal/discovery/services.js +74 -96
  397. package/dist/internal/discovery/skills.js +77 -94
  398. package/dist/internal/discovery/subagent.js +79 -95
  399. package/dist/internal/discovery/tools.js +12 -23
  400. package/dist/internal/distribution.js +2 -2
  401. package/dist/internal/docs-site.js +30 -45
  402. package/dist/internal/duration.js +1 -1
  403. package/dist/internal/env-file.js +48 -64
  404. package/dist/internal/eval-judge-model.js +17 -28
  405. package/dist/internal/eval-run-store.js +265 -254
  406. package/dist/internal/eval-runner.d.ts +8 -0
  407. package/dist/internal/eval-runner.d.ts.map +1 -1
  408. package/dist/internal/eval-runner.js +406 -408
  409. package/dist/internal/eval-transport.d.ts +24 -0
  410. package/dist/internal/eval-transport.d.ts.map +1 -0
  411. package/dist/internal/eval-transport.js +22 -0
  412. package/dist/internal/evals-client.js +242 -246
  413. package/dist/internal/event-log.js +72 -120
  414. package/dist/internal/event-mapper.js +30 -31
  415. package/dist/internal/factory-resource-channel.js +16 -30
  416. package/dist/internal/filesystem/errors.js +6 -6
  417. package/dist/internal/filesystem/format.js +10 -13
  418. package/dist/internal/filesystem/merge.js +52 -94
  419. package/dist/internal/filesystem/nearest.js +15 -27
  420. package/dist/internal/filesystem/scratch.js +65 -85
  421. package/dist/internal/filesystem/tools.js +221 -241
  422. package/dist/internal/filesystem/walk.js +76 -143
  423. package/dist/internal/framework-file-storage.js +118 -139
  424. package/dist/internal/framework-storage-selection.js +21 -13
  425. package/dist/internal/frontmatter.js +4 -6
  426. package/dist/internal/github-fanout.js +50 -64
  427. package/dist/internal/guest-network.js +96 -109
  428. package/dist/internal/handleAgentServeTrigger.js +121 -126
  429. package/dist/internal/host-files.js +73 -88
  430. package/dist/internal/host-kv.js +21 -36
  431. package/dist/internal/host-otel.js +22 -19
  432. package/dist/internal/host-platforms.js +49 -63
  433. package/dist/internal/hosted-catch-protocol.d.ts +1 -0
  434. package/dist/internal/hosted-catch-protocol.d.ts.map +1 -1
  435. package/dist/internal/hosted-catch-protocol.js +1 -0
  436. package/dist/internal/hosted-catch.d.ts +5 -3
  437. package/dist/internal/hosted-catch.d.ts.map +1 -1
  438. package/dist/internal/hosted-catch.js +84 -93
  439. package/dist/internal/hosted-delivery-protocol.js +32 -8
  440. package/dist/internal/hosted-delivery.d.ts +13 -1
  441. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  442. package/dist/internal/hosted-delivery.js +614 -584
  443. package/dist/internal/hosted-eval-cases.d.ts +21 -0
  444. package/dist/internal/hosted-eval-cases.d.ts.map +1 -0
  445. package/dist/internal/hosted-eval-cases.js +162 -0
  446. package/dist/internal/hosted-execution-diag.js +38 -30
  447. package/dist/internal/hosted-execution-flush.js +75 -66
  448. package/dist/internal/hosted-execution-latency.js +16 -8
  449. package/dist/internal/hosted-managed-automation.js +2 -2
  450. package/dist/internal/hosting.js +2 -3
  451. package/dist/internal/http-channel-define.js +4 -1
  452. package/dist/internal/http-channel.js +101 -112
  453. package/dist/internal/http-control-plane-session.d.ts +18 -1
  454. package/dist/internal/http-control-plane-session.d.ts.map +1 -1
  455. package/dist/internal/http-control-plane-session.js +66 -32
  456. package/dist/internal/incoming-headers-to-fetch.js +1 -2
  457. package/dist/internal/init-interview.js +73 -93
  458. package/dist/internal/init-project.js +182 -214
  459. package/dist/internal/init-scaffold.js +10 -21
  460. package/dist/internal/inline-stdio-mcp.js +80 -86
  461. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  462. package/dist/internal/install-cursor-skills.js +238 -274
  463. package/dist/internal/legacy-command-guard.js +18 -31
  464. package/dist/internal/listen-port.js +34 -45
  465. package/dist/internal/local-control-plane.js +293 -307
  466. package/dist/internal/local-env.js +1 -1
  467. package/dist/internal/local-ingress.js +15 -9
  468. package/dist/internal/log-ring.js +1 -2
  469. package/dist/internal/logs-client.js +207 -227
  470. package/dist/internal/map-pool.js +24 -38
  471. package/dist/internal/mcp-endpoint.js +204 -180
  472. package/dist/internal/mcp-host.js +165 -168
  473. package/dist/internal/mcp-oauth-on-demand.js +170 -207
  474. package/dist/internal/mcp-oauth-persist.js +15 -29
  475. package/dist/internal/mcp-oauth.js +209 -266
  476. package/dist/internal/named-webhook-secret.d.ts +39 -0
  477. package/dist/internal/named-webhook-secret.d.ts.map +1 -0
  478. package/dist/internal/named-webhook-secret.js +47 -0
  479. package/dist/internal/open-browser.js +2 -3
  480. package/dist/internal/otel/collector.js +104 -68
  481. package/dist/internal/otel/config.js +24 -37
  482. package/dist/internal/otel/http.js +5 -7
  483. package/dist/internal/otel/mcp.js +3 -12
  484. package/dist/internal/otel/runtime.js +69 -83
  485. package/dist/internal/package-inline-stdio.js +57 -65
  486. package/dist/internal/peer-connections.js +9 -5
  487. package/dist/internal/platform-schedule-sync.js +39 -54
  488. package/dist/internal/platform-timers.js +176 -210
  489. package/dist/internal/playground/static.js +1 -2
  490. package/dist/internal/playground/toolchain.js +37 -53
  491. package/dist/internal/playground-proxy.js +230 -270
  492. package/dist/internal/process-memory-telemetry.js +33 -51
  493. package/dist/internal/prompt-context.js +3 -6
  494. package/dist/internal/reminder-control-plane-protocol.js +46 -13
  495. package/dist/internal/reminder-runner.js +770 -785
  496. package/dist/internal/reminder-schedule.js +1 -1
  497. package/dist/internal/reminder-store.js +57 -78
  498. package/dist/internal/request-error-status.js +1 -3
  499. package/dist/internal/request-headers.js +2 -2
  500. package/dist/internal/resolve-prod-target.js +119 -135
  501. package/dist/internal/resolved-connections.js +16 -6
  502. package/dist/internal/run-client.js +221 -229
  503. package/dist/internal/runtime-dispatch-runner.js +18 -43
  504. package/dist/internal/schedule-runner.js +49 -58
  505. package/dist/internal/scm/pr-url.js +7 -6
  506. package/dist/internal/sdk-runner.js +388 -363
  507. package/dist/internal/serve-restart.js +26 -39
  508. package/dist/internal/server.d.ts.map +1 -1
  509. package/dist/internal/server.js +1283 -1244
  510. package/dist/internal/session-cost.js +7 -9
  511. package/dist/internal/session-engine.d.ts +3 -1
  512. package/dist/internal/session-engine.d.ts.map +1 -1
  513. package/dist/internal/session-engine.js +2801 -2777
  514. package/dist/internal/session-links.js +12 -16
  515. package/dist/internal/session-run-log.js +134 -82
  516. package/dist/internal/session-store.js +133 -164
  517. package/dist/internal/sessions-client.js +97 -118
  518. package/dist/internal/skill-catalog.js +18 -23
  519. package/dist/internal/skills-sync.js +16 -30
  520. package/dist/internal/slack-provision-client.js +90 -116
  521. package/dist/internal/start-log-store.js +48 -67
  522. package/dist/internal/steering.js +1 -2
  523. package/dist/internal/storage-coordinator.js +160 -196
  524. package/dist/internal/store-mirror.js +16 -30
  525. package/dist/internal/stream-progress.js +6 -8
  526. package/dist/internal/terminal-style.js +3 -4
  527. package/dist/internal/testing/scm-continuation-fixtures.js +6 -2
  528. package/dist/internal/testing/slack-continuation-fixtures.d.ts +26 -0
  529. package/dist/internal/testing/slack-continuation-fixtures.d.ts.map +1 -0
  530. package/dist/internal/testing/slack-continuation-fixtures.js +136 -0
  531. package/dist/internal/tool-catalog.js +11 -5
  532. package/dist/internal/tool-result.js +1 -1
  533. package/dist/internal/trajectory.js +19 -22
  534. package/dist/internal/turn-cost.js +52 -62
  535. package/dist/internal/turn-governor.js +5 -8
  536. package/dist/internal/turn-lease-store.js +85 -105
  537. package/dist/internal/turn-outbox.js +28 -43
  538. package/dist/internal/update-check.js +231 -259
  539. package/dist/internal/v2-hosting.js +1 -2
  540. package/dist/internal/workspace-sync.js +25 -41
  541. package/dist/internal/workspace.js +111 -139
  542. package/dist/kv/memory-kv.js +27 -51
  543. package/dist/memory.js +106 -148
  544. package/dist/otel.js +5 -8
  545. package/dist/playground/assets/index-DXm_VXAQ.css +1 -0
  546. package/dist/playground/assets/{index-MijLHTbB.js → index-JekUQERK.js} +45 -45
  547. package/dist/playground/index.html +2 -2
  548. package/dist/prompt.js +2 -4
  549. package/dist/storage-backends/cursor-hosted-v2.js +53 -83
  550. package/dist/storage-backends/cursor-hosted.js +105 -145
  551. package/dist/storage-backends/file-kv.js +100 -128
  552. package/dist/storage-protocol.js +3 -5
  553. package/dist/storage.js +17 -26
  554. package/dist/types.d.ts +68 -0
  555. package/dist/types.d.ts.map +1 -1
  556. package/dist/types.js +20 -18
  557. package/docs/building-with-agents.md +2 -0
  558. package/docs/deployment.md +7 -0
  559. package/docs/guides/bitbucket.md +9 -1
  560. package/docs/guides/github.md +20 -4
  561. package/docs/guides/gitlab.md +9 -1
  562. package/docs/guides/migrate.md +127 -0
  563. package/docs/reference/cli.md +39 -0
  564. package/docs/troubleshooting.md +1 -0
  565. package/package.json +1 -1
  566. package/skills/debug/SKILL.md +1 -0
  567. package/skills/github/SKILL.md +23 -0
  568. package/skills/migrate-v2/SKILL.md +264 -0
  569. package/dist/docs/assets/chunks/@localSearchIndexroot.C25zYVuc.js +0 -1
  570. package/dist/docs/assets/chunks/channel.CRUyWDV-.js +0 -1
  571. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CG_UObcQ.js +0 -1
  572. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CG_UObcQ.js +0 -1
  573. package/dist/docs/assets/chunks/clone.NYSZ9qZN.js +0 -1
  574. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.DOOmulfQ.js +0 -1
  575. package/dist/docs/assets/chunks/wardley-RL74JXVD.BJrCW6xc.js +0 -162
  576. package/dist/docs/assets/reference_cli.md.GwugN3n-.lean.js +0 -1
  577. package/dist/docs/assets/troubleshooting.md.Bscj6ODe.js +0 -1
  578. package/dist/playground/assets/index-DPKLl4C_.css +0 -1
  579. /package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.lean.js → building-with-agents.md.Df87rAe1.lean.js} +0 -0
  580. /package/dist/docs/assets/{deployment.md.BdqTiGdc.lean.js → deployment.md.BYuEcDBv.lean.js} +0 -0
  581. /package/dist/docs/assets/{reference_skills.md.ClkMoQsV.lean.js → reference_skills.md.C0guGcH0.lean.js} +0 -0
@@ -4,33 +4,6 @@
4
4
  * routes, custom channel routes (under `/v1/channels/<id>`), and the
5
5
  * server-level health / info / dev-dispatch routes.
6
6
  */
7
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
- return new (P || (P = Promise))(function (resolve, reject) {
10
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
- step((generator = generator.apply(thisArg, _arguments || [])).next());
14
- });
15
- };
16
- var __rest = (this && this.__rest) || function (s, e) {
17
- var t = {};
18
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
19
- t[p] = s[p];
20
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
21
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
22
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
23
- t[p[i]] = s[p[i]];
24
- }
25
- return t;
26
- };
27
- var __asyncValues = (this && this.__asyncValues) || function (o) {
28
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
29
- var m = o[Symbol.asyncIterator], i;
30
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
31
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
32
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
33
- };
34
7
  import { Buffer } from "node:buffer";
35
8
  import { once } from "node:events";
36
9
  import { createServer } from "node:http";
@@ -58,6 +31,7 @@ import { DeploymentEventRelay, fanOutDeploymentEvent, mergeResolvedSubscriptions
58
31
  import { CursorEventRelay, formatCursorScmDispatchOutcome, formatCursorScmEventLog, scmEventToGitHubPayload, scmMetadataToOriginPayload, } from "./cursor-event-relay.js";
59
32
  import { AGENT_SERVE_GENERATION_ENV_VAR } from "./cursor-relay-core.js";
60
33
  import { buildAgentDeployManifest } from "./deploy-manifest.js";
34
+ import { describeError } from "./describe-error.js";
61
35
  import { formatDiagnostics, hasErrorDiagnostics, projectInfo } from "./discovery.js";
62
36
  import { packageVersion } from "./distribution.js";
63
37
  import { docsSiteExists, ensureDocsSiteBundle, renderDocsFile } from "./docs-site.js";
@@ -66,6 +40,7 @@ import { GUEST_NETWORK_PATH, guestNetworkReadinessResponse } from "./guest-netwo
66
40
  import { collectGitHubTriggerTargets, collectOriginTriggerTargets, handleAgentServeTrigger, } from "./handleAgentServeTrigger.js";
67
41
  import { createHostPlatforms, warmupHostGitHubAuth } from "./host-platforms.js";
68
42
  import { registerHostedDeliveryRoute } from "./hosted-delivery.js";
43
+ import { hostedEvalCatalog, hostedSendStart } from "./hosted-eval-cases.js";
69
44
  import { HOSTED_DELIVERY_HEADER, HOSTED_GUEST_RETRY_TERMINAL, hostedGuestErrorResponse, } from "./hosted-delivery-protocol.js";
70
45
  import { hostedErrorMessageOnly, hostedErrorStackSnippet } from "./hosted-execution-diag.js";
71
46
  import { flushHostedExecutionProcessDeath } from "./hosted-execution-flush.js";
@@ -116,8 +91,7 @@ function localControlPlaneRoute(runtimes) {
116
91
  return undefined;
117
92
  }
118
93
  function firstLocalControlPlane(runtimes) {
119
- var _a;
120
- return (_a = runtimes.find(runtime => runtime.controlPlane !== undefined)) === null || _a === void 0 ? void 0 : _a.controlPlane;
94
+ return runtimes.find(runtime => runtime.controlPlane !== undefined)?.controlPlane;
121
95
  }
122
96
  function isV2Project(project) {
123
97
  return project.agent.architecture === "v2";
@@ -127,181 +101,155 @@ function isV2Project(project) {
127
101
  * empty slug serves at `/v1/*` and `/playground`; multiple agents each serve
128
102
  * under `/<slug>/v1/*` and `/<slug>/playground`, with an index at `/`.
129
103
  */
130
- export function startServer(mounts_1) {
131
- return __awaiter(this, arguments, void 0, function* (mounts, options = {}) {
132
- var _a, _b, _c, _d, _e, _f;
133
- var _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
134
- var _7;
135
- if (mounts.length === 0) {
136
- throw new Error("startServer requires at least one agent mount");
104
+ export async function startServer(mounts, options = {}) {
105
+ if (mounts.length === 0) {
106
+ throw new Error("startServer requires at least one agent mount");
107
+ }
108
+ const multi = mounts.length > 1 || mounts[0]?.slug !== "";
109
+ for (const { slug, project } of mounts) {
110
+ if (hasErrorDiagnostics(project)) {
111
+ const label = slug === "" ? project.name : `${slug} (${project.name})`;
112
+ throw new Error(`Refusing to serve agent ${label} — it has errors:\n${formatDiagnostics(project.diagnostics.filter(d => d.severity === "error"))}`);
137
113
  }
138
- const multi = mounts.length > 1 || ((_a = mounts[0]) === null || _a === void 0 ? void 0 : _a.slug) !== "";
139
- for (const { slug, project } of mounts) {
140
- if (hasErrorDiagnostics(project)) {
141
- const label = slug === "" ? project.name : `${slug} (${project.name})`;
142
- throw new Error(`Refusing to serve agent ${label} — it has errors:\n${formatDiagnostics(project.diagnostics.filter(d => d.severity === "error"))}`);
114
+ }
115
+ const logRing = createLogRing({ capacity: 2000 });
116
+ const logger = logRing.wrap(options.logger ?? ((line) => console.log(line)));
117
+ const dev = options.dev ?? false;
118
+ const playground = options.playground ?? true;
119
+ const hosted = options;
120
+ const noControlPlane = hosted.noControlPlane === true;
121
+ const scmProxyRequested = hosted.cursorScmProxy === true;
122
+ const runSchedules = options.schedules ?? !dev;
123
+ const runReminders = options.reminders ?? !dev;
124
+ // CURSOR_AGENTKIT_VERSION is still the env the SDK reads when building
125
+ // its client-version header (wire prefix remains `agentkit-`). Setting it
126
+ // here makes the internal-only agentkit_enabled gate apply to every turn.
127
+ process.env.CURSOR_AGENTKIT_VERSION ??= packageVersion();
128
+ const authoredOtel = pickAuthoredOtel(mounts.map(m => ({
129
+ slug: m.slug,
130
+ name: m.project.name,
131
+ otel: m.project.otel,
132
+ })));
133
+ const resolveOtelExport = () => resolveOtelConfig({
134
+ authored: authoredOtel,
135
+ serve: options.otel,
136
+ });
137
+ const otelRuntime = createOtelRuntime(resolveOtelExport(), logger, {
138
+ resolveExport: resolveOtelExport,
139
+ });
140
+ const cursorGithubTargets = collectCursorGithubTargets(mounts);
141
+ const cursorOriginTargets = collectCursorOriginTargets(mounts);
142
+ const cursorGithubConfig = resolveCursorGithubEventConfig({
143
+ configured: options.cursorEvents,
144
+ targets: cursorGithubTargets,
145
+ });
146
+ const cursorOriginScope = resolveCursorOriginRepoScope({
147
+ explicitRepos: options.cursorEvents?.repos ?? [],
148
+ targets: cursorOriginTargets,
149
+ });
150
+ const effectiveCursorEvents = options.evals === true
151
+ ? undefined
152
+ : (cursorGithubConfig.cursorEvents ??
153
+ (cursorOriginScope === undefined ? undefined : { repos: [...cursorOriginScope.repos] }));
154
+ // One resolution for every Cursor credential consumer (SDK runner, account
155
+ // MCP bridge, SCM event relay, GitHub credentials): explicit option →
156
+ // CURSOR_API_KEY → CURSOR_API_KEY_FILE (or the hosted default path) →
157
+ // CURSOR_SERVICE_ACCOUNT_KEY → stored `agent-sdk login`. SDK / GitHub /
158
+ // account MCP re-read later; Slack and deployment-event relays capture
159
+ // the key at start.
160
+ const accountKey = await resolveApiKey(options.apiKey === undefined ? {} : { apiKey: options.apiKey });
161
+ // First present source wins (we define the order): option → env → file →
162
+ // service account → stored login. Re-read so bind can drop env or file
163
+ // onto a listening process.
164
+ const liveCursorApiKey = () => resolveApiKeySync(options.apiKey === undefined ? {} : { apiKey: options.apiKey })?.apiKey;
165
+ // The SCM relay reads the event stream as the signed-in user, so
166
+ // `cursorEvents` cannot work signed out. Require the credential before any
167
+ // slow or stateful startup work (playground build, channel onStart, cron).
168
+ // Not on a hosted v2 guest: under `--no-control-plane` with no v1 mount
169
+ // this process never polls `/v0/scm-events` (the hosted control plane
170
+ // owns ingest), and a persistent slot starts before its first credential
171
+ // is bound, so demanding one here would refuse a guest that never needed it.
172
+ const hostedControlPlaneOwnsIngest = noControlPlane && mounts.every(mount => isV2Project(mount.project));
173
+ const cursorEventsAuth = effectiveCursorEvents === undefined || hostedControlPlaneOwnsIngest
174
+ ? undefined
175
+ : requireCursorEventsAuth(effectiveCursorEvents, accountKey);
176
+ // Two architectures + local CP + cursor-events would register two
177
+ // /v0/scm-events consumers (engine offset vs control-plane offset).
178
+ // Fail before engines or relays start. `--no-control-plane` mixed is one
179
+ // July consumer (v1 engine); hosted CP owns v2.
180
+ assertSingleCursorEventsLane({
181
+ noControlPlane,
182
+ config: effectiveCursorEvents,
183
+ auth: cursorEventsAuth,
184
+ v1Mounts: mounts.filter(mount => !isV2Project(mount.project)),
185
+ v2Mounts: mounts.filter(mount => isV2Project(mount.project)),
186
+ githubRepos: cursorGithubConfig.cursorEvents?.repos ?? [],
187
+ originRepos: cursorOriginScope?.repos ?? [],
188
+ });
189
+ let cursorGithubCredentials;
190
+ // Proxy-wired GitHub token resolver for `ctx.host.github` when no startup
191
+ // token mint runs (empty repo scope): host Octokit calls must route
192
+ // through github-proxy exactly like channel Octokit calls.
193
+ let hostGithubProxyResolver;
194
+ if (cursorGithubTargets.length > 0) {
195
+ const githubProxyRequested = scmProxyRequested;
196
+ const needsGithubAuth = cursorGithubConfig.scope !== undefined || githubProxyRequested;
197
+ if (needsGithubAuth) {
198
+ const currentGithubApiKey = () => {
199
+ const fromEvents = cursorEventsAuth?.apiKey.trim();
200
+ if (fromEvents !== undefined && fromEvents !== "") {
201
+ return fromEvents;
202
+ }
203
+ return liveCursorApiKey();
204
+ };
205
+ const githubApiKeyNow = currentGithubApiKey();
206
+ if (githubApiKeyNow === undefined && options.allowAnonymous !== true) {
207
+ throw new Error("githubChannel({ cursorAccount: true }) could not resolve Cursor event authentication.");
143
208
  }
144
- }
145
- const logRing = createLogRing({ capacity: 2000 });
146
- const logger = logRing.wrap((_g = options.logger) !== null && _g !== void 0 ? _g : ((line) => console.log(line)));
147
- const dev = (_h = options.dev) !== null && _h !== void 0 ? _h : false;
148
- const playground = (_j = options.playground) !== null && _j !== void 0 ? _j : true;
149
- const hosted = options;
150
- const noControlPlane = hosted.noControlPlane === true;
151
- const scmProxyRequested = hosted.cursorScmProxy === true;
152
- const runSchedules = (_k = options.schedules) !== null && _k !== void 0 ? _k : !dev;
153
- const runReminders = (_l = options.reminders) !== null && _l !== void 0 ? _l : !dev;
154
- // CURSOR_AGENTKIT_VERSION is still the env the SDK reads when building
155
- // its client-version header (wire prefix remains `agentkit-`). Setting it
156
- // here makes the internal-only agentkit_enabled gate apply to every turn.
157
- (_m = (_7 = process.env).CURSOR_AGENTKIT_VERSION) !== null && _m !== void 0 ? _m : (_7.CURSOR_AGENTKIT_VERSION = packageVersion());
158
- const authoredOtel = pickAuthoredOtel(mounts.map(m => ({
159
- slug: m.slug,
160
- name: m.project.name,
161
- otel: m.project.otel,
162
- })));
163
- const resolveOtelExport = () => resolveOtelConfig({
164
- authored: authoredOtel,
165
- serve: options.otel,
166
- });
167
- const otelRuntime = createOtelRuntime(resolveOtelExport(), logger, {
168
- resolveExport: resolveOtelExport,
169
- });
170
- const cursorGithubTargets = collectCursorGithubTargets(mounts);
171
- const cursorOriginTargets = collectCursorOriginTargets(mounts);
172
- const cursorGithubConfig = resolveCursorGithubEventConfig({
173
- configured: options.cursorEvents,
174
- targets: cursorGithubTargets,
175
- });
176
- const cursorOriginScope = resolveCursorOriginRepoScope({
177
- explicitRepos: (_o = (_b = options.cursorEvents) === null || _b === void 0 ? void 0 : _b.repos) !== null && _o !== void 0 ? _o : [],
178
- targets: cursorOriginTargets,
179
- });
180
- const effectiveCursorEvents = options.evals === true
181
- ? undefined
182
- : ((_p = cursorGithubConfig.cursorEvents) !== null && _p !== void 0 ? _p : (cursorOriginScope === undefined ? undefined : { repos: [...cursorOriginScope.repos] }));
183
- // One resolution for every Cursor credential consumer (SDK runner, account
184
- // MCP bridge, SCM event relay, GitHub credentials): explicit option →
185
- // CURSOR_API_KEY → CURSOR_API_KEY_FILE (or the hosted default path) →
186
- // CURSOR_SERVICE_ACCOUNT_KEY → stored `agent-sdk login`. SDK / GitHub /
187
- // account MCP re-read later; Slack and deployment-event relays capture
188
- // the key at start.
189
- const accountKey = yield resolveApiKey(options.apiKey === undefined ? {} : { apiKey: options.apiKey });
190
- // First present source wins (we define the order): option → env → file →
191
- // service account → stored login. Re-read so bind can drop env or file
192
- // onto a listening process.
193
- const liveCursorApiKey = () => { var _a; return (_a = resolveApiKeySync(options.apiKey === undefined ? {} : { apiKey: options.apiKey })) === null || _a === void 0 ? void 0 : _a.apiKey; };
194
- // The SCM relay reads the event stream as the signed-in user, so
195
- // `cursorEvents` cannot work signed out. Require the credential before any
196
- // slow or stateful startup work (playground build, channel onStart, cron).
197
- // Not on a hosted v2 guest: under `--no-control-plane` with no v1 mount
198
- // this process never polls `/v0/scm-events` (the hosted control plane
199
- // owns ingest), and a persistent slot starts before its first credential
200
- // is bound, so demanding one here would refuse a guest that never needed it.
201
- const hostedControlPlaneOwnsIngest = noControlPlane && mounts.every(mount => isV2Project(mount.project));
202
- const cursorEventsAuth = effectiveCursorEvents === undefined || hostedControlPlaneOwnsIngest
203
- ? undefined
204
- : requireCursorEventsAuth(effectiveCursorEvents, accountKey);
205
- // Two architectures + local CP + cursor-events would register two
206
- // /v0/scm-events consumers (engine offset vs control-plane offset).
207
- // Fail before engines or relays start. `--no-control-plane` mixed is one
208
- // July consumer (v1 engine); hosted CP owns v2.
209
- assertSingleCursorEventsLane({
210
- noControlPlane,
211
- config: effectiveCursorEvents,
212
- auth: cursorEventsAuth,
213
- v1Mounts: mounts.filter(mount => !isV2Project(mount.project)),
214
- v2Mounts: mounts.filter(mount => isV2Project(mount.project)),
215
- githubRepos: (_q = (_c = cursorGithubConfig.cursorEvents) === null || _c === void 0 ? void 0 : _c.repos) !== null && _q !== void 0 ? _q : [],
216
- originRepos: (_r = cursorOriginScope === null || cursorOriginScope === void 0 ? void 0 : cursorOriginScope.repos) !== null && _r !== void 0 ? _r : [],
217
- });
218
- let cursorGithubCredentials;
219
- // Proxy-wired GitHub token resolver for `ctx.host.github` when no startup
220
- // token mint runs (empty repo scope): host Octokit calls must route
221
- // through github-proxy exactly like channel Octokit calls.
222
- let hostGithubProxyResolver;
223
- if (cursorGithubTargets.length > 0) {
224
- const githubProxyRequested = scmProxyRequested;
225
- const needsGithubAuth = cursorGithubConfig.scope !== undefined || githubProxyRequested;
226
- if (needsGithubAuth) {
227
- const currentGithubApiKey = () => {
228
- const fromEvents = cursorEventsAuth === null || cursorEventsAuth === void 0 ? void 0 : cursorEventsAuth.apiKey.trim();
229
- if (fromEvents !== undefined && fromEvents !== "") {
230
- return fromEvents;
231
- }
232
- return liveCursorApiKey();
233
- };
234
- const githubApiKeyNow = currentGithubApiKey();
235
- if (githubApiKeyNow === undefined && options.allowAnonymous !== true) {
236
- throw new Error("githubChannel({ cursorAccount: true }) could not resolve Cursor event authentication.");
209
+ if (options.allowAnonymous === true) {
210
+ if (options.allowAnonymousCursorGithub !== true) {
211
+ throw new Error("githubChannel({ cursorAccount: true }) cannot be served with --allow-anonymous because admitted callers could use the signed-in account's GitHub access. If every admitted caller is trusted (e.g. behind an SSO proxy), opt in with --allow-anonymous-cursor-github.");
237
212
  }
238
- if (options.allowAnonymous === true) {
239
- if (options.allowAnonymousCursorGithub !== true) {
240
- throw new Error("githubChannel({ cursorAccount: true }) cannot be served with --allow-anonymous because admitted callers could use the signed-in account's GitHub access. If every admitted caller is trusted (e.g. behind an SSO proxy), opt in with --allow-anonymous-cursor-github.");
241
- }
242
- logger("[bdk] warning: --allow-anonymous-cursor-github — every admitted HTTP caller can drive sessions holding the signed-in account's repo-scoped GitHub credential; serve this only behind a trusted boundary (e.g. an SSO proxy)");
243
- if (githubApiKeyNow === undefined) {
244
- logger("[bdk] GitHub auth: listening unsigned; credentials bind at task via CURSOR_API_KEY or CURSOR_API_KEY_FILE");
245
- }
213
+ logger("[bdk] warning: --allow-anonymous-cursor-github — every admitted HTTP caller can drive sessions holding the signed-in account's repo-scoped GitHub credential; serve this only behind a trusted boundary (e.g. an SSO proxy)");
214
+ if (githubApiKeyNow === undefined) {
215
+ logger("[bdk] GitHub auth: listening unsigned; credentials bind at task via CURSOR_API_KEY or CURSOR_API_KEY_FILE");
246
216
  }
247
- if (cursorGithubConfig.permissions === "contents-write") {
248
- logger('[bdk] warning: Cursor GitHub credentials include contents:write — the host holds a push-capable token shared with model-driven tools and untrusted webhook content; prefer permissions: "pr-write" unless this agent must push code');
217
+ }
218
+ if (cursorGithubConfig.permissions === "contents-write") {
219
+ logger('[bdk] warning: Cursor GitHub credentials include contents:write — the host holds a push-capable token shared with model-driven tools and untrusted webhook content; prefer permissions: "pr-write" unless this agent must push code');
220
+ }
221
+ const githubAuthBaseUrl = cursorExternalApiUrl();
222
+ const requireGithubApiKey = async () => {
223
+ const apiKey = currentGithubApiKey();
224
+ if (apiKey === undefined) {
225
+ throw new Error(`githubChannel({ cursorAccount: true }) has no Cursor credential yet. ${SIGN_IN_HINT}`);
249
226
  }
250
- const githubAuthBaseUrl = cursorExternalApiUrl();
251
- const requireGithubApiKey = () => __awaiter(this, void 0, void 0, function* () {
252
- const apiKey = currentGithubApiKey();
253
- if (apiKey === undefined) {
254
- throw new Error(`githubChannel({ cursorAccount: true }) has no Cursor credential yet. ${SIGN_IN_HINT}`);
255
- }
256
- return apiKey;
257
- });
258
- const githubProxyUrl = githubProxyRequested
259
- ? resolveCursorGithubProxyUrl(githubAuthBaseUrl)
260
- : undefined;
261
- if (cursorGithubConfig.scope !== undefined && githubApiKeyNow !== undefined) {
262
- const provider = new CursorGithubCredentialProvider({
263
- client: new CursorBackendClient({
264
- backendUrl: githubAuthBaseUrl,
265
- apiKey: githubApiKeyNow,
266
- getApiKey: () => { var _a; return (_a = currentGithubApiKey()) !== null && _a !== void 0 ? _a : ""; },
267
- logger,
268
- }),
269
- scope: cursorGithubConfig.scope,
227
+ return apiKey;
228
+ };
229
+ const githubProxyUrl = githubProxyRequested
230
+ ? resolveCursorGithubProxyUrl(githubAuthBaseUrl)
231
+ : undefined;
232
+ if (cursorGithubConfig.scope !== undefined && githubApiKeyNow !== undefined) {
233
+ const provider = new CursorGithubCredentialProvider({
234
+ client: new CursorBackendClient({
235
+ backendUrl: githubAuthBaseUrl,
236
+ apiKey: githubApiKeyNow,
237
+ getApiKey: () => currentGithubApiKey() ?? "",
270
238
  logger,
271
- });
272
- cursorGithubCredentials = provider;
273
- if (githubProxyUrl !== undefined) {
274
- // Proxy mode: channel Octokit calls carry the Cursor API key to the
275
- // backend forwarder, which swaps in the installation token server-side
276
- // and logs every call with per-deployment attribution. The provider
277
- // still runs so child `gh` processes get a `GH_TOKEN` lease (v1).
278
- const proxyTransport = {
279
- apiBaseUrl: githubProxyUrl,
280
- headers: {
281
- "x-cursor-github-repos": cursorGithubConfig.scope.repos.join(","),
282
- "x-cursor-github-permissions": cursorGithubConfig.permissions,
283
- },
284
- };
285
- for (const target of cursorGithubTargets) {
286
- target.accountRuntime.credentials.bind(requireGithubApiKey);
287
- target.accountRuntime.credentials.bindProxyTransport(proxyTransport);
288
- }
289
- logger(`[bdk] GitHub auth: channel API calls route through ${githubProxyUrl}`);
290
- }
291
- else {
292
- for (const target of cursorGithubTargets) {
293
- target.accountRuntime.credentials.bind(() => provider.getToken());
294
- }
295
- }
296
- }
297
- else if (githubProxyUrl !== undefined) {
298
- // `cursorAccount: true` with no `--repo`: skip the startup token mint
299
- // (it requires a repo list) and let github-proxy take the repo from
300
- // each Octokit call. Hosted freeze bakes this flag into the template
301
- // so restore is GitHub-ready once Bind drops the key.
239
+ }),
240
+ scope: cursorGithubConfig.scope,
241
+ logger,
242
+ });
243
+ cursorGithubCredentials = provider;
244
+ if (githubProxyUrl !== undefined) {
245
+ // Proxy mode: channel Octokit calls carry the Cursor API key to the
246
+ // backend forwarder, which swaps in the installation token server-side
247
+ // and logs every call with per-deployment attribution. The provider
248
+ // still runs so child `gh` processes get a `GH_TOKEN` lease (v1).
302
249
  const proxyTransport = {
303
250
  apiBaseUrl: githubProxyUrl,
304
251
  headers: {
252
+ "x-cursor-github-repos": cursorGithubConfig.scope.repos.join(","),
305
253
  "x-cursor-github-permissions": cursorGithubConfig.permissions,
306
254
  },
307
255
  };
@@ -309,268 +257,311 @@ export function startServer(mounts_1) {
309
257
  target.accountRuntime.credentials.bind(requireGithubApiKey);
310
258
  target.accountRuntime.credentials.bindProxyTransport(proxyTransport);
311
259
  }
312
- // `ctx.host.github` gets the same proxy transport; without this it
313
- // would fall back to ambient auth (env token / `gh`) or an
314
- // unauthenticated Octokit, and every host GitHub call would 404.
315
- hostGithubProxyResolver = createCursorGithubProxyHostResolver({
316
- getApiKey: requireGithubApiKey,
317
- transport: proxyTransport,
318
- });
319
- logger(`[bdk] GitHub auth: channel and host API calls route through ${githubProxyUrl} (repo scope per request)`);
260
+ logger(`[bdk] GitHub auth: channel API calls route through ${githubProxyUrl}`);
261
+ }
262
+ else {
263
+ for (const target of cursorGithubTargets) {
264
+ target.accountRuntime.credentials.bind(() => provider.getToken());
265
+ }
320
266
  }
321
267
  }
268
+ else if (githubProxyUrl !== undefined) {
269
+ // `cursorAccount: true` with no `--repo`: skip the startup token mint
270
+ // (it requires a repo list) and let github-proxy take the repo from
271
+ // each Octokit call. Hosted freeze bakes this flag into the template
272
+ // so restore is GitHub-ready once Bind drops the key.
273
+ const proxyTransport = {
274
+ apiBaseUrl: githubProxyUrl,
275
+ headers: {
276
+ "x-cursor-github-permissions": cursorGithubConfig.permissions,
277
+ },
278
+ };
279
+ for (const target of cursorGithubTargets) {
280
+ target.accountRuntime.credentials.bind(requireGithubApiKey);
281
+ target.accountRuntime.credentials.bindProxyTransport(proxyTransport);
282
+ }
283
+ // `ctx.host.github` gets the same proxy transport; without this it
284
+ // would fall back to ambient auth (env token / `gh`) or an
285
+ // unauthenticated Octokit, and every host GitHub call would 404.
286
+ hostGithubProxyResolver = createCursorGithubProxyHostResolver({
287
+ getApiKey: requireGithubApiKey,
288
+ transport: proxyTransport,
289
+ });
290
+ logger(`[bdk] GitHub auth: channel and host API calls route through ${githubProxyUrl} (repo scope per request)`);
291
+ }
322
292
  }
323
- // GitLab `cursorAccount` channels: `ctx.gitlab` routes through the SCM
324
- // proxy in proxy mode. Without `--cursor-scm-proxy` the runtime stays
325
- // unbound and the handle falls back to direct `GITLAB_TOKEN` access.
326
- if (scmProxyRequested) {
327
- const gitlabProxyUrl = resolveCursorGitLabProxyUrl(cursorExternalApiUrl());
328
- let gitlabTargets = 0;
329
- for (const mount of mounts) {
330
- for (const channel of mount.project.channels) {
331
- const runtime = getGitLabCursorAccountRuntime(channel.definition);
332
- if (runtime === undefined) {
333
- continue;
334
- }
335
- gitlabTargets += 1;
336
- const transport = Object.assign({ apiBaseUrl: gitlabProxyUrl }, (runtime.scope === undefined
293
+ }
294
+ // GitLab `cursorAccount` channels: `ctx.gitlab` routes through the SCM
295
+ // proxy in proxy mode. Without `--cursor-scm-proxy` the runtime stays
296
+ // unbound and the handle falls back to direct `GITLAB_TOKEN` access.
297
+ if (scmProxyRequested) {
298
+ const gitlabProxyUrl = resolveCursorGitLabProxyUrl(cursorExternalApiUrl());
299
+ let gitlabTargets = 0;
300
+ for (const mount of mounts) {
301
+ for (const channel of mount.project.channels) {
302
+ const runtime = getGitLabCursorAccountRuntime(channel.definition);
303
+ if (runtime === undefined) {
304
+ continue;
305
+ }
306
+ gitlabTargets += 1;
307
+ const transport = {
308
+ apiBaseUrl: gitlabProxyUrl,
309
+ ...(runtime.scope === undefined
337
310
  ? {}
338
311
  : {
339
312
  headers: {
340
313
  [CURSOR_GITLAB_PROJECTS_HEADER]: runtime.scope.projects.join(","),
341
314
  },
342
- }));
343
- runtime.credentials.bind(() => __awaiter(this, void 0, void 0, function* () {
344
- const apiKey = liveCursorApiKey();
345
- if (apiKey === undefined) {
346
- throw new Error(`gitlabChannel({ cursorAccount }) has no Cursor credential yet. ${SIGN_IN_HINT}`);
347
- }
348
- return apiKey;
349
- }));
350
- runtime.credentials.bindProxyTransport(transport);
351
- }
352
- }
353
- if (gitlabTargets > 0) {
354
- logger(`[bdk] GitLab auth: channel API calls route through ${gitlabProxyUrl}`);
355
- }
356
- // Bitbucket `cursorAccount` channels: same shape, `/v0/bitbucket-proxy`
357
- // with `x-cursor-bitbucket-repos` scope. The proxy picks Cloud 2.0 or
358
- // the DC host's 1.0 upstream per tenant; the pack picks the dialect
359
- // from the delivery payload.
360
- const bitbucketProxyUrl = resolveCursorBitbucketProxyUrl(cursorExternalApiUrl());
361
- let bitbucketTargets = 0;
362
- for (const mount of mounts) {
363
- for (const channel of mount.project.channels) {
364
- const runtime = getBitbucketCursorAccountRuntime(channel.definition);
365
- if (runtime === undefined) {
366
- continue;
315
+ }),
316
+ };
317
+ runtime.credentials.bind(async () => {
318
+ const apiKey = liveCursorApiKey();
319
+ if (apiKey === undefined) {
320
+ throw new Error(`gitlabChannel({ cursorAccount }) has no Cursor credential yet. ${SIGN_IN_HINT}`);
367
321
  }
368
- bitbucketTargets += 1;
369
- const transport = Object.assign({ apiBaseUrl: bitbucketProxyUrl }, (runtime.scope === undefined
322
+ return apiKey;
323
+ });
324
+ runtime.credentials.bindProxyTransport(transport);
325
+ }
326
+ }
327
+ if (gitlabTargets > 0) {
328
+ logger(`[bdk] GitLab auth: channel API calls route through ${gitlabProxyUrl}`);
329
+ }
330
+ // Bitbucket `cursorAccount` channels: same shape, `/v0/bitbucket-proxy`
331
+ // with `x-cursor-bitbucket-repos` scope. The proxy picks Cloud 2.0 or
332
+ // the DC host's 1.0 upstream per tenant; the pack picks the dialect
333
+ // from the delivery payload.
334
+ const bitbucketProxyUrl = resolveCursorBitbucketProxyUrl(cursorExternalApiUrl());
335
+ let bitbucketTargets = 0;
336
+ for (const mount of mounts) {
337
+ for (const channel of mount.project.channels) {
338
+ const runtime = getBitbucketCursorAccountRuntime(channel.definition);
339
+ if (runtime === undefined) {
340
+ continue;
341
+ }
342
+ bitbucketTargets += 1;
343
+ const transport = {
344
+ apiBaseUrl: bitbucketProxyUrl,
345
+ ...(runtime.scope === undefined
370
346
  ? {}
371
347
  : {
372
348
  headers: {
373
349
  [CURSOR_BITBUCKET_REPOS_HEADER]: runtime.scope.repos.join(","),
374
350
  },
375
- }));
376
- runtime.credentials.bind(() => __awaiter(this, void 0, void 0, function* () {
377
- const apiKey = liveCursorApiKey();
378
- if (apiKey === undefined) {
379
- throw new Error(`bitbucketChannel({ cursorAccount }) has no Cursor credential yet. ${SIGN_IN_HINT}`);
380
- }
381
- return apiKey;
382
- }));
383
- runtime.credentials.bindProxyTransport(transport);
384
- }
385
- }
386
- if (bitbucketTargets > 0) {
387
- logger(`[bdk] Bitbucket auth: channel API calls route through ${bitbucketProxyUrl}`);
351
+ }),
352
+ };
353
+ runtime.credentials.bind(async () => {
354
+ const apiKey = liveCursorApiKey();
355
+ if (apiKey === undefined) {
356
+ throw new Error(`bitbucketChannel({ cursorAccount }) has no Cursor credential yet. ${SIGN_IN_HINT}`);
357
+ }
358
+ return apiKey;
359
+ });
360
+ runtime.credentials.bindProxyTransport(transport);
388
361
  }
389
362
  }
390
- const resolvedCursorGithubCredentials = cursorGithubCredentials;
391
- const hostGithubToken = hostGithubProxyResolver !== null && hostGithubProxyResolver !== void 0 ? hostGithubProxyResolver : (resolvedCursorGithubCredentials === undefined
363
+ if (bitbucketTargets > 0) {
364
+ logger(`[bdk] Bitbucket auth: channel API calls route through ${bitbucketProxyUrl}`);
365
+ }
366
+ }
367
+ const resolvedCursorGithubCredentials = cursorGithubCredentials;
368
+ const hostGithubToken = hostGithubProxyResolver ??
369
+ (resolvedCursorGithubCredentials === undefined
392
370
  ? undefined
393
371
  : createCursorAccountGithubTokenResolver(() => resolvedCursorGithubCredentials.getToken()));
394
- const hostPlatforms = createHostPlatforms(hostGithubToken === undefined ? {} : { githubCredentials: { token: hostGithubToken } });
395
- if (playground) {
396
- // Auto-build dist/playground when missing (monorepo / source checkout).
397
- // Published installs already ship the bundle; vite may be absent there.
398
- yield ensurePlaygroundBundle(logger);
399
- }
400
- const docsSite = (_s = options.docs) !== null && _s !== void 0 ? _s : true;
401
- if (docsSite) {
402
- // Same pattern for the documentation site at /docs.
403
- yield ensureDocsSiteBundle(logger);
404
- }
405
- if (options.allowAnonymous === true) {
406
- logger("[bdk] warning: --allow-anonymous admits every HTTP caller as the same principal; use only on a trusted network (e.g. Tailscale) and prefer --bearer-token for shared hosts");
407
- }
408
- // v2 hosted engines mirror the SDK conversation store to the deployment's
409
- // shared file storage so a fresh pod resumes threads instead of forking
410
- // them. Hosted serve is single-agent; a multi-mount serve (dev) has no
411
- // single agent name to mint keys under and does not mirror.
412
- const conversationMirror = mounts.length === 1 && mounts[0] !== undefined
413
- ? selectConversationMirror({ project: mounts[0].project, logger })
414
- : undefined;
415
- const sessionRunLog = (_t = options.sessionRunLog) !== null && _t !== void 0 ? _t : (mounts.length === 1 && mounts[0] !== undefined
372
+ const hostPlatforms = createHostPlatforms(hostGithubToken === undefined ? {} : { githubCredentials: { token: hostGithubToken } });
373
+ if (playground) {
374
+ // Auto-build dist/playground when missing (monorepo / source checkout).
375
+ // Published installs already ship the bundle; vite may be absent there.
376
+ await ensurePlaygroundBundle(logger);
377
+ }
378
+ const docsSite = options.docs ?? true;
379
+ if (docsSite) {
380
+ // Same pattern for the documentation site at /docs.
381
+ await ensureDocsSiteBundle(logger);
382
+ }
383
+ if (options.allowAnonymous === true) {
384
+ logger("[bdk] warning: --allow-anonymous admits every HTTP caller as the same principal; use only on a trusted network (e.g. Tailscale) and prefer --bearer-token for shared hosts");
385
+ }
386
+ // v2 hosted engines mirror the SDK conversation store to the deployment's
387
+ // shared file storage so a fresh pod resumes threads instead of forking
388
+ // them. Hosted serve is single-agent; a multi-mount serve (dev) has no
389
+ // single agent name to mint keys under and does not mirror.
390
+ const conversationMirror = mounts.length === 1 && mounts[0] !== undefined
391
+ ? selectConversationMirror({ project: mounts[0].project, logger })
392
+ : undefined;
393
+ const sessionRunLog = options.sessionRunLog ??
394
+ (mounts.length === 1 && mounts[0] !== undefined
416
395
  ? selectSessionRunLogStore({
417
396
  project: mounts[0].project,
418
397
  logger,
419
398
  snapshotLogs: () => logRing.since(),
420
399
  })
421
400
  : undefined);
422
- const startLogStore = (_u = options.startLogStore) !== null && _u !== void 0 ? _u : (mounts.length === 1 && mounts[0] !== undefined
401
+ const startLogStore = options.startLogStore ??
402
+ (mounts.length === 1 && mounts[0] !== undefined
423
403
  ? selectStartLogStore({
424
404
  project: mounts[0].project,
425
405
  logger,
426
406
  })
427
407
  : undefined);
428
- // The running claim stamps this before the turn; process-death flush
429
- // reuses it so the tee snapshot lands under the same ses_ key.
430
- let lastStartLogId;
431
- const flushStartLog = (startLogId) => __awaiter(this, void 0, void 0, function* () {
432
- lastStartLogId = startLogId;
433
- if (startLogStore === undefined) {
434
- return;
435
- }
436
- yield flushLocalStartLog({ store: startLogStore, startLogId });
437
- });
438
- if (sessionRunLog !== undefined) {
439
- registerSessionRunFatalFlush((error) => __awaiter(this, void 0, void 0, function* () {
440
- yield flushHostedExecutionProcessDeath({
441
- flushProcessDeath: (reason, flushError) => sessionRunLog.flushProcessDeath(reason, flushError),
442
- flushStartLog,
443
- startLogId: lastStartLogId,
444
- reason: "uncaught_exception",
445
- error,
446
- });
447
- }));
448
- }
449
- const sdkRunner = (_v = options.runner) !== null && _v !== void 0 ? _v : new CursorSdkRunner(Object.assign(Object.assign(Object.assign({}, (options.apiKey === undefined || options.apiKey.trim() === ""
450
- ? {}
451
- : { apiKey: options.apiKey })), (conversationMirror === undefined ? {} : { conversationMirror })), { logger }));
452
- // Grok Bot turns run on Cursor's hosted Grok Bot (Sand) harness through
453
- // the /v0/grokbot session API; the SDK side is a thin remote client. The
454
- // dispatching runner is only interposed when a mount needs it. An
455
- // injected test runner receives every turn, grokbot included.
456
- const hasGrokBotMounts = mounts.some(mount => mount.project.agent.runtime === "grokbot");
457
- // Fail closed like cursor-account GitHub/MCP: grokbot turns execute on the
458
- // signed-in account's hosted computer, so anonymous admission needs its
459
- // own opt-in.
460
- if (hasGrokBotMounts && options.allowAnonymous === true) {
461
- if (options.allowAnonymousGrokbot !== true) {
462
- throw new Error('runtime: "grokbot" cannot be served with --allow-anonymous because admitted callers could drive the signed-in account\'s hosted Grok Bot computer. If every admitted caller is trusted (e.g. behind an SSO proxy), opt in with --allow-anonymous-grokbot.');
463
- }
464
- logger("[bdk] warning: --allow-anonymous-grokbot — every admitted HTTP caller can drive turns on the signed-in account's hosted Grok Bot computer; serve this only behind a trusted boundary (e.g. an SSO proxy)");
408
+ // The running claim stamps this before the turn; process-death flush
409
+ // reuses it so the tee snapshot lands under the same ses_ key.
410
+ let lastStartLogId;
411
+ const flushStartLog = async (startLogId) => {
412
+ lastStartLogId = startLogId;
413
+ if (startLogStore === undefined) {
414
+ return;
465
415
  }
466
- let runner = sdkRunner;
467
- if (hasGrokBotMounts && options.runner === undefined) {
468
- // Cursor-internal client, left out of the npm tarball (`files`); loaded
469
- // only when a mount needs it, so a published install fails here, before
470
- // listen, rather than on the first turn.
471
- const { GrokBotRunner } = yield import("./grokbot/runner.js").catch(() => {
472
- throw new Error('runtime: "grokbot" is not available in the published @cursor/bdk package');
473
- });
474
- runner = new RuntimeDispatchingRunner({
475
- sdkRunner,
476
- grokbot: new GrokBotRunner({
477
- apiKey: options.apiKey,
478
- // `/v0/grokbot` lives on the external API (api.cursor.com), not
479
- // api2. Prefer that default over the account key's backendUrl.
480
- // Do not pass stored login as apiKey: that would pin it as an
481
- // option and beat a later CURSOR_API_KEY_FILE bind.
482
- backendUrl: cursorExternalApiUrl(),
483
- }),
416
+ await flushLocalStartLog({ store: startLogStore, startLogId });
417
+ };
418
+ if (sessionRunLog !== undefined) {
419
+ registerSessionRunFatalFlush(async (error) => {
420
+ await flushHostedExecutionProcessDeath({
421
+ flushProcessDeath: (reason, flushError) => sessionRunLog.flushProcessDeath(reason, flushError),
422
+ flushStartLog,
423
+ startLogId: lastStartLogId,
424
+ reason: "uncaught_exception",
425
+ error,
484
426
  });
485
- logger("[bdk] grokbot runtime: remote client (turns run on the hosted Grok Bot harness)");
427
+ });
428
+ }
429
+ const sdkRunner = options.runner ??
430
+ new CursorSdkRunner({
431
+ ...(options.apiKey === undefined || options.apiKey.trim() === ""
432
+ ? {}
433
+ : { apiKey: options.apiKey }),
434
+ ...(conversationMirror === undefined ? {} : { conversationMirror }),
435
+ logger,
436
+ });
437
+ // Grok Bot turns run on Cursor's hosted Grok Bot (Sand) harness through
438
+ // the /v0/grokbot session API; the SDK side is a thin remote client. The
439
+ // dispatching runner is only interposed when a mount needs it. An
440
+ // injected test runner receives every turn, grokbot included.
441
+ const hasGrokBotMounts = mounts.some(mount => mount.project.agent.runtime === "grokbot");
442
+ // Fail closed like cursor-account GitHub/MCP: grokbot turns execute on the
443
+ // signed-in account's hosted computer, so anonymous admission needs its
444
+ // own opt-in.
445
+ if (hasGrokBotMounts && options.allowAnonymous === true) {
446
+ if (options.allowAnonymousGrokbot !== true) {
447
+ throw new Error('runtime: "grokbot" cannot be served with --allow-anonymous because admitted callers could drive the signed-in account\'s hosted Grok Bot computer. If every admitted caller is trusted (e.g. behind an SSO proxy), opt in with --allow-anonymous-grokbot.');
486
448
  }
487
- const router = new Router();
488
- const runtimes = [];
489
- const channelStopHooks = [];
490
- let githubAuthWarmed = false;
491
- // Validate peer MCP connections (defineConnection({ agent })) against the
492
- // mount set before anything starts: unknown slugs and self-references are
493
- // authoring errors. URLs resolve after listen, once the port is known.
494
- const peerRefsBySlug = collectPeerConnections(mounts);
495
- // Cursor account MCP connections (defineConnection({ cursorAccount: true }))
496
- // need a signed-in host: their tools execute on the Cursor backend with
497
- // the account's stored OAuth credentials. Fail fast at serve start instead
498
- // of at the first turn.
499
- const accountRefsBySlug = collectCursorAccountConnections(mounts);
500
- assertAccountConnectionsNotAnonymous({
501
- allowAnonymous: options.allowAnonymous,
502
- allowAnonymousCursorAccountMcp: options.allowAnonymousCursorAccountMcp,
503
- hasAccountConnections: accountRefsBySlug.size > 0,
449
+ logger("[bdk] warning: --allow-anonymous-grokbot — every admitted HTTP caller can drive turns on the signed-in account's hosted Grok Bot computer; serve this only behind a trusted boundary (e.g. an SSO proxy)");
450
+ }
451
+ let runner = sdkRunner;
452
+ if (hasGrokBotMounts && options.runner === undefined) {
453
+ // Cursor-internal client, left out of the npm tarball (`files`); loaded
454
+ // only when a mount needs it, so a published install fails here, before
455
+ // listen, rather than on the first turn.
456
+ const { GrokBotRunner } = await import("./grokbot/runner.js").catch(() => {
457
+ throw new Error('runtime: "grokbot" is not available in the published @cursor/bdk package');
458
+ });
459
+ runner = new RuntimeDispatchingRunner({
460
+ sdkRunner,
461
+ grokbot: new GrokBotRunner({
462
+ apiKey: options.apiKey,
463
+ // `/v0/grokbot` lives on the external API (api.cursor.com), not
464
+ // api2. Prefer that default over the account key's backendUrl.
465
+ // Do not pass stored login as apiKey: that would pin it as an
466
+ // option and beat a later CURSOR_API_KEY_FILE bind.
467
+ backendUrl: cursorExternalApiUrl(),
468
+ }),
504
469
  });
505
- if (options.allowAnonymous === true &&
506
- options.allowAnonymousCursorAccountMcp === true &&
507
- accountRefsBySlug.size > 0) {
508
- logger("[bdk] warning: --allow-anonymous-cursor-account-mcp — every admitted HTTP caller can drive Cursor account MCP connectors; serve this only behind a trusted boundary (e.g. an SSO proxy or hosted alias token)");
470
+ logger("[bdk] grokbot runtime: remote client (turns run on the hosted Grok Bot harness)");
471
+ }
472
+ const router = new Router();
473
+ const runtimes = [];
474
+ const channelStopHooks = [];
475
+ let githubAuthWarmed = false;
476
+ // Validate peer MCP connections (defineConnection({ agent })) against the
477
+ // mount set before anything starts: unknown slugs and self-references are
478
+ // authoring errors. URLs resolve after listen, once the port is known.
479
+ const peerRefsBySlug = collectPeerConnections(mounts);
480
+ // Cursor account MCP connections (defineConnection({ cursorAccount: true }))
481
+ // need a signed-in host: their tools execute on the Cursor backend with
482
+ // the account's stored OAuth credentials. Fail fast at serve start instead
483
+ // of at the first turn.
484
+ const accountRefsBySlug = collectCursorAccountConnections(mounts);
485
+ assertAccountConnectionsNotAnonymous({
486
+ allowAnonymous: options.allowAnonymous,
487
+ allowAnonymousCursorAccountMcp: options.allowAnonymousCursorAccountMcp,
488
+ hasAccountConnections: accountRefsBySlug.size > 0,
489
+ });
490
+ if (options.allowAnonymous === true &&
491
+ options.allowAnonymousCursorAccountMcp === true &&
492
+ accountRefsBySlug.size > 0) {
493
+ logger("[bdk] warning: --allow-anonymous-cursor-account-mcp — every admitted HTTP caller can drive Cursor account MCP connectors; serve this only behind a trusted boundary (e.g. an SSO proxy or hosted alias token)");
494
+ }
495
+ let accountBridge;
496
+ if (accountRefsBySlug.size > 0) {
497
+ if (accountKey === undefined && options.allowAnonymous !== true) {
498
+ throw new Error(`This project has Cursor account MCP connections (defineConnection({ cursorAccount: true })) but the host is not signed in to Cursor. ${SIGN_IN_HINT}`);
509
499
  }
510
- let accountBridge;
511
- if (accountRefsBySlug.size > 0) {
512
- if (accountKey === undefined && options.allowAnonymous !== true) {
513
- throw new Error(`This project has Cursor account MCP connections (defineConnection({ cursorAccount: true })) but the host is not signed in to Cursor. ${SIGN_IN_HINT}`);
514
- }
515
- if (accountKey === undefined) {
516
- logger("[bdk] Cursor account MCP: listening unsigned; credentials bind at task via CURSOR_API_KEY or CURSOR_API_KEY_FILE");
517
- }
518
- accountBridge = new CursorAccountMcpBridge({
519
- client: new CursorBackendClient({
520
- backendUrl: (_w = accountKey === null || accountKey === void 0 ? void 0 : accountKey.backendUrl) !== null && _w !== void 0 ? _w : cursorBackendUrl(),
521
- apiKey: (_x = accountKey === null || accountKey === void 0 ? void 0 : accountKey.apiKey) !== null && _x !== void 0 ? _x : "",
522
- getApiKey: () => { var _a; return (_a = liveCursorApiKey()) !== null && _a !== void 0 ? _a : ""; },
523
- logger,
524
- }),
525
- logger,
526
- // Cloud turns reach the bridge through the serve publicUrl; without
527
- // one, the bridge admits loopback callers only.
528
- allowRemoteCallers: options.publicUrl !== undefined,
529
- });
500
+ if (accountKey === undefined) {
501
+ logger("[bdk] Cursor account MCP: listening unsigned; credentials bind at task via CURSOR_API_KEY or CURSOR_API_KEY_FILE");
530
502
  }
531
- for (const { slug, project } of mounts) {
532
- // Each agent gets an isolated state root so their sessions never mix.
533
- const baseStateRoot = (_y = options.stateRoot) !== null && _y !== void 0 ? _y : join(project.rootDir, ".agent-serve");
534
- const stateRoot = slug === "" ? baseStateRoot : join(baseStateRoot, slug);
535
- const otelCollector = otelRuntime === undefined
536
- ? undefined
537
- : createOtelCollector(otelRuntime, project.name, logger);
538
- const engine = new SessionEngine({
539
- project,
540
- stateRoot,
541
- runner,
503
+ accountBridge = new CursorAccountMcpBridge({
504
+ client: new CursorBackendClient({
505
+ backendUrl: accountKey?.backendUrl ?? cursorBackendUrl(),
506
+ apiKey: accountKey?.apiKey ?? "",
507
+ getApiKey: () => liveCursorApiKey() ?? "",
542
508
  logger,
543
- platforms: hostPlatforms,
544
- otel: otelCollector,
545
- otelMeter: otelRuntime === null || otelRuntime === void 0 ? void 0 : otelRuntime.meter,
509
+ }),
510
+ logger,
511
+ // Cloud turns reach the bridge through the serve publicUrl; without
512
+ // one, the bridge admits loopback callers only.
513
+ allowRemoteCallers: options.publicUrl !== undefined,
514
+ });
515
+ }
516
+ for (const { slug, project } of mounts) {
517
+ // Each agent gets an isolated state root so their sessions never mix.
518
+ const baseStateRoot = options.stateRoot ?? join(project.rootDir, ".agent-serve");
519
+ const stateRoot = slug === "" ? baseStateRoot : join(baseStateRoot, slug);
520
+ const otelCollector = otelRuntime === undefined
521
+ ? undefined
522
+ : createOtelCollector(otelRuntime, project.name, logger);
523
+ const engine = new SessionEngine({
524
+ project,
525
+ stateRoot,
526
+ runner,
527
+ logger,
528
+ platforms: hostPlatforms,
529
+ otel: otelCollector,
530
+ otelMeter: otelRuntime?.meter,
531
+ });
532
+ engine.oauthCallbackHub.secrets = options.mcpOauthSecrets;
533
+ engine.oauthCallbackHub.secretsBind = {
534
+ slug: slug === "" ? undefined : slug,
535
+ cloudToolsUrl: options.cloudToolsUrl,
536
+ };
537
+ engine.oauthCallbackHub.logger = logger;
538
+ // Rehydrate sessions from the authored storage sink before any
539
+ // channel or route can address them (continuation tokens must resolve).
540
+ await engine.restoreStoredSessions();
541
+ // Resolve a shared harness workspace in the background: on a large repo
542
+ // that takes seconds, and a deployment coming online should absorb it
543
+ // rather than whoever sends the first message. No-op unless the agent
544
+ // pins `local.workspaceDir`.
545
+ void engine.prewarmSharedWorkspace();
546
+ if (!githubAuthWarmed) {
547
+ // Soft ambient GitHub auth check before channel onStart (which may call
548
+ // host.github). Missing auth is a warning only — serve still starts.
549
+ await warmupHostGitHubAuth({
550
+ logger,
551
+ github: engine.host.github,
552
+ ...(cursorGithubCredentials === undefined ? {} : { authSource: "cursor-account" }),
546
553
  });
547
- engine.oauthCallbackHub.secrets = options.mcpOauthSecrets;
548
- engine.oauthCallbackHub.secretsBind = {
549
- slug: slug === "" ? undefined : slug,
550
- cloudToolsUrl: options.cloudToolsUrl,
551
- };
552
- engine.oauthCallbackHub.logger = logger;
553
- // Rehydrate sessions from the authored storage sink before any
554
- // channel or route can address them (continuation tokens must resolve).
555
- yield engine.restoreStoredSessions();
556
- // Resolve a shared harness workspace in the background: on a large repo
557
- // that takes seconds, and a deployment coming online should absorb it
558
- // rather than whoever sends the first message. No-op unless the agent
559
- // pins `local.workspaceDir`.
560
- void engine.prewarmSharedWorkspace();
561
- if (!githubAuthWarmed) {
562
- // Soft ambient GitHub auth check before channel onStart (which may call
563
- // host.github). Missing auth is a warning only — serve still starts.
564
- yield warmupHostGitHubAuth(Object.assign({ logger, github: engine.host.github }, (cursorGithubCredentials === undefined ? {} : { authSource: "cursor-account" })));
565
- githubAuthWarmed = true;
566
- }
567
- const scheduleRunner = new ScheduleRunner(engine, project, logger);
568
- let reminderRunner;
569
- const architecture = project.agent.architecture;
570
- const useReminderCpProtocol = architecture === "v2";
571
- const localControlPlane = noControlPlane
572
- ? undefined
573
- : yield createLocalControlPlane(Object.assign(Object.assign({ fireSchedule: name => scheduleRunner.dispatch(name) }, (useReminderCpProtocol
554
+ githubAuthWarmed = true;
555
+ }
556
+ const scheduleRunner = new ScheduleRunner(engine, project, logger);
557
+ let reminderRunner;
558
+ const architecture = project.agent.architecture;
559
+ const useReminderCpProtocol = architecture === "v2";
560
+ const localControlPlane = noControlPlane
561
+ ? undefined
562
+ : await createLocalControlPlane({
563
+ fireSchedule: name => scheduleRunner.dispatch(name),
564
+ ...(useReminderCpProtocol
574
565
  ? {
575
566
  executeReminder: descriptor => reminderRunner.executeFire(descriptor),
576
567
  }
@@ -578,498 +569,540 @@ export function startServer(mounts_1) {
578
569
  fireReminder: (id, fireCount) => reminderRunner.dispatch(id, {
579
570
  expectedFireCount: fireCount,
580
571
  }),
581
- })), { stateDir: join(stateRoot, "control-plane"), armReminderClocks: runReminders, logger }));
582
- const timerClient = noControlPlane ? createCursorHostedPlatformTimers() : localControlPlane;
583
- const hostedReminderControlPlane = noControlPlane && useReminderCpProtocol
584
- ? createCursorHostedReminderControlPlane()
585
- : undefined;
586
- const reminderControlPlane = useReminderCpProtocol
587
- ? (localControlPlane !== null && localControlPlane !== void 0 ? localControlPlane : hostedReminderControlPlane)
588
- : undefined;
589
- reminderRunner = new ReminderRunner(engine, logger, timerClient, {
590
- namedHandlers: (_z = project.reminders) !== null && _z !== void 0 ? _z : [],
591
- // Architecture v2 rejects anonymous run/until everywhere (local + hosted).
592
- rejectAnonymousHandlers: rejectAnonymousReminderHandlers({
593
- noControlPlane,
594
- architecture,
595
- }),
596
- architecture,
597
- controlPlane: reminderControlPlane,
598
- // Hosted admissions build their channel args with no request
599
- // principal (`buildChannelHandlerArgs` → `auth: null`), so a fire that
600
- // opens a session on a fresh pod uses the same one and a session
601
- // restored from durable storage still matches.
602
- hostedGuest: hostedReminderControlPlane === undefined ? undefined : { fireAuth: () => null },
603
- });
604
- const evalRuns = new EvalRunStore(project.rootDir, logger,
605
- // Playground eval history mirrors onto the defineStorage evals table.
606
- (_d = engine.storage) === null || _d === void 0 ? void 0 : _d.evalRuns());
607
- // Eval history restores with the same startup step as sessions (reads
608
- // also hydrate lazily, but doing it here surfaces store problems at
609
- // boot and makes /v1/dev/evals complete from the first request).
610
- yield evalRuns.hydrate();
611
- engine.setReminders({
612
- create: input => reminderRunner.create(input),
613
- list: filter => reminderRunner.list(filter),
614
- cancel: (id, reason) => reminderRunner.cancel(id, reason),
615
- cancelForContinuation: (token, reason) => reminderRunner.cancelForContinuation(token, reason),
616
- rekeyContinuation: (channelId, oldToken, newToken) => reminderRunner.rekeyContinuation(channelId, oldToken, newToken),
617
- dispatch: id => reminderRunner.dispatch(id),
618
- });
619
- engine.setEvals({
620
- list: () => evalRuns.list(),
621
- get: runId => evalRuns.get(runId),
622
- listRunsWithActive: () => evalRuns.listRunsWithActive(),
623
- start: input => evalRuns.start(input),
624
- cancel: runId => evalRuns.cancel(runId),
572
+ }),
573
+ stateDir: join(stateRoot, "control-plane"),
574
+ armReminderClocks: runReminders,
575
+ logger,
625
576
  });
626
- const runtime = Object.assign(Object.assign({ slug,
627
- project,
628
- engine,
629
- scheduleRunner,
630
- reminderRunner,
631
- evalRuns }, (localControlPlane === undefined ? {} : { controlPlane: localControlPlane })), (reminderControlPlane === undefined ? {} : { reminderControlPlane }));
632
- runtimes.push(runtime);
633
- const accountRefs = accountRefsBySlug.get(slug);
634
- mountAgentRoutes(router, runtime, Object.assign(Object.assign(Object.assign(Object.assign({ dev,
635
- playground,
577
+ const timerClient = noControlPlane ? createCursorHostedPlatformTimers() : localControlPlane;
578
+ const hostedReminderControlPlane = noControlPlane && useReminderCpProtocol
579
+ ? createCursorHostedReminderControlPlane()
580
+ : undefined;
581
+ const reminderControlPlane = useReminderCpProtocol
582
+ ? (localControlPlane ?? hostedReminderControlPlane)
583
+ : undefined;
584
+ reminderRunner = new ReminderRunner(engine, logger, timerClient, {
585
+ namedHandlers: project.reminders ?? [],
586
+ // Architecture v2 rejects anonymous run/until everywhere (local + hosted).
587
+ rejectAnonymousHandlers: rejectAnonymousReminderHandlers({
636
588
  noControlPlane,
637
- multi,
638
- logger,
639
- logRing, diagStateRoot: baseStateRoot, sessionRunLog,
640
- flushStartLog, flushOtel: () => forceFlushOtelRuntime(otelRuntime) }, (options.authToken === undefined ? {} : { authToken: options.authToken })), (options.allowAnonymous === true ? { allowAnonymous: true } : {})), (accountRefs !== undefined && accountBridge !== undefined
589
+ architecture,
590
+ }),
591
+ architecture,
592
+ controlPlane: reminderControlPlane,
593
+ // Hosted admissions build their channel args with no request
594
+ // principal (`buildChannelHandlerArgs` → `auth: null`), so a fire that
595
+ // opens a session on a fresh pod uses the same one and a session
596
+ // restored from durable storage still matches.
597
+ hostedGuest: hostedReminderControlPlane === undefined ? undefined : { fireAuth: () => null },
598
+ });
599
+ const evalRuns = new EvalRunStore(project.rootDir, logger,
600
+ // Playground eval history mirrors onto the defineStorage evals table.
601
+ engine.storage?.evalRuns());
602
+ // Eval history restores with the same startup step as sessions (reads
603
+ // also hydrate lazily, but doing it here surfaces store problems at
604
+ // boot and makes /v1/dev/evals complete from the first request).
605
+ await evalRuns.hydrate();
606
+ engine.setReminders({
607
+ create: input => reminderRunner.create(input),
608
+ list: filter => reminderRunner.list(filter),
609
+ cancel: (id, reason) => reminderRunner.cancel(id, reason),
610
+ cancelForContinuation: (token, reason) => reminderRunner.cancelForContinuation(token, reason),
611
+ rekeyContinuation: (channelId, oldToken, newToken) => reminderRunner.rekeyContinuation(channelId, oldToken, newToken),
612
+ dispatch: id => reminderRunner.dispatch(id),
613
+ });
614
+ engine.setEvals({
615
+ list: () => evalRuns.list(),
616
+ get: runId => evalRuns.get(runId),
617
+ listRunsWithActive: () => evalRuns.listRunsWithActive(),
618
+ start: input => evalRuns.start(input),
619
+ cancel: runId => evalRuns.cancel(runId),
620
+ });
621
+ const runtime = {
622
+ slug,
623
+ project,
624
+ engine,
625
+ scheduleRunner,
626
+ reminderRunner,
627
+ evalRuns,
628
+ ...(localControlPlane === undefined ? {} : { controlPlane: localControlPlane }),
629
+ ...(reminderControlPlane === undefined ? {} : { reminderControlPlane }),
630
+ };
631
+ runtimes.push(runtime);
632
+ const accountRefs = accountRefsBySlug.get(slug);
633
+ mountAgentRoutes(router, runtime, {
634
+ dev,
635
+ playground,
636
+ noControlPlane,
637
+ multi,
638
+ logger,
639
+ logRing,
640
+ diagStateRoot: baseStateRoot,
641
+ sessionRunLog,
642
+ flushStartLog,
643
+ flushOtel: () => forceFlushOtelRuntime(otelRuntime),
644
+ ...(options.authToken === undefined ? {} : { authToken: options.authToken }),
645
+ ...(options.allowAnonymous === true ? { allowAnonymous: true } : {}),
646
+ ...(accountRefs !== undefined && accountBridge !== undefined
641
647
  ? { accountBridge, accountRefs }
642
- : {})), (sdkRunner instanceof CursorSdkRunner
648
+ : {}),
649
+ ...(sdkRunner instanceof CursorSdkRunner
643
650
  ? {
644
651
  evictSdkSession: (sessionId) => {
645
652
  sdkRunner.evictSession(sessionId);
646
653
  },
647
654
  }
648
- : {})));
649
- for (const channel of project.channels) {
650
- const definition = channel.definition;
651
- if (definition.onStop !== undefined) {
652
- channelStopHooks.push(() => { var _a; return (_a = definition.onStop) === null || _a === void 0 ? void 0 : _a.call(definition); });
653
- }
654
- if (definition.onStart !== undefined) {
655
- const startArgs = {
656
- send: (message, sendOptions) => engine.send(channel.id, message, sendOptions),
657
- architecture: project.agent.architecture,
658
- getSession: sessionId => engine.getChannelSession(channel.id, sessionId),
659
- receive: (target, input) => engine.receive(target, input),
660
- callTool: (toolName, input, callOptions) => engine.callTool(toolName, input, callOptions),
661
- emitAssistantMessage: (sessionId, text) => engine.emitAssistantMessage(sessionId, text),
662
- host: engine.host,
663
- waitUntil: promise => {
664
- engine.trackBackground(promise);
665
- },
666
- resolveApproval: (sessionId, callId, decision, auth) => engine.resolveApproval(sessionId, callId, decision, auth),
667
- resolveAuth: (sessionId, callId, decision, auth) => engine.resolveAuth(sessionId, callId, decision, auth),
668
- hasContinuationSession: continuationToken => engine.hasContinuationSession(channel.id, continuationToken),
669
- isContinuationBusy: continuationToken => engine.isContinuationBusy(channel.id, continuationToken),
670
- getContinuationLastBotMessageTs: continuationToken => engine.getContinuationLastBotMessageTs(channel.id, continuationToken),
671
- interruptContinuation: continuationToken => engine.interruptContinuation(channel.id, continuationToken),
672
- logger,
673
- artifacts: engine.artifacts,
674
- };
675
- try {
676
- yield definition.onStart(startArgs);
677
- }
678
- catch (error) {
679
- logger(`[bdk] channel "${channel.id}" onStart failed: ${error instanceof Error ? ((_0 = error.stack) !== null && _0 !== void 0 ? _0 : error.message) : String(error)}`);
680
- }
681
- }
655
+ : {}),
656
+ });
657
+ for (const channel of project.channels) {
658
+ const definition = channel.definition;
659
+ if (definition.onStop !== undefined) {
660
+ channelStopHooks.push(() => definition.onStop?.());
682
661
  }
683
- if (timerClient !== undefined && runSchedules) {
684
- yield syncHostedPlatformSchedules({
685
- timers: timerClient,
686
- schedules: project.schedules,
687
- catalogPath: join(stateRoot, PLATFORM_SCHEDULE_CATALOG_FILENAME),
662
+ if (definition.onStart !== undefined) {
663
+ const startArgs = {
664
+ send: (message, sendOptions) => engine.send(channel.id, message, sendOptions),
665
+ architecture: project.agent.architecture,
666
+ getSession: sessionId => engine.getChannelSession(channel.id, sessionId),
667
+ receive: (target, input) => engine.receive(target, input),
668
+ callTool: (toolName, input, callOptions) => engine.callTool(toolName, input, callOptions),
669
+ emitAssistantMessage: (sessionId, text) => engine.emitAssistantMessage(sessionId, text),
670
+ host: engine.host,
671
+ waitUntil: promise => {
672
+ engine.trackBackground(promise);
673
+ },
674
+ resolveApproval: (sessionId, callId, decision, auth) => engine.resolveApproval(sessionId, callId, decision, auth),
675
+ resolveAuth: (sessionId, callId, decision, auth) => engine.resolveAuth(sessionId, callId, decision, auth),
676
+ hasContinuationSession: continuationToken => engine.hasContinuationSession(channel.id, continuationToken),
677
+ isContinuationBusy: continuationToken => engine.isContinuationBusy(channel.id, continuationToken),
678
+ getContinuationLastBotMessageTs: continuationToken => engine.getContinuationLastBotMessageTs(channel.id, continuationToken),
679
+ interruptContinuation: continuationToken => engine.interruptContinuation(channel.id, continuationToken),
688
680
  logger,
689
- });
690
- }
691
- if (timerClient !== undefined) {
692
- yield reminderRunner.hydrate();
681
+ artifacts: engine.artifacts,
682
+ };
683
+ try {
684
+ await definition.onStart(startArgs);
685
+ }
686
+ catch (error) {
687
+ logger(`[bdk] channel "${channel.id}" onStart failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
688
+ }
693
689
  }
694
- localControlPlane === null || localControlPlane === void 0 ? void 0 : localControlPlane.startClocks();
695
690
  }
696
- if (docsSite) {
697
- // The framework documentation site, mounted at /docs in both layouts
698
- // ("docs" is a reserved slug). Static, no secrets; unauthenticated like
699
- // the playground assets.
700
- router.add({
701
- method: "GET",
702
- pattern: "/docs",
703
- auth: "none",
704
- handler: () => renderDocsFile(""),
705
- });
706
- router.add({
707
- method: "GET",
708
- pattern: "/docs/*path",
709
- auth: "none",
710
- handler: (_request, ctx) => { var _a; return renderDocsFile((_a = ctx.params.path) !== null && _a !== void 0 ? _a : ""); },
691
+ if (timerClient !== undefined && runSchedules) {
692
+ await syncHostedPlatformSchedules({
693
+ timers: timerClient,
694
+ schedules: project.schedules,
695
+ catalogPath: join(stateRoot, PLATFORM_SCHEDULE_CATALOG_FILENAME),
696
+ logger,
711
697
  });
712
698
  }
699
+ if (timerClient !== undefined) {
700
+ await reminderRunner.hydrate();
701
+ }
702
+ localControlPlane?.startClocks();
703
+ }
704
+ if (docsSite) {
705
+ // The framework documentation site, mounted at /docs in both layouts
706
+ // ("docs" is a reserved slug). Static, no secrets; unauthenticated like
707
+ // the playground assets.
708
+ router.add({
709
+ method: "GET",
710
+ pattern: "/docs",
711
+ auth: "none",
712
+ handler: () => renderDocsFile(""),
713
+ });
714
+ router.add({
715
+ method: "GET",
716
+ pattern: "/docs/*path",
717
+ auth: "none",
718
+ handler: (_request, ctx) => renderDocsFile(ctx.params.path ?? ""),
719
+ });
720
+ }
721
+ if (multi) {
722
+ // Host-level liveness for ALB / ECS health checks. Per-agent health stays
723
+ // at `/<slug>/v1/health`; without this, multi-mode has no `/v1/health`.
724
+ router.add({
725
+ method: "GET",
726
+ pattern: "/v1/health",
727
+ auth: "none",
728
+ handler: () => jsonResponse({
729
+ ok: true,
730
+ agents: runtimes.map(({ slug, project }) => ({
731
+ slug,
732
+ name: project.name,
733
+ })),
734
+ ...memoryHealthFields(runtimes.map(runtime => runtime.engine)),
735
+ }),
736
+ });
737
+ }
738
+ // Orienting `/` for every layout (single empty-slug and multi).
739
+ // Lists playground links plus live routes (playground, health, docs).
740
+ if (playground) {
741
+ const entries = buildAgentIndexEntries(runtimes);
742
+ const indexHtml = renderAgentsIndexHtml(entries, {
743
+ docs: docsSite,
744
+ multi,
745
+ });
746
+ router.add({
747
+ method: "GET",
748
+ pattern: "/",
749
+ auth: "none",
750
+ handler: () => new Response(indexHtml, {
751
+ headers: { "content-type": "text/html; charset=utf-8" },
752
+ }),
753
+ });
713
754
  if (multi) {
714
- // Host-level liveness for ALB / ECS health checks. Per-agent health stays
715
- // at `/<slug>/v1/health`; without this, multi-mode has no `/v1/health`.
716
755
  router.add({
717
756
  method: "GET",
718
- pattern: "/v1/health",
757
+ pattern: "/v1/agents",
719
758
  auth: "none",
720
- handler: () => jsonResponse(Object.assign({ ok: true, agents: runtimes.map(({ slug, project }) => ({
721
- slug,
722
- name: project.name,
723
- })) }, memoryHealthFields(runtimes.map(runtime => runtime.engine)))),
759
+ handler: () => jsonResponse({ agents: entries }),
724
760
  });
725
761
  }
726
- // Orienting `/` for every layout (single empty-slug and multi).
727
- // Lists playground links plus live routes (playground, health, docs).
728
- if (playground) {
729
- const entries = buildAgentIndexEntries(runtimes);
730
- const indexHtml = renderAgentsIndexHtml(entries, {
731
- docs: docsSite,
732
- multi,
733
- });
734
- router.add({
735
- method: "GET",
736
- pattern: "/",
737
- auth: "none",
738
- handler: () => new Response(indexHtml, {
739
- headers: { "content-type": "text/html; charset=utf-8" },
740
- }),
762
+ }
763
+ // Shared GitHub webhook ingress: one URL fans out to every mounted agent
764
+ // that declared a github channel. Signature verification is the caller's
765
+ // job (backend `/github_webhook` already verified); we only admit loopback
766
+ // so this route is not a public unsigned endpoint. Agents decide whether
767
+ // to run via their onPullRequest / onComment / … hooks.
768
+ const collectGitHubTargetsFrom = (selected) => collectGitHubTriggerTargets({
769
+ mounts: selected.map(runtime => ({
770
+ slug: runtime.slug,
771
+ channels: runtime.project.channels,
772
+ buildHandlerArgs: channelId => buildChannelHandlerArgs({ runtime, channelId }),
773
+ })),
774
+ });
775
+ const collectOriginTargetsFrom = (selected) => collectOriginTriggerTargets({
776
+ mounts: selected.map(runtime => ({
777
+ slug: runtime.slug,
778
+ channels: runtime.project.channels,
779
+ buildHandlerArgs: channelId => buildChannelHandlerArgs({ runtime, channelId }),
780
+ })),
781
+ });
782
+ const collectGitHubTargets = () => collectGitHubTargetsFrom(runtimes);
783
+ const v1Runtimes = runtimes.filter(runtime => !isV2Project(runtime.project));
784
+ const v2Runtimes = runtimes.filter(runtime => isV2Project(runtime.project));
785
+ const v1Mounts = mounts.filter(mount => !isV2Project(mount.project));
786
+ const v2Mounts = mounts.filter(mount => isV2Project(mount.project));
787
+ router.add({
788
+ method: "POST",
789
+ pattern: "/v1/webhooks/github",
790
+ auth: [localDevStrict()],
791
+ handler: async (request) => {
792
+ const bodyText = await request.text();
793
+ const routeContinuation = localControlPlaneRoute(runtimes);
794
+ const result = await handleAgentServeTrigger({
795
+ type: "github",
796
+ bodyText,
797
+ eventName: request.headers.get("x-github-event"),
798
+ deliveryId: request.headers.get("x-github-delivery") ?? undefined,
799
+ targets: collectGitHubTargets(),
800
+ ...(routeContinuation === undefined ? {} : { routeContinuation }),
741
801
  });
742
- if (multi) {
743
- router.add({
744
- method: "GET",
745
- pattern: "/v1/agents",
746
- auth: "none",
747
- handler: () => jsonResponse({ agents: entries }),
748
- });
749
- }
750
- }
751
- // Shared GitHub webhook ingress: one URL fans out to every mounted agent
752
- // that declared a github channel. Signature verification is the caller's
753
- // job (backend `/github_webhook` already verified); we only admit loopback
754
- // so this route is not a public unsigned endpoint. Agents decide whether
755
- // to run via their onPullRequest / onComment / … hooks.
756
- const collectGitHubTargetsFrom = (selected) => collectGitHubTriggerTargets({
757
- mounts: selected.map(runtime => ({
758
- slug: runtime.slug,
759
- channels: runtime.project.channels,
760
- buildHandlerArgs: channelId => buildChannelHandlerArgs({ runtime, channelId }),
761
- })),
762
- });
763
- const collectOriginTargetsFrom = (selected) => collectOriginTriggerTargets({
764
- mounts: selected.map(runtime => ({
765
- slug: runtime.slug,
766
- channels: runtime.project.channels,
767
- buildHandlerArgs: channelId => buildChannelHandlerArgs({ runtime, channelId }),
768
- })),
769
- });
770
- const collectGitHubTargets = () => collectGitHubTargetsFrom(runtimes);
771
- const v1Runtimes = runtimes.filter(runtime => !isV2Project(runtime.project));
772
- const v2Runtimes = runtimes.filter(runtime => isV2Project(runtime.project));
773
- const v1Mounts = mounts.filter(mount => !isV2Project(mount.project));
774
- const v2Mounts = mounts.filter(mount => isV2Project(mount.project));
775
- router.add({
776
- method: "POST",
777
- pattern: "/v1/webhooks/github",
778
- auth: [localDevStrict()],
779
- handler: (request) => __awaiter(this, void 0, void 0, function* () {
780
- var _a;
781
- var _b, _c;
782
- const bodyText = yield request.text();
783
- const routeContinuation = localControlPlaneRoute(runtimes);
784
- const result = yield handleAgentServeTrigger(Object.assign({ type: "github", bodyText, eventName: request.headers.get("x-github-event"), deliveryId: (_b = request.headers.get("x-github-delivery")) !== null && _b !== void 0 ? _b : undefined, targets: collectGitHubTargets() }, (routeContinuation === undefined ? {} : { routeContinuation })));
785
- const status = result.ok ? 202 : ((_c = (_a = result.targets[0]) === null || _a === void 0 ? void 0 : _a.status) !== null && _c !== void 0 ? _c : 500);
786
- return jsonResponse(result, { status });
787
- }),
802
+ const status = result.ok ? 202 : (result.targets[0]?.status ?? 500);
803
+ return jsonResponse(result, { status });
804
+ },
805
+ });
806
+ for (const { slug, project } of mounts) {
807
+ validateMountConnectionsConfig({
808
+ slug,
809
+ project,
810
+ accountRefs: accountRefsBySlug.get(slug),
811
+ ...(options.publicUrl === undefined ? {} : { publicUrl: options.publicUrl }),
812
+ cloudToolsBridge: options.cloudToolsUrl !== undefined,
788
813
  });
789
- for (const { slug, project } of mounts) {
790
- validateMountConnectionsConfig(Object.assign(Object.assign({ slug,
791
- project, accountRefs: accountRefsBySlug.get(slug) }, (options.publicUrl === undefined ? {} : { publicUrl: options.publicUrl })), { cloudToolsBridge: options.cloudToolsUrl !== undefined }));
792
- }
793
- try {
794
- yield cursorGithubCredentials === null || cursorGithubCredentials === void 0 ? void 0 : cursorGithubCredentials.start();
795
- }
796
- catch (error) {
797
- if (options.evals !== true) {
798
- throw error;
799
- }
800
- logger(`[bdk] GitHub auth: no Cursor account credential (${error instanceof Error ? error.message : String(error)}); GitHub calls from eval sessions will fail`);
814
+ }
815
+ try {
816
+ await cursorGithubCredentials?.start();
817
+ }
818
+ catch (error) {
819
+ if (options.evals !== true) {
820
+ throw error;
801
821
  }
802
- // Cursor SCM events: v1 stays on the engine poll. v2 ingest is local-CP
803
- // only — hosted `--no-control-plane` skips the July poll (hosted CP wakes).
804
- const routeContinuation = localControlPlaneRoute(runtimes);
805
- const cursorEventsCommon = {
806
- config: effectiveCursorEvents,
807
- githubRepos: (_1 = (_e = cursorGithubConfig.cursorEvents) === null || _e === void 0 ? void 0 : _e.repos) !== null && _1 !== void 0 ? _1 : [],
808
- originRepos: (_2 = cursorOriginScope === null || cursorOriginScope === void 0 ? void 0 : cursorOriginScope.repos) !== null && _2 !== void 0 ? _2 : [],
809
- stateRoot: options.stateRoot,
810
- auth: cursorEventsAuth,
811
- logger,
812
- cursorAccountOnly: options.cursorEvents === undefined &&
813
- (cursorGithubTargets.length > 0 || cursorOriginTargets.length > 0),
814
- };
815
- const cursorEventRelay = startCursorEventRelay(Object.assign(Object.assign({}, cursorEventsCommon), { mounts: v1Mounts, collectGitHubTargets: () => collectGitHubTargetsFrom(v1Runtimes), collectOriginTargets: () => collectOriginTargetsFrom(v1Runtimes), lane: "engine", skippedV2: v2Mounts.length > 0 }));
816
- const controlPlaneScmRelay = startCursorEventRelay(Object.assign(Object.assign(Object.assign(Object.assign({}, cursorEventsCommon), { mounts: v2Mounts, collectGitHubTargets: () => collectGitHubTargetsFrom(v2Runtimes), collectOriginTargets: () => collectOriginTargetsFrom(v2Runtimes) }), (routeContinuation === undefined ? {} : { routeContinuation })), { lane: "control-plane", start: false, stateDirName: join("control-plane", "cursor-events") }));
817
- const localCp = firstLocalControlPlane(runtimes);
818
- if (controlPlaneScmRelay !== undefined) {
819
- if (localCp !== undefined) {
820
- localCp.attachScmEvents(controlPlaneScmRelay);
821
- }
822
- else {
823
- logger("[bdk] cursor-events: skipping v2 scm-events poll (--no-control-plane); hosted CP owns ingest");
824
- }
822
+ logger(`[bdk] GitHub auth: no Cursor account credential (${error instanceof Error ? error.message : String(error)}); GitHub calls from eval sessions will fail`);
823
+ }
824
+ // Cursor SCM events: v1 stays on the engine poll. v2 ingest is local-CP
825
+ // only — hosted `--no-control-plane` skips the July poll (hosted CP wakes).
826
+ const routeContinuation = localControlPlaneRoute(runtimes);
827
+ const cursorEventsCommon = {
828
+ config: effectiveCursorEvents,
829
+ githubRepos: cursorGithubConfig.cursorEvents?.repos ?? [],
830
+ originRepos: cursorOriginScope?.repos ?? [],
831
+ stateRoot: options.stateRoot,
832
+ auth: cursorEventsAuth,
833
+ logger,
834
+ cursorAccountOnly: options.cursorEvents === undefined &&
835
+ (cursorGithubTargets.length > 0 || cursorOriginTargets.length > 0),
836
+ };
837
+ const cursorEventRelay = startCursorEventRelay({
838
+ ...cursorEventsCommon,
839
+ mounts: v1Mounts,
840
+ collectGitHubTargets: () => collectGitHubTargetsFrom(v1Runtimes),
841
+ collectOriginTargets: () => collectOriginTargetsFrom(v1Runtimes),
842
+ lane: "engine",
843
+ skippedV2: v2Mounts.length > 0,
844
+ });
845
+ const controlPlaneScmRelay = startCursorEventRelay({
846
+ ...cursorEventsCommon,
847
+ mounts: v2Mounts,
848
+ collectGitHubTargets: () => collectGitHubTargetsFrom(v2Runtimes),
849
+ collectOriginTargets: () => collectOriginTargetsFrom(v2Runtimes),
850
+ ...(routeContinuation === undefined ? {} : { routeContinuation }),
851
+ lane: "control-plane",
852
+ start: false,
853
+ stateDirName: join("control-plane", "cursor-events"),
854
+ });
855
+ const localCp = firstLocalControlPlane(runtimes);
856
+ if (controlPlaneScmRelay !== undefined) {
857
+ if (localCp !== undefined) {
858
+ localCp.attachScmEvents(controlPlaneScmRelay);
825
859
  }
826
- else if (hostedControlPlaneOwnsIngest && effectiveCursorEvents !== undefined) {
827
- // No credential was required above, so no relay object was built; the
828
- // outcome is the same skip.
860
+ else {
829
861
  logger("[bdk] cursor-events: skipping v2 scm-events poll (--no-control-plane); hosted CP owns ingest");
830
862
  }
831
- // Cursor deployment-events relay: automatic when a mounted agent authored
832
- // `deploymentsChannel({ ... })`.
833
- const cursorDeploymentRelay = options.evals === true
834
- ? undefined
835
- : startCursorDeploymentRelay({
836
- options,
837
- runtimes,
838
- accountKey,
839
- logger,
840
- });
841
- // Trust --public-url's host when a reverse proxy rewrites Host.
842
- const browserOriginGuard = browserOriginGuardOptionsForPublicUrl(options.publicUrl);
843
- const server = createServer((req, res) => {
844
- void instrumentHttp(otelRuntime, req, res, () => handleRequest(router, req, res, logger, browserOriginGuard));
863
+ }
864
+ else if (hostedControlPlaneOwnsIngest && effectiveCursorEvents !== undefined) {
865
+ // No credential was required above, so no relay object was built; the
866
+ // outcome is the same skip.
867
+ logger("[bdk] cursor-events: skipping v2 scm-events poll (--no-control-plane); hosted CP owns ingest");
868
+ }
869
+ // Cursor deployment-events relay: automatic when a mounted agent authored
870
+ // `deploymentsChannel({ ... })`.
871
+ const cursorDeploymentRelay = options.evals === true
872
+ ? undefined
873
+ : startCursorDeploymentRelay({
874
+ options,
875
+ runtimes,
876
+ accountKey,
877
+ logger,
845
878
  });
846
- const host = (_3 = options.host) !== null && _3 !== void 0 ? _3 : "127.0.0.1";
847
- const portWasExplicit = options.port !== undefined;
848
- const requestedPort = (_4 = options.port) !== null && _4 !== void 0 ? _4 : DEFAULT_SERVE_PORT;
849
- let boundPort;
850
- try {
851
- boundPort = yield listenHttpServer({
852
- server,
853
- host,
854
- port: requestedPort,
855
- portWasExplicit,
856
- logger,
857
- });
879
+ // Trust --public-url's host when a reverse proxy rewrites Host.
880
+ const browserOriginGuard = browserOriginGuardOptionsForPublicUrl(options.publicUrl);
881
+ const server = createServer((req, res) => {
882
+ void instrumentHttp(otelRuntime, req, res, () => handleRequest(router, req, res, logger, browserOriginGuard));
883
+ });
884
+ const host = options.host ?? "127.0.0.1";
885
+ const portWasExplicit = options.port !== undefined;
886
+ const requestedPort = options.port ?? DEFAULT_SERVE_PORT;
887
+ let boundPort;
888
+ try {
889
+ boundPort = await listenHttpServer({
890
+ server,
891
+ host,
892
+ port: requestedPort,
893
+ portWasExplicit,
894
+ logger,
895
+ });
896
+ }
897
+ catch (error) {
898
+ await cursorDeploymentRelay?.stop();
899
+ await cursorEventRelay?.stop();
900
+ await controlPlaneScmRelay?.stop();
901
+ cursorGithubCredentials?.stop();
902
+ await shutdownOtelRuntime(otelRuntime);
903
+ throw error;
904
+ }
905
+ const address = server.address();
906
+ const displayHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
907
+ const url = `http://${displayHost}:${boundPort}`;
908
+ const oauthOrigin = (options.publicUrl ?? url).replace(/\/$/, "");
909
+ // Resolve peer + Cursor account MCP connections now that the listen port is
910
+ // known (see resolved-connections.ts for the URL/runtime rules).
911
+ for (const runtime of runtimes) {
912
+ const peerRefs = peerRefsBySlug.get(runtime.slug);
913
+ const accountRefs = accountRefsBySlug.get(runtime.slug);
914
+ const resolved = resolveMountConnections({
915
+ slug: runtime.slug,
916
+ project: runtime.project,
917
+ serverUrl: url,
918
+ ...(peerRefs === undefined ? {} : { peerRefs }),
919
+ ...(accountRefs !== undefined && accountBridge !== undefined
920
+ ? { accountRefs, accountBridge }
921
+ : {}),
922
+ ...(options.publicUrl === undefined ? {} : { publicUrl: options.publicUrl }),
923
+ ...(options.authToken === undefined ? {} : { authToken: options.authToken }),
924
+ cloudToolsBridge: options.cloudToolsUrl !== undefined,
925
+ logger,
926
+ });
927
+ if (resolved.length > 0) {
928
+ runtime.engine.setResolvedConnections(resolved);
858
929
  }
859
- catch (error) {
860
- yield cursorDeploymentRelay === null || cursorDeploymentRelay === void 0 ? void 0 : cursorDeploymentRelay.stop();
861
- yield cursorEventRelay === null || cursorEventRelay === void 0 ? void 0 : cursorEventRelay.stop();
862
- yield controlPlaneScmRelay === null || controlPlaneScmRelay === void 0 ? void 0 : controlPlaneScmRelay.stop();
863
- cursorGithubCredentials === null || cursorGithubCredentials === void 0 ? void 0 : cursorGithubCredentials.stop();
864
- yield shutdownOtelRuntime(otelRuntime);
865
- throw error;
930
+ const oauthBase = runtime.slug === "" ? "" : `/${runtime.slug}`;
931
+ runtime.engine.setMcpOauthCallbackUrl(mcpOauthServeCallbackUrl(oauthOrigin, oauthBase));
932
+ if (accountBridge !== undefined && accountRefs !== undefined) {
933
+ const bridge = accountBridge;
934
+ runtime.engine.setCursorAccountAuthProbe(async (connection) => {
935
+ const ref = accountRefs.find(entry => entry.name === connection);
936
+ if (ref === undefined) {
937
+ return undefined;
938
+ }
939
+ return await bridge.probeAuthUrl(ref);
940
+ });
866
941
  }
867
- const address = server.address();
868
- const displayHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
869
- const url = `http://${displayHost}:${boundPort}`;
870
- const oauthOrigin = ((_5 = options.publicUrl) !== null && _5 !== void 0 ? _5 : url).replace(/\/$/, "");
871
- // Resolve peer + Cursor account MCP connections now that the listen port is
872
- // known (see resolved-connections.ts for the URL/runtime rules).
873
- for (const runtime of runtimes) {
874
- const peerRefs = peerRefsBySlug.get(runtime.slug);
875
- const accountRefs = accountRefsBySlug.get(runtime.slug);
876
- const resolved = resolveMountConnections(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ slug: runtime.slug, project: runtime.project, serverUrl: url }, (peerRefs === undefined ? {} : { peerRefs })), (accountRefs !== undefined && accountBridge !== undefined
877
- ? { accountRefs, accountBridge }
878
- : {})), (options.publicUrl === undefined ? {} : { publicUrl: options.publicUrl })), (options.authToken === undefined ? {} : { authToken: options.authToken })), { cloudToolsBridge: options.cloudToolsUrl !== undefined, logger }));
879
- if (resolved.length > 0) {
880
- runtime.engine.setResolvedConnections(resolved);
881
- }
882
- const oauthBase = runtime.slug === "" ? "" : `/${runtime.slug}`;
883
- runtime.engine.setMcpOauthCallbackUrl(mcpOauthServeCallbackUrl(oauthOrigin, oauthBase));
884
- if (accountBridge !== undefined && accountRefs !== undefined) {
885
- const bridge = accountBridge;
886
- runtime.engine.setCursorAccountAuthProbe((connection) => __awaiter(this, void 0, void 0, function* () {
887
- const ref = accountRefs.find(entry => entry.name === connection);
888
- if (ref === undefined) {
889
- return undefined;
890
- }
891
- return yield bridge.probeAuthUrl(ref);
892
- }));
893
- }
894
- const hasServerTools = runtime.project.agent.tools.some(tool => tool.execution === "server");
895
- // Host-bridged connections ride the same endpoint as server tools, so
896
- // the cloud tools connection is set whenever either needs it.
897
- const bridgeableNames = runtime.engine.cloudBridgeableConnectionNames();
898
- const cloudCapable = runtime.project.agent.runtime === "cloud" || runtime.project.agent.cloud !== undefined;
899
- if ((hasServerTools || bridgeableNames.length > 0) && cloudCapable) {
900
- const basePath = runtime.slug === "" ? "" : `/${runtime.slug}`;
901
- const publicToolsUrl = (_6 = options.cloudToolsUrl) !== null && _6 !== void 0 ? _6 : (options.publicUrl === undefined
942
+ const hasServerTools = runtime.project.agent.tools.some(tool => tool.execution === "server");
943
+ // Host-bridged connections ride the same endpoint as server tools, so
944
+ // the cloud tools connection is set whenever either needs it.
945
+ const bridgeableNames = runtime.engine.cloudBridgeableConnectionNames();
946
+ const cloudCapable = runtime.project.agent.runtime === "cloud" || runtime.project.agent.cloud !== undefined;
947
+ if ((hasServerTools || bridgeableNames.length > 0) && cloudCapable) {
948
+ const basePath = runtime.slug === "" ? "" : `/${runtime.slug}`;
949
+ const publicToolsUrl = options.cloudToolsUrl ??
950
+ (options.publicUrl === undefined
902
951
  ? undefined
903
952
  : `${options.publicUrl.replace(/\/$/, "")}${basePath}${TOOL_MCP_ENDPOINT_PATH}`);
904
- if (publicToolsUrl === undefined) {
905
- if (hasServerTools) {
906
- logger(`[bdk] warning: agent "${runtime.project.name}" has server tools but no --public-url or --cloud-tools-url; cloud turns omit those tools.`);
907
- }
953
+ if (publicToolsUrl === undefined) {
954
+ if (hasServerTools) {
955
+ logger(`[bdk] warning: agent "${runtime.project.name}" has server tools but no --public-url or --cloud-tools-url; cloud turns omit those tools.`);
908
956
  }
909
- else {
910
- const resolveCloudToolsHeaders = options.cloudToolsUrl === undefined
957
+ }
958
+ else {
959
+ const resolveCloudToolsHeaders = options.cloudToolsUrl === undefined
960
+ ? undefined
961
+ : () => {
962
+ const apiKey = liveCursorApiKey();
963
+ return apiKey === undefined ? undefined : { authorization: `Bearer ${apiKey}` };
964
+ };
965
+ const headers = options.cloudToolsUrl !== undefined
966
+ ? resolveCloudToolsHeaders?.()
967
+ : options.authToken === undefined
911
968
  ? undefined
912
- : () => {
913
- const apiKey = liveCursorApiKey();
914
- return apiKey === undefined ? undefined : { authorization: `Bearer ${apiKey}` };
915
- };
916
- const headers = options.cloudToolsUrl !== undefined
917
- ? resolveCloudToolsHeaders === null || resolveCloudToolsHeaders === void 0 ? void 0 : resolveCloudToolsHeaders()
918
- : options.authToken === undefined
919
- ? undefined
920
- : { authorization: `Bearer ${options.authToken}` };
921
- if (options.cloudToolsUrl !== undefined && headers === undefined) {
922
- if (options.allowAnonymous !== true) {
923
- throw new Error(`Agent "${runtime.project.name}" needs a Cursor API key to authenticate --cloud-tools-url. ${SIGN_IN_HINT}`);
924
- }
925
- logger(`[bdk] --cloud-tools-url: listening unsigned; Bearer resolves after task-time credential binding`);
969
+ : { authorization: `Bearer ${options.authToken}` };
970
+ if (options.cloudToolsUrl !== undefined && headers === undefined) {
971
+ if (options.allowAnonymous !== true) {
972
+ throw new Error(`Agent "${runtime.project.name}" needs a Cursor API key to authenticate --cloud-tools-url. ${SIGN_IN_HINT}`);
926
973
  }
927
- runtime.engine.setCloudServerToolsConnection(Object.assign({ type: "http", url: publicToolsUrl }, (headers === undefined ? {} : { headers })), resolveCloudToolsHeaders);
974
+ logger(`[bdk] --cloud-tools-url: listening unsigned; Bearer resolves after task-time credential binding`);
928
975
  }
976
+ runtime.engine.setCloudServerToolsConnection({
977
+ type: "http",
978
+ url: publicToolsUrl,
979
+ ...(headers === undefined ? {} : { headers }),
980
+ }, resolveCloudToolsHeaders);
929
981
  }
930
982
  }
931
- const agents = runtimes.map(({ slug, project }) => ({
932
- slug,
933
- project,
934
- url: slug === "" ? url : `${url}/${slug}`,
935
- }));
936
- for (const runtime of runtimes) {
937
- runtime.evalRuns.loopbackUrl = runtime.slug === "" ? url : `${url}/${runtime.slug}`;
938
- }
939
- const runtimeBySlug = new Map(runtimes.map(r => [r.slug, r]));
940
- // --dev: spawn Vite HMR. Single-agent infers the slug base; multi-agent
941
- // serves `/<slug>/playground` on the HMR origin (optional AGENT_SERVE_BASE
942
- // pins one slug at the HMR root instead).
943
- let playgroundDev;
944
- if (playground && dev) {
945
- const pinnedBase = mounts.length === 1 ? playgroundDevBasePath(mounts) : playgroundDevBaseFromEnv();
946
- const multiAgent = mounts.length > 1 && pinnedBase === undefined;
947
- playgroundDev = startPlaygroundDevServer({
948
- targetUrl: url,
949
- basePath: pinnedBase,
950
- multiAgent,
951
- logger,
952
- });
953
- }
954
- const handle = {
955
- url,
956
- port: address.port,
957
- project: (_f = runtimes[0]) === null || _f === void 0 ? void 0 : _f.project,
958
- agents,
959
- dispatchSchedule: (name, slug) => {
960
- var _a;
961
- var _b;
962
- if (slug === void 0) { slug = (_b = (_a = runtimes[0]) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : ""; }
963
- const runtime = runtimeBySlug.get(slug);
964
- if (runtime === undefined) {
965
- throw new Error(`Unknown agent slug "${slug}"`);
966
- }
967
- return runtime.scheduleRunner.dispatch(name);
968
- },
969
- createReminder: (input, slug) => {
970
- var _a;
971
- var _b;
972
- if (slug === void 0) { slug = (_b = (_a = runtimes[0]) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : ""; }
973
- const runtime = runtimeBySlug.get(slug);
974
- if (runtime === undefined) {
975
- throw new Error(`Unknown agent slug "${slug}"`);
976
- }
977
- return runtime.reminderRunner.create(input);
978
- },
979
- listReminders: (filter, slug) => {
980
- var _a;
981
- var _b;
982
- if (slug === void 0) { slug = (_b = (_a = runtimes[0]) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : ""; }
983
- const runtime = runtimeBySlug.get(slug);
984
- if (runtime === undefined) {
985
- throw new Error(`Unknown agent slug "${slug}"`);
986
- }
987
- return runtime.reminderRunner.list(filter);
988
- },
989
- cancelReminder: (id, options) => {
990
- var _a;
991
- var _b, _c;
992
- const slug = (_c = (_b = options === null || options === void 0 ? void 0 : options.slug) !== null && _b !== void 0 ? _b : (_a = runtimes[0]) === null || _a === void 0 ? void 0 : _a.slug) !== null && _c !== void 0 ? _c : "";
993
- const runtime = runtimeBySlug.get(slug);
994
- if (runtime === undefined) {
995
- throw new Error(`Unknown agent slug "${slug}"`);
996
- }
997
- return runtime.reminderRunner.cancel(id, options === null || options === void 0 ? void 0 : options.reason);
998
- },
999
- dispatchReminder: (id, slug) => {
1000
- var _a;
1001
- var _b;
1002
- if (slug === void 0) { slug = (_b = (_a = runtimes[0]) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : ""; }
1003
- const runtime = runtimeBySlug.get(slug);
1004
- if (runtime === undefined) {
1005
- throw new Error(`Unknown agent slug "${slug}"`);
1006
- }
1007
- return runtime.reminderRunner.dispatch(id);
1008
- },
1009
- callTool: (toolName, input, options) => {
1010
- var _a;
1011
- var _b;
1012
- const _c = options !== null && options !== void 0 ? options : {}, { slug } = _c, callOptions = __rest(_c, ["slug"]);
1013
- const runtime = runtimeBySlug.get((_b = slug !== null && slug !== void 0 ? slug : (_a = runtimes[0]) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : "");
1014
- if (runtime === undefined) {
1015
- throw new Error(`Unknown agent slug "${slug}"`);
1016
- }
1017
- return runtime.engine.callTool(toolName, input, callOptions);
1018
- },
1019
- close: () => __awaiter(this, void 0, void 0, function* () {
1020
- var _a;
1021
- var _b;
1022
- if (sessionRunLog !== undefined) {
1023
- yield flushHostedExecutionProcessDeath({
1024
- flushProcessDeath: reason => sessionRunLog.flushProcessDeath(reason),
1025
- flushStartLog,
1026
- startLogId: lastStartLogId,
1027
- reason: "process_exit",
1028
- });
1029
- unregisterSessionRunFatalFlush();
1030
- }
1031
- playgroundDev === null || playgroundDev === void 0 ? void 0 : playgroundDev.stop();
1032
- yield cursorDeploymentRelay === null || cursorDeploymentRelay === void 0 ? void 0 : cursorDeploymentRelay.stop();
1033
- yield cursorEventRelay === null || cursorEventRelay === void 0 ? void 0 : cursorEventRelay.stop();
1034
- yield controlPlaneScmRelay === null || controlPlaneScmRelay === void 0 ? void 0 : controlPlaneScmRelay.stop();
1035
- for (const runtime of runtimes) {
1036
- (_a = runtime.controlPlane) === null || _a === void 0 ? void 0 : _a.stop();
1037
- runtime.scheduleRunner.stop();
1038
- runtime.reminderRunner.stop();
1039
- // Before the engines close their storage coordinators, so the
1040
- // interrupted-batch write can still reach the sink.
1041
- runtime.evalRuns.close();
1042
- }
1043
- for (const stop of channelStopHooks) {
1044
- try {
1045
- yield stop();
1046
- }
1047
- catch (error) {
1048
- logger(`[bdk] channel onStop failed: ${error instanceof Error ? ((_b = error.stack) !== null && _b !== void 0 ? _b : error.message) : String(error)}`);
1049
- }
1050
- }
1051
- server.close();
1052
- server.closeAllConnections();
983
+ }
984
+ const agents = runtimes.map(({ slug, project }) => ({
985
+ slug,
986
+ project,
987
+ url: slug === "" ? url : `${url}/${slug}`,
988
+ }));
989
+ for (const runtime of runtimes) {
990
+ runtime.evalRuns.loopbackUrl = runtime.slug === "" ? url : `${url}/${runtime.slug}`;
991
+ }
992
+ const runtimeBySlug = new Map(runtimes.map(r => [r.slug, r]));
993
+ // --dev: spawn Vite HMR. Single-agent infers the slug base; multi-agent
994
+ // serves `/<slug>/playground` on the HMR origin (optional AGENT_SERVE_BASE
995
+ // pins one slug at the HMR root instead).
996
+ let playgroundDev;
997
+ if (playground && dev) {
998
+ const pinnedBase = mounts.length === 1 ? playgroundDevBasePath(mounts) : playgroundDevBaseFromEnv();
999
+ const multiAgent = mounts.length > 1 && pinnedBase === undefined;
1000
+ playgroundDev = startPlaygroundDevServer({
1001
+ targetUrl: url,
1002
+ basePath: pinnedBase,
1003
+ multiAgent,
1004
+ logger,
1005
+ });
1006
+ }
1007
+ const handle = {
1008
+ url,
1009
+ port: address.port,
1010
+ project: runtimes[0]?.project,
1011
+ agents,
1012
+ dispatchSchedule: (name, slug = runtimes[0]?.slug ?? "") => {
1013
+ const runtime = runtimeBySlug.get(slug);
1014
+ if (runtime === undefined) {
1015
+ throw new Error(`Unknown agent slug "${slug}"`);
1016
+ }
1017
+ return runtime.scheduleRunner.dispatch(name);
1018
+ },
1019
+ createReminder: (input, slug = runtimes[0]?.slug ?? "") => {
1020
+ const runtime = runtimeBySlug.get(slug);
1021
+ if (runtime === undefined) {
1022
+ throw new Error(`Unknown agent slug "${slug}"`);
1023
+ }
1024
+ return runtime.reminderRunner.create(input);
1025
+ },
1026
+ listReminders: (filter, slug = runtimes[0]?.slug ?? "") => {
1027
+ const runtime = runtimeBySlug.get(slug);
1028
+ if (runtime === undefined) {
1029
+ throw new Error(`Unknown agent slug "${slug}"`);
1030
+ }
1031
+ return runtime.reminderRunner.list(filter);
1032
+ },
1033
+ cancelReminder: (id, options) => {
1034
+ const slug = options?.slug ?? runtimes[0]?.slug ?? "";
1035
+ const runtime = runtimeBySlug.get(slug);
1036
+ if (runtime === undefined) {
1037
+ throw new Error(`Unknown agent slug "${slug}"`);
1038
+ }
1039
+ return runtime.reminderRunner.cancel(id, options?.reason);
1040
+ },
1041
+ dispatchReminder: (id, slug = runtimes[0]?.slug ?? "") => {
1042
+ const runtime = runtimeBySlug.get(slug);
1043
+ if (runtime === undefined) {
1044
+ throw new Error(`Unknown agent slug "${slug}"`);
1045
+ }
1046
+ return runtime.reminderRunner.dispatch(id);
1047
+ },
1048
+ callTool: (toolName, input, options) => {
1049
+ const { slug, ...callOptions } = options ?? {};
1050
+ const runtime = runtimeBySlug.get(slug ?? runtimes[0]?.slug ?? "");
1051
+ if (runtime === undefined) {
1052
+ throw new Error(`Unknown agent slug "${slug}"`);
1053
+ }
1054
+ return runtime.engine.callTool(toolName, input, callOptions);
1055
+ },
1056
+ close: async () => {
1057
+ if (sessionRunLog !== undefined) {
1058
+ await flushHostedExecutionProcessDeath({
1059
+ flushProcessDeath: reason => sessionRunLog.flushProcessDeath(reason),
1060
+ flushStartLog,
1061
+ startLogId: lastStartLogId,
1062
+ reason: "process_exit",
1063
+ });
1064
+ unregisterSessionRunFatalFlush();
1065
+ }
1066
+ playgroundDev?.stop();
1067
+ await cursorDeploymentRelay?.stop();
1068
+ await cursorEventRelay?.stop();
1069
+ await controlPlaneScmRelay?.stop();
1070
+ for (const runtime of runtimes) {
1071
+ runtime.controlPlane?.stop();
1072
+ runtime.scheduleRunner.stop();
1073
+ runtime.reminderRunner.stop();
1074
+ // Before the engines close their storage coordinators, so the
1075
+ // interrupted-batch write can still reach the sink.
1076
+ runtime.evalRuns.close();
1077
+ }
1078
+ for (const stop of channelStopHooks) {
1053
1079
  try {
1054
- yield Promise.all(runtimes.map(runtime => runtime.engine.close()));
1080
+ await stop();
1055
1081
  }
1056
- finally {
1057
- cursorGithubCredentials === null || cursorGithubCredentials === void 0 ? void 0 : cursorGithubCredentials.stop();
1058
- yield shutdownOtelRuntime(otelRuntime);
1082
+ catch (error) {
1083
+ logger(`[bdk] channel onStop failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
1059
1084
  }
1060
- }),
1061
- };
1062
- if ((playgroundDev === null || playgroundDev === void 0 ? void 0 : playgroundDev.url) !== undefined) {
1063
- handle.playgroundDevUrl = playgroundDev.url;
1064
- }
1065
- if (docsSite && docsSiteExists()) {
1066
- handle.docsUrl = `${handle.url}/docs`;
1067
- }
1068
- return handle;
1069
- });
1085
+ }
1086
+ server.close();
1087
+ server.closeAllConnections();
1088
+ try {
1089
+ await Promise.all(runtimes.map(runtime => runtime.engine.close()));
1090
+ }
1091
+ finally {
1092
+ cursorGithubCredentials?.stop();
1093
+ await shutdownOtelRuntime(otelRuntime);
1094
+ }
1095
+ },
1096
+ };
1097
+ if (playgroundDev?.url !== undefined) {
1098
+ handle.playgroundDevUrl = playgroundDev.url;
1099
+ }
1100
+ if (docsSite && docsSiteExists()) {
1101
+ handle.docsUrl = `${handle.url}/docs`;
1102
+ }
1103
+ return handle;
1070
1104
  }
1071
1105
  function mountAgentRoutes(router, runtime, args) {
1072
- var _a, _b, _c;
1073
1106
  const { slug, project, engine, scheduleRunner, reminderRunner, reminderControlPlane } = runtime;
1074
1107
  const { dev, playground, noControlPlane, multi, logger, logRing, sessionRunLog, flushStartLog } = args;
1075
1108
  // "" (single) -> "/v1/..."; "my-agent" (multi) -> "/my-agent/v1/...".
@@ -1084,10 +1117,9 @@ function mountAgentRoutes(router, runtime, args) {
1084
1117
  pattern: `${base}${cursorAccountMcpPath(":connection")}`,
1085
1118
  auth: [bridge.authPolicy()],
1086
1119
  handler: (request, ctx) => {
1087
- var _a, _b;
1088
- const ref = refByName.get((_a = ctx.params.connection) !== null && _a !== void 0 ? _a : "");
1120
+ const ref = refByName.get(ctx.params.connection ?? "");
1089
1121
  if (ref === undefined) {
1090
- return errorResponse(404, "not_found", `No Cursor account MCP connection named "${(_b = ctx.params.connection) !== null && _b !== void 0 ? _b : ""}" on this agent.`);
1122
+ return errorResponse(404, "not_found", `No Cursor account MCP connection named "${ctx.params.connection ?? ""}" on this agent.`);
1091
1123
  }
1092
1124
  return bridge.handle(request, ref, appendSlackQuietHint);
1093
1125
  },
@@ -1098,7 +1130,7 @@ function mountAgentRoutes(router, runtime, args) {
1098
1130
  : args.allowAnonymous === true
1099
1131
  ? [allowAll()]
1100
1132
  : [localDevStrict()];
1101
- const httpAuth = (_a = project.httpChannel.auth) !== null && _a !== void 0 ? _a : defaultAuth;
1133
+ const httpAuth = project.httpChannel.auth ?? defaultAuth;
1102
1134
  // Temporal posts this marker on a direct pod port-token fetch. The alias
1103
1135
  // proxy strips it, so webhook/playground tokens cannot present it.
1104
1136
  const platformTimerFireAuth = request => {
@@ -1120,24 +1152,28 @@ function mountAgentRoutes(router, runtime, args) {
1120
1152
  // Local dev, self-hosted serve, and hosted v1 keep the engine mounts.
1121
1153
  const hostedV2Guest = noControlPlane === true && isV2Project(project);
1122
1154
  if (hostedV2Guest) {
1123
- registerHostedDeliveryRoute(Object.assign(Object.assign(Object.assign(Object.assign({ router,
1124
- base,
1155
+ registerHostedDeliveryRoute({
1156
+ router,
1157
+ base,
1125
1158
  // The built-in http channel is not in `project.channels`; the control
1126
1159
  // plane's session start (`agentsdk.session`) is delivered to it.
1127
- channels: [...project.channels, { id: HTTP_CHANNEL_ID, definition: project.httpChannel }], buildHandlerArgs: (channelId, hostedSessionId) => buildChannelHandlerArgs({
1160
+ channels: [...project.channels, { id: HTTP_CHANNEL_ID, definition: project.httpChannel }],
1161
+ buildHandlerArgs: (channelId, hostedSessionId) => buildChannelHandlerArgs({
1128
1162
  runtime,
1129
1163
  channelId,
1130
1164
  hostedSessionId,
1131
- }), fireReminder: (reminderId, fireCount) => reminderRunner.dispatch(reminderId, { expectedFireCount: fireCount }), executeReminderDescriptor: (descriptor) => __awaiter(this, void 0, void 0, function* () {
1165
+ }),
1166
+ fireReminder: (reminderId, fireCount) => reminderRunner.dispatch(reminderId, { expectedFireCount: fireCount }),
1167
+ executeReminderDescriptor: async (descriptor) => {
1132
1168
  if (reminderControlPlane === undefined) {
1133
1169
  throw new Error("hosted reminder CP client is not configured");
1134
1170
  }
1135
1171
  const fireDescriptor = descriptor;
1136
- const outcome = yield reminderRunner.executeFire(fireDescriptor);
1172
+ const outcome = await reminderRunner.executeFire(fireDescriptor);
1137
1173
  // applyReminderOutcome is idempotent and internally retries transient
1138
1174
  // CP failures. Handler execution is at-least-once across Temporal
1139
1175
  // re-admission if apply ultimately fails.
1140
- const apply = yield reminderControlPlane.applyReminderOutcome(claimFromDescriptor(fireDescriptor), outcome);
1176
+ const apply = await reminderControlPlane.applyReminderOutcome(claimFromDescriptor(fireDescriptor), outcome);
1141
1177
  // Cancel/rekey winning the race is a successful no-op from the guest's
1142
1178
  // perspective (fired work may have run; lifecycle authority stayed CP).
1143
1179
  if (!apply.applied && apply.reason === "missing") {
@@ -1151,14 +1187,22 @@ function mountAgentRoutes(router, runtime, args) {
1151
1187
  reminderId: descriptor.id,
1152
1188
  outcome: "fired",
1153
1189
  };
1154
- }), drainSessionDurability: sessionId => engine.drainSessionDurability(sessionId), flushOtel: args.flushOtel }, (args.diagStateRoot === undefined ? {} : { stateRoot: args.diagStateRoot })), (sessionRunLog === undefined
1155
- ? {}
1156
- : {
1157
- persistSessionRun: (document) => __awaiter(this, void 0, void 0, function* () {
1158
- yield sessionRunLog.persist(document);
1190
+ },
1191
+ drainSessionDurability: sessionId => engine.drainSessionDurability(sessionId),
1192
+ flushOtel: args.flushOtel,
1193
+ ...(args.diagStateRoot === undefined ? {} : { stateRoot: args.diagStateRoot }),
1194
+ ...(sessionRunLog === undefined
1195
+ ? {}
1196
+ : {
1197
+ persistSessionRun: async (document) => {
1198
+ await sessionRunLog.persist(document);
1199
+ },
1200
+ flushStartLog,
1159
1201
  }),
1160
- flushStartLog,
1161
- })), { snapshotLogs: () => logRing.since() }), (args.evictSdkSession === undefined ? {} : { evictSdkSession: args.evictSdkSession })));
1202
+ snapshotLogs: () => logRing.since(),
1203
+ ...(args.evictSdkSession === undefined ? {} : { evictSdkSession: args.evictSdkSession }),
1204
+ startSend: hostedSendStart({ engine, projectRoot: project.rootDir, logger }),
1205
+ });
1162
1206
  }
1163
1207
  // Playground lists/opens Slack (and other channel) sessions across
1164
1208
  // principals when `--dev` (loopback) or `--allow-anonymous` (trusted
@@ -1184,7 +1228,12 @@ function mountAgentRoutes(router, runtime, args) {
1184
1228
  // Temporal consumes this response before promoting a newly deployed pod.
1185
1229
  // Include the framework build there so deploy observability gets the
1186
1230
  // version from the process that will serve turns, with no second request.
1187
- handler: () => jsonResponse(Object.assign({ ok: true, name: project.name, version: packageVersion() }, memoryHealthFields([engine]))),
1231
+ handler: () => jsonResponse({
1232
+ ok: true,
1233
+ name: project.name,
1234
+ version: packageVersion(),
1235
+ ...memoryHealthFields([engine]),
1236
+ }),
1188
1237
  });
1189
1238
  // TAS polls this after `/v1/health` and before the hosted POST. Auth none
1190
1239
  // mirrors health: the engine is reachable only through the anyrun port
@@ -1201,11 +1250,16 @@ function mountAgentRoutes(router, runtime, args) {
1201
1250
  method: "GET",
1202
1251
  pattern: `${base}/v1/meta`,
1203
1252
  auth: "none",
1204
- handler: () => jsonResponse(Object.assign({ name: project.name, dev, basePath: base,
1253
+ handler: () => jsonResponse({
1254
+ name: project.name,
1255
+ dev,
1256
+ basePath: base,
1205
1257
  // Framework version, for SPA/engine skew observability now that the
1206
1258
  // hosted playground shell is served centrally (backend deploys)
1207
1259
  // while engines stay on their install-time version.
1208
- version: packageVersion() }, (multi ? { indexPath: "/" } : {}))),
1260
+ version: packageVersion(),
1261
+ ...(multi ? { indexPath: "/" } : {}),
1262
+ }),
1209
1263
  });
1210
1264
  router.add({
1211
1265
  method: "GET",
@@ -1226,7 +1280,18 @@ function mountAgentRoutes(router, runtime, args) {
1226
1280
  method: "GET",
1227
1281
  pattern: `${base}/v1/manifest`,
1228
1282
  auth: "none",
1229
- handler: () => jsonResponse(buildAgentDeployManifest(project)),
1283
+ handler: async () => {
1284
+ const manifest = buildAgentDeployManifest(project);
1285
+ // A v2 release runs eval cases as its own sessions, so the control
1286
+ // plane lists them from the manifest it freezes.
1287
+ if (isV2Project(project)) {
1288
+ manifest.info.evals = await hostedEvalCatalog(project.rootDir).catch(error => {
1289
+ logger(`[bdk] eval discovery failed; release lists no evals: ${describeError(error)}`);
1290
+ return undefined;
1291
+ });
1292
+ }
1293
+ return jsonResponse(manifest);
1294
+ },
1230
1295
  });
1231
1296
  }
1232
1297
  // Playground Logs tab: recent ServeOptions.logger lines (channels, sessions,
@@ -1236,8 +1301,6 @@ function mountAgentRoutes(router, runtime, args) {
1236
1301
  pattern: `${base}/v1/logs`,
1237
1302
  auth: httpAuth,
1238
1303
  handler: request => {
1239
- var _a;
1240
- var _b;
1241
1304
  const url = new URL(request.url);
1242
1305
  const afterRaw = url.searchParams.get("after");
1243
1306
  const after = afterRaw === null || afterRaw === "" ? -1 : Number.parseInt(afterRaw, 10);
@@ -1245,7 +1308,7 @@ function mountAgentRoutes(router, runtime, args) {
1245
1308
  const entries = logRing.since(cursor);
1246
1309
  return jsonResponse({
1247
1310
  entries,
1248
- nextAfter: entries.length === 0 ? cursor : ((_b = (_a = entries[entries.length - 1]) === null || _a === void 0 ? void 0 : _a.index) !== null && _b !== void 0 ? _b : cursor),
1311
+ nextAfter: entries.length === 0 ? cursor : (entries[entries.length - 1]?.index ?? cursor),
1249
1312
  });
1250
1313
  },
1251
1314
  });
@@ -1256,7 +1319,7 @@ function mountAgentRoutes(router, runtime, args) {
1256
1319
  method: "GET",
1257
1320
  pattern: `${base}/v1/sessions`,
1258
1321
  auth: httpAuth,
1259
- handler: (request, ctx) => __awaiter(this, void 0, void 0, function* () {
1322
+ handler: async (request, ctx) => {
1260
1323
  // Same gate as requireSessionOwner / relaxSessionReadAuth: never with
1261
1324
  // bearer or custom channel auth (strict per-principal isolation).
1262
1325
  // `--allow-anonymous` alone is a shared-principal trust boundary (corp
@@ -1268,13 +1331,13 @@ function mountAgentRoutes(router, runtime, args) {
1268
1331
  // binding a default session do not need the cost of a full listing.
1269
1332
  const latest = new URL(request.url).searchParams.get("latest");
1270
1333
  const listed = latest === "1" || latest === "true"
1271
- ? yield engine.latestSessionWithSource(ctx.auth, { includeAll })
1272
- : yield engine.listSessionsWithSource(ctx.auth, { includeAll });
1334
+ ? await engine.latestSessionWithSource(ctx.auth, { includeAll })
1335
+ : await engine.listSessionsWithSource(ctx.auth, { includeAll });
1273
1336
  return jsonResponse({
1274
1337
  sessions: listed.sessions,
1275
1338
  source: listed.source,
1276
1339
  });
1277
- }),
1340
+ },
1278
1341
  });
1279
1342
  }
1280
1343
  // Durable artifacts (ctx.artifacts / tag_artifact), newest-updated first.
@@ -1285,8 +1348,7 @@ function mountAgentRoutes(router, runtime, args) {
1285
1348
  method: "GET",
1286
1349
  pattern: `${base}/v1/artifacts`,
1287
1350
  auth: httpAuth,
1288
- handler: (request, ctx) => __awaiter(this, void 0, void 0, function* () {
1289
- var _a, _b, _c;
1351
+ handler: async (request, ctx) => {
1290
1352
  const url = new URL(request.url);
1291
1353
  const limitRaw = url.searchParams.get("limit");
1292
1354
  let limit = ARTIFACTS_PAGE_DEFAULT_LIMIT;
@@ -1297,9 +1359,9 @@ function mountAgentRoutes(router, runtime, args) {
1297
1359
  }
1298
1360
  limit = Math.min(parsed, ARTIFACTS_PAGE_MAX_LIMIT);
1299
1361
  }
1300
- const kind = (_a = url.searchParams.get("kind")) !== null && _a !== void 0 ? _a : undefined;
1301
- const sessionId = (_b = url.searchParams.get("sessionId")) !== null && _b !== void 0 ? _b : undefined;
1302
- const pageToken = (_c = url.searchParams.get("pageToken")) !== null && _c !== void 0 ? _c : undefined;
1362
+ const kind = url.searchParams.get("kind") ?? undefined;
1363
+ const sessionId = url.searchParams.get("sessionId") ?? undefined;
1364
+ const pageToken = url.searchParams.get("pageToken") ?? undefined;
1303
1365
  // Same includeAll gate as /v1/sessions: never with bearer or custom
1304
1366
  // channel auth (strict per-principal isolation); otherwise session
1305
1367
  // ownership applies (see SessionEngine.pageArtifacts).
@@ -1308,7 +1370,7 @@ function mountAgentRoutes(router, runtime, args) {
1308
1370
  (typeof ctx.requestIp === "string" && isLoopbackAddress(ctx.requestIp)));
1309
1371
  let page;
1310
1372
  try {
1311
- page = yield engine.pageArtifacts(ctx.auth, {
1373
+ page = await engine.pageArtifacts(ctx.auth, {
1312
1374
  includeAll,
1313
1375
  filter: { kind, sessionId },
1314
1376
  limit,
@@ -1325,20 +1387,18 @@ function mountAgentRoutes(router, runtime, args) {
1325
1387
  artifacts: page.records,
1326
1388
  nextPageToken: page.nextCursor,
1327
1389
  });
1328
- }),
1390
+ },
1329
1391
  });
1330
1392
  // File/blob payload of one artifact (`tag({ contents })`).
1331
1393
  router.add({
1332
1394
  method: "GET",
1333
1395
  pattern: `${base}/v1/artifacts/:id/content`,
1334
1396
  auth: httpAuth,
1335
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1336
- var _a;
1337
- var _b, _c;
1397
+ handler: async (_request, ctx) => {
1338
1398
  const includeAll = relaxSessionReadAuth &&
1339
1399
  (relaxSessionReadAuthBeyondLoopback ||
1340
1400
  (typeof ctx.requestIp === "string" && isLoopbackAddress(ctx.requestIp)));
1341
- const found = yield engine.getArtifactContent(ctx.auth, (_b = ctx.params.id) !== null && _b !== void 0 ? _b : "", { includeAll });
1401
+ const found = await engine.getArtifactContent(ctx.auth, ctx.params.id ?? "", { includeAll });
1342
1402
  if (found === undefined) {
1343
1403
  return errorResponse(404, "not_found", "No such artifact, or it carries no content.");
1344
1404
  }
@@ -1348,12 +1408,12 @@ function mountAgentRoutes(router, runtime, args) {
1348
1408
  // this origin: force download, never render or sniff.
1349
1409
  return new Response(found.body, {
1350
1410
  headers: {
1351
- "content-type": (_c = (_a = found.record.content) === null || _a === void 0 ? void 0 : _a.contentType) !== null && _c !== void 0 ? _c : "application/octet-stream",
1411
+ "content-type": found.record.content?.contentType ?? "application/octet-stream",
1352
1412
  "content-disposition": "attachment",
1353
1413
  "x-content-type-options": "nosniff",
1354
1414
  },
1355
1415
  });
1356
- }),
1416
+ },
1357
1417
  });
1358
1418
  // The agent's MCP surface: peers and external MCP clients delegate to
1359
1419
  // this agent (ask / check / call_tool) over streamable HTTP. Stateless —
@@ -1383,13 +1443,12 @@ function mountAgentRoutes(router, runtime, args) {
1383
1443
  // answer. `session` / `continuationToken` query parameters bind the
1384
1444
  // listing to a session identity (advertised inventories can be
1385
1445
  // tenant-scoped and resolved per session).
1386
- const resolveCatalogBinding = (request, ctx) => __awaiter(this, void 0, void 0, function* () {
1387
- var _a, _b;
1446
+ const resolveCatalogBinding = async (request, ctx) => {
1388
1447
  const url = new URL(request.url);
1389
- const sessionId = (_a = url.searchParams.get("session")) !== null && _a !== void 0 ? _a : undefined;
1390
- const continuationToken = (_b = url.searchParams.get("continuationToken")) !== null && _b !== void 0 ? _b : undefined;
1448
+ const sessionId = url.searchParams.get("session") ?? undefined;
1449
+ const continuationToken = url.searchParams.get("continuationToken") ?? undefined;
1391
1450
  if (sessionId !== undefined) {
1392
- const record = yield engine.sessions.get(sessionId);
1451
+ const record = await engine.sessions.get(sessionId);
1393
1452
  if (record === undefined) {
1394
1453
  return {
1395
1454
  errorResponse: errorResponse(404, "session_not_found", `Unknown session ${sessionId}.`),
@@ -1405,18 +1464,21 @@ function mountAgentRoutes(router, runtime, args) {
1405
1464
  }
1406
1465
  }
1407
1466
  return { sessionId, continuationToken };
1408
- });
1467
+ };
1409
1468
  router.add({
1410
1469
  method: "GET",
1411
1470
  pattern: `${base}/v1/tools`,
1412
1471
  auth: httpAuth,
1413
- handler: (request, ctx) => __awaiter(this, void 0, void 0, function* () {
1414
- const binding = yield resolveCatalogBinding(request, ctx);
1472
+ handler: async (request, ctx) => {
1473
+ const binding = await resolveCatalogBinding(request, ctx);
1415
1474
  if ("errorResponse" in binding) {
1416
1475
  return binding.errorResponse;
1417
1476
  }
1418
1477
  try {
1419
- const catalog = yield engine.listCatalogTools(Object.assign({ auth: ctx.auth }, binding));
1478
+ const catalog = await engine.listCatalogTools({
1479
+ auth: ctx.auth,
1480
+ ...binding,
1481
+ });
1420
1482
  return jsonResponse({
1421
1483
  tools: catalog.tools.map(catalogListEntry),
1422
1484
  // JSON.stringify drops the key when there is nothing to report.
@@ -1429,21 +1491,23 @@ function mountAgentRoutes(router, runtime, args) {
1429
1491
  }
1430
1492
  throw error;
1431
1493
  }
1432
- }),
1494
+ },
1433
1495
  });
1434
1496
  router.add({
1435
1497
  method: "GET",
1436
1498
  pattern: `${base}/v1/tools/:toolName`,
1437
1499
  auth: httpAuth,
1438
- handler: (request, ctx) => __awaiter(this, void 0, void 0, function* () {
1439
- var _a;
1440
- const toolName = (_a = ctx.params.toolName) !== null && _a !== void 0 ? _a : "";
1441
- const binding = yield resolveCatalogBinding(request, ctx);
1500
+ handler: async (request, ctx) => {
1501
+ const toolName = ctx.params.toolName ?? "";
1502
+ const binding = await resolveCatalogBinding(request, ctx);
1442
1503
  if ("errorResponse" in binding) {
1443
1504
  return binding.errorResponse;
1444
1505
  }
1445
1506
  try {
1446
- const described = yield engine.describeCatalogTool(toolName, Object.assign({ auth: ctx.auth }, binding));
1507
+ const described = await engine.describeCatalogTool(toolName, {
1508
+ auth: ctx.auth,
1509
+ ...binding,
1510
+ });
1447
1511
  if (described.tool === undefined) {
1448
1512
  return jsonResponse({
1449
1513
  ok: false,
@@ -1460,7 +1524,7 @@ function mountAgentRoutes(router, runtime, args) {
1460
1524
  }
1461
1525
  throw error;
1462
1526
  }
1463
- }),
1527
+ },
1464
1528
  });
1465
1529
  // Deterministic tool invocation: run an authored server tool directly,
1466
1530
  // without a model turn deciding to call it.
@@ -1468,10 +1532,9 @@ function mountAgentRoutes(router, runtime, args) {
1468
1532
  method: "POST",
1469
1533
  pattern: `${base}/v1/tools/:toolName`,
1470
1534
  auth: httpAuth,
1471
- handler: (request, ctx) => __awaiter(this, void 0, void 0, function* () {
1472
- var _a, _b;
1473
- const toolName = (_a = ctx.params.toolName) !== null && _a !== void 0 ? _a : "";
1474
- const body = yield readJsonObject(request);
1535
+ handler: async (request, ctx) => {
1536
+ const toolName = ctx.params.toolName ?? "";
1537
+ const body = await readJsonObject(request);
1475
1538
  if (body === undefined) {
1476
1539
  return errorResponse(400, "invalid_request", 'Expected a JSON object body, e.g. {"input": {...}}.');
1477
1540
  }
@@ -1484,7 +1547,7 @@ function mountAgentRoutes(router, runtime, args) {
1484
1547
  const continuationToken = body.continuationToken;
1485
1548
  const sessionId = body.sessionId;
1486
1549
  if (sessionId !== undefined) {
1487
- const record = yield engine.sessions.get(sessionId);
1550
+ const record = await engine.sessions.get(sessionId);
1488
1551
  if (record === undefined) {
1489
1552
  return errorResponse(404, "session_not_found", `Unknown session ${sessionId}.`);
1490
1553
  }
@@ -1498,12 +1561,12 @@ function mountAgentRoutes(router, runtime, args) {
1498
1561
  }
1499
1562
  }
1500
1563
  try {
1501
- const outcome = yield engine.callTool(toolName, (_b = body.input) !== null && _b !== void 0 ? _b : {}, {
1564
+ const outcome = await engine.callTool(toolName, body.input ?? {}, {
1502
1565
  auth: ctx.auth,
1503
1566
  sessionId,
1504
1567
  continuationToken,
1505
1568
  });
1506
- return jsonResponse(Object.assign({ ok: !outcome.isError }, outcome));
1569
+ return jsonResponse({ ok: !outcome.isError, ...outcome });
1507
1570
  }
1508
1571
  catch (error) {
1509
1572
  if (error instanceof UnknownToolError) {
@@ -1528,7 +1591,7 @@ function mountAgentRoutes(router, runtime, args) {
1528
1591
  }
1529
1592
  throw error;
1530
1593
  }
1531
- }),
1594
+ },
1532
1595
  });
1533
1596
  // Deterministic skill reads: the body the harness would receive, plus
1534
1597
  // resolved sibling files. Read-only, so plain GETs with no session binding.
@@ -1536,21 +1599,18 @@ function mountAgentRoutes(router, runtime, args) {
1536
1599
  method: "GET",
1537
1600
  pattern: `${base}/v1/skills`,
1538
1601
  auth: httpAuth,
1539
- handler: () => __awaiter(this, void 0, void 0, function* () {
1540
- return jsonResponse({
1541
- skills: project.agent.skills.map(skillListEntry),
1542
- });
1602
+ handler: async () => jsonResponse({
1603
+ skills: project.agent.skills.map(skillListEntry),
1543
1604
  }),
1544
1605
  });
1545
1606
  router.add({
1546
1607
  method: "GET",
1547
1608
  pattern: `${base}/v1/skills/:skillName`,
1548
1609
  auth: httpAuth,
1549
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1550
- var _a;
1551
- const skillName = (_a = ctx.params.skillName) !== null && _a !== void 0 ? _a : "";
1610
+ handler: async (_request, ctx) => {
1611
+ const skillName = ctx.params.skillName ?? "";
1552
1612
  try {
1553
- return jsonResponse(yield readSkillDetail(project.agent.skills, skillName));
1613
+ return jsonResponse(await readSkillDetail(project.agent.skills, skillName));
1554
1614
  }
1555
1615
  catch (error) {
1556
1616
  if (error instanceof UnknownSkillError) {
@@ -1563,7 +1623,7 @@ function mountAgentRoutes(router, runtime, args) {
1563
1623
  }
1564
1624
  throw error;
1565
1625
  }
1566
- }),
1626
+ },
1567
1627
  });
1568
1628
  if (playground) {
1569
1629
  // Serve the built Vite SPA. `<base href>` is injected so the SPA's relative
@@ -1583,7 +1643,7 @@ function mountAgentRoutes(router, runtime, args) {
1583
1643
  method: "GET",
1584
1644
  pattern: `${base}/playground/assets/:file`,
1585
1645
  auth: "none",
1586
- handler: (_request, ctx) => { var _a; return renderPlaygroundAsset((_a = ctx.params.file) !== null && _a !== void 0 ? _a : ""); },
1646
+ handler: (_request, ctx) => renderPlaygroundAsset(ctx.params.file ?? ""),
1587
1647
  });
1588
1648
  }
1589
1649
  // The built-in HTTP session channel (`/v1/session*`, including the
@@ -1612,32 +1672,38 @@ function mountAgentRoutes(router, runtime, args) {
1612
1672
  method: "GET",
1613
1673
  pattern: `${base}/v1/dev/evals`,
1614
1674
  auth: httpAuth,
1615
- handler: () => __awaiter(this, void 0, void 0, function* () { return jsonResponse(yield runtime.evalRuns.list()); }),
1675
+ handler: async () => jsonResponse(await runtime.evalRuns.list()),
1616
1676
  });
1617
1677
  router.add({
1618
1678
  method: "GET",
1619
1679
  pattern: `${base}/v1/dev/evals/runs`,
1620
1680
  auth: httpAuth,
1621
- handler: () => __awaiter(this, void 0, void 0, function* () {
1622
- return jsonResponse(yield runtime.evalRuns.listRunsWithActive());
1623
- }),
1681
+ handler: async () => {
1682
+ return jsonResponse(await runtime.evalRuns.listRunsWithActive());
1683
+ },
1624
1684
  });
1625
1685
  router.add({
1626
1686
  method: "POST",
1627
1687
  pattern: `${base}/v1/dev/evals/runs`,
1628
1688
  auth: httpAuth,
1629
- handler: (request) => __awaiter(this, void 0, void 0, function* () {
1630
- const body = yield readJsonObject(request);
1631
- const filterIds = asStringArray(body === null || body === void 0 ? void 0 : body.filterIds);
1632
- const tags = asStringArray(body === null || body === void 0 ? void 0 : body.tags);
1633
- const timeoutMs = asPositiveInt(body === null || body === void 0 ? void 0 : body.timeoutMs);
1634
- const verbose = (body === null || body === void 0 ? void 0 : body.verbose) === true;
1689
+ handler: async (request) => {
1690
+ const body = await readJsonObject(request);
1691
+ const filterIds = asStringArray(body?.filterIds);
1692
+ const tags = asStringArray(body?.tags);
1693
+ const timeoutMs = asPositiveInt(body?.timeoutMs);
1694
+ const verbose = body?.verbose === true;
1635
1695
  const authHeader = request.headers.get("authorization");
1636
- const bearerToken = (authHeader === null || authHeader === void 0 ? void 0 : authHeader.toLowerCase().startsWith("bearer "))
1696
+ const bearerToken = authHeader?.toLowerCase().startsWith("bearer ")
1637
1697
  ? authHeader.slice("bearer ".length).trim()
1638
1698
  : undefined;
1639
1699
  try {
1640
- const snap = yield runtime.evalRuns.start(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (filterIds === undefined ? {} : { filterIds })), (tags === undefined ? {} : { tags })), (bearerToken === undefined || bearerToken === "" ? {} : { bearerToken })), (timeoutMs === undefined ? {} : { timeoutMs })), (verbose ? { verbose: true } : {})));
1700
+ const snap = await runtime.evalRuns.start({
1701
+ ...(filterIds === undefined ? {} : { filterIds }),
1702
+ ...(tags === undefined ? {} : { tags }),
1703
+ ...(bearerToken === undefined || bearerToken === "" ? {} : { bearerToken }),
1704
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
1705
+ ...(verbose ? { verbose: true } : {}),
1706
+ });
1641
1707
  return jsonResponse(snap, { status: 202 });
1642
1708
  }
1643
1709
  catch (error) {
@@ -1654,31 +1720,29 @@ function mountAgentRoutes(router, runtime, args) {
1654
1720
  const message = error instanceof Error ? error.message : String(error);
1655
1721
  return jsonResponse({ ok: false, error: "eval_start_failed", message }, { status: 400 });
1656
1722
  }
1657
- }),
1723
+ },
1658
1724
  });
1659
1725
  router.add({
1660
1726
  method: "GET",
1661
1727
  pattern: `${base}/v1/dev/evals/runs/:runId`,
1662
1728
  auth: httpAuth,
1663
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1664
- var _a;
1665
- const runId = (_a = ctx.params.runId) !== null && _a !== void 0 ? _a : "";
1666
- const snap = yield runtime.evalRuns.get(runId);
1729
+ handler: async (_request, ctx) => {
1730
+ const runId = ctx.params.runId ?? "";
1731
+ const snap = await runtime.evalRuns.get(runId);
1667
1732
  if (snap === undefined) {
1668
1733
  return jsonResponse({ ok: false, error: "unknown_eval_run" }, { status: 404 });
1669
1734
  }
1670
1735
  return jsonResponse(snap);
1671
- }),
1736
+ },
1672
1737
  });
1673
1738
  router.add({
1674
1739
  method: "POST",
1675
1740
  pattern: `${base}/v1/dev/evals/runs/:runId/cancel`,
1676
1741
  auth: httpAuth,
1677
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1678
- var _a;
1679
- const runId = (_a = ctx.params.runId) !== null && _a !== void 0 ? _a : "";
1742
+ handler: async (_request, ctx) => {
1743
+ const runId = ctx.params.runId ?? "";
1680
1744
  try {
1681
- const snap = yield runtime.evalRuns.cancel(runId);
1745
+ const snap = await runtime.evalRuns.cancel(runId);
1682
1746
  return jsonResponse(snap);
1683
1747
  }
1684
1748
  catch (error) {
@@ -1697,18 +1761,17 @@ function mountAgentRoutes(router, runtime, args) {
1697
1761
  const message = error instanceof Error ? error.message : String(error);
1698
1762
  return jsonResponse({ ok: false, error: "eval_cancel_failed", message }, { status: 400 });
1699
1763
  }
1700
- }),
1764
+ },
1701
1765
  });
1702
1766
  if (noControlPlane === true) {
1703
1767
  router.add({
1704
1768
  method: "POST",
1705
1769
  pattern: `${base}/v1/internal/schedules/:scheduleId/fire`,
1706
1770
  auth: [platformTimerFireAuth],
1707
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1708
- var _a;
1709
- const scheduleId = (_a = ctx.params.scheduleId) !== null && _a !== void 0 ? _a : "";
1771
+ handler: async (_request, ctx) => {
1772
+ const scheduleId = ctx.params.scheduleId ?? "";
1710
1773
  try {
1711
- const { sessionIds } = yield scheduleRunner.dispatch(scheduleId);
1774
+ const { sessionIds } = await scheduleRunner.dispatch(scheduleId);
1712
1775
  return jsonResponse({ scheduleId, sessionIds });
1713
1776
  }
1714
1777
  catch (error) {
@@ -1721,19 +1784,18 @@ function mountAgentRoutes(router, runtime, args) {
1721
1784
  }
1722
1785
  throw error;
1723
1786
  }
1724
- }),
1787
+ },
1725
1788
  });
1726
1789
  router.add({
1727
1790
  method: "POST",
1728
1791
  pattern: `${base}/v1/internal/reminders/:reminderId/fire`,
1729
1792
  auth: [platformTimerFireAuth],
1730
- handler: (request, ctx) => __awaiter(this, void 0, void 0, function* () {
1731
- var _a;
1732
- const reminderId = (_a = ctx.params.reminderId) !== null && _a !== void 0 ? _a : "";
1793
+ handler: async (request, ctx) => {
1794
+ const reminderId = ctx.params.reminderId ?? "";
1733
1795
  const fireCountRaw = new URL(request.url).searchParams.get("fireCount");
1734
1796
  const expectedFireCount = fireCountRaw === null ? undefined : Number(fireCountRaw);
1735
1797
  try {
1736
- const result = yield reminderRunner.dispatch(reminderId, expectedFireCount !== undefined && Number.isInteger(expectedFireCount)
1798
+ const result = await reminderRunner.dispatch(reminderId, expectedFireCount !== undefined && Number.isInteger(expectedFireCount)
1737
1799
  ? { expectedFireCount }
1738
1800
  : {});
1739
1801
  return jsonResponse(result);
@@ -1751,7 +1813,7 @@ function mountAgentRoutes(router, runtime, args) {
1751
1813
  }
1752
1814
  throw error;
1753
1815
  }
1754
- }),
1816
+ },
1755
1817
  });
1756
1818
  }
1757
1819
  if (dev) {
@@ -1759,11 +1821,10 @@ function mountAgentRoutes(router, runtime, args) {
1759
1821
  method: "POST",
1760
1822
  pattern: `${base}/v1/dev/schedules/:scheduleId`,
1761
1823
  auth: httpAuth,
1762
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1763
- var _a;
1764
- const scheduleId = (_a = ctx.params.scheduleId) !== null && _a !== void 0 ? _a : "";
1824
+ handler: async (_request, ctx) => {
1825
+ const scheduleId = ctx.params.scheduleId ?? "";
1765
1826
  try {
1766
- const { sessionIds } = yield scheduleRunner.dispatch(scheduleId);
1827
+ const { sessionIds } = await scheduleRunner.dispatch(scheduleId);
1767
1828
  return jsonResponse({ scheduleId, sessionIds });
1768
1829
  }
1769
1830
  catch (error) {
@@ -1776,23 +1837,22 @@ function mountAgentRoutes(router, runtime, args) {
1776
1837
  }
1777
1838
  throw error;
1778
1839
  }
1779
- }),
1840
+ },
1780
1841
  });
1781
1842
  router.add({
1782
1843
  method: "POST",
1783
1844
  pattern: `${base}/v1/dev/reminders/:reminderId`,
1784
1845
  auth: httpAuth,
1785
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1786
- var _a;
1787
- const reminderId = (_a = ctx.params.reminderId) !== null && _a !== void 0 ? _a : "";
1846
+ handler: async (_request, ctx) => {
1847
+ const reminderId = ctx.params.reminderId ?? "";
1788
1848
  try {
1789
- const listed = yield reminderRunner.list();
1849
+ const listed = await reminderRunner.list();
1790
1850
  const reminder = listed.find(r => r.id === reminderId);
1791
1851
  if (reminder === undefined) {
1792
1852
  const ids = listed.map(r => r.id);
1793
1853
  throw new UnknownReminderError(reminderId, ids);
1794
1854
  }
1795
- const ownership = yield assertReminderReadable({
1855
+ const ownership = await assertReminderReadable({
1796
1856
  engine,
1797
1857
  reminder,
1798
1858
  auth: ctx.auth,
@@ -1803,7 +1863,7 @@ function mountAgentRoutes(router, runtime, args) {
1803
1863
  if (ownership !== undefined) {
1804
1864
  return ownership;
1805
1865
  }
1806
- const result = yield reminderRunner.dispatch(reminderId);
1866
+ const result = await reminderRunner.dispatch(reminderId);
1807
1867
  return jsonResponse(result);
1808
1868
  }
1809
1869
  catch (error) {
@@ -1819,17 +1879,17 @@ function mountAgentRoutes(router, runtime, args) {
1819
1879
  }
1820
1880
  throw error;
1821
1881
  }
1822
- }),
1882
+ },
1823
1883
  });
1824
1884
  router.add({
1825
1885
  method: "GET",
1826
1886
  pattern: `${base}/v1/dev/reminders`,
1827
1887
  auth: httpAuth,
1828
- handler: (_request, ctx) => __awaiter(this, void 0, void 0, function* () {
1829
- const all = yield reminderRunner.list();
1888
+ handler: async (_request, ctx) => {
1889
+ const all = await reminderRunner.list();
1830
1890
  const reminders = [];
1831
1891
  for (const reminder of all) {
1832
- const denied = yield assertReminderReadable({
1892
+ const denied = await assertReminderReadable({
1833
1893
  engine,
1834
1894
  reminder,
1835
1895
  auth: ctx.auth,
@@ -1842,12 +1902,12 @@ function mountAgentRoutes(router, runtime, args) {
1842
1902
  }
1843
1903
  }
1844
1904
  return jsonResponse({ reminders });
1845
- }),
1905
+ },
1846
1906
  });
1847
1907
  }
1848
1908
  for (const channel of project.channels) {
1849
- const channelAuth = (_b = channel.definition.auth) !== null && _b !== void 0 ? _b : defaultAuth;
1850
- for (const channelRoute of (_c = channel.definition.routes) !== null && _c !== void 0 ? _c : []) {
1909
+ const channelAuth = channel.definition.auth ?? defaultAuth;
1910
+ for (const channelRoute of channel.definition.routes ?? []) {
1851
1911
  router.add({
1852
1912
  method: channelRoute.method,
1853
1913
  pattern: `${base}/v1/channels/${channel.id}${channelRoute.path}`,
@@ -1873,8 +1933,7 @@ function mountAgentRoutes(router, runtime, args) {
1873
1933
  * serve instead of starting with a relay that could never run.
1874
1934
  */
1875
1935
  function requireCursorEventsAuth(config, accountKey) {
1876
- var _a, _b, _c;
1877
- const apiKey = ((_b = (_a = config.apiKey) !== null && _a !== void 0 ? _a : accountKey === null || accountKey === void 0 ? void 0 : accountKey.apiKey) !== null && _b !== void 0 ? _b : "").trim();
1936
+ const apiKey = (config.apiKey ?? accountKey?.apiKey ?? "").trim();
1878
1937
  if (apiKey === "") {
1879
1938
  throw new Error(`[bdk] --cursor-events (serve({ cursorEvents })) requires a signed-in Cursor account: the SCM event stream is read as the host's user. ${SIGN_IN_HINT}`);
1880
1939
  }
@@ -1883,7 +1942,7 @@ function requireCursorEventsAuth(config, accountKey) {
1883
1942
  // `/v0/scm-events/*` lives on the external API (api.cursor.com), not
1884
1943
  // api2. Prefer that default over the account key's backendUrl, which
1885
1944
  // follows cursorBackendUrl() (api2) when CURSOR_API_KEY is set.
1886
- baseUrl: (_c = config.baseUrl) !== null && _c !== void 0 ? _c : cursorExternalApiUrl(),
1945
+ baseUrl: config.baseUrl ?? cursorExternalApiUrl(),
1887
1946
  };
1888
1947
  }
1889
1948
  /**
@@ -1937,15 +1996,13 @@ function assertSingleCursorEventsLane(input) {
1937
1996
  githubRepos: input.githubRepos,
1938
1997
  originRepos: input.originRepos,
1939
1998
  };
1940
- if (collectCursorEventSubscriptions(Object.assign({ mounts: input.v1Mounts }, shared)).length === 0 ||
1941
- collectCursorEventSubscriptions(Object.assign({ mounts: input.v2Mounts }, shared)).length === 0) {
1999
+ if (collectCursorEventSubscriptions({ mounts: input.v1Mounts, ...shared }).length === 0 ||
2000
+ collectCursorEventSubscriptions({ mounts: input.v2Mounts, ...shared }).length === 0) {
1942
2001
  return;
1943
2002
  }
1944
2003
  throw new Error("[bdk] cursor-events: refusing to serve v1 and v2 github/origin agents in one process — they would open two /v0/scm-events consumers. Serve one architecture per process.");
1945
2004
  }
1946
2005
  function startCursorEventRelay(input) {
1947
- var _a;
1948
- var _b, _c;
1949
2006
  const { config, stateRoot, mounts, auth, logger } = input;
1950
2007
  if (config === undefined || auth === undefined) {
1951
2008
  return undefined;
@@ -1971,14 +2028,14 @@ function startCursorEventRelay(input) {
1971
2028
  }
1972
2029
  return undefined;
1973
2030
  }
1974
- const baseStateRoot = stateRoot !== null && stateRoot !== void 0 ? stateRoot : join((_b = (_a = mounts[0]) === null || _a === void 0 ? void 0 : _a.project.rootDir) !== null && _b !== void 0 ? _b : process.cwd(), ".agent-serve");
2031
+ const baseStateRoot = stateRoot ?? join(mounts[0]?.project.rootDir ?? process.cwd(), ".agent-serve");
1975
2032
  const relay = new CursorEventRelay({
1976
2033
  baseUrl: auth.baseUrl,
1977
2034
  apiKey: auth.apiKey,
1978
2035
  subscriptions,
1979
- stateDir: join(baseStateRoot, (_c = input.stateDirName) !== null && _c !== void 0 ? _c : "cursor-events"),
2036
+ stateDir: join(baseStateRoot, input.stateDirName ?? "cursor-events"),
1980
2037
  logger,
1981
- dispatch: (event) => __awaiter(this, void 0, void 0, function* () {
2038
+ dispatch: async (event) => {
1982
2039
  if (event.provider === "origin") {
1983
2040
  const targets = input.collectOriginTargets().filter(target => {
1984
2041
  const cursorAccount = target.options.cursorAccount;
@@ -1991,9 +2048,14 @@ function startCursorEventRelay(input) {
1991
2048
  ? true
1992
2049
  : cursorAccount.repos.some(repo => repo.toLowerCase() === event.repo.toLowerCase());
1993
2050
  });
1994
- const result = yield handleAgentServeTrigger(Object.assign({ type: "origin", bodyText: JSON.stringify(scmMetadataToOriginPayload(event)), targets }, (input.routeContinuation === undefined
1995
- ? {}
1996
- : { routeContinuation: input.routeContinuation })));
2051
+ const result = await handleAgentServeTrigger({
2052
+ type: "origin",
2053
+ bodyText: JSON.stringify(scmMetadataToOriginPayload(event)),
2054
+ targets,
2055
+ ...(input.routeContinuation === undefined
2056
+ ? {}
2057
+ : { routeContinuation: input.routeContinuation }),
2058
+ });
1997
2059
  logCursorScmDispatch(logger, event, result);
1998
2060
  return;
1999
2061
  }
@@ -2010,11 +2072,18 @@ function startCursorEventRelay(input) {
2010
2072
  ? true
2011
2073
  : cursorAccount.repos.some(repo => repo.toLowerCase() === event.repo.toLowerCase());
2012
2074
  });
2013
- const result = yield handleAgentServeTrigger(Object.assign({ type: "github", bodyText: JSON.stringify(scmEventToGitHubPayload(event)), eventName: event.eventName, deliveryId: event.deliveryId, targets }, (input.routeContinuation === undefined
2014
- ? {}
2015
- : { routeContinuation: input.routeContinuation })));
2075
+ const result = await handleAgentServeTrigger({
2076
+ type: "github",
2077
+ bodyText: JSON.stringify(scmEventToGitHubPayload(event)),
2078
+ eventName: event.eventName,
2079
+ deliveryId: event.deliveryId,
2080
+ targets,
2081
+ ...(input.routeContinuation === undefined
2082
+ ? {}
2083
+ : { routeContinuation: input.routeContinuation }),
2084
+ });
2016
2085
  logCursorScmDispatch(logger, event, result);
2017
- }),
2086
+ },
2018
2087
  });
2019
2088
  if (input.start === false) {
2020
2089
  return relay;
@@ -2048,16 +2117,13 @@ function collectCursorGithubTargets(mounts) {
2048
2117
  return targets;
2049
2118
  }
2050
2119
  function cursorGithubPermissionsForTarget(target) {
2051
- var _a;
2052
- var _b;
2053
2120
  const authored = typeof target.accountRuntime.options.cursorAccount === "object"
2054
2121
  ? target.accountRuntime.options.cursorAccount.permissions
2055
2122
  : undefined;
2056
- return ((_b = (_a = target.accountRuntime.scope) === null || _a === void 0 ? void 0 : _a.permissions) !== null && _b !== void 0 ? _b : cursorGithubPermissionsForChannel(target.accountRuntime.options, authored));
2123
+ return (target.accountRuntime.scope?.permissions ??
2124
+ cursorGithubPermissionsForChannel(target.accountRuntime.options, authored));
2057
2125
  }
2058
2126
  function resolveCursorGithubEventConfig(input) {
2059
- var _a;
2060
- var _b;
2061
2127
  if (input.targets.length === 0) {
2062
2128
  return {
2063
2129
  cursorEvents: input.configured,
@@ -2066,8 +2132,8 @@ function resolveCursorGithubEventConfig(input) {
2066
2132
  };
2067
2133
  }
2068
2134
  const repos = [
2069
- ...((_b = (_a = input.configured) === null || _a === void 0 ? void 0 : _a.repos) !== null && _b !== void 0 ? _b : []),
2070
- ...input.targets.flatMap(target => { var _a; var _b; return [...((_b = (_a = target.accountRuntime.scope) === null || _a === void 0 ? void 0 : _a.repos) !== null && _b !== void 0 ? _b : [])]; }),
2135
+ ...(input.configured?.repos ?? []),
2136
+ ...input.targets.flatMap(target => [...(target.accountRuntime.scope?.repos ?? [])]),
2071
2137
  ];
2072
2138
  const permissions = resolveCursorGithubPermissions(input.targets.map(cursorGithubPermissionsForTarget));
2073
2139
  const scope = resolveCursorGithubCredentialScope(repos, permissions);
@@ -2079,7 +2145,10 @@ function resolveCursorGithubEventConfig(input) {
2079
2145
  };
2080
2146
  }
2081
2147
  return {
2082
- cursorEvents: Object.assign(Object.assign({}, input.configured), { repos: [...scope.repos] }),
2148
+ cursorEvents: {
2149
+ ...input.configured,
2150
+ repos: [...scope.repos],
2151
+ },
2083
2152
  scope,
2084
2153
  permissions,
2085
2154
  };
@@ -2111,7 +2180,7 @@ function resolveCursorOriginRepoScope(input) {
2111
2180
  const wantsHostRepos = input.targets.some(target => target.accountRuntime.options.cursorAccount === true);
2112
2181
  const repos = [
2113
2182
  ...(wantsHostRepos ? input.explicitRepos : []),
2114
- ...input.targets.flatMap(target => { var _a; var _b; return (_b = (_a = target.accountRuntime.scope) === null || _a === void 0 ? void 0 : _a.repos) !== null && _b !== void 0 ? _b : []; }),
2183
+ ...input.targets.flatMap(target => target.accountRuntime.scope?.repos ?? []),
2115
2184
  ];
2116
2185
  if (repos.length === 0) {
2117
2186
  return undefined;
@@ -2120,15 +2189,13 @@ function resolveCursorOriginRepoScope(input) {
2120
2189
  }
2121
2190
  function buildAgentIndexEntries(runtimes) {
2122
2191
  return runtimes.map(({ slug, project }) => {
2123
- var _a;
2124
- var _b;
2125
- const hasSlack = project.channels.some(channel => { var _a; return ((_a = channel.definition.meta) === null || _a === void 0 ? void 0 : _a.kind) === "slack"; });
2192
+ const hasSlack = project.channels.some(channel => channel.definition.meta?.kind === "slack");
2126
2193
  return {
2127
2194
  slug,
2128
2195
  name: project.name,
2129
2196
  model: typeof project.agent.model === "string"
2130
2197
  ? project.agent.model
2131
- : ((_b = (_a = project.agent.model) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : ""),
2198
+ : (project.agent.model?.id ?? ""),
2132
2199
  tools: project.agent.tools.length,
2133
2200
  channels: project.channels.length + 1,
2134
2201
  slack: hasSlack ? { kind: "socket" } : undefined,
@@ -2164,7 +2231,6 @@ function liveDeploymentSubscriptionUnion(targets) {
2164
2231
  * `startCursorEventRelay` has.
2165
2232
  */
2166
2233
  function startCursorDeploymentRelay(input) {
2167
- var _a;
2168
2234
  const { options, runtimes, accountKey, logger } = input;
2169
2235
  const targets = collectCursorDeploymentTargets(runtimes);
2170
2236
  if (targets.length === 0) {
@@ -2188,30 +2254,28 @@ function startCursorDeploymentRelay(input) {
2188
2254
  }
2189
2255
  // Same host split as scm-events: `/v0/deployment-events/*` is on
2190
2256
  // api.cursor.com, not api2.
2191
- const baseStateRoot = (_a = options.stateRoot) !== null && _a !== void 0 ? _a : join(targets[0].runtime.project.rootDir, ".agent-serve");
2257
+ const baseStateRoot = options.stateRoot ?? join(targets[0].runtime.project.rootDir, ".agent-serve");
2192
2258
  const relay = new DeploymentEventRelay({
2193
2259
  baseUrl: cursorExternalApiUrl(),
2194
2260
  apiKey: accountKey.apiKey,
2195
2261
  stateDir: join(baseStateRoot, "deployment-events"),
2196
2262
  subscriptions: () => liveDeploymentSubscriptionUnion(targets),
2197
2263
  logger,
2198
- dispatch: (event) => __awaiter(this, void 0, void 0, function* () {
2199
- return fanOutDeploymentEvent({
2200
- event,
2201
- logger,
2202
- targets: targets.map(target => ({
2203
- name: `${target.runtime.slug || target.runtime.project.name}/${target.channelId}`,
2204
- subscriptions: resolveDeploymentSubscriptions(target.options),
2205
- deliver: delivered => dispatchDeploymentEvent({
2206
- options: target.options,
2207
- event: delivered,
2208
- args: buildChannelHandlerArgs({
2209
- runtime: target.runtime,
2210
- channelId: target.channelId,
2211
- }),
2264
+ dispatch: async (event) => fanOutDeploymentEvent({
2265
+ event,
2266
+ logger,
2267
+ targets: targets.map(target => ({
2268
+ name: `${target.runtime.slug || target.runtime.project.name}/${target.channelId}`,
2269
+ subscriptions: resolveDeploymentSubscriptions(target.options),
2270
+ deliver: delivered => dispatchDeploymentEvent({
2271
+ options: target.options,
2272
+ event: delivered,
2273
+ args: buildChannelHandlerArgs({
2274
+ runtime: target.runtime,
2275
+ channelId: target.channelId,
2212
2276
  }),
2213
- })),
2214
- });
2277
+ }),
2278
+ })),
2215
2279
  }),
2216
2280
  });
2217
2281
  relay.start();
@@ -2219,17 +2283,20 @@ function startCursorDeploymentRelay(input) {
2219
2283
  return relay;
2220
2284
  }
2221
2285
  function buildChannelHandlerArgs(input) {
2222
- var _a, _b, _c;
2223
2286
  const { runtime, channelId } = input;
2224
2287
  const base = runtime.slug === "" ? "" : `/${runtime.slug}`;
2225
- const auth = (_a = input.auth) !== null && _a !== void 0 ? _a : null;
2288
+ const auth = input.auth ?? null;
2226
2289
  return {
2227
- params: (_b = input.params) !== null && _b !== void 0 ? _b : {},
2228
- requestIp: (_c = input.requestIp) !== null && _c !== void 0 ? _c : null,
2290
+ params: input.params ?? {},
2291
+ requestIp: input.requestIp ?? null,
2229
2292
  auth,
2230
2293
  host: runtime.engine.host,
2231
2294
  artifacts: runtime.engine.artifacts,
2232
- send: (message, sendOptions = {}) => runtime.engine.send(channelId, message, Object.assign(Object.assign({}, sendOptions), { auth: sendOptions.auth !== undefined ? sendOptions.auth : auth, hostedSessionId: input.hostedSessionId })),
2295
+ send: (message, sendOptions = {}) => runtime.engine.send(channelId, message, {
2296
+ ...sendOptions,
2297
+ auth: sendOptions.auth !== undefined ? sendOptions.auth : auth,
2298
+ hostedSessionId: input.hostedSessionId,
2299
+ }),
2233
2300
  getSession: sessionId => runtime.engine.getChannelSession(channelId, sessionId),
2234
2301
  receive: (target, inputReceive) => runtime.engine.receive(target, inputReceive),
2235
2302
  callTool: (toolName, toolInput, callOptions) => runtime.engine.callTool(toolName, toolInput, callOptions),
@@ -2243,200 +2310,174 @@ function buildChannelHandlerArgs(input) {
2243
2310
  interruptContinuation: continuationToken => runtime.engine.interruptContinuation(channelId, continuationToken),
2244
2311
  };
2245
2312
  }
2246
- function handleRequest(router, req, res, logger, browserOriginGuard) {
2247
- return __awaiter(this, void 0, void 0, function* () {
2248
- var _a, _b, _c;
2249
- let response;
2250
- let hostedDeliveryRequest = false;
2251
- const method = (_a = req.method) !== null && _a !== void 0 ? _a : "GET";
2252
- try {
2253
- const request = yield toFetchRequest(req);
2254
- hostedDeliveryRequest = request.headers.get(HOSTED_DELIVERY_HEADER) === "1";
2255
- const requestErrorResponse = (status, error, message) => hostedDeliveryRequest
2256
- ? hostedGuestErrorResponse({
2257
- status,
2258
- error,
2259
- retry: HOSTED_GUEST_RETRY_TERMINAL,
2260
- message,
2261
- })
2262
- : errorResponse(status, error, message);
2263
- const url = new URL(request.url);
2264
- const match = router.match(request.method, url.pathname);
2265
- if (!isTrustedBrowserMutation(request, browserOriginGuard)) {
2266
- response = requestErrorResponse(403, "forbidden_origin", "Cross-origin browser mutations are not allowed.");
2267
- }
2268
- else if (match === undefined) {
2269
- response = router.hasPath(url.pathname)
2270
- ? requestErrorResponse(405, "method_not_allowed", `${request.method} is not supported on ${url.pathname}.`)
2271
- : requestErrorResponse(404, "not_found", `No route for ${request.method} ${url.pathname}.`);
2272
- }
2273
- else {
2274
- const requestIp = (_b = req.socket.remoteAddress) !== null && _b !== void 0 ? _b : null;
2275
- let auth = null;
2276
- let unauthorized = false;
2277
- if (match.route.auth !== "none") {
2278
- auth = yield resolveAuth(match.route.auth, request, requestIp);
2279
- unauthorized = auth === null;
2280
- }
2281
- response = unauthorized
2282
- ? requestErrorResponse(401, "unauthorized", "No auth policy admitted this request. In production, configure channel auth (e.g. bearerAuth) — the default localDevStrict() policy only admits loopback callers with a loopback Host.")
2283
- : yield match.route.handler(request, {
2284
- params: match.params,
2285
- requestIp,
2286
- auth,
2287
- });
2288
- }
2313
+ async function handleRequest(router, req, res, logger, browserOriginGuard) {
2314
+ let response;
2315
+ let hostedDeliveryRequest = false;
2316
+ const method = req.method ?? "GET";
2317
+ try {
2318
+ const request = await toFetchRequest(req);
2319
+ hostedDeliveryRequest = request.headers.get(HOSTED_DELIVERY_HEADER) === "1";
2320
+ const requestErrorResponse = (status, error, message) => hostedDeliveryRequest
2321
+ ? hostedGuestErrorResponse({
2322
+ status,
2323
+ error,
2324
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
2325
+ message,
2326
+ })
2327
+ : errorResponse(status, error, message);
2328
+ const url = new URL(request.url);
2329
+ const match = router.match(request.method, url.pathname);
2330
+ if (!isTrustedBrowserMutation(request, browserOriginGuard)) {
2331
+ response = requestErrorResponse(403, "forbidden_origin", "Cross-origin browser mutations are not allowed.");
2289
2332
  }
2290
- catch (error) {
2291
- const mapped = mapThrownRequestError(error);
2292
- if (mapped !== undefined) {
2293
- response = hostedDeliveryRequest
2294
- ? hostedGuestErrorResponse({
2295
- status: mapped.status,
2296
- error: mapped.code,
2297
- retry: mapped.retry,
2298
- message: mapped.message,
2299
- })
2300
- : errorResponse(mapped.status, mapped.code, mapped.message);
2301
- }
2302
- else {
2303
- logger(`[bdk] request failed: ${error instanceof Error ? ((_c = error.stack) !== null && _c !== void 0 ? _c : error.message) : String(error)}`);
2304
- const snippet = hostedErrorStackSnippet(error);
2305
- const message = hostedDeliveryRequest
2306
- ? hostedErrorMessageOnly(error)
2307
- : snippet.length > 0
2308
- ? `Internal server error: ${snippet}`
2309
- : "Internal server error.";
2310
- response = hostedDeliveryRequest
2311
- ? hostedGuestErrorResponse({
2312
- status: 500,
2313
- error: "internal_error",
2314
- retry: HOSTED_GUEST_RETRY_TERMINAL,
2315
- message,
2316
- })
2317
- : errorResponse(500, "internal_error", message);
2333
+ else if (match === undefined) {
2334
+ response = router.hasPath(url.pathname)
2335
+ ? requestErrorResponse(405, "method_not_allowed", `${request.method} is not supported on ${url.pathname}.`)
2336
+ : requestErrorResponse(404, "not_found", `No route for ${request.method} ${url.pathname}.`);
2337
+ }
2338
+ else {
2339
+ const requestIp = req.socket.remoteAddress ?? null;
2340
+ let auth = null;
2341
+ let unauthorized = false;
2342
+ if (match.route.auth !== "none") {
2343
+ auth = await resolveAuth(match.route.auth, request, requestIp);
2344
+ unauthorized = auth === null;
2318
2345
  }
2346
+ response = unauthorized
2347
+ ? requestErrorResponse(401, "unauthorized", "No auth policy admitted this request. In production, configure channel auth (e.g. bearerAuth) — the default localDevStrict() policy only admits loopback callers with a loopback Host.")
2348
+ : await match.route.handler(request, {
2349
+ params: match.params,
2350
+ requestIp,
2351
+ auth,
2352
+ });
2319
2353
  }
2320
- try {
2321
- yield writeFetchResponse(response, res, method);
2354
+ }
2355
+ catch (error) {
2356
+ const mapped = mapThrownRequestError(error);
2357
+ if (mapped !== undefined) {
2358
+ response = hostedDeliveryRequest
2359
+ ? hostedGuestErrorResponse({
2360
+ status: mapped.status,
2361
+ error: mapped.code,
2362
+ retry: mapped.retry,
2363
+ message: mapped.message,
2364
+ })
2365
+ : errorResponse(mapped.status, mapped.code, mapped.message);
2322
2366
  }
2323
- catch (error) {
2324
- logger(`[bdk] response write failed: ${error instanceof Error ? error.message : String(error)}`);
2325
- res.destroy();
2367
+ else {
2368
+ logger(`[bdk] request failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
2369
+ const snippet = hostedErrorStackSnippet(error);
2370
+ const message = hostedDeliveryRequest
2371
+ ? hostedErrorMessageOnly(error)
2372
+ : snippet.length > 0
2373
+ ? `Internal server error: ${snippet}`
2374
+ : "Internal server error.";
2375
+ response = hostedDeliveryRequest
2376
+ ? hostedGuestErrorResponse({
2377
+ status: 500,
2378
+ error: "internal_error",
2379
+ retry: HOSTED_GUEST_RETRY_TERMINAL,
2380
+ message,
2381
+ })
2382
+ : errorResponse(500, "internal_error", message);
2326
2383
  }
2327
- });
2384
+ }
2385
+ try {
2386
+ await writeFetchResponse(response, res, method);
2387
+ }
2388
+ catch (error) {
2389
+ logger(`[bdk] response write failed: ${error instanceof Error ? error.message : String(error)}`);
2390
+ res.destroy();
2391
+ }
2328
2392
  }
2329
- function resolveAuth(policies, request, requestIp) {
2330
- return __awaiter(this, void 0, void 0, function* () {
2331
- for (const policy of policies) {
2332
- const result = yield policy(request, { requestIp });
2333
- if (result !== null) {
2334
- return result;
2335
- }
2393
+ async function resolveAuth(policies, request, requestIp) {
2394
+ for (const policy of policies) {
2395
+ const result = await policy(request, { requestIp });
2396
+ if (result !== null) {
2397
+ return result;
2336
2398
  }
2337
- return null;
2399
+ }
2400
+ return null;
2401
+ }
2402
+ async function toFetchRequest(req) {
2403
+ const method = req.method ?? "GET";
2404
+ const hostHeader = incomingRequestHost(req.headers);
2405
+ const url = new URL(req.url ?? "/", `http://${hostHeader}`);
2406
+ // Drop HTTP/2 pseudo-headers (`:method`, …) — Fetch `Headers` rejects them.
2407
+ const headers = incomingHeadersToFetch(req.headers);
2408
+ if (method === "GET" || method === "HEAD") {
2409
+ return new Request(url, { method, headers });
2410
+ }
2411
+ const body = await readBody(req);
2412
+ // Buffer is a Uint8Array at runtime; TS's BodyInit wants ArrayBuffer-backed
2413
+ // typed arrays, so re-view without copying.
2414
+ return new Request(url, {
2415
+ method,
2416
+ headers,
2417
+ body: new Uint8Array(body.buffer, body.byteOffset, body.byteLength),
2338
2418
  });
2339
2419
  }
2340
- function toFetchRequest(req) {
2341
- return __awaiter(this, void 0, void 0, function* () {
2342
- var _a, _b;
2343
- const method = (_a = req.method) !== null && _a !== void 0 ? _a : "GET";
2344
- const hostHeader = incomingRequestHost(req.headers);
2345
- const url = new URL((_b = req.url) !== null && _b !== void 0 ? _b : "/", `http://${hostHeader}`);
2346
- // Drop HTTP/2 pseudo-headers (`:method`, …) — Fetch `Headers` rejects them.
2347
- const headers = incomingHeadersToFetch(req.headers);
2348
- if (method === "GET" || method === "HEAD") {
2349
- return new Request(url, { method, headers });
2420
+ async function readBody(req) {
2421
+ const chunks = [];
2422
+ let total = 0;
2423
+ for await (const chunk of req) {
2424
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2425
+ total += buffer.length;
2426
+ if (total > MAX_BODY_BYTES) {
2427
+ throw new Error("Request body too large");
2350
2428
  }
2351
- const body = yield readBody(req);
2352
- // Buffer is a Uint8Array at runtime; TS's BodyInit wants ArrayBuffer-backed
2353
- // typed arrays, so re-view without copying.
2354
- return new Request(url, {
2355
- method,
2356
- headers,
2357
- body: new Uint8Array(body.buffer, body.byteOffset, body.byteLength),
2358
- });
2359
- });
2429
+ chunks.push(buffer);
2430
+ }
2431
+ return Buffer.concat(chunks);
2360
2432
  }
2361
- function readBody(req) {
2362
- return __awaiter(this, void 0, void 0, function* () {
2363
- var _a, req_1, req_1_1;
2364
- var _b, e_1, _c, _d;
2365
- const chunks = [];
2366
- let total = 0;
2367
- try {
2368
- for (_a = true, req_1 = __asyncValues(req); req_1_1 = yield req_1.next(), _b = req_1_1.done, !_b; _a = true) {
2369
- _d = req_1_1.value;
2370
- _a = false;
2371
- const chunk = _d;
2372
- const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
2373
- total += buffer.length;
2374
- if (total > MAX_BODY_BYTES) {
2375
- throw new Error("Request body too large");
2376
- }
2377
- chunks.push(buffer);
2378
- }
2433
+ export async function writeFetchResponse(response, res, method = "GET") {
2434
+ const headers = {};
2435
+ response.headers.forEach((value, key) => {
2436
+ headers[key] = value;
2437
+ });
2438
+ res.writeHead(response.status, headers);
2439
+ // HEAD responses must not include a body (RFC 9110 §9.3.2). Cancel any
2440
+ // handler-produced stream so long-lived GET handlers (e.g. session SSE)
2441
+ // still unsubscribe when served via the HEAD→GET fallback. A client that
2442
+ // left while the handler ran gets no body either: its `close` has already
2443
+ // fired, so the loop below would wait on a drain that never comes.
2444
+ if (method === "HEAD" || response.body === null || res.destroyed) {
2445
+ if (response.body !== null) {
2446
+ void response.body.cancel().catch(() => { });
2379
2447
  }
2380
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
2381
- finally {
2382
- try {
2383
- if (!_a && !_b && (_c = req_1.return)) yield _c.call(req_1);
2448
+ res.end();
2449
+ return;
2450
+ }
2451
+ const reader = response.body.getReader();
2452
+ let clientGone = false;
2453
+ const closed = new Promise(resolve => {
2454
+ res.once("close", () => {
2455
+ if (!res.writableFinished) {
2456
+ clientGone = true;
2457
+ void reader.cancel().catch(() => { });
2384
2458
  }
2385
- finally { if (e_1) throw e_1.error; }
2386
- }
2387
- return Buffer.concat(chunks);
2388
- });
2389
- }
2390
- export function writeFetchResponse(response_1, res_1) {
2391
- return __awaiter(this, arguments, void 0, function* (response, res, method = "GET") {
2392
- const headers = {};
2393
- response.headers.forEach((value, key) => {
2394
- headers[key] = value;
2459
+ resolve();
2395
2460
  });
2396
- res.writeHead(response.status, headers);
2397
- // HEAD responses must not include a body (RFC 9110 §9.3.2). Cancel any
2398
- // handler-produced stream so long-lived GET handlers (e.g. session SSE)
2399
- // still unsubscribe when served via the HEAD→GET fallback. A client that
2400
- // left while the handler ran gets no body either: its `close` has already
2401
- // fired, so the loop below would wait on a drain that never comes.
2402
- if (method === "HEAD" || response.body === null || res.destroyed) {
2403
- if (response.body !== null) {
2404
- void response.body.cancel().catch(() => { });
2461
+ });
2462
+ try {
2463
+ while (!clientGone) {
2464
+ const { done, value } = await reader.read();
2465
+ if (done) {
2466
+ break;
2405
2467
  }
2406
- res.end();
2407
- return;
2408
- }
2409
- const reader = response.body.getReader();
2410
- let clientGone = false;
2411
- const closed = new Promise(resolve => {
2412
- res.once("close", () => {
2413
- if (!res.writableFinished) {
2414
- clientGone = true;
2415
- void reader.cancel().catch(() => { });
2416
- }
2417
- resolve();
2418
- });
2419
- });
2420
- try {
2421
- while (!clientGone) {
2422
- const { done, value } = yield reader.read();
2423
- if (done) {
2424
- break;
2425
- }
2426
- if (value !== undefined && value.length > 0) {
2427
- if (!res.write(value) && !clientGone) {
2428
- // Race against close so a vanished client can't wedge the loop
2429
- // waiting for a drain that will never come.
2430
- yield Promise.race([once(res, "drain"), closed]);
2431
- }
2468
+ if (value !== undefined && value.length > 0) {
2469
+ if (!res.write(value) && !clientGone) {
2470
+ // Race against close so a vanished client can't wedge the loop
2471
+ // waiting for a drain that will never come.
2472
+ await Promise.race([once(res, "drain"), closed]);
2432
2473
  }
2433
2474
  }
2434
2475
  }
2435
- catch (_a) {
2436
- void reader.cancel().catch(() => { });
2437
- }
2438
- res.end();
2439
- });
2476
+ }
2477
+ catch {
2478
+ void reader.cancel().catch(() => { });
2479
+ }
2480
+ res.end();
2440
2481
  }
2441
2482
  /**
2442
2483
  * Dev reminder routes may only inspect/fire reminders whose bound session
@@ -2463,25 +2504,23 @@ function asPositiveInt(value) {
2463
2504
  const n = Math.floor(value);
2464
2505
  return n > 0 ? n : undefined;
2465
2506
  }
2466
- function assertReminderReadable(input) {
2467
- return __awaiter(this, void 0, void 0, function* () {
2468
- const existing = yield input.engine.sessions.findByContinuation(input.reminder.channelId, input.reminder.continuationToken);
2469
- if (existing === undefined) {
2470
- // No live session — still gate on relax/loopback so a shared-dev caller
2471
- // cannot enumerate orphan reminder metadata across principals.
2472
- const relaxOwnership = input.relax === true &&
2473
- (input.beyondLoopback === true ||
2474
- (typeof input.requestIp === "string" && isLoopbackAddress(input.requestIp)));
2475
- if (relaxOwnership) {
2476
- return undefined;
2477
- }
2478
- // Without a session principal to compare, deny non-relaxed callers.
2479
- return errorResponse(403, "forbidden", "This reminder is bound to a session that is not visible to the caller.");
2507
+ async function assertReminderReadable(input) {
2508
+ const existing = await input.engine.sessions.findByContinuation(input.reminder.channelId, input.reminder.continuationToken);
2509
+ if (existing === undefined) {
2510
+ // No live session — still gate on relax/loopback so a shared-dev caller
2511
+ // cannot enumerate orphan reminder metadata across principals.
2512
+ const relaxOwnership = input.relax === true &&
2513
+ (input.beyondLoopback === true ||
2514
+ (typeof input.requestIp === "string" && isLoopbackAddress(input.requestIp)));
2515
+ if (relaxOwnership) {
2516
+ return undefined;
2480
2517
  }
2481
- return requireSessionOwner(existing, input.auth, {
2482
- relax: input.relax,
2483
- beyondLoopback: input.beyondLoopback,
2484
- requestIp: input.requestIp,
2485
- });
2518
+ // Without a session principal to compare, deny non-relaxed callers.
2519
+ return errorResponse(403, "forbidden", "This reminder is bound to a session that is not visible to the caller.");
2520
+ }
2521
+ return requireSessionOwner(existing, input.auth, {
2522
+ relax: input.relax,
2523
+ beyondLoopback: input.beyondLoopback,
2524
+ requestIp: input.requestIp,
2486
2525
  });
2487
2526
  }