@agentuity/cli 2.0.12 → 2.0.13

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 (67) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +15 -8
  3. package/dist/cli.js.map +1 -1
  4. package/dist/cmd/cloud/sandbox/snapshot/create.js +4 -4
  5. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
  6. package/dist/cmd/coder/workspace/common.d.ts +29 -0
  7. package/dist/cmd/coder/workspace/common.d.ts.map +1 -0
  8. package/dist/cmd/coder/workspace/common.js +83 -0
  9. package/dist/cmd/coder/workspace/common.js.map +1 -0
  10. package/dist/cmd/coder/workspace/create.d.ts.map +1 -1
  11. package/dist/cmd/coder/workspace/create.js +34 -37
  12. package/dist/cmd/coder/workspace/create.js.map +1 -1
  13. package/dist/cmd/coder/workspace/get.d.ts.map +1 -1
  14. package/dist/cmd/coder/workspace/get.js +2 -5
  15. package/dist/cmd/coder/workspace/get.js.map +1 -1
  16. package/dist/cmd/coder/workspace/index.d.ts.map +1 -1
  17. package/dist/cmd/coder/workspace/index.js +10 -0
  18. package/dist/cmd/coder/workspace/index.js.map +1 -1
  19. package/dist/cmd/coder/workspace/list.d.ts.map +1 -1
  20. package/dist/cmd/coder/workspace/list.js +4 -0
  21. package/dist/cmd/coder/workspace/list.js.map +1 -1
  22. package/dist/cmd/coder/workspace/refresh.d.ts +2 -0
  23. package/dist/cmd/coder/workspace/refresh.d.ts.map +1 -0
  24. package/dist/cmd/coder/workspace/refresh.js +59 -0
  25. package/dist/cmd/coder/workspace/refresh.js.map +1 -0
  26. package/dist/cmd/coder/workspace/update.d.ts +2 -0
  27. package/dist/cmd/coder/workspace/update.d.ts.map +1 -0
  28. package/dist/cmd/coder/workspace/update.js +131 -0
  29. package/dist/cmd/coder/workspace/update.js.map +1 -0
  30. package/dist/cmd/coder/workspace/validate-dependencies.d.ts +2 -0
  31. package/dist/cmd/coder/workspace/validate-dependencies.d.ts.map +1 -0
  32. package/dist/cmd/coder/workspace/validate-dependencies.js +70 -0
  33. package/dist/cmd/coder/workspace/validate-dependencies.js.map +1 -0
  34. package/dist/cmd/project/random-name.d.ts +17 -0
  35. package/dist/cmd/project/random-name.d.ts.map +1 -0
  36. package/dist/cmd/project/random-name.js +144 -0
  37. package/dist/cmd/project/random-name.js.map +1 -0
  38. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  39. package/dist/cmd/project/template-flow.js +181 -153
  40. package/dist/cmd/project/template-flow.js.map +1 -1
  41. package/dist/composite-logger.d.ts.map +1 -1
  42. package/dist/composite-logger.js +19 -0
  43. package/dist/composite-logger.js.map +1 -1
  44. package/dist/config.d.ts +18 -16
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +46 -16
  47. package/dist/config.js.map +1 -1
  48. package/dist/tui/prompt.d.ts +29 -0
  49. package/dist/tui/prompt.d.ts.map +1 -1
  50. package/dist/tui/prompt.js +180 -8
  51. package/dist/tui/prompt.js.map +1 -1
  52. package/package.json +7 -7
  53. package/src/cli.ts +30 -8
  54. package/src/cmd/cloud/sandbox/snapshot/create.ts +6 -6
  55. package/src/cmd/coder/workspace/common.ts +103 -0
  56. package/src/cmd/coder/workspace/create.ts +39 -43
  57. package/src/cmd/coder/workspace/get.ts +2 -5
  58. package/src/cmd/coder/workspace/index.ts +10 -0
  59. package/src/cmd/coder/workspace/list.ts +4 -0
  60. package/src/cmd/coder/workspace/refresh.ts +63 -0
  61. package/src/cmd/coder/workspace/update.ts +154 -0
  62. package/src/cmd/coder/workspace/validate-dependencies.ts +75 -0
  63. package/src/cmd/project/random-name.ts +152 -0
  64. package/src/cmd/project/template-flow.ts +199 -161
  65. package/src/composite-logger.ts +20 -0
  66. package/src/config.ts +69 -19
  67. package/src/tui/prompt.ts +214 -8
package/src/tui/prompt.ts CHANGED
@@ -14,6 +14,12 @@ export interface TextOptions {
14
14
  message: string;
15
15
  initial?: string;
16
16
  hint?: string;
17
+ /**
18
+ * Pre-generated suggestion shown dim in the hint line.
19
+ * Submitting empty input accepts the placeholder.
20
+ * Unlike `initial`, this is rendered visibly so the user knows what they'll get.
21
+ */
22
+ placeholder?: string;
17
23
  validate?: (value: string) => boolean | string | Promise<boolean | string>;
18
24
  }
19
25
 
@@ -92,27 +98,39 @@ export class PromptFlow {
92
98
 
93
99
  /**
94
100
  * Text input prompt
101
+ *
102
+ * Two render paths:
103
+ * - With `placeholder`: custom raw-keypress renderer that paints the placeholder
104
+ * inline as dim ghost text at the cursor (autofill style). Vanishes on the first
105
+ * keystroke; Enter on an empty buffer accepts the placeholder.
106
+ * - Without `placeholder`: original readline-based renderer (untouched).
95
107
  */
96
108
  async text(options: TextOptions): Promise<string> {
97
- const { message, validate } = options;
98
- const initial = options.initial ?? '';
99
- const hasDefault = options.initial !== undefined;
109
+ const { message, validate, placeholder } = options;
110
+ // `placeholder` acts as a visible default: empty submit resolves to it.
111
+ // `initial` (legacy, invisible) still works but `placeholder` takes precedence.
112
+ const fallback = placeholder ?? options.initial ?? '';
113
+ const hasDefault = placeholder !== undefined || options.initial !== undefined;
100
114
 
101
115
  if (!this.isInteractive()) {
102
116
  if (hasDefault) {
103
- const validationResult = validate ? await validate(initial) : true;
117
+ const validationResult = validate ? await validate(fallback) : true;
104
118
  if (validationResult === true) {
105
- return initial;
119
+ return fallback;
106
120
  }
107
121
  // Validation failed - include the error message if it's a string
108
122
  const errorDetail = typeof validationResult === 'string' ? `: ${validationResult}` : '';
109
123
  throw this.nonInteractiveError(
110
- `Cannot prompt for "${message}" in non-interactive mode. Validation failed for default value "${initial}"${errorDetail}.`
124
+ `Cannot prompt for "${message}" in non-interactive mode. Validation failed for default value "${fallback}"${errorDetail}.`
111
125
  );
112
126
  }
113
127
  throw this.nonInteractiveError(`Cannot prompt for "${message}" in non-interactive mode.`);
114
128
  }
115
129
 
130
+ if (placeholder) {
131
+ return this.textWithGhost(options, placeholder);
132
+ }
133
+
116
134
  return new Promise((resolve, reject) => {
117
135
  const rl = readline.createInterface({
118
136
  input: process.stdin,
@@ -139,8 +157,8 @@ export class PromptFlow {
139
157
 
140
158
  rl.on('line', async (input) => {
141
159
  const trimmed = input.trim();
142
- // After a validation error, require explicit input - don't fall back to initial
143
- const value = trimmed.length > 0 ? trimmed : hadValidationError ? '' : initial;
160
+ // After a validation error, require explicit input - don't fall back to default.
161
+ const value = trimmed.length > 0 ? trimmed : hadValidationError ? '' : fallback;
144
162
 
145
163
  // Validate
146
164
  if (validate) {
@@ -229,6 +247,194 @@ export class PromptFlow {
229
247
  });
230
248
  }
231
249
 
250
+ /**
251
+ * Text input with inline ghost-text placeholder (autofill style).
252
+ *
253
+ * Layout:
254
+ * ◆ <message>
255
+ * │ <hint> (optional)
256
+ * │ <typed>│<ghost> ghost is dim, vanishes on first keystroke
257
+ *
258
+ * Behavior:
259
+ * - Typing any char hides the ghost permanently for this prompt instance.
260
+ * - Backspacing back to empty does NOT bring the ghost back.
261
+ * - Enter on empty buffer → resolves to placeholder.
262
+ * - Enter with typed text → resolves to typed text.
263
+ * - Validation error: shows inline error, ghost stays gone, user must type.
264
+ * - Ctrl+C: cancels.
265
+ */
266
+ private async textWithGhost(options: TextOptions, placeholder: string): Promise<string> {
267
+ const { message, validate, hint } = options;
268
+
269
+ return new Promise((resolve, reject) => {
270
+ let buffer = '';
271
+ // Tracks whether the ghost should still be visible. Once any printable key is
272
+ // pressed it goes false and stays false for the rest of this prompt.
273
+ let ghostVisible = true;
274
+ let hasError = false;
275
+ let errorMsg = '';
276
+
277
+ const inputPrefix = `${colors.secondary(symbols.bar)} `;
278
+ // Visible-character length of the input-line prefix ("│ " = 3 cells).
279
+ const PREFIX_VISIBLE = 3;
280
+
281
+ /**
282
+ * Repaint everything from the message line down. Cursor must be on the
283
+ * message line (column 0) when this is called for the first time, or we
284
+ * just moved up to it after a clear.
285
+ */
286
+ const paint = () => {
287
+ const symbol = hasError ? colors.error(symbols.error) : colors.active(symbols.active);
288
+ process.stdout.write(`${symbol} ${message}\n`);
289
+
290
+ if (hasError) {
291
+ process.stdout.write(
292
+ `${colors.secondary(symbols.bar)} ${colors.error(errorMsg)}\n`
293
+ );
294
+ } else if (hint) {
295
+ process.stdout.write(`${colors.secondary(symbols.bar)} ${colors.muted(hint)}\n`);
296
+ }
297
+
298
+ // Input line.
299
+ process.stdout.write(inputPrefix);
300
+ process.stdout.write(buffer);
301
+
302
+ if (ghostVisible && buffer.length === 0) {
303
+ // Paint the ghost, then move the cursor back to the start of it so the
304
+ // caret sits where the user would start typing.
305
+ process.stdout.write(colors.muted(placeholder));
306
+ readline.moveCursor(process.stdout, -placeholder.length, 0);
307
+ }
308
+ };
309
+
310
+ /**
311
+ * Number of terminal lines currently occupied by our render, so we know
312
+ * how many to clear on the next repaint.
313
+ * Always: message (1) + hint-or-error (0/1) + input (1).
314
+ */
315
+ const renderedLines = (): number => {
316
+ let n = 1; // message
317
+ if (hasError || hint) n += 1;
318
+ n += 1; // input
319
+ return n;
320
+ };
321
+
322
+ const repaint = () => {
323
+ // Move cursor to column 0, then up to the start of our render block, then clear.
324
+ readline.cursorTo(process.stdout, 0);
325
+ readline.moveCursor(process.stdout, 0, -(renderedLines() - 1));
326
+ readline.clearScreenDown(process.stdout);
327
+ paint();
328
+ };
329
+
330
+ // Resume stdin if it was paused by a prior prompt.
331
+ if (process.stdin.isTTY && process.stdin.isPaused()) {
332
+ process.stdin.resume();
333
+ }
334
+
335
+ readline.emitKeypressEvents(process.stdin);
336
+ if (process.stdin.isTTY) {
337
+ process.stdin.setRawMode(true);
338
+ }
339
+
340
+ // Initial paint.
341
+ paint();
342
+
343
+ const cleanup = () => {
344
+ process.stdin.removeListener('keypress', onKeypress);
345
+ if (process.stdin.isTTY) {
346
+ process.stdin.setRawMode(false);
347
+ process.stdin.pause();
348
+ }
349
+ };
350
+
351
+ const finalize = (value: string) => {
352
+ // Repaint as completed: replace whole render block with the completed lines.
353
+ readline.cursorTo(process.stdout, 0);
354
+ readline.moveCursor(process.stdout, 0, -(renderedLines() - 1));
355
+ readline.clearScreenDown(process.stdout);
356
+
357
+ if (value === '') {
358
+ process.stdout.write(
359
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)}\n`
360
+ );
361
+ } else {
362
+ process.stdout.write(
363
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)} ${colors.muted(value)}\n${colors.secondary(symbols.bar)}\n`
364
+ );
365
+ }
366
+
367
+ this.states.push({ type: 'completed', message, value });
368
+ cleanup();
369
+ resolve(value);
370
+ };
371
+
372
+ const onKeypress = async (str: string, key: KeypressEvent) => {
373
+ if (key.ctrl && key.name === 'c') {
374
+ cleanup();
375
+ console.log('\n');
376
+ this.cancel('Operation cancelled');
377
+ reject(new Error('User cancelled'));
378
+ return;
379
+ }
380
+
381
+ if (key.name === 'return') {
382
+ const trimmed = buffer.trim();
383
+ // Empty submit accepts the placeholder, but only if no error has occurred
384
+ // (after an error the user must type explicitly — same rule the readline
385
+ // path uses).
386
+ const value = trimmed.length > 0 ? trimmed : hasError ? '' : placeholder;
387
+
388
+ if (validate) {
389
+ try {
390
+ const result = await validate(value);
391
+ if (result !== true) {
392
+ errorMsg = typeof result === 'string' ? result : 'Invalid input';
393
+ hasError = true;
394
+ ghostVisible = false;
395
+ repaint();
396
+ return;
397
+ }
398
+ } catch (err) {
399
+ errorMsg = err instanceof Error ? err.message : 'Validation failed';
400
+ hasError = true;
401
+ ghostVisible = false;
402
+ repaint();
403
+ return;
404
+ }
405
+ }
406
+
407
+ finalize(value);
408
+ return;
409
+ }
410
+
411
+ if (key.name === 'backspace') {
412
+ if (buffer.length > 0) {
413
+ buffer = buffer.slice(0, -1);
414
+ repaint();
415
+ }
416
+ return;
417
+ }
418
+
419
+ // Printable single character (ignore arrow keys, function keys, etc.).
420
+ if (str && str.length === 1 && !key.ctrl && str >= ' ' && str !== '\x7f') {
421
+ buffer += str;
422
+ ghostVisible = false;
423
+ repaint();
424
+ return;
425
+ }
426
+
427
+ // Everything else (arrows, tab, etc.) is ignored.
428
+ };
429
+
430
+ // Mark the prefix length as used so the unused-var rule doesn't trip when we
431
+ // extend this in future. (Keeping it documented for cursor-math sanity.)
432
+ void PREFIX_VISIBLE;
433
+
434
+ process.stdin.on('keypress', onKeypress);
435
+ });
436
+ }
437
+
232
438
  /**
233
439
  * Confirm (yes/no) prompt
234
440
  */