@cursor/july 0.1.68 → 0.1.74

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 (252) hide show
  1. package/AGENTS.md +17 -13
  2. package/README.md +23 -11
  3. package/dist/bin/agent-serve.js +10 -7
  4. package/dist/channels/github/api.d.ts +2 -0
  5. package/dist/channels/github/api.d.ts.map +1 -1
  6. package/dist/channels/github/api.js +2 -1
  7. package/dist/channels/github/binding.d.ts +7 -0
  8. package/dist/channels/github/binding.d.ts.map +1 -1
  9. package/dist/channels/github/binding.js +4 -0
  10. package/dist/channels/github/checks.d.ts +99 -0
  11. package/dist/channels/github/checks.d.ts.map +1 -0
  12. package/dist/channels/github/checks.js +108 -0
  13. package/dist/channels/github/cursor-account.d.ts +4 -4
  14. package/dist/channels/github/cursor-account.d.ts.map +1 -1
  15. package/dist/channels/github/cursor-account.js +7 -5
  16. package/dist/channels/github/index.d.ts +1 -0
  17. package/dist/channels/github/index.d.ts.map +1 -1
  18. package/dist/channels/github/index.js +1 -0
  19. package/dist/channels/github/types.d.ts +8 -0
  20. package/dist/channels/github/types.d.ts.map +1 -1
  21. package/dist/channels/slack/manifest.d.ts +2 -2
  22. package/dist/channels/slack/manifest.d.ts.map +1 -1
  23. package/dist/channels/slack/manifest.js +13 -11
  24. package/dist/channels/slack/types.d.ts +2 -2
  25. package/dist/channels/slack/types.d.ts.map +1 -1
  26. package/dist/connections.d.ts +17 -5
  27. package/dist/connections.d.ts.map +1 -1
  28. package/dist/connections.js +17 -5
  29. package/dist/docs/404.html +2 -2
  30. package/dist/docs/ab.html +3 -3
  31. package/dist/docs/assets/{app.C5XUTCw9.js → app.BETd-WqU.js} +1 -1
  32. package/dist/docs/assets/chunks/@localSearchIndexroot.DM5INS71.js +1 -0
  33. package/dist/docs/assets/chunks/{VPLocalSearchBox.CGDTAYHY.js → VPLocalSearchBox.wEaGEmV9.js} +1 -1
  34. package/dist/docs/assets/chunks/{theme.lPixh250.js → theme.DNDicFOP.js} +2 -2
  35. package/dist/docs/assets/{concepts.md.CqOsxbMU.js → concepts.md.BXAm6G-C.js} +1 -1
  36. package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.js → guides_mcp-oauth.md.CzEB6RaG.js} +1 -1
  37. package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.js → reference_agent-config.md.BZnEKfEc.js} +3 -4
  38. package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.lean.js → reference_agent-config.md.BZnEKfEc.lean.js} +1 -1
  39. package/dist/docs/assets/{reference_cli.md.Cl14Jfo3.js → reference_cli.md.TAaYU8br.js} +3 -3
  40. package/dist/docs/assets/{reference_cli.md.Cl14Jfo3.lean.js → reference_cli.md.TAaYU8br.lean.js} +1 -1
  41. package/dist/docs/assets/{reference_connections.md.Bwswbm6H.js → reference_connections.md.Cu3N-S3Q.js} +18 -11
  42. package/dist/docs/assets/{reference_connections.md.Bwswbm6H.lean.js → reference_connections.md.Cu3N-S3Q.lean.js} +1 -1
  43. package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.js → reference_sessions.md.B0DdlM-K.js} +1 -1
  44. package/dist/docs/assets/{reference_tools.md.Wmvb7Lob.js → reference_tools.md.DTg_kEsx.js} +1 -1
  45. package/dist/docs/assets/scaffolding-agents.md.CiGsJ1aw.js +1 -0
  46. package/dist/docs/assets/{scaffolding-agents.md.CrWSA0Ko.lean.js → scaffolding-agents.md.CiGsJ1aw.lean.js} +1 -1
  47. package/dist/docs/assets/troubleshooting.md.DQ-hYuZT.js +1 -0
  48. package/dist/docs/building-with-agents.html +3 -3
  49. package/dist/docs/concepts.html +5 -5
  50. package/dist/docs/deployment.html +3 -3
  51. package/dist/docs/evals.html +3 -3
  52. package/dist/docs/example-agents/approval-buddy.html +3 -3
  53. package/dist/docs/example-agents/benny.html +3 -3
  54. package/dist/docs/example-agents/bugbot.html +3 -3
  55. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  56. package/dist/docs/example-agents/codeowners-review.html +3 -3
  57. package/dist/docs/example-agents/concierge.html +3 -3
  58. package/dist/docs/example-agents/fsd.html +3 -3
  59. package/dist/docs/example-agents/index.html +3 -3
  60. package/dist/docs/example-agents/knowledge-base.html +3 -3
  61. package/dist/docs/example-agents/oncall.html +3 -3
  62. package/dist/docs/example-agents/security-reviewer.html +3 -3
  63. package/dist/docs/example-agents/slack-agent.html +3 -3
  64. package/dist/docs/example-agents/weather-agent.html +3 -3
  65. package/dist/docs/guides/agent-to-agent.html +3 -3
  66. package/dist/docs/guides/cloud-runtime.html +3 -3
  67. package/dist/docs/guides/convert-automation.html +3 -3
  68. package/dist/docs/guides/github.html +3 -3
  69. package/dist/docs/guides/human-in-the-loop.html +3 -3
  70. package/dist/docs/guides/mcp-oauth.html +5 -5
  71. package/dist/docs/guides/opentelemetry.html +3 -3
  72. package/dist/docs/guides/slack.html +3 -3
  73. package/dist/docs/guides/webhooks.html +3 -3
  74. package/dist/docs/hashmap.json +1 -1
  75. package/dist/docs/hillclimbing.html +3 -3
  76. package/dist/docs/index.html +3 -3
  77. package/dist/docs/quickstart.html +3 -3
  78. package/dist/docs/reference/agent-config.html +5 -6
  79. package/dist/docs/reference/artifacts.html +3 -3
  80. package/dist/docs/reference/channels.html +3 -3
  81. package/dist/docs/reference/cli.html +6 -6
  82. package/dist/docs/reference/connections.html +20 -13
  83. package/dist/docs/reference/hooks.html +3 -3
  84. package/dist/docs/reference/http-api.html +3 -3
  85. package/dist/docs/reference/instructions.html +3 -3
  86. package/dist/docs/reference/playground.html +3 -3
  87. package/dist/docs/reference/project-layout.html +3 -3
  88. package/dist/docs/reference/prompt.html +3 -3
  89. package/dist/docs/reference/schedules.html +3 -3
  90. package/dist/docs/reference/sessions.html +5 -5
  91. package/dist/docs/reference/skills.html +3 -3
  92. package/dist/docs/reference/subagents.html +3 -3
  93. package/dist/docs/reference/tools.html +5 -5
  94. package/dist/docs/scaffolding-agents.html +5 -5
  95. package/dist/docs/storage.html +3 -3
  96. package/dist/docs/templates/agentic-owners.html +3 -3
  97. package/dist/docs/templates/demo.html +3 -3
  98. package/dist/docs/templates/pr-autofixer.html +3 -3
  99. package/dist/docs/templates/security-reviewer.html +3 -3
  100. package/dist/docs/templates/triage.html +3 -3
  101. package/dist/docs/troubleshooting.html +5 -5
  102. package/dist/internal/advertise-tools.d.ts +11 -6
  103. package/dist/internal/advertise-tools.d.ts.map +1 -1
  104. package/dist/internal/advertise-tools.js +63 -30
  105. package/dist/internal/cli-deploy.d.ts.map +1 -1
  106. package/dist/internal/cli-deploy.js +2 -4
  107. package/dist/internal/cli-skills.d.ts +4 -2
  108. package/dist/internal/cli-skills.d.ts.map +1 -1
  109. package/dist/internal/cli-skills.js +8 -3
  110. package/dist/internal/convert-automation/convert-workflow.d.ts.map +1 -1
  111. package/dist/internal/convert-automation/convert-workflow.js +2 -10
  112. package/dist/internal/cursor/account-mcp.d.ts +29 -3
  113. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  114. package/dist/internal/cursor/account-mcp.js +147 -67
  115. package/dist/internal/cursor/backend-client.d.ts +11 -6
  116. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  117. package/dist/internal/cursor/backend-client.js +32 -10
  118. package/dist/internal/cursor-account-mcp-auth.d.ts +11 -0
  119. package/dist/internal/cursor-account-mcp-auth.d.ts.map +1 -1
  120. package/dist/internal/cursor-account-mcp-auth.js +69 -0
  121. package/dist/internal/deploy-client.d.ts +0 -7
  122. package/dist/internal/deploy-client.d.ts.map +1 -1
  123. package/dist/internal/deploy-client.js +2 -4
  124. package/dist/internal/deploy-manifest.d.ts +15 -24
  125. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  126. package/dist/internal/deploy-manifest.js +38 -27
  127. package/dist/internal/deployment-scm-event-stream.d.ts +4 -1
  128. package/dist/internal/deployment-scm-event-stream.d.ts.map +1 -1
  129. package/dist/internal/deployment-scm-event-stream.js +15 -1
  130. package/dist/internal/discovery.d.ts.map +1 -1
  131. package/dist/internal/discovery.js +42 -10
  132. package/dist/internal/init-project.d.ts.map +1 -1
  133. package/dist/internal/init-project.js +7 -106
  134. package/dist/internal/init-scaffold.d.ts +8 -0
  135. package/dist/internal/init-scaffold.d.ts.map +1 -0
  136. package/dist/internal/init-scaffold.js +168 -0
  137. package/dist/internal/inline-stdio-mcp.d.ts +2 -0
  138. package/dist/internal/inline-stdio-mcp.d.ts.map +1 -1
  139. package/dist/internal/inline-stdio-mcp.js +10 -8
  140. package/dist/internal/install-cursor-skills.d.ts +71 -16
  141. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  142. package/dist/internal/install-cursor-skills.js +160 -48
  143. package/dist/internal/json-schema.d.ts +7 -0
  144. package/dist/internal/json-schema.d.ts.map +1 -1
  145. package/dist/internal/json-schema.js +18 -3
  146. package/dist/internal/mcp-endpoint.js +7 -7
  147. package/dist/internal/mcp-host.js +4 -2
  148. package/dist/internal/mcp-oauth.d.ts +22 -0
  149. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  150. package/dist/internal/mcp-oauth.js +40 -1
  151. package/dist/internal/package-inline-stdio.d.ts.map +1 -1
  152. package/dist/internal/package-inline-stdio.js +5 -5
  153. package/dist/internal/review-comments.d.ts +97 -0
  154. package/dist/internal/review-comments.d.ts.map +1 -1
  155. package/dist/internal/review-comments.js +151 -0
  156. package/dist/internal/sanitize-mcp-tool-name.d.ts +20 -0
  157. package/dist/internal/sanitize-mcp-tool-name.d.ts.map +1 -0
  158. package/dist/internal/sanitize-mcp-tool-name.js +30 -0
  159. package/dist/internal/sdk-runner.d.ts.map +1 -1
  160. package/dist/internal/sdk-runner.js +6 -2
  161. package/dist/internal/session-engine.d.ts.map +1 -1
  162. package/dist/internal/session-engine.js +4 -6
  163. package/dist/internal/shallow-clone.d.ts +94 -39
  164. package/dist/internal/shallow-clone.d.ts.map +1 -1
  165. package/dist/internal/shallow-clone.js +188 -68
  166. package/dist/internal/terminal-style.d.ts +18 -0
  167. package/dist/internal/terminal-style.d.ts.map +1 -1
  168. package/dist/internal/terminal-style.js +46 -1
  169. package/dist/internal/workspace.d.ts +2 -0
  170. package/dist/internal/workspace.d.ts.map +1 -1
  171. package/dist/internal/workspace.js +5 -0
  172. package/dist/playground/assets/index-D_8I9TM0.js +85 -0
  173. package/dist/playground/assets/index-M3nSMc6_.css +1 -0
  174. package/dist/playground/index.html +2 -2
  175. package/dist/tools.d.ts +7 -0
  176. package/dist/tools.d.ts.map +1 -1
  177. package/dist/types.d.ts +28 -3
  178. package/dist/types.d.ts.map +1 -1
  179. package/docs/concepts.md +4 -4
  180. package/docs/guides/mcp-oauth.md +3 -1
  181. package/docs/reference/agent-config.md +11 -12
  182. package/docs/reference/cli.md +16 -8
  183. package/docs/reference/connections.md +44 -26
  184. package/docs/reference/sessions.md +2 -2
  185. package/docs/reference/tools.md +1 -1
  186. package/docs/scaffolding-agents.md +14 -6
  187. package/docs/troubleshooting.md +3 -2
  188. package/package.json +6 -1
  189. package/scripts/install-cursor-skills.mjs +36 -0
  190. package/skills/ab/SKILL.md +1 -1
  191. package/skills/create-agent/SKILL.md +13 -10
  192. package/skills/debug/SKILL.md +3 -2
  193. package/skills/evals/SKILL.md +1 -1
  194. package/skills/framework-map/SKILL.md +7 -7
  195. package/skills/github/SKILL.md +1 -1
  196. package/skills/hillclimb/SKILL.md +1 -1
  197. package/skills/mcp-auth/SKILL.md +9 -7
  198. package/skills/otel/SKILL.md +1 -1
  199. package/skills/setup-slack/SKILL.md +1 -1
  200. package/src/bin/agent-serve.ts +10 -7
  201. package/src/channels/github/api.ts +6 -1
  202. package/src/channels/github/binding.ts +21 -0
  203. package/src/channels/github/checks.ts +179 -0
  204. package/src/channels/github/cursor-account.ts +9 -6
  205. package/src/channels/github/index.ts +1 -0
  206. package/src/channels/github/types.ts +8 -0
  207. package/src/channels/slack/manifest.ts +8 -10
  208. package/src/channels/slack/types.ts +2 -2
  209. package/src/connections.ts +17 -5
  210. package/src/internal/advertise-tools.ts +72 -23
  211. package/src/internal/cli-deploy.ts +4 -15
  212. package/src/internal/cli-skills.ts +10 -2
  213. package/src/internal/convert-automation/convert-workflow.ts +2 -11
  214. package/src/internal/cursor/account-mcp.ts +208 -73
  215. package/src/internal/cursor/backend-client.ts +45 -11
  216. package/src/internal/cursor-account-mcp-auth.ts +83 -0
  217. package/src/internal/deploy-client.ts +0 -10
  218. package/src/internal/deploy-manifest.ts +33 -39
  219. package/src/internal/deployment-scm-event-stream.ts +17 -1
  220. package/src/internal/discovery.ts +47 -3
  221. package/src/internal/init-project.ts +7 -133
  222. package/src/internal/init-scaffold.ts +176 -0
  223. package/src/internal/inline-stdio-mcp.ts +13 -0
  224. package/src/internal/install-cursor-skills.ts +204 -49
  225. package/src/internal/json-schema.ts +24 -3
  226. package/src/internal/mcp-endpoint.ts +6 -0
  227. package/src/internal/mcp-host.ts +4 -0
  228. package/src/internal/mcp-oauth.ts +55 -1
  229. package/src/internal/package-inline-stdio.ts +5 -1
  230. package/src/internal/review-comments.ts +245 -0
  231. package/src/internal/sanitize-mcp-tool-name.ts +33 -0
  232. package/src/internal/sdk-runner.ts +6 -3
  233. package/src/internal/session-engine.ts +7 -0
  234. package/src/internal/shallow-clone.ts +293 -105
  235. package/src/internal/terminal-style.ts +67 -1
  236. package/src/internal/workspace.ts +6 -0
  237. package/src/tools.ts +7 -0
  238. package/src/types.ts +32 -4
  239. package/templates/agentic-owners/agent/agent.ts +3 -0
  240. package/templates/demo/agent/agent.ts +3 -0
  241. package/templates/security-reviewer/agent/agent.ts +3 -0
  242. package/templates/triage/agent/agent.ts +3 -0
  243. package/dist/docs/assets/chunks/@localSearchIndexroot.DvUR3lv9.js +0 -1
  244. package/dist/docs/assets/scaffolding-agents.md.CrWSA0Ko.js +0 -1
  245. package/dist/docs/assets/troubleshooting.md.CuVztCKs.js +0 -1
  246. package/dist/playground/assets/index-CoL7xCJl.css +0 -1
  247. package/dist/playground/assets/index-yxs1heea.js +0 -85
  248. /package/dist/docs/assets/{concepts.md.CqOsxbMU.lean.js → concepts.md.BXAm6G-C.lean.js} +0 -0
  249. /package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.lean.js → guides_mcp-oauth.md.CzEB6RaG.lean.js} +0 -0
  250. /package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.lean.js → reference_sessions.md.B0DdlM-K.lean.js} +0 -0
  251. /package/dist/docs/assets/{reference_tools.md.Wmvb7Lob.lean.js → reference_tools.md.DTg_kEsx.lean.js} +0 -0
  252. /package/dist/docs/assets/{troubleshooting.md.CuVztCKs.lean.js → troubleshooting.md.DQ-hYuZT.lean.js} +0 -0
@@ -16,13 +16,21 @@ into a small working project. Have Cursor read that file and follow it.
16
16
 
17
17
  Where to find the file depends on how you got the package:
18
18
 
19
- - Reading these docs on a hosted site? Run `agent-sdk install-skills`
20
- to copy every package skill into `~/.cursor/skills/agentkit/`, where
21
- Cursor discovers them by name.
22
- - Installed `@cursor/july` as a dependency? The skill ships inside the
23
- package at `node_modules/@cursor/july/skills/create-agent/SKILL.md`.
19
+ - Installing `@cursor/july` (`npm install`, `npx @cursor/july`, a
20
+ version bump) copies every package skill into
21
+ `~/.cursor/skills/agentsdk/` with `alwaysApply: true`, so Cursor
22
+ injects the skill body into context instead of waiting for the
23
+ model to pick it from the catalog. The `/` menu lists them as
24
+ `/agentsdk-create-agent`, `/agentsdk-hillclimb`, and the rest. Re-installing overwrites those
25
+ copies with the package version. Set
26
+ `CURSOR_JULY_SKIP_SKILL_INSTALL=1` to skip the copy.
27
+ - Installed `@cursor/july` as a dependency? The skill also ships inside
28
+ the package at `node_modules/@cursor/july/skills/create-agent/SKILL.md`.
24
29
  - Working in the monorepo? It's at
25
- `packages/agent-serve/skills/create-agent/SKILL.md`.
30
+ `packages/agent-serve/skills/create-agent/SKILL.md`. Run
31
+ `agent-sdk install-skills` if you want the same copies in
32
+ `~/.cursor/skills/agentsdk/` (the package postinstall skips the
33
+ source checkout).
26
34
 
27
35
  Cursor will:
28
36
 
@@ -31,7 +31,8 @@ Match your symptom below. Keep the commands as `agent-sdk`; see
31
31
  | --- | --- |
32
32
  | Built-in file reads and greps fail; the turn retries for a long time | Run under Node 22.13+ (or `tsx`), never Bun. Look for `NGHTTP2_FRAME_SIZE_ERROR` in logs. |
33
33
  | The turn fails immediately with an API-key error | Sign in with `agent-sdk login`, or set `CURSOR_API_KEY`. Discovery, `info`, `call`, and serve bring-up work without a key; model turns need one. |
34
- | Replies quote rules or `AGENTS.md` from outside your agent project | The session workspace inherited parent-folder config. Point `defineAgent({ local: { cwd } })` outside that tree, or set `--state-root` to a clean directory (for example under `/tmp`). |
34
+ | Replies quote rules or `AGENTS.md` from outside your agent project | The session workspace inherited parent-folder config. Nested git checkouts default `local.cwd` to `~/.cache/agent-serve/<dir>`. Point `defineAgent({ local: { cwd } })` at a checkout only when the agent should inherit that tree, or set `--state-root` to a clean directory (for example under `/tmp`). |
35
+ | Yellow box shows Datadog/Linear tools, but the model lists `GetDynamicTools` / IDE `cursor` tools and never calls them | Attached MCP sits behind harness meta-tools, or `hostOnly` hid the connection, or the harness cwd is still inside another checkout. Set `advertiseTools: true` for named tools on local turns. Check `GET /v1/info` `local.cwd` and `connections[].advertiseTools`. |
35
36
  | Server tools, skills, or workspace seed files never appear | The agent runtime is `cloud`. Those features apply on the local runtime. `validate` warns when this combination is present. |
36
37
  | `validate` and `run` succeed, but typecheck fails in CI | The CLI runs TypeScript with type-stripping only. Keep tool `execute` return types as object literals or `type` aliases, not `interface` types. |
37
38
  | Login works, but turns are rejected when using custom API hosts | Point login and model traffic at the same host (`CURSOR_API_BASE_URL` and `CURSOR_BACKEND_URL`). A key from one host is rejected by the other. |
@@ -70,7 +71,7 @@ Match your symptom below. Keep the commands as `agent-sdk`; see
70
71
  | --- | --- |
71
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`. |
72
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
- | Model asks for `mcp_auth` or IDE MCP for a privileged server | That connection is likely `hostOnly`. Call it from a host tool via `ctx.host.mcp`, and update instructions. |
74
+ | Model asks for `mcp_auth` or IDE MCP for a privileged server | That connection is `hostOnly`. Call it from a host tool via `ctx.host.mcp`, and update instructions. |
74
75
 
75
76
  See [Host MCP OAuth](./guides/mcp-oauth.md) and
76
77
  [`skills/mcp-auth/SKILL.md`](../skills/mcp-auth/SKILL.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.68",
3
+ "version": "0.1.74",
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": {
@@ -34,6 +34,7 @@
34
34
  "templates/**/*",
35
35
  "docs/**/*.md",
36
36
  "!docs/.cursor/**",
37
+ "scripts/install-cursor-skills.mjs",
37
38
  "package.json",
38
39
  "LICENSE.md",
39
40
  "README.md",
@@ -150,18 +151,21 @@
150
151
  },
151
152
  "./kv": {
152
153
  "anysphere-source": "./src/kv.ts",
154
+ "bun": "./dist/kv.js",
153
155
  "types": "./dist/kv.d.ts",
154
156
  "import": "./dist/kv.js",
155
157
  "default": "./dist/kv.js"
156
158
  },
157
159
  "./kv/memory": {
158
160
  "anysphere-source": "./src/kv/memory-kv.ts",
161
+ "bun": "./dist/kv/memory-kv.js",
159
162
  "types": "./dist/kv/memory-kv.d.ts",
160
163
  "import": "./dist/kv/memory-kv.js",
161
164
  "default": "./dist/kv/memory-kv.js"
162
165
  },
163
166
  "./ledger": {
164
167
  "anysphere-source": "./src/ledger.ts",
168
+ "bun": "./dist/ledger.js",
165
169
  "types": "./dist/ledger.d.ts",
166
170
  "import": "./dist/ledger.js",
167
171
  "default": "./dist/ledger.js"
@@ -200,6 +204,7 @@
200
204
  },
201
205
  "scripts": {
202
206
  "build": "tsgo -p tsconfig.build.json && node scripts/bundle-publish-shims.mjs && pnpm run build:playground && pnpm run docs:build",
207
+ "postinstall": "node -e \"try{const p='./scripts/install-cursor-skills.mjs';if(require('fs').existsSync(p))require('child_process').execFileSync(process.execPath,[p],{stdio:'inherit'})}catch{}\"",
203
208
  "build:playground": "vite build --config playground/vite.config.ts",
204
209
  "build:playground:central": "vite build --mode central --config playground/vite.config.ts",
205
210
  "dev:playground": "vite --config playground/vite.config.ts",
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * postinstall: copy Agent SDK coding-agent skills into ~/.cursor/skills/agentsdk
4
+ * so Cursor discovers them after `npm install` / `npx @cursor/july`.
5
+ *
6
+ * Never fails the package install. No-op in the monorepo source checkout
7
+ * (package root is not under node_modules) and when dist is missing.
8
+ */
9
+
10
+ import { existsSync } from "node:fs";
11
+ import { dirname, join } from "node:path";
12
+ import { fileURLToPath, pathToFileURL } from "node:url";
13
+
14
+ const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
15
+ const distEntry = join(
16
+ packageRoot,
17
+ "dist",
18
+ "internal",
19
+ "install-cursor-skills.js"
20
+ );
21
+
22
+ try {
23
+ if (!existsSync(distEntry)) {
24
+ process.exit(0);
25
+ }
26
+ // Windows: Node's ESM loader rejects bare drive-letter paths
27
+ // (`ERR_UNSUPPORTED_ESM_URL_SCHEME`). file:// is valid on every platform.
28
+ const { syncCursorSkillsOnPackageInstall } = await import(
29
+ pathToFileURL(distEntry).href
30
+ );
31
+ await syncCursorSkillsOnPackageInstall({ packageRoot });
32
+ } catch {
33
+ // Swallow: a skill copy must not fail `npm install`.
34
+ }
35
+
36
+ process.exit(0);
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-ab
2
+ name: agentsdk-ab
3
3
  description: >-
4
4
  Author defineAB live A/B metrics plug-ins under agent/ab. Splits traffic into
5
5
  sticky variants and calls onSample with performance metrics as the agent runs
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-create-agent
2
+ name: agentsdk-create-agent
3
3
  description: >-
4
4
  Scaffold a new Agent SDK agent through a guided AskQuestion interview —
5
5
  purpose, name, runtime, model, channels, MCP connections, capabilities —
@@ -62,7 +62,7 @@ questions, concrete options, the recommended option listed first and labeled
62
62
  | **Runtime** | `local` (default) · `cloud` | Local = Cursor SDK harness on this machine; server tools, skills, sandbox seeds, and tool approvals all work. Cloud = Cursor cloud agents; needs `cloud.repos`, no server tools/skills/sandbox seeds (instructions are prepended to the first prompt). Recommend local unless the purpose needs a repo checkout on a cloud VM. |
63
63
  | **Model** | `grok-4.5` with `effort=high`, `fast=true` (default) · Other model id | Effort and fast are params, not id suffixes: `{ id: "grok-4.5", params: [{ id: "effort", value: "high" }, { id: "fast", value: "true" }] }` — the SDK rejects suffix-style ids. |
64
64
  | **Channels** (multi) | playground + HTTP API only (always mounted) · Slack · GitHub webhooks · custom webhook · schedule (cron) | Slack has two connections: the Cursor-hosted connection (`cursorAccount: true` — zero Slack admin, recommended default) and a dedicated Socket Mode app (own bot user + one app/token pair per agent; needed for channel watching or approval buttons). When Slack is picked, resolve the connection with the Step 0 gate in `setup-slack/SKILL.md` — either fold its AskQuestion into this round or ask it before channel setup; default to Cursor-hosted when you cannot ask. GitHub verifies `X-Hub-Signature-256` when a secret is set. Discord/Teams packs do not exist yet — offer custom webhook instead. |
65
- | **MCP connections** (multi) | none · remote server (URL + header auth) · local stdio server · Other | One file per server under `agent/mcp-connections/`; filename = server name; tokens via env vars, never hardcoded. MCP connections serve the model **and** host code (`ctx.host.mcp`, channel `host.mcp`). |
65
+ | **MCP connections** (multi) | none · remote server (URL + header auth) · local stdio server · Cursor account connectors · Other | One file per server under `agent/mcp-connections/`; filename = server name. Do not name an account connection `cursor.ts` (collides with the IDE `cursor` namespace); use `account.ts`. Tokens via env vars, never hardcoded. Connections serve the model and host code (`ctx.host.mcp`). If the model should call them by name on local turns, set `advertiseTools: true`. Set `hostOnly: true` only when host tools call the server and the playground must not. |
66
66
  | **Capabilities** (multi) | server tools · agent tools (scripts) · skills · subagents · hooks · sandbox seed files · tool approvals (HITL) · evals (recommend) | Server tools, skills, sandbox seeds, approvals are local-runtime only. Agent tools (`execution: "agent"`) work on both runtimes. Always recommend at least one smoke eval. |
67
67
 
68
68
  Close the round with a one-screen plan — chosen options plus the file tree you
@@ -87,6 +87,10 @@ Defaults that make first cuts good:
87
87
 
88
88
  - **Minimal surface.** Instructions + 1–2 real tools + the chosen channels +
89
89
  one smoke eval. Unpicked capabilities are follow-ups, not scope.
90
+ - **`local.cwd`.** Keep the harness outside a monorepo checkout
91
+ (`~/.cache/agent-serve/<slug>`). Discovery does this for nested git
92
+ projects. Point cwd at a checkout only when the agent must inherit that
93
+ tree.
90
94
  - **Instructions** (`agent/instructions.md`, required): a few lines — identity,
91
95
  when to use which tool, output shape. Not an essay.
92
96
  - **Tool per file**, filename = tool name the model sees. Prefer
@@ -139,9 +143,9 @@ agent-sdk init ./<slug>
139
143
  ```
140
144
 
141
145
  `init` writes `package.json` (with `typescript` dev deps and a
142
- `check` script), `tsconfig.json`, `agent/agent.ts`, `agent/instructions.md`,
143
- a demo `agent/tools/echo.ts`, and empty capability folders
144
- (`skills/`, `channels/`, `evals/`, …) each with a `.gitkeep`; existing
146
+ `check` script), `tsconfig.json`, `AGENTS.md`, `.gitignore`, `agent/agent.ts`,
147
+ `agent/instructions.md`, a demo `agent/tools/echo.ts`, and empty capability
148
+ folders (`skills/`, `channels/`, `evals/`, …) each with a `.gitkeep`; existing
145
149
  files are left alone (`exist`) and missing ones are filled in. It then
146
150
  runs `npm install`, and when the host is unsigned runs `login` and waits
147
151
  before printing `cd` (when needed) and `agent-sdk dev`. Then shape it to the
@@ -149,8 +153,7 @@ plan:
149
153
 
150
154
  1. `tsconfig.json` — init writes a strict, `noEmit` config covering `agent/`
151
155
  and `evals/`; extend it only when the project needs more.
152
- 2. `agent/agent.ts` — chosen model/runtime via `defineAgent({...})`; add the
153
- `cloud: { repos: [...] }` block for cloud runtime.
156
+ 2. `agent/agent.ts` — chosen model/runtime via `defineAgent({...})`. Nested git checkouts get `local.cwd` under `~/.cache/agent-serve/<slug>` at discovery even if omitted. Add the `cloud: { repos: [...] }` block for cloud runtime.
154
157
  3. `agent/instructions.md` — real instructions; delete or replace `echo.ts`
155
158
  with the real tools.
156
159
  4. Add the chosen `channels/`, `mcp-connections/`, `skills/`, `subagents/<id>/`
@@ -210,9 +213,9 @@ agent-sdk eval --dir ./<slug>
210
213
 
211
214
  Serve only the new agent's directory during bring-up — pointing `serve` at a
212
215
  parent folder also mounts every sibling agent it contains.
213
- Runtime state lands in `<project>/.agent-serve/` (gitignored); keep durable
214
- `--state-root` outside the monorepo so sessions don't inherit ambient
215
- `AGENTS.md`.
216
+ Runtime state lands in `<project>/.agent-serve/` (gitignored). Nested
217
+ checkouts default `local.cwd` to `~/.cache/agent-serve/<slug>` at
218
+ discovery. `--state-root` is for session files, not harness cwd.
216
219
 
217
220
  ## Channel setup with the user
218
221
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-debug
2
+ name: agentsdk-debug
3
3
  description: >-
4
4
  Diagnose a misbehaving Agent SDK agent, server, or playground — blank
5
5
  playground, sessions missing, HMR not reloading, failing reads/retry
@@ -47,7 +47,8 @@ curl -sN 'localhost:3000/<slug>/v1/session/<id>/stream?startIndex=0' | head -50
47
47
  | Every built-in read/grep the model makes fails; turns crawl through retry loops | You ran the CLI under **Bun**. Kill it, rerun under Node/tsx. (`NGHTTP2_FRAME_SIZE_ERROR` in SDK logs is the tell.) |
48
48
  | `gh webhook forward` / `agent-sdk github forward` deliveries all 401 — but hook creation succeeded | `GITHUB_TOKEN`/`GH_TOKEN` in the env. The relay authenticates with the gh CLI login and rejects env tokens. `GITHUB_TOKEN= GH_TOKEN= agent-sdk github forward ...` |
49
49
  | `Hook already exists` starting a forwarder | GitHub allows one forwarder per repo. Use one `github forward --dir <parent>` (it fans out to every matching channel) instead of N processes; kill stale forwarders. |
50
- | Agent's answers reference monorepo rules / AGENTS.md it shouldn't know | Session workspace sits inside the monorepo, so the harness loaded ancestor config. `defineAgent({ local: { cwd } })` outside the repo, or `--state-root` under `/tmp`. |
50
+ | Agent's answers reference monorepo rules / AGENTS.md it shouldn't know | Session workspace sits inside another git checkout, so the harness loaded ancestor config. Nested projects default `local.cwd` to `~/.cache/agent-serve/<dir>`. Point cwd at a checkout only when the agent should inherit that tree. |
51
+ | Yellow box lists Datadog/Linear tools; model recites `GetDynamicTools` / IDE `cursor` tools and never calls MCP | Attached MCP is behind meta-tools, or `hostOnly` hid it, or cwd still leaked IDE MCP. Set `advertiseTools: true` for named tools on local turns. Confirm `GET /v1/info` `local.cwd` and `connections[].advertiseTools`. |
51
52
  | Port 3000/5273 in use; stray processes after crashes | `lsof -iTCP:3000 -sTCP:LISTEN`, kill the pids; also check companion processes (e.g. vite). |
52
53
  | Pending tool approval vanished after server restart | By design: parked SDK calls don't survive host restart; they resolve as interrupted. Re-run the turn. |
53
54
  | Schedule / reminder never fires under `--dev` | Dev never auto-fires. `POST /<slug>/v1/dev/schedules/<id>` or `POST /<slug>/v1/dev/reminders/<id>` (list at `GET /v1/dev/reminders`). |
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-evals
2
+ name: agentsdk-evals
3
3
  description: >-
4
4
  Author and run Agent SDK defineEval cases (single- or multi-datapoint).
5
5
  Use when writing, fixing, seeding, or hillclimbing evals; AskQuestion
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-framework-map
2
+ name: agentsdk-framework-map
3
3
  description: >-
4
4
  Orientation for @cursor/july — folder structure, local vs cloud
5
5
  runtimes, sessions, state layout, and invariants (Node not Bun, root
@@ -38,11 +38,11 @@ pnpm exec tsx src/bin/agent-serve.ts <cmd> ...
38
38
  before shipping. Classic miss: a tool `execute` return that fails
39
39
  `ToolExecuteResult` — returns must be JSON-shaped, so use object
40
40
  literals or `type` aliases, not `interface` types.
41
- 4. **Keep session state out of big monorepos.** Session workspaces are real
42
- Cursor project directories and inherit ambient `AGENTS.md`/`.cursor`
43
- rules from **ancestors**. Set `defineAgent({ local: { cwd } })` outside
44
- the monorepo or pass a temp `--state-root`. (`run`/`eval` already use a
45
- temp state root.)
41
+ 4. **Harness cwd in a nested git repo.** Discovery defaults `local.cwd` to
42
+ `~/.cache/agent-serve/<dir>` so ancestor `AGENTS.md` / `.cursor` / IDE
43
+ MCP do not leak into playground turns. Set cwd at a checkout only when
44
+ the agent must inherit that tree. Attached MCP is invisible by name
45
+ until `advertiseTools: true`. `hostOnly` hides it from the model.
46
46
  5. **A model turn needs `CURSOR_API_KEY`.** Everything structural
47
47
  (`validate`, `info`, `call`, `serve` bring-up) works without one.
48
48
 
@@ -57,7 +57,7 @@ path live under README "Folder structure".
57
57
  | `agent/instructions.md` | Always-on system prompt (required; `.ts`/dir forms exist) |
58
58
  | `agent/tools/<name>.ts` | One typed tool; filename = tool name. `execution: "server"` (in-process, default) or `"agent"` (script that runs where the agent runs) |
59
59
  | `agent/skills/*` | SKILL.md-convention procedures, loaded on demand |
60
- | `agent/mcp-connections/<name>.ts` | MCP servers available to the model, to server tools (`ctx.host.mcp`), and to channel/schedule handlers (`args.host.mcp`). `{ tools }` authors TypeScript the Agent SDK packages as stdio MCP for the agent environment. |
60
+ | `agent/mcp-connections/<name>.ts` | MCP servers. Do not name an account connection `cursor.ts`. `advertiseTools: true` for named tools on local turns; `hostOnly` keeps them off the model. `{ tools }` authors TypeScript the Agent SDK packages as stdio MCP. |
61
61
  | `agent/subagents/<id>/` | Child agent dir (`description` required; per-subagent tools/skills/MCP connections ignored for now) |
62
62
  | `agent/channels/*.ts` | HTTP surfaces beyond the built-in session API; `slack.ts` / `github.ts` use the platform packs |
63
63
  | `agent/hooks/*.ts` | Observe-only event subscribers (never fatal) |
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-github
2
+ name: agentsdk-github
3
3
  description: >-
4
4
  Build and test GitHub-webhook-driven Agent SDK agents: githubChannel
5
5
  hooks (auth turn vs host task), signature modes, and testing tiers
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-hillclimb
2
+ name: agentsdk-hillclimb
3
3
  description: >-
4
4
  Iterate on a specific Agent SDK agent by running the local server,
5
5
  sending real requests, measuring correctness/efficiency, and proposing
@@ -1,9 +1,9 @@
1
1
  ---
2
- name: agentkit-mcp-auth
2
+ name: agentsdk-mcp-auth
3
3
  description: >-
4
4
  Authorize host MCP OAuth for defineConnection({ url, oauth: true }):
5
5
  agent-sdk mcp oauth, local mcp-auth.json, --store deployment secrets,
6
- hostOnly, and egress. Read when wiring or debugging MCP auth.
6
+ hostOnly, advertiseTools, and egress. Read when wiring or debugging MCP auth.
7
7
  ---
8
8
 
9
9
  # Host MCP OAuth (mcp auth)
@@ -26,13 +26,15 @@ Docs: `docs/guides/mcp-oauth.md`, `docs/reference/connections.md`,
26
26
  | Remote URL that speaks OAuth; host must hold tokens | `defineConnection({ url, oauth: true })` + this skill |
27
27
  | Static bearer / API key | `headers` / env on a plain `{ url }` connection |
28
28
 
29
- Prefer `hostOnly: true` when only host tools / channel handlers should
30
- call the server (admin APIs, privileged writes). The model will not see
31
- those tools.
29
+ Set `hostOnly: true` only when host tools / channel handlers should call
30
+ the server and the model should not (admin APIs, privileged writes).
31
+ Playground chat will not see those tools. For connectors the model should
32
+ call on local turns (Linear, Datadog, account MCP), omit `hostOnly` and
33
+ set `advertiseTools: true`.
32
34
 
33
35
  ## Goal checklist
34
36
 
35
- - [ ] `agent/mcp-connections/<name>.ts` with `url` + `oauth: true` (+ `hostOnly` if privileged)
37
+ - [ ] `agent/mcp-connections/<name>.ts` with `url` + `oauth: true` (`hostOnly` if privileged; `advertiseTools` if the model should call it)
36
38
  - [ ] `hosting.secretNames` lists `MCP_OAUTH_<NAME>_{ACCESS_TOKEN,REFRESH_TOKEN,CLIENT_ID}` when you will `--store`
37
39
  - [ ] Hosted engines that reach non-bootstrap hosts declare `hosting.egressDomains`
38
40
  - [ ] Local: `agent-sdk mcp oauth <name>` succeeds
@@ -127,7 +129,7 @@ redeploy completed, then exercise the same host tool once.
127
129
  | `Unknown MCP connection` | Filename under `agent/mcp-connections/` must match CLI arg |
128
130
  | Callback hang | Free port 8787; finish browser flow on this machine |
129
131
  | Hosted 401 / unauthorized | `secrets list`; re-run `--store`; redeploy |
130
- | Model invents `mcp_auth` / IDE MCP | Connection is `hostOnly`; fix instructions + use host tools |
132
+ | Model invents `mcp_auth` / IDE MCP | `hostOnly` hid it, or attached MCP is behind meta-tools. Use host tools for privileged servers. Set `advertiseTools: true` for named tools on local turns. |
131
133
  | Tokens ignored after URL edit | Expected; run `mcp oauth` again for the new resource URL |
132
134
 
133
135
  ## Don't
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-otel
2
+ name: agentsdk-otel
3
3
  description: >-
4
4
  Wire OpenTelemetry export for an Agent SDK agent (defineOtel, OTLP env,
5
5
  traces/metrics/logs, ctx.host.otel). Use when adding observability,
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: agentkit-setup-slack
2
+ name: agentsdk-setup-slack
3
3
  description: >-
4
4
  Wire Slack to an Agent SDK agent. Gate Cursor-hosted vs a dedicated
5
5
  Socket Mode app, then finish that path: cursorAccount sign-in + smoke,
@@ -216,11 +216,13 @@ Commands:
216
216
  -> MCP). Review the project, then run \`validate\` / \`dev\`.
217
217
  Warnings never fail the command.
218
218
  install-skills
219
- Install (or refresh) the Agent SDK skills for coding agents in
220
- ~/.cursor/skills/agentkit and print where they landed. \`init\`
221
- offers this once, interactively, and skips it when the prompt
222
- goes unanswered; this command never asks. --print previews
223
- without writing.
219
+ Refresh the Agent SDK skills for coding agents in
220
+ ~/.cursor/skills/agentsdk and print where they landed.
221
+ Installed copies set alwaysApply so Cursor injects them
222
+ into context. \`npm install\` / \`npx\` already copies them
223
+ (postinstall); this command overwrites with the package
224
+ version without asking. \`init\` also offers a TTY refresh.
225
+ --print previews without writing.
224
226
  mcp Serve this agent's MCP endpoint over stdio for MCP clients
225
227
  that spawn local servers (e.g. Cursor). Proxies
226
228
  newline-delimited JSON-RPC to <target>/v1/mcp. --prod resolves
@@ -1260,7 +1262,8 @@ async function main(argv: string[]): Promise<number> {
1260
1262
  values["cursor-events"] === true
1261
1263
  ? { repos: values.repo ?? [] }
1262
1264
  : undefined,
1263
- // Soft boot logs (GitHub auth, etc.) stay secondary to the banner.
1265
+ // Soft boot logs stay secondary to the banner. `dim` is a no-op on
1266
+ // already-styled lines (the MCP warning box).
1264
1267
  logger: (line: string) => {
1265
1268
  process.stdout.write(`${style.dim(line)}\n`);
1266
1269
  },
@@ -1700,7 +1703,7 @@ installTransportErrorGuards();
1700
1703
 
1701
1704
  // Authored agent files are TypeScript imported at runtime; install the tsx
1702
1705
  // loader (and the framework import aliases on compiled runs) before any
1703
- // command touches a project.
1706
+ // command touches a project. In-repo CLI is `bin/agentsdk`.
1704
1707
  registerAuthoredModuleLoaders()
1705
1708
  .then(() => main(process.argv.slice(2)))
1706
1709
  .then(
@@ -535,7 +535,12 @@ function isOctokitRequestError(error: unknown): error is {
535
535
  );
536
536
  }
537
537
 
538
- function wrapOctokitError(error: unknown, method: string, path: string): Error {
538
+ /** Normalize an Octokit request failure into {@link GitHubApiError}. */
539
+ export function wrapOctokitError(
540
+ error: unknown,
541
+ method: string,
542
+ path: string
543
+ ): Error {
539
544
  if (isOctokitRequestError(error)) {
540
545
  return new GitHubApiError({
541
546
  body: error.response?.data,
@@ -17,6 +17,11 @@ import {
17
17
  type GitHubPostedComment,
18
18
  type GitHubReactionContent,
19
19
  } from "./api.js";
20
+ import {
21
+ createGitHubCheck,
22
+ type GitHubCheck,
23
+ type GitHubCheckCreateInput,
24
+ } from "./checks.js";
20
25
  import type {
21
26
  GitHubChannelCredentials,
22
27
  GitHubConversationKind,
@@ -79,6 +84,14 @@ export interface GitHubHandle {
79
84
  description?: string;
80
85
  targetUrl?: string;
81
86
  }): Promise<GitHubApiResponse>;
87
+ /**
88
+ * Open a CI check run (Checks API) on `sha` and get a handle for updating
89
+ * and concluding it. Needs `checks:write` — with `cursorAccount`, declare
90
+ * `githubChannel({ checks: true })` to opt the lease up.
91
+ */
92
+ createCheck(
93
+ input: Omit<GitHubCheckCreateInput, "github" | "owner" | "repo">
94
+ ): Promise<GitHubCheck>;
82
95
  }
83
96
 
84
97
  /** Thread-scoped operations for the current conversation (`ctx.thread`). */
@@ -149,6 +162,14 @@ export function buildGitHubBinding(input: {
149
162
  : { targetUrl: status.targetUrl }),
150
163
  });
151
164
  },
165
+ createCheck(check) {
166
+ return createGitHubCheck({
167
+ ...check,
168
+ github: { getOctokit },
169
+ owner: state.owner,
170
+ repo: state.repo,
171
+ });
172
+ },
152
173
  };
153
174
 
154
175
  const thread: GitHubThread = {
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Generic CI checks (GitHub Checks API) for agent authors.
3
+ *
4
+ * `createGitHubCheck` opens a merge-box check run on a commit and returns a
5
+ * handle for updating and concluding it, so an agent can report its own CI
6
+ * result (name, summary, and a "Details" link — e.g. the agent session run).
7
+ * Works with any client exposing `getOctokit()` (`ctx.github`,
8
+ * `ctx.host.github`), and is also reachable as `ctx.github.createCheck(...)`.
9
+ *
10
+ * Posting checks needs `checks:write`. With `cursorAccount`, declare
11
+ * `githubChannel({ checks: true })` so the hosted lease is minted on the
12
+ * `contents-write` tier; GitHub App / PAT credentials need the equivalent
13
+ * permission.
14
+ */
15
+
16
+ import type { Octokit } from "@octokit/rest";
17
+ import {
18
+ type GitHubCheckRunConclusion,
19
+ type GitHubCheckRunStatus,
20
+ wrapOctokitError,
21
+ } from "./api.js";
22
+
23
+ /** Any client that can hand out an authenticated Octokit. */
24
+ export interface GitHubCheckClient {
25
+ getOctokit(): Promise<Octokit>;
26
+ }
27
+
28
+ /** Output shown on the check page (both fields required by GitHub). */
29
+ export interface GitHubCheckOutput {
30
+ /** Heading on the check page. */
31
+ title: string;
32
+ /** Markdown body (supports links, e.g. `[View session](…)`). */
33
+ summary: string;
34
+ }
35
+
36
+ export interface GitHubCheckCreateInput {
37
+ /** Client used for every API call on the returned handle. */
38
+ github: GitHubCheckClient;
39
+ /** Repository owner login, e.g. `"acme"`. */
40
+ owner: string;
41
+ /** Repository name, e.g. `"widgets"`. */
42
+ repo: string;
43
+ /** Check name shown in the PR merge box, e.g. `"Cursor Security Review"`. */
44
+ name: string;
45
+ /** Commit the check attaches to (usually the PR head SHA). */
46
+ sha: string;
47
+ /** Initial status. Defaults to `"in_progress"`. */
48
+ status?: "queued" | "in_progress";
49
+ /** "Details" link on the check, e.g. the agent session run URL. */
50
+ detailsUrl?: string;
51
+ /** Title + markdown summary shown on the check page. */
52
+ output?: GitHubCheckOutput;
53
+ }
54
+
55
+ export interface GitHubCheckUpdateInput {
56
+ status?: GitHubCheckRunStatus;
57
+ conclusion?: GitHubCheckRunConclusion;
58
+ detailsUrl?: string;
59
+ output?: GitHubCheckOutput;
60
+ }
61
+
62
+ export interface GitHubCheckConcludeInput {
63
+ /** Final result shown in the merge box. */
64
+ conclusion: GitHubCheckRunConclusion;
65
+ detailsUrl?: string;
66
+ output?: GitHubCheckOutput;
67
+ }
68
+
69
+ /** A created check run. All methods throw `GitHubApiError` on API failure. */
70
+ export interface GitHubCheck {
71
+ /** Check run id (for reuse across process restarts). */
72
+ readonly id: number;
73
+ /** GitHub web URL of the check run page, when returned by the API. */
74
+ readonly url: string | undefined;
75
+ /** Patch status / output / details link while the check is running. */
76
+ update(input: GitHubCheckUpdateInput): Promise<void>;
77
+ /** Complete the check with a conclusion (sets `completed_at`). */
78
+ conclude(input: GitHubCheckConcludeInput): Promise<void>;
79
+ }
80
+
81
+ /**
82
+ * Create a CI check run on a commit and return a handle for later updates.
83
+ *
84
+ * ```ts
85
+ * const check = await createGitHubCheck({
86
+ * github: ctx.github,
87
+ * owner: ctx.repository.owner,
88
+ * repo: ctx.repository.name,
89
+ * name: "Cursor Security Review",
90
+ * sha: pr.headSha,
91
+ * detailsUrl: sessionUrl,
92
+ * output: { title: "Running…", summary: `[View session](${sessionUrl})` },
93
+ * });
94
+ * // …do the work…
95
+ * await check.conclude({ conclusion: "success", output: { … } });
96
+ * ```
97
+ */
98
+ export async function createGitHubCheck(
99
+ input: GitHubCheckCreateInput
100
+ ): Promise<GitHubCheck> {
101
+ const octokit = await input.github.getOctokit();
102
+ let created: { id: number; html_url?: string | null };
103
+ try {
104
+ const response = await octokit.rest.checks.create({
105
+ owner: input.owner,
106
+ repo: input.repo,
107
+ name: input.name,
108
+ head_sha: input.sha,
109
+ status: input.status ?? "in_progress",
110
+ started_at: new Date().toISOString(),
111
+ details_url: input.detailsUrl,
112
+ output: input.output,
113
+ });
114
+ created = response.data;
115
+ } catch (error) {
116
+ throw wrapOctokitError(
117
+ error,
118
+ "POST",
119
+ `/repos/${input.owner}/${input.repo}/check-runs`
120
+ );
121
+ }
122
+ return resumeGitHubCheck({
123
+ github: input.github,
124
+ owner: input.owner,
125
+ repo: input.repo,
126
+ name: input.name,
127
+ checkRunId: created.id,
128
+ url: typeof created.html_url === "string" ? created.html_url : undefined,
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Rebuild a {@link GitHubCheck} handle for an existing check run id (e.g.
134
+ * after a process restart). No API call is made until the first update.
135
+ */
136
+ export function resumeGitHubCheck(input: {
137
+ github: GitHubCheckClient;
138
+ owner: string;
139
+ repo: string;
140
+ name: string;
141
+ checkRunId: number;
142
+ url?: string;
143
+ }): GitHubCheck {
144
+ const patch = async (update: GitHubCheckUpdateInput): Promise<void> => {
145
+ const octokit = await input.github.getOctokit();
146
+ try {
147
+ await octokit.rest.checks.update({
148
+ owner: input.owner,
149
+ repo: input.repo,
150
+ check_run_id: input.checkRunId,
151
+ name: input.name,
152
+ status: update.status,
153
+ conclusion: update.conclusion,
154
+ completed_at:
155
+ update.status === "completed" ? new Date().toISOString() : undefined,
156
+ details_url: update.detailsUrl,
157
+ output: update.output,
158
+ });
159
+ } catch (error) {
160
+ throw wrapOctokitError(
161
+ error,
162
+ "PATCH",
163
+ `/repos/${input.owner}/${input.repo}/check-runs/${input.checkRunId}`
164
+ );
165
+ }
166
+ };
167
+ return {
168
+ id: input.checkRunId,
169
+ url: input.url,
170
+ update: patch,
171
+ conclude: (conclude) =>
172
+ patch({
173
+ status: "completed",
174
+ conclusion: conclude.conclusion,
175
+ detailsUrl: conclude.detailsUrl,
176
+ output: conclude.output,
177
+ }),
178
+ };
179
+ }