@vincemakes/kiso-tui 0.43.0 → 0.45.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.
@@ -160,21 +160,6 @@ export declare class Body {
160
160
  */
161
161
  fold(label: string, replay: () => void, summary?: string | null): void;
162
162
  notice(text: string): void;
163
- /** W20 — the task checklist as STATE, not events: the FIRST call of a
164
- * turn creates the ONE live block (done:false — the commit loop only
165
- * takes done cells, so it stays in the live region); later calls of
166
- * the SAME turn MUTATE that block in place — same position, same
167
- * height, zero committed rows (the W8 fixed-window rule generalised
168
- * to state). An unchanged whole-table replace (the task extension's
169
- * idempotent shape) is a no-op — no mark, no frame. The block commits
170
- * ONCE at the turn's end (endTurn); the next turn's first call starts
171
- * a fresh block — one settled block per turn that touched the list,
172
- * never one per update. The pipe path stays per-call (byte-linear —
173
- * every write is final; there is no in-place redraw in a pipe). */
174
- checklist(header: string, items: {
175
- text: string;
176
- status: "pending" | "active" | "done";
177
- }[]): void;
178
163
  /** The startup banner (W1): a LIVE cell — the tier re-derives per
179
164
  * frame (bannerLines with the CURRENT W and H), so a resize re-tiers
180
165
  * the art instead of re-folding frozen rows (a window below 40 cols
@@ -89,12 +89,6 @@ const LIVE_ACT_HEADS = 3;
89
89
  /** R8 — the command band's window: five rows plus a counter, the same
90
90
  * budget the composer's own ceiling can afford above it. */
91
91
  const MENU_WINDOW = 5;
92
- /** W20 — the whole-table-replace comparison: the live task block only
93
- * redraws when the items actually changed (the task extension's
94
- * idempotent shape — an unchanged replace is a no-op, no frame). */
95
- function sameTask(a, b) {
96
- return a.length === b.length && a.every((x, i) => x.text === b[i].text && x.status === b[i].status);
97
- }
98
92
  export class Body {
99
93
  #opts;
100
94
  #cells = [];
@@ -646,20 +640,6 @@ export class Body {
646
640
  return;
647
641
  turn.ended = true;
648
642
  turn.thoughtSeconds = thoughtSeconds;
649
- // W20: the turn's live task block settles HERE — the ONE recap
650
- // block for the turn ("`task done · N items · <duration>", the
651
- // duration clocked compositor-side from the block's first call —
652
- // the CLI stays unchanged). A turn that never touched the list has
653
- // no live block — nothing settles. Newest-first: the live block is
654
- // the newest cell of its turn.
655
- for (let i = this.#cells.length - 1; i >= 0; i -= 1) {
656
- const c = this.#cells[i];
657
- if (c.kind === "checklist" && !c.done) {
658
- c.done = true;
659
- c.durationSeconds = Math.max(0, Math.round((Date.now() - c.startedAt) / 1000));
660
- break;
661
- }
662
- }
663
643
  // R3g (fable D3, 2026-08-28): an INTERRUPTED tool never receives a
664
644
  // result, so its cell stays `done: false` — and the commit loop
665
645
  // stops at the first cell that is not done. One esc mid-tool
@@ -739,54 +719,6 @@ export class Body {
739
719
  this.#cells.push({ kind: "notice", text, done: true });
740
720
  this.#mark();
741
721
  }
742
- /** W20 — the task checklist as STATE, not events: the FIRST call of a
743
- * turn creates the ONE live block (done:false — the commit loop only
744
- * takes done cells, so it stays in the live region); later calls of
745
- * the SAME turn MUTATE that block in place — same position, same
746
- * height, zero committed rows (the W8 fixed-window rule generalised
747
- * to state). An unchanged whole-table replace (the task extension's
748
- * idempotent shape) is a no-op — no mark, no frame. The block commits
749
- * ONCE at the turn's end (endTurn); the next turn's first call starts
750
- * a fresh block — one settled block per turn that touched the list,
751
- * never one per update. The pipe path stays per-call (byte-linear —
752
- * every write is final; there is no in-place redraw in a pipe). */
753
- checklist(header, items) {
754
- if (!this.#isActive()) {
755
- this.#closeOpenThinking();
756
- this.#closeOpenText();
757
- const p = palette();
758
- this.#write(`${p.bold}✦${p.reset} ${escapeTerminal(header)}\n`);
759
- const glyphOf = (status) => (status === "pending" ? "□" : status === "active" ? "▖" : "▣");
760
- for (const item of items)
761
- this.#write(` ${glyphOf(item.status)} ${escapeTerminal(item.text)}\n`);
762
- return;
763
- }
764
- this.#closeOpenThinking();
765
- this.#closeOpenText();
766
- const turn = this.#turns.length - 1;
767
- const last = this.#cells[this.#cells.length - 1];
768
- if (last !== undefined && last.kind === "checklist" && !last.done && last.turn === turn) {
769
- // TV-1B: the header participates in the change detection — the
770
- // settle verdict is a header-only update over the same items,
771
- // and an items-only guard would swallow it silently.
772
- if (last.header !== header || !sameTask(last.items, items)) {
773
- Object.assign(last, { header, items });
774
- this.#mark();
775
- }
776
- return;
777
- }
778
- this.#cells.push({
779
- kind: "checklist",
780
- header,
781
- items,
782
- done: false,
783
- expanded: false,
784
- startedAt: Date.now(),
785
- durationSeconds: 0,
786
- turn,
787
- });
788
- this.#mark();
789
- }
790
722
  /** The startup banner (W1): a LIVE cell — the tier re-derives per
791
723
  * frame (bannerLines with the CURRENT W and H), so a resize re-tiers
792
724
  * the art instead of re-folding frozen rows (a window below 40 cols
@@ -1532,11 +1464,13 @@ export class Body {
1532
1464
  // lost anywhere.
1533
1465
  if (panel !== null)
1534
1466
  return { status: panelStatusOf(panel), hint: undefined, expand: null };
1535
- // W22: while turns wait in the queue, the right hint shows the
1536
- // count — the chips below carry the lines themselves.
1467
+ // ADR-0057: while steers wait for the run's next quiescent boundary,
1468
+ // the right hint counts them — the chips carry the lines. Short on
1469
+ // purpose: the running status shares the row, and a hint that does
1470
+ // not fit is dropped whole.
1537
1471
  const queued = this.#queueState?.().length ?? 0;
1538
1472
  if (queued > 0)
1539
- return { status: this.#status, hint: `+${queued} queued`, expand: null };
1473
+ return { status: this.#status, hint: `+${queued} steer`, expand: null };
1540
1474
  // D-S2-1 (owner-ruled 2026-09-06): the idle hint names the ctrl+o
1541
1475
  // SWITCH — `expand all` or `collapse all` by its state — and only
1542
1476
  // while a committed card has something behind the key (#collapsed
@@ -2226,7 +2160,7 @@ export class Body {
2226
2160
  return pendingQueueRows(lines, W);
2227
2161
  const p = palette();
2228
2162
  const hidden = lines.length - keep;
2229
- return [...pendingQueueRows(lines.slice(0, keep), W), `${p.dim}□ …${hidden} more queued${p.reset}`];
2163
+ return [...pendingQueueRows(lines.slice(0, keep), W), `${p.dim}□ …${hidden} more${p.reset}`];
2230
2164
  }
2231
2165
  /**
2232
2166
  * The band ABOVE the box top. Two occupants share it — the slash
package/dist/editor.d.ts CHANGED
@@ -129,6 +129,10 @@ export declare class Editor {
129
129
  * pop walks them (each pop leaves the queue, cancelling the turn);
130
130
  * esc ends the walk after one more pop. */
131
131
  bindQueue(state: () => readonly string[], pop: () => string | null): void;
132
+ /** ADR-0057: put text back into the buffer — the steers a stop handed
133
+ * back before they landed. It goes AHEAD of a draft already there, on
134
+ * its own line, and the draft stays recoverable (undo). */
135
+ restore(text: string): void;
132
136
  /** The whole buffer as text (the CLI's line()/clearLine()). */
133
137
  line(): string;
134
138
  bindViewer(isUp: () => boolean, cb: (cmd: "open" | "up" | "down" | "toggle" | "all" | "pageUp" | "pageDown" | "home" | "end" | "close") => void): void;
package/dist/editor.js CHANGED
@@ -572,6 +572,20 @@ export class Editor {
572
572
  this.#queueState = state;
573
573
  this.#queuePop = pop;
574
574
  }
575
+ /** ADR-0057: put text back into the buffer — the steers a stop handed
576
+ * back before they landed. It goes AHEAD of a draft already there, on
577
+ * its own line, and the draft stays recoverable (undo). */
578
+ restore(text) {
579
+ if (text === "")
580
+ return;
581
+ if (this.#chars.length > 0)
582
+ this.#checkpoint();
583
+ const merged = this.#chars.length > 0 ? `${text}\n${this.line()}` : text;
584
+ this.#chars = [...merged].map((ch) => ch.codePointAt(0));
585
+ this.#cursor = this.#chars.length;
586
+ this.#verticalGoalCol = null;
587
+ this.#onRender();
588
+ }
575
589
  /** The whole buffer as text (the CLI's line()/clearLine()). */
576
590
  line() {
577
591
  return String.fromCodePoint(...this.#chars);
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ export { bannerLines, COLOR_OFF, COLOR_ON, currentGround, setGround, escapeTermi
14
14
  export { editFileDiff, truncateDiff, writeFileDiff, type DiffLine, type DiffResult } from "./diff.js";
15
15
  export { STATUS_GLYPHS, cacheHitPct, compactingStatus, composeRow, decodeRate, idleStatus, retrySegment, runningStatus, type CompactingProgress, type RetryOnRow, type RowSegment, type StatusMeter } from "./status.js";
16
16
  export { contextRows, contextUnavailableRows, type ContextLedger } from "./context-ledger.js";
17
- export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, verifyOfferView, type TrustArtifact } from "./strings.js";
17
+ export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, type TrustArtifact } from "./strings.js";
18
18
  export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows, atWindow, bandHeader, longestRun, type AtItem, type AtMatch } from "./at-picker.js";
19
19
  export { idColumn, sessionAge, sessionCounterRow, sessionFilter, sessionListFooter, sessionListHeader, sessionListUnknownLine, sessionListRow, sessionNote, sessionPickerRows, sessionRow, scopeSessions, scopeTitle, type PickScopeState, type SessionCardView, type SessionPickState, } from "./session-picker.js";
20
20
  export { ASK_HEADER_CAP, ASK_MAX_OPTIONS, ASK_MAX_QUESTIONS, ASK_MIN_OPTIONS, askAffordance, askAnswers, askBlockRows, askCommitCustom, askDeclineAll, askDeclineList, askKey, askLeadPlain, askStart, askStatus, askView, type AskAnswer, type AskOption, type AskQuestion, type AskResult, type AskRuntime, type AskSpec, type AskStep, } from "./ask-panel.js";
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ export { contextRows, contextUnavailableRows } from "./context-ledger.js";
26
26
  // KC3 §1 (the extraction): the human-facing strings — the prompt, the
27
27
  // project-trust listing/view/note, the uncertain execution's view. The
28
28
  // FLOW (who is asked, what a verdict means) stays in the cli.
29
- export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, verifyOfferView } from "./strings.js";
29
+ export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView } from "./strings.js";
30
30
  // KC3 §3/§5: the @ file picker's pure half — the subsequence filter, the
31
31
  // deterministic rank, and the ONE cap the CLI's file source shares.
32
32
  export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows, atWindow, bandHeader, longestRun } from "./at-picker.js";
package/dist/lines.d.ts CHANGED
@@ -90,13 +90,6 @@ export type RenderInput = {
90
90
  readonly name: string;
91
91
  readonly executionId: string;
92
92
  readonly error: string;
93
- } | {
94
- readonly type: "checklist";
95
- readonly header: string;
96
- readonly items: readonly {
97
- readonly text: string;
98
- readonly status: "pending" | "active" | "done";
99
- }[];
100
93
  };
101
94
  /**
102
95
  * Render one event. `text` may be a continuation (text_delta appends to the
package/dist/lines.js CHANGED
@@ -105,17 +105,6 @@ export function renderEvent(ev, prevThinking = false, resolvePath = (p) => p) {
105
105
  newline: true,
106
106
  prompt: false,
107
107
  };
108
- case "checklist": {
109
- // ⑥: the durable checklist — the ✦ header accent (the recap's
110
- // brick) + one brick-glyph line per item. Static line content:
111
- // byte-identical in pipes and NO_COLOR.
112
- const lines = [`${p.bold}✦${p.reset} ${escapeTerminal(ev.header)}`];
113
- for (const item of ev.items) {
114
- const glyph = item.status === "pending" ? "□" : item.status === "active" ? "▖" : "▣";
115
- lines.push(` ${glyph} ${escapeTerminal(item.text)}`);
116
- }
117
- return { text: `${lines.join("\n")}\n`, newline: true, prompt: false };
118
- }
119
108
  default:
120
109
  return { text: "", newline: false, prompt: false };
121
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-tui",
3
- "version": "0.43.0",
3
+ "version": "0.45.0",
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.43.0"
38
+ "@vincemakes/kiso-tui-cells": "0.45.0"
39
39
  }
40
40
  }