@agentuity/cli 0.0.47 → 0.0.49

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 (262) hide show
  1. package/bin/cli.ts +26 -5
  2. package/dist/banner.d.ts +1 -1
  3. package/dist/banner.d.ts.map +1 -1
  4. package/dist/cli-logger.d.ts +27 -0
  5. package/dist/cli-logger.d.ts.map +1 -0
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cmd/auth/index.d.ts.map +1 -1
  8. package/dist/cmd/auth/login.d.ts.map +1 -1
  9. package/dist/cmd/auth/logout.d.ts.map +1 -1
  10. package/dist/cmd/auth/signup.d.ts.map +1 -1
  11. package/dist/cmd/auth/ssh/add.d.ts.map +1 -1
  12. package/dist/cmd/auth/ssh/delete.d.ts.map +1 -1
  13. package/dist/cmd/auth/ssh/index.d.ts +1 -2
  14. package/dist/cmd/auth/ssh/index.d.ts.map +1 -1
  15. package/dist/cmd/auth/ssh/list.d.ts.map +1 -1
  16. package/dist/cmd/auth/whoami.d.ts.map +1 -1
  17. package/dist/cmd/bundle/ast.d.ts.map +1 -1
  18. package/dist/cmd/bundle/index.d.ts.map +1 -1
  19. package/dist/cmd/bundle/plugin.d.ts.map +1 -1
  20. package/dist/cmd/capabilities/index.d.ts +4 -0
  21. package/dist/cmd/capabilities/index.d.ts.map +1 -0
  22. package/dist/cmd/capabilities/show.d.ts +20 -0
  23. package/dist/cmd/capabilities/show.d.ts.map +1 -0
  24. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  25. package/dist/cmd/cloud/deployment/index.d.ts +2 -0
  26. package/dist/cmd/cloud/deployment/index.d.ts.map +1 -0
  27. package/dist/cmd/cloud/deployment/list.d.ts +2 -0
  28. package/dist/cmd/cloud/deployment/list.d.ts.map +1 -0
  29. package/dist/cmd/cloud/deployment/remove.d.ts +2 -0
  30. package/dist/cmd/cloud/deployment/remove.d.ts.map +1 -0
  31. package/dist/cmd/cloud/deployment/rollback.d.ts +2 -0
  32. package/dist/cmd/cloud/deployment/rollback.d.ts.map +1 -0
  33. package/dist/cmd/cloud/deployment/show.d.ts +2 -0
  34. package/dist/cmd/cloud/deployment/show.d.ts.map +1 -0
  35. package/dist/cmd/cloud/deployment/undeploy.d.ts +2 -0
  36. package/dist/cmd/cloud/deployment/undeploy.d.ts.map +1 -0
  37. package/dist/cmd/cloud/deployment/utils.d.ts +7 -0
  38. package/dist/cmd/cloud/deployment/utils.d.ts.map +1 -0
  39. package/dist/cmd/cloud/domain.d.ts.map +1 -1
  40. package/dist/cmd/cloud/index.d.ts.map +1 -1
  41. package/dist/cmd/cloud/resource/add.d.ts.map +1 -1
  42. package/dist/cmd/cloud/resource/delete.d.ts.map +1 -1
  43. package/dist/cmd/cloud/resource/index.d.ts +1 -2
  44. package/dist/cmd/cloud/resource/index.d.ts.map +1 -1
  45. package/dist/cmd/cloud/resource/list.d.ts.map +1 -1
  46. package/dist/cmd/cloud/scp/download.d.ts.map +1 -1
  47. package/dist/cmd/cloud/scp/index.d.ts +1 -2
  48. package/dist/cmd/cloud/scp/index.d.ts.map +1 -1
  49. package/dist/cmd/cloud/scp/upload.d.ts.map +1 -1
  50. package/dist/cmd/cloud/ssh.d.ts.map +1 -1
  51. package/dist/cmd/dev/index.d.ts.map +1 -1
  52. package/dist/cmd/env/delete.d.ts.map +1 -1
  53. package/dist/cmd/env/get.d.ts.map +1 -1
  54. package/dist/cmd/env/import.d.ts.map +1 -1
  55. package/dist/cmd/env/index.d.ts.map +1 -1
  56. package/dist/cmd/env/list.d.ts.map +1 -1
  57. package/dist/cmd/env/pull.d.ts.map +1 -1
  58. package/dist/cmd/env/push.d.ts.map +1 -1
  59. package/dist/cmd/env/set.d.ts.map +1 -1
  60. package/dist/cmd/index.d.ts.map +1 -1
  61. package/dist/cmd/kv/create-namespace.d.ts +3 -0
  62. package/dist/cmd/kv/create-namespace.d.ts.map +1 -0
  63. package/dist/cmd/kv/delete-namespace.d.ts +3 -0
  64. package/dist/cmd/kv/delete-namespace.d.ts.map +1 -0
  65. package/dist/cmd/kv/delete.d.ts +3 -0
  66. package/dist/cmd/kv/delete.d.ts.map +1 -0
  67. package/dist/cmd/kv/get.d.ts +3 -0
  68. package/dist/cmd/kv/get.d.ts.map +1 -0
  69. package/dist/cmd/kv/index.d.ts +2 -0
  70. package/dist/cmd/kv/index.d.ts.map +1 -0
  71. package/dist/cmd/kv/keys.d.ts +3 -0
  72. package/dist/cmd/kv/keys.d.ts.map +1 -0
  73. package/dist/cmd/kv/list-namespaces.d.ts +3 -0
  74. package/dist/cmd/kv/list-namespaces.d.ts.map +1 -0
  75. package/dist/cmd/kv/repl.d.ts +3 -0
  76. package/dist/cmd/kv/repl.d.ts.map +1 -0
  77. package/dist/cmd/kv/search.d.ts +3 -0
  78. package/dist/cmd/kv/search.d.ts.map +1 -0
  79. package/dist/cmd/kv/set.d.ts +3 -0
  80. package/dist/cmd/kv/set.d.ts.map +1 -0
  81. package/dist/cmd/kv/stats.d.ts +3 -0
  82. package/dist/cmd/kv/stats.d.ts.map +1 -0
  83. package/dist/cmd/kv/util.d.ts +8 -0
  84. package/dist/cmd/kv/util.d.ts.map +1 -0
  85. package/dist/cmd/objectstore/delete-bucket.d.ts +3 -0
  86. package/dist/cmd/objectstore/delete-bucket.d.ts.map +1 -0
  87. package/dist/cmd/objectstore/delete.d.ts +3 -0
  88. package/dist/cmd/objectstore/delete.d.ts.map +1 -0
  89. package/dist/cmd/objectstore/get.d.ts +3 -0
  90. package/dist/cmd/objectstore/get.d.ts.map +1 -0
  91. package/dist/cmd/objectstore/index.d.ts +2 -0
  92. package/dist/cmd/objectstore/index.d.ts.map +1 -0
  93. package/dist/cmd/objectstore/list-buckets.d.ts +3 -0
  94. package/dist/cmd/objectstore/list-buckets.d.ts.map +1 -0
  95. package/dist/cmd/objectstore/list-keys.d.ts +3 -0
  96. package/dist/cmd/objectstore/list-keys.d.ts.map +1 -0
  97. package/dist/cmd/objectstore/put.d.ts +3 -0
  98. package/dist/cmd/objectstore/put.d.ts.map +1 -0
  99. package/dist/cmd/objectstore/repl.d.ts +3 -0
  100. package/dist/cmd/objectstore/repl.d.ts.map +1 -0
  101. package/dist/cmd/objectstore/url.d.ts +3 -0
  102. package/dist/cmd/objectstore/url.d.ts.map +1 -0
  103. package/dist/cmd/objectstore/util.d.ts +8 -0
  104. package/dist/cmd/objectstore/util.d.ts.map +1 -0
  105. package/dist/cmd/profile/create.d.ts.map +1 -1
  106. package/dist/cmd/profile/delete.d.ts.map +1 -1
  107. package/dist/cmd/profile/index.d.ts.map +1 -1
  108. package/dist/cmd/profile/list.d.ts +1 -2
  109. package/dist/cmd/profile/list.d.ts.map +1 -1
  110. package/dist/cmd/profile/show.d.ts.map +1 -1
  111. package/dist/cmd/profile/use.d.ts.map +1 -1
  112. package/dist/cmd/project/create.d.ts.map +1 -1
  113. package/dist/cmd/project/delete.d.ts.map +1 -1
  114. package/dist/cmd/project/index.d.ts.map +1 -1
  115. package/dist/cmd/project/list.d.ts.map +1 -1
  116. package/dist/cmd/project/show.d.ts.map +1 -1
  117. package/dist/cmd/project/template-flow.d.ts +1 -1
  118. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  119. package/dist/cmd/prompt/index.d.ts +4 -0
  120. package/dist/cmd/prompt/index.d.ts.map +1 -0
  121. package/dist/cmd/prompt/llm.d.ts +3 -0
  122. package/dist/cmd/prompt/llm.d.ts.map +1 -0
  123. package/dist/cmd/repl/index.d.ts +3 -0
  124. package/dist/cmd/repl/index.d.ts.map +1 -0
  125. package/dist/cmd/schema/index.d.ts +4 -0
  126. package/dist/cmd/schema/index.d.ts.map +1 -0
  127. package/dist/cmd/schema/show.d.ts +3 -0
  128. package/dist/cmd/schema/show.d.ts.map +1 -0
  129. package/dist/cmd/secret/delete.d.ts.map +1 -1
  130. package/dist/cmd/secret/get.d.ts.map +1 -1
  131. package/dist/cmd/secret/import.d.ts.map +1 -1
  132. package/dist/cmd/secret/index.d.ts.map +1 -1
  133. package/dist/cmd/secret/list.d.ts.map +1 -1
  134. package/dist/cmd/secret/pull.d.ts.map +1 -1
  135. package/dist/cmd/secret/push.d.ts.map +1 -1
  136. package/dist/cmd/secret/set.d.ts.map +1 -1
  137. package/dist/cmd/version/index.d.ts.map +1 -1
  138. package/dist/config.d.ts +1 -1
  139. package/dist/config.d.ts.map +1 -1
  140. package/dist/errors.d.ts +83 -0
  141. package/dist/errors.d.ts.map +1 -0
  142. package/dist/explain.d.ts +47 -0
  143. package/dist/explain.d.ts.map +1 -0
  144. package/dist/index.d.ts +6 -0
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/json.d.ts +3 -0
  147. package/dist/json.d.ts.map +1 -0
  148. package/dist/output.d.ts +136 -0
  149. package/dist/output.d.ts.map +1 -0
  150. package/dist/repl.d.ts +124 -0
  151. package/dist/repl.d.ts.map +1 -0
  152. package/dist/schema-generator.d.ts +67 -0
  153. package/dist/schema-generator.d.ts.map +1 -0
  154. package/dist/tui.d.ts +20 -1
  155. package/dist/tui.d.ts.map +1 -1
  156. package/dist/types.d.ts +65 -6
  157. package/dist/types.d.ts.map +1 -1
  158. package/package.json +10 -4
  159. package/src/banner.ts +7 -7
  160. package/src/cli-logger.ts +80 -0
  161. package/src/cli.ts +186 -54
  162. package/src/cmd/auth/index.ts +1 -0
  163. package/src/cmd/auth/login.ts +7 -2
  164. package/src/cmd/auth/logout.ts +4 -0
  165. package/src/cmd/auth/signup.ts +7 -2
  166. package/src/cmd/auth/ssh/add.ts +20 -3
  167. package/src/cmd/auth/ssh/delete.ts +57 -4
  168. package/src/cmd/auth/ssh/index.ts +4 -3
  169. package/src/cmd/auth/ssh/list.ts +44 -32
  170. package/src/cmd/auth/whoami.ts +32 -21
  171. package/src/cmd/bundle/ast.ts +27 -5
  172. package/src/cmd/bundle/index.ts +20 -0
  173. package/src/cmd/bundle/plugin.ts +36 -12
  174. package/src/cmd/capabilities/index.ts +12 -0
  175. package/src/cmd/capabilities/show.ts +256 -0
  176. package/src/cmd/cloud/deploy.ts +60 -0
  177. package/src/cmd/cloud/deployment/index.ts +20 -0
  178. package/src/cmd/cloud/deployment/list.ts +105 -0
  179. package/src/cmd/cloud/deployment/remove.ts +65 -0
  180. package/src/cmd/cloud/deployment/rollback.ts +87 -0
  181. package/src/cmd/cloud/deployment/show.ts +107 -0
  182. package/src/cmd/cloud/deployment/undeploy.ts +48 -0
  183. package/src/cmd/cloud/deployment/utils.ts +14 -0
  184. package/src/cmd/cloud/domain.ts +3 -2
  185. package/src/cmd/cloud/index.ts +9 -1
  186. package/src/cmd/cloud/resource/add.ts +19 -0
  187. package/src/cmd/cloud/resource/delete.ts +24 -3
  188. package/src/cmd/cloud/resource/index.ts +4 -3
  189. package/src/cmd/cloud/resource/list.ts +36 -10
  190. package/src/cmd/cloud/scp/download.ts +27 -1
  191. package/src/cmd/cloud/scp/index.ts +4 -3
  192. package/src/cmd/cloud/scp/upload.ts +27 -1
  193. package/src/cmd/cloud/ssh.ts +12 -0
  194. package/src/cmd/dev/index.ts +11 -7
  195. package/src/cmd/dev/templates.ts +1 -1
  196. package/src/cmd/env/delete.ts +17 -0
  197. package/src/cmd/env/get.ts +17 -1
  198. package/src/cmd/env/import.ts +47 -3
  199. package/src/cmd/env/index.ts +1 -0
  200. package/src/cmd/env/list.ts +13 -1
  201. package/src/cmd/env/pull.ts +20 -0
  202. package/src/cmd/env/push.ts +33 -1
  203. package/src/cmd/env/set.ts +25 -1
  204. package/src/cmd/index.ts +9 -2
  205. package/src/cmd/kv/create-namespace.ts +45 -0
  206. package/src/cmd/kv/delete-namespace.ts +73 -0
  207. package/src/cmd/kv/delete.ts +51 -0
  208. package/src/cmd/kv/get.ts +65 -0
  209. package/src/cmd/kv/index.ts +31 -0
  210. package/src/cmd/kv/keys.ts +57 -0
  211. package/src/cmd/kv/list-namespaces.ts +43 -0
  212. package/src/cmd/kv/repl.ts +284 -0
  213. package/src/cmd/kv/search.ts +80 -0
  214. package/src/cmd/kv/set.ts +63 -0
  215. package/src/cmd/kv/stats.ts +96 -0
  216. package/src/cmd/kv/util.ts +32 -0
  217. package/src/cmd/objectstore/delete-bucket.ts +72 -0
  218. package/src/cmd/objectstore/delete.ts +59 -0
  219. package/src/cmd/objectstore/get.ts +64 -0
  220. package/src/cmd/objectstore/index.ts +27 -0
  221. package/src/cmd/objectstore/list-buckets.ts +45 -0
  222. package/src/cmd/objectstore/list-keys.ts +60 -0
  223. package/src/cmd/objectstore/put.ts +62 -0
  224. package/src/cmd/objectstore/repl.ts +235 -0
  225. package/src/cmd/objectstore/url.ts +59 -0
  226. package/src/cmd/objectstore/util.ts +28 -0
  227. package/src/cmd/profile/create.ts +61 -6
  228. package/src/cmd/profile/delete.ts +25 -5
  229. package/src/cmd/profile/index.ts +1 -0
  230. package/src/cmd/profile/list.ts +7 -3
  231. package/src/cmd/profile/show.ts +33 -19
  232. package/src/cmd/profile/use.ts +17 -4
  233. package/src/cmd/project/create.ts +31 -0
  234. package/src/cmd/project/delete.ts +24 -2
  235. package/src/cmd/project/index.ts +1 -0
  236. package/src/cmd/project/list.ts +23 -9
  237. package/src/cmd/project/show.ts +27 -8
  238. package/src/cmd/project/template-flow.ts +10 -6
  239. package/src/cmd/prompt/index.ts +12 -0
  240. package/src/cmd/prompt/llm.ts +368 -0
  241. package/src/cmd/repl/index.ts +477 -0
  242. package/src/cmd/schema/index.ts +12 -0
  243. package/src/cmd/schema/show.ts +27 -0
  244. package/src/cmd/secret/delete.ts +17 -0
  245. package/src/cmd/secret/get.ts +20 -1
  246. package/src/cmd/secret/import.ts +45 -2
  247. package/src/cmd/secret/index.ts +1 -0
  248. package/src/cmd/secret/list.ts +10 -1
  249. package/src/cmd/secret/pull.ts +20 -0
  250. package/src/cmd/secret/push.ts +33 -1
  251. package/src/cmd/secret/set.ts +20 -0
  252. package/src/cmd/version/index.ts +15 -2
  253. package/src/config.ts +18 -5
  254. package/src/errors.ts +222 -0
  255. package/src/explain.ts +126 -0
  256. package/src/index.ts +51 -0
  257. package/src/json.ts +28 -0
  258. package/src/output.ts +307 -0
  259. package/src/repl.ts +1517 -0
  260. package/src/schema-generator.ts +389 -0
  261. package/src/tui.ts +136 -13
  262. package/src/types.ts +62 -12
@@ -0,0 +1,64 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../types';
3
+ import * as tui from '../../tui';
4
+ import { tryParseJSON } from '../../json';
5
+ import { createStorageAdapter } from './util';
6
+ import { getCommand } from '../../command-prefix';
7
+
8
+ const ObjectGetResponseSchema = z.object({
9
+ exists: z.boolean().describe('Whether the object exists'),
10
+ data: z.any().optional().describe('Object data (binary)'),
11
+ contentType: z.string().optional().describe('Content type'),
12
+ });
13
+
14
+ export const getSubcommand = createCommand({
15
+ name: 'get',
16
+ description: 'Get an object from the object storage',
17
+ tags: ['read-only', 'slow', 'requires-auth'],
18
+ requires: { auth: true, project: true },
19
+ examples: [
20
+ `${getCommand('objectstore get uploads images/logo.png')} - Download logo image`,
21
+ `${getCommand('objectstore get assets data/export.json')} - Get JSON export`,
22
+ `${getCommand('objectstore get backups db-2024.sql')} - Get database backup`,
23
+ ],
24
+ schema: {
25
+ args: z.object({
26
+ bucket: z.string().min(1).describe('the bucket name'),
27
+ key: z.string().min(1).describe('the key name'),
28
+ }),
29
+ response: ObjectGetResponseSchema,
30
+ },
31
+ idempotent: true,
32
+
33
+ async handler(ctx) {
34
+ const { args } = ctx;
35
+ const storage = await createStorageAdapter(ctx);
36
+ const started = Date.now();
37
+ const res = await storage.get(args.bucket, args.key);
38
+ if (res.exists) {
39
+ if (res.data) {
40
+ if (res.contentType?.includes('json')) {
41
+ const val = tryParseJSON(new TextDecoder().decode(res.data));
42
+ tui.json(val);
43
+ } else if (res.contentType?.includes('text')) {
44
+ console.log(new TextDecoder().decode(res.data));
45
+ } else {
46
+ tui.info(`Read ${res.data.byteLength} bytes (${res.contentType})`);
47
+ }
48
+ tui.success(`retrieved in ${(Date.now() - started).toFixed(1)}ms (${res.contentType})`);
49
+ } else {
50
+ tui.warning(`${args.key} returned empty data for bucket ${args.bucket}`);
51
+ }
52
+ } else {
53
+ tui.warning(`${args.key} does not exist in bucket ${args.bucket}`);
54
+ }
55
+
56
+ return {
57
+ exists: res.exists,
58
+ data: res.data,
59
+ contentType: res.exists ? res.contentType : undefined,
60
+ };
61
+ },
62
+ });
63
+
64
+ export default getSubcommand;
@@ -0,0 +1,27 @@
1
+ import { createCommand } from '../../types';
2
+ import { deleteSubcommand } from './delete';
3
+ import { deleteBucketSubcommand } from './delete-bucket';
4
+ import { getSubcommand } from './get';
5
+ import { listBucketsSubcommand } from './list-buckets';
6
+ import { listKeysSubcommand } from './list-keys';
7
+ import { putSubcommand } from './put';
8
+ import { replSubcommand } from './repl';
9
+ import { urlSubcommand } from './url';
10
+
11
+ export const command = createCommand({
12
+ name: 'objectstore',
13
+ aliases: ['object', 'obj'],
14
+ description: 'Manage object storage for your projects',
15
+ tags: ['read-only', 'fast', 'requires-auth'],
16
+ subcommands: [
17
+ replSubcommand,
18
+ getSubcommand,
19
+ putSubcommand,
20
+ deleteSubcommand,
21
+ urlSubcommand,
22
+ listBucketsSubcommand,
23
+ listKeysSubcommand,
24
+ deleteBucketSubcommand,
25
+ ],
26
+ requires: { auth: true, project: true },
27
+ });
@@ -0,0 +1,45 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../types';
3
+ import * as tui from '../../tui';
4
+ import { createStorageAdapter } from './util';
5
+ import { getCommand } from '../../command-prefix';
6
+
7
+ const BucketListResponseSchema = z.array(
8
+ z.object({
9
+ name: z.string().describe('Bucket name'),
10
+ object_count: z.number().describe('Number of objects in bucket'),
11
+ total_bytes: z.number().describe('Total size in bytes'),
12
+ })
13
+ );
14
+
15
+ export const listBucketsSubcommand = createCommand({
16
+ name: 'list-buckets',
17
+ description: 'List all object storage buckets',
18
+ tags: ['read-only', 'fast', 'requires-auth'],
19
+ requires: { auth: true, project: true },
20
+ schema: {
21
+ response: BucketListResponseSchema,
22
+ },
23
+ idempotent: true,
24
+ examples: [`${getCommand('objectstore list-buckets')} - List all buckets with stats`],
25
+
26
+ async handler(ctx) {
27
+ const storage = await createStorageAdapter(ctx);
28
+ const buckets = await storage.listBuckets();
29
+
30
+ if (buckets.length === 0) {
31
+ tui.info('No buckets found');
32
+ return [];
33
+ }
34
+
35
+ tui.info(`Found ${buckets.length} bucket(s):`);
36
+ for (const bucket of buckets) {
37
+ const sizeMB = (bucket.total_bytes / (1024 * 1024)).toFixed(2);
38
+ tui.info(` ${tui.bold(bucket.name)}: ${bucket.object_count} objects, ${sizeMB} MB`);
39
+ }
40
+
41
+ return buckets;
42
+ },
43
+ });
44
+
45
+ export default listBucketsSubcommand;
@@ -0,0 +1,60 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../types';
3
+ import * as tui from '../../tui';
4
+ import { createStorageAdapter } from './util';
5
+ import { getCommand } from '../../command-prefix';
6
+
7
+ export const listKeysSubcommand = createCommand({
8
+ name: 'list-keys',
9
+ aliases: ['ls', 'list'],
10
+ description: 'List all keys in an object storage bucket',
11
+ tags: ['read-only', 'slow', 'requires-auth'],
12
+ requires: { auth: true, project: true },
13
+ idempotent: true,
14
+ examples: [
15
+ `${getCommand('objectstore list-keys uploads')} - List all uploaded files`,
16
+ `${getCommand('objectstore ls assets')} - List assets (using alias)`,
17
+ `${getCommand('objectstore list backups')} - List all backups`,
18
+ ],
19
+ schema: {
20
+ args: z.object({
21
+ bucket: z.string().min(1),
22
+ }),
23
+ response: z.object({
24
+ bucket: z.string().describe('Bucket name'),
25
+ objects: z
26
+ .array(
27
+ z.object({
28
+ key: z.string().describe('Object key'),
29
+ size: z.number().describe('Object size in bytes'),
30
+ updated_at: z.string().describe('Last update timestamp'),
31
+ })
32
+ )
33
+ .describe('List of objects in the bucket'),
34
+ count: z.number().describe('Number of objects found'),
35
+ }),
36
+ },
37
+
38
+ async handler(ctx) {
39
+ const { args } = ctx;
40
+ const objectStore = await createStorageAdapter(ctx);
41
+
42
+ const objects = await objectStore.listKeys(args.bucket);
43
+
44
+ if (objects.length === 0) {
45
+ tui.info(`No objects found in bucket ${tui.bold(args.bucket)}`);
46
+ return { bucket: args.bucket, objects: [], count: 0 };
47
+ }
48
+
49
+ tui.info(`Found ${objects.length} object(s) in ${tui.bold(args.bucket)}:`);
50
+ for (const obj of objects) {
51
+ const sizeMB = (obj.size / (1024 * 1024)).toFixed(2);
52
+ const date = new Date(obj.updated_at).toLocaleString();
53
+ tui.info(` ${tui.bold(obj.key)}: ${sizeMB} MB, updated ${date}`);
54
+ }
55
+
56
+ return { bucket: args.bucket, objects, count: objects.length };
57
+ },
58
+ });
59
+
60
+ export default listKeysSubcommand;
@@ -0,0 +1,62 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../types';
3
+ import * as tui from '../../tui';
4
+ import { isPossiblyJSON } from '../../json';
5
+ import { createStorageAdapter } from './util';
6
+ import { getCommand } from '../../command-prefix';
7
+
8
+ const ObjectStorePutResponseSchema = z.object({
9
+ success: z.boolean().describe('Whether the operation succeeded'),
10
+ bucket: z.string().describe('Bucket name'),
11
+ key: z.string().describe('Object key'),
12
+ size: z.number().describe('Size in bytes'),
13
+ contentType: z.string().describe('Content type'),
14
+ durationMs: z.number().describe('Operation duration in milliseconds'),
15
+ });
16
+
17
+ export const putSubcommand = createCommand({
18
+ name: 'put',
19
+ description: 'Put an object into the object storage',
20
+ tags: ['mutating', 'creates-resource', 'slow', 'requires-auth'],
21
+ idempotent: true,
22
+ requires: { auth: true, project: true },
23
+ examples: [
24
+ `${getCommand('objectstore put uploads images/logo.png @./logo.png')} - Upload logo from file`,
25
+ `${getCommand('objectstore put assets data/config.json \'{"api":"https://api.example.com"}\'')} - Store JSON config`,
26
+ `${getCommand('objectstore put backups db-2024.sql @~/Downloads/backup.sql --content-type application/sql')} - Upload SQL backup`,
27
+ ],
28
+ schema: {
29
+ args: z.object({
30
+ bucket: z.string().min(1).max(64).describe('the bucket name'),
31
+ key: z.string().min(1).max(64).describe('the key name'),
32
+ value: z.string().min(1).describe('the value'),
33
+ contentType: z.string().optional().describe('an optional content type'),
34
+ }),
35
+ response: ObjectStorePutResponseSchema,
36
+ },
37
+
38
+ async handler(ctx) {
39
+ const { args } = ctx;
40
+ const started = Date.now();
41
+ const storage = await createStorageAdapter(ctx);
42
+ const contentType =
43
+ args.contentType ?? (isPossiblyJSON(args.value) ? 'application/json' : 'text/plain');
44
+ const data = new TextEncoder().encode(args.value);
45
+ await storage.put(args.bucket, args.key, data, {
46
+ contentType,
47
+ });
48
+ const durationMs = Date.now() - started;
49
+ tui.success(`saved in ${durationMs.toFixed(1)}ms (${contentType})`);
50
+
51
+ return {
52
+ success: true,
53
+ bucket: args.bucket,
54
+ key: args.key,
55
+ size: data.length,
56
+ contentType,
57
+ durationMs,
58
+ };
59
+ },
60
+ });
61
+
62
+ export default putSubcommand;
@@ -0,0 +1,235 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../types';
3
+ import { createRepl, type ReplCommand } from '../../repl';
4
+ import { showBanner } from '../../banner';
5
+ import * as tui from '../../tui';
6
+ import { isPossiblyJSON, tryParseJSON } from '../../json';
7
+ import { createStorageAdapter } from './util';
8
+ import { getCommand } from '../../command-prefix';
9
+
10
+ export const replSubcommand = createCommand({
11
+ name: 'repl',
12
+ description: 'Start an interactive repl for working with object storage',
13
+ tags: ['slow', 'requires-auth'],
14
+ idempotent: false,
15
+ requires: { auth: true, project: true },
16
+ examples: [`${getCommand('objectstore repl')} - Start interactive object storage session`],
17
+
18
+ async handler(ctx) {
19
+ showBanner(undefined, true);
20
+ tui.info('Managing object store for project');
21
+ tui.newline();
22
+ console.log(tui.bold('Org:'.padEnd(10, ' ')), ' ', tui.muted(ctx.project.orgId));
23
+ console.log(tui.bold('Project:'.padEnd(10, ' ')), ' ', tui.muted(ctx.project.projectId));
24
+ tui.newline();
25
+
26
+ const storage = await createStorageAdapter(ctx);
27
+
28
+ const commands: ReplCommand[] = [
29
+ {
30
+ name: 'put',
31
+ description: 'Put an object into a bucket',
32
+ schema: {
33
+ args: z.tuple([z.string().min(1), z.string().min(1), z.string().min(1)]),
34
+ argNames: ['bucket', 'key', 'value'],
35
+ },
36
+ handler: async (ctx) => {
37
+ ctx.setProgress('saving');
38
+ const started = Date.now();
39
+ const contentType = isPossiblyJSON(ctx.parsed.args[2]!)
40
+ ? 'application/json'
41
+ : 'text/plain';
42
+ const data = new TextEncoder().encode(ctx.parsed.args[2]!);
43
+ await storage.put(ctx.parsed.args[0]!, ctx.parsed.args[1]!, data, {
44
+ contentType,
45
+ });
46
+ ctx.success(`saved in ${(Date.now() - started).toFixed(1)}ms (${contentType})`);
47
+ },
48
+ },
49
+ {
50
+ name: 'get',
51
+ description: 'Get an object from a bucket',
52
+ schema: {
53
+ args: z.tuple([z.string().min(1), z.string().min(1)]),
54
+ argNames: ['bucket', 'key'],
55
+ },
56
+ handler: async (ctx) => {
57
+ ctx.setProgress('fetching');
58
+ const started = Date.now();
59
+ const res = await storage.get(ctx.parsed.args[0]!, ctx.parsed.args[1]!);
60
+ if (res.exists) {
61
+ if (res.data) {
62
+ if (res.contentType?.includes('json')) {
63
+ const val = tryParseJSON(new TextDecoder().decode(res.data));
64
+ ctx.json(val);
65
+ } else if (res.contentType?.includes('text')) {
66
+ ctx.write(new TextDecoder().decode(res.data));
67
+ } else {
68
+ ctx.info(`Read ${res.data.byteLength} bytes (${res.contentType})`);
69
+ }
70
+ ctx.success(
71
+ `retrieved in ${(Date.now() - started).toFixed(1)}ms (${res.contentType})`
72
+ );
73
+ } else {
74
+ ctx.warning(
75
+ `${ctx.parsed.args[1]!} returned empty data for bucket ${ctx.parsed.args[0]!}`
76
+ );
77
+ }
78
+ } else {
79
+ ctx.warning(
80
+ `${ctx.parsed.args[1]!} does not exist in bucket ${ctx.parsed.args[0]!}`
81
+ );
82
+ }
83
+ },
84
+ },
85
+ {
86
+ name: 'delete',
87
+ aliases: ['rm', 'remove', 'del'],
88
+ description: 'Delete an object from a bucket',
89
+ schema: {
90
+ args: z.tuple([z.string().min(1), z.string().min(1)]),
91
+ argNames: ['bucket', 'key'],
92
+ },
93
+ handler: async (ctx) => {
94
+ ctx.setProgress('deleting');
95
+ const started = Date.now();
96
+ const deleted = await storage.delete(ctx.parsed.args[0]!, ctx.parsed.args[1]!);
97
+ if (deleted) {
98
+ ctx.success(`deleted in ${(Date.now() - started).toFixed(1)}ms`);
99
+ } else {
100
+ ctx.warning(
101
+ `${ctx.parsed.args[1]!} did not exist in bucket ${ctx.parsed.args[0]!}`
102
+ );
103
+ }
104
+ },
105
+ },
106
+ {
107
+ name: 'url',
108
+ aliases: ['publicurl', 'presigned'],
109
+ description: 'Create a public URL for an object',
110
+ schema: {
111
+ args: z.tuple([
112
+ z.string().min(1),
113
+ z.string().min(1),
114
+ z.coerce.number().min(60).optional(),
115
+ ]),
116
+ argNames: ['bucket', 'key', 'expires'],
117
+ },
118
+ handler: async (ctx) => {
119
+ ctx.setProgress('creating url');
120
+ const started = Date.now();
121
+ const expires =
122
+ ctx.parsed.args.length > 2 ? parseInt(ctx.parsed.args[2]!) : undefined;
123
+ const url = await storage.createPublicURL(
124
+ ctx.parsed.args[0]!,
125
+ ctx.parsed.args[1]!,
126
+ expires ? { expiresDuration: expires } : undefined
127
+ );
128
+ ctx.write(url);
129
+ ctx.success(`created in ${(Date.now() - started).toFixed(1)}ms`);
130
+ },
131
+ },
132
+ {
133
+ name: 'list-buckets',
134
+ aliases: ['buckets', 'lb'],
135
+ description: 'List all buckets',
136
+ handler: async (ctx) => {
137
+ ctx.setProgress('listing buckets');
138
+ const started = Date.now();
139
+ const buckets = await storage.listBuckets();
140
+ if (buckets.length === 0) {
141
+ ctx.info('No buckets found');
142
+ } else {
143
+ ctx.info(`Found ${buckets.length} bucket(s):`);
144
+ for (const bucket of buckets) {
145
+ const sizeMB = (bucket.total_bytes / (1024 * 1024)).toFixed(2);
146
+ ctx.write(
147
+ ` ${tui.bold(bucket.name)}: ${bucket.object_count} objects, ${sizeMB} MB`
148
+ );
149
+ }
150
+ }
151
+ ctx.success(`retrieved in ${(Date.now() - started).toFixed(1)}ms`);
152
+ },
153
+ },
154
+ {
155
+ name: 'list-keys',
156
+ aliases: ['keys', 'ls'],
157
+ description: 'List all keys in a bucket',
158
+ schema: {
159
+ args: z.tuple([z.string().min(1)]),
160
+ argNames: ['bucket'],
161
+ },
162
+ handler: async (ctx) => {
163
+ ctx.setProgress('listing keys');
164
+ const started = Date.now();
165
+ const objects = await storage.listKeys(ctx.parsed.args[0]!);
166
+ if (objects.length === 0) {
167
+ ctx.info(`No objects found in bucket ${tui.bold(ctx.parsed.args[0]!)}`);
168
+ } else {
169
+ ctx.info(
170
+ `Found ${objects.length} object(s) in ${tui.bold(ctx.parsed.args[0]!)}:`
171
+ );
172
+ for (const obj of objects) {
173
+ const sizeMB = (obj.size / (1024 * 1024)).toFixed(2);
174
+ const date = new Date(obj.updated_at).toLocaleString();
175
+ ctx.write(` ${tui.bold(obj.key)}: ${sizeMB} MB, updated ${date}`);
176
+ }
177
+ }
178
+ ctx.success(`retrieved in ${(Date.now() - started).toFixed(1)}ms`);
179
+ },
180
+ },
181
+ {
182
+ name: 'delete-bucket',
183
+ aliases: ['rmbucket', 'delbucket'],
184
+ description: 'Delete a bucket and all its contents',
185
+ schema: {
186
+ args: z.tuple([z.string().min(1)]),
187
+ argNames: ['bucket'],
188
+ },
189
+ handler: async (ctx) => {
190
+ ctx.warning(
191
+ `This will delete bucket ${tui.bold(ctx.parsed.args[0]!)} and ALL its contents.`
192
+ );
193
+ const confirm = await new Promise<boolean>((resolve) => {
194
+ process.stdout.write('Are you sure? (yes/no): ');
195
+ process.stdin.once('data', (data) => {
196
+ const answer = data.toString().trim().toLowerCase();
197
+ resolve(answer === 'yes' || answer === 'y');
198
+ });
199
+ });
200
+ if (!confirm) {
201
+ ctx.info('Cancelled');
202
+ return;
203
+ }
204
+ ctx.setProgress('deleting bucket');
205
+ const started = Date.now();
206
+ const deleted = await storage.deleteBucket(ctx.parsed.args[0]!);
207
+ if (deleted) {
208
+ ctx.success(`deleted in ${(Date.now() - started).toFixed(1)}ms`);
209
+ } else {
210
+ ctx.warning(`Bucket ${tui.bold(ctx.parsed.args[0]!)} not found`);
211
+ }
212
+ },
213
+ },
214
+ {
215
+ name: 'exit',
216
+ aliases: ['quit'],
217
+ description: 'Exit the repl',
218
+ handler: async (ctx) => {
219
+ return ctx.exit();
220
+ },
221
+ },
222
+ ];
223
+
224
+ // Start the REPL
225
+ await createRepl({
226
+ name: 'objectstore',
227
+ prompt: '> ',
228
+ welcome: tui.muted('Type "help" or / for available commands.'),
229
+ exitMessage: 'Goodbye!',
230
+ commands,
231
+ });
232
+ },
233
+ });
234
+
235
+ export default replSubcommand;
@@ -0,0 +1,59 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../types';
3
+ import * as tui from '../../tui';
4
+ import { createStorageAdapter } from './util';
5
+ import { getCommand } from '../../command-prefix';
6
+
7
+ const ObjectStoreURLResponseSchema = z.object({
8
+ success: z.boolean().describe('Whether the operation succeeded'),
9
+ bucket: z.string().describe('Bucket name'),
10
+ key: z.string().describe('Object key'),
11
+ url: z.string().describe('Public or presigned URL'),
12
+ expires: z.number().optional().describe('URL expiration time in seconds'),
13
+ durationMs: z.number().describe('Operation duration in milliseconds'),
14
+ });
15
+
16
+ export const urlSubcommand = createCommand({
17
+ name: 'url',
18
+ aliases: ['publicurl', 'presigned'],
19
+ description: 'Create a public URL for an object',
20
+ tags: ['read-only', 'fast', 'requires-auth'],
21
+ requires: { auth: true, project: true },
22
+ idempotent: true,
23
+ examples: [
24
+ `${getCommand('objectstore url uploads images/logo.png')} - Get public URL for logo`,
25
+ `${getCommand('objectstore url assets data/export.json --expires 3600')} - Get 1h temporary URL`,
26
+ `${getCommand('objectstore presigned backups db-2024.sql --expires 300')} - Get 5m presigned URL`,
27
+ ],
28
+ schema: {
29
+ args: z.object({
30
+ bucket: z.string().min(1).describe('the bucket name'),
31
+ key: z.string().min(1).describe('the key name'),
32
+ expires: z.coerce.number().min(60).optional().describe('the expiration in seconds'),
33
+ }),
34
+ response: ObjectStoreURLResponseSchema,
35
+ },
36
+
37
+ async handler(ctx) {
38
+ const { args } = ctx;
39
+ const started = Date.now();
40
+ const storage = await createStorageAdapter(ctx);
41
+ const url = await storage.createPublicURL(args.bucket, args.key, {
42
+ expiresDuration: args.expires,
43
+ });
44
+ const durationMs = Date.now() - started;
45
+ console.log(url);
46
+ tui.success(`created in ${durationMs.toFixed(1)}ms`);
47
+
48
+ return {
49
+ success: true,
50
+ bucket: args.bucket,
51
+ key: args.key,
52
+ url,
53
+ expires: args.expires,
54
+ durationMs,
55
+ };
56
+ },
57
+ });
58
+
59
+ export default urlSubcommand;
@@ -0,0 +1,28 @@
1
+ import { Logger, ObjectStorageService } from '@agentuity/core';
2
+ import { createServerFetchAdapter } from '@agentuity/server';
3
+ import { loadProjectSDKKey } from '../../config';
4
+ import type { Config } from '../../types';
5
+ import * as tui from '../../tui';
6
+
7
+ export async function createStorageAdapter(ctx: {
8
+ logger: Logger;
9
+ projectDir: string;
10
+ config: Config | null;
11
+ }) {
12
+ const sdkKey = await loadProjectSDKKey(ctx.projectDir);
13
+ if (!sdkKey) {
14
+ tui.fatal(`Couldn't find the AGENTUITY_SDK_KEY in ${ctx.projectDir} .env file`);
15
+ }
16
+
17
+ const adapter = createServerFetchAdapter(
18
+ {
19
+ headers: {
20
+ Authorization: `Bearer ${sdkKey}`,
21
+ },
22
+ },
23
+ ctx.logger
24
+ );
25
+
26
+ const baseUrl = ctx.config?.overrides?.object_url ?? 'https://catalyst.agentuity.cloud';
27
+ return new ObjectStorageService(baseUrl, adapter);
28
+ }
@@ -1,21 +1,33 @@
1
- import { createSubcommand } from '../../types';
1
+ import { join } from 'node:path';
2
+ import { writeFile, readdir } from 'node:fs/promises';
3
+ import { Config, createSubcommand } from '../../types';
2
4
  import { z } from 'zod';
3
5
  import {
4
6
  fetchProfiles,
5
7
  getDefaultConfigDir,
6
8
  ensureConfigDir,
7
9
  generateYAMLTemplate,
10
+ loadConfig,
11
+ saveConfig,
12
+ saveProfile,
8
13
  } from '../../config';
9
- import { join } from 'node:path';
10
- import { writeFile } from 'node:fs/promises';
11
14
  import * as tui from '../../tui';
15
+ import { getCommand } from '../../command-prefix';
16
+ import { ErrorCode } from '../../errors';
12
17
 
13
18
  const PROFILE_NAME_REGEX = /^[\w_-]{3,}$/;
14
19
 
15
20
  export const createCommand = createSubcommand({
16
21
  name: 'create',
17
22
  description: 'Create a new configuration profile',
23
+ tags: ['mutating', 'creates-resource', 'fast'],
18
24
  aliases: ['new'],
25
+ idempotent: false,
26
+ examples: [
27
+ getCommand('profile create production'),
28
+ getCommand('profile create staging --switch'),
29
+ getCommand('profile create development'),
30
+ ],
19
31
  schema: {
20
32
  args: z
21
33
  .object({
@@ -26,17 +38,28 @@ export const createCommand = createSubcommand({
26
38
  .describe('The name of the profile to create'),
27
39
  })
28
40
  .describe('Profile creation arguments'),
41
+ options: z.object({
42
+ switch: z.boolean().optional().describe('switch to this profile (if more than one)'),
43
+ }),
44
+ response: z.object({
45
+ success: z.boolean().describe('Whether creation succeeded'),
46
+ name: z.string().describe('Profile name'),
47
+ path: z.string().describe('Profile file path'),
48
+ }),
29
49
  },
30
50
 
31
51
  async handler(ctx) {
32
- const { logger, args } = ctx;
52
+ const { logger, args, opts } = ctx;
33
53
  const { name } = args;
34
54
 
35
55
  const profiles = await fetchProfiles();
36
56
  const existing = profiles.find((p) => p.name === name);
37
57
 
38
58
  if (existing) {
39
- return logger.fatal(`Profile "${name}" already exists at ${existing.filename}`);
59
+ return logger.fatal(
60
+ `Profile "${name}" already exists at ${existing.filename}`,
61
+ ErrorCode.RESOURCE_ALREADY_EXISTS
62
+ );
40
63
  }
41
64
 
42
65
  await ensureConfigDir();
@@ -47,11 +70,43 @@ export const createCommand = createSubcommand({
47
70
 
48
71
  try {
49
72
  await writeFile(filename, template, { flag: 'wx', mode: 0o600 });
73
+ if (name === 'local') {
74
+ // if we're creating a local profile, go ahead and fill it out for the dev to make it easier to get started
75
+ const localConfig = (await loadConfig(filename)) as Config;
76
+ localConfig.overrides = {
77
+ api_url: 'https://api.agentuity.io',
78
+ app_url: 'https://app.agentuity.io',
79
+ transport_url: 'https://catalyst.agentuity.io',
80
+ stream_url: 'https://streams.agentuity.io',
81
+ kv_url: 'https://catalyst.agentuity.io',
82
+ object_url: 'https://catalyst.agentuity.io',
83
+ vector_url: 'https://catalyst.agentuity.io',
84
+ catalyst_url: 'https://catalyst.agentuity.io',
85
+ ion_url: 'https://ion.agentuity.io',
86
+ gravity_url: 'grpc://gravity.agentuity.io:8443',
87
+ };
88
+ await saveConfig(localConfig, filename);
89
+ }
90
+
91
+ const files = await readdir(configDir);
92
+ if (opts?.switch || files.length === 1) {
93
+ await saveProfile(filename);
94
+ }
95
+
50
96
  tui.success(`Created profile "${name}" at ${filename}`);
97
+
98
+ return {
99
+ success: true,
100
+ name,
101
+ path: filename,
102
+ };
51
103
  } catch (error) {
52
104
  const message = error instanceof Error ? error.message : String(error);
53
105
  const stack = error instanceof Error ? error.stack : undefined;
54
- logger.fatal(`Failed to create profile: ${message}${stack ? `\n${stack}` : ''}`);
106
+ logger.fatal(
107
+ `Failed to create profile: ${message}${stack ? `\n${stack}` : ''}`,
108
+ ErrorCode.INTERNAL_ERROR
109
+ );
55
110
  }
56
111
  },
57
112
  });