brew-tui 1.2.1 → 1.2.3

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.
Files changed (37) hide show
  1. package/build/{brewbar-installer-GWJ76J6G.js → brewbar-installer-2OHLRM27.js} +37 -3
  2. package/build/brewbar-installer-2OHLRM27.js.map +1 -0
  3. package/build/{brewfile-manager-G7Q4IOG3.js → brewfile-manager-CPVXIVZC.js} +4 -3
  4. package/build/{chunk-KN4GCMIE.js → chunk-5PJWI4XS.js} +20 -1
  5. package/build/chunk-5PJWI4XS.js.map +1 -0
  6. package/build/{chunk-BRXZG7ZL.js → chunk-CMIC4N74.js} +11 -3
  7. package/build/chunk-CMIC4N74.js.map +1 -0
  8. package/build/{chunk-KDKXGXN2.js → chunk-EDQPT5EF.js} +15 -8
  9. package/build/chunk-EDQPT5EF.js.map +1 -0
  10. package/build/{chunk-J6HCX7RG.js → chunk-JNEIP2LJ.js} +2 -2
  11. package/build/chunk-NRRQECXA.js +63 -0
  12. package/build/chunk-NRRQECXA.js.map +1 -0
  13. package/build/{chunk-WDRT6G63.js → chunk-WX7MPVPH.js} +6 -46
  14. package/build/chunk-WX7MPVPH.js.map +1 -0
  15. package/build/{chunk-QX5DEW3S.js → chunk-XI743B6D.js} +408 -2
  16. package/build/chunk-XI743B6D.js.map +1 -0
  17. package/build/{compliance-checker-IXZHIMQG.js → compliance-checker-3FDEX4OI.js} +3 -3
  18. package/build/index.js +115 -400
  19. package/build/index.js.map +1 -1
  20. package/build/{policy-io-EECGRKNA.js → policy-io-P5YIH6C7.js} +2 -2
  21. package/build/{snapshot-ZOJETCED.js → snapshot-RQ444U5L.js} +2 -2
  22. package/build/{sync-engine-76YMONYH.js → sync-engine-Q4B2PPQS.js} +5 -4
  23. package/build/{version-check-AIYMRDFF.js → version-check-NS6RPUSU.js} +2 -2
  24. package/package.json +3 -2
  25. package/build/brewbar-installer-GWJ76J6G.js.map +0 -1
  26. package/build/chunk-BRXZG7ZL.js.map +0 -1
  27. package/build/chunk-KDKXGXN2.js.map +0 -1
  28. package/build/chunk-KN4GCMIE.js.map +0 -1
  29. package/build/chunk-QX5DEW3S.js.map +0 -1
  30. package/build/chunk-WDRT6G63.js.map +0 -1
  31. /package/build/{brewfile-manager-G7Q4IOG3.js.map → brewfile-manager-CPVXIVZC.js.map} +0 -0
  32. /package/build/{chunk-J6HCX7RG.js.map → chunk-JNEIP2LJ.js.map} +0 -0
  33. /package/build/{compliance-checker-IXZHIMQG.js.map → compliance-checker-3FDEX4OI.js.map} +0 -0
  34. /package/build/{policy-io-EECGRKNA.js.map → policy-io-P5YIH6C7.js.map} +0 -0
  35. /package/build/{snapshot-ZOJETCED.js.map → snapshot-RQ444U5L.js.map} +0 -0
  36. /package/build/{sync-engine-76YMONYH.js.map → sync-engine-Q4B2PPQS.js.map} +0 -0
  37. /package/build/{version-check-AIYMRDFF.js.map → version-check-NS6RPUSU.js.map} +0 -0
@@ -1,12 +1,17 @@
1
1
  import {
2
+ BREW_BIN,
2
3
  captureSnapshot,
4
+ execBrew,
3
5
  saveSnapshot,
4
6
  streamBrew
5
- } from "./chunk-BRXZG7ZL.js";
7
+ } from "./chunk-CMIC4N74.js";
6
8
  import {
7
9
  DATA_DIR,
8
10
  ensureDataDirs
9
11
  } from "./chunk-IGDHDXUH.js";
12
+ import {
13
+ t
14
+ } from "./chunk-WX7MPVPH.js";
10
15
  import {
11
16
  logger
12
17
  } from "./chunk-KDHEUNRI.js";
@@ -354,6 +359,376 @@ function parseBrewfile(yaml) {
354
359
  return result;
355
360
  }
356
361
 
362
+ // src/lib/brew-api.ts
363
+ import { spawn } from "child_process";
364
+
365
+ // src/lib/parsers/json-parser.ts
366
+ function safeParse(raw, context) {
367
+ try {
368
+ const result = JSON.parse(raw);
369
+ if (result === null || result === void 0) {
370
+ throw new Error(`${context} returned null or empty response`);
371
+ }
372
+ return result;
373
+ } catch (err) {
374
+ throw new Error(`Failed to parse ${context} JSON: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
375
+ }
376
+ }
377
+ function parseInstalledJson(raw) {
378
+ const data = safeParse(raw, "brew info --installed");
379
+ return {
380
+ formulae: Array.isArray(data.formulae) ? data.formulae : [],
381
+ casks: Array.isArray(data.casks) ? data.casks : []
382
+ };
383
+ }
384
+ function parseOutdatedJson(raw) {
385
+ const data = safeParse(raw, "brew outdated");
386
+ return {
387
+ formulae: Array.isArray(data.formulae) ? data.formulae : [],
388
+ casks: Array.isArray(data.casks) ? data.casks : []
389
+ };
390
+ }
391
+ function parseServicesJson(raw) {
392
+ const data = safeParse(raw, "brew services list");
393
+ if (!Array.isArray(data)) return [];
394
+ return data.map((s) => ({
395
+ name: s.name,
396
+ status: s.status ?? "none",
397
+ user: s.user ?? null,
398
+ file: s.file ?? null,
399
+ exit_code: s.exit_code ?? null
400
+ }));
401
+ }
402
+ function parseFormulaInfoJson(raw) {
403
+ const data = safeParse(raw, "brew info");
404
+ return data.formulae?.[0] ?? null;
405
+ }
406
+
407
+ // src/lib/parsers/text-parser.ts
408
+ function parseSearchResults(raw) {
409
+ const lines = raw.split("\n").map((l) => l.trim()).filter(Boolean);
410
+ const formulae = [];
411
+ const casks = [];
412
+ let section = "formulae";
413
+ for (const line of lines) {
414
+ if (line.startsWith("==> Formulae")) {
415
+ section = "formulae";
416
+ continue;
417
+ }
418
+ if (line.startsWith("==> Casks")) {
419
+ section = "casks";
420
+ continue;
421
+ }
422
+ if (line.startsWith("==>")) continue;
423
+ if (section === "formulae") formulae.push(line);
424
+ else casks.push(line);
425
+ }
426
+ return { formulae, casks };
427
+ }
428
+ function parseDoctorOutput(raw) {
429
+ const cleaned = raw.trim();
430
+ if (cleaned.includes("Your system is ready to brew")) {
431
+ return { warnings: [], isClean: true };
432
+ }
433
+ const warnings = [];
434
+ let current = "";
435
+ for (const line of cleaned.split("\n")) {
436
+ if (line.startsWith("Warning:")) {
437
+ if (current) warnings.push(current.trim());
438
+ current = line;
439
+ } else if (current) {
440
+ current += "\n" + line;
441
+ }
442
+ }
443
+ if (current) warnings.push(current.trim());
444
+ return { warnings, isClean: false };
445
+ }
446
+ function parseBrewConfig(raw) {
447
+ const lines = raw.split("\n");
448
+ const get = (key) => {
449
+ const line = lines.find((l) => l.startsWith(key));
450
+ return line?.split(":").slice(1).join(":").trim() ?? "";
451
+ };
452
+ return {
453
+ HOMEBREW_VERSION: get("HOMEBREW_VERSION"),
454
+ HOMEBREW_PREFIX: get("HOMEBREW_PREFIX"),
455
+ coreUpdated: get("Core tap last commit") || get("Core tap JSON")
456
+ };
457
+ }
458
+ function parseLeavesOutput(raw) {
459
+ return raw.split("\n").map((l) => l.trim()).filter(Boolean);
460
+ }
461
+
462
+ // src/lib/impact/impact-analyzer.ts
463
+ var HIGH_RISK_PACKAGES = /* @__PURE__ */ new Set([
464
+ "openssl",
465
+ "openssl@3",
466
+ "openssl@1.1",
467
+ "python",
468
+ "python@3",
469
+ "python@3.11",
470
+ "python@3.12",
471
+ "python@3.13",
472
+ "node",
473
+ "node@18",
474
+ "node@20",
475
+ "ruby",
476
+ "ruby@3",
477
+ "sqlite",
478
+ "sqlite3",
479
+ "libpq",
480
+ "postgresql",
481
+ "postgresql@16",
482
+ "glibc",
483
+ "gcc",
484
+ "llvm"
485
+ ]);
486
+ function isMajorVersionBump(from, to) {
487
+ const fromMajor = parseInt(from.split(".")[0] ?? "0", 10);
488
+ const toMajor = parseInt(to.split(".")[0] ?? "0", 10);
489
+ return !isNaN(fromMajor) && !isNaN(toMajor) && toMajor > fromMajor;
490
+ }
491
+ function calculateRisk(name, reverseDeps, fromVersion, toVersion) {
492
+ const reasons = [];
493
+ if (HIGH_RISK_PACKAGES.has(name)) {
494
+ reasons.push(t("impact_reason_critical_package"));
495
+ return { risk: "high", reasons };
496
+ }
497
+ if (reverseDeps.length > 10) {
498
+ reasons.push(t("impact_reason_many_deps", { count: reverseDeps.length }));
499
+ return { risk: "high", reasons };
500
+ }
501
+ let factorCount = 0;
502
+ if (reverseDeps.length >= 3) {
503
+ factorCount++;
504
+ reasons.push(t("impact_reason_many_deps", { count: reverseDeps.length }));
505
+ }
506
+ if (isMajorVersionBump(fromVersion, toVersion)) {
507
+ factorCount++;
508
+ reasons.push(t("impact_reason_major_bump"));
509
+ }
510
+ const risk = factorCount >= 2 ? "high" : factorCount === 1 ? "medium" : "low";
511
+ return { risk, reasons };
512
+ }
513
+ async function analyzeUpgradeImpact(packageName, fromVersion, toVersion, packageType) {
514
+ if (packageType === "cask") {
515
+ return {
516
+ packageName,
517
+ fromVersion,
518
+ toVersion,
519
+ packageType,
520
+ directDeps: [],
521
+ reverseDeps: [],
522
+ risk: "low",
523
+ riskReasons: []
524
+ };
525
+ }
526
+ let directDeps = [];
527
+ let reverseDeps = [];
528
+ try {
529
+ const depsOutput = await execBrew(["deps", "--1", packageName]);
530
+ directDeps = depsOutput.split("\n").filter((l) => l.trim() !== "");
531
+ } catch (err) {
532
+ logger.warn(`impact-analyzer: deps failed for ${packageName}: ${err instanceof Error ? err.message : String(err)}`);
533
+ }
534
+ try {
535
+ const usesOutput = await execBrew(["uses", "--installed", packageName]);
536
+ reverseDeps = usesOutput.split("\n").filter((l) => l.trim() !== "");
537
+ } catch (err) {
538
+ logger.warn(`impact-analyzer: uses failed for ${packageName}: ${err instanceof Error ? err.message : String(err)}`);
539
+ }
540
+ const { risk, reasons } = calculateRisk(packageName, reverseDeps, fromVersion, toVersion);
541
+ return {
542
+ packageName,
543
+ fromVersion,
544
+ toVersion,
545
+ packageType,
546
+ directDeps,
547
+ reverseDeps,
548
+ risk,
549
+ riskReasons: reasons
550
+ };
551
+ }
552
+
553
+ // src/lib/brew-api.ts
554
+ var PKG_PATTERN = /^[\w@./+-]+$/;
555
+ function validatePackageName(name) {
556
+ if (!PKG_PATTERN.test(name)) throw new Error("Invalid package name: " + name);
557
+ }
558
+ async function brewUpdate() {
559
+ return new Promise((resolve, reject) => {
560
+ const proc = spawn(BREW_BIN, ["update"], { stdio: "ignore" });
561
+ let settled = false;
562
+ const timeout = setTimeout(() => {
563
+ if (settled) return;
564
+ settled = true;
565
+ proc.kill("SIGTERM");
566
+ reject(new Error("brew update timed out after 120s"));
567
+ }, 12e4);
568
+ proc.on("close", (code) => {
569
+ if (settled) return;
570
+ settled = true;
571
+ clearTimeout(timeout);
572
+ if (code === 0) resolve();
573
+ else reject(new Error(`brew update exited with code ${code}`));
574
+ });
575
+ proc.on("error", (err) => {
576
+ if (settled) return;
577
+ settled = true;
578
+ clearTimeout(timeout);
579
+ reject(err);
580
+ });
581
+ });
582
+ }
583
+ async function getInstalled() {
584
+ const raw = await execBrew(["info", "--json=v2", "--installed"]);
585
+ return parseInstalledJson(raw);
586
+ }
587
+ async function getOutdated() {
588
+ const raw = await execBrew(["outdated", "--json=v2"]);
589
+ return parseOutdatedJson(raw);
590
+ }
591
+ async function getServices() {
592
+ const raw = await execBrew(["services", "list", "--json"]);
593
+ return parseServicesJson(raw);
594
+ }
595
+ async function getFormulaInfo(name) {
596
+ validatePackageName(name);
597
+ const raw = await execBrew(["info", "--json=v2", name]);
598
+ return parseFormulaInfoJson(raw);
599
+ }
600
+ async function getCaskInfo(name) {
601
+ validatePackageName(name);
602
+ try {
603
+ const raw = await execBrew(["info", "--json=v2", "--cask", name]);
604
+ const data = JSON.parse(raw);
605
+ return data.casks?.[0] ?? null;
606
+ } catch {
607
+ return null;
608
+ }
609
+ }
610
+ function formulaeFromCask(cask) {
611
+ return {
612
+ name: cask.token,
613
+ full_name: cask.full_token,
614
+ tap: "",
615
+ desc: cask.desc,
616
+ license: "",
617
+ homepage: cask.homepage,
618
+ versions: { stable: cask.version, head: null, bottle: false },
619
+ dependencies: [],
620
+ build_dependencies: [],
621
+ installed: cask.installed ? [{
622
+ version: cask.installed,
623
+ used_options: [],
624
+ built_as_bottle: false,
625
+ poured_from_bottle: false,
626
+ time: cask.installed_time ?? 0,
627
+ runtime_dependencies: [],
628
+ installed_as_dependency: false,
629
+ installed_on_request: true
630
+ }] : [],
631
+ linked_keg: null,
632
+ pinned: false,
633
+ outdated: cask.outdated,
634
+ deprecated: false,
635
+ keg_only: false,
636
+ caveats: null
637
+ };
638
+ }
639
+ async function search(term) {
640
+ const safeTerm = term.replace(/^-+/, "");
641
+ if (!safeTerm) return { formulae: [], casks: [] };
642
+ const raw = await execBrew(["search", safeTerm]);
643
+ return parseSearchResults(raw);
644
+ }
645
+ async function getDoctor() {
646
+ try {
647
+ const raw = await execBrew(["doctor"]);
648
+ return parseDoctorOutput(raw);
649
+ } catch (err) {
650
+ const msg = err instanceof Error ? err.message : String(err);
651
+ return parseDoctorOutput(msg);
652
+ }
653
+ }
654
+ async function getConfig() {
655
+ const raw = await execBrew(["config"]);
656
+ return parseBrewConfig(raw);
657
+ }
658
+ async function getLeaves() {
659
+ const raw = await execBrew(["leaves"]);
660
+ return parseLeavesOutput(raw);
661
+ }
662
+ async function uninstallPackage(name) {
663
+ validatePackageName(name);
664
+ return execBrew(["uninstall", name]);
665
+ }
666
+ async function serviceAction(name, action) {
667
+ validatePackageName(name);
668
+ return execBrew(["services", action, name]);
669
+ }
670
+ async function pinPackage(name) {
671
+ validatePackageName(name);
672
+ return execBrew(["pin", name]);
673
+ }
674
+ async function unpinPackage(name) {
675
+ validatePackageName(name);
676
+ return execBrew(["unpin", name]);
677
+ }
678
+ function formulaeToListItems(formulae) {
679
+ return formulae.map((f) => {
680
+ const installed = f.installed[0];
681
+ return {
682
+ name: f.name,
683
+ version: installed?.version ?? f.versions.stable,
684
+ desc: f.desc,
685
+ type: "formula",
686
+ outdated: f.outdated,
687
+ pinned: f.pinned,
688
+ kegOnly: f.keg_only,
689
+ installedAsDependency: installed?.installed_as_dependency ?? false,
690
+ installedTime: installed?.time ?? null
691
+ };
692
+ });
693
+ }
694
+ var impactCache = /* @__PURE__ */ new Map();
695
+ var IMPACT_CACHE_LIMIT = 64;
696
+ var IMPACT_CACHE_TTL_MS = 5 * 60 * 1e3;
697
+ function impactKey(name, from, to, type) {
698
+ return `${type}::${name}::${from}::${to}`;
699
+ }
700
+ async function getUpgradeImpact(packageName, fromVersion, toVersion, packageType) {
701
+ validatePackageName(packageName);
702
+ const key = impactKey(packageName, fromVersion, toVersion, packageType);
703
+ const cached = impactCache.get(key);
704
+ if (cached && Date.now() - cached.cachedAt < IMPACT_CACHE_TTL_MS) {
705
+ return cached.result;
706
+ }
707
+ if (cached) {
708
+ impactCache.delete(key);
709
+ }
710
+ const result = await analyzeUpgradeImpact(packageName, fromVersion, toVersion, packageType);
711
+ if (impactCache.size >= IMPACT_CACHE_LIMIT) {
712
+ const firstKey = impactCache.keys().next().value;
713
+ if (firstKey !== void 0) impactCache.delete(firstKey);
714
+ }
715
+ impactCache.set(key, { result, cachedAt: Date.now() });
716
+ return result;
717
+ }
718
+ function casksToListItems(casks) {
719
+ return casks.map((c) => ({
720
+ name: c.token,
721
+ version: c.installed ?? c.version,
722
+ desc: c.desc,
723
+ type: "cask",
724
+ outdated: c.outdated,
725
+ pinned: false,
726
+ kegOnly: false,
727
+ installedAsDependency: false,
728
+ installedTime: c.installed_time ?? null
729
+ }));
730
+ }
731
+
357
732
  // src/lib/brewfile/brewfile-manager.ts
358
733
  var BREWFILE_PATH = join(DATA_DIR, "brewfile.yaml");
359
734
  async function loadBrewfile() {
@@ -415,6 +790,12 @@ async function* reconcile(schema, isPro) {
415
790
  return;
416
791
  }
417
792
  for (const name of report.missingPackages) {
793
+ try {
794
+ validatePackageName(name);
795
+ } catch (err) {
796
+ yield `\u2717 Rejected ${name}: ${err instanceof Error ? err.message : String(err)}`;
797
+ continue;
798
+ }
418
799
  yield `\u2192 Installing ${name}...`;
419
800
  try {
420
801
  for await (const line of streamBrew(["install", name])) {
@@ -426,6 +807,12 @@ async function* reconcile(schema, isPro) {
426
807
  }
427
808
  for (const { name, desired } of report.wrongVersions) {
428
809
  const target = `${name}@${desired}`;
810
+ try {
811
+ validatePackageName(target);
812
+ } catch (err) {
813
+ yield `\u2717 Rejected ${target}: ${err instanceof Error ? err.message : String(err)}`;
814
+ continue;
815
+ }
429
816
  yield `\u2192 Installing ${target}...`;
430
817
  try {
431
818
  for await (const line of streamBrew(["install", target])) {
@@ -456,6 +843,25 @@ function isNodeError(err) {
456
843
  }
457
844
 
458
845
  export {
846
+ validatePackageName,
847
+ brewUpdate,
848
+ getInstalled,
849
+ getOutdated,
850
+ getServices,
851
+ getFormulaInfo,
852
+ getCaskInfo,
853
+ formulaeFromCask,
854
+ search,
855
+ getDoctor,
856
+ getConfig,
857
+ getLeaves,
858
+ uninstallPackage,
859
+ serviceAction,
860
+ pinPackage,
861
+ unpinPackage,
862
+ formulaeToListItems,
863
+ getUpgradeImpact,
864
+ casksToListItems,
459
865
  diffSnapshots,
460
866
  BREWFILE_PATH,
461
867
  loadBrewfile,
@@ -464,4 +870,4 @@ export {
464
870
  computeDrift,
465
871
  reconcile
466
872
  };
467
- //# sourceMappingURL=chunk-QX5DEW3S.js.map
873
+ //# sourceMappingURL=chunk-XI743B6D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/brewfile/brewfile-manager.ts","../src/lib/diff-engine/diff.ts","../src/lib/brewfile/yaml-serializer.ts","../src/lib/brew-api.ts","../src/lib/parsers/json-parser.ts","../src/lib/parsers/text-parser.ts","../src/lib/impact/impact-analyzer.ts"],"sourcesContent":["import { readFile, writeFile, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { DATA_DIR, ensureDataDirs } from '../data-dir.js';\nimport { captureSnapshot, saveSnapshot } from '../state-snapshot/snapshot.js';\nimport { diffDesiredActual } from '../diff-engine/diff.js';\nimport { serializeBrewfile, parseBrewfile } from './yaml-serializer.js';\nimport { streamBrew } from '../brew-cli.js';\nimport { validatePackageName } from '../brew-api.js';\nimport { logger } from '../../utils/logger.js';\nimport type { BrewfileSchema, DriftReport } from './types.js';\n\nexport const BREWFILE_PATH = join(DATA_DIR, 'brewfile.yaml');\n\nexport async function loadBrewfile(): Promise<BrewfileSchema | null> {\n try {\n const raw = await readFile(BREWFILE_PATH, 'utf-8');\n return parseBrewfile(raw);\n } catch (err) {\n if (isNodeError(err) && err.code === 'ENOENT') {\n return null;\n }\n logger.warn('Failed to parse Brewfile', { error: String(err) });\n return null;\n }\n}\n\nexport async function saveBrewfile(schema: BrewfileSchema): Promise<void> {\n await ensureDataDirs();\n const updated: BrewfileSchema = {\n ...schema,\n meta: { ...schema.meta, updatedAt: new Date().toISOString() },\n };\n const tmpPath = BREWFILE_PATH + '.tmp';\n await writeFile(tmpPath, serializeBrewfile(updated), { encoding: 'utf-8', mode: 0o600 });\n await rename(tmpPath, BREWFILE_PATH);\n}\n\nexport async function createDefaultBrewfile(name: string): Promise<BrewfileSchema> {\n const snapshot = await captureSnapshot();\n const now = new Date().toISOString();\n\n const schema: BrewfileSchema = {\n version: 1,\n meta: { name, createdAt: now, updatedAt: now },\n formulae: snapshot.formulae.map((f) => ({ name: f.name })),\n casks: snapshot.casks.map((c) => ({ name: c.name })),\n taps: [...snapshot.taps],\n strictMode: false,\n };\n\n return schema;\n}\n\nexport async function computeDrift(schema: BrewfileSchema): Promise<DriftReport> {\n const snapshot = await captureSnapshot();\n const diff = diffDesiredActual(schema, snapshot);\n\n // missingPackages: in desired but not in actual (added in diff means \"missing from actual\")\n const missingPackages = diff.added\n .filter((e) => e.type !== 'tap')\n .map((e) => e.name);\n\n // extraPackages: in actual but not in desired (removed in diff means \"extra in actual\")\n const extraPackages = diff.removed\n .filter((e) => e.type !== 'tap')\n .map((e) => e.name);\n\n // wrongVersions: upgraded + downgraded entries\n const wrongVersions = [\n ...diff.upgraded.map((e) => ({ name: e.name, desired: e.to, actual: e.from })),\n ...diff.downgraded.map((e) => ({ name: e.name, desired: e.to, actual: e.from })),\n ];\n\n const penalty =\n missingPackages.length * 10 +\n extraPackages.length * 2 +\n wrongVersions.length * 5;\n\n const score = Math.max(0, Math.min(100, 100 - penalty));\n\n return { diff, score, missingPackages, extraPackages, wrongVersions };\n}\n\nexport async function* reconcile(\n schema: BrewfileSchema,\n isPro: boolean,\n): AsyncGenerator<string> {\n if (!isPro) {\n yield 'Pro license required for reconcile.';\n return;\n }\n\n const report = await computeDrift(schema);\n\n if (\n report.missingPackages.length === 0 &&\n report.wrongVersions.length === 0 &&\n report.extraPackages.length === 0\n ) {\n yield 'Already in sync — nothing to do.';\n return;\n }\n\n // Install missing packages\n for (const name of report.missingPackages) {\n // SEG-002: validar antes del spawn — un Brewfile YAML artesanal puede\n // contener nombres con flags si no se rechaza aqui.\n try {\n validatePackageName(name);\n } catch (err) {\n yield `✗ Rejected ${name}: ${err instanceof Error ? err.message : String(err)}`;\n continue;\n }\n yield `→ Installing ${name}...`;\n try {\n for await (const line of streamBrew(['install', name])) {\n yield line;\n }\n } catch (err) {\n yield `✗ Failed to install ${name}: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n\n // Fix wrong versions\n for (const { name, desired } of report.wrongVersions) {\n const target = `${name}@${desired}`;\n try {\n validatePackageName(target);\n } catch (err) {\n yield `✗ Rejected ${target}: ${err instanceof Error ? err.message : String(err)}`;\n continue;\n }\n yield `→ Installing ${target}...`;\n try {\n for await (const line of streamBrew(['install', target])) {\n yield line;\n }\n } catch (err) {\n yield `✗ Failed to install ${target}: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n\n // Extra packages (strict mode) — warn only, never auto-uninstall\n for (const name of report.extraPackages) {\n yield `⚠ Extra package not in Brewfile: ${name} (remove manually if desired)`;\n }\n\n // Save post-reconcile snapshot\n try {\n const postSnapshot = await captureSnapshot();\n await saveSnapshot(postSnapshot, 'post-reconcile');\n } catch (err) {\n logger.warn('Failed to save post-reconcile snapshot', { error: String(err) });\n }\n\n logger.info('Brewfile reconcile complete', {\n missing: report.missingPackages.length,\n extra: report.extraPackages.length,\n wrong: report.wrongVersions.length,\n });\n\n yield '✓ Reconciliation complete.';\n}\n\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && 'code' in err;\n}\n","import type { BrewSnapshot } from '../state-snapshot/snapshot.js';\n\nexport interface BrewDiff {\n added: Array<{ name: string; version: string; type: 'formula' | 'cask' | 'tap' }>;\n removed: Array<{ name: string; version: string; type: 'formula' | 'cask' | 'tap' }>;\n upgraded: Array<{ name: string; from: string; to: string; type: 'formula' | 'cask' }>;\n downgraded: Array<{ name: string; from: string; to: string; type: 'formula' | 'cask' }>;\n}\n\n// Temporary — replaced in Phase 2 when brewfile module is implemented\ninterface BrewfileSchema {\n formulae: Array<{ name: string; version?: string }>;\n casks: Array<{ name: string; version?: string }>;\n taps: string[];\n strictMode?: boolean;\n}\n\n/** Compare two Homebrew version strings segment by segment.\n * Returns positive if a > b, negative if a < b, 0 if equal.\n *\n * Handles Homebrew-specific formats: `1.2.3_1` (revision suffix),\n * date-based (`2024.05.20`), and alpha/rc segments compared lexically\n * when they cannot be parsed as integers.\n */\nfunction compareVersions(a: string, b: string): number {\n // Split on `.` to get segments; within each segment handle `_N` revision.\n const splitSegment = (seg: string): [number, number] => {\n const underIdx = seg.indexOf('_');\n if (underIdx !== -1) {\n const main = parseInt(seg.slice(0, underIdx), 10);\n const rev = parseInt(seg.slice(underIdx + 1), 10);\n return [isNaN(main) ? -1 : main, isNaN(rev) ? 0 : rev];\n }\n const n = parseInt(seg, 10);\n return [isNaN(n) ? -1 : n, 0];\n };\n\n const aParts = a.split('.');\n const bParts = b.split('.');\n const len = Math.max(aParts.length, bParts.length);\n\n for (let i = 0; i < len; i++) {\n const aSeg = aParts[i] ?? '0';\n const bSeg = bParts[i] ?? '0';\n\n const [aMain, aRev] = splitSegment(aSeg);\n const [bMain, bRev] = splitSegment(bSeg);\n\n // Fall back to lexical comparison when segments are non-numeric on both sides\n if (aMain === -1 && bMain === -1) {\n const cmp = aSeg.localeCompare(bSeg);\n if (cmp !== 0) return cmp;\n continue;\n }\n // Treat non-numeric as lower than any numeric\n const aVal = aMain === -1 ? -1 : aMain;\n const bVal = bMain === -1 ? -1 : bMain;\n\n if (aVal !== bVal) return aVal - bVal;\n if (aRev !== bRev) return aRev - bRev;\n }\n\n return 0;\n}\n\nfunction diffPackages<T extends { name: string; version: string }>(\n base: T[],\n current: T[],\n type: 'formula' | 'cask',\n result: BrewDiff,\n): void {\n const baseMap = new Map(base.map((p) => [p.name, p.version]));\n const currentMap = new Map(current.map((p) => [p.name, p.version]));\n\n for (const [name, version] of currentMap) {\n if (!baseMap.has(name)) {\n result.added.push({ name, version, type });\n } else {\n const baseVersion = baseMap.get(name)!;\n if (version !== baseVersion) {\n const cmp = compareVersions(version, baseVersion);\n if (cmp > 0) {\n result.upgraded.push({ name, from: baseVersion, to: version, type });\n } else {\n result.downgraded.push({ name, from: baseVersion, to: version, type });\n }\n }\n }\n }\n\n for (const [name, version] of baseMap) {\n if (!currentMap.has(name)) {\n result.removed.push({ name, version, type });\n }\n }\n}\n\nexport function diffSnapshots(base: BrewSnapshot, current: BrewSnapshot): BrewDiff {\n const result: BrewDiff = { added: [], removed: [], upgraded: [], downgraded: [] };\n\n diffPackages(base.formulae, current.formulae, 'formula', result);\n diffPackages(base.casks, current.casks, 'cask', result);\n\n const baseSet = new Set(base.taps);\n const currentSet = new Set(current.taps);\n\n for (const tap of currentSet) {\n if (!baseSet.has(tap)) result.added.push({ name: tap, version: '', type: 'tap' });\n }\n for (const tap of baseSet) {\n if (!currentSet.has(tap)) result.removed.push({ name: tap, version: '', type: 'tap' });\n }\n\n return result;\n}\n\n/** Compare a desired Brewfile schema against the actual installed snapshot.\n *\n * - Packages in desired but not in actual → added\n * - Packages in actual but not in desired → removed (only when strictMode=true)\n * - Packages in both, desired.version defined and differs from actual → upgraded/downgraded\n * - Taps follow the same logic (no version concept)\n */\nexport function diffDesiredActual(desired: BrewfileSchema, actual: BrewSnapshot): BrewDiff {\n const result: BrewDiff = { added: [], removed: [], upgraded: [], downgraded: [] };\n const strict = desired.strictMode === true;\n\n function processPackages(\n desiredPkgs: Array<{ name: string; version?: string }>,\n actualPkgs: Array<{ name: string; version: string }>,\n type: 'formula' | 'cask',\n ): void {\n const actualMap = new Map(actualPkgs.map((p) => [p.name, p.version]));\n const desiredNames = new Set(desiredPkgs.map((p) => p.name));\n\n for (const pkg of desiredPkgs) {\n const actualVersion = actualMap.get(pkg.name);\n if (actualVersion === undefined) {\n // Package missing from actual — mark as added (needs to be installed)\n result.added.push({ name: pkg.name, version: pkg.version ?? '', type });\n } else if (pkg.version !== undefined && pkg.version !== actualVersion) {\n const cmp = compareVersions(pkg.version, actualVersion);\n if (cmp > 0) {\n result.upgraded.push({ name: pkg.name, from: actualVersion, to: pkg.version, type });\n } else {\n result.downgraded.push({ name: pkg.name, from: actualVersion, to: pkg.version, type });\n }\n }\n }\n\n if (strict) {\n for (const pkg of actualPkgs) {\n if (!desiredNames.has(pkg.name)) {\n // Extra package in actual not in desired — mark as removed (violation)\n result.removed.push({ name: pkg.name, version: pkg.version, type });\n }\n }\n }\n }\n\n processPackages(desired.formulae, actual.formulae, 'formula');\n processPackages(desired.casks, actual.casks, 'cask');\n\n // Taps\n const actualTapSet = new Set(actual.taps);\n const desiredTapSet = new Set(desired.taps);\n\n for (const tap of desiredTapSet) {\n if (!actualTapSet.has(tap)) {\n result.added.push({ name: tap, version: '', type: 'tap' });\n }\n }\n\n if (strict) {\n for (const tap of actualTapSet) {\n if (!desiredTapSet.has(tap)) {\n result.removed.push({ name: tap, version: '', type: 'tap' });\n }\n }\n }\n\n return result;\n}\n","import type { BrewfileSchema } from './types.js';\n\n/**\n * Minimal YAML serializer/deserializer for BrewfileSchema.\n * No external dependencies — supports only the exact format we emit.\n *\n * Quoting rules: single-quote strings that contain :, #, ', \";\n * start with -, [, {, ?, !, @, &, *, >, |, %, digits, or have\n * leading/trailing whitespace, or are empty.\n * Inside single-quoted YAML, ' is escaped as ''.\n */\n\nconst MUST_QUOTE_RE = /[:'\"#[\\]{}?!@&*>|%]/;\nconst STARTS_SPECIAL_RE = /^[-\\s]|^\\d/;\n\nfunction needsQuoting(s: string): boolean {\n if (s === '') return true;\n if (STARTS_SPECIAL_RE.test(s)) return true;\n if (MUST_QUOTE_RE.test(s)) return true;\n if (s !== s.trimStart() || s !== s.trimEnd()) return true;\n return false;\n}\n\nfunction quote(s: string): string {\n if (!needsQuoting(s)) return s;\n return `'${s.replace(/'/g, \"''\")}'`;\n}\n\nfunction unquote(s: string): string {\n const trimmed = s.trim();\n if (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\") && trimmed.length >= 2) {\n return trimmed.slice(1, -1).replace(/''/g, \"'\");\n }\n return trimmed;\n}\n\n// ── Serializer ──────────────────────────────────────────────────────────────\n\nexport function serializeBrewfile(schema: BrewfileSchema): string {\n const lines: string[] = [];\n\n lines.push(`version: ${schema.version}`);\n lines.push('meta:');\n lines.push(` name: ${quote(schema.meta.name)}`);\n if (schema.meta.description !== undefined) {\n lines.push(` description: ${quote(schema.meta.description)}`);\n }\n lines.push(` createdAt: ${quote(schema.meta.createdAt)}`);\n lines.push(` updatedAt: ${quote(schema.meta.updatedAt)}`);\n\n lines.push('formulae:');\n if (schema.formulae.length === 0) {\n lines.push(' []');\n } else {\n for (const f of schema.formulae) {\n lines.push(` - name: ${quote(f.name)}`);\n if (f.version !== undefined) {\n lines.push(` version: ${quote(f.version)}`);\n }\n if (f.options !== undefined && f.options.length > 0) {\n lines.push(' options:');\n for (const opt of f.options) {\n lines.push(` - ${quote(opt)}`);\n }\n }\n }\n }\n\n lines.push('casks:');\n if (schema.casks.length === 0) {\n lines.push(' []');\n } else {\n for (const c of schema.casks) {\n lines.push(` - name: ${quote(c.name)}`);\n if (c.version !== undefined) {\n lines.push(` version: ${quote(c.version)}`);\n }\n }\n }\n\n lines.push('taps:');\n if (schema.taps.length === 0) {\n lines.push(' []');\n } else {\n for (const tap of schema.taps) {\n lines.push(` - ${quote(tap)}`);\n }\n }\n\n if (schema.strictMode !== undefined) {\n lines.push(`strictMode: ${schema.strictMode}`);\n }\n\n return lines.join('\\n') + '\\n';\n}\n\n// ── Parser ───────────────────────────────────────────────────────────────────\n\ntype ParseContext =\n | 'root'\n | 'meta'\n | 'formulae'\n | 'formulae_item'\n | 'formulae_options'\n | 'casks'\n | 'casks_item'\n | 'taps';\n\nexport function parseBrewfile(yaml: string): BrewfileSchema {\n const rawLines = yaml.split('\\n');\n\n // Working state\n let version: number | undefined;\n const meta: Partial<{ name: string; description: string; createdAt: string; updatedAt: string }> = {};\n const formulae: BrewfileSchema['formulae'] = [];\n const casks: BrewfileSchema['casks'] = [];\n const taps: string[] = [];\n let strictMode: boolean | undefined;\n\n let context: ParseContext = 'root';\n let currentFormula: (typeof formulae)[number] | null = null;\n let currentCask: (typeof casks)[number] | null = null;\n\n for (const rawLine of rawLines) {\n // Skip blank lines and comments\n const line = rawLine;\n const trimmed = line.trim();\n if (trimmed === '' || trimmed.startsWith('#')) continue;\n\n // Detect indentation level\n const indent = line.length - line.trimStart().length;\n\n // Empty inline arrays (formulae: [], casks: [], taps: [])\n if (trimmed.endsWith(': []')) {\n const key = trimmed.slice(0, -4);\n if (key === 'formulae') { context = 'formulae'; continue; }\n if (key === 'casks') { context = 'casks'; continue; }\n if (key === 'taps') { context = 'taps'; continue; }\n }\n\n // Root-level keys (indent === 0, contains ':')\n if (indent === 0) {\n if (trimmed.startsWith('version:')) {\n const val = trimmed.slice('version:'.length).trim();\n version = parseInt(val, 10);\n context = 'root';\n continue;\n }\n if (trimmed === 'meta:') { context = 'meta'; continue; }\n if (trimmed === 'formulae:') { context = 'formulae'; continue; }\n if (trimmed === 'casks:') { context = 'casks'; continue; }\n if (trimmed === 'taps:') { context = 'taps'; continue; }\n if (trimmed.startsWith('strictMode:')) {\n const val = trimmed.slice('strictMode:'.length).trim();\n strictMode = val === 'true';\n context = 'root';\n continue;\n }\n // Unknown root key — skip\n context = 'root';\n continue;\n }\n\n // ── meta block (indent 2) ──\n if (context === 'meta' && indent === 2) {\n const colonIdx = trimmed.indexOf(':');\n if (colonIdx === -1) continue;\n const key = trimmed.slice(0, colonIdx).trim();\n const val = unquote(trimmed.slice(colonIdx + 1));\n if (key === 'name') meta.name = val;\n else if (key === 'description') meta.description = val;\n else if (key === 'createdAt') meta.createdAt = val;\n else if (key === 'updatedAt') meta.updatedAt = val;\n continue;\n }\n\n // ── formulae block ──\n if (context === 'formulae' || context === 'formulae_item' || context === 'formulae_options') {\n // New formula item: \" - name: value\" (indent 2)\n if (indent === 2 && trimmed.startsWith('- name:')) {\n const val = unquote(trimmed.slice('- name:'.length));\n currentFormula = { name: val };\n formulae.push(currentFormula);\n context = 'formulae_item';\n continue;\n }\n // Properties of current formula (indent 4)\n if (indent === 4 && context === 'formulae_item') {\n if (trimmed.startsWith('version:')) {\n if (currentFormula) currentFormula.version = unquote(trimmed.slice('version:'.length));\n } else if (trimmed === 'options:') {\n if (currentFormula) currentFormula.options = [];\n context = 'formulae_options';\n }\n continue;\n }\n // Options items (indent 6): \" - value\"\n if (indent === 6 && context === 'formulae_options') {\n if (trimmed.startsWith('- ')) {\n const val = unquote(trimmed.slice(2));\n if (currentFormula?.options) currentFormula.options.push(val);\n }\n continue;\n }\n // If we see something at indent 4 after options, back to formulae_item\n if (indent === 4 && context === 'formulae_options') {\n context = 'formulae_item';\n if (trimmed.startsWith('version:')) {\n if (currentFormula) currentFormula.version = unquote(trimmed.slice('version:'.length));\n }\n continue;\n }\n }\n\n // ── casks block ──\n if (context === 'casks' || context === 'casks_item') {\n if (indent === 2 && trimmed.startsWith('- name:')) {\n const val = unquote(trimmed.slice('- name:'.length));\n currentCask = { name: val };\n casks.push(currentCask);\n context = 'casks_item';\n continue;\n }\n if (indent === 4 && context === 'casks_item') {\n if (trimmed.startsWith('version:')) {\n if (currentCask) currentCask.version = unquote(trimmed.slice('version:'.length));\n }\n continue;\n }\n }\n\n // ── taps block (indent 2): \" - value\" ──\n if (context === 'taps' && indent === 2 && trimmed.startsWith('- ')) {\n taps.push(unquote(trimmed.slice(2)));\n continue;\n }\n }\n\n // Validate\n if (version !== 1) {\n throw new Error(`Invalid Brewfile: expected version 1, got ${String(version)}`);\n }\n if (!meta.name) {\n throw new Error('Invalid Brewfile: missing meta.name');\n }\n if (!meta.createdAt || !meta.updatedAt) {\n throw new Error('Invalid Brewfile: missing meta.createdAt or meta.updatedAt');\n }\n\n const result: BrewfileSchema = {\n version: 1,\n meta: {\n name: meta.name,\n createdAt: meta.createdAt,\n updatedAt: meta.updatedAt,\n },\n formulae,\n casks,\n taps,\n };\n\n if (meta.description !== undefined) result.meta.description = meta.description;\n if (strictMode !== undefined) result.strictMode = strictMode;\n\n return result;\n}\n","import { spawn } from 'node:child_process';\nimport { execBrew, streamBrew, BREW_BIN } from './brew-cli.js';\nimport { parseInstalledJson, parseOutdatedJson, parseServicesJson, parseFormulaInfoJson } from './parsers/json-parser.js';\nimport { parseSearchResults, parseDoctorOutput, parseBrewConfig, parseLeavesOutput } from './parsers/text-parser.js';\nimport type { Formula, Cask, OutdatedPackage, BrewService, BrewConfig, PackageListItem } from './types.js';\nimport { analyzeUpgradeImpact } from './impact/impact-analyzer.js';\nimport type { UpgradeImpact } from './impact/types.js';\n\n// EP-011: Package name validation. Exportada para que cualquier modulo que\n// llame a `streamBrew` con un nombre dinamico (compliance-remediator,\n// brewfile-manager, rollback-engine) pueda blindar el spawn frente a flag\n// injection. PKG_PATTERN sigue siendo el unico patron canonico — cualquier\n// regex divergente en modulos clientes (ARQ-004) debe importarse desde aqui.\nexport const PKG_PATTERN = /^[\\w@./+-]+$/;\n\nexport function validatePackageName(name: string): void {\n if (!PKG_PATTERN.test(name)) throw new Error('Invalid package name: ' + name);\n}\n\nexport async function brewUpdate(): Promise<void> {\n // Run brew update WITHOUT HOMEBREW_NO_AUTO_UPDATE so it actually fetches.\n // BK-016: enforce a 120s ceiling — without one, a stalled brew tap fetch\n // could hang fetchAll() indefinitely.\n return new Promise((resolve, reject) => {\n const proc = spawn(BREW_BIN, ['update'], { stdio: 'ignore' });\n let settled = false;\n const timeout = setTimeout(() => {\n if (settled) return;\n settled = true;\n proc.kill('SIGTERM');\n reject(new Error('brew update timed out after 120s'));\n }, 120_000);\n proc.on('close', (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n if (code === 0) resolve();\n else reject(new Error(`brew update exited with code ${code}`));\n });\n proc.on('error', (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n reject(err);\n });\n });\n}\n\nexport async function getInstalled(): Promise<{ formulae: Formula[]; casks: Cask[] }> {\n const raw = await execBrew(['info', '--json=v2', '--installed']);\n return parseInstalledJson(raw);\n}\n\nexport async function getOutdated(): Promise<{ formulae: OutdatedPackage[]; casks: OutdatedPackage[] }> {\n // Match `brew outdated` exactly: skip `--greedy`. Auto-updating casks\n // (Firefox, Docker, Warp, …) carry stale Homebrew metadata and would\n // otherwise show as outdated even when the app already updated itself.\n const raw = await execBrew(['outdated', '--json=v2']);\n return parseOutdatedJson(raw);\n}\n\nexport async function getServices(): Promise<BrewService[]> {\n const raw = await execBrew(['services', 'list', '--json']);\n return parseServicesJson(raw);\n}\n\nexport async function getFormulaInfo(name: string): Promise<Formula | null> {\n validatePackageName(name);\n const raw = await execBrew(['info', '--json=v2', name]);\n return parseFormulaInfoJson(raw);\n}\n\n// SCR-008: Cask-specific info endpoint\nexport async function getCaskInfo(name: string): Promise<Cask | null> {\n validatePackageName(name);\n try {\n const raw = await execBrew(['info', '--json=v2', '--cask', name]);\n const data = JSON.parse(raw) as { casks?: Cask[] };\n return data.casks?.[0] ?? null;\n } catch {\n return null;\n }\n}\n\n// UI-013: cask → formula-shape adaptor lives next to the canonical Cask type\n// instead of inside a view, so any future formula field added to the type is\n// reflected here once and not in N callers.\nexport function formulaeFromCask(cask: Cask): Formula {\n return {\n name: cask.token,\n full_name: cask.full_token,\n tap: '',\n desc: cask.desc,\n license: '',\n homepage: cask.homepage,\n versions: { stable: cask.version, head: null, bottle: false },\n dependencies: [],\n build_dependencies: [],\n installed: cask.installed\n ? [{\n version: cask.installed,\n used_options: [],\n built_as_bottle: false,\n poured_from_bottle: false,\n time: cask.installed_time ?? 0,\n runtime_dependencies: [],\n installed_as_dependency: false,\n installed_on_request: true,\n }]\n : [],\n linked_keg: null,\n pinned: false,\n outdated: cask.outdated,\n deprecated: false,\n keg_only: false,\n caveats: null,\n };\n}\n\nexport async function search(term: string): Promise<{ formulae: string[]; casks: string[] }> {\n // Strip leading dashes to prevent flag injection into `brew search`\n // (e.g. \"--desc\" would be parsed by brew as an option, not a search term).\n const safeTerm = term.replace(/^-+/, '');\n if (!safeTerm) return { formulae: [], casks: [] };\n const raw = await execBrew(['search', safeTerm]);\n return parseSearchResults(raw);\n}\n\nexport async function getDoctor(): Promise<{ warnings: string[]; isClean: boolean }> {\n try {\n const raw = await execBrew(['doctor']);\n return parseDoctorOutput(raw);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return parseDoctorOutput(msg);\n }\n}\n\nexport async function getConfig(): Promise<BrewConfig> {\n const raw = await execBrew(['config']);\n return parseBrewConfig(raw);\n}\n\nexport async function getLeaves(): Promise<string[]> {\n const raw = await execBrew(['leaves']);\n return parseLeavesOutput(raw);\n}\n\nexport function installPackage(name: string): AsyncGenerator<string> {\n validatePackageName(name);\n return streamBrew(['install', name]);\n}\n\nexport function upgradePackage(name: string): AsyncGenerator<string> {\n validatePackageName(name);\n return streamBrew(['upgrade', name]);\n}\n\nexport function upgradeAll(): AsyncGenerator<string> {\n return streamBrew(['upgrade']);\n}\n\nexport async function uninstallPackage(name: string): Promise<string> {\n validatePackageName(name);\n return execBrew(['uninstall', name]);\n}\n\nexport async function serviceAction(name: string, action: 'start' | 'stop' | 'restart'): Promise<string> {\n validatePackageName(name);\n return execBrew(['services', action, name]);\n}\n\n// ARQ-008: Pin/unpin operations moved from outdated view\nexport async function pinPackage(name: string): Promise<string> {\n validatePackageName(name);\n return execBrew(['pin', name]);\n}\n\nexport async function unpinPackage(name: string): Promise<string> {\n validatePackageName(name);\n return execBrew(['unpin', name]);\n}\n\nexport function formulaeToListItems(formulae: Formula[]): PackageListItem[] {\n return formulae.map((f) => {\n const installed = f.installed[0];\n return {\n name: f.name,\n version: installed?.version ?? f.versions.stable,\n desc: f.desc,\n type: 'formula',\n outdated: f.outdated,\n pinned: f.pinned,\n kegOnly: f.keg_only,\n installedAsDependency: installed?.installed_as_dependency ?? false,\n installedTime: installed?.time ?? null,\n };\n });\n}\n\n// PERF-007: cache impact analyses keyed by name+version pair. Cursor moves\n// in the OutdatedView debounce, but a stable list still re-runs deps/uses\n// for the same package every time it gets focus. The version pair guarantees\n// a fresh analysis when a refetch updates the outdated info.\n// ARQ-002: TTL temporal para invalidar entradas si el usuario hace cambios\n// fuera de la app (brew pin, brew upgrade desde otra terminal). Sin TTL un\n// valor cacheado al inicio de la sesion puede quedar stale toda la sesion.\ninterface CachedImpact {\n result: UpgradeImpact;\n cachedAt: number;\n}\nconst impactCache = new Map<string, CachedImpact>();\nconst IMPACT_CACHE_LIMIT = 64;\nconst IMPACT_CACHE_TTL_MS = 5 * 60 * 1000; // 5 min\n\nfunction impactKey(name: string, from: string, to: string, type: 'formula' | 'cask'): string {\n return `${type}::${name}::${from}::${to}`;\n}\n\nexport async function getUpgradeImpact(\n packageName: string,\n fromVersion: string,\n toVersion: string,\n packageType: 'formula' | 'cask',\n): Promise<UpgradeImpact> {\n validatePackageName(packageName);\n const key = impactKey(packageName, fromVersion, toVersion, packageType);\n const cached = impactCache.get(key);\n if (cached && Date.now() - cached.cachedAt < IMPACT_CACHE_TTL_MS) {\n return cached.result;\n }\n if (cached) {\n // Entrada stale — eliminar para preservar el orden de insercion LRU.\n impactCache.delete(key);\n }\n\n const result = await analyzeUpgradeImpact(packageName, fromVersion, toVersion, packageType);\n\n if (impactCache.size >= IMPACT_CACHE_LIMIT) {\n const firstKey = impactCache.keys().next().value;\n if (firstKey !== undefined) impactCache.delete(firstKey);\n }\n impactCache.set(key, { result, cachedAt: Date.now() });\n return result;\n}\n\n// Test seam: drop cache between scenarios.\nexport function _resetImpactCacheForTests(): void {\n impactCache.clear();\n}\n\nexport function casksToListItems(casks: Cask[]): PackageListItem[] {\n return casks.map((c) => ({\n name: c.token,\n version: c.installed ?? c.version,\n desc: c.desc,\n type: 'cask',\n outdated: c.outdated,\n pinned: false,\n kegOnly: false,\n installedAsDependency: false,\n installedTime: c.installed_time ?? null,\n }));\n}\n","import type { BrewInfoResponse, BrewOutdatedResponse, BrewService, Formula, Cask, OutdatedPackage } from '../types.js';\n\nfunction safeParse<T>(raw: string, context: string): T {\n try {\n const result = JSON.parse(raw);\n if (result === null || result === undefined) {\n throw new Error(`${context} returned null or empty response`);\n }\n return result as T;\n } catch (err) {\n throw new Error(`Failed to parse ${context} JSON: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n }\n}\n\nexport function parseInstalledJson(raw: string): { formulae: Formula[]; casks: Cask[] } {\n const data = safeParse<BrewInfoResponse>(raw, 'brew info --installed');\n return {\n formulae: Array.isArray(data.formulae) ? data.formulae : [],\n casks: Array.isArray(data.casks) ? data.casks : [],\n };\n}\n\nexport function parseOutdatedJson(raw: string): { formulae: OutdatedPackage[]; casks: OutdatedPackage[] } {\n const data = safeParse<BrewOutdatedResponse>(raw, 'brew outdated');\n return {\n formulae: Array.isArray(data.formulae) ? data.formulae : [],\n casks: Array.isArray(data.casks) ? data.casks : [],\n };\n}\n\nexport function parseServicesJson(raw: string): BrewService[] {\n const data = safeParse<BrewService[]>(raw, 'brew services list');\n if (!Array.isArray(data)) return [];\n return data.map((s) => ({\n name: s.name,\n status: s.status ?? 'none',\n user: s.user ?? null,\n file: s.file ?? null,\n exit_code: s.exit_code ?? null,\n }));\n}\n\nexport function parseFormulaInfoJson(raw: string): Formula | null {\n const data = safeParse<BrewInfoResponse>(raw, 'brew info');\n return data.formulae?.[0] ?? null;\n}\n","import type { BrewConfig } from '../types.js';\n\nexport function parseSearchResults(raw: string): { formulae: string[]; casks: string[] } {\n const lines = raw.split('\\n').map((l) => l.trim()).filter(Boolean);\n const formulae: string[] = [];\n const casks: string[] = [];\n let section: 'formulae' | 'casks' = 'formulae';\n\n for (const line of lines) {\n if (line.startsWith('==> Formulae')) {\n section = 'formulae';\n continue;\n }\n if (line.startsWith('==> Casks')) {\n section = 'casks';\n continue;\n }\n if (line.startsWith('==>')) continue;\n\n if (section === 'formulae') formulae.push(line);\n else casks.push(line);\n }\n\n return { formulae, casks };\n}\n\nexport function parseDoctorOutput(raw: string): { warnings: string[]; isClean: boolean } {\n const cleaned = raw.trim();\n if (cleaned.includes('Your system is ready to brew')) {\n return { warnings: [], isClean: true };\n }\n\n const warnings: string[] = [];\n let current = '';\n\n for (const line of cleaned.split('\\n')) {\n if (line.startsWith('Warning:')) {\n if (current) warnings.push(current.trim());\n current = line;\n } else if (current) {\n current += '\\n' + line;\n }\n }\n if (current) warnings.push(current.trim());\n\n return { warnings, isClean: false };\n}\n\nexport function parseBrewConfig(raw: string): BrewConfig {\n const lines = raw.split('\\n');\n const get = (key: string): string => {\n const line = lines.find((l) => l.startsWith(key));\n return line?.split(':').slice(1).join(':').trim() ?? '';\n };\n\n return {\n HOMEBREW_VERSION: get('HOMEBREW_VERSION'),\n HOMEBREW_PREFIX: get('HOMEBREW_PREFIX'),\n coreUpdated: get('Core tap last commit') || get('Core tap JSON'),\n };\n}\n\nexport function parseLeavesOutput(raw: string): string[] {\n return raw.split('\\n').map((l) => l.trim()).filter(Boolean);\n}\n","import { execBrew } from '../brew-cli.js';\nimport { logger } from '../../utils/logger.js';\nimport { t } from '../../i18n/index.js';\nimport type { UpgradeImpact, RiskLevel } from './types.js';\n\n// Packages whose upgrade is always considered high risk\nconst HIGH_RISK_PACKAGES = new Set([\n 'openssl', 'openssl@3', 'openssl@1.1',\n 'python', 'python@3', 'python@3.11', 'python@3.12', 'python@3.13',\n 'node', 'node@18', 'node@20', 'ruby', 'ruby@3',\n 'sqlite', 'sqlite3', 'libpq', 'postgresql', 'postgresql@16',\n 'glibc', 'gcc', 'llvm',\n]);\n\nfunction isMajorVersionBump(from: string, to: string): boolean {\n const fromMajor = parseInt(from.split('.')[0] ?? '0', 10);\n const toMajor = parseInt(to.split('.')[0] ?? '0', 10);\n return !isNaN(fromMajor) && !isNaN(toMajor) && toMajor > fromMajor;\n}\n\nfunction calculateRisk(\n name: string,\n reverseDeps: string[],\n fromVersion: string,\n toVersion: string,\n): { risk: RiskLevel; reasons: string[] } {\n const reasons: string[] = [];\n\n // HIGH_RISK packages are sticky — always 'high' regardless of other factors\n if (HIGH_RISK_PACKAGES.has(name)) {\n reasons.push(t('impact_reason_critical_package'));\n return { risk: 'high', reasons };\n }\n\n // >10 reverse deps forces high directly\n if (reverseDeps.length > 10) {\n reasons.push(t('impact_reason_many_deps', { count: reverseDeps.length }));\n return { risk: 'high', reasons };\n }\n\n let factorCount = 0;\n\n if (reverseDeps.length >= 3) {\n factorCount++;\n reasons.push(t('impact_reason_many_deps', { count: reverseDeps.length }));\n }\n\n if (isMajorVersionBump(fromVersion, toVersion)) {\n factorCount++;\n reasons.push(t('impact_reason_major_bump'));\n }\n\n const risk: RiskLevel = factorCount >= 2 ? 'high' : factorCount === 1 ? 'medium' : 'low';\n return { risk, reasons };\n}\n\nexport async function analyzeUpgradeImpact(\n packageName: string,\n fromVersion: string,\n toVersion: string,\n packageType: 'formula' | 'cask',\n): Promise<UpgradeImpact> {\n // Casks are self-contained — no dependency graph to analyze\n if (packageType === 'cask') {\n return {\n packageName,\n fromVersion,\n toVersion,\n packageType,\n directDeps: [],\n reverseDeps: [],\n risk: 'low',\n riskReasons: [],\n };\n }\n\n let directDeps: string[] = [];\n let reverseDeps: string[] = [];\n\n try {\n const depsOutput = await execBrew(['deps', '--1', packageName]);\n directDeps = depsOutput.split('\\n').filter((l) => l.trim() !== '');\n } catch (err) {\n logger.warn(`impact-analyzer: deps failed for ${packageName}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n try {\n const usesOutput = await execBrew(['uses', '--installed', packageName]);\n reverseDeps = usesOutput.split('\\n').filter((l) => l.trim() !== '');\n } catch (err) {\n logger.warn(`impact-analyzer: uses failed for ${packageName}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const { risk, reasons } = calculateRisk(packageName, reverseDeps, fromVersion, toVersion);\n\n return {\n packageName,\n fromVersion,\n toVersion,\n packageType,\n directDeps,\n reverseDeps,\n risk,\n riskReasons: reasons,\n };\n}\n\nexport { isMajorVersionBump };\n"],"mappings":"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","names":[]}
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  checkCompliance,
3
3
  versionAtLeast
4
- } from "./chunk-J6HCX7RG.js";
5
- import "./chunk-BRXZG7ZL.js";
4
+ } from "./chunk-JNEIP2LJ.js";
5
+ import "./chunk-CMIC4N74.js";
6
6
  import "./chunk-IGDHDXUH.js";
7
7
  import "./chunk-KDHEUNRI.js";
8
8
  export {
9
9
  checkCompliance,
10
10
  versionAtLeast
11
11
  };
12
- //# sourceMappingURL=compliance-checker-IXZHIMQG.js.map
12
+ //# sourceMappingURL=compliance-checker-3FDEX4OI.js.map