Dashboard › cli › Distillation
acff857d-2013-478a-b660-4cd5a7a4d4dc["lore_tm_v1_SBY9s5byqOzt9u-r3h-4EJSi_xBun6r_-uNOVOu7F6U","lore_tm_v1_ml7Zlo_fVP8MqdfqiA_IMgaWt6-1pVYk3ax3mXcUFhs","lore_tm_v1_oJBWLVlKSjCsFBvaXgfYr1lut-GG1-LmEF60Y9Kv09o","lore_tm_v1_41V8G3JmloBM4vUPADfpKX6aag7UqnoVPnBD7TpCo4A"]
detectInstallationMethod() in packages/cli/src/lib/upgrade.ts to always check Homebrew first because stored install information may be stale; isHomebrewInstall() is a cheap, authoritative realpath check that overrides stored data, including when a user previously had curl recorded and switched to Homebrew.detectInstallationMethod() priority in packages/cli/src/lib/upgrade.ts: 1. Homebrew via isHomebrewInstall(); 2. stored install info from getInstallInfo(); 3. legacy detection; 4. best-effort persistence through setInstallInfo({ method: legacyMethod, path: process.execPath, version: CLI_VERSION }), with DB persistence failure logged via log.debug() rather than blocking detection.isHomebrewInstall() in packages/cli/src/lib/upgrade.ts resolving process.execPath with realpathSync() before checking for "/Cellar/"; if resolution throws because the binary was deleted or moved, it checks the unresolved path.getCurlInstallPaths() in packages/cli/src/lib/upgrade.ts using this path priority: 1. stored DB path only when stored.method === "curl" and existsSync(dirname(stored.path)); 2. process.execPath when inside a known curl directory; 3. join(determineInstallDir(homedir(), process.env), getBinaryFilename()). The stale-directory guard fixes an ENOENT ... open '.../sentry.lock' failure caused by purged temporary install directories.buildKnownCurlPaths(homeDir, env) appending a trailing sep to each KNOWN_CURL_DIRS path to enforce directory-boundary matching and adding absolute XDG_BIN_HOME as join(xdgBinHome, ".") + sep; getKnownCurlPaths() lazily memoizes the result to avoid circular-import TDZ issues.packages/cli/src/lib/upgrade.ts: check known curl paths first, then package managers in exact order 1. npm, 2. pnpm, 3. bun, 4. yarn, then fall back to detectPackageManagerFromPath(), otherwise return "unknown".detectPackageManagerFromPath() inspecting process.argv[1]: return null unless the path contains NODE_MODULES_DIRNAME; return "pnpm" for a .pnpm segment, "bun" for a .bun segment, and otherwise "npm" for npm or Yarn Classic layouts.runCommand(command, args) using spawn() with stdio: ["ignore", "pipe", "pipe"] and shell: process.platform === "win32" so Windows .cmd package-manager executables work; it captures trimmed stdout, drains and discards stderr, and maps a null close code to exit code 1.isInstalledWith(pm) running Yarn as ["global", "list", "--depth=0"] and other package managers as ["list", "-g", "sentry"]; detection succeeds only when exit code is 0 and stdout includes "sentry@", while command errors return false.fetchLatestFromGitHub() still using ${GITHUB_RELEASES_URL}/latest, getGitHubHeaders(), and stripping VERSION_PREFIX_REGEX = /^v/; fetchLatestNightlyVersion() still calls getAnonymousToken() and fetchNightlyManifest(token) without an explicit selected UpgradeSource.fetchLatestVersion(method, channel = "stable") behavior in packages/cli/src/lib/upgrade.ts: nightly uses fetchLatestNightlyVersion(); stable curl/brew uses fetchLatestFromGitHub(); other stable installation methods use fetchLatestFromNpm() at https://registry.npmjs.org/sentry/latest.nightlyVersionExists(version) checking GHCR tag nightly-${version} via getAnonymousToken() and fetchManifest(); it returns false only for UpgradeError messages containing HTTP 404 or HTTP 403, and rethrows other failures.versionExists(method, version) routing nightly versions to nightlyVersionExists(version); stable curl/brew versions use a HEAD request to ${GITHUB_RELEASES_URL}/tags/${version}, while package-manager versions use a HEAD request to ${NPM_REGISTRY_URL}/${version}.OfflineMode in packages/cli/src/lib/upgrade.ts as false | "explicit" | "network-fallback" and DownloadResult as { tempBinaryPath: string; lockPath: string; patchBytes?: number }.packages/cli/src/lib/binary.ts (139-line diff), packages/cli/src/lib/ghcr.ts (52-line diff), packages/cli/test/lib/binary.test.ts (129-line diff), packages/cli/test/lib/ghcr.test.ts (30-line diff), and packages/cli/test/lib/install-script.test.ts (10-line diff).packages/cli/test/lib/delta-upgrade.test.ts has 1,846 lines and tests exported delta-upgrade computation/orchestration symbols including applyPatchChain, attemptDeltaUpgrade, canAttemptDelta, downloadStablePatch, extractSha256, extractStableChain, fetchRecentReleases, filterAndSortChainTags, getPatchFromVersion, getPatchTargetSha256, getStableTargetSha256, prefetchNightlyPatches, prefetchStablePatches, resolveNightlyChain, resolveNightlyDelta, resolveStableChain, resolveStableDelta, and validateChainStep.packages/cli/test/lib/delta-upgrade.mocked.test.ts has exactly 500 lines and uses vi.mock("../../src/lib/constants.js", ...) to replace test-mode CLI_VERSION: "0.0.0-dev" with "0.13.0" so canAttemptDelta() passes its development-build guard; the mock is isolated in a sibling file to avoid reversing assumptions in delta-upgrade.test.ts.packages/cli/test/lib/delta-upgrade.mocked.test.ts still refers to isolation under bun test --isolate, despite the test implementation importing from vitest.0.14.0 from current version 0.13.0, downloading ${BINARY_NAME}.patch, applying an empty TRDIFF10 patch, and expecting resolveStableDelta("0.14.0", oldBinaryPath, destPath) to reject with "SHA-256 mismatch" after successful release lookup, chain extraction, and patch download.resolveStableDelta is expected to return null when release fetching returns HTTP 500.resolveNightlyDelta("0.0.0-dev.200", ...) to return null in two cases: 1. the nightly manifest has no ${BINARY_NAME}.gz layer; 2. the manifest has a 30,000,000-byte gzip layer but /tags/list contains no patch-chain tags.attemptDeltaUpgrade() tests expecting null for a stable-to-nightly cross-channel upgrade, for stable chain-resolution failure when all fetches return HTTP 500, and when patch application receives invalid bytes [0, 1, 2, 3].packages/cli/test/fixtures/patches/small-old.bin, small.trdiff10, and small-new.bin; expected SHA-256 is 54d0dcd74478bc154b5b24393fdc6129518271baa36f446384d60e84021bb724, patch size is 89 bytes, output size is 54 bytes, expected patchBytes is 89, and expected chainLength is 1.