@agentuity/cli 0.0.69 → 0.0.71

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 (159) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +1 -1
  3. package/dist/cmd/ai/capabilities/show.d.ts.map +1 -1
  4. package/dist/cmd/ai/capabilities/show.js +0 -13
  5. package/dist/cmd/ai/capabilities/show.js.map +1 -1
  6. package/dist/cmd/ai/prompt/agent.js +1 -1
  7. package/dist/cmd/ai/prompt/api.js +1 -1
  8. package/dist/cmd/build/ast.d.ts +1 -2
  9. package/dist/cmd/build/ast.d.ts.map +1 -1
  10. package/dist/cmd/build/ast.js +261 -260
  11. package/dist/cmd/build/ast.js.map +1 -1
  12. package/dist/cmd/build/bundler.d.ts +4 -1
  13. package/dist/cmd/build/bundler.d.ts.map +1 -1
  14. package/dist/cmd/build/bundler.js +89 -6
  15. package/dist/cmd/build/bundler.js.map +1 -1
  16. package/dist/cmd/build/index.d.ts.map +1 -1
  17. package/dist/cmd/build/index.js +2 -1
  18. package/dist/cmd/build/index.js.map +1 -1
  19. package/dist/cmd/build/plugin.d.ts.map +1 -1
  20. package/dist/cmd/build/plugin.js +152 -414
  21. package/dist/cmd/build/plugin.js.map +1 -1
  22. package/dist/cmd/build/route-registry.d.ts +36 -0
  23. package/dist/cmd/build/route-registry.d.ts.map +1 -0
  24. package/dist/cmd/build/route-registry.js +151 -0
  25. package/dist/cmd/build/route-registry.js.map +1 -0
  26. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  27. package/dist/cmd/cloud/deploy.js +2 -0
  28. package/dist/cmd/cloud/deploy.js.map +1 -1
  29. package/dist/cmd/cloud/index.d.ts.map +1 -1
  30. package/dist/cmd/cloud/index.js +0 -2
  31. package/dist/cmd/cloud/index.js.map +1 -1
  32. package/dist/cmd/dev/index.d.ts.map +1 -1
  33. package/dist/cmd/dev/index.js +4 -3
  34. package/dist/cmd/dev/index.js.map +1 -1
  35. package/dist/cmd/dev/sync.d.ts.map +1 -1
  36. package/dist/cmd/dev/sync.js +0 -15
  37. package/dist/cmd/dev/sync.js.map +1 -1
  38. package/dist/cmd/dev/templates.d.ts.map +1 -1
  39. package/dist/cmd/dev/templates.js +11 -35
  40. package/dist/cmd/dev/templates.js.map +1 -1
  41. package/dist/cmd/profile/create.d.ts.map +1 -1
  42. package/dist/cmd/profile/create.js +0 -1
  43. package/dist/cmd/profile/create.js.map +1 -1
  44. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  45. package/dist/cmd/project/template-flow.js +64 -53
  46. package/dist/cmd/project/template-flow.js.map +1 -1
  47. package/dist/config.d.ts.map +1 -1
  48. package/dist/config.js +0 -3
  49. package/dist/config.js.map +1 -1
  50. package/dist/env-util.d.ts.map +1 -1
  51. package/dist/env-util.js +0 -3
  52. package/dist/env-util.js.map +1 -1
  53. package/dist/tui/box.d.ts +19 -0
  54. package/dist/tui/box.d.ts.map +1 -0
  55. package/dist/tui/box.js +160 -0
  56. package/dist/tui/box.js.map +1 -0
  57. package/dist/tui/colors.d.ts +20 -0
  58. package/dist/tui/colors.d.ts.map +1 -0
  59. package/dist/tui/colors.js +52 -0
  60. package/dist/tui/colors.js.map +1 -0
  61. package/dist/tui/group.d.ts +25 -0
  62. package/dist/tui/group.d.ts.map +1 -0
  63. package/dist/tui/group.js +32 -0
  64. package/dist/tui/group.js.map +1 -0
  65. package/dist/tui/prompt.d.ts +65 -0
  66. package/dist/tui/prompt.d.ts.map +1 -0
  67. package/dist/tui/prompt.js +377 -0
  68. package/dist/tui/prompt.js.map +1 -0
  69. package/dist/tui/symbols.d.ts +32 -0
  70. package/dist/tui/symbols.d.ts.map +1 -0
  71. package/dist/tui/symbols.js +52 -0
  72. package/dist/tui/symbols.js.map +1 -0
  73. package/dist/tui.d.ts +6 -0
  74. package/dist/tui.d.ts.map +1 -1
  75. package/dist/tui.js +6 -0
  76. package/dist/tui.js.map +1 -1
  77. package/dist/types.d.ts +0 -24
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js +0 -1
  80. package/dist/types.js.map +1 -1
  81. package/package.json +3 -3
  82. package/src/cmd/ai/capabilities/show.ts +0 -13
  83. package/src/cmd/ai/prompt/agent.ts +1 -1
  84. package/src/cmd/ai/prompt/api.ts +1 -1
  85. package/src/cmd/build/ast.ts +364 -334
  86. package/src/cmd/build/bundler.ts +123 -9
  87. package/src/cmd/build/index.ts +2 -1
  88. package/src/cmd/build/plugin.ts +171 -493
  89. package/src/cmd/build/route-registry.ts +198 -0
  90. package/src/cmd/cloud/deploy.ts +2 -0
  91. package/src/cmd/cloud/index.ts +0 -2
  92. package/src/cmd/dev/index.ts +4 -3
  93. package/src/cmd/dev/sync.ts +0 -28
  94. package/src/cmd/dev/templates.ts +11 -35
  95. package/src/cmd/profile/create.ts +0 -1
  96. package/src/cmd/project/template-flow.ts +77 -57
  97. package/src/config.ts +0 -3
  98. package/src/env-util.ts +0 -3
  99. package/src/tui/box.ts +202 -0
  100. package/src/tui/colors.ts +55 -0
  101. package/src/tui/group.ts +56 -0
  102. package/src/tui/prompt.ts +506 -0
  103. package/src/tui/symbols.ts +64 -0
  104. package/src/tui.ts +14 -0
  105. package/src/types.ts +0 -1
  106. package/dist/cmd/cloud/objectstore/delete-bucket.d.ts +0 -3
  107. package/dist/cmd/cloud/objectstore/delete-bucket.d.ts.map +0 -1
  108. package/dist/cmd/cloud/objectstore/delete-bucket.js +0 -72
  109. package/dist/cmd/cloud/objectstore/delete-bucket.js.map +0 -1
  110. package/dist/cmd/cloud/objectstore/delete.d.ts +0 -3
  111. package/dist/cmd/cloud/objectstore/delete.d.ts.map +0 -1
  112. package/dist/cmd/cloud/objectstore/delete.js +0 -65
  113. package/dist/cmd/cloud/objectstore/delete.js.map +0 -1
  114. package/dist/cmd/cloud/objectstore/get.d.ts +0 -3
  115. package/dist/cmd/cloud/objectstore/get.d.ts.map +0 -1
  116. package/dist/cmd/cloud/objectstore/get.js +0 -75
  117. package/dist/cmd/cloud/objectstore/get.js.map +0 -1
  118. package/dist/cmd/cloud/objectstore/index.d.ts +0 -3
  119. package/dist/cmd/cloud/objectstore/index.d.ts.map +0 -1
  120. package/dist/cmd/cloud/objectstore/index.js +0 -36
  121. package/dist/cmd/cloud/objectstore/index.js.map +0 -1
  122. package/dist/cmd/cloud/objectstore/list-buckets.d.ts +0 -3
  123. package/dist/cmd/cloud/objectstore/list-buckets.d.ts.map +0 -1
  124. package/dist/cmd/cloud/objectstore/list-buckets.js +0 -46
  125. package/dist/cmd/cloud/objectstore/list-buckets.js.map +0 -1
  126. package/dist/cmd/cloud/objectstore/list-keys.d.ts +0 -3
  127. package/dist/cmd/cloud/objectstore/list-keys.d.ts.map +0 -1
  128. package/dist/cmd/cloud/objectstore/list-keys.js +0 -58
  129. package/dist/cmd/cloud/objectstore/list-keys.js.map +0 -1
  130. package/dist/cmd/cloud/objectstore/put.d.ts +0 -3
  131. package/dist/cmd/cloud/objectstore/put.d.ts.map +0 -1
  132. package/dist/cmd/cloud/objectstore/put.js +0 -66
  133. package/dist/cmd/cloud/objectstore/put.js.map +0 -1
  134. package/dist/cmd/cloud/objectstore/repl.d.ts +0 -3
  135. package/dist/cmd/cloud/objectstore/repl.d.ts.map +0 -1
  136. package/dist/cmd/cloud/objectstore/repl.js +0 -224
  137. package/dist/cmd/cloud/objectstore/repl.js.map +0 -1
  138. package/dist/cmd/cloud/objectstore/url.d.ts +0 -3
  139. package/dist/cmd/cloud/objectstore/url.d.ts.map +0 -1
  140. package/dist/cmd/cloud/objectstore/url.js +0 -64
  141. package/dist/cmd/cloud/objectstore/url.js.map +0 -1
  142. package/dist/cmd/cloud/objectstore/util.d.ts +0 -11
  143. package/dist/cmd/cloud/objectstore/util.d.ts.map +0 -1
  144. package/dist/cmd/cloud/objectstore/util.js +0 -18
  145. package/dist/cmd/cloud/objectstore/util.js.map +0 -1
  146. package/src/cmd/build/ast.test.ts +0 -418
  147. package/src/cmd/build/fix-duplicate-exports.test.ts +0 -387
  148. package/src/cmd/cloud/objectstore/delete-bucket.ts +0 -77
  149. package/src/cmd/cloud/objectstore/delete.ts +0 -67
  150. package/src/cmd/cloud/objectstore/get.ts +0 -77
  151. package/src/cmd/cloud/objectstore/index.ts +0 -36
  152. package/src/cmd/cloud/objectstore/list-buckets.ts +0 -51
  153. package/src/cmd/cloud/objectstore/list-keys.ts +0 -63
  154. package/src/cmd/cloud/objectstore/put.ts +0 -74
  155. package/src/cmd/cloud/objectstore/repl.ts +0 -239
  156. package/src/cmd/cloud/objectstore/url.ts +0 -67
  157. package/src/cmd/cloud/objectstore/util.ts +0 -29
  158. package/src/crypto/box.test.ts +0 -431
  159. package/src/env-util.test.ts +0 -194
@@ -0,0 +1,506 @@
1
+ /**
2
+ * Interactive prompt system for TUI
3
+ */
4
+ import * as readline from 'node:readline';
5
+ import { symbols } from './symbols';
6
+ import { colors } from './colors';
7
+
8
+ interface KeypressEvent {
9
+ name: string;
10
+ ctrl?: boolean;
11
+ }
12
+
13
+ export interface TextOptions {
14
+ message: string;
15
+ initial?: string;
16
+ placeholder?: string;
17
+ validate?: (value: string) => boolean | string | Promise<boolean | string>;
18
+ }
19
+
20
+ export interface ConfirmOptions {
21
+ message: string;
22
+ initial?: boolean;
23
+ }
24
+
25
+ export interface SelectOption<T = string> {
26
+ value: T;
27
+ label: string;
28
+ hint?: string;
29
+ }
30
+
31
+ export interface SelectOptions<T = string> {
32
+ message: string;
33
+ options: SelectOption<T>[];
34
+ initial?: T;
35
+ }
36
+
37
+ export interface MultiSelectOptions<T = string> {
38
+ message: string;
39
+ options: SelectOption<T>[];
40
+ initial?: T[];
41
+ }
42
+
43
+ /**
44
+ * Prompt state tracking
45
+ */
46
+ interface PromptState {
47
+ type: 'active' | 'completed' | 'error' | 'cancelled';
48
+ message: string;
49
+ value?: unknown;
50
+ }
51
+
52
+ /**
53
+ * Main prompt flow class
54
+ */
55
+ export class PromptFlow {
56
+ private states: PromptState[] = [];
57
+ private hasIntro = false;
58
+
59
+ /**
60
+ * Display intro banner
61
+ */
62
+ intro(title: string): void {
63
+ console.log(`${colors.secondary(symbols.squareTL)} ${colors.inverseCyan(` ⨺ ${title} `)}`);
64
+ console.log(colors.secondary(symbols.bar));
65
+ this.hasIntro = true;
66
+ }
67
+
68
+ /**
69
+ * Display outro message
70
+ */
71
+ outro(...messages: string[]): void {
72
+ for (const message of messages) {
73
+ console.log(colors.secondary(symbols.bar));
74
+ console.log(`${colors.secondary(symbols.squareBL)} ${message}`);
75
+ }
76
+ console.log();
77
+
78
+ // Ensure stdin is properly closed
79
+ if (process.stdin.isTTY) {
80
+ process.stdin.pause();
81
+ process.stdin.setRawMode(false);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Text input prompt
87
+ */
88
+ async text(options: TextOptions): Promise<string> {
89
+ const { message, initial = '', validate } = options;
90
+
91
+ return new Promise((resolve, reject) => {
92
+ const rl = readline.createInterface({
93
+ input: process.stdin,
94
+ output: process.stdout,
95
+ });
96
+
97
+ let hasError = false;
98
+
99
+ const showPrompt = () => {
100
+ // Show prompt with active symbol
101
+ process.stdout.write(
102
+ `${colors.active(symbols.active)} ${message}\n${colors.secondary(symbols.bar)} `
103
+ );
104
+ };
105
+
106
+ showPrompt();
107
+
108
+ rl.on('line', async (input) => {
109
+ const trimmed = input.trim();
110
+ const value = trimmed.length > 0 ? trimmed : initial;
111
+
112
+ // Validate
113
+ if (validate) {
114
+ try {
115
+ const result = await validate(value);
116
+ if (result !== true) {
117
+ const errorMsg = typeof result === 'string' ? result : 'Invalid input';
118
+
119
+ // Clear all previous lines (prompt + optional error)
120
+ const linesToClear = hasError ? 3 : 2;
121
+ readline.moveCursor(process.stdout, 0, -linesToClear);
122
+ readline.clearScreenDown(process.stdout);
123
+
124
+ // Redraw prompt with error
125
+ process.stdout.write(
126
+ `${colors.error(symbols.error)} ${message}\n${colors.secondary(symbols.bar)} ${colors.error(errorMsg)}\n${colors.secondary(symbols.bar)} `
127
+ );
128
+ hasError = true;
129
+ return;
130
+ }
131
+ } catch (error) {
132
+ // Handle validation errors
133
+ const errorMsg = error instanceof Error ? error.message : 'Validation failed';
134
+
135
+ // Clear all previous lines
136
+ const linesToClear = hasError ? 3 : 2;
137
+ readline.moveCursor(process.stdout, 0, -linesToClear);
138
+ readline.clearScreenDown(process.stdout);
139
+
140
+ // Show error and cleanup
141
+ process.stdout.write(
142
+ `${colors.error(symbols.error)} ${message}\n${colors.secondary(symbols.bar)} ${colors.error(errorMsg)}\n`
143
+ );
144
+
145
+ rl.close();
146
+ if (process.stdin.isTTY) {
147
+ process.stdin.pause();
148
+ }
149
+
150
+ reject(error);
151
+ return;
152
+ }
153
+ }
154
+
155
+ // Clear all lines and show completed state
156
+ const linesToClear = hasError ? 3 : 2;
157
+ readline.moveCursor(process.stdout, 0, -linesToClear);
158
+ readline.clearScreenDown(process.stdout);
159
+
160
+ process.stdout.write(
161
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)} ${colors.muted(value)}\n${colors.secondary(symbols.bar)}\n`
162
+ );
163
+
164
+ this.states.push({
165
+ type: 'completed',
166
+ message,
167
+ value,
168
+ });
169
+
170
+ rl.close();
171
+
172
+ // Important: pause stdin so next prompt can use it
173
+ if (process.stdin.isTTY) {
174
+ process.stdin.pause();
175
+ }
176
+
177
+ resolve(value);
178
+ });
179
+
180
+ rl.on('SIGINT', () => {
181
+ rl.close();
182
+ console.log('\n');
183
+ this.cancel('Operation cancelled');
184
+ reject(new Error('User cancelled'));
185
+ });
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Confirm (yes/no) prompt
191
+ */
192
+ async confirm(options: ConfirmOptions): Promise<boolean> {
193
+ const { message, initial = false } = options;
194
+
195
+ return new Promise((resolve, reject) => {
196
+ const hint = initial ? 'Y/n' : 'y/N';
197
+
198
+ // Resume stdin if it was paused
199
+ if (process.stdin.isTTY && process.stdin.isPaused()) {
200
+ process.stdin.resume();
201
+ }
202
+
203
+ // Hide cursor
204
+ if (process.stdout.isTTY) {
205
+ process.stdout.write('\x1b[?25l');
206
+ }
207
+
208
+ process.stdout.write(
209
+ `${colors.active(symbols.active)} ${message} ${colors.muted(`(${hint})`)} `
210
+ );
211
+
212
+ readline.emitKeypressEvents(process.stdin);
213
+ if (process.stdin.isTTY) {
214
+ process.stdin.setRawMode(true);
215
+ }
216
+
217
+ const onKeypress = (str: string, key: KeypressEvent) => {
218
+ const normalized = (str || '').toLowerCase();
219
+ let value = initial;
220
+
221
+ // Check for y/n keypress
222
+ if (normalized === 'y') {
223
+ value = true;
224
+ } else if (normalized === 'n') {
225
+ value = false;
226
+ } else if (key.name === 'return') {
227
+ // Enter key uses default
228
+ value = initial;
229
+ } else if (key.ctrl && key.name === 'c') {
230
+ cleanup();
231
+ console.log('\n');
232
+ this.cancel('Operation cancelled');
233
+ reject(new Error('User cancelled'));
234
+ return;
235
+ } else {
236
+ // Ignore other keys
237
+ return;
238
+ }
239
+
240
+ cleanup();
241
+
242
+ // Clear the line and show completed state
243
+ readline.cursorTo(process.stdout, 0);
244
+ readline.clearLine(process.stdout, 0);
245
+
246
+ const displayValue = value ? 'Yes' : 'No';
247
+ process.stdout.write(
248
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)} ${colors.muted(displayValue)}\n${colors.secondary(symbols.bar)}\n`
249
+ );
250
+
251
+ this.states.push({
252
+ type: 'completed',
253
+ message,
254
+ value,
255
+ });
256
+
257
+ resolve(value);
258
+ };
259
+
260
+ const cleanup = () => {
261
+ process.stdin.removeListener('keypress', onKeypress);
262
+ if (process.stdin.isTTY) {
263
+ process.stdin.setRawMode(false);
264
+ // Show cursor again
265
+ process.stdout.write('\x1b[?25h');
266
+ }
267
+ };
268
+
269
+ process.stdin.on('keypress', onKeypress);
270
+ });
271
+ }
272
+
273
+ /**
274
+ * Select (single choice) prompt
275
+ */
276
+ async select<T = string>(options: SelectOptions<T>): Promise<T> {
277
+ const { message, options: choices, initial } = options;
278
+
279
+ return new Promise((resolve, reject) => {
280
+ let selectedIndex = choices.findIndex((c) => c.value === initial);
281
+ if (selectedIndex === -1) selectedIndex = 0;
282
+
283
+ let hasRendered = false;
284
+
285
+ const render = () => {
286
+ // Clear previous render
287
+ if (hasRendered && process.stdout.isTTY) {
288
+ // Move cursor up to the start of the prompt (message + all choices)
289
+ const totalLines = choices.length + 1;
290
+ readline.moveCursor(process.stdout, 0, -totalLines);
291
+ readline.cursorTo(process.stdout, 0);
292
+ readline.clearScreenDown(process.stdout);
293
+ }
294
+
295
+ process.stdout.write(`${colors.active(symbols.active)} ${message}\n`);
296
+
297
+ choices.forEach((choice, index) => {
298
+ const isSelected = index === selectedIndex;
299
+ const symbol = isSelected ? symbols.radioActive : symbols.radioInactive;
300
+ const colorFn = isSelected ? colors.active : colors.secondary;
301
+ const label = choice.hint
302
+ ? `${choice.label} ${colors.muted(choice.hint)}`
303
+ : choice.label;
304
+ process.stdout.write(
305
+ `${colors.secondary(symbols.bar)} ${colorFn(symbol)} ${label}\n`
306
+ );
307
+ });
308
+
309
+ hasRendered = true;
310
+ };
311
+
312
+ // Resume stdin if it was paused
313
+ if (process.stdin.isTTY && process.stdin.isPaused()) {
314
+ process.stdin.resume();
315
+ }
316
+
317
+ render();
318
+
319
+ readline.emitKeypressEvents(process.stdin);
320
+ if (process.stdin.isTTY) {
321
+ process.stdin.setRawMode(true);
322
+ }
323
+
324
+ const onKeypress = (_str: string, key: KeypressEvent) => {
325
+ if (key.name === 'up' || key.name === 'k') {
326
+ selectedIndex = Math.max(0, selectedIndex - 1);
327
+ render();
328
+ } else if (key.name === 'down' || key.name === 'j') {
329
+ selectedIndex = Math.min(choices.length - 1, selectedIndex + 1);
330
+ render();
331
+ } else if (key.name === 'return') {
332
+ cleanup();
333
+ const selected = choices[selectedIndex];
334
+
335
+ // Clear all lines (message + all choices)
336
+ const totalLines = choices.length + 1;
337
+ for (let i = 0; i < totalLines; i++) {
338
+ readline.moveCursor(process.stdout, 0, -1);
339
+ readline.clearLine(process.stdout, 0);
340
+ }
341
+ readline.cursorTo(process.stdout, 0);
342
+
343
+ // Show completed state
344
+ process.stdout.write(
345
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)} ${colors.muted(selected.label)}\n${colors.secondary(symbols.bar)}\n`
346
+ );
347
+
348
+ this.states.push({
349
+ type: 'completed',
350
+ message,
351
+ value: selected.value,
352
+ });
353
+
354
+ resolve(selected.value);
355
+ } else if (key.ctrl && key.name === 'c') {
356
+ cleanup();
357
+ console.log('\n');
358
+ this.cancel('Operation cancelled');
359
+ reject(new Error('User cancelled'));
360
+ }
361
+ };
362
+
363
+ const cleanup = () => {
364
+ process.stdin.removeListener('keypress', onKeypress);
365
+ if (process.stdin.isTTY) {
366
+ process.stdin.setRawMode(false);
367
+ }
368
+ };
369
+
370
+ process.stdin.on('keypress', onKeypress);
371
+ });
372
+ }
373
+
374
+ /**
375
+ * Multi-select (multiple choices) prompt
376
+ */
377
+ async multiselect<T = string>(options: MultiSelectOptions<T>): Promise<T[]> {
378
+ const { message, options: choices, initial = [] } = options;
379
+
380
+ return new Promise((resolve, reject) => {
381
+ let cursorIndex = 0;
382
+ const selected = new Set<number>(
383
+ choices.map((c, i) => (initial.includes(c.value) ? i : -1)).filter((i) => i >= 0)
384
+ );
385
+
386
+ let hasRendered = false;
387
+
388
+ const render = () => {
389
+ // Clear previous render
390
+ if (hasRendered && process.stdout.isTTY) {
391
+ // Move cursor up to the start of the prompt (message + all choices)
392
+ const totalLines = choices.length + 1;
393
+ readline.moveCursor(process.stdout, 0, -totalLines);
394
+ readline.cursorTo(process.stdout, 0);
395
+ readline.clearScreenDown(process.stdout);
396
+ }
397
+
398
+ process.stdout.write(
399
+ `${colors.active(symbols.active)} ${message} ${colors.muted('(space to select, enter to confirm)')}\n`
400
+ );
401
+
402
+ choices.forEach((choice, index) => {
403
+ const isCursor = index === cursorIndex;
404
+ const isSelected = selected.has(index);
405
+ const symbol = isSelected ? symbols.checkboxSelected : symbols.checkboxActive;
406
+ const colorFn = isCursor ? colors.active : colors.secondary;
407
+ const label = choice.hint
408
+ ? `${choice.label} ${colors.muted(choice.hint)}`
409
+ : choice.label;
410
+ process.stdout.write(
411
+ `${colors.secondary(symbols.bar)} ${colorFn(symbol)} ${label}\n`
412
+ );
413
+ });
414
+
415
+ hasRendered = true;
416
+ };
417
+
418
+ // Resume stdin if it was paused
419
+ if (process.stdin.isTTY && process.stdin.isPaused()) {
420
+ process.stdin.resume();
421
+ }
422
+
423
+ render();
424
+
425
+ readline.emitKeypressEvents(process.stdin);
426
+ if (process.stdin.isTTY) {
427
+ process.stdin.setRawMode(true);
428
+ }
429
+
430
+ const onKeypress = (_str: string, key: KeypressEvent) => {
431
+ if (key.name === 'up' || key.name === 'k') {
432
+ cursorIndex = Math.max(0, cursorIndex - 1);
433
+ render();
434
+ } else if (key.name === 'down' || key.name === 'j') {
435
+ cursorIndex = Math.min(choices.length - 1, cursorIndex + 1);
436
+ render();
437
+ } else if (key.name === 'space') {
438
+ if (selected.has(cursorIndex)) {
439
+ selected.delete(cursorIndex);
440
+ } else {
441
+ selected.add(cursorIndex);
442
+ }
443
+ render();
444
+ } else if (key.name === 'return') {
445
+ cleanup();
446
+
447
+ // Sort indices to get consistent order for both values and labels
448
+ const sortedIndices = Array.from(selected).sort((a, b) => a - b);
449
+ const values = sortedIndices.map((i) => choices[i].value);
450
+ const labels = sortedIndices.map((i) => choices[i].label);
451
+
452
+ // Clear all lines (message + all choices)
453
+ const totalLines = choices.length + 1;
454
+ for (let i = 0; i < totalLines; i++) {
455
+ readline.moveCursor(process.stdout, 0, -1);
456
+ readline.clearLine(process.stdout, 0);
457
+ }
458
+ readline.cursorTo(process.stdout, 0);
459
+
460
+ // Show completed state
461
+ const displayValue = labels.length > 0 ? labels.join(', ') : 'None';
462
+ process.stdout.write(
463
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)} ${colors.muted(displayValue)}\n${colors.secondary(symbols.bar)}\n`
464
+ );
465
+
466
+ this.states.push({
467
+ type: 'completed',
468
+ message,
469
+ value: values,
470
+ });
471
+
472
+ resolve(values);
473
+ } else if (key.ctrl && key.name === 'c') {
474
+ cleanup();
475
+ console.log('\n');
476
+ this.cancel('Operation cancelled');
477
+ reject(new Error('User cancelled'));
478
+ }
479
+ };
480
+
481
+ const cleanup = () => {
482
+ process.stdin.removeListener('keypress', onKeypress);
483
+ if (process.stdin.isTTY) {
484
+ process.stdin.setRawMode(false);
485
+ }
486
+ };
487
+
488
+ process.stdin.on('keypress', onKeypress);
489
+ });
490
+ }
491
+
492
+ /**
493
+ * Cancel the flow
494
+ */
495
+ cancel(message: string): void {
496
+ console.log(`${colors.error(symbols.cancel)} ${message}\n`);
497
+ process.exit(0);
498
+ }
499
+ }
500
+
501
+ /**
502
+ * Create a new prompt flow instance
503
+ */
504
+ export function createPrompt(): PromptFlow {
505
+ return new PromptFlow();
506
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Box drawing and UI symbols for TUI components
3
+ * Supports Unicode with ASCII fallbacks for non-unicode terminals
4
+ */
5
+
6
+ // Detect unicode support
7
+ const isUnicodeSupported = (): boolean => {
8
+ if (process.platform !== 'win32') {
9
+ return process.env.TERM !== 'linux'; // Linux console (kernel) doesn't support Unicode
10
+ }
11
+
12
+ return (
13
+ Boolean(process.env.WT_SESSION) || // Windows Terminal
14
+ Boolean(process.env.TERMINUS_SUBLIME) || // Terminus (<0.2.27)
15
+ process.env.TERM_PROGRAM === 'vscode' ||
16
+ process.env.TERM === 'xterm-256color' ||
17
+ process.env.TERM === 'alacritty' ||
18
+ process.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm'
19
+ );
20
+ };
21
+
22
+ const unicode = isUnicodeSupported();
23
+
24
+ export const symbols = {
25
+ // Step symbols
26
+ active: unicode ? '◆' : '*',
27
+ completed: unicode ? '◇' : 'o',
28
+ error: unicode ? '■' : 'x',
29
+ warning: unicode ? '▲' : '!',
30
+ cancel: unicode ? '■' : 'x',
31
+
32
+ // Borders - bars
33
+ bar: unicode ? '│' : '|',
34
+ barH: unicode ? '─' : '-',
35
+
36
+ // Borders - rounded corners
37
+ cornerTL: unicode ? '╭' : '+',
38
+ cornerTR: unicode ? '╮' : '+',
39
+ cornerBL: unicode ? '╰' : '+',
40
+ cornerBR: unicode ? '╯' : '+',
41
+
42
+ // Borders - square corners
43
+ squareTL: unicode ? '┌' : 'T',
44
+ squareTR: unicode ? '┐' : 'T',
45
+ squareBL: unicode ? '└' : 'L',
46
+ squareBR: unicode ? '┘' : 'J',
47
+
48
+ // Connectors
49
+ connect: unicode ? '├' : '+',
50
+ connectRight: unicode ? '┤' : '+',
51
+
52
+ // Selection symbols
53
+ radioActive: unicode ? '●' : '>',
54
+ radioInactive: unicode ? '○' : ' ',
55
+ checkboxActive: unicode ? '◻' : '[ ]',
56
+ checkboxSelected: unicode ? '◼' : '[x]',
57
+ checkboxInactive: unicode ? '◻' : '[ ]',
58
+
59
+ // Other
60
+ passwordMask: unicode ? '▪' : '*',
61
+ info: unicode ? '●' : '*',
62
+ };
63
+
64
+ export const isUnicode = unicode;
package/src/tui.ts CHANGED
@@ -18,6 +18,20 @@ import { maskSecret } from './env-util';
18
18
  // Re-export maskSecret for convenience
19
19
  export { maskSecret };
20
20
 
21
+ // Export new TUI components
22
+ export { createPrompt, PromptFlow } from './tui/prompt';
23
+ export { group } from './tui/group';
24
+ export { note, drawBox } from './tui/box';
25
+ export { symbols } from './tui/symbols';
26
+ export { colors as tuiColors } from './tui/colors';
27
+ export type {
28
+ TextOptions,
29
+ ConfirmOptions,
30
+ SelectOptions,
31
+ SelectOption,
32
+ MultiSelectOptions,
33
+ } from './tui/prompt';
34
+
21
35
  // Icons
22
36
  const ICONS = {
23
37
  success: '✓',
package/src/types.ts CHANGED
@@ -31,7 +31,6 @@ export const ConfigSchema = zod.object({
31
31
  transport_url: zod.url().optional().describe('Override transport URL'),
32
32
  stream_url: zod.url().optional().describe('Override stream URL'),
33
33
  kv_url: zod.url().optional().describe('Override keyvalue URL'),
34
- object_url: zod.url().optional().describe('Override object store URL'),
35
34
  vector_url: zod.url().optional().describe('Override vector store URL'),
36
35
  catalyst_url: zod.url().optional().describe('Override catalyst URL'),
37
36
  ion_url: zod.url().optional().describe('Override ion URL'),
@@ -1,3 +0,0 @@
1
- export declare const deleteBucketSubcommand: import("../../..").CommandDefinition;
2
- export default deleteBucketSubcommand;
3
- //# sourceMappingURL=delete-bucket.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delete-bucket.d.ts","sourceRoot":"","sources":["../../../../src/cmd/cloud/objectstore/delete-bucket.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,sBAAsB,sCAqEjC,CAAC;AAEH,eAAe,sBAAsB,CAAC"}
@@ -1,72 +0,0 @@
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
- export const deleteBucketSubcommand = createCommand({
7
- name: 'delete-bucket',
8
- description: 'Delete an object storage bucket and all its contents',
9
- tags: ['destructive', 'deletes-resource', 'slow', 'requires-auth'],
10
- idempotent: true,
11
- requires: { auth: true, project: true },
12
- examples: [
13
- {
14
- command: getCommand('objectstore delete-bucket temp'),
15
- description: 'Delete temp bucket (interactive)',
16
- },
17
- {
18
- command: getCommand('objectstore delete-bucket old-uploads --confirm'),
19
- description: 'Force delete without confirmation',
20
- },
21
- ],
22
- schema: {
23
- args: z.object({
24
- bucket: z.string().min(1).max(64).describe('the name of the bucket'),
25
- confirm: z
26
- .boolean()
27
- .optional()
28
- .default(false)
29
- .describe('if true will not prompt for confirmation'),
30
- }),
31
- response: z.object({
32
- success: z.boolean().describe('Whether the deletion succeeded'),
33
- bucket: z.string().describe('Deleted bucket name'),
34
- message: z.string().optional().describe('Confirmation message'),
35
- }),
36
- },
37
- async handler(ctx) {
38
- const { args } = ctx;
39
- const objectStore = await createStorageAdapter(ctx);
40
- if (!args.confirm) {
41
- if (!process.stdin.isTTY) {
42
- tui.fatal('No TTY and --confirm is not set. Refusing to delete');
43
- }
44
- tui.warning(`This will delete bucket ${tui.bold(args.bucket)} and ALL its contents.`);
45
- const confirm = await new Promise((resolve) => {
46
- process.stdout.write('Are you sure? (yes/no): ');
47
- process.stdin.once('data', (data) => {
48
- const answer = data.toString().trim().toLowerCase();
49
- resolve(answer === 'yes' || answer === 'y');
50
- });
51
- });
52
- if (!confirm) {
53
- tui.info('Cancelled');
54
- return { success: false, bucket: args.bucket, message: 'Cancelled' };
55
- }
56
- }
57
- const deleted = await objectStore.deleteBucket(args.bucket);
58
- if (deleted) {
59
- tui.success(`Bucket ${tui.bold(args.bucket)} deleted`);
60
- }
61
- else {
62
- tui.error(`Bucket ${tui.bold(args.bucket)} not found`);
63
- }
64
- return {
65
- success: deleted,
66
- bucket: args.bucket,
67
- message: deleted ? `Bucket ${args.bucket} deleted` : `Bucket ${args.bucket} not found`,
68
- };
69
- },
70
- });
71
- export default deleteBucketSubcommand;
72
- //# sourceMappingURL=delete-bucket.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delete-bucket.js","sourceRoot":"","sources":["../../../../src/cmd/cloud/objectstore/delete-bucket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,aAAa,CAAC;IACnD,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,sDAAsD;IACnE,IAAI,EAAE,CAAC,aAAa,EAAE,kBAAkB,EAAE,MAAM,EAAE,eAAe,CAAC;IAClE,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACvC,QAAQ,EAAE;QACT;YACC,OAAO,EAAE,UAAU,CAAC,gCAAgC,CAAC;YACrD,WAAW,EAAE,kCAAkC;SAC/C;QACD;YACC,OAAO,EAAE,UAAU,CAAC,iDAAiD,CAAC;YACtE,WAAW,EAAE,mCAAmC;SAChD;KACD;IACD,MAAM,EAAE;QACP,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;YACd,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;YACpE,OAAO,EAAE,CAAC;iBACR,OAAO,EAAE;iBACT,QAAQ,EAAE;iBACV,OAAO,CAAC,KAAK,CAAC;iBACd,QAAQ,CAAC,0CAA0C,CAAC;SACtD,CAAC;QACF,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC;YAClB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;YAC/D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YAClD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;SAC/D,CAAC;KACF;IAED,KAAK,CAAC,OAAO,CAAC,GAAG;QAChB,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC;QACrB,MAAM,WAAW,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC1B,GAAG,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;YAClE,CAAC;YACD,GAAG,CAAC,OAAO,CAAC,2BAA2B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;YACtF,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;gBACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;gBACjD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;oBACnC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;oBACpD,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,GAAG,CAAC,CAAC;gBAC7C,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;YACtE,CAAC;QACF,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE5D,IAAI,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACxD,CAAC;QAED,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,MAAM,YAAY;SACtF,CAAC;IACH,CAAC;CACD,CAAC,CAAC;AAEH,eAAe,sBAAsB,CAAC"}
@@ -1,3 +0,0 @@
1
- export declare const deleteSubcommand: import("../../..").CommandDefinition;
2
- export default deleteSubcommand;
3
- //# sourceMappingURL=delete.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../../src/cmd/cloud/objectstore/delete.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,gBAAgB,sCAiD3B,CAAC;AAEH,eAAe,gBAAgB,CAAC"}