@cursor/july 0.1.26 → 0.1.28

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 (324) hide show
  1. package/dist/ab.d.ts +6 -0
  2. package/dist/ab.d.ts.map +1 -1
  3. package/dist/ab.js +1 -0
  4. package/dist/artifacts.d.ts +34 -0
  5. package/dist/artifacts.d.ts.map +1 -0
  6. package/dist/artifacts.js +57 -0
  7. package/dist/bin/agent-serve.js +43 -12
  8. package/dist/channels/github/github-channel.d.ts +1 -1
  9. package/dist/channels/github/github-channel.d.ts.map +1 -1
  10. package/dist/channels/github/github-channel.js +14 -1
  11. package/dist/channels/github/types.d.ts +6 -1
  12. package/dist/channels/github/types.d.ts.map +1 -1
  13. package/dist/channels/slack/api.d.ts +2 -1
  14. package/dist/channels/slack/api.d.ts.map +1 -1
  15. package/dist/channels/slack/api.js +1 -0
  16. package/dist/channels/slack/auth.d.ts +13 -13
  17. package/dist/channels/slack/auth.d.ts.map +1 -1
  18. package/dist/channels/slack/auth.js +19 -10
  19. package/dist/channels/slack/cursor-account.d.ts +2 -1
  20. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  21. package/dist/channels/slack/cursor-account.js +3 -1
  22. package/dist/channels/slack/defaults.d.ts +7 -4
  23. package/dist/channels/slack/defaults.d.ts.map +1 -1
  24. package/dist/channels/slack/defaults.js +14 -4
  25. package/dist/channels/slack/dispatch.d.ts +10 -1
  26. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  27. package/dist/channels/slack/dispatch.js +59 -21
  28. package/dist/channels/slack/external-policy.d.ts +27 -0
  29. package/dist/channels/slack/external-policy.d.ts.map +1 -0
  30. package/dist/channels/slack/external-policy.js +53 -0
  31. package/dist/channels/slack/index.d.ts +1 -0
  32. package/dist/channels/slack/index.d.ts.map +1 -1
  33. package/dist/channels/slack/index.js +1 -0
  34. package/dist/channels/slack/interactive.d.ts +8 -1
  35. package/dist/channels/slack/interactive.d.ts.map +1 -1
  36. package/dist/channels/slack/interactive.js +43 -15
  37. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  38. package/dist/channels/slack/slack-channel.js +22 -8
  39. package/dist/channels/slack/types.d.ts +16 -1
  40. package/dist/channels/slack/types.d.ts.map +1 -1
  41. package/dist/docs/404.html +2 -2
  42. package/dist/docs/ab.html +3 -3
  43. package/dist/docs/assets/{app.DYcC9FY-.js → app.CqjrYaT2.js} +1 -1
  44. package/dist/docs/assets/chunks/@localSearchIndexroot.VWQoPFJ1.js +1 -0
  45. package/dist/docs/assets/chunks/{VPLocalSearchBox.o4N_knTV.js → VPLocalSearchBox.ag-MwUel.js} +1 -1
  46. package/dist/docs/assets/chunks/{theme.DQ-njyo0.js → theme.BS-DJWat.js} +2 -2
  47. package/dist/docs/assets/{guides_slack.md.D_xFKlnF.js → guides_slack.md.CjmJSvZS.js} +8 -4
  48. package/dist/docs/assets/guides_slack.md.CjmJSvZS.lean.js +1 -0
  49. package/dist/docs/assets/guides_webhooks.md.wSOYas3X.js +183 -0
  50. package/dist/docs/assets/{guides_webhooks.md.B1EswtUu.lean.js → guides_webhooks.md.wSOYas3X.lean.js} +1 -1
  51. package/dist/docs/assets/{index.md.Dfv5ic9t.js → index.md.CH_s5uZe.js} +1 -1
  52. package/dist/docs/assets/{reference_channels.md.DdmiKgqf.js → reference_channels.md.CDhTRfUz.js} +2 -2
  53. package/dist/docs/assets/{reference_channels.md.DdmiKgqf.lean.js → reference_channels.md.CDhTRfUz.lean.js} +1 -1
  54. package/dist/docs/building-with-agents.html +3 -3
  55. package/dist/docs/concepts.html +3 -3
  56. package/dist/docs/deployment.html +3 -3
  57. package/dist/docs/evals.html +3 -3
  58. package/dist/docs/example-agents/approval-buddy.html +3 -3
  59. package/dist/docs/example-agents/benny.html +3 -3
  60. package/dist/docs/example-agents/bugbot.html +3 -3
  61. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  62. package/dist/docs/example-agents/codeowners-review.html +3 -3
  63. package/dist/docs/example-agents/concierge.html +3 -3
  64. package/dist/docs/example-agents/fsd.html +3 -3
  65. package/dist/docs/example-agents/index.html +3 -3
  66. package/dist/docs/example-agents/knowledge-base.html +3 -3
  67. package/dist/docs/example-agents/oncall.html +3 -3
  68. package/dist/docs/example-agents/security-reviewer.html +3 -3
  69. package/dist/docs/example-agents/slack-agent.html +3 -3
  70. package/dist/docs/example-agents/weather-agent.html +3 -3
  71. package/dist/docs/guides/agent-to-agent.html +3 -3
  72. package/dist/docs/guides/cloud-runtime.html +3 -3
  73. package/dist/docs/guides/github.html +3 -3
  74. package/dist/docs/guides/human-in-the-loop.html +3 -3
  75. package/dist/docs/guides/mcp-oauth.html +3 -3
  76. package/dist/docs/guides/slack.html +11 -7
  77. package/dist/docs/guides/webhooks.html +138 -5
  78. package/dist/docs/hashmap.json +1 -1
  79. package/dist/docs/hillclimbing.html +3 -3
  80. package/dist/docs/index.html +5 -5
  81. package/dist/docs/quickstart.html +3 -3
  82. package/dist/docs/reference/agent-config.html +3 -3
  83. package/dist/docs/reference/channels.html +5 -5
  84. package/dist/docs/reference/cli.html +3 -3
  85. package/dist/docs/reference/connections.html +3 -3
  86. package/dist/docs/reference/hooks.html +3 -3
  87. package/dist/docs/reference/http-api.html +3 -3
  88. package/dist/docs/reference/instructions.html +3 -3
  89. package/dist/docs/reference/playground.html +3 -3
  90. package/dist/docs/reference/project-layout.html +3 -3
  91. package/dist/docs/reference/prompt.html +3 -3
  92. package/dist/docs/reference/schedules.html +3 -3
  93. package/dist/docs/reference/sessions.html +3 -3
  94. package/dist/docs/reference/skills.html +3 -3
  95. package/dist/docs/reference/subagents.html +3 -3
  96. package/dist/docs/reference/tools.html +3 -3
  97. package/dist/docs/scaffolding-agents.html +3 -3
  98. package/dist/docs/storage.html +3 -3
  99. package/dist/docs/troubleshooting.html +3 -3
  100. package/dist/evals/assertions.d.ts +10 -1
  101. package/dist/evals/assertions.d.ts.map +1 -1
  102. package/dist/evals/assertions.js +12 -0
  103. package/dist/evals.d.ts +1 -1
  104. package/dist/evals.d.ts.map +1 -1
  105. package/dist/index.d.ts +1 -0
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +1 -0
  108. package/dist/internal/ab-fold.d.ts.map +1 -1
  109. package/dist/internal/ab-fold.js +4 -0
  110. package/dist/internal/ab-snapshot.d.ts.map +1 -1
  111. package/dist/internal/ab-snapshot.js +1 -0
  112. package/dist/internal/artifacts-store.d.ts +45 -0
  113. package/dist/internal/artifacts-store.d.ts.map +1 -0
  114. package/dist/internal/artifacts-store.js +250 -0
  115. package/dist/internal/builtin-tools/artifacts.d.ts +10 -0
  116. package/dist/internal/builtin-tools/artifacts.d.ts.map +1 -0
  117. package/dist/internal/builtin-tools/artifacts.js +73 -0
  118. package/dist/internal/builtin-tools/index.d.ts +8 -1
  119. package/dist/internal/builtin-tools/index.d.ts.map +1 -1
  120. package/dist/internal/builtin-tools/index.js +15 -0
  121. package/dist/internal/cli-ax.d.ts +19 -0
  122. package/dist/internal/cli-ax.d.ts.map +1 -1
  123. package/dist/internal/cli-ax.js +196 -57
  124. package/dist/internal/cli-slack.d.ts.map +1 -1
  125. package/dist/internal/cli-slack.js +14 -6
  126. package/dist/internal/cursor-slack-relay.d.ts +2 -0
  127. package/dist/internal/cursor-slack-relay.d.ts.map +1 -1
  128. package/dist/internal/cursor-slack-relay.js +1 -0
  129. package/dist/internal/deploy-client.d.ts +2 -0
  130. package/dist/internal/deploy-client.d.ts.map +1 -1
  131. package/dist/internal/deploy-client.js +1 -0
  132. package/dist/internal/discovery.d.ts.map +1 -1
  133. package/dist/internal/discovery.js +91 -3
  134. package/dist/internal/distribution.d.ts.map +1 -1
  135. package/dist/internal/distribution.js +1 -0
  136. package/dist/internal/model-pricing.d.ts +49 -0
  137. package/dist/internal/model-pricing.d.ts.map +1 -0
  138. package/dist/internal/model-pricing.js +377 -0
  139. package/dist/internal/reminder-runner.d.ts.map +1 -1
  140. package/dist/internal/reminder-runner.js +1 -0
  141. package/dist/internal/schedule-runner.d.ts.map +1 -1
  142. package/dist/internal/schedule-runner.js +1 -0
  143. package/dist/internal/sdk-runner.d.ts.map +1 -1
  144. package/dist/internal/sdk-runner.js +9 -1
  145. package/dist/internal/server.d.ts.map +1 -1
  146. package/dist/internal/server.js +49 -5
  147. package/dist/internal/session-cost.d.ts +49 -0
  148. package/dist/internal/session-cost.d.ts.map +1 -0
  149. package/dist/internal/session-cost.js +175 -0
  150. package/dist/internal/session-engine.d.ts +35 -1
  151. package/dist/internal/session-engine.d.ts.map +1 -1
  152. package/dist/internal/session-engine.js +128 -7
  153. package/dist/internal/storage-coordinator.d.ts +15 -0
  154. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  155. package/dist/internal/storage-coordinator.js +52 -0
  156. package/dist/internal/trajectory.d.ts +9 -1
  157. package/dist/internal/trajectory.d.ts.map +1 -1
  158. package/dist/internal/trajectory.js +32 -5
  159. package/dist/playground/assets/index-Bul1WfrB.css +1 -0
  160. package/dist/playground/assets/index-CkN74U_L.js +87 -0
  161. package/dist/playground/index.html +2 -2
  162. package/dist/storage.d.ts +4 -0
  163. package/dist/storage.d.ts.map +1 -1
  164. package/dist/storage.js +4 -0
  165. package/dist/types.d.ts +164 -1
  166. package/dist/types.d.ts.map +1 -1
  167. package/docs/README.md +1 -0
  168. package/docs/guides/slack.md +32 -7
  169. package/docs/guides/webhooks.md +183 -0
  170. package/docs/reference/channels.md +2 -1
  171. package/package.json +26 -26
  172. package/skills/setup-slack/SKILL.md +3 -0
  173. package/src/ab.ts +7 -0
  174. package/src/bin/agent-serve.ts +42 -5
  175. package/src/channels/slack/auth.ts +29 -22
  176. package/src/channels/slack/cursor-account.ts +2 -0
  177. package/src/channels/slack/defaults.ts +24 -4
  178. package/src/channels/slack/dispatch.ts +42 -1
  179. package/src/channels/slack/external-policy.ts +62 -0
  180. package/src/channels/slack/index.ts +1 -0
  181. package/src/channels/slack/interactive.ts +42 -10
  182. package/src/channels/slack/slack-channel.ts +20 -3
  183. package/src/channels/slack/types.ts +12 -0
  184. package/src/internal/ab-fold.ts +4 -0
  185. package/src/internal/ab-snapshot.ts +1 -0
  186. package/src/internal/cli-ax.ts +205 -34
  187. package/src/internal/cursor-slack-relay.ts +3 -0
  188. package/src/internal/deploy-client.ts +3 -0
  189. package/src/internal/discovery.ts +8 -1
  190. package/src/internal/model-pricing.ts +426 -0
  191. package/src/internal/sdk-runner.ts +10 -2
  192. package/src/internal/server.ts +9 -5
  193. package/src/internal/session-cost.ts +231 -0
  194. package/src/internal/session-engine.ts +28 -0
  195. package/src/internal/trajectory.ts +45 -3
  196. package/src/types.ts +24 -1
  197. package/dist/channels/github/instrument.d.ts +0 -20
  198. package/dist/channels/github/instrument.d.ts.map +0 -1
  199. package/dist/docs/assets/chunks/@localSearchIndexroot.BQTzJjR_.js +0 -1
  200. package/dist/docs/assets/guides_slack.md.D_xFKlnF.lean.js +0 -1
  201. package/dist/docs/assets/guides_webhooks.md.B1EswtUu.js +0 -50
  202. package/dist/internal/json-dir-store.d.ts +0 -32
  203. package/dist/internal/json-dir-store.d.ts.map +0 -1
  204. package/dist/internal/json-dir-store.js +0 -100
  205. package/dist/playground/assets/index-CjOQ4hN9.css +0 -1
  206. package/dist/playground/assets/index-DqXdAFGa.js +0 -85
  207. package/src/bin/agent-serve.version.test.ts +0 -64
  208. package/src/channels/github/api.test.ts +0 -64
  209. package/src/channels/github/auth.test.ts +0 -105
  210. package/src/channels/github/cursor-account.test.ts +0 -204
  211. package/src/channels/github/forward.test.ts +0 -457
  212. package/src/channels/github/github.test.ts +0 -985
  213. package/src/channels/github/replay.test.ts +0 -179
  214. package/src/channels/slack/api.post-message.test.ts +0 -148
  215. package/src/channels/slack/approvals.test.ts +0 -328
  216. package/src/channels/slack/block-actions.test.ts +0 -469
  217. package/src/channels/slack/bot-mentions.test.ts +0 -267
  218. package/src/channels/slack/channel-watch.test.ts +0 -363
  219. package/src/channels/slack/cursor-account.test.ts +0 -301
  220. package/src/channels/slack/defaults.final-post.test.ts +0 -182
  221. package/src/channels/slack/dispatch.test.ts +0 -875
  222. package/src/channels/slack/eval-directive.test.ts +0 -273
  223. package/src/channels/slack/message-body.test.ts +0 -54
  224. package/src/channels/slack/nudge-store.test.ts +0 -143
  225. package/src/channels/slack/slack.test.ts +0 -391
  226. package/src/channels/slack/stop.test.ts +0 -23
  227. package/src/channels/slack/thread-context.test.ts +0 -202
  228. package/src/evals/assertions.test.ts +0 -617
  229. package/src/evals/expect.test.ts +0 -144
  230. package/src/evals/judge.test.ts +0 -181
  231. package/src/evals/loaders.test.ts +0 -132
  232. package/src/evals/matchers.test.ts +0 -95
  233. package/src/evals/reporters.test.ts +0 -303
  234. package/src/evals/run-facts.test.ts +0 -259
  235. package/src/internal/ab-snapshot.test.ts +0 -325
  236. package/src/internal/approval-gate.test.ts +0 -49
  237. package/src/internal/approvals.integration.test.ts +0 -383
  238. package/src/internal/artifacts-store.test.ts +0 -283
  239. package/src/internal/authored-loaders.test.ts +0 -31
  240. package/src/internal/builtin-tools/artifacts.test.ts +0 -247
  241. package/src/internal/builtin-tools/reminders.test.ts +0 -201
  242. package/src/internal/channel-route-schema.test.ts +0 -294
  243. package/src/internal/chat-attach.test.ts +0 -262
  244. package/src/internal/cli-deploy.test.ts +0 -1991
  245. package/src/internal/cli-docs.test.ts +0 -161
  246. package/src/internal/cli-mcp.test.ts +0 -789
  247. package/src/internal/cli-skills.test.ts +0 -133
  248. package/src/internal/cli-slack.test.ts +0 -1654
  249. package/src/internal/cloud-merge.test.ts +0 -74
  250. package/src/internal/cron.test.ts +0 -22
  251. package/src/internal/cursor/account-mcp.test.ts +0 -807
  252. package/src/internal/cursor/backend-client.test.ts +0 -591
  253. package/src/internal/cursor/credentials.test.ts +0 -351
  254. package/src/internal/cursor/github-credentials.test.ts +0 -136
  255. package/src/internal/cursor-account-mcp-auth.test.ts +0 -310
  256. package/src/internal/cursor-account.integration.test.ts +0 -441
  257. package/src/internal/cursor-event-relay.test.ts +0 -746
  258. package/src/internal/cursor-github-credentials.integration.test.ts +0 -271
  259. package/src/internal/cursor-slack-relay.test.ts +0 -525
  260. package/src/internal/deploy-source.test.ts +0 -111
  261. package/src/internal/discovery.artifact-tool.test.ts +0 -136
  262. package/src/internal/discovery.artifacts.test.ts +0 -119
  263. package/src/internal/discovery.builtin-tools.test.ts +0 -94
  264. package/src/internal/discovery.concurrency.test.ts +0 -60
  265. package/src/internal/discovery.cursor-account.test.ts +0 -133
  266. package/src/internal/discovery.cwd.test.ts +0 -83
  267. package/src/internal/discovery.hosting.test.ts +0 -80
  268. package/src/internal/discovery.identity.test.ts +0 -44
  269. package/src/internal/docs-site.test.ts +0 -66
  270. package/src/internal/duration.test.ts +0 -29
  271. package/src/internal/eval-judge-model.test.ts +0 -187
  272. package/src/internal/eval-run-store.cancel.test.ts +0 -142
  273. package/src/internal/eval-run-store.storage.test.ts +0 -211
  274. package/src/internal/eval-runner.http.test.ts +0 -403
  275. package/src/internal/eval-runner.run.test.ts +0 -928
  276. package/src/internal/evals-client.test.ts +0 -307
  277. package/src/internal/event-mapper.test.ts +0 -243
  278. package/src/internal/github-fanout.test.ts +0 -213
  279. package/src/internal/handleAgentServeTrigger.test.ts +0 -185
  280. package/src/internal/host-kv.test.ts +0 -82
  281. package/src/internal/host-platforms.test.ts +0 -126
  282. package/src/internal/http-channel.test.ts +0 -402
  283. package/src/internal/init-project.test.ts +0 -270
  284. package/src/internal/install-cursor-skills.test.ts +0 -262
  285. package/src/internal/local-env.test.ts +0 -120
  286. package/src/internal/log-ring.test.ts +0 -31
  287. package/src/internal/logs-client.test.ts +0 -350
  288. package/src/internal/mcp-endpoint.test.ts +0 -436
  289. package/src/internal/mcp-host.test.ts +0 -298
  290. package/src/internal/mcp-oauth.test.ts +0 -148
  291. package/src/internal/net.test.ts +0 -17
  292. package/src/internal/peer-connections.test.ts +0 -128
  293. package/src/internal/peer-mcp.integration.test.ts +0 -289
  294. package/src/internal/playground/toolchain.test.ts +0 -53
  295. package/src/internal/playground-cli.test.ts +0 -187
  296. package/src/internal/playground-proxy.test.ts +0 -376
  297. package/src/internal/prompt-context.integration.test.ts +0 -232
  298. package/src/internal/prompt-context.test.ts +0 -127
  299. package/src/internal/reminder-runner.test.ts +0 -432
  300. package/src/internal/reminder-store.test.ts +0 -53
  301. package/src/internal/request-headers.test.ts +0 -27
  302. package/src/internal/resolve-prod-target.test.ts +0 -787
  303. package/src/internal/resolved-connections.test.ts +0 -295
  304. package/src/internal/router.test.ts +0 -57
  305. package/src/internal/sdk-runner.test.ts +0 -290
  306. package/src/internal/server.artifacts.test.ts +0 -334
  307. package/src/internal/session-engine.artifacts.test.ts +0 -293
  308. package/src/internal/session-engine.coalesce.test.ts +0 -169
  309. package/src/internal/session-engine.concurrency.test.ts +0 -250
  310. package/src/internal/session-engine.host-oauth-mcp.test.ts +0 -110
  311. package/src/internal/session-engine.interrupt.test.ts +0 -577
  312. package/src/internal/session-engine.storage.test.ts +0 -547
  313. package/src/internal/session-urls.test.ts +0 -28
  314. package/src/internal/sessions-client.test.ts +0 -518
  315. package/src/internal/storage-coordinator.test.ts +0 -517
  316. package/src/internal/tool-call.test.ts +0 -458
  317. package/src/internal/tool-result.test.ts +0 -52
  318. package/src/internal/trajectory.approvals.test.ts +0 -83
  319. package/src/internal/trajectory.subagents.test.ts +0 -198
  320. package/src/internal/turn-governor.test.ts +0 -137
  321. package/src/internal/update-check.test.ts +0 -485
  322. package/src/internal/workspace.test.ts +0 -207
  323. package/src/storage-backends/cursor-hosted.test.ts +0 -121
  324. /package/dist/docs/assets/{index.md.Dfv5ic9t.lean.js → index.md.CH_s5uZe.lean.js} +0 -0
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
11
11
  import { tmpdir } from "node:os";
12
- import { join, resolve } from "node:path";
12
+ import { dirname, join, resolve } from "node:path";
13
13
  import { Artifacts, JUnit } from "../evals/reporters.js";
14
14
  import type {
15
15
  EvalAssertionResult,
@@ -50,6 +50,7 @@ import {
50
50
  } from "./init-project.js";
51
51
  import { offerInstallCursorSkills } from "./install-cursor-skills.js";
52
52
  import { runLogsTail, sanitizeCustomerError } from "./logs-client.js";
53
+ import { mapPool } from "./map-pool.js";
53
54
  import { openBrowser } from "./open-browser.js";
54
55
  import { startPlaygroundProxy } from "./playground-proxy.js";
55
56
  import {
@@ -59,6 +60,12 @@ import {
59
60
  resolveProdTarget,
60
61
  } from "./resolve-prod-target.js";
61
62
  import { runSession } from "./run-client.js";
63
+ import {
64
+ buildSessionCostReport,
65
+ formatSessionCostText,
66
+ formatSessionsCostText,
67
+ type SessionCostRow,
68
+ } from "./session-cost.js";
62
69
  import {
63
70
  fetchSessionEvents,
64
71
  formatSessionsTable,
@@ -115,6 +122,12 @@ export interface AxCliOptions {
115
122
  skipReport?: boolean;
116
123
  /** `eval`: override `evals.config.ts` `maxConcurrency`. */
117
124
  maxConcurrency?: number;
125
+ /**
126
+ * `eval` / `eval status <runId>`: also write the full results JSON to this
127
+ * path. `session`: write the raw NDJSON trace (same format as `run
128
+ * --events` and the playground download) to this path instead of printing.
129
+ */
130
+ out?: string;
118
131
  /** Scaffold target directory for `init`. */
119
132
  initTarget?: string;
120
133
  /** Tool name for `call`. */
@@ -787,6 +800,18 @@ export async function cmdEval(options: AxCliOptions): Promise<number> {
787
800
  return 2;
788
801
  }
789
802
  }
803
+ if (trimNonEmpty(options.out) !== undefined) {
804
+ if (options.list === true) {
805
+ process.stderr.write("--out and --list are mutually exclusive\n");
806
+ return 2;
807
+ }
808
+ if (options.noWait === true) {
809
+ process.stderr.write(
810
+ `--out needs the finished results; drop --no-wait, or poll later with ${CLI_COMMAND_NAME} eval status <evalId> --out <path>\n`
811
+ );
812
+ return 2;
813
+ }
814
+ }
790
815
 
791
816
  const filterIds =
792
817
  options.evalIds === undefined || options.evalIds.length === 0
@@ -881,7 +906,12 @@ export async function cmdEval(options: AxCliOptions): Promise<number> {
881
906
  process.stderr.write("No matching evals found.\n");
882
907
  return 2;
883
908
  }
884
- return printEvalResults(results, options, undefined, artifactsDir);
909
+ return await printEvalResults(
910
+ results,
911
+ options,
912
+ undefined,
913
+ artifactsDir
914
+ );
885
915
  } finally {
886
916
  progress?.close();
887
917
  }
@@ -937,7 +967,7 @@ export async function cmdEval(options: AxCliOptions): Promise<number> {
937
967
  process.stderr.write("No matching evals found.\n");
938
968
  return 2;
939
969
  }
940
- return printEvalResults(results, options, {
970
+ return await printEvalResults(results, options, {
941
971
  runId: snapshot.runId,
942
972
  status: snapshot.status,
943
973
  error: snapshot.error,
@@ -1042,8 +1072,8 @@ async function printEvalAccepted(
1042
1072
  agentUrl
1043
1073
  );
1044
1074
  if (options.json) {
1045
- console.log(
1046
- JSON.stringify(
1075
+ process.stdout.write(
1076
+ `${JSON.stringify(
1047
1077
  {
1048
1078
  ok: true,
1049
1079
  accepted: true,
@@ -1057,7 +1087,7 @@ async function printEvalAccepted(
1057
1087
  },
1058
1088
  null,
1059
1089
  2
1060
- )
1090
+ )}\n`
1061
1091
  );
1062
1092
  } else {
1063
1093
  const durable = started.config.durableRuns === true ? " (persisted)" : "";
@@ -1161,7 +1191,7 @@ export async function cmdEvalCancel(
1161
1191
  fetchImpl: options.fetchImpl,
1162
1192
  });
1163
1193
  if (options.json) {
1164
- console.log(JSON.stringify(snap, null, 2));
1194
+ process.stdout.write(`${JSON.stringify(snap, null, 2)}\n`);
1165
1195
  } else {
1166
1196
  process.stdout.write(
1167
1197
  `Cancelled Eval ID ${snap.runId} (${snap.summary.done}/${snap.summary.total} cases finalized)\n`
@@ -1207,6 +1237,13 @@ export async function cmdEvalStatus(
1207
1237
  process.stderr.write("eval status does not accept --list or --no-wait\n");
1208
1238
  return 2;
1209
1239
  }
1240
+ if (
1241
+ trimNonEmpty(options.out) !== undefined &&
1242
+ (runId === undefined || runId === "")
1243
+ ) {
1244
+ process.stderr.write("eval status --out requires an eval id\n");
1245
+ return 2;
1246
+ }
1210
1247
 
1211
1248
  const target = await resolveEvalTarget(options);
1212
1249
  if (typeof target === "number") {
@@ -1225,7 +1262,9 @@ export async function cmdEvalStatus(
1225
1262
  fetchImpl: options.fetchImpl,
1226
1263
  });
1227
1264
  if (options.json) {
1228
- console.log(JSON.stringify({ runs, activeRunId }, null, 2));
1265
+ process.stdout.write(
1266
+ `${JSON.stringify({ runs, activeRunId }, null, 2)}\n`
1267
+ );
1229
1268
  } else if (runs.length === 0) {
1230
1269
  process.stdout.write("No eval runs on this agent.\n");
1231
1270
  } else {
@@ -1245,8 +1284,12 @@ export async function cmdEvalStatus(
1245
1284
  auth,
1246
1285
  fetchImpl: options.fetchImpl,
1247
1286
  });
1287
+ const outPath = await writeJsonOutFile(options.out, snap);
1248
1288
  if (options.json) {
1249
- console.log(JSON.stringify(snap, null, 2));
1289
+ process.stdout.write(`${JSON.stringify(snap, null, 2)}\n`);
1290
+ if (outPath !== undefined) {
1291
+ process.stderr.write(`results: ${outPath}\n`);
1292
+ }
1250
1293
  } else {
1251
1294
  process.stdout.write(`${formatEvalRunSummaryLine(snap)}\n`);
1252
1295
  if (snap.error !== undefined && snap.error !== "") {
@@ -1264,6 +1307,9 @@ export async function cmdEvalStatus(
1264
1307
  process.stdout.write(` error: ${c.error}\n`);
1265
1308
  }
1266
1309
  }
1310
+ if (outPath !== undefined) {
1311
+ process.stdout.write(`results: ${outPath}\n`);
1312
+ }
1267
1313
  }
1268
1314
  if (snap.status === "running") {
1269
1315
  return 3;
@@ -1326,7 +1372,7 @@ function printListedEvals(
1326
1372
  emptyMessage: string
1327
1373
  ): number {
1328
1374
  if (options.json) {
1329
- console.log(JSON.stringify(listed, null, 2));
1375
+ process.stdout.write(`${JSON.stringify(listed, null, 2)}\n`);
1330
1376
  } else if (listed.length === 0) {
1331
1377
  process.stdout.write(`${emptyMessage}\n`);
1332
1378
  } else {
@@ -1431,7 +1477,7 @@ const EVAL_VERDICT_LABEL: Record<EvalVerdict, string> = {
1431
1477
  skipped: "SKIP",
1432
1478
  };
1433
1479
 
1434
- function printEvalResults(
1480
+ async function printEvalResults(
1435
1481
  results: EvalRunResult[],
1436
1482
  options: AxCliOptions,
1437
1483
  batch?: {
@@ -1440,7 +1486,7 @@ function printEvalResults(
1440
1486
  error?: string;
1441
1487
  },
1442
1488
  artifactsDir?: string
1443
- ): number {
1489
+ ): Promise<number> {
1444
1490
  const strict = options.strict === true;
1445
1491
  const counts = { passed: 0, failed: 0, scored: 0, skipped: 0 };
1446
1492
  for (const result of results) {
@@ -1455,28 +1501,29 @@ function printEvalResults(
1455
1501
  process.stderr.write(`eval run error: ${batch.error}\n`);
1456
1502
  }
1457
1503
 
1504
+ const payload = {
1505
+ ok,
1506
+ passed: counts.passed,
1507
+ failed: counts.failed,
1508
+ scored: counts.scored,
1509
+ skipped: counts.skipped,
1510
+ strict,
1511
+ results,
1512
+ ...(artifactsDir === undefined ? {} : { artifactsDir }),
1513
+ ...(batch?.runId === undefined ? {} : { runId: batch.runId }),
1514
+ ...(batch?.status === undefined ? {} : { status: batch.status }),
1515
+ ...(batch?.error === undefined || batch.error === ""
1516
+ ? {}
1517
+ : { error: batch.error }),
1518
+ };
1519
+ const outPath = await writeJsonOutFile(options.out, payload);
1520
+
1458
1521
  if (options.json) {
1459
- console.log(
1460
- JSON.stringify(
1461
- {
1462
- ok,
1463
- passed: counts.passed,
1464
- failed: counts.failed,
1465
- scored: counts.scored,
1466
- skipped: counts.skipped,
1467
- strict,
1468
- results,
1469
- ...(artifactsDir === undefined ? {} : { artifactsDir }),
1470
- ...(batch?.runId === undefined ? {} : { runId: batch.runId }),
1471
- ...(batch?.status === undefined ? {} : { status: batch.status }),
1472
- ...(batch?.error === undefined || batch.error === ""
1473
- ? {}
1474
- : { error: batch.error }),
1475
- },
1476
- null,
1477
- 2
1478
- )
1479
- );
1522
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
1523
+ if (outPath !== undefined) {
1524
+ // stdout stays pure JSON; report the file on stderr.
1525
+ process.stderr.write(`results: ${outPath}\n`);
1526
+ }
1480
1527
  } else {
1481
1528
  for (const r of results) {
1482
1529
  const verdict = evalVerdictOf(r);
@@ -1525,10 +1572,31 @@ function printEvalResults(
1525
1572
  if (artifactsDir !== undefined) {
1526
1573
  process.stdout.write(`artifacts: ${artifactsDir}\n`);
1527
1574
  }
1575
+ if (outPath !== undefined) {
1576
+ process.stdout.write(`results: ${outPath}\n`);
1577
+ }
1528
1578
  }
1529
1579
  return ok ? 0 : 1;
1530
1580
  }
1531
1581
 
1582
+ /**
1583
+ * `--out <path>`: write a JSON payload (results / run snapshot), creating
1584
+ * parent directories. Returns the resolved path, or undefined when unset.
1585
+ */
1586
+ async function writeJsonOutFile(
1587
+ out: string | undefined,
1588
+ payload: unknown
1589
+ ): Promise<string | undefined> {
1590
+ const trimmed = trimNonEmpty(out);
1591
+ if (trimmed === undefined) {
1592
+ return undefined;
1593
+ }
1594
+ const target = resolve(trimmed);
1595
+ await mkdir(dirname(target), { recursive: true });
1596
+ await writeFile(target, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
1597
+ return target;
1598
+ }
1599
+
1532
1600
  /**
1533
1601
  * One assertion line. Soft assertions read `~` rather than `✗` when they miss,
1534
1602
  * so a tracked score is visibly different from a failed gate.
@@ -1714,6 +1782,8 @@ export async function cmdSessions(options: AxCliOptions): Promise<number> {
1714
1782
  /**
1715
1783
  * `session <id>` — view a full session (trajectory text by default).
1716
1784
  * `--json` → trajectory JSON; `--events` (`rawEvents`) → raw event list.
1785
+ * `--out <path>` → write the raw NDJSON trace to a file instead of printing
1786
+ * (same format as `run --events` and the playground download).
1717
1787
  * Interactive reattach: `resume [id]` / `chat --resume` (or `chat --session`).
1718
1788
  */
1719
1789
  export async function cmdSession(
@@ -1722,7 +1792,7 @@ export async function cmdSession(
1722
1792
  ): Promise<number> {
1723
1793
  if (sessionId === undefined || sessionId.trim() === "") {
1724
1794
  process.stderr.write(
1725
- `Usage: ${CLI_COMMAND_NAME} session <sessionId> [--url | --prod] [--json | --text | --events]\n`
1795
+ `Usage: ${CLI_COMMAND_NAME} session <sessionId> [--url | --prod] [--json | --text | --events] [--out <file.ndjson>]\n`
1726
1796
  );
1727
1797
  return 2;
1728
1798
  }
@@ -1747,6 +1817,19 @@ export async function cmdSession(
1747
1817
  fetchImpl: options.fetchImpl,
1748
1818
  });
1749
1819
 
1820
+ const outPath = trimNonEmpty(options.out);
1821
+ if (outPath !== undefined) {
1822
+ const targetPath = resolve(outPath);
1823
+ await mkdir(dirname(targetPath), { recursive: true });
1824
+ await writeFile(
1825
+ targetPath,
1826
+ `${events.map((e) => JSON.stringify(e)).join("\n")}\n`,
1827
+ "utf8"
1828
+ );
1829
+ process.stdout.write(`trace: ${targetPath} (${events.length} events)\n`);
1830
+ return 0;
1831
+ }
1832
+
1750
1833
  if (options.rawEvents === true) {
1751
1834
  process.stdout.write(
1752
1835
  `${JSON.stringify({ sessionId, events }, null, 2)}\n`
@@ -1771,6 +1854,94 @@ export async function cmdSession(
1771
1854
  }
1772
1855
  }
1773
1856
 
1857
+ /** Sessions fetched concurrently when `cost` aggregates every session. */
1858
+ const COST_FETCH_CONCURRENCY = 4;
1859
+
1860
+ /**
1861
+ * `cost [sessionId]` — pull per-session cost metrics.
1862
+ *
1863
+ * With a session id: per-turn token usage + estimated cost for that session.
1864
+ * Without one: one row per session (all sessions on the target) plus a
1865
+ * total row. `--json` prints the underlying report(s); text is the default.
1866
+ * Costs are the engine's recorded estimates on `turn.completed` events
1867
+ * (see `model-pricing.ts`); turns persisted before cost tracking simply
1868
+ * count as unpriced.
1869
+ */
1870
+ export async function cmdCost(
1871
+ sessionId: string | undefined,
1872
+ options: AxCliOptions
1873
+ ): Promise<number> {
1874
+ const target = await resolveSessionTarget(options);
1875
+ if (typeof target === "number") {
1876
+ return target;
1877
+ }
1878
+ const auth = {
1879
+ bearerToken: options.bearerToken,
1880
+ headers: target.headers,
1881
+ };
1882
+
1883
+ try {
1884
+ const resolved = trimNonEmpty(sessionId);
1885
+ if (resolved !== undefined) {
1886
+ const events = await fetchSessionEvents({
1887
+ baseUrl: target.agentUrl,
1888
+ sessionId: resolved,
1889
+ auth,
1890
+ fetchImpl: options.fetchImpl,
1891
+ });
1892
+ const report = buildSessionCostReport(events);
1893
+ if (report.sessionId === "") {
1894
+ report.sessionId = resolved;
1895
+ }
1896
+ if (options.json === true) {
1897
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
1898
+ } else {
1899
+ process.stdout.write(formatSessionCostText(report));
1900
+ }
1901
+ return 0;
1902
+ }
1903
+
1904
+ const listed = await listSessionsWithSource({
1905
+ baseUrl: target.agentUrl,
1906
+ auth,
1907
+ fetchImpl: options.fetchImpl,
1908
+ });
1909
+ const rows = await mapPool(
1910
+ listed.sessions,
1911
+ COST_FETCH_CONCURRENCY,
1912
+ async (session): Promise<SessionCostRow> => {
1913
+ const events = await fetchSessionEvents({
1914
+ baseUrl: target.agentUrl,
1915
+ sessionId: session.sessionId,
1916
+ auth,
1917
+ fetchImpl: options.fetchImpl,
1918
+ });
1919
+ const report = buildSessionCostReport(events);
1920
+ return {
1921
+ sessionId: session.sessionId,
1922
+ channelId: session.channelId,
1923
+ title: session.title,
1924
+ updatedAt: session.updatedAt,
1925
+ totals: report.totals,
1926
+ };
1927
+ }
1928
+ );
1929
+ if (options.json === true) {
1930
+ process.stdout.write(`${JSON.stringify({ sessions: rows }, null, 2)}\n`);
1931
+ } else {
1932
+ process.stdout.write(formatSessionsCostText(rows));
1933
+ }
1934
+ return 0;
1935
+ } catch (error) {
1936
+ process.stderr.write(
1937
+ `${sanitizeCustomerError(
1938
+ error instanceof Error ? error.message : String(error)
1939
+ )}\n`
1940
+ );
1941
+ return 1;
1942
+ }
1943
+ }
1944
+
1774
1945
  /**
1775
1946
  * `playground` — open the web UI against local / `--url` / `--prod`.
1776
1947
  *
@@ -23,6 +23,8 @@ export interface CursorSlackAgentRegistration {
23
23
  name: string;
24
24
  iconUrl?: string;
25
25
  iconEmoji?: string;
26
+ /** Opt out of the default external-sender block. */
27
+ blockExternals?: boolean;
26
28
  }
27
29
 
28
30
  interface RegistrationResponse {
@@ -160,6 +162,7 @@ export class CursorSlackRelay {
160
162
  name: agent.name,
161
163
  iconUrl: agent.iconUrl,
162
164
  iconEmoji: agent.iconEmoji,
165
+ blockExternals: agent.blockExternals === false ? false : undefined,
163
166
  })),
164
167
  };
165
168
  },
@@ -148,6 +148,8 @@ export interface Deployment {
148
148
  engineGeneration?: number | null;
149
149
  publicId?: string;
150
150
  engineUrl?: string | null;
151
+ /** Anyrun pod id for the active engine, when coordinates are known. */
152
+ enginePodId?: string | null;
151
153
  lastError?: string | null;
152
154
  engineAlias: string;
153
155
  desiredUpdatedAt?: string;
@@ -259,6 +261,7 @@ const deploymentSchema = z.object({
259
261
  engineGeneration: z.number().nullable().optional(),
260
262
  publicId: z.string().optional(),
261
263
  engineUrl: z.string().nullable().optional(),
264
+ enginePodId: z.string().nullable().optional(),
262
265
  lastError: z.string().nullable().optional(),
263
266
  engineAlias: z.string(),
264
267
  desiredUpdatedAt: z.string().optional(),
@@ -2000,7 +2000,14 @@ function isModuleFile(fileName: string): boolean {
2000
2000
  if (fileName.endsWith(".d.ts") || fileName.startsWith(".")) {
2001
2001
  return false;
2002
2002
  }
2003
- return MODULE_EXTENSIONS.has(extname(fileName));
2003
+ if (!MODULE_EXTENSIONS.has(extname(fileName))) {
2004
+ return false;
2005
+ }
2006
+ // Colocated unit tests (Vitest/Jest convention) are not definitions.
2007
+ // Without this, `channels/slack.test.ts` is scanned as a channel named
2008
+ // "slack.test", fails NAME_PATTERN, and the whole agent refuses to serve.
2009
+ const stem = moduleStem(fileName);
2010
+ return !stem.endsWith(".test") && !stem.endsWith(".spec");
2004
2011
  }
2005
2012
 
2006
2013
  function moduleStem(fileName: string): string {