@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.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +15 -8
- package/dist/cli.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/create.js +4 -4
- package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
- package/dist/cmd/coder/workspace/common.d.ts +29 -0
- package/dist/cmd/coder/workspace/common.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/common.js +83 -0
- package/dist/cmd/coder/workspace/common.js.map +1 -0
- package/dist/cmd/coder/workspace/create.d.ts.map +1 -1
- package/dist/cmd/coder/workspace/create.js +34 -37
- package/dist/cmd/coder/workspace/create.js.map +1 -1
- package/dist/cmd/coder/workspace/get.d.ts.map +1 -1
- package/dist/cmd/coder/workspace/get.js +2 -5
- package/dist/cmd/coder/workspace/get.js.map +1 -1
- package/dist/cmd/coder/workspace/index.d.ts.map +1 -1
- package/dist/cmd/coder/workspace/index.js +10 -0
- package/dist/cmd/coder/workspace/index.js.map +1 -1
- package/dist/cmd/coder/workspace/list.d.ts.map +1 -1
- package/dist/cmd/coder/workspace/list.js +4 -0
- package/dist/cmd/coder/workspace/list.js.map +1 -1
- package/dist/cmd/coder/workspace/refresh.d.ts +2 -0
- package/dist/cmd/coder/workspace/refresh.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/refresh.js +59 -0
- package/dist/cmd/coder/workspace/refresh.js.map +1 -0
- package/dist/cmd/coder/workspace/update.d.ts +2 -0
- package/dist/cmd/coder/workspace/update.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/update.js +131 -0
- package/dist/cmd/coder/workspace/update.js.map +1 -0
- package/dist/cmd/coder/workspace/validate-dependencies.d.ts +2 -0
- package/dist/cmd/coder/workspace/validate-dependencies.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/validate-dependencies.js +70 -0
- package/dist/cmd/coder/workspace/validate-dependencies.js.map +1 -0
- package/dist/cmd/project/random-name.d.ts +17 -0
- package/dist/cmd/project/random-name.d.ts.map +1 -0
- package/dist/cmd/project/random-name.js +144 -0
- package/dist/cmd/project/random-name.js.map +1 -0
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +181 -153
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/composite-logger.d.ts.map +1 -1
- package/dist/composite-logger.js +19 -0
- package/dist/composite-logger.js.map +1 -1
- package/dist/config.d.ts +18 -16
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +46 -16
- package/dist/config.js.map +1 -1
- package/dist/tui/prompt.d.ts +29 -0
- package/dist/tui/prompt.d.ts.map +1 -1
- package/dist/tui/prompt.js +180 -8
- package/dist/tui/prompt.js.map +1 -1
- package/package.json +7 -7
- package/src/cli.ts +30 -8
- package/src/cmd/cloud/sandbox/snapshot/create.ts +6 -6
- package/src/cmd/coder/workspace/common.ts +103 -0
- package/src/cmd/coder/workspace/create.ts +39 -43
- package/src/cmd/coder/workspace/get.ts +2 -5
- package/src/cmd/coder/workspace/index.ts +10 -0
- package/src/cmd/coder/workspace/list.ts +4 -0
- package/src/cmd/coder/workspace/refresh.ts +63 -0
- package/src/cmd/coder/workspace/update.ts +154 -0
- package/src/cmd/coder/workspace/validate-dependencies.ts +75 -0
- package/src/cmd/project/random-name.ts +152 -0
- package/src/cmd/project/template-flow.ts +199 -161
- package/src/composite-logger.ts +20 -0
- package/src/config.ts +69 -19
- 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
|
-
|
|
99
|
-
|
|
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(
|
|
117
|
+
const validationResult = validate ? await validate(fallback) : true;
|
|
104
118
|
if (validationResult === true) {
|
|
105
|
-
return
|
|
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 "${
|
|
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
|
|
143
|
-
const value = trimmed.length > 0 ? trimmed : hadValidationError ? '' :
|
|
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
|
*/
|