@vincemakes/kiso-tui-cells 0.16.2 → 0.16.4

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/strings.js CHANGED
@@ -51,7 +51,7 @@ export function projectTrustView(root, files) {
51
51
  name: "project trust",
52
52
  title: root,
53
53
  speaker: "kiso",
54
- statusText: " project trust",
54
+ statusText: " project trust",
55
55
  args: { kind: "text", lines: projectTrustRows(files) },
56
56
  ruleOverride: "trust this project's .kiso?",
57
57
  fallbackQuestion: `trust this project's .kiso? (y/n) `,
@@ -96,7 +96,7 @@ export function verifyOfferView() {
96
96
  name: "verification",
97
97
  title: "finish the checklist?",
98
98
  speaker: "kiso",
99
- statusText: "\u25b8 run paused",
99
+ statusText: "\u23f8 run paused",
100
100
  args: { kind: "text", lines: [] },
101
101
  ruleOverride: "every item is marked done \u2014 run a check?",
102
102
  simpleOptions: ["run a verification pass", "not now"],
@@ -109,7 +109,7 @@ export function uncertainView(name, executionId) {
109
109
  name: "uncertain execution",
110
110
  title: `${name} (${executionId})`,
111
111
  speaker: "kiso",
112
- statusText: " uncertain execution",
112
+ statusText: " uncertain execution",
113
113
  args: { kind: "text", lines: [executionId] },
114
114
  ruleOverride: "an interrupted execution may have applied — rerun it?",
115
115
  simpleOptions: ["rerun it", "abandon it"],
@@ -136,7 +136,7 @@ export function unansweredAskView(executionId) {
136
136
  name: "unanswered question",
137
137
  title: `ask_user (${executionId})`,
138
138
  speaker: "kiso",
139
- statusText: " unanswered question",
139
+ statusText: " unanswered question",
140
140
  args: { kind: "text", lines: [executionId] },
141
141
  ruleOverride: "an unanswered question was interrupted — ask it again?",
142
142
  simpleOptions: ["ask it again", "drop it"],
@@ -276,7 +276,10 @@ export function keysSheetRows(W) {
276
276
  const p = palette();
277
277
  const cell = (i) => {
278
278
  const b = KEY_BINDINGS[i];
279
- return b === undefined ? "" : `${p.code}${b.keys}${p.reset} ${b.what}`;
279
+ // DC-3: the key NAMES are the sheet's content, not a code span —
280
+ // they borrowed the inline-code tint and became the least readable
281
+ // thing on the one screen whose whole job is being read.
282
+ return b === undefined ? "" : `${p.bold}${b.keys}${p.reset} ${b.what}`;
280
283
  };
281
284
  const plainCell = (i) => {
282
285
  const b = KEY_BINDINGS[i];
@@ -299,13 +302,40 @@ export function keysSheetRows(W) {
299
302
  }
300
303
  rows.push(row);
301
304
  }
302
- rows.push(`${p.dim}${PANEL_KEYS_ROW}${p.reset}`);
305
+ rows.push(`${p.dim}${panelKeysRow(W)}${p.reset}`);
303
306
  return rows.map((row) => cutRow(row, W));
304
307
  }
308
+ /**
309
+ * DC-2 — the panel row degrades by CLAUSE.
310
+ *
311
+ * The row is 76 columns of independent clauses joined by ` · `. At 72 it
312
+ * used to lose the tail of the last one, so `t types` became `t`: the
313
+ * reader was told a key existed and not told what it did, on a row that
314
+ * still looked complete. Dropping a whole clause says less; it never
315
+ * says something false. `cutRow`'s ellipsis is the floor below this, for
316
+ * a width that cannot hold even the first clause.
317
+ */
318
+ function panelKeysRow(W) {
319
+ const clauses = PANEL_KEYS_ROW.split(" \u00b7 ");
320
+ for (let n = clauses.length; n > 1; n -= 1) {
321
+ const row = clauses.slice(0, n).join(" \u00b7 ");
322
+ if (displayWidth(row) <= W)
323
+ return row;
324
+ }
325
+ return clauses[0];
326
+ }
305
327
  /** One row, cut at the width — SGR-aware, the ellipsis after the reset
306
328
  * (the cutLine convention; duplicated here rather than imported so the
307
329
  * strings module keeps its no-components-dependency shape). */
308
330
  function cutRow(row, W) {
331
+ // DC-2: a cut is MARKED. This returned the surviving prefix with
332
+ // nothing to say it was a prefix, so a row that had lost its tail read
333
+ // as a whole row — the one thing the tree's own fold rule forbids
334
+ // ("the honest …, never a silent truncate"). The mark costs a column,
335
+ // so the cut lands one column earlier to pay for it.
336
+ if (displayWidth(row.replace(/\x1b\[[0-9;]*m/g, "")) <= W)
337
+ return row;
338
+ const limit = Math.max(0, W - 1);
309
339
  let out = "";
310
340
  let width = 0;
311
341
  for (let i = 0; i < row.length;) {
@@ -316,13 +346,13 @@ function cutRow(row, W) {
316
346
  continue;
317
347
  }
318
348
  const cw = displayWidth(row[i]);
319
- if (width + cw > W)
320
- return `${out}${palette().reset}`;
349
+ if (width + cw > limit)
350
+ break;
321
351
  out += row[i];
322
352
  width += cw;
323
353
  i += 1;
324
354
  }
325
- return out;
355
+ return `${out}${palette().reset}\u2026`;
326
356
  }
327
357
  /** TUI2-R1 (D) — the keys as ONE line, for /help. The same table the
328
358
  * sheet renders, joined — so the two can disagree only by deleting a
@@ -343,24 +373,38 @@ export function keysHelpRow() {
343
373
  */
344
374
  export function helpRows() {
345
375
  const p = palette();
346
- const cmd = (name, desc) => `${p.bold}${name}${p.reset} ${desc}`;
347
- return [
348
- cmd("/help", "print this list of commands"),
349
- cmd("/think", "show the last full thinking block"),
350
- cmd("/last", "show the most recent tool call's input and output"),
351
- cmd("/status", "show session id, event count, and context estimate"),
352
- cmd("/mode", "show the approval tier; /mode <name> switches (manual/default/accept-edits/plan/bypass)"),
353
- cmd("/model", "list model profiles; /model <name|provider/model> switches"),
354
- cmd("/compact", "summarize the older conversation to free context"),
355
- cmd("/clear", "start a fresh conversation (the old session stays resumable)"),
356
- cmd("/resume", "switch to another session; /resume <id> goes directly"),
357
- // TUI2-R1 (D): DELIBERATELY UNCHANGED. Deriving this sentence from
358
- // KEY_BINDINGS would be an improvement and it would also move an
359
- // assertion outside the round's two declared supersession classes,
360
- // so the sheet is the derived surface and this row keeps its bytes.
361
- // `keysHelpRow()` exists for the round that is allowed to make the
362
- // swap; until then the drift guard is the test that every binding
363
- // in the table is mentioned here.
364
- `${cmd("exit", "leave the session")}\n${cmd("keys", "enter sends · ctrl+J newline (shift+enter where encoded) · esc stops the run · alt+⏎ stops it and sends this instead · @ files · 1-4 answers an ask")}`,
376
+ // DC-1: ONE description column. The gap used to be four spaces after
377
+ // the name whatever the name's length, so `/help`'s description began
378
+ // three columns left of `/compact`'s and the second column wandered
379
+ // down the list. displayWidth is the authority, as everywhere else.
380
+ const table = [
381
+ ["/help", "print this list of commands"],
382
+ ["/think", "show the last full thinking block"],
383
+ ["/last", "show the most recent tool call's input and output"],
384
+ ["/status", "show session id, event count, and context estimate"],
385
+ ["/mode", "show the approval tier; /mode <name> switches (manual/default/accept-edits/plan/bypass)"],
386
+ ["/model", "list model profiles; /model <name|provider/model> switches"],
387
+ ["/compact", "summarize the older conversation to free context"],
388
+ ["/clear", "start a fresh conversation (the old session stays resumable)"],
389
+ ["/resume", "switch to another session; /resume <id> goes directly"],
390
+ ["exit", "leave the session"],
391
+ // TUI2-R1 (D): the SENTENCE is deliberately unchanged. Deriving it
392
+ // from KEY_BINDINGS would be an improvement and it would also move
393
+ // an assertion outside the round's declared supersession classes,
394
+ // so the sheet stays the derived surface and this row keeps its
395
+ // words. `keysHelpRow()` exists for the round allowed to swap it;
396
+ // until then the drift guard is the test that every binding in the
397
+ // table is mentioned here. DC-1 changes the PADDING, not the words.
398
+ ["keys", "enter sends \u00b7 ctrl+J newline (shift+enter where encoded) \u00b7 esc stops the run \u00b7 alt+\u23ce stops it and sends this instead \u00b7 @ files \u00b7 1-4 answers an ask"],
365
399
  ];
400
+ const stop = Math.max(...table.map(([name]) => displayWidth(name))) + 4;
401
+ const cmd = (name, desc) => `${p.bold}${name}${p.reset}${" ".repeat(stop - displayWidth(name))}${desc}`;
402
+ const rows = table.slice(0, -2).map(([name, desc]) => cmd(name, desc));
403
+ // the last call carries its own newline exactly as it did inline:
404
+ // bodyLog splits on \n, so `exit` and `keys` land as two rows from one
405
+ // call — the shape the KC1/KC2/KC3 gestures were added to, unchanged.
406
+ const [exitName, exitDesc] = table[table.length - 2];
407
+ const [keysName, keysDesc] = table[table.length - 1];
408
+ rows.push(`${cmd(exitName, exitDesc)}\n${cmd(keysName, keysDesc)}`);
409
+ return rows;
366
410
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-tui-cells",
3
- "version": "0.16.2",
4
- "description": "kiso tui-cells \u2014 the components cell renderer (components, diff, width, the render slice). Zero runtime dependencies: input is data, output is bytes.",
3
+ "version": "0.16.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",
7
7
  "exports": {