Dashboard › cli › Distillation
65f4e212-07b1-4ca5-956d-0558ec530d1e["lore_tm_v1_ZH9kHi7PdNsDs7_tsfcV4X3eg8X3XR-ulLkokVvlG8k","lore_tm_v1_a50CUNePMyqgH4gzExzg9cSaA3BzVDVsQjeCG-SxMI4","lore_tm_v1_9hHfwE44v-A3UkfZXaQGYRh4b4qA22Q7AA7peURXYTM","lore_tm_v1_9Pk-zZwRBojxJbPLCkxpBvIqfxRu5gjBDiM7dbGx0B8","lore_tm_v1_BwLXnQd2UNFtZgJcPOyz6h9t8HyhLd_oGrgAmJ801gs","lore_tm_v1_IAwcTP325TvVi6A1qzsOLZWvHUtT0xPWQjdk85_SoHY"]
detectInstallationMethod() in packages/cli/src/lib/upgrade.ts must always check Homebrew first because stored install information may be stale; isHomebrewInstall() is the cheap, authoritative signal and overrides stored DB information.isHomebrewInstall() resolves process.execPath with realpathSync() and checks for "/Cellar/"; if realpath resolution throws because the binary was deleted or moved, it checks the unresolved path instead.packages/cli/src/lib/upgrade.ts is: 1. Homebrew realpath check, 2. stored install info from getInstallInfo(), 3. legacy detection using known curl paths → package-manager subprocesses → node_modules path, 4. best-effort persistence of a detected non-"unknown" method.["npm", "pnpm", "bun", "yarn"]; isInstalledWith(pm) uses ["global", "list", "--depth=0"] for Yarn and ["list", "-g", "sentry"] for the others, requiring exit code 0 and stdout containing "sentry@".runCommand(command, args) in packages/cli/src/lib/upgrade.ts uses spawn() with shell: process.platform === "win32" so Windows .cmd package managers work, captures and trims stdout, drains and discards stderr, and maps a null close code to exit code 1.detectPackageManagerFromPath() inspects process.argv[1]: it returns null unless a path segment equals NODE_MODULES_DIRNAME; returns "pnpm" when a ".pnpm" segment exists; returns "bun" when a ".bun" segment exists; and otherwise returns "npm" for npm or Yarn Classic layouts."unknown" installation method, detectInstallationMethod() best-effort calls setInstallInfo({ method: legacyMethod, path: process.execPath, version: CLI_VERSION }); DB write failure is non-blocking and logs "Failed to persist install info (DB may be read-only)".getCurlInstallPaths() in packages/cli/src/lib/upgrade.ts selects paths in this order: 1. stored curl path only if stored.path exists, stored.method === "curl", and existsSync(dirname(stored.path)); 2. process.execPath when it starts with a known curl directory; 3. join(homedir(), ".sentry", "bin", getBinaryFilename()).SENTRY_INSTALL_DIR, such as /tmp/sentry-test-install, could leave a stale DB row after its directory was purged; trusting that row caused upgrade locking/installing into a dead location and an ENOENT ... open '.../sentry.lock' crash reported in #discuss-cli. Fix in getCurlInstallPaths(): ignore stored curl paths whose parent directory fails existsSync() and fall through to process.execPath or ~/.sentry/bin.getKnownCurlPaths() lazily caches KNOWN_CURL_DIRS.map((dir) => join(homedir(), dir) + sep) in _knownCurlPaths; the trailing separator enforces directory-boundary matching, and lazy initialization avoids TDZ issues from circular imports.startCleanupOldBinary() obtains oldPath from getCurlInstallPaths() and invokes cleanupOldBinary(oldPath) as fire-and-forget, non-blocking startup cleanup.