@cursor/july 0.1.94 → 0.1.96

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 (332) hide show
  1. package/AGENTS.md +3 -4
  2. package/dist/channels/deployments/types.d.ts +1 -1
  3. package/dist/channels/deployments/types.d.ts.map +1 -1
  4. package/dist/channels/deployments/types.js +1 -0
  5. package/dist/channels/github/github-channel.d.ts.map +1 -1
  6. package/dist/channels/github/github-channel.js +14 -2
  7. package/dist/channels/github/types.d.ts +18 -3
  8. package/dist/channels/github/types.d.ts.map +1 -1
  9. package/dist/channels/origin/api.d.ts +59 -13
  10. package/dist/channels/origin/api.d.ts.map +1 -1
  11. package/dist/channels/origin/api.js +168 -27
  12. package/dist/channels/origin/binding.d.ts +2 -2
  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/origin-channel.d.ts.map +1 -1
  19. package/dist/channels/origin/origin-channel.js +11 -3
  20. package/dist/channels/origin/origin-webhook.d.ts +11 -1
  21. package/dist/channels/origin/origin-webhook.d.ts.map +1 -1
  22. package/dist/channels/origin/origin-webhook.js +23 -3
  23. package/dist/channels/origin/types.d.ts +8 -0
  24. package/dist/channels/origin/types.d.ts.map +1 -1
  25. package/dist/channels/slack/api.d.ts +9 -0
  26. package/dist/channels/slack/api.d.ts.map +1 -1
  27. package/dist/channels/slack/api.js +36 -5
  28. package/dist/channels/slack/defaults.d.ts.map +1 -1
  29. package/dist/channels/slack/defaults.js +17 -46
  30. package/dist/channels/slack/dispatch.d.ts +7 -1
  31. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  32. package/dist/channels/slack/dispatch.js +47 -23
  33. package/dist/channels/slack/inbound.d.ts +8 -0
  34. package/dist/channels/slack/inbound.d.ts.map +1 -1
  35. package/dist/channels/slack/inbound.js +32 -0
  36. package/dist/channels/slack/live-delivery.d.ts +26 -29
  37. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  38. package/dist/channels/slack/live-delivery.js +172 -73
  39. package/dist/channels/slack/manifest.d.ts.map +1 -1
  40. package/dist/channels/slack/manifest.js +5 -1
  41. package/dist/channels/slack/nudge-carrier.d.ts +2 -0
  42. package/dist/channels/slack/nudge-carrier.d.ts.map +1 -1
  43. package/dist/channels/slack/nudge-carrier.js +48 -1
  44. package/dist/channels/slack/pr-ref.d.ts +7 -1
  45. package/dist/channels/slack/pr-ref.d.ts.map +1 -1
  46. package/dist/channels/slack/pr-ref.js +42 -23
  47. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  48. package/dist/channels/slack/slack-channel.js +2 -2
  49. package/dist/docs/404.html +2 -2
  50. package/dist/docs/ab.html +4 -4
  51. package/dist/docs/assets/{app.CFDEas4I.js → app.jXleCmOc.js} +1 -1
  52. package/dist/docs/assets/chunks/@localSearchIndexroot.DFoGuETX.js +1 -0
  53. package/dist/docs/assets/chunks/{VPLocalSearchBox.B1IIYpYS.js → VPLocalSearchBox.8LhyglIT.js} +1 -1
  54. package/dist/docs/assets/chunks/{theme.Ct4NSiLm.js → theme.9ged-pr2.js} +2 -2
  55. package/dist/docs/assets/index.md.CI93Ltlb.js +5 -0
  56. package/dist/docs/assets/{index.md.DRakGHFe.lean.js → index.md.CI93Ltlb.lean.js} +1 -1
  57. package/dist/docs/assets/{reference_cli.md.Cw6_ICYG.js → reference_cli.md.CCnG-nJx.js} +4 -2
  58. package/dist/docs/assets/{reference_cli.md.Cw6_ICYG.lean.js → reference_cli.md.CCnG-nJx.lean.js} +1 -1
  59. package/dist/docs/assets/{reference_skills.md.8son6Hjm.js → reference_skills.md.BFW9retM.js} +3 -3
  60. package/dist/docs/assets/{templates_agentic-owners.md.DqtPdm6f.js → templates_agentic-owners.md.BZSH4N9z.js} +1 -1
  61. package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.js +2 -0
  62. package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.lean.js +1 -0
  63. package/dist/docs/assets/{templates_demo.md.DhFcWN6j.js → templates_demo.md.BeQX9V3H.js} +1 -1
  64. package/dist/docs/assets/{templates_pr-autofixer.md.DU7dQpor.js → templates_pr-autofixer.md.x5zl6-GT.js} +2 -2
  65. package/dist/docs/assets/{templates_pr-autofixer.md.DU7dQpor.lean.js → templates_pr-autofixer.md.x5zl6-GT.lean.js} +1 -1
  66. package/dist/docs/assets/templates_security-help.md.C3Ny_Qr2.js +4 -0
  67. package/dist/docs/assets/templates_security-help.md.C3Ny_Qr2.lean.js +1 -0
  68. package/dist/docs/assets/{templates_security-reviewer.md.CTa7u_l1.js → templates_security-reviewer.md.lshxbCLK.js} +2 -2
  69. package/dist/docs/assets/{templates_security-reviewer.md.CTa7u_l1.lean.js → templates_security-reviewer.md.lshxbCLK.lean.js} +1 -1
  70. package/dist/docs/assets/{templates_triage.md.CVlpctKS.js → templates_triage.md.Co4UNzkZ.js} +3 -3
  71. package/dist/docs/assets/{templates_triage.md.CVlpctKS.lean.js → templates_triage.md.Co4UNzkZ.lean.js} +1 -1
  72. package/dist/docs/building-with-agents.html +4 -4
  73. package/dist/docs/concepts.html +4 -4
  74. package/dist/docs/deployment.html +4 -4
  75. package/dist/docs/evals.html +4 -4
  76. package/dist/docs/guides/agent-to-agent.html +4 -4
  77. package/dist/docs/guides/cloud-runtime.html +4 -4
  78. package/dist/docs/guides/convert-automation.html +4 -4
  79. package/dist/docs/guides/github.html +4 -4
  80. package/dist/docs/guides/human-in-the-loop.html +4 -4
  81. package/dist/docs/guides/mcp-oauth.html +4 -4
  82. package/dist/docs/guides/opentelemetry.html +4 -4
  83. package/dist/docs/guides/slack.html +4 -4
  84. package/dist/docs/guides/webhooks.html +4 -4
  85. package/dist/docs/hashmap.json +1 -1
  86. package/dist/docs/hillclimbing.html +4 -4
  87. package/dist/docs/index.html +6 -6
  88. package/dist/docs/index.md +5 -1
  89. package/dist/docs/llms-full.txt +189 -26
  90. package/dist/docs/llms.txt +2 -0
  91. package/dist/docs/quickstart.html +4 -4
  92. package/dist/docs/reference/agent-config.html +4 -4
  93. package/dist/docs/reference/artifacts.html +4 -4
  94. package/dist/docs/reference/channels.html +4 -4
  95. package/dist/docs/reference/cli.html +8 -6
  96. package/dist/docs/reference/cli.md +4 -1
  97. package/dist/docs/reference/connections.html +4 -4
  98. package/dist/docs/reference/hooks.html +4 -4
  99. package/dist/docs/reference/http-api.html +4 -4
  100. package/dist/docs/reference/instructions.html +4 -4
  101. package/dist/docs/reference/playground.html +4 -4
  102. package/dist/docs/reference/project-layout.html +4 -4
  103. package/dist/docs/reference/prompt.html +4 -4
  104. package/dist/docs/reference/schedules.html +4 -4
  105. package/dist/docs/reference/sessions.html +4 -4
  106. package/dist/docs/reference/skills.html +7 -7
  107. package/dist/docs/reference/subagents.html +4 -4
  108. package/dist/docs/reference/tools.html +4 -4
  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 +7 -7
  112. package/dist/docs/templates/agentic-owners.md +1 -1
  113. package/dist/docs/templates/code-wiki.html +28 -0
  114. package/dist/docs/templates/code-wiki.md +91 -0
  115. package/dist/docs/templates/demo.html +6 -6
  116. package/dist/docs/templates/demo.md +3 -2
  117. package/dist/docs/templates/pr-autofixer.html +6 -6
  118. package/dist/docs/templates/pr-autofixer.md +7 -13
  119. package/dist/docs/templates/security-help.html +30 -0
  120. package/dist/docs/templates/security-help.md +65 -0
  121. package/dist/docs/templates/security-reviewer.html +6 -6
  122. package/dist/docs/templates/security-reviewer.md +1 -2
  123. package/dist/docs/templates/triage.html +7 -7
  124. package/dist/docs/templates/triage.md +2 -6
  125. package/dist/docs/troubleshooting.html +4 -4
  126. package/dist/files-backends/cursor-hosted.d.ts +26 -0
  127. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  128. package/dist/files-backends/cursor-hosted.js +32 -4
  129. package/dist/files.d.ts +2 -0
  130. package/dist/files.d.ts.map +1 -1
  131. package/dist/files.js +5 -0
  132. package/dist/internal/advertise-tools.d.ts +2 -0
  133. package/dist/internal/advertise-tools.d.ts.map +1 -1
  134. package/dist/internal/advertise-tools.js +15 -1
  135. package/dist/internal/bounded.d.ts +7 -0
  136. package/dist/internal/bounded.d.ts.map +1 -0
  137. package/dist/internal/bounded.js +32 -0
  138. package/dist/internal/cli-deploy.d.ts.map +1 -1
  139. package/dist/internal/cli-deploy.js +142 -7
  140. package/dist/internal/conversation-mirror.d.ts +85 -0
  141. package/dist/internal/conversation-mirror.d.ts.map +1 -0
  142. package/dist/internal/conversation-mirror.js +312 -0
  143. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  144. package/dist/internal/cursor/backend-client.js +22 -48
  145. package/dist/internal/cursor/session-token.d.ts +45 -0
  146. package/dist/internal/cursor/session-token.d.ts.map +1 -0
  147. package/dist/internal/cursor/session-token.js +99 -0
  148. package/dist/internal/cursor-agent-template.d.ts +1 -1
  149. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  150. package/dist/internal/cursor-agent-template.js +1 -0
  151. package/dist/internal/deferred-channel-session.d.ts +20 -0
  152. package/dist/internal/deferred-channel-session.d.ts.map +1 -0
  153. package/dist/internal/deferred-channel-session.js +62 -0
  154. package/dist/internal/deploy-client.d.ts +13 -1
  155. package/dist/internal/deploy-client.d.ts.map +1 -1
  156. package/dist/internal/deploy-client.js +11 -1
  157. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  158. package/dist/internal/deploy-manifest.js +11 -5
  159. package/dist/internal/discovery.d.ts.map +1 -1
  160. package/dist/internal/discovery.js +22 -2
  161. package/dist/internal/framework-file-storage.d.ts +61 -0
  162. package/dist/internal/framework-file-storage.d.ts.map +1 -0
  163. package/dist/internal/framework-file-storage.js +204 -0
  164. package/dist/internal/framework-storage-selection.d.ts +38 -16
  165. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  166. package/dist/internal/framework-storage-selection.js +78 -17
  167. package/dist/internal/hosted-admission-context.d.ts +20 -0
  168. package/dist/internal/hosted-admission-context.d.ts.map +1 -0
  169. package/dist/internal/hosted-admission-context.js +31 -0
  170. package/dist/internal/hosted-delivery-protocol.d.ts +5 -0
  171. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  172. package/dist/internal/hosted-delivery-protocol.js +33 -1
  173. package/dist/internal/hosted-delivery.d.ts +11 -2
  174. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  175. package/dist/internal/hosted-delivery.js +79 -35
  176. package/dist/internal/hosted-managed-automation.d.ts +30 -0
  177. package/dist/internal/hosted-managed-automation.d.ts.map +1 -0
  178. package/dist/internal/hosted-managed-automation.js +58 -0
  179. package/dist/internal/init-project.d.ts.map +1 -1
  180. package/dist/internal/init-project.js +2 -0
  181. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  182. package/dist/internal/install-cursor-skills.js +1 -3
  183. package/dist/internal/managed-delivery.d.ts +80 -0
  184. package/dist/internal/managed-delivery.d.ts.map +1 -0
  185. package/dist/internal/managed-delivery.js +86 -0
  186. package/dist/internal/review-comments.d.ts.map +1 -1
  187. package/dist/internal/review-comments.js +10 -98
  188. package/dist/internal/runtime-dispatch-runner.d.ts +5 -1
  189. package/dist/internal/runtime-dispatch-runner.d.ts.map +1 -1
  190. package/dist/internal/runtime-dispatch-runner.js +7 -0
  191. package/dist/internal/scm/pr-url.d.ts +14 -0
  192. package/dist/internal/scm/pr-url.d.ts.map +1 -0
  193. package/dist/internal/scm/pr-url.js +65 -0
  194. package/dist/internal/sdk-runner.d.ts +25 -0
  195. package/dist/internal/sdk-runner.d.ts.map +1 -1
  196. package/dist/internal/sdk-runner.js +70 -0
  197. package/dist/internal/server.d.ts.map +1 -1
  198. package/dist/internal/server.js +11 -2
  199. package/dist/internal/session-engine.d.ts +13 -0
  200. package/dist/internal/session-engine.d.ts.map +1 -1
  201. package/dist/internal/session-engine.js +71 -3
  202. package/dist/internal/steering.d.ts +15 -0
  203. package/dist/internal/steering.d.ts.map +1 -0
  204. package/dist/internal/steering.js +18 -0
  205. package/dist/playground/assets/index-B1DDvBeC.css +1 -0
  206. package/dist/playground/assets/{index-B3JCyigB.js → index-Cx9CclK_.js} +47 -47
  207. package/dist/playground/index.html +2 -2
  208. package/dist/storage-backends/cursor-hosted.d.ts +8 -0
  209. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  210. package/dist/storage-backends/cursor-hosted.js +4 -3
  211. package/dist/types.d.ts +2 -1
  212. package/dist/types.d.ts.map +1 -1
  213. package/docs/README.md +5 -1
  214. package/docs/reference/cli.md +4 -1
  215. package/docs/templates/agentic-owners.md +1 -1
  216. package/docs/templates/code-wiki.md +96 -0
  217. package/docs/templates/demo.md +3 -2
  218. package/docs/templates/pr-autofixer.md +7 -13
  219. package/docs/templates/security-help.md +70 -0
  220. package/docs/templates/security-reviewer.md +1 -2
  221. package/docs/templates/triage.md +2 -6
  222. package/package.json +2 -2
  223. package/skills/ab/SKILL.md +13 -97
  224. package/skills/create-agent/SKILL.md +123 -223
  225. package/skills/debug/SKILL.md +34 -68
  226. package/skills/evals/SKILL.md +55 -180
  227. package/skills/framework-map/SKILL.md +83 -145
  228. package/skills/github/SKILL.md +53 -111
  229. package/skills/hillclimb/SKILL.md +40 -163
  230. package/skills/mcp-auth/SKILL.md +48 -107
  231. package/skills/otel/SKILL.md +22 -68
  232. package/skills/setup-slack/SKILL.md +77 -208
  233. package/src/channels/deployments/types.ts +1 -0
  234. package/src/channels/github/github-channel.ts +23 -8
  235. package/src/channels/github/types.ts +19 -2
  236. package/src/channels/origin/api.ts +242 -30
  237. package/src/channels/origin/binding.ts +2 -2
  238. package/src/channels/origin/checks.ts +6 -6
  239. package/src/channels/origin/cursor-account.ts +5 -3
  240. package/src/channels/origin/origin-channel.ts +13 -1
  241. package/src/channels/origin/origin-webhook.ts +27 -3
  242. package/src/channels/origin/types.ts +8 -0
  243. package/src/channels/slack/api.ts +41 -5
  244. package/src/channels/slack/defaults.ts +15 -49
  245. package/src/channels/slack/dispatch.ts +56 -22
  246. package/src/channels/slack/inbound.ts +43 -0
  247. package/src/channels/slack/live-delivery.ts +235 -114
  248. package/src/channels/slack/manifest.ts +5 -1
  249. package/src/channels/slack/nudge-carrier.ts +48 -1
  250. package/src/channels/slack/pr-ref.ts +56 -25
  251. package/src/channels/slack/slack-channel.ts +2 -0
  252. package/src/files-backends/cursor-hosted.ts +41 -2
  253. package/src/files.ts +11 -0
  254. package/src/internal/advertise-tools.ts +18 -2
  255. package/src/internal/bounded.ts +28 -0
  256. package/src/internal/cli-deploy.ts +183 -7
  257. package/src/internal/conversation-mirror.ts +406 -0
  258. package/src/internal/cursor/backend-client.ts +34 -58
  259. package/src/internal/cursor/session-token.ts +115 -0
  260. package/src/internal/cursor-agent-template.ts +1 -0
  261. package/src/internal/deferred-channel-session.ts +61 -0
  262. package/src/internal/deploy-client.ts +24 -1
  263. package/src/internal/deploy-manifest.ts +10 -5
  264. package/src/internal/discovery.ts +25 -2
  265. package/src/internal/framework-file-storage.ts +222 -0
  266. package/src/internal/framework-storage-selection.ts +101 -19
  267. package/src/internal/hosted-admission-context.ts +37 -0
  268. package/src/internal/hosted-delivery-protocol.ts +44 -1
  269. package/src/internal/hosted-delivery.ts +105 -40
  270. package/src/internal/hosted-managed-automation.ts +72 -0
  271. package/src/internal/init-project.ts +2 -0
  272. package/src/internal/install-cursor-skills.ts +1 -4
  273. package/src/internal/managed-delivery.ts +125 -0
  274. package/src/internal/review-comments.ts +10 -113
  275. package/src/internal/runtime-dispatch-runner.ts +10 -0
  276. package/src/internal/scm/pr-url.ts +95 -0
  277. package/src/internal/sdk-runner.ts +103 -0
  278. package/src/internal/server.ts +12 -0
  279. package/src/internal/session-engine.ts +76 -4
  280. package/src/internal/steering.ts +17 -0
  281. package/src/storage-backends/cursor-hosted.ts +10 -1
  282. package/src/types.ts +2 -1
  283. package/templates/agentic-owners/README.md +1 -1
  284. package/templates/agentic-owners/agent/agent.ts +0 -10
  285. package/templates/agentic-owners/agent/channels/github.ts +5 -14
  286. package/templates/agentic-owners/agent/lib/config.ts +0 -8
  287. package/templates/agentic-owners/agent/lib/review.ts +2 -15
  288. package/templates/agentic-owners/agent/tools/record_review.ts +2 -4
  289. package/templates/code-wiki/README.md +34 -0
  290. package/templates/code-wiki/agent/agent.ts +8 -0
  291. package/templates/code-wiki/agent/channels/github.ts +144 -0
  292. package/templates/code-wiki/agent/instructions.md +39 -0
  293. package/templates/code-wiki/agent/lib/repos.ts +5 -0
  294. package/templates/code-wiki/agent/lib/wiki.ts +22 -0
  295. package/templates/code-wiki/agent/tools/apply_wiki.ts +219 -0
  296. package/templates/code-wiki/evals/evals.config.ts +5 -0
  297. package/templates/code-wiki/evals/wiki.eval.ts +132 -0
  298. package/templates/code-wiki/init.json +25 -0
  299. package/templates/code-wiki/package.json +18 -0
  300. package/templates/code-wiki/tsconfig.json +12 -0
  301. package/templates/demo/agent/agent.ts +0 -10
  302. package/templates/pr-autofixer/README.md +0 -2
  303. package/templates/pr-autofixer/agent/agent.ts +0 -11
  304. package/templates/pr-autofixer/agent/channels/slack.ts +0 -7
  305. package/templates/pr-autofixer/agent/lib/pr-state.ts +5 -17
  306. package/templates/pr-autofixer/agent/lib/repos.ts +0 -1
  307. package/templates/security-help/README.md +2 -2
  308. package/templates/security-help/agent/agent.ts +1 -2
  309. package/templates/security-help/agent/channels/slack.ts +0 -3
  310. package/templates/security-help/agent/instructions.md +9 -10
  311. package/templates/security-help/agent/skills/access-request.md +1 -1
  312. package/templates/security-help/agent/skills/faq.md +31 -0
  313. package/templates/security-help/agent/skills/security-playbooks.md +1 -1
  314. package/templates/security-help/package.json +1 -2
  315. package/templates/security-reviewer/agent/agent.ts +0 -10
  316. package/templates/triage/agent/agent.ts +0 -10
  317. package/templates/triage/agent/channels/queue.ts +1 -1
  318. package/templates/triage/agent/channels/webhook.ts +1 -3
  319. package/dist/docs/assets/chunks/@localSearchIndexroot.DU3U2Ij2.js +0 -1
  320. package/dist/docs/assets/index.md.DRakGHFe.js +0 -5
  321. package/dist/internal/deployment-scm-event-stream.d.ts +0 -116
  322. package/dist/internal/deployment-scm-event-stream.d.ts.map +0 -1
  323. package/dist/internal/deployment-scm-event-stream.js +0 -474
  324. package/dist/playground/assets/index-D9N7-q97.css +0 -1
  325. package/src/internal/deployment-scm-event-stream.ts +0 -593
  326. package/templates/security-help/agent/knowledge/faq/approvals.md +0 -5
  327. package/templates/security-help/agent/knowledge/faq/channels.md +0 -6
  328. package/templates/security-help/agent/knowledge/faq/phishing.md +0 -10
  329. package/templates/security-help/agent/skills/security-first-pass.md +0 -15
  330. /package/dist/docs/assets/{reference_skills.md.8son6Hjm.lean.js → reference_skills.md.BFW9retM.lean.js} +0 -0
  331. /package/dist/docs/assets/{templates_agentic-owners.md.DqtPdm6f.lean.js → templates_agentic-owners.md.BZSH4N9z.lean.js} +0 -0
  332. /package/dist/docs/assets/{templates_demo.md.DhFcWN6j.lean.js → templates_demo.md.BeQX9V3H.lean.js} +0 -0
@@ -0,0 +1,34 @@
1
+ # Code wiki
2
+
3
+ Keeps `wiki/` pages current after a pull request merges. Opens a
4
+ follow-up PR against that merge's base when a durable fact changed.
5
+ Skips chores. Same-base updates stack on `wiki/<base>`.
6
+
7
+ ```bash
8
+ npx @cursor/july init ./code-wiki --template code-wiki
9
+ ```
10
+
11
+ `init` asks which repos to watch. Skip the prompt with
12
+ `--var repos=owner/repo`.
13
+
14
+ ## Run
15
+
16
+ Connect GitHub in Cursor for those repos. Then sign the host in:
17
+
18
+ ```bash
19
+ agent-sdk login
20
+ agent-sdk dev
21
+ ```
22
+
23
+ Events and API calls use your Cursor GitHub connection. Replay a merged PR:
24
+
25
+ ```bash
26
+ agent-sdk github replay https://github.com/owner/repo/pull/1 --dir . --action closed
27
+ ```
28
+
29
+ ## Files
30
+
31
+ - `agent/lib/repos.ts`: watched repos
32
+ - `agent/lib/wiki.ts`: wiki path rules
33
+ - `agent/instructions.md`: what counts as a wiki update
34
+ - `evals/wiki.eval.ts`: skip and update smoke cases
@@ -0,0 +1,8 @@
1
+ import { defineAgent } from "@cursor/july";
2
+
3
+ export default defineAgent({
4
+ tools: ["read", "grep"],
5
+ local: {
6
+ sandbox: true,
7
+ },
8
+ });
@@ -0,0 +1,144 @@
1
+ import type { HostGitHubClient } from "@cursor/july";
2
+ import {
3
+ defaultGitHubAuth,
4
+ githubChannel,
5
+ } from "@cursor/july/channels/github";
6
+ import { REPOS, watches } from "../lib/repos.js";
7
+ import { WIKI_DIR, isWikiPath } from "../lib/wiki.js";
8
+
9
+ const MAX_DIFF_CHARS = 150_000;
10
+ const MAX_WIKI_PAGES = 40;
11
+ const LIST_FILES_CAP = 3000;
12
+
13
+ type Octokit = Awaited<ReturnType<HostGitHubClient["getOctokit"]>>;
14
+
15
+ export default githubChannel({
16
+ cursorAccount: { repos: REPOS, permissions: "contents-write" },
17
+ deliverReplies: false,
18
+ onComment: () => null,
19
+ onPullRequest: async (ctx, pr) => {
20
+ if (!watches(ctx.repository.fullName)) {
21
+ return null;
22
+ }
23
+ if (pr.action !== "closed" || !pr.merged) {
24
+ return null;
25
+ }
26
+ if (pr.headRef.startsWith(`${WIKI_DIR}/`)) {
27
+ return null;
28
+ }
29
+ const octokit = await ctx.github.getOctokit();
30
+ const pull = {
31
+ owner: ctx.repository.owner,
32
+ repo: ctx.repository.name,
33
+ pull_number: pr.number,
34
+ };
35
+ const listed = await octokit.paginate(octokit.rest.pulls.listFiles, {
36
+ ...pull,
37
+ per_page: 100,
38
+ });
39
+ const files = listed.map((file) => file.filename);
40
+ if (
41
+ files.length > 0 &&
42
+ files.length < LIST_FILES_CAP &&
43
+ files.every(isWikiPath)
44
+ ) {
45
+ return null;
46
+ }
47
+ return {
48
+ auth: defaultGitHubAuth(ctx),
49
+ context: [
50
+ "This pull request merged. Read pr/files.txt, pr/diff.patch, and wiki/.",
51
+ ],
52
+ async workspaceFiles() {
53
+ const [diff, wiki] = await Promise.all([
54
+ octokit.rest.pulls.get({ ...pull, mediaType: { format: "diff" } }),
55
+ loadWiki(octokit, pull.owner, pull.repo, pr.baseRef),
56
+ ]);
57
+ const text = String(diff.data);
58
+ return {
59
+ "pr/base.ref": `${pr.baseRef}\n`,
60
+ "pr/files.txt": `${files.join("\n")}\n`,
61
+ "pr/diff.patch":
62
+ text.length > MAX_DIFF_CHARS
63
+ ? `${text.slice(0, MAX_DIFF_CHARS)}\n…[truncated]\n`
64
+ : text,
65
+ ...wiki,
66
+ };
67
+ },
68
+ };
69
+ },
70
+ });
71
+
72
+ async function loadWiki(
73
+ octokit: Octokit,
74
+ owner: string,
75
+ repo: string,
76
+ ref: string
77
+ ): Promise<Record<string, string>> {
78
+ const listed = await readContents(octokit, {
79
+ owner,
80
+ repo,
81
+ path: WIKI_DIR,
82
+ ref,
83
+ });
84
+ if (!Array.isArray(listed)) {
85
+ return { "wiki/pages.txt": "" };
86
+ }
87
+ const markdown = listed.filter(
88
+ (item) => item.type === "file" && item.name.endsWith(".md")
89
+ );
90
+ const truncated = markdown.length > MAX_WIKI_PAGES;
91
+ const files = markdown.slice(0, MAX_WIKI_PAGES);
92
+ const pages: Record<string, string> = {};
93
+ await Promise.all(
94
+ files.map(async (file) => {
95
+ const body = await readContents(octokit, {
96
+ owner,
97
+ repo,
98
+ path: `${WIKI_DIR}/${file.name}`,
99
+ ref,
100
+ });
101
+ if (
102
+ body === undefined ||
103
+ Array.isArray(body) ||
104
+ body.encoding !== "base64" ||
105
+ typeof body.content !== "string"
106
+ ) {
107
+ return;
108
+ }
109
+ pages[`${WIKI_DIR}/${file.name}`] = Buffer.from(
110
+ body.content,
111
+ "base64"
112
+ ).toString("utf8");
113
+ })
114
+ );
115
+ const names = Object.keys(pages).sort();
116
+ pages["wiki/pages.txt"] = truncated
117
+ ? `${names.join("\n")}\n…[truncated]\n`
118
+ : `${names.join("\n")}\n`;
119
+ return pages;
120
+ }
121
+
122
+ async function readContents(
123
+ octokit: Octokit,
124
+ args: { owner: string; repo: string; path: string; ref: string }
125
+ ) {
126
+ try {
127
+ const { data } = await octokit.rest.repos.getContent(args);
128
+ return data;
129
+ } catch (error) {
130
+ if (isNotFound(error)) {
131
+ return undefined;
132
+ }
133
+ throw error;
134
+ }
135
+ }
136
+
137
+ function isNotFound(error: unknown): boolean {
138
+ return (
139
+ typeof error === "object" &&
140
+ error !== null &&
141
+ "status" in error &&
142
+ error.status === 404
143
+ );
144
+ }
@@ -0,0 +1,39 @@
1
+ # Code wiki
2
+
3
+ You keep the in-repo wiki current after a pull request merges.
4
+
5
+ ## Read
6
+
7
+ The workspace has `pr/files.txt`, `pr/diff.patch`, and `wiki/`.
8
+ `wiki/pages.txt` lists existing pages. Missing pages mean the wiki is
9
+ empty. Read the file list and the pages that own the change. Use the
10
+ diff only to test a fact.
11
+
12
+ ## Decide
13
+
14
+ Update only when the merge changes a durable fact someone would look
15
+ up later: how a system works, a public or operator contract, a default
16
+ or ownership change, a removed feature.
17
+
18
+ An empty wiki is not a license to document the whole repo. Create a
19
+ page only for a durable contract in this merge.
20
+
21
+ Skip lint, format, lockfiles, dependency pins, tests-only, cherry-picks,
22
+ backports, telemetry-only changes, one-off bug fixes that leave the
23
+ described behavior the same, knobs the wiki never mentioned, and facts
24
+ the matching page already states.
25
+
26
+ Do not write a changelog or a PR list.
27
+
28
+ ## Write
29
+
30
+ Call `apply_wiki` once.
31
+
32
+ - Skip: `{ verdict: "skip", reason }` with one line.
33
+ - Update: `{ verdict: "update", reason, pages }` with full page bodies.
34
+
35
+ Pages stay under `wiki/`, flat, `*.md`. Keep `_index.md` in sync when
36
+ you add a page. Each catalog line names the page and the paths it owns.
37
+ Short declarative sentences. Edit only the stale or missing facts.
38
+
39
+ Reply with `skip` or `update` and the reason.
@@ -0,0 +1,5 @@
1
+ export const REPOS: readonly string[] = ["owner/repo"];
2
+
3
+ export function watches(fullName: string): boolean {
4
+ return REPOS.some((repo) => repo.toLowerCase() === fullName.toLowerCase());
5
+ }
@@ -0,0 +1,22 @@
1
+ export const WIKI_DIR = "wiki";
2
+
3
+ const PAGE = /^[A-Za-z0-9._-]+\.md$/;
4
+
5
+ export function isWikiPath(path: string): boolean {
6
+ return path === WIKI_DIR || path.startsWith(`${WIKI_DIR}/`);
7
+ }
8
+
9
+ export function wikiPagePath(raw: string): string | undefined {
10
+ const path = raw.replace(/^\/+/, "");
11
+ if (path.includes("..") || path.includes("\\")) {
12
+ return undefined;
13
+ }
14
+ if (!path.startsWith(`${WIKI_DIR}/`) || !path.endsWith(".md")) {
15
+ return undefined;
16
+ }
17
+ const name = path.slice(WIKI_DIR.length + 1);
18
+ if (!PAGE.test(name)) {
19
+ return undefined;
20
+ }
21
+ return `${WIKI_DIR}/${name}`;
22
+ }
@@ -0,0 +1,219 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import type { HostGitHubClient } from "@cursor/july";
4
+ import { parseGitHubPrContinuationKey } from "@cursor/july/channels/github";
5
+ import { defineTool } from "@cursor/july/tools";
6
+ import { z } from "zod";
7
+ import { wikiPagePath } from "../lib/wiki.js";
8
+
9
+ const page = z.object({
10
+ path: z.string().min(1).max(160),
11
+ content: z.string().min(1).max(32_000),
12
+ });
13
+
14
+ type Page = z.infer<typeof page>;
15
+ type Octokit = Awaited<ReturnType<HostGitHubClient["getOctokit"]>>;
16
+
17
+ type Write = {
18
+ octokit: Octokit;
19
+ owner: string;
20
+ repo: string;
21
+ number: number;
22
+ label: string;
23
+ reason: string;
24
+ pages: Page[];
25
+ base: string;
26
+ branch: string;
27
+ };
28
+
29
+ export default defineTool({
30
+ description:
31
+ "Skip or open a wiki follow-up PR for this merged pull request. Call once.",
32
+ inputSchema: z.discriminatedUnion("verdict", [
33
+ z.object({
34
+ verdict: z.literal("skip"),
35
+ reason: z.string().min(1).max(280),
36
+ }),
37
+ z.object({
38
+ verdict: z.literal("update"),
39
+ reason: z.string().min(1).max(280),
40
+ pages: z.array(page).min(1).max(8),
41
+ }),
42
+ ]),
43
+ async execute(input, ctx) {
44
+ if (ctx.session.purpose === "eval") {
45
+ return { posted: false, reason: "eval", verdict: input.verdict };
46
+ }
47
+ if (input.verdict === "skip") {
48
+ return { posted: false, reason: input.reason, verdict: "skip" };
49
+ }
50
+ const ref = parseGitHubPrContinuationKey(ctx.session.continuationKey ?? "");
51
+ if (ref === undefined) {
52
+ throw new Error("apply_wiki requires a GitHub pull request session");
53
+ }
54
+ const base = (
55
+ await readFile(join(ctx.workspaceDir, "pr/base.ref"), "utf8")
56
+ ).trim();
57
+ const branch = wikiUpdateBranch(base);
58
+ if (branch === undefined) {
59
+ throw new Error("missing pr/base.ref");
60
+ }
61
+ const pages = input.pages.map((item) => {
62
+ const path = wikiPagePath(item.path);
63
+ if (path === undefined) {
64
+ throw new Error(`invalid wiki path: ${item.path}`);
65
+ }
66
+ return { path, content: item.content };
67
+ });
68
+ return openWikiPr({
69
+ octokit: await ctx.host.github.getOctokit(),
70
+ owner: ref.owner,
71
+ repo: ref.repo,
72
+ number: ref.number,
73
+ label: `${ref.owner}/${ref.repo}#${ref.number}`,
74
+ reason: input.reason,
75
+ pages,
76
+ base,
77
+ branch,
78
+ });
79
+ },
80
+ });
81
+
82
+ function wikiUpdateBranch(base: string): string | undefined {
83
+ if (base === "" || !/^[A-Za-z0-9._/-]+$/.test(base)) {
84
+ return undefined;
85
+ }
86
+ return `wiki/${base.replaceAll("/", "-")}`;
87
+ }
88
+
89
+ async function openWikiPr(input: Write) {
90
+ const repo = { owner: input.owner, repo: input.repo };
91
+ const existing = await input.octokit.rest.pulls.list({
92
+ ...repo,
93
+ state: "open",
94
+ head: `${input.owner}:${input.branch}`,
95
+ base: input.base,
96
+ per_page: 1,
97
+ });
98
+ const open = existing.data[0];
99
+ if (open !== undefined && citesSource(open.body, input.number)) {
100
+ return {
101
+ posted: false,
102
+ reason: "exists",
103
+ verdict: "update",
104
+ pr: input.label,
105
+ url: open.html_url,
106
+ };
107
+ }
108
+ const branchSha = await refSha(input.octokit, repo, input.branch);
109
+ const parent =
110
+ branchSha ?? (await refSha(input.octokit, repo, input.base));
111
+ if (parent === undefined) {
112
+ throw new Error(`missing base ref: ${input.base}`);
113
+ }
114
+ const { data: commit } = await input.octokit.rest.git.getCommit({
115
+ ...repo,
116
+ commit_sha: parent,
117
+ });
118
+ const blobs = await Promise.all(
119
+ input.pages.map(async (item) => {
120
+ const { data } = await input.octokit.rest.git.createBlob({
121
+ ...repo,
122
+ content: Buffer.from(item.content).toString("base64"),
123
+ encoding: "base64",
124
+ });
125
+ return {
126
+ path: item.path,
127
+ mode: "100644" as const,
128
+ type: "blob" as const,
129
+ sha: data.sha,
130
+ };
131
+ })
132
+ );
133
+ const { data: tree } = await input.octokit.rest.git.createTree({
134
+ ...repo,
135
+ base_tree: commit.tree.sha,
136
+ tree: blobs,
137
+ });
138
+ const { data: next } = await input.octokit.rest.git.createCommit({
139
+ ...repo,
140
+ message: `wiki: ${input.reason}`,
141
+ tree: tree.sha,
142
+ parents: [parent],
143
+ });
144
+ if (branchSha === undefined) {
145
+ await input.octokit.rest.git.createRef({
146
+ ...repo,
147
+ ref: `refs/heads/${input.branch}`,
148
+ sha: next.sha,
149
+ });
150
+ } else {
151
+ await input.octokit.rest.git.updateRef({
152
+ ...repo,
153
+ ref: `heads/${input.branch}`,
154
+ sha: next.sha,
155
+ });
156
+ }
157
+ if (open !== undefined) {
158
+ await input.octokit.rest.pulls.update({
159
+ ...repo,
160
+ pull_number: open.number,
161
+ body: appendSource(open.body ?? "", input.reason, input.number),
162
+ });
163
+ return {
164
+ posted: true,
165
+ verdict: "update",
166
+ pr: input.label,
167
+ url: open.html_url,
168
+ };
169
+ }
170
+ const { data: pull } = await input.octokit.rest.pulls.create({
171
+ ...repo,
172
+ title: `wiki: update from #${input.number}`,
173
+ head: input.branch,
174
+ base: input.base,
175
+ body: `${input.reason}\n\nSource: #${input.number}`,
176
+ });
177
+ return {
178
+ posted: true,
179
+ verdict: "update",
180
+ pr: input.label,
181
+ url: pull.html_url,
182
+ };
183
+ }
184
+
185
+ async function refSha(
186
+ octokit: Octokit,
187
+ repo: { owner: string; repo: string },
188
+ name: string
189
+ ): Promise<string | undefined> {
190
+ try {
191
+ const { data } = await octokit.rest.git.getRef({
192
+ ...repo,
193
+ ref: `heads/${name}`,
194
+ });
195
+ return data.object.sha;
196
+ } catch (error) {
197
+ if (isNotFound(error)) {
198
+ return undefined;
199
+ }
200
+ throw error;
201
+ }
202
+ }
203
+
204
+ function citesSource(body: string | null | undefined, number: number): boolean {
205
+ return new RegExp(`(?:^|\\n)Source:.*#${number}(?:\\s|$)`).test(body ?? "");
206
+ }
207
+
208
+ function appendSource(body: string, reason: string, number: number): string {
209
+ return `${body.trim()}\n\n${reason}\nSource: #${number}`;
210
+ }
211
+
212
+ function isNotFound(error: unknown): boolean {
213
+ return (
214
+ typeof error === "object" &&
215
+ error !== null &&
216
+ "status" in error &&
217
+ error.status === 404
218
+ );
219
+ }
@@ -0,0 +1,5 @@
1
+ import { defineEvalConfig } from "@cursor/july/evals";
2
+
3
+ export default defineEvalConfig({
4
+ maxConcurrency: 10,
5
+ });
@@ -0,0 +1,132 @@
1
+ import { defineEval } from "@cursor/july/evals";
2
+
3
+ function merged(title: string): string {
4
+ return [
5
+ "GitHub pull request trigger: acme/api#12",
6
+ "Action: closed",
7
+ "PR: https://github.com/acme/api/pull/12",
8
+ `Title: ${title}`,
9
+ "Head: feat/change (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)",
10
+ "Base: main",
11
+ "Author: sam",
12
+ "",
13
+ "This pull request merged. Read pr/files.txt, pr/diff.patch, and wiki/.",
14
+ ].join("\n");
15
+ }
16
+
17
+ const INDEX = [
18
+ "# Wiki",
19
+ "",
20
+ "- [Billing](billing.md): usage events posted to the warehouse",
21
+ "- [App](app.md): HTTP handlers and UI chrome",
22
+ "",
23
+ ].join("\n");
24
+
25
+ const BILLING = [
26
+ "# Billing",
27
+ "",
28
+ "Usage events are protobuf messages in `proto/billing.proto`.",
29
+ "Each event has `account_id` and `amount_cents`.",
30
+ "",
31
+ ].join("\n");
32
+
33
+ const APP = [
34
+ "# App",
35
+ "",
36
+ "The sidebar opener is a querySelector on `.opener`.",
37
+ "",
38
+ ].join("\n");
39
+
40
+ export default defineEval({
41
+ tags: ["smoke"],
42
+ cases: [
43
+ {
44
+ id: "skip-lint",
45
+ description: "A quote-style lint fix does not open a wiki PR.",
46
+ async test(t) {
47
+ await t.send(merged("Fix sidebar opener lint failure"), {
48
+ workspaceFiles: {
49
+ "pr/files.txt": "src/sidebar.ts\n",
50
+ "pr/diff.patch": [
51
+ "diff --git a/src/sidebar.ts b/src/sidebar.ts",
52
+ "-const opener = document.querySelector('.opener')",
53
+ '+const opener = document.querySelector(".opener");',
54
+ ].join("\n"),
55
+ "wiki/pages.txt": "wiki/_index.md\nwiki/app.md\n",
56
+ "wiki/_index.md": INDEX,
57
+ "wiki/app.md": APP,
58
+ },
59
+ });
60
+ t.succeeded();
61
+ t.calledTool("apply_wiki", { input: { verdict: "skip" } });
62
+ },
63
+ },
64
+ {
65
+ id: "update-contract",
66
+ description: "New billing proto fields update the billing page.",
67
+ async test(t) {
68
+ await t.send(merged("Add unified fields to billing events"), {
69
+ workspaceFiles: {
70
+ "pr/files.txt": "proto/billing.proto\n",
71
+ "pr/diff.patch": [
72
+ "diff --git a/proto/billing.proto b/proto/billing.proto",
73
+ " message UsageEvent {",
74
+ " string account_id = 1;",
75
+ " int64 amount_cents = 2;",
76
+ "+ string usage_unit = 12;",
77
+ "+ string workspace_id = 13;",
78
+ " }",
79
+ ].join("\n"),
80
+ "wiki/pages.txt": "wiki/_index.md\nwiki/billing.md\n",
81
+ "wiki/_index.md": INDEX,
82
+ "wiki/billing.md": BILLING,
83
+ },
84
+ });
85
+ t.succeeded();
86
+ t.calledTool("apply_wiki", { input: { verdict: "update" } });
87
+ },
88
+ },
89
+ {
90
+ id: "skip-docs",
91
+ description: "A markdown-only merge does not open a wiki PR.",
92
+ async test(t) {
93
+ await t.send(merged("Document factory delete in servicetests"), {
94
+ workspaceFiles: {
95
+ "pr/files.txt": "backend/server/src/factory/README.md\n",
96
+ "pr/diff.patch": [
97
+ "diff --git a/backend/server/src/factory/README.md b/backend/server/src/factory/README.md",
98
+ "+Drive environment delete from markdown servicetests.",
99
+ ].join("\n"),
100
+ "wiki/pages.txt": "wiki/_index.md\n",
101
+ "wiki/_index.md": INDEX,
102
+ },
103
+ });
104
+ t.succeeded();
105
+ t.calledTool("apply_wiki", { input: { verdict: "skip" } });
106
+ },
107
+ },
108
+ {
109
+ id: "skip-cherry-pick",
110
+ description: "A release-train cherry-pick does not open a wiki PR.",
111
+ async test(t) {
112
+ await t.send(
113
+ merged("[CP releases/3.19] Stop stale Project corner loaders"),
114
+ {
115
+ workspaceFiles: {
116
+ "pr/files.txt": "src/projects.ts\n",
117
+ "pr/diff.patch": [
118
+ "diff --git a/src/projects.ts b/src/projects.ts",
119
+ "+if (status.seq < last.seq) return;",
120
+ ].join("\n"),
121
+ "wiki/pages.txt": "wiki/_index.md\nwiki/app.md\n",
122
+ "wiki/_index.md": INDEX,
123
+ "wiki/app.md": APP,
124
+ },
125
+ }
126
+ );
127
+ t.succeeded();
128
+ t.calledTool("apply_wiki", { input: { verdict: "skip" } });
129
+ },
130
+ },
131
+ ],
132
+ });
@@ -0,0 +1,25 @@
1
+ {
2
+ "questions": [
3
+ {
4
+ "id": "repos",
5
+ "prompt": "Which GitHub repos should this agent watch for merges?",
6
+ "hint": "Comma-separated owner/repo. One GitHub owner.",
7
+ "placeholder": "acme/api, acme/web",
8
+ "parse": "owner-repo-list"
9
+ }
10
+ ],
11
+ "replace": [
12
+ {
13
+ "file": "agent/lib/repos.ts",
14
+ "find": "[\"owner/repo\"]",
15
+ "answer": "repos",
16
+ "as": "json-array"
17
+ },
18
+ {
19
+ "file": "README.md",
20
+ "find": "owner/repo",
21
+ "answer": "repos",
22
+ "as": "first"
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "code-wiki",
3
+ "private": true,
4
+ "type": "module",
5
+ "description": "Keeps an in-repo wiki current after pull requests merge.",
6
+ "scripts": {
7
+ "check": "tsc --noEmit",
8
+ "dev": "agent-sdk dev"
9
+ },
10
+ "dependencies": {
11
+ "@cursor/july": "latest",
12
+ "zod": "^3.25.0"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^22.14.0",
16
+ "typescript": "^5.8.0"
17
+ }
18
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "noEmit": true,
8
+ "skipLibCheck": true,
9
+ "types": ["node"]
10
+ },
11
+ "include": ["agent/**/*", "evals/**/*"]
12
+ }
@@ -1,18 +1,8 @@
1
- import { homedir } from "node:os";
2
- import { join } from "node:path";
3
1
  import { defineAgent } from "@cursor/july";
4
2
 
5
3
  export default defineAgent({
6
- model: {
7
- id: "grok-4.5",
8
- params: [
9
- { id: "effort", value: "high" },
10
- { id: "fast", value: "true" },
11
- ],
12
- },
13
4
  tools: ["read", "grep"],
14
5
  local: {
15
6
  sandbox: true,
16
- cwd: join(homedir(), ".cache", "agent-serve", "demo"),
17
7
  },
18
8
  });