@vincemakes/kiso-tui-cells 0.31.0 → 0.31.1
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/approval-panel.d.ts +39 -2
- package/dist/approval-panel.js +90 -4
- package/package.json +1 -1
package/dist/approval-panel.d.ts
CHANGED
|
@@ -209,7 +209,39 @@ export interface PickOption {
|
|
|
209
209
|
/** the dim qualifier ("profile: ds \u00b7 current") \u2014 what tells two
|
|
210
210
|
* similar rows apart */
|
|
211
211
|
readonly note?: string;
|
|
212
|
+
/** OR-7 — the SECOND axis. The model's NATIVE levels in vendor order,
|
|
213
|
+
* from the registry. Absent = this option has no second axis and the
|
|
214
|
+
* row renders exactly as it did before. */
|
|
215
|
+
readonly levels?: readonly string[];
|
|
216
|
+
/** where the level cursor starts. UNDEFINED is a real state, not a
|
|
217
|
+
* missing value: a row whose registry default is null (the page
|
|
218
|
+
* states none) marks nothing, and enter applies the profile alone.
|
|
219
|
+
* The panel never invents a default. */
|
|
220
|
+
readonly level?: number;
|
|
221
|
+
/** indexes forbidden for the current thinking mode. The cursor never
|
|
222
|
+
* rests on one \u2014 see `enabledLevel`. */
|
|
223
|
+
readonly disabled?: readonly number[];
|
|
224
|
+
/** shown after the strip when the cursor did NOT land where the
|
|
225
|
+
* previous selection asked ("effort xhigh \u2192 high: the nearest this
|
|
226
|
+
* model supports"). The caller's sentence, reproduced verbatim. */
|
|
227
|
+
readonly levelNote?: string;
|
|
212
228
|
}
|
|
229
|
+
/** The level cursor, CORRECTED at read time: never off the end, never on
|
|
230
|
+
* a forbidden index, and never invented where the caller supplied none.
|
|
231
|
+
*
|
|
232
|
+
* One rule instead of two. The alternative \u2014 letting the cursor rest on
|
|
233
|
+
* a forbidden index and refusing at enter \u2014 needs a second mechanism to
|
|
234
|
+
* say why nothing happened, and a key that silently does nothing is the
|
|
235
|
+
* defect this panel already fixed once (DC-36). Correcting on read is
|
|
236
|
+
* the discipline the session picker uses for its own selection. */
|
|
237
|
+
export declare function enabledLevel(o: PickOption | undefined, want: number | null): number | null;
|
|
238
|
+
/** Where the cursor OPENS on an option: what the caller asked for,
|
|
239
|
+
* corrected. The two callers (the panel opening, and the highlight
|
|
240
|
+
* moving to another row) mean exactly this and nothing else. */
|
|
241
|
+
export declare function startLevel(o: PickOption | undefined): number | null;
|
|
242
|
+
/** The next enabled index in `dir`, or the current one at the end of the
|
|
243
|
+
* ladder. Forbidden indexes are stepped OVER, never landed on. */
|
|
244
|
+
export declare function stepLevel(o: PickOption, from: number | null, dir: -1 | 1): number | null;
|
|
213
245
|
/** The whole pick: the header sentence, the options, the free-text
|
|
214
246
|
* escape hatch, and the honest empty state. */
|
|
215
247
|
export interface PickSpec {
|
|
@@ -231,6 +263,9 @@ export interface PickSpec {
|
|
|
231
263
|
export interface PickRuntime {
|
|
232
264
|
readonly cursor: number;
|
|
233
265
|
readonly phase: "options" | "custom";
|
|
266
|
+
/** OR-7: the level cursor within the highlighted option. null = the
|
|
267
|
+
* option has no levels, or has no default to mark. */
|
|
268
|
+
readonly level: number | null;
|
|
234
269
|
}
|
|
235
270
|
/** What was picked: a listed option by INDEX (never a label the caller
|
|
236
271
|
* would have to re-match against its own list), or typed text. */
|
|
@@ -322,10 +357,12 @@ export type PanelVerdict = {
|
|
|
322
357
|
}
|
|
323
358
|
/** TUI2-R2 \u2463: the pick's verdict \u2014 the chosen index or the typed
|
|
324
359
|
* text. Only pick views ever produce it, so the approval path's
|
|
325
|
-
* switch is untouched.
|
|
360
|
+
* switch is untouched. OR-7 adds the second axis beside it: the
|
|
361
|
+
* level INDEX, absent when the option had no levels or marked none. */
|
|
326
362
|
| {
|
|
327
363
|
readonly action: "picked";
|
|
328
364
|
readonly result: PickResult;
|
|
365
|
+
readonly level?: number;
|
|
329
366
|
};
|
|
330
367
|
/** The bound panel state the compositor reads — the editor owns the
|
|
331
368
|
* phase/selection state machine and the key routing; the compositor
|
|
@@ -432,7 +469,7 @@ export declare function pickLead(view: PanelView, state: PickRuntime): string;
|
|
|
432
469
|
/** The status row's left text \u2014 the CALLER's, because only the caller
|
|
433
470
|
* knows whether a run is paused behind this panel. */
|
|
434
471
|
export declare function pickStatus(view: PanelView): string;
|
|
435
|
-
export declare function pickAffordance(state: PickRuntime): string;
|
|
472
|
+
export declare function pickAffordance(state: PickRuntime, axis?: boolean): string;
|
|
436
473
|
/** Compose a pick view. The flavor/name/title/args fields exist for the
|
|
437
474
|
* approval path and are given inert values here \u2014 the pick block
|
|
438
475
|
* reads none of them. */
|
package/dist/approval-panel.js
CHANGED
|
@@ -164,6 +164,58 @@ function segmentRisk(segment) {
|
|
|
164
164
|
}
|
|
165
165
|
return null;
|
|
166
166
|
}
|
|
167
|
+
/** The level cursor, CORRECTED at read time: never off the end, never on
|
|
168
|
+
* a forbidden index, and never invented where the caller supplied none.
|
|
169
|
+
*
|
|
170
|
+
* One rule instead of two. The alternative \u2014 letting the cursor rest on
|
|
171
|
+
* a forbidden index and refusing at enter \u2014 needs a second mechanism to
|
|
172
|
+
* say why nothing happened, and a key that silently does nothing is the
|
|
173
|
+
* defect this panel already fixed once (DC-36). Correcting on read is
|
|
174
|
+
* the discipline the session picker uses for its own selection. */
|
|
175
|
+
export function enabledLevel(o, want) {
|
|
176
|
+
const levels = o?.levels;
|
|
177
|
+
if (levels === undefined || levels.length === 0 || want === null)
|
|
178
|
+
return null;
|
|
179
|
+
const off = new Set(o?.disabled ?? []);
|
|
180
|
+
if (off.size >= levels.length)
|
|
181
|
+
return null; // every level forbidden: nothing to point at
|
|
182
|
+
const clamped = Math.max(0, Math.min(levels.length - 1, want));
|
|
183
|
+
if (!off.has(clamped))
|
|
184
|
+
return clamped;
|
|
185
|
+
// walk outward from the asked-for index, nearest first
|
|
186
|
+
for (let d = 1; d < levels.length; d += 1) {
|
|
187
|
+
const hi = clamped + d;
|
|
188
|
+
if (hi < levels.length && !off.has(hi))
|
|
189
|
+
return hi;
|
|
190
|
+
const lo = clamped - d;
|
|
191
|
+
if (lo >= 0 && !off.has(lo))
|
|
192
|
+
return lo;
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
/** Where the cursor OPENS on an option: what the caller asked for,
|
|
197
|
+
* corrected. The two callers (the panel opening, and the highlight
|
|
198
|
+
* moving to another row) mean exactly this and nothing else. */
|
|
199
|
+
export function startLevel(o) {
|
|
200
|
+
return enabledLevel(o, o?.level ?? null);
|
|
201
|
+
}
|
|
202
|
+
/** The next enabled index in `dir`, or the current one at the end of the
|
|
203
|
+
* ladder. Forbidden indexes are stepped OVER, never landed on. */
|
|
204
|
+
export function stepLevel(o, from, dir) {
|
|
205
|
+
const levels = o.levels;
|
|
206
|
+
if (levels === undefined || levels.length === 0)
|
|
207
|
+
return null;
|
|
208
|
+
// the first press on a row that marks nothing enters the ladder at
|
|
209
|
+
// its near end rather than guessing a middle.
|
|
210
|
+
if (from === null)
|
|
211
|
+
return enabledLevel(o, dir === 1 ? 0 : levels.length - 1);
|
|
212
|
+
const off = new Set(o.disabled ?? []);
|
|
213
|
+
for (let i = from + dir; i >= 0 && i < levels.length; i += dir) {
|
|
214
|
+
if (!off.has(i))
|
|
215
|
+
return i;
|
|
216
|
+
}
|
|
217
|
+
return from;
|
|
218
|
+
}
|
|
167
219
|
/** The rule line's text — the why-asked line (the R3 chain): the tool
|
|
168
220
|
* name, the first non-abstain speaker, the fix hint (the §3.5 table,
|
|
169
221
|
* code-accented). The simple flavor carries the CLI's own question
|
|
@@ -516,7 +568,14 @@ export function pickBlockRows(view, state, W, maxRows) {
|
|
|
516
568
|
// content were scrolled irreversibly into the scrollback every time
|
|
517
569
|
// `/model` opened on a tight screen. The `+N more` row is a sixth
|
|
518
570
|
// when it appears, so it is paid for too.
|
|
519
|
-
|
|
571
|
+
// OR-7: the level strip is a row of its own under the highlighted
|
|
572
|
+
// option, so it is chrome and it is paid for here. Inline after the
|
|
573
|
+
// note was the coordination note's shape and it does not fit: five
|
|
574
|
+
// levels need 42 columns and the note column has 48 at width 100,
|
|
575
|
+
// which it already spends on `profile: <name>`. A second axis that
|
|
576
|
+
// truncates on a normal terminal is not a second axis.
|
|
577
|
+
const strip = spec.options[state.cursor]?.levels !== undefined && state.phase === "options" ? 1 : 0;
|
|
578
|
+
const chrome = 5 + strip + (spec.options.length > Math.min(Math.max(1, maxRows - 5 - strip), PICK_MAX) ? 1 : 0);
|
|
520
579
|
const budget = Math.max(1, maxRows - chrome);
|
|
521
580
|
const shown = spec.options.slice(0, Math.min(budget, PICK_MAX));
|
|
522
581
|
// R2: the note takes a COLUMN, not three spaces after a label of
|
|
@@ -548,13 +607,35 @@ export function pickBlockRows(view, state, W, maxRows) {
|
|
|
548
607
|
if (spec.options.length > shown.length) {
|
|
549
608
|
rows.push(` ${cutLine(`${p.dim} \u2514 +${spec.options.length - shown.length} more \u2014 /model <name> takes any of them${p.reset}`, room)}`);
|
|
550
609
|
}
|
|
610
|
+
const axis = shown[state.cursor];
|
|
611
|
+
if (strip === 1 && axis?.levels !== undefined) {
|
|
612
|
+
const off = new Set(axis.disabled ?? []);
|
|
613
|
+
// the RUNTIME cursor, not the option's starting index: the option
|
|
614
|
+
// says where the cursor opens, the state says where it is now.
|
|
615
|
+
// Reading the option here rendered a bracket that never moved
|
|
616
|
+
// while the state underneath it did — the silent movement this
|
|
617
|
+
// whole axis exists to replace.
|
|
618
|
+
const cur = enabledLevel(axis, state.level);
|
|
619
|
+
// the bracket means THE CURSOR IS HERE. It used to mean "the
|
|
620
|
+
// registry default" in the note's text form; a row whose
|
|
621
|
+
// default is null now marks nothing at all rather than
|
|
622
|
+
// promoting the first level into one.
|
|
623
|
+
const cells = axis.levels.map((l, i) => {
|
|
624
|
+
const text = escapeTerminal(l);
|
|
625
|
+
if (off.has(i))
|
|
626
|
+
return `${p.dim}${text}${p.reset}`;
|
|
627
|
+
return i === cur ? `${p.bold}[${text}]${p.reset}` : text;
|
|
628
|
+
});
|
|
629
|
+
const note = axis.levelNote === undefined ? "" : ` ${p.dim}\u2014 ${escapeTerminal(axis.levelNote)}${p.reset}`;
|
|
630
|
+
rows.push(` ${cutLine(`${p.dim}effort: ${p.reset}${cells.join(`${p.dim} \u00b7 ${p.reset}`)}${note}`, room)}`);
|
|
631
|
+
}
|
|
551
632
|
}
|
|
552
633
|
const typing = state.phase === "custom";
|
|
553
634
|
if (spec.typeHint !== undefined) {
|
|
554
635
|
const tText = cutLine(`${typing ? p.bold : ""}${typing ? "\u2192" : " "} t ${p.reset}${p.dim}${escapeTerminal(spec.typeHint)}${p.reset}`, room);
|
|
555
636
|
rows.push(typing ? selectionBar(tText, visibleWidth(tText), W) : ` ${tText}`);
|
|
556
637
|
}
|
|
557
|
-
rows.push(` ${p.dim}${cutLine(pickAffordance(state), room)}${p.reset}`);
|
|
638
|
+
rows.push(` ${p.dim}${cutLine(pickAffordance(state, spec.options[state.cursor]?.levels !== undefined), room)}${p.reset}`);
|
|
558
639
|
rows.push(`${p.dim}${"\u2500".repeat(Math.max(0, W))}${p.reset}`);
|
|
559
640
|
return rows;
|
|
560
641
|
}
|
|
@@ -579,14 +660,19 @@ export function pickLead(view, state) {
|
|
|
579
660
|
export function pickStatus(view) {
|
|
580
661
|
return view.statusText;
|
|
581
662
|
}
|
|
582
|
-
export function pickAffordance(state) {
|
|
663
|
+
export function pickAffordance(state, axis = false) {
|
|
583
664
|
// DC-36 — the row NAMES the arrows. TUI2-R2 ④ bound ↑↓ to the pick's
|
|
584
665
|
// cursor and the keys sheet has said `panels: ↑↓ move` ever since,
|
|
585
666
|
// but this row — the one a human is actually looking at while the
|
|
586
667
|
// panel is up — advertised only the digits. The owner read it as
|
|
587
668
|
// "type the answer", which is the same lesson DC-30 filed: a hint
|
|
588
669
|
// that omits the gesture is why the gesture goes unused.
|
|
589
|
-
|
|
670
|
+
// OR-7 names \u2190\u2192 here for the same reason DC-36 named \u2191\u2193: a gesture
|
|
671
|
+
// this row omits is a gesture that goes unused. It appears only when
|
|
672
|
+
// there is a second axis to walk.
|
|
673
|
+
if (state.phase === "custom")
|
|
674
|
+
return "enter commits \u00b7 esc backs out";
|
|
675
|
+
return axis ? "\u2191\u2193 move \u00b7 \u2190\u2192 effort \u00b7 digits pick \u00b7 \u23ce confirms \u00b7 esc" : "\u2191\u2193 move \u00b7 digits pick \u00b7 \u23ce confirms \u00b7 esc";
|
|
590
676
|
}
|
|
591
677
|
/** Compose a pick view. The flavor/name/title/args fields exist for the
|
|
592
678
|
* approval path and are given inert values here \u2014 the pick block
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui-cells",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.1",
|
|
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",
|