@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
@@ -82,6 +82,37 @@ const githubTokenResponseSchema: z.ZodType<CursorGithubToken> = z.object({
82
82
  expiresAt: z.string().datetime(),
83
83
  });
84
84
 
85
+ /** SCMs whose git fetches ride the backend's `/v0/scm-events/<provider>-git-proxy` routes. */
86
+ export type CursorScmCloneProvider = "gitlab" | "bitbucket";
87
+
88
+ /**
89
+ * Proxied clone target for a GitLab / Bitbucket repository. The backend
90
+ * never hands out the provider credential: git fetches go to `remoteUrl`
91
+ * on the backend with the caller's own Cursor API key as a bearer token,
92
+ * and the backend adds the tenant credential per request.
93
+ */
94
+ export interface CursorScmCloneTarget {
95
+ /** Absolute `<backend>/v0/scm-events/<provider>-git-proxy/<repo>.git`. */
96
+ remoteUrl: string;
97
+ /** Bearer credential git presents to the backend (the caller's API key). */
98
+ token: string;
99
+ /** ISO timestamp after which the caller re-resolves the target. */
100
+ expiresAt: string;
101
+ username: string;
102
+ authMode: "bearer";
103
+ }
104
+
105
+ const scmCloneTargetResponseSchema = z.object({
106
+ expiresAt: z.string().datetime(),
107
+ clone: z.object({
108
+ remotePath: z
109
+ .string()
110
+ .regex(/^\/v0\/scm-events\/[a-z]+-git-proxy\/.+\.git$/),
111
+ username: z.string().min(1),
112
+ authMode: z.literal("bearer"),
113
+ }),
114
+ });
115
+
85
116
  const mcpToolSchema = z.object({
86
117
  name: z.string(),
87
118
  providerIdentifier: z.string().optional(),
@@ -490,6 +521,62 @@ export class CursorBackendClient {
490
521
  return githubTokenResponseSchema.parse(parsed);
491
522
  }
492
523
 
524
+ /**
525
+ * Resolve the proxied clone target for a GitLab / Bitbucket repository
526
+ * (`owner/name`; GitLab `path_with_namespace`). Same authorization as the
527
+ * provider proxy this host already calls; the returned remote lives on
528
+ * the backend and takes this client's API key, never a provider token.
529
+ */
530
+ async getScmCloneTarget(
531
+ provider: CursorScmCloneProvider,
532
+ repo: string
533
+ ): Promise<CursorScmCloneTarget> {
534
+ const label = provider === "gitlab" ? "GitLab" : "Bitbucket";
535
+ let response: Response;
536
+ try {
537
+ response = await this.fetchImpl(
538
+ `${this.backendUrl}/v0/scm-events/${provider}-clone-target`,
539
+ {
540
+ method: "POST",
541
+ headers: {
542
+ "content-type": "application/json",
543
+ authorization: `Bearer ${this.currentApiKey()}`,
544
+ },
545
+ body: JSON.stringify({ repo }),
546
+ signal: AbortSignal.timeout(30_000),
547
+ }
548
+ );
549
+ } catch (error) {
550
+ throw new CursorBackendError(
551
+ `Cursor ${label} clone target request failed: ${describeError(error)}`
552
+ );
553
+ }
554
+ const text = await response.text();
555
+ if (!response.ok) {
556
+ throw new CursorBackendError(
557
+ describeGithubTokenHttpFailure(response.status, text, label),
558
+ response.status,
559
+ retryAfterMsFromResponse(response)
560
+ );
561
+ }
562
+ let parsed: unknown;
563
+ try {
564
+ parsed = JSON.parse(text) as unknown;
565
+ } catch {
566
+ throw new CursorBackendError(
567
+ `Cursor backend returned a non-JSON ${label} clone target response.`
568
+ );
569
+ }
570
+ const body = scmCloneTargetResponseSchema.parse(parsed);
571
+ return {
572
+ remoteUrl: `${this.backendUrl}${body.clone.remotePath}`,
573
+ token: this.currentApiKey(),
574
+ expiresAt: body.expiresAt,
575
+ username: body.clone.username,
576
+ authMode: body.clone.authMode,
577
+ };
578
+ }
579
+
493
580
  /**
494
581
  * One unary Connect-JSON call on `aiserver.v1.<service>` with the same
495
582
  * token exchange and 401 retry as the dashboard RPCs. Callers parse the
@@ -864,7 +951,8 @@ const MAX_GITHUB_TOKEN_RETRY_AFTER_MS = 60 * 60_000;
864
951
  */
865
952
  function describeGithubTokenHttpFailure(
866
953
  status: number,
867
- bodyText: string
954
+ bodyText: string,
955
+ label = "GitHub"
868
956
  ): string {
869
957
  const detail = githubTokenErrorFromBody(bodyText);
870
958
  if (status === 401) {
@@ -875,7 +963,7 @@ function describeGithubTokenHttpFailure(
875
963
  if (detail !== undefined) {
876
964
  return detail;
877
965
  }
878
- return `Cursor GitHub credential request failed (${status}).`;
966
+ return `Cursor ${label} credential request failed (${status}).`;
879
967
  }
880
968
 
881
969
  function githubTokenErrorFromBody(bodyText: string): string | undefined {
@@ -176,10 +176,15 @@ export async function clearStoredCredentials(): Promise<boolean> {
176
176
  }
177
177
 
178
178
  // ============================================================================
179
- // Resolution (option > env > file > stored login)
179
+ // Resolution (option > env > file > service account > stored login)
180
180
  // ============================================================================
181
181
 
182
- export type ApiKeySource = "option" | "env" | "file" | "login";
182
+ export type ApiKeySource =
183
+ | "option"
184
+ | "env"
185
+ | "file"
186
+ | "service-account"
187
+ | "login";
183
188
 
184
189
  export interface ResolvedApiKey {
185
190
  apiKey: string;
@@ -274,10 +279,25 @@ export function consumeBoundCursorApiKey(options?: {
274
279
  };
275
280
  }
276
281
 
282
+ function presentEnvKey(name: string): string | undefined {
283
+ const value = process.env[name];
284
+ if (value === undefined) {
285
+ return undefined;
286
+ }
287
+ const trimmed = value.trim();
288
+ return trimmed === "" ? undefined : trimmed;
289
+ }
290
+
277
291
  /**
278
292
  * First present source wins. We define the order; operators do not.
279
293
  * `--api-key` / `serve({ apiKey })` → `CURSOR_API_KEY` → `CURSOR_API_KEY_FILE`
280
- * (hosted default path if unset) → stored `july login`.
294
+ * (hosted default path if unset) → `CURSOR_SERVICE_ACCOUNT_KEY` → stored
295
+ * `july login`.
296
+ *
297
+ * A cloud-agent VM often has the service-account key and no user API key.
298
+ * The explicit key and the hosted bind file still win, so a task credential
299
+ * is not replaced by the ambient service-account key. The service-account
300
+ * key wins over a leftover personal login.
281
301
  */
282
302
  export function resolveApiKeySync(options?: {
283
303
  apiKey?: string;
@@ -287,14 +307,22 @@ export function resolveApiKeySync(options?: {
287
307
  if (options?.apiKey !== undefined && options.apiKey.trim() !== "") {
288
308
  return { apiKey: options.apiKey.trim(), source: "option", backendUrl };
289
309
  }
290
- const envKey = process.env.CURSOR_API_KEY;
291
- if (envKey !== undefined && envKey.trim() !== "") {
292
- return { apiKey: envKey.trim(), source: "env", backendUrl };
310
+ const envKey = presentEnvKey("CURSOR_API_KEY");
311
+ if (envKey !== undefined) {
312
+ return { apiKey: envKey, source: "env", backendUrl };
293
313
  }
294
314
  const fileKey = readApiKeyFromFile();
295
315
  if (fileKey !== undefined) {
296
316
  return { apiKey: fileKey, source: "file", backendUrl };
297
317
  }
318
+ const serviceAccountKey = presentEnvKey("CURSOR_SERVICE_ACCOUNT_KEY");
319
+ if (serviceAccountKey !== undefined) {
320
+ return {
321
+ apiKey: serviceAccountKey,
322
+ source: "service-account",
323
+ backendUrl,
324
+ };
325
+ }
298
326
  const stored = readStoredCredentialsSync();
299
327
  if (stored !== undefined && stored.backendUrl === backendUrl) {
300
328
  return { apiKey: stored.apiKey, source: "login", backendUrl };
@@ -313,7 +341,7 @@ export async function resolveApiKey(options?: {
313
341
  }
314
342
 
315
343
  /** One-line hint for "no credentials" errors, shared across surfaces. */
316
- export const SIGN_IN_HINT: string = `Run \`${CLI_COMMAND_NAME} login\` (or set CURSOR_API_KEY / CURSOR_API_KEY_FILE / pass serve({ apiKey })).`;
344
+ export const SIGN_IN_HINT: string = `Run \`${CLI_COMMAND_NAME} login\` (or set CURSOR_API_KEY / CURSOR_API_KEY_FILE / CURSOR_SERVICE_ACCOUNT_KEY / pass serve({ apiKey })).`;
317
345
 
318
346
  // ============================================================================
319
347
  // PKCE browser login (mirrors cursor-agent / Sand)
@@ -285,6 +285,21 @@ export interface AgentkitStopAccepted {
285
285
  status: string;
286
286
  }
287
287
 
288
+ /**
289
+ * `POST /internal/agentsdk/deployments/:slug/sessions` 202 body. A hosted v2
290
+ * session start is a Temporal delivery: a fresh start allocates `ses_…`
291
+ * only after admission (poll the session list), so the ack is the delivery
292
+ * and workflow ids. `sessionId` is present only when the call resumed one.
293
+ */
294
+ export interface AgentkitStartSessionAccepted {
295
+ deliveryId: string;
296
+ workflowId: string;
297
+ sessionMode: "event" | "continuation";
298
+ sessionId?: string;
299
+ dryRun?: true;
300
+ asOf?: string;
301
+ }
302
+
288
303
  /** One secret's metadata from the list endpoint — names only, never values. */
289
304
  export interface SecretInfo {
290
305
  name: string;
@@ -373,6 +388,17 @@ const agentkitStopAcceptedSchema = z
373
388
  })
374
389
  .passthrough();
375
390
 
391
+ const agentkitStartSessionAcceptedSchema = z
392
+ .object({
393
+ deliveryId: z.string().min(1),
394
+ workflowId: z.string().min(1),
395
+ sessionMode: z.enum(["event", "continuation"]),
396
+ sessionId: z.string().min(1).optional(),
397
+ dryRun: z.literal(true).optional(),
398
+ asOf: z.string().min(1).optional(),
399
+ })
400
+ .passthrough();
401
+
376
402
  const deploymentSchema = z.object({
377
403
  id: z.number(),
378
404
  slug: z.string(),
@@ -675,6 +701,50 @@ export class AgentServeDeployClient {
675
701
  return agentkitStopAcceptedSchema.parse(raw);
676
702
  }
677
703
 
704
+ /**
705
+ * Delete a v2 deployment (`DELETE /internal/agentsdk/deployments/:slug`).
706
+ * 202 means accepted; poll {@link getAgentkitDeploy} until 404.
707
+ */
708
+ async deleteAgentkit(args: {
709
+ teamId: number;
710
+ slug: string;
711
+ }): Promise<AgentkitStopAccepted> {
712
+ const raw = await this.request({
713
+ method: "DELETE",
714
+ path: `/internal/agentsdk/deployments/${encodeURIComponent(args.slug)}?teamId=${args.teamId}`,
715
+ context: { verb: "delete", slug: args.slug },
716
+ });
717
+ return agentkitStopAcceptedSchema.parse(raw);
718
+ }
719
+
720
+ /**
721
+ * Start (or, with `sessionId`, resume) a hosted v2 session through the
722
+ * control plane (`POST /internal/agentsdk/deployments/:slug/sessions`).
723
+ * Does not talk to the v1 engine alias or `/engine/*`.
724
+ */
725
+ async startSession(args: {
726
+ teamId: number;
727
+ slug: string;
728
+ message: string;
729
+ sessionId?: string;
730
+ dryRun?: boolean;
731
+ asOf?: string;
732
+ }): Promise<AgentkitStartSessionAccepted> {
733
+ const raw = await this.request({
734
+ method: "POST",
735
+ path: `/internal/agentsdk/deployments/${encodeURIComponent(args.slug)}/sessions`,
736
+ body: {
737
+ teamId: args.teamId,
738
+ message: args.message,
739
+ sessionId: args.sessionId,
740
+ dryRun: args.dryRun === true ? true : undefined,
741
+ asOf: args.asOf,
742
+ },
743
+ context: { verb: "start session", slug: args.slug },
744
+ });
745
+ return agentkitStartSessionAcceptedSchema.parse(raw);
746
+ }
747
+
678
748
  async listDeployments(args: { teamId: number }): Promise<Deployment[]> {
679
749
  const raw = await this.request({
680
750
  method: "GET",
@@ -30,7 +30,11 @@
30
30
  */
31
31
 
32
32
  import { z } from "zod";
33
- import { isPublicEndpointPolicy } from "../channels.js";
33
+ import {
34
+ type CatchAuthDeclaration,
35
+ catchAuthDeclaration,
36
+ isPublicEndpointPolicy,
37
+ } from "../channels.js";
34
38
  import { isCursorHostedStorage } from "../storage-backends/cursor-hosted.js";
35
39
  import type { AgentProject, AgentProjectInfo } from "../types.js";
36
40
  import {
@@ -47,7 +51,7 @@ import {
47
51
  projectInfo,
48
52
  runtimeArchitectureCompatibilityError,
49
53
  } from "./discovery.js";
50
- import { packageVersion } from "./distribution.js";
54
+ import { packageGitSha, packageVersion } from "./distribution.js";
51
55
 
52
56
  export const DEPLOY_MANIFEST_VERSION: 1 = 1;
53
57
 
@@ -58,10 +62,48 @@ export const DEPLOY_MANIFEST_VERSION: 1 = 1;
58
62
  */
59
63
  const continuationIdentitySchema = z.enum(CONTINUATION_SELECTORS);
60
64
 
65
+ const CATCH_MAX_ROUTES = 32;
66
+ const CATCH_MAX_AUTH_POLICIES = 4;
67
+
68
+ const catchDeclarationSchema = z.object({
69
+ routes: z
70
+ .array(
71
+ z.object({
72
+ method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
73
+ path: z.string().min(1).max(1024),
74
+ })
75
+ )
76
+ .min(1)
77
+ .max(CATCH_MAX_ROUTES),
78
+ auth: z
79
+ .array(
80
+ z.discriminatedUnion("kind", [
81
+ z.object({
82
+ kind: z.literal("header"),
83
+ header: z.string().min(1).max(128),
84
+ secret: z.string().min(1).max(64),
85
+ }),
86
+ z.object({
87
+ kind: z.literal("hmac-sha256"),
88
+ header: z.string().min(1).max(128),
89
+ secret: z.string().min(1).max(64),
90
+ prefix: z.string().max(32).optional(),
91
+ }),
92
+ z.object({ kind: z.literal("public") }),
93
+ ])
94
+ )
95
+ .min(1)
96
+ .max(CATCH_MAX_AUTH_POLICIES),
97
+ });
98
+
61
99
  const agentDeployManifestV1Schema = z.object({
62
100
  manifestVersion: z.literal(DEPLOY_MANIFEST_VERSION),
63
101
  generatedAtMs: z.number().int().nonnegative(),
64
102
  cliVersion: z.string().min(1),
103
+ cliGitSha: z
104
+ .string()
105
+ .regex(/^[0-9a-f]{40,64}$/)
106
+ .optional(),
65
107
  declarations: z.object({
66
108
  egressDomains: z.array(z.string().min(1)).max(64),
67
109
  publicRoutePaths: z.array(z.string().min(1)).max(64),
@@ -74,6 +116,7 @@ const agentDeployManifestV1Schema = z.object({
74
116
  kind: z.string().min(1).max(32).optional(),
75
117
  eventTypes: z.array(z.string().min(1).max(64)).max(64).optional(),
76
118
  continuation: continuationIdentitySchema,
119
+ catch: catchDeclarationSchema.optional(),
77
120
  })
78
121
  )
79
122
  .max(64),
@@ -106,7 +149,22 @@ export interface AgentDeployManifestDeclarations {
106
149
  kind?: string;
107
150
  eventTypes?: string[];
108
151
  continuation: ContinuationIdentity;
152
+ /**
153
+ * Control-plane catch routes: present only for an authored channel
154
+ * whose auth chain carries a `sharedSecretAuth` / `hmacSignatureAuth`
155
+ * policy. The control plane accepts exactly these `(method, path)`
156
+ * pairs and verifies the named deployment secret before any compute.
157
+ */
158
+ catch?: AgentDeployManifestCatchDeclaration;
159
+ }>;
160
+ }
161
+
162
+ export interface AgentDeployManifestCatchDeclaration {
163
+ routes: Array<{
164
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
165
+ path: string;
109
166
  }>;
167
+ auth: CatchAuthDeclaration[];
110
168
  }
111
169
 
112
170
  export interface AgentDeployManifestV1 {
@@ -115,6 +173,8 @@ export interface AgentDeployManifestV1 {
115
173
  generatedAtMs: number;
116
174
  /** `@cursor/july` version that produced the manifest. */
117
175
  cliVersion: string;
176
+ /** Git commit for a checkout-built `@cursor/july`; absent for npm builds. */
177
+ cliGitSha?: string;
118
178
  declarations: AgentDeployManifestDeclarations;
119
179
  /**
120
180
  * Full `projectInfo` payload (see `GET /v1/info`). Opaque to the wire
@@ -129,7 +189,7 @@ export interface AgentDeployManifestV1 {
129
189
  */
130
190
  export function buildAgentDeployManifest(
131
191
  project: AgentProject,
132
- options?: { nowMs?: number; cliVersion?: string }
192
+ options?: { nowMs?: number; cliVersion?: string; cliGitSha?: string }
133
193
  ): AgentDeployManifestV1 {
134
194
  const runtimeArchitectureError = runtimeArchitectureCompatibilityError(
135
195
  project.agent
@@ -152,6 +212,7 @@ export function buildAgentDeployManifest(
152
212
  kind,
153
213
  eventTypes,
154
214
  continuation: channelContinuationIdentity(channel.definition),
215
+ catch: channelCatchDeclaration(channel.definition),
155
216
  };
156
217
  });
157
218
 
@@ -167,20 +228,19 @@ export function buildAgentDeployManifest(
167
228
  manifestVersion: DEPLOY_MANIFEST_VERSION,
168
229
  generatedAtMs: options?.nowMs ?? Date.now(),
169
230
  cliVersion: options?.cliVersion ?? packageVersion(),
231
+ cliGitSha: options?.cliGitSha ?? packageGitSha(),
170
232
  declarations: {
171
233
  egressDomains: [...(project.agent.hosting?.egressDomains ?? [])],
172
234
  publicRoutePaths,
173
- // v2 ignores authored storage; deploy manifests describe
174
- // Cursor-hosted deployments, where framework-storage-selection.ts
175
- // injects the Cursor-hosted mirror.
235
+ // Deploy manifests describe Cursor-hosted deployments. When the agent
236
+ // authors no storage, framework-storage-selection.ts injects the
237
+ // platform Cursor-hosted mirror for both v1 and v2.
176
238
  frameworkStorage:
177
- project.agent.architecture === "v2"
239
+ project.storage === undefined
178
240
  ? "cursor-hosted"
179
- : project.storage === undefined
180
- ? "none"
181
- : isCursorHostedStorage(project.storage)
182
- ? "cursor-hosted"
183
- : "other",
241
+ : isCursorHostedStorage(project.storage)
242
+ ? "cursor-hosted"
243
+ : "other",
184
244
  ...(project.agent.architecture === undefined
185
245
  ? {}
186
246
  : { architecture: project.agent.architecture }),
@@ -190,6 +250,65 @@ export function buildAgentDeployManifest(
190
250
  };
191
251
  }
192
252
 
253
+ /**
254
+ * Catch declaration for one authored channel: its routes, gated by the
255
+ * catch-capable policies in its auth chain (`sharedSecretAuth`,
256
+ * `hmacSignatureAuth`, or `publicEndpoint()` for handler-verified routes).
257
+ * A routed channel with none of those declares nothing and is not reachable
258
+ * through the catch API.
259
+ */
260
+ export function channelCatchDeclaration(
261
+ definition: AgentProject["channels"][number]["definition"]
262
+ ): AgentDeployManifestCatchDeclaration | undefined {
263
+ const routes = definition.routes ?? [];
264
+ if (routes.length === 0) {
265
+ return undefined;
266
+ }
267
+ const declared = (definition.auth ?? [])
268
+ .map(catchAuthDeclaration)
269
+ .filter((declaration) => declaration !== undefined);
270
+ if (declared.length === 0) {
271
+ return undefined;
272
+ }
273
+ // An auth chain is any-of, so `publicEndpoint()` beside secret policies
274
+ // admits everything locally and on the control plane alike. Declare one
275
+ // `public` entry (the control plane then decrypts nothing) but keep the
276
+ // shared-secret header policies next to it: they are what the control
277
+ // plane uses to strip those header values before the request is
278
+ // claim-checked, and senders keep sending the secret regardless of
279
+ // whether anything still checks it. HMAC policies carry body digests,
280
+ // not secrets, so nothing is lost by dropping them.
281
+ const isPublic = declared.some((policy) => policy.kind === "public");
282
+ const auth = isPublic
283
+ ? [
284
+ { kind: "public" as const },
285
+ ...declared.filter((policy) => policy.kind === "header"),
286
+ ]
287
+ : declared;
288
+ if (routes.length > CATCH_MAX_ROUTES) {
289
+ if (isPublic) {
290
+ // publicEndpoint() channels deployed before catch existed; they stay
291
+ // reachable the way they were (not through catch) rather than
292
+ // failing the deploy.
293
+ return undefined;
294
+ }
295
+ throw new Error(
296
+ `Catch channels may declare at most ${CATCH_MAX_ROUTES} routes (got ${routes.length}).`
297
+ );
298
+ }
299
+ if (auth.length > CATCH_MAX_AUTH_POLICIES) {
300
+ throw new Error(
301
+ isPublic
302
+ ? `Catch channels may declare at most ${CATCH_MAX_AUTH_POLICIES} auth policies; publicEndpoint() plus ${String(auth.length - 1)} sharedSecretAuth() policies is ${String(auth.length)}. Drop publicEndpoint() or the shared-secret policies it makes dead.`
303
+ : `Catch channels may declare at most ${CATCH_MAX_AUTH_POLICIES} secret policies (got ${auth.length}).`
304
+ );
305
+ }
306
+ return {
307
+ routes: routes.map((route) => ({ method: route.method, path: route.path })),
308
+ auth,
309
+ };
310
+ }
311
+
193
312
  /**
194
313
  * Parse an untrusted manifest (round-trip check for the CLI's own output;
195
314
  * the CP re-validates server-side with its own copy of the contract).
@@ -2,3 +2,31 @@
2
2
  export function describeError(error: unknown): string {
3
3
  return error instanceof Error ? error.message : String(error);
4
4
  }
5
+
6
+ export function describeErrorCode(error: unknown): string | undefined {
7
+ if (typeof error === "object" && error !== null && "code" in error) {
8
+ const numericCode = (error as { code?: unknown }).code;
9
+ if (numericCode === 1) {
10
+ return "canceled";
11
+ }
12
+ if (numericCode === 14) {
13
+ return "unavailable";
14
+ }
15
+ if (numericCode === 2) {
16
+ return "unknown";
17
+ }
18
+ }
19
+ if (
20
+ typeof error === "object" &&
21
+ error !== null &&
22
+ "name" in error &&
23
+ (error as { name?: unknown }).name === "AbortError"
24
+ ) {
25
+ return "ABORT_ERR";
26
+ }
27
+ if (typeof error !== "object" || error === null || !("code" in error)) {
28
+ return undefined;
29
+ }
30
+ const code = (error as { code?: unknown }).code;
31
+ return typeof code === "string" && code.length <= 64 ? code : undefined;
32
+ }
@@ -372,6 +372,7 @@ export async function warnUnknownSlots(
372
372
  "subagents",
373
373
  "channels",
374
374
  "schedules",
375
+ "reminders",
375
376
  "hooks",
376
377
  "ab",
377
378
  "sandbox",
@@ -151,6 +151,12 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
151
151
  cron: schedule.cron,
152
152
  kind: schedule.kind,
153
153
  })),
154
+ reminders:
155
+ (project.reminders ?? []).length === 0
156
+ ? undefined
157
+ : (project.reminders ?? []).map((reminder) => ({
158
+ name: reminder.name,
159
+ })),
154
160
  hooks: project.hooks.map((hook) => hook.name),
155
161
  abs: project.abs.map((experiment) => experiment.name),
156
162
  ...(project.abConfig === undefined && project.abs.length === 0
@@ -9,10 +9,7 @@ import { type DiscoveryContext, displayPath, errorMessage } from "./context.js";
9
9
  import { isDirectory, isModuleFile, moduleStem, sortedEntries } from "./fs.js";
10
10
  import { validateName } from "./names.js";
11
11
 
12
- type ImportableKind = Exclude<
13
- DefinitionKind,
14
- "instructions" | "eval" | "reminder"
15
- >;
12
+ type ImportableKind = Exclude<DefinitionKind, "instructions" | "eval">;
16
13
 
17
14
  /** The module files of a slot directory whose filenames are valid names. */
18
15
  export async function moduleEntries(
@@ -104,6 +101,7 @@ const DEFINE_HELPER_NAME: Record<ImportableKind, string> = {
104
101
  channel: "defineChannel",
105
102
  "http-channel": "httpChannel",
106
103
  schedule: "defineSchedule",
104
+ reminder: "defineReminder",
107
105
  hook: "defineHook",
108
106
  ab: "defineAB",
109
107
  storage: "defineStorage",
@@ -31,6 +31,7 @@ import {
31
31
  } from "./fs.js";
32
32
  import { loadHooks } from "./hooks.js";
33
33
  import { NAME_PATTERN } from "./names.js";
34
+ import { loadReminders } from "./reminders.js";
34
35
  import { loadSchedules } from "./schedules.js";
35
36
  import {
36
37
  appendArtifactTool,
@@ -236,6 +237,7 @@ export async function loadAgentProject(
236
237
  }
237
238
  const schedules = await loadSchedules(ctx, join(agentDir, "schedules"));
238
239
  schedules.push(...projectSlots.schedules);
240
+ const reminders = await loadReminders(ctx, join(agentDir, "reminders"));
239
241
  const hooks = await loadHooks(ctx, join(agentDir, "hooks"));
240
242
  hooks.push(...projectSlots.hooks);
241
243
  const abs = await loadABs(ctx, agentDir);
@@ -291,6 +293,7 @@ export async function loadAgentProject(
291
293
  httpChannel: resolvedHttpChannel,
292
294
  channels,
293
295
  schedules,
296
+ reminders,
294
297
  hooks,
295
298
  abs,
296
299
  abConfig,
@@ -0,0 +1,65 @@
1
+ /**
2
+ * `agent/reminders/*.ts`: named durable reminder fire handlers.
3
+ */
4
+
5
+ import { basename, extname, relative } from "node:path";
6
+ import type { DiscoveredReminder, ReminderDefinition } from "../../types.js";
7
+ import { getDefinitionKind } from "../brand.js";
8
+ import { type DiscoveryContext, displayPath } from "./context.js";
9
+ import { isDirectory, isModuleFile, toPosix, walkFiles } from "./fs.js";
10
+ import { importDefault } from "./modules.js";
11
+ import { NAME_PATTERN } from "./names.js";
12
+
13
+ export async function loadReminders(
14
+ ctx: DiscoveryContext,
15
+ remindersDir: string,
16
+ onDisable?: (name: string, path: string) => void
17
+ ): Promise<DiscoveredReminder[]> {
18
+ if (!(await isDirectory(remindersDir))) {
19
+ return [];
20
+ }
21
+ const reminders: DiscoveredReminder[] = [];
22
+ for (const filePath of await walkFiles(remindersDir)) {
23
+ const rel = toPosix(relative(remindersDir, filePath));
24
+ if (!isModuleFile(basename(filePath))) {
25
+ continue;
26
+ }
27
+ const name = rel.slice(0, -extname(rel).length);
28
+ if (!NAME_PATTERN.test(name) || name.includes("__")) {
29
+ ctx.diagnostics.push({
30
+ severity: "error",
31
+ path: displayPath(ctx, filePath),
32
+ message: name.includes("__")
33
+ ? `Reminder name "${name}" may not contain "__"; it is reserved for extension contributions (\`<ns>__<name>\`).`
34
+ : `Reminder name "${name}" must match ${NAME_PATTERN}.`,
35
+ });
36
+ continue;
37
+ }
38
+ const definition = await importDefault(
39
+ ctx,
40
+ filePath,
41
+ onDisable === undefined ? "reminder" : ["reminder", "disabled"]
42
+ );
43
+ if (definition === undefined) {
44
+ continue;
45
+ }
46
+ if (getDefinitionKind(definition) === "disabled") {
47
+ onDisable?.(name, filePath);
48
+ continue;
49
+ }
50
+ const reminder = definition as ReminderDefinition;
51
+ if (typeof reminder.run !== "function") {
52
+ ctx.diagnostics.push({
53
+ severity: "error",
54
+ path: displayPath(ctx, filePath),
55
+ message: "Reminder handlers require a `run` function.",
56
+ });
57
+ continue;
58
+ }
59
+ reminders.push({
60
+ name,
61
+ definition: reminder,
62
+ });
63
+ }
64
+ return reminders;
65
+ }
@@ -121,6 +121,7 @@ async function warnUnsupportedSubagentSlots(
121
121
  ["subagents", "nested subagents"],
122
122
  ["channels", "channels"],
123
123
  ["schedules", "schedules"],
124
+ ["reminders", "reminders"],
124
125
  ["hooks", "hooks"],
125
126
  ["sandbox", "sandbox files"],
126
127
  ] as const;