@cursor/july 0.1.54 → 0.1.61

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 (293) hide show
  1. package/dist/bin/agent-serve.js +30 -23
  2. package/dist/channels/github/github-channel.d.ts +12 -0
  3. package/dist/channels/github/github-channel.d.ts.map +1 -1
  4. package/dist/channels/github/github-channel.js +67 -15
  5. package/dist/channels/github/types.d.ts +27 -1
  6. package/dist/channels/github/types.d.ts.map +1 -1
  7. package/dist/channels/origin/cursor-account.d.ts +22 -0
  8. package/dist/channels/origin/cursor-account.d.ts.map +1 -0
  9. package/dist/channels/origin/cursor-account.js +35 -0
  10. package/dist/channels/origin/events.d.ts +10 -0
  11. package/dist/channels/origin/events.d.ts.map +1 -0
  12. package/dist/channels/origin/events.js +27 -0
  13. package/dist/channels/origin/index.d.ts +29 -0
  14. package/dist/channels/origin/index.d.ts.map +1 -0
  15. package/dist/channels/origin/index.js +28 -0
  16. package/dist/channels/origin/origin-channel.d.ts +68 -0
  17. package/dist/channels/origin/origin-channel.d.ts.map +1 -0
  18. package/dist/channels/origin/origin-channel.js +567 -0
  19. package/dist/channels/origin/origin-webhook.d.ts +38 -0
  20. package/dist/channels/origin/origin-webhook.d.ts.map +1 -0
  21. package/dist/channels/origin/origin-webhook.js +151 -0
  22. package/dist/channels/origin/types.d.ts +152 -0
  23. package/dist/channels/origin/types.d.ts.map +1 -0
  24. package/dist/channels/origin/types.js +1 -0
  25. package/dist/channels/slack/doctor.d.ts +17 -1
  26. package/dist/channels/slack/doctor.d.ts.map +1 -1
  27. package/dist/channels/slack/doctor.js +186 -10
  28. package/dist/docs/404.html +2 -2
  29. package/dist/docs/ab.html +4 -4
  30. package/dist/docs/assets/{app.DAKcDclS.js → app.CW3KJh72.js} +1 -1
  31. package/dist/docs/assets/chunks/@localSearchIndexroot.BuymfBAo.js +1 -0
  32. package/dist/docs/assets/chunks/{VPLocalSearchBox.BNIaCSfG.js → VPLocalSearchBox.Bk6EWpPj.js} +1 -1
  33. package/dist/docs/assets/chunks/{theme.B47GzJjc.js → theme.Bz9AodBA.js} +2 -2
  34. package/dist/docs/assets/{example-agents_fsd.md.DPz9ezO4.js → example-agents_fsd.md.ZeGEpAw_.js} +2 -2
  35. package/dist/docs/assets/{example-agents_fsd.md.DPz9ezO4.lean.js → example-agents_fsd.md.ZeGEpAw_.lean.js} +1 -1
  36. package/dist/docs/assets/{example-agents_security-reviewer.md.Dkf1gyo6.js → example-agents_security-reviewer.md.DBL1TwtP.js} +2 -2
  37. package/dist/docs/assets/{example-agents_security-reviewer.md.Dkf1gyo6.lean.js → example-agents_security-reviewer.md.DBL1TwtP.lean.js} +1 -1
  38. package/dist/docs/assets/guides_convert-automation.md.BhMzTkE5.js +12 -0
  39. package/dist/docs/assets/guides_convert-automation.md.BhMzTkE5.lean.js +1 -0
  40. package/dist/docs/assets/{guides_github.md.B8QKtIpw.js → guides_github.md.CLLQJKRB.js} +4 -4
  41. package/dist/docs/assets/{guides_github.md.B8QKtIpw.lean.js → guides_github.md.CLLQJKRB.lean.js} +1 -1
  42. package/dist/docs/assets/index.md.DhRHS_-L.js +5 -0
  43. package/dist/docs/assets/{index.md.COeoSkcF.lean.js → index.md.DhRHS_-L.lean.js} +1 -1
  44. package/dist/docs/assets/{reference_cli.md.-V6J7Cl8.js → reference_cli.md.Cl14Jfo3.js} +10 -2
  45. package/dist/docs/assets/{reference_cli.md.-V6J7Cl8.lean.js → reference_cli.md.Cl14Jfo3.lean.js} +1 -1
  46. package/dist/docs/assets/scaffolding-agents.md.CrWSA0Ko.js +1 -0
  47. package/dist/docs/assets/{scaffolding-agents.md.mkc3B_ZW.lean.js → scaffolding-agents.md.CrWSA0Ko.lean.js} +1 -1
  48. package/dist/docs/assets/templates_agentic-owners.md.BkTLORaU.js +14 -0
  49. package/dist/docs/assets/templates_agentic-owners.md.BkTLORaU.lean.js +1 -0
  50. package/dist/docs/assets/templates_demo.md.Bgd6MBaZ.js +4 -0
  51. package/dist/docs/assets/templates_demo.md.Bgd6MBaZ.lean.js +1 -0
  52. package/dist/docs/assets/templates_pr-autofixer.md.DcmoeUNZ.js +8 -0
  53. package/dist/docs/assets/templates_pr-autofixer.md.DcmoeUNZ.lean.js +1 -0
  54. package/dist/docs/assets/templates_security-reviewer.md.C0yIUaYs.js +2 -0
  55. package/dist/docs/assets/templates_security-reviewer.md.C0yIUaYs.lean.js +1 -0
  56. package/dist/docs/assets/templates_triage.md.DWuQ1bZz.js +9 -0
  57. package/dist/docs/assets/templates_triage.md.DWuQ1bZz.lean.js +1 -0
  58. package/dist/docs/building-with-agents.html +4 -4
  59. package/dist/docs/concepts.html +5 -5
  60. package/dist/docs/deployment.html +4 -4
  61. package/dist/docs/evals.html +4 -4
  62. package/dist/docs/example-agents/approval-buddy.html +4 -4
  63. package/dist/docs/example-agents/benny.html +4 -4
  64. package/dist/docs/example-agents/bugbot.html +4 -4
  65. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  66. package/dist/docs/example-agents/codeowners-review.html +4 -4
  67. package/dist/docs/example-agents/concierge.html +4 -4
  68. package/dist/docs/example-agents/fsd.html +5 -5
  69. package/dist/docs/example-agents/index.html +4 -4
  70. package/dist/docs/example-agents/knowledge-base.html +4 -4
  71. package/dist/docs/example-agents/oncall.html +4 -4
  72. package/dist/docs/example-agents/security-reviewer.html +5 -5
  73. package/dist/docs/example-agents/slack-agent.html +4 -4
  74. package/dist/docs/example-agents/weather-agent.html +4 -4
  75. package/dist/docs/guides/agent-to-agent.html +4 -4
  76. package/dist/docs/guides/cloud-runtime.html +4 -4
  77. package/dist/docs/guides/convert-automation.html +36 -0
  78. package/dist/docs/guides/github.html +7 -7
  79. package/dist/docs/guides/human-in-the-loop.html +4 -4
  80. package/dist/docs/guides/mcp-oauth.html +4 -4
  81. package/dist/docs/guides/opentelemetry.html +4 -4
  82. package/dist/docs/guides/slack.html +4 -4
  83. package/dist/docs/guides/webhooks.html +4 -4
  84. package/dist/docs/hashmap.json +1 -1
  85. package/dist/docs/hillclimbing.html +4 -4
  86. package/dist/docs/index.html +6 -6
  87. package/dist/docs/quickstart.html +4 -4
  88. package/dist/docs/reference/agent-config.html +4 -4
  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 +14 -6
  92. package/dist/docs/reference/connections.html +4 -4
  93. package/dist/docs/reference/hooks.html +4 -4
  94. package/dist/docs/reference/http-api.html +4 -4
  95. package/dist/docs/reference/instructions.html +4 -4
  96. package/dist/docs/reference/playground.html +4 -4
  97. package/dist/docs/reference/project-layout.html +4 -4
  98. package/dist/docs/reference/prompt.html +4 -4
  99. package/dist/docs/reference/schedules.html +4 -4
  100. package/dist/docs/reference/sessions.html +4 -4
  101. package/dist/docs/reference/skills.html +4 -4
  102. package/dist/docs/reference/subagents.html +4 -4
  103. package/dist/docs/reference/tools.html +4 -4
  104. package/dist/docs/scaffolding-agents.html +5 -5
  105. package/dist/docs/storage.html +4 -4
  106. package/dist/docs/templates/agentic-owners.html +38 -0
  107. package/dist/docs/templates/demo.html +28 -0
  108. package/dist/docs/templates/pr-autofixer.html +32 -0
  109. package/dist/docs/templates/security-reviewer.html +26 -0
  110. package/dist/docs/templates/triage.html +14 -16
  111. package/dist/docs/troubleshooting.html +4 -4
  112. package/dist/index.d.ts +3 -3
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +2 -2
  115. package/dist/internal/cli-ax.d.ts +2 -0
  116. package/dist/internal/cli-ax.d.ts.map +1 -1
  117. package/dist/internal/cli-ax.js +30 -1
  118. package/dist/internal/cli-deploy.js +1 -1
  119. package/dist/internal/cli-slack.d.ts +4 -0
  120. package/dist/internal/cli-slack.d.ts.map +1 -1
  121. package/dist/internal/cli-slack.js +46 -20
  122. package/dist/internal/cursor-event-relay.d.ts +59 -11
  123. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  124. package/dist/internal/cursor-event-relay.js +133 -26
  125. package/dist/internal/discovery.d.ts.map +1 -1
  126. package/dist/internal/discovery.js +11 -2
  127. package/dist/internal/distribution.d.ts.map +1 -1
  128. package/dist/internal/distribution.js +1 -0
  129. package/dist/internal/handleAgentServeTrigger.d.ts +33 -6
  130. package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -1
  131. package/dist/internal/handleAgentServeTrigger.js +97 -19
  132. package/dist/internal/init-interview.d.ts +67 -0
  133. package/dist/internal/init-interview.d.ts.map +1 -0
  134. package/dist/internal/init-interview.js +300 -0
  135. package/dist/internal/init-project.d.ts +7 -0
  136. package/dist/internal/init-project.d.ts.map +1 -1
  137. package/dist/internal/init-project.js +99 -43
  138. package/dist/internal/mcp-endpoint.d.ts +7 -0
  139. package/dist/internal/mcp-endpoint.d.ts.map +1 -1
  140. package/dist/internal/mcp-endpoint.js +7 -0
  141. package/dist/internal/server.d.ts.map +1 -1
  142. package/dist/internal/server.js +159 -57
  143. package/dist/internal/session-engine.d.ts.map +1 -1
  144. package/dist/internal/session-engine.js +20 -21
  145. package/dist/internal/session-links.d.ts +14 -0
  146. package/dist/internal/session-links.d.ts.map +1 -0
  147. package/dist/internal/session-links.js +69 -0
  148. package/dist/internal/sessions-client.d.ts.map +1 -1
  149. package/dist/internal/sessions-client.js +1 -0
  150. package/dist/internal/slack-provision-client.js +1 -1
  151. package/dist/playground/assets/index-ClbuaLpm.css +1 -0
  152. package/dist/playground/assets/index-SqkR13k_.js +85 -0
  153. package/dist/playground/index.html +2 -2
  154. package/dist/types.d.ts +19 -12
  155. package/dist/types.d.ts.map +1 -1
  156. package/docs/README.md +15 -0
  157. package/docs/example-agents/fsd.md +3 -0
  158. package/docs/example-agents/security-reviewer.md +3 -0
  159. package/docs/guides/convert-automation.md +176 -0
  160. package/docs/guides/github.md +6 -2
  161. package/docs/reference/cli.md +36 -10
  162. package/docs/scaffolding-agents.md +3 -0
  163. package/docs/templates/agentic-owners.md +97 -0
  164. package/docs/templates/demo.md +84 -0
  165. package/docs/templates/pr-autofixer.md +136 -0
  166. package/docs/templates/security-reviewer.md +89 -0
  167. package/docs/templates/triage.md +59 -101
  168. package/package.json +9 -1
  169. package/skills/github/SKILL.md +4 -5
  170. package/src/bin/agent-serve.ts +13 -6
  171. package/src/channels/github/github-channel.ts +95 -18
  172. package/src/channels/github/types.ts +31 -0
  173. package/src/channels/origin/cursor-account.ts +64 -0
  174. package/src/channels/origin/events.ts +41 -0
  175. package/src/channels/origin/index.ts +29 -0
  176. package/src/channels/origin/origin-channel.ts +784 -0
  177. package/src/channels/origin/origin-webhook.ts +202 -0
  178. package/src/channels/origin/types.ts +186 -0
  179. package/src/channels/slack/doctor.ts +218 -5
  180. package/src/index.ts +3 -1
  181. package/src/internal/cli-ax.ts +33 -1
  182. package/src/internal/cli-deploy.ts +2 -2
  183. package/src/internal/cli-slack.ts +68 -19
  184. package/src/internal/cursor-event-relay.ts +193 -31
  185. package/src/internal/discovery.ts +15 -5
  186. package/src/internal/distribution.ts +1 -0
  187. package/src/internal/handleAgentServeTrigger.ts +129 -19
  188. package/src/internal/init-interview.ts +384 -0
  189. package/src/internal/init-project.ts +146 -46
  190. package/src/internal/mcp-endpoint.ts +7 -0
  191. package/src/internal/server.ts +188 -58
  192. package/src/internal/session-engine.ts +5 -21
  193. package/src/internal/session-links.ts +88 -0
  194. package/src/internal/sessions-client.ts +1 -0
  195. package/src/internal/slack-provision-client.ts +1 -1
  196. package/src/types.ts +19 -12
  197. package/templates/agentic-owners/README.md +73 -0
  198. package/templates/agentic-owners/agent/agent.ts +15 -0
  199. package/templates/agentic-owners/agent/channels/github.ts +85 -0
  200. package/templates/agentic-owners/agent/instructions.md +34 -0
  201. package/templates/agentic-owners/agent/lib/config.ts +13 -0
  202. package/templates/agentic-owners/agent/lib/github.ts +241 -0
  203. package/templates/agentic-owners/agent/lib/owners/README.md +50 -0
  204. package/templates/agentic-owners/agent/lib/owners/constants.ts +22 -0
  205. package/templates/agentic-owners/agent/lib/owners/decision.ts +485 -0
  206. package/templates/agentic-owners/agent/lib/owners/handles.ts +54 -0
  207. package/templates/agentic-owners/agent/lib/owners/match.ts +177 -0
  208. package/templates/agentic-owners/agent/lib/owners/matching.ts +95 -0
  209. package/templates/agentic-owners/agent/lib/owners/parse.ts +589 -0
  210. package/templates/agentic-owners/agent/lib/owners/policyMode.ts +65 -0
  211. package/templates/agentic-owners/agent/lib/owners/prompt.ts +66 -0
  212. package/templates/agentic-owners/agent/lib/owners/prompts/base-review.md +105 -0
  213. package/templates/agentic-owners/agent/lib/owners/types.ts +45 -0
  214. package/templates/agentic-owners/agent/lib/review.ts +777 -0
  215. package/templates/agentic-owners/agent/tools/record_review.ts +69 -0
  216. package/templates/agentic-owners/evals/evals.config.ts +5 -0
  217. package/templates/agentic-owners/evals/owners.eval.ts +116 -0
  218. package/templates/agentic-owners/package.json +20 -0
  219. package/templates/agentic-owners/tsconfig.json +12 -0
  220. package/templates/demo/README.md +33 -0
  221. package/templates/demo/agent/agent.ts +15 -0
  222. package/templates/demo/agent/channels/github.ts +50 -0
  223. package/templates/demo/agent/channels/queue.ts +30 -0
  224. package/templates/demo/agent/instructions.md +8 -0
  225. package/templates/demo/agent/lib/collect.ts +78 -0
  226. package/templates/demo/agent/tools/record_demo.ts +40 -0
  227. package/templates/demo/evals/demo.eval.ts +33 -0
  228. package/templates/demo/evals/evals.config.ts +5 -0
  229. package/templates/demo/package.json +18 -0
  230. package/templates/demo/tsconfig.json +12 -0
  231. package/templates/pr-autofixer/README.md +44 -0
  232. package/templates/pr-autofixer/agent/agent.ts +22 -0
  233. package/templates/pr-autofixer/agent/channels/drive.ts +40 -0
  234. package/templates/pr-autofixer/agent/channels/github.ts +167 -0
  235. package/templates/pr-autofixer/agent/channels/slack.ts +17 -0
  236. package/templates/pr-autofixer/agent/hooks/bind-agent.ts +19 -0
  237. package/templates/pr-autofixer/agent/instructions.md +83 -0
  238. package/templates/pr-autofixer/agent/lib/affinity.ts +33 -0
  239. package/templates/pr-autofixer/agent/lib/drive-schemas.ts +15 -0
  240. package/templates/pr-autofixer/agent/lib/drive.ts +79 -0
  241. package/templates/pr-autofixer/agent/lib/merge-watch.ts +123 -0
  242. package/templates/pr-autofixer/agent/lib/pr-state.ts +54 -0
  243. package/templates/pr-autofixer/agent/lib/repos.ts +19 -0
  244. package/templates/pr-autofixer/agent/lib/start-drive.ts +122 -0
  245. package/templates/pr-autofixer/agent/lib/webhook-buffer.ts +225 -0
  246. package/templates/pr-autofixer/agent/lib/webhook-routing.ts +231 -0
  247. package/templates/pr-autofixer/agent/storage.ts +7 -0
  248. package/templates/pr-autofixer/agent/tools/drive_pr.ts +22 -0
  249. package/templates/pr-autofixer/evals/coordinator.eval.ts +16 -0
  250. package/templates/pr-autofixer/evals/evals.config.ts +5 -0
  251. package/templates/pr-autofixer/init.json +25 -0
  252. package/templates/pr-autofixer/package.json +18 -0
  253. package/templates/pr-autofixer/tsconfig.json +12 -0
  254. package/templates/security-reviewer/README.md +31 -0
  255. package/templates/security-reviewer/agent/agent.ts +15 -0
  256. package/templates/security-reviewer/agent/channels/github.ts +46 -0
  257. package/templates/security-reviewer/agent/instructions.md +22 -0
  258. package/templates/security-reviewer/agent/lib/repos.ts +5 -0
  259. package/templates/security-reviewer/agent/tools/post_findings.ts +72 -0
  260. package/templates/security-reviewer/evals/evals.config.ts +5 -0
  261. package/templates/security-reviewer/evals/review.eval.ts +53 -0
  262. package/templates/security-reviewer/init.json +25 -0
  263. package/templates/security-reviewer/package.json +18 -0
  264. package/templates/security-reviewer/tsconfig.json +12 -0
  265. package/templates/triage/README.md +27 -29
  266. package/templates/triage/agent/agent.ts +1 -0
  267. package/templates/triage/agent/channels/queue.ts +47 -0
  268. package/templates/triage/agent/channels/webhook.ts +50 -0
  269. package/templates/triage/agent/instructions.md +24 -13
  270. package/templates/triage/agent/lib/actuate.ts +759 -0
  271. package/templates/triage/agent/lib/parse-queue-event.ts +168 -0
  272. package/templates/triage/agent/lib/tracker.ts +5 -0
  273. package/templates/triage/agent/lib/types.ts +52 -0
  274. package/templates/triage/agent/lib/verify-webhook.ts +81 -0
  275. package/templates/triage/agent/skills/triage-rubric.md +6 -5
  276. package/templates/triage/agent/tools/record_triage.ts +24 -5
  277. package/templates/triage/evals/triage.eval.ts +25 -3
  278. package/templates/triage/overlays/jira/README.md +21 -0
  279. package/templates/triage/overlays/jira/agent/lib/tracker.ts +8 -0
  280. package/templates/triage/overlays/jira/agent/mcp-connections/tracker.ts +7 -0
  281. package/templates/triage/overlays/linear/README.md +21 -0
  282. package/templates/triage/overlays/linear/agent/lib/tracker.ts +8 -0
  283. package/templates/triage/overlays/linear/agent/mcp-connections/tracker.ts +7 -0
  284. package/templates/triage/package.json +1 -1
  285. package/dist/docs/assets/chunks/@localSearchIndexroot.C4uxzYEU.js +0 -1
  286. package/dist/docs/assets/index.md.COeoSkcF.js +0 -5
  287. package/dist/docs/assets/scaffolding-agents.md.mkc3B_ZW.js +0 -1
  288. package/dist/docs/assets/templates_triage.md.CConZt1z.js +0 -11
  289. package/dist/docs/assets/templates_triage.md.CConZt1z.lean.js +0 -1
  290. package/dist/playground/assets/index-BHAPd9KT.js +0 -85
  291. package/dist/playground/assets/index-DpKH0HcT.css +0 -1
  292. package/templates/triage/agent/channels/intake.ts +0 -20
  293. package/templates/triage/agent/channels/slack.ts +0 -3
@@ -40,6 +40,7 @@ import {
40
40
  snapshotToEvalRunResults,
41
41
  startRemoteEvalRun,
42
42
  } from "./evals-client.js";
43
+ import { runTemplateInit, type TemplateInitSpec } from "./init-interview.js";
43
44
  import {
44
45
  checkInitTarget,
45
46
  formatInitNextSteps,
@@ -134,6 +135,8 @@ export interface AxCliOptions {
134
135
  /** Scaffold target directory for `init`. */
135
136
  initTarget?: string;
136
137
  template?: string;
138
+ /** `init --var id=value` (repeatable). */
139
+ vars?: string[];
137
140
  /** Tool name for `call`. */
138
141
  toolName?: string;
139
142
  /** JSON input for `call`. */
@@ -292,6 +295,8 @@ export async function cmdInit(options: AxCliOptions): Promise<number> {
292
295
  return 0;
293
296
  }
294
297
  let templateDir: string | undefined;
298
+ let overlayDir: string | undefined;
299
+ let templateName: string | undefined;
295
300
  if (options.template !== undefined) {
296
301
  const template = resolveTemplate(options.template);
297
302
  if (!template.ok) {
@@ -299,6 +304,8 @@ export async function cmdInit(options: AxCliOptions): Promise<number> {
299
304
  return 1;
300
305
  }
301
306
  templateDir = template.dir;
307
+ overlayDir = template.overlayDir;
308
+ templateName = template.name;
302
309
  }
303
310
  const cwd = options.cwd ?? process.cwd();
304
311
  const dir = resolve(cwd, target);
@@ -307,7 +314,32 @@ export async function cmdInit(options: AxCliOptions): Promise<number> {
307
314
  process.stderr.write(`${targetCheck.message}\n`);
308
315
  return 1;
309
316
  }
310
- const result = await initProject({ dir, templateDir });
317
+ let answers: Record<string, string> | undefined;
318
+ let initSpec: TemplateInitSpec | undefined;
319
+ if (templateDir !== undefined) {
320
+ const interview = await runTemplateInit({
321
+ templateDir,
322
+ vars: options.vars,
323
+ interactive:
324
+ options.json !== true &&
325
+ process.stdin.isTTY === true &&
326
+ process.stdout.isTTY === true,
327
+ });
328
+ if (!interview.ok) {
329
+ process.stderr.write(`${interview.error}\n`);
330
+ return 1;
331
+ }
332
+ answers = interview.answers;
333
+ initSpec = interview.spec;
334
+ }
335
+ const result = await initProject({
336
+ dir,
337
+ templateDir,
338
+ overlayDir,
339
+ templateName,
340
+ answers,
341
+ initSpec,
342
+ });
311
343
  let signedIn = (await resolveApiKey()) !== undefined;
312
344
 
313
345
  // Machine-readable path: install deps (piped), never block on browser login.
@@ -223,8 +223,8 @@ export async function resolveDeployAuth(
223
223
  `${dim(
224
224
  `Using team ${teamId}${
225
225
  identity.teamName === undefined ? "" : ` (${identity.teamName})`
226
- } — the account's team; pass --team to override.`
227
- )}\n`
226
+ }`
227
+ )}\n${dim(" the account's team — pass --team to override.")}\n`
228
228
  );
229
229
  }
230
230
 
@@ -34,6 +34,7 @@ import {
34
34
  type SlackWizardMintResult,
35
35
  type SlackWizardPollResult,
36
36
  } from "./slack-provision-client.js";
37
+ import { stderrPalette, type TerminalPalette } from "./terminal-style.js";
37
38
 
38
39
  export interface SlackCliOptions {
39
40
  dir: string;
@@ -63,6 +64,8 @@ export interface SlackCliOptions {
63
64
  manual?: boolean;
64
65
  /** `slack icon <source>` positional (same URL-or-file forms as --icon). */
65
66
  iconSource?: string;
67
+ /** doctor: watched channel ids (`C…`) to verify visibility/membership. */
68
+ channels?: string[];
66
69
  /** Test seams. */
67
70
  fetchImpl?: typeof fetch;
68
71
  openBrowserImpl?: (url: string) => void;
@@ -71,6 +74,7 @@ export interface SlackCliOptions {
71
74
  doctorImpl?: typeof runSlackDoctor;
72
75
  out?: (text: string) => void;
73
76
  err?: (text: string) => void;
77
+ palette?: TerminalPalette;
74
78
  }
75
79
 
76
80
  const SLACK_HELP = `${CLI} slack — Slack channel pack helpers (Socket Mode)
@@ -89,6 +93,7 @@ Usage:
89
93
  ${CLI} slack manifest --env dev|prod|both [--dir .] [--name NAME]
90
94
  [--print]
91
95
  ${CLI} slack doctor [--dir .] [--prefix PREFIX | --no-prefix] [--json]
96
+ [--channel C0123ABCD]...
92
97
 
93
98
  create/destroy/icon — dedicated Socket Mode app via the Cursor dashboard:
94
99
  create Opens the signed-in dashboard wizard. Finish name, workspace,
@@ -153,7 +158,11 @@ async function runDoctor(options: SlackCliOptions): Promise<number> {
153
158
  loadAgentLocalEnv(dir);
154
159
  const envPrefix = resolveDoctorEnvPrefix(options, dir);
155
160
  const doctor = options.doctorImpl ?? runSlackDoctor;
156
- const result = await doctor(envPrefix === undefined ? {} : { envPrefix });
161
+ const channels = options.channels ?? [];
162
+ const result = await doctor({
163
+ envPrefix,
164
+ channels: channels.length > 0 ? channels : undefined,
165
+ });
157
166
  if (options.json) {
158
167
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
159
168
  } else {
@@ -198,6 +207,7 @@ interface SlackProvisionContext {
198
207
  json: boolean;
199
208
  out: (text: string) => void;
200
209
  err: (text: string) => void;
210
+ dim: (s: string) => string;
201
211
  openBrowserImpl: (url: string) => void;
202
212
  pollIntervalMs: number;
203
213
  pollTimeoutMs: number;
@@ -373,6 +383,7 @@ async function prepareProvision(
373
383
  json: options.json === true,
374
384
  out,
375
385
  err,
386
+ dim: (options.palette ?? stderrPalette()).dim,
376
387
  openBrowserImpl: options.openBrowserImpl ?? openBrowser,
377
388
  pollIntervalMs:
378
389
  options.connectPollIntervalMs ?? DEFAULT_WIZARD_POLL_INTERVAL_MS,
@@ -381,6 +392,40 @@ async function prepareProvision(
381
392
  };
382
393
  }
383
394
 
395
+ function writePendingAdminWait(
396
+ ctx: SlackProvisionContext,
397
+ poll: SlackWizardPollResult
398
+ ): void {
399
+ const appSuffix = poll.appId === undefined ? "" : ` (${poll.appId})`;
400
+ const requestUrl =
401
+ poll.oauthAuthorizeUrl !== undefined && poll.oauthAuthorizeUrl.length > 0
402
+ ? poll.oauthAuthorizeUrl
403
+ : undefined;
404
+ ctx.err(`Waiting for a Slack admin to approve the app${appSuffix}.\n\n`);
405
+ if (requestUrl !== undefined) {
406
+ ctx.err(
407
+ ctx.dim(
408
+ ` Slack will notify workspace owners once the request is in their queue.\n` +
409
+ ` Open this page to file it or send a reminder:\n\n`
410
+ )
411
+ );
412
+ ctx.err(` ${requestUrl}\n\n`);
413
+ ctx.openBrowserImpl(requestUrl);
414
+ } else {
415
+ ctx.err(
416
+ ctx.dim(
417
+ ` Slack will notify workspace owners once the request is in their queue.\n\n`
418
+ )
419
+ );
420
+ }
421
+ ctx.err(
422
+ ctx.dim(
423
+ ` Keep this command running.\n` +
424
+ ` After an admin approves, click Retry in the dashboard.\n`
425
+ )
426
+ );
427
+ }
428
+
384
429
  export async function cmdSlackCreate(
385
430
  options: SlackCliOptions
386
431
  ): Promise<number> {
@@ -412,7 +457,9 @@ export async function cmdSlackCreate(
412
457
  return 1;
413
458
  }
414
459
  if (wrote.length > 0 && !ctx.json) {
415
- ctx.err(`Scaffolded the Slack channel: ${wrote.join(", ")}\n`);
460
+ ctx.err(
461
+ `${ctx.dim(`Scaffolded the Slack channel: ${wrote.join(", ")}`)}\n`
462
+ );
416
463
  }
417
464
 
418
465
  const source = await inferDeployGitSource(target.dir);
@@ -436,10 +483,13 @@ export async function cmdSlackCreate(
436
483
  return renderSlackApiError(error, ctx.err);
437
484
  }
438
485
 
486
+ const waitMinutes = Math.round(ctx.pollTimeoutMs / 60_000);
487
+ ctx.err(`Finish Slack setup in the browser:\n\n ${minted.url}\n\n`);
439
488
  ctx.err(
440
- `Finish Slack setup in the browser:\n\n ${minted.url}\n\n` +
441
- `Sign in as the same Cursor account that ran this command. ` +
442
- `The CLI waits here (up to ${Math.round(ctx.pollTimeoutMs / 60_000)} minutes).\n`
489
+ ctx.dim(
490
+ ` Sign in as the same Cursor account that ran this command.\n` +
491
+ ` The CLI waits here (up to ${waitMinutes} minutes).\n`
492
+ )
443
493
  );
444
494
  ctx.openBrowserImpl(minted.url);
445
495
 
@@ -465,23 +515,16 @@ export async function cmdSlackCreate(
465
515
  }
466
516
  if (poll.status === "pending_admin_approval" && !sawPendingAdmin) {
467
517
  sawPendingAdmin = true;
468
- const appSuffix = poll.appId === undefined ? "" : ` (${poll.appId})`;
469
- ctx.err(
470
- `Waiting for a Slack admin to approve the app${appSuffix}. Keep this command running.\n` +
471
- `Managed install does not file the request. Open Slack to submit it; that same page lets you send a reminder to workspace owners.\n`
472
- );
473
- if (
474
- poll.oauthAuthorizeUrl !== undefined &&
475
- poll.oauthAuthorizeUrl.length > 0
476
- ) {
477
- ctx.err(` ${poll.oauthAuthorizeUrl}\n`);
478
- }
479
- ctx.err("After an admin approves, click Retry in the dashboard.\n");
518
+ writePendingAdminWait(ctx, poll);
480
519
  }
481
520
  if (Date.now() >= deadline) {
521
+ ctx.err(`Timed out waiting for Slack setup.\n\n`);
482
522
  ctx.err(
483
- `Timed out waiting for Slack setup. Finish it in the browser, then re-run \`${CLI} slack create\`.\n ${minted.url}\n`
523
+ ctx.dim(
524
+ ` Finish it in the browser, then re-run \`${CLI} slack create\`.\n\n`
525
+ )
484
526
  );
527
+ ctx.err(` ${minted.url}\n`);
485
528
  return 1;
486
529
  }
487
530
  await sleep(ctx.pollIntervalMs);
@@ -518,7 +561,10 @@ export async function cmdSlackCreate(
518
561
  }
519
562
  if (poll.localEnv.appToken === undefined) {
520
563
  ctx.err(
521
- `warning: Slack did not return an app-level token, so ${target.envKeys.app} was not written; re-run \`${CLI} slack create\` to recover it.\n`
564
+ ctx.dim(
565
+ `warning: Slack did not return an app-level token, so ${target.envKeys.app} was not written.\n` +
566
+ ` Re-run \`${CLI} slack create\` to recover it.\n`
567
+ )
522
568
  );
523
569
  }
524
570
 
@@ -840,6 +886,9 @@ function renderDoctorReport(result: SlackDoctorResult): string {
840
886
  text += `${check.ok ? "ok" : "!!"} ${check.id}: ${check.message}\n`;
841
887
  }
842
888
  text += result.ok ? "doctor: pass\n" : "doctor: fail\n";
889
+ for (const note of result.notes ?? []) {
890
+ text += `\nnote: ${note}\n`;
891
+ }
843
892
  return text;
844
893
  }
845
894
 
@@ -115,6 +115,12 @@ export interface CursorScmEvent {
115
115
  * Zod-valid `issue_comment` / `pull_request_review_comment` webhook body.
116
116
  */
117
117
  comment?: CursorScmCommentMeta;
118
+ /**
119
+ * Origin comment snapshot. Ids are Origin string ids, not GitHub integers.
120
+ */
121
+ originComment?: CursorScmOriginCommentMeta;
122
+ /** Origin actor (author / pusher / commenter) when present. */
123
+ originActor?: CursorScmOriginActorMeta;
118
124
  /** `check_run` snapshot; enough to stub `onCheckRun`. */
119
125
  checkRun?: CursorScmCheckRunMeta;
120
126
  /** `check_suite` snapshot; enough to stub `onCheckSuite`. */
@@ -125,6 +131,25 @@ export interface CursorScmEvent {
125
131
  occurredAtMs?: number;
126
132
  }
127
133
 
134
+ export type CursorScmOriginActorMeta = {
135
+ id: string;
136
+ kind?: string;
137
+ };
138
+
139
+ export type CursorScmOriginCommentMeta = {
140
+ id: string;
141
+ body?: string;
142
+ author?: CursorScmOriginActorMeta;
143
+ };
144
+
145
+ export type CursorScmProvider = "github" | "origin";
146
+
147
+ export interface CursorScmSubscription {
148
+ provider: CursorScmProvider;
149
+ repo: string;
150
+ events: readonly string[];
151
+ }
152
+
128
153
  interface SubscriptionStatus {
129
154
  provider: string;
130
155
  repo: string;
@@ -135,8 +160,17 @@ interface SubscriptionStatus {
135
160
  export interface CursorEventRelayOptions {
136
161
  baseUrl: string;
137
162
  apiKey: string;
138
- repos: readonly string[];
139
- events: readonly string[];
163
+ /**
164
+ * GitHub-only shorthand. Ignored when {@link subscriptions} is set.
165
+ * Existing `--cursor-events --repo` hosts keep passing these.
166
+ */
167
+ repos?: readonly string[];
168
+ events?: readonly string[];
169
+ /**
170
+ * Mixed GitHub + Origin registrations. Provider is part of the
171
+ * subscription key: mirrored `owner/name` slugs must not collide.
172
+ */
173
+ subscriptions?: readonly CursorScmSubscription[];
140
174
  stateDir: string;
141
175
  /**
142
176
  * Called for each matching event; failures retry a bounded number of
@@ -430,30 +464,149 @@ function stubGitHubWorkflowRun(
430
464
  }
431
465
 
432
466
  /**
433
- * GitHub SCM-events relay: a thin {@link CursorRelayCore} adapter. Consumers
467
+ * Origin webhook envelope from an SCM-events metadata record. One parser
468
+ * handles both live Origin deliveries and this stub: `{ deliveryId, event }`.
469
+ */
470
+ export function scmMetadataToOriginPayload(event: {
471
+ repo: string;
472
+ eventName: string;
473
+ deliveryId?: string;
474
+ action?: string;
475
+ prNumber?: number;
476
+ prUrl?: string;
477
+ pullRequest?: CursorScmPullRequestMeta;
478
+ originComment?: CursorScmOriginCommentMeta;
479
+ originActor?: CursorScmOriginActorMeta;
480
+ occurredAtMs?: number;
481
+ }): Record<string, unknown> {
482
+ const slash = event.repo.indexOf("/");
483
+ const owner = slash === -1 ? "" : event.repo.slice(0, slash);
484
+ const name = slash === -1 ? event.repo : event.repo.slice(slash + 1);
485
+ const prMeta = event.pullRequest;
486
+ const prNumber = prMeta?.number ?? event.prNumber;
487
+ const prUrl =
488
+ prMeta?.url ??
489
+ event.prUrl ??
490
+ (prNumber !== undefined
491
+ ? `https://cursor.com/codebase/${owner}/${name}/pull/${prNumber}`
492
+ : undefined);
493
+
494
+ const payload: Record<string, unknown> = {
495
+ repository: {
496
+ name,
497
+ owner: { slug: owner },
498
+ },
499
+ };
500
+
501
+ if (prNumber !== undefined) {
502
+ const pullRequest: Record<string, unknown> = {
503
+ number: prNumber,
504
+ url: prUrl,
505
+ };
506
+ if (prMeta?.title !== undefined) pullRequest.title = prMeta.title;
507
+ if (prMeta?.body !== undefined) pullRequest.body = prMeta.body;
508
+ if (prMeta?.draft !== undefined) pullRequest.draft = prMeta.draft;
509
+ if (prMeta?.merged !== undefined) pullRequest.merged = prMeta.merged;
510
+ if (prMeta?.headRef !== undefined || prMeta?.headSha !== undefined) {
511
+ pullRequest.head = {
512
+ ref: prMeta.headRef,
513
+ sha: prMeta.headSha,
514
+ };
515
+ }
516
+ if (prMeta?.baseRef !== undefined || prMeta?.baseSha !== undefined) {
517
+ pullRequest.base = {
518
+ ref: prMeta.baseRef,
519
+ sha: prMeta.baseSha,
520
+ };
521
+ }
522
+ if (prMeta?.authorLogin !== undefined) {
523
+ pullRequest.author = { id: prMeta.authorLogin };
524
+ }
525
+ payload.pullRequest = pullRequest;
526
+ }
527
+
528
+ const commentMeta = event.originComment;
529
+ if (commentMeta !== undefined) {
530
+ const comment: Record<string, unknown> = { id: commentMeta.id };
531
+ if (commentMeta.body !== undefined) comment.body = commentMeta.body;
532
+ if (commentMeta.author !== undefined) comment.author = commentMeta.author;
533
+ payload.comment = comment;
534
+ }
535
+ if (event.originActor !== undefined) {
536
+ payload.actor = event.originActor;
537
+ }
538
+
539
+ return {
540
+ deliveryId: event.deliveryId,
541
+ event: {
542
+ type: event.eventName,
543
+ ...(event.occurredAtMs === undefined
544
+ ? {}
545
+ : { eventTime: new Date(event.occurredAtMs).toISOString() }),
546
+ payload,
547
+ },
548
+ };
549
+ }
550
+
551
+ function subscriptionKey(provider: string, repo: string): string {
552
+ return `${provider}:${repo.toLowerCase()}`;
553
+ }
554
+
555
+ function subscriptionLabel(provider: string, repo: string): string {
556
+ return provider === "github" ? repo : `${provider}:${repo}`;
557
+ }
558
+
559
+ export function resolveCursorScmSubscriptions(
560
+ options: Pick<CursorEventRelayOptions, "repos" | "events" | "subscriptions">
561
+ ): CursorScmSubscription[] {
562
+ if (options.subscriptions !== undefined) {
563
+ return options.subscriptions.map((subscription) => ({
564
+ provider: subscription.provider,
565
+ repo: subscription.repo.trim().toLowerCase(),
566
+ events: [...subscription.events],
567
+ }));
568
+ }
569
+ const events = [...(options.events ?? [])];
570
+ return (options.repos ?? []).map((repo) => ({
571
+ provider: "github" as const,
572
+ repo: repo.trim().toLowerCase(),
573
+ events,
574
+ }));
575
+ }
576
+
577
+ /**
578
+ * SCM-events relay: a thin {@link CursorRelayCore} adapter. Consumers
434
579
  * keep the same `new CursorEventRelay(options).start()/.stop()` surface.
435
580
  */
436
581
  export class CursorEventRelay {
437
582
  private readonly core: CursorRelayCore<CursorScmEvent>;
583
+ private readonly subscriptions: CursorScmSubscription[];
438
584
  /**
439
- * Normalized repos the server confirmed for THIS consumer. The stream is
440
- * shared with sibling consumers of the same principal, so only events for
441
- * these repos may dispatch.
585
+ * Confirmed `provider:repo` keys for THIS consumer, with the event kinds
586
+ * requested for each. The stream is shared with sibling consumers, so
587
+ * GitHub and Origin deliveries for the same owner/name must not mix.
442
588
  */
443
- private subscribedRepos = new Set<string>();
444
- private readonly loggedSkippedRepos = new Set<string>();
589
+ private subscribedEvents = new Map<string, ReadonlySet<string>>();
590
+ private readonly loggedSkippedKeys = new Set<string>();
445
591
 
446
592
  constructor(private readonly options: CursorEventRelayOptions) {
593
+ this.subscriptions = resolveCursorScmSubscriptions(options);
594
+ const requestedEvents = new Map(
595
+ this.subscriptions.map((subscription) => [
596
+ subscriptionKey(subscription.provider, subscription.repo),
597
+ new Set(subscription.events),
598
+ ])
599
+ );
447
600
  const adapter: RelayAdapter<CursorScmEvent> = {
448
601
  logPrefix: "cursor-events",
449
602
  subscribePath: "/v0/scm-events/subscriptions",
450
603
  pollPath: "/v0/scm-events",
451
604
  buildRegistrationBody: (consumerId) => ({
452
605
  consumerId,
453
- subscriptions: this.options.repos.map((repo) => ({
454
- provider: "github",
455
- repo,
456
- events: [...this.options.events],
606
+ subscriptions: this.subscriptions.map((subscription) => ({
607
+ provider: subscription.provider,
608
+ repo: subscription.repo,
609
+ events: [...subscription.events],
457
610
  })),
458
611
  }),
459
612
  // Empty subscriptions drop this consumer's registration on clean stop
@@ -465,20 +618,27 @@ export class CursorEventRelay {
465
618
  applyRegistrationResponse: (json) => {
466
619
  const result = json as { repos?: SubscriptionStatus[] };
467
620
  const statuses = result.repos ?? [];
468
- this.subscribedRepos = new Set(
469
- statuses
470
- .filter((status) => status.isSubscribed)
471
- .map((status) => status.repo)
472
- );
621
+ this.subscribedEvents = new Map();
473
622
  const lines: string[] = [];
474
- for (const status of statuses.filter((s) => !s.isSubscribed)) {
475
- lines.push(
476
- `not subscribed to ${status.repo}: ${status.detail ?? "unknown reason"}`
477
- );
623
+ const confirmed: string[] = [];
624
+ for (const status of statuses) {
625
+ const provider = status.provider || "github";
626
+ const key = subscriptionKey(provider, status.repo);
627
+ if (!status.isSubscribed) {
628
+ lines.push(
629
+ `not subscribed to ${subscriptionLabel(provider, status.repo)}: ${status.detail ?? "unknown reason"}`
630
+ );
631
+ continue;
632
+ }
633
+ this.subscribedEvents.set(key, requestedEvents.get(key) ?? new Set());
634
+ confirmed.push(subscriptionLabel(provider, status.repo));
478
635
  }
479
- if (this.subscribedRepos.size > 0) {
636
+ if (confirmed.length > 0) {
637
+ const eventKinds = [
638
+ ...new Set(this.subscriptions.flatMap((s) => [...s.events])),
639
+ ];
480
640
  lines.push(
481
- `subscribed to ${[...this.subscribedRepos].join(", ")} for events: ${this.options.events.join(", ")}`
641
+ `subscribed to ${confirmed.join(", ")} for events: ${eventKinds.join(", ")}`
482
642
  );
483
643
  }
484
644
  return lines;
@@ -503,21 +663,23 @@ export class CursorEventRelay {
503
663
 
504
664
  /**
505
665
  * Whether an event from the shared stream belongs to THIS consumer: the
506
- * repo must be one the server confirmed for us and the event kind one the
507
- * mounted channels declared. Anything else came from a sibling consumer's
508
- * subscription and must not fire this host's hooks.
666
+ * provider+repo must be one the server confirmed for us and the event kind
667
+ * one that subscription declared. GitHub and Origin share owner/name slugs
668
+ * on mirrors, so the provider is part of the key.
509
669
  */
510
670
  private shouldDispatch(event: CursorScmEvent): boolean {
511
- if (!this.subscribedRepos.has(event.repo)) {
512
- if (!this.loggedSkippedRepos.has(event.repo)) {
513
- this.loggedSkippedRepos.add(event.repo);
671
+ const key = subscriptionKey(event.provider || "github", event.repo);
672
+ const events = this.subscribedEvents.get(key);
673
+ if (events === undefined) {
674
+ if (!this.loggedSkippedKeys.has(key)) {
675
+ this.loggedSkippedKeys.add(key);
514
676
  this.options.logger(
515
- `[agent-sdk] cursor-events: skipping events for ${event.repo}: not in this host's subscription (another consumer of this API key likely subscribed it)`
677
+ `[agent-sdk] cursor-events: skipping events for ${subscriptionLabel(event.provider || "github", event.repo)}: not in this host's subscription (another consumer of this API key likely subscribed it)`
516
678
  );
517
679
  }
518
680
  return false;
519
681
  }
520
- return this.options.events.includes(event.eventName);
682
+ return events.has(event.eventName);
521
683
  }
522
684
 
523
685
  start(): void {
@@ -16,6 +16,7 @@ import {
16
16
  relative,
17
17
  resolve,
18
18
  } from "node:path";
19
+ import { pathToFileURL } from "node:url";
19
20
  import { type ABConfigFile, resolveABMaxPlaygroundSessions } from "../ab.js";
20
21
  import { resolveArtifactsMax } from "../artifacts.js";
21
22
  import { httpChannel } from "../channels.js";
@@ -60,10 +61,7 @@ import {
60
61
  type ToolDefinition,
61
62
  toPublicCloudInfo,
62
63
  } from "../types.js";
63
- import {
64
- importAuthoredModule,
65
- registerAuthoredModuleLoaders,
66
- } from "./authored-loaders.js";
64
+ import { registerAuthoredModuleLoaders } from "./authored-loaders.js";
67
65
  import { normalizePositiveInt } from "./bounded-int.js";
68
66
  import { getDefinitionKind } from "./brand.js";
69
67
  import {
@@ -96,6 +94,15 @@ export interface LoadAgentProjectOptions {
96
94
 
97
95
  type ImportModule = (absolutePath: string) => Promise<Record<string, unknown>>;
98
96
 
97
+ async function defaultImportModule(
98
+ absolutePath: string
99
+ ): Promise<Record<string, unknown>> {
100
+ return (await import(pathToFileURL(absolutePath).href)) as Record<
101
+ string,
102
+ unknown
103
+ >;
104
+ }
105
+
99
106
  interface DiscoveryContext {
100
107
  rootDir: string;
101
108
  diagnostics: Diagnostic[];
@@ -275,7 +282,7 @@ export async function loadAgentProject(
275
282
  const ctx: DiscoveryContext = {
276
283
  rootDir,
277
284
  diagnostics,
278
- importModule: options.importModule ?? importAuthoredModule,
285
+ importModule: options.importModule ?? defaultImportModule,
279
286
  };
280
287
 
281
288
  const name = (await readPackageName(rootDir)) ?? basename(rootDir);
@@ -1998,6 +2005,9 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
1998
2005
  if (meta?.githubWebhookEvents !== undefined) {
1999
2006
  info.githubWebhookEvents = meta.githubWebhookEvents;
2000
2007
  }
2008
+ if (meta?.originWebhookEvents !== undefined) {
2009
+ info.originWebhookEvents = meta.originWebhookEvents;
2010
+ }
2001
2011
  if (meta?.slackChannelPosts !== undefined) {
2002
2012
  info.slackChannelPosts = meta.slackChannelPosts;
2003
2013
  }
@@ -96,6 +96,7 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
96
96
  ["channels", "channels.js"],
97
97
  ["channels/slack", "channels/slack/index.js"],
98
98
  ["channels/github", "channels/github/index.js"],
99
+ ["channels/origin", "channels/origin/index.js"],
99
100
  ["skills", "skills.js"],
100
101
  ["schedules", "schedules.js"],
101
102
  ["reminders", "reminders.js"],