@cursor/bdk 0.2.9 → 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 (570) hide show
  1. package/dist/artifacts.js +3 -5
  2. package/dist/bin/agent-serve.js +803 -812
  3. package/dist/channels/bitbucket/api.js +305 -321
  4. package/dist/channels/bitbucket/binding.js +97 -61
  5. package/dist/channels/bitbucket/bitbucket-channel.d.ts +15 -1
  6. package/dist/channels/bitbucket/bitbucket-channel.d.ts.map +1 -1
  7. package/dist/channels/bitbucket/bitbucket-channel.js +95 -42
  8. package/dist/channels/bitbucket/bitbucket-webhook.d.ts +11 -0
  9. package/dist/channels/bitbucket/bitbucket-webhook.d.ts.map +1 -1
  10. package/dist/channels/bitbucket/bitbucket-webhook.js +214 -204
  11. package/dist/channels/bitbucket/checks.js +9 -21
  12. package/dist/channels/bitbucket/cursor-account.js +1 -1
  13. package/dist/channels/bitbucket/defaults.js +14 -4
  14. package/dist/channels/bitbucket/events.js +1 -2
  15. package/dist/channels/bitbucket/index.d.ts +6 -2
  16. package/dist/channels/bitbucket/index.d.ts.map +1 -1
  17. package/dist/channels/bitbucket/index.js +6 -2
  18. package/dist/channels/bitbucket/replay.js +80 -56
  19. package/dist/channels/bitbucket/state.js +16 -7
  20. package/dist/channels/bitbucket/types.d.ts +11 -2
  21. package/dist/channels/bitbucket/types.d.ts.map +1 -1
  22. package/dist/channels/checks.js +18 -28
  23. package/dist/channels/deployments/deployments-channel.js +26 -34
  24. package/dist/channels/github/api.js +216 -210
  25. package/dist/channels/github/auth.d.ts +5 -1
  26. package/dist/channels/github/auth.d.ts.map +1 -1
  27. package/dist/channels/github/auth.js +157 -174
  28. package/dist/channels/github/binding.js +48 -39
  29. package/dist/channels/github/checks.js +9 -14
  30. package/dist/channels/github/cursor-account.js +6 -11
  31. package/dist/channels/github/defaults.js +105 -130
  32. package/dist/channels/github/forward.js +13 -17
  33. package/dist/channels/github/github-channel.d.ts +43 -2
  34. package/dist/channels/github/github-channel.d.ts.map +1 -1
  35. package/dist/channels/github/github-channel.js +1228 -958
  36. package/dist/channels/github/progress.js +145 -146
  37. package/dist/channels/github/replay.js +30 -39
  38. package/dist/channels/github/state.js +40 -16
  39. package/dist/channels/github/types.d.ts +30 -6
  40. package/dist/channels/github/types.d.ts.map +1 -1
  41. package/dist/channels/gitlab/api.js +100 -114
  42. package/dist/channels/gitlab/binding.js +52 -33
  43. package/dist/channels/gitlab/checks.js +28 -29
  44. package/dist/channels/gitlab/cursor-account.js +1 -1
  45. package/dist/channels/gitlab/defaults.js +9 -3
  46. package/dist/channels/gitlab/gitlab-channel.d.ts +16 -1
  47. package/dist/channels/gitlab/gitlab-channel.d.ts.map +1 -1
  48. package/dist/channels/gitlab/gitlab-channel.js +95 -42
  49. package/dist/channels/gitlab/gitlab-webhook.d.ts +10 -1
  50. package/dist/channels/gitlab/gitlab-webhook.d.ts.map +1 -1
  51. package/dist/channels/gitlab/gitlab-webhook.js +282 -249
  52. package/dist/channels/gitlab/index.d.ts +6 -2
  53. package/dist/channels/gitlab/index.d.ts.map +1 -1
  54. package/dist/channels/gitlab/index.js +6 -2
  55. package/dist/channels/gitlab/replay.js +50 -27
  56. package/dist/channels/gitlab/state.js +14 -6
  57. package/dist/channels/gitlab/types.d.ts +13 -2
  58. package/dist/channels/gitlab/types.d.ts.map +1 -1
  59. package/dist/channels/origin/api.js +100 -116
  60. package/dist/channels/origin/binding.js +15 -16
  61. package/dist/channels/origin/checks.js +30 -28
  62. package/dist/channels/origin/defaults.js +50 -65
  63. package/dist/channels/origin/origin-channel.js +266 -272
  64. package/dist/channels/origin/origin-webhook.js +70 -88
  65. package/dist/channels/origin/reactions.js +9 -21
  66. package/dist/channels/origin/state.js +13 -5
  67. package/dist/channels/slack/agentic-delivery.js +426 -478
  68. package/dist/channels/slack/agentic-posted.js +9 -10
  69. package/dist/channels/slack/agentic-signals.js +2 -3
  70. package/dist/channels/slack/api.js +417 -427
  71. package/dist/channels/slack/approvals.js +1 -1
  72. package/dist/channels/slack/assistant.js +37 -47
  73. package/dist/channels/slack/attachments.js +188 -206
  74. package/dist/channels/slack/auth.js +8 -6
  75. package/dist/channels/slack/bot-mentions.js +31 -45
  76. package/dist/channels/slack/channel-watch.js +42 -48
  77. package/dist/channels/slack/cli-project.js +112 -137
  78. package/dist/channels/slack/code-fences.js +3 -5
  79. package/dist/channels/slack/constants.js +2 -2
  80. package/dist/channels/slack/credentials.js +23 -38
  81. package/dist/channels/slack/defaults.js +292 -331
  82. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  83. package/dist/channels/slack/dispatch.js +533 -460
  84. package/dist/channels/slack/doctor.js +200 -214
  85. package/dist/channels/slack/eval-directive.js +79 -96
  86. package/dist/channels/slack/event-id-dedupe.js +1 -1
  87. package/dist/channels/slack/external-policy.js +26 -39
  88. package/dist/channels/slack/footer.js +28 -41
  89. package/dist/channels/slack/inbound.d.ts +1 -0
  90. package/dist/channels/slack/inbound.d.ts.map +1 -1
  91. package/dist/channels/slack/inbound.js +50 -31
  92. package/dist/channels/slack/init.d.ts +1 -5
  93. package/dist/channels/slack/init.d.ts.map +1 -1
  94. package/dist/channels/slack/init.js +42 -59
  95. package/dist/channels/slack/interactive.d.ts +9 -3
  96. package/dist/channels/slack/interactive.d.ts.map +1 -1
  97. package/dist/channels/slack/interactive.js +160 -162
  98. package/dist/channels/slack/links.js +1 -2
  99. package/dist/channels/slack/live-delivery.js +172 -190
  100. package/dist/channels/slack/manifest.d.ts.map +1 -1
  101. package/dist/channels/slack/manifest.js +44 -23
  102. package/dist/channels/slack/message-body.js +2 -2
  103. package/dist/channels/slack/nudge-carrier.js +30 -42
  104. package/dist/channels/slack/nudge-store.js +164 -191
  105. package/dist/channels/slack/paint-start.js +66 -81
  106. package/dist/channels/slack/placeholder.js +123 -152
  107. package/dist/channels/slack/pr-ref.js +1 -1
  108. package/dist/channels/slack/progress-delivery.js +65 -78
  109. package/dist/channels/slack/reasoning-card.js +36 -49
  110. package/dist/channels/slack/recording-sink.js +12 -24
  111. package/dist/channels/slack/reply-options.js +7 -12
  112. package/dist/channels/slack/self-identity.js +27 -35
  113. package/dist/channels/slack/sender-name.d.ts +12 -3
  114. package/dist/channels/slack/sender-name.d.ts.map +1 -1
  115. package/dist/channels/slack/sender-name.js +57 -61
  116. package/dist/channels/slack/setup.js +2 -4
  117. package/dist/channels/slack/slack-channel.d.ts +6 -4
  118. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  119. package/dist/channels/slack/slack-channel.js +441 -308
  120. package/dist/channels/slack/socket-mode.js +38 -52
  121. package/dist/channels/slack/thread-context.js +143 -160
  122. package/dist/channels/slack/tool-approval-events.js +149 -166
  123. package/dist/channels/slack/tool-cards.js +6 -11
  124. package/dist/channels/slack/tool-chip.js +1 -2
  125. package/dist/channels/slack/types.d.ts +15 -17
  126. package/dist/channels/slack/types.d.ts.map +1 -1
  127. package/dist/channels/slack/upload.js +84 -97
  128. package/dist/channels/slack/user-info.js +27 -41
  129. package/dist/channels.js +9 -20
  130. package/dist/dashboard-session-url.js +3 -4
  131. package/dist/docs/404.html +2 -2
  132. package/dist/docs/assets/{app.BNhEdGa8.js → app.DXI7bwox.js} +4 -4
  133. package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.js → building-with-agents.md.Df87rAe1.js} +1 -1
  134. package/dist/docs/assets/chunks/@localSearchIndexroot.CtLtpWcx.js +1 -0
  135. package/dist/docs/assets/chunks/{VPLocalSearchBox.DIdUV1Ph.js → VPLocalSearchBox.BrbO5mEe.js} +1 -1
  136. package/dist/docs/assets/chunks/{arc.lELI4_SR.js → arc.BOG1yms8.js} +1 -1
  137. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.iCMdvuoM.js → architectureDiagram-Q4EWVU46.C0hsMZnZ.js} +1 -1
  138. package/dist/docs/assets/chunks/{baseUniq.C1-nDJBf.js → baseUniq.H044KjKs.js} +1 -1
  139. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.ClemzBox.js → blockDiagram-DXYQGD6D.BsRW6GoB.js} +1 -1
  140. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.BqTak6cR.js → c4Diagram-AHTNJAMY.B9HV5PFR.js} +1 -1
  141. package/dist/docs/assets/chunks/channel.CBwrU9rP.js +1 -0
  142. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.CUS3qs_R.js → chunk-4BX2VUAB.CPoT_ajl.js} +1 -1
  143. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.dz5fdHcl.js → chunk-4TB4RGXK.DZBwWuCL.js} +1 -1
  144. package/dist/docs/assets/chunks/{chunk-55IACEB6.D6BEBmve.js → chunk-55IACEB6.CZ3yTiyq.js} +1 -1
  145. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.B5uK4ID9.js → chunk-EDXVE4YY.6DfvHSd8.js} +1 -1
  146. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.PgOJgNQs.js → chunk-FMBD7UC4.CpBj8HfK.js} +1 -1
  147. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CvkTrCii.js → chunk-OYMX7WX6.BdKo8YqS.js} +1 -1
  148. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BnSfKYsB.js → chunk-QZHKN3VN.BnXNyxJx.js} +1 -1
  149. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.MZH6v5UC.js → chunk-YZCP3GAM.Cg1OcF8G.js} +1 -1
  150. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CbC_mrvB.js +1 -0
  151. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CbC_mrvB.js +1 -0
  152. package/dist/docs/assets/chunks/clone.BTvFyY1a.js +1 -0
  153. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.BBbw_YZi.js → cose-bilkent-S5V4N54A.1SP8al9c.js} +1 -1
  154. package/dist/docs/assets/chunks/{dagre-KV5264BT.CNJB2l7E.js → dagre-KV5264BT.DS1L6hJt.js} +1 -1
  155. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.BQzlnFfq.js → diagram-5BDNPKRD.ChsausbG.js} +1 -1
  156. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.DkgqqZMz.js → diagram-G4DWMVQ6.3XsptNWj.js} +1 -1
  157. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.DIT8L7H_.js → diagram-MMDJMWI5.DPA9Dk_P.js} +1 -1
  158. package/dist/docs/assets/chunks/{diagram-TYMM5635.3xLPZWGJ.js → diagram-TYMM5635.BVswXWrB.js} +1 -1
  159. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.5_IHz8jF.js → erDiagram-SMLLAGMA.BSak5OSP.js} +1 -1
  160. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.BGUCXz8A.js → flowDiagram-DWJPFMVM.CQgN4TTz.js} +1 -1
  161. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.DbfFavS1.js → ganttDiagram-T4ZO3ILL.GrT0kA4a.js} +1 -1
  162. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.D2yKdeNW.js → gitGraphDiagram-UUTBAWPF.CdS7Ucll.js} +1 -1
  163. package/dist/docs/assets/chunks/{graph.CSCxwHba.js → graph.BVqKRmRo.js} +1 -1
  164. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.FDeb6xHY.js → infoDiagram-42DDH7IO.C3C9FRto.js} +1 -1
  165. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DbeYs9VL.js → ishikawaDiagram-UXIWVN3A.2FuAh_Zj.js} +1 -1
  166. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.CWjKINpx.js → journeyDiagram-VCZTEJTY.CaHMfK4b.js} +1 -1
  167. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.B4FrAlwz.js → kanban-definition-6JOO6SKY.CjhIUwcA.js} +1 -1
  168. package/dist/docs/assets/chunks/{layout.DFGxQ9ab.js → layout.CGU3gfSf.js} +1 -1
  169. package/dist/docs/assets/chunks/{linear.BmjZ-G59.js → linear.DaihpW_n.js} +1 -1
  170. package/dist/docs/assets/chunks/{min.DZSxulMW.js → min.BS-j8kHQ.js} +1 -1
  171. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CHLi3-aN.js → mindmap-definition-QFDTVHPH.BVJ1Bbnk.js} +1 -1
  172. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DteG-CkU.js → pieDiagram-DEJITSTG.Cz1WIv9r.js} +1 -1
  173. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D458ipN3.js → quadrantDiagram-34T5L4WZ.DKLFxcjy.js} +1 -1
  174. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.DcFgUxst.js → requirementDiagram-MS252O5E.BHegiK7x.js} +1 -1
  175. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.BwQAMmSA.js → sankeyDiagram-XADWPNL6.DYkY6yPc.js} +1 -1
  176. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.B_Xdsrh9.js → sequenceDiagram-FGHM5R23.DYQ1QUrI.js} +1 -1
  177. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.CdfDW6-C.js → stateDiagram-FHFEXIEX.Iru8BsFo.js} +1 -1
  178. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.BYXl4LW6.js +1 -0
  179. package/dist/docs/assets/chunks/{theme.sfdL3srp.js → theme.DaplWQhQ.js} +2 -2
  180. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.56-4hXaC.js → timeline-definition-GMOUNBTQ.BwFA8hiX.js} +1 -1
  181. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CvZSQBO7.js → vennDiagram-DHZGUBPP.CZ60W1C_.js} +1 -1
  182. package/dist/docs/assets/chunks/{wardley-RL74JXVD.C9qc8k39.js → wardley-RL74JXVD.iXazD3Z7.js} +1 -1
  183. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.D9s0nihi.js → wardleyDiagram-NUSXRM2D.B69D2r8-.js} +1 -1
  184. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.BVJSpYrC.js → xychartDiagram-5P7HB3ND.CLPZEIU9.js} +1 -1
  185. package/dist/docs/assets/{deployment.md.BdqTiGdc.js → deployment.md.BYuEcDBv.js} +2 -2
  186. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.js → guides_bitbucket.md.CKUayYtD.js} +3 -3
  187. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.lean.js → guides_bitbucket.md.CKUayYtD.lean.js} +1 -1
  188. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.js → guides_github.md.TuNiZAOQ.js} +4 -4
  189. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.lean.js → guides_github.md.TuNiZAOQ.lean.js} +1 -1
  190. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.js → guides_gitlab.md.CtNI4fSH.js} +4 -4
  191. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.lean.js → guides_gitlab.md.CtNI4fSH.lean.js} +1 -1
  192. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.js +7 -0
  193. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.lean.js +1 -0
  194. package/dist/docs/assets/{reference_cli.md.GwugN3n-.js → reference_cli.md.dYCAL2lB.js} +4 -3
  195. package/dist/docs/assets/reference_cli.md.dYCAL2lB.lean.js +1 -0
  196. package/dist/docs/assets/{reference_skills.md.ClkMoQsV.js → reference_skills.md.C0guGcH0.js} +3 -3
  197. package/dist/docs/assets/troubleshooting.md.x-GBa7wN.js +1 -0
  198. package/dist/docs/assets/{troubleshooting.md.Bscj6ODe.lean.js → troubleshooting.md.x-GBa7wN.lean.js} +1 -1
  199. package/dist/docs/building-with-agents.html +37 -37
  200. package/dist/docs/building-with-agents.md +2 -0
  201. package/dist/docs/deployment.html +38 -38
  202. package/dist/docs/deployment.md +7 -0
  203. package/dist/docs/evals.html +36 -36
  204. package/dist/docs/guides/agent-to-agent.html +35 -35
  205. package/dist/docs/guides/bitbucket.html +38 -38
  206. package/dist/docs/guides/bitbucket.md +9 -1
  207. package/dist/docs/guides/cloud-agents.html +35 -35
  208. package/dist/docs/guides/convert-automation.html +35 -35
  209. package/dist/docs/guides/github.html +39 -39
  210. package/dist/docs/guides/github.md +20 -4
  211. package/dist/docs/guides/gitlab.html +38 -38
  212. package/dist/docs/guides/gitlab.md +9 -1
  213. package/dist/docs/guides/grokbot-agents.html +35 -35
  214. package/dist/docs/guides/hooks.html +35 -35
  215. package/dist/docs/guides/improve.html +35 -35
  216. package/dist/docs/guides/jev.html +35 -35
  217. package/dist/docs/guides/mcp-oauth.html +35 -35
  218. package/dist/docs/guides/migrate.html +66 -0
  219. package/dist/docs/guides/migrate.md +122 -0
  220. package/dist/docs/guides/opentelemetry.html +35 -35
  221. package/dist/docs/guides/slack.html +35 -35
  222. package/dist/docs/guides/webhooks.html +35 -35
  223. package/dist/docs/hashmap.json +1 -1
  224. package/dist/docs/hillclimbing.html +35 -35
  225. package/dist/docs/index.html +35 -35
  226. package/dist/docs/llms-full.txt +214 -6
  227. package/dist/docs/llms.txt +1 -0
  228. package/dist/docs/quickstart.html +35 -35
  229. package/dist/docs/reference/agent-config.html +35 -35
  230. package/dist/docs/reference/artifacts.html +35 -35
  231. package/dist/docs/reference/channels.html +35 -35
  232. package/dist/docs/reference/cli.html +39 -38
  233. package/dist/docs/reference/cli.md +39 -0
  234. package/dist/docs/reference/connections.html +35 -35
  235. package/dist/docs/reference/evals.html +35 -35
  236. package/dist/docs/reference/extensions.html +35 -35
  237. package/dist/docs/reference/hooks.html +35 -35
  238. package/dist/docs/reference/http-api.html +35 -35
  239. package/dist/docs/reference/instructions.html +35 -35
  240. package/dist/docs/reference/playground.html +35 -35
  241. package/dist/docs/reference/project-layout.html +35 -35
  242. package/dist/docs/reference/prompt.html +35 -35
  243. package/dist/docs/reference/schedules.html +35 -35
  244. package/dist/docs/reference/sessions.html +35 -35
  245. package/dist/docs/reference/skills.html +38 -38
  246. package/dist/docs/reference/subagents.html +35 -35
  247. package/dist/docs/reference/tools.html +35 -35
  248. package/dist/docs/templates/agentic-owners.html +35 -35
  249. package/dist/docs/templates/grokbot-agents.html +35 -35
  250. package/dist/docs/templates/security-reviewer.html +35 -35
  251. package/dist/docs/templates/thermo-quality-review.html +35 -35
  252. package/dist/docs/templates/thermo-review.html +35 -35
  253. package/dist/docs/templates/triage.html +35 -35
  254. package/dist/docs/troubleshooting.html +36 -36
  255. package/dist/docs/troubleshooting.md +1 -0
  256. package/dist/evals/assertions.js +20 -34
  257. package/dist/evals/expect.js +3 -6
  258. package/dist/evals/judge.js +5 -8
  259. package/dist/evals/loaders.js +45 -62
  260. package/dist/evals/matchers.js +2 -3
  261. package/dist/evals/reporters.js +43 -67
  262. package/dist/evals/results.js +1 -1
  263. package/dist/evals/run-facts.js +5 -6
  264. package/dist/evals.js +27 -15
  265. package/dist/extensions/cursor-cloud-agents/extension.js +4 -1
  266. package/dist/extensions/cursor-cloud-agents/lib/backend.js +100 -126
  267. package/dist/extensions/cursor-cloud-agents/lib/fleet.js +22 -38
  268. package/dist/extensions/cursor-cloud-agents/lib/repos.js +8 -10
  269. package/dist/extensions/cursor-cloud-agents/lib/transcript.js +2 -3
  270. package/dist/extensions/cursor-cloud-agents/lib/watch.js +52 -66
  271. package/dist/extensions/cursor-cloud-agents/reminders/cloud-agent-stop-watch.js +29 -40
  272. package/dist/extensions/cursor-cloud-agents/tools/cancel.js +6 -17
  273. package/dist/extensions/cursor-cloud-agents/tools/dump.js +25 -36
  274. package/dist/extensions/cursor-cloud-agents/tools/get.js +3 -14
  275. package/dist/extensions/cursor-cloud-agents/tools/launch.js +13 -21
  276. package/dist/extensions/cursor-cloud-agents/tools/list.js +8 -19
  277. package/dist/extensions/cursor-cloud-agents/tools/reply.js +5 -16
  278. package/dist/extensions/cursor-grokbot-agents/extension.js +4 -1
  279. package/dist/extensions/cursor-grokbot-agents/lib/agents.js +3 -3
  280. package/dist/extensions/cursor-grokbot-agents/lib/backend.js +53 -73
  281. package/dist/extensions/cursor-grokbot-agents/lib/contacts.js +10 -23
  282. package/dist/extensions/cursor-grokbot-agents/lib/conversation.js +112 -132
  283. package/dist/extensions/cursor-grokbot-agents/lib/lock.js +1 -2
  284. package/dist/extensions/cursor-grokbot-agents/tools/ask.js +5 -16
  285. package/dist/extensions/cursor-grokbot-agents/tools/check.js +4 -15
  286. package/dist/extensions/cursor-grokbot-agents/tools/interrupt.js +2 -13
  287. package/dist/extensions/cursor-grokbot-agents/tools/list.js +11 -23
  288. package/dist/extensions/jev/extension.js +3 -3
  289. package/dist/extensions/jev/lib/evaluate.js +43 -60
  290. package/dist/extensions/jev/tools/evaluate.js +6 -17
  291. package/dist/extensions/slack-communication/tools/post-file.js +1 -1
  292. package/dist/extensions.js +3 -5
  293. package/dist/files-backends/cursor-hosted.js +504 -523
  294. package/dist/files-backends/local-fs.js +72 -134
  295. package/dist/files.js +3 -3
  296. package/dist/filesystem.js +562 -861
  297. package/dist/index.js +16 -35
  298. package/dist/internal/advertise-tools.js +74 -86
  299. package/dist/internal/artifacts-store.js +298 -361
  300. package/dist/internal/as-of.js +2 -4
  301. package/dist/internal/authored-alias-hooks.js +6 -4
  302. package/dist/internal/authored-loaders.js +37 -52
  303. package/dist/internal/bounded-int.js +1 -2
  304. package/dist/internal/bounded.js +13 -24
  305. package/dist/internal/brand.js +1 -1
  306. package/dist/internal/browser-origin-guard.js +4 -4
  307. package/dist/internal/builtin-tools/artifacts.js +15 -27
  308. package/dist/internal/builtin-tools/index.js +2 -3
  309. package/dist/internal/builtin-tools/reminders.js +33 -52
  310. package/dist/internal/channel-architecture.d.ts +21 -0
  311. package/dist/internal/channel-architecture.d.ts.map +1 -0
  312. package/dist/internal/channel-architecture.js +41 -0
  313. package/dist/internal/channel-dispatch.js +3 -4
  314. package/dist/internal/channel-route-dispatch.js +40 -51
  315. package/dist/internal/channel-state.js +1 -1
  316. package/dist/internal/chat-client.js +319 -340
  317. package/dist/internal/cli-ax.js +1262 -1294
  318. package/dist/internal/cli-bitbucket.js +244 -272
  319. package/dist/internal/cli-convert-automation.js +137 -151
  320. package/dist/internal/cli-cursor.js +126 -147
  321. package/dist/internal/cli-deploy.d.ts.map +1 -1
  322. package/dist/internal/cli-deploy.js +1457 -1507
  323. package/dist/internal/cli-docs.js +130 -147
  324. package/dist/internal/cli-github.js +437 -476
  325. package/dist/internal/cli-gitlab.js +259 -288
  326. package/dist/internal/cli-images.js +266 -334
  327. package/dist/internal/cli-manifest.js +25 -37
  328. package/dist/internal/cli-mcp-oauth.js +228 -247
  329. package/dist/internal/cli-mcp.js +358 -383
  330. package/dist/internal/cli-migrate.js +73 -90
  331. package/dist/internal/cli-skills.js +35 -47
  332. package/dist/internal/cli-slack-manual.d.ts +0 -1
  333. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  334. package/dist/internal/cli-slack-manual.js +175 -204
  335. package/dist/internal/cli-slack.d.ts +1 -1
  336. package/dist/internal/cli-slack.d.ts.map +1 -1
  337. package/dist/internal/cli-slack.js +416 -456
  338. package/dist/internal/cloud-merge.js +7 -3
  339. package/dist/internal/cloud-turn-cost.js +8 -1
  340. package/dist/internal/connection-env.js +5 -6
  341. package/dist/internal/continuation-channel.js +10 -7
  342. package/dist/internal/continuation-identity.js +85 -67
  343. package/dist/internal/conversation-mirror.js +112 -131
  344. package/dist/internal/convert-automation/convert-workflow.js +21 -31
  345. package/dist/internal/cron.js +3 -3
  346. package/dist/internal/cursor/account-mcp.js +147 -146
  347. package/dist/internal/cursor/backend-client.js +290 -320
  348. package/dist/internal/cursor/bound-secret-file.js +3 -3
  349. package/dist/internal/cursor/credentials.js +127 -142
  350. package/dist/internal/cursor/cursor-api-transport.js +4 -8
  351. package/dist/internal/cursor/github-credentials.js +91 -108
  352. package/dist/internal/cursor/hosted-bound-secrets.js +3 -4
  353. package/dist/internal/cursor/hosted-deployment-secrets.js +1 -1
  354. package/dist/internal/cursor/hosted-store-secrets.js +5 -9
  355. package/dist/internal/cursor/session-token.js +36 -48
  356. package/dist/internal/cursor/store-api-client.js +77 -92
  357. package/dist/internal/cursor-account-mcp-auth.js +132 -149
  358. package/dist/internal/cursor-agent-template.js +1 -1
  359. package/dist/internal/cursor-deployment-relay.js +33 -54
  360. package/dist/internal/cursor-event-relay.js +65 -59
  361. package/dist/internal/cursor-relay-core.js +258 -286
  362. package/dist/internal/deferred-channel-session.js +3 -12
  363. package/dist/internal/deploy-client.js +410 -475
  364. package/dist/internal/deploy-manifest.d.ts +17 -0
  365. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  366. package/dist/internal/deploy-manifest.js +71 -21
  367. package/dist/internal/deploy-source.js +31 -43
  368. package/dist/internal/discovery/agent-config.js +45 -59
  369. package/dist/internal/discovery/agent.js +276 -280
  370. package/dist/internal/discovery/channels.js +67 -80
  371. package/dist/internal/discovery/connections.js +286 -296
  372. package/dist/internal/discovery/context.js +2 -13
  373. package/dist/internal/discovery/cursor-plugin.js +223 -259
  374. package/dist/internal/discovery/extension-overlay.js +104 -131
  375. package/dist/internal/discovery/extensions.js +276 -281
  376. package/dist/internal/discovery/fs.js +56 -79
  377. package/dist/internal/discovery/hooks.js +39 -50
  378. package/dist/internal/discovery/info.js +17 -19
  379. package/dist/internal/discovery/instructions.js +58 -71
  380. package/dist/internal/discovery/modules.js +45 -58
  381. package/dist/internal/discovery/project.d.ts.map +1 -1
  382. package/dist/internal/discovery/project.js +192 -215
  383. package/dist/internal/discovery/reminders.js +41 -52
  384. package/dist/internal/discovery/runtime.js +1 -1
  385. package/dist/internal/discovery/schedules.js +71 -82
  386. package/dist/internal/discovery/seed-files.js +21 -32
  387. package/dist/internal/discovery/services.js +74 -96
  388. package/dist/internal/discovery/skills.js +77 -94
  389. package/dist/internal/discovery/subagent.js +79 -95
  390. package/dist/internal/discovery/tools.js +12 -23
  391. package/dist/internal/distribution.js +2 -2
  392. package/dist/internal/docs-site.js +30 -45
  393. package/dist/internal/duration.js +1 -1
  394. package/dist/internal/env-file.js +48 -64
  395. package/dist/internal/eval-judge-model.js +17 -28
  396. package/dist/internal/eval-run-store.js +265 -254
  397. package/dist/internal/eval-runner.d.ts +8 -0
  398. package/dist/internal/eval-runner.d.ts.map +1 -1
  399. package/dist/internal/eval-runner.js +406 -408
  400. package/dist/internal/eval-transport.d.ts +24 -0
  401. package/dist/internal/eval-transport.d.ts.map +1 -0
  402. package/dist/internal/eval-transport.js +22 -0
  403. package/dist/internal/evals-client.js +242 -246
  404. package/dist/internal/event-log.js +72 -120
  405. package/dist/internal/event-mapper.js +30 -31
  406. package/dist/internal/factory-resource-channel.js +16 -30
  407. package/dist/internal/filesystem/errors.js +6 -6
  408. package/dist/internal/filesystem/format.js +10 -13
  409. package/dist/internal/filesystem/merge.js +52 -94
  410. package/dist/internal/filesystem/nearest.js +15 -27
  411. package/dist/internal/filesystem/scratch.js +65 -85
  412. package/dist/internal/filesystem/tools.js +221 -241
  413. package/dist/internal/filesystem/walk.js +76 -143
  414. package/dist/internal/framework-file-storage.js +118 -139
  415. package/dist/internal/framework-storage-selection.js +21 -13
  416. package/dist/internal/frontmatter.js +4 -6
  417. package/dist/internal/github-fanout.js +50 -64
  418. package/dist/internal/guest-network.js +96 -109
  419. package/dist/internal/handleAgentServeTrigger.js +121 -126
  420. package/dist/internal/host-files.js +73 -88
  421. package/dist/internal/host-kv.js +21 -36
  422. package/dist/internal/host-otel.js +22 -19
  423. package/dist/internal/host-platforms.js +49 -63
  424. package/dist/internal/hosted-catch-protocol.d.ts +1 -0
  425. package/dist/internal/hosted-catch-protocol.d.ts.map +1 -1
  426. package/dist/internal/hosted-catch-protocol.js +1 -0
  427. package/dist/internal/hosted-catch.d.ts +5 -3
  428. package/dist/internal/hosted-catch.d.ts.map +1 -1
  429. package/dist/internal/hosted-catch.js +84 -93
  430. package/dist/internal/hosted-delivery-protocol.js +32 -8
  431. package/dist/internal/hosted-delivery.d.ts +13 -1
  432. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  433. package/dist/internal/hosted-delivery.js +614 -584
  434. package/dist/internal/hosted-eval-cases.d.ts +21 -0
  435. package/dist/internal/hosted-eval-cases.d.ts.map +1 -0
  436. package/dist/internal/hosted-eval-cases.js +162 -0
  437. package/dist/internal/hosted-execution-diag.js +38 -30
  438. package/dist/internal/hosted-execution-flush.js +75 -66
  439. package/dist/internal/hosted-execution-latency.js +16 -8
  440. package/dist/internal/hosted-managed-automation.js +2 -2
  441. package/dist/internal/hosting.js +2 -3
  442. package/dist/internal/http-channel-define.js +4 -1
  443. package/dist/internal/http-channel.js +101 -112
  444. package/dist/internal/http-control-plane-session.d.ts +18 -1
  445. package/dist/internal/http-control-plane-session.d.ts.map +1 -1
  446. package/dist/internal/http-control-plane-session.js +66 -32
  447. package/dist/internal/incoming-headers-to-fetch.js +1 -2
  448. package/dist/internal/init-interview.js +73 -93
  449. package/dist/internal/init-project.js +182 -214
  450. package/dist/internal/init-scaffold.js +10 -21
  451. package/dist/internal/inline-stdio-mcp.js +80 -86
  452. package/dist/internal/install-cursor-skills.js +231 -273
  453. package/dist/internal/legacy-command-guard.js +18 -31
  454. package/dist/internal/listen-port.js +34 -45
  455. package/dist/internal/local-control-plane.js +293 -307
  456. package/dist/internal/local-env.js +1 -1
  457. package/dist/internal/local-ingress.js +15 -9
  458. package/dist/internal/log-ring.js +1 -2
  459. package/dist/internal/logs-client.js +207 -227
  460. package/dist/internal/map-pool.js +24 -38
  461. package/dist/internal/mcp-endpoint.js +204 -180
  462. package/dist/internal/mcp-host.js +165 -168
  463. package/dist/internal/mcp-oauth-on-demand.js +170 -207
  464. package/dist/internal/mcp-oauth-persist.js +15 -29
  465. package/dist/internal/mcp-oauth.js +209 -266
  466. package/dist/internal/named-webhook-secret.d.ts +39 -0
  467. package/dist/internal/named-webhook-secret.d.ts.map +1 -0
  468. package/dist/internal/named-webhook-secret.js +47 -0
  469. package/dist/internal/open-browser.js +2 -3
  470. package/dist/internal/otel/collector.js +104 -68
  471. package/dist/internal/otel/config.js +24 -37
  472. package/dist/internal/otel/http.js +5 -7
  473. package/dist/internal/otel/mcp.js +3 -12
  474. package/dist/internal/otel/runtime.js +69 -83
  475. package/dist/internal/package-inline-stdio.js +57 -65
  476. package/dist/internal/peer-connections.js +9 -5
  477. package/dist/internal/platform-schedule-sync.js +39 -54
  478. package/dist/internal/platform-timers.js +176 -210
  479. package/dist/internal/playground/static.js +1 -2
  480. package/dist/internal/playground/toolchain.js +37 -53
  481. package/dist/internal/playground-proxy.js +230 -270
  482. package/dist/internal/process-memory-telemetry.js +33 -51
  483. package/dist/internal/prompt-context.js +3 -6
  484. package/dist/internal/reminder-control-plane-protocol.js +46 -13
  485. package/dist/internal/reminder-runner.js +770 -785
  486. package/dist/internal/reminder-schedule.js +1 -1
  487. package/dist/internal/reminder-store.js +57 -78
  488. package/dist/internal/request-error-status.js +1 -3
  489. package/dist/internal/request-headers.js +2 -2
  490. package/dist/internal/resolve-prod-target.js +119 -135
  491. package/dist/internal/resolved-connections.js +16 -6
  492. package/dist/internal/run-client.js +221 -229
  493. package/dist/internal/runtime-dispatch-runner.js +18 -43
  494. package/dist/internal/schedule-runner.js +49 -58
  495. package/dist/internal/scm/pr-url.js +7 -6
  496. package/dist/internal/sdk-runner.js +388 -363
  497. package/dist/internal/serve-restart.js +26 -39
  498. package/dist/internal/server.d.ts.map +1 -1
  499. package/dist/internal/server.js +1283 -1244
  500. package/dist/internal/session-cost.js +7 -9
  501. package/dist/internal/session-engine.d.ts +3 -1
  502. package/dist/internal/session-engine.d.ts.map +1 -1
  503. package/dist/internal/session-engine.js +2801 -2777
  504. package/dist/internal/session-links.js +12 -16
  505. package/dist/internal/session-run-log.js +134 -82
  506. package/dist/internal/session-store.js +133 -164
  507. package/dist/internal/sessions-client.js +97 -118
  508. package/dist/internal/skill-catalog.js +18 -23
  509. package/dist/internal/skills-sync.js +16 -30
  510. package/dist/internal/slack-provision-client.js +90 -116
  511. package/dist/internal/start-log-store.js +48 -67
  512. package/dist/internal/steering.js +1 -2
  513. package/dist/internal/storage-coordinator.js +160 -196
  514. package/dist/internal/store-mirror.js +16 -30
  515. package/dist/internal/stream-progress.js +6 -8
  516. package/dist/internal/terminal-style.js +3 -4
  517. package/dist/internal/testing/scm-continuation-fixtures.js +6 -2
  518. package/dist/internal/testing/slack-continuation-fixtures.d.ts +26 -0
  519. package/dist/internal/testing/slack-continuation-fixtures.d.ts.map +1 -0
  520. package/dist/internal/testing/slack-continuation-fixtures.js +136 -0
  521. package/dist/internal/tool-catalog.js +11 -5
  522. package/dist/internal/tool-result.js +1 -1
  523. package/dist/internal/trajectory.js +19 -22
  524. package/dist/internal/turn-cost.js +52 -62
  525. package/dist/internal/turn-governor.js +5 -8
  526. package/dist/internal/turn-lease-store.js +85 -105
  527. package/dist/internal/turn-outbox.js +28 -43
  528. package/dist/internal/update-check.js +231 -259
  529. package/dist/internal/v2-hosting.js +1 -2
  530. package/dist/internal/workspace-sync.js +25 -41
  531. package/dist/internal/workspace.js +111 -139
  532. package/dist/kv/memory-kv.js +27 -51
  533. package/dist/memory.js +106 -148
  534. package/dist/otel.js +5 -8
  535. package/dist/playground/assets/index-DXm_VXAQ.css +1 -0
  536. package/dist/playground/assets/{index-Co4CUVTQ.js → index-JekUQERK.js} +45 -45
  537. package/dist/playground/index.html +2 -2
  538. package/dist/prompt.js +2 -4
  539. package/dist/storage-backends/cursor-hosted-v2.js +53 -83
  540. package/dist/storage-backends/cursor-hosted.js +105 -145
  541. package/dist/storage-backends/file-kv.js +100 -128
  542. package/dist/storage-protocol.js +3 -5
  543. package/dist/storage.js +17 -26
  544. package/dist/types.d.ts +68 -0
  545. package/dist/types.d.ts.map +1 -1
  546. package/dist/types.js +20 -18
  547. package/docs/building-with-agents.md +2 -0
  548. package/docs/deployment.md +7 -0
  549. package/docs/guides/bitbucket.md +9 -1
  550. package/docs/guides/github.md +20 -4
  551. package/docs/guides/gitlab.md +9 -1
  552. package/docs/guides/migrate.md +127 -0
  553. package/docs/reference/cli.md +39 -0
  554. package/docs/troubleshooting.md +1 -0
  555. package/package.json +1 -1
  556. package/skills/debug/SKILL.md +1 -0
  557. package/skills/github/SKILL.md +23 -0
  558. package/skills/migrate-v2/SKILL.md +51 -10
  559. package/dist/docs/assets/chunks/@localSearchIndexroot.BJ8UZggu.js +0 -1
  560. package/dist/docs/assets/chunks/channel.BTJ5J9FI.js +0 -1
  561. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.D4BZ3cVV.js +0 -1
  562. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.D4BZ3cVV.js +0 -1
  563. package/dist/docs/assets/chunks/clone.62tX-O-1.js +0 -1
  564. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.DkTs1aEU.js +0 -1
  565. package/dist/docs/assets/reference_cli.md.GwugN3n-.lean.js +0 -1
  566. package/dist/docs/assets/troubleshooting.md.Bscj6ODe.js +0 -1
  567. package/dist/playground/assets/index-C1g_PTTZ.css +0 -1
  568. /package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.lean.js → building-with-agents.md.Df87rAe1.lean.js} +0 -0
  569. /package/dist/docs/assets/{deployment.md.BdqTiGdc.lean.js → deployment.md.BYuEcDBv.lean.js} +0 -0
  570. /package/dist/docs/assets/{reference_skills.md.ClkMoQsV.lean.js → reference_skills.md.C0guGcH0.lean.js} +0 -0
@@ -10,16 +10,6 @@
10
10
  * {@link FileConflictError}, and the backend reports
11
11
  * `host.files.capabilities.conflictDetection`.
12
12
  */
13
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
- return new (P || (P = Promise))(function (resolve, reject) {
16
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
- step((generator = generator.apply(thisArg, _arguments || [])).next());
20
- });
21
- };
22
- var _a;
23
13
  import { createHash } from "node:crypto";
24
14
  import { FileConflictError, } from "../files.js";
25
15
  import { mapBounded } from "../internal/bounded.js";
@@ -40,9 +30,9 @@ export const AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR = "AGENT_SERVE_STORE_SOURCE_ID"
40
30
  */
41
31
  export const AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID_ENV_VAR = "AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID";
42
32
  /** Cap on the per-process etag cache; a miss costs a lookup, not correctness. */
43
- const MAX_REMEMBERED_ETAGS = 1000;
33
+ const MAX_REMEMBERED_ETAGS = 1_000;
44
34
  /** Bounded directory page for point lookups. */
45
- const DIRECTORY_PAGE_SIZE = 1000;
35
+ const DIRECTORY_PAGE_SIZE = 1_000;
46
36
  /** Paths requested in each {@link FileSink.getMany} batch. */
47
37
  const READ_PRESIGN_BATCH_MAX = 100;
48
38
  /** Concurrent downloads inside one {@link FileSink.getMany} batch. */
@@ -54,7 +44,7 @@ const MAX_DIRECTORY_PAGES = 20;
54
44
  * could not carry (~1M entries at the page size above). Past it, fail loudly:
55
45
  * a silently partial listing would be mistaken for the whole scope.
56
46
  */
57
- const MAX_LIST_WALK_PAGES = 1000;
47
+ const MAX_LIST_WALK_PAGES = 1_000;
58
48
  /**
59
49
  * True on Cursor-managed hosting with a provisioned file store.
60
50
  *
@@ -70,7 +60,6 @@ export function isCursorHostedFilesAvailable(env = process.env) {
70
60
  * deployments always use their deployment-scoped store instead.
71
61
  */
72
62
  export function isCursorUserStoreFilesAvailable(env = process.env) {
73
- var _a;
74
63
  if (isCursorHostedFilesAvailable(env)) {
75
64
  return false;
76
65
  }
@@ -78,7 +67,7 @@ export function isCursorUserStoreFilesAvailable(env = process.env) {
78
67
  if (env.VITEST === "true") {
79
68
  return false;
80
69
  }
81
- const key = (_a = env.CURSOR_API_KEY) === null || _a === void 0 ? void 0 : _a.trim();
70
+ const key = env.CURSOR_API_KEY?.trim();
82
71
  return key !== undefined && key !== "";
83
72
  }
84
73
  /**
@@ -109,26 +98,22 @@ export function cursorHostedFiles(options = {}) {
109
98
  * Storage bindings and transport selection are resolved for each operation
110
99
  * so platform updates do not require recreating the sink.
111
100
  */
112
- function withFiles(call) {
113
- return __awaiter(this, void 0, void 0, function* () {
114
- var _a;
115
- var _b;
116
- const sourceId = resolveStoreSourceId(options);
117
- const protocol = (_b = (_a = options.resolveStoreProtocol) === null || _a === void 0 ? void 0 : _a.call(options)) !== null && _b !== void 0 ? _b : resolveStoreProtocolSync();
118
- if (storeProtocolEnablesFactoryFlush(protocol)) {
119
- // The batched transport addresses managed stores by role. An unknown
120
- // store or transport stays on the compatibility path.
121
- if (sourceId === resolveFrameworkStoreSourceIdSync()) {
122
- return yield call({ wire: "flush", store: "framework" });
123
- }
124
- if (sourceId === resolveDeploymentStoreSourceIdSync()) {
125
- return yield call({ wire: "flush", store: "deployment" });
126
- }
101
+ async function withFiles(call) {
102
+ const sourceId = resolveStoreSourceId(options);
103
+ const protocol = options.resolveStoreProtocol?.() ?? resolveStoreProtocolSync();
104
+ if (storeProtocolEnablesFactoryFlush(protocol)) {
105
+ // The batched transport addresses managed stores by role. An unknown
106
+ // store or transport stays on the compatibility path.
107
+ if (sourceId === resolveFrameworkStoreSourceIdSync()) {
108
+ return await call({ wire: "flush", store: "framework" });
127
109
  }
128
- return yield call({
129
- wire: "v0",
130
- path: (suffix = "") => `/${encodeURIComponent(sourceId)}${suffix}`,
131
- });
110
+ if (sourceId === resolveDeploymentStoreSourceIdSync()) {
111
+ return await call({ wire: "flush", store: "deployment" });
112
+ }
113
+ }
114
+ return await call({
115
+ wire: "v0",
116
+ path: (suffix = "") => `/${encodeURIComponent(sourceId)}${suffix}`,
132
117
  });
133
118
  }
134
119
  /**
@@ -148,77 +133,76 @@ export function cursorHostedFiles(options = {}) {
148
133
  * delete race resolves itself on retry, where the presign returns 404
149
134
  * and this correctly reads as a miss.
150
135
  */
151
- function downloadPresigned(key, url) {
152
- return __awaiter(this, void 0, void 0, function* () {
153
- const response = yield resolveCursorApiFetch(options)(assertPresignedUrlSafe(options, url), {
154
- method: "GET",
155
- redirect: "manual",
156
- });
157
- if (response.status === 404) {
158
- return undefined;
159
- }
160
- if (!response.ok) {
161
- throw new Error(`cursorHostedFiles: download of "${key}" failed (HTTP ${response.status})`);
162
- }
163
- const etag = normalizeEtag(response.headers.get("etag"));
164
- if (etag !== undefined) {
165
- rememberEtag(key, etag);
166
- }
167
- return Object.assign({ body: new Uint8Array(yield response.arrayBuffer()) }, (etag === undefined ? {} : { etag }));
136
+ async function downloadPresigned(key, url) {
137
+ const response = await resolveCursorApiFetch(options)(assertPresignedUrlSafe(options, url), {
138
+ method: "GET",
139
+ redirect: "manual",
168
140
  });
141
+ if (response.status === 404) {
142
+ return undefined;
143
+ }
144
+ if (!response.ok) {
145
+ throw new Error(`cursorHostedFiles: download of "${key}" failed (HTTP ${response.status})`);
146
+ }
147
+ const etag = normalizeEtag(response.headers.get("etag"));
148
+ if (etag !== undefined) {
149
+ rememberEtag(key, etag);
150
+ }
151
+ return {
152
+ body: new Uint8Array(await response.arrayBuffer()),
153
+ ...(etag === undefined ? {} : { etag }),
154
+ };
169
155
  }
170
156
  /** One page of a directory listing. */
171
- function directoryPage(files, directory, pageToken) {
172
- return __awaiter(this, void 0, void 0, function* () {
173
- if (files.wire === "flush") {
174
- return yield flushPost(options, "/list", Object.assign({ store: files.store, path: directory, limit: DIRECTORY_PAGE_SIZE }, (pageToken === undefined ? {} : { pageToken })));
175
- }
176
- const query = new URLSearchParams({
157
+ async function directoryPage(files, directory, pageToken) {
158
+ if (files.wire === "flush") {
159
+ return await flushPost(options, "/list", {
160
+ store: files.store,
177
161
  path: directory,
178
- limit: String(DIRECTORY_PAGE_SIZE),
162
+ limit: DIRECTORY_PAGE_SIZE,
163
+ ...(pageToken === undefined ? {} : { pageToken }),
179
164
  });
180
- if (pageToken !== undefined) {
181
- query.set("pageToken", pageToken);
182
- }
183
- return yield storeGet(options, files.path(`?${query.toString()}`));
165
+ }
166
+ const query = new URLSearchParams({
167
+ path: directory,
168
+ limit: String(DIRECTORY_PAGE_SIZE),
184
169
  });
170
+ if (pageToken !== undefined) {
171
+ query.set("pageToken", pageToken);
172
+ }
173
+ return await storeGet(options, files.path(`?${query.toString()}`));
185
174
  }
186
175
  /** The unscoped whole-store listing. */
187
- function unscopedListing(files) {
188
- return __awaiter(this, void 0, void 0, function* () {
189
- if (files.wire === "flush") {
190
- return yield flushPost(options, "/list", {
191
- store: files.store,
192
- });
193
- }
194
- return yield storeGet(options, files.path());
195
- });
176
+ async function unscopedListing(files) {
177
+ if (files.wire === "flush") {
178
+ return await flushPost(options, "/list", {
179
+ store: files.store,
180
+ });
181
+ }
182
+ return await storeGet(options, files.path());
196
183
  }
197
- function listEntries(prefix) {
198
- return __awaiter(this, void 0, void 0, function* () {
199
- return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
200
- var _a;
201
- const raw = yield unscopedListing(files);
202
- if (raw.complete === true) {
203
- const out = [];
204
- for (const file of (_a = raw.files) !== null && _a !== void 0 ? _a : []) {
205
- if (typeof file.path !== "string" || !file.path.startsWith(prefix)) {
206
- continue;
207
- }
208
- out.push(toEntry(file, file.path));
184
+ async function listEntries(prefix) {
185
+ return await withFiles(async (files) => {
186
+ const raw = await unscopedListing(files);
187
+ if (raw.complete === true) {
188
+ const out = [];
189
+ for (const file of raw.files ?? []) {
190
+ if (typeof file.path !== "string" || !file.path.startsWith(prefix)) {
191
+ continue;
209
192
  }
210
- // The FileSink contract promises key order, and transcript-chunk
211
- // consumers depend on it (chunk keys are zero-padded so key order
212
- // is append order). The server happens to scan in order today; do
213
- // not let that be the only thing holding the contract.
214
- return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
193
+ out.push(toEntry(file, file.path));
215
194
  }
216
- // The unscoped listing was truncated (`complete: false`) and has no
217
- // continuation to follow. `list()` promises the whole scope, so rather
218
- // than lie or fail, walk the paginated per-directory form, which does
219
- // paginate and reports immediate subdirectories to recurse into.
220
- return yield walkDirectoryTree(files, prefix);
221
- }));
195
+ // The FileSink contract promises key order, and transcript-chunk
196
+ // consumers depend on it (chunk keys are zero-padded so key order
197
+ // is append order). The server happens to scan in order today; do
198
+ // not let that be the only thing holding the contract.
199
+ return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
200
+ }
201
+ // The unscoped listing was truncated (`complete: false`) and has no
202
+ // continuation to follow. `list()` promises the whole scope, so rather
203
+ // than lie or fail, walk the paginated per-directory form, which does
204
+ // paginate and reports immediate subdirectories to recurse into.
205
+ return await walkDirectoryTree(files, prefix);
222
206
  });
223
207
  }
224
208
  /**
@@ -229,49 +213,46 @@ export function cursorHostedFiles(options = {}) {
229
213
  * store fails loudly rather than returning a silently partial answer the
230
214
  * caller would mistake for the whole scope.
231
215
  */
232
- function walkDirectoryTree(files, prefix) {
233
- return __awaiter(this, void 0, void 0, function* () {
234
- var _a, _b;
235
- const slash = prefix.lastIndexOf("/");
236
- const pending = [slash === -1 ? "" : prefix.slice(0, slash)];
237
- const queued = new Set(pending);
238
- const out = [];
239
- let pageBudget = MAX_LIST_WALK_PAGES;
240
- while (pending.length > 0) {
241
- const directory = pending.pop();
242
- let pageToken;
243
- do {
244
- if (pageBudget <= 0) {
245
- throw new Error("cursorHostedFiles: the store is too large to list; scope the listing with a narrower prefix");
216
+ async function walkDirectoryTree(files, prefix) {
217
+ const slash = prefix.lastIndexOf("/");
218
+ const pending = [slash === -1 ? "" : prefix.slice(0, slash)];
219
+ const queued = new Set(pending);
220
+ const out = [];
221
+ let pageBudget = MAX_LIST_WALK_PAGES;
222
+ while (pending.length > 0) {
223
+ const directory = pending.pop();
224
+ let pageToken;
225
+ do {
226
+ if (pageBudget <= 0) {
227
+ throw new Error("cursorHostedFiles: the store is too large to list; scope the listing with a narrower prefix");
228
+ }
229
+ pageBudget -= 1;
230
+ const page = await directoryPage(files, directory, pageToken);
231
+ for (const file of page.files ?? []) {
232
+ if (typeof file.path === "string" && file.path.startsWith(prefix)) {
233
+ out.push(toEntry(file, file.path));
246
234
  }
247
- pageBudget -= 1;
248
- const page = yield directoryPage(files, directory, pageToken);
249
- for (const file of (_a = page.files) !== null && _a !== void 0 ? _a : []) {
250
- if (typeof file.path === "string" && file.path.startsWith(prefix)) {
251
- out.push(toEntry(file, file.path));
252
- }
235
+ }
236
+ // Every page can surface different subdirectories, so collect from
237
+ // all of them, deduped — and descend only into branches that can
238
+ // still hold matches: a descendant of the prefix, or (at the first
239
+ // level) a directory the prefix's basename component narrows to.
240
+ for (const subdir of page.directories ?? []) {
241
+ if (queued.has(subdir)) {
242
+ continue;
253
243
  }
254
- // Every page can surface different subdirectories, so collect from
255
- // all of them, deduped — and descend only into branches that can
256
- // still hold matches: a descendant of the prefix, or (at the first
257
- // level) a directory the prefix's basename component narrows to.
258
- for (const subdir of (_b = page.directories) !== null && _b !== void 0 ? _b : []) {
259
- if (queued.has(subdir)) {
260
- continue;
261
- }
262
- if (`${subdir}/`.startsWith(prefix) || prefix.startsWith(`${subdir}/`)) {
263
- queued.add(subdir);
264
- pending.push(subdir);
265
- }
244
+ if (`${subdir}/`.startsWith(prefix) || prefix.startsWith(`${subdir}/`)) {
245
+ queued.add(subdir);
246
+ pending.push(subdir);
266
247
  }
267
- pageToken =
268
- page.complete === false && page.nextPageToken !== undefined
269
- ? page.nextPageToken
270
- : undefined;
271
- } while (pageToken !== undefined);
272
- }
273
- return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
274
- });
248
+ }
249
+ pageToken =
250
+ page.complete === false && page.nextPageToken !== undefined
251
+ ? page.nextPageToken
252
+ : undefined;
253
+ } while (pageToken !== undefined);
254
+ }
255
+ return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
275
256
  }
276
257
  /** Shared decode: remember the etag as a side effect, then shape the entry. */
277
258
  function toEntry(file, key) {
@@ -279,7 +260,12 @@ export function cursorHostedFiles(options = {}) {
279
260
  rememberEtag(key, file.etag);
280
261
  }
281
262
  const mtimeMs = typeof file.updatedAt === "string" ? Date.parse(file.updatedAt) : undefined;
282
- return Object.assign(Object.assign({ key, size: typeof file.sizeBytes === "number" ? file.sizeBytes : 0 }, (typeof file.etag === "string" && file.etag !== "" ? { etag: file.etag } : {})), (mtimeMs === undefined || Number.isNaN(mtimeMs) ? {} : { mtimeMs }));
263
+ return {
264
+ key,
265
+ size: typeof file.sizeBytes === "number" ? file.sizeBytes : 0,
266
+ ...(typeof file.etag === "string" && file.etag !== "" ? { etag: file.etag } : {}),
267
+ ...(mtimeMs === undefined || Number.isNaN(mtimeMs) ? {} : { mtimeMs }),
268
+ };
283
269
  }
284
270
  /**
285
271
  * One key's current entry, via the bounded directory listing.
@@ -289,53 +275,62 @@ export function cursorHostedFiles(options = {}) {
289
275
  * the store got. `?path=` is scoped to one directory and paginates, and the
290
276
  * scan stops as soon as the key appears.
291
277
  */
292
- function statKey(key) {
293
- return __awaiter(this, void 0, void 0, function* () {
294
- const slash = key.lastIndexOf("/");
295
- const directory = slash === -1 ? "" : key.slice(0, slash);
296
- return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
297
- var _a;
298
- let pageToken;
299
- for (let page = 0; page < MAX_DIRECTORY_PAGES; page += 1) {
300
- const raw = yield directoryPage(files, directory, pageToken);
301
- for (const file of (_a = raw.files) !== null && _a !== void 0 ? _a : []) {
302
- if (file.path === key) {
303
- return toEntry(file, key);
304
- }
278
+ async function statKey(key) {
279
+ const slash = key.lastIndexOf("/");
280
+ const directory = slash === -1 ? "" : key.slice(0, slash);
281
+ return await withFiles(async (files) => {
282
+ let pageToken;
283
+ for (let page = 0; page < MAX_DIRECTORY_PAGES; page += 1) {
284
+ const raw = await directoryPage(files, directory, pageToken);
285
+ for (const file of raw.files ?? []) {
286
+ if (file.path === key) {
287
+ return toEntry(file, key);
305
288
  }
306
- // `complete` is false exactly when another page is waiting.
307
- if (raw.complete !== false || raw.nextPageToken === undefined) {
308
- return undefined;
309
- }
310
- pageToken = raw.nextPageToken;
311
289
  }
312
- return undefined;
313
- }));
290
+ // `complete` is false exactly when another page is waiting.
291
+ if (raw.complete !== false || raw.nextPageToken === undefined) {
292
+ return undefined;
293
+ }
294
+ pageToken = raw.nextPageToken;
295
+ }
296
+ return undefined;
314
297
  });
315
298
  }
316
299
  /**
317
300
  * Resolve upload instructions for one attempt. A response without a URL
318
301
  * reports that the file cannot use the single-part upload path.
319
302
  */
320
- function presignUploads(files, specs) {
321
- return __awaiter(this, void 0, void 0, function* () {
322
- var _a;
323
- if (files.wire === "flush") {
324
- const response = yield flushPost(options, "/flush", {
325
- store: files.store,
326
- ops: specs.map(spec => (Object.assign({ op: "put", path: spec.key, sha: createHash("sha256").update(spec.body).digest("hex"), size: spec.body.byteLength }, spec.precondition))),
327
- });
328
- // Index-aligned with the request ops, entries without a `url` included:
329
- // a refused op (oversize) must keep its slot so the by-path/positional
330
- // instruction matching below cannot hand its sibling's presign to it,
331
- // and the missing url surfaces as that key's own error.
332
- return {
333
- files: ((_a = response.ops) !== null && _a !== void 0 ? _a : []).map(op => (Object.assign(Object.assign({ path: op.path }, (typeof op.url === "string" && op.url !== "" ? { url: op.url } : {})), { headers: op.headers }))),
334
- };
335
- }
336
- return yield storePost(options, files.path("/upload"), {
337
- files: specs.map(spec => (Object.assign({ path: spec.key, sha: createHash("sha256").update(spec.body).digest("hex"), size: spec.body.byteLength }, spec.precondition))),
303
+ async function presignUploads(files, specs) {
304
+ if (files.wire === "flush") {
305
+ const response = await flushPost(options, "/flush", {
306
+ store: files.store,
307
+ ops: specs.map(spec => ({
308
+ op: "put",
309
+ path: spec.key,
310
+ sha: createHash("sha256").update(spec.body).digest("hex"),
311
+ size: spec.body.byteLength,
312
+ ...spec.precondition,
313
+ })),
338
314
  });
315
+ // Index-aligned with the request ops, entries without a `url` included:
316
+ // a refused op (oversize) must keep its slot so the by-path/positional
317
+ // instruction matching below cannot hand its sibling's presign to it,
318
+ // and the missing url surfaces as that key's own error.
319
+ return {
320
+ files: (response.ops ?? []).map(op => ({
321
+ path: op.path,
322
+ ...(typeof op.url === "string" && op.url !== "" ? { url: op.url } : {}),
323
+ headers: op.headers,
324
+ })),
325
+ };
326
+ }
327
+ return await storePost(options, files.path("/upload"), {
328
+ files: specs.map(spec => ({
329
+ path: spec.key,
330
+ sha: createHash("sha256").update(spec.body).digest("hex"),
331
+ size: spec.body.byteLength,
332
+ ...spec.precondition,
333
+ })),
339
334
  });
340
335
  }
341
336
  /**
@@ -344,56 +339,52 @@ export function cursorHostedFiles(options = {}) {
344
339
  * disturbs its batch siblings. Resolving the instructions is shared, so
345
340
  * that request failing rejects the whole attempt.
346
341
  */
347
- function attemptUploads(files, specs) {
348
- return __awaiter(this, void 0, void 0, function* () {
349
- const presigned = yield presignUploads(files, specs);
350
- return yield Promise.all(specs.map((spec, index) => __awaiter(this, void 0, void 0, function* () {
351
- var _a, _b;
352
- var _c, _d;
353
- // Match by path, falling back to position for servers that answer
354
- // in request order without echoing the path.
355
- const instruction = (_c = (_a = presigned.files) === null || _a === void 0 ? void 0 : _a.find(file => file.path === spec.key)) !== null && _c !== void 0 ? _c : (_b = presigned.files) === null || _b === void 0 ? void 0 : _b[index];
356
- if ((instruction === null || instruction === void 0 ? void 0 : instruction.url) === undefined) {
357
- // Files past the single-part threshold come back with a multipart
358
- // plan instead of a url; this backend does not implement multipart.
342
+ async function attemptUploads(files, specs) {
343
+ const presigned = await presignUploads(files, specs);
344
+ return await Promise.all(specs.map(async (spec, index) => {
345
+ // Match by path, falling back to position for servers that answer
346
+ // in request order without echoing the path.
347
+ const instruction = presigned.files?.find(file => file.path === spec.key) ?? presigned.files?.[index];
348
+ if (instruction?.url === undefined) {
349
+ // Files past the single-part threshold come back with a multipart
350
+ // plan instead of a url; this backend does not implement multipart.
351
+ return {
352
+ status: "error",
353
+ error: new Error(`cursorHostedFiles: no single-part upload url for "${spec.key}" (too large?)`),
354
+ };
355
+ }
356
+ try {
357
+ const response = await resolveCursorApiFetch(options)(assertPresignedUrlSafe(options, instruction.url), {
358
+ method: "PUT",
359
+ headers: instruction.headers ?? {},
360
+ // A view over bytes is a valid fetch body; the DOM lib types
361
+ // are narrower than the runtime, and copying into a Blob would
362
+ // double the memory for every upload.
363
+ body: spec.body,
364
+ // A redirect would re-send the body somewhere the presign did
365
+ // not authorize.
366
+ redirect: "manual",
367
+ });
368
+ if (response.status === 412) {
369
+ observedEtags.delete(spec.key);
370
+ return { status: "conflict" };
371
+ }
372
+ if (!response.ok) {
359
373
  return {
360
374
  status: "error",
361
- error: new Error(`cursorHostedFiles: no single-part upload url for "${spec.key}" (too large?)`),
375
+ error: new Error(`cursorHostedFiles: upload of "${spec.key}" failed (HTTP ${response.status})`),
362
376
  };
363
377
  }
364
- try {
365
- const response = yield resolveCursorApiFetch(options)(assertPresignedUrlSafe(options, instruction.url), {
366
- method: "PUT",
367
- headers: (_d = instruction.headers) !== null && _d !== void 0 ? _d : {},
368
- // A view over bytes is a valid fetch body; the DOM lib types
369
- // are narrower than the runtime, and copying into a Blob would
370
- // double the memory for every upload.
371
- body: spec.body,
372
- // A redirect would re-send the body somewhere the presign did
373
- // not authorize.
374
- redirect: "manual",
375
- });
376
- if (response.status === 412) {
377
- observedEtags.delete(spec.key);
378
- return { status: "conflict" };
379
- }
380
- if (!response.ok) {
381
- return {
382
- status: "error",
383
- error: new Error(`cursorHostedFiles: upload of "${spec.key}" failed (HTTP ${response.status})`),
384
- };
385
- }
386
- const etag = normalizeEtag(response.headers.get("etag"));
387
- if (etag !== undefined) {
388
- rememberEtag(spec.key, etag);
389
- }
390
- return { status: "ok", result: etag === undefined ? {} : { etag } };
391
- }
392
- catch (error) {
393
- return { status: "error", error };
378
+ const etag = normalizeEtag(response.headers.get("etag"));
379
+ if (etag !== undefined) {
380
+ rememberEtag(spec.key, etag);
394
381
  }
395
- })));
396
- });
382
+ return { status: "ok", result: etag === undefined ? {} : { etag } };
383
+ }
384
+ catch (error) {
385
+ return { status: "error", error };
386
+ }
387
+ }));
397
388
  }
398
389
  /**
399
390
  * The full single-key write flow: precondition resolution, one shared
@@ -401,46 +392,43 @@ export function cursorHostedFiles(options = {}) {
401
392
  * `put` promises — including the one statKey-and-retry when an optimistic
402
393
  * create loses to an existing object.
403
394
  */
404
- function settlePut(files, entry, first) {
405
- return __awaiter(this, void 0, void 0, function* () {
406
- var _a;
407
- if (first.status === "error") {
408
- throw first.error;
409
- }
410
- if (first.status === "ok") {
411
- return first.result;
412
- }
413
- // Conflict. Explicit `ifMatch` (etag or create-only) and cached-etag
414
- // writes are single-attempt: the lost precondition is the caller's.
415
- const requested = (_a = entry.options) === null || _a === void 0 ? void 0 : _a.ifMatch;
416
- if (requested !== undefined) {
417
- throw new FileConflictError(entry.key, {
418
- storedEtag: requested !== null && requested !== void 0 ? requested : undefined,
419
- });
420
- }
421
- if (entry.cachedEtagUsed === true) {
422
- // Someone else wrote between our etag observation and this PUT.
423
- throw new FileConflictError(entry.key, { storedEtag: entry.staleEtag });
424
- }
425
- // The optimistic create lost: learn the current etag once and replace.
426
- const found = yield statKey(entry.key);
427
- if ((found === null || found === void 0 ? void 0 : found.etag) === undefined) {
428
- // Existed a moment ago (the create lost) but stat sees nothing: a
429
- // delete raced this write. Surface the conflict; a retry from the
430
- // caller lands on the fresh create-only path.
431
- throw new FileConflictError(entry.key, {});
432
- }
433
- const [replaced] = yield attemptUploads(files, [
434
- { key: entry.key, body: entry.body, precondition: { etag: found.etag } },
435
- ]);
436
- if (replaced === undefined || replaced.status === "conflict") {
437
- throw new FileConflictError(entry.key, { storedEtag: found === null || found === void 0 ? void 0 : found.etag });
438
- }
439
- if (replaced.status === "error") {
440
- throw replaced.error;
441
- }
442
- return replaced.result;
443
- });
395
+ async function settlePut(files, entry, first) {
396
+ if (first.status === "error") {
397
+ throw first.error;
398
+ }
399
+ if (first.status === "ok") {
400
+ return first.result;
401
+ }
402
+ // Conflict. Explicit `ifMatch` (etag or create-only) and cached-etag
403
+ // writes are single-attempt: the lost precondition is the caller's.
404
+ const requested = entry.options?.ifMatch;
405
+ if (requested !== undefined) {
406
+ throw new FileConflictError(entry.key, {
407
+ storedEtag: requested ?? undefined,
408
+ });
409
+ }
410
+ if (entry.cachedEtagUsed === true) {
411
+ // Someone else wrote between our etag observation and this PUT.
412
+ throw new FileConflictError(entry.key, { storedEtag: entry.staleEtag });
413
+ }
414
+ // The optimistic create lost: learn the current etag once and replace.
415
+ const found = await statKey(entry.key);
416
+ if (found?.etag === undefined) {
417
+ // Existed a moment ago (the create lost) but stat sees nothing: a
418
+ // delete raced this write. Surface the conflict; a retry from the
419
+ // caller lands on the fresh create-only path.
420
+ throw new FileConflictError(entry.key, {});
421
+ }
422
+ const [replaced] = await attemptUploads(files, [
423
+ { key: entry.key, body: entry.body, precondition: { etag: found.etag } },
424
+ ]);
425
+ if (replaced === undefined || replaced.status === "conflict") {
426
+ throw new FileConflictError(entry.key, { storedEtag: found?.etag });
427
+ }
428
+ if (replaced.status === "error") {
429
+ throw replaced.error;
430
+ }
431
+ return replaced.result;
444
432
  }
445
433
  /**
446
434
  * Precondition for a write, and whether it came from the etag cache (a
@@ -448,8 +436,7 @@ export function cursorHostedFiles(options = {}) {
448
436
  * one stat-and-retry).
449
437
  */
450
438
  function preconditionFor(entry) {
451
- var _a;
452
- const requested = (_a = entry.options) === null || _a === void 0 ? void 0 : _a.ifMatch;
439
+ const requested = entry.options?.ifMatch;
453
440
  // The store rejects unconditional writes, so every put carries a
454
441
  // precondition. `null` is create-only and an explicit etag is a caller
455
442
  // assertion.
@@ -477,269 +464,266 @@ export function cursorHostedFiles(options = {}) {
477
464
  // No local copy: bytes live in the store, so `materializedPath()` is
478
465
  // `undefined` and the harness reaches files through `host.files`.
479
466
  capabilities: { etags: true },
480
- put(key, body, putOptions) {
481
- return __awaiter(this, void 0, void 0, function* () {
482
- return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
483
- const entry = { key, body, options: putOptions };
484
- const resolved = preconditionFor(entry);
485
- const [first] = yield attemptUploads(files, [
486
- { key, body, precondition: resolved.precondition },
487
- ]);
488
- if (first === undefined) {
489
- throw new Error(`cursorHostedFiles: upload of "${key}" vanished`);
490
- }
491
- return yield settlePut(files, Object.assign(Object.assign({}, entry), { cachedEtagUsed: resolved.cachedEtagUsed, staleEtag: resolved.staleEtag }), first);
492
- }));
467
+ async put(key, body, putOptions) {
468
+ return await withFiles(async (files) => {
469
+ const entry = { key, body, options: putOptions };
470
+ const resolved = preconditionFor(entry);
471
+ const [first] = await attemptUploads(files, [
472
+ { key, body, precondition: resolved.precondition },
473
+ ]);
474
+ if (first === undefined) {
475
+ throw new Error(`cursorHostedFiles: upload of "${key}" vanished`);
476
+ }
477
+ return await settlePut(files, {
478
+ ...entry,
479
+ cachedEtagUsed: resolved.cachedEtagUsed,
480
+ staleEtag: resolved.staleEtag,
481
+ }, first);
493
482
  });
494
483
  },
495
- putMany(entries) {
496
- return __awaiter(this, void 0, void 0, function* () {
497
- if (entries.length === 0) {
498
- return [];
484
+ async putMany(entries) {
485
+ if (entries.length === 0) {
486
+ return [];
487
+ }
488
+ return await withFiles(async (files) => {
489
+ const resolved = entries.map(entry => ({
490
+ entry,
491
+ ...preconditionFor(entry),
492
+ }));
493
+ let firsts;
494
+ try {
495
+ // One presign call for the whole batch — the point of putMany.
496
+ firsts = await attemptUploads(files, resolved.map(({ entry, precondition }) => ({
497
+ key: entry.key,
498
+ body: entry.body,
499
+ precondition,
500
+ })));
499
501
  }
500
- return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
501
- const resolved = entries.map(entry => (Object.assign({ entry }, preconditionFor(entry))));
502
- let firsts;
503
- try {
504
- // One presign call for the whole batch — the point of putMany.
505
- firsts = yield attemptUploads(files, resolved.map(({ entry, precondition }) => ({
506
- key: entry.key,
507
- body: entry.body,
508
- precondition,
509
- })));
510
- }
511
- catch (error) {
512
- // The shared presign failed: every entry failed the same way.
513
- return entries.map(() => ({
502
+ catch (error) {
503
+ // The shared presign failed: every entry failed the same way.
504
+ return entries.map(() => ({
505
+ status: "rejected",
506
+ reason: error,
507
+ }));
508
+ }
509
+ return await Promise.all(resolved.map(async ({ entry, cachedEtagUsed, staleEtag }, index) => {
510
+ const first = firsts[index];
511
+ if (first === undefined) {
512
+ return {
514
513
  status: "rejected",
515
- reason: error,
516
- }));
514
+ reason: new Error(`cursorHostedFiles: upload of "${entry.key}" vanished`),
515
+ };
517
516
  }
518
- return yield Promise.all(resolved.map((_a, index_1) => __awaiter(this, [_a, index_1], void 0, function* ({ entry, cachedEtagUsed, staleEtag }, index) {
519
- const first = firsts[index];
520
- if (first === undefined) {
521
- return {
522
- status: "rejected",
523
- reason: new Error(`cursorHostedFiles: upload of "${entry.key}" vanished`),
524
- };
525
- }
526
- try {
527
- return {
528
- status: "fulfilled",
529
- value: yield settlePut(files, Object.assign(Object.assign({}, entry), { cachedEtagUsed, staleEtag }), first),
530
- };
531
- }
532
- catch (error) {
533
- return { status: "rejected", reason: error };
534
- }
535
- })));
536
- }));
537
- });
538
- },
539
- get(key) {
540
- return __awaiter(this, void 0, void 0, function* () {
541
- return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
542
- var _a, _b;
543
- // A path with no live object is absent, not a storage failure.
544
- let presigned;
545
517
  try {
546
- presigned =
547
- files.wire === "flush"
548
- ? yield flushPost(options, "/read", {
549
- store: files.store,
550
- paths: [key],
551
- })
552
- : yield storePost(options, files.path("/download"), {
553
- paths: [key],
554
- });
518
+ return {
519
+ status: "fulfilled",
520
+ value: await settlePut(files, { ...entry, cachedEtagUsed, staleEtag }, first),
521
+ };
555
522
  }
556
523
  catch (error) {
557
- if (error instanceof StoreApiError && error.status === 404) {
558
- return undefined;
559
- }
560
- throw error;
561
- }
562
- const url = (_b = (_a = presigned.files) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url;
563
- if (url === undefined) {
564
- return undefined;
524
+ return { status: "rejected", reason: error };
565
525
  }
566
- return yield downloadPresigned(key, url);
567
526
  }));
568
527
  });
569
528
  },
570
- getMany(keys) {
571
- return __awaiter(this, void 0, void 0, function* () {
572
- if (keys.length === 0) {
573
- return [];
574
- }
575
- const bodies = yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
576
- var _a;
577
- if (files.wire !== "flush") {
578
- // This transport cannot distinguish one missing key from a failed
579
- // batch, so preserve exact absence semantics with bounded reads.
580
- return yield mapBounded([...keys], GET_MANY_DOWNLOAD_CONCURRENCY, (key) => __awaiter(this, void 0, void 0, function* () {
581
- var _a, _b;
582
- const presigned = yield storePost(options, files.path("/download"), { paths: [key] }).catch((error) => {
583
- if (error instanceof StoreApiError && error.status === 404) {
584
- return undefined;
585
- }
586
- throw error;
587
- });
588
- const url = (_b = (_a = presigned === null || presigned === void 0 ? void 0 : presigned.files) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url;
589
- if (url === undefined) {
590
- return undefined;
591
- }
592
- return yield downloadPresigned(key, url);
593
- }));
594
- }
595
- const urls = new Map();
596
- for (let from = 0; from < keys.length; from += READ_PRESIGN_BATCH_MAX) {
597
- const chunk = keys.slice(from, from + READ_PRESIGN_BATCH_MAX);
598
- let presigned;
599
- try {
600
- presigned = yield flushPost(options, "/read", {
529
+ async get(key) {
530
+ return await withFiles(async (files) => {
531
+ // A path with no live object is absent, not a storage failure.
532
+ let presigned;
533
+ try {
534
+ presigned =
535
+ files.wire === "flush"
536
+ ? await flushPost(options, "/read", {
601
537
  store: files.store,
602
- paths: chunk,
538
+ paths: [key],
539
+ })
540
+ : await storePost(options, files.path("/download"), {
541
+ paths: [key],
603
542
  });
604
- }
605
- catch (error) {
606
- if (error instanceof StoreApiError && error.status === 404) {
607
- // The read route never 404s per path (absent paths are
608
- // omitted entries); a 404 is the store itself — not
609
- // provisioned, or deleted under us — which get() reads as
610
- // absence for every key.
611
- return keys.map(() => undefined);
612
- }
613
- throw error;
614
- }
615
- for (const entry of (_a = presigned.files) !== null && _a !== void 0 ? _a : []) {
616
- if (entry.path !== undefined && entry.url !== undefined) {
617
- urls.set(entry.path, entry.url);
618
- }
619
- }
543
+ }
544
+ catch (error) {
545
+ if (error instanceof StoreApiError && error.status === 404) {
546
+ return undefined;
620
547
  }
621
- return yield mapBounded([...keys], GET_MANY_DOWNLOAD_CONCURRENCY, (key) => __awaiter(this, void 0, void 0, function* () {
622
- var _a, _b;
623
- const url = urls.get(key);
624
- if (url !== undefined) {
625
- return yield downloadPresigned(key, url);
626
- }
627
- // A miss in the batch is NOT yet a definitive absence: the
628
- // server echoes each path *normalized* (trimmed, backslashes
629
- // folded, empty/"." segments dropped), so a key whose
630
- // normalized form differs from what was sent never matches the
631
- // echo even though its object exists. `get()` is immune (it
632
- // reads the response positionally), so settle every batch miss
633
- // through the single-path read — keeping getMany's absence
634
- // semantics byte-identical to get()'s. Genuine absences pay one
635
- // extra request; every batch caller reads keys it just listed
636
- // or was told exist, so real misses are rare (delete races,
637
- // store loss).
638
- const presigned = yield flushPost(options, "/read", {
639
- store: files.store,
640
- paths: [key],
641
- }).catch((error) => {
642
- // Store-level 404 (deleted between the batch and this read):
643
- // absence, same as get().
548
+ throw error;
549
+ }
550
+ const url = presigned.files?.[0]?.url;
551
+ if (url === undefined) {
552
+ return undefined;
553
+ }
554
+ return await downloadPresigned(key, url);
555
+ });
556
+ },
557
+ async getMany(keys) {
558
+ if (keys.length === 0) {
559
+ return [];
560
+ }
561
+ const bodies = await withFiles(async (files) => {
562
+ if (files.wire !== "flush") {
563
+ // This transport cannot distinguish one missing key from a failed
564
+ // batch, so preserve exact absence semantics with bounded reads.
565
+ return await mapBounded([...keys], GET_MANY_DOWNLOAD_CONCURRENCY, async (key) => {
566
+ const presigned = await storePost(options, files.path("/download"), { paths: [key] }).catch((error) => {
644
567
  if (error instanceof StoreApiError && error.status === 404) {
645
568
  return undefined;
646
569
  }
647
570
  throw error;
648
571
  });
649
- const singleUrl = (_b = (_a = presigned === null || presigned === void 0 ? void 0 : presigned.files) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url;
650
- if (singleUrl === undefined) {
572
+ const url = presigned?.files?.[0]?.url;
573
+ if (url === undefined) {
651
574
  return undefined;
652
575
  }
653
- return yield downloadPresigned(key, singleUrl);
654
- }));
655
- }));
656
- return bodies;
657
- });
658
- },
659
- delete(key) {
660
- return __awaiter(this, void 0, void 0, function* () {
661
- const handled = yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
662
- var _a;
663
- var _b;
664
- if (files.wire !== "flush") {
665
- return false;
576
+ return await downloadPresigned(key, url);
577
+ });
578
+ }
579
+ const urls = new Map();
580
+ for (let from = 0; from < keys.length; from += READ_PRESIGN_BATCH_MAX) {
581
+ const chunk = keys.slice(from, from + READ_PRESIGN_BATCH_MAX);
582
+ let presigned;
583
+ try {
584
+ presigned = await flushPost(options, "/read", {
585
+ store: files.store,
586
+ paths: chunk,
587
+ });
588
+ }
589
+ catch (error) {
590
+ if (error instanceof StoreApiError && error.status === 404) {
591
+ // The read route never 404s per path (absent paths are
592
+ // omitted entries); a 404 is the store itself — not
593
+ // provisioned, or deleted under us — which get() reads as
594
+ // absence for every key.
595
+ return keys.map(() => undefined);
596
+ }
597
+ throw error;
666
598
  }
667
- // With an observed etag the flush delete is If-Match on that version.
668
- // Without one, the server tombstones whatever live object occupies
669
- // the key (no directory walk here) and an absent key settles as
670
- // `already_deleted`.
671
- const cached = observedEtags.get(key);
672
- const response = yield flushPost(options, "/flush", {
599
+ for (const entry of presigned.files ?? []) {
600
+ if (entry.path !== undefined && entry.url !== undefined) {
601
+ urls.set(entry.path, entry.url);
602
+ }
603
+ }
604
+ }
605
+ return await mapBounded([...keys], GET_MANY_DOWNLOAD_CONCURRENCY, async (key) => {
606
+ const url = urls.get(key);
607
+ if (url !== undefined) {
608
+ return await downloadPresigned(key, url);
609
+ }
610
+ // A miss in the batch is NOT yet a definitive absence: the
611
+ // server echoes each path *normalized* (trimmed, backslashes
612
+ // folded, empty/"." segments dropped), so a key whose
613
+ // normalized form differs from what was sent never matches the
614
+ // echo even though its object exists. `get()` is immune (it
615
+ // reads the response positionally), so settle every batch miss
616
+ // through the single-path read — keeping getMany's absence
617
+ // semantics byte-identical to get()'s. Genuine absences pay one
618
+ // extra request; every batch caller reads keys it just listed
619
+ // or was told exist, so real misses are rare (delete races,
620
+ // store loss).
621
+ const presigned = await flushPost(options, "/read", {
673
622
  store: files.store,
674
- ops: [
675
- Object.assign({ op: "delete", path: key }, (cached === undefined ? {} : { etag: cached })),
676
- ],
623
+ paths: [key],
624
+ }).catch((error) => {
625
+ // Store-level 404 (deleted between the batch and this read):
626
+ // absence, same as get().
627
+ if (error instanceof StoreApiError && error.status === 404) {
628
+ return undefined;
629
+ }
630
+ throw error;
677
631
  });
678
- const outcome = (_a = response.ops) === null || _a === void 0 ? void 0 : _a[0];
679
- if ((outcome === null || outcome === void 0 ? void 0 : outcome.status) === "conflict") {
680
- observedEtags.delete(key);
681
- throw new FileConflictError(key, Object.assign({}, (outcome.etag === undefined
682
- ? {}
683
- : { storedEtag: (_b = normalizeEtag(outcome.etag)) !== null && _b !== void 0 ? _b : outcome.etag })));
632
+ const singleUrl = presigned?.files?.[0]?.url;
633
+ if (singleUrl === undefined) {
634
+ return undefined;
684
635
  }
685
- observedEtags.delete(key);
686
- return true;
687
- }));
688
- if (handled) {
689
- return;
636
+ return await downloadPresigned(key, singleUrl);
637
+ });
638
+ });
639
+ return bodies;
640
+ },
641
+ async delete(key) {
642
+ const handled = await withFiles(async (files) => {
643
+ if (files.wire !== "flush") {
644
+ return false;
690
645
  }
691
- if (observedEtags.get(key) === undefined) {
692
- // Deletes are conditional too, so learn the current etag first. A key
693
- // we have never seen is already absent as far as the caller cares.
694
- const found = yield statKey(key);
695
- if ((found === null || found === void 0 ? void 0 : found.etag) === undefined) {
696
- return;
697
- }
646
+ // With an observed etag the flush delete is If-Match on that version.
647
+ // Without one, the server tombstones whatever live object occupies
648
+ // the key (no directory walk here) and an absent key settles as
649
+ // `already_deleted`.
650
+ const cached = observedEtags.get(key);
651
+ const response = await flushPost(options, "/flush", {
652
+ store: files.store,
653
+ ops: [
654
+ {
655
+ op: "delete",
656
+ path: key,
657
+ ...(cached === undefined ? {} : { etag: cached }),
658
+ },
659
+ ],
660
+ });
661
+ const outcome = response.ops?.[0];
662
+ if (outcome?.status === "conflict") {
663
+ observedEtags.delete(key);
664
+ throw new FileConflictError(key, {
665
+ ...(outcome.etag === undefined
666
+ ? {}
667
+ : { storedEtag: normalizeEtag(outcome.etag) ?? outcome.etag }),
668
+ });
698
669
  }
699
- const etag = observedEtags.get(key);
700
- if (etag === undefined) {
670
+ observedEtags.delete(key);
671
+ return true;
672
+ });
673
+ if (handled) {
674
+ return;
675
+ }
676
+ if (observedEtags.get(key) === undefined) {
677
+ // Deletes are conditional too, so learn the current etag first. A key
678
+ // we have never seen is already absent as far as the caller cares.
679
+ const found = await statKey(key);
680
+ if (found?.etag === undefined) {
701
681
  return;
702
682
  }
703
- yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
704
- var _a;
705
- var _b, _c, _d;
706
- if (files.wire === "flush") {
707
- // The protocol pin appeared between the two withFiles calls; the
708
- // cached etag is enough for the conditional flush delete.
709
- const response = yield flushPost(options, "/flush", {
710
- store: files.store,
711
- ops: [{ op: "delete", path: key, etag }],
712
- });
713
- const outcome = (_a = response.ops) === null || _a === void 0 ? void 0 : _a[0];
714
- if ((outcome === null || outcome === void 0 ? void 0 : outcome.status) === "conflict") {
715
- observedEtags.delete(key);
716
- throw new FileConflictError(key, Object.assign({}, (outcome.etag === undefined
717
- ? {}
718
- : { storedEtag: (_b = normalizeEtag(outcome.etag)) !== null && _b !== void 0 ? _b : outcome.etag })));
719
- }
720
- return;
721
- }
722
- const raw = yield storePost(options, files.path("/delete"), {
723
- files: [{ path: key, etag }],
683
+ }
684
+ const etag = observedEtags.get(key);
685
+ if (etag === undefined) {
686
+ return;
687
+ }
688
+ await withFiles(async (files) => {
689
+ if (files.wire === "flush") {
690
+ // The protocol pin appeared between the two withFiles calls; the
691
+ // cached etag is enough for the conditional flush delete.
692
+ const response = await flushPost(options, "/flush", {
693
+ store: files.store,
694
+ ops: [{ op: "delete", path: key, etag }],
724
695
  });
725
- // The API answers 200 with a per-file status, so a lost race would look
726
- // like success unless the outcome is read.
727
- const outcome = ((_c = raw.files) !== null && _c !== void 0 ? _c : []).find(entry => entry.path === key);
728
- if ((outcome === null || outcome === void 0 ? void 0 : outcome.status) === "conflict") {
696
+ const outcome = response.ops?.[0];
697
+ if (outcome?.status === "conflict") {
729
698
  observedEtags.delete(key);
730
- throw new FileConflictError(key, Object.assign({}, (outcome.etag === undefined
731
- ? {}
732
- : { storedEtag: (_d = normalizeEtag(outcome.etag)) !== null && _d !== void 0 ? _d : outcome.etag })));
699
+ throw new FileConflictError(key, {
700
+ ...(outcome.etag === undefined
701
+ ? {}
702
+ : { storedEtag: normalizeEtag(outcome.etag) ?? outcome.etag }),
703
+ });
733
704
  }
734
- }));
735
- observedEtags.delete(key);
705
+ return;
706
+ }
707
+ const raw = await storePost(options, files.path("/delete"), {
708
+ files: [{ path: key, etag }],
709
+ });
710
+ // The API answers 200 with a per-file status, so a lost race would look
711
+ // like success unless the outcome is read.
712
+ const outcome = (raw.files ?? []).find(entry => entry.path === key);
713
+ if (outcome?.status === "conflict") {
714
+ observedEtags.delete(key);
715
+ throw new FileConflictError(key, {
716
+ ...(outcome.etag === undefined
717
+ ? {}
718
+ : { storedEtag: normalizeEtag(outcome.etag) ?? outcome.etag }),
719
+ });
720
+ }
736
721
  });
722
+ observedEtags.delete(key);
737
723
  },
738
724
  list: listEntries,
739
- stat(key) {
740
- return __awaiter(this, void 0, void 0, function* () {
741
- return yield statKey(key);
742
- });
725
+ async stat(key) {
726
+ return await statKey(key);
743
727
  },
744
728
  };
745
729
  }
@@ -755,7 +739,7 @@ function assertPresignedUrlSafe(options, raw) {
755
739
  try {
756
740
  url = new URL(raw);
757
741
  }
758
- catch (_a) {
742
+ catch {
759
743
  throw new Error("cursorHostedFiles: presigned URL is not a valid URL");
760
744
  }
761
745
  if (url.protocol === "https:" &&
@@ -777,56 +761,53 @@ function assertPresignedUrlSafe(options, raw) {
777
761
  * of silently writing to another location.
778
762
  */
779
763
  function resolveStoreSourceId(options) {
780
- var _a, _b;
781
- var _c, _d;
782
- const id = (_b = ((_d = (_c = (_a = options.resolveStoreSourceId) === null || _a === void 0 ? void 0 : _a.call(options)) !== null && _c !== void 0 ? _c : options.storeSourceId) !== null && _d !== void 0 ? _d : resolveDeploymentStoreSourceIdSync(process.env))) === null || _b === void 0 ? void 0 : _b.trim();
764
+ const id = (options.resolveStoreSourceId?.() ??
765
+ options.storeSourceId ??
766
+ resolveDeploymentStoreSourceIdSync(process.env))?.trim();
783
767
  if (id === undefined || id === "") {
784
768
  throw new Error(`cursorHostedFiles requires ${AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR} (set on Cursor-managed deployments)`);
785
769
  }
786
770
  return id;
787
771
  }
788
- const DEV_PRESIGN_HOSTS = new Set(((_a = process.env.CURSOR_HOSTED_FILES_DEV_PRESIGN_HOSTS) !== null && _a !== void 0 ? _a : "")
772
+ const DEV_PRESIGN_HOSTS = new Set((process.env.CURSOR_HOSTED_FILES_DEV_PRESIGN_HOSTS ?? "")
789
773
  .split(",")
790
774
  .map(host => host.trim().toLowerCase())
791
775
  .filter(host => host.length > 0));
792
776
  /** Send a file request with the deployment pod credential. */
793
- function storePost(options, path, body) {
794
- return __awaiter(this, void 0, void 0, function* () {
795
- return yield postJson(options, `${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`, body);
796
- });
777
+ async function storePost(options, path, body) {
778
+ return await postJson(options, `${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`, body);
797
779
  }
798
- function storeGet(options, path) {
799
- return __awaiter(this, void 0, void 0, function* () {
800
- return yield sendJson(options, `${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`, "GET");
801
- });
780
+ async function storeGet(options, path) {
781
+ return await sendJson(options, `${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`, "GET");
802
782
  }
803
783
  /** Send a batched file request with the deployment pod credential. */
804
- function flushPost(options, path, body) {
805
- return __awaiter(this, void 0, void 0, function* () {
806
- return yield postJson(options, `${resolveCursorApiBaseUrl(options)}${AGENTSDK_STORE_PATH}${path}`, body);
807
- });
784
+ async function flushPost(options, path, body) {
785
+ return await postJson(options, `${resolveCursorApiBaseUrl(options)}${AGENTSDK_STORE_PATH}${path}`, body);
808
786
  }
809
- function postJson(options, url, body) {
810
- return __awaiter(this, void 0, void 0, function* () {
811
- return yield sendJson(options, url, "POST", body);
812
- });
787
+ async function postJson(options, url, body) {
788
+ return await sendJson(options, url, "POST", body);
813
789
  }
814
- function sendJson(options, url, method, body) {
815
- return __awaiter(this, void 0, void 0, function* () {
816
- const response = yield resolveCursorApiFetch(options)(url, Object.assign({ method, headers: Object.assign({ Authorization: `Bearer ${resolveCursorApiKey(options)}` }, (body === undefined ? {} : { "Content-Type": "application/json" })) }, (body === undefined ? {} : { body: JSON.stringify(body) })));
817
- const text = yield response.text();
818
- let parsed;
819
- try {
820
- parsed = text.length === 0 ? {} : JSON.parse(text);
821
- }
822
- catch (_a) {
823
- throw new Error(`cursorHostedFiles ${url} returned non-JSON (${response.status})`);
824
- }
825
- if (!response.ok) {
826
- throw new StoreApiError(response.status, `cursorHostedFiles ${url}: ${describeError(parsed, response.status)}`);
827
- }
828
- return parsed;
790
+ async function sendJson(options, url, method, body) {
791
+ const response = await resolveCursorApiFetch(options)(url, {
792
+ method,
793
+ headers: {
794
+ Authorization: `Bearer ${resolveCursorApiKey(options)}`,
795
+ ...(body === undefined ? {} : { "Content-Type": "application/json" }),
796
+ },
797
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
829
798
  });
799
+ const text = await response.text();
800
+ let parsed;
801
+ try {
802
+ parsed = text.length === 0 ? {} : JSON.parse(text);
803
+ }
804
+ catch {
805
+ throw new Error(`cursorHostedFiles ${url} returned non-JSON (${response.status})`);
806
+ }
807
+ if (!response.ok) {
808
+ throw new StoreApiError(response.status, `cursorHostedFiles ${url}: ${describeError(parsed, response.status)}`);
809
+ }
810
+ return parsed;
830
811
  }
831
812
  /**
832
813
  * A non-2xx answer from the files API, carrying the status so a caller can