@topcli/prompts 1.8.1 → 1.10.0

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/index.js CHANGED
@@ -7,6 +7,7 @@ import wcwidth from "@topcli/wcwidth";
7
7
  import { EOL } from "os";
8
8
  import { createInterface } from "readline";
9
9
  import { Writable } from "stream";
10
+ import EventEmitter from "events";
10
11
 
11
12
  // src/utils.ts
12
13
  import process2 from "process";
@@ -72,25 +73,43 @@ var PromptAgent = class _PromptAgent {
72
73
  }
73
74
  };
74
75
 
76
+ // src/errors/abort.ts
77
+ var AbortError = class extends Error {
78
+ constructor(message) {
79
+ super(message);
80
+ this.name = "AbortError";
81
+ }
82
+ };
83
+
75
84
  // src/prompts/abstract.ts
76
- var AbstractPrompt = class _AbstractPrompt {
85
+ var AbstractPrompt = class _AbstractPrompt extends EventEmitter {
77
86
  stdin;
78
87
  stdout;
79
88
  message;
89
+ signal;
80
90
  history;
81
91
  agent;
82
92
  mute;
83
93
  rl;
84
- constructor(message, input = process.stdin, output = process.stdout) {
94
+ #signalHandler;
95
+ constructor(options) {
96
+ super();
85
97
  if (this.constructor === _AbstractPrompt) {
86
98
  throw new Error("AbstractPrompt can't be instantiated.");
87
99
  }
100
+ const {
101
+ stdin: input = process.stdin,
102
+ stdout: output = process.stdout,
103
+ message,
104
+ signal
105
+ } = options;
88
106
  if (typeof message !== "string") {
89
107
  throw new TypeError(`message must be string, ${typeof message} given.`);
90
108
  }
91
109
  this.stdin = input;
92
110
  this.stdout = output;
93
111
  this.message = message;
112
+ this.signal = signal;
94
113
  this.history = [];
95
114
  this.agent = PromptAgent.agent();
96
115
  this.mute = false;
@@ -101,7 +120,7 @@ var AbstractPrompt = class _AbstractPrompt {
101
120
  input,
102
121
  output: new Writable({
103
122
  write: (chunk, encoding, callback) => {
104
- if (!this.mute) {
123
+ if (!this.mute && chunk) {
105
124
  this.stdout.write(chunk, encoding);
106
125
  }
107
126
  callback();
@@ -109,6 +128,16 @@ var AbstractPrompt = class _AbstractPrompt {
109
128
  }),
110
129
  terminal: true
111
130
  });
131
+ if (this.signal) {
132
+ this.#signalHandler = () => {
133
+ this.rl.close();
134
+ for (let i = 0; i < this.history.length; i++) {
135
+ this.clearLastLine();
136
+ }
137
+ this.emit("error", new AbortError("Prompt aborted"));
138
+ };
139
+ this.signal.addEventListener("abort", this.#signalHandler, { once: true });
140
+ }
112
141
  }
113
142
  write(data) {
114
143
  const formattedData = stripAnsi(data).replace(EOL, "");
@@ -128,6 +157,9 @@ var AbstractPrompt = class _AbstractPrompt {
128
157
  }
129
158
  destroy() {
130
159
  this.rl.close();
160
+ if (this.signal) {
161
+ this.signal.removeEventListener("abort", this.#signalHandler);
162
+ }
131
163
  }
132
164
  };
133
165
 
@@ -175,15 +207,14 @@ var QuestionPrompt = class extends AbstractPrompt {
175
207
  answerBuffer;
176
208
  #validators;
177
209
  #secure;
178
- constructor(message, options = {}) {
210
+ constructor(options) {
179
211
  const {
180
- stdin = process.stdin,
181
- stdout = process.stdout,
182
212
  defaultValue,
183
213
  validators = [],
184
- secure = false
214
+ secure = false,
215
+ ...baseOptions
185
216
  } = options;
186
- super(message, stdin, stdout);
217
+ super({ ...baseOptions });
187
218
  if (defaultValue && typeof defaultValue !== "string") {
188
219
  throw new TypeError("defaultValue must be a string");
189
220
  }
@@ -196,6 +227,7 @@ var QuestionPrompt = class extends AbstractPrompt {
196
227
  #question() {
197
228
  return new Promise((resolve) => {
198
229
  const questionQuery = this.#getQuestionQuery();
230
+ this.history.push(questionQuery);
199
231
  this.rl.question(questionQuery, (answer) => {
200
232
  this.history.push(questionQuery + answer);
201
233
  this.mute = false;
@@ -233,24 +265,30 @@ var QuestionPrompt = class extends AbstractPrompt {
233
265
  this.answerBuffer = void 0;
234
266
  this.#writeAnswer();
235
267
  }
236
- async question() {
237
- this.answer = this.agent.nextAnswers.shift();
238
- if (this.answer !== void 0) {
239
- this.#writeAnswer();
240
- this.destroy();
241
- return this.answer;
242
- }
243
- this.answer = await this.#question();
244
- if (this.answer === "" && this.defaultValue) {
245
- this.answer = this.defaultValue;
246
- }
247
- this.#onQuestionAnswer();
248
- while (this.answerBuffer !== void 0) {
249
- this.answer = await this.answerBuffer;
268
+ question() {
269
+ return new Promise(async (resolve, reject) => {
270
+ this.answer = this.agent.nextAnswers.shift();
271
+ if (this.answer !== void 0) {
272
+ this.#writeAnswer();
273
+ this.destroy();
274
+ resolve(this.answer);
275
+ return;
276
+ }
277
+ this.once("error", (error) => {
278
+ reject(error);
279
+ });
280
+ this.answer = await this.#question();
281
+ if (this.answer === "" && this.defaultValue) {
282
+ this.answer = this.defaultValue;
283
+ }
250
284
  this.#onQuestionAnswer();
251
- }
252
- this.destroy();
253
- return this.answer;
285
+ while (this.answerBuffer !== void 0) {
286
+ this.answer = await this.answerBuffer;
287
+ this.#onQuestionAnswer();
288
+ }
289
+ this.destroy();
290
+ resolve(this.answer);
291
+ });
254
292
  }
255
293
  };
256
294
 
@@ -277,13 +315,12 @@ var ConfirmPrompt = class extends AbstractPrompt {
277
315
  fastAnswer;
278
316
  #boundKeyPressEvent;
279
317
  #boundExitEvent;
280
- constructor(message, options = {}) {
318
+ constructor(options) {
281
319
  const {
282
- stdin = process.stdin,
283
- stdout = process.stdout,
284
- initial = false
320
+ initial = false,
321
+ ...baseOptions
285
322
  } = options;
286
- super(message, stdin, stdout);
323
+ super({ ...baseOptions });
287
324
  this.initial = initial;
288
325
  this.selectedValue = initial;
289
326
  }
@@ -339,33 +376,39 @@ var ConfirmPrompt = class extends AbstractPrompt {
339
376
  return `${query} ${this.#getHint()}`;
340
377
  }
341
378
  #onQuestionAnswer() {
342
- const defaultLines = this.fastAnswer ? 0 : 1;
379
+ this.clearLastLine();
343
380
  this.stdout.moveCursor(
344
381
  -this.stdout.columns,
345
- -(Math.floor(wcwidth2(stripAnsi(this.#getQuestionQuery())) / this.stdout.columns) || defaultLines)
382
+ -Math.floor(wcwidth2(stripAnsi(this.#getQuestionQuery())) / this.stdout.columns)
346
383
  );
347
384
  this.stdout.clearScreenDown();
348
385
  this.write(`${this.selectedValue ? SYMBOLS.Tick : SYMBOLS.Cross} ${kleur3.bold(this.message)}${EOL3}`);
349
386
  }
350
- async confirm() {
351
- const answer = this.agent.nextAnswers.shift();
352
- if (answer !== void 0) {
353
- this.selectedValue = answer;
354
- this.#onQuestionAnswer();
355
- this.destroy();
356
- return answer;
357
- }
358
- this.write(SYMBOLS.HideCursor);
359
- try {
360
- await this.#question();
361
- this.#onQuestionAnswer();
362
- return this.selectedValue;
363
- } finally {
364
- this.write(SYMBOLS.ShowCursor);
365
- this.#onProcessExit();
366
- process.off("exit", this.#boundExitEvent);
367
- this.destroy();
368
- }
387
+ confirm() {
388
+ return new Promise(async (resolve, reject) => {
389
+ const answer = this.agent.nextAnswers.shift();
390
+ if (answer !== void 0) {
391
+ this.selectedValue = answer;
392
+ this.#onQuestionAnswer();
393
+ this.destroy();
394
+ resolve(answer);
395
+ return;
396
+ }
397
+ this.once("error", (error) => {
398
+ reject(error);
399
+ });
400
+ this.write(SYMBOLS.HideCursor);
401
+ try {
402
+ await this.#question();
403
+ this.#onQuestionAnswer();
404
+ resolve(this.selectedValue);
405
+ } finally {
406
+ this.write(SYMBOLS.ShowCursor);
407
+ this.#onProcessExit();
408
+ process.off("exit", this.#boundExitEvent);
409
+ this.destroy();
410
+ }
411
+ });
369
412
  }
370
413
  };
371
414
 
@@ -373,50 +416,75 @@ var ConfirmPrompt = class extends AbstractPrompt {
373
416
  import { EOL as EOL4 } from "os";
374
417
  import kleur4 from "kleur";
375
418
  import wcwidth3 from "@topcli/wcwidth";
419
+ var kRequiredChoiceProperties = ["label", "value"];
376
420
  var SelectPrompt = class extends AbstractPrompt {
377
421
  #boundExitEvent = () => void 0;
378
422
  #boundKeyPressEvent = () => void 0;
423
+ #validators;
379
424
  activeIndex = 0;
380
- selectedIndexes = [];
381
425
  questionMessage;
382
- longestChoicelength;
426
+ autocompleteValue = "";
383
427
  options;
384
428
  lastRender;
385
429
  get choices() {
386
430
  return this.options.choices;
387
431
  }
388
- constructor(message, options) {
389
- const {
390
- stdin = process.stdin,
391
- stdout = process.stdout,
392
- choices
393
- } = options ?? {};
394
- super(message, stdin, stdout);
395
- if (!options) {
396
- this.destroy();
397
- throw new TypeError("Missing required options");
432
+ get filteredChoices() {
433
+ if (!(this.options.autocomplete && this.autocompleteValue.length > 0)) {
434
+ return this.choices;
398
435
  }
436
+ const isCaseSensitive = this.options.caseSensitive;
437
+ const autocompleteValue = isCaseSensitive ? this.autocompleteValue : this.autocompleteValue.toLowerCase();
438
+ return this.choices.filter((choice) => this.#filterChoice(choice, autocompleteValue, isCaseSensitive));
439
+ }
440
+ #filterChoice(choice, autocompleteValue, isCaseSensitive = false) {
441
+ const choiceValue = typeof choice === "string" ? isCaseSensitive ? choice : choice.toLowerCase() : isCaseSensitive ? choice.label : choice.label.toLowerCase();
442
+ if (autocompleteValue.includes(" ")) {
443
+ return this.#filterMultipleWords(choiceValue, autocompleteValue, isCaseSensitive);
444
+ }
445
+ return choiceValue.includes(autocompleteValue);
446
+ }
447
+ #filterMultipleWords(choiceValue, autocompleteValue, isCaseSensitive) {
448
+ return autocompleteValue.split(" ").every((word) => {
449
+ const wordValue = isCaseSensitive ? word : word.toLowerCase();
450
+ return choiceValue.includes(wordValue) || choiceValue.includes(autocompleteValue);
451
+ });
452
+ }
453
+ get longestChoice() {
454
+ return Math.max(...this.filteredChoices.map((choice) => {
455
+ if (typeof choice === "string") {
456
+ return choice.length;
457
+ }
458
+ return choice.label.length;
459
+ }));
460
+ }
461
+ constructor(options) {
462
+ const {
463
+ choices,
464
+ validators = [],
465
+ ...baseOptions
466
+ } = options;
467
+ super({ ...baseOptions });
399
468
  this.options = options;
400
469
  if (!choices?.length) {
401
470
  this.destroy();
402
471
  throw new TypeError("Missing required param: choices");
403
472
  }
404
- this.longestChoicelength = Math.max(...choices.map((choice) => {
473
+ this.#validators = validators;
474
+ for (const choice of choices) {
405
475
  if (typeof choice === "string") {
406
- return choice.length;
476
+ continue;
407
477
  }
408
- const kRequiredChoiceProperties2 = ["label", "value"];
409
- for (const prop of kRequiredChoiceProperties2) {
478
+ for (const prop of kRequiredChoiceProperties) {
410
479
  if (!choice[prop]) {
411
480
  this.destroy();
412
481
  throw new TypeError(`Missing ${prop} for choice ${JSON.stringify(choice)}`);
413
482
  }
414
483
  }
415
- return choice.label.length;
416
- }));
484
+ }
417
485
  }
418
486
  #getFormattedChoice(choiceIndex) {
419
- const choice = this.choices[choiceIndex];
487
+ const choice = this.filteredChoices[choiceIndex];
420
488
  if (typeof choice === "string") {
421
489
  return { value: choice, label: choice };
422
490
  }
@@ -424,21 +492,24 @@ var SelectPrompt = class extends AbstractPrompt {
424
492
  }
425
493
  #getVisibleChoices() {
426
494
  const maxVisible = this.options.maxVisible || 8;
427
- let startIndex = Math.min(this.choices.length - maxVisible, this.activeIndex - Math.floor(maxVisible / 2));
495
+ let startIndex = Math.min(this.filteredChoices.length - maxVisible, this.activeIndex - Math.floor(maxVisible / 2));
428
496
  if (startIndex < 0) {
429
497
  startIndex = 0;
430
498
  }
431
- const endIndex = Math.min(startIndex + maxVisible, this.choices.length);
499
+ const endIndex = Math.min(startIndex + maxVisible, this.filteredChoices.length);
432
500
  return { startIndex, endIndex };
433
501
  }
434
502
  #showChoices() {
435
503
  const { startIndex, endIndex } = this.#getVisibleChoices();
436
504
  this.lastRender = { startIndex, endIndex };
505
+ if (this.options.autocomplete) {
506
+ this.write(`${SYMBOLS.Pointer} ${this.autocompleteValue}${EOL4}`);
507
+ }
437
508
  for (let choiceIndex = startIndex; choiceIndex < endIndex; choiceIndex++) {
438
509
  const choice = this.#getFormattedChoice(choiceIndex);
439
510
  const isChoiceSelected = choiceIndex === this.activeIndex;
440
511
  const showPreviousChoicesArrow = startIndex > 0 && choiceIndex === startIndex;
441
- const showNextChoicesArrow = endIndex < this.choices.length && choiceIndex === endIndex - 1;
512
+ const showNextChoicesArrow = endIndex < this.filteredChoices.length && choiceIndex === endIndex - 1;
442
513
  let prefixArrow = " ";
443
514
  if (showPreviousChoicesArrow) {
444
515
  prefixArrow = SYMBOLS.Previous;
@@ -447,16 +518,17 @@ var SelectPrompt = class extends AbstractPrompt {
447
518
  }
448
519
  const prefix = `${prefixArrow}${isChoiceSelected ? `${SYMBOLS.Pointer} ` : " "}`;
449
520
  const formattedLabel = choice.label.padEnd(
450
- this.longestChoicelength < 10 ? this.longestChoicelength : 0
521
+ this.longestChoice < 10 ? this.longestChoice : 0
451
522
  );
452
523
  const formattedDescription = choice.description ? ` - ${choice.description}` : "";
453
524
  const color = isChoiceSelected ? kleur4.white().bold : kleur4.gray;
454
- const str = color(`${prefix}${formattedLabel}${formattedDescription}${EOL4}`);
525
+ const str = `${prefix}${color(`${formattedLabel}${formattedDescription}`)}${EOL4}`;
455
526
  this.write(str);
456
527
  }
457
528
  }
458
529
  #showAnsweredQuestion(choice) {
459
- const prefix = `${SYMBOLS.Tick} ${kleur4.bold(this.message)} ${SYMBOLS.Pointer}`;
530
+ const symbolPrefix = choice === "" ? SYMBOLS.Cross : SYMBOLS.Tick;
531
+ const prefix = `${symbolPrefix} ${kleur4.bold(this.message)} ${SYMBOLS.Pointer}`;
460
532
  const formattedChoice = kleur4.yellow(typeof choice === "string" ? choice : choice.label);
461
533
  this.write(`${prefix} ${formattedChoice}${EOL4}`);
462
534
  }
@@ -469,17 +541,25 @@ var SelectPrompt = class extends AbstractPrompt {
469
541
  #onKeypress(...args) {
470
542
  const [resolve, render, , key] = args;
471
543
  if (key.name === "up") {
472
- this.activeIndex = this.activeIndex === 0 ? this.choices.length - 1 : this.activeIndex - 1;
544
+ this.activeIndex = this.activeIndex === 0 ? this.filteredChoices.length - 1 : this.activeIndex - 1;
473
545
  render();
474
546
  } else if (key.name === "down") {
475
- this.activeIndex = this.activeIndex === this.choices.length - 1 ? 0 : this.activeIndex + 1;
547
+ this.activeIndex = this.activeIndex === this.filteredChoices.length - 1 ? 0 : this.activeIndex + 1;
476
548
  render();
477
549
  } else if (key.name === "return") {
550
+ const choice = this.filteredChoices[this.activeIndex] || "";
551
+ const label = typeof choice === "string" ? choice : choice.label;
552
+ const value = typeof choice === "string" ? choice : choice.value;
553
+ for (const validator of this.#validators) {
554
+ if (!validator.validate(value)) {
555
+ const error = validator.error(value);
556
+ render({ error });
557
+ return;
558
+ }
559
+ }
478
560
  render({ clearRender: true });
479
- const currentChoice = this.choices[this.activeIndex];
480
- const value = typeof currentChoice === "string" ? currentChoice : currentChoice.value;
481
561
  if (!this.options.ignoreValues?.includes(value)) {
482
- this.#showAnsweredQuestion(currentChoice);
562
+ this.#showAnsweredQuestion(label);
483
563
  }
484
564
  this.write(SYMBOLS.ShowCursor);
485
565
  this.destroy();
@@ -487,50 +567,82 @@ var SelectPrompt = class extends AbstractPrompt {
487
567
  process.off("exit", this.#boundExitEvent);
488
568
  resolve(value);
489
569
  } else {
570
+ if (!key.ctrl && this.options.autocomplete) {
571
+ this.activeIndex = 0;
572
+ if (key.name === "backspace" && this.autocompleteValue.length > 0) {
573
+ this.autocompleteValue = this.autocompleteValue.slice(0, -1);
574
+ } else if (key.name !== "backspace") {
575
+ this.autocompleteValue += key.sequence;
576
+ }
577
+ }
490
578
  render();
491
579
  }
492
580
  }
493
- async select() {
494
- const answer = this.agent.nextAnswers.shift();
495
- if (answer !== void 0) {
496
- this.#showAnsweredQuestion(answer);
497
- this.destroy();
498
- return answer;
499
- }
500
- this.write(SYMBOLS.HideCursor);
501
- this.#showQuestion();
502
- const render = (options = {}) => {
503
- const {
504
- initialRender = false,
505
- clearRender = false
506
- } = options;
507
- if (!initialRender) {
508
- let linesToClear = this.lastRender.endIndex - this.lastRender.startIndex;
509
- while (linesToClear > 0) {
510
- this.clearLastLine();
511
- linesToClear--;
512
- }
513
- }
514
- if (clearRender) {
515
- const questionLineCount = Math.ceil(
516
- wcwidth3(stripAnsi(this.questionMessage)) / this.stdout.columns
517
- );
518
- this.stdout.moveCursor(-this.stdout.columns, -(1 + questionLineCount));
519
- this.stdout.clearScreenDown();
581
+ select() {
582
+ return new Promise((resolve, reject) => {
583
+ const answer = this.agent.nextAnswers.shift();
584
+ if (answer !== void 0) {
585
+ this.#showAnsweredQuestion(answer);
586
+ this.destroy();
587
+ resolve(answer);
520
588
  return;
521
589
  }
522
- this.#showChoices();
523
- };
524
- render({ initialRender: true });
525
- return new Promise((resolve) => {
590
+ this.once("error", (error) => {
591
+ reject(error);
592
+ });
593
+ this.write(SYMBOLS.HideCursor);
594
+ this.#showQuestion();
595
+ const render = (options = {}) => {
596
+ const {
597
+ initialRender = false,
598
+ clearRender = false,
599
+ error = null
600
+ } = options;
601
+ if (!initialRender) {
602
+ let linesToClear = this.lastRender.endIndex - this.lastRender.startIndex;
603
+ while (linesToClear > 0) {
604
+ this.clearLastLine();
605
+ linesToClear--;
606
+ }
607
+ if (this.options.autocomplete) {
608
+ let linesToClear2 = Math.ceil(
609
+ wcwidth3(`${SYMBOLS.Pointer} ${this.autocompleteValue}`) / this.stdout.columns
610
+ );
611
+ while (linesToClear2 > 0) {
612
+ this.clearLastLine();
613
+ linesToClear2--;
614
+ }
615
+ }
616
+ }
617
+ if (clearRender) {
618
+ const questionLineCount = Math.ceil(
619
+ wcwidth3(stripAnsi(this.questionMessage)) / this.stdout.columns
620
+ );
621
+ this.stdout.moveCursor(-this.stdout.columns, -(1 + questionLineCount));
622
+ this.stdout.clearScreenDown();
623
+ return;
624
+ }
625
+ if (error) {
626
+ const linesToClear = Math.ceil(wcwidth3(this.questionMessage) / this.stdout.columns) + 1;
627
+ this.stdout.moveCursor(0, -linesToClear);
628
+ this.stdout.clearScreenDown();
629
+ this.#showQuestion(error);
630
+ }
631
+ this.#showChoices();
632
+ };
633
+ render({ initialRender: true });
526
634
  this.#boundKeyPressEvent = this.#onKeypress.bind(this, resolve, render);
527
635
  this.stdin.on("keypress", this.#boundKeyPressEvent);
528
636
  this.#boundExitEvent = this.#onProcessExit.bind(this);
529
637
  process.once("exit", this.#boundExitEvent);
530
638
  });
531
639
  }
532
- #showQuestion() {
533
- this.questionMessage = `${SYMBOLS.QuestionMark} ${kleur4.bold(this.message)}`;
640
+ #showQuestion(error = null) {
641
+ let hint = "";
642
+ if (error) {
643
+ hint = ` ${hint.length > 0 ? " " : ""}${kleur4.red().bold(`[${error}]`)}`;
644
+ }
645
+ this.questionMessage = `${SYMBOLS.QuestionMark} ${kleur4.bold(this.message)}${hint}`;
534
646
  this.write(`${this.questionMessage}${EOL4}`);
535
647
  }
536
648
  };
@@ -539,13 +651,14 @@ var SelectPrompt = class extends AbstractPrompt {
539
651
  import { EOL as EOL5 } from "os";
540
652
  import kleur5 from "kleur";
541
653
  import wcwidth4 from "@topcli/wcwidth";
542
- var kRequiredChoiceProperties = ["label", "value"];
654
+ var kRequiredChoiceProperties2 = ["label", "value"];
543
655
  var MultiselectPrompt = class extends AbstractPrompt {
544
656
  #boundExitEvent = () => void 0;
545
657
  #boundKeyPressEvent = () => void 0;
546
658
  #validators;
659
+ #showHint;
547
660
  activeIndex = 0;
548
- selectedIndexes = [];
661
+ selectedIndexes = /* @__PURE__ */ new Set();
549
662
  questionMessage;
550
663
  autocompleteValue = "";
551
664
  options;
@@ -582,30 +695,27 @@ var MultiselectPrompt = class extends AbstractPrompt {
582
695
  return choice.label.length;
583
696
  }));
584
697
  }
585
- constructor(message, options) {
698
+ constructor(options) {
586
699
  const {
587
- stdin = process.stdin,
588
- stdout = process.stdout,
589
700
  choices,
590
701
  preSelectedChoices,
591
- validators = []
592
- } = options ?? {};
593
- super(message, stdin, stdout);
594
- if (!options) {
595
- this.destroy();
596
- throw new TypeError("Missing required options");
597
- }
702
+ validators = [],
703
+ showHint = true,
704
+ ...baseOptions
705
+ } = options;
706
+ super({ ...baseOptions });
598
707
  this.options = options;
599
708
  if (!choices?.length) {
600
709
  this.destroy();
601
710
  throw new TypeError("Missing required param: choices");
602
711
  }
603
712
  this.#validators = validators;
713
+ this.#showHint = showHint;
604
714
  for (const choice of choices) {
605
715
  if (typeof choice === "string") {
606
716
  continue;
607
717
  }
608
- for (const prop of kRequiredChoiceProperties) {
718
+ for (const prop of kRequiredChoiceProperties2) {
609
719
  if (!choice[prop]) {
610
720
  this.destroy();
611
721
  throw new TypeError(`Missing ${prop} for choice ${JSON.stringify(choice)}`);
@@ -626,7 +736,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
626
736
  this.destroy();
627
737
  throw new Error(`Invalid pre-selected choice: ${typeof choice === "string" ? choice : choice.value}`);
628
738
  }
629
- this.selectedIndexes.push(choiceIndex);
739
+ this.selectedIndexes.add(choiceIndex);
630
740
  }
631
741
  }
632
742
  #getFormattedChoice(choiceIndex) {
@@ -654,7 +764,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
654
764
  for (let choiceIndex = startIndex; choiceIndex < endIndex; choiceIndex++) {
655
765
  const choice = this.#getFormattedChoice(choiceIndex);
656
766
  const isChoiceActive = choiceIndex === this.activeIndex;
657
- const isChoiceSelected = this.selectedIndexes.includes(choiceIndex);
767
+ const isChoiceSelected = this.selectedIndexes.has(choiceIndex);
658
768
  const showPreviousChoicesArrow = startIndex > 0 && choiceIndex === startIndex;
659
769
  const showNextChoicesArrow = endIndex < this.filteredChoices.length && choiceIndex === endIndex - 1;
660
770
  let prefixArrow = " ";
@@ -674,7 +784,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
674
784
  }
675
785
  }
676
786
  #showAnsweredQuestion(choices, isAgentAnswer = false) {
677
- const prefixSymbol = this.selectedIndexes.length === 0 && !isAgentAnswer ? SYMBOLS.Cross : SYMBOLS.Tick;
787
+ const prefixSymbol = this.selectedIndexes.size === 0 && !isAgentAnswer ? SYMBOLS.Cross : SYMBOLS.Tick;
678
788
  const prefix = `${prefixSymbol} ${kleur5.bold(this.message)} ${SYMBOLS.Pointer}`;
679
789
  const formattedChoice = kleur5.yellow(choices);
680
790
  this.write(`${prefix}${choices ? ` ${formattedChoice}` : ""}${EOL5}`);
@@ -694,20 +804,20 @@ var MultiselectPrompt = class extends AbstractPrompt {
694
804
  this.activeIndex = this.activeIndex === this.filteredChoices.length - 1 ? 0 : this.activeIndex + 1;
695
805
  render();
696
806
  } else if (key.ctrl && key.name === "a") {
697
- this.selectedIndexes = this.selectedIndexes.length === this.filteredChoices.length ? [] : this.filteredChoices.map((_, index) => index);
807
+ this.selectedIndexes = this.selectedIndexes.size === this.filteredChoices.length ? /* @__PURE__ */ new Set() : new Set(this.filteredChoices.map((_, index) => index));
698
808
  render();
699
809
  } else if (key.name === "right") {
700
- this.selectedIndexes.push(this.activeIndex);
810
+ this.selectedIndexes.add(this.activeIndex);
701
811
  render();
702
812
  } else if (key.name === "left") {
703
- this.selectedIndexes = this.selectedIndexes.filter((index) => index !== this.activeIndex);
813
+ this.selectedIndexes = new Set([...this.selectedIndexes].filter((index) => index !== this.activeIndex));
704
814
  render();
705
815
  } else if (key.name === "return") {
706
- const labels = this.selectedIndexes.map((index) => {
816
+ const labels = [...this.selectedIndexes].map((index) => {
707
817
  const choice = this.filteredChoices[index];
708
818
  return typeof choice === "string" ? choice : choice.label;
709
819
  });
710
- const values = this.selectedIndexes.map((index) => {
820
+ const values = [...this.selectedIndexes].map((index) => {
711
821
  const choice = this.filteredChoices[index];
712
822
  return typeof choice === "string" ? choice : choice.value;
713
823
  });
@@ -727,7 +837,7 @@ var MultiselectPrompt = class extends AbstractPrompt {
727
837
  resolve(values);
728
838
  } else {
729
839
  if (!key.ctrl && this.options.autocomplete) {
730
- this.selectedIndexes = [];
840
+ this.selectedIndexes.clear();
731
841
  this.activeIndex = 0;
732
842
  if (key.name === "backspace" && this.autocompleteValue.length > 0) {
733
843
  this.autocompleteValue = this.autocompleteValue.slice(0, -1);
@@ -738,56 +848,60 @@ var MultiselectPrompt = class extends AbstractPrompt {
738
848
  render();
739
849
  }
740
850
  }
741
- async multiselect() {
742
- const answer = this.agent.nextAnswers.shift();
743
- if (answer !== void 0) {
744
- const formatedAnser = Array.isArray(answer) ? answer.join(", ") : answer;
745
- this.#showAnsweredQuestion(formatedAnser, true);
746
- this.destroy();
747
- return Array.isArray(answer) ? answer : [answer];
748
- }
749
- this.write(SYMBOLS.HideCursor);
750
- this.#showQuestion();
751
- const render = (options = {}) => {
752
- const {
753
- initialRender = false,
754
- clearRender = false,
755
- error = null
756
- } = options;
757
- if (!initialRender) {
758
- let linesToClear = this.lastRender.endIndex - this.lastRender.startIndex;
759
- while (linesToClear > 0) {
760
- this.clearLastLine();
761
- linesToClear--;
762
- }
763
- if (this.options.autocomplete) {
764
- let linesToClear2 = Math.ceil(
765
- wcwidth4(`${SYMBOLS.Pointer} ${this.autocompleteValue}`) / this.stdout.columns
766
- );
767
- while (linesToClear2 > 0) {
851
+ multiselect() {
852
+ return new Promise((resolve, reject) => {
853
+ const answer = this.agent.nextAnswers.shift();
854
+ if (answer !== void 0) {
855
+ const formatedAnser = Array.isArray(answer) ? answer.join(", ") : answer;
856
+ this.#showAnsweredQuestion(formatedAnser, true);
857
+ this.destroy();
858
+ resolve(Array.isArray(answer) ? answer : [answer]);
859
+ return;
860
+ }
861
+ this.once("error", (error) => {
862
+ reject(error);
863
+ });
864
+ this.write(SYMBOLS.HideCursor);
865
+ this.#showQuestion();
866
+ const render = (options = {}) => {
867
+ const {
868
+ initialRender = false,
869
+ clearRender = false,
870
+ error = null
871
+ } = options;
872
+ if (!initialRender) {
873
+ let linesToClear = this.lastRender.endIndex - this.lastRender.startIndex;
874
+ while (linesToClear > 0) {
768
875
  this.clearLastLine();
769
- linesToClear2--;
876
+ linesToClear--;
877
+ }
878
+ if (this.options.autocomplete) {
879
+ let linesToClear2 = Math.ceil(
880
+ wcwidth4(`${SYMBOLS.Pointer} ${this.autocompleteValue}`) / this.stdout.columns
881
+ );
882
+ while (linesToClear2 > 0) {
883
+ this.clearLastLine();
884
+ linesToClear2--;
885
+ }
770
886
  }
771
887
  }
772
- }
773
- if (clearRender) {
774
- const questionLineCount = Math.ceil(
775
- wcwidth4(stripAnsi(this.questionMessage)) / this.stdout.columns
776
- );
777
- this.stdout.moveCursor(-this.stdout.columns, -(1 + questionLineCount));
778
- this.stdout.clearScreenDown();
779
- return;
780
- }
781
- if (error) {
782
- const linesToClear = Math.ceil(wcwidth4(this.questionMessage) / this.stdout.columns) + 1;
783
- this.stdout.moveCursor(0, -linesToClear);
784
- this.stdout.clearScreenDown();
785
- this.#showQuestion(error);
786
- }
787
- this.#showChoices();
788
- };
789
- render({ initialRender: true });
790
- return new Promise((resolve) => {
888
+ if (clearRender) {
889
+ const questionLineCount = Math.ceil(
890
+ wcwidth4(stripAnsi(this.questionMessage)) / this.stdout.columns
891
+ );
892
+ this.stdout.moveCursor(-this.stdout.columns, -(1 + questionLineCount));
893
+ this.stdout.clearScreenDown();
894
+ return;
895
+ }
896
+ if (error) {
897
+ const linesToClear = Math.ceil(wcwidth4(this.questionMessage) / this.stdout.columns) + 1;
898
+ this.stdout.moveCursor(0, -linesToClear);
899
+ this.stdout.clearScreenDown();
900
+ this.#showQuestion(error);
901
+ }
902
+ this.#showChoices();
903
+ };
904
+ render({ initialRender: true });
791
905
  this.#boundKeyPressEvent = this.#onKeypress.bind(this, resolve, render);
792
906
  this.stdin.on("keypress", this.#boundKeyPressEvent);
793
907
  this.#boundExitEvent = this.#onProcessExit.bind(this);
@@ -795,14 +909,14 @@ var MultiselectPrompt = class extends AbstractPrompt {
795
909
  });
796
910
  }
797
911
  #showQuestion(error = null) {
798
- let hint = kleur5.gray(
912
+ let hint = this.#showHint ? kleur5.gray(
799
913
  // eslint-disable-next-line max-len
800
- `(Press ${kleur5.bold("<Ctrl+A>")} to toggle all, ${kleur5.bold("<Ctrl+Space>")} to select, ${kleur5.bold("<Left/Right>")} to toggle, ${kleur5.bold("<Return>")} to submit)`
801
- );
914
+ `(Press ${kleur5.bold("<Ctrl+A>")} to toggle all, ${kleur5.bold("<Left/Right>")} to toggle, ${kleur5.bold("<Return>")} to submit)`
915
+ ) : "";
802
916
  if (error) {
803
- hint += ` ${kleur5.red().bold(`[${error}]`)}`;
917
+ hint += `${hint.length > 0 ? " " : ""}${kleur5.red().bold(`[${error}]`)}`;
804
918
  }
805
- this.questionMessage = `${SYMBOLS.QuestionMark} ${kleur5.bold(this.message)} ${hint}`;
919
+ this.questionMessage = `${SYMBOLS.QuestionMark} ${kleur5.bold(this.message)}${hint.length > 0 ? ` ${hint}` : ""}`;
806
920
  this.write(`${this.questionMessage}${EOL5}`);
807
921
  }
808
922
  };
@@ -817,19 +931,18 @@ function required() {
817
931
 
818
932
  // index.ts
819
933
  async function question(message, options = {}) {
820
- const questionPrompt = new QuestionPrompt(message, options);
821
- return questionPrompt.question();
934
+ return new QuestionPrompt({ ...options, message }).question();
822
935
  }
823
936
  async function select(message, options) {
824
- const selectPrompt = new SelectPrompt(message, options);
937
+ const selectPrompt = new SelectPrompt({ ...options, message });
825
938
  return selectPrompt.select();
826
939
  }
827
940
  async function confirm(message, options) {
828
- const confirmPrompt = new ConfirmPrompt(message, options);
941
+ const confirmPrompt = new ConfirmPrompt({ ...options, message });
829
942
  return confirmPrompt.confirm();
830
943
  }
831
944
  async function multiselect(message, options) {
832
- const multiselectPrompt = new MultiselectPrompt(message, options);
945
+ const multiselectPrompt = new MultiselectPrompt({ ...options, message });
833
946
  return multiselectPrompt.multiselect();
834
947
  }
835
948
  export {