Dashboard › cli › Distillation
43a27234-ad5c-4893-97b2-a35ec0cab599["lore_tm_v1_ggwvKuJaZhiVH25Z40iXUAGhZR-spbl5DykYhbgr7WA","lore_tm_v1_-Ye_DejqEbNeLtqC2OkfKRhVWQFk_pk3wIQ1-pOGPUE","lore_tm_v1_QJRSa2t5iWkSBpA07kBUH_woGMeCKPrbV0-KqydA25o","lore_tm_v1_YXE_jYXA4I-z6WEm32lcHFLN50uMk3I0MMX6-AyWJwk","lore_tm_v1_IwD_XJ3yLwt5yCZLIjTcSOYSZ4zbfk5RQ_X7vHU-kvU","lore_tm_v1_uY82_THv9OZJmZ6xbAVsm3MdKfUoY7rA7Z2AKgZLpuY","lore_tm_v1_5g5NGoV6EJe42w5lGpe3Mk5il8cx4nxXJU0UuMHMn0k","lore_tm_v1_bJeTwUL2r_pBsAV-JotWUoJakJuaAfu2w8b8McvkQUA","lore_tm_v1_ah87_fR2ec1TqNrZ5QFD0hHNuZ4xnxqBpkR-vWHzS7M","lore_tm_v1_gFjralkpKqKcTLVxFUPcTldXvqDZm_us_-xASNWPLZE"]
VersionCheckInfo state semantics in packages/cli/src/lib/db/version-check.ts: lastChecked is a Unix timestamp in ms or null if βnever checked */β; latestVersion is a GitHub version string or null if βnever fetched */β; lastNotified is the Unix timestamp in ms when the update notification was last printed, or null.packages/cli/src/lib/db/version-check.ts stores metadata under version_check.last_checked, version_check.latest_version, and version_check.last_notified; markUpdateNotified() writes Date.now(), clearVersionCheckCache() clears all 3 keys, and setVersionCheckInfo(latestVersion) updates the checked timestamp and latest version.packages/cli/test/lib/upgrade.test.ts dynamically imports packages/cli/src/lib/upgrade.ts only after vi.mock() so the module receives the mocked spawn; imported upgrade functions include buildKnownCurlPaths, detectInstallationMethod, detectPackageManagerFromPath, downloadBinaryToTemp, executeUpgrade, fetchLatestFromGitHub, fetchLatestFromNpm, fetchLatestNightlyVersion, fetchLatestVersion, getCurlInstallPaths, parseInstallationMethod, startCleanupOldBinary, and versionExists.packages/cli/test/lib/scan/constants.property.test.ts.@sentry/mcp-server uses changelogPolicy: none, preReleaseCommand: bash bin/bump-version.sh, GitHub and npm targets, and npm includeNames: /^sentry-mcp-server-\d.*\.tgz$/.packages/cli/src/lib/upgrade.ts detects installation method by checking stored install info before legacy detection; successful non-unknown legacy detection is persisted with method, path: process.execPath, and version: CLI_VERSION, while DB persistence failure only logs Failed to persist install info (DB may be read-only).fetchLatestFromGitHub(signal?) requests ${GITHUB_RELEASES_URL}/latest through fetchWithUpgradeError() with getGitHubHeaders(), strips VERSION_PREFIX_REGEX from tag_name, maps non-OK responses to UpgradeError("network_error", "Failed to fetch from GitHub: <status>"), and rejects a missing tag_name with No version found in GitHub release.fetchLatestFromNpm() requests ${NPM_REGISTRY_URL}/latest with Accept: application/json, returns data.version, maps non-OK responses to Failed to fetch from npm: <status>, and rejects a missing version with No version found in npm registry.fetchLatestNightlyVersion(signal?) performs exactly 2 HTTP requestsβgetAnonymousToken() followed by fetchNightlyManifest(token)βand extracts the version via getNightlyVersion(manifest); it checks signal.aborted before each network call and throws AbortError.fetchLatestVersion(method, channel = "stable") routes nightly to GHCR, stable curl/brew to GitHub Releases, and stable package-manager installs to npm.nightlyVersionExists(version) checks GHCR tag nightly-${version} via getAnonymousToken() and fetchManifest(); HTTP 404 or 403 means false, while other failures propagate.versionExists(method, version) routes versions recognized by isNightlyVersion() to GHCR; stable curl/brew versions use a GitHub HEAD request to ${GITHUB_RELEASES_URL}/tags/${version}, while package-manager versions use an npm HEAD request to ${NPM_REGISTRY_URL}/${version}.fetchWithUpgradeError(url, init, serviceName) in packages/cli/src/lib/binary.ts calls customFetch, rethrows errors named AbortError, maps TLS certificate failures through buildTlsErrorDetail(error), and wraps other failures as UpgradeError("network_error", "Failed to connect to ${serviceName}: ${msg}").replaceBinarySync(tempPath, installPath) uses atomic renameSync(tempPath, installPath) on Unix; on Windows it first renames the running executable to ${installPath}.old, retries after unlinking an existing .old, and then renames the downloaded temp binary into place.streamDecompressToFile() in packages/cli/src/lib/upgrade.ts intentionally uses openSync, a looping writeSync, and closeSync rather than createWriteStream; root cause was a reproducible Linux ETXTBSY race because a stream writerβs finish event did not guarantee the file descriptor had been released before spawning the binary.writeChunkSync(fd, chunk) handles short writes by looping until the full Uint8Array is written and throws if writeSync returns 0 or less; drainBodyToFd() pipes through new DecompressionStream("gzip"), separately captures stream and write errors, and leaves file-descriptor ownership to its caller.streamDecompressToFile() creates the destination with mode 0o644, reports an indeterminate live byte count through makeByteProgress("Downloading", null, setMessage), closes the descriptor synchronously, prioritizes an existing write error over a close error, and then surfaces any terminal stream error.downloadStableToPath(version, destPath, setMessage?) builds the URL with getBinaryDownloadUrl(version), first tries ${url}.gz (~37 MB versus ~99 MB, approximately 60% smaller), streams it through gzip decompression, and falls back on any failure to the raw asset.response.arrayBuffer() before writeFile(destPath, new Uint8Array(body)); this avoids Bun issue https://github.com/oven-sh/bun/issues/13237, where Bun.write(path, Response) with a large streaming body may let the process exit before completion.VERIFY_MAX_ATTEMPTS = 6 and VERIFY_BASE_DELAY_MS = 100, with 6 probes and 5 exponential-backoff sleeps totaling approximately 3.1 seconds.downloadBinaryToTemp(version, downloadTag?, offline?, setMessage?) acquires the curl-install lock, removes any stale temp file, attempts delta upgrade first, and falls back to a full download unless offline mode prohibits it.UpgradeError("offline_cache_miss", "Cannot upgrade to ${version} in offline mode β no pre-downloaded update is available. Run \sentry cli upgrade` without `--offline` to download the update directly.")`; implicit network-offline cache miss instead tells the user the network is unavailable and to check the internet connection.downloadBinaryToTemp() calls waitForBinaryVisible(tempPath), logs the verified formatted size, clears the consumed patch cache best-effort, applies Unix mode 0o755, and returns { tempBinaryPath, lockPath, patchBytes }; failure releases the lock before rethrowing.1.3.9 issue CLI-1D3, where Bun.file(path).writer() could return before sentry.exe.download became visible and Bun.spawn then failed with Executable not found in $PATH.downloadFullBinary() routes nightly versions to downloadNightlyToPath(destPath, version, setMessage) and stable versions to downloadStableToPath(downloadTag ?? version, destPath, setMessage).brew upgrade getsentry/tools/sentry; the requested version is intentionally ignored because the Homebrew formula controls versioning and does not support arbitrary release pinning.#1239: import the pre-shaped CLI into getsentry/sentry-mcp under its current repository name, validate the complete monorepo and production deployment paths there, and rename the repository to getsentry/toolkit only after every gate passes.#1239, titled toolkit merge: import CLI into sentry-mcp, validate, then rename, is OPEN at https://github.com/getsentry/cli/issues/1239; it is a sub-task of master tracking issue getsentry/cli #1248.#1254 (complete); 2. bridge CLI release completed and verified via getsentry/cli #1244; 3. create a dedicated integration branch from current getsentry/sentry-mcp main, never importing directly into main.git filter-repo refs from the bridge-release commit: 1. import/cli, containing only packages/cli/**; 2. import/cli-docs, containing only apps/cli-docs/**; source commit IDs must be recorded and verified before import.git subtree add --prefix=packages/cli <cli-remote> import/cli and git subtree add --prefix=apps/cli-docs <cli-remote> import/cli-docs.git log --follow and blame across both imported trees; docs must never be nested under packages/cli.apps/* workspace membership and reconcile root files without yet changing the repository name or deployment destinations.#9339 and #9456; 3. Craft workspace selection passes using getsentry/craft #848 and #872, with prefixed tags isolated via #847; 4. existing MCP Vercel and Cloudflare deployments still target getsentry/sentry-mcp; 5. canary the Cloudflare Worker deployment after pnpm-native orchestration replaces Turbo; 6. Vercel CLI-docs preview works from apps/cli-docs; 7. independent correctness and security reviews pass on the exact integration head.#1156 rename the repository to getsentry/toolkit; preserving the known getsentry/sentry-mcp identity during integration keeps GitHub, Vercel, Cloudflare, branch protections, and repository integrations operating against their established repository identity.