@gonrocca/zero-pi 0.1.63 → 0.1.64
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.
|
@@ -346,6 +346,49 @@ export function navigate(state: PickerState, dir: -1 | 1): PickerState {
|
|
|
346
346
|
return state;
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
// decodeKey — keystroke decoding
|
|
351
|
+
// ---------------------------------------------------------------------------
|
|
352
|
+
|
|
353
|
+
/** The picker's five meaningful keys, as decoded from a raw stdin sequence. */
|
|
354
|
+
export type PickerKey = "up" | "down" | "enter" | "esc" | "backspace";
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Kitty-keyboard-protocol matcher for one functional key: `CSI <code>` +
|
|
358
|
+
* optional `;1` (no modifiers) + optional `:1` (press) / `:2` (repeat) +
|
|
359
|
+
* `<final>`. A `:3` (release) or any real modifier does NOT match — releases
|
|
360
|
+
* must be ignored and modified keys are not picker keys.
|
|
361
|
+
*/
|
|
362
|
+
function kittyPressOrRepeat(code: string, final: string): RegExp {
|
|
363
|
+
return new RegExp(`^\\x1b\\[${code}(?:;1(?::[12])?)?${final}$`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const KITTY_UP = kittyPressOrRepeat("1", "A");
|
|
367
|
+
const KITTY_DOWN = kittyPressOrRepeat("1", "B");
|
|
368
|
+
const KITTY_ENTER = kittyPressOrRepeat("13", "u");
|
|
369
|
+
const KITTY_ESC = kittyPressOrRepeat("27", "u");
|
|
370
|
+
const KITTY_BACKSPACE = kittyPressOrRepeat("127", "u");
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Decode one raw stdin sequence into a picker key, or `null` when it is not
|
|
374
|
+
* one (printable characters, releases, modified keys, unknown sequences).
|
|
375
|
+
*
|
|
376
|
+
* pi-tui negotiates kitty keyboard protocol flags 7 with the terminal, and a
|
|
377
|
+
* granting terminal (Ghostty, kitty, …) then encodes arrows as
|
|
378
|
+
* `CSI 1;1:1 A/B` and Esc as `CSI 27 u` — never the legacy `\x1b[A` / bare
|
|
379
|
+
* `\x1b` forms. A non-granting terminal keeps the legacy (or SS3
|
|
380
|
+
* application-cursor-mode) forms. Both worlds are accepted here; kitty
|
|
381
|
+
* repeats (`:2`) navigate too so holding an arrow scrolls the list.
|
|
382
|
+
*/
|
|
383
|
+
export function decodeKey(data: string): PickerKey | null {
|
|
384
|
+
if (data === "\x1b[A" || data === "\x1bOA" || KITTY_UP.test(data)) return "up";
|
|
385
|
+
if (data === "\x1b[B" || data === "\x1bOB" || KITTY_DOWN.test(data)) return "down";
|
|
386
|
+
if (data === "\r" || data === "\n" || data === "\r\n" || KITTY_ENTER.test(data)) return "enter";
|
|
387
|
+
if (data === "\x1b" || KITTY_ESC.test(data)) return "esc";
|
|
388
|
+
if (data === "\x7f" || data === "\x08" || KITTY_BACKSPACE.test(data)) return "backspace";
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
|
|
349
392
|
// ---------------------------------------------------------------------------
|
|
350
393
|
// enter / back — Enter/Esc dispatch
|
|
351
394
|
// ---------------------------------------------------------------------------
|
|
@@ -44,6 +44,7 @@ import type { AutotunePending } from "./autotune-extension.ts";
|
|
|
44
44
|
import {
|
|
45
45
|
back,
|
|
46
46
|
createPickerState,
|
|
47
|
+
decodeKey,
|
|
47
48
|
enter,
|
|
48
49
|
navigate,
|
|
49
50
|
submitText,
|
|
@@ -521,14 +522,6 @@ const PICKER_TITLE = "zero · modelos SDD";
|
|
|
521
522
|
/** The dim help line shown at the foot of the boxed panel. */
|
|
522
523
|
const PICKER_HELP = "↑↓ navegar · enter elegir · esc volver";
|
|
523
524
|
|
|
524
|
-
/** ANSI arrow-key escape sequences. */
|
|
525
|
-
const KEY_UP = "\x1b[A";
|
|
526
|
-
const KEY_DOWN = "\x1b[B";
|
|
527
|
-
const KEY_ESC = "\x1b";
|
|
528
|
-
/** Enter — CR or LF, depending on the terminal. */
|
|
529
|
-
const KEY_ENTER = new Set(["\r", "\n", "\r\n"]);
|
|
530
|
-
/** Backspace — DEL or BS. */
|
|
531
|
-
const KEY_BACKSPACE = new Set(["\x7f", "\x08"]);
|
|
532
525
|
|
|
533
526
|
/**
|
|
534
527
|
* Clamp a rendered line to `width` columns so it never overflows the box
|
|
@@ -678,7 +671,8 @@ function createPickerComponent(
|
|
|
678
671
|
|
|
679
672
|
/** Route a keystroke while the inline text buffer is open. */
|
|
680
673
|
function handleTextInput(data: string): void {
|
|
681
|
-
|
|
674
|
+
const key = decodeKey(data);
|
|
675
|
+
if (key === "esc") {
|
|
682
676
|
// Esc abandons the typed value and returns to the current list screen
|
|
683
677
|
// unchanged. `submitText` with an empty string is exactly that no-op:
|
|
684
678
|
// it clears `textPrompt` and rebuilds the list without committing.
|
|
@@ -687,13 +681,13 @@ function createPickerComponent(
|
|
|
687
681
|
tui.requestRender();
|
|
688
682
|
return;
|
|
689
683
|
}
|
|
690
|
-
if (
|
|
684
|
+
if (key === "enter") {
|
|
691
685
|
state = submitText(state, buffer ?? "");
|
|
692
686
|
buffer = null;
|
|
693
687
|
tui.requestRender();
|
|
694
688
|
return;
|
|
695
689
|
}
|
|
696
|
-
if (
|
|
690
|
+
if (key === "backspace") {
|
|
697
691
|
buffer = (buffer ?? "").slice(0, -1);
|
|
698
692
|
tui.requestRender();
|
|
699
693
|
return;
|
|
@@ -714,24 +708,25 @@ function createPickerComponent(
|
|
|
714
708
|
return;
|
|
715
709
|
}
|
|
716
710
|
|
|
717
|
-
|
|
711
|
+
const key = decodeKey(data);
|
|
712
|
+
if (key === "up") {
|
|
718
713
|
state = navigate(state, -1);
|
|
719
714
|
tui.requestRender();
|
|
720
715
|
return;
|
|
721
716
|
}
|
|
722
|
-
if (
|
|
717
|
+
if (key === "down") {
|
|
723
718
|
state = navigate(state, 1);
|
|
724
719
|
tui.requestRender();
|
|
725
720
|
return;
|
|
726
721
|
}
|
|
727
|
-
if (
|
|
722
|
+
if (key === "enter") {
|
|
728
723
|
const result = enter(state);
|
|
729
724
|
// `enter` on a custom-* row opens `textPrompt`; arm the buffer.
|
|
730
725
|
if (result.type === "state" && result.state.textPrompt) buffer = "";
|
|
731
726
|
applyResult(result);
|
|
732
727
|
return;
|
|
733
728
|
}
|
|
734
|
-
if (
|
|
729
|
+
if (key === "esc") {
|
|
735
730
|
applyResult(back(state));
|
|
736
731
|
return;
|
|
737
732
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gonrocca/zero-pi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.64",
|
|
4
4
|
"description": "zero-pi — an installable layer for pi (pi.dev): the zero spec-driven development workflow (clarify → explore → plan → analyze → build → veredicto) with automatic clarify/analyze gates, per-phase model autotune, and token-efficient batched builds. Adds capability to pi without modifying pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|