@cursor/july 0.1.105 → 0.1.108

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 (395) hide show
  1. package/README.md +10 -5
  2. package/dist/bin/agent-serve.js +31 -16
  3. package/dist/channels/bitbucket/types.d.ts +2 -4
  4. package/dist/channels/bitbucket/types.d.ts.map +1 -1
  5. package/dist/channels/deployments/types.d.ts +5 -8
  6. package/dist/channels/deployments/types.d.ts.map +1 -1
  7. package/dist/channels/github/github-channel.js +8 -5
  8. package/dist/channels/github/types.d.ts +7 -5
  9. package/dist/channels/github/types.d.ts.map +1 -1
  10. package/dist/channels/gitlab/types.d.ts +2 -5
  11. package/dist/channels/gitlab/types.d.ts.map +1 -1
  12. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  13. package/dist/channels/origin/origin-channel.js +27 -13
  14. package/dist/channels/origin/types.d.ts +7 -4
  15. package/dist/channels/origin/types.d.ts.map +1 -1
  16. package/dist/channels/slack/defaults.d.ts.map +1 -1
  17. package/dist/channels/slack/defaults.js +3 -0
  18. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  19. package/dist/channels/slack/dispatch.js +1 -1
  20. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  21. package/dist/channels/slack/live-delivery.js +48 -11
  22. package/dist/channels/slack/types.d.ts +4 -3
  23. package/dist/channels/slack/types.d.ts.map +1 -1
  24. package/dist/channels.d.ts +45 -0
  25. package/dist/channels.d.ts.map +1 -1
  26. package/dist/channels.js +106 -7
  27. package/dist/connections.d.ts +2 -1
  28. package/dist/connections.d.ts.map +1 -1
  29. package/dist/connections.js +2 -1
  30. package/dist/docs/404.html +3 -3
  31. package/dist/docs/ab.html +6 -6
  32. package/dist/docs/assets/{app.BVwaffdK.js → app.BASKM3M4.js} +1 -1
  33. package/dist/docs/assets/chunks/@localSearchIndexroot.BHZYsNVi.js +1 -0
  34. package/dist/docs/assets/chunks/{VPLocalSearchBox.WuWTZ1x8.js → VPLocalSearchBox.BOKxlYGP.js} +2 -2
  35. package/dist/docs/assets/chunks/{theme.BYdI_6sF.js → theme.DbDZW-zb.js} +2 -2
  36. package/dist/docs/assets/{deployment.md.MFPKqsqI.js → deployment.md.JenwuCCB.js} +4 -4
  37. package/dist/docs/assets/{deployment.md.MFPKqsqI.lean.js → deployment.md.JenwuCCB.lean.js} +1 -1
  38. package/dist/docs/assets/{evals.md.CbMoebP1.js → evals.md.C1ekS3k2.js} +1 -1
  39. package/dist/docs/assets/guides_cloud-agents.md.BsloyHdY.js +9 -0
  40. package/dist/docs/assets/{guides_cloud-agents.md.DS8RIjwx.lean.js → guides_cloud-agents.md.BsloyHdY.lean.js} +1 -1
  41. package/dist/docs/assets/{guides_github.md.c0gdGJ-D.js → guides_github.md.BH33UEBJ.js} +1 -1
  42. package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.js → guides_grokbot-agents.md.DyV-WArv.js} +1 -1
  43. package/dist/docs/assets/guides_improve.md.BGVk32bK.js +14 -0
  44. package/dist/docs/assets/guides_improve.md.BGVk32bK.lean.js +1 -0
  45. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.js → guides_opentelemetry.md.SCRMskno.js} +3 -3
  46. package/dist/docs/assets/{guides_opentelemetry.md.COh9jFVg.lean.js → guides_opentelemetry.md.SCRMskno.lean.js} +1 -1
  47. package/dist/docs/assets/{guides_slack.md.9oHPye9o.js → guides_slack.md.D4RVMM4G.js} +3 -3
  48. package/dist/docs/assets/{guides_slack.md.9oHPye9o.lean.js → guides_slack.md.D4RVMM4G.lean.js} +1 -1
  49. package/dist/docs/assets/index.md.BjH1w2ZW.js +5 -0
  50. package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.js → reference_agent-config.md.CvoL6pof.js} +1 -1
  51. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.js → reference_channels.md.D-qTqwcq.js} +2 -2
  52. package/dist/docs/assets/{reference_channels.md.DBGcaB7m.lean.js → reference_channels.md.D-qTqwcq.lean.js} +1 -1
  53. package/dist/docs/assets/{reference_cli.md.C6Lo8SEd.js → reference_cli.md.Ca26u0Es.js} +6 -6
  54. package/dist/docs/assets/{reference_cli.md.C6Lo8SEd.lean.js → reference_cli.md.Ca26u0Es.lean.js} +1 -1
  55. package/dist/docs/assets/{reference_connections.md.Di6jJAXF.js → reference_connections.md.BojkC6c5.js} +1 -1
  56. package/dist/docs/assets/{reference_extensions.md.CGmMLblt.js → reference_extensions.md.CPWt00ds.js} +1 -1
  57. package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.js → scaffolding-agents.md.Kctn3OVb.js} +1 -1
  58. package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.js → skills_create-agent.md.Q3h6Je-e.js} +1 -1
  59. package/dist/docs/assets/{skills_debug.md.CDbPhHfg.js → skills_debug.md.CVjCXMFF.js} +1 -1
  60. package/dist/docs/assets/{skills_debug.md.CDbPhHfg.lean.js → skills_debug.md.CVjCXMFF.lean.js} +1 -1
  61. package/dist/docs/assets/{skills_evals.md.723kpUmA.js → skills_evals.md.BhovOvrl.js} +1 -1
  62. package/dist/docs/assets/skills_framework-map.md.D-tFZhFS.js +1 -0
  63. package/dist/docs/assets/{skills_framework-map.md.haibFyoB.lean.js → skills_framework-map.md.D-tFZhFS.lean.js} +1 -1
  64. package/dist/docs/assets/{skills_github.md.D0JahM8c.js → skills_github.md.hgFX_oKY.js} +1 -1
  65. package/dist/docs/assets/{skills_otel.md.CqhobH3B.js → skills_otel.md.B5Ddv1xH.js} +1 -1
  66. package/dist/docs/assets/{style.BRuM8477.css → style.DCD_zyg3.css} +1 -1
  67. package/dist/docs/assets/troubleshooting.md.CYEAO9bM.js +1 -0
  68. package/dist/docs/building-with-agents.html +6 -6
  69. package/dist/docs/concepts.html +5 -5
  70. package/dist/docs/deployment.html +9 -9
  71. package/dist/docs/deployment.md +7 -2
  72. package/dist/docs/evals.html +8 -8
  73. package/dist/docs/evals.md +3 -2
  74. package/dist/docs/guides/agent-to-agent.html +6 -6
  75. package/dist/docs/guides/cloud-agents.html +7 -7
  76. package/dist/docs/guides/cloud-agents.md +4 -3
  77. package/dist/docs/guides/convert-automation.html +6 -6
  78. package/dist/docs/guides/github.html +7 -7
  79. package/dist/docs/guides/github.md +2 -1
  80. package/dist/docs/guides/grokbot-agents.html +7 -7
  81. package/dist/docs/guides/grokbot-agents.md +2 -2
  82. package/dist/docs/guides/human-in-the-loop.html +6 -6
  83. package/dist/docs/guides/improve.html +40 -0
  84. package/dist/docs/guides/improve.md +91 -0
  85. package/dist/docs/guides/mcp-oauth.html +6 -6
  86. package/dist/docs/guides/opentelemetry.html +8 -8
  87. package/dist/docs/guides/opentelemetry.md +3 -4
  88. package/dist/docs/guides/slack.html +8 -8
  89. package/dist/docs/guides/slack.md +2 -1
  90. package/dist/docs/guides/webhooks.html +6 -6
  91. package/dist/docs/hashmap.json +1 -1
  92. package/dist/docs/hillclimbing.html +6 -6
  93. package/dist/docs/index.html +8 -8
  94. package/dist/docs/index.md +4 -0
  95. package/dist/docs/llms-full.txt +180 -61
  96. package/dist/docs/llms.txt +1 -0
  97. package/dist/docs/quickstart.html +6 -6
  98. package/dist/docs/reference/agent-config.html +7 -7
  99. package/dist/docs/reference/agent-config.md +5 -2
  100. package/dist/docs/reference/artifacts.html +6 -6
  101. package/dist/docs/reference/channels.html +7 -7
  102. package/dist/docs/reference/channels.md +11 -19
  103. package/dist/docs/reference/cli.html +11 -11
  104. package/dist/docs/reference/cli.md +23 -13
  105. package/dist/docs/reference/connections.html +8 -8
  106. package/dist/docs/reference/connections.md +2 -1
  107. package/dist/docs/reference/extensions.html +7 -7
  108. package/dist/docs/reference/extensions.md +2 -0
  109. package/dist/docs/reference/hooks.html +6 -6
  110. package/dist/docs/reference/http-api.html +6 -6
  111. package/dist/docs/reference/instructions.html +6 -6
  112. package/dist/docs/reference/playground.html +5 -5
  113. package/dist/docs/reference/project-layout.html +6 -6
  114. package/dist/docs/reference/prompt.html +6 -6
  115. package/dist/docs/reference/result.html +6 -6
  116. package/dist/docs/reference/schedules.html +6 -6
  117. package/dist/docs/reference/sessions.html +5 -5
  118. package/dist/docs/reference/skills.html +6 -6
  119. package/dist/docs/reference/subagents.html +6 -6
  120. package/dist/docs/reference/tools.html +6 -6
  121. package/dist/docs/scaffolding-agents.html +6 -6
  122. package/dist/docs/scaffolding-agents.md +2 -1
  123. package/dist/docs/skills/ab.html +6 -6
  124. package/dist/docs/skills/create-agent.html +8 -8
  125. package/dist/docs/skills/create-agent.md +1 -1
  126. package/dist/docs/skills/debug.html +6 -6
  127. package/dist/docs/skills/debug.md +1 -1
  128. package/dist/docs/skills/evals.html +8 -8
  129. package/dist/docs/skills/evals.md +1 -1
  130. package/dist/docs/skills/framework-map.html +6 -6
  131. package/dist/docs/skills/framework-map.md +4 -2
  132. package/dist/docs/skills/github.html +8 -8
  133. package/dist/docs/skills/github.md +1 -1
  134. package/dist/docs/skills/hillclimb.html +6 -6
  135. package/dist/docs/skills/index.html +5 -5
  136. package/dist/docs/skills/mcp-auth.html +6 -6
  137. package/dist/docs/skills/otel.html +8 -8
  138. package/dist/docs/skills/otel.md +3 -3
  139. package/dist/docs/skills/setup-slack.html +6 -6
  140. package/dist/docs/storage.html +6 -6
  141. package/dist/docs/templates/agentic-owners.html +6 -6
  142. package/dist/docs/templates/agents-md.html +6 -6
  143. package/dist/docs/templates/code-wiki.html +6 -6
  144. package/dist/docs/templates/demo.html +6 -6
  145. package/dist/docs/templates/grokbot-agents.html +6 -6
  146. package/dist/docs/templates/pr-autofixer.html +6 -6
  147. package/dist/docs/templates/security-help.html +6 -6
  148. package/dist/docs/templates/security-reviewer.html +6 -6
  149. package/dist/docs/templates/triage.html +6 -6
  150. package/dist/docs/troubleshooting.html +6 -6
  151. package/dist/docs/troubleshooting.md +1 -1
  152. package/dist/extensions/improve/extension.d.ts +46 -0
  153. package/dist/extensions/improve/extension.d.ts.map +1 -0
  154. package/dist/extensions/improve/extension.js +41 -0
  155. package/dist/extensions/improve/skills/yourself.d.ts +4 -0
  156. package/dist/extensions/improve/skills/yourself.d.ts.map +1 -0
  157. package/dist/extensions/improve/skills/yourself.js +43 -0
  158. package/dist/index.d.ts +4 -5
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +3 -4
  161. package/dist/internal/builtin-tools/artifacts.d.ts.map +1 -1
  162. package/dist/internal/builtin-tools/artifacts.js +2 -3
  163. package/dist/internal/channel-route-dispatch.d.ts +13 -0
  164. package/dist/internal/channel-route-dispatch.d.ts.map +1 -0
  165. package/dist/internal/channel-route-dispatch.js +62 -0
  166. package/dist/internal/channel-state.d.ts +17 -0
  167. package/dist/internal/channel-state.d.ts.map +1 -0
  168. package/dist/internal/channel-state.js +78 -0
  169. package/dist/internal/cli-ax.d.ts +7 -0
  170. package/dist/internal/cli-ax.d.ts.map +1 -1
  171. package/dist/internal/cli-ax.js +99 -1
  172. package/dist/internal/cli-cursor.d.ts.map +1 -1
  173. package/dist/internal/cli-cursor.js +2 -0
  174. package/dist/internal/cli-deploy.d.ts.map +1 -1
  175. package/dist/internal/cli-deploy.js +61 -25
  176. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
  177. package/dist/internal/cli-mcp-oauth.js +15 -0
  178. package/dist/internal/cli-mcp.d.ts.map +1 -1
  179. package/dist/internal/cli-mcp.js +12 -0
  180. package/dist/internal/cli-slack.d.ts.map +1 -1
  181. package/dist/internal/cli-slack.js +8 -2
  182. package/dist/internal/cursor/backend-client.d.ts +25 -0
  183. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  184. package/dist/internal/cursor/backend-client.js +57 -2
  185. package/dist/internal/cursor/credentials.d.ts +8 -2
  186. package/dist/internal/cursor/credentials.d.ts.map +1 -1
  187. package/dist/internal/cursor/credentials.js +27 -5
  188. package/dist/internal/deploy-client.d.ts +35 -0
  189. package/dist/internal/deploy-client.d.ts.map +1 -1
  190. package/dist/internal/deploy-client.js +46 -0
  191. package/dist/internal/deploy-manifest.d.ts +26 -0
  192. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  193. package/dist/internal/deploy-manifest.js +99 -13
  194. package/dist/internal/describe-error.d.ts +1 -0
  195. package/dist/internal/describe-error.d.ts.map +1 -1
  196. package/dist/internal/describe-error.js +25 -0
  197. package/dist/internal/discovery/agent.d.ts.map +1 -1
  198. package/dist/internal/discovery/agent.js +1 -0
  199. package/dist/internal/discovery/info.d.ts.map +1 -1
  200. package/dist/internal/discovery/info.js +7 -3
  201. package/dist/internal/discovery/modules.d.ts +1 -1
  202. package/dist/internal/discovery/modules.d.ts.map +1 -1
  203. package/dist/internal/discovery/modules.js +1 -0
  204. package/dist/internal/discovery/project.d.ts.map +1 -1
  205. package/dist/internal/discovery/project.js +3 -0
  206. package/dist/internal/discovery/reminders.d.ts +7 -0
  207. package/dist/internal/discovery/reminders.d.ts.map +1 -0
  208. package/dist/internal/discovery/reminders.js +65 -0
  209. package/dist/internal/discovery/subagent.js +1 -0
  210. package/dist/internal/distribution.d.ts +5 -0
  211. package/dist/internal/distribution.d.ts.map +1 -1
  212. package/dist/internal/distribution.js +17 -0
  213. package/dist/internal/framework-storage-selection.d.ts +14 -3
  214. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  215. package/dist/internal/framework-storage-selection.js +36 -6
  216. package/dist/internal/guest-network.d.ts +4 -10
  217. package/dist/internal/guest-network.d.ts.map +1 -1
  218. package/dist/internal/guest-network.js +44 -26
  219. package/dist/internal/hosted-admission-adapter.d.ts +2 -0
  220. package/dist/internal/hosted-admission-adapter.d.ts.map +1 -1
  221. package/dist/internal/hosted-catch-protocol.d.ts +51 -0
  222. package/dist/internal/hosted-catch-protocol.d.ts.map +1 -0
  223. package/dist/internal/hosted-catch-protocol.js +103 -0
  224. package/dist/internal/hosted-catch.d.ts +40 -0
  225. package/dist/internal/hosted-catch.d.ts.map +1 -0
  226. package/dist/internal/hosted-catch.js +149 -0
  227. package/dist/internal/hosted-delivery-protocol.d.ts +89 -0
  228. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  229. package/dist/internal/hosted-delivery-protocol.js +309 -0
  230. package/dist/internal/hosted-delivery.d.ts +20 -1
  231. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  232. package/dist/internal/hosted-delivery.js +179 -36
  233. package/dist/internal/hosted-execution-diag.d.ts +4 -1
  234. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  235. package/dist/internal/hosted-execution-diag.js +13 -4
  236. package/dist/internal/hosted-execution-flush.d.ts +3 -0
  237. package/dist/internal/hosted-execution-flush.d.ts.map +1 -1
  238. package/dist/internal/hosted-execution-flush.js +2 -4
  239. package/dist/internal/http-control-plane-session.d.ts +30 -0
  240. package/dist/internal/http-control-plane-session.d.ts.map +1 -0
  241. package/dist/internal/http-control-plane-session.js +83 -0
  242. package/dist/internal/legacy-command-guard.d.ts +22 -0
  243. package/dist/internal/legacy-command-guard.d.ts.map +1 -0
  244. package/dist/internal/legacy-command-guard.js +51 -0
  245. package/dist/internal/local-control-plane.d.ts +18 -2
  246. package/dist/internal/local-control-plane.d.ts.map +1 -1
  247. package/dist/internal/local-control-plane.js +199 -17
  248. package/dist/internal/platform-timers.d.ts +7 -0
  249. package/dist/internal/platform-timers.d.ts.map +1 -1
  250. package/dist/internal/platform-timers.js +139 -0
  251. package/dist/internal/reminder-control-plane-protocol.d.ts +189 -0
  252. package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -0
  253. package/dist/internal/reminder-control-plane-protocol.js +251 -0
  254. package/dist/internal/reminder-runner.d.ts +56 -6
  255. package/dist/internal/reminder-runner.d.ts.map +1 -1
  256. package/dist/internal/reminder-runner.js +372 -57
  257. package/dist/internal/reminder-schedule.d.ts +5 -2
  258. package/dist/internal/reminder-schedule.d.ts.map +1 -1
  259. package/dist/internal/reminder-schedule.js +8 -6
  260. package/dist/internal/reminder-store.d.ts +24 -7
  261. package/dist/internal/reminder-store.d.ts.map +1 -1
  262. package/dist/internal/reminder-store.js +6 -5
  263. package/dist/internal/request-error-status.d.ts +2 -0
  264. package/dist/internal/request-error-status.d.ts.map +1 -1
  265. package/dist/internal/request-error-status.js +22 -3
  266. package/dist/internal/resolve-prod-target.d.ts +2 -0
  267. package/dist/internal/resolve-prod-target.d.ts.map +1 -1
  268. package/dist/internal/resolve-prod-target.js +13 -0
  269. package/dist/internal/scm/pr-url.d.ts +40 -0
  270. package/dist/internal/scm/pr-url.d.ts.map +1 -1
  271. package/dist/internal/scm/pr-url.js +93 -14
  272. package/dist/internal/sdk-runner.d.ts.map +1 -1
  273. package/dist/internal/sdk-runner.js +4 -3
  274. package/dist/internal/server.d.ts.map +1 -1
  275. package/dist/internal/server.js +118 -77
  276. package/dist/internal/session-engine.d.ts +6 -6
  277. package/dist/internal/session-engine.d.ts.map +1 -1
  278. package/dist/internal/session-engine.js +100 -67
  279. package/dist/playground/assets/{index-BaQzjaNK.js → index-BMDqAeXu.js} +34 -34
  280. package/dist/playground/assets/index-LUgJoWdL.css +1 -0
  281. package/dist/playground/index.html +2 -2
  282. package/dist/reminders.d.ts +24 -5
  283. package/dist/reminders.d.ts.map +1 -1
  284. package/dist/reminders.js +28 -5
  285. package/dist/storage-backends/cursor-hosted.d.ts +6 -0
  286. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  287. package/dist/storage-backends/cursor-hosted.js +29 -1
  288. package/dist/types.d.ts +122 -25
  289. package/dist/types.d.ts.map +1 -1
  290. package/docs/README.md +4 -0
  291. package/docs/deployment.md +7 -2
  292. package/docs/evals.md +3 -2
  293. package/docs/guides/cloud-agents.md +4 -3
  294. package/docs/guides/github.md +2 -1
  295. package/docs/guides/grokbot-agents.md +2 -2
  296. package/docs/guides/improve.md +96 -0
  297. package/docs/guides/opentelemetry.md +3 -4
  298. package/docs/guides/slack.md +2 -1
  299. package/docs/reference/agent-config.md +5 -2
  300. package/docs/reference/channels.md +11 -19
  301. package/docs/reference/cli.md +23 -13
  302. package/docs/reference/connections.md +2 -1
  303. package/docs/reference/extensions.md +2 -0
  304. package/docs/scaffolding-agents.md +2 -1
  305. package/docs/troubleshooting.md +1 -1
  306. package/package.json +10 -3
  307. package/skills/create-agent/SKILL.md +1 -1
  308. package/skills/debug/SKILL.md +1 -1
  309. package/skills/evals/SKILL.md +1 -1
  310. package/skills/framework-map/SKILL.md +4 -2
  311. package/skills/github/SKILL.md +1 -1
  312. package/skills/otel/SKILL.md +3 -3
  313. package/src/bin/agent-serve.ts +28 -11
  314. package/src/channels/bitbucket/types.ts +2 -4
  315. package/src/channels/deployments/types.ts +5 -8
  316. package/src/channels/github/github-channel.ts +8 -8
  317. package/src/channels/github/types.ts +7 -4
  318. package/src/channels/gitlab/types.ts +2 -5
  319. package/src/channels/origin/origin-channel.ts +29 -13
  320. package/src/channels/origin/types.ts +7 -3
  321. package/src/channels/slack/defaults.ts +3 -0
  322. package/src/channels/slack/dispatch.ts +1 -0
  323. package/src/channels/slack/live-delivery.ts +53 -12
  324. package/src/channels/slack/types.ts +4 -3
  325. package/src/channels.ts +157 -10
  326. package/src/connections.ts +2 -1
  327. package/src/extensions/improve/extension.ts +70 -0
  328. package/src/extensions/improve/skills/yourself.ts +50 -0
  329. package/src/index.ts +6 -3
  330. package/src/internal/builtin-tools/artifacts.ts +2 -3
  331. package/src/internal/channel-route-dispatch.ts +66 -0
  332. package/src/internal/channel-state.ts +96 -0
  333. package/src/internal/cli-ax.ts +110 -1
  334. package/src/internal/cli-cursor.ts +4 -1
  335. package/src/internal/cli-deploy.ts +80 -22
  336. package/src/internal/cli-mcp-oauth.ts +18 -0
  337. package/src/internal/cli-mcp.ts +11 -0
  338. package/src/internal/cli-slack.ts +15 -2
  339. package/src/internal/cursor/backend-client.ts +90 -2
  340. package/src/internal/cursor/credentials.ts +35 -7
  341. package/src/internal/deploy-client.ts +70 -0
  342. package/src/internal/deploy-manifest.ts +131 -12
  343. package/src/internal/describe-error.ts +28 -0
  344. package/src/internal/discovery/agent.ts +1 -0
  345. package/src/internal/discovery/info.ts +6 -0
  346. package/src/internal/discovery/modules.ts +2 -4
  347. package/src/internal/discovery/project.ts +3 -0
  348. package/src/internal/discovery/reminders.ts +65 -0
  349. package/src/internal/discovery/subagent.ts +1 -0
  350. package/src/internal/distribution.ts +20 -0
  351. package/src/internal/framework-storage-selection.ts +43 -6
  352. package/src/internal/guest-network.ts +46 -29
  353. package/src/internal/hosted-admission-adapter.ts +2 -0
  354. package/src/internal/hosted-catch-protocol.ts +130 -0
  355. package/src/internal/hosted-catch.ts +192 -0
  356. package/src/internal/hosted-delivery-protocol.ts +483 -0
  357. package/src/internal/hosted-delivery.ts +303 -43
  358. package/src/internal/hosted-execution-diag.ts +21 -3
  359. package/src/internal/hosted-execution-flush.ts +6 -3
  360. package/src/internal/http-control-plane-session.ts +104 -0
  361. package/src/internal/legacy-command-guard.ts +59 -0
  362. package/src/internal/local-control-plane.ts +281 -22
  363. package/src/internal/platform-timers.ts +191 -0
  364. package/src/internal/reminder-control-plane-protocol.ts +512 -0
  365. package/src/internal/reminder-runner.ts +481 -57
  366. package/src/internal/reminder-schedule.ts +11 -6
  367. package/src/internal/reminder-store.ts +27 -7
  368. package/src/internal/request-error-status.ts +27 -3
  369. package/src/internal/resolve-prod-target.ts +15 -0
  370. package/src/internal/scm/pr-url.ts +167 -20
  371. package/src/internal/sdk-runner.ts +2 -1
  372. package/src/internal/server.ts +151 -88
  373. package/src/internal/session-engine.ts +146 -83
  374. package/src/reminders.ts +35 -4
  375. package/src/storage-backends/cursor-hosted.ts +40 -1
  376. package/src/types.ts +134 -26
  377. package/dist/docs/assets/chunks/@localSearchIndexroot.CJxMklAy.js +0 -1
  378. package/dist/docs/assets/guides_cloud-agents.md.DS8RIjwx.js +0 -9
  379. package/dist/docs/assets/index.md.BW_6tOgR.js +0 -5
  380. package/dist/docs/assets/skills_framework-map.md.haibFyoB.js +0 -1
  381. package/dist/docs/assets/troubleshooting.md.Cus_YZga.js +0 -1
  382. package/dist/playground/assets/index-CceqnLTX.css +0 -1
  383. /package/dist/docs/assets/{evals.md.CbMoebP1.lean.js → evals.md.C1ekS3k2.lean.js} +0 -0
  384. /package/dist/docs/assets/{guides_github.md.c0gdGJ-D.lean.js → guides_github.md.BH33UEBJ.lean.js} +0 -0
  385. /package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.lean.js → guides_grokbot-agents.md.DyV-WArv.lean.js} +0 -0
  386. /package/dist/docs/assets/{index.md.BW_6tOgR.lean.js → index.md.BjH1w2ZW.lean.js} +0 -0
  387. /package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.lean.js → reference_agent-config.md.CvoL6pof.lean.js} +0 -0
  388. /package/dist/docs/assets/{reference_connections.md.Di6jJAXF.lean.js → reference_connections.md.BojkC6c5.lean.js} +0 -0
  389. /package/dist/docs/assets/{reference_extensions.md.CGmMLblt.lean.js → reference_extensions.md.CPWt00ds.lean.js} +0 -0
  390. /package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.lean.js → scaffolding-agents.md.Kctn3OVb.lean.js} +0 -0
  391. /package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.lean.js → skills_create-agent.md.Q3h6Je-e.lean.js} +0 -0
  392. /package/dist/docs/assets/{skills_evals.md.723kpUmA.lean.js → skills_evals.md.BhovOvrl.lean.js} +0 -0
  393. /package/dist/docs/assets/{skills_github.md.D0JahM8c.lean.js → skills_github.md.hgFX_oKY.lean.js} +0 -0
  394. /package/dist/docs/assets/{skills_otel.md.CqhobH3B.lean.js → skills_otel.md.B5Ddv1xH.lean.js} +0 -0
  395. /package/dist/docs/assets/{troubleshooting.md.Cus_YZga.lean.js → troubleshooting.md.CYEAO9bM.lean.js} +0 -0
@@ -1,20 +1,40 @@
1
1
  /**
2
2
  * Per-session reminder runner: durable wake subscriptions with
3
- * prompt XOR run, every/cron/delay/at schedules, and until as
4
- * function XOR prompt.
3
+ * prompt XOR named handler XOR run, every/cron/delay/at schedules, and
4
+ * until as function XOR prompt.
5
5
  */
6
6
 
7
7
  import { randomBytes } from "node:crypto";
8
8
  import type {
9
9
  AuthContext,
10
+ DiscoveredReminder,
11
+ JsonObject,
12
+ JsonValue,
10
13
  ReminderCreateInput,
14
+ ReminderDefinition,
11
15
  ReminderFireContext,
12
16
  ReminderFireResult,
13
17
  ReminderInfo,
18
+ ReminderStatus,
14
19
  ReminderUntilContext,
15
20
  } from "../types.js";
21
+ import {
22
+ channelContinuationIdentity,
23
+ httpContinuationIdentity,
24
+ } from "./continuation-channel.js";
25
+ import { continuationSource } from "./continuation-identity.js";
26
+ import { NAME_PATTERN } from "./discovery/names.js";
16
27
  import { parseDuration } from "./duration.js";
17
28
  import type { PlatformTimers } from "./platform-timers.js";
29
+ import {
30
+ REMINDER_CP_PROTOCOL_VERSION,
31
+ type ReminderControlPlane,
32
+ type ReminderCreateIntent,
33
+ type ReminderExecutionOutcome,
34
+ type ReminderFireDescriptor,
35
+ scheduleSpecFromCreateInput,
36
+ toWireReschedule,
37
+ } from "./reminder-control-plane-protocol.js";
18
38
  import {
19
39
  defaultBusyPolicy,
20
40
  MAX_TIMER_MS,
@@ -24,10 +44,18 @@ import {
24
44
  } from "./reminder-schedule.js";
25
45
  import type { ReminderBusyPolicy, ReminderRecord } from "./reminder-store.js";
26
46
  import { APP_AUTH } from "./schedule-runner.js";
27
- import { SessionBusyError, type SessionEngine } from "./session-engine.js";
47
+ import {
48
+ type EngineSendOptions,
49
+ HTTP_CHANNEL_ID,
50
+ SessionBusyError,
51
+ type SessionEngine,
52
+ } from "./session-engine.js";
28
53
 
29
54
  export { ReminderValidationError } from "./reminder-schedule.js";
30
55
 
56
+ /** Max UTF-8 byte length of `JSON.stringify(args)` on named-handler create. */
57
+ export const REMINDER_ARGS_MAX_BYTES: number = 32 * 1024;
58
+
31
59
  export class UnknownReminderError extends Error {
32
60
  constructor(
33
61
  reminderId: string,
@@ -43,10 +71,79 @@ interface LiveHandlers {
43
71
  untilFn?: (ctx: ReminderUntilContext) => Promise<boolean>;
44
72
  }
45
73
 
74
+ export interface ReminderRunnerOptions {
75
+ /** Discovered `agent/reminders/*` handlers, keyed by module stem. */
76
+ namedHandlers?: readonly DiscoveredReminder[];
77
+ /**
78
+ * Architecture v2: reject anonymous `run` and function `until` at create
79
+ * (named `handler` + prompt remain), whether local or hosted.
80
+ */
81
+ rejectAnonymousHandlers?: boolean;
82
+ /**
83
+ * When set (local self-hosted architecture v2), create/cancel/rekey go
84
+ * through the control-plane protocol and fires are guest executions of
85
+ * immutable descriptors.
86
+ */
87
+ controlPlane?: ReminderControlPlane;
88
+ /** Agent architecture; used with {@link controlPlane} for v2 protocol path. */
89
+ architecture?: "v1" | "v2";
90
+ }
91
+
92
+ /**
93
+ * Server wiring for {@link ReminderRunnerOptions.rejectAnonymousHandlers}:
94
+ * architecture v2 always rejects anonymous run/until (local or hosted).
95
+ */
96
+ export function rejectAnonymousReminderHandlers(options: {
97
+ noControlPlane?: boolean;
98
+ architecture?: string;
99
+ }): boolean {
100
+ return options.architecture === "v2";
101
+ }
102
+
46
103
  function newReminderId(): string {
47
104
  return `rem_${randomBytes(8).toString("hex")}`;
48
105
  }
49
106
 
107
+ function isJsonObject(value: unknown): value is JsonObject {
108
+ return (
109
+ typeof value === "object" &&
110
+ value !== null &&
111
+ !Array.isArray(value) &&
112
+ Object.values(value as Record<string, unknown>).every(isJsonValue)
113
+ );
114
+ }
115
+
116
+ function isJsonValue(value: unknown): value is JsonValue {
117
+ if (
118
+ value === null ||
119
+ typeof value === "string" ||
120
+ typeof value === "boolean"
121
+ ) {
122
+ return true;
123
+ }
124
+ if (typeof value === "number") {
125
+ return Number.isFinite(value);
126
+ }
127
+ if (Array.isArray(value)) {
128
+ return value.every(isJsonValue);
129
+ }
130
+ return isJsonObject(value);
131
+ }
132
+
133
+ /** Same stem rules as `agent/reminders/<name>.ts` discovery. */
134
+ function isValidReminderHandlerName(name: string): boolean {
135
+ return NAME_PATTERN.test(name) && !name.includes("__");
136
+ }
137
+
138
+ function assertReminderArgsSize(args: JsonObject): void {
139
+ const bytes = Buffer.byteLength(JSON.stringify(args), "utf8");
140
+ if (bytes > REMINDER_ARGS_MAX_BYTES) {
141
+ throw new ReminderValidationError(
142
+ `reminders.create args exceed ${REMINDER_ARGS_MAX_BYTES} bytes (got ${bytes})`
143
+ );
144
+ }
145
+ }
146
+
50
147
  function toInfo(record: ReminderRecord): ReminderInfo {
51
148
  return {
52
149
  id: record.id,
@@ -57,9 +154,11 @@ function toInfo(record: ReminderRecord): ReminderInfo {
57
154
  scheduleKind: record.scheduleKind,
58
155
  scheduleValue: record.scheduleValue,
59
156
  prompt: record.prompt,
157
+ handler: record.handler,
158
+ args: record.args,
60
159
  untilPrompt: record.untilPrompt,
61
160
  busyPolicy: record.busyPolicy,
62
- status: record.status,
161
+ status: record.status === "firing" ? "armed" : record.status,
63
162
  disarmReason: record.disarmReason,
64
163
  fireCount: record.fireCount,
65
164
  nextFireAt: new Date(record.nextFireAtMs).toISOString(),
@@ -96,17 +195,36 @@ function buildFirePrompt(record: ReminderRecord): string {
96
195
  export class ReminderRunner {
97
196
  private readonly records = new Map<string, ReminderRecord>();
98
197
  private readonly handlers = new Map<string, LiveHandlers>();
198
+ private readonly namedHandlers = new Map<string, ReminderDefinition>();
199
+ private readonly namedHandlerNames = new Map<ReminderDefinition, string>();
99
200
  private readonly timers = new Map<string, NodeJS.Timeout>();
100
201
  private readonly firing = new Set<string>();
101
202
  /** Single-flight idle gates keyed by `channelId:continuationToken`. */
102
203
  private readonly idleGates = new Map<string, Promise<void>>();
103
204
  private started = false;
205
+ private readonly rejectAnonymousHandlers: boolean;
206
+ private readonly controlPlane: ReminderControlPlane | undefined;
207
+ private readonly architecture: "v1" | "v2" | undefined;
104
208
 
105
209
  constructor(
106
210
  private readonly engine: SessionEngine,
107
211
  private readonly logger: (line: string) => void = () => {},
108
- private readonly platformTimers?: PlatformTimers
109
- ) {}
212
+ private readonly platformTimers?: PlatformTimers,
213
+ options: ReminderRunnerOptions = {}
214
+ ) {
215
+ this.rejectAnonymousHandlers = options.rejectAnonymousHandlers === true;
216
+ this.controlPlane = options.controlPlane;
217
+ this.architecture = options.architecture;
218
+ for (const reminder of options.namedHandlers ?? []) {
219
+ this.namedHandlers.set(reminder.name, reminder.definition);
220
+ this.namedHandlerNames.set(reminder.definition, reminder.name);
221
+ }
222
+ }
223
+
224
+ /** True when create/cancel/rekey/fire go through the CP protocol. */
225
+ private get usesControlPlaneProtocol(): boolean {
226
+ return this.controlPlane !== undefined && this.architecture === "v2";
227
+ }
110
228
 
111
229
  /**
112
230
  * Load reminder documents from the control plane into memory. Does not
@@ -136,6 +254,13 @@ export class ReminderRunner {
136
254
  if (record.status !== "armed") {
137
255
  continue;
138
256
  }
257
+ if (record.handler !== undefined) {
258
+ if (this.namedHandlers.get(record.handler) === undefined) {
259
+ await this.disarm(record, "handler_missing");
260
+ disarmedOrphan += 1;
261
+ }
262
+ continue;
263
+ }
139
264
  if (
140
265
  (record.hasRunHandler === true || record.hasUntilFn === true) &&
141
266
  this.handlers.get(record.id) === undefined
@@ -168,6 +293,16 @@ export class ReminderRunner {
168
293
  let restored = 0;
169
294
  let disarmedOrphan = 0;
170
295
  for (const record of armed) {
296
+ if (record.handler !== undefined) {
297
+ if (this.namedHandlers.get(record.handler) === undefined) {
298
+ await this.disarm(record, "handler_missing");
299
+ disarmedOrphan += 1;
300
+ continue;
301
+ }
302
+ this.armTimer(record);
303
+ restored += 1;
304
+ continue;
305
+ }
171
306
  if (
172
307
  (record.hasRunHandler === true || record.hasUntilFn === true) &&
173
308
  this.handlers.get(record.id) === undefined
@@ -249,9 +384,11 @@ export class ReminderRunner {
249
384
  async create(input: ReminderCreateInput): Promise<ReminderInfo> {
250
385
  const hasPrompt = input.prompt !== undefined;
251
386
  const hasRun = input.run !== undefined;
252
- if (hasPrompt === hasRun) {
387
+ const hasHandler = input.handler !== undefined;
388
+ const formCount = [hasPrompt, hasRun, hasHandler].filter(Boolean).length;
389
+ if (formCount !== 1) {
253
390
  throw new ReminderValidationError(
254
- "reminders.create requires exactly one of prompt or run"
391
+ "reminders.create requires exactly one of prompt, handler, or run"
255
392
  );
256
393
  }
257
394
  if (input.continuationToken.trim() === "") {
@@ -264,46 +401,136 @@ export class ReminderRunner {
264
401
  throw new ReminderValidationError("purpose is required");
265
402
  }
266
403
 
267
- const schedule = resolveSchedule(input);
268
- const busyPolicy: ReminderBusyPolicy =
269
- input.busyPolicy ?? defaultBusyPolicy(schedule.kind);
270
- const now = new Date().toISOString();
271
- const id = newReminderId();
272
-
273
404
  const untilPrompt =
274
405
  typeof input.until === "string" ? input.until : undefined;
275
406
  const untilFn = typeof input.until === "function" ? input.until : undefined;
407
+
408
+ if (hasHandler && input.until !== undefined) {
409
+ throw new ReminderValidationError(
410
+ "reminders.create: until is not valid with handler; encode the stop condition in args and the handler body"
411
+ );
412
+ }
413
+
414
+ if (this.rejectAnonymousHandlers) {
415
+ if (hasRun) {
416
+ throw new ReminderValidationError(
417
+ "reminders.create: anonymous run handlers are not durable on architecture v2; author agent/reminders/<name>.ts and pass handler + args"
418
+ );
419
+ }
420
+ if (untilFn !== undefined) {
421
+ throw new ReminderValidationError(
422
+ "reminders.create: function until is not durable on architecture v2; use a string until prompt"
423
+ );
424
+ }
425
+ }
426
+
427
+ let handlerName: string | undefined;
428
+ let handlerArgs: JsonObject | undefined;
429
+ if (hasHandler) {
430
+ const handler = input.handler!;
431
+ const name =
432
+ typeof handler === "string"
433
+ ? handler.trim()
434
+ : this.namedHandlerNames.get(handler);
435
+ if (name === undefined) {
436
+ throw new ReminderValidationError(
437
+ "Unknown reminder handler definition (expected a default export discovered under agent/reminders/)"
438
+ );
439
+ }
440
+ if (name === "") {
441
+ throw new ReminderValidationError("handler name is required");
442
+ }
443
+ if (!isValidReminderHandlerName(name)) {
444
+ throw new ReminderValidationError(
445
+ name.includes("__")
446
+ ? `Invalid reminder handler name "${name}": may not contain "__"`
447
+ : `Invalid reminder handler name "${name}": must match ${NAME_PATTERN}`
448
+ );
449
+ }
450
+ if (this.namedHandlers.get(name) === undefined) {
451
+ throw new ReminderValidationError(
452
+ `Unknown reminder handler "${name}" (expected agent/reminders/${name}.ts)`
453
+ );
454
+ }
455
+ if (input.args !== undefined && !isJsonObject(input.args)) {
456
+ throw new ReminderValidationError(
457
+ "reminders.create args must be a JSON object"
458
+ );
459
+ }
460
+ handlerName = name;
461
+ handlerArgs = input.args ?? {};
462
+ assertReminderArgsSize(handlerArgs);
463
+ } else if (input.args !== undefined) {
464
+ throw new ReminderValidationError(
465
+ "reminders.create args is only valid with handler"
466
+ );
467
+ }
468
+
469
+ const schedule = resolveSchedule(input);
470
+ const busyPolicy: ReminderBusyPolicy =
471
+ input.busyPolicy ?? defaultBusyPolicy(schedule.kind);
276
472
  const hasRunHandler = input.run !== undefined;
277
473
  const hasUntilFn = untilFn !== undefined;
278
474
 
279
- const record: ReminderRecord = {
280
- version: 1,
281
- id,
282
- purpose: input.purpose,
283
- channelId: input.channelId,
284
- continuationToken: input.continuationToken,
285
- target: input.target,
286
- scheduleKind: schedule.kind,
287
- scheduleValue: schedule.value,
288
- intervalMs: schedule.intervalMs,
289
- prompt: input.prompt,
290
- hasRunHandler,
291
- hasUntilFn,
292
- untilPrompt,
293
- busyPolicy,
294
- status: "armed",
295
- fireCount: 0,
296
- nextFireAtMs: schedule.nextFireAtMs,
297
- createdAt: now,
298
- updatedAt: now,
299
- };
475
+ let record: ReminderRecord;
476
+ if (this.usesControlPlaneProtocol) {
477
+ const intent: ReminderCreateIntent = {
478
+ protocolVersion: REMINDER_CP_PROTOCOL_VERSION,
479
+ purpose: input.purpose,
480
+ channelId: input.channelId,
481
+ continuationToken: input.continuationToken,
482
+ target: input.target,
483
+ // CP recalculates nextFireAtMs / intervalMs from the raw schedule.
484
+ schedule: scheduleSpecFromCreateInput(input),
485
+ prompt: input.prompt,
486
+ handler: handlerName,
487
+ args: handlerArgs,
488
+ hasRunHandler,
489
+ hasUntilFn,
490
+ untilPrompt,
491
+ busyPolicy,
492
+ };
493
+ record = await this.controlPlane!.createReminder(intent);
494
+ this.records.set(record.id, record);
495
+ } else {
496
+ const now = new Date().toISOString();
497
+ const id = newReminderId();
498
+ record = {
499
+ version: 1,
500
+ id,
501
+ purpose: input.purpose,
502
+ channelId: input.channelId,
503
+ continuationToken: input.continuationToken,
504
+ target: input.target,
505
+ scheduleKind: schedule.kind,
506
+ scheduleValue: schedule.value,
507
+ intervalMs: schedule.intervalMs,
508
+ prompt: input.prompt,
509
+ handler: handlerName,
510
+ args: handlerArgs,
511
+ hasRunHandler,
512
+ hasUntilFn,
513
+ untilPrompt,
514
+ busyPolicy,
515
+ status: "armed",
516
+ fireCount: 0,
517
+ nextFireAtMs: schedule.nextFireAtMs,
518
+ generation: 0,
519
+ createdAt: now,
520
+ updatedAt: now,
521
+ };
522
+ await this.persist(record);
523
+ }
300
524
 
301
- await this.persist(record);
302
- this.handlers.set(id, {
525
+ this.handlers.set(record.id, {
303
526
  run: input.run,
304
527
  untilFn,
305
528
  });
306
- if (this.started && this.platformTimers === undefined) {
529
+ if (
530
+ this.started &&
531
+ this.platformTimers === undefined &&
532
+ !this.usesControlPlaneProtocol
533
+ ) {
307
534
  this.armTimer(record);
308
535
  }
309
536
 
@@ -311,15 +538,18 @@ export class ReminderRunner {
311
538
  }
312
539
 
313
540
  async list(filter?: {
314
- status?: ReminderRecord["status"];
541
+ status?: ReminderStatus;
315
542
  purpose?: string;
316
543
  continuationToken?: string;
317
544
  }): Promise<ReminderInfo[]> {
318
545
  const all = await this.allRecords();
319
546
  return all
320
547
  .filter((r) => {
321
- if (filter?.status !== undefined && r.status !== filter.status) {
322
- return false;
548
+ if (filter?.status !== undefined) {
549
+ const publicStatus = r.status === "firing" ? "armed" : r.status;
550
+ if (publicStatus !== filter.status) {
551
+ return false;
552
+ }
323
553
  }
324
554
  if (filter?.purpose !== undefined && r.purpose !== filter.purpose) {
325
555
  return false;
@@ -348,11 +578,22 @@ export class ReminderRunner {
348
578
  id: string,
349
579
  reason = "explicit_cancel"
350
580
  ): Promise<ReminderInfo | undefined> {
581
+ if (this.usesControlPlaneProtocol) {
582
+ const updated = await this.controlPlane!.cancelReminder(id, reason);
583
+ if (updated === undefined) {
584
+ this.records.delete(id);
585
+ this.handlers.delete(id);
586
+ return undefined;
587
+ }
588
+ this.records.set(id, updated);
589
+ this.handlers.delete(id);
590
+ return toInfo(updated);
591
+ }
351
592
  const record = await this.getRecord(id);
352
593
  if (record === undefined) {
353
594
  return undefined;
354
595
  }
355
- if (record.status !== "armed") {
596
+ if (record.status !== "armed" && record.status !== "firing") {
356
597
  return toInfo(record);
357
598
  }
358
599
  this.clearTimer(id);
@@ -360,6 +601,7 @@ export class ReminderRunner {
360
601
  ...record,
361
602
  status: "cancelled",
362
603
  disarmReason: reason,
604
+ generation: (record.generation ?? 0) + 1,
363
605
  updatedAt: new Date().toISOString(),
364
606
  };
365
607
  await this.persist(updated);
@@ -394,7 +636,12 @@ export class ReminderRunner {
394
636
  oldToken: string,
395
637
  newToken: string
396
638
  ): Promise<number> {
397
- const armed = (await this.allRecords()).filter((r) => r.status === "armed");
639
+ if (this.usesControlPlaneProtocol) {
640
+ return this.controlPlane!.rekeyReminders(channelId, oldToken, newToken);
641
+ }
642
+ const armed = (await this.allRecords()).filter(
643
+ (r) => r.status === "armed" || r.status === "firing"
644
+ );
398
645
  let n = 0;
399
646
  for (const record of armed) {
400
647
  if (
@@ -406,6 +653,7 @@ export class ReminderRunner {
406
653
  await this.persist({
407
654
  ...record,
408
655
  continuationToken: newToken,
656
+ generation: (record.generation ?? 0) + 1,
409
657
  updatedAt: new Date().toISOString(),
410
658
  });
411
659
  n += 1;
@@ -441,6 +689,121 @@ export class ReminderRunner {
441
689
  return { reminderId, ...result };
442
690
  }
443
691
 
692
+ /**
693
+ * Architecture v2 / CP protocol guest entrypoint: execute an immutable fire
694
+ * descriptor and return an outcome. Does not mint ids or mutate
695
+ * authoritative status/fireCount — the control plane applies the outcome.
696
+ */
697
+ async executeFire(
698
+ descriptor: ReminderFireDescriptor
699
+ ): Promise<ReminderExecutionOutcome> {
700
+ const record = this.recordFromDescriptor(descriptor);
701
+ this.records.set(record.id, record);
702
+
703
+ const live = this.handlers.get(record.id) ?? {};
704
+ if (record.handler !== undefined) {
705
+ if (this.resolveNamedHandler(record.handler) === undefined) {
706
+ return { kind: "stop", reason: "handler_missing" };
707
+ }
708
+ } else if (
709
+ (record.hasRunHandler === true || record.hasUntilFn === true) &&
710
+ live.run === undefined &&
711
+ live.untilFn === undefined
712
+ ) {
713
+ return { kind: "stop", reason: "handler_lost_on_restart" };
714
+ }
715
+
716
+ if (live.untilFn !== undefined) {
717
+ try {
718
+ const done = await live.untilFn(this.buildUntilContext(record));
719
+ if (done) {
720
+ return { kind: "stop", reason: "until_fn" };
721
+ }
722
+ } catch (error) {
723
+ this.logger(
724
+ `[agent-sdk] reminder "${record.id}" until() failed: ${
725
+ error instanceof Error ? error.message : String(error)
726
+ }`
727
+ );
728
+ }
729
+ }
730
+
731
+ if (await this.isSessionBusy(record.channelId, record.continuationToken)) {
732
+ if (record.busyPolicy === "skipIfBusy") {
733
+ this.logger(
734
+ `[agent-sdk] reminder "${record.id}" (${record.purpose}) skipped: session busy`
735
+ );
736
+ return { kind: "skipped" };
737
+ }
738
+ await this.whenSessionIdle(record.channelId, record.continuationToken);
739
+ }
740
+
741
+ let result: ReminderFireResult;
742
+ if (record.handler !== undefined) {
743
+ const named = this.resolveNamedHandler(record.handler);
744
+ if (named === undefined) {
745
+ return { kind: "stop", reason: "handler_missing" };
746
+ }
747
+ result = await named.run(this.buildFireContext(record));
748
+ } else if (live.run !== undefined) {
749
+ result = await live.run(this.buildFireContext(record));
750
+ } else if (record.prompt !== undefined) {
751
+ result = await this.deliverPrompt(record);
752
+ } else {
753
+ return { kind: "stop", reason: "missing_handler" };
754
+ }
755
+
756
+ if (result.action === "stop") {
757
+ return { kind: "stop", reason: "run_stop" };
758
+ }
759
+ if (result.action === "skip") {
760
+ return {
761
+ kind: "skipped",
762
+ reschedule:
763
+ result.reschedule !== undefined
764
+ ? toWireReschedule(result.reschedule)
765
+ : undefined,
766
+ };
767
+ }
768
+ return {
769
+ kind: "delivered",
770
+ reschedule:
771
+ result.reschedule !== undefined
772
+ ? toWireReschedule(result.reschedule)
773
+ : undefined,
774
+ };
775
+ }
776
+
777
+ private recordFromDescriptor(
778
+ descriptor: ReminderFireDescriptor
779
+ ): ReminderRecord {
780
+ const now = new Date().toISOString();
781
+ return {
782
+ version: 1,
783
+ id: descriptor.id,
784
+ purpose: descriptor.purpose,
785
+ channelId: descriptor.channelId,
786
+ continuationToken: descriptor.continuationToken,
787
+ target: descriptor.target,
788
+ scheduleKind: descriptor.scheduleKind,
789
+ scheduleValue: descriptor.scheduleValue,
790
+ intervalMs: descriptor.intervalMs,
791
+ prompt: descriptor.prompt,
792
+ handler: descriptor.handler,
793
+ args: descriptor.args,
794
+ hasRunHandler: descriptor.hasRunHandler,
795
+ hasUntilFn: descriptor.hasUntilFn,
796
+ untilPrompt: descriptor.untilPrompt,
797
+ busyPolicy: descriptor.busyPolicy,
798
+ status: "firing",
799
+ fireCount: descriptor.fireCount,
800
+ nextFireAtMs: descriptor.nextFireAtMs,
801
+ generation: descriptor.generation,
802
+ createdAt: now,
803
+ updatedAt: now,
804
+ };
805
+ }
806
+
444
807
  private armTimer(record: ReminderRecord): void {
445
808
  this.clearTimer(record.id);
446
809
  if (!this.started || record.status !== "armed") return;
@@ -493,6 +856,10 @@ export class ReminderRunner {
493
856
  }
494
857
  }
495
858
 
859
+ private resolveNamedHandler(name: string): ReminderDefinition | undefined {
860
+ return this.namedHandlers.get(name);
861
+ }
862
+
496
863
  private async fire(
497
864
  id: string,
498
865
  opts: { force?: boolean } = {}
@@ -515,7 +882,12 @@ export class ReminderRunner {
515
882
  }
516
883
 
517
884
  const live = this.handlers.get(id) ?? {};
518
- if (
885
+ if (record.handler !== undefined) {
886
+ if (this.resolveNamedHandler(record.handler) === undefined) {
887
+ await this.disarm(record, "handler_missing");
888
+ return { outcome: "noop", reason: "handler_missing" };
889
+ }
890
+ } else if (
519
891
  (record.hasRunHandler === true || record.hasUntilFn === true) &&
520
892
  live.run === undefined &&
521
893
  live.untilFn === undefined
@@ -560,9 +932,15 @@ export class ReminderRunner {
560
932
  }
561
933
 
562
934
  let result: ReminderFireResult;
563
- if (live.run !== undefined) {
564
- const fireCtx = this.buildFireContext(record);
565
- result = await live.run(fireCtx);
935
+ if (record.handler !== undefined) {
936
+ const named = this.resolveNamedHandler(record.handler);
937
+ if (named === undefined) {
938
+ await this.disarm(record, "handler_missing");
939
+ return { outcome: "noop", reason: "handler_missing" };
940
+ }
941
+ result = await named.run(this.buildFireContext(record));
942
+ } else if (live.run !== undefined) {
943
+ result = await live.run(this.buildFireContext(record));
566
944
  } else if (record.prompt !== undefined) {
567
945
  result = await this.deliverPrompt(record);
568
946
  } else {
@@ -595,7 +973,7 @@ export class ReminderRunner {
595
973
  return { outcome: "fired", reason: "skipped" };
596
974
  }
597
975
  await this.afterFire(latest, "delivered", result.reschedule);
598
- this.logger(`[agent-sdk] reminder "${id}" (${record.purpose}) delivered`);
976
+ this.logger(`[agent-sdk] reminder "${id}" (${record.purpose}) fired`);
599
977
  return { outcome: "fired", reason: "delivered" };
600
978
  } finally {
601
979
  this.firing.delete(id);
@@ -662,22 +1040,66 @@ export class ReminderRunner {
662
1040
  record.continuationToken
663
1041
  );
664
1042
  if (auth === undefined) {
665
- await this.disarm(record, "session_gone");
1043
+ // Under CP protocol, return stop and let the CP apply/CAS; do not
1044
+ // mutate authoritative status from the guest mid-fire.
1045
+ if (!this.usesControlPlaneProtocol) {
1046
+ await this.disarm(record, "session_gone");
1047
+ }
666
1048
  return { action: "stop" };
667
1049
  }
668
1050
  return this.sendFollowup(record, buildFirePrompt(record), auth);
669
1051
  }
670
1052
 
1053
+ /**
1054
+ * Join the reminder's existing session. Control-plane (`/v2`) channels
1055
+ * refuse authored `continuationToken`; pass the stored key as
1056
+ * {@link EngineSendOptions.mailboxContinuation} so the engine reuses the
1057
+ * CP-selected identity without channel admission.
1058
+ */
1059
+ private followupSendOptions(
1060
+ record: ReminderRecord,
1061
+ auth: AuthContext | null
1062
+ ): EngineSendOptions {
1063
+ if (this.channelUsesControlPlaneContinuation(record.channelId)) {
1064
+ return {
1065
+ auth,
1066
+ mailboxContinuation: { key: record.continuationToken },
1067
+ };
1068
+ }
1069
+ return {
1070
+ auth,
1071
+ continuationToken: record.continuationToken,
1072
+ };
1073
+ }
1074
+
1075
+ private channelUsesControlPlaneContinuation(channelId: string): boolean {
1076
+ const project = this.engine.project;
1077
+ // Test doubles may omit `project`; keep the legacy continuationToken path.
1078
+ if (project === undefined) {
1079
+ return false;
1080
+ }
1081
+ const identity =
1082
+ channelId === HTTP_CHANNEL_ID
1083
+ ? httpContinuationIdentity(project.httpChannel)
1084
+ : channelContinuationIdentity(
1085
+ project.channels.find((channel) => channel.id === channelId)
1086
+ ?.definition
1087
+ );
1088
+ return continuationSource(identity) === "control-plane";
1089
+ }
1090
+
671
1091
  private async sendFollowup(
672
1092
  record: ReminderRecord,
673
1093
  message: string,
674
1094
  auth: AuthContext | null
675
1095
  ): Promise<ReminderFireResult> {
1096
+ const sendOptions = this.followupSendOptions(record, auth);
676
1097
  try {
677
- const session = await this.engine.send(record.channelId, message, {
678
- auth,
679
- continuationToken: record.continuationToken,
680
- });
1098
+ const session = await this.engine.send(
1099
+ record.channelId,
1100
+ message,
1101
+ sendOptions
1102
+ );
681
1103
  this.engine.trackBackground(this.engine.waitForCompletion(session.id));
682
1104
  return { action: "delivered" };
683
1105
  } catch (error) {
@@ -687,10 +1109,11 @@ export class ReminderRunner {
687
1109
  }
688
1110
  await this.whenSessionIdle(record.channelId, record.continuationToken);
689
1111
  try {
690
- const session = await this.engine.send(record.channelId, message, {
691
- auth,
692
- continuationToken: record.continuationToken,
693
- });
1112
+ const session = await this.engine.send(
1113
+ record.channelId,
1114
+ message,
1115
+ sendOptions
1116
+ );
694
1117
  this.engine.trackBackground(
695
1118
  this.engine.waitForCompletion(session.id)
696
1119
  );
@@ -721,6 +1144,7 @@ export class ReminderRunner {
721
1144
  continuationToken: record.continuationToken,
722
1145
  ...(record.target ?? {}),
723
1146
  },
1147
+ args: record.args ?? {},
724
1148
  host: this.engine.host,
725
1149
  mcp: this.engine.host.mcp,
726
1150
  appAuth: APP_AUTH,