@cursor/july 0.1.29 → 0.1.31

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 (392) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +10 -5
  3. package/dist/bin/agent-serve.js +4 -4
  4. package/dist/channels/github/index.d.ts +1 -1
  5. package/dist/channels/github/index.js +1 -1
  6. package/dist/channels/slack/bot-mentions.d.ts +1 -1
  7. package/dist/channels/slack/bot-mentions.d.ts.map +1 -1
  8. package/dist/channels/slack/bot-mentions.js +1 -1
  9. package/dist/channels/slack/eval-directive.js +1 -1
  10. package/dist/channels/slack/external-policy.d.ts +1 -1
  11. package/dist/channels/slack/external-policy.js +1 -1
  12. package/dist/channels/slack/log.d.ts +1 -1
  13. package/dist/channels/slack/log.js +1 -1
  14. package/dist/channels/slack/setup.js +1 -1
  15. package/dist/channels/slack/socket-mode.js +1 -1
  16. package/dist/docs/404.html +3 -3
  17. package/dist/docs/ab.html +11 -11
  18. package/dist/docs/assets/{ab.md.BMCZ6Hd7.js → ab.md.DAQoJ-up.js} +6 -6
  19. package/dist/docs/assets/{ab.md.BMCZ6Hd7.lean.js → ab.md.DAQoJ-up.lean.js} +1 -1
  20. package/dist/docs/assets/{app.QdunVQKg.js → app.DigB_9cQ.js} +1 -1
  21. package/dist/docs/assets/building-with-agents.md.CnHqvYDd.js +13 -0
  22. package/dist/docs/assets/{building-with-agents.md.CJCtZCyi.lean.js → building-with-agents.md.CnHqvYDd.lean.js} +1 -1
  23. package/dist/docs/assets/chunks/@localSearchIndexroot.CnFFl07y.js +1 -0
  24. package/dist/docs/assets/chunks/{VPLocalSearchBox.B6EpUXYf.js → VPLocalSearchBox.BCMX25Bv.js} +1 -1
  25. package/dist/docs/assets/chunks/{theme.BOTJVqh7.js → theme.BDDWeELx.js} +2 -2
  26. package/dist/docs/assets/concepts.md.DFaQEFkA.js +4 -0
  27. package/dist/docs/assets/concepts.md.DFaQEFkA.lean.js +1 -0
  28. package/dist/docs/assets/deployment.md.9MYBuKM1.js +55 -0
  29. package/dist/docs/assets/deployment.md.9MYBuKM1.lean.js +1 -0
  30. package/dist/docs/assets/{evals.md.DYOjkRCX.js → evals.md.BIUoVZ6X.js} +13 -13
  31. package/dist/docs/assets/evals.md.BIUoVZ6X.lean.js +1 -0
  32. package/dist/docs/assets/{example-agents_approval-buddy.md.DFGBYLcc.js → example-agents_approval-buddy.md.BhEfleVx.js} +4 -4
  33. package/dist/docs/assets/{example-agents_approval-buddy.md.DFGBYLcc.lean.js → example-agents_approval-buddy.md.BhEfleVx.lean.js} +1 -1
  34. package/dist/docs/assets/example-agents_benny.md.2Et1qa8f.js +7 -0
  35. package/dist/docs/assets/{example-agents_bugbot.md.DelIdhxB.js → example-agents_bugbot.md.ByUexi5i.js} +5 -5
  36. package/dist/docs/assets/{example-agents_codebase-wiki.md.DC6sgwn0.js → example-agents_codebase-wiki.md.B4y-7ZVW.js} +6 -6
  37. package/dist/docs/assets/{example-agents_codebase-wiki.md.DC6sgwn0.lean.js → example-agents_codebase-wiki.md.B4y-7ZVW.lean.js} +1 -1
  38. package/dist/docs/assets/{example-agents_codeowners-review.md.Ku_tG2RY.js → example-agents_codeowners-review.md.D6ay4nvf.js} +6 -6
  39. package/dist/docs/assets/{example-agents_codeowners-review.md.Ku_tG2RY.lean.js → example-agents_codeowners-review.md.D6ay4nvf.lean.js} +1 -1
  40. package/dist/docs/assets/{example-agents_concierge.md.4rQTSMXt.js → example-agents_concierge.md.lL8rhYlj.js} +7 -7
  41. package/dist/docs/assets/{example-agents_fsd.md.CzgUrDfi.js → example-agents_fsd.md.DfNKQTHz.js} +5 -5
  42. package/dist/docs/assets/example-agents_index.md.DgGBwckv.js +2 -0
  43. package/dist/docs/assets/example-agents_index.md.DgGBwckv.lean.js +1 -0
  44. package/dist/docs/assets/{example-agents_knowledge-base.md.BPJiVueF.js → example-agents_knowledge-base.md.CzyZ2DCr.js} +5 -5
  45. package/dist/docs/assets/{example-agents_knowledge-base.md.BPJiVueF.lean.js → example-agents_knowledge-base.md.CzyZ2DCr.lean.js} +1 -1
  46. package/dist/docs/assets/example-agents_oncall.md.wFFXXEyW.js +10 -0
  47. package/dist/docs/assets/{example-agents_security-reviewer.md.Dhj_m7_B.js → example-agents_security-reviewer.md.Dkf1gyo6.js} +8 -8
  48. package/dist/docs/assets/example-agents_slack-agent.md.DvgvT4nn.js +5 -0
  49. package/dist/docs/assets/example-agents_weather-agent.md.Dmrcphhl.js +24 -0
  50. package/dist/docs/assets/example-agents_weather-agent.md.Dmrcphhl.lean.js +1 -0
  51. package/dist/docs/assets/{guides_agent-to-agent.md.Bpzgq2Pq.js → guides_agent-to-agent.md.Bmbxy-FA.js} +4 -4
  52. package/dist/docs/assets/guides_cloud-runtime.md.BZ2GA7Es.js +9 -0
  53. package/dist/docs/assets/{guides_github.md.DOOCpqsW.js → guides_github.md.R2QlpR75.js} +5 -5
  54. package/dist/docs/assets/{guides_human-in-the-loop.md.DlUqsp1S.js → guides_human-in-the-loop.md.BWvT7UqY.js} +1 -1
  55. package/dist/docs/assets/{guides_mcp-oauth.md.Dd8EgSem.js → guides_mcp-oauth.md.C7G7IykG.js} +5 -5
  56. package/dist/docs/assets/guides_mcp-oauth.md.C7G7IykG.lean.js +1 -0
  57. package/dist/docs/assets/guides_slack.md.zriQpU_9.js +47 -0
  58. package/dist/docs/assets/guides_slack.md.zriQpU_9.lean.js +1 -0
  59. package/dist/docs/assets/{guides_webhooks.md.wSOYas3X.js → guides_webhooks.md.DiAwSR42.js} +1 -1
  60. package/dist/docs/assets/{hillclimbing.md.DHNast08.js → hillclimbing.md.D9Y1_bYh.js} +1 -1
  61. package/dist/docs/assets/index.md.CZqbBJPB.js +20 -0
  62. package/dist/docs/assets/index.md.CZqbBJPB.lean.js +1 -0
  63. package/dist/docs/assets/{quickstart.md.BU6Iwi_9.js → quickstart.md.TnEXYgYW.js} +12 -12
  64. package/dist/docs/assets/{reference_agent-config.md.DrW2JUM8.js → reference_agent-config.md.kuN6-OxK.js} +1 -1
  65. package/dist/docs/assets/reference_cli.md.sD-IUWjg.js +73 -0
  66. package/dist/docs/assets/{reference_cli.md.ccoKOoXt.lean.js → reference_cli.md.sD-IUWjg.lean.js} +1 -1
  67. package/dist/docs/assets/{reference_connections.md.B9Q3TOve.js → reference_connections.md.DGqAsFXb.js} +3 -3
  68. package/dist/docs/assets/reference_http-api.md.CfVM_ICa.js +11 -0
  69. package/dist/docs/assets/{reference_project-layout.md.Bd_CKtNS.js → reference_project-layout.md.D8E6ZmHJ.js} +4 -4
  70. package/dist/docs/assets/{reference_project-layout.md.Bd_CKtNS.lean.js → reference_project-layout.md.D8E6ZmHJ.lean.js} +1 -1
  71. package/dist/docs/assets/{reference_schedules.md.w_F2mXB6.js → reference_schedules.md.gmfYzf_I.js} +1 -1
  72. package/dist/docs/assets/{reference_sessions.md.DLd6mvbv.js → reference_sessions.md.C_ouF_uf.js} +3 -3
  73. package/dist/docs/assets/{reference_tools.md.BRSDnTbN.js → reference_tools.md.BswAQM41.js} +3 -3
  74. package/dist/docs/assets/{scaffolding-agents.md.C3pTrmoE.js → scaffolding-agents.md.Bsr9Pwzu.js} +1 -1
  75. package/dist/docs/assets/{scaffolding-agents.md.C3pTrmoE.lean.js → scaffolding-agents.md.Bsr9Pwzu.lean.js} +1 -1
  76. package/dist/docs/assets/{storage.md.DRTdnFvd.js → storage.md.xZoiGM58.js} +3 -3
  77. package/dist/docs/assets/storage.md.xZoiGM58.lean.js +1 -0
  78. package/dist/docs/assets/troubleshooting.md.B5RVX_tL.js +1 -0
  79. package/dist/docs/assets/{troubleshooting.md.CmQkmnzC.lean.js → troubleshooting.md.B5RVX_tL.lean.js} +1 -1
  80. package/dist/docs/building-with-agents.html +12 -12
  81. package/dist/docs/concepts.html +6 -6
  82. package/dist/docs/deployment.html +32 -32
  83. package/dist/docs/evals.html +19 -19
  84. package/dist/docs/example-agents/approval-buddy.html +9 -9
  85. package/dist/docs/example-agents/benny.html +11 -11
  86. package/dist/docs/example-agents/bugbot.html +10 -10
  87. package/dist/docs/example-agents/codebase-wiki.html +11 -11
  88. package/dist/docs/example-agents/codeowners-review.html +11 -11
  89. package/dist/docs/example-agents/concierge.html +12 -12
  90. package/dist/docs/example-agents/fsd.html +10 -10
  91. package/dist/docs/example-agents/index.html +7 -7
  92. package/dist/docs/example-agents/knowledge-base.html +10 -10
  93. package/dist/docs/example-agents/oncall.html +10 -10
  94. package/dist/docs/example-agents/security-reviewer.html +13 -13
  95. package/dist/docs/example-agents/slack-agent.html +10 -10
  96. package/dist/docs/example-agents/weather-agent.html +16 -16
  97. package/dist/docs/guides/agent-to-agent.html +9 -9
  98. package/dist/docs/guides/cloud-runtime.html +7 -7
  99. package/dist/docs/guides/github.html +10 -10
  100. package/dist/docs/guides/human-in-the-loop.html +7 -7
  101. package/dist/docs/guides/mcp-oauth.html +11 -11
  102. package/dist/docs/guides/slack.html +22 -17
  103. package/dist/docs/guides/webhooks.html +7 -7
  104. package/dist/docs/hashmap.json +1 -1
  105. package/dist/docs/hillclimbing.html +7 -7
  106. package/dist/docs/index.html +9 -9
  107. package/dist/docs/quickstart.html +17 -17
  108. package/dist/docs/reference/agent-config.html +7 -7
  109. package/dist/docs/reference/channels.html +5 -5
  110. package/dist/docs/reference/cli.html +56 -48
  111. package/dist/docs/reference/connections.html +9 -9
  112. package/dist/docs/reference/hooks.html +5 -5
  113. package/dist/docs/reference/http-api.html +7 -7
  114. package/dist/docs/reference/instructions.html +5 -5
  115. package/dist/docs/reference/playground.html +5 -5
  116. package/dist/docs/reference/project-layout.html +9 -9
  117. package/dist/docs/reference/prompt.html +5 -5
  118. package/dist/docs/reference/schedules.html +7 -7
  119. package/dist/docs/reference/sessions.html +8 -8
  120. package/dist/docs/reference/skills.html +5 -5
  121. package/dist/docs/reference/subagents.html +5 -5
  122. package/dist/docs/reference/tools.html +9 -9
  123. package/dist/docs/scaffolding-agents.html +6 -6
  124. package/dist/docs/storage.html +9 -9
  125. package/dist/docs/troubleshooting.html +6 -6
  126. package/dist/evals/reporters.d.ts +1 -1
  127. package/dist/evals/reporters.js +1 -1
  128. package/dist/evals.d.ts +2 -2
  129. package/dist/files-backends/agent-store-presigned-url.d.ts +100 -0
  130. package/dist/files-backends/agent-store-presigned-url.d.ts.map +1 -0
  131. package/dist/files-backends/agent-store-presigned-url.js +347 -0
  132. package/dist/files-backends/cursor-hosted.d.ts +87 -0
  133. package/dist/files-backends/cursor-hosted.d.ts.map +1 -0
  134. package/dist/files-backends/cursor-hosted.js +540 -0
  135. package/dist/files-backends/local-fs.d.ts +33 -0
  136. package/dist/files-backends/local-fs.d.ts.map +1 -0
  137. package/dist/files-backends/local-fs.js +199 -0
  138. package/dist/files.d.ts +139 -0
  139. package/dist/files.d.ts.map +1 -0
  140. package/dist/files.js +89 -0
  141. package/dist/internal/ab-collector.js +2 -2
  142. package/dist/internal/ab-fold.js +1 -1
  143. package/dist/internal/cli-ax.d.ts +2 -2
  144. package/dist/internal/cli-ax.js +2 -2
  145. package/dist/internal/cli-deploy.d.ts +1 -1
  146. package/dist/internal/cli-deploy.d.ts.map +1 -1
  147. package/dist/internal/cli-deploy.js +7 -2
  148. package/dist/internal/cli-docs.d.ts +1 -1
  149. package/dist/internal/cli-docs.js +1 -1
  150. package/dist/internal/cli-github.js +13 -13
  151. package/dist/internal/cli-mcp-oauth.d.ts +1 -1
  152. package/dist/internal/cli-mcp-oauth.js +2 -2
  153. package/dist/internal/cli-mcp.d.ts +3 -3
  154. package/dist/internal/cli-mcp.js +4 -4
  155. package/dist/internal/cli-skills.js +1 -1
  156. package/dist/internal/cloud-turn-cost.d.ts +9 -1
  157. package/dist/internal/cloud-turn-cost.d.ts.map +1 -1
  158. package/dist/internal/cloud-turn-cost.js +14 -4
  159. package/dist/internal/cursor/account-mcp.js +5 -5
  160. package/dist/internal/cursor/backend-client.js +1 -1
  161. package/dist/internal/cursor/github-credentials.js +3 -3
  162. package/dist/internal/cursor-account-mcp-auth.d.ts +1 -1
  163. package/dist/internal/cursor-account-mcp-auth.js +1 -1
  164. package/dist/internal/cursor-event-relay.js +1 -1
  165. package/dist/internal/cursor-relay-core.d.ts +1 -1
  166. package/dist/internal/cursor-relay-core.d.ts.map +1 -1
  167. package/dist/internal/cursor-slack-relay.js +1 -1
  168. package/dist/internal/deploy-client.d.ts +6 -1
  169. package/dist/internal/deploy-client.d.ts.map +1 -1
  170. package/dist/internal/deploy-client.js +3 -2
  171. package/dist/internal/deploy-source.d.ts +2 -2
  172. package/dist/internal/deploy-source.js +2 -2
  173. package/dist/internal/discovery.js +2 -2
  174. package/dist/internal/distribution.d.ts +5 -5
  175. package/dist/internal/distribution.d.ts.map +1 -1
  176. package/dist/internal/distribution.js +6 -6
  177. package/dist/internal/docs-site.js +5 -5
  178. package/dist/internal/eval-run-store.js +8 -8
  179. package/dist/internal/evals-client.d.ts +1 -1
  180. package/dist/internal/evals-client.js +1 -1
  181. package/dist/internal/github-fanout.js +2 -2
  182. package/dist/internal/host-files.d.ts +29 -0
  183. package/dist/internal/host-files.d.ts.map +1 -0
  184. package/dist/internal/host-files.js +283 -0
  185. package/dist/internal/host-platforms.js +5 -5
  186. package/dist/internal/hosting.d.ts +1 -1
  187. package/dist/internal/hosting.js +1 -1
  188. package/dist/internal/http-channel.d.ts.map +1 -1
  189. package/dist/internal/http-channel.js +26 -0
  190. package/dist/internal/install-cursor-skills.d.ts +1 -1
  191. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  192. package/dist/internal/install-cursor-skills.js +33 -4
  193. package/dist/internal/local-control-plane.js +2 -2
  194. package/dist/internal/logs-client.d.ts +2 -2
  195. package/dist/internal/logs-client.js +2 -2
  196. package/dist/internal/mcp-endpoint.js +1 -1
  197. package/dist/internal/mcp-oauth.js +2 -2
  198. package/dist/internal/platform-schedule-sync.js +2 -2
  199. package/dist/internal/playground/toolchain.js +6 -6
  200. package/dist/internal/reminder-runner.js +13 -13
  201. package/dist/internal/resolved-connections.js +6 -6
  202. package/dist/internal/schedule-runner.js +1 -1
  203. package/dist/internal/sdk-runner.js +5 -5
  204. package/dist/internal/server.js +16 -16
  205. package/dist/internal/session-cost.d.ts +3 -2
  206. package/dist/internal/session-cost.d.ts.map +1 -1
  207. package/dist/internal/session-cost.js +7 -6
  208. package/dist/internal/session-engine.d.ts +31 -1
  209. package/dist/internal/session-engine.d.ts.map +1 -1
  210. package/dist/internal/session-engine.js +119 -31
  211. package/dist/internal/slack-provision-client.js +1 -1
  212. package/dist/internal/storage-coordinator.js +7 -7
  213. package/dist/internal/trajectory.js +2 -2
  214. package/dist/internal/turn-cost.d.ts +27 -0
  215. package/dist/internal/turn-cost.d.ts.map +1 -0
  216. package/dist/internal/turn-cost.js +83 -0
  217. package/dist/internal/update-check.d.ts +3 -3
  218. package/dist/internal/update-check.d.ts.map +1 -1
  219. package/dist/internal/update-check.js +5 -5
  220. package/dist/memory.d.ts +1 -1
  221. package/dist/memory.js +1 -1
  222. package/dist/playground/assets/index-50PKeJlG.css +1 -0
  223. package/dist/playground/assets/index-C0f2Wl1q.js +85 -0
  224. package/dist/playground/index.html +2 -2
  225. package/dist/storage.d.ts +1 -1
  226. package/dist/storage.js +1 -1
  227. package/dist/types.d.ts +120 -16
  228. package/dist/types.d.ts.map +1 -1
  229. package/docs/README.md +23 -23
  230. package/docs/ab.md +12 -12
  231. package/docs/building-with-agents.md +9 -9
  232. package/docs/concepts.md +11 -11
  233. package/docs/deployment.md +55 -43
  234. package/docs/evals.md +20 -20
  235. package/docs/example-agents/approval-buddy.md +9 -9
  236. package/docs/example-agents/benny.md +13 -13
  237. package/docs/example-agents/bugbot.md +6 -6
  238. package/docs/example-agents/codebase-wiki.md +8 -8
  239. package/docs/example-agents/codeowners-review.md +8 -8
  240. package/docs/example-agents/concierge.md +10 -10
  241. package/docs/example-agents/fsd.md +7 -7
  242. package/docs/example-agents/index.md +8 -8
  243. package/docs/example-agents/knowledge-base.md +9 -9
  244. package/docs/example-agents/oncall.md +7 -7
  245. package/docs/example-agents/security-reviewer.md +12 -12
  246. package/docs/example-agents/slack-agent.md +10 -10
  247. package/docs/example-agents/weather-agent.md +30 -26
  248. package/docs/guides/agent-to-agent.md +4 -4
  249. package/docs/guides/cloud-runtime.md +3 -3
  250. package/docs/guides/github.md +6 -6
  251. package/docs/guides/human-in-the-loop.md +1 -1
  252. package/docs/guides/mcp-oauth.md +9 -9
  253. package/docs/guides/slack.md +94 -21
  254. package/docs/guides/webhooks.md +1 -1
  255. package/docs/hillclimbing.md +3 -3
  256. package/docs/quickstart.md +18 -18
  257. package/docs/reference/agent-config.md +1 -1
  258. package/docs/reference/cli.md +110 -79
  259. package/docs/reference/connections.md +3 -3
  260. package/docs/reference/http-api.md +2 -2
  261. package/docs/reference/project-layout.md +7 -7
  262. package/docs/reference/schedules.md +1 -1
  263. package/docs/reference/sessions.md +7 -7
  264. package/docs/reference/tools.md +3 -3
  265. package/docs/scaffolding-agents.md +2 -2
  266. package/docs/storage.md +5 -5
  267. package/docs/troubleshooting.md +11 -10
  268. package/package.json +3 -1
  269. package/skills/ab/SKILL.md +5 -5
  270. package/skills/create-agent/SKILL.md +17 -17
  271. package/skills/debug/SKILL.md +10 -10
  272. package/skills/evals/SKILL.md +13 -13
  273. package/skills/framework-map/SKILL.md +3 -3
  274. package/skills/github/SKILL.md +11 -11
  275. package/skills/hillclimb/SKILL.md +9 -9
  276. package/skills/mcp-auth/SKILL.md +11 -11
  277. package/skills/setup-slack/SKILL.md +28 -28
  278. package/src/bin/agent-serve.ts +4 -4
  279. package/src/channels/github/index.ts +1 -1
  280. package/src/channels/slack/bot-mentions.ts +1 -1
  281. package/src/channels/slack/eval-directive.ts +1 -1
  282. package/src/channels/slack/external-policy.ts +1 -1
  283. package/src/channels/slack/log.ts +1 -1
  284. package/src/channels/slack/setup.ts +1 -1
  285. package/src/channels/slack/socket-mode.ts +1 -1
  286. package/src/evals/reporters.ts +1 -1
  287. package/src/evals.ts +2 -2
  288. package/src/files-backends/agent-store-presigned-url.ts +402 -0
  289. package/src/files-backends/cursor-hosted.ts +698 -0
  290. package/src/files-backends/local-fs.ts +178 -0
  291. package/src/files.ts +195 -0
  292. package/src/internal/ab-collector.ts +2 -2
  293. package/src/internal/ab-fold.ts +1 -1
  294. package/src/internal/cli-ax.ts +2 -2
  295. package/src/internal/cli-deploy.ts +7 -2
  296. package/src/internal/cli-docs.ts +1 -1
  297. package/src/internal/cli-github.ts +13 -13
  298. package/src/internal/cli-mcp-oauth.ts +2 -2
  299. package/src/internal/cli-mcp.ts +4 -4
  300. package/src/internal/cli-skills.ts +1 -1
  301. package/src/internal/cloud-turn-cost.ts +20 -4
  302. package/src/internal/cursor/account-mcp.ts +5 -5
  303. package/src/internal/cursor/backend-client.ts +1 -1
  304. package/src/internal/cursor/github-credentials.ts +3 -3
  305. package/src/internal/cursor-account-mcp-auth.ts +1 -1
  306. package/src/internal/cursor-event-relay.ts +1 -1
  307. package/src/internal/cursor-relay-core.ts +1 -1
  308. package/src/internal/cursor-slack-relay.ts +1 -1
  309. package/src/internal/deploy-client.ts +8 -2
  310. package/src/internal/deploy-source.ts +2 -2
  311. package/src/internal/discovery.ts +2 -2
  312. package/src/internal/distribution.ts +6 -6
  313. package/src/internal/docs-site.ts +5 -5
  314. package/src/internal/eval-run-store.ts +8 -8
  315. package/src/internal/evals-client.ts +1 -1
  316. package/src/internal/github-fanout.ts +2 -2
  317. package/src/internal/host-files.ts +372 -0
  318. package/src/internal/host-platforms.ts +5 -5
  319. package/src/internal/hosting.ts +1 -1
  320. package/src/internal/http-channel.ts +30 -0
  321. package/src/internal/install-cursor-skills.ts +31 -3
  322. package/src/internal/local-control-plane.ts +2 -2
  323. package/src/internal/logs-client.ts +2 -2
  324. package/src/internal/mcp-endpoint.ts +1 -1
  325. package/src/internal/mcp-oauth.ts +2 -2
  326. package/src/internal/platform-schedule-sync.ts +2 -2
  327. package/src/internal/playground/toolchain.ts +6 -6
  328. package/src/internal/reminder-runner.ts +13 -13
  329. package/src/internal/resolved-connections.ts +6 -6
  330. package/src/internal/schedule-runner.ts +1 -1
  331. package/src/internal/sdk-runner.ts +5 -5
  332. package/src/internal/server.ts +16 -16
  333. package/src/internal/session-cost.ts +7 -6
  334. package/src/internal/session-engine.ts +141 -28
  335. package/src/internal/slack-provision-client.ts +1 -1
  336. package/src/internal/storage-coordinator.ts +7 -7
  337. package/src/internal/trajectory.ts +2 -2
  338. package/src/internal/turn-cost.ts +110 -0
  339. package/src/internal/update-check.ts +6 -6
  340. package/src/memory.ts +1 -1
  341. package/src/storage.ts +1 -1
  342. package/src/types.ts +148 -16
  343. package/dist/docs/assets/building-with-agents.md.CJCtZCyi.js +0 -13
  344. package/dist/docs/assets/chunks/@localSearchIndexroot.DGe61XHA.js +0 -1
  345. package/dist/docs/assets/concepts.md.Cfb9b-k1.js +0 -4
  346. package/dist/docs/assets/concepts.md.Cfb9b-k1.lean.js +0 -1
  347. package/dist/docs/assets/deployment.md.TecHo0_2.js +0 -55
  348. package/dist/docs/assets/deployment.md.TecHo0_2.lean.js +0 -1
  349. package/dist/docs/assets/evals.md.DYOjkRCX.lean.js +0 -1
  350. package/dist/docs/assets/example-agents_benny.md.B0gjhI-p.js +0 -7
  351. package/dist/docs/assets/example-agents_index.md.D2PEVSXl.js +0 -2
  352. package/dist/docs/assets/example-agents_index.md.D2PEVSXl.lean.js +0 -1
  353. package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.js +0 -10
  354. package/dist/docs/assets/example-agents_slack-agent.md.buLbgvBf.js +0 -5
  355. package/dist/docs/assets/example-agents_weather-agent.md.C9Qv-W0o.js +0 -24
  356. package/dist/docs/assets/example-agents_weather-agent.md.C9Qv-W0o.lean.js +0 -1
  357. package/dist/docs/assets/guides_cloud-runtime.md.gVzabdQL.js +0 -9
  358. package/dist/docs/assets/guides_mcp-oauth.md.Dd8EgSem.lean.js +0 -1
  359. package/dist/docs/assets/guides_slack.md.CjmJSvZS.js +0 -42
  360. package/dist/docs/assets/guides_slack.md.CjmJSvZS.lean.js +0 -1
  361. package/dist/docs/assets/index.md.CH_s5uZe.js +0 -20
  362. package/dist/docs/assets/index.md.CH_s5uZe.lean.js +0 -1
  363. package/dist/docs/assets/reference_cli.md.ccoKOoXt.js +0 -65
  364. package/dist/docs/assets/reference_http-api.md.BncLd3PZ.js +0 -11
  365. package/dist/docs/assets/storage.md.DRTdnFvd.lean.js +0 -1
  366. package/dist/docs/assets/troubleshooting.md.CmQkmnzC.js +0 -1
  367. package/dist/internal/model-pricing.d.ts +0 -49
  368. package/dist/internal/model-pricing.d.ts.map +0 -1
  369. package/dist/internal/model-pricing.js +0 -377
  370. package/dist/playground/assets/index-CquRB-l0.js +0 -85
  371. package/dist/playground/assets/index-Dj0bWpkn.css +0 -1
  372. package/src/internal/model-pricing.ts +0 -426
  373. /package/dist/docs/assets/{example-agents_benny.md.B0gjhI-p.lean.js → example-agents_benny.md.2Et1qa8f.lean.js} +0 -0
  374. /package/dist/docs/assets/{example-agents_bugbot.md.DelIdhxB.lean.js → example-agents_bugbot.md.ByUexi5i.lean.js} +0 -0
  375. /package/dist/docs/assets/{example-agents_concierge.md.4rQTSMXt.lean.js → example-agents_concierge.md.lL8rhYlj.lean.js} +0 -0
  376. /package/dist/docs/assets/{example-agents_fsd.md.CzgUrDfi.lean.js → example-agents_fsd.md.DfNKQTHz.lean.js} +0 -0
  377. /package/dist/docs/assets/{example-agents_oncall.md.BG_sUMly.lean.js → example-agents_oncall.md.wFFXXEyW.lean.js} +0 -0
  378. /package/dist/docs/assets/{example-agents_security-reviewer.md.Dhj_m7_B.lean.js → example-agents_security-reviewer.md.Dkf1gyo6.lean.js} +0 -0
  379. /package/dist/docs/assets/{example-agents_slack-agent.md.buLbgvBf.lean.js → example-agents_slack-agent.md.DvgvT4nn.lean.js} +0 -0
  380. /package/dist/docs/assets/{guides_agent-to-agent.md.Bpzgq2Pq.lean.js → guides_agent-to-agent.md.Bmbxy-FA.lean.js} +0 -0
  381. /package/dist/docs/assets/{guides_cloud-runtime.md.gVzabdQL.lean.js → guides_cloud-runtime.md.BZ2GA7Es.lean.js} +0 -0
  382. /package/dist/docs/assets/{guides_github.md.DOOCpqsW.lean.js → guides_github.md.R2QlpR75.lean.js} +0 -0
  383. /package/dist/docs/assets/{guides_human-in-the-loop.md.DlUqsp1S.lean.js → guides_human-in-the-loop.md.BWvT7UqY.lean.js} +0 -0
  384. /package/dist/docs/assets/{guides_webhooks.md.wSOYas3X.lean.js → guides_webhooks.md.DiAwSR42.lean.js} +0 -0
  385. /package/dist/docs/assets/{hillclimbing.md.DHNast08.lean.js → hillclimbing.md.D9Y1_bYh.lean.js} +0 -0
  386. /package/dist/docs/assets/{quickstart.md.BU6Iwi_9.lean.js → quickstart.md.TnEXYgYW.lean.js} +0 -0
  387. /package/dist/docs/assets/{reference_agent-config.md.DrW2JUM8.lean.js → reference_agent-config.md.kuN6-OxK.lean.js} +0 -0
  388. /package/dist/docs/assets/{reference_connections.md.B9Q3TOve.lean.js → reference_connections.md.DGqAsFXb.lean.js} +0 -0
  389. /package/dist/docs/assets/{reference_http-api.md.BncLd3PZ.lean.js → reference_http-api.md.CfVM_ICa.lean.js} +0 -0
  390. /package/dist/docs/assets/{reference_schedules.md.w_F2mXB6.lean.js → reference_schedules.md.gmfYzf_I.lean.js} +0 -0
  391. /package/dist/docs/assets/{reference_sessions.md.DLd6mvbv.lean.js → reference_sessions.md.C_ouF_uf.lean.js} +0 -0
  392. /package/dist/docs/assets/{reference_tools.md.BRSDnTbN.lean.js → reference_tools.md.BswAQM41.lean.js} +0 -0
@@ -0,0 +1,540 @@
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
+ * Everything goes through the public API under `/v0/agent-serve-files`, the same
11
+ * surface any API-key holder gets. This process is an ordinary client of it —
12
+ * there is no private endpoint, no second base URL, and nothing here that only
13
+ * works because the caller happens to be an Agent Serve engine. That matters
14
+ * beyond tidiness: a self-hosted deployment, a CI job, or a customer script can
15
+ * drive the same store with the same requests.
16
+ *
17
+ * Two things follow. There is no Agent Store token: a token narrows an identity
18
+ * to one store and one capability, which is what a caller that cannot hold a
19
+ * credential needs (an in-pod FUSE daemon). This process holds the credential
20
+ * the token would be minted from, so a token bought a round trip, an expiry to
21
+ * manage, and a second auth path, and no privilege reduction. And there is no
22
+ * direct call to the store service: the API layer owns the policy, and the
23
+ * engine never addresses it.
24
+ *
25
+ * There is also no store lookup. Every request names this deployment's file
26
+ * store by the `agentStoreSourceId` the deploy pipeline pinned into the pod
27
+ * env as `AGENT_SERVE_STORE_SOURCE_ID` — provisioning the store at the same
28
+ * time, so by boot the store exists and the id resolves. The id is an
29
+ * address, not a credential: the server maps it to a store and authorizes
30
+ * every call against the deployment's own live service account, so holding
31
+ * it grants nothing, and this process never learns a store id it could use
32
+ * to ask for anyone else's.
33
+ *
34
+ * Locally, point `CURSOR_API_BASE_URL` at a backend that serves
35
+ * `/v0/agent-serve-files` and use a deployment SA key; off hosting the
36
+ * local-disk sink is the default instead.
37
+ *
38
+ * Writes are conditional. The store rejects unconditional writes, so every
39
+ * `put` first learns the current etag: `new` for a path we believe is absent,
40
+ * `etag` to replace what we last observed. A raced write comes back 412 and
41
+ * surfaces as {@link FileConflictError}, which is why this backend reports
42
+ * `etags: true` and `host.files.capabilities.conflictDetection` is honestly
43
+ * true.
44
+ */
45
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
46
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
47
+ return new (P || (P = Promise))(function (resolve, reject) {
48
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
49
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
50
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
51
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
52
+ });
53
+ };
54
+ import { createHash } from "node:crypto";
55
+ import { FileConflictError, } from "../files.js";
56
+ import { createAgentStorePresignedUrlValidatorForBackend } from "./agent-store-presigned-url.js";
57
+ /**
58
+ * Same default as the hosted storage backend, inlined so this entrypoint does
59
+ * not import CLI code.
60
+ */
61
+ const DEFAULT_CURSOR_EXTERNAL_API_URL = "https://api.cursor.com";
62
+ const AGENT_SERVE_FILES_PATH = "/v0/agent-serve-files";
63
+ /**
64
+ * Pinned by the deploy pipeline for every Cursor-managed deployment — which
65
+ * provisions the file store it names in the same step — and reserved from
66
+ * user secrets. Its presence is the signal that a durable store exists and
67
+ * the hosted control plane is reachable; a deployment without one (no
68
+ * service account yet) has no store, and this backend is not selected.
69
+ */
70
+ export const AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR = "AGENT_SERVE_STORE_SOURCE_ID";
71
+ /** Cap on the per-process etag cache; a miss costs a lookup, not correctness. */
72
+ const MAX_REMEMBERED_ETAGS = 1000;
73
+ /** Bounded directory page for point lookups. */
74
+ const DIRECTORY_PAGE_SIZE = 1000;
75
+ /** Stop paging a pathological directory rather than scanning forever. */
76
+ const MAX_DIRECTORY_PAGES = 20;
77
+ /**
78
+ * Total page budget for a full `list()` walk of a store the unscoped listing
79
+ * could not carry (~1M entries at the page size above). Past it, fail loudly:
80
+ * a silently partial listing would be mistaken for the whole scope.
81
+ */
82
+ const MAX_LIST_WALK_PAGES = 1000;
83
+ /**
84
+ * True on Cursor-managed hosting with a provisioned file store.
85
+ *
86
+ * Keyed on the store source id alone, deliberately: the credential is not part
87
+ * of the test. If it were, a missing or regressed `CURSOR_API_KEY` would
88
+ * silently select pod-local disk on a hosted pod and accept writes that vanish
89
+ * with the pod. Instead the store is detected, and a missing credential fails
90
+ * loudly when the sink is used.
91
+ */
92
+ export function isCursorHostedFilesAvailable(env = process.env) {
93
+ var _a;
94
+ const sourceId = (_a = env[AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR]) === null || _a === void 0 ? void 0 : _a.trim();
95
+ return sourceId !== undefined && sourceId !== "";
96
+ }
97
+ /**
98
+ * Cursor-hosted {@link FileSink}, selected on Cursor-managed hosting.
99
+ *
100
+ * Stateless apart from the etag cache below: every request names this
101
+ * deployment's store by its pinned source id, so there is nothing to
102
+ * resolve, hold, or invalidate.
103
+ */
104
+ export function cursorHostedFiles(options = {}) {
105
+ /**
106
+ * Etags observed per key, so a replace can carry a precondition without
107
+ * re-reading. Bounded: a resident engine is long-lived and touches an
108
+ * unbounded number of keys over its lifetime. Oldest-out is fine — a miss
109
+ * costs one lookup, not correctness.
110
+ */
111
+ const observedEtags = new Map();
112
+ const rememberEtag = (key, etag) => {
113
+ if (observedEtags.size >= MAX_REMEMBERED_ETAGS) {
114
+ const oldest = observedEtags.keys().next();
115
+ if (!oldest.done) {
116
+ observedEtags.delete(oldest.value);
117
+ }
118
+ }
119
+ observedEtags.set(key, etag);
120
+ };
121
+ /**
122
+ * Run `call` against this deployment's files.
123
+ *
124
+ * No network call and nothing cached: the store source id comes from the
125
+ * environment and the server maps it to a store on every request. Resolved
126
+ * per call rather than once at construction so a misconfigured environment
127
+ * fails where the operation is, not where the sink was created.
128
+ */
129
+ function withFiles(call) {
130
+ return __awaiter(this, void 0, void 0, function* () {
131
+ const sourceId = resolveStoreSourceId(options);
132
+ return yield call({
133
+ path: (suffix = "") => `/${encodeURIComponent(sourceId)}${suffix}`,
134
+ });
135
+ });
136
+ }
137
+ /** One page of the paginated per-directory listing. */
138
+ function directoryPage(files, directory, pageToken) {
139
+ return __awaiter(this, void 0, void 0, function* () {
140
+ const query = new URLSearchParams({
141
+ path: directory,
142
+ limit: String(DIRECTORY_PAGE_SIZE),
143
+ });
144
+ if (pageToken !== undefined) {
145
+ query.set("pageToken", pageToken);
146
+ }
147
+ return yield storeGet(options, files.path(`?${query.toString()}`));
148
+ });
149
+ }
150
+ function listEntries(prefix) {
151
+ return __awaiter(this, void 0, void 0, function* () {
152
+ return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
153
+ var _a;
154
+ const raw = yield storeGet(options, files.path());
155
+ if (raw.complete === true) {
156
+ const out = [];
157
+ for (const file of (_a = raw.files) !== null && _a !== void 0 ? _a : []) {
158
+ if (typeof file.path !== "string" || !file.path.startsWith(prefix)) {
159
+ continue;
160
+ }
161
+ out.push(toEntry(file, file.path));
162
+ }
163
+ return out;
164
+ }
165
+ // The unscoped listing was truncated (`complete: false`) and has no
166
+ // continuation to follow. `list()` promises the whole scope, so rather
167
+ // than lie or fail, walk the paginated per-directory form, which does
168
+ // paginate and reports immediate subdirectories to recurse into.
169
+ return yield walkDirectoryTree(files, prefix);
170
+ }));
171
+ });
172
+ }
173
+ /**
174
+ * Every entry under `prefix`, via the paginated directory listing.
175
+ *
176
+ * Starts at the deepest directory the prefix fully names and descends only
177
+ * into subdirectories that can still hold matches. Bounded so a runaway
178
+ * store fails loudly rather than returning a silently partial answer the
179
+ * caller would mistake for the whole scope.
180
+ */
181
+ function walkDirectoryTree(files, prefix) {
182
+ return __awaiter(this, void 0, void 0, function* () {
183
+ var _a, _b;
184
+ const slash = prefix.lastIndexOf("/");
185
+ const pending = [slash === -1 ? "" : prefix.slice(0, slash)];
186
+ const queued = new Set(pending);
187
+ const out = [];
188
+ let pageBudget = MAX_LIST_WALK_PAGES;
189
+ while (pending.length > 0) {
190
+ const directory = pending.pop();
191
+ let pageToken;
192
+ do {
193
+ if (pageBudget <= 0) {
194
+ throw new Error("cursorHostedFiles: the store is too large to list; scope the listing with a narrower prefix");
195
+ }
196
+ pageBudget -= 1;
197
+ const page = yield directoryPage(files, directory, pageToken);
198
+ for (const file of (_a = page.files) !== null && _a !== void 0 ? _a : []) {
199
+ if (typeof file.path === "string" && file.path.startsWith(prefix)) {
200
+ out.push(toEntry(file, file.path));
201
+ }
202
+ }
203
+ // Every page can surface different subdirectories, so collect from
204
+ // all of them, deduped — and descend only into branches that can
205
+ // still hold matches: a descendant of the prefix, or (at the first
206
+ // level) a directory the prefix's basename component narrows to.
207
+ for (const subdir of (_b = page.directories) !== null && _b !== void 0 ? _b : []) {
208
+ if (queued.has(subdir)) {
209
+ continue;
210
+ }
211
+ if (`${subdir}/`.startsWith(prefix) ||
212
+ prefix.startsWith(`${subdir}/`)) {
213
+ queued.add(subdir);
214
+ pending.push(subdir);
215
+ }
216
+ }
217
+ pageToken =
218
+ page.complete === false && page.nextPageToken !== undefined
219
+ ? page.nextPageToken
220
+ : undefined;
221
+ } while (pageToken !== undefined);
222
+ }
223
+ return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
224
+ });
225
+ }
226
+ /** Shared decode: remember the etag as a side effect, then shape the entry. */
227
+ function toEntry(file, key) {
228
+ if (typeof file.etag === "string" && file.etag !== "") {
229
+ rememberEtag(key, file.etag);
230
+ }
231
+ const mtimeMs = typeof file.updatedAt === "string"
232
+ ? Date.parse(file.updatedAt)
233
+ : undefined;
234
+ return Object.assign(Object.assign({ key, size: typeof file.sizeBytes === "number" ? file.sizeBytes : 0 }, (typeof file.etag === "string" && file.etag !== ""
235
+ ? { etag: file.etag }
236
+ : {})), (mtimeMs === undefined || Number.isNaN(mtimeMs) ? {} : { mtimeMs }));
237
+ }
238
+ /**
239
+ * One key's current entry, via the bounded directory listing.
240
+ *
241
+ * The unscoped listing has no prefix parameter, so using it for a point lookup
242
+ * would walk the whole store on the hot write path and cost more the fuller
243
+ * the store got. `?path=` is scoped to one directory and paginates, and the
244
+ * scan stops as soon as the key appears.
245
+ */
246
+ function statKey(key) {
247
+ return __awaiter(this, void 0, void 0, function* () {
248
+ const slash = key.lastIndexOf("/");
249
+ const directory = slash === -1 ? "" : key.slice(0, slash);
250
+ return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
251
+ var _a;
252
+ let pageToken;
253
+ for (let page = 0; page < MAX_DIRECTORY_PAGES; page += 1) {
254
+ const raw = yield directoryPage(files, directory, pageToken);
255
+ for (const file of (_a = raw.files) !== null && _a !== void 0 ? _a : []) {
256
+ if (file.path === key) {
257
+ return toEntry(file, key);
258
+ }
259
+ }
260
+ // `complete` is false exactly when another page is waiting.
261
+ if (raw.complete !== false || raw.nextPageToken === undefined) {
262
+ return undefined;
263
+ }
264
+ pageToken = raw.nextPageToken;
265
+ }
266
+ return undefined;
267
+ }));
268
+ });
269
+ }
270
+ /**
271
+ * Precondition for an unconditional write: replace what is there now, or
272
+ * create when nothing is.
273
+ */
274
+ function currentPrecondition(key) {
275
+ return __awaiter(this, void 0, void 0, function* () {
276
+ const cached = observedEtags.get(key);
277
+ if (cached !== undefined) {
278
+ return { etag: cached };
279
+ }
280
+ const found = yield statKey(key);
281
+ // Unknown falls through to create-only. If the object does in fact exist,
282
+ // the store answers 412 and the caller gets a FileConflictError it can
283
+ // retry with an explicit `ifMatch` — degraded, but never wrong.
284
+ return (found === null || found === void 0 ? void 0 : found.etag) === undefined ? { new: true } : { etag: found.etag };
285
+ });
286
+ }
287
+ return {
288
+ // No local copy: bytes live in the store, so `materializedPath()` is
289
+ // `undefined` and the harness reaches files through `host.files`.
290
+ capabilities: { etags: true },
291
+ put(key, body, putOptions) {
292
+ return __awaiter(this, void 0, void 0, function* () {
293
+ const sha = createHash("sha256").update(body).digest("hex");
294
+ const requested = putOptions === null || putOptions === void 0 ? void 0 : putOptions.ifMatch;
295
+ // The store rejects unconditional writes, so every put carries a
296
+ // precondition. `null` is create-only and an explicit etag is a caller
297
+ // assertion; an unconditional write has to learn the current state,
298
+ // because assuming "absent" would make replace fail on any process that
299
+ // has not already read the path — which is every fresh pod.
300
+ const precondition = requested === null
301
+ ? { new: true }
302
+ : requested !== undefined
303
+ ? { etag: requested }
304
+ : yield currentPrecondition(key);
305
+ return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
306
+ var _a;
307
+ var _b;
308
+ const presigned = yield storePost(options, files.path("/upload"), {
309
+ files: [Object.assign({ path: key, sha, size: body.byteLength }, precondition)],
310
+ });
311
+ const instruction = (_a = presigned.files) === null || _a === void 0 ? void 0 : _a[0];
312
+ if ((instruction === null || instruction === void 0 ? void 0 : instruction.url) === undefined) {
313
+ // Files past the single-part threshold come back with a multipart
314
+ // plan instead of a url; this backend does not implement multipart.
315
+ throw new Error(`cursorHostedFiles: no single-part upload url for "${key}" (too large?)`);
316
+ }
317
+ const response = yield fetchImpl(options)(assertPresignedUrlSafe(options, instruction.url), {
318
+ method: "PUT",
319
+ headers: (_b = instruction.headers) !== null && _b !== void 0 ? _b : {},
320
+ // A view over bytes is a valid fetch body; the DOM lib types are
321
+ // narrower than the runtime, and copying into a Blob would double
322
+ // the memory for every upload.
323
+ body: body,
324
+ // A redirect would re-send the body somewhere the presign did not
325
+ // authorize.
326
+ redirect: "manual",
327
+ });
328
+ if (response.status === 412) {
329
+ // Someone else wrote between our etag observation and this PUT.
330
+ observedEtags.delete(key);
331
+ throw new FileConflictError(key, Object.assign({}, ("etag" in precondition
332
+ ? { storedEtag: precondition.etag }
333
+ : {})));
334
+ }
335
+ if (!response.ok) {
336
+ throw new Error(`cursorHostedFiles: upload of "${key}" failed (HTTP ${response.status})`);
337
+ }
338
+ const etag = normalizeEtag(response.headers.get("etag"));
339
+ if (etag !== undefined) {
340
+ rememberEtag(key, etag);
341
+ }
342
+ return etag === undefined ? {} : { etag };
343
+ }));
344
+ });
345
+ },
346
+ get(key) {
347
+ return __awaiter(this, void 0, void 0, function* () {
348
+ return yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
349
+ var _a, _b;
350
+ const presigned = yield storePost(options, files.path("/download"), { paths: [key] });
351
+ const url = (_b = (_a = presigned.files) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.url;
352
+ if (url === undefined) {
353
+ return undefined;
354
+ }
355
+ const response = yield fetchImpl(options)(assertPresignedUrlSafe(options, url), {
356
+ method: "GET",
357
+ redirect: "manual",
358
+ });
359
+ if (response.status === 404 || response.status === 403) {
360
+ // A presigned GET for a missing object surfaces as 403 on S3.
361
+ return undefined;
362
+ }
363
+ if (!response.ok) {
364
+ throw new Error(`cursorHostedFiles: download of "${key}" failed (HTTP ${response.status})`);
365
+ }
366
+ const etag = normalizeEtag(response.headers.get("etag"));
367
+ if (etag !== undefined) {
368
+ rememberEtag(key, etag);
369
+ }
370
+ return Object.assign({ body: new Uint8Array(yield response.arrayBuffer()) }, (etag === undefined ? {} : { etag }));
371
+ }));
372
+ });
373
+ },
374
+ delete(key) {
375
+ return __awaiter(this, void 0, void 0, function* () {
376
+ if (observedEtags.get(key) === undefined) {
377
+ // Deletes are conditional too, so learn the current etag first. A key
378
+ // we have never seen is already absent as far as the caller cares.
379
+ const found = yield statKey(key);
380
+ if ((found === null || found === void 0 ? void 0 : found.etag) === undefined) {
381
+ return;
382
+ }
383
+ }
384
+ const etag = observedEtags.get(key);
385
+ if (etag === undefined) {
386
+ return;
387
+ }
388
+ yield withFiles((files) => __awaiter(this, void 0, void 0, function* () {
389
+ var _a, _b;
390
+ const raw = yield storePost(options, files.path("/delete"), { files: [{ path: key, etag }] });
391
+ // The API answers 200 with a per-file status, so a lost race would look
392
+ // like success unless the outcome is read.
393
+ const outcome = ((_a = raw.files) !== null && _a !== void 0 ? _a : []).find((entry) => entry.path === key);
394
+ if ((outcome === null || outcome === void 0 ? void 0 : outcome.status) === "conflict") {
395
+ observedEtags.delete(key);
396
+ throw new FileConflictError(key, Object.assign({}, (outcome.etag === undefined
397
+ ? {}
398
+ : { storedEtag: (_b = normalizeEtag(outcome.etag)) !== null && _b !== void 0 ? _b : outcome.etag })));
399
+ }
400
+ }));
401
+ observedEtags.delete(key);
402
+ });
403
+ },
404
+ list: listEntries,
405
+ stat(key) {
406
+ return __awaiter(this, void 0, void 0, function* () {
407
+ return yield statKey(key);
408
+ });
409
+ },
410
+ };
411
+ }
412
+ /**
413
+ * Refuse a presigned URL that does not target this backend's agent-stores
414
+ * bucket.
415
+ *
416
+ * The URL arrives from BCS over TLS, so this is defense in depth rather than
417
+ * a live hole — but the engine pod can reach link-local metadata and other
418
+ * allowlisted egress hosts, so a BCS bug or compromise returning a foreign
419
+ * address would otherwise steer file bytes somewhere the caller never chose.
420
+ * Same pin as the sibling sync client: production backends allow only the
421
+ * agent-stores bucket hosts, playground its bucket, and a local dev backend
422
+ * additionally admits loopback http for LocalStack.
423
+ */
424
+ function assertPresignedUrlSafe(options, raw) {
425
+ let url;
426
+ try {
427
+ url = new URL(raw);
428
+ }
429
+ catch (_a) {
430
+ throw new Error("cursorHostedFiles: presigned URL is not a valid URL");
431
+ }
432
+ try {
433
+ createAgentStorePresignedUrlValidatorForBackend(resolveBaseUrl(options))(url);
434
+ }
435
+ catch (error) {
436
+ throw new Error(`cursorHostedFiles: refused presigned URL: ${error instanceof Error ? error.message : String(error)}`);
437
+ }
438
+ return url.toString();
439
+ }
440
+ function fetchImpl(options) {
441
+ var _a;
442
+ const impl = (_a = options.fetch) !== null && _a !== void 0 ? _a : globalThis.fetch;
443
+ if (typeof impl !== "function") {
444
+ throw new Error("cursorHostedFiles requires fetch");
445
+ }
446
+ return impl;
447
+ }
448
+ /**
449
+ * The file store this engine's deployment owns. Every request names it, so
450
+ * the server resolves the store row and this process never handles a store id.
451
+ *
452
+ * Fails loudly rather than defaulting: with no source id there is no store to
453
+ * address, and writing somewhere else silently is worse than not writing.
454
+ */
455
+ function resolveStoreSourceId(options) {
456
+ var _a;
457
+ var _b;
458
+ const id = (_a = ((_b = options.storeSourceId) !== null && _b !== void 0 ? _b : process.env[AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR])) === null || _a === void 0 ? void 0 : _a.trim();
459
+ if (id === undefined || id === "") {
460
+ throw new Error(`cursorHostedFiles requires ${AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR} (set on Cursor-managed deployments)`);
461
+ }
462
+ return id;
463
+ }
464
+ function resolveApiKey(options) {
465
+ var _a;
466
+ var _b;
467
+ const key = (_a = ((_b = options.apiKey) !== null && _b !== void 0 ? _b : process.env.CURSOR_API_KEY)) === null || _a === void 0 ? void 0 : _a.trim();
468
+ if (key === undefined || key === "") {
469
+ throw new Error("cursorHostedFiles requires CURSOR_API_KEY (deployment pod credential on Cursor hosting)");
470
+ }
471
+ return key;
472
+ }
473
+ function resolveBaseUrl(options) {
474
+ var _a, _b;
475
+ return trimTrailingSlash((_b = (_a = options.baseUrl) !== null && _a !== void 0 ? _a : process.env.CURSOR_API_BASE_URL) !== null && _b !== void 0 ? _b : DEFAULT_CURSOR_EXTERNAL_API_URL);
476
+ }
477
+ function trimTrailingSlash(raw) {
478
+ const trimmed = raw.trim();
479
+ return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
480
+ }
481
+ /**
482
+ * Public agent-serve-files API call. The pod credential is the whole authorization:
483
+ * the API forwards this caller's identity to the store service, which checks it
484
+ * against the store's live owner. There is no second, narrower credential.
485
+ */
486
+ function storePost(options, path, body) {
487
+ return __awaiter(this, void 0, void 0, function* () {
488
+ return yield postJson(options, `${resolveBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`, body);
489
+ });
490
+ }
491
+ function storeGet(options, path) {
492
+ return __awaiter(this, void 0, void 0, function* () {
493
+ return yield sendJson(options, `${resolveBaseUrl(options)}${AGENT_SERVE_FILES_PATH}${path}`, "GET");
494
+ });
495
+ }
496
+ function postJson(options, url, body) {
497
+ return __awaiter(this, void 0, void 0, function* () {
498
+ return yield sendJson(options, url, "POST", body);
499
+ });
500
+ }
501
+ function sendJson(options, url, method, body) {
502
+ return __awaiter(this, void 0, void 0, function* () {
503
+ const response = yield fetchImpl(options)(url, Object.assign({ method, headers: Object.assign({ Authorization: `Bearer ${resolveApiKey(options)}` }, (body === undefined ? {} : { "Content-Type": "application/json" })) }, (body === undefined ? {} : { body: JSON.stringify(body) })));
504
+ const text = yield response.text();
505
+ let parsed;
506
+ try {
507
+ parsed = text.length === 0 ? {} : JSON.parse(text);
508
+ }
509
+ catch (_a) {
510
+ throw new Error(`cursorHostedFiles ${url} returned non-JSON (${response.status})`);
511
+ }
512
+ if (!response.ok) {
513
+ throw new Error(`cursorHostedFiles ${url}: ${describeError(parsed, response.status)}`);
514
+ }
515
+ return parsed;
516
+ });
517
+ }
518
+ function describeError(parsed, status) {
519
+ if (parsed !== null &&
520
+ typeof parsed === "object" &&
521
+ "error" in parsed &&
522
+ typeof parsed.error === "string") {
523
+ return parsed.error;
524
+ }
525
+ if (parsed !== null &&
526
+ typeof parsed === "object" &&
527
+ "message" in parsed &&
528
+ typeof parsed.message === "string") {
529
+ return parsed.message;
530
+ }
531
+ return `HTTP ${status}`;
532
+ }
533
+ /** S3 returns quoted etags; the store compares them unquoted. */
534
+ function normalizeEtag(raw) {
535
+ if (raw === null) {
536
+ return undefined;
537
+ }
538
+ const trimmed = raw.trim().replace(/^"+|"+$/g, "");
539
+ return trimmed === "" ? undefined : trimmed;
540
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Local-disk file sink: one file per key under a directory you own.
3
+ *
4
+ * The default off Cursor-managed hosting. Paths are real, so the harness can
5
+ * open a file with its ordinary tools — that is why this reports
6
+ * `materialized` — and there are no etags, so `conflictDetection` is honestly
7
+ * false and concurrent writers are last-writer-wins.
8
+ */
9
+ import { type FileSink } from "../files.js";
10
+ export interface LocalFilesOptions {
11
+ /** Directory the sink owns. */
12
+ filesRoot: string;
13
+ /**
14
+ * Prefix trimmed off each key before building the on-disk path, so the tree
15
+ * reads `deployment/notes.md` instead of repeating the framework key root.
16
+ *
17
+ * Framework-supplied. Authors should omit it: the value has to match the
18
+ * internal key scheme exactly, and a near-miss would silently nest files
19
+ * under a redundant path instead of failing. Omitted, keys are stored
20
+ * verbatim, which is always correct and lets two agents share one root.
21
+ */
22
+ stripKeyPrefix?: string;
23
+ }
24
+ /**
25
+ * Default sink: one file per key under the state root, written atomically.
26
+ *
27
+ * Reports `materialized` because the paths are real — that is what lets the
28
+ * harness read a file with its ordinary tools — and reports no `etags`, so
29
+ * `host.files.capabilities.conflictDetection` is honestly false and concurrent
30
+ * writers are last-writer-wins.
31
+ */
32
+ export declare function localFiles(options: LocalFilesOptions): FileSink;
33
+ //# sourceMappingURL=local-fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-fs.d.ts","sourceRoot":"","sources":["../../src/files-backends/local-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,OAAO,EAEL,KAAK,QAAQ,EAGd,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,QAAQ,CAmG/D"}