@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
@@ -1,787 +0,0 @@
1
- import { once } from "node:events";
2
- import { mkdtemp, rm } from "node:fs/promises";
3
- import { createServer, type Server } from "node:http";
4
- import type { AddressInfo } from "node:net";
5
- import { tmpdir } from "node:os";
6
- import { join } from "node:path";
7
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
8
- import {
9
- cmdCall,
10
- cmdEval,
11
- cmdEvalStatus,
12
- cmdRun,
13
- formatEvalStatusFlags,
14
- resolveEvalTargetMode,
15
- resolveTarget,
16
- } from "./cli-ax.js";
17
- import {
18
- PROD_ENGINE_WAKE_HEADERS,
19
- ProdTargetError,
20
- resolveProdAliasPlaygroundUrl,
21
- resolveProdSlug,
22
- resolveProdTarget,
23
- } from "./resolve-prod-target.js";
24
-
25
- const API_KEY = "test-api-key";
26
- const TEAM_ID = 42;
27
-
28
- interface MockBackend {
29
- url: string;
30
- close: () => Promise<void>;
31
- setDeployment: (slug: string, body: Record<string, unknown>) => void;
32
- }
33
-
34
- async function startMockBackend(): Promise<MockBackend> {
35
- const deployments = new Map<string, Record<string, unknown>>();
36
- const server: Server = createServer((req, res) => {
37
- let raw = "";
38
- req.on("data", (chunk: Buffer) => {
39
- raw += chunk.toString("utf8");
40
- });
41
- req.on("end", () => {
42
- void raw;
43
- const url = new URL(req.url ?? "/", "http://localhost");
44
- const send = (status: number, body: unknown): void => {
45
- res.writeHead(status, { "content-type": "application/json" });
46
- res.end(JSON.stringify(body));
47
- };
48
-
49
- if (url.pathname === "/auth/exchange_user_api_key") {
50
- const claims = Buffer.from(
51
- JSON.stringify({ exp: Math.floor(Date.now() / 1000) + 3600 })
52
- ).toString("base64url");
53
- send(200, { accessToken: `header.${claims}.signature` });
54
- return;
55
- }
56
- if (url.pathname === "/aiserver.v1.DashboardService/GetMe") {
57
- send(200, {
58
- authId: "auth0|1",
59
- email: "dev@example.com",
60
- teamId: TEAM_ID,
61
- teamName: "Acme",
62
- });
63
- return;
64
- }
65
-
66
- const prefix = "/internal/agent-serve/deployments/";
67
- if (
68
- req.method === "GET" &&
69
- url.pathname.startsWith(prefix) &&
70
- req.headers.authorization === `Bearer ${API_KEY}`
71
- ) {
72
- const slug = decodeURIComponent(url.pathname.slice(prefix.length));
73
- const detail = deployments.get(slug);
74
- if (detail === undefined) {
75
- send(404, { error: "Deployment not found" });
76
- return;
77
- }
78
- send(200, detail);
79
- return;
80
- }
81
-
82
- send(404, { error: "Not found" });
83
- });
84
- });
85
-
86
- server.listen(0, "127.0.0.1");
87
- await once(server, "listening");
88
- const { port } = server.address() as AddressInfo;
89
- return {
90
- url: `http://127.0.0.1:${port}`,
91
- setDeployment: (slug, body) => {
92
- deployments.set(slug, body);
93
- },
94
- close: () =>
95
- new Promise<void>((resolvePromise, reject) =>
96
- server.close((error) => (error ? reject(error) : resolvePromise()))
97
- ),
98
- };
99
- }
100
-
101
- interface StubEngine {
102
- url: string;
103
- close: () => Promise<void>;
104
- sessionHeaders: Array<Record<string, string | string[] | undefined>>;
105
- toolHeaders: Array<Record<string, string | string[] | undefined>>;
106
- evalRunHeaders: Array<Record<string, string | string[] | undefined>>;
107
- evalRunBodies: unknown[];
108
- }
109
-
110
- async function startStubEngine(): Promise<StubEngine> {
111
- const sessionHeaders: StubEngine["sessionHeaders"] = [];
112
- const toolHeaders: StubEngine["toolHeaders"] = [];
113
- const evalRunHeaders: StubEngine["evalRunHeaders"] = [];
114
- const evalRunBodies: unknown[] = [];
115
- const evalSnapshot = {
116
- runId: "evalrun_test",
117
- status: "completed" as const,
118
- startedAt: "2026-07-20T00:00:00.000Z",
119
- finishedAt: "2026-07-20T00:00:01.000Z",
120
- summary: { passed: 1, failed: 0, total: 1, done: 1 },
121
- cases: [
122
- {
123
- id: "smoke",
124
- fileId: "smoke",
125
- status: "done" as const,
126
- ok: true,
127
- assertions: [{ name: "succeeded", passed: true }],
128
- durationMs: 10,
129
- inputs: [],
130
- logs: [],
131
- },
132
- ],
133
- config: { maxConcurrency: 1, durableRuns: true },
134
- };
135
- const server: Server = createServer((req, res) => {
136
- let raw = "";
137
- req.on("data", (chunk: Buffer) => {
138
- raw += chunk.toString("utf8");
139
- });
140
- req.on("end", () => {
141
- const url = new URL(req.url ?? "/", "http://localhost");
142
- const send = (status: number, body: unknown): void => {
143
- res.writeHead(status, { "content-type": "application/json" });
144
- res.end(JSON.stringify(body));
145
- };
146
- const sendNdjson = (lines: unknown[]): void => {
147
- res.writeHead(200, { "content-type": "application/x-ndjson" });
148
- res.end(`${lines.map((line) => JSON.stringify(line)).join("\n")}\n`);
149
- };
150
-
151
- if (req.method === "POST" && url.pathname === "/v1/dev/evals/runs") {
152
- evalRunHeaders.push({ ...req.headers });
153
- evalRunBodies.push(raw === "" ? {} : JSON.parse(raw));
154
- send(202, {
155
- ...evalSnapshot,
156
- status: "running",
157
- finishedAt: undefined,
158
- });
159
- return;
160
- }
161
- if (req.method === "GET" && url.pathname === "/v1/dev/evals/runs") {
162
- send(200, { runs: [evalSnapshot], activeRunId: undefined });
163
- return;
164
- }
165
- if (
166
- req.method === "GET" &&
167
- url.pathname === "/v1/dev/evals/runs/evalrun_test"
168
- ) {
169
- send(200, evalSnapshot);
170
- return;
171
- }
172
- if (
173
- req.method === "GET" &&
174
- url.pathname === "/v1/dev/evals/runs/evalrun_running"
175
- ) {
176
- send(200, {
177
- ...evalSnapshot,
178
- runId: "evalrun_running",
179
- status: "running",
180
- finishedAt: undefined,
181
- cases: evalSnapshot.cases.map((c) => ({
182
- ...c,
183
- status: "running" as const,
184
- ok: undefined,
185
- })),
186
- });
187
- return;
188
- }
189
- if (req.method === "POST" && url.pathname === "/v1/session") {
190
- sessionHeaders.push({ ...req.headers });
191
- send(200, {
192
- ok: true,
193
- sessionId: "ses_test",
194
- continuationToken: "http:tok",
195
- });
196
- return;
197
- }
198
- if (
199
- req.method === "GET" &&
200
- url.pathname === "/v1/session/ses_test/stream"
201
- ) {
202
- sendNdjson([
203
- {
204
- index: 0,
205
- sessionId: "ses_test",
206
- type: "session.started",
207
- data: { channelId: "http" },
208
- },
209
- {
210
- index: 1,
211
- sessionId: "ses_test",
212
- turnId: "turn_1",
213
- type: "turn.started",
214
- data: {},
215
- },
216
- {
217
- index: 2,
218
- sessionId: "ses_test",
219
- turnId: "turn_1",
220
- type: "message.completed",
221
- data: { text: "pong", finishReason: "stop" },
222
- },
223
- {
224
- index: 3,
225
- sessionId: "ses_test",
226
- turnId: "turn_1",
227
- type: "turn.completed",
228
- data: { result: "pong" },
229
- },
230
- {
231
- index: 4,
232
- sessionId: "ses_test",
233
- type: "session.waiting",
234
- data: {},
235
- },
236
- ]);
237
- return;
238
- }
239
- if (req.method === "POST" && url.pathname.startsWith("/v1/tools/")) {
240
- toolHeaders.push({ ...req.headers });
241
- send(200, { ok: true, output: { echoed: "hi" } });
242
- return;
243
- }
244
- send(404, { ok: false, error: "not_found" });
245
- });
246
- });
247
-
248
- server.listen(0, "127.0.0.1");
249
- await once(server, "listening");
250
- const { port } = server.address() as AddressInfo;
251
- return {
252
- url: `http://127.0.0.1:${port}`,
253
- sessionHeaders,
254
- toolHeaders,
255
- evalRunHeaders,
256
- evalRunBodies,
257
- close: () =>
258
- new Promise<void>((resolvePromise, reject) =>
259
- server.close((error) => (error ? reject(error) : resolvePromise()))
260
- ),
261
- };
262
- }
263
-
264
- function runningDetail(
265
- slug: string,
266
- engineUrl: string
267
- ): Record<string, unknown> {
268
- return {
269
- id: 1,
270
- slug,
271
- teamId: TEAM_ID,
272
- deploymentKind: "repo",
273
- status: "running",
274
- generation: 1,
275
- engineAlias: `/internal/agent-serve/agents/asd_test/engine`,
276
- engineAccess: {
277
- url: engineUrl,
278
- headers: { "x-anyrun-port-token": "port-tok-1" },
279
- expiresAt: "2099-01-01T00:00:00.000Z",
280
- },
281
- };
282
- }
283
-
284
- describe("resolveEvalTargetMode", () => {
285
- it("defaults to local; --prod and --url opt into remote surfaces", () => {
286
- expect(resolveEvalTargetMode({})).toBe("local");
287
- expect(resolveEvalTargetMode({ prod: true })).toBe("deployment");
288
- expect(resolveEvalTargetMode({ url: "http://127.0.0.1:3000" })).toBe("url");
289
- });
290
-
291
- it("rejects conflicting target flags", () => {
292
- expect(resolveEvalTargetMode({ prod: true, url: "http://x" })).toEqual({
293
- error: "--prod and --url are mutually exclusive",
294
- });
295
- });
296
- });
297
-
298
- describe("formatEvalStatusFlags", () => {
299
- it("includes --slug/--team for --prod and --url/--team for --url", () => {
300
- expect(formatEvalStatusFlags({ prod: true })).toBe(" --prod");
301
- expect(
302
- formatEvalStatusFlags({ prod: true, slug: "approval-buddy", team: "1" })
303
- ).toBe(" --prod --slug approval-buddy --team 1");
304
- expect(
305
- formatEvalStatusFlags({ url: "http://127.0.0.1:3000/", team: "7" })
306
- ).toBe(" --url http://127.0.0.1:3000 --team 7");
307
- });
308
- });
309
-
310
- describe("resolveProdSlug", () => {
311
- it("uses --slug when provided", () => {
312
- expect(resolveProdSlug({ dir: ".", slug: "danny" })).toBe("danny");
313
- });
314
-
315
- it("derives from directory basename", async () => {
316
- const dir = await mkdtemp(join(tmpdir(), "Danny Agent-"));
317
- // basename is like "Danny Agent-xxxxx" → slugFromDirectoryName lowercases
318
- const slug = resolveProdSlug({ dir });
319
- expect(slug).toMatch(/^danny-agent-/);
320
- await rm(dir, { recursive: true, force: true });
321
- });
322
-
323
- it("rejects invalid --slug", () => {
324
- expect(() => resolveProdSlug({ dir: ".", slug: "Bad Slug" })).toThrow(
325
- /Invalid slug/
326
- );
327
- });
328
- });
329
-
330
- describe("resolveProdTarget / --prod", () => {
331
- let backend: MockBackend;
332
- let engine: StubEngine;
333
- const savedEnv: Record<string, string | undefined> = {};
334
- let agentDir: string;
335
-
336
- beforeEach(async () => {
337
- backend = await startMockBackend();
338
- engine = await startStubEngine();
339
- for (const key of [
340
- "CURSOR_API_BASE_URL",
341
- "CURSOR_API_KEY",
342
- "AGENT_SERVE_CONFIG_DIR",
343
- ]) {
344
- savedEnv[key] = process.env[key];
345
- }
346
- process.env.CURSOR_API_BASE_URL = backend.url;
347
- delete process.env.CURSOR_API_KEY;
348
- process.env.AGENT_SERVE_CONFIG_DIR = join(
349
- tmpdir(),
350
- `agentkit-prod-test-${process.pid}`
351
- );
352
- agentDir = await mkdtemp(join(tmpdir(), "danny-"));
353
- });
354
-
355
- afterEach(async () => {
356
- await backend.close();
357
- await engine.close();
358
- await rm(agentDir, { recursive: true, force: true });
359
- for (const [key, value] of Object.entries(savedEnv)) {
360
- if (value === undefined) {
361
- delete process.env[key];
362
- } else {
363
- process.env[key] = value;
364
- }
365
- }
366
- });
367
-
368
- it("resolves slug from dir name and returns engineAccess headers", async () => {
369
- const slug = resolveProdSlug({ dir: agentDir });
370
- backend.setDeployment(slug, runningDetail(slug, engine.url));
371
- const stderr: string[] = [];
372
-
373
- const target = await resolveProdTarget({
374
- dir: agentDir,
375
- team: String(TEAM_ID),
376
- apiKey: API_KEY,
377
- err: (text) => stderr.push(text),
378
- });
379
-
380
- expect(target.slug).toBe(slug);
381
- expect(target.agentUrl).toBe(engine.url);
382
- expect(target.headers["x-anyrun-port-token"]).toBe("port-tok-1");
383
- expect(target.headers["x-anyrun-hibernation-lower-bound-s"]).toBe(
384
- PROD_ENGINE_WAKE_HEADERS["x-anyrun-hibernation-lower-bound-s"]
385
- );
386
- expect(target.headers["x-anyrun-hibernation-upper-bound-s"]).toBe(
387
- PROD_ENGINE_WAKE_HEADERS["x-anyrun-hibernation-upper-bound-s"]
388
- );
389
- expect(stderr.join("")).toContain(`Using hosted deployment "${slug}".`);
390
- expect(stderr.join("")).not.toMatch(/engine access|expires/i);
391
- });
392
-
393
- it("honors --slug override", async () => {
394
- backend.setDeployment("weather", runningDetail("weather", engine.url));
395
- const target = await resolveProdTarget({
396
- dir: agentDir,
397
- slug: "weather",
398
- team: String(TEAM_ID),
399
- apiKey: API_KEY,
400
- err: () => {},
401
- });
402
- expect(target.slug).toBe("weather");
403
- });
404
-
405
- it("fails when deployment is not running", async () => {
406
- backend.setDeployment("danny", {
407
- ...runningDetail("danny", engine.url),
408
- status: "stopped",
409
- engineAccess: null,
410
- });
411
- await expect(
412
- resolveProdTarget({
413
- dir: agentDir,
414
- slug: "danny",
415
- team: String(TEAM_ID),
416
- apiKey: API_KEY,
417
- err: () => {},
418
- })
419
- ).rejects.toThrow(/stopped, not running/);
420
- });
421
-
422
- it("fails when engineAccess is missing", async () => {
423
- backend.setDeployment("danny", {
424
- ...runningDetail("danny", engine.url),
425
- engineAccess: null,
426
- });
427
- await expect(
428
- resolveProdTarget({
429
- dir: agentDir,
430
- slug: "danny",
431
- team: String(TEAM_ID),
432
- apiKey: API_KEY,
433
- err: () => {},
434
- sleep: async () => {},
435
- })
436
- ).rejects.toThrow(/is not reachable yet/);
437
- });
438
-
439
- it("retries when engineAccess appears after a wake", async () => {
440
- backend.setDeployment("danny", {
441
- ...runningDetail("danny", engine.url),
442
- engineAccess: null,
443
- });
444
- const stderr: string[] = [];
445
- const sleepCalls: number[] = [];
446
- const target = await resolveProdTarget({
447
- dir: agentDir,
448
- slug: "danny",
449
- team: String(TEAM_ID),
450
- apiKey: API_KEY,
451
- err: (text) => stderr.push(text),
452
- sleep: async (ms) => {
453
- sleepCalls.push(ms);
454
- // After the first miss, the engine becomes reachable (wake).
455
- backend.setDeployment("danny", runningDetail("danny", engine.url));
456
- },
457
- });
458
- expect(target.agentUrl).toBe(engine.url);
459
- expect(sleepCalls).toEqual([1000]);
460
- expect(stderr.join("")).toContain("is waking");
461
- });
462
-
463
- it("rejects --prod with --url", async () => {
464
- const exitSpy = vi.spyOn(process, "exit").mockImplementation((() => {
465
- throw new Error("process.exit");
466
- }) as never);
467
- const errSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
468
- try {
469
- await expect(
470
- resolveTarget({
471
- dir: agentDir,
472
- prod: true,
473
- url: "http://127.0.0.1:3000",
474
- })
475
- ).rejects.toThrow(/process\.exit/);
476
- expect(
477
- errSpy.mock.calls.some((c) =>
478
- String(c[0]).includes("mutually exclusive")
479
- )
480
- ).toBe(true);
481
- } finally {
482
- exitSpy.mockRestore();
483
- errSpy.mockRestore();
484
- }
485
- });
486
-
487
- it("cmdRun --prod sends X-Anyrun-Port-Token on /v1/session", async () => {
488
- const slug = resolveProdSlug({ dir: agentDir });
489
- backend.setDeployment(slug, runningDetail(slug, engine.url));
490
-
491
- const code = await cmdRun({
492
- dir: agentDir,
493
- prod: true,
494
- team: String(TEAM_ID),
495
- apiKey: API_KEY,
496
- messages: ["hello"],
497
- events: false,
498
- stream: false,
499
- });
500
-
501
- expect(code).toBe(0);
502
- expect(engine.sessionHeaders.length).toBe(1);
503
- expect(engine.sessionHeaders[0]!["x-anyrun-port-token"]).toBe("port-tok-1");
504
- expect(
505
- engine.sessionHeaders[0]!["x-anyrun-hibernation-lower-bound-s"]
506
- ).toBe("1800");
507
- });
508
-
509
- it("marks a missing deployment as notFound", async () => {
510
- const error = await resolveProdTarget({
511
- dir: agentDir,
512
- slug: "danny",
513
- team: String(TEAM_ID),
514
- apiKey: API_KEY,
515
- err: () => {},
516
- }).then(
517
- () => undefined,
518
- (thrown: unknown) => thrown
519
- );
520
- expect(error).toBeInstanceOf(ProdTargetError);
521
- expect((error as ProdTargetError).notFound).toBe(true);
522
- expect((error as ProdTargetError).slug).toBe("danny");
523
- });
524
-
525
- it("cmdEval --prod explains when the deployment is missing", async () => {
526
- const errSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
527
- try {
528
- const code = await cmdEval({
529
- dir: agentDir,
530
- prod: true,
531
- slug: "danny",
532
- team: String(TEAM_ID),
533
- apiKey: API_KEY,
534
- stream: false,
535
- });
536
- expect(code).toBe(1);
537
- const stderr = errSpy.mock.calls.map((c) => String(c[0])).join("");
538
- // The API 404 text is kept (it distinguishes a missing deployment
539
- // from a wrong host / disabled gate), plus the deploy/local hints.
540
- expect(stderr).toContain('Deployment "danny"');
541
- expect(stderr).toContain("not found");
542
- expect(stderr).toContain("deploy --slug danny");
543
- expect(stderr).toContain("omit --prod");
544
- } finally {
545
- errSpy.mockRestore();
546
- }
547
- });
548
-
549
- it("cmdEval --prod starts a server-side persisted eval batch", async () => {
550
- const slug = resolveProdSlug({ dir: agentDir });
551
- backend.setDeployment(slug, runningDetail(slug, engine.url));
552
- const outSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
553
- const errSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
554
- try {
555
- const code = await cmdEval({
556
- dir: agentDir,
557
- prod: true,
558
- team: String(TEAM_ID),
559
- apiKey: API_KEY,
560
- stream: false,
561
- evalIds: ["smoke"],
562
- });
563
- expect(code).toBe(0);
564
- expect(engine.evalRunHeaders.length).toBe(1);
565
- expect(engine.evalRunHeaders[0]!["x-anyrun-port-token"]).toBe(
566
- "port-tok-1"
567
- );
568
- expect(engine.evalRunBodies[0]).toEqual({ filterIds: ["smoke"] });
569
- // Must not fall back to the client-side session harness.
570
- expect(engine.sessionHeaders.length).toBe(0);
571
- const stdout = outSpy.mock.calls.map((c) => String(c[0])).join("");
572
- expect(stdout).toContain("PASS smoke");
573
- } finally {
574
- outSpy.mockRestore();
575
- errSpy.mockRestore();
576
- }
577
- });
578
-
579
- it("cmdEval --prod --no-wait accepts the batch without polling", async () => {
580
- const slug = resolveProdSlug({ dir: agentDir });
581
- backend.setDeployment(slug, runningDetail(slug, engine.url));
582
- const outSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
583
- const errSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
584
- try {
585
- const code = await cmdEval({
586
- dir: agentDir,
587
- prod: true,
588
- team: String(TEAM_ID),
589
- apiKey: API_KEY,
590
- stream: false,
591
- noWait: true,
592
- evalIds: ["smoke"],
593
- });
594
- expect(code).toBe(0);
595
- expect(engine.evalRunHeaders.length).toBe(1);
596
- expect(engine.evalRunBodies[0]).toEqual({ filterIds: ["smoke"] });
597
- const stdout = outSpy.mock.calls.map((c) => String(c[0])).join("");
598
- expect(stdout).toContain("Eval ID: evalrun_test");
599
- expect(stdout).toContain(
600
- `eval status evalrun_test --prod --team ${TEAM_ID}`
601
- );
602
- expect(stdout).toContain("/v1/dev/evals/runs/evalrun_test");
603
- } finally {
604
- outSpy.mockRestore();
605
- errSpy.mockRestore();
606
- }
607
- });
608
-
609
- it("cmdEvalStatus --prod fetches a run and lists recent runs", async () => {
610
- const slug = resolveProdSlug({ dir: agentDir });
611
- backend.setDeployment(slug, runningDetail(slug, engine.url));
612
- const outSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
613
- const errSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
614
- try {
615
- const one = await cmdEvalStatus("evalrun_test", {
616
- dir: agentDir,
617
- prod: true,
618
- team: String(TEAM_ID),
619
- apiKey: API_KEY,
620
- });
621
- expect(one).toBe(0);
622
- let stdout = outSpy.mock.calls.map((c) => String(c[0])).join("");
623
- expect(stdout).toContain("evalrun_test completed");
624
- expect(stdout).toContain("PASS smoke");
625
-
626
- outSpy.mockClear();
627
- const listed = await cmdEvalStatus(undefined, {
628
- dir: agentDir,
629
- prod: true,
630
- team: String(TEAM_ID),
631
- apiKey: API_KEY,
632
- });
633
- expect(listed).toBe(0);
634
- stdout = outSpy.mock.calls.map((c) => String(c[0])).join("");
635
- expect(stdout).toContain("evalrun_test completed");
636
- } finally {
637
- outSpy.mockRestore();
638
- errSpy.mockRestore();
639
- }
640
- });
641
-
642
- it("cmdEvalStatus exits 3 while the remote batch is still running", async () => {
643
- const slug = resolveProdSlug({ dir: agentDir });
644
- backend.setDeployment(slug, runningDetail(slug, engine.url));
645
- const outSpy = vi.spyOn(process.stdout, "write").mockReturnValue(true);
646
- const errSpy = vi.spyOn(process.stderr, "write").mockReturnValue(true);
647
- try {
648
- const code = await cmdEvalStatus("evalrun_running", {
649
- dir: agentDir,
650
- prod: true,
651
- team: String(TEAM_ID),
652
- apiKey: API_KEY,
653
- });
654
- expect(code).toBe(3);
655
- const stdout = outSpy.mock.calls.map((c) => String(c[0])).join("");
656
- expect(stdout).toContain("evalrun_running running");
657
- } finally {
658
- outSpy.mockRestore();
659
- errSpy.mockRestore();
660
- }
661
- });
662
-
663
- it("cmdCall --prod sends engineAccess headers", async () => {
664
- const slug = resolveProdSlug({ dir: agentDir });
665
- backend.setDeployment(slug, runningDetail(slug, engine.url));
666
-
667
- const code = await cmdCall({
668
- dir: agentDir,
669
- prod: true,
670
- team: String(TEAM_ID),
671
- apiKey: API_KEY,
672
- toolName: "echo",
673
- toolInput: '{"message":"hi"}',
674
- });
675
-
676
- expect(code).toBe(0);
677
- expect(engine.toolHeaders.length).toBe(1);
678
- expect(engine.toolHeaders[0]!["x-anyrun-port-token"]).toBe("port-tok-1");
679
- });
680
- });
681
-
682
- describe("resolveProdAliasPlaygroundUrl", () => {
683
- let backend: MockBackend;
684
- const savedEnv: Record<string, string | undefined> = {};
685
- let agentDir: string;
686
-
687
- beforeEach(async () => {
688
- backend = await startMockBackend();
689
- for (const key of [
690
- "CURSOR_API_BASE_URL",
691
- "CURSOR_API_KEY",
692
- "AGENT_SERVE_CONFIG_DIR",
693
- ]) {
694
- savedEnv[key] = process.env[key];
695
- }
696
- process.env.CURSOR_API_BASE_URL = backend.url;
697
- delete process.env.CURSOR_API_KEY;
698
- process.env.AGENT_SERVE_CONFIG_DIR = join(
699
- tmpdir(),
700
- `agentkit-prod-alias-test-${process.pid}`
701
- );
702
- agentDir = await mkdtemp(join(tmpdir(), "danny-"));
703
- });
704
-
705
- afterEach(async () => {
706
- await backend.close();
707
- await rm(agentDir, { recursive: true, force: true });
708
- for (const [key, value] of Object.entries(savedEnv)) {
709
- if (value === undefined) {
710
- delete process.env[key];
711
- } else {
712
- process.env[key] = value;
713
- }
714
- }
715
- });
716
-
717
- it("returns the alias playground URL without requiring engineAccess", async () => {
718
- backend.setDeployment("weather", {
719
- ...runningDetail("weather", "http://127.0.0.1:9"),
720
- engineAccess: null,
721
- });
722
- const stderr: string[] = [];
723
-
724
- const resolved = await resolveProdAliasPlaygroundUrl({
725
- dir: agentDir,
726
- slug: "weather",
727
- team: String(TEAM_ID),
728
- apiKey: API_KEY,
729
- err: (text) => stderr.push(text),
730
- });
731
-
732
- expect(resolved.slug).toBe("weather");
733
- expect(resolved.playgroundUrl).toBe(
734
- `${backend.url}/internal/agent-serve/agents/asd_test/engine/playground`
735
- );
736
- expect(stderr.join("")).toContain('Using hosted deployment "weather".');
737
- });
738
-
739
- it("appends sessionId when provided", async () => {
740
- backend.setDeployment("weather", {
741
- ...runningDetail("weather", "http://127.0.0.1:9"),
742
- engineAccess: null,
743
- });
744
-
745
- const resolved = await resolveProdAliasPlaygroundUrl({
746
- dir: agentDir,
747
- slug: "weather",
748
- team: String(TEAM_ID),
749
- apiKey: API_KEY,
750
- sessionId: "ses_abc",
751
- err: () => {},
752
- });
753
-
754
- expect(resolved.playgroundUrl).toBe(
755
- `${backend.url}/internal/agent-serve/agents/asd_test/engine/playground?sessionId=ses_abc`
756
- );
757
- });
758
-
759
- it("fails when deployment is not running", async () => {
760
- backend.setDeployment("weather", {
761
- ...runningDetail("weather", "http://127.0.0.1:9"),
762
- status: "stopped",
763
- engineAccess: null,
764
- });
765
- await expect(
766
- resolveProdAliasPlaygroundUrl({
767
- dir: agentDir,
768
- slug: "weather",
769
- team: String(TEAM_ID),
770
- apiKey: API_KEY,
771
- err: () => {},
772
- })
773
- ).rejects.toThrow(/stopped, not running/);
774
- });
775
-
776
- it("fails when deployment is missing", async () => {
777
- await expect(
778
- resolveProdAliasPlaygroundUrl({
779
- dir: agentDir,
780
- slug: "missing",
781
- team: String(TEAM_ID),
782
- apiKey: API_KEY,
783
- err: () => {},
784
- })
785
- ).rejects.toThrow(/Deployment "missing"/);
786
- });
787
- });