@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.
- package/AGENTS.md +16 -5
- package/README.md +8 -9
- package/dist/bin/agent-serve.d.ts +3 -1
- package/dist/bin/agent-serve.d.ts.map +1 -1
- package/dist/bin/agent-serve.js +416 -155
- package/dist/channels/slack/log.d.ts +1 -1
- package/dist/channels/slack/log.d.ts.map +1 -1
- package/dist/channels/slack/log.js +4 -5
- package/dist/channels/slack/setup.js +1 -1
- package/dist/channels/slack/socket-mode.d.ts.map +1 -1
- package/dist/channels/slack/socket-mode.js +10 -9
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.Oje4vhlk.js → app.DF-Yx4OP.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.0XrheBv2.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.H5XZ2zCB.js → VPLocalSearchBox.DSeJSudL.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CTR_TuaE.js → theme.DZVLTXOC.js} +2 -2
- package/dist/docs/assets/{index.md.m81y7TY7.js → index.md.Cylk70gg.js} +1 -1
- package/dist/docs/assets/{quickstart.md.CfU8_uTC.js → quickstart.md.BU6Iwi_9.js} +18 -6
- package/dist/docs/assets/{reference_cli.md.DA730zCu.js → reference_cli.md.Bv6pOxcF.js} +11 -6
- package/dist/docs/assets/{reference_cli.md.DA730zCu.lean.js → reference_cli.md.Bv6pOxcF.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +5 -5
- package/dist/docs/quickstart.html +22 -10
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +14 -9
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/internal/ab-collector.js +3 -3
- package/dist/internal/ab-fold.js +1 -1
- package/dist/internal/chat-client.d.ts +29 -3
- package/dist/internal/chat-client.d.ts.map +1 -1
- package/dist/internal/chat-client.js +180 -27
- package/dist/internal/cli-ax.d.ts +83 -2
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +626 -52
- package/dist/internal/cli-cursor.d.ts.map +1 -1
- package/dist/internal/cli-cursor.js +8 -36
- package/dist/internal/cli-deploy.d.ts +59 -3
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +316 -38
- package/dist/internal/cli-github.js +13 -13
- package/dist/internal/cursor/account-mcp.js +3 -3
- package/dist/internal/cursor/backend-client.js +1 -1
- package/dist/internal/cursor/credentials.d.ts +14 -3
- package/dist/internal/cursor/credentials.d.ts.map +1 -1
- package/dist/internal/cursor/credentials.js +21 -6
- package/dist/internal/cursor/github-credentials.js +3 -3
- package/dist/internal/cursor-event-relay.js +1 -1
- package/dist/internal/cursor-relay-core.d.ts +1 -1
- package/dist/internal/cursor-relay-core.d.ts.map +1 -1
- package/dist/internal/cursor-relay-core.js +2 -1
- package/dist/internal/cursor-slack-relay.js +1 -1
- package/dist/internal/deploy-client.d.ts +9 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +23 -3
- package/dist/internal/deploy-source.d.ts +35 -0
- package/dist/internal/deploy-source.d.ts.map +1 -0
- package/dist/internal/deploy-source.js +118 -0
- package/dist/internal/discovery.d.ts +11 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +43 -14
- package/dist/internal/distribution.d.ts +7 -0
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +7 -0
- package/dist/internal/docs-site.js +3 -3
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +10 -9
- package/dist/internal/eval-runner.d.ts +2 -0
- package/dist/internal/eval-runner.d.ts.map +1 -1
- package/dist/internal/eval-runner.js +2 -0
- package/dist/internal/event-mapper.d.ts +54 -1
- package/dist/internal/event-mapper.d.ts.map +1 -1
- package/dist/internal/event-mapper.js +151 -41
- package/dist/internal/github-fanout.js +2 -2
- package/dist/internal/host-platforms.js +5 -5
- package/dist/internal/init-project.d.ts +88 -1
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +221 -31
- package/dist/internal/install-cursor-skills.d.ts +64 -0
- package/dist/internal/install-cursor-skills.d.ts.map +1 -0
- package/dist/internal/install-cursor-skills.js +274 -0
- package/dist/internal/logs-client.d.ts +60 -0
- package/dist/internal/logs-client.d.ts.map +1 -0
- package/dist/internal/logs-client.js +311 -0
- package/dist/internal/mcp-endpoint.d.ts.map +1 -1
- package/dist/internal/mcp-endpoint.js +1 -1
- package/dist/internal/open-browser.d.ts +5 -0
- package/dist/internal/open-browser.d.ts.map +1 -0
- package/dist/internal/open-browser.js +34 -0
- package/dist/internal/playground/toolchain.d.ts.map +1 -1
- package/dist/internal/playground/toolchain.js +19 -14
- package/dist/internal/playground-proxy.d.ts +69 -0
- package/dist/internal/playground-proxy.d.ts.map +1 -0
- package/dist/internal/playground-proxy.js +468 -0
- package/dist/internal/prompt-context.d.ts +35 -0
- package/dist/internal/prompt-context.d.ts.map +1 -0
- package/dist/internal/prompt-context.js +71 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +11 -11
- package/dist/internal/request-headers.d.ts +11 -0
- package/dist/internal/request-headers.d.ts.map +1 -0
- package/dist/internal/request-headers.js +14 -0
- package/dist/internal/resolve-prod-target.d.ts +44 -0
- package/dist/internal/resolve-prod-target.d.ts.map +1 -0
- package/dist/internal/resolve-prod-target.js +134 -0
- package/dist/internal/resolved-connections.js +5 -5
- package/dist/internal/run-client.d.ts +2 -2
- package/dist/internal/run-client.d.ts.map +1 -1
- package/dist/internal/run-client.js +38 -23
- package/dist/internal/schedule-runner.js +1 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +23 -17
- package/dist/internal/session-engine.d.ts +1 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +34 -19
- package/dist/internal/sessions-client.d.ts +34 -0
- package/dist/internal/sessions-client.d.ts.map +1 -0
- package/dist/internal/sessions-client.js +193 -0
- package/dist/internal/storage-coordinator.js +6 -6
- package/dist/internal/stream-progress.d.ts.map +1 -1
- package/dist/internal/stream-progress.js +31 -3
- package/dist/internal/terminal-style.d.ts +22 -0
- package/dist/internal/terminal-style.d.ts.map +1 -0
- package/dist/internal/terminal-style.js +49 -0
- package/dist/internal/trajectory.d.ts +10 -5
- package/dist/internal/trajectory.d.ts.map +1 -1
- package/dist/internal/trajectory.js +82 -10
- package/dist/internal/update-check.d.ts +93 -0
- package/dist/internal/update-check.d.ts.map +1 -0
- package/dist/internal/update-check.js +431 -0
- package/dist/internal/workspace.d.ts +11 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +38 -4
- package/dist/playground/assets/index-Ct_Usdm8.css +1 -0
- package/dist/playground/assets/index-Dsyb-Vaj.js +319 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +29 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +0 -1
- package/docs/quickstart.md +22 -7
- package/docs/reference/cli.md +51 -3
- package/package.json +4 -1
- package/skills/ab/SKILL.md +8 -8
- package/skills/create-agent/SKILL.md +28 -22
- package/skills/debug/SKILL.md +11 -11
- package/skills/evals/SKILL.md +16 -16
- package/skills/framework-map/SKILL.md +6 -6
- package/skills/github/SKILL.md +13 -13
- package/skills/hillclimb/SKILL.md +10 -10
- package/skills/setup-slack/SKILL.md +14 -14
- package/src/bin/agent-serve.ts +451 -191
- package/src/channels/slack/log.ts +5 -5
- package/src/channels/slack/setup.ts +1 -1
- package/src/channels/slack/socket-mode.ts +11 -9
- package/src/internal/ab-collector.ts +3 -3
- package/src/internal/ab-fold.ts +1 -1
- package/src/internal/chat-client.ts +252 -37
- package/src/internal/cli-ax.ts +761 -72
- package/src/internal/cli-cursor.ts +14 -42
- package/src/internal/cli-deploy.ts +428 -49
- package/src/internal/cli-github.ts +13 -15
- package/src/internal/cursor/account-mcp.ts +3 -3
- package/src/internal/cursor/backend-client.ts +1 -1
- package/src/internal/cursor/credentials.ts +26 -7
- package/src/internal/cursor/github-credentials.ts +3 -3
- package/src/internal/cursor-event-relay.ts +1 -1
- package/src/internal/cursor-relay-core.ts +4 -2
- package/src/internal/cursor-slack-relay.ts +1 -1
- package/src/internal/deploy-client.ts +45 -4
- package/src/internal/deploy-source.ts +133 -0
- package/src/internal/discovery.ts +53 -16
- package/src/internal/distribution.ts +8 -0
- package/src/internal/docs-site.ts +3 -3
- package/src/internal/eval-run-store.ts +10 -11
- package/src/internal/eval-runner.ts +5 -0
- package/src/internal/event-mapper.ts +222 -42
- package/src/internal/github-fanout.ts +2 -2
- package/src/internal/host-platforms.ts +5 -5
- package/src/internal/init-project.ts +333 -51
- package/src/internal/install-cursor-skills.ts +327 -0
- package/src/internal/logs-client.ts +442 -0
- package/src/internal/mcp-endpoint.ts +1 -3
- package/src/internal/open-browser.ts +41 -0
- package/src/internal/playground/toolchain.ts +18 -16
- package/src/internal/playground-proxy.ts +576 -0
- package/src/internal/prompt-context.ts +95 -0
- package/src/internal/reminder-runner.ts +11 -17
- package/src/internal/request-headers.ts +23 -0
- package/src/internal/resolve-prod-target.ts +182 -0
- package/src/internal/resolved-connections.ts +5 -5
- package/src/internal/run-client.ts +39 -36
- package/src/internal/schedule-runner.ts +1 -1
- package/src/internal/server.ts +25 -16
- package/src/internal/session-engine.ts +35 -18
- package/src/internal/sessions-client.ts +216 -0
- package/src/internal/storage-coordinator.ts +6 -6
- package/src/internal/stream-progress.ts +36 -2
- package/src/internal/terminal-style.ts +74 -0
- package/src/internal/trajectory.ts +91 -13
- package/src/internal/update-check.ts +552 -0
- package/src/internal/workspace.ts +42 -4
- package/src/types.ts +45 -7
- package/dist/docs/assets/chunks/@localSearchIndexroot.zwQ9RCQ7.js +0 -1
- package/dist/playground/assets/index-B1Qc9h2u.css +0 -1
- package/dist/playground/assets/index-CpDYCj8W.js +0 -79
- /package/dist/docs/assets/{index.md.m81y7TY7.lean.js → index.md.Cylk70gg.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.CfU8_uTC.lean.js → quickstart.md.BU6Iwi_9.lean.js} +0 -0
package/src/internal/cli-ax.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
/**
|
|
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<
|
|
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
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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.
|
|
231
|
-
?
|
|
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
|
-
|
|
253
|
-
? `
|
|
254
|
-
:
|
|
255
|
-
? `
|
|
256
|
-
:
|
|
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
|
-
|
|
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
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
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
|
+
}
|