Dashboard › cli › Distillation
5bf10fea-fe0a-415d-bb08-efd3105ef561["lore_tm_v1_myb8qZZptZjNSP2kMcnXzDlKyyKDcJL866el9UM87pM","lore_tm_v1_9wu5qWlCNW2OAewvhRKftk697VOmQsxTOCflXlwoVd0","lore_tm_v1_kdSChctMzY5NCJXqKY8L0o7z_eakFE9hwKQLRWUuX6c","lore_tm_v1_eOkbDuJYl5TFlpHvBxIq34fdun2IqbB1zYZM1ka899o","lore_tm_v1_i6u1db2lvZ0pmh96VXKtuc3hHGFFrN4rrRMYkqWmcdY","lore_tm_v1_2VRXzOmfCA95lCMMyerEjc05Y6a5mW_4ANNKmLTurUU","lore_tm_v1_qAeNCtcpcNsm_9KLjBfHtp29rFN2_mgI3Dqv73AdMHY","lore_tm_v1_HvT_DJAin2hsvDB0MpziLsLogIs7AHD2YhqvjKQNLnQ","lore_tm_v1_ncbG7NNtPsY39wQ7CnbWYA9bTionsPGs4ecbpYWfzXk","lore_tm_v1_GPgkRbtSRWIX5naO0AQga016QP0t0BcR0yLffVyzZuk","lore_tm_v1_jgKypuEw3nqDdsZC0HFYQ0sDAAWixxoJFzeU_bP0Il8","lore_tm_v1_FeihLD5Fcv3j0ZEO9Xk3mqA4dGttzRWapEiCIpIeSh4","lore_tm_v1_utXX61VHrR7ZHBzYIYqS524qWA_8RzUiYeh0AwymYvU","lore_tm_v1_fzWVVJzmvHmqbXtv3mWHUNr_XDWcOew50xtnJqHVONw","lore_tm_v1_S_MuncQThYPFJE5HiSz0IITBnwFnzhDV4cunHI1YzPY"]
Date: September 9, 2026
packages/cli/AGENTS.md states Sentry CLI is built with Node.js, pnpm, and Stricli; it lives in packages/cli within a pnpm workspace, while the Astro + Starlight documentation site lives in apps/cli-docs.gh conventions, agent-friendly JSON/predictable behavior, and fast Node SEA (fossilize) native binaries with SQLite API-response caching.packages/cli/AGENTS.md: DSN scanning in .env and JS, Python, Go, Java, Ruby, and PHP source; project-root detection from VCS/language/build markers; directory-name inference via bidirectional word-boundary matching; regional API fan-out to us.sentry.io and de.sentry.io; monorepo aliases; Seer-backed issue explain and issue plan; and OAuth Device Flow.package.json for the latest scripts before running project commands. Commands run from packages/cli, or from the repository root through pnpm --filter sentry run <script>.pnpm install from the repository root; pnpm run dev; pnpm run cli -- <args>; pnpm run build; pnpm run build:all; pnpm run typecheck; pnpm run lint; pnpm run lint:fix before committing; pnpm run test:unit; pnpm run test:e2e; pnpm exec vitest run test/lib/foo.test.ts; and watch mode via pnpm exec vitest.devDependencies, never dependencies, because everything is bundled at build time with esbuild and CI enforces the rule through pnpm run check:deps.pnpm add -D <package> with the -D flag.@sentry/api provides response types, code must import those types directly rather than creating redundant Zod schemas in src/types/sentry.ts.node:* standard-library APIs and must not reintroduce Bun.* globals, bun:test, or bun CLI commands.packages/cli/AGENTS.md: read with readFile(path, "utf-8") and write with writeFile(path, content) from node:fs/promises; existence checks use existsSync() from node:fs; processes use spawn()/execFile() from node:child_process; shell commands use execSync(); executable lookup uses src/lib/which.ts; globbing uses src/lib/scan/; sleep uses await setTimeout(ms) from node:timers/promises; JSON files use JSON.parse(await readFile(path, "utf-8")).mkdirSync(dir, { recursive: true, mode: 0o700 }); commands containing user-controlled values should prefer execFileSync(command, args) over string-based execSync() to prevent shell injection.apps/cli-docs/src/content/docs/contributing.md under the project-structure block generated by script/generate-docs-sections.ts; current commands can also be inspected with ls src/commands/ or sentry --help.src/bin.ts as entry point, src/app.ts for Stricli setup, src/context.ts for dependency injection, src/commands/, src/lib/, src/types/, test/, script/, .cursor/rules/, and biome.jsonc.src/commands/ includes command groups auth, cli, dashboard, event, issue, log, org, project, release, replay, repo, sourcemap, span, team, trace, trial, and local, plus standalone files api.ts, explore.ts, help.ts, init.ts, and schema.ts.buildCommand from ../../lib/command.js, never directly from @stricli/core, because the wrapper supplies telemetry, automatic --json/--fields, and output rendering.async *func() generators, yield new CommandOutput(data), and may return { hint }; output.human receives the same object serialized as JSON. Commands must not add a separate json flag, call stdout.write(), or branch on flags.json.src/lib/formatters/<domain>.ts. Files exceeding approximately 400 lines should extract formatting helpers, following references such as src/lib/formatters/replay.ts, src/lib/formatters/trace.ts, and src/lib/formatters/human.ts.stderr.write() is banned in command files by a GritQL rule; diagnostics use logger and data output uses CommandOutput.buildRouteMap from ../../lib/route-map.js, never directly from @stricli/core; standard aliases are automatically injected as list → ls, view → show, delete → remove, rm, and create → new. Explicit aliases are merged and take precedence, but standard aliases must not be manually duplicated.[<org>/<project>/]<id> positional parsing uses parseSlashSeparatedArg from src/lib/arg-parsing.ts, followed by parseOrgProjectArg; resulting target types are "auto-detect", "explicit", "project-search", or "org-all". Required trace/span identifiers should be positional arguments rather than flags.mdKvTable(), colorTag(), escapeMarkdownCell(), and renderMarkdown(); raw muted()/chalk must not be embedded in output strings. Non-markdown tree output uses isPlainOutput() ? text : muted(text).isPlainOutput() precedence is SENTRY_PLAIN_OUTPUT over NO_COLOR, then FORCE_COLOR for TTYs, then !isTTY; implementation is in src/lib/formatters/plain-detect.ts and re-exported from markdown.ts.buildDeleteCommand() from src/lib/mutate-command.ts; it injects --yes/-y, --force/-f, and --dry-run/-n, rejects non-TTY execution without --yes or --force unless dry-run is active, and supports noForceFlag, noDryRunFlag, and noNonInteractiveGuard.test/lib/upgrade.test.ts, test/commands/cli/upgrade.test.ts, test/lib/delta-upgrade.test.ts, test/lib/delta-upgrade.mocked.test.ts, and test/e2e/delta-upgrade.test.ts.src/lib/binary.ts exports KNOWN_CURL_DIRS, parseInstallationMethod(), isMusl(), getPlatformBinaryName(), getBinaryDownloadUrl(), GITHUB_RELEASES_URL, isNightlyVersion(), compareVersions(), isDowngrade(), getBinaryFilename(), getBinaryPaths(), determineInstallDir(), getGitHubHeaders(), fetchWithUpgradeError(), replaceBinarySync(), cleanupOldBinary(), acquireLock(), releaseLock(), and installBinary(); it also contains internal VALID_METHODS and handleExistingLock().src/lib/version-check.ts imports from ./delta-upgrade.js and imports fetchLatestFromGitHub plus fetchLatestNightlyVersion from ./upgrade.js; src/lib/upgrade.ts imports from ./binary.js, imports attemptDeltaUpgrade and DeltaResult from ./delta-upgrade.js, imports from ./ghcr.js, and re-exports InstallationMethod plus parseInstallationMethod; src/lib/telemetry.ts imports isMusl; src/lib/delta-upgrade.ts imports binary helpers and GHCR_REPO; src/lib/release-notes.ts imports binary helpers and the GitHubRelease type from ./delta-upgrade.js.test/lib/version-check.test.ts, test/lib/upgrade.test.ts, test/lib/release-notes.test.ts, test/lib/release-notes.property.test.ts, test/lib/ghcr.test.ts, test/lib/delta-upgrade.test.ts, test/lib/delta-upgrade.mocked.test.ts, test/lib/binary.test.ts, test/lib/binary.mocked.test.ts, test/e2e/delta-upgrade.test.ts, and test/commands/cli/upgrade.test.ts; scanner tests include test/lib/scan/binary.test.ts and test/lib/scan/binary.property.test.ts.test/lib/version-check.test.ts covers notification suppression for upgrade/CLI-management commands, --version, and --json; non-suppression for feedback, unrelated setup/fix arguments, regular commands, and empty arguments; stable/nightly update labels; TTY gating; once-per-process and once-per-day rate limits; contextual error notifications; shared notification latching; abort behavior; background checks; and SENTRY_CLI_NO_UPDATE_CHECK=1."checks for update when never checked before"; recent checks instead use probabilistic checking, and abortPendingVersionCheck() must abort cleanly.test/lib/upgrade.test.ts covers case-insensitive installation-method parsing and invalid methods; GitHub/npm latest-version fetching; UpgradeError reasons unknown_method, network_error, execution_failed, version_not_found, unsupported_operation, and offline_cache_miss; stable versus nightly source selection; version existence; execution failures; stored install information; and Homebrew detection, including /Cellar/ and /usr/local/Cellar/ paths overriding stale stored information.fetchLatestVersion() test expectations select GitHub for curl and brew, npm for npm, pnpm, bun, yarn, and unknown methods, GHCR manifests for the nightly channel regardless of installation method, and GitHub stable releases when the channel is omitted.test/lib/ghcr.test.ts covers anonymous token success and failures; nightly/arbitrary-tag manifest fetching; extracting nightly versions from annotations; finding platform layers by filename; direct 200 blob responses; 307 and 302 redirects followed without authorization; missing Location; storage/network/unexpected-status failures; tag listing/filtering; empty or missing tag results; pagination when a page contains 100 tags; and downloadLayerBlob() success/failure.test/lib/install-script.test.ts; nearby unrelated references include test/lib/error-reporting.test.ts, test/lib/node-polyfills-file-stat.test.ts, and test/lib/proguard.property.test.ts.test/lib/install-script.test.ts is a 109-line Vitest suite that exercises the shell install script without network access by placing fake curl and gunzip executables in a temporary bin directory created via mkdtempSync().bash install --version 0.31.0 --no-modify-path --no-completions --no-agent-skills, expects exit code 0, and verifies exact delegated setup arguments in order: cli, setup, --install, --method, curl, --channel, stable, --no-modify-path, --no-completions, --no-agent-skills.src/lib/binary.ts:isMusl() runs ldd --version, combines stdout and stderr because musl writes "musl libc" to stderr, caches whether lowercase output includes "musl", and falls back to cached false/glibc when ldd is unavailable or fails.getPlatformBinaryName() builds sentry-<os>-<arch>[-musl][.exe]: OS is darwin, windows, or default linux; architecture is arm64 only when process.arch === "arm64", otherwise x64; musl adds -musl; Windows adds .exe.getBinaryDownloadUrl(version) returns https://github.com/getsentry/cli/releases/download/${version}/${getPlatformBinaryName()}, and GITHUB_RELEASES_URL is https://api.github.com/repos/getsentry/cli/releases.isNightlyVersion(version) identifies nightlies by version.includes("-dev."); documented nightly format is X.Y.Z-dev.<unix-seconds>.compareVersions(a, b) delegates to semverCompare(a, b) and returns -1 | 0 | 1; isDowngrade(current, target) returns whether compareVersions(current, target) === 1.src/lib/binary.ts: the compareVersions() JSDoc still says it uses Bun.semver.order, although the implementation calls semverCompare() and packages/cli/AGENTS.md prohibits reintroducing Bun APIs.getBinaryFilename() returns sentry.exe on Windows and sentry elsewhere; getBinaryPaths(installPath) returns installPath, ${installPath}.download, ${installPath}.old, and ${installPath}.lock.determineInstallDir(homeDir, env) prioritizes: 1. SENTRY_INSTALL_DIR, 2. ~/.local/bin when it exists and is in PATH, 3. ~/bin when it exists and is in PATH, 4. ~/.sentry/bin as fallback for later PATH setup.