brew-tui 4.0.2 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ import {
6
6
  launchBrewTUIBar,
7
7
  syncAndLaunchBrewTUIBar,
8
8
  uninstallBrewTUIBar
9
- } from "./chunk-IOHEB7EM.js";
9
+ } from "./chunk-D3RSUZGP.js";
10
10
  import "./chunk-NRRQECXA.js";
11
11
  import "./chunk-A7U3NZYM.js";
12
12
  import "./chunk-KDHEUNRI.js";
@@ -19,4 +19,4 @@ export {
19
19
  syncAndLaunchBrewTUIBar,
20
20
  uninstallBrewTUIBar
21
21
  };
22
- //# sourceMappingURL=brew-tui-bar-installer-DN4YUHYD.js.map
22
+ //# sourceMappingURL=brew-tui-bar-installer-Q5WNHF4M.js.map
@@ -5,7 +5,7 @@ import {
5
5
  loadBrewfile,
6
6
  reconcile,
7
7
  saveBrewfile
8
- } from "./chunk-6VLQW2JL.js";
8
+ } from "./chunk-KHUJQWK3.js";
9
9
  import "./chunk-A7U3NZYM.js";
10
10
  import "./chunk-OXDZ4DCK.js";
11
11
  import "./chunk-KDHEUNRI.js";
@@ -18,4 +18,4 @@ export {
18
18
  reconcile,
19
19
  saveBrewfile
20
20
  };
21
- //# sourceMappingURL=brewfile-manager-KHDIFP23.js.map
21
+ //# sourceMappingURL=brewfile-manager-CSD44YVL.js.map
@@ -186,7 +186,7 @@ async function launchBrewTUIBar() {
186
186
  }
187
187
  async function syncAndLaunchBrewTUIBar() {
188
188
  if (process.platform !== "darwin") return;
189
- const { checkBrewTUIBarVersion } = await import("./version-check-P6VR6UH4.js");
189
+ const { checkBrewTUIBarVersion } = await import("./version-check-6BTSOLYP.js");
190
190
  try {
191
191
  if (!await isBrewTUIBarInstalled()) {
192
192
  console.log(t("cli_brewtuibarInstalling"));
@@ -225,4 +225,4 @@ export {
225
225
  syncAndLaunchBrewTUIBar,
226
226
  uninstallBrewTUIBar
227
227
  };
228
- //# sourceMappingURL=chunk-IOHEB7EM.js.map
228
+ //# sourceMappingURL=chunk-D3RSUZGP.js.map
@@ -463,6 +463,7 @@ function parseLeavesOutput(raw) {
463
463
  var HIGH_RISK_PACKAGES = /* @__PURE__ */ new Set([
464
464
  "openssl",
465
465
  "openssl@3",
466
+ "openssl@4",
466
467
  "openssl@1.1",
467
468
  "python",
468
469
  "python@3",
@@ -870,4 +871,4 @@ export {
870
871
  computeDrift,
871
872
  reconcile
872
873
  };
873
- //# sourceMappingURL=chunk-6VLQW2JL.js.map
874
+ //# sourceMappingURL=chunk-KHUJQWK3.js.map
@@ -1 +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
+ {"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@4', '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":[]}
@@ -6,7 +6,7 @@ var execFileAsync = promisify(execFile);
6
6
  var BREWTUIBAR_INFO_PLIST = "/Applications/Brew-TUI-Bar.app/Contents/Info.plist";
7
7
  var CONTRACT_VERSION = 1;
8
8
  function expectedVersion() {
9
- return "4.0.2";
9
+ return "4.1.1";
10
10
  }
11
11
  async function readBrewTUIBarVersion() {
12
12
  try {
@@ -62,4 +62,4 @@ export {
62
62
  compareSemver,
63
63
  checkBrewTUIBarVersion
64
64
  };
65
- //# sourceMappingURL=chunk-3SEPHWUW.js.map
65
+ //# sourceMappingURL=chunk-LZ5EZ2BR.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  checkBrewTUIBarVersion,
3
3
  readBrewTUIBarVersion
4
- } from "./chunk-3SEPHWUW.js";
4
+ } from "./chunk-LZ5EZ2BR.js";
5
5
  import {
6
6
  useLicenseStore
7
7
  } from "./chunk-ILKWT7WR.js";
@@ -9,7 +9,7 @@ import {
9
9
  bundleIdAt,
10
10
  isBrewTUIBarInstalled,
11
11
  isBrewTUIBarRunning
12
- } from "./chunk-IOHEB7EM.js";
12
+ } from "./chunk-D3RSUZGP.js";
13
13
  import "./chunk-TA3XPHF4.js";
14
14
  import "./chunk-NRRQECXA.js";
15
15
  import "./chunk-A7U3NZYM.js";
@@ -53,7 +53,7 @@ async function findBrewBinary() {
53
53
  }
54
54
  }
55
55
  async function runDoctor() {
56
- const cliVersion = "4.0.2";
56
+ const cliVersion = "4.1.1";
57
57
  console.log(format("Brew-TUI", [
58
58
  { label: "CLI version", value: cliVersion },
59
59
  { label: "Platform", value: `${process.platform} (${arch()})` },
@@ -130,4 +130,4 @@ async function runDoctor() {
130
130
  export {
131
131
  runDoctor
132
132
  };
133
- //# sourceMappingURL=doctor-I5TSHWHO.js.map
133
+ //# sourceMappingURL=doctor-BIQYAYW6.js.map
package/build/index.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  uninstallPackage,
29
29
  unpinPackage,
30
30
  validatePackageName
31
- } from "./chunk-6VLQW2JL.js";
31
+ } from "./chunk-KHUJQWK3.js";
32
32
  import {
33
33
  applyConflictResolutions,
34
34
  decryptPayload,
@@ -4562,7 +4562,7 @@ function AccountView() {
4562
4562
  status === "pro" || status === "team" || status === "expired" ? `v ${t("hint_revalidate")} ` : "",
4563
4563
  revalidating ? t("account_revalidating") : "",
4564
4564
  " ",
4565
- t("app_version", { version: "4.0.2" })
4565
+ t("app_version", { version: "4.1.1" })
4566
4566
  ] }) })
4567
4567
  ] });
4568
4568
  }
@@ -6070,7 +6070,7 @@ async function reportError(err, context = {}) {
6070
6070
  const config = await resolveConfig();
6071
6071
  if (!config.enabled || !config.endpoint) return;
6072
6072
  const machineId = await getMachineId();
6073
- const version = true ? "4.0.2" : "unknown";
6073
+ const version = true ? "4.1.1" : "unknown";
6074
6074
  await postReport(buildReport("error", err, context, machineId, version), config);
6075
6075
  }
6076
6076
  async function installCrashReporter() {
@@ -6079,7 +6079,7 @@ async function installCrashReporter() {
6079
6079
  if (!config.enabled || !config.endpoint) return;
6080
6080
  _installed = true;
6081
6081
  const machineId = await getMachineId();
6082
- const version = true ? "4.0.2" : "unknown";
6082
+ const version = true ? "4.1.1" : "unknown";
6083
6083
  process.on("uncaughtException", (err) => {
6084
6084
  void postReport(buildReport("fatal", err, { kind: "uncaughtException" }, machineId, version), config);
6085
6085
  });
@@ -6094,11 +6094,11 @@ import { jsx as jsx39 } from "react/jsx-runtime";
6094
6094
  var [, , command, arg] = process.argv;
6095
6095
  async function runCli() {
6096
6096
  if (command === "--version" || command === "-v" || command === "version") {
6097
- const cliVersion = "4.0.2";
6097
+ const cliVersion = "4.1.1";
6098
6098
  process.stdout.write(cliVersion + "\n");
6099
6099
  if (process.platform === "darwin") {
6100
6100
  try {
6101
- const { readBrewTUIBarVersion } = await import("./version-check-P6VR6UH4.js");
6101
+ const { readBrewTUIBarVersion } = await import("./version-check-6BTSOLYP.js");
6102
6102
  const appVersion = await readBrewTUIBarVersion();
6103
6103
  if (appVersion && appVersion !== cliVersion) {
6104
6104
  process.stderr.write(t("cli_versionMismatchWarning", { installed: appVersion, expected: cliVersion }) + "\n");
@@ -6213,7 +6213,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
6213
6213
  } catch {
6214
6214
  }
6215
6215
  try {
6216
- const { loadBrewfile: loadBrewfile2, computeDrift: computeDrift2 } = await import("./brewfile-manager-KHDIFP23.js");
6216
+ const { loadBrewfile: loadBrewfile2, computeDrift: computeDrift2 } = await import("./brewfile-manager-CSD44YVL.js");
6217
6217
  const schema = await loadBrewfile2();
6218
6218
  if (schema) {
6219
6219
  const drift = await computeDrift2(schema);
@@ -6243,7 +6243,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
6243
6243
  return;
6244
6244
  }
6245
6245
  if (command === "install-brew-tui-bar") {
6246
- const { installBrewTUIBar } = await import("./brew-tui-bar-installer-DN4YUHYD.js");
6246
+ const { installBrewTUIBar } = await import("./brew-tui-bar-installer-Q5WNHF4M.js");
6247
6247
  try {
6248
6248
  console.log(t("cli_brewtuibarInstalling"));
6249
6249
  await installBrewTUIBar(false, arg === "--force");
@@ -6255,7 +6255,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
6255
6255
  return;
6256
6256
  }
6257
6257
  if (command === "uninstall-brew-tui-bar") {
6258
- const { uninstallBrewTUIBar } = await import("./brew-tui-bar-installer-DN4YUHYD.js");
6258
+ const { uninstallBrewTUIBar } = await import("./brew-tui-bar-installer-Q5WNHF4M.js");
6259
6259
  try {
6260
6260
  await uninstallBrewTUIBar();
6261
6261
  console.log(t("cli_brewtuibarUninstalled"));
@@ -6266,7 +6266,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
6266
6266
  return;
6267
6267
  }
6268
6268
  if (command === "doctor") {
6269
- const { runDoctor } = await import("./doctor-I5TSHWHO.js");
6269
+ const { runDoctor } = await import("./doctor-BIQYAYW6.js");
6270
6270
  await runDoctor();
6271
6271
  return;
6272
6272
  }
@@ -6290,7 +6290,7 @@ Snapshots: ${snapshots.length} (latest: ${latest ? formatDate(latest.capturedAt)
6290
6290
  async function ensureBrewTUIBarRunning() {
6291
6291
  if (process.platform !== "darwin") return;
6292
6292
  await useLicenseStore.getState().initialize();
6293
- const { syncAndLaunchBrewTUIBar } = await import("./brew-tui-bar-installer-DN4YUHYD.js");
6293
+ const { syncAndLaunchBrewTUIBar } = await import("./brew-tui-bar-installer-Q5WNHF4M.js");
6294
6294
  await syncAndLaunchBrewTUIBar();
6295
6295
  }
6296
6296
  runCli().catch((err) => {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  syncAndLaunchBrewTUIBar
4
- } from "./chunk-IOHEB7EM.js";
4
+ } from "./chunk-D3RSUZGP.js";
5
5
  import "./chunk-NRRQECXA.js";
6
6
  import {
7
7
  t
@@ -4,7 +4,7 @@ import {
4
4
  compareSemver,
5
5
  expectedVersion,
6
6
  readBrewTUIBarVersion
7
- } from "./chunk-3SEPHWUW.js";
7
+ } from "./chunk-LZ5EZ2BR.js";
8
8
  export {
9
9
  CONTRACT_VERSION,
10
10
  checkBrewTUIBarVersion,
@@ -12,4 +12,4 @@ export {
12
12
  expectedVersion,
13
13
  readBrewTUIBarVersion
14
14
  };
15
- //# sourceMappingURL=version-check-P6VR6UH4.js.map
15
+ //# sourceMappingURL=version-check-6BTSOLYP.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brew-tui",
3
- "version": "4.0.2",
3
+ "version": "4.1.1",
4
4
  "description": "Brew-TUI — Visual TUI for Homebrew package management",
5
5
  "type": "module",
6
6
  "bin": {