@vincemakes/kiso-tui 0.16.2 → 0.16.3

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.
@@ -52,7 +52,7 @@ export interface AtPanelState {
52
52
  readonly selected: number;
53
53
  readonly capped: boolean;
54
54
  }
55
- import { type ResumeMeta } from "./render.js";
55
+ import { type BannerMeta, type ResumeMeta } from "./render.js";
56
56
  /** The cursor marker — an APC private sequence the focus component
57
57
  * embeds at the edit position; the compositor strips it and moves
58
58
  * relatively (it never reaches the terminal). */
@@ -171,7 +171,7 @@ export declare class Body {
171
171
  * list re-gates with the tier (BIG only) and re-times with the
172
172
  * frame. The inactive path keeps the historical bytes (no resume —
173
173
  * the pipe contract). */
174
- banner(version: string, extensionsText: string, resume?: ResumeMeta[]): void;
174
+ banner(version: string, extensionsText: string, resume?: ResumeMeta[], meta?: BannerMeta | undefined): void;
175
175
  raw(lines: string[], wrap?: "words"): void;
176
176
  /** The last COMPLETE thinking block, for /think. */
177
177
  lastThinking(): string | null;
@@ -239,6 +239,20 @@ export declare class Body {
239
239
  * that choice here, and has to pay carefully.
240
240
  */
241
241
  onResize(): void;
242
+ /**
243
+ * DC-3 — the ground arrived, so every colour on the held screen is
244
+ * stale.
245
+ *
246
+ * The terminal answers `OSC 11` a few milliseconds after startup, by
247
+ * which time the first frame is already painted with the no-ground
248
+ * palette. Rather than delay the opening to wait for an answer that
249
+ * may never come, the frame is painted at once and repainted when the
250
+ * answer lands. Invalidating the held screen is exactly what a resize
251
+ * does, for exactly the same reason — every row's bytes are wrong —
252
+ * so it rides the settle the resize already owns and costs one
253
+ * repaint, once per session.
254
+ */
255
+ onGroundChange(): void;
242
256
  /** W18: the status row's right-aligned hint is part of the status
243
257
  * state — the compacting row passes "esc to cancel" (the affordance
244
258
  * must survive repaints). */
@@ -295,6 +309,8 @@ export declare class Dock {
295
309
  enter(): void;
296
310
  exit(): void;
297
311
  onResize(): void;
312
+ /** DC-3 — the terminal answered what its background is; repaint. */
313
+ onGroundChange(): void;
298
314
  /** TUI2-R3v2 ②: where the last frame put the panel's clickable option
299
315
  * rows (absolute screen rows). The editor binds this and does no row
300
316
  * arithmetic of its own. */
@@ -706,21 +706,21 @@ export class Body {
706
706
  * list re-gates with the tier (BIG only) and re-times with the
707
707
  * frame. The inactive path keeps the historical bytes (no resume —
708
708
  * the pipe contract). */
709
- banner(version, extensionsText, resume = []) {
709
+ banner(version, extensionsText, resume = [], meta) {
710
710
  if (!this.#isActive()) {
711
711
  this.#closeOpenThinking();
712
712
  this.#closeOpenText();
713
713
  const W = this.#opts.width() || 80; // a 0-size pty falls back
714
714
  const H = this.#opts.height();
715
715
  const p = palette();
716
- for (const r of bannerLines(W, H, version, extensionsText))
716
+ for (const r of bannerLines(W, H, version, extensionsText, [], Date.now(), meta))
717
717
  this.#write(`${p.dim}${r}${p.reset}\n`);
718
718
  this.#write("\n");
719
719
  return;
720
720
  }
721
721
  this.#closeOpenThinking();
722
722
  this.#closeOpenText();
723
- this.#cells.push({ kind: "banner", version, extensionsText, resume, done: true });
723
+ this.#cells.push({ kind: "banner", version, extensionsText, resume, meta, done: true });
724
724
  this.#mark();
725
725
  }
726
726
  raw(lines, wrap) {
@@ -1092,6 +1092,23 @@ export class Body {
1092
1092
  if (this.#resizeTimer.unref !== undefined)
1093
1093
  this.#resizeTimer.unref();
1094
1094
  }
1095
+ /**
1096
+ * DC-3 — the ground arrived, so every colour on the held screen is
1097
+ * stale.
1098
+ *
1099
+ * The terminal answers `OSC 11` a few milliseconds after startup, by
1100
+ * which time the first frame is already painted with the no-ground
1101
+ * palette. Rather than delay the opening to wait for an answer that
1102
+ * may never come, the frame is painted at once and repainted when the
1103
+ * answer lands. Invalidating the held screen is exactly what a resize
1104
+ * does, for exactly the same reason — every row's bytes are wrong —
1105
+ * so it rides the settle the resize already owns and costs one
1106
+ * repaint, once per session.
1107
+ */
1108
+ onGroundChange() {
1109
+ this.#screen = [];
1110
+ this.onResize();
1111
+ }
1095
1112
  /** The one repaint a drag earns, once its signals have stopped. */
1096
1113
  #settleResize() {
1097
1114
  if (!this.#resizePending || !this.#isActive())
@@ -2323,6 +2340,10 @@ export class Dock {
2323
2340
  onResize() {
2324
2341
  compositorRef?.onResize();
2325
2342
  }
2343
+ /** DC-3 — the terminal answered what its background is; repaint. */
2344
+ onGroundChange() {
2345
+ compositorRef?.onGroundChange();
2346
+ }
2326
2347
  /** TUI2-R3v2 ②: where the last frame put the panel's clickable option
2327
2348
  * rows (absolute screen rows). The editor binds this and does no row
2328
2349
  * arithmetic of its own. */
package/dist/editor.d.ts CHANGED
@@ -56,6 +56,15 @@ export declare class Editor {
56
56
  #private;
57
57
  readonly closed: Promise<void>;
58
58
  constructor(onRender: () => void);
59
+ /**
60
+ * DC-7 — the terminal answering a question kiso asked it.
61
+ *
62
+ * The body is everything between `ESC ]` and the terminator, verbatim
63
+ * and unparsed (`11;rgb:ffff/ffff/ffff`). The editor's job ends at
64
+ * keeping it out of the draft; deciding what a report MEANS belongs to
65
+ * whoever asked the question.
66
+ */
67
+ onOsc(cb: (body: string) => void): void;
59
68
  onLine(cb: (line: string) => void): void;
60
69
  onSigint(cb: () => void): void;
61
70
  onEot(cb: () => void): void;
package/dist/editor.js CHANGED
@@ -81,6 +81,11 @@ const TAB = 0x09;
81
81
  * the geometry stays legal down to the compositor's enter gate (H = 4
82
82
  * ⇒ one row, exactly today's minimum). */
83
83
  const N_MAX = 6;
84
+ /** DC-7 — the longest OSC kiso will hold while waiting for a terminator.
85
+ * The reports it reads are tens of bytes; anything past this is a
86
+ * payload for someone else, and holding it is how the editor goes
87
+ * deaf. */
88
+ const OSC_MAX = 1024;
84
89
  /** The dim "…" — the ONE truncation mark: the horizontal scroll's
85
90
  * prefix (unchanged) and the viewport's hidden-rows markers. */
86
91
  const ELLIPSIS = "\x1b[2m…\x1b[0m";
@@ -293,7 +298,9 @@ export class Editor {
293
298
  #queueState = () => [];
294
299
  #queuePop = null;
295
300
  #queuePopMode = false;
296
- #pending = ""; // an incomplete ESC/CSI prefix across chunks
301
+ #pending = ""; // an incomplete ESC/CSI/OSC prefix across chunks
302
+ /** DC-7: the terminal's own reports (OSC). Never a keystroke. */
303
+ #oscCb = null;
297
304
  #decoder = new TextDecoder();
298
305
  #entered = false;
299
306
  #onData;
@@ -306,6 +313,17 @@ export class Editor {
306
313
  this.#closedResolve = resolve;
307
314
  });
308
315
  }
316
+ /**
317
+ * DC-7 — the terminal answering a question kiso asked it.
318
+ *
319
+ * The body is everything between `ESC ]` and the terminator, verbatim
320
+ * and unparsed (`11;rgb:ffff/ffff/ffff`). The editor's job ends at
321
+ * keeping it out of the draft; deciding what a report MEANS belongs to
322
+ * whoever asked the question.
323
+ */
324
+ onOsc(cb) {
325
+ this.#oscCb = cb;
326
+ }
309
327
  onLine(cb) {
310
328
  this.#lineCb = cb;
311
329
  // Flush submits that arrived before the handler was wired (typed
@@ -1101,6 +1119,32 @@ export class Editor {
1101
1119
  this.#csi(m[1], m[2]);
1102
1120
  i += m[0].length + 1;
1103
1121
  }
1122
+ else if (rest.startsWith("]")) {
1123
+ // DC-7: an OSC is a message FROM the terminal — a background
1124
+ // colour answer, a theme-change notice, a clipboard report.
1125
+ // There was no branch for it, so the bytes fell through to
1126
+ // the literal-text path and the answer was typed into the
1127
+ // draft. The terminator is BEL **or** ST: Apple Terminal
1128
+ // answers `ESC ] 11 ; rgb:… BEL`, and ST is the standard.
1129
+ const end = /\x07|\x1b\\/.exec(rest);
1130
+ if (end === null) {
1131
+ const tail = text.slice(i);
1132
+ // The unterminated case is the SGR-1006 hazard by another
1133
+ // door: park it and a stream that never terminates grows
1134
+ // #pending forever until the editor goes deaf. A report
1135
+ // long enough to be a payload (OSC 52 carries a whole
1136
+ // clipboard) is not one we read, so past the cap it is
1137
+ // dropped rather than held.
1138
+ if (tail.length > OSC_MAX) {
1139
+ i = text.length;
1140
+ break;
1141
+ }
1142
+ this.#pending = tail; // incomplete OSC — wait for more
1143
+ break;
1144
+ }
1145
+ this.#oscCb?.(rest.slice(1, end.index));
1146
+ i += 1 + end.index + end[0].length;
1147
+ }
1104
1148
  else if (rest.startsWith("O")) {
1105
1149
  i += 3; // SS3 (function keys) — ignored
1106
1150
  }
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export { Body, Dock, CURSOR_MARKER, type BodyOptions } from "./compositor.js";
10
10
  export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, PICK_MAX, modelPickView, pickAffordance, pickBlockRows, pickLeadPlain, type PickOption, type PickResult, type PickRuntime, type PickSpec, type PanelArgs, type PanelFlavor, type PanelPhase, deletionRiskHint, SAFER_BACK, SAFER_DEGRADED, SAFER_DEGRADED_TRUNCATED, saferDegradedNote, type SaferAnswer, type SaferFailure, type SaferOption, type SaferRuntime, panelOptions, type PanelOption, type PanelOptionKind, type PanelState, type PanelVerdict, type PanelView, } from "./approval-panel.js";
11
11
  export { Container, foldLine, foldWords, visibleWidth, SPINNER, type Component, type FrameCtx } from "./components.js";
12
12
  export { Editor, MENU_ITEMS, PROMPT, PROMPT_WIDTH, displayWidth, charWidth, widthOf, type MenuItem, } from "./editor.js";
13
- export { bannerLines, COLOR_OFF, COLOR_ON, escapeTerminal, foldResult, foldThinking, kUnit, palette, renderEvent, renderRecap, renderResumeList, renderSessionLine, renderStatusLine, relativeTime, renderTerminalGap, renderToolSummary, TAGLINE, toolTarget, truncateRow, type Palette, type PathResolver, type RecapStats, type ResumeMeta, type RenderInput, type RenderResult, type RunUsage, } from "./render.js";
13
+ export { bannerLines, COLOR_OFF, COLOR_ON, currentGround, setGround, escapeTerminal, foldResult, foldThinking, kUnit, palette, renderEvent, renderRecap, renderResumeList, renderSessionLine, renderStatusLine, relativeTime, renderTerminalGap, renderToolSummary, TAGLINE, toolTarget, truncateRow, type Palette, type PathResolver, type RecapStats, type ResumeMeta, type RenderInput, type RenderResult, type RunUsage, } from "./render.js";
14
14
  export { editFileDiff, truncateDiff, writeFileDiff, type DiffLine, type DiffResult } from "./diff.js";
15
15
  export { STATUS_GLYPHS, cacheHitPct, idleStatus, runningStatus, type StatusMeter } from "./status.js";
16
16
  export { contextRows, contextUnavailableRows, type ContextLedger } from "./context-ledger.js";
@@ -18,4 +18,5 @@ export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrusted
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 { BADGE_GLYPH, idColumn, sessionAge, sessionBadge, sessionCounterRow, sessionFilter, sessionListFooter, sessionListRow, sessionNote, sessionPickerRows, sessionRow, 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";
21
+ export { resolveGround, type Ground } from "@vincemakes/kiso-tui-cells";
21
22
  export { KEY_BINDINGS, PANEL_KEYS_ROW, displayVerb, extensionsBannerText, helpRows, keysHelpRow, keysSheetRows, unansweredAskView, type BannerExtension, type KeyBinding } from "./strings.js";
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWi
15
15
  PICK_MAX, modelPickView, pickAffordance, pickBlockRows, pickLeadPlain, deletionRiskHint, SAFER_BACK, SAFER_DEGRADED, SAFER_DEGRADED_TRUNCATED, saferDegradedNote, panelOptions, } from "./approval-panel.js";
16
16
  export { Container, foldLine, foldWords, visibleWidth, SPINNER } from "./components.js";
17
17
  export { Editor, MENU_ITEMS, PROMPT, PROMPT_WIDTH, displayWidth, charWidth, widthOf, } from "./editor.js";
18
- export { bannerLines, COLOR_OFF, COLOR_ON, escapeTerminal, foldResult, foldThinking, kUnit, palette, renderEvent, renderRecap, renderResumeList, renderSessionLine, renderStatusLine, relativeTime, renderTerminalGap, renderToolSummary, TAGLINE, toolTarget, truncateRow, } from "./render.js";
18
+ export { bannerLines, COLOR_OFF, COLOR_ON, currentGround, setGround, escapeTerminal, foldResult, foldThinking, kUnit, palette, renderEvent, renderRecap, renderResumeList, renderSessionLine, renderStatusLine, relativeTime, renderTerminalGap, renderToolSummary, TAGLINE, toolTarget, truncateRow, } from "./render.js";
19
19
  export { editFileDiff, truncateDiff, writeFileDiff } from "./diff.js";
20
20
  // KC2 §5: the status rows' formatters — the CLI keeps the state and the
21
21
  // repaint, the terminal layer owns what the row says.
@@ -42,4 +42,5 @@ export { ASK_HEADER_CAP, ASK_MAX_OPTIONS, ASK_MAX_QUESTIONS, ASK_MIN_OPTIONS, as
42
42
  // honestly for a question nobody answered (the ① probe's surface).
43
43
  // TUI2-R1 (D): the keys sheet + THE key table — one source for the ?
44
44
  // overlay and /help's keys row.
45
+ export { resolveGround } from "@vincemakes/kiso-tui-cells";
45
46
  export { KEY_BINDINGS, PANEL_KEYS_ROW, displayVerb, extensionsBannerText, helpRows, keysHelpRow, keysSheetRows, unansweredAskView } from "./strings.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-tui",
3
- "version": "0.16.2",
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.",
3
+ "version": "0.16.3",
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",
7
7
  "exports": {
@@ -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.2"
38
+ "@vincemakes/kiso-tui-cells": "0.16.3"
39
39
  }
40
40
  }