@vincemakes/kiso-tui 0.16.0 → 0.16.1

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.
@@ -1473,7 +1473,11 @@ export class Body {
1473
1473
  // frame, and the PTY gates that wait on the boot stream feel
1474
1474
  // it; inside the frame it is four sequences and no new event.
1475
1475
  this.#needsReset = false;
1476
- out.push("\x1b[r\x1b[?69l\x1b[?7h\x1b[?25h");
1476
+ // REL-0161: the reset ESTABLISHES the hidden cursor (?25l)
1477
+ // the steady state for the session's whole life. It repairs a
1478
+ // killed predecessor straight into the same state. The visible
1479
+ // cursor comes back exactly once, in editor.exit().
1480
+ out.push("\x1b[r\x1b[?69l\x1b[?7h\x1b[?25l");
1477
1481
  // REL-0152-D20 — the mechanism is understood and the obvious fix
1478
1482
  // is NOT taken here. See the finding.
1479
1483
  //
@@ -1493,7 +1497,12 @@ export class Body {
1493
1497
  // for stdin).
1494
1498
  }
1495
1499
  out.push("\x1b[?7l");
1496
- out.push(this.#conservative ? "\x1b[?25l" : "\x1b[?2026h"); // D1: sync ON, or cursor-hide where 2026 is dead bytes
1500
+ // REL-0161: ?25l is the STEADY state now, not a frame bracket
1501
+ // re-asserted at every frame open as self-healing (a subprocess
1502
+ // or stray output that showed the cursor is corrected here), and
1503
+ // never paired with a ?25h. Sync (2026) still brackets the frame
1504
+ // where the terminal understands it.
1505
+ out.push(this.#conservative ? "\x1b[?25l" : "\x1b[?2026h\x1b[?25l");
1497
1506
  // A8: the bottom-anchored window (the model's last H rows) shifts
1498
1507
  // DOWN when the live region SHRINKS — the done-fold, the fold-hold
1499
1508
  // release at the terminal event. The steady path's scroll syncs
@@ -1517,7 +1526,12 @@ export class Body {
1517
1526
  // with it.
1518
1527
  this.#drawFull(out, W, H, liveTop, liveLines, queueRows, menuRows, editor);
1519
1528
  this.#fullRedraw = false;
1520
- out.push(this.#conservative ? "\x1b[?25h" : "\x1b[?2026l");
1529
+ // REL-0161: the frame close no longer shows the cursor — hidden IS
1530
+ // the steady state (Terminal.app infers "a prompt line" from
1531
+ // bracketed-paste + a visible cursor and decorates it with a Mark;
1532
+ // the composer draws its own cursor cell instead — #inputRowBytes).
1533
+ if (!this.#conservative)
1534
+ out.push("\x1b[?2026l");
1521
1535
  out.push("\x1b[?7h"); // REL-0152-D14: autowrap back on for everything outside the frame
1522
1536
  this.#inFrame = true;
1523
1537
  try {
@@ -1902,16 +1916,47 @@ export class Body {
1902
1916
  markerLine += CURSOR_MARKER;
1903
1917
  markerCell = w;
1904
1918
  }
1905
- const stripped0 = markerLine.replace(CURSOR_MARKER, "");
1906
1919
  if (W < 4) {
1907
1920
  // the degenerate screen: the box cannot hold its walls — the
1908
1921
  // bare row (the pre-W6 bytes; the fold probe's pass-through
1909
1922
  // line still crashes invariant ① downstream, as before)
1910
- return { stripped: stripped0, markerCell };
1923
+ return { stripped: markerLine.replace(CURSOR_MARKER, ""), markerCell };
1924
+ }
1925
+ // REL-0161 — the DRAWN cursor. The hardware cursor is hidden for
1926
+ // the session's life (Terminal.app infers "a prompt line" from
1927
+ // bracketed-paste + a visible cursor and Marks it), so the cell
1928
+ // at the marker renders inverse instead. The hardware cursor
1929
+ // still PARKS at the marker — the IME anchor is its position.
1930
+ const mi = markerLine.indexOf(CURSOR_MARKER);
1931
+ let stripped0;
1932
+ let cursorPad = 0; // 1 when the drawn cursor consumed a pad cell
1933
+ if (mi < 0) {
1934
+ stripped0 = markerLine; // a row that does not own the cursor
1935
+ }
1936
+ else {
1937
+ const before = markerLine.slice(0, mi);
1938
+ const after = markerLine.slice(mi + CURSOR_MARKER.length);
1939
+ if (after.length === 0) {
1940
+ // the cursor rests past the content — an inverse space,
1941
+ // taken OUT of the pad (the walk capped content at W−4,
1942
+ // so the pad is ≥ 1 and the row still totals W)
1943
+ stripped0 = `${before}\x1b[7m \x1b[27m`;
1944
+ cursorPad = 1;
1945
+ }
1946
+ else if (after[0] === "\x1b" || (after.codePointAt(0) >= 0xd800 && after.codePointAt(0) <= 0xdfff)) {
1947
+ // never wrap a sequence, never split a surrogate pair —
1948
+ // the cell keeps its bytes, the parked cursor still marks
1949
+ // the position for the terminal's own affordances
1950
+ stripped0 = before + after;
1951
+ }
1952
+ else {
1953
+ const glyph = String.fromCodePoint(after.codePointAt(0));
1954
+ stripped0 = `${before}\x1b[7m${glyph}\x1b[27m${after.slice(glyph.length)}`;
1955
+ }
1911
1956
  }
1912
1957
  // the pad completes the row to W — the content stopped at W−4,
1913
- // so the pad is ≥ 1
1914
- const padW = W - 3 - w;
1958
+ // so the pad is ≥ 1 (≥ 0 after the drawn cursor consumed one)
1959
+ const padW = W - 3 - w - cursorPad;
1915
1960
  return { stripped: `\x1b[2m│ \x1b[0m${stripped0}\x1b[2m${" ".repeat(padW)}│\x1b[0m`, markerCell };
1916
1961
  }
1917
1962
  /** KC1 §6 — the focus component's input ROWS (N = 1 today's single
package/dist/editor.js CHANGED
@@ -748,6 +748,12 @@ export class Editor {
748
748
  process.stdout.write(MOUSE_OFF);
749
749
  this.#mouseOn = false;
750
750
  process.stdout.write("\x1b[?2004l"); // bracketed paste OFF
751
+ // REL-0161: the hardware cursor was hidden for the session's whole
752
+ // life (the compositor's entry reset); this is the one place kiso
753
+ // hands the terminal back. kill -9 skips it — the same exposure
754
+ // the reference implementation accepts; the entry repair covers
755
+ // the next kiso, and `reset` covers the shell.
756
+ process.stdout.write("\x1b[?25h");
751
757
  process.stdin.setRawMode(false);
752
758
  this.#closedResolve();
753
759
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-tui",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "kiso tui \u2014 the pure terminal layer (cell renderer, dock, raw editor, diff, palette). Zero runtime dependencies: input is data, output is bytes.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -35,6 +35,6 @@
35
35
  },
36
36
  "homepage": "https://github.com/vincemakes/kiso/tree/main/packages/tui#readme",
37
37
  "dependencies": {
38
- "@vincemakes/kiso-tui-cells": "0.16.0"
38
+ "@vincemakes/kiso-tui-cells": "0.16.1"
39
39
  }
40
40
  }