Dashboard › cli › Distillation
b6ed26df-4eba-4534-8cf5-10a6875cb017["lore_tm_v1_NkDiXrfUjWgFWZYbc2hjt_lqHVK4xbcrixHvgdXW1eM","lore_tm_v1_lqenEN3uQN2aUFvY_KrM9haUT-aNjZY89AaBdVCbm8c","lore_tm_v1_q9cbB6mOVKcYdLPAFgp_pGWKH5YnqGuMpgu3i74RU1U","lore_tm_v1_MKp8FZbE1auST2Zw_jaxceatbQ7TleHcB5eIcOoFdFg","lore_tm_v1_8_MSgHWAFvoW9g9BeLZDjcGK6hSTMVmMVm9IiAmXzoY"]
packages/cli/src/lib/delta-upgrade.ts is a 648-line binpatch-backed delta-upgrade implementation. It imports applyPatchChainInMemory, stable/nightly source strategies, OCI support, patch-chain validation, caching, telemetry types, MAX_NIGHTLY_CHAIN_DEPTH, PATCH_TAG_PREFIX, and SIZE_THRESHOLD_RATIO from binpatch.packages/cli/src/lib/delta-upgrade.ts:50-70 preserves the existing public API by re-exporting ExtractStableChainOpts, GitHubAsset, GitHubRelease, PatchChain, StableChainInfo, extractSha256, getPatchFromVersion, getPatchTargetSha256, getStableTargetSha256, and PATCH_TAG_PREFIX. DeltaResult is { sha256: string; patchBytes: number; chainLength: number }.getPrimaryUpgradeSource() in packages/cli/src/lib/delta-upgrade.ts:74-79 returns PRIMARY_UPGRADE_SOURCE or throws Error("No primary upgrade source is configured"). The HTTP InstrumentHook wraps operations with withTracing(name, "http.client", fn).patch-chain:${fromVersion}-${toVersion}. instrumentCache() wraps loads in a cache.get span with cache.key, cache.hit, and, on hits, cache.item_size; saves use a cache.put span keyed by the first stepβs fromVersion and last stepβs toVersion, with cache.item_size equal to summed patch sizes. Empty-step saves delegate directly. getPatchCache() stores data under join(getConfigDir(), "patch-cache").stableSource(source) configures githubReleaseSource() with getGitHubReleasesUrl(source), getPlatformBinaryName(), User-Agent sentry-cli/${CLI_VERSION}, customFetch, and tracing instrumentation. nightlySource(source) configures ghcrSource() for registry https://ghcr.io, source.ghcrRepo, the platform binary name, target tags nightly-${version}, compareVersions, the same User-Agent/fetch/instrumentation, and the selected upgrade source.canAttemptDelta(targetVersion) rejects delta upgrades when CLI_VERSION === "0.0.0-dev", when current and target versions differ between stable/nightly channels, or when the target is a downgrade; otherwise it returns true.fetchRecentReleases(signal?, source?) requests ${getGitHubReleasesUrl(source)}?per_page=12 with GitHub v3 Accept header and User-Agent sentry-cli/${CLI_VERSION}. Non-OK responses, transport failures, and non-array JSON all produce []; malformed JSON shape and fetch failures are debug-logged.downloadStablePatch(url, signal?) downloads with User-Agent sentry-cli/${CLI_VERSION} and returns the body as Uint8Array only for an OK response. HTTP or transport failure returns null, with transport failures debug-logged as "Failed to download stable patch".extractStableChain(opts) adapts binpatchExtractStableChain(opts), converting any result containing "failure" to null. filterAndSortChainTags(allTags, currentVersion, targetVersion) delegates to binpatchFilterAndSortChainTags() using local compareVersions.ChainStepResult preserves 3 detailed failure classes: version-mismatch with expected/actual versions, missing-layer with layerName, and size-exceeded with layerSize and budget. validateChainStep(manifest, opts) first verifies getPatchFromVersion(manifest) === opts.expectedFrom, then delegates to binpatchValidateChainStep; a failed delegate result is classified as size-exceeded when the named OCI layer exists and missing-layer otherwise.resolveStableChain(currentVersion, targetVersion, signal?, source?) delegates to stableSource(source).resolveChain(...) and returns Promise<PatchChain | null>.resolveNightlyChain() accepts { token, currentVersion, targetVersion, fullGzSize, preloadedTags?, signal?, source? }. It creates OciClient with registry https://ghcr.io, the selected source.ghcrRepo, User-Agent sentry-cli/${CLI_VERSION}, and customFetch; it uses preloadedTags or lists tags matching PATCH_TAG_PREFIX, then filters/sorts them between current and target versions.resolveNightlyChain() returns null when no chain tags exist or the count exceeds MAX_NIGHTLY_CHAIN_DEPTH. It fetches all manifests concurrently with Promise.all; the manifest-fetch catch is intentionally silent/grandfathered under issue #1531 and returns null.${getPlatformBinaryName()}.patch. Each manifest must link from the previous version and fit the remaining budget opts.fullGzSize * SIZE_THRESHOLD_RATIO - totalSize. The local rich validation is deliberately retained over binpatchβs coarser "malformed" | "over_budget" result so telemetry can distinguish version-mismatch, missing-layer, and size-exceeded; failures set active-span telemetry_reason and return null.resolveNightlyChain() derives toVersion by removing PATCH_TAG_PREFIX, records { fromVersion, toVersion }, stores the layer digest and size, and gets final expectedSha256 via getPatchTargetSha256(manifest, binaryName). A chain not ending exactly at opts.targetVersion, or lacking a final SHA-256, sets telemetry_reason="version-mismatch" and returns null. Valid blobs are downloaded concurrently with client.downloadBlobBuffer(), converted to Uint8Array, and returned as { patches, totalSize, expectedSha256, steps }.applyPatchChain(chain, oldBinaryPath, destPath, onBytes?) runs in an "apply-patches" / "upgrade.delta.apply" tracing span with patches.count and patches.total_bytes. It calls applyPatchChainInMemory() with each patchβs data and verifies the resulting hash exactly; mismatch throws Error("SHA-256 mismatch after patching: got ${sha256}, expected ${chain.expectedSha256}").makeProgressHandler(setMessage?) creates a fresh byte-progress display whenever the progress phase changes and reports deltas via event.written - previousWritten. Apply phases use label "Applying patch(es)" and { format: "pct" }; download/read phases use "Processing patch(es)" and { format: "bytes" }. Percent-only apply rendering avoids misleading cumulative multi-hop totals such as 930 MB for a final 310 MB binary; "done" completes the active progress display._source.current. onResolved records the source, sets span attribute delta.source, and debug-logs source, patch count, and formatted total size; onOfflineMiss records and attributes "offline_miss"; onUnavailable(reason) sets telemetry_reason.resolveDelta(source, targetVersion, oldBinaryPath, destPath, offline?, setMessage?) calls binpatch resolveAndApply() with currentVersion: CLI_VERSION, target/old/destination paths, the instrumented patch cache, offline mode, phase-aware progress, and telemetry, then maps success to { result, source: tel._source.current }.resolveStableDelta(...) and resolveNightlyDelta(...) preserve the existing 5-argument public call shape plus optional source; each invokes resolveDelta() with its respective source strategy and returns only result.attemptDeltaUpgrade(targetVersion, oldBinaryPath, destPath, offline?, setMessage?, source?) immediately resolves null when canAttemptDelta() is false. Otherwise it chooses channel "nightly" or "stable" and runs in an "upgrade.delta" tracing span initialized with delta.channel, delta.from_version, and delta.to_version.attemptDeltaUpgrade() sets delta.patch_bytes and delta.chain_length, emits Sentry distributions upgrade.delta.patch_bytes and upgrade.delta.chain_length with the channel attribute, and sets span status code 1. A null result additionally sets delta.result="unavailable".attemptDeltaUpgrade() captures a warning-level Sentry exception tagged with delta.from_version, delta.to_version, and delta.channel; attempts to preserve delta.source for post-resolution apply failures through chainSource; logs "Delta upgrade failed (${message}), falling back to full download"; sets span status code 2, delta.result="error", and delta.error=message; and returns null so the full download can proceed.prefetch(source, targetVersion, signal?) does nothing if delta is ineligible or already aborted, resolves a chain from CLI_VERSION to the target, and saves it only when chain.steps exists and the signal remains unaborted. prefetchNightlyPatches() and prefetchStablePatches() select their corresponding source strategies."No files found"."No files found".packages/cli/node_modules contained exactly 48 entries: .bin/, .vite-temp/, .vite/, @anthropic-ai/, @biomejs/, @clack/, @hono/, @mastra/, @sentry/, @spotlightjs/, @stricli/, @types/, @vitest/, binpatch/, chalk/, cli-highlight/, consola/, esbuild/, fast-check/, fflate/, fossilize/, hono/, http-cache-semantics/, ignore/, ink-spinner/, ink/, jpeg-js/, marked/, node-sqlite3-wasm/, p-limit/, peggy/, picomatch/, pixelmatch/, pngjs/, pretty-ms/, qrcode-terminal/, react-devtools-core/, react/, semver/, string-width/, tinyglobby/, tsx/, typescript/, ultracite/, uuidv7/, valibot/, vitest/, and wrap-ansi/.