@gjermundgaraba/upup 0.2.0 → 0.3.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.
@@ -1,10 +1,46 @@
1
- import { a as describeOutcome, c as describeError, d as rowKey, i as questionOf, l as isAppUpdate, n as aboutKey, o as changedLines, r as auditKey, s as unauditable, t as Session, u as isVendorUpdate } from "./main.mjs";
1
+ import { a as describeOutcome, c as describeError, d as unauditedKind, i as questionOf, l as isUnauditedUpdate, n as aboutKey, o as changedLines, r as auditKey, s as unauditable, t as Session, u as rowKey } from "./main.mjs";
2
2
  import { Deferred, Effect, FiberSet, Stream } from "effect";
3
3
  import { spawn } from "node:child_process";
4
4
  import { homedir } from "node:os";
5
+ import semver from "semver";
5
6
  import { createComponent, createElement, createTextNode, effect, insert, insertNode, memo, render, setProp, use, useKeyboard, usePaste, useTerminalDimensions } from "@opentui/solid";
6
7
  import { TextAttributes, createCliRenderer } from "@opentui/core";
7
8
  import { For, Match, Show, Switch, createEffect, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack } from "solid-js/dist/solid.js";
9
+ // src/tui/text.ts
10
+ const segmenter = new Intl.Segmenter();
11
+ const graphemes = (text) => Array.from(segmenter.segment(text), ({ segment }) => segment);
12
+ const padded = (text, width, align = "start") => {
13
+ const room = " ".repeat(Math.max(0, width - graphemes(text).length));
14
+ return align === "end" ? `${room}${text}` : `${text}${room}`;
15
+ };
16
+ const cut = (chars, width) => {
17
+ if (chars.length <= width) return chars.join("");
18
+ if (width <= 0) return "";
19
+ return `${chars.slice(0, width - 1).join("")}…`;
20
+ };
21
+ const fit = (text, width, align = "start") => {
22
+ const shown = cut(graphemes(text.replaceAll(/\s+/gu, " ")), width);
23
+ return padded(shown, width, align);
24
+ };
25
+ const clip = (text, width) => graphemes(text).length <= width ? text : cut(graphemes(text.trimEnd()), width);
26
+ const fitName = (text, width) => {
27
+ const chars = graphemes(text);
28
+ if (chars.length <= width) return padded(text, width);
29
+ if (width <= 3) return fit(text, width);
30
+ const slash = chars.indexOf("/");
31
+ const base = chars.slice(slash + 1);
32
+ const scope = chars.slice(0, slash);
33
+ if (text.startsWith("@") && slash > 0 && base.length + 4 <= width) {
34
+ const keep = Math.min(scope.length, width - base.length - 2);
35
+ return padded(`${scope.slice(0, keep).join("")}…/${base.join("")}`, width);
36
+ }
37
+ const head = Math.ceil((width - 1) / 2);
38
+ const tail = width - 1 - head;
39
+ return `${chars.slice(0, head).join("")}…${chars.slice(chars.length - tail).join("")}`;
40
+ };
41
+ const plural = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
42
+ const capitalized = (text) => `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
43
+ const listed = (names) => names.length <= 3 ? names.join(", ") : `${names.slice(0, 3).join(", ")} and ${names.length - 3} more`;
8
44
  // src/tui/keys.ts
9
45
  const keys = {
10
46
  up: {
@@ -261,7 +297,7 @@ const describe = (key) => {
261
297
  return `${key.ctrl ? "ctrl+" : ""}${key.meta ? "meta+" : ""}${key.shift && !single ? "shift+" : ""}${name}`;
262
298
  };
263
299
  const matches = (binding, key) => binding.keys.includes(describe(key));
264
- const typed = (key) => !key.ctrl && !key.meta && [...key.sequence].length === 1 && key.sequence >= " " ? key.sequence : void 0;
300
+ const typed = (key) => !key.ctrl && !key.meta && graphemes(key.sequence).length === 1 && key.sequence >= " " ? key.sequence : void 0;
265
301
  const pasted = (bytes) => new TextDecoder().decode(bytes).replaceAll(/[\r\n]+/gu, "");
266
302
  // src/tui/theme.ts
267
303
  const dark = {
@@ -270,13 +306,12 @@ const dark = {
270
306
  accent: "#8aa9ff",
271
307
  onAccent: "#14161c",
272
308
  muted: "#9198a8",
273
- faint: "#7c8496",
274
309
  ok: "#8fd694",
275
310
  warn: "#f2c46d",
276
311
  danger: "#ff8a94",
277
312
  info: "#7dd3e8",
278
- cursor: "#2b3348",
279
- selected: "#1f2a3d",
313
+ cursor: "#262b3c",
314
+ selected: "#1e212c",
280
315
  surface: "#1c1f27",
281
316
  chip: "#2e3340",
282
317
  rule: "#3a3f4c",
@@ -288,13 +323,12 @@ const light = {
288
323
  accent: "#3657d6",
289
324
  onAccent: "#ffffff",
290
325
  muted: "#5f6878",
291
- faint: "#6f7787",
292
- ok: "#25803a",
293
- warn: "#a86a00",
326
+ ok: "#1f7033",
327
+ warn: "#8f5a00",
294
328
  danger: "#c8283c",
295
329
  info: "#0b7c99",
296
- cursor: "#dfe6fb",
297
- selected: "#edf1fd",
330
+ cursor: "#e7ebfa",
331
+ selected: "#f5f7fd",
298
332
  surface: "#f6f7fa",
299
333
  chip: "#e4e7ee",
300
334
  rule: "#d3d7e0",
@@ -333,8 +367,8 @@ const derive = (base, background) => {
333
367
  const lift = base === light ? "#000000" : "#ffffff";
334
368
  return {
335
369
  ...base,
336
- cursor: mix(background, base.accent, .22),
337
- selected: mix(background, base.accent, .1),
370
+ cursor: mix(background, base.accent, .12),
371
+ selected: mix(background, base.accent, .05),
338
372
  surface: mix(background, lift, .04),
339
373
  chip: mix(background, lift, .12),
340
374
  rule: mix(background, lift, .16)
@@ -371,9 +405,6 @@ const theme = {
371
405
  get muted() {
372
406
  return palette().muted;
373
407
  },
374
- get faint() {
375
- return palette().faint;
376
- },
377
408
  get ok() {
378
409
  return palette().ok;
379
410
  },
@@ -406,69 +437,65 @@ const theme = {
406
437
  // src/tui/Popup.tsx
407
438
  const separator = 2;
408
439
  const chip = (binding) => ` ${binding.hint ?? ""} `;
409
- const hintsWidth = (bindings) => bindings.reduce((width, binding, index) => width + (index === 0 ? 0 : separator) + [...chip(binding)].length + 1 + [...binding.description ?? ""].length, 0);
410
- function Key(props) {
411
- return (() => {
412
- var _el$ = createElement("text");
413
- setProp(_el$, "flexShrink", 0);
414
- insert(_el$, () => ` ${props.hint} `);
415
- effect((_p$) => {
416
- var _v$ = props.color ?? theme.strong, _v$2 = theme.chip, _v$3 = TextAttributes.BOLD;
417
- _v$ !== _p$.e && (_p$.e = setProp(_el$, "fg", _v$, _p$.e));
418
- _v$2 !== _p$.t && (_p$.t = setProp(_el$, "bg", _v$2, _p$.t));
419
- _v$3 !== _p$.a && (_p$.a = setProp(_el$, "attributes", _v$3, _p$.a));
420
- return _p$;
421
- }, {
422
- e: void 0,
423
- t: void 0,
424
- a: void 0
425
- });
426
- return _el$;
427
- })();
428
- }
429
- function Hints(props) {
430
- return (() => {
431
- var _el$2 = createElement("box");
432
- setProp(_el$2, "flexDirection", "row");
433
- setProp(_el$2, "flexShrink", 0);
434
- insert(_el$2, createComponent(For, {
435
- get each() {
436
- return props.bindings;
437
- },
438
- children: (binding, index) => (() => {
439
- var _el$3 = createElement("box"), _el$4 = createElement("text");
440
- insertNode(_el$3, _el$4);
441
- setProp(_el$3, "flexDirection", "row");
442
- setProp(_el$3, "flexShrink", 0);
443
- insert(_el$3, createComponent(Key, { get hint() {
444
- return binding.hint ?? "";
445
- } }), _el$4);
446
- setProp(_el$4, "flexShrink", 0);
447
- insert(_el$4, () => ` ${binding.description ?? ""}`);
448
- effect((_p$) => {
449
- var _v$6 = index() === 0 ? 0 : separator, _v$7 = theme.muted;
450
- _v$6 !== _p$.e && (_p$.e = setProp(_el$3, "marginLeft", _v$6, _p$.e));
451
- _v$7 !== _p$.t && (_p$.t = setProp(_el$4, "fg", _v$7, _p$.t));
452
- return _p$;
453
- }, {
454
- e: void 0,
455
- t: void 0
456
- });
457
- return _el$3;
458
- })()
459
- }));
460
- effect((_p$) => {
461
- var _v$4 = props.wrap === true ? "wrap" : "no-wrap", _v$5 = props.wrap === true ? "auto" : 1;
462
- _v$4 !== _p$.e && (_p$.e = setProp(_el$2, "flexWrap", _v$4, _p$.e));
463
- _v$5 !== _p$.t && (_p$.t = setProp(_el$2, "height", _v$5, _p$.t));
464
- return _p$;
465
- }, {
466
- e: void 0,
467
- t: void 0
468
- });
469
- return _el$2;
470
- })();
471
- }
440
+ const hintsWidth = (bindings) => bindings.reduce((width, binding, index) => width + (index === 0 ? 0 : separator) + graphemes(chip(binding)).length + 1 + graphemes(binding.description ?? "").length, 0);
441
+ const Key = (props) => (() => {
442
+ var _el$ = createElement("text");
443
+ setProp(_el$, "flexShrink", 0);
444
+ insert(_el$, () => ` ${props.hint} `);
445
+ effect((_p$) => {
446
+ var _v$ = props.color ?? theme.strong, _v$2 = theme.chip, _v$3 = TextAttributes.BOLD;
447
+ _v$ !== _p$.e && (_p$.e = setProp(_el$, "fg", _v$, _p$.e));
448
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$, "bg", _v$2, _p$.t));
449
+ _v$3 !== _p$.a && (_p$.a = setProp(_el$, "attributes", _v$3, _p$.a));
450
+ return _p$;
451
+ }, {
452
+ e: void 0,
453
+ t: void 0,
454
+ a: void 0
455
+ });
456
+ return _el$;
457
+ })();
458
+ const Hints = (props) => (() => {
459
+ var _el$2 = createElement("box");
460
+ setProp(_el$2, "flexDirection", "row");
461
+ setProp(_el$2, "flexShrink", 0);
462
+ insert(_el$2, createComponent(For, {
463
+ get each() {
464
+ return props.bindings;
465
+ },
466
+ children: (binding, index) => (() => {
467
+ var _el$3 = createElement("box"), _el$4 = createElement("text");
468
+ insertNode(_el$3, _el$4);
469
+ setProp(_el$3, "flexDirection", "row");
470
+ setProp(_el$3, "flexShrink", 0);
471
+ insert(_el$3, createComponent(Key, { get hint() {
472
+ return binding.hint ?? "";
473
+ } }), _el$4);
474
+ setProp(_el$4, "flexShrink", 0);
475
+ insert(_el$4, () => ` ${binding.description ?? ""}`);
476
+ effect((_p$) => {
477
+ var _v$6 = index() === 0 ? 0 : separator, _v$7 = theme.muted;
478
+ _v$6 !== _p$.e && (_p$.e = setProp(_el$3, "marginLeft", _v$6, _p$.e));
479
+ _v$7 !== _p$.t && (_p$.t = setProp(_el$4, "fg", _v$7, _p$.t));
480
+ return _p$;
481
+ }, {
482
+ e: void 0,
483
+ t: void 0
484
+ });
485
+ return _el$3;
486
+ })()
487
+ }));
488
+ effect((_p$) => {
489
+ var _v$4 = props.wrap === true ? "wrap" : "no-wrap", _v$5 = props.wrap === true ? "auto" : 1;
490
+ _v$4 !== _p$.e && (_p$.e = setProp(_el$2, "flexWrap", _v$4, _p$.e));
491
+ _v$5 !== _p$.t && (_p$.t = setProp(_el$2, "height", _v$5, _p$.t));
492
+ return _p$;
493
+ }, {
494
+ e: void 0,
495
+ t: void 0
496
+ });
497
+ return _el$2;
498
+ })();
472
499
  const toneColor = (tone) => {
473
500
  switch (tone) {
474
501
  case "accent": return theme.accent;
@@ -477,12 +504,31 @@ const toneColor = (tone) => {
477
504
  case "quiet": return theme.muted;
478
505
  }
479
506
  };
480
- function Popup(props) {
507
+ const useCompact = () => {
508
+ const dimensions = useTerminalDimensions();
509
+ return () => dimensions().height < 20;
510
+ };
511
+ const frame = 6;
512
+ const popupWidth = (wanted, terminal) => Math.min(wanted, terminal - 4);
513
+ const bodyWidth = (wanted, terminal) => popupWidth(wanted, terminal) - frame;
514
+ const scrollHint = {
515
+ keys: [],
516
+ hint: "↑↓",
517
+ description: "scroll"
518
+ };
519
+ const Popup = (props) => {
481
520
  const dimensions = useTerminalDimensions();
482
- const width = () => Math.min(props.width ?? 64, dimensions().width - 4);
521
+ const compact = useCompact();
522
+ const width = () => popupWidth(props.width ?? 64, dimensions().width);
483
523
  const color = () => toneColor(props.tone ?? "accent");
524
+ let body;
525
+ useKeyboard((key) => {
526
+ if (props.scrolls !== true) return;
527
+ if (matches(keys.down, key)) body?.scrollBy(1);
528
+ else if (matches(keys.up, key)) body?.scrollBy(-1);
529
+ });
484
530
  return (() => {
485
- var _el$5 = createElement("box"), _el$6 = createElement("box"), _el$7 = createElement("box"), _el$8 = createElement("text"), _el$9 = createElement("text"), _el$1 = createElement("text");
531
+ var _el$5 = createElement("box"), _el$6 = createElement("box"), _el$7 = createElement("box"), _el$8 = createElement("text"), _el$9 = createElement("text"), _el$1 = createElement("scrollbox"), _el$10 = createElement("text");
486
532
  insertNode(_el$5, _el$6);
487
533
  setProp(_el$5, "position", "absolute");
488
534
  setProp(_el$5, "zIndex", 10);
@@ -500,6 +546,7 @@ function Popup(props) {
500
546
  insertNode(_el$7, _el$8);
501
547
  insertNode(_el$7, _el$9);
502
548
  insertNode(_el$7, _el$1);
549
+ insertNode(_el$7, _el$10);
503
550
  setProp(_el$7, "flexShrink", 1);
504
551
  setProp(_el$7, "overflow", "hidden");
505
552
  setProp(_el$7, "flexDirection", "column");
@@ -507,27 +554,36 @@ function Popup(props) {
507
554
  setProp(_el$7, "borderStyle", "rounded");
508
555
  setProp(_el$7, "paddingLeft", 2);
509
556
  setProp(_el$7, "paddingRight", 2);
510
- setProp(_el$7, "paddingTop", 1);
557
+ setProp(_el$8, "flexShrink", 0);
511
558
  insert(_el$8, () => props.title);
512
559
  insertNode(_el$9, createTextNode(` `));
513
- insert(_el$7, () => props.children, _el$1);
514
- insertNode(_el$1, createTextNode(` `));
560
+ setProp(_el$9, "flexShrink", 0);
561
+ use((box) => {
562
+ body = box;
563
+ }, _el$1);
564
+ setProp(_el$1, "flexShrink", 1);
565
+ setProp(_el$1, "minHeight", 1);
566
+ setProp(_el$1, "contentOptions", { minHeight: 0 });
567
+ insert(_el$1, () => props.children);
568
+ insertNode(_el$10, createTextNode(` `));
569
+ setProp(_el$10, "flexShrink", 0);
515
570
  insert(_el$7, createComponent(Hints, {
516
571
  get bindings() {
517
- return props.bindings;
572
+ return memo(() => props.scrolls === true)() ? [scrollHint, ...props.bindings] : props.bindings;
518
573
  },
519
574
  wrap: true
520
575
  }), null);
521
576
  effect((_p$) => {
522
- var _v$8 = width() + 2, _v$9 = dimensions().height, _v$0 = theme.surface, _v$1 = width(), _v$10 = color(), _v$11 = theme.surface, _v$12 = props.tone === "quiet" ? theme.strong : color(), _v$13 = TextAttributes.BOLD;
577
+ var _v$8 = width() + 2, _v$9 = theme.surface, _v$0 = width(), _v$1 = dimensions().height, _v$10 = color(), _v$11 = theme.surface, _v$12 = compact() ? 0 : 1, _v$13 = props.tone === "quiet" ? theme.strong : color(), _v$14 = TextAttributes.BOLD;
523
578
  _v$8 !== _p$.e && (_p$.e = setProp(_el$6, "width", _v$8, _p$.e));
524
- _v$9 !== _p$.t && (_p$.t = setProp(_el$6, "maxHeight", _v$9, _p$.t));
525
- _v$0 !== _p$.a && (_p$.a = setProp(_el$6, "backgroundColor", _v$0, _p$.a));
526
- _v$1 !== _p$.o && (_p$.o = setProp(_el$7, "width", _v$1, _p$.o));
579
+ _v$9 !== _p$.t && (_p$.t = setProp(_el$6, "backgroundColor", _v$9, _p$.t));
580
+ _v$0 !== _p$.a && (_p$.a = setProp(_el$7, "width", _v$0, _p$.a));
581
+ _v$1 !== _p$.o && (_p$.o = setProp(_el$7, "maxHeight", _v$1, _p$.o));
527
582
  _v$10 !== _p$.i && (_p$.i = setProp(_el$7, "borderColor", _v$10, _p$.i));
528
583
  _v$11 !== _p$.n && (_p$.n = setProp(_el$7, "backgroundColor", _v$11, _p$.n));
529
- _v$12 !== _p$.s && (_p$.s = setProp(_el$8, "fg", _v$12, _p$.s));
530
- _v$13 !== _p$.h && (_p$.h = setProp(_el$8, "attributes", _v$13, _p$.h));
584
+ _v$12 !== _p$.s && (_p$.s = setProp(_el$7, "paddingTop", _v$12, _p$.s));
585
+ _v$13 !== _p$.h && (_p$.h = setProp(_el$8, "fg", _v$13, _p$.h));
586
+ _v$14 !== _p$.r && (_p$.r = setProp(_el$8, "attributes", _v$14, _p$.r));
531
587
  return _p$;
532
588
  }, {
533
589
  e: void 0,
@@ -537,11 +593,12 @@ function Popup(props) {
537
593
  i: void 0,
538
594
  n: void 0,
539
595
  s: void 0,
540
- h: void 0
596
+ h: void 0,
597
+ r: void 0
541
598
  });
542
599
  return _el$5;
543
600
  })();
544
- }
601
+ };
545
602
  // src/tui/Spinner.tsx
546
603
  const frames = [
547
604
  "⠋",
@@ -555,10 +612,14 @@ const frames = [
555
612
  "⠇",
556
613
  "⠏"
557
614
  ];
558
- function Spinner(props) {
615
+ const Spinner = (props) => {
559
616
  const [frame, setFrame] = createSignal(0);
560
- const timer = setInterval(() => setFrame((at) => (at + 1) % frames.length), 80);
561
- onCleanup(() => clearInterval(timer));
617
+ const timer = setInterval(() => {
618
+ setFrame((at) => (at + 1) % frames.length);
619
+ }, 80);
620
+ onCleanup(() => {
621
+ clearInterval(timer);
622
+ });
562
623
  return (() => {
563
624
  var _el$ = createElement("text");
564
625
  setProp(_el$, "flexShrink", 0);
@@ -566,24 +627,31 @@ function Spinner(props) {
566
627
  effect((_$p) => setProp(_el$, "fg", props.color ?? theme.accent, _$p));
567
628
  return _el$;
568
629
  })();
569
- }
630
+ };
570
631
  // src/tui/Changes.tsx
571
632
  const shownLines = 2e3;
572
633
  const diffHead = "changes-diff-head";
573
- const areas = {
574
- to: "Package",
575
- "payload-to": "Payload",
576
- "wheel-to": "Wheel",
577
- source: "Source",
578
- "repo-to": "Source repository",
579
- "go-source-to": "Go source",
580
- "dependencies-to": "Dependencies"
581
- };
634
+ const areas = /* @__PURE__ */ new Map([
635
+ ["to", "Package"],
636
+ ["payload-to", "Payload"],
637
+ ["wheel-to", "Wheel"],
638
+ ["source", "Source"],
639
+ ["repo-to", "Source repository"],
640
+ ["go-source-to", "Go source"],
641
+ ["dependencies-to", "Dependencies"]
642
+ ]);
582
643
  const metadata = "Package metadata";
583
644
  const generated = "Generated";
584
- const isGenerated = (path) => path.endsWith(".map") || /\.min\.(js|css)$/u.test(path) || /(^|\/)chunk-[\w-]*\d[\w-]*\.\w+$/u.test(path) || /(^|\/)(dist|build|out)\//u.test(path);
585
- const areaOf = (section) => isGenerated(section.path) ? generated : section.tree === "" ? metadata : areas[section.tree] ?? section.tree;
586
- const rank = (area) => area === generated ? 2 : area === metadata ? 1 : 0;
645
+ const isGenerated = (path) => path.endsWith(".map") || /\.min\.(?:js|css)$/u.test(path) || /(?:^|\/)chunk-[\w-]*\d[\w-]*\.\w+$/u.test(path) || /(?:^|\/)(?:dist|build|out)\//u.test(path);
646
+ const areaOf = (section) => {
647
+ if (isGenerated(section.path)) return generated;
648
+ if (section.tree === "") return metadata;
649
+ return areas.get(section.tree) ?? section.tree;
650
+ };
651
+ const rank = (area) => {
652
+ if (area === generated) return 2;
653
+ return area === metadata ? 1 : 0;
654
+ };
587
655
  const files = (view) => view.sections.map((section) => ({
588
656
  section,
589
657
  area: areaOf(section),
@@ -624,11 +692,15 @@ const grades = {
624
692
  color: () => theme.muted
625
693
  }
626
694
  };
627
- const lineColor = (line) => line.startsWith("+") ? theme.ok : line.startsWith("-") ? theme.danger : line.startsWith("@@") ? theme.info : theme.muted;
695
+ const lineColor = (line) => {
696
+ if (line.startsWith("+")) return theme.ok;
697
+ if (line.startsWith("-")) return theme.danger;
698
+ return line.startsWith("@@") ? theme.info : theme.muted;
699
+ };
628
700
  const endings = (from, to) => {
629
701
  const left = from.split("/");
630
702
  const right = to.split("/");
631
- for (let count = 2; count < Math.max(left.length, right.length); count++) {
703
+ for (let count = 2; count < Math.max(left.length, right.length); count += 1) {
632
704
  const ours = left.slice(-count).join("/");
633
705
  const theirs = right.slice(-count).join("/");
634
706
  if (ours !== theirs) return [ours, theirs];
@@ -636,18 +708,23 @@ const endings = (from, to) => {
636
708
  return [from, to];
637
709
  };
638
710
  const flags = (section) => [section.binary ? "binary" : "", section.longLine ? "long lines" : ""].filter(Boolean).join(", ");
639
- function Diff(props) {
711
+ const Diff = (props) => {
640
712
  const list = createMemo(() => files(props.view));
641
713
  const current = createMemo(() => list()[Math.min(props.at, list().length - 1)]);
642
714
  const at = (file) => file.section === current()?.section;
643
715
  const next = () => list()[Math.min(props.at, list().length - 1) + 1];
644
- const totals = () => list().reduce((sum, file) => ({
645
- added: sum.added + file.added,
646
- removed: sum.removed + file.removed
647
- }), {
648
- added: 0,
649
- removed: 0
650
- });
716
+ const totals = () => {
717
+ let added = 0;
718
+ let removed = 0;
719
+ for (const file of list()) {
720
+ added += file.added;
721
+ removed += file.removed;
722
+ }
723
+ return {
724
+ added,
725
+ removed
726
+ };
727
+ };
651
728
  const width = () => Math.max(3, ...list().flatMap((file) => [`${file.added}`.length, `${file.removed}`.length])) + 1;
652
729
  const grouped = () => {
653
730
  const byArea = /* @__PURE__ */ new Map();
@@ -764,6 +841,10 @@ function Diff(props) {
764
841
  children: ([area, entries]) => {
765
842
  const folded = () => area === generated && !entries.some(at);
766
843
  const window = () => around(entries, entries.findIndex(at));
844
+ const foldMark = () => {
845
+ if (area !== generated) return "";
846
+ return folded() ? "▸ " : "▾ ";
847
+ };
767
848
  return (() => {
768
849
  var _el$22 = createElement("box"), _el$23 = createElement("box"), _el$24 = createElement("text"), _el$25 = createElement("text");
769
850
  insertNode(_el$22, _el$23);
@@ -774,7 +855,7 @@ function Diff(props) {
774
855
  setProp(_el$23, "flexDirection", "row");
775
856
  setProp(_el$23, "height", 1);
776
857
  setProp(_el$24, "flexShrink", 0);
777
- insert(_el$24, () => `${area === generated ? folded() ? "▸ " : "▾ " : ""}${area}`);
858
+ insert(_el$24, () => `${foldMark()}${area}`);
778
859
  setProp(_el$25, "flexShrink", 0);
779
860
  insert(_el$25, () => ` ${entries.length}`);
780
861
  insert(_el$23, createComponent(Show, {
@@ -801,7 +882,7 @@ function Diff(props) {
801
882
  var _el$28 = createElement("text");
802
883
  insertNode(_el$28, createTextNode(` build output, maps and hashed chunks`));
803
884
  setProp(_el$28, "flexShrink", 0);
804
- effect((_$p) => setProp(_el$28, "fg", theme.faint, _$p));
885
+ effect((_$p) => setProp(_el$28, "fg", theme.muted, _$p));
805
886
  return _el$28;
806
887
  })()
807
888
  ];
@@ -820,7 +901,7 @@ function Diff(props) {
820
901
  get children() {
821
902
  var _el$30 = createElement("text");
822
903
  insert(_el$30, () => ` … ${window().before} earlier`);
823
- effect((_$p) => setProp(_el$30, "fg", theme.faint, _$p));
904
+ effect((_$p) => setProp(_el$30, "fg", theme.muted, _$p));
824
905
  return _el$30;
825
906
  }
826
907
  }),
@@ -883,7 +964,7 @@ function Diff(props) {
883
964
  get children() {
884
965
  var _el$31 = createElement("text");
885
966
  insert(_el$31, () => ` … ${window().after} more · n/p step through them`);
886
- effect((_$p) => setProp(_el$31, "fg", theme.faint, _$p));
967
+ effect((_$p) => setProp(_el$31, "fg", theme.muted, _$p));
887
968
  return _el$31;
888
969
  }
889
970
  })
@@ -891,7 +972,7 @@ function Diff(props) {
891
972
  }
892
973
  }), null);
893
974
  effect((_p$) => {
894
- var _v$0 = theme.muted, _v$1 = TextAttributes.BOLD, _v$10 = theme.faint;
975
+ var _v$0 = theme.muted, _v$1 = TextAttributes.BOLD, _v$10 = theme.muted;
895
976
  _v$0 !== _p$.e && (_p$.e = setProp(_el$24, "fg", _v$0, _p$.e));
896
977
  _v$1 !== _p$.t && (_p$.t = setProp(_el$24, "attributes", _v$1, _p$.t));
897
978
  _v$10 !== _p$.a && (_p$.a = setProp(_el$25, "fg", _v$10, _p$.a));
@@ -989,7 +1070,7 @@ function Diff(props) {
989
1070
  return () => _c$() ? " previous file (this is the last)" : ` next: ${endings(file().section.path, next()?.section.path ?? "")[1]}`;
990
1071
  })());
991
1072
  effect((_p$) => {
992
- var _v$16 = theme.faint, _v$17 = theme.muted;
1073
+ var _v$16 = theme.muted, _v$17 = theme.muted;
993
1074
  _v$16 !== _p$.e && (_p$.e = setProp(_el$50, "fg", _v$16, _p$.e));
994
1075
  _v$17 !== _p$.t && (_p$.t = setProp(_el$51, "fg", _v$17, _p$.t));
995
1076
  return _p$;
@@ -1046,8 +1127,8 @@ function Diff(props) {
1046
1127
  });
1047
1128
  return _el$;
1048
1129
  })();
1049
- }
1050
- function Changes(props) {
1130
+ };
1131
+ const Changes = (props) => {
1051
1132
  const ready = () => props.loaded?._tag === "Ready" ? props.loaded.value : void 0;
1052
1133
  const unavailable = () => props.loaded?._tag === "Unavailable" ? props.loaded.issue : void 0;
1053
1134
  return createComponent(Switch, {
@@ -1058,56 +1139,56 @@ function Changes(props) {
1058
1139
  },
1059
1140
  get fallback() {
1060
1141
  return (() => {
1061
- var _el$59 = createElement("box"), _el$60 = createElement("text");
1062
- insertNode(_el$59, _el$60);
1063
- setProp(_el$59, "flexDirection", "column");
1064
- setProp(_el$60, "wrapMode", "word");
1065
- insert(_el$60, () => `Nothing to compare: ${props.unauditable ?? ""}.`);
1066
- insert(_el$59, createComponent(Show, {
1142
+ var _el$60 = createElement("box"), _el$61 = createElement("text");
1143
+ insertNode(_el$60, _el$61);
1144
+ setProp(_el$60, "flexDirection", "column");
1145
+ setProp(_el$61, "wrapMode", "word");
1146
+ insert(_el$61, () => `Nothing to compare: ${props.unauditable ?? ""}.`);
1147
+ insert(_el$60, createComponent(Show, {
1067
1148
  get when() {
1068
1149
  return props.notes;
1069
1150
  },
1070
1151
  children: (notes) => [
1071
1152
  (() => {
1072
- var _el$61 = createElement("text");
1073
- insertNode(_el$61, createTextNode(` `));
1074
- return _el$61;
1153
+ var _el$62 = createElement("text");
1154
+ insertNode(_el$62, createTextNode(` `));
1155
+ return _el$62;
1075
1156
  })(),
1076
1157
  (() => {
1077
- var _el$63 = createElement("text");
1078
- insertNode(_el$63, createTextNode(`Release notes`));
1158
+ var _el$64 = createElement("text");
1159
+ insertNode(_el$64, createTextNode(`Release notes`));
1079
1160
  effect((_p$) => {
1080
1161
  var _v$21 = theme.muted, _v$22 = TextAttributes.BOLD;
1081
- _v$21 !== _p$.e && (_p$.e = setProp(_el$63, "fg", _v$21, _p$.e));
1082
- _v$22 !== _p$.t && (_p$.t = setProp(_el$63, "attributes", _v$22, _p$.t));
1162
+ _v$21 !== _p$.e && (_p$.e = setProp(_el$64, "fg", _v$21, _p$.e));
1163
+ _v$22 !== _p$.t && (_p$.t = setProp(_el$64, "attributes", _v$22, _p$.t));
1083
1164
  return _p$;
1084
1165
  }, {
1085
1166
  e: void 0,
1086
1167
  t: void 0
1087
1168
  });
1088
- return _el$63;
1169
+ return _el$64;
1089
1170
  })(),
1090
1171
  (() => {
1091
- var _el$65 = createElement("text");
1092
- setProp(_el$65, "wrapMode", "word");
1093
- insert(_el$65, notes);
1094
- return _el$65;
1172
+ var _el$66 = createElement("text");
1173
+ setProp(_el$66, "wrapMode", "word");
1174
+ insert(_el$66, notes);
1175
+ return _el$66;
1095
1176
  })()
1096
1177
  ]
1097
1178
  }), null);
1098
- effect((_$p) => setProp(_el$60, "fg", theme.muted, _$p));
1099
- return _el$59;
1179
+ effect((_$p) => setProp(_el$61, "fg", theme.muted, _$p));
1180
+ return _el$60;
1100
1181
  })();
1101
1182
  },
1102
1183
  get children() {
1103
- var _el$56 = createElement("box"), _el$57 = createElement("text");
1104
- insertNode(_el$56, _el$57);
1105
- setProp(_el$56, "flexDirection", "row");
1106
- setProp(_el$56, "height", 1);
1107
- insert(_el$56, createComponent(Spinner, {}), _el$57);
1108
- insertNode(_el$57, createTextNode(` Preparing the comparison…`));
1109
- effect((_$p) => setProp(_el$57, "fg", theme.muted, _$p));
1110
- return _el$56;
1184
+ var _el$57 = createElement("box"), _el$58 = createElement("text");
1185
+ insertNode(_el$57, _el$58);
1186
+ setProp(_el$57, "flexDirection", "row");
1187
+ setProp(_el$57, "height", 1);
1188
+ insert(_el$57, createComponent(Spinner, {}), _el$58);
1189
+ insertNode(_el$58, createTextNode(` Preparing the comparison…`));
1190
+ effect((_$p) => setProp(_el$58, "fg", theme.muted, _$p));
1191
+ return _el$57;
1111
1192
  }
1112
1193
  });
1113
1194
  },
@@ -1118,12 +1199,12 @@ function Changes(props) {
1118
1199
  return props.loaded?._tag === "Loading";
1119
1200
  },
1120
1201
  get children() {
1121
- var _el$53 = createElement("box"), _el$54 = createElement("text");
1202
+ var _el$53 = createElement("box"), _el$54 = createElement("text"), _el$55 = createTextNode(` Downloading, verifying and comparing both versions…`);
1122
1203
  insertNode(_el$53, _el$54);
1123
1204
  setProp(_el$53, "flexDirection", "row");
1124
1205
  setProp(_el$53, "height", 1);
1125
1206
  insert(_el$53, createComponent(Spinner, {}), _el$54);
1126
- insertNode(_el$54, createTextNode(` Downloading, verifying and comparing both versions…`));
1207
+ insertNode(_el$54, _el$55);
1127
1208
  effect((_$p) => setProp(_el$54, "fg", theme.muted, _$p));
1128
1209
  return _el$53;
1129
1210
  }
@@ -1133,11 +1214,11 @@ function Changes(props) {
1133
1214
  return unavailable();
1134
1215
  },
1135
1216
  children: (issue) => (() => {
1136
- var _el$66 = createElement("text");
1137
- setProp(_el$66, "wrapMode", "word");
1138
- insert(_el$66, () => `✗ Changes unavailable: ${issue()}`);
1139
- effect((_$p) => setProp(_el$66, "fg", theme.danger, _$p));
1140
- return _el$66;
1217
+ var _el$67 = createElement("text");
1218
+ setProp(_el$67, "wrapMode", "word");
1219
+ insert(_el$67, () => `✗ Changes unavailable: ${issue()}`);
1220
+ effect((_$p) => setProp(_el$67, "fg", theme.danger, _$p));
1221
+ return _el$67;
1141
1222
  })()
1142
1223
  }),
1143
1224
  createComponent(Match, {
@@ -1156,10 +1237,60 @@ function Changes(props) {
1156
1237
  ];
1157
1238
  }
1158
1239
  });
1159
- }
1240
+ };
1241
+ // src/tui/Segments.tsx
1242
+ const segment = (color, text, bold = false) => ({
1243
+ text,
1244
+ color,
1245
+ bold
1246
+ });
1247
+ const Segments = (props) => (() => {
1248
+ var _el$ = createElement("box");
1249
+ setProp(_el$, "flexDirection", "row");
1250
+ setProp(_el$, "height", 1);
1251
+ insert(_el$, createComponent(For, {
1252
+ get each() {
1253
+ return props.segments.filter((part) => part.text !== "");
1254
+ },
1255
+ children: (part) => (() => {
1256
+ var _el$2 = createElement("text");
1257
+ setProp(_el$2, "flexShrink", 0);
1258
+ setProp(_el$2, "wrapMode", "none");
1259
+ insert(_el$2, () => part.text);
1260
+ effect((_p$) => {
1261
+ var _v$ = part.color, _v$2 = part.bold === true ? TextAttributes.BOLD : TextAttributes.NONE;
1262
+ _v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
1263
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$2, "attributes", _v$2, _p$.t));
1264
+ return _p$;
1265
+ }, {
1266
+ e: void 0,
1267
+ t: void 0
1268
+ });
1269
+ return _el$2;
1270
+ })()
1271
+ }));
1272
+ effect((_$p) => setProp(_el$, "backgroundColor", props.background ?? theme.none, _$p));
1273
+ return _el$;
1274
+ })();
1160
1275
  // src/tui/view.ts
1161
1276
  const visibleRows = (group) => group.collapsed === true ? group.kept ?? [] : group.rows;
1162
1277
  const byName = (left, right) => left.pkg.name.localeCompare(right.pkg.name) || left.pkg.provider.localeCompare(right.pkg.provider);
1278
+ const providerLabels = /* @__PURE__ */ new Map([
1279
+ ["brew", "Homebrew"],
1280
+ ["npm-global", "npm -g"],
1281
+ ["pnpm-global", "pnpm -g"],
1282
+ ["vp-global", "Vite+ global"],
1283
+ ["vp-self", "Vite+"],
1284
+ ["cargo-install", "cargo install"],
1285
+ ["go-install", "go install"],
1286
+ ["uv-tool", "uv tool"],
1287
+ ["softwareupdate", "Software Update"],
1288
+ ["apps", "Apps"],
1289
+ ["github-actions", "GitHub Actions"],
1290
+ ["node-not-listed", "Node"],
1291
+ ["node-pins", "Node.js"]
1292
+ ]);
1293
+ const providerLabel = (provider) => providerLabels.get(provider) ?? provider;
1163
1294
  const providedBy = (provider, needle) => needle.length >= 2 && `${provider} ${providerLabel(provider)}`.toLowerCase().split(/[^a-z0-9+]+/u).some((word) => word.startsWith(needle));
1164
1295
  const groups = (state, filter) => {
1165
1296
  const needle = filter.toLowerCase();
@@ -1207,39 +1338,51 @@ const lines = (grouped) => {
1207
1338
  _tag: "Heading",
1208
1339
  group
1209
1340
  },
1210
- ...visibleRows(group).map((row) => ({
1211
- _tag: "Package",
1212
- row,
1213
- index: index++
1214
- }))
1341
+ ...visibleRows(group).map((row) => {
1342
+ const line = {
1343
+ _tag: "Package",
1344
+ row,
1345
+ index
1346
+ };
1347
+ index += 1;
1348
+ return line;
1349
+ })
1215
1350
  ]);
1216
1351
  };
1217
1352
  const reachable = (grouped) => grouped.flatMap(visibleRows);
1218
- const providerLabels = {
1219
- brew: "Homebrew",
1220
- "npm-global": "npm -g",
1221
- "pnpm-global": "pnpm -g",
1222
- "vp-global": "Vite+ global",
1223
- "vp-self": "Vite+",
1224
- "cargo-install": "cargo install",
1225
- "go-install": "go install",
1226
- "uv-tool": "uv tool",
1227
- softwareupdate: "Software Update",
1228
- "github-actions": "GitHub Actions"
1353
+ const unauditedLabels = {
1354
+ app: "app update",
1355
+ runtime: "runtime pin",
1356
+ os: "OS update"
1229
1357
  };
1230
- const providerLabel = (provider) => providerLabels[provider] ?? provider;
1231
- const parts = (version) => version.replace(/^v/u, "").split(/([._+-])/u);
1232
- const bump = (current, target) => {
1358
+ const parts = (version) => version.replace(/^v/u, "").split(/(?<separator>[._+-])/u);
1359
+ const semverPrerelease = (version) => semver.prerelease(version) !== null;
1360
+ const prereleases = {
1361
+ npm: semverPrerelease,
1362
+ crates: semverPrerelease,
1363
+ go: semverPrerelease,
1364
+ "github-actions": semverPrerelease,
1365
+ node: semverPrerelease,
1366
+ pypi: (version) => /\d(?:[-_.]?(?:a|b|c|rc|alpha|beta|pre|preview)\d*|[-_.]?dev\d*)(?:$|[+.-])/iu.test(version)
1367
+ };
1368
+ const bump = (current, target, ecosystem) => {
1233
1369
  const from = parts(current);
1234
1370
  const to = parts(target);
1235
1371
  let at = 0;
1236
- while (at < to.length && from[at] === to[at]) at++;
1372
+ while (at < to.length && from[at] === to[at]) at += 1;
1237
1373
  const prefix = target.startsWith("v") && current.startsWith("v") ? 1 : 0;
1238
1374
  const shared = to.slice(0, at);
1239
1375
  const same = target.slice(0, prefix + shared.join("").length);
1240
1376
  const changed = target.slice(same.length);
1241
1377
  const numbers = to.filter((_, index) => index % 2 === 0);
1242
- if (!(numbers.length >= 2 && numbers.slice(0, 3).every((part) => /^\d+$/u.test(part)))) return {
1378
+ const plain = numbers.length >= 2 && numbers.slice(0, 3).every((part) => /^\d+$/u.test(part));
1379
+ if (prereleases[ecosystem]?.(current) === true) return {
1380
+ kind: "prerelease",
1381
+ risk: "major",
1382
+ same,
1383
+ changed
1384
+ };
1385
+ if (!plain) return {
1243
1386
  kind: "other",
1244
1387
  risk: "other",
1245
1388
  same,
@@ -1260,8 +1403,16 @@ const bump = (current, target) => {
1260
1403
  changed
1261
1404
  };
1262
1405
  };
1263
- const bumpLabel = (change) => change.kind === "other" ? "" : change.risk === change.kind ? change.kind : `0.x ${change.kind}`;
1264
- const bumpTone = (change) => change.risk === "major" ? theme.strong : change.kind === "patch" ? theme.muted : theme.text;
1406
+ const bumpLabel = (change) => {
1407
+ if (change.kind === "other") return "";
1408
+ if (change.kind === "prerelease" || change.risk === change.kind) return change.kind;
1409
+ return `0.x ${change.kind}`;
1410
+ };
1411
+ const bumpTone = (change) => {
1412
+ if (change.risk === "major") return theme.strong;
1413
+ if (change.kind === "patch") return theme.muted;
1414
+ return theme.text;
1415
+ };
1265
1416
  const window = (count, height, focus, offset) => {
1266
1417
  const page = Math.max(1, height);
1267
1418
  const bottom = Math.max(Math.min(offset, focus), focus - page + 1);
@@ -1323,7 +1474,9 @@ const outcomeIcon = (outcome) => {
1323
1474
  case "Completed": return "✓";
1324
1475
  case "Failed":
1325
1476
  case "Unexpected": return "✗";
1326
- default: return "·";
1477
+ case "Excluded":
1478
+ case "NotStarted":
1479
+ case "Stale": return "·";
1327
1480
  }
1328
1481
  };
1329
1482
  const outcomeColor = (outcome) => {
@@ -1331,7 +1484,9 @@ const outcomeColor = (outcome) => {
1331
1484
  case "Completed": return theme.ok;
1332
1485
  case "Failed":
1333
1486
  case "Unexpected": return theme.danger;
1334
- default: return theme.warn;
1487
+ case "Excluded":
1488
+ case "NotStarted":
1489
+ case "Stale": return theme.warn;
1335
1490
  }
1336
1491
  };
1337
1492
  const verdictIcons = {
@@ -1356,7 +1511,7 @@ const status = (state, row) => {
1356
1511
  const outcome = state.outcomes[row.key];
1357
1512
  if (state.removed[row.key] !== void 0) return {
1358
1513
  text: "– removed",
1359
- color: theme.faint
1514
+ color: theme.muted
1360
1515
  };
1361
1516
  if (outcome !== void 0 && (audit === void 0 || ran.has(outcome._tag))) {
1362
1517
  if (outcome._tag === "Completed" && auditedAs(state, row.pkg) !== row.pkg) {
@@ -1382,18 +1537,12 @@ const status = (state, row) => {
1382
1537
  };
1383
1538
  if (row.pkg.target === void 0 || state.recalling) return {
1384
1539
  text: "",
1385
- color: theme.faint
1540
+ color: theme.muted
1386
1541
  };
1387
- if (isAppUpdate(row.pkg)) return {
1388
- text: "app update",
1389
- color: theme.faint
1390
- };
1391
- if (isVendorUpdate(row.pkg)) return row.pkg.restart === true ? {
1392
- text: "OS · restarts",
1393
- color: theme.faint
1394
- } : {
1395
- text: "OS update",
1396
- color: theme.faint
1542
+ const kind = unauditedKind(row.pkg);
1543
+ if (kind !== void 0) return {
1544
+ text: kind === "os" && row.pkg.restart === true ? "OS · restarts" : unauditedLabels[kind],
1545
+ color: theme.muted
1397
1546
  };
1398
1547
  if (majorsOf(state, row.pkg).length > 0) return {
1399
1548
  text: breakingMark,
@@ -1401,7 +1550,7 @@ const status = (state, row) => {
1401
1550
  };
1402
1551
  return {
1403
1552
  text: "not audited",
1404
- color: theme.faint
1553
+ color: theme.muted
1405
1554
  };
1406
1555
  }
1407
1556
  if (audit._tag === "Running") return {
@@ -1413,22 +1562,321 @@ const status = (state, row) => {
1413
1562
  text: "✗ audit failed",
1414
1563
  color: theme.danger
1415
1564
  };
1416
- const verdict = audit.result.report.verdict;
1565
+ const { verdict } = audit.result.report;
1417
1566
  const installed = auditedAs(state, row.pkg) !== row.pkg;
1418
1567
  return {
1419
1568
  text: `${verdictIcons[verdict]} ${installed ? "installed" : verdictLabels[verdict]}`,
1420
1569
  color: verdictColor(verdict)
1421
1570
  };
1422
1571
  };
1423
- const fit = (text, width) => {
1424
- const chars = [...text.replaceAll(/\s+/gu, " ")];
1425
- if (chars.length <= width) return chars.join("").padEnd(width);
1426
- return width <= 1 ? "…".slice(0, width) : `${chars.slice(0, width - 1).join("")}…`;
1427
- };
1428
1572
  const modelLabel = (state, provider, modelId) => {
1429
1573
  const choice = state.catalogue?._tag === "Ready" ? state.catalogue.value.find((entry) => entry.provider === provider && entry.modelId === modelId) : void 0;
1430
1574
  return choice === void 0 ? `${provider}/${modelId}` : `${choice.providerName} · ${choice.name}`;
1431
1575
  };
1576
+ // src/tui/Confirm.tsx
1577
+ const confirmations = {
1578
+ update: {
1579
+ verb: "Update",
1580
+ done: "updated"
1581
+ },
1582
+ uninstall: {
1583
+ verb: "Remove",
1584
+ done: "removed"
1585
+ },
1586
+ audit: {
1587
+ verb: "Audit",
1588
+ done: "audited"
1589
+ }
1590
+ };
1591
+ const flaggedFirst = (pending) => {
1592
+ const flagged = new Set(pending.flagged.map((entry) => entry.row.key));
1593
+ return [...pending.rows.filter((row) => flagged.has(row.key)), ...pending.rows.filter((row) => !flagged.has(row.key))];
1594
+ };
1595
+ const markOf = (pending, row) => {
1596
+ const verdict = pending.flagged.find((entry) => entry.row.key === row.key)?.verdict;
1597
+ const mixed = pending.unaudited.length > 0 && pending.unaudited.length < pending.rows.length;
1598
+ if (verdict === void 0 && pending.unauditable.includes(row.key)) {
1599
+ const restarts = pending.action === "update" && row.pkg.restart === true;
1600
+ return {
1601
+ text: `${unauditedLabels[unauditedKind(row.pkg) ?? "os"]}${restarts ? " · restarts" : ""} · not audited`,
1602
+ color: restarts ? theme.warn : theme.muted
1603
+ };
1604
+ }
1605
+ if (verdict === void 0) {
1606
+ if (pending.action === "update" && !pending.unaudited.includes(row.key)) return {
1607
+ text: `${verdictIcons.ok} ${verdictLabels.ok}`,
1608
+ color: theme.ok
1609
+ };
1610
+ const unread = pending.action === "update" && pending.unaudited.includes(row.key) && (mixed || !pending.auditFirst);
1611
+ if (pending.action === "update" && pending.breaking.includes(row.key)) return {
1612
+ text: `${breakingMark}${unread ? " · not audited" : ""}`,
1613
+ color: theme.warn
1614
+ };
1615
+ return unread ? {
1616
+ text: "not audited",
1617
+ color: theme.muted
1618
+ } : void 0;
1619
+ }
1620
+ if (verdict === "failed") return {
1621
+ text: "✗ audit failed",
1622
+ color: theme.danger
1623
+ };
1624
+ return {
1625
+ text: `${verdictIcons[verdict]} ${verdictLabels[verdict]}`,
1626
+ color: verdictColor(verdict)
1627
+ };
1628
+ };
1629
+ const flaggedSentence = (flagged) => {
1630
+ const only = flagged.length === 1 ? flagged[0] : void 0;
1631
+ if (only !== void 0) return only.verdict === "failed" ? `! ${only.row.pkg.name}'s audit did not complete, so it was not reviewed. Confirming installs it anyway.` : `! ${only.row.pkg.name} was audited: ${verdictLabels[only.verdict]}${only.top === void 0 ? "" : ` (${only.top})`}. Confirming installs it anyway.`;
1632
+ const failed = flagged.filter((entry) => entry.verdict === "failed").length;
1633
+ const reviewed = flagged.length - failed;
1634
+ return `! Of these, ${[...reviewed > 0 ? [`${reviewed} ${reviewed === 1 ? "has" : "have"} an audit warning`] : [], ...failed > 0 ? [`${failed} could not be audited`] : []].join(" and ")}. Confirming installs them anyway.`;
1635
+ };
1636
+ const tone = (pending) => {
1637
+ if (pending.action === "uninstall") return "danger";
1638
+ if (pending.flagged.some((entry) => entry.verdict === "danger")) return "danger";
1639
+ return pending.flagged.length > 0 ? "warn" : "accent";
1640
+ };
1641
+ const signedOut = (state) => {
1642
+ const { setup } = state.preferences;
1643
+ const { catalogue } = state;
1644
+ if (setup === void 0 || catalogue?._tag !== "Ready") return;
1645
+ const choice = catalogue.value.find((entry) => entry.provider === setup.provider && entry.modelId === setup.modelId);
1646
+ return choice === void 0 || choice.signedIn ? void 0 : choice.providerName;
1647
+ };
1648
+ const signIn$1 = {
1649
+ keys: [",", "return"],
1650
+ hint: ",/Enter",
1651
+ description: "sign in"
1652
+ };
1653
+ const widest$1 = (texts) => Math.max(0, ...texts.map((text) => graphemes(text).length));
1654
+ const wantedWidth = 90;
1655
+ const ConfirmPopup = (props) => {
1656
+ const dimensions = useTerminalDimensions();
1657
+ const compact = useCompact();
1658
+ const pending = () => props.pending;
1659
+ const removing = () => pending().action === "uninstall";
1660
+ const unsigned = () => pending().action === "audit" || pending().action === "update" && props.state.preferences.auditFirst && pending().unauditable.length < pending().rows.length ? signedOut(props.state) : void 0;
1661
+ const confirmKey = () => {
1662
+ const verb = confirmations[pending().action].verb.toLowerCase();
1663
+ if (removing()) return keys.confirmRemove;
1664
+ if (unsigned() !== void 0 || pending().flagged.length > 0) return {
1665
+ keys: ["y"],
1666
+ hint: "y",
1667
+ description: `${verb} anyway`
1668
+ };
1669
+ return {
1670
+ ...keys.confirm,
1671
+ hint: "y/Enter",
1672
+ description: verb
1673
+ };
1674
+ };
1675
+ const version = (row) => removing() ? row.pkg.current : `→ ${row.pkg.target ?? ""}`;
1676
+ const layout = createMemo(() => {
1677
+ const rows = flaggedFirst(pending());
1678
+ const marks = rows.map((row) => markOf(pending(), row));
1679
+ const versions = Math.min(16, widest$1(rows.map(version)));
1680
+ const verdicts = widest$1(marks.map((mark) => mark?.text ?? ""));
1681
+ const longest = widest$1(rows.map((row) => row.pkg.name));
1682
+ const width = Math.max(64, Math.min(8 + longest + 2 + versions + 2 + verdicts, wantedWidth));
1683
+ const inner = bodyWidth(width, dimensions().width) - 1;
1684
+ const name = Math.max(Math.min(longest, 12), Math.min(longest, inner - 6 - versions - verdicts));
1685
+ return {
1686
+ width,
1687
+ lines: rows.map((row, at) => ({
1688
+ row,
1689
+ version: fit(version(row), versions),
1690
+ mark: marks[at],
1691
+ room: inner - 6 - name - versions
1692
+ })),
1693
+ name
1694
+ };
1695
+ });
1696
+ useKeyboard((key) => {
1697
+ if (unsigned() !== void 0 && matches(signIn$1, key)) props.signIn();
1698
+ else if (matches(confirmKey(), key)) props.confirm();
1699
+ else if (matches(keys.cancel, key)) props.cancel();
1700
+ });
1701
+ const body = () => bodyWidth(layout().width, dimensions().width);
1702
+ const providers = () => [...new Set(pending().rows.map((row) => providerLabel(row.pkg.provider)))].join(", ");
1703
+ const explains = () => !compact();
1704
+ return createComponent(Popup, {
1705
+ get title() {
1706
+ return `${confirmations[pending().action].verb} ${plural(pending().rows.length, "package")}?`;
1707
+ },
1708
+ get width() {
1709
+ return layout().width;
1710
+ },
1711
+ get tone() {
1712
+ return tone(pending());
1713
+ },
1714
+ get bindings() {
1715
+ return [
1716
+ ...unsigned() === void 0 ? [] : [signIn$1],
1717
+ confirmKey(),
1718
+ keys.cancel
1719
+ ];
1720
+ },
1721
+ scrolls: true,
1722
+ get children() {
1723
+ return [
1724
+ (() => {
1725
+ var _el$ = createElement("text");
1726
+ setProp(_el$, "wrapMode", "none");
1727
+ insert(_el$, () => clip(pending().action === "audit" ? `${props.where} · read-only, nothing will be installed` : `${props.where} · ${providers()}`, body()));
1728
+ effect((_$p) => setProp(_el$, "fg", theme.muted, _$p));
1729
+ return _el$;
1730
+ })(),
1731
+ createComponent(Show, {
1732
+ get when() {
1733
+ return pending().skipped > 0;
1734
+ },
1735
+ get children() {
1736
+ var _el$2 = createElement("text");
1737
+ setProp(_el$2, "wrapMode", "word");
1738
+ insert(_el$2, () => `${pending().skipped} selected ${pending().skipped === 1 ? "package has" : "packages have"} no update and ${pending().skipped === 1 ? "is" : "are"} left out.`);
1739
+ effect((_$p) => setProp(_el$2, "fg", theme.muted, _$p));
1740
+ return _el$2;
1741
+ }
1742
+ }),
1743
+ createComponent(For, {
1744
+ get each() {
1745
+ return pending().refused;
1746
+ },
1747
+ children: (group) => (() => {
1748
+ var _el$10 = createElement("text");
1749
+ setProp(_el$10, "wrapMode", "word");
1750
+ insert(_el$10, () => `! Left out: ${listed(group.names)}. ${capitalized(group.reason)}.`);
1751
+ effect((_$p) => setProp(_el$10, "fg", theme.warn, _$p));
1752
+ return _el$10;
1753
+ })()
1754
+ }),
1755
+ (() => {
1756
+ var _el$3 = createElement("text");
1757
+ insertNode(_el$3, createTextNode(` `));
1758
+ return _el$3;
1759
+ })(),
1760
+ createComponent(Show, {
1761
+ get when() {
1762
+ return memo(() => !!(explains() && pending().action === "update" && props.state.preferences.auditFirst))() && pending().flagged.length + pending().unauditable.length < pending().rows.length;
1763
+ },
1764
+ get children() {
1765
+ var _el$5 = createElement("text");
1766
+ setProp(_el$5, "wrapMode", "word");
1767
+ insert(_el$5, () => pending().flagged.length === 0 && pending().unauditable.length === 0 ? "Each is audited first, and only those the audit finds ok are applied." : "The rest are audited first, and only those the audit finds ok are applied.");
1768
+ effect((_$p) => setProp(_el$5, "fg", theme.muted, _$p));
1769
+ return _el$5;
1770
+ }
1771
+ }),
1772
+ createComponent(Show, {
1773
+ get when() {
1774
+ return memo(() => !!(explains() && pending().action === "update"))() && pending().unauditable.length > 0;
1775
+ },
1776
+ get children() {
1777
+ var _el$6 = createElement("text");
1778
+ setProp(_el$6, "wrapMode", "word");
1779
+ insert(_el$6, () => pending().rows.some((row) => unauditedKind(row.pkg) === "runtime") ? "upup does not audit the runtime versions a project pins: confirming moves them as offered." : "upup does not audit operating-system or app updates: confirming installs them as the vendor offers them, and upup asks for your password if sudo needs it.");
1780
+ effect((_$p) => setProp(_el$6, "fg", theme.muted, _$p));
1781
+ return _el$6;
1782
+ }
1783
+ }),
1784
+ createComponent(Show, {
1785
+ get when() {
1786
+ return pending().flagged.length > 0;
1787
+ },
1788
+ get children() {
1789
+ var _el$7 = createElement("text");
1790
+ setProp(_el$7, "wrapMode", "word");
1791
+ insert(_el$7, () => flaggedSentence(pending().flagged));
1792
+ effect((_$p) => setProp(_el$7, "fg", theme.warn, _$p));
1793
+ return _el$7;
1794
+ }
1795
+ }),
1796
+ createComponent(Show, {
1797
+ get when() {
1798
+ return unsigned();
1799
+ },
1800
+ children: (provider) => (() => {
1801
+ var _el$11 = createElement("text");
1802
+ setProp(_el$11, "wrapMode", "word");
1803
+ setProp(_el$11, "marginBottom", 1);
1804
+ insert(_el$11, () => `! upup is not signed in to ${provider()}, so no model can read this. Press Enter to sign in.`);
1805
+ effect((_$p) => setProp(_el$11, "fg", theme.warn, _$p));
1806
+ return _el$11;
1807
+ })()
1808
+ }),
1809
+ createComponent(Show, {
1810
+ get when() {
1811
+ return pending().action === "audit";
1812
+ },
1813
+ get children() {
1814
+ return [createComponent(Show, {
1815
+ get when() {
1816
+ return explains();
1817
+ },
1818
+ get children() {
1819
+ var _el$8 = createElement("text");
1820
+ insertNode(_el$8, createTextNode(`Both versions are downloaded and verified, and the model reads what changed.`));
1821
+ setProp(_el$8, "wrapMode", "word");
1822
+ effect((_$p) => setProp(_el$8, "fg", theme.muted, _$p));
1823
+ return _el$8;
1824
+ }
1825
+ }), createComponent(Show, {
1826
+ get when() {
1827
+ return props.state.preferences.setup;
1828
+ },
1829
+ children: (setup) => (() => {
1830
+ var _el$12 = createElement("box"), _el$13 = createElement("text"), _el$15 = createElement("text");
1831
+ insertNode(_el$12, _el$13);
1832
+ insertNode(_el$12, _el$15);
1833
+ setProp(_el$12, "flexDirection", "row");
1834
+ setProp(_el$12, "height", 1);
1835
+ setProp(_el$12, "marginTop", 1);
1836
+ insertNode(_el$13, createTextNode(`Model `));
1837
+ setProp(_el$13, "flexShrink", 0);
1838
+ setProp(_el$15, "flexShrink", 0);
1839
+ insert(_el$15, () => clip(`${modelLabel(props.state, setup().provider, setup().modelId)} · ${setup().thinking} thinking`, body() - 7));
1840
+ effect((_p$) => {
1841
+ var _v$ = theme.muted, _v$2 = theme.text;
1842
+ _v$ !== _p$.e && (_p$.e = setProp(_el$13, "fg", _v$, _p$.e));
1843
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$15, "fg", _v$2, _p$.t));
1844
+ return _p$;
1845
+ }, {
1846
+ e: void 0,
1847
+ t: void 0
1848
+ });
1849
+ return _el$12;
1850
+ })()
1851
+ })];
1852
+ }
1853
+ }),
1854
+ createComponent(Show, {
1855
+ get when() {
1856
+ return pending().flagged.length > 0 || pending().action === "audit" || explains() && pending().action === "update" && (props.state.preferences.auditFirst || pending().unauditable.length > 0);
1857
+ },
1858
+ get children() {
1859
+ var _el$0 = createElement("text");
1860
+ insertNode(_el$0, createTextNode(` `));
1861
+ return _el$0;
1862
+ }
1863
+ }),
1864
+ createComponent(For, {
1865
+ get each() {
1866
+ return layout().lines;
1867
+ },
1868
+ children: (line) => createComponent(Segments, { get segments() {
1869
+ return [
1870
+ segment(theme.text, ` ${fitName(line.row.pkg.name, layout().name)}`),
1871
+ segment(theme.strong, ` ${line.version}`),
1872
+ ...line.mark === void 0 ? [] : [segment(line.mark.color, ` ${clip(line.mark.text, line.room)}`)]
1873
+ ];
1874
+ } })
1875
+ })
1876
+ ];
1877
+ }
1878
+ });
1879
+ };
1432
1880
  // src/tui/Report.tsx
1433
1881
  const severityColor = (severity) => {
1434
1882
  switch (severity) {
@@ -1453,75 +1901,69 @@ const stages = {
1453
1901
  preparing: "Downloading and verifying the published artifacts…",
1454
1902
  auditing: "The model is reading the evidence. Its steps are on the Transcript tab."
1455
1903
  };
1456
- function Heading$1(props) {
1457
- return (() => {
1458
- var _el$ = createElement("text");
1459
- insert(_el$, () => props.children);
1460
- effect((_p$) => {
1461
- var _v$ = theme.muted, _v$2 = TextAttributes.BOLD;
1462
- _v$ !== _p$.e && (_p$.e = setProp(_el$, "fg", _v$, _p$.e));
1463
- _v$2 !== _p$.t && (_p$.t = setProp(_el$, "attributes", _v$2, _p$.t));
1464
- return _p$;
1465
- }, {
1466
- e: void 0,
1467
- t: void 0
1468
- });
1469
- return _el$;
1470
- })();
1471
- }
1472
- const pieces = (text) => text.split(/(`[^`\n]+`)/u).map((piece) => piece.startsWith("`") && piece.endsWith("`") && piece.length > 2 ? {
1904
+ const Heading$1 = (props) => (() => {
1905
+ var _el$ = createElement("text");
1906
+ insert(_el$, () => props.children);
1907
+ effect((_p$) => {
1908
+ var _v$ = theme.muted, _v$2 = TextAttributes.BOLD;
1909
+ _v$ !== _p$.e && (_p$.e = setProp(_el$, "fg", _v$, _p$.e));
1910
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$, "attributes", _v$2, _p$.t));
1911
+ return _p$;
1912
+ }, {
1913
+ e: void 0,
1914
+ t: void 0
1915
+ });
1916
+ return _el$;
1917
+ })();
1918
+ const pieces = (text) => text.split(/(?<code>`[^`\n]+`)/u).map((piece) => piece.startsWith("`") && piece.endsWith("`") && piece.length > 2 ? {
1473
1919
  code: true,
1474
1920
  text: piece.slice(1, -1)
1475
1921
  } : {
1476
1922
  code: false,
1477
1923
  text: piece
1478
1924
  });
1479
- function Prose(props) {
1480
- return (() => {
1481
- var _el$2 = createElement("text");
1482
- setProp(_el$2, "wrapMode", "word");
1483
- insert(_el$2, createComponent(For, {
1484
- get each() {
1485
- return pieces(props.children);
1486
- },
1487
- children: (piece) => piece.code ? (() => {
1488
- var _el$3 = createElement("span");
1489
- use((node) => {
1490
- createRenderEffect(() => {
1491
- node.fg = theme.info;
1492
- });
1493
- }, _el$3);
1494
- insert(_el$3, () => piece.text);
1495
- return _el$3;
1496
- })() : piece.text
1497
- }));
1498
- effect((_$p) => setProp(_el$2, "fg", props.color ?? theme.text, _$p));
1499
- return _el$2;
1500
- })();
1501
- }
1502
- function Bullet(props) {
1503
- return (() => {
1504
- var _el$4 = createElement("box"), _el$5 = createElement("text"), _el$7 = createElement("box");
1505
- insertNode(_el$4, _el$5);
1506
- insertNode(_el$4, _el$7);
1507
- setProp(_el$4, "flexDirection", "row");
1508
- insertNode(_el$5, createTextNode(`• `));
1509
- setProp(_el$5, "flexShrink", 0);
1510
- setProp(_el$7, "flexGrow", 1);
1511
- setProp(_el$7, "flexShrink", 1);
1512
- insert(_el$7, createComponent(Prose, {
1513
- get color() {
1514
- return props.color;
1515
- },
1516
- get children() {
1517
- return props.children;
1518
- }
1519
- }));
1520
- effect((_$p) => setProp(_el$5, "fg", theme.faint, _$p));
1521
- return _el$4;
1522
- })();
1523
- }
1524
- function Done(props) {
1925
+ const Prose = (props) => (() => {
1926
+ var _el$2 = createElement("text");
1927
+ setProp(_el$2, "wrapMode", "word");
1928
+ insert(_el$2, createComponent(For, {
1929
+ get each() {
1930
+ return pieces(props.children);
1931
+ },
1932
+ children: (piece) => piece.code ? (() => {
1933
+ var _el$3 = createElement("span");
1934
+ use((node) => {
1935
+ createRenderEffect(() => {
1936
+ node.fg = theme.info;
1937
+ });
1938
+ }, _el$3);
1939
+ insert(_el$3, () => piece.text);
1940
+ return _el$3;
1941
+ })() : piece.text
1942
+ }));
1943
+ effect((_$p) => setProp(_el$2, "fg", props.color ?? theme.text, _$p));
1944
+ return _el$2;
1945
+ })();
1946
+ const Bullet = (props) => (() => {
1947
+ var _el$4 = createElement("box"), _el$5 = createElement("text"), _el$7 = createElement("box");
1948
+ insertNode(_el$4, _el$5);
1949
+ insertNode(_el$4, _el$7);
1950
+ setProp(_el$4, "flexDirection", "row");
1951
+ insertNode(_el$5, createTextNode(`• `));
1952
+ setProp(_el$5, "flexShrink", 0);
1953
+ setProp(_el$7, "flexGrow", 1);
1954
+ setProp(_el$7, "flexShrink", 1);
1955
+ insert(_el$7, createComponent(Prose, {
1956
+ get color() {
1957
+ return props.color;
1958
+ },
1959
+ get children() {
1960
+ return props.children;
1961
+ }
1962
+ }));
1963
+ effect((_$p) => setProp(_el$5, "fg", theme.muted, _$p));
1964
+ return _el$4;
1965
+ })();
1966
+ const Done = (props) => {
1525
1967
  const report = () => props.result.report;
1526
1968
  return (() => {
1527
1969
  var _el$8 = createElement("box"), _el$9 = createElement("box"), _el$0 = createElement("text"), _el$1 = createElement("text"), _el$10 = createElement("text"), _el$12 = createElement("text"), _el$16 = createElement("text"), _el$18 = createElement("box"), _el$19 = createElement("text");
@@ -1692,9 +2134,9 @@ function Done(props) {
1692
2134
  });
1693
2135
  return _el$8;
1694
2136
  })();
1695
- }
2137
+ };
1696
2138
  const signIn = (issue) => /not configured|sign[ -]?in|log ?in|api key|unauthori[sz]ed|credential|\b401\b|\b403\b/iu.test(issue);
1697
- function Report(props) {
2139
+ const Report = (props) => {
1698
2140
  const running = () => props.audit?._tag === "Running" ? props.audit : void 0;
1699
2141
  const result = () => props.audit?._tag === "Done" ? props.audit.result : void 0;
1700
2142
  const reported = () => {
@@ -1705,6 +2147,11 @@ function Report(props) {
1705
2147
  const done = result();
1706
2148
  return done?._tag === "Failed" ? done : void 0;
1707
2149
  };
2150
+ const unaudited = () => {
2151
+ if (props.unauditable !== void 0) return `Nothing to audit: ${props.unauditable}.`;
2152
+ if (props.installed === true) return "This update was installed without an audit, so there is no report.";
2153
+ return "Not audited yet. Press r to have a model review this update.";
2154
+ };
1708
2155
  return createComponent(Switch, {
1709
2156
  get fallback() {
1710
2157
  return createComponent(Prose, {
@@ -1712,7 +2159,7 @@ function Report(props) {
1712
2159
  return theme.muted;
1713
2160
  },
1714
2161
  get children() {
1715
- return memo(() => props.unauditable !== void 0)() ? `Nothing to audit: ${props.unauditable}.` : props.installed === true ? "This update was installed without an audit, so there is no report." : "Not audited yet. Press r to have a model review this update.";
2162
+ return unaudited();
1716
2163
  }
1717
2164
  });
1718
2165
  },
@@ -1796,7 +2243,7 @@ function Report(props) {
1796
2243
  ];
1797
2244
  }
1798
2245
  });
1799
- }
2246
+ };
1800
2247
  // src/tui/Transcript.tsx
1801
2248
  const color = (kind) => {
1802
2249
  switch (kind) {
@@ -1807,9 +2254,9 @@ const color = (kind) => {
1807
2254
  case "retry": return theme.warn;
1808
2255
  }
1809
2256
  };
1810
- const heading = /^\*\*(.+?)\*\*\s*/u;
1811
- function Thought(props) {
1812
- const title = () => heading.exec(props.text.trim())?.[1];
2257
+ const heading = /^\*\*(?<title>.+?)\*\*\s*/u;
2258
+ const Thought = (props) => {
2259
+ const title = () => heading.exec(props.text.trim())?.groups?.["title"];
1813
2260
  const body = () => props.text.trim().replace(heading, "").replaceAll("**", "").trim();
1814
2261
  return (() => {
1815
2262
  var _el$ = createElement("box");
@@ -1857,12 +2304,12 @@ function Thought(props) {
1857
2304
  effect((_$p) => setProp(_el$, "marginTop", title() === void 0 ? 0 : 1, _$p));
1858
2305
  return _el$;
1859
2306
  })();
1860
- }
1861
- function Tool(props) {
2307
+ };
2308
+ const Tool = (props) => {
1862
2309
  const space = () => props.text.indexOf(" ");
1863
2310
  const verb = () => space() < 0 ? props.text : props.text.slice(0, space());
1864
2311
  const rest = () => space() < 0 ? "" : props.text.slice(space() + 1);
1865
- const range = () => /^(.*?)(\s+bytes \S+)$/u.exec(rest());
2312
+ const range = () => /^(?<path>.*?)(?<bytes>\s+bytes \S+)$/u.exec(rest());
1866
2313
  return createComponent(Show, {
1867
2314
  get when() {
1868
2315
  return verb() !== "submit_report";
@@ -1894,7 +2341,7 @@ function Tool(props) {
1894
2341
  insert(_el$5, () => verb().padEnd(8));
1895
2342
  setProp(_el$6, "flexShrink", 1);
1896
2343
  setProp(_el$6, "wrapMode", "char");
1897
- insert(_el$6, () => range()?.[1] ?? rest());
2344
+ insert(_el$6, () => range()?.groups?.["path"] ?? rest());
1898
2345
  insert(_el$4, createComponent(Show, {
1899
2346
  get when() {
1900
2347
  return range();
@@ -1902,7 +2349,7 @@ function Tool(props) {
1902
2349
  children: (found) => (() => {
1903
2350
  var _el$0 = createElement("text");
1904
2351
  setProp(_el$0, "flexShrink", 0);
1905
- insert(_el$0, () => found()[2]);
2352
+ insert(_el$0, () => found().groups?.["bytes"]);
1906
2353
  effect((_$p) => setProp(_el$0, "fg", theme.muted, _$p));
1907
2354
  return _el$0;
1908
2355
  })()
@@ -1931,46 +2378,48 @@ function Tool(props) {
1931
2378
  return _el$4;
1932
2379
  }
1933
2380
  });
1934
- }
1935
- const runs = (entries) => entries.reduce((list, entry) => {
1936
- const last = list.at(-1);
1937
- if (last !== void 0 && entry.kind === "tool" && last.entry.kind === "tool" && last.entry.text === entry.text) {
1938
- last.times += 1;
1939
- return list;
2381
+ };
2382
+ const runs = (entries) => {
2383
+ const list = [];
2384
+ for (const entry of entries) {
2385
+ const last = list.at(-1);
2386
+ if (last !== void 0 && entry.kind === "tool" && last.entry.kind === "tool" && last.entry.text === entry.text) {
2387
+ last.times += 1;
2388
+ continue;
2389
+ }
2390
+ list.push({
2391
+ entry,
2392
+ times: 1
2393
+ });
1940
2394
  }
1941
- return [...list, {
1942
- entry,
1943
- times: 1
1944
- }];
1945
- }, []);
1946
- function Lines(props) {
1947
- return (() => {
1948
- var _el$1 = createElement("box");
1949
- setProp(_el$1, "flexDirection", "column");
1950
- insert(_el$1, createComponent(For, {
1951
- get each() {
1952
- return runs(props.entries);
2395
+ return list;
2396
+ };
2397
+ const Lines = (props) => (() => {
2398
+ var _el$1 = createElement("box");
2399
+ setProp(_el$1, "flexDirection", "column");
2400
+ insert(_el$1, createComponent(For, {
2401
+ get each() {
2402
+ return runs(props.entries);
2403
+ },
2404
+ children: (run) => run.entry.kind === "tool" ? createComponent(Tool, {
2405
+ get text() {
2406
+ return run.entry.text;
1953
2407
  },
1954
- children: (run) => run.entry.kind === "tool" ? createComponent(Tool, {
1955
- get text() {
1956
- return run.entry.text;
1957
- },
1958
- get times() {
1959
- return run.times;
1960
- }
1961
- }) : createComponent(Thought, {
1962
- get text() {
1963
- return run.entry.text;
1964
- },
1965
- get kind() {
1966
- return run.entry.kind;
1967
- }
1968
- })
1969
- }));
1970
- return _el$1;
1971
- })();
1972
- }
1973
- function Transcript(props) {
2408
+ get times() {
2409
+ return run.times;
2410
+ }
2411
+ }) : createComponent(Thought, {
2412
+ get text() {
2413
+ return run.entry.text;
2414
+ },
2415
+ get kind() {
2416
+ return run.entry.kind;
2417
+ }
2418
+ })
2419
+ }));
2420
+ return _el$1;
2421
+ })();
2422
+ const Transcript = (props) => {
1974
2423
  const ready = () => props.stored?._tag === "Ready" ? props.stored.value : void 0;
1975
2424
  const unavailable = () => props.stored?._tag === "Unavailable" ? props.stored.issue : void 0;
1976
2425
  return createComponent(Switch, {
@@ -2006,19 +2455,19 @@ function Transcript(props) {
2006
2455
  },
2007
2456
  get fallback() {
2008
2457
  return (() => {
2009
- var _el$21 = createElement("text");
2010
- insertNode(_el$21, createTextNode(`✗ The audit failed before the model started.`));
2011
- effect((_$p) => setProp(_el$21, "fg", theme.danger, _$p));
2012
- return _el$21;
2458
+ var _el$22 = createElement("text");
2459
+ insertNode(_el$22, createTextNode(`✗ The audit failed before the model started.`));
2460
+ effect((_$p) => setProp(_el$22, "fg", theme.danger, _$p));
2461
+ return _el$22;
2013
2462
  })();
2014
2463
  },
2015
2464
  get children() {
2016
- var _el$18 = createElement("box"), _el$19 = createElement("text");
2465
+ var _el$18 = createElement("box"), _el$19 = createElement("text"), _el$20 = createTextNode(` Preparing the evidence; the model starts next…`);
2017
2466
  insertNode(_el$18, _el$19);
2018
2467
  setProp(_el$18, "flexDirection", "row");
2019
2468
  setProp(_el$18, "height", 1);
2020
2469
  insert(_el$18, createComponent(Spinner, {}), _el$19);
2021
- insertNode(_el$19, createTextNode(` Preparing the evidence; the model starts next…`));
2470
+ insertNode(_el$19, _el$20);
2022
2471
  effect((_$p) => setProp(_el$19, "fg", theme.muted, _$p));
2023
2472
  return _el$18;
2024
2473
  }
@@ -2068,11 +2517,11 @@ function Transcript(props) {
2068
2517
  return unavailable();
2069
2518
  },
2070
2519
  children: (issue) => (() => {
2071
- var _el$23 = createElement("text");
2072
- setProp(_el$23, "wrapMode", "word");
2073
- insert(_el$23, () => `Transcript unavailable: ${issue()}`);
2074
- effect((_$p) => setProp(_el$23, "fg", theme.faint, _$p));
2075
- return _el$23;
2520
+ var _el$24 = createElement("text");
2521
+ setProp(_el$24, "wrapMode", "word");
2522
+ insert(_el$24, () => `Transcript unavailable: ${issue()}`);
2523
+ effect((_$p) => setProp(_el$24, "fg", theme.muted, _$p));
2524
+ return _el$24;
2076
2525
  })()
2077
2526
  }),
2078
2527
  createComponent(Match, {
@@ -2086,43 +2535,41 @@ function Transcript(props) {
2086
2535
  ];
2087
2536
  }
2088
2537
  });
2089
- }
2538
+ };
2090
2539
  // src/tui/Details.tsx
2091
- function Fact(props) {
2092
- return createComponent(Show, {
2093
- get when() {
2094
- return memo(() => props.value !== void 0)() && props.value !== "";
2095
- },
2096
- get children() {
2097
- var _el$ = createElement("box"), _el$2 = createElement("text"), _el$3 = createElement("text");
2098
- insertNode(_el$, _el$2);
2099
- insertNode(_el$, _el$3);
2100
- setProp(_el$, "flexDirection", "row");
2101
- setProp(_el$2, "width", 13);
2102
- setProp(_el$2, "flexShrink", 0);
2103
- insert(_el$2, () => props.label);
2104
- setProp(_el$3, "flexGrow", 1);
2105
- setProp(_el$3, "flexShrink", 1);
2106
- setProp(_el$3, "wrapMode", "word");
2107
- insert(_el$3, () => props.value ?? "");
2108
- effect((_p$) => {
2109
- var _v$ = theme.faint, _v$2 = theme.text;
2110
- _v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
2111
- _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
2112
- return _p$;
2113
- }, {
2114
- e: void 0,
2115
- t: void 0
2116
- });
2117
- return _el$;
2118
- }
2119
- });
2120
- }
2540
+ const Fact = (props) => createComponent(Show, {
2541
+ get when() {
2542
+ return memo(() => props.value !== void 0)() && props.value !== "";
2543
+ },
2544
+ get children() {
2545
+ var _el$ = createElement("box"), _el$2 = createElement("text"), _el$3 = createElement("text");
2546
+ insertNode(_el$, _el$2);
2547
+ insertNode(_el$, _el$3);
2548
+ setProp(_el$, "flexDirection", "row");
2549
+ setProp(_el$2, "width", 13);
2550
+ setProp(_el$2, "flexShrink", 0);
2551
+ insert(_el$2, () => props.label);
2552
+ setProp(_el$3, "flexGrow", 1);
2553
+ setProp(_el$3, "flexShrink", 1);
2554
+ setProp(_el$3, "wrapMode", "word");
2555
+ insert(_el$3, () => props.value ?? "");
2556
+ effect((_p$) => {
2557
+ var _v$ = theme.muted, _v$2 = theme.text;
2558
+ _v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
2559
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
2560
+ return _p$;
2561
+ }, {
2562
+ e: void 0,
2563
+ t: void 0
2564
+ });
2565
+ return _el$;
2566
+ }
2567
+ });
2121
2568
  const described = (about) => about?._tag === "Ready" ? about.value.description : void 0;
2122
2569
  const months = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");
2123
2570
  const day = (timestamp) => {
2124
2571
  const at = new Date(timestamp ?? "");
2125
- if (Number.isNaN(at.getTime())) return void 0;
2572
+ if (Number.isNaN(at.getTime())) return;
2126
2573
  const year = at.getFullYear();
2127
2574
  const shown = `${months[at.getMonth()] ?? ""} ${at.getDate()}`;
2128
2575
  return year === (/* @__PURE__ */ new Date()).getFullYear() ? shown : `${shown} ${year}`;
@@ -2148,7 +2595,7 @@ const releases = (metadata, versions) => {
2148
2595
  const apart = gap === void 0 || Number.isNaN(gap) || gap < 0 ? [] : [gap === 0 ? "released the same day" : `released ${gap} day${gap === 1 ? "" : "s"} apart`];
2149
2596
  return dated.length === 0 ? void 0 : [...dated.toReversed(), ...apart].join("\n");
2150
2597
  };
2151
- function Registry(props) {
2598
+ const Registry = (props) => {
2152
2599
  const versions = () => [props.current, ...props.target === void 0 ? [] : [props.target]];
2153
2600
  const ready = () => props.about?._tag === "Ready" ? props.about.value : void 0;
2154
2601
  const unavailable = () => props.about?._tag === "Unavailable" ? props.about.issue : void 0;
@@ -2161,7 +2608,7 @@ function Registry(props) {
2161
2608
  get children() {
2162
2609
  var _el$4 = createElement("text");
2163
2610
  insertNode(_el$4, createTextNode(`Looking up the registry…`));
2164
- effect((_$p) => setProp(_el$4, "fg", theme.faint, _$p));
2611
+ effect((_$p) => setProp(_el$4, "fg", theme.muted, _$p));
2165
2612
  return _el$4;
2166
2613
  }
2167
2614
  }),
@@ -2173,7 +2620,7 @@ function Registry(props) {
2173
2620
  var _el$6 = createElement("text");
2174
2621
  setProp(_el$6, "wrapMode", "word");
2175
2622
  insert(_el$6, () => `Registry details unavailable: ${issue()}`);
2176
- effect((_$p) => setProp(_el$6, "fg", theme.faint, _$p));
2623
+ effect((_$p) => setProp(_el$6, "fg", theme.muted, _$p));
2177
2624
  return _el$6;
2178
2625
  })()
2179
2626
  }),
@@ -2258,9 +2705,9 @@ function Registry(props) {
2258
2705
  })
2259
2706
  ];
2260
2707
  } });
2261
- }
2708
+ };
2262
2709
  const badge = (tab, audit) => {
2263
- if (tab !== "report" || audit === void 0) return void 0;
2710
+ if (tab !== "report" || audit === void 0) return;
2264
2711
  if (audit._tag === "Running") return {
2265
2712
  text: "…",
2266
2713
  color: theme.accent
@@ -2269,14 +2716,14 @@ const badge = (tab, audit) => {
2269
2716
  text: "✗",
2270
2717
  color: theme.danger
2271
2718
  };
2272
- const verdict = audit.result.report.verdict;
2719
+ const { verdict } = audit.result.report;
2273
2720
  return {
2274
2721
  text: verdictIcons[verdict],
2275
2722
  color: verdictColor(verdict)
2276
2723
  };
2277
2724
  };
2278
- function Version(props) {
2279
- const change = () => props.target === void 0 ? void 0 : bump(props.current, props.target);
2725
+ const Version = (props) => {
2726
+ const change = () => props.target === void 0 ? void 0 : bump(props.current, props.target, props.ecosystem);
2280
2727
  return (() => {
2281
2728
  var _el$10 = createElement("box"), _el$11 = createElement("text"), _el$12 = createElement("text");
2282
2729
  insertNode(_el$10, _el$11);
@@ -2316,7 +2763,7 @@ function Version(props) {
2316
2763
  }
2317
2764
  }), null);
2318
2765
  effect((_p$) => {
2319
- var _v$5 = theme.faint, _v$6 = theme.text, _v$7 = theme.strong, _v$8 = TextAttributes.BOLD;
2766
+ var _v$5 = theme.muted, _v$6 = theme.text, _v$7 = theme.strong, _v$8 = TextAttributes.BOLD;
2320
2767
  _v$5 !== _p$.e && (_p$.e = setProp(_el$14, "fg", _v$5, _p$.e));
2321
2768
  _v$6 !== _p$.t && (_p$.t = setProp(_el$16, "fg", _v$6, _p$.t));
2322
2769
  _v$7 !== _p$.a && (_p$.a = setProp(_el$17, "fg", _v$7, _p$.a));
@@ -2334,7 +2781,7 @@ function Version(props) {
2334
2781
  setProp(_el$12, "flexShrink", 0);
2335
2782
  insert(_el$12, () => ` · ${props.provider}`);
2336
2783
  effect((_p$) => {
2337
- var _v$3 = theme.muted, _v$4 = theme.faint;
2784
+ var _v$3 = theme.muted, _v$4 = theme.muted;
2338
2785
  _v$3 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$3, _p$.e));
2339
2786
  _v$4 !== _p$.t && (_p$.t = setProp(_el$12, "fg", _v$4, _p$.t));
2340
2787
  return _p$;
@@ -2344,7 +2791,7 @@ function Version(props) {
2344
2791
  });
2345
2792
  return _el$10;
2346
2793
  })();
2347
- }
2794
+ };
2348
2795
  const headerLines = 5;
2349
2796
  const tabs = [
2350
2797
  "about",
@@ -2359,491 +2806,516 @@ const tabTitles = {
2359
2806
  transcript: "Transcript"
2360
2807
  };
2361
2808
  const storedTranscript = (audit) => audit?._tag === "Done" && audit.result._tag === "Reported" ? audit.result.file : void 0;
2362
- const liveTranscript = (audit) => audit?._tag === "Running" ? audit.transcript : audit?._tag === "Done" && audit.result._tag === "Failed" ? audit.result.transcript : void 0;
2363
- function Details(props) {
2364
- return (() => {
2365
- var _el$19 = createElement("box");
2366
- setProp(_el$19, "flexDirection", "column");
2367
- setProp(_el$19, "flexGrow", 1);
2368
- setProp(_el$19, "paddingLeft", 1);
2369
- setProp(_el$19, "paddingRight", 1);
2370
- insert(_el$19, createComponent(Show, {
2371
- get when() {
2372
- return props.row;
2373
- },
2374
- get fallback() {
2375
- return (() => {
2376
- var _el$20 = createElement("text");
2377
- insertNode(_el$20, createTextNode(` `));
2378
- return _el$20;
2379
- })();
2380
- },
2381
- children: (row) => {
2382
- const pkg = () => row().pkg;
2383
- const reviewed = () => auditedAs(props.state, pkg());
2384
- const notices = () => props.state.providers.flatMap((entry) => entry.notices).filter((notice) => notice.rowKey === row().key);
2385
- const outcome = () => props.state.outcomes[row().key];
2386
- const gone = () => props.state.removed[row().key] !== void 0;
2387
- const nothing = () => gone() ? "it was removed" : unauditable(reviewed());
2388
- const failure = () => {
2389
- const latest = outcome();
2390
- if (latest?._tag !== "Failed" && latest?._tag !== "Unexpected") return void 0;
2391
- const what = props.state.actions[row().key] === "uninstall" ? "Removal" : "Update";
2392
- const told = describeOutcome(latest);
2393
- const whole = `✗ ${what} ${told.charAt(0).toLowerCase()}${told.slice(1)}`;
2394
- const room = props.width - 4;
2395
- if (props.tab === "about" || Array.from(whole).length <= room) return whole;
2396
- return `${Array.from(whole).slice(0, Math.max(10, room - 17)).join("").trimEnd()} … whole on About`;
2397
- };
2398
- const about = () => props.state.about[aboutKey(pkg())];
2399
- const reading = () => {
2400
- const key = auditKey(reviewed(), props.state.mode);
2401
- const loaded = key === void 0 ? void 0 : props.state.changes[key];
2402
- if (loaded?._tag !== "Ready") return void 0;
2403
- const list = files(loaded.value);
2404
- const file = list[Math.min(props.file, list.length - 1)];
2405
- return file === void 0 || list.length < 2 ? void 0 : `${position(list, props.file)} · ${file.section.path}`;
2406
- };
2407
- const declaration = () => {
2408
- const declared = pkg().declaration;
2409
- return declared === void 0 ? void 0 : `${declared.manifest} (${declared.section})`;
2410
- };
2411
- return (() => {
2412
- var _el$22 = createElement("box"), _el$23 = createElement("box"), _el$24 = createElement("text"), _el$25 = createElement("text"), _el$26 = createElement("box"), _el$27 = createElement("text"), _el$28 = createElement("scrollbox");
2413
- insertNode(_el$22, _el$23);
2414
- insertNode(_el$22, _el$25);
2415
- insertNode(_el$22, _el$26);
2416
- insertNode(_el$22, _el$27);
2417
- insertNode(_el$22, _el$28);
2418
- setProp(_el$22, "flexDirection", "column");
2419
- setProp(_el$22, "flexGrow", 1);
2420
- insertNode(_el$23, _el$24);
2421
- setProp(_el$23, "flexDirection", "row");
2422
- setProp(_el$23, "height", 1);
2423
- setProp(_el$23, "flexShrink", 0);
2424
- setProp(_el$24, "wrapMode", "none");
2425
- setProp(_el$24, "truncate", true);
2426
- setProp(_el$24, "flexShrink", 1);
2427
- insert(_el$24, () => pkg().name);
2428
- insert(_el$23, createComponent(Show, {
2429
- get when() {
2430
- return props.position;
2431
- },
2432
- children: (position) => (() => {
2433
- var _el$32 = createElement("text");
2434
- setProp(_el$32, "flexShrink", 0);
2435
- insert(_el$32, () => ` ${position()}`);
2436
- effect((_$p) => setProp(_el$32, "fg", theme.faint, _$p));
2437
- return _el$32;
2438
- })()
2439
- }), null);
2440
- insert(_el$22, createComponent(Version, {
2441
- get current() {
2442
- return pkg().current;
2443
- },
2444
- get target() {
2445
- return pkg().target;
2446
- },
2447
- get provider() {
2448
- return providerLabel(pkg().provider);
2449
- }
2450
- }), _el$25);
2451
- setProp(_el$25, "flexShrink", 0);
2452
- setProp(_el$25, "wrapMode", "none");
2453
- setProp(_el$25, "truncate", true);
2454
- insert(_el$25, () => failure() ?? (gone() ? "– Removed this week · there is nothing to do" : reviewed() === pkg() ? " " : auditOf(props.state, pkg()) === void 0 ? `Updated from ${reviewed().current} · not audited` : `Updated from ${reviewed().current} · audited before installing`));
2455
- setProp(_el$26, "flexDirection", "row");
2456
- setProp(_el$26, "height", 1);
2457
- setProp(_el$26, "flexShrink", 0);
2458
- insert(_el$26, createComponent(For, {
2459
- each: tabs,
2460
- children: (tab) => (() => {
2461
- var _el$33 = createElement("box"), _el$34 = createElement("text"), _el$35 = createElement("text");
2462
- insertNode(_el$33, _el$34);
2463
- insertNode(_el$33, _el$35);
2464
- setProp(_el$33, "flexDirection", "row");
2465
- setProp(_el$33, "flexShrink", 0);
2466
- setProp(_el$33, "marginRight", 1);
2467
- setProp(_el$34, "flexShrink", 0);
2468
- insert(_el$34, () => ` ${tabTitles[tab]}${badge(tab, auditOf(props.state, pkg())) === void 0 ? "" : " "}`);
2469
- insert(_el$33, createComponent(Show, {
2470
- get when() {
2471
- return badge(tab, auditOf(props.state, pkg()));
2472
- },
2473
- children: (shown) => (() => {
2474
- var _el$37 = createElement("text");
2475
- setProp(_el$37, "flexShrink", 0);
2476
- insert(_el$37, () => shown().text);
2477
- effect((_p$) => {
2478
- var _v$18 = tab === props.tab ? theme.onAccent : shown().color, _v$19 = tab === props.tab ? theme.accent : theme.none;
2479
- _v$18 !== _p$.e && (_p$.e = setProp(_el$37, "fg", _v$18, _p$.e));
2480
- _v$19 !== _p$.t && (_p$.t = setProp(_el$37, "bg", _v$19, _p$.t));
2481
- return _p$;
2482
- }, {
2483
- e: void 0,
2484
- t: void 0
2485
- });
2486
- return _el$37;
2487
- })()
2488
- }), _el$35);
2489
- insertNode(_el$35, createTextNode(` `));
2490
- setProp(_el$35, "flexShrink", 0);
2491
- effect((_p$) => {
2492
- var _v$14 = tab === props.tab ? theme.onAccent : theme.muted, _v$15 = tab === props.tab ? theme.accent : theme.none, _v$16 = tab === props.tab ? TextAttributes.BOLD : TextAttributes.NONE, _v$17 = tab === props.tab ? theme.accent : theme.none;
2493
- _v$14 !== _p$.e && (_p$.e = setProp(_el$34, "fg", _v$14, _p$.e));
2494
- _v$15 !== _p$.t && (_p$.t = setProp(_el$34, "bg", _v$15, _p$.t));
2495
- _v$16 !== _p$.a && (_p$.a = setProp(_el$34, "attributes", _v$16, _p$.a));
2496
- _v$17 !== _p$.o && (_p$.o = setProp(_el$35, "bg", _v$17, _p$.o));
2497
- return _p$;
2498
- }, {
2499
- e: void 0,
2500
- t: void 0,
2501
- a: void 0,
2502
- o: void 0
2503
- });
2504
- return _el$33;
2505
- })()
2506
- }));
2507
- setProp(_el$27, "flexShrink", 0);
2508
- setProp(_el$27, "wrapMode", "none");
2509
- setProp(_el$27, "truncate", true);
2510
- insert(_el$27, (() => {
2511
- var _c$ = memo(() => props.tab === "changes");
2512
- return () => _c$() ? reading() ?? " " : " ";
2513
- })());
2514
- var _ref$ = props.scroller;
2515
- typeof _ref$ === "function" ? use(_ref$, _el$28) : props.scroller = _el$28;
2516
- setProp(_el$28, "contentOptions", { paddingRight: 2 });
2517
- setProp(_el$28, "stickyStart", "bottom");
2518
- insert(_el$28, createComponent(Switch, { get children() {
2519
- return [
2520
- createComponent(Match, {
2521
- get when() {
2522
- return props.tab === "about";
2523
- },
2524
- get children() {
2525
- var _el$29 = createElement("box"), _el$30 = createElement("text");
2526
- insertNode(_el$29, _el$30);
2527
- setProp(_el$29, "flexDirection", "column");
2528
- insert(_el$29, createComponent(Show, {
2529
- get when() {
2530
- return pkg().description ?? described(about());
2809
+ const liveTranscript = (audit) => {
2810
+ if (audit?._tag === "Running") return audit.transcript;
2811
+ if (audit?._tag === "Done" && audit.result._tag === "Failed") return audit.result.transcript;
2812
+ };
2813
+ const Details = (props) => (() => {
2814
+ var _el$19 = createElement("box");
2815
+ setProp(_el$19, "flexDirection", "column");
2816
+ setProp(_el$19, "flexGrow", 1);
2817
+ setProp(_el$19, "paddingLeft", 1);
2818
+ setProp(_el$19, "paddingRight", 1);
2819
+ insert(_el$19, createComponent(Show, {
2820
+ get when() {
2821
+ return props.row;
2822
+ },
2823
+ get fallback() {
2824
+ return (() => {
2825
+ var _el$20 = createElement("text");
2826
+ insertNode(_el$20, createTextNode(` `));
2827
+ return _el$20;
2828
+ })();
2829
+ },
2830
+ children: (row) => {
2831
+ const pkg = () => row().pkg;
2832
+ const reviewed = () => auditedAs(props.state, pkg());
2833
+ const notices = () => props.state.providers.flatMap((entry) => entry.notices).filter((notice) => notice.rowKey === row().key);
2834
+ const outcome = () => props.state.outcomes[row().key];
2835
+ const gone = () => props.state.removed[row().key] !== void 0;
2836
+ const nothing = () => gone() ? "it was removed" : unauditable(reviewed());
2837
+ const failure = () => {
2838
+ const latest = outcome();
2839
+ if (latest?._tag !== "Failed" && latest?._tag !== "Unexpected") return;
2840
+ const what = props.state.actions[row().key] === "uninstall" ? "Removal" : "Update";
2841
+ const told = describeOutcome(latest);
2842
+ const whole = `✗ ${what} ${told.charAt(0).toLowerCase()}${told.slice(1)}`;
2843
+ const room = props.width - 4;
2844
+ if (props.tab === "about" || graphemes(whole).length <= room) return whole;
2845
+ return `${graphemes(whole).slice(0, Math.max(10, room - 17)).join("").trimEnd()} … whole on About`;
2846
+ };
2847
+ const installedNote = () => {
2848
+ if (gone()) return "– Removed this week · there is nothing to do";
2849
+ if (reviewed() === pkg()) return " ";
2850
+ if (auditOf(props.state, pkg()) === void 0) return `Updated from ${reviewed().current} · not audited`;
2851
+ return `Updated from ${reviewed().current} · audited before installing`;
2852
+ };
2853
+ const updateLabel = (latest) => {
2854
+ if (props.state.actions[row().key] === "uninstall") return "Removal";
2855
+ if (latest._tag === "Completed") return "Updated";
2856
+ return "Update";
2857
+ };
2858
+ const about = () => props.state.about[aboutKey(pkg())];
2859
+ const reading = () => {
2860
+ const key = auditKey(reviewed(), props.state.mode);
2861
+ const loaded = key === void 0 ? void 0 : props.state.changes[key];
2862
+ if (loaded?._tag !== "Ready") return;
2863
+ const list = files(loaded.value);
2864
+ const file = list[Math.min(props.file, list.length - 1)];
2865
+ if (file === void 0 || list.length < 2) return;
2866
+ return `${position(list, props.file)} · ${file.section.path}`;
2867
+ };
2868
+ const declaration = () => {
2869
+ const declared = pkg().declaration;
2870
+ return declared === void 0 ? void 0 : `${declared.manifest} (${declared.section})`;
2871
+ };
2872
+ return (() => {
2873
+ var _el$22 = createElement("box"), _el$23 = createElement("box"), _el$24 = createElement("text"), _el$25 = createElement("text"), _el$26 = createElement("box"), _el$27 = createElement("text"), _el$28 = createElement("scrollbox");
2874
+ insertNode(_el$22, _el$23);
2875
+ insertNode(_el$22, _el$25);
2876
+ insertNode(_el$22, _el$26);
2877
+ insertNode(_el$22, _el$27);
2878
+ insertNode(_el$22, _el$28);
2879
+ setProp(_el$22, "flexDirection", "column");
2880
+ setProp(_el$22, "flexGrow", 1);
2881
+ insertNode(_el$23, _el$24);
2882
+ setProp(_el$23, "flexDirection", "row");
2883
+ setProp(_el$23, "height", 1);
2884
+ setProp(_el$23, "flexShrink", 0);
2885
+ setProp(_el$24, "wrapMode", "none");
2886
+ setProp(_el$24, "truncate", true);
2887
+ setProp(_el$24, "flexShrink", 1);
2888
+ insert(_el$24, () => pkg().name);
2889
+ insert(_el$23, createComponent(Show, {
2890
+ get when() {
2891
+ return props.position;
2892
+ },
2893
+ children: (rowPosition) => (() => {
2894
+ var _el$32 = createElement("text");
2895
+ setProp(_el$32, "flexShrink", 0);
2896
+ insert(_el$32, () => ` ${rowPosition()}`);
2897
+ effect((_$p) => setProp(_el$32, "fg", theme.muted, _$p));
2898
+ return _el$32;
2899
+ })()
2900
+ }), null);
2901
+ insert(_el$22, createComponent(Version, {
2902
+ get current() {
2903
+ return pkg().current;
2904
+ },
2905
+ get target() {
2906
+ return pkg().target;
2907
+ },
2908
+ get ecosystem() {
2909
+ return pkg().ecosystem;
2910
+ },
2911
+ get provider() {
2912
+ return providerLabel(pkg().provider);
2913
+ }
2914
+ }), _el$25);
2915
+ setProp(_el$25, "flexShrink", 0);
2916
+ setProp(_el$25, "wrapMode", "none");
2917
+ setProp(_el$25, "truncate", true);
2918
+ insert(_el$25, () => failure() ?? installedNote());
2919
+ setProp(_el$26, "flexDirection", "row");
2920
+ setProp(_el$26, "height", 1);
2921
+ setProp(_el$26, "flexShrink", 0);
2922
+ insert(_el$26, createComponent(For, {
2923
+ each: tabs,
2924
+ children: (tab) => (() => {
2925
+ var _el$33 = createElement("box"), _el$34 = createElement("text"), _el$35 = createElement("text");
2926
+ insertNode(_el$33, _el$34);
2927
+ insertNode(_el$33, _el$35);
2928
+ setProp(_el$33, "flexDirection", "row");
2929
+ setProp(_el$33, "flexShrink", 0);
2930
+ setProp(_el$33, "marginRight", 1);
2931
+ setProp(_el$34, "flexShrink", 0);
2932
+ insert(_el$34, () => ` ${tabTitles[tab]}${badge(tab, auditOf(props.state, pkg())) === void 0 ? "" : " "}`);
2933
+ insert(_el$33, createComponent(Show, {
2934
+ get when() {
2935
+ return badge(tab, auditOf(props.state, pkg()));
2936
+ },
2937
+ children: (shown) => (() => {
2938
+ var _el$37 = createElement("text");
2939
+ setProp(_el$37, "flexShrink", 0);
2940
+ insert(_el$37, () => shown().text);
2941
+ effect((_p$) => {
2942
+ var _v$18 = tab === props.tab ? theme.onAccent : shown().color, _v$19 = tab === props.tab ? theme.accent : theme.none;
2943
+ _v$18 !== _p$.e && (_p$.e = setProp(_el$37, "fg", _v$18, _p$.e));
2944
+ _v$19 !== _p$.t && (_p$.t = setProp(_el$37, "bg", _v$19, _p$.t));
2945
+ return _p$;
2946
+ }, {
2947
+ e: void 0,
2948
+ t: void 0
2949
+ });
2950
+ return _el$37;
2951
+ })()
2952
+ }), _el$35);
2953
+ insertNode(_el$35, createTextNode(` `));
2954
+ setProp(_el$35, "flexShrink", 0);
2955
+ effect((_p$) => {
2956
+ var _v$14 = tab === props.tab ? theme.onAccent : theme.muted, _v$15 = tab === props.tab ? theme.accent : theme.none, _v$16 = tab === props.tab ? TextAttributes.BOLD : TextAttributes.NONE, _v$17 = tab === props.tab ? theme.accent : theme.none;
2957
+ _v$14 !== _p$.e && (_p$.e = setProp(_el$34, "fg", _v$14, _p$.e));
2958
+ _v$15 !== _p$.t && (_p$.t = setProp(_el$34, "bg", _v$15, _p$.t));
2959
+ _v$16 !== _p$.a && (_p$.a = setProp(_el$34, "attributes", _v$16, _p$.a));
2960
+ _v$17 !== _p$.o && (_p$.o = setProp(_el$35, "bg", _v$17, _p$.o));
2961
+ return _p$;
2962
+ }, {
2963
+ e: void 0,
2964
+ t: void 0,
2965
+ a: void 0,
2966
+ o: void 0
2967
+ });
2968
+ return _el$33;
2969
+ })()
2970
+ }));
2971
+ setProp(_el$27, "flexShrink", 0);
2972
+ setProp(_el$27, "wrapMode", "none");
2973
+ setProp(_el$27, "truncate", true);
2974
+ insert(_el$27, (() => {
2975
+ var _c$ = memo(() => props.tab === "changes");
2976
+ return () => _c$() ? reading() ?? " " : " ";
2977
+ })());
2978
+ var _ref$ = props.scroller;
2979
+ typeof _ref$ === "function" ? use(_ref$, _el$28) : props.scroller = _el$28;
2980
+ setProp(_el$28, "contentOptions", { paddingRight: 2 });
2981
+ setProp(_el$28, "stickyStart", "bottom");
2982
+ insert(_el$28, createComponent(Switch, { get children() {
2983
+ return [
2984
+ createComponent(Match, {
2985
+ get when() {
2986
+ return props.tab === "about";
2987
+ },
2988
+ get children() {
2989
+ var _el$29 = createElement("box"), _el$30 = createElement("text");
2990
+ insertNode(_el$29, _el$30);
2991
+ setProp(_el$29, "flexDirection", "column");
2992
+ insert(_el$29, createComponent(Show, {
2993
+ get when() {
2994
+ return pkg().description ?? described(about());
2995
+ },
2996
+ children: (description) => (() => {
2997
+ var _el$38 = createElement("text");
2998
+ setProp(_el$38, "wrapMode", "word");
2999
+ insert(_el$38, description);
3000
+ effect((_$p) => setProp(_el$38, "fg", theme.text, _$p));
3001
+ return _el$38;
3002
+ })()
3003
+ }), _el$30);
3004
+ insertNode(_el$30, createTextNode(` `));
3005
+ insert(_el$29, createComponent(Fact, {
3006
+ label: "Provider",
3007
+ get value() {
3008
+ return providerLabel(pkg().provider);
3009
+ }
3010
+ }), null);
3011
+ insert(_el$29, createComponent(Fact, {
3012
+ label: "Ecosystem",
3013
+ get value() {
3014
+ return pkg().ecosystem;
3015
+ }
3016
+ }), null);
3017
+ insert(_el$29, createComponent(Fact, {
3018
+ label: "Artifact",
3019
+ get value() {
3020
+ return pkg().artifact;
3021
+ }
3022
+ }), null);
3023
+ insert(_el$29, createComponent(Fact, {
3024
+ label: "Runtime",
3025
+ get value() {
3026
+ return pkg().runtime;
3027
+ }
3028
+ }), null);
3029
+ insert(_el$29, createComponent(Fact, {
3030
+ label: "Declared in",
3031
+ get value() {
3032
+ return declaration();
3033
+ }
3034
+ }), null);
3035
+ insert(_el$29, createComponent(Fact, {
3036
+ label: "Requires",
3037
+ get value() {
3038
+ return pkg().requires?.join(", ");
3039
+ }
3040
+ }), null);
3041
+ insert(_el$29, createComponent(Fact, {
3042
+ label: "Required by",
3043
+ get value() {
3044
+ return pkg().requiredBy?.join(", ");
3045
+ }
3046
+ }), null);
3047
+ insert(_el$29, createComponent(Show, {
3048
+ get when() {
3049
+ return outcome();
3050
+ },
3051
+ children: (latest) => createComponent(Fact, {
3052
+ get label() {
3053
+ return updateLabel(latest());
2531
3054
  },
2532
- children: (description) => (() => {
2533
- var _el$38 = createElement("text");
2534
- setProp(_el$38, "wrapMode", "word");
2535
- insert(_el$38, description);
2536
- effect((_$p) => setProp(_el$38, "fg", theme.text, _$p));
2537
- return _el$38;
2538
- })()
2539
- }), _el$30);
2540
- insertNode(_el$30, createTextNode(` `));
2541
- insert(_el$29, createComponent(Fact, {
2542
- label: "Provider",
2543
- get value() {
2544
- return providerLabel(pkg().provider);
2545
- }
2546
- }), null);
2547
- insert(_el$29, createComponent(Fact, {
2548
- label: "Ecosystem",
2549
- get value() {
2550
- return pkg().ecosystem;
2551
- }
2552
- }), null);
2553
- insert(_el$29, createComponent(Fact, {
2554
- label: "Artifact",
2555
- get value() {
2556
- return pkg().artifact;
2557
- }
2558
- }), null);
2559
- insert(_el$29, createComponent(Fact, {
2560
- label: "Runtime",
2561
- get value() {
2562
- return pkg().runtime;
2563
- }
2564
- }), null);
2565
- insert(_el$29, createComponent(Fact, {
2566
- label: "Declared in",
2567
- get value() {
2568
- return declaration();
2569
- }
2570
- }), null);
2571
- insert(_el$29, createComponent(Fact, {
2572
- label: "Requires",
2573
3055
  get value() {
2574
- return pkg().requires?.join(", ");
3056
+ return memo(() => !!(latest()._tag === "Completed" && reviewed() !== pkg()))() ? `this session, from ${reviewed().current}` : describeOutcome(latest());
2575
3057
  }
2576
- }), null);
2577
- insert(_el$29, createComponent(Fact, {
2578
- label: "Required by",
2579
- get value() {
2580
- return pkg().requiredBy?.join(", ");
2581
- }
2582
- }), null);
2583
- insert(_el$29, createComponent(Show, {
2584
- get when() {
2585
- return outcome();
2586
- },
2587
- children: (latest) => createComponent(Fact, {
2588
- get label() {
2589
- return memo(() => props.state.actions[row().key] === "uninstall")() ? "Removal" : latest()._tag === "Completed" ? "Updated" : "Update";
2590
- },
2591
- get value() {
2592
- return memo(() => !!(latest()._tag === "Completed" && reviewed() !== pkg()))() ? `this session, from ${reviewed().current}` : describeOutcome(latest());
3058
+ })
3059
+ }), null);
3060
+ insert(_el$29, createComponent(Registry, {
3061
+ get about() {
3062
+ return about();
3063
+ },
3064
+ get current() {
3065
+ return pkg().current;
3066
+ },
3067
+ get target() {
3068
+ return pkg().target;
3069
+ }
3070
+ }), null);
3071
+ insert(_el$29, createComponent(Show, {
3072
+ get when() {
3073
+ return memo(() => pkg().target === void 0)() ? void 0 : pkg().elsewhere;
3074
+ },
3075
+ children: (elsewhere) => (() => {
3076
+ var _el$39 = createElement("box"), _el$40 = createElement("text"), _el$41 = createElement("box"), _el$42 = createElement("text");
3077
+ insertNode(_el$39, _el$40);
3078
+ insertNode(_el$39, _el$41);
3079
+ setProp(_el$39, "flexDirection", "column");
3080
+ setProp(_el$39, "marginTop", 1);
3081
+ setProp(_el$40, "wrapMode", "word");
3082
+ insert(_el$40, () => `${elsewhere().reason.replace(/^./u, (first) => first.toUpperCase())}.`);
3083
+ insertNode(_el$41, _el$42);
3084
+ setProp(_el$41, "flexDirection", "row");
3085
+ setProp(_el$41, "height", 1);
3086
+ insert(_el$41, createComponent(Key, {
3087
+ hint: "o",
3088
+ get color() {
3089
+ return theme.muted;
2593
3090
  }
2594
- })
2595
- }), null);
2596
- insert(_el$29, createComponent(Registry, {
2597
- get about() {
2598
- return about();
2599
- },
2600
- get current() {
2601
- return pkg().current;
2602
- },
2603
- get target() {
2604
- return pkg().target;
2605
- }
2606
- }), null);
2607
- insert(_el$29, createComponent(Show, {
2608
- get when() {
2609
- return memo(() => pkg().target === void 0)() ? void 0 : pkg().elsewhere;
2610
- },
2611
- children: (elsewhere) => (() => {
2612
- var _el$39 = createElement("box"), _el$40 = createElement("text"), _el$41 = createElement("box"), _el$42 = createElement("text");
2613
- insertNode(_el$39, _el$40);
2614
- insertNode(_el$39, _el$41);
2615
- setProp(_el$39, "flexDirection", "column");
2616
- setProp(_el$39, "marginTop", 1);
2617
- setProp(_el$40, "wrapMode", "word");
2618
- insert(_el$40, () => `${elsewhere().reason.replace(/^./u, (first) => first.toUpperCase())}.`);
2619
- insertNode(_el$41, _el$42);
2620
- setProp(_el$41, "flexDirection", "row");
2621
- setProp(_el$41, "height", 1);
2622
- insert(_el$41, createComponent(Key, {
2623
- hint: "o",
2624
- get color() {
2625
- return theme.muted;
2626
- }
2627
- }), _el$42);
2628
- insert(_el$42, () => ` open ${elsewhere().app}`);
2629
- effect((_p$) => {
2630
- var _v$20 = theme.muted, _v$21 = theme.muted;
2631
- _v$20 !== _p$.e && (_p$.e = setProp(_el$40, "fg", _v$20, _p$.e));
2632
- _v$21 !== _p$.t && (_p$.t = setProp(_el$42, "fg", _v$21, _p$.t));
2633
- return _p$;
2634
- }, {
2635
- e: void 0,
2636
- t: void 0
2637
- });
2638
- return _el$39;
2639
- })()
2640
- }), null);
2641
- insert(_el$29, createComponent(For, {
2642
- get each() {
2643
- return notices();
2644
- },
2645
- children: (notice) => (() => {
2646
- var _el$43 = createElement("text");
2647
- setProp(_el$43, "wrapMode", "word");
2648
- insert(_el$43, () => notice.message);
2649
- effect((_$p) => setProp(_el$43, "fg", theme.warn, _$p));
2650
- return _el$43;
2651
- })()
2652
- }), null);
2653
- return _el$29;
2654
- }
2655
- }),
2656
- createComponent(Match, {
2657
- get when() {
2658
- return props.tab === "changes";
2659
- },
2660
- get children() {
2661
- return createComponent(Changes, {
2662
- get loaded() {
2663
- const key = auditKey(reviewed(), props.state.mode);
2664
- return key === void 0 ? void 0 : props.state.changes[key];
2665
- },
2666
- get unauditable() {
2667
- return nothing();
2668
- },
2669
- get notes() {
2670
- return memo(() => !!gone())() ? void 0 : pkg().notes;
2671
- },
2672
- get at() {
2673
- return props.file;
2674
- }
2675
- });
2676
- }
2677
- }),
2678
- createComponent(Match, {
2679
- get when() {
2680
- return props.tab === "report";
2681
- },
2682
- get children() {
2683
- return createComponent(Report, {
2684
- get audit() {
2685
- return auditOf(props.state, pkg());
2686
- },
2687
- get installed() {
2688
- return reviewed() !== pkg();
2689
- },
2690
- get unauditable() {
2691
- return nothing();
2692
- },
2693
- model: (id) => {
2694
- const slash = id.indexOf("/");
2695
- return slash < 0 ? id : modelLabel(props.state, id.slice(0, slash), id.slice(slash + 1));
2696
- }
2697
- });
2698
- }
2699
- }),
2700
- createComponent(Match, {
2701
- get when() {
2702
- return props.tab === "transcript";
2703
- },
2704
- get children() {
2705
- return createComponent(Transcript, {
2706
- get live() {
2707
- return liveTranscript(auditOf(props.state, pkg()));
2708
- },
2709
- get running() {
2710
- return auditOf(props.state, pkg())?._tag === "Running";
2711
- },
2712
- get stored() {
2713
- const file = storedTranscript(auditOf(props.state, pkg()));
2714
- return file === void 0 ? void 0 : props.state.transcripts[file];
2715
- },
2716
- get unauditable() {
2717
- return nothing();
2718
- }
2719
- });
2720
- }
2721
- })
2722
- ];
2723
- } }));
2724
- effect((_p$) => {
2725
- var _v$9 = theme.strong, _v$0 = TextAttributes.BOLD, _v$1 = failure() === void 0 ? theme.muted : theme.danger, _v$10 = theme.muted, _v$11 = Math.max(1, props.height - headerLines), _v$12 = props.tab === "transcript", _v$13 = { trackOptions: {
2726
- backgroundColor: theme.surface,
2727
- foregroundColor: theme.rule
2728
- } };
2729
- _v$9 !== _p$.e && (_p$.e = setProp(_el$24, "fg", _v$9, _p$.e));
2730
- _v$0 !== _p$.t && (_p$.t = setProp(_el$24, "attributes", _v$0, _p$.t));
2731
- _v$1 !== _p$.a && (_p$.a = setProp(_el$25, "fg", _v$1, _p$.a));
2732
- _v$10 !== _p$.o && (_p$.o = setProp(_el$27, "fg", _v$10, _p$.o));
2733
- _v$11 !== _p$.i && (_p$.i = setProp(_el$28, "height", _v$11, _p$.i));
2734
- _v$12 !== _p$.n && (_p$.n = setProp(_el$28, "stickyScroll", _v$12, _p$.n));
2735
- _v$13 !== _p$.s && (_p$.s = setProp(_el$28, "verticalScrollbarOptions", _v$13, _p$.s));
2736
- return _p$;
2737
- }, {
2738
- e: void 0,
2739
- t: void 0,
2740
- a: void 0,
2741
- o: void 0,
2742
- i: void 0,
2743
- n: void 0,
2744
- s: void 0
2745
- });
2746
- return _el$22;
2747
- })();
2748
- }
2749
- }));
2750
- effect((_$p) => setProp(_el$19, "maxWidth", props.tab === "about" || props.tab === "report" ? 100 : "100%", _$p));
2751
- return _el$19;
2752
- })();
2753
- }
3091
+ }), _el$42);
3092
+ insert(_el$42, () => ` open ${elsewhere().app}`);
3093
+ effect((_p$) => {
3094
+ var _v$20 = theme.muted, _v$21 = theme.muted;
3095
+ _v$20 !== _p$.e && (_p$.e = setProp(_el$40, "fg", _v$20, _p$.e));
3096
+ _v$21 !== _p$.t && (_p$.t = setProp(_el$42, "fg", _v$21, _p$.t));
3097
+ return _p$;
3098
+ }, {
3099
+ e: void 0,
3100
+ t: void 0
3101
+ });
3102
+ return _el$39;
3103
+ })()
3104
+ }), null);
3105
+ insert(_el$29, createComponent(For, {
3106
+ get each() {
3107
+ return notices();
3108
+ },
3109
+ children: (notice) => (() => {
3110
+ var _el$43 = createElement("text");
3111
+ setProp(_el$43, "wrapMode", "word");
3112
+ insert(_el$43, () => notice.message);
3113
+ effect((_$p) => setProp(_el$43, "fg", theme.warn, _$p));
3114
+ return _el$43;
3115
+ })()
3116
+ }), null);
3117
+ return _el$29;
3118
+ }
3119
+ }),
3120
+ createComponent(Match, {
3121
+ get when() {
3122
+ return props.tab === "changes";
3123
+ },
3124
+ get children() {
3125
+ return createComponent(Changes, {
3126
+ get loaded() {
3127
+ const key = auditKey(reviewed(), props.state.mode);
3128
+ return key === void 0 ? void 0 : props.state.changes[key];
3129
+ },
3130
+ get unauditable() {
3131
+ return nothing();
3132
+ },
3133
+ get notes() {
3134
+ return memo(() => !!gone())() ? void 0 : pkg().notes;
3135
+ },
3136
+ get at() {
3137
+ return props.file;
3138
+ }
3139
+ });
3140
+ }
3141
+ }),
3142
+ createComponent(Match, {
3143
+ get when() {
3144
+ return props.tab === "report";
3145
+ },
3146
+ get children() {
3147
+ return createComponent(Report, {
3148
+ get audit() {
3149
+ return auditOf(props.state, pkg());
3150
+ },
3151
+ get installed() {
3152
+ return reviewed() !== pkg();
3153
+ },
3154
+ get unauditable() {
3155
+ return nothing();
3156
+ },
3157
+ model: (id) => {
3158
+ const slash = id.indexOf("/");
3159
+ return slash === -1 ? id : modelLabel(props.state, id.slice(0, slash), id.slice(slash + 1));
3160
+ }
3161
+ });
3162
+ }
3163
+ }),
3164
+ createComponent(Match, {
3165
+ get when() {
3166
+ return props.tab === "transcript";
3167
+ },
3168
+ get children() {
3169
+ return createComponent(Transcript, {
3170
+ get live() {
3171
+ return liveTranscript(auditOf(props.state, pkg()));
3172
+ },
3173
+ get running() {
3174
+ return auditOf(props.state, pkg())?._tag === "Running";
3175
+ },
3176
+ get stored() {
3177
+ const file = storedTranscript(auditOf(props.state, pkg()));
3178
+ return file === void 0 ? void 0 : props.state.transcripts[file];
3179
+ },
3180
+ get unauditable() {
3181
+ return nothing();
3182
+ }
3183
+ });
3184
+ }
3185
+ })
3186
+ ];
3187
+ } }));
3188
+ effect((_p$) => {
3189
+ var _v$9 = theme.strong, _v$0 = TextAttributes.BOLD, _v$1 = failure() === void 0 ? theme.muted : theme.danger, _v$10 = theme.muted, _v$11 = Math.max(1, props.height - headerLines), _v$12 = props.tab === "transcript", _v$13 = { trackOptions: {
3190
+ backgroundColor: theme.surface,
3191
+ foregroundColor: theme.rule
3192
+ } };
3193
+ _v$9 !== _p$.e && (_p$.e = setProp(_el$24, "fg", _v$9, _p$.e));
3194
+ _v$0 !== _p$.t && (_p$.t = setProp(_el$24, "attributes", _v$0, _p$.t));
3195
+ _v$1 !== _p$.a && (_p$.a = setProp(_el$25, "fg", _v$1, _p$.a));
3196
+ _v$10 !== _p$.o && (_p$.o = setProp(_el$27, "fg", _v$10, _p$.o));
3197
+ _v$11 !== _p$.i && (_p$.i = setProp(_el$28, "height", _v$11, _p$.i));
3198
+ _v$12 !== _p$.n && (_p$.n = setProp(_el$28, "stickyScroll", _v$12, _p$.n));
3199
+ _v$13 !== _p$.s && (_p$.s = setProp(_el$28, "verticalScrollbarOptions", _v$13, _p$.s));
3200
+ return _p$;
3201
+ }, {
3202
+ e: void 0,
3203
+ t: void 0,
3204
+ a: void 0,
3205
+ o: void 0,
3206
+ i: void 0,
3207
+ n: void 0,
3208
+ s: void 0
3209
+ });
3210
+ return _el$22;
3211
+ })();
3212
+ }
3213
+ }));
3214
+ effect((_$p) => setProp(_el$19, "maxWidth", props.tab === "about" || props.tab === "report" ? 100 : "100%", _$p));
3215
+ return _el$19;
3216
+ })();
2754
3217
  // src/tui/Inventory.tsx
2755
3218
  const gap = 2;
2756
3219
  const prefix = 4;
2757
3220
  const arrow = " → ";
2758
3221
  const statusWidth = 14;
2759
3222
  const mark = (text) => {
2760
- const first = [...text][0] ?? "";
3223
+ const first = graphemes(text)[0] ?? "";
2761
3224
  return /\p{L}/u.test(first) ? "·" : first;
2762
3225
  };
2763
- const widest = (values, least, most) => Math.min(most, Math.max(least, ...values.map((value) => [...value].length)));
3226
+ const widest = (values, least, most = Infinity) => Math.min(most, Math.max(least, ...values.map((value) => graphemes(value).length)));
2764
3227
  const naturalColumns = (rows, state) => {
2765
3228
  const providers = new Set(rows.map((row) => row.pkg.provider));
2766
3229
  const statuses = rows.some((row) => row.pkg.target !== void 0 || status(state, row).text !== "");
2767
3230
  return {
2768
3231
  name: widest(rows.map((row) => row.pkg.name), 22, 40),
2769
- current: widest(rows.map((row) => row.pkg.current), 10, 16),
3232
+ current: widest(rows.map((row) => row.pkg.current), 10, 24),
2770
3233
  target: widest(rows.map((row) => row.pkg.target ?? ""), 0, 24),
2771
- bump: rows.some((row) => row.pkg.target !== void 0) ? widest(rows.map((row) => row.pkg.target === void 0 ? "" : bumpLabel(bump(row.pkg.current, row.pkg.target))), 4, 9) : 0,
3234
+ bump: rows.some((row) => row.pkg.target !== void 0) ? widest(rows.map((row) => row.pkg.target === void 0 ? "" : bumpLabel(bump(row.pkg.current, row.pkg.target, row.pkg.ecosystem))), 4) : 0,
2772
3235
  provider: providers.size > 1 ? widest(rows.map((row) => providerLabel(row.pkg.provider)), 8, 16) : 0,
2773
3236
  status: statuses ? statusWidth : 0
2774
3237
  };
2775
3238
  };
2776
3239
  const optional = (width) => width === 0 ? 0 : gap + width;
2777
3240
  const tableWidth = (columns) => prefix + columns.name + gap + columns.current + (columns.target === 0 ? 0 : 3 + columns.target) + optional(columns.bump) + optional(columns.provider) + optional(columns.status);
2778
- const fitColumns = (columns, width, mode = "project") => {
2779
- let excess = tableWidth(columns) - width;
2780
- const shrink = (value, floor) => {
2781
- const cut = Math.max(0, Math.min(excess, value - floor));
2782
- excess -= cut;
2783
- return value - cut;
2784
- };
2785
- const drop = (width) => {
2786
- if (excess <= 0 || width === 0) return width;
2787
- excess -= gap + width;
2788
- return 0;
2789
- };
2790
- const system = mode === "system";
2791
- const bumpFirst = system ? drop(columns.bump) : void 0;
2792
- const narrowed = system ? {
2793
- name: shrink(columns.name, Math.min(columns.name, 24)),
2794
- target: shrink(columns.target, Math.min(columns.target, 10)),
2795
- current: shrink(columns.current, 10)
2796
- } : columns;
2797
- const provider = drop(columns.provider);
2798
- const kind = bumpFirst ?? drop(columns.bump);
2799
- const target = shrink(narrowed.target, Math.min(narrowed.target, 8));
2800
- const current = shrink(narrowed.current, 8);
2801
- const roomy = shrink(narrowed.name, Math.min(narrowed.name, 18));
2802
- const status = shrink(columns.status, Math.min(columns.status, 2));
2803
- const current2 = excess > 0 && columns.target > 0 ? 0 : current;
2804
- excess -= current - current2;
2805
- return {
2806
- name: roomy - Math.max(0, Math.min(excess, roomy - 8)),
2807
- current: current2,
2808
- target,
2809
- bump: kind,
2810
- provider,
2811
- status
2812
- };
3241
+ const drop = (column) => [column, 0];
3242
+ const nameFloor = {
3243
+ roomy: 24,
3244
+ bothEnds: 18,
3245
+ last: 8
2813
3246
  };
2814
- const leastWidth = (columns, mode = "project") => {
2815
- const keeps = (fitted) => fitted.status === columns.status && fitted.current > 0 && fitted.name >= Math.min(columns.name, 24) && (mode !== "system" || fitted.provider === columns.provider);
2816
- let least = tableWidth(columns);
2817
- while (least > 0 && keeps(fitColumns(columns, least - 1, mode))) least -= 1;
2818
- return least;
3247
+ const versionFloor = {
3248
+ long: 10,
3249
+ short: 8
2819
3250
  };
2820
- const fitName = (text, width) => {
2821
- const chars = [...text];
2822
- if (chars.length <= width) return text.padEnd(width);
2823
- if (width <= 3) return fit(text, width);
2824
- const slash = text.indexOf("/");
2825
- const base = Array.from(text.slice(slash + 1));
2826
- const scope = Array.from(text.slice(0, slash));
2827
- if (text.startsWith("@") && slash > 0 && base.length + 4 <= width) {
2828
- const keep = Math.min(scope.length, width - base.length - 2);
2829
- return `${scope.slice(0, keep).join("")}…/${base.join("")}`.padEnd(width);
3251
+ const giveWayByMode = {
3252
+ system: {
3253
+ besideDetails: [
3254
+ drop("bump"),
3255
+ ["name", nameFloor.roomy],
3256
+ ["current", versionFloor.long]
3257
+ ],
3258
+ listAlone: [
3259
+ ["name", nameFloor.bothEnds],
3260
+ ["target", versionFloor.long],
3261
+ drop("provider")
3262
+ ]
3263
+ },
3264
+ project: {
3265
+ besideDetails: [
3266
+ drop("provider"),
3267
+ drop("bump"),
3268
+ ["name", nameFloor.roomy]
3269
+ ],
3270
+ listAlone: [["name", nameFloor.bothEnds]]
2830
3271
  }
2831
- const head = Math.ceil((width - 1) / 2);
2832
- const tail = width - 1 - head;
2833
- return `${chars.slice(0, head).join("")}…${chars.slice(chars.length - tail).join("")}`;
2834
3272
  };
3273
+ const lastResort = (columns) => {
3274
+ const offersVersion = columns.target > 0;
3275
+ return [
3276
+ ["current", versionFloor.short],
3277
+ ["target", versionFloor.short],
3278
+ ["status", 2],
3279
+ ...offersVersion ? [drop("current")] : [],
3280
+ ["name", nameFloor.last]
3281
+ ];
3282
+ };
3283
+ const giveWay = (columns, width, order) => {
3284
+ const fitted = { ...columns };
3285
+ for (const [column, floor] of order) {
3286
+ const excess = tableWidth(fitted) - width;
3287
+ const value = fitted[column];
3288
+ if (excess <= 0 || value === 0) continue;
3289
+ fitted[column] = floor === 0 ? 0 : value - Math.min(excess, Math.max(0, value - floor));
3290
+ }
3291
+ return fitted;
3292
+ };
3293
+ const fitColumns = (columns, width, mode = "project") => {
3294
+ const { besideDetails, listAlone } = giveWayByMode[mode];
3295
+ return giveWay(columns, width, [
3296
+ ...besideDetails,
3297
+ ...listAlone,
3298
+ ...lastResort(columns)
3299
+ ]);
3300
+ };
3301
+ const leastWidth = (columns, mode = "project") => tableWidth(giveWay(columns, 0, giveWayByMode[mode].besideDetails));
2835
3302
  const pad = " ".repeat(gap);
3303
+ const targetText = (text, room) => fit(text, room).trimEnd();
2836
3304
  const labels = (columns, filled) => [
2837
- fit("Version", columns.current + (columns.target === 0 ? 0 : 3 + columns.target)),
3305
+ `${" ".repeat(Math.max(0, columns.current - 7))}${fit("Version", Math.min(columns.current, 7) + (columns.target === 0 ? 0 : 3 + columns.target))}`,
2838
3306
  columns.bump === 0 ? "" : pad + fit(filled.bump ? "Bump" : "", columns.bump),
2839
3307
  columns.provider === 0 ? "" : pad + fit("Provider", columns.provider),
2840
3308
  columns.status === 0 ? "" : pad + fit(filled.status ? "Status" : "", columns.status)
2841
3309
  ].join("").trimEnd();
2842
- function Heading(props) {
3310
+ const Heading = (props) => {
2843
3311
  const updates = () => props.group.kind === "updates";
2844
3312
  const folds = () => props.group.kind === "current";
2845
3313
  const hinted = () => folds() && !props.typing;
2846
- const used = () => 2 + Array.from(props.group.title).length + ` ${props.group.rows.length}`.length + (props.selected > 0 ? ` · ${props.selected} selected`.length : 0) + (hinted() ? ` ${keys.fold.hint ?? ""} show`.length + 2 : 0);
3314
+ const foldMark = () => {
3315
+ if (!folds()) return " ";
3316
+ return props.group.collapsed === true ? "▸ " : "▾ ";
3317
+ };
3318
+ const used = () => 2 + graphemes(props.group.title).length + ` ${props.group.rows.length}`.length + (props.selected > 0 ? ` · ${props.selected} selected`.length : 0) + (hinted() ? ` ${keys.fold.hint ?? ""} show`.length + 2 : 0);
2847
3319
  const start = () => prefix + props.columns.name + gap;
2848
3320
  return (() => {
2849
3321
  var _el$ = createElement("box"), _el$2 = createElement("text"), _el$3 = createElement("text"), _el$4 = createElement("text");
@@ -2853,10 +3325,7 @@ function Heading(props) {
2853
3325
  setProp(_el$, "flexDirection", "row");
2854
3326
  setProp(_el$, "height", 1);
2855
3327
  setProp(_el$2, "flexShrink", 0);
2856
- insert(_el$2, (() => {
2857
- var _c$ = memo(() => !!folds());
2858
- return () => _c$() ? props.group.collapsed === true ? "▸ " : "▾ " : " ";
2859
- })());
3328
+ insert(_el$2, foldMark);
2860
3329
  setProp(_el$3, "flexShrink", 0);
2861
3330
  insert(_el$3, () => props.group.title);
2862
3331
  setProp(_el$4, "flexShrink", 0);
@@ -2897,7 +3366,7 @@ function Heading(props) {
2897
3366
  var _el$8 = createElement("text");
2898
3367
  setProp(_el$8, "flexShrink", 0);
2899
3368
  insert(_el$8, () => props.group.collapsed === true ? " show" : " hide");
2900
- effect((_$p) => setProp(_el$8, "fg", theme.faint, _$p));
3369
+ effect((_$p) => setProp(_el$8, "fg", theme.muted, _$p));
2901
3370
  return _el$8;
2902
3371
  })()
2903
3372
  ];
@@ -2913,12 +3382,12 @@ function Heading(props) {
2913
3382
  setProp(_el$9, "wrapMode", "none");
2914
3383
  setProp(_el$9, "truncate", true);
2915
3384
  insert(_el$9, () => " ".repeat(start() - used()) + labels(props.columns, props.filled));
2916
- effect((_$p) => setProp(_el$9, "fg", theme.faint, _$p));
3385
+ effect((_$p) => setProp(_el$9, "fg", theme.muted, _$p));
2917
3386
  return _el$9;
2918
3387
  }
2919
3388
  }), null);
2920
3389
  effect((_p$) => {
2921
- var _v$ = theme.faint, _v$2 = updates() ? theme.accent : theme.muted, _v$3 = TextAttributes.BOLD, _v$4 = theme.faint;
3390
+ var _v$ = theme.muted, _v$2 = updates() ? theme.accent : theme.muted, _v$3 = TextAttributes.BOLD, _v$4 = theme.muted;
2922
3391
  _v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
2923
3392
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
2924
3393
  _v$3 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$3, _p$.a));
@@ -2932,111 +3401,36 @@ function Heading(props) {
2932
3401
  });
2933
3402
  return _el$;
2934
3403
  })();
2935
- }
2936
- function Inventory(props) {
2937
- const visible = () => props.lines.slice(props.offset, props.offset + props.height);
2938
- return (() => {
2939
- var _el$0 = createElement("box");
2940
- setProp(_el$0, "flexDirection", "column");
2941
- insert(_el$0, createComponent(For, {
2942
- get each() {
2943
- return visible();
2944
- },
2945
- children: (line) => createComponent(Switch, { get children() {
2946
- return [
2947
- createComponent(Match, {
2948
- get when() {
2949
- return line._tag === "Gap";
2950
- },
2951
- get children() {
2952
- var _el$1 = createElement("text");
2953
- insertNode(_el$1, createTextNode(` `));
2954
- return _el$1;
2955
- }
2956
- }),
2957
- createComponent(Match, {
2958
- get when() {
2959
- return memo(() => line._tag === "Heading")() ? line.group : void 0;
2960
- },
2961
- children: (group) => createComponent(Heading, {
2962
- get group() {
2963
- return group();
2964
- },
2965
- get columns() {
2966
- return props.columns;
2967
- },
2968
- get filled() {
2969
- return {
2970
- bump: group().kind === "updates",
2971
- status: visibleRows(group()).some((row) => status(props.state, row).text !== "")
2972
- };
2973
- },
2974
- get typing() {
2975
- return props.typing;
2976
- },
2977
- get selected() {
2978
- return group().rows.filter((row) => props.state.selected.includes(row.key)).length;
2979
- }
2980
- })
2981
- }),
2982
- createComponent(Match, {
2983
- get when() {
2984
- return line._tag === "Package" ? line : void 0;
2985
- },
2986
- children: (found) => createComponent(PackageLine, {
2987
- get row() {
2988
- return found().row;
2989
- },
2990
- get state() {
2991
- return props.state;
2992
- },
2993
- get columns() {
2994
- return props.columns;
2995
- },
2996
- get focused() {
2997
- return found().index === props.cursor;
2998
- }
2999
- })
3000
- })
3001
- ];
3002
- } })
3003
- }));
3004
- effect((_$p) => setProp(_el$0, "flexGrow", props.lines.length === 0 ? 0 : 1, _$p));
3404
+ };
3405
+ const Cell = (props) => createComponent(Show, {
3406
+ get when() {
3407
+ return props.text !== "";
3408
+ },
3409
+ get children() {
3410
+ var _el$0 = createElement("text");
3411
+ setProp(_el$0, "flexShrink", 0);
3412
+ setProp(_el$0, "wrapMode", "none");
3413
+ insert(_el$0, () => props.text);
3414
+ effect((_p$) => {
3415
+ var _v$5 = props.color, _v$6 = props.bold === true ? TextAttributes.BOLD : TextAttributes.NONE;
3416
+ _v$5 !== _p$.e && (_p$.e = setProp(_el$0, "fg", _v$5, _p$.e));
3417
+ _v$6 !== _p$.t && (_p$.t = setProp(_el$0, "attributes", _v$6, _p$.t));
3418
+ return _p$;
3419
+ }, {
3420
+ e: void 0,
3421
+ t: void 0
3422
+ });
3005
3423
  return _el$0;
3006
- })();
3007
- }
3008
- function Cell(props) {
3009
- return createComponent(Show, {
3010
- get when() {
3011
- return props.text !== "";
3012
- },
3013
- get children() {
3014
- var _el$11 = createElement("text");
3015
- setProp(_el$11, "flexShrink", 0);
3016
- setProp(_el$11, "wrapMode", "none");
3017
- insert(_el$11, () => props.text);
3018
- effect((_p$) => {
3019
- var _v$5 = props.color, _v$6 = props.bold === true ? TextAttributes.BOLD : TextAttributes.NONE;
3020
- _v$5 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$5, _p$.e));
3021
- _v$6 !== _p$.t && (_p$.t = setProp(_el$11, "attributes", _v$6, _p$.t));
3022
- return _p$;
3023
- }, {
3024
- e: void 0,
3025
- t: void 0
3026
- });
3027
- return _el$11;
3028
- }
3029
- });
3030
- }
3031
- function PackageLine(props) {
3424
+ }
3425
+ });
3426
+ const PackageLine = (props) => {
3032
3427
  const pkg = () => props.row.pkg;
3033
3428
  const selected = () => props.state.selected.includes(props.row.key);
3034
3429
  const shown = () => status(props.state, props.row);
3035
3430
  const change = () => {
3036
- const target = pkg().target;
3037
- return target === void 0 ? void 0 : bump(pkg().current, target);
3431
+ const { target } = pkg();
3432
+ return target === void 0 ? void 0 : bump(pkg().current, target, pkg().ecosystem);
3038
3433
  };
3039
- const targetText = (text, room) => fit(text, room).trimEnd();
3040
3434
  const outcome = () => props.state.outcomes[props.row.key];
3041
3435
  const marker = () => {
3042
3436
  if (selected()) return {
@@ -3045,7 +3439,7 @@ function PackageLine(props) {
3045
3439
  };
3046
3440
  if (props.state.removed[props.row.key] !== void 0) return {
3047
3441
  text: "–",
3048
- color: theme.faint
3442
+ color: theme.muted
3049
3443
  };
3050
3444
  const done = outcome();
3051
3445
  if (done !== void 0) return {
@@ -3054,14 +3448,31 @@ function PackageLine(props) {
3054
3448
  };
3055
3449
  return {
3056
3450
  text: "○",
3057
- color: props.focused ? theme.muted : theme.faint
3451
+ color: theme.muted
3058
3452
  };
3059
3453
  };
3454
+ const background = () => {
3455
+ if (props.focused) return theme.cursor;
3456
+ return selected() ? theme.selected : theme.none;
3457
+ };
3458
+ const nameColor = () => {
3459
+ if (selected()) return theme.accent;
3460
+ if (props.state.removed[props.row.key] !== void 0) return theme.muted;
3461
+ return props.focused ? theme.strong : theme.text;
3462
+ };
3463
+ const bumpText = () => {
3464
+ const changed = change();
3465
+ return changed === void 0 ? "" : bumpLabel(changed);
3466
+ };
3467
+ const bumpColor = () => {
3468
+ const changed = change();
3469
+ return changed === void 0 ? theme.muted : bumpTone(changed);
3470
+ };
3060
3471
  return (() => {
3061
- var _el$12 = createElement("box");
3062
- setProp(_el$12, "flexDirection", "row");
3063
- setProp(_el$12, "height", 1);
3064
- insert(_el$12, createComponent(Cell, {
3472
+ var _el$1 = createElement("box");
3473
+ setProp(_el$1, "flexDirection", "row");
3474
+ setProp(_el$1, "height", 1);
3475
+ insert(_el$1, createComponent(Cell, {
3065
3476
  get text() {
3066
3477
  return props.focused ? "▌" : " ";
3067
3478
  },
@@ -3069,13 +3480,13 @@ function PackageLine(props) {
3069
3480
  return theme.accent;
3070
3481
  }
3071
3482
  }), null);
3072
- insert(_el$12, createComponent(Cell, {
3483
+ insert(_el$1, createComponent(Cell, {
3073
3484
  text: " ",
3074
3485
  get color() {
3075
3486
  return theme.text;
3076
3487
  }
3077
3488
  }), null);
3078
- insert(_el$12, createComponent(Cell, {
3489
+ insert(_el$1, createComponent(Cell, {
3079
3490
  get text() {
3080
3491
  return marker().text;
3081
3492
  },
@@ -3084,31 +3495,31 @@ function PackageLine(props) {
3084
3495
  },
3085
3496
  bold: true
3086
3497
  }), null);
3087
- insert(_el$12, createComponent(Cell, {
3498
+ insert(_el$1, createComponent(Cell, {
3088
3499
  text: " ",
3089
3500
  get color() {
3090
3501
  return theme.text;
3091
3502
  }
3092
3503
  }), null);
3093
- insert(_el$12, createComponent(Cell, {
3504
+ insert(_el$1, createComponent(Cell, {
3094
3505
  get text() {
3095
3506
  return fitName(pkg().name, props.columns.name) + pad;
3096
3507
  },
3097
3508
  get color() {
3098
- return memo(() => !!selected())() ? theme.accent : memo(() => props.state.removed[props.row.key] !== void 0)() ? theme.faint : memo(() => !!props.focused)() ? theme.strong : theme.text;
3509
+ return nameColor();
3099
3510
  },
3100
3511
  get bold() {
3101
3512
  return selected() || props.focused;
3102
3513
  }
3103
3514
  }), null);
3104
- insert(_el$12, createComponent(Show, {
3515
+ insert(_el$1, createComponent(Show, {
3105
3516
  get when() {
3106
3517
  return props.columns.current > 0;
3107
3518
  },
3108
3519
  get children() {
3109
3520
  return createComponent(Cell, {
3110
3521
  get text() {
3111
- return fit(pkg().current, props.columns.current);
3522
+ return fit(pkg().current, props.columns.current, "end");
3112
3523
  },
3113
3524
  get color() {
3114
3525
  return theme.muted;
@@ -3116,7 +3527,7 @@ function PackageLine(props) {
3116
3527
  });
3117
3528
  }
3118
3529
  }), null);
3119
- insert(_el$12, createComponent(Show, {
3530
+ insert(_el$1, createComponent(Show, {
3120
3531
  get when() {
3121
3532
  return props.columns.target > 0;
3122
3533
  },
@@ -3136,16 +3547,16 @@ function PackageLine(props) {
3136
3547
  });
3137
3548
  },
3138
3549
  children: (changed) => (() => {
3139
- var _el$13 = createElement("box");
3140
- setProp(_el$13, "flexDirection", "row");
3141
- setProp(_el$13, "flexShrink", 0);
3142
- insert(_el$13, createComponent(Cell, {
3550
+ var _el$10 = createElement("box");
3551
+ setProp(_el$10, "flexDirection", "row");
3552
+ setProp(_el$10, "flexShrink", 0);
3553
+ insert(_el$10, createComponent(Cell, {
3143
3554
  text: arrow,
3144
3555
  get color() {
3145
- return theme.faint;
3556
+ return theme.muted;
3146
3557
  }
3147
3558
  }), null);
3148
- insert(_el$13, createComponent(Cell, {
3559
+ insert(_el$10, createComponent(Cell, {
3149
3560
  get text() {
3150
3561
  return targetText(changed().same, props.columns.target);
3151
3562
  },
@@ -3153,39 +3564,39 @@ function PackageLine(props) {
3153
3564
  return theme.muted;
3154
3565
  }
3155
3566
  }), null);
3156
- insert(_el$13, createComponent(Cell, {
3567
+ insert(_el$10, createComponent(Cell, {
3157
3568
  get text() {
3158
- return targetText(changed().changed, Math.max(0, props.columns.target - [...changed().same].length));
3569
+ return targetText(changed().changed, Math.max(0, props.columns.target - graphemes(changed().same).length));
3159
3570
  },
3160
3571
  get color() {
3161
3572
  return theme.strong;
3162
3573
  },
3163
3574
  bold: true
3164
3575
  }), null);
3165
- insert(_el$13, createComponent(Cell, {
3576
+ insert(_el$10, createComponent(Cell, {
3166
3577
  get text() {
3167
- return " ".repeat(Math.max(0, props.columns.target - [...changed().same, ...changed().changed].length));
3578
+ return " ".repeat(Math.max(0, props.columns.target - (graphemes(changed().same).length + graphemes(changed().changed).length)));
3168
3579
  },
3169
3580
  get color() {
3170
3581
  return theme.text;
3171
3582
  }
3172
3583
  }), null);
3173
- return _el$13;
3584
+ return _el$10;
3174
3585
  })()
3175
3586
  });
3176
3587
  }
3177
3588
  }), null);
3178
- insert(_el$12, createComponent(Show, {
3589
+ insert(_el$1, createComponent(Show, {
3179
3590
  get when() {
3180
3591
  return props.columns.bump > 0;
3181
3592
  },
3182
3593
  get children() {
3183
3594
  return createComponent(Cell, {
3184
3595
  get text() {
3185
- return pad + fit(change() === void 0 ? "" : bumpLabel(change()), props.columns.bump);
3596
+ return pad + fit(bumpText(), props.columns.bump);
3186
3597
  },
3187
3598
  get color() {
3188
- return memo(() => change() === void 0)() ? theme.faint : bumpTone(change());
3599
+ return bumpColor();
3189
3600
  },
3190
3601
  get bold() {
3191
3602
  return change()?.risk === "major";
@@ -3193,22 +3604,22 @@ function PackageLine(props) {
3193
3604
  });
3194
3605
  }
3195
3606
  }), null);
3196
- insert(_el$12, createComponent(Show, {
3607
+ insert(_el$1, createComponent(Show, {
3197
3608
  get when() {
3198
3609
  return props.columns.provider > 0;
3199
3610
  },
3200
3611
  get children() {
3201
3612
  return createComponent(Cell, {
3202
3613
  get text() {
3203
- return pad + fit(providerLabel(pkg().provider), props.columns.provider);
3614
+ return pad + fitName(providerLabel(pkg().provider), props.columns.provider);
3204
3615
  },
3205
3616
  get color() {
3206
- return theme.faint;
3617
+ return theme.muted;
3207
3618
  }
3208
3619
  });
3209
3620
  }
3210
3621
  }), null);
3211
- insert(_el$12, createComponent(Show, {
3622
+ insert(_el$1, createComponent(Show, {
3212
3623
  get when() {
3213
3624
  return props.columns.status > 0;
3214
3625
  },
@@ -3246,11 +3657,83 @@ function PackageLine(props) {
3246
3657
  ];
3247
3658
  }
3248
3659
  }), null);
3249
- effect((_$p) => setProp(_el$12, "backgroundColor", props.focused ? theme.cursor : selected() ? theme.selected : theme.none, _$p));
3250
- return _el$12;
3660
+ effect((_$p) => setProp(_el$1, "backgroundColor", background(), _$p));
3661
+ return _el$1;
3662
+ })();
3663
+ };
3664
+ const Inventory = (props) => {
3665
+ const visible = () => props.lines.slice(props.offset, props.offset + props.height);
3666
+ return (() => {
3667
+ var _el$11 = createElement("box");
3668
+ setProp(_el$11, "flexDirection", "column");
3669
+ insert(_el$11, createComponent(For, {
3670
+ get each() {
3671
+ return visible();
3672
+ },
3673
+ children: (line) => createComponent(Switch, { get children() {
3674
+ return [
3675
+ createComponent(Match, {
3676
+ get when() {
3677
+ return line._tag === "Gap";
3678
+ },
3679
+ get children() {
3680
+ var _el$12 = createElement("text");
3681
+ insertNode(_el$12, createTextNode(` `));
3682
+ return _el$12;
3683
+ }
3684
+ }),
3685
+ createComponent(Match, {
3686
+ get when() {
3687
+ return memo(() => line._tag === "Heading")() ? line.group : void 0;
3688
+ },
3689
+ children: (group) => createComponent(Heading, {
3690
+ get group() {
3691
+ return group();
3692
+ },
3693
+ get columns() {
3694
+ return props.columns;
3695
+ },
3696
+ get filled() {
3697
+ return {
3698
+ bump: group().kind === "updates",
3699
+ status: visibleRows(group()).some((row) => status(props.state, row).text !== "")
3700
+ };
3701
+ },
3702
+ get typing() {
3703
+ return props.typing;
3704
+ },
3705
+ get selected() {
3706
+ return group().rows.filter((row) => props.state.selected.includes(row.key)).length;
3707
+ }
3708
+ })
3709
+ }),
3710
+ createComponent(Match, {
3711
+ get when() {
3712
+ return line._tag === "Package" ? line : void 0;
3713
+ },
3714
+ children: (found) => createComponent(PackageLine, {
3715
+ get row() {
3716
+ return found().row;
3717
+ },
3718
+ get state() {
3719
+ return props.state;
3720
+ },
3721
+ get columns() {
3722
+ return props.columns;
3723
+ },
3724
+ get focused() {
3725
+ return found().index === props.cursor;
3726
+ }
3727
+ })
3728
+ })
3729
+ ];
3730
+ } })
3731
+ }));
3732
+ effect((_$p) => setProp(_el$11, "flexGrow", props.lines.length === 0 ? 0 : 1, _$p));
3733
+ return _el$11;
3251
3734
  })();
3252
- }
3253
- function Empty(props) {
3735
+ };
3736
+ const Empty = (props) => {
3254
3737
  const problems = () => [...props.state.discoveryError === void 0 ? [] : [describeError(props.state.discoveryError)], ...props.state.providers.flatMap((entry) => entry.error === void 0 ? [] : [`${providerLabel(entry.name)}: ${describeError(entry.error)}`])];
3255
3738
  return (() => {
3256
3739
  var _el$14 = createElement("box");
@@ -3349,11 +3832,11 @@ function Empty(props) {
3349
3832
  insert(_el$36, () => ` ${providerLabel(entry.name).padEnd(16)}`);
3350
3833
  setProp(_el$37, "flexShrink", 0);
3351
3834
  insert(_el$37, (() => {
3352
- var _c$2 = memo(() => entry.status === "ready");
3353
- return () => _c$2() ? `${entry.packages.length}` : "";
3835
+ var _c$ = memo(() => entry.status === "ready");
3836
+ return () => _c$() ? `${entry.packages.length}` : "";
3354
3837
  })());
3355
3838
  effect((_p$) => {
3356
- var _v$7 = theme.text, _v$8 = theme.faint;
3839
+ var _v$7 = theme.text, _v$8 = theme.muted;
3357
3840
  _v$7 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$7, _p$.e));
3358
3841
  _v$8 !== _p$.t && (_p$.t = setProp(_el$37, "fg", _v$8, _p$.t));
3359
3842
  return _p$;
@@ -3423,72 +3906,29 @@ function Empty(props) {
3423
3906
  })(), (() => {
3424
3907
  var _el$27 = createElement("text");
3425
3908
  insertNode(_el$27, createTextNode(`Press m to see the tools installed on this machine.`));
3426
- effect((_$p) => setProp(_el$27, "fg", theme.faint, _$p));
3909
+ effect((_$p) => setProp(_el$27, "fg", theme.muted, _$p));
3427
3910
  return _el$27;
3428
3911
  })()];
3429
3912
  }
3430
- }),
3431
- createComponent(Match, {
3432
- get when() {
3433
- return props.state.mode === "system";
3434
- },
3435
- get children() {
3436
- var _el$29 = createElement("text");
3437
- insertNode(_el$29, createTextNode(`No package managers reported any installed tools.`));
3438
- effect((_$p) => setProp(_el$29, "fg", theme.text, _$p));
3439
- return _el$29;
3440
- }
3441
- })
3442
- ];
3443
- } }));
3444
- return _el$14;
3445
- })();
3446
- }
3447
- // src/tui/Segments.tsx
3448
- const segment = (color, text, bold = false) => ({
3449
- text,
3450
- color,
3451
- bold
3452
- });
3453
- const shrinking = (color, text, bold = false) => ({
3454
- ...segment(color, text, bold),
3455
- shrink: true
3456
- });
3457
- function Segments(props) {
3458
- return (() => {
3459
- var _el$ = createElement("box");
3460
- setProp(_el$, "flexDirection", "row");
3461
- setProp(_el$, "height", 1);
3462
- insert(_el$, createComponent(For, {
3463
- get each() {
3464
- return props.segments;
3465
- },
3466
- children: (part) => (() => {
3467
- var _el$2 = createElement("text");
3468
- setProp(_el$2, "wrapMode", "none");
3469
- insert(_el$2, () => part.text);
3470
- effect((_p$) => {
3471
- var _v$ = part.color, _v$2 = part.shrink === true ? 1 : 0, _v$3 = part.shrink === true, _v$4 = part.bold === true ? TextAttributes.BOLD : TextAttributes.NONE;
3472
- _v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
3473
- _v$2 !== _p$.t && (_p$.t = setProp(_el$2, "flexShrink", _v$2, _p$.t));
3474
- _v$3 !== _p$.a && (_p$.a = setProp(_el$2, "truncate", _v$3, _p$.a));
3475
- _v$4 !== _p$.o && (_p$.o = setProp(_el$2, "attributes", _v$4, _p$.o));
3476
- return _p$;
3477
- }, {
3478
- e: void 0,
3479
- t: void 0,
3480
- a: void 0,
3481
- o: void 0
3482
- });
3483
- return _el$2;
3484
- })()
3485
- }));
3486
- effect((_$p) => setProp(_el$, "backgroundColor", props.background ?? theme.none, _$p));
3487
- return _el$;
3913
+ }),
3914
+ createComponent(Match, {
3915
+ get when() {
3916
+ return props.state.mode === "system";
3917
+ },
3918
+ get children() {
3919
+ var _el$29 = createElement("text");
3920
+ insertNode(_el$29, createTextNode(`No package managers reported any installed tools.`));
3921
+ effect((_$p) => setProp(_el$29, "fg", theme.text, _$p));
3922
+ return _el$29;
3923
+ }
3924
+ })
3925
+ ];
3926
+ } }));
3927
+ return _el$14;
3488
3928
  })();
3489
- }
3929
+ };
3490
3930
  // src/tui/Password.tsx
3491
- function PasswordPopup(props) {
3931
+ const PasswordPopup = (props) => {
3492
3932
  const [entry, setEntry] = createSignal("");
3493
3933
  useKeyboard((key) => {
3494
3934
  if (key.name === "escape") props.answer(void 0);
@@ -3503,7 +3943,9 @@ function PasswordPopup(props) {
3503
3943
  if (char !== void 0) setEntry((text) => text + char);
3504
3944
  }
3505
3945
  });
3506
- usePaste((event) => setEntry((text) => text + pasted(event.bytes)));
3946
+ usePaste((event) => {
3947
+ setEntry((text) => text + pasted(event.bytes));
3948
+ });
3507
3949
  return createComponent(Popup, {
3508
3950
  title: "Password needed",
3509
3951
  tone: "warn",
@@ -3532,16 +3974,17 @@ function PasswordPopup(props) {
3532
3974
  })(),
3533
3975
  (() => {
3534
3976
  var _el$4 = createElement("text");
3535
- insert(_el$4, () => `${"•".repeat([...entry()].length)}▏`);
3977
+ insert(_el$4, () => `${"•".repeat(graphemes(entry()).length)}▏`);
3536
3978
  effect((_$p) => setProp(_el$4, "fg", theme.text, _$p));
3537
3979
  return _el$4;
3538
3980
  })()
3539
3981
  ];
3540
3982
  }
3541
3983
  });
3542
- }
3984
+ };
3543
3985
  // src/tui/Settings.tsx
3544
3986
  const listHeight = 10;
3987
+ const width$1 = 84;
3545
3988
  const menu = [
3546
3989
  "model",
3547
3990
  "thinking",
@@ -3557,7 +4000,7 @@ const binding = (hint, description) => ({
3557
4000
  hint,
3558
4001
  description
3559
4002
  });
3560
- function SettingsPopup(props) {
4003
+ const SettingsPopup = (props) => {
3561
4004
  const [mode, setMode] = createSignal({ _tag: "Menu" });
3562
4005
  const [row, setRow] = createSignal(0);
3563
4006
  const [filter, setFilter] = createSignal("");
@@ -3572,10 +4015,11 @@ function SettingsPopup(props) {
3572
4015
  const chosen = current();
3573
4016
  return chosen !== void 0 && !chosen.signedIn ? chosen : void 0;
3574
4017
  };
3575
- const ordered = createMemo(() => {
3576
- const standing = (choice) => choice === current() ? 0 : choice.signedIn ? 1 : 2;
3577
- return catalogue().toSorted((left, right) => standing(left) - standing(right));
3578
- });
4018
+ const standing = (choice) => {
4019
+ if (choice === current()) return 0;
4020
+ return choice.signedIn ? 1 : 2;
4021
+ };
4022
+ const ordered = createMemo(() => catalogue().toSorted((left, right) => standing(left) - standing(right)));
3579
4023
  const matching = createMemo(() => {
3580
4024
  const words = filter().toLowerCase().split(/\s+/u).filter(Boolean);
3581
4025
  return ordered().filter((choice) => {
@@ -3678,16 +4122,16 @@ function SettingsPopup(props) {
3678
4122
  if (char !== void 0) setEntry((text) => text + char);
3679
4123
  }
3680
4124
  };
4125
+ const cancel = () => {
4126
+ props.run(props.session.closeSignIn);
4127
+ setMode({ _tag: "Picker" });
4128
+ };
3681
4129
  const onSignIn = (key, signIn) => {
3682
- const cancel = () => {
3683
- props.run(props.session.closeSignIn);
3684
- setMode({ _tag: "Picker" });
3685
- };
3686
4130
  if (signIn?._tag !== "Working" || signIn.prompt === void 0) {
3687
4131
  if (key.name === "escape") cancel();
3688
4132
  return;
3689
4133
  }
3690
- const prompt = signIn.prompt;
4134
+ const { prompt } = signIn;
3691
4135
  if (prompt.type === "select") {
3692
4136
  if (key.name === "escape") cancel();
3693
4137
  else if (key.name === "down") setPicked((index) => Math.min(prompt.options.length - 1, index + 1));
@@ -3706,22 +4150,32 @@ function SettingsPopup(props) {
3706
4150
  useKeyboard((key) => {
3707
4151
  const now = mode();
3708
4152
  switch (now._tag) {
3709
- case "Menu": return onMenu(key);
3710
- case "Picker": return onPicker(key);
3711
- case "Method": return onMethod(key, now.choice);
3712
- case "Key": return onEntry(key, (text) => {
3713
- if (text.trim() === "") return;
3714
- props.run(props.session.saveKey(now.choice.provider, text.trim()));
3715
- setEntry("");
3716
- setMode({
3717
- _tag: "SigningIn",
3718
- choice: now.choice
4153
+ case "Menu":
4154
+ onMenu(key);
4155
+ return;
4156
+ case "Picker":
4157
+ onPicker(key);
4158
+ return;
4159
+ case "Method":
4160
+ onMethod(key, now.choice);
4161
+ return;
4162
+ case "Key":
4163
+ onEntry(key, (text) => {
4164
+ if (text.trim() === "") return;
4165
+ props.run(props.session.saveKey(now.choice.provider, text.trim()));
4166
+ setEntry("");
4167
+ setMode({
4168
+ _tag: "SigningIn",
4169
+ choice: now.choice
4170
+ });
4171
+ }, () => {
4172
+ setMode({
4173
+ _tag: "Method",
4174
+ choice: now.choice
4175
+ });
3719
4176
  });
3720
- }, () => setMode({
3721
- _tag: "Method",
3722
- choice: now.choice
3723
- }));
3724
- case "SigningIn": return onSignIn(key, props.state.signIn);
4177
+ return;
4178
+ case "SigningIn": onSignIn(key, props.state.signIn);
3725
4179
  }
3726
4180
  });
3727
4181
  const modelLabel = () => {
@@ -3730,27 +4184,38 @@ function SettingsPopup(props) {
3730
4184
  const known = current();
3731
4185
  return known === void 0 ? `${chosen.provider}/${chosen.modelId}` : `${known.providerName} · ${known.name}`;
3732
4186
  };
4187
+ const compact = useCompact();
4188
+ const dimensions = useTerminalDimensions();
4189
+ const room = (before) => bodyWidth(width$1, dimensions().width) - before;
3733
4190
  const menuLine = (index, label, value, color, help) => (() => {
3734
- var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text");
3735
- insertNode(_el$, _el$2);
4191
+ var _el$ = createElement("box");
3736
4192
  setProp(_el$, "flexDirection", "column");
3737
- setProp(_el$, "marginBottom", 1);
3738
4193
  insert(_el$, createComponent(Segments, { get segments() {
3739
4194
  return [
3740
4195
  segment(theme.accent, row() === index ? "▌ " : " "),
3741
4196
  segment(row() === index ? theme.strong : theme.muted, label.padEnd(14), row() === index),
3742
- shrinking(color, value, true)
4197
+ segment(color, clip(value, room(16)), true)
3743
4198
  ];
3744
- } }), _el$2);
3745
- insertNode(_el$2, _el$3);
3746
- setProp(_el$2, "paddingLeft", 16);
3747
- setProp(_el$2, "paddingRight", 1);
3748
- setProp(_el$3, "wrapMode", "word");
3749
- insert(_el$3, help);
4199
+ } }), null);
4200
+ insert(_el$, createComponent(Show, {
4201
+ get when() {
4202
+ return !compact();
4203
+ },
4204
+ get children() {
4205
+ var _el$2 = createElement("box"), _el$3 = createElement("text");
4206
+ insertNode(_el$2, _el$3);
4207
+ setProp(_el$2, "paddingLeft", 16);
4208
+ setProp(_el$2, "paddingRight", 1);
4209
+ setProp(_el$3, "wrapMode", "word");
4210
+ insert(_el$3, help);
4211
+ effect((_$p) => setProp(_el$3, "fg", theme.muted, _$p));
4212
+ return _el$2;
4213
+ }
4214
+ }), null);
3750
4215
  effect((_p$) => {
3751
- var _v$ = row() === index ? theme.cursor : theme.none, _v$2 = theme.muted;
3752
- _v$ !== _p$.e && (_p$.e = setProp(_el$, "backgroundColor", _v$, _p$.e));
3753
- _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
4216
+ var _v$ = index === menu.length - 1 ? 0 : 1, _v$2 = row() === index ? theme.cursor : theme.none;
4217
+ _v$ !== _p$.e && (_p$.e = setProp(_el$, "marginBottom", _v$, _p$.e));
4218
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$, "backgroundColor", _v$2, _p$.t));
3754
4219
  return _p$;
3755
4220
  }, {
3756
4221
  e: void 0,
@@ -3758,7 +4223,7 @@ function SettingsPopup(props) {
3758
4223
  });
3759
4224
  return _el$;
3760
4225
  })();
3761
- const masked = () => "•".repeat([...entry()].length);
4226
+ const masked = () => "•".repeat(graphemes(entry()).length);
3762
4227
  const method = () => {
3763
4228
  const now = mode();
3764
4229
  return now._tag === "Method" ? now : void 0;
@@ -3786,9 +4251,9 @@ function SettingsPopup(props) {
3786
4251
  const text = pasted(event.bytes);
3787
4252
  const now = mode();
3788
4253
  if (now._tag === "Picker") {
3789
- setFilter((current) => current + text);
4254
+ setFilter((previous) => previous + text);
3790
4255
  setCursor(0);
3791
- } else if (now._tag === "Key" || now._tag === "SigningIn" && selecting() === void 0) setEntry((current) => current + text);
4256
+ } else if (now._tag === "Key" || now._tag === "SigningIn" && selecting() === void 0) setEntry((previous) => previous + text);
3792
4257
  });
3793
4258
  return createComponent(Switch, { get children() {
3794
4259
  return [
@@ -3799,7 +4264,7 @@ function SettingsPopup(props) {
3799
4264
  get children() {
3800
4265
  return createComponent(Popup, {
3801
4266
  title: "Settings",
3802
- width: 76,
4267
+ width: width$1,
3803
4268
  get bindings() {
3804
4269
  return [
3805
4270
  keys.up,
@@ -3818,20 +4283,14 @@ function SettingsPopup(props) {
3818
4283
  return props.state.settingsIssue;
3819
4284
  },
3820
4285
  children: (issue) => (() => {
3821
- var _el$8 = createElement("text");
3822
- setProp(_el$8, "wrapMode", "word");
3823
- insert(_el$8, issue);
3824
- effect((_$p) => setProp(_el$8, "fg", theme.danger, _$p));
3825
- return _el$8;
4286
+ var _el$6 = createElement("text");
4287
+ setProp(_el$6, "wrapMode", "word");
4288
+ setProp(_el$6, "marginTop", 1);
4289
+ insert(_el$6, issue);
4290
+ effect((_$p) => setProp(_el$6, "fg", theme.danger, _$p));
4291
+ return _el$6;
3826
4292
  })()
3827
- }),
3828
- (() => {
3829
- var _el$4 = createElement("text");
3830
- insertNode(_el$4, createTextNode(`Credentials are shared with pi through its auth.json.`));
3831
- setProp(_el$4, "wrapMode", "word");
3832
- effect((_$p) => setProp(_el$4, "fg", theme.faint, _$p));
3833
- return _el$4;
3834
- })()
4293
+ })
3835
4294
  ];
3836
4295
  }
3837
4296
  });
@@ -3844,7 +4303,7 @@ function SettingsPopup(props) {
3844
4303
  get children() {
3845
4304
  return createComponent(Popup, {
3846
4305
  title: "Audit model",
3847
- width: 84,
4306
+ width: width$1,
3848
4307
  get bindings() {
3849
4308
  return [
3850
4309
  binding("type", "filter"),
@@ -3855,20 +4314,20 @@ function SettingsPopup(props) {
3855
4314
  },
3856
4315
  get children() {
3857
4316
  return [(() => {
3858
- var _el$6 = createElement("text");
3859
- insert(_el$6, () => `/${filter()}▏`);
3860
- effect((_$p) => setProp(_el$6, "fg", theme.text, _$p));
3861
- return _el$6;
4317
+ var _el$4 = createElement("text");
4318
+ insert(_el$4, () => `/${filter()}▏`);
4319
+ effect((_$p) => setProp(_el$4, "fg", theme.text, _$p));
4320
+ return _el$4;
3862
4321
  })(), createComponent(Show, {
3863
4322
  get when() {
3864
4323
  return props.state.catalogue?._tag === "Ready";
3865
4324
  },
3866
4325
  get fallback() {
3867
4326
  return (() => {
3868
- var _el$9 = createElement("text");
3869
- insertNode(_el$9, createTextNode(`Reading pi-ai's catalogue…`));
3870
- effect((_$p) => setProp(_el$9, "fg", theme.faint, _$p));
3871
- return _el$9;
4327
+ var _el$7 = createElement("text");
4328
+ insertNode(_el$7, createTextNode(`Reading pi-ai's catalogue…`));
4329
+ effect((_$p) => setProp(_el$7, "fg", theme.muted, _$p));
4330
+ return _el$7;
3872
4331
  })();
3873
4332
  },
3874
4333
  get children() {
@@ -3882,18 +4341,18 @@ function SettingsPopup(props) {
3882
4341
  },
3883
4342
  get segments() {
3884
4343
  return [
3885
- segment(choice === current() ? theme.accent : theme.faint, choice === current() ? "● " : " "),
3886
- segment(choice.signedIn ? theme.ok : theme.faint, choice.signedIn ? "✓ " : " "),
4344
+ segment(choice === current() ? theme.accent : theme.muted, choice === current() ? "● " : " "),
4345
+ segment(choice.signedIn ? theme.ok : theme.muted, choice.signedIn ? "✓ " : " "),
3887
4346
  segment(theme.muted, fit(choice.providerName, 22)),
3888
- shrinking(choice === current() ? theme.strong : theme.text, ` ${choice.name}`, choice === current())
4347
+ segment(choice === current() ? theme.strong : theme.text, ` ${clip(choice.name, room(27))}`, choice === current())
3889
4348
  ];
3890
4349
  }
3891
4350
  })
3892
4351
  }), (() => {
3893
- var _el$7 = createElement("text");
3894
- insert(_el$7, () => `${matching().length} of ${catalogue().length} models · ✓ signed in · ● current`);
3895
- effect((_$p) => setProp(_el$7, "fg", theme.faint, _$p));
3896
- return _el$7;
4352
+ var _el$5 = createElement("text");
4353
+ insert(_el$5, () => `${matching().length} of ${catalogue().length} models · ✓ signed in · ● current`);
4354
+ effect((_$p) => setProp(_el$5, "fg", theme.muted, _$p));
4355
+ return _el$5;
3897
4356
  })()];
3898
4357
  }
3899
4358
  })];
@@ -3906,6 +4365,7 @@ function SettingsPopup(props) {
3906
4365
  return method();
3907
4366
  },
3908
4367
  children: (chosen) => createComponent(Popup, {
4368
+ width: width$1,
3909
4369
  get title() {
3910
4370
  return `Sign in to ${chosen().choice.providerName}`;
3911
4371
  },
@@ -3938,6 +4398,7 @@ function SettingsPopup(props) {
3938
4398
  return entering();
3939
4399
  },
3940
4400
  children: (keyed) => createComponent(Popup, {
4401
+ width: width$1,
3941
4402
  get title() {
3942
4403
  return `${keyed().choice.providerName} API key`;
3943
4404
  },
@@ -3946,16 +4407,16 @@ function SettingsPopup(props) {
3946
4407
  },
3947
4408
  get children() {
3948
4409
  return [(() => {
3949
- var _el$1 = createElement("text");
3950
- insert(_el$1, () => `${masked()}▏`);
3951
- effect((_$p) => setProp(_el$1, "fg", theme.text, _$p));
3952
- return _el$1;
4410
+ var _el$9 = createElement("text");
4411
+ insert(_el$9, () => `${masked()}▏`);
4412
+ effect((_$p) => setProp(_el$9, "fg", theme.text, _$p));
4413
+ return _el$9;
3953
4414
  })(), (() => {
3954
- var _el$10 = createElement("text");
3955
- insertNode(_el$10, createTextNode(`Saved to pi's auth.json. $VAR and !command values resolve the way pi resolves them.`));
3956
- setProp(_el$10, "wrapMode", "word");
3957
- effect((_$p) => setProp(_el$10, "fg", theme.faint, _$p));
3958
- return _el$10;
4415
+ var _el$0 = createElement("text");
4416
+ insertNode(_el$0, createTextNode(`Saved to pi's auth.json. $VAR and !command values resolve the way pi resolves them.`));
4417
+ setProp(_el$0, "wrapMode", "word");
4418
+ effect((_$p) => setProp(_el$0, "fg", theme.muted, _$p));
4419
+ return _el$0;
3959
4420
  })()];
3960
4421
  }
3961
4422
  })
@@ -3964,9 +4425,10 @@ function SettingsPopup(props) {
3964
4425
  get when() {
3965
4426
  return signing();
3966
4427
  },
3967
- children: (current) => createComponent(Popup, {
4428
+ children: (signingIn) => createComponent(Popup, {
4429
+ width: width$1,
3968
4430
  get title() {
3969
- return `Sign in to ${current().choice.providerName}`;
4431
+ return `Sign in to ${signingIn().choice.providerName}`;
3970
4432
  },
3971
4433
  get bindings() {
3972
4434
  return [binding("Enter", "submit"), binding("Esc", "cancel")];
@@ -3978,51 +4440,51 @@ function SettingsPopup(props) {
3978
4440
  },
3979
4441
  get fallback() {
3980
4442
  return (() => {
3981
- var _el$12 = createElement("box");
3982
- setProp(_el$12, "flexDirection", "column");
3983
- insert(_el$12, createComponent(Show, {
4443
+ var _el$10 = createElement("box");
4444
+ setProp(_el$10, "flexDirection", "column");
4445
+ insert(_el$10, createComponent(Show, {
3984
4446
  get when() {
3985
4447
  return memo(() => (working()?.notices.length ?? 0) === 0)() && prompt() === void 0;
3986
4448
  },
3987
4449
  get children() {
3988
- var _el$13 = createElement("text");
3989
- insertNode(_el$13, createTextNode(`Working…`));
3990
- effect((_$p) => setProp(_el$13, "fg", theme.faint, _$p));
3991
- return _el$13;
4450
+ var _el$11 = createElement("text");
4451
+ insertNode(_el$11, createTextNode(`Working…`));
4452
+ effect((_$p) => setProp(_el$11, "fg", theme.muted, _$p));
4453
+ return _el$11;
3992
4454
  }
3993
4455
  }), null);
3994
- insert(_el$12, createComponent(For, {
4456
+ insert(_el$10, createComponent(For, {
3995
4457
  get each() {
3996
4458
  return working()?.notices ?? [];
3997
4459
  },
3998
4460
  children: (notice) => (() => {
3999
- var _el$15 = createElement("text");
4000
- setProp(_el$15, "wrapMode", "char");
4001
- insert(_el$15, notice);
4002
- effect((_$p) => setProp(_el$15, "fg", theme.text, _$p));
4003
- return _el$15;
4461
+ var _el$13 = createElement("text");
4462
+ setProp(_el$13, "wrapMode", "char");
4463
+ insert(_el$13, notice);
4464
+ effect((_$p) => setProp(_el$13, "fg", theme.text, _$p));
4465
+ return _el$13;
4004
4466
  })()
4005
4467
  }), null);
4006
- insert(_el$12, createComponent(Show, {
4468
+ insert(_el$10, createComponent(Show, {
4007
4469
  get when() {
4008
4470
  return prompt();
4009
4471
  },
4010
4472
  children: (asked) => (() => {
4011
- var _el$16 = createElement("box"), _el$17 = createElement("text");
4012
- insertNode(_el$16, _el$17);
4013
- setProp(_el$16, "flexDirection", "column");
4014
- setProp(_el$17, "wrapMode", "word");
4015
- insert(_el$17, () => asked().message);
4016
- insert(_el$16, createComponent(Show, {
4473
+ var _el$14 = createElement("box"), _el$15 = createElement("text");
4474
+ insertNode(_el$14, _el$15);
4475
+ setProp(_el$14, "flexDirection", "column");
4476
+ setProp(_el$15, "wrapMode", "word");
4477
+ insert(_el$15, () => asked().message);
4478
+ insert(_el$14, createComponent(Show, {
4017
4479
  get when() {
4018
4480
  return selecting();
4019
4481
  },
4020
4482
  get fallback() {
4021
4483
  return (() => {
4022
- var _el$18 = createElement("text");
4023
- insert(_el$18, () => `${asked().type === "secret" ? masked() : entry()}▏`);
4024
- effect((_$p) => setProp(_el$18, "fg", theme.text, _$p));
4025
- return _el$18;
4484
+ var _el$16 = createElement("text");
4485
+ insert(_el$16, () => `${asked().type === "secret" ? masked() : entry()}▏`);
4486
+ effect((_$p) => setProp(_el$16, "fg", theme.text, _$p));
4487
+ return _el$16;
4026
4488
  })();
4027
4489
  },
4028
4490
  children: (select) => createComponent(For, {
@@ -4034,24 +4496,24 @@ function SettingsPopup(props) {
4034
4496
  return memo(() => index() === picked())() ? theme.cursor : theme.none;
4035
4497
  },
4036
4498
  get segments() {
4037
- return [shrinking(theme.text, ` ${option.label}`)];
4499
+ return [segment(theme.text, ` ${clip(option.label, room(2))}`)];
4038
4500
  }
4039
4501
  })
4040
4502
  })
4041
4503
  }), null);
4042
- effect((_$p) => setProp(_el$17, "fg", theme.accent, _$p));
4043
- return _el$16;
4504
+ effect((_$p) => setProp(_el$15, "fg", theme.accent, _$p));
4505
+ return _el$14;
4044
4506
  })()
4045
4507
  }), null);
4046
- return _el$12;
4508
+ return _el$10;
4047
4509
  })();
4048
4510
  },
4049
4511
  children: (failed) => (() => {
4050
- var _el$19 = createElement("text");
4051
- setProp(_el$19, "wrapMode", "word");
4052
- insert(_el$19, () => `Sign-in failed: ${failed().issue}`);
4053
- effect((_$p) => setProp(_el$19, "fg", theme.danger, _$p));
4054
- return _el$19;
4512
+ var _el$17 = createElement("text");
4513
+ setProp(_el$17, "wrapMode", "word");
4514
+ insert(_el$17, () => `Sign-in failed: ${failed().issue}`);
4515
+ effect((_$p) => setProp(_el$17, "fg", theme.danger, _$p));
4516
+ return _el$17;
4055
4517
  })()
4056
4518
  });
4057
4519
  }
@@ -4059,7 +4521,7 @@ function SettingsPopup(props) {
4059
4521
  })
4060
4522
  ];
4061
4523
  } });
4062
- }
4524
+ };
4063
4525
  // src/tui/App.tsx
4064
4526
  const severities = [
4065
4527
  "high",
@@ -4068,89 +4530,58 @@ const severities = [
4068
4530
  "info"
4069
4531
  ];
4070
4532
  const topFinding = (report) => {
4071
- const finding = [...report.findings].sort((left, right) => severities.indexOf(left.severity) - severities.indexOf(right.severity))[0];
4533
+ const [finding] = report.findings.toSorted((left, right) => severities.indexOf(left.severity) - severities.indexOf(right.severity));
4072
4534
  return finding === void 0 ? void 0 : `${finding.severity}: ${finding.title}`;
4073
4535
  };
4074
4536
  const leftOut = (rows, why) => {
4075
- const groups = /* @__PURE__ */ new Map();
4537
+ const byReason = /* @__PURE__ */ new Map();
4076
4538
  for (const row of rows) {
4077
4539
  const reason = why(row);
4078
- if (reason !== void 0) groups.set(reason, [...groups.get(reason) ?? [], row.pkg.name]);
4540
+ if (reason !== void 0) byReason.set(reason, [...byReason.get(reason) ?? [], row.pkg.name]);
4079
4541
  }
4080
- return [...groups].map(([reason, names]) => ({
4542
+ return [...byReason].map(([reason, names]) => ({
4081
4543
  names,
4082
4544
  reason
4083
4545
  }));
4084
4546
  };
4547
+ const runTone = (failed, skipped) => {
4548
+ if (failed > 0) return theme.danger;
4549
+ return skipped > 0 ? theme.warn : theme.ok;
4550
+ };
4551
+ const updatesNote = (offered, total, settled) => {
4552
+ if (offered > 0) return plural(offered, "update");
4553
+ if (!settled) return "checking…";
4554
+ return total > 0 ? "all up to date" : "";
4555
+ };
4556
+ const openCommand = (platform) => {
4557
+ if (platform === "darwin") return "open";
4558
+ return platform === "win32" ? "explorer" : "xdg-open";
4559
+ };
4560
+ const essential = 0;
4561
+ const leastStatusRoom = 12;
4562
+ const width = (list) => hintsWidth(list.map(([binding]) => binding));
4563
+ const lowestRanked = (list) => {
4564
+ let worst = 0;
4565
+ for (const [index, [, rank]] of list.entries()) if (rank >= (list[worst]?.[1] ?? 0)) worst = index;
4566
+ return worst;
4567
+ };
4568
+ const fitFooterHints = (hints, room, status) => {
4569
+ const kept = [...hints];
4570
+ const droppable = () => kept.some(([, rank]) => rank > essential);
4571
+ while (droppable() && width(kept) > room - status) kept.splice(lowestRanked(kept), 1);
4572
+ while (kept.length > 0 && width(kept) > room - leastStatusRoom) kept.pop();
4573
+ return kept.map(([binding]) => binding);
4574
+ };
4085
4575
  const none = { _tag: "None" };
4086
4576
  const sameAnchor = (left, right) => left?.key === right?.key && left?.section === right?.section && left?.index === right?.index;
4087
- const confirmations = {
4088
- update: {
4089
- verb: "Update",
4090
- done: "updated",
4091
- tone: "accent"
4092
- },
4093
- uninstall: {
4094
- verb: "Remove",
4095
- done: "removed",
4096
- tone: "danger"
4097
- },
4098
- audit: {
4099
- verb: "Audit",
4100
- done: "audited",
4101
- tone: "accent"
4102
- }
4103
- };
4104
4577
  const detailMin = 60;
4105
4578
  const listMin = 60;
4106
4579
  const chromeLines = 4;
4107
- const clip = (text, width) => {
4108
- if (Array.from(text).length <= width) return text;
4109
- const trimmed = Array.from(text.trimEnd());
4110
- if (trimmed.length <= width) return trimmed.join("");
4111
- return width <= 0 ? "" : `${trimmed.slice(0, width - 1).join("")}…`;
4112
- };
4113
- const plural = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
4114
- const capitalized = (text) => `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
4115
- const listed = (names) => names.length <= 3 ? names.join(", ") : `${names.slice(0, 3).join(", ")} and ${names.length - 3} more`;
4116
4580
  const home = homedir();
4117
4581
  const tidy = (path) => home !== "" && (path === home || path.startsWith(`${home}/`)) ? `~${path.slice(home.length)}` : path;
4118
4582
  const noticeLimit = 4;
4119
4583
  const otherMode = (mode) => mode === "system" ? "project" : "system";
4120
- const flaggedFirst = (pending) => {
4121
- const flagged = new Set(pending.flagged.map((entry) => entry.row.key));
4122
- return [...pending.rows.filter((row) => flagged.has(row.key)), ...pending.rows.filter((row) => !flagged.has(row.key))];
4123
- };
4124
- const confirmColumns = (pending, inner) => {
4125
- const widest = (texts) => Math.max(0, ...texts.map((text) => Array.from(text).length));
4126
- const current = Math.min(14, widest(pending.rows.map((row) => row.pkg.current)));
4127
- const target = pending.action === "uninstall" ? 0 : 3 + Math.min(14, widest(pending.rows.map((row) => row.pkg.target ?? "")));
4128
- const verdict = widest(pending.rows.map((row) => flaggedVerdict(pending, row).map((part) => part.text).join("")));
4129
- const room = inner - 2 - 2 - current - target - verdict;
4130
- const longest = widest(pending.rows.map((row) => row.pkg.name));
4131
- const name = Math.max(6, Math.min(longest, room));
4132
- const wanted = 8 + longest + 2 + current + target + verdict;
4133
- return {
4134
- name,
4135
- current,
4136
- target: Math.max(0, target - 3),
4137
- wanted
4138
- };
4139
- };
4140
- const flaggedVerdict = (pending, row) => {
4141
- const verdict = pending.flagged.find((entry) => entry.row.key === row.key)?.verdict;
4142
- const mixed = pending.unaudited.length > 0 && pending.unaudited.length < pending.rows.length;
4143
- if (verdict === void 0 && pending.vendor.includes(row.key)) return [segment(theme.faint, ` ${isAppUpdate(row.pkg) ? "app" : "OS"} update · not audited`), ...pending.action === "update" && row.pkg.restart === true ? [segment(theme.warn, " · restarts")] : []];
4144
- if (verdict === void 0) {
4145
- if (pending.action === "update" && !pending.unaudited.includes(row.key)) return [segment(theme.ok, ` ${verdictIcons.ok} ${verdictLabels.ok}`)];
4146
- const unread = pending.action === "update" && pending.unaudited.includes(row.key) && (mixed || !pending.auditFirst);
4147
- if (pending.action === "update" && pending.breaking.includes(row.key)) return [segment(theme.warn, ` ${breakingMark}`), ...unread ? [segment(theme.faint, " · not audited")] : []];
4148
- return unread ? [segment(theme.faint, " not audited")] : [];
4149
- }
4150
- if (verdict === "failed") return [segment(theme.danger, " ✗ audit failed")];
4151
- return [segment(verdictColor(verdict), ` ${verdictIcons[verdict]} ${verdictLabels[verdict]}`)];
4152
- };
4153
- function App(props) {
4584
+ const App = (props) => {
4154
4585
  const dimensions = useTerminalDimensions();
4155
4586
  const [anchor, setAnchor] = createSignal(void 0, { equals: sameAnchor });
4156
4587
  const [offset, setOffset] = createSignal(0);
@@ -4159,25 +4590,28 @@ function App(props) {
4159
4590
  const [overlay, setOverlay] = createSignal(none);
4160
4591
  const [quitting, setQuitting] = createSignal(false);
4161
4592
  const [tab, setTab] = createSignal("about");
4162
- const [listTop, setListTop] = createSignal(0);
4163
4593
  const [fileAt, setFileAt] = createSignal(0);
4164
- const [lastRun, setLastRun] = createSignal([]);
4165
- const [runNames, setRunNames] = createSignal(/* @__PURE__ */ new Map());
4594
+ const [run, setRun] = createSignal();
4166
4595
  const [toast, setToast] = createSignal();
4167
4596
  let toastTimer;
4168
4597
  const showToast = (next) => {
4169
4598
  clearTimeout(toastTimer);
4170
4599
  setToast(next);
4171
- if (next !== void 0) toastTimer = setTimeout(() => setToast(void 0), 8e3);
4600
+ if (next !== void 0) toastTimer = setTimeout(() => {
4601
+ setToast(void 0);
4602
+ }, 8e3);
4172
4603
  };
4173
- onCleanup(() => clearTimeout(toastTimer));
4604
+ onCleanup(() => {
4605
+ clearTimeout(toastTimer);
4606
+ });
4174
4607
  let scroller;
4175
- let helpScroller;
4176
4608
  const loadedOnce = createMemo((was) => !props.state.discovering && (was || !props.state.providers.some((entry) => entry.status === "loading")), false);
4177
4609
  const [fold, setFold] = createSignal("auto");
4178
4610
  const grouped = createMemo(() => {
4179
4611
  const found = groups(props.state, filter());
4180
- const folds = fold() === "hidden" || fold() === "auto" && filter() === "" && (!loadedOnce() || found.some((group) => group.kind === "updates"));
4612
+ const updatesToDecideOn = !loadedOnce() || found.some((group) => group.kind === "updates");
4613
+ const foldsUntilToggled = filter() === "" && updatesToDecideOn;
4614
+ const folds = fold() === "auto" ? foldsUntilToggled : fold() === "hidden";
4181
4615
  const kept = (row) => props.state.outcomes[row.key] !== void 0 || props.state.selected.includes(row.key);
4182
4616
  return found.map((group) => group.kind === "current" && folds ? {
4183
4617
  ...group,
@@ -4188,19 +4622,27 @@ function App(props) {
4188
4622
  const rows = createMemo(() => reachable(grouped()));
4189
4623
  const allLines = createMemo(() => lines(grouped()));
4190
4624
  const clamp = (index) => Math.max(0, Math.min(index, rows().length - 1));
4191
- const sectionOf = (row) => props.state.removed[row.key] !== void 0 ? "removed" : row.pkg.target !== void 0 ? "updates" : props.state.installed[row.key] !== void 0 ? "updated" : "current";
4192
- const cursor = () => {
4193
- const held = anchor();
4194
- if (held === void 0) return 0;
4625
+ const sectionOf = (row) => {
4626
+ if (props.state.removed[row.key] !== void 0) return "removed";
4627
+ if (row.pkg.target !== void 0) return "updates";
4628
+ return props.state.installed[row.key] === void 0 ? "current" : "updated";
4629
+ };
4630
+ const successorInSection = (held) => {
4195
4631
  const all = rows();
4196
- const index = all.findIndex((row) => row.key === held.key);
4197
- const row = all[index];
4198
- if (row !== void 0 && sectionOf(row) === held.section) return index;
4199
4632
  const start = all.findIndex((other) => sectionOf(other) === held.section);
4200
- if (start < 0) return held.section === "updates" ? 0 : clamp(all.length - 1);
4633
+ if (start === -1) return held.section === "updates" ? 0 : clamp(all.length - 1);
4201
4634
  const end = all.findLastIndex((other) => sectionOf(other) === held.section);
4202
4635
  return Math.min(start + held.index, end);
4203
4636
  };
4637
+ const followAnchor = (held) => {
4638
+ const index = rows().findIndex((row) => row.key === held.key);
4639
+ const row = rows()[index];
4640
+ return row !== void 0 && sectionOf(row) === held.section ? index : successorInSection(held);
4641
+ };
4642
+ const cursor = () => {
4643
+ const held = anchor();
4644
+ return held === void 0 ? 0 : followAnchor(held);
4645
+ };
4204
4646
  const anchorAt = (index) => {
4205
4647
  const row = rows()[index];
4206
4648
  if (row === void 0) return;
@@ -4235,11 +4677,11 @@ function App(props) {
4235
4677
  }],
4236
4678
  ...props.state.providers.flatMap((entry) => entry.error === void 0 ? [] : [{
4237
4679
  color: theme.danger,
4238
- message: `✗ ${entry.name}: ${describeError(entry.error)}`
4680
+ message: `✗ ${providerLabel(entry.name)}: ${describeError(entry.error)}`
4239
4681
  }]),
4240
4682
  ...props.state.providers.flatMap((entry) => entry.notices.filter((notice) => notice.rowKey === void 0 || !everyRow().some((row) => row.key === notice.rowKey)).map((notice) => ({
4241
4683
  color: theme.warn,
4242
- message: `! ${entry.name}: ${notice.message}`
4684
+ message: `! ${providerLabel(entry.name)}: ${notice.message}`
4243
4685
  })))
4244
4686
  ].slice(0, noticeLimit);
4245
4687
  });
@@ -4247,7 +4689,7 @@ function App(props) {
4247
4689
  const fullList = () => Math.max(tableWidth(natural()) + 4, listMin);
4248
4690
  const leastList = createMemo(() => Math.max(leastWidth(natural(), props.state.mode) + 4, listMin));
4249
4691
  const split = () => dimensions().width >= leastList() + 1 + detailMin;
4250
- const listWidth = () => Math.min(fullList(), Math.max(leastList(), dimensions().width - 1 - detailMin));
4692
+ const listWidth = () => Math.max(leastList(), Math.min(fullList(), dimensions().width - 1 - detailMin, Math.floor(dimensions().width * .6)));
4251
4693
  const contentHeight = () => Math.max(1, dimensions().height - chromeLines - notices().length);
4252
4694
  const inventoryWidth = () => split() ? listWidth() : dimensions().width;
4253
4695
  const columns = () => fitColumns(natural(), split() ? inventoryWidth() - 2 : inventoryWidth(), props.state.mode);
@@ -4258,6 +4700,8 @@ function App(props) {
4258
4700
  return index <= 1 ? 0 : index;
4259
4701
  };
4260
4702
  const top = () => window(allLines().length, contentHeight(), focusLine(), offset());
4703
+ const places = /* @__PURE__ */ new Map();
4704
+ const [restoring, setRestoring] = createSignal();
4261
4705
  const move = (to) => {
4262
4706
  setRestoring(void 0);
4263
4707
  anchorAt(clamp(to));
@@ -4284,20 +4728,19 @@ function App(props) {
4284
4728
  setAnchor(void 0);
4285
4729
  setOffset(0);
4286
4730
  };
4287
- const places = /* @__PURE__ */ new Map();
4288
- const [restoring, setRestoring] = createSignal();
4289
4731
  createEffect(() => {
4290
4732
  const wanted = restoring();
4291
4733
  if (wanted === void 0 || props.state.mode !== wanted.mode) return;
4292
4734
  const index = rows().findIndex((row) => row.key === wanted.key);
4293
- if (index >= 0) {
4735
+ if (index !== -1) {
4294
4736
  anchorAt(index);
4295
4737
  setOffset(top());
4296
4738
  setRestoring(void 0);
4297
4739
  } else if (!props.state.discovering && !props.state.providers.some((entry) => entry.status === "loading")) setRestoring(void 0);
4298
4740
  });
4299
- const fire = (effect) => props.run(effect);
4300
- const modelName = (provider, modelId) => modelLabel(props.state, provider, modelId);
4741
+ const fire = (effect) => {
4742
+ props.run(effect);
4743
+ };
4301
4744
  const shown = (wanted) => {
4302
4745
  const row = focused();
4303
4746
  return row !== void 0 && showDetails() && tab() === wanted ? row : void 0;
@@ -4309,7 +4752,7 @@ function App(props) {
4309
4752
  const compared = createMemo(() => {
4310
4753
  const row = shown("changes");
4311
4754
  const pkg = row === void 0 ? void 0 : auditedAs(props.state, row.pkg);
4312
- if (pkg?.target === void 0) return void 0;
4755
+ if (pkg?.target === void 0) return;
4313
4756
  const key = auditKey(pkg, props.state.mode);
4314
4757
  const missing = key !== void 0 && props.state.changes[key] === void 0 && auditOf(props.state, pkg)?._tag !== "Running";
4315
4758
  return `${aboutKey(pkg)}${missing ? ":missing" : ""}`;
@@ -4323,12 +4766,17 @@ function App(props) {
4323
4766
  if (key !== void 0 && row !== void 0) fire(props.session.describe(row.pkg));
4324
4767
  }));
4325
4768
  createEffect(on(compared, (key) => {
4326
- if (key === void 0) return fire(props.session.readChanges(void 0));
4769
+ if (key === void 0) {
4770
+ fire(props.session.readChanges(void 0));
4771
+ return;
4772
+ }
4327
4773
  const timer = setTimeout(() => {
4328
4774
  const row = untrack(focused);
4329
4775
  fire(props.session.readChanges(row && auditedAs(props.state, row.pkg)));
4330
4776
  }, 250);
4331
- onCleanup(() => clearTimeout(timer));
4777
+ onCleanup(() => {
4778
+ clearTimeout(timer);
4779
+ });
4332
4780
  }));
4333
4781
  const readTo = /* @__PURE__ */ new Map();
4334
4782
  createEffect(on(() => [focused()?.key, tab()], ([key, now], before) => {
@@ -4349,24 +4797,24 @@ function App(props) {
4349
4797
  }));
4350
4798
  createEffect(on(() => props.state.running, (now, before) => {
4351
4799
  if (before !== true || now) return;
4352
- const outcomes = untrack(lastRun).flatMap((key) => {
4353
- const outcome = props.state.outcomes[key];
4800
+ const last = untrack(run);
4801
+ if (last === void 0) return;
4802
+ const outcomes = last.targets.flatMap((target) => {
4803
+ const outcome = props.state.outcomes[target.key];
4354
4804
  return outcome === void 0 ? [] : [outcome];
4355
4805
  });
4356
4806
  if (outcomes.length === 0) return;
4357
4807
  const done = outcomes.filter((outcome) => outcome._tag === "Completed").length;
4358
4808
  const failed = outcomes.filter((outcome) => outcome._tag === "Failed" || outcome._tag === "Unexpected").length;
4359
4809
  const other = outcomes.length - done - failed;
4360
- const only = outcomes.length === 1 ? untrack(lastRun)[0] : void 0;
4361
- const name = only === void 0 ? void 0 : untrack(runNames).get(only);
4362
- const removal = only !== void 0 && props.state.actions[only] === "uninstall";
4363
- const parts = name !== void 0 && done === 1 ? [removal ? `✓ Removed ${name}` : `✓ ${name} updated`] : [
4810
+ const name = outcomes.length === 1 ? last.targets[0]?.name : void 0;
4811
+ const parts = name !== void 0 && done === 1 ? [last.action === "uninstall" ? `✓ Removed ${name}` : `✓ ${name} updated`] : [
4364
4812
  ...done > 0 ? [`✓ ${done} done`] : [],
4365
4813
  ...failed > 0 ? [`✗ ${failed} failed`] : [],
4366
4814
  ...other > 0 ? [`· ${other} skipped`] : []
4367
4815
  ];
4368
4816
  showToast({
4369
- color: failed > 0 ? theme.danger : other > 0 ? theme.warn : theme.ok,
4817
+ color: runTone(failed, other),
4370
4818
  text: parts.join(" ")
4371
4819
  });
4372
4820
  }));
@@ -4377,14 +4825,15 @@ function App(props) {
4377
4825
  const only = finished.length === 1 ? finished[0]?.[1] : void 0;
4378
4826
  const row = everyRow().find((entry) => auditOf(props.state, entry.pkg) === only);
4379
4827
  if (only?._tag === "Done" && row !== void 0) {
4380
- const result = only.result;
4381
- return showToast(result._tag === "Failed" ? {
4828
+ const { result } = only;
4829
+ showToast(result._tag === "Failed" ? {
4382
4830
  color: theme.danger,
4383
4831
  text: `✗ ${row.pkg.name} audit failed`
4384
4832
  } : {
4385
4833
  color: verdictColor(result.report.verdict),
4386
4834
  text: `${verdictIcons[result.report.verdict]} ${row.pkg.name} audited: ${verdictLabels[result.report.verdict]}`
4387
4835
  });
4836
+ return;
4388
4837
  }
4389
4838
  showToast({
4390
4839
  color: theme.accent,
@@ -4397,37 +4846,7 @@ function App(props) {
4397
4846
  createEffect(() => {
4398
4847
  if (tab() === "report" && props.state.catalogue === void 0) fire(props.session.loadCatalogue);
4399
4848
  });
4400
- const confirmWidth = (pending) => Math.min(Math.max(64, Math.min(confirmColumns(pending, 0).wanted, 90)), dimensions().width - 4);
4401
- const confirmInner = () => {
4402
- const pending = confirmation();
4403
- return (pending === void 0 ? 64 : confirmWidth(pending)) - 6;
4404
- };
4405
4849
  const scrollDetails = (direction) => scroller?.scrollBy(direction * Math.max(1, Math.floor(contentHeight() / 2)));
4406
- const flaggedSentence = (flagged) => {
4407
- const only = flagged.length === 1 ? flagged[0] : void 0;
4408
- if (only !== void 0) return only.verdict === "failed" ? `! ${only.row.pkg.name}'s audit did not complete, so it was not reviewed. Confirming installs it anyway.` : `! ${only.row.pkg.name} was audited: ${verdictLabels[only.verdict]}${only.top === void 0 ? "" : ` (${only.top})`}. Confirming installs it anyway.`;
4409
- const failed = flagged.filter((entry) => entry.verdict === "failed").length;
4410
- const reviewed = flagged.length - failed;
4411
- return `! Of these, ${[...reviewed > 0 ? [`${reviewed} ${reviewed === 1 ? "has" : "have"} an audit warning`] : [], ...failed > 0 ? [`${failed} could not be audited`] : []].join(" and ")}. Confirming installs them anyway.`;
4412
- };
4413
- const confirmTone = (pending) => {
4414
- if (pending.action === "uninstall") return "danger";
4415
- if (pending.flagged.some((entry) => entry.verdict === "danger")) return "danger";
4416
- return pending.flagged.length > 0 ? "warn" : "accent";
4417
- };
4418
- const destination = (pending) => {
4419
- const providers = [...new Set(pending.rows.map((row) => providerLabel(row.pkg.provider)))].join(", ");
4420
- const where = props.state.mode === "system" ? "on this machine" : `in ${tidy(props.state.scope)}`;
4421
- return pending.action === "audit" ? `${where} · read-only, nothing will be installed` : `${where} · ${providers}`;
4422
- };
4423
- const signedOut = () => {
4424
- const setup = props.state.preferences.setup;
4425
- const catalogue = props.state.catalogue;
4426
- if (setup === void 0 || catalogue?._tag !== "Ready") return void 0;
4427
- const choice = catalogue.value.find((entry) => entry.provider === setup.provider && entry.modelId === setup.modelId);
4428
- return choice === void 0 || choice.signedIn ? void 0 : choice.providerName;
4429
- };
4430
- const needsSignIn = (pending) => (pending.action === "audit" || pending.action === "update" && props.state.preferences.auditFirst && pending.vendor.length < pending.rows.length) && signedOut() !== void 0;
4431
4850
  const confirm = (action) => {
4432
4851
  if (action === "audit" || action === "update" && props.state.preferences.auditFirst) fire(props.session.loadCatalogue);
4433
4852
  const focusedRow = focused();
@@ -4439,7 +4858,11 @@ function App(props) {
4439
4858
  return;
4440
4859
  }
4441
4860
  const candidates = selectedRows().length > 0 ? selectedRows() : [focused()].filter((row) => row !== void 0);
4442
- const why = (row) => action === "uninstall" ? row.pkg.unremovable : action === "audit" ? unauditable(row.pkg) : row.pkg.elsewhere?.reason;
4861
+ const why = (row) => {
4862
+ if (action === "uninstall") return row.pkg.unremovable;
4863
+ if (action === "audit") return unauditable(row.pkg);
4864
+ return row.pkg.elsewhere?.reason;
4865
+ };
4443
4866
  const eligible = action === "uninstall" ? candidates : candidates.filter((row) => row.pkg.target !== void 0);
4444
4867
  const refused = eligible.filter((row) => why(row) !== void 0);
4445
4868
  const actionable = eligible.filter((row) => why(row) === void 0);
@@ -4454,32 +4877,30 @@ function App(props) {
4454
4877
  row,
4455
4878
  verdict: "failed"
4456
4879
  }];
4457
- const report = audit.result.report;
4458
- return report.verdict !== "ok" ? [{
4880
+ const { report } = audit.result;
4881
+ return report.verdict === "ok" ? [] : [{
4459
4882
  row,
4460
4883
  verdict: report.verdict,
4461
4884
  top: topFinding(report)
4462
- }] : [];
4885
+ }];
4463
4886
  }) : [];
4464
- if (actionable.length > 0) {
4465
- setListTop(0);
4466
- setOverlay({
4467
- _tag: "Confirm",
4468
- pending: {
4469
- action,
4470
- rows: actionable,
4471
- flagged,
4472
- auditFirst: props.state.preferences.auditFirst,
4473
- breaking: action === "update" ? actionable.filter((row) => majorsOf(props.state, row.pkg).length > 0).map((row) => row.key) : [],
4474
- unaudited: action === "update" ? actionable.filter((row) => !isVendorUpdate(row.pkg) && auditOf(props.state, row.pkg)?._tag !== "Done").map((row) => row.key) : [],
4475
- vendor: actionable.filter((row) => isVendorUpdate(row.pkg)).map((row) => row.key),
4476
- skipped: candidates.length - actionable.length - refused.length,
4477
- refused: leftOut(refused, why)
4478
- }
4479
- });
4480
- } else if (refused.length > 0) {
4887
+ if (actionable.length > 0) setOverlay({
4888
+ _tag: "Confirm",
4889
+ pending: {
4890
+ action,
4891
+ rows: actionable,
4892
+ flagged,
4893
+ auditFirst: props.state.preferences.auditFirst,
4894
+ breaking: action === "update" ? actionable.filter((row) => majorsOf(props.state, row.pkg).length > 0).map((row) => row.key) : [],
4895
+ unaudited: action === "update" ? actionable.filter((row) => !isUnauditedUpdate(row.pkg) && auditOf(props.state, row.pkg)?._tag !== "Done").map((row) => row.key) : [],
4896
+ unauditable: actionable.filter((row) => isUnauditedUpdate(row.pkg)).map((row) => row.key),
4897
+ skipped: candidates.length - actionable.length - refused.length,
4898
+ refused: leftOut(refused, why)
4899
+ }
4900
+ });
4901
+ else if (refused.length > 0) {
4481
4902
  const only = refused.length === 1 ? refused[0]?.pkg.name : void 0;
4482
- const done = confirmations[action].done;
4903
+ const { done } = confirmations[action];
4483
4904
  const opens = refused.some((row) => row.pkg.elsewhere !== void 0);
4484
4905
  setOverlay({
4485
4906
  _tag: "Notice",
@@ -4496,7 +4917,10 @@ function App(props) {
4496
4917
  }
4497
4918
  };
4498
4919
  const quit = () => {
4499
- if (!props.state.running) return props.quit();
4920
+ if (!props.state.running) {
4921
+ props.quit();
4922
+ return;
4923
+ }
4500
4924
  setQuitting(true);
4501
4925
  fire(props.session.stop.pipe(Effect.andThen(props.session.awaitIdle), Effect.andThen(Effect.sync(props.quit))));
4502
4926
  };
@@ -4504,45 +4928,17 @@ function App(props) {
4504
4928
  if (matches(keys.allow, key)) fire(props.session.answer(true));
4505
4929
  else if (matches(keys.deny, key)) fire(props.session.answer(false));
4506
4930
  };
4507
- const listRoom = () => Math.max(3, dimensions().height - 20);
4508
- const shownTop = (pending) => Math.max(0, Math.min(listTop(), pending.rows.length - listRoom()));
4509
- const signIn = {
4510
- ...keys.settings,
4511
- keys: [",", "return"],
4512
- hint: ",/Enter",
4513
- description: "sign in"
4514
- };
4515
- const confirmKey = (pending) => {
4516
- const verb = confirmations[pending.action].verb.toLowerCase();
4517
- if (pending.action === "uninstall") return keys.confirmRemove;
4518
- if (needsSignIn(pending) || pending.flagged.length > 0) return {
4519
- keys: ["y"],
4520
- hint: "y",
4521
- description: `${verb} anyway`
4522
- };
4523
- return {
4524
- ...keys.confirm,
4525
- hint: "y/Enter",
4526
- description: verb
4527
- };
4528
- };
4529
- const onConfirmation = (key, pending) => {
4530
- const last = Math.max(0, pending.rows.length - listRoom());
4531
- if (matches(keys.down, key)) setListTop(Math.min(last, shownTop(pending) + 1));
4532
- else if (matches(keys.up, key)) setListTop(Math.max(0, shownTop(pending) - 1));
4533
- else if (needsSignIn(pending) && matches(signIn, key)) setOverlay({
4534
- _tag: "Settings",
4535
- back: pending
4931
+ const onConfirmation = (pending) => {
4932
+ setOverlay(none);
4933
+ const chosen = pending.rows.map((row) => row.key);
4934
+ if (pending.action !== "audit") setRun({
4935
+ action: pending.action,
4936
+ targets: pending.rows.map((row) => ({
4937
+ key: row.key,
4938
+ name: row.pkg.name
4939
+ }))
4536
4940
  });
4537
- else if (matches(confirmKey(pending), key)) {
4538
- setOverlay(none);
4539
- const chosen = pending.rows.map((row) => row.key);
4540
- if (pending.action !== "audit") {
4541
- setLastRun(chosen);
4542
- setRunNames(new Map(pending.rows.map((row) => [row.key, row.pkg.name])));
4543
- }
4544
- fire(pending.action === "audit" ? props.session.audit(chosen) : props.session.run(pending.action, chosen, pending.flagged.map((entry) => entry.row.key)));
4545
- } else if (matches(keys.cancel, key)) setOverlay(none);
4941
+ fire(pending.action === "audit" ? props.session.audit(chosen) : props.session.run(pending.action, chosen, pending.flagged.map((entry) => entry.row.key)));
4546
4942
  };
4547
4943
  const onFinding = (key) => {
4548
4944
  if (matches(keys.keepFilter, key) && filter() === "") {
@@ -4556,7 +4952,7 @@ function App(props) {
4556
4952
  return;
4557
4953
  } else if (key.name === "backspace") setFilter((current) => current.slice(0, -1));
4558
4954
  else if (key.ctrl && key.name === "u") setFilter("");
4559
- else if (!key.ctrl && !key.meta && [...key.sequence].length === 1 && key.sequence >= " ") setFilter((current) => current + key.sequence);
4955
+ else if (!key.ctrl && !key.meta && graphemes(key.sequence).length === 1 && key.sequence >= " ") setFilter((current) => current + key.sequence);
4560
4956
  else return;
4561
4957
  toFirst();
4562
4958
  };
@@ -4582,23 +4978,24 @@ function App(props) {
4582
4978
  const homepage = about?._tag === "Ready" ? about.value.homepage ?? about.value.repository : void 0;
4583
4979
  const url = row?.pkg.elsewhere?.open ?? (homepage !== void 0 && /^https?:\/\//u.test(homepage) ? homepage : void 0);
4584
4980
  if (url === void 0) return;
4585
- const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "explorer" : "xdg-open";
4981
+ const opener = openCommand(process.platform);
4586
4982
  const child = spawn(opener, [url], {
4587
4983
  detached: true,
4588
4984
  stdio: "ignore"
4589
4985
  });
4590
- child.on("error", () => showToast({
4591
- color: theme.danger,
4592
- text: `✗ Could not open ${url}`
4593
- }));
4986
+ child.on("error", () => {
4987
+ showToast({
4988
+ color: theme.danger,
4989
+ text: `✗ Could not open ${url}`
4990
+ });
4991
+ });
4594
4992
  child.unref();
4595
4993
  showToast({
4596
4994
  color: theme.accent,
4597
4995
  text: `Opened ${row?.pkg.elsewhere?.app ?? url}`
4598
4996
  });
4599
4997
  };
4600
- const helpColumns = () => dimensions().width >= 84 ? [help.slice(0, 3), help.slice(3)] : [help];
4601
- const helpHeight = () => Math.max(...helpColumns().map((column) => column.reduce((sum, group, index) => sum + group.bindings.length + 1 + (index === 0 ? 0 : 1), 0)));
4998
+ const helpColumns = () => dimensions().width >= 88 ? [help.slice(0, 3), help.slice(3)] : [help];
4602
4999
  const onInventory = (key) => {
4603
5000
  const page = contentHeight() - 1;
4604
5001
  if (reading() && matches(keys.down, key)) scroller?.scrollBy(1);
@@ -4668,21 +5065,21 @@ function App(props) {
4668
5065
  };
4669
5066
  useKeyboard((key) => {
4670
5067
  const asked = question();
4671
- if (asked !== void 0) return asked._tag === "Password" ? void 0 : onDecision(key);
4672
- const now = overlay();
4673
- switch (now._tag) {
4674
- case "Settings": return;
5068
+ if (asked !== void 0) {
5069
+ if (asked._tag !== "Password") onDecision(key);
5070
+ return;
5071
+ }
5072
+ switch (overlay()._tag) {
5073
+ case "Settings":
5074
+ case "Confirm": return;
4675
5075
  case "Help":
4676
- if (matches(keys.down, key)) return helpScroller?.scrollBy(1);
4677
- if (matches(keys.up, key)) return helpScroller?.scrollBy(-1);
4678
- if (matches(keys.closeHelp, key)) return setOverlay(none);
4679
- return;
4680
- case "Confirm": return onConfirmation(key, now.pending);
4681
5076
  case "Notice":
4682
5077
  if (matches(keys.closeHelp, key)) setOverlay(none);
4683
5078
  return;
4684
- case "Find": return onFinding(key);
4685
- case "None": return onInventory(key);
5079
+ case "Find":
5080
+ onFinding(key);
5081
+ return;
5082
+ case "None": onInventory(key);
4686
5083
  }
4687
5084
  });
4688
5085
  usePaste((event) => {
@@ -4690,18 +5087,17 @@ function App(props) {
4690
5087
  setFilter((current) => current + pasted(event.bytes));
4691
5088
  toFirst();
4692
5089
  });
4693
- const loading = () => props.state.providers.filter((entry) => entry.status === "loading").map((entry) => entry.name);
5090
+ const loading = () => props.state.providers.filter((entry) => entry.status === "loading").map((entry) => providerLabel(entry.name));
4694
5091
  const scope = () => {
4695
5092
  if (props.state.discovering || props.state.mode === "system") return "";
4696
5093
  const path = tidy(props.state.scope);
4697
5094
  return dimensions().width < 90 ? path.split("/").at(-1) ?? path : path;
4698
5095
  };
4699
5096
  const progress = () => {
4700
- const busy = Object.keys(props.state.activity);
4701
- const done = lastRun().filter((key) => props.state.outcomes[key] !== void 0).length;
4702
- const total = Math.max(lastRun().length, done + busy.length);
4703
- const name = everyRow().find((row) => props.state.activity[row.key] !== void 0)?.pkg.name;
4704
- return `Working… ${done} of ${total}${name === void 0 ? "" : ` · ${name}`}`;
5097
+ const targets = run()?.targets ?? [];
5098
+ const done = targets.filter((target) => props.state.outcomes[target.key] !== void 0).length;
5099
+ const total = Math.max(targets.length, done + Object.keys(props.state.activity).length);
5100
+ return `${run()?.action === "uninstall" ? "Removing" : "Updating"} ${done} of ${total}`;
4705
5101
  };
4706
5102
  const auditing = () => Object.values(props.state.audits).filter((audit) => audit._tag === "Running").length;
4707
5103
  const summary = () => {
@@ -4710,16 +5106,19 @@ function App(props) {
4710
5106
  if (props.state.running) return progress();
4711
5107
  const all = rows();
4712
5108
  const selected = selectedRows().length;
4713
- const hidden = selectedRows().filter((row) => !all.some((shown) => shown.key === row.key)).length;
5109
+ const hidden = selectedRows().filter((row) => !all.some((visible) => visible.key === row.key)).length;
4714
5110
  const total = everyRow().length;
4715
5111
  const offeredOverall = everyRow().filter((row) => row.pkg.target !== void 0).length;
4716
5112
  const settled = !props.state.discovering && loading().length === 0;
4717
5113
  const matched = grouped().reduce((sum, group) => sum + group.rows.length, 0);
4718
5114
  const count = filter() === "" ? plural(total, "package") : `${matched} of ${total} match`;
4719
- const updates = offeredOverall > 0 ? plural(offeredOverall, "update") : settled && total > 0 ? "all up to date" : settled ? "" : "checking…";
5115
+ const updates = updatesNote(offeredOverall, total, settled);
4720
5116
  const picked = selected === 0 ? "" : ` · ${selected} selected${hidden > 0 ? ` (${hidden} hidden)` : ""}`;
4721
5117
  const audits = auditing() > 0 ? `Auditing ${auditing()}… · ` : "";
4722
- if (dimensions().width < 90) return `${audits}${filter() === "" ? updates === "" ? count : updates : `${matched}/${total} match`}${picked}`;
5118
+ if (dimensions().width < 90) {
5119
+ const unfiltered = updates === "" ? count : updates;
5120
+ return `${audits}${filter() === "" ? unfiltered : `${matched}/${total} match`}${picked}`;
5121
+ }
4723
5122
  const position = rows().length > contentHeight() ? ` · ${cursor() + 1}/${rows().length}` : "";
4724
5123
  return `${audits}${count}${updates === "" ? "" : ` · ${updates}`}${picked}${position}`;
4725
5124
  };
@@ -4765,13 +5164,14 @@ function App(props) {
4765
5164
  ...keys.nextFile,
4766
5165
  description: "file"
4767
5166
  }, 3]] : [],
4768
- ...filter() !== "" ? [[{
4769
- ...keys.back,
4770
- description: "clear filter"
4771
- }, 0]] : picked ? [[{
5167
+ ...filter() === "" && picked ? [[{
4772
5168
  ...keys.back,
4773
5169
  description: "clear checks"
4774
5170
  }, 3]] : [],
5171
+ ...filter() === "" ? [] : [[{
5172
+ ...keys.back,
5173
+ description: "clear filter"
5174
+ }, 0]],
4775
5175
  ...anything && !record ? [[keys.select, 2]] : [],
4776
5176
  ...actionable ? [[keys.update, 1]] : [],
4777
5177
  ...actionable ? [[keys.audit, picked ? 1 : 2]] : [],
@@ -4789,24 +5189,13 @@ function App(props) {
4789
5189
  ];
4790
5190
  };
4791
5191
  const footnote = () => {
4792
- const shown = toast();
4793
- return shown === void 0 ? summary() : `${summary()} ${shown.text}`;
5192
+ const latest = toast();
5193
+ return latest === void 0 ? summary() : `${summary()} ${latest.text}`;
4794
5194
  };
4795
5195
  const busy = () => props.state.running || auditing() > 0;
4796
5196
  const footerRoom = () => dimensions().width - 2 - (busy() ? 2 : 0);
5197
+ const fitted = () => overlay()._tag !== "None" && !finding() ? [] : fitFooterHints(hints(), footerRoom(), graphemes(`${footnote()} `).length);
4797
5198
  const statusRoom = () => footerRoom() - hintsWidth(fitted());
4798
- const fitted = () => {
4799
- if (overlay()._tag !== "None" && !finding()) return [];
4800
- const width = (list) => hintsWidth(list.map(([binding]) => binding));
4801
- const room = footerRoom() - Array.from(`${footnote()} `).length;
4802
- const shown = [...hints()];
4803
- while (shown.some(([, rank]) => rank > 0) && width(shown) > room) {
4804
- const worst = shown.reduce((at, [, rank], index) => rank >= (shown[at]?.[1] ?? 0) ? index : at, 0);
4805
- shown.splice(worst, 1);
4806
- }
4807
- while (shown.length > 0 && width(shown) > footerRoom() - 12) shown.pop();
4808
- return shown.map(([binding]) => binding);
4809
- };
4810
5199
  return (() => {
4811
5200
  var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$7 = createElement("text"), _el$10 = createElement("text"), _el$12 = createElement("text"), _el$14 = createElement("box"), _el$19 = createElement("text"), _el$21 = createElement("box"), _el$24 = createElement("text"), _el$25 = createElement("box");
4812
5201
  insertNode(_el$, _el$2);
@@ -4832,20 +5221,20 @@ function App(props) {
4832
5221
  insert(_el$2, createComponent(For, {
4833
5222
  each: ["project", "system"],
4834
5223
  children: (mode) => (() => {
4835
- var _el$28 = createElement("text");
4836
- setProp(_el$28, "flexShrink", 0);
4837
- setProp(_el$28, "marginRight", 2);
4838
- insert(_el$28, mode === "project" ? "Project" : "System");
5224
+ var _el$27 = createElement("text");
5225
+ setProp(_el$27, "flexShrink", 0);
5226
+ setProp(_el$27, "marginRight", 2);
5227
+ insert(_el$27, mode === "project" ? "Project" : "System");
4839
5228
  effect((_p$) => {
4840
- var _v$8 = props.state.mode === mode ? theme.strong : theme.faint, _v$9 = props.state.mode === mode ? TextAttributes.BOLD | TextAttributes.UNDERLINE : TextAttributes.NONE;
4841
- _v$8 !== _p$.e && (_p$.e = setProp(_el$28, "fg", _v$8, _p$.e));
4842
- _v$9 !== _p$.t && (_p$.t = setProp(_el$28, "attributes", _v$9, _p$.t));
5229
+ var _v$8 = props.state.mode === mode ? theme.strong : theme.muted, _v$9 = props.state.mode === mode ? TextAttributes.BOLD | TextAttributes.UNDERLINE : TextAttributes.NONE;
5230
+ _v$8 !== _p$.e && (_p$.e = setProp(_el$27, "fg", _v$8, _p$.e));
5231
+ _v$9 !== _p$.t && (_p$.t = setProp(_el$27, "attributes", _v$9, _p$.t));
4843
5232
  return _p$;
4844
5233
  }, {
4845
5234
  e: void 0,
4846
5235
  t: void 0
4847
5236
  });
4848
- return _el$28;
5237
+ return _el$27;
4849
5238
  })()
4850
5239
  }), _el$7);
4851
5240
  insert(_el$2, createComponent(Key, {
@@ -5027,14 +5416,14 @@ function App(props) {
5027
5416
  return notices();
5028
5417
  },
5029
5418
  children: (notice) => (() => {
5030
- var _el$29 = createElement("box"), _el$30 = createElement("text");
5031
- insertNode(_el$29, _el$30);
5032
- setProp(_el$29, "paddingLeft", 1);
5033
- setProp(_el$29, "height", 1);
5034
- setProp(_el$30, "truncate", true);
5035
- insert(_el$30, () => notice.message);
5036
- effect((_$p) => setProp(_el$30, "fg", notice.color, _$p));
5037
- return _el$29;
5419
+ var _el$28 = createElement("box"), _el$29 = createElement("text");
5420
+ insertNode(_el$28, _el$29);
5421
+ setProp(_el$28, "paddingLeft", 1);
5422
+ setProp(_el$28, "height", 1);
5423
+ setProp(_el$29, "truncate", true);
5424
+ insert(_el$29, () => notice.message);
5425
+ effect((_$p) => setProp(_el$29, "fg", notice.color, _$p));
5426
+ return _el$28;
5038
5427
  })()
5039
5428
  }), _el$19);
5040
5429
  insertNode(_el$19, createTextNode(` `));
@@ -5065,20 +5454,20 @@ function App(props) {
5065
5454
  get when() {
5066
5455
  return toast();
5067
5456
  },
5068
- children: (shown) => (() => {
5069
- var _el$31 = createElement("text");
5070
- setProp(_el$31, "flexShrink", 0);
5071
- insert(_el$31, () => clip(`${shown().text} `, statusRoom() - Array.from(`${summary()} `).length));
5457
+ children: (note) => (() => {
5458
+ var _el$30 = createElement("text");
5459
+ setProp(_el$30, "flexShrink", 0);
5460
+ insert(_el$30, () => clip(`${note().text} `, statusRoom() - graphemes(`${summary()} `).length));
5072
5461
  effect((_p$) => {
5073
- var _v$0 = shown().color, _v$1 = TextAttributes.BOLD;
5074
- _v$0 !== _p$.e && (_p$.e = setProp(_el$31, "fg", _v$0, _p$.e));
5075
- _v$1 !== _p$.t && (_p$.t = setProp(_el$31, "attributes", _v$1, _p$.t));
5462
+ var _v$0 = note().color, _v$1 = TextAttributes.BOLD;
5463
+ _v$0 !== _p$.e && (_p$.e = setProp(_el$30, "fg", _v$0, _p$.e));
5464
+ _v$1 !== _p$.t && (_p$.t = setProp(_el$30, "attributes", _v$1, _p$.t));
5076
5465
  return _p$;
5077
5466
  }, {
5078
5467
  e: void 0,
5079
5468
  t: void 0
5080
5469
  });
5081
- return _el$31;
5470
+ return _el$30;
5082
5471
  })()
5083
5472
  }), _el$25);
5084
5473
  setProp(_el$25, "flexGrow", 1);
@@ -5089,187 +5478,27 @@ function App(props) {
5089
5478
  get when() {
5090
5479
  return confirmation();
5091
5480
  },
5092
- children: (pending) => createComponent(Popup, {
5093
- get title() {
5094
- return `${confirmations[pending().action].verb} ${plural(pending().rows.length, "package")}?`;
5481
+ children: (pending) => createComponent(ConfirmPopup, {
5482
+ get pending() {
5483
+ return pending();
5095
5484
  },
5096
- get width() {
5097
- return confirmWidth(pending());
5485
+ get state() {
5486
+ return props.state;
5098
5487
  },
5099
- get tone() {
5100
- return confirmTone(pending());
5488
+ get where() {
5489
+ return memo(() => props.state.mode === "system")() ? "on this machine" : `in ${tidy(props.state.scope)}`;
5101
5490
  },
5102
- get bindings() {
5103
- return [
5104
- ...needsSignIn(pending()) ? [signIn] : [],
5105
- confirmKey(pending()),
5106
- keys.cancel
5107
- ];
5491
+ confirm: () => {
5492
+ onConfirmation(pending());
5108
5493
  },
5109
- get children() {
5110
- return [
5111
- (() => {
5112
- var _el$32 = createElement("text");
5113
- setProp(_el$32, "wrapMode", "none");
5114
- setProp(_el$32, "truncate", true);
5115
- insert(_el$32, () => destination(pending()));
5116
- effect((_$p) => setProp(_el$32, "fg", theme.muted, _$p));
5117
- return _el$32;
5118
- })(),
5119
- createComponent(Show, {
5120
- get when() {
5121
- return pending().skipped > 0;
5122
- },
5123
- get children() {
5124
- var _el$33 = createElement("text");
5125
- setProp(_el$33, "wrapMode", "word");
5126
- insert(_el$33, () => `${pending().skipped} selected ${pending().skipped === 1 ? "package has" : "packages have"} no update and ${pending().skipped === 1 ? "is" : "are"} left out.`);
5127
- effect((_$p) => setProp(_el$33, "fg", theme.muted, _$p));
5128
- return _el$33;
5129
- }
5130
- }),
5131
- createComponent(For, {
5132
- get each() {
5133
- return pending().refused;
5134
- },
5135
- children: (group) => (() => {
5136
- var _el$45 = createElement("text");
5137
- setProp(_el$45, "wrapMode", "word");
5138
- insert(_el$45, () => `! Left out: ${listed(group.names)}. ${capitalized(group.reason)}.`);
5139
- effect((_$p) => setProp(_el$45, "fg", theme.warn, _$p));
5140
- return _el$45;
5141
- })()
5142
- }),
5143
- (() => {
5144
- var _el$34 = createElement("text");
5145
- insertNode(_el$34, createTextNode(` `));
5146
- return _el$34;
5147
- })(),
5148
- createComponent(Show, {
5149
- get when() {
5150
- return memo(() => !!(pending().action === "update" && props.state.preferences.auditFirst))() && pending().flagged.length + pending().vendor.length < pending().rows.length;
5151
- },
5152
- get children() {
5153
- var _el$36 = createElement("text");
5154
- setProp(_el$36, "wrapMode", "word");
5155
- insert(_el$36, () => pending().flagged.length === 0 && pending().vendor.length === 0 ? "Each is audited first, and only those the audit finds ok are applied." : "The rest are audited first, and only those the audit finds ok are applied.");
5156
- effect((_$p) => setProp(_el$36, "fg", theme.muted, _$p));
5157
- return _el$36;
5158
- }
5159
- }),
5160
- createComponent(Show, {
5161
- get when() {
5162
- return memo(() => pending().action === "update")() && pending().vendor.length > 0;
5163
- },
5164
- get children() {
5165
- var _el$37 = createElement("text");
5166
- insertNode(_el$37, createTextNode(`upup does not audit operating-system or app updates: confirming installs them as the vendor offers them, and upup asks for your password if sudo needs it.`));
5167
- setProp(_el$37, "wrapMode", "word");
5168
- effect((_$p) => setProp(_el$37, "fg", theme.muted, _$p));
5169
- return _el$37;
5170
- }
5171
- }),
5172
- createComponent(Show, {
5173
- get when() {
5174
- return pending().flagged.length > 0;
5175
- },
5176
- get children() {
5177
- var _el$39 = createElement("text");
5178
- setProp(_el$39, "wrapMode", "word");
5179
- insert(_el$39, () => flaggedSentence(pending().flagged));
5180
- effect((_$p) => setProp(_el$39, "fg", theme.warn, _$p));
5181
- return _el$39;
5182
- }
5183
- }),
5184
- createComponent(Show, {
5185
- get when() {
5186
- return memo(() => !!needsSignIn(pending()))() ? signedOut() : void 0;
5187
- },
5188
- children: (provider) => (() => {
5189
- var _el$46 = createElement("text");
5190
- setProp(_el$46, "wrapMode", "word");
5191
- setProp(_el$46, "marginBottom", 1);
5192
- insert(_el$46, () => `! upup is not signed in to ${provider()}, so no model can read this. Press Enter to sign in.`);
5193
- effect((_$p) => setProp(_el$46, "fg", theme.warn, _$p));
5194
- return _el$46;
5195
- })()
5196
- }),
5197
- createComponent(Show, {
5198
- get when() {
5199
- return pending().action === "audit";
5200
- },
5201
- get children() {
5202
- return [(() => {
5203
- var _el$40 = createElement("text");
5204
- insertNode(_el$40, createTextNode(`Both versions are downloaded and verified, and the model reads what changed.`));
5205
- setProp(_el$40, "wrapMode", "word");
5206
- effect((_$p) => setProp(_el$40, "fg", theme.muted, _$p));
5207
- return _el$40;
5208
- })(), createComponent(Show, {
5209
- get when() {
5210
- return props.state.preferences.setup;
5211
- },
5212
- children: (setup) => (() => {
5213
- var _el$47 = createElement("box"), _el$48 = createElement("text"), _el$50 = createElement("text");
5214
- insertNode(_el$47, _el$48);
5215
- insertNode(_el$47, _el$50);
5216
- setProp(_el$47, "flexDirection", "row");
5217
- setProp(_el$47, "height", 1);
5218
- setProp(_el$47, "marginTop", 1);
5219
- insertNode(_el$48, createTextNode(`Model `));
5220
- setProp(_el$48, "flexShrink", 0);
5221
- setProp(_el$50, "flexShrink", 1);
5222
- setProp(_el$50, "truncate", true);
5223
- insert(_el$50, () => `${modelName(setup().provider, setup().modelId)} · ${setup().thinking} thinking`);
5224
- effect((_p$) => {
5225
- var _v$10 = theme.faint, _v$11 = theme.text;
5226
- _v$10 !== _p$.e && (_p$.e = setProp(_el$48, "fg", _v$10, _p$.e));
5227
- _v$11 !== _p$.t && (_p$.t = setProp(_el$50, "fg", _v$11, _p$.t));
5228
- return _p$;
5229
- }, {
5230
- e: void 0,
5231
- t: void 0
5232
- });
5233
- return _el$47;
5234
- })()
5235
- })];
5236
- }
5237
- }),
5238
- createComponent(Show, {
5239
- get when() {
5240
- return pending().flagged.length > 0 || pending().action === "audit" || pending().action === "update" && (props.state.preferences.auditFirst || pending().vendor.length > 0);
5241
- },
5242
- get children() {
5243
- var _el$42 = createElement("text");
5244
- insertNode(_el$42, createTextNode(` `));
5245
- return _el$42;
5246
- }
5247
- }),
5248
- createComponent(For, {
5249
- get each() {
5250
- return flaggedFirst(pending()).slice(shownTop(pending()), shownTop(pending()) + listRoom());
5251
- },
5252
- children: (row) => createComponent(Segments, { get segments() {
5253
- return [
5254
- shrinking(theme.text, ` ${fitName(row.pkg.name, confirmColumns(pending(), confirmInner()).name)}`),
5255
- segment(theme.muted, ` ${fit(row.pkg.current, confirmColumns(pending(), confirmInner()).current)}`),
5256
- segment(theme.strong, pending().action === "uninstall" ? "" : ` → ${fit(row.pkg.target ?? "", confirmColumns(pending(), confirmInner()).target)}`),
5257
- ...flaggedVerdict(pending(), row)
5258
- ];
5259
- } })
5260
- }),
5261
- createComponent(Show, {
5262
- get when() {
5263
- return pending().rows.length > listRoom();
5264
- },
5265
- get children() {
5266
- var _el$44 = createElement("text");
5267
- insert(_el$44, () => ` ${shownTop(pending()) + 1}–${Math.min(pending().rows.length, shownTop(pending()) + listRoom())} of ${pending().rows.length} · ↑↓ scroll`);
5268
- effect((_$p) => setProp(_el$44, "fg", theme.faint, _$p));
5269
- return _el$44;
5270
- }
5271
- })
5272
- ];
5494
+ cancel: () => {
5495
+ setOverlay(none);
5496
+ },
5497
+ signIn: () => {
5498
+ setOverlay({
5499
+ _tag: "Settings",
5500
+ back: pending()
5501
+ });
5273
5502
  }
5274
5503
  })
5275
5504
  }), null);
@@ -5287,11 +5516,11 @@ function App(props) {
5287
5516
  return [keys.closeHelp];
5288
5517
  },
5289
5518
  get children() {
5290
- var _el$51 = createElement("text");
5291
- setProp(_el$51, "wrapMode", "word");
5292
- insert(_el$51, () => notice().text);
5293
- effect((_$p) => setProp(_el$51, "fg", theme.text, _$p));
5294
- return _el$51;
5519
+ var _el$31 = createElement("text");
5520
+ setProp(_el$31, "wrapMode", "word");
5521
+ insert(_el$31, () => notice().text);
5522
+ effect((_$p) => setProp(_el$31, "fg", theme.text, _$p));
5523
+ return _el$31;
5295
5524
  }
5296
5525
  })
5297
5526
  }), null);
@@ -5305,83 +5534,74 @@ function App(props) {
5305
5534
  tone: "quiet",
5306
5535
  width: 86,
5307
5536
  bindings: [{
5308
- keys: [],
5309
- hint: "↑↓",
5310
- description: "scroll"
5311
- }, {
5312
5537
  keys: [],
5313
5538
  hint: "Esc",
5314
5539
  description: "close"
5315
5540
  }],
5541
+ scrolls: true,
5316
5542
  get children() {
5317
- var _el$26 = createElement("scrollbox"), _el$27 = createElement("box");
5318
- insertNode(_el$26, _el$27);
5319
- use((box) => {
5320
- helpScroller = box;
5321
- }, _el$26);
5322
- setProp(_el$27, "flexDirection", "row");
5323
- setProp(_el$27, "flexShrink", 0);
5324
- insert(_el$27, createComponent(For, {
5543
+ var _el$26 = createElement("box");
5544
+ setProp(_el$26, "flexDirection", "row");
5545
+ setProp(_el$26, "flexShrink", 0);
5546
+ insert(_el$26, createComponent(For, {
5325
5547
  get each() {
5326
5548
  return helpColumns();
5327
5549
  },
5328
5550
  children: (column) => (() => {
5329
- var _el$52 = createElement("box");
5330
- setProp(_el$52, "flexDirection", "column");
5331
- setProp(_el$52, "flexGrow", 1);
5332
- setProp(_el$52, "flexBasis", 0);
5333
- setProp(_el$52, "flexShrink", 0);
5334
- insert(_el$52, createComponent(For, {
5551
+ var _el$32 = createElement("box");
5552
+ setProp(_el$32, "flexDirection", "column");
5553
+ setProp(_el$32, "flexGrow", 1);
5554
+ setProp(_el$32, "flexBasis", 0);
5555
+ setProp(_el$32, "flexShrink", 0);
5556
+ insert(_el$32, createComponent(For, {
5335
5557
  each: column,
5336
5558
  children: (group, index) => (() => {
5337
- var _el$53 = createElement("box"), _el$54 = createElement("text");
5338
- insertNode(_el$53, _el$54);
5339
- setProp(_el$53, "flexDirection", "column");
5340
- setProp(_el$53, "flexShrink", 0);
5341
- setProp(_el$54, "flexShrink", 0);
5342
- insert(_el$54, () => group.title);
5343
- insert(_el$53, createComponent(For, {
5559
+ var _el$33 = createElement("box"), _el$34 = createElement("text");
5560
+ insertNode(_el$33, _el$34);
5561
+ setProp(_el$33, "flexDirection", "column");
5562
+ setProp(_el$33, "flexShrink", 0);
5563
+ setProp(_el$34, "flexShrink", 0);
5564
+ insert(_el$34, () => group.title);
5565
+ insert(_el$33, createComponent(For, {
5344
5566
  get each() {
5345
5567
  return group.bindings;
5346
5568
  },
5347
5569
  children: (binding) => (() => {
5348
- var _el$55 = createElement("box"), _el$56 = createElement("box"), _el$57 = createElement("text");
5349
- insertNode(_el$55, _el$56);
5350
- insertNode(_el$55, _el$57);
5351
- setProp(_el$55, "flexDirection", "row");
5352
- setProp(_el$55, "height", 1);
5353
- setProp(_el$55, "flexShrink", 0);
5354
- setProp(_el$56, "width", 13);
5355
- setProp(_el$56, "flexShrink", 0);
5356
- setProp(_el$56, "flexDirection", "row");
5357
- insert(_el$56, createComponent(Key, { get hint() {
5570
+ var _el$35 = createElement("box"), _el$36 = createElement("box"), _el$37 = createElement("text");
5571
+ insertNode(_el$35, _el$36);
5572
+ insertNode(_el$35, _el$37);
5573
+ setProp(_el$35, "flexDirection", "row");
5574
+ setProp(_el$35, "height", 1);
5575
+ setProp(_el$35, "flexShrink", 0);
5576
+ setProp(_el$36, "width", 13);
5577
+ setProp(_el$36, "flexShrink", 0);
5578
+ setProp(_el$36, "flexDirection", "row");
5579
+ insert(_el$36, createComponent(Key, { get hint() {
5358
5580
  return binding.hint ?? "";
5359
5581
  } }));
5360
- setProp(_el$57, "flexShrink", 1);
5361
- setProp(_el$57, "truncate", true);
5362
- insert(_el$57, () => binding.description ?? "");
5363
- effect((_$p) => setProp(_el$57, "fg", theme.text, _$p));
5364
- return _el$55;
5582
+ setProp(_el$37, "flexShrink", 0);
5583
+ insert(_el$37, () => binding.description ?? "");
5584
+ effect((_$p) => setProp(_el$37, "fg", theme.text, _$p));
5585
+ return _el$35;
5365
5586
  })()
5366
5587
  }), null);
5367
5588
  effect((_p$) => {
5368
- var _v$12 = index() === 0 ? 0 : 1, _v$13 = theme.accent, _v$14 = TextAttributes.BOLD;
5369
- _v$12 !== _p$.e && (_p$.e = setProp(_el$53, "marginTop", _v$12, _p$.e));
5370
- _v$13 !== _p$.t && (_p$.t = setProp(_el$54, "fg", _v$13, _p$.t));
5371
- _v$14 !== _p$.a && (_p$.a = setProp(_el$54, "attributes", _v$14, _p$.a));
5589
+ var _v$10 = index() === 0 ? 0 : 1, _v$11 = theme.accent, _v$12 = TextAttributes.BOLD;
5590
+ _v$10 !== _p$.e && (_p$.e = setProp(_el$33, "marginTop", _v$10, _p$.e));
5591
+ _v$11 !== _p$.t && (_p$.t = setProp(_el$34, "fg", _v$11, _p$.t));
5592
+ _v$12 !== _p$.a && (_p$.a = setProp(_el$34, "attributes", _v$12, _p$.a));
5372
5593
  return _p$;
5373
5594
  }, {
5374
5595
  e: void 0,
5375
5596
  t: void 0,
5376
5597
  a: void 0
5377
5598
  });
5378
- return _el$53;
5599
+ return _el$33;
5379
5600
  })()
5380
5601
  }));
5381
- return _el$52;
5602
+ return _el$32;
5382
5603
  })()
5383
5604
  }));
5384
- effect((_$p) => setProp(_el$26, "height", Math.max(3, Math.min(helpHeight(), dimensions().height - 9)), _$p));
5385
5605
  return _el$26;
5386
5606
  }
5387
5607
  });
@@ -5420,7 +5640,9 @@ function App(props) {
5420
5640
  get request() {
5421
5641
  return request();
5422
5642
  },
5423
- answer: (password) => fire(props.session.answerPassword(password))
5643
+ answer: (password) => {
5644
+ fire(props.session.answerPassword(password));
5645
+ }
5424
5646
  })
5425
5647
  }), null);
5426
5648
  insert(_el$, createComponent(Show, {
@@ -5440,11 +5662,11 @@ function App(props) {
5440
5662
  }, keys.deny];
5441
5663
  },
5442
5664
  get children() {
5443
- var _el$58 = createElement("text");
5444
- setProp(_el$58, "wrapMode", "word");
5445
- insert(_el$58, () => `${running().app} is open. upup quits it to install its update, then opens it again. Unsaved work in it may be lost.`);
5446
- effect((_$p) => setProp(_el$58, "fg", theme.text, _$p));
5447
- return _el$58;
5665
+ var _el$38 = createElement("text");
5666
+ setProp(_el$38, "wrapMode", "word");
5667
+ insert(_el$38, () => `${running().app} is open. upup quits it to install its update, then opens it again. Unsaved work in it may be lost.`);
5668
+ effect((_$p) => setProp(_el$38, "fg", theme.text, _$p));
5669
+ return _el$38;
5448
5670
  }
5449
5671
  })
5450
5672
  }), null);
@@ -5466,36 +5688,36 @@ function App(props) {
5466
5688
  },
5467
5689
  get fallback() {
5468
5690
  return [(() => {
5469
- var _el$62 = createElement("text");
5470
- setProp(_el$62, "wrapMode", "word");
5471
- insert(_el$62, () => `${blocked().command} wants to run install scripts that are not allowed:`);
5472
- effect((_$p) => setProp(_el$62, "fg", theme.text, _$p));
5473
- return _el$62;
5691
+ var _el$42 = createElement("text");
5692
+ setProp(_el$42, "wrapMode", "word");
5693
+ insert(_el$42, () => `${blocked().command} wants to run install scripts that are not allowed:`);
5694
+ effect((_$p) => setProp(_el$42, "fg", theme.text, _$p));
5695
+ return _el$42;
5474
5696
  })(), createComponent(For, {
5475
5697
  get each() {
5476
5698
  return blocked().scripts;
5477
5699
  },
5478
5700
  children: (script) => (() => {
5479
- var _el$63 = createElement("text");
5480
- insert(_el$63, ` ${script}`);
5481
- effect((_$p) => setProp(_el$63, "fg", theme.warn, _$p));
5482
- return _el$63;
5701
+ var _el$43 = createElement("text");
5702
+ insert(_el$43, ` ${script}`);
5703
+ effect((_$p) => setProp(_el$43, "fg", theme.warn, _$p));
5704
+ return _el$43;
5483
5705
  })()
5484
5706
  })];
5485
5707
  },
5486
5708
  get children() {
5487
5709
  return [(() => {
5488
- var _el$59 = createElement("text");
5489
- setProp(_el$59, "wrapMode", "word");
5490
- insert(_el$59, () => `${blocked().command} failed in npm's strict-allow-scripts check before installing (an npm bug with new global install folders).`);
5491
- effect((_$p) => setProp(_el$59, "fg", theme.text, _$p));
5492
- return _el$59;
5710
+ var _el$39 = createElement("text");
5711
+ setProp(_el$39, "wrapMode", "word");
5712
+ insert(_el$39, () => `${blocked().command} failed in npm's strict-allow-scripts check before installing (an npm bug with new global install folders).`);
5713
+ effect((_$p) => setProp(_el$39, "fg", theme.text, _$p));
5714
+ return _el$39;
5493
5715
  })(), (() => {
5494
- var _el$60 = createElement("text");
5495
- insertNode(_el$60, createTextNode(`Retrying turns the strict check off for this one command, so install scripts not on your allow list may run.`));
5496
- setProp(_el$60, "wrapMode", "word");
5497
- effect((_$p) => setProp(_el$60, "fg", theme.warn, _$p));
5498
- return _el$60;
5716
+ var _el$40 = createElement("text");
5717
+ insertNode(_el$40, createTextNode(`Retrying turns the strict check off for this one command, so install scripts not on your allow list may run.`));
5718
+ setProp(_el$40, "wrapMode", "word");
5719
+ effect((_$p) => setProp(_el$40, "fg", theme.warn, _$p));
5720
+ return _el$40;
5499
5721
  })()];
5500
5722
  }
5501
5723
  });
@@ -5503,7 +5725,7 @@ function App(props) {
5503
5725
  })
5504
5726
  }), null);
5505
5727
  effect((_p$) => {
5506
- var _v$3 = theme.onAccent, _v$4 = theme.accent, _v$5 = TextAttributes.BOLD, _v$6 = theme.faint, _v$7 = props.state.running ? theme.text : theme.muted;
5728
+ var _v$3 = theme.onAccent, _v$4 = theme.accent, _v$5 = TextAttributes.BOLD, _v$6 = theme.muted, _v$7 = props.state.running ? theme.text : theme.muted;
5507
5729
  _v$3 !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$3, _p$.e));
5508
5730
  _v$4 !== _p$.t && (_p$.t = setProp(_el$3, "bg", _v$4, _p$.t));
5509
5731
  _v$5 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$5, _p$.a));
@@ -5519,7 +5741,7 @@ function App(props) {
5519
5741
  });
5520
5742
  return _el$;
5521
5743
  })();
5522
- }
5744
+ };
5523
5745
  // src/tui/Tui.tsx
5524
5746
  const connect = Effect.fn("Tui.connect")(function* (projectDir) {
5525
5747
  const session = yield* Session;
@@ -5549,16 +5771,24 @@ const connect = Effect.fn("Tui.connect")(function* (projectDir) {
5549
5771
  });
5550
5772
  const launch = Effect.fn("Tui.launch")(function* (projectDir) {
5551
5773
  const { view, quit, done } = yield* connect(projectDir);
5552
- const renderer = yield* Effect.acquireRelease(Effect.promise(() => createCliRenderer({ exitOnCtrlC: true })), (renderer) => Effect.sync(() => renderer.destroy()));
5774
+ const renderer = yield* Effect.acquireRelease(Effect.promise(async () => await createCliRenderer({ exitOnCtrlC: true })), (created) => Effect.sync(() => {
5775
+ created.destroy();
5776
+ }));
5553
5777
  renderer.on("destroy", quit);
5554
- const adopt = Effect.promise(() => renderer.getPalette({ timeout: 300 }).then((colors) => setBackground(colors.defaultBackground), () => void 0));
5555
- setThemeMode(yield* Effect.promise(() => renderer.waitForThemeMode(300)));
5778
+ const adopt = Effect.promise(async () => {
5779
+ const colors = await renderer.getPalette({ timeout: 300 }).catch(() => void 0);
5780
+ if (colors !== void 0) setBackground(colors.defaultBackground);
5781
+ });
5782
+ setThemeMode(yield* Effect.promise(async () => await renderer.waitForThemeMode(300)));
5783
+ const context = yield* Effect.context();
5556
5784
  yield* adopt;
5557
5785
  renderer.on("theme_mode", (mode) => {
5558
5786
  setThemeMode(mode);
5559
- Effect.runPromise(adopt);
5787
+ Effect.runPromiseWith(context)(adopt);
5788
+ });
5789
+ yield* Effect.promise(async () => {
5790
+ await render(view, renderer);
5560
5791
  });
5561
- yield* Effect.promise(() => render(view, renderer));
5562
5792
  yield* done;
5563
5793
  });
5564
5794
  export { connect, launch };