@cursor/bdk 0.2.3 → 0.2.5

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 (760) hide show
  1. package/README.md +76 -1154
  2. package/dist/bin/agent-serve.js +9 -1
  3. package/dist/channels/slack/attachments.d.ts +2 -1
  4. package/dist/channels/slack/attachments.d.ts.map +1 -1
  5. package/dist/channels/slack/attachments.js +19 -9
  6. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  7. package/dist/channels/slack/dispatch.js +26 -24
  8. package/dist/channels/slack/thread-context.d.ts +21 -11
  9. package/dist/channels/slack/thread-context.d.ts.map +1 -1
  10. package/dist/channels/slack/thread-context.js +75 -27
  11. package/dist/docs/404.html +2 -2
  12. package/dist/docs/assets/{app.BOIHhrKi.js → app.94Iu5dyD.js} +4 -4
  13. package/dist/docs/assets/{building-with-agents.md.-fcjCmJU.js → building-with-agents.md.BPjPFxFg.js} +2 -2
  14. package/dist/docs/assets/{building-with-agents.md.-fcjCmJU.lean.js → building-with-agents.md.BPjPFxFg.lean.js} +1 -1
  15. package/dist/docs/assets/chunks/@localSearchIndexroot.BITLoOQa.js +1 -0
  16. package/dist/docs/assets/chunks/{VPLocalSearchBox.D49zVZqM.js → VPLocalSearchBox.DTKFDlBr.js} +1 -1
  17. package/dist/docs/assets/chunks/{arc.hmjb-sc4.js → arc.DuzwHEeg.js} +1 -1
  18. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.CxEI1KqM.js → architectureDiagram-Q4EWVU46.C6lyhLs0.js} +1 -1
  19. package/dist/docs/assets/chunks/{baseUniq.DHHvBWoV.js → baseUniq.DUNEWlY8.js} +1 -1
  20. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.DnXW-3bu.js → blockDiagram-DXYQGD6D.CXOQGI0O.js} +1 -1
  21. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.e-47O2jM.js → c4Diagram-AHTNJAMY.BYdPE-Oe.js} +1 -1
  22. package/dist/docs/assets/chunks/channel.B46uXH41.js +1 -0
  23. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.3ry4pYXB.js → chunk-4BX2VUAB.YIV9HeX0.js} +1 -1
  24. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.DGIZFRx6.js → chunk-4TB4RGXK.BG80DEOc.js} +1 -1
  25. package/dist/docs/assets/chunks/{chunk-55IACEB6.DKBnqg9U.js → chunk-55IACEB6.BDKJSZQc.js} +1 -1
  26. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.BIU8Ue5k.js → chunk-EDXVE4YY.CtYnQqts.js} +1 -1
  27. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.DP-TFhjI.js → chunk-FMBD7UC4.CityOth-.js} +1 -1
  28. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.Ux0OYj5v.js → chunk-OYMX7WX6.CMD22CQX.js} +1 -1
  29. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BzHMwYox.js → chunk-QZHKN3VN.WWpc3ND0.js} +1 -1
  30. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.D4OGAsSP.js → chunk-YZCP3GAM.BMg-yhj3.js} +1 -1
  31. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.0cmCFsSf.js +1 -0
  32. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.0cmCFsSf.js +1 -0
  33. package/dist/docs/assets/chunks/clone.1vTOFZT1.js +1 -0
  34. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.Jq_7BUNx.js → cose-bilkent-S5V4N54A.Buu_LC5q.js} +1 -1
  35. package/dist/docs/assets/chunks/{dagre-KV5264BT.Di-skR2x.js → dagre-KV5264BT.DW7onj6E.js} +1 -1
  36. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.DeREHIdH.js → diagram-5BDNPKRD.B3NxIbEV.js} +1 -1
  37. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.C7Kcqxro.js → diagram-G4DWMVQ6.BJvN6Vkv.js} +1 -1
  38. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.BK3eohyo.js → diagram-MMDJMWI5.wfRWrexs.js} +1 -1
  39. package/dist/docs/assets/chunks/{diagram-TYMM5635.C6TyymXT.js → diagram-TYMM5635.7QtjSYio.js} +1 -1
  40. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.DYGG-gGx.js → erDiagram-SMLLAGMA.jxPgDH1t.js} +1 -1
  41. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.C9nBcSV4.js → flowDiagram-DWJPFMVM.BhDWA-TO.js} +1 -1
  42. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.wAg_ymsp.js → ganttDiagram-T4ZO3ILL.Ijq8iYKv.js} +1 -1
  43. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.B87j9Oeg.js → gitGraphDiagram-UUTBAWPF.DXpfW4YG.js} +1 -1
  44. package/dist/docs/assets/chunks/{graph.CuFMj31w.js → graph.CoPlssRl.js} +1 -1
  45. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.P_mLGumP.js → infoDiagram-42DDH7IO.eJuv_EOz.js} +1 -1
  46. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DyuL_MsT.js → ishikawaDiagram-UXIWVN3A._OEzenCR.js} +1 -1
  47. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.CtP09IoJ.js → journeyDiagram-VCZTEJTY.CwlTjirB.js} +1 -1
  48. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.BoeSYPZo.js → kanban-definition-6JOO6SKY.DSp_C8cZ.js} +1 -1
  49. package/dist/docs/assets/chunks/{layout.B0lMMtNo.js → layout.Bms9s7uB.js} +1 -1
  50. package/dist/docs/assets/chunks/{linear.HxRBiAFX.js → linear.BjnmB4je.js} +1 -1
  51. package/dist/docs/assets/chunks/{min.BGlFFHwS.js → min.CKkYlMsn.js} +1 -1
  52. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.JyLBD9M8.js → mindmap-definition-QFDTVHPH.T2d0vJ7X.js} +1 -1
  53. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DnSmNZF8.js → pieDiagram-DEJITSTG.DU0RoCvx.js} +1 -1
  54. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.CUCnbfCa.js → quadrantDiagram-34T5L4WZ.9QZjM-x0.js} +1 -1
  55. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.py0IVUn5.js → requirementDiagram-MS252O5E.CZpylJMd.js} +1 -1
  56. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.Bkc-HWYp.js → sankeyDiagram-XADWPNL6.CnFdfW95.js} +1 -1
  57. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.Dqn8Mlv2.js → sequenceDiagram-FGHM5R23.-jC0PP1t.js} +1 -1
  58. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.JikkoQUU.js → stateDiagram-FHFEXIEX.DG7yBRUU.js} +1 -1
  59. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.CbsZcOOu.js +1 -0
  60. package/dist/docs/assets/chunks/{theme.b6HQ6zG_.js → theme.B3O9koXV.js} +2 -2
  61. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.BvpSXiBj.js → timeline-definition-GMOUNBTQ.Bf9u4Ebb.js} +1 -1
  62. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CU7MVnZx.js → vennDiagram-DHZGUBPP.BjhbbYE6.js} +1 -1
  63. package/dist/docs/assets/chunks/{wardley-RL74JXVD.BKwC4ctG.js → wardley-RL74JXVD.DEA21akR.js} +1 -1
  64. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.BfaF6Uhe.js → wardleyDiagram-NUSXRM2D.8fRb4Nb5.js} +1 -1
  65. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.Bg5dcpj4.js → xychartDiagram-5P7HB3ND.DoOP3zZM.js} +1 -1
  66. package/dist/docs/assets/{deployment.md.BJ8i7Q6p.js → deployment.md.BdqTiGdc.js} +5 -5
  67. package/dist/docs/assets/{deployment.md.BJ8i7Q6p.lean.js → deployment.md.BdqTiGdc.lean.js} +1 -1
  68. package/dist/docs/assets/{evals.md.CCAtNcuL.js → evals.md.LRCSn6Ik.js} +2 -2
  69. package/dist/docs/assets/{evals.md.CCAtNcuL.lean.js → evals.md.LRCSn6Ik.lean.js} +1 -1
  70. package/dist/docs/assets/{guides_agent-to-agent.md.CGkicXeB.js → guides_agent-to-agent.md.Cps5NiCV.js} +2 -2
  71. package/dist/docs/assets/{guides_agent-to-agent.md.CGkicXeB.lean.js → guides_agent-to-agent.md.Cps5NiCV.lean.js} +1 -1
  72. package/dist/docs/assets/{guides_bitbucket.md.Cb3LPKt3.js → guides_bitbucket.md.BB6fqD-M.js} +2 -2
  73. package/dist/docs/assets/{guides_bitbucket.md.Cb3LPKt3.lean.js → guides_bitbucket.md.BB6fqD-M.lean.js} +1 -1
  74. package/dist/docs/assets/{guides_cloud-agents.md.BuEkDCwo.js → guides_cloud-agents.md.CWJjS9No.js} +2 -2
  75. package/dist/docs/assets/{guides_cloud-agents.md.BuEkDCwo.lean.js → guides_cloud-agents.md.CWJjS9No.lean.js} +1 -1
  76. package/dist/docs/assets/{guides_convert-automation.md.Ci-Y2iD5.js → guides_convert-automation.md.DMEX9nF-.js} +3 -3
  77. package/dist/docs/assets/{guides_convert-automation.md.Ci-Y2iD5.lean.js → guides_convert-automation.md.DMEX9nF-.lean.js} +1 -1
  78. package/dist/docs/assets/{guides_github.md.Bq9kQU9B.js → guides_github.md.Cr1Xlf-m.js} +3 -3
  79. package/dist/docs/assets/{guides_github.md.Bq9kQU9B.lean.js → guides_github.md.Cr1Xlf-m.lean.js} +1 -1
  80. package/dist/docs/assets/{guides_gitlab.md.BM27P43u.js → guides_gitlab.md.CMpmFi4M.js} +2 -2
  81. package/dist/docs/assets/{guides_gitlab.md.BM27P43u.lean.js → guides_gitlab.md.CMpmFi4M.lean.js} +1 -1
  82. package/dist/docs/assets/{guides_grokbot-agents.md.yxVbSlKA.js → guides_grokbot-agents.md.tD1smFhU.js} +2 -2
  83. package/dist/docs/assets/{guides_grokbot-agents.md.yxVbSlKA.lean.js → guides_grokbot-agents.md.tD1smFhU.lean.js} +1 -1
  84. package/dist/docs/assets/{guides_hooks.md.BWoiNaMq.js → guides_hooks.md.5Ce3NXxZ.js} +2 -2
  85. package/dist/docs/assets/{guides_hooks.md.BWoiNaMq.lean.js → guides_hooks.md.5Ce3NXxZ.lean.js} +1 -1
  86. package/dist/docs/assets/{guides_improve.md.COtL-6ft.js → guides_improve.md.CRrYq22s.js} +2 -2
  87. package/dist/docs/assets/{guides_improve.md.COtL-6ft.lean.js → guides_improve.md.CRrYq22s.lean.js} +1 -1
  88. package/dist/docs/assets/{guides_jev.md.BNDm14Gy.js → guides_jev.md.D7XH4JH3.js} +2 -2
  89. package/dist/docs/assets/{guides_mcp-oauth.md.Cu6mhZ_3.js → guides_mcp-oauth.md.DR3zhC9r.js} +2 -2
  90. package/dist/docs/assets/{guides_mcp-oauth.md.Cu6mhZ_3.lean.js → guides_mcp-oauth.md.DR3zhC9r.lean.js} +1 -1
  91. package/dist/docs/assets/{guides_opentelemetry.md.DLlIB5rv.js → guides_opentelemetry.md.jcPNrQbH.js} +8 -6
  92. package/dist/docs/assets/{guides_opentelemetry.md.DLlIB5rv.lean.js → guides_opentelemetry.md.jcPNrQbH.lean.js} +1 -1
  93. package/dist/docs/assets/{guides_slack.md.diqqXTTm.js → guides_slack.md.Bn-WupSE.js} +8 -8
  94. package/dist/docs/assets/{guides_slack.md.diqqXTTm.lean.js → guides_slack.md.Bn-WupSE.lean.js} +1 -1
  95. package/dist/docs/assets/{guides_webhooks.md.D0furjw0.js → guides_webhooks.md.BBvAm_VF.js} +2 -2
  96. package/dist/docs/assets/{guides_webhooks.md.D0furjw0.lean.js → guides_webhooks.md.BBvAm_VF.lean.js} +1 -1
  97. package/dist/docs/assets/{hillclimbing.md.Biy0m-Qb.js → hillclimbing.md.Dxvd-0gT.js} +2 -2
  98. package/dist/docs/assets/{hillclimbing.md.Biy0m-Qb.lean.js → hillclimbing.md.Dxvd-0gT.lean.js} +1 -1
  99. package/dist/docs/assets/index.md.Dxxr7pFa.js +27 -0
  100. package/dist/docs/assets/{index.md.CVc_oOA3.lean.js → index.md.Dxxr7pFa.lean.js} +1 -1
  101. package/dist/docs/assets/{quickstart.md.CHpHPBUN.js → quickstart.md.BK5gjHM2.js} +2 -2
  102. package/dist/docs/assets/{quickstart.md.CHpHPBUN.lean.js → quickstart.md.BK5gjHM2.lean.js} +1 -1
  103. package/dist/docs/assets/{reference_agent-config.md.DzGI777n.js → reference_agent-config.md.DrtLxWgR.js} +4 -4
  104. package/dist/docs/assets/{reference_agent-config.md.DzGI777n.lean.js → reference_agent-config.md.DrtLxWgR.lean.js} +1 -1
  105. package/dist/docs/assets/{reference_artifacts.md.CQfKq8F2.js → reference_artifacts.md.DLV9MZES.js} +2 -2
  106. package/dist/docs/assets/{reference_artifacts.md.CQfKq8F2.lean.js → reference_artifacts.md.DLV9MZES.lean.js} +1 -1
  107. package/dist/docs/assets/{reference_channels.md.mbNtKCiR.js → reference_channels.md.LbNIJBwd.js} +2 -2
  108. package/dist/docs/assets/{reference_channels.md.mbNtKCiR.lean.js → reference_channels.md.LbNIJBwd.lean.js} +1 -1
  109. package/dist/docs/assets/{reference_cli.md.DgeLTO18.js → reference_cli.md.BsgDqYPh.js} +4 -4
  110. package/dist/docs/assets/{reference_cli.md.DgeLTO18.lean.js → reference_cli.md.BsgDqYPh.lean.js} +1 -1
  111. package/dist/docs/assets/{reference_connections.md.COq--gAm.js → reference_connections.md.Bljpve-y.js} +4 -4
  112. package/dist/docs/assets/{reference_connections.md.COq--gAm.lean.js → reference_connections.md.Bljpve-y.lean.js} +1 -1
  113. package/dist/docs/assets/{reference_evals.md.CJm3uCUm.js → reference_evals.md.D5i8PuXJ.js} +2 -2
  114. package/dist/docs/assets/{reference_evals.md.CJm3uCUm.lean.js → reference_evals.md.D5i8PuXJ.lean.js} +1 -1
  115. package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.js → reference_extensions.md.OUacPetl.js} +5 -4
  116. package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.lean.js → reference_extensions.md.OUacPetl.lean.js} +1 -1
  117. package/dist/docs/assets/{reference_hooks.md.DbthhtIR.js → reference_hooks.md.C5LCJ1R3.js} +2 -2
  118. package/dist/docs/assets/{reference_hooks.md.DbthhtIR.lean.js → reference_hooks.md.C5LCJ1R3.lean.js} +1 -1
  119. package/dist/docs/assets/{reference_http-api.md.BZOvhCqY.js → reference_http-api.md.DbFNOubV.js} +1 -1
  120. package/dist/docs/assets/{reference_instructions.md.Bdwscs4G.js → reference_instructions.md.DrcHZXig.js} +2 -2
  121. package/dist/docs/assets/{reference_instructions.md.Bdwscs4G.lean.js → reference_instructions.md.DrcHZXig.lean.js} +1 -1
  122. package/dist/docs/assets/reference_playground.md.1hx0gcIu.js +1 -0
  123. package/dist/docs/assets/{reference_playground.md.BdQzRJc2.lean.js → reference_playground.md.1hx0gcIu.lean.js} +1 -1
  124. package/dist/docs/assets/{reference_project-layout.md.CpLQ9j4K.js → reference_project-layout.md.C2JMRh7p.js} +2 -2
  125. package/dist/docs/assets/{reference_prompt.md.BQZB4eaV.js → reference_prompt.md.DqPh71XN.js} +3 -3
  126. package/dist/docs/assets/{reference_prompt.md.BQZB4eaV.lean.js → reference_prompt.md.DqPh71XN.lean.js} +1 -1
  127. package/dist/docs/assets/{reference_schedules.md.BVU5EFbz.js → reference_schedules.md.BuJ8fgMa.js} +2 -2
  128. package/dist/docs/assets/{reference_schedules.md.BVU5EFbz.lean.js → reference_schedules.md.BuJ8fgMa.lean.js} +1 -1
  129. package/dist/docs/assets/reference_sessions.md.CM5zo3w4.js +1 -0
  130. package/dist/docs/assets/{reference_sessions.md.DeRUItHD.lean.js → reference_sessions.md.CM5zo3w4.lean.js} +1 -1
  131. package/dist/docs/assets/{reference_skills.md.Cy00QMKS.js → reference_skills.md.C0guGcH0.js} +4 -4
  132. package/dist/docs/assets/{reference_skills.md.Cy00QMKS.lean.js → reference_skills.md.C0guGcH0.lean.js} +1 -1
  133. package/dist/docs/assets/{reference_subagents.md.B8oyeXOI.js → reference_subagents.md.gmPt5J-M.js} +2 -2
  134. package/dist/docs/assets/{reference_subagents.md.B8oyeXOI.lean.js → reference_subagents.md.gmPt5J-M.lean.js} +1 -1
  135. package/dist/docs/assets/{reference_tools.md.hg2Wi5Bq.js → reference_tools.md.v3SXVSs_.js} +2 -2
  136. package/dist/docs/assets/{reference_tools.md.hg2Wi5Bq.lean.js → reference_tools.md.v3SXVSs_.lean.js} +1 -1
  137. package/dist/docs/assets/{templates_agentic-owners.md.BykUiZ8j.js → templates_agentic-owners.md.vtjfwxbf.js} +2 -2
  138. package/dist/docs/assets/{templates_agentic-owners.md.BykUiZ8j.lean.js → templates_agentic-owners.md.vtjfwxbf.lean.js} +1 -1
  139. package/dist/docs/assets/templates_grokbot-agents.md.2sydjFiO.js +5 -0
  140. package/dist/docs/assets/templates_grokbot-agents.md.2sydjFiO.lean.js +1 -0
  141. package/dist/docs/assets/{templates_security-reviewer.md.DXMmKl_o.js → templates_security-reviewer.md.CX9l9bcg.js} +2 -2
  142. package/dist/docs/assets/{templates_security-reviewer.md.DXMmKl_o.lean.js → templates_security-reviewer.md.CX9l9bcg.lean.js} +1 -1
  143. package/dist/docs/assets/{templates_thermo-quality-review.md.Dg1p1MsG.js → templates_thermo-quality-review.md.95qmTmr1.js} +2 -2
  144. package/dist/docs/assets/{templates_thermo-quality-review.md.Dg1p1MsG.lean.js → templates_thermo-quality-review.md.95qmTmr1.lean.js} +1 -1
  145. package/dist/docs/assets/{templates_thermo-review.md.Dlylkowj.js → templates_thermo-review.md.DQh6Q0C-.js} +2 -2
  146. package/dist/docs/assets/{templates_thermo-review.md.Dlylkowj.lean.js → templates_thermo-review.md.DQh6Q0C-.lean.js} +1 -1
  147. package/dist/docs/assets/{templates_triage.md.CvJyx81N.js → templates_triage.md.BFlQhWXf.js} +3 -3
  148. package/dist/docs/assets/{templates_triage.md.CvJyx81N.lean.js → templates_triage.md.BFlQhWXf.lean.js} +1 -1
  149. package/dist/docs/assets/troubleshooting.md.Bscj6ODe.js +1 -0
  150. package/dist/docs/assets/{troubleshooting.md.Cw5PKa3t.lean.js → troubleshooting.md.Bscj6ODe.lean.js} +1 -1
  151. package/dist/docs/building-with-agents.html +36 -36
  152. package/dist/docs/building-with-agents.md +0 -3
  153. package/dist/docs/deployment.html +39 -39
  154. package/dist/docs/deployment.md +6 -10
  155. package/dist/docs/evals.html +36 -36
  156. package/dist/docs/evals.md +0 -3
  157. package/dist/docs/guides/agent-to-agent.html +36 -36
  158. package/dist/docs/guides/agent-to-agent.md +0 -3
  159. package/dist/docs/guides/bitbucket.html +36 -36
  160. package/dist/docs/guides/bitbucket.md +0 -3
  161. package/dist/docs/guides/cloud-agents.html +36 -36
  162. package/dist/docs/guides/cloud-agents.md +0 -4
  163. package/dist/docs/guides/convert-automation.html +37 -37
  164. package/dist/docs/guides/convert-automation.md +2 -5
  165. package/dist/docs/guides/github.html +37 -37
  166. package/dist/docs/guides/github.md +1 -4
  167. package/dist/docs/guides/gitlab.html +36 -36
  168. package/dist/docs/guides/gitlab.md +0 -3
  169. package/dist/docs/guides/grokbot-agents.html +37 -37
  170. package/dist/docs/guides/grokbot-agents.md +1 -4
  171. package/dist/docs/guides/hooks.html +36 -36
  172. package/dist/docs/guides/hooks.md +0 -3
  173. package/dist/docs/guides/improve.html +36 -36
  174. package/dist/docs/guides/improve.md +0 -3
  175. package/dist/docs/guides/jev.html +37 -37
  176. package/dist/docs/guides/jev.md +7 -3
  177. package/dist/docs/guides/mcp-oauth.html +37 -37
  178. package/dist/docs/guides/mcp-oauth.md +1 -4
  179. package/dist/docs/guides/opentelemetry.html +42 -40
  180. package/dist/docs/guides/opentelemetry.md +4 -5
  181. package/dist/docs/guides/slack.html +43 -43
  182. package/dist/docs/guides/slack.md +14 -24
  183. package/dist/docs/guides/webhooks.html +36 -36
  184. package/dist/docs/guides/webhooks.md +0 -3
  185. package/dist/docs/hashmap.json +1 -1
  186. package/dist/docs/hillclimbing.html +36 -36
  187. package/dist/docs/hillclimbing.md +0 -3
  188. package/dist/docs/index.html +38 -38
  189. package/dist/docs/index.md +9 -16
  190. package/dist/docs/llms-full.txt +156 -220
  191. package/dist/docs/llms.txt +1 -0
  192. package/dist/docs/quickstart.html +36 -36
  193. package/dist/docs/quickstart.md +2 -7
  194. package/dist/docs/reference/agent-config.html +38 -38
  195. package/dist/docs/reference/agent-config.md +4 -7
  196. package/dist/docs/reference/artifacts.html +36 -36
  197. package/dist/docs/reference/artifacts.md +0 -3
  198. package/dist/docs/reference/channels.html +37 -37
  199. package/dist/docs/reference/channels.md +1 -6
  200. package/dist/docs/reference/cli.html +38 -38
  201. package/dist/docs/reference/cli.md +7 -14
  202. package/dist/docs/reference/connections.html +38 -38
  203. package/dist/docs/reference/connections.md +7 -10
  204. package/dist/docs/reference/evals.html +36 -36
  205. package/dist/docs/reference/evals.md +0 -3
  206. package/dist/docs/reference/extensions.html +40 -39
  207. package/dist/docs/reference/extensions.md +15 -5
  208. package/dist/docs/reference/hooks.html +36 -36
  209. package/dist/docs/reference/hooks.md +0 -3
  210. package/dist/docs/reference/http-api.html +37 -37
  211. package/dist/docs/reference/http-api.md +1 -1
  212. package/dist/docs/reference/instructions.html +36 -36
  213. package/dist/docs/reference/instructions.md +0 -3
  214. package/dist/docs/reference/playground.html +36 -36
  215. package/dist/docs/reference/playground.md +0 -3
  216. package/dist/docs/reference/project-layout.html +37 -37
  217. package/dist/docs/reference/project-layout.md +2 -2
  218. package/dist/docs/reference/prompt.html +37 -37
  219. package/dist/docs/reference/prompt.md +0 -3
  220. package/dist/docs/reference/schedules.html +36 -36
  221. package/dist/docs/reference/schedules.md +0 -3
  222. package/dist/docs/reference/sessions.html +36 -36
  223. package/dist/docs/reference/sessions.md +0 -3
  224. package/dist/docs/reference/skills.html +38 -38
  225. package/dist/docs/reference/skills.md +0 -3
  226. package/dist/docs/reference/subagents.html +36 -36
  227. package/dist/docs/reference/subagents.md +0 -3
  228. package/dist/docs/reference/tools.html +36 -36
  229. package/dist/docs/reference/tools.md +1 -5
  230. package/dist/docs/templates/agentic-owners.html +36 -36
  231. package/dist/docs/templates/agentic-owners.md +0 -3
  232. package/dist/docs/templates/grokbot-agents.html +64 -0
  233. package/dist/docs/templates/grokbot-agents.md +55 -0
  234. package/dist/docs/templates/security-reviewer.html +37 -37
  235. package/dist/docs/templates/security-reviewer.md +0 -3
  236. package/dist/docs/templates/thermo-quality-review.html +36 -36
  237. package/dist/docs/templates/thermo-quality-review.md +3 -6
  238. package/dist/docs/templates/thermo-review.html +36 -36
  239. package/dist/docs/templates/thermo-review.md +3 -5
  240. package/dist/docs/templates/triage.html +37 -37
  241. package/dist/docs/templates/triage.md +2 -3
  242. package/dist/docs/troubleshooting.html +36 -36
  243. package/dist/docs/troubleshooting.md +3 -7
  244. package/dist/extensions/jev/extension.d.ts +3 -0
  245. package/dist/extensions/jev/extension.d.ts.map +1 -1
  246. package/dist/extensions/jev/extension.js +10 -1
  247. package/dist/extensions/jev/lib/evaluate.d.ts +4 -0
  248. package/dist/extensions/jev/lib/evaluate.d.ts.map +1 -1
  249. package/dist/extensions/jev/lib/evaluate.js +6 -2
  250. package/dist/extensions.d.ts +4 -2
  251. package/dist/extensions.d.ts.map +1 -1
  252. package/dist/extensions.js +5 -2
  253. package/dist/internal/cli-deploy.d.ts.map +1 -1
  254. package/dist/internal/cli-deploy.js +19 -5
  255. package/dist/internal/discovery/agent-config.d.ts +6 -5
  256. package/dist/internal/discovery/agent-config.d.ts.map +1 -1
  257. package/dist/internal/discovery/agent-config.js +29 -28
  258. package/dist/internal/discovery/agent.js +1 -1
  259. package/dist/internal/discovery/extensions.d.ts.map +1 -1
  260. package/dist/internal/discovery/extensions.js +12 -0
  261. package/dist/internal/hosting.d.ts +8 -0
  262. package/dist/internal/hosting.d.ts.map +1 -1
  263. package/dist/internal/hosting.js +24 -0
  264. package/dist/types.d.ts +18 -2
  265. package/dist/types.d.ts.map +1 -1
  266. package/docs/README.md +9 -16
  267. package/docs/building-with-agents.md +0 -3
  268. package/docs/deployment.md +6 -10
  269. package/docs/evals.md +0 -3
  270. package/docs/guides/agent-to-agent.md +0 -3
  271. package/docs/guides/bitbucket.md +0 -3
  272. package/docs/guides/cloud-agents.md +0 -4
  273. package/docs/guides/convert-automation.md +2 -5
  274. package/docs/guides/github.md +1 -4
  275. package/docs/guides/gitlab.md +0 -3
  276. package/docs/guides/grokbot-agents.md +1 -4
  277. package/docs/guides/hooks.md +0 -3
  278. package/docs/guides/improve.md +0 -3
  279. package/docs/guides/jev.md +7 -3
  280. package/docs/guides/mcp-oauth.md +1 -4
  281. package/docs/guides/opentelemetry.md +4 -5
  282. package/docs/guides/slack.md +14 -24
  283. package/docs/guides/webhooks.md +0 -3
  284. package/docs/hillclimbing.md +0 -3
  285. package/docs/quickstart.md +2 -7
  286. package/docs/reference/agent-config.md +4 -7
  287. package/docs/reference/artifacts.md +0 -3
  288. package/docs/reference/channels.md +1 -6
  289. package/docs/reference/cli.md +7 -14
  290. package/docs/reference/connections.md +7 -10
  291. package/docs/reference/evals.md +0 -3
  292. package/docs/reference/extensions.md +15 -5
  293. package/docs/reference/hooks.md +0 -3
  294. package/docs/reference/http-api.md +1 -1
  295. package/docs/reference/instructions.md +0 -3
  296. package/docs/reference/playground.md +0 -3
  297. package/docs/reference/project-layout.md +2 -2
  298. package/docs/reference/prompt.md +0 -3
  299. package/docs/reference/schedules.md +0 -3
  300. package/docs/reference/sessions.md +0 -3
  301. package/docs/reference/skills.md +0 -3
  302. package/docs/reference/subagents.md +0 -3
  303. package/docs/reference/tools.md +1 -5
  304. package/docs/templates/agentic-owners.md +0 -3
  305. package/docs/templates/grokbot-agents.md +60 -0
  306. package/docs/templates/security-reviewer.md +0 -3
  307. package/docs/templates/thermo-quality-review.md +3 -6
  308. package/docs/templates/thermo-review.md +3 -5
  309. package/docs/templates/triage.md +2 -3
  310. package/docs/troubleshooting.md +3 -7
  311. package/package.json +2 -10
  312. package/templates/agentic-owners/README.md +0 -3
  313. package/templates/agents-md/README.md +4 -3
  314. package/templates/code-wiki/README.md +0 -3
  315. package/templates/demo/README.md +0 -3
  316. package/templates/grokbot-agents/README.md +4 -6
  317. package/templates/security-help/README.md +12 -6
  318. package/templates/security-reviewer/README.md +0 -3
  319. package/templates/thermo-quality-review/README.md +0 -3
  320. package/templates/thermo-review/README.md +0 -3
  321. package/templates/triage/README.md +0 -3
  322. package/templates/triage/overlays/jira/README.md +0 -3
  323. package/templates/triage/overlays/linear/README.md +0 -3
  324. package/dist/docs/assets/chunks/@localSearchIndexroot.D5L-b34G.js +0 -1
  325. package/dist/docs/assets/chunks/channel.BbOGaJQP.js +0 -1
  326. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.Db58HCb1.js +0 -1
  327. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.Db58HCb1.js +0 -1
  328. package/dist/docs/assets/chunks/clone.Co4MBflG.js +0 -1
  329. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.CMsKhrW0.js +0 -1
  330. package/dist/docs/assets/index.md.CVc_oOA3.js +0 -27
  331. package/dist/docs/assets/reference_playground.md.BdQzRJc2.js +0 -1
  332. package/dist/docs/assets/reference_sessions.md.DeRUItHD.js +0 -1
  333. package/dist/docs/assets/troubleshooting.md.Cw5PKa3t.js +0 -1
  334. package/src/artifacts.ts +0 -68
  335. package/src/bin/agent-serve.ts +0 -1854
  336. package/src/channels/bitbucket/api.ts +0 -891
  337. package/src/channels/bitbucket/binding.ts +0 -417
  338. package/src/channels/bitbucket/bitbucket-channel.ts +0 -162
  339. package/src/channels/bitbucket/bitbucket-webhook.ts +0 -519
  340. package/src/channels/bitbucket/checks.ts +0 -146
  341. package/src/channels/bitbucket/cursor-account.ts +0 -106
  342. package/src/channels/bitbucket/defaults.ts +0 -100
  343. package/src/channels/bitbucket/events.ts +0 -74
  344. package/src/channels/bitbucket/index.ts +0 -51
  345. package/src/channels/bitbucket/replay.ts +0 -421
  346. package/src/channels/bitbucket/state.ts +0 -59
  347. package/src/channels/bitbucket/types.ts +0 -261
  348. package/src/channels/change-monitors/change-monitors-channel.ts +0 -63
  349. package/src/channels/change-monitors/index.ts +0 -8
  350. package/src/channels/change-monitors/types.ts +0 -42
  351. package/src/channels/checks.ts +0 -185
  352. package/src/channels/deployments/deployments-channel.ts +0 -224
  353. package/src/channels/deployments/index.ts +0 -25
  354. package/src/channels/deployments/types.ts +0 -92
  355. package/src/channels/github/api.ts +0 -526
  356. package/src/channels/github/auth.ts +0 -293
  357. package/src/channels/github/binding.ts +0 -233
  358. package/src/channels/github/checks.ts +0 -145
  359. package/src/channels/github/cursor-account.ts +0 -303
  360. package/src/channels/github/defaults.ts +0 -168
  361. package/src/channels/github/events.ts +0 -67
  362. package/src/channels/github/forward.ts +0 -359
  363. package/src/channels/github/github-channel.ts +0 -2334
  364. package/src/channels/github/index.ts +0 -54
  365. package/src/channels/github/progress.ts +0 -365
  366. package/src/channels/github/replay.ts +0 -372
  367. package/src/channels/github/state.ts +0 -124
  368. package/src/channels/github/types.ts +0 -590
  369. package/src/channels/gitlab/api.ts +0 -329
  370. package/src/channels/gitlab/binding.ts +0 -231
  371. package/src/channels/gitlab/checks.ts +0 -228
  372. package/src/channels/gitlab/cursor-account.ts +0 -105
  373. package/src/channels/gitlab/defaults.ts +0 -80
  374. package/src/channels/gitlab/events.ts +0 -37
  375. package/src/channels/gitlab/gitlab-channel.ts +0 -160
  376. package/src/channels/gitlab/gitlab-webhook.ts +0 -509
  377. package/src/channels/gitlab/index.ts +0 -44
  378. package/src/channels/gitlab/replay.ts +0 -328
  379. package/src/channels/gitlab/state.ts +0 -55
  380. package/src/channels/gitlab/types.ts +0 -247
  381. package/src/channels/issues/index.ts +0 -9
  382. package/src/channels/issues/issues-channel.ts +0 -45
  383. package/src/channels/issues/types.ts +0 -38
  384. package/src/channels/origin/api.ts +0 -507
  385. package/src/channels/origin/binding.ts +0 -114
  386. package/src/channels/origin/checks.ts +0 -250
  387. package/src/channels/origin/cursor-account.ts +0 -58
  388. package/src/channels/origin/defaults.ts +0 -140
  389. package/src/channels/origin/events.ts +0 -35
  390. package/src/channels/origin/index.ts +0 -35
  391. package/src/channels/origin/origin-channel.ts +0 -815
  392. package/src/channels/origin/origin-webhook.ts +0 -296
  393. package/src/channels/origin/reactions.ts +0 -72
  394. package/src/channels/origin/state.ts +0 -54
  395. package/src/channels/origin/types.ts +0 -295
  396. package/src/channels/slack/agentic-delivery.ts +0 -634
  397. package/src/channels/slack/agentic-posted.ts +0 -135
  398. package/src/channels/slack/agentic-signals.ts +0 -231
  399. package/src/channels/slack/api.ts +0 -761
  400. package/src/channels/slack/approvals.ts +0 -279
  401. package/src/channels/slack/assistant.ts +0 -76
  402. package/src/channels/slack/attachments.ts +0 -596
  403. package/src/channels/slack/auth.ts +0 -127
  404. package/src/channels/slack/blocks.ts +0 -131
  405. package/src/channels/slack/bot-mentions.ts +0 -318
  406. package/src/channels/slack/channel-watch.ts +0 -314
  407. package/src/channels/slack/cli-project.ts +0 -249
  408. package/src/channels/slack/code-fences.ts +0 -171
  409. package/src/channels/slack/constants.ts +0 -38
  410. package/src/channels/slack/credentials.ts +0 -88
  411. package/src/channels/slack/defaults.ts +0 -714
  412. package/src/channels/slack/dispatch.ts +0 -1060
  413. package/src/channels/slack/doctor.ts +0 -338
  414. package/src/channels/slack/eval-directive.ts +0 -306
  415. package/src/channels/slack/event-id-dedupe.ts +0 -30
  416. package/src/channels/slack/external-policy.ts +0 -75
  417. package/src/channels/slack/footer.ts +0 -106
  418. package/src/channels/slack/inbound.ts +0 -416
  419. package/src/channels/slack/index.ts +0 -53
  420. package/src/channels/slack/init.ts +0 -169
  421. package/src/channels/slack/interactive.ts +0 -406
  422. package/src/channels/slack/links.ts +0 -23
  423. package/src/channels/slack/live-delivery.ts +0 -489
  424. package/src/channels/slack/log.ts +0 -70
  425. package/src/channels/slack/manifest.ts +0 -240
  426. package/src/channels/slack/message-body.ts +0 -82
  427. package/src/channels/slack/nudge-carrier.ts +0 -224
  428. package/src/channels/slack/nudge-store.ts +0 -334
  429. package/src/channels/slack/paint-start.ts +0 -93
  430. package/src/channels/slack/placeholder.ts +0 -358
  431. package/src/channels/slack/pr-ref.ts +0 -74
  432. package/src/channels/slack/progress-delivery.ts +0 -138
  433. package/src/channels/slack/reasoning-card.ts +0 -125
  434. package/src/channels/slack/reasoning-chip.ts +0 -41
  435. package/src/channels/slack/recording-sink.ts +0 -167
  436. package/src/channels/slack/redact.ts +0 -6
  437. package/src/channels/slack/reply-options.ts +0 -279
  438. package/src/channels/slack/setup.ts +0 -125
  439. package/src/channels/slack/slack-channel.ts +0 -744
  440. package/src/channels/slack/socket-mode.ts +0 -140
  441. package/src/channels/slack/stop.ts +0 -25
  442. package/src/channels/slack/stream.ts +0 -66
  443. package/src/channels/slack/thread-context.ts +0 -485
  444. package/src/channels/slack/tool-approval-events.ts +0 -233
  445. package/src/channels/slack/tool-cards.ts +0 -198
  446. package/src/channels/slack/tool-chip.ts +0 -34
  447. package/src/channels/slack/types.ts +0 -787
  448. package/src/channels/slack/upload.ts +0 -137
  449. package/src/channels.ts +0 -543
  450. package/src/connections.ts +0 -153
  451. package/src/dashboard-session-url.ts +0 -30
  452. package/src/evals/assertions.ts +0 -688
  453. package/src/evals/expect.ts +0 -250
  454. package/src/evals/judge.ts +0 -329
  455. package/src/evals/loaders.ts +0 -111
  456. package/src/evals/matchers.ts +0 -223
  457. package/src/evals/reporters.ts +0 -257
  458. package/src/evals/results.ts +0 -130
  459. package/src/evals/run-facts.ts +0 -306
  460. package/src/evals.ts +0 -709
  461. package/src/extensions/cursor-cloud-agents/extension.ts +0 -131
  462. package/src/extensions/cursor-cloud-agents/lib/backend.ts +0 -386
  463. package/src/extensions/cursor-cloud-agents/lib/channels.ts +0 -11
  464. package/src/extensions/cursor-cloud-agents/lib/fleet.ts +0 -98
  465. package/src/extensions/cursor-cloud-agents/lib/inputs.ts +0 -5
  466. package/src/extensions/cursor-cloud-agents/lib/repos.ts +0 -80
  467. package/src/extensions/cursor-cloud-agents/lib/transcript.ts +0 -19
  468. package/src/extensions/cursor-cloud-agents/skills/handoff.md +0 -37
  469. package/src/extensions/cursor-cloud-agents/tools/cancel.ts +0 -21
  470. package/src/extensions/cursor-cloud-agents/tools/dump.ts +0 -47
  471. package/src/extensions/cursor-cloud-agents/tools/get.ts +0 -18
  472. package/src/extensions/cursor-cloud-agents/tools/launch.ts +0 -62
  473. package/src/extensions/cursor-cloud-agents/tools/list.ts +0 -31
  474. package/src/extensions/cursor-cloud-agents/tools/reply.ts +0 -36
  475. package/src/extensions/cursor-grokbot-agents/extension.ts +0 -132
  476. package/src/extensions/cursor-grokbot-agents/lib/agents.ts +0 -42
  477. package/src/extensions/cursor-grokbot-agents/lib/backend.ts +0 -208
  478. package/src/extensions/cursor-grokbot-agents/lib/contacts.ts +0 -74
  479. package/src/extensions/cursor-grokbot-agents/lib/conversation.ts +0 -260
  480. package/src/extensions/cursor-grokbot-agents/lib/inputs.ts +0 -21
  481. package/src/extensions/cursor-grokbot-agents/lib/lock.ts +0 -26
  482. package/src/extensions/cursor-grokbot-agents/skills/consult.md +0 -40
  483. package/src/extensions/cursor-grokbot-agents/tools/ask.ts +0 -32
  484. package/src/extensions/cursor-grokbot-agents/tools/check.ts +0 -25
  485. package/src/extensions/cursor-grokbot-agents/tools/interrupt.ts +0 -17
  486. package/src/extensions/cursor-grokbot-agents/tools/list.ts +0 -26
  487. package/src/extensions/improve/extension.ts +0 -69
  488. package/src/extensions/improve/skills/yourself.ts +0 -50
  489. package/src/extensions/jev/extension.ts +0 -95
  490. package/src/extensions/jev/lib/evaluate.ts +0 -266
  491. package/src/extensions/jev/skills/gated-write.md +0 -25
  492. package/src/extensions/jev/skills/questions.md +0 -33
  493. package/src/extensions/jev/tools/evaluate.ts +0 -82
  494. package/src/extensions/slack-communication/evals/harness.ts +0 -705
  495. package/src/extensions/slack-communication/evals/slack-communication.eval.ts +0 -830
  496. package/src/extensions/slack-communication/evals/slack-placeholder.eval.ts +0 -172
  497. package/src/extensions/slack-communication/extension.ts +0 -44
  498. package/src/extensions/slack-communication/skills/slack-voice.ts +0 -56
  499. package/src/extensions/slack-communication/tools/delete-message.ts +0 -33
  500. package/src/extensions/slack-communication/tools/edit-message.ts +0 -42
  501. package/src/extensions/slack-communication/tools/post-card.ts +0 -28
  502. package/src/extensions/slack-communication/tools/post-file.ts +0 -82
  503. package/src/extensions/slack-communication/tools/post-update.ts +0 -40
  504. package/src/extensions/slack-communication/tools/react.ts +0 -30
  505. package/src/extensions/slack-communication/tools/set-status.ts +0 -21
  506. package/src/extensions.ts +0 -179
  507. package/src/files-backends/agent-store-presigned-url.ts +0 -11
  508. package/src/files-backends/cursor-hosted.ts +0 -1212
  509. package/src/files-backends/local-fs.ts +0 -163
  510. package/src/files.ts +0 -293
  511. package/src/filesystem.ts +0 -2005
  512. package/src/hooks.ts +0 -30
  513. package/src/index.ts +0 -259
  514. package/src/internal/advertise-tools.ts +0 -370
  515. package/src/internal/approval-gate.ts +0 -103
  516. package/src/internal/artifacts-store.ts +0 -836
  517. package/src/internal/as-of.ts +0 -257
  518. package/src/internal/auth.ts +0 -46
  519. package/src/internal/authored-alias-hooks.ts +0 -138
  520. package/src/internal/authored-loaders.ts +0 -188
  521. package/src/internal/bounded-int.ts +0 -24
  522. package/src/internal/bounded.ts +0 -25
  523. package/src/internal/brand.ts +0 -28
  524. package/src/internal/browser-origin-guard.ts +0 -67
  525. package/src/internal/builtin-tools/artifacts.ts +0 -62
  526. package/src/internal/builtin-tools/index.ts +0 -53
  527. package/src/internal/builtin-tools/reminders.ts +0 -145
  528. package/src/internal/channel-dispatch.ts +0 -129
  529. package/src/internal/channel-route-dispatch.ts +0 -58
  530. package/src/internal/channel-state.ts +0 -83
  531. package/src/internal/chat-client.ts +0 -594
  532. package/src/internal/cli-ax.ts +0 -2318
  533. package/src/internal/cli-bitbucket.ts +0 -438
  534. package/src/internal/cli-convert-automation.ts +0 -335
  535. package/src/internal/cli-cursor.ts +0 -282
  536. package/src/internal/cli-deploy.ts +0 -2519
  537. package/src/internal/cli-docs.ts +0 -192
  538. package/src/internal/cli-github.ts +0 -806
  539. package/src/internal/cli-gitlab.ts +0 -452
  540. package/src/internal/cli-images.ts +0 -672
  541. package/src/internal/cli-manifest.ts +0 -56
  542. package/src/internal/cli-mcp-oauth.ts +0 -396
  543. package/src/internal/cli-mcp.ts +0 -808
  544. package/src/internal/cli-skills.ts +0 -98
  545. package/src/internal/cli-slack-manual.ts +0 -418
  546. package/src/internal/cli-slack.ts +0 -874
  547. package/src/internal/cloud-merge.ts +0 -51
  548. package/src/internal/cloud-turn-cost.ts +0 -159
  549. package/src/internal/connection-env.ts +0 -106
  550. package/src/internal/continuation-channel.ts +0 -233
  551. package/src/internal/continuation-identity.ts +0 -935
  552. package/src/internal/conversation-mirror.ts +0 -423
  553. package/src/internal/convert-automation/convert-workflow.ts +0 -1377
  554. package/src/internal/convert-automation/slug.ts +0 -29
  555. package/src/internal/convert-automation/types.ts +0 -212
  556. package/src/internal/cron.ts +0 -76
  557. package/src/internal/cursor/account-mcp.ts +0 -692
  558. package/src/internal/cursor/backend-client.ts +0 -984
  559. package/src/internal/cursor/bound-secret-file.ts +0 -101
  560. package/src/internal/cursor/credentials.ts +0 -560
  561. package/src/internal/cursor/cursor-api-transport.ts +0 -65
  562. package/src/internal/cursor/github-credentials.ts +0 -228
  563. package/src/internal/cursor/hosted-bound-secrets.ts +0 -71
  564. package/src/internal/cursor/hosted-deployment-secrets.ts +0 -100
  565. package/src/internal/cursor/hosted-store-secrets.ts +0 -152
  566. package/src/internal/cursor/session-token.ts +0 -111
  567. package/src/internal/cursor/store-api-client.ts +0 -323
  568. package/src/internal/cursor-account-mcp-auth.ts +0 -303
  569. package/src/internal/cursor-agent-template.ts +0 -50
  570. package/src/internal/cursor-deployment-relay.ts +0 -315
  571. package/src/internal/cursor-event-relay.ts +0 -675
  572. package/src/internal/cursor-relay-core.ts +0 -563
  573. package/src/internal/deferred-channel-session.ts +0 -61
  574. package/src/internal/deploy-client.ts +0 -1574
  575. package/src/internal/deploy-manifest.ts +0 -361
  576. package/src/internal/deploy-source.ts +0 -144
  577. package/src/internal/describe-error.ts +0 -32
  578. package/src/internal/dev-mode.ts +0 -20
  579. package/src/internal/discovery/agent-config.ts +0 -288
  580. package/src/internal/discovery/agent.ts +0 -381
  581. package/src/internal/discovery/channels.ts +0 -100
  582. package/src/internal/discovery/connections.ts +0 -516
  583. package/src/internal/discovery/context.ts +0 -38
  584. package/src/internal/discovery/cursor-plugin.ts +0 -628
  585. package/src/internal/discovery/extension-overlay.ts +0 -247
  586. package/src/internal/discovery/extensions.ts +0 -490
  587. package/src/internal/discovery/fs.ts +0 -103
  588. package/src/internal/discovery/hooks.ts +0 -63
  589. package/src/internal/discovery/info.ts +0 -174
  590. package/src/internal/discovery/instructions.ts +0 -98
  591. package/src/internal/discovery/modules.ts +0 -107
  592. package/src/internal/discovery/names.ts +0 -45
  593. package/src/internal/discovery/project.ts +0 -319
  594. package/src/internal/discovery/reminders.ts +0 -65
  595. package/src/internal/discovery/runtime.ts +0 -158
  596. package/src/internal/discovery/schedules.ts +0 -120
  597. package/src/internal/discovery/seed-files.ts +0 -34
  598. package/src/internal/discovery/services.ts +0 -151
  599. package/src/internal/discovery/skills.ts +0 -174
  600. package/src/internal/discovery/subagent.ts +0 -138
  601. package/src/internal/discovery/tools.ts +0 -170
  602. package/src/internal/discovery.ts +0 -27
  603. package/src/internal/distribution.ts +0 -126
  604. package/src/internal/docs-site.ts +0 -248
  605. package/src/internal/duration.ts +0 -37
  606. package/src/internal/env-file.ts +0 -83
  607. package/src/internal/eval-judge-model.ts +0 -142
  608. package/src/internal/eval-run-store.ts +0 -585
  609. package/src/internal/eval-runner.ts +0 -823
  610. package/src/internal/evals-client.ts +0 -475
  611. package/src/internal/event-log.ts +0 -342
  612. package/src/internal/event-mapper.ts +0 -811
  613. package/src/internal/expected-delivery-failure.ts +0 -34
  614. package/src/internal/factory-resource-channel.ts +0 -103
  615. package/src/internal/filesystem/errors.ts +0 -207
  616. package/src/internal/filesystem/format.ts +0 -253
  617. package/src/internal/filesystem/merge.ts +0 -192
  618. package/src/internal/filesystem/nearest.ts +0 -112
  619. package/src/internal/filesystem/scratch.ts +0 -239
  620. package/src/internal/filesystem/sdk-schemas.ts +0 -204
  621. package/src/internal/filesystem/tools.ts +0 -804
  622. package/src/internal/filesystem/walk.ts +0 -366
  623. package/src/internal/fixtures/units-server.ts +0 -52
  624. package/src/internal/framework-file-storage.ts +0 -357
  625. package/src/internal/framework-storage-selection.ts +0 -156
  626. package/src/internal/frontmatter.ts +0 -108
  627. package/src/internal/github-fanout.ts +0 -144
  628. package/src/internal/guest-network.ts +0 -391
  629. package/src/internal/handleAgentServeTrigger.ts +0 -286
  630. package/src/internal/host-files.ts +0 -341
  631. package/src/internal/host-kv.ts +0 -81
  632. package/src/internal/host-otel.ts +0 -231
  633. package/src/internal/host-platforms.ts +0 -170
  634. package/src/internal/hosted-admission-adapter.ts +0 -47
  635. package/src/internal/hosted-admission-context.ts +0 -37
  636. package/src/internal/hosted-catch-protocol.ts +0 -112
  637. package/src/internal/hosted-catch.ts +0 -179
  638. package/src/internal/hosted-delivery-protocol.ts +0 -824
  639. package/src/internal/hosted-delivery.ts +0 -1410
  640. package/src/internal/hosted-execution-diag.ts +0 -291
  641. package/src/internal/hosted-execution-flush.ts +0 -136
  642. package/src/internal/hosted-execution-latency.ts +0 -301
  643. package/src/internal/hosted-managed-automation.ts +0 -116
  644. package/src/internal/hosting.ts +0 -114
  645. package/src/internal/http-channel-define.ts +0 -25
  646. package/src/internal/http-channel.ts +0 -669
  647. package/src/internal/http-control-plane-session.ts +0 -110
  648. package/src/internal/ids.ts +0 -39
  649. package/src/internal/incoming-headers-to-fetch.ts +0 -45
  650. package/src/internal/init-interview.ts +0 -360
  651. package/src/internal/init-project.ts +0 -711
  652. package/src/internal/init-scaffold.ts +0 -182
  653. package/src/internal/inline-stdio-define-stub.ts +0 -4
  654. package/src/internal/inline-stdio-mcp.ts +0 -230
  655. package/src/internal/install-cursor-skills.ts +0 -604
  656. package/src/internal/is-record.ts +0 -3
  657. package/src/internal/json-schema.ts +0 -95
  658. package/src/internal/legacy-command-guard.ts +0 -66
  659. package/src/internal/listen-port.ts +0 -85
  660. package/src/internal/local-control-plane.ts +0 -442
  661. package/src/internal/local-env.ts +0 -59
  662. package/src/internal/local-ingress.ts +0 -90
  663. package/src/internal/log-ring.ts +0 -59
  664. package/src/internal/logs-client.ts +0 -477
  665. package/src/internal/map-pool.ts +0 -39
  666. package/src/internal/mcp-endpoint.ts +0 -747
  667. package/src/internal/mcp-host.ts +0 -509
  668. package/src/internal/mcp-oauth-on-demand.ts +0 -337
  669. package/src/internal/mcp-oauth-persist.ts +0 -118
  670. package/src/internal/mcp-oauth.ts +0 -549
  671. package/src/internal/net.ts +0 -29
  672. package/src/internal/open-browser.ts +0 -41
  673. package/src/internal/otel/attrs.ts +0 -16
  674. package/src/internal/otel/collector.ts +0 -937
  675. package/src/internal/otel/config.ts +0 -287
  676. package/src/internal/otel/http.ts +0 -122
  677. package/src/internal/otel/mcp.ts +0 -56
  678. package/src/internal/otel/propagation.ts +0 -17
  679. package/src/internal/otel/runtime.ts +0 -441
  680. package/src/internal/package-inline-stdio.ts +0 -114
  681. package/src/internal/peer-connections.ts +0 -96
  682. package/src/internal/platform-schedule-sync.ts +0 -75
  683. package/src/internal/platform-timers.ts +0 -365
  684. package/src/internal/playground/static.ts +0 -278
  685. package/src/internal/playground/toolchain.ts +0 -270
  686. package/src/internal/playground-proxy.ts +0 -564
  687. package/src/internal/process-memory-telemetry.ts +0 -334
  688. package/src/internal/project-layout.ts +0 -31
  689. package/src/internal/prompt-context.ts +0 -116
  690. package/src/internal/reminder-control-plane-protocol.ts +0 -482
  691. package/src/internal/reminder-runner.ts +0 -1559
  692. package/src/internal/reminder-schedule.ts +0 -104
  693. package/src/internal/reminder-store.ts +0 -176
  694. package/src/internal/request-error-status.ts +0 -95
  695. package/src/internal/request-headers.ts +0 -21
  696. package/src/internal/resolve-prod-target.ts +0 -334
  697. package/src/internal/resolved-connections.ts +0 -190
  698. package/src/internal/router.ts +0 -143
  699. package/src/internal/run-client.ts +0 -354
  700. package/src/internal/runtime-dispatch-runner.ts +0 -50
  701. package/src/internal/sanitize-mcp-tool-name.ts +0 -31
  702. package/src/internal/schedule-runner.ts +0 -154
  703. package/src/internal/scm/pr-url.ts +0 -245
  704. package/src/internal/sdk-runner.ts +0 -959
  705. package/src/internal/serve-restart.ts +0 -113
  706. package/src/internal/server.ts +0 -3147
  707. package/src/internal/session-cost.ts +0 -208
  708. package/src/internal/session-engine.ts +0 -5622
  709. package/src/internal/session-links.ts +0 -84
  710. package/src/internal/session-run-log.ts +0 -535
  711. package/src/internal/session-store.ts +0 -307
  712. package/src/internal/session-urls.ts +0 -32
  713. package/src/internal/sessions-client.ts +0 -239
  714. package/src/internal/skill-catalog.ts +0 -66
  715. package/src/internal/skills-sync.ts +0 -55
  716. package/src/internal/slack-provision-client.ts +0 -544
  717. package/src/internal/slack-thread-key.ts +0 -11
  718. package/src/internal/sleep.ts +0 -3
  719. package/src/internal/start-log-store.ts +0 -164
  720. package/src/internal/steering.ts +0 -17
  721. package/src/internal/storage-coordinator.ts +0 -800
  722. package/src/internal/storage-roles.ts +0 -86
  723. package/src/internal/storage.ts +0 -1
  724. package/src/internal/store-api-protocol.ts +0 -205
  725. package/src/internal/store-mirror.ts +0 -73
  726. package/src/internal/stream-progress.ts +0 -294
  727. package/src/internal/terminal-style.ts +0 -133
  728. package/src/internal/testing/factory-resource-fixtures.ts +0 -84
  729. package/src/internal/testing/scm-continuation-fixtures.ts +0 -285
  730. package/src/internal/tool-catalog.ts +0 -104
  731. package/src/internal/tool-policy.ts +0 -222
  732. package/src/internal/tool-result.ts +0 -50
  733. package/src/internal/trajectory.ts +0 -418
  734. package/src/internal/turn-cost.ts +0 -136
  735. package/src/internal/turn-governor.ts +0 -145
  736. package/src/internal/turn-lease-store.ts +0 -144
  737. package/src/internal/turn-outbox.ts +0 -77
  738. package/src/internal/update-check.ts +0 -517
  739. package/src/internal/v2-hosting.ts +0 -52
  740. package/src/internal/workspace-sync.ts +0 -114
  741. package/src/internal/workspace.ts +0 -505
  742. package/src/kv/memory-kv.ts +0 -94
  743. package/src/kv.ts +0 -18
  744. package/src/memory.ts +0 -487
  745. package/src/otel-public.ts +0 -24
  746. package/src/otel.ts +0 -320
  747. package/src/prompt.ts +0 -80
  748. package/src/reminders.ts +0 -65
  749. package/src/schedules.ts +0 -31
  750. package/src/skills.ts +0 -27
  751. package/src/storage-backends/cursor-hosted-v2.ts +0 -204
  752. package/src/storage-backends/cursor-hosted.ts +0 -388
  753. package/src/storage-backends/file-kv.ts +0 -276
  754. package/src/storage-protocol.ts +0 -261
  755. package/src/storage.ts +0 -408
  756. package/src/tools.ts +0 -166
  757. package/src/types.ts +0 -3776
  758. /package/dist/docs/assets/{guides_jev.md.BNDm14Gy.lean.js → guides_jev.md.D7XH4JH3.lean.js} +0 -0
  759. /package/dist/docs/assets/{reference_http-api.md.BZOvhCqY.lean.js → reference_http-api.md.DbFNOubV.lean.js} +0 -0
  760. /package/dist/docs/assets/{reference_project-layout.md.CpLQ9j4K.lean.js → reference_project-layout.md.C2JMRh7p.lean.js} +0 -0
@@ -1,1212 +0,0 @@
1
- /**
2
- * Cursor-managed durable files for hosted agents — the backend that puts
3
- * `ctx.host.files` bytes in an Agent Store on S3.
4
- *
5
- * One credential throughout: the engine's pod `CURSOR_API_KEY`. It authorizes
6
- * every call, and the bytes then move between this process and presigned S3
7
- * URLs. File contents never transit the control plane, so a large artifact
8
- * costs S3 bandwidth rather than backend memory.
9
- *
10
- * By default everything goes through the public API under
11
- * `/v0/agent-serve-files`, the same surface any API-key holder gets — a
12
- * self-hosted deployment, a CI job, or a customer script can drive the same
13
- * store with the same requests. Cursor-managed v2 pods can instead be pinned
14
- * (per deployment, at task-time bind) onto the engine-facing factory store API
15
- * under `/internal/agentsdk/store`: same host, same credential, same stores
16
- * and S3 objects, but flush-shaped — one control-plane request settles a whole
17
- * `putMany` batch or a conditional delete, where `/v0` costs a presign POST
18
- * plus stat GETs and a delete POST. The pin fails safe: an absent or
19
- * unrecognized protocol value, or a source id that maps to neither deployment
20
- * store role, keeps `/v0`.
21
- *
22
- * Two things follow. There is no Agent Store token: a token narrows an identity
23
- * to one store and one capability, which is what a caller that cannot hold a
24
- * credential needs (an in-pod FUSE daemon). This process holds the credential
25
- * the token would be minted from, so a token bought a round trip, an expiry to
26
- * manage, and a second auth path, and no privilege reduction. And there is no
27
- * direct call to the store service: the API layer owns the policy, and the
28
- * engine never addresses it.
29
- *
30
- * There is also no store lookup. Every request names this deployment's file
31
- * store by the `agentStoreSourceId` the deploy pipeline pinned into the pod
32
- * env as `AGENT_SERVE_STORE_SOURCE_ID` — provisioning the store at the same
33
- * time, so by boot the store exists and the id resolves. The id is an
34
- * address, not a credential: the server maps it to a store and authorizes
35
- * every call against the deployment's own live service account, so holding
36
- * it grants nothing, and this process never learns a store id it could use
37
- * to ask for anyone else's.
38
- *
39
- * Locally, point `CURSOR_API_BASE_URL` at a backend that serves
40
- * `/v0/agent-serve-files` and use a deployment SA key; off hosting the
41
- * local-disk sink is the default instead.
42
- *
43
- * Writes are conditional. The store rejects unconditional writes, so every
44
- * `put` first learns the current etag: `new` for a path we believe is absent,
45
- * `etag` to replace what we last observed. A raced write comes back 412 and
46
- * surfaces as {@link FileConflictError}, which is why this backend reports
47
- * `etags: true` and `host.files.capabilities.conflictDetection` is honestly
48
- * true.
49
- */
50
-
51
- import { createHash } from "node:crypto";
52
- import {
53
- FileConflictError,
54
- type FileSink,
55
- type FileSinkBody,
56
- type FileSinkEntry,
57
- type FileSinkPutResult,
58
- } from "../files.js";
59
- import { mapBounded } from "../internal/bounded.js";
60
- import {
61
- type CursorApiTransportOptions,
62
- resolveCursorApiBaseUrl,
63
- resolveCursorApiFetch,
64
- resolveCursorApiKey,
65
- } from "../internal/cursor/cursor-api-transport.js";
66
- import {
67
- resolveDeploymentStoreSourceIdSync,
68
- resolveFrameworkStoreSourceIdSync,
69
- resolveStoreProtocolSync,
70
- storeProtocolEnablesFactoryFlush,
71
- } from "../internal/cursor/hosted-store-secrets.js";
72
- import { createAgentStorePresignedUrlValidatorForBackend } from "./agent-store-presigned-url.js";
73
-
74
- const AGENT_SERVE_FILES_PATH = "/v0/agent-serve-files";
75
-
76
- /**
77
- * Engine-facing store API on the factory service — same host, different path
78
- * family. Selected per pod by the task-bound protocol pin
79
- * ({@link resolveStoreProtocolSync}); the server resolves the deployment and
80
- * its stores from the pod credential, so requests carry a store *role*
81
- * (`deployment` | `framework`), never a store id. One flush request replaces
82
- * the presign POST plus the stat GETs and delete POST a turn costs on `/v0`.
83
- */
84
- const AGENTSDK_STORE_PATH = "/internal/agentsdk/store";
85
-
86
- /**
87
- * Pinned by the deploy pipeline for every Cursor-managed deployment — which
88
- * provisions the file store it names in the same step — and reserved from
89
- * user secrets. Its presence is the signal that a durable store exists and
90
- * the hosted control plane is reachable; a deployment without one (no
91
- * service account yet) has no store, and this backend is not selected.
92
- */
93
- export const AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR = "AGENT_SERVE_STORE_SOURCE_ID";
94
-
95
- /**
96
- * The deployment's **framework-level** file store, distinct from the
97
- * user-level store above. The user store carries author-facing bytes
98
- * (`ctx.host.files`, skills, memory, artifacts) and is browsable and
99
- * mountable; the framework store carries engine-owned session state —
100
- * session records, event transcripts, hosted-execution run logs,
101
- * continuation index, and the SDK conversation mirror — and is never
102
- * exposed to authors or models.
103
- * Provisioned by the v2 deploy pipeline alongside the user store; v1
104
- * deployments have only the user store.
105
- */
106
- export const AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID_ENV_VAR =
107
- "AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID";
108
-
109
- /** Cap on the per-process etag cache; a miss costs a lookup, not correctness. */
110
- const MAX_REMEMBERED_ETAGS = 1_000;
111
-
112
- /** Bounded directory page for point lookups. */
113
- const DIRECTORY_PAGE_SIZE = 1_000;
114
- /**
115
- * Paths per presign call in {@link FileSink.getMany}, matching the factory
116
- * `/read` route's server-side `MAX_READ_PATHS`. The whole point of the batch:
117
- * the factory wire's per-deployment rate limiter counts requests, not files,
118
- * so a restore that used to spend N `/read` calls now spends ceil(N/100).
119
- */
120
- const READ_PRESIGN_BATCH_MAX = 100;
121
- /**
122
- * Concurrent presigned-URL downloads inside one {@link FileSink.getMany}
123
- * batch — the S3 fan-out, not the control-plane call count. Matches the
124
- * conversation mirror's historical `HYDRATE_DOWNLOAD_CONCURRENCY`.
125
- */
126
- const GET_MANY_DOWNLOAD_CONCURRENCY = 8;
127
- /** Stop paging a pathological directory rather than scanning forever. */
128
- const MAX_DIRECTORY_PAGES = 20;
129
- /**
130
- * Total page budget for a full `list()` walk of a store the unscoped listing
131
- * could not carry (~1M entries at the page size above). Past it, fail loudly:
132
- * a silently partial listing would be mistaken for the whole scope.
133
- */
134
- const MAX_LIST_WALK_PAGES = 1_000;
135
-
136
- /**
137
- * True on Cursor-managed hosting with a provisioned file store.
138
- *
139
- * Keyed on the store source id alone, deliberately: the credential is not part
140
- * of the test. If it were, a missing or regressed `CURSOR_API_KEY` would
141
- * silently select pod-local disk on a hosted pod and accept writes that vanish
142
- * with the pod. Instead the store is detected, and a missing credential fails
143
- * loudly when the sink is used.
144
- */
145
- export function isCursorHostedFilesAvailable(env: NodeJS.ProcessEnv = process.env): boolean {
146
- return resolveDeploymentStoreSourceIdSync(env) !== undefined;
147
- }
148
-
149
- /**
150
- * Local `serve`/`run` with a personal `CURSOR_API_KEY` can address
151
- * `/v0/agent-serve-files/user`. Hosted deployments have a store source id
152
- * and must not take this path — they own the deployment store instead.
153
- */
154
- export function isCursorUserStoreFilesAvailable(env: NodeJS.ProcessEnv = process.env): boolean {
155
- if (isCursorHostedFilesAvailable(env)) {
156
- return false;
157
- }
158
- // Vitest inherits the developer's shell. User-store sync writes durable
159
- // keys; skip it in the test runner so `pnpm test` cannot poison
160
- // `agent-serve/<agent>/skills/` on the caller's USER store.
161
- if (env.VITEST === "true") {
162
- return false;
163
- }
164
- const key = env.CURSOR_API_KEY?.trim();
165
- return key !== undefined && key !== "";
166
- }
167
-
168
- /**
169
- * Base URL / credential / fetch resolution is the shared
170
- * {@link CursorApiTransportOptions} (`internal/cursor/cursor-api-transport.ts`),
171
- * so this sink and the domain-lane store API client resolve identically.
172
- */
173
- export interface CursorHostedFilesOptions extends CursorApiTransportOptions {
174
- /** File store to address (default: `AGENT_SERVE_STORE_SOURCE_ID`). */
175
- storeSourceId?: string;
176
- /**
177
- * Lazy store source id, re-resolved on every call and preferred over
178
- * {@link storeSourceId} — freeze bind drops ids into `/run/cursor/secrets`
179
- * after serve start without restarting July.
180
- */
181
- resolveStoreSourceId?: () => string | undefined;
182
- /**
183
- * Lazy store protocol pin (default: env, then the task-bound file). When it
184
- * enables the factory flush wire (`factory-flush-v1`, or the superset
185
- * domain-API pin `factory-api-v1`) and the source id maps to a deployment
186
- * store role, requests ride the factory store API instead of
187
- * `/v0/agent-serve-files`. Any other value keeps `/v0`.
188
- */
189
- resolveStoreProtocol?: () => string | undefined;
190
- }
191
-
192
- /**
193
- * What a file operation needs: where this deployment's files live, and which
194
- * wire reaches them. `v0` addresses the public API by store source id; `flush`
195
- * addresses the factory store API by role and lets the server resolve.
196
- */
197
- type FilesTarget =
198
- | { wire: "v0"; path(suffix?: string): string }
199
- | { wire: "flush"; store: "deployment" | "framework" };
200
-
201
- /**
202
- * Wire shapes from `/v0/agent-serve-files`. Declared loosely on purpose: this is a
203
- * versioned public API, and a client that hard-required every field would break
204
- * on an additive change it could otherwise ignore.
205
- */
206
- interface ApiFile {
207
- path?: string;
208
- sizeBytes?: number;
209
- etag?: string;
210
- updatedAt?: string;
211
- }
212
-
213
- interface ApiFileListing {
214
- files?: ApiFile[];
215
- complete?: boolean;
216
- /** Immediate subdirectories; only returned by the `?path=` form. */
217
- directories?: string[];
218
- nextPageToken?: string;
219
- }
220
-
221
- interface ApiPresignResponse {
222
- files?: Array<{
223
- path?: string;
224
- url?: string;
225
- headers?: Record<string, string>;
226
- }>;
227
- }
228
-
229
- interface ApiDeleteResponse {
230
- files?: Array<{ path?: string; status?: string; etag?: string }>;
231
- }
232
-
233
- /**
234
- * Per-op outcome from the factory store API's `flush` route, index-aligned
235
- * with the request ops. A put answers `url`/`headers`; a delete answers
236
- * `status`; declared loosely for the same additive-change reason as the
237
- * `/v0` shapes above.
238
- */
239
- interface FlushWireOpOutcome {
240
- path?: string;
241
- url?: string;
242
- headers?: Record<string, string>;
243
- error?: string;
244
- status?: string;
245
- etag?: string;
246
- }
247
-
248
- interface FlushWireResponse {
249
- ops?: FlushWireOpOutcome[];
250
- }
251
-
252
- type HostedFilesMethods = Omit<FileSink, "get" | "getMany"> & {
253
- /** Narrower than {@link FileSink.get}: this backend always reports the etag. */
254
- get(key: string): Promise<FileSinkBody | undefined>;
255
- /** Always present here (and narrowed like {@link get}); optional on {@link FileSink}. */
256
- getMany(keys: readonly string[]): Promise<Array<FileSinkBody | undefined>>;
257
- };
258
-
259
- /**
260
- * Cursor-hosted {@link FileSink}, selected on Cursor-managed hosting.
261
- *
262
- * Stateless apart from the etag cache below: every request names this
263
- * deployment's store by its pinned source id, so there is nothing to
264
- * resolve, hold, or invalidate.
265
- */
266
- export function cursorHostedFiles(options: CursorHostedFilesOptions = {}): HostedFilesMethods {
267
- /**
268
- * Etags observed per key, so a replace can carry a precondition without
269
- * re-reading. Bounded: a resident engine is long-lived and touches an
270
- * unbounded number of keys over its lifetime. Oldest-out is fine — a miss
271
- * costs one lookup, not correctness.
272
- */
273
- const observedEtags = new Map<string, string>();
274
- const rememberEtag = (key: string, etag: string): void => {
275
- if (observedEtags.size >= MAX_REMEMBERED_ETAGS) {
276
- const oldest = observedEtags.keys().next();
277
- if (!oldest.done) {
278
- observedEtags.delete(oldest.value);
279
- }
280
- }
281
- observedEtags.set(key, etag);
282
- };
283
-
284
- /**
285
- * Run `call` against this deployment's files.
286
- *
287
- * No network call and nothing cached: the store source id and protocol pin
288
- * come from the environment (or task-bound files) and the server maps them
289
- * on every request. Resolved per call rather than once at construction so a
290
- * misconfigured environment fails where the operation is, not where the
291
- * sink was created — and so a protocol pin bound after serve start takes
292
- * effect without a restart.
293
- */
294
- async function withFiles<T>(call: (files: FilesTarget) => Promise<T>): Promise<T> {
295
- const sourceId = resolveStoreSourceId(options);
296
- const protocol = options.resolveStoreProtocol?.() ?? resolveStoreProtocolSync();
297
- if (storeProtocolEnablesFactoryFlush(protocol)) {
298
- // The factory API addresses stores by role, so map the pinned source id
299
- // back to the role it was pinned from. A source id matching neither (a
300
- // local-dev override) has no role there and stays on `/v0`, as does any
301
- // protocol value this runtime does not recognize.
302
- if (sourceId === resolveFrameworkStoreSourceIdSync()) {
303
- return await call({ wire: "flush", store: "framework" });
304
- }
305
- if (sourceId === resolveDeploymentStoreSourceIdSync()) {
306
- return await call({ wire: "flush", store: "deployment" });
307
- }
308
- }
309
- return await call({
310
- wire: "v0",
311
- path: (suffix = "") => `/${encodeURIComponent(sourceId)}${suffix}`,
312
- });
313
- }
314
-
315
- /**
316
- * Fetch one presigned read URL, shared by `get` and `getMany`. A 404 on
317
- * the object GET is absence (a delete raced the presign).
318
- *
319
- * A 403 here is deliberately *not* absence. Absence was already settled
320
- * by the presign: the store refuses to presign a path with no live
321
- * object, so reaching this point means the object existed moments ago.
322
- * What produces a 403 after a good presign is an expired or clock-skewed
323
- * signature, a policy change, or a delete that raced the GET — all
324
- * transient or retryable, none of them "definitively gone".
325
- *
326
- * Reporting them as absence is how a store blip becomes data loss:
327
- * `undefined` on a continuation read is taken as "unknown token", and
328
- * the engine mints a fresh session under it, forking the thread. The
329
- * delete race resolves itself on retry, where the presign returns 404
330
- * and this correctly reads as a miss.
331
- */
332
- async function downloadPresigned(key: string, url: string): Promise<FileSinkBody | undefined> {
333
- const response = await resolveCursorApiFetch(options)(assertPresignedUrlSafe(options, url), {
334
- method: "GET",
335
- redirect: "manual",
336
- });
337
- if (response.status === 404) {
338
- return undefined;
339
- }
340
- if (!response.ok) {
341
- throw new Error(`cursorHostedFiles: download of "${key}" failed (HTTP ${response.status})`);
342
- }
343
- const etag = normalizeEtag(response.headers.get("etag"));
344
- if (etag !== undefined) {
345
- rememberEtag(key, etag);
346
- }
347
- return {
348
- body: new Uint8Array(await response.arrayBuffer()),
349
- ...(etag === undefined ? {} : { etag }),
350
- };
351
- }
352
-
353
- /** One page of the paginated per-directory listing. */
354
- async function directoryPage(
355
- files: FilesTarget,
356
- directory: string,
357
- pageToken: string | undefined,
358
- ): Promise<ApiFileListing> {
359
- if (files.wire === "flush") {
360
- return await flushPost<ApiFileListing>(options, "/list", {
361
- store: files.store,
362
- path: directory,
363
- limit: DIRECTORY_PAGE_SIZE,
364
- ...(pageToken === undefined ? {} : { pageToken }),
365
- });
366
- }
367
- const query = new URLSearchParams({
368
- path: directory,
369
- limit: String(DIRECTORY_PAGE_SIZE),
370
- });
371
- if (pageToken !== undefined) {
372
- query.set("pageToken", pageToken);
373
- }
374
- return await storeGet<ApiFileListing>(options, files.path(`?${query.toString()}`));
375
- }
376
-
377
- /** The unscoped whole-store listing, on whichever wire the target rides. */
378
- async function unscopedListing(files: FilesTarget): Promise<ApiFileListing> {
379
- if (files.wire === "flush") {
380
- return await flushPost<ApiFileListing>(options, "/list", {
381
- store: files.store,
382
- });
383
- }
384
- return await storeGet<ApiFileListing>(options, files.path());
385
- }
386
-
387
- async function listEntries(prefix: string): Promise<FileSinkEntry[]> {
388
- return await withFiles(async files => {
389
- const raw = await unscopedListing(files);
390
- if (raw.complete === true) {
391
- const out: FileSinkEntry[] = [];
392
- for (const file of raw.files ?? []) {
393
- if (typeof file.path !== "string" || !file.path.startsWith(prefix)) {
394
- continue;
395
- }
396
- out.push(toEntry(file, file.path));
397
- }
398
- // The FileSink contract promises key order, and transcript-chunk
399
- // consumers depend on it (chunk keys are zero-padded so key order
400
- // is append order). The server happens to scan in order today; do
401
- // not let that be the only thing holding the contract.
402
- return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
403
- }
404
- // The unscoped listing was truncated (`complete: false`) and has no
405
- // continuation to follow. `list()` promises the whole scope, so rather
406
- // than lie or fail, walk the paginated per-directory form, which does
407
- // paginate and reports immediate subdirectories to recurse into.
408
- return await walkDirectoryTree(files, prefix);
409
- });
410
- }
411
-
412
- /**
413
- * Every entry under `prefix`, via the paginated directory listing.
414
- *
415
- * Starts at the deepest directory the prefix fully names and descends only
416
- * into subdirectories that can still hold matches. Bounded so a runaway
417
- * store fails loudly rather than returning a silently partial answer the
418
- * caller would mistake for the whole scope.
419
- */
420
- async function walkDirectoryTree(files: FilesTarget, prefix: string): Promise<FileSinkEntry[]> {
421
- const slash = prefix.lastIndexOf("/");
422
- const pending: string[] = [slash === -1 ? "" : prefix.slice(0, slash)];
423
- const queued = new Set<string>(pending);
424
- const out: FileSinkEntry[] = [];
425
- let pageBudget = MAX_LIST_WALK_PAGES;
426
- while (pending.length > 0) {
427
- const directory = pending.pop() as string;
428
- let pageToken: string | undefined;
429
- do {
430
- if (pageBudget <= 0) {
431
- throw new Error(
432
- "cursorHostedFiles: the store is too large to list; scope the listing with a narrower prefix",
433
- );
434
- }
435
- pageBudget -= 1;
436
- const page = await directoryPage(files, directory, pageToken);
437
- for (const file of page.files ?? []) {
438
- if (typeof file.path === "string" && file.path.startsWith(prefix)) {
439
- out.push(toEntry(file, file.path));
440
- }
441
- }
442
- // Every page can surface different subdirectories, so collect from
443
- // all of them, deduped — and descend only into branches that can
444
- // still hold matches: a descendant of the prefix, or (at the first
445
- // level) a directory the prefix's basename component narrows to.
446
- for (const subdir of page.directories ?? []) {
447
- if (queued.has(subdir)) {
448
- continue;
449
- }
450
- if (`${subdir}/`.startsWith(prefix) || prefix.startsWith(`${subdir}/`)) {
451
- queued.add(subdir);
452
- pending.push(subdir);
453
- }
454
- }
455
- pageToken =
456
- page.complete === false && page.nextPageToken !== undefined
457
- ? page.nextPageToken
458
- : undefined;
459
- } while (pageToken !== undefined);
460
- }
461
- return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
462
- }
463
-
464
- /** Shared decode: remember the etag as a side effect, then shape the entry. */
465
- function toEntry(file: ApiFile, key: string): FileSinkEntry {
466
- if (typeof file.etag === "string" && file.etag !== "") {
467
- rememberEtag(key, file.etag);
468
- }
469
- const mtimeMs = typeof file.updatedAt === "string" ? Date.parse(file.updatedAt) : undefined;
470
- return {
471
- key,
472
- size: typeof file.sizeBytes === "number" ? file.sizeBytes : 0,
473
- ...(typeof file.etag === "string" && file.etag !== "" ? { etag: file.etag } : {}),
474
- ...(mtimeMs === undefined || Number.isNaN(mtimeMs) ? {} : { mtimeMs }),
475
- };
476
- }
477
-
478
- /**
479
- * One key's current entry, via the bounded directory listing.
480
- *
481
- * The unscoped listing has no prefix parameter, so using it for a point lookup
482
- * would walk the whole store on the hot write path and cost more the fuller
483
- * the store got. `?path=` is scoped to one directory and paginates, and the
484
- * scan stops as soon as the key appears.
485
- */
486
- async function statKey(key: string): Promise<FileSinkEntry | undefined> {
487
- const slash = key.lastIndexOf("/");
488
- const directory = slash === -1 ? "" : key.slice(0, slash);
489
- return await withFiles(async files => {
490
- let pageToken: string | undefined;
491
- for (let page = 0; page < MAX_DIRECTORY_PAGES; page += 1) {
492
- const raw = await directoryPage(files, directory, pageToken);
493
- for (const file of raw.files ?? []) {
494
- if (file.path === key) {
495
- return toEntry(file, key);
496
- }
497
- }
498
- // `complete` is false exactly when another page is waiting.
499
- if (raw.complete !== false || raw.nextPageToken === undefined) {
500
- return undefined;
501
- }
502
- pageToken = raw.nextPageToken;
503
- }
504
- return undefined;
505
- });
506
- }
507
-
508
- /** One key's share of a (possibly multi-file) upload attempt. */
509
- type UploadSpec = {
510
- key: string;
511
- body: Uint8Array;
512
- precondition: { etag: string } | { new: true };
513
- };
514
- type UploadOutcome =
515
- | { status: "ok"; result: FileSinkPutResult }
516
- | { status: "conflict" }
517
- | { status: "error"; error: unknown };
518
-
519
- /**
520
- * The shared presign for one upload attempt: a `/v0` upload POST, or one
521
- * flush request whose put outcomes are reshaped into the same instruction
522
- * list (an outcome without a `url` — an oversize refusal — surfaces exactly
523
- * like a `/v0` multipart answer: no single-part instruction for that key).
524
- */
525
- async function presignUploads(
526
- files: FilesTarget,
527
- specs: UploadSpec[],
528
- ): Promise<ApiPresignResponse> {
529
- if (files.wire === "flush") {
530
- const response = await flushPost<FlushWireResponse>(options, "/flush", {
531
- store: files.store,
532
- ops: specs.map(spec => ({
533
- op: "put",
534
- path: spec.key,
535
- sha: createHash("sha256").update(spec.body).digest("hex"),
536
- size: spec.body.byteLength,
537
- ...spec.precondition,
538
- })),
539
- });
540
- // Index-aligned with the request ops, entries without a `url` included:
541
- // a refused op (oversize) must keep its slot so the by-path/positional
542
- // instruction matching below cannot hand its sibling's presign to it,
543
- // and the missing url surfaces as that key's own error.
544
- return {
545
- files: (response.ops ?? []).map(op => ({
546
- path: op.path,
547
- ...(typeof op.url === "string" && op.url !== "" ? { url: op.url } : {}),
548
- headers: op.headers,
549
- })),
550
- };
551
- }
552
- return await storePost<ApiPresignResponse>(options, files.path("/upload"), {
553
- files: specs.map(spec => ({
554
- path: spec.key,
555
- sha: createHash("sha256").update(spec.body).digest("hex"),
556
- size: spec.body.byteLength,
557
- ...spec.precondition,
558
- })),
559
- });
560
- }
561
-
562
- /**
563
- * One presign call covering every spec, then parallel presigned PUTs.
564
- * Outcomes are per spec: a 412 ("conflict") or a failed PUT for one key
565
- * never disturbs its batch siblings. Only the presign itself is shared —
566
- * a presign error throws and fails the whole attempt.
567
- */
568
- async function attemptUploads(files: FilesTarget, specs: UploadSpec[]): Promise<UploadOutcome[]> {
569
- const presigned = await presignUploads(files, specs);
570
- return await Promise.all(
571
- specs.map(async (spec, index): Promise<UploadOutcome> => {
572
- // Match by path, falling back to position for servers that answer
573
- // in request order without echoing the path.
574
- const instruction =
575
- presigned.files?.find(file => file.path === spec.key) ?? presigned.files?.[index];
576
- if (instruction?.url === undefined) {
577
- // Files past the single-part threshold come back with a multipart
578
- // plan instead of a url; this backend does not implement multipart.
579
- return {
580
- status: "error",
581
- error: new Error(
582
- `cursorHostedFiles: no single-part upload url for "${spec.key}" (too large?)`,
583
- ),
584
- };
585
- }
586
- try {
587
- const response = await resolveCursorApiFetch(options)(
588
- assertPresignedUrlSafe(options, instruction.url),
589
- {
590
- method: "PUT",
591
- headers: instruction.headers ?? {},
592
- // A view over bytes is a valid fetch body; the DOM lib types
593
- // are narrower than the runtime, and copying into a Blob would
594
- // double the memory for every upload.
595
- body: spec.body as unknown as BodyInit,
596
- // A redirect would re-send the body somewhere the presign did
597
- // not authorize.
598
- redirect: "manual",
599
- },
600
- );
601
- if (response.status === 412) {
602
- observedEtags.delete(spec.key);
603
- return { status: "conflict" };
604
- }
605
- if (!response.ok) {
606
- return {
607
- status: "error",
608
- error: new Error(
609
- `cursorHostedFiles: upload of "${spec.key}" failed (HTTP ${response.status})`,
610
- ),
611
- };
612
- }
613
- const etag = normalizeEtag(response.headers.get("etag"));
614
- if (etag !== undefined) {
615
- rememberEtag(spec.key, etag);
616
- }
617
- return { status: "ok", result: etag === undefined ? {} : { etag } };
618
- } catch (error) {
619
- return { status: "error", error };
620
- }
621
- }),
622
- );
623
- }
624
-
625
- /**
626
- * The full single-key write flow: precondition resolution, one shared
627
- * (already-performed) first attempt outcome, and the conflict handling
628
- * `put` promises — including the one statKey-and-retry when an optimistic
629
- * create loses to an existing object.
630
- */
631
- async function settlePut(
632
- files: FilesTarget,
633
- entry: {
634
- key: string;
635
- body: Uint8Array;
636
- options?: { ifMatch?: string | null };
637
- cachedEtagUsed?: boolean;
638
- staleEtag?: string;
639
- },
640
- first: UploadOutcome,
641
- ): Promise<FileSinkPutResult> {
642
- if (first.status === "error") {
643
- throw first.error;
644
- }
645
- if (first.status === "ok") {
646
- return first.result;
647
- }
648
- // Conflict. Explicit `ifMatch` (etag or create-only) and cached-etag
649
- // writes are single-attempt: the lost precondition is the caller's.
650
- const requested = entry.options?.ifMatch;
651
- if (requested !== undefined) {
652
- throw new FileConflictError(entry.key, {
653
- storedEtag: requested ?? undefined,
654
- });
655
- }
656
- if (entry.cachedEtagUsed === true) {
657
- // Someone else wrote between our etag observation and this PUT.
658
- throw new FileConflictError(entry.key, { storedEtag: entry.staleEtag });
659
- }
660
- // The optimistic create lost: learn the current etag once and replace.
661
- const found = await statKey(entry.key);
662
- if (found?.etag === undefined) {
663
- // Existed a moment ago (the create lost) but stat sees nothing: a
664
- // delete raced this write. Surface the conflict; a retry from the
665
- // caller lands on the fresh create-only path.
666
- throw new FileConflictError(entry.key, {});
667
- }
668
- const [replaced] = await attemptUploads(files, [
669
- { key: entry.key, body: entry.body, precondition: { etag: found.etag } },
670
- ]);
671
- if (replaced === undefined || replaced.status === "conflict") {
672
- throw new FileConflictError(entry.key, { storedEtag: found?.etag });
673
- }
674
- if (replaced.status === "error") {
675
- throw replaced.error;
676
- }
677
- return replaced.result;
678
- }
679
-
680
- /**
681
- * Precondition for a write, and whether it came from the etag cache (a
682
- * cached-etag conflict is terminal; an optimistic-create conflict earns
683
- * one stat-and-retry).
684
- */
685
- function preconditionFor(entry: { key: string; options?: { ifMatch?: string | null } }): {
686
- precondition: { etag: string } | { new: true };
687
- cachedEtagUsed: boolean;
688
- staleEtag?: string;
689
- } {
690
- const requested = entry.options?.ifMatch;
691
- // The store rejects unconditional writes, so every put carries a
692
- // precondition. `null` is create-only and an explicit etag is a caller
693
- // assertion.
694
- if (requested !== undefined) {
695
- return {
696
- precondition: requested === null ? { new: true } : { etag: requested },
697
- cachedEtagUsed: false,
698
- };
699
- }
700
- // Unconditional write with a known etag: replace what we saw last.
701
- const cached = observedEtags.get(entry.key);
702
- if (cached !== undefined) {
703
- return {
704
- precondition: { etag: cached },
705
- cachedEtagUsed: true,
706
- staleEtag: cached,
707
- };
708
- }
709
- // Unconditional write to a key this process has never observed:
710
- // create-only first, learning the current etag only on conflict. Most
711
- // such writes are brand-new keys (session-event chunks mint a fresh key
712
- // per flush), and the old stat-before-every-put shape made the
713
- // precondition lookup the single largest source of `agent-serve-files`
714
- // list traffic — every fresh pod re-listed a directory per key before
715
- // its first write.
716
- return { precondition: { new: true }, cachedEtagUsed: false };
717
- }
718
-
719
- return {
720
- // No local copy: bytes live in the store, so `materializedPath()` is
721
- // `undefined` and the harness reaches files through `host.files`.
722
- capabilities: { etags: true },
723
-
724
- async put(key, body, putOptions): Promise<FileSinkPutResult> {
725
- return await withFiles(async files => {
726
- const entry = { key, body, options: putOptions };
727
- const resolved = preconditionFor(entry);
728
- const [first] = await attemptUploads(files, [
729
- { key, body, precondition: resolved.precondition },
730
- ]);
731
- if (first === undefined) {
732
- throw new Error(`cursorHostedFiles: upload of "${key}" vanished`);
733
- }
734
- return await settlePut(
735
- files,
736
- {
737
- ...entry,
738
- cachedEtagUsed: resolved.cachedEtagUsed,
739
- staleEtag: resolved.staleEtag,
740
- },
741
- first,
742
- );
743
- });
744
- },
745
-
746
- async putMany(entries) {
747
- if (entries.length === 0) {
748
- return [];
749
- }
750
- return await withFiles(async files => {
751
- const resolved = entries.map(entry => ({
752
- entry,
753
- ...preconditionFor(entry),
754
- }));
755
- let firsts: UploadOutcome[];
756
- try {
757
- // One presign call for the whole batch — the point of putMany.
758
- firsts = await attemptUploads(
759
- files,
760
- resolved.map(({ entry, precondition }) => ({
761
- key: entry.key,
762
- body: entry.body,
763
- precondition,
764
- })),
765
- );
766
- } catch (error) {
767
- // The shared presign failed: every entry failed the same way.
768
- return entries.map(() => ({
769
- status: "rejected" as const,
770
- reason: error,
771
- }));
772
- }
773
- return await Promise.all(
774
- resolved.map(
775
- async (
776
- { entry, cachedEtagUsed, staleEtag },
777
- index,
778
- ): Promise<PromiseSettledResult<FileSinkPutResult>> => {
779
- const first = firsts[index];
780
- if (first === undefined) {
781
- return {
782
- status: "rejected",
783
- reason: new Error(`cursorHostedFiles: upload of "${entry.key}" vanished`),
784
- };
785
- }
786
- try {
787
- return {
788
- status: "fulfilled",
789
- value: await settlePut(files, { ...entry, cachedEtagUsed, staleEtag }, first),
790
- };
791
- } catch (error) {
792
- return { status: "rejected", reason: error };
793
- }
794
- },
795
- ),
796
- );
797
- });
798
- },
799
-
800
- async get(key): Promise<FileSinkBody | undefined> {
801
- return await withFiles(async files => {
802
- // Presigning a read of a path the store has no live object for — never
803
- // written, or deleted and now holding a tombstone — is a 404 on `/v0`
804
- // and an absent entry on the flush wire. Either is absence, which
805
- // `read()` reports as undefined, not a failure.
806
- let presigned: ApiPresignResponse;
807
- try {
808
- presigned =
809
- files.wire === "flush"
810
- ? await flushPost<ApiPresignResponse>(options, "/read", {
811
- store: files.store,
812
- paths: [key],
813
- })
814
- : await storePost<ApiPresignResponse>(options, files.path("/download"), {
815
- paths: [key],
816
- });
817
- } catch (error) {
818
- if (error instanceof StoreApiError && error.status === 404) {
819
- return undefined;
820
- }
821
- throw error;
822
- }
823
- const url = presigned.files?.[0]?.url;
824
- if (url === undefined) {
825
- return undefined;
826
- }
827
- return await downloadPresigned(key, url);
828
- });
829
- },
830
-
831
- async getMany(keys): Promise<Array<FileSinkBody | undefined>> {
832
- if (keys.length === 0) {
833
- return [];
834
- }
835
- const bodies = await withFiles(async files => {
836
- if (files.wire !== "flush") {
837
- // `/v0` presigns 404 the whole batch when any path is absent, so a
838
- // batched call cannot tell one missing key from a failed request.
839
- // Bounded per-key gets keep the `/v0` absence semantics exact; the
840
- // batch win belongs to the flush wire, whose contract is "an absent
841
- // path is an absent entry" — and whose per-deployment rate limiter
842
- // is the reason to spend fewer requests in the first place.
843
- return await mapBounded([...keys], GET_MANY_DOWNLOAD_CONCURRENCY, async key => {
844
- const presigned = await storePost<ApiPresignResponse>(
845
- options,
846
- files.path("/download"),
847
- { paths: [key] },
848
- ).catch((error: unknown) => {
849
- if (error instanceof StoreApiError && error.status === 404) {
850
- return undefined;
851
- }
852
- throw error;
853
- });
854
- const url = presigned?.files?.[0]?.url;
855
- if (url === undefined) {
856
- return undefined;
857
- }
858
- return await downloadPresigned(key, url);
859
- });
860
- }
861
- const urls = new Map<string, string>();
862
- for (let from = 0; from < keys.length; from += READ_PRESIGN_BATCH_MAX) {
863
- const chunk = keys.slice(from, from + READ_PRESIGN_BATCH_MAX);
864
- let presigned: ApiPresignResponse;
865
- try {
866
- presigned = await flushPost<ApiPresignResponse>(options, "/read", {
867
- store: files.store,
868
- paths: chunk,
869
- });
870
- } catch (error) {
871
- if (error instanceof StoreApiError && error.status === 404) {
872
- // The read route never 404s per path (absent paths are
873
- // omitted entries); a 404 is the store itself — not
874
- // provisioned, or deleted under us — which get() reads as
875
- // absence for every key.
876
- return keys.map(() => undefined);
877
- }
878
- throw error;
879
- }
880
- for (const entry of presigned.files ?? []) {
881
- if (entry.path !== undefined && entry.url !== undefined) {
882
- urls.set(entry.path, entry.url);
883
- }
884
- }
885
- }
886
- return await mapBounded([...keys], GET_MANY_DOWNLOAD_CONCURRENCY, async key => {
887
- const url = urls.get(key);
888
- if (url !== undefined) {
889
- return await downloadPresigned(key, url);
890
- }
891
- // A miss in the batch is NOT yet a definitive absence: the
892
- // server echoes each path *normalized* (trimmed, backslashes
893
- // folded, empty/"." segments dropped), so a key whose
894
- // normalized form differs from what was sent never matches the
895
- // echo even though its object exists. `get()` is immune (it
896
- // reads the response positionally), so settle every batch miss
897
- // through the single-path read — keeping getMany's absence
898
- // semantics byte-identical to get()'s. Genuine absences pay one
899
- // extra request; every batch caller reads keys it just listed
900
- // or was told exist, so real misses are rare (delete races,
901
- // store loss).
902
- const presigned = await flushPost<ApiPresignResponse>(options, "/read", {
903
- store: files.store,
904
- paths: [key],
905
- }).catch((error: unknown) => {
906
- // Store-level 404 (deleted between the batch and this read):
907
- // absence, same as get().
908
- if (error instanceof StoreApiError && error.status === 404) {
909
- return undefined;
910
- }
911
- throw error;
912
- });
913
- const singleUrl = presigned?.files?.[0]?.url;
914
- if (singleUrl === undefined) {
915
- return undefined;
916
- }
917
- return await downloadPresigned(key, singleUrl);
918
- });
919
- });
920
- return bodies;
921
- },
922
-
923
- async delete(key): Promise<void> {
924
- const handled = await withFiles(async files => {
925
- if (files.wire !== "flush") {
926
- return false;
927
- }
928
- // With an observed etag the flush delete is If-Match on that version.
929
- // Without one, the server tombstones whatever live object occupies
930
- // the key (no directory walk here) and an absent key settles as
931
- // `already_deleted`.
932
- const cached = observedEtags.get(key);
933
- const response = await flushPost<FlushWireResponse>(options, "/flush", {
934
- store: files.store,
935
- ops: [
936
- {
937
- op: "delete",
938
- path: key,
939
- ...(cached === undefined ? {} : { etag: cached }),
940
- },
941
- ],
942
- });
943
- const outcome = response.ops?.[0];
944
- if (outcome?.status === "conflict") {
945
- observedEtags.delete(key);
946
- throw new FileConflictError(key, {
947
- ...(outcome.etag === undefined
948
- ? {}
949
- : { storedEtag: normalizeEtag(outcome.etag) ?? outcome.etag }),
950
- });
951
- }
952
- observedEtags.delete(key);
953
- return true;
954
- });
955
- if (handled) {
956
- return;
957
- }
958
- if (observedEtags.get(key) === undefined) {
959
- // Deletes are conditional too, so learn the current etag first. A key
960
- // we have never seen is already absent as far as the caller cares.
961
- const found = await statKey(key);
962
- if (found?.etag === undefined) {
963
- return;
964
- }
965
- }
966
- const etag = observedEtags.get(key);
967
- if (etag === undefined) {
968
- return;
969
- }
970
- await withFiles(async files => {
971
- if (files.wire === "flush") {
972
- // The protocol pin appeared between the two withFiles calls; the
973
- // cached etag is enough for the conditional flush delete.
974
- const response = await flushPost<FlushWireResponse>(options, "/flush", {
975
- store: files.store,
976
- ops: [{ op: "delete", path: key, etag }],
977
- });
978
- const outcome = response.ops?.[0];
979
- if (outcome?.status === "conflict") {
980
- observedEtags.delete(key);
981
- throw new FileConflictError(key, {
982
- ...(outcome.etag === undefined
983
- ? {}
984
- : { storedEtag: normalizeEtag(outcome.etag) ?? outcome.etag }),
985
- });
986
- }
987
- return;
988
- }
989
- const raw = await storePost<ApiDeleteResponse>(options, files.path("/delete"), {
990
- files: [{ path: key, etag }],
991
- });
992
- // The API answers 200 with a per-file status, so a lost race would look
993
- // like success unless the outcome is read.
994
- const outcome = (raw.files ?? []).find(entry => entry.path === key);
995
- if (outcome?.status === "conflict") {
996
- observedEtags.delete(key);
997
- throw new FileConflictError(key, {
998
- ...(outcome.etag === undefined
999
- ? {}
1000
- : { storedEtag: normalizeEtag(outcome.etag) ?? outcome.etag }),
1001
- });
1002
- }
1003
- });
1004
- observedEtags.delete(key);
1005
- },
1006
-
1007
- list: listEntries,
1008
-
1009
- async stat(key): Promise<FileSinkEntry | undefined> {
1010
- return await statKey(key);
1011
- },
1012
- };
1013
- }
1014
-
1015
- /**
1016
- * Refuse a presigned URL that does not target this backend's agent-stores
1017
- * bucket.
1018
- *
1019
- * The URL arrives from BCS over TLS, so this is defense in depth rather than
1020
- * a live hole — but the engine pod can reach link-local metadata and other
1021
- * allowlisted egress hosts, so a BCS bug or compromise returning a foreign
1022
- * address would otherwise steer file bytes somewhere the caller never chose.
1023
- * Same pin as the sibling sync client: production backends allow only the
1024
- * agent-stores bucket hosts, playground its bucket, and a local dev backend
1025
- * additionally admits loopback http for LocalStack.
1026
- *
1027
- * `CURSOR_HOSTED_FILES_DEV_PRESIGN_HOSTS` (comma-separated hostnames) admits
1028
- * extra https hosts. A laptop backend hosting agents on a shared cluster
1029
- * fronts its LocalStack with a public tunnel and exports this in the pod's
1030
- * start script; production start scripts never set it. Read once at module
1031
- * load, so authored agent code sharing this process cannot widen the list
1032
- * by mutating `process.env` later.
1033
- */
1034
- function assertPresignedUrlSafe(options: CursorHostedFilesOptions, raw: string): string {
1035
- let url: URL;
1036
- try {
1037
- url = new URL(raw);
1038
- } catch {
1039
- throw new Error("cursorHostedFiles: presigned URL is not a valid URL");
1040
- }
1041
- if (
1042
- url.protocol === "https:" &&
1043
- url.username === "" &&
1044
- url.password === "" &&
1045
- DEV_PRESIGN_HOSTS.has(url.hostname.toLowerCase())
1046
- ) {
1047
- return url.toString();
1048
- }
1049
- try {
1050
- createAgentStorePresignedUrlValidatorForBackend(resolveCursorApiBaseUrl(options))(url);
1051
- } catch (error) {
1052
- throw new Error(
1053
- `cursorHostedFiles: refused presigned URL: ${
1054
- error instanceof Error ? error.message : String(error)
1055
- }`,
1056
- );
1057
- }
1058
- return url.toString();
1059
- }
1060
-
1061
- /**
1062
- * The file store this engine's deployment owns. Every request names it, so
1063
- * the server resolves the store row and this process never handles a store id.
1064
- *
1065
- * Fails loudly rather than defaulting: with no source id there is no store to
1066
- * address, and writing somewhere else silently is worse than not writing.
1067
- */
1068
- function resolveStoreSourceId(options: CursorHostedFilesOptions): string {
1069
- const id = (
1070
- options.resolveStoreSourceId?.() ??
1071
- options.storeSourceId ??
1072
- resolveDeploymentStoreSourceIdSync(process.env)
1073
- )?.trim();
1074
- if (id === undefined || id === "") {
1075
- throw new Error(
1076
- `cursorHostedFiles requires ${AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR} (set on Cursor-managed deployments)`,
1077
- );
1078
- }
1079
- return id;
1080
- }
1081
-
1082
- const DEV_PRESIGN_HOSTS: ReadonlySet<string> = new Set(
1083
- (process.env.CURSOR_HOSTED_FILES_DEV_PRESIGN_HOSTS ?? "")
1084
- .split(",")
1085
- .map(host => host.trim().toLowerCase())
1086
- .filter(host => host.length > 0),
1087
- );
1088
-
1089
- /**
1090
- * Public agent-serve-files API call. The pod credential is the whole authorization:
1091
- * the API forwards this caller's identity to the store service, which checks it
1092
- * against the store's live owner. There is no second, narrower credential.
1093
- */
1094
- async function storePost<T>(
1095
- options: CursorHostedFilesOptions,
1096
- path: string,
1097
- body: Record<string, unknown>,
1098
- ): Promise<T> {
1099
- return await postJson<T>(
1100
- options,
1101
- `${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`,
1102
- body,
1103
- );
1104
- }
1105
-
1106
- async function storeGet<T>(options: CursorHostedFilesOptions, path: string): Promise<T> {
1107
- return await sendJson<T>(
1108
- options,
1109
- `${resolveCursorApiBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`,
1110
- "GET",
1111
- );
1112
- }
1113
-
1114
- /**
1115
- * Factory store API call — same base URL and pod credential as
1116
- * {@link storePost}, different path family. The server resolves the
1117
- * deployment (and the addressed store role) from the credential. The
1118
- * domain-call lane one path family deeper is NOT here: it belongs to the
1119
- * store API client (`../internal/cursor/store-api-client.ts`).
1120
- */
1121
- async function flushPost<T>(
1122
- options: CursorHostedFilesOptions,
1123
- path: string,
1124
- body: Record<string, unknown>,
1125
- ): Promise<T> {
1126
- return await postJson<T>(
1127
- options,
1128
- `${resolveCursorApiBaseUrl(options)}${AGENTSDK_STORE_PATH}${path}`,
1129
- body,
1130
- );
1131
- }
1132
-
1133
- async function postJson<T>(
1134
- options: CursorHostedFilesOptions,
1135
- url: string,
1136
- body: Record<string, unknown>,
1137
- ): Promise<T> {
1138
- return await sendJson<T>(options, url, "POST", body);
1139
- }
1140
-
1141
- async function sendJson<T>(
1142
- options: CursorHostedFilesOptions,
1143
- url: string,
1144
- method: "GET" | "POST",
1145
- body?: Record<string, unknown>,
1146
- ): Promise<T> {
1147
- const response = await resolveCursorApiFetch(options)(url, {
1148
- method,
1149
- headers: {
1150
- Authorization: `Bearer ${resolveCursorApiKey(options)}`,
1151
- ...(body === undefined ? {} : { "Content-Type": "application/json" }),
1152
- },
1153
- ...(body === undefined ? {} : { body: JSON.stringify(body) }),
1154
- });
1155
- const text = await response.text();
1156
- let parsed: unknown;
1157
- try {
1158
- parsed = text.length === 0 ? {} : JSON.parse(text);
1159
- } catch {
1160
- throw new Error(`cursorHostedFiles ${url} returned non-JSON (${response.status})`);
1161
- }
1162
- if (!response.ok) {
1163
- throw new StoreApiError(
1164
- response.status,
1165
- `cursorHostedFiles ${url}: ${describeError(parsed, response.status)}`,
1166
- );
1167
- }
1168
- return parsed as T;
1169
- }
1170
-
1171
- /**
1172
- * A non-2xx answer from the files API, carrying the status so a caller can
1173
- * tell "absent" apart from a failure it must not swallow.
1174
- */
1175
- class StoreApiError extends Error {
1176
- constructor(
1177
- readonly status: number,
1178
- message: string,
1179
- ) {
1180
- super(message);
1181
- this.name = "StoreApiError";
1182
- }
1183
- }
1184
-
1185
- function describeError(parsed: unknown, status: number): string {
1186
- if (
1187
- parsed !== null &&
1188
- typeof parsed === "object" &&
1189
- "error" in parsed &&
1190
- typeof (parsed as { error: unknown }).error === "string"
1191
- ) {
1192
- return (parsed as { error: string }).error;
1193
- }
1194
- if (
1195
- parsed !== null &&
1196
- typeof parsed === "object" &&
1197
- "message" in parsed &&
1198
- typeof (parsed as { message: unknown }).message === "string"
1199
- ) {
1200
- return (parsed as { message: string }).message;
1201
- }
1202
- return `HTTP ${status}`;
1203
- }
1204
-
1205
- /** S3 returns quoted etags; the store compares them unquoted. */
1206
- function normalizeEtag(raw: string | null): string | undefined {
1207
- if (raw === null) {
1208
- return undefined;
1209
- }
1210
- const trimmed = raw.trim().replace(/^"+|"+$/g, "");
1211
- return trimmed === "" ? undefined : trimmed;
1212
- }