brew-tui 0.6.1 → 0.7.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/README.md +5 -5
- package/build/{brewbar-installer-BAHS6EEZ.js → brewbar-installer-KJTIZIVU.js} +3 -3
- package/build/brewbar-installer-KJTIZIVU.js.map +1 -0
- package/build/{brewfile-manager-3SERRYNC.js → brewfile-manager-6LXONGSA.js} +4 -4
- package/build/{chunk-LXF72RCD.js → chunk-3VDIKVS3.js} +3 -3
- package/build/{chunk-MSXH66I2.js → chunk-F6EISN54.js} +65 -5
- package/build/chunk-F6EISN54.js.map +1 -0
- package/build/{chunk-U2DRWB7A.js → chunk-FIPCCYL6.js} +2 -2
- package/build/chunk-GWXDXFUC.js +721 -0
- package/build/chunk-GWXDXFUC.js.map +1 -0
- package/build/{chunk-KVCVIRWI.js → chunk-JYHINZVV.js} +19 -4
- package/build/chunk-JYHINZVV.js.map +1 -0
- package/build/chunk-QZZZAAWG.js +56 -0
- package/build/chunk-QZZZAAWG.js.map +1 -0
- package/build/{chunk-4I344KQX.js → chunk-VLREAA5F.js} +59 -3
- package/build/chunk-VLREAA5F.js.map +1 -0
- package/build/compliance-checker-MAREAFDH.js +12 -0
- package/build/{history-logger-PBDOLKNJ.js → history-logger-FJ3HZSFU.js} +3 -3
- package/build/index.js +1273 -1303
- package/build/index.js.map +1 -1
- package/build/{snapshot-RAPGMAJF.js → snapshot-JDRSBMG6.js} +7 -3
- package/build/{sync-engine-CAFK4LHA.js → sync-engine-4OA4JNR3.js} +7 -5
- package/package.json +4 -4
- package/build/brewbar-installer-BAHS6EEZ.js.map +0 -1
- package/build/chunk-4I344KQX.js.map +0 -1
- package/build/chunk-AIAZQJKL.js +0 -299
- package/build/chunk-AIAZQJKL.js.map +0 -1
- package/build/chunk-KVCVIRWI.js.map +0 -1
- package/build/chunk-MSXH66I2.js.map +0 -1
- package/build/chunk-UWS4A4F5.js +0 -25
- package/build/chunk-UWS4A4F5.js.map +0 -1
- package/build/compliance-checker-X7P623UF.js +0 -12
- /package/build/{brewfile-manager-3SERRYNC.js.map → brewfile-manager-6LXONGSA.js.map} +0 -0
- /package/build/{chunk-LXF72RCD.js.map → chunk-3VDIKVS3.js.map} +0 -0
- /package/build/{chunk-U2DRWB7A.js.map → chunk-FIPCCYL6.js.map} +0 -0
- /package/build/{compliance-checker-X7P623UF.js.map → compliance-checker-MAREAFDH.js.map} +0 -0
- /package/build/{history-logger-PBDOLKNJ.js.map → history-logger-FJ3HZSFU.js.map} +0 -0
- /package/build/{snapshot-RAPGMAJF.js.map → snapshot-JDRSBMG6.js.map} +0 -0
- /package/build/{sync-engine-CAFK4LHA.js.map → sync-engine-4OA4JNR3.js.map} +0 -0
package/build/index.js
CHANGED
|
@@ -5,24 +5,31 @@ import {
|
|
|
5
5
|
loadBrewfile,
|
|
6
6
|
reconcile,
|
|
7
7
|
saveBrewfile
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3VDIKVS3.js";
|
|
9
9
|
import {
|
|
10
|
+
activate,
|
|
10
11
|
applyConflictResolutions,
|
|
12
|
+
deactivate,
|
|
11
13
|
decryptPayload,
|
|
14
|
+
getDegradationLevel,
|
|
15
|
+
isExpired,
|
|
16
|
+
loadLicense,
|
|
12
17
|
loadSyncConfig,
|
|
18
|
+
needsRevalidation,
|
|
13
19
|
readSyncEnvelope,
|
|
20
|
+
revalidate,
|
|
14
21
|
sync
|
|
15
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-GWXDXFUC.js";
|
|
16
23
|
import {
|
|
17
24
|
checkCompliance
|
|
18
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-FIPCCYL6.js";
|
|
19
26
|
import {
|
|
20
27
|
captureSnapshot,
|
|
21
28
|
execBrew,
|
|
22
29
|
loadSnapshots,
|
|
23
30
|
saveSnapshot,
|
|
24
31
|
streamBrew
|
|
25
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-VLREAA5F.js";
|
|
26
33
|
import {
|
|
27
34
|
exportReport,
|
|
28
35
|
loadPolicy
|
|
@@ -32,13 +39,14 @@ import {
|
|
|
32
39
|
clearHistory,
|
|
33
40
|
detectAction,
|
|
34
41
|
loadHistory
|
|
35
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-JYHINZVV.js";
|
|
36
43
|
import {
|
|
37
44
|
DATA_DIR,
|
|
38
|
-
|
|
45
|
+
ONBOARDING_FLAG_PATH,
|
|
39
46
|
PROFILES_DIR,
|
|
40
|
-
ensureDataDirs
|
|
41
|
-
|
|
47
|
+
ensureDataDirs,
|
|
48
|
+
getMachineId
|
|
49
|
+
} from "./chunk-QZZZAAWG.js";
|
|
42
50
|
import {
|
|
43
51
|
fetchWithRetry,
|
|
44
52
|
fetchWithTimeout,
|
|
@@ -46,18 +54,18 @@ import {
|
|
|
46
54
|
t,
|
|
47
55
|
tp,
|
|
48
56
|
useLocaleStore
|
|
49
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-F6EISN54.js";
|
|
50
58
|
import {
|
|
51
59
|
logger
|
|
52
60
|
} from "./chunk-KDHEUNRI.js";
|
|
53
61
|
|
|
54
62
|
// src/index.tsx
|
|
55
63
|
import { createInterface } from "readline/promises";
|
|
56
|
-
import { rm as
|
|
64
|
+
import { rm as rm2 } from "fs/promises";
|
|
57
65
|
import { render } from "ink";
|
|
58
66
|
|
|
59
67
|
// src/app.tsx
|
|
60
|
-
import { useEffect as
|
|
68
|
+
import { useEffect as useEffect20, useState as useState17 } from "react";
|
|
61
69
|
import { useApp } from "ink";
|
|
62
70
|
|
|
63
71
|
// src/components/layout/app-layout.tsx
|
|
@@ -73,6 +81,7 @@ var VIEWS = [
|
|
|
73
81
|
"installed",
|
|
74
82
|
"outdated",
|
|
75
83
|
"package-info",
|
|
84
|
+
"search",
|
|
76
85
|
"services",
|
|
77
86
|
"doctor",
|
|
78
87
|
"profiles",
|
|
@@ -137,7 +146,7 @@ function isTeamView(viewId) {
|
|
|
137
146
|
}
|
|
138
147
|
|
|
139
148
|
// src/utils/colors.ts
|
|
140
|
-
var
|
|
149
|
+
var DARK_PALETTE = {
|
|
141
150
|
success: "#22C55E",
|
|
142
151
|
error: "#EF4444",
|
|
143
152
|
warning: "#F59E0B",
|
|
@@ -149,12 +158,61 @@ var COLORS = {
|
|
|
149
158
|
teal: "#2DD4BF",
|
|
150
159
|
sky: "#38BDF8",
|
|
151
160
|
gold: "#FFD700",
|
|
161
|
+
goldOrange: "#FFA500",
|
|
162
|
+
goldDeep: "#B8860B",
|
|
163
|
+
goldDark: "#8B6914",
|
|
164
|
+
goldDeepest: "#6B4F10",
|
|
152
165
|
purple: "#A855F7",
|
|
153
166
|
blue: "#3B82F6",
|
|
154
167
|
lavender: "#C4B5FD",
|
|
155
168
|
border: "#4B5563",
|
|
156
169
|
white: "#FFFFFF"
|
|
157
170
|
};
|
|
171
|
+
var LIGHT_PALETTE = {
|
|
172
|
+
success: "#15803D",
|
|
173
|
+
error: "#B91C1C",
|
|
174
|
+
warning: "#B45309",
|
|
175
|
+
info: "#0E7490",
|
|
176
|
+
brand: "#C2410C",
|
|
177
|
+
muted: "#4B5563",
|
|
178
|
+
text: "#111827",
|
|
179
|
+
textSecondary: "#374151",
|
|
180
|
+
teal: "#0F766E",
|
|
181
|
+
sky: "#0369A1",
|
|
182
|
+
gold: "#A16207",
|
|
183
|
+
goldOrange: "#9A3412",
|
|
184
|
+
goldDeep: "#7C2D12",
|
|
185
|
+
goldDark: "#5B2509",
|
|
186
|
+
goldDeepest: "#3F1A06",
|
|
187
|
+
purple: "#6B21A8",
|
|
188
|
+
blue: "#1D4ED8",
|
|
189
|
+
lavender: "#6D28D9",
|
|
190
|
+
border: "#D1D5DB",
|
|
191
|
+
white: "#000000"
|
|
192
|
+
// intentional: "white-on-light" reads as black ink
|
|
193
|
+
};
|
|
194
|
+
function detectTheme() {
|
|
195
|
+
const override = process.env["BREW_TUI_THEME"];
|
|
196
|
+
if (override === "dark" || override === "light") return override;
|
|
197
|
+
const cfb = process.env["COLORFGBG"];
|
|
198
|
+
if (cfb) {
|
|
199
|
+
const parts = cfb.split(";");
|
|
200
|
+
const bg = Number(parts[parts.length - 1]);
|
|
201
|
+
if (!isNaN(bg) && bg >= 7) return "light";
|
|
202
|
+
if (!isNaN(bg) && bg <= 6) return "dark";
|
|
203
|
+
}
|
|
204
|
+
return "dark";
|
|
205
|
+
}
|
|
206
|
+
var PALETTE = detectTheme() === "light" ? LIGHT_PALETTE : DARK_PALETTE;
|
|
207
|
+
function isNoColorRequested() {
|
|
208
|
+
const v = process.env["NO_COLOR"];
|
|
209
|
+
return typeof v === "string" && v.length > 0;
|
|
210
|
+
}
|
|
211
|
+
var NO_COLOR = isNoColorRequested();
|
|
212
|
+
var THEME = detectTheme();
|
|
213
|
+
var COLORS = NO_COLOR ? Object.fromEntries(
|
|
214
|
+
Object.keys(PALETTE).map((k) => [k, ""])
|
|
215
|
+
) : PALETTE;
|
|
158
216
|
|
|
159
217
|
// src/utils/gradient.tsx
|
|
160
218
|
import React, { useMemo } from "react";
|
|
@@ -176,6 +234,9 @@ function interpolateColor(c1, c2, t2) {
|
|
|
176
234
|
return rgbToHex(lerp(r1, r2, t2), lerp(g1, g2, t2), lerp(b1, b2, t2));
|
|
177
235
|
}
|
|
178
236
|
var GradientText = React.memo(function GradientText2({ children, colors, bold }) {
|
|
237
|
+
if (NO_COLOR) {
|
|
238
|
+
return /* @__PURE__ */ jsx(Text, { bold, children });
|
|
239
|
+
}
|
|
179
240
|
if (colors.length < 2) {
|
|
180
241
|
return /* @__PURE__ */ jsx(Text, { color: colors[0], bold, children });
|
|
181
242
|
}
|
|
@@ -195,14 +256,25 @@ var GradientText = React.memo(function GradientText2({ children, colors, bold })
|
|
|
195
256
|
return /* @__PURE__ */ jsx(Fragment, { children: coloredChars.map(({ char, color, key }) => /* @__PURE__ */ jsx(Text, { color, bold, children: char }, key)) });
|
|
196
257
|
});
|
|
197
258
|
var GRADIENTS = {
|
|
198
|
-
gold: [
|
|
199
|
-
sunset: [
|
|
200
|
-
ocean: [
|
|
201
|
-
emerald: [
|
|
202
|
-
fire: [
|
|
203
|
-
version: [
|
|
204
|
-
pro: [
|
|
205
|
-
darkGold: [
|
|
259
|
+
gold: [COLORS.gold, COLORS.goldOrange, COLORS.goldDeep],
|
|
260
|
+
sunset: [COLORS.brand, COLORS.gold, COLORS.brand],
|
|
261
|
+
ocean: [COLORS.info, COLORS.blue, COLORS.purple],
|
|
262
|
+
emerald: [COLORS.success, COLORS.teal, COLORS.info],
|
|
263
|
+
fire: [COLORS.error, COLORS.warning, COLORS.gold],
|
|
264
|
+
version: [COLORS.error, COLORS.muted, COLORS.teal],
|
|
265
|
+
pro: [COLORS.brand, COLORS.gold, COLORS.brand],
|
|
266
|
+
darkGold: [COLORS.goldDeep, COLORS.goldDark, COLORS.goldDeepest]
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// src/utils/spacing.ts
|
|
270
|
+
var SPACING = {
|
|
271
|
+
none: 0,
|
|
272
|
+
xs: 1,
|
|
273
|
+
sm: 2,
|
|
274
|
+
md: 3,
|
|
275
|
+
lg: 4,
|
|
276
|
+
xl: 6,
|
|
277
|
+
xxl: 8
|
|
206
278
|
};
|
|
207
279
|
|
|
208
280
|
// src/components/layout/header.tsx
|
|
@@ -310,13 +382,13 @@ function Header() {
|
|
|
310
382
|
const logoBlock = /* @__PURE__ */ jsx2(Box, { flexDirection: "column", flexShrink: 0, children: LOGO_BREW.map((brew, i) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
311
383
|
/* @__PURE__ */ jsx2(GradientText, { colors: GRADIENTS.gold, children: brew }),
|
|
312
384
|
/* @__PURE__ */ jsx2(GradientText, { colors: GRADIENTS.darkGold, children: LOGO_TUI[i] })
|
|
313
|
-
] }, i)) });
|
|
314
|
-
const menuBlock = /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: COLORS.lavender, paddingX:
|
|
385
|
+
] }, `logo-${i}`)) });
|
|
386
|
+
const menuBlock = /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: COLORS.lavender, paddingX: SPACING.xs, flexDirection: "column", alignSelf: isNarrow ? "flex-start" : "center", children: [
|
|
315
387
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
|
|
316
388
|
/* @__PURE__ */ jsx2(Box, { flexDirection: "column", children: COL1_VIEWS.map((view) => /* @__PURE__ */ jsx2(MenuItem, { view, currentView }, view)) }),
|
|
317
|
-
/* @__PURE__ */ jsx2(Box, { flexDirection: "column", marginLeft:
|
|
389
|
+
/* @__PURE__ */ jsx2(Box, { flexDirection: "column", marginLeft: SPACING.sm, children: COL2_VIEWS.map((view) => /* @__PURE__ */ jsx2(MenuItem, { view, currentView }, view)) })
|
|
318
390
|
] }),
|
|
319
|
-
/* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: COLORS.lavender, marginTop:
|
|
391
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: COLORS.lavender, marginTop: SPACING.none, children: [
|
|
320
392
|
/* @__PURE__ */ jsx2(Text2, { bold: true, color: COLORS.white, children: "S" }),
|
|
321
393
|
/* @__PURE__ */ jsxs(Text2, { color: COLORS.textSecondary, children: [
|
|
322
394
|
" ",
|
|
@@ -335,14 +407,14 @@ function Header() {
|
|
|
335
407
|
] })
|
|
336
408
|
] });
|
|
337
409
|
if (isNarrow) {
|
|
338
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX:
|
|
410
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: SPACING.xs, children: [
|
|
339
411
|
logoBlock,
|
|
340
|
-
/* @__PURE__ */ jsx2(Box, { marginTop:
|
|
412
|
+
/* @__PURE__ */ jsx2(Box, { marginTop: SPACING.xs, children: menuBlock })
|
|
341
413
|
] });
|
|
342
414
|
}
|
|
343
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", paddingX:
|
|
415
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", paddingX: SPACING.xs, alignItems: "center", children: [
|
|
344
416
|
logoBlock,
|
|
345
|
-
/* @__PURE__ */ jsx2(Box, { marginLeft:
|
|
417
|
+
/* @__PURE__ */ jsx2(Box, { marginLeft: SPACING.sm, children: menuBlock })
|
|
346
418
|
] });
|
|
347
419
|
}
|
|
348
420
|
|
|
@@ -380,7 +452,7 @@ function Footer() {
|
|
|
380
452
|
const currentView = useNavigationStore((s) => s.currentView);
|
|
381
453
|
const locale = useLocaleStore((s) => s.locale);
|
|
382
454
|
const defs = VIEW_HINT_DEFS[currentView] ?? [];
|
|
383
|
-
return /* @__PURE__ */ jsxs2(Box2, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: COLORS.gold, paddingX:
|
|
455
|
+
return /* @__PURE__ */ jsxs2(Box2, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: COLORS.gold, paddingX: SPACING.xs, flexWrap: "wrap", children: [
|
|
384
456
|
defs.map((def, i) => {
|
|
385
457
|
const key = def.length === 1 ? def[0] : `${def[0]}:${def[1]}`;
|
|
386
458
|
return /* @__PURE__ */ jsxs2(React2.Fragment, { children: [
|
|
@@ -413,7 +485,7 @@ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
|
413
485
|
function AppLayout({ children }) {
|
|
414
486
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", width: "100%", children: [
|
|
415
487
|
/* @__PURE__ */ jsx4(Header, {}),
|
|
416
|
-
/* @__PURE__ */ jsx4(Box3, { flexDirection: "column", flexGrow: 1, paddingX:
|
|
488
|
+
/* @__PURE__ */ jsx4(Box3, { flexDirection: "column", flexGrow: 1, paddingX: SPACING.sm, paddingY: SPACING.xs, children }),
|
|
417
489
|
/* @__PURE__ */ jsx4(Footer, {})
|
|
418
490
|
] });
|
|
419
491
|
}
|
|
@@ -421,371 +493,6 @@ function AppLayout({ children }) {
|
|
|
421
493
|
// src/stores/license-store.ts
|
|
422
494
|
import { create as create2 } from "zustand";
|
|
423
495
|
|
|
424
|
-
// src/lib/license/license-manager.ts
|
|
425
|
-
import { readFile as readFile2, writeFile as writeFile2, rename, rm } from "fs/promises";
|
|
426
|
-
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
|
|
427
|
-
|
|
428
|
-
// src/lib/license/polar-api.ts
|
|
429
|
-
import { randomUUID } from "crypto";
|
|
430
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
431
|
-
import { join } from "path";
|
|
432
|
-
import { homedir } from "os";
|
|
433
|
-
var BASE_URL = "https://api.polar.sh/v1/customer-portal/license-keys";
|
|
434
|
-
var POLAR_ORGANIZATION_ID = "b8f245c0-d116-4457-92fb-1bda47139f82";
|
|
435
|
-
var DATA_DIR2 = join(homedir(), ".brew-tui");
|
|
436
|
-
var MACHINE_ID_PATH = join(DATA_DIR2, "machine-id");
|
|
437
|
-
async function getMachineId() {
|
|
438
|
-
try {
|
|
439
|
-
const id2 = (await readFile(MACHINE_ID_PATH, "utf-8")).trim();
|
|
440
|
-
if (id2) return id2;
|
|
441
|
-
} catch {
|
|
442
|
-
}
|
|
443
|
-
const id = randomUUID();
|
|
444
|
-
await mkdir(DATA_DIR2, { recursive: true, mode: 448 });
|
|
445
|
-
await writeFile(MACHINE_ID_PATH, id, { encoding: "utf-8", mode: 384 });
|
|
446
|
-
return id;
|
|
447
|
-
}
|
|
448
|
-
function validateApiUrl(url) {
|
|
449
|
-
const parsed = new URL(url);
|
|
450
|
-
if (parsed.protocol !== "https:") {
|
|
451
|
-
throw new Error("HTTPS required for license API");
|
|
452
|
-
}
|
|
453
|
-
if (!parsed.hostname.endsWith("polar.sh")) {
|
|
454
|
-
throw new Error("Invalid API host");
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
async function post(endpoint, body, expectEmpty = false) {
|
|
458
|
-
const url = `${BASE_URL}/${endpoint}`;
|
|
459
|
-
validateApiUrl(url);
|
|
460
|
-
const res = await fetchWithRetry(url, {
|
|
461
|
-
method: "POST",
|
|
462
|
-
headers: { "Content-Type": "application/json" },
|
|
463
|
-
body: JSON.stringify(body)
|
|
464
|
-
}, 15e3);
|
|
465
|
-
if (!res.ok) {
|
|
466
|
-
let message = `Request failed with status ${res.status}`;
|
|
467
|
-
try {
|
|
468
|
-
const errBody = await res.json();
|
|
469
|
-
if (typeof errBody.detail === "string") message = errBody.detail;
|
|
470
|
-
else if (typeof errBody.error === "string") message = errBody.error;
|
|
471
|
-
else if (typeof errBody.message === "string") message = errBody.message;
|
|
472
|
-
} catch {
|
|
473
|
-
}
|
|
474
|
-
throw new Error(message);
|
|
475
|
-
}
|
|
476
|
-
if (expectEmpty || res.status === 204) return void 0;
|
|
477
|
-
return res.json();
|
|
478
|
-
}
|
|
479
|
-
async function activateLicense(key) {
|
|
480
|
-
const machineId = await getMachineId();
|
|
481
|
-
const activation = await post("activate", {
|
|
482
|
-
key,
|
|
483
|
-
organization_id: POLAR_ORGANIZATION_ID,
|
|
484
|
-
label: machineId
|
|
485
|
-
// SEG-004: Use machine UUID instead of hostname
|
|
486
|
-
});
|
|
487
|
-
if (!activation || typeof activation.id !== "string" || !activation.license_key) {
|
|
488
|
-
throw new Error("Invalid activation response: missing required fields");
|
|
489
|
-
}
|
|
490
|
-
let customerEmail = "";
|
|
491
|
-
let customerName = "";
|
|
492
|
-
try {
|
|
493
|
-
const validated = await post("validate", {
|
|
494
|
-
key,
|
|
495
|
-
organization_id: POLAR_ORGANIZATION_ID,
|
|
496
|
-
activation_id: activation.id
|
|
497
|
-
});
|
|
498
|
-
customerEmail = validated.customer?.email ?? "";
|
|
499
|
-
customerName = validated.customer?.name ?? "";
|
|
500
|
-
} catch {
|
|
501
|
-
}
|
|
502
|
-
return {
|
|
503
|
-
activated: true,
|
|
504
|
-
error: null,
|
|
505
|
-
instance: { id: activation.id },
|
|
506
|
-
license_key: {
|
|
507
|
-
id: 0,
|
|
508
|
-
status: activation.license_key.status,
|
|
509
|
-
key,
|
|
510
|
-
activation_limit: 0,
|
|
511
|
-
activations_count: 0,
|
|
512
|
-
expires_at: activation.license_key.expires_at
|
|
513
|
-
},
|
|
514
|
-
meta: { customer_email: customerEmail, customer_name: customerName }
|
|
515
|
-
};
|
|
516
|
-
}
|
|
517
|
-
async function validateLicense(key, instanceId) {
|
|
518
|
-
const res = await post("validate", {
|
|
519
|
-
key,
|
|
520
|
-
organization_id: POLAR_ORGANIZATION_ID,
|
|
521
|
-
activation_id: instanceId
|
|
522
|
-
});
|
|
523
|
-
if (!res || typeof res.id !== "string" || typeof res.status !== "string" || !res.customer) {
|
|
524
|
-
throw new Error("Invalid validation response: missing required fields");
|
|
525
|
-
}
|
|
526
|
-
const notExpired = res.expires_at === null || new Date(res.expires_at) > /* @__PURE__ */ new Date();
|
|
527
|
-
const valid = res.status === "granted" && notExpired;
|
|
528
|
-
return {
|
|
529
|
-
valid,
|
|
530
|
-
error: valid ? null : `License ${res.status}`,
|
|
531
|
-
license_key: {
|
|
532
|
-
id: 0,
|
|
533
|
-
status: res.status,
|
|
534
|
-
key,
|
|
535
|
-
expires_at: res.expires_at
|
|
536
|
-
},
|
|
537
|
-
instance: { id: instanceId }
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
async function deactivateLicense(key, instanceId) {
|
|
541
|
-
await post(
|
|
542
|
-
"deactivate",
|
|
543
|
-
{ key, organization_id: POLAR_ORGANIZATION_ID, activation_id: instanceId },
|
|
544
|
-
true
|
|
545
|
-
);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// src/lib/license/license-manager.ts
|
|
549
|
-
var REVALIDATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
550
|
-
var GRACE_PERIOD_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
551
|
-
var ACTIVATION_COOLDOWN_MS = 3e4;
|
|
552
|
-
var MAX_ATTEMPTS = 5;
|
|
553
|
-
var LOCKOUT_MS = 15 * 60 * 1e3;
|
|
554
|
-
var tracker = {
|
|
555
|
-
attempts: 0,
|
|
556
|
-
lastAttempt: 0,
|
|
557
|
-
lockedUntil: 0
|
|
558
|
-
};
|
|
559
|
-
function checkRateLimit() {
|
|
560
|
-
const now = Date.now();
|
|
561
|
-
if (now < tracker.lockedUntil) {
|
|
562
|
-
const remaining = Math.ceil((tracker.lockedUntil - now) / 6e4);
|
|
563
|
-
throw new Error(t("cli_rateLimited", { minutes: remaining }));
|
|
564
|
-
}
|
|
565
|
-
if (now - tracker.lastAttempt < ACTIVATION_COOLDOWN_MS) {
|
|
566
|
-
throw new Error(t("cli_cooldown"));
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
function recordAttempt(success) {
|
|
570
|
-
const now = Date.now();
|
|
571
|
-
tracker.lastAttempt = now;
|
|
572
|
-
if (success) {
|
|
573
|
-
tracker.attempts = 0;
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
tracker.attempts++;
|
|
577
|
-
if (tracker.attempts >= MAX_ATTEMPTS) {
|
|
578
|
-
tracker.lockedUntil = now + LOCKOUT_MS;
|
|
579
|
-
tracker.attempts = 0;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
var ENCRYPTION_SECRET = "brew-tui-license-aes256gcm-v1";
|
|
583
|
-
var SCRYPT_SALT = "brew-tui-salt-v1";
|
|
584
|
-
var _derivedKey = null;
|
|
585
|
-
function deriveEncryptionKey() {
|
|
586
|
-
if (!_derivedKey) _derivedKey = scryptSync(ENCRYPTION_SECRET, SCRYPT_SALT, 32);
|
|
587
|
-
return _derivedKey;
|
|
588
|
-
}
|
|
589
|
-
function encryptLicenseData(data) {
|
|
590
|
-
const key = deriveEncryptionKey();
|
|
591
|
-
const iv = randomBytes(12);
|
|
592
|
-
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
593
|
-
const plaintext = JSON.stringify(data);
|
|
594
|
-
const ciphertext = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
|
|
595
|
-
const tag = cipher.getAuthTag();
|
|
596
|
-
return {
|
|
597
|
-
encrypted: ciphertext.toString("base64"),
|
|
598
|
-
iv: iv.toString("base64"),
|
|
599
|
-
tag: tag.toString("base64")
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
function decryptLicenseData(encrypted, iv, tag) {
|
|
603
|
-
const key = deriveEncryptionKey();
|
|
604
|
-
const decipher = createDecipheriv(
|
|
605
|
-
"aes-256-gcm",
|
|
606
|
-
key,
|
|
607
|
-
Buffer.from(iv, "base64")
|
|
608
|
-
);
|
|
609
|
-
decipher.setAuthTag(Buffer.from(tag, "base64"));
|
|
610
|
-
const plaintext = Buffer.concat([
|
|
611
|
-
decipher.update(Buffer.from(encrypted, "base64")),
|
|
612
|
-
decipher.final()
|
|
613
|
-
]);
|
|
614
|
-
return JSON.parse(plaintext.toString("utf-8"));
|
|
615
|
-
}
|
|
616
|
-
function isLicenseFile(obj) {
|
|
617
|
-
return typeof obj === "object" && obj !== null && obj.version === 1;
|
|
618
|
-
}
|
|
619
|
-
function isEncryptedLicenseFile(obj) {
|
|
620
|
-
if (!isLicenseFile(obj)) return false;
|
|
621
|
-
const record = obj;
|
|
622
|
-
return typeof record.encrypted === "string" && typeof record.iv === "string" && typeof record.tag === "string";
|
|
623
|
-
}
|
|
624
|
-
async function getMachineId2() {
|
|
625
|
-
try {
|
|
626
|
-
const { readFile: readMachineId } = await import("fs/promises");
|
|
627
|
-
const { join: join7 } = await import("path");
|
|
628
|
-
const { homedir: homedir4 } = await import("os");
|
|
629
|
-
const machineIdPath = join7(homedir4(), ".brew-tui", "machine-id");
|
|
630
|
-
return (await readMachineId(machineIdPath, "utf-8")).trim() || null;
|
|
631
|
-
} catch {
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
async function loadLicense() {
|
|
636
|
-
try {
|
|
637
|
-
const raw = await readFile2(LICENSE_PATH, "utf-8");
|
|
638
|
-
const parsed = JSON.parse(raw);
|
|
639
|
-
if (!isLicenseFile(parsed)) {
|
|
640
|
-
throw new Error("Invalid license data format");
|
|
641
|
-
}
|
|
642
|
-
const file = parsed;
|
|
643
|
-
if (file.version !== 1) {
|
|
644
|
-
throw new Error("Unsupported data version");
|
|
645
|
-
}
|
|
646
|
-
if (isEncryptedLicenseFile(file)) {
|
|
647
|
-
const data = decryptLicenseData(file.encrypted, file.iv, file.tag);
|
|
648
|
-
const fileRecord = file;
|
|
649
|
-
if (fileRecord.machineId) {
|
|
650
|
-
const currentMachineId = await getMachineId2();
|
|
651
|
-
if (currentMachineId && fileRecord.machineId !== currentMachineId) {
|
|
652
|
-
throw new Error("License was activated on a different machine");
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return data;
|
|
656
|
-
}
|
|
657
|
-
if (file.license) {
|
|
658
|
-
const data = file.license;
|
|
659
|
-
await saveLicense(data);
|
|
660
|
-
return data;
|
|
661
|
-
}
|
|
662
|
-
return null;
|
|
663
|
-
} catch {
|
|
664
|
-
return null;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
async function saveLicense(data) {
|
|
668
|
-
await ensureDataDirs();
|
|
669
|
-
const { encrypted, iv, tag } = encryptLicenseData(data);
|
|
670
|
-
const machineId = await getMachineId2();
|
|
671
|
-
const file = { version: 1, encrypted, iv, tag };
|
|
672
|
-
if (machineId) file.machineId = machineId;
|
|
673
|
-
const tmpPath = LICENSE_PATH + ".tmp";
|
|
674
|
-
await writeFile2(tmpPath, JSON.stringify(file, null, 2), { encoding: "utf-8", mode: 384 });
|
|
675
|
-
await rename(tmpPath, LICENSE_PATH);
|
|
676
|
-
}
|
|
677
|
-
async function clearLicense() {
|
|
678
|
-
try {
|
|
679
|
-
await rm(LICENSE_PATH);
|
|
680
|
-
} catch {
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
function isExpired(license) {
|
|
684
|
-
if (!license.expiresAt) return false;
|
|
685
|
-
return new Date(license.expiresAt).getTime() < Date.now();
|
|
686
|
-
}
|
|
687
|
-
function needsRevalidation(license) {
|
|
688
|
-
const lastValidated = new Date(license.lastValidatedAt).getTime();
|
|
689
|
-
if (isNaN(lastValidated)) return true;
|
|
690
|
-
return Date.now() - lastValidated > REVALIDATION_INTERVAL_MS;
|
|
691
|
-
}
|
|
692
|
-
function isWithinGracePeriod(license) {
|
|
693
|
-
const lastValidated = new Date(license.lastValidatedAt).getTime();
|
|
694
|
-
if (isNaN(lastValidated)) return false;
|
|
695
|
-
return Date.now() - lastValidated < GRACE_PERIOD_MS;
|
|
696
|
-
}
|
|
697
|
-
function getDegradationLevel(license) {
|
|
698
|
-
const lastValidated = new Date(license.lastValidatedAt).getTime();
|
|
699
|
-
if (isNaN(lastValidated)) return "expired";
|
|
700
|
-
const elapsed = Date.now() - lastValidated;
|
|
701
|
-
if (elapsed < 0) return "none";
|
|
702
|
-
const days = elapsed / (24 * 60 * 60 * 1e3);
|
|
703
|
-
if (days <= 7) return "none";
|
|
704
|
-
if (days <= 14) return "warning";
|
|
705
|
-
if (days <= 30) return "limited";
|
|
706
|
-
return "expired";
|
|
707
|
-
}
|
|
708
|
-
function validateLicenseKey(key) {
|
|
709
|
-
if (key.length < 10 || key.length > 100) {
|
|
710
|
-
throw new Error("Invalid license key format");
|
|
711
|
-
}
|
|
712
|
-
if (!/^[\w-]+$/.test(key)) {
|
|
713
|
-
throw new Error("Invalid license key format");
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
function detectPlan(key) {
|
|
717
|
-
const upper = key.toUpperCase();
|
|
718
|
-
return upper.startsWith("BTUI-T-") || upper.startsWith("BTUI-T_") ? "team" : "pro";
|
|
719
|
-
}
|
|
720
|
-
async function activate(key) {
|
|
721
|
-
validateLicenseKey(key);
|
|
722
|
-
checkRateLimit();
|
|
723
|
-
let success = false;
|
|
724
|
-
try {
|
|
725
|
-
const res = await activateLicense(key);
|
|
726
|
-
if (!res.activated) {
|
|
727
|
-
throw new Error(res.error ?? "Activation failed");
|
|
728
|
-
}
|
|
729
|
-
const license = {
|
|
730
|
-
key,
|
|
731
|
-
instanceId: res.instance.id,
|
|
732
|
-
status: "active",
|
|
733
|
-
customerEmail: res.meta.customer_email,
|
|
734
|
-
customerName: res.meta.customer_name,
|
|
735
|
-
plan: detectPlan(key),
|
|
736
|
-
activatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
737
|
-
expiresAt: res.license_key.expires_at,
|
|
738
|
-
lastValidatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
739
|
-
};
|
|
740
|
-
await saveLicense(license);
|
|
741
|
-
success = true;
|
|
742
|
-
return license;
|
|
743
|
-
} finally {
|
|
744
|
-
recordAttempt(success);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
function isNetworkError(err) {
|
|
748
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
749
|
-
return /fetch failed|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network|timeout|abort/i.test(msg);
|
|
750
|
-
}
|
|
751
|
-
async function revalidate(license) {
|
|
752
|
-
try {
|
|
753
|
-
const res = await validateLicense(license.key, license.instanceId);
|
|
754
|
-
if (res.valid) {
|
|
755
|
-
const updated = {
|
|
756
|
-
...license,
|
|
757
|
-
lastValidatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
758
|
-
status: "active",
|
|
759
|
-
expiresAt: res.license_key.expires_at
|
|
760
|
-
};
|
|
761
|
-
await saveLicense(updated);
|
|
762
|
-
return "valid";
|
|
763
|
-
}
|
|
764
|
-
await saveLicense({ ...license, status: "expired" });
|
|
765
|
-
return "expired";
|
|
766
|
-
} catch (err) {
|
|
767
|
-
if (isNetworkError(err)) {
|
|
768
|
-
return isWithinGracePeriod(license) ? "grace" : "expired";
|
|
769
|
-
}
|
|
770
|
-
await saveLicense({ ...license, status: "expired" });
|
|
771
|
-
return "expired";
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
async function deactivate(license) {
|
|
775
|
-
let remoteSuccess = false;
|
|
776
|
-
for (let attempt = 0; attempt < 3; attempt++) {
|
|
777
|
-
try {
|
|
778
|
-
await deactivateLicense(license.key, license.instanceId);
|
|
779
|
-
remoteSuccess = true;
|
|
780
|
-
break;
|
|
781
|
-
} catch {
|
|
782
|
-
if (attempt < 2) await new Promise((r) => setTimeout(r, 1e3));
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
await clearLicense();
|
|
786
|
-
return { remoteSuccess };
|
|
787
|
-
}
|
|
788
|
-
|
|
789
496
|
// src/lib/license/anti-tamper.ts
|
|
790
497
|
var _originalIsPro = null;
|
|
791
498
|
var _originalGetState = null;
|
|
@@ -885,6 +592,15 @@ var useLicenseStore = create2((set, get) => ({
|
|
|
885
592
|
}
|
|
886
593
|
set({ status: "free", license: null, degradation: "none", error: null });
|
|
887
594
|
},
|
|
595
|
+
revalidate: async () => {
|
|
596
|
+
const { license } = get();
|
|
597
|
+
if (!license) return;
|
|
598
|
+
try {
|
|
599
|
+
await doRevalidation(license, set);
|
|
600
|
+
} catch (err) {
|
|
601
|
+
set({ error: err instanceof Error ? err.message : String(err) });
|
|
602
|
+
}
|
|
603
|
+
},
|
|
888
604
|
// Team is a superset of Pro — team users have full Pro access plus team features.
|
|
889
605
|
// Pro users do NOT get Team features (Compliance) without paying for the Team tier.
|
|
890
606
|
isPro: () => {
|
|
@@ -964,16 +680,111 @@ function useGlobalKeyboard(opts) {
|
|
|
964
680
|
}, { isActive: !opts?.disabled });
|
|
965
681
|
}
|
|
966
682
|
|
|
967
|
-
// src/
|
|
968
|
-
import {
|
|
683
|
+
// src/lib/onboarding.ts
|
|
684
|
+
import { access, writeFile, mkdir } from "fs/promises";
|
|
685
|
+
var cached = null;
|
|
686
|
+
async function hasCompletedOnboarding() {
|
|
687
|
+
if (cached !== null) return cached;
|
|
688
|
+
try {
|
|
689
|
+
await access(ONBOARDING_FLAG_PATH);
|
|
690
|
+
cached = true;
|
|
691
|
+
} catch {
|
|
692
|
+
cached = false;
|
|
693
|
+
}
|
|
694
|
+
return cached;
|
|
695
|
+
}
|
|
696
|
+
async function markOnboardingComplete() {
|
|
697
|
+
await ensureDataDirs();
|
|
698
|
+
await mkdir(DATA_DIR, { recursive: true, mode: 448 });
|
|
699
|
+
await writeFile(ONBOARDING_FLAG_PATH, (/* @__PURE__ */ new Date()).toISOString(), {
|
|
700
|
+
encoding: "utf-8",
|
|
701
|
+
mode: 384
|
|
702
|
+
});
|
|
703
|
+
cached = true;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// src/views/welcome.tsx
|
|
707
|
+
import { useEffect } from "react";
|
|
708
|
+
import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
|
|
969
709
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
710
|
+
function WelcomeView({ onContinue }) {
|
|
711
|
+
useEffect(() => {
|
|
712
|
+
return () => {
|
|
713
|
+
};
|
|
714
|
+
}, []);
|
|
715
|
+
useInput2((input, key) => {
|
|
716
|
+
if (key.return || input === " " || key.escape) {
|
|
717
|
+
void markOnboardingComplete().finally(onContinue);
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingY: SPACING.md, paddingX: SPACING.lg, children: [
|
|
721
|
+
/* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsx5(GradientText, { colors: GRADIENTS.gold, bold: true, children: t("welcome_title") }) }),
|
|
722
|
+
/* @__PURE__ */ jsx5(Box4, { marginTop: SPACING.sm, children: /* @__PURE__ */ jsx5(Text4, { color: COLORS.text, children: t("welcome_intro") }) }),
|
|
723
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: SPACING.sm, children: [
|
|
724
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.muted, children: t("welcome_keysHeader") }),
|
|
725
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingLeft: SPACING.sm, marginTop: SPACING.xs, children: [
|
|
726
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
727
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "1-9 0" }),
|
|
728
|
+
" ",
|
|
729
|
+
t("welcome_keyJumpView")
|
|
730
|
+
] }),
|
|
731
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
732
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "Tab" }),
|
|
733
|
+
" ",
|
|
734
|
+
t("welcome_keyCycleView")
|
|
735
|
+
] }),
|
|
736
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
737
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "j k" }),
|
|
738
|
+
" ",
|
|
739
|
+
t("welcome_keyMove")
|
|
740
|
+
] }),
|
|
741
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
742
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "/" }),
|
|
743
|
+
" ",
|
|
744
|
+
t("welcome_keySearch")
|
|
745
|
+
] }),
|
|
746
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
747
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "Enter" }),
|
|
748
|
+
" ",
|
|
749
|
+
t("welcome_keySelect")
|
|
750
|
+
] }),
|
|
751
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
752
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "Esc" }),
|
|
753
|
+
" ",
|
|
754
|
+
t("welcome_keyBack")
|
|
755
|
+
] }),
|
|
756
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
757
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "L" }),
|
|
758
|
+
" ",
|
|
759
|
+
t("welcome_keyLocale")
|
|
760
|
+
] }),
|
|
761
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
762
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.gold, bold: true, children: "q" }),
|
|
763
|
+
" ",
|
|
764
|
+
t("welcome_keyQuit")
|
|
765
|
+
] })
|
|
766
|
+
] })
|
|
767
|
+
] }),
|
|
768
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: SPACING.sm, children: [
|
|
769
|
+
/* @__PURE__ */ jsx5(Text4, { color: COLORS.muted, children: t("welcome_proHeader") }),
|
|
770
|
+
/* @__PURE__ */ jsx5(Box4, { paddingLeft: SPACING.sm, children: /* @__PURE__ */ jsx5(Text4, { color: COLORS.textSecondary, children: t("welcome_proIntro") }) })
|
|
771
|
+
] }),
|
|
772
|
+
/* @__PURE__ */ jsx5(Box4, { marginTop: SPACING.md, children: /* @__PURE__ */ jsx5(Text4, { color: COLORS.success, bold: true, children: t("welcome_continueHint") }) })
|
|
773
|
+
] });
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/components/common/upgrade-prompt.tsx
|
|
777
|
+
import { Box as Box5, Text as Text5 } from "ink";
|
|
778
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
970
779
|
var FEATURE_KEYS = {
|
|
971
780
|
profiles: { title: "upgrade_profiles", desc: "upgrade_profilesDesc" },
|
|
972
781
|
"smart-cleanup": { title: "upgrade_cleanup", desc: "upgrade_cleanupDesc" },
|
|
973
782
|
history: { title: "upgrade_history", desc: "upgrade_historyDesc" },
|
|
974
783
|
"security-audit": { title: "upgrade_security", desc: "upgrade_securityDesc" },
|
|
975
784
|
sync: { title: "upgrade_sync", desc: "upgrade_syncDesc" },
|
|
976
|
-
compliance: { title: "upgrade_compliance", desc: "upgrade_complianceDesc" }
|
|
785
|
+
compliance: { title: "upgrade_compliance", desc: "upgrade_complianceDesc" },
|
|
786
|
+
rollback: { title: "upgrade_rollback", desc: "upgrade_rollbackDesc" },
|
|
787
|
+
brewfile: { title: "upgrade_brewfile", desc: "upgrade_brewfileDesc" }
|
|
977
788
|
};
|
|
978
789
|
function UpgradePrompt({ viewId }) {
|
|
979
790
|
const keys = FEATURE_KEYS[viewId];
|
|
@@ -984,41 +795,41 @@ function UpgradePrompt({ viewId }) {
|
|
|
984
795
|
const pricingKey = team ? "upgrade_teamPricing" : "upgrade_pricing";
|
|
985
796
|
const buyUrlKey = team ? "upgrade_buyUrlTeam" : "upgrade_buyUrl";
|
|
986
797
|
const labelKey = team ? "upgrade_teamLabel" : "upgrade_proLabel";
|
|
987
|
-
return /* @__PURE__ */
|
|
988
|
-
|
|
798
|
+
return /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", alignItems: "center", paddingY: SPACING.sm, children: /* @__PURE__ */ jsxs5(
|
|
799
|
+
Box5,
|
|
989
800
|
{
|
|
990
801
|
borderStyle: "double",
|
|
991
802
|
borderColor: COLORS.brand,
|
|
992
|
-
paddingX:
|
|
993
|
-
paddingY:
|
|
803
|
+
paddingX: SPACING.md,
|
|
804
|
+
paddingY: SPACING.sm,
|
|
994
805
|
flexDirection: "column",
|
|
995
806
|
alignItems: "center",
|
|
996
807
|
width: "80%",
|
|
997
808
|
children: [
|
|
998
|
-
/* @__PURE__ */
|
|
809
|
+
/* @__PURE__ */ jsxs5(Text5, { bold: true, color: COLORS.brand, children: [
|
|
999
810
|
"\u2B50",
|
|
1000
811
|
" ",
|
|
1001
812
|
t(headerKey, { title })
|
|
1002
813
|
] }),
|
|
1003
|
-
/* @__PURE__ */
|
|
1004
|
-
/* @__PURE__ */
|
|
1005
|
-
/* @__PURE__ */
|
|
1006
|
-
/* @__PURE__ */
|
|
1007
|
-
/* @__PURE__ */
|
|
1008
|
-
/* @__PURE__ */
|
|
1009
|
-
/* @__PURE__ */
|
|
1010
|
-
/* @__PURE__ */
|
|
814
|
+
/* @__PURE__ */ jsx6(Text5, { children: " " }),
|
|
815
|
+
/* @__PURE__ */ jsx6(Text5, { color: COLORS.text, wrap: "wrap", children: t(keys.desc) }),
|
|
816
|
+
/* @__PURE__ */ jsx6(Text5, { children: " " }),
|
|
817
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", alignItems: "center", children: [
|
|
818
|
+
/* @__PURE__ */ jsx6(Text5, { color: COLORS.info, bold: true, children: t(pricingKey) }),
|
|
819
|
+
/* @__PURE__ */ jsx6(Text5, { children: " " }),
|
|
820
|
+
/* @__PURE__ */ jsx6(Text5, { color: COLORS.muted, children: t("upgrade_buyAt") }),
|
|
821
|
+
/* @__PURE__ */ jsxs5(Text5, { color: COLORS.sky, bold: true, children: [
|
|
1011
822
|
" ",
|
|
1012
823
|
t(buyUrlKey)
|
|
1013
824
|
] }),
|
|
1014
|
-
/* @__PURE__ */
|
|
1015
|
-
/* @__PURE__ */
|
|
1016
|
-
/* @__PURE__ */
|
|
825
|
+
/* @__PURE__ */ jsx6(Text5, { children: " " }),
|
|
826
|
+
/* @__PURE__ */ jsx6(Text5, { color: COLORS.muted, children: t("upgrade_activateWith") }),
|
|
827
|
+
/* @__PURE__ */ jsxs5(Text5, { color: COLORS.success, bold: true, children: [
|
|
1017
828
|
" ",
|
|
1018
829
|
t("upgrade_activateCmd")
|
|
1019
830
|
] }),
|
|
1020
|
-
/* @__PURE__ */
|
|
1021
|
-
/* @__PURE__ */
|
|
831
|
+
/* @__PURE__ */ jsx6(Text5, { children: " " }),
|
|
832
|
+
/* @__PURE__ */ jsx6(Text5, { color: COLORS.brand, children: t(labelKey) })
|
|
1022
833
|
] })
|
|
1023
834
|
]
|
|
1024
835
|
}
|
|
@@ -1026,8 +837,8 @@ function UpgradePrompt({ viewId }) {
|
|
|
1026
837
|
}
|
|
1027
838
|
|
|
1028
839
|
// src/views/dashboard.tsx
|
|
1029
|
-
import { useEffect, useMemo as useMemo2 } from "react";
|
|
1030
|
-
import { Box as
|
|
840
|
+
import { useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
841
|
+
import { Box as Box9, Text as Text11, useInput as useInput3, useStdout as useStdout3 } from "ink";
|
|
1031
842
|
|
|
1032
843
|
// src/stores/brew-store.ts
|
|
1033
844
|
import { create as create4 } from "zustand";
|
|
@@ -1231,11 +1042,26 @@ function validatePackageName(name) {
|
|
|
1231
1042
|
async function brewUpdate() {
|
|
1232
1043
|
return new Promise((resolve, reject) => {
|
|
1233
1044
|
const proc = spawn("brew", ["update"], { stdio: "ignore" });
|
|
1045
|
+
let settled = false;
|
|
1046
|
+
const timeout = setTimeout(() => {
|
|
1047
|
+
if (settled) return;
|
|
1048
|
+
settled = true;
|
|
1049
|
+
proc.kill("SIGTERM");
|
|
1050
|
+
reject(new Error("brew update timed out after 120s"));
|
|
1051
|
+
}, 12e4);
|
|
1234
1052
|
proc.on("close", (code) => {
|
|
1053
|
+
if (settled) return;
|
|
1054
|
+
settled = true;
|
|
1055
|
+
clearTimeout(timeout);
|
|
1235
1056
|
if (code === 0) resolve();
|
|
1236
1057
|
else reject(new Error(`brew update exited with code ${code}`));
|
|
1237
1058
|
});
|
|
1238
|
-
proc.on("error",
|
|
1059
|
+
proc.on("error", (err) => {
|
|
1060
|
+
if (settled) return;
|
|
1061
|
+
settled = true;
|
|
1062
|
+
clearTimeout(timeout);
|
|
1063
|
+
reject(err);
|
|
1064
|
+
});
|
|
1239
1065
|
});
|
|
1240
1066
|
}
|
|
1241
1067
|
async function getInstalled() {
|
|
@@ -1265,6 +1091,35 @@ async function getCaskInfo(name) {
|
|
|
1265
1091
|
return null;
|
|
1266
1092
|
}
|
|
1267
1093
|
}
|
|
1094
|
+
function formulaeFromCask(cask) {
|
|
1095
|
+
return {
|
|
1096
|
+
name: cask.token,
|
|
1097
|
+
full_name: cask.full_token,
|
|
1098
|
+
tap: "",
|
|
1099
|
+
desc: cask.desc,
|
|
1100
|
+
license: "",
|
|
1101
|
+
homepage: cask.homepage,
|
|
1102
|
+
versions: { stable: cask.version, head: null, bottle: false },
|
|
1103
|
+
dependencies: [],
|
|
1104
|
+
build_dependencies: [],
|
|
1105
|
+
installed: cask.installed ? [{
|
|
1106
|
+
version: cask.installed,
|
|
1107
|
+
used_options: [],
|
|
1108
|
+
built_as_bottle: false,
|
|
1109
|
+
poured_from_bottle: false,
|
|
1110
|
+
time: cask.installed_time ?? 0,
|
|
1111
|
+
runtime_dependencies: [],
|
|
1112
|
+
installed_as_dependency: false,
|
|
1113
|
+
installed_on_request: true
|
|
1114
|
+
}] : [],
|
|
1115
|
+
linked_keg: null,
|
|
1116
|
+
pinned: false,
|
|
1117
|
+
outdated: cask.outdated,
|
|
1118
|
+
deprecated: false,
|
|
1119
|
+
keg_only: false,
|
|
1120
|
+
caveats: null
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1268
1123
|
async function search(term) {
|
|
1269
1124
|
const safeTerm = term.replace(/^-+/, "");
|
|
1270
1125
|
if (!safeTerm) return { formulae: [], casks: [] };
|
|
@@ -1320,9 +1175,23 @@ function formulaeToListItems(formulae) {
|
|
|
1320
1175
|
};
|
|
1321
1176
|
});
|
|
1322
1177
|
}
|
|
1178
|
+
var impactCache = /* @__PURE__ */ new Map();
|
|
1179
|
+
var IMPACT_CACHE_LIMIT = 64;
|
|
1180
|
+
function impactKey(name, from, to, type) {
|
|
1181
|
+
return `${type}::${name}::${from}::${to}`;
|
|
1182
|
+
}
|
|
1323
1183
|
async function getUpgradeImpact(packageName, fromVersion, toVersion, packageType) {
|
|
1324
1184
|
validatePackageName(packageName);
|
|
1325
|
-
|
|
1185
|
+
const key = impactKey(packageName, fromVersion, toVersion, packageType);
|
|
1186
|
+
const cached2 = impactCache.get(key);
|
|
1187
|
+
if (cached2) return cached2;
|
|
1188
|
+
const result = await analyzeUpgradeImpact(packageName, fromVersion, toVersion, packageType);
|
|
1189
|
+
if (impactCache.size >= IMPACT_CACHE_LIMIT) {
|
|
1190
|
+
const firstKey = impactCache.keys().next().value;
|
|
1191
|
+
if (firstKey !== void 0) impactCache.delete(firstKey);
|
|
1192
|
+
}
|
|
1193
|
+
impactCache.set(key, result);
|
|
1194
|
+
return result;
|
|
1326
1195
|
}
|
|
1327
1196
|
function casksToListItems(casks) {
|
|
1328
1197
|
return casks.map((c) => ({
|
|
@@ -1568,7 +1437,7 @@ async function queryOneByOne(packages) {
|
|
|
1568
1437
|
try {
|
|
1569
1438
|
const partial = await queryBatch(
|
|
1570
1439
|
[pkg],
|
|
1571
|
-
[{ package: { name: pkg.name, ecosystem: "
|
|
1440
|
+
[{ package: { name: pkg.name, ecosystem: "Bitnami" }, version: pkg.version }]
|
|
1572
1441
|
);
|
|
1573
1442
|
for (const [k, v] of partial) result.set(k, v);
|
|
1574
1443
|
} catch (err) {
|
|
@@ -1583,7 +1452,7 @@ async function queryOneByOne(packages) {
|
|
|
1583
1452
|
try {
|
|
1584
1453
|
const retryResult = await queryBatch(
|
|
1585
1454
|
[pkg],
|
|
1586
|
-
[{ package: { name: pkg.name, ecosystem: "
|
|
1455
|
+
[{ package: { name: pkg.name, ecosystem: "Bitnami" }, version: pkg.version }]
|
|
1587
1456
|
);
|
|
1588
1457
|
for (const [k, v] of retryResult) result.set(k, v);
|
|
1589
1458
|
} catch {
|
|
@@ -1609,7 +1478,7 @@ async function queryVulnerabilities(packages) {
|
|
|
1609
1478
|
for (let i = 0; i < validPackages.length; i += BATCH_SIZE) {
|
|
1610
1479
|
const batch = validPackages.slice(i, i + BATCH_SIZE);
|
|
1611
1480
|
const queries = batch.map((p) => ({
|
|
1612
|
-
package: { name: p.name, ecosystem: "
|
|
1481
|
+
package: { name: p.name, ecosystem: "Bitnami" },
|
|
1613
1482
|
version: p.version
|
|
1614
1483
|
}));
|
|
1615
1484
|
const partial = await queryBatch(batch, queries);
|
|
@@ -1885,7 +1754,9 @@ var useSyncStore = create7((set, get) => ({
|
|
|
1885
1754
|
if (!config) throw new Error("Sync not initialized");
|
|
1886
1755
|
const envelope = await readSyncEnvelope();
|
|
1887
1756
|
if (!envelope) throw new Error("No sync data found");
|
|
1888
|
-
const
|
|
1757
|
+
const license = await loadLicense();
|
|
1758
|
+
if (!license) throw new Error("License missing");
|
|
1759
|
+
const payload = decryptPayload(envelope.encrypted, envelope.iv, envelope.tag, license.key);
|
|
1889
1760
|
await applyConflictResolutions(payload, resolutions, config.machineId);
|
|
1890
1761
|
const updatedConfig = await loadSyncConfig();
|
|
1891
1762
|
set({ config: updatedConfig, conflicts: [], loading: false });
|
|
@@ -1933,53 +1804,53 @@ var useComplianceStore = create8((set, get) => ({
|
|
|
1933
1804
|
}));
|
|
1934
1805
|
|
|
1935
1806
|
// src/components/common/stat-card.tsx
|
|
1936
|
-
import { Box as
|
|
1937
|
-
import { jsx as
|
|
1938
|
-
function StatCard({ label, value, color =
|
|
1807
|
+
import { Box as Box6, Text as Text6, useStdout as useStdout2 } from "ink";
|
|
1808
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1809
|
+
function StatCard({ label, value, color = COLORS.white }) {
|
|
1939
1810
|
const { stdout } = useStdout2();
|
|
1940
1811
|
const cols = stdout?.columns ?? 80;
|
|
1941
1812
|
const minW = cols < 60 ? 12 : cols < 100 ? 14 : 16;
|
|
1942
|
-
return /* @__PURE__ */
|
|
1943
|
-
|
|
1813
|
+
return /* @__PURE__ */ jsxs6(
|
|
1814
|
+
Box6,
|
|
1944
1815
|
{
|
|
1945
1816
|
borderStyle: "round",
|
|
1946
1817
|
borderColor: color,
|
|
1947
|
-
paddingX:
|
|
1948
|
-
paddingY:
|
|
1818
|
+
paddingX: SPACING.sm,
|
|
1819
|
+
paddingY: SPACING.none,
|
|
1949
1820
|
flexDirection: "column",
|
|
1950
1821
|
alignItems: "center",
|
|
1951
1822
|
minWidth: minW,
|
|
1952
1823
|
children: [
|
|
1953
|
-
/* @__PURE__ */
|
|
1954
|
-
/* @__PURE__ */
|
|
1824
|
+
/* @__PURE__ */ jsx7(Text6, { bold: true, color, children: value }),
|
|
1825
|
+
/* @__PURE__ */ jsx7(Text6, { color: COLORS.muted, children: label })
|
|
1955
1826
|
]
|
|
1956
1827
|
}
|
|
1957
1828
|
);
|
|
1958
1829
|
}
|
|
1959
1830
|
|
|
1960
1831
|
// src/components/common/loading.tsx
|
|
1961
|
-
import { Box as
|
|
1832
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
1962
1833
|
import { Spinner } from "@inkjs/ui";
|
|
1963
|
-
import { jsx as
|
|
1834
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1964
1835
|
function Loading({ message }) {
|
|
1965
1836
|
useLocaleStore((s) => s.locale);
|
|
1966
|
-
return /* @__PURE__ */
|
|
1837
|
+
return /* @__PURE__ */ jsx8(Box7, { paddingY: SPACING.xs, children: /* @__PURE__ */ jsx8(Spinner, { label: message ?? t("loading_default") }) });
|
|
1967
1838
|
}
|
|
1968
1839
|
function ErrorMessage({ message }) {
|
|
1969
1840
|
useLocaleStore((s) => s.locale);
|
|
1970
|
-
return /* @__PURE__ */
|
|
1971
|
-
/* @__PURE__ */
|
|
1841
|
+
return /* @__PURE__ */ jsxs7(Box7, { paddingY: SPACING.xs, children: [
|
|
1842
|
+
/* @__PURE__ */ jsxs7(Text7, { color: COLORS.error, bold: true, children: [
|
|
1972
1843
|
"\u2718",
|
|
1973
1844
|
" ",
|
|
1974
1845
|
t("error_prefix")
|
|
1975
1846
|
] }),
|
|
1976
|
-
/* @__PURE__ */
|
|
1847
|
+
/* @__PURE__ */ jsx8(Text7, { color: COLORS.error, children: message })
|
|
1977
1848
|
] });
|
|
1978
1849
|
}
|
|
1979
1850
|
|
|
1980
1851
|
// src/components/common/status-badge.tsx
|
|
1981
|
-
import { Text as
|
|
1982
|
-
import { jsxs as
|
|
1852
|
+
import { Text as Text8 } from "ink";
|
|
1853
|
+
import { jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1983
1854
|
var BADGE_STYLES = {
|
|
1984
1855
|
success: { icon: "\u2714", color: COLORS.success },
|
|
1985
1856
|
warning: { icon: "\u25B2", color: COLORS.warning },
|
|
@@ -1989,7 +1860,7 @@ var BADGE_STYLES = {
|
|
|
1989
1860
|
};
|
|
1990
1861
|
function StatusBadge({ label, variant }) {
|
|
1991
1862
|
const { icon, color } = BADGE_STYLES[variant];
|
|
1992
|
-
return /* @__PURE__ */
|
|
1863
|
+
return /* @__PURE__ */ jsxs8(Text8, { color, children: [
|
|
1993
1864
|
icon,
|
|
1994
1865
|
" ",
|
|
1995
1866
|
label
|
|
@@ -1997,16 +1868,16 @@ function StatusBadge({ label, variant }) {
|
|
|
1997
1868
|
}
|
|
1998
1869
|
|
|
1999
1870
|
// src/components/common/section-header.tsx
|
|
2000
|
-
import { Box as
|
|
2001
|
-
import { jsx as
|
|
1871
|
+
import { Box as Box8, Text as Text9 } from "ink";
|
|
1872
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2002
1873
|
function SectionHeader({ emoji, title, color = COLORS.gold, gradient, count }) {
|
|
2003
|
-
return /* @__PURE__ */
|
|
2004
|
-
/* @__PURE__ */
|
|
1874
|
+
return /* @__PURE__ */ jsxs9(Box8, { gap: SPACING.xs, children: [
|
|
1875
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
2005
1876
|
emoji,
|
|
2006
1877
|
" "
|
|
2007
1878
|
] }),
|
|
2008
|
-
gradient ? /* @__PURE__ */
|
|
2009
|
-
count !== void 0 && /* @__PURE__ */
|
|
1879
|
+
gradient ? /* @__PURE__ */ jsx9(GradientText, { colors: gradient, bold: true, children: title }) : /* @__PURE__ */ jsx9(Text9, { bold: true, color, children: title }),
|
|
1880
|
+
count !== void 0 && /* @__PURE__ */ jsxs9(Text9, { color: COLORS.textSecondary, children: [
|
|
2010
1881
|
"(",
|
|
2011
1882
|
count,
|
|
2012
1883
|
")"
|
|
@@ -2015,23 +1886,23 @@ function SectionHeader({ emoji, title, color = COLORS.gold, gradient, count }) {
|
|
|
2015
1886
|
}
|
|
2016
1887
|
|
|
2017
1888
|
// src/components/common/version-arrow.tsx
|
|
2018
|
-
import { Text as
|
|
2019
|
-
import { Fragment as Fragment3, jsx as
|
|
1889
|
+
import { Text as Text10 } from "ink";
|
|
1890
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2020
1891
|
function VersionArrow({ current, latest }) {
|
|
2021
|
-
return /* @__PURE__ */
|
|
2022
|
-
/* @__PURE__ */
|
|
1892
|
+
return /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1893
|
+
/* @__PURE__ */ jsxs10(Text10, { color: COLORS.muted, children: [
|
|
2023
1894
|
t("version_installed"),
|
|
2024
1895
|
" "
|
|
2025
1896
|
] }),
|
|
2026
|
-
/* @__PURE__ */
|
|
2027
|
-
/* @__PURE__ */
|
|
2028
|
-
/* @__PURE__ */
|
|
2029
|
-
/* @__PURE__ */
|
|
1897
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.error, children: current }),
|
|
1898
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.warning, children: " \u2500\u2500 " }),
|
|
1899
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.gold, children: "\u25B6" }),
|
|
1900
|
+
/* @__PURE__ */ jsxs10(Text10, { color: COLORS.muted, children: [
|
|
2030
1901
|
" ",
|
|
2031
1902
|
t("version_available"),
|
|
2032
1903
|
" "
|
|
2033
1904
|
] }),
|
|
2034
|
-
/* @__PURE__ */
|
|
1905
|
+
/* @__PURE__ */ jsx10(Text10, { color: COLORS.teal, children: latest })
|
|
2035
1906
|
] });
|
|
2036
1907
|
}
|
|
2037
1908
|
|
|
@@ -2063,7 +1934,7 @@ function truncate(str, maxLen) {
|
|
|
2063
1934
|
}
|
|
2064
1935
|
|
|
2065
1936
|
// src/views/dashboard.tsx
|
|
2066
|
-
import { jsx as
|
|
1937
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2067
1938
|
function ProStatusPanel() {
|
|
2068
1939
|
const security = useSecurityStore((s) => s.summary);
|
|
2069
1940
|
const drift = useBrewfileStore((s) => s.drift);
|
|
@@ -2075,40 +1946,53 @@ function ProStatusPanel() {
|
|
|
2075
1946
|
const lastSync = syncConfig?.lastSync ?? null;
|
|
2076
1947
|
const syncAgo = lastSync ? formatRelativeTime(new Date(lastSync).getTime() / 1e3) : null;
|
|
2077
1948
|
const violationCount = complianceReport ? complianceReport.violations.length : null;
|
|
2078
|
-
return /* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2080
|
-
/* @__PURE__ */
|
|
2081
|
-
/* @__PURE__ */
|
|
2082
|
-
cveCount === null ? /* @__PURE__ */
|
|
1949
|
+
return /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", borderStyle: "round", borderColor: COLORS.purple, paddingX: SPACING.sm, paddingY: SPACING.none, marginTop: SPACING.xs, children: [
|
|
1950
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, color: COLORS.purple, children: t("dashboard_pro_status") }),
|
|
1951
|
+
/* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
1952
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_security") }),
|
|
1953
|
+
cveCount === null ? /* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: "\u2014" }) : cveCount === 0 ? /* @__PURE__ */ jsx11(Text11, { color: COLORS.success, children: t("dashboard_no_cves") }) : /* @__PURE__ */ jsxs11(Text11, { color: COLORS.error, children: [
|
|
2083
1954
|
t("dashboard_cves", { count: String(cveCount) }),
|
|
2084
1955
|
criticalCount && criticalCount > 0 ? ` (${criticalCount} critical)` : ""
|
|
2085
1956
|
] })
|
|
2086
1957
|
] }),
|
|
2087
|
-
/* @__PURE__ */
|
|
2088
|
-
/* @__PURE__ */
|
|
2089
|
-
driftScore === null ? /* @__PURE__ */
|
|
1958
|
+
/* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
1959
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_brewfile") }),
|
|
1960
|
+
driftScore === null ? /* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: "\u2014" }) : /* @__PURE__ */ jsxs11(Text11, { color: driftScore >= 80 ? COLORS.success : COLORS.warning, children: [
|
|
2090
1961
|
driftScore,
|
|
2091
1962
|
"%"
|
|
2092
1963
|
] })
|
|
2093
1964
|
] }),
|
|
2094
|
-
/* @__PURE__ */
|
|
2095
|
-
/* @__PURE__ */
|
|
2096
|
-
syncAgo === null ? /* @__PURE__ */
|
|
1965
|
+
/* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
1966
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_sync") }),
|
|
1967
|
+
syncAgo === null ? /* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_sync_never") }) : /* @__PURE__ */ jsx11(Text11, { color: COLORS.info, children: t("dashboard_sync_ago", { time: syncAgo }) })
|
|
2097
1968
|
] }),
|
|
2098
|
-
/* @__PURE__ */
|
|
2099
|
-
/* @__PURE__ */
|
|
2100
|
-
violationCount === null ? /* @__PURE__ */
|
|
1969
|
+
/* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
1970
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_compliance") }),
|
|
1971
|
+
violationCount === null ? /* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: "\u2014" }) : violationCount === 0 ? /* @__PURE__ */ jsx11(Text11, { color: COLORS.success, children: t("dashboard_compliance_ok") }) : /* @__PURE__ */ jsx11(Text11, { color: COLORS.warning, children: t("dashboard_compliance_violations", { count: String(violationCount) }) })
|
|
2101
1972
|
] })
|
|
2102
1973
|
] });
|
|
2103
1974
|
}
|
|
2104
1975
|
function DashboardView() {
|
|
2105
|
-
const
|
|
1976
|
+
const formulae = useBrewStore((s) => s.formulae);
|
|
1977
|
+
const casks = useBrewStore((s) => s.casks);
|
|
1978
|
+
const outdated = useBrewStore((s) => s.outdated);
|
|
1979
|
+
const services = useBrewStore((s) => s.services);
|
|
1980
|
+
const config = useBrewStore((s) => s.config);
|
|
1981
|
+
const loading = useBrewStore((s) => s.loading);
|
|
1982
|
+
const errors = useBrewStore((s) => s.errors);
|
|
1983
|
+
const lastFetchedAt = useBrewStore((s) => s.lastFetchedAt);
|
|
1984
|
+
const fetchAll = useBrewStore((s) => s.fetchAll);
|
|
2106
1985
|
const isPro = useLicenseStore((s) => s.isPro);
|
|
2107
1986
|
const { stdout } = useStdout3();
|
|
2108
1987
|
const columns = stdout?.columns ?? 80;
|
|
2109
|
-
|
|
1988
|
+
useEffect2(() => {
|
|
2110
1989
|
fetchAll();
|
|
2111
1990
|
}, []);
|
|
1991
|
+
useInput3((input) => {
|
|
1992
|
+
if (errors.installed && (input === "r" || input === "R")) {
|
|
1993
|
+
void fetchAll();
|
|
1994
|
+
}
|
|
1995
|
+
});
|
|
2112
1996
|
const errorServiceList = useMemo2(
|
|
2113
1997
|
() => services.filter((s) => s.status === "error"),
|
|
2114
1998
|
[services]
|
|
@@ -2126,15 +2010,23 @@ function DashboardView() {
|
|
|
2126
2010
|
const outdatedValue = loading.outdated ? "..." : errors.outdated ? t("dashboard_statError") : outdated.formulae.length + outdated.casks.length;
|
|
2127
2011
|
const servicesValue = loading.services ? "..." : errors.services ? t("dashboard_statError") : `${runningServices}/${services.length}`;
|
|
2128
2012
|
const lastUpdated = lastFetchedAt.installed ? formatRelativeTime(lastFetchedAt.installed / 1e3) : null;
|
|
2129
|
-
if (loading.installed) return /* @__PURE__ */
|
|
2130
|
-
if (errors.installed)
|
|
2013
|
+
if (loading.installed) return /* @__PURE__ */ jsx11(Loading, { message: t("loading_fetchingBrew") });
|
|
2014
|
+
if (errors.installed) {
|
|
2015
|
+
return /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", children: [
|
|
2016
|
+
/* @__PURE__ */ jsx11(ErrorMessage, { message: errors.installed }),
|
|
2017
|
+
/* @__PURE__ */ jsx11(Box9, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs11(Text11, { color: COLORS.textSecondary, children: [
|
|
2018
|
+
"r:",
|
|
2019
|
+
t("hint_refresh")
|
|
2020
|
+
] }) })
|
|
2021
|
+
] });
|
|
2022
|
+
}
|
|
2131
2023
|
const isNarrow = columns < 60;
|
|
2132
|
-
return /* @__PURE__ */
|
|
2133
|
-
/* @__PURE__ */
|
|
2134
|
-
/* @__PURE__ */
|
|
2135
|
-
/* @__PURE__ */
|
|
2136
|
-
/* @__PURE__ */
|
|
2137
|
-
/* @__PURE__ */
|
|
2024
|
+
return /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", gap: SPACING.sm, children: [
|
|
2025
|
+
/* @__PURE__ */ jsx11(SectionHeader, { emoji: "\u{1F4CA}", title: t("dashboard_overview"), gradient: GRADIENTS.gold }),
|
|
2026
|
+
/* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, flexWrap: "wrap", flexDirection: isNarrow ? "column" : "row", children: [
|
|
2027
|
+
/* @__PURE__ */ jsx11(StatCard, { label: t("dashboard_formulae"), value: formulae.length, color: COLORS.info }),
|
|
2028
|
+
/* @__PURE__ */ jsx11(StatCard, { label: t("dashboard_casks"), value: casks.length, color: COLORS.purple }),
|
|
2029
|
+
/* @__PURE__ */ jsx11(
|
|
2138
2030
|
StatCard,
|
|
2139
2031
|
{
|
|
2140
2032
|
label: t("dashboard_outdated"),
|
|
@@ -2142,7 +2034,7 @@ function DashboardView() {
|
|
|
2142
2034
|
color: typeof outdatedValue === "number" && outdatedValue > 0 ? COLORS.warning : errors.outdated ? COLORS.error : COLORS.success
|
|
2143
2035
|
}
|
|
2144
2036
|
),
|
|
2145
|
-
/* @__PURE__ */
|
|
2037
|
+
/* @__PURE__ */ jsx11(
|
|
2146
2038
|
StatCard,
|
|
2147
2039
|
{
|
|
2148
2040
|
label: t("dashboard_services"),
|
|
@@ -2151,66 +2043,66 @@ function DashboardView() {
|
|
|
2151
2043
|
}
|
|
2152
2044
|
)
|
|
2153
2045
|
] }),
|
|
2154
|
-
lastUpdated && /* @__PURE__ */
|
|
2155
|
-
partialErrors.length > 0 && /* @__PURE__ */
|
|
2156
|
-
/* @__PURE__ */
|
|
2157
|
-
partialErrors.map((item) => /* @__PURE__ */
|
|
2046
|
+
lastUpdated && /* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_lastUpdated", { time: lastUpdated }) }),
|
|
2047
|
+
partialErrors.length > 0 && /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", borderStyle: "round", borderColor: COLORS.warning, paddingX: SPACING.sm, paddingY: SPACING.none, children: [
|
|
2048
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.warning, bold: true, children: t("dashboard_partialData") }),
|
|
2049
|
+
partialErrors.map((item) => /* @__PURE__ */ jsxs11(Text11, { color: COLORS.muted, children: [
|
|
2158
2050
|
item.label,
|
|
2159
2051
|
": ",
|
|
2160
2052
|
item.message
|
|
2161
2053
|
] }, item.label))
|
|
2162
2054
|
] }),
|
|
2163
|
-
config && !errors.config && /* @__PURE__ */
|
|
2164
|
-
/* @__PURE__ */
|
|
2165
|
-
/* @__PURE__ */
|
|
2166
|
-
/* @__PURE__ */
|
|
2167
|
-
/* @__PURE__ */
|
|
2055
|
+
config && !errors.config && /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", children: [
|
|
2056
|
+
/* @__PURE__ */ jsx11(SectionHeader, { emoji: "\u2139\uFE0F", title: t("dashboard_systemInfo"), gradient: [COLORS.text, COLORS.muted] }),
|
|
2057
|
+
/* @__PURE__ */ jsxs11(Box9, { borderStyle: "round", borderColor: COLORS.blue, paddingX: SPACING.sm, paddingY: SPACING.none, flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2058
|
+
/* @__PURE__ */ jsxs11(Text11, { children: [
|
|
2059
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_homebrew") }),
|
|
2168
2060
|
" ",
|
|
2169
2061
|
config.HOMEBREW_VERSION
|
|
2170
2062
|
] }),
|
|
2171
|
-
/* @__PURE__ */
|
|
2172
|
-
/* @__PURE__ */
|
|
2063
|
+
/* @__PURE__ */ jsxs11(Text11, { children: [
|
|
2064
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_prefix") }),
|
|
2173
2065
|
" ",
|
|
2174
2066
|
config.HOMEBREW_PREFIX
|
|
2175
2067
|
] }),
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
2068
|
+
/* @__PURE__ */ jsxs11(Text11, { children: [
|
|
2069
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("dashboard_updated") }),
|
|
2178
2070
|
" ",
|
|
2179
2071
|
config.coreUpdated
|
|
2180
2072
|
] })
|
|
2181
2073
|
] })
|
|
2182
2074
|
] }),
|
|
2183
|
-
!errors.outdated && outdated.formulae.length > 0 && /* @__PURE__ */
|
|
2184
|
-
/* @__PURE__ */
|
|
2185
|
-
/* @__PURE__ */
|
|
2186
|
-
outdated.formulae.slice(0, 10).map((pkg) => /* @__PURE__ */
|
|
2187
|
-
/* @__PURE__ */
|
|
2188
|
-
/* @__PURE__ */
|
|
2075
|
+
!errors.outdated && outdated.formulae.length > 0 && /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2076
|
+
/* @__PURE__ */ jsx11(SectionHeader, { emoji: "\u{1F4E6}", title: t("dashboard_outdatedPackages"), gradient: GRADIENTS.fire }),
|
|
2077
|
+
/* @__PURE__ */ jsxs11(Box9, { paddingLeft: SPACING.sm, flexDirection: "column", children: [
|
|
2078
|
+
outdated.formulae.slice(0, 10).map((pkg) => /* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
2079
|
+
/* @__PURE__ */ jsx11(Text11, { color: COLORS.text, children: pkg.name }),
|
|
2080
|
+
/* @__PURE__ */ jsx11(VersionArrow, { current: pkg.installed_versions[0] ?? "", latest: pkg.current_version })
|
|
2189
2081
|
] }, pkg.name)),
|
|
2190
|
-
outdated.formulae.length > 10 && /* @__PURE__ */
|
|
2082
|
+
outdated.formulae.length > 10 && /* @__PURE__ */ jsx11(Text11, { color: COLORS.textSecondary, italic: true, children: t("common_andMore", { count: outdated.formulae.length - 10 }) })
|
|
2191
2083
|
] })
|
|
2192
2084
|
] }),
|
|
2193
|
-
!errors.services && errorServices > 0 && /* @__PURE__ */
|
|
2194
|
-
/* @__PURE__ */
|
|
2195
|
-
/* @__PURE__ */
|
|
2196
|
-
/* @__PURE__ */
|
|
2197
|
-
/* @__PURE__ */
|
|
2198
|
-
s.exit_code != null && /* @__PURE__ */
|
|
2085
|
+
!errors.services && errorServices > 0 && /* @__PURE__ */ jsxs11(Box9, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2086
|
+
/* @__PURE__ */ jsx11(SectionHeader, { emoji: "\u26A0\uFE0F", title: t("dashboard_serviceErrors"), color: COLORS.error }),
|
|
2087
|
+
/* @__PURE__ */ jsx11(Box9, { paddingLeft: SPACING.sm, flexDirection: "column", children: errorServiceList.map((s) => /* @__PURE__ */ jsxs11(Box9, { gap: SPACING.xs, children: [
|
|
2088
|
+
/* @__PURE__ */ jsx11(StatusBadge, { label: t("badge_error"), variant: "error" }),
|
|
2089
|
+
/* @__PURE__ */ jsx11(Text11, { children: s.name }),
|
|
2090
|
+
s.exit_code != null && /* @__PURE__ */ jsx11(Text11, { color: COLORS.muted, children: t("common_exit", { code: s.exit_code }) })
|
|
2199
2091
|
] }, s.name)) })
|
|
2200
2092
|
] }),
|
|
2201
|
-
isPro() && /* @__PURE__ */
|
|
2093
|
+
isPro() && /* @__PURE__ */ jsx11(ProStatusPanel, {})
|
|
2202
2094
|
] });
|
|
2203
2095
|
}
|
|
2204
2096
|
|
|
2205
2097
|
// src/views/installed.tsx
|
|
2206
|
-
import { useState as useState3, useMemo as useMemo3, useEffect as
|
|
2207
|
-
import { Box as
|
|
2098
|
+
import { useState as useState3, useMemo as useMemo3, useEffect as useEffect6 } from "react";
|
|
2099
|
+
import { Box as Box15, Text as Text17, useInput as useInput5, useStdout as useStdout4 } from "ink";
|
|
2208
2100
|
|
|
2209
2101
|
// src/hooks/use-debounce.ts
|
|
2210
|
-
import { useState, useEffect as
|
|
2102
|
+
import { useState, useEffect as useEffect3 } from "react";
|
|
2211
2103
|
function useDebounce(value, delayMs) {
|
|
2212
2104
|
const [debounced, setDebounced] = useState(value);
|
|
2213
|
-
|
|
2105
|
+
useEffect3(() => {
|
|
2214
2106
|
const timer = setTimeout(() => setDebounced(value), delayMs);
|
|
2215
2107
|
return () => clearTimeout(timer);
|
|
2216
2108
|
}, [value, delayMs]);
|
|
@@ -2218,14 +2110,14 @@ function useDebounce(value, delayMs) {
|
|
|
2218
2110
|
}
|
|
2219
2111
|
|
|
2220
2112
|
// src/hooks/use-brew-stream.ts
|
|
2221
|
-
import { useState as useState2, useCallback, useRef, useEffect as
|
|
2113
|
+
import { useState as useState2, useCallback, useRef, useEffect as useEffect4 } from "react";
|
|
2222
2114
|
var MAX_LINES = 100;
|
|
2223
2115
|
async function logToHistory(args, success, error) {
|
|
2224
2116
|
const detected = detectAction(args);
|
|
2225
2117
|
if (!detected) return;
|
|
2226
2118
|
try {
|
|
2227
2119
|
const isPro = useLicenseStore.getState().isPro();
|
|
2228
|
-
const { appendEntry: appendEntry2 } = await import("./history-logger-
|
|
2120
|
+
const { appendEntry: appendEntry2 } = await import("./history-logger-FJ3HZSFU.js");
|
|
2229
2121
|
await appendEntry2(isPro, detected.action, detected.packageName, success, error);
|
|
2230
2122
|
} catch {
|
|
2231
2123
|
}
|
|
@@ -2237,7 +2129,7 @@ function useBrewStream() {
|
|
|
2237
2129
|
const cancelRef = useRef(false);
|
|
2238
2130
|
const generatorRef = useRef(null);
|
|
2239
2131
|
const mountedRef = useRef(true);
|
|
2240
|
-
|
|
2132
|
+
useEffect4(() => {
|
|
2241
2133
|
mountedRef.current = true;
|
|
2242
2134
|
return () => {
|
|
2243
2135
|
mountedRef.current = false;
|
|
@@ -2277,7 +2169,7 @@ function useBrewStream() {
|
|
|
2277
2169
|
}
|
|
2278
2170
|
const MUTATING_COMMANDS = /* @__PURE__ */ new Set(["install", "uninstall", "upgrade", "pin", "unpin", "tap", "untap"]);
|
|
2279
2171
|
if (!cancelRef.current && MUTATING_COMMANDS.has(args[0] ?? "")) {
|
|
2280
|
-
void import("./snapshot-
|
|
2172
|
+
void import("./snapshot-JDRSBMG6.js").then(({ captureSnapshot: captureSnapshot2, saveSnapshot: saveSnapshot2 }) => {
|
|
2281
2173
|
captureSnapshot2().then((s) => saveSnapshot2(s)).catch((err) => logger.warn("snapshot: capture/save failed", { error: String(err) }));
|
|
2282
2174
|
});
|
|
2283
2175
|
}
|
|
@@ -2295,78 +2187,84 @@ function useBrewStream() {
|
|
|
2295
2187
|
}
|
|
2296
2188
|
|
|
2297
2189
|
// src/components/common/search-input.tsx
|
|
2298
|
-
import { Box as
|
|
2190
|
+
import { Box as Box10, Text as Text12 } from "ink";
|
|
2299
2191
|
import { TextInput } from "@inkjs/ui";
|
|
2300
|
-
import { jsx as
|
|
2192
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2301
2193
|
function SearchInput({ defaultValue, onChange, placeholder, isActive = true }) {
|
|
2302
2194
|
const resolvedPlaceholder = placeholder ?? t("searchInput_placeholder");
|
|
2303
|
-
return /* @__PURE__ */
|
|
2304
|
-
/* @__PURE__ */
|
|
2195
|
+
return /* @__PURE__ */ jsxs12(Box10, { children: [
|
|
2196
|
+
/* @__PURE__ */ jsxs12(Text12, { color: COLORS.gold, children: [
|
|
2305
2197
|
"\u{1F50D}",
|
|
2306
2198
|
" "
|
|
2307
2199
|
] }),
|
|
2308
|
-
isActive ? /* @__PURE__ */
|
|
2200
|
+
isActive ? /* @__PURE__ */ jsx12(
|
|
2309
2201
|
TextInput,
|
|
2310
2202
|
{
|
|
2311
2203
|
placeholder: resolvedPlaceholder,
|
|
2312
2204
|
defaultValue,
|
|
2313
2205
|
onChange
|
|
2314
2206
|
}
|
|
2315
|
-
) : /* @__PURE__ */
|
|
2207
|
+
) : /* @__PURE__ */ jsx12(Text12, { color: COLORS.textSecondary, children: defaultValue || placeholder })
|
|
2316
2208
|
] });
|
|
2317
2209
|
}
|
|
2318
2210
|
|
|
2319
2211
|
// src/components/common/confirm-dialog.tsx
|
|
2320
|
-
import { useEffect as
|
|
2321
|
-
import { Box as
|
|
2322
|
-
import { jsx as
|
|
2212
|
+
import { useEffect as useEffect5 } from "react";
|
|
2213
|
+
import { Box as Box11, Text as Text13, useInput as useInput4 } from "ink";
|
|
2214
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2323
2215
|
function ConfirmDialog({ message, onConfirm, onCancel }) {
|
|
2324
2216
|
const locale = useLocaleStore((s) => s.locale);
|
|
2325
2217
|
const { openModal, closeModal } = useModalStore();
|
|
2326
|
-
|
|
2218
|
+
useEffect5(() => {
|
|
2327
2219
|
openModal();
|
|
2328
2220
|
return () => {
|
|
2329
2221
|
closeModal();
|
|
2330
2222
|
};
|
|
2331
2223
|
}, []);
|
|
2332
|
-
|
|
2224
|
+
useInput4((input, key) => {
|
|
2333
2225
|
if (input === "y" || input === "Y") onConfirm();
|
|
2334
2226
|
else if (locale === "es" && (input === "s" || input === "S")) onConfirm();
|
|
2335
2227
|
else if (input === "n" || input === "N") onCancel();
|
|
2336
2228
|
else if (key.escape) onCancel();
|
|
2337
2229
|
});
|
|
2338
|
-
return /* @__PURE__ */
|
|
2339
|
-
/* @__PURE__ */
|
|
2340
|
-
/* @__PURE__ */
|
|
2341
|
-
/* @__PURE__ */
|
|
2342
|
-
/* @__PURE__ */
|
|
2343
|
-
/* @__PURE__ */
|
|
2230
|
+
return /* @__PURE__ */ jsxs13(Box11, { borderStyle: "double", borderColor: COLORS.purple, paddingX: SPACING.sm, paddingY: SPACING.xs, flexDirection: "column", children: [
|
|
2231
|
+
/* @__PURE__ */ jsx13(Text13, { bold: true, color: COLORS.text, children: message }),
|
|
2232
|
+
/* @__PURE__ */ jsxs13(Box11, { marginTop: SPACING.xs, children: [
|
|
2233
|
+
/* @__PURE__ */ jsx13(Text13, { color: COLORS.success, children: t("confirm_yes") }),
|
|
2234
|
+
/* @__PURE__ */ jsx13(Text13, { children: " / " }),
|
|
2235
|
+
/* @__PURE__ */ jsx13(Text13, { color: COLORS.error, children: t("confirm_no") })
|
|
2344
2236
|
] })
|
|
2345
2237
|
] });
|
|
2346
2238
|
}
|
|
2347
2239
|
|
|
2348
2240
|
// src/components/common/progress-log.tsx
|
|
2349
|
-
import { Box as
|
|
2241
|
+
import { Box as Box12, Text as Text14 } from "ink";
|
|
2350
2242
|
import { Spinner as Spinner2 } from "@inkjs/ui";
|
|
2351
|
-
import { jsx as
|
|
2243
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2352
2244
|
function ProgressLog({ lines, isRunning, title, maxVisible = 15 }) {
|
|
2353
|
-
const
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
/* @__PURE__ */
|
|
2245
|
+
const start = Math.max(0, lines.length - maxVisible);
|
|
2246
|
+
const visible = lines.slice(start);
|
|
2247
|
+
return /* @__PURE__ */ jsxs14(Box12, { flexDirection: "column", borderStyle: "round", borderColor: COLORS.sky, paddingX: SPACING.xs, children: [
|
|
2248
|
+
title && /* @__PURE__ */ jsxs14(Box12, { marginBottom: SPACING.xs, children: [
|
|
2249
|
+
isRunning && /* @__PURE__ */ jsx14(Spinner2, { label: "" }),
|
|
2250
|
+
/* @__PURE__ */ jsxs14(Text14, { bold: true, color: COLORS.sky, children: [
|
|
2358
2251
|
" ",
|
|
2359
2252
|
title
|
|
2360
2253
|
] })
|
|
2361
2254
|
] }),
|
|
2362
|
-
visible.map((line, i) =>
|
|
2363
|
-
|
|
2255
|
+
visible.map((line, i) => (
|
|
2256
|
+
// UI-006: keys are absolute indices, so a line that scrolls off-screen
|
|
2257
|
+
// does not change the key of remaining lines. Stable identity prevents
|
|
2258
|
+
// React from treating the whole list as new on every append.
|
|
2259
|
+
/* @__PURE__ */ jsx14(Text14, { color: COLORS.muted, wrap: "wrap", children: line }, `log-${start + i}`)
|
|
2260
|
+
)),
|
|
2261
|
+
lines.length === 0 && !isRunning && /* @__PURE__ */ jsx14(Text14, { color: COLORS.textSecondary, italic: true, children: t("progress_noOutput") })
|
|
2364
2262
|
] });
|
|
2365
2263
|
}
|
|
2366
2264
|
|
|
2367
2265
|
// src/components/common/result-banner.tsx
|
|
2368
|
-
import { Box as
|
|
2369
|
-
import { jsx as
|
|
2266
|
+
import { Box as Box13, Text as Text15 } from "ink";
|
|
2267
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
2370
2268
|
var STATUS_COLORS = {
|
|
2371
2269
|
success: COLORS.success,
|
|
2372
2270
|
error: COLORS.error,
|
|
@@ -2374,21 +2272,21 @@ var STATUS_COLORS = {
|
|
|
2374
2272
|
info: COLORS.info
|
|
2375
2273
|
};
|
|
2376
2274
|
function ResultBanner({ status, message }) {
|
|
2377
|
-
return /* @__PURE__ */
|
|
2275
|
+
return /* @__PURE__ */ jsx15(Box13, { borderStyle: "round", borderColor: STATUS_COLORS[status], paddingX: SPACING.sm, paddingY: SPACING.none, children: /* @__PURE__ */ jsx15(Text15, { color: STATUS_COLORS[status], bold: true, children: message }) });
|
|
2378
2276
|
}
|
|
2379
2277
|
|
|
2380
2278
|
// src/components/common/selectable-row.tsx
|
|
2381
|
-
import { Box as
|
|
2382
|
-
import { jsx as
|
|
2279
|
+
import { Box as Box14, Text as Text16 } from "ink";
|
|
2280
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2383
2281
|
function SelectableRow({ isCurrent, children, gap = 1 }) {
|
|
2384
|
-
return /* @__PURE__ */
|
|
2385
|
-
/* @__PURE__ */
|
|
2282
|
+
return /* @__PURE__ */ jsxs15(Box14, { gap, children: [
|
|
2283
|
+
/* @__PURE__ */ jsx16(Text16, { color: isCurrent ? COLORS.success : COLORS.muted, children: isCurrent ? "\u25B6" : " " }),
|
|
2386
2284
|
children
|
|
2387
2285
|
] });
|
|
2388
2286
|
}
|
|
2389
2287
|
|
|
2390
2288
|
// src/views/installed.tsx
|
|
2391
|
-
import { jsx as
|
|
2289
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2392
2290
|
function InstalledView() {
|
|
2393
2291
|
const formulae = useBrewStore((s) => s.formulae);
|
|
2394
2292
|
const casks = useBrewStore((s) => s.casks);
|
|
@@ -2409,10 +2307,10 @@ function InstalledView() {
|
|
|
2409
2307
|
const cols = stdout?.columns ?? 80;
|
|
2410
2308
|
const nameWidth = Math.floor(cols * 0.35);
|
|
2411
2309
|
const versionWidth = Math.floor(cols * 0.15);
|
|
2412
|
-
|
|
2310
|
+
useEffect6(() => {
|
|
2413
2311
|
fetchInstalled();
|
|
2414
2312
|
}, []);
|
|
2415
|
-
|
|
2313
|
+
useEffect6(() => {
|
|
2416
2314
|
if (isSearching) {
|
|
2417
2315
|
openModal();
|
|
2418
2316
|
return () => {
|
|
@@ -2429,9 +2327,13 @@ function InstalledView() {
|
|
|
2429
2327
|
(p) => p.name.toLowerCase().includes(lower) || p.desc.toLowerCase().includes(lower)
|
|
2430
2328
|
);
|
|
2431
2329
|
}, [formulae, casks, tab, debouncedFilter]);
|
|
2432
|
-
|
|
2433
|
-
if (confirmUninstall
|
|
2434
|
-
if (
|
|
2330
|
+
useInput5((input, key) => {
|
|
2331
|
+
if (confirmUninstall) return;
|
|
2332
|
+
if (stream.isRunning) {
|
|
2333
|
+
if (key.escape) stream.cancel();
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
if (stream.lines.length > 0) {
|
|
2435
2337
|
if (key.escape) {
|
|
2436
2338
|
stream.clear();
|
|
2437
2339
|
void fetchInstalled();
|
|
@@ -2469,11 +2371,11 @@ function InstalledView() {
|
|
|
2469
2371
|
setCursor(0);
|
|
2470
2372
|
}
|
|
2471
2373
|
}, { isActive: true });
|
|
2472
|
-
if (loading.installed) return /* @__PURE__ */
|
|
2473
|
-
if (errors.installed) return /* @__PURE__ */
|
|
2374
|
+
if (loading.installed) return /* @__PURE__ */ jsx17(Loading, { message: t("loading_installed") });
|
|
2375
|
+
if (errors.installed) return /* @__PURE__ */ jsx17(ErrorMessage, { message: errors.installed });
|
|
2474
2376
|
if (stream.isRunning || stream.lines.length > 0) {
|
|
2475
|
-
return /* @__PURE__ */
|
|
2476
|
-
/* @__PURE__ */
|
|
2377
|
+
return /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
|
|
2378
|
+
/* @__PURE__ */ jsx17(
|
|
2477
2379
|
ProgressLog,
|
|
2478
2380
|
{
|
|
2479
2381
|
lines: stream.lines,
|
|
@@ -2481,19 +2383,19 @@ function InstalledView() {
|
|
|
2481
2383
|
title: t("pkgInfo_uninstalling", { name: "..." })
|
|
2482
2384
|
}
|
|
2483
2385
|
),
|
|
2484
|
-
stream.isRunning && /* @__PURE__ */
|
|
2386
|
+
stream.isRunning && /* @__PURE__ */ jsxs16(Text17, { color: COLORS.textSecondary, children: [
|
|
2485
2387
|
"esc:",
|
|
2486
2388
|
t("hint_cancel")
|
|
2487
2389
|
] }),
|
|
2488
|
-
!stream.isRunning && /* @__PURE__ */
|
|
2489
|
-
/* @__PURE__ */
|
|
2390
|
+
!stream.isRunning && /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2391
|
+
/* @__PURE__ */ jsx17(
|
|
2490
2392
|
ResultBanner,
|
|
2491
2393
|
{
|
|
2492
2394
|
status: stream.error ? "error" : "success",
|
|
2493
2395
|
message: stream.error ? `\u2718 ${stream.error}` : `\u2714 ${t("pkgInfo_done")}`
|
|
2494
2396
|
}
|
|
2495
2397
|
),
|
|
2496
|
-
/* @__PURE__ */
|
|
2398
|
+
/* @__PURE__ */ jsxs16(Text17, { color: COLORS.textSecondary, children: [
|
|
2497
2399
|
"esc:",
|
|
2498
2400
|
t("hint_back")
|
|
2499
2401
|
] })
|
|
@@ -2503,28 +2405,28 @@ function InstalledView() {
|
|
|
2503
2405
|
const MAX_VISIBLE_ROWS = Math.max(5, (stdout?.rows ?? 24) - 8);
|
|
2504
2406
|
const start = Math.max(0, cursor - Math.floor(MAX_VISIBLE_ROWS / 2));
|
|
2505
2407
|
const visible = allItems.slice(start, start + MAX_VISIBLE_ROWS);
|
|
2506
|
-
return /* @__PURE__ */
|
|
2507
|
-
/* @__PURE__ */
|
|
2508
|
-
/* @__PURE__ */
|
|
2509
|
-
|
|
2408
|
+
return /* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
|
|
2409
|
+
/* @__PURE__ */ jsxs16(Box15, { marginBottom: SPACING.xs, gap: SPACING.xs, children: [
|
|
2410
|
+
/* @__PURE__ */ jsx17(
|
|
2411
|
+
Box15,
|
|
2510
2412
|
{
|
|
2511
2413
|
borderStyle: "round",
|
|
2512
2414
|
borderColor: tab === "formulae" ? COLORS.info : COLORS.textSecondary,
|
|
2513
|
-
paddingX:
|
|
2514
|
-
children: /* @__PURE__ */
|
|
2415
|
+
paddingX: SPACING.xs,
|
|
2416
|
+
children: /* @__PURE__ */ jsxs16(Text17, { bold: tab === "formulae", color: tab === "formulae" ? COLORS.info : COLORS.textSecondary, children: [
|
|
2515
2417
|
"\u{1F4E6}",
|
|
2516
2418
|
" ",
|
|
2517
2419
|
t("installed_formulaeCount", { count: formulae.length })
|
|
2518
2420
|
] })
|
|
2519
2421
|
}
|
|
2520
2422
|
),
|
|
2521
|
-
/* @__PURE__ */
|
|
2522
|
-
|
|
2423
|
+
/* @__PURE__ */ jsx17(
|
|
2424
|
+
Box15,
|
|
2523
2425
|
{
|
|
2524
2426
|
borderStyle: "round",
|
|
2525
2427
|
borderColor: tab === "casks" ? COLORS.purple : COLORS.textSecondary,
|
|
2526
|
-
paddingX:
|
|
2527
|
-
children: /* @__PURE__ */
|
|
2428
|
+
paddingX: SPACING.xs,
|
|
2429
|
+
children: /* @__PURE__ */ jsxs16(Text17, { bold: tab === "casks", color: tab === "casks" ? COLORS.purple : COLORS.textSecondary, children: [
|
|
2528
2430
|
"\u{1F37A}",
|
|
2529
2431
|
" ",
|
|
2530
2432
|
t("installed_casksCount", { count: casks.length })
|
|
@@ -2532,7 +2434,7 @@ function InstalledView() {
|
|
|
2532
2434
|
}
|
|
2533
2435
|
)
|
|
2534
2436
|
] }),
|
|
2535
|
-
confirmUninstall && /* @__PURE__ */
|
|
2437
|
+
confirmUninstall && /* @__PURE__ */ jsx17(
|
|
2536
2438
|
ConfirmDialog,
|
|
2537
2439
|
{
|
|
2538
2440
|
message: t("installed_confirmUninstall", { name: confirmUninstall }),
|
|
@@ -2546,48 +2448,48 @@ function InstalledView() {
|
|
|
2546
2448
|
onCancel: () => setConfirmUninstall(null)
|
|
2547
2449
|
}
|
|
2548
2450
|
),
|
|
2549
|
-
isSearching && /* @__PURE__ */
|
|
2550
|
-
/* @__PURE__ */
|
|
2551
|
-
/* @__PURE__ */
|
|
2451
|
+
isSearching && /* @__PURE__ */ jsx17(Box15, { marginBottom: SPACING.xs, borderStyle: "round", borderColor: COLORS.gold, paddingX: SPACING.xs, children: /* @__PURE__ */ jsx17(SearchInput, { defaultValue: filter, onChange: setFilter, isActive: isSearching }) }),
|
|
2452
|
+
/* @__PURE__ */ jsxs16(Box15, { gap: SPACING.xs, borderStyle: "single", borderBottom: true, borderTop: false, borderLeft: false, borderRight: false, borderColor: COLORS.border, children: [
|
|
2453
|
+
/* @__PURE__ */ jsxs16(Text17, { color: COLORS.text, bold: true, children: [
|
|
2552
2454
|
" ",
|
|
2553
2455
|
t("installed_col_package").padEnd(nameWidth)
|
|
2554
2456
|
] }),
|
|
2555
|
-
/* @__PURE__ */
|
|
2556
|
-
/* @__PURE__ */
|
|
2457
|
+
/* @__PURE__ */ jsx17(Text17, { color: COLORS.text, bold: true, children: t("installed_col_version").padEnd(versionWidth) }),
|
|
2458
|
+
/* @__PURE__ */ jsx17(Text17, { color: COLORS.text, bold: true, children: t("installed_col_status") })
|
|
2557
2459
|
] }),
|
|
2558
|
-
/* @__PURE__ */
|
|
2559
|
-
visible.length === 0 && /* @__PURE__ */
|
|
2560
|
-
start > 0 && /* @__PURE__ */
|
|
2460
|
+
/* @__PURE__ */ jsxs16(Box15, { flexDirection: "column", children: [
|
|
2461
|
+
visible.length === 0 && /* @__PURE__ */ jsx17(Box15, { paddingY: SPACING.xs, justifyContent: "center", children: /* @__PURE__ */ jsx17(Text17, { color: COLORS.textSecondary, italic: true, children: t("installed_noPackages") }) }),
|
|
2462
|
+
start > 0 && /* @__PURE__ */ jsxs16(Text17, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
2561
2463
|
" ",
|
|
2562
2464
|
t("scroll_moreAbove", { count: start })
|
|
2563
2465
|
] }),
|
|
2564
2466
|
visible.map((item, i) => {
|
|
2565
2467
|
const idx = start + i;
|
|
2566
2468
|
const isCurrent = idx === cursor;
|
|
2567
|
-
return /* @__PURE__ */
|
|
2568
|
-
/* @__PURE__ */
|
|
2569
|
-
/* @__PURE__ */
|
|
2570
|
-
item.outdated && /* @__PURE__ */
|
|
2571
|
-
item.pinned && /* @__PURE__ */
|
|
2572
|
-
item.kegOnly && /* @__PURE__ */
|
|
2573
|
-
item.installedAsDependency && /* @__PURE__ */
|
|
2574
|
-
!item.outdated && !item.pinned && !item.kegOnly && !item.installedAsDependency && /* @__PURE__ */
|
|
2469
|
+
return /* @__PURE__ */ jsxs16(SelectableRow, { isCurrent, children: [
|
|
2470
|
+
/* @__PURE__ */ jsx17(Text17, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: truncate(item.name, nameWidth).padEnd(nameWidth) }),
|
|
2471
|
+
/* @__PURE__ */ jsx17(Text17, { color: COLORS.teal, children: item.version.padEnd(versionWidth) }),
|
|
2472
|
+
item.outdated && /* @__PURE__ */ jsx17(StatusBadge, { label: t("badge_outdated"), variant: "warning" }),
|
|
2473
|
+
item.pinned && /* @__PURE__ */ jsx17(StatusBadge, { label: t("badge_pinned"), variant: "info" }),
|
|
2474
|
+
item.kegOnly && /* @__PURE__ */ jsx17(StatusBadge, { label: t("badge_kegOnly"), variant: "muted" }),
|
|
2475
|
+
item.installedAsDependency && /* @__PURE__ */ jsx17(StatusBadge, { label: t("badge_dep"), variant: "muted" }),
|
|
2476
|
+
!item.outdated && !item.pinned && !item.kegOnly && !item.installedAsDependency && /* @__PURE__ */ jsx17(Text17, { color: COLORS.textSecondary, dimColor: true, children: truncate(item.desc, 30) })
|
|
2575
2477
|
] }, item.name);
|
|
2576
2478
|
}),
|
|
2577
|
-
start + MAX_VISIBLE_ROWS < allItems.length && /* @__PURE__ */
|
|
2479
|
+
start + MAX_VISIBLE_ROWS < allItems.length && /* @__PURE__ */ jsxs16(Text17, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
2578
2480
|
" ",
|
|
2579
2481
|
t("scroll_moreBelow", { count: allItems.length - start - MAX_VISIBLE_ROWS })
|
|
2580
2482
|
] })
|
|
2581
2483
|
] }),
|
|
2582
|
-
/* @__PURE__ */
|
|
2484
|
+
/* @__PURE__ */ jsx17(Box15, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx17(Text17, { color: COLORS.text, bold: true, children: allItems.length > 0 ? `${cursor + 1}/${allItems.length}` : "0/0" }) })
|
|
2583
2485
|
] });
|
|
2584
2486
|
}
|
|
2585
2487
|
|
|
2586
2488
|
// src/views/search.tsx
|
|
2587
|
-
import { useState as useState4, useCallback as useCallback2, useEffect as
|
|
2588
|
-
import { Box as
|
|
2489
|
+
import { useState as useState4, useCallback as useCallback2, useEffect as useEffect7, useRef as useRef2 } from "react";
|
|
2490
|
+
import { Box as Box16, Text as Text18, useInput as useInput6 } from "ink";
|
|
2589
2491
|
import { TextInput as TextInput2 } from "@inkjs/ui";
|
|
2590
|
-
import { jsx as
|
|
2492
|
+
import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2591
2493
|
function SearchView() {
|
|
2592
2494
|
const [query, setQuery] = useState4("");
|
|
2593
2495
|
const [results, setResults] = useState4(null);
|
|
@@ -2601,7 +2503,7 @@ function SearchView() {
|
|
|
2601
2503
|
const selectPackage = useNavigationStore((s) => s.selectPackage);
|
|
2602
2504
|
const fetchInstalled = useBrewStore((s) => s.fetchInstalled);
|
|
2603
2505
|
const hasRefreshed = useRef2(false);
|
|
2604
|
-
|
|
2506
|
+
useEffect7(() => {
|
|
2605
2507
|
if (results !== null) {
|
|
2606
2508
|
openModal();
|
|
2607
2509
|
return () => {
|
|
@@ -2629,7 +2531,7 @@ function SearchView() {
|
|
|
2629
2531
|
setSearching(false);
|
|
2630
2532
|
}
|
|
2631
2533
|
}, []);
|
|
2632
|
-
|
|
2534
|
+
useEffect7(() => {
|
|
2633
2535
|
if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current) {
|
|
2634
2536
|
hasRefreshed.current = true;
|
|
2635
2537
|
void fetchInstalled();
|
|
@@ -2639,7 +2541,7 @@ function SearchView() {
|
|
|
2639
2541
|
const visibleFormulae = results ? results.formulae.slice(0, MAX_VISIBLE) : [];
|
|
2640
2542
|
const visibleCasks = results ? results.casks.slice(0, MAX_VISIBLE) : [];
|
|
2641
2543
|
const allVisible = [...visibleFormulae, ...visibleCasks];
|
|
2642
|
-
|
|
2544
|
+
useInput6((input, key) => {
|
|
2643
2545
|
if (stream.isRunning) {
|
|
2644
2546
|
if (key.escape) stream.cancel();
|
|
2645
2547
|
return;
|
|
@@ -2674,8 +2576,8 @@ function SearchView() {
|
|
|
2674
2576
|
}
|
|
2675
2577
|
});
|
|
2676
2578
|
if (stream.isRunning || stream.lines.length > 0) {
|
|
2677
|
-
return /* @__PURE__ */
|
|
2678
|
-
/* @__PURE__ */
|
|
2579
|
+
return /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
2580
|
+
/* @__PURE__ */ jsx18(
|
|
2679
2581
|
ProgressLog,
|
|
2680
2582
|
{
|
|
2681
2583
|
lines: stream.lines,
|
|
@@ -2683,32 +2585,32 @@ function SearchView() {
|
|
|
2683
2585
|
title: t("search_installing")
|
|
2684
2586
|
}
|
|
2685
2587
|
),
|
|
2686
|
-
stream.isRunning && /* @__PURE__ */
|
|
2588
|
+
stream.isRunning && /* @__PURE__ */ jsxs17(Text18, { color: COLORS.textSecondary, children: [
|
|
2687
2589
|
"esc:",
|
|
2688
2590
|
t("hint_cancel")
|
|
2689
2591
|
] }),
|
|
2690
|
-
!stream.isRunning && /* @__PURE__ */
|
|
2691
|
-
/* @__PURE__ */
|
|
2592
|
+
!stream.isRunning && /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2593
|
+
/* @__PURE__ */ jsx18(
|
|
2692
2594
|
ResultBanner,
|
|
2693
2595
|
{
|
|
2694
2596
|
status: stream.error ? "error" : "success",
|
|
2695
2597
|
message: stream.error ? `\u2718 ${stream.error}` : `\u2714 ${t("search_installComplete")}`
|
|
2696
2598
|
}
|
|
2697
2599
|
),
|
|
2698
|
-
/* @__PURE__ */
|
|
2600
|
+
/* @__PURE__ */ jsxs17(Text18, { color: COLORS.textSecondary, children: [
|
|
2699
2601
|
"esc:",
|
|
2700
2602
|
t("hint_clear")
|
|
2701
2603
|
] })
|
|
2702
2604
|
] })
|
|
2703
2605
|
] });
|
|
2704
2606
|
}
|
|
2705
|
-
return /* @__PURE__ */
|
|
2706
|
-
/* @__PURE__ */
|
|
2707
|
-
/* @__PURE__ */
|
|
2607
|
+
return /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
2608
|
+
/* @__PURE__ */ jsxs17(Box16, { marginBottom: SPACING.xs, children: [
|
|
2609
|
+
/* @__PURE__ */ jsxs17(Text18, { color: COLORS.gold, children: [
|
|
2708
2610
|
"\u{1F50D}",
|
|
2709
2611
|
" "
|
|
2710
2612
|
] }),
|
|
2711
|
-
!results ? /* @__PURE__ */
|
|
2613
|
+
!results ? /* @__PURE__ */ jsx18(
|
|
2712
2614
|
TextInput2,
|
|
2713
2615
|
{
|
|
2714
2616
|
placeholder: t("search_placeholder"),
|
|
@@ -2716,17 +2618,17 @@ function SearchView() {
|
|
|
2716
2618
|
onChange: setQuery,
|
|
2717
2619
|
onSubmit: () => void doSearch(query)
|
|
2718
2620
|
}
|
|
2719
|
-
) : /* @__PURE__ */
|
|
2621
|
+
) : /* @__PURE__ */ jsxs17(Text18, { children: [
|
|
2720
2622
|
t("search_resultsFor"),
|
|
2721
2623
|
' "',
|
|
2722
|
-
/* @__PURE__ */
|
|
2624
|
+
/* @__PURE__ */ jsx18(Text18, { bold: true, color: COLORS.text, children: query }),
|
|
2723
2625
|
'" ',
|
|
2724
|
-
/* @__PURE__ */
|
|
2626
|
+
/* @__PURE__ */ jsx18(Text18, { color: COLORS.textSecondary, children: t("search_escToClear") })
|
|
2725
2627
|
] })
|
|
2726
2628
|
] }),
|
|
2727
|
-
searching && /* @__PURE__ */
|
|
2728
|
-
searchError && /* @__PURE__ */
|
|
2729
|
-
confirmInstall && /* @__PURE__ */
|
|
2629
|
+
searching && /* @__PURE__ */ jsx18(Loading, { message: t("loading_searching") }),
|
|
2630
|
+
searchError && /* @__PURE__ */ jsx18(Box16, { marginBottom: SPACING.xs, children: /* @__PURE__ */ jsx18(Text18, { color: COLORS.error, children: searchError }) }),
|
|
2631
|
+
confirmInstall && /* @__PURE__ */ jsx18(
|
|
2730
2632
|
ConfirmDialog,
|
|
2731
2633
|
{
|
|
2732
2634
|
message: t("search_confirmInstall", { name: confirmInstall }),
|
|
@@ -2739,59 +2641,59 @@ function SearchView() {
|
|
|
2739
2641
|
onCancel: () => setConfirmInstall(null)
|
|
2740
2642
|
}
|
|
2741
2643
|
),
|
|
2742
|
-
results && !searching && !confirmInstall && /* @__PURE__ */
|
|
2743
|
-
visibleFormulae.length > 0 && /* @__PURE__ */
|
|
2744
|
-
/* @__PURE__ */
|
|
2644
|
+
results && !searching && !confirmInstall && /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
2645
|
+
visibleFormulae.length > 0 && /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", marginBottom: SPACING.xs, children: [
|
|
2646
|
+
/* @__PURE__ */ jsx18(Text18, { bold: true, color: COLORS.info, children: t("search_formulaeHeader", { count: results.formulae.length }) }),
|
|
2745
2647
|
visibleFormulae.map((name, i) => {
|
|
2746
2648
|
const isCurrent = i === cursor;
|
|
2747
|
-
return /* @__PURE__ */
|
|
2649
|
+
return /* @__PURE__ */ jsx18(SelectableRow, { isCurrent, children: /* @__PURE__ */ jsx18(Text18, { bold: isCurrent, inverse: isCurrent, children: name }) }, name);
|
|
2748
2650
|
}),
|
|
2749
|
-
results.formulae.length > MAX_VISIBLE && /* @__PURE__ */
|
|
2651
|
+
results.formulae.length > MAX_VISIBLE && /* @__PURE__ */ jsxs17(Text18, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
2750
2652
|
" ",
|
|
2751
2653
|
t("scroll_moreBelow", { count: results.formulae.length - MAX_VISIBLE })
|
|
2752
2654
|
] })
|
|
2753
2655
|
] }),
|
|
2754
|
-
visibleCasks.length > 0 && /* @__PURE__ */
|
|
2755
|
-
/* @__PURE__ */
|
|
2656
|
+
visibleCasks.length > 0 && /* @__PURE__ */ jsxs17(Box16, { flexDirection: "column", children: [
|
|
2657
|
+
/* @__PURE__ */ jsx18(Text18, { bold: true, color: COLORS.purple, children: t("search_casksHeader", { count: results.casks.length }) }),
|
|
2756
2658
|
visibleCasks.map((name, i) => {
|
|
2757
2659
|
const idx = visibleFormulae.length + i;
|
|
2758
2660
|
const isCurrent = idx === cursor;
|
|
2759
|
-
return /* @__PURE__ */
|
|
2661
|
+
return /* @__PURE__ */ jsx18(SelectableRow, { isCurrent, children: /* @__PURE__ */ jsx18(Text18, { bold: isCurrent, inverse: isCurrent, children: name }) }, name);
|
|
2760
2662
|
}),
|
|
2761
|
-
results.casks.length > MAX_VISIBLE && /* @__PURE__ */
|
|
2663
|
+
results.casks.length > MAX_VISIBLE && /* @__PURE__ */ jsxs17(Text18, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
2762
2664
|
" ",
|
|
2763
2665
|
t("scroll_moreBelow", { count: results.casks.length - MAX_VISIBLE })
|
|
2764
2666
|
] })
|
|
2765
2667
|
] }),
|
|
2766
|
-
allVisible.length === 0 && /* @__PURE__ */
|
|
2767
|
-
/* @__PURE__ */
|
|
2668
|
+
allVisible.length === 0 && /* @__PURE__ */ jsx18(Box16, { borderStyle: "round", borderColor: COLORS.textSecondary, paddingX: SPACING.sm, children: /* @__PURE__ */ jsx18(Text18, { color: COLORS.textSecondary, italic: true, children: t("search_noResults") }) }),
|
|
2669
|
+
/* @__PURE__ */ jsx18(Box16, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx18(Text18, { color: COLORS.text, bold: true, children: allVisible.length > 0 ? `${cursor + 1}/${allVisible.length}` : "" }) })
|
|
2768
2670
|
] })
|
|
2769
2671
|
] });
|
|
2770
2672
|
}
|
|
2771
2673
|
|
|
2772
2674
|
// src/views/outdated.tsx
|
|
2773
|
-
import { useEffect as
|
|
2774
|
-
import { Box as
|
|
2775
|
-
import { jsx as
|
|
2675
|
+
import { useEffect as useEffect8, useMemo as useMemo4, useRef as useRef3, useState as useState5 } from "react";
|
|
2676
|
+
import { Box as Box17, Text as Text19, useInput as useInput7, useStdout as useStdout5 } from "ink";
|
|
2677
|
+
import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2776
2678
|
function ImpactPanel({ impact }) {
|
|
2777
2679
|
const riskColor = impact.risk === "high" ? COLORS.error : impact.risk === "medium" ? COLORS.warning : COLORS.success;
|
|
2778
2680
|
const riskLabel = impact.risk === "high" ? t("impact_high") : impact.risk === "medium" ? t("impact_medium") : t("impact_low");
|
|
2779
2681
|
const riskIcon = impact.risk === "high" ? "\u26A0" : impact.risk === "medium" ? "~" : "\u2713";
|
|
2780
|
-
return /* @__PURE__ */
|
|
2781
|
-
/* @__PURE__ */
|
|
2782
|
-
/* @__PURE__ */
|
|
2682
|
+
return /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", marginTop: SPACING.xs, borderStyle: "round", borderColor: riskColor, paddingX: SPACING.sm, paddingY: SPACING.none, children: [
|
|
2683
|
+
/* @__PURE__ */ jsxs18(Box17, { children: [
|
|
2684
|
+
/* @__PURE__ */ jsxs18(Text19, { bold: true, color: riskColor, children: [
|
|
2783
2685
|
riskIcon,
|
|
2784
2686
|
" ",
|
|
2785
2687
|
riskLabel
|
|
2786
2688
|
] }),
|
|
2787
|
-
impact.reverseDeps.length > 0 && /* @__PURE__ */
|
|
2689
|
+
impact.reverseDeps.length > 0 && /* @__PURE__ */ jsxs18(Text19, { color: COLORS.textSecondary, children: [
|
|
2788
2690
|
" \\u2014 ",
|
|
2789
2691
|
t("impact_affects", { count: impact.reverseDeps.length })
|
|
2790
2692
|
] })
|
|
2791
2693
|
] }),
|
|
2792
|
-
impact.riskReasons.length > 0 && /* @__PURE__ */
|
|
2793
|
-
impact.reverseDeps.length > 0 && impact.reverseDeps.length <= 5 && /* @__PURE__ */
|
|
2794
|
-
impact.risk === "high" && /* @__PURE__ */
|
|
2694
|
+
impact.riskReasons.length > 0 && /* @__PURE__ */ jsx19(Text19, { color: COLORS.textSecondary, children: impact.riskReasons.join(" \xB7 ") }),
|
|
2695
|
+
impact.reverseDeps.length > 0 && impact.reverseDeps.length <= 5 && /* @__PURE__ */ jsx19(Text19, { color: COLORS.muted, dimColor: true, children: t("impact_usedBy", { packages: impact.reverseDeps.join(", ") }) }),
|
|
2696
|
+
impact.risk === "high" && /* @__PURE__ */ jsx19(Text19, { color: COLORS.info, children: t("impact_brewfile_hint") })
|
|
2795
2697
|
] });
|
|
2796
2698
|
}
|
|
2797
2699
|
function OutdatedView() {
|
|
@@ -2802,35 +2704,48 @@ function OutdatedView() {
|
|
|
2802
2704
|
const hasRefreshed = useRef3(false);
|
|
2803
2705
|
const [impact, setImpact] = useState5(null);
|
|
2804
2706
|
const [impactLoading, setImpactLoading] = useState5(false);
|
|
2805
|
-
|
|
2707
|
+
useEffect8(() => {
|
|
2806
2708
|
fetchOutdated();
|
|
2807
2709
|
}, []);
|
|
2808
|
-
|
|
2710
|
+
useEffect8(() => {
|
|
2809
2711
|
if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current) {
|
|
2810
2712
|
hasRefreshed.current = true;
|
|
2811
2713
|
void fetchOutdated();
|
|
2812
2714
|
}
|
|
2813
2715
|
}, [stream.isRunning, stream.error]);
|
|
2814
|
-
const allOutdated =
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2716
|
+
const allOutdated = useMemo4(
|
|
2717
|
+
() => [
|
|
2718
|
+
...outdated.formulae.map((p) => ({ ...p, type: "formula" })),
|
|
2719
|
+
...outdated.casks.map((p) => ({ ...p, type: "cask" }))
|
|
2720
|
+
],
|
|
2721
|
+
[outdated.formulae, outdated.casks]
|
|
2722
|
+
);
|
|
2818
2723
|
const debouncedCursor = useDebounce(cursor, 150);
|
|
2819
|
-
|
|
2724
|
+
useEffect8(() => {
|
|
2820
2725
|
const pkg = allOutdated[debouncedCursor];
|
|
2821
2726
|
if (!pkg || stream.isRunning) {
|
|
2822
2727
|
setImpact(null);
|
|
2823
2728
|
return;
|
|
2824
2729
|
}
|
|
2730
|
+
let cancelled = false;
|
|
2825
2731
|
setImpactLoading(true);
|
|
2826
2732
|
void getUpgradeImpact(
|
|
2827
2733
|
pkg.name,
|
|
2828
2734
|
pkg.installed_versions[0] ?? "",
|
|
2829
2735
|
pkg.current_version,
|
|
2830
2736
|
pkg.type
|
|
2831
|
-
).then(
|
|
2737
|
+
).then((result) => {
|
|
2738
|
+
if (!cancelled) setImpact(result);
|
|
2739
|
+
}).catch(() => {
|
|
2740
|
+
if (!cancelled) setImpact(null);
|
|
2741
|
+
}).finally(() => {
|
|
2742
|
+
if (!cancelled) setImpactLoading(false);
|
|
2743
|
+
});
|
|
2744
|
+
return () => {
|
|
2745
|
+
cancelled = true;
|
|
2746
|
+
};
|
|
2832
2747
|
}, [debouncedCursor, stream.isRunning]);
|
|
2833
|
-
|
|
2748
|
+
useInput7((input, key) => {
|
|
2834
2749
|
if (stream.isRunning) {
|
|
2835
2750
|
if (key.escape) stream.cancel();
|
|
2836
2751
|
return;
|
|
@@ -2867,11 +2782,11 @@ function OutdatedView() {
|
|
|
2867
2782
|
const MAX_VISIBLE_ROWS = Math.max(5, (stdout?.rows ?? 24) - 8);
|
|
2868
2783
|
const start = Math.max(0, cursor - Math.floor(MAX_VISIBLE_ROWS / 2));
|
|
2869
2784
|
const visible = allOutdated.slice(start, start + MAX_VISIBLE_ROWS);
|
|
2870
|
-
if (loading.outdated) return /* @__PURE__ */
|
|
2871
|
-
if (errors.outdated) return /* @__PURE__ */
|
|
2785
|
+
if (loading.outdated) return /* @__PURE__ */ jsx19(Loading, { message: t("loading_outdated") });
|
|
2786
|
+
if (errors.outdated) return /* @__PURE__ */ jsx19(ErrorMessage, { message: errors.outdated });
|
|
2872
2787
|
if (stream.isRunning || stream.lines.length > 0) {
|
|
2873
|
-
return /* @__PURE__ */
|
|
2874
|
-
/* @__PURE__ */
|
|
2788
|
+
return /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", children: [
|
|
2789
|
+
/* @__PURE__ */ jsx19(
|
|
2875
2790
|
ProgressLog,
|
|
2876
2791
|
{
|
|
2877
2792
|
lines: stream.lines,
|
|
@@ -2879,19 +2794,19 @@ function OutdatedView() {
|
|
|
2879
2794
|
title: t("outdated_upgrading")
|
|
2880
2795
|
}
|
|
2881
2796
|
),
|
|
2882
|
-
stream.isRunning && /* @__PURE__ */
|
|
2797
|
+
stream.isRunning && /* @__PURE__ */ jsxs18(Text19, { color: COLORS.textSecondary, children: [
|
|
2883
2798
|
"esc:",
|
|
2884
2799
|
t("hint_cancel")
|
|
2885
2800
|
] }),
|
|
2886
|
-
!stream.isRunning && /* @__PURE__ */
|
|
2887
|
-
/* @__PURE__ */
|
|
2888
|
-
/* @__PURE__ */
|
|
2889
|
-
/* @__PURE__ */
|
|
2801
|
+
!stream.isRunning && /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2802
|
+
/* @__PURE__ */ jsxs18(Box17, { borderStyle: "round", borderColor: stream.error ? COLORS.error : COLORS.success, paddingX: SPACING.sm, paddingY: SPACING.none, children: [
|
|
2803
|
+
/* @__PURE__ */ jsx19(Text19, { color: stream.error ? COLORS.error : COLORS.success, bold: true, children: stream.error ? `\u2718 ${stream.error}` : `\u2714 ${t("outdated_upgradeComplete")}` }),
|
|
2804
|
+
/* @__PURE__ */ jsxs18(Text19, { color: COLORS.muted, children: [
|
|
2890
2805
|
" ",
|
|
2891
2806
|
t("outdated_pressRefresh")
|
|
2892
2807
|
] })
|
|
2893
2808
|
] }),
|
|
2894
|
-
/* @__PURE__ */
|
|
2809
|
+
/* @__PURE__ */ jsxs18(Text19, { color: COLORS.textSecondary, children: [
|
|
2895
2810
|
"r:",
|
|
2896
2811
|
t("hint_refresh"),
|
|
2897
2812
|
" esc:",
|
|
@@ -2902,9 +2817,9 @@ function OutdatedView() {
|
|
|
2902
2817
|
}
|
|
2903
2818
|
const upgradeAllMessage = confirmAction?.type === "all" ? `${t("outdated_confirmAll", { count: allOutdated.length })}
|
|
2904
2819
|
${t("outdated_upgradeAllList", { list: allOutdated.map((p) => p.name).join(", ") })}` : "";
|
|
2905
|
-
return /* @__PURE__ */
|
|
2906
|
-
/* @__PURE__ */
|
|
2907
|
-
confirmAction && /* @__PURE__ */
|
|
2820
|
+
return /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", children: [
|
|
2821
|
+
/* @__PURE__ */ jsx19(SectionHeader, { emoji: "\u{1F4E6}", title: t("outdated_title", { count: allOutdated.length }), gradient: GRADIENTS.fire }),
|
|
2822
|
+
confirmAction && /* @__PURE__ */ jsx19(Box17, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx19(
|
|
2908
2823
|
ConfirmDialog,
|
|
2909
2824
|
{
|
|
2910
2825
|
message: confirmAction.type === "all" ? upgradeAllMessage : t("outdated_confirmSingle", { name: confirmAction.type === "single" ? confirmAction.name : "" }),
|
|
@@ -2920,41 +2835,41 @@ ${t("outdated_upgradeAllList", { list: allOutdated.map((p) => p.name).join(", ")
|
|
|
2920
2835
|
onCancel: () => setConfirmAction(null)
|
|
2921
2836
|
}
|
|
2922
2837
|
) }),
|
|
2923
|
-
allOutdated.length === 0 && !confirmAction && /* @__PURE__ */
|
|
2924
|
-
allOutdated.length > 0 && !confirmAction && /* @__PURE__ */
|
|
2925
|
-
start > 0 && /* @__PURE__ */
|
|
2838
|
+
allOutdated.length === 0 && !confirmAction && /* @__PURE__ */ jsx19(Box17, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx19(ResultBanner, { status: "success", message: `\u2714 ${t("outdated_upToDate")}` }) }),
|
|
2839
|
+
allOutdated.length > 0 && !confirmAction && /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
2840
|
+
start > 0 && /* @__PURE__ */ jsxs18(Text19, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
2926
2841
|
" ",
|
|
2927
2842
|
t("scroll_moreAbove", { count: start })
|
|
2928
2843
|
] }),
|
|
2929
2844
|
visible.map((pkg, i) => {
|
|
2930
2845
|
const idx = start + i;
|
|
2931
2846
|
const isCurrent = idx === cursor;
|
|
2932
|
-
return /* @__PURE__ */
|
|
2933
|
-
/* @__PURE__ */
|
|
2934
|
-
/* @__PURE__ */
|
|
2935
|
-
pkg.pinned && /* @__PURE__ */
|
|
2847
|
+
return /* @__PURE__ */ jsxs18(SelectableRow, { isCurrent, children: [
|
|
2848
|
+
/* @__PURE__ */ jsx19(Text19, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: pkg.name }),
|
|
2849
|
+
/* @__PURE__ */ jsx19(VersionArrow, { current: pkg.installed_versions[0] ?? "", latest: pkg.current_version }),
|
|
2850
|
+
pkg.pinned && /* @__PURE__ */ jsx19(StatusBadge, { label: t("outdated_pinned"), variant: "info" })
|
|
2936
2851
|
] }, pkg.name);
|
|
2937
2852
|
}),
|
|
2938
|
-
start + MAX_VISIBLE_ROWS < allOutdated.length && /* @__PURE__ */
|
|
2853
|
+
start + MAX_VISIBLE_ROWS < allOutdated.length && /* @__PURE__ */ jsxs18(Text19, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
2939
2854
|
" ",
|
|
2940
2855
|
t("scroll_moreBelow", { count: allOutdated.length - start - MAX_VISIBLE_ROWS })
|
|
2941
2856
|
] }),
|
|
2942
|
-
/* @__PURE__ */
|
|
2857
|
+
/* @__PURE__ */ jsx19(Box17, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs18(Text19, { color: COLORS.text, bold: true, children: [
|
|
2943
2858
|
cursor + 1,
|
|
2944
2859
|
"/",
|
|
2945
2860
|
allOutdated.length
|
|
2946
2861
|
] }) }),
|
|
2947
|
-
impact && !stream.isRunning && !confirmAction && /* @__PURE__ */
|
|
2948
|
-
impactLoading && !stream.isRunning && !confirmAction && /* @__PURE__ */
|
|
2949
|
-
/* @__PURE__ */
|
|
2862
|
+
impact && !stream.isRunning && !confirmAction && /* @__PURE__ */ jsx19(ImpactPanel, { impact }),
|
|
2863
|
+
impactLoading && !stream.isRunning && !confirmAction && /* @__PURE__ */ jsx19(Box17, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.textSecondary, children: t("impact_analyzing") }) }),
|
|
2864
|
+
/* @__PURE__ */ jsx19(Box17, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx19(Text19, { color: COLORS.textSecondary, children: t("impact_hint") }) })
|
|
2950
2865
|
] })
|
|
2951
2866
|
] });
|
|
2952
2867
|
}
|
|
2953
2868
|
|
|
2954
2869
|
// src/views/package-info.tsx
|
|
2955
|
-
import { useEffect as
|
|
2956
|
-
import { Box as
|
|
2957
|
-
import { Fragment as Fragment4, jsx as
|
|
2870
|
+
import { useEffect as useEffect9, useRef as useRef4, useState as useState6 } from "react";
|
|
2871
|
+
import { Box as Box18, Text as Text20, useInput as useInput8 } from "ink";
|
|
2872
|
+
import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2958
2873
|
var ACTION_PROGRESS_KEYS = {
|
|
2959
2874
|
install: "pkgInfo_installing",
|
|
2960
2875
|
uninstall: "pkgInfo_uninstalling",
|
|
@@ -2976,47 +2891,20 @@ function PackageInfoView() {
|
|
|
2976
2891
|
const mountedRef = useRef4(true);
|
|
2977
2892
|
const hasRefreshed = useRef4(false);
|
|
2978
2893
|
const stream = useBrewStream();
|
|
2979
|
-
|
|
2894
|
+
useEffect9(() => {
|
|
2980
2895
|
mountedRef.current = true;
|
|
2981
2896
|
return () => {
|
|
2982
2897
|
mountedRef.current = false;
|
|
2983
2898
|
};
|
|
2984
2899
|
}, []);
|
|
2985
|
-
|
|
2900
|
+
useEffect9(() => {
|
|
2986
2901
|
if (!packageName) return;
|
|
2987
2902
|
setLoading2(true);
|
|
2988
2903
|
const fetchInfo = async () => {
|
|
2989
2904
|
if (packageType === "cask") {
|
|
2990
2905
|
const caskInfo = await getCaskInfo(packageName);
|
|
2991
2906
|
if (caskInfo && mountedRef.current) {
|
|
2992
|
-
|
|
2993
|
-
name: caskInfo.token,
|
|
2994
|
-
full_name: caskInfo.full_token,
|
|
2995
|
-
tap: "",
|
|
2996
|
-
desc: caskInfo.desc,
|
|
2997
|
-
license: "",
|
|
2998
|
-
homepage: caskInfo.homepage,
|
|
2999
|
-
versions: { stable: caskInfo.version, head: null, bottle: false },
|
|
3000
|
-
dependencies: [],
|
|
3001
|
-
build_dependencies: [],
|
|
3002
|
-
installed: caskInfo.installed ? [{
|
|
3003
|
-
version: caskInfo.installed,
|
|
3004
|
-
used_options: [],
|
|
3005
|
-
built_as_bottle: false,
|
|
3006
|
-
poured_from_bottle: false,
|
|
3007
|
-
time: caskInfo.installed_time ?? 0,
|
|
3008
|
-
runtime_dependencies: [],
|
|
3009
|
-
installed_as_dependency: false,
|
|
3010
|
-
installed_on_request: true
|
|
3011
|
-
}] : [],
|
|
3012
|
-
linked_keg: null,
|
|
3013
|
-
pinned: false,
|
|
3014
|
-
outdated: caskInfo.outdated,
|
|
3015
|
-
deprecated: false,
|
|
3016
|
-
keg_only: false,
|
|
3017
|
-
caveats: null
|
|
3018
|
-
};
|
|
3019
|
-
setFormula(formulaLike);
|
|
2907
|
+
setFormula(formulaeFromCask(caskInfo));
|
|
3020
2908
|
setLoading2(false);
|
|
3021
2909
|
return;
|
|
3022
2910
|
}
|
|
@@ -3034,7 +2922,7 @@ function PackageInfoView() {
|
|
|
3034
2922
|
}
|
|
3035
2923
|
});
|
|
3036
2924
|
}, [packageName, packageType]);
|
|
3037
|
-
|
|
2925
|
+
useEffect9(() => {
|
|
3038
2926
|
if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current && packageName) {
|
|
3039
2927
|
hasRefreshed.current = true;
|
|
3040
2928
|
const refreshFn = packageType === "cask" ? getCaskInfo(packageName).then((c) => c ? { ...c, installed: c.installed ? [{ version: c.installed }] : [] } : null) : getFormulaInfo(packageName);
|
|
@@ -3046,7 +2934,7 @@ function PackageInfoView() {
|
|
|
3046
2934
|
});
|
|
3047
2935
|
}
|
|
3048
2936
|
}, [stream.isRunning, stream.error]);
|
|
3049
|
-
|
|
2937
|
+
useInput8((input, key) => {
|
|
3050
2938
|
if (stream.isRunning) {
|
|
3051
2939
|
if (key.escape) stream.cancel();
|
|
3052
2940
|
return;
|
|
@@ -3063,21 +2951,21 @@ function PackageInfoView() {
|
|
|
3063
2951
|
}
|
|
3064
2952
|
});
|
|
3065
2953
|
if (!packageName) {
|
|
3066
|
-
return /* @__PURE__ */
|
|
2954
|
+
return /* @__PURE__ */ jsx20(Text20, { color: COLORS.textSecondary, italic: true, children: t("pkgInfo_noPackage") });
|
|
3067
2955
|
}
|
|
3068
|
-
if (loading) return /* @__PURE__ */
|
|
3069
|
-
if (error) return /* @__PURE__ */
|
|
3070
|
-
if (!formula) return /* @__PURE__ */
|
|
2956
|
+
if (loading) return /* @__PURE__ */ jsx20(Loading, { message: t("loading_package", { name: packageName }) });
|
|
2957
|
+
if (error) return /* @__PURE__ */ jsx20(ErrorMessage, { message: error });
|
|
2958
|
+
if (!formula) return /* @__PURE__ */ jsx20(ErrorMessage, { message: t("pkgInfo_notFound") });
|
|
3071
2959
|
if (stream.isRunning || stream.lines.length > 0) {
|
|
3072
|
-
return /* @__PURE__ */
|
|
3073
|
-
/* @__PURE__ */
|
|
3074
|
-
stream.isRunning && /* @__PURE__ */
|
|
2960
|
+
return /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
2961
|
+
/* @__PURE__ */ jsx20(ProgressLog, { lines: stream.lines, isRunning: stream.isRunning, title: t(ACTION_PROGRESS_KEYS[activeActionRef.current] ?? ACTION_PROGRESS_KEYS["install"], { name: formula.name }) }),
|
|
2962
|
+
stream.isRunning && /* @__PURE__ */ jsxs19(Text20, { color: COLORS.textSecondary, children: [
|
|
3075
2963
|
"esc:",
|
|
3076
2964
|
t("hint_cancel")
|
|
3077
2965
|
] }),
|
|
3078
|
-
!stream.isRunning && /* @__PURE__ */
|
|
3079
|
-
/* @__PURE__ */
|
|
3080
|
-
/* @__PURE__ */
|
|
2966
|
+
!stream.isRunning && /* @__PURE__ */ jsxs19(Fragment4, { children: [
|
|
2967
|
+
/* @__PURE__ */ jsx20(Text20, { color: stream.error ? COLORS.error : COLORS.success, bold: true, children: stream.error ? `\u2718 ${stream.error}` : `\u2714 ${t("pkgInfo_done")}` }),
|
|
2968
|
+
/* @__PURE__ */ jsxs19(Text20, { color: COLORS.textSecondary, children: [
|
|
3081
2969
|
"esc:",
|
|
3082
2970
|
t("hint_back")
|
|
3083
2971
|
] })
|
|
@@ -3086,8 +2974,8 @@ function PackageInfoView() {
|
|
|
3086
2974
|
}
|
|
3087
2975
|
const installed = formula.installed[0];
|
|
3088
2976
|
const isInstalled = formula.installed.length > 0;
|
|
3089
|
-
return /* @__PURE__ */
|
|
3090
|
-
confirmAction && /* @__PURE__ */
|
|
2977
|
+
return /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
2978
|
+
confirmAction && /* @__PURE__ */ jsx20(
|
|
3091
2979
|
ConfirmDialog,
|
|
3092
2980
|
{
|
|
3093
2981
|
message: t(ACTION_CONFIRM_KEYS[confirmAction], { name: formula.name }),
|
|
@@ -3103,72 +2991,72 @@ function PackageInfoView() {
|
|
|
3103
2991
|
onCancel: () => setConfirmAction(null)
|
|
3104
2992
|
}
|
|
3105
2993
|
),
|
|
3106
|
-
/* @__PURE__ */
|
|
3107
|
-
/* @__PURE__ */
|
|
3108
|
-
/* @__PURE__ */
|
|
3109
|
-
isInstalled && /* @__PURE__ */
|
|
3110
|
-
formula.outdated && /* @__PURE__ */
|
|
3111
|
-
formula.pinned && /* @__PURE__ */
|
|
3112
|
-
formula.keg_only && /* @__PURE__ */
|
|
3113
|
-
formula.deprecated && /* @__PURE__ */
|
|
2994
|
+
/* @__PURE__ */ jsxs19(Box18, { gap: SPACING.sm, marginBottom: SPACING.xs, children: [
|
|
2995
|
+
/* @__PURE__ */ jsx20(GradientText, { colors: GRADIENTS.gold, bold: true, children: formula.name }),
|
|
2996
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.teal, children: installed?.version ?? formula.versions.stable }),
|
|
2997
|
+
isInstalled && /* @__PURE__ */ jsx20(StatusBadge, { label: t("badge_installed"), variant: "success" }),
|
|
2998
|
+
formula.outdated && /* @__PURE__ */ jsx20(StatusBadge, { label: t("badge_outdated"), variant: "warning" }),
|
|
2999
|
+
formula.pinned && /* @__PURE__ */ jsx20(StatusBadge, { label: t("badge_pinned"), variant: "info" }),
|
|
3000
|
+
formula.keg_only && /* @__PURE__ */ jsx20(StatusBadge, { label: t("badge_kegOnly"), variant: "muted" }),
|
|
3001
|
+
formula.deprecated && /* @__PURE__ */ jsx20(StatusBadge, { label: t("badge_deprecated"), variant: "error" })
|
|
3114
3002
|
] }),
|
|
3115
|
-
/* @__PURE__ */
|
|
3116
|
-
/* @__PURE__ */
|
|
3117
|
-
/* @__PURE__ */
|
|
3118
|
-
/* @__PURE__ */
|
|
3119
|
-
/* @__PURE__ */
|
|
3120
|
-
/* @__PURE__ */
|
|
3121
|
-
/* @__PURE__ */
|
|
3003
|
+
/* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", gap: SPACING.xs, children: [
|
|
3004
|
+
/* @__PURE__ */ jsx20(Text20, { children: formula.desc }),
|
|
3005
|
+
/* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
3006
|
+
/* @__PURE__ */ jsx20(SectionHeader, { emoji: "\u{1F4CB}", title: t("pkgInfo_details"), gradient: [COLORS.text, COLORS.muted] }),
|
|
3007
|
+
/* @__PURE__ */ jsxs19(Box18, { borderStyle: "round", borderColor: COLORS.border, paddingX: SPACING.sm, flexDirection: "column", children: [
|
|
3008
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
3009
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: t("pkgInfo_homepage") }),
|
|
3122
3010
|
" ",
|
|
3123
3011
|
formula.homepage
|
|
3124
3012
|
] }),
|
|
3125
|
-
/* @__PURE__ */
|
|
3126
|
-
/* @__PURE__ */
|
|
3013
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
3014
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: t("pkgInfo_license") }),
|
|
3127
3015
|
" ",
|
|
3128
3016
|
formula.license
|
|
3129
3017
|
] }),
|
|
3130
|
-
/* @__PURE__ */
|
|
3131
|
-
/* @__PURE__ */
|
|
3018
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
3019
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: t("pkgInfo_tap") }),
|
|
3132
3020
|
" ",
|
|
3133
3021
|
formula.tap
|
|
3134
3022
|
] }),
|
|
3135
|
-
/* @__PURE__ */
|
|
3136
|
-
/* @__PURE__ */
|
|
3023
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
3024
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: t("pkgInfo_stable") }),
|
|
3137
3025
|
" ",
|
|
3138
3026
|
formula.versions.stable
|
|
3139
3027
|
] }),
|
|
3140
|
-
installed && /* @__PURE__ */
|
|
3141
|
-
/* @__PURE__ */
|
|
3142
|
-
/* @__PURE__ */
|
|
3028
|
+
installed && /* @__PURE__ */ jsxs19(Fragment4, { children: [
|
|
3029
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
3030
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: t("pkgInfo_installed") }),
|
|
3143
3031
|
" ",
|
|
3144
3032
|
installed.version,
|
|
3145
3033
|
" (",
|
|
3146
3034
|
formatRelativeTime(installed.time),
|
|
3147
3035
|
")"
|
|
3148
3036
|
] }),
|
|
3149
|
-
/* @__PURE__ */
|
|
3150
|
-
/* @__PURE__ */
|
|
3037
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
3038
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: t("pkgInfo_bottle") }),
|
|
3151
3039
|
" ",
|
|
3152
3040
|
installed.poured_from_bottle ? t("common_yes") : t("common_no")
|
|
3153
3041
|
] }),
|
|
3154
|
-
/* @__PURE__ */
|
|
3155
|
-
/* @__PURE__ */
|
|
3042
|
+
/* @__PURE__ */ jsxs19(Text20, { children: [
|
|
3043
|
+
/* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: t("pkgInfo_onRequest") }),
|
|
3156
3044
|
" ",
|
|
3157
3045
|
installed.installed_on_request ? t("common_yes") : t("pkgInfo_noDependency")
|
|
3158
3046
|
] })
|
|
3159
3047
|
] })
|
|
3160
3048
|
] })
|
|
3161
3049
|
] }),
|
|
3162
|
-
formula.dependencies.length > 0 && /* @__PURE__ */
|
|
3163
|
-
/* @__PURE__ */
|
|
3164
|
-
/* @__PURE__ */
|
|
3050
|
+
formula.dependencies.length > 0 && /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
3051
|
+
/* @__PURE__ */ jsx20(SectionHeader, { emoji: "\u{1F517}", title: t("pkgInfo_dependencies", { count: formula.dependencies.length }), gradient: GRADIENTS.ocean }),
|
|
3052
|
+
/* @__PURE__ */ jsx20(Box18, { paddingLeft: SPACING.sm, flexWrap: "wrap", columnGap: 2, children: formula.dependencies.map((dep) => /* @__PURE__ */ jsx20(Text20, { color: COLORS.muted, children: dep }, dep)) })
|
|
3165
3053
|
] }),
|
|
3166
|
-
formula.caveats && /* @__PURE__ */
|
|
3167
|
-
/* @__PURE__ */
|
|
3168
|
-
/* @__PURE__ */
|
|
3054
|
+
formula.caveats && /* @__PURE__ */ jsxs19(Box18, { flexDirection: "column", children: [
|
|
3055
|
+
/* @__PURE__ */ jsx20(SectionHeader, { emoji: "\u26A0\uFE0F", title: t("pkgInfo_caveats"), color: COLORS.warning }),
|
|
3056
|
+
/* @__PURE__ */ jsx20(Box18, { borderStyle: "round", borderColor: COLORS.warning, paddingX: SPACING.sm, children: /* @__PURE__ */ jsx20(Text20, { color: COLORS.warning, children: formula.caveats }) })
|
|
3169
3057
|
] })
|
|
3170
3058
|
] }),
|
|
3171
|
-
/* @__PURE__ */
|
|
3059
|
+
/* @__PURE__ */ jsx20(Box18, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs19(Text20, { color: COLORS.textSecondary, children: [
|
|
3172
3060
|
isInstalled ? `u:${t("hint_uninstall")}` : `i:${t("hint_install")}`,
|
|
3173
3061
|
isInstalled && formula.outdated ? ` U:${t("hint_upgrade")}` : "",
|
|
3174
3062
|
` esc:${t("hint_back")}`
|
|
@@ -3177,15 +3065,21 @@ function PackageInfoView() {
|
|
|
3177
3065
|
}
|
|
3178
3066
|
|
|
3179
3067
|
// src/views/services.tsx
|
|
3180
|
-
import { useEffect as
|
|
3181
|
-
import { Box as
|
|
3182
|
-
import { jsx as
|
|
3068
|
+
import { useEffect as useEffect10, useState as useState7 } from "react";
|
|
3069
|
+
import { Box as Box19, Text as Text21, useInput as useInput9, useStdout as useStdout6 } from "ink";
|
|
3070
|
+
import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3183
3071
|
var STATUS_VARIANTS = {
|
|
3184
3072
|
started: "success",
|
|
3185
3073
|
stopped: "muted",
|
|
3186
3074
|
error: "error",
|
|
3187
3075
|
none: "muted"
|
|
3188
3076
|
};
|
|
3077
|
+
function humaniseServiceError(message) {
|
|
3078
|
+
if (/EACCES|operation not permitted|permission denied|sudo/i.test(message)) {
|
|
3079
|
+
return t("services_errorPermission");
|
|
3080
|
+
}
|
|
3081
|
+
return message;
|
|
3082
|
+
}
|
|
3189
3083
|
function ServicesView() {
|
|
3190
3084
|
const { services, loading, errors, fetchServices, serviceAction: serviceAction2 } = useBrewStore();
|
|
3191
3085
|
const [cursor, setCursor] = useState7(0);
|
|
@@ -3197,10 +3091,10 @@ function ServicesView() {
|
|
|
3197
3091
|
const svcNameWidth = Math.floor(cols * 0.35);
|
|
3198
3092
|
const svcStatusWidth = Math.floor(cols * 0.15);
|
|
3199
3093
|
const MAX_VISIBLE_ROWS = Math.max(5, (stdout?.rows ?? 24) - 10);
|
|
3200
|
-
|
|
3094
|
+
useEffect10(() => {
|
|
3201
3095
|
fetchServices();
|
|
3202
3096
|
}, []);
|
|
3203
|
-
|
|
3097
|
+
useInput9((input, key) => {
|
|
3204
3098
|
if (actionInProgress) return;
|
|
3205
3099
|
if (confirmAction) return;
|
|
3206
3100
|
if (lastError) {
|
|
@@ -3218,30 +3112,30 @@ function ServicesView() {
|
|
|
3218
3112
|
const doAction = (action) => {
|
|
3219
3113
|
setActionInProgress(true);
|
|
3220
3114
|
void serviceAction2(svc.name, action).catch((err) => {
|
|
3221
|
-
setLastError(err instanceof Error ? err.message : String(err));
|
|
3115
|
+
setLastError(humaniseServiceError(err instanceof Error ? err.message : String(err)));
|
|
3222
3116
|
}).finally(() => {
|
|
3223
3117
|
setActionInProgress(false);
|
|
3224
3118
|
const storeError = useBrewStore.getState().errors["service-action"];
|
|
3225
|
-
if (storeError) setLastError(storeError);
|
|
3119
|
+
if (storeError) setLastError(humaniseServiceError(storeError));
|
|
3226
3120
|
});
|
|
3227
3121
|
};
|
|
3228
3122
|
if (input === "s") doAction("start");
|
|
3229
3123
|
else if (input === "x") setConfirmAction({ type: "stop", name: svc.name });
|
|
3230
3124
|
else if (input === "R") setConfirmAction({ type: "restart", name: svc.name });
|
|
3231
3125
|
});
|
|
3232
|
-
if (loading.services) return /* @__PURE__ */
|
|
3233
|
-
if (errors.services) return /* @__PURE__ */
|
|
3126
|
+
if (loading.services) return /* @__PURE__ */ jsx21(Loading, { message: t("loading_services") });
|
|
3127
|
+
if (errors.services) return /* @__PURE__ */ jsx21(ErrorMessage, { message: errors.services });
|
|
3234
3128
|
if (services.length === 0) {
|
|
3235
|
-
return /* @__PURE__ */
|
|
3236
|
-
/* @__PURE__ */
|
|
3237
|
-
/* @__PURE__ */
|
|
3129
|
+
return /* @__PURE__ */ jsxs20(Box19, { flexDirection: "column", children: [
|
|
3130
|
+
/* @__PURE__ */ jsx21(SectionHeader, { emoji: "\u2699\uFE0F", title: t("services_title"), gradient: GRADIENTS.ocean }),
|
|
3131
|
+
/* @__PURE__ */ jsx21(Text21, { color: COLORS.textSecondary, italic: true, children: t("services_noServices") })
|
|
3238
3132
|
] });
|
|
3239
3133
|
}
|
|
3240
3134
|
const start = Math.max(0, cursor - Math.floor(MAX_VISIBLE_ROWS / 2));
|
|
3241
3135
|
const visible = services.slice(start, start + MAX_VISIBLE_ROWS);
|
|
3242
|
-
return /* @__PURE__ */
|
|
3243
|
-
/* @__PURE__ */
|
|
3244
|
-
confirmAction && /* @__PURE__ */
|
|
3136
|
+
return /* @__PURE__ */ jsxs20(Box19, { flexDirection: "column", children: [
|
|
3137
|
+
/* @__PURE__ */ jsx21(SectionHeader, { emoji: "\u2699\uFE0F", title: t("services_titleCount", { count: services.length }), gradient: GRADIENTS.ocean }),
|
|
3138
|
+
confirmAction && /* @__PURE__ */ jsx21(Box19, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx21(
|
|
3245
3139
|
ConfirmDialog,
|
|
3246
3140
|
{
|
|
3247
3141
|
message: confirmAction.type === "stop" ? t("services_confirmStop", { name: confirmAction.name }) : t("services_confirmRestart", { name: confirmAction.name }),
|
|
@@ -3260,37 +3154,37 @@ function ServicesView() {
|
|
|
3260
3154
|
onCancel: () => setConfirmAction(null)
|
|
3261
3155
|
}
|
|
3262
3156
|
) }),
|
|
3263
|
-
/* @__PURE__ */
|
|
3264
|
-
/* @__PURE__ */
|
|
3265
|
-
/* @__PURE__ */
|
|
3157
|
+
/* @__PURE__ */ jsxs20(Box19, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
3158
|
+
/* @__PURE__ */ jsxs20(Box19, { gap: SPACING.xs, borderStyle: "single", borderBottom: true, borderTop: false, borderLeft: false, borderRight: false, borderColor: COLORS.border, paddingBottom: SPACING.none, children: [
|
|
3159
|
+
/* @__PURE__ */ jsxs20(Text21, { bold: true, color: COLORS.text, children: [
|
|
3266
3160
|
" ",
|
|
3267
3161
|
t("services_name").padEnd(svcNameWidth)
|
|
3268
3162
|
] }),
|
|
3269
|
-
/* @__PURE__ */
|
|
3270
|
-
/* @__PURE__ */
|
|
3163
|
+
/* @__PURE__ */ jsx21(Text21, { bold: true, color: COLORS.text, children: t("services_status").padEnd(svcStatusWidth) }),
|
|
3164
|
+
/* @__PURE__ */ jsx21(Text21, { bold: true, color: COLORS.text, children: t("services_user") })
|
|
3271
3165
|
] }),
|
|
3272
|
-
start > 0 && /* @__PURE__ */
|
|
3166
|
+
start > 0 && /* @__PURE__ */ jsxs20(Text21, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
3273
3167
|
" ",
|
|
3274
3168
|
t("scroll_moreAbove", { count: start })
|
|
3275
3169
|
] }),
|
|
3276
3170
|
visible.map((svc, i) => {
|
|
3277
3171
|
const idx = start + i;
|
|
3278
3172
|
const isCurrent = idx === cursor;
|
|
3279
|
-
return /* @__PURE__ */
|
|
3280
|
-
/* @__PURE__ */
|
|
3281
|
-
/* @__PURE__ */
|
|
3282
|
-
/* @__PURE__ */
|
|
3283
|
-
svc.exit_code != null && svc.exit_code !== 0 && /* @__PURE__ */
|
|
3173
|
+
return /* @__PURE__ */ jsxs20(SelectableRow, { isCurrent, children: [
|
|
3174
|
+
/* @__PURE__ */ jsx21(Text21, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: svc.name.padEnd(svcNameWidth - 2) }),
|
|
3175
|
+
/* @__PURE__ */ jsx21(StatusBadge, { label: svc.status, variant: STATUS_VARIANTS[svc.status] }),
|
|
3176
|
+
/* @__PURE__ */ jsx21(Text21, { color: COLORS.muted, children: svc.user ?? "-" }),
|
|
3177
|
+
svc.exit_code != null && svc.exit_code !== 0 && /* @__PURE__ */ jsx21(Text21, { color: COLORS.error, children: t("common_exit", { code: svc.exit_code }) })
|
|
3284
3178
|
] }, svc.name);
|
|
3285
3179
|
}),
|
|
3286
|
-
start + MAX_VISIBLE_ROWS < services.length && /* @__PURE__ */
|
|
3180
|
+
start + MAX_VISIBLE_ROWS < services.length && /* @__PURE__ */ jsxs20(Text21, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
3287
3181
|
" ",
|
|
3288
3182
|
t("scroll_moreBelow", { count: services.length - start - MAX_VISIBLE_ROWS })
|
|
3289
3183
|
] })
|
|
3290
3184
|
] }),
|
|
3291
|
-
actionInProgress && /* @__PURE__ */
|
|
3292
|
-
lastError && /* @__PURE__ */
|
|
3293
|
-
/* @__PURE__ */
|
|
3185
|
+
actionInProgress && /* @__PURE__ */ jsx21(Text21, { color: COLORS.sky, children: t("services_processing") }),
|
|
3186
|
+
lastError && /* @__PURE__ */ jsx21(Box19, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx21(Text21, { color: COLORS.error, children: lastError }) }),
|
|
3187
|
+
/* @__PURE__ */ jsx21(Box19, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs20(Text21, { color: COLORS.text, bold: true, children: [
|
|
3294
3188
|
cursor + 1,
|
|
3295
3189
|
"/",
|
|
3296
3190
|
services.length
|
|
@@ -3299,53 +3193,53 @@ function ServicesView() {
|
|
|
3299
3193
|
}
|
|
3300
3194
|
|
|
3301
3195
|
// src/views/doctor.tsx
|
|
3302
|
-
import { useEffect as
|
|
3303
|
-
import { Box as
|
|
3304
|
-
import { jsx as
|
|
3196
|
+
import { useEffect as useEffect11, useRef as useRef5 } from "react";
|
|
3197
|
+
import { Box as Box20, Text as Text22, useInput as useInput10 } from "ink";
|
|
3198
|
+
import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3305
3199
|
function DoctorView() {
|
|
3306
3200
|
const { doctorWarnings, doctorClean, loading, errors, fetchDoctor } = useBrewStore();
|
|
3307
3201
|
const mountedRef = useRef5(true);
|
|
3308
|
-
|
|
3202
|
+
useEffect11(() => {
|
|
3309
3203
|
mountedRef.current = true;
|
|
3310
3204
|
return () => {
|
|
3311
3205
|
mountedRef.current = false;
|
|
3312
3206
|
};
|
|
3313
3207
|
}, []);
|
|
3314
|
-
|
|
3208
|
+
useEffect11(() => {
|
|
3315
3209
|
fetchDoctor();
|
|
3316
3210
|
}, []);
|
|
3317
|
-
|
|
3211
|
+
useInput10((input) => {
|
|
3318
3212
|
if (input === "r") void fetchDoctor();
|
|
3319
3213
|
});
|
|
3320
|
-
if (loading.doctor) return /* @__PURE__ */
|
|
3321
|
-
if (errors.doctor) return /* @__PURE__ */
|
|
3322
|
-
return /* @__PURE__ */
|
|
3323
|
-
/* @__PURE__ */
|
|
3324
|
-
/* @__PURE__ */
|
|
3325
|
-
doctorClean && /* @__PURE__ */
|
|
3326
|
-
doctorClean === false && doctorWarnings.length === 0 && /* @__PURE__ */
|
|
3214
|
+
if (loading.doctor) return /* @__PURE__ */ jsx22(Loading, { message: t("loading_doctor") });
|
|
3215
|
+
if (errors.doctor) return /* @__PURE__ */ jsx22(ErrorMessage, { message: errors.doctor });
|
|
3216
|
+
return /* @__PURE__ */ jsxs21(Box20, { flexDirection: "column", children: [
|
|
3217
|
+
/* @__PURE__ */ jsx22(SectionHeader, { emoji: "\u{1FA7A}", title: t("doctor_title"), gradient: GRADIENTS.emerald }),
|
|
3218
|
+
/* @__PURE__ */ jsxs21(Box20, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
3219
|
+
doctorClean && /* @__PURE__ */ jsx22(ResultBanner, { status: "success", message: `\u2714 ${t("doctor_clean")}` }),
|
|
3220
|
+
doctorClean === false && doctorWarnings.length === 0 && /* @__PURE__ */ jsx22(Text22, { color: COLORS.warning, children: t("doctor_warningsNotCaptured") }),
|
|
3327
3221
|
doctorWarnings.map((warning, i) => (
|
|
3328
3222
|
// FE-004: Improved React key
|
|
3329
|
-
/* @__PURE__ */
|
|
3223
|
+
/* @__PURE__ */ jsx22(Box20, { flexDirection: "column", marginBottom: SPACING.xs, borderStyle: "single", borderColor: COLORS.warning, paddingX: SPACING.xs, children: warning.split("\n").map((line, j) => /* @__PURE__ */ jsx22(Text22, { color: j === 0 ? COLORS.warning : COLORS.muted, children: line }, `warning-${i}-${j}-${line.slice(0, 20)}`)) }, `warning-${i}-${warning.slice(0, 20)}`)
|
|
3330
3224
|
))
|
|
3331
3225
|
] }),
|
|
3332
|
-
/* @__PURE__ */
|
|
3226
|
+
/* @__PURE__ */ jsx22(Box20, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx22(Text22, { color: COLORS.text, bold: true, children: doctorWarnings.length > 0 ? tp("plural_warnings", doctorWarnings.length) : "" }) })
|
|
3333
3227
|
] });
|
|
3334
3228
|
}
|
|
3335
3229
|
|
|
3336
3230
|
// src/views/profiles.tsx
|
|
3337
|
-
import { useEffect as
|
|
3338
|
-
import { Box as
|
|
3231
|
+
import { useEffect as useEffect12, useRef as useRef6, useState as useState8 } from "react";
|
|
3232
|
+
import { Box as Box25, useInput as useInput11 } from "ink";
|
|
3339
3233
|
|
|
3340
3234
|
// src/stores/profile-store.ts
|
|
3341
3235
|
import { create as create9 } from "zustand";
|
|
3342
3236
|
|
|
3343
3237
|
// src/lib/profiles/profile-manager.ts
|
|
3344
|
-
import { readFile
|
|
3345
|
-
import { join
|
|
3238
|
+
import { readFile, writeFile as writeFile2, readdir, rm, rename } from "fs/promises";
|
|
3239
|
+
import { join, basename } from "path";
|
|
3346
3240
|
|
|
3347
3241
|
// src/lib/license/watermark.ts
|
|
3348
|
-
function getWatermark(license, consent =
|
|
3242
|
+
function getWatermark(license, consent = false) {
|
|
3349
3243
|
if (!consent) return "";
|
|
3350
3244
|
if (!license?.customerEmail) return "";
|
|
3351
3245
|
return `Licensed to: ${license.customerEmail}`;
|
|
@@ -3369,7 +3263,7 @@ function validateProfileName(name) {
|
|
|
3369
3263
|
}
|
|
3370
3264
|
function profilePath(name) {
|
|
3371
3265
|
validateProfileName(name);
|
|
3372
|
-
return
|
|
3266
|
+
return join(PROFILES_DIR, `${basename(name)}.json`);
|
|
3373
3267
|
}
|
|
3374
3268
|
async function listProfiles(isPro) {
|
|
3375
3269
|
proCheck(isPro);
|
|
@@ -3383,7 +3277,7 @@ async function listProfiles(isPro) {
|
|
|
3383
3277
|
}
|
|
3384
3278
|
async function loadProfile(isPro, name) {
|
|
3385
3279
|
proCheck(isPro);
|
|
3386
|
-
const raw = await
|
|
3280
|
+
const raw = await readFile(profilePath(name), "utf-8");
|
|
3387
3281
|
let file;
|
|
3388
3282
|
try {
|
|
3389
3283
|
file = JSON.parse(raw);
|
|
@@ -3404,13 +3298,13 @@ async function saveProfile(isPro, profile) {
|
|
|
3404
3298
|
const filePath = profilePath(profile.name);
|
|
3405
3299
|
const tmpPath = filePath + ".tmp";
|
|
3406
3300
|
const file = { version: 1, profile };
|
|
3407
|
-
await
|
|
3408
|
-
await
|
|
3301
|
+
await writeFile2(tmpPath, JSON.stringify(file, null, 2), { encoding: "utf-8", mode: 384 });
|
|
3302
|
+
await rename(tmpPath, filePath);
|
|
3409
3303
|
}
|
|
3410
3304
|
async function deleteProfile(isPro, name) {
|
|
3411
3305
|
proCheck(isPro);
|
|
3412
3306
|
try {
|
|
3413
|
-
await
|
|
3307
|
+
await rm(profilePath(name));
|
|
3414
3308
|
} catch {
|
|
3415
3309
|
}
|
|
3416
3310
|
}
|
|
@@ -3436,8 +3330,8 @@ async function exportCurrentSetup(isPro, name, description, license = null, cons
|
|
|
3436
3330
|
formulae: leaves,
|
|
3437
3331
|
casks,
|
|
3438
3332
|
taps,
|
|
3439
|
-
exportedBy:
|
|
3440
|
-
//
|
|
3333
|
+
exportedBy: getWatermark(license, consent)
|
|
3334
|
+
// BK-014: explicit consent required (default false)
|
|
3441
3335
|
};
|
|
3442
3336
|
await saveProfile(isPro, profile);
|
|
3443
3337
|
return profile;
|
|
@@ -3555,13 +3449,13 @@ var useProfileStore = create9((set) => ({
|
|
|
3555
3449
|
}));
|
|
3556
3450
|
|
|
3557
3451
|
// src/views/profiles/profile-list-mode.tsx
|
|
3558
|
-
import { Box as
|
|
3559
|
-
import { jsx as
|
|
3452
|
+
import { Box as Box21, Text as Text23 } from "ink";
|
|
3453
|
+
import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3560
3454
|
function ProfileListMode({ profileNames, cursor, confirmDelete, loadError, onConfirmDelete, onCancelDelete }) {
|
|
3561
|
-
return /* @__PURE__ */
|
|
3562
|
-
/* @__PURE__ */
|
|
3563
|
-
loadError && /* @__PURE__ */
|
|
3564
|
-
confirmDelete && profileNames[cursor] && /* @__PURE__ */
|
|
3455
|
+
return /* @__PURE__ */ jsxs22(Box21, { flexDirection: "column", children: [
|
|
3456
|
+
/* @__PURE__ */ jsx23(SectionHeader, { emoji: "\u{1F4C1}", title: t("profiles_title", { count: profileNames.length }), gradient: GRADIENTS.gold }),
|
|
3457
|
+
loadError && /* @__PURE__ */ jsx23(Box21, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx23(Text23, { color: COLORS.error, children: loadError }) }),
|
|
3458
|
+
confirmDelete && profileNames[cursor] && /* @__PURE__ */ jsx23(Box21, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx23(
|
|
3565
3459
|
ConfirmDialog,
|
|
3566
3460
|
{
|
|
3567
3461
|
message: t("profiles_confirmDelete", { name: profileNames[cursor] }),
|
|
@@ -3569,22 +3463,22 @@ function ProfileListMode({ profileNames, cursor, confirmDelete, loadError, onCon
|
|
|
3569
3463
|
onCancel: onCancelDelete
|
|
3570
3464
|
}
|
|
3571
3465
|
) }),
|
|
3572
|
-
profileNames.length === 0 && !confirmDelete && /* @__PURE__ */
|
|
3573
|
-
/* @__PURE__ */
|
|
3574
|
-
/* @__PURE__ */
|
|
3466
|
+
profileNames.length === 0 && !confirmDelete && /* @__PURE__ */ jsx23(Box21, { marginTop: SPACING.xs, borderStyle: "round", borderColor: COLORS.textSecondary, paddingX: SPACING.sm, paddingY: SPACING.none, children: /* @__PURE__ */ jsxs22(Box21, { flexDirection: "column", children: [
|
|
3467
|
+
/* @__PURE__ */ jsx23(Text23, { color: COLORS.textSecondary, italic: true, children: t("profiles_noProfiles") }),
|
|
3468
|
+
/* @__PURE__ */ jsxs22(Text23, { color: COLORS.muted, children: [
|
|
3575
3469
|
t("profiles_press"),
|
|
3576
3470
|
" ",
|
|
3577
|
-
/* @__PURE__ */
|
|
3471
|
+
/* @__PURE__ */ jsx23(Text23, { color: COLORS.gold, bold: true, children: "n" }),
|
|
3578
3472
|
" ",
|
|
3579
3473
|
t("profiles_exportHint")
|
|
3580
3474
|
] })
|
|
3581
3475
|
] }) }),
|
|
3582
|
-
profileNames.length > 0 && !confirmDelete && /* @__PURE__ */
|
|
3476
|
+
profileNames.length > 0 && !confirmDelete && /* @__PURE__ */ jsxs22(Box21, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
3583
3477
|
profileNames.map((name, i) => {
|
|
3584
3478
|
const isCurrent = i === cursor;
|
|
3585
|
-
return /* @__PURE__ */
|
|
3479
|
+
return /* @__PURE__ */ jsx23(SelectableRow, { isCurrent, children: /* @__PURE__ */ jsx23(Text23, { bold: isCurrent, inverse: isCurrent, children: name }) }, name);
|
|
3586
3480
|
}),
|
|
3587
|
-
/* @__PURE__ */
|
|
3481
|
+
/* @__PURE__ */ jsx23(Box21, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs22(Text23, { color: COLORS.text, bold: true, children: [
|
|
3588
3482
|
cursor + 1,
|
|
3589
3483
|
"/",
|
|
3590
3484
|
profileNames.length
|
|
@@ -3594,23 +3488,23 @@ function ProfileListMode({ profileNames, cursor, confirmDelete, loadError, onCon
|
|
|
3594
3488
|
}
|
|
3595
3489
|
|
|
3596
3490
|
// src/views/profiles/profile-detail-mode.tsx
|
|
3597
|
-
import { Box as
|
|
3598
|
-
import { jsx as
|
|
3491
|
+
import { Box as Box22, Text as Text24 } from "ink";
|
|
3492
|
+
import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3599
3493
|
function ProfileDetailMode({ profile }) {
|
|
3600
|
-
return /* @__PURE__ */
|
|
3601
|
-
/* @__PURE__ */
|
|
3602
|
-
/* @__PURE__ */
|
|
3603
|
-
/* @__PURE__ */
|
|
3604
|
-
/* @__PURE__ */
|
|
3605
|
-
/* @__PURE__ */
|
|
3606
|
-
/* @__PURE__ */
|
|
3607
|
-
profile.formulae.slice(0, 30).map((f) => /* @__PURE__ */
|
|
3608
|
-
profile.formulae.length > 30 && /* @__PURE__ */
|
|
3494
|
+
return /* @__PURE__ */ jsxs23(Box22, { flexDirection: "column", children: [
|
|
3495
|
+
/* @__PURE__ */ jsx24(Text24, { bold: true, color: COLORS.gold, children: profile.name }),
|
|
3496
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.muted, children: profile.description }),
|
|
3497
|
+
/* @__PURE__ */ jsx24(Text24, { color: COLORS.muted, children: t("profiles_created", { date: formatDate(profile.createdAt) }) }),
|
|
3498
|
+
/* @__PURE__ */ jsxs23(Box22, { marginTop: SPACING.xs, flexDirection: "column", children: [
|
|
3499
|
+
/* @__PURE__ */ jsx24(Text24, { bold: true, children: t("profiles_formulaeCount", { count: profile.formulae.length }) }),
|
|
3500
|
+
/* @__PURE__ */ jsxs23(Box22, { paddingLeft: SPACING.sm, flexDirection: "column", children: [
|
|
3501
|
+
profile.formulae.slice(0, 30).map((f) => /* @__PURE__ */ jsx24(Text24, { color: COLORS.muted, children: f }, f)),
|
|
3502
|
+
profile.formulae.length > 30 && /* @__PURE__ */ jsx24(Text24, { color: COLORS.textSecondary, italic: true, children: t("common_andMore", { count: profile.formulae.length - 30 }) })
|
|
3609
3503
|
] }),
|
|
3610
|
-
/* @__PURE__ */
|
|
3611
|
-
/* @__PURE__ */
|
|
3504
|
+
/* @__PURE__ */ jsx24(Text24, { bold: true, children: t("profiles_casksCount", { count: profile.casks.length }) }),
|
|
3505
|
+
/* @__PURE__ */ jsx24(Box22, { paddingLeft: SPACING.sm, flexDirection: "column", children: profile.casks.map((c) => /* @__PURE__ */ jsx24(Text24, { color: COLORS.muted, children: c }, c)) })
|
|
3612
3506
|
] }),
|
|
3613
|
-
/* @__PURE__ */
|
|
3507
|
+
/* @__PURE__ */ jsx24(Box22, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs23(Text24, { color: COLORS.textSecondary, children: [
|
|
3614
3508
|
"esc:",
|
|
3615
3509
|
t("hint_back"),
|
|
3616
3510
|
" e:",
|
|
@@ -3622,13 +3516,13 @@ function ProfileDetailMode({ profile }) {
|
|
|
3622
3516
|
}
|
|
3623
3517
|
|
|
3624
3518
|
// src/views/profiles/profile-create-flow.tsx
|
|
3625
|
-
import { Box as
|
|
3519
|
+
import { Box as Box23, Text as Text25 } from "ink";
|
|
3626
3520
|
import { TextInput as TextInput3 } from "@inkjs/ui";
|
|
3627
|
-
import { jsx as
|
|
3521
|
+
import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
3628
3522
|
function ProfileCreateName({ onSubmit }) {
|
|
3629
|
-
return /* @__PURE__ */
|
|
3630
|
-
/* @__PURE__ */
|
|
3631
|
-
/* @__PURE__ */
|
|
3523
|
+
return /* @__PURE__ */ jsxs24(Box23, { flexDirection: "column", children: [
|
|
3524
|
+
/* @__PURE__ */ jsx25(Text25, { bold: true, children: t("profiles_createName") }),
|
|
3525
|
+
/* @__PURE__ */ jsx25(
|
|
3632
3526
|
TextInput3,
|
|
3633
3527
|
{
|
|
3634
3528
|
placeholder: t("profiles_namePlaceholder"),
|
|
@@ -3638,13 +3532,13 @@ function ProfileCreateName({ onSubmit }) {
|
|
|
3638
3532
|
] });
|
|
3639
3533
|
}
|
|
3640
3534
|
function ProfileCreateDesc({ name, loadError, onSubmit }) {
|
|
3641
|
-
return /* @__PURE__ */
|
|
3642
|
-
/* @__PURE__ */
|
|
3643
|
-
loadError && /* @__PURE__ */
|
|
3535
|
+
return /* @__PURE__ */ jsxs24(Box23, { flexDirection: "column", children: [
|
|
3536
|
+
/* @__PURE__ */ jsx25(Text25, { bold: true, children: t("profiles_createDesc", { name }) }),
|
|
3537
|
+
loadError && /* @__PURE__ */ jsxs24(Text25, { color: COLORS.error, children: [
|
|
3644
3538
|
t("error_prefix"),
|
|
3645
3539
|
loadError
|
|
3646
3540
|
] }),
|
|
3647
|
-
/* @__PURE__ */
|
|
3541
|
+
/* @__PURE__ */ jsx25(
|
|
3648
3542
|
TextInput3,
|
|
3649
3543
|
{
|
|
3650
3544
|
placeholder: t("profiles_descPlaceholder"),
|
|
@@ -3655,13 +3549,13 @@ function ProfileCreateDesc({ name, loadError, onSubmit }) {
|
|
|
3655
3549
|
}
|
|
3656
3550
|
|
|
3657
3551
|
// src/views/profiles/profile-edit-flow.tsx
|
|
3658
|
-
import { Box as
|
|
3552
|
+
import { Box as Box24, Text as Text26 } from "ink";
|
|
3659
3553
|
import { TextInput as TextInput4 } from "@inkjs/ui";
|
|
3660
|
-
import { jsx as
|
|
3554
|
+
import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3661
3555
|
function ProfileEditName({ defaultName, onSubmit }) {
|
|
3662
|
-
return /* @__PURE__ */
|
|
3663
|
-
/* @__PURE__ */
|
|
3664
|
-
/* @__PURE__ */
|
|
3556
|
+
return /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", children: [
|
|
3557
|
+
/* @__PURE__ */ jsx26(Text26, { bold: true, children: t("profiles_editName") }),
|
|
3558
|
+
/* @__PURE__ */ jsx26(
|
|
3665
3559
|
TextInput4,
|
|
3666
3560
|
{
|
|
3667
3561
|
defaultValue: defaultName,
|
|
@@ -3671,13 +3565,13 @@ function ProfileEditName({ defaultName, onSubmit }) {
|
|
|
3671
3565
|
] });
|
|
3672
3566
|
}
|
|
3673
3567
|
function ProfileEditDesc({ name, defaultDesc, loadError, onSubmit }) {
|
|
3674
|
-
return /* @__PURE__ */
|
|
3675
|
-
/* @__PURE__ */
|
|
3676
|
-
loadError && /* @__PURE__ */
|
|
3568
|
+
return /* @__PURE__ */ jsxs25(Box24, { flexDirection: "column", children: [
|
|
3569
|
+
/* @__PURE__ */ jsx26(Text26, { bold: true, children: t("profiles_editDesc", { name }) }),
|
|
3570
|
+
loadError && /* @__PURE__ */ jsxs25(Text26, { color: COLORS.error, children: [
|
|
3677
3571
|
t("error_prefix"),
|
|
3678
3572
|
loadError
|
|
3679
3573
|
] }),
|
|
3680
|
-
/* @__PURE__ */
|
|
3574
|
+
/* @__PURE__ */ jsx26(
|
|
3681
3575
|
TextInput4,
|
|
3682
3576
|
{
|
|
3683
3577
|
defaultValue: defaultDesc,
|
|
@@ -3688,7 +3582,7 @@ function ProfileEditDesc({ name, defaultDesc, loadError, onSubmit }) {
|
|
|
3688
3582
|
}
|
|
3689
3583
|
|
|
3690
3584
|
// src/views/profiles.tsx
|
|
3691
|
-
import { jsx as
|
|
3585
|
+
import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3692
3586
|
function ProfilesView() {
|
|
3693
3587
|
const { profileNames, selectedProfile, loading, loadError, fetchProfiles, loadProfile: loadProfile2, exportCurrent, deleteProfile: deleteProfile2, updateProfile: updateProfile2 } = useProfileStore();
|
|
3694
3588
|
const [cursor, setCursor] = useState8(0);
|
|
@@ -3704,10 +3598,10 @@ function ProfilesView() {
|
|
|
3704
3598
|
const { openModal, closeModal } = useModalStore();
|
|
3705
3599
|
const importGenRef = useRef6(null);
|
|
3706
3600
|
const mountedRef = useRef6(true);
|
|
3707
|
-
|
|
3601
|
+
useEffect12(() => {
|
|
3708
3602
|
fetchProfiles();
|
|
3709
3603
|
}, []);
|
|
3710
|
-
|
|
3604
|
+
useEffect12(() => {
|
|
3711
3605
|
mountedRef.current = true;
|
|
3712
3606
|
return () => {
|
|
3713
3607
|
mountedRef.current = false;
|
|
@@ -3715,7 +3609,7 @@ function ProfilesView() {
|
|
|
3715
3609
|
importGenRef.current = null;
|
|
3716
3610
|
};
|
|
3717
3611
|
}, []);
|
|
3718
|
-
|
|
3612
|
+
useEffect12(() => {
|
|
3719
3613
|
if (mode !== "list") {
|
|
3720
3614
|
openModal();
|
|
3721
3615
|
return () => {
|
|
@@ -3724,7 +3618,7 @@ function ProfilesView() {
|
|
|
3724
3618
|
}
|
|
3725
3619
|
return void 0;
|
|
3726
3620
|
}, [mode]);
|
|
3727
|
-
|
|
3621
|
+
useInput11((input, key) => {
|
|
3728
3622
|
if (mode !== "list" || confirmDelete) return;
|
|
3729
3623
|
if (input === "n") {
|
|
3730
3624
|
setMode("create-name");
|
|
@@ -3746,7 +3640,7 @@ function ProfilesView() {
|
|
|
3746
3640
|
if (input === "j" || key.downArrow) setCursor((c) => Math.min(c + 1, Math.max(0, profileNames.length - 1)));
|
|
3747
3641
|
else if (input === "k" || key.upArrow) setCursor((c) => Math.max(c - 1, 0));
|
|
3748
3642
|
});
|
|
3749
|
-
|
|
3643
|
+
useInput11((input, key) => {
|
|
3750
3644
|
if (key.escape || input === "q") {
|
|
3751
3645
|
setMode("list");
|
|
3752
3646
|
return;
|
|
@@ -3757,7 +3651,7 @@ function ProfilesView() {
|
|
|
3757
3651
|
setMode("edit-name");
|
|
3758
3652
|
}
|
|
3759
3653
|
}, { isActive: mode === "detail" });
|
|
3760
|
-
|
|
3654
|
+
useInput11(() => {
|
|
3761
3655
|
setMode("list");
|
|
3762
3656
|
}, { isActive: mode === "importing" && !importRunning });
|
|
3763
3657
|
const prepareImport = async (name) => {
|
|
@@ -3797,9 +3691,9 @@ function ProfilesView() {
|
|
|
3797
3691
|
}
|
|
3798
3692
|
}
|
|
3799
3693
|
};
|
|
3800
|
-
if (loading) return /* @__PURE__ */
|
|
3694
|
+
if (loading) return /* @__PURE__ */ jsx27(Loading, { message: t("loading_profiles") });
|
|
3801
3695
|
if (mode === "confirm-import" && importProfile2) {
|
|
3802
|
-
return /* @__PURE__ */
|
|
3696
|
+
return /* @__PURE__ */ jsx27(Box25, { flexDirection: "column", children: /* @__PURE__ */ jsx27(
|
|
3803
3697
|
ConfirmDialog,
|
|
3804
3698
|
{
|
|
3805
3699
|
message: t("profiles_importSummary", {
|
|
@@ -3819,19 +3713,19 @@ function ProfilesView() {
|
|
|
3819
3713
|
) });
|
|
3820
3714
|
}
|
|
3821
3715
|
if (mode === "importing") {
|
|
3822
|
-
return /* @__PURE__ */
|
|
3823
|
-
/* @__PURE__ */
|
|
3824
|
-
!importRunning && /* @__PURE__ */
|
|
3716
|
+
return /* @__PURE__ */ jsxs26(Box25, { flexDirection: "column", children: [
|
|
3717
|
+
/* @__PURE__ */ jsx27(ProgressLog, { lines: importLines, isRunning: importRunning, title: t("profiles_importTitle") }),
|
|
3718
|
+
!importRunning && /* @__PURE__ */ jsx27(Box25, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx27(ResultBanner, { status: importHadError ? "error" : "success", message: importHadError ? t("profiles_importPartial") : `\u2714 ${t("profiles_importComplete")}` }) })
|
|
3825
3719
|
] });
|
|
3826
3720
|
}
|
|
3827
3721
|
if (mode === "create-name") {
|
|
3828
|
-
return /* @__PURE__ */
|
|
3722
|
+
return /* @__PURE__ */ jsx27(ProfileCreateName, { onSubmit: (val) => {
|
|
3829
3723
|
setNewName(val);
|
|
3830
3724
|
setMode("create-desc");
|
|
3831
3725
|
} });
|
|
3832
3726
|
}
|
|
3833
3727
|
if (mode === "create-desc") {
|
|
3834
|
-
return /* @__PURE__ */
|
|
3728
|
+
return /* @__PURE__ */ jsx27(
|
|
3835
3729
|
ProfileCreateDesc,
|
|
3836
3730
|
{
|
|
3837
3731
|
name: newName,
|
|
@@ -3848,13 +3742,13 @@ function ProfilesView() {
|
|
|
3848
3742
|
);
|
|
3849
3743
|
}
|
|
3850
3744
|
if (mode === "edit-name") {
|
|
3851
|
-
return /* @__PURE__ */
|
|
3745
|
+
return /* @__PURE__ */ jsx27(ProfileEditName, { defaultName: editName, onSubmit: (val) => {
|
|
3852
3746
|
setEditName(val);
|
|
3853
3747
|
setMode("edit-desc");
|
|
3854
3748
|
} });
|
|
3855
3749
|
}
|
|
3856
3750
|
if (mode === "edit-desc") {
|
|
3857
|
-
return /* @__PURE__ */
|
|
3751
|
+
return /* @__PURE__ */ jsx27(
|
|
3858
3752
|
ProfileEditDesc,
|
|
3859
3753
|
{
|
|
3860
3754
|
name: editName,
|
|
@@ -3872,9 +3766,9 @@ function ProfilesView() {
|
|
|
3872
3766
|
);
|
|
3873
3767
|
}
|
|
3874
3768
|
if (mode === "detail" && selectedProfile) {
|
|
3875
|
-
return /* @__PURE__ */
|
|
3769
|
+
return /* @__PURE__ */ jsx27(ProfileDetailMode, { profile: selectedProfile });
|
|
3876
3770
|
}
|
|
3877
|
-
return /* @__PURE__ */
|
|
3771
|
+
return /* @__PURE__ */ jsx27(
|
|
3878
3772
|
ProfileListMode,
|
|
3879
3773
|
{
|
|
3880
3774
|
profileNames,
|
|
@@ -3891,8 +3785,8 @@ function ProfilesView() {
|
|
|
3891
3785
|
}
|
|
3892
3786
|
|
|
3893
3787
|
// src/views/smart-cleanup.tsx
|
|
3894
|
-
import { useEffect as
|
|
3895
|
-
import { Box as
|
|
3788
|
+
import { useEffect as useEffect13, useRef as useRef7, useState as useState9 } from "react";
|
|
3789
|
+
import { Box as Box26, Text as Text27, useInput as useInput12 } from "ink";
|
|
3896
3790
|
|
|
3897
3791
|
// src/stores/cleanup-store.ts
|
|
3898
3792
|
import { create as create10 } from "zustand";
|
|
@@ -4012,7 +3906,7 @@ var useCleanupStore = create10((set, get) => ({
|
|
|
4012
3906
|
}));
|
|
4013
3907
|
|
|
4014
3908
|
// src/views/smart-cleanup.tsx
|
|
4015
|
-
import { jsx as
|
|
3909
|
+
import { jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
4016
3910
|
function SmartCleanupView() {
|
|
4017
3911
|
const { summary, selected, loading, error, analyze, toggleSelect, selectAll } = useCleanupStore();
|
|
4018
3912
|
const [cursor, setCursor] = useState9(0);
|
|
@@ -4021,10 +3915,10 @@ function SmartCleanupView() {
|
|
|
4021
3915
|
const [failedNames, setFailedNames] = useState9([]);
|
|
4022
3916
|
const stream = useBrewStream();
|
|
4023
3917
|
const hasRefreshed = useRef7(false);
|
|
4024
|
-
|
|
3918
|
+
useEffect13(() => {
|
|
4025
3919
|
analyze();
|
|
4026
3920
|
}, []);
|
|
4027
|
-
|
|
3921
|
+
useEffect13(() => {
|
|
4028
3922
|
if (!stream.isRunning && !stream.error && stream.lines.length > 0 && !hasRefreshed.current) {
|
|
4029
3923
|
hasRefreshed.current = true;
|
|
4030
3924
|
void analyze();
|
|
@@ -4032,7 +3926,7 @@ function SmartCleanupView() {
|
|
|
4032
3926
|
}, [stream.isRunning, stream.error]);
|
|
4033
3927
|
const candidates = summary?.candidates ?? [];
|
|
4034
3928
|
const isDependencyError = stream.error != null && stream.lines.some((l) => l.includes("Refusing to uninstall") || l.includes("required by"));
|
|
4035
|
-
|
|
3929
|
+
useInput12((input, key) => {
|
|
4036
3930
|
if (stream.isRunning) {
|
|
4037
3931
|
if (key.escape) stream.cancel();
|
|
4038
3932
|
return;
|
|
@@ -4063,26 +3957,26 @@ function SmartCleanupView() {
|
|
|
4063
3957
|
if (input === "j" || key.downArrow) setCursor((c) => Math.min(c + 1, Math.max(0, candidates.length - 1)));
|
|
4064
3958
|
else if (input === "k" || key.upArrow) setCursor((c) => Math.max(c - 1, 0));
|
|
4065
3959
|
});
|
|
4066
|
-
if (loading) return /* @__PURE__ */
|
|
4067
|
-
if (error) return /* @__PURE__ */
|
|
3960
|
+
if (loading) return /* @__PURE__ */ jsx28(Loading, { message: t("loading_cleanup") });
|
|
3961
|
+
if (error) return /* @__PURE__ */ jsx28(ErrorMessage, { message: error });
|
|
4068
3962
|
if (stream.isRunning || stream.lines.length > 0) {
|
|
4069
|
-
return /* @__PURE__ */
|
|
4070
|
-
/* @__PURE__ */
|
|
4071
|
-
stream.isRunning && /* @__PURE__ */
|
|
3963
|
+
return /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", children: [
|
|
3964
|
+
/* @__PURE__ */ jsx28(ProgressLog, { lines: stream.lines, isRunning: stream.isRunning, title: t("cleanup_cleaning") }),
|
|
3965
|
+
stream.isRunning && /* @__PURE__ */ jsxs27(Text27, { color: COLORS.muted, children: [
|
|
4072
3966
|
"esc:",
|
|
4073
3967
|
t("hint_cancel")
|
|
4074
3968
|
] }),
|
|
4075
|
-
!stream.isRunning && !stream.error && /* @__PURE__ */
|
|
4076
|
-
!stream.isRunning && stream.error && /* @__PURE__ */
|
|
4077
|
-
/* @__PURE__ */
|
|
4078
|
-
isDependencyError && failedNames.length > 0 && /* @__PURE__ */
|
|
3969
|
+
!stream.isRunning && !stream.error && /* @__PURE__ */ jsx28(ResultBanner, { status: "success", message: `\u2714 ${t("cleanup_complete")}` }),
|
|
3970
|
+
!stream.isRunning && stream.error && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", gap: SPACING.xs, children: [
|
|
3971
|
+
/* @__PURE__ */ jsx28(ResultBanner, { status: "error", message: `\u2718 ${t("cleanup_depError")}` }),
|
|
3972
|
+
isDependencyError && failedNames.length > 0 && /* @__PURE__ */ jsxs27(Text27, { color: COLORS.warning, children: [
|
|
4079
3973
|
"F:",
|
|
4080
3974
|
t("hint_force"),
|
|
4081
3975
|
" r:",
|
|
4082
3976
|
t("hint_refresh")
|
|
4083
3977
|
] })
|
|
4084
3978
|
] }),
|
|
4085
|
-
confirmForce && /* @__PURE__ */
|
|
3979
|
+
confirmForce && /* @__PURE__ */ jsx28(Box26, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx28(
|
|
4086
3980
|
ConfirmDialog,
|
|
4087
3981
|
{
|
|
4088
3982
|
message: t("cleanup_confirmForce", { count: failedNames.length }),
|
|
@@ -4097,16 +3991,16 @@ function SmartCleanupView() {
|
|
|
4097
3991
|
) })
|
|
4098
3992
|
] });
|
|
4099
3993
|
}
|
|
4100
|
-
return /* @__PURE__ */
|
|
4101
|
-
/* @__PURE__ */
|
|
4102
|
-
summary && /* @__PURE__ */
|
|
4103
|
-
/* @__PURE__ */
|
|
4104
|
-
/* @__PURE__ */
|
|
4105
|
-
/* @__PURE__ */
|
|
3994
|
+
return /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", children: [
|
|
3995
|
+
/* @__PURE__ */ jsx28(SectionHeader, { emoji: "\u{1F9F9}", title: t("cleanup_title"), gradient: GRADIENTS.emerald }),
|
|
3996
|
+
summary && /* @__PURE__ */ jsxs27(Box26, { gap: SPACING.xs, marginY: SPACING.xs, children: [
|
|
3997
|
+
/* @__PURE__ */ jsx28(StatCard, { label: t("cleanup_orphans"), value: candidates.length, color: candidates.length > 0 ? COLORS.warning : COLORS.success }),
|
|
3998
|
+
/* @__PURE__ */ jsx28(StatCard, { label: t("cleanup_reclaimable"), value: summary.totalReclaimableFormatted, color: COLORS.sky }),
|
|
3999
|
+
/* @__PURE__ */ jsx28(StatCard, { label: t("cleanup_selected"), value: selected.size, color: selected.size > 0 ? COLORS.success : COLORS.muted })
|
|
4106
4000
|
] }),
|
|
4107
|
-
confirmClean && /* @__PURE__ */
|
|
4108
|
-
/* @__PURE__ */
|
|
4109
|
-
/* @__PURE__ */
|
|
4001
|
+
confirmClean && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", marginY: SPACING.xs, gap: SPACING.xs, children: [
|
|
4002
|
+
/* @__PURE__ */ jsx28(Box26, { borderStyle: "round", borderColor: COLORS.warning, paddingX: SPACING.sm, paddingY: SPACING.none, children: /* @__PURE__ */ jsx28(Text27, { color: COLORS.warning, children: t("cleanup_warning_system_tools") }) }),
|
|
4003
|
+
/* @__PURE__ */ jsx28(
|
|
4110
4004
|
ConfirmDialog,
|
|
4111
4005
|
{
|
|
4112
4006
|
message: t("cleanup_confirmUninstall", { count: selected.size }),
|
|
@@ -4121,23 +4015,23 @@ function SmartCleanupView() {
|
|
|
4121
4015
|
}
|
|
4122
4016
|
)
|
|
4123
4017
|
] }),
|
|
4124
|
-
candidates.length === 0 && !confirmClean && /* @__PURE__ */
|
|
4125
|
-
candidates.length > 0 && !confirmClean && /* @__PURE__ */
|
|
4018
|
+
candidates.length === 0 && !confirmClean && /* @__PURE__ */ jsx28(ResultBanner, { status: "success", message: `\u2714 ${t("cleanup_systemClean")}` }),
|
|
4019
|
+
candidates.length > 0 && !confirmClean && /* @__PURE__ */ jsxs27(Box26, { flexDirection: "column", children: [
|
|
4126
4020
|
candidates.map((c, i) => {
|
|
4127
4021
|
const isCurrent = i === cursor;
|
|
4128
4022
|
const isSelected = selected.has(c.name);
|
|
4129
|
-
return /* @__PURE__ */
|
|
4130
|
-
/* @__PURE__ */
|
|
4131
|
-
/* @__PURE__ */
|
|
4132
|
-
/* @__PURE__ */
|
|
4133
|
-
/* @__PURE__ */
|
|
4023
|
+
return /* @__PURE__ */ jsxs27(SelectableRow, { isCurrent, children: [
|
|
4024
|
+
/* @__PURE__ */ jsx28(Text27, { color: isSelected ? COLORS.success : COLORS.muted, children: isSelected ? "\u2611" : "\u2610" }),
|
|
4025
|
+
/* @__PURE__ */ jsx28(Text27, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: c.name }),
|
|
4026
|
+
/* @__PURE__ */ jsx28(Text27, { color: COLORS.warning, children: c.diskUsageFormatted }),
|
|
4027
|
+
/* @__PURE__ */ jsxs27(Text27, { color: COLORS.textSecondary, children: [
|
|
4134
4028
|
"[",
|
|
4135
4029
|
c.reason,
|
|
4136
4030
|
"]"
|
|
4137
4031
|
] })
|
|
4138
4032
|
] }, c.name);
|
|
4139
4033
|
}),
|
|
4140
|
-
/* @__PURE__ */
|
|
4034
|
+
/* @__PURE__ */ jsx28(Box26, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs27(Text27, { color: COLORS.text, bold: true, children: [
|
|
4141
4035
|
cursor + 1,
|
|
4142
4036
|
"/",
|
|
4143
4037
|
candidates.length
|
|
@@ -4147,8 +4041,8 @@ function SmartCleanupView() {
|
|
|
4147
4041
|
}
|
|
4148
4042
|
|
|
4149
4043
|
// src/views/history.tsx
|
|
4150
|
-
import { useEffect as
|
|
4151
|
-
import { Box as
|
|
4044
|
+
import { useEffect as useEffect14, useState as useState10, useMemo as useMemo5 } from "react";
|
|
4045
|
+
import { Box as Box27, Text as Text28, useInput as useInput13, useStdout as useStdout7 } from "ink";
|
|
4152
4046
|
|
|
4153
4047
|
// src/stores/history-store.ts
|
|
4154
4048
|
import { create as create11 } from "zustand";
|
|
@@ -4184,7 +4078,7 @@ var useHistoryStore = create11((set) => ({
|
|
|
4184
4078
|
}));
|
|
4185
4079
|
|
|
4186
4080
|
// src/views/history.tsx
|
|
4187
|
-
import { jsx as
|
|
4081
|
+
import { jsx as jsx29, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
4188
4082
|
var ACTION_ICONS = {
|
|
4189
4083
|
install: { icon: "+", color: COLORS.success },
|
|
4190
4084
|
uninstall: { icon: "-", color: COLORS.error },
|
|
@@ -4209,10 +4103,12 @@ function HistoryView() {
|
|
|
4209
4103
|
const stream = useBrewStream();
|
|
4210
4104
|
const debouncedQuery = useDebounce(searchQuery, 200);
|
|
4211
4105
|
const { openModal, closeModal } = useModalStore();
|
|
4212
|
-
|
|
4106
|
+
const { stdout } = useStdout7();
|
|
4107
|
+
const MAX_VISIBLE_ROWS = Math.max(5, (stdout?.rows ?? 24) - 8);
|
|
4108
|
+
useEffect14(() => {
|
|
4213
4109
|
fetchHistory();
|
|
4214
4110
|
}, []);
|
|
4215
|
-
|
|
4111
|
+
useEffect14(() => {
|
|
4216
4112
|
if (isSearching) {
|
|
4217
4113
|
openModal();
|
|
4218
4114
|
return () => {
|
|
@@ -4221,7 +4117,7 @@ function HistoryView() {
|
|
|
4221
4117
|
}
|
|
4222
4118
|
return void 0;
|
|
4223
4119
|
}, [isSearching]);
|
|
4224
|
-
const filtered =
|
|
4120
|
+
const filtered = useMemo5(() => {
|
|
4225
4121
|
let result = entries;
|
|
4226
4122
|
if (filter !== "all") {
|
|
4227
4123
|
result = result.filter((e) => e.action === filter);
|
|
@@ -4232,7 +4128,7 @@ function HistoryView() {
|
|
|
4232
4128
|
}
|
|
4233
4129
|
return result;
|
|
4234
4130
|
}, [entries, filter, debouncedQuery]);
|
|
4235
|
-
|
|
4131
|
+
useInput13((input, key) => {
|
|
4236
4132
|
if (confirmClear || confirmReplay || stream.isRunning) return;
|
|
4237
4133
|
if (isSearching) {
|
|
4238
4134
|
if (key.escape) {
|
|
@@ -4262,19 +4158,17 @@ function HistoryView() {
|
|
|
4262
4158
|
if (input === "j" || key.downArrow) setCursor((c) => Math.min(c + 1, Math.max(0, filtered.length - 1)));
|
|
4263
4159
|
else if (input === "k" || key.upArrow) setCursor((c) => Math.max(c - 1, 0));
|
|
4264
4160
|
});
|
|
4265
|
-
if (loading) return /* @__PURE__ */
|
|
4266
|
-
if (error) return /* @__PURE__ */
|
|
4267
|
-
const { stdout } = useStdout7();
|
|
4268
|
-
const MAX_VISIBLE_ROWS = Math.max(5, (stdout?.rows ?? 24) - 8);
|
|
4161
|
+
if (loading) return /* @__PURE__ */ jsx29(Loading, { message: t("loading_history") });
|
|
4162
|
+
if (error) return /* @__PURE__ */ jsx29(ErrorMessage, { message: error });
|
|
4269
4163
|
const start = Math.max(0, cursor - Math.floor(MAX_VISIBLE_ROWS / 2));
|
|
4270
4164
|
const visible = filtered.slice(start, start + MAX_VISIBLE_ROWS);
|
|
4271
|
-
return /* @__PURE__ */
|
|
4272
|
-
/* @__PURE__ */
|
|
4273
|
-
/* @__PURE__ */
|
|
4274
|
-
/* @__PURE__ */
|
|
4165
|
+
return /* @__PURE__ */ jsxs28(Box27, { flexDirection: "column", children: [
|
|
4166
|
+
/* @__PURE__ */ jsxs28(Box27, { gap: SPACING.sm, marginBottom: SPACING.xs, children: [
|
|
4167
|
+
/* @__PURE__ */ jsx29(SectionHeader, { emoji: "\u{1F4DC}", title: t("history_title", { count: filtered.length }), gradient: GRADIENTS.gold }),
|
|
4168
|
+
/* @__PURE__ */ jsx29(Text28, { color: filter === "all" ? COLORS.text : COLORS.gold, children: t("history_filterLabel", { filter }) })
|
|
4275
4169
|
] }),
|
|
4276
|
-
isSearching && /* @__PURE__ */
|
|
4277
|
-
confirmClear && /* @__PURE__ */
|
|
4170
|
+
isSearching && /* @__PURE__ */ jsx29(Box27, { marginBottom: SPACING.xs, children: /* @__PURE__ */ jsx29(SearchInput, { defaultValue: searchQuery, onChange: setSearchQuery, placeholder: t("history_searchPlaceholder"), isActive: true }) }),
|
|
4171
|
+
confirmClear && /* @__PURE__ */ jsx29(
|
|
4278
4172
|
ConfirmDialog,
|
|
4279
4173
|
{
|
|
4280
4174
|
message: t("history_confirmClear", { count: entries.length }),
|
|
@@ -4285,7 +4179,7 @@ function HistoryView() {
|
|
|
4285
4179
|
onCancel: () => setConfirmClear(false)
|
|
4286
4180
|
}
|
|
4287
4181
|
),
|
|
4288
|
-
confirmReplay && /* @__PURE__ */
|
|
4182
|
+
confirmReplay && /* @__PURE__ */ jsx29(
|
|
4289
4183
|
ConfirmDialog,
|
|
4290
4184
|
{
|
|
4291
4185
|
message: confirmReplay.action === "upgrade-all" ? t("history_replayAll") + "\n" + t("upgrade_all_warning") : t("history_confirmReplay", { action: t(ACTION_LABEL_KEYS[confirmReplay.action]), name: confirmReplay.packageName ?? "" }),
|
|
@@ -4313,10 +4207,10 @@ function HistoryView() {
|
|
|
4313
4207
|
onCancel: () => setConfirmReplay(null)
|
|
4314
4208
|
}
|
|
4315
4209
|
),
|
|
4316
|
-
(stream.isRunning || stream.lines.length > 0) && /* @__PURE__ */
|
|
4317
|
-
filtered.length === 0 && !confirmClear && /* @__PURE__ */
|
|
4318
|
-
filtered.length > 0 && !confirmClear && /* @__PURE__ */
|
|
4319
|
-
start > 0 && /* @__PURE__ */
|
|
4210
|
+
(stream.isRunning || stream.lines.length > 0) && /* @__PURE__ */ jsx29(Box27, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx29(ProgressLog, { lines: stream.lines, isRunning: stream.isRunning, title: t("hint_replay") }) }),
|
|
4211
|
+
filtered.length === 0 && !confirmClear && /* @__PURE__ */ jsx29(Text28, { color: COLORS.textSecondary, italic: true, children: filter !== "all" ? t("history_noEntriesFor", { filter }) : t("history_noEntries") }),
|
|
4212
|
+
filtered.length > 0 && !confirmClear && /* @__PURE__ */ jsxs28(Box27, { flexDirection: "column", children: [
|
|
4213
|
+
start > 0 && /* @__PURE__ */ jsxs28(Text28, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
4320
4214
|
" ",
|
|
4321
4215
|
t("scroll_moreAbove", { count: start })
|
|
4322
4216
|
] }),
|
|
@@ -4325,19 +4219,19 @@ function HistoryView() {
|
|
|
4325
4219
|
const isCurrent = idx === cursor;
|
|
4326
4220
|
const { icon, color } = ACTION_ICONS[entry.action];
|
|
4327
4221
|
const ts = new Date(entry.timestamp).getTime() / 1e3;
|
|
4328
|
-
return /* @__PURE__ */
|
|
4329
|
-
/* @__PURE__ */
|
|
4330
|
-
/* @__PURE__ */
|
|
4331
|
-
/* @__PURE__ */
|
|
4332
|
-
entry.success ? /* @__PURE__ */
|
|
4333
|
-
/* @__PURE__ */
|
|
4222
|
+
return /* @__PURE__ */ jsxs28(SelectableRow, { isCurrent, children: [
|
|
4223
|
+
/* @__PURE__ */ jsx29(Text28, { color, bold: true, children: icon }),
|
|
4224
|
+
/* @__PURE__ */ jsx29(Text28, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: t(ACTION_LABEL_KEYS[entry.action]).padEnd(12) }),
|
|
4225
|
+
/* @__PURE__ */ jsx29(Text28, { color: COLORS.text, children: entry.packageName ?? t("history_all") }),
|
|
4226
|
+
entry.success ? /* @__PURE__ */ jsx29(StatusBadge, { label: t("badge_ok"), variant: "success" }) : /* @__PURE__ */ jsx29(StatusBadge, { label: t("badge_fail"), variant: "error" }),
|
|
4227
|
+
/* @__PURE__ */ jsx29(Text28, { color: COLORS.muted, children: formatRelativeTime(ts) })
|
|
4334
4228
|
] }, entry.id);
|
|
4335
4229
|
}),
|
|
4336
|
-
start + MAX_VISIBLE_ROWS < filtered.length && /* @__PURE__ */
|
|
4230
|
+
start + MAX_VISIBLE_ROWS < filtered.length && /* @__PURE__ */ jsxs28(Text28, { color: COLORS.textSecondary, dimColor: true, children: [
|
|
4337
4231
|
" ",
|
|
4338
4232
|
t("scroll_moreBelow", { count: filtered.length - start - MAX_VISIBLE_ROWS })
|
|
4339
4233
|
] }),
|
|
4340
|
-
/* @__PURE__ */
|
|
4234
|
+
/* @__PURE__ */ jsx29(Box27, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs28(Text28, { color: COLORS.text, bold: true, children: [
|
|
4341
4235
|
cursor + 1,
|
|
4342
4236
|
"/",
|
|
4343
4237
|
filtered.length
|
|
@@ -4347,9 +4241,9 @@ function HistoryView() {
|
|
|
4347
4241
|
}
|
|
4348
4242
|
|
|
4349
4243
|
// src/views/security-audit.tsx
|
|
4350
|
-
import { useEffect as
|
|
4351
|
-
import { Box as
|
|
4352
|
-
import { jsx as
|
|
4244
|
+
import { useEffect as useEffect15, useState as useState11 } from "react";
|
|
4245
|
+
import { Box as Box28, Text as Text29, useInput as useInput14 } from "ink";
|
|
4246
|
+
import { jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4353
4247
|
var SEVERITY_COLORS = {
|
|
4354
4248
|
CRITICAL: COLORS.error,
|
|
4355
4249
|
HIGH: COLORS.error,
|
|
@@ -4364,7 +4258,7 @@ var SEVERITY_BADGE = {
|
|
|
4364
4258
|
LOW: "muted",
|
|
4365
4259
|
UNKNOWN: "muted"
|
|
4366
4260
|
};
|
|
4367
|
-
function
|
|
4261
|
+
function isNetworkError(msg) {
|
|
4368
4262
|
return /fetch failed|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|network|abort/i.test(msg);
|
|
4369
4263
|
}
|
|
4370
4264
|
function SecurityAuditView() {
|
|
@@ -4374,11 +4268,11 @@ function SecurityAuditView() {
|
|
|
4374
4268
|
const [expandedPkg, setExpandedPkg] = useState11(null);
|
|
4375
4269
|
const [confirmUpgrade, setConfirmUpgrade] = useState11(null);
|
|
4376
4270
|
const stream = useBrewStream();
|
|
4377
|
-
|
|
4271
|
+
useEffect15(() => {
|
|
4378
4272
|
scan();
|
|
4379
4273
|
}, []);
|
|
4380
4274
|
const results = summary?.results ?? [];
|
|
4381
|
-
|
|
4275
|
+
useInput14((input, key) => {
|
|
4382
4276
|
if (confirmUpgrade || stream.isRunning) return;
|
|
4383
4277
|
if (input === "r") {
|
|
4384
4278
|
void scan(true);
|
|
@@ -4398,17 +4292,17 @@ function SecurityAuditView() {
|
|
|
4398
4292
|
setExpandedPkg(expandedPkg === results[cursor].packageName ? null : results[cursor].packageName);
|
|
4399
4293
|
}
|
|
4400
4294
|
});
|
|
4401
|
-
if (loading) return /* @__PURE__ */
|
|
4295
|
+
if (loading) return /* @__PURE__ */ jsx30(Loading, { message: t("loading_security") });
|
|
4402
4296
|
if (error) {
|
|
4403
|
-
const displayError =
|
|
4404
|
-
return /* @__PURE__ */
|
|
4297
|
+
const displayError = isNetworkError(error) ? t("security_networkError") : error;
|
|
4298
|
+
return /* @__PURE__ */ jsx30(ErrorMessage, { message: displayError });
|
|
4405
4299
|
}
|
|
4406
4300
|
const cacheAge = cachedAt ? formatRelativeTime(cachedAt / 1e3) : null;
|
|
4407
|
-
return /* @__PURE__ */
|
|
4408
|
-
/* @__PURE__ */
|
|
4409
|
-
summary && /* @__PURE__ */
|
|
4410
|
-
/* @__PURE__ */
|
|
4411
|
-
/* @__PURE__ */
|
|
4301
|
+
return /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", children: [
|
|
4302
|
+
/* @__PURE__ */ jsx30(SectionHeader, { emoji: "\u{1F6E1}\uFE0F", title: t("security_title"), gradient: GRADIENTS.ocean }),
|
|
4303
|
+
summary && /* @__PURE__ */ jsxs29(Box28, { gap: SPACING.xs, marginY: SPACING.xs, children: [
|
|
4304
|
+
/* @__PURE__ */ jsx30(StatCard, { label: t("security_scanned"), value: summary.totalPackages, color: COLORS.info }),
|
|
4305
|
+
/* @__PURE__ */ jsx30(
|
|
4412
4306
|
StatCard,
|
|
4413
4307
|
{
|
|
4414
4308
|
label: t("security_vulnerable"),
|
|
@@ -4416,13 +4310,14 @@ function SecurityAuditView() {
|
|
|
4416
4310
|
color: summary.vulnerablePackages > 0 ? COLORS.error : COLORS.success
|
|
4417
4311
|
}
|
|
4418
4312
|
),
|
|
4419
|
-
summary.criticalCount > 0 && /* @__PURE__ */
|
|
4420
|
-
summary.highCount > 0 && /* @__PURE__ */
|
|
4421
|
-
summary.mediumCount > 0 && /* @__PURE__ */
|
|
4313
|
+
summary.criticalCount > 0 && /* @__PURE__ */ jsx30(StatCard, { label: t("security_critical"), value: summary.criticalCount, color: COLORS.error }),
|
|
4314
|
+
summary.highCount > 0 && /* @__PURE__ */ jsx30(StatCard, { label: t("security_high"), value: summary.highCount, color: COLORS.error }),
|
|
4315
|
+
summary.mediumCount > 0 && /* @__PURE__ */ jsx30(StatCard, { label: t("security_medium"), value: summary.mediumCount, color: COLORS.warning })
|
|
4422
4316
|
] }),
|
|
4423
|
-
cacheAge && /* @__PURE__ */
|
|
4424
|
-
|
|
4425
|
-
|
|
4317
|
+
cacheAge && /* @__PURE__ */ jsx30(Text29, { color: COLORS.muted, children: t("security_cachedResults", { time: cacheAge }) }),
|
|
4318
|
+
summary && /* @__PURE__ */ jsx30(Box28, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx30(Text29, { color: COLORS.textSecondary, italic: true, children: t("security_coverage_warning") }) }),
|
|
4319
|
+
results.length === 0 && summary && /* @__PURE__ */ jsx30(Box28, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx30(ResultBanner, { status: "success", message: `\u2714 ${t("security_noVulns")}` }) }),
|
|
4320
|
+
confirmUpgrade && /* @__PURE__ */ jsx30(Box28, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx30(
|
|
4426
4321
|
ConfirmDialog,
|
|
4427
4322
|
{
|
|
4428
4323
|
message: t("security_confirmUpgrade", { name: confirmUpgrade }),
|
|
@@ -4435,82 +4330,83 @@ function SecurityAuditView() {
|
|
|
4435
4330
|
onCancel: () => setConfirmUpgrade(null)
|
|
4436
4331
|
}
|
|
4437
4332
|
) }),
|
|
4438
|
-
(stream.isRunning || stream.lines.length > 0) && /* @__PURE__ */
|
|
4439
|
-
results.length > 0 && /* @__PURE__ */
|
|
4333
|
+
(stream.isRunning || stream.lines.length > 0) && /* @__PURE__ */ jsx30(Box28, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx30(ProgressLog, { lines: stream.lines, isRunning: stream.isRunning, title: t("hint_upgrade") }) }),
|
|
4334
|
+
results.length > 0 && /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
4440
4335
|
results.map((pkg, i) => {
|
|
4441
4336
|
const isCurrent = i === cursor;
|
|
4442
4337
|
const isExpanded = expandedPkg === pkg.packageName;
|
|
4443
|
-
return /* @__PURE__ */
|
|
4444
|
-
/* @__PURE__ */
|
|
4445
|
-
/* @__PURE__ */
|
|
4446
|
-
/* @__PURE__ */
|
|
4447
|
-
/* @__PURE__ */
|
|
4448
|
-
/* @__PURE__ */
|
|
4449
|
-
pkg.vulnerabilities.some((v) => v.fixedVersion) && /* @__PURE__ */
|
|
4338
|
+
return /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", children: [
|
|
4339
|
+
/* @__PURE__ */ jsxs29(SelectableRow, { isCurrent, children: [
|
|
4340
|
+
/* @__PURE__ */ jsx30(StatusBadge, { label: pkg.maxSeverity, variant: SEVERITY_BADGE[pkg.maxSeverity] }),
|
|
4341
|
+
/* @__PURE__ */ jsx30(Text29, { bold: isCurrent, inverse: isCurrent, color: isCurrent ? COLORS.text : COLORS.muted, children: pkg.packageName }),
|
|
4342
|
+
/* @__PURE__ */ jsx30(Text29, { color: COLORS.muted, children: pkg.installedVersion }),
|
|
4343
|
+
/* @__PURE__ */ jsx30(Text29, { color: COLORS.muted, children: tp("plural_vulns", pkg.vulnerabilities.length) }),
|
|
4344
|
+
pkg.vulnerabilities.some((v) => v.fixedVersion) && /* @__PURE__ */ jsxs29(Text29, { color: COLORS.textSecondary, children: [
|
|
4450
4345
|
"[R:",
|
|
4451
4346
|
t("hint_rollback"),
|
|
4452
4347
|
"]"
|
|
4453
4348
|
] }),
|
|
4454
|
-
/* @__PURE__ */
|
|
4349
|
+
/* @__PURE__ */ jsx30(Text29, { color: COLORS.muted, children: isExpanded ? "\u25BC" : "\u25B6" })
|
|
4455
4350
|
] }),
|
|
4456
|
-
isExpanded && /* @__PURE__ */
|
|
4457
|
-
/* @__PURE__ */
|
|
4458
|
-
/* @__PURE__ */
|
|
4459
|
-
/* @__PURE__ */
|
|
4351
|
+
isExpanded && /* @__PURE__ */ jsx30(Box28, { flexDirection: "column", paddingLeft: SPACING.lg, marginBottom: SPACING.xs, children: pkg.vulnerabilities.map((vuln) => /* @__PURE__ */ jsxs29(Box28, { flexDirection: "column", marginBottom: SPACING.xs, children: [
|
|
4352
|
+
/* @__PURE__ */ jsxs29(Box28, { gap: SPACING.xs, children: [
|
|
4353
|
+
/* @__PURE__ */ jsx30(Text29, { color: SEVERITY_COLORS[vuln.severity], bold: true, children: vuln.id }),
|
|
4354
|
+
/* @__PURE__ */ jsxs29(Text29, { color: COLORS.muted, children: [
|
|
4460
4355
|
"[",
|
|
4461
4356
|
vuln.severity,
|
|
4462
4357
|
"]"
|
|
4463
4358
|
] })
|
|
4464
4359
|
] }),
|
|
4465
|
-
/* @__PURE__ */
|
|
4466
|
-
vuln.fixedVersion && /* @__PURE__ */
|
|
4360
|
+
/* @__PURE__ */ jsx30(Text29, { color: COLORS.muted, wrap: "wrap", children: vuln.summary }),
|
|
4361
|
+
vuln.fixedVersion && /* @__PURE__ */ jsx30(Text29, { color: COLORS.success, children: t("security_fixedIn", { version: vuln.fixedVersion }) })
|
|
4467
4362
|
] }, vuln.id)) })
|
|
4468
4363
|
] }, pkg.packageName);
|
|
4469
4364
|
}),
|
|
4470
|
-
/* @__PURE__ */
|
|
4365
|
+
/* @__PURE__ */ jsx30(Box28, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs29(Text29, { color: COLORS.text, bold: true, children: [
|
|
4471
4366
|
cursor + 1,
|
|
4472
4367
|
"/",
|
|
4473
4368
|
results.length
|
|
4474
4369
|
] }) }),
|
|
4475
|
-
/* @__PURE__ */
|
|
4370
|
+
/* @__PURE__ */ jsx30(Box28, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx30(Text29, { color: COLORS.textSecondary, children: t("security_rollback_hint") }) })
|
|
4476
4371
|
] })
|
|
4477
4372
|
] });
|
|
4478
4373
|
}
|
|
4479
4374
|
|
|
4480
4375
|
// src/views/account.tsx
|
|
4481
4376
|
import { useState as useState12 } from "react";
|
|
4482
|
-
import { Box as
|
|
4377
|
+
import { Box as Box29, Text as Text30, useInput as useInput15 } from "ink";
|
|
4483
4378
|
import { TextInput as TextInput5 } from "@inkjs/ui";
|
|
4484
4379
|
|
|
4485
4380
|
// src/lib/license/promo.ts
|
|
4486
|
-
import { readFile as
|
|
4487
|
-
import { randomBytes
|
|
4488
|
-
import { join as
|
|
4489
|
-
|
|
4490
|
-
var
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
}
|
|
4381
|
+
import { readFile as readFile2, writeFile as writeFile3, rename as rename2 } from "fs/promises";
|
|
4382
|
+
import { randomBytes, randomUUID } from "crypto";
|
|
4383
|
+
import { join as join2 } from "path";
|
|
4384
|
+
var PROMO_PATH = join2(DATA_DIR, "promo.json");
|
|
4385
|
+
var PROMO_API_URL = "https://api.molinesdesigns.com/api/promo";
|
|
4386
|
+
function validatePromoApiUrl(url) {
|
|
4387
|
+
const parsed = new URL(url);
|
|
4388
|
+
if (parsed.protocol !== "https:") {
|
|
4389
|
+
throw new Error("HTTPS required for promo API");
|
|
4390
|
+
}
|
|
4391
|
+
if (!parsed.hostname.endsWith("molinesdesigns.com")) {
|
|
4392
|
+
throw new Error("Invalid promo API host");
|
|
4496
4393
|
}
|
|
4497
|
-
const id = randomUUID2();
|
|
4498
|
-
await mkdir2(join3(homedir2(), ".brew-tui"), { recursive: true, mode: 448 });
|
|
4499
|
-
await writeFile4(MACHINE_ID_PATH2, id, { encoding: "utf-8", mode: 384 });
|
|
4500
|
-
return id;
|
|
4501
4394
|
}
|
|
4502
|
-
var PROMO_PATH = join3(DATA_DIR, "promo.json");
|
|
4503
|
-
var PROMO_API_URL = "https://api.molinesdesigns.com/api/promo";
|
|
4504
4395
|
async function redeemPromoCode(code) {
|
|
4505
4396
|
const normalized = code.trim().toUpperCase();
|
|
4506
|
-
const machineId = await
|
|
4397
|
+
const machineId = await getMachineId();
|
|
4398
|
+
validatePromoApiUrl(`${PROMO_API_URL}/redeem`);
|
|
4507
4399
|
let serverExpiresAt;
|
|
4508
4400
|
let serverType;
|
|
4401
|
+
const idempotencyKey = randomUUID();
|
|
4509
4402
|
try {
|
|
4510
4403
|
const res = await fetchWithTimeout(`${PROMO_API_URL}/redeem`, {
|
|
4511
4404
|
method: "POST",
|
|
4512
|
-
headers: {
|
|
4513
|
-
|
|
4405
|
+
headers: {
|
|
4406
|
+
"Content-Type": "application/json",
|
|
4407
|
+
"Idempotency-Key": idempotencyKey
|
|
4408
|
+
},
|
|
4409
|
+
body: JSON.stringify({ code: normalized, machineId, idempotencyKey })
|
|
4514
4410
|
}, 1e4);
|
|
4515
4411
|
if (!res.ok) {
|
|
4516
4412
|
const body = await res.json().catch(() => ({}));
|
|
@@ -4541,7 +4437,7 @@ async function redeemPromoCode(code) {
|
|
|
4541
4437
|
};
|
|
4542
4438
|
let file = { version: 1, redemptions: [] };
|
|
4543
4439
|
try {
|
|
4544
|
-
const raw = await
|
|
4440
|
+
const raw = await readFile2(PROMO_PATH, "utf-8");
|
|
4545
4441
|
file = JSON.parse(raw);
|
|
4546
4442
|
} catch {
|
|
4547
4443
|
}
|
|
@@ -4550,23 +4446,24 @@ async function redeemPromoCode(code) {
|
|
|
4550
4446
|
}
|
|
4551
4447
|
file.redemptions.push(redemption);
|
|
4552
4448
|
const tmpPath = PROMO_PATH + ".tmp";
|
|
4553
|
-
await
|
|
4554
|
-
await
|
|
4449
|
+
await writeFile3(tmpPath, JSON.stringify(file, null, 2), { encoding: "utf-8", mode: 384 });
|
|
4450
|
+
await rename2(tmpPath, PROMO_PATH);
|
|
4555
4451
|
return { success: true, expiresAt: redemption.expiresAt };
|
|
4556
4452
|
}
|
|
4557
4453
|
|
|
4558
4454
|
// src/views/account.tsx
|
|
4559
|
-
import { Fragment as Fragment5, jsx as
|
|
4455
|
+
import { Fragment as Fragment5, jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
4560
4456
|
function AccountView() {
|
|
4561
|
-
const { status, license, deactivate: deactivate2, degradation } = useLicenseStore();
|
|
4457
|
+
const { status, license, deactivate: deactivate2, revalidate: revalidate2, degradation } = useLicenseStore();
|
|
4562
4458
|
const [confirmDeactivate, setConfirmDeactivate] = useState12(false);
|
|
4563
4459
|
const [deactivating, setDeactivating] = useState12(false);
|
|
4564
4460
|
const [deactivateError, setDeactivateError] = useState12(null);
|
|
4565
4461
|
const [promoMode, setPromoMode] = useState12(false);
|
|
4566
4462
|
const [promoLoading, setPromoLoading] = useState12(false);
|
|
4567
4463
|
const [promoResult, setPromoResult] = useState12(null);
|
|
4568
|
-
|
|
4569
|
-
|
|
4464
|
+
const [revalidating, setRevalidating] = useState12(false);
|
|
4465
|
+
useInput15((input, key) => {
|
|
4466
|
+
if (confirmDeactivate || deactivating || promoMode || revalidating) {
|
|
4570
4467
|
if (key.escape && promoMode) {
|
|
4571
4468
|
setPromoMode(false);
|
|
4572
4469
|
setPromoResult(null);
|
|
@@ -4580,17 +4477,21 @@ function AccountView() {
|
|
|
4580
4477
|
setPromoMode(true);
|
|
4581
4478
|
setPromoResult(null);
|
|
4582
4479
|
}
|
|
4480
|
+
if ((input === "v" || input === "V") && (status === "pro" || status === "team" || status === "expired")) {
|
|
4481
|
+
setRevalidating(true);
|
|
4482
|
+
void revalidate2().finally(() => setRevalidating(false));
|
|
4483
|
+
}
|
|
4583
4484
|
});
|
|
4584
4485
|
const maskKey = (key) => {
|
|
4585
4486
|
if (key.length <= 8) return key;
|
|
4586
4487
|
return key.slice(0, 4) + "-****-****-" + key.slice(-4);
|
|
4587
4488
|
};
|
|
4588
4489
|
if (status === "validating") {
|
|
4589
|
-
return /* @__PURE__ */
|
|
4490
|
+
return /* @__PURE__ */ jsx31(Loading, { message: t("account_loading") });
|
|
4590
4491
|
}
|
|
4591
|
-
return /* @__PURE__ */
|
|
4592
|
-
/* @__PURE__ */
|
|
4593
|
-
confirmDeactivate && /* @__PURE__ */
|
|
4492
|
+
return /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", children: [
|
|
4493
|
+
/* @__PURE__ */ jsx31(SectionHeader, { emoji: "\u{1F464}", title: t("account_title"), gradient: GRADIENTS.gold }),
|
|
4494
|
+
confirmDeactivate && /* @__PURE__ */ jsx31(Box29, { marginY: SPACING.xs, children: /* @__PURE__ */ jsx31(
|
|
4594
4495
|
ConfirmDialog,
|
|
4595
4496
|
{
|
|
4596
4497
|
message: t("account_confirmDeactivate"),
|
|
@@ -4609,72 +4510,72 @@ function AccountView() {
|
|
|
4609
4510
|
onCancel: () => setConfirmDeactivate(false)
|
|
4610
4511
|
}
|
|
4611
4512
|
) }),
|
|
4612
|
-
/* @__PURE__ */
|
|
4613
|
-
/* @__PURE__ */
|
|
4614
|
-
/* @__PURE__ */
|
|
4615
|
-
status === "pro" && /* @__PURE__ */
|
|
4616
|
-
status === "free" && /* @__PURE__ */
|
|
4617
|
-
status === "expired" && /* @__PURE__ */
|
|
4513
|
+
/* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: SPACING.xs, paddingLeft: SPACING.sm, children: [
|
|
4514
|
+
/* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4515
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_statusLabel") }),
|
|
4516
|
+
status === "pro" && /* @__PURE__ */ jsx31(Text30, { color: COLORS.success, bold: true, children: t("account_pro") }),
|
|
4517
|
+
status === "free" && /* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_free") }),
|
|
4518
|
+
status === "expired" && /* @__PURE__ */ jsx31(Text30, { color: COLORS.error, children: t("account_expired") })
|
|
4618
4519
|
] }),
|
|
4619
|
-
(degradation === "warning" || degradation === "limited") && license && /* @__PURE__ */
|
|
4520
|
+
(degradation === "warning" || degradation === "limited") && license && /* @__PURE__ */ jsx31(Box29, { marginTop: SPACING.xs, borderStyle: "round", borderColor: COLORS.warning, paddingX: SPACING.sm, paddingY: SPACING.none, children: /* @__PURE__ */ jsx31(Text30, { color: COLORS.warning, children: t("license_offlineWarning", {
|
|
4620
4521
|
days: Math.floor((Date.now() - new Date(license.lastValidatedAt).getTime()) / (24 * 60 * 60 * 1e3))
|
|
4621
4522
|
}) }) }),
|
|
4622
|
-
license && /* @__PURE__ */
|
|
4623
|
-
/* @__PURE__ */
|
|
4624
|
-
/* @__PURE__ */
|
|
4625
|
-
/* @__PURE__ */
|
|
4523
|
+
license && /* @__PURE__ */ jsxs30(Fragment5, { children: [
|
|
4524
|
+
/* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4525
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_emailLabel") }),
|
|
4526
|
+
/* @__PURE__ */ jsx31(Text30, { children: license.customerEmail })
|
|
4626
4527
|
] }),
|
|
4627
|
-
/* @__PURE__ */
|
|
4628
|
-
/* @__PURE__ */
|
|
4629
|
-
/* @__PURE__ */
|
|
4528
|
+
/* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4529
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_nameLabel") }),
|
|
4530
|
+
/* @__PURE__ */ jsx31(Text30, { children: license.customerName })
|
|
4630
4531
|
] }),
|
|
4631
|
-
/* @__PURE__ */
|
|
4632
|
-
/* @__PURE__ */
|
|
4633
|
-
/* @__PURE__ */
|
|
4532
|
+
/* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4533
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_planLabel") }),
|
|
4534
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.success, bold: true, children: "Pro" })
|
|
4634
4535
|
] }),
|
|
4635
|
-
/* @__PURE__ */
|
|
4636
|
-
/* @__PURE__ */
|
|
4637
|
-
/* @__PURE__ */
|
|
4536
|
+
/* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4537
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_keyLabel") }),
|
|
4538
|
+
/* @__PURE__ */ jsx31(Text30, { children: maskKey(license.key) })
|
|
4638
4539
|
] }),
|
|
4639
|
-
license.expiresAt && /* @__PURE__ */
|
|
4640
|
-
/* @__PURE__ */
|
|
4641
|
-
/* @__PURE__ */
|
|
4540
|
+
license.expiresAt && /* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4541
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_expiresLabel") }),
|
|
4542
|
+
/* @__PURE__ */ jsx31(Text30, { children: formatDate(license.expiresAt) })
|
|
4642
4543
|
] }),
|
|
4643
|
-
/* @__PURE__ */
|
|
4644
|
-
/* @__PURE__ */
|
|
4645
|
-
/* @__PURE__ */
|
|
4544
|
+
/* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4545
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_activatedLabel") }),
|
|
4546
|
+
/* @__PURE__ */ jsx31(Text30, { children: formatDate(license.activatedAt) })
|
|
4646
4547
|
] })
|
|
4647
4548
|
] }),
|
|
4648
|
-
status === "free" && /* @__PURE__ */
|
|
4649
|
-
/* @__PURE__ */
|
|
4549
|
+
status === "free" && /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", marginTop: SPACING.sm, borderStyle: "round", borderColor: COLORS.brand, paddingX: SPACING.sm, paddingY: SPACING.xs, children: [
|
|
4550
|
+
/* @__PURE__ */ jsxs30(Text30, { bold: true, color: COLORS.brand, children: [
|
|
4650
4551
|
"\u2B50",
|
|
4651
4552
|
" ",
|
|
4652
4553
|
t("account_upgradeTitle")
|
|
4653
4554
|
] }),
|
|
4654
|
-
/* @__PURE__ */
|
|
4655
|
-
/* @__PURE__ */
|
|
4656
|
-
/* @__PURE__ */
|
|
4657
|
-
/* @__PURE__ */
|
|
4658
|
-
/* @__PURE__ */
|
|
4555
|
+
/* @__PURE__ */ jsx31(Text30, { children: " " }),
|
|
4556
|
+
/* @__PURE__ */ jsx31(Text30, { children: t("account_unlockDesc") }),
|
|
4557
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.info, bold: true, children: t("account_pricing") }),
|
|
4558
|
+
/* @__PURE__ */ jsx31(Text30, { children: " " }),
|
|
4559
|
+
/* @__PURE__ */ jsxs30(Text30, { color: COLORS.muted, children: [
|
|
4659
4560
|
t("upgrade_buyAt"),
|
|
4660
4561
|
" ",
|
|
4661
|
-
/* @__PURE__ */
|
|
4562
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.sky, bold: true, children: t("upgrade_buyUrl") })
|
|
4662
4563
|
] }),
|
|
4663
|
-
/* @__PURE__ */
|
|
4564
|
+
/* @__PURE__ */ jsxs30(Text30, { color: COLORS.muted, children: [
|
|
4664
4565
|
t("account_runActivate"),
|
|
4665
4566
|
" ",
|
|
4666
|
-
/* @__PURE__ */
|
|
4567
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.success, bold: true, children: t("account_activateCmd") })
|
|
4667
4568
|
] })
|
|
4668
4569
|
] }),
|
|
4669
|
-
status === "expired" && /* @__PURE__ */
|
|
4670
|
-
deactivating && /* @__PURE__ */
|
|
4671
|
-
deactivateError && /* @__PURE__ */
|
|
4570
|
+
status === "expired" && /* @__PURE__ */ jsx31(Box29, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx31(Box29, { borderStyle: "round", borderColor: COLORS.error, paddingX: SPACING.sm, paddingY: SPACING.none, children: /* @__PURE__ */ jsx31(Text30, { color: COLORS.error, children: t("account_licenseExpired") }) }) }),
|
|
4571
|
+
deactivating && /* @__PURE__ */ jsx31(Text30, { color: COLORS.sky, children: t("account_deactivating") }),
|
|
4572
|
+
deactivateError && /* @__PURE__ */ jsx31(Text30, { color: COLORS.error, children: deactivateError })
|
|
4672
4573
|
] }),
|
|
4673
|
-
/* @__PURE__ */
|
|
4674
|
-
/* @__PURE__ */
|
|
4675
|
-
promoLoading ? /* @__PURE__ */
|
|
4676
|
-
/* @__PURE__ */
|
|
4677
|
-
/* @__PURE__ */
|
|
4574
|
+
/* @__PURE__ */ jsx31(Box29, { flexDirection: "column", marginTop: SPACING.xs, paddingLeft: SPACING.sm, children: promoMode ? /* @__PURE__ */ jsxs30(Box29, { flexDirection: "column", gap: SPACING.xs, children: [
|
|
4575
|
+
/* @__PURE__ */ jsx31(Text30, { bold: true, color: COLORS.gold, children: t("account_promoTitle") }),
|
|
4576
|
+
promoLoading ? /* @__PURE__ */ jsx31(Text30, { color: COLORS.sky, children: t("account_promoValidating") }) : /* @__PURE__ */ jsxs30(Box29, { gap: SPACING.xs, children: [
|
|
4577
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.muted, children: t("account_promoLabel") }),
|
|
4578
|
+
/* @__PURE__ */ jsx31(
|
|
4678
4579
|
TextInput5,
|
|
4679
4580
|
{
|
|
4680
4581
|
defaultValue: "",
|
|
@@ -4698,27 +4599,29 @@ function AccountView() {
|
|
|
4698
4599
|
}
|
|
4699
4600
|
)
|
|
4700
4601
|
] }),
|
|
4701
|
-
promoResult && /* @__PURE__ */
|
|
4702
|
-
/* @__PURE__ */
|
|
4703
|
-
] }) : /* @__PURE__ */
|
|
4704
|
-
/* @__PURE__ */
|
|
4705
|
-
status === "pro" ? `d ${t("hint_deactivate")}` : "",
|
|
4602
|
+
promoResult && /* @__PURE__ */ jsx31(ResultBanner, { status: promoResult.success ? "success" : "error", message: promoResult.message }),
|
|
4603
|
+
/* @__PURE__ */ jsx31(Text30, { color: COLORS.textSecondary, dimColor: true, children: t("account_promoEsc") })
|
|
4604
|
+
] }) : /* @__PURE__ */ jsx31(Text30, { color: COLORS.textSecondary, children: t("account_promoHint") }) }),
|
|
4605
|
+
/* @__PURE__ */ jsx31(Box29, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs30(Text30, { color: COLORS.textSecondary, children: [
|
|
4606
|
+
status === "pro" || status === "team" ? `d ${t("hint_deactivate")} ` : "",
|
|
4607
|
+
status === "pro" || status === "team" || status === "expired" ? `v ${t("hint_revalidate")} ` : "",
|
|
4608
|
+
revalidating ? t("account_revalidating") : "",
|
|
4706
4609
|
" ",
|
|
4707
|
-
t("app_version", { version: "0.
|
|
4610
|
+
t("app_version", { version: "0.7.0" })
|
|
4708
4611
|
] }) })
|
|
4709
4612
|
] });
|
|
4710
4613
|
}
|
|
4711
4614
|
|
|
4712
4615
|
// src/views/rollback.tsx
|
|
4713
|
-
import { useCallback as useCallback3, useEffect as
|
|
4714
|
-
import { Box as
|
|
4616
|
+
import { useCallback as useCallback3, useEffect as useEffect16, useRef as useRef8, useState as useState13 } from "react";
|
|
4617
|
+
import { Box as Box30, Text as Text31, useInput as useInput16 } from "ink";
|
|
4715
4618
|
|
|
4716
4619
|
// src/stores/rollback-store.ts
|
|
4717
4620
|
import { create as create12 } from "zustand";
|
|
4718
4621
|
|
|
4719
4622
|
// src/lib/rollback/rollback-engine.ts
|
|
4720
4623
|
import { readdir as readdir2 } from "fs/promises";
|
|
4721
|
-
import { join as
|
|
4624
|
+
import { join as join3 } from "path";
|
|
4722
4625
|
async function detectStrategy(name, targetVersion, packageType) {
|
|
4723
4626
|
if (packageType === "cask") {
|
|
4724
4627
|
return { strategy: "pin-only" };
|
|
@@ -4734,7 +4637,7 @@ async function detectStrategy(name, targetVersion, packageType) {
|
|
|
4734
4637
|
}
|
|
4735
4638
|
try {
|
|
4736
4639
|
const brewCache = (await execBrew(["--cache"])).trim();
|
|
4737
|
-
const downloadsDir =
|
|
4640
|
+
const downloadsDir = join3(brewCache, "downloads");
|
|
4738
4641
|
const entries = await readdir2(downloadsDir);
|
|
4739
4642
|
const found = entries.some(
|
|
4740
4643
|
(entry) => entry.includes(name) && entry.includes(targetVersion)
|
|
@@ -4921,7 +4824,7 @@ var useRollbackStore = create12((set) => ({
|
|
|
4921
4824
|
}));
|
|
4922
4825
|
|
|
4923
4826
|
// src/views/rollback.tsx
|
|
4924
|
-
import { jsx as
|
|
4827
|
+
import { jsx as jsx32, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
4925
4828
|
function strategyLabel(action) {
|
|
4926
4829
|
switch (action.strategy) {
|
|
4927
4830
|
case "versioned-formula":
|
|
@@ -4949,48 +4852,48 @@ function actionPrefix(action) {
|
|
|
4949
4852
|
}
|
|
4950
4853
|
function PlanView({ plan }) {
|
|
4951
4854
|
const executableCount = plan.actions.filter((a) => a.strategy !== "unavailable" && a.action !== "remove").length;
|
|
4952
|
-
return /* @__PURE__ */
|
|
4953
|
-
/* @__PURE__ */
|
|
4954
|
-
/* @__PURE__ */
|
|
4855
|
+
return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
4856
|
+
/* @__PURE__ */ jsxs31(Box30, { marginBottom: SPACING.xs, children: [
|
|
4857
|
+
/* @__PURE__ */ jsxs31(Text31, { color: COLORS.text, bold: true, children: [
|
|
4955
4858
|
plan.snapshotLabel,
|
|
4956
4859
|
" "
|
|
4957
4860
|
] }),
|
|
4958
|
-
/* @__PURE__ */
|
|
4861
|
+
/* @__PURE__ */ jsx32(Text31, { color: COLORS.textSecondary, children: plan.snapshotDate })
|
|
4959
4862
|
] }),
|
|
4960
|
-
plan.actions.length === 0 && /* @__PURE__ */
|
|
4961
|
-
plan.actions.map((a) => /* @__PURE__ */
|
|
4962
|
-
/* @__PURE__ */
|
|
4863
|
+
plan.actions.length === 0 && /* @__PURE__ */ jsx32(ResultBanner, { status: "success", message: t("rollback_diff_empty") }),
|
|
4864
|
+
plan.actions.map((a) => /* @__PURE__ */ jsxs31(Box30, { children: [
|
|
4865
|
+
/* @__PURE__ */ jsxs31(Text31, { color: actionColor(a), children: [
|
|
4963
4866
|
actionPrefix(a),
|
|
4964
4867
|
" "
|
|
4965
4868
|
] }),
|
|
4966
|
-
/* @__PURE__ */
|
|
4967
|
-
a.fromVersion !== "" && a.toVersion !== "" && /* @__PURE__ */
|
|
4869
|
+
/* @__PURE__ */ jsx32(Text31, { color: actionColor(a), bold: true, children: a.packageName }),
|
|
4870
|
+
a.fromVersion !== "" && a.toVersion !== "" && /* @__PURE__ */ jsxs31(Text31, { color: COLORS.textSecondary, children: [
|
|
4968
4871
|
" ",
|
|
4969
4872
|
a.fromVersion,
|
|
4970
4873
|
" \u2192 ",
|
|
4971
4874
|
a.toVersion
|
|
4972
4875
|
] }),
|
|
4973
|
-
a.fromVersion === "" && a.toVersion !== "" && /* @__PURE__ */
|
|
4876
|
+
a.fromVersion === "" && a.toVersion !== "" && /* @__PURE__ */ jsxs31(Text31, { color: COLORS.textSecondary, children: [
|
|
4974
4877
|
" install ",
|
|
4975
4878
|
a.toVersion
|
|
4976
4879
|
] }),
|
|
4977
|
-
a.fromVersion !== "" && a.toVersion === "" && /* @__PURE__ */
|
|
4978
|
-
/* @__PURE__ */
|
|
4880
|
+
a.fromVersion !== "" && a.toVersion === "" && /* @__PURE__ */ jsx32(Text31, { color: COLORS.textSecondary, children: " remove" }),
|
|
4881
|
+
/* @__PURE__ */ jsxs31(Text31, { color: COLORS.muted, dimColor: true, children: [
|
|
4979
4882
|
" [",
|
|
4980
4883
|
strategyLabel(a),
|
|
4981
4884
|
"]"
|
|
4982
4885
|
] })
|
|
4983
4886
|
] }, a.packageName + a.action)),
|
|
4984
|
-
plan.warnings.map((w) => /* @__PURE__ */
|
|
4887
|
+
plan.warnings.map((w) => /* @__PURE__ */ jsx32(Box30, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs31(Text31, { color: COLORS.warning, children: [
|
|
4985
4888
|
"\u26A0 ",
|
|
4986
4889
|
w
|
|
4987
4890
|
] }) }, w)),
|
|
4988
|
-
/* @__PURE__ */
|
|
4891
|
+
/* @__PURE__ */ jsx32(Box30, { marginTop: SPACING.xs, children: plan.canExecute ? /* @__PURE__ */ jsxs31(Text31, { color: COLORS.textSecondary, children: [
|
|
4989
4892
|
"enter:",
|
|
4990
4893
|
t("rollback_confirm", { count: String(executableCount) }),
|
|
4991
4894
|
" esc:",
|
|
4992
4895
|
t("hint_back")
|
|
4993
|
-
] }) : /* @__PURE__ */
|
|
4896
|
+
] }) : /* @__PURE__ */ jsxs31(Text31, { color: COLORS.muted, children: [
|
|
4994
4897
|
t("rollback_strategy_unavailable"),
|
|
4995
4898
|
" esc:",
|
|
4996
4899
|
t("hint_back")
|
|
@@ -5007,14 +4910,14 @@ function RollbackView() {
|
|
|
5007
4910
|
const [streamError, setStreamError] = useState13(null);
|
|
5008
4911
|
const generatorRef = useRef8(null);
|
|
5009
4912
|
const mountedRef = useRef8(true);
|
|
5010
|
-
|
|
4913
|
+
useEffect16(() => {
|
|
5011
4914
|
mountedRef.current = true;
|
|
5012
4915
|
return () => {
|
|
5013
4916
|
mountedRef.current = false;
|
|
5014
4917
|
void generatorRef.current?.return(void 0);
|
|
5015
4918
|
};
|
|
5016
4919
|
}, []);
|
|
5017
|
-
|
|
4920
|
+
useEffect16(() => {
|
|
5018
4921
|
void fetchSnapshots(isPro());
|
|
5019
4922
|
}, []);
|
|
5020
4923
|
const runRollback = useCallback3(async (p) => {
|
|
@@ -5041,7 +4944,7 @@ function RollbackView() {
|
|
|
5041
4944
|
}
|
|
5042
4945
|
}
|
|
5043
4946
|
}, [isPro]);
|
|
5044
|
-
|
|
4947
|
+
useInput16((input, key) => {
|
|
5045
4948
|
if (phase === "executing") return;
|
|
5046
4949
|
if (phase === "result") {
|
|
5047
4950
|
if (key.escape || input === "r") {
|
|
@@ -5074,21 +4977,21 @@ function RollbackView() {
|
|
|
5074
4977
|
void fetchSnapshots(isPro());
|
|
5075
4978
|
}
|
|
5076
4979
|
});
|
|
5077
|
-
if (loading) return /* @__PURE__ */
|
|
5078
|
-
if (error) return /* @__PURE__ */
|
|
4980
|
+
if (loading) return /* @__PURE__ */ jsx32(Loading, { message: t("rollback_select_snapshot") });
|
|
4981
|
+
if (error) return /* @__PURE__ */ jsx32(ErrorMessage, { message: error });
|
|
5079
4982
|
if (phase === "executing") {
|
|
5080
|
-
return /* @__PURE__ */
|
|
4983
|
+
return /* @__PURE__ */ jsx32(Box30, { flexDirection: "column", children: /* @__PURE__ */ jsx32(ProgressLog, { lines: streamLines, isRunning: streamRunning, title: t("rollback_executing") }) });
|
|
5081
4984
|
}
|
|
5082
4985
|
if (phase === "result") {
|
|
5083
|
-
return /* @__PURE__ */
|
|
5084
|
-
/* @__PURE__ */
|
|
4986
|
+
return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
4987
|
+
/* @__PURE__ */ jsx32(
|
|
5085
4988
|
ResultBanner,
|
|
5086
4989
|
{
|
|
5087
4990
|
status: streamError ? "error" : "success",
|
|
5088
4991
|
message: streamError ? t("rollback_error", { error: streamError }) : t("rollback_success")
|
|
5089
4992
|
}
|
|
5090
4993
|
),
|
|
5091
|
-
/* @__PURE__ */
|
|
4994
|
+
/* @__PURE__ */ jsx32(Box30, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs31(Text31, { color: COLORS.textSecondary, children: [
|
|
5092
4995
|
"r:",
|
|
5093
4996
|
t("hint_refresh"),
|
|
5094
4997
|
" esc:",
|
|
@@ -5096,18 +4999,18 @@ function RollbackView() {
|
|
|
5096
4999
|
] }) })
|
|
5097
5000
|
] });
|
|
5098
5001
|
}
|
|
5099
|
-
return /* @__PURE__ */
|
|
5100
|
-
/* @__PURE__ */
|
|
5101
|
-
snapshots.length === 0 && /* @__PURE__ */
|
|
5102
|
-
phase === "list" && snapshots.length > 0 && /* @__PURE__ */
|
|
5103
|
-
/* @__PURE__ */
|
|
5104
|
-
/* @__PURE__ */
|
|
5105
|
-
/* @__PURE__ */
|
|
5106
|
-
/* @__PURE__ */
|
|
5002
|
+
return /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
|
|
5003
|
+
/* @__PURE__ */ jsx32(SectionHeader, { emoji: "\u23EA", title: t("rollback_title"), gradient: GRADIENTS.gold }),
|
|
5004
|
+
snapshots.length === 0 && /* @__PURE__ */ jsx32(Box30, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx32(ResultBanner, { status: "info", message: t("rollback_no_snapshots") }) }),
|
|
5005
|
+
phase === "list" && snapshots.length > 0 && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5006
|
+
/* @__PURE__ */ jsx32(Text31, { color: COLORS.textSecondary, dimColor: true, children: t("rollback_select_snapshot") }),
|
|
5007
|
+
/* @__PURE__ */ jsx32(Box30, { flexDirection: "column", marginTop: SPACING.xs, children: snapshots.map((s, i) => /* @__PURE__ */ jsxs31(SelectableRow, { isCurrent: i === cursor, children: [
|
|
5008
|
+
/* @__PURE__ */ jsx32(Text31, { bold: i === cursor, color: i === cursor ? COLORS.text : COLORS.muted, children: s.label ?? t("rollback_snapshot_auto") }),
|
|
5009
|
+
/* @__PURE__ */ jsxs31(Text31, { color: COLORS.textSecondary, children: [
|
|
5107
5010
|
" \u2014 ",
|
|
5108
5011
|
new Date(s.capturedAt).toLocaleString()
|
|
5109
5012
|
] }),
|
|
5110
|
-
/* @__PURE__ */
|
|
5013
|
+
/* @__PURE__ */ jsxs31(Text31, { color: COLORS.muted, dimColor: true, children: [
|
|
5111
5014
|
" ",
|
|
5112
5015
|
"(",
|
|
5113
5016
|
tp("packages", s.formulae.length + s.casks.length),
|
|
@@ -5115,12 +5018,12 @@ function RollbackView() {
|
|
|
5115
5018
|
] })
|
|
5116
5019
|
] }, s.capturedAt)) })
|
|
5117
5020
|
] }),
|
|
5118
|
-
phase === "plan" && /* @__PURE__ */
|
|
5119
|
-
planLoading && /* @__PURE__ */
|
|
5120
|
-
planError && /* @__PURE__ */
|
|
5121
|
-
plan && !planLoading && /* @__PURE__ */
|
|
5021
|
+
phase === "plan" && /* @__PURE__ */ jsxs31(Box30, { flexDirection: "column", children: [
|
|
5022
|
+
planLoading && /* @__PURE__ */ jsx32(Loading, { message: t("rollback_capturing") }),
|
|
5023
|
+
planError && /* @__PURE__ */ jsx32(ErrorMessage, { message: planError }),
|
|
5024
|
+
plan && !planLoading && /* @__PURE__ */ jsx32(PlanView, { plan })
|
|
5122
5025
|
] }),
|
|
5123
|
-
phase === "confirm" && plan && /* @__PURE__ */
|
|
5026
|
+
phase === "confirm" && plan && /* @__PURE__ */ jsx32(Box30, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx32(
|
|
5124
5027
|
ConfirmDialog,
|
|
5125
5028
|
{
|
|
5126
5029
|
message: t("rollback_confirm", {
|
|
@@ -5134,47 +5037,47 @@ function RollbackView() {
|
|
|
5134
5037
|
}
|
|
5135
5038
|
|
|
5136
5039
|
// src/views/brewfile.tsx
|
|
5137
|
-
import { useCallback as useCallback4, useEffect as
|
|
5138
|
-
import { Box as
|
|
5040
|
+
import { useCallback as useCallback4, useEffect as useEffect17, useRef as useRef9, useState as useState14 } from "react";
|
|
5041
|
+
import { Box as Box31, Text as Text32, useInput as useInput17 } from "ink";
|
|
5139
5042
|
import { TextInput as TextInput6 } from "@inkjs/ui";
|
|
5140
|
-
import { jsx as
|
|
5043
|
+
import { jsx as jsx33, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
5141
5044
|
function DriftScore({ score }) {
|
|
5142
5045
|
const color = score >= 80 ? COLORS.success : score >= 50 ? COLORS.warning : COLORS.error;
|
|
5143
5046
|
const bars = Math.round(score / 10);
|
|
5144
5047
|
const filled = "\u2593".repeat(bars);
|
|
5145
5048
|
const empty = "\u2591".repeat(10 - bars);
|
|
5146
|
-
return /* @__PURE__ */
|
|
5147
|
-
/* @__PURE__ */
|
|
5049
|
+
return /* @__PURE__ */ jsxs32(Box31, { children: [
|
|
5050
|
+
/* @__PURE__ */ jsxs32(Text32, { color, children: [
|
|
5148
5051
|
filled,
|
|
5149
5052
|
empty
|
|
5150
5053
|
] }),
|
|
5151
|
-
/* @__PURE__ */
|
|
5054
|
+
/* @__PURE__ */ jsxs32(Text32, { color, bold: true, children: [
|
|
5152
5055
|
" ",
|
|
5153
5056
|
score,
|
|
5154
5057
|
"% "
|
|
5155
5058
|
] }),
|
|
5156
|
-
/* @__PURE__ */
|
|
5059
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.textSecondary, children: t("brewfile_compliant") })
|
|
5157
5060
|
] });
|
|
5158
5061
|
}
|
|
5159
5062
|
function DriftSummary({ drift }) {
|
|
5160
|
-
return /* @__PURE__ */
|
|
5161
|
-
drift.missingPackages.length > 0 && /* @__PURE__ */
|
|
5162
|
-
/* @__PURE__ */
|
|
5163
|
-
/* @__PURE__ */
|
|
5164
|
-
/* @__PURE__ */
|
|
5063
|
+
return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5064
|
+
drift.missingPackages.length > 0 && /* @__PURE__ */ jsxs32(Box31, { children: [
|
|
5065
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.error, children: "\u25CF " }),
|
|
5066
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.error, children: t("brewfile_drift_missing", { count: drift.missingPackages.length }) }),
|
|
5067
|
+
/* @__PURE__ */ jsxs32(Text32, { color: COLORS.textSecondary, children: [
|
|
5165
5068
|
": " + drift.missingPackages.slice(0, 3).join(", "),
|
|
5166
5069
|
drift.missingPackages.length > 3 ? "..." : ""
|
|
5167
5070
|
] })
|
|
5168
5071
|
] }),
|
|
5169
|
-
drift.extraPackages.length > 0 && /* @__PURE__ */
|
|
5170
|
-
/* @__PURE__ */
|
|
5171
|
-
/* @__PURE__ */
|
|
5072
|
+
drift.extraPackages.length > 0 && /* @__PURE__ */ jsxs32(Box31, { children: [
|
|
5073
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.warning, children: "\u25CF " }),
|
|
5074
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.warning, children: t("brewfile_drift_extra", { count: drift.extraPackages.length }) })
|
|
5172
5075
|
] }),
|
|
5173
|
-
drift.wrongVersions.length > 0 && /* @__PURE__ */
|
|
5174
|
-
/* @__PURE__ */
|
|
5175
|
-
/* @__PURE__ */
|
|
5076
|
+
drift.wrongVersions.length > 0 && /* @__PURE__ */ jsxs32(Box31, { children: [
|
|
5077
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.info, children: "\u25CF " }),
|
|
5078
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.info, children: t("brewfile_drift_wrong", { count: drift.wrongVersions.length }) })
|
|
5176
5079
|
] }),
|
|
5177
|
-
drift.missingPackages.length === 0 && drift.extraPackages.length === 0 && drift.wrongVersions.length === 0 && /* @__PURE__ */
|
|
5080
|
+
drift.missingPackages.length === 0 && drift.extraPackages.length === 0 && drift.wrongVersions.length === 0 && /* @__PURE__ */ jsx33(ResultBanner, { status: "success", message: t("brewfile_in_sync") })
|
|
5178
5081
|
] });
|
|
5179
5082
|
}
|
|
5180
5083
|
function BrewfileView() {
|
|
@@ -5187,7 +5090,7 @@ function BrewfileView() {
|
|
|
5187
5090
|
const [resultMessage, setResultMessage] = useState14("");
|
|
5188
5091
|
const generatorRef = useRef9(null);
|
|
5189
5092
|
const mountedRef = useRef9(true);
|
|
5190
|
-
|
|
5093
|
+
useEffect17(() => {
|
|
5191
5094
|
mountedRef.current = true;
|
|
5192
5095
|
void load();
|
|
5193
5096
|
return () => {
|
|
@@ -5225,8 +5128,9 @@ function BrewfileView() {
|
|
|
5225
5128
|
}
|
|
5226
5129
|
}
|
|
5227
5130
|
}, [schema, isPro]);
|
|
5228
|
-
|
|
5131
|
+
useInput17((input, key) => {
|
|
5229
5132
|
if (phase === "reconciling") return;
|
|
5133
|
+
if (phase === "confirming-reconcile") return;
|
|
5230
5134
|
if (phase === "result") {
|
|
5231
5135
|
if (key.escape || input === "r") {
|
|
5232
5136
|
setPhase("overview");
|
|
@@ -5246,24 +5150,41 @@ function BrewfileView() {
|
|
|
5246
5150
|
if (input === "c") {
|
|
5247
5151
|
const needsReconcile = drift && (drift.missingPackages.length > 0 || drift.wrongVersions.length > 0);
|
|
5248
5152
|
if (needsReconcile) {
|
|
5249
|
-
|
|
5153
|
+
setPhase("confirming-reconcile");
|
|
5250
5154
|
}
|
|
5251
5155
|
return;
|
|
5252
5156
|
}
|
|
5253
5157
|
if (key.escape) {
|
|
5254
5158
|
}
|
|
5255
5159
|
});
|
|
5256
|
-
if (loading) return /* @__PURE__ */
|
|
5257
|
-
if (error) return /* @__PURE__ */
|
|
5160
|
+
if (loading) return /* @__PURE__ */ jsx33(Loading, { message: t("loading_default") });
|
|
5161
|
+
if (error) return /* @__PURE__ */ jsx33(ErrorMessage, { message: error });
|
|
5162
|
+
if (phase === "confirming-reconcile" && drift) {
|
|
5163
|
+
return /* @__PURE__ */ jsx33(
|
|
5164
|
+
ConfirmDialog,
|
|
5165
|
+
{
|
|
5166
|
+
message: t("confirm_brewfile_reconcile", {
|
|
5167
|
+
missing: String(drift.missingPackages.length),
|
|
5168
|
+
wrongVer: String(drift.wrongVersions.length)
|
|
5169
|
+
}),
|
|
5170
|
+
onConfirm: () => {
|
|
5171
|
+
void startReconcile();
|
|
5172
|
+
},
|
|
5173
|
+
onCancel: () => {
|
|
5174
|
+
setPhase("overview");
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
);
|
|
5178
|
+
}
|
|
5258
5179
|
if (phase === "creating") {
|
|
5259
|
-
return /* @__PURE__ */
|
|
5260
|
-
/* @__PURE__ */
|
|
5261
|
-
/* @__PURE__ */
|
|
5262
|
-
/* @__PURE__ */
|
|
5180
|
+
return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5181
|
+
/* @__PURE__ */ jsx33(SectionHeader, { emoji: "\u{1F4E6}", title: t("brewfile_title"), gradient: GRADIENTS.ocean }),
|
|
5182
|
+
/* @__PURE__ */ jsxs32(Box31, { marginTop: SPACING.xs, children: [
|
|
5183
|
+
/* @__PURE__ */ jsxs32(Text32, { color: COLORS.textSecondary, children: [
|
|
5263
5184
|
t("brewfile_create_name"),
|
|
5264
5185
|
" "
|
|
5265
5186
|
] }),
|
|
5266
|
-
/* @__PURE__ */
|
|
5187
|
+
/* @__PURE__ */ jsx33(
|
|
5267
5188
|
TextInput6,
|
|
5268
5189
|
{
|
|
5269
5190
|
defaultValue: "My Environment",
|
|
@@ -5279,7 +5200,7 @@ function BrewfileView() {
|
|
|
5279
5200
|
] });
|
|
5280
5201
|
}
|
|
5281
5202
|
if (phase === "reconciling") {
|
|
5282
|
-
return /* @__PURE__ */
|
|
5203
|
+
return /* @__PURE__ */ jsx33(Box31, { flexDirection: "column", children: /* @__PURE__ */ jsx33(
|
|
5283
5204
|
ProgressLog,
|
|
5284
5205
|
{
|
|
5285
5206
|
lines: streamLines,
|
|
@@ -5289,15 +5210,15 @@ function BrewfileView() {
|
|
|
5289
5210
|
) });
|
|
5290
5211
|
}
|
|
5291
5212
|
if (phase === "result") {
|
|
5292
|
-
return /* @__PURE__ */
|
|
5293
|
-
/* @__PURE__ */
|
|
5213
|
+
return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5214
|
+
/* @__PURE__ */ jsx33(
|
|
5294
5215
|
ResultBanner,
|
|
5295
5216
|
{
|
|
5296
5217
|
status: streamError ? "error" : "success",
|
|
5297
5218
|
message: resultMessage
|
|
5298
5219
|
}
|
|
5299
5220
|
),
|
|
5300
|
-
/* @__PURE__ */
|
|
5221
|
+
/* @__PURE__ */ jsx33(Box31, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs32(Text32, { color: COLORS.textSecondary, children: [
|
|
5301
5222
|
"r:",
|
|
5302
5223
|
t("hint_refresh"),
|
|
5303
5224
|
" esc:",
|
|
@@ -5305,34 +5226,34 @@ function BrewfileView() {
|
|
|
5305
5226
|
] }) })
|
|
5306
5227
|
] });
|
|
5307
5228
|
}
|
|
5308
|
-
return /* @__PURE__ */
|
|
5309
|
-
/* @__PURE__ */
|
|
5310
|
-
schema === null ? /* @__PURE__ */
|
|
5311
|
-
/* @__PURE__ */
|
|
5312
|
-
/* @__PURE__ */
|
|
5229
|
+
return /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", children: [
|
|
5230
|
+
/* @__PURE__ */ jsx33(SectionHeader, { emoji: "\u{1F4E6}", title: t("brewfile_title"), gradient: GRADIENTS.ocean }),
|
|
5231
|
+
schema === null ? /* @__PURE__ */ jsxs32(Box31, { marginTop: SPACING.xs, flexDirection: "column", children: [
|
|
5232
|
+
/* @__PURE__ */ jsx33(ResultBanner, { status: "info", message: t("brewfile_no_brewfile") }),
|
|
5233
|
+
/* @__PURE__ */ jsx33(Box31, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs32(Text32, { color: COLORS.textSecondary, children: [
|
|
5313
5234
|
"n:",
|
|
5314
5235
|
t("hint_new")
|
|
5315
5236
|
] }) })
|
|
5316
|
-
] }) : /* @__PURE__ */
|
|
5317
|
-
/* @__PURE__ */
|
|
5318
|
-
/* @__PURE__ */
|
|
5319
|
-
schema.meta.description && /* @__PURE__ */
|
|
5320
|
-
schema.strictMode && /* @__PURE__ */
|
|
5237
|
+
] }) : /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5238
|
+
/* @__PURE__ */ jsxs32(Box31, { gap: SPACING.sm, children: [
|
|
5239
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.text, bold: true, children: schema.meta.name }),
|
|
5240
|
+
schema.meta.description && /* @__PURE__ */ jsx33(Text32, { color: COLORS.textSecondary, children: schema.meta.description }),
|
|
5241
|
+
schema.strictMode && /* @__PURE__ */ jsxs32(Text32, { color: COLORS.warning, children: [
|
|
5321
5242
|
"[",
|
|
5322
5243
|
t("brewfile_strict_mode"),
|
|
5323
5244
|
"]"
|
|
5324
5245
|
] })
|
|
5325
5246
|
] }),
|
|
5326
|
-
/* @__PURE__ */
|
|
5327
|
-
/* @__PURE__ */
|
|
5328
|
-
/* @__PURE__ */
|
|
5247
|
+
/* @__PURE__ */ jsxs32(Box31, { gap: SPACING.md, marginTop: SPACING.xs, children: [
|
|
5248
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.sky, children: t("brewfile_formulae_count", { count: schema.formulae.length }) }),
|
|
5249
|
+
/* @__PURE__ */ jsx33(Text32, { color: COLORS.teal, children: t("brewfile_casks_count", { count: schema.casks.length }) })
|
|
5329
5250
|
] }),
|
|
5330
|
-
driftLoading && /* @__PURE__ */
|
|
5331
|
-
drift && !driftLoading && /* @__PURE__ */
|
|
5332
|
-
/* @__PURE__ */
|
|
5333
|
-
/* @__PURE__ */
|
|
5251
|
+
driftLoading && /* @__PURE__ */ jsx33(Box31, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx33(Text32, { color: COLORS.muted, children: t("brewfile_computing_drift") }) }),
|
|
5252
|
+
drift && !driftLoading && /* @__PURE__ */ jsxs32(Box31, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5253
|
+
/* @__PURE__ */ jsx33(DriftScore, { score: drift.score }),
|
|
5254
|
+
/* @__PURE__ */ jsx33(DriftSummary, { drift })
|
|
5334
5255
|
] }),
|
|
5335
|
-
/* @__PURE__ */
|
|
5256
|
+
/* @__PURE__ */ jsx33(Box31, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs32(Text32, { color: COLORS.textSecondary, children: [
|
|
5336
5257
|
"r:",
|
|
5337
5258
|
t("hint_refresh"),
|
|
5338
5259
|
drift && (drift.missingPackages.length > 0 || drift.wrongVersions.length > 0) ? ` c:${t("hint_reconcile")}` : "",
|
|
@@ -5345,9 +5266,9 @@ function BrewfileView() {
|
|
|
5345
5266
|
}
|
|
5346
5267
|
|
|
5347
5268
|
// src/views/sync.tsx
|
|
5348
|
-
import { useCallback as useCallback5, useEffect as
|
|
5349
|
-
import { Box as
|
|
5350
|
-
import { Fragment as Fragment6, jsx as
|
|
5269
|
+
import { useCallback as useCallback5, useEffect as useEffect18, useState as useState15 } from "react";
|
|
5270
|
+
import { Box as Box32, Text as Text33, useInput as useInput18 } from "ink";
|
|
5271
|
+
import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
5351
5272
|
function OverviewSection({
|
|
5352
5273
|
config,
|
|
5353
5274
|
lastResult,
|
|
@@ -5357,34 +5278,34 @@ function OverviewSection({
|
|
|
5357
5278
|
}) {
|
|
5358
5279
|
const hasConflicts = conflicts.length > 0;
|
|
5359
5280
|
const showComplianceHint = !hasConflicts && !!lastResult?.success;
|
|
5360
|
-
return /* @__PURE__ */
|
|
5361
|
-
config ? /* @__PURE__ */
|
|
5362
|
-
/* @__PURE__ */
|
|
5363
|
-
config.lastSync && /* @__PURE__ */
|
|
5364
|
-
hasConflicts ? /* @__PURE__ */
|
|
5281
|
+
return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5282
|
+
config ? /* @__PURE__ */ jsxs33(Fragment6, { children: [
|
|
5283
|
+
/* @__PURE__ */ jsx34(Box32, { marginBottom: SPACING.xs, children: /* @__PURE__ */ jsx34(Text33, { color: COLORS.textSecondary, children: t("sync_machine", { name: config.machineName }) }) }),
|
|
5284
|
+
config.lastSync && /* @__PURE__ */ jsx34(Box32, { marginBottom: SPACING.xs, children: /* @__PURE__ */ jsx34(Text33, { color: COLORS.textSecondary, children: t("sync_last_sync", { date: new Date(config.lastSync).toLocaleString() }) }) }),
|
|
5285
|
+
hasConflicts ? /* @__PURE__ */ jsx34(
|
|
5365
5286
|
ResultBanner,
|
|
5366
5287
|
{
|
|
5367
5288
|
status: "error",
|
|
5368
5289
|
message: t("sync_status_conflict", { count: String(conflicts.length) })
|
|
5369
5290
|
}
|
|
5370
|
-
) : lastResult?.success ? /* @__PURE__ */
|
|
5371
|
-
] }) : /* @__PURE__ */
|
|
5372
|
-
/* @__PURE__ */
|
|
5291
|
+
) : lastResult?.success ? /* @__PURE__ */ jsx34(ResultBanner, { status: "success", message: t("sync_status_ok") }) : null
|
|
5292
|
+
] }) : /* @__PURE__ */ jsx34(Box32, { marginBottom: SPACING.xs, children: /* @__PURE__ */ jsx34(Text33, { color: COLORS.textSecondary, children: t("sync_disabled") }) }),
|
|
5293
|
+
/* @__PURE__ */ jsx34(Box32, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs33(Text33, { color: COLORS.textSecondary, children: [
|
|
5373
5294
|
"s",
|
|
5374
|
-
/* @__PURE__ */
|
|
5295
|
+
/* @__PURE__ */ jsxs33(Text33, { color: COLORS.gold, children: [
|
|
5375
5296
|
":",
|
|
5376
5297
|
t("hint_sync")
|
|
5377
5298
|
] }),
|
|
5378
|
-
hasConflicts && /* @__PURE__ */
|
|
5299
|
+
hasConflicts && /* @__PURE__ */ jsxs33(Fragment6, { children: [
|
|
5379
5300
|
" c",
|
|
5380
|
-
/* @__PURE__ */
|
|
5301
|
+
/* @__PURE__ */ jsxs33(Text33, { color: COLORS.gold, children: [
|
|
5381
5302
|
":",
|
|
5382
5303
|
t("hint_conflict")
|
|
5383
5304
|
] })
|
|
5384
5305
|
] }),
|
|
5385
|
-
showComplianceHint && /* @__PURE__ */
|
|
5306
|
+
showComplianceHint && /* @__PURE__ */ jsxs33(Fragment6, { children: [
|
|
5386
5307
|
" c",
|
|
5387
|
-
/* @__PURE__ */
|
|
5308
|
+
/* @__PURE__ */ jsxs33(Text33, { color: COLORS.gold, children: [
|
|
5388
5309
|
":",
|
|
5389
5310
|
t("hint_check_compliance")
|
|
5390
5311
|
] })
|
|
@@ -5396,22 +5317,22 @@ function ConflictsList({
|
|
|
5396
5317
|
entries,
|
|
5397
5318
|
cursor
|
|
5398
5319
|
}) {
|
|
5399
|
-
return /* @__PURE__ */
|
|
5320
|
+
return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5400
5321
|
entries.map((entry, i) => {
|
|
5401
5322
|
const { conflict, resolution } = entry;
|
|
5402
5323
|
const isActive = i === cursor;
|
|
5403
|
-
return /* @__PURE__ */
|
|
5404
|
-
/* @__PURE__ */
|
|
5405
|
-
/* @__PURE__ */
|
|
5406
|
-
/* @__PURE__ */
|
|
5324
|
+
return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginBottom: SPACING.xs, children: [
|
|
5325
|
+
/* @__PURE__ */ jsxs33(SelectableRow, { isCurrent: isActive, children: [
|
|
5326
|
+
/* @__PURE__ */ jsx34(Text33, { bold: true, color: isActive ? COLORS.text : COLORS.textSecondary, children: t("sync_conflict_title", { package: conflict.packageName }) }),
|
|
5327
|
+
/* @__PURE__ */ jsxs33(Text33, { color: COLORS.muted, children: [
|
|
5407
5328
|
" (",
|
|
5408
5329
|
conflict.packageType,
|
|
5409
5330
|
")"
|
|
5410
5331
|
] })
|
|
5411
5332
|
] }),
|
|
5412
|
-
/* @__PURE__ */
|
|
5413
|
-
/* @__PURE__ */
|
|
5414
|
-
|
|
5333
|
+
/* @__PURE__ */ jsxs33(Box32, { marginLeft: SPACING.sm, flexDirection: "column", children: [
|
|
5334
|
+
/* @__PURE__ */ jsxs33(
|
|
5335
|
+
Text33,
|
|
5415
5336
|
{
|
|
5416
5337
|
color: resolution === "use-local" ? COLORS.success : COLORS.textSecondary,
|
|
5417
5338
|
children: [
|
|
@@ -5421,8 +5342,8 @@ function ConflictsList({
|
|
|
5421
5342
|
]
|
|
5422
5343
|
}
|
|
5423
5344
|
),
|
|
5424
|
-
/* @__PURE__ */
|
|
5425
|
-
|
|
5345
|
+
/* @__PURE__ */ jsxs33(
|
|
5346
|
+
Text33,
|
|
5426
5347
|
{
|
|
5427
5348
|
color: resolution === "use-remote" ? COLORS.success : COLORS.textSecondary,
|
|
5428
5349
|
children: [
|
|
@@ -5435,12 +5356,17 @@ function ConflictsList({
|
|
|
5435
5356
|
] })
|
|
5436
5357
|
] }, `${conflict.packageName}-${conflict.remoteMachine}`);
|
|
5437
5358
|
}),
|
|
5438
|
-
/* @__PURE__ */
|
|
5439
|
-
"j/k:
|
|
5359
|
+
/* @__PURE__ */ jsx34(Box32, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs33(Text33, { color: COLORS.textSecondary, children: [
|
|
5360
|
+
"j/k:",
|
|
5361
|
+
t("hint_navigate"),
|
|
5362
|
+
" l:",
|
|
5440
5363
|
t("sync_conflict_use_local"),
|
|
5441
5364
|
" r:",
|
|
5442
5365
|
t("sync_conflict_use_remote"),
|
|
5443
|
-
" enter:
|
|
5366
|
+
" enter:",
|
|
5367
|
+
t("hint_apply"),
|
|
5368
|
+
" esc:",
|
|
5369
|
+
t("hint_back")
|
|
5444
5370
|
] }) })
|
|
5445
5371
|
] });
|
|
5446
5372
|
}
|
|
@@ -5452,10 +5378,10 @@ function SyncView() {
|
|
|
5452
5378
|
const [syncError, setSyncError] = useState15(null);
|
|
5453
5379
|
const [conflictEntries, setConflictEntries] = useState15([]);
|
|
5454
5380
|
const [cursor, setCursor] = useState15(0);
|
|
5455
|
-
|
|
5381
|
+
useEffect18(() => {
|
|
5456
5382
|
void initialize(isPro());
|
|
5457
5383
|
}, []);
|
|
5458
|
-
|
|
5384
|
+
useEffect18(() => {
|
|
5459
5385
|
if (conflicts.length > 0) {
|
|
5460
5386
|
setConflictEntries(
|
|
5461
5387
|
conflicts.map((c) => ({ conflict: c, resolution: "pending" }))
|
|
@@ -5486,8 +5412,9 @@ function SyncView() {
|
|
|
5486
5412
|
await resolveConflicts(resolutions);
|
|
5487
5413
|
setPhase("result");
|
|
5488
5414
|
}, [conflictEntries, resolveConflicts]);
|
|
5489
|
-
|
|
5415
|
+
useInput18((input, key) => {
|
|
5490
5416
|
if (phase === "syncing") return;
|
|
5417
|
+
if (phase === "confirming-sync" || phase === "confirming-apply") return;
|
|
5491
5418
|
if (phase === "result") {
|
|
5492
5419
|
if (key.escape || input === "r") {
|
|
5493
5420
|
setPhase("overview");
|
|
@@ -5522,12 +5449,13 @@ function SyncView() {
|
|
|
5522
5449
|
return;
|
|
5523
5450
|
}
|
|
5524
5451
|
if (key.return) {
|
|
5525
|
-
|
|
5452
|
+
const pending = conflictEntries.filter((e) => e.resolution === "pending");
|
|
5453
|
+
if (pending.length === 0) setPhase("confirming-apply");
|
|
5526
5454
|
return;
|
|
5527
5455
|
}
|
|
5528
5456
|
}
|
|
5529
5457
|
if (input === "s") {
|
|
5530
|
-
|
|
5458
|
+
setPhase("confirming-sync");
|
|
5531
5459
|
return;
|
|
5532
5460
|
}
|
|
5533
5461
|
if (input === "c" && conflicts.length > 0) {
|
|
@@ -5544,21 +5472,49 @@ function SyncView() {
|
|
|
5544
5472
|
return;
|
|
5545
5473
|
}
|
|
5546
5474
|
});
|
|
5475
|
+
if (phase === "confirming-sync") {
|
|
5476
|
+
return /* @__PURE__ */ jsx34(
|
|
5477
|
+
ConfirmDialog,
|
|
5478
|
+
{
|
|
5479
|
+
message: t("confirm_sync_now"),
|
|
5480
|
+
onConfirm: () => {
|
|
5481
|
+
void handleSyncNow();
|
|
5482
|
+
},
|
|
5483
|
+
onCancel: () => {
|
|
5484
|
+
setPhase("overview");
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
);
|
|
5488
|
+
}
|
|
5489
|
+
if (phase === "confirming-apply") {
|
|
5490
|
+
return /* @__PURE__ */ jsx34(
|
|
5491
|
+
ConfirmDialog,
|
|
5492
|
+
{
|
|
5493
|
+
message: t("confirm_sync_apply", { count: String(conflictEntries.length) }),
|
|
5494
|
+
onConfirm: () => {
|
|
5495
|
+
void handleApplyResolutions();
|
|
5496
|
+
},
|
|
5497
|
+
onCancel: () => {
|
|
5498
|
+
setPhase("conflicts");
|
|
5499
|
+
}
|
|
5500
|
+
}
|
|
5501
|
+
);
|
|
5502
|
+
}
|
|
5547
5503
|
if (phase === "syncing" || loading) {
|
|
5548
|
-
return /* @__PURE__ */
|
|
5504
|
+
return /* @__PURE__ */ jsx34(Loading, { message: t("sync_syncing") });
|
|
5549
5505
|
}
|
|
5550
5506
|
if (phase === "result") {
|
|
5551
5507
|
const isError = !!(syncError ?? error);
|
|
5552
|
-
return /* @__PURE__ */
|
|
5553
|
-
/* @__PURE__ */
|
|
5554
|
-
/* @__PURE__ */
|
|
5508
|
+
return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5509
|
+
/* @__PURE__ */ jsx34(SectionHeader, { emoji: "\u{1F504}", title: t("sync_title"), gradient: GRADIENTS.gold }),
|
|
5510
|
+
/* @__PURE__ */ jsx34(Box32, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx34(
|
|
5555
5511
|
ResultBanner,
|
|
5556
5512
|
{
|
|
5557
5513
|
status: isError ? "error" : "success",
|
|
5558
5514
|
message: isError ? t("sync_error", { error: syncError ?? error ?? "" }) : t("sync_success")
|
|
5559
5515
|
}
|
|
5560
5516
|
) }),
|
|
5561
|
-
/* @__PURE__ */
|
|
5517
|
+
/* @__PURE__ */ jsx34(Box32, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs33(Text33, { color: COLORS.textSecondary, children: [
|
|
5562
5518
|
"r:",
|
|
5563
5519
|
t("hint_refresh"),
|
|
5564
5520
|
" esc:",
|
|
@@ -5566,10 +5522,10 @@ function SyncView() {
|
|
|
5566
5522
|
] }) })
|
|
5567
5523
|
] });
|
|
5568
5524
|
}
|
|
5569
|
-
return /* @__PURE__ */
|
|
5570
|
-
/* @__PURE__ */
|
|
5571
|
-
error && phase === "overview" && /* @__PURE__ */
|
|
5572
|
-
phase === "overview" && /* @__PURE__ */
|
|
5525
|
+
return /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
|
|
5526
|
+
/* @__PURE__ */ jsx34(SectionHeader, { emoji: "\u{1F504}", title: t("sync_title"), gradient: GRADIENTS.gold }),
|
|
5527
|
+
error && phase === "overview" && /* @__PURE__ */ jsx34(Box32, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx34(ResultBanner, { status: "error", message: t("sync_error", { error }) }) }),
|
|
5528
|
+
phase === "overview" && /* @__PURE__ */ jsx34(
|
|
5573
5529
|
OverviewSection,
|
|
5574
5530
|
{
|
|
5575
5531
|
config,
|
|
@@ -5582,16 +5538,16 @@ function SyncView() {
|
|
|
5582
5538
|
}
|
|
5583
5539
|
}
|
|
5584
5540
|
),
|
|
5585
|
-
phase === "conflicts" && /* @__PURE__ */
|
|
5586
|
-
/* @__PURE__ */
|
|
5587
|
-
/* @__PURE__ */
|
|
5541
|
+
phase === "conflicts" && /* @__PURE__ */ jsxs33(Box32, { flexDirection: "column", children: [
|
|
5542
|
+
/* @__PURE__ */ jsx34(SectionHeader, { emoji: "\u26A0", title: t("sync_status_conflict", { count: String(conflictEntries.length) }), gradient: GRADIENTS.gold }),
|
|
5543
|
+
/* @__PURE__ */ jsx34(ConflictsList, { entries: conflictEntries, cursor })
|
|
5588
5544
|
] })
|
|
5589
5545
|
] });
|
|
5590
5546
|
}
|
|
5591
5547
|
|
|
5592
5548
|
// src/views/compliance.tsx
|
|
5593
|
-
import { useCallback as useCallback6, useEffect as
|
|
5594
|
-
import { Box as
|
|
5549
|
+
import { useCallback as useCallback6, useEffect as useEffect19, useRef as useRef10, useState as useState16 } from "react";
|
|
5550
|
+
import { Box as Box33, Text as Text34, useInput as useInput19 } from "ink";
|
|
5595
5551
|
import { TextInput as TextInput7 } from "@inkjs/ui";
|
|
5596
5552
|
|
|
5597
5553
|
// src/lib/compliance/compliance-remediator.ts
|
|
@@ -5635,28 +5591,28 @@ async function* remediateViolations(violations, isPro) {
|
|
|
5635
5591
|
}
|
|
5636
5592
|
|
|
5637
5593
|
// src/views/compliance.tsx
|
|
5638
|
-
import { join as
|
|
5639
|
-
import { jsx as
|
|
5594
|
+
import { join as join4 } from "path";
|
|
5595
|
+
import { jsx as jsx35, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
5640
5596
|
function ComplianceScore({ report }) {
|
|
5641
5597
|
const color = report.score >= 80 ? COLORS.success : report.score >= 50 ? COLORS.warning : COLORS.error;
|
|
5642
5598
|
const bars = Math.round(report.score / 10);
|
|
5643
|
-
return /* @__PURE__ */
|
|
5644
|
-
/* @__PURE__ */
|
|
5645
|
-
/* @__PURE__ */
|
|
5599
|
+
return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginBottom: SPACING.xs, children: [
|
|
5600
|
+
/* @__PURE__ */ jsxs34(Box33, { children: [
|
|
5601
|
+
/* @__PURE__ */ jsxs34(Text34, { color, children: [
|
|
5646
5602
|
"\u2593".repeat(bars),
|
|
5647
5603
|
"\u2591".repeat(10 - bars)
|
|
5648
5604
|
] }),
|
|
5649
|
-
/* @__PURE__ */
|
|
5605
|
+
/* @__PURE__ */ jsxs34(Text34, { color, bold: true, children: [
|
|
5650
5606
|
" ",
|
|
5651
5607
|
report.score,
|
|
5652
5608
|
"%"
|
|
5653
5609
|
] }),
|
|
5654
|
-
/* @__PURE__ */
|
|
5610
|
+
/* @__PURE__ */ jsxs34(Text34, { color: COLORS.textSecondary, children: [
|
|
5655
5611
|
" ",
|
|
5656
5612
|
t("compliance_score", { score: String(report.score) })
|
|
5657
5613
|
] })
|
|
5658
5614
|
] }),
|
|
5659
|
-
/* @__PURE__ */
|
|
5615
|
+
/* @__PURE__ */ jsxs34(Text34, { color: COLORS.muted, dimColor: true, children: [
|
|
5660
5616
|
t("compliance_policy_name", { name: report.policyName }),
|
|
5661
5617
|
" \xB7 ",
|
|
5662
5618
|
t("compliance_machine", { name: report.machineName })
|
|
@@ -5666,31 +5622,31 @@ function ComplianceScore({ report }) {
|
|
|
5666
5622
|
function ViolationItem({ violation }) {
|
|
5667
5623
|
const color = violation.severity === "error" ? COLORS.error : COLORS.warning;
|
|
5668
5624
|
const prefix = violation.severity === "error" ? "\u2717" : "\u26A0";
|
|
5669
|
-
return /* @__PURE__ */
|
|
5670
|
-
/* @__PURE__ */
|
|
5625
|
+
return /* @__PURE__ */ jsxs34(Box33, { marginBottom: SPACING.none, children: [
|
|
5626
|
+
/* @__PURE__ */ jsxs34(Text34, { color, children: [
|
|
5671
5627
|
prefix,
|
|
5672
5628
|
" "
|
|
5673
5629
|
] }),
|
|
5674
|
-
/* @__PURE__ */
|
|
5630
|
+
/* @__PURE__ */ jsx35(Text34, { color, children: violation.detail })
|
|
5675
5631
|
] });
|
|
5676
5632
|
}
|
|
5677
5633
|
function ViolationList({ violations }) {
|
|
5678
5634
|
const errors = violations.filter((v) => v.severity === "error");
|
|
5679
5635
|
const warnings = violations.filter((v) => v.severity === "warning");
|
|
5680
|
-
return /* @__PURE__ */
|
|
5681
|
-
errors.length > 0 && /* @__PURE__ */
|
|
5682
|
-
/* @__PURE__ */
|
|
5636
|
+
return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5637
|
+
errors.length > 0 && /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginBottom: SPACING.xs, children: [
|
|
5638
|
+
/* @__PURE__ */ jsxs34(Text34, { color: COLORS.error, bold: true, children: [
|
|
5683
5639
|
t("compliance_violations", { count: String(errors.length) }),
|
|
5684
5640
|
" (errors)"
|
|
5685
5641
|
] }),
|
|
5686
|
-
errors.map((v) => /* @__PURE__ */
|
|
5642
|
+
errors.map((v) => /* @__PURE__ */ jsx35(ViolationItem, { violation: v }, `${v.type}-${v.packageName}`))
|
|
5687
5643
|
] }),
|
|
5688
|
-
warnings.length > 0 && /* @__PURE__ */
|
|
5689
|
-
/* @__PURE__ */
|
|
5644
|
+
warnings.length > 0 && /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", children: [
|
|
5645
|
+
/* @__PURE__ */ jsxs34(Text34, { color: COLORS.warning, bold: true, children: [
|
|
5690
5646
|
t("compliance_violations", { count: String(warnings.length) }),
|
|
5691
5647
|
" (warnings)"
|
|
5692
5648
|
] }),
|
|
5693
|
-
warnings.map((v) => /* @__PURE__ */
|
|
5649
|
+
warnings.map((v) => /* @__PURE__ */ jsx35(ViolationItem, { violation: v }, `${v.type}-${v.packageName}`))
|
|
5694
5650
|
] })
|
|
5695
5651
|
] });
|
|
5696
5652
|
}
|
|
@@ -5703,7 +5659,7 @@ function ComplianceView() {
|
|
|
5703
5659
|
const [streamRunning, setStreamRunning] = useState16(false);
|
|
5704
5660
|
const generatorRef = useRef10(null);
|
|
5705
5661
|
const mountedRef = useRef10(true);
|
|
5706
|
-
|
|
5662
|
+
useEffect19(() => {
|
|
5707
5663
|
mountedRef.current = true;
|
|
5708
5664
|
return () => {
|
|
5709
5665
|
mountedRef.current = false;
|
|
@@ -5731,7 +5687,7 @@ function ComplianceView() {
|
|
|
5731
5687
|
const handleExport = useCallback6(async () => {
|
|
5732
5688
|
if (!report) return;
|
|
5733
5689
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5734
|
-
const outputPath =
|
|
5690
|
+
const outputPath = join4(DATA_DIR, `compliance-report-${timestamp}.json`);
|
|
5735
5691
|
try {
|
|
5736
5692
|
await exportReport(report, outputPath);
|
|
5737
5693
|
setResultMessage({ ok: true, text: t("compliance_export_done", { path: outputPath }) });
|
|
@@ -5779,8 +5735,9 @@ function ComplianceView() {
|
|
|
5779
5735
|
}
|
|
5780
5736
|
}
|
|
5781
5737
|
}, [report, isPro, runCheck]);
|
|
5782
|
-
|
|
5738
|
+
useInput19((input, key) => {
|
|
5783
5739
|
if (phase === "remediating" || phase === "importing") return;
|
|
5740
|
+
if (phase === "confirming-remediate") return;
|
|
5784
5741
|
if (phase === "result") {
|
|
5785
5742
|
if (key.escape || input === "r") {
|
|
5786
5743
|
setPhase("overview");
|
|
@@ -5805,31 +5762,48 @@ function ComplianceView() {
|
|
|
5805
5762
|
(v) => v.type === "missing" || v.type === "wrong-version"
|
|
5806
5763
|
);
|
|
5807
5764
|
if (actionable.length > 0) {
|
|
5808
|
-
|
|
5765
|
+
setPhase("confirming-remediate");
|
|
5809
5766
|
}
|
|
5810
5767
|
return;
|
|
5811
5768
|
}
|
|
5812
5769
|
});
|
|
5770
|
+
if (phase === "confirming-remediate" && report) {
|
|
5771
|
+
const actionable = report.violations.filter(
|
|
5772
|
+
(v) => v.type === "missing" || v.type === "wrong-version"
|
|
5773
|
+
);
|
|
5774
|
+
return /* @__PURE__ */ jsx35(
|
|
5775
|
+
ConfirmDialog,
|
|
5776
|
+
{
|
|
5777
|
+
message: t("confirm_compliance_remediate", { count: String(actionable.length) }),
|
|
5778
|
+
onConfirm: () => {
|
|
5779
|
+
void handleRemediate();
|
|
5780
|
+
},
|
|
5781
|
+
onCancel: () => {
|
|
5782
|
+
setPhase("overview");
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5785
|
+
);
|
|
5786
|
+
}
|
|
5813
5787
|
if (phase === "remediating" || loading && phase !== "importing") {
|
|
5814
5788
|
if (phase === "remediating") {
|
|
5815
|
-
return /* @__PURE__ */
|
|
5816
|
-
/* @__PURE__ */
|
|
5817
|
-
/* @__PURE__ */
|
|
5789
|
+
return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", children: [
|
|
5790
|
+
/* @__PURE__ */ jsx35(SectionHeader, { emoji: "\u{1F50D}", title: t("compliance_title"), gradient: GRADIENTS.gold }),
|
|
5791
|
+
/* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx35(ProgressLog, { lines: streamLines, isRunning: streamRunning, title: t("compliance_remediating") }) })
|
|
5818
5792
|
] });
|
|
5819
5793
|
}
|
|
5820
|
-
return /* @__PURE__ */
|
|
5794
|
+
return /* @__PURE__ */ jsx35(Loading, { message: t("compliance_title") });
|
|
5821
5795
|
}
|
|
5822
5796
|
if (phase === "result" && resultMessage) {
|
|
5823
|
-
return /* @__PURE__ */
|
|
5824
|
-
/* @__PURE__ */
|
|
5825
|
-
/* @__PURE__ */
|
|
5797
|
+
return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5798
|
+
/* @__PURE__ */ jsx35(SectionHeader, { emoji: "\u{1F50D}", title: t("compliance_title"), gradient: GRADIENTS.gold }),
|
|
5799
|
+
/* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx35(
|
|
5826
5800
|
ResultBanner,
|
|
5827
5801
|
{
|
|
5828
5802
|
status: resultMessage.ok ? "success" : "error",
|
|
5829
5803
|
message: resultMessage.text
|
|
5830
5804
|
}
|
|
5831
5805
|
) }),
|
|
5832
|
-
/* @__PURE__ */
|
|
5806
|
+
/* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs34(Text34, { color: COLORS.textSecondary, children: [
|
|
5833
5807
|
"r:",
|
|
5834
5808
|
t("hint_refresh"),
|
|
5835
5809
|
" esc:",
|
|
@@ -5837,12 +5811,12 @@ function ComplianceView() {
|
|
|
5837
5811
|
] }) })
|
|
5838
5812
|
] });
|
|
5839
5813
|
}
|
|
5840
|
-
return /* @__PURE__ */
|
|
5841
|
-
/* @__PURE__ */
|
|
5842
|
-
error && /* @__PURE__ */
|
|
5843
|
-
phase === "importing" && /* @__PURE__ */
|
|
5844
|
-
/* @__PURE__ */
|
|
5845
|
-
/* @__PURE__ */
|
|
5814
|
+
return /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", children: [
|
|
5815
|
+
/* @__PURE__ */ jsx35(SectionHeader, { emoji: "\u{1F50D}", title: t("compliance_title"), gradient: GRADIENTS.gold }),
|
|
5816
|
+
error && /* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx35(ResultBanner, { status: "error", message: t("compliance_import_error", { error }) }) }),
|
|
5817
|
+
phase === "importing" && /* @__PURE__ */ jsxs34(Box33, { marginTop: SPACING.xs, flexDirection: "column", children: [
|
|
5818
|
+
/* @__PURE__ */ jsx35(Text34, { color: COLORS.textSecondary, children: t("compliance_import_prompt") }),
|
|
5819
|
+
/* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx35(
|
|
5846
5820
|
TextInput7,
|
|
5847
5821
|
{
|
|
5848
5822
|
defaultValue: "",
|
|
@@ -5851,31 +5825,31 @@ function ComplianceView() {
|
|
|
5851
5825
|
}
|
|
5852
5826
|
}
|
|
5853
5827
|
) }),
|
|
5854
|
-
/* @__PURE__ */
|
|
5828
|
+
/* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsxs34(Text34, { color: COLORS.muted, dimColor: true, children: [
|
|
5855
5829
|
"esc:",
|
|
5856
5830
|
t("hint_back")
|
|
5857
5831
|
] }) })
|
|
5858
5832
|
] }),
|
|
5859
|
-
phase === "overview" && /* @__PURE__ */
|
|
5860
|
-
!policy ? /* @__PURE__ */
|
|
5861
|
-
/* @__PURE__ */
|
|
5862
|
-
report ? /* @__PURE__ */
|
|
5863
|
-
/* @__PURE__ */
|
|
5864
|
-
report.compliant ? /* @__PURE__ */
|
|
5865
|
-
] }) : /* @__PURE__ */
|
|
5833
|
+
phase === "overview" && /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5834
|
+
!policy ? /* @__PURE__ */ jsx35(Box33, { flexDirection: "column", children: /* @__PURE__ */ jsx35(Text34, { color: COLORS.textSecondary, children: t("compliance_no_policy") }) }) : /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", children: [
|
|
5835
|
+
/* @__PURE__ */ jsx35(Text34, { color: COLORS.textSecondary, bold: true, children: t("compliance_policy_by", { maintainer: policy.meta.maintainer }) }),
|
|
5836
|
+
report ? /* @__PURE__ */ jsxs34(Box33, { flexDirection: "column", marginTop: SPACING.xs, children: [
|
|
5837
|
+
/* @__PURE__ */ jsx35(ComplianceScore, { report }),
|
|
5838
|
+
report.compliant ? /* @__PURE__ */ jsx35(ResultBanner, { status: "success", message: t("compliance_ok") }) : /* @__PURE__ */ jsx35(ViolationList, { violations: report.violations })
|
|
5839
|
+
] }) : /* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.xs, children: /* @__PURE__ */ jsx35(Text34, { color: COLORS.muted, dimColor: true, children: t("compliance_press_r_hint") }) })
|
|
5866
5840
|
] }),
|
|
5867
|
-
/* @__PURE__ */
|
|
5841
|
+
/* @__PURE__ */ jsx35(Box33, { marginTop: SPACING.sm, flexWrap: "wrap", children: /* @__PURE__ */ jsxs34(Text34, { color: COLORS.textSecondary, children: [
|
|
5868
5842
|
"i:",
|
|
5869
5843
|
t("hint_import"),
|
|
5870
|
-
policy && /* @__PURE__ */
|
|
5844
|
+
policy && /* @__PURE__ */ jsxs34(Text34, { children: [
|
|
5871
5845
|
" r:",
|
|
5872
5846
|
t("hint_scan")
|
|
5873
5847
|
] }),
|
|
5874
|
-
report && /* @__PURE__ */
|
|
5848
|
+
report && /* @__PURE__ */ jsxs34(Text34, { children: [
|
|
5875
5849
|
" e:",
|
|
5876
5850
|
t("hint_export")
|
|
5877
5851
|
] }),
|
|
5878
|
-
report && report.violations.some((v) => v.type === "missing" || v.type === "wrong-version") && /* @__PURE__ */
|
|
5852
|
+
report && report.violations.some((v) => v.type === "missing" || v.type === "wrong-version") && /* @__PURE__ */ jsxs34(Text34, { children: [
|
|
5879
5853
|
" c:",
|
|
5880
5854
|
t("hint_clean")
|
|
5881
5855
|
] }),
|
|
@@ -5887,10 +5861,10 @@ function ComplianceView() {
|
|
|
5887
5861
|
}
|
|
5888
5862
|
|
|
5889
5863
|
// src/app.tsx
|
|
5890
|
-
import { jsx as
|
|
5864
|
+
import { Fragment as Fragment7, jsx as jsx36, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
5891
5865
|
function LicenseInitializer() {
|
|
5892
5866
|
const initLicense = useLicenseStore((s) => s.initialize);
|
|
5893
|
-
|
|
5867
|
+
useEffect20(() => {
|
|
5894
5868
|
initLicense();
|
|
5895
5869
|
}, []);
|
|
5896
5870
|
return null;
|
|
@@ -5899,70 +5873,80 @@ function ViewRouter({ currentView }) {
|
|
|
5899
5873
|
const isPro = useLicenseStore((s) => s.isPro);
|
|
5900
5874
|
const isTeam = useLicenseStore((s) => s.isTeam);
|
|
5901
5875
|
if (isProView(currentView) && !isPro()) {
|
|
5902
|
-
return /* @__PURE__ */
|
|
5876
|
+
return /* @__PURE__ */ jsx36(UpgradePrompt, { viewId: currentView });
|
|
5903
5877
|
}
|
|
5904
5878
|
if (isTeamView(currentView) && !isTeam()) {
|
|
5905
|
-
return /* @__PURE__ */
|
|
5879
|
+
return /* @__PURE__ */ jsx36(UpgradePrompt, { viewId: currentView });
|
|
5906
5880
|
}
|
|
5907
5881
|
switch (currentView) {
|
|
5908
5882
|
case "dashboard":
|
|
5909
|
-
return /* @__PURE__ */
|
|
5883
|
+
return /* @__PURE__ */ jsx36(DashboardView, {});
|
|
5910
5884
|
case "installed":
|
|
5911
|
-
return /* @__PURE__ */
|
|
5885
|
+
return /* @__PURE__ */ jsx36(InstalledView, {});
|
|
5912
5886
|
case "search":
|
|
5913
|
-
return /* @__PURE__ */
|
|
5887
|
+
return /* @__PURE__ */ jsx36(SearchView, {});
|
|
5914
5888
|
case "outdated":
|
|
5915
|
-
return /* @__PURE__ */
|
|
5889
|
+
return /* @__PURE__ */ jsx36(OutdatedView, {});
|
|
5916
5890
|
case "package-info":
|
|
5917
|
-
return /* @__PURE__ */
|
|
5891
|
+
return /* @__PURE__ */ jsx36(PackageInfoView, {});
|
|
5918
5892
|
case "services":
|
|
5919
|
-
return /* @__PURE__ */
|
|
5893
|
+
return /* @__PURE__ */ jsx36(ServicesView, {});
|
|
5920
5894
|
case "doctor":
|
|
5921
|
-
return /* @__PURE__ */
|
|
5895
|
+
return /* @__PURE__ */ jsx36(DoctorView, {});
|
|
5922
5896
|
case "profiles":
|
|
5923
|
-
return /* @__PURE__ */
|
|
5897
|
+
return /* @__PURE__ */ jsx36(ProfilesView, {});
|
|
5924
5898
|
case "smart-cleanup":
|
|
5925
|
-
return /* @__PURE__ */
|
|
5899
|
+
return /* @__PURE__ */ jsx36(SmartCleanupView, {});
|
|
5926
5900
|
case "history":
|
|
5927
|
-
return /* @__PURE__ */
|
|
5901
|
+
return /* @__PURE__ */ jsx36(HistoryView, {});
|
|
5928
5902
|
case "rollback":
|
|
5929
|
-
return /* @__PURE__ */
|
|
5903
|
+
return /* @__PURE__ */ jsx36(RollbackView, {});
|
|
5930
5904
|
case "brewfile":
|
|
5931
|
-
return /* @__PURE__ */
|
|
5905
|
+
return /* @__PURE__ */ jsx36(BrewfileView, {});
|
|
5932
5906
|
case "sync":
|
|
5933
|
-
return /* @__PURE__ */
|
|
5907
|
+
return /* @__PURE__ */ jsx36(SyncView, {});
|
|
5934
5908
|
case "security-audit":
|
|
5935
|
-
return /* @__PURE__ */
|
|
5909
|
+
return /* @__PURE__ */ jsx36(SecurityAuditView, {});
|
|
5936
5910
|
case "compliance":
|
|
5937
|
-
return /* @__PURE__ */
|
|
5911
|
+
return /* @__PURE__ */ jsx36(ComplianceView, {});
|
|
5938
5912
|
case "account":
|
|
5939
|
-
return /* @__PURE__ */
|
|
5913
|
+
return /* @__PURE__ */ jsx36(AccountView, {});
|
|
5940
5914
|
}
|
|
5941
5915
|
}
|
|
5942
5916
|
function App() {
|
|
5943
5917
|
const { exit } = useApp();
|
|
5944
5918
|
const currentView = useNavigationStore((s) => s.currentView);
|
|
5919
|
+
const isTestEnv = typeof process !== "undefined" && false;
|
|
5920
|
+
const [showWelcome, setShowWelcome] = useState17(isTestEnv ? false : null);
|
|
5921
|
+
useEffect20(() => {
|
|
5922
|
+
if (isTestEnv) return;
|
|
5923
|
+
void hasCompletedOnboarding().then((done) => setShowWelcome(!done));
|
|
5924
|
+
}, []);
|
|
5945
5925
|
useGlobalKeyboard({ onQuit: exit });
|
|
5946
|
-
|
|
5947
|
-
/* @__PURE__ */
|
|
5948
|
-
|
|
5926
|
+
if (showWelcome === null) {
|
|
5927
|
+
return /* @__PURE__ */ jsx36(AppLayout, { children: /* @__PURE__ */ jsx36(Fragment7, {}) });
|
|
5928
|
+
}
|
|
5929
|
+
if (showWelcome) {
|
|
5930
|
+
return /* @__PURE__ */ jsx36(AppLayout, { children: /* @__PURE__ */ jsx36(WelcomeView, { onContinue: () => setShowWelcome(false) }) });
|
|
5931
|
+
}
|
|
5932
|
+
return /* @__PURE__ */ jsxs35(AppLayout, { children: [
|
|
5933
|
+
/* @__PURE__ */ jsx36(LicenseInitializer, {}),
|
|
5934
|
+
/* @__PURE__ */ jsx36(ViewRouter, { currentView })
|
|
5949
5935
|
] });
|
|
5950
5936
|
}
|
|
5951
5937
|
|
|
5952
5938
|
// src/lib/crash-reporter.ts
|
|
5953
|
-
import { readFile as
|
|
5954
|
-
import {
|
|
5955
|
-
import {
|
|
5956
|
-
import { join as join6 } from "path";
|
|
5939
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
5940
|
+
import { homedir, platform, release, arch } from "os";
|
|
5941
|
+
import { join as join5 } from "path";
|
|
5957
5942
|
var ENDPOINT_ENV = "BREW_TUI_CRASH_ENDPOINT";
|
|
5958
5943
|
var TOKEN_ENV = "BREW_TUI_CRASH_TOKEN";
|
|
5959
|
-
var CONFIG_PATH =
|
|
5960
|
-
var MACHINE_ID_PATH3 = join6(homedir3(), ".brew-tui", "machine-id");
|
|
5944
|
+
var CONFIG_PATH = join5(homedir(), ".brew-tui", "crash-reporter.json");
|
|
5961
5945
|
var POST_TIMEOUT_MS = 5e3;
|
|
5962
5946
|
var _installed = false;
|
|
5963
5947
|
async function loadConfigFromDisk() {
|
|
5964
5948
|
try {
|
|
5965
|
-
const raw = await
|
|
5949
|
+
const raw = await readFile3(CONFIG_PATH, "utf-8");
|
|
5966
5950
|
const parsed = JSON.parse(raw);
|
|
5967
5951
|
return {
|
|
5968
5952
|
endpoint: typeof parsed.endpoint === "string" ? parsed.endpoint : null,
|
|
@@ -5973,20 +5957,6 @@ async function loadConfigFromDisk() {
|
|
|
5973
5957
|
return { endpoint: null, token: null, enabled: false };
|
|
5974
5958
|
}
|
|
5975
5959
|
}
|
|
5976
|
-
async function getMachineId4() {
|
|
5977
|
-
try {
|
|
5978
|
-
const id2 = (await readFile5(MACHINE_ID_PATH3, "utf-8")).trim();
|
|
5979
|
-
if (id2) return id2;
|
|
5980
|
-
} catch {
|
|
5981
|
-
}
|
|
5982
|
-
const id = randomUUID3();
|
|
5983
|
-
try {
|
|
5984
|
-
await mkdir3(join6(homedir3(), ".brew-tui"), { recursive: true, mode: 448 });
|
|
5985
|
-
await writeFile5(MACHINE_ID_PATH3, id, { encoding: "utf-8", mode: 384 });
|
|
5986
|
-
} catch {
|
|
5987
|
-
}
|
|
5988
|
-
return id;
|
|
5989
|
-
}
|
|
5990
5960
|
async function resolveConfig() {
|
|
5991
5961
|
const envEndpoint = process.env[ENDPOINT_ENV]?.trim();
|
|
5992
5962
|
const envToken = process.env[TOKEN_ENV]?.trim();
|
|
@@ -6044,8 +6014,8 @@ function buildReport(level, err, context, machineId, version) {
|
|
|
6044
6014
|
async function reportError(err, context = {}) {
|
|
6045
6015
|
const config = await resolveConfig();
|
|
6046
6016
|
if (!config.enabled || !config.endpoint) return;
|
|
6047
|
-
const machineId = await
|
|
6048
|
-
const version = true ? "0.
|
|
6017
|
+
const machineId = await getMachineId();
|
|
6018
|
+
const version = true ? "0.7.0" : "unknown";
|
|
6049
6019
|
await postReport(buildReport("error", err, context, machineId, version), config);
|
|
6050
6020
|
}
|
|
6051
6021
|
async function installCrashReporter() {
|
|
@@ -6053,8 +6023,8 @@ async function installCrashReporter() {
|
|
|
6053
6023
|
const config = await resolveConfig();
|
|
6054
6024
|
if (!config.enabled || !config.endpoint) return;
|
|
6055
6025
|
_installed = true;
|
|
6056
|
-
const machineId = await
|
|
6057
|
-
const version = true ? "0.
|
|
6026
|
+
const machineId = await getMachineId();
|
|
6027
|
+
const version = true ? "0.7.0" : "unknown";
|
|
6058
6028
|
process.on("uncaughtException", (err) => {
|
|
6059
6029
|
void postReport(buildReport("fatal", err, { kind: "uncaughtException" }, machineId, version), config);
|
|
6060
6030
|
});
|
|
@@ -6065,7 +6035,7 @@ async function installCrashReporter() {
|
|
|
6065
6035
|
}
|
|
6066
6036
|
|
|
6067
6037
|
// src/index.tsx
|
|
6068
|
-
import { jsx as
|
|
6038
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
6069
6039
|
var [, , command, arg] = process.argv;
|
|
6070
6040
|
async function runCli() {
|
|
6071
6041
|
await ensureDataDirs();
|
|
@@ -6160,7 +6130,7 @@ async function runCli() {
|
|
|
6160
6130
|
}
|
|
6161
6131
|
if (isPro) {
|
|
6162
6132
|
try {
|
|
6163
|
-
const { loadSnapshots: loadSnapshots2 } = await import("./snapshot-
|
|
6133
|
+
const { loadSnapshots: loadSnapshots2 } = await import("./snapshot-JDRSBMG6.js");
|
|
6164
6134
|
const snapshots = await loadSnapshots2();
|
|
6165
6135
|
if (snapshots.length > 0) {
|
|
6166
6136
|
const latest = snapshots[0];
|
|
@@ -6172,7 +6142,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
|
|
|
6172
6142
|
} catch {
|
|
6173
6143
|
}
|
|
6174
6144
|
try {
|
|
6175
|
-
const { loadBrewfile: loadBrewfile2, computeDrift: computeDrift2 } = await import("./brewfile-manager-
|
|
6145
|
+
const { loadBrewfile: loadBrewfile2, computeDrift: computeDrift2 } = await import("./brewfile-manager-6LXONGSA.js");
|
|
6176
6146
|
const schema = await loadBrewfile2();
|
|
6177
6147
|
if (schema) {
|
|
6178
6148
|
const drift = await computeDrift2(schema);
|
|
@@ -6181,7 +6151,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
|
|
|
6181
6151
|
} catch {
|
|
6182
6152
|
}
|
|
6183
6153
|
try {
|
|
6184
|
-
const { loadSyncConfig: loadSyncConfig2 } = await import("./sync-engine-
|
|
6154
|
+
const { loadSyncConfig: loadSyncConfig2 } = await import("./sync-engine-4OA4JNR3.js");
|
|
6185
6155
|
const syncConfig = await loadSyncConfig2();
|
|
6186
6156
|
if (syncConfig?.lastSync) {
|
|
6187
6157
|
console.log(`Sync: last sync ${formatDate(syncConfig.lastSync)}`);
|
|
@@ -6190,7 +6160,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
|
|
|
6190
6160
|
}
|
|
6191
6161
|
try {
|
|
6192
6162
|
const { loadPolicy: loadPolicy2 } = await import("./policy-io-EECGRKNA.js");
|
|
6193
|
-
const { checkCompliance: checkCompliance2 } = await import("./compliance-checker-
|
|
6163
|
+
const { checkCompliance: checkCompliance2 } = await import("./compliance-checker-MAREAFDH.js");
|
|
6194
6164
|
const policy = await loadPolicy2(`${process.env["HOME"] ?? "~"}/.brew-tui/policy.yaml`).catch(() => null);
|
|
6195
6165
|
if (policy) {
|
|
6196
6166
|
const report = await checkCompliance2(policy, true);
|
|
@@ -6204,7 +6174,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
|
|
|
6204
6174
|
if (command === "install-brewbar") {
|
|
6205
6175
|
await useLicenseStore.getState().initialize();
|
|
6206
6176
|
const isPro = useLicenseStore.getState().isPro();
|
|
6207
|
-
const { installBrewBar } = await import("./brewbar-installer-
|
|
6177
|
+
const { installBrewBar } = await import("./brewbar-installer-KJTIZIVU.js");
|
|
6208
6178
|
try {
|
|
6209
6179
|
await installBrewBar(isPro, arg === "--force");
|
|
6210
6180
|
console.log(t("cli_brewbarInstalled"));
|
|
@@ -6215,7 +6185,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
|
|
|
6215
6185
|
return;
|
|
6216
6186
|
}
|
|
6217
6187
|
if (command === "uninstall-brewbar") {
|
|
6218
|
-
const { uninstallBrewBar } = await import("./brewbar-installer-
|
|
6188
|
+
const { uninstallBrewBar } = await import("./brewbar-installer-KJTIZIVU.js");
|
|
6219
6189
|
try {
|
|
6220
6190
|
await uninstallBrewBar();
|
|
6221
6191
|
console.log(t("cli_brewbarUninstalled"));
|
|
@@ -6233,20 +6203,20 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
|
|
|
6233
6203
|
console.log(t("cli_deactivateCancelled"));
|
|
6234
6204
|
return;
|
|
6235
6205
|
}
|
|
6236
|
-
await
|
|
6206
|
+
await rm2(DATA_DIR, { recursive: true, force: true });
|
|
6237
6207
|
console.log(t("delete_account_success"));
|
|
6238
6208
|
return;
|
|
6239
6209
|
}
|
|
6240
6210
|
await ensureBrewBarRunning();
|
|
6241
6211
|
process.env.BREW_TUI_TUI_MODE = "1";
|
|
6242
6212
|
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
6243
|
-
render(/* @__PURE__ */
|
|
6213
|
+
render(/* @__PURE__ */ jsx37(App, {}));
|
|
6244
6214
|
}
|
|
6245
6215
|
async function ensureBrewBarRunning() {
|
|
6246
6216
|
if (process.platform !== "darwin") return;
|
|
6247
6217
|
await useLicenseStore.getState().initialize();
|
|
6248
6218
|
if (!useLicenseStore.getState().isPro()) return;
|
|
6249
|
-
const { isBrewBarInstalled, installBrewBar, launchBrewBar } = await import("./brewbar-installer-
|
|
6219
|
+
const { isBrewBarInstalled, installBrewBar, launchBrewBar } = await import("./brewbar-installer-KJTIZIVU.js");
|
|
6250
6220
|
try {
|
|
6251
6221
|
if (!await isBrewBarInstalled()) {
|
|
6252
6222
|
console.log(t("cli_brewbarInstalling"));
|