brew-tui 4.0.3 → 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.
- package/build/{brew-tui-bar-installer-2YIVTG24.js → brew-tui-bar-installer-Q5WNHF4M.js} +2 -2
- package/build/{brewfile-manager-KHDIFP23.js → brewfile-manager-CSD44YVL.js} +2 -2
- package/build/{chunk-3DCKHTET.js → chunk-D3RSUZGP.js} +2 -2
- package/build/{chunk-6VLQW2JL.js → chunk-KHUJQWK3.js} +2 -1
- package/build/{chunk-6VLQW2JL.js.map → chunk-KHUJQWK3.js.map} +1 -1
- package/build/{chunk-H4OP57MF.js → chunk-LZ5EZ2BR.js} +2 -2
- package/build/{doctor-HSTLSGYM.js → doctor-BIQYAYW6.js} +4 -4
- package/build/index.js +11 -11
- package/build/postinstall.js +1 -1
- package/build/{version-check-OVV3RVB7.js → version-check-6BTSOLYP.js} +2 -2
- package/package.json +1 -1
- /package/build/{brew-tui-bar-installer-2YIVTG24.js.map → brew-tui-bar-installer-Q5WNHF4M.js.map} +0 -0
- /package/build/{brewfile-manager-KHDIFP23.js.map → brewfile-manager-CSD44YVL.js.map} +0 -0
- /package/build/{chunk-3DCKHTET.js.map → chunk-D3RSUZGP.js.map} +0 -0
- /package/build/{chunk-H4OP57MF.js.map → chunk-LZ5EZ2BR.js.map} +0 -0
- /package/build/{doctor-HSTLSGYM.js.map → doctor-BIQYAYW6.js.map} +0 -0
- /package/build/{version-check-OVV3RVB7.js.map → version-check-6BTSOLYP.js.map} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
launchBrewTUIBar,
|
|
7
7
|
syncAndLaunchBrewTUIBar,
|
|
8
8
|
uninstallBrewTUIBar
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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-
|
|
65
|
+
//# sourceMappingURL=chunk-LZ5EZ2BR.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
checkBrewTUIBarVersion,
|
|
3
3
|
readBrewTUIBarVersion
|
|
4
|
-
} from "./chunk-
|
|
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-
|
|
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.
|
|
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-
|
|
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-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
6293
|
+
const { syncAndLaunchBrewTUIBar } = await import("./brew-tui-bar-installer-Q5WNHF4M.js");
|
|
6294
6294
|
await syncAndLaunchBrewTUIBar();
|
|
6295
6295
|
}
|
|
6296
6296
|
runCli().catch((err) => {
|
package/build/postinstall.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
compareSemver,
|
|
5
5
|
expectedVersion,
|
|
6
6
|
readBrewTUIBarVersion
|
|
7
|
-
} from "./chunk-
|
|
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-
|
|
15
|
+
//# sourceMappingURL=version-check-6BTSOLYP.js.map
|
package/package.json
CHANGED
/package/build/{brew-tui-bar-installer-2YIVTG24.js.map → brew-tui-bar-installer-Q5WNHF4M.js.map}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|