brew-tui 1.0.0 → 1.1.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.
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
|
|
69
|
+
import { useEffect as useEffect23, useState as useState21 } from "react";
|
|
70
70
|
import { useApp } from "ink";
|
|
71
71
|
|
|
72
72
|
// src/components/layout/app-layout.tsx
|
|
@@ -74,7 +74,32 @@ import { useRef } from "react";
|
|
|
74
74
|
import { Box as Box3 } from "ink";
|
|
75
75
|
|
|
76
76
|
// src/components/layout/header.tsx
|
|
77
|
-
import { Box, Text as Text3
|
|
77
|
+
import { Box, Text as Text3 } from "ink";
|
|
78
|
+
|
|
79
|
+
// src/hooks/use-terminal-size.ts
|
|
80
|
+
import { useEffect, useState } from "react";
|
|
81
|
+
import { useStdout } from "ink";
|
|
82
|
+
function useTerminalSize() {
|
|
83
|
+
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;
|
|
102
|
+
}
|
|
78
103
|
|
|
79
104
|
// src/stores/navigation-store.ts
|
|
80
105
|
import { create } from "zustand";
|
|
@@ -297,7 +322,7 @@ var GRADIENTS = {
|
|
|
297
322
|
};
|
|
298
323
|
|
|
299
324
|
// src/components/common/blinking-text.tsx
|
|
300
|
-
import { useEffect, useState } from "react";
|
|
325
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
301
326
|
import { Text as Text2 } from "ink";
|
|
302
327
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
303
328
|
function BlinkingText({
|
|
@@ -306,8 +331,8 @@ function BlinkingText({
|
|
|
306
331
|
bold = true,
|
|
307
332
|
children
|
|
308
333
|
}) {
|
|
309
|
-
const [bright, setBright] =
|
|
310
|
-
|
|
334
|
+
const [bright, setBright] = useState2(true);
|
|
335
|
+
useEffect2(() => {
|
|
311
336
|
const id = setInterval(() => setBright((b) => !b), intervalMs);
|
|
312
337
|
return () => clearInterval(id);
|
|
313
338
|
}, [intervalMs]);
|
|
@@ -389,9 +414,11 @@ function Header() {
|
|
|
389
414
|
const menuMode = useNavigationStore((s) => s.menuMode);
|
|
390
415
|
const menuCursor = useNavigationStore((s) => s.menuCursor);
|
|
391
416
|
useLocaleStore((s) => s.locale);
|
|
392
|
-
const {
|
|
393
|
-
const
|
|
394
|
-
const
|
|
417
|
+
const { columns, rows } = useTerminalSize();
|
|
418
|
+
const isNarrow = columns < 95;
|
|
419
|
+
const hideLogoByWidth = columns < 45;
|
|
420
|
+
const hideLogoByHeight = rows < 32;
|
|
421
|
+
const collapseMenu = rows < 22 && !menuMode;
|
|
395
422
|
const cursorView = menuMode ? MENU_VIEWS[menuCursor] ?? null : null;
|
|
396
423
|
const logoBlock = /* @__PURE__ */ jsx3(Box, { flexDirection: "column", flexShrink: 0, children: LOGO_BREW.map((brew, i) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
397
424
|
/* @__PURE__ */ jsx3(GradientText, { colors: GRADIENTS.gold, children: brew }),
|
|
@@ -412,12 +439,30 @@ function Header() {
|
|
|
412
439
|
t("hint_menuOpen_suffix")
|
|
413
440
|
] }) })
|
|
414
441
|
] });
|
|
442
|
+
if (collapseMenu) {
|
|
443
|
+
const currentLabel = t(VIEW_LABEL_KEYS[currentView]);
|
|
444
|
+
const currentIsPro = isProView(currentView) || isTeamView(currentView);
|
|
445
|
+
return /* @__PURE__ */ jsxs(Box, { paddingX: SPACING.xs, children: [
|
|
446
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.success, bold: true, children: "\u25B6 " }),
|
|
447
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.success, bold: true, children: currentLabel }),
|
|
448
|
+
currentIsPro && /* @__PURE__ */ jsxs(Text3, { color: COLORS.brand, bold: true, children: [
|
|
449
|
+
" ",
|
|
450
|
+
t("pro_badge")
|
|
451
|
+
] }),
|
|
452
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.textSecondary, children: " " }),
|
|
453
|
+
/* @__PURE__ */ jsx3(BlinkingText, { color: COLORS.brand, children: "M" }),
|
|
454
|
+
/* @__PURE__ */ jsx3(Text3, { color: COLORS.textSecondary, children: t("hint_menuOpen_suffix") })
|
|
455
|
+
] });
|
|
456
|
+
}
|
|
415
457
|
if (isNarrow) {
|
|
416
458
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: SPACING.xs, children: [
|
|
417
|
-
logoBlock,
|
|
418
|
-
/* @__PURE__ */ jsx3(Box, { marginTop: SPACING.xs, children: menuBlock })
|
|
459
|
+
!hideLogoByWidth && !hideLogoByHeight && logoBlock,
|
|
460
|
+
/* @__PURE__ */ jsx3(Box, { marginTop: hideLogoByWidth || hideLogoByHeight ? SPACING.none : SPACING.xs, children: menuBlock })
|
|
419
461
|
] });
|
|
420
462
|
}
|
|
463
|
+
if (hideLogoByHeight) {
|
|
464
|
+
return /* @__PURE__ */ jsx3(Box, { flexDirection: "column", paddingX: SPACING.xs, children: menuBlock });
|
|
465
|
+
}
|
|
421
466
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", paddingX: SPACING.xs, alignItems: "center", children: [
|
|
422
467
|
logoBlock,
|
|
423
468
|
/* @__PURE__ */ jsx3(Box, { marginLeft: SPACING.sm, children: menuBlock })
|
|
@@ -460,8 +505,9 @@ function Footer() {
|
|
|
460
505
|
const currentView = useNavigationStore((s) => s.currentView);
|
|
461
506
|
const menuMode = useNavigationStore((s) => s.menuMode);
|
|
462
507
|
const locale = useLocaleStore((s) => s.locale);
|
|
508
|
+
const { rows } = useTerminalSize();
|
|
463
509
|
const defs = VIEW_HINT_DEFS[currentView] ?? [];
|
|
464
|
-
const showChoose = hasNumberedActions(defs) && !menuMode;
|
|
510
|
+
const showChoose = hasNumberedActions(defs) && !menuMode && rows >= 26;
|
|
465
511
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
466
512
|
showChoose && /* @__PURE__ */ jsx4(Box2, { paddingX: SPACING.xs, children: /* @__PURE__ */ jsx4(Text4, { color: COLORS.text, children: t("hint_chooseNumber") }) }),
|
|
467
513
|
/* @__PURE__ */ jsxs2(Box2, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: COLORS.gold, paddingX: SPACING.xs, flexWrap: "wrap", children: [
|
|
@@ -506,31 +552,6 @@ function Footer() {
|
|
|
506
552
|
] });
|
|
507
553
|
}
|
|
508
554
|
|
|
509
|
-
// src/hooks/use-terminal-size.ts
|
|
510
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
511
|
-
import { useStdout as useStdout2 } from "ink";
|
|
512
|
-
function useTerminalSize() {
|
|
513
|
-
const { stdout } = useStdout2();
|
|
514
|
-
const [size, setSize] = useState2(() => ({
|
|
515
|
-
columns: stdout?.columns ?? 80,
|
|
516
|
-
rows: stdout?.rows ?? 24
|
|
517
|
-
}));
|
|
518
|
-
useEffect2(() => {
|
|
519
|
-
if (!stdout) return;
|
|
520
|
-
const onResize = () => {
|
|
521
|
-
setSize({
|
|
522
|
-
columns: stdout.columns ?? 80,
|
|
523
|
-
rows: stdout.rows ?? 24
|
|
524
|
-
});
|
|
525
|
-
};
|
|
526
|
-
stdout.on("resize", onResize);
|
|
527
|
-
return () => {
|
|
528
|
-
stdout.off("resize", onResize);
|
|
529
|
-
};
|
|
530
|
-
}, [stdout]);
|
|
531
|
-
return size;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
555
|
// src/hooks/use-container-size.ts
|
|
535
556
|
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
536
557
|
import { measureElement } from "ink";
|
|
@@ -837,12 +858,12 @@ function WelcomeView({ onContinue }) {
|
|
|
837
858
|
void markOnboardingComplete().finally(onContinue);
|
|
838
859
|
}
|
|
839
860
|
});
|
|
840
|
-
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingY: SPACING.
|
|
861
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingY: SPACING.xs, paddingX: SPACING.sm, flexShrink: 1, children: [
|
|
841
862
|
/* @__PURE__ */ jsx7(Box4, { children: /* @__PURE__ */ jsx7(GradientText, { colors: GRADIENTS.gold, bold: true, children: t("welcome_title") }) }),
|
|
842
|
-
/* @__PURE__ */ jsx7(Box4, { marginTop: SPACING.
|
|
843
|
-
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: SPACING.
|
|
863
|
+
/* @__PURE__ */ jsx7(Box4, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx7(Text5, { color: COLORS.text, wrap: "wrap", children: t("welcome_intro") }) }),
|
|
864
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
844
865
|
/* @__PURE__ */ jsx7(Text5, { color: COLORS.muted, children: t("welcome_keysHeader") }),
|
|
845
|
-
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingLeft: SPACING.sm,
|
|
866
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingLeft: SPACING.sm, children: [
|
|
846
867
|
/* @__PURE__ */ jsxs4(Text5, { children: [
|
|
847
868
|
/* @__PURE__ */ jsx7(Text5, { color: COLORS.gold, bold: true, children: "m" }),
|
|
848
869
|
" ",
|
|
@@ -885,11 +906,11 @@ function WelcomeView({ onContinue }) {
|
|
|
885
906
|
] })
|
|
886
907
|
] })
|
|
887
908
|
] }),
|
|
888
|
-
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: SPACING.
|
|
909
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
889
910
|
/* @__PURE__ */ jsx7(Text5, { color: COLORS.muted, children: t("welcome_proHeader") }),
|
|
890
|
-
/* @__PURE__ */ jsx7(Box4, { paddingLeft: SPACING.sm, children: /* @__PURE__ */ jsx7(Text5, { color: COLORS.textSecondary, children: t("welcome_proIntro") }) })
|
|
911
|
+
/* @__PURE__ */ jsx7(Box4, { paddingLeft: SPACING.sm, children: /* @__PURE__ */ jsx7(Text5, { color: COLORS.textSecondary, wrap: "wrap", children: t("welcome_proIntro") }) })
|
|
891
912
|
] }),
|
|
892
|
-
/* @__PURE__ */ jsx7(Box4, { marginTop: SPACING.
|
|
913
|
+
/* @__PURE__ */ jsx7(Box4, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx7(Text5, { color: COLORS.success, bold: true, children: t("welcome_continueHint") }) })
|
|
893
914
|
] });
|
|
894
915
|
}
|
|
895
916
|
|
|
@@ -915,15 +936,16 @@ function UpgradePrompt({ viewId }) {
|
|
|
915
936
|
const pricingKey = team ? "upgrade_teamPricing" : "upgrade_pricing";
|
|
916
937
|
const buyUrlKey = team ? "upgrade_buyUrlTeam" : "upgrade_buyUrl";
|
|
917
938
|
const labelKey = team ? "upgrade_teamLabel" : "upgrade_proLabel";
|
|
918
|
-
return /* @__PURE__ */ jsx8(Box5, { flexDirection: "column", alignItems: "center", paddingY: SPACING.
|
|
939
|
+
return /* @__PURE__ */ jsx8(Box5, { flexDirection: "column", alignItems: "center", paddingY: SPACING.xs, children: /* @__PURE__ */ jsxs5(
|
|
919
940
|
Box5,
|
|
920
941
|
{
|
|
921
942
|
borderStyle: "double",
|
|
922
943
|
borderColor: COLORS.brand,
|
|
923
|
-
paddingX: SPACING.
|
|
924
|
-
paddingY: SPACING.
|
|
944
|
+
paddingX: SPACING.sm,
|
|
945
|
+
paddingY: SPACING.none,
|
|
925
946
|
flexDirection: "column",
|
|
926
947
|
alignItems: "center",
|
|
948
|
+
flexShrink: 1,
|
|
927
949
|
width: "80%",
|
|
928
950
|
children: [
|
|
929
951
|
/* @__PURE__ */ jsxs5(Text6, { bold: true, color: COLORS.brand, children: [
|
|
@@ -931,24 +953,13 @@ function UpgradePrompt({ viewId }) {
|
|
|
931
953
|
" ",
|
|
932
954
|
t(headerKey, { title })
|
|
933
955
|
] }),
|
|
934
|
-
/* @__PURE__ */ jsx8(Text6, { children: " " }),
|
|
935
956
|
/* @__PURE__ */ jsx8(Text6, { color: COLORS.text, wrap: "wrap", children: t(keys.desc) }),
|
|
936
|
-
/* @__PURE__ */
|
|
937
|
-
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", alignItems: "center", children: [
|
|
957
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", alignItems: "center", marginTop: SPACING.xs, children: [
|
|
938
958
|
/* @__PURE__ */ jsx8(Text6, { color: COLORS.info, bold: true, children: t(pricingKey) }),
|
|
939
|
-
/* @__PURE__ */ jsx8(Text6, { children: " " }),
|
|
940
959
|
/* @__PURE__ */ jsx8(Text6, { color: COLORS.muted, children: t("upgrade_buyAt") }),
|
|
941
|
-
/* @__PURE__ */
|
|
942
|
-
" ",
|
|
943
|
-
t(buyUrlKey)
|
|
944
|
-
] }),
|
|
945
|
-
/* @__PURE__ */ jsx8(Text6, { children: " " }),
|
|
960
|
+
/* @__PURE__ */ jsx8(Text6, { color: COLORS.sky, bold: true, children: t(buyUrlKey) }),
|
|
946
961
|
/* @__PURE__ */ jsx8(Text6, { color: COLORS.muted, children: t("upgrade_activateWith") }),
|
|
947
|
-
/* @__PURE__ */
|
|
948
|
-
" ",
|
|
949
|
-
t("upgrade_activateCmd")
|
|
950
|
-
] }),
|
|
951
|
-
/* @__PURE__ */ jsx8(Text6, { children: " " }),
|
|
962
|
+
/* @__PURE__ */ jsx8(Text6, { color: COLORS.success, bold: true, children: t("upgrade_activateCmd") }),
|
|
952
963
|
/* @__PURE__ */ jsx8(Text6, { color: COLORS.brand, children: t(labelKey) })
|
|
953
964
|
] })
|
|
954
965
|
]
|
|
@@ -958,7 +969,19 @@ function UpgradePrompt({ viewId }) {
|
|
|
958
969
|
|
|
959
970
|
// src/views/dashboard.tsx
|
|
960
971
|
import { useEffect as useEffect5, useMemo as useMemo2 } from "react";
|
|
961
|
-
import { Box as Box9, Text as Text12
|
|
972
|
+
import { Box as Box9, Text as Text12 } from "ink";
|
|
973
|
+
|
|
974
|
+
// src/hooks/use-visible-rows.ts
|
|
975
|
+
function useVisibleRows({
|
|
976
|
+
reservedRows,
|
|
977
|
+
fallbackReservedRows = reservedRows,
|
|
978
|
+
minRows = 3
|
|
979
|
+
}) {
|
|
980
|
+
const { height: contentHeight } = useContentSize();
|
|
981
|
+
const { rows: terminalRows } = useTerminalSize();
|
|
982
|
+
const availableRows = contentHeight > 0 ? contentHeight - reservedRows : terminalRows - fallbackReservedRows;
|
|
983
|
+
return Math.max(minRows, Math.floor(availableRows));
|
|
984
|
+
}
|
|
962
985
|
|
|
963
986
|
// src/stores/brew-store.ts
|
|
964
987
|
import { create as create4 } from "zustand";
|
|
@@ -1924,12 +1947,11 @@ var useComplianceStore = create8((set, get) => ({
|
|
|
1924
1947
|
}));
|
|
1925
1948
|
|
|
1926
1949
|
// src/components/common/stat-card.tsx
|
|
1927
|
-
import { Box as Box6, Text as Text7
|
|
1950
|
+
import { Box as Box6, Text as Text7 } from "ink";
|
|
1928
1951
|
import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1929
1952
|
function StatCard({ label, value, color = COLORS.white }) {
|
|
1930
|
-
const {
|
|
1931
|
-
const
|
|
1932
|
-
const minW = cols < 60 ? 12 : cols < 100 ? 14 : 16;
|
|
1953
|
+
const { columns } = useTerminalSize();
|
|
1954
|
+
const minW = columns < 60 ? 12 : columns < 100 ? 14 : 16;
|
|
1933
1955
|
return /* @__PURE__ */ jsxs6(
|
|
1934
1956
|
Box6,
|
|
1935
1957
|
{
|
|
@@ -1939,6 +1961,7 @@ function StatCard({ label, value, color = COLORS.white }) {
|
|
|
1939
1961
|
paddingY: SPACING.none,
|
|
1940
1962
|
flexDirection: "column",
|
|
1941
1963
|
alignItems: "center",
|
|
1964
|
+
flexShrink: 1,
|
|
1942
1965
|
minWidth: minW,
|
|
1943
1966
|
children: [
|
|
1944
1967
|
/* @__PURE__ */ jsx9(Text7, { bold: true, color, children: value }),
|
|
@@ -2103,8 +2126,13 @@ function DashboardView() {
|
|
|
2103
2126
|
const lastFetchedAt = useBrewStore((s) => s.lastFetchedAt);
|
|
2104
2127
|
const fetchAll = useBrewStore((s) => s.fetchAll);
|
|
2105
2128
|
const isPro = useLicenseStore((s) => s.isPro);
|
|
2106
|
-
const {
|
|
2107
|
-
const
|
|
2129
|
+
const { columns } = useTerminalSize();
|
|
2130
|
+
const splitRows = useVisibleRows({
|
|
2131
|
+
reservedRows: 18,
|
|
2132
|
+
fallbackReservedRows: 22,
|
|
2133
|
+
minRows: 2
|
|
2134
|
+
});
|
|
2135
|
+
const halfRows = Math.max(1, Math.floor(splitRows / 2));
|
|
2108
2136
|
useEffect5(() => {
|
|
2109
2137
|
fetchAll();
|
|
2110
2138
|
}, []);
|
|
@@ -2195,20 +2223,23 @@ function DashboardView() {
|
|
|
2195
2223
|
!errors.outdated && outdated.formulae.length > 0 && /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2196
2224
|
/* @__PURE__ */ jsx13(SectionHeader, { emoji: "\u{1F4E6}", title: t("dashboard_outdatedPackages"), gradient: GRADIENTS.fire }),
|
|
2197
2225
|
/* @__PURE__ */ jsxs11(Box9, { paddingLeft: SPACING.sm, flexDirection: "column", children: [
|
|
2198
|
-
outdated.formulae.slice(0,
|
|
2226
|
+
outdated.formulae.slice(0, halfRows).map((pkg) => /* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
2199
2227
|
/* @__PURE__ */ jsx13(Text12, { color: COLORS.text, children: pkg.name }),
|
|
2200
2228
|
/* @__PURE__ */ jsx13(VersionArrow, { current: pkg.installed_versions[0] ?? "", latest: pkg.current_version })
|
|
2201
2229
|
] }, pkg.name)),
|
|
2202
|
-
outdated.formulae.length >
|
|
2230
|
+
outdated.formulae.length > halfRows && /* @__PURE__ */ jsx13(Text12, { color: COLORS.textSecondary, italic: true, children: t("common_andMore", { count: outdated.formulae.length - halfRows }) })
|
|
2203
2231
|
] })
|
|
2204
2232
|
] }),
|
|
2205
2233
|
!errors.services && errorServices > 0 && /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2206
2234
|
/* @__PURE__ */ jsx13(SectionHeader, { emoji: "\u26A0\uFE0F", title: t("dashboard_serviceErrors"), color: COLORS.error }),
|
|
2207
|
-
/* @__PURE__ */
|
|
2208
|
-
/* @__PURE__ */
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2235
|
+
/* @__PURE__ */ jsxs11(Box9, { paddingLeft: SPACING.sm, flexDirection: "column", children: [
|
|
2236
|
+
errorServiceList.slice(0, halfRows).map((s) => /* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
2237
|
+
/* @__PURE__ */ jsx13(StatusBadge, { label: t("badge_error"), variant: "error" }),
|
|
2238
|
+
/* @__PURE__ */ jsx13(Text12, { children: s.name }),
|
|
2239
|
+
s.exit_code != null && /* @__PURE__ */ jsx13(Text12, { color: COLORS.muted, children: t("common_exit", { code: s.exit_code }) })
|
|
2240
|
+
] }, s.name)),
|
|
2241
|
+
errorServiceList.length > halfRows && /* @__PURE__ */ jsx13(Text12, { color: COLORS.textSecondary, italic: true, children: t("common_andMore", { count: errorServiceList.length - halfRows }) })
|
|
2242
|
+
] })
|
|
2212
2243
|
] }),
|
|
2213
2244
|
isPro() && /* @__PURE__ */ jsx13(ProStatusPanel, {})
|
|
2214
2245
|
] });
|
|
@@ -2347,8 +2378,8 @@ function ConfirmDialog({ message, onConfirm, onCancel }) {
|
|
|
2347
2378
|
else if (input === "n" || input === "N") onCancel();
|
|
2348
2379
|
else if (key.escape) onCancel();
|
|
2349
2380
|
});
|
|
2350
|
-
return /* @__PURE__ */ jsxs13(Box11, { borderStyle: "double", borderColor: COLORS.purple, paddingX: SPACING.sm, paddingY: SPACING.xs, flexDirection: "column", children: [
|
|
2351
|
-
/* @__PURE__ */ jsx15(Text14, { bold: true, color: COLORS.text, children: message }),
|
|
2381
|
+
return /* @__PURE__ */ jsxs13(Box11, { borderStyle: "double", borderColor: COLORS.purple, paddingX: SPACING.sm, paddingY: SPACING.xs, flexDirection: "column", flexShrink: 1, children: [
|
|
2382
|
+
/* @__PURE__ */ jsx15(Text14, { bold: true, color: COLORS.text, wrap: "wrap", children: message }),
|
|
2352
2383
|
/* @__PURE__ */ jsxs13(Box11, { marginTop: SPACING.xs, children: [
|
|
2353
2384
|
/* @__PURE__ */ jsx15(Text14, { color: COLORS.success, children: t("confirm_yes") }),
|
|
2354
2385
|
/* @__PURE__ */ jsx15(Text14, { children: " / " }),
|
|
@@ -2405,18 +2436,6 @@ function SelectableRow({ isCurrent, children, gap = 1 }) {
|
|
|
2405
2436
|
] });
|
|
2406
2437
|
}
|
|
2407
2438
|
|
|
2408
|
-
// src/hooks/use-visible-rows.ts
|
|
2409
|
-
function useVisibleRows({
|
|
2410
|
-
reservedRows,
|
|
2411
|
-
fallbackReservedRows = reservedRows,
|
|
2412
|
-
minRows = 3
|
|
2413
|
-
}) {
|
|
2414
|
-
const { height: contentHeight } = useContentSize();
|
|
2415
|
-
const { rows: terminalRows } = useTerminalSize();
|
|
2416
|
-
const availableRows = contentHeight > 0 ? contentHeight - reservedRows : terminalRows - fallbackReservedRows;
|
|
2417
|
-
return Math.max(minRows, Math.floor(availableRows));
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
2439
|
// src/views/installed.tsx
|
|
2421
2440
|
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2422
2441
|
function InstalledView() {
|
|
@@ -2431,8 +2450,9 @@ function InstalledView() {
|
|
|
2431
2450
|
const containerRef = useRef3(null);
|
|
2432
2451
|
const { width: containerWidth } = useContainerSize(containerRef);
|
|
2433
2452
|
const columns = containerWidth > 0 ? containerWidth : 80;
|
|
2434
|
-
const nameWidth = Math.floor(columns * 0.35);
|
|
2435
|
-
const versionWidth = Math.floor(columns * 0.15);
|
|
2453
|
+
const nameWidth = Math.max(12, Math.floor(columns * 0.35));
|
|
2454
|
+
const versionWidth = Math.max(8, Math.floor(columns * 0.15));
|
|
2455
|
+
const descWidth = Math.max(10, columns - nameWidth - versionWidth - 8);
|
|
2436
2456
|
const [filter, setFilter] = useState6("");
|
|
2437
2457
|
const [cursor, setCursor] = useState6(0);
|
|
2438
2458
|
const [tab, setTab] = useState6("formulae");
|
|
@@ -2617,7 +2637,7 @@ function InstalledView() {
|
|
|
2617
2637
|
item.pinned && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_pinned"), variant: "info" }),
|
|
2618
2638
|
item.kegOnly && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_kegOnly"), variant: "muted" }),
|
|
2619
2639
|
item.installedAsDependency && /* @__PURE__ */ jsx19(StatusBadge, { label: t("badge_dep"), variant: "muted" }),
|
|
2620
|
-
!item.outdated && !item.pinned && !item.kegOnly && !item.installedAsDependency && /* @__PURE__ */ jsx19(Text18, { color: COLORS.textSecondary, dimColor: true, children: truncate(item.desc,
|
|
2640
|
+
!item.outdated && !item.pinned && !item.kegOnly && !item.installedAsDependency && /* @__PURE__ */ jsx19(Text18, { color: COLORS.textSecondary, dimColor: true, children: truncate(item.desc, descWidth) })
|
|
2621
2641
|
] }, item.name);
|
|
2622
2642
|
}),
|
|
2623
2643
|
start + MAX_VISIBLE_ROWS < allItems.length && /* @__PURE__ */ jsxs16(Text18, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
@@ -3259,11 +3279,14 @@ function PackageInfoView() {
|
|
|
3259
3279
|
] }),
|
|
3260
3280
|
formula.dependencies.length > 0 && /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
3261
3281
|
/* @__PURE__ */ jsx22(SectionHeader, { emoji: "\u{1F517}", title: t("pkgInfo_dependencies", { count: formula.dependencies.length }), gradient: GRADIENTS.ocean }),
|
|
3262
|
-
/* @__PURE__ */
|
|
3282
|
+
/* @__PURE__ */ jsxs19(Box18, { paddingLeft: SPACING.sm, flexWrap: "wrap", columnGap: 2, children: [
|
|
3283
|
+
formula.dependencies.slice(0, 30).map((dep) => /* @__PURE__ */ jsx22(Text21, { color: COLORS.muted, children: dep }, dep)),
|
|
3284
|
+
formula.dependencies.length > 30 && /* @__PURE__ */ jsx22(Text21, { color: COLORS.textSecondary, italic: true, children: t("common_andMore", { count: formula.dependencies.length - 30 }) })
|
|
3285
|
+
] })
|
|
3263
3286
|
] }),
|
|
3264
3287
|
formula.caveats && /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
3265
3288
|
/* @__PURE__ */ jsx22(SectionHeader, { emoji: "\u26A0\uFE0F", title: t("pkgInfo_caveats"), color: COLORS.warning }),
|
|
3266
|
-
/* @__PURE__ */ jsx22(Box18, { borderStyle: "round", borderColor: COLORS.warning, paddingX: SPACING.sm, children: /* @__PURE__ */ jsx22(Text21, { color: COLORS.warning, children: formula.caveats }) })
|
|
3289
|
+
/* @__PURE__ */ jsx22(Box18, { borderStyle: "round", borderColor: COLORS.warning, paddingX: SPACING.sm, children: /* @__PURE__ */ jsx22(Text21, { color: COLORS.warning, wrap: "wrap", children: formula.caveats }) })
|
|
3267
3290
|
] })
|
|
3268
3291
|
] }),
|
|
3269
3292
|
/* @__PURE__ */ jsx22(Box18, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs19(Text21, { color: COLORS.textSecondary, children: [
|
|
@@ -3275,8 +3298,8 @@ function PackageInfoView() {
|
|
|
3275
3298
|
}
|
|
3276
3299
|
|
|
3277
3300
|
// src/views/services.tsx
|
|
3278
|
-
import { useEffect as useEffect13, useState as useState10 } from "react";
|
|
3279
|
-
import { Box as Box19, Text as Text22
|
|
3301
|
+
import { useEffect as useEffect13, useRef as useRef7, useState as useState10 } from "react";
|
|
3302
|
+
import { Box as Box19, Text as Text22 } from "ink";
|
|
3280
3303
|
import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3281
3304
|
var STATUS_VARIANTS = {
|
|
3282
3305
|
started: "success",
|
|
@@ -3296,10 +3319,11 @@ function ServicesView() {
|
|
|
3296
3319
|
const [actionInProgress, setActionInProgress] = useState10(false);
|
|
3297
3320
|
const [confirmAction, setConfirmAction] = useState10(null);
|
|
3298
3321
|
const [lastError, setLastError] = useState10(null);
|
|
3299
|
-
const
|
|
3300
|
-
const
|
|
3301
|
-
const
|
|
3302
|
-
const
|
|
3322
|
+
const containerRef = useRef7(null);
|
|
3323
|
+
const { width: containerWidth } = useContainerSize(containerRef);
|
|
3324
|
+
const cols = containerWidth > 0 ? containerWidth : 80;
|
|
3325
|
+
const svcNameWidth = Math.max(12, Math.floor(cols * 0.35));
|
|
3326
|
+
const svcStatusWidth = Math.max(8, Math.floor(cols * 0.15));
|
|
3303
3327
|
const MAX_VISIBLE_ROWS = useVisibleRows({
|
|
3304
3328
|
reservedRows: lastError || actionInProgress ? 8 : 6,
|
|
3305
3329
|
fallbackReservedRows: lastError || actionInProgress ? 16 : 14,
|
|
@@ -3347,7 +3371,7 @@ function ServicesView() {
|
|
|
3347
3371
|
}
|
|
3348
3372
|
const start = Math.max(0, cursor - Math.floor(MAX_VISIBLE_ROWS / 2));
|
|
3349
3373
|
const visible = services.slice(start, start + MAX_VISIBLE_ROWS);
|
|
3350
|
-
return /* @__PURE__ */ jsxs20(Box19, { flexDirection: "column", children: [
|
|
3374
|
+
return /* @__PURE__ */ jsxs20(Box19, { flexDirection: "column", ref: containerRef, children: [
|
|
3351
3375
|
/* @__PURE__ */ jsx23(SectionHeader, { emoji: "\u2699\uFE0F", title: t("services_titleCount", { count: services.length }), gradient: GRADIENTS.ocean }),
|
|
3352
3376
|
confirmAction && /* @__PURE__ */ jsx23(Box19, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx23(
|
|
3353
3377
|
ConfirmDialog,
|
|
@@ -3385,7 +3409,7 @@ function ServicesView() {
|
|
|
3385
3409
|
const idx = start + i;
|
|
3386
3410
|
const isCurrent = idx === cursor;
|
|
3387
3411
|
return /* @__PURE__ */ jsxs20(SelectableRow, { isCurrent, children: [
|
|
3388
|
-
/* @__PURE__ */ jsx23(Text22, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: svc.name.padEnd(svcNameWidth - 2) }),
|
|
3412
|
+
/* @__PURE__ */ jsx23(Text22, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: truncate(svc.name, svcNameWidth - 2).padEnd(svcNameWidth - 2) }),
|
|
3389
3413
|
/* @__PURE__ */ jsx23(StatusBadge, { label: svc.status, variant: STATUS_VARIANTS[svc.status] }),
|
|
3390
3414
|
/* @__PURE__ */ jsx23(Text22, { color: COLORS.muted, children: svc.user ?? "-" }),
|
|
3391
3415
|
svc.exit_code != null && svc.exit_code !== 0 && /* @__PURE__ */ jsx23(Text22, { color: COLORS.error, children: t("common_exit", { code: svc.exit_code }) })
|
|
@@ -3407,12 +3431,18 @@ function ServicesView() {
|
|
|
3407
3431
|
}
|
|
3408
3432
|
|
|
3409
3433
|
// src/views/doctor.tsx
|
|
3410
|
-
import { useEffect as useEffect14, useRef as
|
|
3434
|
+
import { useEffect as useEffect14, useRef as useRef8, useState as useState11 } from "react";
|
|
3411
3435
|
import { Box as Box20, Text as Text23 } from "ink";
|
|
3412
3436
|
import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3413
3437
|
function DoctorView() {
|
|
3414
3438
|
const { doctorWarnings, doctorClean, loading, errors, fetchDoctor } = useBrewStore();
|
|
3415
|
-
const
|
|
3439
|
+
const [cursor, setCursor] = useState11(0);
|
|
3440
|
+
const visibleWarnings = useVisibleRows({
|
|
3441
|
+
reservedRows: 6,
|
|
3442
|
+
fallbackReservedRows: 14,
|
|
3443
|
+
minRows: 1
|
|
3444
|
+
});
|
|
3445
|
+
const mountedRef = useRef8(true);
|
|
3416
3446
|
useEffect14(() => {
|
|
3417
3447
|
mountedRef.current = true;
|
|
3418
3448
|
return () => {
|
|
@@ -3422,27 +3452,42 @@ function DoctorView() {
|
|
|
3422
3452
|
useEffect14(() => {
|
|
3423
3453
|
fetchDoctor();
|
|
3424
3454
|
}, []);
|
|
3425
|
-
useViewInput((input) => {
|
|
3426
|
-
if (input === "r" || input === "1")
|
|
3455
|
+
useViewInput((input, key) => {
|
|
3456
|
+
if (input === "r" || input === "1") {
|
|
3457
|
+
void fetchDoctor();
|
|
3458
|
+
return;
|
|
3459
|
+
}
|
|
3460
|
+
if (input === "j" || key.downArrow) setCursor((c) => Math.min(c + 1, Math.max(0, doctorWarnings.length - 1)));
|
|
3461
|
+
else if (input === "k" || key.upArrow) setCursor((c) => Math.max(c - 1, 0));
|
|
3427
3462
|
});
|
|
3428
3463
|
if (loading.doctor) return /* @__PURE__ */ jsx24(Loading, { message: t("loading_doctor") });
|
|
3429
3464
|
if (errors.doctor) return /* @__PURE__ */ jsx24(ErrorMessage, { message: errors.doctor });
|
|
3465
|
+
const start = Math.max(0, cursor - Math.floor(visibleWarnings / 2));
|
|
3466
|
+
const visible = doctorWarnings.slice(start, start + visibleWarnings);
|
|
3430
3467
|
return /* @__PURE__ */ jsxs21(Box20, { flexDirection: "column", children: [
|
|
3431
3468
|
/* @__PURE__ */ jsx24(SectionHeader, { emoji: "\u{1FA7A}", title: t("doctor_title"), gradient: GRADIENTS.emerald }),
|
|
3432
3469
|
/* @__PURE__ */ jsxs21(Box20, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
3433
3470
|
doctorClean && /* @__PURE__ */ jsx24(ResultBanner, { status: "success", message: `\u2714 ${t("doctor_clean")}` }),
|
|
3434
3471
|
doctorClean === false && doctorWarnings.length === 0 && /* @__PURE__ */ jsx24(Text23, { color: COLORS.warning, children: t("doctor_warningsNotCaptured") }),
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
)
|
|
3472
|
+
start > 0 && /* @__PURE__ */ jsxs21(Text23, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
3473
|
+
" ",
|
|
3474
|
+
t("scroll_moreAbove", { count: start })
|
|
3475
|
+
] }),
|
|
3476
|
+
visible.map((warning, i) => {
|
|
3477
|
+
const idx = start + i;
|
|
3478
|
+
return /* @__PURE__ */ jsx24(Box20, { flexDirection: "column", marginBottom: SPACING.xs, borderStyle: "single", borderColor: idx === cursor ? COLORS.gold : COLORS.warning, paddingX: SPACING.xs, children: warning.split("\n").map((line, j) => /* @__PURE__ */ jsx24(Text23, { color: j === 0 ? COLORS.warning : COLORS.muted, wrap: "wrap", children: line }, `warning-${idx}-${j}-${line.slice(0, 20)}`)) }, `warning-${idx}-${warning.slice(0, 20)}`);
|
|
3479
|
+
}),
|
|
3480
|
+
start + visibleWarnings < doctorWarnings.length && /* @__PURE__ */ jsxs21(Text23, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
3481
|
+
" ",
|
|
3482
|
+
t("scroll_moreBelow", { count: doctorWarnings.length - start - visibleWarnings })
|
|
3483
|
+
] })
|
|
3439
3484
|
] }),
|
|
3440
3485
|
/* @__PURE__ */ jsx24(Box20, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx24(Text23, { color: COLORS.text, bold: true, children: doctorWarnings.length > 0 ? tp("plural_warnings", doctorWarnings.length) : "" }) })
|
|
3441
3486
|
] });
|
|
3442
3487
|
}
|
|
3443
3488
|
|
|
3444
3489
|
// src/views/profiles.tsx
|
|
3445
|
-
import { useEffect as useEffect15, useRef as
|
|
3490
|
+
import { useEffect as useEffect15, useRef as useRef9, useState as useState12 } from "react";
|
|
3446
3491
|
import { Box as Box25 } from "ink";
|
|
3447
3492
|
|
|
3448
3493
|
// src/stores/profile-store.ts
|
|
@@ -3705,18 +3750,33 @@ function ProfileListMode({ profileNames, cursor, confirmDelete, loadError, onCon
|
|
|
3705
3750
|
import { Box as Box22, Text as Text25 } from "ink";
|
|
3706
3751
|
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3707
3752
|
function ProfileDetailMode({ profile }) {
|
|
3753
|
+
const totalRows = useVisibleRows({
|
|
3754
|
+
reservedRows: 7,
|
|
3755
|
+
fallbackReservedRows: 14,
|
|
3756
|
+
minRows: 2
|
|
3757
|
+
});
|
|
3758
|
+
const total = profile.formulae.length + profile.casks.length;
|
|
3759
|
+
const formulaeBudget = total === 0 ? 0 : Math.min(profile.formulae.length, Math.max(1, Math.round(profile.formulae.length / total * totalRows)));
|
|
3760
|
+
const casksBudget = Math.max(0, totalRows - formulaeBudget);
|
|
3761
|
+
const visibleFormulae = profile.formulae.slice(0, formulaeBudget);
|
|
3762
|
+
const visibleCasks = profile.casks.slice(0, casksBudget);
|
|
3763
|
+
const formulaeHidden = profile.formulae.length - visibleFormulae.length;
|
|
3764
|
+
const casksHidden = profile.casks.length - visibleCasks.length;
|
|
3708
3765
|
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
3709
3766
|
/* @__PURE__ */ jsx26(Text25, { bold: true, color: COLORS.gold, children: profile.name }),
|
|
3710
|
-
/* @__PURE__ */ jsx26(Text25, { color: COLORS.muted, children: profile.description }),
|
|
3767
|
+
/* @__PURE__ */ jsx26(Text25, { color: COLORS.muted, wrap: "wrap", children: profile.description }),
|
|
3711
3768
|
/* @__PURE__ */ jsx26(Text25, { color: COLORS.muted, children: t("profiles_created", { date: formatDate(profile.createdAt) }) }),
|
|
3712
3769
|
/* @__PURE__ */ jsxs23(Box22, { marginTop: SPACING.xs, flexDirection: "column", children: [
|
|
3713
3770
|
/* @__PURE__ */ jsx26(Text25, { bold: true, children: t("profiles_formulaeCount", { count: profile.formulae.length }) }),
|
|
3714
3771
|
/* @__PURE__ */ jsxs23(Box22, { paddingLeft: SPACING.sm, flexDirection: "column", children: [
|
|
3715
|
-
|
|
3716
|
-
|
|
3772
|
+
visibleFormulae.map((f) => /* @__PURE__ */ jsx26(Text25, { color: COLORS.muted, children: f }, f)),
|
|
3773
|
+
formulaeHidden > 0 && /* @__PURE__ */ jsx26(Text25, { color: COLORS.textSecondary, italic: true, children: t("common_andMore", { count: formulaeHidden }) })
|
|
3717
3774
|
] }),
|
|
3718
3775
|
/* @__PURE__ */ jsx26(Text25, { bold: true, children: t("profiles_casksCount", { count: profile.casks.length }) }),
|
|
3719
|
-
/* @__PURE__ */
|
|
3776
|
+
/* @__PURE__ */ jsxs23(Box22, { paddingLeft: SPACING.sm, flexDirection: "column", children: [
|
|
3777
|
+
visibleCasks.map((c) => /* @__PURE__ */ jsx26(Text25, { color: COLORS.muted, children: c }, c)),
|
|
3778
|
+
casksHidden > 0 && /* @__PURE__ */ jsx26(Text25, { color: COLORS.textSecondary, italic: true, children: t("common_andMore", { count: casksHidden }) })
|
|
3779
|
+
] })
|
|
3720
3780
|
] }),
|
|
3721
3781
|
/* @__PURE__ */ jsx26(Box22, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs23(Text25, { color: COLORS.textSecondary, children: [
|
|
3722
3782
|
"esc:",
|
|
@@ -3799,19 +3859,19 @@ function ProfileEditDesc({ name, defaultDesc, loadError, onSubmit }) {
|
|
|
3799
3859
|
import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3800
3860
|
function ProfilesView() {
|
|
3801
3861
|
const { profileNames, selectedProfile, loading, loadError, fetchProfiles, loadProfile: loadProfile2, exportCurrent, deleteProfile: deleteProfile2, updateProfile: updateProfile2 } = useProfileStore();
|
|
3802
|
-
const [cursor, setCursor] =
|
|
3803
|
-
const [mode, setMode] =
|
|
3804
|
-
const [newName, setNewName] =
|
|
3805
|
-
const [confirmDelete, setConfirmDelete] =
|
|
3806
|
-
const [editName, setEditName] =
|
|
3807
|
-
const [editDesc, setEditDesc] =
|
|
3808
|
-
const [importLines, setImportLines] =
|
|
3809
|
-
const [importRunning, setImportRunning] =
|
|
3810
|
-
const [importHadError, setImportHadError] =
|
|
3811
|
-
const [importProfile2, setImportProfile] =
|
|
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);
|
|
3812
3872
|
const { openModal, closeModal } = useModalStore();
|
|
3813
|
-
const importGenRef =
|
|
3814
|
-
const mountedRef =
|
|
3873
|
+
const importGenRef = useRef9(null);
|
|
3874
|
+
const mountedRef = useRef9(true);
|
|
3815
3875
|
useEffect15(() => {
|
|
3816
3876
|
fetchProfiles();
|
|
3817
3877
|
}, []);
|
|
@@ -3999,7 +4059,7 @@ function ProfilesView() {
|
|
|
3999
4059
|
}
|
|
4000
4060
|
|
|
4001
4061
|
// src/views/smart-cleanup.tsx
|
|
4002
|
-
import { useEffect as useEffect16, useRef as
|
|
4062
|
+
import { useEffect as useEffect16, useRef as useRef10, useState as useState13 } from "react";
|
|
4003
4063
|
import { Box as Box26, Text as Text28 } from "ink";
|
|
4004
4064
|
|
|
4005
4065
|
// src/stores/cleanup-store.ts
|
|
@@ -4123,12 +4183,17 @@ var useCleanupStore = create10((set, get) => ({
|
|
|
4123
4183
|
import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
4124
4184
|
function SmartCleanupView() {
|
|
4125
4185
|
const { summary, selected, loading, error, analyze, toggleSelect, selectAll } = useCleanupStore();
|
|
4126
|
-
const [cursor, setCursor] =
|
|
4127
|
-
const [confirmClean, setConfirmClean] =
|
|
4128
|
-
const [confirmForce, setConfirmForce] =
|
|
4129
|
-
const [failedNames, setFailedNames] =
|
|
4186
|
+
const [cursor, setCursor] = useState13(0);
|
|
4187
|
+
const [confirmClean, setConfirmClean] = useState13(false);
|
|
4188
|
+
const [confirmForce, setConfirmForce] = useState13(false);
|
|
4189
|
+
const [failedNames, setFailedNames] = useState13([]);
|
|
4130
4190
|
const stream = useBrewStream();
|
|
4131
|
-
const hasRefreshed =
|
|
4191
|
+
const hasRefreshed = useRef10(false);
|
|
4192
|
+
const listRows = useVisibleRows({
|
|
4193
|
+
reservedRows: confirmClean || confirmForce ? 12 : 9,
|
|
4194
|
+
fallbackReservedRows: confirmClean || confirmForce ? 18 : 14,
|
|
4195
|
+
minRows: 1
|
|
4196
|
+
});
|
|
4132
4197
|
useEffect16(() => {
|
|
4133
4198
|
analyze();
|
|
4134
4199
|
}, []);
|
|
@@ -4230,32 +4295,45 @@ function SmartCleanupView() {
|
|
|
4230
4295
|
)
|
|
4231
4296
|
] }),
|
|
4232
4297
|
candidates.length === 0 && !confirmClean && /* @__PURE__ */ jsx30(ResultBanner, { status: "success", message: `\u2714 ${t("cleanup_systemClean")}` }),
|
|
4233
|
-
candidates.length > 0 && !confirmClean &&
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4298
|
+
candidates.length > 0 && !confirmClean && (() => {
|
|
4299
|
+
const start = Math.max(0, cursor - Math.floor(listRows / 2));
|
|
4300
|
+
const visible = candidates.slice(start, start + listRows);
|
|
4301
|
+
return /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", children: [
|
|
4302
|
+
start > 0 && /* @__PURE__ */ jsxs27(Text28, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
4303
|
+
" ",
|
|
4304
|
+
t("scroll_moreAbove", { count: start })
|
|
4305
|
+
] }),
|
|
4306
|
+
visible.map((c, i) => {
|
|
4307
|
+
const idx = start + i;
|
|
4308
|
+
const isCurrent = idx === cursor;
|
|
4309
|
+
const isSelected = selected.has(c.name);
|
|
4310
|
+
return /* @__PURE__ */ jsxs27(SelectableRow, { isCurrent, children: [
|
|
4311
|
+
/* @__PURE__ */ jsx30(Text28, { color: isSelected ? COLORS.success : COLORS.muted, children: isSelected ? "\u2611" : "\u2610" }),
|
|
4312
|
+
/* @__PURE__ */ jsx30(Text28, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: c.name }),
|
|
4313
|
+
/* @__PURE__ */ jsx30(Text28, { color: COLORS.warning, children: c.diskUsageFormatted }),
|
|
4314
|
+
/* @__PURE__ */ jsxs27(Text28, { color: COLORS.textSecondary, children: [
|
|
4315
|
+
"[",
|
|
4316
|
+
c.reason,
|
|
4317
|
+
"]"
|
|
4318
|
+
] })
|
|
4319
|
+
] }, c.name);
|
|
4320
|
+
}),
|
|
4321
|
+
start + listRows < candidates.length && /* @__PURE__ */ jsxs27(Text28, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
4322
|
+
" ",
|
|
4323
|
+
t("scroll_moreBelow", { count: candidates.length - start - listRows })
|
|
4324
|
+
] }),
|
|
4325
|
+
/* @__PURE__ */ jsx30(Box26, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs27(Text28, { color: COLORS.text, bold: true, children: [
|
|
4326
|
+
cursor + 1,
|
|
4327
|
+
"/",
|
|
4328
|
+
candidates.length
|
|
4329
|
+
] }) })
|
|
4330
|
+
] });
|
|
4331
|
+
})()
|
|
4254
4332
|
] });
|
|
4255
4333
|
}
|
|
4256
4334
|
|
|
4257
4335
|
// src/views/history.tsx
|
|
4258
|
-
import { useEffect as useEffect17, useState as
|
|
4336
|
+
import { useEffect as useEffect17, useState as useState14, useMemo as useMemo5 } from "react";
|
|
4259
4337
|
import { Box as Box27, Text as Text29 } from "ink";
|
|
4260
4338
|
|
|
4261
4339
|
// src/stores/history-store.ts
|
|
@@ -4308,12 +4386,12 @@ var ACTION_LABEL_KEYS = {
|
|
|
4308
4386
|
var FILTERS = ["all", "install", "uninstall", "upgrade", "upgrade-all"];
|
|
4309
4387
|
function HistoryView() {
|
|
4310
4388
|
const { entries, loading, error, fetchHistory, clearHistory: clearHistory2 } = useHistoryStore();
|
|
4311
|
-
const [cursor, setCursor] =
|
|
4312
|
-
const [filter, setFilter] =
|
|
4313
|
-
const [searchQuery, setSearchQuery] =
|
|
4314
|
-
const [isSearching, setIsSearching] =
|
|
4315
|
-
const [confirmClear, setConfirmClear] =
|
|
4316
|
-
const [confirmReplay, setConfirmReplay] =
|
|
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);
|
|
4317
4395
|
const stream = useBrewStream();
|
|
4318
4396
|
const debouncedQuery = useDebounce(searchQuery, 200);
|
|
4319
4397
|
const { openModal, closeModal } = useModalStore();
|
|
@@ -4471,7 +4549,7 @@ function HistoryView() {
|
|
|
4471
4549
|
}
|
|
4472
4550
|
|
|
4473
4551
|
// src/views/security-audit.tsx
|
|
4474
|
-
import { useEffect as useEffect18, useState as
|
|
4552
|
+
import { useEffect as useEffect18, useState as useState15 } from "react";
|
|
4475
4553
|
import { Box as Box28, Text as Text30 } from "ink";
|
|
4476
4554
|
import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4477
4555
|
var SEVERITY_COLORS = {
|
|
@@ -4494,9 +4572,9 @@ function isNetworkError(msg) {
|
|
|
4494
4572
|
function SecurityAuditView() {
|
|
4495
4573
|
const { summary, loading, error, scan, cachedAt } = useSecurityStore();
|
|
4496
4574
|
const navigate = useNavigationStore((s) => s.navigate);
|
|
4497
|
-
const [cursor, setCursor] =
|
|
4498
|
-
const [expandedPkg, setExpandedPkg] =
|
|
4499
|
-
const [confirmUpgrade, setConfirmUpgrade] =
|
|
4575
|
+
const [cursor, setCursor] = useState15(0);
|
|
4576
|
+
const [expandedPkg, setExpandedPkg] = useState15(null);
|
|
4577
|
+
const [confirmUpgrade, setConfirmUpgrade] = useState15(null);
|
|
4500
4578
|
const stream = useBrewStream();
|
|
4501
4579
|
useEffect18(() => {
|
|
4502
4580
|
scan();
|
|
@@ -4603,7 +4681,7 @@ function SecurityAuditView() {
|
|
|
4603
4681
|
}
|
|
4604
4682
|
|
|
4605
4683
|
// src/views/account.tsx
|
|
4606
|
-
import { useState as
|
|
4684
|
+
import { useState as useState16 } from "react";
|
|
4607
4685
|
import { Box as Box29, Text as Text31 } from "ink";
|
|
4608
4686
|
import { TextInput as TextInput5 } from "@inkjs/ui";
|
|
4609
4687
|
|
|
@@ -4685,13 +4763,13 @@ async function redeemPromoCode(code) {
|
|
|
4685
4763
|
import { Fragment as Fragment5, jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
4686
4764
|
function AccountView() {
|
|
4687
4765
|
const { status, license, deactivate: deactivate2, revalidate: revalidate2, degradation } = useLicenseStore();
|
|
4688
|
-
const [confirmDeactivate, setConfirmDeactivate] =
|
|
4689
|
-
const [deactivating, setDeactivating] =
|
|
4690
|
-
const [deactivateError, setDeactivateError] =
|
|
4691
|
-
const [promoMode, setPromoMode] =
|
|
4692
|
-
const [promoLoading, setPromoLoading] =
|
|
4693
|
-
const [promoResult, setPromoResult] =
|
|
4694
|
-
const [revalidating, setRevalidating] =
|
|
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);
|
|
4695
4773
|
useViewInput((input, key) => {
|
|
4696
4774
|
if (confirmDeactivate || deactivating || promoMode || revalidating) {
|
|
4697
4775
|
if (key.escape && promoMode) {
|
|
@@ -4776,16 +4854,14 @@ function AccountView() {
|
|
|
4776
4854
|
/* @__PURE__ */ jsx33(Text31, { children: formatDate(license.activatedAt) })
|
|
4777
4855
|
] })
|
|
4778
4856
|
] }),
|
|
4779
|
-
status === "free" && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: SPACING.
|
|
4857
|
+
status === "free" && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: SPACING.xs, borderStyle: "round", borderColor: COLORS.brand, paddingX: SPACING.sm, paddingY: SPACING.none, flexShrink: 1, children: [
|
|
4780
4858
|
/* @__PURE__ */ jsxs30(Text31, { bold: true, color: COLORS.brand, children: [
|
|
4781
4859
|
"\u2B50",
|
|
4782
4860
|
" ",
|
|
4783
4861
|
t("account_upgradeTitle")
|
|
4784
4862
|
] }),
|
|
4785
|
-
/* @__PURE__ */ jsx33(Text31, {
|
|
4786
|
-
/* @__PURE__ */ jsx33(Text31, { children: t("account_unlockDesc") }),
|
|
4863
|
+
/* @__PURE__ */ jsx33(Text31, { wrap: "wrap", children: t("account_unlockDesc") }),
|
|
4787
4864
|
/* @__PURE__ */ jsx33(Text31, { color: COLORS.info, bold: true, children: t("account_pricing") }),
|
|
4788
|
-
/* @__PURE__ */ jsx33(Text31, { children: " " }),
|
|
4789
4865
|
/* @__PURE__ */ jsxs30(Text31, { color: COLORS.muted, children: [
|
|
4790
4866
|
t("upgrade_buyAt"),
|
|
4791
4867
|
" ",
|
|
@@ -4837,13 +4913,13 @@ function AccountView() {
|
|
|
4837
4913
|
status === "pro" || status === "team" || status === "expired" ? `v ${t("hint_revalidate")} ` : "",
|
|
4838
4914
|
revalidating ? t("account_revalidating") : "",
|
|
4839
4915
|
" ",
|
|
4840
|
-
t("app_version", { version: "1.
|
|
4916
|
+
t("app_version", { version: "1.1.0" })
|
|
4841
4917
|
] }) })
|
|
4842
4918
|
] });
|
|
4843
4919
|
}
|
|
4844
4920
|
|
|
4845
4921
|
// src/views/rollback.tsx
|
|
4846
|
-
import { useCallback as useCallback3, useEffect as useEffect19, useRef as
|
|
4922
|
+
import { useCallback as useCallback3, useEffect as useEffect19, useRef as useRef11, useState as useState17 } from "react";
|
|
4847
4923
|
import { Box as Box30, Text as Text32 } from "ink";
|
|
4848
4924
|
|
|
4849
4925
|
// src/stores/rollback-store.ts
|
|
@@ -5082,6 +5158,14 @@ function actionPrefix(action) {
|
|
|
5082
5158
|
}
|
|
5083
5159
|
function PlanView({ plan }) {
|
|
5084
5160
|
const executableCount = plan.actions.filter((a) => a.strategy !== "unavailable" && a.action !== "remove").length;
|
|
5161
|
+
const reservedForWarnings = Math.min(plan.warnings.length, 3) * 2;
|
|
5162
|
+
const actionsBudget = useVisibleRows({
|
|
5163
|
+
reservedRows: 6 + reservedForWarnings,
|
|
5164
|
+
fallbackReservedRows: 14 + reservedForWarnings,
|
|
5165
|
+
minRows: 2
|
|
5166
|
+
});
|
|
5167
|
+
const visibleActions = plan.actions.slice(0, actionsBudget);
|
|
5168
|
+
const hiddenActions = plan.actions.length - visibleActions.length;
|
|
5085
5169
|
return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5086
5170
|
/* @__PURE__ */ jsxs31(Box30, { marginBottom: SPACING.xs, children: [
|
|
5087
5171
|
/* @__PURE__ */ jsxs31(Text32, { color: COLORS.text, bold: true, children: [
|
|
@@ -5091,7 +5175,7 @@ function PlanView({ plan }) {
|
|
|
5091
5175
|
/* @__PURE__ */ jsx34(Text32, { color: COLORS.textSecondary, children: plan.snapshotDate })
|
|
5092
5176
|
] }),
|
|
5093
5177
|
plan.actions.length === 0 && /* @__PURE__ */ jsx34(ResultBanner, { status: "success", message: t("rollback_diff_empty") }),
|
|
5094
|
-
|
|
5178
|
+
visibleActions.map((a) => /* @__PURE__ */ jsxs31(Box30, { children: [
|
|
5095
5179
|
/* @__PURE__ */ jsxs31(Text32, { color: actionColor(a), children: [
|
|
5096
5180
|
actionPrefix(a),
|
|
5097
5181
|
" "
|
|
@@ -5114,10 +5198,18 @@ function PlanView({ plan }) {
|
|
|
5114
5198
|
"]"
|
|
5115
5199
|
] })
|
|
5116
5200
|
] }, a.packageName + a.action)),
|
|
5117
|
-
|
|
5201
|
+
hiddenActions > 0 && /* @__PURE__ */ jsxs31(Text32, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
5202
|
+
" ",
|
|
5203
|
+
t("scroll_moreBelow", { count: hiddenActions })
|
|
5204
|
+
] }),
|
|
5205
|
+
plan.warnings.slice(0, 3).map((w) => /* @__PURE__ */ jsx34(Box30, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs31(Text32, { color: COLORS.warning, wrap: "wrap", children: [
|
|
5118
5206
|
"\u26A0 ",
|
|
5119
5207
|
w
|
|
5120
5208
|
] }) }, w)),
|
|
5209
|
+
plan.warnings.length > 3 && /* @__PURE__ */ jsxs31(Text32, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
5210
|
+
" ",
|
|
5211
|
+
t("common_andMore", { count: plan.warnings.length - 3 })
|
|
5212
|
+
] }),
|
|
5121
5213
|
/* @__PURE__ */ jsx34(Box30, { marginTop: SPACING.xs, children: plan.canExecute ? /* @__PURE__ */ jsxs31(Text32, { color: COLORS.textSecondary, children: [
|
|
5122
5214
|
"enter:",
|
|
5123
5215
|
t("rollback_confirm", { count: String(executableCount) }),
|
|
@@ -5133,13 +5225,18 @@ function PlanView({ plan }) {
|
|
|
5133
5225
|
function RollbackView() {
|
|
5134
5226
|
const isPro = useLicenseStore((s) => s.isPro);
|
|
5135
5227
|
const { snapshots, loading, error, plan, planLoading, planError, fetchSnapshots, selectSnapshot, clearPlan } = useRollbackStore();
|
|
5136
|
-
const [cursor, setCursor] =
|
|
5137
|
-
const [phase, setPhase] =
|
|
5138
|
-
const [streamLines, setStreamLines] =
|
|
5139
|
-
const [streamRunning, setStreamRunning] =
|
|
5140
|
-
const [streamError, setStreamError] =
|
|
5141
|
-
const generatorRef =
|
|
5142
|
-
const mountedRef =
|
|
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);
|
|
5233
|
+
const generatorRef = useRef11(null);
|
|
5234
|
+
const mountedRef = useRef11(true);
|
|
5235
|
+
const snapshotRows = useVisibleRows({
|
|
5236
|
+
reservedRows: 6,
|
|
5237
|
+
fallbackReservedRows: 14,
|
|
5238
|
+
minRows: 1
|
|
5239
|
+
});
|
|
5143
5240
|
useEffect19(() => {
|
|
5144
5241
|
mountedRef.current = true;
|
|
5145
5242
|
return () => {
|
|
@@ -5232,22 +5329,39 @@ function RollbackView() {
|
|
|
5232
5329
|
return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
|
|
5233
5330
|
/* @__PURE__ */ jsx34(SectionHeader, { emoji: "\u23EA", title: t("rollback_title"), gradient: GRADIENTS.gold }),
|
|
5234
5331
|
snapshots.length === 0 && /* @__PURE__ */ jsx34(Box30, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx34(ResultBanner, { status: "info", message: t("rollback_no_snapshots") }) }),
|
|
5235
|
-
phase === "list" && snapshots.length > 0 &&
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
/* @__PURE__ */
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5332
|
+
phase === "list" && snapshots.length > 0 && (() => {
|
|
5333
|
+
const start = Math.max(0, cursor - Math.floor(snapshotRows / 2));
|
|
5334
|
+
const visible = snapshots.slice(start, start + snapshotRows);
|
|
5335
|
+
return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5336
|
+
/* @__PURE__ */ jsx34(Text32, { color: COLORS.textSecondary, dimColor: true, children: t("rollback_select_snapshot") }),
|
|
5337
|
+
/* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5338
|
+
start > 0 && /* @__PURE__ */ jsxs31(Text32, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
5339
|
+
" ",
|
|
5340
|
+
t("scroll_moreAbove", { count: start })
|
|
5341
|
+
] }),
|
|
5342
|
+
visible.map((s, vi) => {
|
|
5343
|
+
const i = start + vi;
|
|
5344
|
+
return /* @__PURE__ */ jsxs31(SelectableRow, { isCurrent: i === cursor, children: [
|
|
5345
|
+
/* @__PURE__ */ jsx34(Text32, { bold: i === cursor, color: i === cursor ? COLORS.text : COLORS.muted, children: s.label ?? t("rollback_snapshot_auto") }),
|
|
5346
|
+
/* @__PURE__ */ jsxs31(Text32, { color: COLORS.textSecondary, children: [
|
|
5347
|
+
" \u2014 ",
|
|
5348
|
+
new Date(s.capturedAt).toLocaleString()
|
|
5349
|
+
] }),
|
|
5350
|
+
/* @__PURE__ */ jsxs31(Text32, { color: COLORS.muted, dimColor: true, children: [
|
|
5351
|
+
" ",
|
|
5352
|
+
"(",
|
|
5353
|
+
tp("packages", s.formulae.length + s.casks.length),
|
|
5354
|
+
")"
|
|
5355
|
+
] })
|
|
5356
|
+
] }, s.capturedAt);
|
|
5357
|
+
}),
|
|
5358
|
+
start + snapshotRows < snapshots.length && /* @__PURE__ */ jsxs31(Text32, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
5359
|
+
" ",
|
|
5360
|
+
t("scroll_moreBelow", { count: snapshots.length - start - snapshotRows })
|
|
5361
|
+
] })
|
|
5248
5362
|
] })
|
|
5249
|
-
] }
|
|
5250
|
-
|
|
5363
|
+
] });
|
|
5364
|
+
})(),
|
|
5251
5365
|
phase === "plan" && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
|
|
5252
5366
|
planLoading && /* @__PURE__ */ jsx34(Loading, { message: t("rollback_capturing") }),
|
|
5253
5367
|
planError && /* @__PURE__ */ jsx34(ErrorMessage, { message: planError }),
|
|
@@ -5267,7 +5381,7 @@ function RollbackView() {
|
|
|
5267
5381
|
}
|
|
5268
5382
|
|
|
5269
5383
|
// src/views/brewfile.tsx
|
|
5270
|
-
import { useCallback as useCallback4, useEffect as useEffect20, useRef as
|
|
5384
|
+
import { useCallback as useCallback4, useEffect as useEffect20, useRef as useRef12, useState as useState18 } from "react";
|
|
5271
5385
|
import { Box as Box31, Text as Text33 } from "ink";
|
|
5272
5386
|
import { TextInput as TextInput6 } from "@inkjs/ui";
|
|
5273
5387
|
import { jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
@@ -5313,13 +5427,13 @@ function DriftSummary({ drift }) {
|
|
|
5313
5427
|
function BrewfileView() {
|
|
5314
5428
|
const isPro = useLicenseStore((s) => s.isPro);
|
|
5315
5429
|
const { schema, drift, loading, driftLoading, error, load, createFromCurrent } = useBrewfileStore();
|
|
5316
|
-
const [phase, setPhase] =
|
|
5317
|
-
const [streamLines, setStreamLines] =
|
|
5318
|
-
const [streamRunning, setStreamRunning] =
|
|
5319
|
-
const [streamError, setStreamError] =
|
|
5320
|
-
const [resultMessage, setResultMessage] =
|
|
5321
|
-
const generatorRef =
|
|
5322
|
-
const mountedRef =
|
|
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("");
|
|
5435
|
+
const generatorRef = useRef12(null);
|
|
5436
|
+
const mountedRef = useRef12(true);
|
|
5323
5437
|
useEffect20(() => {
|
|
5324
5438
|
mountedRef.current = true;
|
|
5325
5439
|
void load();
|
|
@@ -5496,7 +5610,7 @@ function BrewfileView() {
|
|
|
5496
5610
|
}
|
|
5497
5611
|
|
|
5498
5612
|
// src/views/sync.tsx
|
|
5499
|
-
import { useCallback as useCallback5, useEffect as useEffect21, useState as
|
|
5613
|
+
import { useCallback as useCallback5, useEffect as useEffect21, useState as useState19 } from "react";
|
|
5500
5614
|
import { Box as Box32, Text as Text34 } from "ink";
|
|
5501
5615
|
import { Fragment as Fragment6, jsx as jsx36, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
5502
5616
|
function OverviewSection({
|
|
@@ -5547,8 +5661,22 @@ function ConflictsList({
|
|
|
5547
5661
|
entries,
|
|
5548
5662
|
cursor
|
|
5549
5663
|
}) {
|
|
5664
|
+
const availableRows = useVisibleRows({
|
|
5665
|
+
reservedRows: 8,
|
|
5666
|
+
fallbackReservedRows: 14,
|
|
5667
|
+
minRows: 4
|
|
5668
|
+
});
|
|
5669
|
+
const perEntryRows = 4;
|
|
5670
|
+
const maxEntries = Math.max(1, Math.floor(availableRows / perEntryRows));
|
|
5671
|
+
const start = Math.max(0, cursor - Math.floor(maxEntries / 2));
|
|
5672
|
+
const visible = entries.slice(start, start + maxEntries);
|
|
5550
5673
|
return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5551
|
-
|
|
5674
|
+
start > 0 && /* @__PURE__ */ jsxs33(Text34, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
5675
|
+
" ",
|
|
5676
|
+
t("scroll_moreAbove", { count: start })
|
|
5677
|
+
] }),
|
|
5678
|
+
visible.map((entry, vi) => {
|
|
5679
|
+
const i = start + vi;
|
|
5552
5680
|
const { conflict, resolution } = entry;
|
|
5553
5681
|
const isActive = i === cursor;
|
|
5554
5682
|
return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginBottom: SPACING.xs, children: [
|
|
@@ -5586,6 +5714,10 @@ function ConflictsList({
|
|
|
5586
5714
|
] })
|
|
5587
5715
|
] }, `${conflict.packageName}-${conflict.remoteMachine}`);
|
|
5588
5716
|
}),
|
|
5717
|
+
start + maxEntries < entries.length && /* @__PURE__ */ jsxs33(Text34, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
5718
|
+
" ",
|
|
5719
|
+
t("scroll_moreBelow", { count: entries.length - start - maxEntries })
|
|
5720
|
+
] }),
|
|
5589
5721
|
/* @__PURE__ */ jsx36(Box32, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs33(Text34, { color: COLORS.textSecondary, children: [
|
|
5590
5722
|
"j/k:",
|
|
5591
5723
|
t("hint_navigate"),
|
|
@@ -5604,10 +5736,10 @@ function SyncView() {
|
|
|
5604
5736
|
const isPro = useLicenseStore((s) => s.isPro);
|
|
5605
5737
|
const navigate = useNavigationStore((s) => s.navigate);
|
|
5606
5738
|
const { config, lastResult, conflicts, loading, error, initialize, syncNow, resolveConflicts } = useSyncStore();
|
|
5607
|
-
const [phase, setPhase] =
|
|
5608
|
-
const [syncError, setSyncError] =
|
|
5609
|
-
const [conflictEntries, setConflictEntries] =
|
|
5610
|
-
const [cursor, setCursor] =
|
|
5739
|
+
const [phase, setPhase] = useState19("overview");
|
|
5740
|
+
const [syncError, setSyncError] = useState19(null);
|
|
5741
|
+
const [conflictEntries, setConflictEntries] = useState19([]);
|
|
5742
|
+
const [cursor, setCursor] = useState19(0);
|
|
5611
5743
|
useEffect21(() => {
|
|
5612
5744
|
void initialize(isPro());
|
|
5613
5745
|
}, []);
|
|
@@ -5776,7 +5908,7 @@ function SyncView() {
|
|
|
5776
5908
|
}
|
|
5777
5909
|
|
|
5778
5910
|
// src/views/compliance.tsx
|
|
5779
|
-
import { useCallback as useCallback6, useEffect as useEffect22, useRef as
|
|
5911
|
+
import { useCallback as useCallback6, useEffect as useEffect22, useRef as useRef13, useState as useState20 } from "react";
|
|
5780
5912
|
import { Box as Box33, Text as Text35 } from "ink";
|
|
5781
5913
|
import { TextInput as TextInput7 } from "@inkjs/ui";
|
|
5782
5914
|
|
|
@@ -5857,38 +5989,58 @@ function ViolationItem({ violation }) {
|
|
|
5857
5989
|
prefix,
|
|
5858
5990
|
" "
|
|
5859
5991
|
] }),
|
|
5860
|
-
/* @__PURE__ */ jsx37(Text35, { color, children: violation.detail })
|
|
5992
|
+
/* @__PURE__ */ jsx37(Text35, { color, wrap: "wrap", children: violation.detail })
|
|
5861
5993
|
] });
|
|
5862
5994
|
}
|
|
5863
5995
|
function ViolationList({ violations }) {
|
|
5864
5996
|
const errors = violations.filter((v) => v.severity === "error");
|
|
5865
5997
|
const warnings = violations.filter((v) => v.severity === "warning");
|
|
5998
|
+
const totalRows = useVisibleRows({
|
|
5999
|
+
reservedRows: 11,
|
|
6000
|
+
fallbackReservedRows: 18,
|
|
6001
|
+
minRows: 2
|
|
6002
|
+
});
|
|
6003
|
+
const total = errors.length + warnings.length;
|
|
6004
|
+
const errorBudget = total === 0 ? 0 : Math.min(errors.length, Math.max(1, Math.round(errors.length / total * totalRows)));
|
|
6005
|
+
const warningBudget = Math.max(0, totalRows - errorBudget);
|
|
6006
|
+
const visibleErrors = errors.slice(0, errorBudget);
|
|
6007
|
+
const visibleWarnings = warnings.slice(0, warningBudget);
|
|
6008
|
+
const errorsHidden = errors.length - visibleErrors.length;
|
|
6009
|
+
const warningsHidden = warnings.length - visibleWarnings.length;
|
|
5866
6010
|
return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5867
6011
|
errors.length > 0 && /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginBottom: SPACING.xs, children: [
|
|
5868
6012
|
/* @__PURE__ */ jsxs34(Text35, { color: COLORS.error, bold: true, children: [
|
|
5869
6013
|
t("compliance_violations", { count: String(errors.length) }),
|
|
5870
6014
|
" (errors)"
|
|
5871
6015
|
] }),
|
|
5872
|
-
|
|
6016
|
+
visibleErrors.map((v) => /* @__PURE__ */ jsx37(ViolationItem, { violation: v }, `${v.type}-${v.packageName}`)),
|
|
6017
|
+
errorsHidden > 0 && /* @__PURE__ */ jsxs34(Text35, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
6018
|
+
" ",
|
|
6019
|
+
t("scroll_moreBelow", { count: errorsHidden })
|
|
6020
|
+
] })
|
|
5873
6021
|
] }),
|
|
5874
6022
|
warnings.length > 0 && /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", children: [
|
|
5875
6023
|
/* @__PURE__ */ jsxs34(Text35, { color: COLORS.warning, bold: true, children: [
|
|
5876
6024
|
t("compliance_violations", { count: String(warnings.length) }),
|
|
5877
6025
|
" (warnings)"
|
|
5878
6026
|
] }),
|
|
5879
|
-
|
|
6027
|
+
visibleWarnings.map((v) => /* @__PURE__ */ jsx37(ViolationItem, { violation: v }, `${v.type}-${v.packageName}`)),
|
|
6028
|
+
warningsHidden > 0 && /* @__PURE__ */ jsxs34(Text35, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
6029
|
+
" ",
|
|
6030
|
+
t("scroll_moreBelow", { count: warningsHidden })
|
|
6031
|
+
] })
|
|
5880
6032
|
] })
|
|
5881
6033
|
] });
|
|
5882
6034
|
}
|
|
5883
6035
|
function ComplianceView() {
|
|
5884
6036
|
const isPro = useLicenseStore((s) => s.isPro);
|
|
5885
6037
|
const { policy, report, loading, error, importPolicy, runCheck } = useComplianceStore();
|
|
5886
|
-
const [phase, setPhase] =
|
|
5887
|
-
const [resultMessage, setResultMessage] =
|
|
5888
|
-
const [streamLines, setStreamLines] =
|
|
5889
|
-
const [streamRunning, setStreamRunning] =
|
|
5890
|
-
const generatorRef =
|
|
5891
|
-
const mountedRef =
|
|
6038
|
+
const [phase, setPhase] = useState20("overview");
|
|
6039
|
+
const [resultMessage, setResultMessage] = useState20(null);
|
|
6040
|
+
const [streamLines, setStreamLines] = useState20([]);
|
|
6041
|
+
const [streamRunning, setStreamRunning] = useState20(false);
|
|
6042
|
+
const generatorRef = useRef13(null);
|
|
6043
|
+
const mountedRef = useRef13(true);
|
|
5892
6044
|
useEffect22(() => {
|
|
5893
6045
|
mountedRef.current = true;
|
|
5894
6046
|
return () => {
|
|
@@ -6147,7 +6299,7 @@ function App() {
|
|
|
6147
6299
|
const { exit } = useApp();
|
|
6148
6300
|
const currentView = useNavigationStore((s) => s.currentView);
|
|
6149
6301
|
const isTestEnv = typeof process !== "undefined" && false;
|
|
6150
|
-
const [showWelcome, setShowWelcome] =
|
|
6302
|
+
const [showWelcome, setShowWelcome] = useState21(isTestEnv ? false : null);
|
|
6151
6303
|
useEffect23(() => {
|
|
6152
6304
|
if (isTestEnv) return;
|
|
6153
6305
|
void hasCompletedOnboarding().then((done) => setShowWelcome(!done));
|
|
@@ -6245,7 +6397,7 @@ async function reportError(err, context = {}) {
|
|
|
6245
6397
|
const config = await resolveConfig();
|
|
6246
6398
|
if (!config.enabled || !config.endpoint) return;
|
|
6247
6399
|
const machineId = await getMachineId();
|
|
6248
|
-
const version = true ? "1.
|
|
6400
|
+
const version = true ? "1.1.0" : "unknown";
|
|
6249
6401
|
await postReport(buildReport("error", err, context, machineId, version), config);
|
|
6250
6402
|
}
|
|
6251
6403
|
async function installCrashReporter() {
|
|
@@ -6254,7 +6406,7 @@ async function installCrashReporter() {
|
|
|
6254
6406
|
if (!config.enabled || !config.endpoint) return;
|
|
6255
6407
|
_installed = true;
|
|
6256
6408
|
const machineId = await getMachineId();
|
|
6257
|
-
const version = true ? "1.
|
|
6409
|
+
const version = true ? "1.1.0" : "unknown";
|
|
6258
6410
|
process.on("uncaughtException", (err) => {
|
|
6259
6411
|
void postReport(buildReport("fatal", err, { kind: "uncaughtException" }, machineId, version), config);
|
|
6260
6412
|
});
|
|
@@ -6269,7 +6421,7 @@ import { jsx as jsx39 } from "react/jsx-runtime";
|
|
|
6269
6421
|
var [, , command, arg] = process.argv;
|
|
6270
6422
|
async function runCli() {
|
|
6271
6423
|
if (command === "--version" || command === "-v" || command === "version") {
|
|
6272
|
-
process.stdout.write("1.
|
|
6424
|
+
process.stdout.write("1.1.0\n");
|
|
6273
6425
|
return;
|
|
6274
6426
|
}
|
|
6275
6427
|
await ensureDataDirs();
|
|
@@ -6452,7 +6604,7 @@ async function ensureBrewBarRunning() {
|
|
|
6452
6604
|
await useLicenseStore.getState().initialize();
|
|
6453
6605
|
if (!useLicenseStore.getState().isPro()) return;
|
|
6454
6606
|
const { isBrewBarInstalled, installBrewBar, launchBrewBar } = await import("./brewbar-installer-GWJ76J6G.js");
|
|
6455
|
-
const { checkBrewBarVersion } = await import("./version-check-
|
|
6607
|
+
const { checkBrewBarVersion } = await import("./version-check-LVSQFXZU.js");
|
|
6456
6608
|
try {
|
|
6457
6609
|
if (!await isBrewBarInstalled()) {
|
|
6458
6610
|
console.log(t("cli_brewbarInstalling"));
|