@cursor/july 0.1.95 → 0.1.97

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 (424) hide show
  1. package/AGENTS.md +3 -4
  2. package/README.md +3 -2
  3. package/dist/bin/agent-serve.js +14 -3
  4. package/dist/channels/deployments/types.d.ts +1 -1
  5. package/dist/channels/deployments/types.d.ts.map +1 -1
  6. package/dist/channels/deployments/types.js +1 -0
  7. package/dist/channels/origin/api.d.ts +72 -15
  8. package/dist/channels/origin/api.d.ts.map +1 -1
  9. package/dist/channels/origin/api.js +185 -28
  10. package/dist/channels/origin/binding.d.ts +13 -2
  11. package/dist/channels/origin/binding.d.ts.map +1 -1
  12. package/dist/channels/origin/binding.js +41 -25
  13. package/dist/channels/origin/checks.d.ts +6 -6
  14. package/dist/channels/origin/checks.js +6 -6
  15. package/dist/channels/origin/cursor-account.d.ts +5 -3
  16. package/dist/channels/origin/cursor-account.d.ts.map +1 -1
  17. package/dist/channels/origin/cursor-account.js +5 -3
  18. package/dist/channels/origin/index.d.ts +1 -0
  19. package/dist/channels/origin/index.d.ts.map +1 -1
  20. package/dist/channels/origin/index.js +1 -0
  21. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  22. package/dist/channels/origin/origin-channel.js +3 -0
  23. package/dist/channels/origin/reactions.d.ts +56 -0
  24. package/dist/channels/origin/reactions.d.ts.map +1 -0
  25. package/dist/channels/origin/reactions.js +67 -0
  26. package/dist/channels/origin/types.d.ts +11 -0
  27. package/dist/channels/origin/types.d.ts.map +1 -1
  28. package/dist/channels/slack/api.d.ts +9 -0
  29. package/dist/channels/slack/api.d.ts.map +1 -1
  30. package/dist/channels/slack/api.js +36 -5
  31. package/dist/channels/slack/approvals.d.ts +16 -0
  32. package/dist/channels/slack/approvals.d.ts.map +1 -1
  33. package/dist/channels/slack/approvals.js +86 -0
  34. package/dist/channels/slack/cli-project.d.ts +19 -0
  35. package/dist/channels/slack/cli-project.d.ts.map +1 -0
  36. package/dist/channels/slack/cli-project.js +234 -0
  37. package/dist/channels/slack/defaults.d.ts.map +1 -1
  38. package/dist/channels/slack/defaults.js +110 -81
  39. package/dist/channels/slack/dispatch.d.ts +7 -1
  40. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  41. package/dist/channels/slack/dispatch.js +47 -23
  42. package/dist/channels/slack/inbound.d.ts +8 -0
  43. package/dist/channels/slack/inbound.d.ts.map +1 -1
  44. package/dist/channels/slack/inbound.js +32 -0
  45. package/dist/channels/slack/init.d.ts +3 -2
  46. package/dist/channels/slack/init.d.ts.map +1 -1
  47. package/dist/channels/slack/init.js +5 -5
  48. package/dist/channels/slack/interactive.d.ts +2 -1
  49. package/dist/channels/slack/interactive.d.ts.map +1 -1
  50. package/dist/channels/slack/interactive.js +15 -4
  51. package/dist/channels/slack/live-delivery.d.ts +26 -29
  52. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  53. package/dist/channels/slack/live-delivery.js +172 -73
  54. package/dist/channels/slack/manifest.d.ts +1 -1
  55. package/dist/channels/slack/manifest.d.ts.map +1 -1
  56. package/dist/channels/slack/manifest.js +6 -2
  57. package/dist/channels/slack/nudge-carrier.d.ts +2 -0
  58. package/dist/channels/slack/nudge-carrier.d.ts.map +1 -1
  59. package/dist/channels/slack/nudge-carrier.js +48 -1
  60. package/dist/channels/slack/setup.d.ts +1 -1
  61. package/dist/channels/slack/setup.d.ts.map +1 -1
  62. package/dist/channels/slack/setup.js +10 -6
  63. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  64. package/dist/channels/slack/slack-channel.js +3 -2
  65. package/dist/channels/slack/tool-approval-events.d.ts.map +1 -1
  66. package/dist/channels/slack/tool-approval-events.js +91 -1
  67. package/dist/docs/404.html +2 -2
  68. package/dist/docs/ab.html +4 -4
  69. package/dist/docs/assets/{app.BBj0klBO.js → app.B3rWNYE1.js} +1 -1
  70. package/dist/docs/assets/chunks/@localSearchIndexroot.BU9nHdnQ.js +1 -0
  71. package/dist/docs/assets/chunks/{VPLocalSearchBox.CUEXpL78.js → VPLocalSearchBox.C1lhqJJR.js} +1 -1
  72. package/dist/docs/assets/chunks/{theme.DabmQnia.js → theme.B40_SXuv.js} +2 -2
  73. package/dist/docs/assets/{deployment.md.D9msOFOW.js → deployment.md.MFPKqsqI.js} +2 -2
  74. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.js → guides_mcp-oauth.md.CN-6YmTJ.js} +4 -4
  75. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.lean.js → guides_mcp-oauth.md.CN-6YmTJ.lean.js} +1 -1
  76. package/dist/docs/assets/guides_slack.md.VDXQV3ja.js +22 -0
  77. package/dist/docs/assets/guides_slack.md.VDXQV3ja.lean.js +1 -0
  78. package/dist/docs/assets/index.md.CVeRUOeZ.js +5 -0
  79. package/dist/docs/assets/{index.md.BoHaMdeZ.lean.js → index.md.CVeRUOeZ.lean.js} +1 -1
  80. package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.js → reference_agent-config.md.BHeYMgme.js} +1 -1
  81. package/dist/docs/assets/{reference_cli.md.BsMOxDvh.js → reference_cli.md.RyZf5OTE.js} +10 -6
  82. package/dist/docs/assets/{reference_cli.md.BsMOxDvh.lean.js → reference_cli.md.RyZf5OTE.lean.js} +1 -1
  83. package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.js → reference_connections.md.DxldvyIB.js} +4 -3
  84. package/dist/docs/assets/{reference_http-api.md.D89k1mdm.js → reference_http-api.md.5zOAbV86.js} +1 -1
  85. package/dist/docs/assets/reference_sessions.md.NxFP_CAC.js +1 -0
  86. package/dist/docs/assets/{reference_tools.md.BHeXn2id.js → reference_tools.md.B84gw9Ii.js} +1 -1
  87. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.js +2 -0
  88. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.lean.js +1 -0
  89. package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.js +2 -0
  90. package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.lean.js +1 -0
  91. package/dist/docs/assets/troubleshooting.md.DCiPBhYs.js +1 -0
  92. package/dist/docs/building-with-agents.html +4 -4
  93. package/dist/docs/concepts.html +4 -4
  94. package/dist/docs/deployment.html +7 -7
  95. package/dist/docs/deployment.md +5 -4
  96. package/dist/docs/evals.html +4 -4
  97. package/dist/docs/guides/agent-to-agent.html +4 -4
  98. package/dist/docs/guides/cloud-runtime.html +4 -4
  99. package/dist/docs/guides/convert-automation.html +4 -4
  100. package/dist/docs/guides/github.html +4 -4
  101. package/dist/docs/guides/human-in-the-loop.html +4 -4
  102. package/dist/docs/guides/mcp-oauth.html +8 -8
  103. package/dist/docs/guides/mcp-oauth.md +26 -8
  104. package/dist/docs/guides/opentelemetry.html +4 -4
  105. package/dist/docs/guides/slack.html +17 -33
  106. package/dist/docs/guides/slack.md +92 -201
  107. package/dist/docs/guides/webhooks.html +4 -4
  108. package/dist/docs/hashmap.json +1 -1
  109. package/dist/docs/hillclimbing.html +4 -4
  110. package/dist/docs/index.html +6 -6
  111. package/dist/docs/index.md +7 -3
  112. package/dist/docs/llms-full.txt +398 -653
  113. package/dist/docs/llms.txt +3 -2
  114. package/dist/docs/quickstart.html +4 -4
  115. package/dist/docs/reference/agent-config.html +6 -6
  116. package/dist/docs/reference/agent-config.md +2 -2
  117. package/dist/docs/reference/artifacts.html +4 -4
  118. package/dist/docs/reference/channels.html +4 -4
  119. package/dist/docs/reference/cli.html +14 -10
  120. package/dist/docs/reference/cli.md +39 -16
  121. package/dist/docs/reference/connections.html +9 -8
  122. package/dist/docs/reference/connections.md +6 -3
  123. package/dist/docs/reference/hooks.html +4 -4
  124. package/dist/docs/reference/http-api.html +6 -6
  125. package/dist/docs/reference/http-api.md +2 -1
  126. package/dist/docs/reference/instructions.html +4 -4
  127. package/dist/docs/reference/playground.html +4 -4
  128. package/dist/docs/reference/project-layout.html +4 -4
  129. package/dist/docs/reference/prompt.html +4 -4
  130. package/dist/docs/reference/schedules.html +4 -4
  131. package/dist/docs/reference/sessions.html +5 -5
  132. package/dist/docs/reference/sessions.md +4 -2
  133. package/dist/docs/reference/skills.html +4 -4
  134. package/dist/docs/reference/subagents.html +4 -4
  135. package/dist/docs/reference/tools.html +6 -6
  136. package/dist/docs/reference/tools.md +9 -2
  137. package/dist/docs/scaffolding-agents.html +4 -4
  138. package/dist/docs/storage.html +4 -4
  139. package/dist/docs/templates/agentic-owners.html +4 -4
  140. package/dist/docs/templates/agents-md.html +28 -0
  141. package/dist/docs/templates/agents-md.md +105 -0
  142. package/dist/docs/templates/code-wiki.html +28 -0
  143. package/dist/docs/templates/code-wiki.md +91 -0
  144. package/dist/docs/templates/demo.html +5 -5
  145. package/dist/docs/templates/pr-autofixer.html +4 -4
  146. package/dist/docs/templates/security-help.html +4 -4
  147. package/dist/docs/templates/security-reviewer.html +5 -5
  148. package/dist/docs/templates/triage.html +4 -4
  149. package/dist/docs/troubleshooting.html +5 -5
  150. package/dist/docs/troubleshooting.md +2 -2
  151. package/dist/evals/run-facts.d.ts.map +1 -1
  152. package/dist/evals/run-facts.js +27 -0
  153. package/dist/files-backends/cursor-hosted.d.ts +26 -4
  154. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  155. package/dist/files-backends/cursor-hosted.js +32 -4
  156. package/dist/internal/advertise-tools.d.ts +2 -0
  157. package/dist/internal/advertise-tools.d.ts.map +1 -1
  158. package/dist/internal/advertise-tools.js +30 -10
  159. package/dist/internal/approval-gate.d.ts +12 -13
  160. package/dist/internal/approval-gate.d.ts.map +1 -1
  161. package/dist/internal/approval-gate.js +16 -21
  162. package/dist/internal/bounded.d.ts +7 -0
  163. package/dist/internal/bounded.d.ts.map +1 -0
  164. package/dist/internal/bounded.js +32 -0
  165. package/dist/internal/chat-client.js +10 -0
  166. package/dist/internal/cli-deploy.d.ts +5 -0
  167. package/dist/internal/cli-deploy.d.ts.map +1 -1
  168. package/dist/internal/cli-deploy.js +57 -18
  169. package/dist/internal/cli-mcp-oauth.js +8 -18
  170. package/dist/internal/cli-slack-manual.d.ts +24 -2
  171. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  172. package/dist/internal/cli-slack-manual.js +251 -20
  173. package/dist/internal/cli-slack.d.ts +9 -2
  174. package/dist/internal/cli-slack.d.ts.map +1 -1
  175. package/dist/internal/cli-slack.js +29 -82
  176. package/dist/internal/conversation-mirror.d.ts +11 -8
  177. package/dist/internal/conversation-mirror.d.ts.map +1 -1
  178. package/dist/internal/conversation-mirror.js +116 -55
  179. package/dist/internal/cursor/account-mcp.d.ts +1 -0
  180. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  181. package/dist/internal/cursor/account-mcp.js +17 -0
  182. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  183. package/dist/internal/cursor/backend-client.js +22 -48
  184. package/dist/internal/cursor/session-token.d.ts +45 -0
  185. package/dist/internal/cursor/session-token.d.ts.map +1 -0
  186. package/dist/internal/cursor/session-token.js +99 -0
  187. package/dist/internal/cursor-agent-template.d.ts +1 -1
  188. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  189. package/dist/internal/cursor-agent-template.js +2 -0
  190. package/dist/internal/deploy-client.d.ts +17 -0
  191. package/dist/internal/deploy-client.d.ts.map +1 -1
  192. package/dist/internal/deploy-client.js +31 -10
  193. package/dist/internal/env-file.d.ts +19 -0
  194. package/dist/internal/env-file.d.ts.map +1 -0
  195. package/dist/internal/env-file.js +90 -0
  196. package/dist/internal/framework-file-storage.d.ts +61 -0
  197. package/dist/internal/framework-file-storage.d.ts.map +1 -0
  198. package/dist/internal/framework-file-storage.js +210 -0
  199. package/dist/internal/framework-storage-selection.d.ts +11 -5
  200. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  201. package/dist/internal/framework-storage-selection.js +38 -11
  202. package/dist/internal/hosted-delivery-protocol.d.ts +7 -0
  203. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  204. package/dist/internal/hosted-delivery-protocol.js +7 -0
  205. package/dist/internal/hosted-delivery.d.ts +13 -0
  206. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  207. package/dist/internal/hosted-delivery.js +64 -19
  208. package/dist/internal/hosted-execution-diag.d.ts +48 -0
  209. package/dist/internal/hosted-execution-diag.d.ts.map +1 -0
  210. package/dist/internal/hosted-execution-diag.js +150 -0
  211. package/dist/internal/http-channel.d.ts.map +1 -1
  212. package/dist/internal/http-channel.js +81 -1
  213. package/dist/internal/init-project.d.ts.map +1 -1
  214. package/dist/internal/init-project.js +4 -0
  215. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  216. package/dist/internal/install-cursor-skills.js +1 -3
  217. package/dist/internal/logs-client.d.ts +5 -0
  218. package/dist/internal/logs-client.d.ts.map +1 -1
  219. package/dist/internal/logs-client.js +5 -0
  220. package/dist/internal/managed-delivery.d.ts +80 -0
  221. package/dist/internal/managed-delivery.d.ts.map +1 -0
  222. package/dist/internal/managed-delivery.js +86 -0
  223. package/dist/internal/mcp-endpoint.js +2 -3
  224. package/dist/internal/mcp-host.d.ts +10 -0
  225. package/dist/internal/mcp-host.d.ts.map +1 -1
  226. package/dist/internal/mcp-host.js +57 -8
  227. package/dist/internal/mcp-oauth-on-demand.d.ts +68 -0
  228. package/dist/internal/mcp-oauth-on-demand.d.ts.map +1 -0
  229. package/dist/internal/mcp-oauth-on-demand.js +287 -0
  230. package/dist/internal/mcp-oauth-persist.d.ts +42 -0
  231. package/dist/internal/mcp-oauth-persist.d.ts.map +1 -0
  232. package/dist/internal/mcp-oauth-persist.js +92 -0
  233. package/dist/internal/mcp-oauth.d.ts +1 -0
  234. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  235. package/dist/internal/mcp-oauth.js +10 -2
  236. package/dist/internal/otel/collector.d.ts.map +1 -1
  237. package/dist/internal/otel/collector.js +22 -9
  238. package/dist/internal/runtime-dispatch-runner.d.ts +5 -1
  239. package/dist/internal/runtime-dispatch-runner.d.ts.map +1 -1
  240. package/dist/internal/runtime-dispatch-runner.js +7 -0
  241. package/dist/internal/sdk-runner.d.ts +11 -0
  242. package/dist/internal/sdk-runner.d.ts.map +1 -1
  243. package/dist/internal/sdk-runner.js +39 -8
  244. package/dist/internal/server.d.ts +3 -0
  245. package/dist/internal/server.d.ts.map +1 -1
  246. package/dist/internal/server.js +49 -21
  247. package/dist/internal/session-engine.d.ts +101 -3
  248. package/dist/internal/session-engine.d.ts.map +1 -1
  249. package/dist/internal/session-engine.js +577 -46
  250. package/dist/internal/sessions-client.d.ts +9 -7
  251. package/dist/internal/sessions-client.d.ts.map +1 -1
  252. package/dist/internal/sessions-client.js +3 -1
  253. package/dist/internal/steering.d.ts +15 -0
  254. package/dist/internal/steering.d.ts.map +1 -0
  255. package/dist/internal/steering.js +18 -0
  256. package/dist/internal/storage-coordinator.d.ts +7 -0
  257. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  258. package/dist/internal/storage-coordinator.js +28 -5
  259. package/dist/internal/storage-roles.d.ts +5 -0
  260. package/dist/internal/storage-roles.d.ts.map +1 -1
  261. package/dist/internal/stream-progress.d.ts.map +1 -1
  262. package/dist/internal/stream-progress.js +10 -0
  263. package/dist/internal/tool-policy.d.ts +9 -1
  264. package/dist/internal/tool-policy.d.ts.map +1 -1
  265. package/dist/internal/tool-policy.js +13 -0
  266. package/dist/internal/trajectory.d.ts.map +1 -1
  267. package/dist/internal/trajectory.js +10 -0
  268. package/dist/internal/turn-outbox.d.ts +24 -0
  269. package/dist/internal/turn-outbox.d.ts.map +1 -0
  270. package/dist/internal/turn-outbox.js +80 -0
  271. package/dist/playground/assets/{index-CZA1uEWA.js → index-DrkI6y5O.js} +51 -51
  272. package/dist/playground/assets/index-DzNGwm7q.css +1 -0
  273. package/dist/playground/index.html +2 -2
  274. package/dist/storage-backends/cursor-hosted.d.ts +9 -6
  275. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  276. package/dist/storage-backends/cursor-hosted.js +16 -3
  277. package/dist/storage.d.ts +8 -0
  278. package/dist/storage.d.ts.map +1 -1
  279. package/dist/types.d.ts +65 -8
  280. package/dist/types.d.ts.map +1 -1
  281. package/docs/README.md +7 -3
  282. package/docs/deployment.md +5 -4
  283. package/docs/guides/mcp-oauth.md +26 -8
  284. package/docs/guides/slack.md +93 -202
  285. package/docs/reference/agent-config.md +2 -2
  286. package/docs/reference/cli.md +39 -16
  287. package/docs/reference/connections.md +6 -3
  288. package/docs/reference/http-api.md +2 -1
  289. package/docs/reference/sessions.md +4 -2
  290. package/docs/reference/tools.md +9 -2
  291. package/docs/templates/agents-md.md +110 -0
  292. package/docs/templates/code-wiki.md +96 -0
  293. package/docs/troubleshooting.md +2 -2
  294. package/package.json +2 -2
  295. package/skills/ab/SKILL.md +13 -97
  296. package/skills/create-agent/SKILL.md +124 -223
  297. package/skills/debug/SKILL.md +34 -68
  298. package/skills/evals/SKILL.md +55 -180
  299. package/skills/framework-map/SKILL.md +83 -145
  300. package/skills/github/SKILL.md +53 -111
  301. package/skills/hillclimb/SKILL.md +40 -163
  302. package/skills/mcp-auth/SKILL.md +51 -107
  303. package/skills/otel/SKILL.md +22 -68
  304. package/skills/setup-slack/SKILL.md +91 -212
  305. package/src/bin/agent-serve.ts +13 -1
  306. package/src/channels/deployments/types.ts +1 -0
  307. package/src/channels/origin/api.ts +264 -33
  308. package/src/channels/origin/binding.ts +57 -28
  309. package/src/channels/origin/checks.ts +6 -6
  310. package/src/channels/origin/cursor-account.ts +5 -3
  311. package/src/channels/origin/index.ts +1 -0
  312. package/src/channels/origin/origin-channel.ts +4 -0
  313. package/src/channels/origin/reactions.ts +82 -0
  314. package/src/channels/origin/types.ts +11 -0
  315. package/src/channels/slack/api.ts +41 -5
  316. package/src/channels/slack/approvals.ts +105 -0
  317. package/src/channels/slack/cli-project.ts +267 -0
  318. package/src/channels/slack/defaults.ts +122 -93
  319. package/src/channels/slack/dispatch.ts +56 -22
  320. package/src/channels/slack/inbound.ts +43 -0
  321. package/src/channels/slack/init.ts +10 -5
  322. package/src/channels/slack/interactive.ts +35 -9
  323. package/src/channels/slack/live-delivery.ts +235 -114
  324. package/src/channels/slack/manifest.ts +6 -2
  325. package/src/channels/slack/nudge-carrier.ts +48 -1
  326. package/src/channels/slack/setup.ts +10 -6
  327. package/src/channels/slack/slack-channel.ts +3 -0
  328. package/src/channels/slack/tool-approval-events.ts +93 -0
  329. package/src/evals/run-facts.ts +32 -0
  330. package/src/files-backends/cursor-hosted.ts +40 -7
  331. package/src/internal/advertise-tools.ts +49 -12
  332. package/src/internal/approval-gate.ts +20 -29
  333. package/src/internal/bounded.ts +28 -0
  334. package/src/internal/chat-client.ts +19 -0
  335. package/src/internal/cli-deploy.ts +91 -9
  336. package/src/internal/cli-mcp-oauth.ts +7 -21
  337. package/src/internal/cli-slack-manual.ts +350 -18
  338. package/src/internal/cli-slack.ts +40 -84
  339. package/src/internal/conversation-mirror.ts +145 -69
  340. package/src/internal/cursor/account-mcp.ts +21 -0
  341. package/src/internal/cursor/backend-client.ts +34 -58
  342. package/src/internal/cursor/session-token.ts +115 -0
  343. package/src/internal/cursor-agent-template.ts +2 -0
  344. package/src/internal/deploy-client.ts +43 -0
  345. package/src/internal/env-file.ts +84 -0
  346. package/src/internal/framework-file-storage.ts +228 -0
  347. package/src/internal/framework-storage-selection.ts +51 -11
  348. package/src/internal/hosted-delivery-protocol.ts +7 -0
  349. package/src/internal/hosted-delivery.ts +107 -24
  350. package/src/internal/hosted-execution-diag.ts +207 -0
  351. package/src/internal/http-channel.ts +99 -0
  352. package/src/internal/init-project.ts +4 -0
  353. package/src/internal/install-cursor-skills.ts +1 -4
  354. package/src/internal/logs-client.ts +5 -0
  355. package/src/internal/managed-delivery.ts +125 -0
  356. package/src/internal/mcp-endpoint.ts +13 -4
  357. package/src/internal/mcp-host.ts +77 -11
  358. package/src/internal/mcp-oauth-on-demand.ts +352 -0
  359. package/src/internal/mcp-oauth-persist.ts +127 -0
  360. package/src/internal/mcp-oauth.ts +17 -1
  361. package/src/internal/otel/collector.ts +30 -0
  362. package/src/internal/runtime-dispatch-runner.ts +10 -0
  363. package/src/internal/sdk-runner.ts +56 -8
  364. package/src/internal/server.ts +61 -9
  365. package/src/internal/session-engine.ts +723 -60
  366. package/src/internal/sessions-client.ts +17 -8
  367. package/src/internal/steering.ts +17 -0
  368. package/src/internal/storage-coordinator.ts +38 -8
  369. package/src/internal/storage-roles.ts +7 -0
  370. package/src/internal/stream-progress.ts +19 -0
  371. package/src/internal/tool-policy.ts +18 -0
  372. package/src/internal/trajectory.ts +10 -0
  373. package/src/internal/turn-outbox.ts +85 -0
  374. package/src/storage-backends/cursor-hosted.ts +22 -8
  375. package/src/storage.ts +12 -0
  376. package/src/types.ts +70 -9
  377. package/templates/agents-md/README.md +39 -0
  378. package/templates/agents-md/agent/agent.ts +8 -0
  379. package/templates/agents-md/agent/channels/github.ts +10 -0
  380. package/templates/agents-md/agent/channels/queue.ts +28 -0
  381. package/templates/agents-md/agent/channels/slack.ts +9 -0
  382. package/templates/agents-md/agent/instructions.md +39 -0
  383. package/templates/agents-md/agent/lib/collect.ts +439 -0
  384. package/templates/agents-md/agent/lib/config.ts +8 -0
  385. package/templates/agents-md/agent/lib/paths.ts +51 -0
  386. package/templates/agents-md/agent/schedules/weekly.ts +17 -0
  387. package/templates/agents-md/agent/tools/apply_agents.ts +226 -0
  388. package/templates/agents-md/evals/agents.eval.ts +135 -0
  389. package/templates/agents-md/evals/evals.config.ts +5 -0
  390. package/templates/agents-md/init.json +38 -0
  391. package/templates/agents-md/package.json +18 -0
  392. package/templates/agents-md/tsconfig.json +12 -0
  393. package/templates/code-wiki/README.md +34 -0
  394. package/templates/code-wiki/agent/agent.ts +8 -0
  395. package/templates/code-wiki/agent/channels/github.ts +144 -0
  396. package/templates/code-wiki/agent/instructions.md +39 -0
  397. package/templates/code-wiki/agent/lib/repos.ts +5 -0
  398. package/templates/code-wiki/agent/lib/wiki.ts +22 -0
  399. package/templates/code-wiki/agent/tools/apply_wiki.ts +219 -0
  400. package/templates/code-wiki/evals/evals.config.ts +5 -0
  401. package/templates/code-wiki/evals/wiki.eval.ts +132 -0
  402. package/templates/code-wiki/init.json +25 -0
  403. package/templates/code-wiki/package.json +18 -0
  404. package/templates/code-wiki/tsconfig.json +12 -0
  405. package/dist/docs/assets/chunks/@localSearchIndexroot.oqPawjiD.js +0 -1
  406. package/dist/docs/assets/guides_slack.md.C32HsdKk.js +0 -38
  407. package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +0 -1
  408. package/dist/docs/assets/index.md.BoHaMdeZ.js +0 -5
  409. package/dist/docs/assets/reference_sessions.md.D0mIh4KK.js +0 -1
  410. package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +0 -1
  411. package/dist/docs/design/agsh.md +0 -406
  412. package/dist/internal/deployment-scm-event-stream.d.ts +0 -116
  413. package/dist/internal/deployment-scm-event-stream.d.ts.map +0 -1
  414. package/dist/internal/deployment-scm-event-stream.js +0 -474
  415. package/dist/playground/assets/index-CF7hUDnQ.css +0 -1
  416. package/docs/design/agsh.md +0 -406
  417. package/src/internal/deployment-scm-event-stream.ts +0 -593
  418. /package/dist/docs/assets/{deployment.md.D9msOFOW.lean.js → deployment.md.MFPKqsqI.lean.js} +0 -0
  419. /package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.lean.js → reference_agent-config.md.BHeYMgme.lean.js} +0 -0
  420. /package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.lean.js → reference_connections.md.DxldvyIB.lean.js} +0 -0
  421. /package/dist/docs/assets/{reference_http-api.md.D89k1mdm.lean.js → reference_http-api.md.5zOAbV86.lean.js} +0 -0
  422. /package/dist/docs/assets/{reference_sessions.md.D0mIh4KK.lean.js → reference_sessions.md.NxFP_CAC.lean.js} +0 -0
  423. /package/dist/docs/assets/{reference_tools.md.BHeXn2id.lean.js → reference_tools.md.B84gw9Ii.lean.js} +0 -0
  424. /package/dist/docs/assets/{troubleshooting.md.Ctv3T8C2.lean.js → troubleshooting.md.DCiPBhYs.lean.js} +0 -0
@@ -1,22 +1,37 @@
1
1
  /**
2
2
  * Origin public REST helpers (`https://api.cursor.com/v1/origin/...`).
3
3
  *
4
- * Origin writes such as CI check runs are installation-only: they need an
5
- * `oit_…` installation token minted from Origin app credentials (EdDSA app
6
- * JWT → `/v1/origin/app/installations/{id}/access_tokens`). This module
7
- * consolidates that flow so agents configure credentials once and call
8
- * {@link createOriginClient} — the GitHub-channel analogue of
4
+ * This module consolidates Origin auth so agents configure credentials once
5
+ * and call {@link createOriginClient} the GitHub-channel analogue of
9
6
  * `createGitHubOctokit`.
10
7
  *
11
- * Credentials resolve from options first, then the environment:
12
- * `ORIGIN_APP_ID` (or `AGENT_SERVE_ORIGIN_APP_ID`),
13
- * `ORIGIN_APP_INSTALLATION_ID`, `ORIGIN_APP_PRIVATE_KEY` (PKCS8 PEM for the
14
- * app's Ed25519 key; literal `\n` sequences are normalized), and
15
- * `ORIGIN_API_BASE_URL` for the public REST base.
8
+ * Self-configured channels with their own Origin app resolve credentials
9
+ * from options first, then the environment: `ORIGIN_APP_ID` (or
10
+ * `AGENT_SERVE_ORIGIN_APP_ID`), `ORIGIN_APP_INSTALLATION_ID`,
11
+ * `ORIGIN_APP_PRIVATE_KEY` (PKCS8 PEM for the app's Ed25519 key; literal
12
+ * `\n` sequences are normalized), `ORIGIN_API_BASE_URL` for the public REST
13
+ * base, and `ORIGIN_RPC_BASE_URL` for the first-party ConnectRPC base.
14
+ *
15
+ * Hosted v2 forks configure none of that: their only credential is the
16
+ * deployment service account's `CURSOR_API_KEY`, exchanged for a Cursor
17
+ * session ({@link cursorSessionTokenProvider}, `POST
18
+ * /auth/exchange_user_api_key`) and sent as the Origin bearer. Reads and
19
+ * writes both run as the deployment **service-account principal**; Origin's
20
+ * `agent-serve` allowlist grants team-namespace read/write, so there is no
21
+ * app-installation token exchange for managed deployments.
16
22
  */
17
23
 
18
24
  import { Buffer } from "node:buffer";
19
25
  import { createPrivateKey, sign } from "node:crypto";
26
+ import {
27
+ cursorBackendUrl,
28
+ resolveApiKeySync,
29
+ } from "../../internal/cursor/credentials.js";
30
+ import {
31
+ CURSOR_SESSION_EXCHANGE_PATH,
32
+ exchangeCursorApiKeyForSession,
33
+ SESSION_TOKEN_EXPIRY_LEEWAY_MS,
34
+ } from "../../internal/cursor/session-token.js";
20
35
 
21
36
  /**
22
37
  * Public Origin REST base (check runs, installation tokens). Distinct from
@@ -25,6 +40,15 @@ import { createPrivateKey, sign } from "node:crypto";
25
40
  */
26
41
  export const DEFAULT_ORIGIN_PUBLIC_API_BASE_URL = "https://api.cursor.com";
27
42
 
43
+ /**
44
+ * Origin's first-party ConnectRPC host (`origin.v1.OriginService`). Separate
45
+ * deployment from {@link DEFAULT_ORIGIN_PUBLIC_API_BASE_URL}: a handful of
46
+ * workflow operations — comment reactions among them — have no
47
+ * `/v1/origin/...` REST binding yet and are only reachable as Connect unary
48
+ * JSON here.
49
+ */
50
+ export const DEFAULT_ORIGIN_RPC_BASE_URL = "https://api.origin.cursor.com";
51
+
28
52
  /** Fixed audience for Origin app JWTs (`APP_TOKEN_AUDIENCE` backend-side). */
29
53
  const ORIGIN_APP_TOKEN_AUDIENCE = "origin-apps";
30
54
  const APP_JWT_TTL_SECONDS = 5 * 60;
@@ -58,7 +82,10 @@ export class OriginApiError extends Error {
58
82
  }
59
83
  }
60
84
 
61
- /** Yields a bearer for Origin REST calls (usually a short-lived `oit_…`). */
85
+ /**
86
+ * Yields a bearer for Origin REST calls (a short-lived `oit_…` for app
87
+ * channels, or a Cursor session token for service-account access).
88
+ */
62
89
  export type OriginTokenProvider = () => Promise<string>;
63
90
 
64
91
  export interface OriginAppCredentials {
@@ -121,6 +148,12 @@ export function originPublicApiBaseUrl(
121
148
  return fromEnv ?? DEFAULT_ORIGIN_PUBLIC_API_BASE_URL;
122
149
  }
123
150
 
151
+ /** Origin ConnectRPC base. Trailing slashes are stripped for path joins. */
152
+ export function originRpcBaseUrl(env: NodeJS.ProcessEnv = process.env): string {
153
+ const fromEnv = envValue(env.ORIGIN_RPC_BASE_URL)?.replace(/\/+$/, "");
154
+ return fromEnv ?? DEFAULT_ORIGIN_RPC_BASE_URL;
155
+ }
156
+
124
157
  function base64UrlJson(value: unknown): string {
125
158
  return Buffer.from(JSON.stringify(value)).toString("base64url");
126
159
  }
@@ -181,6 +214,147 @@ async function mintOriginInstallationToken(input: {
181
214
  return token;
182
215
  }
183
216
 
217
+ /**
218
+ * Exchange endpoint for Cursor-account session tokens. Override with
219
+ * `AGENT_SERVE_CURSOR_SESSION_EXCHANGE_URL`; defaults to the Cursor backend.
220
+ */
221
+ export function resolveCursorSessionExchangeUrl(): string {
222
+ const override = process.env.AGENT_SERVE_CURSOR_SESSION_EXCHANGE_URL;
223
+ if (override !== undefined && override.trim() !== "") {
224
+ return override.trim().replace(/\/+$/, "");
225
+ }
226
+ return `${cursorBackendUrl()}${CURSOR_SESSION_EXCHANGE_PATH}`;
227
+ }
228
+
229
+ /**
230
+ * A session-backed Origin token provider: {@link OriginTokenProvider} plus
231
+ * an `invalidate` hook `createOriginClient` calls when Origin rejects the
232
+ * bearer (401), so the next mint re-exchanges instead of serving the
233
+ * rejected session until its local renewal deadline.
234
+ */
235
+ export type CursorSessionTokenProvider = OriginTokenProvider & {
236
+ invalidate: (token: string) => void;
237
+ };
238
+
239
+ /**
240
+ * Token provider backed by the shared Cursor session exchange
241
+ * (`exchangeCursorApiKeyForSession`, `POST /auth/exchange_user_api_key` —
242
+ * the same primitive `CursorBackendClient` mints through).
243
+ *
244
+ * Hosted v2 forks hold exactly one credential — the deployment service
245
+ * account's `CURSOR_API_KEY` — and Origin authenticates the exchanged
246
+ * session directly: reads and writes run as the deployment
247
+ * **service-account principal**, confined server-side to namespaces owned
248
+ * by the deployment's team (`agent-serve` allowlist). Local runs work the
249
+ * same way with a personal key: Origin authorizes the user principal.
250
+ *
251
+ * The API key is re-read on every mint so Bind can drop
252
+ * `CURSOR_API_KEY_FILE` onto a listening process; sessions are cached until
253
+ * shortly before their JWT expiry. The cache is **process-wide**, keyed by
254
+ * (endpoint, API key): hosted channels build a fresh `createOriginClient()`
255
+ * per event, so a per-provider cache would re-exchange on every read/write
256
+ * and concurrent first calls would race. In-flight exchanges are deduped
257
+ * for the same reason.
258
+ */
259
+ const cursorSessionTokenCache = new Map<
260
+ string,
261
+ { token: string; renewAtMs: number }
262
+ >();
263
+ const cursorSessionTokenInFlight = new Map<string, Promise<string>>();
264
+
265
+ /** Test-only: drop the process-wide exchanged-session cache. */
266
+ export function _clearCursorSessionTokenCacheForTesting(): void {
267
+ cursorSessionTokenCache.clear();
268
+ cursorSessionTokenInFlight.clear();
269
+ }
270
+
271
+ export function cursorSessionTokenProvider(input?: {
272
+ /** Cursor API key source. Defaults to the standard host resolution. */
273
+ getApiKey?: () => string | undefined;
274
+ /** Exchange endpoint. Defaults to {@link resolveCursorSessionExchangeUrl}. */
275
+ exchangeUrl?: string;
276
+ fetch?: typeof fetch;
277
+ now?: () => number;
278
+ }): CursorSessionTokenProvider {
279
+ const getApiKey =
280
+ input?.getApiKey ?? ((): string | undefined => resolveApiKeySync()?.apiKey);
281
+ const fetchImpl = input?.fetch ?? fetch;
282
+ const now = input?.now ?? Date.now;
283
+
284
+ const cacheKey = (url: string, apiKey: string): string =>
285
+ `${url}\u0000${apiKey}`;
286
+ const resolveUrl = (): string =>
287
+ input?.exchangeUrl ?? resolveCursorSessionExchangeUrl();
288
+
289
+ const mint = async (url: string, apiKey: string): Promise<string> => {
290
+ const nowMs = now();
291
+ let session: { token: string; expiresAtMs: number };
292
+ try {
293
+ session = await exchangeCursorApiKeyForSession({
294
+ exchangeUrl: url,
295
+ apiKey,
296
+ fetchImpl,
297
+ nowMs,
298
+ });
299
+ } catch (error) {
300
+ throw new Error(
301
+ `originClient: ${
302
+ error instanceof Error ? error.message : String(error)
303
+ } Check CURSOR_API_KEY / CURSOR_API_KEY_FILE, or pass an explicit token.`
304
+ );
305
+ }
306
+ const renewAtMs = Math.max(
307
+ nowMs + 1_000,
308
+ session.expiresAtMs - SESSION_TOKEN_EXPIRY_LEEWAY_MS
309
+ );
310
+ cursorSessionTokenCache.set(cacheKey(url, apiKey), {
311
+ token: session.token,
312
+ renewAtMs,
313
+ });
314
+ return session.token;
315
+ };
316
+
317
+ const provider = async (): Promise<string> => {
318
+ const apiKey = getApiKey();
319
+ if (apiKey === undefined || apiKey === "") {
320
+ throw new Error(
321
+ "originClient: no Cursor credential available for the session exchange (set CURSOR_API_KEY or CURSOR_API_KEY_FILE)."
322
+ );
323
+ }
324
+ const url = resolveUrl();
325
+ const key = cacheKey(url, apiKey);
326
+ const cached = cursorSessionTokenCache.get(key);
327
+ if (cached !== undefined && now() < cached.renewAtMs) {
328
+ return cached.token;
329
+ }
330
+ // Dedupe concurrent first calls: one exchange per (endpoint, key).
331
+ const inFlight = cursorSessionTokenInFlight.get(key);
332
+ if (inFlight !== undefined) {
333
+ return await inFlight;
334
+ }
335
+ const pending = mint(url, apiKey).finally(() => {
336
+ cursorSessionTokenInFlight.delete(key);
337
+ });
338
+ cursorSessionTokenInFlight.set(key, pending);
339
+ return await pending;
340
+ };
341
+
342
+ // Origin answered 401 for this bearer: drop it (unless a newer session
343
+ // already replaced it) so the next call re-exchanges immediately.
344
+ const invalidate = (token: string): void => {
345
+ const apiKey = getApiKey();
346
+ if (apiKey === undefined || apiKey === "") {
347
+ return;
348
+ }
349
+ const key = cacheKey(resolveUrl(), apiKey);
350
+ if (cursorSessionTokenCache.get(key)?.token === token) {
351
+ cursorSessionTokenCache.delete(key);
352
+ }
353
+ };
354
+
355
+ return Object.assign(provider, { invalidate });
356
+ }
357
+
184
358
  /**
185
359
  * A cached per-use token provider for one set of app credentials. Every call
186
360
  * inside the reuse window returns the same `oit_…`; the first call after it
@@ -217,13 +391,26 @@ export interface OriginClientOptions {
217
391
  token?: string | OriginTokenProvider;
218
392
  /**
219
393
  * App credentials to mint installation tokens from. Defaults to the
220
- * environment ({@link resolveOriginAppCredentials}).
394
+ * environment ({@link resolveOriginAppCredentials}). Pass `false` to
395
+ * disable app credential lookup and force the Cursor-account exchange.
221
396
  */
222
- credentials?: OriginAppCredentials;
397
+ credentials?: OriginAppCredentials | false;
223
398
  /** Public Origin REST base. Defaults to `ORIGIN_API_BASE_URL` / prod. */
224
399
  apiBaseUrl?: string;
225
400
  /** Injectable fetch for tests. */
226
401
  fetch?: typeof fetch;
402
+ /**
403
+ * Cursor-account session exchange fallback (hosted v2 deployment SAs and
404
+ * local personal keys). `true` (default) engages when no explicit token
405
+ * or app credentials resolve and a Cursor credential is present; `false`
406
+ * disables it; an object injects the key source / endpoint.
407
+ */
408
+ cursorAccountExchange?:
409
+ | boolean
410
+ | {
411
+ getApiKey?: () => string | undefined;
412
+ exchangeUrl?: string;
413
+ };
227
414
  }
228
415
 
229
416
  /** Minimal authenticated Origin REST client (the `Octokit` analogue). */
@@ -242,8 +429,11 @@ export interface OriginClient {
242
429
 
243
430
  /**
244
431
  * Build an authenticated Origin REST client. Auth resolution: explicit
245
- * token/provider, then app credentials (options or environment). Missing
246
- * auth fails at the first request with a clear message.
432
+ * token/provider, then app credentials (options or environment, for
433
+ * channels with their own Origin app), then the Cursor-account session
434
+ * exchange (hosted v2 deployment SAs — reads and writes both run as the
435
+ * deployment service-account principal). Missing auth fails at the first
436
+ * request with a clear message.
247
437
  */
248
438
  export function createOriginClient(
249
439
  options: OriginClientOptions = {}
@@ -255,6 +445,10 @@ export function createOriginClient(
255
445
  const fetchImpl = options.fetch ?? fetch;
256
446
 
257
447
  let tokenProvider: OriginTokenProvider | undefined;
448
+ // Set when the session-exchange fallback is engaged: a 401 from Origin
449
+ // invalidates the cached session and retries once with a fresh one, the
450
+ // `CursorBackendClient` re-exchange behavior.
451
+ let sessionProvider: CursorSessionTokenProvider | undefined;
258
452
  const getToken = async (): Promise<string> => {
259
453
  if (typeof options.token === "string") {
260
454
  return options.token;
@@ -263,21 +457,59 @@ export function createOriginClient(
263
457
  return await options.token();
264
458
  }
265
459
  if (tokenProvider === undefined) {
266
- const credentials = options.credentials ?? resolveOriginAppCredentials();
267
- if (credentials === undefined) {
460
+ const credentials =
461
+ options.credentials === false
462
+ ? undefined
463
+ : (options.credentials ?? resolveOriginAppCredentials());
464
+ const exchange = options.cursorAccountExchange ?? true;
465
+ const exchangeOptions =
466
+ exchange === false ? undefined : exchange === true ? {} : exchange;
467
+ const getExchangeApiKey =
468
+ exchangeOptions?.getApiKey ??
469
+ ((): string | undefined => resolveApiKeySync()?.apiKey);
470
+ if (credentials !== undefined) {
471
+ tokenProvider = originAppTokenProvider({
472
+ credentials,
473
+ apiBaseUrl,
474
+ fetch: fetchImpl,
475
+ });
476
+ } else if (
477
+ exchangeOptions !== undefined &&
478
+ (getExchangeApiKey() ?? "") !== ""
479
+ ) {
480
+ sessionProvider = cursorSessionTokenProvider({
481
+ fetch: fetchImpl,
482
+ getApiKey: getExchangeApiKey,
483
+ ...(exchangeOptions.exchangeUrl === undefined
484
+ ? {}
485
+ : { exchangeUrl: exchangeOptions.exchangeUrl }),
486
+ });
487
+ tokenProvider = sessionProvider;
488
+ } else {
268
489
  throw new Error(
269
- "originClient: no Origin credential available (pass token / credentials, or set ORIGIN_APP_ID + ORIGIN_APP_INSTALLATION_ID + ORIGIN_APP_PRIVATE_KEY)."
490
+ "originClient: no Origin credential available (pass token / credentials, set ORIGIN_APP_ID + ORIGIN_APP_INSTALLATION_ID + ORIGIN_APP_PRIVATE_KEY, or sign in with a Cursor credential for the session exchange)."
270
491
  );
271
492
  }
272
- tokenProvider = originAppTokenProvider({
273
- credentials,
274
- apiBaseUrl,
275
- fetch: fetchImpl,
276
- });
277
493
  }
278
494
  return await tokenProvider();
279
495
  };
280
496
 
497
+ const send = async (
498
+ input: { method: OriginApiMethod; path: string; body?: unknown },
499
+ path: string,
500
+ token: string
501
+ ): Promise<Response> =>
502
+ await fetchImpl(`${apiBaseUrl}${path}`, {
503
+ method: input.method,
504
+ headers: {
505
+ authorization: `Bearer ${token}`,
506
+ ...(input.body === undefined
507
+ ? {}
508
+ : { "content-type": "application/json" }),
509
+ },
510
+ body: input.body === undefined ? undefined : JSON.stringify(input.body),
511
+ });
512
+
281
513
  return {
282
514
  apiBaseUrl,
283
515
  async request<T = unknown>(input: {
@@ -287,16 +519,15 @@ export function createOriginClient(
287
519
  }): Promise<T> {
288
520
  const path = input.path.startsWith("/") ? input.path : `/${input.path}`;
289
521
  const token = await getToken();
290
- const response = await fetchImpl(`${apiBaseUrl}${path}`, {
291
- method: input.method,
292
- headers: {
293
- authorization: `Bearer ${token}`,
294
- ...(input.body === undefined
295
- ? {}
296
- : { "content-type": "application/json" }),
297
- },
298
- body: input.body === undefined ? undefined : JSON.stringify(input.body),
299
- });
522
+ let response = await send(input, path, token);
523
+ if (response.status === 401 && sessionProvider !== undefined) {
524
+ // The session aged out server-side. Drop it — unless a concurrent
525
+ // retry already minted a newer one — and retry once.
526
+ await response.text().catch(() => undefined);
527
+ sessionProvider.invalidate(token);
528
+ const retryToken = await getToken();
529
+ response = await send(input, path, retryToken);
530
+ }
300
531
  const text = await response.text();
301
532
  let parsed: unknown;
302
533
  try {
@@ -13,6 +13,7 @@ import {
13
13
  createOriginClient,
14
14
  type OriginApiMethod,
15
15
  type OriginClient,
16
+ originRpcBaseUrl,
16
17
  resolveOriginAppCredentialParts,
17
18
  } from "./api.js";
18
19
  import {
@@ -20,6 +21,10 @@ import {
20
21
  type OriginCheck,
21
22
  type OriginCheckCreateInput,
22
23
  } from "./checks.js";
24
+ import {
25
+ type OriginCommentReactionInput,
26
+ setOriginCommentReaction,
27
+ } from "./reactions.js";
23
28
  import type { OriginAppOptions, OriginRepositoryRef } from "./types.js";
24
29
 
25
30
  /** Origin operations exposed to hooks (`ctx.origin`). */
@@ -38,59 +43,83 @@ export interface OriginHandle {
38
43
  }): Promise<T>;
39
44
  /**
40
45
  * Open a CI check run on `sha` and get a handle for updating and
41
- * concluding it. Needs an app installation with
42
- * `repository:checks:write` Origin check writes are installation-only.
46
+ * concluding it. Needs `repository:checks:write` — via an app
47
+ * installation, or the deployment service account on hosted v2 forks.
43
48
  */
44
49
  createCheck(
45
50
  input: Omit<OriginCheckCreateInput, "origin" | "owner" | "repo">
46
51
  ): Promise<OriginCheck>;
52
+ /**
53
+ * Add or remove one reaction on a PR comment — the Origin analogue of
54
+ * GitHub's `thread.react("eyes")`. Needs
55
+ * `repository:pull_requests:reviews:write`. Reactions have no REST
56
+ * binding, so this call goes to Origin's ConnectRPC host rather than the
57
+ * public API base {@link request} uses.
58
+ */
59
+ reactToComment(input: OriginCommentReactionInput): Promise<void>;
47
60
  }
48
61
 
49
62
  export function buildOriginBinding(input: {
50
63
  repository: OriginRepositoryRef;
51
64
  /** Installation id from the delivery envelope, when present. */
52
65
  installationId?: string;
66
+ /** Force the signed-in Cursor account / deployment SA credential path. */
67
+ cursorAccount?: boolean;
53
68
  /** Channel-authored outbound app credentials / API base. */
54
69
  app?: OriginAppOptions;
55
70
  /** Injectable fetch for tests. */
56
71
  fetch?: typeof fetch;
57
72
  }): OriginHandle {
58
- let client: OriginClient | undefined;
59
- const getClient = (): OriginClient => {
60
- if (client === undefined) {
61
- const fromEnv = resolveOriginAppCredentialParts();
62
- const appId = input.app?.appId ?? fromEnv.appId;
63
- const installationId =
64
- input.app?.installationId ??
65
- input.installationId ??
66
- fromEnv.installationId;
67
- const privateKey = input.app?.privateKey ?? fromEnv.privateKey;
68
- const credentials =
69
- appId !== undefined &&
70
- installationId !== undefined &&
71
- privateKey !== undefined
72
- ? { appId, installationId, privateKey }
73
- : undefined;
74
- client = createOriginClient({
75
- token: input.app?.token,
76
- credentials,
77
- apiBaseUrl: input.app?.apiBaseUrl,
78
- fetch: input.fetch,
79
- });
80
- }
81
- return client;
73
+ const buildClient = (apiBaseUrl: string | undefined): OriginClient => {
74
+ const fromEnv = input.cursorAccount
75
+ ? {}
76
+ : resolveOriginAppCredentialParts();
77
+ const appId = input.app?.appId ?? fromEnv.appId;
78
+ const installationId =
79
+ input.app?.installationId ??
80
+ input.installationId ??
81
+ fromEnv.installationId;
82
+ const privateKey = input.app?.privateKey ?? fromEnv.privateKey;
83
+ const credentials =
84
+ appId !== undefined &&
85
+ installationId !== undefined &&
86
+ privateKey !== undefined
87
+ ? { appId, installationId, privateKey }
88
+ : undefined;
89
+ return createOriginClient({
90
+ token: input.cursorAccount ? undefined : input.app?.token,
91
+ credentials: input.cursorAccount ? false : credentials,
92
+ apiBaseUrl,
93
+ fetch: input.fetch,
94
+ });
95
+ };
96
+
97
+ // Public REST and ConnectRPC are separate Origin deployments, so the
98
+ // handle keeps a client per host. Both stay lazy: a hook that touches
99
+ // neither needs no credential.
100
+ let restClient: OriginClient | undefined;
101
+ const getRestClient = (): OriginClient => {
102
+ restClient ??= buildClient(input.app?.apiBaseUrl);
103
+ return restClient;
104
+ };
105
+ let rpcClient: OriginClient | undefined;
106
+ const getRpcClient = (): OriginClient => {
107
+ rpcClient ??= buildClient(input.app?.rpcBaseUrl ?? originRpcBaseUrl());
108
+ return rpcClient;
82
109
  };
83
110
 
84
111
  return {
85
112
  installationId: input.app?.installationId ?? input.installationId,
86
113
  repository: input.repository,
87
- request: (request) => getClient().request(request),
114
+ request: (request) => getRestClient().request(request),
88
115
  createCheck: (check) =>
89
116
  createOriginCheck({
90
117
  ...check,
91
- origin: getClient(),
118
+ origin: getRestClient(),
92
119
  owner: input.repository.owner,
93
120
  repo: input.repository.name,
94
121
  }),
122
+ reactToComment: (reaction) =>
123
+ setOriginCommentReaction({ ...reaction, origin: getRpcClient() }),
95
124
  };
96
125
  }
@@ -7,12 +7,12 @@
7
7
  * fresh `externalUpdatedAt`, and `resumeOriginCheck` needs only those
8
8
  * identity fields (no server id) to rebuild a handle after a restart.
9
9
  *
10
- * Posting needs `repository:checks:write` and is installation-only: the
11
- * client must authenticate with an `oit_…` installation token (see
12
- * `createOriginClient` / `originAppTokenProvider` in `api.js`). Works with
13
- * any client exposing `request()` (`ctx.origin`, `createOriginClient()`),
14
- * and is also reachable as `ctx.origin.createCheck(...)`. API failures throw
15
- * `OriginApiError`.
10
+ * Posting needs `repository:checks:write`: an `oit_…` installation token for
11
+ * app channels, or a deployment service-account session (hosted v2 forks —
12
+ * the `agent-serve` allowlist grants checks:write on team-owned namespaces).
13
+ * See `createOriginClient` in `api.js`. Works with any client exposing
14
+ * `request()` (`ctx.origin`, `createOriginClient()`), and is also reachable
15
+ * as `ctx.origin.createCheck(...)`. API failures throw `OriginApiError`.
16
16
  */
17
17
 
18
18
  import {
@@ -3,9 +3,11 @@
3
3
  *
4
4
  * Origin identity is the signed-in Cursor user (no third-party OAuth). The
5
5
  * channel declares repos at definition time; the serve host subscribes
6
- * `/v0/scm-events` with `provider: "origin"` as that user. Unlike GitHub,
7
- * there is no installation token to mint outbound Origin API calls already
8
- * authenticate as the Cursor principal.
6
+ * `/v0/scm-events` with `provider: "origin"` as that user. Outbound Origin
7
+ * API calls authenticate with the channel's app credentials when configured;
8
+ * hosted v2 deployments instead exchange the Cursor credential for a
9
+ * session (`cursorSessionTokenProvider` in ./api.ts), so reads and writes
10
+ * both run as the deployment service-account principal.
9
11
  */
10
12
 
11
13
  import type { OriginChannelOptions } from "./types.js";
@@ -29,4 +29,5 @@ export * from "./cursor-account.js";
29
29
  export * from "./events.js";
30
30
  export * from "./origin-channel.js";
31
31
  export * from "./origin-webhook.js";
32
+ export * from "./reactions.js";
32
33
  export * from "./types.js";
@@ -306,6 +306,7 @@ export function parseOriginPullRequestEvent(input: {
306
306
  repository,
307
307
  pullRequestNumber: number,
308
308
  pullRequestUrl: url,
309
+ pullRequestAuthor: author,
309
310
  payload,
310
311
  sender: originSender(input.envelope, payload),
311
312
  },
@@ -432,6 +433,9 @@ function enrichEventContext(input: {
432
433
  origin: buildOriginBinding({
433
434
  repository: input.ctx.repository,
434
435
  installationId: input.ctx.installationId,
436
+ cursorAccount:
437
+ input.options.cursorAccount !== undefined &&
438
+ input.options.cursorAccount !== false,
435
439
  app: input.options.app,
436
440
  }),
437
441
  };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Origin PR comment reactions — the Origin analogue of the GitHub channel's
3
+ * `thread.react("eyes")`.
4
+ *
5
+ * Unlike checks and comments, reactions have no `/v1/origin/...` REST
6
+ * binding. The only write is Connect unary JSON against Origin's first-party
7
+ * service (`origin.v1.OriginService/SetCommentReaction`), which lives on a
8
+ * different host than the public REST API — {@link originRpcBaseUrl}, not
9
+ * {@link originPublicApiBaseUrl}. `ctx.origin.reactToComment` already points
10
+ * at the right one; a hand-built client must too.
11
+ *
12
+ * Writing needs `repository:pull_requests:reviews:write`: an `oit_…`
13
+ * installation token for app channels, or a deployment service-account
14
+ * session (hosted v2 forks). Origin rejects reactions on comments that
15
+ * belong to an unsubmitted review. API failures throw `OriginApiError`.
16
+ */
17
+
18
+ import type { OriginApiMethod } from "./api.js";
19
+
20
+ /** Any client that can call Origin's ConnectRPC host. */
21
+ export interface OriginReactionClient {
22
+ request<T = unknown>(input: {
23
+ method: OriginApiMethod;
24
+ path: string;
25
+ body?: unknown;
26
+ }): Promise<T>;
27
+ }
28
+
29
+ /** Connect unary route backing {@link setOriginCommentReaction}. */
30
+ export const SET_ORIGIN_COMMENT_REACTION_PATH =
31
+ "/origin.v1.OriginService/SetCommentReaction";
32
+
33
+ /**
34
+ * The eight reactions Origin accepts. Anything else is rejected with
35
+ * `invalid_argument`, so channels get a compile error instead of a 400.
36
+ */
37
+ export const ORIGIN_COMMENT_REACTIONS = [
38
+ "👍",
39
+ "👎",
40
+ "😄",
41
+ "🎉",
42
+ "😕",
43
+ "❤️",
44
+ "🚀",
45
+ "👀",
46
+ ] as const;
47
+
48
+ export type OriginCommentReaction = (typeof ORIGIN_COMMENT_REACTIONS)[number];
49
+
50
+ export interface OriginCommentReactionInput {
51
+ /** Origin comment TypeID (`cmt_…`), i.e. `comment.id` on a comment hook. */
52
+ commentId: string;
53
+ emoji: OriginCommentReaction;
54
+ /** `false` removes the reaction. Removing one that is absent is a no-op. */
55
+ active?: boolean;
56
+ }
57
+
58
+ /**
59
+ * Add (or, with `active: false`, remove) one reaction on an Origin PR
60
+ * comment as the client's own principal.
61
+ *
62
+ * ```ts
63
+ * await setOriginCommentReaction({
64
+ * origin: createOriginClient({ apiBaseUrl: originRpcBaseUrl() }),
65
+ * commentId: comment.id,
66
+ * emoji: "👀",
67
+ * });
68
+ * ```
69
+ */
70
+ export async function setOriginCommentReaction(
71
+ input: OriginCommentReactionInput & { origin: OriginReactionClient }
72
+ ): Promise<void> {
73
+ await input.origin.request({
74
+ method: "POST",
75
+ path: SET_ORIGIN_COMMENT_REACTION_PATH,
76
+ body: {
77
+ commentId: input.commentId,
78
+ emoji: input.emoji,
79
+ active: input.active ?? true,
80
+ },
81
+ });
82
+ }