@vincemakes/kiso-tui 0.46.1 → 0.47.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 +10 -5
- package/dist/ask-panel.js +109 -54
- package/dist/at-picker.d.ts +38 -68
- package/dist/at-picker.js +50 -141
- package/dist/compositor.d.ts +79 -10
- package/dist/compositor.js +339 -57
- package/dist/context-ledger.d.ts +28 -0
- package/dist/context-ledger.js +62 -0
- package/dist/editor.d.ts +17 -0
- package/dist/editor.js +76 -15
- package/dist/index.d.ts +10 -10
- package/dist/index.js +10 -10
- package/dist/lines.d.ts +11 -0
- package/dist/lines.js +38 -0
- package/dist/notice-meta.d.ts +25 -0
- package/dist/notice-meta.js +83 -0
- package/dist/panel-input.d.ts +2 -2
- package/dist/panel-input.js +70 -60
- package/dist/pick-input.d.ts +23 -3
- package/dist/pick-input.js +9 -29
- package/dist/session-picker.d.ts +37 -22
- package/dist/session-picker.js +270 -57
- package/dist/status.d.ts +78 -75
- package/dist/status.js +182 -108
- package/package.json +2 -2
package/dist/context-ledger.js
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* Every number is a count the ledger already carries. Nothing here
|
|
18
18
|
* estimates, projects, or predicts.
|
|
19
19
|
*/
|
|
20
|
+
import { SHEET_CLOSE, bandHeader } from "@vincemakes/kiso-tui-cells/strings";
|
|
21
|
+
import { cutLine } from "@vincemakes/kiso-tui-cells/render";
|
|
20
22
|
import { palette } from "./lines.js";
|
|
21
23
|
const BAR_CELLS = 12;
|
|
22
24
|
/** k-units for the ledger's columns: 25700 → 25.7k, 300 → 300, 11 → 11.
|
|
@@ -94,3 +96,63 @@ export function contextUnavailableRows(reason) {
|
|
|
94
96
|
const p = palette();
|
|
95
97
|
return [`${p.bold}context — no ledger yet${p.reset}`, ` ${p.dim}${reason}${p.reset}`];
|
|
96
98
|
}
|
|
99
|
+
/** §8.9 — the meter's cells, ONE rule for the status bar's ctx meter and
|
|
100
|
+
* the `/context` sheet (the sheets round, owner 2026-10-06: the two
|
|
101
|
+
* meters cannot disagree). Ten `▆` cells filled to the percentage SHOWN
|
|
102
|
+
* (`0%` is empty; from 1% at least one cell), `ink2` below the soft
|
|
103
|
+
* compaction tier, gold to the hard one, the failure colour past it; the
|
|
104
|
+
* empty cells `track`. "" off a known ground: the colours carry nothing
|
|
105
|
+
* there, and the percentage says it alone. `used`, `soft` and `hard`
|
|
106
|
+
* are shares of the window. */
|
|
107
|
+
export const METER_CELLS = 10;
|
|
108
|
+
export function meterCells(used, soft, hard) {
|
|
109
|
+
const p = palette();
|
|
110
|
+
if (p.track === "")
|
|
111
|
+
return "";
|
|
112
|
+
const shown = Math.round(Math.max(0, used) * 100);
|
|
113
|
+
const filled = shown <= 0 ? 0 : Math.min(METER_CELLS, Math.max(1, Math.round(shown / 10)));
|
|
114
|
+
const tone = used >= hard ? p.fail : used >= soft ? p.gold : p.ink2;
|
|
115
|
+
return `${tone}${"\u2586".repeat(filled)}${p.track}${"\u2586".repeat(METER_CELLS - filled)}${p.fgEnd}`;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The sheets round (owner, 2026-10-06) — `/context` on a dock is a sheet
|
|
119
|
+
* over the input, the shape `/status` has (§8.16): the band names the
|
|
120
|
+
* total (`context · 2.7k of 200k · 1%`), the bar's meter with when
|
|
121
|
+
* compaction happens beside it, the surfaces as a table — the label, the
|
|
122
|
+
* count right-aligned, the detail dim — the free remainder dim, and the
|
|
123
|
+
* closing row. No blank rows: the printed form spent a cell per row and
|
|
124
|
+
* came out double-spaced. On a pipe `/context` prints `contextRows`,
|
|
125
|
+
* unchanged. `tiers` are the compaction thresholds as shares of the
|
|
126
|
+
* window, or null when the window is not known.
|
|
127
|
+
*/
|
|
128
|
+
export function contextSheetRows(ledger, tiers, W) {
|
|
129
|
+
const p = palette();
|
|
130
|
+
const used = ledger.systemPrompt + ledger.toolTable + ledger.skillsIndex + ledger.envelope + ledger.messages;
|
|
131
|
+
const free = Math.max(0, ledger.window - used);
|
|
132
|
+
const ratio = ledger.window > 0 ? Math.min(1, used / ledger.window) : 1;
|
|
133
|
+
const rows = [bandHeader(`context \u00b7 ${k(used)} of ${k(ledger.window)} \u00b7 ${Math.round(ratio * 100)}%`, W)];
|
|
134
|
+
const cells = meterCells(ratio, tiers?.soft ?? Number.POSITIVE_INFINITY, tiers?.hard ?? Number.POSITIVE_INFINITY);
|
|
135
|
+
const when = tiers === null ? "" : `compaction past ${Math.round(tiers.soft * 100)}% at a phase end, past ${Math.round(tiers.hard * 100)}% at once`;
|
|
136
|
+
if (cells !== "" || when !== "")
|
|
137
|
+
rows.push(` ${cells}${cells !== "" && when !== "" ? " " : ""}${when === "" ? "" : `${p.dim}${when}${p.reset}`}`);
|
|
138
|
+
const row = (label, value, detail) => ` ${label.padEnd(15)}${k(value).padStart(6)}${detail === "" ? "" : ` ${p.dim}${detail}${p.reset}`}`;
|
|
139
|
+
if (ledger.systemPrompt > 0)
|
|
140
|
+
rows.push(row("system prompt", ledger.systemPrompt, `base ${k(ledger.systemBase)}${ledger.appends > 0 ? ` + ${ledger.appends} extension append${ledger.appends === 1 ? "" : "s"}` : ""}`));
|
|
141
|
+
if (ledger.toolTable > 0)
|
|
142
|
+
rows.push(row("tool table", ledger.toolTable, `${ledger.tools} tool${ledger.tools === 1 ? "" : "s"}`));
|
|
143
|
+
if (ledger.skillsIndex > 0)
|
|
144
|
+
rows.push(row("skills index", ledger.skillsIndex, `${ledger.skills > 0 ? `${ledger.skills} skill${ledger.skills === 1 ? "" : "s"}, ` : ""}tier-1 lines only`));
|
|
145
|
+
if (ledger.envelope > 0)
|
|
146
|
+
rows.push(row("envelope", ledger.envelope, ""));
|
|
147
|
+
if (ledger.messages > 0)
|
|
148
|
+
rows.push(row("messages", ledger.messages, `${ledger.turns} turn${ledger.turns === 1 ? "" : "s"}`));
|
|
149
|
+
rows.push(` ${p.dim}${"free".padEnd(15)}${k(free).padStart(6)}${p.reset}`);
|
|
150
|
+
rows.push(` ${p.dim}${SHEET_CLOSE}${p.reset}`);
|
|
151
|
+
return rows.map((r) => cutLine(r, W));
|
|
152
|
+
}
|
|
153
|
+
/** The sheets round — `/context` before any request, as a sheet: the band
|
|
154
|
+
* says there is no ledger yet, the row says what produces one. */
|
|
155
|
+
export function contextUnavailableSheetRows(reason, W) {
|
|
156
|
+
const p = palette();
|
|
157
|
+
return [bandHeader("context \u00b7 no ledger yet", W), ` ${p.dim}${reason}${p.reset}`, ` ${p.dim}${SHEET_CLOSE}${p.reset}`].map((r) => cutLine(r, W));
|
|
158
|
+
}
|
package/dist/editor.d.ts
CHANGED
|
@@ -142,6 +142,17 @@ export declare class Editor {
|
|
|
142
142
|
/** TUI2-R1 (D): whether the keys sheet is up — the compositor's slot
|
|
143
143
|
* read (bound like the menu and the picker). */
|
|
144
144
|
sheetOpen(): boolean;
|
|
145
|
+
/** Graphite R3e: what the sheet shows — false when it is closed, true for
|
|
146
|
+
* the keys sheet, the caller's rows otherwise. */
|
|
147
|
+
sheetContent(): boolean | ((W: number) => string[]);
|
|
148
|
+
/** Graphite R3e: open a read-only sheet over the input with the caller's
|
|
149
|
+
* rows (`/status`, `/context`, `/skills`). Any key closes it, and what
|
|
150
|
+
* is typed goes to the input; esc is eaten. */
|
|
151
|
+
openSheet(rows: (W: number) => string[]): void;
|
|
152
|
+
/** The sheets round (owner, 2026-10-06): `/help` opens the command
|
|
153
|
+
* list — the band a typed `/` opens, filtered as the person types. On
|
|
154
|
+
* an empty composer only: a line already being written is theirs. */
|
|
155
|
+
openCommands(): void;
|
|
145
156
|
clearLine(): void;
|
|
146
157
|
/** The dock's input-row state — ADDITIVE (§5): `line` + `cursor` keep
|
|
147
158
|
* their legacy meaning (the CURSOR LINE's visible slice and the
|
|
@@ -165,6 +176,9 @@ export declare class Editor {
|
|
|
165
176
|
menuState(): {
|
|
166
177
|
items: readonly MenuItem[];
|
|
167
178
|
selected: number;
|
|
179
|
+
total?: number;
|
|
180
|
+
query?: string;
|
|
181
|
+
nameCol?: number;
|
|
168
182
|
} | null;
|
|
169
183
|
/** 0.40.1 — bind the menu's extra entries (the CLI binds the installed
|
|
170
184
|
* skills). A function, read per keystroke, never a snapshot. */
|
|
@@ -182,6 +196,9 @@ export declare class Editor {
|
|
|
182
196
|
matches: readonly AtMatch[];
|
|
183
197
|
selected: number;
|
|
184
198
|
capped: boolean;
|
|
199
|
+
query: string;
|
|
200
|
+
total: number;
|
|
201
|
+
nameCol: number;
|
|
185
202
|
} | null;
|
|
186
203
|
/** Open the picker on a bound card source (PickInput, S5). */
|
|
187
204
|
beginPick(cards: () => readonly SessionCardView[], onPick: (id: string | null) => void, here?: string): void;
|
package/dist/editor.js
CHANGED
|
@@ -31,7 +31,7 @@ import {} from "./approval-panel.js";
|
|
|
31
31
|
// KC3.5: the panel-slot dispatchers — the ask branch folded into the
|
|
32
32
|
// W21 lead/rows, so this file keeps ONE panel and one key owner.
|
|
33
33
|
import { panelLead } from "./ask-panel.js";
|
|
34
|
-
import {
|
|
34
|
+
import { AT_CAP, atFilter, atNameWidth, bandVisible } from "./at-picker.js";
|
|
35
35
|
// TUI2-R2 ②: the session picker — the band's THIRD occupant. Its filter
|
|
36
36
|
// is the @ picker's rank aimed at the session id; the editor owns the
|
|
37
37
|
// keys, the compositor draws the rows.
|
|
@@ -137,6 +137,8 @@ export const MENU_ITEMS = [
|
|
|
137
137
|
// never be re-wrapped in place (ADR-0046); this appends it re-folded.
|
|
138
138
|
{ name: "/rewrap", desc: "re-print the recent prose at the current width" },
|
|
139
139
|
{ name: "/status", desc: "show session id, event count, and context estimate" },
|
|
140
|
+
// Graphite R3d: the session's own name (the title, the /resume row)
|
|
141
|
+
{ name: "/name", desc: "name this session · /name shows it · /name - clears it" },
|
|
140
142
|
{ name: "/settings", desc: "show the settings in force, each value's source, and how to change it" },
|
|
141
143
|
// TUI2-R1 (E): the rent-ledger attribution — where the context went
|
|
142
144
|
{ name: "/context", desc: "show where the context went — the last request's rent ledger" },
|
|
@@ -374,6 +376,9 @@ export class Editor {
|
|
|
374
376
|
* exists for interactions (a lead, a status, a reducer, a stashed
|
|
375
377
|
* buffer), and the sheet has no interaction to speak of. */
|
|
376
378
|
#sheetOpen = false;
|
|
379
|
+
/** Graphite R3e: a sheet with the CALLER's rows (`/status`), null for the
|
|
380
|
+
* keys sheet. Any key closes either. */
|
|
381
|
+
#sheetRows = null;
|
|
377
382
|
#menuOpen = false; // v3 §04: the slash-command menu
|
|
378
383
|
/** 0.40.1: the menu's extra entries (the installed skills), read LIVE on
|
|
379
384
|
* every keystroke — a skill added by /reload appears without rebinding. */
|
|
@@ -394,6 +399,9 @@ export class Editor {
|
|
|
394
399
|
// bit with no token under the cursor is inert by construction — the
|
|
395
400
|
// next open re-snapshots, so a stale list can never be shown.
|
|
396
401
|
#atList = null;
|
|
402
|
+
/** Graphite P2: the widest file name in the list, in cells — measured
|
|
403
|
+
* once per open, as the list is listed */
|
|
404
|
+
#atNameCol = 0;
|
|
397
405
|
#atItems = null;
|
|
398
406
|
// TUI2-R2 ② — the session picker. Two fields: the bound source (its
|
|
399
407
|
// presence IS "the picker is up") and the selection. The query, like
|
|
@@ -618,6 +626,30 @@ export class Editor {
|
|
|
618
626
|
sheetOpen() {
|
|
619
627
|
return this.#sheetOpen;
|
|
620
628
|
}
|
|
629
|
+
/** Graphite R3e: what the sheet shows — false when it is closed, true for
|
|
630
|
+
* the keys sheet, the caller's rows otherwise. */
|
|
631
|
+
sheetContent() {
|
|
632
|
+
return !this.#sheetOpen ? false : (this.#sheetRows ?? true);
|
|
633
|
+
}
|
|
634
|
+
/** Graphite R3e: open a read-only sheet over the input with the caller's
|
|
635
|
+
* rows (`/status`, `/context`, `/skills`). Any key closes it, and what
|
|
636
|
+
* is typed goes to the input; esc is eaten. */
|
|
637
|
+
openSheet(rows) {
|
|
638
|
+
this.#sheetRows = rows;
|
|
639
|
+
this.#sheetOpen = true;
|
|
640
|
+
this.#onRender();
|
|
641
|
+
}
|
|
642
|
+
/** The sheets round (owner, 2026-10-06): `/help` opens the command
|
|
643
|
+
* list — the band a typed `/` opens, filtered as the person types. On
|
|
644
|
+
* an empty composer only: a line already being written is theirs. */
|
|
645
|
+
openCommands() {
|
|
646
|
+
if (this.#chars.length > 0)
|
|
647
|
+
return;
|
|
648
|
+
this.#chars = ["/".codePointAt(0)];
|
|
649
|
+
this.#cursor = 1;
|
|
650
|
+
this.#verticalGoalCol = null;
|
|
651
|
+
this.#refreshMenu();
|
|
652
|
+
}
|
|
621
653
|
clearLine() {
|
|
622
654
|
this.#undoStack.length = 0; // UD-1
|
|
623
655
|
this.#redoStack.length = 0;
|
|
@@ -783,7 +815,7 @@ export class Editor {
|
|
|
783
815
|
* the frame's clamp is the authority. */
|
|
784
816
|
#visibleRows(lineCount) {
|
|
785
817
|
const H = process.stdout.rows ?? 24;
|
|
786
|
-
const bands = (this.#menuOpen ? this.#menuFiltered().length : 0) + this.#atRows() + this.#pickInput.rows() + this.#queueState().length;
|
|
818
|
+
const bands = (this.#menuOpen ? Math.min(this.#menuFiltered().length, bandVisible(H)) + 2 : 0) + this.#atRows() + this.#pickInput.rows(H) + this.#queueState().length;
|
|
787
819
|
return Math.max(1, Math.min(lineCount, N_MAX, Math.max(1, H - 3 - bands)));
|
|
788
820
|
}
|
|
789
821
|
/** The dock's input-row state — ADDITIVE (§5): `line` + `cursor` keep
|
|
@@ -825,7 +857,16 @@ export class Editor {
|
|
|
825
857
|
menuState() {
|
|
826
858
|
if (!this.#menuOpen)
|
|
827
859
|
return null;
|
|
828
|
-
|
|
860
|
+
// Graphite P2: the whole list's size and its widest name (the column
|
|
861
|
+
// never moves while the person types), and the typed prefix
|
|
862
|
+
const all = this.#menuAll();
|
|
863
|
+
return { items: this.#menuFiltered(), selected: this.#menuSel, total: all.length, query: this.line().slice(1), nameCol: all.reduce((n, m) => Math.max(n, m.name.length - 1), 0) };
|
|
864
|
+
}
|
|
865
|
+
/** Every entry the menu can show: the built-ins, then the extras that do
|
|
866
|
+
* not shadow one (0.40.1's rule, shared with #menuFiltered). */
|
|
867
|
+
#menuAll() {
|
|
868
|
+
const builtins = new Set(MENU_ITEMS.map((m) => m.name));
|
|
869
|
+
return [...MENU_ITEMS, ...this.#menuExtras().filter((m) => !builtins.has(m.name))];
|
|
829
870
|
}
|
|
830
871
|
/** v3 §04: the filtered command list for the current buffer.
|
|
831
872
|
*
|
|
@@ -845,9 +886,13 @@ export class Editor {
|
|
|
845
886
|
// 0.40.1: the built-ins first, then the extras (skills) — and a
|
|
846
887
|
// built-in WINS a shared name, so a skill named like a command is
|
|
847
888
|
// never listed twice and never shadows it (the dispatcher's rule)
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
|
|
889
|
+
const matches = this.#menuAll().filter((m) => m.name.startsWith(line));
|
|
890
|
+
// the last sweep (owner, 2026-10-06): a line that IS a command's name
|
|
891
|
+
// lists that command first, so ⏎ runs it. `/skill` listed `/skills`
|
|
892
|
+
// first (the table's order) and ⏎ completed the line to it — the
|
|
893
|
+
// command typed in full never ran. The rest keep the table's order.
|
|
894
|
+
const exact = matches.findIndex((m) => m.name === line);
|
|
895
|
+
return exact <= 0 ? matches : [matches[exact], ...matches.slice(0, exact), ...matches.slice(exact + 1)];
|
|
851
896
|
}
|
|
852
897
|
/** 0.40.1 — bind the menu's extra entries (the CLI binds the installed
|
|
853
898
|
* skills). A function, read per keystroke, never a snapshot. */
|
|
@@ -936,7 +981,10 @@ export class Editor {
|
|
|
936
981
|
const view = this.#atView();
|
|
937
982
|
if (view === null)
|
|
938
983
|
return null;
|
|
939
|
-
|
|
984
|
+
// Graphite P2: the band counts the whole list and lays its name column
|
|
985
|
+
// over it, so the folder column never moves while the person types
|
|
986
|
+
const total = Math.min(this.#atList?.length ?? 0, AT_CAP);
|
|
987
|
+
return { matches: view.matches, selected: view.selected, capped: view.capped, query: this.#atToken()?.query ?? "", total, nameCol: this.#atNameCol };
|
|
940
988
|
}
|
|
941
989
|
/** KC3 §3 — arm the picker at a freshly typed `@`. The gate is the
|
|
942
990
|
* KC2 precedence pattern: the approval panel, the slash menu and a
|
|
@@ -959,12 +1007,16 @@ export class Editor {
|
|
|
959
1007
|
this.#atOpen = true;
|
|
960
1008
|
this.#atSel = 0;
|
|
961
1009
|
this.#atList = this.#atItems(); // §5: listed per OPEN, never per keystroke
|
|
1010
|
+
this.#atNameCol = 0;
|
|
1011
|
+
for (const item of this.#atList.slice(0, AT_CAP))
|
|
1012
|
+
this.#atNameCol = Math.max(this.#atNameCol, atNameWidth(item.path));
|
|
962
1013
|
this.#syncMouse();
|
|
963
1014
|
}
|
|
964
1015
|
#atClose() {
|
|
965
1016
|
this.#atOpen = false;
|
|
966
1017
|
this.#atSel = 0;
|
|
967
1018
|
this.#atList = null;
|
|
1019
|
+
this.#atNameCol = 0;
|
|
968
1020
|
this.#syncMouse();
|
|
969
1021
|
}
|
|
970
1022
|
/**
|
|
@@ -999,7 +1051,8 @@ export class Editor {
|
|
|
999
1051
|
* plus the counter row. */
|
|
1000
1052
|
#atRows() {
|
|
1001
1053
|
const view = this.#atView();
|
|
1002
|
-
|
|
1054
|
+
// Graphite P2: the band's name, its window, its key row
|
|
1055
|
+
return view === null ? 0 : Math.min(view.matches.length, bandVisible(process.stdout.rows ?? 24)) + 2;
|
|
1003
1056
|
}
|
|
1004
1057
|
// ── TUI2-R2 ② — the session picker ───────────────────────────────
|
|
1005
1058
|
/** Open the picker on a bound card source (PickInput, S5). */
|
|
@@ -1153,16 +1206,23 @@ export class Editor {
|
|
|
1153
1206
|
#feedKeys(raw) {
|
|
1154
1207
|
const text = this.#pending + this.#decoder.decode(raw, { stream: true });
|
|
1155
1208
|
this.#pending = "";
|
|
1156
|
-
// TUI2-R1 (D): the sheet is up — ANY key closes it
|
|
1157
|
-
//
|
|
1158
|
-
//
|
|
1159
|
-
//
|
|
1160
|
-
//
|
|
1161
|
-
//
|
|
1209
|
+
// TUI2-R1 (D): the sheet is up — ANY key closes it. Graphite R3e: a
|
|
1210
|
+
// sheet is read and then typed past — the whole chunk is typed as it
|
|
1211
|
+
// would have been (it is parsed whole, so an arrow is an arrow, never
|
|
1212
|
+
// `[A`); only esc, which means nothing else here, is eaten.
|
|
1213
|
+
//
|
|
1214
|
+
// DECLARED REVERSAL (the sheets round, owner, 2026-10-06): the keys
|
|
1215
|
+
// sheet ate the key that closed it, where `/status` let it through;
|
|
1216
|
+
// every sheet now closes the same way, and says so on its last row.
|
|
1217
|
+
// The `?` that opens the keys sheet is eaten too: typed onto an
|
|
1218
|
+
// empty composer it would open the sheet it just closed.
|
|
1162
1219
|
if (this.#sheetOpen) {
|
|
1220
|
+
const keys = this.#sheetRows === null;
|
|
1163
1221
|
this.#sheetOpen = false;
|
|
1222
|
+
this.#sheetRows = null;
|
|
1164
1223
|
this.#onRender();
|
|
1165
|
-
|
|
1224
|
+
if (text === "\x1b" || (keys && text === "?"))
|
|
1225
|
+
return;
|
|
1166
1226
|
}
|
|
1167
1227
|
// R5 — while the viewer is up it OWNS the keyboard. Unlike the
|
|
1168
1228
|
// sheet (which any key dismisses) this surface is INTERACTIVE, so
|
|
@@ -1723,6 +1783,7 @@ export class Editor {
|
|
|
1723
1783
|
// already encodes "no panel, no menu, no picker, no browse".
|
|
1724
1784
|
// The precedence can only ever ADD: every state that used to
|
|
1725
1785
|
// insert a `?` still inserts one.
|
|
1786
|
+
this.#sheetRows = null;
|
|
1726
1787
|
this.#sheetOpen = true;
|
|
1727
1788
|
this.#onRender();
|
|
1728
1789
|
i += 1;
|
package/dist/index.d.ts
CHANGED
|
@@ -7,17 +7,17 @@
|
|
|
7
7
|
* editor, the diff renderer, and the palette.
|
|
8
8
|
*/
|
|
9
9
|
export { Body, Dock, CURSOR_MARKER, type BodyOptions } from "./compositor.js";
|
|
10
|
-
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, PICK_MAX, modePickView, modelPickView, namedPickView, 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
|
-
export { Container, foldLine, foldWords, visibleWidth, SPINNER, type Component, type FrameCtx } from "./components.js";
|
|
10
|
+
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, PICK_MAX, modePickView, modelPickView, settingsPickView, namedPickView, 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
|
+
export { Container, foldLine, foldWords, infoSheetRows, visibleWidth, SPINNER, type Component, type FrameCtx, type NoticeMark, type RecallSection } 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, 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 "./lines.js";
|
|
14
|
-
export { editFileDiff, truncateDiff, writeFileDiff, type DiffLine, type DiffResult } from "./diff.js";
|
|
15
|
-
export { STATUS_GLYPHS, cacheHitPct, compactingStatus, composeRow, decodeRate,
|
|
16
|
-
export { contextRows, contextUnavailableRows, type ContextLedger } from "./context-ledger.js";
|
|
13
|
+
export { bannerLines, COLOR_OFF, COLOR_ON, currentGround, setGround, escapeTerminal, foldResult, foldThinking, kUnit, palette, renderEvent, renderRecap, sealTiers, renderResumeList, renderSessionLine, renderStatusLine, relativeTime, renderTerminalGap, renderToolSummary, TAGLINE, MOTTO, WORDMARK_W, type BannerFact, type BannerMeta, toolTarget, truncateRow, type Palette, type PathResolver, type RecapStats, type ResumeMeta, type RenderInput, type RenderResult, type RunUsage, } from "./lines.js";
|
|
14
|
+
export { editFileDiff, editFileHunksDiff, hunksDiff, hunksOf, truncateDiff, writeFileDiff, type DiffLine, type DiffResult, type Hunk } from "./diff.js";
|
|
15
|
+
export { STATUS_GLYPHS, cacheHitPct, compactingStatus, composeRow, ctxMeter, decodeRate, liveRow, retrySegment, statusBar, tasksSegment, workingRow, type BarInput, type CompactingProgress, type RetryOnRow, type RowSegment, type TaskCountsOnRow } from "./status.js";
|
|
16
|
+
export { contextRows, contextSheetRows, contextUnavailableRows, contextUnavailableSheetRows, meterCells, type ContextLedger } from "./context-ledger.js";
|
|
17
17
|
export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, type TrustArtifact } from "./strings.js";
|
|
18
|
-
export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows,
|
|
19
|
-
export { idColumn, sessionAge,
|
|
18
|
+
export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows, bandHeader, longestRun, type AtItem, type AtMatch } from "./at-picker.js";
|
|
19
|
+
export { idColumn, sessionAge, sessionFilter, sessionListFooter, sessionListHeader, sessionListUnknownLine, sessionListRow, sessionNote, sessionPickerRows, 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";
|
|
21
|
-
export { resolveGround, type Ground } from "@vincemakes/kiso-tui-cells";
|
|
21
|
+
export { currentGroundRgb, parseOscColor, resolveGround, type Ground, type Rgb } from "@vincemakes/kiso-tui-cells";
|
|
22
22
|
export { settledLabel } from "@vincemakes/kiso-tui-cells";
|
|
23
|
-
export { KEY_BINDINGS,
|
|
23
|
+
export { KEY_BINDINGS, SHEET_CLOSE, coldResumeLine, coldResumeView, displayVerb, extensionsBannerText, extensionsFact, helpRows, keysHelpRow, keysSheetRows, slashCommandNames, unansweredAskView, type BannerExtension, type KeyBinding } from "./strings.js";
|
package/dist/index.js
CHANGED
|
@@ -12,28 +12,28 @@ export { Body, Dock, CURSOR_MARKER } from "./compositor.js";
|
|
|
12
12
|
// approval is pending (the shape authority is the committed preview).
|
|
13
13
|
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus,
|
|
14
14
|
// TUI2-R2 ④: the pick payload — the panel slot's third occupant.
|
|
15
|
-
PICK_MAX, modePickView, modelPickView, namedPickView, pickAffordance, pickBlockRows, pickLeadPlain, deletionRiskHint, SAFER_BACK, SAFER_DEGRADED, SAFER_DEGRADED_TRUNCATED, saferDegradedNote, panelOptions, } from "./approval-panel.js";
|
|
16
|
-
export { Container, foldLine, foldWords, visibleWidth, SPINNER } from "./components.js";
|
|
15
|
+
PICK_MAX, modePickView, modelPickView, settingsPickView, namedPickView, pickAffordance, pickBlockRows, pickLeadPlain, deletionRiskHint, SAFER_BACK, SAFER_DEGRADED, SAFER_DEGRADED_TRUNCATED, saferDegradedNote, panelOptions, } from "./approval-panel.js";
|
|
16
|
+
export { Container, foldLine, foldWords, infoSheetRows, 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, currentGround, setGround, escapeTerminal, foldResult, foldThinking, kUnit, palette, renderEvent, renderRecap, renderResumeList, renderSessionLine, renderStatusLine, relativeTime, renderTerminalGap, renderToolSummary, TAGLINE, toolTarget, truncateRow, } from "./lines.js";
|
|
19
|
-
export { editFileDiff, truncateDiff, writeFileDiff } from "./diff.js";
|
|
18
|
+
export { bannerLines, COLOR_OFF, COLOR_ON, currentGround, setGround, escapeTerminal, foldResult, foldThinking, kUnit, palette, renderEvent, renderRecap, sealTiers, renderResumeList, renderSessionLine, renderStatusLine, relativeTime, renderTerminalGap, renderToolSummary, TAGLINE, MOTTO, WORDMARK_W, toolTarget, truncateRow, } from "./lines.js";
|
|
19
|
+
export { editFileDiff, editFileHunksDiff, hunksDiff, hunksOf, 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.
|
|
22
|
-
export { STATUS_GLYPHS, cacheHitPct, compactingStatus, composeRow, decodeRate,
|
|
22
|
+
export { STATUS_GLYPHS, cacheHitPct, compactingStatus, composeRow, ctxMeter, decodeRate, liveRow, retrySegment, statusBar, tasksSegment, workingRow } from "./status.js";
|
|
23
23
|
// TUI2-R1 (E): /context's attribution rows — a pure function of the
|
|
24
24
|
// counts the trace sidecar already records (the CLI reads, this renders).
|
|
25
|
-
export { contextRows, contextUnavailableRows } from "./context-ledger.js";
|
|
25
|
+
export { contextRows, contextSheetRows, contextUnavailableRows, contextUnavailableSheetRows, meterCells } 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
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
|
-
export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows,
|
|
32
|
+
export { AT_CAP, AT_SKIP, AT_VISIBLE, atEmbed, atFilter, atPanelRows, bandHeader, longestRun } from "./at-picker.js";
|
|
33
33
|
// TUI2-R2 ①–③: the session picker's pure half — the durability badge,
|
|
34
34
|
// the row (picked or printed), the band, and the filter. The CARDS are
|
|
35
35
|
// the cli's projection (session-cards.ts); this turns them into bytes.
|
|
36
|
-
export { idColumn, sessionAge,
|
|
36
|
+
export { idColumn, sessionAge, sessionFilter, sessionListFooter, sessionListHeader, sessionListUnknownLine, sessionListRow, sessionNote, sessionPickerRows,
|
|
37
37
|
// 0.40.0: the workspace scope — pure, so `kiso sessions` and the picker
|
|
38
38
|
// scope by one rule
|
|
39
39
|
scopeSessions, scopeTitle, } from "./session-picker.js";
|
|
@@ -45,8 +45,8 @@ export { ASK_HEADER_CAP, ASK_MAX_OPTIONS, ASK_MAX_QUESTIONS, ASK_MIN_OPTIONS, as
|
|
|
45
45
|
// honestly for a question nobody answered (the ① probe's surface).
|
|
46
46
|
// TUI2-R1 (D): the keys sheet + THE key table — one source for the ?
|
|
47
47
|
// overlay and /help's keys row.
|
|
48
|
-
export { resolveGround } from "@vincemakes/kiso-tui-cells";
|
|
48
|
+
export { currentGroundRgb, parseOscColor, resolveGround } from "@vincemakes/kiso-tui-cells";
|
|
49
49
|
// one duration form: the CLI's own surfaces label a settled duration the
|
|
50
50
|
// way a settled card does, rather than writing a second one.
|
|
51
51
|
export { settledLabel } from "@vincemakes/kiso-tui-cells";
|
|
52
|
-
export { KEY_BINDINGS,
|
|
52
|
+
export { KEY_BINDINGS, SHEET_CLOSE, coldResumeLine, coldResumeView, displayVerb, extensionsBannerText, extensionsFact, helpRows, keysHelpRow, keysSheetRows, slashCommandNames, unansweredAskView } from "./strings.js";
|
package/dist/lines.d.ts
CHANGED
|
@@ -181,7 +181,18 @@ export interface RecapStats {
|
|
|
181
181
|
* the plan, not the tool count — the timing and tool-count parts
|
|
182
182
|
* drop, and the two /mode hints replace them. */
|
|
183
183
|
readonly mode?: string;
|
|
184
|
+
/** Graphite §7.11 — the person stopped the turn (esc): the seal says
|
|
185
|
+
* so, and that everything before the stop is on disk. */
|
|
186
|
+
readonly stopped?: boolean;
|
|
184
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Graphite §7.11 — THE SEAL's forms, widest first, without the `✦`: the
|
|
190
|
+
* compositor draws the mark and picks the widest form that fits. The
|
|
191
|
+
* same facts as `renderRecap`, in its words, with two differences: no
|
|
192
|
+
* context share — the status bar's meter carries it — and a stopped turn
|
|
193
|
+
* says so. The pipe keeps `renderRecap`'s line.
|
|
194
|
+
*/
|
|
195
|
+
export declare function sealTiers(s: RecapStats): string[];
|
|
185
196
|
export declare function renderRecap(s: RecapStats): string;
|
|
186
197
|
/** One-line summary of a session, for `kiso sessions`. */
|
|
187
198
|
export declare function renderSessionLine(meta: {
|
package/dist/lines.js
CHANGED
|
@@ -155,6 +155,44 @@ export function renderStatusLine(turn, usage, ctxRatio, faux = false) {
|
|
|
155
155
|
return null;
|
|
156
156
|
return `[turn ${turn} · ${parts.join(" · ")}]`;
|
|
157
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Graphite §7.11 — THE SEAL's forms, widest first, without the `✦`: the
|
|
160
|
+
* compositor draws the mark and picks the widest form that fits. The
|
|
161
|
+
* same facts as `renderRecap`, in its words, with two differences: no
|
|
162
|
+
* context share — the status bar's meter carries it — and a stopped turn
|
|
163
|
+
* says so. The pipe keeps `renderRecap`'s line.
|
|
164
|
+
*/
|
|
165
|
+
export function sealTiers(s) {
|
|
166
|
+
if (s.mode === "plan")
|
|
167
|
+
return [["plan ready", "/mode default executes", "/mode accept-edits auto-approves edits"].join(" \u00b7 ")];
|
|
168
|
+
const time = s.stopped === true ? `stopped by you after ${elapsedLabel(s.seconds)}` : `took ${elapsedLabel(s.seconds)}`;
|
|
169
|
+
const parts = [time];
|
|
170
|
+
const cold = s.coldAfterMinutes !== undefined && s.usage.known && s.usage.in !== null;
|
|
171
|
+
let coldLabel = null;
|
|
172
|
+
if (cold) {
|
|
173
|
+
coldLabel = `cache cold after ${s.coldAfterMinutes} min`;
|
|
174
|
+
parts.push(coldLabel, `re-read ${kUnit(s.missed ?? s.usage.in ?? 0)}`);
|
|
175
|
+
if (s.usage.out !== null)
|
|
176
|
+
parts.push(`out ${kUnit(s.usage.out)}`);
|
|
177
|
+
}
|
|
178
|
+
else if (s.usage.known) {
|
|
179
|
+
const seg = `${s.usage.in !== null ? `fresh ${kUnit(s.usage.in)}` : ""}${s.usage.in !== null && s.usage.out !== null ? " " : ""}${s.usage.out !== null ? `out ${kUnit(s.usage.out)}` : ""}`;
|
|
180
|
+
if (seg !== "")
|
|
181
|
+
parts.push(seg);
|
|
182
|
+
if (s.usage.cache !== null && s.usage.in !== null && (s.usage.in > 0 || s.usage.cache > 0)) {
|
|
183
|
+
const hit = `cache ${Math.round((s.usage.cache / (s.usage.in + s.usage.cache)) * 100)}%`;
|
|
184
|
+
parts.push(s.missed !== undefined && s.missed > 0 ? `${hit} \u00b7 miss ${kUnit(s.missed)}` : hit);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (s.stopped === true)
|
|
188
|
+
parts.push("everything up to here is saved");
|
|
189
|
+
const full = parts.join(" \u00b7 ");
|
|
190
|
+
if (coldLabel === null)
|
|
191
|
+
return [full];
|
|
192
|
+
// R3g: a cold turn sheds its LABEL before anything is cut — the gap and
|
|
193
|
+
// the re-read are the facts.
|
|
194
|
+
return [full, parts.map((x) => (x === coldLabel ? `cold ${s.coldAfterMinutes} min` : x)).join(" \u00b7 ")];
|
|
195
|
+
}
|
|
158
196
|
/** R3d — the per-tool terms of a settled turn (`read 4 files · ran 1
|
|
159
197
|
* shell command`, zero terms dropped). One wording for "what a run
|
|
160
198
|
* did", wherever it is said. */
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graphite §7.12 — a notice's META ROW: the label and the sentence.
|
|
3
|
+
*
|
|
4
|
+
* kiso's notices are sentences the CLI writes in a handful of shapes, and
|
|
5
|
+
* a pipe prints them exactly as written. On a terminal each becomes a meta
|
|
6
|
+
* row — a word label and the sentence beside it — so this maps the shapes
|
|
7
|
+
* to their labels in ONE place, and the call sites keep their text.
|
|
8
|
+
*
|
|
9
|
+
* The `✦` some notices open with retires on the terminal: `✦` is the
|
|
10
|
+
* turn's seal (§4), and a label says what the row is.
|
|
11
|
+
*/
|
|
12
|
+
import type { NoticeMark } from "./components.js";
|
|
13
|
+
export interface NoticeMeta {
|
|
14
|
+
/** The row's label; absent for a sentence that has no kind of its own
|
|
15
|
+
* (a command's confirmation — `mode → plan`, `[/compact] …` without
|
|
16
|
+
* its brackets), which stays whole at the content edge. `""`
|
|
17
|
+
* continues the row above. */
|
|
18
|
+
readonly label?: string;
|
|
19
|
+
readonly sentence: string;
|
|
20
|
+
/** The word the row marks, and its colour — a lost task's gold. */
|
|
21
|
+
readonly mark?: NoticeMark;
|
|
22
|
+
/** One row, cut with `…` — a row that names a thing (§7.12). */
|
|
23
|
+
readonly oneRow?: true;
|
|
24
|
+
}
|
|
25
|
+
export declare function noticeMeta(text: string): NoticeMeta;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graphite §7.12 — a notice's META ROW: the label and the sentence.
|
|
3
|
+
*
|
|
4
|
+
* kiso's notices are sentences the CLI writes in a handful of shapes, and
|
|
5
|
+
* a pipe prints them exactly as written. On a terminal each becomes a meta
|
|
6
|
+
* row — a word label and the sentence beside it — so this maps the shapes
|
|
7
|
+
* to their labels in ONE place, and the call sites keep their text.
|
|
8
|
+
*
|
|
9
|
+
* The `✦` some notices open with retires on the terminal: `✦` is the
|
|
10
|
+
* turn's seal (§4), and a label says what the row is.
|
|
11
|
+
*/
|
|
12
|
+
/** kiso's session events — the notices that are a KIND of thing, first
|
|
13
|
+
* match wins. A command's own confirmation is not one of them: its words
|
|
14
|
+
* are read as a whole, and a label would only split them. */
|
|
15
|
+
const SHAPES = [
|
|
16
|
+
[/^✦ compacted (.*)$/s, "COMPACTED", (m) => m[1]],
|
|
17
|
+
[/^\[\/compact\] ✦ compacted(?: · )?(.*)$/s, "COMPACTED", (m) => m[1]],
|
|
18
|
+
[/^✦ pruned (.*)$/s, "PRUNED", (m) => m[1]],
|
|
19
|
+
[/^✦ window learned — (.*)$/s, "WINDOW", (m) => `learned — ${m[1]}`],
|
|
20
|
+
// the main-sync round: a background task's delivery (ADR-0058, main's
|
|
21
|
+
// task-notice.ts) is a session event like the others
|
|
22
|
+
[/^✦ task (.*)$/s, "TASK", (m) => m[1]],
|
|
23
|
+
[/^run failed — (.*)$/s, "FAILED", (m) => m[1]],
|
|
24
|
+
[/^(\S+) FAILED — (.*)$/s, "UNCERTAIN", (m) => `${m[1]} — ${m[2]}`],
|
|
25
|
+
// Graphite P1b (owner, 2026-09-30): dontAsk leaves an interrupted call
|
|
26
|
+
// undecided — said as what it is, and when it will be asked
|
|
27
|
+
[/^\[dontAsk\] (\d+) uncertain executions? left unresolved — resolve them in an asking mode$/s, "UNCERTAIN", (m) => `${m[1]} interrupted command${m[1] === "1" ? "" : "s"} left undecided — asked once don't ask is off`],
|
|
28
|
+
// the main-sync round (owner, 2026-09-30): a call refused because the
|
|
29
|
+
// don't-ask switch is on — the person set this up, so the label is dim,
|
|
30
|
+
// not a failure's red
|
|
31
|
+
[/^\[dontAsk\] (\S+) would ask — denied$/s, "DENIED", (m) => `${m[1]} would ask — denied`],
|
|
32
|
+
[/^(stopped at the .*-turn limit.*)$/s, "LIMIT", (m) => m[1]],
|
|
33
|
+
[/^(answer truncated at max_tokens.*)$/s, "LIMIT", (m) => m[1]],
|
|
34
|
+
[/^stream interrupted — (.*)$/s, "INTERRUPTED", (m) => m[1]],
|
|
35
|
+
[/^(no reply recorded — .*)$/s, "INTERRUPTED", (m) => m[1]],
|
|
36
|
+
[/^verification pass$/s, "VERIFY", () => ""],
|
|
37
|
+
// the last sweep (owner, 2026-10-06): a session switch (`/clear`,
|
|
38
|
+
// `/resume <id>`) is a session event — the id it opened and the way back
|
|
39
|
+
[/^session (\S+) \(switched — previous: (\S+), \/resume \S+ returns\)\n?$/s, "SESSION", (m) => `${m[1]} · /resume ${m[2]} returns`],
|
|
40
|
+
[/^--- re-wrapped (\d+ blocks?) at the current width \(appended — the history above is unchanged\) ---$/s, "REWRAPPED", (m) => `${m[1]} at the current width · the history above is unchanged`],
|
|
41
|
+
[/^\[dontAsk\] the model's question was declined — nothing asks in dontAsk$/s, "DENIED", () => "the model's question — nothing asks while don't ask is on"],
|
|
42
|
+
// …and a command's own reply. It wore its command in brackets
|
|
43
|
+
// (`[/compact] …`, `[reload] …`), or brackets alone (`[no thinking
|
|
44
|
+
// yet]`), or `--- … ---` rules; on the terminal the person has just
|
|
45
|
+
// typed the command, so the reply is a sentence at the content edge.
|
|
46
|
+
// A pipe keeps every bracket.
|
|
47
|
+
[/^\[reload\] (\d+ extensions?\b.*)$/s, null, (m) => `reloaded ${m[1]}`],
|
|
48
|
+
[/^\[reload\] (.*)$/s, null, (m) => `reload failed: ${m[1]}`],
|
|
49
|
+
[/^\[\/([a-z-]+)\] failed: (.*)$/s, null, (m) => `/${m[1]} failed: ${m[2]}`],
|
|
50
|
+
[/^\[\/[a-z-]+\] (.*)$/s, null, (m) => m[1]],
|
|
51
|
+
[/^\[(turn held — [^\]]+)\] (.*)$/s, null, (m) => `${m[1]} · ${m[2]}`],
|
|
52
|
+
[/^\[([^[\]\n]+)\]$/s, null, (m) => m[1]],
|
|
53
|
+
[/^no such mode: (.*)\ntiers: (.*)$/s, null, (m) => `no such mode: ${m[1]} · tiers: ${m[2]}`],
|
|
54
|
+
[/^--- (\d+ earlier blocks?) not re-wrapped \(bounded at two screens\) ---$/s, null, (m) => `${m[1]} not re-wrapped — bounded at two screens`],
|
|
55
|
+
];
|
|
56
|
+
/** The main sync (0.46.2, Amendment 8) — a task kiso lost track of, said
|
|
57
|
+
* the moment it is concluded: `✦ lost track of <id> (<what>) — it may
|
|
58
|
+
* still be running · /tasks shows it` (the parenthesis only when the
|
|
59
|
+
* command is known; the last ` — ` opens the tail — both pinned by the
|
|
60
|
+
* line's own test). On the terminal it is the TASK row a delivery draws,
|
|
61
|
+
* `lost track — may still be running` in gold. */
|
|
62
|
+
const LOST = /^✦ lost track of (\S+)(?: \((.*)\))? — (it may still be running.*)$/s;
|
|
63
|
+
export function noticeMeta(text) {
|
|
64
|
+
const lost = LOST.exec(text);
|
|
65
|
+
if (lost !== null) {
|
|
66
|
+
const word = "lost track — may still be running";
|
|
67
|
+
// one row, as every row that names a thing (§7.12): where to look before
|
|
68
|
+
// what ran, so a cut takes the command, never the way to it
|
|
69
|
+
return { label: "TASK", sentence: `${lost[1]} ${word} · /tasks shows it${lost[2] !== undefined ? ` · ${lost[2]}` : ""}`, mark: { text: word, tone: "gold" }, oneRow: true };
|
|
70
|
+
}
|
|
71
|
+
// a notice that opens with spaces continues the one above it (the
|
|
72
|
+
// verification pass's content): no label of its own
|
|
73
|
+
if (/^ {2}\S/.test(text))
|
|
74
|
+
return { label: "", sentence: text.trim() };
|
|
75
|
+
for (const [re, label, sentence] of SHAPES) {
|
|
76
|
+
const m = re.exec(text);
|
|
77
|
+
if (m !== null)
|
|
78
|
+
return label === null ? { sentence: sentence(m) } : { label, sentence: sentence(m) };
|
|
79
|
+
}
|
|
80
|
+
// no kind of its own: the sentence stays whole — only the `✦`, which is
|
|
81
|
+
// the seal's mark on a terminal (§4), comes off
|
|
82
|
+
return { sentence: text.replace(/^✦ /, "") };
|
|
83
|
+
}
|
package/dist/panel-input.d.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* one band, in an order the editor keeps in one place: the panel first,
|
|
7
7
|
* then the session picker, then the composer's own bands. What the
|
|
8
8
|
* panel may do to the composer is the `BandHost` surface and nothing
|
|
9
|
-
* else: it types its amend reason, its custom ask answer and
|
|
10
|
-
*
|
|
9
|
+
* else: it types its amend reason, its custom ask answer and a pick's
|
|
10
|
+
* filter into the composer, stashes the composer at open, restores it at
|
|
11
11
|
* close — that is the whole coupling, and it is visible here.
|
|
12
12
|
*
|
|
13
13
|
* DECLARED MOVE (S5, 2026-09-06): every method below stood in editor.ts
|