@cursor/july 0.1.96 → 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 (321) hide show
  1. package/README.md +3 -2
  2. package/dist/bin/agent-serve.js +14 -3
  3. package/dist/channels/origin/api.d.ts +15 -4
  4. package/dist/channels/origin/api.d.ts.map +1 -1
  5. package/dist/channels/origin/api.js +19 -3
  6. package/dist/channels/origin/binding.d.ts +11 -0
  7. package/dist/channels/origin/binding.d.ts.map +1 -1
  8. package/dist/channels/origin/binding.js +41 -25
  9. package/dist/channels/origin/index.d.ts +1 -0
  10. package/dist/channels/origin/index.d.ts.map +1 -1
  11. package/dist/channels/origin/index.js +1 -0
  12. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  13. package/dist/channels/origin/origin-channel.js +3 -0
  14. package/dist/channels/origin/reactions.d.ts +56 -0
  15. package/dist/channels/origin/reactions.d.ts.map +1 -0
  16. package/dist/channels/origin/reactions.js +67 -0
  17. package/dist/channels/origin/types.d.ts +11 -0
  18. package/dist/channels/origin/types.d.ts.map +1 -1
  19. package/dist/channels/slack/approvals.d.ts +16 -0
  20. package/dist/channels/slack/approvals.d.ts.map +1 -1
  21. package/dist/channels/slack/approvals.js +86 -0
  22. package/dist/channels/slack/cli-project.d.ts +19 -0
  23. package/dist/channels/slack/cli-project.d.ts.map +1 -0
  24. package/dist/channels/slack/cli-project.js +234 -0
  25. package/dist/channels/slack/defaults.d.ts.map +1 -1
  26. package/dist/channels/slack/defaults.js +97 -39
  27. package/dist/channels/slack/init.d.ts +3 -2
  28. package/dist/channels/slack/init.d.ts.map +1 -1
  29. package/dist/channels/slack/init.js +5 -5
  30. package/dist/channels/slack/interactive.d.ts +2 -1
  31. package/dist/channels/slack/interactive.d.ts.map +1 -1
  32. package/dist/channels/slack/interactive.js +15 -4
  33. package/dist/channels/slack/manifest.d.ts +1 -1
  34. package/dist/channels/slack/manifest.js +1 -1
  35. package/dist/channels/slack/setup.d.ts +1 -1
  36. package/dist/channels/slack/setup.d.ts.map +1 -1
  37. package/dist/channels/slack/setup.js +10 -6
  38. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  39. package/dist/channels/slack/slack-channel.js +1 -0
  40. package/dist/channels/slack/tool-approval-events.d.ts.map +1 -1
  41. package/dist/channels/slack/tool-approval-events.js +91 -1
  42. package/dist/docs/404.html +2 -2
  43. package/dist/docs/ab.html +4 -4
  44. package/dist/docs/assets/{app.jXleCmOc.js → app.B3rWNYE1.js} +1 -1
  45. package/dist/docs/assets/chunks/@localSearchIndexroot.BU9nHdnQ.js +1 -0
  46. package/dist/docs/assets/chunks/{VPLocalSearchBox.8LhyglIT.js → VPLocalSearchBox.C1lhqJJR.js} +1 -1
  47. package/dist/docs/assets/chunks/{theme.9ged-pr2.js → theme.B40_SXuv.js} +2 -2
  48. package/dist/docs/assets/{deployment.md.D9msOFOW.js → deployment.md.MFPKqsqI.js} +2 -2
  49. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.js → guides_mcp-oauth.md.CN-6YmTJ.js} +4 -4
  50. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.lean.js → guides_mcp-oauth.md.CN-6YmTJ.lean.js} +1 -1
  51. package/dist/docs/assets/guides_slack.md.VDXQV3ja.js +22 -0
  52. package/dist/docs/assets/guides_slack.md.VDXQV3ja.lean.js +1 -0
  53. package/dist/docs/assets/index.md.CVeRUOeZ.js +5 -0
  54. package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.js → reference_agent-config.md.BHeYMgme.js} +1 -1
  55. package/dist/docs/assets/{reference_cli.md.CCnG-nJx.js → reference_cli.md.RyZf5OTE.js} +9 -6
  56. package/dist/docs/assets/{reference_cli.md.CCnG-nJx.lean.js → reference_cli.md.RyZf5OTE.lean.js} +1 -1
  57. package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.js → reference_connections.md.DxldvyIB.js} +4 -3
  58. package/dist/docs/assets/{reference_http-api.md.D89k1mdm.js → reference_http-api.md.5zOAbV86.js} +1 -1
  59. package/dist/docs/assets/reference_sessions.md.NxFP_CAC.js +1 -0
  60. package/dist/docs/assets/{reference_tools.md.BHeXn2id.js → reference_tools.md.B84gw9Ii.js} +1 -1
  61. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.js +2 -0
  62. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.lean.js +1 -0
  63. package/dist/docs/assets/troubleshooting.md.DCiPBhYs.js +1 -0
  64. package/dist/docs/building-with-agents.html +4 -4
  65. package/dist/docs/concepts.html +4 -4
  66. package/dist/docs/deployment.html +7 -7
  67. package/dist/docs/deployment.md +5 -4
  68. package/dist/docs/evals.html +4 -4
  69. package/dist/docs/guides/agent-to-agent.html +4 -4
  70. package/dist/docs/guides/cloud-runtime.html +4 -4
  71. package/dist/docs/guides/convert-automation.html +4 -4
  72. package/dist/docs/guides/github.html +4 -4
  73. package/dist/docs/guides/human-in-the-loop.html +4 -4
  74. package/dist/docs/guides/mcp-oauth.html +8 -8
  75. package/dist/docs/guides/mcp-oauth.md +26 -8
  76. package/dist/docs/guides/opentelemetry.html +4 -4
  77. package/dist/docs/guides/slack.html +17 -33
  78. package/dist/docs/guides/slack.md +92 -201
  79. package/dist/docs/guides/webhooks.html +4 -4
  80. package/dist/docs/hashmap.json +1 -1
  81. package/dist/docs/hillclimbing.html +4 -4
  82. package/dist/docs/index.html +6 -6
  83. package/dist/docs/index.md +5 -3
  84. package/dist/docs/llms-full.txt +299 -653
  85. package/dist/docs/llms.txt +2 -2
  86. package/dist/docs/quickstart.html +4 -4
  87. package/dist/docs/reference/agent-config.html +6 -6
  88. package/dist/docs/reference/agent-config.md +2 -2
  89. package/dist/docs/reference/artifacts.html +4 -4
  90. package/dist/docs/reference/channels.html +4 -4
  91. package/dist/docs/reference/cli.html +13 -10
  92. package/dist/docs/reference/cli.md +38 -16
  93. package/dist/docs/reference/connections.html +9 -8
  94. package/dist/docs/reference/connections.md +6 -3
  95. package/dist/docs/reference/hooks.html +4 -4
  96. package/dist/docs/reference/http-api.html +6 -6
  97. package/dist/docs/reference/http-api.md +2 -1
  98. package/dist/docs/reference/instructions.html +4 -4
  99. package/dist/docs/reference/playground.html +4 -4
  100. package/dist/docs/reference/project-layout.html +4 -4
  101. package/dist/docs/reference/prompt.html +4 -4
  102. package/dist/docs/reference/schedules.html +4 -4
  103. package/dist/docs/reference/sessions.html +5 -5
  104. package/dist/docs/reference/sessions.md +4 -2
  105. package/dist/docs/reference/skills.html +4 -4
  106. package/dist/docs/reference/subagents.html +4 -4
  107. package/dist/docs/reference/tools.html +6 -6
  108. package/dist/docs/reference/tools.md +9 -2
  109. package/dist/docs/scaffolding-agents.html +4 -4
  110. package/dist/docs/storage.html +4 -4
  111. package/dist/docs/templates/agentic-owners.html +4 -4
  112. package/dist/docs/templates/agents-md.html +28 -0
  113. package/dist/docs/templates/agents-md.md +105 -0
  114. package/dist/docs/templates/code-wiki.html +5 -5
  115. package/dist/docs/templates/demo.html +4 -4
  116. package/dist/docs/templates/pr-autofixer.html +4 -4
  117. package/dist/docs/templates/security-help.html +4 -4
  118. package/dist/docs/templates/security-reviewer.html +5 -5
  119. package/dist/docs/templates/triage.html +4 -4
  120. package/dist/docs/troubleshooting.html +5 -5
  121. package/dist/docs/troubleshooting.md +2 -2
  122. package/dist/evals/run-facts.d.ts.map +1 -1
  123. package/dist/evals/run-facts.js +27 -0
  124. package/dist/internal/advertise-tools.d.ts.map +1 -1
  125. package/dist/internal/advertise-tools.js +15 -9
  126. package/dist/internal/approval-gate.d.ts +12 -13
  127. package/dist/internal/approval-gate.d.ts.map +1 -1
  128. package/dist/internal/approval-gate.js +16 -21
  129. package/dist/internal/chat-client.js +10 -0
  130. package/dist/internal/cli-deploy.d.ts +5 -0
  131. package/dist/internal/cli-deploy.d.ts.map +1 -1
  132. package/dist/internal/cli-deploy.js +50 -17
  133. package/dist/internal/cli-mcp-oauth.js +8 -18
  134. package/dist/internal/cli-slack-manual.d.ts +24 -2
  135. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  136. package/dist/internal/cli-slack-manual.js +251 -20
  137. package/dist/internal/cli-slack.d.ts +9 -2
  138. package/dist/internal/cli-slack.d.ts.map +1 -1
  139. package/dist/internal/cli-slack.js +29 -82
  140. package/dist/internal/cursor/account-mcp.d.ts +1 -0
  141. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  142. package/dist/internal/cursor/account-mcp.js +17 -0
  143. package/dist/internal/cursor-agent-template.d.ts +1 -1
  144. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  145. package/dist/internal/cursor-agent-template.js +1 -0
  146. package/dist/internal/deploy-client.d.ts +17 -0
  147. package/dist/internal/deploy-client.d.ts.map +1 -1
  148. package/dist/internal/deploy-client.js +31 -10
  149. package/dist/internal/env-file.d.ts +19 -0
  150. package/dist/internal/env-file.d.ts.map +1 -0
  151. package/dist/internal/env-file.js +90 -0
  152. package/dist/internal/framework-file-storage.d.ts +1 -1
  153. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  154. package/dist/internal/framework-file-storage.js +6 -0
  155. package/dist/internal/hosted-delivery-protocol.d.ts +7 -0
  156. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  157. package/dist/internal/hosted-delivery-protocol.js +7 -0
  158. package/dist/internal/hosted-delivery.d.ts +6 -0
  159. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  160. package/dist/internal/hosted-delivery.js +63 -22
  161. package/dist/internal/hosted-execution-diag.d.ts +48 -0
  162. package/dist/internal/hosted-execution-diag.d.ts.map +1 -0
  163. package/dist/internal/hosted-execution-diag.js +150 -0
  164. package/dist/internal/http-channel.d.ts.map +1 -1
  165. package/dist/internal/http-channel.js +81 -1
  166. package/dist/internal/init-project.d.ts.map +1 -1
  167. package/dist/internal/init-project.js +2 -0
  168. package/dist/internal/logs-client.d.ts +5 -0
  169. package/dist/internal/logs-client.d.ts.map +1 -1
  170. package/dist/internal/logs-client.js +5 -0
  171. package/dist/internal/mcp-endpoint.js +2 -3
  172. package/dist/internal/mcp-host.d.ts +10 -0
  173. package/dist/internal/mcp-host.d.ts.map +1 -1
  174. package/dist/internal/mcp-host.js +57 -8
  175. package/dist/internal/mcp-oauth-on-demand.d.ts +68 -0
  176. package/dist/internal/mcp-oauth-on-demand.d.ts.map +1 -0
  177. package/dist/internal/mcp-oauth-on-demand.js +287 -0
  178. package/dist/internal/mcp-oauth-persist.d.ts +42 -0
  179. package/dist/internal/mcp-oauth-persist.d.ts.map +1 -0
  180. package/dist/internal/mcp-oauth-persist.js +92 -0
  181. package/dist/internal/mcp-oauth.d.ts +1 -0
  182. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  183. package/dist/internal/mcp-oauth.js +10 -2
  184. package/dist/internal/otel/collector.d.ts.map +1 -1
  185. package/dist/internal/otel/collector.js +22 -9
  186. package/dist/internal/server.d.ts +3 -0
  187. package/dist/internal/server.d.ts.map +1 -1
  188. package/dist/internal/server.js +49 -22
  189. package/dist/internal/session-engine.d.ts +88 -3
  190. package/dist/internal/session-engine.d.ts.map +1 -1
  191. package/dist/internal/session-engine.js +515 -43
  192. package/dist/internal/sessions-client.d.ts +9 -7
  193. package/dist/internal/sessions-client.d.ts.map +1 -1
  194. package/dist/internal/sessions-client.js +3 -1
  195. package/dist/internal/storage-coordinator.d.ts +7 -0
  196. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  197. package/dist/internal/storage-coordinator.js +28 -5
  198. package/dist/internal/storage-roles.d.ts +5 -0
  199. package/dist/internal/storage-roles.d.ts.map +1 -1
  200. package/dist/internal/stream-progress.d.ts.map +1 -1
  201. package/dist/internal/stream-progress.js +10 -0
  202. package/dist/internal/tool-policy.d.ts +9 -1
  203. package/dist/internal/tool-policy.d.ts.map +1 -1
  204. package/dist/internal/tool-policy.js +13 -0
  205. package/dist/internal/trajectory.d.ts.map +1 -1
  206. package/dist/internal/trajectory.js +10 -0
  207. package/dist/internal/turn-outbox.d.ts +24 -0
  208. package/dist/internal/turn-outbox.d.ts.map +1 -0
  209. package/dist/internal/turn-outbox.js +80 -0
  210. package/dist/playground/assets/{index-Cx9CclK_.js → index-DrkI6y5O.js} +45 -45
  211. package/dist/playground/assets/index-DzNGwm7q.css +1 -0
  212. package/dist/playground/index.html +2 -2
  213. package/dist/storage-backends/cursor-hosted.d.ts +1 -1
  214. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  215. package/dist/storage-backends/cursor-hosted.js +12 -0
  216. package/dist/storage.d.ts +8 -0
  217. package/dist/storage.d.ts.map +1 -1
  218. package/dist/types.d.ts +63 -7
  219. package/dist/types.d.ts.map +1 -1
  220. package/docs/README.md +5 -3
  221. package/docs/deployment.md +5 -4
  222. package/docs/guides/mcp-oauth.md +26 -8
  223. package/docs/guides/slack.md +93 -202
  224. package/docs/reference/agent-config.md +2 -2
  225. package/docs/reference/cli.md +38 -16
  226. package/docs/reference/connections.md +6 -3
  227. package/docs/reference/http-api.md +2 -1
  228. package/docs/reference/sessions.md +4 -2
  229. package/docs/reference/tools.md +9 -2
  230. package/docs/templates/agents-md.md +110 -0
  231. package/docs/troubleshooting.md +2 -2
  232. package/package.json +1 -1
  233. package/skills/create-agent/SKILL.md +2 -1
  234. package/skills/mcp-auth/SKILL.md +6 -3
  235. package/skills/setup-slack/SKILL.md +23 -13
  236. package/src/bin/agent-serve.ts +13 -1
  237. package/src/channels/origin/api.ts +24 -5
  238. package/src/channels/origin/binding.ts +55 -26
  239. package/src/channels/origin/index.ts +1 -0
  240. package/src/channels/origin/origin-channel.ts +4 -0
  241. package/src/channels/origin/reactions.ts +82 -0
  242. package/src/channels/origin/types.ts +11 -0
  243. package/src/channels/slack/approvals.ts +105 -0
  244. package/src/channels/slack/cli-project.ts +267 -0
  245. package/src/channels/slack/defaults.ts +109 -46
  246. package/src/channels/slack/init.ts +10 -5
  247. package/src/channels/slack/interactive.ts +35 -9
  248. package/src/channels/slack/manifest.ts +1 -1
  249. package/src/channels/slack/setup.ts +10 -6
  250. package/src/channels/slack/slack-channel.ts +1 -0
  251. package/src/channels/slack/tool-approval-events.ts +93 -0
  252. package/src/evals/run-facts.ts +32 -0
  253. package/src/internal/advertise-tools.ts +31 -10
  254. package/src/internal/approval-gate.ts +20 -29
  255. package/src/internal/chat-client.ts +19 -0
  256. package/src/internal/cli-deploy.ts +79 -9
  257. package/src/internal/cli-mcp-oauth.ts +7 -21
  258. package/src/internal/cli-slack-manual.ts +350 -18
  259. package/src/internal/cli-slack.ts +40 -84
  260. package/src/internal/cursor/account-mcp.ts +21 -0
  261. package/src/internal/cursor-agent-template.ts +1 -0
  262. package/src/internal/deploy-client.ts +43 -0
  263. package/src/internal/env-file.ts +84 -0
  264. package/src/internal/framework-file-storage.ts +7 -1
  265. package/src/internal/hosted-delivery-protocol.ts +7 -0
  266. package/src/internal/hosted-delivery.ts +100 -27
  267. package/src/internal/hosted-execution-diag.ts +207 -0
  268. package/src/internal/http-channel.ts +99 -0
  269. package/src/internal/init-project.ts +2 -0
  270. package/src/internal/logs-client.ts +5 -0
  271. package/src/internal/mcp-endpoint.ts +13 -4
  272. package/src/internal/mcp-host.ts +77 -11
  273. package/src/internal/mcp-oauth-on-demand.ts +352 -0
  274. package/src/internal/mcp-oauth-persist.ts +127 -0
  275. package/src/internal/mcp-oauth.ts +17 -1
  276. package/src/internal/otel/collector.ts +30 -0
  277. package/src/internal/server.ts +59 -9
  278. package/src/internal/session-engine.ts +659 -56
  279. package/src/internal/sessions-client.ts +17 -8
  280. package/src/internal/storage-coordinator.ts +38 -8
  281. package/src/internal/storage-roles.ts +7 -0
  282. package/src/internal/stream-progress.ts +19 -0
  283. package/src/internal/tool-policy.ts +18 -0
  284. package/src/internal/trajectory.ts +10 -0
  285. package/src/internal/turn-outbox.ts +85 -0
  286. package/src/storage-backends/cursor-hosted.ts +13 -1
  287. package/src/storage.ts +12 -0
  288. package/src/types.ts +68 -8
  289. package/templates/agents-md/README.md +39 -0
  290. package/templates/agents-md/agent/agent.ts +8 -0
  291. package/templates/agents-md/agent/channels/github.ts +10 -0
  292. package/templates/agents-md/agent/channels/queue.ts +28 -0
  293. package/templates/agents-md/agent/channels/slack.ts +9 -0
  294. package/templates/agents-md/agent/instructions.md +39 -0
  295. package/templates/agents-md/agent/lib/collect.ts +439 -0
  296. package/templates/agents-md/agent/lib/config.ts +8 -0
  297. package/templates/agents-md/agent/lib/paths.ts +51 -0
  298. package/templates/agents-md/agent/schedules/weekly.ts +17 -0
  299. package/templates/agents-md/agent/tools/apply_agents.ts +226 -0
  300. package/templates/agents-md/evals/agents.eval.ts +135 -0
  301. package/templates/agents-md/evals/evals.config.ts +5 -0
  302. package/templates/agents-md/init.json +38 -0
  303. package/templates/agents-md/package.json +18 -0
  304. package/templates/agents-md/tsconfig.json +12 -0
  305. package/dist/docs/assets/chunks/@localSearchIndexroot.DFoGuETX.js +0 -1
  306. package/dist/docs/assets/guides_slack.md.C32HsdKk.js +0 -38
  307. package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +0 -1
  308. package/dist/docs/assets/index.md.CI93Ltlb.js +0 -5
  309. package/dist/docs/assets/reference_sessions.md.D0mIh4KK.js +0 -1
  310. package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +0 -1
  311. package/dist/docs/design/agsh.md +0 -406
  312. package/dist/playground/assets/index-B1DDvBeC.css +0 -1
  313. package/docs/design/agsh.md +0 -406
  314. /package/dist/docs/assets/{deployment.md.D9msOFOW.lean.js → deployment.md.MFPKqsqI.lean.js} +0 -0
  315. /package/dist/docs/assets/{index.md.CI93Ltlb.lean.js → index.md.CVeRUOeZ.lean.js} +0 -0
  316. /package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.lean.js → reference_agent-config.md.BHeYMgme.lean.js} +0 -0
  317. /package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.lean.js → reference_connections.md.DxldvyIB.lean.js} +0 -0
  318. /package/dist/docs/assets/{reference_http-api.md.D89k1mdm.lean.js → reference_http-api.md.5zOAbV86.lean.js} +0 -0
  319. /package/dist/docs/assets/{reference_sessions.md.D0mIh4KK.lean.js → reference_sessions.md.NxFP_CAC.lean.js} +0 -0
  320. /package/dist/docs/assets/{reference_tools.md.BHeXn2id.lean.js → reference_tools.md.B84gw9Ii.lean.js} +0 -0
  321. /package/dist/docs/assets/{troubleshooting.md.Ctv3T8C2.lean.js → troubleshooting.md.DCiPBhYs.lean.js} +0 -0
@@ -0,0 +1,110 @@
1
+ ---
2
+ title: "Keep AGENTS.md current from last week's work"
3
+ description: "Scaffold the agent, pick a repo and Slack channels, dispatch the weekly job, and deploy."
4
+ ---
5
+
6
+ # Keep AGENTS.md current from last week's work
7
+
8
+ This agent runs every Monday at 09:00 UTC. It reads last week's merged
9
+ pull requests and the Slack channels you list. When a durable rule
10
+ showed up, `apply_agents` parks the write until a person approves it,
11
+ then opens a draft follow-up pull request against the default branch.
12
+ Chores and rules the file already states stay quiet.
13
+
14
+ This template is one model turn: read the week, then call
15
+ `apply_agents`.
16
+
17
+ Init once per app. Pass a different repo and channel list each time.
18
+
19
+ ## Scaffold
20
+
21
+ ```bash
22
+ npx @cursor/july init ./agents-md --template agents-md
23
+ ```
24
+
25
+ `init` asks which GitHub repo to watch and which Slack channels to
26
+ read. Pass `--var repos=acme/api --var slack=#eng-api,#api-private`
27
+ to skip the prompt. Use `--var slack=none` when Slack is out of
28
+ scope.
29
+
30
+ The answers land in `agent/lib/config.ts`. Edit that file when the
31
+ set changes.
32
+
33
+ ## Connect GitHub and Slack
34
+
35
+ Connect GitHub in Cursor for that repository (Settings or
36
+ [cursor.com/dashboard](https://cursor.com/dashboard)). Sign the host
37
+ in:
38
+
39
+ ```bash
40
+ cd agents-md
41
+ agent-sdk login
42
+ ```
43
+
44
+ `cursorAccount` mints a short-lived, repo-scoped credential with
45
+ `contents-write` so the agent can open the follow-up PR. See the
46
+ [GitHub guide](../guides/github.md).
47
+
48
+ Create the Slack app and invite the bot to each listed channel,
49
+ including private ones:
50
+
51
+ ```bash
52
+ agent-sdk slack create --dir .
53
+ ```
54
+
55
+ See the [Slack guide](../guides/slack.md).
56
+
57
+ ## First weekly run
58
+
59
+ ```bash
60
+ agent-sdk dev
61
+ ```
62
+
63
+ Schedules never fire under `dev`. Dispatch the same path production
64
+ uses:
65
+
66
+ ```bash
67
+ curl -X POST http://127.0.0.1:3000/v1/dev/schedules/weekly
68
+ ```
69
+
70
+ The playground can run `/queue/run` too.
71
+
72
+ The host writes `week/prs.md`, `week/slack.md`, `week/window.txt`,
73
+ and `week/tree/**.txt` snapshots of the current `AGENTS.md` files,
74
+ then starts a model turn. The
75
+ model calls `apply_agents` once. A skip finishes. An update parks in
76
+ the playground until someone approves; then a draft PR opens against
77
+ the repository default branch. Later updates to the same base stack
78
+ on `agents-md/<base>`. Pull requests from those branches are ignored
79
+ so the follow-up cannot feed the next week.
80
+
81
+ Chat replies stay in the playground. `apply_agents` records a skip,
82
+ or parks the write. Approve there or with
83
+ `POST /v1/session/:id/approvals/:callId`.
84
+
85
+ ## What to edit
86
+
87
+ - `agent/lib/config.ts`: repo and Slack channels
88
+ - `agent/instructions.md`: what counts as an update
89
+ - `evals/agents.eval.ts`: smoke cases
90
+
91
+ ## Evals
92
+
93
+ Four smoke cases: a lint-only week, a billing rule that parks the
94
+ write, the same rule already in `AGENTS.md`, and an empty week.
95
+
96
+ ```bash
97
+ agent-sdk eval
98
+ ```
99
+
100
+ Eval sessions skip the GitHub write.
101
+
102
+ ## Deploy
103
+
104
+ ```bash
105
+ agent-sdk deploy
106
+ ```
107
+
108
+ Run it from the agent's git checkout. The command infers repository,
109
+ ref, path, and slug. Production fires the Monday cron. The deployment
110
+ uses the team's Cursor GitHub connection for the watched repo.
@@ -42,7 +42,7 @@ not on `PATH`, use `npx @cursor/july`.
42
42
  | What you see | What to do |
43
43
  | --- | --- |
44
44
  | `409` on a follow-up message | Refresh the `continuationToken` or confirm the session is a chat session. Task sessions do not accept follow-ups. |
45
- | `409 session_busy` on `call --session` | Wait for the model turn to finish, or omit `--session` for a one-off call. |
45
+ | `409 session_busy` on `call --session` | The tool is a write (or declares no effect) and a model turn is running. Wait for the turn to finish, omit `--session` for a one-off call, or declare `effect: "read"` on a tool that only reads so it runs alongside turns. |
46
46
  | `403` on stream or follow-up | Use the same auth identity that created the session. Off localhost, pass `--bearer-token` and send it on every request. |
47
47
  | Works on localhost; blocked through a tunnel or LAN | Default auth allows only direct loopback callers. Share the host with `--bearer-token <secret>` (or authored `bearerAuth`). Use `--allow-anonymous` only on a trusted private network. |
48
48
  | A channel route fails to compile with a schema type error | `GET` routes need a Zod `querySchema`. `POST` / `PUT` / `PATCH` need a Zod `bodySchema`. Use `z.object({})` or `z.unknown()` for open shapes. |
@@ -70,7 +70,7 @@ not on `PATH`, use `npx @cursor/july`.
70
70
  | What you see | What to do |
71
71
  | --- | --- |
72
72
  | `must be defineConnection({ url, oauth: true })` | The connection file needs `oauth: true`, or you passed the wrong connection name to `agent-sdk mcp oauth`. |
73
- | Local auth works; hosted calls unauthorized | Run `agent-sdk mcp oauth <name> --store`, confirm names with `agent-sdk secrets list <slug>`, then redeploy. |
73
+ | Local auth works; hosted calls unauthorized | Finish Connect on the hosted engine, or run `agent-sdk mcp oauth <name> --store`. Confirm names with `agent-sdk secrets list <slug>`, then redeploy. |
74
74
  | Model asks for `mcp_auth` or IDE MCP for a connector it already has | Attached MCP is behind meta-tools. Set `advertiseTools: true` for named tools on local turns, or call it from a host tool via `ctx.host.mcp`. |
75
75
 
76
76
  See [Host MCP OAuth](./guides/mcp-oauth.md) and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.96",
3
+ "version": "0.1.97",
4
4
  "description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {
@@ -111,7 +111,8 @@ agent-sdk init ./<slug>
111
111
  `subagents/<id>/` (needs `description`), `schedules/`, `hooks/`.
112
112
  Slack: `agent-sdk slack create --dir ./<slug> --name "<Name>"`,
113
113
  not a hand-written channel. Manual Slack app:
114
- `agent-sdk slack init --manual`.
114
+ `agent-sdk slack init --manual` (Slack CLI, or paste at
115
+ api.slack.com).
115
116
  4. `evals/evals.config.ts` with `maxConcurrency: 20` (required;
116
117
  cap 200) plus `evals/**/*.eval.ts`. Assert `t.succeeded()` +
117
118
  `t.calledTool(...)`. API: `skills/evals/SKILL.md`.
@@ -30,8 +30,11 @@ can still call `ctx.host.mcp`.
30
30
  3. **Allow egress** on hosted non-bootstrap hosts:
31
31
  `hosting.egressDomains`.
32
32
  4. **Authorize.** Local: `agent-sdk mcp oauth <name>`. Hosted:
33
- `agent-sdk mcp oauth <name> --store` then `agent-sdk deploy`.
34
- `secrets list` shows the names.
33
+ finish Connect so the current process can retry, then
34
+ `agent-sdk mcp oauth <name> --store` and `agent-sdk deploy` so
35
+ the next pod gets `MCP_OAUTH_*`. `secrets list` shows the names.
36
+ Secrets are deployment-wide, not per caller. `cursorAccount: true`
37
+ stays on the Cursor backend.
35
38
 
36
39
  ```ts
37
40
  // agent/mcp-connections/inventory.ts
@@ -75,7 +78,7 @@ the CLI config directory (`mcp-auth.json` or
75
78
  | `must be defineConnection({ url, oauth: true })` | Wrong name or missing `oauth: true` |
76
79
  | `Unknown MCP connection` | Filename must match the CLI arg |
77
80
  | Callback hang | Free port 8787; finish the browser flow here |
78
- | Hosted 401 | `secrets list`; `--store`; redeploy |
81
+ | Hosted 401 | `secrets list`; Connect or `--store`; redeploy |
79
82
  | Model invents `mcp_auth` / IDE MCP | `advertiseTools: true` on local turns |
80
83
 
81
84
  No raw tokens in git.
@@ -64,28 +64,38 @@ Local serve does not need a hosted engine. Next
64
64
 
65
65
  ## 2. Manual (`slack init --manual`)
66
66
 
67
- Only when they own the app at api.slack.com.
67
+ Only when they own the app. Preferred: Slack CLI
68
+ (`~/.slack/bin/slack`). Paste at api.slack.com if the CLI is
69
+ missing. Never `slack deploy`; Agent SDK serve owns Socket Mode.
68
70
 
69
71
  ```bash
70
72
  agent-sdk slack init --manual --dir . --name "My Agent"
73
+ # --slack-team T0123ABCD when several workspaces are logged in
74
+ # --no-install to scaffold only
71
75
  ```
72
76
 
73
77
  Writes `agent/channels/slack.ts` (`envPrefix` from the directory),
74
- manifests under the project state directory, and `env.example`.
75
- `--channel-posts` subscribes `message.channels` /
76
- `message.groups`.
78
+ manifests, a `.slack/` project (`get-manifest` those JSON files),
79
+ and `env.example`. `--channel-posts` subscribes `message.channels`
80
+ / `message.groups`. If Slack CLI is logged in, this installs the
81
+ app. `--install` fails when that cannot run.
77
82
 
78
83
  Human gates, one at a time. Stop after each.
79
84
 
80
- 1. **Create the app.** Create New App From a manifest. Start
81
- with `manifest.dev.json`.
82
- 2. **Install.** Install to Workspace. Copy the bot token
83
- (`xoxb-...`).
84
- 3. **App token.** Create an app-level token with
85
- `connections:write` (`xapp-...`).
86
- 4. **Write env.** Put both in `.env.local`. Then doctor.
87
-
88
- Repeat for prod with the prod manifest.
85
+ 1. **Install the app.** If `next` starts with "Ask the user to
86
+ install this Slack app", stop and prompt them. Slack CLI: they
87
+ run `slack login --no-prompt`, send `/slackauthticket <ticket>`,
88
+ then `slack login --ticket <ticket> --challenge <code>`, then
89
+ `slack app install --environment local --team <T> --force`.
90
+ Prod: `SLACK_ENV=deployed slack app install --environment
91
+ deployed --team <T> --force`. Fallback: Create New App → From a
92
+ manifest, start with `.slack/manifest.dev.json`.
93
+ 2. **Tokens.** Slack CLI leaves xoxb / xapp in that process only.
94
+ Copy the bot token from the app's OAuth page. Mint an app-level
95
+ token with `connections:write`. Put both in `.env.local` using
96
+ `env.example` names. If Slack CLI wrote `SLACK_*` to `.env`,
97
+ copy those values to the prefixed keys.
98
+ 3. **Doctor.**
89
99
 
90
100
  ## 3. Doctor and smoke
91
101
 
@@ -140,7 +140,7 @@ Usage:
140
140
  ${CLI} deploy [--dir <path>] [--slug <slug> | --all] [--team <id>] [--json]
141
141
  [--no-wait] [--repo <url>] [--ref <ref>]
142
142
  [--path <agentPath>] [--cursor-events-repo <owner/name>]...
143
- [--allow-domain <domain>]...
143
+ [--allow-domain <domain>]... [--multi-tenant]
144
144
  ${CLI} manifest [--dir <path>] [--json]
145
145
  ${CLI} deployments [--team <id>] [--json]
146
146
  ${CLI} deployment <slug> [--team <id>] [--json]
@@ -268,6 +268,8 @@ Commands:
268
268
  (flags always win). When --dir is a multi-agent parent,
269
269
  pick one interactively, or pass --slug / --all. First deploy
270
270
  of a slug prints the alias token exactly once — save it.
271
+ --multi-tenant adds a release to an existing Cursor-managed
272
+ product (v2 only); it cannot create a new multi-tenant app.
271
273
  deployments List the team's deployments (slug, status, generation, kind).
272
274
  deployment Show one deployment in full (status, lastError, engine info).
273
275
  stop Stop a deployment and wait until it reports stopped.
@@ -430,6 +432,9 @@ Options:
430
432
  --allow-domain deploy: egress domain the engine pod may reach
431
433
  (repeatable; unioned with hosting.egressDomains from the
432
434
  agent manifest). Repo-backed deploys only.
435
+ --multi-tenant deploy: add a release to an existing Cursor-managed
436
+ (multi-tenant) product. architecture v2 only. Cannot
437
+ create a new multi-tenant application.
433
438
  --from-argv secrets set: allow NAME=VALUE on argv (leaks into shell
434
439
  history and agent-captured terminals). Default is names
435
440
  only with a hidden prompt or piped stdin.
@@ -439,6 +444,8 @@ Options:
439
444
  GITHUB_WEBHOOK_SECRET). github: --events overrides the
440
445
  derived webhook event list.
441
446
  --install github: install the cli/gh-webhook extension if missing.
447
+ slack init --manual: require Slack CLI app install.
448
+ --no-install slack init --manual: skip Slack CLI app install.
442
449
  --action github replay: event action (e.g. opened, synchronize).
443
450
  --conclusion github replay: CI conclusion (check_run/suite/status).
444
451
  --comment github replay: comment body for comment events.
@@ -557,6 +564,7 @@ async function main(argv: string[]): Promise<number> {
557
564
  secret: { type: "string" },
558
565
  channel: { type: "string", multiple: true },
559
566
  install: { type: "boolean", default: false },
567
+ "no-install": { type: "boolean", default: false },
560
568
  action: { type: "string" },
561
569
  conclusion: { type: "string" },
562
570
  context: { type: "string" },
@@ -570,6 +578,7 @@ async function main(argv: string[]): Promise<number> {
570
578
  all: { type: "boolean", default: false },
571
579
  "cursor-events-repo": { type: "string", multiple: true },
572
580
  "allow-domain": { type: "string", multiple: true },
581
+ "multi-tenant": { type: "boolean", default: false },
573
582
  "from-argv": { type: "boolean", default: false },
574
583
  strict: { type: "boolean", default: false },
575
584
  junit: { type: "string" },
@@ -622,6 +631,8 @@ async function main(argv: string[]): Promise<number> {
622
631
  icon: values.icon,
623
632
  force: values.force,
624
633
  manual: values.manual,
634
+ install: values.install,
635
+ noInstall: values["no-install"],
625
636
  iconSource: positionals[0] === "icon" ? positionals[1] : undefined,
626
637
  });
627
638
  }
@@ -757,6 +768,7 @@ async function main(argv: string[]): Promise<number> {
757
768
  ...(values["allow-domain"] === undefined
758
769
  ? {}
759
770
  : { allowDomains: values["allow-domain"] }),
771
+ multiTenant: values["multi-tenant"] === true,
760
772
  });
761
773
  }
762
774
 
@@ -9,8 +9,8 @@
9
9
  * from options first, then the environment: `ORIGIN_APP_ID` (or
10
10
  * `AGENT_SERVE_ORIGIN_APP_ID`), `ORIGIN_APP_INSTALLATION_ID`,
11
11
  * `ORIGIN_APP_PRIVATE_KEY` (PKCS8 PEM for the app's Ed25519 key; literal
12
- * `\n` sequences are normalized), and `ORIGIN_API_BASE_URL` for the public
13
- * REST base.
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
14
  *
15
15
  * Hosted v2 forks configure none of that: their only credential is the
16
16
  * deployment service account's `CURSOR_API_KEY`, exchanged for a Cursor
@@ -40,6 +40,15 @@ import {
40
40
  */
41
41
  export const DEFAULT_ORIGIN_PUBLIC_API_BASE_URL = "https://api.cursor.com";
42
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
+
43
52
  /** Fixed audience for Origin app JWTs (`APP_TOKEN_AUDIENCE` backend-side). */
44
53
  const ORIGIN_APP_TOKEN_AUDIENCE = "origin-apps";
45
54
  const APP_JWT_TTL_SECONDS = 5 * 60;
@@ -139,6 +148,12 @@ export function originPublicApiBaseUrl(
139
148
  return fromEnv ?? DEFAULT_ORIGIN_PUBLIC_API_BASE_URL;
140
149
  }
141
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
+
142
157
  function base64UrlJson(value: unknown): string {
143
158
  return Buffer.from(JSON.stringify(value)).toString("base64url");
144
159
  }
@@ -376,9 +391,10 @@ export interface OriginClientOptions {
376
391
  token?: string | OriginTokenProvider;
377
392
  /**
378
393
  * App credentials to mint installation tokens from. Defaults to the
379
- * environment ({@link resolveOriginAppCredentials}).
394
+ * environment ({@link resolveOriginAppCredentials}). Pass `false` to
395
+ * disable app credential lookup and force the Cursor-account exchange.
380
396
  */
381
- credentials?: OriginAppCredentials;
397
+ credentials?: OriginAppCredentials | false;
382
398
  /** Public Origin REST base. Defaults to `ORIGIN_API_BASE_URL` / prod. */
383
399
  apiBaseUrl?: string;
384
400
  /** Injectable fetch for tests. */
@@ -441,7 +457,10 @@ export function createOriginClient(
441
457
  return await options.token();
442
458
  }
443
459
  if (tokenProvider === undefined) {
444
- const credentials = options.credentials ?? resolveOriginAppCredentials();
460
+ const credentials =
461
+ options.credentials === false
462
+ ? undefined
463
+ : (options.credentials ?? resolveOriginAppCredentials());
445
464
  const exchange = options.cursorAccountExchange ?? true;
446
465
  const exchangeOptions =
447
466
  exchange === false ? undefined : exchange === true ? {} : exchange;
@@ -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`). */
@@ -44,53 +49,77 @@ export interface OriginHandle {
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
  }
@@ -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
+ }
@@ -58,6 +58,11 @@ export interface OriginEventContext {
58
58
  repository: OriginRepositoryRef;
59
59
  pullRequestNumber: number;
60
60
  pullRequestUrl: string;
61
+ /**
62
+ * Who opened the pull request, when the payload carries it. Distinct from
63
+ * {@link sender} — on a comment event the sender is the commenter.
64
+ */
65
+ pullRequestAuthor?: OriginActor;
61
66
  /**
62
67
  * Raw parsed `event.payload` record (`{}` when absent), for consumers
63
68
  * whose normalization needs more than the typed event — the GitHub
@@ -152,6 +157,12 @@ export interface OriginAppOptions {
152
157
  token?: string | OriginTokenProvider;
153
158
  /** Public Origin REST base, e.g. `https://api.cursor.com`. */
154
159
  apiBaseUrl?: string;
160
+ /**
161
+ * Origin ConnectRPC base for operations without a REST binding (comment
162
+ * reactions), e.g. `https://api.origin.cursor.com`. Falls back to
163
+ * `ORIGIN_RPC_BASE_URL`.
164
+ */
165
+ rpcBaseUrl?: string;
155
166
  }
156
167
 
157
168
  export interface OriginChannelOptions {