@oxecli/oxe 1.0.68 → 1.0.69

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/dist/ui.js +44 -30
  2. package/package.json +1 -1
package/dist/ui.js CHANGED
@@ -9,7 +9,7 @@ export function enableRawStdin() {
9
9
  readline.emitKeypressEvents(process.stdin);
10
10
  if (process.stdin.isTTY) {
11
11
  process.stdin.setRawMode(true);
12
- process.stdout.write("\x1b[?9001h\x1b[>1u");
12
+ process.stdout.write("\x1b[>1u");
13
13
  }
14
14
  process.stdin.resume();
15
15
  hideCursor();
@@ -927,7 +927,7 @@ export function renderBufferWithCursor(buffer, pasteSpans, prefix, label, cursor
927
927
  * application (SS3): ESC O M
928
928
  * win32-input-mode: ESC [ G ; R ; C ; VK ; MOD u
929
929
  * (VK = 13 for Enter, MOD = raw bitmask where
930
- * bit0 = Shift)
930
+ * bit2 = Shift)
931
931
  */
932
932
  function parseEnterSequence(seq) {
933
933
  if (!seq)
@@ -939,7 +939,7 @@ function parseEnterSequence(seq) {
939
939
  if (vk !== 13)
940
940
  return null;
941
941
  const mod = parseInt(m[5], 10);
942
- return mod & 1 ? "newline" : "submit";
942
+ return mod & 4 ? "newline" : "submit";
943
943
  }
944
944
  // modifyOtherKeys / kitty: ESC [ 27 ; M ; 13 ~ (or _)
945
945
  m = seq.match(/^\x1b\[27;(\d+);13[~_]$/);
@@ -1045,9 +1045,10 @@ function decodeWin32Key(seq) {
1045
1045
  return null;
1046
1046
  const vk = parseInt(m[4], 10);
1047
1047
  const mod = parseInt(m[5], 10);
1048
- const shift = (mod & 1) === 1;
1049
- const ctrl = (mod & 4) === 4;
1050
- const alt = (mod & 2) === 2;
1048
+ // win32-input-mode MOD bitmask: bit2 = Shift, bit1 = Ctrl, bit0 = Alt
1049
+ const shift = (mod & 4) === 4;
1050
+ const ctrl = (mod & 2) === 2;
1051
+ const alt = (mod & 1) === 1;
1051
1052
  const cmd = (c) => ({ type: "cmd", cmd: c });
1052
1053
  const text = (t) => ({ type: "text", text: t });
1053
1054
  // Control combos
@@ -1141,10 +1142,14 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
1141
1142
  if (process.stdin.isTTY) {
1142
1143
  process.stdin.setRawMode(true);
1143
1144
  process.stdout.write("\x1b[?2004h");
1144
- // Enable win32-input-mode (preferred by Windows Terminal) and CSI-u
1145
- // disambiguation so Shift+Enter arrives as a distinct code instead of a
1146
- // plain Enter. Harmless if a terminal doesn't support them.
1147
- process.stdout.write("\x1b[?9001h\x1b[>1u");
1145
+ // Enable CSI-u disambiguation so Shift+Enter arrives as a distinct code
1146
+ // (`\x1b[13;2u`) instead of a plain Enter. Plain keys still arrive as
1147
+ // single keypress events. Deliberately NOT enabling win32-input-mode
1148
+ // (`\x1b[?9001h`): it rewrites EVERY keystroke into a long CSI sequence
1149
+ // that readline splits across many events, and an interrupted split
1150
+ // leaves modSeq stuck so the next keystroke is silently dropped —
1151
+ // that regression made typing in the prompt impossible.
1152
+ process.stdout.write("\x1b[>1u");
1148
1153
  }
1149
1154
  process.stdin.resume();
1150
1155
  hideCursor();
@@ -1167,7 +1172,7 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
1167
1172
  if (done)
1168
1173
  return;
1169
1174
  done = true;
1170
- process.stdout.write("\x1b[?2004l\x1b[?9001l");
1175
+ process.stdout.write("\x1b[?2004l");
1171
1176
  process.stdin.setRawMode(false);
1172
1177
  if (pasteBurstTimer)
1173
1178
  clearTimeout(pasteBurstTimer);
@@ -1586,26 +1591,15 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
1586
1591
  }
1587
1592
  };
1588
1593
  const onKeypress = (str, key) => {
1589
- // Reassemble modifier-prefixed / win32-input-mode CSI sequences, which
1590
- // Node's readline splits into several keypress events (e.g. Shift+Enter
1591
- // arriving as `\x1b[27;2;` + "1" + "3" + "~", or a win32-input-mode
1592
- // sequence `\x1b[0;1;1;13;2u` arriving piecemeal). A "partial CSI" is
1593
- // any ESC [ sequence readline left unterminated; we keep appending until
1594
- // it ends in a terminator, then classify it.
1594
+ // Reassemble modifier-prefixed CSI sequences that Node's readline may
1595
+ // split across keypress events (e.g. `\x1b[13;2u` arriving as `\x1b[13;2`
1596
+ // + "u"). Only start/continue accumulation on bytes that can belong to a
1597
+ // CSI sequence: digits / `;` while incomplete, or a terminator byte
1598
+ // [A-Z~_u] that completes it. Any other keystroke (a typed letter, for
1599
+ // instance) ABANDONS the partial instead of being swallowed, so a stuck
1600
+ // partial can never eat input.
1595
1601
  const seq = key?.sequence || str || "";
1596
- if (modSeq) {
1597
- modSeq += str || seq || "";
1598
- if (/^\x1b\[[\d;]*[a-zA-Z~_u]$/.test(modSeq)) {
1599
- const full = modSeq;
1600
- modSeq = "";
1601
- if (modSeqTimeout)
1602
- clearTimeout(modSeqTimeout);
1603
- modSeqTimeout = null;
1604
- handleRawSequence(full);
1605
- }
1606
- return;
1607
- }
1608
- if (/^\x1b\[[\d;]*$/.test(seq)) {
1602
+ if (seq.startsWith("\x1b[") && /^\x1b\[[\d;]*$/.test(seq)) {
1609
1603
  modSeq = seq;
1610
1604
  if (modSeqTimeout)
1611
1605
  clearTimeout(modSeqTimeout);
@@ -1615,6 +1609,26 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
1615
1609
  }, 200);
1616
1610
  return;
1617
1611
  }
1612
+ if (modSeq) {
1613
+ const s = str ?? seq ?? "";
1614
+ const completes = /^\x1b\[[\d;]*[A-Z~_u]$/.test(modSeq + s);
1615
+ if (/^[0-9;]$/.test(s) || completes) {
1616
+ modSeq += s;
1617
+ if (completes) {
1618
+ const full = modSeq;
1619
+ modSeq = "";
1620
+ if (modSeqTimeout)
1621
+ clearTimeout(modSeqTimeout);
1622
+ modSeqTimeout = null;
1623
+ handleRawSequence(full);
1624
+ }
1625
+ return;
1626
+ }
1627
+ modSeq = "";
1628
+ if (modSeqTimeout)
1629
+ clearTimeout(modSeqTimeout);
1630
+ modSeqTimeout = null;
1631
+ }
1618
1632
  if (consumeBracketedPaste(str, key))
1619
1633
  return;
1620
1634
  if (pasteBurst && str && str.length === 1 && !key?.ctrl && !key?.meta) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxecli/oxe",
3
- "version": "1.0.68",
3
+ "version": "1.0.69",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },