@cursor/july 0.1.1

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 (623) hide show
  1. package/AGENTS.md +290 -0
  2. package/LICENSE.md +3 -0
  3. package/README.md +1233 -0
  4. package/dist/ab.d.ts +290 -0
  5. package/dist/ab.d.ts.map +1 -0
  6. package/dist/ab.js +386 -0
  7. package/dist/bin/agent-serve.d.ts +15 -0
  8. package/dist/bin/agent-serve.d.ts.map +1 -0
  9. package/dist/bin/agent-serve.js +754 -0
  10. package/dist/channels/github/api.d.ts +101 -0
  11. package/dist/channels/github/api.d.ts.map +1 -0
  12. package/dist/channels/github/api.js +229 -0
  13. package/dist/channels/github/auth.d.ts +67 -0
  14. package/dist/channels/github/auth.d.ts.map +1 -0
  15. package/dist/channels/github/auth.js +239 -0
  16. package/dist/channels/github/binding.d.ts +73 -0
  17. package/dist/channels/github/binding.d.ts.map +1 -0
  18. package/dist/channels/github/binding.js +114 -0
  19. package/dist/channels/github/defaults.d.ts +24 -0
  20. package/dist/channels/github/defaults.d.ts.map +1 -0
  21. package/dist/channels/github/defaults.js +100 -0
  22. package/dist/channels/github/events.d.ts +18 -0
  23. package/dist/channels/github/events.d.ts.map +1 -0
  24. package/dist/channels/github/events.js +59 -0
  25. package/dist/channels/github/forward.d.ts +137 -0
  26. package/dist/channels/github/forward.d.ts.map +1 -0
  27. package/dist/channels/github/forward.js +271 -0
  28. package/dist/channels/github/github-channel.d.ts +127 -0
  29. package/dist/channels/github/github-channel.d.ts.map +1 -0
  30. package/dist/channels/github/github-channel.js +1688 -0
  31. package/dist/channels/github/index.d.ts +52 -0
  32. package/dist/channels/github/index.d.ts.map +1 -0
  33. package/dist/channels/github/index.js +51 -0
  34. package/dist/channels/github/replay.d.ts +115 -0
  35. package/dist/channels/github/replay.d.ts.map +1 -0
  36. package/dist/channels/github/replay.js +282 -0
  37. package/dist/channels/github/state.d.ts +26 -0
  38. package/dist/channels/github/state.d.ts.map +1 -0
  39. package/dist/channels/github/state.js +50 -0
  40. package/dist/channels/github/types.d.ts +385 -0
  41. package/dist/channels/github/types.d.ts.map +1 -0
  42. package/dist/channels/github/types.js +1 -0
  43. package/dist/channels/slack/api.d.ts +117 -0
  44. package/dist/channels/slack/api.d.ts.map +1 -0
  45. package/dist/channels/slack/api.js +437 -0
  46. package/dist/channels/slack/approvals.d.ts +32 -0
  47. package/dist/channels/slack/approvals.d.ts.map +1 -0
  48. package/dist/channels/slack/approvals.js +157 -0
  49. package/dist/channels/slack/assistant.d.ts +23 -0
  50. package/dist/channels/slack/assistant.d.ts.map +1 -0
  51. package/dist/channels/slack/assistant.js +67 -0
  52. package/dist/channels/slack/auth.d.ts +40 -0
  53. package/dist/channels/slack/auth.d.ts.map +1 -0
  54. package/dist/channels/slack/auth.js +71 -0
  55. package/dist/channels/slack/channel-watch.d.ts +46 -0
  56. package/dist/channels/slack/channel-watch.d.ts.map +1 -0
  57. package/dist/channels/slack/channel-watch.js +180 -0
  58. package/dist/channels/slack/constants.d.ts +17 -0
  59. package/dist/channels/slack/constants.d.ts.map +1 -0
  60. package/dist/channels/slack/constants.js +27 -0
  61. package/dist/channels/slack/credentials.d.ts +35 -0
  62. package/dist/channels/slack/credentials.d.ts.map +1 -0
  63. package/dist/channels/slack/credentials.js +88 -0
  64. package/dist/channels/slack/cursor-account.d.ts +76 -0
  65. package/dist/channels/slack/cursor-account.d.ts.map +1 -0
  66. package/dist/channels/slack/cursor-account.js +88 -0
  67. package/dist/channels/slack/defaults.d.ts +32 -0
  68. package/dist/channels/slack/defaults.d.ts.map +1 -0
  69. package/dist/channels/slack/defaults.js +380 -0
  70. package/dist/channels/slack/dispatch.d.ts +43 -0
  71. package/dist/channels/slack/dispatch.d.ts.map +1 -0
  72. package/dist/channels/slack/dispatch.js +185 -0
  73. package/dist/channels/slack/doctor.d.ts +24 -0
  74. package/dist/channels/slack/doctor.d.ts.map +1 -0
  75. package/dist/channels/slack/doctor.js +115 -0
  76. package/dist/channels/slack/event-id-dedupe.d.ts +10 -0
  77. package/dist/channels/slack/event-id-dedupe.d.ts.map +1 -0
  78. package/dist/channels/slack/event-id-dedupe.js +23 -0
  79. package/dist/channels/slack/inbound.d.ts +41 -0
  80. package/dist/channels/slack/inbound.d.ts.map +1 -0
  81. package/dist/channels/slack/inbound.js +166 -0
  82. package/dist/channels/slack/index.d.ts +45 -0
  83. package/dist/channels/slack/index.d.ts.map +1 -0
  84. package/dist/channels/slack/index.js +44 -0
  85. package/dist/channels/slack/init.d.ts +32 -0
  86. package/dist/channels/slack/init.d.ts.map +1 -0
  87. package/dist/channels/slack/init.js +82 -0
  88. package/dist/channels/slack/interactive.d.ts +19 -0
  89. package/dist/channels/slack/interactive.d.ts.map +1 -0
  90. package/dist/channels/slack/interactive.js +142 -0
  91. package/dist/channels/slack/links.d.ts +10 -0
  92. package/dist/channels/slack/links.d.ts.map +1 -0
  93. package/dist/channels/slack/links.js +19 -0
  94. package/dist/channels/slack/live-delivery.d.ts +75 -0
  95. package/dist/channels/slack/live-delivery.d.ts.map +1 -0
  96. package/dist/channels/slack/live-delivery.js +143 -0
  97. package/dist/channels/slack/log.d.ts +25 -0
  98. package/dist/channels/slack/log.d.ts.map +1 -0
  99. package/dist/channels/slack/log.js +47 -0
  100. package/dist/channels/slack/manifest.d.ts +57 -0
  101. package/dist/channels/slack/manifest.d.ts.map +1 -0
  102. package/dist/channels/slack/manifest.js +110 -0
  103. package/dist/channels/slack/pr-ref.d.ts +18 -0
  104. package/dist/channels/slack/pr-ref.d.ts.map +1 -0
  105. package/dist/channels/slack/pr-ref.js +36 -0
  106. package/dist/channels/slack/setup.d.ts +14 -0
  107. package/dist/channels/slack/setup.d.ts.map +1 -0
  108. package/dist/channels/slack/setup.js +86 -0
  109. package/dist/channels/slack/slack-channel.d.ts +15 -0
  110. package/dist/channels/slack/slack-channel.d.ts.map +1 -0
  111. package/dist/channels/slack/slack-channel.js +281 -0
  112. package/dist/channels/slack/socket-mode.d.ts +26 -0
  113. package/dist/channels/slack/socket-mode.d.ts.map +1 -0
  114. package/dist/channels/slack/socket-mode.js +116 -0
  115. package/dist/channels/slack/stream.d.ts +26 -0
  116. package/dist/channels/slack/stream.d.ts.map +1 -0
  117. package/dist/channels/slack/stream.js +39 -0
  118. package/dist/channels/slack/tool-approval-events.d.ts +33 -0
  119. package/dist/channels/slack/tool-approval-events.d.ts.map +1 -0
  120. package/dist/channels/slack/tool-approval-events.js +129 -0
  121. package/dist/channels/slack/types.d.ts +326 -0
  122. package/dist/channels/slack/types.d.ts.map +1 -0
  123. package/dist/channels/slack/types.js +4 -0
  124. package/dist/channels.d.ts +116 -0
  125. package/dist/channels.d.ts.map +1 -0
  126. package/dist/channels.js +294 -0
  127. package/dist/connections.d.ts +75 -0
  128. package/dist/connections.d.ts.map +1 -0
  129. package/dist/connections.js +75 -0
  130. package/dist/docs/404.html +22 -0
  131. package/dist/docs/ab.html +87 -0
  132. package/dist/docs/assets/ab.md.COdXkces.js +63 -0
  133. package/dist/docs/assets/ab.md.COdXkces.lean.js +1 -0
  134. package/dist/docs/assets/app.DqfFEmJd.js +1 -0
  135. package/dist/docs/assets/building-with-agents.md.CJCtZCyi.js +13 -0
  136. package/dist/docs/assets/building-with-agents.md.CJCtZCyi.lean.js +1 -0
  137. package/dist/docs/assets/chunks/@localSearchIndexroot.CcVk1uKq.js +1 -0
  138. package/dist/docs/assets/chunks/VPLocalSearchBox.BaLEdS15.js +9 -0
  139. package/dist/docs/assets/chunks/framework.CAZyNGu9.js +19 -0
  140. package/dist/docs/assets/chunks/theme.CZRvu_0q.js +2 -0
  141. package/dist/docs/assets/concepts.md.Cfb9b-k1.js +4 -0
  142. package/dist/docs/assets/concepts.md.Cfb9b-k1.lean.js +1 -0
  143. package/dist/docs/assets/deployment.md.Dx1TYNk5.js +14 -0
  144. package/dist/docs/assets/deployment.md.Dx1TYNk5.lean.js +1 -0
  145. package/dist/docs/assets/evals.md.DPZ_MAnI.js +85 -0
  146. package/dist/docs/assets/evals.md.DPZ_MAnI.lean.js +1 -0
  147. package/dist/docs/assets/guides_agent-to-agent.md.CrtrsySy.js +10 -0
  148. package/dist/docs/assets/guides_agent-to-agent.md.CrtrsySy.lean.js +1 -0
  149. package/dist/docs/assets/guides_cloud-runtime.md.CYlNMTNp.js +9 -0
  150. package/dist/docs/assets/guides_cloud-runtime.md.CYlNMTNp.lean.js +1 -0
  151. package/dist/docs/assets/guides_github.md.DwbKhCeS.js +20 -0
  152. package/dist/docs/assets/guides_github.md.DwbKhCeS.lean.js +1 -0
  153. package/dist/docs/assets/guides_human-in-the-loop.md.Dvuctx7s.js +28 -0
  154. package/dist/docs/assets/guides_human-in-the-loop.md.Dvuctx7s.lean.js +1 -0
  155. package/dist/docs/assets/guides_slack.md.bv41fHfW.js +37 -0
  156. package/dist/docs/assets/guides_slack.md.bv41fHfW.lean.js +1 -0
  157. package/dist/docs/assets/guides_webhooks.md.hFTik3lf.js +50 -0
  158. package/dist/docs/assets/guides_webhooks.md.hFTik3lf.lean.js +1 -0
  159. package/dist/docs/assets/hillclimbing.md.DHNast08.js +4 -0
  160. package/dist/docs/assets/hillclimbing.md.DHNast08.lean.js +1 -0
  161. package/dist/docs/assets/index.md.BPKcj5AI.js +20 -0
  162. package/dist/docs/assets/index.md.BPKcj5AI.lean.js +1 -0
  163. package/dist/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  164. package/dist/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  165. package/dist/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  166. package/dist/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  167. package/dist/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  168. package/dist/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  169. package/dist/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  170. package/dist/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  171. package/dist/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  172. package/dist/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  173. package/dist/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  174. package/dist/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  175. package/dist/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  176. package/dist/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  177. package/dist/docs/assets/quickstart.md.tVPiGK_L.js +35 -0
  178. package/dist/docs/assets/quickstart.md.tVPiGK_L.lean.js +1 -0
  179. package/dist/docs/assets/reference_agent-config.md.Bpd7HQwf.js +34 -0
  180. package/dist/docs/assets/reference_agent-config.md.Bpd7HQwf.lean.js +1 -0
  181. package/dist/docs/assets/reference_channels.md.D7JTR03W.js +53 -0
  182. package/dist/docs/assets/reference_channels.md.D7JTR03W.lean.js +1 -0
  183. package/dist/docs/assets/reference_cli.md.DA730zCu.js +33 -0
  184. package/dist/docs/assets/reference_cli.md.DA730zCu.lean.js +1 -0
  185. package/dist/docs/assets/reference_connections.md.C3vNH_DE.js +26 -0
  186. package/dist/docs/assets/reference_connections.md.C3vNH_DE.lean.js +1 -0
  187. package/dist/docs/assets/reference_hooks.md.BCEc3MyM.js +12 -0
  188. package/dist/docs/assets/reference_hooks.md.BCEc3MyM.lean.js +1 -0
  189. package/dist/docs/assets/reference_http-api.md.DBAahtdz.js +11 -0
  190. package/dist/docs/assets/reference_http-api.md.DBAahtdz.lean.js +1 -0
  191. package/dist/docs/assets/reference_instructions.md.BC05LEQ8.js +12 -0
  192. package/dist/docs/assets/reference_instructions.md.BC05LEQ8.lean.js +1 -0
  193. package/dist/docs/assets/reference_playground.md.CPZhfYaO.js +1 -0
  194. package/dist/docs/assets/reference_playground.md.CPZhfYaO.lean.js +1 -0
  195. package/dist/docs/assets/reference_project-layout.md.Bd_CKtNS.js +31 -0
  196. package/dist/docs/assets/reference_project-layout.md.Bd_CKtNS.lean.js +1 -0
  197. package/dist/docs/assets/reference_schedules.md.D7qijxLk.js +82 -0
  198. package/dist/docs/assets/reference_schedules.md.D7qijxLk.lean.js +1 -0
  199. package/dist/docs/assets/reference_sessions.md.DdjWabnN.js +8 -0
  200. package/dist/docs/assets/reference_sessions.md.DdjWabnN.lean.js +1 -0
  201. package/dist/docs/assets/reference_skills.md.VQnlBT3Q.js +15 -0
  202. package/dist/docs/assets/reference_skills.md.VQnlBT3Q.lean.js +1 -0
  203. package/dist/docs/assets/reference_subagents.md.CIRAVcPK.js +10 -0
  204. package/dist/docs/assets/reference_subagents.md.CIRAVcPK.lean.js +1 -0
  205. package/dist/docs/assets/reference_tools.md.DF5kwlt0.js +46 -0
  206. package/dist/docs/assets/reference_tools.md.DF5kwlt0.lean.js +1 -0
  207. package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.js +1 -0
  208. package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.lean.js +1 -0
  209. package/dist/docs/assets/style.Bj-IXa5W.css +1 -0
  210. package/dist/docs/assets/troubleshooting.md.DkovjS7h.js +1 -0
  211. package/dist/docs/assets/troubleshooting.md.DkovjS7h.lean.js +1 -0
  212. package/dist/docs/building-with-agents.html +37 -0
  213. package/dist/docs/concepts.html +28 -0
  214. package/dist/docs/deployment.html +38 -0
  215. package/dist/docs/evals.html +109 -0
  216. package/dist/docs/guides/agent-to-agent.html +34 -0
  217. package/dist/docs/guides/cloud-runtime.html +33 -0
  218. package/dist/docs/guides/github.html +44 -0
  219. package/dist/docs/guides/human-in-the-loop.html +52 -0
  220. package/dist/docs/guides/slack.html +61 -0
  221. package/dist/docs/guides/webhooks.html +74 -0
  222. package/dist/docs/hashmap.json +1 -0
  223. package/dist/docs/hillclimbing.html +28 -0
  224. package/dist/docs/index.html +44 -0
  225. package/dist/docs/quickstart.html +59 -0
  226. package/dist/docs/reference/agent-config.html +58 -0
  227. package/dist/docs/reference/channels.html +77 -0
  228. package/dist/docs/reference/cli.html +57 -0
  229. package/dist/docs/reference/connections.html +50 -0
  230. package/dist/docs/reference/hooks.html +36 -0
  231. package/dist/docs/reference/http-api.html +35 -0
  232. package/dist/docs/reference/instructions.html +36 -0
  233. package/dist/docs/reference/playground.html +25 -0
  234. package/dist/docs/reference/project-layout.html +55 -0
  235. package/dist/docs/reference/schedules.html +106 -0
  236. package/dist/docs/reference/sessions.html +32 -0
  237. package/dist/docs/reference/skills.html +39 -0
  238. package/dist/docs/reference/subagents.html +34 -0
  239. package/dist/docs/reference/tools.html +70 -0
  240. package/dist/docs/scaffolding-agents.html +25 -0
  241. package/dist/docs/troubleshooting.html +25 -0
  242. package/dist/docs/vp-icons.css +0 -0
  243. package/dist/evals.d.ts +312 -0
  244. package/dist/evals.d.ts.map +1 -0
  245. package/dist/evals.js +254 -0
  246. package/dist/hooks.d.ts +23 -0
  247. package/dist/hooks.d.ts.map +1 -0
  248. package/dist/hooks.js +23 -0
  249. package/dist/index.d.ts +71 -0
  250. package/dist/index.d.ts.map +1 -0
  251. package/dist/index.js +101 -0
  252. package/dist/internal/ab-collector.d.ts +42 -0
  253. package/dist/internal/ab-collector.d.ts.map +1 -0
  254. package/dist/internal/ab-collector.js +153 -0
  255. package/dist/internal/ab-fold.d.ts +36 -0
  256. package/dist/internal/ab-fold.d.ts.map +1 -0
  257. package/dist/internal/ab-fold.js +171 -0
  258. package/dist/internal/ab-snapshot.d.ts +70 -0
  259. package/dist/internal/ab-snapshot.d.ts.map +1 -0
  260. package/dist/internal/ab-snapshot.js +208 -0
  261. package/dist/internal/approval-gate.d.ts +34 -0
  262. package/dist/internal/approval-gate.d.ts.map +1 -0
  263. package/dist/internal/approval-gate.js +85 -0
  264. package/dist/internal/auth.d.ts +8 -0
  265. package/dist/internal/auth.d.ts.map +1 -0
  266. package/dist/internal/auth.js +27 -0
  267. package/dist/internal/authored-alias-hooks.d.ts +31 -0
  268. package/dist/internal/authored-alias-hooks.d.ts.map +1 -0
  269. package/dist/internal/authored-alias-hooks.js +43 -0
  270. package/dist/internal/authored-loaders.d.ts +25 -0
  271. package/dist/internal/authored-loaders.d.ts.map +1 -0
  272. package/dist/internal/authored-loaders.js +129 -0
  273. package/dist/internal/bounded-int.d.ts +11 -0
  274. package/dist/internal/bounded-int.d.ts.map +1 -0
  275. package/dist/internal/bounded-int.js +13 -0
  276. package/dist/internal/brand.d.ts +6 -0
  277. package/dist/internal/brand.d.ts.map +1 -0
  278. package/dist/internal/brand.js +17 -0
  279. package/dist/internal/chat-client.d.ts +19 -0
  280. package/dist/internal/chat-client.d.ts.map +1 -0
  281. package/dist/internal/chat-client.js +327 -0
  282. package/dist/internal/cli-ax.d.ts +58 -0
  283. package/dist/internal/cli-ax.d.ts.map +1 -0
  284. package/dist/internal/cli-ax.js +345 -0
  285. package/dist/internal/cli-cursor.d.ts +20 -0
  286. package/dist/internal/cli-cursor.d.ts.map +1 -0
  287. package/dist/internal/cli-cursor.js +227 -0
  288. package/dist/internal/cli-github.d.ts +47 -0
  289. package/dist/internal/cli-github.d.ts.map +1 -0
  290. package/dist/internal/cli-github.js +644 -0
  291. package/dist/internal/cli-slack.d.ts +18 -0
  292. package/dist/internal/cli-slack.d.ts.map +1 -0
  293. package/dist/internal/cli-slack.js +144 -0
  294. package/dist/internal/cloud-merge.d.ts +23 -0
  295. package/dist/internal/cloud-merge.d.ts.map +1 -0
  296. package/dist/internal/cloud-merge.js +28 -0
  297. package/dist/internal/cron.d.ts +17 -0
  298. package/dist/internal/cron.d.ts.map +1 -0
  299. package/dist/internal/cron.js +60 -0
  300. package/dist/internal/cursor/account-mcp.d.ts +95 -0
  301. package/dist/internal/cursor/account-mcp.d.ts.map +1 -0
  302. package/dist/internal/cursor/account-mcp.js +342 -0
  303. package/dist/internal/cursor/backend-client.d.ts +118 -0
  304. package/dist/internal/cursor/backend-client.d.ts.map +1 -0
  305. package/dist/internal/cursor/backend-client.js +477 -0
  306. package/dist/internal/cursor/credentials.d.ts +112 -0
  307. package/dist/internal/cursor/credentials.d.ts.map +1 -0
  308. package/dist/internal/cursor/credentials.js +329 -0
  309. package/dist/internal/cursor-event-relay.d.ts +111 -0
  310. package/dist/internal/cursor-event-relay.d.ts.map +1 -0
  311. package/dist/internal/cursor-event-relay.js +181 -0
  312. package/dist/internal/cursor-relay-core.d.ts +113 -0
  313. package/dist/internal/cursor-relay-core.d.ts.map +1 -0
  314. package/dist/internal/cursor-relay-core.js +364 -0
  315. package/dist/internal/cursor-slack-relay.d.ts +94 -0
  316. package/dist/internal/cursor-slack-relay.d.ts.map +1 -0
  317. package/dist/internal/cursor-slack-relay.js +171 -0
  318. package/dist/internal/describe-error.d.ts +3 -0
  319. package/dist/internal/describe-error.d.ts.map +1 -0
  320. package/dist/internal/describe-error.js +4 -0
  321. package/dist/internal/dev-mode.d.ts +13 -0
  322. package/dist/internal/dev-mode.d.ts.map +1 -0
  323. package/dist/internal/dev-mode.js +17 -0
  324. package/dist/internal/discovery.d.ts +55 -0
  325. package/dist/internal/discovery.d.ts.map +1 -0
  326. package/dist/internal/discovery.js +1427 -0
  327. package/dist/internal/distribution.d.ts +47 -0
  328. package/dist/internal/distribution.d.ts.map +1 -0
  329. package/dist/internal/distribution.js +82 -0
  330. package/dist/internal/docs-site.d.ts +28 -0
  331. package/dist/internal/docs-site.d.ts.map +1 -0
  332. package/dist/internal/docs-site.js +169 -0
  333. package/dist/internal/duration.d.ts +8 -0
  334. package/dist/internal/duration.d.ts.map +1 -0
  335. package/dist/internal/duration.js +35 -0
  336. package/dist/internal/eval-run-store.d.ts +81 -0
  337. package/dist/internal/eval-run-store.d.ts.map +1 -0
  338. package/dist/internal/eval-run-store.js +396 -0
  339. package/dist/internal/eval-runner.d.ts +76 -0
  340. package/dist/internal/eval-runner.d.ts.map +1 -0
  341. package/dist/internal/eval-runner.js +336 -0
  342. package/dist/internal/event-log.d.ts +51 -0
  343. package/dist/internal/event-log.d.ts.map +1 -0
  344. package/dist/internal/event-log.js +167 -0
  345. package/dist/internal/event-mapper.d.ts +46 -0
  346. package/dist/internal/event-mapper.d.ts.map +1 -0
  347. package/dist/internal/event-mapper.js +226 -0
  348. package/dist/internal/frontmatter.d.ts +12 -0
  349. package/dist/internal/frontmatter.d.ts.map +1 -0
  350. package/dist/internal/frontmatter.js +61 -0
  351. package/dist/internal/github-fanout.d.ts +32 -0
  352. package/dist/internal/github-fanout.d.ts.map +1 -0
  353. package/dist/internal/github-fanout.js +122 -0
  354. package/dist/internal/handleAgentServeTrigger.d.ts +59 -0
  355. package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -0
  356. package/dist/internal/handleAgentServeTrigger.js +115 -0
  357. package/dist/internal/host-platforms.d.ts +40 -0
  358. package/dist/internal/host-platforms.d.ts.map +1 -0
  359. package/dist/internal/host-platforms.js +113 -0
  360. package/dist/internal/http-channel.d.ts +54 -0
  361. package/dist/internal/http-channel.d.ts.map +1 -0
  362. package/dist/internal/http-channel.js +382 -0
  363. package/dist/internal/ids.d.ts +19 -0
  364. package/dist/internal/ids.d.ts.map +1 -0
  365. package/dist/internal/ids.js +34 -0
  366. package/dist/internal/init-project.d.ts +22 -0
  367. package/dist/internal/init-project.d.ts.map +1 -0
  368. package/dist/internal/init-project.js +125 -0
  369. package/dist/internal/json-dir-store.d.ts +32 -0
  370. package/dist/internal/json-dir-store.d.ts.map +1 -0
  371. package/dist/internal/json-dir-store.js +100 -0
  372. package/dist/internal/json-schema.d.ts +18 -0
  373. package/dist/internal/json-schema.d.ts.map +1 -0
  374. package/dist/internal/json-schema.js +53 -0
  375. package/dist/internal/log-ring.d.ts +23 -0
  376. package/dist/internal/log-ring.d.ts.map +1 -0
  377. package/dist/internal/log-ring.js +42 -0
  378. package/dist/internal/map-pool.d.ts +6 -0
  379. package/dist/internal/map-pool.d.ts.map +1 -0
  380. package/dist/internal/map-pool.js +41 -0
  381. package/dist/internal/mcp-endpoint.d.ts +59 -0
  382. package/dist/internal/mcp-endpoint.d.ts.map +1 -0
  383. package/dist/internal/mcp-endpoint.js +355 -0
  384. package/dist/internal/mcp-host.d.ts +28 -0
  385. package/dist/internal/mcp-host.d.ts.map +1 -0
  386. package/dist/internal/mcp-host.js +162 -0
  387. package/dist/internal/net.d.ts +5 -0
  388. package/dist/internal/net.d.ts.map +1 -0
  389. package/dist/internal/net.js +30 -0
  390. package/dist/internal/peer-connections.d.ts +44 -0
  391. package/dist/internal/peer-connections.d.ts.map +1 -0
  392. package/dist/internal/peer-connections.js +67 -0
  393. package/dist/internal/playground/static.d.ts +35 -0
  394. package/dist/internal/playground/static.d.ts.map +1 -0
  395. package/dist/internal/playground/static.js +162 -0
  396. package/dist/internal/playground/toolchain.d.ts +57 -0
  397. package/dist/internal/playground/toolchain.d.ts.map +1 -0
  398. package/dist/internal/playground/toolchain.js +226 -0
  399. package/dist/internal/reminder-runner.d.ts +62 -0
  400. package/dist/internal/reminder-runner.d.ts.map +1 -0
  401. package/dist/internal/reminder-runner.js +582 -0
  402. package/dist/internal/reminder-schedule.d.ts +22 -0
  403. package/dist/internal/reminder-schedule.d.ts.map +1 -0
  404. package/dist/internal/reminder-schedule.js +82 -0
  405. package/dist/internal/reminder-store.d.ts +58 -0
  406. package/dist/internal/reminder-store.d.ts.map +1 -0
  407. package/dist/internal/reminder-store.js +106 -0
  408. package/dist/internal/resolved-connections.d.ts +41 -0
  409. package/dist/internal/resolved-connections.d.ts.map +1 -0
  410. package/dist/internal/resolved-connections.js +73 -0
  411. package/dist/internal/review-comments.d.ts +50 -0
  412. package/dist/internal/review-comments.d.ts.map +1 -0
  413. package/dist/internal/review-comments.js +194 -0
  414. package/dist/internal/router.d.ts +33 -0
  415. package/dist/internal/router.d.ts.map +1 -0
  416. package/dist/internal/router.js +93 -0
  417. package/dist/internal/run-client.d.ts +49 -0
  418. package/dist/internal/run-client.d.ts.map +1 -0
  419. package/dist/internal/run-client.js +208 -0
  420. package/dist/internal/schedule-runner.d.ts +31 -0
  421. package/dist/internal/schedule-runner.d.ts.map +1 -0
  422. package/dist/internal/schedule-runner.js +126 -0
  423. package/dist/internal/sdk-runner.d.ts +41 -0
  424. package/dist/internal/sdk-runner.d.ts.map +1 -0
  425. package/dist/internal/sdk-runner.js +221 -0
  426. package/dist/internal/server.d.ts +25 -0
  427. package/dist/internal/server.d.ts.map +1 -0
  428. package/dist/internal/server.js +1374 -0
  429. package/dist/internal/session-engine.d.ts +287 -0
  430. package/dist/internal/session-engine.d.ts.map +1 -0
  431. package/dist/internal/session-engine.js +1377 -0
  432. package/dist/internal/session-store.d.ts +29 -0
  433. package/dist/internal/session-store.d.ts.map +1 -0
  434. package/dist/internal/session-store.js +140 -0
  435. package/dist/internal/session-urls.d.ts +10 -0
  436. package/dist/internal/session-urls.d.ts.map +1 -0
  437. package/dist/internal/session-urls.js +25 -0
  438. package/dist/internal/stream-progress.d.ts +14 -0
  439. package/dist/internal/stream-progress.d.ts.map +1 -0
  440. package/dist/internal/stream-progress.js +195 -0
  441. package/dist/internal/tool-result.d.ts +20 -0
  442. package/dist/internal/tool-result.d.ts.map +1 -0
  443. package/dist/internal/tool-result.js +45 -0
  444. package/dist/internal/trajectory.d.ts +56 -0
  445. package/dist/internal/trajectory.d.ts.map +1 -0
  446. package/dist/internal/trajectory.js +248 -0
  447. package/dist/internal/workspace.d.ts +42 -0
  448. package/dist/internal/workspace.d.ts.map +1 -0
  449. package/dist/internal/workspace.js +199 -0
  450. package/dist/playground/assets/cursor-icons-outline-oY2V_mvK.woff2 +0 -0
  451. package/dist/playground/assets/index-1K-hG-7p.css +1 -0
  452. package/dist/playground/assets/index-FlWjhg3x.js +79 -0
  453. package/dist/playground/index.html +17 -0
  454. package/dist/reminders.d.ts +23 -0
  455. package/dist/reminders.d.ts.map +1 -0
  456. package/dist/reminders.js +22 -0
  457. package/dist/schedules.d.ts +23 -0
  458. package/dist/schedules.d.ts.map +1 -0
  459. package/dist/schedules.js +26 -0
  460. package/dist/skills.d.ts +22 -0
  461. package/dist/skills.d.ts.map +1 -0
  462. package/dist/skills.js +22 -0
  463. package/dist/tools.d.ts +92 -0
  464. package/dist/tools.d.ts.map +1 -0
  465. package/dist/tools.js +68 -0
  466. package/dist/types.d.ts +1609 -0
  467. package/dist/types.d.ts.map +1 -0
  468. package/dist/types.js +80 -0
  469. package/docs/README.md +174 -0
  470. package/docs/ab.md +355 -0
  471. package/docs/building-with-agents.md +129 -0
  472. package/docs/concepts.md +177 -0
  473. package/docs/deployment.md +218 -0
  474. package/docs/evals.md +383 -0
  475. package/docs/guides/agent-to-agent.md +118 -0
  476. package/docs/guides/cloud-runtime.md +122 -0
  477. package/docs/guides/github.md +172 -0
  478. package/docs/guides/human-in-the-loop.md +131 -0
  479. package/docs/guides/slack.md +245 -0
  480. package/docs/guides/webhooks.md +201 -0
  481. package/docs/hillclimbing.md +93 -0
  482. package/docs/quickstart.md +183 -0
  483. package/docs/reference/agent-config.md +154 -0
  484. package/docs/reference/channels.md +206 -0
  485. package/docs/reference/cli.md +257 -0
  486. package/docs/reference/connections.md +137 -0
  487. package/docs/reference/hooks.md +74 -0
  488. package/docs/reference/http-api.md +219 -0
  489. package/docs/reference/instructions.md +77 -0
  490. package/docs/reference/playground.md +67 -0
  491. package/docs/reference/project-layout.md +119 -0
  492. package/docs/reference/schedules.md +220 -0
  493. package/docs/reference/sessions.md +165 -0
  494. package/docs/reference/skills.md +79 -0
  495. package/docs/reference/subagents.md +74 -0
  496. package/docs/reference/tools.md +203 -0
  497. package/docs/scaffolding-agents.md +113 -0
  498. package/docs/troubleshooting.md +95 -0
  499. package/package.json +185 -0
  500. package/skills/ab/SKILL.md +139 -0
  501. package/skills/create-agent/SKILL.md +219 -0
  502. package/skills/debug/SKILL.md +71 -0
  503. package/skills/evals/SKILL.md +217 -0
  504. package/skills/framework-map/SKILL.md +142 -0
  505. package/skills/github/SKILL.md +144 -0
  506. package/skills/hillclimb/SKILL.md +162 -0
  507. package/skills/setup-slack/SKILL.md +180 -0
  508. package/src/ab.ts +675 -0
  509. package/src/bin/agent-serve.ts +949 -0
  510. package/src/channels/github/api.ts +374 -0
  511. package/src/channels/github/auth.ts +275 -0
  512. package/src/channels/github/binding.ts +223 -0
  513. package/src/channels/github/defaults.ts +111 -0
  514. package/src/channels/github/events.ts +72 -0
  515. package/src/channels/github/forward.ts +381 -0
  516. package/src/channels/github/github-channel.ts +2270 -0
  517. package/src/channels/github/index.ts +52 -0
  518. package/src/channels/github/replay.ts +387 -0
  519. package/src/channels/github/state.ts +95 -0
  520. package/src/channels/github/types.ts +490 -0
  521. package/src/channels/slack/api.ts +580 -0
  522. package/src/channels/slack/approvals.ts +198 -0
  523. package/src/channels/slack/assistant.ts +76 -0
  524. package/src/channels/slack/auth.ts +112 -0
  525. package/src/channels/slack/channel-watch.ts +219 -0
  526. package/src/channels/slack/constants.ts +30 -0
  527. package/src/channels/slack/credentials.ts +90 -0
  528. package/src/channels/slack/cursor-account.ts +166 -0
  529. package/src/channels/slack/defaults.ts +450 -0
  530. package/src/channels/slack/dispatch.ts +293 -0
  531. package/src/channels/slack/doctor.ts +135 -0
  532. package/src/channels/slack/event-id-dedupe.ts +30 -0
  533. package/src/channels/slack/inbound.ts +219 -0
  534. package/src/channels/slack/index.ts +45 -0
  535. package/src/channels/slack/init.ts +133 -0
  536. package/src/channels/slack/interactive.ts +194 -0
  537. package/src/channels/slack/links.ts +23 -0
  538. package/src/channels/slack/live-delivery.ts +201 -0
  539. package/src/channels/slack/log.ts +83 -0
  540. package/src/channels/slack/manifest.ts +179 -0
  541. package/src/channels/slack/pr-ref.ts +50 -0
  542. package/src/channels/slack/setup.ts +97 -0
  543. package/src/channels/slack/slack-channel.ts +374 -0
  544. package/src/channels/slack/socket-mode.ts +154 -0
  545. package/src/channels/slack/stream.ts +63 -0
  546. package/src/channels/slack/tool-approval-events.ts +136 -0
  547. package/src/channels/slack/types.ts +349 -0
  548. package/src/channels.ts +385 -0
  549. package/src/connections.ts +89 -0
  550. package/src/evals.ts +501 -0
  551. package/src/hooks.ts +33 -0
  552. package/src/index.ts +184 -0
  553. package/src/internal/ab-collector.ts +210 -0
  554. package/src/internal/ab-fold.ts +228 -0
  555. package/src/internal/ab-snapshot.ts +335 -0
  556. package/src/internal/approval-gate.ts +115 -0
  557. package/src/internal/auth.ts +39 -0
  558. package/src/internal/authored-alias-hooks.ts +69 -0
  559. package/src/internal/authored-loaders.ts +138 -0
  560. package/src/internal/bounded-int.ts +27 -0
  561. package/src/internal/brand.ts +29 -0
  562. package/src/internal/chat-client.ts +407 -0
  563. package/src/internal/cli-ax.ts +474 -0
  564. package/src/internal/cli-cursor.ts +275 -0
  565. package/src/internal/cli-github.ts +849 -0
  566. package/src/internal/cli-slack.ts +175 -0
  567. package/src/internal/cloud-merge.ts +41 -0
  568. package/src/internal/cron.ts +78 -0
  569. package/src/internal/cursor/account-mcp.ts +472 -0
  570. package/src/internal/cursor/backend-client.ts +614 -0
  571. package/src/internal/cursor/credentials.ts +401 -0
  572. package/src/internal/cursor-event-relay.ts +281 -0
  573. package/src/internal/cursor-relay-core.ts +444 -0
  574. package/src/internal/cursor-slack-relay.ts +242 -0
  575. package/src/internal/describe-error.ts +4 -0
  576. package/src/internal/dev-mode.ts +20 -0
  577. package/src/internal/discovery.ts +1709 -0
  578. package/src/internal/distribution.ts +97 -0
  579. package/src/internal/docs-site.ts +191 -0
  580. package/src/internal/duration.ts +39 -0
  581. package/src/internal/eval-run-store.ts +519 -0
  582. package/src/internal/eval-runner.ts +522 -0
  583. package/src/internal/event-log.ts +175 -0
  584. package/src/internal/event-mapper.ts +272 -0
  585. package/src/internal/frontmatter.ts +77 -0
  586. package/src/internal/github-fanout.ts +159 -0
  587. package/src/internal/handleAgentServeTrigger.ts +156 -0
  588. package/src/internal/host-platforms.ts +144 -0
  589. package/src/internal/http-channel.ts +546 -0
  590. package/src/internal/ids.ts +44 -0
  591. package/src/internal/init-project.ts +165 -0
  592. package/src/internal/json-dir-store.ts +109 -0
  593. package/src/internal/json-schema.ts +69 -0
  594. package/src/internal/log-ring.ts +59 -0
  595. package/src/internal/map-pool.ts +32 -0
  596. package/src/internal/mcp-endpoint.ts +518 -0
  597. package/src/internal/mcp-host.ts +211 -0
  598. package/src/internal/net.ts +31 -0
  599. package/src/internal/peer-connections.ts +100 -0
  600. package/src/internal/playground/static.ts +189 -0
  601. package/src/internal/playground/toolchain.ts +277 -0
  602. package/src/internal/reminder-runner.ts +756 -0
  603. package/src/internal/reminder-schedule.ts +106 -0
  604. package/src/internal/reminder-store.ts +145 -0
  605. package/src/internal/resolved-connections.ts +145 -0
  606. package/src/internal/review-comments.ts +268 -0
  607. package/src/internal/router.ts +145 -0
  608. package/src/internal/run-client.ts +320 -0
  609. package/src/internal/schedule-runner.ts +161 -0
  610. package/src/internal/sdk-runner.ts +315 -0
  611. package/src/internal/server.ts +1737 -0
  612. package/src/internal/session-engine.ts +1810 -0
  613. package/src/internal/session-store.ts +147 -0
  614. package/src/internal/session-urls.ts +40 -0
  615. package/src/internal/stream-progress.ts +254 -0
  616. package/src/internal/tool-result.ts +54 -0
  617. package/src/internal/trajectory.ts +306 -0
  618. package/src/internal/workspace.ts +223 -0
  619. package/src/reminders.ts +35 -0
  620. package/src/schedules.ts +37 -0
  621. package/src/skills.ts +27 -0
  622. package/src/tools.ts +127 -0
  623. package/src/types.ts +1848 -0
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Cursor account credentials for the agent-serve host.
3
+ *
4
+ * Exactly one kind of secret exists at runtime: a **personal Cursor user API
5
+ * key**. Two ways to obtain it, one code path after that:
6
+ *
7
+ * - `agent-serve login` runs the same PKCE browser flow as `cursor-agent`
8
+ * and Sand, then uses the short-lived session once to mint a named,
9
+ * dashboard-revocable user API key — only the key is stored.
10
+ * - `CURSOR_API_KEY` (or `serve({ apiKey })`) wins over the stored key, so
11
+ * CI and hosted deployments stay env-driven.
12
+ *
13
+ * There is deliberately no session-token storage, refresh-token rotation, or
14
+ * cross-tool credential sharing here: short-lived access tokens are minted
15
+ * on demand from the API key (see `backend-client.ts`).
16
+ */
17
+
18
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
19
+ import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
20
+ import { homedir } from "node:os";
21
+ import { dirname, join } from "node:path";
22
+ import { z } from "zod";
23
+ import { CLI_COMMAND_NAME } from "../distribution.js";
24
+
25
+ export const DEFAULT_CURSOR_BACKEND_URL = "https://api2.cursor.sh";
26
+ const DEFAULT_CURSOR_WEBSITE_URL = "https://cursor.com";
27
+
28
+ /** Backend API base URL (`CURSOR_API_BASE_URL` override for local dev). */
29
+ export function cursorBackendUrl(): string {
30
+ return trimTrailingSlash(
31
+ process.env.CURSOR_API_BASE_URL ?? DEFAULT_CURSOR_BACKEND_URL
32
+ );
33
+ }
34
+
35
+ /** Website base URL for the login deep link (`CURSOR_WEBSITE_URL` override). */
36
+ export function cursorWebsiteUrl(): string {
37
+ return trimTrailingSlash(
38
+ process.env.CURSOR_WEBSITE_URL ?? DEFAULT_CURSOR_WEBSITE_URL
39
+ );
40
+ }
41
+
42
+ function trimTrailingSlash(url: string): string {
43
+ return url.endsWith("/") ? url.slice(0, -1) : url;
44
+ }
45
+
46
+ // ============================================================================
47
+ // Stored credential (one file, one secret)
48
+ // ============================================================================
49
+
50
+ const storedCredentialsSchema: z.ZodObject<
51
+ { backendUrl: z.ZodString; apiKey: z.ZodString },
52
+ "strip"
53
+ > = z.object({
54
+ /** Backend the key was minted against; keys never cross backends. */
55
+ backendUrl: z.string(),
56
+ apiKey: z.string().min(1),
57
+ });
58
+
59
+ export type StoredCredentials = z.infer<typeof storedCredentialsSchema>;
60
+
61
+ /**
62
+ * `~/.config/agent-serve/credentials.json` (0600), honoring
63
+ * `XDG_CONFIG_HOME`. `AGENT_SERVE_CONFIG_DIR` pins the directory outright
64
+ * (tests, containers).
65
+ */
66
+ export function credentialsFilePath(): string {
67
+ const configDir =
68
+ process.env.AGENT_SERVE_CONFIG_DIR ??
69
+ join(
70
+ process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"),
71
+ "agent-serve"
72
+ );
73
+ return join(configDir, "credentials.json");
74
+ }
75
+
76
+ export async function readStoredCredentials(): Promise<
77
+ StoredCredentials | undefined
78
+ > {
79
+ let raw: string;
80
+ try {
81
+ raw = await readFile(credentialsFilePath(), "utf8");
82
+ } catch {
83
+ return undefined;
84
+ }
85
+ let parsed: unknown;
86
+ try {
87
+ parsed = JSON.parse(raw) as unknown;
88
+ } catch {
89
+ // Corrupt file — treat as signed out; login rewrites it.
90
+ return undefined;
91
+ }
92
+ const credentials = storedCredentialsSchema.safeParse(parsed);
93
+ if (!credentials.success) {
94
+ return undefined;
95
+ }
96
+ return {
97
+ backendUrl: trimTrailingSlash(credentials.data.backendUrl),
98
+ apiKey: credentials.data.apiKey,
99
+ };
100
+ }
101
+
102
+ export async function writeStoredCredentials(
103
+ credentials: StoredCredentials
104
+ ): Promise<void> {
105
+ const path = credentialsFilePath();
106
+ await mkdir(dirname(path), { recursive: true, mode: 0o700 });
107
+ await writeFile(path, `${JSON.stringify(credentials, null, 2)}\n`, {
108
+ mode: 0o600,
109
+ });
110
+ // writeFile mode only applies on create; clamp pre-existing files too.
111
+ await chmod(path, 0o600);
112
+ }
113
+
114
+ export async function clearStoredCredentials(): Promise<boolean> {
115
+ try {
116
+ await rm(credentialsFilePath());
117
+ return true;
118
+ } catch {
119
+ return false;
120
+ }
121
+ }
122
+
123
+ // ============================================================================
124
+ // Resolution (option > env > stored login)
125
+ // ============================================================================
126
+
127
+ export type ApiKeySource = "option" | "env" | "login";
128
+
129
+ export interface ResolvedApiKey {
130
+ apiKey: string;
131
+ source: ApiKeySource;
132
+ backendUrl: string;
133
+ }
134
+
135
+ /**
136
+ * Resolve the account API key for `backendUrl` (defaults to the active
137
+ * backend): explicit option → `CURSOR_API_KEY` → stored login. A stored key
138
+ * minted against a different backend is ignored rather than sent to the
139
+ * wrong host.
140
+ */
141
+ export async function resolveApiKey(options?: {
142
+ apiKey?: string;
143
+ backendUrl?: string;
144
+ }): Promise<ResolvedApiKey | undefined> {
145
+ const backendUrl = options?.backendUrl ?? cursorBackendUrl();
146
+ if (options?.apiKey !== undefined && options.apiKey.trim() !== "") {
147
+ return { apiKey: options.apiKey.trim(), source: "option", backendUrl };
148
+ }
149
+ const envKey = process.env.CURSOR_API_KEY;
150
+ if (envKey !== undefined && envKey.trim() !== "") {
151
+ return { apiKey: envKey.trim(), source: "env", backendUrl };
152
+ }
153
+ const stored = await readStoredCredentials();
154
+ if (stored !== undefined && stored.backendUrl === backendUrl) {
155
+ return { apiKey: stored.apiKey, source: "login", backendUrl };
156
+ }
157
+ return undefined;
158
+ }
159
+
160
+ /** One-line hint for "no credentials" errors, shared across surfaces. */
161
+ export const SIGN_IN_HINT: string = `Run \`${CLI_COMMAND_NAME} login\` (or set CURSOR_API_KEY / pass serve({ apiKey })).`;
162
+
163
+ // ============================================================================
164
+ // PKCE browser login (mirrors cursor-agent / Sand)
165
+ // ============================================================================
166
+
167
+ const loginPollResponseSchema = z.object({ accessToken: z.string() });
168
+
169
+ export interface LoginStart {
170
+ /** URL the user opens in a browser to approve the login. */
171
+ loginUrl: string;
172
+ uuid: string;
173
+ verifier: string;
174
+ }
175
+
176
+ /**
177
+ * Build the `/loginDeepControl` deep link and its PKCE material. The portal
178
+ * completes the login and the backend holds the resulting session until
179
+ * {@link pollForLoginTokens} picks it up with the verifier.
180
+ */
181
+ export function startBrowserLogin(): LoginStart {
182
+ const verifier = randomBytes(32).toString("base64url");
183
+ const challenge = createHash("sha256").update(verifier).digest("base64url");
184
+ const uuid = randomUUID();
185
+ const url = new URL("/loginDeepControl", `${cursorWebsiteUrl()}/`);
186
+ url.searchParams.set("challenge", challenge);
187
+ url.searchParams.set("uuid", uuid);
188
+ url.searchParams.set("mode", "login");
189
+ url.searchParams.set("redirectTarget", "cli");
190
+ return { loginUrl: url.toString(), uuid, verifier };
191
+ }
192
+
193
+ /** Backend pending-login 404 body from `respondToPollLogin` ("still waiting"). */
194
+ const POLL_PENDING_BODY = "Not found";
195
+
196
+ /**
197
+ * Why the poll stopped. Distinct cases because collapsing them into
198
+ * "timed out or was cancelled" turned an unsupported-verb 404 into an
199
+ * unfalsifiable "login is slow" report.
200
+ */
201
+ export type LoginPollResult =
202
+ | { status: "signed_in"; accessToken: string }
203
+ | { status: "cancelled" }
204
+ | { status: "timed_out" }
205
+ | { status: "failed"; message: string };
206
+
207
+ /**
208
+ * Poll `/auth/poll` until the browser login completes.
209
+ *
210
+ * **POST, with the verifier in the JSON body.** The verifier is redeemable:
211
+ * anyone holding it (plus the uuid) can complete the login and mint a durable
212
+ * user API key, so it must not reach a URL — not the backend's access log, not
213
+ * a proxy's request log, not a terminal. `POST /auth/poll` exists for exactly
214
+ * this reason.
215
+ *
216
+ * A backend that predates that route answers POST with a route-not-found 404.
217
+ * Those get one sticky fallback to `GET /auth/poll?uuid=…&verifier=…` — the
218
+ * shape the vscode client and Sand already use — so the login still works
219
+ * while the backend catches up. The fallback puts the verifier in the query
220
+ * string, which is the exposure POST was added to remove, so it warns; it
221
+ * disappears on its own once the backend serves POST.
222
+ */
223
+ export async function pollForLoginTokens(args: {
224
+ uuid: string;
225
+ verifier: string;
226
+ backendUrl?: string;
227
+ signal?: AbortSignal;
228
+ /** Notified once if the backend forces the GET fallback. */
229
+ logger?: (line: string) => void;
230
+ /** Test seam; defaults to global fetch. */
231
+ fetchImpl?: typeof fetch;
232
+ /** Test seam; defaults to 150 (~24 minutes with the backoff below). */
233
+ maxAttempts?: number;
234
+ }): Promise<LoginPollResult> {
235
+ const backendUrl = trimTrailingSlash(args.backendUrl ?? cursorBackendUrl());
236
+ const fetchImpl = args.fetchImpl ?? fetch;
237
+ const redact = (text: string): string =>
238
+ truncate(redactVerifier(text, args.verifier));
239
+
240
+ const postUrl = `${backendUrl}/auth/poll`;
241
+ // Only built if the backend leaves us no choice (see the doc comment).
242
+ const getUrl = (): string => {
243
+ const url = new URL("/auth/poll", `${backendUrl}/`);
244
+ url.searchParams.set("uuid", args.uuid);
245
+ url.searchParams.set("verifier", args.verifier);
246
+ return url.toString();
247
+ };
248
+
249
+ const maxAttempts = args.maxAttempts ?? 150;
250
+ let useGet = false;
251
+ let consecutiveErrors = 0;
252
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
253
+ if (isAborted(args.signal)) {
254
+ return { status: "cancelled" };
255
+ }
256
+ try {
257
+ const response = useGet
258
+ ? await fetchImpl(getUrl(), {
259
+ method: "GET",
260
+ headers: { accept: "application/json" },
261
+ ...(args.signal === undefined ? {} : { signal: args.signal }),
262
+ })
263
+ : await fetchImpl(postUrl, {
264
+ method: "POST",
265
+ headers: {
266
+ accept: "application/json",
267
+ "content-type": "application/json",
268
+ },
269
+ body: JSON.stringify({ uuid: args.uuid, verifier: args.verifier }),
270
+ ...(args.signal === undefined ? {} : { signal: args.signal }),
271
+ });
272
+
273
+ if (response.status === 404) {
274
+ const body = (await response.text()).trim();
275
+ if (!useGet && body !== POLL_PENDING_BODY) {
276
+ // Any 404 on POST that is not the pending marker means this backend
277
+ // has no POST route. Retry the same attempt over GET rather than
278
+ // guessing at body shapes; GET's handling below is deliberately
279
+ // lenient, so an unrecognized body cannot strand the login.
280
+ useGet = true;
281
+ args.logger?.(
282
+ `${backendUrl} has no POST /auth/poll; falling back to GET, which puts the single-use login verifier in the request URL (and the backend's access log). It will use POST once the backend deploys that route.`
283
+ );
284
+ continue;
285
+ }
286
+ if (useGet && isRouteNotFoundBody(body)) {
287
+ // Neither verb is served — polling harder cannot fix that.
288
+ return {
289
+ status: "failed",
290
+ message: `${backendUrl} serves neither POST nor GET /auth/poll (404: ${redact(body)})`,
291
+ };
292
+ }
293
+ // Pending: the browser sign-in has not landed yet. On GET this is
294
+ // deliberately lenient — treating an unrecognized 404 body as fatal is
295
+ // what made an earlier poll die on its first attempt and call it a
296
+ // timeout.
297
+ consecutiveErrors = 0;
298
+ } else if (!response.ok) {
299
+ consecutiveErrors++;
300
+ if (consecutiveErrors >= 3) {
301
+ return {
302
+ status: "failed",
303
+ message: `${backendUrl}/auth/poll kept failing (${response.status}: ${redact((await response.text()).trim())})`,
304
+ };
305
+ }
306
+ } else {
307
+ const body = loginPollResponseSchema.safeParse(await response.json());
308
+ if (body.success && body.data.accessToken !== "") {
309
+ return { status: "signed_in", accessToken: body.data.accessToken };
310
+ }
311
+ return {
312
+ status: "failed",
313
+ message: `${backendUrl}/auth/poll returned 200 without an accessToken`,
314
+ };
315
+ }
316
+ } catch (error) {
317
+ if (isAborted(args.signal)) {
318
+ return { status: "cancelled" };
319
+ }
320
+ consecutiveErrors++;
321
+ if (consecutiveErrors >= 3) {
322
+ return {
323
+ status: "failed",
324
+ message: `could not reach ${backendUrl}/auth/poll (${redact(
325
+ error instanceof Error ? error.message : String(error)
326
+ )})`,
327
+ };
328
+ }
329
+ }
330
+ await sleep(Math.min(1000 * 1.2 ** attempt, 10_000), args.signal);
331
+ }
332
+ return { status: "timed_out" };
333
+ }
334
+
335
+ /**
336
+ * Fastify's route-not-found envelope: `{"message":"Route GET:/auth/poll not
337
+ * found",…}`. Distinct from the backend's pending marker ({@link
338
+ * POLL_PENDING_BODY}), and the only 404 shape on the GET path that is fatal.
339
+ */
340
+ function isRouteNotFoundBody(body: string): boolean {
341
+ if (!body.startsWith("{")) {
342
+ return false;
343
+ }
344
+ try {
345
+ const parsed = JSON.parse(body) as { message?: unknown };
346
+ return (
347
+ typeof parsed.message === "string" &&
348
+ /^Route \w+:/.test(parsed.message) &&
349
+ parsed.message.includes("not found")
350
+ );
351
+ } catch {
352
+ return false;
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Keep the verifier out of anything user-visible. Fastify's 404 body echoes the
358
+ * whole request URL — `Route GET:/auth/poll?uuid=…&verifier=… not found` — so
359
+ * echoing a poll response verbatim would print a redeemable secret into the
360
+ * terminal, CI logs, and pasted bug reports.
361
+ */
362
+ function redactVerifier(text: string, verifier: string): string {
363
+ if (verifier === "") {
364
+ return text;
365
+ }
366
+ let redacted = text.split(verifier).join("[verifier redacted]");
367
+ const encoded = encodeURIComponent(verifier);
368
+ if (encoded !== verifier) {
369
+ redacted = redacted.split(encoded).join("[verifier redacted]");
370
+ }
371
+ return redacted;
372
+ }
373
+
374
+ function truncate(value: string, max = 200): string {
375
+ return value.length <= max ? value : `${value.slice(0, max)}…`;
376
+ }
377
+
378
+ // Reads the abort flag through a call boundary so repeated checks across an
379
+ // `await` aren't collapsed by control-flow narrowing (the signal is mutated
380
+ // by another task, so `aborted` really can flip mid-loop).
381
+ function isAborted(signal?: AbortSignal): boolean {
382
+ return signal?.aborted === true;
383
+ }
384
+
385
+ function sleep(ms: number, signal?: AbortSignal): Promise<void> {
386
+ return new Promise((resolve) => {
387
+ if (signal?.aborted === true) {
388
+ resolve();
389
+ return;
390
+ }
391
+ const timer = setTimeout(() => {
392
+ signal?.removeEventListener("abort", onAbort);
393
+ resolve();
394
+ }, ms);
395
+ const onAbort = (): void => {
396
+ clearTimeout(timer);
397
+ resolve();
398
+ };
399
+ signal?.addEventListener("abort", onAbort, { once: true });
400
+ });
401
+ }
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Pulls `/v0/scm-events` into agent-serve: register repos+events, long-poll
3
+ * with a durable offset under `<stateDir>/offset.json`. Registration-gated
4
+ * so consumption never starts unsubscribed. Shared streams: durable
5
+ * consumer id + repo/event filtering skip sibling deliveries.
6
+ *
7
+ * The long-poll lifecycle (consumer id, registration-gated consume loop,
8
+ * anchor/offset/backoff) lives in the shared {@link CursorRelayCore}; this
9
+ * module is the GitHub adapter over it. {@link RelayOffsetStore} and
10
+ * {@link compareStreamOffsets} are re-exported for stability.
11
+ */
12
+
13
+ import {
14
+ CursorRelayCore,
15
+ type RelayAdapter,
16
+ RelayOffsetStore,
17
+ } from "./cursor-relay-core.js";
18
+
19
+ export { RelayOffsetStore };
20
+
21
+ /** PR snapshot from scm-events compact metadata (Sand-style; no raw body). */
22
+ export type CursorScmPullRequestMeta = {
23
+ number: number;
24
+ url: string;
25
+ title?: string;
26
+ body?: string | null;
27
+ draft?: boolean;
28
+ authorLogin?: string;
29
+ headRef?: string;
30
+ headSha?: string;
31
+ baseRef?: string;
32
+ baseSha?: string;
33
+ };
34
+
35
+ /** One event delivered by `GET /v0/scm-events` (metadata only). */
36
+ export interface CursorScmEvent {
37
+ offset: string;
38
+ provider: string;
39
+ eventName: string;
40
+ deliveryId?: string;
41
+ repo: string;
42
+ receivedAtMs: number;
43
+ /** Webhook `action` when present. */
44
+ action?: string;
45
+ /** PR number when the delivery is PR-scoped. */
46
+ prNumber?: number;
47
+ /** Canonical PR URL when known. */
48
+ prUrl?: string;
49
+ /**
50
+ * Richer PR snapshot when the backend saw `body.pull_request`. Enough to
51
+ * stub a Zod-valid GitHub `pull_request` webhook body.
52
+ */
53
+ pullRequest?: CursorScmPullRequestMeta;
54
+ /** GitHub-side event time from the payload, when present. */
55
+ occurredAtMs?: number;
56
+ }
57
+
58
+ interface SubscriptionStatus {
59
+ provider: string;
60
+ repo: string;
61
+ isSubscribed: boolean;
62
+ detail?: string;
63
+ }
64
+
65
+ export interface CursorEventRelayOptions {
66
+ baseUrl: string;
67
+ apiKey: string;
68
+ repos: readonly string[];
69
+ events: readonly string[];
70
+ stateDir: string;
71
+ /** Called for each matching event; failures are logged, not retried. */
72
+ dispatch: (event: CursorScmEvent) => Promise<void>;
73
+ logger: (line: string) => void;
74
+ /** Test seam. Defaults to global fetch. */
75
+ fetchImpl?: typeof fetch;
76
+ /** Test seam: override long-poll wait (default 25s). */
77
+ pollWaitMs?: number;
78
+ }
79
+
80
+ /** Human-readable cursor-events log fragment: event, repo/PR, times, delivery. */
81
+ export function formatCursorScmEventLog(event: {
82
+ eventName: string;
83
+ repo: string;
84
+ action?: string;
85
+ prNumber?: number;
86
+ prUrl?: string;
87
+ receivedAtMs: number;
88
+ occurredAtMs?: number;
89
+ deliveryId?: string;
90
+ }): string {
91
+ const action =
92
+ event.action !== undefined && event.action !== "" ? `.${event.action}` : "";
93
+ const pr =
94
+ event.prUrl !== undefined
95
+ ? event.prUrl
96
+ : event.prNumber !== undefined
97
+ ? `${event.repo}#${event.prNumber}`
98
+ : event.repo;
99
+ const received = new Date(event.receivedAtMs).toISOString();
100
+ const occurred =
101
+ event.occurredAtMs !== undefined
102
+ ? ` occurred=${new Date(event.occurredAtMs).toISOString()}`
103
+ : "";
104
+ const delivery = event.deliveryId ?? "no delivery id";
105
+ return `${event.eventName}${action} on ${pr} received=${received}${occurred} (${delivery})`;
106
+ }
107
+
108
+ /**
109
+ * Minimal GitHub webhook body from an SCM-events metadata envelope.
110
+ * When `pullRequest` has title + head/base refs+shas, emits a Zod-valid
111
+ * `pull_request` object for `onPullRequest`; otherwise identity-only stubs.
112
+ */
113
+ export function scmMetadataToGitHubPayload(event: {
114
+ repo: string;
115
+ action?: string;
116
+ prNumber?: number;
117
+ prUrl?: string;
118
+ pullRequest?: CursorScmPullRequestMeta;
119
+ }): Record<string, unknown> {
120
+ const slash = event.repo.indexOf("/");
121
+ const owner = slash === -1 ? "" : event.repo.slice(0, slash);
122
+ const name = slash === -1 ? event.repo : event.repo.slice(slash + 1);
123
+ const repoUrl = `https://github.com/${event.repo}`;
124
+ const prMeta = event.pullRequest;
125
+ const prNumber = prMeta?.number ?? event.prNumber;
126
+ const prUrl =
127
+ prMeta?.url ??
128
+ event.prUrl ??
129
+ (prNumber !== undefined ? `${repoUrl}/pull/${prNumber}` : undefined);
130
+
131
+ const payload: Record<string, unknown> = {
132
+ repository: {
133
+ full_name: event.repo,
134
+ name,
135
+ html_url: repoUrl,
136
+ owner: { login: owner },
137
+ },
138
+ };
139
+ payload.action = event.action;
140
+
141
+ const title = prMeta?.title;
142
+ const headRef = prMeta?.headRef;
143
+ const headSha = prMeta?.headSha;
144
+ const baseRef = prMeta?.baseRef;
145
+ const canStubTypedPr =
146
+ prNumber !== undefined &&
147
+ prUrl !== undefined &&
148
+ title !== undefined &&
149
+ headRef !== undefined &&
150
+ headSha !== undefined &&
151
+ baseRef !== undefined;
152
+
153
+ if (canStubTypedPr) {
154
+ const pullRequest: Record<string, unknown> = {
155
+ number: prNumber,
156
+ html_url: prUrl,
157
+ title,
158
+ body: prMeta?.body,
159
+ draft: prMeta?.draft,
160
+ head: { ref: headRef, sha: headSha },
161
+ base: { ref: baseRef, sha: prMeta?.baseSha },
162
+ };
163
+ if (prMeta?.authorLogin !== undefined) {
164
+ pullRequest.user = { login: prMeta.authorLogin };
165
+ }
166
+ payload.pull_request = pullRequest;
167
+ payload.issue = {
168
+ number: prNumber,
169
+ html_url: prUrl,
170
+ pull_request: {},
171
+ };
172
+ return payload;
173
+ }
174
+
175
+ if (prNumber !== undefined) {
176
+ payload.pull_request = {
177
+ number: prNumber,
178
+ html_url: prUrl ?? `${repoUrl}/pull/${prNumber}`,
179
+ };
180
+ payload.issue = {
181
+ number: prNumber,
182
+ html_url: prUrl ?? `${repoUrl}/pull/${prNumber}`,
183
+ pull_request: {},
184
+ };
185
+ }
186
+ return payload;
187
+ }
188
+
189
+ /**
190
+ * GitHub SCM-events relay: a thin {@link CursorRelayCore} adapter. Consumers
191
+ * keep the same `new CursorEventRelay(options).start()/.stop()` surface.
192
+ */
193
+ export class CursorEventRelay {
194
+ private readonly core: CursorRelayCore<CursorScmEvent>;
195
+ /**
196
+ * Normalized repos the server confirmed for THIS consumer. The stream is
197
+ * shared with sibling consumers of the same principal, so only events for
198
+ * these repos may dispatch.
199
+ */
200
+ private subscribedRepos = new Set<string>();
201
+ private readonly loggedSkippedRepos = new Set<string>();
202
+
203
+ constructor(private readonly options: CursorEventRelayOptions) {
204
+ const adapter: RelayAdapter<CursorScmEvent> = {
205
+ logPrefix: "cursor-events",
206
+ subscribePath: "/v0/scm-events/subscriptions",
207
+ pollPath: "/v0/scm-events",
208
+ buildRegistrationBody: (consumerId) => ({
209
+ consumerId,
210
+ subscriptions: this.options.repos.map((repo) => ({
211
+ provider: "github",
212
+ repo,
213
+ events: [...this.options.events],
214
+ })),
215
+ }),
216
+ applyRegistrationResponse: (json) => {
217
+ const result = json as { repos?: SubscriptionStatus[] };
218
+ const statuses = result.repos ?? [];
219
+ this.subscribedRepos = new Set(
220
+ statuses
221
+ .filter((status) => status.isSubscribed)
222
+ .map((status) => status.repo)
223
+ );
224
+ const lines: string[] = [];
225
+ for (const status of statuses.filter((s) => !s.isSubscribed)) {
226
+ lines.push(
227
+ `not subscribed to ${status.repo}: ${status.detail ?? "unknown reason"}`
228
+ );
229
+ }
230
+ if (this.subscribedRepos.size > 0) {
231
+ lines.push(
232
+ `subscribed to ${[...this.subscribedRepos].join(", ")} for events: ${this.options.events.join(", ")}`
233
+ );
234
+ }
235
+ return lines;
236
+ },
237
+ shouldDispatch: (event) => this.shouldDispatch(event),
238
+ dispatch: (event) => this.options.dispatch(event),
239
+ };
240
+ this.core = new CursorRelayCore<CursorScmEvent>({
241
+ baseUrl: options.baseUrl,
242
+ apiKey: options.apiKey,
243
+ stateDir: options.stateDir,
244
+ adapter,
245
+ logger: options.logger,
246
+ ...(options.fetchImpl === undefined
247
+ ? {}
248
+ : { fetchImpl: options.fetchImpl }),
249
+ ...(options.pollWaitMs === undefined
250
+ ? {}
251
+ : { pollWaitMs: options.pollWaitMs }),
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Whether an event from the shared stream belongs to THIS consumer: the
257
+ * repo must be one the server confirmed for us and the event kind one the
258
+ * mounted channels declared. Anything else came from a sibling consumer's
259
+ * subscription and must not fire this host's hooks.
260
+ */
261
+ private shouldDispatch(event: CursorScmEvent): boolean {
262
+ if (!this.subscribedRepos.has(event.repo)) {
263
+ if (!this.loggedSkippedRepos.has(event.repo)) {
264
+ this.loggedSkippedRepos.add(event.repo);
265
+ this.options.logger(
266
+ `[agent-serve] cursor-events: skipping events for ${event.repo}: not in this host's subscription (another consumer of this API key likely subscribed it)`
267
+ );
268
+ }
269
+ return false;
270
+ }
271
+ return this.options.events.includes(event.eventName);
272
+ }
273
+
274
+ start(): void {
275
+ this.core.start();
276
+ }
277
+
278
+ async stop(): Promise<void> {
279
+ await this.core.stop();
280
+ }
281
+ }