@xynogen/pix-runtime 0.17.1 → 0.17.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-runtime",
3
- "version": "0.17.1",
3
+ "version": "0.17.2",
4
4
  "description": "Pix shared runtime — versioned pix.json config, atomic persistence, typed change events",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -245,9 +245,10 @@ export function createBinariesTab(opts: BinariesTabOptions) {
245
245
 
246
246
  view(width: number): TabView {
247
247
  const nameW = Math.max(6, ...rows.map((r) => r.name.length));
248
+ const iconW = Math.max(2, ...Object.values(STATE_ICON).map((key) => visibleWidth(icon(key))));
248
249
  // Frame border + padding take 4 columns; every row must fit on one line.
249
250
  const inner = Math.max(20, width - 4);
250
- const lead = 2 + 2 + nameW + 2; // cursor, glyph, name, gap
251
+ const lead = 2 + iconW + 1 + nameW + 2; // cursor, glyph, name, gap
251
252
  const body: string[] = [];
252
253
  let selectedBodyLine: number | undefined;
253
254
  let otherHeader = false;
@@ -294,7 +295,7 @@ export function createBinariesTab(opts: BinariesTabOptions) {
294
295
  detail = theme.fg("muted", `not used on this OS · ${row.hint}`);
295
296
  }
296
297
  if (sel) selectedBodyLine = body.length;
297
- const line = `${cursor} ${glyph} ${name} ${detail}`;
298
+ const line = `${cursor} ${glyph}${" ".repeat(iconW - visibleWidth(glyph))} ${name} ${detail}`;
298
299
  body.push(visibleWidth(line) > inner ? truncateToWidth(line, inner, "…") : line);
299
300
  }
300
301
 
@@ -213,7 +213,27 @@ const SETTINGS: SettingRow<unknown>[] = [
213
213
  const part = key as keyof typeof prettySection.defaults.footer;
214
214
  return row({
215
215
  section: "Footer",
216
- label: part === "wrap" ? "wrap line" : part,
216
+ get label() {
217
+ const key = {
218
+ mode: "status.active",
219
+ cwd: "cwd",
220
+ git: "git.unstaged",
221
+ context: "tokens",
222
+ model: "model",
223
+ thinking: "agent",
224
+ score: "score",
225
+ statuses: "status.running",
226
+ tokens: "tokens",
227
+ cost: "data.float",
228
+ tps: "score",
229
+ system: "sys.cpu",
230
+ clock: "clock",
231
+ wrap: "turns",
232
+ } as const;
233
+ const glyph = icon(key[part]);
234
+ const iconW = Math.max(2, ...Object.values(key).map((key) => visibleWidth(icon(key))));
235
+ return `${glyph}${" ".repeat(iconW - visibleWidth(glyph))} ${part === "wrap" ? "wrap line" : part}`;
236
+ },
217
237
  handle: prettySection,
218
238
  values: part === "wrap" ? ["on", "off"] : ["show", "hide"],
219
239
  read: (v) =>
@@ -457,14 +477,20 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
457
477
  });
458
478
  return binaries;
459
479
  };
460
- const tabBar = () =>
461
- tabs
480
+ const tabBar = (width: number) => {
481
+ const full = tabs
462
482
  .map((name) =>
463
483
  name === tab
464
484
  ? theme.fg("accent", theme.bold(` ${name} `))
465
485
  : theme.fg("muted", ` ${name} `),
466
486
  )
467
487
  .join(theme.fg("muted", "│"));
488
+ if (visibleWidth(full) <= width) return full;
489
+ return (
490
+ theme.fg("accent", theme.bold(` ${tab} `)) +
491
+ theme.fg("muted", `${tabs.indexOf(tab) + 1}/${tabs.length}`)
492
+ );
493
+ };
468
494
  const switchTab = (direction: -1 | 1) => {
469
495
  const next = (tabs.indexOf(tab) + direction + tabs.length) % tabs.length;
470
496
  tab = tabs[next] ?? "Settings";
@@ -548,7 +574,7 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
548
574
  const hints = view.footer.map(([key, action]) => guide(key, action)).join(guideSep);
549
575
  const result = frameModal({
550
576
  ...frame,
551
- header: [tabBar(), "", ...view.header],
577
+ header: [tabBar(Math.max(1, width - 4)), "", ...view.header],
552
578
  body: view.body,
553
579
  footer: [
554
580
  "",
@@ -573,19 +599,26 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
573
599
  lines = embedded.render(width);
574
600
  }
575
601
  const panelWidth = visibleWidth(lines[0] ?? "");
576
- lines.splice(1, 0, ...frameRows(panelWidth, [tabBar()], frame).slice(1, -1));
602
+ lines.splice(
603
+ 1,
604
+ 0,
605
+ ...frameRows(panelWidth, [tabBar(Math.max(1, panelWidth - 4))], frame).slice(
606
+ 1,
607
+ -1,
608
+ ),
609
+ );
577
610
  return lines;
578
611
  }
579
612
  return frameModal({
580
613
  ...frame,
581
- header: [tabBar(), ""],
614
+ header: [tabBar(Math.max(1, width - 4)), ""],
582
615
  body: [theme.fg("dim", ` Loading ${tab} settings…`)],
583
616
  footer: ["", tabGuide + guideSep + guide("esc", "close")],
584
617
  bodyOffset: 0,
585
618
  }).lines;
586
619
  }
587
620
  const settings = rows();
588
- const labelW = Math.max(...settings.map((r) => r.label.length));
621
+ const labelW = Math.max(...settings.map((r) => visibleWidth(r.label)));
589
622
  const body: string[] = [];
590
623
  const settingBodyLines: number[] = [];
591
624
  let lastSection = "";
@@ -599,7 +632,10 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
599
632
  }
600
633
  const sel = i === selected;
601
634
  const cursor = sel ? theme.fg("accent", "→") : " ";
602
- const label = theme.fg(sel ? "accent" : "text", row.label.padEnd(labelW));
635
+ const label = theme.fg(
636
+ sel ? "accent" : "text",
637
+ row.label + " ".repeat(labelW - visibleWidth(row.label)),
638
+ );
603
639
  const value = isThemeRow(row) ? row.current() : row.read(runtime.get(row.handle));
604
640
  const isDefault = isThemeRow(row) || value === row.read(row.handle.defaults);
605
641
  settingBodyLines[i] = body.length;
@@ -607,7 +643,7 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
607
643
  }
608
644
  const result = frameModal({
609
645
  ...frame,
610
- header: [tabBar(), ""],
646
+ header: [tabBar(Math.max(1, width - 4)), ""],
611
647
  body,
612
648
  footer: [
613
649
  "",
@@ -782,7 +818,10 @@ function frameModal(opts: RuntimeModalOptions): RuntimeModalResult {
782
818
  const maxBodyOffset = Math.max(0, body.length - visibleBodyLines);
783
819
  let offset = Math.min(maxBodyOffset, Math.max(0, opts.bodyOffset));
784
820
  if (opts.selectedBodyLine !== undefined) {
785
- const selected = Math.min(body.length - 1, Math.max(0, opts.selectedBodyLine));
821
+ const selected = Math.min(
822
+ body.length - 1,
823
+ fitLines(opts.body.slice(0, Math.max(0, opts.selectedBodyLine)), inner).length,
824
+ );
786
825
  if (selected < offset) offset = selected;
787
826
  else if (selected >= offset + visibleBodyLines) offset = selected - visibleBodyLines + 1;
788
827
  }
@@ -26,7 +26,6 @@ export interface PrettyConfig {
26
26
  | "context"
27
27
  | "model"
28
28
  | "thinking"
29
- | "price"
30
29
  | "score"
31
30
  | "statuses"
32
31
  | "tokens"
@@ -68,7 +67,6 @@ const DEFAULTS: Readonly<PrettyConfig> = {
68
67
  context: true,
69
68
  model: true,
70
69
  thinking: true,
71
- price: true,
72
70
  score: true,
73
71
  statuses: true,
74
72
  tokens: true,