@cursor/july 0.1.16 → 0.1.18

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 (273) hide show
  1. package/README.md +9 -4
  2. package/dist/bin/agent-serve.js +60 -2
  3. package/dist/channels/slack/api.d.ts.map +1 -1
  4. package/dist/channels/slack/api.js +13 -3
  5. package/dist/channels/slack/auth.d.ts +7 -1
  6. package/dist/channels/slack/auth.d.ts.map +1 -1
  7. package/dist/channels/slack/auth.js +14 -0
  8. package/dist/channels/slack/blocks.d.ts +61 -0
  9. package/dist/channels/slack/blocks.d.ts.map +1 -0
  10. package/dist/channels/slack/blocks.js +90 -0
  11. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  12. package/dist/channels/slack/cursor-account.js +1 -1
  13. package/dist/channels/slack/defaults.d.ts +2 -0
  14. package/dist/channels/slack/defaults.d.ts.map +1 -1
  15. package/dist/channels/slack/defaults.js +29 -3
  16. package/dist/channels/slack/dispatch.d.ts +3 -17
  17. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  18. package/dist/channels/slack/dispatch.js +4 -1
  19. package/dist/channels/slack/inbound.d.ts.map +1 -1
  20. package/dist/channels/slack/inbound.js +6 -1
  21. package/dist/channels/slack/index.d.ts +2 -0
  22. package/dist/channels/slack/index.d.ts.map +1 -1
  23. package/dist/channels/slack/index.js +2 -0
  24. package/dist/channels/slack/init.d.ts.map +1 -1
  25. package/dist/channels/slack/init.js +4 -1
  26. package/dist/channels/slack/interactive.d.ts +39 -3
  27. package/dist/channels/slack/interactive.d.ts.map +1 -1
  28. package/dist/channels/slack/interactive.js +153 -7
  29. package/dist/channels/slack/manifest.d.ts +13 -0
  30. package/dist/channels/slack/manifest.d.ts.map +1 -1
  31. package/dist/channels/slack/manifest.js +36 -14
  32. package/dist/channels/slack/message-body.d.ts +13 -0
  33. package/dist/channels/slack/message-body.d.ts.map +1 -0
  34. package/dist/channels/slack/message-body.js +82 -0
  35. package/dist/channels/slack/setup.d.ts +4 -1
  36. package/dist/channels/slack/setup.d.ts.map +1 -1
  37. package/dist/channels/slack/setup.js +16 -2
  38. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  39. package/dist/channels/slack/slack-channel.js +24 -3
  40. package/dist/channels/slack/thread-context.d.ts +0 -2
  41. package/dist/channels/slack/thread-context.d.ts.map +1 -1
  42. package/dist/channels/slack/thread-context.js +1 -65
  43. package/dist/channels/slack/types.d.ts +93 -1
  44. package/dist/channels/slack/types.d.ts.map +1 -1
  45. package/dist/connections.d.ts +4 -1
  46. package/dist/connections.d.ts.map +1 -1
  47. package/dist/connections.js +4 -1
  48. package/dist/docs/404.html +2 -2
  49. package/dist/docs/ab.html +3 -3
  50. package/dist/docs/assets/{app.DjHC-Ggf.js → app.BR5EdVSq.js} +1 -1
  51. package/dist/docs/assets/chunks/@localSearchIndexroot.BOzkeUi8.js +1 -0
  52. package/dist/docs/assets/chunks/{VPLocalSearchBox.DwviwmIq.js → VPLocalSearchBox.CNCzfUKC.js} +1 -1
  53. package/dist/docs/assets/chunks/{theme.BIpeYSon.js → theme.CwKvMSWv.js} +2 -2
  54. package/dist/docs/assets/{example-agents_security-reviewer.md.BZSNycMf.js → example-agents_security-reviewer.md.Dhj_m7_B.js} +1 -1
  55. package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.js → guides_mcp-oauth.md.Dd8EgSem.js} +3 -2
  56. package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.lean.js → guides_mcp-oauth.md.Dd8EgSem.lean.js} +1 -1
  57. package/dist/docs/assets/{guides_slack.md.FWale6Ip.js → guides_slack.md.D_xFKlnF.js} +1 -1
  58. package/dist/docs/assets/{reference_connections.md.CsSr3rDz.js → reference_connections.md.B9Q3TOve.js} +12 -5
  59. package/dist/docs/assets/{reference_connections.md.CsSr3rDz.lean.js → reference_connections.md.B9Q3TOve.lean.js} +1 -1
  60. package/dist/docs/building-with-agents.html +3 -3
  61. package/dist/docs/concepts.html +3 -3
  62. package/dist/docs/deployment.html +3 -3
  63. package/dist/docs/evals.html +3 -3
  64. package/dist/docs/example-agents/approval-buddy.html +3 -3
  65. package/dist/docs/example-agents/benny.html +3 -3
  66. package/dist/docs/example-agents/bugbot.html +3 -3
  67. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  68. package/dist/docs/example-agents/codeowners-review.html +3 -3
  69. package/dist/docs/example-agents/concierge.html +3 -3
  70. package/dist/docs/example-agents/fsd.html +3 -3
  71. package/dist/docs/example-agents/index.html +3 -3
  72. package/dist/docs/example-agents/knowledge-base.html +3 -3
  73. package/dist/docs/example-agents/oncall.html +3 -3
  74. package/dist/docs/example-agents/security-reviewer.html +5 -5
  75. package/dist/docs/example-agents/slack-agent.html +3 -3
  76. package/dist/docs/example-agents/weather-agent.html +3 -3
  77. package/dist/docs/guides/agent-to-agent.html +3 -3
  78. package/dist/docs/guides/cloud-runtime.html +3 -3
  79. package/dist/docs/guides/github.html +3 -3
  80. package/dist/docs/guides/human-in-the-loop.html +3 -3
  81. package/dist/docs/guides/mcp-oauth.html +6 -5
  82. package/dist/docs/guides/slack.html +5 -5
  83. package/dist/docs/guides/webhooks.html +3 -3
  84. package/dist/docs/hashmap.json +1 -1
  85. package/dist/docs/hillclimbing.html +3 -3
  86. package/dist/docs/index.html +3 -3
  87. package/dist/docs/quickstart.html +3 -3
  88. package/dist/docs/reference/agent-config.html +3 -3
  89. package/dist/docs/reference/channels.html +3 -3
  90. package/dist/docs/reference/cli.html +3 -3
  91. package/dist/docs/reference/connections.html +14 -7
  92. package/dist/docs/reference/hooks.html +3 -3
  93. package/dist/docs/reference/http-api.html +3 -3
  94. package/dist/docs/reference/instructions.html +3 -3
  95. package/dist/docs/reference/playground.html +3 -3
  96. package/dist/docs/reference/project-layout.html +3 -3
  97. package/dist/docs/reference/prompt.html +3 -3
  98. package/dist/docs/reference/schedules.html +3 -3
  99. package/dist/docs/reference/sessions.html +3 -3
  100. package/dist/docs/reference/skills.html +3 -3
  101. package/dist/docs/reference/subagents.html +3 -3
  102. package/dist/docs/reference/tools.html +3 -3
  103. package/dist/docs/scaffolding-agents.html +3 -3
  104. package/dist/docs/storage.html +3 -3
  105. package/dist/docs/troubleshooting.html +3 -3
  106. package/dist/evals/assertions.d.ts +190 -0
  107. package/dist/evals/assertions.d.ts.map +1 -0
  108. package/dist/evals/assertions.js +461 -0
  109. package/dist/evals/expect.d.ts +95 -0
  110. package/dist/evals/expect.d.ts.map +1 -0
  111. package/dist/evals/expect.js +194 -0
  112. package/dist/evals/judge.d.ts +133 -0
  113. package/dist/evals/judge.d.ts.map +1 -0
  114. package/dist/evals/judge.js +228 -0
  115. package/dist/evals/loaders.d.ts +51 -0
  116. package/dist/evals/loaders.d.ts.map +1 -0
  117. package/dist/evals/loaders.js +124 -0
  118. package/dist/evals/matchers.d.ts +95 -0
  119. package/dist/evals/matchers.d.ts.map +1 -0
  120. package/dist/evals/matchers.js +145 -0
  121. package/dist/evals/reporters.d.ts +70 -0
  122. package/dist/evals/reporters.d.ts.map +1 -0
  123. package/dist/evals/reporters.js +221 -0
  124. package/dist/evals/results.d.ts +103 -0
  125. package/dist/evals/results.d.ts.map +1 -0
  126. package/dist/evals/results.js +28 -0
  127. package/dist/evals/run-facts.d.ts +77 -0
  128. package/dist/evals/run-facts.d.ts.map +1 -0
  129. package/dist/evals/run-facts.js +187 -0
  130. package/dist/evals.d.ts +118 -31
  131. package/dist/evals.d.ts.map +1 -1
  132. package/dist/evals.js +46 -12
  133. package/dist/index.d.ts +1 -1
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +1 -1
  136. package/dist/internal/builtin-tools/index.d.ts +10 -0
  137. package/dist/internal/builtin-tools/index.d.ts.map +1 -0
  138. package/dist/internal/builtin-tools/index.js +27 -0
  139. package/dist/internal/builtin-tools/reminders.d.ts +9 -0
  140. package/dist/internal/builtin-tools/reminders.d.ts.map +1 -0
  141. package/dist/internal/builtin-tools/reminders.js +138 -0
  142. package/dist/internal/cli-ax.d.ts +27 -0
  143. package/dist/internal/cli-ax.d.ts.map +1 -1
  144. package/dist/internal/cli-ax.js +90 -12
  145. package/dist/internal/cli-mcp.d.ts +8 -0
  146. package/dist/internal/cli-mcp.d.ts.map +1 -1
  147. package/dist/internal/cli-mcp.js +98 -0
  148. package/dist/internal/cli-slack.d.ts +29 -1
  149. package/dist/internal/cli-slack.d.ts.map +1 -1
  150. package/dist/internal/cli-slack.js +799 -13
  151. package/dist/internal/cursor-event-relay.d.ts +30 -0
  152. package/dist/internal/cursor-event-relay.d.ts.map +1 -1
  153. package/dist/internal/cursor-event-relay.js +37 -0
  154. package/dist/internal/deploy-client.d.ts +7 -0
  155. package/dist/internal/deploy-client.d.ts.map +1 -1
  156. package/dist/internal/deploy-client.js +9 -0
  157. package/dist/internal/discovery.d.ts.map +1 -1
  158. package/dist/internal/discovery.js +70 -9
  159. package/dist/internal/distribution.d.ts.map +1 -1
  160. package/dist/internal/distribution.js +2 -0
  161. package/dist/internal/eval-judge-model.d.ts +59 -0
  162. package/dist/internal/eval-judge-model.d.ts.map +1 -0
  163. package/dist/internal/eval-judge-model.js +131 -0
  164. package/dist/internal/eval-run-store.d.ts.map +1 -1
  165. package/dist/internal/eval-run-store.js +12 -20
  166. package/dist/internal/eval-runner.d.ts +31 -25
  167. package/dist/internal/eval-runner.d.ts.map +1 -1
  168. package/dist/internal/eval-runner.js +329 -126
  169. package/dist/internal/evals-client.d.ts.map +1 -1
  170. package/dist/internal/evals-client.js +4 -1
  171. package/dist/internal/local-env.d.ts +8 -0
  172. package/dist/internal/local-env.d.ts.map +1 -0
  173. package/dist/internal/local-env.js +47 -0
  174. package/dist/internal/playground/static.d.ts +3 -0
  175. package/dist/internal/playground/static.d.ts.map +1 -1
  176. package/dist/internal/playground/static.js +3 -0
  177. package/dist/internal/reminder-runner.d.ts +7 -0
  178. package/dist/internal/reminder-runner.d.ts.map +1 -1
  179. package/dist/internal/reminder-runner.js +21 -0
  180. package/dist/internal/run-client.d.ts +15 -0
  181. package/dist/internal/run-client.d.ts.map +1 -1
  182. package/dist/internal/run-client.js +3 -2
  183. package/dist/internal/sdk-runner.d.ts +51 -1
  184. package/dist/internal/sdk-runner.d.ts.map +1 -1
  185. package/dist/internal/sdk-runner.js +176 -36
  186. package/dist/internal/server.d.ts.map +1 -1
  187. package/dist/internal/server.js +11 -1
  188. package/dist/internal/session-engine.d.ts +18 -5
  189. package/dist/internal/session-engine.d.ts.map +1 -1
  190. package/dist/internal/session-engine.js +81 -19
  191. package/dist/internal/slack-provision-client.d.ts +133 -0
  192. package/dist/internal/slack-provision-client.d.ts.map +1 -0
  193. package/dist/internal/slack-provision-client.js +286 -0
  194. package/dist/playground/assets/cursor-icons-16-f_W_ogc-.woff2 +0 -0
  195. package/dist/playground/assets/index-DRjS5klQ.js +85 -0
  196. package/dist/playground/assets/index-TCDs-UhZ.css +1 -0
  197. package/dist/playground/index.html +2 -2
  198. package/dist/types.d.ts +98 -4
  199. package/dist/types.d.ts.map +1 -1
  200. package/dist/types.js +26 -0
  201. package/docs/example-agents/security-reviewer.md +1 -1
  202. package/docs/guides/mcp-oauth.md +10 -5
  203. package/docs/guides/slack.md +3 -2
  204. package/docs/reference/connections.md +28 -18
  205. package/package.json +20 -2
  206. package/skills/create-agent/SKILL.md +15 -7
  207. package/skills/debug/SKILL.md +3 -1
  208. package/skills/mcp-auth/SKILL.md +1 -1
  209. package/skills/setup-slack/SKILL.md +177 -11
  210. package/src/bin/agent-serve.ts +63 -2
  211. package/src/channels/slack/api.ts +16 -3
  212. package/src/channels/slack/auth.ts +16 -1
  213. package/src/channels/slack/blocks.ts +139 -0
  214. package/src/channels/slack/cursor-account.ts +1 -0
  215. package/src/channels/slack/defaults.ts +32 -4
  216. package/src/channels/slack/dispatch.ts +6 -19
  217. package/src/channels/slack/inbound.ts +6 -1
  218. package/src/channels/slack/index.ts +2 -0
  219. package/src/channels/slack/init.ts +3 -0
  220. package/src/channels/slack/interactive.ts +184 -19
  221. package/src/channels/slack/manifest.ts +37 -6
  222. package/src/channels/slack/message-body.ts +90 -0
  223. package/src/channels/slack/setup.ts +16 -2
  224. package/src/channels/slack/slack-channel.ts +37 -6
  225. package/src/channels/slack/thread-context.ts +1 -69
  226. package/src/channels/slack/types.ts +105 -1
  227. package/src/connections.ts +4 -1
  228. package/src/evals/assertions.ts +704 -0
  229. package/src/evals/expect.ts +272 -0
  230. package/src/evals/judge.ts +346 -0
  231. package/src/evals/loaders.ts +113 -0
  232. package/src/evals/matchers.ts +246 -0
  233. package/src/evals/reporters.ts +274 -0
  234. package/src/evals/results.ts +132 -0
  235. package/src/evals/run-facts.ts +274 -0
  236. package/src/evals.ts +205 -42
  237. package/src/index.ts +2 -0
  238. package/src/internal/builtin-tools/index.ts +40 -0
  239. package/src/internal/builtin-tools/reminders.ts +158 -0
  240. package/src/internal/cli-ax.ts +134 -15
  241. package/src/internal/cli-mcp.ts +118 -5
  242. package/src/internal/cli-slack.ts +1017 -15
  243. package/src/internal/cursor-event-relay.ts +67 -0
  244. package/src/internal/deploy-client.ts +10 -0
  245. package/src/internal/discovery.ts +83 -5
  246. package/src/internal/distribution.ts +2 -0
  247. package/src/internal/eval-judge-model.ts +148 -0
  248. package/src/internal/eval-run-store.ts +10 -14
  249. package/src/internal/eval-runner.ts +460 -214
  250. package/src/internal/evals-client.ts +5 -0
  251. package/src/internal/local-env.ts +53 -0
  252. package/src/internal/playground/static.ts +3 -0
  253. package/src/internal/reminder-runner.ts +30 -0
  254. package/src/internal/run-client.ts +17 -1
  255. package/src/internal/sdk-runner.ts +234 -35
  256. package/src/internal/server.ts +12 -0
  257. package/src/internal/session-engine.ts +103 -21
  258. package/src/internal/slack-provision-client.ts +442 -0
  259. package/src/types.ts +125 -4
  260. package/dist/channels/slack/post-update-delivery.d.ts +0 -85
  261. package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
  262. package/dist/docs/assets/chunks/@localSearchIndexroot.DZtu0ZIc.js +0 -1
  263. package/dist/internal/json-dir-store.d.ts +0 -32
  264. package/dist/internal/json-dir-store.d.ts.map +0 -1
  265. package/dist/internal/persistence-coordinator.d.ts +0 -127
  266. package/dist/internal/persistence-coordinator.d.ts.map +0 -1
  267. package/dist/persistence.d.ts +0 -184
  268. package/dist/persistence.d.ts.map +0 -1
  269. package/dist/playground/assets/cursor-icons-16-CQ50JpfO.woff2 +0 -0
  270. package/dist/playground/assets/index-Bwl4Onx4.js +0 -85
  271. package/dist/playground/assets/index-ByV4nfch.css +0 -1
  272. /package/dist/docs/assets/{example-agents_security-reviewer.md.BZSNycMf.lean.js → example-agents_security-reviewer.md.Dhj_m7_B.lean.js} +0 -0
  273. /package/dist/docs/assets/{guides_slack.md.FWale6Ip.lean.js → guides_slack.md.D_xFKlnF.lean.js} +0 -0
@@ -18,6 +18,29 @@ import {
18
18
 
19
19
  export { RelayOffsetStore };
20
20
 
21
+ /**
22
+ * Comment snapshot from scm-events compact metadata. Carries what the GitHub
23
+ * channel's `issue_comment` / `pull_request_review_comment` Zod schemas
24
+ * require so relayed comment wakes parse without re-fetching the comment.
25
+ */
26
+ export type CursorScmCommentMeta = {
27
+ id: number;
28
+ body: string;
29
+ htmlUrl: string;
30
+ authorLogin?: string;
31
+ /**
32
+ * GitHub `user.type` ("User", "Bot", …). Carried onto the stubbed
33
+ * `comment.user` / `sender` so `isGitHubAppBotAuthor` keeps recognizing
34
+ * the agent's own comments on the relay path (self/bot-loop gate).
35
+ */
36
+ authorType?: string;
37
+ /** Review comments only. */
38
+ path?: string;
39
+ line?: number;
40
+ pullRequestReviewId?: number;
41
+ inReplyToId?: number;
42
+ };
43
+
21
44
  /** PR snapshot from scm-events compact metadata (Sand-style; no raw body). */
22
45
  export type CursorScmPullRequestMeta = {
23
46
  number: number;
@@ -53,6 +76,11 @@ export interface CursorScmEvent {
53
76
  * stub a Zod-valid GitHub `pull_request` webhook body.
54
77
  */
55
78
  pullRequest?: CursorScmPullRequestMeta;
79
+ /**
80
+ * Comment snapshot when the backend saw `body.comment`. Enough to stub a
81
+ * Zod-valid `issue_comment` / `pull_request_review_comment` webhook body.
82
+ */
83
+ comment?: CursorScmCommentMeta;
56
84
  /** GitHub-side event time from the payload, when present. */
57
85
  occurredAtMs?: number;
58
86
  }
@@ -114,6 +142,8 @@ export function formatCursorScmEventLog(event: {
114
142
  * Minimal GitHub webhook body from an SCM-events metadata envelope.
115
143
  * When `pullRequest` has title + head/base refs+shas, emits a Zod-valid
116
144
  * `pull_request` object for `onPullRequest`; otherwise identity-only stubs.
145
+ * When `comment` is present, emits a Zod-valid `comment` object so relayed
146
+ * `issue_comment` / `pull_request_review_comment` deliveries dispatch.
117
147
  */
118
148
  export function scmMetadataToGitHubPayload(event: {
119
149
  repo: string;
@@ -121,6 +151,7 @@ export function scmMetadataToGitHubPayload(event: {
121
151
  prNumber?: number;
122
152
  prUrl?: string;
123
153
  pullRequest?: CursorScmPullRequestMeta;
154
+ comment?: CursorScmCommentMeta;
124
155
  }): Record<string, unknown> {
125
156
  const slash = event.repo.indexOf("/");
126
157
  const owner = slash === -1 ? "" : event.repo.slice(0, slash);
@@ -143,6 +174,42 @@ export function scmMetadataToGitHubPayload(event: {
143
174
  };
144
175
  payload.action = event.action;
145
176
 
177
+ const commentMeta = event.comment;
178
+ if (commentMeta !== undefined) {
179
+ const comment: Record<string, unknown> = {
180
+ id: commentMeta.id,
181
+ body: commentMeta.body,
182
+ html_url: commentMeta.htmlUrl,
183
+ };
184
+ if (commentMeta.authorLogin !== undefined) {
185
+ const author: Record<string, unknown> = {
186
+ login: commentMeta.authorLogin,
187
+ };
188
+ if (commentMeta.authorType !== undefined) {
189
+ // Without user.type the isGitHubAppBotAuthor gate fails open and the
190
+ // agent's own relayed comments could wake it again (bot loop).
191
+ author.type = commentMeta.authorType;
192
+ }
193
+ comment.user = author;
194
+ // The comment author is the closest thing the envelope has to the
195
+ // webhook sender; channels use it for self/bot-loop gates.
196
+ payload.sender = { ...author };
197
+ }
198
+ if (commentMeta.path !== undefined) {
199
+ comment.path = commentMeta.path;
200
+ }
201
+ if (commentMeta.line !== undefined) {
202
+ comment.line = commentMeta.line;
203
+ }
204
+ if (commentMeta.pullRequestReviewId !== undefined) {
205
+ comment.pull_request_review_id = commentMeta.pullRequestReviewId;
206
+ }
207
+ if (commentMeta.inReplyToId !== undefined) {
208
+ comment.in_reply_to_id = commentMeta.inReplyToId;
209
+ }
210
+ payload.comment = comment;
211
+ }
212
+
146
213
  const title = prMeta?.title;
147
214
  const headRef = prMeta?.headRef;
148
215
  const headSha = prMeta?.headSha;
@@ -529,6 +529,16 @@ export class AgentServeDeployClient {
529
529
  return `${this.backendUrl}${engineAlias}`;
530
530
  }
531
531
 
532
+ /**
533
+ * Stable remote MCP gateway URL for a deployment, on the user-API-key
534
+ * surface (headless / CLI, `agentkit login` credential). The gateway
535
+ * mints/refreshes engineAccess server-side and proxies `/v1/mcp` to the
536
+ * pod, so a signed-in client never sees a pod hostname or port token.
537
+ */
538
+ mcpGatewayUrl(teamId: number, slug: string): string {
539
+ return `${this.backendUrl}/internal/agent-serve/mcp/${teamId}/${encodeURIComponent(slug)}`;
540
+ }
541
+
532
542
  private async request(args: {
533
543
  method: "GET" | "POST" | "PUT" | "DELETE";
534
544
  path: string;
@@ -26,9 +26,12 @@ import {
26
26
  type AgentHostingOptions,
27
27
  type AgentProject,
28
28
  type AgentProjectInfo,
29
+ type AgentRuntime,
30
+ type BuiltinToolsConfig,
29
31
  type ChannelDefinition,
30
32
  type ConnectionDefinition,
31
33
  type ConnectionTransport,
34
+ cursorAccountServersHasMixedWildcard,
32
35
  DEFAULT_MODEL,
33
36
  type Diagnostic,
34
37
  type DiscoveredAB,
@@ -43,6 +46,7 @@ import {
43
46
  type InstructionsDefinition,
44
47
  MAX_RUNNING_TURNS_LIMIT,
45
48
  type ModelSetting,
49
+ normalizeCursorAccountServers,
46
50
  type ResolvedAgent,
47
51
  type ScheduleDefinition,
48
52
  type SeedFile,
@@ -54,6 +58,7 @@ import {
54
58
  import { registerAuthoredModuleLoaders } from "./authored-loaders.js";
55
59
  import { normalizePositiveInt } from "./bounded-int.js";
56
60
  import { getDefinitionKind } from "./brand.js";
61
+ import { builtinTools } from "./builtin-tools/index.js";
57
62
  import { isValidCron } from "./cron.js";
58
63
  import { parseFrontmatter } from "./frontmatter.js";
59
64
  import {
@@ -339,6 +344,13 @@ async function loadAgent(
339
344
  // warn that they exist.
340
345
  if (!options.isRoot) {
341
346
  await warnUnsupportedSubagentSlots(ctx, agentDir);
347
+ if (config?.builtinTools !== undefined) {
348
+ ctx.diagnostics.push({
349
+ severity: "warning",
350
+ path: displayPath(ctx, join(agentDir, "agent.ts")),
351
+ message: "builtinTools is not supported on subagents; ignoring.",
352
+ });
353
+ }
342
354
  return {
343
355
  name,
344
356
  ...(config?.description === undefined
@@ -368,11 +380,23 @@ async function loadAgent(
368
380
  // `send({ cloud })` merges it under cloudOverride for handoff sessions.
369
381
  const cloud = config?.cloud;
370
382
  const localCwd = resolveAgentCwd(ctx, config?.local?.cwd);
383
+ const localWorkspaceDir = resolveAgentCwd(ctx, config?.local?.workspaceDir);
384
+ const localSandbox = config?.local?.sandbox === true;
385
+ if (localCwd !== undefined && localWorkspaceDir !== undefined) {
386
+ ctx.diagnostics.push({
387
+ severity: "warning",
388
+ path: displayPath(ctx, join(agentDir, "agent.ts")),
389
+ message:
390
+ "local.workspaceDir pins every session to one directory, so local.cwd is unused. Drop one of them.",
391
+ });
392
+ }
371
393
  const local =
372
- localCwd === undefined
394
+ localCwd === undefined && localWorkspaceDir === undefined && !localSandbox
373
395
  ? undefined
374
396
  : {
375
397
  cwd: localCwd,
398
+ workspaceDir: localWorkspaceDir,
399
+ sandbox: localSandbox,
376
400
  };
377
401
  const hosting = resolveHosting(ctx, agentDir, config?.hosting);
378
402
  const concurrency = resolveConcurrency(ctx, agentDir, config?.concurrency);
@@ -387,6 +411,8 @@ async function loadAgent(
387
411
  });
388
412
  }
389
413
 
414
+ appendBuiltinTools(ctx, agentDir, tools, config?.builtinTools, runtime);
415
+
390
416
  return {
391
417
  name,
392
418
  description: config?.description,
@@ -889,11 +915,10 @@ function connectionTransport(
889
915
  connection: ConnectionDefinition
890
916
  ): ConnectionTransport | undefined {
891
917
  if ("cursorAccount" in connection && connection.cursorAccount === true) {
918
+ const servers = normalizeCursorAccountServers(connection.servers);
892
919
  return {
893
920
  cursorAccount: true,
894
- ...(connection.servers === undefined
895
- ? {}
896
- : { servers: connection.servers }),
921
+ ...(servers === undefined ? {} : { servers }),
897
922
  };
898
923
  }
899
924
  if ("agent" in connection && !isBlank(connection.agent)) {
@@ -1035,6 +1060,19 @@ async function loadConnections(
1035
1060
  });
1036
1061
  continue;
1037
1062
  }
1063
+ if (
1064
+ "cursorAccount" in connection &&
1065
+ connection.cursorAccount === true &&
1066
+ cursorAccountServersHasMixedWildcard(connection.servers)
1067
+ ) {
1068
+ ctx.diagnostics.push({
1069
+ severity: "error",
1070
+ path: displayPath(ctx, entryPath),
1071
+ message:
1072
+ 'Cursor account MCP connection `servers` cannot mix `"*"` with connector names. Use `"*"` / `["*"]` (or omit `servers`) for every connected server, or list only concrete connector names.',
1073
+ });
1074
+ continue;
1075
+ }
1038
1076
  const transport = connectionTransport(connection);
1039
1077
  if (transport === undefined) {
1040
1078
  ctx.diagnostics.push({
@@ -1055,7 +1093,7 @@ async function loadConnections(
1055
1093
  severity: "error",
1056
1094
  path: displayPath(ctx, entryPath),
1057
1095
  message:
1058
- "Cursor account MCP connection `servers` must be a non-empty list of connector names (or omitted to expose every connected server).",
1096
+ 'Cursor account MCP connection `servers` must be a non-empty list of connector names, `"*"` / `["*"]` for every connected server, or omitted for the same all-connectors behavior.',
1059
1097
  });
1060
1098
  continue;
1061
1099
  }
@@ -1135,6 +1173,46 @@ async function warnUnsupportedSubagentSlots(
1135
1173
  }
1136
1174
  }
1137
1175
 
1176
+ /**
1177
+ * Append enabled built-in tools after authored tools. Authored tools with
1178
+ * the same name win; built-ins are server tools, so cloud runtimes get a
1179
+ * warning instead of tools.
1180
+ */
1181
+ function appendBuiltinTools(
1182
+ ctx: DiscoveryContext,
1183
+ agentDir: string,
1184
+ tools: DiscoveredTool[],
1185
+ config: BuiltinToolsConfig | undefined,
1186
+ runtime: AgentRuntime
1187
+ ): void {
1188
+ const builtin = builtinTools(config);
1189
+ if (builtin.length === 0) {
1190
+ return;
1191
+ }
1192
+ const agentPath = displayPath(ctx, join(agentDir, "agent.ts"));
1193
+ if (runtime === "cloud") {
1194
+ ctx.diagnostics.push({
1195
+ severity: "warning",
1196
+ path: agentPath,
1197
+ message:
1198
+ "builtinTools are in-process server tools and are not available on cloud agents; they are skipped.",
1199
+ });
1200
+ return;
1201
+ }
1202
+ const authored = new Set(tools.map((tool) => tool.name));
1203
+ for (const tool of builtin) {
1204
+ if (authored.has(tool.name)) {
1205
+ ctx.diagnostics.push({
1206
+ severity: "warning",
1207
+ path: agentPath,
1208
+ message: `Authored tool "${tool.name}" shadows the built-in tool of the same name; the authored tool wins.`,
1209
+ });
1210
+ continue;
1211
+ }
1212
+ tools.push(tool);
1213
+ }
1214
+ }
1215
+
1138
1216
  function warnCloudRuntimeLimitations(
1139
1217
  ctx: DiscoveryContext,
1140
1218
  agentDir: string,
@@ -102,6 +102,8 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
102
102
  ["hooks", "hooks.js"],
103
103
  ["prompt", "prompt.js"],
104
104
  ["evals", "evals.js"],
105
+ ["evals/reporters", "evals/reporters.js"],
106
+ ["evals/loaders", "evals/loaders.js"],
105
107
  ["ab", "ab.js"],
106
108
  ["storage", "storage.js"],
107
109
  ["storage/file-kv", "storage-backends/file-kv.js"],
@@ -0,0 +1,148 @@
1
+ /**
2
+ * The model call behind `t.judge.*`.
3
+ *
4
+ * Grading is completion-only in intent: the judge reads a prompt and returns a
5
+ * choice. It is nonetheless a real SDK session, and its prompt embeds output
6
+ * from the agent under test — attacker-controlled text in exactly the way a
7
+ * prompt injection needs. A reply that talks the judge into running a tool would
8
+ * do so on the machine running the eval CLI, under the runner's credentials.
9
+ *
10
+ * The session is therefore confined on every axis the SDK exposes:
11
+ *
12
+ * - `sandboxOptions.enabled` so any tool call the judge is talked into is
13
+ * confined rather than run directly against the host.
14
+ * - `mcpServers: {}` so no MCP surface is reachable.
15
+ * - `settingSources: []` plus an empty temp `cwd`, so there is no repo to act on
16
+ * and no ambient `AGENTS.md` / `.cursor` rule can steer a verdict.
17
+ *
18
+ * The prompt side is hardened separately: `evals/judge.ts` fences untrusted
19
+ * content behind a per-call boundary. Both halves matter — this one limits blast
20
+ * radius, that one removes the instruction channel.
21
+ *
22
+ * Grading also declines outright when the credential's backend and the SDK's
23
+ * backend disagree, rather than sending a key somewhere it was not minted for
24
+ * (see {@link assertJudgeBackendMatch}).
25
+ */
26
+
27
+ import { mkdtemp, rm } from "node:fs/promises";
28
+ import { tmpdir } from "node:os";
29
+ import { join } from "node:path";
30
+ import type { EvalJudgeCaller } from "../evals/judge.js";
31
+ import { EvalJudgeUnavailableError } from "../evals/judge.js";
32
+ import type { ModelSetting } from "../types.js";
33
+ import {
34
+ DEFAULT_CURSOR_BACKEND_URL,
35
+ resolveApiKey,
36
+ SIGN_IN_HINT,
37
+ } from "./cursor/credentials.js";
38
+
39
+ /** Env override for the default judge model (below `evals.config.ts`). */
40
+ export const EVAL_JUDGE_MODEL_ENV = "AGENTKIT_EVAL_JUDGE_MODEL";
41
+
42
+ /**
43
+ * Backend the Cursor SDK will actually talk to.
44
+ *
45
+ * `Agent.create` takes a credential but no backend, so the SDK picks its own
46
+ * host from `CURSOR_API_BASE_URL`. Kept next to {@link assertJudgeBackendMatch}
47
+ * so the two stay in step if the SDK's resolution changes.
48
+ */
49
+ function sdkBackendUrl(): string {
50
+ const configured = process.env.CURSOR_API_BASE_URL?.trim();
51
+ return trimTrailingSlash(
52
+ configured === undefined || configured === ""
53
+ ? DEFAULT_CURSOR_BACKEND_URL
54
+ : configured
55
+ );
56
+ }
57
+
58
+ function trimTrailingSlash(url: string): string {
59
+ return url.replace(/\/+$/, "");
60
+ }
61
+
62
+ /**
63
+ * Refuse to grade when the judge credential belongs to a different backend than
64
+ * the SDK will send it to.
65
+ *
66
+ * `resolveApiKey` resolves against `AGENT_SERVE_CURSOR_BACKEND_URL`, which the
67
+ * SDK does not read. When only that override is set, the key and the judge
68
+ * prompt — which embeds agent output — would go to the default host instead of
69
+ * the intended one. There is no backend field on `AgentOptions` to reconcile
70
+ * them, so the honest move is to decline rather than send a credential
71
+ * somewhere it was not minted for.
72
+ */
73
+ export function assertJudgeBackendMatch(
74
+ credentialBackendUrl: string,
75
+ sdkBackend: string = sdkBackendUrl()
76
+ ): void {
77
+ const credentialBackend = trimTrailingSlash(credentialBackendUrl);
78
+ if (credentialBackend === sdkBackend) {
79
+ return;
80
+ }
81
+ throw new EvalJudgeUnavailableError(
82
+ `eval judge credential is scoped to ${credentialBackend}, but the Cursor SDK would send it to ${sdkBackend}. ` +
83
+ "Set CURSOR_API_BASE_URL to the same backend (the SDK does not read AGENT_SERVE_CURSOR_BACKEND_URL)."
84
+ );
85
+ }
86
+
87
+ /**
88
+ * Resolve the judge model, innermost first: per-call → per-eval →
89
+ * `evals.config.ts` → {@link EVAL_JUDGE_MODEL_ENV}.
90
+ */
91
+ export function resolveJudgeModel(layers: {
92
+ call?: ModelSetting;
93
+ evalLevel?: ModelSetting;
94
+ config?: ModelSetting;
95
+ env?: string | undefined;
96
+ }): ModelSetting | undefined {
97
+ const envModel = layers.env?.trim();
98
+ return (
99
+ layers.call ??
100
+ layers.evalLevel ??
101
+ layers.config ??
102
+ (envModel === undefined || envModel === "" ? undefined : envModel)
103
+ );
104
+ }
105
+
106
+ /**
107
+ * Ask the judge model for a grade.
108
+ *
109
+ * Throws {@link EvalJudgeUnavailableError} when no credentials are available so
110
+ * the runner can skip the eval visibly instead of reporting a spurious failure.
111
+ */
112
+ export const callJudgeModel: EvalJudgeCaller = async ({ prompt, model }) => {
113
+ const resolved = await resolveApiKey();
114
+ if (resolved === undefined) {
115
+ throw new EvalJudgeUnavailableError(
116
+ `no Cursor credentials for the eval judge. ${SIGN_IN_HINT}`
117
+ );
118
+ }
119
+ assertJudgeBackendMatch(resolved.backendUrl);
120
+ // Imported lazily so a tree of fully deterministic evals never loads the SDK.
121
+ const { Agent } = await import("@cursor/sdk");
122
+ const cwd = await mkdtemp(join(tmpdir(), "agentkit-eval-judge-"));
123
+ const agent = await Agent.create({
124
+ apiKey: resolved.apiKey,
125
+ model: typeof model === "string" ? { id: model } : model,
126
+ // See the module comment: grading embeds untrusted agent output, so the
127
+ // session gets no MCP surface, no ambient settings, an empty working
128
+ // directory, and a sandbox around anything it does attempt.
129
+ mcpServers: {},
130
+ local: {
131
+ cwd,
132
+ settingSources: [],
133
+ sandboxOptions: { enabled: true },
134
+ },
135
+ });
136
+ try {
137
+ const run = await agent.send(prompt);
138
+ const result = await run.wait();
139
+ if (result.status === "error" || result.status === "cancelled") {
140
+ const detail = result.error?.message ?? result.result ?? result.status;
141
+ throw new Error(`eval judge run failed: ${detail}`);
142
+ }
143
+ return result.result ?? "";
144
+ } finally {
145
+ agent.close();
146
+ await rm(cwd, { recursive: true, force: true }).catch(() => undefined);
147
+ }
148
+ };
@@ -173,6 +173,8 @@ export class EvalRunStore {
173
173
  summary: {
174
174
  passed: 0,
175
175
  failed: 0,
176
+ scored: 0,
177
+ skipped: 0,
176
178
  total: cases.length,
177
179
  done: 0,
178
180
  },
@@ -474,6 +476,9 @@ export class EvalRunStore {
474
476
  const alreadyCounted = c.status === "done";
475
477
  c.status = "done";
476
478
  c.ok = result.ok;
479
+ c.verdict = result.verdict;
480
+ c.skipReason = result.skipReason;
481
+ c.metadata = result.metadata;
477
482
  c.assertions = result.assertions;
478
483
  c.durationMs = result.durationMs;
479
484
  c.logs = result.logs;
@@ -502,11 +507,8 @@ export class EvalRunStore {
502
507
  return;
503
508
  }
504
509
  run.summary.done += 1;
505
- if (result.ok) {
506
- run.summary.passed += 1;
507
- } else {
508
- run.summary.failed += 1;
509
- }
510
+ const verdict = result.verdict ?? (result.ok ? "passed" : "failed");
511
+ run.summary[verdict] = (run.summary[verdict] ?? 0) + 1;
510
512
  }
511
513
  }
512
514
 
@@ -539,18 +541,12 @@ function markCancelledRun(run: EvalRunSnapshot): void {
539
541
  }
540
542
 
541
543
  function reconcileRunSummary(run: EvalRunSnapshot): void {
542
- let passed = 0;
543
- let failed = 0;
544
+ const counts = { passed: 0, failed: 0, scored: 0, skipped: 0 };
544
545
  for (const c of run.cases) {
545
- if (c.ok === true) {
546
- passed += 1;
547
- } else {
548
- failed += 1;
549
- }
546
+ counts[c.verdict ?? (c.ok === true ? "passed" : "failed")] += 1;
550
547
  }
551
548
  run.summary = {
552
- passed,
553
- failed,
549
+ ...counts,
554
550
  total: run.cases.length,
555
551
  done: run.cases.length,
556
552
  };