@agentuity/cli 0.0.68 → 0.0.70

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 (182) hide show
  1. package/AGENTS.md +1 -1
  2. package/README.md +1 -1
  3. package/bin/cli.ts +20 -8
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +16 -0
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cmd/ai/capabilities/show.d.ts.map +1 -1
  8. package/dist/cmd/ai/capabilities/show.js +0 -13
  9. package/dist/cmd/ai/capabilities/show.js.map +1 -1
  10. package/dist/cmd/ai/prompt/agent.d.ts.map +1 -1
  11. package/dist/cmd/ai/prompt/agent.js +23 -24
  12. package/dist/cmd/ai/prompt/agent.js.map +1 -1
  13. package/dist/cmd/ai/prompt/api.d.ts.map +1 -1
  14. package/dist/cmd/ai/prompt/api.js +12 -9
  15. package/dist/cmd/ai/prompt/api.js.map +1 -1
  16. package/dist/cmd/build/ast.d.ts +1 -2
  17. package/dist/cmd/build/ast.d.ts.map +1 -1
  18. package/dist/cmd/build/ast.js +261 -260
  19. package/dist/cmd/build/ast.js.map +1 -1
  20. package/dist/cmd/build/bundler.d.ts +2 -1
  21. package/dist/cmd/build/bundler.d.ts.map +1 -1
  22. package/dist/cmd/build/bundler.js +11 -2
  23. package/dist/cmd/build/bundler.js.map +1 -1
  24. package/dist/cmd/build/index.js +1 -1
  25. package/dist/cmd/build/index.js.map +1 -1
  26. package/dist/cmd/build/plugin.d.ts.map +1 -1
  27. package/dist/cmd/build/plugin.js +152 -416
  28. package/dist/cmd/build/plugin.js.map +1 -1
  29. package/dist/cmd/build/route-registry.d.ts +36 -0
  30. package/dist/cmd/build/route-registry.d.ts.map +1 -0
  31. package/dist/cmd/build/route-registry.js +151 -0
  32. package/dist/cmd/build/route-registry.js.map +1 -0
  33. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  34. package/dist/cmd/cloud/deploy.js +1 -0
  35. package/dist/cmd/cloud/deploy.js.map +1 -1
  36. package/dist/cmd/cloud/index.d.ts.map +1 -1
  37. package/dist/cmd/cloud/index.js +0 -2
  38. package/dist/cmd/cloud/index.js.map +1 -1
  39. package/dist/cmd/dev/index.js +3 -3
  40. package/dist/cmd/dev/index.js.map +1 -1
  41. package/dist/cmd/dev/sync.d.ts.map +1 -1
  42. package/dist/cmd/dev/sync.js +0 -15
  43. package/dist/cmd/dev/sync.js.map +1 -1
  44. package/dist/cmd/dev/templates.d.ts.map +1 -1
  45. package/dist/cmd/dev/templates.js +14 -31
  46. package/dist/cmd/dev/templates.js.map +1 -1
  47. package/dist/cmd/profile/create.d.ts.map +1 -1
  48. package/dist/cmd/profile/create.js +0 -1
  49. package/dist/cmd/profile/create.js.map +1 -1
  50. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  51. package/dist/cmd/project/template-flow.js +64 -53
  52. package/dist/cmd/project/template-flow.js.map +1 -1
  53. package/dist/config.d.ts.map +1 -1
  54. package/dist/config.js +0 -3
  55. package/dist/config.js.map +1 -1
  56. package/dist/keychain.d.ts.map +1 -1
  57. package/dist/keychain.js +8 -4
  58. package/dist/keychain.js.map +1 -1
  59. package/dist/tui/box.d.ts +19 -0
  60. package/dist/tui/box.d.ts.map +1 -0
  61. package/dist/tui/box.js +160 -0
  62. package/dist/tui/box.js.map +1 -0
  63. package/dist/tui/colors.d.ts +20 -0
  64. package/dist/tui/colors.d.ts.map +1 -0
  65. package/dist/tui/colors.js +52 -0
  66. package/dist/tui/colors.js.map +1 -0
  67. package/dist/tui/group.d.ts +25 -0
  68. package/dist/tui/group.d.ts.map +1 -0
  69. package/dist/tui/group.js +32 -0
  70. package/dist/tui/group.js.map +1 -0
  71. package/dist/tui/prompt.d.ts +65 -0
  72. package/dist/tui/prompt.d.ts.map +1 -0
  73. package/dist/tui/prompt.js +377 -0
  74. package/dist/tui/prompt.js.map +1 -0
  75. package/dist/tui/symbols.d.ts +32 -0
  76. package/dist/tui/symbols.d.ts.map +1 -0
  77. package/dist/tui/symbols.js +52 -0
  78. package/dist/tui/symbols.js.map +1 -0
  79. package/dist/tui.d.ts +6 -0
  80. package/dist/tui.d.ts.map +1 -1
  81. package/dist/tui.js +6 -0
  82. package/dist/tui.js.map +1 -1
  83. package/dist/types.d.ts +0 -24
  84. package/dist/types.d.ts.map +1 -1
  85. package/dist/types.js +0 -1
  86. package/dist/types.js.map +1 -1
  87. package/package.json +3 -3
  88. package/src/cli.ts +19 -0
  89. package/src/cmd/ai/capabilities/show.ts +0 -13
  90. package/src/cmd/ai/prompt/agent.ts +23 -24
  91. package/src/cmd/ai/prompt/api.ts +12 -9
  92. package/src/cmd/build/ast.ts +364 -334
  93. package/src/cmd/build/bundler.ts +16 -1
  94. package/src/cmd/build/index.ts +1 -1
  95. package/src/cmd/build/plugin.ts +171 -495
  96. package/src/cmd/build/route-registry.ts +198 -0
  97. package/src/cmd/cloud/deploy.ts +1 -0
  98. package/src/cmd/cloud/index.ts +0 -2
  99. package/src/cmd/dev/index.ts +3 -3
  100. package/src/cmd/dev/sync.ts +0 -28
  101. package/src/cmd/dev/templates.ts +14 -31
  102. package/src/cmd/profile/create.ts +0 -1
  103. package/src/cmd/project/template-flow.ts +77 -57
  104. package/src/config.ts +1 -5
  105. package/src/keychain.ts +9 -11
  106. package/src/tui/box.ts +202 -0
  107. package/src/tui/colors.ts +55 -0
  108. package/src/tui/group.ts +56 -0
  109. package/src/tui/prompt.ts +506 -0
  110. package/src/tui/symbols.ts +64 -0
  111. package/src/tui.ts +14 -0
  112. package/src/types.ts +0 -1
  113. package/dist/cmd/build/ast.test.d.ts +0 -2
  114. package/dist/cmd/build/ast.test.d.ts.map +0 -1
  115. package/dist/cmd/build/ast.test.js +0 -339
  116. package/dist/cmd/build/ast.test.js.map +0 -1
  117. package/dist/cmd/build/fix-duplicate-exports.test.d.ts +0 -2
  118. package/dist/cmd/build/fix-duplicate-exports.test.d.ts.map +0 -1
  119. package/dist/cmd/build/fix-duplicate-exports.test.js +0 -300
  120. package/dist/cmd/build/fix-duplicate-exports.test.js.map +0 -1
  121. package/dist/cmd/cloud/objectstore/delete-bucket.d.ts +0 -3
  122. package/dist/cmd/cloud/objectstore/delete-bucket.d.ts.map +0 -1
  123. package/dist/cmd/cloud/objectstore/delete-bucket.js +0 -72
  124. package/dist/cmd/cloud/objectstore/delete-bucket.js.map +0 -1
  125. package/dist/cmd/cloud/objectstore/delete.d.ts +0 -3
  126. package/dist/cmd/cloud/objectstore/delete.d.ts.map +0 -1
  127. package/dist/cmd/cloud/objectstore/delete.js +0 -65
  128. package/dist/cmd/cloud/objectstore/delete.js.map +0 -1
  129. package/dist/cmd/cloud/objectstore/get.d.ts +0 -3
  130. package/dist/cmd/cloud/objectstore/get.d.ts.map +0 -1
  131. package/dist/cmd/cloud/objectstore/get.js +0 -75
  132. package/dist/cmd/cloud/objectstore/get.js.map +0 -1
  133. package/dist/cmd/cloud/objectstore/index.d.ts +0 -3
  134. package/dist/cmd/cloud/objectstore/index.d.ts.map +0 -1
  135. package/dist/cmd/cloud/objectstore/index.js +0 -36
  136. package/dist/cmd/cloud/objectstore/index.js.map +0 -1
  137. package/dist/cmd/cloud/objectstore/list-buckets.d.ts +0 -3
  138. package/dist/cmd/cloud/objectstore/list-buckets.d.ts.map +0 -1
  139. package/dist/cmd/cloud/objectstore/list-buckets.js +0 -46
  140. package/dist/cmd/cloud/objectstore/list-buckets.js.map +0 -1
  141. package/dist/cmd/cloud/objectstore/list-keys.d.ts +0 -3
  142. package/dist/cmd/cloud/objectstore/list-keys.d.ts.map +0 -1
  143. package/dist/cmd/cloud/objectstore/list-keys.js +0 -58
  144. package/dist/cmd/cloud/objectstore/list-keys.js.map +0 -1
  145. package/dist/cmd/cloud/objectstore/put.d.ts +0 -3
  146. package/dist/cmd/cloud/objectstore/put.d.ts.map +0 -1
  147. package/dist/cmd/cloud/objectstore/put.js +0 -66
  148. package/dist/cmd/cloud/objectstore/put.js.map +0 -1
  149. package/dist/cmd/cloud/objectstore/repl.d.ts +0 -3
  150. package/dist/cmd/cloud/objectstore/repl.d.ts.map +0 -1
  151. package/dist/cmd/cloud/objectstore/repl.js +0 -224
  152. package/dist/cmd/cloud/objectstore/repl.js.map +0 -1
  153. package/dist/cmd/cloud/objectstore/url.d.ts +0 -3
  154. package/dist/cmd/cloud/objectstore/url.d.ts.map +0 -1
  155. package/dist/cmd/cloud/objectstore/url.js +0 -64
  156. package/dist/cmd/cloud/objectstore/url.js.map +0 -1
  157. package/dist/cmd/cloud/objectstore/util.d.ts +0 -11
  158. package/dist/cmd/cloud/objectstore/util.d.ts.map +0 -1
  159. package/dist/cmd/cloud/objectstore/util.js +0 -18
  160. package/dist/cmd/cloud/objectstore/util.js.map +0 -1
  161. package/dist/crypto/box.test.d.ts +0 -2
  162. package/dist/crypto/box.test.d.ts.map +0 -1
  163. package/dist/crypto/box.test.js +0 -317
  164. package/dist/crypto/box.test.js.map +0 -1
  165. package/dist/env-util.test.d.ts +0 -2
  166. package/dist/env-util.test.d.ts.map +0 -1
  167. package/dist/env-util.test.js +0 -146
  168. package/dist/env-util.test.js.map +0 -1
  169. package/src/cmd/build/ast.test.ts +0 -418
  170. package/src/cmd/build/fix-duplicate-exports.test.ts +0 -387
  171. package/src/cmd/cloud/objectstore/delete-bucket.ts +0 -77
  172. package/src/cmd/cloud/objectstore/delete.ts +0 -67
  173. package/src/cmd/cloud/objectstore/get.ts +0 -77
  174. package/src/cmd/cloud/objectstore/index.ts +0 -36
  175. package/src/cmd/cloud/objectstore/list-buckets.ts +0 -51
  176. package/src/cmd/cloud/objectstore/list-keys.ts +0 -63
  177. package/src/cmd/cloud/objectstore/put.ts +0 -74
  178. package/src/cmd/cloud/objectstore/repl.ts +0 -239
  179. package/src/cmd/cloud/objectstore/url.ts +0 -67
  180. package/src/cmd/cloud/objectstore/util.ts +0 -29
  181. package/src/crypto/box.test.ts +0 -431
  182. 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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ast.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ast.test.d.ts","sourceRoot":"","sources":["../../../src/cmd/build/ast.test.ts"],"names":[],"mappings":""}