@vincemakes/kiso-tui-cells 0.16.7 → 0.16.8
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/components.d.ts +2 -0
- package/dist/components.js +109 -16
- package/package.json +1 -1
package/dist/components.d.ts
CHANGED
|
@@ -280,6 +280,8 @@ export declare function exploreRows(parts: readonly {
|
|
|
280
280
|
name: string;
|
|
281
281
|
subjects: readonly string[];
|
|
282
282
|
}[], W: number): string[];
|
|
283
|
+
/** Does this tool's fold term count distinct targets rather than calls? */
|
|
284
|
+
export declare function foldCountsObjects(name: string): boolean;
|
|
283
285
|
export declare function foldTerms(reads: number, edits: number, others: readonly [string, number][]): string[];
|
|
284
286
|
export declare function turnFold(t: {
|
|
285
287
|
words: string;
|
package/dist/components.js
CHANGED
|
@@ -920,7 +920,14 @@ export function exploreCounts(parts) {
|
|
|
920
920
|
return parts
|
|
921
921
|
.map((part) => {
|
|
922
922
|
const [singular, plural] = EXPLORE_NOUN[part.name] ?? ["call", "calls"];
|
|
923
|
-
|
|
923
|
+
// R3h (fable, 2026-08-29): DISTINCT subjects. This counted calls
|
|
924
|
+
// while exploreRows — the very next function, the expansion of
|
|
925
|
+
// THIS row — deduped them with `×N`. So the head said "6 files"
|
|
926
|
+
// over a list showing four, one of them `a.ts ×3`. The head and
|
|
927
|
+
// the body are two views of one run and must count alike; the
|
|
928
|
+
// body was right (a file read twice is one file).
|
|
929
|
+
const n = foldCountsObjects(part.name) ? new Set(part.subjects).size : part.subjects.length;
|
|
930
|
+
return `${n} ${n === 1 ? singular : plural}`;
|
|
924
931
|
})
|
|
925
932
|
.join(" · ");
|
|
926
933
|
}
|
|
@@ -965,12 +972,20 @@ function countTerm(n, singular, plural) {
|
|
|
965
972
|
* as first-call-order terms (the ROLLUP_NOUN plurals when the tool opts
|
|
966
973
|
* in, the verb + "s" otherwise).
|
|
967
974
|
* A9 (ruling R2, mock A): the user chip rides the fold — the human's
|
|
968
|
-
* words LEAD the one line,
|
|
969
|
-
*
|
|
970
|
-
*
|
|
971
|
-
*
|
|
972
|
-
*
|
|
973
|
-
*
|
|
975
|
+
* words LEAD the one line, `✦ <chip> · thought 19s · read 5 files` —
|
|
976
|
+
* the chip the SAME SGR-7 bracket as the live user row (#16f, side
|
|
977
|
+
* pads included). The words take the fold's width budget and width-cut
|
|
978
|
+
* at the end with the honest "…" (never a silent truncate — invariant
|
|
979
|
+
* ① holds on the ONE row by construction).
|
|
980
|
+
*
|
|
981
|
+
* DECLARED SUPERSESSION (R3g, 2026-08-28) — A9 also ruled that "the
|
|
982
|
+
* metadata terms give way LAST". They do not any more: the KEY does.
|
|
983
|
+
* A9 was taken when this line carried no key, and at a width where the
|
|
984
|
+
* chip, the full metadata and " · ctrl+r" cannot coexist, a fold with
|
|
985
|
+
* no key is the turn's work behind a line with no way back to it. So
|
|
986
|
+
* the order is now words, then metadata, then — never — the key. The
|
|
987
|
+
* glyph is ✦ and the zero terms are dropped (R3b), so the example above
|
|
988
|
+
* is written as the code renders it rather than as A9 first wrote it. */
|
|
974
989
|
/**
|
|
975
990
|
* R3b — what a run of work DID, in words. One definition, because two
|
|
976
991
|
* surfaces say it: the fold line (`turnFold`, above) and the expand
|
|
@@ -1006,6 +1021,24 @@ const FOLD_TERM = {
|
|
|
1006
1021
|
search_text: ["ran", "search", "searches"],
|
|
1007
1022
|
shell: ["ran", "shell command", "shell commands"],
|
|
1008
1023
|
};
|
|
1024
|
+
/**
|
|
1025
|
+
* R3h (fable, 2026-08-29) — WHICH TERMS COUNT OBJECTS.
|
|
1026
|
+
*
|
|
1027
|
+
* The rule, one sentence: a term that counts OBJECTS counts distinct
|
|
1028
|
+
* objects; a term that counts ACTS counts calls. `read 2 files` after
|
|
1029
|
+
* reading ONE file twice is a false sentence, and law 1.3 does not
|
|
1030
|
+
* become optional because the falsehood is small. `ran 2 searches`
|
|
1031
|
+
* after searching the same pattern twice is TRUE — the acts happened.
|
|
1032
|
+
*
|
|
1033
|
+
* The table sits beside FOLD_TERM so the two cannot drift: a tool whose
|
|
1034
|
+
* noun is a thing ("files", "directories") belongs here; a tool whose
|
|
1035
|
+
* noun is an act ("searches", "shell commands") does not.
|
|
1036
|
+
*/
|
|
1037
|
+
const FOLD_COUNTS_OBJECTS = new Set(["read_file", "edit_file", "write_file", "list_dir"]);
|
|
1038
|
+
/** Does this tool's fold term count distinct targets rather than calls? */
|
|
1039
|
+
export function foldCountsObjects(name) {
|
|
1040
|
+
return FOLD_COUNTS_OBJECTS.has(name);
|
|
1041
|
+
}
|
|
1009
1042
|
function foldTerm(name, n) {
|
|
1010
1043
|
const t = FOLD_TERM[name];
|
|
1011
1044
|
if (t === undefined)
|
|
@@ -1032,7 +1065,12 @@ export function turnFold(t, W) {
|
|
|
1032
1065
|
// happen — on a segment fold, where a run is usually all reads or all
|
|
1033
1066
|
// edits, half the row was the half that said nothing. A term earns its
|
|
1034
1067
|
// place by having a count.
|
|
1035
|
-
|
|
1068
|
+
// R3h (fable, 2026-08-29): the THOUGHT term obeys the same zero-drop
|
|
1069
|
+
// rule every other term got at R3b. It was exempt by accident — it
|
|
1070
|
+
// was written before the rule — so a model that emits no thinking
|
|
1071
|
+
// folded every turn of its life under `thought 0s`, a sentence about
|
|
1072
|
+
// something that did not happen, in the lead position.
|
|
1073
|
+
const meta = [...(t.thoughtSeconds > 0 ? [`thought ${t.thoughtSeconds}s`] : []), ...foldTerms(t.reads, t.edits, t.others)].join(" · ");
|
|
1036
1074
|
// R3f: the same one-row rule. This one is worse than the thinking
|
|
1037
1075
|
// fold's — the fold is a COMMITTED row, so a multi-line user message
|
|
1038
1076
|
// would desync the committed-line accounting permanently rather than
|
|
@@ -1056,6 +1094,29 @@ export function turnFold(t, W) {
|
|
|
1056
1094
|
// words was unreachable by the key its siblings advertise. Found by
|
|
1057
1095
|
// an independent review (fable) and then by the paced-rollup gate,
|
|
1058
1096
|
// which got `kind: "none"` back from expandNext.
|
|
1097
|
+
// R3h: the COMPACT tier. The owner's own sentence — "thought 17s ·
|
|
1098
|
+
// read 4 files · listed 1 directory · ran 4 shell commands" — is 81
|
|
1099
|
+
// cells with the key at W=80: one over, so the tail was cut off the
|
|
1100
|
+
// exact shape this round exists to produce. The nouns shorten before
|
|
1101
|
+
// anything is lost, which is the same "degrade, never truncate"
|
|
1102
|
+
// ladder every other row here walks.
|
|
1103
|
+
// A LADDER, cheapest first, and it stops as soon as the row fits: the
|
|
1104
|
+
// owner's canonical sentence is ONE cell over at W=80, and spending
|
|
1105
|
+
// every substitution to buy one cell would shorten words that had
|
|
1106
|
+
// room. "directory" is the cheapest to lose (nobody misreads "dir");
|
|
1107
|
+
// "commands" is next and still says what happened.
|
|
1108
|
+
const COMPACT = [
|
|
1109
|
+
["directories", "dirs"],
|
|
1110
|
+
["directory", "dir"],
|
|
1111
|
+
["shell commands", "commands"],
|
|
1112
|
+
["shell command", "command"],
|
|
1113
|
+
];
|
|
1114
|
+
const compactAll = (text) => {
|
|
1115
|
+
let out = text;
|
|
1116
|
+
for (const [long, short] of COMPACT)
|
|
1117
|
+
out = out.replaceAll(long, short);
|
|
1118
|
+
return out;
|
|
1119
|
+
};
|
|
1059
1120
|
const KEY = " · ctrl+r";
|
|
1060
1121
|
const keyW = KEY.length;
|
|
1061
1122
|
const key = `${p.dim}${KEY}${p.reset}`;
|
|
@@ -1063,12 +1124,29 @@ export function turnFold(t, W) {
|
|
|
1063
1124
|
const keyed = `${p.bold}✦${p.reset} ${meta}${key}`;
|
|
1064
1125
|
if (visibleWidth(keyed) <= W)
|
|
1065
1126
|
return [keyed];
|
|
1066
|
-
|
|
1067
|
-
|
|
1127
|
+
let tightMeta = meta;
|
|
1128
|
+
for (const [long, short] of COMPACT) {
|
|
1129
|
+
tightMeta = tightMeta.replaceAll(long, short);
|
|
1130
|
+
const tight = `${p.bold}✦${p.reset} ${tightMeta}${key}`;
|
|
1131
|
+
if (visibleWidth(tight) <= W)
|
|
1132
|
+
return [tight];
|
|
1133
|
+
}
|
|
1134
|
+
// the meta cuts with the honest "…" — the COMPACT form of it, so a
|
|
1135
|
+
// cut row still carries as many whole terms as the width allows;
|
|
1136
|
+
// below the width where even the key fits there is nothing to
|
|
1137
|
+
// preserve and the row is a cut.
|
|
1068
1138
|
const room = W - 2 - keyW - 1;
|
|
1069
|
-
if (room < 2)
|
|
1070
|
-
|
|
1071
|
-
|
|
1139
|
+
if (room < 2) {
|
|
1140
|
+
// R3h: and below FOUR columns even that row is 4 cells wide (the
|
|
1141
|
+
// gutter, one character, the "…"), so invariant ① threw AT the
|
|
1142
|
+
// widths this branch exists to serve — the same class DC-15
|
|
1143
|
+
// closed in the thinking fold, still open here. A width with no
|
|
1144
|
+
// room for the mark is a width with nothing to say: the row is
|
|
1145
|
+
// a hard cut of what it would have said.
|
|
1146
|
+
const cut = `${p.bold}✦${p.reset} ${widthCut(tightMeta, Math.max(1, W - 3))}…`;
|
|
1147
|
+
return [visibleWidth(cut) <= W ? cut : cutLine(`${p.bold}✦${p.reset} ${tightMeta}`, W)];
|
|
1148
|
+
}
|
|
1149
|
+
return [`${p.bold}✦${p.reset} ${widthCut(tightMeta, room)}…${key}`];
|
|
1072
1150
|
}
|
|
1073
1151
|
// A9 (ruling R2, mock A): the user chip rides the fold — the human's
|
|
1074
1152
|
// words LEAD the one line, the same SGR-7 bracket as the live user
|
|
@@ -1083,14 +1161,29 @@ export function turnFold(t, W) {
|
|
|
1083
1161
|
const row = `${p.bold}✦${p.reset} ${p.rv} ${cut} ${p.rvEnd} · ${meta}${key}`;
|
|
1084
1162
|
if (visibleWidth(row) <= W)
|
|
1085
1163
|
return [row];
|
|
1164
|
+
// R3h: the same COMPACT ladder the wordless branch walks — the nouns
|
|
1165
|
+
// shorten before the words or the metadata lose anything.
|
|
1166
|
+
let chipMeta = meta;
|
|
1167
|
+
for (const [long, short] of COMPACT) {
|
|
1168
|
+
chipMeta = chipMeta.replaceAll(long, short);
|
|
1169
|
+
const tighter = `${p.bold}✦${p.reset} ${p.rv} ${cut} ${p.rvEnd} · ${chipMeta}${key}`;
|
|
1170
|
+
if (visibleWidth(tighter) <= W)
|
|
1171
|
+
return [tighter];
|
|
1172
|
+
}
|
|
1086
1173
|
// the last resort: the METADATA gives way — the words hold their
|
|
1087
1174
|
// budget, the key holds its nine cells, the meta cuts with the honest
|
|
1088
1175
|
// "…"; invariant ① never trips at ANY width (a degenerate W's fold is
|
|
1089
1176
|
// a cut, never a crash).
|
|
1090
1177
|
const room = W - 8 - keyW - visibleWidth(cut);
|
|
1091
|
-
if (room < 2)
|
|
1092
|
-
|
|
1093
|
-
|
|
1178
|
+
if (room < 2) {
|
|
1179
|
+
// R3h: the chip branch's own degenerate floor. The gutter, the
|
|
1180
|
+
// bracket's pads, the join and the "…" are ten cells before a
|
|
1181
|
+
// single character of content, so every width below ten threw
|
|
1182
|
+
// invariant ① — see the wordless branch above for the same class.
|
|
1183
|
+
const tail = `${p.bold}✦${p.reset} ${p.rv} ${cut} ${p.rvEnd} · ${widthCut(compactAll(meta), Math.max(1, W - 8 - visibleWidth(cut)))}…`;
|
|
1184
|
+
return [visibleWidth(tail) <= W ? tail : cutLine(`${p.bold}✦${p.reset} ${p.rv} ${cut} ${p.rvEnd}`, W)];
|
|
1185
|
+
}
|
|
1186
|
+
return [`${p.bold}✦${p.reset} ${p.rv} ${cut} ${p.rvEnd} · ${widthCut(compactAll(meta), room)}…${key}`];
|
|
1094
1187
|
}
|
|
1095
1188
|
// ---- the bounded-block flow contract (W7, W8, W10) ----
|
|
1096
1189
|
/** The caps — screen rows counted AFTER the fold, at the current width
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui-cells",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.8",
|
|
4
4
|
"description": "kiso tui-cells — the components cell renderer (components, diff, width, the render slice). Zero runtime dependencies: input is data, output is bytes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|