@vincemakes/kiso-tui 0.20.3 → 0.21.0
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/ask-panel.js +2 -2
- package/dist/compositor.d.ts +3 -3
- package/dist/compositor.js +70 -40
- package/dist/editor.js +23 -11
- package/dist/render.js +1 -1
- package/dist/transcript.js +1 -1
- package/package.json +2 -2
package/dist/ask-panel.js
CHANGED
|
@@ -418,7 +418,7 @@ export function askStatus(view, state) {
|
|
|
418
418
|
// that no competitor can copy without building the log first.
|
|
419
419
|
const total = view.ask.questions.length;
|
|
420
420
|
const where = total > 1 ? `question ${state.qIndex + 1} of ${total}` : "a question for you";
|
|
421
|
-
return
|
|
421
|
+
return `❯ ${where} · answers are durable facts`;
|
|
422
422
|
}
|
|
423
423
|
/** The input row's lead: the digit lead while picking, the typing lead
|
|
424
424
|
* in the custom phase (the rule-input phase's shape, reused). */
|
|
@@ -508,7 +508,7 @@ export function askView(spec) {
|
|
|
508
508
|
name: "ask_user",
|
|
509
509
|
title: first.header ?? first.question,
|
|
510
510
|
speaker: "kiso",
|
|
511
|
-
statusText: "
|
|
511
|
+
statusText: "❯ a question for you",
|
|
512
512
|
args: { kind: "text", lines: askDeclineList(spec) },
|
|
513
513
|
fallbackQuestion: `⚠ ${escapeTerminal(first.question)} — this terminal cannot show the option panel; the question is declined `,
|
|
514
514
|
ask: spec,
|
package/dist/compositor.d.ts
CHANGED
|
@@ -221,21 +221,21 @@ export declare class Body {
|
|
|
221
221
|
};
|
|
222
222
|
/** Whether the viewer owns the live region right now. */
|
|
223
223
|
viewerOpen(): boolean;
|
|
224
|
-
/** ctrl+
|
|
224
|
+
/** ctrl+r — open on the newest fold, or close. */
|
|
225
225
|
viewerToggleMode(): void;
|
|
226
226
|
/** The viewer's keys. Everything the surface can do, a key does —
|
|
227
227
|
* there is no pointer, so there is nothing a pointer could reach
|
|
228
228
|
* that a keyboard cannot. */
|
|
229
229
|
viewerKey(cmd: "up" | "down" | "toggle" | "all" | "pageUp" | "pageDown" | "home" | "end"): void;
|
|
230
230
|
/**
|
|
231
|
-
* DC-35 — ctrl+
|
|
231
|
+
* DC-35 — ctrl+o does not print the same expansion twice in a row.
|
|
232
232
|
*
|
|
233
233
|
* The ring walks newest-back and restarts its cycle once every entry
|
|
234
234
|
* has been opened (R4/C1, which is what makes the walk immune to the
|
|
235
235
|
* ring growing underneath it). With a ring of ONE the restart is
|
|
236
236
|
* immediate, so holding the key appended the identical block over
|
|
237
237
|
* and over — the owner got three copies of the same four rows, each
|
|
238
|
-
* closing with `ctrl+
|
|
238
|
+
* closing with `ctrl+o opens the one before it`, a footer naming
|
|
239
239
|
* something that does not exist.
|
|
240
240
|
*
|
|
241
241
|
* The bar is the BOTTOM of the transcript, not "ever shown": once
|
package/dist/compositor.js
CHANGED
|
@@ -47,7 +47,7 @@ import { MENU_ITEMS, displayWidth } from "./editor.js";
|
|
|
47
47
|
import { leadWidth } from "./width.js"; // W23: the ONE width authority (the editor, #inputRow, and editCol share it)
|
|
48
48
|
// KC3.5: the panel-slot reads come from the DISPATCHERS — one source
|
|
49
49
|
// for four reads, so an ask can never render half as an approval.
|
|
50
|
-
import {
|
|
50
|
+
import { panelFrameOf, panelLeadOf, panelRowsOf, panelStatusOf } from "./ask-panel.js";
|
|
51
51
|
import { MOUSE_OFF } from "./editor.js";
|
|
52
52
|
import { atPanelRows, bandHeader } from "./at-picker.js";
|
|
53
53
|
// TUI2-R2 ②: the session picker's rows — the band's third occupant.
|
|
@@ -93,7 +93,7 @@ function rolledTitle(cell) {
|
|
|
93
93
|
* one.
|
|
94
94
|
*
|
|
95
95
|
* Extracted at R3b so the segment fold's expansion opens a run to the
|
|
96
|
-
* SAME rows `ctrl+
|
|
96
|
+
* SAME rows `ctrl+o` on the run itself would have opened. Two copies of
|
|
97
97
|
* this would be two answers to "show me that run". */
|
|
98
98
|
function rolledDetail(cell, W) {
|
|
99
99
|
const p = palette();
|
|
@@ -331,7 +331,7 @@ export class Body {
|
|
|
331
331
|
#mdBase = 0;
|
|
332
332
|
#toolCells = new Map(); // callId → cell index (parallel tools)
|
|
333
333
|
// W15: the collapsed (cut) tool cells — committed cells whose last
|
|
334
|
-
// rendered row carried the "ctrl+
|
|
334
|
+
// rendered row carried the "ctrl+o" affordance; the expand key's
|
|
335
335
|
// cycling pointer walks this list from the newest back.
|
|
336
336
|
#collapsed = [];
|
|
337
337
|
/** R4 (C1) — the ring walk is by IDENTITY, not by a modular pointer.
|
|
@@ -1040,7 +1040,7 @@ export class Body {
|
|
|
1040
1040
|
lastTool() {
|
|
1041
1041
|
return this.#lastTool;
|
|
1042
1042
|
}
|
|
1043
|
-
/** W15 — the expand key's target (ctrl+
|
|
1043
|
+
/** W15 — the expand key's target (ctrl+o). A cell still in the LIVE
|
|
1044
1044
|
* region (the newest live tool) TOGGLES in place — the compositor
|
|
1045
1045
|
* owns those rows and redraws them (the body flips to the full
|
|
1046
1046
|
* form, no cap). A committed cell can never toggle — history is
|
|
@@ -1050,7 +1050,7 @@ export class Body {
|
|
|
1050
1050
|
* the header names the target ("N turns back" — the user cells
|
|
1051
1051
|
* after it), so every press tells the user what they got. */
|
|
1052
1052
|
/**
|
|
1053
|
-
* TUI2-R2 ⑤ — the cell the next ctrl+
|
|
1053
|
+
* TUI2-R2 ⑤ — the cell the next ctrl+o will act on, or -1.
|
|
1054
1054
|
*
|
|
1055
1055
|
* The rule is expandNext's own first loop, extracted verbatim: the
|
|
1056
1056
|
* LAST live cell that can toggle. It is a separate method rather than
|
|
@@ -1158,7 +1158,7 @@ export class Body {
|
|
|
1158
1158
|
const saved = head.rolled;
|
|
1159
1159
|
head.rolled = rolledOf(run);
|
|
1160
1160
|
// the run OPENS. The fold's key already asked to see the
|
|
1161
|
-
// work, so what lands is the same rows `ctrl+
|
|
1161
|
+
// work, so what lands is the same rows `ctrl+o` on the
|
|
1162
1162
|
// run itself would have opened — its title, then its
|
|
1163
1163
|
// detail — never its collapsed row, which would make the
|
|
1164
1164
|
// reader press a second time for what the first press
|
|
@@ -1226,7 +1226,7 @@ export class Body {
|
|
|
1226
1226
|
viewerOpen() {
|
|
1227
1227
|
return this.#viewer !== null;
|
|
1228
1228
|
}
|
|
1229
|
-
/** ctrl+
|
|
1229
|
+
/** ctrl+r — open on the newest fold, or close. */
|
|
1230
1230
|
viewerToggleMode() {
|
|
1231
1231
|
if (this.#viewer !== null) {
|
|
1232
1232
|
this.#viewer = null;
|
|
@@ -1288,7 +1288,7 @@ export class Body {
|
|
|
1288
1288
|
/**
|
|
1289
1289
|
* The expandable things in the transcript, oldest first.
|
|
1290
1290
|
*
|
|
1291
|
-
* The set is `#collapsed` — the SAME ring `ctrl+
|
|
1291
|
+
* The set is `#collapsed` — the SAME ring `ctrl+o` walks — so the two
|
|
1292
1292
|
* mechanisms can never disagree about what is reachable. The ring is
|
|
1293
1293
|
* newest-first (it is unshifted on commit); reading order is the
|
|
1294
1294
|
* other way, so it is reversed here.
|
|
@@ -1315,7 +1315,7 @@ export class Body {
|
|
|
1315
1315
|
}
|
|
1316
1316
|
if (cell.kind !== "tool")
|
|
1317
1317
|
continue;
|
|
1318
|
-
// the tool card's FULL body — the same rows its own ctrl+
|
|
1318
|
+
// the tool card's FULL body — the same rows its own ctrl+o
|
|
1319
1319
|
// opens. The expanded flag is saved and restored inside this
|
|
1320
1320
|
// synchronous call, the pattern the rollup path has always
|
|
1321
1321
|
// used for head.rolled; it never outlives the render, so the
|
|
@@ -1355,14 +1355,14 @@ export class Body {
|
|
|
1355
1355
|
* transcript does not already END with. */
|
|
1356
1356
|
#lastAppend = null;
|
|
1357
1357
|
/**
|
|
1358
|
-
* DC-35 — ctrl+
|
|
1358
|
+
* DC-35 — ctrl+o does not print the same expansion twice in a row.
|
|
1359
1359
|
*
|
|
1360
1360
|
* The ring walks newest-back and restarts its cycle once every entry
|
|
1361
1361
|
* has been opened (R4/C1, which is what makes the walk immune to the
|
|
1362
1362
|
* ring growing underneath it). With a ring of ONE the restart is
|
|
1363
1363
|
* immediate, so holding the key appended the identical block over
|
|
1364
1364
|
* and over — the owner got three copies of the same four rows, each
|
|
1365
|
-
* closing with `ctrl+
|
|
1365
|
+
* closing with `ctrl+o opens the one before it`, a footer naming
|
|
1366
1366
|
* something that does not exist.
|
|
1367
1367
|
*
|
|
1368
1368
|
* The bar is the BOTTOM of the transcript, not "ever shown": once
|
|
@@ -1395,7 +1395,7 @@ export class Body {
|
|
|
1395
1395
|
}
|
|
1396
1396
|
// W20: the LIVE task block toggles in place too — the capped
|
|
1397
1397
|
// form flips to the full list (the "done-collapse expands
|
|
1398
|
-
// under ctrl+
|
|
1398
|
+
// under ctrl+o" claim). The SETTLED block is already full —
|
|
1399
1399
|
// no toggle, and its rows carry no affordance, so it never
|
|
1400
1400
|
// joins #collapsed (the committed /last append is moot).
|
|
1401
1401
|
if (cell.kind === "checklist" && !cell.done) {
|
|
@@ -1462,12 +1462,12 @@ export class Body {
|
|
|
1462
1462
|
// R3i phase 4 — THE FOOTER TELLS THE TRUTH ABOUT THIS PATH.
|
|
1463
1463
|
//
|
|
1464
1464
|
// The rows come from the rollup's own projection, whose last
|
|
1465
|
-
// row reads `└ ctrl+
|
|
1465
|
+
// row reads `└ ctrl+o collapses` — true where it was written
|
|
1466
1466
|
// (the LIVE toggle, which really does close again) and false
|
|
1467
1467
|
// here. A committed row is ink: ADR-0046 forbids rewriting
|
|
1468
1468
|
// history, so nothing about this block can be taken back. The
|
|
1469
1469
|
// next press opens the NEXT fold, and the row now says so.
|
|
1470
|
-
const closing = rows.length > 0 && /ctrl\+
|
|
1470
|
+
const closing = rows.length > 0 && /ctrl\+o collapses/.test(rows[rows.length - 1] ?? "");
|
|
1471
1471
|
const body = closing ? rows.slice(0, -1) : rows;
|
|
1472
1472
|
return {
|
|
1473
1473
|
kind: "appended",
|
|
@@ -1480,7 +1480,7 @@ export class Body {
|
|
|
1480
1480
|
...body,
|
|
1481
1481
|
// R8a: an in-block note takes the block's indent, not a
|
|
1482
1482
|
// second corner — the corner opens the body above it.
|
|
1483
|
-
`${p.dim} end of expansion · ctrl+
|
|
1483
|
+
`${p.dim} end of expansion · ctrl+o opens the one before it${p.reset}`,
|
|
1484
1484
|
],
|
|
1485
1485
|
};
|
|
1486
1486
|
}
|
|
@@ -1820,8 +1820,25 @@ export class Body {
|
|
|
1820
1820
|
* now). */
|
|
1821
1821
|
#statusSource() {
|
|
1822
1822
|
const panel = this.#panelState?.() ?? null;
|
|
1823
|
+
// DC-38: the panel's STATUS replaces the CLI's painting status —
|
|
1824
|
+
// that half of W21 stands. The HINT does not come with it, because
|
|
1825
|
+
// the panel block already ends in its own affordance row and has
|
|
1826
|
+
// since TUI2-R1.5 ("the affordance — the phase's key hint, ONE
|
|
1827
|
+
// row"). Both sites read `panelAffordance`, neither knew about the
|
|
1828
|
+
// other, and an approval at W≥100 printed the same 48-cell sentence
|
|
1829
|
+
// twice, six rows apart.
|
|
1830
|
+
//
|
|
1831
|
+
// The block's copy is the one to keep, on two grounds. It sits next
|
|
1832
|
+
// to the options it names. And it never disappears: the status row
|
|
1833
|
+
// drops its hint when the left text plus the hint will not fit, so
|
|
1834
|
+
// the duplicate was width-dependent — one copy on an ask (long left
|
|
1835
|
+
// text), two on an approval (`❯ run paused`, twelve cells) — which
|
|
1836
|
+
// is why every fixed-width gate was blind to it. Each flavour's
|
|
1837
|
+
// block carries its own row (approval-panel.ts pushes it for the
|
|
1838
|
+
// approval and the pick, ask-panel.ts for the ask), so nothing is
|
|
1839
|
+
// lost anywhere.
|
|
1823
1840
|
if (panel !== null)
|
|
1824
|
-
return { status: panelStatusOf(panel), hint:
|
|
1841
|
+
return { status: panelStatusOf(panel), hint: undefined };
|
|
1825
1842
|
// W22: while turns wait in the queue, the right hint shows the
|
|
1826
1843
|
// count — the chips below carry the lines themselves.
|
|
1827
1844
|
const queued = this.#queueState?.().length ?? 0;
|
|
@@ -2116,7 +2133,7 @@ export class Body {
|
|
|
2116
2133
|
* The phases, in the order they are tested:
|
|
2117
2134
|
* - an EXPANDED live cell outranks the slot (W15 — "the user asked
|
|
2118
2135
|
* for it"): it renders in full, variable height. This is also
|
|
2119
|
-
* DC-28's cure: mid-stretch `ctrl+
|
|
2136
|
+
* DC-28's cure: mid-stretch `ctrl+o` had a target it toggled and
|
|
2120
2137
|
* never drew, so the press did nothing visible now and changed a
|
|
2121
2138
|
* later expansion's shape;
|
|
2122
2139
|
* - CALLS IN FLIGHT: one head row each within the budget, the tail
|
|
@@ -2161,8 +2178,8 @@ export class Body {
|
|
|
2161
2178
|
//
|
|
2162
2179
|
// (The approval half is a regression this round caused and its
|
|
2163
2180
|
// gate caught: the first draft treated a pending approval as a
|
|
2164
|
-
// call in flight, so
|
|
2165
|
-
// `ctrl+
|
|
2181
|
+
// call in flight, so `❯ edit x.ts` lost its diff tail and the
|
|
2182
|
+
// `ctrl+o to expand` note with it.)
|
|
2166
2183
|
const owned = tools.filter((i) => toolAt(i).expanded || toolAt(i).state === "approval");
|
|
2167
2184
|
if (owned.length > 0) {
|
|
2168
2185
|
// In CELL ORDER, so the frame reads the way the work happened:
|
|
@@ -2621,7 +2638,7 @@ export class Body {
|
|
|
2621
2638
|
panelSpan = frame.options;
|
|
2622
2639
|
}
|
|
2623
2640
|
else {
|
|
2624
|
-
// TUI2-R2 ⑤ (D, candidate 1): the FOCUS — the cell the next ctrl+
|
|
2641
|
+
// TUI2-R2 ⑤ (D, candidate 1): the FOCUS — the cell the next ctrl+o
|
|
2625
2642
|
// will act on brightens its own token. The index is derived from
|
|
2626
2643
|
// the SAME scan expandNext performs (#focusIndex shares its rule
|
|
2627
2644
|
// by construction), so the marker can never point at a cell the
|
|
@@ -2702,24 +2719,37 @@ export class Body {
|
|
|
2702
2719
|
// the steady state for the session's whole life. It repairs a
|
|
2703
2720
|
// killed predecessor straight into the same state. The visible
|
|
2704
2721
|
// cursor comes back exactly once, in editor.exit().
|
|
2705
|
-
|
|
2706
|
-
//
|
|
2707
|
-
//
|
|
2722
|
+
// DC-40 — H line feeds BEFORE the reset, from wherever the shell
|
|
2723
|
+
// left the cursor. The first frame is the full-redraw path and
|
|
2724
|
+
// addresses rows 1..H absolutely; at launch those rows are the
|
|
2725
|
+
// shell's (its prompt, the launch command, the tail of whatever
|
|
2726
|
+
// ran before), and the frame painted over them — gone, not in
|
|
2727
|
+
// the scrollback (REL-0152-D20 established the mechanism; 37/60
|
|
2728
|
+
// shell lines survived on Apple Terminal, every line ON SCREEN
|
|
2729
|
+
// lost). From cursor row r, H feeds move H−r rows and then
|
|
2730
|
+
// scroll exactly r: the shell's rows 1..r enter the scrollback
|
|
2731
|
+
// as CONTENT (at most one blank row — the cursor's own line),
|
|
2732
|
+
// the screen is blank, and the model's assumption "row 0 is the
|
|
2733
|
+
// terminal's row 1" is true by construction. The count does not
|
|
2734
|
+
// depend on r, so nothing is asked of the terminal.
|
|
2708
2735
|
//
|
|
2709
|
-
//
|
|
2710
|
-
//
|
|
2711
|
-
//
|
|
2712
|
-
//
|
|
2713
|
-
//
|
|
2714
|
-
//
|
|
2715
|
-
//
|
|
2716
|
-
//
|
|
2736
|
+
// THE ORDER IS THE FIX. `ESC[r` (DECSTBM) HOMES THE CURSOR to
|
|
2737
|
+
// row 1 — VT100 semantics, honoured by Apple Terminal, xterm,
|
|
2738
|
+
// xterm.js and tmux alike. Feeds emitted AFTER the reset start
|
|
2739
|
+
// from row 1, move H−1 rows and scroll ONE: measured on Apple
|
|
2740
|
+
// Terminal, 1/20 shell lines survived with an otherwise
|
|
2741
|
+
// byte-identical frame. Feeds BEFORE the reset: 20/20. The house
|
|
2742
|
+
// emulators did not model the homing and passed the wrong order;
|
|
2743
|
+
// VtScrollback does now, and the DC-40 gate is red on it.
|
|
2717
2744
|
//
|
|
2718
|
-
// The
|
|
2719
|
-
//
|
|
2720
|
-
//
|
|
2721
|
-
//
|
|
2722
|
-
//
|
|
2745
|
+
// The reset still precedes the FRAME (REL-0152-D19: a frame
|
|
2746
|
+
// drawn into an inherited sub-region is the defect); only the
|
|
2747
|
+
// feeds run under whatever region the shell left. A region a
|
|
2748
|
+
// killed foreign program left set makes the feeds scroll that
|
|
2749
|
+
// region alone and the frame paint over the rows outside it —
|
|
2750
|
+
// which is what every frame did before this fix, never worse.
|
|
2751
|
+
out.push("\n".repeat(H));
|
|
2752
|
+
out.push("\x1b[r\x1b[?69l\x1b[?7h\x1b[?25l");
|
|
2723
2753
|
}
|
|
2724
2754
|
out.push("\x1b[?7l");
|
|
2725
2755
|
// REL-0161: ?25l is the STEADY state now, not a frame bracket —
|
|
@@ -2852,11 +2882,11 @@ export class Body {
|
|
|
2852
2882
|
#commitCell(i, W, ctx) {
|
|
2853
2883
|
const cell = this.#cells[i];
|
|
2854
2884
|
const lines = this.#foldOrRollup(cell, i, W, ctx);
|
|
2855
|
-
// W15: a tool cell whose committed rows carried the "ctrl+
|
|
2885
|
+
// W15: a tool cell whose committed rows carried the "ctrl+o"
|
|
2856
2886
|
// affordance joins the expand history — the detection is the
|
|
2857
2887
|
// renderer's OWN output, so the read's "/last"-only cut note never
|
|
2858
2888
|
// lands here. TUI2-R1 (A/B): the affordance is no longer only the
|
|
2859
|
-
// renderer cut's "└ … ctrl+
|
|
2889
|
+
// renderer cut's "└ … ctrl+o" — the self-naming head suffix and
|
|
2860
2890
|
// the exploration row carry it on the HEAD row, and a promise the
|
|
2861
2891
|
// key does not answer would be the one thing worse than silence.
|
|
2862
2892
|
// unshift: the cells commit oldest-first, so the NEWEST cut lands
|
|
@@ -2870,13 +2900,13 @@ export class Body {
|
|
|
2870
2900
|
// printed bytes.
|
|
2871
2901
|
//
|
|
2872
2902
|
// This used to require the rendered rows to contain the literal
|
|
2873
|
-
// "ctrl+
|
|
2903
|
+
// "ctrl+o", which made the affordance LOAD-BEARING: retiring the
|
|
2874
2904
|
// printed key (the owner's ruling) would have silently emptied the
|
|
2875
2905
|
// ring and taken the expand key with it — not a missing hint, a
|
|
2876
2906
|
// missing feature. A fold head is a fold head because the segment
|
|
2877
2907
|
// says so; a tool cell is expandable when it is hiding rows.
|
|
2878
2908
|
const isFoldHead = this.#segmentOf(i)?.headCell === i;
|
|
2879
|
-
const hidesRows = cell.kind === "tool" && lines.some((l) => l.includes("ctrl+
|
|
2909
|
+
const hidesRows = cell.kind === "tool" && lines.some((l) => l.includes("ctrl+o"));
|
|
2880
2910
|
if (isFoldHead || hidesRows) {
|
|
2881
2911
|
this.#collapsed.unshift(i);
|
|
2882
2912
|
// R4a — a new fold resets the walk, so the FIRST press after any
|
package/dist/editor.js
CHANGED
|
@@ -83,7 +83,7 @@ export function viewerCommand(text) {
|
|
|
83
83
|
return "end";
|
|
84
84
|
case "\x1b":
|
|
85
85
|
case "q":
|
|
86
|
-
case "\
|
|
86
|
+
case "\x12": // ctrl+r — the key that opens it also puts it away
|
|
87
87
|
return "close";
|
|
88
88
|
default:
|
|
89
89
|
return null;
|
|
@@ -275,7 +275,7 @@ export class Editor {
|
|
|
275
275
|
// the CLI's — here it is only "these two keys, pressed together, hand
|
|
276
276
|
// the line over by a different door than Enter's".
|
|
277
277
|
#redirectCbs = [];
|
|
278
|
-
// W15: the expand-key list (ctrl+
|
|
278
|
+
// W15: the expand-key list (ctrl+o) — the CLI's dispatch decides the
|
|
279
279
|
// target (a live cell toggles in place; a committed cell appends the
|
|
280
280
|
// expanded block). Mirrors the escape list: multiple listeners can
|
|
281
281
|
// coexist; the editor never interprets the key itself.
|
|
@@ -929,7 +929,7 @@ export class Editor {
|
|
|
929
929
|
// sheet (which any key dismisses) this surface is INTERACTIVE, so
|
|
930
930
|
// the chunk is matched against its own bindings and anything
|
|
931
931
|
// unrecognised is swallowed rather than typed into the composer
|
|
932
|
-
// behind it. esc closes; ctrl+
|
|
932
|
+
// behind it. esc closes; ctrl+r closes too, so the key that opens
|
|
933
933
|
// it also puts it away.
|
|
934
934
|
if (this.#viewerUp?.() === true) {
|
|
935
935
|
const cmd = viewerCommand(text);
|
|
@@ -1407,18 +1407,30 @@ export class Editor {
|
|
|
1407
1407
|
}
|
|
1408
1408
|
i += 1;
|
|
1409
1409
|
}
|
|
1410
|
-
else if (c === "\
|
|
1411
|
-
// W15: the expand key
|
|
1412
|
-
//
|
|
1410
|
+
else if (c === "\x0f") {
|
|
1411
|
+
// W15: the expand key — rides the chain like a command, the
|
|
1412
|
+
// editor just forwards it.
|
|
1413
|
+
//
|
|
1414
|
+
// DC-41 (owner ruling 2026-09-02): this is ctrl+o now. R5
|
|
1415
|
+
// gave ctrl+o to the viewer because it was free and because
|
|
1416
|
+
// the reference implementation uses it — betting that the
|
|
1417
|
+
// finger cared about the KEY. It does not: the reference's
|
|
1418
|
+
// ctrl+o expands the tool output in front of you, which is
|
|
1419
|
+
// this action, and the owner reported reaching for it and
|
|
1420
|
+
// getting a reader. The gesture and the job are together
|
|
1421
|
+
// again; §7.1 is why kiso's form of it appends rather than
|
|
1422
|
+
// toggling in place.
|
|
1413
1423
|
for (const cb of [...this.#expandCbs])
|
|
1414
1424
|
cb();
|
|
1415
1425
|
i += 1;
|
|
1416
1426
|
}
|
|
1417
|
-
else if (c === "\
|
|
1418
|
-
// R5 —
|
|
1419
|
-
//
|
|
1420
|
-
//
|
|
1421
|
-
//
|
|
1427
|
+
else if (c === "\x12" && this.#composerIdle() && this.#chars.length === 0) {
|
|
1428
|
+
// R5 — the transcript viewer, on ctrl+r since DC-41. The
|
|
1429
|
+
// reference binds ctrl+r to renaming a session, which kiso
|
|
1430
|
+
// has no equivalent of, so nothing a reference user means by
|
|
1431
|
+
// it is displaced; every other free control key in this
|
|
1432
|
+
// dispatch collides with something that surface actually
|
|
1433
|
+
// does. Idle composer only, exactly like `?`:
|
|
1422
1434
|
// mid-text it would be a keystroke stolen from the human.
|
|
1423
1435
|
this.#viewerSend("open");
|
|
1424
1436
|
i += 1;
|
package/dist/render.js
CHANGED
|
@@ -72,7 +72,7 @@ export function renderEvent(ev, prevThinking = false, resolvePath = (p) => p) {
|
|
|
72
72
|
case "permission_requested":
|
|
73
73
|
// round 8: the tool NAME is model text — escaped like everything else.
|
|
74
74
|
return {
|
|
75
|
-
text:
|
|
75
|
+
text: `❯ ${escapeTerminal(ev.name)} needs approval ${p.dim}${approvalDetail(ev.name, ev.input, resolvePath)}${p.reset} `,
|
|
76
76
|
newline: false,
|
|
77
77
|
prompt: true,
|
|
78
78
|
};
|
package/dist/transcript.js
CHANGED
|
@@ -38,7 +38,7 @@ import { visibleWidth } from "./components.js";
|
|
|
38
38
|
/** The gutter every viewer row carries: the cursor mark and its space. */
|
|
39
39
|
export const VIEWER_GUTTER = 3;
|
|
40
40
|
export function viewerInit(entries) {
|
|
41
|
-
// the cursor starts on the NEWEST fold — the one ctrl+
|
|
41
|
+
// the cursor starts on the NEWEST fold — the one ctrl+o would have
|
|
42
42
|
// opened, so the two mechanisms agree on their first answer.
|
|
43
43
|
return { cursor: Math.max(0, entries.length - 1), top: 0, open: new Set() };
|
|
44
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
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",
|
|
@@ -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.
|
|
38
|
+
"@vincemakes/kiso-tui-cells": "0.21.0"
|
|
39
39
|
}
|
|
40
40
|
}
|