@vincemakes/kiso-tui 0.1.33 → 0.1.35
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/components.js +10 -3
- package/dist/compositor.js +42 -20
- package/package.json +1 -1
package/dist/components.js
CHANGED
|
@@ -165,7 +165,10 @@ class UserMessage {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
/** The thinking fold — one dim line, width-capped so the /think suffix
|
|
168
|
-
* rides the fold's own row (the #17 fix's slice, componentized).
|
|
168
|
+
* rides the fold's own row (the #17 fix's slice, componentized). The
|
|
169
|
+
* slice is DISPLAY-WIDTH-based (the char-based slice overflowed with
|
|
170
|
+
* CJK — 2 cells per char — and tripped invariant ① on a real
|
|
171
|
+
* Chinese session). */
|
|
169
172
|
class ThinkingFold {
|
|
170
173
|
cell;
|
|
171
174
|
constructor(cell) {
|
|
@@ -174,11 +177,15 @@ class ThinkingFold {
|
|
|
174
177
|
render(W, _ctx) {
|
|
175
178
|
const block = this.cell.text;
|
|
176
179
|
const trimmed = escapeTerminal(block.trim());
|
|
180
|
+
// the SHORT branch is width-aware TOO: the ≤100 short-circuit was
|
|
181
|
+
// W-blind — a short block at a narrow width returned the line
|
|
182
|
+
// UNFOLDED and tripped invariant ① (the crash class still live on
|
|
183
|
+
// npm for short /think blocks after a resize).
|
|
177
184
|
if (trimmed.length <= 100)
|
|
178
|
-
return [`${palette().dim}…${trimmed}${palette().reset}`];
|
|
185
|
+
return [`${palette().dim}…${widthCut(trimmed, Math.max(1, W - 1))}${palette().reset}`];
|
|
179
186
|
const suffix = ` (${block.length} chars · /think)`;
|
|
180
187
|
const slice = Math.max(1, W - 1 - suffix.length);
|
|
181
|
-
return [`${palette().dim}…${trimmed
|
|
188
|
+
return [`${palette().dim}…${widthCut(trimmed, slice)}${suffix}${palette().reset}`];
|
|
182
189
|
}
|
|
183
190
|
}
|
|
184
191
|
/** The tool execution line + the approval mini-diff — every state is
|
package/dist/compositor.js
CHANGED
|
@@ -674,15 +674,16 @@ export class Body {
|
|
|
674
674
|
#drawSteady(out, W, H, liveTop, liveLines, menuRows, ctx) {
|
|
675
675
|
const editor = this.#inputRow(W, ctx); // derived from the frame — the marker
|
|
676
676
|
const committed = this.#committedLinesThisFrame;
|
|
677
|
-
// the
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
677
|
+
// the jump from the anchor (H−2) straight to the bottom row H,
|
|
678
|
+
// then N real LFs scroll the screen exactly N rows — ONE per
|
|
679
|
+
// committed line (the bookkeeping; the stale 1B anchor jumped to
|
|
680
|
+
// H−1 and the N LFs scrolled only N−1 — the committed section sat
|
|
681
|
+
// one row short in the scrollback). The bottom-up repaint below
|
|
682
|
+
// overwrites the scrolled-in rows (the scroll count is screen-
|
|
683
|
+
// neutral — proven by the emulator probe).
|
|
684
|
+
out.push("\x1b[2B");
|
|
685
|
+
for (let i = 0; i < committed.length; i += 1)
|
|
686
|
+
out.push("\n");
|
|
686
687
|
// the bottom-up repaint, from the last row up — V6-3: the design
|
|
687
688
|
// §03 chrome: status (H), lower ╌ (H−1), input (H−2), upper ╌ (H−3)
|
|
688
689
|
out.push(`\x1b[1G\x1b[0K${this.#checked(statusLine(this.#status, this.#tail, this.#question !== null, W), W)}`); // H — the status
|
|
@@ -692,17 +693,26 @@ export class Body {
|
|
|
692
693
|
for (let i = menuRows.length - 1; i >= 0; i -= 1) {
|
|
693
694
|
out.push(`\x1b[1A\x1b[1G\x1b[0K${this.#checked(menuRows[i], W)}`);
|
|
694
695
|
}
|
|
695
|
-
|
|
696
|
-
|
|
696
|
+
// the LIVE lines at their MODEL rows — CUP, never the relative
|
|
697
|
+
// march: the march drew them adjacent to the chrome (rows
|
|
698
|
+
// H−3−n..H−3) while the model placed them at [liveTop..liveTop+n−1]
|
|
699
|
+
// — in the unclamped geometry the gap ELs below erased the march's
|
|
700
|
+
// copy and the streamed text was INVISIBLE until the commit frame.
|
|
701
|
+
// The CUP rows land in the content area (≤ H−4−menu ≤ 21), inside
|
|
702
|
+
// the frozen CUP budget of invariant ②.
|
|
703
|
+
for (let i = 0; i < liveLines.length; i += 1) {
|
|
704
|
+
out.push(`\x1b[${liveTop + i};1H\x1b[0K${this.#checked(liveLines[i], W)}`);
|
|
697
705
|
}
|
|
698
706
|
// the FROZEN area — CUP (absolute rows; this is the FREEZE path —
|
|
699
|
-
// the old code's frozen writes were CUP too. The
|
|
700
|
-
//
|
|
701
|
-
//
|
|
702
|
-
//
|
|
707
|
+
// the old code's frozen writes were CUP too. The frozen rows are
|
|
708
|
+
// computed from the current geometry, so external writes (the CLI's
|
|
709
|
+
// console.error CRLF) cannot misplace them the way a relative march
|
|
710
|
+
// could).
|
|
703
711
|
// 1. the GAP rows (between the live content and the chrome) — EL'd
|
|
704
|
-
// so the old content there cannot ghost
|
|
705
|
-
|
|
712
|
+
// so the old content there cannot ghost; the range stops ABOVE
|
|
713
|
+
// the menu (the menu's rows at [H−3−menu..H−4] are marched and
|
|
714
|
+
// must survive — the unclamped geometry erased them).
|
|
715
|
+
for (let r = liveTop + liveLines.length; r <= H - 4 - menuRows.length; r += 1) {
|
|
706
716
|
out.push(`\x1b[${r};1H\x1b[0K`);
|
|
707
717
|
}
|
|
708
718
|
// 2. the STALE rows above the committed section — the scrolled old
|
|
@@ -719,9 +729,21 @@ export class Body {
|
|
|
719
729
|
out.push(`\x1b[${Math.max(1, liveTop - committed.length + i)};1H\x1b[0K${this.#checked(committed[i], W)}`);
|
|
720
730
|
}
|
|
721
731
|
// the cursor: down to the anchor (H−2, the input row) + left to the marker —
|
|
722
|
-
// the down-distance from the LAST written row
|
|
723
|
-
//
|
|
724
|
-
|
|
732
|
+
// the down-distance from the LAST written row, in byte order: the
|
|
733
|
+
// committed band's bottom, then the stale ELs' bottom, then the gap
|
|
734
|
+
// ELs' bottom, then the live lines' bottom, then the menu's top
|
|
735
|
+
// (its last marched row), else the chrome's upper ╌.
|
|
736
|
+
const lastRow = committed.length > 0
|
|
737
|
+
? Math.max(1, liveTop - 1)
|
|
738
|
+
: staleFrom < liveTop
|
|
739
|
+
? liveTop - 1
|
|
740
|
+
: liveTop + liveLines.length <= H - 4 - menuRows.length
|
|
741
|
+
? H - 4 - menuRows.length
|
|
742
|
+
: liveLines.length > 0
|
|
743
|
+
? liveTop + liveLines.length - 1
|
|
744
|
+
: menuRows.length > 0
|
|
745
|
+
? H - 3 - menuRows.length
|
|
746
|
+
: H - 3;
|
|
725
747
|
const down = H - 2 - lastRow; // the anchor: the input row (H−2)
|
|
726
748
|
if (down > 0)
|
|
727
749
|
out.push(`\x1b[${down}B`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"description": "kiso tui — 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",
|