omniharness-cli 0.1.31 → 0.1.33

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/ui/keys.d.ts CHANGED
@@ -1,19 +1,43 @@
1
1
  /**
2
2
  * Keyboard input normalization for the chat.
3
3
  *
4
- * Terminals cannot distinguish Shift+Enter from Enter by default: both send
5
- * `\r`. Capable terminals (kitty, foot, WezTerm, Ghostty, modern Windows
6
- * Terminal, …) fix this with the kitty keyboard protocol the app pushes
7
- * `CSI > 1 u` and the terminal then encodes colliding keys as `CSI keycode ;
8
- * modifier u` (Shift+Enter = `ESC[13;2u`). Ink 5.x does not parse those
9
- * sequences; they reach `useInput` as plain text with the leading ESC
10
- * stripped. This module recovers their meaning, and also maps the bare LF
11
- * some terminals send for Shift+Enter.
4
+ * Two problems make raw byte handling necessary instead of Ink's `useInput`:
5
+ *
6
+ * 1. Windows ConPTY sends DEL (0x7f) for the Backspace key. Ink labels 0x7f
7
+ * as `delete`, so an app that trusts `key.delete` deletes forward a no-op
8
+ * at the end of the line. We intercept 0x7f on raw stdin and treat it as
9
+ * backspace, while the real Delete key (`ESC[3~` / kitty `ESC[3u`) keeps
10
+ * deleting forward.
11
+ *
12
+ * 2. The kitty keyboard protocol (pushed via `CSI > 1 u`) re-encodes Enter,
13
+ * Tab, Backspace, Escape, arrows, Home/End, Delete and ctrl+letters as
14
+ * `CSI keycode ; modifier u` sequences. Ink 5.x misparses most of them:
15
+ * some arrive as empty input with bogus ctrl/meta flags, others as raw text
16
+ * like `[13;2u`. `parseRawKey` recovers their meaning from the raw chunk.
17
+ *
18
+ * Plain text, paste and legacy (non-kitty) keys like `\r`, `\n`, `\x08`,
19
+ * `ESC[A` arrows and ctrl+letters are left to Ink's `useInput`.
12
20
  */
13
- export type TranslatedKey = {
21
+ export type KeyAction = {
14
22
  kind: 'submit';
15
23
  } | {
16
24
  kind: 'newline';
25
+ } | {
26
+ kind: 'backspace';
27
+ } | {
28
+ kind: 'delete';
29
+ } | {
30
+ kind: 'left';
31
+ } | {
32
+ kind: 'right';
33
+ } | {
34
+ kind: 'up';
35
+ } | {
36
+ kind: 'down';
37
+ } | {
38
+ kind: 'home';
39
+ } | {
40
+ kind: 'end';
17
41
  } | {
18
42
  kind: 'escape';
19
43
  } | {
@@ -24,25 +48,29 @@ export type TranslatedKey = {
24
48
  kind: 'ctrlM';
25
49
  } | {
26
50
  kind: 'ctrlO';
51
+ } | {
52
+ kind: 'ctrlE';
27
53
  };
28
54
  /** Enable the kitty keyboard protocol (disambiguate escape codes). */
29
55
  export declare const KITTY_PUSH = "\u001B[>1u";
30
56
  /** Restore the previous keyboard state. */
31
57
  export declare const KITTY_POP = "\u001B[<1u";
58
+ /** Query the terminal for its current progressive-enhancement flags. */
59
+ export declare const KITTY_QUERY = "\u001B[?u";
32
60
  /**
33
- * Translate a CSI-u value (ESC already stripped by Ink) into a semantic key,
34
- * or null when it is a plain character. Returns null for encoded sequences we
35
- * do not act on (unknown keys) callers should not insert those as text.
61
+ * True when `chunk` is the terminal's answer to the kitty-protocol query
62
+ * (`ESC[? flags u`), confirming the protocol is actually active. Terminals
63
+ * without kitty support ignore the query and answer nothing.
36
64
  */
37
- export declare function translateCsiU(value: string): TranslatedKey | null;
38
- /** True when `value` is an unrecognized CSI-u encoded key, never plain text. */
39
- export declare function isEncodedKey(value: string): boolean;
40
- export type RawKey = 'home' | 'end';
65
+ export declare function isKittyQueryResponse(chunk: string): boolean;
66
+ /**
67
+ * Map a raw stdin chunk to a semantic key action, or null when it is plain
68
+ * text or a key `useInput` already handles correctly (legacy arrows, `\r`,
69
+ * `\n`, `\x08`, ctrl+letters, …).
70
+ */
71
+ export declare function parseRawKey(chunk: string): KeyAction | null;
41
72
  /**
42
- * Detect Home/End from a raw stdin chunk. Ink's `useInput` drops these keys
43
- * (its Key object has no home/end flags), so we listen on stdin directly.
44
- * Handles the legacy sequences (xterm `ESC[H`/`ESC[F`, rxvt `ESC[1~`/`ESC[4~`,
45
- * `ESC[7~`/`ESC[8~`) and the kitty-protocol forms (`ESC[1u`/`ESC[4u` with any
46
- * modifier). Returns null for anything that is not exactly a Home/End key.
73
+ * True when `value` is a CSI-u encoded key or protocol response (kitty key
74
+ * events, push/pop echoes, query answers), never plain text to insert.
47
75
  */
48
- export declare function parseRawKey(chunk: string): RawKey | null;
76
+ export declare function isEncodedKey(value: string): boolean;
package/dist/ui/keys.js CHANGED
@@ -1,61 +1,110 @@
1
1
  /**
2
2
  * Keyboard input normalization for the chat.
3
3
  *
4
- * Terminals cannot distinguish Shift+Enter from Enter by default: both send
5
- * `\r`. Capable terminals (kitty, foot, WezTerm, Ghostty, modern Windows
6
- * Terminal, …) fix this with the kitty keyboard protocol the app pushes
7
- * `CSI > 1 u` and the terminal then encodes colliding keys as `CSI keycode ;
8
- * modifier u` (Shift+Enter = `ESC[13;2u`). Ink 5.x does not parse those
9
- * sequences; they reach `useInput` as plain text with the leading ESC
10
- * stripped. This module recovers their meaning, and also maps the bare LF
11
- * some terminals send for Shift+Enter.
4
+ * Two problems make raw byte handling necessary instead of Ink's `useInput`:
5
+ *
6
+ * 1. Windows ConPTY sends DEL (0x7f) for the Backspace key. Ink labels 0x7f
7
+ * as `delete`, so an app that trusts `key.delete` deletes forward a no-op
8
+ * at the end of the line. We intercept 0x7f on raw stdin and treat it as
9
+ * backspace, while the real Delete key (`ESC[3~` / kitty `ESC[3u`) keeps
10
+ * deleting forward.
11
+ *
12
+ * 2. The kitty keyboard protocol (pushed via `CSI > 1 u`) re-encodes Enter,
13
+ * Tab, Backspace, Escape, arrows, Home/End, Delete and ctrl+letters as
14
+ * `CSI keycode ; modifier u` sequences. Ink 5.x misparses most of them:
15
+ * some arrive as empty input with bogus ctrl/meta flags, others as raw text
16
+ * like `[13;2u`. `parseRawKey` recovers their meaning from the raw chunk.
17
+ *
18
+ * Plain text, paste and legacy (non-kitty) keys like `\r`, `\n`, `\x08`,
19
+ * `ESC[A` arrows and ctrl+letters are left to Ink's `useInput`.
12
20
  */
13
21
  /** Enable the kitty keyboard protocol (disambiguate escape codes). */
14
22
  export const KITTY_PUSH = '\x1b[>1u';
15
23
  /** Restore the previous keyboard state. */
16
24
  export const KITTY_POP = '\x1b[<1u';
25
+ /** Query the terminal for its current progressive-enhancement flags. */
26
+ export const KITTY_QUERY = '\x1b[?u';
17
27
  /**
18
- * Translate a CSI-u value (ESC already stripped by Ink) into a semantic key,
19
- * or null when it is a plain character. Returns null for encoded sequences we
20
- * do not act on (unknown keys) callers should not insert those as text.
28
+ * True when `chunk` is the terminal's answer to the kitty-protocol query
29
+ * (`ESC[? flags u`), confirming the protocol is actually active. Terminals
30
+ * without kitty support ignore the query and answer nothing.
21
31
  */
22
- export function translateCsiU(value) {
23
- const enter = /^\[13(?:;(\d+))?u$/.exec(value);
24
- if (enter) {
25
- const modifier = enter[1] === undefined ? 1 : Number(enter[1]);
26
- return modifier === 1 ? { kind: 'submit' } : { kind: 'newline' };
27
- }
28
- switch (value) {
29
- case '[27u': return { kind: 'escape' };
30
- case '[9u':
31
- case '[9;2u':
32
- case '[9;5u':
33
- return { kind: 'tab' };
34
- case '[99;5u': return { kind: 'ctrlC' };
35
- case '[109;5u': return { kind: 'ctrlM' };
36
- case '[111;5u': return { kind: 'ctrlO' };
37
- default: return null;
38
- }
39
- }
40
- /** True when `value` is an unrecognized CSI-u encoded key, never plain text. */
41
- export function isEncodedKey(value) {
42
- return /^\[\d+(?:;\d+)*u$/.test(value);
32
+ export function isKittyQueryResponse(chunk) {
33
+ return /^\x1b\[\?\d+(?:;\d+)*u$/.test(chunk);
43
34
  }
44
35
  /**
45
- * Detect Home/End from a raw stdin chunk. Ink's `useInput` drops these keys
46
- * (its Key object has no home/end flags), so we listen on stdin directly.
47
- * Handles the legacy sequences (xterm `ESC[H`/`ESC[F`, rxvt `ESC[1~`/`ESC[4~`,
48
- * `ESC[7~`/`ESC[8~`) and the kitty-protocol forms (`ESC[1u`/`ESC[4u` with any
49
- * modifier). Returns null for anything that is not exactly a Home/End key.
36
+ * Map a raw stdin chunk to a semantic key action, or null when it is plain
37
+ * text or a key `useInput` already handles correctly (legacy arrows, `\r`,
38
+ * `\n`, `\x08`, ctrl+letters, …).
50
39
  */
51
40
  export function parseRawKey(chunk) {
41
+ if (chunk === '\x7f')
42
+ return { kind: 'backspace' }; // Windows ConPTY Backspace
52
43
  if (!chunk.startsWith('\x1b'))
53
44
  return null;
54
45
  const body = chunk.slice(1);
55
- if (body === 'H' || body === '[H' || body === 'OH' || body === '[1~' || body === '[7~' || /^\[1(?:;\d+)?u$/.test(body))
56
- return 'home';
57
- if (body === 'F' || body === '[F' || body === 'OF' || body === '[4~' || body === '[8~' || /^\[4(?:;\d+)?u$/.test(body))
58
- return 'end';
46
+ // Legacy sequences Ink drops from its Key object or mislabels.
47
+ switch (body) {
48
+ case 'H':
49
+ case '[H':
50
+ case 'OH':
51
+ case '[1~':
52
+ case '[7~': return { kind: 'home' };
53
+ case 'F':
54
+ case '[F':
55
+ case 'OF':
56
+ case '[4~':
57
+ case '[8~': return { kind: 'end' };
58
+ case '[3~': return { kind: 'delete' };
59
+ case '[27u': return { kind: 'escape' };
60
+ case '[9u':
61
+ case '[9;2u':
62
+ case '[9;5u': return { kind: 'tab' };
63
+ }
64
+ // Kitty protocol: CSI keycode ; modifier u.
65
+ const kitty = /^\[(\d+)(?:;(\d+))?u$/.exec(body);
66
+ if (kitty) {
67
+ const code = Number(kitty[1]);
68
+ const modifier = kitty[2] === undefined ? 1 : Number(kitty[2]);
69
+ if (code === 13)
70
+ return modifier === 1 ? { kind: 'submit' } : { kind: 'newline' }; // Enter / Shift+Ctrl+Alt+Enter
71
+ if (code === 27)
72
+ return { kind: 'escape' };
73
+ if (code === 9)
74
+ return { kind: 'tab' };
75
+ if (code === 127)
76
+ return { kind: 'backspace' };
77
+ if (code === 3)
78
+ return { kind: 'delete' };
79
+ if (code === 11)
80
+ return { kind: 'left' };
81
+ if (code === 12)
82
+ return { kind: 'right' };
83
+ if (code === 7)
84
+ return { kind: 'up' };
85
+ if (code === 8)
86
+ return { kind: 'down' };
87
+ if (code === 1)
88
+ return { kind: 'home' };
89
+ if (code === 4)
90
+ return { kind: 'end' };
91
+ if (code === 99 && modifier === 5)
92
+ return { kind: 'ctrlC' }; // ctrl+c
93
+ if (code === 109 && modifier === 5)
94
+ return { kind: 'ctrlM' }; // ctrl+m (kitty-only: legacy Ctrl+M is \r)
95
+ if (code === 111 && modifier === 5)
96
+ return { kind: 'ctrlO' }; // ctrl+o
97
+ if (code === 101 && modifier === 5)
98
+ return { kind: 'ctrlE' }; // ctrl+e
99
+ return null; // other kitty-encoded keys (letters, F-keys, …) — not bound
100
+ }
59
101
  return null;
60
102
  }
103
+ /**
104
+ * True when `value` is a CSI-u encoded key or protocol response (kitty key
105
+ * events, push/pop echoes, query answers), never plain text to insert.
106
+ */
107
+ export function isEncodedKey(value) {
108
+ return /^\[\d+(?:;\d+)*u$|^\[[><?]\d+(?:;\d+)*u$/.test(value);
109
+ }
61
110
  //# sourceMappingURL=keys.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/ui/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;AACrC,2CAA2C;AAC3C,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC;AAEpC;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACnE,CAAC;IACD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QACvC,KAAK,KAAK,CAAC;QACX,KAAK,OAAO,CAAC;QACb,KAAK,OAAO;YACV,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACxC,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACzC,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACzC,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC;IACvB,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAID;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACtI,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACrI,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/ui/keys.ts"],"names":[],"mappings":"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"}