@vincemakes/kiso-tui 0.1.21 → 0.1.24
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/body.d.ts +9 -0
- package/dist/body.js +49 -5
- package/dist/editor.d.ts +1 -1
- package/dist/editor.js +5 -1
- package/dist/render.d.ts +4 -2
- package/dist/render.js +2 -2
- package/package.json +2 -2
package/dist/body.d.ts
CHANGED
|
@@ -84,6 +84,15 @@ export declare class Body {
|
|
|
84
84
|
constructor(opts: BodyOptions);
|
|
85
85
|
/** Teardown — flush a pending frame, stop the timers. */
|
|
86
86
|
close(): void;
|
|
87
|
+
/**
|
|
88
|
+
* TUI v4 #16a: a resize reflows the terminal's scrollback — the frozen
|
|
89
|
+
* rows' positions are no longer what we tracked (and the frozen CONTENT
|
|
90
|
+
* is never re-emitted: the terminal reflowed it, we only redraw the
|
|
91
|
+
* dock + active tail). The counters reset so the next render writes new
|
|
92
|
+
* frozen lines through the REAL-LF scroll path above the tail, never at
|
|
93
|
+
* a stale CUP row (the drag-garbage the #16 user saw).
|
|
94
|
+
*/
|
|
95
|
+
onResize(): void;
|
|
87
96
|
/** The last COMPLETE thinking block, for /think. */
|
|
88
97
|
lastThinking(): string | null;
|
|
89
98
|
/** The last completed tool call, for /last. */
|
package/dist/body.js
CHANGED
|
@@ -48,11 +48,21 @@ export class Body {
|
|
|
48
48
|
#pipeBuf = ""; // the passthrough's thinking buffer — the cell model needs no buffer
|
|
49
49
|
#toolCells = new Map(); // callId → cell index (parallel tools)
|
|
50
50
|
#write;
|
|
51
|
+
#resizeHandler = null;
|
|
51
52
|
constructor(opts) {
|
|
52
53
|
this.#opts = opts;
|
|
53
54
|
this.#write = opts.write ?? ((s) => process.stdout.write(s));
|
|
54
55
|
this.#active = opts.active();
|
|
55
56
|
if (this.#isActive()) {
|
|
57
|
+
// TUI v4 #16a: the resize event — the terminal reflows its
|
|
58
|
+
// scrollback, so OUR row bookkeeping is stale. The frozen
|
|
59
|
+
// content is never re-emitted (the terminal reflowed it); the
|
|
60
|
+
// counters reset so the next render lands new frozen lines via
|
|
61
|
+
// the REAL-LF scroll path (just above the tail), never at stale
|
|
62
|
+
// CUP rows — the overwrite garbage after a drag (the #16
|
|
63
|
+
// defect). The dock redraws its own chrome on the same event.
|
|
64
|
+
this.#resizeHandler = () => this.onResize();
|
|
65
|
+
process.stdout.on("resize", this.#resizeHandler);
|
|
56
66
|
this.#heartbeat = setInterval(() => {
|
|
57
67
|
// #14/#15: the idle heartbeat PAINTS NOTHING unless an
|
|
58
68
|
// ANIMATION advances — only a RUNNING tool's glyph/elapsed
|
|
@@ -86,9 +96,32 @@ export class Body {
|
|
|
86
96
|
clearInterval(this.#heartbeat);
|
|
87
97
|
this.#heartbeat = null;
|
|
88
98
|
}
|
|
99
|
+
if (this.#resizeHandler !== null) {
|
|
100
|
+
process.stdout.off("resize", this.#resizeHandler);
|
|
101
|
+
this.#resizeHandler = null;
|
|
102
|
+
}
|
|
89
103
|
if (this.#dirty)
|
|
90
104
|
this.render();
|
|
91
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* TUI v4 #16a: a resize reflows the terminal's scrollback — the frozen
|
|
108
|
+
* rows' positions are no longer what we tracked (and the frozen CONTENT
|
|
109
|
+
* is never re-emitted: the terminal reflowed it, we only redraw the
|
|
110
|
+
* dock + active tail). The counters reset so the next render writes new
|
|
111
|
+
* frozen lines through the REAL-LF scroll path above the tail, never at
|
|
112
|
+
* a stale CUP row (the drag-garbage the #16 user saw).
|
|
113
|
+
*/
|
|
114
|
+
onResize() {
|
|
115
|
+
if (!this.#isActive())
|
|
116
|
+
return;
|
|
117
|
+
this.#frozenRows = Number.MAX_SAFE_INTEGER; // the frozen area is "full" — the next line scrolls
|
|
118
|
+
this.#oldTailTop = 0; // the reflowed tail's old rows are gone — clear only the new area
|
|
119
|
+
// NO #dirty: an immediate frame would re-render the ACTIVE TAIL —
|
|
120
|
+
// re-emitting its bytes (the terminal already reflowed the tail's
|
|
121
|
+
// content; a re-print duplicates the text in the byte stream — the
|
|
122
|
+
// #16 storm gate's "response text exactly once"). The geometry
|
|
123
|
+
// reset takes effect at the next NATURAL render (the next event).
|
|
124
|
+
}
|
|
92
125
|
/** The last COMPLETE thinking block, for /think. */
|
|
93
126
|
lastThinking() {
|
|
94
127
|
return this.#lastThinking;
|
|
@@ -372,10 +405,13 @@ export class Body {
|
|
|
372
405
|
const p = palette();
|
|
373
406
|
switch (cell.kind) {
|
|
374
407
|
case "user":
|
|
375
|
-
// v3 §02: the user message is a SGR
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
|
|
408
|
+
// v3 §02: the user message is a SGR block, no prefix — every
|
|
409
|
+
// line carries the block's highlight (multi-line whole;
|
|
410
|
+
// resize-safe). TUI v4 #16c: the fixed dark background
|
|
411
|
+
// (48;5;237) is GONE — reverse video (7m) swaps foreground/
|
|
412
|
+
// background, so the block follows the terminal theme (light
|
|
413
|
+
// theme → dark text on light). Pipes stay plain.
|
|
414
|
+
return cell.text.split("\n").map((l) => `${p.rev}${escapeTerminal(l)}${p.reset}`);
|
|
379
415
|
case "thinking": {
|
|
380
416
|
const block = cell.text;
|
|
381
417
|
const trimmed = escapeTerminal(block.trim());
|
|
@@ -425,7 +461,15 @@ export class Body {
|
|
|
425
461
|
case "notice":
|
|
426
462
|
return [escapeTerminal(cell.text)];
|
|
427
463
|
case "raw":
|
|
428
|
-
|
|
464
|
+
// TUI v4 #16b: the raw cell carries the CLI's OWN pre-rendered
|
|
465
|
+
// lines (the banner, the recap, slash-command output) — the
|
|
466
|
+
// SGR is applied at COMPOSITION time (renderRecap/startupBanner),
|
|
467
|
+
// and model/tool content was already escapeTerminal'd there.
|
|
468
|
+
// Re-escaping at render STRIPPED the ESC from the SGR — the
|
|
469
|
+
// literal "[38;5;75m▞[0m" garbage the user saw (the #16 乱码,
|
|
470
|
+
// also the banner's dim). Verbatim: the injection guard lives
|
|
471
|
+
// at composition, not here.
|
|
472
|
+
return cell.lines;
|
|
429
473
|
case "terminal":
|
|
430
474
|
// the honest label (done / aborted / error) + the status + the
|
|
431
475
|
// rhythm gap blank
|
package/dist/editor.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare function charWidth(cp: number): number;
|
|
|
22
22
|
export declare function widthOf(chars: readonly number[]): number;
|
|
23
23
|
/** Display width of a string. */
|
|
24
24
|
export declare function displayWidth(text: string): number;
|
|
25
|
-
export declare const PROMPT = "\
|
|
25
|
+
export declare const PROMPT = "\u258C ";
|
|
26
26
|
export declare const PROMPT_WIDTH: number;
|
|
27
27
|
/** v3 §04 — the slash-command menu's command table (English one-liners). */
|
|
28
28
|
export interface MenuItem {
|
package/dist/editor.js
CHANGED
|
@@ -67,10 +67,14 @@ export function displayWidth(text) {
|
|
|
67
67
|
return w;
|
|
68
68
|
}
|
|
69
69
|
import { palette } from "./render.js";
|
|
70
|
-
|
|
70
|
+
// TUI v4 #16d: the input row is the blue brick + the edit area — the
|
|
71
|
+
// "you>" text is gone (the brick IS the prompt; the pipe path's readline
|
|
72
|
+
// prompt keeps its own "you> " — v2a line mode, byte-for-byte).
|
|
73
|
+
export const PROMPT = "▌ ";
|
|
71
74
|
export const PROMPT_WIDTH = displayWidth(PROMPT);
|
|
72
75
|
export const MENU_ITEMS = [
|
|
73
76
|
{ name: "/mode", desc: "switch the approval tier (manual/default/accept-edits/plan/bypass)" },
|
|
77
|
+
{ name: "/model", desc: "list model profiles; switch with /model <name|provider/model>" },
|
|
74
78
|
{ name: "/compact", desc: "summarize the older conversation to free context" },
|
|
75
79
|
{ name: "/think", desc: "show the last full thinking block" },
|
|
76
80
|
{ name: "/last", desc: "show the most recent tool call's input and output" },
|
package/dist/render.d.ts
CHANGED
|
@@ -14,14 +14,16 @@
|
|
|
14
14
|
* errors; dim for metadata. NO_COLOR set, or a non-TTY output → every
|
|
15
15
|
* code is empty, so pipes and CI carry ZERO ANSI (the existing byte-level
|
|
16
16
|
* e2e assertions guard it). Everything not listed here is plain.
|
|
17
|
-
* v3: `
|
|
17
|
+
* v3: `rev` — the user-message block highlight (SGR 7 reverse video,
|
|
18
|
+
* TUI v4 #16c: the fixed dark background is GONE — reverse follows the
|
|
19
|
+
* terminal theme).
|
|
18
20
|
*/
|
|
19
21
|
export interface Palette {
|
|
20
22
|
readonly blue: string;
|
|
21
23
|
readonly dim: string;
|
|
22
24
|
readonly red: string;
|
|
23
25
|
readonly green: string;
|
|
24
|
-
readonly
|
|
26
|
+
readonly rev: string;
|
|
25
27
|
readonly reset: string;
|
|
26
28
|
}
|
|
27
29
|
export declare const COLOR_ON: Palette;
|
package/dist/render.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* kiso-core's Event — the CLI translates Event → RenderInput. The tui
|
|
8
8
|
* package has ZERO kiso-core imports: input is data, output is bytes.
|
|
9
9
|
*/
|
|
10
|
-
export const COLOR_ON = { blue: "\x1b[38;5;75m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m",
|
|
11
|
-
export const COLOR_OFF = { blue: "", dim: "", red: "", green: "",
|
|
10
|
+
export const COLOR_ON = { blue: "\x1b[38;5;75m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m", rev: "\x1b[7m", reset: "\x1b[0m" };
|
|
11
|
+
export const COLOR_OFF = { blue: "", dim: "", red: "", green: "", rev: "", reset: "" };
|
|
12
12
|
export function palette() {
|
|
13
13
|
return process.env.NO_COLOR === undefined && process.stdout.isTTY ? COLOR_ON : COLOR_OFF;
|
|
14
14
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "kiso tui
|
|
3
|
+
"version": "0.1.24",
|
|
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",
|
|
7
7
|
"exports": {
|