@pi-unipi/ask-user 2.0.0 → 2.0.1

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 (2) hide show
  1. package/ask-ui.ts +61 -22
  2. package/package.json +1 -1
package/ask-ui.ts CHANGED
@@ -450,6 +450,20 @@ export function renderAskUI(params: {
450
450
  theme: Theme,
451
451
  width: number,
452
452
  ) {
453
+ const addWrappedOptionLine = (prefix: string, content: string) => {
454
+ const prefixWidth = visibleWidth(prefix);
455
+ const contentWidth = Math.max(1, width - prefixWidth);
456
+ const continuationPrefix = " ".repeat(prefixWidth);
457
+ const wrapped = wrapTextWithAnsi(content, contentWidth);
458
+ for (let lineIndex = 0; lineIndex < wrapped.length; lineIndex++) {
459
+ add((lineIndex === 0 ? prefix : continuationPrefix) + wrapped[lineIndex]);
460
+ }
461
+ };
462
+
463
+ const addWrappedDescription = (description: string) => {
464
+ addWrappedOptionLine(" ", theme.fg("muted", description));
465
+ };
466
+
453
467
  for (let i = 0; i < displayOptions.length; i++) {
454
468
  const opt = displayOptions[i];
455
469
  const isSelected = i === optionIndex;
@@ -467,11 +481,9 @@ export function renderAskUI(params: {
467
481
  label = `${opt.label}: "${customText}"`;
468
482
  }
469
483
 
470
- add(
471
- prefix +
472
- theme.fg(color, `[${box}]`) +
473
- " " +
474
- theme.fg(isSelected ? "accent" : "text", label),
484
+ addWrappedOptionLine(
485
+ prefix + theme.fg(color, `[${box}]`) + " ",
486
+ theme.fg(isSelected ? "accent" : "text", label),
475
487
  );
476
488
 
477
489
  // Show edit indicator if in edit mode for this option
@@ -493,11 +505,9 @@ export function renderAskUI(params: {
493
505
  label = `${opt.label}: "${optCustom}"`;
494
506
  }
495
507
 
496
- add(
497
- prefix +
498
- theme.fg(color, `[${box}]`) +
499
- " " +
500
- theme.fg(isSelected ? "accent" : "text", label),
508
+ addWrappedOptionLine(
509
+ prefix + theme.fg(color, `[${box}]`) + " ",
510
+ theme.fg(isSelected ? "accent" : "text", label),
501
511
  );
502
512
 
503
513
  // Show edit indicator if in edit mode for this option
@@ -525,11 +535,11 @@ export function renderAskUI(params: {
525
535
  label += theme.fg("dim", " ↗");
526
536
  }
527
537
 
528
- add(
529
- prefix +
530
- (isSelected
531
- ? theme.fg("accent", label)
532
- : theme.fg("text", label)),
538
+ addWrappedOptionLine(
539
+ prefix,
540
+ isSelected
541
+ ? theme.fg("accent", label)
542
+ : theme.fg("text", label),
533
543
  );
534
544
 
535
545
  // Show edit indicator if in edit mode for this option
@@ -543,7 +553,7 @@ export function renderAskUI(params: {
543
553
 
544
554
  // Description
545
555
  if (opt.description) {
546
- add(` ${theme.fg("muted", opt.description)}`);
556
+ addWrappedDescription(opt.description);
547
557
  }
548
558
  }
549
559
  }
@@ -564,17 +574,46 @@ export function renderAskUI(params: {
564
574
  export function createRenderCall() {
565
575
  return (args: Record<string, unknown>, theme: Theme, _context: unknown) => {
566
576
  const question = (args.question as string) || "";
567
- const options = Array.isArray(args.options) ? args.options : [];
577
+ const context = (args.context as string | undefined) || "";
578
+ const options = Array.isArray(args.options)
579
+ ? (args.options as Array<Record<string, unknown>>)
580
+ : [];
568
581
  const mode = args.allowMultiple ? "multi-select" : "single-select";
582
+ const allowFreeform = args.allowFreeform !== false;
569
583
  const count = options.length;
570
584
 
571
- let text =
572
- theme.fg("toolTitle", theme.bold("ask_user ")) +
573
- theme.fg("muted", question);
585
+ const lines: string[] = [];
586
+ lines.push(
587
+ theme.fg("toolTitle", theme.bold("ask_user")) +
588
+ theme.fg("dim", ` (${count} option${count !== 1 ? "s" : ""}, ${mode}${allowFreeform ? ", freeform" : ""})`),
589
+ );
590
+ if (context) {
591
+ lines.push(theme.fg("muted", "Context: ") + theme.fg("text", context));
592
+ }
593
+ lines.push(theme.fg("muted", "Question: ") + theme.fg("text", question));
594
+
574
595
  if (count > 0) {
575
- text += theme.fg("dim", ` (${count} option${count !== 1 ? "s" : ""}, ${mode})`);
596
+ lines.push(theme.fg("muted", "Options:"));
597
+ options.forEach((option, index) => {
598
+ const label = String(option.label ?? option.value ?? `Option ${index + 1}`);
599
+ const action = typeof option.action === "string" && option.action !== "select"
600
+ ? theme.fg("dim", ` [${option.action}]`)
601
+ : "";
602
+ lines.push(
603
+ theme.fg("dim", ` ${index + 1}. `) +
604
+ theme.fg("text", label) +
605
+ action,
606
+ );
607
+ if (typeof option.description === "string" && option.description.trim()) {
608
+ lines.push(theme.fg("muted", ` ${option.description}`));
609
+ }
610
+ if (typeof option.prefill === "string" && option.prefill.trim()) {
611
+ lines.push(theme.fg("dim", ` prefill: ${option.prefill}`));
612
+ }
613
+ });
576
614
  }
577
- return new Text(text, 0, 0);
615
+
616
+ return new Text(lines.join("\n"), 0, 0);
578
617
  };
579
618
  }
580
619
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/ask-user",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Structured user input tool for Pi coding agent — single-select, multi-select, freeform",
5
5
  "type": "module",
6
6
  "license": "MIT",