@agentuity/cli 1.0.62 → 1.0.64

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.
@@ -1 +1 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../../src/cmd/cloud/sandbox/exec.ts"],"names":[],"mappings":"AAqCA,eAAO,MAAM,cAAc,sCAgSzB,CAAC;AAsFH,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../../src/cmd/cloud/sandbox/exec.ts"],"names":[],"mappings":"AAoCA,eAAO,MAAM,cAAc,sCAwQzB,CAAC;AAgBH,eAAe,cAAc,CAAC"}
@@ -5,8 +5,8 @@ import { createCommand } from '../../../types';
5
5
  import * as tui from '../../../tui';
6
6
  import { createSandboxClient } from './util';
7
7
  import { getCommand } from '../../../command-prefix';
8
- import { sandboxExecute, executionGet, writeAndDrain, sandboxResolve } from '@agentuity/server';
9
- // Server-side long-poll wait duration (max 5 minutes supported by server)
8
+ import { sandboxExecute, executionGet, sandboxResolve } from '@agentuity/server';
9
+ import { streamUrlToWritable } from '../../../utils/stream-url';
10
10
  const EXECUTION_WAIT_DURATION = '5m';
11
11
  const SandboxExecResponseSchema = z.object({
12
12
  executionId: z.string().describe('Unique execution identifier'),
@@ -64,15 +64,11 @@ export const execSubcommand = createCommand({
64
64
  },
65
65
  async handler(ctx) {
66
66
  const { args, opts, options, auth, logger, apiClient } = ctx;
67
- // Validate timeout format if provided (fail fast before any network calls)
68
67
  if (opts.timeout) {
69
- // Go's time.ParseDuration accepts "0" or one-or-more number+unit tokens.
70
- // Valid units: ns, us, µs (U+00B5), μs (U+03BC), ms, s, m, h
71
68
  if (!/^(?:0|(\d+(\.\d+)?(ns|us|[µμ]s|ms|s|m|h))+)$/.test(opts.timeout)) {
72
69
  tui.fatal(`Invalid timeout format '${opts.timeout}': expected duration like '5s', '1m', '1h', '300ms'`, ErrorCode.INVALID_ARGUMENT);
73
70
  }
74
71
  }
75
- // Resolve sandbox to get region and orgId using CLI API
76
72
  const sandboxInfo = await sandboxResolve(apiClient, args.sandboxId);
77
73
  const { region, orgId } = sandboxInfo;
78
74
  const client = createSandboxClient(logger, auth, region);
@@ -104,11 +100,8 @@ export const execSubcommand = createCommand({
104
100
  const streamAbortController = new AbortController();
105
101
  const streamPromises = [];
106
102
  const streamLabels = [];
107
- // Check if stdout and stderr are the same stream (combined output)
108
103
  const isCombinedOutput = stdoutStreamUrl && stderrStreamUrl && stdoutStreamUrl === stderrStreamUrl;
109
104
  logger.debug('[exec] stream mode: combined=%s, stdoutUrl=%s, stderrUrl=%s', isCombinedOutput, stdoutStreamUrl ?? 'none', stderrStreamUrl ?? 'none');
110
- // Set up stream capture — in JSON mode, capture to buffers;
111
- // when streams are separate, capture stdout/stderr independently
112
105
  const outputChunks = [];
113
106
  const stdoutChunks = [];
114
107
  const stderrChunks = [];
@@ -116,12 +109,10 @@ export const execSubcommand = createCommand({
116
109
  let stderrWritable;
117
110
  if (options.json) {
118
111
  if (isCombinedOutput) {
119
- // Combined stream: can't distinguish stdout from stderr
120
112
  stdoutWritable = createCaptureStream((chunk) => outputChunks.push(chunk));
121
113
  stderrWritable = createCaptureStream((chunk) => outputChunks.push(chunk));
122
114
  }
123
115
  else {
124
- // Separate streams: capture each independently and also to combined output
125
116
  stdoutWritable = createCaptureStream((chunk) => {
126
117
  stdoutChunks.push(chunk);
127
118
  outputChunks.push(chunk);
@@ -137,27 +128,38 @@ export const execSubcommand = createCommand({
137
128
  stderrWritable = process.stderr;
138
129
  }
139
130
  if (isCombinedOutput) {
140
- // Stream combined output to stdout only to avoid duplicates
141
131
  logger.debug('[exec] starting combined stream: %s', stdoutStreamUrl);
142
132
  streamLabels.push('combined');
143
- streamPromises.push(streamUrlToWritable('combined', stdoutStreamUrl, stdoutWritable, streamAbortController.signal, logger));
133
+ streamPromises.push(streamUrlToWritable(stdoutStreamUrl, stdoutWritable, logger, {
134
+ signal: streamAbortController.signal,
135
+ label: 'combined',
136
+ raw: true,
137
+ v2: true,
138
+ }).then(() => { }));
144
139
  }
145
140
  else {
146
141
  if (stdoutStreamUrl) {
147
142
  logger.debug('[exec] starting stdout stream: %s', stdoutStreamUrl);
148
143
  streamLabels.push('stdout');
149
- streamPromises.push(streamUrlToWritable('stdout', stdoutStreamUrl, stdoutWritable, streamAbortController.signal, logger));
144
+ streamPromises.push(streamUrlToWritable(stdoutStreamUrl, stdoutWritable, logger, {
145
+ signal: streamAbortController.signal,
146
+ label: 'stdout',
147
+ raw: true,
148
+ v2: true,
149
+ }).then(() => { }));
150
150
  }
151
151
  if (stderrStreamUrl) {
152
152
  logger.debug('[exec] starting stderr stream: %s', stderrStreamUrl);
153
153
  streamLabels.push('stderr');
154
- streamPromises.push(streamUrlToWritable('stderr', stderrStreamUrl, stderrWritable, streamAbortController.signal, logger));
154
+ streamPromises.push(streamUrlToWritable(stderrStreamUrl, stderrWritable, logger, {
155
+ signal: streamAbortController.signal,
156
+ label: 'stderr',
157
+ raw: true,
158
+ v2: true,
159
+ }).then(() => { }));
155
160
  }
156
161
  }
157
162
  logger.debug('[exec] %d stream(s) started [%s], now long-polling executionGet', streamPromises.length, streamLabels.join(', '));
158
- // Use server-side long-polling to wait for execution completion
159
- // This is more efficient than client-side polling and provides immediate
160
- // error detection if the sandbox is terminated
161
163
  let finalExecution;
162
164
  const pollStart = Date.now();
163
165
  try {
@@ -168,17 +170,10 @@ export const execSubcommand = createCommand({
168
170
  });
169
171
  }
170
172
  catch (err) {
171
- // Abort any active stream readers before rethrowing so they
172
- // don't keep running after the execution poll has failed.
173
173
  streamAbortController.abort();
174
174
  throw err;
175
175
  }
176
176
  logger.debug('[exec] executionGet returned in %dms: status=%s, exitCode=%s', Date.now() - pollStart, finalExecution.status, finalExecution.exitCode ?? 'undefined');
177
- // Wait for all streams to reach EOF (Pulse blocks until true EOF).
178
- // Safety: execution is confirmed complete so all data has been written
179
- // and complete/v2 sent. If Pulse doesn't close the response within
180
- // a grace period (e.g. cross-server routing delay, stale metadata
181
- // cache), abort the streams to prevent an indefinite hang.
182
177
  if (streamPromises.length > 0) {
183
178
  logger.debug('[exec] waiting for %d stream(s) to EOF', streamPromises.length);
184
179
  const streamWaitStart = Date.now();
@@ -196,7 +191,6 @@ export const execSubcommand = createCommand({
196
191
  }
197
192
  logger.debug('[exec] all streams done in %dms (graceTriggered=%s)', Date.now() - streamWaitStart, graceTriggered);
198
193
  }
199
- // Ensure stdout is fully flushed before continuing
200
194
  if (!options.json && process.stdout.writable) {
201
195
  await new Promise((resolve) => {
202
196
  if (process.stdout.writableNeedDrain) {
@@ -247,48 +241,6 @@ export const execSubcommand = createCommand({
247
241
  }
248
242
  },
249
243
  });
250
- async function streamUrlToWritable(label, url, writable, signal, logger) {
251
- const streamStart = Date.now();
252
- try {
253
- // Signal to Pulse that this is a v2 stream so it waits for v2 metadata
254
- // instead of falling back to the legacy download path on a short timeout.
255
- const v2Url = new URL(url);
256
- v2Url.searchParams.set('v', '2');
257
- logger.debug('[stream:%s] fetching: %s', label, v2Url.href);
258
- const response = await fetch(v2Url.href, { signal });
259
- logger.debug('[stream:%s] response status=%d in %dms', label, response.status, Date.now() - streamStart);
260
- if (!response.ok || !response.body) {
261
- logger.debug('[stream:%s] not ok or no body — returning', label);
262
- return;
263
- }
264
- const reader = response.body.getReader();
265
- let chunks = 0;
266
- let totalBytes = 0;
267
- // Read until EOF - Pulse will block until data is available
268
- while (true) {
269
- const { done, value } = await reader.read();
270
- if (done) {
271
- logger.debug('[stream:%s] EOF after %dms (%d chunks, %d bytes)', label, Date.now() - streamStart, chunks, totalBytes);
272
- break;
273
- }
274
- if (value) {
275
- chunks++;
276
- totalBytes += value.length;
277
- if (chunks <= 3 || chunks % 100 === 0) {
278
- logger.debug('[stream:%s] chunk #%d: %d bytes (total: %d bytes, +%dms)', label, chunks, value.length, totalBytes, Date.now() - streamStart);
279
- }
280
- await writeAndDrain(writable, value);
281
- }
282
- }
283
- }
284
- catch (err) {
285
- if (err instanceof Error && err.name === 'AbortError') {
286
- logger.debug('[stream:%s] aborted after %dms', label, Date.now() - streamStart);
287
- return;
288
- }
289
- logger.debug('[stream:%s] error after %dms: %s', label, Date.now() - streamStart, err);
290
- }
291
- }
292
244
  function createCaptureStream(onChunk) {
293
245
  return new Writable({
294
246
  write(chunk, _encoding, callback) {
@@ -1 +1 @@
1
- {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../../src/cmd/cloud/sandbox/exec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../../src/cmd/cloud/sandbox/exec.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cmd/cloud/sandbox/job/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,OAAO,yCAqBlB,CAAC;AAEH,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/cmd/cloud/sandbox/job/index.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,OAAO,yCA+BlB,CAAC;AAEH,eAAe,OAAO,CAAC"}
@@ -3,6 +3,7 @@ import { getSubcommand } from './get';
3
3
  import { listSubcommand } from './list';
4
4
  import { createSubcommand } from './create';
5
5
  import { destroySubcommand } from './destroy';
6
+ import { logsSubcommand } from './logs';
6
7
  import { getCommand } from '../../../../command-prefix';
7
8
  export const command = createCommand({
8
9
  name: 'job',
@@ -22,8 +23,18 @@ export const command = createCommand({
22
23
  command: getCommand('cloud sandbox job destroy sbx_abc123 job_xyz789'),
23
24
  description: 'Terminate a running job',
24
25
  },
26
+ {
27
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789'),
28
+ description: 'View logs from a job',
29
+ },
30
+ ],
31
+ subcommands: [
32
+ createSubcommand,
33
+ getSubcommand,
34
+ listSubcommand,
35
+ destroySubcommand,
36
+ logsSubcommand,
25
37
  ],
26
- subcommands: [createSubcommand, getSubcommand, listSubcommand, destroySubcommand],
27
38
  requires: { auth: true, org: true },
28
39
  });
29
40
  export default command;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/cmd/cloud/sandbox/job/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAExD,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;IACpC,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,WAAW,EAAE,qCAAqC;IAClD,IAAI,EAAE,CAAC,eAAe,CAAC;IACvB,QAAQ,EAAE;QACT;YACC,OAAO,EAAE,UAAU,CAAC,sDAAsD,CAAC;YAC3E,WAAW,EAAE,yBAAyB;SACtC;QACD;YACC,OAAO,EAAE,UAAU,CAAC,mCAAmC,CAAC;YACxD,WAAW,EAAE,yBAAyB;SACtC;QACD;YACC,OAAO,EAAE,UAAU,CAAC,iDAAiD,CAAC;YACtE,WAAW,EAAE,yBAAyB;SACtC;KACD;IACD,WAAW,EAAE,CAAC,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,CAAC;IACjF,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;CACnC,CAAC,CAAC;AAEH,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/cmd/cloud/sandbox/job/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAExD,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,CAAC;IACpC,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,WAAW,EAAE,qCAAqC;IAClD,IAAI,EAAE,CAAC,eAAe,CAAC;IACvB,QAAQ,EAAE;QACT;YACC,OAAO,EAAE,UAAU,CAAC,sDAAsD,CAAC;YAC3E,WAAW,EAAE,yBAAyB;SACtC;QACD;YACC,OAAO,EAAE,UAAU,CAAC,mCAAmC,CAAC;YACxD,WAAW,EAAE,yBAAyB;SACtC;QACD;YACC,OAAO,EAAE,UAAU,CAAC,iDAAiD,CAAC;YACtE,WAAW,EAAE,yBAAyB;SACtC;QACD;YACC,OAAO,EAAE,UAAU,CAAC,8CAA8C,CAAC;YACnE,WAAW,EAAE,sBAAsB;SACnC;KACD;IACD,WAAW,EAAE;QACZ,gBAAgB;QAChB,aAAa;QACb,cAAc;QACd,iBAAiB;QACjB,cAAc;KACd;IACD,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;CACnC,CAAC,CAAC;AAEH,eAAe,OAAO,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const logsSubcommand: import("../../../..").SubcommandDefinition;
2
+ export default logsSubcommand;
3
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../../../../src/cmd/cloud/sandbox/job/logs.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,cAAc,4CAyHzB,CAAC;AAEH,eAAe,cAAc,CAAC"}
@@ -0,0 +1,124 @@
1
+ import { z } from 'zod';
2
+ import { createSubcommand } from '../../../../types';
3
+ import * as tui from '../../../../tui';
4
+ import { createSandboxClient } from '../util';
5
+ import { jobGet, sandboxResolve } from '@agentuity/server';
6
+ import { getCommand } from '../../../../command-prefix';
7
+ import { streamUrlToWritable } from '../../../../utils/stream-url';
8
+ const JobLogsResponseSchema = z.object({
9
+ jobId: z.string(),
10
+ sandboxId: z.string(),
11
+ status: z.string(),
12
+ bytesRead: z.number().optional(),
13
+ });
14
+ export const logsSubcommand = createSubcommand({
15
+ name: 'logs',
16
+ aliases: ['log'],
17
+ description: 'Stream logs from a sandbox job',
18
+ tags: ['read-only', 'slow', 'requires-auth'],
19
+ requires: { auth: true, apiClient: true },
20
+ examples: [
21
+ {
22
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789'),
23
+ description: 'View stdout logs from a job',
24
+ },
25
+ {
26
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --stderr'),
27
+ description: 'View stderr logs from a job',
28
+ },
29
+ {
30
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --follow'),
31
+ description: 'Follow logs in real-time',
32
+ },
33
+ {
34
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --grep error'),
35
+ description: 'Filter logs containing "error"',
36
+ },
37
+ {
38
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --tail 100'),
39
+ description: 'Show last 100 lines',
40
+ },
41
+ ],
42
+ schema: {
43
+ args: z.object({
44
+ sandboxId: z.string().describe('Sandbox ID'),
45
+ jobId: z.string().describe('Job ID'),
46
+ }),
47
+ options: z.object({
48
+ stderr: z.boolean().default(false).describe('Show stderr instead of stdout'),
49
+ follow: z.boolean().default(false).describe('Follow logs in real-time (for running jobs)'),
50
+ timestamps: z.boolean().default(true).describe('Show timestamps in output'),
51
+ grep: z.string().optional().describe('Filter logs by pattern (case-insensitive)'),
52
+ tail: z.coerce
53
+ .number()
54
+ .int()
55
+ .min(1)
56
+ .optional()
57
+ .describe('Number of lines to show from the end'),
58
+ }),
59
+ response: JobLogsResponseSchema,
60
+ },
61
+ async handler(ctx) {
62
+ const { args, opts, options, auth, logger, apiClient } = ctx;
63
+ const sandboxInfo = await sandboxResolve(apiClient, args.sandboxId);
64
+ const { region, orgId } = sandboxInfo;
65
+ const client = createSandboxClient(logger, auth, region);
66
+ const job = await jobGet(client, {
67
+ sandboxId: args.sandboxId,
68
+ jobId: args.jobId,
69
+ orgId,
70
+ });
71
+ const streamUrl = opts.stderr ? job.stderrStreamUrl : job.stdoutStreamUrl;
72
+ const isJson = options.json ?? false;
73
+ if (!streamUrl) {
74
+ if (isJson) {
75
+ return {
76
+ jobId: job.jobId,
77
+ sandboxId: job.sandboxId,
78
+ status: job.status,
79
+ };
80
+ }
81
+ tui.warning(`No ${opts.stderr ? 'stderr' : 'stdout'} stream available for job ${job.jobId}`);
82
+ if (job.status === 'pending') {
83
+ tui.info('Job is still pending - logs will be available once it starts running');
84
+ }
85
+ return {
86
+ jobId: job.jobId,
87
+ sandboxId: job.sandboxId,
88
+ status: job.status,
89
+ };
90
+ }
91
+ if (!isJson) {
92
+ tui.info(`Streaming ${opts.stderr ? 'stderr' : 'stdout'} for job ${tui.bold(job.jobId)} (status: ${job.status})`);
93
+ }
94
+ const abortController = new AbortController();
95
+ const handleSignal = () => {
96
+ abortController.abort();
97
+ };
98
+ process.on('SIGINT', handleSignal);
99
+ process.on('SIGTERM', handleSignal);
100
+ try {
101
+ const result = await streamUrlToWritable(streamUrl, process.stdout, logger, {
102
+ signal: abortController.signal,
103
+ follow: opts.follow,
104
+ timestamps: opts.timestamps ?? true,
105
+ grep: opts.grep,
106
+ tail: opts.tail,
107
+ json: isJson,
108
+ label: opts.stderr ? 'stderr' : 'stdout',
109
+ });
110
+ return {
111
+ jobId: job.jobId,
112
+ sandboxId: job.sandboxId,
113
+ status: job.status,
114
+ bytesRead: result.bytesRead,
115
+ };
116
+ }
117
+ finally {
118
+ process.off('SIGINT', handleSignal);
119
+ process.off('SIGTERM', handleSignal);
120
+ }
121
+ },
122
+ });
123
+ export default logsSubcommand;
124
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../../../../src/cmd/cloud/sandbox/job/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Logger } from '@agentuity/core';
2
+ export interface StreamUrlOptions {
3
+ signal?: AbortSignal;
4
+ follow?: boolean;
5
+ timestamps?: boolean;
6
+ grep?: string;
7
+ tail?: number;
8
+ json?: boolean;
9
+ label?: string;
10
+ raw?: boolean;
11
+ v2?: boolean;
12
+ }
13
+ export interface StreamUrlResult {
14
+ bytesRead: number;
15
+ chunks: number;
16
+ }
17
+ export declare class StreamFetchError extends Error {
18
+ status: number;
19
+ statusText: string;
20
+ constructor(status: number, statusText: string, message: string);
21
+ }
22
+ export declare function streamUrlToWritable(url: string, writable: NodeJS.WritableStream, logger: Logger, options?: StreamUrlOptions): Promise<StreamUrlResult>;
23
+ //# sourceMappingURL=stream-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-url.d.ts","sourceRoot":"","sources":["../../src/utils/stream-url.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAG9C,MAAM,WAAW,gBAAgB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IAElC,MAAM,EAAE,MAAM;IACd,UAAU,EAAE,MAAM;gBADlB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EACzB,OAAO,EAAE,MAAM;CAKhB;AAMD,wBAAsB,mBAAmB,CACxC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,CAAC,cAAc,EAC/B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,gBAAqB,GAC5B,OAAO,CAAC,eAAe,CAAC,CA8K1B"}
@@ -0,0 +1,153 @@
1
+ import { writeAndDrain } from '@agentuity/server';
2
+ import * as tui from '../tui';
3
+ export class StreamFetchError extends Error {
4
+ status;
5
+ statusText;
6
+ constructor(status, statusText, message) {
7
+ super(message);
8
+ this.status = status;
9
+ this.statusText = statusText;
10
+ this.name = 'StreamFetchError';
11
+ }
12
+ }
13
+ function escapeRegExp(str) {
14
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
15
+ }
16
+ export async function streamUrlToWritable(url, writable, logger, options = {}) {
17
+ const { signal, follow, timestamps, grep, tail, json, label = 'stream', raw = false, v2 = false, } = options;
18
+ const streamStart = Date.now();
19
+ let bytesRead = 0;
20
+ let chunks = 0;
21
+ try {
22
+ const fetchUrl = new URL(url);
23
+ if (follow || v2) {
24
+ fetchUrl.searchParams.set('v', '2');
25
+ }
26
+ if (follow) {
27
+ fetchUrl.searchParams.set('follow', 'true');
28
+ }
29
+ const redactedUrl = fetchUrl.origin + fetchUrl.pathname + (fetchUrl.search ? '?REDACTED' : '');
30
+ logger.debug('[%s] fetching: %s', label, redactedUrl);
31
+ const response = await fetch(fetchUrl.href, { signal });
32
+ logger.debug('[%s] response status=%d in %dms', label, response.status, Date.now() - streamStart);
33
+ if (!response.ok || !response.body) {
34
+ logger.debug('[%s] not ok or no body', label);
35
+ if (!json) {
36
+ tui.error(`Failed to fetch stream: ${response.status} ${response.statusText}`);
37
+ }
38
+ throw new StreamFetchError(response.status, response.statusText, `Failed to fetch stream: ${response.status} ${response.statusText}`);
39
+ }
40
+ const reader = response.body.getReader();
41
+ if (raw) {
42
+ while (true) {
43
+ const { done, value } = await reader.read();
44
+ if (done) {
45
+ logger.debug('[%s] EOF after %dms (%d chunks, %d bytes)', label, Date.now() - streamStart, chunks, bytesRead);
46
+ break;
47
+ }
48
+ if (value) {
49
+ chunks++;
50
+ bytesRead += value.length;
51
+ if (chunks <= 3 || chunks % 100 === 0) {
52
+ logger.debug('[%s] chunk #%d: %d bytes (total: %d bytes, +%dms)', label, chunks, value.length, bytesRead, Date.now() - streamStart);
53
+ }
54
+ await writeAndDrain(writable, value);
55
+ }
56
+ }
57
+ }
58
+ else {
59
+ const decoder = new TextDecoder();
60
+ let leftover = '';
61
+ const grepPattern = grep ? new RegExp(escapeRegExp(grep), 'i') : null;
62
+ const needsFiltering = tail !== undefined || grepPattern !== null;
63
+ const tailBuffer = [];
64
+ const maxTail = tail ?? Infinity;
65
+ const liveOutput = follow && needsFiltering;
66
+ const outputLine = async (line) => {
67
+ if (json) {
68
+ const obj = {
69
+ timestamp: new Date().toISOString(),
70
+ stream: label,
71
+ message: line,
72
+ };
73
+ await writeAndDrain(writable, Buffer.from(JSON.stringify(obj) + '\n'));
74
+ }
75
+ else {
76
+ const formatted = timestamps ? formatLineWithTimestamp(line) : line;
77
+ await writeAndDrain(writable, Buffer.from(formatted + '\n'));
78
+ }
79
+ };
80
+ const processFilteredLine = async (line) => {
81
+ if (grepPattern && !grepPattern.test(line)) {
82
+ return;
83
+ }
84
+ if (tail !== undefined) {
85
+ tailBuffer.push(line);
86
+ if (tailBuffer.length > maxTail) {
87
+ tailBuffer.shift();
88
+ }
89
+ if (liveOutput) {
90
+ await outputLine(line);
91
+ }
92
+ }
93
+ else {
94
+ await outputLine(line);
95
+ }
96
+ };
97
+ while (true) {
98
+ const { done, value } = await reader.read();
99
+ if (done) {
100
+ if (leftover) {
101
+ if (needsFiltering) {
102
+ await processFilteredLine(leftover);
103
+ }
104
+ else {
105
+ await outputLine(leftover);
106
+ }
107
+ }
108
+ logger.debug('[%s] EOF after %dms (%d chunks, %d bytes)', label, Date.now() - streamStart, chunks, bytesRead);
109
+ break;
110
+ }
111
+ if (value) {
112
+ chunks++;
113
+ bytesRead += value.length;
114
+ const text = leftover + decoder.decode(value, { stream: true });
115
+ const lines = text.split('\n');
116
+ leftover = lines.pop() ?? '';
117
+ for (const line of lines) {
118
+ if (needsFiltering) {
119
+ await processFilteredLine(line);
120
+ }
121
+ else {
122
+ await outputLine(line);
123
+ }
124
+ }
125
+ }
126
+ }
127
+ if (!liveOutput && needsFiltering && tailBuffer.length > 0) {
128
+ for (const line of tailBuffer) {
129
+ await outputLine(line);
130
+ }
131
+ }
132
+ }
133
+ return { bytesRead, chunks };
134
+ }
135
+ catch (err) {
136
+ if (err instanceof Error && err.name === 'AbortError') {
137
+ logger.debug('[%s] aborted after %dms', label, Date.now() - streamStart);
138
+ return { bytesRead, chunks };
139
+ }
140
+ logger.debug('[%s] error after %dms: %s', label, Date.now() - streamStart, err);
141
+ throw err;
142
+ }
143
+ }
144
+ function formatLineWithTimestamp(line) {
145
+ const timestamp = new Date().toLocaleTimeString('en-US', {
146
+ hour12: false,
147
+ hour: '2-digit',
148
+ minute: '2-digit',
149
+ second: '2-digit',
150
+ });
151
+ return `${tui.muted(timestamp)} ${line}`;
152
+ }
153
+ //# sourceMappingURL=stream-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-url.js","sourceRoot":"","sources":["../../src/utils/stream-url.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentuity/cli",
3
- "version": "1.0.62",
3
+ "version": "1.0.64",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Agentuity employees and contributors",
6
6
  "type": "module",
@@ -41,9 +41,9 @@
41
41
  "prepublishOnly": "bun run clean && bun run build"
42
42
  },
43
43
  "dependencies": {
44
- "@agentuity/auth": "1.0.62",
45
- "@agentuity/core": "1.0.62",
46
- "@agentuity/server": "1.0.62",
44
+ "@agentuity/auth": "1.0.64",
45
+ "@agentuity/core": "1.0.64",
46
+ "@agentuity/server": "1.0.64",
47
47
  "@datasert/cronjs-parser": "^1.4.0",
48
48
  "@vitejs/plugin-react": "^5.1.2",
49
49
  "acorn-loose": "^8.5.2",
@@ -59,10 +59,10 @@
59
59
  "typescript": "^5.9.0",
60
60
  "vite": "^7.2.7",
61
61
  "zod": "^4.3.5",
62
- "@agentuity/frontend": "1.0.62"
62
+ "@agentuity/frontend": "1.0.64"
63
63
  },
64
64
  "devDependencies": {
65
- "@agentuity/test-utils": "1.0.62",
65
+ "@agentuity/test-utils": "1.0.64",
66
66
  "@types/archiver": "^6.0.3",
67
67
  "@types/bun": "latest",
68
68
  "@types/tar-fs": "^2.0.4",
@@ -5,10 +5,9 @@ import { createCommand } from '../../../types';
5
5
  import * as tui from '../../../tui';
6
6
  import { createSandboxClient } from './util';
7
7
  import { getCommand } from '../../../command-prefix';
8
- import { sandboxExecute, executionGet, writeAndDrain, sandboxResolve } from '@agentuity/server';
9
- import type { Logger } from '@agentuity/core';
8
+ import { sandboxExecute, executionGet, sandboxResolve } from '@agentuity/server';
9
+ import { streamUrlToWritable } from '../../../utils/stream-url';
10
10
 
11
- // Server-side long-poll wait duration (max 5 minutes supported by server)
12
11
  const EXECUTION_WAIT_DURATION = '5m';
13
12
 
14
13
  const SandboxExecResponseSchema = z.object({
@@ -71,10 +70,7 @@ export const execSubcommand = createCommand({
71
70
  async handler(ctx) {
72
71
  const { args, opts, options, auth, logger, apiClient } = ctx;
73
72
 
74
- // Validate timeout format if provided (fail fast before any network calls)
75
73
  if (opts.timeout) {
76
- // Go's time.ParseDuration accepts "0" or one-or-more number+unit tokens.
77
- // Valid units: ns, us, µs (U+00B5), μs (U+03BC), ms, s, m, h
78
74
  if (!/^(?:0|(\d+(\.\d+)?(ns|us|[µμ]s|ms|s|m|h))+)$/.test(opts.timeout)) {
79
75
  tui.fatal(
80
76
  `Invalid timeout format '${opts.timeout}': expected duration like '5s', '1m', '1h', '300ms'`,
@@ -83,7 +79,6 @@ export const execSubcommand = createCommand({
83
79
  }
84
80
  }
85
81
 
86
- // Resolve sandbox to get region and orgId using CLI API
87
82
  const sandboxInfo = await sandboxResolve(apiClient, args.sandboxId);
88
83
  const { region, orgId } = sandboxInfo;
89
84
 
@@ -127,7 +122,6 @@ export const execSubcommand = createCommand({
127
122
  const streamPromises: Promise<void>[] = [];
128
123
  const streamLabels: string[] = [];
129
124
 
130
- // Check if stdout and stderr are the same stream (combined output)
131
125
  const isCombinedOutput =
132
126
  stdoutStreamUrl && stderrStreamUrl && stdoutStreamUrl === stderrStreamUrl;
133
127
  logger.debug(
@@ -137,8 +131,6 @@ export const execSubcommand = createCommand({
137
131
  stderrStreamUrl ?? 'none'
138
132
  );
139
133
 
140
- // Set up stream capture — in JSON mode, capture to buffers;
141
- // when streams are separate, capture stdout/stderr independently
142
134
  const outputChunks: string[] = [];
143
135
  const stdoutChunks: string[] = [];
144
136
  const stderrChunks: string[] = [];
@@ -148,11 +140,9 @@ export const execSubcommand = createCommand({
148
140
 
149
141
  if (options.json) {
150
142
  if (isCombinedOutput) {
151
- // Combined stream: can't distinguish stdout from stderr
152
143
  stdoutWritable = createCaptureStream((chunk) => outputChunks.push(chunk));
153
144
  stderrWritable = createCaptureStream((chunk) => outputChunks.push(chunk));
154
145
  } else {
155
- // Separate streams: capture each independently and also to combined output
156
146
  stdoutWritable = createCaptureStream((chunk) => {
157
147
  stdoutChunks.push(chunk);
158
148
  outputChunks.push(chunk);
@@ -168,30 +158,27 @@ export const execSubcommand = createCommand({
168
158
  }
169
159
 
170
160
  if (isCombinedOutput) {
171
- // Stream combined output to stdout only to avoid duplicates
172
161
  logger.debug('[exec] starting combined stream: %s', stdoutStreamUrl);
173
162
  streamLabels.push('combined');
174
163
  streamPromises.push(
175
- streamUrlToWritable(
176
- 'combined',
177
- stdoutStreamUrl,
178
- stdoutWritable,
179
- streamAbortController.signal,
180
- logger
181
- )
164
+ streamUrlToWritable(stdoutStreamUrl!, stdoutWritable, logger, {
165
+ signal: streamAbortController.signal,
166
+ label: 'combined',
167
+ raw: true,
168
+ v2: true,
169
+ }).then(() => {})
182
170
  );
183
171
  } else {
184
172
  if (stdoutStreamUrl) {
185
173
  logger.debug('[exec] starting stdout stream: %s', stdoutStreamUrl);
186
174
  streamLabels.push('stdout');
187
175
  streamPromises.push(
188
- streamUrlToWritable(
189
- 'stdout',
190
- stdoutStreamUrl,
191
- stdoutWritable,
192
- streamAbortController.signal,
193
- logger
194
- )
176
+ streamUrlToWritable(stdoutStreamUrl, stdoutWritable, logger, {
177
+ signal: streamAbortController.signal,
178
+ label: 'stdout',
179
+ raw: true,
180
+ v2: true,
181
+ }).then(() => {})
195
182
  );
196
183
  }
197
184
 
@@ -199,13 +186,12 @@ export const execSubcommand = createCommand({
199
186
  logger.debug('[exec] starting stderr stream: %s', stderrStreamUrl);
200
187
  streamLabels.push('stderr');
201
188
  streamPromises.push(
202
- streamUrlToWritable(
203
- 'stderr',
204
- stderrStreamUrl,
205
- stderrWritable,
206
- streamAbortController.signal,
207
- logger
208
- )
189
+ streamUrlToWritable(stderrStreamUrl, stderrWritable, logger, {
190
+ signal: streamAbortController.signal,
191
+ label: 'stderr',
192
+ raw: true,
193
+ v2: true,
194
+ }).then(() => {})
209
195
  );
210
196
  }
211
197
  }
@@ -216,9 +202,6 @@ export const execSubcommand = createCommand({
216
202
  streamLabels.join(', ')
217
203
  );
218
204
 
219
- // Use server-side long-polling to wait for execution completion
220
- // This is more efficient than client-side polling and provides immediate
221
- // error detection if the sandbox is terminated
222
205
  let finalExecution: Awaited<ReturnType<typeof executionGet>>;
223
206
  const pollStart = Date.now();
224
207
  try {
@@ -228,8 +211,6 @@ export const execSubcommand = createCommand({
228
211
  wait: EXECUTION_WAIT_DURATION,
229
212
  });
230
213
  } catch (err) {
231
- // Abort any active stream readers before rethrowing so they
232
- // don't keep running after the execution poll has failed.
233
214
  streamAbortController.abort();
234
215
  throw err;
235
216
  }
@@ -240,11 +221,6 @@ export const execSubcommand = createCommand({
240
221
  finalExecution.exitCode ?? 'undefined'
241
222
  );
242
223
 
243
- // Wait for all streams to reach EOF (Pulse blocks until true EOF).
244
- // Safety: execution is confirmed complete so all data has been written
245
- // and complete/v2 sent. If Pulse doesn't close the response within
246
- // a grace period (e.g. cross-server routing delay, stale metadata
247
- // cache), abort the streams to prevent an indefinite hang.
248
224
  if (streamPromises.length > 0) {
249
225
  logger.debug('[exec] waiting for %d stream(s) to EOF', streamPromises.length);
250
226
  const streamWaitStart = Date.now();
@@ -268,7 +244,6 @@ export const execSubcommand = createCommand({
268
244
  );
269
245
  }
270
246
 
271
- // Ensure stdout is fully flushed before continuing
272
247
  if (!options.json && process.stdout.writable) {
273
248
  await new Promise<void>((resolve) => {
274
249
  if (process.stdout.writableNeedDrain) {
@@ -325,76 +300,6 @@ export const execSubcommand = createCommand({
325
300
  },
326
301
  });
327
302
 
328
- async function streamUrlToWritable(
329
- label: string,
330
- url: string,
331
- writable: NodeJS.WritableStream,
332
- signal: AbortSignal,
333
- logger: Logger
334
- ): Promise<void> {
335
- const streamStart = Date.now();
336
- try {
337
- // Signal to Pulse that this is a v2 stream so it waits for v2 metadata
338
- // instead of falling back to the legacy download path on a short timeout.
339
- const v2Url = new URL(url);
340
- v2Url.searchParams.set('v', '2');
341
- logger.debug('[stream:%s] fetching: %s', label, v2Url.href);
342
- const response = await fetch(v2Url.href, { signal });
343
- logger.debug(
344
- '[stream:%s] response status=%d in %dms',
345
- label,
346
- response.status,
347
- Date.now() - streamStart
348
- );
349
-
350
- if (!response.ok || !response.body) {
351
- logger.debug('[stream:%s] not ok or no body — returning', label);
352
- return;
353
- }
354
-
355
- const reader = response.body.getReader();
356
- let chunks = 0;
357
- let totalBytes = 0;
358
-
359
- // Read until EOF - Pulse will block until data is available
360
- while (true) {
361
- const { done, value } = await reader.read();
362
- if (done) {
363
- logger.debug(
364
- '[stream:%s] EOF after %dms (%d chunks, %d bytes)',
365
- label,
366
- Date.now() - streamStart,
367
- chunks,
368
- totalBytes
369
- );
370
- break;
371
- }
372
-
373
- if (value) {
374
- chunks++;
375
- totalBytes += value.length;
376
- if (chunks <= 3 || chunks % 100 === 0) {
377
- logger.debug(
378
- '[stream:%s] chunk #%d: %d bytes (total: %d bytes, +%dms)',
379
- label,
380
- chunks,
381
- value.length,
382
- totalBytes,
383
- Date.now() - streamStart
384
- );
385
- }
386
- await writeAndDrain(writable, value);
387
- }
388
- }
389
- } catch (err) {
390
- if (err instanceof Error && err.name === 'AbortError') {
391
- logger.debug('[stream:%s] aborted after %dms', label, Date.now() - streamStart);
392
- return;
393
- }
394
- logger.debug('[stream:%s] error after %dms: %s', label, Date.now() - streamStart, err);
395
- }
396
- }
397
-
398
303
  function createCaptureStream(onChunk: (chunk: string) => void): NodeJS.WritableStream {
399
304
  return new Writable({
400
305
  write(
@@ -3,6 +3,7 @@ import { getSubcommand } from './get';
3
3
  import { listSubcommand } from './list';
4
4
  import { createSubcommand } from './create';
5
5
  import { destroySubcommand } from './destroy';
6
+ import { logsSubcommand } from './logs';
6
7
  import { getCommand } from '../../../../command-prefix';
7
8
 
8
9
  export const command = createCommand({
@@ -23,8 +24,18 @@ export const command = createCommand({
23
24
  command: getCommand('cloud sandbox job destroy sbx_abc123 job_xyz789'),
24
25
  description: 'Terminate a running job',
25
26
  },
27
+ {
28
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789'),
29
+ description: 'View logs from a job',
30
+ },
31
+ ],
32
+ subcommands: [
33
+ createSubcommand,
34
+ getSubcommand,
35
+ listSubcommand,
36
+ destroySubcommand,
37
+ logsSubcommand,
26
38
  ],
27
- subcommands: [createSubcommand, getSubcommand, listSubcommand, destroySubcommand],
28
39
  requires: { auth: true, org: true },
29
40
  });
30
41
 
@@ -0,0 +1,139 @@
1
+ import { z } from 'zod';
2
+ import { createSubcommand } from '../../../../types';
3
+ import * as tui from '../../../../tui';
4
+ import { createSandboxClient } from '../util';
5
+ import { jobGet, sandboxResolve } from '@agentuity/server';
6
+ import { getCommand } from '../../../../command-prefix';
7
+ import { streamUrlToWritable } from '../../../../utils/stream-url';
8
+
9
+ const JobLogsResponseSchema = z.object({
10
+ jobId: z.string(),
11
+ sandboxId: z.string(),
12
+ status: z.string(),
13
+ bytesRead: z.number().optional(),
14
+ });
15
+
16
+ export const logsSubcommand = createSubcommand({
17
+ name: 'logs',
18
+ aliases: ['log'],
19
+ description: 'Stream logs from a sandbox job',
20
+ tags: ['read-only', 'slow', 'requires-auth'],
21
+ requires: { auth: true, apiClient: true },
22
+ examples: [
23
+ {
24
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789'),
25
+ description: 'View stdout logs from a job',
26
+ },
27
+ {
28
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --stderr'),
29
+ description: 'View stderr logs from a job',
30
+ },
31
+ {
32
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --follow'),
33
+ description: 'Follow logs in real-time',
34
+ },
35
+ {
36
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --grep error'),
37
+ description: 'Filter logs containing "error"',
38
+ },
39
+ {
40
+ command: getCommand('cloud sandbox job logs sbx_abc123 job_xyz789 --tail 100'),
41
+ description: 'Show last 100 lines',
42
+ },
43
+ ],
44
+ schema: {
45
+ args: z.object({
46
+ sandboxId: z.string().describe('Sandbox ID'),
47
+ jobId: z.string().describe('Job ID'),
48
+ }),
49
+ options: z.object({
50
+ stderr: z.boolean().default(false).describe('Show stderr instead of stdout'),
51
+ follow: z.boolean().default(false).describe('Follow logs in real-time (for running jobs)'),
52
+ timestamps: z.boolean().default(true).describe('Show timestamps in output'),
53
+ grep: z.string().optional().describe('Filter logs by pattern (case-insensitive)'),
54
+ tail: z.coerce
55
+ .number()
56
+ .int()
57
+ .min(1)
58
+ .optional()
59
+ .describe('Number of lines to show from the end'),
60
+ }),
61
+ response: JobLogsResponseSchema,
62
+ },
63
+
64
+ async handler(ctx) {
65
+ const { args, opts, options, auth, logger, apiClient } = ctx;
66
+
67
+ const sandboxInfo = await sandboxResolve(apiClient, args.sandboxId);
68
+ const { region, orgId } = sandboxInfo;
69
+
70
+ const client = createSandboxClient(logger, auth, region);
71
+
72
+ const job = await jobGet(client, {
73
+ sandboxId: args.sandboxId,
74
+ jobId: args.jobId,
75
+ orgId,
76
+ });
77
+
78
+ const streamUrl = opts.stderr ? job.stderrStreamUrl : job.stdoutStreamUrl;
79
+ const isJson = options.json ?? false;
80
+
81
+ if (!streamUrl) {
82
+ if (isJson) {
83
+ return {
84
+ jobId: job.jobId,
85
+ sandboxId: job.sandboxId,
86
+ status: job.status,
87
+ };
88
+ }
89
+ tui.warning(
90
+ `No ${opts.stderr ? 'stderr' : 'stdout'} stream available for job ${job.jobId}`
91
+ );
92
+ if (job.status === 'pending') {
93
+ tui.info('Job is still pending - logs will be available once it starts running');
94
+ }
95
+ return {
96
+ jobId: job.jobId,
97
+ sandboxId: job.sandboxId,
98
+ status: job.status,
99
+ };
100
+ }
101
+
102
+ if (!isJson) {
103
+ tui.info(
104
+ `Streaming ${opts.stderr ? 'stderr' : 'stdout'} for job ${tui.bold(job.jobId)} (status: ${job.status})`
105
+ );
106
+ }
107
+
108
+ const abortController = new AbortController();
109
+ const handleSignal = () => {
110
+ abortController.abort();
111
+ };
112
+ process.on('SIGINT', handleSignal);
113
+ process.on('SIGTERM', handleSignal);
114
+
115
+ try {
116
+ const result = await streamUrlToWritable(streamUrl, process.stdout, logger, {
117
+ signal: abortController.signal,
118
+ follow: opts.follow,
119
+ timestamps: opts.timestamps ?? true,
120
+ grep: opts.grep,
121
+ tail: opts.tail,
122
+ json: isJson,
123
+ label: opts.stderr ? 'stderr' : 'stdout',
124
+ });
125
+
126
+ return {
127
+ jobId: job.jobId,
128
+ sandboxId: job.sandboxId,
129
+ status: job.status,
130
+ bytesRead: result.bytesRead,
131
+ };
132
+ } finally {
133
+ process.off('SIGINT', handleSignal);
134
+ process.off('SIGTERM', handleSignal);
135
+ }
136
+ },
137
+ });
138
+
139
+ export default logsSubcommand;
@@ -0,0 +1,226 @@
1
+ import { writeAndDrain } from '@agentuity/server';
2
+ import type { Logger } from '@agentuity/core';
3
+ import * as tui from '../tui';
4
+
5
+ export interface StreamUrlOptions {
6
+ signal?: AbortSignal;
7
+ follow?: boolean;
8
+ timestamps?: boolean;
9
+ grep?: string;
10
+ tail?: number;
11
+ json?: boolean;
12
+ label?: string;
13
+ raw?: boolean;
14
+ v2?: boolean;
15
+ }
16
+
17
+ export interface StreamUrlResult {
18
+ bytesRead: number;
19
+ chunks: number;
20
+ }
21
+
22
+ export class StreamFetchError extends Error {
23
+ constructor(
24
+ public status: number,
25
+ public statusText: string,
26
+ message: string
27
+ ) {
28
+ super(message);
29
+ this.name = 'StreamFetchError';
30
+ }
31
+ }
32
+
33
+ function escapeRegExp(str: string): string {
34
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
35
+ }
36
+
37
+ export async function streamUrlToWritable(
38
+ url: string,
39
+ writable: NodeJS.WritableStream,
40
+ logger: Logger,
41
+ options: StreamUrlOptions = {}
42
+ ): Promise<StreamUrlResult> {
43
+ const {
44
+ signal,
45
+ follow,
46
+ timestamps,
47
+ grep,
48
+ tail,
49
+ json,
50
+ label = 'stream',
51
+ raw = false,
52
+ v2 = false,
53
+ } = options;
54
+ const streamStart = Date.now();
55
+ let bytesRead = 0;
56
+ let chunks = 0;
57
+
58
+ try {
59
+ const fetchUrl = new URL(url);
60
+
61
+ if (follow || v2) {
62
+ fetchUrl.searchParams.set('v', '2');
63
+ }
64
+ if (follow) {
65
+ fetchUrl.searchParams.set('follow', 'true');
66
+ }
67
+
68
+ const redactedUrl =
69
+ fetchUrl.origin + fetchUrl.pathname + (fetchUrl.search ? '?REDACTED' : '');
70
+ logger.debug('[%s] fetching: %s', label, redactedUrl);
71
+ const response = await fetch(fetchUrl.href, { signal });
72
+ logger.debug(
73
+ '[%s] response status=%d in %dms',
74
+ label,
75
+ response.status,
76
+ Date.now() - streamStart
77
+ );
78
+
79
+ if (!response.ok || !response.body) {
80
+ logger.debug('[%s] not ok or no body', label);
81
+ if (!json) {
82
+ tui.error(`Failed to fetch stream: ${response.status} ${response.statusText}`);
83
+ }
84
+ throw new StreamFetchError(
85
+ response.status,
86
+ response.statusText,
87
+ `Failed to fetch stream: ${response.status} ${response.statusText}`
88
+ );
89
+ }
90
+
91
+ const reader = response.body.getReader();
92
+
93
+ if (raw) {
94
+ while (true) {
95
+ const { done, value } = await reader.read();
96
+ if (done) {
97
+ logger.debug(
98
+ '[%s] EOF after %dms (%d chunks, %d bytes)',
99
+ label,
100
+ Date.now() - streamStart,
101
+ chunks,
102
+ bytesRead
103
+ );
104
+ break;
105
+ }
106
+
107
+ if (value) {
108
+ chunks++;
109
+ bytesRead += value.length;
110
+ if (chunks <= 3 || chunks % 100 === 0) {
111
+ logger.debug(
112
+ '[%s] chunk #%d: %d bytes (total: %d bytes, +%dms)',
113
+ label,
114
+ chunks,
115
+ value.length,
116
+ bytesRead,
117
+ Date.now() - streamStart
118
+ );
119
+ }
120
+ await writeAndDrain(writable, value);
121
+ }
122
+ }
123
+ } else {
124
+ const decoder = new TextDecoder();
125
+ let leftover = '';
126
+ const grepPattern = grep ? new RegExp(escapeRegExp(grep), 'i') : null;
127
+ const needsFiltering = tail !== undefined || grepPattern !== null;
128
+ const tailBuffer: string[] = [];
129
+ const maxTail = tail ?? Infinity;
130
+ const liveOutput = follow && needsFiltering;
131
+
132
+ const outputLine = async (line: string) => {
133
+ if (json) {
134
+ const obj = {
135
+ timestamp: new Date().toISOString(),
136
+ stream: label,
137
+ message: line,
138
+ };
139
+ await writeAndDrain(writable, Buffer.from(JSON.stringify(obj) + '\n'));
140
+ } else {
141
+ const formatted = timestamps ? formatLineWithTimestamp(line) : line;
142
+ await writeAndDrain(writable, Buffer.from(formatted + '\n'));
143
+ }
144
+ };
145
+
146
+ const processFilteredLine = async (line: string) => {
147
+ if (grepPattern && !grepPattern.test(line)) {
148
+ return;
149
+ }
150
+ if (tail !== undefined) {
151
+ tailBuffer.push(line);
152
+ if (tailBuffer.length > maxTail) {
153
+ tailBuffer.shift();
154
+ }
155
+ if (liveOutput) {
156
+ await outputLine(line);
157
+ }
158
+ } else {
159
+ await outputLine(line);
160
+ }
161
+ };
162
+
163
+ while (true) {
164
+ const { done, value } = await reader.read();
165
+ if (done) {
166
+ if (leftover) {
167
+ if (needsFiltering) {
168
+ await processFilteredLine(leftover);
169
+ } else {
170
+ await outputLine(leftover);
171
+ }
172
+ }
173
+ logger.debug(
174
+ '[%s] EOF after %dms (%d chunks, %d bytes)',
175
+ label,
176
+ Date.now() - streamStart,
177
+ chunks,
178
+ bytesRead
179
+ );
180
+ break;
181
+ }
182
+
183
+ if (value) {
184
+ chunks++;
185
+ bytesRead += value.length;
186
+ const text = leftover + decoder.decode(value, { stream: true });
187
+ const lines = text.split('\n');
188
+ leftover = lines.pop() ?? '';
189
+
190
+ for (const line of lines) {
191
+ if (needsFiltering) {
192
+ await processFilteredLine(line);
193
+ } else {
194
+ await outputLine(line);
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ if (!liveOutput && needsFiltering && tailBuffer.length > 0) {
201
+ for (const line of tailBuffer) {
202
+ await outputLine(line);
203
+ }
204
+ }
205
+ }
206
+
207
+ return { bytesRead, chunks };
208
+ } catch (err) {
209
+ if (err instanceof Error && err.name === 'AbortError') {
210
+ logger.debug('[%s] aborted after %dms', label, Date.now() - streamStart);
211
+ return { bytesRead, chunks };
212
+ }
213
+ logger.debug('[%s] error after %dms: %s', label, Date.now() - streamStart, err);
214
+ throw err;
215
+ }
216
+ }
217
+
218
+ function formatLineWithTimestamp(line: string): string {
219
+ const timestamp = new Date().toLocaleTimeString('en-US', {
220
+ hour12: false,
221
+ hour: '2-digit',
222
+ minute: '2-digit',
223
+ second: '2-digit',
224
+ });
225
+ return `${tui.muted(timestamp)} ${line}`;
226
+ }