@agentuity/cli 2.0.11 → 2.0.12

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 (220) hide show
  1. package/dist/cache/resource-region.d.ts.map +1 -1
  2. package/dist/cache/resource-region.js +48 -25
  3. package/dist/cache/resource-region.js.map +1 -1
  4. package/dist/cmd/build/vite/bun-dev-server.d.ts +20 -0
  5. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  6. package/dist/cmd/build/vite/bun-dev-server.js +62 -4
  7. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  8. package/dist/cmd/build/vite/index.d.ts +0 -1
  9. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  10. package/dist/cmd/build/vite/index.js +0 -1
  11. package/dist/cmd/build/vite/index.js.map +1 -1
  12. package/dist/cmd/build/vite/static-renderer.d.ts +17 -0
  13. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  14. package/dist/cmd/build/vite/static-renderer.js +18 -6
  15. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  16. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  17. package/dist/cmd/build/vite/vite-asset-server-config.js +34 -27
  18. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  19. package/dist/cmd/build/vite/vite-asset-server.d.ts +9 -0
  20. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  21. package/dist/cmd/build/vite/vite-asset-server.js +5 -1
  22. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  23. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  24. package/dist/cmd/build/vite/vite-builder.js +12 -1
  25. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  26. package/dist/cmd/build/vite/ws-proxy.d.ts +15 -1
  27. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -1
  28. package/dist/cmd/build/vite/ws-proxy.js +33 -0
  29. package/dist/cmd/build/vite/ws-proxy.js.map +1 -1
  30. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  31. package/dist/cmd/cloud/deploy.js +98 -39
  32. package/dist/cmd/cloud/deploy.js.map +1 -1
  33. package/dist/cmd/cloud/sandbox/checkpoint/create.d.ts.map +1 -1
  34. package/dist/cmd/cloud/sandbox/checkpoint/create.js +3 -4
  35. package/dist/cmd/cloud/sandbox/checkpoint/create.js.map +1 -1
  36. package/dist/cmd/cloud/sandbox/checkpoint/delete.d.ts.map +1 -1
  37. package/dist/cmd/cloud/sandbox/checkpoint/delete.js +3 -4
  38. package/dist/cmd/cloud/sandbox/checkpoint/delete.js.map +1 -1
  39. package/dist/cmd/cloud/sandbox/checkpoint/list.d.ts.map +1 -1
  40. package/dist/cmd/cloud/sandbox/checkpoint/list.js +3 -4
  41. package/dist/cmd/cloud/sandbox/checkpoint/list.js.map +1 -1
  42. package/dist/cmd/cloud/sandbox/checkpoint/restore.d.ts.map +1 -1
  43. package/dist/cmd/cloud/sandbox/checkpoint/restore.js +3 -4
  44. package/dist/cmd/cloud/sandbox/checkpoint/restore.js.map +1 -1
  45. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
  46. package/dist/cmd/cloud/sandbox/create.js +13 -4
  47. package/dist/cmd/cloud/sandbox/create.js.map +1 -1
  48. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -1
  49. package/dist/cmd/cloud/sandbox/delete.js +3 -4
  50. package/dist/cmd/cloud/sandbox/delete.js.map +1 -1
  51. package/dist/cmd/cloud/sandbox/env.d.ts.map +1 -1
  52. package/dist/cmd/cloud/sandbox/env.js +3 -5
  53. package/dist/cmd/cloud/sandbox/env.js.map +1 -1
  54. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
  55. package/dist/cmd/cloud/sandbox/exec.js +114 -41
  56. package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
  57. package/dist/cmd/cloud/sandbox/execution/list.d.ts.map +1 -1
  58. package/dist/cmd/cloud/sandbox/execution/list.js +3 -5
  59. package/dist/cmd/cloud/sandbox/execution/list.js.map +1 -1
  60. package/dist/cmd/cloud/sandbox/fs/cp.d.ts.map +1 -1
  61. package/dist/cmd/cloud/sandbox/fs/cp.js +61 -113
  62. package/dist/cmd/cloud/sandbox/fs/cp.js.map +1 -1
  63. package/dist/cmd/cloud/sandbox/fs/download.d.ts.map +1 -1
  64. package/dist/cmd/cloud/sandbox/fs/download.js +11 -22
  65. package/dist/cmd/cloud/sandbox/fs/download.js.map +1 -1
  66. package/dist/cmd/cloud/sandbox/fs/ls.d.ts.map +1 -1
  67. package/dist/cmd/cloud/sandbox/fs/ls.js +3 -5
  68. package/dist/cmd/cloud/sandbox/fs/ls.js.map +1 -1
  69. package/dist/cmd/cloud/sandbox/fs/mkdir.d.ts.map +1 -1
  70. package/dist/cmd/cloud/sandbox/fs/mkdir.js +3 -5
  71. package/dist/cmd/cloud/sandbox/fs/mkdir.js.map +1 -1
  72. package/dist/cmd/cloud/sandbox/fs/rm.d.ts.map +1 -1
  73. package/dist/cmd/cloud/sandbox/fs/rm.js +3 -5
  74. package/dist/cmd/cloud/sandbox/fs/rm.js.map +1 -1
  75. package/dist/cmd/cloud/sandbox/fs/rmdir.d.ts.map +1 -1
  76. package/dist/cmd/cloud/sandbox/fs/rmdir.js +3 -5
  77. package/dist/cmd/cloud/sandbox/fs/rmdir.js.map +1 -1
  78. package/dist/cmd/cloud/sandbox/fs/upload.d.ts.map +1 -1
  79. package/dist/cmd/cloud/sandbox/fs/upload.js +7 -8
  80. package/dist/cmd/cloud/sandbox/fs/upload.js.map +1 -1
  81. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
  82. package/dist/cmd/cloud/sandbox/get.js +21 -7
  83. package/dist/cmd/cloud/sandbox/get.js.map +1 -1
  84. package/dist/cmd/cloud/sandbox/job/create.d.ts.map +1 -1
  85. package/dist/cmd/cloud/sandbox/job/create.js +3 -4
  86. package/dist/cmd/cloud/sandbox/job/create.js.map +1 -1
  87. package/dist/cmd/cloud/sandbox/job/destroy.d.ts.map +1 -1
  88. package/dist/cmd/cloud/sandbox/job/destroy.js +3 -4
  89. package/dist/cmd/cloud/sandbox/job/destroy.js.map +1 -1
  90. package/dist/cmd/cloud/sandbox/job/get.d.ts.map +1 -1
  91. package/dist/cmd/cloud/sandbox/job/get.js +3 -4
  92. package/dist/cmd/cloud/sandbox/job/get.js.map +1 -1
  93. package/dist/cmd/cloud/sandbox/job/list.d.ts.map +1 -1
  94. package/dist/cmd/cloud/sandbox/job/list.js +3 -4
  95. package/dist/cmd/cloud/sandbox/job/list.js.map +1 -1
  96. package/dist/cmd/cloud/sandbox/job/logs.d.ts.map +1 -1
  97. package/dist/cmd/cloud/sandbox/job/logs.js +4 -4
  98. package/dist/cmd/cloud/sandbox/job/logs.js.map +1 -1
  99. package/dist/cmd/cloud/sandbox/pause.d.ts.map +1 -1
  100. package/dist/cmd/cloud/sandbox/pause.js +21 -5
  101. package/dist/cmd/cloud/sandbox/pause.js.map +1 -1
  102. package/dist/cmd/cloud/sandbox/resume.d.ts.map +1 -1
  103. package/dist/cmd/cloud/sandbox/resume.js +3 -4
  104. package/dist/cmd/cloud/sandbox/resume.js.map +1 -1
  105. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
  106. package/dist/cmd/cloud/sandbox/run.js +36 -7
  107. package/dist/cmd/cloud/sandbox/run.js.map +1 -1
  108. package/dist/cmd/cloud/sandbox/util.d.ts +19 -0
  109. package/dist/cmd/cloud/sandbox/util.d.ts.map +1 -1
  110. package/dist/cmd/cloud/sandbox/util.js +40 -2
  111. package/dist/cmd/cloud/sandbox/util.js.map +1 -1
  112. package/dist/cmd/coder/create.js +7 -7
  113. package/dist/cmd/coder/create.js.map +1 -1
  114. package/dist/cmd/coder/start.d.ts.map +1 -1
  115. package/dist/cmd/coder/start.js +3 -0
  116. package/dist/cmd/coder/start.js.map +1 -1
  117. package/dist/cmd/coder/tui-init.js +1 -1
  118. package/dist/cmd/coder/tui-init.js.map +1 -1
  119. package/dist/cmd/coder/update.js +8 -8
  120. package/dist/cmd/coder/update.js.map +1 -1
  121. package/dist/cmd/coder/workspace/create.d.ts.map +1 -1
  122. package/dist/cmd/coder/workspace/create.js +49 -21
  123. package/dist/cmd/coder/workspace/create.js.map +1 -1
  124. package/dist/cmd/coder/workspace/index.d.ts.map +1 -1
  125. package/dist/cmd/coder/workspace/index.js +1 -1
  126. package/dist/cmd/coder/workspace/index.js.map +1 -1
  127. package/dist/cmd/dev/dev-lock.d.ts.map +1 -1
  128. package/dist/cmd/dev/dev-lock.js +43 -17
  129. package/dist/cmd/dev/dev-lock.js.map +1 -1
  130. package/dist/cmd/dev/index.d.ts.map +1 -1
  131. package/dist/cmd/dev/index.js +211 -125
  132. package/dist/cmd/dev/index.js.map +1 -1
  133. package/dist/cmd/dev/process-manager.d.ts +41 -1
  134. package/dist/cmd/dev/process-manager.d.ts.map +1 -1
  135. package/dist/cmd/dev/process-manager.js +160 -31
  136. package/dist/cmd/dev/process-manager.js.map +1 -1
  137. package/dist/cmd/project/create.d.ts.map +1 -1
  138. package/dist/cmd/project/create.js +0 -2
  139. package/dist/cmd/project/create.js.map +1 -1
  140. package/dist/cmd/project/index.d.ts.map +1 -1
  141. package/dist/cmd/project/index.js +0 -3
  142. package/dist/cmd/project/index.js.map +1 -1
  143. package/dist/cmd/project/template-flow.d.ts +0 -1
  144. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  145. package/dist/cmd/project/template-flow.js +1 -124
  146. package/dist/cmd/project/template-flow.js.map +1 -1
  147. package/package.json +7 -7
  148. package/src/cache/resource-region.ts +68 -44
  149. package/src/cmd/ai/prompt/web.md +43 -17
  150. package/src/cmd/build/vite/bun-dev-server.ts +92 -6
  151. package/src/cmd/build/vite/index.ts +0 -1
  152. package/src/cmd/build/vite/static-renderer.ts +18 -7
  153. package/src/cmd/build/vite/vite-asset-server-config.ts +37 -27
  154. package/src/cmd/build/vite/vite-asset-server.ts +5 -1
  155. package/src/cmd/build/vite/vite-builder.ts +12 -1
  156. package/src/cmd/build/vite/ws-proxy.ts +52 -3
  157. package/src/cmd/cloud/deploy.ts +117 -49
  158. package/src/cmd/cloud/sandbox/checkpoint/create.ts +10 -4
  159. package/src/cmd/cloud/sandbox/checkpoint/delete.ts +10 -4
  160. package/src/cmd/cloud/sandbox/checkpoint/list.ts +10 -4
  161. package/src/cmd/cloud/sandbox/checkpoint/restore.ts +10 -4
  162. package/src/cmd/cloud/sandbox/create.ts +14 -4
  163. package/src/cmd/cloud/sandbox/delete.ts +10 -4
  164. package/src/cmd/cloud/sandbox/env.ts +10 -5
  165. package/src/cmd/cloud/sandbox/exec.ts +157 -42
  166. package/src/cmd/cloud/sandbox/execution/list.ts +10 -5
  167. package/src/cmd/cloud/sandbox/fs/cp.ts +94 -126
  168. package/src/cmd/cloud/sandbox/fs/download.ts +18 -25
  169. package/src/cmd/cloud/sandbox/fs/ls.ts +10 -5
  170. package/src/cmd/cloud/sandbox/fs/mkdir.ts +10 -5
  171. package/src/cmd/cloud/sandbox/fs/rm.ts +10 -5
  172. package/src/cmd/cloud/sandbox/fs/rmdir.ts +10 -5
  173. package/src/cmd/cloud/sandbox/fs/upload.ts +14 -8
  174. package/src/cmd/cloud/sandbox/get.ts +28 -7
  175. package/src/cmd/cloud/sandbox/job/create.ts +10 -4
  176. package/src/cmd/cloud/sandbox/job/destroy.ts +10 -4
  177. package/src/cmd/cloud/sandbox/job/get.ts +10 -4
  178. package/src/cmd/cloud/sandbox/job/list.ts +10 -4
  179. package/src/cmd/cloud/sandbox/job/logs.ts +11 -4
  180. package/src/cmd/cloud/sandbox/pause.ts +31 -5
  181. package/src/cmd/cloud/sandbox/resume.ts +10 -4
  182. package/src/cmd/cloud/sandbox/run.ts +49 -11
  183. package/src/cmd/cloud/sandbox/util.ts +63 -2
  184. package/src/cmd/coder/create.ts +8 -8
  185. package/src/cmd/coder/start.ts +3 -0
  186. package/src/cmd/coder/tui-init.ts +1 -1
  187. package/src/cmd/coder/update.ts +7 -7
  188. package/src/cmd/coder/workspace/create.ts +77 -26
  189. package/src/cmd/coder/workspace/index.ts +3 -1
  190. package/src/cmd/dev/dev-lock.ts +50 -16
  191. package/src/cmd/dev/index.ts +249 -134
  192. package/src/cmd/dev/process-manager.ts +173 -33
  193. package/src/cmd/project/create.ts +0 -2
  194. package/src/cmd/project/index.ts +0 -3
  195. package/src/cmd/project/template-flow.ts +0 -147
  196. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts +0 -45
  197. package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +0 -1
  198. package/dist/cmd/build/vite/public-asset-path-plugin.js +0 -166
  199. package/dist/cmd/build/vite/public-asset-path-plugin.js.map +0 -1
  200. package/dist/cmd/project/auth/generate.d.ts +0 -5
  201. package/dist/cmd/project/auth/generate.d.ts.map +0 -1
  202. package/dist/cmd/project/auth/generate.js +0 -102
  203. package/dist/cmd/project/auth/generate.js.map +0 -1
  204. package/dist/cmd/project/auth/index.d.ts +0 -2
  205. package/dist/cmd/project/auth/index.d.ts.map +0 -1
  206. package/dist/cmd/project/auth/index.js +0 -21
  207. package/dist/cmd/project/auth/index.js.map +0 -1
  208. package/dist/cmd/project/auth/init.d.ts +0 -2
  209. package/dist/cmd/project/auth/init.d.ts.map +0 -1
  210. package/dist/cmd/project/auth/init.js +0 -213
  211. package/dist/cmd/project/auth/init.js.map +0 -1
  212. package/dist/cmd/project/auth/shared.d.ts +0 -93
  213. package/dist/cmd/project/auth/shared.d.ts.map +0 -1
  214. package/dist/cmd/project/auth/shared.js +0 -475
  215. package/dist/cmd/project/auth/shared.js.map +0 -1
  216. package/src/cmd/build/vite/public-asset-path-plugin.ts +0 -209
  217. package/src/cmd/project/auth/generate.ts +0 -116
  218. package/src/cmd/project/auth/index.ts +0 -21
  219. package/src/cmd/project/auth/init.ts +0 -256
  220. package/src/cmd/project/auth/shared.ts +0 -591
@@ -1,9 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import { createCommand } from '../../../types';
3
3
  import * as tui from '../../../tui';
4
- import { createSandboxClient } from './util';
4
+ import { createSandboxClient, resolveSandboxTarget } from './util';
5
5
  import { getCommand } from '../../../command-prefix';
6
- import { sandboxSetEnv, sandboxResolve } from '@agentuity/server';
6
+ import { sandboxSetEnv } from '@agentuity/server';
7
7
 
8
8
  export const envSubcommand = createCommand({
9
9
  name: 'env',
@@ -44,9 +44,14 @@ export const envSubcommand = createCommand({
44
44
  async handler(ctx) {
45
45
  const { args, opts, options, auth, logger, apiClient } = ctx;
46
46
 
47
- // Resolve sandbox to get region and orgId using CLI API
48
- const sandboxInfo = await sandboxResolve(apiClient, args.sandboxId);
49
- const { region, orgId } = sandboxInfo;
47
+ const { region, orgId } = await resolveSandboxTarget(
48
+ logger,
49
+ auth,
50
+ apiClient,
51
+ args.sandboxId,
52
+ ctx.config?.name ?? 'production',
53
+ ctx.config
54
+ );
50
55
 
51
56
  const client = createSandboxClient(logger, auth, region);
52
57
 
@@ -3,12 +3,14 @@ import { Writable } from 'node:stream';
3
3
  import { ErrorCode } from '../../../errors';
4
4
  import { createCommand } from '../../../types';
5
5
  import * as tui from '../../../tui';
6
- import { createSandboxClient } from './util';
6
+ import { createSandboxClient, detectNullStream, resolveSandboxTarget } from './util';
7
7
  import { getCommand } from '../../../command-prefix';
8
- import { sandboxExecute, executionGet, sandboxResolve } from '@agentuity/server';
8
+ import { sandboxExecute, executionGet } from '@agentuity/server';
9
9
  import { streamUrlToWritable } from '../../../utils/stream-url';
10
10
 
11
11
  const EXECUTION_WAIT_DURATION = '5m';
12
+ const EMPTY_STREAM_FAST_POLL_MS = 100;
13
+ const EMPTY_STREAM_FAST_TIMEOUT_MS = 2000;
12
14
 
13
15
  const SandboxExecResponseSchema = z.object({
14
16
  executionId: z.string().describe('Unique execution identifier'),
@@ -63,6 +65,11 @@ export const execSubcommand = createCommand({
63
65
  .default(false)
64
66
  .optional()
65
67
  .describe('Include timestamps in output (default: false)'),
68
+ quiet: z
69
+ .boolean()
70
+ .default(false)
71
+ .optional()
72
+ .describe('Suppress output (do not create stdout/stderr streams)'),
66
73
  }),
67
74
  response: SandboxExecResponseSchema,
68
75
  },
@@ -79,12 +86,46 @@ export const execSubcommand = createCommand({
79
86
  }
80
87
  }
81
88
 
82
- const sandboxInfo = await sandboxResolve(apiClient, args.sandboxId);
83
- const { region, orgId } = sandboxInfo;
89
+ const { region, orgId } = await resolveSandboxTarget(
90
+ logger,
91
+ auth,
92
+ apiClient,
93
+ args.sandboxId,
94
+ ctx.config?.name ?? 'production',
95
+ ctx.config
96
+ );
84
97
 
85
98
  const client = createSandboxClient(logger, auth, region);
86
99
  const started = Date.now();
87
100
 
101
+ // Detect if stdout/stderr are redirected to /dev/null
102
+ const stdoutIsNull = detectNullStream(1);
103
+ const stderrIsNull = detectNullStream(2);
104
+
105
+ // Build stream configuration
106
+ const streamConfig: {
107
+ timestamps?: boolean;
108
+ stdout?: string;
109
+ stderr?: string;
110
+ } = {
111
+ timestamps: opts.timestamps,
112
+ };
113
+
114
+ // --quiet: suppress all output streams (no server streams, no local capture)
115
+ if (opts.quiet) {
116
+ streamConfig.stdout = 'ignore';
117
+ streamConfig.stderr = 'ignore';
118
+ } else if (!options.json) {
119
+ // Auto-detect /dev/null redirection (only when not in JSON mode)
120
+ // In JSON mode we need output for the response, so keep streams even if redirected
121
+ if (stdoutIsNull) {
122
+ streamConfig.stdout = 'ignore';
123
+ }
124
+ if (stderrIsNull) {
125
+ streamConfig.stderr = 'ignore';
126
+ }
127
+ }
128
+
88
129
  const abortController = new AbortController();
89
130
  const handleSignal = () => {
90
131
  abortController.abort();
@@ -100,7 +141,7 @@ export const execSubcommand = createCommand({
100
141
  options: {
101
142
  command: args.command,
102
143
  timeout: opts.timeout,
103
- stream: opts.timestamps !== undefined ? { timestamps: opts.timestamps } : undefined,
144
+ stream: streamConfig,
104
145
  },
105
146
  orgId,
106
147
  });
@@ -119,7 +160,7 @@ export const execSubcommand = createCommand({
119
160
  const stdoutStreamUrl = execution.stdoutStreamUrl;
120
161
  const stderrStreamUrl = execution.stderrStreamUrl;
121
162
  const streamAbortController = new AbortController();
122
- const streamPromises: Promise<void>[] = [];
163
+ const streamPromises: Promise<{ bytesRead: number; chunks: number }>[] = [];
123
164
  const streamLabels: string[] = [];
124
165
 
125
166
  const isCombinedOutput =
@@ -135,27 +176,20 @@ export const execSubcommand = createCommand({
135
176
  const stdoutChunks: string[] = [];
136
177
  const stderrChunks: string[] = [];
137
178
 
138
- let stdoutWritable: NodeJS.WritableStream;
139
- let stderrWritable: NodeJS.WritableStream;
140
-
141
- if (options.json) {
142
- if (isCombinedOutput) {
143
- stdoutWritable = createCaptureStream((chunk) => outputChunks.push(chunk));
144
- stderrWritable = createCaptureStream((chunk) => outputChunks.push(chunk));
145
- } else {
146
- stdoutWritable = createCaptureStream((chunk) => {
147
- stdoutChunks.push(chunk);
148
- outputChunks.push(chunk);
149
- });
150
- stderrWritable = createCaptureStream((chunk) => {
151
- stderrChunks.push(chunk);
152
- outputChunks.push(chunk);
153
- });
154
- }
155
- } else {
156
- stdoutWritable = process.stdout;
157
- stderrWritable = process.stderr;
158
- }
179
+ const stdoutWritable: NodeJS.WritableStream =
180
+ options.json || stdoutIsNull
181
+ ? createCaptureStream((chunk) => {
182
+ stdoutChunks.push(chunk);
183
+ outputChunks.push(chunk);
184
+ })
185
+ : process.stdout;
186
+ const stderrWritable: NodeJS.WritableStream =
187
+ options.json || stderrIsNull
188
+ ? createCaptureStream((chunk) => {
189
+ stderrChunks.push(chunk);
190
+ outputChunks.push(chunk);
191
+ })
192
+ : process.stderr;
159
193
 
160
194
  if (isCombinedOutput) {
161
195
  logger.debug('[exec] starting combined stream: %s', stdoutStreamUrl);
@@ -166,7 +200,7 @@ export const execSubcommand = createCommand({
166
200
  label: 'combined',
167
201
  raw: true,
168
202
  v2: true,
169
- }).then(() => {})
203
+ })
170
204
  );
171
205
  } else {
172
206
  if (stdoutStreamUrl) {
@@ -178,7 +212,7 @@ export const execSubcommand = createCommand({
178
212
  label: 'stdout',
179
213
  raw: true,
180
214
  v2: true,
181
- }).then(() => {})
215
+ })
182
216
  );
183
217
  }
184
218
 
@@ -191,7 +225,7 @@ export const execSubcommand = createCommand({
191
225
  label: 'stderr',
192
226
  raw: true,
193
227
  v2: true,
194
- }).then(() => {})
228
+ })
195
229
  );
196
230
  }
197
231
  }
@@ -203,13 +237,53 @@ export const execSubcommand = createCommand({
203
237
  );
204
238
 
205
239
  let finalExecution: Awaited<ReturnType<typeof executionGet>>;
240
+ let streamResults: { bytesRead: number; chunks: number }[] | undefined;
206
241
  const pollStart = Date.now();
242
+ const executionWaitAbortController = new AbortController();
207
243
  try {
208
- finalExecution = await executionGet(client, {
244
+ const executionWaitPromise = executionGet(client, {
209
245
  executionId: execution.executionId,
210
246
  orgId,
211
247
  wait: EXECUTION_WAIT_DURATION,
248
+ signal: executionWaitAbortController.signal,
212
249
  });
250
+
251
+ if (streamPromises.length > 0) {
252
+ const winner = await Promise.race([
253
+ executionWaitPromise.then((result) => ({ type: 'execution' as const, result })),
254
+ Promise.all(streamPromises).then((results) => ({
255
+ type: 'streams' as const,
256
+ results,
257
+ })),
258
+ ]);
259
+
260
+ if (winner.type === 'execution') {
261
+ finalExecution = winner.result;
262
+ } else {
263
+ streamResults = winner.results;
264
+ const bytesRead = streamResults.reduce(
265
+ (sum, result) => sum + result.bytesRead,
266
+ 0
267
+ );
268
+ if (bytesRead === 0) {
269
+ logger.debug(
270
+ '[exec] all streams EOF with 0 bytes before executionGet completed — switching to fast terminal poll'
271
+ );
272
+ void executionWaitPromise.catch(() => undefined);
273
+ executionWaitAbortController.abort();
274
+ finalExecution = await waitForTerminalExecutionFast(
275
+ client,
276
+ execution.executionId,
277
+ orgId,
278
+ logger
279
+ );
280
+ } else {
281
+ finalExecution = await executionWaitPromise;
282
+ }
283
+ }
284
+ } else {
285
+ finalExecution = await executionWaitPromise;
286
+ }
213
287
  } catch (err) {
214
288
  streamAbortController.abort();
215
289
  throw err;
@@ -225,17 +299,21 @@ export const execSubcommand = createCommand({
225
299
  logger.debug('[exec] waiting for %d stream(s) to EOF', streamPromises.length);
226
300
  const streamWaitStart = Date.now();
227
301
  let graceTriggered = false;
228
- const streamGrace = setTimeout(() => {
229
- graceTriggered = true;
230
- logger.debug(
231
- '[exec] stream grace period (5s) expired after execution complete — aborting streams'
232
- );
233
- streamAbortController.abort();
234
- }, 5_000);
235
- try {
236
- await Promise.all(streamPromises);
237
- } finally {
238
- clearTimeout(streamGrace);
302
+ if (!streamResults) {
303
+ const streamGraceMs = 500;
304
+ const streamGrace = setTimeout(() => {
305
+ graceTriggered = true;
306
+ logger.debug(
307
+ '[exec] stream grace period (%dms) expired after execution complete — aborting streams',
308
+ streamGraceMs
309
+ );
310
+ streamAbortController.abort();
311
+ }, streamGraceMs);
312
+ try {
313
+ streamResults = await Promise.all(streamPromises);
314
+ } finally {
315
+ clearTimeout(streamGrace);
316
+ }
239
317
  }
240
318
  logger.debug(
241
319
  '[exec] all streams done in %dms (graceTriggered=%s)',
@@ -314,4 +392,41 @@ function createCaptureStream(onChunk: (chunk: string) => void): NodeJS.WritableS
314
392
  });
315
393
  }
316
394
 
395
+ const TERMINAL_EXECUTION_STATUSES = new Set([
396
+ 'completed',
397
+ 'failed',
398
+ 'error',
399
+ 'timeout',
400
+ 'killed',
401
+ 'cancelled',
402
+ ]);
403
+
404
+ async function waitForTerminalExecutionFast(
405
+ client: Parameters<typeof executionGet>[0],
406
+ executionId: string,
407
+ orgId: string,
408
+ logger: Parameters<typeof streamUrlToWritable>[2]
409
+ ) {
410
+ const deadline = Date.now() + EMPTY_STREAM_FAST_TIMEOUT_MS;
411
+ while (Date.now() < deadline) {
412
+ const info = await executionGet(client, { executionId, orgId });
413
+ if (TERMINAL_EXECUTION_STATUSES.has(info.status)) {
414
+ logger.debug(
415
+ '[exec] fast terminal poll observed status=%s for executionId=%s',
416
+ info.status,
417
+ executionId
418
+ );
419
+ return info;
420
+ }
421
+ await new Promise((resolve) => setTimeout(resolve, EMPTY_STREAM_FAST_POLL_MS));
422
+ }
423
+
424
+ logger.debug(
425
+ '[exec] fast terminal poll timed out after %dms for executionId=%s, falling back to long-poll',
426
+ EMPTY_STREAM_FAST_TIMEOUT_MS,
427
+ executionId
428
+ );
429
+ return executionGet(client, { executionId, orgId, wait: EXECUTION_WAIT_DURATION });
430
+ }
431
+
317
432
  export default execSubcommand;
@@ -1,9 +1,9 @@
1
- import { executionList, sandboxResolve } from '@agentuity/server';
1
+ import { executionList } from '@agentuity/server';
2
2
  import { z } from 'zod';
3
3
  import { getCommand } from '../../../../command-prefix';
4
4
  import * as tui from '../../../../tui';
5
5
  import { createCommand } from '../../../../types';
6
- import { createSandboxClient } from '../util';
6
+ import { createSandboxClient, resolveSandboxTarget } from '../util';
7
7
 
8
8
  const ExecutionInfoSchema = z.object({
9
9
  executionId: z.string().describe('Execution ID'),
@@ -54,9 +54,14 @@ export const listSubcommand = createCommand({
54
54
  async handler(ctx) {
55
55
  const { args, opts, options, auth, logger, apiClient } = ctx;
56
56
 
57
- // Resolve sandbox to get region and orgId (like exec.ts does)
58
- const sandboxInfo = await sandboxResolve(apiClient, args.sandboxId);
59
- const { region, orgId: resolvedOrgId } = sandboxInfo;
57
+ const { region, orgId: resolvedOrgId } = await resolveSandboxTarget(
58
+ logger,
59
+ auth,
60
+ apiClient,
61
+ args.sandboxId,
62
+ ctx.config?.name ?? 'production',
63
+ ctx.config
64
+ );
60
65
  const effectiveOrgId = opts?.orgId || resolvedOrgId;
61
66
  const client = createSandboxClient(logger, auth, region);
62
67
 
@@ -1,17 +1,30 @@
1
1
  import { z } from 'zod';
2
- import { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from 'node:fs';
2
+ import {
3
+ readFileSync,
4
+ mkdirSync,
5
+ statSync,
6
+ readdirSync,
7
+ createWriteStream,
8
+ mkdtempSync,
9
+ rmSync,
10
+ } from 'node:fs';
3
11
  import { dirname, resolve, basename, join, relative } from 'node:path';
12
+ import { tmpdir } from 'node:os';
13
+ import { pipeline } from 'node:stream/promises';
14
+ import { Readable } from 'node:stream';
15
+ import * as tar from 'tar';
4
16
  import { createCommand } from '../../../../types';
5
17
  import { toForwardSlash } from '../../../../utils/normalize-path';
6
18
  import * as tui from '../../../../tui';
7
- import { createSandboxClient } from '../util';
19
+ import { createSandboxClient, resolveSandboxTarget } from '../util';
8
20
  import { getCommand } from '../../../../command-prefix';
9
21
  import {
10
22
  sandboxWriteFiles,
11
23
  sandboxReadFile,
12
24
  sandboxExecute,
13
25
  executionGet,
14
- sandboxResolve,
26
+ sandboxDownloadArchive,
27
+ sandboxUploadArchive,
15
28
  type APIClient,
16
29
  } from '@agentuity/server';
17
30
  import type { Logger, FileToWrite } from '@agentuity/core';
@@ -125,9 +138,14 @@ export const cpSubcommand = createCommand({
125
138
 
126
139
  const sandboxId = source.sandboxId ?? destination.sandboxId!;
127
140
 
128
- // Resolve sandbox to get region and orgId using CLI API
129
- const sandboxInfo = await sandboxResolve(apiClient, sandboxId);
130
- const { region, orgId } = sandboxInfo;
141
+ const { region, orgId } = await resolveSandboxTarget(
142
+ logger,
143
+ auth,
144
+ apiClient,
145
+ sandboxId,
146
+ ctx.config?.name ?? 'production',
147
+ ctx.config
148
+ );
131
149
 
132
150
  const client = createSandboxClient(logger, auth, region);
133
151
  const recursive = opts.recursive ?? false;
@@ -337,7 +355,6 @@ async function uploadDirectory(
337
355
  logger.fatal(`Directory is empty: ${localDir}`);
338
356
  }
339
357
 
340
- const files: FileToWrite[] = [];
341
358
  let totalBytes = 0;
342
359
  const effectiveRemotePath = remotePath || basename(localDir);
343
360
  const baseRemotePath = effectiveRemotePath.endsWith('/')
@@ -371,14 +388,23 @@ async function uploadDirectory(
371
388
  }
372
389
 
373
390
  for (const filePath of allFiles) {
374
- const relativePath = toForwardSlash(relative(localDir, filePath));
375
- const targetPath = `${baseRemotePath}/${relativePath}`;
376
- const buffer = readFileSync(filePath);
377
- files.push({ path: targetPath, content: buffer });
378
- totalBytes += buffer.length;
391
+ totalBytes += statSync(filePath).size;
379
392
  }
380
393
 
381
- await sandboxWriteFiles(client, { sandboxId, files, orgId });
394
+ const tempDir = mkdtempSync(join(tmpdir(), 'agentuity-fs-cp-'));
395
+ const archivePath = join(tempDir, 'upload.tar.gz');
396
+ try {
397
+ await createTarGzArchive(localDir, allFiles, archivePath);
398
+ await sandboxUploadArchive(client, {
399
+ sandboxId,
400
+ archive: Bun.file(archivePath).stream(),
401
+ path: baseRemotePath,
402
+ format: 'tar.gz',
403
+ orgId,
404
+ });
405
+ } finally {
406
+ rmSync(tempDir, { recursive: true, force: true });
407
+ }
382
408
 
383
409
  if (!jsonOutput) {
384
410
  tui.success(
@@ -386,7 +412,11 @@ async function uploadDirectory(
386
412
  );
387
413
  }
388
414
 
389
- const implicitDirs = getImplicitDirectories(files.map((f) => f.path));
415
+ const implicitDirs = getImplicitDirectories(
416
+ allFiles.map(
417
+ (filePath) => `${baseRemotePath}/${toForwardSlash(relative(localDir, filePath))}`
418
+ )
419
+ );
390
420
  return {
391
421
  source: localDir,
392
422
  destination: `${sandboxId}:${baseRemotePath}`,
@@ -444,15 +474,6 @@ async function downloadSingleFile(
444
474
  ): Promise<z.infer<typeof SandboxCpResponseSchema>> {
445
475
  const stream = await sandboxReadFile(client, { sandboxId, path: remotePath, orgId });
446
476
 
447
- const chunks: Uint8Array[] = [];
448
- const reader = stream.getReader();
449
- while (true) {
450
- const { done, value } = await reader.read();
451
- if (done) break;
452
- if (value) chunks.push(value);
453
- }
454
- const buffer = Buffer.concat(chunks);
455
-
456
477
  let targetPath = localPath;
457
478
  if (localPath.endsWith('/') || localPath === '.') {
458
479
  targetPath = resolve(localPath, basename(remotePath));
@@ -462,101 +483,70 @@ async function downloadSingleFile(
462
483
 
463
484
  const dir = dirname(targetPath);
464
485
  mkdirSync(dir, { recursive: true });
465
-
466
- writeFileSync(targetPath, buffer);
486
+ await pipeline(
487
+ Readable.fromWeb(stream as unknown as globalThis.ReadableStream<ArrayBufferView>),
488
+ createWriteStream(targetPath)
489
+ );
490
+ const buffer = Bun.file(targetPath);
467
491
 
468
492
  if (!jsonOutput) {
469
- tui.success(`Copied ${sandboxId}:${remotePath} → ${targetPath} (${buffer.length} bytes)`);
493
+ tui.success(`Copied ${sandboxId}:${remotePath} → ${targetPath} (${buffer.size} bytes)`);
470
494
  }
471
495
 
472
496
  return {
473
497
  source: `${sandboxId}:${remotePath}`,
474
498
  destination: targetPath,
475
- bytesTransferred: buffer.length,
499
+ bytesTransferred: buffer.size,
476
500
  filesTransferred: 1,
477
501
  };
478
502
  }
479
503
 
480
504
  async function downloadDirectory(
481
505
  client: APIClient,
482
- logger: Logger,
506
+ _logger: Logger,
483
507
  orgId: string,
484
508
  sandboxId: string,
485
509
  remotePath: string,
486
510
  localPath: string,
487
- timeout: string | undefined,
511
+ _timeout: string | undefined,
488
512
  jsonOutput: boolean
489
513
  ): Promise<z.infer<typeof SandboxCpResponseSchema>> {
490
- const listExecution = await sandboxExecute(client, {
491
- sandboxId,
492
- options: {
493
- command: ['find', remotePath, '-type', 'f'],
494
- timeout,
495
- },
496
- orgId,
497
- });
498
-
499
- const listChunks: Buffer[] = [];
500
- if (listExecution.stdoutStreamUrl) {
501
- await streamToBuffer(listExecution.stdoutStreamUrl, listChunks, logger);
502
- }
503
-
504
- await waitForExecution(client, orgId, listExecution.executionId, logger);
505
-
506
- const fileList = Buffer.concat(listChunks)
507
- .toString('utf-8')
508
- .trim()
509
- .split('\n')
510
- .filter((f) => f.length > 0);
511
-
512
- if (fileList.length === 0) {
513
- logger.fatal(`No files found in directory: ${remotePath}`);
514
- }
515
-
516
- const baseRemotePath = remotePath.endsWith('/') ? remotePath.slice(0, -1) : remotePath;
517
514
  const baseLocalPath = resolve(localPath);
518
- let totalBytes = 0;
519
-
520
- for (const remoteFile of fileList) {
521
- const relativePath = remoteFile.startsWith(baseRemotePath + '/')
522
- ? remoteFile.slice(baseRemotePath.length + 1)
523
- : basename(remoteFile);
524
-
525
- const localFilePath = join(baseLocalPath, relativePath);
526
-
527
- try {
528
- const stream = await sandboxReadFile(client, { sandboxId, path: remoteFile, orgId });
529
- const chunks: Uint8Array[] = [];
530
- const reader = stream.getReader();
531
- while (true) {
532
- const { done, value } = await reader.read();
533
- if (done) break;
534
- if (value) chunks.push(value);
535
- }
536
- const buffer = Buffer.concat(chunks);
537
- totalBytes += buffer.length;
538
-
539
- const dir = dirname(localFilePath);
540
- mkdirSync(dir, { recursive: true });
541
- writeFileSync(localFilePath, buffer);
542
-
543
- if (!jsonOutput) {
544
- logger.info(`Downloaded ${remoteFile} (${buffer.length} bytes)`);
545
- }
546
- } catch (err) {
547
- logger.warn(`Failed to read file: ${remoteFile}, skipping: ${err}`);
548
- continue;
549
- }
515
+ mkdirSync(baseLocalPath, { recursive: true });
516
+ const tempDir = mkdtempSync(join(tmpdir(), 'agentuity-fs-cp-'));
517
+ const archivePath = join(tempDir, 'download.tar.gz');
518
+ try {
519
+ const archiveStream = await sandboxDownloadArchive(client, {
520
+ sandboxId,
521
+ path: remotePath,
522
+ format: 'tar.gz',
523
+ orgId,
524
+ });
525
+ await pipeline(
526
+ Readable.fromWeb(archiveStream as unknown as globalThis.ReadableStream<ArrayBufferView>),
527
+ createWriteStream(archivePath)
528
+ );
529
+ await tar.extract({
530
+ file: archivePath,
531
+ cwd: baseLocalPath,
532
+ preservePaths: false,
533
+ strict: true,
534
+ });
535
+ } finally {
536
+ rmSync(tempDir, { recursive: true, force: true });
550
537
  }
551
538
 
539
+ const fileList = getAllFiles(baseLocalPath);
540
+ const totalBytes = fileList.reduce((sum, filePath) => sum + statSync(filePath).size, 0);
541
+
552
542
  if (!jsonOutput) {
553
543
  tui.success(
554
- `Copied ${sandboxId}:${baseRemotePath} → ${baseLocalPath} (${fileList.length} files, ${totalBytes} bytes)`
544
+ `Copied ${sandboxId}:${remotePath} → ${baseLocalPath} (${fileList.length} files, ${totalBytes} bytes)`
555
545
  );
556
546
  }
557
547
 
558
548
  return {
559
- source: `${sandboxId}:${baseRemotePath}`,
549
+ source: `${sandboxId}:${remotePath}`,
560
550
  destination: baseLocalPath,
561
551
  bytesTransferred: totalBytes,
562
552
  filesTransferred: fileList.length,
@@ -601,42 +591,20 @@ async function waitForExecution(
601
591
  logger.fatal('Execution timed out waiting for completion');
602
592
  }
603
593
 
604
- async function streamToBuffer(url: string, chunks: Buffer[], logger: Logger): Promise<void> {
605
- const maxRetries = 10;
606
- const retryDelay = 200;
607
-
608
- for (let attempt = 0; attempt < maxRetries; attempt++) {
609
- try {
610
- if (attempt > 0) {
611
- logger.debug('stream retry attempt %d', attempt + 1);
612
- await sleep(retryDelay);
613
- }
614
-
615
- const response = await fetch(url);
616
-
617
- if (!response.ok || !response.body) {
618
- continue;
619
- }
620
-
621
- const reader = response.body.getReader();
622
-
623
- while (true) {
624
- const { done, value } = await reader.read();
625
- if (done) {
626
- return;
627
- }
628
-
629
- if (value) {
630
- chunks.push(Buffer.from(value));
631
- }
632
- }
633
- } catch (err) {
634
- if (err instanceof Error && err.name === 'AbortError') {
635
- throw err;
636
- }
637
- logger.debug('stream error: %s', err);
638
- }
639
- }
594
+ async function createTarGzArchive(
595
+ localDir: string,
596
+ allFiles: string[],
597
+ archivePath: string
598
+ ): Promise<void> {
599
+ const relativePaths = allFiles.map((filePath) => toForwardSlash(relative(localDir, filePath)));
600
+ await tar.create(
601
+ {
602
+ gzip: true,
603
+ file: archivePath,
604
+ cwd: localDir,
605
+ },
606
+ relativePaths
607
+ );
640
608
  }
641
609
 
642
610
  function sleep(ms: number): Promise<void> {