@vincemakes/kiso-tui 0.7.0 → 0.9.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.d.ts +95 -0
- package/dist/ask-panel.js +276 -0
- package/dist/at-picker.d.ts +4 -0
- package/dist/at-picker.js +41 -8
- package/dist/compositor.d.ts +21 -2
- package/dist/compositor.js +232 -35
- package/dist/context-ledger.d.ts +66 -0
- package/dist/context-ledger.js +87 -0
- package/dist/editor.d.ts +4 -1
- package/dist/editor.js +118 -6
- package/dist/index.d.ts +5 -2
- package/dist/index.js +14 -2
- package/dist/status.d.ts +32 -2
- package/dist/status.js +24 -3
- package/package.json +2 -2
package/dist/editor.d.ts
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import { charWidth, displayWidth, widthOf } from "./width.js";
|
|
25
25
|
export { charWidth, displayWidth, widthOf };
|
|
26
|
-
import {
|
|
26
|
+
import type { PanelState, PanelVerdict, PanelView } from "./approval-panel.js";
|
|
27
27
|
import { type AtItem, type AtMatch } from "./at-picker.js";
|
|
28
28
|
export declare const PROMPT = "\u258C ";
|
|
29
29
|
export declare const PROMPT_WIDTH: number;
|
|
@@ -60,6 +60,9 @@ export declare class Editor {
|
|
|
60
60
|
bindQueue(state: () => readonly string[], pop: () => string | null): void;
|
|
61
61
|
/** The whole buffer as text (the CLI's line()/clearLine()). */
|
|
62
62
|
line(): string;
|
|
63
|
+
/** TUI2-R1 (D): whether the keys sheet is up — the compositor's slot
|
|
64
|
+
* read (bound like the menu and the picker). */
|
|
65
|
+
sheetOpen(): boolean;
|
|
63
66
|
clearLine(): void;
|
|
64
67
|
/** The dock's input-row state — ADDITIVE (§5): `line` + `cursor` keep
|
|
65
68
|
* their legacy meaning (the CURSOR LINE's visible slice and the
|
package/dist/editor.js
CHANGED
|
@@ -26,7 +26,9 @@ import { charWidth, displayWidth, leadWidth, widthOf } from "./width.js";
|
|
|
26
26
|
// authority) — re-exported so the editor's public surface is unchanged.
|
|
27
27
|
export { charWidth, displayWidth, widthOf };
|
|
28
28
|
import { palette } from "./render.js";
|
|
29
|
-
|
|
29
|
+
// KC3.5: the panel-slot dispatchers — the ask branch folded into the
|
|
30
|
+
// W21 lead/rows, so this file keeps ONE panel and one key owner.
|
|
31
|
+
import { askCommitCustom, askKey, askStart, panelLead } from "./ask-panel.js";
|
|
30
32
|
import { AT_VISIBLE, atFilter } from "./at-picker.js";
|
|
31
33
|
// TUI v4 #16d: the input row is the blue brick + the edit area — the
|
|
32
34
|
// "you>" text is gone (the brick IS the prompt; the pipe path's readline
|
|
@@ -40,6 +42,8 @@ export const MENU_ITEMS = [
|
|
|
40
42
|
{ name: "/think", desc: "show the last full thinking block" },
|
|
41
43
|
{ name: "/last", desc: "show the most recent tool call's input and output" },
|
|
42
44
|
{ name: "/status", desc: "show session id, event count, and context estimate" },
|
|
45
|
+
// TUI2-R1 (E): the rent-ledger attribution — where the context went
|
|
46
|
+
{ name: "/context", desc: "show where the context went — the last request's rent ledger" },
|
|
43
47
|
{ name: "/help", desc: "print this list of commands" },
|
|
44
48
|
];
|
|
45
49
|
/** KC1 §3 — the newline code point. Every source (paste, Ctrl+J, the
|
|
@@ -107,6 +111,12 @@ export class Editor {
|
|
|
107
111
|
// coexist; the editor never interprets the key itself.
|
|
108
112
|
#expandCbs = [];
|
|
109
113
|
#onRender;
|
|
114
|
+
/** TUI2-R1 (D): the keys sheet — a static one-screen overlay opened by
|
|
115
|
+
* `?` on an empty composer and closed by the next key, whatever it
|
|
116
|
+
* is. Deliberately a BOOLEAN and not a panel: the panel machinery
|
|
117
|
+
* exists for interactions (a lead, a status, a reducer, a stashed
|
|
118
|
+
* buffer), and the sheet has no interaction to speak of. */
|
|
119
|
+
#sheetOpen = false;
|
|
110
120
|
#menuOpen = false; // v3 §04: the slash-command menu
|
|
111
121
|
#menuSel = 0;
|
|
112
122
|
// KC3 §3 — the @ file picker. THREE fields and no more: the armed
|
|
@@ -192,6 +202,11 @@ export class Editor {
|
|
|
192
202
|
line() {
|
|
193
203
|
return String.fromCodePoint(...this.#chars);
|
|
194
204
|
}
|
|
205
|
+
/** TUI2-R1 (D): whether the keys sheet is up — the compositor's slot
|
|
206
|
+
* read (bound like the menu and the picker). */
|
|
207
|
+
sheetOpen() {
|
|
208
|
+
return this.#sheetOpen;
|
|
209
|
+
}
|
|
195
210
|
clearLine() {
|
|
196
211
|
this.#chars = [];
|
|
197
212
|
this.#cursor = 0;
|
|
@@ -439,6 +454,7 @@ export class Editor {
|
|
|
439
454
|
view,
|
|
440
455
|
phase: "options",
|
|
441
456
|
sel: 0,
|
|
457
|
+
ask: view.ask === undefined ? null : askStart(view.ask),
|
|
442
458
|
amend: "yes",
|
|
443
459
|
onCommit,
|
|
444
460
|
stash: { chars: this.#chars, cursor: this.#cursor, scroll: this.#scroll },
|
|
@@ -463,7 +479,7 @@ export class Editor {
|
|
|
463
479
|
const panel = this.#panel;
|
|
464
480
|
if (panel === null)
|
|
465
481
|
return null;
|
|
466
|
-
return { view: panel.view, phase: panel.phase, sel: panel.sel };
|
|
482
|
+
return { view: panel.view, phase: panel.phase, sel: panel.sel, ...(panel.ask === null ? {} : { ask: panel.ask }) };
|
|
467
483
|
}
|
|
468
484
|
enter() {
|
|
469
485
|
if (this.#entered)
|
|
@@ -493,7 +509,7 @@ export class Editor {
|
|
|
493
509
|
// W21: the panel's lead owns the row while up (the brick returns
|
|
494
510
|
// when the panel closes).
|
|
495
511
|
const panel = this.#panel;
|
|
496
|
-
const lead = panel !== null ? panelLead(panel.view, panel.phase, panel.sel) : `${p.bold}${PROMPT}${p.reset}`;
|
|
512
|
+
const lead = panel !== null ? panelLead(panel.view, panel.phase, panel.sel, panel.ask ?? undefined) : `${p.bold}${PROMPT}${p.reset}`;
|
|
497
513
|
// W23: the ONE width authority — leadWidth(lead), the ANSI-stripped
|
|
498
514
|
// visible width (the styled panel lead / the styled brick measure
|
|
499
515
|
// the same as their plain text — a lead can never measure
|
|
@@ -507,6 +523,17 @@ export class Editor {
|
|
|
507
523
|
feed(raw) {
|
|
508
524
|
const text = this.#pending + this.#decoder.decode(raw, { stream: true });
|
|
509
525
|
this.#pending = "";
|
|
526
|
+
// TUI2-R1 (D): the sheet is up — ANY key closes it, and the key
|
|
527
|
+
// that closed it is CONSUMED. The whole chunk goes, deliberately:
|
|
528
|
+
// an arrow key is three bytes, and closing on the first while
|
|
529
|
+
// letting `[A` fall through as literal text would be a sheet that
|
|
530
|
+
// types into your composer on the way out. A dismissal costs one
|
|
531
|
+
// keystroke; that is the entire contract.
|
|
532
|
+
if (this.#sheetOpen) {
|
|
533
|
+
this.#sheetOpen = false;
|
|
534
|
+
this.#onRender();
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
510
537
|
let i = 0;
|
|
511
538
|
while (i < text.length) {
|
|
512
539
|
const c = text[i];
|
|
@@ -520,6 +547,45 @@ export class Editor {
|
|
|
520
547
|
// text); ctrl-c still rides the SIGINT handler (which
|
|
521
548
|
// cancels the panel).
|
|
522
549
|
const panel = this.#panel;
|
|
550
|
+
// KC3.5: an ASK panel routes its own keys — the digits pick
|
|
551
|
+
// (single-select advances, multi toggles), space toggles at
|
|
552
|
+
// the cursor, `t` opens the type-your-own line (the
|
|
553
|
+
// rule-input phase's shape: the buffer is the editor's, so
|
|
554
|
+
// only esc and enter are intercepted while typing), esc
|
|
555
|
+
// declines the whole call. Everything else falls through to
|
|
556
|
+
// the ordinary editing chain below.
|
|
557
|
+
if (panel.ask !== null) {
|
|
558
|
+
const typing = panel.ask.phase === "custom";
|
|
559
|
+
if (c === "\x1b" && !text.slice(i + 1).startsWith("[") && !text.slice(i + 1).startsWith("O")) {
|
|
560
|
+
this.#askStep("esc");
|
|
561
|
+
i += 1;
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
if (c === "\x0d" || c === "\x0a") {
|
|
565
|
+
this.#askStep(typing ? "commit" : "enter");
|
|
566
|
+
i += 1;
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
if (!typing && (c === " " || (c !== undefined && c >= "1" && c <= "4") || c === "t" || c === "T")) {
|
|
570
|
+
this.#askStep(c === " " ? "space" : c === "T" ? "t" : c);
|
|
571
|
+
i += 1;
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
// an ask at rest swallows stray PRINTABLE keys — the panel
|
|
575
|
+
// owns them, and a typed "/" or "@" must not arm the menu
|
|
576
|
+
// or the picker underneath. Two things are never
|
|
577
|
+
// swallowed: the CSI/SS3 introducer, because ←/↑/↓ are
|
|
578
|
+
// the ask's own keys and the parser below routes them
|
|
579
|
+
// (the T-Q1 red), and the CONTROL characters, because
|
|
580
|
+
// ctrl-c must still reach the SIGINT handler that
|
|
581
|
+
// cancels the panel — W21's own rule, and what the T-Q6
|
|
582
|
+
// race red caught: an abort with the panel up did
|
|
583
|
+
// nothing at all.
|
|
584
|
+
if (!typing && c !== undefined && c >= " " && c !== "\x7f") {
|
|
585
|
+
i += 1;
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
523
589
|
if (c === "\x1b" && !text.slice(i + 1).startsWith("[") && !text.slice(i + 1).startsWith("O")) {
|
|
524
590
|
this.#panelEsc();
|
|
525
591
|
i += 1;
|
|
@@ -710,6 +776,17 @@ export class Editor {
|
|
|
710
776
|
cb();
|
|
711
777
|
i += 1;
|
|
712
778
|
}
|
|
779
|
+
else if (c === "?" && this.#composerIdle() && this.#chars.length === 0) {
|
|
780
|
+
// TUI2-R1 (D): `?` opens the keys sheet — but ONLY on an
|
|
781
|
+
// empty composer with nobody else holding the keys. Mid-text
|
|
782
|
+
// it is the question mark a human is typing, and #composerIdle
|
|
783
|
+
// already encodes "no panel, no menu, no picker, no browse".
|
|
784
|
+
// The precedence can only ever ADD: every state that used to
|
|
785
|
+
// insert a `?` still inserts one.
|
|
786
|
+
this.#sheetOpen = true;
|
|
787
|
+
this.#onRender();
|
|
788
|
+
i += 1;
|
|
789
|
+
}
|
|
713
790
|
else if (c !== undefined && c < " ") {
|
|
714
791
|
i += 1; // other control — ignored
|
|
715
792
|
}
|
|
@@ -760,7 +837,10 @@ export class Editor {
|
|
|
760
837
|
// panel owns the keys while up (↑↓ do nothing — the panel has no
|
|
761
838
|
// ↑↓ role).
|
|
762
839
|
if (this.#panel !== null) {
|
|
763
|
-
|
|
840
|
+
// W21: the panel owns the keys. KC3.5: an ask uses ↑↓ for
|
|
841
|
+
// the option cursor (the approval panel still has no ↑↓ role).
|
|
842
|
+
if (this.#panel.ask !== null && this.#panel.ask.phase === "options")
|
|
843
|
+
this.#askStep(final === "A" ? "up" : "down");
|
|
764
844
|
}
|
|
765
845
|
else if (this.#menuOpen) {
|
|
766
846
|
if (final === "A")
|
|
@@ -798,7 +878,12 @@ export class Editor {
|
|
|
798
878
|
this.#onRender();
|
|
799
879
|
}
|
|
800
880
|
else if (final === "D") {
|
|
801
|
-
|
|
881
|
+
// KC3.5: ← walks the ask BACK a question (the ‹ n/m › walk); at
|
|
882
|
+
// question one it stays put — esc is the decline, never ←.
|
|
883
|
+
if (this.#panel?.ask != null && this.#panel.ask.phase === "options")
|
|
884
|
+
this.#askStep("left");
|
|
885
|
+
else
|
|
886
|
+
this.#move(-1);
|
|
802
887
|
}
|
|
803
888
|
else if (final === "C") {
|
|
804
889
|
this.#move(1);
|
|
@@ -913,6 +998,33 @@ export class Editor {
|
|
|
913
998
|
else if (panel.sel === 3)
|
|
914
999
|
this.#panelClose({ action: "deny", reason: "" });
|
|
915
1000
|
}
|
|
1001
|
+
/**
|
|
1002
|
+
* KC3.5 — one ask key: the pure reducer decides, this method applies.
|
|
1003
|
+
* The buffer is cleared on every phase change so the type-your-own
|
|
1004
|
+
* line starts empty and its text never leaks back into the options
|
|
1005
|
+
* (the rule-input phase's own discipline). A step that produced a
|
|
1006
|
+
* RESULT closes the panel with it — the stash/restore is the W21
|
|
1007
|
+
* path, identical for an answer and for a decline.
|
|
1008
|
+
*/
|
|
1009
|
+
#askStep(key) {
|
|
1010
|
+
const panel = this.#panel;
|
|
1011
|
+
if (panel === null || panel.ask === null)
|
|
1012
|
+
return;
|
|
1013
|
+
const spec = panel.view.ask;
|
|
1014
|
+
const before = panel.ask.phase;
|
|
1015
|
+
const step = key === "commit" ? askCommitCustom(spec, panel.ask, this.line()) : askKey(spec, panel.ask, key);
|
|
1016
|
+
panel.ask = step.state;
|
|
1017
|
+
if (step.state.phase !== before) {
|
|
1018
|
+
this.#chars = [];
|
|
1019
|
+
this.#cursor = 0;
|
|
1020
|
+
this.#scroll = 0;
|
|
1021
|
+
}
|
|
1022
|
+
if (step.result !== undefined) {
|
|
1023
|
+
this.#panelClose({ action: "answers", result: step.result });
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
this.#onRender();
|
|
1027
|
+
}
|
|
916
1028
|
#panelClose(verdict) {
|
|
917
1029
|
const panel = this.#panel;
|
|
918
1030
|
if (panel === null)
|
|
@@ -1162,7 +1274,7 @@ export class Editor {
|
|
|
1162
1274
|
// W23: the ONE width authority — leadWidth(lead) — the cap follows
|
|
1163
1275
|
// the lead the editor itself renders (the panel lead when the panel
|
|
1164
1276
|
// owns the keys, the brick otherwise): maxW = W − walls − lead.
|
|
1165
|
-
const lead = this.#panel !== null ? panelLead(this.#panel.view, this.#panel.phase, this.#panel.sel) : PROMPT;
|
|
1277
|
+
const lead = this.#panel !== null ? panelLead(this.#panel.view, this.#panel.phase, this.#panel.sel, this.#panel.ask ?? undefined) : PROMPT;
|
|
1166
1278
|
const leadW = leadWidth(lead);
|
|
1167
1279
|
const maxW = Math.max(1, W - leadW - 4); // W6: the box's walls (2+2) — the visible line fits the box's inner width; the "…" rides inside
|
|
1168
1280
|
// KC1: the scroll is the CURSOR LINE's own offset — a single-line
|
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { Body, Dock, CURSOR_MARKER, type BodyOptions } from "./compositor.js";
|
|
9
9
|
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, type PanelArgs, type PanelFlavor, type PanelPhase, type PanelSel, type PanelState, type PanelVerdict, type PanelView, } from "./approval-panel.js";
|
|
10
|
-
export { Container, foldLine, visibleWidth, SPINNER, type Component, type FrameCtx } from "./components.js";
|
|
10
|
+
export { Container, foldLine, foldWords, visibleWidth, SPINNER, type Component, type FrameCtx } from "./components.js";
|
|
11
11
|
export { Editor, MENU_ITEMS, PROMPT, PROMPT_WIDTH, displayWidth, charWidth, widthOf, type MenuItem, } from "./editor.js";
|
|
12
12
|
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
13
|
export { editFileDiff, truncateDiff, writeFileDiff, type DiffLine, type DiffResult } from "./diff.js";
|
|
14
|
-
export { STATUS_GLYPHS, idleStatus, runningStatus } from "./status.js";
|
|
14
|
+
export { STATUS_GLYPHS, cacheHitPct, idleStatus, runningStatus, type StatusMeter } from "./status.js";
|
|
15
|
+
export { contextRows, contextUnavailableRows, type ContextLedger } from "./context-ledger.js";
|
|
15
16
|
export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, type TrustArtifact } from "./strings.js";
|
|
16
17
|
export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows, atWindow, longestRun, type AtItem, type AtMatch } from "./at-picker.js";
|
|
18
|
+
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";
|
|
19
|
+
export { KEY_BINDINGS, PANEL_KEYS_ROW, extensionsBannerText, helpRows, keysHelpRow, keysSheetRows, unansweredAskView, type BannerExtension, type KeyBinding } from "./strings.js";
|
package/dist/index.js
CHANGED
|
@@ -10,13 +10,16 @@ export { Body, Dock, CURSOR_MARKER } from "./compositor.js";
|
|
|
10
10
|
// that replaces the running tool's live window while a human-chain
|
|
11
11
|
// approval is pending (the shape authority is the committed preview).
|
|
12
12
|
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, } from "./approval-panel.js";
|
|
13
|
-
export { Container, foldLine, visibleWidth, SPINNER } from "./components.js";
|
|
13
|
+
export { Container, foldLine, foldWords, visibleWidth, SPINNER } from "./components.js";
|
|
14
14
|
export { Editor, MENU_ITEMS, PROMPT, PROMPT_WIDTH, displayWidth, charWidth, widthOf, } from "./editor.js";
|
|
15
15
|
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";
|
|
16
16
|
export { editFileDiff, truncateDiff, writeFileDiff } from "./diff.js";
|
|
17
17
|
// KC2 §5: the status rows' formatters — the CLI keeps the state and the
|
|
18
18
|
// repaint, the terminal layer owns what the row says.
|
|
19
|
-
export { STATUS_GLYPHS, idleStatus, runningStatus } from "./status.js";
|
|
19
|
+
export { STATUS_GLYPHS, cacheHitPct, idleStatus, runningStatus } from "./status.js";
|
|
20
|
+
// TUI2-R1 (E): /context's attribution rows — a pure function of the
|
|
21
|
+
// counts the trace sidecar already records (the CLI reads, this renders).
|
|
22
|
+
export { contextRows, contextUnavailableRows } from "./context-ledger.js";
|
|
20
23
|
// KC3 §1 (the extraction): the human-facing strings — the prompt, the
|
|
21
24
|
// project-trust listing/view/note, the uncertain execution's view. The
|
|
22
25
|
// FLOW (who is asked, what a verdict means) stays in the cli.
|
|
@@ -24,3 +27,12 @@ export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrusted
|
|
|
24
27
|
// KC3 §3/§5: the @ file picker's pure half — the subsequence filter, the
|
|
25
28
|
// deterministic rank, and the ONE cap the CLI's file source shares.
|
|
26
29
|
export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows, atWindow, longestRun } from "./at-picker.js";
|
|
30
|
+
// KC3.5 (the ask round): the ask view — the panel machinery generalized.
|
|
31
|
+
// The cli composes the view and hands the answers to the tool; the keys,
|
|
32
|
+
// the rows and the walk are the terminal layer's.
|
|
33
|
+
export { ASK_HEADER_CAP, ASK_MAX_OPTIONS, ASK_MAX_QUESTIONS, ASK_MIN_OPTIONS, askAffordance, askAnswers, askBlockRows, askCommitCustom, askDeclineAll, askDeclineList, askKey, askLeadPlain, askStart, askStatus, askView, } from "./ask-panel.js";
|
|
34
|
+
// KC3.5 §4: the interrupted-ask copy — the SAME uncertainty gate, said
|
|
35
|
+
// honestly for a question nobody answered (the ① probe's surface).
|
|
36
|
+
// TUI2-R1 (D): the keys sheet + THE key table — one source for the ?
|
|
37
|
+
// overlay and /help's keys row.
|
|
38
|
+
export { KEY_BINDINGS, PANEL_KEYS_ROW, extensionsBannerText, helpRows, keysHelpRow, keysSheetRows, unansweredAskView } from "./strings.js";
|
package/dist/status.d.ts
CHANGED
|
@@ -33,6 +33,36 @@ export declare const STATUS_GLYPHS: readonly ["▖", "▘", "▝", "▗"];
|
|
|
33
33
|
* because it is on screen exactly when the gesture is useful.
|
|
34
34
|
*/
|
|
35
35
|
export declare function runningStatus(glyph: string, since: number, outTokens: number | null, ctxRatio: number): string;
|
|
36
|
+
/**
|
|
37
|
+
* TUI2-R1 (E) — the idle row's meter: what the session has SPENT, next
|
|
38
|
+
* to what it has left.
|
|
39
|
+
*
|
|
40
|
+
* Both fields are optional and both are omitted when unknown, because
|
|
41
|
+
* the row's job is to be true rather than complete:
|
|
42
|
+
*
|
|
43
|
+
* - `cacheHitPct` is cacheRead / (fresh + cacheRead) — the E2
|
|
44
|
+
* denominator (the pinned sentence: it cannot exceed 100%). A
|
|
45
|
+
* session with no usage yet has no cache hit rate, and an
|
|
46
|
+
* unmeasured cache is NOT a 0% cache, so it renders nothing.
|
|
47
|
+
* - `costUsd` is the CANONICAL cost, which is null whenever the
|
|
48
|
+
* pricing table has no rate for the route. Null renders nothing.
|
|
49
|
+
* No rate table, no number — kiso does not invent a price.
|
|
50
|
+
*/
|
|
51
|
+
export interface StatusMeter {
|
|
52
|
+
readonly cacheHitPct: number | null;
|
|
53
|
+
readonly costUsd: number | null;
|
|
54
|
+
}
|
|
36
55
|
/** The IDLE row: the approval tier as the CALLER names it, the /mode
|
|
37
|
-
* hint, the model driving the session,
|
|
38
|
-
|
|
56
|
+
* hint, the model driving the session, the TUI2-R1 meter when there is
|
|
57
|
+
* one, and the ctx estimate. Called without a meter — or with one that
|
|
58
|
+
* knows nothing — the row is byte-identical to the pre-round row. */
|
|
59
|
+
export declare function idleStatus(tier: string, model: string, ctxRatio: number, meter?: StatusMeter): string;
|
|
60
|
+
/** TUI2-R1 (E) — the cache hit rate the status row shows, from the usage
|
|
61
|
+
* the CLI already tracks. The denominator is the TOTAL the model was
|
|
62
|
+
* given (fresh + cacheRead), which is the E2 ruling's own: cacheRead
|
|
63
|
+
* over fresh alone once rendered 923%. No input at all → null, never a
|
|
64
|
+
* zero. */
|
|
65
|
+
export declare function cacheHitPct(usage: {
|
|
66
|
+
in: number | null;
|
|
67
|
+
cache: number | null;
|
|
68
|
+
}): number | null;
|
package/dist/status.js
CHANGED
|
@@ -46,7 +46,28 @@ export function runningStatus(glyph, since, outTokens, ctxRatio) {
|
|
|
46
46
|
return `${glyph} working ${seconds}s${out} · esc stop · alt+⏎ redirect · ctx left ~${ctxLeft(ctxRatio)}%`;
|
|
47
47
|
}
|
|
48
48
|
/** The IDLE row: the approval tier as the CALLER names it, the /mode
|
|
49
|
-
* hint, the model driving the session,
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
* hint, the model driving the session, the TUI2-R1 meter when there is
|
|
50
|
+
* one, and the ctx estimate. Called without a meter — or with one that
|
|
51
|
+
* knows nothing — the row is byte-identical to the pre-round row. */
|
|
52
|
+
export function idleStatus(tier, model, ctxRatio, meter) {
|
|
53
|
+
const parts = [`▸ ${tier}`, "/mode to switch", model];
|
|
54
|
+
if (meter?.cacheHitPct != null)
|
|
55
|
+
parts.push(`CH ${Math.round(meter.cacheHitPct)}%`);
|
|
56
|
+
if (meter?.costUsd != null)
|
|
57
|
+
parts.push(`$${meter.costUsd.toFixed(4)}`);
|
|
58
|
+
parts.push(`ctx left ~${ctxLeft(ctxRatio)}%`);
|
|
59
|
+
return parts.join(" · ");
|
|
60
|
+
}
|
|
61
|
+
/** TUI2-R1 (E) — the cache hit rate the status row shows, from the usage
|
|
62
|
+
* the CLI already tracks. The denominator is the TOTAL the model was
|
|
63
|
+
* given (fresh + cacheRead), which is the E2 ruling's own: cacheRead
|
|
64
|
+
* over fresh alone once rendered 923%. No input at all → null, never a
|
|
65
|
+
* zero. */
|
|
66
|
+
export function cacheHitPct(usage) {
|
|
67
|
+
const fresh = usage.in;
|
|
68
|
+
const cached = usage.cache;
|
|
69
|
+
if (fresh === null || cached === null)
|
|
70
|
+
return null;
|
|
71
|
+
const total = fresh + cached;
|
|
72
|
+
return total > 0 ? (cached / total) * 100 : null;
|
|
52
73
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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.9.0"
|
|
39
39
|
}
|
|
40
40
|
}
|