@agentuity/cli 0.0.104 → 0.0.106

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/bin/cli.ts +6 -3
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +93 -21
  4. package/dist/cli.js.map +1 -1
  5. package/dist/cmd/ai/prompt/version.d.ts +1 -0
  6. package/dist/cmd/ai/prompt/version.d.ts.map +1 -1
  7. package/dist/cmd/ai/prompt/version.js +3 -2
  8. package/dist/cmd/ai/prompt/version.js.map +1 -1
  9. package/dist/cmd/build/ast.d.ts.map +1 -1
  10. package/dist/cmd/build/ast.js +179 -37
  11. package/dist/cmd/build/ast.js.map +1 -1
  12. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  13. package/dist/cmd/build/entry-generator.js +24 -14
  14. package/dist/cmd/build/entry-generator.js.map +1 -1
  15. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  16. package/dist/cmd/build/vite/registry-generator.js +8 -9
  17. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  18. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  19. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  20. package/dist/cmd/cloud/db/create.d.ts.map +1 -1
  21. package/dist/cmd/cloud/db/create.js +11 -2
  22. package/dist/cmd/cloud/db/create.js.map +1 -1
  23. package/dist/cmd/cloud/db/delete.d.ts.map +1 -1
  24. package/dist/cmd/cloud/db/delete.js +13 -2
  25. package/dist/cmd/cloud/db/delete.js.map +1 -1
  26. package/dist/cmd/cloud/deploy.js +3 -3
  27. package/dist/cmd/cloud/deploy.js.map +1 -1
  28. package/dist/cmd/cloud/env/delete.js +1 -1
  29. package/dist/cmd/cloud/env/delete.js.map +1 -1
  30. package/dist/cmd/cloud/env/import.js +4 -4
  31. package/dist/cmd/cloud/env/import.js.map +1 -1
  32. package/dist/cmd/cloud/env/pull.d.ts.map +1 -1
  33. package/dist/cmd/cloud/env/pull.js +7 -9
  34. package/dist/cmd/cloud/env/pull.js.map +1 -1
  35. package/dist/cmd/cloud/env/push.js +2 -2
  36. package/dist/cmd/cloud/env/push.js.map +1 -1
  37. package/dist/cmd/cloud/env/set.js +3 -3
  38. package/dist/cmd/cloud/env/set.js.map +1 -1
  39. package/dist/cmd/cloud/index.d.ts.map +1 -1
  40. package/dist/cmd/cloud/index.js +2 -0
  41. package/dist/cmd/cloud/index.js.map +1 -1
  42. package/dist/cmd/cloud/sandbox/cp.d.ts +3 -0
  43. package/dist/cmd/cloud/sandbox/cp.d.ts.map +1 -0
  44. package/dist/cmd/cloud/sandbox/cp.js +334 -0
  45. package/dist/cmd/cloud/sandbox/cp.js.map +1 -0
  46. package/dist/cmd/cloud/sandbox/create.d.ts +3 -0
  47. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -0
  48. package/dist/cmd/cloud/sandbox/create.js +105 -0
  49. package/dist/cmd/cloud/sandbox/create.js.map +1 -0
  50. package/dist/cmd/cloud/sandbox/delete.d.ts +3 -0
  51. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -0
  52. package/dist/cmd/cloud/sandbox/delete.js +72 -0
  53. package/dist/cmd/cloud/sandbox/delete.js.map +1 -0
  54. package/dist/cmd/cloud/sandbox/exec.d.ts +3 -0
  55. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -0
  56. package/dist/cmd/cloud/sandbox/exec.js +211 -0
  57. package/dist/cmd/cloud/sandbox/exec.js.map +1 -0
  58. package/dist/cmd/cloud/sandbox/execution/get.d.ts +3 -0
  59. package/dist/cmd/cloud/sandbox/execution/get.d.ts.map +1 -0
  60. package/dist/cmd/cloud/sandbox/execution/get.js +96 -0
  61. package/dist/cmd/cloud/sandbox/execution/get.js.map +1 -0
  62. package/dist/cmd/cloud/sandbox/execution/index.d.ts +3 -0
  63. package/dist/cmd/cloud/sandbox/execution/index.d.ts.map +1 -0
  64. package/dist/cmd/cloud/sandbox/execution/index.js +24 -0
  65. package/dist/cmd/cloud/sandbox/execution/index.js.map +1 -0
  66. package/dist/cmd/cloud/sandbox/execution/list.d.ts +3 -0
  67. package/dist/cmd/cloud/sandbox/execution/list.d.ts.map +1 -0
  68. package/dist/cmd/cloud/sandbox/execution/list.js +100 -0
  69. package/dist/cmd/cloud/sandbox/execution/list.js.map +1 -0
  70. package/dist/cmd/cloud/sandbox/get.d.ts +3 -0
  71. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -0
  72. package/dist/cmd/cloud/sandbox/get.js +95 -0
  73. package/dist/cmd/cloud/sandbox/get.js.map +1 -0
  74. package/dist/cmd/cloud/sandbox/index.d.ts +3 -0
  75. package/dist/cmd/cloud/sandbox/index.d.ts.map +1 -0
  76. package/dist/cmd/cloud/sandbox/index.js +45 -0
  77. package/dist/cmd/cloud/sandbox/index.js.map +1 -0
  78. package/dist/cmd/cloud/sandbox/list.d.ts +3 -0
  79. package/dist/cmd/cloud/sandbox/list.d.ts.map +1 -0
  80. package/dist/cmd/cloud/sandbox/list.js +120 -0
  81. package/dist/cmd/cloud/sandbox/list.js.map +1 -0
  82. package/dist/cmd/cloud/sandbox/run.d.ts +3 -0
  83. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -0
  84. package/dist/cmd/cloud/sandbox/run.js +152 -0
  85. package/dist/cmd/cloud/sandbox/run.js.map +1 -0
  86. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts +3 -0
  87. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -0
  88. package/dist/cmd/cloud/sandbox/snapshot/create.js +65 -0
  89. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -0
  90. package/dist/cmd/cloud/sandbox/snapshot/delete.d.ts +3 -0
  91. package/dist/cmd/cloud/sandbox/snapshot/delete.d.ts.map +1 -0
  92. package/dist/cmd/cloud/sandbox/snapshot/delete.js +66 -0
  93. package/dist/cmd/cloud/sandbox/snapshot/delete.js.map +1 -0
  94. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts +3 -0
  95. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -0
  96. package/dist/cmd/cloud/sandbox/snapshot/get.js +154 -0
  97. package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -0
  98. package/dist/cmd/cloud/sandbox/snapshot/index.d.ts +3 -0
  99. package/dist/cmd/cloud/sandbox/snapshot/index.d.ts.map +1 -0
  100. package/dist/cmd/cloud/sandbox/snapshot/index.js +27 -0
  101. package/dist/cmd/cloud/sandbox/snapshot/index.js.map +1 -0
  102. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts +3 -0
  103. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -0
  104. package/dist/cmd/cloud/sandbox/snapshot/list.js +83 -0
  105. package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -0
  106. package/dist/cmd/cloud/sandbox/snapshot/tag.d.ts +3 -0
  107. package/dist/cmd/cloud/sandbox/snapshot/tag.d.ts.map +1 -0
  108. package/dist/cmd/cloud/sandbox/snapshot/tag.js +63 -0
  109. package/dist/cmd/cloud/sandbox/snapshot/tag.js.map +1 -0
  110. package/dist/cmd/cloud/sandbox/util.d.ts +15 -0
  111. package/dist/cmd/cloud/sandbox/util.d.ts.map +1 -0
  112. package/dist/cmd/cloud/sandbox/util.js +50 -0
  113. package/dist/cmd/cloud/sandbox/util.js.map +1 -0
  114. package/dist/cmd/cloud/secret/delete.d.ts.map +1 -1
  115. package/dist/cmd/cloud/secret/delete.js +3 -3
  116. package/dist/cmd/cloud/secret/delete.js.map +1 -1
  117. package/dist/cmd/cloud/secret/import.js +6 -6
  118. package/dist/cmd/cloud/secret/import.js.map +1 -1
  119. package/dist/cmd/cloud/secret/index.d.ts.map +1 -1
  120. package/dist/cmd/cloud/secret/index.js +1 -0
  121. package/dist/cmd/cloud/secret/index.js.map +1 -1
  122. package/dist/cmd/cloud/secret/pull.d.ts.map +1 -1
  123. package/dist/cmd/cloud/secret/pull.js +7 -9
  124. package/dist/cmd/cloud/secret/pull.js.map +1 -1
  125. package/dist/cmd/cloud/secret/push.js +3 -3
  126. package/dist/cmd/cloud/secret/push.js.map +1 -1
  127. package/dist/cmd/cloud/secret/set.d.ts.map +1 -1
  128. package/dist/cmd/cloud/secret/set.js +3 -3
  129. package/dist/cmd/cloud/secret/set.js.map +1 -1
  130. package/dist/cmd/cloud/storage/create.d.ts.map +1 -1
  131. package/dist/cmd/cloud/storage/create.js +13 -2
  132. package/dist/cmd/cloud/storage/create.js.map +1 -1
  133. package/dist/cmd/cloud/storage/delete.d.ts.map +1 -1
  134. package/dist/cmd/cloud/storage/delete.js +13 -2
  135. package/dist/cmd/cloud/storage/delete.js.map +1 -1
  136. package/dist/cmd/cloud/stream/list.d.ts.map +1 -1
  137. package/dist/cmd/cloud/stream/list.js +2 -13
  138. package/dist/cmd/cloud/stream/list.js.map +1 -1
  139. package/dist/cmd/dev/index.d.ts.map +1 -1
  140. package/dist/cmd/dev/index.js +14 -1
  141. package/dist/cmd/dev/index.js.map +1 -1
  142. package/dist/cmd/profile/create.d.ts.map +1 -1
  143. package/dist/cmd/profile/create.js +1 -0
  144. package/dist/cmd/profile/create.js.map +1 -1
  145. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  146. package/dist/cmd/project/template-flow.js +27 -10
  147. package/dist/cmd/project/template-flow.js.map +1 -1
  148. package/dist/config.d.ts +0 -2
  149. package/dist/config.d.ts.map +1 -1
  150. package/dist/config.js +3 -0
  151. package/dist/config.js.map +1 -1
  152. package/dist/env-util.d.ts +16 -8
  153. package/dist/env-util.d.ts.map +1 -1
  154. package/dist/env-util.js +46 -18
  155. package/dist/env-util.js.map +1 -1
  156. package/dist/tui.d.ts +20 -3
  157. package/dist/tui.d.ts.map +1 -1
  158. package/dist/tui.js +82 -23
  159. package/dist/tui.js.map +1 -1
  160. package/dist/types.d.ts +18 -4
  161. package/dist/types.d.ts.map +1 -1
  162. package/dist/types.js +1 -0
  163. package/dist/types.js.map +1 -1
  164. package/package.json +4 -4
  165. package/src/cli.ts +99 -21
  166. package/src/cmd/ai/prompt/api.md +26 -21
  167. package/src/cmd/ai/prompt/version.ts +3 -2
  168. package/src/cmd/build/ast.ts +214 -37
  169. package/src/cmd/build/entry-generator.ts +24 -14
  170. package/src/cmd/build/vite/registry-generator.ts +8 -11
  171. package/src/cmd/build/vite/vite-asset-server.ts +3 -1
  172. package/src/cmd/cloud/db/create.ts +13 -2
  173. package/src/cmd/cloud/db/delete.ts +15 -2
  174. package/src/cmd/cloud/deploy.ts +3 -3
  175. package/src/cmd/cloud/env/delete.ts +1 -1
  176. package/src/cmd/cloud/env/import.ts +4 -4
  177. package/src/cmd/cloud/env/pull.ts +7 -16
  178. package/src/cmd/cloud/env/push.ts +2 -2
  179. package/src/cmd/cloud/env/set.ts +3 -3
  180. package/src/cmd/cloud/index.ts +2 -0
  181. package/src/cmd/cloud/sandbox/cp.ts +531 -0
  182. package/src/cmd/cloud/sandbox/create.ts +114 -0
  183. package/src/cmd/cloud/sandbox/delete.ts +80 -0
  184. package/src/cmd/cloud/sandbox/exec.ts +254 -0
  185. package/src/cmd/cloud/sandbox/execution/get.ts +106 -0
  186. package/src/cmd/cloud/sandbox/execution/index.ts +25 -0
  187. package/src/cmd/cloud/sandbox/execution/list.ts +111 -0
  188. package/src/cmd/cloud/sandbox/get.ts +104 -0
  189. package/src/cmd/cloud/sandbox/index.ts +46 -0
  190. package/src/cmd/cloud/sandbox/list.ts +129 -0
  191. package/src/cmd/cloud/sandbox/run.ts +170 -0
  192. package/src/cmd/cloud/sandbox/snapshot/create.ts +71 -0
  193. package/src/cmd/cloud/sandbox/snapshot/delete.ts +74 -0
  194. package/src/cmd/cloud/sandbox/snapshot/get.ts +188 -0
  195. package/src/cmd/cloud/sandbox/snapshot/index.ts +28 -0
  196. package/src/cmd/cloud/sandbox/snapshot/list.ts +90 -0
  197. package/src/cmd/cloud/sandbox/snapshot/tag.ts +70 -0
  198. package/src/cmd/cloud/sandbox/util.ts +59 -0
  199. package/src/cmd/cloud/secret/delete.ts +8 -3
  200. package/src/cmd/cloud/secret/import.ts +6 -6
  201. package/src/cmd/cloud/secret/index.ts +1 -0
  202. package/src/cmd/cloud/secret/pull.ts +7 -16
  203. package/src/cmd/cloud/secret/push.ts +3 -3
  204. package/src/cmd/cloud/secret/set.ts +8 -3
  205. package/src/cmd/cloud/storage/create.ts +15 -2
  206. package/src/cmd/cloud/storage/delete.ts +15 -2
  207. package/src/cmd/cloud/stream/list.ts +2 -9
  208. package/src/cmd/dev/index.ts +18 -1
  209. package/src/cmd/profile/create.ts +1 -0
  210. package/src/cmd/project/template-flow.ts +29 -13
  211. package/src/config.ts +3 -0
  212. package/src/env-util.ts +52 -21
  213. package/src/tui.ts +131 -39
  214. package/src/types.ts +18 -16
@@ -0,0 +1,254 @@
1
+ import { z } from 'zod';
2
+ import { Writable } from 'node:stream';
3
+ import { createCommand } from '../../../types';
4
+ import * as tui from '../../../tui';
5
+ import { createSandboxClient } from './util';
6
+ import { getCommand } from '../../../command-prefix';
7
+ import { sandboxExecute, executionGet, writeAndDrain } from '@agentuity/server';
8
+ import type { Logger } from '@agentuity/core';
9
+
10
+ const POLL_INTERVAL_MS = 500;
11
+ const MAX_POLL_ATTEMPTS = 7200;
12
+
13
+ const SandboxExecResponseSchema = z.object({
14
+ executionId: z.string().describe('Unique execution identifier'),
15
+ status: z.string().describe('Execution status'),
16
+ exitCode: z.number().optional().describe('Exit code (if completed)'),
17
+ durationMs: z.number().optional().describe('Duration in milliseconds (if completed)'),
18
+ output: z.string().optional().describe('Combined stdout/stderr output'),
19
+ });
20
+
21
+ export const execSubcommand = createCommand({
22
+ name: 'exec',
23
+ aliases: ['execute'],
24
+ description: 'Execute a command in a running sandbox',
25
+ tags: ['slow', 'requires-auth'],
26
+ requires: { auth: true, region: true, org: true },
27
+ examples: [
28
+ {
29
+ command: getCommand('cloud sandbox exec abc123 -- echo "hello"'),
30
+ description: 'Execute a command in a sandbox',
31
+ },
32
+ {
33
+ command: getCommand('cloud sandbox exec abc123 --timeout 5m -- bun run build'),
34
+ description: 'Execute with timeout',
35
+ },
36
+ ],
37
+ schema: {
38
+ args: z.object({
39
+ sandboxId: z.string().describe('Sandbox ID'),
40
+ command: z.array(z.string()).describe('Command and arguments to execute'),
41
+ }),
42
+ options: z.object({
43
+ timeout: z.string().optional().describe('Execution timeout (e.g., "5m", "1h")'),
44
+ timestamps: z
45
+ .boolean()
46
+ .default(false)
47
+ .optional()
48
+ .describe('Include timestamps in output (default: false)'),
49
+ }),
50
+ response: SandboxExecResponseSchema,
51
+ },
52
+
53
+ async handler(ctx) {
54
+ const { args, opts, options, auth, region, logger, orgId } = ctx;
55
+ const client = createSandboxClient(logger, auth, region);
56
+ const started = Date.now();
57
+
58
+ const abortController = new AbortController();
59
+ const handleSignal = () => {
60
+ abortController.abort();
61
+ };
62
+ process.on('SIGINT', handleSignal);
63
+ process.on('SIGTERM', handleSignal);
64
+
65
+ const outputChunks: string[] = [];
66
+
67
+ // For JSON output, capture to buffer; otherwise stream to process
68
+ const stdout = options.json
69
+ ? createCaptureStream((chunk) => outputChunks.push(chunk))
70
+ : process.stdout;
71
+ const stderr = options.json
72
+ ? createCaptureStream((chunk) => outputChunks.push(chunk))
73
+ : process.stderr;
74
+
75
+ try {
76
+ const execution = await sandboxExecute(client, {
77
+ sandboxId: args.sandboxId,
78
+ options: {
79
+ command: args.command,
80
+ timeout: opts.timeout,
81
+ stream: opts.timestamps !== undefined ? { timestamps: opts.timestamps } : undefined,
82
+ },
83
+ orgId,
84
+ });
85
+
86
+ const stdoutStreamUrl = execution.stdoutStreamUrl;
87
+ const stderrStreamUrl = execution.stderrStreamUrl;
88
+ const streamAbortController = new AbortController();
89
+ const streamPromises: Promise<void>[] = [];
90
+
91
+ // Check if stdout and stderr are the same stream (combined output)
92
+ const isCombinedOutput =
93
+ stdoutStreamUrl && stderrStreamUrl && stdoutStreamUrl === stderrStreamUrl;
94
+
95
+ if (isCombinedOutput) {
96
+ // Stream combined output to stdout only to avoid duplicates
97
+ logger.debug('using combined output stream (stdout === stderr): %s', stdoutStreamUrl);
98
+ streamPromises.push(
99
+ streamUrlToWritable(stdoutStreamUrl, stdout, streamAbortController.signal, logger)
100
+ );
101
+ } else {
102
+ if (stdoutStreamUrl) {
103
+ logger.debug('starting stdout stream from: %s', stdoutStreamUrl);
104
+ streamPromises.push(
105
+ streamUrlToWritable(stdoutStreamUrl, stdout, streamAbortController.signal, logger)
106
+ );
107
+ }
108
+
109
+ if (stderrStreamUrl) {
110
+ logger.debug('starting stderr stream from: %s', stderrStreamUrl);
111
+ streamPromises.push(
112
+ streamUrlToWritable(stderrStreamUrl, stderr, streamAbortController.signal, logger)
113
+ );
114
+ }
115
+ }
116
+
117
+ let attempts = 0;
118
+ let finalExecution = execution;
119
+
120
+ while (attempts < MAX_POLL_ATTEMPTS) {
121
+ if (abortController.signal.aborted) {
122
+ throw new Error('Execution cancelled');
123
+ }
124
+
125
+ await sleep(POLL_INTERVAL_MS);
126
+ attempts++;
127
+
128
+ try {
129
+ const execInfo = await executionGet(client, {
130
+ executionId: execution.executionId,
131
+ orgId,
132
+ });
133
+
134
+ if (
135
+ execInfo.status === 'completed' ||
136
+ execInfo.status === 'failed' ||
137
+ execInfo.status === 'timeout' ||
138
+ execInfo.status === 'cancelled'
139
+ ) {
140
+ finalExecution = {
141
+ executionId: execInfo.executionId,
142
+ status: execInfo.status,
143
+ exitCode: execInfo.exitCode,
144
+ durationMs: execInfo.durationMs,
145
+ };
146
+ break;
147
+ }
148
+ } catch {
149
+ continue;
150
+ }
151
+ }
152
+
153
+ // Wait for all streams to reach EOF (Pulse blocks until true EOF)
154
+ await Promise.all(streamPromises);
155
+
156
+ // Ensure stdout is fully flushed before continuing
157
+ if (!options.json && process.stdout.writable) {
158
+ await new Promise<void>((resolve) => {
159
+ if (process.stdout.writableNeedDrain) {
160
+ process.stdout.once('drain', () => resolve());
161
+ } else {
162
+ resolve();
163
+ }
164
+ });
165
+ }
166
+
167
+ const duration = Date.now() - started;
168
+ const output = outputChunks.join('');
169
+
170
+ if (!options.json) {
171
+ if (finalExecution.exitCode === 0) {
172
+ // no op
173
+ } else if (finalExecution.exitCode !== undefined) {
174
+ tui.error(`failed with exit code ${finalExecution.exitCode} in ${duration}ms`);
175
+ } else {
176
+ tui.info(
177
+ `Execution ${tui.bold(finalExecution.executionId)} - Status: ${finalExecution.status}`
178
+ );
179
+ }
180
+ }
181
+
182
+ return {
183
+ executionId: finalExecution.executionId,
184
+ status: finalExecution.status,
185
+ exitCode: finalExecution.exitCode,
186
+ durationMs: finalExecution.durationMs,
187
+ output: options.json ? output : undefined,
188
+ };
189
+ } finally {
190
+ process.off('SIGINT', handleSignal);
191
+ process.off('SIGTERM', handleSignal);
192
+ }
193
+ },
194
+ });
195
+
196
+ async function streamUrlToWritable(
197
+ url: string,
198
+ writable: NodeJS.WritableStream,
199
+ signal: AbortSignal,
200
+ logger: Logger
201
+ ): Promise<void> {
202
+ try {
203
+ logger.debug('fetching stream: %s', url);
204
+ const response = await fetch(url, { signal });
205
+ logger.debug('stream response status: %d', response.status);
206
+
207
+ if (!response.ok || !response.body) {
208
+ logger.debug('stream response not ok or no body');
209
+ return;
210
+ }
211
+
212
+ const reader = response.body.getReader();
213
+
214
+ // Read until EOF - Pulse will block until data is available
215
+ while (true) {
216
+ const { done, value } = await reader.read();
217
+ if (done) {
218
+ logger.debug('stream EOF');
219
+ break;
220
+ }
221
+
222
+ if (value) {
223
+ logger.debug('stream chunk: %d bytes', value.length);
224
+ await writeAndDrain(writable, value);
225
+ }
226
+ }
227
+ } catch (err) {
228
+ if (err instanceof Error && err.name === 'AbortError') {
229
+ logger.debug('stream aborted');
230
+ return;
231
+ }
232
+ logger.debug('stream error: %s', err);
233
+ }
234
+ }
235
+
236
+ function createCaptureStream(onChunk: (chunk: string) => void): NodeJS.WritableStream {
237
+ return new Writable({
238
+ write(
239
+ chunk: Buffer | string,
240
+ _encoding: string,
241
+ callback: (error?: Error | null) => void
242
+ ): void {
243
+ const text = typeof chunk === 'string' ? chunk : chunk.toString('utf-8');
244
+ onChunk(text);
245
+ callback();
246
+ },
247
+ });
248
+ }
249
+
250
+ function sleep(ms: number): Promise<void> {
251
+ return new Promise((resolve) => setTimeout(resolve, ms));
252
+ }
253
+
254
+ export default execSubcommand;
@@ -0,0 +1,106 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../../types';
3
+ import * as tui from '../../../../tui';
4
+ import { createSandboxClient } from '../util';
5
+ import { getCommand } from '../../../../command-prefix';
6
+ import { executionGet } from '@agentuity/server';
7
+
8
+ const ExecutionGetResponseSchema = z.object({
9
+ executionId: z.string().describe('Execution ID'),
10
+ sandboxId: z.string().describe('Sandbox ID'),
11
+ status: z.string().describe('Current status'),
12
+ command: z.array(z.string()).optional().describe('Command that was executed'),
13
+ exitCode: z.number().optional().describe('Exit code'),
14
+ durationMs: z.number().optional().describe('Duration in milliseconds'),
15
+ startedAt: z.string().optional().describe('Start timestamp'),
16
+ completedAt: z.string().optional().describe('Completion timestamp'),
17
+ error: z.string().optional().describe('Error message if failed'),
18
+ stdoutStreamUrl: z.string().optional().describe('URL to stream stdout'),
19
+ stderrStreamUrl: z.string().optional().describe('URL to stream stderr'),
20
+ });
21
+
22
+ export const getSubcommand = createCommand({
23
+ name: 'get',
24
+ aliases: ['info', 'show'],
25
+ description: 'Get information about a specific execution',
26
+ tags: ['read-only', 'fast', 'requires-auth'],
27
+ requires: { auth: true, region: true, org: true },
28
+ idempotent: true,
29
+ examples: [
30
+ {
31
+ command: getCommand('cloud sandbox execution get exec_abc123'),
32
+ description: 'Get execution information',
33
+ },
34
+ ],
35
+ schema: {
36
+ args: z.object({
37
+ executionId: z.string().describe('Execution ID'),
38
+ }),
39
+ response: ExecutionGetResponseSchema,
40
+ },
41
+
42
+ async handler(ctx) {
43
+ const { args, options, auth, region, logger, orgId } = ctx;
44
+ const client = createSandboxClient(logger, auth, region);
45
+
46
+ const result = await executionGet(client, { executionId: args.executionId, orgId });
47
+
48
+ if (!options.json) {
49
+ const statusColor =
50
+ result.status === 'completed'
51
+ ? tui.colorSuccess
52
+ : result.status === 'running'
53
+ ? tui.colorWarning
54
+ : result.status === 'failed' || result.status === 'timeout'
55
+ ? tui.colorError
56
+ : tui.colorMuted;
57
+
58
+ console.log(`${tui.muted('Execution:')} ${tui.bold(result.executionId)}`);
59
+ console.log(`${tui.muted('Sandbox:')} ${result.sandboxId}`);
60
+ console.log(`${tui.muted('Status:')} ${statusColor(result.status)}`);
61
+ if (result.exitCode !== undefined) {
62
+ const exitCodeColor = result.exitCode === 0 ? tui.colorSuccess : tui.colorError;
63
+ console.log(
64
+ `${tui.muted('Exit Code:')} ${exitCodeColor(String(result.exitCode))}`
65
+ );
66
+ }
67
+ if (result.durationMs !== undefined) {
68
+ console.log(`${tui.muted('Duration:')} ${result.durationMs}ms`);
69
+ }
70
+ if (result.startedAt) {
71
+ console.log(`${tui.muted('Started:')} ${result.startedAt}`);
72
+ }
73
+ if (result.completedAt) {
74
+ console.log(`${tui.muted('Completed:')} ${result.completedAt}`);
75
+ }
76
+ if (result.error) {
77
+ console.log(`${tui.muted('Error:')} ${tui.colorError(result.error)}`);
78
+ }
79
+ if (result.stdoutStreamUrl) {
80
+ console.log(`${tui.muted('Stdout:')} ${result.stdoutStreamUrl}`);
81
+ }
82
+ if (result.stderrStreamUrl) {
83
+ console.log(`${tui.muted('Stderr:')} ${result.stderrStreamUrl}`);
84
+ }
85
+ if (result.command && result.command.length > 0) {
86
+ console.log(`${tui.muted('Command:')} ${result.command.join(' ')}`);
87
+ }
88
+ }
89
+
90
+ return {
91
+ executionId: result.executionId,
92
+ sandboxId: result.sandboxId,
93
+ status: result.status,
94
+ command: result.command,
95
+ exitCode: result.exitCode,
96
+ durationMs: result.durationMs,
97
+ startedAt: result.startedAt,
98
+ completedAt: result.completedAt,
99
+ error: result.error,
100
+ stdoutStreamUrl: result.stdoutStreamUrl,
101
+ stderrStreamUrl: result.stderrStreamUrl,
102
+ };
103
+ },
104
+ });
105
+
106
+ export default getSubcommand;
@@ -0,0 +1,25 @@
1
+ import { createCommand } from '../../../../types';
2
+ import { getSubcommand } from './get';
3
+ import { listSubcommand } from './list';
4
+ import { getCommand } from '../../../../command-prefix';
5
+
6
+ export const command = createCommand({
7
+ name: 'execution',
8
+ aliases: ['executions'],
9
+ description: 'Manage sandbox executions',
10
+ tags: ['read-only', 'requires-auth'],
11
+ examples: [
12
+ {
13
+ command: getCommand('cloud sandbox execution list snbx_abc123'),
14
+ description: 'List executions for a sandbox',
15
+ },
16
+ {
17
+ command: getCommand('cloud sandbox execution get exec_abc123'),
18
+ description: 'Get details of a specific execution',
19
+ },
20
+ ],
21
+ subcommands: [getSubcommand, listSubcommand],
22
+ requires: { auth: true, region: true, org: true },
23
+ });
24
+
25
+ export default command;
@@ -0,0 +1,111 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../../types';
3
+ import * as tui from '../../../../tui';
4
+ import { createSandboxClient } from '../util';
5
+ import { getCommand } from '../../../../command-prefix';
6
+ import { executionList } from '@agentuity/server';
7
+
8
+ const ExecutionInfoSchema = z.object({
9
+ executionId: z.string().describe('Execution ID'),
10
+ sandboxId: z.string().describe('Sandbox ID'),
11
+ status: z.string().describe('Current status'),
12
+ exitCode: z.number().optional().describe('Exit code'),
13
+ durationMs: z.number().optional().describe('Duration in milliseconds'),
14
+ startedAt: z.string().optional().describe('Start timestamp'),
15
+ completedAt: z.string().optional().describe('Completion timestamp'),
16
+ error: z.string().optional().describe('Error message if failed'),
17
+ });
18
+
19
+ const ExecutionListResponseSchema = z.object({
20
+ executions: z.array(ExecutionInfoSchema).describe('List of executions'),
21
+ });
22
+
23
+ export const listSubcommand = createCommand({
24
+ name: 'list',
25
+ aliases: ['ls'],
26
+ description: 'List executions for a sandbox',
27
+ tags: ['read-only', 'fast', 'requires-auth'],
28
+ requires: { auth: true, region: true, org: true },
29
+ idempotent: true,
30
+ examples: [
31
+ {
32
+ command: getCommand('cloud sandbox execution list snbx_abc123'),
33
+ description: 'List executions for a sandbox',
34
+ },
35
+ {
36
+ command: getCommand('cloud sandbox execution list snbx_abc123 --limit 10'),
37
+ description: 'List with a limit',
38
+ },
39
+ ],
40
+ schema: {
41
+ args: z.object({
42
+ sandboxId: z.string().describe('Sandbox ID'),
43
+ }),
44
+ options: z.object({
45
+ limit: z.number().optional().describe('Maximum number of results (default: 50, max: 100)'),
46
+ }),
47
+ response: ExecutionListResponseSchema,
48
+ },
49
+
50
+ async handler(ctx) {
51
+ const { args, opts, options, auth, region, logger, orgId } = ctx;
52
+ const client = createSandboxClient(logger, auth, region);
53
+
54
+ const result = await executionList(client, {
55
+ sandboxId: args.sandboxId,
56
+ orgId,
57
+ limit: opts.limit,
58
+ });
59
+
60
+ if (!options.json) {
61
+ if (result.executions.length === 0) {
62
+ tui.info('No executions found');
63
+ } else {
64
+ const tableData = result.executions.map((exec) => {
65
+ const statusColor =
66
+ exec.status === 'completed'
67
+ ? tui.colorSuccess
68
+ : exec.status === 'running'
69
+ ? tui.colorWarning
70
+ : exec.status === 'failed' || exec.status === 'timeout'
71
+ ? tui.colorError
72
+ : tui.colorMuted;
73
+
74
+ return {
75
+ ID: exec.executionId,
76
+ Status: statusColor(exec.status),
77
+ 'Exit Code': exec.exitCode !== undefined ? String(exec.exitCode) : '-',
78
+ Duration: exec.durationMs !== undefined ? `${exec.durationMs}ms` : '-',
79
+ Started: exec.startedAt || '-',
80
+ };
81
+ });
82
+ tui.table(tableData, [
83
+ { name: 'ID', alignment: 'left' },
84
+ { name: 'Status', alignment: 'left' },
85
+ { name: 'Exit Code', alignment: 'right' },
86
+ { name: 'Duration', alignment: 'right' },
87
+ { name: 'Started', alignment: 'left' },
88
+ ]);
89
+
90
+ tui.info(
91
+ `Total: ${result.executions.length} ${tui.plural(result.executions.length, 'execution', 'executions')}`
92
+ );
93
+ }
94
+ }
95
+
96
+ return {
97
+ executions: result.executions.map((e) => ({
98
+ executionId: e.executionId,
99
+ sandboxId: e.sandboxId,
100
+ status: e.status,
101
+ exitCode: e.exitCode,
102
+ durationMs: e.durationMs,
103
+ startedAt: e.startedAt,
104
+ completedAt: e.completedAt,
105
+ error: e.error,
106
+ })),
107
+ };
108
+ },
109
+ });
110
+
111
+ export default listSubcommand;
@@ -0,0 +1,104 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../types';
3
+ import * as tui from '../../../tui';
4
+ import { createSandboxClient } from './util';
5
+ import { getCommand } from '../../../command-prefix';
6
+ import { sandboxGet } from '@agentuity/server';
7
+
8
+ const SandboxGetResponseSchema = z.object({
9
+ sandboxId: z.string().describe('Sandbox ID'),
10
+ status: z.string().describe('Current status'),
11
+ createdAt: z.string().describe('Creation timestamp'),
12
+ region: z.string().optional().describe('Region where sandbox is running'),
13
+ snapshotId: z.string().optional().describe('Snapshot ID sandbox was created from'),
14
+ snapshotTag: z.string().optional().describe('Snapshot tag sandbox was created from'),
15
+ executions: z.number().describe('Number of executions'),
16
+ stdoutStreamUrl: z.string().optional().describe('URL to stdout output stream'),
17
+ stderrStreamUrl: z.string().optional().describe('URL to stderr output stream'),
18
+ dependencies: z.array(z.string()).optional().describe('Apt packages installed'),
19
+ });
20
+
21
+ export const getSubcommand = createCommand({
22
+ name: 'get',
23
+ aliases: ['info', 'show'],
24
+ description: 'Get information about a sandbox',
25
+ tags: ['read-only', 'fast', 'requires-auth'],
26
+ requires: { auth: true, region: true, org: true },
27
+ idempotent: true,
28
+ examples: [
29
+ {
30
+ command: getCommand('cloud sandbox get abc123'),
31
+ description: 'Get sandbox information',
32
+ },
33
+ ],
34
+ schema: {
35
+ args: z.object({
36
+ sandboxId: z.string().describe('Sandbox ID'),
37
+ }),
38
+ response: SandboxGetResponseSchema,
39
+ },
40
+
41
+ async handler(ctx) {
42
+ const { args, options, auth, region, logger, orgId } = ctx;
43
+ const client = createSandboxClient(logger, auth, region);
44
+
45
+ const result = await sandboxGet(client, { sandboxId: args.sandboxId, orgId });
46
+
47
+ if (!options.json) {
48
+ const statusColor =
49
+ result.status === 'running'
50
+ ? tui.colorSuccess
51
+ : result.status === 'idle'
52
+ ? tui.colorWarning
53
+ : result.status === 'failed'
54
+ ? tui.colorError
55
+ : tui.colorMuted;
56
+
57
+ console.log(`${tui.muted('Sandbox:')} ${tui.bold(result.sandboxId)}`);
58
+ console.log(`${tui.muted('Status:')} ${statusColor(result.status)}`);
59
+ console.log(`${tui.muted('Created:')} ${result.createdAt}`);
60
+ if (result.region) {
61
+ console.log(`${tui.muted('Region:')} ${result.region}`);
62
+ }
63
+ if (result.snapshotId || result.snapshotTag) {
64
+ const snapshotDisplay = result.snapshotTag
65
+ ? `${result.snapshotTag} ${tui.muted('(' + result.snapshotId + ')')}`
66
+ : result.snapshotId;
67
+ console.log(`${tui.muted('Snapshot:')} ${snapshotDisplay}`);
68
+ }
69
+ console.log(`${tui.muted('Executions:')} ${result.executions}`);
70
+ if (
71
+ result.stdoutStreamUrl &&
72
+ result.stderrStreamUrl &&
73
+ result.stdoutStreamUrl === result.stderrStreamUrl
74
+ ) {
75
+ console.log(`${tui.muted('Stream:')} ${tui.link(result.stdoutStreamUrl)}`);
76
+ } else {
77
+ if (result.stdoutStreamUrl) {
78
+ console.log(`${tui.muted('Stream (stdout):')} ${tui.link(result.stdoutStreamUrl)}`);
79
+ }
80
+ if (result.stderrStreamUrl) {
81
+ console.log(`${tui.muted('Stream (stderr):')} ${tui.link(result.stderrStreamUrl)}`);
82
+ }
83
+ }
84
+ if (result.dependencies && result.dependencies.length > 0) {
85
+ console.log(`${tui.muted('Dependencies:')} ${result.dependencies.join(', ')}`);
86
+ }
87
+ }
88
+
89
+ return {
90
+ sandboxId: result.sandboxId,
91
+ status: result.status,
92
+ createdAt: result.createdAt,
93
+ region: result.region,
94
+ snapshotId: result.snapshotId,
95
+ snapshotTag: result.snapshotTag,
96
+ executions: result.executions,
97
+ stdoutStreamUrl: result.stdoutStreamUrl,
98
+ stderrStreamUrl: result.stderrStreamUrl,
99
+ dependencies: result.dependencies,
100
+ };
101
+ },
102
+ });
103
+
104
+ export default getSubcommand;
@@ -0,0 +1,46 @@
1
+ import { createCommand } from '../../../types';
2
+ import { runSubcommand } from './run';
3
+ import { createSubcommand } from './create';
4
+ import { execSubcommand } from './exec';
5
+ import { listSubcommand } from './list';
6
+ import { getSubcommand } from './get';
7
+ import { deleteSubcommand } from './delete';
8
+ import { snapshotCommand } from './snapshot';
9
+ import { cpSubcommand } from './cp';
10
+ import { command as executionCommand } from './execution';
11
+ import { getCommand } from '../../../command-prefix';
12
+
13
+ export const command = createCommand({
14
+ name: 'sandbox',
15
+ aliases: ['sb'],
16
+ description: 'Manage sandboxes for isolated code execution',
17
+ tags: ['slow', 'requires-auth'],
18
+ examples: [
19
+ {
20
+ command: getCommand('cloud sandbox run -- echo "hello"'),
21
+ description: 'Run a one-shot command in a sandbox',
22
+ },
23
+ {
24
+ command: getCommand('cloud sandbox create'),
25
+ description: 'Create an interactive sandbox',
26
+ },
27
+ {
28
+ command: getCommand('cloud sandbox list'),
29
+ description: 'List all sandboxes',
30
+ },
31
+ ],
32
+ subcommands: [
33
+ runSubcommand,
34
+ createSubcommand,
35
+ execSubcommand,
36
+ listSubcommand,
37
+ getSubcommand,
38
+ deleteSubcommand,
39
+ snapshotCommand,
40
+ cpSubcommand,
41
+ executionCommand,
42
+ ],
43
+ requires: { auth: true, region: true, org: true },
44
+ });
45
+
46
+ export default command;