@agentuity/cli 0.0.71 → 0.0.73

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 (132) hide show
  1. package/bin/cli.ts +19 -5
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +77 -19
  4. package/dist/cli.js.map +1 -1
  5. package/dist/cmd/auth/api.d.ts +2 -2
  6. package/dist/cmd/auth/api.d.ts.map +1 -1
  7. package/dist/cmd/auth/api.js +15 -14
  8. package/dist/cmd/auth/api.js.map +1 -1
  9. package/dist/cmd/auth/login.d.ts.map +1 -1
  10. package/dist/cmd/auth/login.js +37 -16
  11. package/dist/cmd/auth/login.js.map +1 -1
  12. package/dist/cmd/auth/ssh/api.d.ts.map +1 -1
  13. package/dist/cmd/auth/ssh/api.js +3 -2
  14. package/dist/cmd/auth/ssh/api.js.map +1 -1
  15. package/dist/cmd/build/ast.d.ts.map +1 -1
  16. package/dist/cmd/build/ast.js +56 -8
  17. package/dist/cmd/build/ast.js.map +1 -1
  18. package/dist/cmd/build/bundler.d.ts +1 -2
  19. package/dist/cmd/build/bundler.d.ts.map +1 -1
  20. package/dist/cmd/build/bundler.js +30 -8
  21. package/dist/cmd/build/bundler.js.map +1 -1
  22. package/dist/cmd/build/format-schema.d.ts +6 -0
  23. package/dist/cmd/build/format-schema.d.ts.map +1 -0
  24. package/dist/cmd/build/format-schema.js +60 -0
  25. package/dist/cmd/build/format-schema.js.map +1 -0
  26. package/dist/cmd/build/index.d.ts.map +1 -1
  27. package/dist/cmd/build/index.js +13 -0
  28. package/dist/cmd/build/index.js.map +1 -1
  29. package/dist/cmd/build/plugin.d.ts.map +1 -1
  30. package/dist/cmd/build/plugin.js +72 -2
  31. package/dist/cmd/build/plugin.js.map +1 -1
  32. package/dist/cmd/cloud/db/create.js +2 -2
  33. package/dist/cmd/cloud/db/create.js.map +1 -1
  34. package/dist/cmd/cloud/db/delete.js +2 -2
  35. package/dist/cmd/cloud/db/delete.js.map +1 -1
  36. package/dist/cmd/cloud/db/get.js +2 -2
  37. package/dist/cmd/cloud/db/get.js.map +1 -1
  38. package/dist/cmd/cloud/db/list.js +2 -2
  39. package/dist/cmd/cloud/db/list.js.map +1 -1
  40. package/dist/cmd/cloud/db/logs.js +2 -2
  41. package/dist/cmd/cloud/db/logs.js.map +1 -1
  42. package/dist/cmd/cloud/db/sql.js +2 -2
  43. package/dist/cmd/cloud/db/sql.js.map +1 -1
  44. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  45. package/dist/cmd/cloud/deploy.js +163 -24
  46. package/dist/cmd/cloud/deploy.js.map +1 -1
  47. package/dist/cmd/cloud/deployment/show.d.ts.map +1 -1
  48. package/dist/cmd/cloud/deployment/show.js +34 -10
  49. package/dist/cmd/cloud/deployment/show.js.map +1 -1
  50. package/dist/cmd/cloud/session/get.js +2 -2
  51. package/dist/cmd/cloud/session/get.js.map +1 -1
  52. package/dist/cmd/cloud/session/list.js +2 -2
  53. package/dist/cmd/cloud/session/list.js.map +1 -1
  54. package/dist/cmd/cloud/storage/create.js +2 -2
  55. package/dist/cmd/cloud/storage/create.js.map +1 -1
  56. package/dist/cmd/cloud/storage/delete.js +2 -2
  57. package/dist/cmd/cloud/storage/delete.js.map +1 -1
  58. package/dist/cmd/cloud/storage/download.js +2 -2
  59. package/dist/cmd/cloud/storage/download.js.map +1 -1
  60. package/dist/cmd/cloud/storage/get.js +2 -2
  61. package/dist/cmd/cloud/storage/get.js.map +1 -1
  62. package/dist/cmd/cloud/storage/list.js +2 -2
  63. package/dist/cmd/cloud/storage/list.js.map +1 -1
  64. package/dist/cmd/cloud/storage/upload.js +2 -2
  65. package/dist/cmd/cloud/storage/upload.js.map +1 -1
  66. package/dist/cmd/cloud/thread/delete.js +2 -2
  67. package/dist/cmd/cloud/thread/delete.js.map +1 -1
  68. package/dist/cmd/cloud/thread/get.js +2 -2
  69. package/dist/cmd/cloud/thread/get.js.map +1 -1
  70. package/dist/cmd/cloud/thread/list.js +2 -2
  71. package/dist/cmd/cloud/thread/list.js.map +1 -1
  72. package/dist/cmd/dev/agents.d.ts.map +1 -1
  73. package/dist/cmd/dev/agents.js +2 -2
  74. package/dist/cmd/dev/agents.js.map +1 -1
  75. package/dist/cmd/dev/sync.d.ts.map +1 -1
  76. package/dist/cmd/dev/sync.js +2 -2
  77. package/dist/cmd/dev/sync.js.map +1 -1
  78. package/dist/cmd/project/show.d.ts.map +1 -1
  79. package/dist/cmd/project/show.js +8 -7
  80. package/dist/cmd/project/show.js.map +1 -1
  81. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  82. package/dist/cmd/project/template-flow.js +14 -2
  83. package/dist/cmd/project/template-flow.js.map +1 -1
  84. package/dist/config.d.ts +2 -1
  85. package/dist/config.d.ts.map +1 -1
  86. package/dist/config.js +17 -1
  87. package/dist/config.js.map +1 -1
  88. package/dist/output.d.ts.map +1 -1
  89. package/dist/output.js +5 -1
  90. package/dist/output.js.map +1 -1
  91. package/dist/tui.d.ts +46 -1
  92. package/dist/tui.d.ts.map +1 -1
  93. package/dist/tui.js +217 -39
  94. package/dist/tui.js.map +1 -1
  95. package/dist/types.d.ts +10 -0
  96. package/dist/types.d.ts.map +1 -1
  97. package/package.json +3 -3
  98. package/src/cli.ts +85 -25
  99. package/src/cmd/auth/api.ts +20 -26
  100. package/src/cmd/auth/login.ts +36 -17
  101. package/src/cmd/auth/ssh/api.ts +5 -6
  102. package/src/cmd/build/ast.ts +67 -8
  103. package/src/cmd/build/bundler.ts +37 -9
  104. package/src/cmd/build/format-schema.ts +66 -0
  105. package/src/cmd/build/index.ts +14 -0
  106. package/src/cmd/build/plugin.ts +86 -2
  107. package/src/cmd/cloud/db/create.ts +2 -2
  108. package/src/cmd/cloud/db/delete.ts +2 -2
  109. package/src/cmd/cloud/db/get.ts +2 -2
  110. package/src/cmd/cloud/db/list.ts +2 -2
  111. package/src/cmd/cloud/db/logs.ts +2 -2
  112. package/src/cmd/cloud/db/sql.ts +2 -2
  113. package/src/cmd/cloud/deploy.ts +187 -24
  114. package/src/cmd/cloud/deployment/show.ts +42 -10
  115. package/src/cmd/cloud/session/get.ts +2 -2
  116. package/src/cmd/cloud/session/list.ts +2 -2
  117. package/src/cmd/cloud/storage/create.ts +2 -2
  118. package/src/cmd/cloud/storage/delete.ts +2 -2
  119. package/src/cmd/cloud/storage/download.ts +2 -2
  120. package/src/cmd/cloud/storage/get.ts +2 -2
  121. package/src/cmd/cloud/storage/list.ts +2 -2
  122. package/src/cmd/cloud/storage/upload.ts +2 -2
  123. package/src/cmd/cloud/thread/delete.ts +2 -2
  124. package/src/cmd/cloud/thread/get.ts +2 -2
  125. package/src/cmd/cloud/thread/list.ts +2 -2
  126. package/src/cmd/dev/agents.ts +2 -4
  127. package/src/cmd/dev/sync.ts +6 -8
  128. package/src/cmd/project/show.ts +8 -6
  129. package/src/cmd/project/template-flow.ts +21 -2
  130. package/src/config.ts +19 -6
  131. package/src/output.ts +7 -1
  132. package/src/tui.ts +302 -41
@@ -1,23 +1,25 @@
1
1
  import { z } from 'zod';
2
2
  import { join, resolve } from 'node:path';
3
3
  import { createPublicKey } from 'node:crypto';
4
- import { createReadStream, createWriteStream } from 'node:fs';
4
+ import { createReadStream, createWriteStream, existsSync, mkdirSync, writeFileSync } from 'node:fs';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { createSubcommand } from '../../types';
7
7
  import * as tui from '../../tui';
8
- import { saveProjectDir } from '../../config';
8
+ import { saveProjectDir, getDefaultConfigDir } from '../../config';
9
9
  import { runSteps, stepSuccess, stepSkipped, stepError, Step, ProgressCallback } from '../../steps';
10
10
  import { bundle } from '../build/bundler';
11
- import { loadBuildMetadata } from '../../config';
11
+ import { loadBuildMetadata, getStreamURL } from '../../config';
12
12
  import {
13
13
  projectEnvUpdate,
14
14
  projectDeploymentCreate,
15
15
  projectDeploymentUpdate,
16
16
  projectDeploymentComplete,
17
+ projectDeploymentStatus,
17
18
  type Deployment,
18
19
  type BuildMetadata,
19
20
  type DeploymentInstructions,
20
21
  type DeploymentComplete,
22
+ type DeploymentStatusResult,
21
23
  } from '@agentuity/server';
22
24
  import {
23
25
  findEnvFile,
@@ -30,11 +32,13 @@ import { encryptFIPSKEMDEMStream } from '../../crypto/box';
30
32
  import { getCommand } from '../../command-prefix';
31
33
  import { checkCustomDomainForDNS } from './domain';
32
34
  import { DeployOptionsSchema } from '../../schemas/deploy';
35
+ import { ErrorCode } from '../../errors';
33
36
 
34
37
  const DeployResponseSchema = z.object({
35
38
  success: z.boolean().describe('Whether deployment succeeded'),
36
39
  deploymentId: z.string().describe('Deployment ID'),
37
40
  projectId: z.string().describe('Project ID'),
41
+ logs: z.array(z.string()).optional().describe('The deployment startup logs'),
38
42
  urls: z
39
43
  .object({
40
44
  deployment: z.string().describe('Deployment-specific URL'),
@@ -77,12 +81,14 @@ export const deploySubcommand = createSubcommand({
77
81
  },
78
82
 
79
83
  async handler(ctx) {
80
- const { project, apiClient, projectDir, config, options, opts } = ctx;
84
+ const { project, apiClient, projectDir, config, options, opts, logger } = ctx;
81
85
 
82
86
  let deployment: Deployment | undefined;
83
87
  let build: BuildMetadata | undefined;
84
88
  let instructions: DeploymentInstructions | undefined;
85
89
  let complete: DeploymentComplete | undefined;
90
+ let statusResult: DeploymentStatusResult | undefined;
91
+ const logs: string[] = [];
86
92
 
87
93
  try {
88
94
  await saveProjectDir(projectDir);
@@ -237,7 +243,6 @@ export const deploySubcommand = createSubcommand({
237
243
  if (relative.startsWith('.env')) return false;
238
244
  if (relative.startsWith('.git/')) return false;
239
245
  if (relative.startsWith('.ssh/')) return false;
240
- if (relative.startsWith('node_modules/')) return false;
241
246
  if (relative === '.DS_Store') return false;
242
247
  return true;
243
248
  },
@@ -367,9 +372,174 @@ export const deploySubcommand = createSubcommand({
367
372
  ].filter(Boolean) as Step[],
368
373
  options.logLevel
369
374
  );
370
- tui.success('Your project was deployed!');
371
375
 
372
- if (complete?.publicUrls && deployment) {
376
+ if (!deployment) {
377
+ return {
378
+ success: false,
379
+ deploymentId: '',
380
+ projectId: project.projectId,
381
+ };
382
+ }
383
+
384
+ const streamId = complete?.streamId;
385
+
386
+ // Poll for deployment status with optional log streaming
387
+ const pollInterval = 500;
388
+ const maxAttempts = 600;
389
+ let attempts = 0;
390
+
391
+ if (streamId) {
392
+ // Use progress logger to stream logs while polling
393
+ const streamsUrl = getStreamURL(project.region, config);
394
+
395
+ await tui
396
+ .progress({
397
+ message: 'Deploying project...',
398
+ type: 'logger',
399
+ maxLines: 2,
400
+ clearOnSuccess: true,
401
+ callback: async (log) => {
402
+ // Start log streaming
403
+ const logStreamController = new AbortController();
404
+ const logStreamPromise = (async () => {
405
+ try {
406
+ logger.debug('fetching stream: %s/%s', streamsUrl, streamId);
407
+ const resp = await fetch(`${streamsUrl}/${streamId}`, {
408
+ signal: logStreamController.signal,
409
+ });
410
+ if (!resp.ok || !resp.body) {
411
+ ctx.logger.trace(
412
+ `Failed to connect to warmup log stream: ${resp.status}`
413
+ );
414
+ return;
415
+ }
416
+ const reader = resp.body.getReader();
417
+ const decoder = new TextDecoder();
418
+ let buffer = '';
419
+ while (true) {
420
+ const { done, value } = await reader.read();
421
+ if (done) break;
422
+ buffer += decoder.decode(value, { stream: true });
423
+ const lines = buffer.split('\n');
424
+ buffer = lines.pop() || ''; // Keep incomplete line in buffer
425
+ for (const line of lines) {
426
+ // Strip ISO 8601 timestamp prefix if present
427
+ const message = line.replace(
428
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z\s?/,
429
+ ''
430
+ );
431
+ if (message) {
432
+ logs.push(message);
433
+ log(message);
434
+ }
435
+ }
436
+ }
437
+ } catch (err) {
438
+ if (err instanceof Error && err.name === 'AbortError') {
439
+ return;
440
+ }
441
+ ctx.logger.trace(`Warmup log stream error: ${err}`);
442
+ }
443
+ })();
444
+
445
+ // Poll for deployment status
446
+ while (attempts < maxAttempts) {
447
+ attempts++;
448
+ try {
449
+ statusResult = await projectDeploymentStatus(
450
+ apiClient,
451
+ deployment?.id ?? ''
452
+ );
453
+
454
+ logger.trace('status result: %s', statusResult);
455
+
456
+ if (statusResult.state === 'completed') {
457
+ logStreamController.abort();
458
+ break;
459
+ }
460
+
461
+ if (statusResult.state === 'failed') {
462
+ throw new Error('Deployment failed');
463
+ }
464
+
465
+ await Bun.sleep(pollInterval);
466
+ } catch (err) {
467
+ logStreamController.abort();
468
+ throw err;
469
+ }
470
+ }
471
+
472
+ // Wait for log stream to finish
473
+ await logStreamPromise;
474
+
475
+ if (attempts >= maxAttempts) {
476
+ throw new Error('Deployment timed out');
477
+ }
478
+ },
479
+ })
480
+ .then(() => {
481
+ tui.success('Your project was deployed!');
482
+ })
483
+ .catch((ex) => {
484
+ const exwithmessage = ex as { message: string };
485
+ const msg =
486
+ exwithmessage.message === 'Deployment failed' ? '' : exwithmessage.toString();
487
+ tui.error(`Your deployment failed to start${msg ? `: ${msg}` : ''}`);
488
+ if (logs.length) {
489
+ const logsDir = join(getDefaultConfigDir(), 'logs');
490
+ if (!existsSync(logsDir)) {
491
+ mkdirSync(logsDir, { recursive: true });
492
+ }
493
+ const errorFile = join(logsDir, `${deployment?.id ?? Date.now()}.txt`);
494
+ writeFileSync(errorFile, logs.join('\n'));
495
+ const count = Math.min(logs.length, 10);
496
+ const last = logs.length - count;
497
+ tui.newline();
498
+ tui.warning(`The last ${count} lines of the log:`);
499
+ let offset = last + 1; // we want to show the offset from inside the log starting at 1
500
+ const max = String(logs.length).length;
501
+ for (const _log of logs.slice(last)) {
502
+ console.log(tui.muted(`${offset.toFixed().padEnd(max)} | ${_log}`));
503
+ offset++;
504
+ }
505
+ tui.newline();
506
+ tui.fatal(`The logs were written to ${errorFile}`, ErrorCode.BUILD_FAILED);
507
+ }
508
+ tui.fatal('Deployment failed', ErrorCode.BUILD_FAILED);
509
+ });
510
+ } else {
511
+ // No stream ID - poll without log streaming
512
+ await tui.spinner({
513
+ message: 'Deploying project...',
514
+ type: 'simple',
515
+ clearOnSuccess: true,
516
+ callback: async () => {
517
+ while (attempts < maxAttempts) {
518
+ attempts++;
519
+ statusResult = await projectDeploymentStatus(apiClient, deployment?.id ?? '');
520
+
521
+ if (statusResult.state === 'completed') {
522
+ break;
523
+ }
524
+
525
+ if (statusResult.state === 'failed') {
526
+ throw new Error('Deployment failed');
527
+ }
528
+
529
+ await Bun.sleep(pollInterval);
530
+ }
531
+
532
+ if (attempts >= maxAttempts) {
533
+ throw new Error('Deployment timed out');
534
+ }
535
+ },
536
+ });
537
+
538
+ tui.success('Your project was deployed!');
539
+ }
540
+
541
+ // Show deployment URLs
542
+ if (complete?.publicUrls) {
373
543
  tui.arrow(tui.bold(tui.padRight('Deployment ID:', 17)) + tui.link(deployment.id));
374
544
  if (complete.publicUrls.custom?.length) {
375
545
  for (const url of complete.publicUrls.custom) {
@@ -386,25 +556,18 @@ export const deploySubcommand = createSubcommand({
386
556
  }
387
557
  }
388
558
 
389
- // Return deployment result (if available)
390
- if (deployment && complete?.publicUrls) {
391
- return {
392
- success: true,
393
- deploymentId: deployment.id,
394
- projectId: project.projectId,
395
- urls: {
396
- deployment: complete.publicUrls.deployment,
397
- latest: complete.publicUrls.latest,
398
- custom: complete.publicUrls.custom,
399
- },
400
- };
401
- }
402
-
403
- // Fallback response
404
559
  return {
405
- success: false,
406
- deploymentId: '',
560
+ success: true,
561
+ deploymentId: deployment.id,
407
562
  projectId: project.projectId,
563
+ logs,
564
+ urls: complete?.publicUrls
565
+ ? {
566
+ deployment: complete.publicUrls.deployment,
567
+ latest: complete.publicUrls.latest,
568
+ custom: complete.publicUrls.custom,
569
+ }
570
+ : undefined,
408
571
  };
409
572
  } catch (ex) {
410
573
  tui.fatal(`unexpected error trying to deploy project. ${ex}`);
@@ -15,6 +15,10 @@ const DeploymentShowResponseSchema = z.object({
15
15
  tags: z.array(z.string()).describe('Deployment tags'),
16
16
  customDomains: z.array(z.string()).optional().describe('Custom domains'),
17
17
  cloudRegion: z.string().optional().describe('Cloud region'),
18
+ resourceDb: z.string().nullable().optional().describe('the database name'),
19
+ resourceStorage: z.string().nullable().optional().describe('the storage name'),
20
+ deploymentLogsURL: z.string().nullable().optional().describe('the url to the deployment logs'),
21
+ buildLogsURL: z.string().nullable().optional().describe('the url to the build logs'),
18
22
  metadata: z
19
23
  .object({
20
24
  git: z
@@ -87,27 +91,51 @@ export const showSubcommand = createSubcommand({
87
91
 
88
92
  // Skip TUI output in JSON mode
89
93
  if (!options.json) {
90
- console.log(tui.bold('ID: ') + deployment.id);
91
- console.log(tui.bold('Project: ') + projectId);
92
- console.log(tui.bold('State: ') + (deployment.state || 'unknown'));
93
- console.log(tui.bold('Active: ') + (deployment.active ? 'Yes' : 'No'));
94
- console.log(tui.bold('Created: ') + new Date(deployment.createdAt).toLocaleString());
94
+ const maxWidth = 18;
95
+ console.log(tui.bold('ID:'.padEnd(maxWidth)) + deployment.id);
96
+ console.log(tui.bold('Project:'.padEnd(maxWidth)) + projectId);
97
+ console.log(tui.bold('State:'.padEnd(maxWidth)) + (deployment.state || 'unknown'));
98
+ console.log(tui.bold('Active:'.padEnd(maxWidth)) + (deployment.active ? 'Yes' : 'No'));
99
+ console.log(
100
+ tui.bold('Created:'.padEnd(maxWidth)) +
101
+ new Date(deployment.createdAt).toLocaleString()
102
+ );
95
103
  if (deployment.updatedAt) {
96
104
  console.log(
97
- tui.bold('Updated: ') + new Date(deployment.updatedAt).toLocaleString()
105
+ tui.bold('Updated:'.padEnd(maxWidth)) +
106
+ new Date(deployment.updatedAt).toLocaleString()
98
107
  );
99
108
  }
100
109
  if (deployment.message) {
101
- console.log(tui.bold('Message: ') + deployment.message);
110
+ console.log(tui.bold('Message:'.padEnd(maxWidth)) + deployment.message);
102
111
  }
103
112
  if (deployment.tags.length > 0) {
104
- console.log(tui.bold('Tags: ') + deployment.tags.join(', '));
113
+ console.log(tui.bold('Tags:'.padEnd(maxWidth)) + deployment.tags.join(', '));
105
114
  }
106
115
  if (deployment.customDomains && deployment.customDomains.length > 0) {
107
- console.log(tui.bold('Domains: ') + deployment.customDomains.join(', '));
116
+ console.log(
117
+ tui.bold('Domains:'.padEnd(maxWidth)) + deployment.customDomains.join(', ')
118
+ );
108
119
  }
109
120
  if (deployment.cloudRegion) {
110
- console.log(tui.bold('Region: ') + deployment.cloudRegion);
121
+ console.log(tui.bold('Region:'.padEnd(maxWidth)) + deployment.cloudRegion);
122
+ }
123
+ if (deployment.resourceDb) {
124
+ console.log(tui.bold('Database:'.padEnd(maxWidth)) + deployment.resourceDb);
125
+ }
126
+ if (deployment.resourceStorage) {
127
+ console.log(tui.bold('Storage:'.padEnd(maxWidth)) + deployment.resourceStorage);
128
+ }
129
+ if (deployment.deploymentLogsURL) {
130
+ console.log(
131
+ tui.bold('Deployment Logs:'.padEnd(maxWidth)) +
132
+ tui.link(deployment.deploymentLogsURL)
133
+ );
134
+ }
135
+ if (deployment.buildLogsURL) {
136
+ console.log(
137
+ tui.bold('Build Logs:'.padEnd(maxWidth)) + tui.link(deployment.buildLogsURL)
138
+ );
111
139
  }
112
140
 
113
141
  // Git metadata
@@ -153,6 +181,10 @@ export const showSubcommand = createSubcommand({
153
181
  customDomains: deployment.customDomains ?? undefined,
154
182
  cloudRegion: deployment.cloudRegion ?? undefined,
155
183
  metadata: deployment.metadata ?? undefined,
184
+ resourceDb: deployment.resourceDb ?? undefined,
185
+ resourceStorage: deployment.resourceStorage ?? undefined,
186
+ deploymentLogsURL: deployment.deploymentLogsURL ?? undefined,
187
+ buildLogsURL: deployment.buildLogsURL ?? undefined,
156
188
  };
157
189
  } catch (ex) {
158
190
  tui.fatal(`Failed to show deployment: ${ex}`);
@@ -125,8 +125,8 @@ export const getSubcommand = createSubcommand({
125
125
  response: SessionGetResponseSchema,
126
126
  },
127
127
  async handler(ctx) {
128
- const { config, logger, auth, args, options, region } = ctx;
129
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
128
+ const { logger, auth, args, options, region } = ctx;
129
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
130
130
 
131
131
  try {
132
132
  const enriched = await sessionGet(catalystClient, { id: args.session_id });
@@ -89,8 +89,8 @@ export const listSubcommand = createSubcommand({
89
89
  response: SessionListResponseSchema,
90
90
  },
91
91
  async handler(ctx) {
92
- const { config, logger, auth, project, opts, options, region } = ctx;
93
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
92
+ const { logger, auth, project, opts, options, region } = ctx;
93
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
94
94
 
95
95
  const projectId = opts.projectId || project?.projectId;
96
96
 
@@ -35,7 +35,7 @@ export const createSubcommand = defineSubcommand({
35
35
  },
36
36
 
37
37
  async handler(ctx) {
38
- const { logger, orgId, region, config, auth, options } = ctx;
38
+ const { logger, orgId, region, auth, options } = ctx;
39
39
 
40
40
  // Handle dry-run mode
41
41
  if (isDryRunMode(options)) {
@@ -51,7 +51,7 @@ export const createSubcommand = defineSubcommand({
51
51
  };
52
52
  }
53
53
 
54
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
54
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
55
55
 
56
56
  const created = await tui.spinner({
57
57
  message: `Creating storage in ${region}`,
@@ -49,9 +49,9 @@ export const deleteSubcommand = createSubcommand({
49
49
  },
50
50
 
51
51
  async handler(ctx) {
52
- const { logger, args, opts, config, orgId, region, auth, options } = ctx;
52
+ const { logger, args, opts, orgId, region, auth, options } = ctx;
53
53
 
54
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
54
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
55
55
 
56
56
  const resources = await tui.spinner({
57
57
  message: `Fetching storage for ${orgId} in ${region}`,
@@ -51,9 +51,9 @@ export const downloadSubcommand = createSubcommand({
51
51
  },
52
52
 
53
53
  async handler(ctx) {
54
- const { logger, args, opts, options, orgId, region, config, auth } = ctx;
54
+ const { logger, args, opts, options, orgId, region, auth } = ctx;
55
55
 
56
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
56
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
57
57
 
58
58
  // Fetch bucket credentials
59
59
  const resources = await tui.spinner({
@@ -51,9 +51,9 @@ export const getSubcommand = createSubcommand({
51
51
  },
52
52
 
53
53
  async handler(ctx) {
54
- const { logger, args, opts, options, orgId, region, config, auth } = ctx;
54
+ const { logger, args, opts, options, orgId, region, auth } = ctx;
55
55
 
56
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
56
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
57
57
 
58
58
  const resources = await tui.spinner({
59
59
  message: `Fetching storage bucket ${args.name}`,
@@ -74,9 +74,9 @@ export const listSubcommand = createSubcommand({
74
74
  },
75
75
 
76
76
  async handler(ctx) {
77
- const { logger, args, opts, options, orgId, region, config, auth } = ctx;
77
+ const { logger, args, opts, options, orgId, region, auth } = ctx;
78
78
 
79
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
79
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
80
80
 
81
81
  const resources = await tui.spinner({
82
82
  message: `Fetching storage for ${orgId} in ${region}`,
@@ -49,9 +49,9 @@ export const uploadSubcommand = createSubcommand({
49
49
  },
50
50
 
51
51
  async handler(ctx) {
52
- const { logger, args, opts, options, orgId, region, config, auth } = ctx;
52
+ const { logger, args, opts, options, orgId, region, auth } = ctx;
53
53
 
54
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
54
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
55
55
 
56
56
  // Fetch bucket credentials
57
57
  const resources = await tui.spinner({
@@ -24,8 +24,8 @@ export const deleteSubcommand = createSubcommand({
24
24
  }),
25
25
  },
26
26
  async handler(ctx) {
27
- const { config, logger, auth, args, region } = ctx;
28
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
27
+ const { logger, auth, args, region } = ctx;
28
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
29
29
 
30
30
  try {
31
31
  await threadDelete(catalystClient, { id: args.thread_id });
@@ -37,8 +37,8 @@ export const getSubcommand = createSubcommand({
37
37
  response: ThreadGetResponseSchema,
38
38
  },
39
39
  async handler(ctx) {
40
- const { config, logger, auth, args, options, region } = ctx;
41
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
40
+ const { logger, auth, args, options, region } = ctx;
41
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
42
42
 
43
43
  try {
44
44
  const thread = await threadGet(catalystClient, { id: args.thread_id });
@@ -62,8 +62,8 @@ export const listSubcommand = createSubcommand({
62
62
  response: ThreadListResponseSchema,
63
63
  },
64
64
  async handler(ctx) {
65
- const { config, logger, auth, project, opts, options, region } = ctx;
66
- const catalystClient = getCatalystAPIClient(config, logger, auth, region);
65
+ const { logger, auth, project, opts, options, region } = ctx;
66
+ const catalystClient = getCatalystAPIClient(logger, auth, region);
67
67
 
68
68
  const projectId = opts.projectId || project?.projectId;
69
69
  const orgId = opts.orgId;
@@ -63,14 +63,12 @@ export const agentsSubcommand = createSubcommand({
63
63
  const queryParams = deploymentId ? `?deploymentId=${deploymentId}` : '';
64
64
 
65
65
  const response = options.json
66
- ? await apiClient.request(
67
- 'GET',
66
+ ? await apiClient.get(
68
67
  `/cli/agent/${projectId}${queryParams}`,
69
68
  AgentsResponseSchema
70
69
  )
71
70
  : await tui.spinner('Fetching agents', async () => {
72
- return apiClient.request(
73
- 'GET',
71
+ return apiClient.get(
74
72
  `/cli/agent/${projectId}${queryParams}`,
75
73
  AgentsResponseSchema
76
74
  );
@@ -253,11 +253,10 @@ class DevmodeSyncService implements IDevmodeSyncService {
253
253
  JSON.stringify(payload, null, 2)
254
254
  );
255
255
 
256
- await this.apiClient.request(
257
- 'POST',
256
+ await this.apiClient.post(
258
257
  '/cli/devmode/agent',
259
- z.object({ success: z.boolean() }),
260
- payload
258
+ payload,
259
+ z.object({ success: z.boolean() })
261
260
  );
262
261
  }
263
262
 
@@ -280,11 +279,10 @@ class DevmodeSyncService implements IDevmodeSyncService {
280
279
  JSON.stringify(payload, null, 2)
281
280
  );
282
281
 
283
- await this.apiClient.request(
284
- 'POST',
282
+ await this.apiClient.post(
285
283
  '/cli/devmode/eval',
286
- z.object({ success: z.boolean() }),
287
- payload
284
+ payload,
285
+ z.object({ success: z.boolean() })
288
286
  );
289
287
  }
290
288
  }
@@ -6,8 +6,10 @@ import { getCommand } from '../../command-prefix';
6
6
 
7
7
  const ProjectShowResponseSchema = z.object({
8
8
  id: z.string().describe('Project ID'),
9
+ name: z.string().describe('Project name'),
10
+ description: z.string().nullable().optional().describe('Project description'),
11
+ tags: z.array(z.string()).nullable().optional().describe('Project tags'),
9
12
  orgId: z.string().describe('Organization ID'),
10
- name: z.string().optional().describe('Project name'),
11
13
  secrets: z.record(z.string(), z.string()).optional().describe('Project secrets (masked)'),
12
14
  env: z.record(z.string(), z.string()).optional().describe('Environment variables'),
13
15
  });
@@ -45,16 +47,16 @@ export const showSubcommand = createSubcommand({
45
47
  tui.fatal('Project not found');
46
48
  }
47
49
 
48
- if (options.json) {
49
- console.log(JSON.stringify(project, null, 2));
50
- } else {
51
- tui.table([project], ['id', 'orgId']);
50
+ if (!options.json) {
51
+ tui.table([project], ['id', 'name', 'description', 'tags', 'orgId']);
52
52
  }
53
53
 
54
54
  return {
55
55
  id: project.id,
56
+ name: project.name,
57
+ description: project.description,
58
+ tags: project.tags,
56
59
  orgId: project.orgId,
57
- name: undefined,
58
60
  secrets: project.secrets,
59
61
  env: project.env,
60
62
  };
@@ -177,7 +177,13 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
177
177
  if (initialTemplate) {
178
178
  const found = templates.find((t) => t.id === initialTemplate);
179
179
  if (!found) {
180
- logger.fatal(`Template "${initialTemplate}" not found`, ErrorCode.RESOURCE_NOT_FOUND);
180
+ const availableTemplates = templates
181
+ .map((t) => ` - ${t.id.padEnd(20)} ${t.description}`)
182
+ .join('\n');
183
+ logger.fatal(
184
+ `Template "${initialTemplate}" not found\n\nAvailable templates:\n${availableTemplates}`,
185
+ ErrorCode.RESOURCE_NOT_FOUND
186
+ );
181
187
  return;
182
188
  }
183
189
  selectedTemplate = found;
@@ -232,7 +238,7 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
232
238
 
233
239
  const resourceConfig: ResourcesTypes = Resources.parse({});
234
240
 
235
- if (auth && apiClient && catalystClient && orgId && region) {
241
+ if (auth && apiClient && catalystClient && orgId && region && !skipPrompts) {
236
242
  // Fetch resources for selected org and region using Catalyst API
237
243
  const resources = await tui.spinner({
238
244
  message: 'Fetching resources',
@@ -316,12 +322,25 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
316
322
 
317
323
  const cloudRegion = region ?? process.env.AGENTUITY_REGION ?? 'usc';
318
324
 
325
+ const pkgJsonPath = resolve(dest, 'package.json');
326
+ let pkgJson: { description?: string; keywords?: string[] } = {};
327
+ if (existsSync(pkgJsonPath)) {
328
+ pkgJson = await Bun.file(pkgJsonPath).json();
329
+ }
330
+
331
+ const keywords = Array.isArray(pkgJson.keywords) ? pkgJson.keywords : [];
332
+ const tags = keywords.filter(
333
+ (tag) => tag.toLowerCase() !== 'agentuity' && !tag.toLowerCase().startsWith('agentuity')
334
+ );
335
+
319
336
  await tui.spinner({
320
337
  message: 'Registering your project',
321
338
  clearOnSuccess: true,
322
339
  callback: async () => {
323
340
  const project = await projectCreate(apiClient, {
324
341
  name: projectName,
342
+ description: pkgJson.description,
343
+ tags: tags.length > 0 ? tags : undefined,
325
344
  orgId,
326
345
  cloudRegion,
327
346
  });