@cursor/bdk 0.2.9 → 0.2.11

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 (569) hide show
  1. package/dist/artifacts.js +3 -5
  2. package/dist/bin/agent-serve.js +803 -812
  3. package/dist/channels/bitbucket/api.js +305 -321
  4. package/dist/channels/bitbucket/binding.js +97 -61
  5. package/dist/channels/bitbucket/bitbucket-channel.d.ts +15 -1
  6. package/dist/channels/bitbucket/bitbucket-channel.d.ts.map +1 -1
  7. package/dist/channels/bitbucket/bitbucket-channel.js +95 -42
  8. package/dist/channels/bitbucket/bitbucket-webhook.d.ts +11 -0
  9. package/dist/channels/bitbucket/bitbucket-webhook.d.ts.map +1 -1
  10. package/dist/channels/bitbucket/bitbucket-webhook.js +214 -204
  11. package/dist/channels/bitbucket/checks.js +9 -21
  12. package/dist/channels/bitbucket/cursor-account.js +1 -1
  13. package/dist/channels/bitbucket/defaults.js +14 -4
  14. package/dist/channels/bitbucket/events.js +1 -2
  15. package/dist/channels/bitbucket/index.d.ts +6 -2
  16. package/dist/channels/bitbucket/index.d.ts.map +1 -1
  17. package/dist/channels/bitbucket/index.js +6 -2
  18. package/dist/channels/bitbucket/replay.js +80 -56
  19. package/dist/channels/bitbucket/state.js +16 -7
  20. package/dist/channels/bitbucket/types.d.ts +11 -2
  21. package/dist/channels/bitbucket/types.d.ts.map +1 -1
  22. package/dist/channels/checks.js +18 -28
  23. package/dist/channels/deployments/deployments-channel.js +26 -34
  24. package/dist/channels/github/api.js +216 -210
  25. package/dist/channels/github/auth.d.ts +5 -1
  26. package/dist/channels/github/auth.d.ts.map +1 -1
  27. package/dist/channels/github/auth.js +157 -174
  28. package/dist/channels/github/binding.js +48 -39
  29. package/dist/channels/github/checks.js +9 -14
  30. package/dist/channels/github/cursor-account.js +6 -11
  31. package/dist/channels/github/defaults.js +105 -130
  32. package/dist/channels/github/forward.js +13 -17
  33. package/dist/channels/github/github-channel.d.ts +43 -2
  34. package/dist/channels/github/github-channel.d.ts.map +1 -1
  35. package/dist/channels/github/github-channel.js +1228 -958
  36. package/dist/channels/github/progress.js +145 -146
  37. package/dist/channels/github/replay.js +30 -39
  38. package/dist/channels/github/state.js +40 -16
  39. package/dist/channels/github/types.d.ts +30 -6
  40. package/dist/channels/github/types.d.ts.map +1 -1
  41. package/dist/channels/gitlab/api.js +100 -114
  42. package/dist/channels/gitlab/binding.js +52 -33
  43. package/dist/channels/gitlab/checks.js +28 -29
  44. package/dist/channels/gitlab/cursor-account.js +1 -1
  45. package/dist/channels/gitlab/defaults.js +9 -3
  46. package/dist/channels/gitlab/gitlab-channel.d.ts +16 -1
  47. package/dist/channels/gitlab/gitlab-channel.d.ts.map +1 -1
  48. package/dist/channels/gitlab/gitlab-channel.js +95 -42
  49. package/dist/channels/gitlab/gitlab-webhook.d.ts +10 -1
  50. package/dist/channels/gitlab/gitlab-webhook.d.ts.map +1 -1
  51. package/dist/channels/gitlab/gitlab-webhook.js +282 -249
  52. package/dist/channels/gitlab/index.d.ts +6 -2
  53. package/dist/channels/gitlab/index.d.ts.map +1 -1
  54. package/dist/channels/gitlab/index.js +6 -2
  55. package/dist/channels/gitlab/replay.js +50 -27
  56. package/dist/channels/gitlab/state.js +14 -6
  57. package/dist/channels/gitlab/types.d.ts +13 -2
  58. package/dist/channels/gitlab/types.d.ts.map +1 -1
  59. package/dist/channels/origin/api.js +100 -116
  60. package/dist/channels/origin/binding.js +15 -16
  61. package/dist/channels/origin/checks.js +30 -28
  62. package/dist/channels/origin/defaults.js +50 -65
  63. package/dist/channels/origin/origin-channel.js +266 -272
  64. package/dist/channels/origin/origin-webhook.js +70 -88
  65. package/dist/channels/origin/reactions.js +9 -21
  66. package/dist/channels/origin/state.js +13 -5
  67. package/dist/channels/slack/agentic-delivery.js +426 -478
  68. package/dist/channels/slack/agentic-posted.js +9 -10
  69. package/dist/channels/slack/agentic-signals.js +2 -3
  70. package/dist/channels/slack/api.js +417 -427
  71. package/dist/channels/slack/approvals.js +1 -1
  72. package/dist/channels/slack/assistant.js +37 -47
  73. package/dist/channels/slack/attachments.js +188 -206
  74. package/dist/channels/slack/auth.js +8 -6
  75. package/dist/channels/slack/bot-mentions.js +31 -45
  76. package/dist/channels/slack/channel-watch.js +42 -48
  77. package/dist/channels/slack/cli-project.js +112 -137
  78. package/dist/channels/slack/code-fences.js +3 -5
  79. package/dist/channels/slack/constants.js +2 -2
  80. package/dist/channels/slack/credentials.js +23 -38
  81. package/dist/channels/slack/defaults.js +292 -331
  82. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  83. package/dist/channels/slack/dispatch.js +533 -460
  84. package/dist/channels/slack/doctor.js +200 -214
  85. package/dist/channels/slack/eval-directive.js +79 -96
  86. package/dist/channels/slack/event-id-dedupe.js +1 -1
  87. package/dist/channels/slack/external-policy.js +26 -39
  88. package/dist/channels/slack/footer.js +28 -41
  89. package/dist/channels/slack/inbound.d.ts +1 -0
  90. package/dist/channels/slack/inbound.d.ts.map +1 -1
  91. package/dist/channels/slack/inbound.js +50 -31
  92. package/dist/channels/slack/init.d.ts +1 -5
  93. package/dist/channels/slack/init.d.ts.map +1 -1
  94. package/dist/channels/slack/init.js +42 -59
  95. package/dist/channels/slack/interactive.d.ts +9 -3
  96. package/dist/channels/slack/interactive.d.ts.map +1 -1
  97. package/dist/channels/slack/interactive.js +160 -162
  98. package/dist/channels/slack/links.js +1 -2
  99. package/dist/channels/slack/live-delivery.js +172 -190
  100. package/dist/channels/slack/manifest.d.ts.map +1 -1
  101. package/dist/channels/slack/manifest.js +44 -23
  102. package/dist/channels/slack/message-body.js +2 -2
  103. package/dist/channels/slack/nudge-carrier.js +30 -42
  104. package/dist/channels/slack/nudge-store.js +164 -191
  105. package/dist/channels/slack/paint-start.js +66 -81
  106. package/dist/channels/slack/placeholder.js +123 -152
  107. package/dist/channels/slack/pr-ref.js +1 -1
  108. package/dist/channels/slack/progress-delivery.js +65 -78
  109. package/dist/channels/slack/reasoning-card.js +36 -49
  110. package/dist/channels/slack/recording-sink.js +12 -24
  111. package/dist/channels/slack/reply-options.js +7 -12
  112. package/dist/channels/slack/self-identity.js +27 -35
  113. package/dist/channels/slack/sender-name.d.ts +12 -3
  114. package/dist/channels/slack/sender-name.d.ts.map +1 -1
  115. package/dist/channels/slack/sender-name.js +57 -61
  116. package/dist/channels/slack/setup.js +2 -4
  117. package/dist/channels/slack/slack-channel.d.ts +6 -4
  118. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  119. package/dist/channels/slack/slack-channel.js +441 -308
  120. package/dist/channels/slack/socket-mode.js +38 -52
  121. package/dist/channels/slack/thread-context.js +143 -160
  122. package/dist/channels/slack/tool-approval-events.js +149 -166
  123. package/dist/channels/slack/tool-cards.js +6 -11
  124. package/dist/channels/slack/tool-chip.js +1 -2
  125. package/dist/channels/slack/types.d.ts +15 -17
  126. package/dist/channels/slack/types.d.ts.map +1 -1
  127. package/dist/channels/slack/upload.js +84 -97
  128. package/dist/channels/slack/user-info.js +27 -41
  129. package/dist/channels.js +9 -20
  130. package/dist/dashboard-session-url.js +3 -4
  131. package/dist/docs/404.html +2 -2
  132. package/dist/docs/assets/{app.BNhEdGa8.js → app.DXI7bwox.js} +4 -4
  133. package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.js → building-with-agents.md.Df87rAe1.js} +1 -1
  134. package/dist/docs/assets/chunks/@localSearchIndexroot.CtLtpWcx.js +1 -0
  135. package/dist/docs/assets/chunks/{VPLocalSearchBox.DIdUV1Ph.js → VPLocalSearchBox.BrbO5mEe.js} +1 -1
  136. package/dist/docs/assets/chunks/{arc.lELI4_SR.js → arc.BOG1yms8.js} +1 -1
  137. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.iCMdvuoM.js → architectureDiagram-Q4EWVU46.C0hsMZnZ.js} +1 -1
  138. package/dist/docs/assets/chunks/{baseUniq.C1-nDJBf.js → baseUniq.H044KjKs.js} +1 -1
  139. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.ClemzBox.js → blockDiagram-DXYQGD6D.BsRW6GoB.js} +1 -1
  140. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.BqTak6cR.js → c4Diagram-AHTNJAMY.B9HV5PFR.js} +1 -1
  141. package/dist/docs/assets/chunks/channel.CBwrU9rP.js +1 -0
  142. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.CUS3qs_R.js → chunk-4BX2VUAB.CPoT_ajl.js} +1 -1
  143. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.dz5fdHcl.js → chunk-4TB4RGXK.DZBwWuCL.js} +1 -1
  144. package/dist/docs/assets/chunks/{chunk-55IACEB6.D6BEBmve.js → chunk-55IACEB6.CZ3yTiyq.js} +1 -1
  145. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.B5uK4ID9.js → chunk-EDXVE4YY.6DfvHSd8.js} +1 -1
  146. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.PgOJgNQs.js → chunk-FMBD7UC4.CpBj8HfK.js} +1 -1
  147. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CvkTrCii.js → chunk-OYMX7WX6.BdKo8YqS.js} +1 -1
  148. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BnSfKYsB.js → chunk-QZHKN3VN.BnXNyxJx.js} +1 -1
  149. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.MZH6v5UC.js → chunk-YZCP3GAM.Cg1OcF8G.js} +1 -1
  150. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CbC_mrvB.js +1 -0
  151. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CbC_mrvB.js +1 -0
  152. package/dist/docs/assets/chunks/clone.BTvFyY1a.js +1 -0
  153. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.BBbw_YZi.js → cose-bilkent-S5V4N54A.1SP8al9c.js} +1 -1
  154. package/dist/docs/assets/chunks/{dagre-KV5264BT.CNJB2l7E.js → dagre-KV5264BT.DS1L6hJt.js} +1 -1
  155. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.BQzlnFfq.js → diagram-5BDNPKRD.ChsausbG.js} +1 -1
  156. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.DkgqqZMz.js → diagram-G4DWMVQ6.3XsptNWj.js} +1 -1
  157. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.DIT8L7H_.js → diagram-MMDJMWI5.DPA9Dk_P.js} +1 -1
  158. package/dist/docs/assets/chunks/{diagram-TYMM5635.3xLPZWGJ.js → diagram-TYMM5635.BVswXWrB.js} +1 -1
  159. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.5_IHz8jF.js → erDiagram-SMLLAGMA.BSak5OSP.js} +1 -1
  160. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.BGUCXz8A.js → flowDiagram-DWJPFMVM.CQgN4TTz.js} +1 -1
  161. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.DbfFavS1.js → ganttDiagram-T4ZO3ILL.GrT0kA4a.js} +1 -1
  162. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.D2yKdeNW.js → gitGraphDiagram-UUTBAWPF.CdS7Ucll.js} +1 -1
  163. package/dist/docs/assets/chunks/{graph.CSCxwHba.js → graph.BVqKRmRo.js} +1 -1
  164. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.FDeb6xHY.js → infoDiagram-42DDH7IO.C3C9FRto.js} +1 -1
  165. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DbeYs9VL.js → ishikawaDiagram-UXIWVN3A.2FuAh_Zj.js} +1 -1
  166. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.CWjKINpx.js → journeyDiagram-VCZTEJTY.CaHMfK4b.js} +1 -1
  167. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.B4FrAlwz.js → kanban-definition-6JOO6SKY.CjhIUwcA.js} +1 -1
  168. package/dist/docs/assets/chunks/{layout.DFGxQ9ab.js → layout.CGU3gfSf.js} +1 -1
  169. package/dist/docs/assets/chunks/{linear.BmjZ-G59.js → linear.DaihpW_n.js} +1 -1
  170. package/dist/docs/assets/chunks/{min.DZSxulMW.js → min.BS-j8kHQ.js} +1 -1
  171. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CHLi3-aN.js → mindmap-definition-QFDTVHPH.BVJ1Bbnk.js} +1 -1
  172. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DteG-CkU.js → pieDiagram-DEJITSTG.Cz1WIv9r.js} +1 -1
  173. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D458ipN3.js → quadrantDiagram-34T5L4WZ.DKLFxcjy.js} +1 -1
  174. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.DcFgUxst.js → requirementDiagram-MS252O5E.BHegiK7x.js} +1 -1
  175. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.BwQAMmSA.js → sankeyDiagram-XADWPNL6.DYkY6yPc.js} +1 -1
  176. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.B_Xdsrh9.js → sequenceDiagram-FGHM5R23.DYQ1QUrI.js} +1 -1
  177. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.CdfDW6-C.js → stateDiagram-FHFEXIEX.Iru8BsFo.js} +1 -1
  178. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.BYXl4LW6.js +1 -0
  179. package/dist/docs/assets/chunks/{theme.sfdL3srp.js → theme.DaplWQhQ.js} +2 -2
  180. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.56-4hXaC.js → timeline-definition-GMOUNBTQ.BwFA8hiX.js} +1 -1
  181. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CvZSQBO7.js → vennDiagram-DHZGUBPP.CZ60W1C_.js} +1 -1
  182. package/dist/docs/assets/chunks/{wardley-RL74JXVD.C9qc8k39.js → wardley-RL74JXVD.iXazD3Z7.js} +1 -1
  183. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.D9s0nihi.js → wardleyDiagram-NUSXRM2D.B69D2r8-.js} +1 -1
  184. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.BVJSpYrC.js → xychartDiagram-5P7HB3ND.CLPZEIU9.js} +1 -1
  185. package/dist/docs/assets/{deployment.md.BdqTiGdc.js → deployment.md.BYuEcDBv.js} +2 -2
  186. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.js → guides_bitbucket.md.CKUayYtD.js} +3 -3
  187. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.lean.js → guides_bitbucket.md.CKUayYtD.lean.js} +1 -1
  188. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.js → guides_github.md.TuNiZAOQ.js} +4 -4
  189. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.lean.js → guides_github.md.TuNiZAOQ.lean.js} +1 -1
  190. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.js → guides_gitlab.md.CtNI4fSH.js} +4 -4
  191. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.lean.js → guides_gitlab.md.CtNI4fSH.lean.js} +1 -1
  192. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.js +7 -0
  193. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.lean.js +1 -0
  194. package/dist/docs/assets/{reference_cli.md.GwugN3n-.js → reference_cli.md.dYCAL2lB.js} +4 -3
  195. package/dist/docs/assets/reference_cli.md.dYCAL2lB.lean.js +1 -0
  196. package/dist/docs/assets/troubleshooting.md.x-GBa7wN.js +1 -0
  197. package/dist/docs/assets/{troubleshooting.md.Bscj6ODe.lean.js → troubleshooting.md.x-GBa7wN.lean.js} +1 -1
  198. package/dist/docs/building-with-agents.html +37 -37
  199. package/dist/docs/building-with-agents.md +2 -0
  200. package/dist/docs/deployment.html +38 -38
  201. package/dist/docs/deployment.md +7 -0
  202. package/dist/docs/evals.html +36 -36
  203. package/dist/docs/guides/agent-to-agent.html +35 -35
  204. package/dist/docs/guides/bitbucket.html +38 -38
  205. package/dist/docs/guides/bitbucket.md +9 -1
  206. package/dist/docs/guides/cloud-agents.html +35 -35
  207. package/dist/docs/guides/convert-automation.html +35 -35
  208. package/dist/docs/guides/github.html +39 -39
  209. package/dist/docs/guides/github.md +20 -4
  210. package/dist/docs/guides/gitlab.html +38 -38
  211. package/dist/docs/guides/gitlab.md +9 -1
  212. package/dist/docs/guides/grokbot-agents.html +35 -35
  213. package/dist/docs/guides/hooks.html +35 -35
  214. package/dist/docs/guides/improve.html +35 -35
  215. package/dist/docs/guides/jev.html +35 -35
  216. package/dist/docs/guides/mcp-oauth.html +35 -35
  217. package/dist/docs/guides/migrate.html +66 -0
  218. package/dist/docs/guides/migrate.md +122 -0
  219. package/dist/docs/guides/opentelemetry.html +35 -35
  220. package/dist/docs/guides/slack.html +35 -35
  221. package/dist/docs/guides/webhooks.html +35 -35
  222. package/dist/docs/hashmap.json +1 -1
  223. package/dist/docs/hillclimbing.html +35 -35
  224. package/dist/docs/index.html +35 -35
  225. package/dist/docs/llms-full.txt +214 -6
  226. package/dist/docs/llms.txt +1 -0
  227. package/dist/docs/quickstart.html +35 -35
  228. package/dist/docs/reference/agent-config.html +35 -35
  229. package/dist/docs/reference/artifacts.html +35 -35
  230. package/dist/docs/reference/channels.html +35 -35
  231. package/dist/docs/reference/cli.html +39 -38
  232. package/dist/docs/reference/cli.md +39 -0
  233. package/dist/docs/reference/connections.html +35 -35
  234. package/dist/docs/reference/evals.html +35 -35
  235. package/dist/docs/reference/extensions.html +35 -35
  236. package/dist/docs/reference/hooks.html +35 -35
  237. package/dist/docs/reference/http-api.html +35 -35
  238. package/dist/docs/reference/instructions.html +35 -35
  239. package/dist/docs/reference/playground.html +35 -35
  240. package/dist/docs/reference/project-layout.html +35 -35
  241. package/dist/docs/reference/prompt.html +35 -35
  242. package/dist/docs/reference/schedules.html +35 -35
  243. package/dist/docs/reference/sessions.html +35 -35
  244. package/dist/docs/reference/skills.html +35 -35
  245. package/dist/docs/reference/subagents.html +35 -35
  246. package/dist/docs/reference/tools.html +35 -35
  247. package/dist/docs/templates/agentic-owners.html +35 -35
  248. package/dist/docs/templates/grokbot-agents.html +35 -35
  249. package/dist/docs/templates/security-reviewer.html +35 -35
  250. package/dist/docs/templates/thermo-quality-review.html +35 -35
  251. package/dist/docs/templates/thermo-review.html +35 -35
  252. package/dist/docs/templates/triage.html +35 -35
  253. package/dist/docs/troubleshooting.html +36 -36
  254. package/dist/docs/troubleshooting.md +1 -0
  255. package/dist/evals/assertions.js +20 -34
  256. package/dist/evals/expect.js +3 -6
  257. package/dist/evals/judge.js +5 -8
  258. package/dist/evals/loaders.js +45 -62
  259. package/dist/evals/matchers.js +2 -3
  260. package/dist/evals/reporters.js +43 -67
  261. package/dist/evals/results.js +1 -1
  262. package/dist/evals/run-facts.js +5 -6
  263. package/dist/evals.js +27 -15
  264. package/dist/extensions/cursor-cloud-agents/extension.js +4 -1
  265. package/dist/extensions/cursor-cloud-agents/lib/backend.js +100 -126
  266. package/dist/extensions/cursor-cloud-agents/lib/fleet.js +22 -38
  267. package/dist/extensions/cursor-cloud-agents/lib/repos.js +8 -10
  268. package/dist/extensions/cursor-cloud-agents/lib/transcript.js +2 -3
  269. package/dist/extensions/cursor-cloud-agents/lib/watch.js +52 -66
  270. package/dist/extensions/cursor-cloud-agents/reminders/cloud-agent-stop-watch.js +29 -40
  271. package/dist/extensions/cursor-cloud-agents/tools/cancel.js +6 -17
  272. package/dist/extensions/cursor-cloud-agents/tools/dump.js +25 -36
  273. package/dist/extensions/cursor-cloud-agents/tools/get.js +3 -14
  274. package/dist/extensions/cursor-cloud-agents/tools/launch.js +13 -21
  275. package/dist/extensions/cursor-cloud-agents/tools/list.js +8 -19
  276. package/dist/extensions/cursor-cloud-agents/tools/reply.js +5 -16
  277. package/dist/extensions/cursor-grokbot-agents/extension.js +4 -1
  278. package/dist/extensions/cursor-grokbot-agents/lib/agents.js +3 -3
  279. package/dist/extensions/cursor-grokbot-agents/lib/backend.js +53 -73
  280. package/dist/extensions/cursor-grokbot-agents/lib/contacts.js +10 -23
  281. package/dist/extensions/cursor-grokbot-agents/lib/conversation.js +112 -132
  282. package/dist/extensions/cursor-grokbot-agents/lib/lock.js +1 -2
  283. package/dist/extensions/cursor-grokbot-agents/tools/ask.js +5 -16
  284. package/dist/extensions/cursor-grokbot-agents/tools/check.js +4 -15
  285. package/dist/extensions/cursor-grokbot-agents/tools/interrupt.js +2 -13
  286. package/dist/extensions/cursor-grokbot-agents/tools/list.js +11 -23
  287. package/dist/extensions/jev/extension.js +3 -3
  288. package/dist/extensions/jev/lib/evaluate.js +43 -60
  289. package/dist/extensions/jev/tools/evaluate.js +6 -17
  290. package/dist/extensions/slack-communication/tools/post-file.js +1 -1
  291. package/dist/extensions.js +3 -5
  292. package/dist/files-backends/cursor-hosted.js +504 -523
  293. package/dist/files-backends/local-fs.js +72 -134
  294. package/dist/files.js +3 -3
  295. package/dist/filesystem.js +562 -861
  296. package/dist/index.js +16 -35
  297. package/dist/internal/advertise-tools.js +74 -86
  298. package/dist/internal/artifacts-store.js +298 -361
  299. package/dist/internal/as-of.js +2 -4
  300. package/dist/internal/authored-alias-hooks.js +6 -4
  301. package/dist/internal/authored-loaders.js +37 -52
  302. package/dist/internal/bounded-int.js +1 -2
  303. package/dist/internal/bounded.js +13 -24
  304. package/dist/internal/brand.js +1 -1
  305. package/dist/internal/browser-origin-guard.js +4 -4
  306. package/dist/internal/builtin-tools/artifacts.js +15 -27
  307. package/dist/internal/builtin-tools/index.js +2 -3
  308. package/dist/internal/builtin-tools/reminders.js +33 -52
  309. package/dist/internal/channel-architecture.d.ts +21 -0
  310. package/dist/internal/channel-architecture.d.ts.map +1 -0
  311. package/dist/internal/channel-architecture.js +41 -0
  312. package/dist/internal/channel-dispatch.js +3 -4
  313. package/dist/internal/channel-route-dispatch.js +40 -51
  314. package/dist/internal/channel-state.js +1 -1
  315. package/dist/internal/chat-client.js +319 -340
  316. package/dist/internal/cli-ax.js +1262 -1294
  317. package/dist/internal/cli-bitbucket.js +244 -272
  318. package/dist/internal/cli-convert-automation.js +137 -151
  319. package/dist/internal/cli-cursor.js +126 -147
  320. package/dist/internal/cli-deploy.d.ts.map +1 -1
  321. package/dist/internal/cli-deploy.js +1457 -1507
  322. package/dist/internal/cli-docs.js +130 -147
  323. package/dist/internal/cli-github.js +437 -476
  324. package/dist/internal/cli-gitlab.js +259 -288
  325. package/dist/internal/cli-images.js +266 -334
  326. package/dist/internal/cli-manifest.js +25 -37
  327. package/dist/internal/cli-mcp-oauth.js +228 -247
  328. package/dist/internal/cli-mcp.js +358 -383
  329. package/dist/internal/cli-migrate.js +73 -90
  330. package/dist/internal/cli-skills.js +35 -47
  331. package/dist/internal/cli-slack-manual.d.ts +0 -1
  332. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  333. package/dist/internal/cli-slack-manual.js +175 -204
  334. package/dist/internal/cli-slack.d.ts +1 -1
  335. package/dist/internal/cli-slack.d.ts.map +1 -1
  336. package/dist/internal/cli-slack.js +416 -456
  337. package/dist/internal/cloud-merge.js +7 -3
  338. package/dist/internal/cloud-turn-cost.js +8 -1
  339. package/dist/internal/connection-env.js +5 -6
  340. package/dist/internal/continuation-channel.js +10 -7
  341. package/dist/internal/continuation-identity.js +85 -67
  342. package/dist/internal/conversation-mirror.js +112 -131
  343. package/dist/internal/convert-automation/convert-workflow.js +21 -31
  344. package/dist/internal/cron.js +3 -3
  345. package/dist/internal/cursor/account-mcp.js +147 -146
  346. package/dist/internal/cursor/backend-client.js +290 -320
  347. package/dist/internal/cursor/bound-secret-file.js +3 -3
  348. package/dist/internal/cursor/credentials.js +127 -142
  349. package/dist/internal/cursor/cursor-api-transport.js +4 -8
  350. package/dist/internal/cursor/github-credentials.js +91 -108
  351. package/dist/internal/cursor/hosted-bound-secrets.js +3 -4
  352. package/dist/internal/cursor/hosted-deployment-secrets.js +1 -1
  353. package/dist/internal/cursor/hosted-store-secrets.js +5 -9
  354. package/dist/internal/cursor/session-token.js +36 -48
  355. package/dist/internal/cursor/store-api-client.js +77 -92
  356. package/dist/internal/cursor-account-mcp-auth.js +132 -149
  357. package/dist/internal/cursor-agent-template.js +1 -1
  358. package/dist/internal/cursor-deployment-relay.js +33 -54
  359. package/dist/internal/cursor-event-relay.js +65 -59
  360. package/dist/internal/cursor-relay-core.js +258 -286
  361. package/dist/internal/deferred-channel-session.js +3 -12
  362. package/dist/internal/deploy-client.d.ts.map +1 -1
  363. package/dist/internal/deploy-client.js +413 -475
  364. package/dist/internal/deploy-manifest.d.ts +17 -0
  365. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  366. package/dist/internal/deploy-manifest.js +71 -21
  367. package/dist/internal/deploy-source.js +31 -43
  368. package/dist/internal/discovery/agent-config.js +45 -59
  369. package/dist/internal/discovery/agent.js +276 -280
  370. package/dist/internal/discovery/channels.js +67 -80
  371. package/dist/internal/discovery/connections.js +286 -296
  372. package/dist/internal/discovery/context.js +2 -13
  373. package/dist/internal/discovery/cursor-plugin.js +223 -259
  374. package/dist/internal/discovery/extension-overlay.js +104 -131
  375. package/dist/internal/discovery/extensions.js +276 -281
  376. package/dist/internal/discovery/fs.js +56 -79
  377. package/dist/internal/discovery/hooks.js +39 -50
  378. package/dist/internal/discovery/info.js +17 -19
  379. package/dist/internal/discovery/instructions.js +58 -71
  380. package/dist/internal/discovery/modules.js +45 -58
  381. package/dist/internal/discovery/project.d.ts.map +1 -1
  382. package/dist/internal/discovery/project.js +192 -215
  383. package/dist/internal/discovery/reminders.js +41 -52
  384. package/dist/internal/discovery/runtime.js +1 -1
  385. package/dist/internal/discovery/schedules.js +71 -82
  386. package/dist/internal/discovery/seed-files.js +21 -32
  387. package/dist/internal/discovery/services.js +74 -96
  388. package/dist/internal/discovery/skills.js +77 -94
  389. package/dist/internal/discovery/subagent.js +79 -95
  390. package/dist/internal/discovery/tools.js +12 -23
  391. package/dist/internal/distribution.js +2 -2
  392. package/dist/internal/docs-site.js +30 -45
  393. package/dist/internal/duration.js +1 -1
  394. package/dist/internal/env-file.js +48 -64
  395. package/dist/internal/eval-judge-model.js +17 -28
  396. package/dist/internal/eval-run-store.js +265 -254
  397. package/dist/internal/eval-runner.d.ts +8 -0
  398. package/dist/internal/eval-runner.d.ts.map +1 -1
  399. package/dist/internal/eval-runner.js +406 -408
  400. package/dist/internal/eval-transport.d.ts +24 -0
  401. package/dist/internal/eval-transport.d.ts.map +1 -0
  402. package/dist/internal/eval-transport.js +22 -0
  403. package/dist/internal/evals-client.js +242 -246
  404. package/dist/internal/event-log.js +72 -120
  405. package/dist/internal/event-mapper.js +30 -31
  406. package/dist/internal/factory-resource-channel.js +16 -30
  407. package/dist/internal/filesystem/errors.js +6 -6
  408. package/dist/internal/filesystem/format.js +10 -13
  409. package/dist/internal/filesystem/merge.js +52 -94
  410. package/dist/internal/filesystem/nearest.js +15 -27
  411. package/dist/internal/filesystem/scratch.js +65 -85
  412. package/dist/internal/filesystem/tools.js +221 -241
  413. package/dist/internal/filesystem/walk.js +76 -143
  414. package/dist/internal/framework-file-storage.js +118 -139
  415. package/dist/internal/framework-storage-selection.js +21 -13
  416. package/dist/internal/frontmatter.js +4 -6
  417. package/dist/internal/github-fanout.js +50 -64
  418. package/dist/internal/guest-network.js +96 -109
  419. package/dist/internal/handleAgentServeTrigger.js +121 -126
  420. package/dist/internal/host-files.js +73 -88
  421. package/dist/internal/host-kv.js +21 -36
  422. package/dist/internal/host-otel.js +22 -19
  423. package/dist/internal/host-platforms.js +49 -63
  424. package/dist/internal/hosted-catch-protocol.d.ts +1 -0
  425. package/dist/internal/hosted-catch-protocol.d.ts.map +1 -1
  426. package/dist/internal/hosted-catch-protocol.js +1 -0
  427. package/dist/internal/hosted-catch.d.ts +5 -3
  428. package/dist/internal/hosted-catch.d.ts.map +1 -1
  429. package/dist/internal/hosted-catch.js +84 -93
  430. package/dist/internal/hosted-delivery-protocol.js +32 -8
  431. package/dist/internal/hosted-delivery.d.ts +13 -1
  432. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  433. package/dist/internal/hosted-delivery.js +614 -584
  434. package/dist/internal/hosted-eval-cases.d.ts +21 -0
  435. package/dist/internal/hosted-eval-cases.d.ts.map +1 -0
  436. package/dist/internal/hosted-eval-cases.js +162 -0
  437. package/dist/internal/hosted-execution-diag.js +38 -30
  438. package/dist/internal/hosted-execution-flush.js +75 -66
  439. package/dist/internal/hosted-execution-latency.js +16 -8
  440. package/dist/internal/hosted-managed-automation.js +2 -2
  441. package/dist/internal/hosting.js +2 -3
  442. package/dist/internal/http-channel-define.js +4 -1
  443. package/dist/internal/http-channel.js +101 -112
  444. package/dist/internal/http-control-plane-session.d.ts +18 -1
  445. package/dist/internal/http-control-plane-session.d.ts.map +1 -1
  446. package/dist/internal/http-control-plane-session.js +66 -32
  447. package/dist/internal/incoming-headers-to-fetch.js +1 -2
  448. package/dist/internal/init-interview.js +73 -93
  449. package/dist/internal/init-project.js +182 -214
  450. package/dist/internal/init-scaffold.js +10 -21
  451. package/dist/internal/inline-stdio-mcp.js +80 -86
  452. package/dist/internal/install-cursor-skills.js +231 -273
  453. package/dist/internal/legacy-command-guard.js +18 -31
  454. package/dist/internal/listen-port.js +34 -45
  455. package/dist/internal/local-control-plane.js +293 -307
  456. package/dist/internal/local-env.js +1 -1
  457. package/dist/internal/local-ingress.js +15 -9
  458. package/dist/internal/log-ring.js +1 -2
  459. package/dist/internal/logs-client.js +207 -227
  460. package/dist/internal/map-pool.js +24 -38
  461. package/dist/internal/mcp-endpoint.js +204 -180
  462. package/dist/internal/mcp-host.js +165 -168
  463. package/dist/internal/mcp-oauth-on-demand.js +170 -207
  464. package/dist/internal/mcp-oauth-persist.js +15 -29
  465. package/dist/internal/mcp-oauth.js +209 -266
  466. package/dist/internal/named-webhook-secret.d.ts +39 -0
  467. package/dist/internal/named-webhook-secret.d.ts.map +1 -0
  468. package/dist/internal/named-webhook-secret.js +47 -0
  469. package/dist/internal/open-browser.js +2 -3
  470. package/dist/internal/otel/collector.js +104 -68
  471. package/dist/internal/otel/config.js +24 -37
  472. package/dist/internal/otel/http.js +5 -7
  473. package/dist/internal/otel/mcp.js +3 -12
  474. package/dist/internal/otel/runtime.js +69 -83
  475. package/dist/internal/package-inline-stdio.js +57 -65
  476. package/dist/internal/peer-connections.js +9 -5
  477. package/dist/internal/platform-schedule-sync.js +39 -54
  478. package/dist/internal/platform-timers.js +176 -210
  479. package/dist/internal/playground/static.js +1 -2
  480. package/dist/internal/playground/toolchain.js +37 -53
  481. package/dist/internal/playground-proxy.js +230 -270
  482. package/dist/internal/process-memory-telemetry.js +33 -51
  483. package/dist/internal/prompt-context.js +3 -6
  484. package/dist/internal/reminder-control-plane-protocol.js +46 -13
  485. package/dist/internal/reminder-runner.js +770 -785
  486. package/dist/internal/reminder-schedule.js +1 -1
  487. package/dist/internal/reminder-store.js +57 -78
  488. package/dist/internal/request-error-status.js +1 -3
  489. package/dist/internal/request-headers.js +2 -2
  490. package/dist/internal/resolve-prod-target.js +119 -135
  491. package/dist/internal/resolved-connections.js +16 -6
  492. package/dist/internal/run-client.js +221 -229
  493. package/dist/internal/runtime-dispatch-runner.js +18 -43
  494. package/dist/internal/schedule-runner.js +49 -58
  495. package/dist/internal/scm/pr-url.js +7 -6
  496. package/dist/internal/sdk-runner.js +388 -363
  497. package/dist/internal/serve-restart.js +26 -39
  498. package/dist/internal/server.d.ts.map +1 -1
  499. package/dist/internal/server.js +1283 -1244
  500. package/dist/internal/session-cost.js +7 -9
  501. package/dist/internal/session-engine.d.ts +3 -1
  502. package/dist/internal/session-engine.d.ts.map +1 -1
  503. package/dist/internal/session-engine.js +2801 -2777
  504. package/dist/internal/session-links.js +12 -16
  505. package/dist/internal/session-run-log.js +134 -82
  506. package/dist/internal/session-store.js +133 -164
  507. package/dist/internal/sessions-client.js +97 -118
  508. package/dist/internal/skill-catalog.js +18 -23
  509. package/dist/internal/skills-sync.js +16 -30
  510. package/dist/internal/slack-provision-client.js +90 -116
  511. package/dist/internal/start-log-store.js +48 -67
  512. package/dist/internal/steering.js +1 -2
  513. package/dist/internal/storage-coordinator.js +160 -196
  514. package/dist/internal/store-mirror.js +16 -30
  515. package/dist/internal/stream-progress.js +6 -8
  516. package/dist/internal/terminal-style.js +3 -4
  517. package/dist/internal/testing/scm-continuation-fixtures.js +6 -2
  518. package/dist/internal/testing/slack-continuation-fixtures.d.ts +26 -0
  519. package/dist/internal/testing/slack-continuation-fixtures.d.ts.map +1 -0
  520. package/dist/internal/testing/slack-continuation-fixtures.js +136 -0
  521. package/dist/internal/tool-catalog.js +11 -5
  522. package/dist/internal/tool-result.js +1 -1
  523. package/dist/internal/trajectory.js +19 -22
  524. package/dist/internal/turn-cost.js +52 -62
  525. package/dist/internal/turn-governor.js +5 -8
  526. package/dist/internal/turn-lease-store.js +85 -105
  527. package/dist/internal/turn-outbox.js +28 -43
  528. package/dist/internal/update-check.js +231 -259
  529. package/dist/internal/v2-hosting.js +1 -2
  530. package/dist/internal/workspace-sync.js +25 -41
  531. package/dist/internal/workspace.js +111 -139
  532. package/dist/kv/memory-kv.js +27 -51
  533. package/dist/memory.js +106 -148
  534. package/dist/otel.js +5 -8
  535. package/dist/playground/assets/{index-Co4CUVTQ.js → index-Be0-1hw2.js} +45 -45
  536. package/dist/playground/assets/index-Clz6uHj9.css +1 -0
  537. package/dist/playground/index.html +2 -2
  538. package/dist/prompt.js +2 -4
  539. package/dist/storage-backends/cursor-hosted-v2.js +53 -83
  540. package/dist/storage-backends/cursor-hosted.js +105 -145
  541. package/dist/storage-backends/file-kv.js +100 -128
  542. package/dist/storage-protocol.js +3 -5
  543. package/dist/storage.js +17 -26
  544. package/dist/types.d.ts +68 -0
  545. package/dist/types.d.ts.map +1 -1
  546. package/dist/types.js +20 -18
  547. package/docs/building-with-agents.md +2 -0
  548. package/docs/deployment.md +7 -0
  549. package/docs/guides/bitbucket.md +9 -1
  550. package/docs/guides/github.md +20 -4
  551. package/docs/guides/gitlab.md +9 -1
  552. package/docs/guides/migrate.md +127 -0
  553. package/docs/reference/cli.md +39 -0
  554. package/docs/troubleshooting.md +1 -0
  555. package/package.json +1 -1
  556. package/skills/debug/SKILL.md +1 -0
  557. package/skills/github/SKILL.md +23 -0
  558. package/skills/migrate-v2/SKILL.md +51 -10
  559. package/dist/docs/assets/chunks/@localSearchIndexroot.BJ8UZggu.js +0 -1
  560. package/dist/docs/assets/chunks/channel.BTJ5J9FI.js +0 -1
  561. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.D4BZ3cVV.js +0 -1
  562. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.D4BZ3cVV.js +0 -1
  563. package/dist/docs/assets/chunks/clone.62tX-O-1.js +0 -1
  564. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.DkTs1aEU.js +0 -1
  565. package/dist/docs/assets/reference_cli.md.GwugN3n-.lean.js +0 -1
  566. package/dist/docs/assets/troubleshooting.md.Bscj6ODe.js +0 -1
  567. package/dist/playground/assets/index-C1g_PTTZ.css +0 -1
  568. /package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.lean.js → building-with-agents.md.Df87rAe1.lean.js} +0 -0
  569. /package/dist/docs/assets/{deployment.md.BdqTiGdc.lean.js → deployment.md.BYuEcDBv.lean.js} +0 -0
@@ -3,15 +3,6 @@
3
3
  * prompt XOR named handler XOR run, every/cron/delay/at schedules, and
4
4
  * until as function XOR prompt.
5
5
  */
6
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
8
- return new (P || (P = Promise))(function (resolve, reject) {
9
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
10
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
11
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
12
- step((generator = generator.apply(thisArg, _arguments || [])).next());
13
- });
14
- };
15
6
  import { randomBytes } from "node:crypto";
16
7
  import { channelContinuationIdentity, httpContinuationIdentity } from "./continuation-channel.js";
17
8
  import { continuationSource, isOneShotContinuationKey } from "./continuation-identity.js";
@@ -114,11 +105,10 @@ function runReason(result) {
114
105
  }
115
106
  }
116
107
  function buildFirePrompt(record) {
117
- var _a;
118
108
  const recurring = record.scheduleKind === "every" || record.scheduleKind === "cron";
119
109
  const lines = [
120
110
  `[reminder] id=${record.id} purpose=${record.purpose}`,
121
- (_a = record.prompt) !== null && _a !== void 0 ? _a : "Reminder fired. Check current state and only act if needed.",
111
+ record.prompt ?? "Reminder fired. Check current state and only act if needed.",
122
112
  ];
123
113
  if (record.untilPrompt !== undefined && record.untilPrompt.trim() !== "") {
124
114
  lines.push("", `Stop condition: ${record.untilPrompt}`);
@@ -133,7 +123,6 @@ function buildFirePrompt(record) {
133
123
  }
134
124
  export class ReminderRunner {
135
125
  constructor(engine, logger = () => { }, platformTimers, options = {}) {
136
- var _a;
137
126
  this.engine = engine;
138
127
  this.logger = logger;
139
128
  this.platformTimers = platformTimers;
@@ -155,7 +144,7 @@ export class ReminderRunner {
155
144
  this.controlPlane = options.controlPlane;
156
145
  this.architecture = options.architecture;
157
146
  this.hostedGuest = options.hostedGuest;
158
- for (const reminder of (_a = options.namedHandlers) !== null && _a !== void 0 ? _a : []) {
147
+ for (const reminder of options.namedHandlers ?? []) {
159
148
  this.namedHandlers.set(reminder.name, reminder.definition);
160
149
  this.namedHandlerNames.set(reminder.definition, reminder.name);
161
150
  }
@@ -187,178 +176,169 @@ export class ReminderRunner {
187
176
  * Load reminder documents from the control plane into memory. Does not
188
177
  * arm in-process timers — the CP owns clocks.
189
178
  */
190
- hydrate() {
191
- return __awaiter(this, void 0, void 0, function* () {
192
- const reader = this.reminderReader;
193
- if (reader === undefined) {
194
- return;
195
- }
196
- let remote = [];
197
- try {
198
- remote = yield reader.listReminders();
199
- }
200
- catch (error) {
201
- this.logControlPlaneReadFailure("list", error);
202
- return;
203
- }
204
- this.controlPlaneReadFailureLogged = false;
205
- this.records.clear();
206
- for (const record of remote) {
207
- this.records.set(record.id, record);
179
+ async hydrate() {
180
+ const reader = this.reminderReader;
181
+ if (reader === undefined) {
182
+ return;
183
+ }
184
+ let remote = [];
185
+ try {
186
+ remote = await reader.listReminders();
187
+ }
188
+ catch (error) {
189
+ this.logControlPlaneReadFailure("list", error);
190
+ return;
191
+ }
192
+ this.controlPlaneReadFailureLogged = false;
193
+ this.records.clear();
194
+ for (const record of remote) {
195
+ this.records.set(record.id, record);
196
+ }
197
+ if (this.usesControlPlaneProtocol) {
198
+ // The CP owns status; a fire whose handler is missing reports `stop`
199
+ // from executeFire instead of the guest writing a disarm.
200
+ if (remote.length > 0) {
201
+ this.logger(`[bdk] reminders: hydrated ${remote.length} reminder(s) from control plane`);
208
202
  }
209
- if (this.usesControlPlaneProtocol) {
210
- // The CP owns status; a fire whose handler is missing reports `stop`
211
- // from executeFire instead of the guest writing a disarm.
212
- if (remote.length > 0) {
213
- this.logger(`[bdk] reminders: hydrated ${remote.length} reminder(s) from control plane`);
214
- }
215
- return;
203
+ return;
204
+ }
205
+ let disarmedOrphan = 0;
206
+ for (const record of [...this.records.values()]) {
207
+ if (record.status !== "armed") {
208
+ continue;
216
209
  }
217
- let disarmedOrphan = 0;
218
- for (const record of [...this.records.values()]) {
219
- if (record.status !== "armed") {
220
- continue;
221
- }
222
- if (record.handler !== undefined) {
223
- if (this.namedHandlers.get(record.handler) === undefined) {
224
- yield this.disarm(record, "handler_missing");
225
- disarmedOrphan += 1;
226
- }
227
- continue;
228
- }
229
- if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
230
- this.handlers.get(record.id) === undefined) {
231
- yield this.disarm(record, "handler_lost_on_restart");
210
+ if (record.handler !== undefined) {
211
+ if (this.namedHandlers.get(record.handler) === undefined) {
212
+ await this.disarm(record, "handler_missing");
232
213
  disarmedOrphan += 1;
233
214
  }
215
+ continue;
234
216
  }
235
- if (remote.length > 0 || disarmedOrphan > 0) {
236
- this.logger(`[bdk] reminders: hydrated ${remote.length} reminder(s) from control plane` +
237
- (disarmedOrphan > 0 ? `; disarmed ${disarmedOrphan} without live handlers` : ""));
217
+ if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
218
+ this.handlers.get(record.id) === undefined) {
219
+ await this.disarm(record, "handler_lost_on_restart");
220
+ disarmedOrphan += 1;
238
221
  }
239
- });
222
+ }
223
+ if (remote.length > 0 || disarmedOrphan > 0) {
224
+ this.logger(`[bdk] reminders: hydrated ${remote.length} reminder(s) from control plane` +
225
+ (disarmedOrphan > 0 ? `; disarmed ${disarmedOrphan} without live handlers` : ""));
226
+ }
240
227
  }
241
228
  /** Start deadline timers for armed reminders (tests / no control plane). */
242
- start() {
243
- return __awaiter(this, void 0, void 0, function* () {
244
- if (this.started)
245
- return;
246
- this.started = true;
247
- yield this.hydrate();
248
- if (this.platformTimers !== undefined) {
249
- return;
250
- }
251
- const armed = [...this.records.values()].filter(r => r.status === "armed");
252
- let restored = 0;
253
- let disarmedOrphan = 0;
254
- for (const record of armed) {
255
- if (record.handler !== undefined) {
256
- if (this.namedHandlers.get(record.handler) === undefined) {
257
- yield this.disarm(record, "handler_missing");
258
- disarmedOrphan += 1;
259
- continue;
260
- }
261
- this.armTimer(record);
262
- restored += 1;
263
- continue;
264
- }
265
- if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
266
- this.handlers.get(record.id) === undefined) {
267
- yield this.disarm(record, "handler_lost_on_restart");
229
+ async start() {
230
+ if (this.started)
231
+ return;
232
+ this.started = true;
233
+ await this.hydrate();
234
+ if (this.platformTimers !== undefined) {
235
+ return;
236
+ }
237
+ const armed = [...this.records.values()].filter(r => r.status === "armed");
238
+ let restored = 0;
239
+ let disarmedOrphan = 0;
240
+ for (const record of armed) {
241
+ if (record.handler !== undefined) {
242
+ if (this.namedHandlers.get(record.handler) === undefined) {
243
+ await this.disarm(record, "handler_missing");
268
244
  disarmedOrphan += 1;
269
245
  continue;
270
246
  }
271
247
  this.armTimer(record);
272
248
  restored += 1;
249
+ continue;
273
250
  }
274
- if (restored > 0 || disarmedOrphan > 0) {
275
- this.logger(`[bdk] reminders: restored ${restored} armed reminder(s)` +
276
- (disarmedOrphan > 0 ? `; disarmed ${disarmedOrphan} without live handlers` : ""));
251
+ if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
252
+ this.handlers.get(record.id) === undefined) {
253
+ await this.disarm(record, "handler_lost_on_restart");
254
+ disarmedOrphan += 1;
255
+ continue;
277
256
  }
278
- });
257
+ this.armTimer(record);
258
+ restored += 1;
259
+ }
260
+ if (restored > 0 || disarmedOrphan > 0) {
261
+ this.logger(`[bdk] reminders: restored ${restored} armed reminder(s)` +
262
+ (disarmedOrphan > 0 ? `; disarmed ${disarmedOrphan} without live handlers` : ""));
263
+ }
279
264
  }
280
- persist(record) {
281
- return __awaiter(this, void 0, void 0, function* () {
282
- if (this.platformTimers !== undefined) {
283
- yield this.platformTimers.putReminder(record);
284
- }
285
- this.records.set(record.id, record);
286
- });
265
+ async persist(record) {
266
+ if (this.platformTimers !== undefined) {
267
+ await this.platformTimers.putReminder(record);
268
+ }
269
+ this.records.set(record.id, record);
287
270
  }
288
- getRecord(id) {
289
- return __awaiter(this, void 0, void 0, function* () {
290
- const reader = this.reminderReader;
291
- if (reader !== undefined) {
292
- try {
293
- const remote = yield reader.getReminder(id);
294
- this.controlPlaneReadFailureLogged = false;
295
- if (remote === undefined) {
296
- this.records.delete(id);
297
- return undefined;
298
- }
299
- this.records.set(id, remote);
300
- return remote;
301
- }
302
- catch (error) {
303
- this.logControlPlaneReadFailure(`get for ${id}`, error);
304
- return this.records.get(id);
271
+ async getRecord(id) {
272
+ const reader = this.reminderReader;
273
+ if (reader !== undefined) {
274
+ try {
275
+ const remote = await reader.getReminder(id);
276
+ this.controlPlaneReadFailureLogged = false;
277
+ if (remote === undefined) {
278
+ this.records.delete(id);
279
+ return undefined;
305
280
  }
281
+ this.records.set(id, remote);
282
+ return remote;
306
283
  }
307
- return this.records.get(id);
308
- });
284
+ catch (error) {
285
+ this.logControlPlaneReadFailure(`get for ${id}`, error);
286
+ return this.records.get(id);
287
+ }
288
+ }
289
+ return this.records.get(id);
309
290
  }
310
291
  /**
311
292
  * Under the CP protocol a list failure propagates: the in-memory map is
312
293
  * only what this process created, and returning it would let a caller
313
294
  * arm duplicates or miss rows to cancel. v1 keeps the best-effort form.
314
295
  */
315
- allRecords() {
316
- return __awaiter(this, void 0, void 0, function* () {
317
- const reader = this.reminderReader;
318
- if (reader !== undefined) {
319
- try {
320
- const remote = yield reader.listReminders();
321
- this.controlPlaneReadFailureLogged = false;
322
- this.records.clear();
323
- for (const record of remote) {
324
- this.records.set(record.id, record);
325
- }
296
+ async allRecords() {
297
+ const reader = this.reminderReader;
298
+ if (reader !== undefined) {
299
+ try {
300
+ const remote = await reader.listReminders();
301
+ this.controlPlaneReadFailureLogged = false;
302
+ this.records.clear();
303
+ for (const record of remote) {
304
+ this.records.set(record.id, record);
326
305
  }
327
- catch (error) {
328
- this.logControlPlaneReadFailure("list", error);
329
- if (this.usesControlPlaneProtocol) {
330
- throw error;
331
- }
306
+ }
307
+ catch (error) {
308
+ this.logControlPlaneReadFailure("list", error);
309
+ if (this.usesControlPlaneProtocol) {
310
+ throw error;
332
311
  }
333
312
  }
334
- return [...this.records.values()];
335
- });
313
+ }
314
+ return [...this.records.values()];
336
315
  }
337
316
  /**
338
317
  * A keyed list asks the control plane for that key. An unfiltered list
339
318
  * still uses allRecords. Do not replace the in-memory map with the keyed page.
340
319
  */
341
- recordsForList(filter) {
342
- return __awaiter(this, void 0, void 0, function* () {
343
- if (this.usesControlPlaneProtocol &&
344
- ((filter === null || filter === void 0 ? void 0 : filter.purpose) !== undefined || (filter === null || filter === void 0 ? void 0 : filter.continuationToken) !== undefined)) {
345
- try {
346
- const remote = yield this.controlPlane.listReminders(Object.assign(Object.assign({}, (filter.purpose === undefined ? {} : { purpose: filter.purpose })), (filter.continuationToken === undefined
320
+ async recordsForList(filter) {
321
+ if (this.usesControlPlaneProtocol &&
322
+ (filter?.purpose !== undefined || filter?.continuationToken !== undefined)) {
323
+ try {
324
+ const remote = await this.controlPlane.listReminders({
325
+ ...(filter.purpose === undefined ? {} : { purpose: filter.purpose }),
326
+ ...(filter.continuationToken === undefined
347
327
  ? {}
348
- : { continuationToken: filter.continuationToken })));
349
- this.controlPlaneReadFailureLogged = false;
350
- for (const record of remote) {
351
- this.records.set(record.id, record);
352
- }
353
- return remote;
354
- }
355
- catch (error) {
356
- this.logControlPlaneReadFailure("list", error);
357
- throw error;
328
+ : { continuationToken: filter.continuationToken }),
329
+ });
330
+ this.controlPlaneReadFailureLogged = false;
331
+ for (const record of remote) {
332
+ this.records.set(record.id, record);
358
333
  }
334
+ return remote;
359
335
  }
360
- return this.allRecords();
361
- });
336
+ catch (error) {
337
+ this.logControlPlaneReadFailure("list", error);
338
+ throw error;
339
+ }
340
+ }
341
+ return this.allRecords();
362
342
  }
363
343
  stop() {
364
344
  this.started = false;
@@ -368,204 +348,204 @@ export class ReminderRunner {
368
348
  this.timers.clear();
369
349
  this.idleGates.clear();
370
350
  }
371
- create(input) {
372
- return __awaiter(this, void 0, void 0, function* () {
373
- var _a, _b;
374
- const hasPrompt = input.prompt !== undefined;
375
- const hasRun = input.run !== undefined;
376
- const hasHandler = input.handler !== undefined;
377
- const formCount = [hasPrompt, hasRun, hasHandler].filter(Boolean).length;
378
- if (formCount !== 1) {
379
- throw new ReminderValidationError("reminders.create requires exactly one of prompt, handler, or run");
380
- }
381
- if (input.continuationToken.trim() === "") {
382
- throw new ReminderValidationError("continuationToken is required");
383
- }
384
- if (input.channelId.trim() === "") {
385
- throw new ReminderValidationError("channelId is required");
386
- }
387
- if (input.purpose.trim() === "") {
388
- throw new ReminderValidationError("purpose is required");
389
- }
390
- const untilPrompt = typeof input.until === "string" ? input.until : undefined;
391
- const untilFn = typeof input.until === "function" ? input.until : undefined;
392
- if (hasHandler && input.until !== undefined) {
393
- throw new ReminderValidationError("reminders.create: until is not valid with handler; encode the stop condition in args and the handler body");
394
- }
395
- if (this.rejectAnonymousHandlers) {
396
- if (hasRun) {
397
- throw new ReminderValidationError("reminders.create: anonymous run handlers are not durable on architecture v2; author reminders/<name>.ts under the project root and pass handler + args");
398
- }
399
- if (untilFn !== undefined) {
400
- throw new ReminderValidationError("reminders.create: function until is not durable on architecture v2; use a string until prompt");
401
- }
402
- }
403
- let handlerName;
404
- let handlerArgs;
405
- if (hasHandler) {
406
- const handler = input.handler;
407
- const name = typeof handler === "string" ? handler.trim() : this.namedHandlerNames.get(handler);
408
- if (name === undefined) {
409
- throw new ReminderValidationError("Unknown reminder handler definition (expected a default export discovered under reminders/)");
410
- }
411
- if (name === "") {
412
- throw new ReminderValidationError("handler name is required");
413
- }
414
- // A mounted extension's handler registers as `<ns>__<name>`, a name no
415
- // authored stem may take.
416
- const registered = this.namedHandlers.has(name);
417
- if (!registered && !isValidReminderHandlerName(name)) {
418
- throw new ReminderValidationError(name.includes("__")
419
- ? `Invalid reminder handler name "${name}": may not contain "__" (reserved for mounted extensions' <ns>__<name> handlers)`
420
- : `Invalid reminder handler name "${name}": must match ${NAME_PATTERN}`);
421
- }
422
- if (!registered) {
423
- throw new ReminderValidationError(`Unknown reminder handler "${name}" (expected reminders/${name}.ts under the project root)`);
424
- }
425
- if (input.args !== undefined && !isJsonObject(input.args)) {
426
- throw new ReminderValidationError("reminders.create args must be a JSON object");
427
- }
428
- handlerName = name;
429
- handlerArgs = (_a = input.args) !== null && _a !== void 0 ? _a : {};
430
- assertReminderArgsSize(handlerArgs);
431
- }
432
- else if (input.args !== undefined) {
433
- throw new ReminderValidationError("reminders.create args is only valid with handler");
434
- }
435
- const schedule = resolveSchedule(input);
436
- const busyPolicy = (_b = input.busyPolicy) !== null && _b !== void 0 ? _b : defaultBusyPolicy(schedule.kind);
437
- const hasRunHandler = input.run !== undefined;
438
- const hasUntilFn = untilFn !== undefined;
439
- let record;
440
- if (this.usesControlPlaneProtocol) {
441
- const intent = {
442
- protocolVersion: REMINDER_CP_PROTOCOL_VERSION,
443
- purpose: input.purpose,
444
- channelId: input.channelId,
445
- continuationToken: input.continuationToken,
446
- target: input.target,
447
- // CP recalculates nextFireAtMs / intervalMs from the raw schedule.
448
- schedule: scheduleSpecFromCreateInput(input),
449
- prompt: input.prompt,
450
- handler: handlerName,
451
- args: handlerArgs,
452
- hasRunHandler,
453
- hasUntilFn,
454
- untilPrompt,
455
- busyPolicy,
456
- };
457
- record = yield this.controlPlane.createReminder(intent);
458
- this.records.set(record.id, record);
459
- }
460
- else {
461
- const now = new Date().toISOString();
462
- const id = newReminderId();
463
- record = {
464
- version: 1,
465
- id,
466
- purpose: input.purpose,
467
- channelId: input.channelId,
468
- continuationToken: input.continuationToken,
469
- target: input.target,
470
- scheduleKind: schedule.kind,
471
- scheduleValue: schedule.value,
472
- intervalMs: schedule.intervalMs,
473
- prompt: input.prompt,
474
- handler: handlerName,
475
- args: handlerArgs,
476
- hasRunHandler,
477
- hasUntilFn,
478
- untilPrompt,
479
- busyPolicy,
480
- status: "armed",
481
- fireCount: 0,
482
- nextFireAtMs: schedule.nextFireAtMs,
483
- generation: 0,
484
- createdAt: now,
485
- updatedAt: now,
486
- };
487
- yield this.persist(record);
351
+ async create(input) {
352
+ const hasPrompt = input.prompt !== undefined;
353
+ const hasRun = input.run !== undefined;
354
+ const hasHandler = input.handler !== undefined;
355
+ const formCount = [hasPrompt, hasRun, hasHandler].filter(Boolean).length;
356
+ if (formCount !== 1) {
357
+ throw new ReminderValidationError("reminders.create requires exactly one of prompt, handler, or run");
358
+ }
359
+ if (input.continuationToken.trim() === "") {
360
+ throw new ReminderValidationError("continuationToken is required");
361
+ }
362
+ if (input.channelId.trim() === "") {
363
+ throw new ReminderValidationError("channelId is required");
364
+ }
365
+ if (input.purpose.trim() === "") {
366
+ throw new ReminderValidationError("purpose is required");
367
+ }
368
+ const untilPrompt = typeof input.until === "string" ? input.until : undefined;
369
+ const untilFn = typeof input.until === "function" ? input.until : undefined;
370
+ if (hasHandler && input.until !== undefined) {
371
+ throw new ReminderValidationError("reminders.create: until is not valid with handler; encode the stop condition in args and the handler body");
372
+ }
373
+ if (this.rejectAnonymousHandlers) {
374
+ if (hasRun) {
375
+ throw new ReminderValidationError("reminders.create: anonymous run handlers are not durable on architecture v2; author reminders/<name>.ts under the project root and pass handler + args");
488
376
  }
489
- this.handlers.set(record.id, {
490
- run: input.run,
491
- untilFn,
492
- });
493
- if (this.started && this.platformTimers === undefined && !this.usesControlPlaneProtocol) {
494
- this.armTimer(record);
377
+ if (untilFn !== undefined) {
378
+ throw new ReminderValidationError("reminders.create: function until is not durable on architecture v2; use a string until prompt");
495
379
  }
496
- return toInfo(record);
380
+ }
381
+ let handlerName;
382
+ let handlerArgs;
383
+ if (hasHandler) {
384
+ const handler = input.handler;
385
+ const name = typeof handler === "string" ? handler.trim() : this.namedHandlerNames.get(handler);
386
+ if (name === undefined) {
387
+ throw new ReminderValidationError("Unknown reminder handler definition (expected a default export discovered under reminders/)");
388
+ }
389
+ if (name === "") {
390
+ throw new ReminderValidationError("handler name is required");
391
+ }
392
+ // A mounted extension's handler registers as `<ns>__<name>`, a name no
393
+ // authored stem may take.
394
+ const registered = this.namedHandlers.has(name);
395
+ if (!registered && !isValidReminderHandlerName(name)) {
396
+ throw new ReminderValidationError(name.includes("__")
397
+ ? `Invalid reminder handler name "${name}": may not contain "__" (reserved for mounted extensions' <ns>__<name> handlers)`
398
+ : `Invalid reminder handler name "${name}": must match ${NAME_PATTERN}`);
399
+ }
400
+ if (!registered) {
401
+ throw new ReminderValidationError(`Unknown reminder handler "${name}" (expected reminders/${name}.ts under the project root)`);
402
+ }
403
+ if (input.args !== undefined && !isJsonObject(input.args)) {
404
+ throw new ReminderValidationError("reminders.create args must be a JSON object");
405
+ }
406
+ handlerName = name;
407
+ handlerArgs = input.args ?? {};
408
+ assertReminderArgsSize(handlerArgs);
409
+ }
410
+ else if (input.args !== undefined) {
411
+ throw new ReminderValidationError("reminders.create args is only valid with handler");
412
+ }
413
+ const schedule = resolveSchedule(input);
414
+ const busyPolicy = input.busyPolicy ?? defaultBusyPolicy(schedule.kind);
415
+ const hasRunHandler = input.run !== undefined;
416
+ const hasUntilFn = untilFn !== undefined;
417
+ let record;
418
+ if (this.usesControlPlaneProtocol) {
419
+ const intent = {
420
+ protocolVersion: REMINDER_CP_PROTOCOL_VERSION,
421
+ purpose: input.purpose,
422
+ channelId: input.channelId,
423
+ continuationToken: input.continuationToken,
424
+ target: input.target,
425
+ // CP recalculates nextFireAtMs / intervalMs from the raw schedule.
426
+ schedule: scheduleSpecFromCreateInput(input),
427
+ prompt: input.prompt,
428
+ handler: handlerName,
429
+ args: handlerArgs,
430
+ hasRunHandler,
431
+ hasUntilFn,
432
+ untilPrompt,
433
+ busyPolicy,
434
+ };
435
+ record = await this.controlPlane.createReminder(intent);
436
+ this.records.set(record.id, record);
437
+ }
438
+ else {
439
+ const now = new Date().toISOString();
440
+ const id = newReminderId();
441
+ record = {
442
+ version: 1,
443
+ id,
444
+ purpose: input.purpose,
445
+ channelId: input.channelId,
446
+ continuationToken: input.continuationToken,
447
+ target: input.target,
448
+ scheduleKind: schedule.kind,
449
+ scheduleValue: schedule.value,
450
+ intervalMs: schedule.intervalMs,
451
+ prompt: input.prompt,
452
+ handler: handlerName,
453
+ args: handlerArgs,
454
+ hasRunHandler,
455
+ hasUntilFn,
456
+ untilPrompt,
457
+ busyPolicy,
458
+ status: "armed",
459
+ fireCount: 0,
460
+ nextFireAtMs: schedule.nextFireAtMs,
461
+ generation: 0,
462
+ createdAt: now,
463
+ updatedAt: now,
464
+ };
465
+ await this.persist(record);
466
+ }
467
+ this.handlers.set(record.id, {
468
+ run: input.run,
469
+ untilFn,
497
470
  });
471
+ if (this.started && this.platformTimers === undefined && !this.usesControlPlaneProtocol) {
472
+ this.armTimer(record);
473
+ }
474
+ return toInfo(record);
498
475
  }
499
- list(filter) {
500
- return __awaiter(this, void 0, void 0, function* () {
501
- const all = yield this.recordsForList(filter);
502
- return all
503
- .filter(r => {
504
- if ((filter === null || filter === void 0 ? void 0 : filter.status) !== undefined) {
505
- const publicStatus = r.status === "firing" ? "armed" : r.status;
506
- if (publicStatus !== filter.status) {
507
- return false;
508
- }
509
- }
510
- if ((filter === null || filter === void 0 ? void 0 : filter.purpose) !== undefined && r.purpose !== filter.purpose) {
511
- return false;
512
- }
513
- if ((filter === null || filter === void 0 ? void 0 : filter.continuationToken) !== undefined &&
514
- r.continuationToken !== filter.continuationToken) {
476
+ async list(filter) {
477
+ const all = await this.recordsForList(filter);
478
+ return all
479
+ .filter(r => {
480
+ if (filter?.status !== undefined) {
481
+ const publicStatus = r.status === "firing" ? "armed" : r.status;
482
+ if (publicStatus !== filter.status) {
515
483
  return false;
516
484
  }
517
- return true;
518
- })
519
- .map(r => {
520
- const live = this.handlers.get(r.id);
521
- const info = toInfo(r);
522
- if (live === undefined)
523
- return info;
524
- return Object.assign(Object.assign({}, info), { hasRunHandler: live.run !== undefined || info.hasRunHandler, hasUntilFn: live.untilFn !== undefined || info.hasUntilFn });
525
- });
485
+ }
486
+ if (filter?.purpose !== undefined && r.purpose !== filter.purpose) {
487
+ return false;
488
+ }
489
+ if (filter?.continuationToken !== undefined &&
490
+ r.continuationToken !== filter.continuationToken) {
491
+ return false;
492
+ }
493
+ return true;
494
+ })
495
+ .map(r => {
496
+ const live = this.handlers.get(r.id);
497
+ const info = toInfo(r);
498
+ if (live === undefined)
499
+ return info;
500
+ return {
501
+ ...info,
502
+ hasRunHandler: live.run !== undefined || info.hasRunHandler,
503
+ hasUntilFn: live.untilFn !== undefined || info.hasUntilFn,
504
+ };
526
505
  });
527
506
  }
528
- cancel(id_1) {
529
- return __awaiter(this, arguments, void 0, function* (id, reason = "explicit_cancel") {
530
- var _a;
531
- if (this.usesControlPlaneProtocol) {
532
- const updated = yield this.controlPlane.cancelReminder(id, reason);
533
- if (updated === undefined) {
534
- this.records.delete(id);
535
- this.handlers.delete(id);
536
- return undefined;
537
- }
538
- this.records.set(id, updated);
507
+ async cancel(id, reason = "explicit_cancel") {
508
+ if (this.usesControlPlaneProtocol) {
509
+ const updated = await this.controlPlane.cancelReminder(id, reason);
510
+ if (updated === undefined) {
511
+ this.records.delete(id);
539
512
  this.handlers.delete(id);
540
- return toInfo(updated);
541
- }
542
- const record = yield this.getRecord(id);
543
- if (record === undefined) {
544
513
  return undefined;
545
514
  }
546
- if (record.status !== "armed" && record.status !== "firing") {
547
- return toInfo(record);
548
- }
549
- this.clearTimer(id);
550
- const updated = Object.assign(Object.assign({}, record), { status: "cancelled", disarmReason: reason, generation: ((_a = record.generation) !== null && _a !== void 0 ? _a : 0) + 1, updatedAt: new Date().toISOString() });
551
- yield this.persist(updated);
515
+ this.records.set(id, updated);
552
516
  this.handlers.delete(id);
553
517
  return toInfo(updated);
554
- });
518
+ }
519
+ const record = await this.getRecord(id);
520
+ if (record === undefined) {
521
+ return undefined;
522
+ }
523
+ if (record.status !== "armed" && record.status !== "firing") {
524
+ return toInfo(record);
525
+ }
526
+ this.clearTimer(id);
527
+ const updated = {
528
+ ...record,
529
+ status: "cancelled",
530
+ disarmReason: reason,
531
+ generation: (record.generation ?? 0) + 1,
532
+ updatedAt: new Date().toISOString(),
533
+ };
534
+ await this.persist(updated);
535
+ this.handlers.delete(id);
536
+ return toInfo(updated);
555
537
  }
556
538
  /** Cancel all armed reminders matching a continuation token (e.g. PR closed). */
557
- cancelForContinuation(continuationToken, reason) {
558
- return __awaiter(this, void 0, void 0, function* () {
559
- const armed = (yield this.allRecords()).filter(r => r.status === "armed");
560
- let n = 0;
561
- for (const record of armed) {
562
- if (record.continuationToken === continuationToken) {
563
- yield this.cancel(record.id, reason);
564
- n += 1;
565
- }
539
+ async cancelForContinuation(continuationToken, reason) {
540
+ const armed = (await this.allRecords()).filter(r => r.status === "armed");
541
+ let n = 0;
542
+ for (const record of armed) {
543
+ if (record.continuationToken === continuationToken) {
544
+ await this.cancel(record.id, reason);
545
+ n += 1;
566
546
  }
567
- return n;
568
- });
547
+ }
548
+ return n;
569
549
  }
570
550
  /**
571
551
  * Re-key armed reminders when a channel rotates a session's continuation
@@ -573,142 +553,137 @@ export class ReminderRunner {
573
553
  * this, a reminder armed before the rotation misses its session at fire
574
554
  * time and disarms as `session_gone`.
575
555
  */
576
- rekeyContinuation(channelId, oldToken, newToken) {
577
- return __awaiter(this, void 0, void 0, function* () {
578
- var _a;
579
- if (this.usesControlPlaneProtocol) {
580
- return this.controlPlane.rekeyReminders(channelId, oldToken, newToken);
581
- }
582
- const armed = (yield this.allRecords()).filter(r => r.status === "armed" || r.status === "firing");
583
- let n = 0;
584
- for (const record of armed) {
585
- if (record.channelId !== channelId || record.continuationToken !== oldToken) {
586
- continue;
587
- }
588
- yield this.persist(Object.assign(Object.assign({}, record), { continuationToken: newToken, generation: ((_a = record.generation) !== null && _a !== void 0 ? _a : 0) + 1, updatedAt: new Date().toISOString() }));
589
- n += 1;
590
- }
591
- return n;
592
- });
556
+ async rekeyContinuation(channelId, oldToken, newToken) {
557
+ if (this.usesControlPlaneProtocol) {
558
+ return this.controlPlane.rekeyReminders(channelId, oldToken, newToken);
559
+ }
560
+ const armed = (await this.allRecords()).filter(r => r.status === "armed" || r.status === "firing");
561
+ let n = 0;
562
+ for (const record of armed) {
563
+ if (record.channelId !== channelId || record.continuationToken !== oldToken) {
564
+ continue;
565
+ }
566
+ await this.persist({
567
+ ...record,
568
+ continuationToken: newToken,
569
+ generation: (record.generation ?? 0) + 1,
570
+ updatedAt: new Date().toISOString(),
571
+ });
572
+ n += 1;
573
+ }
574
+ return n;
593
575
  }
594
576
  /** Fire one reminder immediately (dev / hillclimb / control plane). */
595
- dispatch(reminderId_1) {
596
- return __awaiter(this, arguments, void 0, function* (reminderId, opts = {}) {
597
- const record = yield this.getRecord(reminderId);
598
- if (record === undefined) {
599
- const ids = (yield this.allRecords()).map(r => r.id);
600
- throw new UnknownReminderError(reminderId, ids);
601
- }
602
- if (opts.expectedFireCount !== undefined && record.fireCount !== opts.expectedFireCount) {
603
- return {
604
- reminderId,
605
- outcome: "noop",
606
- reason: "stale_fire_count",
607
- };
608
- }
609
- const result = yield this.fire(record.id, { force: true });
610
- return Object.assign({ reminderId }, result);
611
- });
577
+ async dispatch(reminderId, opts = {}) {
578
+ const record = await this.getRecord(reminderId);
579
+ if (record === undefined) {
580
+ const ids = (await this.allRecords()).map(r => r.id);
581
+ throw new UnknownReminderError(reminderId, ids);
582
+ }
583
+ if (opts.expectedFireCount !== undefined && record.fireCount !== opts.expectedFireCount) {
584
+ return {
585
+ reminderId,
586
+ outcome: "noop",
587
+ reason: "stale_fire_count",
588
+ };
589
+ }
590
+ const result = await this.fire(record.id, { force: true });
591
+ return { reminderId, ...result };
612
592
  }
613
593
  /**
614
594
  * Architecture v2 / CP protocol guest entrypoint: execute an immutable fire
615
595
  * descriptor and return an outcome. Does not mint ids or mutate
616
596
  * authoritative status/fireCount — the control plane applies the outcome.
617
597
  */
618
- executeFire(descriptor) {
619
- return __awaiter(this, void 0, void 0, function* () {
620
- const record = this.recordFromDescriptor(descriptor);
621
- this.records.set(record.id, record);
622
- let fire;
623
- try {
624
- fire = yield this.runFire(record);
625
- }
626
- catch (error) {
627
- // The hosted admission maps the throw to a retryable failure; count
628
- // it so the retry loop is visible beside the settled outcomes.
629
- this.recordFireOutcome(record, {
630
- kind: "error",
631
- reason: "fire_threw",
632
- detail: error instanceof Error ? error.message : String(error),
633
- });
634
- throw error;
635
- }
598
+ async executeFire(descriptor) {
599
+ const record = this.recordFromDescriptor(descriptor);
600
+ this.records.set(record.id, record);
601
+ let fire;
602
+ try {
603
+ fire = await this.runFire(record);
604
+ }
605
+ catch (error) {
606
+ // The hosted admission maps the throw to a retryable failure; count
607
+ // it so the retry loop is visible beside the settled outcomes.
636
608
  this.recordFireOutcome(record, {
637
- kind: fire.outcome.kind,
638
- reason: fire.reason,
639
- turnStatus: fire.turnStatus,
609
+ kind: "error",
610
+ reason: "fire_threw",
611
+ detail: error instanceof Error ? error.message : String(error),
640
612
  });
641
- return fire.outcome;
613
+ throw error;
614
+ }
615
+ this.recordFireOutcome(record, {
616
+ kind: fire.outcome.kind,
617
+ reason: fire.reason,
618
+ turnStatus: fire.turnStatus,
642
619
  });
620
+ return fire.outcome;
643
621
  }
644
- runFire(record) {
645
- return __awaiter(this, void 0, void 0, function* () {
646
- var _a;
647
- const live = (_a = this.handlers.get(record.id)) !== null && _a !== void 0 ? _a : {};
648
- if (record.handler !== undefined) {
649
- if (this.resolveNamedHandler(record.handler) === undefined) {
650
- return stopFire("handler_missing");
651
- }
652
- }
653
- else if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
654
- live.run === undefined &&
655
- live.untilFn === undefined) {
656
- return stopFire("handler_lost_on_restart");
657
- }
658
- if (live.untilFn !== undefined) {
659
- try {
660
- const done = yield live.untilFn(this.buildUntilContext(record));
661
- if (done) {
662
- return stopFire("until_fn");
663
- }
664
- }
665
- catch (error) {
666
- this.logger(`[bdk] reminder "${record.id}" until() failed: ${error instanceof Error ? error.message : String(error)}`);
667
- }
668
- }
669
- if (yield this.isSessionBusy(record.channelId, record.continuationToken)) {
670
- if (record.busyPolicy === "skipIfBusy") {
671
- return { outcome: { kind: "skipped" }, reason: "busy" };
672
- }
673
- yield this.whenSessionIdle(record.channelId, record.continuationToken);
622
+ async runFire(record) {
623
+ const live = this.handlers.get(record.id) ?? {};
624
+ if (record.handler !== undefined) {
625
+ if (this.resolveNamedHandler(record.handler) === undefined) {
626
+ return stopFire("handler_missing");
674
627
  }
675
- let result;
676
- let reason;
677
- let turnStatus;
678
- if (record.handler !== undefined) {
679
- const named = this.resolveNamedHandler(record.handler);
680
- if (named === undefined) {
681
- return stopFire("handler_missing");
628
+ }
629
+ else if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
630
+ live.run === undefined &&
631
+ live.untilFn === undefined) {
632
+ return stopFire("handler_lost_on_restart");
633
+ }
634
+ if (live.untilFn !== undefined) {
635
+ try {
636
+ const done = await live.untilFn(this.buildUntilContext(record));
637
+ if (done) {
638
+ return stopFire("until_fn");
682
639
  }
683
- result = yield named.run(this.buildFireContext(record));
684
- reason = runReason(result);
685
- }
686
- else if (live.run !== undefined) {
687
- result = yield live.run(this.buildFireContext(record));
688
- reason = runReason(result);
689
- }
690
- else if (record.prompt !== undefined) {
691
- const delivery = yield this.deliverPromptFire(record);
692
- result = delivery.result;
693
- reason = delivery.reason;
694
- turnStatus = delivery.turnStatus;
695
640
  }
696
- else {
697
- return stopFire("missing_handler");
641
+ catch (error) {
642
+ this.logger(`[bdk] reminder "${record.id}" until() failed: ${error instanceof Error ? error.message : String(error)}`);
698
643
  }
699
- if (result.action === "stop") {
700
- return { outcome: { kind: "stop", reason }, reason };
644
+ }
645
+ if (await this.isSessionBusy(record.channelId, record.continuationToken)) {
646
+ if (record.busyPolicy === "skipIfBusy") {
647
+ return { outcome: { kind: "skipped" }, reason: "busy" };
701
648
  }
702
- const reschedule = result.reschedule !== undefined ? toWireReschedule(result.reschedule) : undefined;
703
- return {
704
- outcome: {
705
- kind: result.action === "skip" ? "skipped" : "delivered",
706
- reschedule,
707
- },
708
- reason,
709
- turnStatus,
710
- };
711
- });
649
+ await this.whenSessionIdle(record.channelId, record.continuationToken);
650
+ }
651
+ let result;
652
+ let reason;
653
+ let turnStatus;
654
+ if (record.handler !== undefined) {
655
+ const named = this.resolveNamedHandler(record.handler);
656
+ if (named === undefined) {
657
+ return stopFire("handler_missing");
658
+ }
659
+ result = await named.run(this.buildFireContext(record));
660
+ reason = runReason(result);
661
+ }
662
+ else if (live.run !== undefined) {
663
+ result = await live.run(this.buildFireContext(record));
664
+ reason = runReason(result);
665
+ }
666
+ else if (record.prompt !== undefined) {
667
+ const delivery = await this.deliverPromptFire(record);
668
+ result = delivery.result;
669
+ reason = delivery.reason;
670
+ turnStatus = delivery.turnStatus;
671
+ }
672
+ else {
673
+ return stopFire("missing_handler");
674
+ }
675
+ if (result.action === "stop") {
676
+ return { outcome: { kind: "stop", reason }, reason };
677
+ }
678
+ const reschedule = result.reschedule !== undefined ? toWireReschedule(result.reschedule) : undefined;
679
+ return {
680
+ outcome: {
681
+ kind: result.action === "skip" ? "skipped" : "delivered",
682
+ reschedule,
683
+ },
684
+ reason,
685
+ turnStatus,
686
+ };
712
687
  }
713
688
  /**
714
689
  * One structured line and one `agent_sdk.reminder.fire_outcome` count per
@@ -766,19 +741,18 @@ export class ReminderRunner {
766
741
  };
767
742
  }
768
743
  armTimer(record) {
769
- var _a;
770
744
  this.clearTimer(record.id);
771
745
  if (!this.started || record.status !== "armed")
772
746
  return;
773
747
  const nextFireAtMs = Number.isFinite(record.nextFireAtMs) ? record.nextFireAtMs : Date.now();
774
748
  const delay = Math.min(MAX_TIMER_MS, Math.max(0, nextFireAtMs - Date.now()));
775
749
  const timer = setTimeout(() => {
776
- void this.fire(record.id).catch((error) => __awaiter(this, void 0, void 0, function* () {
750
+ void this.fire(record.id).catch(async (error) => {
777
751
  this.logger(`[bdk] reminder "${record.id}" fire failed: ${error instanceof Error ? error.message : String(error)}`);
778
752
  // Keep recurring reminders alive after unexpected throws.
779
753
  // One-shots stay armed so a failed wake can be retried / dispatched.
780
754
  try {
781
- const current = yield this.getRecord(record.id);
755
+ const current = await this.getRecord(record.id);
782
756
  if (current === undefined || current.status !== "armed")
783
757
  return;
784
758
  const oneShot = current.scheduleKind === "delay" || current.scheduleKind === "at";
@@ -786,14 +760,14 @@ export class ReminderRunner {
786
760
  this.armTimer(current);
787
761
  return;
788
762
  }
789
- yield this.afterFire(current, "skip");
763
+ await this.afterFire(current, "skip");
790
764
  }
791
765
  catch (rescheduleError) {
792
766
  this.logger(`[bdk] reminder "${record.id}" reschedule after failure failed: ${rescheduleError instanceof Error ? rescheduleError.message : String(rescheduleError)}`);
793
767
  }
794
- }));
768
+ });
795
769
  }, delay);
796
- (_a = timer.unref) === null || _a === void 0 ? void 0 : _a.call(timer);
770
+ timer.unref?.();
797
771
  this.timers.set(record.id, timer);
798
772
  }
799
773
  clearTimer(id) {
@@ -806,130 +780,125 @@ export class ReminderRunner {
806
780
  resolveNamedHandler(name) {
807
781
  return this.namedHandlers.get(name);
808
782
  }
809
- fire(id_1) {
810
- return __awaiter(this, arguments, void 0, function* (id, opts = {}) {
811
- var _a, _b;
812
- if (this.firing.has(id)) {
813
- return { outcome: "noop", reason: "already_firing" };
783
+ async fire(id, opts = {}) {
784
+ if (this.firing.has(id)) {
785
+ return { outcome: "noop", reason: "already_firing" };
786
+ }
787
+ this.firing.add(id);
788
+ try {
789
+ const record = await this.getRecord(id);
790
+ if (record === undefined || record.status !== "armed") {
791
+ this.clearTimer(id);
792
+ return { outcome: "noop", reason: "not_armed" };
814
793
  }
815
- this.firing.add(id);
816
- try {
817
- const record = yield this.getRecord(id);
818
- if (record === undefined || record.status !== "armed") {
819
- this.clearTimer(id);
820
- return { outcome: "noop", reason: "not_armed" };
821
- }
822
- if (!opts.force && record.nextFireAtMs > Date.now() + 50) {
823
- // Spurious early wake — re-arm.
824
- this.armTimer(record);
825
- return { outcome: "noop", reason: "not_due" };
826
- }
827
- const live = (_a = this.handlers.get(id)) !== null && _a !== void 0 ? _a : {};
828
- if (record.handler !== undefined) {
829
- if (this.resolveNamedHandler(record.handler) === undefined) {
830
- yield this.disarm(record, "handler_missing");
831
- return { outcome: "noop", reason: "handler_missing" };
832
- }
833
- }
834
- else if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
835
- live.run === undefined &&
836
- live.untilFn === undefined) {
837
- yield this.disarm(record, "handler_lost_on_restart");
838
- return { outcome: "noop", reason: "handler_lost_on_restart" };
839
- }
840
- const untilCtx = this.buildUntilContext(record);
841
- if (live.untilFn !== undefined) {
842
- try {
843
- const done = yield live.untilFn(untilCtx);
844
- if (done) {
845
- yield this.disarm(record, "until_fn");
846
- return { outcome: "fired", reason: "until_fn" };
847
- }
848
- }
849
- catch (error) {
850
- this.logger(`[bdk] reminder "${id}" until() failed: ${error instanceof Error ? error.message : String(error)}`);
851
- }
852
- }
853
- if (yield this.isSessionBusy(record.channelId, record.continuationToken)) {
854
- if (record.busyPolicy === "skipIfBusy") {
855
- yield this.afterFire(record, "skip");
856
- this.logger(`[bdk] reminder "${id}" (${record.purpose}) skipped: session busy`);
857
- return { outcome: "fired", reason: "skipped_busy" };
858
- }
859
- yield this.whenSessionIdle(record.channelId, record.continuationToken);
860
- const still = yield this.getRecord(id);
861
- if (still === undefined || still.status !== "armed") {
862
- return { outcome: "noop", reason: "disarmed_while_waiting" };
863
- }
794
+ if (!opts.force && record.nextFireAtMs > Date.now() + 50) {
795
+ // Spurious early wake — re-arm.
796
+ this.armTimer(record);
797
+ return { outcome: "noop", reason: "not_due" };
798
+ }
799
+ const live = this.handlers.get(id) ?? {};
800
+ if (record.handler !== undefined) {
801
+ if (this.resolveNamedHandler(record.handler) === undefined) {
802
+ await this.disarm(record, "handler_missing");
803
+ return { outcome: "noop", reason: "handler_missing" };
864
804
  }
865
- let result;
866
- if (record.handler !== undefined) {
867
- const named = this.resolveNamedHandler(record.handler);
868
- if (named === undefined) {
869
- yield this.disarm(record, "handler_missing");
870
- return { outcome: "noop", reason: "handler_missing" };
805
+ }
806
+ else if ((record.hasRunHandler === true || record.hasUntilFn === true) &&
807
+ live.run === undefined &&
808
+ live.untilFn === undefined) {
809
+ await this.disarm(record, "handler_lost_on_restart");
810
+ return { outcome: "noop", reason: "handler_lost_on_restart" };
811
+ }
812
+ const untilCtx = this.buildUntilContext(record);
813
+ if (live.untilFn !== undefined) {
814
+ try {
815
+ const done = await live.untilFn(untilCtx);
816
+ if (done) {
817
+ await this.disarm(record, "until_fn");
818
+ return { outcome: "fired", reason: "until_fn" };
871
819
  }
872
- result = yield named.run(this.buildFireContext(record));
873
- }
874
- else if (live.run !== undefined) {
875
- result = yield live.run(this.buildFireContext(record));
876
820
  }
877
- else if (record.prompt !== undefined) {
878
- result = yield this.deliverPrompt(record);
821
+ catch (error) {
822
+ this.logger(`[bdk] reminder "${id}" until() failed: ${error instanceof Error ? error.message : String(error)}`);
879
823
  }
880
- else {
881
- yield this.disarm(record, "missing_handler");
882
- return { outcome: "noop", reason: "missing_handler" };
824
+ }
825
+ if (await this.isSessionBusy(record.channelId, record.continuationToken)) {
826
+ if (record.busyPolicy === "skipIfBusy") {
827
+ await this.afterFire(record, "skip");
828
+ this.logger(`[bdk] reminder "${id}" (${record.purpose}) skipped: session busy`);
829
+ return { outcome: "fired", reason: "skipped_busy" };
883
830
  }
884
- // Cancel / disarm during the handler must win over reschedule.
885
- const latest = yield this.getRecord(id);
886
- if (result.action === "stop") {
887
- if (latest !== undefined && latest.status === "armed") {
888
- yield this.disarm(latest, "run_stop");
889
- this.logger(`[bdk] reminder "${id}" (${record.purpose}) disarmed: run_stop`);
890
- return { outcome: "fired", reason: "run_stop" };
891
- }
892
- return {
893
- outcome: "fired",
894
- reason: (_b = latest === null || latest === void 0 ? void 0 : latest.disarmReason) !== null && _b !== void 0 ? _b : "run_stop",
895
- };
831
+ await this.whenSessionIdle(record.channelId, record.continuationToken);
832
+ const still = await this.getRecord(id);
833
+ if (still === undefined || still.status !== "armed") {
834
+ return { outcome: "noop", reason: "disarmed_while_waiting" };
896
835
  }
897
- if (latest === undefined || latest.status !== "armed") {
898
- return { outcome: "noop", reason: "disarmed_during_fire" };
836
+ }
837
+ let result;
838
+ if (record.handler !== undefined) {
839
+ const named = this.resolveNamedHandler(record.handler);
840
+ if (named === undefined) {
841
+ await this.disarm(record, "handler_missing");
842
+ return { outcome: "noop", reason: "handler_missing" };
899
843
  }
900
- if (result.action === "skip") {
901
- yield this.afterFire(latest, "skip", result.reschedule);
902
- this.logger(`[bdk] reminder "${id}" (${record.purpose}) skipped`);
903
- return { outcome: "fired", reason: "skipped" };
844
+ result = await named.run(this.buildFireContext(record));
845
+ }
846
+ else if (live.run !== undefined) {
847
+ result = await live.run(this.buildFireContext(record));
848
+ }
849
+ else if (record.prompt !== undefined) {
850
+ result = await this.deliverPrompt(record);
851
+ }
852
+ else {
853
+ await this.disarm(record, "missing_handler");
854
+ return { outcome: "noop", reason: "missing_handler" };
855
+ }
856
+ // Cancel / disarm during the handler must win over reschedule.
857
+ const latest = await this.getRecord(id);
858
+ if (result.action === "stop") {
859
+ if (latest !== undefined && latest.status === "armed") {
860
+ await this.disarm(latest, "run_stop");
861
+ this.logger(`[bdk] reminder "${id}" (${record.purpose}) disarmed: run_stop`);
862
+ return { outcome: "fired", reason: "run_stop" };
904
863
  }
905
- yield this.afterFire(latest, "delivered", result.reschedule);
906
- this.logger(`[bdk] reminder "${id}" (${record.purpose}) fired`);
907
- return { outcome: "fired", reason: "delivered" };
864
+ return {
865
+ outcome: "fired",
866
+ reason: latest?.disarmReason ?? "run_stop",
867
+ };
908
868
  }
909
- finally {
910
- this.firing.delete(id);
869
+ if (latest === undefined || latest.status !== "armed") {
870
+ return { outcome: "noop", reason: "disarmed_during_fire" };
911
871
  }
912
- });
872
+ if (result.action === "skip") {
873
+ await this.afterFire(latest, "skip", result.reschedule);
874
+ this.logger(`[bdk] reminder "${id}" (${record.purpose}) skipped`);
875
+ return { outcome: "fired", reason: "skipped" };
876
+ }
877
+ await this.afterFire(latest, "delivered", result.reschedule);
878
+ this.logger(`[bdk] reminder "${id}" (${record.purpose}) fired`);
879
+ return { outcome: "fired", reason: "delivered" };
880
+ }
881
+ finally {
882
+ this.firing.delete(id);
883
+ }
913
884
  }
914
- isSessionBusy(channelId, continuationToken) {
915
- return __awaiter(this, void 0, void 0, function* () {
916
- const existing = yield this.engine.sessions.findByContinuation(channelId, continuationToken);
917
- if (existing === undefined)
918
- return false;
919
- return this.engine.isTurnRunning(existing.sessionId);
920
- });
885
+ async isSessionBusy(channelId, continuationToken) {
886
+ const existing = await this.engine.sessions.findByContinuation(channelId, continuationToken);
887
+ if (existing === undefined)
888
+ return false;
889
+ return this.engine.isTurnRunning(existing.sessionId);
921
890
  }
922
891
  whenSessionIdle(channelId, continuationToken) {
923
892
  const sessionKey = `${channelId}:${continuationToken}`;
924
893
  const existing = this.idleGates.get(sessionKey);
925
894
  if (existing !== undefined)
926
895
  return existing;
927
- const gate = (() => __awaiter(this, void 0, void 0, function* () {
928
- const session = yield this.engine.sessions.findByContinuation(channelId, continuationToken);
896
+ const gate = (async () => {
897
+ const session = await this.engine.sessions.findByContinuation(channelId, continuationToken);
929
898
  if (session === undefined)
930
899
  return;
931
- yield this.engine.waitForCompletion(session.sessionId);
932
- }))().finally(() => {
900
+ await this.engine.waitForCompletion(session.sessionId);
901
+ })().finally(() => {
933
902
  this.idleGates.delete(sessionKey);
934
903
  });
935
904
  this.idleGates.set(sessionKey, gate);
@@ -942,10 +911,8 @@ export class ReminderRunner {
942
911
  boundSession(record) {
943
912
  return this.engine.sessions.findByContinuation(record.channelId, record.continuationToken);
944
913
  }
945
- deliverPrompt(record) {
946
- return __awaiter(this, void 0, void 0, function* () {
947
- return (yield this.deliverPromptFire(record)).result;
948
- });
914
+ async deliverPrompt(record) {
915
+ return (await this.deliverPromptFire(record)).result;
949
916
  }
950
917
  /**
951
918
  * Where a prompt fire joins. The pod's own store first; on a hosted guest
@@ -954,85 +921,78 @@ export class ReminderRunner {
954
921
  * keeps its own principal (channel admissions may carry a sender), so the
955
922
  * fire joins under that, never under {@link ReminderHostedGuestOptions.fireAuth}.
956
923
  */
957
- resolveFollowupTarget(record) {
958
- return __awaiter(this, void 0, void 0, function* () {
959
- const local = yield this.boundSession(record);
960
- if (local !== undefined) {
961
- return { auth: local.auth, sessionId: local.sessionId, reached: "session_joined" };
962
- }
963
- if (this.hostedGuest === undefined) {
964
- return { auth: undefined, reached: "session_gone" };
965
- }
966
- // Materializes the durable record locally; a storage error propagates
967
- // and the hosted admission retries the fire.
968
- const restored = yield this.engine.hasContinuationSession(record.channelId, record.continuationToken);
969
- if (!restored) {
970
- return { auth: undefined, reached: "session_gone" };
971
- }
972
- const session = yield this.boundSession(record);
973
- return session === undefined
974
- ? { auth: undefined, reached: "session_unreadable" }
975
- : { auth: session.auth, sessionId: session.sessionId, reached: "session_restored" };
976
- });
924
+ async resolveFollowupTarget(record) {
925
+ const local = await this.boundSession(record);
926
+ if (local !== undefined) {
927
+ return { auth: local.auth, sessionId: local.sessionId, reached: "session_joined" };
928
+ }
929
+ if (this.hostedGuest === undefined) {
930
+ return { auth: undefined, reached: "session_gone" };
931
+ }
932
+ // Materializes the durable record locally; a storage error propagates
933
+ // and the hosted admission retries the fire.
934
+ const restored = await this.engine.hasContinuationSession(record.channelId, record.continuationToken);
935
+ if (!restored) {
936
+ return { auth: undefined, reached: "session_gone" };
937
+ }
938
+ const session = await this.boundSession(record);
939
+ return session === undefined
940
+ ? { auth: undefined, reached: "session_unreadable" }
941
+ : { auth: session.auth, sessionId: session.sessionId, reached: "session_restored" };
977
942
  }
978
- deliverPromptFire(record) {
979
- return __awaiter(this, void 0, void 0, function* () {
980
- const target = yield this.resolveFollowupTarget(record);
981
- if (target.auth !== undefined) {
982
- return this.promptDelivery(record, target, target.reached);
943
+ async deliverPromptFire(record) {
944
+ const target = await this.resolveFollowupTarget(record);
945
+ if (target.auth !== undefined) {
946
+ return this.promptDelivery(record, target, target.reached);
947
+ }
948
+ if (target.reached === "session_unreadable") {
949
+ this.logger(`[bdk] reminder "${record.id}" (${record.purpose}) durable session did not materialize locally; not opening a new one`);
950
+ return { result: { action: "stop" }, reason: "session_gone" };
951
+ }
952
+ if (this.hostedGuest !== undefined &&
953
+ this.channelUsesControlPlaneContinuation(record.channelId)) {
954
+ // No session on this pod and none in durable storage. Open one on the
955
+ // stored key the way an inbound event on a fresh key does, instead of
956
+ // consuming the fire with no turn.
957
+ const fireAuth = this.hostedGuest.fireAuth();
958
+ if (fireAuth === undefined) {
959
+ return {
960
+ result: {
961
+ action: "skip",
962
+ reschedule: { delay: REMINDER_SESSION_OPEN_RETRY_DELAY },
963
+ },
964
+ reason: "session_gone",
965
+ };
983
966
  }
984
- if (target.reached === "session_unreadable") {
985
- this.logger(`[bdk] reminder "${record.id}" (${record.purpose}) durable session did not materialize locally; not opening a new one`);
986
- return { result: { action: "stop" }, reason: "session_gone" };
967
+ try {
968
+ return await this.promptDelivery(record, { auth: fireAuth }, "session_opened");
987
969
  }
988
- if (this.hostedGuest !== undefined &&
989
- this.channelUsesControlPlaneContinuation(record.channelId)) {
990
- // No session on this pod and none in durable storage. Open one on the
991
- // stored key the way an inbound event on a fresh key does, instead of
992
- // consuming the fire with no turn.
993
- const fireAuth = this.hostedGuest.fireAuth();
994
- if (fireAuth === undefined) {
995
- return {
996
- result: {
997
- action: "skip",
998
- reschedule: { delay: REMINDER_SESSION_OPEN_RETRY_DELAY },
999
- },
1000
- reason: "session_gone",
1001
- };
1002
- }
1003
- try {
1004
- return yield this.promptDelivery(record, { auth: fireAuth }, "session_opened");
1005
- }
1006
- catch (error) {
1007
- if (!(error instanceof SessionAuthError)) {
1008
- throw error;
1009
- }
1010
- // A session landed on this key under another principal between the
1011
- // lookup and the send. That does not change on retry, so stop
1012
- // rather than let the control plane re-admit until its attempt cap.
1013
- this.logger(`[bdk] reminder "${record.id}" (${record.purpose}) cannot join session on its continuation: ${error.message}`);
1014
- return { result: { action: "stop" }, reason: "session_gone" };
970
+ catch (error) {
971
+ if (!(error instanceof SessionAuthError)) {
972
+ throw error;
1015
973
  }
974
+ // A session landed on this key under another principal between the
975
+ // lookup and the send. That does not change on retry, so stop
976
+ // rather than let the control plane re-admit until its attempt cap.
977
+ this.logger(`[bdk] reminder "${record.id}" (${record.purpose}) cannot join session on its continuation: ${error.message}`);
978
+ return { result: { action: "stop" }, reason: "session_gone" };
1016
979
  }
1017
- // Under CP protocol, return stop and let the CP apply/CAS; do not
1018
- // mutate authoritative status from the guest mid-fire.
1019
- if (!this.usesControlPlaneProtocol) {
1020
- yield this.disarm(record, "session_gone");
1021
- }
1022
- return { result: { action: "stop" }, reason: "session_gone" };
1023
- });
980
+ }
981
+ // Under CP protocol, return stop and let the CP apply/CAS; do not
982
+ // mutate authoritative status from the guest mid-fire.
983
+ if (!this.usesControlPlaneProtocol) {
984
+ await this.disarm(record, "session_gone");
985
+ }
986
+ return { result: { action: "stop" }, reason: "session_gone" };
1024
987
  }
1025
- promptDelivery(record, address, delivered) {
1026
- return __awaiter(this, void 0, void 0, function* () {
1027
- var _a;
1028
- const settle = {};
1029
- const result = yield this.sendFollowup(record, buildFirePrompt(record), address, settle);
1030
- return {
1031
- result,
1032
- reason: result.action === "skip" ? ((_a = settle.skipReason) !== null && _a !== void 0 ? _a : "busy") : delivered,
1033
- turnStatus: settle.turnStatus,
1034
- };
1035
- });
988
+ async promptDelivery(record, address, delivered) {
989
+ const settle = {};
990
+ const result = await this.sendFollowup(record, buildFirePrompt(record), address, settle);
991
+ return {
992
+ result,
993
+ reason: result.action === "skip" ? (settle.skipReason ?? "busy") : delivered,
994
+ turnStatus: settle.turnStatus,
995
+ };
1036
996
  }
1037
997
  /**
1038
998
  * Join the reminder's existing session. Control-plane (`/v2`) channels
@@ -1045,9 +1005,13 @@ export class ReminderRunner {
1045
1005
  followupSendOptions(record, address) {
1046
1006
  const { auth, sessionId } = address;
1047
1007
  if (this.channelUsesControlPlaneContinuation(record.channelId)) {
1048
- return Object.assign({ auth, mailboxContinuation: { key: record.continuationToken } }, (sessionId !== undefined && isOneShotContinuationKey(record.continuationToken)
1049
- ? { hostedSessionId: sessionId }
1050
- : {}));
1008
+ return {
1009
+ auth,
1010
+ mailboxContinuation: { key: record.continuationToken },
1011
+ ...(sessionId !== undefined && isOneShotContinuationKey(record.continuationToken)
1012
+ ? { hostedSessionId: sessionId }
1013
+ : {}),
1014
+ };
1051
1015
  }
1052
1016
  return {
1053
1017
  auth,
@@ -1055,7 +1019,6 @@ export class ReminderRunner {
1055
1019
  };
1056
1020
  }
1057
1021
  channelUsesControlPlaneContinuation(channelId) {
1058
- var _a;
1059
1022
  const project = this.engine.project;
1060
1023
  // Test doubles may omit `project`; keep the legacy continuationToken path.
1061
1024
  if (project === undefined) {
@@ -1063,7 +1026,7 @@ export class ReminderRunner {
1063
1026
  }
1064
1027
  const identity = channelId === HTTP_CHANNEL_ID
1065
1028
  ? httpContinuationIdentity(project.httpChannel)
1066
- : channelContinuationIdentity((_a = project.channels.find(channel => channel.id === channelId)) === null || _a === void 0 ? void 0 : _a.definition);
1029
+ : channelContinuationIdentity(project.channels.find(channel => channel.id === channelId)?.definition);
1067
1030
  return continuationSource(identity) === "control-plane";
1068
1031
  }
1069
1032
  /**
@@ -1072,185 +1035,207 @@ export class ReminderRunner {
1072
1035
  * because the control plane may stop the pod as soon as the fire's
1073
1036
  * outcome is applied, and `delivered` must mean the turn ran.
1074
1037
  */
1075
- settleFollowup(session, settle) {
1076
- return __awaiter(this, void 0, void 0, function* () {
1077
- const completion = this.engine.waitForCompletion(session.id);
1078
- if (this.hostedGuest === undefined) {
1079
- this.engine.trackBackground(completion);
1080
- return;
1081
- }
1082
- const outcome = yield completion;
1083
- yield this.engine.drainSessionDurability(session.id);
1084
- if (settle !== undefined) {
1085
- settle.turnStatus = outcome.status;
1086
- }
1087
- });
1038
+ async settleFollowup(session, settle) {
1039
+ const completion = this.engine.waitForCompletion(session.id);
1040
+ if (this.hostedGuest === undefined) {
1041
+ this.engine.trackBackground(completion);
1042
+ return;
1043
+ }
1044
+ const outcome = await completion;
1045
+ await this.engine.drainSessionDurability(session.id);
1046
+ if (settle !== undefined) {
1047
+ settle.turnStatus = outcome.status;
1048
+ }
1088
1049
  }
1089
- sendFollowup(record, message, address, settle, extra) {
1090
- return __awaiter(this, void 0, void 0, function* () {
1091
- const sendOptions = Object.assign(Object.assign({}, this.followupSendOptions(record, address)), { state: extra === null || extra === void 0 ? void 0 : extra.state, refreshState: extra === null || extra === void 0 ? void 0 : extra.refreshState, title: extra === null || extra === void 0 ? void 0 : extra.title, clearCloudOverride: extra === null || extra === void 0 ? void 0 : extra.clearCloudOverride });
1092
- try {
1093
- const session = yield this.engine.send(record.channelId, message, sendOptions);
1094
- yield this.settleFollowup(session, settle);
1095
- return { action: "delivered" };
1096
- }
1097
- catch (error) {
1098
- if (error instanceof SessionBusyError) {
1099
- if (record.busyPolicy === "skipIfBusy") {
1100
- if (settle !== undefined) {
1101
- settle.skipReason = "busy";
1102
- }
1103
- return { action: "skip" };
1104
- }
1105
- yield this.whenSessionIdle(record.channelId, record.continuationToken);
1106
- try {
1107
- const session = yield this.engine.send(record.channelId, message, sendOptions);
1108
- yield this.settleFollowup(session, settle);
1109
- return { action: "delivered" };
1050
+ async sendFollowup(record, message, address, settle, extra) {
1051
+ const sendOptions = {
1052
+ ...this.followupSendOptions(record, address),
1053
+ state: extra?.state,
1054
+ refreshState: extra?.refreshState,
1055
+ title: extra?.title,
1056
+ clearCloudOverride: extra?.clearCloudOverride,
1057
+ };
1058
+ try {
1059
+ const session = await this.engine.send(record.channelId, message, sendOptions);
1060
+ await this.settleFollowup(session, settle);
1061
+ return { action: "delivered" };
1062
+ }
1063
+ catch (error) {
1064
+ if (error instanceof SessionBusyError) {
1065
+ if (record.busyPolicy === "skipIfBusy") {
1066
+ if (settle !== undefined) {
1067
+ settle.skipReason = "busy";
1110
1068
  }
1111
- catch (retryError) {
1112
- this.logger(`[bdk] reminder "${record.id}" followup failed after wait: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
1113
- if (settle !== undefined) {
1114
- settle.skipReason = "followup_failed";
1115
- }
1116
- return { action: "skip" };
1069
+ return { action: "skip" };
1070
+ }
1071
+ await this.whenSessionIdle(record.channelId, record.continuationToken);
1072
+ try {
1073
+ const session = await this.engine.send(record.channelId, message, sendOptions);
1074
+ await this.settleFollowup(session, settle);
1075
+ return { action: "delivered" };
1076
+ }
1077
+ catch (retryError) {
1078
+ this.logger(`[bdk] reminder "${record.id}" followup failed after wait: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
1079
+ if (settle !== undefined) {
1080
+ settle.skipReason = "followup_failed";
1117
1081
  }
1082
+ return { action: "skip" };
1118
1083
  }
1119
- throw error;
1120
1084
  }
1121
- });
1085
+ throw error;
1086
+ }
1122
1087
  }
1123
1088
  buildFireContext(record) {
1124
- var _a, _b;
1125
1089
  const self = this;
1126
1090
  return {
1127
1091
  id: record.id,
1128
1092
  purpose: record.purpose,
1129
1093
  fireCount: record.fireCount,
1130
- target: Object.assign({ channelId: record.channelId, continuationToken: record.continuationToken }, ((_a = record.target) !== null && _a !== void 0 ? _a : {})),
1131
- args: (_b = record.args) !== null && _b !== void 0 ? _b : {},
1094
+ target: {
1095
+ channelId: record.channelId,
1096
+ continuationToken: record.continuationToken,
1097
+ ...(record.target ?? {}),
1098
+ },
1099
+ args: record.args ?? {},
1132
1100
  host: this.engine.host,
1133
1101
  mcp: this.engine.host.mcp,
1134
1102
  appAuth: APP_AUTH,
1135
1103
  artifacts: this.engine.artifacts,
1136
- followup(args) {
1137
- return __awaiter(this, void 0, void 0, function* () {
1138
- const target = yield self.resolveFollowupTarget(record);
1139
- let address = target.auth === undefined ? undefined : target;
1140
- // `openAuth` opens only when nothing exists anywhere: an unreadable
1141
- // durable session must not be shadowed by a second one on the same
1142
- // key (prompt-fire parity).
1143
- if (address === undefined &&
1144
- target.reached === "session_gone" &&
1145
- args.openAuth !== undefined) {
1146
- address = { auth: args.openAuth };
1147
- }
1148
- if (address === undefined) {
1149
- // Under the CP protocol the guest never writes reminder status;
1150
- // the fire's `stop` outcome carries the reason instead.
1151
- if (!self.usesControlPlaneProtocol) {
1152
- yield self.disarm(record, "session_gone");
1153
- }
1154
- throw new Error(`Reminder "${record.id}" followup: session gone for continuation`);
1155
- }
1156
- const result = yield self.sendFollowup(record, args.message, address, undefined, args);
1157
- if (result.action === "skip") {
1158
- throw new Error(`Reminder "${record.id}" followup skipped: session busy`);
1159
- }
1160
- const existing = yield self.boundSession(record);
1161
- if (existing === undefined) {
1162
- throw new Error(`Reminder "${record.id}" followup: session not found for continuation`);
1163
- }
1164
- const session = yield self.engine.getChannelSession(record.channelId, existing.sessionId);
1165
- if (session === null) {
1166
- throw new Error(`Reminder "${record.id}" followup: channel session missing`);
1104
+ async followup(args) {
1105
+ const target = await self.resolveFollowupTarget(record);
1106
+ let address = target.auth === undefined ? undefined : target;
1107
+ // `openAuth` opens only when nothing exists anywhere: an unreadable
1108
+ // durable session must not be shadowed by a second one on the same
1109
+ // key (prompt-fire parity).
1110
+ if (address === undefined &&
1111
+ target.reached === "session_gone" &&
1112
+ args.openAuth !== undefined) {
1113
+ address = { auth: args.openAuth };
1114
+ }
1115
+ if (address === undefined) {
1116
+ // Under the CP protocol the guest never writes reminder status;
1117
+ // the fire's `stop` outcome carries the reason instead.
1118
+ if (!self.usesControlPlaneProtocol) {
1119
+ await self.disarm(record, "session_gone");
1167
1120
  }
1168
- return session;
1169
- });
1121
+ throw new Error(`Reminder "${record.id}" followup: session gone for continuation`);
1122
+ }
1123
+ const result = await self.sendFollowup(record, args.message, address, undefined, args);
1124
+ if (result.action === "skip") {
1125
+ throw new Error(`Reminder "${record.id}" followup skipped: session busy`);
1126
+ }
1127
+ const existing = await self.boundSession(record);
1128
+ if (existing === undefined) {
1129
+ throw new Error(`Reminder "${record.id}" followup: session not found for continuation`);
1130
+ }
1131
+ const session = await self.engine.getChannelSession(record.channelId, existing.sessionId);
1132
+ if (session === null) {
1133
+ throw new Error(`Reminder "${record.id}" followup: channel session missing`);
1134
+ }
1135
+ return session;
1170
1136
  },
1171
- cancel() {
1172
- return __awaiter(this, arguments, void 0, function* (reason = "handler_cancel") {
1173
- yield self.cancel(record.id, reason);
1174
- });
1137
+ async cancel(reason = "handler_cancel") {
1138
+ await self.cancel(record.id, reason);
1175
1139
  },
1176
1140
  };
1177
1141
  }
1178
1142
  buildUntilContext(record) {
1179
- var _a;
1180
1143
  return {
1181
1144
  id: record.id,
1182
1145
  purpose: record.purpose,
1183
1146
  fireCount: record.fireCount,
1184
- target: Object.assign({ channelId: record.channelId, continuationToken: record.continuationToken }, ((_a = record.target) !== null && _a !== void 0 ? _a : {})),
1147
+ target: {
1148
+ channelId: record.channelId,
1149
+ continuationToken: record.continuationToken,
1150
+ ...(record.target ?? {}),
1151
+ },
1185
1152
  host: this.engine.host,
1186
1153
  mcp: this.engine.host.mcp,
1187
1154
  };
1188
1155
  }
1189
- disarm(record, reason) {
1190
- return __awaiter(this, void 0, void 0, function* () {
1191
- this.clearTimer(record.id);
1192
- const updated = Object.assign(Object.assign({}, record), { status: "disarmed", disarmReason: reason, updatedAt: new Date().toISOString() });
1193
- yield this.persist(updated);
1194
- this.handlers.delete(record.id);
1195
- });
1156
+ async disarm(record, reason) {
1157
+ this.clearTimer(record.id);
1158
+ const updated = {
1159
+ ...record,
1160
+ status: "disarmed",
1161
+ disarmReason: reason,
1162
+ updatedAt: new Date().toISOString(),
1163
+ };
1164
+ await this.persist(updated);
1165
+ this.handlers.delete(record.id);
1196
1166
  }
1197
- afterFire(record, _outcome, reschedule) {
1198
- return __awaiter(this, void 0, void 0, function* () {
1199
- const current = yield this.getRecord(record.id);
1200
- if (current === undefined || current.status !== "armed") {
1201
- return;
1202
- }
1203
- const now = Date.now();
1204
- const oneShot = current.scheduleKind === "delay" || current.scheduleKind === "at";
1205
- if (reschedule !== undefined) {
1206
- let nextFireAtMs;
1207
- if (reschedule.delay !== undefined) {
1208
- nextFireAtMs = now + parseDuration(reschedule.delay);
1209
- }
1210
- else if (reschedule.at !== undefined) {
1211
- nextFireAtMs =
1212
- reschedule.at instanceof Date
1213
- ? reschedule.at.getTime()
1214
- : Date.parse(String(reschedule.at));
1215
- if (!Number.isFinite(nextFireAtMs)) {
1216
- throw new ReminderValidationError(`Invalid reschedule.at for reminder "${current.id}"`);
1217
- }
1218
- }
1219
- else {
1220
- throw new ReminderValidationError(`reschedule requires delay or at for reminder "${current.id}"`);
1221
- }
1222
- const updated = Object.assign(Object.assign({}, current), { fireCount: current.fireCount + 1, nextFireAtMs,
1223
- // Promote to one-shot-from-now semantics if they rescheduled
1224
- scheduleKind: reschedule.delay !== undefined ? "delay" : "at", scheduleValue: reschedule.delay !== undefined ? String(reschedule.delay) : String(reschedule.at), updatedAt: new Date().toISOString() });
1225
- yield this.persist(updated);
1226
- if (this.platformTimers === undefined) {
1227
- this.armTimer(updated);
1228
- }
1229
- return;
1230
- }
1231
- if (oneShot) {
1232
- this.clearTimer(current.id);
1233
- const updated = Object.assign(Object.assign({}, current), { fireCount: current.fireCount + 1, status: "completed", disarmReason: "one_shot_complete", updatedAt: new Date().toISOString() });
1234
- yield this.persist(updated);
1235
- this.handlers.delete(current.id);
1236
- return;
1237
- }
1238
- // Recurring
1167
+ async afterFire(record, _outcome, reschedule) {
1168
+ const current = await this.getRecord(record.id);
1169
+ if (current === undefined || current.status !== "armed") {
1170
+ return;
1171
+ }
1172
+ const now = Date.now();
1173
+ const oneShot = current.scheduleKind === "delay" || current.scheduleKind === "at";
1174
+ if (reschedule !== undefined) {
1239
1175
  let nextFireAtMs;
1240
- if (current.scheduleKind === "every" && current.intervalMs !== undefined) {
1241
- nextFireAtMs = now + current.intervalMs;
1242
- }
1243
- else if (current.scheduleKind === "cron") {
1244
- nextFireAtMs = nextCronFireMs(current.scheduleValue, now);
1176
+ if (reschedule.delay !== undefined) {
1177
+ nextFireAtMs = now + parseDuration(reschedule.delay);
1178
+ }
1179
+ else if (reschedule.at !== undefined) {
1180
+ nextFireAtMs =
1181
+ reschedule.at instanceof Date
1182
+ ? reschedule.at.getTime()
1183
+ : Date.parse(String(reschedule.at));
1184
+ if (!Number.isFinite(nextFireAtMs)) {
1185
+ throw new ReminderValidationError(`Invalid reschedule.at for reminder "${current.id}"`);
1186
+ }
1245
1187
  }
1246
1188
  else {
1247
- throw new Error(`Reminder "${current.id}" has recurring status with scheduleKind=${current.scheduleKind}`);
1248
- }
1249
- const updated = Object.assign(Object.assign({}, current), { fireCount: current.fireCount + 1, nextFireAtMs, updatedAt: new Date().toISOString() });
1250
- yield this.persist(updated);
1189
+ throw new ReminderValidationError(`reschedule requires delay or at for reminder "${current.id}"`);
1190
+ }
1191
+ const updated = {
1192
+ ...current,
1193
+ fireCount: current.fireCount + 1,
1194
+ nextFireAtMs,
1195
+ // Promote to one-shot-from-now semantics if they rescheduled
1196
+ scheduleKind: reschedule.delay !== undefined ? "delay" : "at",
1197
+ scheduleValue: reschedule.delay !== undefined ? String(reschedule.delay) : String(reschedule.at),
1198
+ updatedAt: new Date().toISOString(),
1199
+ };
1200
+ await this.persist(updated);
1251
1201
  if (this.platformTimers === undefined) {
1252
1202
  this.armTimer(updated);
1253
1203
  }
1254
- });
1204
+ return;
1205
+ }
1206
+ if (oneShot) {
1207
+ this.clearTimer(current.id);
1208
+ const updated = {
1209
+ ...current,
1210
+ fireCount: current.fireCount + 1,
1211
+ status: "completed",
1212
+ disarmReason: "one_shot_complete",
1213
+ updatedAt: new Date().toISOString(),
1214
+ };
1215
+ await this.persist(updated);
1216
+ this.handlers.delete(current.id);
1217
+ return;
1218
+ }
1219
+ // Recurring
1220
+ let nextFireAtMs;
1221
+ if (current.scheduleKind === "every" && current.intervalMs !== undefined) {
1222
+ nextFireAtMs = now + current.intervalMs;
1223
+ }
1224
+ else if (current.scheduleKind === "cron") {
1225
+ nextFireAtMs = nextCronFireMs(current.scheduleValue, now);
1226
+ }
1227
+ else {
1228
+ throw new Error(`Reminder "${current.id}" has recurring status with scheduleKind=${current.scheduleKind}`);
1229
+ }
1230
+ const updated = {
1231
+ ...current,
1232
+ fireCount: current.fireCount + 1,
1233
+ nextFireAtMs,
1234
+ updatedAt: new Date().toISOString(),
1235
+ };
1236
+ await this.persist(updated);
1237
+ if (this.platformTimers === undefined) {
1238
+ this.armTimer(updated);
1239
+ }
1255
1240
  }
1256
1241
  }