@cursor/bdk 0.2.3 → 0.2.4

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 (577) hide show
  1. package/dist/bin/agent-serve.js +9 -1
  2. package/dist/channels/slack/attachments.d.ts +2 -1
  3. package/dist/channels/slack/attachments.d.ts.map +1 -1
  4. package/dist/channels/slack/attachments.js +19 -9
  5. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  6. package/dist/channels/slack/dispatch.js +26 -24
  7. package/dist/channels/slack/thread-context.d.ts +21 -11
  8. package/dist/channels/slack/thread-context.d.ts.map +1 -1
  9. package/dist/channels/slack/thread-context.js +75 -27
  10. package/dist/docs/404.html +2 -2
  11. package/dist/docs/assets/{app.BOIHhrKi.js → app.4kQ8Db_q.js} +4 -4
  12. package/dist/docs/assets/chunks/@localSearchIndexroot.CvuAJ0My.js +1 -0
  13. package/dist/docs/assets/chunks/{VPLocalSearchBox.D49zVZqM.js → VPLocalSearchBox.DY1RwB8Q.js} +1 -1
  14. package/dist/docs/assets/chunks/{arc.hmjb-sc4.js → arc.CxE_fSPK.js} +1 -1
  15. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.CxEI1KqM.js → architectureDiagram-Q4EWVU46.CPX426ui.js} +1 -1
  16. package/dist/docs/assets/chunks/{baseUniq.DHHvBWoV.js → baseUniq.CB52JrKG.js} +1 -1
  17. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.DnXW-3bu.js → blockDiagram-DXYQGD6D.J0cNaQCL.js} +1 -1
  18. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.e-47O2jM.js → c4Diagram-AHTNJAMY.DJn3vEGT.js} +1 -1
  19. package/dist/docs/assets/chunks/channel.BoNycAoN.js +1 -0
  20. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.3ry4pYXB.js → chunk-4BX2VUAB.Dao618F6.js} +1 -1
  21. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.DGIZFRx6.js → chunk-4TB4RGXK.QW8Rhjai.js} +1 -1
  22. package/dist/docs/assets/chunks/{chunk-55IACEB6.DKBnqg9U.js → chunk-55IACEB6.DfRLLKF_.js} +1 -1
  23. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.BIU8Ue5k.js → chunk-EDXVE4YY.CIV2ApKQ.js} +1 -1
  24. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.DP-TFhjI.js → chunk-FMBD7UC4.BEheSuxp.js} +1 -1
  25. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.Ux0OYj5v.js → chunk-OYMX7WX6.CUN88ENB.js} +1 -1
  26. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BzHMwYox.js → chunk-QZHKN3VN.CgqCs8b_.js} +1 -1
  27. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.D4OGAsSP.js → chunk-YZCP3GAM.iCH0nnTJ.js} +1 -1
  28. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.C4x07Gkj.js +1 -0
  29. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.C4x07Gkj.js +1 -0
  30. package/dist/docs/assets/chunks/clone.Db22cH_-.js +1 -0
  31. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.Jq_7BUNx.js → cose-bilkent-S5V4N54A.BLcUxhWE.js} +1 -1
  32. package/dist/docs/assets/chunks/{dagre-KV5264BT.Di-skR2x.js → dagre-KV5264BT.Ep7LofOm.js} +1 -1
  33. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.DeREHIdH.js → diagram-5BDNPKRD.Bzf4GSQ4.js} +1 -1
  34. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.C7Kcqxro.js → diagram-G4DWMVQ6.DD6Jh-eM.js} +1 -1
  35. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.BK3eohyo.js → diagram-MMDJMWI5.oOIl8bWd.js} +1 -1
  36. package/dist/docs/assets/chunks/{diagram-TYMM5635.C6TyymXT.js → diagram-TYMM5635.DHs85Ade.js} +1 -1
  37. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.DYGG-gGx.js → erDiagram-SMLLAGMA.BIb5ghCk.js} +1 -1
  38. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.C9nBcSV4.js → flowDiagram-DWJPFMVM.DV4paY9k.js} +1 -1
  39. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.wAg_ymsp.js → ganttDiagram-T4ZO3ILL.AyEKA6_v.js} +1 -1
  40. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.B87j9Oeg.js → gitGraphDiagram-UUTBAWPF.BltiCDFo.js} +1 -1
  41. package/dist/docs/assets/chunks/{graph.CuFMj31w.js → graph.DzuEYGdC.js} +1 -1
  42. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.P_mLGumP.js → infoDiagram-42DDH7IO.BV2l981J.js} +1 -1
  43. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DyuL_MsT.js → ishikawaDiagram-UXIWVN3A.BA4Izf-m.js} +1 -1
  44. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.CtP09IoJ.js → journeyDiagram-VCZTEJTY.DjaFbFS3.js} +1 -1
  45. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.BoeSYPZo.js → kanban-definition-6JOO6SKY.CfTFieDs.js} +1 -1
  46. package/dist/docs/assets/chunks/{layout.B0lMMtNo.js → layout.DzfWqTBV.js} +1 -1
  47. package/dist/docs/assets/chunks/{linear.HxRBiAFX.js → linear.BO6mpulV.js} +1 -1
  48. package/dist/docs/assets/chunks/{min.BGlFFHwS.js → min.BGgTadgT.js} +1 -1
  49. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.JyLBD9M8.js → mindmap-definition-QFDTVHPH.DPuIXVWY.js} +1 -1
  50. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DnSmNZF8.js → pieDiagram-DEJITSTG.BOnl3bBg.js} +1 -1
  51. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.CUCnbfCa.js → quadrantDiagram-34T5L4WZ.DNB6Ckdc.js} +1 -1
  52. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.py0IVUn5.js → requirementDiagram-MS252O5E.D5-Qo7vb.js} +1 -1
  53. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.Bkc-HWYp.js → sankeyDiagram-XADWPNL6.8t65cesf.js} +1 -1
  54. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.Dqn8Mlv2.js → sequenceDiagram-FGHM5R23.CaG07BdS.js} +1 -1
  55. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.JikkoQUU.js → stateDiagram-FHFEXIEX.TKOweTB6.js} +1 -1
  56. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.CuqmyQc4.js +1 -0
  57. package/dist/docs/assets/chunks/{theme.b6HQ6zG_.js → theme.Dx-JhpTB.js} +2 -2
  58. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.BvpSXiBj.js → timeline-definition-GMOUNBTQ.fE53zQ2s.js} +1 -1
  59. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CU7MVnZx.js → vennDiagram-DHZGUBPP.DJsZZaJg.js} +1 -1
  60. package/dist/docs/assets/chunks/{wardley-RL74JXVD.BKwC4ctG.js → wardley-RL74JXVD.844kyrjl.js} +1 -1
  61. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.BfaF6Uhe.js → wardleyDiagram-NUSXRM2D.CMZ-Ru_t.js} +1 -1
  62. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.Bg5dcpj4.js → xychartDiagram-5P7HB3ND.XXrhBc7a.js} +1 -1
  63. package/dist/docs/assets/{deployment.md.BJ8i7Q6p.js → deployment.md.UhnJIMr-.js} +2 -2
  64. package/dist/docs/assets/{deployment.md.BJ8i7Q6p.lean.js → deployment.md.UhnJIMr-.lean.js} +1 -1
  65. package/dist/docs/assets/{guides_jev.md.BNDm14Gy.js → guides_jev.md.CRcgmjDb.js} +2 -2
  66. package/dist/docs/assets/{guides_jev.md.BNDm14Gy.lean.js → guides_jev.md.CRcgmjDb.lean.js} +1 -1
  67. package/dist/docs/assets/{reference_agent-config.md.DzGI777n.js → reference_agent-config.md.Cj5uBKp4.js} +1 -1
  68. package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.js → reference_extensions.md.pa2tN-e4.js} +4 -3
  69. package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.lean.js → reference_extensions.md.pa2tN-e4.lean.js} +1 -1
  70. package/dist/docs/building-with-agents.html +35 -35
  71. package/dist/docs/deployment.html +37 -37
  72. package/dist/docs/deployment.md +4 -1
  73. package/dist/docs/evals.html +35 -35
  74. package/dist/docs/guides/agent-to-agent.html +35 -35
  75. package/dist/docs/guides/bitbucket.html +35 -35
  76. package/dist/docs/guides/cloud-agents.html +35 -35
  77. package/dist/docs/guides/convert-automation.html +35 -35
  78. package/dist/docs/guides/github.html +35 -35
  79. package/dist/docs/guides/gitlab.html +35 -35
  80. package/dist/docs/guides/grokbot-agents.html +35 -35
  81. package/dist/docs/guides/hooks.html +35 -35
  82. package/dist/docs/guides/improve.html +35 -35
  83. package/dist/docs/guides/jev.html +37 -37
  84. package/dist/docs/guides/jev.md +7 -0
  85. package/dist/docs/guides/mcp-oauth.html +35 -35
  86. package/dist/docs/guides/opentelemetry.html +35 -35
  87. package/dist/docs/guides/slack.html +35 -35
  88. package/dist/docs/guides/webhooks.html +35 -35
  89. package/dist/docs/hashmap.json +1 -1
  90. package/dist/docs/hillclimbing.html +35 -35
  91. package/dist/docs/index.html +35 -35
  92. package/dist/docs/llms-full.txt +25 -2
  93. package/dist/docs/quickstart.html +35 -35
  94. package/dist/docs/reference/agent-config.html +37 -37
  95. package/dist/docs/reference/agent-config.md +1 -1
  96. package/dist/docs/reference/artifacts.html +35 -35
  97. package/dist/docs/reference/channels.html +35 -35
  98. package/dist/docs/reference/cli.html +35 -35
  99. package/dist/docs/reference/connections.html +35 -35
  100. package/dist/docs/reference/evals.html +35 -35
  101. package/dist/docs/reference/extensions.html +39 -38
  102. package/dist/docs/reference/extensions.md +13 -0
  103. package/dist/docs/reference/hooks.html +35 -35
  104. package/dist/docs/reference/http-api.html +35 -35
  105. package/dist/docs/reference/instructions.html +35 -35
  106. package/dist/docs/reference/playground.html +35 -35
  107. package/dist/docs/reference/project-layout.html +35 -35
  108. package/dist/docs/reference/prompt.html +35 -35
  109. package/dist/docs/reference/schedules.html +35 -35
  110. package/dist/docs/reference/sessions.html +35 -35
  111. package/dist/docs/reference/skills.html +35 -35
  112. package/dist/docs/reference/subagents.html +35 -35
  113. package/dist/docs/reference/tools.html +35 -35
  114. package/dist/docs/templates/agentic-owners.html +35 -35
  115. package/dist/docs/templates/security-reviewer.html +35 -35
  116. package/dist/docs/templates/thermo-quality-review.html +35 -35
  117. package/dist/docs/templates/thermo-review.html +35 -35
  118. package/dist/docs/templates/triage.html +35 -35
  119. package/dist/docs/troubleshooting.html +35 -35
  120. package/dist/extensions/jev/extension.d.ts +3 -0
  121. package/dist/extensions/jev/extension.d.ts.map +1 -1
  122. package/dist/extensions/jev/extension.js +10 -1
  123. package/dist/extensions/jev/lib/evaluate.d.ts +4 -0
  124. package/dist/extensions/jev/lib/evaluate.d.ts.map +1 -1
  125. package/dist/extensions/jev/lib/evaluate.js +6 -2
  126. package/dist/extensions.d.ts +4 -2
  127. package/dist/extensions.d.ts.map +1 -1
  128. package/dist/extensions.js +5 -2
  129. package/dist/internal/cli-deploy.d.ts.map +1 -1
  130. package/dist/internal/cli-deploy.js +19 -5
  131. package/dist/internal/discovery/agent-config.d.ts +6 -5
  132. package/dist/internal/discovery/agent-config.d.ts.map +1 -1
  133. package/dist/internal/discovery/agent-config.js +29 -28
  134. package/dist/internal/discovery/agent.js +1 -1
  135. package/dist/internal/discovery/extensions.d.ts.map +1 -1
  136. package/dist/internal/discovery/extensions.js +12 -0
  137. package/dist/internal/hosting.d.ts +8 -0
  138. package/dist/internal/hosting.d.ts.map +1 -1
  139. package/dist/internal/hosting.js +24 -0
  140. package/dist/types.d.ts +18 -2
  141. package/dist/types.d.ts.map +1 -1
  142. package/docs/deployment.md +4 -1
  143. package/docs/guides/jev.md +7 -0
  144. package/docs/reference/agent-config.md +1 -1
  145. package/docs/reference/extensions.md +13 -0
  146. package/package.json +1 -9
  147. package/dist/docs/assets/chunks/@localSearchIndexroot.D5L-b34G.js +0 -1
  148. package/dist/docs/assets/chunks/channel.BbOGaJQP.js +0 -1
  149. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.Db58HCb1.js +0 -1
  150. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.Db58HCb1.js +0 -1
  151. package/dist/docs/assets/chunks/clone.Co4MBflG.js +0 -1
  152. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.CMsKhrW0.js +0 -1
  153. package/src/artifacts.ts +0 -68
  154. package/src/bin/agent-serve.ts +0 -1854
  155. package/src/channels/bitbucket/api.ts +0 -891
  156. package/src/channels/bitbucket/binding.ts +0 -417
  157. package/src/channels/bitbucket/bitbucket-channel.ts +0 -162
  158. package/src/channels/bitbucket/bitbucket-webhook.ts +0 -519
  159. package/src/channels/bitbucket/checks.ts +0 -146
  160. package/src/channels/bitbucket/cursor-account.ts +0 -106
  161. package/src/channels/bitbucket/defaults.ts +0 -100
  162. package/src/channels/bitbucket/events.ts +0 -74
  163. package/src/channels/bitbucket/index.ts +0 -51
  164. package/src/channels/bitbucket/replay.ts +0 -421
  165. package/src/channels/bitbucket/state.ts +0 -59
  166. package/src/channels/bitbucket/types.ts +0 -261
  167. package/src/channels/change-monitors/change-monitors-channel.ts +0 -63
  168. package/src/channels/change-monitors/index.ts +0 -8
  169. package/src/channels/change-monitors/types.ts +0 -42
  170. package/src/channels/checks.ts +0 -185
  171. package/src/channels/deployments/deployments-channel.ts +0 -224
  172. package/src/channels/deployments/index.ts +0 -25
  173. package/src/channels/deployments/types.ts +0 -92
  174. package/src/channels/github/api.ts +0 -526
  175. package/src/channels/github/auth.ts +0 -293
  176. package/src/channels/github/binding.ts +0 -233
  177. package/src/channels/github/checks.ts +0 -145
  178. package/src/channels/github/cursor-account.ts +0 -303
  179. package/src/channels/github/defaults.ts +0 -168
  180. package/src/channels/github/events.ts +0 -67
  181. package/src/channels/github/forward.ts +0 -359
  182. package/src/channels/github/github-channel.ts +0 -2334
  183. package/src/channels/github/index.ts +0 -54
  184. package/src/channels/github/progress.ts +0 -365
  185. package/src/channels/github/replay.ts +0 -372
  186. package/src/channels/github/state.ts +0 -124
  187. package/src/channels/github/types.ts +0 -590
  188. package/src/channels/gitlab/api.ts +0 -329
  189. package/src/channels/gitlab/binding.ts +0 -231
  190. package/src/channels/gitlab/checks.ts +0 -228
  191. package/src/channels/gitlab/cursor-account.ts +0 -105
  192. package/src/channels/gitlab/defaults.ts +0 -80
  193. package/src/channels/gitlab/events.ts +0 -37
  194. package/src/channels/gitlab/gitlab-channel.ts +0 -160
  195. package/src/channels/gitlab/gitlab-webhook.ts +0 -509
  196. package/src/channels/gitlab/index.ts +0 -44
  197. package/src/channels/gitlab/replay.ts +0 -328
  198. package/src/channels/gitlab/state.ts +0 -55
  199. package/src/channels/gitlab/types.ts +0 -247
  200. package/src/channels/issues/index.ts +0 -9
  201. package/src/channels/issues/issues-channel.ts +0 -45
  202. package/src/channels/issues/types.ts +0 -38
  203. package/src/channels/origin/api.ts +0 -507
  204. package/src/channels/origin/binding.ts +0 -114
  205. package/src/channels/origin/checks.ts +0 -250
  206. package/src/channels/origin/cursor-account.ts +0 -58
  207. package/src/channels/origin/defaults.ts +0 -140
  208. package/src/channels/origin/events.ts +0 -35
  209. package/src/channels/origin/index.ts +0 -35
  210. package/src/channels/origin/origin-channel.ts +0 -815
  211. package/src/channels/origin/origin-webhook.ts +0 -296
  212. package/src/channels/origin/reactions.ts +0 -72
  213. package/src/channels/origin/state.ts +0 -54
  214. package/src/channels/origin/types.ts +0 -295
  215. package/src/channels/slack/agentic-delivery.ts +0 -634
  216. package/src/channels/slack/agentic-posted.ts +0 -135
  217. package/src/channels/slack/agentic-signals.ts +0 -231
  218. package/src/channels/slack/api.ts +0 -761
  219. package/src/channels/slack/approvals.ts +0 -279
  220. package/src/channels/slack/assistant.ts +0 -76
  221. package/src/channels/slack/attachments.ts +0 -596
  222. package/src/channels/slack/auth.ts +0 -127
  223. package/src/channels/slack/blocks.ts +0 -131
  224. package/src/channels/slack/bot-mentions.ts +0 -318
  225. package/src/channels/slack/channel-watch.ts +0 -314
  226. package/src/channels/slack/cli-project.ts +0 -249
  227. package/src/channels/slack/code-fences.ts +0 -171
  228. package/src/channels/slack/constants.ts +0 -38
  229. package/src/channels/slack/credentials.ts +0 -88
  230. package/src/channels/slack/defaults.ts +0 -714
  231. package/src/channels/slack/dispatch.ts +0 -1060
  232. package/src/channels/slack/doctor.ts +0 -338
  233. package/src/channels/slack/eval-directive.ts +0 -306
  234. package/src/channels/slack/event-id-dedupe.ts +0 -30
  235. package/src/channels/slack/external-policy.ts +0 -75
  236. package/src/channels/slack/footer.ts +0 -106
  237. package/src/channels/slack/inbound.ts +0 -416
  238. package/src/channels/slack/index.ts +0 -53
  239. package/src/channels/slack/init.ts +0 -169
  240. package/src/channels/slack/interactive.ts +0 -406
  241. package/src/channels/slack/links.ts +0 -23
  242. package/src/channels/slack/live-delivery.ts +0 -489
  243. package/src/channels/slack/log.ts +0 -70
  244. package/src/channels/slack/manifest.ts +0 -240
  245. package/src/channels/slack/message-body.ts +0 -82
  246. package/src/channels/slack/nudge-carrier.ts +0 -224
  247. package/src/channels/slack/nudge-store.ts +0 -334
  248. package/src/channels/slack/paint-start.ts +0 -93
  249. package/src/channels/slack/placeholder.ts +0 -358
  250. package/src/channels/slack/pr-ref.ts +0 -74
  251. package/src/channels/slack/progress-delivery.ts +0 -138
  252. package/src/channels/slack/reasoning-card.ts +0 -125
  253. package/src/channels/slack/reasoning-chip.ts +0 -41
  254. package/src/channels/slack/recording-sink.ts +0 -167
  255. package/src/channels/slack/redact.ts +0 -6
  256. package/src/channels/slack/reply-options.ts +0 -279
  257. package/src/channels/slack/setup.ts +0 -125
  258. package/src/channels/slack/slack-channel.ts +0 -744
  259. package/src/channels/slack/socket-mode.ts +0 -140
  260. package/src/channels/slack/stop.ts +0 -25
  261. package/src/channels/slack/stream.ts +0 -66
  262. package/src/channels/slack/thread-context.ts +0 -485
  263. package/src/channels/slack/tool-approval-events.ts +0 -233
  264. package/src/channels/slack/tool-cards.ts +0 -198
  265. package/src/channels/slack/tool-chip.ts +0 -34
  266. package/src/channels/slack/types.ts +0 -787
  267. package/src/channels/slack/upload.ts +0 -137
  268. package/src/channels.ts +0 -543
  269. package/src/connections.ts +0 -153
  270. package/src/dashboard-session-url.ts +0 -30
  271. package/src/evals/assertions.ts +0 -688
  272. package/src/evals/expect.ts +0 -250
  273. package/src/evals/judge.ts +0 -329
  274. package/src/evals/loaders.ts +0 -111
  275. package/src/evals/matchers.ts +0 -223
  276. package/src/evals/reporters.ts +0 -257
  277. package/src/evals/results.ts +0 -130
  278. package/src/evals/run-facts.ts +0 -306
  279. package/src/evals.ts +0 -709
  280. package/src/extensions/cursor-cloud-agents/extension.ts +0 -131
  281. package/src/extensions/cursor-cloud-agents/lib/backend.ts +0 -386
  282. package/src/extensions/cursor-cloud-agents/lib/channels.ts +0 -11
  283. package/src/extensions/cursor-cloud-agents/lib/fleet.ts +0 -98
  284. package/src/extensions/cursor-cloud-agents/lib/inputs.ts +0 -5
  285. package/src/extensions/cursor-cloud-agents/lib/repos.ts +0 -80
  286. package/src/extensions/cursor-cloud-agents/lib/transcript.ts +0 -19
  287. package/src/extensions/cursor-cloud-agents/skills/handoff.md +0 -37
  288. package/src/extensions/cursor-cloud-agents/tools/cancel.ts +0 -21
  289. package/src/extensions/cursor-cloud-agents/tools/dump.ts +0 -47
  290. package/src/extensions/cursor-cloud-agents/tools/get.ts +0 -18
  291. package/src/extensions/cursor-cloud-agents/tools/launch.ts +0 -62
  292. package/src/extensions/cursor-cloud-agents/tools/list.ts +0 -31
  293. package/src/extensions/cursor-cloud-agents/tools/reply.ts +0 -36
  294. package/src/extensions/cursor-grokbot-agents/extension.ts +0 -132
  295. package/src/extensions/cursor-grokbot-agents/lib/agents.ts +0 -42
  296. package/src/extensions/cursor-grokbot-agents/lib/backend.ts +0 -208
  297. package/src/extensions/cursor-grokbot-agents/lib/contacts.ts +0 -74
  298. package/src/extensions/cursor-grokbot-agents/lib/conversation.ts +0 -260
  299. package/src/extensions/cursor-grokbot-agents/lib/inputs.ts +0 -21
  300. package/src/extensions/cursor-grokbot-agents/lib/lock.ts +0 -26
  301. package/src/extensions/cursor-grokbot-agents/skills/consult.md +0 -40
  302. package/src/extensions/cursor-grokbot-agents/tools/ask.ts +0 -32
  303. package/src/extensions/cursor-grokbot-agents/tools/check.ts +0 -25
  304. package/src/extensions/cursor-grokbot-agents/tools/interrupt.ts +0 -17
  305. package/src/extensions/cursor-grokbot-agents/tools/list.ts +0 -26
  306. package/src/extensions/improve/extension.ts +0 -69
  307. package/src/extensions/improve/skills/yourself.ts +0 -50
  308. package/src/extensions/jev/extension.ts +0 -95
  309. package/src/extensions/jev/lib/evaluate.ts +0 -266
  310. package/src/extensions/jev/skills/gated-write.md +0 -25
  311. package/src/extensions/jev/skills/questions.md +0 -33
  312. package/src/extensions/jev/tools/evaluate.ts +0 -82
  313. package/src/extensions/slack-communication/evals/harness.ts +0 -705
  314. package/src/extensions/slack-communication/evals/slack-communication.eval.ts +0 -830
  315. package/src/extensions/slack-communication/evals/slack-placeholder.eval.ts +0 -172
  316. package/src/extensions/slack-communication/extension.ts +0 -44
  317. package/src/extensions/slack-communication/skills/slack-voice.ts +0 -56
  318. package/src/extensions/slack-communication/tools/delete-message.ts +0 -33
  319. package/src/extensions/slack-communication/tools/edit-message.ts +0 -42
  320. package/src/extensions/slack-communication/tools/post-card.ts +0 -28
  321. package/src/extensions/slack-communication/tools/post-file.ts +0 -82
  322. package/src/extensions/slack-communication/tools/post-update.ts +0 -40
  323. package/src/extensions/slack-communication/tools/react.ts +0 -30
  324. package/src/extensions/slack-communication/tools/set-status.ts +0 -21
  325. package/src/extensions.ts +0 -179
  326. package/src/files-backends/agent-store-presigned-url.ts +0 -11
  327. package/src/files-backends/cursor-hosted.ts +0 -1212
  328. package/src/files-backends/local-fs.ts +0 -163
  329. package/src/files.ts +0 -293
  330. package/src/filesystem.ts +0 -2005
  331. package/src/hooks.ts +0 -30
  332. package/src/index.ts +0 -259
  333. package/src/internal/advertise-tools.ts +0 -370
  334. package/src/internal/approval-gate.ts +0 -103
  335. package/src/internal/artifacts-store.ts +0 -836
  336. package/src/internal/as-of.ts +0 -257
  337. package/src/internal/auth.ts +0 -46
  338. package/src/internal/authored-alias-hooks.ts +0 -138
  339. package/src/internal/authored-loaders.ts +0 -188
  340. package/src/internal/bounded-int.ts +0 -24
  341. package/src/internal/bounded.ts +0 -25
  342. package/src/internal/brand.ts +0 -28
  343. package/src/internal/browser-origin-guard.ts +0 -67
  344. package/src/internal/builtin-tools/artifacts.ts +0 -62
  345. package/src/internal/builtin-tools/index.ts +0 -53
  346. package/src/internal/builtin-tools/reminders.ts +0 -145
  347. package/src/internal/channel-dispatch.ts +0 -129
  348. package/src/internal/channel-route-dispatch.ts +0 -58
  349. package/src/internal/channel-state.ts +0 -83
  350. package/src/internal/chat-client.ts +0 -594
  351. package/src/internal/cli-ax.ts +0 -2318
  352. package/src/internal/cli-bitbucket.ts +0 -438
  353. package/src/internal/cli-convert-automation.ts +0 -335
  354. package/src/internal/cli-cursor.ts +0 -282
  355. package/src/internal/cli-deploy.ts +0 -2519
  356. package/src/internal/cli-docs.ts +0 -192
  357. package/src/internal/cli-github.ts +0 -806
  358. package/src/internal/cli-gitlab.ts +0 -452
  359. package/src/internal/cli-images.ts +0 -672
  360. package/src/internal/cli-manifest.ts +0 -56
  361. package/src/internal/cli-mcp-oauth.ts +0 -396
  362. package/src/internal/cli-mcp.ts +0 -808
  363. package/src/internal/cli-skills.ts +0 -98
  364. package/src/internal/cli-slack-manual.ts +0 -418
  365. package/src/internal/cli-slack.ts +0 -874
  366. package/src/internal/cloud-merge.ts +0 -51
  367. package/src/internal/cloud-turn-cost.ts +0 -159
  368. package/src/internal/connection-env.ts +0 -106
  369. package/src/internal/continuation-channel.ts +0 -233
  370. package/src/internal/continuation-identity.ts +0 -935
  371. package/src/internal/conversation-mirror.ts +0 -423
  372. package/src/internal/convert-automation/convert-workflow.ts +0 -1377
  373. package/src/internal/convert-automation/slug.ts +0 -29
  374. package/src/internal/convert-automation/types.ts +0 -212
  375. package/src/internal/cron.ts +0 -76
  376. package/src/internal/cursor/account-mcp.ts +0 -692
  377. package/src/internal/cursor/backend-client.ts +0 -984
  378. package/src/internal/cursor/bound-secret-file.ts +0 -101
  379. package/src/internal/cursor/credentials.ts +0 -560
  380. package/src/internal/cursor/cursor-api-transport.ts +0 -65
  381. package/src/internal/cursor/github-credentials.ts +0 -228
  382. package/src/internal/cursor/hosted-bound-secrets.ts +0 -71
  383. package/src/internal/cursor/hosted-deployment-secrets.ts +0 -100
  384. package/src/internal/cursor/hosted-store-secrets.ts +0 -152
  385. package/src/internal/cursor/session-token.ts +0 -111
  386. package/src/internal/cursor/store-api-client.ts +0 -323
  387. package/src/internal/cursor-account-mcp-auth.ts +0 -303
  388. package/src/internal/cursor-agent-template.ts +0 -50
  389. package/src/internal/cursor-deployment-relay.ts +0 -315
  390. package/src/internal/cursor-event-relay.ts +0 -675
  391. package/src/internal/cursor-relay-core.ts +0 -563
  392. package/src/internal/deferred-channel-session.ts +0 -61
  393. package/src/internal/deploy-client.ts +0 -1574
  394. package/src/internal/deploy-manifest.ts +0 -361
  395. package/src/internal/deploy-source.ts +0 -144
  396. package/src/internal/describe-error.ts +0 -32
  397. package/src/internal/dev-mode.ts +0 -20
  398. package/src/internal/discovery/agent-config.ts +0 -288
  399. package/src/internal/discovery/agent.ts +0 -381
  400. package/src/internal/discovery/channels.ts +0 -100
  401. package/src/internal/discovery/connections.ts +0 -516
  402. package/src/internal/discovery/context.ts +0 -38
  403. package/src/internal/discovery/cursor-plugin.ts +0 -628
  404. package/src/internal/discovery/extension-overlay.ts +0 -247
  405. package/src/internal/discovery/extensions.ts +0 -490
  406. package/src/internal/discovery/fs.ts +0 -103
  407. package/src/internal/discovery/hooks.ts +0 -63
  408. package/src/internal/discovery/info.ts +0 -174
  409. package/src/internal/discovery/instructions.ts +0 -98
  410. package/src/internal/discovery/modules.ts +0 -107
  411. package/src/internal/discovery/names.ts +0 -45
  412. package/src/internal/discovery/project.ts +0 -319
  413. package/src/internal/discovery/reminders.ts +0 -65
  414. package/src/internal/discovery/runtime.ts +0 -158
  415. package/src/internal/discovery/schedules.ts +0 -120
  416. package/src/internal/discovery/seed-files.ts +0 -34
  417. package/src/internal/discovery/services.ts +0 -151
  418. package/src/internal/discovery/skills.ts +0 -174
  419. package/src/internal/discovery/subagent.ts +0 -138
  420. package/src/internal/discovery/tools.ts +0 -170
  421. package/src/internal/discovery.ts +0 -27
  422. package/src/internal/distribution.ts +0 -126
  423. package/src/internal/docs-site.ts +0 -248
  424. package/src/internal/duration.ts +0 -37
  425. package/src/internal/env-file.ts +0 -83
  426. package/src/internal/eval-judge-model.ts +0 -142
  427. package/src/internal/eval-run-store.ts +0 -585
  428. package/src/internal/eval-runner.ts +0 -823
  429. package/src/internal/evals-client.ts +0 -475
  430. package/src/internal/event-log.ts +0 -342
  431. package/src/internal/event-mapper.ts +0 -811
  432. package/src/internal/expected-delivery-failure.ts +0 -34
  433. package/src/internal/factory-resource-channel.ts +0 -103
  434. package/src/internal/filesystem/errors.ts +0 -207
  435. package/src/internal/filesystem/format.ts +0 -253
  436. package/src/internal/filesystem/merge.ts +0 -192
  437. package/src/internal/filesystem/nearest.ts +0 -112
  438. package/src/internal/filesystem/scratch.ts +0 -239
  439. package/src/internal/filesystem/sdk-schemas.ts +0 -204
  440. package/src/internal/filesystem/tools.ts +0 -804
  441. package/src/internal/filesystem/walk.ts +0 -366
  442. package/src/internal/fixtures/units-server.ts +0 -52
  443. package/src/internal/framework-file-storage.ts +0 -357
  444. package/src/internal/framework-storage-selection.ts +0 -156
  445. package/src/internal/frontmatter.ts +0 -108
  446. package/src/internal/github-fanout.ts +0 -144
  447. package/src/internal/guest-network.ts +0 -391
  448. package/src/internal/handleAgentServeTrigger.ts +0 -286
  449. package/src/internal/host-files.ts +0 -341
  450. package/src/internal/host-kv.ts +0 -81
  451. package/src/internal/host-otel.ts +0 -231
  452. package/src/internal/host-platforms.ts +0 -170
  453. package/src/internal/hosted-admission-adapter.ts +0 -47
  454. package/src/internal/hosted-admission-context.ts +0 -37
  455. package/src/internal/hosted-catch-protocol.ts +0 -112
  456. package/src/internal/hosted-catch.ts +0 -179
  457. package/src/internal/hosted-delivery-protocol.ts +0 -824
  458. package/src/internal/hosted-delivery.ts +0 -1410
  459. package/src/internal/hosted-execution-diag.ts +0 -291
  460. package/src/internal/hosted-execution-flush.ts +0 -136
  461. package/src/internal/hosted-execution-latency.ts +0 -301
  462. package/src/internal/hosted-managed-automation.ts +0 -116
  463. package/src/internal/hosting.ts +0 -114
  464. package/src/internal/http-channel-define.ts +0 -25
  465. package/src/internal/http-channel.ts +0 -669
  466. package/src/internal/http-control-plane-session.ts +0 -110
  467. package/src/internal/ids.ts +0 -39
  468. package/src/internal/incoming-headers-to-fetch.ts +0 -45
  469. package/src/internal/init-interview.ts +0 -360
  470. package/src/internal/init-project.ts +0 -711
  471. package/src/internal/init-scaffold.ts +0 -182
  472. package/src/internal/inline-stdio-define-stub.ts +0 -4
  473. package/src/internal/inline-stdio-mcp.ts +0 -230
  474. package/src/internal/install-cursor-skills.ts +0 -604
  475. package/src/internal/is-record.ts +0 -3
  476. package/src/internal/json-schema.ts +0 -95
  477. package/src/internal/legacy-command-guard.ts +0 -66
  478. package/src/internal/listen-port.ts +0 -85
  479. package/src/internal/local-control-plane.ts +0 -442
  480. package/src/internal/local-env.ts +0 -59
  481. package/src/internal/local-ingress.ts +0 -90
  482. package/src/internal/log-ring.ts +0 -59
  483. package/src/internal/logs-client.ts +0 -477
  484. package/src/internal/map-pool.ts +0 -39
  485. package/src/internal/mcp-endpoint.ts +0 -747
  486. package/src/internal/mcp-host.ts +0 -509
  487. package/src/internal/mcp-oauth-on-demand.ts +0 -337
  488. package/src/internal/mcp-oauth-persist.ts +0 -118
  489. package/src/internal/mcp-oauth.ts +0 -549
  490. package/src/internal/net.ts +0 -29
  491. package/src/internal/open-browser.ts +0 -41
  492. package/src/internal/otel/attrs.ts +0 -16
  493. package/src/internal/otel/collector.ts +0 -937
  494. package/src/internal/otel/config.ts +0 -287
  495. package/src/internal/otel/http.ts +0 -122
  496. package/src/internal/otel/mcp.ts +0 -56
  497. package/src/internal/otel/propagation.ts +0 -17
  498. package/src/internal/otel/runtime.ts +0 -441
  499. package/src/internal/package-inline-stdio.ts +0 -114
  500. package/src/internal/peer-connections.ts +0 -96
  501. package/src/internal/platform-schedule-sync.ts +0 -75
  502. package/src/internal/platform-timers.ts +0 -365
  503. package/src/internal/playground/static.ts +0 -278
  504. package/src/internal/playground/toolchain.ts +0 -270
  505. package/src/internal/playground-proxy.ts +0 -564
  506. package/src/internal/process-memory-telemetry.ts +0 -334
  507. package/src/internal/project-layout.ts +0 -31
  508. package/src/internal/prompt-context.ts +0 -116
  509. package/src/internal/reminder-control-plane-protocol.ts +0 -482
  510. package/src/internal/reminder-runner.ts +0 -1559
  511. package/src/internal/reminder-schedule.ts +0 -104
  512. package/src/internal/reminder-store.ts +0 -176
  513. package/src/internal/request-error-status.ts +0 -95
  514. package/src/internal/request-headers.ts +0 -21
  515. package/src/internal/resolve-prod-target.ts +0 -334
  516. package/src/internal/resolved-connections.ts +0 -190
  517. package/src/internal/router.ts +0 -143
  518. package/src/internal/run-client.ts +0 -354
  519. package/src/internal/runtime-dispatch-runner.ts +0 -50
  520. package/src/internal/sanitize-mcp-tool-name.ts +0 -31
  521. package/src/internal/schedule-runner.ts +0 -154
  522. package/src/internal/scm/pr-url.ts +0 -245
  523. package/src/internal/sdk-runner.ts +0 -959
  524. package/src/internal/serve-restart.ts +0 -113
  525. package/src/internal/server.ts +0 -3147
  526. package/src/internal/session-cost.ts +0 -208
  527. package/src/internal/session-engine.ts +0 -5622
  528. package/src/internal/session-links.ts +0 -84
  529. package/src/internal/session-run-log.ts +0 -535
  530. package/src/internal/session-store.ts +0 -307
  531. package/src/internal/session-urls.ts +0 -32
  532. package/src/internal/sessions-client.ts +0 -239
  533. package/src/internal/skill-catalog.ts +0 -66
  534. package/src/internal/skills-sync.ts +0 -55
  535. package/src/internal/slack-provision-client.ts +0 -544
  536. package/src/internal/slack-thread-key.ts +0 -11
  537. package/src/internal/sleep.ts +0 -3
  538. package/src/internal/start-log-store.ts +0 -164
  539. package/src/internal/steering.ts +0 -17
  540. package/src/internal/storage-coordinator.ts +0 -800
  541. package/src/internal/storage-roles.ts +0 -86
  542. package/src/internal/storage.ts +0 -1
  543. package/src/internal/store-api-protocol.ts +0 -205
  544. package/src/internal/store-mirror.ts +0 -73
  545. package/src/internal/stream-progress.ts +0 -294
  546. package/src/internal/terminal-style.ts +0 -133
  547. package/src/internal/testing/factory-resource-fixtures.ts +0 -84
  548. package/src/internal/testing/scm-continuation-fixtures.ts +0 -285
  549. package/src/internal/tool-catalog.ts +0 -104
  550. package/src/internal/tool-policy.ts +0 -222
  551. package/src/internal/tool-result.ts +0 -50
  552. package/src/internal/trajectory.ts +0 -418
  553. package/src/internal/turn-cost.ts +0 -136
  554. package/src/internal/turn-governor.ts +0 -145
  555. package/src/internal/turn-lease-store.ts +0 -144
  556. package/src/internal/turn-outbox.ts +0 -77
  557. package/src/internal/update-check.ts +0 -517
  558. package/src/internal/v2-hosting.ts +0 -52
  559. package/src/internal/workspace-sync.ts +0 -114
  560. package/src/internal/workspace.ts +0 -505
  561. package/src/kv/memory-kv.ts +0 -94
  562. package/src/kv.ts +0 -18
  563. package/src/memory.ts +0 -487
  564. package/src/otel-public.ts +0 -24
  565. package/src/otel.ts +0 -320
  566. package/src/prompt.ts +0 -80
  567. package/src/reminders.ts +0 -65
  568. package/src/schedules.ts +0 -31
  569. package/src/skills.ts +0 -27
  570. package/src/storage-backends/cursor-hosted-v2.ts +0 -204
  571. package/src/storage-backends/cursor-hosted.ts +0 -388
  572. package/src/storage-backends/file-kv.ts +0 -276
  573. package/src/storage-protocol.ts +0 -261
  574. package/src/storage.ts +0 -408
  575. package/src/tools.ts +0 -166
  576. package/src/types.ts +0 -3776
  577. /package/dist/docs/assets/{reference_agent-config.md.DzGI777n.lean.js → reference_agent-config.md.Cj5uBKp4.lean.js} +0 -0
@@ -1,836 +0,0 @@
1
- /**
2
- * Durable artifact rows and payloads behind `ctx.artifacts`
3
- * ({@link ArtifactsApi}).
4
- *
5
- * On Cursor-managed hosting rows and file payloads live on the deployment's
6
- * Agent Store (the same store behind `ctx.host.files`, so they survive
7
- * deploys and are visible on cloud VMs under the store mount); otherwise
8
- * they land under `--state-root/artifacts` on local disk.
9
- */
10
-
11
- import { createHash, randomUUID } from "node:crypto";
12
- import { mkdir, readdir, readFile, rename, rm, writeFile } from "node:fs/promises";
13
- import { join } from "node:path";
14
- import { resolveArtifactsMax } from "../artifacts.js";
15
- import { agentStoreKeys, type FileSink } from "../files.js";
16
- import {
17
- cursorHostedFiles,
18
- isCursorHostedFilesAvailable,
19
- } from "../files-backends/cursor-hosted.js";
20
- import type {
21
- ArtifactListFilter,
22
- ArtifactPage,
23
- ArtifactPageOptions,
24
- ArtifactRecord,
25
- ArtifactsConfig,
26
- ArtifactTagInput,
27
- JsonValue,
28
- } from "../types.js";
29
- import { mapBounded } from "./bounded.js";
30
-
31
- /** Default {@link ArtifactPageOptions.limit}; also `GET /v1/artifacts`. */
32
- export const ARTIFACTS_PAGE_DEFAULT_LIMIT = 200;
33
- /** Ceiling for {@link ArtifactPageOptions.limit}; larger asks clamp. */
34
- export const ARTIFACTS_PAGE_MAX_LIMIT = 1_000;
35
- /**
36
- * Rows examined per `page()` call, floor. Filters live in row bodies, so a
37
- * sparse filter must hydrate rows just to reject them; this stops one call
38
- * from scanning an arbitrarily large store, returning a short (possibly
39
- * empty) page with a `nextCursor` instead. `Math.max(limit, …)` keeps a
40
- * full unfiltered page satisfiable in one call.
41
- */
42
- const ARTIFACTS_PAGE_SCAN_MIN = 250;
43
-
44
- /**
45
- * Row-body hydration fan-out cap. `list()` fetches one object per row; on
46
- * the Agent Store each fetch is a control-plane request, and an unbounded
47
- * `Promise.all` over ~1k rows is a fleet-visible read burst (the 2026-09-18
48
- * Agent Store read storm was this exact fan-out, run once per insert by the
49
- * pre-metadata eviction path).
50
- */
51
- const ROW_HYDRATION_CONCURRENCY = 8;
52
-
53
- /**
54
- * Rows hydrated per round trip when the row store batches
55
- * ({@link ArtifactRowStore.getMany}). Matches the hosted sink's presign
56
- * batch, so one page-scan slice is one control-plane request instead of one
57
- * per row.
58
- */
59
- const ARTIFACTS_SCAN_BATCH_ROWS = 100;
60
-
61
- /**
62
- * Most rows one eviction pass may delete. Bounds the tag-latency cost of
63
- * draining a store that sits far past the retention cap (see
64
- * {@link ArtifactsStore.evictPastCap}): at ~0.7s per Agent Store delete and
65
- * {@link ROW_HYDRATION_CONCURRENCY}-way batching, a full pass stays under
66
- * ~10s while a backlog drains across the inserts that keep arriving.
67
- */
68
- const ARTIFACTS_EVICT_MAX_PER_PASS = 64;
69
-
70
- /** One row's identity + modification metadata, without its body. */
71
- interface ArtifactRowMeta {
72
- id: string;
73
- /** Last-modified epoch ms, when the backing store tracks one. */
74
- mtimeMs?: number;
75
- }
76
-
77
- interface ArtifactRowStore {
78
- get(id: string): Promise<ArtifactRecord | undefined>;
79
- /**
80
- * Batched {@link get}, index-aligned with `ids`; a miss is `undefined`.
81
- * Optional — the paged scan falls back to bounded per-id gets. The sink
82
- * row store implements it over `FileSink.getMany` so a page walk spends
83
- * one control-plane call per 100 rows instead of one per row.
84
- */
85
- getMany?(ids: readonly string[]): Promise<Array<ArtifactRecord | undefined>>;
86
- put(record: ArtifactRecord): Promise<void>;
87
- delete(id: string): Promise<void>;
88
- list(): Promise<ArtifactRecord[]>;
89
- /**
90
- * Row ids + modification metadata without hydrating bodies — the
91
- * per-insert cap check and (when mtimes are tracked) the eviction order.
92
- */
93
- listMeta(): Promise<ArtifactRowMeta[]>;
94
- }
95
-
96
- /** File/blob payload bytes, keyed by artifact id (metadata lives on the row). */
97
- interface ArtifactContentStore {
98
- get(id: string): Promise<Uint8Array | undefined>;
99
- put(id: string, body: Uint8Array): Promise<void>;
100
- delete(id: string): Promise<void>;
101
- }
102
-
103
- export interface CreateArtifactsStoreOptions {
104
- stateRoot: string;
105
- agentName: string;
106
- /** `agent/artifacts.ts` config, when authored. */
107
- config?: ArtifactsConfig;
108
- /** Explicit sink override (tests). Omitted → hosted store or local disk. */
109
- sink?: FileSink;
110
- /**
111
- * Whether `tag` enforces {@link ArtifactsConfig.max} by listing and
112
- * deleting. Default true. Hosted architecture v2 passes false: the
113
- * installation store is allowed to grow, and a tag must not list the prefix.
114
- */
115
- enforceCap?: () => boolean;
116
- }
117
-
118
- /** Kind used by freeform tags when no kinds are declared. */
119
- export const ARTIFACT_DEFAULT_KIND = "artifact";
120
-
121
- /**
122
- * Upsert + list semantics over one {@link ArtifactRowStore}: kind/schema
123
- * validation, deterministic ids for keyed tags, and `max` eviction.
124
- * Architecture v1 and self-hosted v2 evict. Hosted architecture v2 sets
125
- * {@link CreateArtifactsStoreOptions.enforceCap} false and does not list
126
- * or delete on tag. The engine wraps this into the per-context
127
- * {@link ArtifactsApi} facades and
128
- * owns the `artifact.tagged` event append.
129
- */
130
- export class ArtifactsStore {
131
- private readonly rows: ArtifactRowStore;
132
- private readonly content: ArtifactContentStore;
133
- private readonly config: ArtifactsConfig | undefined;
134
- private readonly max: number;
135
- private readonly enforceCap: () => boolean;
136
- /** Serializes tags so read-modify-write upserts and eviction don't race. */
137
- private tagChain: Promise<unknown> = Promise.resolve();
138
-
139
- constructor(options: CreateArtifactsStoreOptions) {
140
- const sink = options.sink ?? (isCursorHostedFilesAvailable() ? cursorHostedFiles() : undefined);
141
- if (sink === undefined) {
142
- this.rows = createFilesystemRowStore(options.stateRoot);
143
- this.content = createFilesystemContentStore(options.stateRoot);
144
- } else {
145
- this.rows = createSinkRowStore(sink, options.agentName);
146
- this.content = createSinkContentStore(sink, options.agentName);
147
- }
148
- this.config = options.config;
149
- this.max = resolveArtifactsMax(options.config);
150
- this.enforceCap = options.enforceCap ?? (() => true);
151
- }
152
-
153
- tag(input: ArtifactTagInput): Promise<ArtifactRecord> {
154
- const result = this.tagChain.then(() => this.tagSerialized(input));
155
- this.tagChain = result.catch(() => {});
156
- return result;
157
- }
158
-
159
- private async tagSerialized(input: ArtifactTagInput): Promise<ArtifactRecord> {
160
- const { kind, data } = this.resolveKindAndData(input);
161
- const id = input.key === undefined ? `art_${randomUUID()}` : artifactIdForKey(input.key);
162
- // Fresh random ids can't collide; only keyed tags upsert.
163
- const existing = input.key === undefined ? undefined : await this.rows.get(id);
164
- const now = new Date().toISOString();
165
- const record: ArtifactRecord = {
166
- id,
167
- kind,
168
- key: input.key,
169
- title: input.title,
170
- data,
171
- sessionId: input.sessionId,
172
- turnId: input.turnId,
173
- source: input.source ?? "host",
174
- createdAt: existing?.createdAt ?? now,
175
- updatedAt: now,
176
- };
177
- if (input.contents !== undefined) {
178
- const body =
179
- typeof input.contents === "string" ? Buffer.from(input.contents, "utf8") : input.contents;
180
- await this.content.put(id, body);
181
- record.content = {
182
- size: body.byteLength,
183
- contentType: input.contentType,
184
- };
185
- } else if (existing?.content !== undefined) {
186
- if (existing.sessionId === record.sessionId) {
187
- record.content = existing.content;
188
- } else {
189
- // Keys are deployment-global: rebinding a keyed row to another
190
- // session must not carry the prior session's payload with it.
191
- await this.content.delete(id);
192
- }
193
- }
194
- await this.rows.put(record);
195
- if (existing === undefined && this.enforceCap()) {
196
- await this.evictPastCap();
197
- }
198
- return record;
199
- }
200
-
201
- get(id: string): Promise<ArtifactRecord | undefined> {
202
- return this.rows.get(id);
203
- }
204
-
205
- /** Payload bytes for one artifact; undefined when it carries none. */
206
- getContent(id: string): Promise<Uint8Array | undefined> {
207
- return this.content.get(id);
208
- }
209
-
210
- /**
211
- * Newest page only (default limit, no cursor) — the bounded
212
- * {@link ArtifactsApi.list} contract. Walk the full set via
213
- * {@link ArtifactsStore.page}.
214
- */
215
- async list(filter?: ArtifactListFilter): Promise<ArtifactRecord[]> {
216
- const page = await this.page(filter);
217
- return page.records;
218
- }
219
-
220
- /**
221
- * Bounded cursor pagination, newest-updated first. On a store whose
222
- * listing tracks mtimes (the hosted Agent Store), a page hydrates only
223
- * the rows it examines — roughly `limit` bodies, never the whole store.
224
- * Row-body order is the listing's mtime order (upserts rewrite the row,
225
- * so mtime tracks `updatedAt`; same argument as eviction). The
226
- * filesystem store hydrates everything (cheap local reads) and orders
227
- * exactly by `updatedAt`.
228
- *
229
- * `matches` is a host-side *visibility* predicate composed with the
230
- * public filter — the engine passes session-ownership through it. Its
231
- * presence forces the exact hydrated lane: the metadata lane's cursor
232
- * and its short-page continuation are derived from every row in the
233
- * store, and handing them to a caller who may not see every row is a
234
- * side channel (existence, count within the scan budget, boundary
235
- * mtimes and cohort depths of hidden rows) that the pre-pagination
236
- * filtered list never had. The exact lane's cursor names only a record
237
- * the caller received, and continues only while more *visible* records
238
- * remain — at the pre-pagination cost (hydrate all rows, bounded).
239
- */
240
- async page(
241
- options?: ArtifactPageOptions & {
242
- matches?: (record: ArtifactRecord) => boolean;
243
- },
244
- ): Promise<ArtifactPage> {
245
- const limit = Math.min(
246
- Math.max(options?.limit ?? ARTIFACTS_PAGE_DEFAULT_LIMIT, 1),
247
- ARTIFACTS_PAGE_MAX_LIMIT,
248
- );
249
- const cursor =
250
- options?.cursor === undefined ? undefined : decodeArtifactPageCursor(options.cursor);
251
- const matches = (record: ArtifactRecord): boolean =>
252
- (options?.kind === undefined || record.kind === options.kind) &&
253
- (options?.sessionId === undefined || record.sessionId === options.sessionId) &&
254
- (options?.matches === undefined || options.matches(record));
255
-
256
- if (options?.matches === undefined) {
257
- const metas = await this.rows.listMeta();
258
- if (metas.some(meta => meta.mtimeMs !== undefined)) {
259
- return this.pageFromMetadata(
260
- metas,
261
- limit,
262
- cursor,
263
- matches,
264
- options?.kind !== undefined || options?.sessionId !== undefined,
265
- );
266
- }
267
- }
268
- return this.pageFromRecords(limit, cursor, matches);
269
- }
270
-
271
- /**
272
- * Metadata-ordered page: sort metas newest first, resume after the
273
- * cursor, hydrate in bounded batches until the page fills, the scan
274
- * budget runs out, or the metas do. The cursor marks the last *examined*
275
- * meta, so a budget-limited call still makes progress.
276
- */
277
- private async pageFromMetadata(
278
- metas: ArtifactRowMeta[],
279
- limit: number,
280
- cursor: ArtifactPageCursor | undefined,
281
- matches: (record: ArtifactRecord) => boolean,
282
- filtered: boolean,
283
- ): Promise<ArtifactPage> {
284
- const newestFirst = metas.sort((a, b) => byOldestModified(b, a));
285
- let start = 0;
286
- if (cursor !== undefined && cursor.kind === "mtime") {
287
- // Resume after (boundary stamp, rows of that cohort already
288
- // examined). Same-stamp rows sit contiguously in the sort, so the
289
- // pair names an exact position without identifying any row.
290
- start = newestFirst.findIndex(meta => (meta.mtimeMs ?? 0) <= cursor.m);
291
- if (start === -1) {
292
- return { records: [] };
293
- }
294
- let skipped = 0;
295
- while (
296
- start < newestFirst.length &&
297
- (newestFirst[start]?.mtimeMs ?? 0) === cursor.m &&
298
- skipped < cursor.s
299
- ) {
300
- start += 1;
301
- skipped += 1;
302
- }
303
- if (start >= newestFirst.length) {
304
- return { records: [] };
305
- }
306
- }
307
- // A cursor of the other kind means the store's listing gained mtimes
308
- // between pages (a mode flip, not caller error): restart from the top
309
- // rather than fail the walk.
310
- const budget = Math.max(limit, ARTIFACTS_PAGE_SCAN_MIN);
311
- const records: ArtifactRecord[] = [];
312
- let examined = 0;
313
- let lastExamined = start - 1;
314
- // A batched row store hydrates a bigger slice per round trip (one
315
- // control-plane call on the hosted sink); without one, keep the slice at
316
- // the per-row fan-out bound so concurrency stays capped. An unfiltered
317
- // page needs exactly the rows it returns — every hydrated row matches —
318
- // so cap its slice at the remaining page instead of over-hydrating a
319
- // full batch for a small `limit`.
320
- const scanBatchSize =
321
- this.rows.getMany !== undefined ? ARTIFACTS_SCAN_BATCH_ROWS : ROW_HYDRATION_CONCURRENCY;
322
- scan: while (
323
- lastExamined + 1 < newestFirst.length &&
324
- records.length < limit &&
325
- examined < budget
326
- ) {
327
- const from = lastExamined + 1;
328
- const sliceCap = filtered ? scanBatchSize : Math.min(scanBatchSize, limit - records.length);
329
- const batch = newestFirst.slice(from, from + Math.min(sliceCap, budget - examined));
330
- const bodies =
331
- this.rows.getMany !== undefined
332
- ? await this.rows.getMany(batch.map(meta => meta.id))
333
- : await mapBounded(batch, ROW_HYDRATION_CONCURRENCY, meta => this.rows.get(meta.id));
334
- for (let i = 0; i < batch.length; i += 1) {
335
- lastExamined = from + i;
336
- examined += 1;
337
- const record = bodies[i];
338
- if (record !== undefined && matches(record)) {
339
- records.push(record);
340
- if (records.length === limit) {
341
- break scan;
342
- }
343
- }
344
- }
345
- }
346
- if (lastExamined >= newestFirst.length - 1) {
347
- return { records };
348
- }
349
- const boundary = (newestFirst[lastExamined] as ArtifactRowMeta).mtimeMs ?? 0;
350
- // How deep into the boundary's same-stamp cohort the scan got —
351
- // cohorts are contiguous, so count back from the last examined row.
352
- let cohortExamined = 0;
353
- for (let i = lastExamined; i >= 0 && (newestFirst[i]?.mtimeMs ?? 0) === boundary; i -= 1) {
354
- cohortExamined += 1;
355
- }
356
- return {
357
- records,
358
- nextCursor: encodeArtifactPageCursor({
359
- v: 1,
360
- kind: "mtime",
361
- m: boundary,
362
- s: cohortExamined,
363
- }),
364
- };
365
- }
366
-
367
- /**
368
- * Hydrate-everything page: exact `updatedAt` order, cursor = the last
369
- * *returned* record's position. Serves stores without listing mtimes
370
- * (the local filesystem store) and every visibility-filtered walk — see
371
- * {@link ArtifactsStore.page} for why filtered callers must not receive
372
- * metadata-lane cursors.
373
- */
374
- private async pageFromRecords(
375
- limit: number,
376
- cursor: ArtifactPageCursor | undefined,
377
- matches: (record: ArtifactRecord) => boolean,
378
- ): Promise<ArtifactPage> {
379
- const records = (await this.rows.list()).filter(matches).sort(byNewestUpdated);
380
- let start = 0;
381
- if (cursor !== undefined && cursor.kind === "updated") {
382
- const position = {
383
- updatedAt: cursor.u,
384
- createdAt: cursor.c,
385
- id: cursor.id,
386
- } as ArtifactRecord;
387
- start = records.findIndex(record => byNewestUpdated(record, position) > 0);
388
- if (start === -1) {
389
- return { records: [] };
390
- }
391
- }
392
- const page = records.slice(start, start + limit);
393
- const last = page[page.length - 1];
394
- if (last === undefined || start + page.length >= records.length) {
395
- return { records: page };
396
- }
397
- return {
398
- records: page,
399
- nextCursor: encodeArtifactPageCursor({
400
- v: 1,
401
- kind: "updated",
402
- u: last.updatedAt,
403
- c: last.createdAt,
404
- id: last.id,
405
- }),
406
- };
407
- }
408
-
409
- /**
410
- * Resolve the effective kind (freeform when no kinds are declared) and
411
- * the payload to persist. Like tool input schemas
412
- * (`validateToolInput`), zod schemas validate *and* transform: the
413
- * parsed output — defaults and coercions applied — is what gets stored.
414
- */
415
- private resolveKindAndData(input: ArtifactTagInput): {
416
- kind: string;
417
- data: JsonValue;
418
- } {
419
- const kind = input.kind ?? ARTIFACT_DEFAULT_KIND;
420
- if (kind.trim() === "") {
421
- throw new Error("artifacts.tag: kind must be a non-empty string");
422
- }
423
- const kinds = this.config?.kinds;
424
- if (kinds === undefined || Object.keys(kinds).length === 0) {
425
- return { kind, data: input.data };
426
- }
427
- const kindConfig = kinds[kind];
428
- if (kindConfig === undefined) {
429
- throw new Error(
430
- `artifacts.tag: unknown kind ${JSON.stringify(kind)} (declared: ${Object.keys(kinds).join(", ")})`,
431
- );
432
- }
433
- if (kindConfig.schema !== undefined) {
434
- const parsed = kindConfig.schema.safeParse(input.data);
435
- if (!parsed.success) {
436
- throw new Error(
437
- `artifacts.tag: data does not match the ${JSON.stringify(kind)} schema: ${parsed.error.message}`,
438
- );
439
- }
440
- return { kind, data: parsed.data as JsonValue };
441
- }
442
- return { kind, data: input.data };
443
- }
444
-
445
- /**
446
- * Trim toward the retention cap from listing metadata alone. Past the
447
- * cap this runs on every new-row insert, so it must not hydrate row
448
- * bodies: on the Agent Store that is one read per row (~`max` reads per
449
- * insert, forever, since eviction trims right back to the cap) — the
450
- * 2026-09-18 read storm on the security-reviewer deployment. The store
451
- * listing carries last-modified metadata, and a row is rewritten on
452
- * every upsert, so listing mtime orders rows the same way their
453
- * `updatedAt` does.
454
- *
455
- * Deletes are capped per pass: eviction runs inside `tag()`'s per-pod
456
- * chain, so its wall time is tag latency for every queued caller. A
457
- * store far past the cap (evictions failed during the 2026-09-19 read
458
- * throttling and the backlog grew unchecked) must drain amortized
459
- * across inserts, not wedge one insert deleting the whole backlog — on
460
- * 2026-09-20 an uncapped pass held security-reviewer tags for hours and
461
- * tripled review stage durations. Steady state (excess of 1) is
462
- * unaffected.
463
- */
464
- private async evictPastCap(): Promise<void> {
465
- const metas = await this.rows.listMeta();
466
- const excess = Math.min(metas.length - this.max, ARTIFACTS_EVICT_MAX_PER_PASS);
467
- if (excess <= 0) {
468
- return;
469
- }
470
- await mapBounded(
471
- await this.oldestRowIds(metas, excess),
472
- ROW_HYDRATION_CONCURRENCY,
473
- async id => {
474
- await this.rows.delete(id);
475
- // Without the row body there is no `content` flag to consult;
476
- // delete the payload unconditionally — absent ones are a no-op.
477
- await this.content.delete(id);
478
- },
479
- );
480
- }
481
-
482
- /** The `excess` oldest row ids, cheapest available ordering first. */
483
- private async oldestRowIds(metas: ArtifactRowMeta[], excess: number): Promise<string[]> {
484
- if (metas.some(meta => meta.mtimeMs !== undefined)) {
485
- // A store that tracks mtimes must never regress to per-insert
486
- // hydration. The rare entry missing one (anomalous on such a store)
487
- // sorts oldest via the comparator's `?? 0` and gets evicted first —
488
- // evicting an anomaly beats re-reading every row on every insert.
489
- return metas
490
- .sort(byOldestModified)
491
- .slice(0, excess)
492
- .map(meta => meta.id);
493
- }
494
- // A store that tracks no modification times at all (the local
495
- // filesystem store, deliberately) leaves only the rows' own
496
- // `updatedAt`: hydrate — bounded — and order exactly. Corrupt rows
497
- // drop out of `list()`, so recompute the excess against the rows that
498
- // actually parsed.
499
- const records = await this.rows.list();
500
- return records
501
- .sort((a, b) => byNewestUpdated(b, a))
502
- .slice(0, Math.min(excess, Math.max(0, records.length - this.max)))
503
- .map(record => record.id);
504
- }
505
- }
506
-
507
- /** A syntactically invalid {@link ArtifactPageOptions.cursor}. */
508
- export class InvalidArtifactCursorError extends Error {
509
- constructor() {
510
- super("artifacts.page: invalid cursor");
511
- this.name = "InvalidArtifactCursorError";
512
- }
513
- }
514
-
515
- /**
516
- * Resume position, opaque to callers (base64url JSON). Which kind a store
517
- * mints follows which ordering source it paged from.
518
- *
519
- * `mtime` is purely positional — the boundary modification stamp plus how
520
- * many rows of that same-stamp cohort were already examined. It must never
521
- * carry a row id: the scan examines rows the caller's visibility predicate
522
- * then rejects, so a cursor naming the last *examined* row would hand
523
- * strict-auth callers other principals' artifact ids inside an unsigned
524
- * token. `updated` names only the last *returned* record, which the caller
525
- * already received.
526
- */
527
- type ArtifactPageCursor =
528
- | { v: 1; kind: "mtime"; m: number; s: number }
529
- | { v: 1; kind: "updated"; u: string; c: string; id: string };
530
-
531
- function encodeArtifactPageCursor(cursor: ArtifactPageCursor): string {
532
- return Buffer.from(JSON.stringify(cursor), "utf8").toString("base64url");
533
- }
534
-
535
- /** Throws {@link InvalidArtifactCursorError} on anything undecodable. */
536
- function decodeArtifactPageCursor(raw: string): ArtifactPageCursor {
537
- let value: unknown;
538
- try {
539
- value = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
540
- } catch {
541
- throw new InvalidArtifactCursorError();
542
- }
543
- if (typeof value !== "object" || value === null) {
544
- throw new InvalidArtifactCursorError();
545
- }
546
- const cursor = value as Record<string, unknown>;
547
- if (cursor.v !== 1) {
548
- throw new InvalidArtifactCursorError();
549
- }
550
- if (
551
- cursor.kind === "mtime" &&
552
- typeof cursor.m === "number" &&
553
- typeof cursor.s === "number" &&
554
- Number.isInteger(cursor.s) &&
555
- cursor.s >= 0
556
- ) {
557
- return { v: 1, kind: "mtime", m: cursor.m, s: cursor.s };
558
- }
559
- if (
560
- cursor.kind === "updated" &&
561
- typeof cursor.u === "string" &&
562
- typeof cursor.c === "string" &&
563
- typeof cursor.id === "string"
564
- ) {
565
- return { v: 1, kind: "updated", u: cursor.u, c: cursor.c, id: cursor.id };
566
- }
567
- throw new InvalidArtifactCursorError();
568
- }
569
-
570
- /** Deterministic id for a keyed tag (same key ⇒ same id ⇒ upsert). */
571
- export function artifactIdForKey(key: string): string {
572
- if (key.trim() === "") {
573
- throw new Error("artifacts.tag: key must be a non-empty string");
574
- }
575
- return `art_${createHash("sha256").update(key, "utf8").digest("hex").slice(0, 32)}`;
576
- }
577
-
578
- /**
579
- * Oldest-modified first. Store mtimes can be coarse (S3 rounds to the
580
- * second), so equal stamps tie-break by id — deterministic, and within a
581
- * same-stamp cohort any victim is equally past the retention cap.
582
- */
583
- function byOldestModified(a: ArtifactRowMeta, b: ArtifactRowMeta): number {
584
- if (a.mtimeMs !== b.mtimeMs) {
585
- return (a.mtimeMs ?? 0) - (b.mtimeMs ?? 0);
586
- }
587
- return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
588
- }
589
-
590
- function byNewestUpdated(a: ArtifactRecord, b: ArtifactRecord): number {
591
- if (a.updatedAt !== b.updatedAt) {
592
- return a.updatedAt < b.updatedAt ? 1 : -1;
593
- }
594
- // Tie-break so eviction and listing stay deterministic.
595
- if (a.createdAt !== b.createdAt) {
596
- return a.createdAt < b.createdAt ? 1 : -1;
597
- }
598
- return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
599
- }
600
-
601
- function isArtifactRecord(value: JsonValue | undefined): value is ArtifactRecord & JsonValue {
602
- if (
603
- typeof value !== "object" ||
604
- value === null ||
605
- Array.isArray(value) ||
606
- typeof value.id !== "string" ||
607
- typeof value.kind !== "string" ||
608
- (value.source !== "host" && value.source !== "model") ||
609
- typeof value.createdAt !== "string" ||
610
- typeof value.updatedAt !== "string" ||
611
- !("data" in value)
612
- ) {
613
- return false;
614
- }
615
- for (const field of ["key", "title", "sessionId", "turnId"] as const) {
616
- if (value[field] !== undefined && typeof value[field] !== "string") {
617
- return false;
618
- }
619
- }
620
- return true;
621
- }
622
-
623
- function parseRecordBytes(bytes: Uint8Array | undefined): ArtifactRecord | undefined {
624
- if (bytes === undefined) {
625
- return undefined;
626
- }
627
- let value: JsonValue;
628
- try {
629
- value = JSON.parse(Buffer.from(bytes).toString("utf8")) as JsonValue;
630
- } catch {
631
- // A corrupt row must not poison list().
632
- return undefined;
633
- }
634
- return isArtifactRecord(value) ? value : undefined;
635
- }
636
-
637
- function sinkBody(found: Awaited<ReturnType<FileSink["get"]>>): Uint8Array | undefined {
638
- if (found === undefined) {
639
- return undefined;
640
- }
641
- return found instanceof Uint8Array ? found : found.body;
642
- }
643
-
644
- /** Rows as one JSON file each on the deployment's Agent Store. */
645
- function createSinkRowStore(sink: FileSink, agentName: string): ArtifactRowStore {
646
- const key = (id: string): string => agentStoreKeys.artifactRow(agentName, id);
647
- return {
648
- async get(id): Promise<ArtifactRecord | undefined> {
649
- return parseRecordBytes(sinkBody(await sink.get(key(id))));
650
- },
651
- async put(record): Promise<void> {
652
- await sink.put(key(record.id), Buffer.from(JSON.stringify(record), "utf8"));
653
- },
654
- async delete(id): Promise<void> {
655
- await sink.delete(key(id));
656
- },
657
- async getMany(ids): Promise<Array<ArtifactRecord | undefined>> {
658
- const keys = ids.map(id => key(id));
659
- const bodies =
660
- sink.getMany !== undefined
661
- ? await sink.getMany(keys)
662
- : await mapBounded(keys, ROW_HYDRATION_CONCURRENCY, rowKey => sink.get(rowKey));
663
- return bodies.map(body => parseRecordBytes(sinkBody(body)));
664
- },
665
- async list(): Promise<ArtifactRecord[]> {
666
- const entries = await sink.list(agentStoreKeys.artifactRowPrefix(agentName));
667
- const bodies =
668
- sink.getMany !== undefined
669
- ? await sink.getMany(entries.map(entry => entry.key))
670
- : await mapBounded(entries, ROW_HYDRATION_CONCURRENCY, entry => sink.get(entry.key));
671
- const records: ArtifactRecord[] = [];
672
- for (const body of bodies) {
673
- const record = parseRecordBytes(sinkBody(body));
674
- if (record !== undefined) {
675
- records.push(record);
676
- }
677
- }
678
- return records;
679
- },
680
- async listMeta(): Promise<ArtifactRowMeta[]> {
681
- const prefix = agentStoreKeys.artifactRowPrefix(agentName);
682
- const metas: ArtifactRowMeta[] = [];
683
- for (const entry of await sink.list(prefix)) {
684
- const id = rowIdFromName(entry.key.slice(prefix.length));
685
- if (id !== undefined) {
686
- metas.push({ id, mtimeMs: entry.mtimeMs });
687
- }
688
- }
689
- return metas;
690
- },
691
- };
692
- }
693
-
694
- /**
695
- * Invert the row naming scheme (`encodeURIComponent(id) + ".json"`).
696
- * Foreign keys under the prefix — no `.json` suffix, malformed escapes,
697
- * non-canonical encodings — read as absent rather than throwing. The
698
- * round-trip check matters for eviction: a name that decodes but does not
699
- * re-encode to itself (`a+b.json`, `foo bar.json`) would count toward the
700
- * cap yet be undeletable through `key(id)`, leaving a phantom victim that
701
- * every subsequent insert re-selects and fails to remove.
702
- */
703
- function rowIdFromName(name: string): string | undefined {
704
- if (!name.endsWith(".json") || name.includes("/")) {
705
- return undefined;
706
- }
707
- const encoded = name.slice(0, -".json".length);
708
- try {
709
- const id = decodeURIComponent(encoded);
710
- return encodeURIComponent(id) === encoded ? id : undefined;
711
- } catch {
712
- return undefined;
713
- }
714
- }
715
-
716
- function createSinkContentStore(sink: FileSink, agentName: string): ArtifactContentStore {
717
- const key = (id: string): string => agentStoreKeys.artifactContent(agentName, id);
718
- return {
719
- async get(id): Promise<Uint8Array | undefined> {
720
- return sinkBody(await sink.get(key(id)));
721
- },
722
- async put(id, body): Promise<void> {
723
- await sink.put(key(id), body);
724
- },
725
- async delete(id): Promise<void> {
726
- await sink.delete(key(id));
727
- },
728
- };
729
- }
730
-
731
- function createFilesystemRowStore(stateRoot: string): ArtifactRowStore {
732
- const dir = join(stateRoot, "artifacts");
733
- const filePath = (id: string): string => join(dir, `${encodeURIComponent(id)}.json`);
734
-
735
- // Missing and corrupt rows both read as absent — a truncated/garbled
736
- // file must not poison list() (and with it every insert's eviction).
737
- const readRecord = async (path: string): Promise<ArtifactRecord | undefined> => {
738
- try {
739
- const value = JSON.parse(await readFile(path, "utf8")) as JsonValue;
740
- return isArtifactRecord(value) ? value : undefined;
741
- } catch (error) {
742
- if ((error as NodeJS.ErrnoException).code === "ENOENT" || error instanceof SyntaxError) {
743
- return undefined;
744
- }
745
- throw error;
746
- }
747
- };
748
-
749
- return {
750
- get(id): Promise<ArtifactRecord | undefined> {
751
- return readRecord(filePath(id));
752
- },
753
- async put(record): Promise<void> {
754
- await mkdir(dir, { recursive: true });
755
- const tmp = join(dir, `.tmp-${randomUUID()}`);
756
- await writeFile(tmp, JSON.stringify(record), "utf8");
757
- await rename(tmp, filePath(record.id));
758
- },
759
- async delete(id): Promise<void> {
760
- await rm(filePath(id), { force: true });
761
- },
762
- async list(): Promise<ArtifactRecord[]> {
763
- let names: string[];
764
- try {
765
- names = await readdir(dir);
766
- } catch (error) {
767
- if ((error as NodeJS.ErrnoException).code === "ENOENT") {
768
- return [];
769
- }
770
- throw error;
771
- }
772
- const records: ArtifactRecord[] = [];
773
- for (const name of names.sort()) {
774
- if (name.startsWith(".") || !name.endsWith(".json")) {
775
- continue;
776
- }
777
- const record = await readRecord(join(dir, name));
778
- if (record !== undefined) {
779
- records.push(record);
780
- }
781
- }
782
- return records;
783
- },
784
- async listMeta(): Promise<ArtifactRowMeta[]> {
785
- // No mtimes on purpose: local rows are cheap to hydrate, and the
786
- // rows' own `updatedAt` orders eviction exactly, immune to coarse
787
- // filesystem timestamp granularity.
788
- let names: string[];
789
- try {
790
- names = await readdir(dir);
791
- } catch (error) {
792
- if ((error as NodeJS.ErrnoException).code === "ENOENT") {
793
- return [];
794
- }
795
- throw error;
796
- }
797
- const metas: ArtifactRowMeta[] = [];
798
- for (const name of names) {
799
- if (name.startsWith(".")) {
800
- continue;
801
- }
802
- const id = rowIdFromName(name);
803
- if (id !== undefined) {
804
- metas.push({ id });
805
- }
806
- }
807
- return metas;
808
- },
809
- };
810
- }
811
-
812
- function createFilesystemContentStore(stateRoot: string): ArtifactContentStore {
813
- const dir = join(stateRoot, "artifacts", "content");
814
- const filePath = (id: string): string => join(dir, encodeURIComponent(id));
815
- return {
816
- async get(id): Promise<Uint8Array | undefined> {
817
- try {
818
- return new Uint8Array(await readFile(filePath(id)));
819
- } catch (error) {
820
- if ((error as NodeJS.ErrnoException).code === "ENOENT") {
821
- return undefined;
822
- }
823
- throw error;
824
- }
825
- },
826
- async put(id, body): Promise<void> {
827
- await mkdir(dir, { recursive: true });
828
- const tmp = join(dir, `.tmp-${randomUUID()}`);
829
- await writeFile(tmp, body);
830
- await rename(tmp, filePath(id));
831
- },
832
- async delete(id): Promise<void> {
833
- await rm(filePath(id), { force: true });
834
- },
835
- };
836
- }