brew-tui 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -66,7 +66,7 @@ import { rm as rm2 } from "fs/promises";
66
66
  import { render } from "ink";
67
67
 
68
68
  // src/app.tsx
69
- import { useEffect as useEffect23, useState as useState21 } from "react";
69
+ import { useEffect as useEffect22, useState as useState20 } from "react";
70
70
  import { useApp } from "ink";
71
71
 
72
72
  // src/components/layout/app-layout.tsx
@@ -77,28 +77,46 @@ import { Box as Box3 } from "ink";
77
77
  import { Box, Text as Text3 } from "ink";
78
78
 
79
79
  // src/hooks/use-terminal-size.ts
80
- import { useEffect, useState } from "react";
80
+ import { useSyncExternalStore } from "react";
81
81
  import { useStdout } from "ink";
82
+ var FALLBACK = { columns: 80, rows: 24 };
83
+ var cache = /* @__PURE__ */ new WeakMap();
84
+ function snapshot(stdout) {
85
+ return {
86
+ columns: stdout.columns ?? FALLBACK.columns,
87
+ rows: stdout.rows ?? FALLBACK.rows
88
+ };
89
+ }
90
+ function getCache(stdout) {
91
+ const existing = cache.get(stdout);
92
+ if (existing) return existing;
93
+ const entry = {
94
+ current: snapshot(stdout),
95
+ subscribers: /* @__PURE__ */ new Set()
96
+ };
97
+ cache.set(stdout, entry);
98
+ stdout.on("resize", () => {
99
+ entry.current = snapshot(stdout);
100
+ entry.subscribers.forEach((cb) => cb());
101
+ });
102
+ return entry;
103
+ }
82
104
  function useTerminalSize() {
83
105
  const { stdout } = useStdout();
84
- const [size, setSize] = useState(() => ({
85
- columns: stdout?.columns ?? 80,
86
- rows: stdout?.rows ?? 24
87
- }));
88
- useEffect(() => {
89
- if (!stdout) return;
90
- const onResize = () => {
91
- setSize({
92
- columns: stdout.columns ?? 80,
93
- rows: stdout.rows ?? 24
94
- });
95
- };
96
- stdout.on("resize", onResize);
97
- return () => {
98
- stdout.off("resize", onResize);
99
- };
100
- }, [stdout]);
101
- return size;
106
+ return useSyncExternalStore(
107
+ (cb) => {
108
+ if (!stdout) return () => {
109
+ };
110
+ const entry = getCache(stdout);
111
+ entry.subscribers.add(cb);
112
+ return () => {
113
+ entry.subscribers.delete(cb);
114
+ };
115
+ },
116
+ () => stdout ? getCache(stdout).current : FALLBACK,
117
+ // Server snapshot — not used in CLI, but useSyncExternalStore requires it.
118
+ () => FALLBACK
119
+ );
102
120
  }
103
121
 
104
122
  // src/stores/navigation-store.ts
@@ -322,7 +340,7 @@ var GRADIENTS = {
322
340
  };
323
341
 
324
342
  // src/components/common/blinking-text.tsx
325
- import { useEffect as useEffect2, useState as useState2 } from "react";
343
+ import { useEffect, useState } from "react";
326
344
  import { Text as Text2 } from "ink";
327
345
  import { jsx as jsx2 } from "react/jsx-runtime";
328
346
  function BlinkingText({
@@ -331,8 +349,8 @@ function BlinkingText({
331
349
  bold = true,
332
350
  children
333
351
  }) {
334
- const [bright, setBright] = useState2(true);
335
- useEffect2(() => {
352
+ const [bright, setBright] = useState(true);
353
+ useEffect(() => {
336
354
  const id = setInterval(() => setBright((b) => !b), intervalMs);
337
355
  return () => clearInterval(id);
338
356
  }, [intervalMs]);
@@ -349,6 +367,20 @@ var SPACING = {
349
367
  xl: 6,
350
368
  xxl: 8
351
369
  };
370
+ var BREAKPOINTS = {
371
+ /** Below this we collapse to single-column rows (only the name fits). */
372
+ narrow: 50,
373
+ /** Below this we drop the description column but keep version. */
374
+ mid: 80,
375
+ /** At or above this we render every column comfortably. */
376
+ wide: 120
377
+ };
378
+ function getLayoutMode(columns) {
379
+ if (columns < BREAKPOINTS.narrow) return "single";
380
+ if (columns < BREAKPOINTS.mid) return "compact";
381
+ if (columns < BREAKPOINTS.wide) return "comfortable";
382
+ return "wide";
383
+ }
352
384
 
353
385
  // src/components/layout/header.tsx
354
386
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
@@ -553,12 +585,12 @@ function Footer() {
553
585
  }
554
586
 
555
587
  // src/hooks/use-container-size.ts
556
- import { useEffect as useEffect3, useState as useState3 } from "react";
588
+ import { useEffect as useEffect2, useState as useState2 } from "react";
557
589
  import { measureElement } from "ink";
558
590
  function useContainerSize(ref) {
559
591
  const terminal = useTerminalSize();
560
- const [size, setSize] = useState3({ width: 0, height: 0 });
561
- useEffect3(() => {
592
+ const [size, setSize] = useState2({ width: 0, height: 0 });
593
+ useEffect2(() => {
562
594
  if (!ref.current) return;
563
595
  const measured = measureElement(ref.current);
564
596
  setSize(
@@ -835,7 +867,7 @@ async function markOnboardingComplete() {
835
867
  }
836
868
 
837
869
  // src/views/welcome.tsx
838
- import { useEffect as useEffect4 } from "react";
870
+ import { useEffect as useEffect3 } from "react";
839
871
  import { Box as Box4, Text as Text5 } from "ink";
840
872
 
841
873
  // src/hooks/use-view-input.ts
@@ -849,7 +881,7 @@ function useViewInput(handler, opts) {
849
881
  // src/views/welcome.tsx
850
882
  import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
851
883
  function WelcomeView({ onContinue }) {
852
- useEffect4(() => {
884
+ useEffect3(() => {
853
885
  return () => {
854
886
  };
855
887
  }, []);
@@ -968,7 +1000,7 @@ function UpgradePrompt({ viewId }) {
968
1000
  }
969
1001
 
970
1002
  // src/views/dashboard.tsx
971
- import { useEffect as useEffect5, useMemo as useMemo2 } from "react";
1003
+ import { useEffect as useEffect4, useMemo as useMemo2 } from "react";
972
1004
  import { Box as Box9, Text as Text12 } from "ink";
973
1005
 
974
1006
  // src/hooks/use-visible-rows.ts
@@ -2071,10 +2103,6 @@ function formatDate(value) {
2071
2103
  const locale = getLocale();
2072
2104
  return date.toLocaleDateString(locale === "es" ? "es-ES" : "en-US");
2073
2105
  }
2074
- function truncate(str, maxLen) {
2075
- if (str.length <= maxLen) return str;
2076
- return str.slice(0, maxLen - 1) + "\u2026";
2077
- }
2078
2106
 
2079
2107
  // src/views/dashboard.tsx
2080
2108
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
@@ -2133,7 +2161,7 @@ function DashboardView() {
2133
2161
  minRows: 2
2134
2162
  });
2135
2163
  const halfRows = Math.max(1, Math.floor(splitRows / 2));
2136
- useEffect5(() => {
2164
+ useEffect4(() => {
2137
2165
  fetchAll();
2138
2166
  }, []);
2139
2167
  useViewInput((input) => {
@@ -2246,14 +2274,14 @@ function DashboardView() {
2246
2274
  }
2247
2275
 
2248
2276
  // src/views/installed.tsx
2249
- import { useState as useState6, useMemo as useMemo3, useEffect as useEffect9, useRef as useRef3 } from "react";
2277
+ import { useState as useState5, useMemo as useMemo3, useEffect as useEffect8, useRef as useRef3 } from "react";
2250
2278
  import { Box as Box15, Text as Text18 } from "ink";
2251
2279
 
2252
2280
  // src/hooks/use-debounce.ts
2253
- import { useState as useState4, useEffect as useEffect6 } from "react";
2281
+ import { useState as useState3, useEffect as useEffect5 } from "react";
2254
2282
  function useDebounce(value, delayMs) {
2255
- const [debounced, setDebounced] = useState4(value);
2256
- useEffect6(() => {
2283
+ const [debounced, setDebounced] = useState3(value);
2284
+ useEffect5(() => {
2257
2285
  const timer = setTimeout(() => setDebounced(value), delayMs);
2258
2286
  return () => clearTimeout(timer);
2259
2287
  }, [value, delayMs]);
@@ -2261,7 +2289,7 @@ function useDebounce(value, delayMs) {
2261
2289
  }
2262
2290
 
2263
2291
  // src/hooks/use-brew-stream.ts
2264
- import { useState as useState5, useCallback, useRef as useRef2, useEffect as useEffect7 } from "react";
2292
+ import { useState as useState4, useCallback, useRef as useRef2, useEffect as useEffect6 } from "react";
2265
2293
  var MAX_LINES = 100;
2266
2294
  async function logToHistory(args, success, error) {
2267
2295
  const detected = detectAction(args);
@@ -2274,13 +2302,13 @@ async function logToHistory(args, success, error) {
2274
2302
  }
2275
2303
  }
2276
2304
  function useBrewStream() {
2277
- const [lines, setLines] = useState5([]);
2278
- const [isRunning, setIsRunning] = useState5(false);
2279
- const [error, setError2] = useState5(null);
2305
+ const [lines, setLines] = useState4([]);
2306
+ const [isRunning, setIsRunning] = useState4(false);
2307
+ const [error, setError2] = useState4(null);
2280
2308
  const cancelRef = useRef2(false);
2281
2309
  const generatorRef = useRef2(null);
2282
2310
  const mountedRef = useRef2(true);
2283
- useEffect7(() => {
2311
+ useEffect6(() => {
2284
2312
  mountedRef.current = true;
2285
2313
  return () => {
2286
2314
  mountedRef.current = false;
@@ -2360,13 +2388,13 @@ function SearchInput({ defaultValue, onChange, placeholder, isActive = true }) {
2360
2388
  }
2361
2389
 
2362
2390
  // src/components/common/confirm-dialog.tsx
2363
- import { useEffect as useEffect8 } from "react";
2391
+ import { useEffect as useEffect7 } from "react";
2364
2392
  import { Box as Box11, Text as Text14, useInput as useInput3 } from "ink";
2365
2393
  import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2366
2394
  function ConfirmDialog({ message, onConfirm, onCancel }) {
2367
2395
  const locale = useLocaleStore((s) => s.locale);
2368
2396
  const { openModal, closeModal } = useModalStore();
2369
- useEffect8(() => {
2397
+ useEffect7(() => {
2370
2398
  openModal();
2371
2399
  return () => {
2372
2400
  closeModal();
@@ -2450,14 +2478,18 @@ function InstalledView() {
2450
2478
  const containerRef = useRef3(null);
2451
2479
  const { width: containerWidth } = useContainerSize(containerRef);
2452
2480
  const columns = containerWidth > 0 ? containerWidth : 80;
2453
- const nameWidth = Math.max(12, Math.floor(columns * 0.35));
2481
+ const mode = getLayoutMode(columns);
2482
+ const nameWidth = mode === "single" ? Math.max(
2483
+ 8,
2484
+ columns - 2
2485
+ /* cursor + gap */
2486
+ ) : Math.max(12, Math.floor(columns * 0.35));
2454
2487
  const versionWidth = Math.max(8, Math.floor(columns * 0.15));
2455
- const descWidth = Math.max(10, columns - nameWidth - versionWidth - 8);
2456
- const [filter, setFilter] = useState6("");
2457
- const [cursor, setCursor] = useState6(0);
2458
- const [tab, setTab] = useState6("formulae");
2459
- const [isSearching, setIsSearching] = useState6(false);
2460
- const [confirmUninstall, setConfirmUninstall] = useState6(null);
2488
+ const [filter, setFilter] = useState5("");
2489
+ const [cursor, setCursor] = useState5(0);
2490
+ const [tab, setTab] = useState5("formulae");
2491
+ const [isSearching, setIsSearching] = useState5(false);
2492
+ const [confirmUninstall, setConfirmUninstall] = useState5(null);
2461
2493
  const debouncedFilter = useDebounce(filter, 200);
2462
2494
  const stream = useBrewStream();
2463
2495
  const listRows = useVisibleRows({
@@ -2470,10 +2502,10 @@ function InstalledView() {
2470
2502
  fallbackReservedRows: 14,
2471
2503
  minRows: 1
2472
2504
  });
2473
- useEffect9(() => {
2505
+ useEffect8(() => {
2474
2506
  fetchInstalled();
2475
2507
  }, []);
2476
- useEffect9(() => {
2508
+ useEffect8(() => {
2477
2509
  if (isSearching) {
2478
2510
  openModal();
2479
2511
  return () => {
@@ -2614,12 +2646,10 @@ function InstalledView() {
2614
2646
  ),
2615
2647
  isSearching && /* @__PURE__ */ jsx19(Box15, { marginBottom: SPACING.xs, borderStyle: "round", borderColor: COLORS.gold, paddingX: SPACING.xs, children: /* @__PURE__ */ jsx19(SearchInput, { defaultValue: filter, onChange: setFilter, isActive: isSearching }) }),
2616
2648
  /* @__PURE__ */ jsxs16(Box15, { gap: SPACING.xs, borderStyle: "single", borderBottom: true, borderTop: false, borderLeft: false, borderRight: false, borderColor: COLORS.border, children: [
2617
- /* @__PURE__ */ jsxs16(Text18, { color: COLORS.text, bold: true, children: [
2618
- " ",
2619
- t("installed_col_package").padEnd(nameWidth)
2620
- ] }),
2621
- /* @__PURE__ */ jsx19(Text18, { color: COLORS.text, bold: true, children: t("installed_col_version").padEnd(versionWidth) }),
2622
- /* @__PURE__ */ jsx19(Text18, { color: COLORS.text, bold: true, children: t("installed_col_status") })
2649
+ /* @__PURE__ */ jsx19(Text18, { color: COLORS.text, children: " " }),
2650
+ /* @__PURE__ */ jsx19(Box15, { width: nameWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx19(Text18, { color: COLORS.text, bold: true, wrap: "truncate", children: t("installed_col_package") }) }),
2651
+ mode !== "single" && /* @__PURE__ */ jsx19(Box15, { width: versionWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx19(Text18, { color: COLORS.text, bold: true, wrap: "truncate", children: t("installed_col_version") }) }),
2652
+ mode !== "single" && mode !== "compact" && /* @__PURE__ */ jsx19(Box15, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx19(Text18, { color: COLORS.text, bold: true, wrap: "truncate", children: t("installed_col_status") }) })
2623
2653
  ] }),
2624
2654
  /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
2625
2655
  visible.length === 0 && /* @__PURE__ */ jsx19(Box15, { paddingY: SPACING.xs, justifyContent: "center", children: /* @__PURE__ */ jsx19(Text18, { color: COLORS.textSecondary, italic: true, children: t("installed_noPackages") }) }),
@@ -2630,14 +2660,25 @@ function InstalledView() {
2630
2660
  visible.map((item, i) => {
2631
2661
  const idx = start + i;
2632
2662
  const isCurrent = idx === cursor;
2663
+ const hasBadge = item.outdated || item.pinned || item.kegOnly || item.installedAsDependency;
2633
2664
  return /* @__PURE__ */ jsxs16(SelectableRow, { isCurrent, children: [
2634
- /* @__PURE__ */ jsx19(Text18, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: truncate(item.name, nameWidth).padEnd(nameWidth) }),
2635
- /* @__PURE__ */ jsx19(Text18, { color: COLORS.teal, children: item.version.padEnd(versionWidth) }),
2636
- item.outdated && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_outdated"), variant: "warning" }),
2637
- item.pinned && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_pinned"), variant: "info" }),
2638
- item.kegOnly && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_kegOnly"), variant: "muted" }),
2639
- item.installedAsDependency && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_dep"), variant: "muted" }),
2640
- !item.outdated && !item.pinned && !item.kegOnly && !item.installedAsDependency && /* @__PURE__ */ jsx19(Text18, { color: COLORS.textSecondary, dimColor: true, children: truncate(item.desc, descWidth) })
2665
+ /* @__PURE__ */ jsx19(Box15, { width: nameWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx19(
2666
+ Text18,
2667
+ {
2668
+ bold: isCurrent,
2669
+ inverse: isCurrent,
2670
+ color: isCurrent ? COLORS.text : COLORS.muted,
2671
+ wrap: "truncate-middle",
2672
+ children: item.name
2673
+ }
2674
+ ) }),
2675
+ mode !== "single" && /* @__PURE__ */ jsx19(Box15, { width: versionWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx19(Text18, { color: COLORS.teal, wrap: "truncate", children: item.version }) }),
2676
+ mode !== "single" && mode !== "compact" && /* @__PURE__ */ jsx19(Box15, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: hasBadge ? /* @__PURE__ */ jsxs16(Box15, { gap: SPACING.xs, children: [
2677
+ item.outdated && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_outdated"), variant: "warning" }),
2678
+ item.pinned && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_pinned"), variant: "info" }),
2679
+ item.kegOnly && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_kegOnly"), variant: "muted" }),
2680
+ item.installedAsDependency && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_dep"), variant: "muted" })
2681
+ ] }) : /* @__PURE__ */ jsx19(Text18, { color: COLORS.textSecondary, dimColor: true, wrap: "truncate", children: item.desc }) })
2641
2682
  ] }, item.name);
2642
2683
  }),
2643
2684
  start + MAX_VISIBLE_ROWS < allItems.length && /* @__PURE__ */ jsxs16(Text18, { color: COLORS.textSecondary, dimColor: true, children: [
@@ -2650,17 +2691,17 @@ function InstalledView() {
2650
2691
  }
2651
2692
 
2652
2693
  // src/views/search.tsx
2653
- import { useState as useState7, useCallback as useCallback2, useEffect as useEffect10, useRef as useRef4 } from "react";
2694
+ import { useState as useState6, useCallback as useCallback2, useEffect as useEffect9, useRef as useRef4 } from "react";
2654
2695
  import { Box as Box16, Text as Text19 } from "ink";
2655
2696
  import { TextInput as TextInput2 } from "@inkjs/ui";
2656
2697
  import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2657
2698
  function SearchView() {
2658
- const [query, setQuery] = useState7("");
2659
- const [results, setResults] = useState7(null);
2660
- const [searching, setSearching] = useState7(false);
2661
- const [searchError, setSearchError] = useState7(null);
2662
- const [cursor, setCursor] = useState7(0);
2663
- const [confirmInstall, setConfirmInstall] = useState7(null);
2699
+ const [query, setQuery] = useState6("");
2700
+ const [results, setResults] = useState6(null);
2701
+ const [searching, setSearching] = useState6(false);
2702
+ const [searchError, setSearchError] = useState6(null);
2703
+ const [cursor, setCursor] = useState6(0);
2704
+ const [confirmInstall, setConfirmInstall] = useState6(null);
2664
2705
  const stream = useBrewStream();
2665
2706
  const { openModal, closeModal } = useModalStore();
2666
2707
  const navigate = useNavigationStore((s) => s.navigate);
@@ -2677,7 +2718,7 @@ function SearchView() {
2677
2718
  fallbackReservedRows: 14,
2678
2719
  minRows: 1
2679
2720
  });
2680
- useEffect10(() => {
2721
+ useEffect9(() => {
2681
2722
  if (results !== null) {
2682
2723
  openModal();
2683
2724
  return () => {
@@ -2705,7 +2746,7 @@ function SearchView() {
2705
2746
  setSearching(false);
2706
2747
  }
2707
2748
  }, []);
2708
- useEffect10(() => {
2749
+ useEffect9(() => {
2709
2750
  if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current) {
2710
2751
  hasRefreshed.current = true;
2711
2752
  void fetchInstalled();
@@ -2720,7 +2761,7 @@ function SearchView() {
2720
2761
  Math.max(0, allResults.length - resultRows)
2721
2762
  );
2722
2763
  const visibleResults = allResults.slice(start, start + resultRows);
2723
- useEffect10(() => {
2764
+ useEffect9(() => {
2724
2765
  setCursor((current) => Math.min(current, Math.max(0, allResults.length - 1)));
2725
2766
  }, [allResults.length]);
2726
2767
  useViewInput((input, key) => {
@@ -2840,7 +2881,7 @@ function SearchView() {
2840
2881
  const idx = start + i;
2841
2882
  const isCurrent = idx === cursor;
2842
2883
  return /* @__PURE__ */ jsxs17(SelectableRow, { isCurrent, children: [
2843
- /* @__PURE__ */ jsx20(Text19, { bold: isCurrent, inverse: isCurrent, children: result.name }),
2884
+ /* @__PURE__ */ jsx20(Box16, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx20(Text19, { bold: isCurrent, inverse: isCurrent, wrap: "truncate-middle", children: result.name }) }),
2844
2885
  /* @__PURE__ */ jsx20(
2845
2886
  StatusBadge,
2846
2887
  {
@@ -2862,7 +2903,7 @@ function SearchView() {
2862
2903
  }
2863
2904
 
2864
2905
  // src/views/outdated.tsx
2865
- import { useEffect as useEffect11, useMemo as useMemo4, useRef as useRef5, useState as useState8 } from "react";
2906
+ import { useEffect as useEffect10, useMemo as useMemo4, useRef as useRef5, useState as useState7 } from "react";
2866
2907
  import { Box as Box17, Text as Text20 } from "ink";
2867
2908
  import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
2868
2909
  function ImpactPanel({ impact }) {
@@ -2889,12 +2930,12 @@ function ImpactPanel({ impact }) {
2889
2930
  function OutdatedView() {
2890
2931
  const { outdated, loading, errors, fetchOutdated } = useBrewStore();
2891
2932
  const stream = useBrewStream();
2892
- const [cursor, setCursor] = useState8(0);
2893
- const [confirmAction, setConfirmAction] = useState8(null);
2933
+ const [cursor, setCursor] = useState7(0);
2934
+ const [confirmAction, setConfirmAction] = useState7(null);
2894
2935
  const hasRefreshed = useRef5(false);
2895
2936
  const pendingUpgradeRef = useRef5(null);
2896
- const [impact, setImpact] = useState8(null);
2897
- const [impactLoading, setImpactLoading] = useState8(false);
2937
+ const [impact, setImpact] = useState7(null);
2938
+ const [impactLoading, setImpactLoading] = useState7(false);
2898
2939
  const listRows = useVisibleRows({
2899
2940
  reservedRows: impact || impactLoading ? 11 : 7,
2900
2941
  fallbackReservedRows: impact || impactLoading ? 18 : 14,
@@ -2905,10 +2946,10 @@ function OutdatedView() {
2905
2946
  fallbackReservedRows: 14,
2906
2947
  minRows: 1
2907
2948
  });
2908
- useEffect11(() => {
2949
+ useEffect10(() => {
2909
2950
  fetchOutdated();
2910
2951
  }, []);
2911
- useEffect11(() => {
2952
+ useEffect10(() => {
2912
2953
  if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current) {
2913
2954
  hasRefreshed.current = true;
2914
2955
  void fetchOutdated().then(() => {
@@ -2935,7 +2976,7 @@ function OutdatedView() {
2935
2976
  [outdated.formulae, outdated.casks]
2936
2977
  );
2937
2978
  const debouncedCursor = useDebounce(cursor, 150);
2938
- useEffect11(() => {
2979
+ useEffect10(() => {
2939
2980
  const pkg = allOutdated[debouncedCursor];
2940
2981
  if (!pkg || stream.isRunning) {
2941
2982
  setImpact(null);
@@ -3061,7 +3102,16 @@ ${t("outdated_upgradeAllList", { list: allOutdated.map((p) => p.name).join(", ")
3061
3102
  const idx = start + i;
3062
3103
  const isCurrent = idx === cursor;
3063
3104
  return /* @__PURE__ */ jsxs18(SelectableRow, { isCurrent, children: [
3064
- /* @__PURE__ */ jsx21(Text20, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: pkg.name }),
3105
+ /* @__PURE__ */ jsx21(Box17, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx21(
3106
+ Text20,
3107
+ {
3108
+ bold: isCurrent,
3109
+ inverse: isCurrent,
3110
+ color: isCurrent ? COLORS.text : COLORS.muted,
3111
+ wrap: "truncate-middle",
3112
+ children: pkg.name
3113
+ }
3114
+ ) }),
3065
3115
  /* @__PURE__ */ jsx21(VersionArrow, { current: pkg.installed_versions[0] ?? "", latest: pkg.current_version }),
3066
3116
  pkg.pinned && /* @__PURE__ */ jsx21(StatusBadge, { label: t("outdated_pinned"), variant: "info" })
3067
3117
  ] }, pkg.name);
@@ -3083,7 +3133,7 @@ ${t("outdated_upgradeAllList", { list: allOutdated.map((p) => p.name).join(", ")
3083
3133
  }
3084
3134
 
3085
3135
  // src/views/package-info.tsx
3086
- import { useEffect as useEffect12, useRef as useRef6, useState as useState9 } from "react";
3136
+ import { useEffect as useEffect11, useRef as useRef6, useState as useState8 } from "react";
3087
3137
  import { Box as Box18, Text as Text21 } from "ink";
3088
3138
  import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
3089
3139
  var ACTION_PROGRESS_KEYS = {
@@ -3099,21 +3149,21 @@ var ACTION_CONFIRM_KEYS = {
3099
3149
  function PackageInfoView() {
3100
3150
  const packageName = useNavigationStore((s) => s.selectedPackage);
3101
3151
  const packageType = useNavigationStore((s) => s.selectedPackageType);
3102
- const [formula, setFormula] = useState9(null);
3103
- const [loading, setLoading2] = useState9(true);
3104
- const [error, setError2] = useState9(null);
3105
- const [confirmAction, setConfirmAction] = useState9(null);
3152
+ const [formula, setFormula] = useState8(null);
3153
+ const [loading, setLoading2] = useState8(true);
3154
+ const [error, setError2] = useState8(null);
3155
+ const [confirmAction, setConfirmAction] = useState8(null);
3106
3156
  const activeActionRef = useRef6("install");
3107
3157
  const mountedRef = useRef6(true);
3108
3158
  const hasRefreshed = useRef6(false);
3109
3159
  const stream = useBrewStream();
3110
- useEffect12(() => {
3160
+ useEffect11(() => {
3111
3161
  mountedRef.current = true;
3112
3162
  return () => {
3113
3163
  mountedRef.current = false;
3114
3164
  };
3115
3165
  }, []);
3116
- useEffect12(() => {
3166
+ useEffect11(() => {
3117
3167
  if (!packageName) return;
3118
3168
  setLoading2(true);
3119
3169
  const fetchInfo = async () => {
@@ -3138,7 +3188,7 @@ function PackageInfoView() {
3138
3188
  }
3139
3189
  });
3140
3190
  }, [packageName, packageType]);
3141
- useEffect12(() => {
3191
+ useEffect11(() => {
3142
3192
  if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current && packageName) {
3143
3193
  hasRefreshed.current = true;
3144
3194
  const refreshFn = packageType === "cask" ? getCaskInfo(packageName).then((c) => c ? { ...c, installed: c.installed ? [{ version: c.installed }] : [] } : null) : getFormulaInfo(packageName);
@@ -3298,7 +3348,7 @@ function PackageInfoView() {
3298
3348
  }
3299
3349
 
3300
3350
  // src/views/services.tsx
3301
- import { useEffect as useEffect13, useRef as useRef7, useState as useState10 } from "react";
3351
+ import { useEffect as useEffect12, useRef as useRef7, useState as useState9 } from "react";
3302
3352
  import { Box as Box19, Text as Text22 } from "ink";
3303
3353
  import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
3304
3354
  var STATUS_VARIANTS = {
@@ -3315,21 +3365,26 @@ function humaniseServiceError(message) {
3315
3365
  }
3316
3366
  function ServicesView() {
3317
3367
  const { services, loading, errors, fetchServices, serviceAction: serviceAction2 } = useBrewStore();
3318
- const [cursor, setCursor] = useState10(0);
3319
- const [actionInProgress, setActionInProgress] = useState10(false);
3320
- const [confirmAction, setConfirmAction] = useState10(null);
3321
- const [lastError, setLastError] = useState10(null);
3368
+ const [cursor, setCursor] = useState9(0);
3369
+ const [actionInProgress, setActionInProgress] = useState9(false);
3370
+ const [confirmAction, setConfirmAction] = useState9(null);
3371
+ const [lastError, setLastError] = useState9(null);
3322
3372
  const containerRef = useRef7(null);
3323
3373
  const { width: containerWidth } = useContainerSize(containerRef);
3324
3374
  const cols = containerWidth > 0 ? containerWidth : 80;
3325
- const svcNameWidth = Math.max(12, Math.floor(cols * 0.35));
3375
+ const mode = getLayoutMode(cols);
3376
+ const svcNameWidth = mode === "single" ? Math.max(
3377
+ 8,
3378
+ cols - 2
3379
+ /* cursor + gap */
3380
+ ) : Math.max(12, Math.floor(cols * 0.35));
3326
3381
  const svcStatusWidth = Math.max(8, Math.floor(cols * 0.15));
3327
3382
  const MAX_VISIBLE_ROWS = useVisibleRows({
3328
3383
  reservedRows: lastError || actionInProgress ? 8 : 6,
3329
3384
  fallbackReservedRows: lastError || actionInProgress ? 16 : 14,
3330
3385
  minRows: 1
3331
3386
  });
3332
- useEffect13(() => {
3387
+ useEffect12(() => {
3333
3388
  fetchServices();
3334
3389
  }, []);
3335
3390
  useViewInput((input, key) => {
@@ -3394,12 +3449,10 @@ function ServicesView() {
3394
3449
  ) }),
3395
3450
  /* @__PURE__ */ jsxs20(Box19, { flexDirection: "column", marginTop: SPACING.xs, children: [
3396
3451
  /* @__PURE__ */ jsxs20(Box19, { gap: SPACING.xs, borderStyle: "single", borderBottom: true, borderTop: false, borderLeft: false, borderRight: false, borderColor: COLORS.border, paddingBottom: SPACING.none, children: [
3397
- /* @__PURE__ */ jsxs20(Text22, { bold: true, color: COLORS.text, children: [
3398
- " ",
3399
- t("services_name").padEnd(svcNameWidth)
3400
- ] }),
3401
- /* @__PURE__ */ jsx23(Text22, { bold: true, color: COLORS.text, children: t("services_status").padEnd(svcStatusWidth) }),
3402
- /* @__PURE__ */ jsx23(Text22, { bold: true, color: COLORS.text, children: t("services_user") })
3452
+ /* @__PURE__ */ jsx23(Text22, { bold: true, color: COLORS.text, children: " " }),
3453
+ /* @__PURE__ */ jsx23(Box19, { width: svcNameWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx23(Text22, { bold: true, color: COLORS.text, wrap: "truncate", children: t("services_name") }) }),
3454
+ mode !== "single" && /* @__PURE__ */ jsx23(Box19, { width: svcStatusWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx23(Text22, { bold: true, color: COLORS.text, wrap: "truncate", children: t("services_status") }) }),
3455
+ mode !== "single" && mode !== "compact" && /* @__PURE__ */ jsx23(Box19, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx23(Text22, { bold: true, color: COLORS.text, wrap: "truncate", children: t("services_user") }) })
3403
3456
  ] }),
3404
3457
  start > 0 && /* @__PURE__ */ jsxs20(Text22, { color: COLORS.textSecondary, dimColor: true, children: [
3405
3458
  " ",
@@ -3409,10 +3462,21 @@ function ServicesView() {
3409
3462
  const idx = start + i;
3410
3463
  const isCurrent = idx === cursor;
3411
3464
  return /* @__PURE__ */ jsxs20(SelectableRow, { isCurrent, children: [
3412
- /* @__PURE__ */ jsx23(Text22, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: truncate(svc.name, svcNameWidth - 2).padEnd(svcNameWidth - 2) }),
3413
- /* @__PURE__ */ jsx23(StatusBadge, { label: svc.status, variant: STATUS_VARIANTS[svc.status] }),
3414
- /* @__PURE__ */ jsx23(Text22, { color: COLORS.muted, children: svc.user ?? "-" }),
3415
- svc.exit_code != null && svc.exit_code !== 0 && /* @__PURE__ */ jsx23(Text22, { color: COLORS.error, children: t("common_exit", { code: svc.exit_code }) })
3465
+ /* @__PURE__ */ jsx23(Box19, { width: svcNameWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx23(
3466
+ Text22,
3467
+ {
3468
+ bold: isCurrent,
3469
+ inverse: isCurrent,
3470
+ color: isCurrent ? COLORS.text : COLORS.muted,
3471
+ wrap: "truncate-middle",
3472
+ children: svc.name
3473
+ }
3474
+ ) }),
3475
+ mode !== "single" && /* @__PURE__ */ jsx23(Box19, { width: svcStatusWidth, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx23(StatusBadge, { label: svc.status, variant: STATUS_VARIANTS[svc.status] }) }),
3476
+ mode !== "single" && mode !== "compact" && /* @__PURE__ */ jsxs20(Box19, { flexGrow: 1, flexShrink: 1, minWidth: 0, gap: SPACING.xs, children: [
3477
+ /* @__PURE__ */ jsx23(Text22, { color: COLORS.muted, wrap: "truncate", children: svc.user ?? "-" }),
3478
+ svc.exit_code != null && svc.exit_code !== 0 && /* @__PURE__ */ jsx23(Text22, { color: COLORS.error, children: t("common_exit", { code: svc.exit_code }) })
3479
+ ] })
3416
3480
  ] }, svc.name);
3417
3481
  }),
3418
3482
  start + MAX_VISIBLE_ROWS < services.length && /* @__PURE__ */ jsxs20(Text22, { color: COLORS.textSecondary, dimColor: true, children: [
@@ -3431,25 +3495,25 @@ function ServicesView() {
3431
3495
  }
3432
3496
 
3433
3497
  // src/views/doctor.tsx
3434
- import { useEffect as useEffect14, useRef as useRef8, useState as useState11 } from "react";
3498
+ import { useEffect as useEffect13, useRef as useRef8, useState as useState10 } from "react";
3435
3499
  import { Box as Box20, Text as Text23 } from "ink";
3436
3500
  import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
3437
3501
  function DoctorView() {
3438
3502
  const { doctorWarnings, doctorClean, loading, errors, fetchDoctor } = useBrewStore();
3439
- const [cursor, setCursor] = useState11(0);
3503
+ const [cursor, setCursor] = useState10(0);
3440
3504
  const visibleWarnings = useVisibleRows({
3441
3505
  reservedRows: 6,
3442
3506
  fallbackReservedRows: 14,
3443
3507
  minRows: 1
3444
3508
  });
3445
3509
  const mountedRef = useRef8(true);
3446
- useEffect14(() => {
3510
+ useEffect13(() => {
3447
3511
  mountedRef.current = true;
3448
3512
  return () => {
3449
3513
  mountedRef.current = false;
3450
3514
  };
3451
3515
  }, []);
3452
- useEffect14(() => {
3516
+ useEffect13(() => {
3453
3517
  fetchDoctor();
3454
3518
  }, []);
3455
3519
  useViewInput((input, key) => {
@@ -3487,7 +3551,7 @@ function DoctorView() {
3487
3551
  }
3488
3552
 
3489
3553
  // src/views/profiles.tsx
3490
- import { useEffect as useEffect15, useRef as useRef9, useState as useState12 } from "react";
3554
+ import { useEffect as useEffect14, useRef as useRef9, useState as useState11 } from "react";
3491
3555
  import { Box as Box25 } from "ink";
3492
3556
 
3493
3557
  // src/stores/profile-store.ts
@@ -3859,23 +3923,23 @@ function ProfileEditDesc({ name, defaultDesc, loadError, onSubmit }) {
3859
3923
  import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
3860
3924
  function ProfilesView() {
3861
3925
  const { profileNames, selectedProfile, loading, loadError, fetchProfiles, loadProfile: loadProfile2, exportCurrent, deleteProfile: deleteProfile2, updateProfile: updateProfile2 } = useProfileStore();
3862
- const [cursor, setCursor] = useState12(0);
3863
- const [mode, setMode] = useState12("list");
3864
- const [newName, setNewName] = useState12("");
3865
- const [confirmDelete, setConfirmDelete] = useState12(false);
3866
- const [editName, setEditName] = useState12("");
3867
- const [editDesc, setEditDesc] = useState12("");
3868
- const [importLines, setImportLines] = useState12([]);
3869
- const [importRunning, setImportRunning] = useState12(false);
3870
- const [importHadError, setImportHadError] = useState12(false);
3871
- const [importProfile2, setImportProfile] = useState12(null);
3926
+ const [cursor, setCursor] = useState11(0);
3927
+ const [mode, setMode] = useState11("list");
3928
+ const [newName, setNewName] = useState11("");
3929
+ const [confirmDelete, setConfirmDelete] = useState11(false);
3930
+ const [editName, setEditName] = useState11("");
3931
+ const [editDesc, setEditDesc] = useState11("");
3932
+ const [importLines, setImportLines] = useState11([]);
3933
+ const [importRunning, setImportRunning] = useState11(false);
3934
+ const [importHadError, setImportHadError] = useState11(false);
3935
+ const [importProfile2, setImportProfile] = useState11(null);
3872
3936
  const { openModal, closeModal } = useModalStore();
3873
3937
  const importGenRef = useRef9(null);
3874
3938
  const mountedRef = useRef9(true);
3875
- useEffect15(() => {
3939
+ useEffect14(() => {
3876
3940
  fetchProfiles();
3877
3941
  }, []);
3878
- useEffect15(() => {
3942
+ useEffect14(() => {
3879
3943
  mountedRef.current = true;
3880
3944
  return () => {
3881
3945
  mountedRef.current = false;
@@ -3883,7 +3947,7 @@ function ProfilesView() {
3883
3947
  importGenRef.current = null;
3884
3948
  };
3885
3949
  }, []);
3886
- useEffect15(() => {
3950
+ useEffect14(() => {
3887
3951
  if (mode !== "list") {
3888
3952
  openModal();
3889
3953
  return () => {
@@ -4059,7 +4123,7 @@ function ProfilesView() {
4059
4123
  }
4060
4124
 
4061
4125
  // src/views/smart-cleanup.tsx
4062
- import { useEffect as useEffect16, useRef as useRef10, useState as useState13 } from "react";
4126
+ import { useEffect as useEffect15, useRef as useRef10, useState as useState12 } from "react";
4063
4127
  import { Box as Box26, Text as Text28 } from "ink";
4064
4128
 
4065
4129
  // src/stores/cleanup-store.ts
@@ -4183,10 +4247,10 @@ var useCleanupStore = create10((set, get) => ({
4183
4247
  import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
4184
4248
  function SmartCleanupView() {
4185
4249
  const { summary, selected, loading, error, analyze, toggleSelect, selectAll } = useCleanupStore();
4186
- const [cursor, setCursor] = useState13(0);
4187
- const [confirmClean, setConfirmClean] = useState13(false);
4188
- const [confirmForce, setConfirmForce] = useState13(false);
4189
- const [failedNames, setFailedNames] = useState13([]);
4250
+ const [cursor, setCursor] = useState12(0);
4251
+ const [confirmClean, setConfirmClean] = useState12(false);
4252
+ const [confirmForce, setConfirmForce] = useState12(false);
4253
+ const [failedNames, setFailedNames] = useState12([]);
4190
4254
  const stream = useBrewStream();
4191
4255
  const hasRefreshed = useRef10(false);
4192
4256
  const listRows = useVisibleRows({
@@ -4194,10 +4258,10 @@ function SmartCleanupView() {
4194
4258
  fallbackReservedRows: confirmClean || confirmForce ? 18 : 14,
4195
4259
  minRows: 1
4196
4260
  });
4197
- useEffect16(() => {
4261
+ useEffect15(() => {
4198
4262
  analyze();
4199
4263
  }, []);
4200
- useEffect16(() => {
4264
+ useEffect15(() => {
4201
4265
  if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current) {
4202
4266
  hasRefreshed.current = true;
4203
4267
  void analyze();
@@ -4333,7 +4397,7 @@ function SmartCleanupView() {
4333
4397
  }
4334
4398
 
4335
4399
  // src/views/history.tsx
4336
- import { useEffect as useEffect17, useState as useState14, useMemo as useMemo5 } from "react";
4400
+ import { useEffect as useEffect16, useState as useState13, useMemo as useMemo5 } from "react";
4337
4401
  import { Box as Box27, Text as Text29 } from "ink";
4338
4402
 
4339
4403
  // src/stores/history-store.ts
@@ -4386,12 +4450,12 @@ var ACTION_LABEL_KEYS = {
4386
4450
  var FILTERS = ["all", "install", "uninstall", "upgrade", "upgrade-all"];
4387
4451
  function HistoryView() {
4388
4452
  const { entries, loading, error, fetchHistory, clearHistory: clearHistory2 } = useHistoryStore();
4389
- const [cursor, setCursor] = useState14(0);
4390
- const [filter, setFilter] = useState14("all");
4391
- const [searchQuery, setSearchQuery] = useState14("");
4392
- const [isSearching, setIsSearching] = useState14(false);
4393
- const [confirmClear, setConfirmClear] = useState14(false);
4394
- const [confirmReplay, setConfirmReplay] = useState14(null);
4453
+ const [cursor, setCursor] = useState13(0);
4454
+ const [filter, setFilter] = useState13("all");
4455
+ const [searchQuery, setSearchQuery] = useState13("");
4456
+ const [isSearching, setIsSearching] = useState13(false);
4457
+ const [confirmClear, setConfirmClear] = useState13(false);
4458
+ const [confirmReplay, setConfirmReplay] = useState13(null);
4395
4459
  const stream = useBrewStream();
4396
4460
  const debouncedQuery = useDebounce(searchQuery, 200);
4397
4461
  const { openModal, closeModal } = useModalStore();
@@ -4405,10 +4469,10 @@ function HistoryView() {
4405
4469
  fallbackReservedRows: 16,
4406
4470
  minRows: 1
4407
4471
  });
4408
- useEffect17(() => {
4472
+ useEffect16(() => {
4409
4473
  fetchHistory();
4410
4474
  }, []);
4411
- useEffect17(() => {
4475
+ useEffect16(() => {
4412
4476
  if (isSearching) {
4413
4477
  openModal();
4414
4478
  return () => {
@@ -4529,8 +4593,8 @@ function HistoryView() {
4529
4593
  const ts = new Date(entry.timestamp).getTime() / 1e3;
4530
4594
  return /* @__PURE__ */ jsxs28(SelectableRow, { isCurrent, children: [
4531
4595
  /* @__PURE__ */ jsx31(Text29, { color, bold: true, children: icon }),
4532
- /* @__PURE__ */ jsx31(Text29, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: t(ACTION_LABEL_KEYS[entry.action]).padEnd(12) }),
4533
- /* @__PURE__ */ jsx31(Text29, { color: COLORS.text, children: entry.packageName ?? t("history_all") }),
4596
+ /* @__PURE__ */ jsx31(Box27, { width: 14, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx31(Text29, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, wrap: "truncate", children: t(ACTION_LABEL_KEYS[entry.action]) }) }),
4597
+ /* @__PURE__ */ jsx31(Box27, { flexGrow: 1, flexShrink: 1, minWidth: 0, children: /* @__PURE__ */ jsx31(Text29, { color: COLORS.text, wrap: "truncate-middle", children: entry.packageName ?? t("history_all") }) }),
4534
4598
  entry.success ? /* @__PURE__ */ jsx31(StatusBadge, { label: t("badge_ok"), variant: "success" }) : /* @__PURE__ */ jsx31(StatusBadge, { label: t("badge_fail"), variant: "error" }),
4535
4599
  /* @__PURE__ */ jsx31(Text29, { color: COLORS.muted, children: formatRelativeTime(ts) })
4536
4600
  ] }, entry.id);
@@ -4549,7 +4613,7 @@ function HistoryView() {
4549
4613
  }
4550
4614
 
4551
4615
  // src/views/security-audit.tsx
4552
- import { useEffect as useEffect18, useState as useState15 } from "react";
4616
+ import { useEffect as useEffect17, useState as useState14 } from "react";
4553
4617
  import { Box as Box28, Text as Text30 } from "ink";
4554
4618
  import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
4555
4619
  var SEVERITY_COLORS = {
@@ -4572,11 +4636,11 @@ function isNetworkError(msg) {
4572
4636
  function SecurityAuditView() {
4573
4637
  const { summary, loading, error, scan, cachedAt } = useSecurityStore();
4574
4638
  const navigate = useNavigationStore((s) => s.navigate);
4575
- const [cursor, setCursor] = useState15(0);
4576
- const [expandedPkg, setExpandedPkg] = useState15(null);
4577
- const [confirmUpgrade, setConfirmUpgrade] = useState15(null);
4639
+ const [cursor, setCursor] = useState14(0);
4640
+ const [expandedPkg, setExpandedPkg] = useState14(null);
4641
+ const [confirmUpgrade, setConfirmUpgrade] = useState14(null);
4578
4642
  const stream = useBrewStream();
4579
- useEffect18(() => {
4643
+ useEffect17(() => {
4580
4644
  scan();
4581
4645
  }, []);
4582
4646
  const results = summary?.results ?? [];
@@ -4681,7 +4745,7 @@ function SecurityAuditView() {
4681
4745
  }
4682
4746
 
4683
4747
  // src/views/account.tsx
4684
- import { useState as useState16 } from "react";
4748
+ import { useState as useState15 } from "react";
4685
4749
  import { Box as Box29, Text as Text31 } from "ink";
4686
4750
  import { TextInput as TextInput5 } from "@inkjs/ui";
4687
4751
 
@@ -4763,13 +4827,13 @@ async function redeemPromoCode(code) {
4763
4827
  import { Fragment as Fragment5, jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
4764
4828
  function AccountView() {
4765
4829
  const { status, license, deactivate: deactivate2, revalidate: revalidate2, degradation } = useLicenseStore();
4766
- const [confirmDeactivate, setConfirmDeactivate] = useState16(false);
4767
- const [deactivating, setDeactivating] = useState16(false);
4768
- const [deactivateError, setDeactivateError] = useState16(null);
4769
- const [promoMode, setPromoMode] = useState16(false);
4770
- const [promoLoading, setPromoLoading] = useState16(false);
4771
- const [promoResult, setPromoResult] = useState16(null);
4772
- const [revalidating, setRevalidating] = useState16(false);
4830
+ const [confirmDeactivate, setConfirmDeactivate] = useState15(false);
4831
+ const [deactivating, setDeactivating] = useState15(false);
4832
+ const [deactivateError, setDeactivateError] = useState15(null);
4833
+ const [promoMode, setPromoMode] = useState15(false);
4834
+ const [promoLoading, setPromoLoading] = useState15(false);
4835
+ const [promoResult, setPromoResult] = useState15(null);
4836
+ const [revalidating, setRevalidating] = useState15(false);
4773
4837
  useViewInput((input, key) => {
4774
4838
  if (confirmDeactivate || deactivating || promoMode || revalidating) {
4775
4839
  if (key.escape && promoMode) {
@@ -4913,13 +4977,13 @@ function AccountView() {
4913
4977
  status === "pro" || status === "team" || status === "expired" ? `v ${t("hint_revalidate")} ` : "",
4914
4978
  revalidating ? t("account_revalidating") : "",
4915
4979
  " ",
4916
- t("app_version", { version: "1.1.0" })
4980
+ t("app_version", { version: "1.2.1" })
4917
4981
  ] }) })
4918
4982
  ] });
4919
4983
  }
4920
4984
 
4921
4985
  // src/views/rollback.tsx
4922
- import { useCallback as useCallback3, useEffect as useEffect19, useRef as useRef11, useState as useState17 } from "react";
4986
+ import { useCallback as useCallback3, useEffect as useEffect18, useRef as useRef11, useState as useState16 } from "react";
4923
4987
  import { Box as Box30, Text as Text32 } from "ink";
4924
4988
 
4925
4989
  // src/stores/rollback-store.ts
@@ -4955,10 +5019,10 @@ async function detectStrategy(name, targetVersion, packageType) {
4955
5019
  }
4956
5020
  return { strategy: "pin-only" };
4957
5021
  }
4958
- async function buildRollbackPlan(snapshot, isPro) {
5022
+ async function buildRollbackPlan(snapshot2, isPro) {
4959
5023
  if (!isPro) throw new Error("Pro license required");
4960
5024
  const current = await captureSnapshot();
4961
- const diff = diffSnapshots(snapshot, current);
5025
+ const diff = diffSnapshots(snapshot2, current);
4962
5026
  const actions = [];
4963
5027
  const warnings = [];
4964
5028
  for (const entry of diff.upgraded) {
@@ -5024,8 +5088,8 @@ async function buildRollbackPlan(snapshot, isPro) {
5024
5088
  warnings.push(`${caskPinCount} cask(s) will be pinned only (version restoration not supported)`);
5025
5089
  }
5026
5090
  const canExecute = actions.some((a) => a.strategy !== "unavailable");
5027
- const snapshotLabel = snapshot.label ?? "Auto";
5028
- const snapshotDate = new Date(snapshot.capturedAt).toLocaleString();
5091
+ const snapshotLabel = snapshot2.label ?? "Auto";
5092
+ const snapshotDate = new Date(snapshot2.capturedAt).toLocaleString();
5029
5093
  logger.debug("Built rollback plan", { actionCount: actions.length, canExecute });
5030
5094
  return {
5031
5095
  snapshotLabel,
@@ -5113,14 +5177,14 @@ var useRollbackStore = create12((set) => ({
5113
5177
  set({ error: err instanceof Error ? err.message : String(err), loading: false });
5114
5178
  }
5115
5179
  },
5116
- selectSnapshot: async (snapshot, isPro) => {
5117
- if (!snapshot) {
5180
+ selectSnapshot: async (snapshot2, isPro) => {
5181
+ if (!snapshot2) {
5118
5182
  set({ selectedSnapshot: null, plan: null, planError: null });
5119
5183
  return;
5120
5184
  }
5121
- set({ selectedSnapshot: snapshot, plan: null, planLoading: true, planError: null });
5185
+ set({ selectedSnapshot: snapshot2, plan: null, planLoading: true, planError: null });
5122
5186
  try {
5123
- const plan = await buildRollbackPlan(snapshot, isPro);
5187
+ const plan = await buildRollbackPlan(snapshot2, isPro);
5124
5188
  set({ plan, planLoading: false });
5125
5189
  } catch (err) {
5126
5190
  set({ planError: err instanceof Error ? err.message : String(err), planLoading: false });
@@ -5225,11 +5289,11 @@ function PlanView({ plan }) {
5225
5289
  function RollbackView() {
5226
5290
  const isPro = useLicenseStore((s) => s.isPro);
5227
5291
  const { snapshots, loading, error, plan, planLoading, planError, fetchSnapshots, selectSnapshot, clearPlan } = useRollbackStore();
5228
- const [cursor, setCursor] = useState17(0);
5229
- const [phase, setPhase] = useState17("list");
5230
- const [streamLines, setStreamLines] = useState17([]);
5231
- const [streamRunning, setStreamRunning] = useState17(false);
5232
- const [streamError, setStreamError] = useState17(null);
5292
+ const [cursor, setCursor] = useState16(0);
5293
+ const [phase, setPhase] = useState16("list");
5294
+ const [streamLines, setStreamLines] = useState16([]);
5295
+ const [streamRunning, setStreamRunning] = useState16(false);
5296
+ const [streamError, setStreamError] = useState16(null);
5233
5297
  const generatorRef = useRef11(null);
5234
5298
  const mountedRef = useRef11(true);
5235
5299
  const snapshotRows = useVisibleRows({
@@ -5237,14 +5301,14 @@ function RollbackView() {
5237
5301
  fallbackReservedRows: 14,
5238
5302
  minRows: 1
5239
5303
  });
5240
- useEffect19(() => {
5304
+ useEffect18(() => {
5241
5305
  mountedRef.current = true;
5242
5306
  return () => {
5243
5307
  mountedRef.current = false;
5244
5308
  void generatorRef.current?.return(void 0);
5245
5309
  };
5246
5310
  }, []);
5247
- useEffect19(() => {
5311
+ useEffect18(() => {
5248
5312
  void fetchSnapshots(isPro());
5249
5313
  }, []);
5250
5314
  const runRollback = useCallback3(async (p) => {
@@ -5381,7 +5445,7 @@ function RollbackView() {
5381
5445
  }
5382
5446
 
5383
5447
  // src/views/brewfile.tsx
5384
- import { useCallback as useCallback4, useEffect as useEffect20, useRef as useRef12, useState as useState18 } from "react";
5448
+ import { useCallback as useCallback4, useEffect as useEffect19, useRef as useRef12, useState as useState17 } from "react";
5385
5449
  import { Box as Box31, Text as Text33 } from "ink";
5386
5450
  import { TextInput as TextInput6 } from "@inkjs/ui";
5387
5451
  import { jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
@@ -5427,14 +5491,14 @@ function DriftSummary({ drift }) {
5427
5491
  function BrewfileView() {
5428
5492
  const isPro = useLicenseStore((s) => s.isPro);
5429
5493
  const { schema, drift, loading, driftLoading, error, load, createFromCurrent } = useBrewfileStore();
5430
- const [phase, setPhase] = useState18("overview");
5431
- const [streamLines, setStreamLines] = useState18([]);
5432
- const [streamRunning, setStreamRunning] = useState18(false);
5433
- const [streamError, setStreamError] = useState18(null);
5434
- const [resultMessage, setResultMessage] = useState18("");
5494
+ const [phase, setPhase] = useState17("overview");
5495
+ const [streamLines, setStreamLines] = useState17([]);
5496
+ const [streamRunning, setStreamRunning] = useState17(false);
5497
+ const [streamError, setStreamError] = useState17(null);
5498
+ const [resultMessage, setResultMessage] = useState17("");
5435
5499
  const generatorRef = useRef12(null);
5436
5500
  const mountedRef = useRef12(true);
5437
- useEffect20(() => {
5501
+ useEffect19(() => {
5438
5502
  mountedRef.current = true;
5439
5503
  void load();
5440
5504
  return () => {
@@ -5610,7 +5674,7 @@ function BrewfileView() {
5610
5674
  }
5611
5675
 
5612
5676
  // src/views/sync.tsx
5613
- import { useCallback as useCallback5, useEffect as useEffect21, useState as useState19 } from "react";
5677
+ import { useCallback as useCallback5, useEffect as useEffect20, useState as useState18 } from "react";
5614
5678
  import { Box as Box32, Text as Text34 } from "ink";
5615
5679
  import { Fragment as Fragment6, jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
5616
5680
  function OverviewSection({
@@ -5736,14 +5800,14 @@ function SyncView() {
5736
5800
  const isPro = useLicenseStore((s) => s.isPro);
5737
5801
  const navigate = useNavigationStore((s) => s.navigate);
5738
5802
  const { config, lastResult, conflicts, loading, error, initialize, syncNow, resolveConflicts } = useSyncStore();
5739
- const [phase, setPhase] = useState19("overview");
5740
- const [syncError, setSyncError] = useState19(null);
5741
- const [conflictEntries, setConflictEntries] = useState19([]);
5742
- const [cursor, setCursor] = useState19(0);
5743
- useEffect21(() => {
5803
+ const [phase, setPhase] = useState18("overview");
5804
+ const [syncError, setSyncError] = useState18(null);
5805
+ const [conflictEntries, setConflictEntries] = useState18([]);
5806
+ const [cursor, setCursor] = useState18(0);
5807
+ useEffect20(() => {
5744
5808
  void initialize(isPro());
5745
5809
  }, []);
5746
- useEffect21(() => {
5810
+ useEffect20(() => {
5747
5811
  if (conflicts.length > 0) {
5748
5812
  setConflictEntries(
5749
5813
  conflicts.map((c) => ({ conflict: c, resolution: "pending" }))
@@ -5908,7 +5972,7 @@ function SyncView() {
5908
5972
  }
5909
5973
 
5910
5974
  // src/views/compliance.tsx
5911
- import { useCallback as useCallback6, useEffect as useEffect22, useRef as useRef13, useState as useState20 } from "react";
5975
+ import { useCallback as useCallback6, useEffect as useEffect21, useRef as useRef13, useState as useState19 } from "react";
5912
5976
  import { Box as Box33, Text as Text35 } from "ink";
5913
5977
  import { TextInput as TextInput7 } from "@inkjs/ui";
5914
5978
 
@@ -6035,13 +6099,13 @@ function ViolationList({ violations }) {
6035
6099
  function ComplianceView() {
6036
6100
  const isPro = useLicenseStore((s) => s.isPro);
6037
6101
  const { policy, report, loading, error, importPolicy, runCheck } = useComplianceStore();
6038
- const [phase, setPhase] = useState20("overview");
6039
- const [resultMessage, setResultMessage] = useState20(null);
6040
- const [streamLines, setStreamLines] = useState20([]);
6041
- const [streamRunning, setStreamRunning] = useState20(false);
6102
+ const [phase, setPhase] = useState19("overview");
6103
+ const [resultMessage, setResultMessage] = useState19(null);
6104
+ const [streamLines, setStreamLines] = useState19([]);
6105
+ const [streamRunning, setStreamRunning] = useState19(false);
6042
6106
  const generatorRef = useRef13(null);
6043
6107
  const mountedRef = useRef13(true);
6044
- useEffect22(() => {
6108
+ useEffect21(() => {
6045
6109
  mountedRef.current = true;
6046
6110
  return () => {
6047
6111
  mountedRef.current = false;
@@ -6246,7 +6310,7 @@ function ComplianceView() {
6246
6310
  import { Fragment as Fragment7, jsx as jsx38, jsxs as jsxs35 } from "react/jsx-runtime";
6247
6311
  function LicenseInitializer() {
6248
6312
  const initLicense = useLicenseStore((s) => s.initialize);
6249
- useEffect23(() => {
6313
+ useEffect22(() => {
6250
6314
  initLicense();
6251
6315
  }, []);
6252
6316
  return null;
@@ -6299,8 +6363,8 @@ function App() {
6299
6363
  const { exit } = useApp();
6300
6364
  const currentView = useNavigationStore((s) => s.currentView);
6301
6365
  const isTestEnv = typeof process !== "undefined" && false;
6302
- const [showWelcome, setShowWelcome] = useState21(isTestEnv ? false : null);
6303
- useEffect23(() => {
6366
+ const [showWelcome, setShowWelcome] = useState20(isTestEnv ? false : null);
6367
+ useEffect22(() => {
6304
6368
  if (isTestEnv) return;
6305
6369
  void hasCompletedOnboarding().then((done) => setShowWelcome(!done));
6306
6370
  }, []);
@@ -6397,7 +6461,7 @@ async function reportError(err, context = {}) {
6397
6461
  const config = await resolveConfig();
6398
6462
  if (!config.enabled || !config.endpoint) return;
6399
6463
  const machineId = await getMachineId();
6400
- const version = true ? "1.1.0" : "unknown";
6464
+ const version = true ? "1.2.1" : "unknown";
6401
6465
  await postReport(buildReport("error", err, context, machineId, version), config);
6402
6466
  }
6403
6467
  async function installCrashReporter() {
@@ -6406,7 +6470,7 @@ async function installCrashReporter() {
6406
6470
  if (!config.enabled || !config.endpoint) return;
6407
6471
  _installed = true;
6408
6472
  const machineId = await getMachineId();
6409
- const version = true ? "1.1.0" : "unknown";
6473
+ const version = true ? "1.2.1" : "unknown";
6410
6474
  process.on("uncaughtException", (err) => {
6411
6475
  void postReport(buildReport("fatal", err, { kind: "uncaughtException" }, machineId, version), config);
6412
6476
  });
@@ -6421,7 +6485,7 @@ import { jsx as jsx39 } from "react/jsx-runtime";
6421
6485
  var [, , command, arg] = process.argv;
6422
6486
  async function runCli() {
6423
6487
  if (command === "--version" || command === "-v" || command === "version") {
6424
- process.stdout.write("1.1.0\n");
6488
+ process.stdout.write("1.2.1\n");
6425
6489
  return;
6426
6490
  }
6427
6491
  await ensureDataDirs();
@@ -6604,7 +6668,7 @@ async function ensureBrewBarRunning() {
6604
6668
  await useLicenseStore.getState().initialize();
6605
6669
  if (!useLicenseStore.getState().isPro()) return;
6606
6670
  const { isBrewBarInstalled, installBrewBar, launchBrewBar } = await import("./brewbar-installer-GWJ76J6G.js");
6607
- const { checkBrewBarVersion } = await import("./version-check-LVSQFXZU.js");
6671
+ const { checkBrewBarVersion } = await import("./version-check-AIYMRDFF.js");
6608
6672
  try {
6609
6673
  if (!await isBrewBarInstalled()) {
6610
6674
  console.log(t("cli_brewbarInstalling"));