pi-sage 0.2.7 → 0.2.9

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.
@@ -1,4 +1,5 @@
1
- import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import { DynamicBorder, type ExtensionAPI, type ExtensionCommandContext, type ExtensionContext } from "@mariozechner/pi-coding-agent";
2
+ import { Container, type SelectItem, SelectList, Text } from "@mariozechner/pi-tui";
2
3
  import { Type } from "@sinclair/typebox";
3
4
  import {
4
5
  evaluateSoftBudget,
@@ -724,69 +725,51 @@ async function selectScrollable(
724
725
  ): Promise<string | undefined> {
725
726
  if (options.length === 0) return undefined;
726
727
 
727
- return await ctx.ui.custom<string | undefined>((tui, theme, _keybindings, done) => {
728
- let selectedIndex = 0;
729
-
730
- const move = (delta: number): void => {
731
- const next = selectedIndex + delta;
732
- selectedIndex = Math.max(0, Math.min(options.length - 1, next));
733
- tui.requestRender();
734
- };
728
+ const items: SelectItem[] = options.map((option, index) => ({
729
+ value: String(index),
730
+ label: option
731
+ }));
732
+
733
+ const selectedValue = await ctx.ui.custom<string | undefined>((tui, theme, _keybindings, done) => {
734
+ const container = new Container();
735
+ container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
736
+ container.addChild(new Text(theme.fg("accent", title), 1, 0));
737
+ container.addChild(new Text("", 0, 0));
738
+
739
+ const selectList = new SelectList(items, Math.max(3, Math.min(maxVisible, items.length)), {
740
+ selectedPrefix: (text) => theme.fg("accent", text),
741
+ selectedText: (text) => theme.fg("accent", text),
742
+ description: (text) => theme.fg("muted", text),
743
+ scrollInfo: (text) => theme.fg("dim", text),
744
+ noMatch: (text) => theme.fg("warning", text)
745
+ });
735
746
 
736
- const render = (width: number): string[] => {
737
- const lines: string[] = [];
738
- lines.push(theme.fg("accent", title));
739
- lines.push("");
747
+ selectList.onSelect = (item) => done(item.value);
748
+ selectList.onCancel = () => done(undefined);
749
+ container.addChild(selectList);
740
750
 
741
- const visible = Math.max(3, Math.min(maxVisible, options.length));
742
- const start = Math.max(0, Math.min(selectedIndex - Math.floor(visible / 2), options.length - visible));
743
- const end = Math.min(options.length, start + visible);
751
+ container.addChild(new Text("", 0, 0));
752
+ container.addChild(new Text(theme.fg("dim", "↑↓ navigate enter select • esc back"), 1, 0));
753
+ container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
744
754
 
745
- for (let i = start; i < end; i += 1) {
746
- const option = options[i] ?? "";
747
- const prefix = i === selectedIndex ? "→ " : " ";
748
- const raw = `${prefix}${option}`;
749
- lines.push(i === selectedIndex ? theme.fg("accent", raw) : raw);
755
+ return {
756
+ render: (width: number) => container.render(width),
757
+ invalidate: () => container.invalidate(),
758
+ handleInput: (data: string) => {
759
+ selectList.handleInput(data);
760
+ tui.requestRender();
750
761
  }
751
-
752
- lines.push("");
753
- lines.push(theme.fg("muted", `(${selectedIndex + 1}/${options.length}) ↑↓ navigate • enter select • esc back`));
754
-
755
- return lines.map((line) => (line.length > width ? `${line.slice(0, Math.max(0, width - 1))}…` : line));
756
762
  };
763
+ });
757
764
 
758
- const handleInput = (data: string): void => {
759
- if (data.includes("\u001b[A")) {
760
- move(-1);
761
- return;
762
- }
763
- if (data.includes("\u001b[B")) {
764
- move(1);
765
- return;
766
- }
767
- if (data === "k") {
768
- move(-1);
769
- return;
770
- }
771
- if (data === "j") {
772
- move(1);
773
- return;
774
- }
775
- if (data === "\r" || data === "\n") {
776
- done(options[selectedIndex]);
777
- return;
778
- }
779
- if (data === "\u001b") {
780
- done(undefined);
781
- }
782
- };
765
+ if (selectedValue === undefined) return undefined;
783
766
 
784
- return {
785
- render,
786
- invalidate: () => {},
787
- handleInput
788
- };
789
- });
767
+ const selectedIndex = Number(selectedValue);
768
+ if (!Number.isInteger(selectedIndex) || selectedIndex < 0 || selectedIndex >= options.length) {
769
+ return undefined;
770
+ }
771
+
772
+ return options[selectedIndex];
790
773
  }
791
774
 
792
775
  function onOff(value: boolean): string {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-sage",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Interactive-only advisory Sage extension for Pi",