@cursor/july 0.1.2 → 0.1.4

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 (232) hide show
  1. package/AGENTS.md +16 -5
  2. package/README.md +8 -9
  3. package/dist/bin/agent-serve.d.ts +3 -1
  4. package/dist/bin/agent-serve.d.ts.map +1 -1
  5. package/dist/bin/agent-serve.js +416 -155
  6. package/dist/channels/slack/log.d.ts +1 -1
  7. package/dist/channels/slack/log.d.ts.map +1 -1
  8. package/dist/channels/slack/log.js +4 -5
  9. package/dist/channels/slack/setup.js +1 -1
  10. package/dist/channels/slack/socket-mode.d.ts.map +1 -1
  11. package/dist/channels/slack/socket-mode.js +10 -9
  12. package/dist/docs/404.html +2 -2
  13. package/dist/docs/ab.html +3 -3
  14. package/dist/docs/assets/{app.Oje4vhlk.js → app.DF-Yx4OP.js} +1 -1
  15. package/dist/docs/assets/chunks/@localSearchIndexroot.0XrheBv2.js +1 -0
  16. package/dist/docs/assets/chunks/{VPLocalSearchBox.H5XZ2zCB.js → VPLocalSearchBox.DSeJSudL.js} +1 -1
  17. package/dist/docs/assets/chunks/{theme.CTR_TuaE.js → theme.DZVLTXOC.js} +2 -2
  18. package/dist/docs/assets/{index.md.m81y7TY7.js → index.md.Cylk70gg.js} +1 -1
  19. package/dist/docs/assets/{quickstart.md.CfU8_uTC.js → quickstart.md.BU6Iwi_9.js} +18 -6
  20. package/dist/docs/assets/{reference_cli.md.DA730zCu.js → reference_cli.md.Bv6pOxcF.js} +11 -6
  21. package/dist/docs/assets/{reference_cli.md.DA730zCu.lean.js → reference_cli.md.Bv6pOxcF.lean.js} +1 -1
  22. package/dist/docs/building-with-agents.html +3 -3
  23. package/dist/docs/concepts.html +3 -3
  24. package/dist/docs/deployment.html +3 -3
  25. package/dist/docs/evals.html +3 -3
  26. package/dist/docs/guides/agent-to-agent.html +3 -3
  27. package/dist/docs/guides/cloud-runtime.html +3 -3
  28. package/dist/docs/guides/github.html +3 -3
  29. package/dist/docs/guides/human-in-the-loop.html +3 -3
  30. package/dist/docs/guides/slack.html +3 -3
  31. package/dist/docs/guides/webhooks.html +3 -3
  32. package/dist/docs/hashmap.json +1 -1
  33. package/dist/docs/hillclimbing.html +3 -3
  34. package/dist/docs/index.html +5 -5
  35. package/dist/docs/quickstart.html +22 -10
  36. package/dist/docs/reference/agent-config.html +3 -3
  37. package/dist/docs/reference/channels.html +3 -3
  38. package/dist/docs/reference/cli.html +14 -9
  39. package/dist/docs/reference/connections.html +3 -3
  40. package/dist/docs/reference/hooks.html +3 -3
  41. package/dist/docs/reference/http-api.html +3 -3
  42. package/dist/docs/reference/instructions.html +3 -3
  43. package/dist/docs/reference/playground.html +3 -3
  44. package/dist/docs/reference/project-layout.html +3 -3
  45. package/dist/docs/reference/schedules.html +3 -3
  46. package/dist/docs/reference/sessions.html +3 -3
  47. package/dist/docs/reference/skills.html +3 -3
  48. package/dist/docs/reference/subagents.html +3 -3
  49. package/dist/docs/reference/tools.html +3 -3
  50. package/dist/docs/scaffolding-agents.html +3 -3
  51. package/dist/docs/storage.html +3 -3
  52. package/dist/docs/troubleshooting.html +3 -3
  53. package/dist/internal/ab-collector.js +3 -3
  54. package/dist/internal/ab-fold.js +1 -1
  55. package/dist/internal/chat-client.d.ts +29 -3
  56. package/dist/internal/chat-client.d.ts.map +1 -1
  57. package/dist/internal/chat-client.js +180 -27
  58. package/dist/internal/cli-ax.d.ts +83 -2
  59. package/dist/internal/cli-ax.d.ts.map +1 -1
  60. package/dist/internal/cli-ax.js +626 -52
  61. package/dist/internal/cli-cursor.d.ts.map +1 -1
  62. package/dist/internal/cli-cursor.js +8 -36
  63. package/dist/internal/cli-deploy.d.ts +59 -3
  64. package/dist/internal/cli-deploy.d.ts.map +1 -1
  65. package/dist/internal/cli-deploy.js +316 -38
  66. package/dist/internal/cli-github.js +13 -13
  67. package/dist/internal/cursor/account-mcp.js +3 -3
  68. package/dist/internal/cursor/backend-client.js +1 -1
  69. package/dist/internal/cursor/credentials.d.ts +14 -3
  70. package/dist/internal/cursor/credentials.d.ts.map +1 -1
  71. package/dist/internal/cursor/credentials.js +21 -6
  72. package/dist/internal/cursor/github-credentials.js +3 -3
  73. package/dist/internal/cursor-event-relay.js +1 -1
  74. package/dist/internal/cursor-relay-core.d.ts +1 -1
  75. package/dist/internal/cursor-relay-core.d.ts.map +1 -1
  76. package/dist/internal/cursor-relay-core.js +2 -1
  77. package/dist/internal/cursor-slack-relay.js +1 -1
  78. package/dist/internal/deploy-client.d.ts +9 -1
  79. package/dist/internal/deploy-client.d.ts.map +1 -1
  80. package/dist/internal/deploy-client.js +23 -3
  81. package/dist/internal/deploy-source.d.ts +35 -0
  82. package/dist/internal/deploy-source.d.ts.map +1 -0
  83. package/dist/internal/deploy-source.js +118 -0
  84. package/dist/internal/discovery.d.ts +11 -0
  85. package/dist/internal/discovery.d.ts.map +1 -1
  86. package/dist/internal/discovery.js +43 -14
  87. package/dist/internal/distribution.d.ts +7 -0
  88. package/dist/internal/distribution.d.ts.map +1 -1
  89. package/dist/internal/distribution.js +7 -0
  90. package/dist/internal/docs-site.js +3 -3
  91. package/dist/internal/eval-run-store.d.ts.map +1 -1
  92. package/dist/internal/eval-run-store.js +10 -9
  93. package/dist/internal/eval-runner.d.ts +2 -0
  94. package/dist/internal/eval-runner.d.ts.map +1 -1
  95. package/dist/internal/eval-runner.js +2 -0
  96. package/dist/internal/event-mapper.d.ts +54 -1
  97. package/dist/internal/event-mapper.d.ts.map +1 -1
  98. package/dist/internal/event-mapper.js +151 -41
  99. package/dist/internal/github-fanout.js +2 -2
  100. package/dist/internal/host-platforms.js +5 -5
  101. package/dist/internal/init-project.d.ts +88 -1
  102. package/dist/internal/init-project.d.ts.map +1 -1
  103. package/dist/internal/init-project.js +221 -31
  104. package/dist/internal/install-cursor-skills.d.ts +64 -0
  105. package/dist/internal/install-cursor-skills.d.ts.map +1 -0
  106. package/dist/internal/install-cursor-skills.js +274 -0
  107. package/dist/internal/logs-client.d.ts +60 -0
  108. package/dist/internal/logs-client.d.ts.map +1 -0
  109. package/dist/internal/logs-client.js +311 -0
  110. package/dist/internal/mcp-endpoint.d.ts.map +1 -1
  111. package/dist/internal/mcp-endpoint.js +1 -1
  112. package/dist/internal/open-browser.d.ts +5 -0
  113. package/dist/internal/open-browser.d.ts.map +1 -0
  114. package/dist/internal/open-browser.js +34 -0
  115. package/dist/internal/playground/toolchain.d.ts.map +1 -1
  116. package/dist/internal/playground/toolchain.js +19 -14
  117. package/dist/internal/playground-proxy.d.ts +69 -0
  118. package/dist/internal/playground-proxy.d.ts.map +1 -0
  119. package/dist/internal/playground-proxy.js +468 -0
  120. package/dist/internal/prompt-context.d.ts +35 -0
  121. package/dist/internal/prompt-context.d.ts.map +1 -0
  122. package/dist/internal/prompt-context.js +71 -0
  123. package/dist/internal/reminder-runner.d.ts.map +1 -1
  124. package/dist/internal/reminder-runner.js +11 -11
  125. package/dist/internal/request-headers.d.ts +11 -0
  126. package/dist/internal/request-headers.d.ts.map +1 -0
  127. package/dist/internal/request-headers.js +14 -0
  128. package/dist/internal/resolve-prod-target.d.ts +44 -0
  129. package/dist/internal/resolve-prod-target.d.ts.map +1 -0
  130. package/dist/internal/resolve-prod-target.js +134 -0
  131. package/dist/internal/resolved-connections.js +5 -5
  132. package/dist/internal/run-client.d.ts +2 -2
  133. package/dist/internal/run-client.d.ts.map +1 -1
  134. package/dist/internal/run-client.js +38 -23
  135. package/dist/internal/schedule-runner.js +1 -1
  136. package/dist/internal/server.d.ts.map +1 -1
  137. package/dist/internal/server.js +23 -17
  138. package/dist/internal/session-engine.d.ts +1 -1
  139. package/dist/internal/session-engine.d.ts.map +1 -1
  140. package/dist/internal/session-engine.js +34 -19
  141. package/dist/internal/sessions-client.d.ts +34 -0
  142. package/dist/internal/sessions-client.d.ts.map +1 -0
  143. package/dist/internal/sessions-client.js +193 -0
  144. package/dist/internal/storage-coordinator.js +6 -6
  145. package/dist/internal/stream-progress.d.ts.map +1 -1
  146. package/dist/internal/stream-progress.js +31 -3
  147. package/dist/internal/terminal-style.d.ts +22 -0
  148. package/dist/internal/terminal-style.d.ts.map +1 -0
  149. package/dist/internal/terminal-style.js +49 -0
  150. package/dist/internal/trajectory.d.ts +10 -5
  151. package/dist/internal/trajectory.d.ts.map +1 -1
  152. package/dist/internal/trajectory.js +82 -10
  153. package/dist/internal/update-check.d.ts +93 -0
  154. package/dist/internal/update-check.d.ts.map +1 -0
  155. package/dist/internal/update-check.js +431 -0
  156. package/dist/internal/workspace.d.ts +11 -0
  157. package/dist/internal/workspace.d.ts.map +1 -1
  158. package/dist/internal/workspace.js +38 -4
  159. package/dist/playground/assets/index-Ct_Usdm8.css +1 -0
  160. package/dist/playground/assets/index-Dsyb-Vaj.js +319 -0
  161. package/dist/playground/index.html +2 -2
  162. package/dist/types.d.ts +29 -2
  163. package/dist/types.d.ts.map +1 -1
  164. package/docs/README.md +0 -1
  165. package/docs/quickstart.md +22 -7
  166. package/docs/reference/cli.md +51 -3
  167. package/package.json +4 -1
  168. package/skills/ab/SKILL.md +8 -8
  169. package/skills/create-agent/SKILL.md +28 -22
  170. package/skills/debug/SKILL.md +11 -11
  171. package/skills/evals/SKILL.md +16 -16
  172. package/skills/framework-map/SKILL.md +6 -6
  173. package/skills/github/SKILL.md +13 -13
  174. package/skills/hillclimb/SKILL.md +10 -10
  175. package/skills/setup-slack/SKILL.md +14 -14
  176. package/src/bin/agent-serve.ts +451 -191
  177. package/src/channels/slack/log.ts +5 -5
  178. package/src/channels/slack/setup.ts +1 -1
  179. package/src/channels/slack/socket-mode.ts +11 -9
  180. package/src/internal/ab-collector.ts +3 -3
  181. package/src/internal/ab-fold.ts +1 -1
  182. package/src/internal/chat-client.ts +252 -37
  183. package/src/internal/cli-ax.ts +761 -72
  184. package/src/internal/cli-cursor.ts +14 -42
  185. package/src/internal/cli-deploy.ts +428 -49
  186. package/src/internal/cli-github.ts +13 -15
  187. package/src/internal/cursor/account-mcp.ts +3 -3
  188. package/src/internal/cursor/backend-client.ts +1 -1
  189. package/src/internal/cursor/credentials.ts +26 -7
  190. package/src/internal/cursor/github-credentials.ts +3 -3
  191. package/src/internal/cursor-event-relay.ts +1 -1
  192. package/src/internal/cursor-relay-core.ts +4 -2
  193. package/src/internal/cursor-slack-relay.ts +1 -1
  194. package/src/internal/deploy-client.ts +45 -4
  195. package/src/internal/deploy-source.ts +133 -0
  196. package/src/internal/discovery.ts +53 -16
  197. package/src/internal/distribution.ts +8 -0
  198. package/src/internal/docs-site.ts +3 -3
  199. package/src/internal/eval-run-store.ts +10 -11
  200. package/src/internal/eval-runner.ts +5 -0
  201. package/src/internal/event-mapper.ts +222 -42
  202. package/src/internal/github-fanout.ts +2 -2
  203. package/src/internal/host-platforms.ts +5 -5
  204. package/src/internal/init-project.ts +333 -51
  205. package/src/internal/install-cursor-skills.ts +327 -0
  206. package/src/internal/logs-client.ts +442 -0
  207. package/src/internal/mcp-endpoint.ts +1 -3
  208. package/src/internal/open-browser.ts +41 -0
  209. package/src/internal/playground/toolchain.ts +18 -16
  210. package/src/internal/playground-proxy.ts +576 -0
  211. package/src/internal/prompt-context.ts +95 -0
  212. package/src/internal/reminder-runner.ts +11 -17
  213. package/src/internal/request-headers.ts +23 -0
  214. package/src/internal/resolve-prod-target.ts +182 -0
  215. package/src/internal/resolved-connections.ts +5 -5
  216. package/src/internal/run-client.ts +39 -36
  217. package/src/internal/schedule-runner.ts +1 -1
  218. package/src/internal/server.ts +25 -16
  219. package/src/internal/session-engine.ts +35 -18
  220. package/src/internal/sessions-client.ts +216 -0
  221. package/src/internal/storage-coordinator.ts +6 -6
  222. package/src/internal/stream-progress.ts +36 -2
  223. package/src/internal/terminal-style.ts +74 -0
  224. package/src/internal/trajectory.ts +91 -13
  225. package/src/internal/update-check.ts +552 -0
  226. package/src/internal/workspace.ts +42 -4
  227. package/src/types.ts +45 -7
  228. package/dist/docs/assets/chunks/@localSearchIndexroot.zwQ9RCQ7.js +0 -1
  229. package/dist/playground/assets/index-B1Qc9h2u.css +0 -1
  230. package/dist/playground/assets/index-CpDYCj8W.js +0 -79
  231. /package/dist/docs/assets/{index.md.m81y7TY7.lean.js → index.md.Cylk70gg.lean.js} +0 -0
  232. /package/dist/docs/assets/{quickstart.md.CfU8_uTC.lean.js → quickstart.md.BU6Iwi_9.lean.js} +0 -0
@@ -12,6 +12,10 @@ import { tmpdir } from "node:os";
12
12
  import { join, resolve } from "node:path";
13
13
  import { serve } from "../index.js";
14
14
  import type { AgentServeHandle } from "../types.js";
15
+ import { lookupSessionContinuation, runChat } from "./chat-client.js";
16
+ import { cmdLogin } from "./cli-cursor.js";
17
+ import { resolveDeployAuth } from "./cli-deploy.js";
18
+ import { resolveApiKey } from "./cursor/credentials.js";
15
19
  import { CLI_COMMAND_NAME } from "./distribution.js";
16
20
  import {
17
21
  discoverEvals,
@@ -19,10 +23,29 @@ import {
19
23
  filterDiscoveredEvals,
20
24
  runDiscoveredEvals,
21
25
  } from "./eval-runner.js";
22
- import { initProject, printInitGuide } from "./init-project.js";
26
+ import {
27
+ formatInitNextSteps,
28
+ formatInitScaffoldSummary,
29
+ initNextCommands,
30
+ initProject,
31
+ installScaffoldDependencies,
32
+ printInitGuide,
33
+ } from "./init-project.js";
34
+ import { offerInstallCursorSkills } from "./install-cursor-skills.js";
35
+ import { runLogsTail, sanitizeCustomerError } from "./logs-client.js";
36
+ import { openBrowser } from "./open-browser.js";
37
+ import { startPlaygroundProxy } from "./playground-proxy.js";
38
+ import { resolveProdSlug, resolveProdTarget } from "./resolve-prod-target.js";
23
39
  import { runSession } from "./run-client.js";
40
+ import {
41
+ fetchSessionEvents,
42
+ formatSessionsTable,
43
+ listSessions,
44
+ resolvePreviousSessionId,
45
+ } from "./sessions-client.js";
24
46
  import { createStreamProgress } from "./stream-progress.js";
25
47
  import {
48
+ buildTrajectory,
26
49
  formatTrajectoryText,
27
50
  loadTrajectoryFromEventsFile,
28
51
  } from "./trajectory.js";
@@ -30,7 +53,11 @@ import {
30
53
  export interface AxCliOptions {
31
54
  cwd?: string;
32
55
  dir: string;
33
- /** Agent slug when multiple agents are mounted. */
56
+ /**
57
+ * Local multi-agent mount slug, or (with `--prod`) the hosted deployment
58
+ * slug. When `--prod` is set and this is omitted, the slug is derived from
59
+ * the directory name (same as `deploy`).
60
+ */
34
61
  slug?: string;
35
62
  bearerToken?: string;
36
63
  stateRoot?: string;
@@ -59,13 +86,52 @@ export interface AxCliOptions {
59
86
  toolName?: string;
60
87
  /** JSON input for `call`. */
61
88
  toolInput?: string;
62
- /** Remote agent base URL (skip local host) for run/eval. */
89
+ /** Remote agent base URL (skip local host) for run/eval/chat. */
63
90
  url?: string;
91
+ /**
92
+ * Route chat/resume/run/call/eval/logs/sessions at the team's hosted
93
+ * deployment
94
+ * instead of a local ephemeral server. Mutually exclusive with `--url`.
95
+ */
96
+ prod?: boolean;
97
+ /** Cursor team id for `--prod` (defaults to the account's team). */
98
+ team?: string;
99
+ /** Cursor API key override for `--prod` management calls. */
100
+ apiKey?: string;
101
+ /** Injected fetch for `--prod` tests. */
102
+ fetchImpl?: typeof fetch;
64
103
  /**
65
104
  * Stream live turn progress to stderr (default: stderr is a TTY).
66
105
  * Final JSON/text still goes to stdout.
67
106
  */
68
107
  stream?: boolean;
108
+ /** Force plain chat output even on a TTY. */
109
+ noColor?: boolean;
110
+ /** `logs`: dump current buffer / progress once and exit. */
111
+ once?: boolean;
112
+ /**
113
+ * `session`: print raw `{ sessionId, events }` JSON instead of a trajectory.
114
+ * (CLI flag `--events`; rewritten from colliding with run's `--events <file>`.)
115
+ */
116
+ rawEvents?: boolean;
117
+ /**
118
+ * `playground`: print the URL only; do not open a browser.
119
+ * (CLI flag `--print`.)
120
+ */
121
+ print?: boolean;
122
+ /**
123
+ * `chat --resume` / `resume` with no session id: reattach the most
124
+ * recently updated followable session from `/v1/sessions`.
125
+ */
126
+ resume?: boolean;
127
+ /** Abort signal (tests / programmatic stop of `playground` proxy). */
128
+ signal?: AbortSignal;
129
+ }
130
+
131
+ export interface ResolvedAgentTarget {
132
+ agentUrl: string;
133
+ headers?: Record<string, string>;
134
+ close?: () => Promise<void>;
69
135
  }
70
136
 
71
137
  function shouldStreamProgress(options: AxCliOptions): boolean {
@@ -136,12 +202,26 @@ async function startEphemeral(
136
202
  };
137
203
  }
138
204
 
139
- async function resolveTarget(
205
+ export async function resolveTarget(
140
206
  options: AxCliOptions
141
- ): Promise<{ agentUrl: string; close?: () => Promise<void> }> {
207
+ ): Promise<ResolvedAgentTarget> {
208
+ if (options.prod === true && options.url !== undefined) {
209
+ die("--prod and --url are mutually exclusive");
210
+ }
142
211
  if (options.url !== undefined) {
143
212
  return { agentUrl: options.url.replace(/\/$/, "") };
144
213
  }
214
+ if (options.prod === true) {
215
+ const prod = await resolveProdTarget({
216
+ dir: options.dir,
217
+ cwd: options.cwd,
218
+ slug: options.slug,
219
+ team: options.team,
220
+ apiKey: options.apiKey,
221
+ fetchImpl: options.fetchImpl,
222
+ });
223
+ return { agentUrl: prod.agentUrl, headers: prod.headers };
224
+ }
145
225
  return startEphemeral(options);
146
226
  }
147
227
 
@@ -151,27 +231,236 @@ export async function cmdInit(options: AxCliOptions): Promise<number> {
151
231
  printInitGuide();
152
232
  return 0;
153
233
  }
154
- const dir = resolve(options.cwd ?? process.cwd(), target);
234
+ const cwd = options.cwd ?? process.cwd();
235
+ const dir = resolve(cwd, target);
155
236
  const result = await initProject({ dir });
237
+ let signedIn = (await resolveApiKey()) !== undefined;
238
+
239
+ // Machine-readable path: install deps (piped), never block on browser login.
240
+ if (options.json) {
241
+ const install = await installScaffoldDependencies(result.rootDir, {
242
+ stdio: "pipe",
243
+ });
244
+ process.stdout.write(
245
+ `${JSON.stringify(
246
+ {
247
+ ok: install.ok,
248
+ directory: result.rootDir,
249
+ created: result.created,
250
+ skipped: result.skipped,
251
+ installed: install.ok,
252
+ installError: install.ok
253
+ ? null
254
+ : install.stderr.trim() || `npm install exited ${install.exitCode}`,
255
+ next: initNextCommands({
256
+ rootDir: result.rootDir,
257
+ cwd,
258
+ signedIn,
259
+ }),
260
+ },
261
+ null,
262
+ 2
263
+ )}\n`
264
+ );
265
+ return install.ok ? 0 : 1;
266
+ }
267
+
156
268
  process.stdout.write(
157
- `${JSON.stringify(
158
- {
159
- ok: true,
160
- directory: result.rootDir,
161
- created: result.files,
162
- next: [
163
- `cd ${dir === process.cwd() ? "." : dir}`,
164
- `${CLI_COMMAND_NAME} validate`,
165
- `${CLI_COMMAND_NAME} info --json`,
166
- `${CLI_COMMAND_NAME} run --message "hello"`,
167
- `${CLI_COMMAND_NAME} eval`,
168
- ],
169
- },
170
- null,
171
- 2
172
- )}\n`
269
+ formatInitScaffoldSummary({
270
+ rootDir: result.rootDir,
271
+ files: result.files,
272
+ })
173
273
  );
174
- return 0;
274
+ process.stdout.write("Installing npm packages\n\n");
275
+ const install = await installScaffoldDependencies(result.rootDir, {
276
+ stdio: "inherit",
277
+ });
278
+ if (!install.ok) {
279
+ process.stderr.write(
280
+ `\nnpm install failed (exit ${install.exitCode}). Fix the install, then run ${CLI_COMMAND_NAME} dev.\n`
281
+ );
282
+ return install.exitCode || 1;
283
+ }
284
+ process.stdout.write("\n");
285
+
286
+ // Personal Cursor skills so coding agents can pick up create-agent / debug / …
287
+ try {
288
+ await offerInstallCursorSkills();
289
+ } catch (err) {
290
+ const message = err instanceof Error ? err.message : String(err);
291
+ process.stderr.write(
292
+ `\nCould not install Cursor skills (${message}). Continuing init.\n\n`
293
+ );
294
+ }
295
+
296
+ let loginExit = 0;
297
+ if (!signedIn) {
298
+ process.stdout.write("Signing you in to Cursor\n\n");
299
+ loginExit = await cmdLogin({});
300
+ signedIn = loginExit === 0 && (await resolveApiKey()) !== undefined;
301
+ process.stdout.write("\n");
302
+ }
303
+
304
+ process.stdout.write(
305
+ formatInitNextSteps({
306
+ rootDir: result.rootDir,
307
+ cwd,
308
+ signedIn,
309
+ })
310
+ );
311
+ return loginExit;
312
+ }
313
+
314
+ /**
315
+ * `chat` — talk to a running (or `--prod` hosted) agent. With `--json`,
316
+ * prints a trajectory instead of the interactive UI.
317
+ */
318
+ /**
319
+ * `resume [sessionId]` — reattach the interactive chat REPL to an existing
320
+ * session. When the id is omitted, picks the most recently updated
321
+ * followable session from `/v1/sessions` (same as `chat --resume`).
322
+ * Looks up the continuation token via `/v1/sessions` when
323
+ * `--continuation-token` is omitted. Same flags as `chat` (`--prod`,
324
+ * `--message`, `--json`, …). `--session` is accepted as a redundant
325
+ * alias for the positional id.
326
+ */
327
+ export async function cmdResume(
328
+ sessionId: string | undefined,
329
+ options: AxCliOptions
330
+ ): Promise<number> {
331
+ const resolved = trimNonEmpty(sessionId) ?? trimNonEmpty(options.sessionId);
332
+ if (resolved !== undefined) {
333
+ return cmdChat({
334
+ ...options,
335
+ sessionId: resolved,
336
+ resume: false,
337
+ });
338
+ }
339
+ return cmdChat({
340
+ ...options,
341
+ sessionId: undefined,
342
+ resume: true,
343
+ });
344
+ }
345
+
346
+ function trimNonEmpty(value: string | undefined): string | undefined {
347
+ if (value === undefined) {
348
+ return undefined;
349
+ }
350
+ const trimmed = value.trim();
351
+ return trimmed === "" ? undefined : trimmed;
352
+ }
353
+
354
+ export async function cmdChat(options: AxCliOptions): Promise<number> {
355
+ const message = options.messages?.[0];
356
+ // chat never starts an ephemeral server — default to local serve URL.
357
+ const target = await resolveTarget({
358
+ ...options,
359
+ url:
360
+ options.prod === true
361
+ ? undefined
362
+ : (options.url ?? "http://127.0.0.1:3000"),
363
+ });
364
+
365
+ let sessionId = trimNonEmpty(options.sessionId);
366
+ // `--resume` without an id → most recently updated followable session.
367
+ // An explicit `--session` / positional id always wins.
368
+ if (options.resume === true && sessionId === undefined) {
369
+ try {
370
+ const previous = await resolvePreviousSessionId({
371
+ baseUrl: target.agentUrl,
372
+ auth: {
373
+ bearerToken: options.bearerToken,
374
+ headers: target.headers,
375
+ },
376
+ fetchImpl: options.fetchImpl,
377
+ });
378
+ if (previous === undefined) {
379
+ process.stderr.write(
380
+ "No previous followable session found. Start one with " +
381
+ `\`${CLI_COMMAND_NAME} chat\` or pass a session id.\n`
382
+ );
383
+ return 1;
384
+ }
385
+ sessionId = previous;
386
+ } catch (error) {
387
+ process.stderr.write(
388
+ `${error instanceof Error ? error.message : String(error)}\n`
389
+ );
390
+ return 1;
391
+ }
392
+ }
393
+
394
+ if (options.json) {
395
+ if (message === undefined) {
396
+ process.stderr.write("chat --json requires --message\n");
397
+ return 2;
398
+ }
399
+ let continuationToken = options.continuationToken;
400
+ if (
401
+ sessionId !== undefined &&
402
+ (continuationToken === undefined || continuationToken === "")
403
+ ) {
404
+ try {
405
+ continuationToken = await lookupSessionContinuation({
406
+ baseUrl: target.agentUrl,
407
+ sessionId,
408
+ auth: {
409
+ bearerToken: options.bearerToken,
410
+ headers: target.headers,
411
+ },
412
+ });
413
+ } catch (error) {
414
+ process.stderr.write(
415
+ `${error instanceof Error ? error.message : String(error)}\n`
416
+ );
417
+ return 1;
418
+ }
419
+ }
420
+ const result = await runSession({
421
+ baseUrl: target.agentUrl,
422
+ messages: [message],
423
+ sessionId,
424
+ continuationToken,
425
+ bearerToken: options.bearerToken,
426
+ headers: target.headers,
427
+ });
428
+ if (options.text) {
429
+ process.stdout.write(formatTrajectoryText(result.trajectory));
430
+ } else {
431
+ console.log(
432
+ JSON.stringify(
433
+ {
434
+ ok: result.ok,
435
+ sessionId: result.sessionId,
436
+ continuationToken: result.continuationToken ?? null,
437
+ trajectory: result.trajectory,
438
+ },
439
+ null,
440
+ 2
441
+ )
442
+ );
443
+ }
444
+ return result.ok ? 0 : 1;
445
+ }
446
+
447
+ try {
448
+ await runChat({
449
+ baseUrl: target.agentUrl,
450
+ message,
451
+ sessionId,
452
+ continuationToken: options.continuationToken,
453
+ bearerToken: options.bearerToken,
454
+ headers: target.headers,
455
+ noColor: options.noColor,
456
+ });
457
+ return 0;
458
+ } catch (error) {
459
+ process.stderr.write(
460
+ `${error instanceof Error ? error.message : String(error)}\n`
461
+ );
462
+ return 1;
463
+ }
175
464
  }
176
465
 
177
466
  export async function cmdRun(options: AxCliOptions): Promise<number> {
@@ -191,21 +480,12 @@ export async function cmdRun(options: AxCliOptions): Promise<number> {
191
480
  const result = await runSession({
192
481
  baseUrl: target.agentUrl,
193
482
  messages,
194
- ...(options.sessionId === undefined
195
- ? {}
196
- : { sessionId: options.sessionId }),
197
- ...(options.continuationToken === undefined
198
- ? {}
199
- : { continuationToken: options.continuationToken }),
200
- ...(options.bearerToken === undefined
201
- ? {}
202
- : { bearerToken: options.bearerToken }),
203
- ...(options.timeoutMs === undefined
204
- ? {}
205
- : { timeoutMs: options.timeoutMs }),
206
- ...(progress === undefined
207
- ? {}
208
- : { onEvent: (e) => progress.onEvent(e) }),
483
+ sessionId: options.sessionId,
484
+ continuationToken: options.continuationToken,
485
+ bearerToken: options.bearerToken,
486
+ headers: target.headers,
487
+ timeoutMs: options.timeoutMs,
488
+ onEvent: progress === undefined ? undefined : (e) => progress.onEvent(e),
209
489
  });
210
490
 
211
491
  let eventsPath: string | undefined;
@@ -227,8 +507,26 @@ export async function cmdRun(options: AxCliOptions): Promise<number> {
227
507
  }
228
508
 
229
509
  const playgroundUrl =
230
- options.url !== undefined
231
- ? `${target.agentUrl.replace(/\/$/, "")}/playground?sessionId=${encodeURIComponent(result.sessionId)}`
510
+ options.prod === true
511
+ ? null
512
+ : options.url !== undefined
513
+ ? `${target.agentUrl.replace(/\/$/, "")}/playground?sessionId=${encodeURIComponent(result.sessionId)}`
514
+ : null;
515
+ const playgroundHint =
516
+ options.prod === true
517
+ ? [
518
+ CLI_COMMAND_NAME,
519
+ "playground",
520
+ "--prod",
521
+ ...(options.slug !== undefined && options.slug.trim() !== ""
522
+ ? ["--slug", options.slug.trim()]
523
+ : []),
524
+ ...(options.team !== undefined && options.team.trim() !== ""
525
+ ? ["--team", options.team.trim()]
526
+ : []),
527
+ "--session",
528
+ result.sessionId,
529
+ ].join(" ")
232
530
  : null;
233
531
 
234
532
  if (options.text) {
@@ -238,6 +536,8 @@ export async function cmdRun(options: AxCliOptions): Promise<number> {
238
536
  }
239
537
  if (playgroundUrl !== null) {
240
538
  process.stderr.write(`playground: ${playgroundUrl}\n`);
539
+ } else if (playgroundHint !== null) {
540
+ process.stderr.write(`playground: ${playgroundHint}\n`);
241
541
  }
242
542
  } else {
243
543
  console.log(
@@ -248,12 +548,15 @@ export async function cmdRun(options: AxCliOptions): Promise<number> {
248
548
  continuationToken: result.continuationToken ?? null,
249
549
  trace: eventsPath ?? null,
250
550
  playgroundUrl,
551
+ playgroundHint,
251
552
  visualize:
252
- playgroundUrl !== null
253
- ? `Open ${playgroundUrl}`
254
- : eventsPath !== undefined
255
- ? `Start the playground (${CLI_COMMAND_NAME} serve --dir ${options.dir}), then Open trace → ${eventsPath}`
256
- : null,
553
+ playgroundHint !== null
554
+ ? `Run ${playgroundHint}`
555
+ : playgroundUrl !== null
556
+ ? `Open ${playgroundUrl}`
557
+ : eventsPath !== undefined
558
+ ? `Start the playground (${CLI_COMMAND_NAME} serve --dir ${options.dir}), then Open trace → ${eventsPath}`
559
+ : null,
257
560
  trajectory: result.trajectory,
258
561
  },
259
562
  null,
@@ -296,22 +599,25 @@ export async function cmdCall(options: AxCliOptions): Promise<number> {
296
599
 
297
600
  const target = await resolveTarget(options);
298
601
  try {
602
+ const headers: Record<string, string> = {
603
+ "content-type": "application/json",
604
+ };
605
+ if (target.headers !== undefined) {
606
+ Object.assign(headers, target.headers);
607
+ }
608
+ if (options.bearerToken !== undefined) {
609
+ headers.authorization = `Bearer ${options.bearerToken}`;
610
+ }
611
+ const body: { input: unknown; sessionId?: string } = { input };
612
+ if (options.sessionId !== undefined) {
613
+ body.sessionId = options.sessionId;
614
+ }
299
615
  const response = await fetch(
300
616
  `${target.agentUrl}/v1/tools/${encodeURIComponent(toolName)}`,
301
617
  {
302
618
  method: "POST",
303
- headers: {
304
- "content-type": "application/json",
305
- ...(options.bearerToken === undefined
306
- ? {}
307
- : { authorization: `Bearer ${options.bearerToken}` }),
308
- },
309
- body: JSON.stringify({
310
- input,
311
- ...(options.sessionId === undefined
312
- ? {}
313
- : { sessionId: options.sessionId }),
314
- }),
619
+ headers,
620
+ body: JSON.stringify(body),
315
621
  }
316
622
  );
317
623
  const payload: unknown = await response
@@ -399,22 +705,19 @@ export async function cmdEval(options: AxCliOptions): Promise<number> {
399
705
  const results = await runDiscoveredEvals({
400
706
  projectRoot,
401
707
  baseUrl: target.agentUrl,
402
- ...(options.evalIds === undefined || options.evalIds.length === 0
403
- ? {}
404
- : { filterIds: options.evalIds }),
405
- ...(options.tags === undefined || options.tags.length === 0
406
- ? {}
407
- : { tags: options.tags }),
408
- ...(options.timeoutMs === undefined
409
- ? {}
410
- : { timeoutMs: options.timeoutMs }),
411
- ...(options.bearerToken === undefined
412
- ? {}
413
- : { bearerToken: options.bearerToken }),
708
+ filterIds:
709
+ options.evalIds === undefined || options.evalIds.length === 0
710
+ ? undefined
711
+ : options.evalIds,
712
+ tags:
713
+ options.tags === undefined || options.tags.length === 0
714
+ ? undefined
715
+ : options.tags,
716
+ timeoutMs: options.timeoutMs,
717
+ bearerToken: options.bearerToken,
718
+ headers: target.headers,
414
719
  verbose: Boolean(options.verbose) || stream,
415
- ...(progress === undefined
416
- ? {}
417
- : { onEvent: (e) => progress.onEvent(e) }),
720
+ onEvent: progress === undefined ? undefined : (e) => progress.onEvent(e),
418
721
  });
419
722
 
420
723
  if (results.length === 0) {
@@ -472,3 +775,389 @@ function printEvalResults(
472
775
  }
473
776
  return failed === 0 ? 0 : 1;
474
777
  }
778
+
779
+ /**
780
+ * `logs` — follow deploy progress (`--prod`) then runtime agent logs.
781
+ * Local / `--url` tails `/v1/logs` only.
782
+ */
783
+ export async function cmdLogs(options: AxCliOptions): Promise<number> {
784
+ if (options.prod === true && options.url !== undefined) {
785
+ process.stderr.write("--prod and --url are mutually exclusive\n");
786
+ return 2;
787
+ }
788
+
789
+ const controller = new AbortController();
790
+ const onSignal = (): void => {
791
+ controller.abort();
792
+ };
793
+ process.on("SIGINT", onSignal);
794
+ process.on("SIGTERM", onSignal);
795
+
796
+ try {
797
+ if (options.prod === true) {
798
+ const slug = resolveProdSlug({
799
+ dir: options.dir,
800
+ cwd: options.cwd,
801
+ slug: options.slug,
802
+ });
803
+ const auth = await resolveDeployAuth({
804
+ team: options.team,
805
+ apiKey: options.apiKey,
806
+ fetchImpl: options.fetchImpl,
807
+ });
808
+ if (typeof auth === "number") {
809
+ return auth;
810
+ }
811
+ await runLogsTail({
812
+ prod: true,
813
+ dir: options.dir,
814
+ cwd: options.cwd,
815
+ slug,
816
+ team: options.team,
817
+ apiKey: options.apiKey,
818
+ bearerToken: options.bearerToken,
819
+ once: options.once,
820
+ json: options.json,
821
+ fetchImpl: options.fetchImpl,
822
+ signal: controller.signal,
823
+ getDeployment: () =>
824
+ auth.client.getDeployment({ teamId: auth.teamId, slug }),
825
+ resolveRuntime: async () => {
826
+ const target = await resolveProdTarget({
827
+ dir: options.dir,
828
+ cwd: options.cwd,
829
+ slug,
830
+ team: options.team,
831
+ apiKey: options.apiKey,
832
+ fetchImpl: options.fetchImpl,
833
+ err: () => {},
834
+ });
835
+ return { agentUrl: target.agentUrl, headers: target.headers };
836
+ },
837
+ });
838
+ return 0;
839
+ }
840
+
841
+ await runLogsTail({
842
+ dir: options.dir,
843
+ cwd: options.cwd,
844
+ url: options.url ?? "http://127.0.0.1:3000",
845
+ bearerToken: options.bearerToken,
846
+ once: options.once,
847
+ json: options.json,
848
+ fetchImpl: options.fetchImpl,
849
+ signal: controller.signal,
850
+ });
851
+ return 0;
852
+ } catch (error) {
853
+ if (controller.signal.aborted) {
854
+ return 0;
855
+ }
856
+ const raw = error instanceof Error ? error.message : String(error);
857
+ process.stderr.write(`${sanitizeCustomerError(raw)}\n`);
858
+ return 1;
859
+ } finally {
860
+ process.off("SIGINT", onSignal);
861
+ process.off("SIGTERM", onSignal);
862
+ }
863
+ }
864
+
865
+ /** Resolve local / `--url` / `--prod` agent base URL + request headers. */
866
+ async function resolveSessionTarget(
867
+ options: AxCliOptions
868
+ ): Promise<{ agentUrl: string; headers?: Record<string, string> } | number> {
869
+ if (options.prod === true && options.url !== undefined) {
870
+ process.stderr.write("--prod and --url are mutually exclusive\n");
871
+ return 2;
872
+ }
873
+ if (options.prod === true) {
874
+ try {
875
+ const target = await resolveProdTarget({
876
+ dir: options.dir,
877
+ cwd: options.cwd,
878
+ slug: options.slug,
879
+ team: options.team,
880
+ apiKey: options.apiKey,
881
+ fetchImpl: options.fetchImpl,
882
+ });
883
+ return { agentUrl: target.agentUrl, headers: target.headers };
884
+ } catch (error) {
885
+ process.stderr.write(
886
+ `${sanitizeCustomerError(
887
+ error instanceof Error ? error.message : String(error)
888
+ )}\n`
889
+ );
890
+ return 1;
891
+ }
892
+ }
893
+ return {
894
+ agentUrl: (options.url ?? "http://127.0.0.1:3000").replace(/\/$/, ""),
895
+ };
896
+ }
897
+
898
+ /**
899
+ * `sessions` — list sessions on a running (or `--prod` hosted) agent.
900
+ */
901
+ export async function cmdSessions(options: AxCliOptions): Promise<number> {
902
+ const target = await resolveSessionTarget(options);
903
+ if (typeof target === "number") {
904
+ return target;
905
+ }
906
+ try {
907
+ const sessions = await listSessions({
908
+ baseUrl: target.agentUrl,
909
+ auth: {
910
+ bearerToken: options.bearerToken,
911
+ headers: target.headers,
912
+ },
913
+ fetchImpl: options.fetchImpl,
914
+ });
915
+ if (options.json === true) {
916
+ process.stdout.write(`${JSON.stringify({ sessions }, null, 2)}\n`);
917
+ return 0;
918
+ }
919
+ process.stdout.write(formatSessionsTable(sessions));
920
+ return 0;
921
+ } catch (error) {
922
+ process.stderr.write(
923
+ `${sanitizeCustomerError(
924
+ error instanceof Error ? error.message : String(error)
925
+ )}\n`
926
+ );
927
+ return 1;
928
+ }
929
+ }
930
+
931
+ /**
932
+ * `session <id>` — view a full session (trajectory text by default).
933
+ * `--json` → trajectory JSON; `--events` (`rawEvents`) → raw event list.
934
+ * Interactive reattach: `resume [id]` / `chat --resume` (or `chat --session`).
935
+ */
936
+ export async function cmdSession(
937
+ sessionId: string | undefined,
938
+ options: AxCliOptions
939
+ ): Promise<number> {
940
+ if (sessionId === undefined || sessionId.trim() === "") {
941
+ process.stderr.write(
942
+ `Usage: ${CLI_COMMAND_NAME} session <sessionId> [--url | --prod] [--json | --text | --events]\n`
943
+ );
944
+ return 2;
945
+ }
946
+ if (options.rawEvents === true && options.json === true) {
947
+ process.stderr.write("--events and --json are mutually exclusive\n");
948
+ return 2;
949
+ }
950
+
951
+ const target = await resolveSessionTarget(options);
952
+ if (typeof target === "number") {
953
+ return target;
954
+ }
955
+
956
+ try {
957
+ const events = await fetchSessionEvents({
958
+ baseUrl: target.agentUrl,
959
+ sessionId,
960
+ auth: {
961
+ bearerToken: options.bearerToken,
962
+ headers: target.headers,
963
+ },
964
+ fetchImpl: options.fetchImpl,
965
+ });
966
+
967
+ if (options.rawEvents === true) {
968
+ process.stdout.write(
969
+ `${JSON.stringify({ sessionId, events }, null, 2)}\n`
970
+ );
971
+ return 0;
972
+ }
973
+
974
+ const trajectory = buildTrajectory(events);
975
+ if (options.json === true) {
976
+ process.stdout.write(`${JSON.stringify(trajectory, null, 2)}\n`);
977
+ return 0;
978
+ }
979
+ process.stdout.write(formatTrajectoryText(trajectory));
980
+ return 0;
981
+ } catch (error) {
982
+ process.stderr.write(
983
+ `${sanitizeCustomerError(
984
+ error instanceof Error ? error.message : String(error)
985
+ )}\n`
986
+ );
987
+ return 1;
988
+ }
989
+ }
990
+
991
+ /**
992
+ * `playground` — open the web UI against local / `--url` / `--prod`.
993
+ *
994
+ * Hosted engines need short-lived access headers a browser cannot set, so
995
+ * `--prod` (and `--bearer-token`) run a loopback reverse proxy that injects
996
+ * them. Ctrl-C stops the proxy.
997
+ */
998
+ export async function cmdPlayground(options: AxCliOptions): Promise<number> {
999
+ if (options.prod === true && options.url !== undefined) {
1000
+ process.stderr.write("--prod and --url are mutually exclusive\n");
1001
+ return 2;
1002
+ }
1003
+
1004
+ const sessionId =
1005
+ options.sessionId !== undefined && options.sessionId.trim() !== ""
1006
+ ? options.sessionId.trim()
1007
+ : undefined;
1008
+
1009
+ // Hosted: mint engineAccess and refresh it for the life of the proxy.
1010
+ if (options.prod === true) {
1011
+ let initial: Awaited<ReturnType<typeof resolveProdTarget>>;
1012
+ try {
1013
+ initial = await resolveProdTarget({
1014
+ dir: options.dir,
1015
+ cwd: options.cwd,
1016
+ slug: options.slug,
1017
+ team: options.team,
1018
+ apiKey: options.apiKey,
1019
+ fetchImpl: options.fetchImpl,
1020
+ });
1021
+ } catch (error) {
1022
+ process.stderr.write(
1023
+ `${sanitizeCustomerError(
1024
+ error instanceof Error ? error.message : String(error)
1025
+ )}\n`
1026
+ );
1027
+ return 1;
1028
+ }
1029
+
1030
+ let proxy: Awaited<ReturnType<typeof startPlaygroundProxy>>;
1031
+ try {
1032
+ proxy = await startPlaygroundProxy({
1033
+ upstreamUrl: initial.agentUrl,
1034
+ headers: initial.headers,
1035
+ expiresAt: initial.expiresAt,
1036
+ refreshUpstream: async () => {
1037
+ const next = await resolveProdTarget({
1038
+ dir: options.dir,
1039
+ cwd: options.cwd,
1040
+ slug: options.slug ?? initial.slug,
1041
+ team: options.team,
1042
+ apiKey: options.apiKey,
1043
+ fetchImpl: options.fetchImpl,
1044
+ err: () => {},
1045
+ });
1046
+ return {
1047
+ upstreamUrl: next.agentUrl,
1048
+ headers: next.headers,
1049
+ expiresAt: next.expiresAt,
1050
+ };
1051
+ },
1052
+ });
1053
+ } catch (error) {
1054
+ process.stderr.write(
1055
+ `${sanitizeCustomerError(
1056
+ error instanceof Error ? error.message : String(error)
1057
+ )}\n`
1058
+ );
1059
+ return 1;
1060
+ }
1061
+
1062
+ return await runPlaygroundProxySession({
1063
+ proxy,
1064
+ sessionId,
1065
+ print: options.print === true,
1066
+ signal: options.signal,
1067
+ });
1068
+ }
1069
+
1070
+ const target = await resolveSessionTarget(options);
1071
+ if (typeof target === "number") {
1072
+ return target;
1073
+ }
1074
+
1075
+ const needsProxy =
1076
+ (target.headers !== undefined && Object.keys(target.headers).length > 0) ||
1077
+ (options.bearerToken !== undefined && options.bearerToken.trim() !== "");
1078
+
1079
+ if (!needsProxy) {
1080
+ const base = `${target.agentUrl.replace(/\/$/, "")}/playground`;
1081
+ const playgroundUrl =
1082
+ sessionId === undefined
1083
+ ? base
1084
+ : `${base}?sessionId=${encodeURIComponent(sessionId)}`;
1085
+ process.stdout.write(`${playgroundUrl}\n`);
1086
+ if (options.print !== true) {
1087
+ openBrowser(playgroundUrl);
1088
+ }
1089
+ return 0;
1090
+ }
1091
+
1092
+ let proxy: Awaited<ReturnType<typeof startPlaygroundProxy>>;
1093
+ try {
1094
+ proxy = await startPlaygroundProxy({
1095
+ upstreamUrl: target.agentUrl,
1096
+ headers: target.headers,
1097
+ bearerToken: options.bearerToken,
1098
+ });
1099
+ } catch (error) {
1100
+ process.stderr.write(
1101
+ `${sanitizeCustomerError(
1102
+ error instanceof Error ? error.message : String(error)
1103
+ )}\n`
1104
+ );
1105
+ return 1;
1106
+ }
1107
+
1108
+ return await runPlaygroundProxySession({
1109
+ proxy,
1110
+ sessionId,
1111
+ print: options.print === true,
1112
+ signal: options.signal,
1113
+ });
1114
+ }
1115
+
1116
+ async function runPlaygroundProxySession(args: {
1117
+ proxy: Awaited<ReturnType<typeof startPlaygroundProxy>>;
1118
+ sessionId?: string;
1119
+ print: boolean;
1120
+ signal?: AbortSignal;
1121
+ }): Promise<number> {
1122
+ const { proxy } = args;
1123
+
1124
+ const playgroundUrl = proxy.playgroundUrl(args.sessionId);
1125
+ process.stdout.write(`${playgroundUrl}\n`);
1126
+ process.stderr.write(`Playground proxy on loopback (Ctrl-C to stop).\n`);
1127
+ if (args.print !== true) {
1128
+ openBrowser(playgroundUrl);
1129
+ }
1130
+
1131
+ const controller = new AbortController();
1132
+ const onSignal = (): void => {
1133
+ controller.abort();
1134
+ };
1135
+ process.on("SIGINT", onSignal);
1136
+ process.on("SIGTERM", onSignal);
1137
+ const external = args.signal;
1138
+ if (external !== undefined) {
1139
+ if (external.aborted) {
1140
+ controller.abort();
1141
+ } else {
1142
+ external.addEventListener("abort", onSignal, { once: true });
1143
+ }
1144
+ }
1145
+
1146
+ try {
1147
+ await new Promise<void>((resolve) => {
1148
+ if (controller.signal.aborted) {
1149
+ resolve();
1150
+ return;
1151
+ }
1152
+ controller.signal.addEventListener("abort", () => resolve(), {
1153
+ once: true,
1154
+ });
1155
+ });
1156
+ return 0;
1157
+ } finally {
1158
+ process.off("SIGINT", onSignal);
1159
+ process.off("SIGTERM", onSignal);
1160
+ external?.removeEventListener("abort", onSignal);
1161
+ await proxy.close().catch(() => {});
1162
+ }
1163
+ }