@agentuity/cli 0.0.105 → 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 (204) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +93 -21
  3. package/dist/cli.js.map +1 -1
  4. package/dist/cmd/build/ast.d.ts.map +1 -1
  5. package/dist/cmd/build/ast.js +130 -4
  6. package/dist/cmd/build/ast.js.map +1 -1
  7. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  8. package/dist/cmd/build/entry-generator.js +8 -2
  9. package/dist/cmd/build/entry-generator.js.map +1 -1
  10. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  11. package/dist/cmd/build/vite/registry-generator.js +8 -9
  12. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  13. package/dist/cmd/cloud/db/create.d.ts.map +1 -1
  14. package/dist/cmd/cloud/db/create.js +11 -2
  15. package/dist/cmd/cloud/db/create.js.map +1 -1
  16. package/dist/cmd/cloud/db/delete.d.ts.map +1 -1
  17. package/dist/cmd/cloud/db/delete.js +13 -2
  18. package/dist/cmd/cloud/db/delete.js.map +1 -1
  19. package/dist/cmd/cloud/deploy.js +3 -3
  20. package/dist/cmd/cloud/deploy.js.map +1 -1
  21. package/dist/cmd/cloud/env/delete.js +1 -1
  22. package/dist/cmd/cloud/env/delete.js.map +1 -1
  23. package/dist/cmd/cloud/env/import.js +4 -4
  24. package/dist/cmd/cloud/env/import.js.map +1 -1
  25. package/dist/cmd/cloud/env/pull.d.ts.map +1 -1
  26. package/dist/cmd/cloud/env/pull.js +7 -9
  27. package/dist/cmd/cloud/env/pull.js.map +1 -1
  28. package/dist/cmd/cloud/env/push.js +2 -2
  29. package/dist/cmd/cloud/env/push.js.map +1 -1
  30. package/dist/cmd/cloud/env/set.js +3 -3
  31. package/dist/cmd/cloud/env/set.js.map +1 -1
  32. package/dist/cmd/cloud/index.d.ts.map +1 -1
  33. package/dist/cmd/cloud/index.js +2 -0
  34. package/dist/cmd/cloud/index.js.map +1 -1
  35. package/dist/cmd/cloud/sandbox/cp.d.ts +3 -0
  36. package/dist/cmd/cloud/sandbox/cp.d.ts.map +1 -0
  37. package/dist/cmd/cloud/sandbox/cp.js +334 -0
  38. package/dist/cmd/cloud/sandbox/cp.js.map +1 -0
  39. package/dist/cmd/cloud/sandbox/create.d.ts +3 -0
  40. package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -0
  41. package/dist/cmd/cloud/sandbox/create.js +105 -0
  42. package/dist/cmd/cloud/sandbox/create.js.map +1 -0
  43. package/dist/cmd/cloud/sandbox/delete.d.ts +3 -0
  44. package/dist/cmd/cloud/sandbox/delete.d.ts.map +1 -0
  45. package/dist/cmd/cloud/sandbox/delete.js +72 -0
  46. package/dist/cmd/cloud/sandbox/delete.js.map +1 -0
  47. package/dist/cmd/cloud/sandbox/exec.d.ts +3 -0
  48. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -0
  49. package/dist/cmd/cloud/sandbox/exec.js +211 -0
  50. package/dist/cmd/cloud/sandbox/exec.js.map +1 -0
  51. package/dist/cmd/cloud/sandbox/execution/get.d.ts +3 -0
  52. package/dist/cmd/cloud/sandbox/execution/get.d.ts.map +1 -0
  53. package/dist/cmd/cloud/sandbox/execution/get.js +96 -0
  54. package/dist/cmd/cloud/sandbox/execution/get.js.map +1 -0
  55. package/dist/cmd/cloud/sandbox/execution/index.d.ts +3 -0
  56. package/dist/cmd/cloud/sandbox/execution/index.d.ts.map +1 -0
  57. package/dist/cmd/cloud/sandbox/execution/index.js +24 -0
  58. package/dist/cmd/cloud/sandbox/execution/index.js.map +1 -0
  59. package/dist/cmd/cloud/sandbox/execution/list.d.ts +3 -0
  60. package/dist/cmd/cloud/sandbox/execution/list.d.ts.map +1 -0
  61. package/dist/cmd/cloud/sandbox/execution/list.js +100 -0
  62. package/dist/cmd/cloud/sandbox/execution/list.js.map +1 -0
  63. package/dist/cmd/cloud/sandbox/get.d.ts +3 -0
  64. package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -0
  65. package/dist/cmd/cloud/sandbox/get.js +95 -0
  66. package/dist/cmd/cloud/sandbox/get.js.map +1 -0
  67. package/dist/cmd/cloud/sandbox/index.d.ts +3 -0
  68. package/dist/cmd/cloud/sandbox/index.d.ts.map +1 -0
  69. package/dist/cmd/cloud/sandbox/index.js +45 -0
  70. package/dist/cmd/cloud/sandbox/index.js.map +1 -0
  71. package/dist/cmd/cloud/sandbox/list.d.ts +3 -0
  72. package/dist/cmd/cloud/sandbox/list.d.ts.map +1 -0
  73. package/dist/cmd/cloud/sandbox/list.js +120 -0
  74. package/dist/cmd/cloud/sandbox/list.js.map +1 -0
  75. package/dist/cmd/cloud/sandbox/run.d.ts +3 -0
  76. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -0
  77. package/dist/cmd/cloud/sandbox/run.js +152 -0
  78. package/dist/cmd/cloud/sandbox/run.js.map +1 -0
  79. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts +3 -0
  80. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -0
  81. package/dist/cmd/cloud/sandbox/snapshot/create.js +65 -0
  82. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -0
  83. package/dist/cmd/cloud/sandbox/snapshot/delete.d.ts +3 -0
  84. package/dist/cmd/cloud/sandbox/snapshot/delete.d.ts.map +1 -0
  85. package/dist/cmd/cloud/sandbox/snapshot/delete.js +66 -0
  86. package/dist/cmd/cloud/sandbox/snapshot/delete.js.map +1 -0
  87. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts +3 -0
  88. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -0
  89. package/dist/cmd/cloud/sandbox/snapshot/get.js +154 -0
  90. package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -0
  91. package/dist/cmd/cloud/sandbox/snapshot/index.d.ts +3 -0
  92. package/dist/cmd/cloud/sandbox/snapshot/index.d.ts.map +1 -0
  93. package/dist/cmd/cloud/sandbox/snapshot/index.js +27 -0
  94. package/dist/cmd/cloud/sandbox/snapshot/index.js.map +1 -0
  95. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts +3 -0
  96. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -0
  97. package/dist/cmd/cloud/sandbox/snapshot/list.js +83 -0
  98. package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -0
  99. package/dist/cmd/cloud/sandbox/snapshot/tag.d.ts +3 -0
  100. package/dist/cmd/cloud/sandbox/snapshot/tag.d.ts.map +1 -0
  101. package/dist/cmd/cloud/sandbox/snapshot/tag.js +63 -0
  102. package/dist/cmd/cloud/sandbox/snapshot/tag.js.map +1 -0
  103. package/dist/cmd/cloud/sandbox/util.d.ts +15 -0
  104. package/dist/cmd/cloud/sandbox/util.d.ts.map +1 -0
  105. package/dist/cmd/cloud/sandbox/util.js +50 -0
  106. package/dist/cmd/cloud/sandbox/util.js.map +1 -0
  107. package/dist/cmd/cloud/secret/delete.d.ts.map +1 -1
  108. package/dist/cmd/cloud/secret/delete.js +3 -3
  109. package/dist/cmd/cloud/secret/delete.js.map +1 -1
  110. package/dist/cmd/cloud/secret/import.js +6 -6
  111. package/dist/cmd/cloud/secret/import.js.map +1 -1
  112. package/dist/cmd/cloud/secret/index.d.ts.map +1 -1
  113. package/dist/cmd/cloud/secret/index.js +1 -0
  114. package/dist/cmd/cloud/secret/index.js.map +1 -1
  115. package/dist/cmd/cloud/secret/pull.d.ts.map +1 -1
  116. package/dist/cmd/cloud/secret/pull.js +7 -9
  117. package/dist/cmd/cloud/secret/pull.js.map +1 -1
  118. package/dist/cmd/cloud/secret/push.js +3 -3
  119. package/dist/cmd/cloud/secret/push.js.map +1 -1
  120. package/dist/cmd/cloud/secret/set.d.ts.map +1 -1
  121. package/dist/cmd/cloud/secret/set.js +3 -3
  122. package/dist/cmd/cloud/secret/set.js.map +1 -1
  123. package/dist/cmd/cloud/storage/create.d.ts.map +1 -1
  124. package/dist/cmd/cloud/storage/create.js +13 -2
  125. package/dist/cmd/cloud/storage/create.js.map +1 -1
  126. package/dist/cmd/cloud/storage/delete.d.ts.map +1 -1
  127. package/dist/cmd/cloud/storage/delete.js +13 -2
  128. package/dist/cmd/cloud/storage/delete.js.map +1 -1
  129. package/dist/cmd/cloud/stream/list.d.ts.map +1 -1
  130. package/dist/cmd/cloud/stream/list.js +2 -13
  131. package/dist/cmd/cloud/stream/list.js.map +1 -1
  132. package/dist/cmd/dev/index.d.ts.map +1 -1
  133. package/dist/cmd/dev/index.js +1 -0
  134. package/dist/cmd/dev/index.js.map +1 -1
  135. package/dist/cmd/profile/create.d.ts.map +1 -1
  136. package/dist/cmd/profile/create.js +1 -0
  137. package/dist/cmd/profile/create.js.map +1 -1
  138. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  139. package/dist/cmd/project/template-flow.js +27 -10
  140. package/dist/cmd/project/template-flow.js.map +1 -1
  141. package/dist/config.d.ts +0 -2
  142. package/dist/config.d.ts.map +1 -1
  143. package/dist/config.js +3 -0
  144. package/dist/config.js.map +1 -1
  145. package/dist/env-util.d.ts +16 -8
  146. package/dist/env-util.d.ts.map +1 -1
  147. package/dist/env-util.js +46 -18
  148. package/dist/env-util.js.map +1 -1
  149. package/dist/tui.d.ts +20 -3
  150. package/dist/tui.d.ts.map +1 -1
  151. package/dist/tui.js +82 -23
  152. package/dist/tui.js.map +1 -1
  153. package/dist/types.d.ts +18 -4
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/types.js +1 -0
  156. package/dist/types.js.map +1 -1
  157. package/package.json +4 -4
  158. package/src/cli.ts +99 -21
  159. package/src/cmd/build/ast.ts +163 -4
  160. package/src/cmd/build/entry-generator.ts +8 -2
  161. package/src/cmd/build/vite/registry-generator.ts +8 -11
  162. package/src/cmd/cloud/db/create.ts +13 -2
  163. package/src/cmd/cloud/db/delete.ts +15 -2
  164. package/src/cmd/cloud/deploy.ts +3 -3
  165. package/src/cmd/cloud/env/delete.ts +1 -1
  166. package/src/cmd/cloud/env/import.ts +4 -4
  167. package/src/cmd/cloud/env/pull.ts +7 -16
  168. package/src/cmd/cloud/env/push.ts +2 -2
  169. package/src/cmd/cloud/env/set.ts +3 -3
  170. package/src/cmd/cloud/index.ts +2 -0
  171. package/src/cmd/cloud/sandbox/cp.ts +531 -0
  172. package/src/cmd/cloud/sandbox/create.ts +114 -0
  173. package/src/cmd/cloud/sandbox/delete.ts +80 -0
  174. package/src/cmd/cloud/sandbox/exec.ts +254 -0
  175. package/src/cmd/cloud/sandbox/execution/get.ts +106 -0
  176. package/src/cmd/cloud/sandbox/execution/index.ts +25 -0
  177. package/src/cmd/cloud/sandbox/execution/list.ts +111 -0
  178. package/src/cmd/cloud/sandbox/get.ts +104 -0
  179. package/src/cmd/cloud/sandbox/index.ts +46 -0
  180. package/src/cmd/cloud/sandbox/list.ts +129 -0
  181. package/src/cmd/cloud/sandbox/run.ts +170 -0
  182. package/src/cmd/cloud/sandbox/snapshot/create.ts +71 -0
  183. package/src/cmd/cloud/sandbox/snapshot/delete.ts +74 -0
  184. package/src/cmd/cloud/sandbox/snapshot/get.ts +188 -0
  185. package/src/cmd/cloud/sandbox/snapshot/index.ts +28 -0
  186. package/src/cmd/cloud/sandbox/snapshot/list.ts +90 -0
  187. package/src/cmd/cloud/sandbox/snapshot/tag.ts +70 -0
  188. package/src/cmd/cloud/sandbox/util.ts +59 -0
  189. package/src/cmd/cloud/secret/delete.ts +8 -3
  190. package/src/cmd/cloud/secret/import.ts +6 -6
  191. package/src/cmd/cloud/secret/index.ts +1 -0
  192. package/src/cmd/cloud/secret/pull.ts +7 -16
  193. package/src/cmd/cloud/secret/push.ts +3 -3
  194. package/src/cmd/cloud/secret/set.ts +8 -3
  195. package/src/cmd/cloud/storage/create.ts +15 -2
  196. package/src/cmd/cloud/storage/delete.ts +15 -2
  197. package/src/cmd/cloud/stream/list.ts +2 -9
  198. package/src/cmd/dev/index.ts +1 -0
  199. package/src/cmd/profile/create.ts +1 -0
  200. package/src/cmd/project/template-flow.ts +29 -13
  201. package/src/config.ts +3 -0
  202. package/src/env-util.ts +52 -21
  203. package/src/tui.ts +131 -39
  204. package/src/types.ts +18 -16
@@ -0,0 +1,188 @@
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 { snapshotGet, sandboxList } from '@agentuity/server';
7
+ import type { SnapshotFileInfo } from '@agentuity/server';
8
+ import type { SandboxInfo } from '@agentuity/core';
9
+
10
+ const SnapshotFileSchema = z.object({
11
+ path: z.string(),
12
+ size: z.number(),
13
+ });
14
+
15
+ const SandboxInfoSchema = z.object({
16
+ sandboxId: z.string().describe('Sandbox ID'),
17
+ status: z.string().describe('Current status'),
18
+ createdAt: z.string().describe('Creation timestamp'),
19
+ executions: z.number().describe('Number of executions'),
20
+ });
21
+
22
+ const SnapshotGetResponseSchema = z.object({
23
+ snapshotId: z.string().describe('Snapshot ID'),
24
+ sandboxId: z.string().describe('Source sandbox ID'),
25
+ tag: z.string().nullable().optional().describe('Snapshot tag'),
26
+ sizeBytes: z.number().describe('Snapshot size in bytes'),
27
+ fileCount: z.number().describe('Number of files'),
28
+ parentSnapshotId: z.string().nullable().optional().describe('Parent snapshot ID'),
29
+ createdAt: z.string().describe('Creation timestamp'),
30
+ downloadUrl: z.string().optional().describe('Presigned download URL'),
31
+ files: z.array(SnapshotFileSchema).optional().describe('Files in snapshot'),
32
+ sandboxes: z
33
+ .array(SandboxInfoSchema)
34
+ .optional()
35
+ .describe('Attached sandboxes (idle or running)'),
36
+ });
37
+
38
+ export const getSubcommand = createCommand({
39
+ name: 'get',
40
+ aliases: ['info', 'show'],
41
+ description: 'Get snapshot details',
42
+ tags: ['slow', 'requires-auth'],
43
+ requires: { auth: true, region: true, org: true },
44
+ examples: [
45
+ {
46
+ command: getCommand('cloud sandbox snapshot get snp_abc123'),
47
+ description: 'Get details for a snapshot',
48
+ },
49
+ ],
50
+ schema: {
51
+ args: z.object({
52
+ snapshotId: z.string().describe('Snapshot ID'),
53
+ }),
54
+ response: SnapshotGetResponseSchema,
55
+ },
56
+
57
+ async handler(ctx) {
58
+ const { args, options, auth, region, logger, orgId } = ctx;
59
+ const client = createSandboxClient(logger, auth, region);
60
+
61
+ const snapshot = await snapshotGet(client, {
62
+ snapshotId: args.snapshotId,
63
+ orgId,
64
+ });
65
+
66
+ const sandboxesResult = await sandboxList(client, {
67
+ orgId,
68
+ snapshotId: args.snapshotId,
69
+ });
70
+
71
+ const activeSandboxes = sandboxesResult.sandboxes.filter(
72
+ (s) => s.status === 'idle' || s.status === 'running'
73
+ );
74
+
75
+ if (!options.json) {
76
+ tui.info(`Snapshot: ${tui.bold(snapshot.snapshotId)}`);
77
+ console.log(` ${tui.muted('Sandbox:')} ${snapshot.sandboxId}`);
78
+ if (snapshot.tag) {
79
+ console.log(` ${tui.muted('Tag:')} ${snapshot.tag}`);
80
+ }
81
+ console.log(` ${tui.muted('Size:')} ${tui.formatBytes(snapshot.sizeBytes)}`);
82
+ console.log(` ${tui.muted('Files:')} ${snapshot.fileCount}`);
83
+ console.log(` ${tui.muted('Created:')} ${snapshot.createdAt}`);
84
+ if (snapshot.parentSnapshotId) {
85
+ console.log(` ${tui.muted('Parent:')} ${snapshot.parentSnapshotId}`);
86
+ }
87
+
88
+ if (snapshot.files && snapshot.files.length > 0) {
89
+ console.log('');
90
+ tui.info('Files:');
91
+ printFileTree(snapshot.files);
92
+ }
93
+
94
+ if (activeSandboxes.length > 0) {
95
+ console.log('');
96
+ tui.info(`Attached Sandboxes (${activeSandboxes.length}):`);
97
+ printSandboxTree(activeSandboxes);
98
+ }
99
+ }
100
+
101
+ return {
102
+ ...snapshot,
103
+ sandboxes: activeSandboxes.map((s) => ({
104
+ sandboxId: s.sandboxId,
105
+ status: s.status,
106
+ createdAt: s.createdAt,
107
+ executions: s.executions,
108
+ })),
109
+ };
110
+ },
111
+ });
112
+
113
+ interface TreeNode {
114
+ name: string;
115
+ size?: number;
116
+ isFile: boolean;
117
+ children: Map<string, TreeNode>;
118
+ }
119
+
120
+ function buildFileTree(files: SnapshotFileInfo[]): TreeNode {
121
+ const root: TreeNode = { name: '', isFile: false, children: new Map() };
122
+
123
+ for (const file of files) {
124
+ const parts = file.path.split('/');
125
+ let current = root;
126
+
127
+ for (let i = 0; i < parts.length; i++) {
128
+ const part = parts[i];
129
+ if (!current.children.has(part)) {
130
+ current.children.set(part, {
131
+ name: part,
132
+ isFile: i === parts.length - 1,
133
+ children: new Map(),
134
+ });
135
+ }
136
+ current = current.children.get(part)!;
137
+
138
+ if (i === parts.length - 1) {
139
+ current.size = file.size;
140
+ current.isFile = true;
141
+ }
142
+ }
143
+ }
144
+
145
+ return root;
146
+ }
147
+
148
+ function printFileTree(files: SnapshotFileInfo[]): void {
149
+ const tree = buildFileTree(files);
150
+ printTreeNode(tree, ' ');
151
+ }
152
+
153
+ function printTreeNode(node: TreeNode, prefix: string): void {
154
+ const entries = Array.from(node.children.entries()).sort((a, b) => {
155
+ const aIsDir = !a[1].isFile;
156
+ const bIsDir = !b[1].isFile;
157
+ if (aIsDir !== bIsDir) return aIsDir ? -1 : 1;
158
+ return a[0].localeCompare(b[0]);
159
+ });
160
+
161
+ for (let i = 0; i < entries.length; i++) {
162
+ const [, child] = entries[i];
163
+ const isLast = i === entries.length - 1;
164
+ const connector = tui.muted(isLast ? '└── ' : '├── ');
165
+ const sizeStr =
166
+ child.isFile && child.size !== undefined ? ` (${tui.formatBytes(child.size)})` : '';
167
+
168
+ console.log(`${prefix}${connector}${child.name}${sizeStr}`);
169
+
170
+ if (child.children.size > 0) {
171
+ const newPrefix = prefix + (isLast ? ' ' : tui.muted('│ '));
172
+ printTreeNode(child, newPrefix);
173
+ }
174
+ }
175
+ }
176
+
177
+ function printSandboxTree(sandboxes: SandboxInfo[]): void {
178
+ const sorted = [...sandboxes].sort((a, b) => a.sandboxId.localeCompare(b.sandboxId));
179
+ for (let i = 0; i < sorted.length; i++) {
180
+ const sandbox = sorted[i];
181
+ const isLast = i === sorted.length - 1;
182
+ const connector = tui.muted(isLast ? '└── ' : '├── ');
183
+ const statusColor = sandbox.status === 'running' ? tui.success : tui.muted;
184
+ console.log(` ${connector}${sandbox.sandboxId} ${statusColor(`(${sandbox.status})`)}`);
185
+ }
186
+ }
187
+
188
+ export default getSubcommand;
@@ -0,0 +1,28 @@
1
+ import { createCommand } from '../../../../types';
2
+ import { createSubcommand } from './create';
3
+ import { listSubcommand } from './list';
4
+ import { getSubcommand } from './get';
5
+ import { deleteSubcommand } from './delete';
6
+ import { tagSubcommand } from './tag';
7
+ import { getCommand } from '../../../../command-prefix';
8
+
9
+ export const snapshotCommand = createCommand({
10
+ name: 'snapshot',
11
+ aliases: ['snap'],
12
+ description: 'Manage sandbox snapshots',
13
+ tags: ['slow', 'requires-auth'],
14
+ examples: [
15
+ {
16
+ command: getCommand('cloud sandbox snapshot create <sandbox-id>'),
17
+ description: 'Create a snapshot from a sandbox',
18
+ },
19
+ {
20
+ command: getCommand('cloud sandbox snapshot list'),
21
+ description: 'List all snapshots',
22
+ },
23
+ ],
24
+ subcommands: [createSubcommand, listSubcommand, getSubcommand, deleteSubcommand, tagSubcommand],
25
+ requires: { auth: true, region: true, org: true },
26
+ });
27
+
28
+ export default snapshotCommand;
@@ -0,0 +1,90 @@
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 { snapshotList } from '@agentuity/server';
7
+
8
+ const SnapshotInfoSchema = z.object({
9
+ snapshotId: z.string(),
10
+ sandboxId: z.string(),
11
+ tag: z.string().nullable().optional(),
12
+ sizeBytes: z.number(),
13
+ fileCount: z.number(),
14
+ parentSnapshotId: z.string().nullable().optional(),
15
+ createdAt: z.string(),
16
+ });
17
+
18
+ const SnapshotListResponseSchema = z.object({
19
+ snapshots: z.array(SnapshotInfoSchema).describe('List of snapshots'),
20
+ total: z.number().describe('Total number of snapshots'),
21
+ });
22
+
23
+ export const listSubcommand = createCommand({
24
+ name: 'list',
25
+ aliases: ['ls'],
26
+ description: 'List snapshots',
27
+ tags: ['slow', 'requires-auth'],
28
+ requires: { auth: true, region: true, org: true },
29
+ examples: [
30
+ {
31
+ command: getCommand('cloud sandbox snapshot list'),
32
+ description: 'List all snapshots',
33
+ },
34
+ {
35
+ command: getCommand('cloud sandbox snapshot list --sandbox sbx_abc123'),
36
+ description: 'List snapshots for a specific sandbox',
37
+ },
38
+ ],
39
+ schema: {
40
+ options: z.object({
41
+ sandbox: z.string().optional().describe('Filter by sandbox ID'),
42
+ limit: z.number().optional().describe('Maximum number of results'),
43
+ offset: z.number().optional().describe('Offset for pagination'),
44
+ }),
45
+ response: SnapshotListResponseSchema,
46
+ },
47
+
48
+ async handler(ctx) {
49
+ const { opts, options, auth, region, logger, orgId } = ctx;
50
+ const client = createSandboxClient(logger, auth, region);
51
+
52
+ const result = await snapshotList(client, {
53
+ sandboxId: opts.sandbox,
54
+ limit: opts.limit,
55
+ offset: opts.offset,
56
+ orgId,
57
+ });
58
+
59
+ if (!options.json) {
60
+ if (result.snapshots.length === 0) {
61
+ tui.info('No snapshots found');
62
+ } else {
63
+ const tableData = result.snapshots.map((snap) => {
64
+ return {
65
+ ID: snap.snapshotId,
66
+ Tag: snap.tag ?? '-',
67
+ Sandbox: snap.sandboxId,
68
+ Size: tui.formatBytes(snap.sizeBytes),
69
+ Files: snap.fileCount,
70
+ 'Created At': snap.createdAt,
71
+ };
72
+ });
73
+ tui.table(tableData, [
74
+ { name: 'ID', alignment: 'left' },
75
+ { name: 'Tag', alignment: 'left' },
76
+ { name: 'Sandbox', alignment: 'left' },
77
+ { name: 'Size', alignment: 'right' },
78
+ { name: 'Files', alignment: 'right' },
79
+ { name: 'Created At', alignment: 'left' },
80
+ ]);
81
+
82
+ tui.info(`Total: ${result.total} ${tui.plural(result.total, 'snapshot', 'snapshots')}`);
83
+ }
84
+ }
85
+
86
+ return result;
87
+ },
88
+ });
89
+
90
+ export default listSubcommand;
@@ -0,0 +1,70 @@
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 { snapshotTag } from '@agentuity/server';
7
+
8
+ const SnapshotTagResponseSchema = z.object({
9
+ snapshotId: z.string().describe('Snapshot ID'),
10
+ tag: z.string().nullable().optional().describe('New tag'),
11
+ });
12
+
13
+ export const tagSubcommand = createCommand({
14
+ name: 'tag',
15
+ description: 'Add or update a tag on a snapshot',
16
+ tags: ['slow', 'requires-auth'],
17
+ requires: { auth: true, region: true, org: true },
18
+ examples: [
19
+ {
20
+ command: getCommand('cloud sandbox snapshot tag snp_abc123 latest'),
21
+ description: 'Tag a snapshot as "latest"',
22
+ },
23
+ {
24
+ command: getCommand('cloud sandbox snapshot tag snp_abc123 --clear'),
25
+ description: 'Remove a tag from a snapshot',
26
+ },
27
+ ],
28
+ schema: {
29
+ args: z.object({
30
+ snapshotId: z.string().describe('Snapshot ID to tag'),
31
+ tag: z.string().optional().describe('Tag name to apply'),
32
+ }),
33
+ options: z.object({
34
+ clear: z.boolean().optional().describe('Remove the tag from the snapshot'),
35
+ }),
36
+ response: SnapshotTagResponseSchema,
37
+ },
38
+
39
+ async handler(ctx) {
40
+ const { args, opts, options, auth, region, logger, orgId } = ctx;
41
+ const client = createSandboxClient(logger, auth, region);
42
+
43
+ if (!args.tag && !opts.clear) {
44
+ throw new Error('Either provide a tag name or use --clear to remove the tag');
45
+ }
46
+
47
+ const tag = opts.clear ? null : (args.tag ?? null);
48
+
49
+ const snapshot = await snapshotTag(client, {
50
+ snapshotId: args.snapshotId,
51
+ tag,
52
+ orgId,
53
+ });
54
+
55
+ if (!options.json) {
56
+ if (tag) {
57
+ tui.success(`tagged snapshot ${tui.bold(snapshot.snapshotId)} as ${tui.bold(tag)}`);
58
+ } else {
59
+ tui.success(`removed tag from snapshot ${tui.bold(snapshot.snapshotId)}`);
60
+ }
61
+ }
62
+
63
+ return {
64
+ snapshotId: snapshot.snapshotId,
65
+ tag: snapshot.tag,
66
+ };
67
+ },
68
+ });
69
+
70
+ export default tagSubcommand;
@@ -0,0 +1,59 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import type { Logger, FileToWrite } from '@agentuity/core';
4
+ import { APIClient, getServiceUrls } from '@agentuity/server';
5
+ import type { AuthData } from '../../../types';
6
+
7
+ export function createSandboxClient(logger: Logger, auth: AuthData, region: string): APIClient {
8
+ const urls = getServiceUrls(region);
9
+ return new APIClient(urls.catalyst, logger, auth.apiKey);
10
+ }
11
+
12
+ /**
13
+ * Parse --file arguments and read file contents.
14
+ *
15
+ * Formats:
16
+ * - <sandbox-path>:<local-path> - explicit mapping (e.g., script.js:./local/script.js)
17
+ * - <filename> - shorthand, uses same name for both (e.g., script.js -> script.js:./script.js)
18
+ *
19
+ * @returns Array of FileToWrite objects
20
+ */
21
+ export function parseFileArgs(fileArgs: string[] | undefined): FileToWrite[] {
22
+ if (!fileArgs || fileArgs.length === 0) {
23
+ return [];
24
+ }
25
+
26
+ const files: FileToWrite[] = [];
27
+
28
+ for (const arg of fileArgs) {
29
+ let sandboxPath: string;
30
+ let localPath: string;
31
+
32
+ const colonIndex = arg.indexOf(':');
33
+ if (colonIndex === -1) {
34
+ // Shorthand: just filename, use same name for sandbox and look in current dir
35
+ sandboxPath = arg;
36
+ localPath = `./${arg}`;
37
+ } else {
38
+ sandboxPath = arg.slice(0, colonIndex);
39
+ localPath = arg.slice(colonIndex + 1);
40
+
41
+ if (!sandboxPath) {
42
+ throw new Error(`Invalid --file format: "${arg}". Sandbox path cannot be empty`);
43
+ }
44
+ if (!localPath) {
45
+ throw new Error(`Invalid --file format: "${arg}". Local path cannot be empty`);
46
+ }
47
+ }
48
+
49
+ const resolvedPath = resolve(localPath);
50
+ if (!existsSync(resolvedPath)) {
51
+ throw new Error(`File not found: ${localPath} (resolved to ${resolvedPath})`);
52
+ }
53
+
54
+ const content = readFileSync(resolvedPath);
55
+ files.push({ path: sandboxPath, content });
56
+ }
57
+
58
+ return files;
59
+ }
@@ -2,7 +2,12 @@ import { z } from 'zod';
2
2
  import { createSubcommand } from '../../../types';
3
3
  import * as tui from '../../../tui';
4
4
  import { projectEnvDelete } from '@agentuity/server';
5
- import { findEnvFile, readEnvFile, writeEnvFile, filterAgentuitySdkKeys } from '../../../env-util';
5
+ import {
6
+ findExistingEnvFile,
7
+ readEnvFile,
8
+ writeEnvFile,
9
+ filterAgentuitySdkKeys,
10
+ } from '../../../env-util';
6
11
  import { getCommand } from '../../../command-prefix';
7
12
 
8
13
  const SecretDeleteResponseSchema = z.object({
@@ -40,8 +45,8 @@ export const deleteSubcommand = createSubcommand({
40
45
  });
41
46
  });
42
47
 
43
- // Update local .env.production file
44
- const envFilePath = await findEnvFile(projectDir);
48
+ // Update local .env file
49
+ const envFilePath = await findExistingEnvFile(projectDir);
45
50
  const currentEnv = await readEnvFile(envFilePath);
46
51
  delete currentEnv[args.key];
47
52
 
@@ -3,7 +3,7 @@ import { createSubcommand } from '../../../types';
3
3
  import * as tui from '../../../tui';
4
4
  import { projectEnvUpdate } from '@agentuity/server';
5
5
  import {
6
- findEnvFile,
6
+ findExistingEnvFile,
7
7
  readEnvFile,
8
8
  writeEnvFile,
9
9
  filterAgentuitySdkKeys,
@@ -21,7 +21,7 @@ const SecretImportResponseSchema = z.object({
21
21
 
22
22
  export const importSubcommand = createSubcommand({
23
23
  name: 'import',
24
- description: 'Import secrets from a file to cloud and local .env.production',
24
+ description: 'Import secrets from a file to cloud and local .env',
25
25
  tags: [
26
26
  'mutating',
27
27
  'creates-resource',
@@ -33,8 +33,8 @@ export const importSubcommand = createSubcommand({
33
33
  examples: [
34
34
  { command: getCommand('secret import .env.local'), description: 'Run .env.local command' },
35
35
  {
36
- command: getCommand('secret import .env.production.backup'),
37
- description: 'Run .env.production.backup command',
36
+ command: getCommand('secret import .env.backup'),
37
+ description: 'Run .env.backup command',
38
38
  },
39
39
  ],
40
40
  idempotent: false,
@@ -85,8 +85,8 @@ export const importSubcommand = createSubcommand({
85
85
  });
86
86
  });
87
87
 
88
- // Merge with local .env.production file
89
- const localEnvPath = await findEnvFile(projectDir);
88
+ // Merge with local .env file
89
+ const localEnvPath = await findExistingEnvFile(projectDir);
90
90
  const localEnv = await readEnvFile(localEnvPath);
91
91
  const mergedEnv = mergeEnvVars(localEnv, filteredSecrets);
92
92
 
@@ -10,6 +10,7 @@ import { getCommand } from '../../../command-prefix';
10
10
 
11
11
  export const command = createCommand({
12
12
  name: 'secret',
13
+ aliases: ['secrets'],
13
14
  description: 'Manage secrets for your project',
14
15
  tags: ['fast', 'requires-auth', 'requires-project'],
15
16
  examples: [
@@ -3,13 +3,7 @@ import { join } from 'node:path';
3
3
  import { createSubcommand } from '../../../types';
4
4
  import * as tui from '../../../tui';
5
5
  import { projectGet } from '@agentuity/server';
6
- import {
7
- findEnvFile,
8
- findExistingEnvFile,
9
- readEnvFile,
10
- writeEnvFile,
11
- mergeEnvVars,
12
- } from '../../../env-util';
6
+ import { findExistingEnvFile, readEnvFile, writeEnvFile, mergeEnvVars } from '../../../env-util';
13
7
  import { getCommand } from '../../../command-prefix';
14
8
 
15
9
  const SecretPullResponseSchema = z.object({
@@ -21,7 +15,7 @@ const SecretPullResponseSchema = z.object({
21
15
 
22
16
  export const pullSubcommand = createSubcommand({
23
17
  name: 'pull',
24
- description: 'Pull secrets from cloud to local .env.production file',
18
+ description: 'Pull secrets from cloud to local .env file',
25
19
  tags: ['slow', 'requires-auth', 'requires-project'],
26
20
  idempotent: true,
27
21
  examples: [
@@ -45,14 +39,11 @@ export const pullSubcommand = createSubcommand({
45
39
  return projectGet(apiClient, { id: project.projectId, mask: false });
46
40
  });
47
41
 
48
- const cloudSecrets = projectData.secrets || {};
42
+ const cloudSecrets = { ...projectData.env, ...projectData.secrets }; // secret pull with actually do both secrets and env since thats likely what the user would want
49
43
 
50
- // Read current local env from existing file (.env.production or .env)
51
- const existingEnvPath = await findExistingEnvFile(projectDir);
52
- const localEnv = await readEnvFile(existingEnvPath);
53
-
54
- // Target file is always .env.production
55
- const targetEnvPath = await findEnvFile(projectDir);
44
+ // Target file is always .env
45
+ const targetEnvPath = await findExistingEnvFile(projectDir);
46
+ const localEnv = await readEnvFile(targetEnvPath);
56
47
 
57
48
  // Merge: cloud values override local if force=true, otherwise keep local
58
49
  let mergedEnv: Record<string, string>;
@@ -64,7 +55,7 @@ export const pullSubcommand = createSubcommand({
64
55
  mergedEnv = mergeEnvVars(cloudSecrets, localEnv);
65
56
  }
66
57
 
67
- // Write to .env.production (skip AGENTUITY_ keys)
58
+ // Write to .env (skip AGENTUITY_ keys)
68
59
  await writeEnvFile(targetEnvPath, mergedEnv, {
69
60
  skipKeys: Object.keys(mergedEnv).filter((k) => k.startsWith('AGENTUITY_')),
70
61
  });
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { createSubcommand } from '../../../types';
3
3
  import * as tui from '../../../tui';
4
4
  import { projectEnvUpdate } from '@agentuity/server';
5
- import { findEnvFile, readEnvFile, filterAgentuitySdkKeys } from '../../../env-util';
5
+ import { findExistingEnvFile, readEnvFile, filterAgentuitySdkKeys } from '../../../env-util';
6
6
  import { getCommand } from '../../../command-prefix';
7
7
 
8
8
  const SecretPushResponseSchema = z.object({
@@ -13,7 +13,7 @@ const SecretPushResponseSchema = z.object({
13
13
 
14
14
  export const pushSubcommand = createSubcommand({
15
15
  name: 'push',
16
- description: 'Push secrets from local .env.production file to cloud',
16
+ description: 'Push secrets from local .env file to cloud',
17
17
  tags: [
18
18
  'mutating',
19
19
  'updates-resource',
@@ -34,7 +34,7 @@ export const pushSubcommand = createSubcommand({
34
34
  const { apiClient, project, projectDir } = ctx;
35
35
 
36
36
  // Read local env file
37
- const envFilePath = await findEnvFile(projectDir);
37
+ const envFilePath = await findExistingEnvFile(projectDir);
38
38
  const localEnv = await readEnvFile(envFilePath);
39
39
 
40
40
  // Filter out AGENTUITY_ prefixed keys (don't push SDK keys)
@@ -2,7 +2,12 @@ import { z } from 'zod';
2
2
  import { createSubcommand } from '../../../types';
3
3
  import * as tui from '../../../tui';
4
4
  import { projectEnvUpdate } from '@agentuity/server';
5
- import { findEnvFile, readEnvFile, writeEnvFile, filterAgentuitySdkKeys } from '../../../env-util';
5
+ import {
6
+ findExistingEnvFile,
7
+ readEnvFile,
8
+ writeEnvFile,
9
+ filterAgentuitySdkKeys,
10
+ } from '../../../env-util';
6
11
  import { getCommand } from '../../../command-prefix';
7
12
 
8
13
  const SecretSetResponseSchema = z.object({
@@ -51,8 +56,8 @@ export const setSubcommand = createSubcommand({
51
56
  });
52
57
  });
53
58
 
54
- // Update local .env.production file
55
- const envFilePath = await findEnvFile(projectDir);
59
+ // Update local .env file
60
+ const envFilePath = await findExistingEnvFile(projectDir);
56
61
  const currentEnv = await readEnvFile(envFilePath);
57
62
  currentEnv[args.key] = args.value;
58
63
 
@@ -5,6 +5,7 @@ import * as tui from '../../../tui';
5
5
  import { getCatalystAPIClient } from '../../../config';
6
6
  import { getCommand } from '../../../command-prefix';
7
7
  import { isDryRunMode, outputDryRun } from '../../../explain';
8
+ import { addResourceEnvVars } from '../../../env-util';
8
9
 
9
10
  export const createSubcommand = defineSubcommand({
10
11
  name: 'create',
@@ -62,10 +63,22 @@ export const createSubcommand = defineSubcommand({
62
63
  });
63
64
 
64
65
  if (created.length > 0) {
65
- tui.success(`Created storage: ${tui.bold(created[0].name)}`);
66
+ const resource = created[0];
67
+
68
+ // Write environment variables to .env if running inside a project
69
+ if (ctx.projectDir && resource.env && Object.keys(resource.env).length > 0) {
70
+ await addResourceEnvVars(ctx.projectDir, resource.env);
71
+ if (!options.json) {
72
+ tui.info('Environment variables written to .env');
73
+ }
74
+ }
75
+
76
+ if (!options.json) {
77
+ tui.success(`Created storage: ${tui.bold(resource.name)}`);
78
+ }
66
79
  return {
67
80
  success: true,
68
- name: created[0].name,
81
+ name: resource.name,
69
82
  };
70
83
  } else {
71
84
  tui.fatal('Failed to create storage');
@@ -8,6 +8,7 @@ import { getCommand } from '../../../command-prefix';
8
8
  import { isDryRunMode, outputDryRun } from '../../../explain';
9
9
  import { ErrorCode } from '../../../errors';
10
10
  import { createS3Client } from './utils';
11
+ import { removeResourceEnvVars } from '../../../env-util';
11
12
 
12
13
  export const deleteSubcommand = createSubcommand({
13
14
  name: 'delete',
@@ -194,10 +195,22 @@ export const deleteSubcommand = createSubcommand({
194
195
  });
195
196
 
196
197
  if (deleted.length > 0) {
197
- tui.success(`Deleted storage bucket: ${tui.bold(deleted[0])}`);
198
+ const resource = deleted[0];
199
+
200
+ // Remove env vars from .env if running inside a project
201
+ if (ctx.projectDir && resource.env_keys.length > 0) {
202
+ await removeResourceEnvVars(ctx.projectDir, resource.env_keys);
203
+ if (!options.json) {
204
+ tui.info(`Removed ${resource.env_keys.join(', ')} from .env`);
205
+ }
206
+ }
207
+
208
+ if (!options.json) {
209
+ tui.success(`Deleted storage bucket: ${tui.bold(resource.name)}`);
210
+ }
198
211
  return {
199
212
  success: true,
200
- name: deleted[0],
213
+ name: resource.name,
201
214
  };
202
215
  } else {
203
216
  tui.error('Failed to delete storage bucket');