@agentuity/cli 0.1.16 → 0.1.18

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 (185) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +3 -1
  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 +68 -2
  6. package/dist/cmd/build/ast.js.map +1 -1
  7. package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
  8. package/dist/cmd/build/vite/registry-generator.js +112 -23
  9. package/dist/cmd/build/vite/registry-generator.js.map +1 -1
  10. package/dist/cmd/build/vite/route-discovery.d.ts +4 -0
  11. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  12. package/dist/cmd/build/vite/route-discovery.js +4 -0
  13. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  14. package/dist/cmd/cloud/env/delete.d.ts.map +1 -1
  15. package/dist/cmd/cloud/env/delete.js +8 -2
  16. package/dist/cmd/cloud/env/delete.js.map +1 -1
  17. package/dist/cmd/cloud/env/get.d.ts.map +1 -1
  18. package/dist/cmd/cloud/env/get.js +4 -1
  19. package/dist/cmd/cloud/env/get.js.map +1 -1
  20. package/dist/cmd/cloud/env/import.d.ts.map +1 -1
  21. package/dist/cmd/cloud/env/import.js +5 -8
  22. package/dist/cmd/cloud/env/import.js.map +1 -1
  23. package/dist/cmd/cloud/env/list.d.ts.map +1 -1
  24. package/dist/cmd/cloud/env/list.js +11 -6
  25. package/dist/cmd/cloud/env/list.js.map +1 -1
  26. package/dist/cmd/cloud/env/pull.d.ts.map +1 -1
  27. package/dist/cmd/cloud/env/pull.js.map +1 -1
  28. package/dist/cmd/cloud/env/push.d.ts.map +1 -1
  29. package/dist/cmd/cloud/env/push.js +1 -7
  30. package/dist/cmd/cloud/env/push.js.map +1 -1
  31. package/dist/cmd/cloud/env/set.d.ts.map +1 -1
  32. package/dist/cmd/cloud/env/set.js +4 -1
  33. package/dist/cmd/cloud/env/set.js.map +1 -1
  34. package/dist/cmd/cloud/index.d.ts.map +1 -1
  35. package/dist/cmd/cloud/index.js +2 -0
  36. package/dist/cmd/cloud/index.js.map +1 -1
  37. package/dist/cmd/cloud/queue/ack.d.ts +3 -0
  38. package/dist/cmd/cloud/queue/ack.d.ts.map +1 -0
  39. package/dist/cmd/cloud/queue/ack.js +45 -0
  40. package/dist/cmd/cloud/queue/ack.js.map +1 -0
  41. package/dist/cmd/cloud/queue/create.d.ts +3 -0
  42. package/dist/cmd/cloud/queue/create.d.ts.map +1 -0
  43. package/dist/cmd/cloud/queue/create.js +80 -0
  44. package/dist/cmd/cloud/queue/create.js.map +1 -0
  45. package/dist/cmd/cloud/queue/delete.d.ts +3 -0
  46. package/dist/cmd/cloud/queue/delete.d.ts.map +1 -0
  47. package/dist/cmd/cloud/queue/delete.js +50 -0
  48. package/dist/cmd/cloud/queue/delete.js.map +1 -0
  49. package/dist/cmd/cloud/queue/destinations.d.ts +3 -0
  50. package/dist/cmd/cloud/queue/destinations.d.ts.map +1 -0
  51. package/dist/cmd/cloud/queue/destinations.js +232 -0
  52. package/dist/cmd/cloud/queue/destinations.js.map +1 -0
  53. package/dist/cmd/cloud/queue/dlq.d.ts +3 -0
  54. package/dist/cmd/cloud/queue/dlq.d.ts.map +1 -0
  55. package/dist/cmd/cloud/queue/dlq.js +168 -0
  56. package/dist/cmd/cloud/queue/dlq.js.map +1 -0
  57. package/dist/cmd/cloud/queue/get.d.ts +3 -0
  58. package/dist/cmd/cloud/queue/get.d.ts.map +1 -0
  59. package/dist/cmd/cloud/queue/get.js +130 -0
  60. package/dist/cmd/cloud/queue/get.js.map +1 -0
  61. package/dist/cmd/cloud/queue/index.d.ts +3 -0
  62. package/dist/cmd/cloud/queue/index.d.ts.map +1 -0
  63. package/dist/cmd/cloud/queue/index.js +65 -0
  64. package/dist/cmd/cloud/queue/index.js.map +1 -0
  65. package/dist/cmd/cloud/queue/list.d.ts +3 -0
  66. package/dist/cmd/cloud/queue/list.d.ts.map +1 -0
  67. package/dist/cmd/cloud/queue/list.js +71 -0
  68. package/dist/cmd/cloud/queue/list.js.map +1 -0
  69. package/dist/cmd/cloud/queue/messages.d.ts +3 -0
  70. package/dist/cmd/cloud/queue/messages.d.ts.map +1 -0
  71. package/dist/cmd/cloud/queue/messages.js +137 -0
  72. package/dist/cmd/cloud/queue/messages.js.map +1 -0
  73. package/dist/cmd/cloud/queue/nack.d.ts +3 -0
  74. package/dist/cmd/cloud/queue/nack.d.ts.map +1 -0
  75. package/dist/cmd/cloud/queue/nack.js +45 -0
  76. package/dist/cmd/cloud/queue/nack.js.map +1 -0
  77. package/dist/cmd/cloud/queue/pause.d.ts +3 -0
  78. package/dist/cmd/cloud/queue/pause.d.ts.map +1 -0
  79. package/dist/cmd/cloud/queue/pause.js +36 -0
  80. package/dist/cmd/cloud/queue/pause.js.map +1 -0
  81. package/dist/cmd/cloud/queue/publish.d.ts +3 -0
  82. package/dist/cmd/cloud/queue/publish.d.ts.map +1 -0
  83. package/dist/cmd/cloud/queue/publish.js +76 -0
  84. package/dist/cmd/cloud/queue/publish.js.map +1 -0
  85. package/dist/cmd/cloud/queue/receive.d.ts +3 -0
  86. package/dist/cmd/cloud/queue/receive.d.ts.map +1 -0
  87. package/dist/cmd/cloud/queue/receive.js +67 -0
  88. package/dist/cmd/cloud/queue/receive.js.map +1 -0
  89. package/dist/cmd/cloud/queue/resume.d.ts +3 -0
  90. package/dist/cmd/cloud/queue/resume.d.ts.map +1 -0
  91. package/dist/cmd/cloud/queue/resume.js +35 -0
  92. package/dist/cmd/cloud/queue/resume.js.map +1 -0
  93. package/dist/cmd/cloud/queue/sources.d.ts +3 -0
  94. package/dist/cmd/cloud/queue/sources.d.ts.map +1 -0
  95. package/dist/cmd/cloud/queue/sources.js +290 -0
  96. package/dist/cmd/cloud/queue/sources.js.map +1 -0
  97. package/dist/cmd/cloud/queue/stats.d.ts +3 -0
  98. package/dist/cmd/cloud/queue/stats.d.ts.map +1 -0
  99. package/dist/cmd/cloud/queue/stats.js +239 -0
  100. package/dist/cmd/cloud/queue/stats.js.map +1 -0
  101. package/dist/cmd/cloud/queue/util.d.ts +26 -0
  102. package/dist/cmd/cloud/queue/util.d.ts.map +1 -0
  103. package/dist/cmd/cloud/queue/util.js +19 -0
  104. package/dist/cmd/cloud/queue/util.js.map +1 -0
  105. package/dist/cmd/cloud/sandbox/snapshot/build.d.ts.map +1 -1
  106. package/dist/cmd/cloud/sandbox/snapshot/build.js +152 -30
  107. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  108. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -1
  109. package/dist/cmd/cloud/sandbox/snapshot/create.js +19 -7
  110. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
  111. package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -1
  112. package/dist/cmd/cloud/sandbox/snapshot/get.js +20 -0
  113. package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
  114. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -1
  115. package/dist/cmd/cloud/sandbox/snapshot/list.js +4 -0
  116. package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -1
  117. package/dist/cmd/cloud/vector/stats.d.ts.map +1 -1
  118. package/dist/cmd/cloud/vector/stats.js +8 -0
  119. package/dist/cmd/cloud/vector/stats.js.map +1 -1
  120. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  121. package/dist/cmd/project/template-flow.js.map +1 -1
  122. package/dist/env-util.d.ts +6 -1
  123. package/dist/env-util.d.ts.map +1 -1
  124. package/dist/env-util.js +16 -2
  125. package/dist/env-util.js.map +1 -1
  126. package/dist/errors.d.ts +4 -2
  127. package/dist/errors.d.ts.map +1 -1
  128. package/dist/errors.js +6 -0
  129. package/dist/errors.js.map +1 -1
  130. package/dist/schema-parser.d.ts.map +1 -1
  131. package/dist/schema-parser.js +2 -2
  132. package/dist/schema-parser.js.map +1 -1
  133. package/dist/tui/box.d.ts +8 -0
  134. package/dist/tui/box.d.ts.map +1 -1
  135. package/dist/tui/box.js +78 -0
  136. package/dist/tui/box.js.map +1 -1
  137. package/dist/tui.d.ts +11 -1
  138. package/dist/tui.d.ts.map +1 -1
  139. package/dist/tui.js +16 -8
  140. package/dist/tui.js.map +1 -1
  141. package/dist/types.d.ts.map +1 -1
  142. package/dist/types.js.map +1 -1
  143. package/package.json +6 -6
  144. package/src/cli.ts +5 -1
  145. package/src/cmd/build/ast.ts +88 -2
  146. package/src/cmd/build/vite/registry-generator.ts +120 -24
  147. package/src/cmd/build/vite/route-discovery.ts +16 -0
  148. package/src/cmd/cloud/env/delete.ts +18 -5
  149. package/src/cmd/cloud/env/get.ts +10 -3
  150. package/src/cmd/cloud/env/import.ts +10 -11
  151. package/src/cmd/cloud/env/list.ts +19 -9
  152. package/src/cmd/cloud/env/org-util.ts +1 -1
  153. package/src/cmd/cloud/env/pull.ts +9 -4
  154. package/src/cmd/cloud/env/push.ts +5 -9
  155. package/src/cmd/cloud/env/set.ts +10 -3
  156. package/src/cmd/cloud/index.ts +2 -0
  157. package/src/cmd/cloud/queue/ack.ts +50 -0
  158. package/src/cmd/cloud/queue/create.ts +91 -0
  159. package/src/cmd/cloud/queue/delete.ts +57 -0
  160. package/src/cmd/cloud/queue/destinations.ts +287 -0
  161. package/src/cmd/cloud/queue/dlq.ts +203 -0
  162. package/src/cmd/cloud/queue/get.ts +158 -0
  163. package/src/cmd/cloud/queue/index.ts +66 -0
  164. package/src/cmd/cloud/queue/list.ts +81 -0
  165. package/src/cmd/cloud/queue/messages.ts +160 -0
  166. package/src/cmd/cloud/queue/nack.ts +50 -0
  167. package/src/cmd/cloud/queue/pause.ts +41 -0
  168. package/src/cmd/cloud/queue/publish.ts +88 -0
  169. package/src/cmd/cloud/queue/receive.ts +76 -0
  170. package/src/cmd/cloud/queue/resume.ts +40 -0
  171. package/src/cmd/cloud/queue/sources.ts +352 -0
  172. package/src/cmd/cloud/queue/stats.ts +297 -0
  173. package/src/cmd/cloud/queue/util.ts +34 -0
  174. package/src/cmd/cloud/sandbox/snapshot/build.ts +186 -31
  175. package/src/cmd/cloud/sandbox/snapshot/create.ts +24 -7
  176. package/src/cmd/cloud/sandbox/snapshot/get.ts +20 -0
  177. package/src/cmd/cloud/sandbox/snapshot/list.ts +4 -0
  178. package/src/cmd/cloud/vector/stats.ts +9 -0
  179. package/src/cmd/project/template-flow.ts +1 -3
  180. package/src/env-util.ts +17 -2
  181. package/src/errors.ts +8 -0
  182. package/src/schema-parser.ts +6 -3
  183. package/src/tui/box.ts +104 -0
  184. package/src/tui.ts +28 -8
  185. package/src/types.ts +0 -1
@@ -39,6 +39,10 @@ export const createSubcommand = createCommand({
39
39
  ),
40
40
  description: 'Create a named snapshot with description',
41
41
  },
42
+ {
43
+ command: getCommand('cloud sandbox snapshot create sbx_abc123 --public'),
44
+ description: 'Create a public snapshot',
45
+ },
42
46
  ],
43
47
  schema: {
44
48
  args: z.object({
@@ -51,6 +55,7 @@ export const createSubcommand = createCommand({
51
55
  .describe('Display name for the snapshot (letters, numbers, underscores, dashes only)'),
52
56
  description: z.string().optional().describe('Description of the snapshot'),
53
57
  tag: z.string().optional().describe('Tag for the snapshot (defaults to "latest")'),
58
+ public: z.boolean().optional().default(false).describe('Make the snapshot publicly accessible'),
54
59
  }),
55
60
  response: SnapshotCreateResponseSchema,
56
61
  },
@@ -86,17 +91,29 @@ export const createSubcommand = createCommand({
86
91
  name: opts.name,
87
92
  description: opts.description,
88
93
  tag: opts.tag,
94
+ public: opts.public,
89
95
  orgId,
90
96
  });
91
97
 
92
98
  if (!options.json) {
93
- tui.success(`created snapshot ${tui.bold(snapshot.snapshotId)}`);
94
- tui.info(`Name: ${snapshot.name}`);
95
- if (snapshot.description) {
96
- tui.info(`Description: ${snapshot.description}`);
97
- }
98
- tui.info(`Size: ${tui.formatBytes(snapshot.sizeBytes)}, Files: ${snapshot.fileCount}`);
99
- tui.info(`Tag: ${snapshot.tag ?? 'latest'}`);
99
+ tui.success(`Created snapshot ${tui.bold(snapshot.snapshotId)}`);
100
+ console.log('');
101
+
102
+ tui.table(
103
+ [
104
+ {
105
+ Name: snapshot.name,
106
+ Description: snapshot.description ?? '-',
107
+ Tag: snapshot.tag ?? 'latest',
108
+ Size: tui.formatBytes(snapshot.sizeBytes),
109
+ Files: snapshot.fileCount.toFixed(),
110
+ Visibility: snapshot.public ? 'public' : 'private',
111
+ Created: snapshot.createdAt,
112
+ },
113
+ ],
114
+ ['Name', 'Description', 'Tag', 'Size', 'Files', 'Visibility', 'Created'],
115
+ { layout: 'vertical', padStart: ' ' }
116
+ );
100
117
  }
101
118
 
102
119
  return {
@@ -10,6 +10,9 @@ import { getGlobalCatalystAPIClient } from '../../../../config';
10
10
  const SnapshotFileSchema = z.object({
11
11
  path: z.string(),
12
12
  size: z.number(),
13
+ sha256: z.string(),
14
+ contentType: z.string(),
15
+ mode: z.number(),
13
16
  });
14
17
 
15
18
  const SandboxInfoSchema = z.object({
@@ -22,10 +25,15 @@ const SandboxInfoSchema = z.object({
22
25
  const SnapshotGetResponseSchema = z.object({
23
26
  snapshotId: z.string().describe('Snapshot ID'),
24
27
  name: z.string().describe('Snapshot name'),
28
+ fullName: z.string().optional().describe('Full name with org slug (@slug/name:tag)'),
25
29
  tag: z.string().nullable().optional().describe('Snapshot tag'),
30
+ message: z.string().nullable().optional().describe('Build message'),
26
31
  sizeBytes: z.number().describe('Snapshot size in bytes'),
27
32
  fileCount: z.number().describe('Number of files'),
28
33
  parentSnapshotId: z.string().nullable().optional().describe('Parent snapshot ID'),
34
+ public: z.boolean().optional().describe('Whether snapshot is publicly accessible'),
35
+ orgName: z.string().optional().describe('Organization name (for public snapshots)'),
36
+ orgSlug: z.string().optional().describe('Organization slug (for public snapshots)'),
29
37
  createdAt: z.string().describe('Creation timestamp'),
30
38
  downloadUrl: z.string().optional().describe('Presigned download URL'),
31
39
  files: z.array(SnapshotFileSchema).nullable().optional().describe('Files in snapshot'),
@@ -85,8 +93,20 @@ export const getSubcommand = createCommand({
85
93
  if (snapshot.tag) {
86
94
  tableData['Tag'] = snapshot.tag;
87
95
  }
96
+ if (snapshot.message) {
97
+ tableData['Message'] = snapshot.message;
98
+ }
88
99
  tableData['Size'] = tui.formatBytes(snapshot.sizeBytes);
89
100
  tableData['Files'] = snapshot.fileCount;
101
+ if (snapshot.public) {
102
+ tableData['Public'] = 'Yes';
103
+ if (snapshot.fullName) {
104
+ tableData['Full Name'] = snapshot.fullName;
105
+ }
106
+ if (snapshot.orgName) {
107
+ tableData['Publisher'] = snapshot.orgName;
108
+ }
109
+ }
90
110
  tableData['Created'] = snapshot.createdAt;
91
111
  if (snapshot.parentSnapshotId) {
92
112
  tableData['Parent'] = snapshot.parentSnapshotId;
@@ -8,11 +8,15 @@ import { getGlobalCatalystAPIClient } from '../../../../config';
8
8
  const SnapshotInfoSchema = z.object({
9
9
  snapshotId: z.string(),
10
10
  name: z.string().nullable().optional(),
11
+ fullName: z.string().nullable().optional(),
11
12
  description: z.string().nullable().optional(),
12
13
  tag: z.string().nullable().optional(),
13
14
  sizeBytes: z.number(),
14
15
  fileCount: z.number(),
15
16
  parentSnapshotId: z.string().nullable().optional(),
17
+ public: z.boolean().optional(),
18
+ orgName: z.string().optional(),
19
+ orgSlug: z.string().optional(),
16
20
  createdAt: z.string(),
17
21
  });
18
22
 
@@ -21,12 +21,21 @@ const VectorNamespaceStatsSchema = z.object({
21
21
  lastUsed: z.number().optional().describe('Last used timestamp (ms)'),
22
22
  });
23
23
 
24
+ const VectorStatsPaginatedSchema = z.object({
25
+ namespaces: z.record(z.string(), VectorNamespaceStatsSchema).describe('Map of namespace names to their statistics'),
26
+ total: z.number().describe('Total number of namespaces across all pages'),
27
+ limit: z.number().describe('Number of namespaces requested per page'),
28
+ offset: z.number().describe('Number of namespaces skipped'),
29
+ hasMore: z.boolean().describe('Whether there are more namespaces available'),
30
+ });
31
+
24
32
  const VectorStatsResponseSchema = z.union([
25
33
  VectorNamespaceStatsSchema.extend({
26
34
  namespace: z.string().describe('Namespace name'),
27
35
  sampledResults: z.record(z.string(), VectorItemStatsSchema).optional(),
28
36
  }),
29
37
  z.record(z.string(), VectorNamespaceStatsSchema),
38
+ VectorStatsPaginatedSchema,
30
39
  ]);
31
40
 
32
41
  export const statsSubcommand = createCommand({
@@ -337,9 +337,7 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
337
337
  logger.debug(
338
338
  `Resources for org ${orgId} in region ${region}: ${resources.db.length} databases, ${resources.s3.length} storage buckets`
339
339
  );
340
- logger.debug(
341
- `Database names: ${resources.db.map((d) => d.name).join(', ') || '(none)'}`
342
- );
340
+ logger.debug(`Database names: ${resources.db.map((d) => d.name).join(', ') || '(none)'}`);
343
341
  logger.debug(
344
342
  `Storage buckets: ${resources.s3.map((b) => b.bucket_name).join(', ') || '(none)'}`
345
343
  );
package/src/env-util.ts CHANGED
@@ -13,6 +13,12 @@ export interface EnvVars {
13
13
  */
14
14
  export const PUBLIC_VAR_PREFIXES = ['VITE_', 'AGENTUITY_PUBLIC_', 'PUBLIC_'] as const;
15
15
 
16
+ /**
17
+ * Specific AGENTUITY_ keys that are allowed to be set by users.
18
+ * Note: There is also a whitelist in the API that must be kept in sync.
19
+ */
20
+ export const AGENTUITY_ALLOWED_KEYS = ['AGENTUITY_AUTH_SECRET'] as const;
21
+
16
22
  /**
17
23
  * Check if a key is a public variable (exposed to frontend)
18
24
  */
@@ -22,11 +28,20 @@ export function isPublicVarKey(key: string): boolean {
22
28
  }
23
29
 
24
30
  /**
25
- * Check if a key is a reserved AGENTUITY key (except AGENTUITY_PUBLIC_)
31
+ * Check if a key is a reserved AGENTUITY key (except AGENTUITY_PUBLIC_ and allowed keys)
26
32
  */
27
33
  export function isReservedAgentuityKey(key: string): boolean {
28
34
  const upperKey = key.toUpperCase();
29
- return upperKey.startsWith('AGENTUITY_') && !upperKey.startsWith('AGENTUITY_PUBLIC_');
35
+ if (!upperKey.startsWith('AGENTUITY_')) {
36
+ return false;
37
+ }
38
+ if (upperKey.startsWith('AGENTUITY_PUBLIC_')) {
39
+ return false;
40
+ }
41
+ if (AGENTUITY_ALLOWED_KEYS.includes(key as (typeof AGENTUITY_ALLOWED_KEYS)[number])) {
42
+ return false;
43
+ }
44
+ return true;
30
45
  }
31
46
 
32
47
  /**
package/src/errors.ts CHANGED
@@ -14,6 +14,7 @@ export enum ExitCode {
14
14
  FILE_ERROR = 7,
15
15
  USER_CANCELLED = 8,
16
16
  BUILD_FAILED = 9,
17
+ SECURITY_ERROR = 10,
17
18
  }
18
19
 
19
20
  /**
@@ -75,6 +76,9 @@ export enum ErrorCode {
75
76
 
76
77
  // Integration errors
77
78
  INTEGRATION_FAILED = 'INTEGRATION_FAILED',
79
+
80
+ // Security errors
81
+ MALWARE_DETECTED = 'MALWARE_DETECTED',
78
82
  }
79
83
 
80
84
  /**
@@ -136,6 +140,10 @@ export function getExitCode(errorCode: ErrorCode): ExitCode {
136
140
  case ErrorCode.INTEGRATION_FAILED:
137
141
  return ExitCode.NETWORK_ERROR;
138
142
 
143
+ // Security errors
144
+ case ErrorCode.MALWARE_DETECTED:
145
+ return ExitCode.SECURITY_ERROR;
146
+
139
147
  // Resource conflicts and other errors
140
148
  case ErrorCode.RESOURCE_ALREADY_EXISTS:
141
149
  case ErrorCode.RESOURCE_CONFLICT:
@@ -85,12 +85,15 @@ function isBooleanStringUnion(schema: unknown): boolean {
85
85
  // Zod 3: type is _def.typeName
86
86
  const optUnknown = opt as unknown as Record<string, unknown>;
87
87
  const optDef = optUnknown?._def as Record<string, unknown> | undefined;
88
- const optType = (optUnknown?.type as string) || (optDef?.typeName as string) || (optDef?.type as string);
88
+ const optType =
89
+ (optUnknown?.type as string) || (optDef?.typeName as string) || (optDef?.type as string);
89
90
  types.add(optType);
90
91
  }
91
92
 
92
- return (types.has('boolean') || types.has('ZodBoolean')) &&
93
- (types.has('string') || types.has('ZodString'));
93
+ return (
94
+ (types.has('boolean') || types.has('ZodBoolean')) &&
95
+ (types.has('string') || types.has('ZodString'))
96
+ );
94
97
  }
95
98
 
96
99
  function getShape(schema: ZodType): Record<string, unknown> {
package/src/tui/box.ts CHANGED
@@ -198,3 +198,107 @@ export function note(message: string, title = ''): void {
198
198
  });
199
199
  console.log(output);
200
200
  }
201
+
202
+ /**
203
+ * Draw an error box with red border
204
+ */
205
+ export function errorBox(title: string, message: string): void {
206
+ const termWidth = getTerminalWidth();
207
+ const maxWidth = termWidth - 3;
208
+ const boxWidth = Math.min(60, maxWidth);
209
+ const innerWidth = Math.max(boxWidth - 2, 1);
210
+ const contentWidth = Math.max(innerWidth - 1, 0);
211
+ const padding = 2;
212
+
213
+ const lines: string[] = [];
214
+
215
+ // Title line with error symbol
216
+ const errorSymbol = colors.error('✗');
217
+ const titleText = colors.error(title);
218
+ const titleTextWidth = 1 + stringWidth(title); // symbol + title
219
+ const barsNeeded = Math.max(innerWidth - titleTextWidth - 3, 1);
220
+ const titleLine = `${errorSymbol} ${titleText} ${colors.error(symbols.barH.repeat(barsNeeded) + symbols.cornerTR)}`;
221
+
222
+ lines.push(colors.error(symbols.bar));
223
+ lines.push(titleLine);
224
+
225
+ // Empty line
226
+ const emptyLine = `${colors.error(symbols.bar)}${' '.repeat(contentWidth)}${colors.error(symbols.bar)}`;
227
+ lines.push(emptyLine);
228
+
229
+ // Wrap and render content lines
230
+ const wrapWidth = Math.max(contentWidth - padding * 2, 0);
231
+ const contentLines = message.split('\n');
232
+ for (const line of contentLines) {
233
+ const wrapped = stringWidth(line) > wrapWidth ? wrapText(line, wrapWidth) : [line];
234
+ for (const wl of wrapped) {
235
+ const lineLen = stringWidth(wl);
236
+ const leftPad = padding;
237
+ const rightPad = Math.max(contentWidth - lineLen - leftPad, 0);
238
+ lines.push(
239
+ `${colors.error(symbols.bar)}${' '.repeat(leftPad)}${wl}${' '.repeat(rightPad)}${colors.error(symbols.bar)}`
240
+ );
241
+ }
242
+ }
243
+
244
+ lines.push(emptyLine);
245
+
246
+ // Bottom border
247
+ lines.push(
248
+ colors.error(symbols.connect + symbols.barH.repeat(innerWidth - 1) + symbols.cornerBR)
249
+ );
250
+
251
+ console.log(lines.join('\n'));
252
+ }
253
+
254
+ /**
255
+ * Draw a warning box with yellow border
256
+ */
257
+ export function warningBox(title: string, message: string): void {
258
+ const termWidth = getTerminalWidth();
259
+ const maxWidth = termWidth - 3;
260
+ const boxWidth = Math.min(60, maxWidth);
261
+ const innerWidth = Math.max(boxWidth - 2, 1);
262
+ const contentWidth = Math.max(innerWidth - 1, 0);
263
+ const padding = 2;
264
+
265
+ const lines: string[] = [];
266
+
267
+ // Title line with warning symbol
268
+ const warnSymbol = colors.warning(symbols.warning);
269
+ const titleText = colors.warning(title);
270
+ const titleTextWidth = stringWidth(symbols.warning) + stringWidth(title);
271
+ const barsNeeded = Math.max(innerWidth - titleTextWidth - 3, 1);
272
+ const titleLine = `${warnSymbol} ${titleText} ${colors.warning(symbols.barH.repeat(barsNeeded) + symbols.cornerTR)}`;
273
+
274
+ lines.push(colors.warning(symbols.bar));
275
+ lines.push(titleLine);
276
+
277
+ // Empty line
278
+ const emptyLine = `${colors.warning(symbols.bar)}${' '.repeat(contentWidth)}${colors.warning(symbols.bar)}`;
279
+ lines.push(emptyLine);
280
+
281
+ // Wrap and render content lines
282
+ const wrapWidth = Math.max(contentWidth - padding * 2, 0);
283
+ const contentLines = message.split('\n');
284
+ for (const line of contentLines) {
285
+ const wrapped = stringWidth(line) > wrapWidth ? wrapText(line, wrapWidth) : [line];
286
+ for (const wl of wrapped) {
287
+ const lineLen = stringWidth(wl);
288
+ const leftPad = padding;
289
+ const rightPad = Math.max(contentWidth - lineLen - leftPad, 0);
290
+ lines.push(
291
+ `${colors.warning(symbols.bar)}${' '.repeat(leftPad)}${wl}${' '.repeat(rightPad)}${colors.warning(symbols.bar)}`
292
+ );
293
+ }
294
+ }
295
+
296
+ lines.push(emptyLine);
297
+
298
+ // Bottom border
299
+ lines.push(
300
+ colors.warning(symbols.connect + symbols.barH.repeat(innerWidth - 1) + symbols.cornerBR)
301
+ );
302
+
303
+ console.log(lines.join('\n'));
304
+ }
package/src/tui.ts CHANGED
@@ -45,7 +45,7 @@ export { maskSecret };
45
45
  // Export new TUI components
46
46
  export { createPrompt, PromptFlow } from './tui/prompt';
47
47
  export { group } from './tui/group';
48
- export { note, drawBox } from './tui/box';
48
+ export { note, drawBox, errorBox, warningBox } from './tui/box';
49
49
  export { symbols } from './tui/symbols';
50
50
  export { colors as tuiColors } from './tui/colors';
51
51
  export type {
@@ -834,7 +834,9 @@ export function showLoggedOutMessage(appBaseUrl: string, hasProfile = false): vo
834
834
  // Box format: "║ " + content + "║" = 48 chars total
835
835
  // Content area = 46 chars, with leading space = 45 chars for URL + padding
836
836
  const urlPadding = Math.max(0, 45 - signupURL.length);
837
- const showNewLine = showInline ? '' : `║ ${RESET}${link(signupURL)}${YELLOW}${' '.repeat(urlPadding)}║`;
837
+ const showNewLine = showInline
838
+ ? ''
839
+ : `║ ${RESET}${link(signupURL)}${YELLOW}${' '.repeat(urlPadding)}║`;
838
840
 
839
841
  const lines = [
840
842
  '╔══════════════════════════════════════════════╗',
@@ -1057,6 +1059,11 @@ export interface SimpleSpinnerOptions<T> {
1057
1059
  * Defaults to false
1058
1060
  */
1059
1061
  clearOnSuccess?: boolean;
1062
+ /**
1063
+ * If true, suppress the error message display on failure (for custom error handling)
1064
+ * Defaults to false
1065
+ */
1066
+ clearOnError?: boolean;
1060
1067
  }
1061
1068
 
1062
1069
  /**
@@ -1071,6 +1078,11 @@ export interface ProgressSpinnerOptions<T> {
1071
1078
  * Defaults to false
1072
1079
  */
1073
1080
  clearOnSuccess?: boolean;
1081
+ /**
1082
+ * If true, suppress the error message display on failure (for custom error handling)
1083
+ * Defaults to false
1084
+ */
1085
+ clearOnError?: boolean;
1074
1086
  }
1075
1087
 
1076
1088
  /**
@@ -1196,8 +1208,12 @@ export async function spinner<T>(
1196
1208
 
1197
1209
  return result;
1198
1210
  } catch (err) {
1199
- const errorColor = getColor('error');
1200
- console.error(`${errorColor}${ICONS.error} ${message}${reset}`);
1211
+ const clearOnError =
1212
+ (options.type === 'progress' || options.type === 'simple') && options.clearOnError;
1213
+ if (!clearOnError) {
1214
+ const errorColor = getColor('error');
1215
+ console.error(`${errorColor}${ICONS.error} ${message}${reset}`);
1216
+ }
1201
1217
  throw err;
1202
1218
  }
1203
1219
  }
@@ -1426,10 +1442,14 @@ export async function spinner<T>(
1426
1442
  }
1427
1443
  process.stderr.write('\x1B[?25h'); // Show cursor
1428
1444
 
1429
- // Show error
1430
- const errorColor = getColor('error');
1431
- const errorMessage = err instanceof Error ? err.message : String(err);
1432
- console.error(`${errorColor}${ICONS.error} ${message}: ${errorMessage}${reset}`);
1445
+ // Show error (unless clearOnError is set for custom error handling)
1446
+ const clearOnError =
1447
+ (options.type === 'progress' || options.type === 'simple') && options.clearOnError;
1448
+ if (!clearOnError) {
1449
+ const errorColor = getColor('error');
1450
+ const errorMessage = err instanceof Error ? err.message : String(err);
1451
+ console.error(`${errorColor}${ICONS.error} ${message}: ${errorMessage}${reset}`);
1452
+ }
1433
1453
 
1434
1454
  throw err;
1435
1455
  }
package/src/types.ts CHANGED
@@ -62,7 +62,6 @@ export const ConfigSchema = zod.object({
62
62
  })
63
63
  .optional()
64
64
  .describe('the gravity client information'),
65
-
66
65
  });
67
66
 
68
67
  export type Config = zod.infer<typeof ConfigSchema>;