@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
@@ -9,6 +9,21 @@ export type ReviewCommentPostResult = {
9
9
  mode: "review_with_inline_comments" | "review_body_only" | "skipped";
10
10
  inlineCommentCount: number;
11
11
  detail: string;
12
+ /**
13
+ * Ids of the inline comments this post created, when the publisher could
14
+ * read them back. Callers that later re-read a PR's comments use these as
15
+ * the provenance allowlist: a comment id we did not create is not ours,
16
+ * no matter what its body looks like. Empty when the publisher cannot
17
+ * resolve them (it never guesses).
18
+ */
19
+ postedComments?: PostedReviewComment[];
20
+ };
21
+
22
+ /** One inline comment this agent created, as the SCM assigned it. */
23
+ export type PostedReviewComment = {
24
+ id: number;
25
+ file: string;
26
+ line: number;
12
27
  };
13
28
 
14
29
  export type ReviewInlineComment = {
@@ -41,6 +56,175 @@ export type ReviewCommentPublisherImplementation = {
41
56
  postReview: (args: ReviewCommentPostArgs) => Promise<ReviewCommentPostResult>;
42
57
  };
43
58
 
59
+ /**
60
+ * SCMs this module can read review comments back from. Same growth seam as
61
+ * `shallow-clone.ts`'s {@link import("./shallow-clone.js").ScmProvider}:
62
+ * adding GitLab/Bitbucket/Origin means a resolver case plus a reader
63
+ * implementation, and nothing above this line changes.
64
+ */
65
+ export type ScmReviewProvider = "github";
66
+
67
+ /** Which SCM's PR to read review comments from. */
68
+ export type ScmReviewTarget = {
69
+ provider: ScmReviewProvider;
70
+ /** `owner/name`. */
71
+ repo: string;
72
+ prNumber: number;
73
+ };
74
+
75
+ /**
76
+ * One existing inline review comment, provider-neutral.
77
+ *
78
+ * Field names follow Bugbot's `ExistingInlineComment`
79
+ * (`backend/server/src/bugbot/review/applyBugbotPRReview.ts`), which is the
80
+ * shape its resolution judge consumes after normalizing each provider's
81
+ * `getPRComments` output — so the same review logic reads the same way here.
82
+ */
83
+ export type ExistingReviewComment = {
84
+ id: number;
85
+ file: string;
86
+ startLine: number;
87
+ endLine: number;
88
+ body: string;
89
+ };
90
+
91
+ export type GetReviewCommentsArgs = {
92
+ target: ScmReviewTarget;
93
+ /** Comment ids to fetch; ids the SCM no longer has are omitted. */
94
+ commentIds: readonly number[];
95
+ signal?: AbortSignal;
96
+ };
97
+
98
+ /**
99
+ * Read side of the review-comment seam, mirroring
100
+ * {@link ReviewCommentPublisherImplementation}. Bugbot's equivalent is
101
+ * `IGitProvider.getPRComments`.
102
+ *
103
+ * By id rather than by listing: callers only ever want comments they
104
+ * recorded creating, and a busy PR's comment list runs to thousands, where
105
+ * any page cap silently drops exactly the older comments a re-review needs.
106
+ */
107
+ export type ReviewCommentReaderImplementation = {
108
+ getReviewComments: (
109
+ args: GetReviewCommentsArgs
110
+ ) => Promise<ExistingReviewComment[]>;
111
+ };
112
+
113
+ /** Parse a PR URL into the SCM target to read comments from. */
114
+ export function resolveScmReviewTarget(
115
+ prUrl: string
116
+ ): ScmReviewTarget | undefined {
117
+ const parsed = parseGithubPrUrl(prUrl);
118
+ return parsed.kind === "valid"
119
+ ? {
120
+ provider: "github",
121
+ repo: parsed.value.repo,
122
+ prNumber: parsed.value.prNumber,
123
+ }
124
+ : undefined;
125
+ }
126
+
127
+ /**
128
+ * Reader for a resolved target, mirroring Bugbot's `createPrGitProvider`
129
+ * dispatch. Returns undefined when the host cannot serve that provider (no
130
+ * GitHub client bound), so callers degrade instead of throwing.
131
+ */
132
+ export function createReviewCommentReader(args: {
133
+ target: ScmReviewTarget;
134
+ github?: HostGitHubClient;
135
+ }): ReviewCommentReaderImplementation | undefined {
136
+ switch (args.target.provider) {
137
+ case "github":
138
+ return args.github === undefined
139
+ ? undefined
140
+ : createHostGithubReviewCommentReader(args.github);
141
+ }
142
+ }
143
+
144
+ /** Cap on pages pulled per PR; GitHub serves 100 comments per page. */
145
+ const REVIEW_COMMENTS_MAX_PAGES = 5;
146
+ const REVIEW_COMMENTS_PAGE_SIZE = 100;
147
+
148
+ /**
149
+ * Reads inline review comments through the host GitHub client (Cursor
150
+ * account lease, App installation token, or PAT).
151
+ */
152
+ export function createHostGithubReviewCommentReader(
153
+ github: HostGitHubClient
154
+ ): ReviewCommentReaderImplementation {
155
+ return {
156
+ async getReviewComments({ target, commentIds, signal }) {
157
+ const [owner, repo] = target.repo.split("/", 2);
158
+ if (owner === undefined || repo === undefined || repo === "") {
159
+ return [];
160
+ }
161
+ const octokit = await github.getOctokit();
162
+ const comments: ExistingReviewComment[] = [];
163
+ for (const commentId of commentIds) {
164
+ signal?.throwIfAborted();
165
+ try {
166
+ const response = await octokit.rest.pulls.getReviewComment({
167
+ owner,
168
+ repo,
169
+ comment_id: commentId,
170
+ });
171
+ const normalized = normalizeGithubReviewComment(response.data);
172
+ if (normalized !== undefined) {
173
+ comments.push(normalized);
174
+ }
175
+ } catch {
176
+ // Deleted or otherwise unreadable: that finding simply has no
177
+ // prior text to judge, which is the same as it not being there.
178
+ }
179
+ }
180
+ return comments;
181
+ },
182
+ };
183
+ }
184
+
185
+ type GithubReviewCommentLike = {
186
+ id: number;
187
+ path: string;
188
+ body: string;
189
+ line?: number | null;
190
+ start_line?: number | null;
191
+ original_line?: number | null;
192
+ original_start_line?: number | null;
193
+ };
194
+
195
+ /**
196
+ * GitHub review comment → {@link ExistingReviewComment}.
197
+ *
198
+ * Prefers the `original_*` fields — the path/lines/commit as of the review
199
+ * the comment belongs to. `line` drifts as the PR gains commits, so a
200
+ * caller correlating a comment with the review that produced it needs the
201
+ * original position, the same fields Bugbot carries on
202
+ * `PullRequestCommentOutput`.
203
+ */
204
+ export function normalizeGithubReviewComment(
205
+ comment: GithubReviewCommentLike
206
+ ): ExistingReviewComment | undefined {
207
+ // Take both lines from the same position set. Mixing them (original end
208
+ // line with the drifted current start line) would describe a range that
209
+ // never existed in either revision.
210
+ const original = comment.original_line ?? undefined;
211
+ const endLine = original ?? comment.line ?? undefined;
212
+ if (endLine === undefined || endLine === null) {
213
+ return undefined;
214
+ }
215
+ const startLine =
216
+ (original === undefined
217
+ ? comment.start_line
218
+ : comment.original_start_line) ?? endLine;
219
+ return {
220
+ id: comment.id,
221
+ file: comment.path,
222
+ startLine,
223
+ endLine,
224
+ body: comment.body,
225
+ };
226
+ }
227
+
44
228
  type ParsedGithubPrUrl = {
45
229
  repo: string;
46
230
  prNumber: number;
@@ -148,6 +332,15 @@ async function postReviewViaHostGithub(
148
332
  detail: htmlUrl
149
333
  ? `posted via host GitHub: ${htmlUrl}`
150
334
  : `posted via host GitHub with ${inlineCommentCount} inline comment(s)`,
335
+ postedComments: await readPostedComments({
336
+ octokit,
337
+ owner,
338
+ repo,
339
+ prNumber: request.prNumber,
340
+ reviewId: response.data.id,
341
+ expected: inlineCommentCount,
342
+ signal: args.signal,
343
+ }),
151
344
  };
152
345
  } catch (error) {
153
346
  if (args.signal?.aborted) {
@@ -159,6 +352,58 @@ async function postReviewViaHostGithub(
159
352
  }
160
353
  }
161
354
 
355
+ /**
356
+ * Ids of the inline comments a just-created review owns.
357
+ *
358
+ * `pulls.createReview` returns the review, not its comments, so they come
359
+ * from the review-scoped listing. Scoping to the review matters: the
360
+ * PR-wide list is ordered oldest-first and runs to thousands on a busy PR,
361
+ * so the comments we just created are the ones a page cap would drop.
362
+ * Best-effort: any failure yields an empty list, which costs the next run
363
+ * its prior findings rather than risking a wrong id. Never throws — the
364
+ * review is already posted by this point.
365
+ */
366
+ async function readPostedComments(args: {
367
+ octokit: Awaited<ReturnType<HostGitHubClient["getOctokit"]>>;
368
+ owner: string;
369
+ repo: string;
370
+ prNumber: number;
371
+ reviewId: number;
372
+ expected: number;
373
+ signal?: AbortSignal;
374
+ }): Promise<PostedReviewComment[]> {
375
+ if (args.expected === 0) {
376
+ return [];
377
+ }
378
+ try {
379
+ const posted: PostedReviewComment[] = [];
380
+ for (let page = 1; page <= REVIEW_COMMENTS_MAX_PAGES; page++) {
381
+ args.signal?.throwIfAborted();
382
+ const response = await args.octokit.rest.pulls.listCommentsForReview({
383
+ owner: args.owner,
384
+ repo: args.repo,
385
+ pull_number: args.prNumber,
386
+ review_id: args.reviewId,
387
+ per_page: REVIEW_COMMENTS_PAGE_SIZE,
388
+ page,
389
+ });
390
+ for (const comment of response.data) {
391
+ const line = comment.original_line ?? comment.line;
392
+ if (line === null || line === undefined) {
393
+ continue;
394
+ }
395
+ posted.push({ id: comment.id, file: comment.path, line });
396
+ }
397
+ if (response.data.length < REVIEW_COMMENTS_PAGE_SIZE) {
398
+ break;
399
+ }
400
+ }
401
+ return posted;
402
+ } catch {
403
+ return [];
404
+ }
405
+ }
406
+
162
407
  async function postReviewViaLocalGh(
163
408
  args: ReviewCommentPostArgs
164
409
  ): Promise<ReviewCommentPostResult> {
@@ -0,0 +1,33 @@
1
+ /**
2
+ * MCP tool-name sanitization shared by the Cursor-account bridge
3
+ * (`account-mcp.ts`) and advertised connections (`advertise-tools.ts`).
4
+ *
5
+ * Connector display names — and the aggregate `/v1/agent/mcp` names minted
6
+ * from them (`<serverIdentifier>-<tool>`) — can contain spaces, dots, and
7
+ * other characters that are illegal as the tool name a model sees.
8
+ *
9
+ * Character class matches `packages/agent` `normalizeMcpToolName`
10
+ * (`[^a-zA-Z0-9_-]` → `_`). Length cap and the empty fallback match the
11
+ * account bridge (MCP clients commonly enforce `^[a-zA-Z0-9_-]{1,128}$`).
12
+ * Callers that talk to the backend keep the original advertised name.
13
+ */
14
+
15
+ /** MCP clients commonly enforce `^[a-zA-Z0-9_-]{1,128}$` for tool names. */
16
+ export const MAX_MCP_TOOL_NAME_LENGTH = 128;
17
+
18
+ /** Connector display names can contain anything (spaces, dots, emoji). */
19
+ export function sanitizeMcpToolName(name: string): string {
20
+ const cleaned = name
21
+ .replace(/[^a-zA-Z0-9_-]/g, "_")
22
+ .slice(0, MAX_MCP_TOOL_NAME_LENGTH);
23
+ return cleaned === "" ? "tool" : cleaned;
24
+ }
25
+
26
+ /** `base` for the first claimant, `base_2` / `base_3` … for colliders. */
27
+ export function suffixMcpToolName(base: string, index: number): string {
28
+ if (index === 0) {
29
+ return base;
30
+ }
31
+ const suffix = `_${index + 1}`;
32
+ return `${base.slice(0, MAX_MCP_TOOL_NAME_LENGTH - suffix.length)}${suffix}`;
33
+ }
@@ -14,12 +14,12 @@ import {
14
14
  type CloudAgentOptions,
15
15
  Cursor,
16
16
  createAgentPlatform,
17
- JsonlLocalAgentStore,
18
17
  type LocalAgentStore,
19
18
  type ModelSelection,
20
19
  type RunResult,
21
20
  type SDKAgent,
22
21
  } from "@cursor/sdk";
22
+ import { SqliteLocalAgentStore } from "@cursor/sdk/sqlite";
23
23
  import {
24
24
  DEFAULT_MODEL,
25
25
  type ModelSetting,
@@ -558,8 +558,11 @@ export class CursorSdkRunner implements AgentRunner {
558
558
  private getStore(stateDir: string): Promise<LocalAgentStore> {
559
559
  let storePromise = this.stores.get(stateDir);
560
560
  if (storePromise === undefined) {
561
- storePromise = mkdir(stateDir, { recursive: true }).then(
562
- () => new JsonlLocalAgentStore(stateDir)
561
+ storePromise = mkdir(stateDir, { recursive: true }).then(() =>
562
+ SqliteLocalAgentStore.open({
563
+ stateRoot: stateDir,
564
+ workspaceRef: stateDir,
565
+ })
563
566
  );
564
567
  this.stores.set(stateDir, storePromise);
565
568
  }
@@ -2327,6 +2327,13 @@ export class SessionEngine {
2327
2327
  tools[tool.name] = {
2328
2328
  description: tool.description,
2329
2329
  inputSchema: tool.inputSchema as SDKCustomTool["inputSchema"],
2330
+ // `SDKCustomTool.outputSchema` ships in the next published
2331
+ // @cursor/sdk; the conditional spread carries the field through the
2332
+ // pinned SDK's type until the dependency bumps, at which point local
2333
+ // runs start advertising it.
2334
+ ...(tool.outputSchema === undefined
2335
+ ? {}
2336
+ : { outputSchema: tool.outputSchema }),
2330
2337
  execute: async (args, context) => {
2331
2338
  return this.executeServerTool({
2332
2339
  tool,