pi-sage 0.2.8 → 0.2.10
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/.pi/extensions/sage/index.ts +51 -67
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
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,
|
|
@@ -377,8 +378,10 @@ async function runSettingsWizard(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
377
378
|
ctx.ui.notify(`Saved Sage settings to ${target}`, "info");
|
|
378
379
|
};
|
|
379
380
|
|
|
381
|
+
let rootSelectionIndex = 0;
|
|
382
|
+
|
|
380
383
|
while (true) {
|
|
381
|
-
const
|
|
384
|
+
const rootOptions = [
|
|
382
385
|
`Enabled: ${onOff(draft.enabled)}`,
|
|
383
386
|
`Autonomous mode: ${onOff(draft.autonomousEnabled)}`,
|
|
384
387
|
`Explicit requests bypass soft limits: ${onOff(draft.explicitRequestAlwaysAllowed)}`,
|
|
@@ -400,13 +403,18 @@ async function runSettingsWizard(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
400
403
|
`Cost cap/session: ${draft.maxEstimatedCostPerSession ?? "(none)"}`,
|
|
401
404
|
`Save scope: ${scope}`,
|
|
402
405
|
"Test Sage call"
|
|
403
|
-
]
|
|
406
|
+
];
|
|
407
|
+
|
|
408
|
+
const action = await selectScrollable(ctx, "Sage settings", rootOptions, 10, rootSelectionIndex);
|
|
404
409
|
|
|
405
410
|
if (!action) {
|
|
406
411
|
ctx.ui.notify("Sage settings closed (changes are saved immediately)", "info");
|
|
407
412
|
return;
|
|
408
413
|
}
|
|
409
414
|
|
|
415
|
+
const selectedIndex = rootOptions.indexOf(action);
|
|
416
|
+
if (selectedIndex >= 0) rootSelectionIndex = selectedIndex;
|
|
417
|
+
|
|
410
418
|
if (action === "Test Sage call") {
|
|
411
419
|
await runSettingsTestCall(ctx, draft);
|
|
412
420
|
continue;
|
|
@@ -720,82 +728,58 @@ async function selectScrollable(
|
|
|
720
728
|
ctx: HasUIContext,
|
|
721
729
|
title: string,
|
|
722
730
|
options: string[],
|
|
723
|
-
maxVisible = 10
|
|
731
|
+
maxVisible = 10,
|
|
732
|
+
initialSelectedIndex = 0
|
|
724
733
|
): Promise<string | undefined> {
|
|
725
734
|
if (options.length === 0) return undefined;
|
|
726
735
|
|
|
727
|
-
|
|
728
|
-
|
|
736
|
+
const items: SelectItem[] = options.map((option, index) => ({
|
|
737
|
+
value: String(index),
|
|
738
|
+
label: option
|
|
739
|
+
}));
|
|
740
|
+
|
|
741
|
+
const selectedValue = await ctx.ui.custom<string | undefined>((tui, theme, _keybindings, done) => {
|
|
742
|
+
const container = new Container();
|
|
743
|
+
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
744
|
+
container.addChild(new Text(theme.fg("accent", title), 1, 0));
|
|
745
|
+
container.addChild(new Text("", 0, 0));
|
|
746
|
+
|
|
747
|
+
const selectList = new SelectList(items, Math.max(3, Math.min(maxVisible, items.length)), {
|
|
748
|
+
selectedPrefix: (text) => theme.fg("accent", text),
|
|
749
|
+
selectedText: (text) => theme.fg("accent", text),
|
|
750
|
+
description: (text) => theme.fg("muted", text),
|
|
751
|
+
scrollInfo: (text) => theme.fg("dim", text),
|
|
752
|
+
noMatch: (text) => theme.fg("warning", text)
|
|
753
|
+
});
|
|
729
754
|
|
|
730
|
-
|
|
731
|
-
const next = selectedIndex + delta;
|
|
732
|
-
selectedIndex = Math.max(0, Math.min(options.length - 1, next));
|
|
733
|
-
tui.requestRender();
|
|
734
|
-
};
|
|
755
|
+
selectList.setSelectedIndex(initialSelectedIndex);
|
|
735
756
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
lines.push("");
|
|
757
|
+
selectList.onSelect = (item) => done(item.value);
|
|
758
|
+
selectList.onCancel = () => done(undefined);
|
|
759
|
+
container.addChild(selectList);
|
|
740
760
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
761
|
+
container.addChild(new Text("", 0, 0));
|
|
762
|
+
container.addChild(new Text(theme.fg("dim", "↑↓ navigate • enter select • esc back"), 1, 0));
|
|
763
|
+
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
744
764
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
765
|
+
return {
|
|
766
|
+
render: (width: number) => container.render(width),
|
|
767
|
+
invalidate: () => container.invalidate(),
|
|
768
|
+
handleInput: (data: string) => {
|
|
769
|
+
selectList.handleInput(data);
|
|
770
|
+
tui.requestRender();
|
|
750
771
|
}
|
|
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
772
|
};
|
|
773
|
+
});
|
|
757
774
|
|
|
758
|
-
|
|
759
|
-
const isUp = data.includes("\u001b[A") || data.includes("\u001bOA");
|
|
760
|
-
const isDown = data.includes("\u001b[B") || data.includes("\u001bOB");
|
|
761
|
-
const isEnter = data.includes("\r") || data.includes("\n") || data.includes("\u001bOM");
|
|
762
|
-
const isEscLike = data.startsWith("\u001b");
|
|
775
|
+
if (selectedValue === undefined) return undefined;
|
|
763
776
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
if (isDown) {
|
|
769
|
-
move(1);
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
if (data === "k" || data === "K") {
|
|
773
|
-
move(-1);
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
if (data === "j" || data === "J") {
|
|
777
|
-
move(1);
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
if (isEnter) {
|
|
781
|
-
done(options[selectedIndex]);
|
|
782
|
-
return;
|
|
783
|
-
}
|
|
784
|
-
if (data.includes("\u0003")) {
|
|
785
|
-
done(undefined);
|
|
786
|
-
return;
|
|
787
|
-
}
|
|
788
|
-
if (isEscLike) {
|
|
789
|
-
done(undefined);
|
|
790
|
-
}
|
|
791
|
-
};
|
|
777
|
+
const selectedIndex = Number(selectedValue);
|
|
778
|
+
if (!Number.isInteger(selectedIndex) || selectedIndex < 0 || selectedIndex >= options.length) {
|
|
779
|
+
return undefined;
|
|
780
|
+
}
|
|
792
781
|
|
|
793
|
-
|
|
794
|
-
render,
|
|
795
|
-
invalidate: () => {},
|
|
796
|
-
handleInput
|
|
797
|
-
};
|
|
798
|
-
});
|
|
782
|
+
return options[selectedIndex];
|
|
799
783
|
}
|
|
800
784
|
|
|
801
785
|
function onOff(value: boolean): string {
|